2 test_cases_set_port.c -- Execution of specific meshlink black box test cases
3 Copyright (C) 2018 Guus Sliepen <guus@meshlink.io>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 #include "execute_tests.h"
25 #include "test_cases_destroy.h"
26 #include "../common/containers.h"
27 #include "../common/test_step.h"
28 #include "../common/common_handlers.h"
29 #include "../../utils.h"
30 #include "test_cases_set_port.h"
39 #include <linux/limits.h>
41 /* Modify this to change the logging level of Meshlink */
42 #define TEST_MESHLINK_LOG_LEVEL MESHLINK_DEBUG
46 #define TEST_MESHLINK_SET_PORT "test_set_port"
47 #define create_path(confbase, node_name, test_case_no) assert(snprintf(confbase, sizeof(confbase), TEST_MESHLINK_SET_PORT "_%ld_%s_%02d", (long) getpid(), node_name, test_case_no) > 0)
49 static void test_case_set_port_01(void **state);
50 static bool test_set_port_01(void);
51 static void test_case_set_port_02(void **state);
52 static bool test_set_port_02(void);
53 static void test_case_set_port_03(void **state);
54 static bool test_set_port_03(void);
55 static void test_case_set_port_04(void **state);
56 static bool test_set_port_04(void);
58 /* State structure for set port API Test Case #1 */
59 static black_box_state_t test_case_set_port_01_state = {
60 .test_case_name = "test_case_set_port_01",
62 /* State structure for set port API Test Case #2 */
63 static black_box_state_t test_case_set_port_02_state = {
64 .test_case_name = "test_case_set_port_02",
66 /* State structure for set port API Test Case #3 */
67 static black_box_state_t test_case_set_port_03_state = {
68 .test_case_name = "test_case_set_port_03",
70 /* State structure for set port API Test Case #4 */
71 static black_box_state_t test_case_set_port_04_state = {
72 .test_case_name = "test_case_set_port_04",
75 static bool try_bind(int portno) {
76 int socket_fd = socket(AF_INET, SOCK_STREAM, 0);
77 assert_int_not_equal(socket_fd, -1);
79 struct sockaddr_in sin;
80 socklen_t len = sizeof(sin);
83 assert_int_not_equal(getsockname(socket_fd, (struct sockaddr *)&sin, &len), -1);
84 sin.sin_addr.s_addr = INADDR_ANY;
85 sin.sin_port = htons(portno);
88 int bind_status = bind(socket_fd, (struct sockaddr *)&sin, len);
90 // Exempt EADDRINUSE error only
93 assert_int_equal(errno, EADDRINUSE);
96 assert_int_not_equal(close(socket_fd), -1);
101 static void wait_for_socket_free(int portno) {
103 // Wait upto 20 seconds and poll every second whether the port is freed or not
105 for(int i = 0; i < 20; i++) {
106 if(try_bind(portno)) {
116 static int get_free_port(void) {
120 int socket_fd = socket(AF_INET, SOCK_STREAM, 0);
121 assert_int_not_equal(socket_fd, -1);
123 struct sockaddr_in sin;
124 socklen_t len = sizeof(sin);
127 assert_int_not_equal(getsockname(socket_fd, (struct sockaddr *)&sin, &len), -1);
128 sin.sin_addr.s_addr = INADDR_ANY;
131 assert_int_not_equal(bind(socket_fd, (struct sockaddr *)&sin, len), -1);
133 assert_int_not_equal(getsockname(socket_fd, (struct sockaddr *)&sin, &len), -1);
135 assert_int_not_equal(close(socket_fd), -1);
137 return (int) sin.sin_port;
141 /* Execute meshlink_set_port Test Case # 1 - valid case*/
142 static void test_case_set_port_01(void **state) {
143 execute_test(test_set_port_01, state);
145 /* Test Steps for meshlink_set_port Test Case # 1 - Valid case
148 1. Open NUT(Node Under Test)
152 Set the new port to the NUT.
154 static bool test_set_port_01(void) {
155 meshlink_set_log_cb(NULL, TEST_MESHLINK_LOG_LEVEL, meshlink_callback_logger);
157 // Create meshlink instance
159 mesh_handle = meshlink_open("setportconf", "nut", "test", 1);
161 meshlink_set_log_cb(mesh_handle, TEST_MESHLINK_LOG_LEVEL, meshlink_callback_logger);
163 // Get old port and set a new port number
166 port = meshlink_get_port(mesh_handle);
168 bool ret = meshlink_set_port(mesh_handle, 8000);
169 port = meshlink_get_port(mesh_handle);
171 assert_int_equal(port, 8000);
172 assert_int_equal(ret, true);
176 meshlink_close(mesh_handle);
177 assert(meshlink_destroy("setportconf"));
182 /* Execute meshlink_set_port Test Case # 2 - Invalid arguments */
183 static void test_case_set_port_02(void **state) {
184 execute_test(test_set_port_02, state);
187 /* Test Steps for meshlink_set_port Test Case # 2 - functionality test
190 1. Open and start NUT and then pass invalid arguments to the set port API
193 Meshlink set port API should fail and error out when invalid arguments are passed
195 static bool test_set_port_02(void) {
196 char nut_confbase[PATH_MAX];
197 create_path(nut_confbase, NUT, 2);
199 // Create meshlink instance
201 meshlink_set_log_cb(NULL, TEST_MESHLINK_LOG_LEVEL, log_cb);
202 meshlink_handle_t *mesh = meshlink_open(nut_confbase, NUT, TEST_MESHLINK_SET_PORT, DEV_CLASS_STATIONARY);
203 meshlink_set_log_cb(mesh, TEST_MESHLINK_LOG_LEVEL, log_cb);
205 // meshlink_set_port called using NULL as mesh handle
207 meshlink_errno = MESHLINK_OK;
208 assert_false(meshlink_set_port(NULL, 8000));
209 assert_int_equal(meshlink_errno, MESHLINK_EINVAL);
211 // Setting port after starting NUT
212 meshlink_errno = MESHLINK_OK;
213 assert_false(meshlink_set_port(mesh, -1));
214 assert_int_equal(meshlink_errno, MESHLINK_EINVAL);
216 meshlink_errno = MESHLINK_OK;
217 assert_false(meshlink_set_port(mesh, 70000));
218 assert_int_equal(meshlink_errno, MESHLINK_EINVAL);
220 assert_true(meshlink_start(mesh));
221 meshlink_errno = MESHLINK_OK;
222 assert_false(meshlink_set_port(mesh, 8000));
223 assert_int_equal(meshlink_errno, MESHLINK_EINVAL);
227 meshlink_close(mesh);
228 assert_true(meshlink_destroy(nut_confbase));
232 /* Execute meshlink_set_port Test Case # 3 - Synchronization testing */
233 static void test_case_set_port_03(void **state) {
234 execute_test(test_set_port_03, state);
237 static bool test_set_port_03(void) {
240 char nut_confbase[PATH_MAX];
241 create_path(nut_confbase, NUT, 3);
243 int new_port = get_free_port();
245 // Fork a new process in which NUT opens it's instance, set's the new port and raises SIGINT to terminate.
248 assert_int_not_equal(pid, -1);
251 meshlink_set_log_cb(NULL, MESHLINK_DEBUG, log_cb);
252 meshlink_handle_t *mesh = meshlink_open(nut_confbase, NUT, TEST_MESHLINK_SET_PORT, DEV_CLASS_STATIONARY);
255 assert(meshlink_set_port(mesh, new_port));
259 // Wait for child exit and verify which signal terminated it
261 assert_int_not_equal(waitpid(pid, &pid_status, 0), -1);
262 assert_int_equal(WIFSIGNALED(pid_status), true);
263 assert_int_equal(WTERMSIG(pid_status), SIGINT);
265 // Wait for the NUT's listening socket to be freed. (i.e, preventing meshlink from binding to a new port
266 // when NUT instance is reopened and the actual port is not freed due EADDRINUSE)
268 wait_for_socket_free(new_port);
270 // Reopen the NUT instance in the same test suite
272 meshlink_set_log_cb(NULL, MESHLINK_DEBUG, log_cb);
273 meshlink_handle_t *mesh = meshlink_open(nut_confbase, NUT, TEST_MESHLINK_SET_PORT, DEV_CLASS_STATIONARY);
274 assert_non_null(mesh);
276 assert_false(try_bind(new_port));
278 // Validate the new port that's being set in the previous instance persists.
280 int get_port = meshlink_get_port(mesh);
281 assert_int_equal(get_port, new_port);
283 // Close the mesh instance and verify that the listening port is closed or not
285 meshlink_close(mesh);
287 wait_for_socket_free(new_port);
289 assert_true(meshlink_destroy(nut_confbase));
294 int test_meshlink_set_port(void) {
295 const struct CMUnitTest blackbox_set_port_tests[] = {
296 cmocka_unit_test_prestate_setup_teardown(test_case_set_port_01, NULL, NULL,
297 (void *)&test_case_set_port_01_state),
298 cmocka_unit_test_prestate_setup_teardown(test_case_set_port_02, NULL, NULL,
299 (void *)&test_case_set_port_02_state),
300 cmocka_unit_test_prestate_setup_teardown(test_case_set_port_03, NULL, NULL,
301 (void *)&test_case_set_port_03_state)
303 total_tests += sizeof(blackbox_set_port_tests) / sizeof(blackbox_set_port_tests[0]);
304 return cmocka_run_group_tests(blackbox_set_port_tests, NULL, NULL);