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 /* CHECK_LEASE_OBJECTS
30 * Checks the list of objects associated with a given lease_index.
31 * Asks the lease manager to create the lease, and checks that
32 * the requested objects are the ones given in the supplied list. */
34 #define CHECK_LEASE_OBJECTS(lease, ...) \
36 lm_lease_grant(lm, lease); \
37 uint32_t objs[] = {__VA_ARGS__}; \
38 int nobjs = ARRAY_LEN(objs); \
39 ck_assert_int_eq(drmModeCreateLease_fake.arg2_val, nobjs); \
40 check_uint_array_eq(drmModeCreateLease_fake.arg1_val, objs, \
44 /************** Mock functions *************/
47 FAKE_VALUE_FUNC(drmModeResPtr, drmModeGetResources, int);
48 FAKE_VOID_FUNC(drmModeFreeResources, drmModeResPtr);
49 FAKE_VALUE_FUNC(drmModePlaneResPtr, drmModeGetPlaneResources, int);
50 FAKE_VOID_FUNC(drmModeFreePlaneResources, drmModePlaneResPtr);
52 FAKE_VALUE_FUNC(drmModePlanePtr, drmModeGetPlane, int, uint32_t);
53 FAKE_VOID_FUNC(drmModeFreePlane, drmModePlanePtr);
54 FAKE_VALUE_FUNC(drmModeConnectorPtr, drmModeGetConnector, int, uint32_t);
55 FAKE_VOID_FUNC(drmModeFreeConnector, drmModeConnectorPtr);
56 FAKE_VALUE_FUNC(drmModeEncoderPtr, drmModeGetEncoder, int, uint32_t);
57 FAKE_VOID_FUNC(drmModeFreeEncoder, drmModeEncoderPtr);
59 FAKE_VALUE_FUNC(int, drmModeCreateLease, int, const uint32_t *, int, int,
61 FAKE_VALUE_FUNC(int, drmModeRevokeLease, int, uint32_t);
63 /************** Test fixutre functions *************************/
65 static void test_setup(void)
67 RESET_FAKE(drmModeGetResources);
68 RESET_FAKE(drmModeFreeResources);
69 RESET_FAKE(drmModeGetPlaneResources);
70 RESET_FAKE(drmModeFreePlaneResources);
72 RESET_FAKE(drmModeGetPlane);
73 RESET_FAKE(drmModeFreePlane);
74 RESET_FAKE(drmModeGetConnector);
75 RESET_FAKE(drmModeFreeConnector);
76 RESET_FAKE(drmModeGetEncoder);
77 RESET_FAKE(drmModeFreeEncoder);
79 RESET_FAKE(drmModeCreateLease);
80 RESET_FAKE(drmModeRevokeLease);
82 drmModeGetResources_fake.return_val = TEST_DEVICE_RESOURCES;
83 drmModeGetPlaneResources_fake.return_val = TEST_DEVICE_PLANE_RESOURCES;
85 drmModeGetPlane_fake.custom_fake = get_plane;
86 drmModeGetConnector_fake.custom_fake = get_connector;
87 drmModeGetEncoder_fake.custom_fake = get_encoder;
88 drmModeCreateLease_fake.custom_fake = create_lease;
91 static void test_shutdown(void)
93 reset_drm_test_device();
96 /************** Resource enumeration tests *************/
98 /* These tests verify that the lease manager correctly assigns
99 * DRM resources to thier respective leases. In some cases
100 * the lease manager must choose which resources to include in
101 * each lease, so these tests verify that a valid (but not
102 * necessarily optimal) choice is made.
105 /* all_outputs_connected
107 * Test details: Create leases when all crtc/encoder/connector paths are
110 * Expected results: Leases are created for the currently connected sets of
113 START_TEST(all_outputs_connected)
115 int out_cnt = 2, plane_cnt = 0;
118 setup_drm_test_device(out_cnt, out_cnt, out_cnt, plane_cnt), true);
120 drmModeConnector connectors[] = {
121 CONNECTOR(CONNECTOR_ID(0), ENCODER_ID(0), &ENCODER_ID(0), 1),
122 CONNECTOR(CONNECTOR_ID(1), ENCODER_ID(1), &ENCODER_ID(1), 1),
125 drmModeEncoder encoders[] = {
126 ENCODER(ENCODER_ID(0), CRTC_ID(0), 0x3),
127 ENCODER(ENCODER_ID(1), CRTC_ID(1), 0x2),
130 setup_test_device_layout(connectors, encoders, NULL);
132 struct lm *lm = lm_create(TEST_DRM_DEVICE);
133 ck_assert_ptr_ne(lm, NULL);
135 struct lease_handle **handles;
136 ck_assert_int_eq(out_cnt, lm_get_lease_handles(lm, &handles));
137 ck_assert_ptr_ne(handles, NULL);
139 CHECK_LEASE_OBJECTS(handles[0], CRTC_ID(0), CONNECTOR_ID(0));
140 CHECK_LEASE_OBJECTS(handles[1], CRTC_ID(1), CONNECTOR_ID(1));
146 /* no_outputs_connected
148 * Test details: Create leases when no crtc/encoder/connector paths are
151 * Expected results: Available resources are divided between the leases.
152 * The same resource should not appear in multiple leases.
154 START_TEST(no_outputs_connected)
156 int out_cnt = 2, plane_cnt = 0;
159 setup_drm_test_device(out_cnt, out_cnt, out_cnt, plane_cnt), true);
161 drmModeConnector connectors[] = {
162 CONNECTOR(CONNECTOR_ID(0), 0, &ENCODER_ID(0), 1),
163 CONNECTOR(CONNECTOR_ID(1), 0, &ENCODER_ID(1), 1),
166 drmModeEncoder encoders[] = {
167 ENCODER(ENCODER_ID(0), 0, 0x2),
168 ENCODER(ENCODER_ID(1), 0, 0x3),
171 setup_test_device_layout(connectors, encoders, NULL);
173 struct lm *lm = lm_create(TEST_DRM_DEVICE);
174 ck_assert_ptr_ne(lm, NULL);
176 struct lease_handle **handles;
177 ck_assert_int_eq(out_cnt, lm_get_lease_handles(lm, &handles));
178 ck_assert_ptr_ne(handles, NULL);
180 CHECK_LEASE_OBJECTS(handles[0], CRTC_ID(1), CONNECTOR_ID(0));
181 CHECK_LEASE_OBJECTS(handles[1], CRTC_ID(0), CONNECTOR_ID(1));
187 /* some_outputs_connected */
188 /* Test details: Create leases when one output is connected and one is not.
189 * Expected results: Currently connected resources should be added to
191 * The non-connected resources should be added to a second
194 START_TEST(some_outputs_connected)
196 int out_cnt = 2, plane_cnt = 0;
199 setup_drm_test_device(out_cnt, out_cnt, out_cnt, plane_cnt), true);
201 drmModeConnector connectors[] = {
202 CONNECTOR(CONNECTOR_ID(0), ENCODER_ID(0), &ENCODER_ID(0), 1),
203 CONNECTOR(CONNECTOR_ID(1), 0, &ENCODER_ID(1), 1),
206 drmModeEncoder encoders[] = {
207 ENCODER(ENCODER_ID(0), CRTC_ID(0), 0x3),
208 ENCODER(ENCODER_ID(1), 0, 0x3),
211 setup_test_device_layout(connectors, encoders, NULL);
213 struct lm *lm = lm_create(TEST_DRM_DEVICE);
214 ck_assert_ptr_ne(lm, NULL);
216 struct lease_handle **handles;
217 ck_assert_int_eq(out_cnt, lm_get_lease_handles(lm, &handles));
218 ck_assert_ptr_ne(handles, NULL);
220 CHECK_LEASE_OBJECTS(handles[0], CRTC_ID(0), CONNECTOR_ID(0));
221 CHECK_LEASE_OBJECTS(handles[1], CRTC_ID(1), CONNECTOR_ID(1));
227 /* fewer_crtcs_than_connectors */
228 /* Test details: Create leases on a system with more connectors than CRTCs
229 * Expected results: Number of leases generated should correspond to number of
231 * Leases contain one valid connector for each CRTC.
233 START_TEST(fewer_crtcs_than_connectors)
235 int out_cnt = 3, plane_cnt = 0, crtc_cnt = 2;
238 setup_drm_test_device(crtc_cnt, out_cnt, out_cnt, plane_cnt), true);
240 drmModeConnector connectors[] = {
241 CONNECTOR(CONNECTOR_ID(0), 0, &ENCODER_ID(0), 1),
242 CONNECTOR(CONNECTOR_ID(1), 0, &ENCODER_ID(1), 1),
243 CONNECTOR(CONNECTOR_ID(2), 0, &ENCODER_ID(2), 1),
246 drmModeEncoder encoders[] = {
247 ENCODER(ENCODER_ID(0), 0, 0x3),
248 ENCODER(ENCODER_ID(1), 0, 0x1),
249 ENCODER(ENCODER_ID(2), 0, 0x3),
252 setup_test_device_layout(connectors, encoders, NULL);
254 struct lm *lm = lm_create(TEST_DRM_DEVICE);
255 ck_assert_ptr_ne(lm, NULL);
257 struct lease_handle **handles;
258 ck_assert_int_eq(lm_get_lease_handles(lm, &handles), crtc_cnt);
259 ck_assert_ptr_ne(handles, NULL);
261 CHECK_LEASE_OBJECTS(handles[0], CRTC_ID(0), CONNECTOR_ID(0));
262 CHECK_LEASE_OBJECTS(handles[1], CRTC_ID(1), CONNECTOR_ID(2));
267 /* separate_overlay_planes_by_crtc */
268 /* Test details: Add overlay planes to leases. Each plane is tied to a
270 * Expected results: The leases contain all of the planes for connected to
271 * each CRTC and no others.
273 START_TEST(separate_overlay_planes_by_crtc)
276 int out_cnt = 2, plane_cnt = 3;
279 setup_drm_test_device(out_cnt, out_cnt, out_cnt, plane_cnt), true);
281 drmModeConnector connectors[] = {
282 CONNECTOR(CONNECTOR_ID(0), ENCODER_ID(0), &ENCODER_ID(0), 1),
283 CONNECTOR(CONNECTOR_ID(1), ENCODER_ID(1), &ENCODER_ID(1), 1),
286 drmModeEncoder encoders[] = {
287 ENCODER(ENCODER_ID(0), CRTC_ID(0), 0x1),
288 ENCODER(ENCODER_ID(1), CRTC_ID(1), 0x2),
291 drmModePlane planes[] = {
292 PLANE(PLANE_ID(0), 0x2),
293 PLANE(PLANE_ID(1), 0x1),
294 PLANE(PLANE_ID(2), 0x2),
297 setup_test_device_layout(connectors, encoders, planes);
299 struct lm *lm = lm_create(TEST_DRM_DEVICE);
300 ck_assert_ptr_ne(lm, NULL);
302 struct lease_handle **handles;
303 ck_assert_int_eq(out_cnt, lm_get_lease_handles(lm, &handles));
304 ck_assert_ptr_ne(handles, NULL);
306 CHECK_LEASE_OBJECTS(handles[0], PLANE_ID(1), CRTC_ID(0),
308 CHECK_LEASE_OBJECTS(handles[1], PLANE_ID(0), PLANE_ID(2), CRTC_ID(1),
314 /* reject_planes_shared_between_multiple_crtcs */
315 /* Test details: Add overlay planes to leases. Some planes are shared between
317 * Expected results: The leases contain all of the unique planes for each CRTC.
318 * Planes that can be used on multiple CRTCs are not included
321 START_TEST(reject_planes_shared_between_multiple_crtcs)
324 int out_cnt = 2, plane_cnt = 3;
327 setup_drm_test_device(out_cnt, out_cnt, out_cnt, plane_cnt), true);
329 drmModeConnector connectors[] = {
330 CONNECTOR(CONNECTOR_ID(0), ENCODER_ID(0), &ENCODER_ID(0), 1),
331 CONNECTOR(CONNECTOR_ID(1), ENCODER_ID(1), &ENCODER_ID(1), 1),
334 drmModeEncoder encoders[] = {
335 ENCODER(ENCODER_ID(0), CRTC_ID(0), 0x1),
336 ENCODER(ENCODER_ID(1), CRTC_ID(1), 0x2),
339 drmModePlane planes[] = {
340 PLANE(PLANE_ID(0), 0x2),
341 PLANE(PLANE_ID(1), 0x1),
342 PLANE(PLANE_ID(2), 0x3),
345 setup_test_device_layout(connectors, encoders, planes);
347 struct lm *lm = lm_create(TEST_DRM_DEVICE);
348 ck_assert_ptr_ne(lm, NULL);
350 struct lease_handle **handles;
351 ck_assert_int_eq(out_cnt, lm_get_lease_handles(lm, &handles));
352 ck_assert_ptr_ne(handles, NULL);
354 CHECK_LEASE_OBJECTS(handles[0], PLANE_ID(1), CRTC_ID(0),
356 CHECK_LEASE_OBJECTS(handles[1], PLANE_ID(0), CRTC_ID(1),
362 static void add_connector_enum_tests(Suite *s)
364 TCase *tc = tcase_create("Resource enumeration");
366 tcase_add_checked_fixture(tc, test_setup, test_shutdown);
368 tcase_add_test(tc, all_outputs_connected);
369 tcase_add_test(tc, no_outputs_connected);
370 tcase_add_test(tc, fewer_crtcs_than_connectors);
371 tcase_add_test(tc, some_outputs_connected);
372 tcase_add_test(tc, separate_overlay_planes_by_crtc);
373 tcase_add_test(tc, reject_planes_shared_between_multiple_crtcs);
374 suite_add_tcase(s, tc);
377 /************** Lease management tests *************/
379 /* create_and_revoke_lease */
380 /* Test details: Create leases and revoke them.
381 * Expected results: drmModeRevokeLease() is called with the correct leasee_id.
383 START_TEST(create_and_revoke_lease)
386 bool res = setup_drm_test_device(lease_cnt, lease_cnt, lease_cnt, 0);
387 ck_assert_int_eq(res, true);
389 drmModeConnector connectors[] = {
390 CONNECTOR(CONNECTOR_ID(0), ENCODER_ID(0), &ENCODER_ID(0), 1),
391 CONNECTOR(CONNECTOR_ID(1), ENCODER_ID(1), &ENCODER_ID(1), 1),
394 drmModeEncoder encoders[] = {
395 ENCODER(ENCODER_ID(0), CRTC_ID(0), 0x1),
396 ENCODER(ENCODER_ID(1), CRTC_ID(1), 0x2),
399 setup_test_device_layout(connectors, encoders, NULL);
401 struct lm *lm = lm_create(TEST_DRM_DEVICE);
402 ck_assert_ptr_ne(lm, NULL);
404 struct lease_handle **handles;
405 ck_assert_int_eq(lease_cnt, lm_get_lease_handles(lm, &handles));
406 ck_assert_ptr_ne(handles, NULL);
408 for (int i = 0; i < lease_cnt; i++) {
409 ck_assert_int_ge(lm_lease_grant(lm, handles[i]), 0);
410 lm_lease_revoke(lm, handles[i]);
413 ck_assert_int_eq(drmModeRevokeLease_fake.call_count, lease_cnt);
415 for (int i = 0; i < lease_cnt; i++) {
416 ck_assert_int_eq(drmModeRevokeLease_fake.arg1_history[i],
422 static void add_lease_management_tests(Suite *s)
424 TCase *tc = tcase_create("Lease management");
426 tcase_add_checked_fixture(tc, test_setup, test_shutdown);
428 tcase_add_test(tc, create_and_revoke_lease);
429 suite_add_tcase(s, tc);
438 s = suite_create("DLM lease manager tests");
440 add_connector_enum_tests(s);
441 add_lease_management_tests(s);
443 sr = srunner_create(s);
444 srunner_run_all(sr, CK_NORMAL);
445 number_failed = srunner_ntests_failed(sr);
447 return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;