]> git.meshlink.io Git - meshlink/blob - test/blackbox/run_blackbox_tests/test_cases_get_node_reachability.c
Updated test vectors for get node reachability
[meshlink] / test / blackbox / run_blackbox_tests / test_cases_get_node_reachability.c
1 /*
2     test_cases_get_node_reachability.c -- Execution of specific meshlink black box test cases
3     Copyright (C) 2019  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 #ifdef NDEBUG
21 #undef NDEBUG
22 #endif
23
24 #include <assert.h>
25 #include <string.h>
26 #include <stdlib.h>
27 #include <stdarg.h>
28 #include <setjmp.h>
29 #include <cmocka.h>
30 #include <pthread.h>
31 #include <stdio.h>
32 #include <sys/types.h>
33 #include <dirent.h>
34 #include <sys/wait.h>
35 #include <signal.h>
36 #include <sys/stat.h>
37 #include <unistd.h>
38 #include <utime.h>
39 #include "execute_tests.h"
40 #include "test_cases_get_node_reachability.h"
41 #include "../common/test_step.h"
42 #include "../common/common_handlers.h"
43 #include "../../utils.h"
44
45 #define NUT                         "nut"
46 #define PEER                        "peer"
47 #define PEER2                       "peer2"
48 #define GET_NODE_REACHABILITY       "test_get_node_reachability"
49 #define create_path(confbase, node_name, test_case_no)   assert(snprintf(confbase, sizeof(confbase), GET_NODE_REACHABILITY "_%ld_%s_%02d", (long) getpid(), node_name, test_case_no) > 0)
50
51 static struct sync_flag peer_reachable_status_cond = {.mutex  = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER};
52 static bool peer_reachable_status;
53 static struct sync_flag nut_reachable_status_cond = {.mutex  = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER};
54 static bool nut_reachable_status;
55 static struct sync_flag nut_started_status_cond = {.mutex  = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER};
56 static bool peer_node_callback_test_status;
57
58 static void test_case_get_node_reachability_01(void **state);
59 static bool test_get_node_reachability_01(void);
60 static void test_case_get_node_reachability_02(void **state);
61 static bool test_get_node_reachability_02(void);
62 static void test_case_get_node_reachability_03(void **state);
63 static bool test_get_node_reachability_03(void);
64 static void test_case_get_node_reachability_04(void **state);
65 static bool test_get_node_reachability_04(void);
66 static void test_case_get_node_reachability_05(void **state);
67 static bool test_get_node_reachability_05(void);
68 static void test_case_get_node_reachability_06(void **state);
69 static bool test_get_node_reachability_06(void);
70 static void test_case_get_node_reachability_07(void **state);
71 static bool test_get_node_reachability_07(void);
72
73 /* Node reachable status callback which signals the respective conditional varibale */
74 static void meshlink_node_reachable_status_cb(meshlink_handle_t *mesh, meshlink_node_t *node, bool reachable_status) {
75         if(meshlink_get_self(mesh) == node) {
76                 return;
77         }
78
79         if(!strcasecmp(mesh->name, NUT)) {
80                 if(!strcasecmp(node->name, PEER)) {
81                         peer_reachable_status = reachable_status;
82                         set_sync_flag(&peer_reachable_status_cond, true);
83                 }
84         } else if(!strcasecmp(mesh->name, PEER)) {
85                 if(!strcasecmp(node->name, NUT)) {
86                         nut_reachable_status = reachable_status;
87                         set_sync_flag(&nut_reachable_status_cond, true);
88                 }
89         }
90
91         // Reset the node reachability status callback, as the two nodes making a simultaneous connection to each other, and then one connection will win and cause the other one to be disconnected.
92         meshlink_set_node_status_cb(mesh, NULL);
93 }
94
95 static void meshlink_node_reachable_status_cb_2(meshlink_handle_t *mesh, meshlink_node_t *node, bool reachable_status) {
96         meshlink_node_t *peer_handle;
97         char *peer_name = NULL;
98         time_t last_unreachable, last_reachable;
99         static int count = 2;
100
101         if(meshlink_get_self(mesh) == node) {
102                 return;
103         }
104
105         /*  Of the 2 node reachable callbacks, the latest callback calls meshlink_get_node_reachability API
106             for the 1st node joined  */
107         if(count && reachable_status && !strcasecmp(mesh->name, NUT)) {
108                 --count;
109
110                 if(!count) {
111                         if(!strcasecmp(node->name, PEER)) {
112                                 peer_name = PEER2;
113                         } else if(!strcasecmp(node->name, PEER2)) {
114                                 peer_name = PEER;
115                         }
116
117                         peer_handle = meshlink_get_node(mesh, peer_name);
118                         assert_non_null(peer_handle);
119
120                         bool status = meshlink_get_node_reachability(mesh, peer_handle, &last_reachable, &last_unreachable);
121
122                         peer_node_callback_test_status = status && last_reachable && !last_unreachable;
123                         set_sync_flag(&peer_reachable_status_cond, true);
124                 }
125         }
126 }
127
128 /* SIGUSR2 signal handler that signals the NUT started and PEER node can join */
129 void nut_started_user_signal_handler(int signum) {
130         if(signum == SIGUSR2) {
131                 set_sync_flag(&nut_started_status_cond, true);
132         }
133
134 }
135
136 /*
137     Execute meshlink get last node reachability times feature Test Case # 1 -
138     Sanity API test
139 */
140 static void test_case_get_node_reachability_01(void **state) {
141         execute_test(test_get_node_reachability_01, state);
142 }
143
144 /* Test Steps for meshlink_get_node_reachability Test Case # 1
145
146     Test steps and scenarios:
147     1.  Open Node-Under-Test (NUT) instance, Call meshlink_get_node_reachability API
148         with valid mesh handle, self node handle,  last_reachable pointer and
149         last_unreachable pointer.
150         Expected Result:
151         API returns self node unreachable, last_reachable and last_unreachable values
152         as 0 seconds
153
154     2.  Call meshlink_get_node_reachability API with valid mesh handle, self node handle.
155         But pass NULL pointers for last_reachable and last_unreachable arguments
156         Expected Result:
157         API returns self node unreachable
158
159     3.  Call meshlink_get_node_reachability API with NULL as mesh handle,
160         valid self node handle, last_reachable pointer and last_unreachable pointer.
161         Expected Result:
162         API fails and sets MESHLINK_EINVAL as meshlink errno value
163
164     4.  Call meshlink_get_node_reachability API with NULL as mesh handle,
165         valid self node handle, NULL pointers for last_reachable and last_unreachable
166         arguments
167         Expected Result:
168         API fails and sets MESHLINK_EINVAL as meshlink errno value
169
170     5.  Call meshlink_get_node_reachability API with valid mesh handle,
171         NULL as self node handle, last_reachable pointer and last_unreachable pointer.
172         Expected Result:
173         API fails and sets MESHLINK_EINVAL as meshlink errno value
174
175     6.  Call meshlink_get_node_reachability API with valid mesh handle,
176         NULL as self node handle, NULL pointers for last_reachable and last_unreachable
177         arguments
178         Expected Result:
179         API fails and sets MESHLINK_EINVAL as meshlink errno value
180
181 */
182 static bool test_get_node_reachability_01(void) {
183         bool status;
184         time_t last_unreachable, last_reachable;
185         char nut_confbase[PATH_MAX];
186         create_path(nut_confbase, NUT, 1);
187
188         meshlink_set_log_cb(NULL, MESHLINK_DEBUG, log_cb);
189
190         // Open Node-Under-Test node instance
191
192         meshlink_handle_t *mesh = meshlink_open(nut_confbase, NUT, GET_NODE_REACHABILITY, DEV_CLASS_STATIONARY);
193         assert_int_not_equal(mesh, NULL);
194
195         // Call meshlink_get_node_reachability API with all valid arguments
196
197         status = meshlink_get_node_reachability(mesh, meshlink_get_self(mesh), &last_reachable, &last_unreachable);
198         assert_int_equal(status, false);
199         assert_int_equal(last_reachable, 0);
200         assert_int_equal(last_unreachable, 0);
201
202         // Call meshlink_get_node_reachability API with all valid arguments
203
204         status = meshlink_get_node_reachability(mesh, meshlink_get_self(mesh), NULL, NULL);
205         assert_int_equal(status, false);
206
207         // Call meshlink_get_node_reachability API with invalid parameters
208
209         meshlink_errno = MESHLINK_OK;
210         meshlink_get_node_reachability(NULL, meshlink_get_self(mesh), NULL, NULL);
211         assert_int_equal(meshlink_errno, MESHLINK_EINVAL);
212         meshlink_errno = MESHLINK_OK;
213         meshlink_get_node_reachability(NULL, meshlink_get_self(mesh), &last_reachable, &last_unreachable);
214         assert_int_equal(meshlink_errno, MESHLINK_EINVAL);
215         meshlink_errno = MESHLINK_OK;
216         meshlink_get_node_reachability(mesh, NULL, NULL, NULL);
217         assert_int_equal(meshlink_errno, MESHLINK_EINVAL);
218         meshlink_errno = MESHLINK_OK;
219         meshlink_get_node_reachability(mesh, NULL, &last_reachable, &last_unreachable);
220         assert_int_equal(meshlink_errno, MESHLINK_EINVAL);
221
222         // Cleanup
223
224         meshlink_close(mesh);
225         assert_true(meshlink_destroy(nut_confbase));
226         return true;
227 }
228
229 /*
230     Execute meshlink get last node reachability times feature Test Case # 2 -
231     API testing with stand-alone node
232 */
233 static void test_case_get_node_reachability_02(void **state) {
234         execute_test(test_get_node_reachability_02, state);
235 }
236
237 /* Test Steps for meshlink_get_node_reachability Test Case # 2
238
239     Test steps and scenarios:
240     1.  Open and start Node-Under-Test (NUT) instance, Call meshlink_get_node_reachability API.
241         Expected Result:
242         API returns self node reachable status, last_reachable as some positive non-zero integer
243         and last_unreachable value as 0 seconds
244
245     2.  Stop the NUT instance, Call meshlink_get_node_reachability API.
246         Expected Result:
247         API returns self node unreachable, both last_reachable and last_unreachable values
248         as some positive non-zero time in seconds
249
250     3.  Close and reopen NUT instance, Call meshlink_get_node_reachability API.
251         Expected Result:
252         API returns self node unreachable, both last_reachable and last_unreachable values
253         as some positive non-zero time in seconds
254
255 */
256 static bool test_get_node_reachability_02(void) {
257         bool status;
258         time_t last_unreachable, last_reachable, last_peer_unreachable, last_peer_reachable;
259         char nut_confbase[PATH_MAX];
260         create_path(nut_confbase, NUT, 2);
261         meshlink_set_log_cb(NULL, MESHLINK_DEBUG, log_cb);
262
263         // Open and start Node-Under-Test node instance
264
265         meshlink_handle_t *mesh = meshlink_open(nut_confbase, NUT, GET_NODE_REACHABILITY, DEV_CLASS_STATIONARY);
266         assert_non_null(mesh);
267         assert_true(meshlink_start(mesh));
268
269         // Call meshlink_get_node_reachability API with all valid arguments
270
271         status = meshlink_get_node_reachability(mesh, meshlink_get_self(mesh), &last_reachable, &last_unreachable);
272         assert_true(status);
273         assert_int_not_equal(last_reachable, 0);
274         assert_int_equal(last_unreachable, 0);
275         last_peer_reachable = last_reachable;
276
277         // Stop NUT node instance
278
279         meshlink_stop(mesh);
280
281         // Call meshlink_get_node_reachability API with all valid arguments
282
283         status = meshlink_get_node_reachability(mesh, meshlink_get_self(mesh), &last_reachable, &last_unreachable);
284         assert_false(status);
285         assert_int_not_equal(last_unreachable, 0);
286         assert_int_equal(last_reachable, last_peer_reachable);
287         last_peer_unreachable = last_unreachable;
288
289         // Reinitialize NUT node instance
290
291         meshlink_close(mesh);
292         mesh = meshlink_open(nut_confbase, NUT, GET_NODE_REACHABILITY, DEV_CLASS_STATIONARY);
293         assert_non_null(mesh);
294
295         // Call meshlink_get_node_reachability API with all valid arguments
296
297         status = meshlink_get_node_reachability(mesh, meshlink_get_self(mesh), &last_reachable, &last_unreachable);
298         assert_false(status);
299         assert_int_equal(last_reachable, last_peer_reachable);
300         assert_int_equal(last_unreachable, last_peer_unreachable);
301
302         // Cleanup
303
304         meshlink_close(mesh);
305         assert_true(meshlink_destroy(nut_confbase));
306         return true;
307 }
308
309 /*
310     Execute meshlink get last node reachability times feature Test Case # 3 -
311     API testing with host node which already joined with a peer node which later
312     goes offline, test host node with an offline peer node case.
313 */
314 static void test_case_get_node_reachability_03(void **state) {
315         execute_test(test_get_node_reachability_03, state);
316 }
317
318 /* Test Steps for meshlink_get_node_reachability Test Case # 3
319
320     Test steps and scenarios:
321     1.  Open Node-Under-Test (NUT) and peer node instance, start peer node instance
322         and invite NUT. NUT joins peer and destroy peer node instance.
323         Call meshlink_get_node_reachability API.
324         Expected Result:
325         API returns peer node unreachable status, last_reachable and last_unreachable
326         value as 0 seconds.
327
328     2.  Start the NUT instance, Call meshlink_get_node_reachability API.
329         Expected Result:
330         API returns peer node unreachable status, last_reachable and last_unreachable
331         value as 0 seconds.
332
333     3.  Stop the NUT instance, Call meshlink_get_node_reachability API.
334         Expected Result:
335         API returns peer node unreachable status, last_reachable and last_unreachable
336         value as 0 seconds.
337
338     4.  Close and reopen NUT instance, Call meshlink_get_node_reachability API.
339         Expected Result:
340         API returns peer node unreachable status, last_reachable and last_unreachable
341         value as 0 seconds.
342
343 */
344 static bool test_get_node_reachability_03(void) {
345         bool status;
346         time_t last_unreachable, last_reachable;
347         char nut_confbase[PATH_MAX];
348         char peer_confbase[PATH_MAX];
349         create_path(nut_confbase, NUT, 3);
350         create_path(peer_confbase, PEER, 3);
351
352         meshlink_set_log_cb(NULL, MESHLINK_DEBUG, log_cb);
353
354         // Open and start peer node instance, invite NUT.
355
356         meshlink_handle_t *mesh_peer = meshlink_open(peer_confbase, PEER, GET_NODE_REACHABILITY,
357                                        DEV_CLASS_STATIONARY);
358         assert_non_null(mesh_peer);
359         assert_true(meshlink_start(mesh_peer));
360         char *invitation = meshlink_invite(mesh_peer, NULL, NUT);
361         assert_non_null(invitation);
362
363         // Open NUT node instance and join with the peer node
364
365         meshlink_handle_t *mesh = meshlink_open(nut_confbase, NUT, GET_NODE_REACHABILITY, DEV_CLASS_STATIONARY);
366         assert_non_null(mesh);
367         assert_true(meshlink_join(mesh, invitation));
368         free(invitation);
369         meshlink_node_t *peer_handle = meshlink_get_node(mesh, PEER);
370         assert_non_null(peer_handle);
371
372         // Cleanup peer node instance
373
374         meshlink_close(mesh_peer);
375         assert_true(meshlink_destroy(peer_confbase));
376
377         // Call meshlink_get_node_reachability API with valid arguments
378
379         status = meshlink_get_node_reachability(mesh, peer_handle, &last_reachable, &last_unreachable);
380         assert_false(status);
381         assert_int_equal(last_reachable, 0);
382         assert_int_equal(last_unreachable, 0);
383
384         // Start NUT node instance
385
386         assert_true(meshlink_start(mesh));
387
388         // Call meshlink_get_node_reachability API with valid arguments
389
390         status = meshlink_get_node_reachability(mesh, peer_handle, &last_reachable, &last_unreachable);
391         assert_false(status);
392         assert_int_equal(last_reachable, 0);
393         assert_int_equal(last_unreachable, 0);
394
395         // Stop NUT node instance
396
397         meshlink_stop(mesh);
398
399         // Call meshlink_get_node_reachability API with valid arguments
400
401         status = meshlink_get_node_reachability(mesh, peer_handle, &last_reachable, &last_unreachable);
402         assert_false(status);
403         assert_int_equal(last_reachable, 0);
404         assert_int_equal(last_unreachable, 0);
405
406         // Reinitialize NUT node instance
407
408         meshlink_close(mesh);
409         mesh = meshlink_open(nut_confbase, NUT, GET_NODE_REACHABILITY, DEV_CLASS_STATIONARY);
410         assert_non_null(mesh);
411         peer_handle = meshlink_get_node(mesh, PEER);
412         assert_non_null(peer_handle);
413
414         // Call meshlink_get_node_reachability API with valid arguments
415
416         status = meshlink_get_node_reachability(mesh, peer_handle, &last_reachable, &last_unreachable);
417         assert_false(status);
418         assert_int_equal(last_reachable, 0);
419         assert_int_equal(last_unreachable, 0);
420
421         // Cleanup NUT
422
423         meshlink_close(mesh);
424         assert_true(meshlink_destroy(nut_confbase));
425         return true;
426 }
427
428 /*
429     Execute meshlink get last node reachability times feature Test Case # 4 -
430     API testing around invited and invitee node.
431 */
432 static void test_case_get_node_reachability_04(void **state) {
433         execute_test(test_get_node_reachability_04, state);
434 }
435
436 /* Test Steps for meshlink_get_node_reachability Test Case # 4
437
438     Test steps and scenarios:
439     1.  Open Node-Under-Test (NUT) and peer node instance, join both the node and
440         bring them online. Call meshlink_get_node_reachability API from both the nodes.
441         Expected Result:
442         API for both the nodes returns reachable status, last_reachable should be
443          some non-zero positive seconds and last_unreachable should be 0 seconds.
444
445     2.  Stop both the node instances, Call meshlink_get_node_reachability API from both the nodes.
446         Expected Result:
447         API for both the nodes returns unreachable status. last_reachable should match with
448         the old value and last_unreachable should be non-zero positive value.
449
450     3.  Restart both the node instances, Call meshlink_get_node_reachability APIs.
451         Expected Result:
452         API for both the nodes should return reachable status. last_reachable should not match with
453         the old value, but last_unreachable should remain same
454
455     4.  Close and reopen both the node instances, Call meshlink_get_node_reachability APIs.
456         Expected Result:
457         API returns self node unreachable status, last_reachable should remain same
458         but last_unreachable should vary.
459
460     4.  Start both the node instances, Call meshlink_get_node_reachability APIs.
461         Expected Result:
462         API returns self node reachable status, last_reachable should vary and
463         last_unreachable remains same.
464
465 */
466 static bool test_get_node_reachability_04(void) {
467         bool status;
468         time_t last_nut_unreachable, last_nut_reachable;
469         time_t last_peer_unreachable, last_peer_reachable;
470         time_t last_reachable, last_unreachable;
471         char nut_confbase[PATH_MAX];
472         char peer_confbase[PATH_MAX];
473         create_path(nut_confbase, NUT, 4);
474         create_path(peer_confbase, PEER, 4);
475         meshlink_set_log_cb(NULL, MESHLINK_DEBUG, log_cb);
476
477         // Open both NUT and peer node instance, invite and join NUT with peer node.
478
479         meshlink_handle_t *mesh_peer = meshlink_open(peer_confbase, PEER, GET_NODE_REACHABILITY,
480                                        DEV_CLASS_STATIONARY);
481         assert_non_null(mesh_peer);
482         meshlink_set_node_status_cb(mesh_peer, meshlink_node_reachable_status_cb);
483         char *invitation = meshlink_invite(mesh_peer, NULL, NUT);
484         assert_non_null(invitation);
485         assert_true(meshlink_start(mesh_peer));
486
487         meshlink_handle_t *mesh = meshlink_open(nut_confbase, NUT, GET_NODE_REACHABILITY,
488                                                 DEV_CLASS_STATIONARY);
489         assert_non_null(mesh);
490         meshlink_set_node_status_cb(mesh, meshlink_node_reachable_status_cb);
491         assert_true(meshlink_join(mesh, invitation));
492         free(invitation);
493
494         meshlink_node_t *peer_handle = meshlink_get_node(mesh, PEER);
495         assert_non_null(peer_handle);
496         meshlink_node_t *nut_handle = meshlink_get_node(mesh_peer, NUT);
497         assert_non_null(nut_handle);
498
499         // Bring nodes online.
500
501         set_sync_flag(&peer_reachable_status_cond, false);
502         set_sync_flag(&nut_reachable_status_cond, false);
503         assert_true(meshlink_start(mesh));
504         assert_true(wait_sync_flag(&peer_reachable_status_cond, 60));
505         assert_true(peer_reachable_status);
506         assert_true(wait_sync_flag(&nut_reachable_status_cond, 60));
507         assert_true(nut_reachable_status);
508
509         // Call meshlink_get_node_reachability API from joined node and also from joining node.
510
511         status = meshlink_get_node_reachability(mesh, peer_handle, &last_reachable, &last_unreachable);
512         assert_true(status);
513         assert_int_not_equal(last_reachable, 0);
514         assert_int_equal(last_unreachable, 0);
515         last_peer_reachable = last_reachable;
516
517         status = meshlink_get_node_reachability(mesh_peer, nut_handle, &last_reachable, &last_unreachable);
518         assert_true(status);
519         assert_int_not_equal(last_reachable, 0);
520         assert_int_equal(last_unreachable, 0);
521         last_nut_reachable = last_reachable;
522
523         // Stop the node instances of both peer and NUT.
524
525         meshlink_stop(mesh);
526         meshlink_stop(mesh_peer);
527
528         // Call meshlink_get_node_reachability API from joined node and also from joining node.
529
530         status = meshlink_get_node_reachability(mesh, peer_handle, &last_reachable, &last_unreachable);
531         assert_false(status);
532         assert_int_not_equal(last_unreachable, 0);
533         assert_int_equal(last_reachable, last_peer_reachable);
534         last_peer_unreachable = last_unreachable;
535
536         status = meshlink_get_node_reachability(mesh_peer, nut_handle, &last_reachable, &last_unreachable);
537         assert_false(status);
538         assert_int_not_equal(last_unreachable, 0);
539         assert_int_equal(last_reachable, last_nut_reachable);
540         last_nut_unreachable = last_unreachable;
541
542         // Restart the node instances of both peer and NUT and wait for nodes to come online
543
544         sleep(2);
545         set_sync_flag(&peer_reachable_status_cond, false);
546         set_sync_flag(&nut_reachable_status_cond, false);
547         meshlink_set_node_status_cb(mesh, meshlink_node_reachable_status_cb);
548         meshlink_set_node_status_cb(mesh_peer, meshlink_node_reachable_status_cb);
549         assert_true(meshlink_start(mesh));
550         assert_true(meshlink_start(mesh_peer));
551
552         assert_true(wait_sync_flag(&peer_reachable_status_cond, 60));
553         assert_true(peer_reachable_status);
554         assert_true(wait_sync_flag(&nut_reachable_status_cond, 60));
555         assert_true(nut_reachable_status);
556
557         // Call meshlink_get_node_reachability API from joined node and also from joining node.
558
559         status = meshlink_get_node_reachability(mesh, peer_handle, &last_reachable, &last_unreachable);
560         assert_true(status);
561         assert_int_not_equal(last_reachable, last_peer_reachable);
562         assert_true(last_unreachable >= last_peer_unreachable);
563         last_peer_reachable = last_reachable;
564
565         status = meshlink_get_node_reachability(mesh_peer, nut_handle, &last_reachable, &last_unreachable);
566         assert_true(status);
567         assert_int_not_equal(last_reachable, last_nut_reachable);
568         assert_true(last_unreachable >= last_nut_unreachable);
569         last_nut_reachable = last_reachable;
570
571         // Reinitialize the node instances of both peer and NUT
572
573         meshlink_close(mesh);
574         meshlink_close(mesh_peer);
575
576         sleep(2);
577
578         mesh = meshlink_open(nut_confbase, NUT, GET_NODE_REACHABILITY, DEV_CLASS_STATIONARY);
579         assert_non_null(mesh);
580         meshlink_set_node_status_cb(mesh, meshlink_node_reachable_status_cb);
581         mesh_peer = meshlink_open(peer_confbase, PEER, GET_NODE_REACHABILITY,
582                                   DEV_CLASS_STATIONARY);
583         assert_non_null(mesh_peer);
584         meshlink_set_node_status_cb(mesh_peer, meshlink_node_reachable_status_cb);
585
586         peer_handle = meshlink_get_node(mesh, PEER);
587         assert_non_null(peer_handle);
588         nut_handle = meshlink_get_node(mesh_peer, NUT);
589         assert_non_null(nut_handle);
590
591         // Call meshlink_get_node_reachability API from joined node and also from joining node.
592
593         status = meshlink_get_node_reachability(mesh, peer_handle, &last_reachable, &last_unreachable);
594         assert_false(status);
595         assert_int_equal(last_reachable, last_peer_reachable);
596         assert_int_not_equal(last_unreachable, last_peer_unreachable);
597         last_peer_unreachable = last_unreachable;
598
599         status = meshlink_get_node_reachability(mesh_peer, nut_handle, &last_reachable, &last_unreachable);
600         assert_false(status);
601         assert_int_equal(last_reachable, last_nut_reachable);
602         assert_int_not_equal(last_unreachable, last_nut_unreachable);
603         last_nut_unreachable = last_unreachable;
604
605         // Restart the node instances of both peer and NUT
606
607         set_sync_flag(&peer_reachable_status_cond, false);
608         set_sync_flag(&nut_reachable_status_cond, false);
609
610         assert_true(meshlink_start(mesh));
611         assert_true(meshlink_start(mesh_peer));
612
613         assert_true(wait_sync_flag(&peer_reachable_status_cond, 60));
614         assert_true(peer_reachable_status);
615         assert_true(wait_sync_flag(&nut_reachable_status_cond, 60));
616         assert_true(nut_reachable_status);
617
618         // Call meshlink_get_node_reachability API from joined node and also from joining node.
619
620         status = meshlink_get_node_reachability(mesh, peer_handle, &last_reachable, &last_unreachable);
621         assert_true(status);
622         assert_int_not_equal(last_reachable, last_peer_reachable);
623         assert_true(last_unreachable >= last_peer_unreachable);
624
625         status = meshlink_get_node_reachability(mesh_peer, nut_handle, &last_reachable, &last_unreachable);
626         assert_true(status);
627         assert_int_not_equal(last_reachable, last_nut_reachable);
628         assert_true(last_unreachable >= last_nut_unreachable);
629
630         // Cleanup
631
632         meshlink_close(mesh);
633         meshlink_close(mesh_peer);
634         assert_true(meshlink_destroy(nut_confbase));
635         assert_true(meshlink_destroy(peer_confbase));
636         return true;
637 }
638
639 /*
640     Execute meshlink get last node reachability times feature Test Case # 5 -
641     API testing by calling it in the meshlink callback(s) and also isolation property.
642 */
643 static void test_case_get_node_reachability_05(void **state) {
644         execute_test(test_get_node_reachability_05, state);
645 }
646
647 /* Test Steps for meshlink_get_node_reachability Test Case # 5
648
649     Test steps and scenarios:
650     1.  Open Node-Under-Test (NUT), peer and peer2 node instances. Join both the peer nodes
651         with NUT and bring them online.
652         Expected Result:
653         API called from the node reachable callback of the latest peer node from NUT
654         about other peer node which joined 1st should return reachable status,
655         last_reachable status as some positive non-zero value and last unreachable value as 0.
656
657 */
658 static bool test_get_node_reachability_05(void) {
659         char *invitation;
660         bool status;
661         time_t last_reachable, last_unreachable;
662         char nut_confbase[PATH_MAX];
663         char peer_confbase[PATH_MAX];
664         char peer2_confbase[PATH_MAX];
665         create_path(nut_confbase, NUT, 5);
666         create_path(peer_confbase, PEER, 5);
667         create_path(peer2_confbase, PEER2, 5);
668         meshlink_set_log_cb(NULL, MESHLINK_DEBUG, log_cb);
669
670         // Open NUT, peer and peer2 and join peer nodes with NUT.
671
672         meshlink_handle_t *mesh = meshlink_open(nut_confbase, NUT, GET_NODE_REACHABILITY,
673                                                 DEV_CLASS_STATIONARY);
674         assert_non_null(mesh);
675         meshlink_set_node_status_cb(mesh, meshlink_node_reachable_status_cb_2);
676         meshlink_handle_t *mesh_peer = meshlink_open(peer_confbase, PEER, GET_NODE_REACHABILITY,
677                                        DEV_CLASS_STATIONARY);
678         assert_non_null(mesh_peer);
679         meshlink_handle_t *mesh_peer2 = meshlink_open(peer2_confbase, PEER2, GET_NODE_REACHABILITY,
680                                         DEV_CLASS_STATIONARY);
681         assert_non_null(mesh_peer2);
682
683         assert_true(meshlink_start(mesh));
684
685         invitation = meshlink_invite(mesh, NULL, PEER);
686         assert_non_null(invitation);
687         assert_true(meshlink_join(mesh_peer, invitation));
688         invitation = meshlink_invite(mesh, NULL, PEER2);
689         assert_non_null(invitation);
690         assert_true(meshlink_join(mesh_peer2, invitation));
691
692         // Call meshlink_get_node_reachability API from NUT and check they remained 0 and unreachable
693
694         status = meshlink_get_node_reachability(mesh, meshlink_get_node(mesh, PEER), &last_reachable, &last_unreachable);
695         assert_int_equal(status, false);
696         assert_int_equal(last_reachable, 0);
697         assert_int_equal(last_unreachable, 0);
698         status = meshlink_get_node_reachability(mesh, meshlink_get_node(mesh, PEER2), &last_reachable, &last_unreachable);
699         assert_int_equal(status, false);
700         assert_int_equal(last_reachable, 0);
701         assert_int_equal(last_unreachable, 0);
702
703         // Start and wait for the signal from the node reachable callback which is raised when
704         // NUT is able to call meshlink_get_node_reachability API from callback of other peer node.
705
706         set_sync_flag(&peer_reachable_status_cond, false);
707         assert_true(meshlink_start(mesh_peer));
708         assert_true(meshlink_start(mesh_peer2));
709         assert_true(wait_sync_flag(&peer_reachable_status_cond, 60));
710         assert_true(peer_node_callback_test_status);
711
712         // Cleanup
713
714         meshlink_close(mesh);
715         meshlink_close(mesh_peer);
716         meshlink_close(mesh_peer2);
717         assert_true(meshlink_destroy(nut_confbase));
718         assert_true(meshlink_destroy(peer_confbase));
719         assert_true(meshlink_destroy(peer2_confbase));
720         return true;
721 }
722
723 /*
724     Execute meshlink get last node reachability times feature Test Case # 6 -
725     Persistence testing on the joining node.
726 */
727 static void test_case_get_node_reachability_06(void **state) {
728         execute_test(test_get_node_reachability_06, state);
729 }
730
731 /* Test Steps for meshlink_get_node_reachability Test Case # 6
732
733     Test steps and scenarios:
734     1.  Open Node-Under-Test (NUT) and invite peer node and close it's instance.
735         Spawn a process which waits for the peer node to join and raises SIGINT if the
736         appropriate callback is received (on the other hand the test suite opens and joins
737         the peer node with NUT in the forked process).
738         Reopen NUT instance in the test suite process and call meshlink_get_node_reachability.
739         Expected Result:
740         API returns peer node unreachable, last_reachable and last_unreachable values
741         as 0 seconds. It is expected that this feature synchronize it at least for the first time
742         when the NUT receives that a new peer node joined.
743
744 */
745 static bool test_get_node_reachability_06(void) {
746         bool status;
747         time_t last_reachable, last_unreachable;
748         pid_t pid;
749         int pid_status;
750         char nut_confbase[PATH_MAX];
751         char peer_confbase[PATH_MAX];
752         create_path(nut_confbase, NUT, 6);
753         create_path(peer_confbase, PEER, 6);
754         meshlink_set_log_cb(NULL, MESHLINK_DEBUG, log_cb);
755
756         // Open NUT node instance and invite peer node. Close NUT node instance.
757
758         meshlink_handle_t *mesh = meshlink_open(nut_confbase, NUT, GET_NODE_REACHABILITY, DEV_CLASS_STATIONARY);
759         assert_non_null(mesh);
760         char *invitation = meshlink_invite(mesh, NULL, PEER);
761         meshlink_close(mesh);
762
763         // Set the SIGUSR2 signal handler with handler that signal the condition to the test suite
764
765         sighandler_t usr2sighandler = signal(SIGUSR2, nut_started_user_signal_handler);
766         assert_int_not_equal(usr2sighandler, SIG_ERR);
767
768         // Fork a new process and run NUT in it which just waits for the peer node reachable status callback
769         // and terminates the process immediately.
770
771         pid = fork();
772         assert_int_not_equal(pid, -1);
773
774         if(!pid) {
775                 assert(signal(SIGUSR2, SIG_DFL) != SIG_ERR);
776
777                 mesh = meshlink_open(nut_confbase, NUT, GET_NODE_REACHABILITY, DEV_CLASS_STATIONARY);
778                 assert(mesh);
779                 meshlink_set_log_cb(mesh, MESHLINK_DEBUG, log_cb);
780                 meshlink_set_node_status_cb(mesh, meshlink_node_reachable_status_cb);
781
782                 set_sync_flag(&peer_reachable_status_cond, false);
783                 assert(meshlink_start(mesh));
784
785                 assert(kill(getppid(), SIGUSR2) != -1);
786
787                 assert(wait_sync_flag(&peer_reachable_status_cond, 60));
788                 assert(peer_reachable_status);
789
790                 raise(SIGINT);
791         }
792
793         // Open peer node instance and join with the invitation obtained.
794
795         meshlink_handle_t *mesh_peer = meshlink_open(peer_confbase, PEER, GET_NODE_REACHABILITY,
796                                        DEV_CLASS_STATIONARY);
797         assert_non_null(mesh_peer);
798
799         // Wait for the started signal from NUT and reset the previous SIGUSR2 signal handler
800
801         assert_true(wait_sync_flag(&nut_started_status_cond, 60));
802         assert_int_not_equal(signal(SIGUSR2, usr2sighandler), SIG_ERR);
803
804         assert_true(meshlink_join(mesh_peer, invitation));
805         assert_true(meshlink_start(mesh_peer));
806
807         // Wait for child exit and verify which signal terminated it
808
809         assert_int_not_equal(waitpid(pid, &pid_status, 0), -1);
810         assert_int_equal(WIFSIGNALED(pid_status), true);
811         assert_int_equal(WTERMSIG(pid_status), SIGINT);
812
813         // Reopen the NUT instance in the same test suite
814
815         mesh = meshlink_open(nut_confbase, NUT, GET_NODE_REACHABILITY, DEV_CLASS_STATIONARY);
816         assert_non_null(mesh);
817
818         // Call meshlink_get_node_reachability API and verify that the time stamps has persisted.
819
820         status = meshlink_get_node_reachability(mesh, meshlink_get_node(mesh, PEER), &last_reachable, &last_unreachable);
821         assert_int_equal(status, false);
822         assert_int_not_equal(last_reachable, 0);
823         assert_int_equal(last_unreachable, 0);
824
825         // Cleanup
826
827         meshlink_close(mesh);
828         meshlink_close(mesh_peer);
829         assert_true(meshlink_destroy(nut_confbase));
830         assert_true(meshlink_destroy(peer_confbase));
831         return true;
832 }
833
834 /*
835     Execute meshlink get last node reachability times feature Test Case # 7 -
836     Persistence testing on the invited node.
837 */
838 static void test_case_get_node_reachability_07(void **state) {
839         execute_test(test_get_node_reachability_07, state);
840 }
841
842 /* Test Steps for meshlink_get_node_reachability Test Case # 7
843
844     Test steps and scenarios:
845     1.  Open peer node instance, invite NUT and start peer node. Spawn a new process in
846         which it opens and joins the NUT with peer node.
847         Reopen NUT instance in the test suite process and call meshlink_get_node_reachability API.
848         Expected Result:
849         API returns peer node unreachable, last_reachable and last_unreachable values
850         as 0 seconds. It is expected that this feature synchronize it at least for the first time
851         when the Node-Under-Test joined with the peer node.
852
853 */
854 static bool test_get_node_reachability_07(void) {
855         bool status;
856         time_t last_reachable, last_unreachable;
857         pid_t pid;
858         int pid_status;
859         char nut_confbase[PATH_MAX];
860         char peer_confbase[PATH_MAX];
861         create_path(nut_confbase, NUT, 7);
862         create_path(peer_confbase, PEER, 7);
863         meshlink_set_log_cb(NULL, MESHLINK_DEBUG, log_cb);
864
865         // Open peer node instance and invite NUT.
866
867         meshlink_handle_t *mesh_peer = meshlink_open(peer_confbase, PEER, GET_NODE_REACHABILITY,
868                                        DEV_CLASS_STATIONARY);
869         assert_int_not_equal(mesh_peer, NULL);
870         char *invitation = meshlink_invite(mesh_peer, NULL, NUT);
871         assert_non_null(invitation);
872
873         assert_true(meshlink_start(mesh_peer));
874
875         // Fork a new process in which NUT is joins with the peer node and raises SIGINT to terminate.
876
877         pid = fork();
878         assert_int_not_equal(pid, -1);
879
880         if(!pid) {
881                 meshlink_handle_t *mesh = meshlink_open(nut_confbase, NUT, GET_NODE_REACHABILITY, DEV_CLASS_STATIONARY);
882                 assert(mesh);
883                 meshlink_set_log_cb(mesh, MESHLINK_DEBUG, log_cb);
884
885                 assert(meshlink_join(mesh, invitation));
886
887                 raise(SIGINT);
888         }
889
890         // Wait for child exit and verify which signal terminated it
891
892         assert_int_not_equal(waitpid(pid, &pid_status, 0), -1);
893         assert_int_equal(WIFSIGNALED(pid_status), true);
894         assert_int_equal(WTERMSIG(pid_status), SIGINT);
895
896         // Reopen the NUT instance in the same test suite
897
898         meshlink_handle_t *mesh = meshlink_open(nut_confbase, NUT, GET_NODE_REACHABILITY, DEV_CLASS_STATIONARY);
899         assert_non_null(mesh);
900
901         // Call meshlink_get_node_reachability API and verify that the time stamps has persisted.
902
903         status = meshlink_get_node_reachability(mesh, meshlink_get_node(mesh, PEER), &last_reachable, &last_unreachable);
904         assert_int_equal(status, false);
905         assert_int_equal(last_reachable, 0);
906         assert_int_equal(last_unreachable, 0);
907
908         // Cleanup
909
910         meshlink_close(mesh);
911         meshlink_close(mesh_peer);
912         assert_true(meshlink_destroy(nut_confbase));
913         assert_true(meshlink_destroy(peer_confbase));
914         return true;
915 }
916
917 int test_get_node_reachability(void) {
918         /* State structures for get node reachability Test Cases */
919         black_box_state_t test_case_get_node_reachability_01_state = {
920                 .test_case_name = "test_case_get_node_reachability_01",
921         };
922         black_box_state_t test_case_get_node_reachability_02_state = {
923                 .test_case_name = "test_case_get_node_reachability_02",
924         };
925         black_box_state_t test_case_get_node_reachability_03_state = {
926                 .test_case_name = "test_case_get_node_reachability_03",
927         };
928         black_box_state_t test_case_get_node_reachability_04_state = {
929                 .test_case_name = "test_case_get_node_reachability_04",
930         };
931         black_box_state_t test_case_get_node_reachability_05_state = {
932                 .test_case_name = "test_case_get_node_reachability_05",
933         };
934         black_box_state_t test_case_get_node_reachability_06_state = {
935                 .test_case_name = "test_case_get_node_reachability_06",
936         };
937         black_box_state_t test_case_get_node_reachability_07_state = {
938                 .test_case_name = "test_case_get_node_reachability_07",
939         };
940
941         const struct CMUnitTest blackbox_status_tests[] = {
942                 cmocka_unit_test_prestate_setup_teardown(test_case_get_node_reachability_01, NULL, NULL,
943                                 (void *)&test_case_get_node_reachability_01_state),
944                 cmocka_unit_test_prestate_setup_teardown(test_case_get_node_reachability_02, NULL, NULL,
945                                 (void *)&test_case_get_node_reachability_02_state),
946                 cmocka_unit_test_prestate_setup_teardown(test_case_get_node_reachability_03, NULL, NULL,
947                                 (void *)&test_case_get_node_reachability_03_state),
948                 cmocka_unit_test_prestate_setup_teardown(test_case_get_node_reachability_04, NULL, NULL,
949                                 (void *)&test_case_get_node_reachability_04_state),
950                 cmocka_unit_test_prestate_setup_teardown(test_case_get_node_reachability_05, NULL, NULL,
951                                 (void *)&test_case_get_node_reachability_05_state),
952                 cmocka_unit_test_prestate_setup_teardown(test_case_get_node_reachability_06, NULL, NULL,
953                                 (void *)&test_case_get_node_reachability_06_state),
954                 cmocka_unit_test_prestate_setup_teardown(test_case_get_node_reachability_07, NULL, NULL,
955                                 (void *)&test_case_get_node_reachability_07_state),
956         };
957         total_tests += sizeof(blackbox_status_tests) / sizeof(blackbox_status_tests[0]);
958
959         return cmocka_run_group_tests(blackbox_status_tests, NULL, NULL);
960 }