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) {
54 netns_create_topology(test_random_port_bindings_state);
55 fprintf(stderr, "\nCreated topology\n");
57 set_sync_flag(&test_random_port_binding_node_connected, false);
58 set_sync_flag(&test_random_port_binding_node_started, false);
59 set_sync_flag(&test_random_port_binding_peer_reachable, false);
60 set_sync_flag(&test_random_port_binding_make_switch, false);
61 set_sync_flag(&test_random_port_binding_relay_closed, false);
62 set_sync_flag(&test_random_port_binding_peer_closed, false);
63 set_sync_flag(&test_random_port_binding_nut_closed, false);
65 meshlink_destroy("nut");
66 meshlink_destroy("peer");
67 meshlink_destroy("relay");
72 static int teardown_test(void **state) {
73 meshlink_destroy("nut");
74 meshlink_destroy("peer");
75 meshlink_destroy("relay");
76 netns_destroy_topology(test_random_port_bindings_state);
81 static void execute_test(test_step_func_t step_func, void **state) {
83 fprintf(stderr, "\n\x1b[32mRunning Test\x1b[0m\n");
84 bool test_result = step_func();
91 static void message_log(meshlink_handle_t *mesh, meshlink_log_level_t level, const char *text) {
92 char *levelstr = "\x1b[32mRELAY";
94 if(strcmp(mesh->name, "peer") == 0) {
95 if(strcmp("Connection with nut activated", text) == 0) {
96 set_sync_flag(&test_random_port_binding_node_connected, true);
99 levelstr = "\x1b[34mPEER";
100 } else if(strcmp(mesh->name, "nut") == 0) {
101 if(strcmp("Connection with peer activated", text) == 0) {
102 set_sync_flag(&test_random_port_binding_node_connected, true);
105 levelstr = "\x1b[33mNUT";
108 fprintf(stderr, "%s:\x1b[0m %s\n", levelstr, text);
111 static void node_status(meshlink_handle_t *mesh, meshlink_node_t *node, bool reachable) {
115 if((strcmp(mesh->name, "nut") == 0) && (strcmp(node->name, "peer") == 0)) {
116 set_sync_flag(&test_random_port_binding_peer_reachable, true);
119 fprintf(stderr, "%s: %s joined.\n", mesh->name, node->name);
123 static void *relay_node(void *arg) {
124 mesh_arg_t *mesh_arg = (mesh_arg_t *)arg;
126 //system("ifconfig");
128 meshlink_destroy("relay");
130 relay = meshlink_open(mesh_arg->node_name, mesh_arg->confbase, mesh_arg->app_name, mesh_arg->dev_class);
133 assert_true(meshlink_start(relay));
134 fprintf(stderr, "\n\x1b[32mRelay Started\x1b[0m\n");
136 assert((peer_invite = meshlink_invite(relay, NULL, "peer")));
137 assert((nut_invite = meshlink_invite(relay, NULL, "nut")));
139 set_sync_flag(&test_random_port_binding_node_started, true);
141 meshlink_set_log_cb(relay, MESHLINK_DEBUG, message_log);
143 if(localnode == true) {
144 assert(wait_sync_flag(&test_random_port_binding_make_switch, 300));
145 meshlink_close(relay);
146 meshlink_destroy("relay");
149 set_sync_flag(&test_random_port_binding_relay_closed, true);
154 assert(wait_sync_flag(&test_random_port_binding_node_connected, 300));
156 meshlink_close(relay);
157 meshlink_destroy("relay");
160 set_sync_flag(&test_random_port_binding_relay_closed, true);
165 static void *peer_node(void *arg) {
166 mesh_arg_t *mesh_arg = (mesh_arg_t *)arg;
168 fprintf(stderr, "\n\x1b[32mPeer Thread Started\x1b[0m\n");
170 meshlink_destroy("peer");
172 peer = meshlink_open(mesh_arg->node_name, mesh_arg->confbase, mesh_arg->app_name, mesh_arg->dev_class);
174 meshlink_set_log_cb(peer, MESHLINK_DEBUG, message_log);
176 fprintf(stderr, "\n\x1b[32mPeer joining relay\x1b[0m\n");
178 assert_true(meshlink_join(peer, (const char *)mesh_arg->join_invitation));
180 assert_true(meshlink_start(peer));
182 fprintf(stderr, "\n\x1b[32mPeer Started\x1b[0m\n");
184 set_sync_flag(&test_random_port_binding_node_started, true);
186 assert(wait_sync_flag(&test_random_port_binding_make_switch, 300));
190 //meshlink_set_log_cb(peer, MESHLINK_DEBUG, message_log);
192 assert(meshlink_set_port(peer, 20000));
194 assert_true(meshlink_start(peer));
196 assert(wait_sync_flag(&test_random_port_binding_node_connected, 300));
198 meshlink_close(peer);
199 meshlink_destroy("peer");
201 set_sync_flag(&test_random_port_binding_peer_closed, true);
206 static void *nut_node(void *arg) {
207 mesh_arg_t *mesh_arg = (mesh_arg_t *)arg;
209 fprintf(stderr, "\n\x1b[32mNut Thread Started\x1b[0m\n");
211 meshlink_destroy("nut");
213 nut_instance = meshlink_open(mesh_arg->node_name, mesh_arg->confbase, mesh_arg->app_name, mesh_arg->dev_class);
214 assert(nut_instance);
216 meshlink_set_log_cb(nut_instance, MESHLINK_DEBUG, message_log);
218 fprintf(stderr, "\n\x1b[32mNut joining relay\x1b[0m\n");
220 assert_true(meshlink_join(nut_instance, (const char *)mesh_arg->join_invitation));
222 meshlink_set_node_status_cb(nut_instance, node_status);
224 assert_true(meshlink_start(nut_instance));
226 fprintf(stderr, "\n\x1b[32mNut Started\x1b[0m\n");
229 set_sync_flag(&test_random_port_binding_node_started, true);
231 assert(wait_sync_flag(&test_random_port_binding_make_switch, 300));
233 meshlink_stop(nut_instance);
235 //meshlink_set_log_cb(nut_instance, MESHLINK_DEBUG, message_log);
237 assert(meshlink_set_port(nut_instance, 30000));
239 assert_true(meshlink_start(nut_instance));
241 assert(wait_sync_flag(&test_random_port_binding_node_connected, 300));
243 meshlink_close(nut_instance);
244 meshlink_destroy("nut");
246 set_sync_flag(&test_random_port_binding_nut_closed, true);
251 /* Test Steps for Random port bindings Test Case # 4 */
252 static void test_case_mesh_random_port_bindings_04(void **state) {
253 execute_test(test_steps_mesh_random_port_bindings_04, state);
257 /* Test Steps for Random port bindings Test Case # 4
260 1. Create three node nut, peer and relay in three different name spaces.
261 2. Join nut and peer to relay with invitation.
262 3. Stop the three nodes and change the ports of nut and peer.
263 4. Start all the nodes again.
265 NUT and Peer should be able to discover each others port with the help
266 of RELAY and form the direct meta connection.
268 static bool test_steps_mesh_random_port_bindings_04(void) {
269 mesh_arg_t relay_arg = {.node_name = "relay", .confbase = "relay", .app_name = "chat", .dev_class = 0 };
270 mesh_arg_t peer_arg = {.node_name = "peer", .confbase = "peer", .app_name = "chat", .dev_class = 1 };
271 mesh_arg_t nut_arg = {.node_name = "nut", .confbase = "nut", .app_name = "chat", .dev_class = 1 };
273 netns_thread_t netns_relay_handle = {.namespace_name = "relay", .netns_thread = relay_node, .arg = &relay_arg};
274 run_node_in_namespace_thread(&netns_relay_handle);
276 assert(wait_sync_flag(&test_random_port_binding_node_started, 5));
277 fprintf(stderr, "\n\x1b[32mTest-04 : Relay Started\x1b[0m\n");
279 set_sync_flag(&test_random_port_binding_node_started, false);
280 peer_arg.join_invitation = peer_invite;
281 fprintf(stderr, "\n\x1b[32mTest-04: Got Invite {%s} for peer\x1b[0m\n", peer_arg.join_invitation);
282 netns_thread_t netns_peer_handle = {.namespace_name = "peer", .netns_thread = peer_node, .arg = &peer_arg};
283 run_node_in_namespace_thread(&netns_peer_handle);
285 assert(wait_sync_flag(&test_random_port_binding_node_started, 20));
286 fprintf(stderr, "\n\x1b[32mTest-04 : Peer Started\x1b[0m\n");
288 set_sync_flag(&test_random_port_binding_node_started, false);
289 nut_arg.join_invitation = nut_invite;
290 fprintf(stderr, "\n\x1b[32mTest-04: Got Invite {%s} for nut\x1b[0m\n", nut_arg.join_invitation);
291 netns_thread_t netns_nut_handle = {.namespace_name = "nut", .netns_thread = nut_node, .arg = &nut_arg};
292 run_node_in_namespace_thread(&netns_nut_handle);
294 assert(wait_sync_flag(&test_random_port_binding_node_started, 20));
295 fprintf(stderr, "\n\x1b[32mTest-04 : Nut Started\x1b[0m\n");
297 set_sync_flag(&test_random_port_binding_make_switch, true);
298 fprintf(stderr, "\n\x1b[32mTest-04 : Making Switch\x1b[0m\n");
300 assert(wait_sync_flag(&test_random_port_binding_node_connected, 300));
302 fprintf(stderr, "\n\x1b[32mDone Test-04\x1b[0m\n");
304 assert(wait_sync_flag(&test_random_port_binding_relay_closed, 10));
305 assert(wait_sync_flag(&test_random_port_binding_peer_closed, 10));
306 assert(wait_sync_flag(&test_random_port_binding_nut_closed, 10));
311 /* Test Steps for Random port bindings Test Case # 5 */
312 static void test_case_mesh_random_port_bindings_05(void **state) {
313 execute_test(test_steps_mesh_random_port_bindings_05, state);
317 /* Test Steps for Random port bindings Test Case # 5
320 1. Create three node nut, peer and relay in same name spaces.
321 2. Join nut and peer to relay with invitation.
322 3. Stop the three nodes and change the ports of nut and peer.
323 4. Close the relay node and start nut and peer nodes again.
325 NUT and Peer should be able to discover each others port with the help
326 of CATTA and form the direct meta connection.
328 static bool test_steps_mesh_random_port_bindings_05(void) {
331 mesh_arg_t relay_arg = {.node_name = "relay", .confbase = "relay", .app_name = "chat", .dev_class = 1 };
332 mesh_arg_t peer_arg = {.node_name = "peer", .confbase = "peer", .app_name = "chat", .dev_class = 1 };
333 mesh_arg_t nut_arg = {.node_name = "nut", .confbase = "nut", .app_name = "chat", .dev_class = 1 };
335 netns_thread_t netns_relay_handle = {.namespace_name = "relay", .netns_thread = relay_node, .arg = &relay_arg};
336 run_node_in_namespace_thread(&netns_relay_handle);
338 assert(wait_sync_flag(&test_random_port_binding_node_started, 20));
340 set_sync_flag(&test_random_port_binding_node_started, false);
341 peer_arg.join_invitation = peer_invite;
342 netns_thread_t netns_peer_handle = {.namespace_name = "peer", .netns_thread = peer_node, .arg = &peer_arg};
343 run_node_in_namespace_thread(&netns_peer_handle);
345 assert(wait_sync_flag(&test_random_port_binding_node_started, 20));
347 set_sync_flag(&test_random_port_binding_node_started, false);
348 nut_arg.join_invitation = nut_invite;
349 netns_thread_t netns_nut_handle = {.namespace_name = "nut", .netns_thread = nut_node, .arg = &nut_arg};
350 run_node_in_namespace_thread(&netns_nut_handle);
352 assert(wait_sync_flag(&test_random_port_binding_node_started, 20));
354 assert(wait_sync_flag(&test_random_port_binding_peer_reachable, 300));
356 set_sync_flag(&test_random_port_binding_make_switch, true);
358 assert(wait_sync_flag(&test_random_port_binding_node_connected, 300));
360 fprintf(stderr, "\n\x1b[32mDone Test-05\x1b[0m\n");
362 assert(wait_sync_flag(&test_random_port_binding_relay_closed, 10));
363 assert(wait_sync_flag(&test_random_port_binding_peer_closed, 10));
364 assert(wait_sync_flag(&test_random_port_binding_nut_closed, 10));
369 // Optimal PMTU test case driver
371 int test_meshlink_random_port_bindings02(void) {
372 interface_t nut_ifs[] = {{.if_peer = "wan_bridge"}};
376 .interfaces = nut_ifs,
380 interface_t peer_ifs[] = {{.if_peer = "wan_bridge"}};
384 .interfaces = peer_ifs,
388 interface_t relay_ifs[] = {{.if_peer = "wan_bridge"}};
389 namespace_t relay = {
392 .interfaces = relay_ifs,
396 interface_t wan_ifs[] = { { .if_peer = "nut" }, { .if_peer = "peer" }, { .if_peer = "relay" } };
397 namespace_t wan_bridge = {
398 .name = "wan_bridge",
400 .interfaces = wan_ifs,
404 namespace_t test_random_port_bindings_02_nodes[] = {wan_bridge, nut, peer, relay };
406 netns_state_t test_port_bindings_nodes = {
407 .test_case_name = "test_case_random_port_bindings_02",
408 .namespaces = test_random_port_bindings_02_nodes,
411 test_random_port_bindings_state = &test_port_bindings_nodes;
413 const struct CMUnitTest blackbox_group0_tests[] = {
414 cmocka_unit_test_prestate_setup_teardown(test_case_mesh_random_port_bindings_04, setup_test, teardown_test,
415 (void *)&test_random_port_bindings_state),
416 cmocka_unit_test_prestate_setup_teardown(test_case_mesh_random_port_bindings_05, setup_test, teardown_test,
417 (void *)&test_random_port_bindings_state)
419 total_tests += sizeof(blackbox_group0_tests) / sizeof(blackbox_group0_tests[0]);
421 return cmocka_run_group_tests(blackbox_group0_tests, NULL, NULL);