Skip to content

Commit abe1890

Browse files
authored
graphics_card: add drm_node field (New) (#2341)
* graphics_card: add `drm_node` field * resource: fix old Python support * resource: add graphics_card drm_node tests * black
1 parent 1440fc9 commit abe1890

2 files changed

Lines changed: 123 additions & 1 deletion

File tree

providers/resource/bin/graphics_card_resource.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,10 @@
2020

2121
import argparse
2222
import collections
23+
from pathlib import Path
2324
import subprocess
2425
import shlex
26+
import sys
2527

2628
from checkbox_support.helpers.slugify import slugify
2729
from checkbox_support.helpers.release_info import get_release_info
@@ -216,6 +218,21 @@ def main():
216218
video_devices[0]["switch_to_cmd"] = switch_cmds[
217219
record["driver"]
218220
][1]
221+
222+
cards = tuple(Path("/sys" + record["path"]).glob("drm/card*"))
223+
if "name" in record and (Path("/dev/") / record["name"]).exists():
224+
# DRM node named in the udev record
225+
record["drm_node"] = Path("/dev/") / record["name"]
226+
elif len(cards) == 1:
227+
# Find the DRM node in device tree
228+
record["drm_node"] = Path("/dev/dri") / cards[0].name
229+
else:
230+
sys.stderr.write(
231+
"Warning: could not find DRM node for device at path "
232+
"{path}\n".format(path=record["path"])
233+
)
234+
record["drm_node"] = ""
235+
219236
# Finally, print the records
220237
for record in video_devices:
221238
items = [

providers/resource/tests/test_graphics_card_resource.py

Lines changed: 106 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,29 @@
1818
# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
1919

2020
import unittest
21-
from unittest.mock import patch
21+
from unittest.mock import patch, MagicMock
22+
from pathlib import Path
23+
from io import StringIO
2224
import graphics_card_resource
2325

2426

2527
class GraphicsCardResourceTests(unittest.TestCase):
2628

29+
def _run_main_with_udev_data(self, udev_data):
30+
"""Helper to run main() with mocked udev data."""
31+
with patch("graphics_card_resource.parse_args") as mock_args, patch(
32+
"graphics_card_resource.subprocess_lines_generator"
33+
) as mock_gen, patch(
34+
"graphics_card_resource.sys.stderr", new_callable=StringIO
35+
) as mock_stderr, patch(
36+
"builtins.print"
37+
):
38+
39+
mock_args.return_value = MagicMock(command="udev_resource.py")
40+
mock_gen.return_value = iter(udev_data)
41+
graphics_card_resource.main()
42+
return mock_stderr.getvalue()
43+
2744
@patch("graphics_card_resource.get_release_info")
2845
def test_compare_ubuntu_release_version(self, mock_release_info):
2946
mock_release_info.return_value = {"release": "24.04"}
@@ -57,6 +74,94 @@ def test_udev_devices_success(self):
5774
self.assertEqual(len(record_list), 1)
5875
self.assertEqual(record_list[0]["pci_device_name"], "0000:01:00.0")
5976

77+
def test_drm_node_from_udev_name(self):
78+
"""Test DRM node detection when name is in udev record."""
79+
udev_data = [
80+
"category: VIDEO",
81+
"path: /devices/pci0000:00/0000:00:02.0",
82+
"name: card0",
83+
"",
84+
]
85+
86+
def path_factory(path_str):
87+
mock_path = MagicMock(spec=Path)
88+
if path_str.startswith("/sys"):
89+
mock_path.glob.return_value = iter([])
90+
elif path_str == "/dev/":
91+
mock_result = MagicMock(spec=Path)
92+
mock_result.exists.return_value = True
93+
mock_path.__truediv__ = MagicMock(return_value=mock_result)
94+
return mock_path
95+
96+
with patch("graphics_card_resource.Path", side_effect=path_factory):
97+
stderr = self._run_main_with_udev_data(udev_data)
98+
self.assertEqual(stderr, "")
99+
100+
def test_drm_node_single_card_in_sysfs(self):
101+
"""Test DRM node detection when exactly one card found in sysfs."""
102+
udev_data = [
103+
"category: VIDEO",
104+
"path: /devices/pci0000:00/0000:00:02.0",
105+
"",
106+
]
107+
108+
mock_card = MagicMock(spec=Path, name="card0")
109+
110+
def path_factory(path_str):
111+
mock_path = MagicMock(spec=Path)
112+
if path_str.startswith("/sys"):
113+
mock_path.glob.return_value = iter([mock_card])
114+
elif path_str == "/dev/dri":
115+
mock_path.__truediv__ = MagicMock(
116+
return_value=MagicMock(spec=Path)
117+
)
118+
return mock_path
119+
120+
with patch("graphics_card_resource.Path", side_effect=path_factory):
121+
stderr = self._run_main_with_udev_data(udev_data)
122+
self.assertEqual(stderr, "")
123+
124+
def test_drm_node_warning_no_cards(self):
125+
"""Test DRM node detection when no cards found (warning case)."""
126+
udev_data = [
127+
"category: VIDEO",
128+
"path: /devices/pci0000:00/0000:00:02.0",
129+
"",
130+
]
131+
132+
def path_factory(path_str):
133+
mock_path = MagicMock(spec=Path)
134+
if path_str.startswith("/sys"):
135+
mock_path.glob.return_value = iter([])
136+
return mock_path
137+
138+
with patch("graphics_card_resource.Path", side_effect=path_factory):
139+
stderr = self._run_main_with_udev_data(udev_data)
140+
self.assertIn("Warning: could not find DRM node", stderr)
141+
self.assertIn("/devices/pci0000:00/0000:00:02.0", stderr)
142+
143+
def test_drm_node_warning_multiple_cards(self):
144+
"""Test DRM node detection when multiple cards found (warning case)."""
145+
udev_data = [
146+
"category: VIDEO",
147+
"path: /devices/pci0000:00/0000:00:02.0",
148+
"",
149+
]
150+
151+
mock_card1 = MagicMock(spec=Path, name="card0")
152+
mock_card2 = MagicMock(spec=Path, name="card1")
153+
154+
def path_factory(path_str):
155+
mock_path = MagicMock(spec=Path)
156+
if path_str.startswith("/sys"):
157+
mock_path.glob.return_value = iter([mock_card1, mock_card2])
158+
return mock_path
159+
160+
with patch("graphics_card_resource.Path", side_effect=path_factory):
161+
stderr = self._run_main_with_udev_data(udev_data)
162+
self.assertIn("Warning: could not find DRM node", stderr)
163+
self.assertIn("/devices/pci0000:00/0000:00:02.0", stderr)
164+
60165

61166
if __name__ == "__main__":
62167
unittest.main()

0 commit comments

Comments
 (0)