]> git.meshlink.io Git - meshlink/blob - test/blackbox/run_blackbox_tests/test_cases_channel_shutdown.c
Add the blackbox container based test suite.
[meshlink] / test / blackbox / run_blackbox_tests / test_cases_channel_shutdown.c
1 /*
2     test_cases_channel_shutdown.c -- Execution of specific meshlink black box test cases
3     Copyright (C) 2018  Guus Sliepen <guus@meshlink.io>
4
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.
9
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.
14
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.
18 */
19
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"
25 #include <assert.h>
26 #include <string.h>
27 #include <stdlib.h>
28 #include <stdarg.h>
29 #include <setjmp.h>
30 #include <cmocka.h>
31 #include <pthread.h>
32
33 /* Modify this to change the logging level of Meshlink */
34 #define TEST_MESHLINK_LOG_LEVEL MESHLINK_DEBUG
35
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);
46
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);
50
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",
54 };
55
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",
59 };
60
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",
64 };
65
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",
69 };
70
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",
74 };
75
76 static bool channel_acc;
77 static bool polled;
78 static bool foo_responded;
79 static bool bar_responded;
80
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;
86
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;
91
92 static bool accept_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, uint16_t port, const void *data, size_t len) {
93         assert(port == 7);
94         assert(!len);
95
96         meshlink_set_channel_receive_cb(mesh, channel, receive_cb);
97         channel->node->priv = channel;
98         pthread_mutex_lock(&accept_lock);
99         channel_acc = true;
100         assert(!pthread_cond_broadcast(&accept_cond));
101         pthread_mutex_unlock(&accept_lock);
102
103         return true;
104 }
105
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);
113
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);
119
120                 assert(meshlink_channel_send(mesh, channel, "echo", 4) >= 0);
121
122         }
123 }
124
125 static void poll_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, size_t len) {
126         (void)len;
127
128         meshlink_set_channel_poll_cb(mesh, channel, NULL);
129         pthread_mutex_lock(&poll_lock);
130         polled = true;
131         assert(!pthread_cond_broadcast(&poll_cond));
132         pthread_mutex_unlock(&poll_lock);
133 }
134
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);
138 }
139
140 /* Test Steps for meshlink_channel_shutdown Test Case # 1 - Valid case
141
142     Test Steps:
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
147
148     Expected Result:
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.
152 */
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.
158
159         meshlink_handle_t *mesh1 = meshlink_open("chan_shutdown_conf.1", "foo", "channels", DEV_CLASS_BACKBONE);
160         assert(mesh1 != NULL);
161
162         meshlink_handle_t *mesh2 = meshlink_open("chan_shutdown_conf.2", "bar", "channels", DEV_CLASS_BACKBONE);
163         assert(mesh2 != NULL);
164
165         char *data = meshlink_export(mesh1);
166         assert(data);
167         assert(meshlink_import(mesh2, data));
168         free(data);
169         data = meshlink_export(mesh2);
170         assert(data);
171         assert(meshlink_import(mesh1, data));
172         free(data);
173
174         // Set the callbacks.
175
176         meshlink_set_channel_accept_cb(mesh2, accept_cb);
177
178         // Start both instances
179
180         assert(meshlink_start(mesh1));
181         assert(meshlink_start(mesh2));
182         sleep(1);
183
184         // Open a channel from foo to bar.
185
186         meshlink_node_t *bar = meshlink_get_node(mesh1, "bar");
187         assert(bar);
188
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);
191
192         timeout.tv_sec = time(NULL) + 10;
193         pthread_mutex_lock(&poll_lock);
194
195         while(polled == false) {
196                 assert(!pthread_cond_timedwait(&poll_cond, &poll_lock, &timeout));
197         }
198
199         pthread_mutex_unlock(&poll_lock);
200
201         timeout.tv_sec = time(NULL) + 10;
202         pthread_mutex_lock(&accept_lock);
203
204         while(channel_acc == false) {
205                 assert(!pthread_cond_timedwait(&accept_cond, &accept_lock, &timeout));
206         }
207
208         pthread_mutex_unlock(&accept_lock);
209
210         meshlink_channel_t *channel2 = bar->priv;
211
212         // Sending to bar and testing the echo
213
214         assert(meshlink_channel_send(mesh1, channel1, "echo", 4) >= 0);
215
216         timeout.tv_sec = time(NULL) + 10;
217         pthread_mutex_lock(&foo_responded_lock);
218
219         while(foo_responded == false) {
220                 assert(!pthread_cond_timedwait(&foo_cond, &foo_responded_lock, &timeout));
221         }
222
223         pthread_mutex_unlock(&foo_responded_lock);
224         assert(foo_responded);
225
226         // Shutting down channel read
227
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);
232
233         timeout.tv_sec = time(NULL) + 10;
234         pthread_mutex_lock(&bar_responded_lock);
235
236         while(bar_responded == false) {
237                 assert(!pthread_cond_timedwait(&bar_cond, &bar_responded_lock, &timeout));
238         }
239
240         pthread_mutex_unlock(&bar_responded_lock);
241         assert_int_equal(bar_responded, true);
242         sleep(1);
243         assert_int_equal(foo_responded, false);
244
245         // Shutting down channel write
246
247         meshlink_channel_shutdown(mesh1, channel1, SHUT_WR);
248
249         ssize_t send_ret = meshlink_channel_send(mesh1, channel1, "echo", 4);
250         assert_int_equal(send_ret, -1);
251
252         // Clean up.
253
254         meshlink_close(mesh2);
255         meshlink_close(mesh1);
256         meshlink_destroy("chan_shutdown_conf.1");
257         meshlink_destroy("chan_shutdown_conf.2");
258
259         return true;
260 }
261
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);
265 }
266
267 /* Test Steps for meshlink_channel_shutdown Test Case # 2 - Invalid case
268
269     Test Steps:
270     1. Open node instance and create a channel
271     2. Call meshlink_channel_shutdown API by passing NULL as mesh handle
272
273     Expected Result:
274     meshlink_channel_shutdown API should report proper error handling
275 */
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);
279
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);
285
286         assert(meshlink_start(mesh_handle));
287
288         meshlink_node_t *node = meshlink_get_self(mesh_handle);
289         assert(node != NULL);
290
291         meshlink_channel_t *channel = meshlink_channel_open(mesh_handle, node, 8000, NULL, NULL, 0);
292         assert(channel);
293         meshlink_set_channel_poll_cb(mesh_handle, channel, poll_cb);
294
295         // Passing NULL as mesh handle and other arguments being valid
296
297         meshlink_channel_shutdown(NULL, channel, SHUT_WR);
298         assert_int_equal(meshlink_errno, MESHLINK_EINVAL);
299
300         meshlink_close(mesh_handle);
301         meshlink_destroy("channelshutdownconf.3");
302
303         return true;
304 }
305
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);
309 }
310
311 /* Test Steps for meshlink_channel_shutdown Test Case # 3
312
313     Test Steps:
314     1. Open node instance
315     2. Call meshlink_channel_shutdown API by passing NULL as channel handle
316
317     Expected Result:
318     meshlink_channel_shutdown API should report proper error handling
319 */
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);
323
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);
329
330         assert(meshlink_start(mesh_handle));
331
332         // Passing NULL as mesh handle and other arguments being valid
333
334         meshlink_channel_shutdown(mesh_handle, NULL, SHUT_WR);
335         assert_int_equal(meshlink_errno, MESHLINK_EINVAL);
336
337         meshlink_close(mesh_handle);
338         meshlink_destroy("channelshutdownconf.4");
339
340         return true;
341 }
342
343
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)
352         };
353         total_tests += sizeof(blackbox_channel_shutdown_tests) / sizeof(blackbox_channel_shutdown_tests[0]);
354
355         return cmocka_run_group_tests(blackbox_channel_shutdown_tests, NULL, NULL);
356 }