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.
21 #include <xf86drmMode.h>
23 #include "lease-manager.h"
25 #include "test-drm-device.h"
26 #include "test-helpers.h"
28 #define INVALID_OBJECT_ID (0)
30 /* CHECK_LEASE_OBJECTS
32 * Checks the list of objects associated with a given lease_index.
33 * Asks the lease manager to create the lease, and checks that
34 * the requested objects are the ones given in the supplied list. */
36 #define CHECK_LEASE_OBJECTS(lease, ...) \
38 lm_lease_grant(g_lm, lease); \
39 uint32_t objs[] = {__VA_ARGS__}; \
40 int nobjs = ARRAY_LEN(objs); \
41 ck_assert_int_eq(drmModeCreateLease_fake.arg2_val, nobjs); \
42 check_uint_array_eq(drmModeCreateLease_fake.arg1_val, objs, \
46 /************** Mock functions *************/
49 FAKE_VALUE_FUNC(drmModeResPtr, drmModeGetResources, int);
50 FAKE_VOID_FUNC(drmModeFreeResources, drmModeResPtr);
51 FAKE_VALUE_FUNC(drmModePlaneResPtr, drmModeGetPlaneResources, int);
52 FAKE_VOID_FUNC(drmModeFreePlaneResources, drmModePlaneResPtr);
54 FAKE_VALUE_FUNC(drmModePlanePtr, drmModeGetPlane, int, uint32_t);
55 FAKE_VOID_FUNC(drmModeFreePlane, drmModePlanePtr);
56 FAKE_VALUE_FUNC(drmModeConnectorPtr, drmModeGetConnector, int, uint32_t);
57 FAKE_VOID_FUNC(drmModeFreeConnector, drmModeConnectorPtr);
58 FAKE_VALUE_FUNC(drmModeEncoderPtr, drmModeGetEncoder, int, uint32_t);
59 FAKE_VOID_FUNC(drmModeFreeEncoder, drmModeEncoderPtr);
61 FAKE_VALUE_FUNC(int, drmModeCreateLease, int, const uint32_t *, int, int,
63 FAKE_VALUE_FUNC(int, drmModeRevokeLease, int, uint32_t);
65 /************** Test fixutre functions *************************/
66 struct lm *g_lm = NULL;
68 static void test_setup(void)
70 RESET_FAKE(drmModeGetResources);
71 RESET_FAKE(drmModeFreeResources);
72 RESET_FAKE(drmModeGetPlaneResources);
73 RESET_FAKE(drmModeFreePlaneResources);
75 RESET_FAKE(drmModeGetPlane);
76 RESET_FAKE(drmModeFreePlane);
77 RESET_FAKE(drmModeGetConnector);
78 RESET_FAKE(drmModeFreeConnector);
79 RESET_FAKE(drmModeGetEncoder);
80 RESET_FAKE(drmModeFreeEncoder);
82 RESET_FAKE(drmModeCreateLease);
83 RESET_FAKE(drmModeRevokeLease);
85 drmModeGetResources_fake.return_val = TEST_DEVICE_RESOURCES;
86 drmModeGetPlaneResources_fake.return_val = TEST_DEVICE_PLANE_RESOURCES;
88 drmModeGetPlane_fake.custom_fake = get_plane;
89 drmModeGetConnector_fake.custom_fake = get_connector;
90 drmModeGetEncoder_fake.custom_fake = get_encoder;
91 drmModeCreateLease_fake.custom_fake = create_lease;
93 ck_assert_msg(g_lm == NULL,
94 "Lease manager context not clear at start of test");
97 static void test_shutdown(void)
99 reset_drm_test_device();
104 static struct lease_handle **create_leases(int num_leases,
105 struct lease_config *configs)
109 lm_create_with_config(TEST_DRM_DEVICE, num_leases, configs);
111 g_lm = lm_create(TEST_DRM_DEVICE);
113 ck_assert_ptr_ne(g_lm, NULL);
115 struct lease_handle **handles;
116 ck_assert_int_eq(num_leases, lm_get_lease_handles(g_lm, &handles));
117 ck_assert_ptr_ne(handles, NULL);
122 /************** Resource enumeration tests *************/
124 /* These tests verify that the lease manager correctly assigns
125 * DRM resources to thier respective leases. In some cases
126 * the lease manager must choose which resources to include in
127 * each lease, so these tests verify that a valid (but not
128 * necessarily optimal) choice is made.
131 /* all_outputs_connected
133 * Test details: Create leases when all crtc/encoder/connector paths are
136 * Expected results: Leases are created for the currently connected sets of
139 START_TEST(all_outputs_connected)
141 int out_cnt = 2, plane_cnt = 0;
143 setup_layout_simple_test_device(out_cnt, plane_cnt);
145 struct lease_handle **handles = create_leases(out_cnt, NULL);
147 CHECK_LEASE_OBJECTS(handles[0], CRTC_ID(0), CONNECTOR_ID(0));
148 CHECK_LEASE_OBJECTS(handles[1], CRTC_ID(1), CONNECTOR_ID(1));
152 /* no_outputs_connected
154 * Test details: Create leases when no crtc/encoder/connector paths are
157 * Expected results: Available resources are divided between the leases.
158 * The same resource should not appear in multiple leases.
160 START_TEST(no_outputs_connected)
162 int out_cnt = 2, plane_cnt = 0;
165 setup_drm_test_device(out_cnt, out_cnt, out_cnt, plane_cnt), true);
167 drmModeConnector connectors[] = {
168 CONNECTOR(CONNECTOR_ID(0), 0, &ENCODER_ID(0), 1),
169 CONNECTOR(CONNECTOR_ID(1), 0, &ENCODER_ID(1), 1),
172 drmModeEncoder encoders[] = {
173 ENCODER(ENCODER_ID(0), 0, 0x2),
174 ENCODER(ENCODER_ID(1), 0, 0x3),
177 setup_test_device_layout(connectors, encoders, NULL);
179 g_lm = lm_create(TEST_DRM_DEVICE);
180 ck_assert_ptr_ne(g_lm, NULL);
182 struct lease_handle **handles = create_leases(out_cnt, NULL);
184 CHECK_LEASE_OBJECTS(handles[0], CRTC_ID(1), CONNECTOR_ID(0));
185 CHECK_LEASE_OBJECTS(handles[1], CRTC_ID(0), CONNECTOR_ID(1));
189 /* some_outputs_connected */
190 /* Test details: Create leases when one output is connected and one is not.
191 * Expected results: Currently connected resources should be added to
193 * The non-connected resources should be added to a second
196 START_TEST(some_outputs_connected)
198 int out_cnt = 2, plane_cnt = 0;
201 setup_drm_test_device(out_cnt, out_cnt, out_cnt, plane_cnt), true);
203 drmModeConnector connectors[] = {
204 CONNECTOR(CONNECTOR_ID(0), ENCODER_ID(0), &ENCODER_ID(0), 1),
205 CONNECTOR(CONNECTOR_ID(1), 0, &ENCODER_ID(1), 1),
208 drmModeEncoder encoders[] = {
209 ENCODER(ENCODER_ID(0), CRTC_ID(0), 0x3),
210 ENCODER(ENCODER_ID(1), 0, 0x3),
213 setup_test_device_layout(connectors, encoders, NULL);
215 struct lease_handle **handles = create_leases(out_cnt, NULL);
217 CHECK_LEASE_OBJECTS(handles[0], CRTC_ID(0), CONNECTOR_ID(0));
218 CHECK_LEASE_OBJECTS(handles[1], CRTC_ID(1), CONNECTOR_ID(1));
222 /* fewer_crtcs_than_connectors */
223 /* Test details: Create leases on a system with more connectors than CRTCs
224 * Expected results: Number of leases generated should correspond to number of
226 * Leases contain one valid connector for each CRTC.
228 START_TEST(fewer_crtcs_than_connectors)
230 int out_cnt = 3, plane_cnt = 0, crtc_cnt = 2;
233 setup_drm_test_device(crtc_cnt, out_cnt, out_cnt, plane_cnt), true);
235 drmModeConnector connectors[] = {
236 CONNECTOR(CONNECTOR_ID(0), 0, &ENCODER_ID(0), 1),
237 CONNECTOR(CONNECTOR_ID(1), 0, &ENCODER_ID(1), 1),
238 CONNECTOR(CONNECTOR_ID(2), 0, &ENCODER_ID(2), 1),
241 drmModeEncoder encoders[] = {
242 ENCODER(ENCODER_ID(0), 0, 0x3),
243 ENCODER(ENCODER_ID(1), 0, 0x1),
244 ENCODER(ENCODER_ID(2), 0, 0x3),
247 setup_test_device_layout(connectors, encoders, NULL);
249 struct lease_handle **handles = create_leases(crtc_cnt, NULL);
251 CHECK_LEASE_OBJECTS(handles[0], CRTC_ID(0), CONNECTOR_ID(0));
252 CHECK_LEASE_OBJECTS(handles[1], CRTC_ID(1), CONNECTOR_ID(2));
256 /* separate_overlay_planes_by_crtc */
257 /* Test details: Add overlay planes to leases. Each plane is tied to a
259 * Expected results: The leases contain all of the planes for connected to
260 * each CRTC and no others.
262 START_TEST(separate_overlay_planes_by_crtc)
265 int out_cnt = 2, plane_cnt = 3;
267 setup_layout_simple_test_device(out_cnt, plane_cnt);
269 struct lease_handle **handles = create_leases(out_cnt, NULL);
271 CHECK_LEASE_OBJECTS(handles[0], PLANE_ID(0), PLANE_ID(2), CRTC_ID(0),
273 CHECK_LEASE_OBJECTS(handles[1], PLANE_ID(1), CRTC_ID(1),
278 /* reject_planes_shared_between_multiple_crtcs */
279 /* Test details: Add overlay planes to leases. Some planes are shared between
281 * Expected results: The leases contain all of the unique planes for each CRTC.
282 * Planes that can be used on multiple CRTCs are not included
285 START_TEST(reject_planes_shared_between_multiple_crtcs)
288 int out_cnt = 2, plane_cnt = 3;
291 setup_drm_test_device(out_cnt, out_cnt, out_cnt, plane_cnt), true);
293 drmModeConnector connectors[] = {
294 CONNECTOR(CONNECTOR_ID(0), ENCODER_ID(0), &ENCODER_ID(0), 1),
295 CONNECTOR(CONNECTOR_ID(1), ENCODER_ID(1), &ENCODER_ID(1), 1),
298 drmModeEncoder encoders[] = {
299 ENCODER(ENCODER_ID(0), CRTC_ID(0), 0x1),
300 ENCODER(ENCODER_ID(1), CRTC_ID(1), 0x2),
303 drmModePlane planes[] = {
304 PLANE(PLANE_ID(0), 0x2),
305 PLANE(PLANE_ID(1), 0x1),
306 PLANE(PLANE_ID(2), 0x3),
309 setup_test_device_layout(connectors, encoders, planes);
311 struct lease_handle **handles = create_leases(out_cnt, NULL);
313 CHECK_LEASE_OBJECTS(handles[0], PLANE_ID(1), CRTC_ID(0),
315 CHECK_LEASE_OBJECTS(handles[1], PLANE_ID(0), CRTC_ID(1),
320 static void add_connector_enum_tests(Suite *s)
322 TCase *tc = tcase_create("Resource enumeration");
324 tcase_add_checked_fixture(tc, test_setup, test_shutdown);
326 tcase_add_test(tc, all_outputs_connected);
327 tcase_add_test(tc, no_outputs_connected);
328 tcase_add_test(tc, fewer_crtcs_than_connectors);
329 tcase_add_test(tc, some_outputs_connected);
330 tcase_add_test(tc, separate_overlay_planes_by_crtc);
331 tcase_add_test(tc, reject_planes_shared_between_multiple_crtcs);
332 suite_add_tcase(s, tc);
335 /************** Lease management tests *************/
337 /* create_and_revoke_lease */
338 /* Test details: Create leases and revoke them.
339 * Expected results: drmModeRevokeLease() is called with the correct leasee_id.
341 START_TEST(create_and_revoke_lease)
343 int lease_cnt = 2, plane_cnt = 0;
345 setup_layout_simple_test_device(lease_cnt, plane_cnt);
347 struct lease_handle **handles = create_leases(lease_cnt, NULL);
349 for (int i = 0; i < lease_cnt; i++) {
350 ck_assert_int_ge(lm_lease_grant(g_lm, handles[i]), 0);
351 lm_lease_revoke(g_lm, handles[i]);
354 ck_assert_int_eq(drmModeRevokeLease_fake.call_count, lease_cnt);
356 for (int i = 0; i < lease_cnt; i++) {
357 ck_assert_int_eq(drmModeRevokeLease_fake.arg1_history[i],
363 /* Test lease names */
364 /* Test details: Create some leases and verify that they have the correct names
365 * Expected results: lease names should match the expected values
367 START_TEST(verify_lease_names)
370 bool res = setup_drm_test_device(lease_cnt, lease_cnt, lease_cnt, 0);
371 ck_assert_int_eq(res, true);
373 drmModeConnector connectors[] = {
374 CONNECTOR_FULL(CONNECTOR_ID(0), ENCODER_ID(0), &ENCODER_ID(0), 1,
375 DRM_MODE_CONNECTOR_HDMIA, 1),
376 CONNECTOR_FULL(CONNECTOR_ID(1), ENCODER_ID(1), &ENCODER_ID(1), 1,
377 DRM_MODE_CONNECTOR_LVDS, 3),
378 CONNECTOR_FULL(CONNECTOR_ID(2), ENCODER_ID(2), &ENCODER_ID(2), 1,
379 DRM_MODE_CONNECTOR_eDP, 6),
382 drmModeEncoder encoders[] = {
383 ENCODER(ENCODER_ID(0), CRTC_ID(0), 0x7),
384 ENCODER(ENCODER_ID(1), CRTC_ID(1), 0x7),
385 ENCODER(ENCODER_ID(2), CRTC_ID(2), 0x7),
388 setup_test_device_layout(connectors, encoders, NULL);
390 const char *expected_names[] = {
396 struct lease_handle **handles = create_leases(lease_cnt, NULL);
398 for (int i = 0; i < lease_cnt; i++) {
399 ck_assert_str_eq(handles[i]->name, expected_names[i]);
404 static void add_lease_management_tests(Suite *s)
406 TCase *tc = tcase_create("Lease management");
408 tcase_add_checked_fixture(tc, test_setup, test_shutdown);
410 tcase_add_test(tc, create_and_revoke_lease);
411 tcase_add_test(tc, verify_lease_names);
412 suite_add_tcase(s, tc);
415 /***************** Lease Configuration Tests *************/
417 /* multiple_connector_lease */
418 /* Test details: Create a lease with multipe connectors
419 * Expected results: a lease is created with the CRTC and connector ID for both
422 START_TEST(multiple_connector_lease)
424 int out_cnt = 2, plane_cnt = 0, lease_cnt = 1;
426 setup_layout_simple_test_device(out_cnt, plane_cnt);
428 struct lease_config lconfig = {
429 .lease_name = "Lease Config Test 1",
431 .connector_ids = (uint32_t[]){CONNECTOR_ID(0), CONNECTOR_ID(1)},
434 struct lease_handle **handles = create_leases(lease_cnt, &lconfig);
436 CHECK_LEASE_OBJECTS(handles[0], CRTC_ID(0), CONNECTOR_ID(0), CRTC_ID(1),
441 /* single_failed_lease */
442 /* Test details: Create 2 lease configs. One with valid data, one without.
443 * Expected results: A handle is created for the single valid lease.
445 START_TEST(single_failed_lease)
447 int out_cnt = 3, plane_cnt = 0, success_lease_cnt = 1;
449 setup_layout_simple_test_device(out_cnt, plane_cnt);
451 struct lease_config lconfigs[2] = {
454 .lease_name = "Lease Config Test 1",
456 .connector_ids = (uint32_t[]){INVALID_OBJECT_ID},
460 .lease_name = "Lease Config Test 2",
463 (uint32_t[]){CONNECTOR_ID(0), CONNECTOR_ID(1)},
467 /* Expect fewer leases than configurations supplied, so explicitly
468 * create and check leases. */
469 g_lm = lm_create_with_config(TEST_DRM_DEVICE, ARRAY_LEN(lconfigs),
471 ck_assert_ptr_ne(g_lm, NULL);
473 struct lease_handle **handles;
474 ck_assert_int_eq(success_lease_cnt,
475 lm_get_lease_handles(g_lm, &handles));
476 ck_assert_ptr_ne(handles, NULL);
478 CHECK_LEASE_OBJECTS(handles[0], CRTC_ID(0), CONNECTOR_ID(0), CRTC_ID(1),
483 /* named_connector_config */
484 /* Test details: Test specifying connectors by name in config
485 * Expected results: A handle is created for each named connector
488 START_TEST(named_connector_config)
490 int out_cnt = 2, plane_cnt = 0, lease_cnt = 1;
493 setup_drm_test_device(out_cnt, out_cnt, out_cnt, plane_cnt), true);
495 drmModeConnector connectors[] = {
496 CONNECTOR_FULL(CONNECTOR_ID(0), ENCODER_ID(0), &ENCODER_ID(0), 1,
497 DRM_MODE_CONNECTOR_HDMIA, 1),
498 CONNECTOR_FULL(CONNECTOR_ID(1), ENCODER_ID(1), &ENCODER_ID(1), 1,
499 DRM_MODE_CONNECTOR_VGA, 3),
502 drmModeEncoder encoders[] = {
503 ENCODER(ENCODER_ID(0), CRTC_ID(0), 0x1),
504 ENCODER(ENCODER_ID(1), CRTC_ID(1), 0x2),
507 setup_test_device_layout(connectors, encoders, NULL);
509 struct lease_config lconfig = {
510 .lease_name = "Lease Config Test 1",
513 (struct connector_config[]){
514 {.name = "HDMI-A-1"},
519 struct lease_handle **handles = create_leases(lease_cnt, &lconfig);
521 ck_assert_str_eq(handles[0]->name, lconfig.lease_name);
522 CHECK_LEASE_OBJECTS(handles[0], CRTC_ID(0), CONNECTOR_ID(0), CRTC_ID(1),
527 static void add_lease_config_tests(Suite *s)
529 TCase *tc = tcase_create("Lease configuration");
531 tcase_add_checked_fixture(tc, test_setup, test_shutdown);
533 tcase_add_test(tc, multiple_connector_lease);
534 tcase_add_test(tc, single_failed_lease);
535 tcase_add_test(tc, named_connector_config);
536 suite_add_tcase(s, tc);
545 s = suite_create("DLM lease manager tests");
547 add_connector_enum_tests(s);
548 add_lease_management_tests(s);
549 add_lease_config_tests(s);
551 sr = srunner_create(s);
552 srunner_run_all(sr, CK_NORMAL);
553 number_failed = srunner_ntests_failed(sr);
555 return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;