]> git.meshlink.io Git - meshlink/blob - test/blackbox/run_blackbox_tests/test_cases_channel_shutdown.c
Fix compiler warnings in the test suites.
[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
43 static void receive_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, const void *dat, size_t len);
44 static void poll_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, size_t len);
45
46 /* State structure for meshlink_channel_shutdown Test Case #1 */
47 static black_box_state_t test_mesh_channel_shutdown_01_state = {
48         .test_case_name = "test_case_mesh_channel_shutdown_01",
49 };
50
51 /* State structure for meshlink_channel_shutdown Test Case #2 */
52 static black_box_state_t test_mesh_channel_shutdown_02_state = {
53         .test_case_name = "test_case_mesh_channel_shutdown_02",
54 };
55
56 /* State structure for meshlink_channel_shutdown Test Case #3 */
57 static black_box_state_t test_mesh_channel_shutdown_03_state = {
58         .test_case_name = "test_case_mesh_channel_shutdown_03",
59 };
60
61 static bool channel_acc;
62 static bool polled;
63 static bool foo_responded;
64 static bool bar_responded;
65
66 /* mutex for the common variable */
67 static pthread_mutex_t accept_lock = PTHREAD_MUTEX_INITIALIZER;
68 static pthread_mutex_t poll_lock = PTHREAD_MUTEX_INITIALIZER;
69 static pthread_mutex_t bar_responded_lock = PTHREAD_MUTEX_INITIALIZER;
70 static pthread_mutex_t foo_responded_lock = PTHREAD_MUTEX_INITIALIZER;
71
72 static pthread_cond_t accept_cond = PTHREAD_COND_INITIALIZER;
73 static pthread_cond_t poll_cond = PTHREAD_COND_INITIALIZER;
74 static pthread_cond_t foo_cond = PTHREAD_COND_INITIALIZER;
75 static pthread_cond_t bar_cond = PTHREAD_COND_INITIALIZER;
76
77 static bool accept_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, uint16_t port, const void *data, size_t len) {
78         (void)data;
79
80         assert(port == 7);
81         assert(!len);
82
83         meshlink_set_channel_receive_cb(mesh, channel, receive_cb);
84         channel->node->priv = channel;
85         pthread_mutex_lock(&accept_lock);
86         channel_acc = true;
87         assert(!pthread_cond_broadcast(&accept_cond));
88         pthread_mutex_unlock(&accept_lock);
89
90         return true;
91 }
92
93 /* channel receive callback */
94 static void receive_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, const void *dat, size_t len) {
95         (void)dat;
96         (void)len;
97
98         if(!strcmp(mesh->name, "foo")) {
99                 pthread_mutex_lock(& foo_responded_lock);
100                 foo_responded = true;
101                 assert(!pthread_cond_broadcast(&foo_cond));
102                 pthread_mutex_unlock(& foo_responded_lock);
103
104         } else if(!strcmp(mesh->name, "bar")) {
105                 pthread_mutex_lock(& bar_responded_lock);
106                 bar_responded = true;
107                 assert(!pthread_cond_broadcast(&bar_cond));
108                 pthread_mutex_unlock(& bar_responded_lock);
109
110                 assert(meshlink_channel_send(mesh, channel, "echo", 4) >= 0);
111
112         }
113 }
114
115 static void poll_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, size_t len) {
116         (void)len;
117
118         meshlink_set_channel_poll_cb(mesh, channel, NULL);
119         pthread_mutex_lock(&poll_lock);
120         polled = true;
121         assert(!pthread_cond_broadcast(&poll_cond));
122         pthread_mutex_unlock(&poll_lock);
123 }
124
125 /* Execute meshlink_channel_shutdown Test Case # 1*/
126 static void test_case_mesh_channel_shutdown_01(void **state) {
127         execute_test(test_steps_mesh_channel_shutdown_01, state);
128 }
129
130 /* Test Steps for meshlink_channel_shutdown Test Case # 1 - Valid case
131
132     Test Steps:
133     1. Open foo and bar instances and open a channel between them
134     2. Send data through the channel.
135     3. Shut down channel's read and send data
136     4. Shutdown channel's write and send data
137
138     Expected Result:
139     Data is able to receive through channel before shutting down,
140     On shutting down read its should not able to receive data and when write
141     is shut down its should be able to send data through channel.
142 */
143 static bool test_steps_mesh_channel_shutdown_01(void) {
144         struct timespec timeout = {0};
145         meshlink_destroy("chan_shutdown_conf.1");
146         meshlink_destroy("chan_shutdown_conf.2");
147         // Open two new meshlink instance.
148
149         meshlink_handle_t *mesh1 = meshlink_open("chan_shutdown_conf.1", "foo", "channels", DEV_CLASS_BACKBONE);
150         assert(mesh1 != NULL);
151
152         meshlink_handle_t *mesh2 = meshlink_open("chan_shutdown_conf.2", "bar", "channels", DEV_CLASS_BACKBONE);
153         assert(mesh2 != NULL);
154
155         char *data = meshlink_export(mesh1);
156         assert(data);
157         assert(meshlink_import(mesh2, data));
158         free(data);
159         data = meshlink_export(mesh2);
160         assert(data);
161         assert(meshlink_import(mesh1, data));
162         free(data);
163
164         // Set the callbacks.
165
166         meshlink_set_channel_accept_cb(mesh2, accept_cb);
167
168         // Start both instances
169
170         assert(meshlink_start(mesh1));
171         assert(meshlink_start(mesh2));
172         sleep(1);
173
174         // Open a channel from foo to bar.
175
176         meshlink_node_t *bar = meshlink_get_node(mesh1, "bar");
177         assert(bar);
178
179         meshlink_channel_t *channel1 = meshlink_channel_open(mesh1, bar, 7, receive_cb, NULL, 0);
180         meshlink_set_channel_poll_cb(mesh1, channel1, poll_cb);
181
182         timeout.tv_sec = time(NULL) + 10;
183         pthread_mutex_lock(&poll_lock);
184
185         while(polled == false) {
186                 assert(!pthread_cond_timedwait(&poll_cond, &poll_lock, &timeout));
187         }
188
189         pthread_mutex_unlock(&poll_lock);
190
191         timeout.tv_sec = time(NULL) + 10;
192         pthread_mutex_lock(&accept_lock);
193
194         while(channel_acc == false) {
195                 assert(!pthread_cond_timedwait(&accept_cond, &accept_lock, &timeout));
196         }
197
198         pthread_mutex_unlock(&accept_lock);
199
200         // Sending to bar and testing the echo
201
202         assert(meshlink_channel_send(mesh1, channel1, "echo", 4) >= 0);
203
204         timeout.tv_sec = time(NULL) + 10;
205         pthread_mutex_lock(&foo_responded_lock);
206
207         while(foo_responded == false) {
208                 assert(!pthread_cond_timedwait(&foo_cond, &foo_responded_lock, &timeout));
209         }
210
211         pthread_mutex_unlock(&foo_responded_lock);
212         assert(foo_responded);
213
214         // Shutting down channel read
215
216         meshlink_channel_shutdown(mesh1, channel1, SHUT_RD);
217         bar_responded = false;
218         foo_responded = false;
219         assert(meshlink_channel_send(mesh1, channel1, "echo", 4) >= 0);
220
221         timeout.tv_sec = time(NULL) + 10;
222         pthread_mutex_lock(&bar_responded_lock);
223
224         while(bar_responded == false) {
225                 assert(!pthread_cond_timedwait(&bar_cond, &bar_responded_lock, &timeout));
226         }
227
228         pthread_mutex_unlock(&bar_responded_lock);
229         assert_int_equal(bar_responded, true);
230         sleep(1);
231         assert_int_equal(foo_responded, false);
232
233         // Shutting down channel write
234
235         meshlink_channel_shutdown(mesh1, channel1, SHUT_WR);
236
237         ssize_t send_ret = meshlink_channel_send(mesh1, channel1, "echo", 4);
238         assert_int_equal(send_ret, -1);
239
240         // Clean up.
241
242         meshlink_close(mesh2);
243         meshlink_close(mesh1);
244         meshlink_destroy("chan_shutdown_conf.1");
245         meshlink_destroy("chan_shutdown_conf.2");
246
247         return true;
248 }
249
250 /* Execute meshlink_channel_shutdown Test Case # 2*/
251 static void test_case_mesh_channel_shutdown_02(void **state) {
252         execute_test(test_steps_mesh_channel_shutdown_02, state);
253 }
254
255 /* Test Steps for meshlink_channel_shutdown Test Case # 2 - Invalid case
256
257     Test Steps:
258     1. Open node instance and create a channel
259     2. Call meshlink_channel_shutdown API by passing NULL as mesh handle
260
261     Expected Result:
262     meshlink_channel_shutdown API should report proper error handling
263 */
264 static bool test_steps_mesh_channel_shutdown_02(void) {
265         meshlink_destroy("channelshutdownconf.3");
266         meshlink_set_log_cb(NULL, TEST_MESHLINK_LOG_LEVEL, meshlink_callback_logger);
267
268         /* Create meshlink instance */
269         meshlink_handle_t *mesh_handle = meshlink_open("channelshutdownconf.3", "nut", "node_sim", 1);
270         assert(mesh_handle != NULL);
271         meshlink_set_log_cb(mesh_handle, TEST_MESHLINK_LOG_LEVEL, meshlink_callback_logger);
272         meshlink_set_channel_accept_cb(mesh_handle, accept_cb);
273
274         assert(meshlink_start(mesh_handle));
275
276         meshlink_node_t *node = meshlink_get_self(mesh_handle);
277         assert(node != NULL);
278
279         meshlink_channel_t *channel = meshlink_channel_open(mesh_handle, node, 8000, NULL, NULL, 0);
280         assert(channel);
281         meshlink_set_channel_poll_cb(mesh_handle, channel, poll_cb);
282
283         // Passing NULL as mesh handle and other arguments being valid
284
285         meshlink_channel_shutdown(NULL, channel, SHUT_WR);
286         assert_int_equal(meshlink_errno, MESHLINK_EINVAL);
287
288         meshlink_close(mesh_handle);
289         meshlink_destroy("channelshutdownconf.3");
290
291         return true;
292 }
293
294 /* Execute meshlink_channel_shutdown Test Case # 3*/
295 static void test_case_mesh_channel_shutdown_03(void **state) {
296         execute_test(test_steps_mesh_channel_shutdown_03, state);
297 }
298
299 /* Test Steps for meshlink_channel_shutdown Test Case # 3
300
301     Test Steps:
302     1. Open node instance
303     2. Call meshlink_channel_shutdown API by passing NULL as channel handle
304
305     Expected Result:
306     meshlink_channel_shutdown API should report proper error handling
307 */
308 static bool test_steps_mesh_channel_shutdown_03(void) {
309         meshlink_destroy("channelshutdownconf.4");
310         meshlink_set_log_cb(NULL, TEST_MESHLINK_LOG_LEVEL, meshlink_callback_logger);
311
312         /* Create meshlink instance */
313         meshlink_handle_t *mesh_handle = meshlink_open("channelshutdownconf.4", "nut", "node_sim", 1);
314         assert(mesh_handle != NULL);
315         meshlink_set_log_cb(mesh_handle, TEST_MESHLINK_LOG_LEVEL, meshlink_callback_logger);
316         meshlink_set_channel_accept_cb(mesh_handle, accept_cb);
317
318         assert(meshlink_start(mesh_handle));
319
320         // Passing NULL as mesh handle and other arguments being valid
321
322         meshlink_channel_shutdown(mesh_handle, NULL, SHUT_WR);
323         assert_int_equal(meshlink_errno, MESHLINK_EINVAL);
324
325         meshlink_close(mesh_handle);
326         meshlink_destroy("channelshutdownconf.4");
327
328         return true;
329 }
330
331
332 int test_meshlink_channel_shutdown(void) {
333         const struct CMUnitTest blackbox_channel_shutdown_tests[] = {
334                 cmocka_unit_test_prestate_setup_teardown(test_case_mesh_channel_shutdown_01, NULL, NULL,
335                                 (void *)&test_mesh_channel_shutdown_01_state),
336                 cmocka_unit_test_prestate_setup_teardown(test_case_mesh_channel_shutdown_02, NULL, NULL,
337                                 (void *)&test_mesh_channel_shutdown_02_state),
338                 cmocka_unit_test_prestate_setup_teardown(test_case_mesh_channel_shutdown_03, NULL, NULL,
339                                 (void *)&test_mesh_channel_shutdown_03_state)
340         };
341         total_tests += sizeof(blackbox_channel_shutdown_tests) / sizeof(blackbox_channel_shutdown_tests[0]);
342
343         return cmocka_run_group_tests(blackbox_channel_shutdown_tests, NULL, NULL);
344 }