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