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.
20 #include "execute_tests.h"
21 #include "test_cases_channel_shutdown.h"
22 #include "../common/containers.h"
23 #include "../common/test_step.h"
24 #include "../common/common_handlers.h"
33 /* Modify this to change the logging level of Meshlink */
34 #define TEST_MESHLINK_LOG_LEVEL MESHLINK_DEBUG
36 static void test_case_mesh_channel_shutdown_01(void **state);
37 static bool test_steps_mesh_channel_shutdown_01(void);
38 static void test_case_mesh_channel_shutdown_02(void **state);
39 static bool test_steps_mesh_channel_shutdown_02(void);
40 static void test_case_mesh_channel_shutdown_03(void **state);
41 static bool test_steps_mesh_channel_shutdown_03(void);
42 static void test_case_mesh_channel_shutdown_04(void **state);
43 static bool test_steps_mesh_channel_shutdown_04(void);
44 static void test_case_mesh_channel_shutdown_05(void **state);
45 static bool test_steps_mesh_channel_shutdown_05(void);
47 static void receive_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, const void *dat, size_t len);
48 static void status_cb(meshlink_handle_t *mesh, meshlink_node_t *node, bool reachable);
49 static void poll_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, size_t len);
51 /* State structure for meshlink_channel_shutdown Test Case #1 */
52 static black_box_state_t test_mesh_channel_shutdown_01_state = {
53 .test_case_name = "test_case_mesh_channel_shutdown_01",
56 /* State structure for meshlink_channel_shutdown Test Case #2 */
57 static black_box_state_t test_mesh_channel_shutdown_02_state = {
58 .test_case_name = "test_case_mesh_channel_shutdown_02",
61 /* State structure for meshlink_channel_shutdown Test Case #3 */
62 static black_box_state_t test_mesh_channel_shutdown_03_state = {
63 .test_case_name = "test_case_mesh_channel_shutdown_03",
66 /* State structure for meshlink_channel_shutdown Test Case #4 */
67 static black_box_state_t test_mesh_channel_shutdown_04_state = {
68 .test_case_name = "test_case_mesh_channel_shutdown_04",
71 /* State structure for meshlink_channel_shutdown Test Case #5 */
72 static black_box_state_t test_mesh_channel_shutdown_05_state = {
73 .test_case_name = "test_case_mesh_channel_shutdown_05",
76 static bool channel_acc;
78 static bool foo_responded;
79 static bool bar_responded;
81 /* mutex for the common variable */
82 static pthread_mutex_t accept_lock = PTHREAD_MUTEX_INITIALIZER;
83 static pthread_mutex_t poll_lock = PTHREAD_MUTEX_INITIALIZER;
84 static pthread_mutex_t bar_responded_lock = PTHREAD_MUTEX_INITIALIZER;
85 static pthread_mutex_t foo_responded_lock = PTHREAD_MUTEX_INITIALIZER;
87 static pthread_cond_t accept_cond = PTHREAD_COND_INITIALIZER;
88 static pthread_cond_t poll_cond = PTHREAD_COND_INITIALIZER;
89 static pthread_cond_t foo_cond = PTHREAD_COND_INITIALIZER;
90 static pthread_cond_t bar_cond = PTHREAD_COND_INITIALIZER;
92 static bool accept_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, uint16_t port, const void *data, size_t len) {
96 meshlink_set_channel_receive_cb(mesh, channel, receive_cb);
97 channel->node->priv = channel;
98 pthread_mutex_lock(&accept_lock);
100 assert(!pthread_cond_broadcast(&accept_cond));
101 pthread_mutex_unlock(&accept_lock);
106 /* channel receive callback */
107 static void receive_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, const void *dat, size_t len) {
108 if(!strcmp(mesh->name, "foo")) {
109 pthread_mutex_lock(& foo_responded_lock);
110 foo_responded = true;
111 assert(!pthread_cond_broadcast(&foo_cond));
112 pthread_mutex_unlock(& foo_responded_lock);
114 } else if(!strcmp(mesh->name, "bar")) {
115 pthread_mutex_lock(& bar_responded_lock);
116 bar_responded = true;
117 assert(!pthread_cond_broadcast(&bar_cond));
118 pthread_mutex_unlock(& bar_responded_lock);
120 assert(meshlink_channel_send(mesh, channel, "echo", 4) >= 0);
125 static void poll_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, size_t len) {
128 meshlink_set_channel_poll_cb(mesh, channel, NULL);
129 pthread_mutex_lock(&poll_lock);
131 assert(!pthread_cond_broadcast(&poll_cond));
132 pthread_mutex_unlock(&poll_lock);
135 /* Execute meshlink_channel_shutdown Test Case # 1*/
136 static void test_case_mesh_channel_shutdown_01(void **state) {
137 execute_test(test_steps_mesh_channel_shutdown_01, state);
140 /* Test Steps for meshlink_channel_shutdown Test Case # 1 - Valid case
143 1. Open foo and bar instances and open a channel between them
144 2. Send data through the channel.
145 3. Shut down channel's read and send data
146 4. Shutdown channel's write and send data
149 Data is able to receive through channel before shutting down,
150 On shutting down read its should not able to receive data and when write
151 is shut down its should be able to send data through channel.
153 static bool test_steps_mesh_channel_shutdown_01(void) {
154 struct timespec timeout = {0};
155 meshlink_destroy("chan_shutdown_conf.1");
156 meshlink_destroy("chan_shutdown_conf.2");
157 // Open two new meshlink instance.
159 meshlink_handle_t *mesh1 = meshlink_open("chan_shutdown_conf.1", "foo", "channels", DEV_CLASS_BACKBONE);
160 assert(mesh1 != NULL);
162 meshlink_handle_t *mesh2 = meshlink_open("chan_shutdown_conf.2", "bar", "channels", DEV_CLASS_BACKBONE);
163 assert(mesh2 != NULL);
165 char *data = meshlink_export(mesh1);
167 assert(meshlink_import(mesh2, data));
169 data = meshlink_export(mesh2);
171 assert(meshlink_import(mesh1, data));
174 // Set the callbacks.
176 meshlink_set_channel_accept_cb(mesh2, accept_cb);
178 // Start both instances
180 assert(meshlink_start(mesh1));
181 assert(meshlink_start(mesh2));
184 // Open a channel from foo to bar.
186 meshlink_node_t *bar = meshlink_get_node(mesh1, "bar");
189 meshlink_channel_t *channel1 = meshlink_channel_open(mesh1, bar, 7, receive_cb, NULL, 0);
190 meshlink_set_channel_poll_cb(mesh1, channel1, poll_cb);
192 timeout.tv_sec = time(NULL) + 10;
193 pthread_mutex_lock(&poll_lock);
195 while(polled == false) {
196 assert(!pthread_cond_timedwait(&poll_cond, &poll_lock, &timeout));
199 pthread_mutex_unlock(&poll_lock);
201 timeout.tv_sec = time(NULL) + 10;
202 pthread_mutex_lock(&accept_lock);
204 while(channel_acc == false) {
205 assert(!pthread_cond_timedwait(&accept_cond, &accept_lock, &timeout));
208 pthread_mutex_unlock(&accept_lock);
210 meshlink_channel_t *channel2 = bar->priv;
212 // Sending to bar and testing the echo
214 assert(meshlink_channel_send(mesh1, channel1, "echo", 4) >= 0);
216 timeout.tv_sec = time(NULL) + 10;
217 pthread_mutex_lock(&foo_responded_lock);
219 while(foo_responded == false) {
220 assert(!pthread_cond_timedwait(&foo_cond, &foo_responded_lock, &timeout));
223 pthread_mutex_unlock(&foo_responded_lock);
224 assert(foo_responded);
226 // Shutting down channel read
228 meshlink_channel_shutdown(mesh1, channel1, SHUT_RD);
229 bar_responded = false;
230 foo_responded = false;
231 assert(meshlink_channel_send(mesh1, channel1, "echo", 4) >= 0);
233 timeout.tv_sec = time(NULL) + 10;
234 pthread_mutex_lock(&bar_responded_lock);
236 while(bar_responded == false) {
237 assert(!pthread_cond_timedwait(&bar_cond, &bar_responded_lock, &timeout));
240 pthread_mutex_unlock(&bar_responded_lock);
241 assert_int_equal(bar_responded, true);
243 assert_int_equal(foo_responded, false);
245 // Shutting down channel write
247 meshlink_channel_shutdown(mesh1, channel1, SHUT_WR);
249 ssize_t send_ret = meshlink_channel_send(mesh1, channel1, "echo", 4);
250 assert_int_equal(send_ret, -1);
254 meshlink_close(mesh2);
255 meshlink_close(mesh1);
256 meshlink_destroy("chan_shutdown_conf.1");
257 meshlink_destroy("chan_shutdown_conf.2");
262 /* Execute meshlink_channel_shutdown Test Case # 2*/
263 static void test_case_mesh_channel_shutdown_02(void **state) {
264 execute_test(test_steps_mesh_channel_shutdown_02, state);
267 /* Test Steps for meshlink_channel_shutdown Test Case # 2 - Invalid case
270 1. Open node instance and create a channel
271 2. Call meshlink_channel_shutdown API by passing NULL as mesh handle
274 meshlink_channel_shutdown API should report proper error handling
276 static bool test_steps_mesh_channel_shutdown_02(void) {
277 meshlink_destroy("channelshutdownconf.3");
278 meshlink_set_log_cb(NULL, TEST_MESHLINK_LOG_LEVEL, meshlink_callback_logger);
280 /* Create meshlink instance */
281 meshlink_handle_t *mesh_handle = meshlink_open("channelshutdownconf.3", "nut", "node_sim", 1);
282 assert(mesh_handle != NULL);
283 meshlink_set_log_cb(mesh_handle, TEST_MESHLINK_LOG_LEVEL, meshlink_callback_logger);
284 meshlink_set_channel_accept_cb(mesh_handle, accept_cb);
286 assert(meshlink_start(mesh_handle));
288 meshlink_node_t *node = meshlink_get_self(mesh_handle);
289 assert(node != NULL);
291 meshlink_channel_t *channel = meshlink_channel_open(mesh_handle, node, 8000, NULL, NULL, 0);
293 meshlink_set_channel_poll_cb(mesh_handle, channel, poll_cb);
295 // Passing NULL as mesh handle and other arguments being valid
297 meshlink_channel_shutdown(NULL, channel, SHUT_WR);
298 assert_int_equal(meshlink_errno, MESHLINK_EINVAL);
300 meshlink_close(mesh_handle);
301 meshlink_destroy("channelshutdownconf.3");
306 /* Execute meshlink_channel_shutdown Test Case # 3*/
307 static void test_case_mesh_channel_shutdown_03(void **state) {
308 execute_test(test_steps_mesh_channel_shutdown_03, state);
311 /* Test Steps for meshlink_channel_shutdown Test Case # 3
314 1. Open node instance
315 2. Call meshlink_channel_shutdown API by passing NULL as channel handle
318 meshlink_channel_shutdown API should report proper error handling
320 static bool test_steps_mesh_channel_shutdown_03(void) {
321 meshlink_destroy("channelshutdownconf.4");
322 meshlink_set_log_cb(NULL, TEST_MESHLINK_LOG_LEVEL, meshlink_callback_logger);
324 /* Create meshlink instance */
325 meshlink_handle_t *mesh_handle = meshlink_open("channelshutdownconf.4", "nut", "node_sim", 1);
326 assert(mesh_handle != NULL);
327 meshlink_set_log_cb(mesh_handle, TEST_MESHLINK_LOG_LEVEL, meshlink_callback_logger);
328 meshlink_set_channel_accept_cb(mesh_handle, accept_cb);
330 assert(meshlink_start(mesh_handle));
332 // Passing NULL as mesh handle and other arguments being valid
334 meshlink_channel_shutdown(mesh_handle, NULL, SHUT_WR);
335 assert_int_equal(meshlink_errno, MESHLINK_EINVAL);
337 meshlink_close(mesh_handle);
338 meshlink_destroy("channelshutdownconf.4");
344 int test_meshlink_channel_shutdown(void) {
345 const struct CMUnitTest blackbox_channel_shutdown_tests[] = {
346 cmocka_unit_test_prestate_setup_teardown(test_case_mesh_channel_shutdown_01, NULL, NULL,
347 (void *)&test_mesh_channel_shutdown_01_state),
348 cmocka_unit_test_prestate_setup_teardown(test_case_mesh_channel_shutdown_02, NULL, NULL,
349 (void *)&test_mesh_channel_shutdown_02_state),
350 cmocka_unit_test_prestate_setup_teardown(test_case_mesh_channel_shutdown_03, NULL, NULL,
351 (void *)&test_mesh_channel_shutdown_03_state)
353 total_tests += sizeof(blackbox_channel_shutdown_tests) / sizeof(blackbox_channel_shutdown_tests[0]);
355 return cmocka_run_group_tests(blackbox_channel_shutdown_tests, NULL, NULL);