lease-server: Allow multiple client connections
[src/drm-lease-manager.git] / drm-lease-manager / test / lease-server-test.c
1 /* Copyright 2020-2021 IGEL Co., Ltd.
2  *
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
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
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.
14  */
15
16 #include <check.h>
17
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <unistd.h>
21
22 #include <pthread.h>
23
24 #include "lease-server.h"
25 #include "log.h"
26 #include "test-helpers.h"
27 #include "test-socket-client.h"
28
29 #define SOCKETDIR "/tmp"
30
31 #define ARRAY_LENGTH(x) sizeof(x) / sizeof(x[0])
32
33 /************** Test fixutre functions *************************/
34 struct test_config default_test_config;
35
36 #define TEST_LEASE_NAME "test-lease"
37
38 static struct lease_handle test_lease = {
39     .name = TEST_LEASE_NAME,
40 };
41
42 static void test_setup(void)
43 {
44         dlm_log_enable_debug(true);
45         setenv("DLM_RUNTIME_PATH", SOCKETDIR, 1);
46
47         default_test_config = (struct test_config){
48             .lease = &test_lease,
49         };
50 }
51
52 static void test_shutdown(void)
53 {
54         test_config_cleanup(&default_test_config);
55 }
56
57 static struct ls *create_default_server(void)
58 {
59         struct lease_handle *leases[] = {
60             &test_lease,
61         };
62         struct ls *ls = ls_create(leases, 1);
63         ck_assert_ptr_ne(ls, NULL);
64         return ls;
65 }
66
67 /**************  Lease server error handling tests *************/
68
69 /* duplicate_server_failure
70  *
71  * Test details: Try to intialize the same server twice
72  * Expected results: ls_create() fails.
73  */
74 START_TEST(duplicate_server_failure)
75 {
76         struct lease_handle *leases[] = {&test_lease, &test_lease};
77         struct ls *ls = ls_create(leases, 2);
78         ck_assert_ptr_eq(ls, NULL);
79 }
80 END_TEST
81
82 START_TEST(long_lease_name_failure)
83 {
84         char long_lease_name[200];
85
86         size_t len = sizeof(long_lease_name) - 1;
87         memset(long_lease_name, 'a', len);
88         long_lease_name[len] = '\0';
89
90         struct lease_handle long_name_lease = {.name = long_lease_name};
91
92         struct lease_handle *leases[] = {&long_name_lease};
93         struct ls *ls = ls_create(leases, 1);
94         ck_assert_ptr_eq(ls, NULL);
95 }
96 END_TEST
97
98 static void add_error_tests(Suite *s)
99 {
100         TCase *tc = tcase_create("Lease server errors");
101
102         tcase_add_checked_fixture(tc, test_setup, test_shutdown);
103
104         tcase_add_test(tc, duplicate_server_failure);
105         tcase_add_test(tc, long_lease_name_failure);
106         suite_add_tcase(s, tc);
107 }
108
109 /**************  Client request handling tests ************/
110
111 /* Test the handling of client requests.  Make sure that the
112  * proper struct ls_req are generated for each client request.
113  */
114
115 static void check_request(struct ls_req *req,
116                           struct lease_handle *expected_lease,
117                           enum ls_req_type expected_type)
118 {
119         ck_assert_ptr_eq(req->lease_handle, expected_lease);
120         ck_assert_int_eq(req->type, expected_type);
121 }
122
123 static void get_and_check_request(struct ls *ls,
124                                   struct lease_handle *expected_lease,
125                                   enum ls_req_type expected_type)
126 {
127         struct ls_req req;
128         bool req_valid = ls_get_request(ls, &req);
129         ck_assert_int_eq(req_valid, true);
130         check_request(&req, expected_lease, expected_type);
131 }
132
133 /* issue_lease_request_and_release
134  *
135  * Test details: Generate a lease request and lease release command from
136  *               a client.
137  * Expected results: One get lease and one release lease request are returned
138  *                   from ls_get_request().
139  */
140 START_TEST(issue_lease_request_and_release)
141 {
142         struct ls *ls = create_default_server();
143
144         struct client_state *cstate = test_client_start(&default_test_config);
145
146         get_and_check_request(ls, &test_lease, LS_REQ_GET_LEASE);
147         test_client_stop(cstate);
148         get_and_check_request(ls, &test_lease, LS_REQ_RELEASE_LEASE);
149         ls_destroy(ls);
150 }
151 END_TEST
152
153 /* issue_lease_request_and_early_release
154  *
155  * Test details: Close client connection immediately after connecting (before
156  *               lease request is processed)
157  * Expected results: Should be the same result as
158  * issue_lease_request_and_release.
159  */
160 START_TEST(issue_lease_request_and_early_release)
161 {
162         struct ls *ls = create_default_server();
163
164         struct client_state *cstate = test_client_start(&default_test_config);
165
166         test_client_stop(cstate);
167         get_and_check_request(ls, &test_lease, LS_REQ_GET_LEASE);
168         get_and_check_request(ls, &test_lease, LS_REQ_RELEASE_LEASE);
169         ls_destroy(ls);
170 }
171 END_TEST
172
173 /* issue_multiple_lease_requests
174  *
175  * Test details: Generate multiple lease requests to the same lease server from
176  *               multiple clients at the same time
177  * Expected results: One lease request per client is returned from
178  *                   ls_get_request().
179  *                   (Test will process each connection in series and either
180  *                    keep the current connection or switch a new one.)
181  *                   Only one client remains connected at the end of the test,
182  *                   and it returns a validlease release request.
183  */
184 START_TEST(issue_multiple_lease_requests)
185 {
186         /* List of which client connections to accept.
187          * If the nth element is `false` that client request will be
188          * rejected, and should be reflected in the final configuration
189          * state */
190         bool keep_current_client[] = {false, true, true, false, true};
191
192         struct lease_handle *leases[] = {
193             &test_lease,
194         };
195         struct ls *ls = ls_create(leases, 1);
196
197         const int clients = ARRAY_LENGTH(keep_current_client);
198         struct test_config configs[clients];
199         struct client_state *cstates[clients];
200
201         struct ls_req req;
202         struct ls_client *current_client = NULL;
203
204         /* Start all clients and accept / reject connections */
205         for (int i = 0; i < clients; i++) {
206                 configs[i] = default_test_config;
207                 cstates[i] = test_client_start(&configs[i]);
208                 ck_assert_int_eq(ls_get_request(ls, &req), true);
209                 check_request(&req, &test_lease, LS_REQ_GET_LEASE);
210                 if (current_client && keep_current_client[i]) {
211                         ls_disconnect_client(ls, req.client);
212                 } else {
213                         if (current_client)
214                                 ls_disconnect_client(ls, current_client);
215                         current_client = req.client;
216                 }
217         }
218
219         /* Shut down all clients */
220         for (int i = 0; i < clients; i++)
221                 test_client_stop(cstates[i]);
222
223         /* Check that a valid release is received from the last accepted client
224          * connection */
225         ck_assert_int_eq(ls_get_request(ls, &req), true);
226         check_request(&req, &test_lease, LS_REQ_RELEASE_LEASE);
227         ck_assert_ptr_eq(current_client, req.client);
228
229         /* Check that no other client connections have completed */
230         int connections_completed = 0;
231         for (int i = 0; i < clients; i++) {
232                 if (configs[i].connection_completed) {
233                         connections_completed++;
234                         ck_assert_int_eq(connections_completed, 1);
235                 }
236         }
237         ls_destroy(ls);
238 }
239 END_TEST
240
241 static void add_client_request_tests(Suite *s)
242 {
243         TCase *tc = tcase_create("Client request testing");
244
245         tcase_add_checked_fixture(tc, test_setup, test_shutdown);
246
247         tcase_add_test(tc, issue_lease_request_and_release);
248         tcase_add_test(tc, issue_lease_request_and_early_release);
249         tcase_add_test(tc, issue_multiple_lease_requests);
250         suite_add_tcase(s, tc);
251 }
252
253 /**************  File descriptor sending tests ************/
254
255 /* Test the sending (and failure to send) of file descriptors
256  * to the client.
257  */
258
259 /* send_fd_to_client
260  *
261  * Test details: Send a valid fd to a given client.
262  * Expected results: The correct fd is successfully sent.
263  */
264 START_TEST(send_fd_to_client)
265 {
266         struct ls *ls = create_default_server();
267
268         struct client_state *cstate = test_client_start(&default_test_config);
269
270         struct ls_req req;
271         bool req_valid = ls_get_request(ls, &req);
272         ck_assert_int_eq(req_valid, true);
273         check_request(&req, &test_lease, LS_REQ_GET_LEASE);
274
275         /* send an fd to the client*/
276         int test_fd = get_dummy_fd();
277         ck_assert_int_eq(ls_send_fd(ls, req.client, test_fd), true);
278
279         test_client_stop(cstate);
280         get_and_check_request(ls, &test_lease, LS_REQ_RELEASE_LEASE);
281
282         ck_assert_int_eq(default_test_config.connection_completed, true);
283         ck_assert_int_eq(default_test_config.has_data, true);
284         check_fd_equality(test_fd, default_test_config.received_fd);
285         ls_destroy(ls);
286 }
287 END_TEST
288
289 /* ls_send_fd_is_noop_when_fd_is_invalid
290  *
291  * Test details: Call ls_send_fd() with an invalid  fd.
292  * Expected results: No fd is sent to client.  The connection to the
293  *                   client is closed.
294  */
295 START_TEST(ls_send_fd_is_noop_when_fd_is_invalid)
296 {
297         struct ls *ls = create_default_server();
298
299         struct client_state *cstate = test_client_start(&default_test_config);
300
301         struct ls_req req;
302         bool req_valid = ls_get_request(ls, &req);
303         ck_assert_int_eq(req_valid, true);
304         check_request(&req, &test_lease, LS_REQ_GET_LEASE);
305
306         int invalid_fd = get_dummy_fd();
307         close(invalid_fd);
308
309         ck_assert_int_eq(ls_send_fd(ls, req.client, invalid_fd), false);
310
311         test_client_stop(cstate);
312         get_and_check_request(ls, &test_lease, LS_REQ_RELEASE_LEASE);
313         ck_assert_int_eq(default_test_config.connection_completed, true);
314         ck_assert_int_eq(default_test_config.has_data, false);
315         ls_destroy(ls);
316 }
317 END_TEST
318
319 static void add_fd_send_tests(Suite *s)
320 {
321         TCase *tc = tcase_create("File descriptor sending tests");
322
323         tcase_add_checked_fixture(tc, test_setup, test_shutdown);
324
325         tcase_add_test(tc, send_fd_to_client);
326         tcase_add_test(tc, ls_send_fd_is_noop_when_fd_is_invalid);
327         suite_add_tcase(s, tc);
328 }
329
330 int main(void)
331 {
332         int number_failed;
333         Suite *s;
334         SRunner *sr;
335
336         s = suite_create("DLM lease server tests");
337
338         add_error_tests(s);
339         add_client_request_tests(s);
340         add_fd_send_tests(s);
341
342         sr = srunner_create(s);
343
344         srunner_run_all(sr, CK_NORMAL);
345         number_failed = srunner_ntests_failed(sr);
346         srunner_free(sr);
347         return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
348 }