]> git.meshlink.io Git - meshlink/blob - test/blackbox/run_blackbox_tests/test_cases_join.c
Update the blackbox join test cases.
[meshlink] / test / blackbox / run_blackbox_tests / test_cases_join.c
1 /*
2     test_cases_join.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 #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 #include "../../../src/devtools.h"
45
46 #define NUT                         "nut"
47 #define PEER                        "peer"
48 #define PEER2                       "peer2"
49 #define TEST_MESHLINK_JOIN          "test_meshlink_join"
50 #define create_path(confbase, node_name, test_case_no)   assert(snprintf(confbase, sizeof(confbase), TEST_MESHLINK_JOIN "_%ld_%s_%02d", (long) getpid(), node_name, test_case_no) > 0)
51
52 static struct sync_flag peer_reachable_status_cond = {.mutex  = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER};
53 static bool peer_reachable_status;
54 static struct sync_flag nut_reachable_status_cond = {.mutex  = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER};
55 static bool nut_reachable_status;
56 static struct sync_flag nut_started_status_cond = {.mutex  = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER};
57
58 /* Node reachable status callback which signals the respective conditional varibale */
59 static void meshlink_node_reachable_status_cb(meshlink_handle_t *mesh, meshlink_node_t *node, bool reachable_status) {
60         if(!strcasecmp(mesh->name, NUT)) {
61                 if(!strcasecmp(node->name, PEER)) {
62                         peer_reachable_status = reachable_status;
63                         set_sync_flag(&peer_reachable_status_cond, true);
64                 }
65         } else if(!strcasecmp(mesh->name, PEER)) {
66                 if(!strcasecmp(node->name, NUT)) {
67                         nut_reachable_status = reachable_status;
68                         set_sync_flag(&nut_reachable_status_cond, true);
69                 }
70         }
71 }
72
73 /* SIGUSR2 signal handler that signals the NUT started and PEER node can join */
74 static void nut_started_user_signal_handler(int signum) {
75         if(signum == SIGUSR2) {
76                 set_sync_flag(&nut_started_status_cond, true);
77         }
78
79 }
80
81 /* Test Steps for meshlink_join Test Case # 1 - Valid case
82
83     Test Steps:
84     1. Open instances for NUT and peer, peer invites NUT and starts instance.
85     2. NUT consumes the invitation generated by peer
86
87     Expected Result:
88     NUT joins peer using the invitation generated.
89 */
90 static void test_case_meshlink_join_01(void **state) {
91         (void) state;
92         char nut_confbase[PATH_MAX];
93         char peer_confbase[PATH_MAX];
94         create_path(nut_confbase, NUT, 1);
95         create_path(peer_confbase, PEER, 1);
96         meshlink_set_log_cb(NULL, MESHLINK_DEBUG, log_cb);
97
98         // Open both NUT and peer node instance, invite and join NUT with peer node.
99
100         meshlink_handle_t *mesh_peer = meshlink_open(peer_confbase, PEER, TEST_MESHLINK_JOIN,
101                                        DEV_CLASS_STATIONARY);
102         assert_non_null(mesh_peer);
103         meshlink_set_inviter_commits_first(mesh_peer, true);
104         meshlink_set_node_status_cb(mesh_peer, meshlink_node_reachable_status_cb);
105         char *invitation = meshlink_invite(mesh_peer, NULL, NUT);
106         assert_non_null(invitation);
107         assert_true(meshlink_start(mesh_peer));
108
109         meshlink_handle_t *mesh = meshlink_open(nut_confbase, NUT, TEST_MESHLINK_JOIN,
110                                                 DEV_CLASS_STATIONARY);
111         assert_non_null(mesh);
112         meshlink_set_inviter_commits_first(mesh, true);
113         meshlink_set_node_status_cb(mesh, meshlink_node_reachable_status_cb);
114         assert_true(meshlink_join(mesh, invitation));
115         free(invitation);
116
117         meshlink_node_t *peer_handle = meshlink_get_node(mesh, PEER);
118         assert_non_null(peer_handle);
119         meshlink_node_t *nut_handle = meshlink_get_node(mesh_peer, NUT);
120         assert_non_null(nut_handle);
121
122         // Bring nodes online.
123
124         set_sync_flag(&peer_reachable_status_cond, false);
125         set_sync_flag(&nut_reachable_status_cond, false);
126         assert_true(meshlink_start(mesh));
127         assert_true(wait_sync_flag(&peer_reachable_status_cond, 60));
128         assert_true(peer_reachable_status);
129         assert_true(wait_sync_flag(&nut_reachable_status_cond, 60));
130         assert_true(nut_reachable_status);
131
132         // Cleanup
133
134         meshlink_close(mesh);
135         meshlink_close(mesh_peer);
136         assert_true(meshlink_destroy(nut_confbase));
137         assert_true(meshlink_destroy(peer_confbase));
138         return;
139 }
140
141 /* Test Steps for meshlink_join Test Case # 2 - Invalid case
142
143     Test Steps:
144     1. Call meshlink_join with NULL as mesh handler or node name argument.
145
146     Expected Result:
147     NUT joining fails when NULL is passed as mesh handle or node name argument
148 */
149 static void test_case_meshlink_join_02(void **state) {
150         (void) state;
151         char nut_confbase[PATH_MAX];
152         char peer_confbase[PATH_MAX];
153         create_path(nut_confbase, NUT, 2);
154         create_path(peer_confbase, PEER, 2);
155         meshlink_set_log_cb(NULL, MESHLINK_DEBUG, log_cb);
156
157         // Open both NUT and peer node instance, invite and join NUT with peer node.
158
159         meshlink_handle_t *mesh_peer = meshlink_open(peer_confbase, PEER, TEST_MESHLINK_JOIN,
160                                        DEV_CLASS_STATIONARY);
161         assert_non_null(mesh_peer);
162         meshlink_set_node_status_cb(mesh_peer, meshlink_node_reachable_status_cb);
163         char *invitation = meshlink_invite(mesh_peer, NULL, NUT);
164         assert_non_null(invitation);
165         assert_true(meshlink_start(mesh_peer));
166
167         meshlink_handle_t *mesh = meshlink_open(nut_confbase, NUT, TEST_MESHLINK_JOIN,
168                                                 DEV_CLASS_STATIONARY);
169         assert_non_null(mesh);
170         meshlink_set_node_status_cb(mesh, meshlink_node_reachable_status_cb);
171
172         // meshlink_join called with NULL as mesh handle and with valid invitation
173
174         assert_int_equal(meshlink_join(NULL, invitation), false);
175         assert_int_equal(meshlink_join(mesh, NULL), false);
176
177         // Cleanup
178
179         free(invitation);
180         meshlink_close(mesh);
181         meshlink_close(mesh_peer);
182         assert_true(meshlink_destroy(nut_confbase));
183         assert_true(meshlink_destroy(peer_confbase));
184         return;
185 }
186
187 /* Test Steps for meshlink_join Test Case # 3 - Persistence testing around inviter
188
189     Test steps and scenarios:
190     1.  Open Node-Under-Test (NUT) and invite peer node and close it's instance.
191         Spawn a process which waits for the peer node to join and raises SIGINT if the
192         appropriate callback is received (on the other hand the test suite opens and joins
193         the peer node with NUT in the forked process).
194         Expected Result:
195         NUT joins peer successfully
196
197
198 */
199 static void test_case_meshlink_join_03(void **state) {
200         (void) state;
201         pid_t pid;
202         int pid_status;
203         char nut_confbase[PATH_MAX];
204         char peer_confbase[PATH_MAX];
205         create_path(nut_confbase, NUT, 3);
206         create_path(peer_confbase, PEER, 3);
207         meshlink_set_log_cb(NULL, MESHLINK_DEBUG, log_cb);
208
209         // Open NUT node instance and invite peer node. Close NUT node instance.
210
211         meshlink_handle_t *mesh = meshlink_open(nut_confbase, NUT, TEST_MESHLINK_JOIN, DEV_CLASS_STATIONARY);
212         assert_non_null(mesh);
213         char *invitation = meshlink_invite(mesh, NULL, PEER);
214         meshlink_close(mesh);
215
216         // Set the SIGUSR2 signal handler with handler that signal the condition to the test suite
217
218         sighandler_t usr2sighandler = signal(SIGUSR2, nut_started_user_signal_handler);
219         assert_int_not_equal(usr2sighandler, SIG_ERR);
220
221         // Fork a new process and run NUT in it which just waits for the peer node reachable status callback
222         // and terminates the process immediately.
223
224         pid = fork();
225         assert_int_not_equal(pid, -1);
226
227         if(!pid) {
228                 assert(signal(SIGUSR2, SIG_DFL) != SIG_ERR);
229
230                 mesh = meshlink_open(nut_confbase, NUT, TEST_MESHLINK_JOIN, DEV_CLASS_STATIONARY);
231                 assert(mesh);
232                 meshlink_set_log_cb(mesh, MESHLINK_DEBUG, log_cb);
233                 meshlink_set_node_status_cb(mesh, meshlink_node_reachable_status_cb);
234
235                 set_sync_flag(&peer_reachable_status_cond, false);
236                 assert(meshlink_start(mesh));
237
238                 assert(kill(getppid(), SIGUSR2) != -1);
239
240                 assert(wait_sync_flag(&peer_reachable_status_cond, 60));
241                 assert(peer_reachable_status);
242
243                 raise(SIGINT);
244         }
245
246         // Open peer node instance and join with the invitation obtained.
247
248         meshlink_handle_t *mesh_peer = meshlink_open(peer_confbase, PEER, TEST_MESHLINK_JOIN,
249                                        DEV_CLASS_STATIONARY);
250         assert_non_null(mesh_peer);
251
252         // Wait for the started signal from NUT and reset the previous SIGUSR2 signal handler
253
254         assert_true(wait_sync_flag(&nut_started_status_cond, 60));
255         assert_int_not_equal(signal(SIGUSR2, usr2sighandler), SIG_ERR);
256
257         assert_true(meshlink_join(mesh_peer, invitation));
258         assert_true(meshlink_start(mesh_peer));
259
260         // Wait for child exit and verify which signal terminated it
261
262         assert_int_not_equal(waitpid(pid, &pid_status, 0), -1);
263         assert_int_equal(WIFSIGNALED(pid_status), true);
264         assert_int_equal(WTERMSIG(pid_status), SIGINT);
265
266         // Reopen the NUT instance in the same test suite
267
268         mesh = meshlink_open(nut_confbase, NUT, TEST_MESHLINK_JOIN, DEV_CLASS_STATIONARY);
269         assert_non_null(mesh);
270
271         assert_non_null(meshlink_get_node(mesh, PEER));
272
273         // Cleanup
274
275         meshlink_close(mesh);
276         meshlink_close(mesh_peer);
277         assert_true(meshlink_destroy(nut_confbase));
278         assert_true(meshlink_destroy(peer_confbase));
279         return;
280 }
281
282 /* Test Steps for meshlink_get_node_reachability Test Case # 4 - Persistence testing around invitee
283
284     Test steps and scenarios:
285     1.  Open peer node instance, invite NUT and start peer node. Spawn a new process in
286         which it opens and joins the NUT with peer node.
287         Reopen NUT instance in the test suite process and verify peer is joined.
288         Expected Result:
289         NUT joins peer successfully
290
291 */
292 static void test_case_meshlink_join_04(void **state) {
293         (void) state;
294         pid_t pid;
295         int pid_status;
296         char nut_confbase[PATH_MAX];
297         char peer_confbase[PATH_MAX];
298         create_path(nut_confbase, NUT, 4);
299         create_path(peer_confbase, PEER, 4);
300         meshlink_set_log_cb(NULL, MESHLINK_DEBUG, log_cb);
301
302         // Open peer node instance and invite NUT.
303
304         meshlink_handle_t *mesh_peer = meshlink_open(peer_confbase, PEER, TEST_MESHLINK_JOIN,
305                                        DEV_CLASS_STATIONARY);
306         assert_int_not_equal(mesh_peer, NULL);
307         char *invitation = meshlink_invite(mesh_peer, NULL, NUT);
308         assert_non_null(invitation);
309
310         assert_true(meshlink_start(mesh_peer));
311
312         // Fork a new process in which NUT is joins with the peer node and raises SIGINT to terminate.
313
314         pid = fork();
315         assert_int_not_equal(pid, -1);
316
317         if(!pid) {
318                 meshlink_handle_t *mesh = meshlink_open(nut_confbase, NUT, TEST_MESHLINK_JOIN, DEV_CLASS_STATIONARY);
319                 assert(mesh);
320                 meshlink_set_log_cb(mesh, MESHLINK_DEBUG, log_cb);
321
322                 assert(meshlink_join(mesh, invitation));
323
324                 raise(SIGINT);
325         }
326
327         // Wait for child exit and verify which signal terminated it
328
329         assert_int_not_equal(waitpid(pid, &pid_status, 0), -1);
330         assert_int_equal(WIFSIGNALED(pid_status), true);
331         assert_int_equal(WTERMSIG(pid_status), SIGINT);
332
333         // Reopen the NUT instance in the same test suite
334
335         meshlink_handle_t *mesh = meshlink_open(nut_confbase, NUT, TEST_MESHLINK_JOIN, DEV_CLASS_STATIONARY);
336         assert_non_null(mesh);
337
338         assert_non_null(meshlink_get_node(mesh, PEER));
339
340         // Cleanup
341
342         meshlink_close(mesh);
343         meshlink_close(mesh_peer);
344         assert_true(meshlink_destroy(nut_confbase));
345         assert_true(meshlink_destroy(peer_confbase));
346         return;
347 }
348
349 static void nop_stage(bool stage) {
350         (void)stage;
351         return;
352 }
353
354 static void debug_probe(bool stage) {
355         (void)stage;
356         raise(SIGINT);
357         return;
358 }
359
360 /* Test Steps for meshlink_get_node_reachability Test Case # 5 - Test the invitee committing first scenario
361
362     Test steps and scenarios:
363     1.  Open peer node instance, invite NUT and start peer node. Enable the debug probe, Spawn a new process in
364         which it opens and joins the NUT with peer node which terminates the NUT while joining.
365         Reopen NUT instance in the test suite process and verify peer is joined.
366         Expected Result:
367         NUT(invitee) commits the config file(s) first but peer is unaware of NUT.
368
369 */
370 static void test_case_meshlink_join_05(void **state) {
371         (void) state;
372         pid_t pid;
373         int pid_status;
374         char nut_confbase[PATH_MAX];
375         char peer_confbase[PATH_MAX];
376         create_path(nut_confbase, NUT, 5);
377         create_path(peer_confbase, PEER, 5);
378         meshlink_set_log_cb(NULL, MESHLINK_DEBUG, log_cb);
379
380         assert(signal(SIGINT, SIG_DFL) != SIG_ERR);
381         assert(signal(SIGABRT, SIG_DFL) != SIG_ERR);
382
383         // Set debug_probe callback
384
385         devtool_set_inviter_commits_first = debug_probe;
386
387         // Open peer node instance and invite NUT.
388
389         meshlink_handle_t *mesh_peer = meshlink_open(peer_confbase, PEER, TEST_MESHLINK_JOIN,
390                                        DEV_CLASS_STATIONARY);
391         assert_int_not_equal(mesh_peer, NULL);
392         meshlink_set_inviter_commits_first(mesh_peer, false);
393         char *invitation = meshlink_invite(mesh_peer, NULL, NUT);
394         assert_non_null(invitation);
395
396         assert_true(meshlink_start(mesh_peer));
397
398         // Fork a new process in which NUT is joins with the peer node and raises SIGINT to terminate.
399
400         pid = fork();
401         assert_int_not_equal(pid, -1);
402
403         if(!pid) {
404                 meshlink_handle_t *mesh = meshlink_open(nut_confbase, NUT, TEST_MESHLINK_JOIN, DEV_CLASS_STATIONARY);
405                 assert(mesh);
406                 meshlink_set_inviter_commits_first(mesh_peer, false);
407                 meshlink_set_log_cb(mesh, MESHLINK_DEBUG, log_cb);
408
409                 assert_true(meshlink_join(mesh, invitation));
410
411                 raise(SIGABRT);
412         }
413
414         // Wait for child exit and verify which signal terminated it
415         printf("\n");
416         assert_int_not_equal(waitpid(pid, &pid_status, 0), -1);
417         assert_int_equal(WIFSIGNALED(pid_status), true);
418         assert_int_equal(WTERMSIG(pid_status), SIGINT);
419
420         // Reopen the NUT instance in the same test suite
421
422         meshlink_handle_t *mesh = meshlink_open(nut_confbase, NUT, TEST_MESHLINK_JOIN, DEV_CLASS_STATIONARY);
423         assert_non_null(mesh);
424
425         // Invitee committed host config file but invitee should not
426
427         assert_non_null(meshlink_get_node(mesh, PEER));
428         assert_null(meshlink_get_node(mesh_peer, NUT));
429
430         // Cleanup
431
432         free(invitation);
433         meshlink_close(mesh);
434         meshlink_close(mesh_peer);
435         assert_true(meshlink_destroy(nut_confbase));
436         assert_true(meshlink_destroy(peer_confbase));
437
438         devtool_set_inviter_commits_first = nop_stage;
439         return;
440 }
441
442 /* Test Steps for meshlink_get_node_reachability Test Case # 6 - Test the inviter committing first scenario
443
444     Test steps and scenarios:
445     1.  Open NUT node instance, invite peer and close the instance. Enable the debug probe, Spawn a new process in
446         which it starts the NUT instance. At the parents/test vector thread wait for the signal that NUT raises after starting
447         and join peer with NUT. NUT terminates in debug probe after committing into the disk
448         Reopen NUT instance in the test suite process and verify peer is joined.
449         Expected Result:
450         NUT(inviter) commits the config file(s) first but peer is unaware of NUT.
451
452 */
453 static void test_case_meshlink_join_06(void **state) {
454         (void) state;
455         pid_t pid;
456         int pid_status;
457         char nut_confbase[PATH_MAX];
458         char peer_confbase[PATH_MAX];
459         create_path(nut_confbase, NUT, 6);
460         create_path(peer_confbase, PEER, 6);
461         meshlink_set_log_cb(NULL, MESHLINK_DEBUG, log_cb);
462
463         assert(signal(SIGINT, SIG_DFL) != SIG_ERR);
464         assert(signal(SIGABRT, SIG_DFL) != SIG_ERR);
465
466         // Set debug_probe callback
467
468         devtool_set_inviter_commits_first = debug_probe;
469
470         // Open NUT node instance and invite peer node. Close NUT node instance.
471
472         meshlink_handle_t *mesh = meshlink_open(nut_confbase, NUT, TEST_MESHLINK_JOIN, DEV_CLASS_STATIONARY);
473         assert_non_null(mesh);
474         meshlink_set_inviter_commits_first(mesh, true);
475         char *invitation = meshlink_invite(mesh, NULL, PEER);
476         meshlink_close(mesh);
477
478         // Set the SIGUSR2 signal handler with handler that signal the condition to the test suite
479
480         sighandler_t usr2sighandler = signal(SIGUSR2, nut_started_user_signal_handler);
481         assert_int_not_equal(usr2sighandler, SIG_ERR);
482         set_sync_flag(&peer_reachable_status_cond, false);
483
484         // Fork a new process and run NUT in it which just waits for the peer node reachable status callback
485         // and terminates the process immediately.
486
487         pid = fork();
488         assert_int_not_equal(pid, -1);
489
490         if(!pid) {
491                 assert(signal(SIGUSR2, SIG_DFL) != SIG_ERR);
492
493                 mesh = meshlink_open(nut_confbase, NUT, TEST_MESHLINK_JOIN, DEV_CLASS_STATIONARY);
494                 assert(mesh);
495                 meshlink_set_inviter_commits_first(mesh, true);
496                 meshlink_set_log_cb(mesh, MESHLINK_DEBUG, log_cb);
497                 meshlink_set_node_status_cb(mesh, meshlink_node_reachable_status_cb);
498
499                 assert(meshlink_start(mesh));
500
501                 assert(kill(getppid(), SIGUSR2) != -1);
502
503                 sleep(10);
504
505                 raise(SIGABRT);
506         }
507
508         // Open peer node instance and join with the invitation obtained.
509
510         meshlink_handle_t *mesh_peer = meshlink_open(peer_confbase, PEER, TEST_MESHLINK_JOIN,
511                                        DEV_CLASS_STATIONARY);
512         assert_non_null(mesh_peer);
513         meshlink_set_inviter_commits_first(mesh_peer, true);
514
515         // Wait for the started signal from NUT and reset the previous SIGUSR2 signal handler
516
517         assert_true(wait_sync_flag(&nut_started_status_cond, 60));
518         assert_int_not_equal(signal(SIGUSR2, usr2sighandler), SIG_ERR);
519
520         assert_false(meshlink_join(mesh_peer, invitation));
521
522         // Wait for child exit and verify which signal terminated it
523
524         assert_int_not_equal(waitpid(pid, &pid_status, 0), -1);
525         assert_int_equal(WIFSIGNALED(pid_status), true);
526         assert_int_equal(WTERMSIG(pid_status), SIGINT);
527
528         // Reopen the NUT instance in the same test suite
529
530         mesh = meshlink_open(nut_confbase, NUT, TEST_MESHLINK_JOIN, DEV_CLASS_STATIONARY);
531         assert_non_null(mesh);
532
533         // Inviter should first commit config file(s) into the disk
534
535         assert_null(meshlink_get_node(mesh_peer, NUT));
536         assert_non_null(meshlink_get_node(mesh, PEER));
537
538         // Cleanup
539
540         free(invitation);
541         meshlink_close(mesh);
542         meshlink_close(mesh_peer);
543         assert_true(meshlink_destroy(nut_confbase));
544         assert_true(meshlink_destroy(peer_confbase));
545         devtool_set_inviter_commits_first = nop_stage;
546         return;
547 }
548
549 /* Test Steps for meshlink_join Test Case # 7 - Inviter sets that invitee should commit first,
550                                                 even invitee sets that inviter should commit first.
551
552     Test Steps:
553     1. Open instances for NUT and peer, peer invites NUT and starts instance.
554        Both the instances sets meshlink_set_inviter_commits_first API mutually exclusively
555        NUT tries to consume the invitation generated by peer
556
557     Expected Result:
558     NUT fails to join peer using the invitation generated.
559 */
560 static void test_case_meshlink_join_07(void **state) {
561         (void) state;
562         char nut_confbase[PATH_MAX];
563         char peer_confbase[PATH_MAX];
564         create_path(nut_confbase, NUT, 7);
565         create_path(peer_confbase, PEER, 7);
566         meshlink_set_log_cb(NULL, MESHLINK_DEBUG, log_cb);
567
568         // Open both NUT and peer node instance, invite and join NUT with peer node.
569
570         meshlink_handle_t *mesh_peer = meshlink_open(peer_confbase, PEER, TEST_MESHLINK_JOIN,
571                                        DEV_CLASS_STATIONARY);
572         assert_non_null(mesh_peer);
573         meshlink_set_inviter_commits_first(mesh_peer, false);
574         meshlink_set_node_status_cb(mesh_peer, meshlink_node_reachable_status_cb);
575         char *invitation = meshlink_invite(mesh_peer, NULL, NUT);
576         assert_non_null(invitation);
577         assert_true(meshlink_start(mesh_peer));
578
579         meshlink_handle_t *mesh = meshlink_open(nut_confbase, NUT, TEST_MESHLINK_JOIN,
580                                                 DEV_CLASS_STATIONARY);
581         assert_non_null(mesh);
582         meshlink_set_inviter_commits_first(mesh, true);
583         meshlink_set_node_status_cb(mesh, meshlink_node_reachable_status_cb);
584         assert_false(meshlink_join(mesh, invitation));
585         free(invitation);
586
587         meshlink_node_t *peer_handle = meshlink_get_node(mesh, PEER);
588         assert_null(peer_handle);
589         meshlink_node_t *nut_handle = meshlink_get_node(mesh_peer, NUT);
590         assert_null(nut_handle);
591
592         // Cleanup
593
594         meshlink_close(mesh);
595         meshlink_close(mesh_peer);
596         assert_true(meshlink_destroy(nut_confbase));
597         assert_true(meshlink_destroy(peer_confbase));
598         return;
599 }
600
601 /* Test Steps for meshlink_join Test Case # 8 - Inviter sets that it should commit first,
602                                                 even invitee sets that it should commit first
603
604     Test Steps:
605     1. Open instances for NUT and peer, peer invites NUT and starts instance.
606        Both the instances sets meshlink_set_inviter_commits_first API mutually exclusively
607        NUT tries to consume the invitation generated by peer
608
609     Expected Result:
610     NUT fails to join peer using the invitation generated.
611 */
612 static void test_case_meshlink_join_08(void **state) {
613         (void) state;
614         char nut_confbase[PATH_MAX];
615         char peer_confbase[PATH_MAX];
616         create_path(nut_confbase, NUT, 8);
617         create_path(peer_confbase, PEER, 8);
618         meshlink_set_log_cb(NULL, MESHLINK_DEBUG, log_cb);
619
620         // Open both NUT and peer node instance, invite and join NUT with peer node.
621
622         meshlink_handle_t *mesh_peer = meshlink_open(peer_confbase, PEER, TEST_MESHLINK_JOIN,
623                                        DEV_CLASS_STATIONARY);
624         assert_non_null(mesh_peer);
625         meshlink_set_inviter_commits_first(mesh_peer, true);
626         meshlink_set_node_status_cb(mesh_peer, meshlink_node_reachable_status_cb);
627         char *invitation = meshlink_invite(mesh_peer, NULL, NUT);
628         assert_non_null(invitation);
629         assert_true(meshlink_start(mesh_peer));
630
631         meshlink_handle_t *mesh = meshlink_open(nut_confbase, NUT, TEST_MESHLINK_JOIN,
632                                                 DEV_CLASS_STATIONARY);
633         assert_non_null(mesh);
634         meshlink_set_inviter_commits_first(mesh, false);
635         meshlink_set_node_status_cb(mesh, meshlink_node_reachable_status_cb);
636         assert_false(meshlink_join(mesh, invitation));
637         free(invitation);
638
639         meshlink_node_t *peer_handle = meshlink_get_node(mesh, PEER);
640         assert_null(peer_handle);
641         meshlink_node_t *nut_handle = meshlink_get_node(mesh_peer, NUT);
642         assert_null(nut_handle);
643
644         // Cleanup
645
646         meshlink_close(mesh);
647         meshlink_close(mesh_peer);
648         assert_true(meshlink_destroy(nut_confbase));
649         assert_true(meshlink_destroy(peer_confbase));
650         return;
651 }
652
653 /* Test Steps for meshlink_join Test Case # 9 - Invitee already started its instance
654
655     Test Steps:
656     1. Open instances for NUT and peer, peer invites NUT and both the instances starts their instances.
657        NUT tries to join the peer with the generated invitation.
658
659     Expected Result:
660     NUT fails to join peer using the invitation generated.
661 */
662 static void test_case_meshlink_join_09(void **state) {
663         (void) state;
664         char nut_confbase[PATH_MAX];
665         char peer_confbase[PATH_MAX];
666         create_path(nut_confbase, NUT, 9);
667         create_path(peer_confbase, PEER, 9);
668         meshlink_set_log_cb(NULL, MESHLINK_DEBUG, log_cb);
669
670         // Open both NUT and peer node instance, invite and join NUT with peer node.
671
672         meshlink_handle_t *mesh_peer = meshlink_open(peer_confbase, PEER, TEST_MESHLINK_JOIN,
673                                        DEV_CLASS_STATIONARY);
674         assert_non_null(mesh_peer);
675         meshlink_set_node_status_cb(mesh_peer, meshlink_node_reachable_status_cb);
676         char *invitation = meshlink_invite(mesh_peer, NULL, NUT);
677         assert_non_null(invitation);
678         assert_true(meshlink_start(mesh_peer));
679
680         meshlink_handle_t *mesh = meshlink_open(nut_confbase, NUT, TEST_MESHLINK_JOIN,
681                                                 DEV_CLASS_STATIONARY);
682         assert_non_null(mesh);
683         meshlink_set_node_status_cb(mesh, meshlink_node_reachable_status_cb);
684
685         assert_true(meshlink_start(mesh));
686
687         assert_false(meshlink_join(mesh, invitation));
688         free(invitation);
689
690         meshlink_node_t *peer_handle = meshlink_get_node(mesh, PEER);
691         assert_null(peer_handle);
692         meshlink_node_t *nut_handle = meshlink_get_node(mesh_peer, NUT);
693         assert_null(nut_handle);
694
695         // Cleanup
696
697         meshlink_close(mesh);
698         meshlink_close(mesh_peer);
699         assert_true(meshlink_destroy(nut_confbase));
700         assert_true(meshlink_destroy(peer_confbase));
701         return;
702 }
703
704 /* Test Steps for meshlink_join Test Case # 10 - Invitee already joined in a mesh
705
706     Test Steps:
707     1. Open instances for NUT, peer2 and peer, peer invites NUT. Peer2 and NUT both mutually imports data
708        i.e, both formed or joined the mesh.
709        NUT tries to join the peer with the generated invitation.
710
711     Expected Result:
712     NUT fails to join peer using the invitation generated.
713 */
714 static void test_case_meshlink_join_10(void **state) {
715         (void) state;
716         char nut_confbase[PATH_MAX];
717         char peer_confbase[PATH_MAX];
718         char peer_confbase2[PATH_MAX];
719         create_path(nut_confbase, NUT, 10);
720         create_path(peer_confbase, PEER, 10);
721         create_path(peer_confbase2, PEER2, 10);
722         meshlink_set_log_cb(NULL, MESHLINK_DEBUG, log_cb);
723
724         // Open both NUT and peer node instance, invite and join NUT with peer node.
725
726         meshlink_handle_t *mesh_peer = meshlink_open(peer_confbase, PEER, TEST_MESHLINK_JOIN,
727                                        DEV_CLASS_STATIONARY);
728         assert_non_null(mesh_peer);
729         meshlink_set_node_status_cb(mesh_peer, meshlink_node_reachable_status_cb);
730         char *invitation = meshlink_invite(mesh_peer, NULL, NUT);
731         assert_non_null(invitation);
732         assert_true(meshlink_start(mesh_peer));
733
734         meshlink_handle_t *mesh_peer2 = meshlink_open(peer_confbase2, PEER2, TEST_MESHLINK_JOIN,
735                                         DEV_CLASS_STATIONARY);
736         assert_non_null(mesh_peer2);
737         meshlink_handle_t *mesh = meshlink_open(nut_confbase, NUT, TEST_MESHLINK_JOIN,
738                                                 DEV_CLASS_STATIONARY);
739         assert_non_null(mesh);
740         meshlink_set_node_status_cb(mesh, meshlink_node_reachable_status_cb);
741
742         char *data = meshlink_export(mesh);
743         assert_non_null(data);
744         assert_true(meshlink_import(mesh_peer2, data));
745         free(data);
746         data = meshlink_export(mesh_peer2);
747         assert_non_null(data);
748         assert_true(meshlink_import(mesh, data));
749         free(data);
750
751         assert_true(meshlink_start(mesh));
752
753         assert_false(meshlink_join(mesh, invitation));
754         free(invitation);
755
756         meshlink_node_t *peer_handle = meshlink_get_node(mesh, PEER);
757         assert_null(peer_handle);
758         meshlink_node_t *nut_handle = meshlink_get_node(mesh_peer, NUT);
759         assert_null(nut_handle);
760
761         // Cleanup
762
763         meshlink_close(mesh);
764         meshlink_close(mesh_peer);
765         assert_true(meshlink_destroy(nut_confbase));
766         assert_true(meshlink_destroy(peer_confbase));
767         return;
768 }
769
770 int test_meshlink_join(void) {
771         const struct CMUnitTest blackbox_join_tests[] = {
772                 cmocka_unit_test(test_case_meshlink_join_01),
773                 cmocka_unit_test(test_case_meshlink_join_02),
774                 cmocka_unit_test(test_case_meshlink_join_03),
775                 cmocka_unit_test(test_case_meshlink_join_04),
776                 cmocka_unit_test(test_case_meshlink_join_05),
777                 cmocka_unit_test(test_case_meshlink_join_06),
778                 cmocka_unit_test(test_case_meshlink_join_07),
779                 cmocka_unit_test(test_case_meshlink_join_08),
780                 cmocka_unit_test(test_case_meshlink_join_09),
781                 cmocka_unit_test(test_case_meshlink_join_10)
782         };
783         total_tests += sizeof(blackbox_join_tests) / sizeof(blackbox_join_tests[0]);
784
785         int failed = cmocka_run_group_tests(blackbox_join_tests, NULL, NULL);
786
787         return failed;
788 }