lease-server-test: Destroy server on shutdown
[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 /************** Test fixutre functions *************************/
32 struct test_config default_test_config;
33
34 #define TEST_LEASE_NAME "test-lease"
35
36 static struct lease_handle test_lease = {
37     .name = TEST_LEASE_NAME,
38 };
39
40 static void test_setup(void)
41 {
42         dlm_log_enable_debug(true);
43         setenv("DLM_RUNTIME_PATH", SOCKETDIR, 1);
44
45         default_test_config = (struct test_config){
46             .lease = &test_lease,
47         };
48 }
49
50 static void test_shutdown(void)
51 {
52         test_config_cleanup(&default_test_config);
53 }
54
55 static struct ls *create_default_server(void)
56 {
57         struct lease_handle *leases[] = {
58             &test_lease,
59         };
60         struct ls *ls = ls_create(leases, 1);
61         ck_assert_ptr_ne(ls, NULL);
62         return ls;
63 }
64
65 /**************  Lease server error handling tests *************/
66
67 /* duplicate_server_failure
68  *
69  * Test details: Try to intialize the same server twice
70  * Expected results: ls_create() fails.
71  */
72 START_TEST(duplicate_server_failure)
73 {
74         struct lease_handle *leases[] = {&test_lease, &test_lease};
75         struct ls *ls = ls_create(leases, 2);
76         ck_assert_ptr_eq(ls, NULL);
77 }
78 END_TEST
79
80 START_TEST(long_lease_name_failure)
81 {
82         char long_lease_name[200];
83
84         size_t len = sizeof(long_lease_name) - 1;
85         memset(long_lease_name, 'a', len);
86         long_lease_name[len] = '\0';
87
88         struct lease_handle long_name_lease = {.name = long_lease_name};
89
90         struct lease_handle *leases[] = {&long_name_lease};
91         struct ls *ls = ls_create(leases, 1);
92         ck_assert_ptr_eq(ls, NULL);
93 }
94 END_TEST
95
96 static void add_error_tests(Suite *s)
97 {
98         TCase *tc = tcase_create("Lease server errors");
99
100         tcase_add_checked_fixture(tc, test_setup, test_shutdown);
101
102         tcase_add_test(tc, duplicate_server_failure);
103         tcase_add_test(tc, long_lease_name_failure);
104         suite_add_tcase(s, tc);
105 }
106
107 /**************  Client request handling tests ************/
108
109 /* Test the handling of client requests.  Make sure that the
110  * proper struct ls_req are generated for each client request.
111  */
112
113 static void check_request(struct ls_req *req,
114                           struct lease_handle *expected_lease,
115                           enum ls_req_type expected_type)
116 {
117         ck_assert_ptr_eq(req->lease_handle, expected_lease);
118         ck_assert_int_eq(req->type, expected_type);
119 }
120
121 static void get_and_check_request(struct ls *ls,
122                                   struct lease_handle *expected_lease,
123                                   enum ls_req_type expected_type)
124 {
125         struct ls_req req;
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);
129 }
130
131 /* Asynchronous version of the above.  Has the extra overhead of
132  * spawning a new thread, so should be used sparingly. */
133 struct async_req {
134         pthread_t tid;
135         struct ls *ls;
136
137         bool req_valid;
138         struct ls_req expected;
139         struct ls_req actual;
140 };
141
142 static void *get_request_thread(void *arg)
143 {
144         struct async_req *async_req = arg;
145         async_req->req_valid =
146             ls_get_request(async_req->ls, &async_req->actual);
147
148         return NULL;
149 }
150
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)
154
155 {
156         struct async_req *req = malloc(sizeof(struct async_req));
157         ck_assert_ptr_ne(req, NULL);
158
159         *req = (struct async_req){
160             .ls = ls,
161             .expected =
162                 {
163                     .lease_handle = expected_lease,
164                     .type = expected_type,
165                 },
166         };
167
168         int ret = pthread_create(&req->tid, NULL, get_request_thread, req);
169         ck_assert_int_eq(ret, 0);
170
171         return req;
172 }
173
174 static void check_async_req_result(struct async_req *req)
175 {
176
177         pthread_join(req->tid, NULL);
178         ck_assert_int_eq(req->req_valid, true);
179         check_request(&req->actual, req->expected.lease_handle,
180                       req->expected.type);
181         free(req);
182 }
183
184 /* issue_lease_request_and_release
185  *
186  * Test details: Generate a lease request and lease release command from
187  *               a client.
188  * Expected results: One get lease and one release lease request are returned
189  *                   from ls_get_request().
190  */
191 START_TEST(issue_lease_request_and_release)
192 {
193         struct ls *ls = create_default_server();
194
195         struct client_state *cstate = test_client_start(&default_test_config);
196
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);
200         ls_destroy(ls);
201 }
202 END_TEST
203
204 /* issue_lease_request_and_early_release
205  *
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.
210  */
211 START_TEST(issue_lease_request_and_early_release)
212 {
213         struct ls *ls = create_default_server();
214
215         struct client_state *cstate = test_client_start(&default_test_config);
216
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);
220         ls_destroy(ls);
221 }
222 END_TEST
223
224 /* issue_multiple_lease_requests
225  *
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).
232  */
233 START_TEST(issue_multiple_lease_requests)
234 {
235         struct lease_handle *leases[] = {
236             &test_lease,
237         };
238         struct ls *ls = ls_create(leases, 1);
239
240         struct test_config accepted_config;
241         struct client_state *accepted_cstate;
242
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);
246
247         /*Try to make additional connections while the first is still
248          *connected. */
249         const int nextra_clients = 2;
250         struct test_config extra_configs[nextra_clients];
251         struct client_state *extra_cstates[nextra_clients];
252
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]);
256         }
257
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);
261
262         for (int i = 0; i < nextra_clients; i++) {
263                 test_client_stop(extra_cstates[i]);
264         }
265
266         /* Release the first connection and check results */
267         test_client_stop(accepted_cstate);
268         check_async_req_result(async_release_req);
269
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);
274         ls_destroy(ls);
275 }
276 END_TEST
277
278 static void add_client_request_tests(Suite *s)
279 {
280         TCase *tc = tcase_create("Client request testing");
281
282         tcase_add_checked_fixture(tc, test_setup, test_shutdown);
283
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);
288 }
289
290 /**************  File descriptor sending tests ************/
291
292 /* Test the sending (and failure to send) of file descriptors
293  * to the client.
294  */
295
296 /* send_fd_to_client
297  *
298  * Test details: Send a valid fd to a given client.
299  * Expected results: The correct fd is successfully sent.
300  */
301 START_TEST(send_fd_to_client)
302 {
303         struct ls *ls = create_default_server();
304
305         struct client_state *cstate = test_client_start(&default_test_config);
306
307         struct ls_req req;
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);
311
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);
315
316         test_client_stop(cstate);
317         get_and_check_request(ls, &test_lease, LS_REQ_RELEASE_LEASE);
318
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);
322         ls_destroy(ls);
323 }
324 END_TEST
325
326 /* ls_send_fd_is_noop_when_fd_is_invalid
327  *
328  * Test details: Call ls_send_fd() with an invalid  fd.
329  * Expected results: No fd is sent to client.  The connection to the
330  *                   client is closed.
331  */
332 START_TEST(ls_send_fd_is_noop_when_fd_is_invalid)
333 {
334         struct ls *ls = create_default_server();
335
336         struct client_state *cstate = test_client_start(&default_test_config);
337
338         struct ls_req req;
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);
342
343         int invalid_fd = get_dummy_fd();
344         close(invalid_fd);
345
346         ck_assert_int_eq(ls_send_fd(ls, req.server, invalid_fd), false);
347
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);
352         ls_destroy(ls);
353 }
354 END_TEST
355
356 static void add_fd_send_tests(Suite *s)
357 {
358         TCase *tc = tcase_create("File descriptor sending tests");
359
360         tcase_add_checked_fixture(tc, test_setup, test_shutdown);
361
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);
365 }
366
367 int main(void)
368 {
369         int number_failed;
370         Suite *s;
371         SRunner *sr;
372
373         s = suite_create("DLM lease server tests");
374
375         add_error_tests(s);
376         add_client_request_tests(s);
377         add_fd_send_tests(s);
378
379         sr = srunner_create(s);
380
381         srunner_run_all(sr, CK_NORMAL);
382         number_failed = srunner_ntests_failed(sr);
383         srunner_free(sr);
384         return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
385 }