From de40dd736a1b048e5e0f856184f832fa4db184d3 Mon Sep 17 00:00:00 2001 From: Guus Sliepen Date: Sun, 18 Nov 2018 14:50:08 +0100 Subject: [PATCH] Add the blackbox channel connection tests. --- configure.ac | 8 + test/blackbox/Makefile.am | 10 +- test/blackbox/common/common_handlers.c | 91 ++- test/blackbox/common/common_handlers.h | 20 + test/blackbox/common/containers.c | 446 +++++++++- test/blackbox/common/containers.h | 36 +- test/blackbox/run_blackbox_tests/Makefile.am | 3 +- .../run_blackbox_tests/execute_tests.c | 1 + .../run_blackbox_tests/run_blackbox_tests.c | 5 + .../test_cases_channel_conn.c | 767 ++++++++++++++++++ .../test_cases_channel_conn.h | 2 +- .../test_case_channel_conn_01/Makefile.am | 9 + .../test_case_channel_conn_01/node_sim_nut.c | 161 ++++ .../test_case_channel_conn_01/node_sim_peer.c | 120 +++ .../test_case_channel_conn_02/Makefile.am | 9 + .../test_case_channel_conn_02/node_sim_nut.c | 163 ++++ .../test_case_channel_conn_02/node_sim_peer.c | 113 +++ .../test_case_channel_conn_03/Makefile.am | 9 + .../test_case_channel_conn_03/node_sim_nut.c | 167 ++++ .../test_case_channel_conn_03/node_sim_peer.c | 109 +++ .../test_case_channel_conn_04/Makefile.am | 9 + .../test_case_channel_conn_04/node_sim_nut.c | 159 ++++ .../test_case_channel_conn_04/node_sim_peer.c | 128 +++ .../test_case_channel_conn_05/Makefile.am | 13 + .../test_case_channel_conn_05/node_sim_nut.c | 161 ++++ .../test_case_channel_conn_05/node_sim_peer.c | 120 +++ .../node_sim_relay.c | 57 ++ .../test_case_channel_conn_06/Makefile.am | 13 + .../test_case_channel_conn_06/node_sim_nut.c | 173 ++++ .../test_case_channel_conn_06/node_sim_peer.c | 116 +++ .../node_sim_relay.c | 57 ++ .../test_case_channel_conn_07/Makefile.am | 13 + .../test_case_channel_conn_07/node_sim_nut.c | 172 ++++ .../test_case_channel_conn_07/node_sim_peer.c | 109 +++ .../node_sim_relay.c | 57 ++ .../test_case_channel_conn_08/Makefile.am | 13 + .../test_case_channel_conn_08/node_sim_nut.c | 159 ++++ .../test_case_channel_conn_08/node_sim_peer.c | 128 +++ .../node_sim_relay.c | 57 ++ 39 files changed, 3905 insertions(+), 58 deletions(-) create mode 100644 test/blackbox/run_blackbox_tests/test_cases_channel_conn.c create mode 100644 test/blackbox/test_case_channel_conn_01/Makefile.am create mode 100644 test/blackbox/test_case_channel_conn_01/node_sim_nut.c create mode 100644 test/blackbox/test_case_channel_conn_01/node_sim_peer.c create mode 100644 test/blackbox/test_case_channel_conn_02/Makefile.am create mode 100644 test/blackbox/test_case_channel_conn_02/node_sim_nut.c create mode 100644 test/blackbox/test_case_channel_conn_02/node_sim_peer.c create mode 100644 test/blackbox/test_case_channel_conn_03/Makefile.am create mode 100644 test/blackbox/test_case_channel_conn_03/node_sim_nut.c create mode 100644 test/blackbox/test_case_channel_conn_03/node_sim_peer.c create mode 100644 test/blackbox/test_case_channel_conn_04/Makefile.am create mode 100644 test/blackbox/test_case_channel_conn_04/node_sim_nut.c create mode 100644 test/blackbox/test_case_channel_conn_04/node_sim_peer.c create mode 100644 test/blackbox/test_case_channel_conn_05/Makefile.am create mode 100644 test/blackbox/test_case_channel_conn_05/node_sim_nut.c create mode 100644 test/blackbox/test_case_channel_conn_05/node_sim_peer.c create mode 100644 test/blackbox/test_case_channel_conn_05/node_sim_relay.c create mode 100644 test/blackbox/test_case_channel_conn_06/Makefile.am create mode 100644 test/blackbox/test_case_channel_conn_06/node_sim_nut.c create mode 100644 test/blackbox/test_case_channel_conn_06/node_sim_peer.c create mode 100644 test/blackbox/test_case_channel_conn_06/node_sim_relay.c create mode 100644 test/blackbox/test_case_channel_conn_07/Makefile.am create mode 100644 test/blackbox/test_case_channel_conn_07/node_sim_nut.c create mode 100644 test/blackbox/test_case_channel_conn_07/node_sim_peer.c create mode 100644 test/blackbox/test_case_channel_conn_07/node_sim_relay.c create mode 100644 test/blackbox/test_case_channel_conn_08/Makefile.am create mode 100644 test/blackbox/test_case_channel_conn_08/node_sim_nut.c create mode 100644 test/blackbox/test_case_channel_conn_08/node_sim_peer.c create mode 100644 test/blackbox/test_case_channel_conn_08/node_sim_relay.c diff --git a/configure.ac b/configure.ac index 363676ee..ed193cd4 100644 --- a/configure.ac +++ b/configure.ac @@ -145,6 +145,14 @@ AC_CONFIG_FILES([ test/Makefile test/blackbox/Makefile test/blackbox/run_blackbox_tests/Makefile + test/blackbox/test_case_channel_conn_01/Makefile + test/blackbox/test_case_channel_conn_02/Makefile + test/blackbox/test_case_channel_conn_03/Makefile + test/blackbox/test_case_channel_conn_04/Makefile + test/blackbox/test_case_channel_conn_05/Makefile + test/blackbox/test_case_channel_conn_06/Makefile + test/blackbox/test_case_channel_conn_07/Makefile + test/blackbox/test_case_channel_conn_08/Makefile test/blackbox/test_case_meta_conn_01/Makefile test/blackbox/test_case_meta_conn_02/Makefile test/blackbox/test_case_meta_conn_03/Makefile diff --git a/test/blackbox/Makefile.am b/test/blackbox/Makefile.am index 3afae4b1..3d0e6005 100644 --- a/test/blackbox/Makefile.am +++ b/test/blackbox/Makefile.am @@ -1,13 +1,21 @@ check_PROGRAMS = gen_invite - SUBDIRS = \ run_blackbox_tests \ + test_case_channel_conn_01 \ + test_case_channel_conn_02 \ + test_case_channel_conn_03 \ + test_case_channel_conn_04 \ + test_case_channel_conn_05 \ + test_case_channel_conn_06 \ + test_case_channel_conn_07 \ + test_case_channel_conn_08 \ test_case_meta_conn_01 \ test_case_meta_conn_02 \ test_case_meta_conn_03 \ test_case_meta_conn_04 \ test_case_meta_conn_05 + gen_invite_SOURCES = util/gen_invite.c common/common_handlers.c common/test_step.c common/mesh_event_handler.c gen_invite_LDADD = ../../src/libmeshlink.la gen_invite_CFLAGS = -D_GNU_SOURCE diff --git a/test/blackbox/common/common_handlers.c b/test/blackbox/common/common_handlers.c index ad32a223..d6ef7756 100644 --- a/test/blackbox/common/common_handlers.c +++ b/test/blackbox/common/common_handlers.c @@ -33,35 +33,31 @@ #include "test_step.h" #include "common_handlers.h" +#define GET_IP_FAMILY AF_INET + char *lxc_bridge = NULL; black_box_state_t *state_ptr = NULL; bool meta_conn_status[10]; +bool node_reachable_status[10]; bool test_running; -static int meshlink_get_node_in_container(const char *name) { - int i; - - for(i = 0; i < state_ptr->num_nodes; i++) { - if(!strcasecmp(state_ptr->node_names[i], name)) { - return i; - break; - } - } - - return -1; -} - void mesh_close_signal_handler(int a) { test_running = false; exit(EXIT_SUCCESS); } +void mesh_stop_start_signal_handler(int a) { + /* Stop the Mesh if it is running, otherwise start it again */ + (mesh_started) ? execute_stop() : execute_start(); +} + void setup_signals(void) { test_running = true; signal(SIGTERM, mesh_close_signal_handler); + signal(SIGINT, mesh_stop_start_signal_handler); } /* Return the IP Address of the Interface 'if_name' @@ -82,8 +78,8 @@ char *get_ip(const char *if_name) { family = ifa->ifa_addr->sa_family; - if(family == AF_INET && !strcmp(ifa->ifa_name, if_name)) { - assert(!getnameinfo(ifa->ifa_addr, (family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6), ip, NI_MAXHOST, NULL, 0, NI_NUMERICHOST)); + if(family == GET_IP_FAMILY && !strcmp(ifa->ifa_name, if_name)) { + assert(!getnameinfo(ifa->ifa_addr, (family == GET_IP_FAMILY) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6), ip, NI_MAXHOST, NULL, 0, NI_NUMERICHOST)); break; } } @@ -109,8 +105,8 @@ char *get_netmask(const char *if_name) { family = ifa->ifa_addr->sa_family; - if(family == AF_INET && !strcmp(ifa->ifa_name, if_name)) { - assert(!getnameinfo(ifa->ifa_netmask, (family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6), ip, NI_MAXHOST, NULL, 0, NI_NUMERICHOST)); + if(family == GET_IP_FAMILY && !strcmp(ifa->ifa_name, if_name)) { + assert(!getnameinfo(ifa->ifa_netmask, (family == GET_IP_FAMILY) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6), ip, NI_MAXHOST, NULL, 0, NI_NUMERICHOST)); break; } } @@ -149,35 +145,60 @@ void start_nw_intf(const char *if_name) { void meshlink_callback_node_status(meshlink_handle_t *mesh, meshlink_node_t *node, bool reachable) { + int i; + (void)mesh; fprintf(stderr, "Node %s became %s\n", node->name, (reachable) ? "reachable" : "unreachable"); + + if(state_ptr) + for(i = 0; i < state_ptr->num_nodes; i++) + if(strcmp(node->name, state_ptr->node_names[i]) == 0) { + node_reachable_status[i] = reachable; + } } void meshlink_callback_logger(meshlink_handle_t *mesh, meshlink_log_level_t level, const char *text) { + int i; + char connection_match_msg[100]; (void)mesh; (void)level; fprintf(stderr, "meshlink>> %s\n", text); - if(state_ptr) { - bool status; - char name[100]; - - if(sscanf(text, "Connection with %s activated", name) == 1) { - status = true; - } else if(sscanf(text, "Already connected to %s", name) == 1) { - status = true; - } else if(sscanf(text, "Connection closed by %s", name) == 1) { - status = false; - } else if(sscanf(text, "Closing connection with %s", name) == 1) { - status = false; - } else { - return; - } + if(state_ptr && (strstr(text, "Connection") || strstr(text, "connection"))) { + for(i = 0; i < state_ptr->num_nodes; i++) { + assert(snprintf(connection_match_msg, sizeof(connection_match_msg), + "Connection with %s", state_ptr->node_names[i]) >= 0); + + if(strstr(text, connection_match_msg) && strstr(text, "activated")) { + meta_conn_status[i] = true; + continue; + } + + assert(snprintf(connection_match_msg, sizeof(connection_match_msg), + "Already connected to %s", state_ptr->node_names[i]) >= 0); - int i = meshlink_get_node_in_container(name); - assert(i != -1); - meta_conn_status[i] = status; + if(strstr(text, connection_match_msg)) { + meta_conn_status[i] = true; + continue; + } + + assert(snprintf(connection_match_msg, sizeof(connection_match_msg), + "Connection closed by %s", state_ptr->node_names[i]) >= 0); + + if(strstr(text, connection_match_msg)) { + meta_conn_status[i] = false; + continue; + } + + assert(snprintf(connection_match_msg, sizeof(connection_match_msg), + "Closing connection with %s", state_ptr->node_names[i]) >= 0); + + if(strstr(text, connection_match_msg)) { + meta_conn_status[i] = false; + continue; + } + } } } diff --git a/test/blackbox/common/common_handlers.h b/test/blackbox/common/common_handlers.h index 7c5fbd23..e878f3b7 100644 --- a/test/blackbox/common/common_handlers.h +++ b/test/blackbox/common/common_handlers.h @@ -50,4 +50,24 @@ void meshlink_callback_node_status(meshlink_handle_t *mesh, meshlink_node_t *nod void meshlink_callback_logger(meshlink_handle_t *mesh, meshlink_log_level_t level, const char *text); +void change_ip(int node); +void create_bridge(const char *bridgeName); +void add_interface(const char *bridgeName, const char *interfaceName); +void add_veth_pair(const char *vethName1, const char *vethName2); +void bring_if_up(const char *bridgeName); +void replaceAll(char *str, const char *oldWord, const char *newWord); +void switch_bridge(const char *containerName, const char *currentBridge, const char *newBridge); +void bring_if_down(const char *bridgeName); +void del_interface(const char *bridgeName, const char *interfaceName); +void delete_bridge(const char *bridgeName); +void create_container_on_bridge(const char *containerName, const char *bridgeName, const char *ifName); +void config_dnsmasq(const char *containerName, const char *ifName, const char *listenAddress, const char *dhcpRange); +void config_nat(const char *containerName, const char *listenAddress); +void create_nat_layer(const char *containerName, const char *bridgeName, const char *ifName, const char *listenAddress, char *dhcpRange); +void destroy_nat_layer(const char *containerName, const char *bridgeName); +void incoming_firewall_ipv4(const char *packetType, int portNumber); +void incoming_firewall_ipv6(const char *packetType, int portNumber); +void outgoing_firewall_ipv4(const char *packetType, int portNumber); +void outgoing_firewall_ipv6(const char *packetType, int portNumber); + #endif // COMMON_HANDLERS_H diff --git a/test/blackbox/common/containers.c b/test/blackbox/common/containers.c index 263cbf97..d96b1a37 100644 --- a/test/blackbox/common/containers.c +++ b/test/blackbox/common/containers.c @@ -302,7 +302,7 @@ void destroy_containers(void) { test_containers[i]->stop(test_containers[i]); /* Destroy the Container */ test_containers[i]->destroy(test_containers[i]); - /* call destroy_with_snapshots() in case destroy() fails + /* Call destroy_with_snapshots() in case destroy() fails one of these two calls will always succeed */ test_containers[i]->destroy_with_snapshots(test_containers[i]); } @@ -356,7 +356,7 @@ void node_sim_in_container(const char *node, const char *device_class, const cha PRINT_TEST_CASE_MSG("node_sim_%s started in Container\n", node); } -/* Run the node_sim_ program inside the 'node''s container with event handling capable*/ +/* Run the node_sim_ program inside the 'node''s container with event handling capable */ void node_sim_in_container_event(const char *node, const char *device_class, const char *invite_url, const char *clientId, const char *import) { char node_sim_command[200]; @@ -368,8 +368,6 @@ void node_sim_in_container_event(const char *node, const char *device_class, run_in_container(node_sim_command, node, true); PRINT_TEST_CASE_MSG("node_sim_%s(Client Id :%s) started in Container with event handling\n", node, clientId); - PRINT_TEST_CASE_MSG("node_sim_%s mesh event import string : %s\n", - node, import); } /* Run the node_step.sh script inside the 'node''s container to send the 'sig' signal to the @@ -453,3 +451,443 @@ void change_ip(int node) { PRINT_TEST_CASE_MSG("Node '%s' IP Address changed to %s\n", state_ptr->node_names[node], container_ips[node]); } + +/* Return container's IP address */ +char *get_container_ip(const char *node_name) { + char *ip; + int n, node = -1, i; + + for(i = 0; i < state_ptr->num_nodes; i++) { + if(!strcasecmp(state_ptr->node_names[i], node_name)) { + node = i; + break; + } + } + + if(i == state_ptr->num_nodes) { + return NULL; + } + + n = strlen(container_ips[node]) + 1; + ip = malloc(n); + assert(ip); + strncpy(ip, container_ips[node], n); + + return ip; +} + +/* Install an app in a container */ +void install_in_container(const char *node, const char *app) { + char install_cmd[100]; + + assert(snprintf(install_cmd, sizeof(install_cmd), + "apt-get install %s -y >> /dev/null", app) >= 0); + char *ret = run_in_container(install_cmd, node, false); + // TODO: Check in container whether app has installed or not with a timeout + sleep(10); +} + +/* Simulate a network failure by adding NAT rule in the container with it's IP address */ +void block_node_ip(const char *node) { + char block_cmd[100]; + char *node_ip; + + node_ip = get_container_ip(node); + assert(node_ip); + assert(snprintf(block_cmd, sizeof(block_cmd), "iptables -A OUTPUT -p all -s %s -j DROP", node_ip) >= 0); + run_in_container(block_cmd, node, false); + + assert(snprintf(block_cmd, sizeof(block_cmd), "iptables -A INPUT -p all -s %s -j DROP", node_ip) >= 0); + run_in_container(block_cmd, node, false); + + assert(snprintf(block_cmd, sizeof(block_cmd), "iptables -A FORWARD -p all -s %s -j DROP", node_ip) >= 0); + run_in_container(block_cmd, node, false); + + free(node_ip); +} + +void accept_port_rule(const char *node, const char *chain, const char *protocol, int port) { + char block_cmd[100]; + + assert(port >= 0 && port < 65536); + assert(!strcmp(chain, "INPUT") || !strcmp(chain, "FORWARD") || !strcmp(chain, "OUTPUT")); + assert(!strcmp(protocol, "all") || !strcmp(protocol, "tcp") || !strcmp(protocol, "udp")); + assert(snprintf(block_cmd, sizeof(block_cmd), "iptables -A %s -p %s --dport %d -j ACCEPT", chain, protocol, port) >= 0); + run_in_container(block_cmd, node, false); +} + +/* Restore the network that was blocked before by the NAT rule with it's own IP address */ +void unblock_node_ip(const char *node) { + char unblock_cmd[100]; + char *node_ip; + + node_ip = get_container_ip(node); + assert(node_ip); + assert(snprintf(unblock_cmd, sizeof(unblock_cmd), "iptables -D OUTPUT -p all -s %s -j DROP", node_ip) >= 0); + run_in_container(unblock_cmd, node, false); + + assert(snprintf(unblock_cmd, sizeof(unblock_cmd), "iptables -D INPUT -p all -s %s -j DROP", node_ip) >= 0); + run_in_container(unblock_cmd, node, false); + + assert(snprintf(unblock_cmd, sizeof(unblock_cmd), "iptables -D FORWARD -p all -s %s -j DROP", node_ip) >= 0); + run_in_container(unblock_cmd, node, false); +} + +/* Takes bridgeName as input parameter and creates a bridge */ +void create_bridge(const char *bridgeName) { + char command[100] = "brctl addbr "; + strcat(command, bridgeName); + int create_bridge_status = system(command); + assert(create_bridge_status == 0); + PRINT_TEST_CASE_MSG("%s bridge created\n", bridgeName); +} + +/* Add interface for the bridge created */ +void add_interface(const char *bridgeName, const char *interfaceName) { + char command[100] = "brctl addif "; + char cmd[100] = "dhclient "; + + strcat(command, bridgeName); + strcat(command, " "); + strcat(command, interfaceName); + int addif_status = system(command); + assert(addif_status == 0); + strcat(cmd, bridgeName); + int dhclient_status = system(cmd); + assert(dhclient_status == 0); + PRINT_TEST_CASE_MSG("Added interface for %s\n", bridgeName); +} + +/* Create a veth pair and bring them up */ +void add_veth_pair(const char *vethName1, const char *vethName2) { + char command[100] = "ip link add "; + char upCommand1[100] = "ip link set "; + char upCommand2[100] = "ip link set "; + + strcat(command, vethName1); + strcat(command, " type veth peer name "); + strcat(command, vethName2); + int link_add_status = system(command); + assert(link_add_status == 0); + strcat(upCommand1, vethName1); + strcat(upCommand1, " up"); + int link_set_veth1_status = system(upCommand1); + assert(link_set_veth1_status == 0); + strcat(upCommand2, vethName2); + strcat(upCommand2, " up"); + int link_set_veth2_status = system(upCommand2); + assert(link_set_veth2_status == 0); + PRINT_TEST_CASE_MSG("Added veth pairs %s and %s\n", vethName1, vethName2); +} + +/* Bring the interface up for the bridge created */ +void bring_if_up(const char *bridgeName) { + char command[300] = "ifconfig "; + char dhcommand[300] = "dhclient "; + strcat(command, bridgeName); + strcat(command, " up"); + int if_up_status = system(command); + assert(if_up_status == 0); + sleep(2); + PRINT_TEST_CASE_MSG("Interface brought up for %s created\n", bridgeName); +} + +/** + * Replace all occurrences of a given a word in string. + */ +void replaceAll(char *str, const char *oldWord, const char *newWord) { + char *pos, temp[BUFSIZ]; + int index = 0; + int owlen; + owlen = strlen(oldWord); + + while((pos = strstr(str, oldWord)) != NULL) { + strcpy(temp, str); + index = pos - str; + str[index] = '\0'; + strcat(str, newWord); + strcat(str, temp + index + owlen); + } +} + +/* Switches the bridge for a given container */ +void switch_bridge(const char *containerName, const char *currentBridge, const char *newBridge) { + char command[100] = "lxc-stop -n "; + char command_start[100] = "lxc-start -n "; + PRINT_TEST_CASE_MSG("Switching %s container to %s\n", containerName, newBridge); + strcat(command, containerName); + strcat(command_start, containerName); + int container_stop_status = system(command); + assert(container_stop_status == 0); + sleep(2); + FILE *fPtr; + FILE *fTemp; + char path[300] = "/var/lib/lxc/"; + strcat(path, containerName); + strcat(path, "/config"); + + char buffer[BUFSIZ]; + /* Open all required files */ + fPtr = fopen(path, "r"); + fTemp = fopen("replace.tmp", "w"); + + if(fPtr == NULL || fTemp == NULL) { + PRINT_TEST_CASE_MSG("\nUnable to open file.\n"); + PRINT_TEST_CASE_MSG("Please check whether file exists and you have read/write privilege.\n"); + exit(EXIT_SUCCESS); + } + + while((fgets(buffer, BUFSIZ, fPtr)) != NULL) { + replaceAll(buffer, currentBridge, newBridge); + fputs(buffer, fTemp); + } + + fclose(fPtr); + fclose(fTemp); + remove(path); + rename("replace.tmp", path); + PRINT_TEST_CASE_MSG("Switching procedure done successfully\n"); + int container_start_status = system(command_start); + assert(container_start_status == 0); + sleep(2); +} + +/* Bring the interface down for the bridge created */ +void bring_if_down(const char *bridgeName) { + char command[300] = "ip link set dev "; + strcat(command, bridgeName); + strcat(command, " down"); + int if_down_status = system(command); + assert(if_down_status == 0); + PRINT_TEST_CASE_MSG("Interface brought down for %s created\n", bridgeName); +} + +/* Delete interface for the bridge created */ +void del_interface(const char *bridgeName, const char *interfaceName) { + char command[300] = "brctl delif "; + strcat(command, bridgeName); + strcat(command, interfaceName); + int if_delete_status = system(command); + assert(if_delete_status == 0); + PRINT_TEST_CASE_MSG("Deleted interface for %s\n", bridgeName); +} + +/* Takes bridgeName as input parameter and deletes a bridge */ +void delete_bridge(const char *bridgeName) { + bring_if_down(bridgeName); + char command[300] = "brctl delbr "; + strcat(command, bridgeName); + int bridge_delete = system(command); + assert(bridge_delete == 0); + PRINT_TEST_CASE_MSG("%s bridge deleted\n", bridgeName); + sleep(2); +} + +/* Creates container on a specified bridge with added interface */ +void create_container_on_bridge(const char *containerName, const char *bridgeName, const char *ifName) { + char command[100] = "lxc-create -t download -n "; + char cmd[100] = " -- -d ubuntu -r trusty -a "; + char start[100] = "lxc-start -n "; + FILE *fPtr; + char path[300] = "/var/lib/lxc/"; + strcat(path, containerName); + strcat(path, "/config"); + strcat(command, containerName); + strcat(command, cmd); + strcat(command, choose_arch); + int container_create_status = system(command); + assert(container_create_status == 0); + sleep(3); + assert(fPtr = fopen(path, "a+")); + fprintf(fPtr, "lxc.net.0.name = eth0\n"); + fprintf(fPtr, "\n"); + fprintf(fPtr, "lxc.net.1.type = veth\n"); + fprintf(fPtr, "lxc.net.1.flags = up\n"); + fprintf(fPtr, "lxc.net.1.link = %s\n", bridgeName); + fprintf(fPtr, "lxc.net.1.name = %s\n", ifName); + fprintf(fPtr, "lxc.net.1.hwaddr = 00:16:3e:ab:xx:xx\n"); + fclose(fPtr); + strcat(start, containerName); + int container_start_status = system(start); + assert(container_start_status == 0); + sleep(3); + PRINT_TEST_CASE_MSG("Created %s on %s with interface name %s\n", containerName, bridgeName, ifName); +} + +/* Configures dnsmasq and iptables for the specified container with inputs of listen address and dhcp range */ +void config_dnsmasq(const char *containerName, const char *ifName, const char *listenAddress, const char *dhcpRange) { + char command[500] = "echo \"apt-get install dnsmasq iptables -y\" | lxc-attach -n "; + strcat(command, containerName); + strcat(command, " --"); + int iptables_install_status = system(command); + assert(iptables_install_status == 0); + sleep(5); + char com1[300] = "echo \"echo \"interface=eth1\" >> /etc/dnsmasq.conf\" | lxc-attach -n "; + strcat(com1, containerName); + strcat(com1, " --"); + int dnsmasq_status = system(com1); + assert(dnsmasq_status == 0); + sleep(5); + char com2[300] = "echo \"echo \"bind-interfaces\" >> /etc/dnsmasq.conf\" | lxc-attach -n "; + strcat(com2, containerName); + strcat(com2, " --"); + dnsmasq_status = system(com2); + assert(dnsmasq_status == 0); + sleep(5); + char com3[300] = "echo \"echo \"listen-address="; + strcat(com3, listenAddress); + strcat(com3, "\" >> /etc/dnsmasq.conf\" | lxc-attach -n "); + strcat(com3, containerName); + strcat(com3, " --"); + dnsmasq_status = system(com3); + assert(dnsmasq_status == 0); + sleep(5); + char com4[300] = "echo \"echo \"dhcp-range="; + strcat(com4, dhcpRange); + strcat(com4, "\" >> /etc/dnsmasq.conf\" | lxc-attach -n "); + strcat(com4, containerName); + strcat(com4, " --"); + dnsmasq_status = system(com4); + assert(dnsmasq_status == 0); + sleep(5); + char cmd[300] = "echo \"ifconfig "; + strcat(cmd, ifName); + strcat(cmd, " "); + strcat(cmd, listenAddress); + strcat(cmd, " netmask 255.255.255.0 up\" | lxc-attach -n "); + strcat(cmd, containerName); + strcat(cmd, " --"); + dnsmasq_status = system(cmd); + assert(dnsmasq_status == 0); + sleep(2); + char com[500] = "echo \"service dnsmasq restart >> /dev/null\" | lxc-attach -n "; + strcat(com, containerName); + strcat(com, " --"); + dnsmasq_status = system(com); + assert(dnsmasq_status == 0); + sleep(2); + PRINT_TEST_CASE_MSG("Configured dnsmasq in %s with interface name %s, listen-address = %s, dhcp-range = %s\n", containerName, ifName, listenAddress, dhcpRange); +} + +/* Configure the NAT rules inside the container */ +void config_nat(const char *containerName, const char *listenAddress) { + char *last_dot_in_ip; + int last_ip_byte = 0; + char new_ip[300] = {0}; + strncpy(new_ip, listenAddress, sizeof(new_ip)); + assert(last_dot_in_ip = strrchr(new_ip, '.')); + assert(snprintf(last_dot_in_ip + 1, 4, "%d", last_ip_byte) >= 0); + char comd[300] = "echo \"iptables -t nat -A POSTROUTING -s "; + strcat(comd, new_ip); + strcat(comd, "/24 ! -d "); + strcat(comd, new_ip); + strcat(comd, "/24 -j MASQUERADE\" | lxc-attach -n "); + strcat(comd, containerName); + strcat(comd, " --"); + int conf_nat_status = system(comd); + assert(conf_nat_status == 0); + sleep(2); + PRINT_TEST_CASE_MSG("Configured NAT on %s\n", containerName); +} + +/* Creates a NAT layer on a specified bridge with certain dhcp range to allocate ips for nodes */ +void create_nat_layer(const char *containerName, const char *bridgeName, const char *ifName, const char *listenAddress, char *dhcpRange) { + create_bridge(bridgeName); + bring_if_up(bridgeName); + create_container_on_bridge(containerName, bridgeName, ifName); + config_dnsmasq(containerName, ifName, listenAddress, dhcpRange); + config_nat(containerName, listenAddress); + PRINT_TEST_CASE_MSG("NAT layer created with %s\n", containerName); +} + +/* Destroys the NAT layer created */ +void destroy_nat_layer(const char *containerName, const char *bridgeName) { + bring_if_down(bridgeName); + delete_bridge(bridgeName); + char command[100] = "lxc-stop -n "; + strcat(command, containerName); + int container_stop_status = system(command); + assert(container_stop_status == 0); + char destroy[100] = "lxc-destroy -n "; + strcat(destroy, containerName); + strcat(destroy, " -s"); + int container_destroy_status = system(destroy); + assert(container_destroy_status == 0); + PRINT_TEST_CASE_MSG("NAT layer destroyed with %s\n", containerName); +} + +/* Add incoming firewall rules for ipv4 addresses with packet type and port number */ +void incoming_firewall_ipv4(const char *packetType, int portNumber) { + char buf[5]; + snprintf(buf, sizeof(buf), "%d", portNumber); + assert(system("iptables -F") == 0); + assert(system("iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT") == 0); + assert(system("iptables -A INPUT -s 127.0.0.1 -d 127.0.0.1 -j ACCEPT") == 0); + char command[100] = "iptables -A INPUT -p "; + strcat(command, packetType); + strcat(command, " --dport "); + strcat(command, buf); + strcat(command, " -j ACCEPT"); + assert(system(command) == 0); + sleep(2); + assert(system("iptables -A INPUT -j DROP") == 0); + PRINT_TEST_CASE_MSG("Firewall for incoming requests added on IPv4"); + assert(system("iptables -L") == 0); +} + +/* Add incoming firewall rules for ipv6 addresses with packet type and port number */ +void incoming_firewall_ipv6(const char *packetType, int portNumber) { + char buf[5]; + snprintf(buf, sizeof(buf), "%d", portNumber); + assert(system("ip6tables -F") == 0); + assert(system("ip6tables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT") == 0); + assert(system("ip6tables -A INPUT -s ::1 -d ::1 -j ACCEPT") == 0); + char command[100] = "ip6tables -A INPUT -p "; + strcat(command, packetType); + strcat(command, " --dport "); + strcat(command, buf); + strcat(command, " -j ACCEPT"); + assert(system(command) == 0); + sleep(2); + assert(system("ip6tables -A INPUT -j DROP") == 0); + PRINT_TEST_CASE_MSG("Firewall for incoming requests added on IPv6"); + assert(system("ip6tables -L") == 0); +} + +/* Add outgoing firewall rules for ipv4 addresses with packet type and port number */ +void outgoing_firewall_ipv4(const char *packetType, int portNumber) { + char buf[5]; + snprintf(buf, sizeof(buf), "%d", portNumber); + assert(system("iptables -F") == 0); + assert(system("iptables -A OUTPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT") == 0); + assert(system("iptables -A OUTPUT -s 127.0.0.1 -d 127.0.0.1 -j ACCEPT") == 0); + char command[100] = "iptables -A OUTPUT -p "; + strcat(command, packetType); + strcat(command, " --dport "); + strcat(command, buf); + strcat(command, " -j ACCEPT"); + assert(system(command) == 0); + sleep(2); + assert(system("iptables -A OUTPUT -j DROP") == 0); + PRINT_TEST_CASE_MSG("Firewall for outgoing requests added on IPv4"); + assert(system("iptables -L") == 0); +} + +/* Add outgoing firewall rules for ipv6 addresses with packet type and port number */ +void outgoing_firewall_ipv6(const char *packetType, int portNumber) { + char buf[5]; + snprintf(buf, sizeof(buf), "%d", portNumber); + assert(system("ip6tables -F") == 0); + assert(system("ip6tables -A OUTPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT") == 0); + assert(system("ip6tables -A OUTPUT -s ::1 -d ::1 -j ACCEPT") == 0); + char command[100] = "ip6tables -A OUTPUT -p "; + strcat(command, packetType); + strcat(command, " --dport "); + strcat(command, buf); + strcat(command, " -j ACCEPT"); + assert(system(command) == 0); + sleep(2); + assert(system("ip6tables -A OUTPUT -j DROP") == 0); + PRINT_TEST_CASE_MSG("Firewall for outgoing requests added on IPv6"); + assert(system("ip6tables -L") == 0); +} diff --git a/test/blackbox/common/containers.h b/test/blackbox/common/containers.h index 49cbb7c3..66b6c51d 100644 --- a/test/blackbox/common/containers.h +++ b/test/blackbox/common/containers.h @@ -28,21 +28,25 @@ extern char *lxc_path; -struct lxc_container *find_container(const char *name); -void rename_container(const char *old_name, const char *new_name); -char *run_in_container(const char *cmd, const char *node, bool daemonize); -void container_wait_ip(int node); -void create_containers(const char *node_names[], int num_nodes); -void setup_containers(void **state); -void destroy_containers(void); -void restart_all_containers(void); -char *invite_in_container(const char *inviter, const char *invitee); -void node_sim_in_container(const char *node, const char *device_class, const char *invite_url); -void node_sim_in_container_event(const char *node, const char *device_class, - const char *invite_url, const char *clientId, const char *import); -void node_step_in_container(const char *node, const char *sig); -void change_ip(int node); - -char *get_container_ip(int node); +extern struct lxc_container *find_container(const char *name); +extern void rename_container(const char *old_name, const char *new_name); +extern char *run_in_container(const char *cmd, const char *node, bool daemonize); +extern void container_wait_ip(int node); +extern void create_containers(const char *node_names[], int num_nodes); +extern void setup_containers(void **state); +extern void destroy_containers(void); +extern void restart_all_containers(void); +extern char *invite_in_container(const char *inviter, const char *invitee); +extern void node_sim_in_container(const char *node, const char *device_class, const char *invite_url); +extern void node_sim_in_container_event(const char *node, const char *device_class, + const char *invite_url, const char *clientId, const char *import); +extern void node_step_in_container(const char *node, const char *sig); +extern void change_ip(int node); + +extern char *get_container_ip(const char *node_name); +extern void install_in_container(const char *node, const char *app); +extern void unblock_node_ip(const char *node); +extern void block_node_ip(const char *node); +void accept_port_rule(const char *node, const char *chain, const char *protocol, int port); #endif // CONTAINERS_H diff --git a/test/blackbox/run_blackbox_tests/Makefile.am b/test/blackbox/run_blackbox_tests/Makefile.am index defd4b57..5b6877df 100644 --- a/test/blackbox/run_blackbox_tests/Makefile.am +++ b/test/blackbox/run_blackbox_tests/Makefile.am @@ -44,7 +44,8 @@ run_blackbox_tests_SOURCES = \ test_cases_channel_open.c \ test_cases_channel_close.c \ test_cases_channel_send.c \ - test_cases_channel_shutdown.c + test_cases_channel_shutdown.c \ + test_cases_channel_conn.c run_blackbox_tests_LDADD = ../../../src/libmeshlink.la -llxc -lcmocka run_blackbox_tests_CFLAGS = -D_GNU_SOURCE diff --git a/test/blackbox/run_blackbox_tests/execute_tests.c b/test/blackbox/run_blackbox_tests/execute_tests.c index 2f9730e1..b9fd1fa9 100644 --- a/test/blackbox/run_blackbox_tests/execute_tests.c +++ b/test/blackbox/run_blackbox_tests/execute_tests.c @@ -35,6 +35,7 @@ int setup_test(void **state) { for(i = 0; i < state_ptr->num_nodes; i++) { meta_conn_status[i] = false; + node_reachable_status[i] = false; } setup_containers(state); diff --git a/test/blackbox/run_blackbox_tests/run_blackbox_tests.c b/test/blackbox/run_blackbox_tests/run_blackbox_tests.c index 3f6e081a..691ac215 100644 --- a/test/blackbox/run_blackbox_tests/run_blackbox_tests.c +++ b/test/blackbox/run_blackbox_tests/run_blackbox_tests.c @@ -62,6 +62,9 @@ #include "test_cases_channel_set_poll_cb.h" #include "test_cases_channel_set_receive_cb.h" #include "test_cases_hint_address.h" + +#include "test_cases_channel_conn.h" + #include "../common/containers.h" #include "../common/common_handlers.h" @@ -120,6 +123,8 @@ int main(int argc, char *argv[]) { failed_tests += test_meshlink_channel_open(); failed_tests += test_meshlink_channel_close(); + failed_tests += test_meshlink_channel_conn(); + printf("[ PASSED ] %d test(s).\n", total_tests - failed_tests); printf("[ FAILED ] %d test(s).\n", failed_tests); diff --git a/test/blackbox/run_blackbox_tests/test_cases_channel_conn.c b/test/blackbox/run_blackbox_tests/test_cases_channel_conn.c new file mode 100644 index 00000000..4bccf884 --- /dev/null +++ b/test/blackbox/run_blackbox_tests/test_cases_channel_conn.c @@ -0,0 +1,767 @@ +/* + test_cases_channel_conn.c -- Execution of specific meshlink black box test cases + Copyright (C) 2018 Guus Sliepen + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include "execute_tests.h" +#include "test_cases_channel_conn.h" +#include "../common/containers.h" +#include "../common/test_step.h" +#include "../common/common_handlers.h" +#include "../common/mesh_event_handler.h" + +#define PEER_ID "0" +#define NUT_ID "1" +#define RELAY_ID "2" + +static void test_case_channel_conn_01(void **state); +static bool test_steps_channel_conn_01(void); +static void test_case_channel_conn_02(void **state); +static bool test_steps_channel_conn_02(void); +static void test_case_channel_conn_03(void **state); +static bool test_steps_channel_conn_03(void); +static void test_case_channel_conn_04(void **state); +static bool test_steps_channel_conn_04(void); +static void test_case_channel_conn_05(void **state); +static bool test_steps_channel_conn_05(void); +static void test_case_channel_conn_06(void **state); +static bool test_steps_channel_conn_06(void); +static void test_case_channel_conn_07(void **state); +static bool test_steps_channel_conn_07(void); +static void test_case_channel_conn_08(void **state); +static bool test_steps_channel_conn_08(void); + +static char *test_channel_conn_2_nodes[] = { "peer", "nut" }; +static char *test_channel_conn_3_nodes[] = { "peer", "nut", "relay" }; + +static black_box_state_t test_case_channel_conn_01_state = { + .test_case_name = "test_case_channel_conn_01", + .node_names = test_channel_conn_2_nodes, + .num_nodes = 2, +}; +static black_box_state_t test_case_channel_conn_02_state = { + .test_case_name = "test_case_channel_conn_02", + .node_names = test_channel_conn_2_nodes, + .num_nodes = 2, +}; +static black_box_state_t test_case_channel_conn_03_state = { + .test_case_name = "test_case_channel_conn_03", + .node_names = test_channel_conn_2_nodes, + .num_nodes = 2, +}; +static black_box_state_t test_case_channel_conn_04_state = { + .test_case_name = "test_case_channel_conn_04", + .node_names = test_channel_conn_2_nodes, + .num_nodes = 2, +}; +static black_box_state_t test_case_channel_conn_05_state = { + .test_case_name = "test_case_channel_conn_05", + .node_names = test_channel_conn_3_nodes, + .num_nodes = 3, +}; +static black_box_state_t test_case_channel_conn_06_state = { + .test_case_name = "test_case_channel_conn_06", + .node_names = test_channel_conn_3_nodes, + .num_nodes = 3, +}; +static black_box_state_t test_case_channel_conn_07_state = { + .test_case_name = "test_case_channel_conn_07", + .node_names = test_channel_conn_3_nodes, + .num_nodes = 3, +}; +static black_box_state_t test_case_channel_conn_08_state = { + .test_case_name = "test_case_channel_conn_08", + .node_names = test_channel_conn_3_nodes, + .num_nodes = 3, +}; + +static bool joined; +static bool channel_opened; +static bool node_restarted; +static bool received_error; +static bool channel_received; +static bool node_reachable; +static bool node_unreachable; + +/* Callback function for handling channel connection test cases mesh events */ +static void channel_conn_cb(mesh_event_payload_t payload) { + switch(payload.mesh_event) { + case NODE_JOINED : + joined = true; + break; + + case CHANNEL_OPENED : + channel_opened = true; + break; + + case NODE_RESTARTED : + node_restarted = true; + break; + + case ERR_NETWORK : + received_error = true; + break; + + case CHANNEL_DATA_RECIEVED : + channel_received = true; + break; + + case NODE_UNREACHABLE : + node_unreachable = true; + break; + + case NODE_REACHABLE : + node_reachable = true; + break; + + default : + PRINT_TEST_CASE_MSG("Undefined event occurred\n"); + } + + return; +} + +/* Execute channel connections Test Case # 1 - simulate a temporary network + failure of about 30 seconds, messages sent while the network was down + should be received by the other side after the network comes up again. */ +static void test_case_channel_conn_01(void **state) { + execute_test(test_steps_channel_conn_01, state); + return; +} + +/* Test Steps for channel connections Test Case # 1 + + Test Steps: + 1. Run NUT & peer node instances and open a channel between them + 2. Simulate a network failure in NUT's container for about 30 secs, + meanwhile send data via channel from NUT to peer. + 3. After restoring network, peer node receive's data via channel. + + Expected Result: + Peer node receives data via channel without any error after restoring network. +*/ +static bool test_steps_channel_conn_01(void) { + char *invite_nut; + char *import; + + joined = false; + channel_opened = false; + channel_received = false; + + // Setup Containers + + install_in_container("nut", "iptables"); + accept_port_rule("nut", "OUTPUT", "udp", 9000); + import = mesh_event_sock_create(eth_if_name); + invite_nut = invite_in_container("peer", "nut"); + assert(invite_nut); + + // Run node instances in containers & open a channel + + node_sim_in_container_event("peer", "1", NULL, PEER_ID, import); + node_sim_in_container_event("nut", "1", invite_nut, NUT_ID, import); + + wait_for_event(channel_conn_cb, 30); + assert_int_equal(joined, true); + + wait_for_event(channel_conn_cb, 30); + assert_int_equal(channel_opened, true); + + // Simulate network failure in NUT's LXC container with it's IP address as NAT rule + + block_node_ip("nut"); + sleep(2); + + // Sending SIGUSR1 signal to node-under-test indicating the network failure + + node_step_in_container("nut", "SIGUSR1"); + sleep(30); + + // Restore NUT's network + + unblock_node_ip("nut"); + + // Wait for peer node to receive data via channel from NUT + + wait_for_event(channel_conn_cb, 60); + assert_int_equal(channel_received, true); + + free(invite_nut); + free(import); + return true; +} + +/* Execute channel connections Test Case # 2 - a simulated network failure + of more than 1 minute, and sending messages over the channel during the + failure. Then after about 1 minute, the channel should receive an error */ +static void test_case_channel_conn_02(void **state) { + execute_test(test_steps_channel_conn_02, state); + return; +} + +/* Test Steps for channel connections Test Case # 2 + + Test Steps: + 1. Run NUT and peer node instances in containers and open a channel between them. + 2. Create a network failure for about 90 secs in NUT container + and signal NUT node about the network failure. + 3. Meanwhile NUT sends data to peer via channel and restore the network after + 90 secs. + + Expected Result: + Peer node should receive error closing the channel after channel timeout(60 secs). +*/ +static bool test_steps_channel_conn_02(void) { + char *invite_nut; + char *import; + + joined = false; + channel_opened = false; + received_error = false; + + // Setup containers + + install_in_container("nut", "iptables"); + accept_port_rule("nut", "OUTPUT", "udp", 9000); + import = mesh_event_sock_create(eth_if_name); + invite_nut = invite_in_container("peer", "nut"); + assert(invite_nut); + + // Run NUT and peer node instances in containers & open a channel + + node_sim_in_container_event("peer", "1", NULL, PEER_ID, import); + node_sim_in_container_event("nut", "1", invite_nut, NUT_ID, import); + + wait_for_event(channel_conn_cb, 30); + assert_int_equal(joined, true); + + wait_for_event(channel_conn_cb, 10); + assert_int_equal(channel_opened, true); + + // Simulate network failure in NUT's LXC container with it's IP address as NAT rule + + block_node_ip("nut"); + + // Sending SIGUSR1 signal to node-under-test indicating the network failure + + node_step_in_container("nut", "SIGUSR1"); + sleep(90); + + // Restore NUT containers network after 90 secs + + unblock_node_ip("nut"); + + // Wait for peer node to send the event about the channel error occurred with length = 0 + + wait_for_event(channel_conn_cb, 90); + assert_int_equal(received_error, true); + + free(invite_nut); + free(import); + return true; +} + +/* Execute channel connections Test Case # 3 - a simulated network failure + once node instance is made offline restore the network and send data via + channel */ +static void test_case_channel_conn_03(void **state) { + execute_test(test_steps_channel_conn_03, state); + return; +} + +/* Test Steps for channel connections Test Case # 3 + + Test Steps: + 1. Run NUT and peer node instances and open a channel between them. + 2. Create a network failure in NUT container, bring NUT node offline + and receive the status at test driver and restore the network + 3. After peer node instance is reachable to NUT node send data via channel + + Expected Result: + Peer node should receive data from NUT without any error. +*/ +static bool test_steps_channel_conn_03(void) { + char *invite_nut; + char *import; + + joined = false; + channel_opened = false; + node_unreachable = false; + node_reachable = false; + channel_received = false; + + // Setup containers + + install_in_container("nut", "iptables"); + accept_port_rule("nut", "OUTPUT", "udp", 9000); + import = mesh_event_sock_create(eth_if_name); + invite_nut = invite_in_container("peer", "nut"); + assert(invite_nut); + + // Run NUT and peer node instances in containers & open a channel + + node_sim_in_container_event("peer", "1", NULL, PEER_ID, import); + node_sim_in_container_event("nut", "1", invite_nut, NUT_ID, import); + + wait_for_event(channel_conn_cb, 30); + assert_int_equal(joined, true); + + wait_for_event(channel_conn_cb, 10); + assert_int_equal(channel_opened, true); + + // Simulate network failure in NUT's LXC container with it's IP address as NAT rule + + node_reachable = false; + block_node_ip("nut"); + + // Sending SIGUSR1 signal to node-under-test indicating the network failure + + node_step_in_container("nut", "SIGUSR1"); + + // Wait for the node status to become unreachable + + wait_for_event(channel_conn_cb, 100); + assert_int_equal(node_unreachable, true); + + // Restore NUT container's network + + unblock_node_ip("nut"); + + // Wait for the node status to become reachable + + wait_for_event(channel_conn_cb, 100); + assert_int_equal(node_reachable, true); + + // Wait for data to be received at peer via channel from NUT after restoring n/w + + wait_for_event(channel_conn_cb, 90); + assert_int_equal(channel_received, true); + + free(invite_nut); + free(import); + return true; +} + +/* Execute channel connections Test Case # 4 - receiving an error when node-under-test + tries to send data on channel to peer node after peer node stops and starts the + node instance */ +static void test_case_channel_conn_04(void **state) { + execute_test(test_steps_channel_conn_04, state); + return; +} + +/* Test Steps for Meta-connections Test Case # 4 + + Test Steps: + 1. Run peer and NUT node instances in containers and open a channel between them. + 2. Stop and start the NUT node instance and wait for about > 60 secs. + 3. Send data via channel from Peer node and wait for event in test driver. + + Expected Result: + Peer node should receive error(as length = 0) in receive callback of peer node's instance. +*/ +static bool test_steps_channel_conn_04(void) { + char *invite_nut; + char *import; + + joined = false; + channel_opened = false; + node_restarted = false; + received_error = false; + import = mesh_event_sock_create(eth_if_name); + invite_nut = invite_in_container("peer", "nut"); + assert(invite_nut); + + // Run NUT and peer node instances in containers and open a channel + + node_sim_in_container_event("peer", "1", NULL, PEER_ID, import); + node_sim_in_container_event("nut", "1", invite_nut, NUT_ID, import); + + wait_for_event(channel_conn_cb, 10); + assert_int_equal(joined, true); + + wait_for_event(channel_conn_cb, 10); + assert_int_equal(channel_opened, true); + + // Wait for NUT node instance to stop and start + + wait_for_event(channel_conn_cb, 60); + assert_int_equal(node_restarted, true); + + sleep(60); + + // After 1 min the channel between NUT and peer should result in error + + wait_for_event(channel_conn_cb, 10); + assert_int_equal(received_error, true); + + return true; +} + +/* Execute channel connections Test Case # 5 - simulate a temporary network + failure of about 30 seconds, messages sent while the network was down + should be received by the other side after the network comes up again. */ +static void test_case_channel_conn_05(void **state) { + execute_test(test_steps_channel_conn_05, state); + return; +} + +/* Test Steps for channel connections Test Case # 5 + + Test Steps: + 1. Run NUT, relay & peer node instances with relay inviting NUT and peer + and open a channel between them + 2. Simulate a network failure in NUT's container for about 30 secs, + meanwhile send data via channel from NUT to peer. + 3. After restoring network, peer node receive's data via channel. + + Expected Result: + Peer node receives data via channel without any error after restoring network. +*/ +static bool test_steps_channel_conn_05(void) { + char *invite_nut, *invite_peer; + char *import; + + joined = false; + channel_opened = false; + channel_received = false; + + // Setup containers + + install_in_container("nut", "iptables"); + accept_port_rule("nut", "OUTPUT", "udp", 9000); + import = mesh_event_sock_create(eth_if_name); + invite_peer = invite_in_container("relay", "peer"); + invite_nut = invite_in_container("relay", "nut"); + assert(invite_nut); + assert(invite_peer); + + // Run node instances and open a channel between NUT and peer nodes + + node_sim_in_container_event("relay", "1", NULL, RELAY_ID, import); + node_sim_in_container_event("peer", "1", invite_peer, PEER_ID, import); + node_sim_in_container_event("nut", "1", invite_nut, NUT_ID, import); + + wait_for_event(channel_conn_cb, 30); + assert_int_equal(joined, true); + + wait_for_event(channel_conn_cb, 30); + assert_int_equal(channel_opened, true); + + // Create a network failure in NUT node's container with it's IP address + + block_node_ip("nut"); + + // Sending SIGUSR1 signal to node-under-test indicating the network failure + + node_step_in_container("nut", "SIGUSR1"); + sleep(30); + + // Restore the network + + unblock_node_ip("nut"); + + // Wait for peer to get data from NUT node via channel after restoring network in < 60 secs + + wait_for_event(channel_conn_cb, 60); + assert_int_equal(channel_received, true); + + free(invite_nut); + free(invite_peer); + free(import); + return true; +} + +/* Execute channel connections Test Case # 6 - a simulated network failure + of more than 1 minute, and sending messages over the channel during the + failure. Then after about 1 minute, the channel should receive an error */ +static void test_case_channel_conn_06(void **state) { + execute_test(test_steps_channel_conn_06, state); + return; +} + +/* Test Steps for channel connections Test Case # 6 + + Test Steps: + 1. Run NUT, relay & peer node instances with relay inviting NUT and peer + and open a channel between them + 2. Create a network failure for about 90 secs in NUT container + and signal NUT node about the network failure. + 3. Meanwhile NUT sends data to peer via channel and restore the network after + 90 secs. + + Expected Result: + Peer node should receive error closing the channel after channel timeout(60 secs). +*/ +static bool test_steps_channel_conn_06(void) { + char *invite_nut, *invite_peer; + char *import; + + joined = false; + channel_opened = false; + received_error = false; + + // Setup containers + + install_in_container("nut", "iptables"); + accept_port_rule("nut", "OUTPUT", "udp", 9000); + import = mesh_event_sock_create(eth_if_name); + invite_peer = invite_in_container("relay", "peer"); + assert(invite_peer); + invite_nut = invite_in_container("relay", "nut"); + assert(invite_nut); + + // Run nodes in containers and open a channel between NUt and peer + + node_sim_in_container_event("relay", "1", NULL, RELAY_ID, import); + node_sim_in_container_event("peer", "1", invite_peer, PEER_ID, import); + node_sim_in_container_event("nut", "1", invite_nut, NUT_ID, import); + + wait_for_event(channel_conn_cb, 30); + assert_int_equal(joined, true); + + wait_for_event(channel_conn_cb, 10); + assert_int_equal(channel_opened, true); + + // Simulate a network failure in NUT's container for > 60 secs + + block_node_ip("nut"); + + // Sending SIGUSR1 signal to node-under-test indicating the network failure + + node_step_in_container("nut", "SIGUSR1"); + sleep(90); + + // Restore the network after 90 secs + + unblock_node_ip("nut"); + + // Wait for channel to receive error and receive the event + + wait_for_event(channel_conn_cb, 90); + assert_int_equal(received_error, true); + + free(invite_nut); + free(invite_peer); + free(import); + return true; +} + +/* Execute channel connections Test Case # 7 - a simulated network failure + once node instance is made offline restore the network and send data via + channel */ +static void test_case_channel_conn_07(void **state) { + execute_test(test_steps_channel_conn_07, state); + return; +} + +/* Test Steps for channel connections Test Case # 7 + + Test Steps: + 1. Run NUT, relay & peer node instances with relay inviting NUT and peer + and open a channel between them + 2. Create a network failure in NUT container, bring NUT node offline + and receive the status at test driver and restore the network + 3. After peer node instance is reachable to NUT node send data via channel + + Expected Result: + Peer node should receive data from NUT without any error. +*/ +static bool test_steps_channel_conn_07(void) { + char *invite_nut, *invite_peer; + char *import; + + joined = false; + channel_opened = false; + node_unreachable = false; + node_reachable = false; + channel_received = false; + + // Setup containers + + install_in_container("nut", "iptables"); + accept_port_rule("nut", "OUTPUT", "udp", 9000); + import = mesh_event_sock_create(eth_if_name); + invite_peer = invite_in_container("relay", "peer"); + invite_nut = invite_in_container("relay", "nut"); + assert(invite_nut); + assert(invite_peer); + + // Run nodes and open a channel + + node_sim_in_container_event("relay", "1", NULL, RELAY_ID, import); + node_sim_in_container_event("peer", "1", invite_peer, PEER_ID, import); + node_sim_in_container_event("nut", "1", invite_nut, NUT_ID, import); + + wait_for_event(channel_conn_cb, 30); + assert_int_equal(joined, true); + + wait_for_event(channel_conn_cb, 15); + assert_int_equal(channel_opened, true); + + // Simulate a network failure + + node_reachable = false; + block_node_ip("nut"); + + // Sending SIGUSR1 signal to node-under-test indicating the network failure + + node_step_in_container("nut", "SIGUSR1"); + + // Wait for node to become unreachable + + wait_for_event(channel_conn_cb, 100); + assert_int_equal(node_unreachable, true); + + // Restore the network + + unblock_node_ip("nut"); + + // Wait for node to become reachable after restoring n/w + + wait_for_event(channel_conn_cb, 100); + assert_int_equal(node_reachable, true); + + // Wait for peer node to receive data via channel without any error + + wait_for_event(channel_conn_cb, 90); + assert_int_equal(channel_received, true); + + free(invite_nut); + free(invite_peer); + free(import); + return true; +} + +/* Execute channel connections Test Case # 8 - receiving an error when node-under-test + tries to send data on channel to peer node after peer node stops and starts the + node instance */ +static void test_case_channel_conn_08(void **state) { + execute_test(test_steps_channel_conn_08, state); + return; +} + +/* Test Steps for Meta-connections Test Case # 8 + + Test Steps: + 1. Run NUT, relay & peer node instances with relay inviting NUT and peer + and open a channel between them + 2. Stop and start the NUT node instance and wait for about > 60 secs. + 3. Send data via channel from Peer node and wait for event in test driver. + + Expected Result: + Peer node should receive error(as length = 0) in receive callback of peer node's instance. +*/ +static bool test_steps_channel_conn_08(void) { + char *invite_nut, *invite_peer; + char *import; + + joined = false; + channel_opened = false; + node_restarted = false; + received_error = false; + + // Setup containers + + import = mesh_event_sock_create(eth_if_name); + invite_peer = invite_in_container("relay", "peer"); + invite_nut = invite_in_container("relay", "nut"); + assert(invite_nut); + assert(invite_peer); + + // Run nodes and open a channel between NUT and peer + + node_sim_in_container_event("relay", "1", NULL, RELAY_ID, import); + node_sim_in_container_event("peer", "1", invite_peer, PEER_ID, import); + node_sim_in_container_event("nut", "1", invite_nut, NUT_ID, import); + + wait_for_event(channel_conn_cb, 10); + assert_int_equal(joined, true); + + wait_for_event(channel_conn_cb, 10); + assert_int_equal(channel_opened, true); + + // Wait for NUT node to restart it's instance + + wait_for_event(channel_conn_cb, 60); + assert_int_equal(node_restarted, true); + + sleep(60); + + // Signal peer to send data to NUT node via channel + + node_step_in_container("peer", "SIGUSR1"); + + // Wait for peer to receive channel error + + wait_for_event(channel_conn_cb, 10); + assert_int_equal(received_error, true); + + free(invite_nut); + free(invite_peer); + free(import); + return true; +} + +static int black_box_group_setup(void **state) { + const char *nodes[] = { "peer", "nut", "relay" }; + int num_nodes = sizeof(nodes) / sizeof(nodes[0]); + + printf("Creating Containers\n"); + destroy_containers(); + create_containers(nodes, num_nodes); + + return 0; +} + +static int black_box_group_teardown(void **state) { + printf("Destroying Containers\n"); + destroy_containers(); + + return 0; +} + +int test_meshlink_channel_conn(void) { + const struct CMUnitTest blackbox_group0_tests[] = { + cmocka_unit_test_prestate_setup_teardown(test_case_channel_conn_01, setup_test, teardown_test, + (void *)&test_case_channel_conn_01_state), + cmocka_unit_test_prestate_setup_teardown(test_case_channel_conn_02, setup_test, teardown_test, + (void *)&test_case_channel_conn_02_state), + cmocka_unit_test_prestate_setup_teardown(test_case_channel_conn_03, setup_test, teardown_test, + (void *)&test_case_channel_conn_03_state), + cmocka_unit_test_prestate_setup_teardown(test_case_channel_conn_04, setup_test, teardown_test, + (void *)&test_case_channel_conn_04_state), + cmocka_unit_test_prestate_setup_teardown(test_case_channel_conn_05, setup_test, teardown_test, + (void *)&test_case_channel_conn_05_state), + cmocka_unit_test_prestate_setup_teardown(test_case_channel_conn_06, setup_test, teardown_test, + (void *)&test_case_channel_conn_06_state), + cmocka_unit_test_prestate_setup_teardown(test_case_channel_conn_07, setup_test, teardown_test, + (void *)&test_case_channel_conn_07_state), + cmocka_unit_test_prestate_setup_teardown(test_case_channel_conn_08, setup_test, teardown_test, + (void *)&test_case_channel_conn_08_state) + }; + total_tests += sizeof(blackbox_group0_tests) / sizeof(blackbox_group0_tests[0]); + + return cmocka_run_group_tests(blackbox_group0_tests, black_box_group_setup, black_box_group_teardown); +} diff --git a/test/blackbox/run_blackbox_tests/test_cases_channel_conn.h b/test/blackbox/run_blackbox_tests/test_cases_channel_conn.h index 9efed2f4..f05e1655 100644 --- a/test/blackbox/run_blackbox_tests/test_cases_channel_conn.h +++ b/test/blackbox/run_blackbox_tests/test_cases_channel_conn.h @@ -24,6 +24,6 @@ #include extern int total_tests; -extern int test_case_channel_conn(void); +extern int test_meshlink_channel_conn(void); #endif // TEST_CASES_CHANNEL_CONN_H diff --git a/test/blackbox/test_case_channel_conn_01/Makefile.am b/test/blackbox/test_case_channel_conn_01/Makefile.am new file mode 100644 index 00000000..4cca831a --- /dev/null +++ b/test/blackbox/test_case_channel_conn_01/Makefile.am @@ -0,0 +1,9 @@ +check_PROGRAMS = node_sim_peer node_sim_nut + +node_sim_peer_SOURCES = node_sim_peer.c ../common/common_handlers.c ../common/test_step.c ../common/mesh_event_handler.c ../../utils.c +node_sim_peer_LDADD = ../../../src/libmeshlink.la +node_sim_peer_CFLAGS = -D_GNU_SOURCE + +node_sim_nut_SOURCES = node_sim_nut.c ../common/common_handlers.c ../common/test_step.c ../common/mesh_event_handler.c ../../utils.c +node_sim_nut_LDADD = ../../../src/libmeshlink.la +node_sim_nut_CFLAGS = -D_GNU_SOURCE diff --git a/test/blackbox/test_case_channel_conn_01/node_sim_nut.c b/test/blackbox/test_case_channel_conn_01/node_sim_nut.c new file mode 100644 index 00000000..bded500a --- /dev/null +++ b/test/blackbox/test_case_channel_conn_01/node_sim_nut.c @@ -0,0 +1,161 @@ +/* + node_sim_nut.c -- Implementation of Node Simulation for Meshlink Testing + for meta connection test case 01 - re-connection of + two nodes when relay node goes down + Copyright (C) 2018 Guus Sliepen + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include +#include +#include +#include +#include +#include +#include "../common/common_handlers.h" +#include "../common/test_step.h" +#include "../common/mesh_event_handler.h" +#include "../../utils.h" + +#define CMD_LINE_ARG_NODENAME 1 +#define CMD_LINE_ARG_DEVCLASS 2 +#define CMD_LINE_ARG_CLIENTID 3 +#define CMD_LINE_ARG_IMPORTSTR 4 +#define CMD_LINE_ARG_INVITEURL 5 +#define CHANNEL_PORT 1234 + +static int client_id = -1; + +static struct sync_flag peer_reachable = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER}; +static struct sync_flag channel_opened = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER}; +static struct sync_flag sigusr_received = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER}; +static struct sync_flag channel_received = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER}; + +static void send_event(mesh_event_t event); +static void node_status_cb(meshlink_handle_t *mesh, meshlink_node_t *node, + bool reachable); +static void mesh_siguser1_signal_handler(int sig_num); + +static void mesh_siguser1_signal_handler(int sig_num) { + set_sync_flag(&sigusr_received, true); + + return; +} + +static void send_event(mesh_event_t event) { + int attempts; + + for(attempts = 0; attempts < 5; attempts += 1) { + if(mesh_event_sock_send(client_id, event, NULL, 0)) { + break; + } + } + + assert(attempts < 5); + + return; +} + +static void node_status_cb(meshlink_handle_t *mesh, meshlink_node_t *node, + bool reachable) { + if(!strcasecmp(node->name, "peer") && reachable) { + set_sync_flag(&peer_reachable, true); + } + + return; +} + +static void poll_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, size_t len) { + (void)len; + meshlink_set_channel_poll_cb(mesh, channel, NULL); + assert(meshlink_channel_send(mesh, channel, "test", 5) >= 0); + return; +} + +static void channel_receive_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, const void *dat, size_t len) { + if(len == 0) { + send_event(ERR_NETWORK); + assert(false); + } + + if(!strcmp(channel->node->name, "peer")) { + if(len == 5 && !memcmp(dat, "reply", 5)) { + set_sync_flag(&channel_opened, true); + } + } + + return; +} + +int main(int argc, char *argv[]) { + struct timeval main_loop_wait = { 2, 0 }; + struct timespec timeout = {0}; + int i; + + // Import mesh event handler + + if((argv[CMD_LINE_ARG_CLIENTID]) && (argv[CMD_LINE_ARG_IMPORTSTR])) { + client_id = atoi(argv[CMD_LINE_ARG_CLIENTID]); + mesh_event_sock_connect(argv[CMD_LINE_ARG_IMPORTSTR]); + } + + // Setup required signals + + setup_signals(); + signal(SIGUSR1, mesh_siguser1_signal_handler); + + // Execute test steps + + meshlink_handle_t *mesh = meshlink_open("testconf", argv[CMD_LINE_ARG_NODENAME], + "test_channel_conn", atoi(argv[CMD_LINE_ARG_DEVCLASS])); + assert(mesh); + meshlink_set_log_cb(mesh, MESHLINK_DEBUG, meshlink_callback_logger); + meshlink_set_node_status_cb(mesh, node_status_cb); + + if(argv[CMD_LINE_ARG_INVITEURL]) { + assert(meshlink_join(mesh, argv[CMD_LINE_ARG_INVITEURL])); + } + + assert(meshlink_start(mesh)); + + // Wait for peer node to join + + assert(wait_sync_flag(&peer_reachable, 30)); + send_event(NODE_JOINED); + + // Open a channel to peer node + + meshlink_node_t *peer_node = meshlink_get_node(mesh, "peer"); + assert(peer_node); + meshlink_channel_t *channel = meshlink_channel_open(mesh, peer_node, CHANNEL_PORT, + channel_receive_cb, NULL, 0); + meshlink_set_channel_poll_cb(mesh, channel, poll_cb); + + assert(wait_sync_flag(&channel_opened, 10)); + send_event(CHANNEL_OPENED); + + assert(wait_sync_flag(&sigusr_received, 10)); + + sleep(10); + + assert(meshlink_channel_send(mesh, channel, "after", 6) >= 0); + + // All test steps executed - wait for signals to stop/start or close the mesh + while(test_running) { + select(1, NULL, NULL, NULL, &main_loop_wait); + } + + meshlink_close(mesh); +} diff --git a/test/blackbox/test_case_channel_conn_01/node_sim_peer.c b/test/blackbox/test_case_channel_conn_01/node_sim_peer.c new file mode 100644 index 00000000..7cc095d7 --- /dev/null +++ b/test/blackbox/test_case_channel_conn_01/node_sim_peer.c @@ -0,0 +1,120 @@ +/* + node_sim_peer.c -- Implementation of Node Simulation for Meshlink Testing + for meta connection test case 01 - re-connection of + two nodes when relay node goes down + Copyright (C) 2018 Guus Sliepen + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include +#include +#include +#include +#include +#include +#include "../common/common_handlers.h" +#include "../common/test_step.h" +#include "../common/mesh_event_handler.h" +#include "../../utils.h" + +#define CMD_LINE_ARG_NODENAME 1 +#define CMD_LINE_ARG_DEVCLASS 2 +#define CMD_LINE_ARG_CLIENTID 3 +#define CMD_LINE_ARG_IMPORTSTR 4 +#define CMD_LINE_ARG_INVITEURL 5 +#define CHANNEL_PORT 1234 + +static void channel_receive_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, const void *dat, size_t len); +static bool channel_accept(meshlink_handle_t *mesh, meshlink_channel_t *channel, uint16_t port, const void *dat, size_t len); + +static int client_id = -1; + +static bool channel_accept(meshlink_handle_t *mesh, meshlink_channel_t *channel, uint16_t port, const void *dat, size_t len) { + (void)dat; + (void)len; + + assert(port == CHANNEL_PORT); + + if(!strcmp(channel->node->name, "nut")) { + meshlink_set_channel_receive_cb(mesh, channel, channel_receive_cb); + mesh->priv = channel; + + return true; + } + + return false; +} + +/* channel receive callback */ +static void channel_receive_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, const void *dat, size_t len) { + (void)mesh; + (void)channel; + (void)dat; + (void)len; + + if(len == 0) { + mesh_event_sock_send(client_id, ERR_NETWORK, NULL, 0); + assert(false); + } + + if(!strcmp(channel->node->name, "nut")) { + if(!memcmp(dat, "test", 5)) { + assert(meshlink_channel_send(mesh, channel, "reply", 5) >= 0); + } else if(!memcmp(dat, "after", 6)) { + assert(mesh_event_sock_send(client_id, CHANNEL_DATA_RECIEVED, NULL, 0)); + } + } + + return; +} + +int main(int argc, char *argv[]) { + struct timeval main_loop_wait = { 2, 0 }; + + // Import mesh event handler + + if((argv[CMD_LINE_ARG_CLIENTID]) && (argv[CMD_LINE_ARG_IMPORTSTR])) { + client_id = atoi(argv[CMD_LINE_ARG_CLIENTID]); + mesh_event_sock_connect(argv[CMD_LINE_ARG_IMPORTSTR]); + } + + // Setup required signals + + setup_signals(); + + // Run peer node instance + + meshlink_handle_t *mesh = meshlink_open("testconf", argv[CMD_LINE_ARG_NODENAME], + "test_channel_conn", atoi(argv[CMD_LINE_ARG_DEVCLASS])); + assert(mesh); + meshlink_set_log_cb(mesh, MESHLINK_DEBUG, meshlink_callback_logger); + meshlink_set_channel_accept_cb(mesh, channel_accept); + + if(argv[CMD_LINE_ARG_INVITEURL]) { + assert(meshlink_join(mesh, argv[CMD_LINE_ARG_INVITEURL])); + } + + assert(meshlink_start(mesh)); + + // All test steps executed - wait for signals to stop/start or close the mesh + + while(test_running) { + select(1, NULL, NULL, NULL, &main_loop_wait); + } + + meshlink_close(mesh); + + return EXIT_SUCCESS; +} diff --git a/test/blackbox/test_case_channel_conn_02/Makefile.am b/test/blackbox/test_case_channel_conn_02/Makefile.am new file mode 100644 index 00000000..4cca831a --- /dev/null +++ b/test/blackbox/test_case_channel_conn_02/Makefile.am @@ -0,0 +1,9 @@ +check_PROGRAMS = node_sim_peer node_sim_nut + +node_sim_peer_SOURCES = node_sim_peer.c ../common/common_handlers.c ../common/test_step.c ../common/mesh_event_handler.c ../../utils.c +node_sim_peer_LDADD = ../../../src/libmeshlink.la +node_sim_peer_CFLAGS = -D_GNU_SOURCE + +node_sim_nut_SOURCES = node_sim_nut.c ../common/common_handlers.c ../common/test_step.c ../common/mesh_event_handler.c ../../utils.c +node_sim_nut_LDADD = ../../../src/libmeshlink.la +node_sim_nut_CFLAGS = -D_GNU_SOURCE diff --git a/test/blackbox/test_case_channel_conn_02/node_sim_nut.c b/test/blackbox/test_case_channel_conn_02/node_sim_nut.c new file mode 100644 index 00000000..d8af0923 --- /dev/null +++ b/test/blackbox/test_case_channel_conn_02/node_sim_nut.c @@ -0,0 +1,163 @@ +/* + node_sim_nut.c -- Implementation of Node Simulation for Meshlink Testing + for meta connection test case 01 - re-connection of + two nodes when relay node goes down + Copyright (C) 2018 Guus Sliepen + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include +#include +#include +#include +#include +#include +#include "../common/common_handlers.h" +#include "../common/test_step.h" +#include "../common/mesh_event_handler.h" +#include "../../utils.h" + +#define CMD_LINE_ARG_NODENAME 1 +#define CMD_LINE_ARG_DEVCLASS 2 +#define CMD_LINE_ARG_CLIENTID 3 +#define CMD_LINE_ARG_IMPORTSTR 4 +#define CMD_LINE_ARG_INVITEURL 5 +#define CHANNEL_PORT 1234 + +static int client_id = -1; + +static struct sync_flag peer_reachable = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER}; +static struct sync_flag channel_opened = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER}; +static struct sync_flag channel_closed = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER}; +static struct sync_flag sigusr_received = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER}; + +static void send_event(mesh_event_t event); +static void node_status_cb(meshlink_handle_t *mesh, meshlink_node_t *node, + bool reachable); +static void mesh_siguser1_signal_handler(int sig_num); + +static void mesh_siguser1_signal_handler(int sig_num) { + set_sync_flag(&sigusr_received, true); + return; +} + +static void send_event(mesh_event_t event) { + bool send_ret = false; + int attempts; + + for(attempts = 0; attempts < 5; attempts += 1) { + send_ret = mesh_event_sock_send(client_id, event, NULL, 0); + + if(send_ret) { + break; + } + } + + return; +} + +static void node_status_cb(meshlink_handle_t *mesh, meshlink_node_t *node, + bool reachable) { + if(!strcasecmp(node->name, "peer") && reachable) { + set_sync_flag(&peer_reachable, true); + } + + return; +} + +static void poll_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, size_t len) { + (void)len; + meshlink_set_channel_poll_cb(mesh, channel, NULL); + assert(meshlink_channel_send(mesh, channel, "test", 5) >= 0); + return; +} + +static void channel_receive_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, const void *dat, size_t len) { + if(len == 0) { + set_sync_flag(&channel_closed, true); + send_event(ERR_NETWORK); + return; + } + + if(!strcmp(channel->node->name, "peer")) { + if(len == 5 && !memcmp(dat, "reply", 5)) { + set_sync_flag(&channel_opened, true); + } + } + + return; +} + +int main(int argc, char *argv[]) { + struct timeval main_loop_wait = { 2, 0 }; + struct timespec timeout = {0}; + int i; + + // Import mesh event handler + + if((argv[CMD_LINE_ARG_CLIENTID]) && (argv[CMD_LINE_ARG_IMPORTSTR])) { + client_id = atoi(argv[CMD_LINE_ARG_CLIENTID]); + mesh_event_sock_connect(argv[CMD_LINE_ARG_IMPORTSTR]); + } + + // Setup required signals + + setup_signals(); + signal(SIGUSR1, mesh_siguser1_signal_handler); + + // Execute test steps + + meshlink_handle_t *mesh = meshlink_open("testconf", argv[CMD_LINE_ARG_NODENAME], + "test_channel_conn", atoi(argv[CMD_LINE_ARG_DEVCLASS])); + assert(mesh); + meshlink_set_log_cb(mesh, MESHLINK_DEBUG, meshlink_callback_logger); + meshlink_set_node_status_cb(mesh, node_status_cb); + + if(argv[CMD_LINE_ARG_INVITEURL]) { + assert(meshlink_join(mesh, argv[CMD_LINE_ARG_INVITEURL])); + } + + assert(meshlink_start(mesh)); + + // Wait for peer node to join + + assert(wait_sync_flag(&peer_reachable, 30)); + send_event(NODE_JOINED); + + // Open a channel to peer node + + meshlink_node_t *peer_node = meshlink_get_node(mesh, "peer"); + assert(peer_node); + meshlink_channel_t *channel = meshlink_channel_open(mesh, peer_node, CHANNEL_PORT, + channel_receive_cb, NULL, 0); + meshlink_set_channel_poll_cb(mesh, channel, poll_cb); + + assert(wait_sync_flag(&channel_opened, 10)); + send_event(CHANNEL_OPENED); + + assert(wait_sync_flag(&sigusr_received, 10)); + + assert(meshlink_channel_send(mesh, channel, "after", 6) >= 0); + + assert(wait_sync_flag(&channel_closed, 180)); + + // All test steps executed - wait for signals to stop/start or close the mesh + while(test_running) { + select(1, NULL, NULL, NULL, &main_loop_wait); + } + + meshlink_close(mesh); +} diff --git a/test/blackbox/test_case_channel_conn_02/node_sim_peer.c b/test/blackbox/test_case_channel_conn_02/node_sim_peer.c new file mode 100644 index 00000000..ac94066f --- /dev/null +++ b/test/blackbox/test_case_channel_conn_02/node_sim_peer.c @@ -0,0 +1,113 @@ +/* + node_sim_peer.c -- Implementation of Node Simulation for Meshlink Testing + for meta connection test case 01 - re-connection of + two nodes when relay node goes down + Copyright (C) 2018 Guus Sliepen + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include +#include +#include +#include +#include +#include "../common/common_handlers.h" +#include "../common/test_step.h" +#include "../common/mesh_event_handler.h" + +#define CMD_LINE_ARG_NODENAME 1 +#define CMD_LINE_ARG_DEVCLASS 2 +#define CMD_LINE_ARG_CLIENTID 3 +#define CMD_LINE_ARG_IMPORTSTR 4 +#define CMD_LINE_ARG_INVITEURL 5 +#define CHANNEL_PORT 1234 + +static int client_id = -1; +static bool channel_rec; +static bool channel_reply; +static pthread_mutex_t reply_lock = PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t reply_cond = PTHREAD_COND_INITIALIZER; +static pthread_mutex_t recv_lock = PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t recv_cond = PTHREAD_COND_INITIALIZER; + +static void channel_receive_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, const void *dat, size_t len); + +static bool channel_accept(meshlink_handle_t *mesh, meshlink_channel_t *channel, uint16_t port, const void *dat, size_t len) { + (void)dat; + (void)len; + + assert(port == CHANNEL_PORT); + + if(!strcmp(channel->node->name, "nut")) { + meshlink_set_channel_receive_cb(mesh, channel, channel_receive_cb); + mesh->priv = channel; + + return true; + } + + return false; +} + +static void channel_receive_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, const void *dat, size_t len) { + if(len == 0) { + assert(mesh_event_sock_send(client_id, ERR_NETWORK, NULL, 0)); + return; + } + + if(!strcmp(channel->node->name, "nut")) { + if(!memcmp(dat, "test", 5)) { + assert(meshlink_channel_send(mesh, channel, "reply", 5) >= 0); + } + } + + return; +} + +int main(int argc, char *argv[]) { + struct timeval main_loop_wait = { 2, 0 }; + struct timespec timeout = {0}; + + // Import mesh event handler + + if((argv[CMD_LINE_ARG_CLIENTID]) && (argv[CMD_LINE_ARG_IMPORTSTR])) { + client_id = atoi(argv[CMD_LINE_ARG_CLIENTID]); + mesh_event_sock_connect(argv[CMD_LINE_ARG_IMPORTSTR]); + } + + // Run peer node instance + + setup_signals(); + + meshlink_handle_t *mesh = meshlink_open("testconf", argv[CMD_LINE_ARG_NODENAME], + "test_channel_conn", atoi(argv[CMD_LINE_ARG_DEVCLASS])); + assert(mesh); + meshlink_set_log_cb(mesh, MESHLINK_DEBUG, meshlink_callback_logger); + meshlink_set_channel_accept_cb(mesh, channel_accept); + + if(argv[CMD_LINE_ARG_INVITEURL]) { + assert(meshlink_join(mesh, argv[CMD_LINE_ARG_INVITEURL])); + } + + assert(meshlink_start(mesh)); + + // All test steps executed - wait for signals to stop/start or close the mesh + while(test_running) { + select(1, NULL, NULL, NULL, &main_loop_wait); + } + + meshlink_close(mesh); + + return EXIT_SUCCESS; +} diff --git a/test/blackbox/test_case_channel_conn_03/Makefile.am b/test/blackbox/test_case_channel_conn_03/Makefile.am new file mode 100644 index 00000000..4cca831a --- /dev/null +++ b/test/blackbox/test_case_channel_conn_03/Makefile.am @@ -0,0 +1,9 @@ +check_PROGRAMS = node_sim_peer node_sim_nut + +node_sim_peer_SOURCES = node_sim_peer.c ../common/common_handlers.c ../common/test_step.c ../common/mesh_event_handler.c ../../utils.c +node_sim_peer_LDADD = ../../../src/libmeshlink.la +node_sim_peer_CFLAGS = -D_GNU_SOURCE + +node_sim_nut_SOURCES = node_sim_nut.c ../common/common_handlers.c ../common/test_step.c ../common/mesh_event_handler.c ../../utils.c +node_sim_nut_LDADD = ../../../src/libmeshlink.la +node_sim_nut_CFLAGS = -D_GNU_SOURCE diff --git a/test/blackbox/test_case_channel_conn_03/node_sim_nut.c b/test/blackbox/test_case_channel_conn_03/node_sim_nut.c new file mode 100644 index 00000000..2f1e7e60 --- /dev/null +++ b/test/blackbox/test_case_channel_conn_03/node_sim_nut.c @@ -0,0 +1,167 @@ +/* + node_sim_nut.c -- Implementation of Node Simulation for Meshlink Testing + for meta connection test case 01 - re-connection of + two nodes when relay node goes down + Copyright (C) 2018 Guus Sliepen + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include +#include +#include +#include +#include +#include +#include "../common/common_handlers.h" +#include "../common/test_step.h" +#include "../common/mesh_event_handler.h" +#include "../../utils.h" + +#define CMD_LINE_ARG_NODENAME 1 +#define CMD_LINE_ARG_DEVCLASS 2 +#define CMD_LINE_ARG_CLIENTID 3 +#define CMD_LINE_ARG_IMPORTSTR 4 +#define CMD_LINE_ARG_INVITEURL 5 +#define CHANNEL_PORT 1234 + +static int client_id = -1; + +static struct sync_flag peer_reachable = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER}; +static struct sync_flag channel_opened = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER}; +static struct sync_flag peer_unreachable = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER}; +static struct sync_flag sigusr_received = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER}; + +static void send_event(mesh_event_t event); +static void node_status_cb(meshlink_handle_t *mesh, meshlink_node_t *node, + bool reachable); +static void mesh_siguser1_signal_handler(int sig_num); + +static void mesh_siguser1_signal_handler(int sig_num) { + set_sync_flag(&sigusr_received, true); + return; +} + +static void send_event(mesh_event_t event) { + bool send_ret = false; + int attempts; + + for(attempts = 0; attempts < 5; attempts += 1) { + if(mesh_event_sock_send(client_id, event, NULL, 0)) { + break; + } + } + + assert(attempts < 5); + + return; +} + +static void node_status_cb(meshlink_handle_t *mesh, meshlink_node_t *node, + bool reachable) { + if(!strcasecmp(node->name, "peer")) { + if(reachable) { + set_sync_flag(&peer_reachable, true); + } else { + set_sync_flag(&peer_unreachable, true); + } + } + + return; +} + +static void poll_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, size_t len) { + (void)len; + meshlink_set_channel_poll_cb(mesh, channel, NULL); + assert(meshlink_channel_send(mesh, channel, "test", 5) >= 0); + return; +} + +static void channel_receive_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, const void *dat, size_t len) { + if(!strcmp(channel->node->name, "peer")) { + if(len == 5 && !memcmp(dat, "reply", 5)) { + set_sync_flag(&channel_opened, true); + } + } + + return; +} + +int main(int argc, char *argv[]) { + struct timeval main_loop_wait = { 2, 0 }; + struct timespec timeout = {0}; + int i; + + // Import mesh event handler + + if((argv[CMD_LINE_ARG_CLIENTID]) && (argv[CMD_LINE_ARG_IMPORTSTR])) { + client_id = atoi(argv[CMD_LINE_ARG_CLIENTID]); + mesh_event_sock_connect(argv[CMD_LINE_ARG_IMPORTSTR]); + } + + // Setup required signals + + setup_signals(); + signal(SIGUSR1, mesh_siguser1_signal_handler); + + // Execute test steps + + meshlink_handle_t *mesh = meshlink_open("testconf", argv[CMD_LINE_ARG_NODENAME], + "test_channel_conn", atoi(argv[CMD_LINE_ARG_DEVCLASS])); + assert(mesh); + meshlink_set_log_cb(mesh, MESHLINK_DEBUG, meshlink_callback_logger); + meshlink_set_node_status_cb(mesh, node_status_cb); + + if(argv[CMD_LINE_ARG_INVITEURL]) { + assert(meshlink_join(mesh, argv[CMD_LINE_ARG_INVITEURL])); + } + + assert(meshlink_start(mesh)); + + // Wait for peer node to join + + assert(wait_sync_flag(&peer_reachable, 30)); + send_event(NODE_JOINED); + + // Open a channel to peer node + + meshlink_node_t *peer_node = meshlink_get_node(mesh, "peer"); + assert(peer_node); + meshlink_channel_t *channel = meshlink_channel_open(mesh, peer_node, CHANNEL_PORT, + channel_receive_cb, NULL, 0); + meshlink_set_channel_poll_cb(mesh, channel, poll_cb); + + assert(wait_sync_flag(&channel_opened, 10)); + send_event(CHANNEL_OPENED); + + peer_unreachable.flag = false; + peer_reachable.flag = false; + assert(wait_sync_flag(&sigusr_received, 10)); + + assert(wait_sync_flag(&peer_unreachable, 100)); + send_event(NODE_UNREACHABLE); + + assert(wait_sync_flag(&peer_reachable, 100)); + send_event(NODE_REACHABLE); + + assert(meshlink_channel_send(mesh, channel, "after", 6) >= 0); + + // All test steps executed - wait for signals to stop/start or close the mesh + + while(test_running) { + select(1, NULL, NULL, NULL, &main_loop_wait); + } + + meshlink_close(mesh); +} diff --git a/test/blackbox/test_case_channel_conn_03/node_sim_peer.c b/test/blackbox/test_case_channel_conn_03/node_sim_peer.c new file mode 100644 index 00000000..ae8dadcc --- /dev/null +++ b/test/blackbox/test_case_channel_conn_03/node_sim_peer.c @@ -0,0 +1,109 @@ +/* + node_sim_peer.c -- Implementation of Node Simulation for Meshlink Testing + for meta connection test case 01 - re-connection of + two nodes when relay node goes down + Copyright (C) 2018 Guus Sliepen + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include +#include +#include +#include +#include +#include "../common/common_handlers.h" +#include "../common/test_step.h" +#include "../common/mesh_event_handler.h" + +#define CMD_LINE_ARG_NODENAME 1 +#define CMD_LINE_ARG_DEVCLASS 2 +#define CMD_LINE_ARG_CLIENTID 3 +#define CMD_LINE_ARG_IMPORTSTR 4 +#define CMD_LINE_ARG_INVITEURL 5 +#define CHANNEL_PORT 1234 + +static int client_id = -1; + +static void channel_receive_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, const void *dat, size_t len); + +static bool channel_accept(meshlink_handle_t *mesh, meshlink_channel_t *channel, uint16_t port, const void *dat, size_t len) { + (void)dat; + (void)len; + + assert(port == CHANNEL_PORT); + + if(!strcmp(channel->node->name, "nut")) { + meshlink_set_channel_receive_cb(mesh, channel, channel_receive_cb); + mesh->priv = channel; + + return true; + } + + return false; +} + +static void channel_receive_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, const void *dat, size_t len) { + if(len == 0) { + assert(mesh_event_sock_send(client_id, ERR_NETWORK, NULL, 0)); + return; + } + + if(!strcmp(channel->node->name, "nut")) { + if(!memcmp(dat, "test", 5)) { + assert(meshlink_channel_send(mesh, channel, "reply", 5) >= 0); + } else if(!memcmp(dat, "after", 5)) { + assert(mesh_event_sock_send(client_id, CHANNEL_DATA_RECIEVED, NULL, 0)); + } + } + + return; +} + +int main(int argc, char *argv[]) { + struct timeval main_loop_wait = { 2, 0 }; + struct timespec timeout = {0}; + + // Import mesh event handler + + if((argv[CMD_LINE_ARG_CLIENTID]) && (argv[CMD_LINE_ARG_IMPORTSTR])) { + client_id = atoi(argv[CMD_LINE_ARG_CLIENTID]); + mesh_event_sock_connect(argv[CMD_LINE_ARG_IMPORTSTR]); + } + + // Run peer node instance + + setup_signals(); + + meshlink_handle_t *mesh = meshlink_open("testconf", argv[CMD_LINE_ARG_NODENAME], + "test_channel_conn", atoi(argv[CMD_LINE_ARG_DEVCLASS])); + assert(mesh); + meshlink_set_log_cb(mesh, MESHLINK_DEBUG, meshlink_callback_logger); + meshlink_set_channel_accept_cb(mesh, channel_accept); + + if(argv[CMD_LINE_ARG_INVITEURL]) { + assert(meshlink_join(mesh, argv[CMD_LINE_ARG_INVITEURL])); + } + + assert(meshlink_start(mesh)); + + // All test steps executed - wait for signals to stop/start or close the mesh + while(test_running) { + select(1, NULL, NULL, NULL, &main_loop_wait); + } + + meshlink_close(mesh); + + return EXIT_SUCCESS; +} diff --git a/test/blackbox/test_case_channel_conn_04/Makefile.am b/test/blackbox/test_case_channel_conn_04/Makefile.am new file mode 100644 index 00000000..4cca831a --- /dev/null +++ b/test/blackbox/test_case_channel_conn_04/Makefile.am @@ -0,0 +1,9 @@ +check_PROGRAMS = node_sim_peer node_sim_nut + +node_sim_peer_SOURCES = node_sim_peer.c ../common/common_handlers.c ../common/test_step.c ../common/mesh_event_handler.c ../../utils.c +node_sim_peer_LDADD = ../../../src/libmeshlink.la +node_sim_peer_CFLAGS = -D_GNU_SOURCE + +node_sim_nut_SOURCES = node_sim_nut.c ../common/common_handlers.c ../common/test_step.c ../common/mesh_event_handler.c ../../utils.c +node_sim_nut_LDADD = ../../../src/libmeshlink.la +node_sim_nut_CFLAGS = -D_GNU_SOURCE diff --git a/test/blackbox/test_case_channel_conn_04/node_sim_nut.c b/test/blackbox/test_case_channel_conn_04/node_sim_nut.c new file mode 100644 index 00000000..fe338704 --- /dev/null +++ b/test/blackbox/test_case_channel_conn_04/node_sim_nut.c @@ -0,0 +1,159 @@ +/* + node_sim_nut.c -- Implementation of Node Simulation for Meshlink Testing + for meta connection test case 01 - re-connection of + two nodes when relay node goes down + Copyright (C) 2018 Guus Sliepen + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include +#include +#include +#include +#include +#include +#include "../common/common_handlers.h" +#include "../common/test_step.h" +#include "../common/mesh_event_handler.h" +#include "../../utils.h" + +#define CMD_LINE_ARG_NODENAME 1 +#define CMD_LINE_ARG_DEVCLASS 2 +#define CMD_LINE_ARG_CLIENTID 3 +#define CMD_LINE_ARG_IMPORTSTR 4 +#define CMD_LINE_ARG_INVITEURL 5 +#define CHANNEL_PORT 1234 + +static int client_id = -1; + +static struct sync_flag peer_reachable = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER}; +static struct sync_flag channel_opened = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER}; +static struct sync_flag channel_closed = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER}; + +static void send_event(mesh_event_t event); +static void node_status_cb(meshlink_handle_t *mesh, meshlink_node_t *node, + bool reachable); + +static void send_event(mesh_event_t event) { + int attempts; + + for(attempts = 0; attempts < 5; attempts += 1) { + if(mesh_event_sock_send(client_id, event, NULL, 0)) { + break; + } + } + + assert(attempts < 5); + + return; +} + +static void node_status_cb(meshlink_handle_t *mesh, meshlink_node_t *node, + bool reachable) { + if(!strcasecmp(node->name, "peer")) { + if(reachable) { + set_sync_flag(&peer_reachable, true); + } else { + peer_reachable.flag = false; + } + } + + return; +} + +static void poll_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, size_t len) { + (void)len; + meshlink_set_channel_poll_cb(mesh, channel, NULL); + assert(meshlink_channel_send(mesh, channel, "test", 5) >= 0); + return; +} + +/* channel receive callback */ +static void channel_receive_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, const void *dat, size_t len) { + if(len == 0) { + //send_event(ERR_NETWORK); + return; + } + + if(!strcmp(channel->node->name, "peer")) { + if(!memcmp(dat, "reply", 5)) { + set_sync_flag(&channel_opened, true); + } else if(!memcmp(dat, "failure", 7)) { + assert(false); + } + } + + return; +} + +int main(int argc, char *argv[]) { + struct timeval main_loop_wait = { 5, 0 }; + int i; + + // Import mesh event handler + + if((argv[CMD_LINE_ARG_CLIENTID]) && (argv[CMD_LINE_ARG_IMPORTSTR])) { + client_id = atoi(argv[CMD_LINE_ARG_CLIENTID]); + mesh_event_sock_connect(argv[CMD_LINE_ARG_IMPORTSTR]); + } + + setup_signals(); + + // Execute test steps + + meshlink_handle_t *mesh = meshlink_open("testconf", argv[CMD_LINE_ARG_NODENAME], + "test_channel_conn", atoi(argv[CMD_LINE_ARG_DEVCLASS])); + assert(mesh); + meshlink_set_log_cb(mesh, MESHLINK_DEBUG, meshlink_callback_logger); + meshlink_set_node_status_cb(mesh, node_status_cb); + + if(argv[CMD_LINE_ARG_INVITEURL]) { + assert(meshlink_join(mesh, argv[CMD_LINE_ARG_INVITEURL])); + } + + assert(meshlink_start(mesh)); + + // Wait for peer node to join + + assert(wait_sync_flag(&peer_reachable, 10)); + send_event(NODE_JOINED); + + // Open a channel to peer node + + meshlink_node_t *peer_node = meshlink_get_node(mesh, "peer"); + assert(peer_node); + meshlink_channel_t *channel = meshlink_channel_open(mesh, peer_node, CHANNEL_PORT, + channel_receive_cb, NULL, 0); + meshlink_set_channel_poll_cb(mesh, channel, poll_cb); + + assert(wait_sync_flag(&channel_opened, 10)); + send_event(CHANNEL_OPENED); + + // Restarting the node instance + + meshlink_stop(mesh); + meshlink_start(mesh); + + assert(wait_sync_flag(&peer_reachable, 60)); + send_event(NODE_RESTARTED); + + // All test steps executed - wait for signals to stop/start or close the mesh + + while(test_running) { + select(1, NULL, NULL, NULL, &main_loop_wait); + } + + meshlink_close(mesh); +} diff --git a/test/blackbox/test_case_channel_conn_04/node_sim_peer.c b/test/blackbox/test_case_channel_conn_04/node_sim_peer.c new file mode 100644 index 00000000..01289786 --- /dev/null +++ b/test/blackbox/test_case_channel_conn_04/node_sim_peer.c @@ -0,0 +1,128 @@ +/* + node_sim_peer.c -- Implementation of Node Simulation for Meshlink Testing + for meta connection test case 01 - re-connection of + two nodes when relay node goes down + Copyright (C) 2018 Guus Sliepen + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include +#include +#include +#include +#include +#include +#include "../common/common_handlers.h" +#include "../common/test_step.h" +#include "../common/mesh_event_handler.h" +#include "../../utils.h" + +#define CMD_LINE_ARG_NODENAME 1 +#define CMD_LINE_ARG_DEVCLASS 2 +#define CMD_LINE_ARG_CLIENTID 3 +#define CMD_LINE_ARG_IMPORTSTR 4 +#define CMD_LINE_ARG_INVITEURL 5 +#define CHANNEL_PORT 1234 + +static void channel_receive_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, const void *dat, size_t len); +static bool channel_accept(meshlink_handle_t *mesh, meshlink_channel_t *channel, uint16_t port, const void *dat, size_t len); + +static struct sync_flag sigusr = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER}; +static int client_id = -1; + +static void mesh_siguser1_signal_handler(int sig_num) { + set_sync_flag(&sigusr, true); + + return; +} + +static bool channel_accept(meshlink_handle_t *mesh, meshlink_channel_t *channel, uint16_t port, const void *dat, size_t len) { + (void)dat; + (void)len; + + assert(port == CHANNEL_PORT); + + if(!strcmp(channel->node->name, "nut")) { + meshlink_set_channel_receive_cb(mesh, channel, channel_receive_cb); + mesh->priv = channel; + + return true; + } + + return false; +} + +/* channel receive callback */ +static void channel_receive_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, const void *dat, size_t len) { + (void)mesh; + (void)channel; + (void)dat; + (void)len; + + if(len == 0) { + mesh_event_sock_send(client_id, ERR_NETWORK, NULL, 0); + return; + } + + if(!strcmp(channel->node->name, "nut") && !memcmp(dat, "test", 5)) { + assert(meshlink_channel_send(mesh, channel, "reply", 5) >= 0); + } + + return; +} + +int main(int argc, char *argv[]) { + struct timeval main_loop_wait = { 2, 0 }; + + // Import mesh event handler + + if((argv[CMD_LINE_ARG_CLIENTID]) && (argv[CMD_LINE_ARG_IMPORTSTR])) { + client_id = atoi(argv[CMD_LINE_ARG_CLIENTID]); + mesh_event_sock_connect(argv[CMD_LINE_ARG_IMPORTSTR]); + } + + // Setup required signals + + setup_signals(); + signal(SIGUSR1, mesh_siguser1_signal_handler); + + // Run peer node instance + + meshlink_handle_t *mesh = meshlink_open("testconf", argv[CMD_LINE_ARG_NODENAME], + "test_channel_conn", atoi(argv[CMD_LINE_ARG_DEVCLASS])); + assert(mesh); + meshlink_set_log_cb(mesh, MESHLINK_DEBUG, meshlink_callback_logger); + meshlink_set_channel_accept_cb(mesh, channel_accept); + + if(argv[CMD_LINE_ARG_INVITEURL]) { + assert(meshlink_join(mesh, argv[CMD_LINE_ARG_INVITEURL])); + } + + assert(meshlink_start(mesh)); + + assert(wait_sync_flag(&sigusr, 140)); + meshlink_channel_t *channel = mesh->priv; + assert(meshlink_channel_send(mesh, channel, "failure", 7)); + + // All test steps executed - wait for signals to stop/start or close the mesh + + while(test_running) { + select(1, NULL, NULL, NULL, &main_loop_wait); + } + + meshlink_close(mesh); + + return EXIT_SUCCESS; +} diff --git a/test/blackbox/test_case_channel_conn_05/Makefile.am b/test/blackbox/test_case_channel_conn_05/Makefile.am new file mode 100644 index 00000000..8bde53de --- /dev/null +++ b/test/blackbox/test_case_channel_conn_05/Makefile.am @@ -0,0 +1,13 @@ +check_PROGRAMS = node_sim_peer node_sim_nut node_sim_relay + +node_sim_peer_SOURCES = node_sim_peer.c ../common/common_handlers.c ../common/test_step.c ../common/mesh_event_handler.c ../../utils.c +node_sim_peer_LDADD = ../../../src/libmeshlink.la +node_sim_peer_CFLAGS = -D_GNU_SOURCE + +node_sim_nut_SOURCES = node_sim_nut.c ../common/common_handlers.c ../common/test_step.c ../common/mesh_event_handler.c ../../utils.c +node_sim_nut_LDADD = ../../../src/libmeshlink.la +node_sim_nut_CFLAGS = -D_GNU_SOURCE + +node_sim_relay_SOURCES = node_sim_relay.c ../common/common_handlers.c ../common/test_step.c ../common/mesh_event_handler.c ../../utils.c +node_sim_relay_LDADD = ../../../src/libmeshlink.la +node_sim_relay_CFLAGS = -D_GNU_SOURCE diff --git a/test/blackbox/test_case_channel_conn_05/node_sim_nut.c b/test/blackbox/test_case_channel_conn_05/node_sim_nut.c new file mode 100644 index 00000000..bded500a --- /dev/null +++ b/test/blackbox/test_case_channel_conn_05/node_sim_nut.c @@ -0,0 +1,161 @@ +/* + node_sim_nut.c -- Implementation of Node Simulation for Meshlink Testing + for meta connection test case 01 - re-connection of + two nodes when relay node goes down + Copyright (C) 2018 Guus Sliepen + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include +#include +#include +#include +#include +#include +#include "../common/common_handlers.h" +#include "../common/test_step.h" +#include "../common/mesh_event_handler.h" +#include "../../utils.h" + +#define CMD_LINE_ARG_NODENAME 1 +#define CMD_LINE_ARG_DEVCLASS 2 +#define CMD_LINE_ARG_CLIENTID 3 +#define CMD_LINE_ARG_IMPORTSTR 4 +#define CMD_LINE_ARG_INVITEURL 5 +#define CHANNEL_PORT 1234 + +static int client_id = -1; + +static struct sync_flag peer_reachable = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER}; +static struct sync_flag channel_opened = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER}; +static struct sync_flag sigusr_received = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER}; +static struct sync_flag channel_received = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER}; + +static void send_event(mesh_event_t event); +static void node_status_cb(meshlink_handle_t *mesh, meshlink_node_t *node, + bool reachable); +static void mesh_siguser1_signal_handler(int sig_num); + +static void mesh_siguser1_signal_handler(int sig_num) { + set_sync_flag(&sigusr_received, true); + + return; +} + +static void send_event(mesh_event_t event) { + int attempts; + + for(attempts = 0; attempts < 5; attempts += 1) { + if(mesh_event_sock_send(client_id, event, NULL, 0)) { + break; + } + } + + assert(attempts < 5); + + return; +} + +static void node_status_cb(meshlink_handle_t *mesh, meshlink_node_t *node, + bool reachable) { + if(!strcasecmp(node->name, "peer") && reachable) { + set_sync_flag(&peer_reachable, true); + } + + return; +} + +static void poll_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, size_t len) { + (void)len; + meshlink_set_channel_poll_cb(mesh, channel, NULL); + assert(meshlink_channel_send(mesh, channel, "test", 5) >= 0); + return; +} + +static void channel_receive_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, const void *dat, size_t len) { + if(len == 0) { + send_event(ERR_NETWORK); + assert(false); + } + + if(!strcmp(channel->node->name, "peer")) { + if(len == 5 && !memcmp(dat, "reply", 5)) { + set_sync_flag(&channel_opened, true); + } + } + + return; +} + +int main(int argc, char *argv[]) { + struct timeval main_loop_wait = { 2, 0 }; + struct timespec timeout = {0}; + int i; + + // Import mesh event handler + + if((argv[CMD_LINE_ARG_CLIENTID]) && (argv[CMD_LINE_ARG_IMPORTSTR])) { + client_id = atoi(argv[CMD_LINE_ARG_CLIENTID]); + mesh_event_sock_connect(argv[CMD_LINE_ARG_IMPORTSTR]); + } + + // Setup required signals + + setup_signals(); + signal(SIGUSR1, mesh_siguser1_signal_handler); + + // Execute test steps + + meshlink_handle_t *mesh = meshlink_open("testconf", argv[CMD_LINE_ARG_NODENAME], + "test_channel_conn", atoi(argv[CMD_LINE_ARG_DEVCLASS])); + assert(mesh); + meshlink_set_log_cb(mesh, MESHLINK_DEBUG, meshlink_callback_logger); + meshlink_set_node_status_cb(mesh, node_status_cb); + + if(argv[CMD_LINE_ARG_INVITEURL]) { + assert(meshlink_join(mesh, argv[CMD_LINE_ARG_INVITEURL])); + } + + assert(meshlink_start(mesh)); + + // Wait for peer node to join + + assert(wait_sync_flag(&peer_reachable, 30)); + send_event(NODE_JOINED); + + // Open a channel to peer node + + meshlink_node_t *peer_node = meshlink_get_node(mesh, "peer"); + assert(peer_node); + meshlink_channel_t *channel = meshlink_channel_open(mesh, peer_node, CHANNEL_PORT, + channel_receive_cb, NULL, 0); + meshlink_set_channel_poll_cb(mesh, channel, poll_cb); + + assert(wait_sync_flag(&channel_opened, 10)); + send_event(CHANNEL_OPENED); + + assert(wait_sync_flag(&sigusr_received, 10)); + + sleep(10); + + assert(meshlink_channel_send(mesh, channel, "after", 6) >= 0); + + // All test steps executed - wait for signals to stop/start or close the mesh + while(test_running) { + select(1, NULL, NULL, NULL, &main_loop_wait); + } + + meshlink_close(mesh); +} diff --git a/test/blackbox/test_case_channel_conn_05/node_sim_peer.c b/test/blackbox/test_case_channel_conn_05/node_sim_peer.c new file mode 100644 index 00000000..7cc095d7 --- /dev/null +++ b/test/blackbox/test_case_channel_conn_05/node_sim_peer.c @@ -0,0 +1,120 @@ +/* + node_sim_peer.c -- Implementation of Node Simulation for Meshlink Testing + for meta connection test case 01 - re-connection of + two nodes when relay node goes down + Copyright (C) 2018 Guus Sliepen + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include +#include +#include +#include +#include +#include +#include "../common/common_handlers.h" +#include "../common/test_step.h" +#include "../common/mesh_event_handler.h" +#include "../../utils.h" + +#define CMD_LINE_ARG_NODENAME 1 +#define CMD_LINE_ARG_DEVCLASS 2 +#define CMD_LINE_ARG_CLIENTID 3 +#define CMD_LINE_ARG_IMPORTSTR 4 +#define CMD_LINE_ARG_INVITEURL 5 +#define CHANNEL_PORT 1234 + +static void channel_receive_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, const void *dat, size_t len); +static bool channel_accept(meshlink_handle_t *mesh, meshlink_channel_t *channel, uint16_t port, const void *dat, size_t len); + +static int client_id = -1; + +static bool channel_accept(meshlink_handle_t *mesh, meshlink_channel_t *channel, uint16_t port, const void *dat, size_t len) { + (void)dat; + (void)len; + + assert(port == CHANNEL_PORT); + + if(!strcmp(channel->node->name, "nut")) { + meshlink_set_channel_receive_cb(mesh, channel, channel_receive_cb); + mesh->priv = channel; + + return true; + } + + return false; +} + +/* channel receive callback */ +static void channel_receive_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, const void *dat, size_t len) { + (void)mesh; + (void)channel; + (void)dat; + (void)len; + + if(len == 0) { + mesh_event_sock_send(client_id, ERR_NETWORK, NULL, 0); + assert(false); + } + + if(!strcmp(channel->node->name, "nut")) { + if(!memcmp(dat, "test", 5)) { + assert(meshlink_channel_send(mesh, channel, "reply", 5) >= 0); + } else if(!memcmp(dat, "after", 6)) { + assert(mesh_event_sock_send(client_id, CHANNEL_DATA_RECIEVED, NULL, 0)); + } + } + + return; +} + +int main(int argc, char *argv[]) { + struct timeval main_loop_wait = { 2, 0 }; + + // Import mesh event handler + + if((argv[CMD_LINE_ARG_CLIENTID]) && (argv[CMD_LINE_ARG_IMPORTSTR])) { + client_id = atoi(argv[CMD_LINE_ARG_CLIENTID]); + mesh_event_sock_connect(argv[CMD_LINE_ARG_IMPORTSTR]); + } + + // Setup required signals + + setup_signals(); + + // Run peer node instance + + meshlink_handle_t *mesh = meshlink_open("testconf", argv[CMD_LINE_ARG_NODENAME], + "test_channel_conn", atoi(argv[CMD_LINE_ARG_DEVCLASS])); + assert(mesh); + meshlink_set_log_cb(mesh, MESHLINK_DEBUG, meshlink_callback_logger); + meshlink_set_channel_accept_cb(mesh, channel_accept); + + if(argv[CMD_LINE_ARG_INVITEURL]) { + assert(meshlink_join(mesh, argv[CMD_LINE_ARG_INVITEURL])); + } + + assert(meshlink_start(mesh)); + + // All test steps executed - wait for signals to stop/start or close the mesh + + while(test_running) { + select(1, NULL, NULL, NULL, &main_loop_wait); + } + + meshlink_close(mesh); + + return EXIT_SUCCESS; +} diff --git a/test/blackbox/test_case_channel_conn_05/node_sim_relay.c b/test/blackbox/test_case_channel_conn_05/node_sim_relay.c new file mode 100644 index 00000000..46fbf163 --- /dev/null +++ b/test/blackbox/test_case_channel_conn_05/node_sim_relay.c @@ -0,0 +1,57 @@ +/* + node_sim_relay.c -- Implementation of Node Simulation for Meshlink Testing + for meta connection test case 01 - re-connection of + two nodes when relay node goes down + Copyright (C) 2018 Guus Sliepen + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include +#include +#include "../common/common_handlers.h" +#include "../common/test_step.h" +#include "../common/mesh_event_handler.h" + +#define CMD_LINE_ARG_NODENAME 1 +#define CMD_LINE_ARG_DEVCLASS 2 +#define CMD_LINE_ARG_CLIENTID 3 +#define CMD_LINE_ARG_IMPORTSTR 4 +#define CMD_LINE_ARG_INVITEURL 5 + +int main(int argc, char *argv[]) { + struct timeval main_loop_wait = { 5, 0 }; + + // Setup required signals + + setup_signals(); + + // Run relay node instance + + meshlink_handle_t *mesh = meshlink_open("testconf", argv[CMD_LINE_ARG_NODENAME], + "test_channel_conn", atoi(argv[CMD_LINE_ARG_DEVCLASS])); + assert(mesh); + meshlink_set_log_cb(mesh, MESHLINK_DEBUG, meshlink_callback_logger); + + meshlink_start(mesh); + + /* All test steps executed - wait for signals to stop/start or close the mesh */ + while(test_running) { + select(1, NULL, NULL, NULL, &main_loop_wait); + } + + meshlink_close(mesh); + + return 0; +} diff --git a/test/blackbox/test_case_channel_conn_06/Makefile.am b/test/blackbox/test_case_channel_conn_06/Makefile.am new file mode 100644 index 00000000..8bde53de --- /dev/null +++ b/test/blackbox/test_case_channel_conn_06/Makefile.am @@ -0,0 +1,13 @@ +check_PROGRAMS = node_sim_peer node_sim_nut node_sim_relay + +node_sim_peer_SOURCES = node_sim_peer.c ../common/common_handlers.c ../common/test_step.c ../common/mesh_event_handler.c ../../utils.c +node_sim_peer_LDADD = ../../../src/libmeshlink.la +node_sim_peer_CFLAGS = -D_GNU_SOURCE + +node_sim_nut_SOURCES = node_sim_nut.c ../common/common_handlers.c ../common/test_step.c ../common/mesh_event_handler.c ../../utils.c +node_sim_nut_LDADD = ../../../src/libmeshlink.la +node_sim_nut_CFLAGS = -D_GNU_SOURCE + +node_sim_relay_SOURCES = node_sim_relay.c ../common/common_handlers.c ../common/test_step.c ../common/mesh_event_handler.c ../../utils.c +node_sim_relay_LDADD = ../../../src/libmeshlink.la +node_sim_relay_CFLAGS = -D_GNU_SOURCE diff --git a/test/blackbox/test_case_channel_conn_06/node_sim_nut.c b/test/blackbox/test_case_channel_conn_06/node_sim_nut.c new file mode 100644 index 00000000..858e48d0 --- /dev/null +++ b/test/blackbox/test_case_channel_conn_06/node_sim_nut.c @@ -0,0 +1,173 @@ +/* + node_sim_nut.c -- Implementation of Node Simulation for Meshlink Testing + for meta connection test case 01 - re-connection of + two nodes when relay node goes down + Copyright (C) 2018 Guus Sliepen + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include +#include +#include +#include +#include +#include +#include "../common/common_handlers.h" +#include "../common/test_step.h" +#include "../common/mesh_event_handler.h" +#include "../../utils.h" + +#define CMD_LINE_ARG_NODENAME 1 +#define CMD_LINE_ARG_DEVCLASS 2 +#define CMD_LINE_ARG_CLIENTID 3 +#define CMD_LINE_ARG_IMPORTSTR 4 +#define CMD_LINE_ARG_INVITEURL 5 +#define CHANNEL_PORT 1234 + +static int client_id = -1; + +static struct sync_flag peer_reachable = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER}; +static struct sync_flag channel_opened = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER}; +static struct sync_flag channel_closed = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER}; +static struct sync_flag sigusr_received = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER}; + +static void send_event(mesh_event_t event); +static void node_status_cb(meshlink_handle_t *mesh, meshlink_node_t *node, + bool reachable); +static void mesh_siguser1_signal_handler(int sig_num); + +static void mesh_siguser1_signal_handler(int sig_num) { + set_sync_flag(&sigusr_received, true); + return; +} + +static void send_event(mesh_event_t event) { + bool send_ret = false; + int attempts; + + for(attempts = 0; attempts < 5; attempts += 1) { + send_ret = mesh_event_sock_send(client_id, event, NULL, 0); + + if(send_ret) { + break; + } + } + + return; +} + +static void node_status_cb(meshlink_handle_t *mesh, meshlink_node_t *node, + bool reachable) { + fprintf(stderr, "\n\n\n NODE STATUS CB : %s is %d\n\n\n\n", node->name, reachable); + + if(!strcasecmp(node->name, "peer") && reachable) { + set_sync_flag(&peer_reachable, true); + } + + return; +} + +static void poll_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, size_t len) { + (void)len; + meshlink_set_channel_poll_cb(mesh, channel, NULL); + assert(meshlink_channel_send(mesh, channel, "test", 5) >= 0); + return; +} + +static void channel_receive_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, const void *dat, size_t len) { + fprintf(stderr, "\n\n\n LEN = %u & DATA = %s in RECV CB\n\n\n\n", len, (char *)dat); + + if(len == 0) { + set_sync_flag(&channel_closed, true); + send_event(ERR_NETWORK); + return; + } + + if(!strcmp(channel->node->name, "peer")) { + if(len == 5 && !memcmp(dat, "reply", 5)) { + set_sync_flag(&channel_opened, true); + } + } + + return; +} + +int main(int argc, char *argv[]) { + struct timeval main_loop_wait = { 2, 0 }; + struct timespec timeout = {0}; + int i; + + // Import mesh event handler + + if((argv[CMD_LINE_ARG_CLIENTID]) && (argv[CMD_LINE_ARG_IMPORTSTR])) { + client_id = atoi(argv[CMD_LINE_ARG_CLIENTID]); + mesh_event_sock_connect(argv[CMD_LINE_ARG_IMPORTSTR]); + } + + // Setup required signals + + setup_signals(); + signal(SIGUSR1, mesh_siguser1_signal_handler); + + // Execute test steps + + meshlink_handle_t *mesh = meshlink_open("testconf", argv[CMD_LINE_ARG_NODENAME], + "test_channel_conn", atoi(argv[CMD_LINE_ARG_DEVCLASS])); + assert(mesh); + meshlink_set_log_cb(mesh, MESHLINK_DEBUG, meshlink_callback_logger); + meshlink_set_node_status_cb(mesh, node_status_cb); + + if(argv[CMD_LINE_ARG_INVITEURL]) { + assert(meshlink_join(mesh, argv[CMD_LINE_ARG_INVITEURL])); + } + + assert(meshlink_start(mesh)); + + // Wait for peer node to join + + assert(wait_sync_flag(&peer_reachable, 30)); + send_event(NODE_JOINED); + + // Open a channel to peer node + + meshlink_node_t *peer_node = meshlink_get_node(mesh, "peer"); + assert(peer_node); + meshlink_channel_t *channel = meshlink_channel_open(mesh, peer_node, CHANNEL_PORT, + channel_receive_cb, NULL, 0); + meshlink_set_channel_poll_cb(mesh, channel, poll_cb); + + assert(wait_sync_flag(&channel_opened, 10)); + send_event(CHANNEL_OPENED); + fprintf(stderr, "\n\n\nChannel opened, Waiting for SIGUSR1\n\n\n\n"); + assert(wait_sync_flag(&sigusr_received, 10)); + + fprintf(stderr, "\n\n\nChannel sending, got SIGUSR1\n\n\n\n"); + sleep(40); + assert(meshlink_channel_send(mesh, channel, "after", 6) >= 0); + + fprintf(stderr, "\n\n\nWaiting for close\n\n\n\n"); + + assert(wait_sync_flag(&channel_closed, 140)); + + fprintf(stderr, "\n\n\nCHANNEL CLOSED\n\n\n\n"); + + // All test steps executed - wait for signals to stop/start or close the mesh + while(test_running) { + select(1, NULL, NULL, NULL, &main_loop_wait); + } + + meshlink_close(mesh); +} diff --git a/test/blackbox/test_case_channel_conn_06/node_sim_peer.c b/test/blackbox/test_case_channel_conn_06/node_sim_peer.c new file mode 100644 index 00000000..a0be6237 --- /dev/null +++ b/test/blackbox/test_case_channel_conn_06/node_sim_peer.c @@ -0,0 +1,116 @@ +/* + node_sim_peer.c -- Implementation of Node Simulation for Meshlink Testing + for meta connection test case 01 - re-connection of + two nodes when relay node goes down + Copyright (C) 2018 Guus Sliepen + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include +#include +#include +#include +#include +#include "../common/common_handlers.h" +#include "../common/test_step.h" +#include "../common/mesh_event_handler.h" + +#define CMD_LINE_ARG_NODENAME 1 +#define CMD_LINE_ARG_DEVCLASS 2 +#define CMD_LINE_ARG_CLIENTID 3 +#define CMD_LINE_ARG_IMPORTSTR 4 +#define CMD_LINE_ARG_INVITEURL 5 +#define CHANNEL_PORT 1234 + +static int client_id = -1; +static bool channel_rec; +static bool channel_reply; +static pthread_mutex_t reply_lock = PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t reply_cond = PTHREAD_COND_INITIALIZER; +static pthread_mutex_t recv_lock = PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t recv_cond = PTHREAD_COND_INITIALIZER; + +static void channel_receive_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, const void *dat, size_t len); + +static bool channel_accept(meshlink_handle_t *mesh, meshlink_channel_t *channel, uint16_t port, const void *dat, size_t len) { + (void)dat; + (void)len; + + assert(port == CHANNEL_PORT); + + if(!strcmp(channel->node->name, "nut")) { + meshlink_set_channel_receive_cb(mesh, channel, channel_receive_cb); + mesh->priv = channel; + + return true; + } + + return false; +} + +static void channel_receive_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, const void *dat, size_t len) { + fprintf(stderr, "\n\n\n LEN = %u & DATA = %s in RECV CB\n\n\n\n", len, (char *)dat); + + if(len == 0) { + assert(mesh_event_sock_send(client_id, ERR_NETWORK, NULL, 0)); + return; + } + + if(!strcmp(channel->node->name, "nut")) { + if(!memcmp(dat, "test", 5)) { + assert(meshlink_channel_send(mesh, channel, "reply", 5) >= 0); + } + } + + return; +} + +int main(int argc, char *argv[]) { + struct timeval main_loop_wait = { 5, 0 }; + struct timespec timeout = {0}; + + // Import mesh event handler + + if((argv[CMD_LINE_ARG_CLIENTID]) && (argv[CMD_LINE_ARG_IMPORTSTR])) { + client_id = atoi(argv[CMD_LINE_ARG_CLIENTID]); + mesh_event_sock_connect(argv[CMD_LINE_ARG_IMPORTSTR]); + } + + // Run peer node instance + + setup_signals(); + + meshlink_set_log_cb(NULL, MESHLINK_DEBUG, meshlink_callback_logger); + meshlink_handle_t *mesh = meshlink_open("testconf", argv[CMD_LINE_ARG_NODENAME], + "test_channel_conn", atoi(argv[CMD_LINE_ARG_DEVCLASS])); + assert(mesh); + meshlink_set_log_cb(mesh, MESHLINK_DEBUG, meshlink_callback_logger); + meshlink_set_channel_accept_cb(mesh, channel_accept); + + if(argv[CMD_LINE_ARG_INVITEURL]) { + assert(meshlink_join(mesh, argv[CMD_LINE_ARG_INVITEURL])); + } + + assert(meshlink_start(mesh)); + + // All test steps executed - wait for signals to stop/start or close the mesh + while(test_running) { + select(1, NULL, NULL, NULL, &main_loop_wait); + } + + meshlink_close(mesh); + + return EXIT_SUCCESS; +} diff --git a/test/blackbox/test_case_channel_conn_06/node_sim_relay.c b/test/blackbox/test_case_channel_conn_06/node_sim_relay.c new file mode 100644 index 00000000..46fbf163 --- /dev/null +++ b/test/blackbox/test_case_channel_conn_06/node_sim_relay.c @@ -0,0 +1,57 @@ +/* + node_sim_relay.c -- Implementation of Node Simulation for Meshlink Testing + for meta connection test case 01 - re-connection of + two nodes when relay node goes down + Copyright (C) 2018 Guus Sliepen + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include +#include +#include "../common/common_handlers.h" +#include "../common/test_step.h" +#include "../common/mesh_event_handler.h" + +#define CMD_LINE_ARG_NODENAME 1 +#define CMD_LINE_ARG_DEVCLASS 2 +#define CMD_LINE_ARG_CLIENTID 3 +#define CMD_LINE_ARG_IMPORTSTR 4 +#define CMD_LINE_ARG_INVITEURL 5 + +int main(int argc, char *argv[]) { + struct timeval main_loop_wait = { 5, 0 }; + + // Setup required signals + + setup_signals(); + + // Run relay node instance + + meshlink_handle_t *mesh = meshlink_open("testconf", argv[CMD_LINE_ARG_NODENAME], + "test_channel_conn", atoi(argv[CMD_LINE_ARG_DEVCLASS])); + assert(mesh); + meshlink_set_log_cb(mesh, MESHLINK_DEBUG, meshlink_callback_logger); + + meshlink_start(mesh); + + /* All test steps executed - wait for signals to stop/start or close the mesh */ + while(test_running) { + select(1, NULL, NULL, NULL, &main_loop_wait); + } + + meshlink_close(mesh); + + return 0; +} diff --git a/test/blackbox/test_case_channel_conn_07/Makefile.am b/test/blackbox/test_case_channel_conn_07/Makefile.am new file mode 100644 index 00000000..8bde53de --- /dev/null +++ b/test/blackbox/test_case_channel_conn_07/Makefile.am @@ -0,0 +1,13 @@ +check_PROGRAMS = node_sim_peer node_sim_nut node_sim_relay + +node_sim_peer_SOURCES = node_sim_peer.c ../common/common_handlers.c ../common/test_step.c ../common/mesh_event_handler.c ../../utils.c +node_sim_peer_LDADD = ../../../src/libmeshlink.la +node_sim_peer_CFLAGS = -D_GNU_SOURCE + +node_sim_nut_SOURCES = node_sim_nut.c ../common/common_handlers.c ../common/test_step.c ../common/mesh_event_handler.c ../../utils.c +node_sim_nut_LDADD = ../../../src/libmeshlink.la +node_sim_nut_CFLAGS = -D_GNU_SOURCE + +node_sim_relay_SOURCES = node_sim_relay.c ../common/common_handlers.c ../common/test_step.c ../common/mesh_event_handler.c ../../utils.c +node_sim_relay_LDADD = ../../../src/libmeshlink.la +node_sim_relay_CFLAGS = -D_GNU_SOURCE diff --git a/test/blackbox/test_case_channel_conn_07/node_sim_nut.c b/test/blackbox/test_case_channel_conn_07/node_sim_nut.c new file mode 100644 index 00000000..b47c0006 --- /dev/null +++ b/test/blackbox/test_case_channel_conn_07/node_sim_nut.c @@ -0,0 +1,172 @@ +/* + node_sim_nut.c -- Implementation of Node Simulation for Meshlink Testing + for meta connection test case 01 - re-connection of + two nodes when relay node goes down + Copyright (C) 2018 Guus Sliepen + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include +#include +#include +#include +#include +#include +#include "../common/common_handlers.h" +#include "../common/test_step.h" +#include "../common/mesh_event_handler.h" +#include "../../utils.h" + +#define CMD_LINE_ARG_NODENAME 1 +#define CMD_LINE_ARG_DEVCLASS 2 +#define CMD_LINE_ARG_CLIENTID 3 +#define CMD_LINE_ARG_IMPORTSTR 4 +#define CMD_LINE_ARG_INVITEURL 5 +#define CHANNEL_PORT 1234 + +static int client_id = -1; + +static struct sync_flag peer_reachable = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER}; +static struct sync_flag channel_opened = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER}; +static struct sync_flag peer_unreachable = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER}; +static struct sync_flag sigusr_received = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER}; + +static void send_event(mesh_event_t event); +static void node_status_cb(meshlink_handle_t *mesh, meshlink_node_t *node, + bool reachable); +static void mesh_siguser1_signal_handler(int sig_num); + +static void mesh_siguser1_signal_handler(int sig_num) { + set_sync_flag(&sigusr_received, true); + return; +} + +static void send_event(mesh_event_t event) { + bool send_ret = false; + int attempts; + + for(attempts = 0; attempts < 5; attempts += 1) { + if(mesh_event_sock_send(client_id, event, NULL, 0)) { + break; + } + } + + assert(attempts < 5); + + return; +} + +static void node_status_cb(meshlink_handle_t *mesh, meshlink_node_t *node, + bool reachable) { + + if(!strcasecmp(node->name, "peer")) { + if(reachable) { + set_sync_flag(&peer_reachable, true); + } else { + set_sync_flag(&peer_unreachable, true); + } + } + + return; +} + +static void poll_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, size_t len) { + (void)len; + meshlink_set_channel_poll_cb(mesh, channel, NULL); + assert(meshlink_channel_send(mesh, channel, "test", 5) >= 0); + return; +} + +static void channel_receive_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, const void *dat, size_t len) { + if(len == 0) { + send_event(ERR_NETWORK); + return; + } + + if(!strcmp(channel->node->name, "peer")) { + if(len == 5 && !memcmp(dat, "reply", 5)) { + set_sync_flag(&channel_opened, true); + } + } + + return; +} + +int main(int argc, char *argv[]) { + struct timeval main_loop_wait = { 2, 0 }; + struct timespec timeout = {0}; + int i; + + // Import mesh event handler + + if((argv[CMD_LINE_ARG_CLIENTID]) && (argv[CMD_LINE_ARG_IMPORTSTR])) { + client_id = atoi(argv[CMD_LINE_ARG_CLIENTID]); + mesh_event_sock_connect(argv[CMD_LINE_ARG_IMPORTSTR]); + } + + // Setup required signals + + setup_signals(); + signal(SIGUSR1, mesh_siguser1_signal_handler); + + // Execute test steps + + meshlink_handle_t *mesh = meshlink_open("testconf", argv[CMD_LINE_ARG_NODENAME], + "test_channel_conn", atoi(argv[CMD_LINE_ARG_DEVCLASS])); + assert(mesh); + meshlink_set_log_cb(mesh, MESHLINK_DEBUG, meshlink_callback_logger); + meshlink_set_node_status_cb(mesh, node_status_cb); + + if(argv[CMD_LINE_ARG_INVITEURL]) { + assert(meshlink_join(mesh, argv[CMD_LINE_ARG_INVITEURL])); + } + + assert(meshlink_start(mesh)); + + // Wait for peer node to join + assert(wait_sync_flag(&peer_reachable, 30)); + send_event(NODE_JOINED); + + // Open a channel to peer node + + meshlink_node_t *peer_node = meshlink_get_node(mesh, "peer"); + assert(peer_node); + meshlink_channel_t *channel = meshlink_channel_open(mesh, peer_node, CHANNEL_PORT, + channel_receive_cb, NULL, 0); + meshlink_set_channel_poll_cb(mesh, channel, poll_cb); + + assert(wait_sync_flag(&channel_opened, 10)); + send_event(CHANNEL_OPENED); + + peer_unreachable.flag = false; + peer_reachable.flag = false; + assert(wait_sync_flag(&sigusr_received, 10)); + + assert(wait_sync_flag(&peer_unreachable, 100)); + send_event(NODE_UNREACHABLE); + + assert(wait_sync_flag(&peer_reachable, 100)); + send_event(NODE_REACHABLE); + + assert(meshlink_channel_send(mesh, channel, "after", 6) >= 0); + + // All test steps executed - wait for signals to stop/start or close the mesh + + while(test_running) { + select(1, NULL, NULL, NULL, &main_loop_wait); + } + + meshlink_close(mesh); +} diff --git a/test/blackbox/test_case_channel_conn_07/node_sim_peer.c b/test/blackbox/test_case_channel_conn_07/node_sim_peer.c new file mode 100644 index 00000000..ae8dadcc --- /dev/null +++ b/test/blackbox/test_case_channel_conn_07/node_sim_peer.c @@ -0,0 +1,109 @@ +/* + node_sim_peer.c -- Implementation of Node Simulation for Meshlink Testing + for meta connection test case 01 - re-connection of + two nodes when relay node goes down + Copyright (C) 2018 Guus Sliepen + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include +#include +#include +#include +#include +#include "../common/common_handlers.h" +#include "../common/test_step.h" +#include "../common/mesh_event_handler.h" + +#define CMD_LINE_ARG_NODENAME 1 +#define CMD_LINE_ARG_DEVCLASS 2 +#define CMD_LINE_ARG_CLIENTID 3 +#define CMD_LINE_ARG_IMPORTSTR 4 +#define CMD_LINE_ARG_INVITEURL 5 +#define CHANNEL_PORT 1234 + +static int client_id = -1; + +static void channel_receive_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, const void *dat, size_t len); + +static bool channel_accept(meshlink_handle_t *mesh, meshlink_channel_t *channel, uint16_t port, const void *dat, size_t len) { + (void)dat; + (void)len; + + assert(port == CHANNEL_PORT); + + if(!strcmp(channel->node->name, "nut")) { + meshlink_set_channel_receive_cb(mesh, channel, channel_receive_cb); + mesh->priv = channel; + + return true; + } + + return false; +} + +static void channel_receive_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, const void *dat, size_t len) { + if(len == 0) { + assert(mesh_event_sock_send(client_id, ERR_NETWORK, NULL, 0)); + return; + } + + if(!strcmp(channel->node->name, "nut")) { + if(!memcmp(dat, "test", 5)) { + assert(meshlink_channel_send(mesh, channel, "reply", 5) >= 0); + } else if(!memcmp(dat, "after", 5)) { + assert(mesh_event_sock_send(client_id, CHANNEL_DATA_RECIEVED, NULL, 0)); + } + } + + return; +} + +int main(int argc, char *argv[]) { + struct timeval main_loop_wait = { 2, 0 }; + struct timespec timeout = {0}; + + // Import mesh event handler + + if((argv[CMD_LINE_ARG_CLIENTID]) && (argv[CMD_LINE_ARG_IMPORTSTR])) { + client_id = atoi(argv[CMD_LINE_ARG_CLIENTID]); + mesh_event_sock_connect(argv[CMD_LINE_ARG_IMPORTSTR]); + } + + // Run peer node instance + + setup_signals(); + + meshlink_handle_t *mesh = meshlink_open("testconf", argv[CMD_LINE_ARG_NODENAME], + "test_channel_conn", atoi(argv[CMD_LINE_ARG_DEVCLASS])); + assert(mesh); + meshlink_set_log_cb(mesh, MESHLINK_DEBUG, meshlink_callback_logger); + meshlink_set_channel_accept_cb(mesh, channel_accept); + + if(argv[CMD_LINE_ARG_INVITEURL]) { + assert(meshlink_join(mesh, argv[CMD_LINE_ARG_INVITEURL])); + } + + assert(meshlink_start(mesh)); + + // All test steps executed - wait for signals to stop/start or close the mesh + while(test_running) { + select(1, NULL, NULL, NULL, &main_loop_wait); + } + + meshlink_close(mesh); + + return EXIT_SUCCESS; +} diff --git a/test/blackbox/test_case_channel_conn_07/node_sim_relay.c b/test/blackbox/test_case_channel_conn_07/node_sim_relay.c new file mode 100644 index 00000000..46fbf163 --- /dev/null +++ b/test/blackbox/test_case_channel_conn_07/node_sim_relay.c @@ -0,0 +1,57 @@ +/* + node_sim_relay.c -- Implementation of Node Simulation for Meshlink Testing + for meta connection test case 01 - re-connection of + two nodes when relay node goes down + Copyright (C) 2018 Guus Sliepen + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include +#include +#include "../common/common_handlers.h" +#include "../common/test_step.h" +#include "../common/mesh_event_handler.h" + +#define CMD_LINE_ARG_NODENAME 1 +#define CMD_LINE_ARG_DEVCLASS 2 +#define CMD_LINE_ARG_CLIENTID 3 +#define CMD_LINE_ARG_IMPORTSTR 4 +#define CMD_LINE_ARG_INVITEURL 5 + +int main(int argc, char *argv[]) { + struct timeval main_loop_wait = { 5, 0 }; + + // Setup required signals + + setup_signals(); + + // Run relay node instance + + meshlink_handle_t *mesh = meshlink_open("testconf", argv[CMD_LINE_ARG_NODENAME], + "test_channel_conn", atoi(argv[CMD_LINE_ARG_DEVCLASS])); + assert(mesh); + meshlink_set_log_cb(mesh, MESHLINK_DEBUG, meshlink_callback_logger); + + meshlink_start(mesh); + + /* All test steps executed - wait for signals to stop/start or close the mesh */ + while(test_running) { + select(1, NULL, NULL, NULL, &main_loop_wait); + } + + meshlink_close(mesh); + + return 0; +} diff --git a/test/blackbox/test_case_channel_conn_08/Makefile.am b/test/blackbox/test_case_channel_conn_08/Makefile.am new file mode 100644 index 00000000..8bde53de --- /dev/null +++ b/test/blackbox/test_case_channel_conn_08/Makefile.am @@ -0,0 +1,13 @@ +check_PROGRAMS = node_sim_peer node_sim_nut node_sim_relay + +node_sim_peer_SOURCES = node_sim_peer.c ../common/common_handlers.c ../common/test_step.c ../common/mesh_event_handler.c ../../utils.c +node_sim_peer_LDADD = ../../../src/libmeshlink.la +node_sim_peer_CFLAGS = -D_GNU_SOURCE + +node_sim_nut_SOURCES = node_sim_nut.c ../common/common_handlers.c ../common/test_step.c ../common/mesh_event_handler.c ../../utils.c +node_sim_nut_LDADD = ../../../src/libmeshlink.la +node_sim_nut_CFLAGS = -D_GNU_SOURCE + +node_sim_relay_SOURCES = node_sim_relay.c ../common/common_handlers.c ../common/test_step.c ../common/mesh_event_handler.c ../../utils.c +node_sim_relay_LDADD = ../../../src/libmeshlink.la +node_sim_relay_CFLAGS = -D_GNU_SOURCE diff --git a/test/blackbox/test_case_channel_conn_08/node_sim_nut.c b/test/blackbox/test_case_channel_conn_08/node_sim_nut.c new file mode 100644 index 00000000..fe338704 --- /dev/null +++ b/test/blackbox/test_case_channel_conn_08/node_sim_nut.c @@ -0,0 +1,159 @@ +/* + node_sim_nut.c -- Implementation of Node Simulation for Meshlink Testing + for meta connection test case 01 - re-connection of + two nodes when relay node goes down + Copyright (C) 2018 Guus Sliepen + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include +#include +#include +#include +#include +#include +#include "../common/common_handlers.h" +#include "../common/test_step.h" +#include "../common/mesh_event_handler.h" +#include "../../utils.h" + +#define CMD_LINE_ARG_NODENAME 1 +#define CMD_LINE_ARG_DEVCLASS 2 +#define CMD_LINE_ARG_CLIENTID 3 +#define CMD_LINE_ARG_IMPORTSTR 4 +#define CMD_LINE_ARG_INVITEURL 5 +#define CHANNEL_PORT 1234 + +static int client_id = -1; + +static struct sync_flag peer_reachable = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER}; +static struct sync_flag channel_opened = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER}; +static struct sync_flag channel_closed = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER}; + +static void send_event(mesh_event_t event); +static void node_status_cb(meshlink_handle_t *mesh, meshlink_node_t *node, + bool reachable); + +static void send_event(mesh_event_t event) { + int attempts; + + for(attempts = 0; attempts < 5; attempts += 1) { + if(mesh_event_sock_send(client_id, event, NULL, 0)) { + break; + } + } + + assert(attempts < 5); + + return; +} + +static void node_status_cb(meshlink_handle_t *mesh, meshlink_node_t *node, + bool reachable) { + if(!strcasecmp(node->name, "peer")) { + if(reachable) { + set_sync_flag(&peer_reachable, true); + } else { + peer_reachable.flag = false; + } + } + + return; +} + +static void poll_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, size_t len) { + (void)len; + meshlink_set_channel_poll_cb(mesh, channel, NULL); + assert(meshlink_channel_send(mesh, channel, "test", 5) >= 0); + return; +} + +/* channel receive callback */ +static void channel_receive_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, const void *dat, size_t len) { + if(len == 0) { + //send_event(ERR_NETWORK); + return; + } + + if(!strcmp(channel->node->name, "peer")) { + if(!memcmp(dat, "reply", 5)) { + set_sync_flag(&channel_opened, true); + } else if(!memcmp(dat, "failure", 7)) { + assert(false); + } + } + + return; +} + +int main(int argc, char *argv[]) { + struct timeval main_loop_wait = { 5, 0 }; + int i; + + // Import mesh event handler + + if((argv[CMD_LINE_ARG_CLIENTID]) && (argv[CMD_LINE_ARG_IMPORTSTR])) { + client_id = atoi(argv[CMD_LINE_ARG_CLIENTID]); + mesh_event_sock_connect(argv[CMD_LINE_ARG_IMPORTSTR]); + } + + setup_signals(); + + // Execute test steps + + meshlink_handle_t *mesh = meshlink_open("testconf", argv[CMD_LINE_ARG_NODENAME], + "test_channel_conn", atoi(argv[CMD_LINE_ARG_DEVCLASS])); + assert(mesh); + meshlink_set_log_cb(mesh, MESHLINK_DEBUG, meshlink_callback_logger); + meshlink_set_node_status_cb(mesh, node_status_cb); + + if(argv[CMD_LINE_ARG_INVITEURL]) { + assert(meshlink_join(mesh, argv[CMD_LINE_ARG_INVITEURL])); + } + + assert(meshlink_start(mesh)); + + // Wait for peer node to join + + assert(wait_sync_flag(&peer_reachable, 10)); + send_event(NODE_JOINED); + + // Open a channel to peer node + + meshlink_node_t *peer_node = meshlink_get_node(mesh, "peer"); + assert(peer_node); + meshlink_channel_t *channel = meshlink_channel_open(mesh, peer_node, CHANNEL_PORT, + channel_receive_cb, NULL, 0); + meshlink_set_channel_poll_cb(mesh, channel, poll_cb); + + assert(wait_sync_flag(&channel_opened, 10)); + send_event(CHANNEL_OPENED); + + // Restarting the node instance + + meshlink_stop(mesh); + meshlink_start(mesh); + + assert(wait_sync_flag(&peer_reachable, 60)); + send_event(NODE_RESTARTED); + + // All test steps executed - wait for signals to stop/start or close the mesh + + while(test_running) { + select(1, NULL, NULL, NULL, &main_loop_wait); + } + + meshlink_close(mesh); +} diff --git a/test/blackbox/test_case_channel_conn_08/node_sim_peer.c b/test/blackbox/test_case_channel_conn_08/node_sim_peer.c new file mode 100644 index 00000000..01289786 --- /dev/null +++ b/test/blackbox/test_case_channel_conn_08/node_sim_peer.c @@ -0,0 +1,128 @@ +/* + node_sim_peer.c -- Implementation of Node Simulation for Meshlink Testing + for meta connection test case 01 - re-connection of + two nodes when relay node goes down + Copyright (C) 2018 Guus Sliepen + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include +#include +#include +#include +#include +#include +#include "../common/common_handlers.h" +#include "../common/test_step.h" +#include "../common/mesh_event_handler.h" +#include "../../utils.h" + +#define CMD_LINE_ARG_NODENAME 1 +#define CMD_LINE_ARG_DEVCLASS 2 +#define CMD_LINE_ARG_CLIENTID 3 +#define CMD_LINE_ARG_IMPORTSTR 4 +#define CMD_LINE_ARG_INVITEURL 5 +#define CHANNEL_PORT 1234 + +static void channel_receive_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, const void *dat, size_t len); +static bool channel_accept(meshlink_handle_t *mesh, meshlink_channel_t *channel, uint16_t port, const void *dat, size_t len); + +static struct sync_flag sigusr = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER}; +static int client_id = -1; + +static void mesh_siguser1_signal_handler(int sig_num) { + set_sync_flag(&sigusr, true); + + return; +} + +static bool channel_accept(meshlink_handle_t *mesh, meshlink_channel_t *channel, uint16_t port, const void *dat, size_t len) { + (void)dat; + (void)len; + + assert(port == CHANNEL_PORT); + + if(!strcmp(channel->node->name, "nut")) { + meshlink_set_channel_receive_cb(mesh, channel, channel_receive_cb); + mesh->priv = channel; + + return true; + } + + return false; +} + +/* channel receive callback */ +static void channel_receive_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, const void *dat, size_t len) { + (void)mesh; + (void)channel; + (void)dat; + (void)len; + + if(len == 0) { + mesh_event_sock_send(client_id, ERR_NETWORK, NULL, 0); + return; + } + + if(!strcmp(channel->node->name, "nut") && !memcmp(dat, "test", 5)) { + assert(meshlink_channel_send(mesh, channel, "reply", 5) >= 0); + } + + return; +} + +int main(int argc, char *argv[]) { + struct timeval main_loop_wait = { 2, 0 }; + + // Import mesh event handler + + if((argv[CMD_LINE_ARG_CLIENTID]) && (argv[CMD_LINE_ARG_IMPORTSTR])) { + client_id = atoi(argv[CMD_LINE_ARG_CLIENTID]); + mesh_event_sock_connect(argv[CMD_LINE_ARG_IMPORTSTR]); + } + + // Setup required signals + + setup_signals(); + signal(SIGUSR1, mesh_siguser1_signal_handler); + + // Run peer node instance + + meshlink_handle_t *mesh = meshlink_open("testconf", argv[CMD_LINE_ARG_NODENAME], + "test_channel_conn", atoi(argv[CMD_LINE_ARG_DEVCLASS])); + assert(mesh); + meshlink_set_log_cb(mesh, MESHLINK_DEBUG, meshlink_callback_logger); + meshlink_set_channel_accept_cb(mesh, channel_accept); + + if(argv[CMD_LINE_ARG_INVITEURL]) { + assert(meshlink_join(mesh, argv[CMD_LINE_ARG_INVITEURL])); + } + + assert(meshlink_start(mesh)); + + assert(wait_sync_flag(&sigusr, 140)); + meshlink_channel_t *channel = mesh->priv; + assert(meshlink_channel_send(mesh, channel, "failure", 7)); + + // All test steps executed - wait for signals to stop/start or close the mesh + + while(test_running) { + select(1, NULL, NULL, NULL, &main_loop_wait); + } + + meshlink_close(mesh); + + return EXIT_SUCCESS; +} diff --git a/test/blackbox/test_case_channel_conn_08/node_sim_relay.c b/test/blackbox/test_case_channel_conn_08/node_sim_relay.c new file mode 100644 index 00000000..46fbf163 --- /dev/null +++ b/test/blackbox/test_case_channel_conn_08/node_sim_relay.c @@ -0,0 +1,57 @@ +/* + node_sim_relay.c -- Implementation of Node Simulation for Meshlink Testing + for meta connection test case 01 - re-connection of + two nodes when relay node goes down + Copyright (C) 2018 Guus Sliepen + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include +#include +#include "../common/common_handlers.h" +#include "../common/test_step.h" +#include "../common/mesh_event_handler.h" + +#define CMD_LINE_ARG_NODENAME 1 +#define CMD_LINE_ARG_DEVCLASS 2 +#define CMD_LINE_ARG_CLIENTID 3 +#define CMD_LINE_ARG_IMPORTSTR 4 +#define CMD_LINE_ARG_INVITEURL 5 + +int main(int argc, char *argv[]) { + struct timeval main_loop_wait = { 5, 0 }; + + // Setup required signals + + setup_signals(); + + // Run relay node instance + + meshlink_handle_t *mesh = meshlink_open("testconf", argv[CMD_LINE_ARG_NODENAME], + "test_channel_conn", atoi(argv[CMD_LINE_ARG_DEVCLASS])); + assert(mesh); + meshlink_set_log_cb(mesh, MESHLINK_DEBUG, meshlink_callback_logger); + + meshlink_start(mesh); + + /* All test steps executed - wait for signals to stop/start or close the mesh */ + while(test_running) { + select(1, NULL, NULL, NULL, &main_loop_wait); + } + + meshlink_close(mesh); + + return 0; +} -- 2.39.2