2 test_optimal_pmtu.c -- Execution of specific meshlink black box test cases
3 Copyright (C) 2019 Guus Sliepen <guus@meshlink.io>
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.
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.
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.
25 #include "../../../src/meshlink.h"
26 #include "../common/containers.h"
27 #include "../common/test_step.h"
28 #include "../common/common_handlers.h"
29 #include "../common/network_namespace_framework.h"
30 #include "../../utils.h"
31 #include "test_cases_random_port_bindings02.h"
33 static void test_case_mesh_random_port_bindings_04(void **state);
34 static bool test_steps_mesh_random_port_bindings_04(void);
35 static void test_case_mesh_random_port_bindings_05(void **state);
36 static bool test_steps_mesh_random_port_bindings_05(void);
38 typedef bool (*test_step_func_t)(void);
39 static int setup_test(void **state);
41 static meshlink_handle_t *peer, *nut_instance, *relay;
42 static char *peer_invite, *nut_invite;
43 struct sync_flag test_random_port_binding_node_connected = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER};
44 struct sync_flag test_random_port_binding_node_started = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER};
45 struct sync_flag test_random_port_binding_peer_reachable = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER};
46 struct sync_flag test_random_port_binding_make_switch = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER};
47 struct sync_flag test_random_port_binding_relay_closed = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER};
48 struct sync_flag test_random_port_binding_peer_closed = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER};
49 struct sync_flag test_random_port_binding_nut_closed = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER};
50 static netns_state_t *test_random_port_bindings_state;
51 static bool localnode = false;
53 static int setup_test(void **state) {
56 netns_create_topology(test_random_port_bindings_state);
57 fprintf(stderr, "\nCreated topology\n");
59 set_sync_flag(&test_random_port_binding_node_connected, false);
60 set_sync_flag(&test_random_port_binding_node_started, false);
61 set_sync_flag(&test_random_port_binding_peer_reachable, false);
62 set_sync_flag(&test_random_port_binding_make_switch, false);
63 set_sync_flag(&test_random_port_binding_relay_closed, false);
64 set_sync_flag(&test_random_port_binding_peer_closed, false);
65 set_sync_flag(&test_random_port_binding_nut_closed, false);
67 meshlink_destroy("nut");
68 meshlink_destroy("peer");
69 meshlink_destroy("relay");
74 static int teardown_test(void **state) {
77 meshlink_destroy("nut");
78 meshlink_destroy("peer");
79 meshlink_destroy("relay");
80 netns_destroy_topology(test_random_port_bindings_state);
85 static void execute_test(test_step_func_t step_func, void **state) {
89 fprintf(stderr, "\n\x1b[32mRunning Test\x1b[0m\n");
90 bool test_result = step_func();
97 static void message_log(meshlink_handle_t *mesh, meshlink_log_level_t level, const char *text) {
100 char *levelstr = "\x1b[32mRELAY";
102 if(strcmp(mesh->name, "peer") == 0) {
103 if(strcmp("Connection with nut activated", text) == 0) {
104 set_sync_flag(&test_random_port_binding_node_connected, true);
107 levelstr = "\x1b[34mPEER";
108 } else if(strcmp(mesh->name, "nut") == 0) {
109 if(strcmp("Connection with peer activated", text) == 0) {
110 set_sync_flag(&test_random_port_binding_node_connected, true);
113 levelstr = "\x1b[33mNUT";
116 fprintf(stderr, "%s:\x1b[0m %s\n", levelstr, text);
119 static void node_status(meshlink_handle_t *mesh, meshlink_node_t *node, bool reachable) {
123 if((strcmp(mesh->name, "nut") == 0) && (strcmp(node->name, "peer") == 0)) {
124 set_sync_flag(&test_random_port_binding_peer_reachable, true);
127 fprintf(stderr, "%s: %s joined.\n", mesh->name, node->name);
131 static void *relay_node(void *arg) {
132 mesh_arg_t *mesh_arg = (mesh_arg_t *)arg;
134 //system("ifconfig");
136 meshlink_destroy("relay");
138 relay = meshlink_open(mesh_arg->node_name, mesh_arg->confbase, mesh_arg->app_name, mesh_arg->dev_class);
141 assert_true(meshlink_start(relay));
142 fprintf(stderr, "\n\x1b[32mRelay Started\x1b[0m\n");
144 assert((peer_invite = meshlink_invite(relay, NULL, "peer")));
145 assert((nut_invite = meshlink_invite(relay, NULL, "nut")));
147 set_sync_flag(&test_random_port_binding_node_started, true);
149 meshlink_set_log_cb(relay, MESHLINK_DEBUG, message_log);
151 if(localnode == true) {
152 assert(wait_sync_flag(&test_random_port_binding_make_switch, 300));
153 meshlink_close(relay);
154 meshlink_destroy("relay");
157 set_sync_flag(&test_random_port_binding_relay_closed, true);
162 assert(wait_sync_flag(&test_random_port_binding_node_connected, 300));
164 meshlink_close(relay);
165 meshlink_destroy("relay");
168 set_sync_flag(&test_random_port_binding_relay_closed, true);
173 static void *peer_node(void *arg) {
174 mesh_arg_t *mesh_arg = (mesh_arg_t *)arg;
176 fprintf(stderr, "\n\x1b[32mPeer Thread Started\x1b[0m\n");
178 meshlink_destroy("peer");
180 peer = meshlink_open(mesh_arg->node_name, mesh_arg->confbase, mesh_arg->app_name, mesh_arg->dev_class);
182 meshlink_set_log_cb(peer, MESHLINK_DEBUG, message_log);
184 fprintf(stderr, "\n\x1b[32mPeer joining relay\x1b[0m\n");
186 assert_true(meshlink_join(peer, (const char *)mesh_arg->join_invitation));
188 assert_true(meshlink_start(peer));
190 fprintf(stderr, "\n\x1b[32mPeer Started\x1b[0m\n");
192 set_sync_flag(&test_random_port_binding_node_started, true);
194 assert(wait_sync_flag(&test_random_port_binding_make_switch, 300));
198 //meshlink_set_log_cb(peer, MESHLINK_DEBUG, message_log);
200 assert(meshlink_set_port(peer, 20000));
202 assert_true(meshlink_start(peer));
204 assert(wait_sync_flag(&test_random_port_binding_node_connected, 300));
206 meshlink_close(peer);
207 meshlink_destroy("peer");
209 set_sync_flag(&test_random_port_binding_peer_closed, true);
214 static void *nut_node(void *arg) {
215 mesh_arg_t *mesh_arg = (mesh_arg_t *)arg;
217 fprintf(stderr, "\n\x1b[32mNut Thread Started\x1b[0m\n");
219 meshlink_destroy("nut");
221 nut_instance = meshlink_open(mesh_arg->node_name, mesh_arg->confbase, mesh_arg->app_name, mesh_arg->dev_class);
222 assert(nut_instance);
224 meshlink_set_log_cb(nut_instance, MESHLINK_DEBUG, message_log);
226 fprintf(stderr, "\n\x1b[32mNut joining relay\x1b[0m\n");
228 assert_true(meshlink_join(nut_instance, (const char *)mesh_arg->join_invitation));
230 meshlink_set_node_status_cb(nut_instance, node_status);
232 assert_true(meshlink_start(nut_instance));
234 fprintf(stderr, "\n\x1b[32mNut Started\x1b[0m\n");
237 set_sync_flag(&test_random_port_binding_node_started, true);
239 assert(wait_sync_flag(&test_random_port_binding_make_switch, 300));
241 meshlink_stop(nut_instance);
243 //meshlink_set_log_cb(nut_instance, MESHLINK_DEBUG, message_log);
245 assert(meshlink_set_port(nut_instance, 30000));
247 assert_true(meshlink_start(nut_instance));
249 assert(wait_sync_flag(&test_random_port_binding_node_connected, 300));
251 meshlink_close(nut_instance);
252 meshlink_destroy("nut");
254 set_sync_flag(&test_random_port_binding_nut_closed, true);
259 /* Test Steps for Random port bindings Test Case # 4 */
260 static void test_case_mesh_random_port_bindings_04(void **state) {
261 execute_test(test_steps_mesh_random_port_bindings_04, state);
265 /* Test Steps for Random port bindings Test Case # 4
268 1. Create three node nut, peer and relay in three different name spaces.
269 2. Join nut and peer to relay with invitation.
270 3. Stop the three nodes and change the ports of nut and peer.
271 4. Start all the nodes again.
273 NUT and Peer should be able to discover each others port with the help
274 of RELAY and form the direct meta connection.
276 static bool test_steps_mesh_random_port_bindings_04(void) {
277 mesh_arg_t relay_arg = {.node_name = "relay", .confbase = "relay", .app_name = "chat", .dev_class = 0 };
278 mesh_arg_t peer_arg = {.node_name = "peer", .confbase = "peer", .app_name = "chat", .dev_class = 1 };
279 mesh_arg_t nut_arg = {.node_name = "nut", .confbase = "nut", .app_name = "chat", .dev_class = 1 };
281 netns_thread_t netns_relay_handle = {.namespace_name = "relay", .netns_thread = relay_node, .arg = &relay_arg};
282 run_node_in_namespace_thread(&netns_relay_handle);
284 assert(wait_sync_flag(&test_random_port_binding_node_started, 5));
285 fprintf(stderr, "\n\x1b[32mTest-04 : Relay Started\x1b[0m\n");
287 set_sync_flag(&test_random_port_binding_node_started, false);
288 peer_arg.join_invitation = peer_invite;
289 fprintf(stderr, "\n\x1b[32mTest-04: Got Invite {%s} for peer\x1b[0m\n", peer_arg.join_invitation);
290 netns_thread_t netns_peer_handle = {.namespace_name = "peer", .netns_thread = peer_node, .arg = &peer_arg};
291 run_node_in_namespace_thread(&netns_peer_handle);
293 assert(wait_sync_flag(&test_random_port_binding_node_started, 20));
294 fprintf(stderr, "\n\x1b[32mTest-04 : Peer Started\x1b[0m\n");
296 set_sync_flag(&test_random_port_binding_node_started, false);
297 nut_arg.join_invitation = nut_invite;
298 fprintf(stderr, "\n\x1b[32mTest-04: Got Invite {%s} for nut\x1b[0m\n", nut_arg.join_invitation);
299 netns_thread_t netns_nut_handle = {.namespace_name = "nut", .netns_thread = nut_node, .arg = &nut_arg};
300 run_node_in_namespace_thread(&netns_nut_handle);
302 assert(wait_sync_flag(&test_random_port_binding_node_started, 20));
303 fprintf(stderr, "\n\x1b[32mTest-04 : Nut Started\x1b[0m\n");
305 set_sync_flag(&test_random_port_binding_make_switch, true);
306 fprintf(stderr, "\n\x1b[32mTest-04 : Making Switch\x1b[0m\n");
308 assert(wait_sync_flag(&test_random_port_binding_node_connected, 300));
310 fprintf(stderr, "\n\x1b[32mDone Test-04\x1b[0m\n");
312 assert(wait_sync_flag(&test_random_port_binding_relay_closed, 10));
313 assert(wait_sync_flag(&test_random_port_binding_peer_closed, 10));
314 assert(wait_sync_flag(&test_random_port_binding_nut_closed, 10));
319 /* Test Steps for Random port bindings Test Case # 5 */
320 static void test_case_mesh_random_port_bindings_05(void **state) {
321 execute_test(test_steps_mesh_random_port_bindings_05, state);
325 /* Test Steps for Random port bindings Test Case # 5
328 1. Create three node nut, peer and relay in same name spaces.
329 2. Join nut and peer to relay with invitation.
330 3. Stop the three nodes and change the ports of nut and peer.
331 4. Close the relay node and start nut and peer nodes again.
333 NUT and Peer should be able to discover each others port with the help
334 of CATTA and form the direct meta connection.
336 static bool test_steps_mesh_random_port_bindings_05(void) {
339 mesh_arg_t relay_arg = {.node_name = "relay", .confbase = "relay", .app_name = "chat", .dev_class = 1 };
340 mesh_arg_t peer_arg = {.node_name = "peer", .confbase = "peer", .app_name = "chat", .dev_class = 1 };
341 mesh_arg_t nut_arg = {.node_name = "nut", .confbase = "nut", .app_name = "chat", .dev_class = 1 };
343 netns_thread_t netns_relay_handle = {.namespace_name = "relay", .netns_thread = relay_node, .arg = &relay_arg};
344 run_node_in_namespace_thread(&netns_relay_handle);
346 assert(wait_sync_flag(&test_random_port_binding_node_started, 20));
348 set_sync_flag(&test_random_port_binding_node_started, false);
349 peer_arg.join_invitation = peer_invite;
350 netns_thread_t netns_peer_handle = {.namespace_name = "peer", .netns_thread = peer_node, .arg = &peer_arg};
351 run_node_in_namespace_thread(&netns_peer_handle);
353 assert(wait_sync_flag(&test_random_port_binding_node_started, 20));
355 set_sync_flag(&test_random_port_binding_node_started, false);
356 nut_arg.join_invitation = nut_invite;
357 netns_thread_t netns_nut_handle = {.namespace_name = "nut", .netns_thread = nut_node, .arg = &nut_arg};
358 run_node_in_namespace_thread(&netns_nut_handle);
360 assert(wait_sync_flag(&test_random_port_binding_node_started, 20));
362 assert(wait_sync_flag(&test_random_port_binding_peer_reachable, 300));
364 set_sync_flag(&test_random_port_binding_make_switch, true);
366 assert(wait_sync_flag(&test_random_port_binding_node_connected, 300));
368 fprintf(stderr, "\n\x1b[32mDone Test-05\x1b[0m\n");
370 assert(wait_sync_flag(&test_random_port_binding_relay_closed, 10));
371 assert(wait_sync_flag(&test_random_port_binding_peer_closed, 10));
372 assert(wait_sync_flag(&test_random_port_binding_nut_closed, 10));
377 // Optimal PMTU test case driver
379 int test_meshlink_random_port_bindings02(void) {
380 interface_t nut_ifs[] = {{.if_peer = "wan_bridge"}};
384 .interfaces = nut_ifs,
388 interface_t peer_ifs[] = {{.if_peer = "wan_bridge"}};
392 .interfaces = peer_ifs,
396 interface_t relay_ifs[] = {{.if_peer = "wan_bridge"}};
397 namespace_t relay = {
400 .interfaces = relay_ifs,
404 interface_t wan_ifs[] = { { .if_peer = "nut" }, { .if_peer = "peer" }, { .if_peer = "relay" } };
405 namespace_t wan_bridge = {
406 .name = "wan_bridge",
408 .interfaces = wan_ifs,
412 namespace_t test_random_port_bindings_02_nodes[] = {wan_bridge, nut, peer, relay };
414 netns_state_t test_port_bindings_nodes = {
415 .test_case_name = "test_case_random_port_bindings_02",
416 .namespaces = test_random_port_bindings_02_nodes,
419 test_random_port_bindings_state = &test_port_bindings_nodes;
421 const struct CMUnitTest blackbox_group0_tests[] = {
422 cmocka_unit_test_prestate_setup_teardown(test_case_mesh_random_port_bindings_04, setup_test, teardown_test,
423 (void *)&test_random_port_bindings_state),
424 cmocka_unit_test_prestate_setup_teardown(test_case_mesh_random_port_bindings_05, setup_test, teardown_test,
425 (void *)&test_random_port_bindings_state)
427 total_tests += sizeof(blackbox_group0_tests) / sizeof(blackbox_group0_tests[0]);
429 return cmocka_run_group_tests(blackbox_group0_tests, NULL, NULL);