Skip to content

Commit 511fdf8

Browse files
committed
CP-54481: support DMV RPU plugin
add unit test for DMV code Signed-off-by: Chunjie Zhu <chunjie.zhu@cloud.com>
1 parent 2bb35de commit 511fdf8

File tree

1 file changed

+197
-0
lines changed

1 file changed

+197
-0
lines changed

tests/test_dmv.py

Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
"""tests/test_dmv.py: Unit test for xcp/dmv.py"""
2+
import unittest
3+
from unittest import mock
4+
import types
5+
import json
6+
import errno
7+
from xcp import dmv
8+
9+
10+
class TestDMV(unittest.TestCase):
11+
@mock.patch("os.listdir")
12+
def test_get_all_kabi_dirs(self, m_listdir):
13+
m_listdir.return_value = ["4.19.0", "5.10.0"]
14+
dirs = dmv.get_all_kabi_dirs()
15+
self.assertIn(("4.19.0", "/lib/modules/4.19.0/updates", "/lib/modules/4.19.0/dmv"), dirs)
16+
self.assertIn(("5.10.0", "/lib/modules/5.10.0/updates", "/lib/modules/5.10.0/dmv"), dirs)
17+
18+
def test_note_offset(self):
19+
self.assertEqual(dmv.note_offset(1), 3)
20+
self.assertEqual(dmv.note_offset(4), 0)
21+
self.assertEqual(dmv.note_offset(5), 3)
22+
23+
def test_id_matches(self):
24+
self.assertTrue(dmv.id_matches("*", "1234"))
25+
self.assertTrue(dmv.id_matches("1234", "*"))
26+
self.assertTrue(dmv.id_matches("1234", "1234"))
27+
self.assertFalse(dmv.id_matches("1234", "5678"))
28+
29+
def test_pci_matches_true(self):
30+
present = {"vendor": "14e4", "device": "163c", "subvendor": "*", "subdevice": "*"}
31+
driver_pci_ids = {
32+
"abc.ko": [
33+
{"vendor_id": "14e4", "device_id": "163c", "subvendor_id": "*", "subdevice_id": "*"}
34+
]
35+
}
36+
self.assertTrue(dmv.pci_matches(present, driver_pci_ids))
37+
38+
def test_pci_matches_false(self):
39+
present = {"vendor": "abcd", "device": "9999", "subvendor": "*", "subdevice": "*"}
40+
driver_pci_ids = {
41+
"abc.ko": [
42+
{"vendor_id": "14e4", "device_id": "163c", "subvendor_id": "*", "subdevice_id": "*"}
43+
]
44+
}
45+
self.assertFalse(dmv.pci_matches(present, driver_pci_ids))
46+
47+
@mock.patch("re.compile")
48+
def test_hardware_present_true(self, m_compile):
49+
m = mock.Mock()
50+
m.finditer.return_value = [
51+
mock.Mock(groupdict=lambda: {"vendor": "14e4", "device": "163c", "subvendor": "*", "subdevice": "*"})
52+
]
53+
m_compile.return_value = m
54+
pci_ids = {
55+
"abc.ko": [
56+
{"vendor_id": "14e4", "device_id": "163c", "subvendor_id": "*", "subdevice_id": "*"}
57+
]
58+
}
59+
self.assertTrue(dmv.hardware_present("dummy", pci_ids))
60+
61+
@mock.patch("re.compile")
62+
def test_hardware_present_false(self, m_compile):
63+
m = mock.Mock()
64+
m.finditer.return_value = [
65+
mock.Mock(groupdict=lambda: {"vendor": "abcd", "device": "9999", "subvendor": "*", "subdevice": "*"})
66+
]
67+
m_compile.return_value = m
68+
pci_ids = {
69+
"abc.ko": [
70+
{"vendor_id": "14e4", "device_id": "163c", "subvendor_id": "*", "subdevice_id": "*"}
71+
]
72+
}
73+
self.assertFalse(dmv.hardware_present("dummy", pci_ids))
74+
75+
@mock.patch("os.path.islink")
76+
@mock.patch("os.path.realpath")
77+
@mock.patch("os.path.dirname")
78+
@mock.patch("builtins.open", new_callable=mock.mock_open, read_data='{"variant": "v1"}')
79+
@mock.patch("json.load")
80+
def test_variant_selected(self, m_json_load, m_open, m_dirname, m_realpath, m_islink):
81+
m_islink.return_value = True
82+
m_realpath.return_value = "/some/dir"
83+
m_dirname.return_value = "/some/dir"
84+
m_json_load.return_value = {"variant": "v1"}
85+
result = dmv.variant_selected(["foo.ko"], "/updates")
86+
self.assertEqual(result, "v1")
87+
88+
@mock.patch("os.path.isfile")
89+
@mock.patch("builtins.open", new_callable=mock.mock_open)
90+
@mock.patch("struct.calcsize")
91+
@mock.patch("struct.unpack")
92+
def test_get_active_variant(self, m_unpack, m_calcsize, m_open, m_isfile):
93+
m_isfile.return_value = True
94+
m_calcsize.return_value = 12
95+
m_unpack.return_value = (9, 3, 1)
96+
fake_file = mock.Mock()
97+
fake_file.read.side_effect = [
98+
b"x"*12, # header
99+
b"", # offset
100+
b"XenServer", b"", b"v1\x00", b"", # vendor, offset, content, offset
101+
]
102+
m_open.return_value.__enter__.return_value = fake_file
103+
result = dmv.get_active_variant(["foo.ko"])
104+
self.assertEqual(result, "v1")
105+
106+
@mock.patch("os.path.isfile")
107+
def test_get_loaded_modules(self, m_isfile):
108+
m_isfile.side_effect = lambda path: "foo" in path
109+
result = dmv.get_loaded_modules(["foo.ko", "bar.ko"])
110+
self.assertEqual(result, ["foo.ko"])
111+
112+
@mock.patch("os.path.islink")
113+
@mock.patch("os.path.realpath")
114+
@mock.patch("os.path.dirname")
115+
@mock.patch("builtins.open", new_callable=mock.mock_open, read_data='{"variant": "v1"}')
116+
@mock.patch("json.load")
117+
def test_variant_selected(self, m_json_load, m_open, m_dirname, m_realpath, m_islink):
118+
m_islink.return_value = True
119+
m_realpath.return_value = "/some/dir"
120+
m_dirname.return_value = "/some/dir"
121+
m_json_load.return_value = {"variant": "v1"}
122+
d = dmv.DriverMultiVersion("/updates", None)
123+
result = d.variant_selected(["foo.ko"])
124+
self.assertEqual(result, "v1")
125+
126+
@mock.patch("xcp.dmv.open_with_codec_handling")
127+
@mock.patch("xcp.dmv.hardware_present")
128+
def test_parse_dmv_info(self, m_hw_present, m_open_codec):
129+
m_hw_present.return_value = True
130+
info_json = {
131+
"category": "net",
132+
"name": "foo",
133+
"description": "desc",
134+
"variant": "v1",
135+
"version": "1.0",
136+
"priority": 1,
137+
"status": "ok",
138+
"pci_ids": {
139+
"foo.ko": [
140+
{"vendor_id": "14e4", "device_id": "163c", "subvendor_id": "*", "subdevice_id": "*"}
141+
]
142+
}
143+
}
144+
m_open_codec.return_value.__enter__.return_value = mock.Mock(
145+
spec=["read"], read=lambda: json.dumps(info_json)
146+
)
147+
with mock.patch("json.load", return_value=info_json):
148+
lspci_out = types.SimpleNamespace(stdout="dummy")
149+
d = dmv.DriverMultiVersion("", lspci_out)
150+
json_data, json_formatted = d.parse_dmv_info("dummy")
151+
self.assertEqual(json_data["name"], "foo")
152+
self.assertEqual(json_formatted["type"], "net")
153+
self.assertTrue(json_formatted["variants"]["v1"]["hardware_present"])
154+
155+
def test_merge_jsondata(self):
156+
mgr = dmv.DriverMultiVersionManager(runtime=True)
157+
oldone = {
158+
"type": "net",
159+
"friendly_name": "foo",
160+
"description": "desc",
161+
"info": "foo",
162+
"variants": {"v1": {"version": "1.0"}},
163+
"selected": "v1",
164+
"active": "v1",
165+
"loaded modules": ["foo.ko"]
166+
}
167+
newone = {
168+
"type": "net",
169+
"friendly_name": "foo",
170+
"description": "desc",
171+
"info": "foo",
172+
"variants": {"v2": {"version": "2.0"}},
173+
"selected": None,
174+
"active": None,
175+
"loaded modules": ["bar.ko"]
176+
}
177+
mgr.merge_jsondata(oldone, newone)
178+
merged = mgr.dmv_list["drivers"]["foo"]
179+
self.assertIn("v1", merged["variants"])
180+
self.assertIn("v2", merged["variants"])
181+
self.assertEqual(merged["selected"], "v1")
182+
self.assertEqual(merged["active"], "v1")
183+
self.assertEqual(merged["loaded modules"], ["foo.ko", "bar.ko"])
184+
185+
def test_process_dmv_data(self):
186+
mgr = dmv.DriverMultiVersionManager()
187+
json_data = {"name": "foo"}
188+
json_formatted = {"type": "net"}
189+
mgr.process_dmv_data(json_data, json_formatted)
190+
self.assertEqual(mgr.dmv_list["drivers"]["foo"], json_formatted)
191+
192+
def test_get_set_error(self):
193+
mgr = dmv.DriverMultiVersionManager()
194+
mgr.set_dmv_error(errno.ENOENT)
195+
err = mgr.get_dmv_error()
196+
self.assertEqual(err["exit_code"], errno.ENOENT)
197+
self.assertIn("No such file", err["message"])

0 commit comments

Comments
 (0)