1 /* Copyright 2020-2021 IGEL Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
7 * http://www.apache.org/licenses/LICENSE-2.0
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
24 #include "lease-server.h"
26 #include "test-helpers.h"
27 #include "test-socket-client.h"
29 #define SOCKETDIR "/tmp"
31 /************** Test fixutre functions *************************/
32 struct test_config default_test_config;
34 #define TEST_LEASE_NAME "test-lease"
36 static struct lease_handle test_lease = {
37 .name = TEST_LEASE_NAME,
40 static void test_setup(void)
42 dlm_log_enable_debug(true);
43 setenv("DLM_RUNTIME_PATH", SOCKETDIR, 1);
45 default_test_config = (struct test_config){
50 static void test_shutdown(void)
52 test_config_cleanup(&default_test_config);
55 static struct ls *create_default_server(void)
57 struct lease_handle *leases[] = {
60 struct ls *ls = ls_create(leases, 1);
61 ck_assert_ptr_ne(ls, NULL);
65 /************** Lease server error handling tests *************/
67 /* duplicate_server_failure
69 * Test details: Try to intialize the same server twice
70 * Expected results: ls_create() fails.
72 START_TEST(duplicate_server_failure)
74 struct lease_handle *leases[] = {&test_lease, &test_lease};
75 struct ls *ls = ls_create(leases, 2);
76 ck_assert_ptr_eq(ls, NULL);
80 START_TEST(long_lease_name_failure)
82 char long_lease_name[200];
84 size_t len = sizeof(long_lease_name) - 1;
85 memset(long_lease_name, 'a', len);
86 long_lease_name[len] = '\0';
88 struct lease_handle long_name_lease = {.name = long_lease_name};
90 struct lease_handle *leases[] = {&long_name_lease};
91 struct ls *ls = ls_create(leases, 1);
92 ck_assert_ptr_eq(ls, NULL);
96 static void add_error_tests(Suite *s)
98 TCase *tc = tcase_create("Lease server errors");
100 tcase_add_checked_fixture(tc, test_setup, test_shutdown);
102 tcase_add_test(tc, duplicate_server_failure);
103 tcase_add_test(tc, long_lease_name_failure);
104 suite_add_tcase(s, tc);
107 /************** Client request handling tests ************/
109 /* Test the handling of client requests. Make sure that the
110 * proper struct ls_req are generated for each client request.
113 static void check_request(struct ls_req *req,
114 struct lease_handle *expected_lease,
115 enum ls_req_type expected_type)
117 ck_assert_ptr_eq(req->lease_handle, expected_lease);
118 ck_assert_int_eq(req->type, expected_type);
121 static void get_and_check_request(struct ls *ls,
122 struct lease_handle *expected_lease,
123 enum ls_req_type expected_type)
126 bool req_valid = ls_get_request(ls, &req);
127 ck_assert_int_eq(req_valid, true);
128 check_request(&req, expected_lease, expected_type);
131 /* Asynchronous version of the above. Has the extra overhead of
132 * spawning a new thread, so should be used sparingly. */
138 struct ls_req expected;
139 struct ls_req actual;
142 static void *get_request_thread(void *arg)
144 struct async_req *async_req = arg;
145 async_req->req_valid =
146 ls_get_request(async_req->ls, &async_req->actual);
151 static struct async_req *
152 get_and_check_request_async(struct ls *ls, struct lease_handle *expected_lease,
153 enum ls_req_type expected_type)
156 struct async_req *req = malloc(sizeof(struct async_req));
157 ck_assert_ptr_ne(req, NULL);
159 *req = (struct async_req){
163 .lease_handle = expected_lease,
164 .type = expected_type,
168 int ret = pthread_create(&req->tid, NULL, get_request_thread, req);
169 ck_assert_int_eq(ret, 0);
174 static void check_async_req_result(struct async_req *req)
177 pthread_join(req->tid, NULL);
178 ck_assert_int_eq(req->req_valid, true);
179 check_request(&req->actual, req->expected.lease_handle,
184 /* issue_lease_request_and_release
186 * Test details: Generate a lease request and lease release command from
188 * Expected results: One get lease and one release lease request are returned
189 * from ls_get_request().
191 START_TEST(issue_lease_request_and_release)
193 struct ls *ls = create_default_server();
195 struct client_state *cstate = test_client_start(&default_test_config);
197 get_and_check_request(ls, &test_lease, LS_REQ_GET_LEASE);
198 test_client_stop(cstate);
199 get_and_check_request(ls, &test_lease, LS_REQ_RELEASE_LEASE);
204 /* issue_lease_request_and_early_release
206 * Test details: Close client connection immediately after connecting (before
207 * lease request is processed)
208 * Expected results: Should be the same result as
209 * issue_lease_request_and_release.
211 START_TEST(issue_lease_request_and_early_release)
213 struct ls *ls = create_default_server();
215 struct client_state *cstate = test_client_start(&default_test_config);
217 test_client_stop(cstate);
218 get_and_check_request(ls, &test_lease, LS_REQ_GET_LEASE);
219 get_and_check_request(ls, &test_lease, LS_REQ_RELEASE_LEASE);
224 /* issue_multiple_lease_requests
226 * Test details: Generate multiple lease requests to the same lease server from
227 * multiple clients at the same time
228 * Expected results: One get lease and one release lease request are returned
229 * from ls_get_request().
230 * Requests from all but the first client are rejected
231 * (sockets are closed).
233 START_TEST(issue_multiple_lease_requests)
235 struct lease_handle *leases[] = {
238 struct ls *ls = ls_create(leases, 1);
240 struct test_config accepted_config;
241 struct client_state *accepted_cstate;
243 accepted_config = default_test_config;
244 accepted_cstate = test_client_start(&accepted_config);
245 get_and_check_request(ls, &test_lease, LS_REQ_GET_LEASE);
247 /*Try to make additional connections while the first is still
249 const int nextra_clients = 2;
250 struct test_config extra_configs[nextra_clients];
251 struct client_state *extra_cstates[nextra_clients];
253 for (int i = 0; i < nextra_clients; i++) {
254 extra_configs[i] = default_test_config;
255 extra_cstates[i] = test_client_start(&extra_configs[i]);
258 // Start asyncronously checking for the accepted client to release.
259 struct async_req *async_release_req =
260 get_and_check_request_async(ls, &test_lease, LS_REQ_RELEASE_LEASE);
262 for (int i = 0; i < nextra_clients; i++) {
263 test_client_stop(extra_cstates[i]);
266 /* Release the first connection and check results */
267 test_client_stop(accepted_cstate);
268 check_async_req_result(async_release_req);
270 /* Only one connection should be granted access by the lease manager */
271 ck_assert_int_eq(accepted_config.connection_completed, true);
272 for (int i = 0; i < nextra_clients; i++)
273 ck_assert_int_eq(extra_configs[i].connection_completed, false);
278 static void add_client_request_tests(Suite *s)
280 TCase *tc = tcase_create("Client request testing");
282 tcase_add_checked_fixture(tc, test_setup, test_shutdown);
284 tcase_add_test(tc, issue_lease_request_and_release);
285 tcase_add_test(tc, issue_lease_request_and_early_release);
286 tcase_add_test(tc, issue_multiple_lease_requests);
287 suite_add_tcase(s, tc);
290 /************** File descriptor sending tests ************/
292 /* Test the sending (and failure to send) of file descriptors
298 * Test details: Send a valid fd to a given client.
299 * Expected results: The correct fd is successfully sent.
301 START_TEST(send_fd_to_client)
303 struct ls *ls = create_default_server();
305 struct client_state *cstate = test_client_start(&default_test_config);
308 bool req_valid = ls_get_request(ls, &req);
309 ck_assert_int_eq(req_valid, true);
310 check_request(&req, &test_lease, LS_REQ_GET_LEASE);
312 /* send an fd to the client*/
313 int test_fd = get_dummy_fd();
314 ck_assert_int_eq(ls_send_fd(ls, req.server, test_fd), true);
316 test_client_stop(cstate);
317 get_and_check_request(ls, &test_lease, LS_REQ_RELEASE_LEASE);
319 ck_assert_int_eq(default_test_config.connection_completed, true);
320 ck_assert_int_eq(default_test_config.has_data, true);
321 check_fd_equality(test_fd, default_test_config.received_fd);
326 /* ls_send_fd_is_noop_when_fd_is_invalid
328 * Test details: Call ls_send_fd() with an invalid fd.
329 * Expected results: No fd is sent to client. The connection to the
332 START_TEST(ls_send_fd_is_noop_when_fd_is_invalid)
334 struct ls *ls = create_default_server();
336 struct client_state *cstate = test_client_start(&default_test_config);
339 bool req_valid = ls_get_request(ls, &req);
340 ck_assert_int_eq(req_valid, true);
341 check_request(&req, &test_lease, LS_REQ_GET_LEASE);
343 int invalid_fd = get_dummy_fd();
346 ck_assert_int_eq(ls_send_fd(ls, req.server, invalid_fd), false);
348 test_client_stop(cstate);
349 get_and_check_request(ls, &test_lease, LS_REQ_RELEASE_LEASE);
350 ck_assert_int_eq(default_test_config.connection_completed, true);
351 ck_assert_int_eq(default_test_config.has_data, false);
356 static void add_fd_send_tests(Suite *s)
358 TCase *tc = tcase_create("File descriptor sending tests");
360 tcase_add_checked_fixture(tc, test_setup, test_shutdown);
362 tcase_add_test(tc, send_fd_to_client);
363 tcase_add_test(tc, ls_send_fd_is_noop_when_fd_is_invalid);
364 suite_add_tcase(s, tc);
373 s = suite_create("DLM lease server tests");
376 add_client_request_tests(s);
377 add_fd_send_tests(s);
379 sr = srunner_create(s);
381 srunner_run_all(sr, CK_NORMAL);
382 number_failed = srunner_ntests_failed(sr);
384 return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;