2 test_cases_channel_shutdown.c -- Execution of specific meshlink black box test cases
3 Copyright (C) 2018 Guus Sliepen <guus@meshlink.io>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 #include "execute_tests.h"
25 #include "test_cases_channel_shutdown.h"
26 #include "../common/containers.h"
27 #include "../common/test_step.h"
28 #include "../common/common_handlers.h"
37 /* Modify this to change the logging level of Meshlink */
38 #define TEST_MESHLINK_LOG_LEVEL MESHLINK_DEBUG
40 static void test_case_mesh_channel_shutdown_01(void **state);
41 static bool test_steps_mesh_channel_shutdown_01(void);
42 static void test_case_mesh_channel_shutdown_02(void **state);
43 static bool test_steps_mesh_channel_shutdown_02(void);
44 static void test_case_mesh_channel_shutdown_03(void **state);
45 static bool test_steps_mesh_channel_shutdown_03(void);
47 static void receive_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, const void *dat, size_t len);
48 static void poll_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, size_t len);
50 /* State structure for meshlink_channel_shutdown Test Case #1 */
51 static black_box_state_t test_mesh_channel_shutdown_01_state = {
52 .test_case_name = "test_case_mesh_channel_shutdown_01",
55 /* State structure for meshlink_channel_shutdown Test Case #2 */
56 static black_box_state_t test_mesh_channel_shutdown_02_state = {
57 .test_case_name = "test_case_mesh_channel_shutdown_02",
60 /* State structure for meshlink_channel_shutdown Test Case #3 */
61 static black_box_state_t test_mesh_channel_shutdown_03_state = {
62 .test_case_name = "test_case_mesh_channel_shutdown_03",
65 static bool channel_acc;
67 static bool foo_responded;
68 static bool bar_responded;
70 /* mutex for the common variable */
71 static pthread_mutex_t accept_lock = PTHREAD_MUTEX_INITIALIZER;
72 static pthread_mutex_t poll_lock = PTHREAD_MUTEX_INITIALIZER;
73 static pthread_mutex_t bar_responded_lock = PTHREAD_MUTEX_INITIALIZER;
74 static pthread_mutex_t foo_responded_lock = PTHREAD_MUTEX_INITIALIZER;
76 static pthread_cond_t accept_cond = PTHREAD_COND_INITIALIZER;
77 static pthread_cond_t poll_cond = PTHREAD_COND_INITIALIZER;
78 static pthread_cond_t foo_cond = PTHREAD_COND_INITIALIZER;
79 static pthread_cond_t bar_cond = PTHREAD_COND_INITIALIZER;
81 static bool accept_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, uint16_t port, const void *data, size_t len) {
87 meshlink_set_channel_receive_cb(mesh, channel, receive_cb);
88 channel->node->priv = channel;
89 pthread_mutex_lock(&accept_lock);
91 assert(!pthread_cond_broadcast(&accept_cond));
92 pthread_mutex_unlock(&accept_lock);
97 /* channel receive callback */
98 static void receive_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, const void *dat, size_t len) {
102 if(!strcmp(mesh->name, "foo")) {
103 pthread_mutex_lock(& foo_responded_lock);
104 foo_responded = true;
105 assert(!pthread_cond_broadcast(&foo_cond));
106 pthread_mutex_unlock(& foo_responded_lock);
108 } else if(!strcmp(mesh->name, "bar")) {
109 pthread_mutex_lock(& bar_responded_lock);
110 bar_responded = true;
111 assert(!pthread_cond_broadcast(&bar_cond));
112 pthread_mutex_unlock(& bar_responded_lock);
114 assert(meshlink_channel_send(mesh, channel, "echo", 4) >= 0);
119 static void poll_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, size_t len) {
122 meshlink_set_channel_poll_cb(mesh, channel, NULL);
123 pthread_mutex_lock(&poll_lock);
125 assert(!pthread_cond_broadcast(&poll_cond));
126 pthread_mutex_unlock(&poll_lock);
129 /* Execute meshlink_channel_shutdown Test Case # 1*/
130 static void test_case_mesh_channel_shutdown_01(void **state) {
131 execute_test(test_steps_mesh_channel_shutdown_01, state);
134 /* Test Steps for meshlink_channel_shutdown Test Case # 1 - Valid case
137 1. Open foo and bar instances and open a channel between them
138 2. Send data through the channel.
139 3. Shut down channel's read and send data
140 4. Shutdown channel's write and send data
143 Data is able to receive through channel before shutting down,
144 On shutting down read its should not able to receive data and when write
145 is shut down its should be able to send data through channel.
147 static bool test_steps_mesh_channel_shutdown_01(void) {
148 struct timespec timeout = {0};
149 assert(meshlink_destroy("chan_shutdown_conf.1"));
150 assert(meshlink_destroy("chan_shutdown_conf.2"));
151 // Open two new meshlink instance.
153 meshlink_handle_t *mesh1 = meshlink_open("chan_shutdown_conf.1", "foo", "channels", DEV_CLASS_BACKBONE);
154 assert(mesh1 != NULL);
156 meshlink_handle_t *mesh2 = meshlink_open("chan_shutdown_conf.2", "bar", "channels", DEV_CLASS_BACKBONE);
157 assert(mesh2 != NULL);
159 char *data = meshlink_export(mesh1);
161 assert(meshlink_import(mesh2, data));
163 data = meshlink_export(mesh2);
165 assert(meshlink_import(mesh1, data));
168 // Set the callbacks.
170 meshlink_set_channel_accept_cb(mesh2, accept_cb);
172 // Start both instances
174 assert(meshlink_start(mesh1));
175 assert(meshlink_start(mesh2));
178 // Open a channel from foo to bar.
180 meshlink_node_t *bar = meshlink_get_node(mesh1, "bar");
183 meshlink_channel_t *channel1 = meshlink_channel_open(mesh1, bar, 7, receive_cb, NULL, 0);
184 meshlink_set_channel_poll_cb(mesh1, channel1, poll_cb);
186 timeout.tv_sec = time(NULL) + 10;
187 pthread_mutex_lock(&poll_lock);
189 while(polled == false) {
190 assert(!pthread_cond_timedwait(&poll_cond, &poll_lock, &timeout));
193 pthread_mutex_unlock(&poll_lock);
195 timeout.tv_sec = time(NULL) + 10;
196 pthread_mutex_lock(&accept_lock);
198 while(channel_acc == false) {
199 assert(!pthread_cond_timedwait(&accept_cond, &accept_lock, &timeout));
202 pthread_mutex_unlock(&accept_lock);
204 // Sending to bar and testing the echo
206 assert(meshlink_channel_send(mesh1, channel1, "echo", 4) >= 0);
208 timeout.tv_sec = time(NULL) + 10;
209 pthread_mutex_lock(&foo_responded_lock);
211 while(foo_responded == false) {
212 assert(!pthread_cond_timedwait(&foo_cond, &foo_responded_lock, &timeout));
215 pthread_mutex_unlock(&foo_responded_lock);
216 assert(foo_responded);
218 // Shutting down channel read
220 meshlink_channel_shutdown(mesh1, channel1, SHUT_RD);
221 bar_responded = false;
222 foo_responded = false;
223 assert(meshlink_channel_send(mesh1, channel1, "echo", 4) >= 0);
225 timeout.tv_sec = time(NULL) + 10;
226 pthread_mutex_lock(&bar_responded_lock);
228 while(bar_responded == false) {
229 assert(!pthread_cond_timedwait(&bar_cond, &bar_responded_lock, &timeout));
232 pthread_mutex_unlock(&bar_responded_lock);
233 assert_int_equal(bar_responded, true);
235 assert_int_equal(foo_responded, false);
237 // Shutting down channel write
239 meshlink_channel_shutdown(mesh1, channel1, SHUT_WR);
241 ssize_t send_ret = meshlink_channel_send(mesh1, channel1, "echo", 4);
242 assert_int_equal(send_ret, -1);
246 meshlink_close(mesh2);
247 meshlink_close(mesh1);
248 assert(meshlink_destroy("chan_shutdown_conf.1"));
249 assert(meshlink_destroy("chan_shutdown_conf.2"));
254 /* Execute meshlink_channel_shutdown Test Case # 2*/
255 static void test_case_mesh_channel_shutdown_02(void **state) {
256 execute_test(test_steps_mesh_channel_shutdown_02, state);
259 /* Test Steps for meshlink_channel_shutdown Test Case # 2 - Invalid case
262 1. Open node instance and create a channel
263 2. Call meshlink_channel_shutdown API by passing NULL as mesh handle
266 meshlink_channel_shutdown API should report proper error handling
268 static bool test_steps_mesh_channel_shutdown_02(void) {
269 assert(meshlink_destroy("channelshutdownconf.3"));
270 meshlink_set_log_cb(NULL, TEST_MESHLINK_LOG_LEVEL, meshlink_callback_logger);
272 /* Create meshlink instance */
273 meshlink_handle_t *mesh_handle = meshlink_open("channelshutdownconf.3", "nut", "node_sim", 1);
274 assert(mesh_handle != NULL);
275 meshlink_set_log_cb(mesh_handle, TEST_MESHLINK_LOG_LEVEL, meshlink_callback_logger);
276 meshlink_set_channel_accept_cb(mesh_handle, accept_cb);
278 assert(meshlink_start(mesh_handle));
280 meshlink_node_t *node = meshlink_get_self(mesh_handle);
281 assert(node != NULL);
283 meshlink_channel_t *channel = meshlink_channel_open(mesh_handle, node, 8000, NULL, NULL, 0);
285 meshlink_set_channel_poll_cb(mesh_handle, channel, poll_cb);
287 // Passing NULL as mesh handle and other arguments being valid
289 meshlink_channel_shutdown(NULL, channel, SHUT_WR);
290 assert_int_equal(meshlink_errno, MESHLINK_EINVAL);
292 meshlink_close(mesh_handle);
293 assert(meshlink_destroy("channelshutdownconf.3"));
298 /* Execute meshlink_channel_shutdown Test Case # 3*/
299 static void test_case_mesh_channel_shutdown_03(void **state) {
300 execute_test(test_steps_mesh_channel_shutdown_03, state);
303 /* Test Steps for meshlink_channel_shutdown Test Case # 3
306 1. Open node instance
307 2. Call meshlink_channel_shutdown API by passing NULL as channel handle
310 meshlink_channel_shutdown API should report proper error handling
312 static bool test_steps_mesh_channel_shutdown_03(void) {
313 assert(meshlink_destroy("channelshutdownconf.4"));
314 meshlink_set_log_cb(NULL, TEST_MESHLINK_LOG_LEVEL, meshlink_callback_logger);
316 /* Create meshlink instance */
317 meshlink_handle_t *mesh_handle = meshlink_open("channelshutdownconf.4", "nut", "node_sim", 1);
318 assert(mesh_handle != NULL);
319 meshlink_set_log_cb(mesh_handle, TEST_MESHLINK_LOG_LEVEL, meshlink_callback_logger);
320 meshlink_set_channel_accept_cb(mesh_handle, accept_cb);
322 assert(meshlink_start(mesh_handle));
324 // Passing NULL as mesh handle and other arguments being valid
326 meshlink_channel_shutdown(mesh_handle, NULL, SHUT_WR);
327 assert_int_equal(meshlink_errno, MESHLINK_EINVAL);
329 meshlink_close(mesh_handle);
330 assert(meshlink_destroy("channelshutdownconf.4"));
336 int test_meshlink_channel_shutdown(void) {
337 const struct CMUnitTest blackbox_channel_shutdown_tests[] = {
338 cmocka_unit_test_prestate_setup_teardown(test_case_mesh_channel_shutdown_01, NULL, NULL,
339 (void *)&test_mesh_channel_shutdown_01_state),
340 cmocka_unit_test_prestate_setup_teardown(test_case_mesh_channel_shutdown_02, NULL, NULL,
341 (void *)&test_mesh_channel_shutdown_02_state),
342 cmocka_unit_test_prestate_setup_teardown(test_case_mesh_channel_shutdown_03, NULL, NULL,
343 (void *)&test_mesh_channel_shutdown_03_state)
345 total_tests += sizeof(blackbox_channel_shutdown_tests) / sizeof(blackbox_channel_shutdown_tests[0]);
347 return cmocka_run_group_tests(blackbox_channel_shutdown_tests, NULL, NULL);