Merge lp:~adeuring/launchpad/hwdb-class-udev-device-5 into lp:launchpad/db-devel
- hwdb-class-udev-device-5
- Merge into db-devel
Proposed by
Abel Deuring
Status: | Merged |
---|---|
Approved by: | Gavin Panella |
Approved revision: | no longer in the source branch. |
Merged at revision: | not available |
Proposed branch: | lp:~adeuring/launchpad/hwdb-class-udev-device-5 |
Merge into: | lp:launchpad/db-devel |
Diff against target: |
1059 lines 2 files modified
lib/canonical/launchpad/scripts/hwdbsubmissions.py (+200/-36) lib/canonical/launchpad/scripts/tests/test_hwdb_submission_processing.py (+473/-67) |
To merge this branch: | bzr merge lp:~adeuring/launchpad/hwdb-class-udev-device-5 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Gavin Panella (community) | Approve | ||
Review via email: mp+13350@code.launchpad.net |
Commit message
Description of the change
To post a comment you must log in.
Revision history for this message
Abel Deuring (adeuring) wrote : | # |
Revision history for this message
Gavin Panella (allenap) wrote : | # |
This all looks good.
As discussed on IRC, this is really meant for devel, not db-devel, so
I've attached the diff I actually reviewed.
Gavin.
1 | === modified file 'lib/canonical/launchpad/scripts/hwdbsubmissions.py' |
2 | --- lib/canonical/launchpad/scripts/hwdbsubmissions.py 2009-10-13 21:03:31 +0000 |
3 | +++ lib/canonical/launchpad/scripts/hwdbsubmissions.py 2009-10-14 16:00:26 +0000 |
4 | @@ -87,12 +87,14 @@ |
5 | 'pci': '0x%04x', |
6 | 'usb_device': '0x%04x', |
7 | 'scsi': '%-8s', |
8 | + 'scsi_device': '%-8s', |
9 | } |
10 | |
11 | DB_FORMAT_FOR_PRODUCT_ID = { |
12 | 'pci': '0x%04x', |
13 | 'usb_device': '0x%04x', |
14 | 'scsi': '%-16s', |
15 | + 'scsi_device': '%-16s', |
16 | } |
17 | |
18 | UDEV_USB_DEVICE_PROPERTIES = set(('DEVTYPE', 'PRODUCT', 'TYPE')) |
19 | @@ -1609,6 +1611,11 @@ |
20 | """The name of the driver contolling this device. May be None.""" |
21 | raise NotImplementedError |
22 | |
23 | + @property |
24 | + def scsi_controller(self): |
25 | + """Return the SCSI host controller for this device.""" |
26 | + raise NotImplementedError |
27 | + |
28 | def translateScsiBus(self): |
29 | """Return the real bus of a device where raw_bus=='scsi'. |
30 | |
31 | @@ -1617,37 +1624,27 @@ |
32 | for more details. This method determines the real bus |
33 | of a device accessed via the kernel's SCSI subsystem. |
34 | """ |
35 | - # While SCSI devices from valid submissions should have a |
36 | - # parent and a grandparent, we can't be sure for bogus or |
37 | - # broken submissions. |
38 | - parent = self.parent |
39 | - if parent is None: |
40 | - self.parser._logWarning( |
41 | - 'Found SCSI device without a parent: %s.' % self.device_id) |
42 | - return None |
43 | - grandparent = parent.parent |
44 | - if grandparent is None: |
45 | - self.parser._logWarning( |
46 | - 'Found SCSI device without a grandparent: %s.' |
47 | - % self.device_id) |
48 | + scsi_controller = self.scsi_controller |
49 | + if scsi_controller is None: |
50 | return None |
51 | |
52 | - grandparent_bus = grandparent.raw_bus |
53 | - if grandparent_bus == 'pci': |
54 | - if (grandparent.pci_class != PCI_CLASS_STORAGE): |
55 | + scsi_controller_bus = scsi_controller.raw_bus |
56 | + if scsi_controller_bus == 'pci': |
57 | + if (scsi_controller.pci_class != PCI_CLASS_STORAGE): |
58 | # This is not a storage class PCI device? This |
59 | # indicates a bug somewhere in HAL or in the hwdb |
60 | # client, or a fake submission. |
61 | - device_class = grandparent.pci_class |
62 | + device_class = scsi_controller.pci_class |
63 | self.parser._logWarning( |
64 | 'A (possibly fake) SCSI device %s is connected to ' |
65 | 'PCI device %s that has the PCI device class %s; ' |
66 | 'expected class 1 (storage).' |
67 | - % (self.device_id, grandparent.device_id, device_class)) |
68 | + % (self.device_id, scsi_controller.device_id, |
69 | + device_class)) |
70 | return None |
71 | - pci_subclass = grandparent.pci_subclass |
72 | + pci_subclass = scsi_controller.pci_subclass |
73 | return self.pci_storage_subclass_hwbus.get(pci_subclass) |
74 | - elif grandparent_bus == 'usb': |
75 | + elif scsi_controller_bus == 'usb': |
76 | # USB storage devices have the following HAL device hierarchy: |
77 | # - HAL node for the USB device. info.bus == 'usb_device', |
78 | # device class == 0, device subclass == 0 |
79 | @@ -2357,6 +2354,27 @@ |
80 | """See `BaseDevice`.""" |
81 | return self.getVendorOrProductID('product') |
82 | |
83 | + @property |
84 | + def scsi_controller(self): |
85 | + """See `BaseDevice`.""" |
86 | + # While SCSI devices from valid submissions should have a |
87 | + # parent and a grandparent, we can't be sure for bogus or |
88 | + # broken submissions. |
89 | + if self.raw_bus != 'scsi': |
90 | + return None |
91 | + parent = self.parent |
92 | + if parent is None: |
93 | + self.parser._logWarning( |
94 | + 'Found SCSI device without a parent: %s.' % self.device_id) |
95 | + return None |
96 | + grandparent = parent.parent |
97 | + if grandparent is None: |
98 | + self.parser._logWarning( |
99 | + 'Found SCSI device without a grandparent: %s.' |
100 | + % self.device_id) |
101 | + return None |
102 | + return grandparent |
103 | + |
104 | |
105 | class UdevDevice(BaseDevice): |
106 | """The representation of a udev device node.""" |
107 | @@ -2617,6 +2635,11 @@ |
108 | """See `BaseDevice`.""" |
109 | return self.getVendorOrProductID('product') |
110 | |
111 | + @property |
112 | + def driver_name(self): |
113 | + """See `BaseDevice`.""" |
114 | + return self.udev['E'].get('DRIVER') |
115 | + |
116 | |
117 | class ProcessingLoop(object): |
118 | """An `ITunableLoop` for processing HWDB submissions.""" |
119 | |
120 | === modified file 'lib/canonical/launchpad/scripts/tests/test_hwdb_submission_processing.py' |
121 | --- lib/canonical/launchpad/scripts/tests/test_hwdb_submission_processing.py 2009-10-13 21:02:35 +0000 |
122 | +++ lib/canonical/launchpad/scripts/tests/test_hwdb_submission_processing.py 2009-10-14 16:00:26 +0000 |
123 | @@ -539,6 +539,214 @@ |
124 | 'HAL property info.bus.') |
125 | |
126 | |
127 | + def test_HALDevice_scsi_controller_usb_storage_device(self): |
128 | + """test of HALDevice.scsi_controller. |
129 | + |
130 | + The physical device is a USB storage device. |
131 | + """ |
132 | + devices = [ |
133 | + # The main node of the USB storage device. |
134 | + { |
135 | + 'id': 1, |
136 | + 'udi': self.UDI_USB_STORAGE, |
137 | + 'properties': { |
138 | + 'info.bus': ('usb_device', 'str'), |
139 | + }, |
140 | + }, |
141 | + # The storage interface of the USB device. |
142 | + { |
143 | + 'id': 2, |
144 | + 'udi': self.UDI_USB_STORAGE_IF0, |
145 | + 'properties': { |
146 | + 'info.bus': ('usb', 'str'), |
147 | + 'info.parent': (self.UDI_USB_STORAGE, 'str'), |
148 | + }, |
149 | + }, |
150 | + # The fake SCSI host of the storage device. Note that HAL does |
151 | + # _not_ provide the info.bus property. |
152 | + { |
153 | + 'id': 3, |
154 | + 'udi': self.UDI_USB_STORAGE_SCSI_HOST, |
155 | + 'properties': { |
156 | + 'info.parent': (self.UDI_USB_STORAGE_IF0, 'str'), |
157 | + }, |
158 | + }, |
159 | + # The fake SCSI disk. |
160 | + { |
161 | + 'id': 3, |
162 | + 'udi': self.UDI_USB_STORAGE_SCSI_DEVICE, |
163 | + 'properties': { |
164 | + 'info.bus': ('scsi', 'str'), |
165 | + 'info.parent': (self.UDI_USB_STORAGE_SCSI_HOST, 'str'), |
166 | + }, |
167 | + }, |
168 | + ] |
169 | + parsed_data = { |
170 | + 'hardware': { |
171 | + 'hal': { |
172 | + 'devices': devices, |
173 | + }, |
174 | + }, |
175 | + } |
176 | + |
177 | + parser = SubmissionParser() |
178 | + parser.buildDeviceList(parsed_data) |
179 | + |
180 | + usb_fake_scsi_disk = parser.hal_devices[ |
181 | + self.UDI_USB_STORAGE_SCSI_DEVICE] |
182 | + usb_main_device = parser.hal_devices[self.UDI_USB_STORAGE_IF0] |
183 | + self.assertEqual(usb_main_device, usb_fake_scsi_disk.scsi_controller) |
184 | + |
185 | + def test_HALDevice_scsi_controller_pci_controller(self): |
186 | + """test of HALDevice.scsi_controller. |
187 | + |
188 | + Variant for a SCSI device connected to a PCI controller. |
189 | + """ |
190 | + devices = [ |
191 | + # The PCI host controller. |
192 | + { |
193 | + 'id': 1, |
194 | + 'udi': self.UDI_SATA_CONTROLLER, |
195 | + 'properties': { |
196 | + 'info.bus': ('pci', 'str'), |
197 | + 'pci.device_class': (PCI_CLASS_STORAGE, 'int'), |
198 | + 'pci.device_subclass': (PCI_SUBCLASS_STORAGE_SATA, |
199 | + 'int'), |
200 | + }, |
201 | + }, |
202 | + # The (fake or real) SCSI host of the storage device. |
203 | + { |
204 | + 'id': 2, |
205 | + 'udi': self.UDI_SATA_CONTROLLER_SCSI, |
206 | + 'properties': { |
207 | + 'info.parent': (self.UDI_SATA_CONTROLLER, 'str'), |
208 | + }, |
209 | + }, |
210 | + # The (possibly fake) SCSI disk. |
211 | + { |
212 | + 'id': 3, |
213 | + 'udi': self.UDI_SATA_DISK, |
214 | + 'properties': { |
215 | + 'info.bus': ('scsi', 'str'), |
216 | + 'info.parent': (self.UDI_SATA_CONTROLLER_SCSI, 'str'), |
217 | + }, |
218 | + }, |
219 | + ] |
220 | + parsed_data = { |
221 | + 'hardware': { |
222 | + 'hal': { |
223 | + 'devices': devices, |
224 | + }, |
225 | + }, |
226 | + } |
227 | + |
228 | + parser = SubmissionParser() |
229 | + parser.buildDeviceList(parsed_data) |
230 | + |
231 | + scsi_device = parser.hal_devices[self.UDI_SATA_DISK] |
232 | + controller = parser.hal_devices[self.UDI_SATA_CONTROLLER] |
233 | + self.assertEqual(controller, scsi_device.scsi_controller) |
234 | + |
235 | + def test_HALDevice_scsi_controller_non_scsi_device(self): |
236 | + """test of HALDevice.scsi_controller. |
237 | + |
238 | + Variant for non-SCSI devices. |
239 | + """ |
240 | + devices = [ |
241 | + { |
242 | + 'id': 1, |
243 | + 'udi': self.UDI_COMPUTER, |
244 | + 'properties': {}, |
245 | + }, |
246 | + ] |
247 | + parsed_data = { |
248 | + 'hardware': { |
249 | + 'hal': { |
250 | + 'devices': devices, |
251 | + }, |
252 | + }, |
253 | + } |
254 | + |
255 | + parser = SubmissionParser() |
256 | + parser.buildDeviceList(parsed_data) |
257 | + |
258 | + device = parser.hal_devices[self.UDI_COMPUTER] |
259 | + self.assertEqual(None, device.scsi_controller) |
260 | + |
261 | + def test_HALDevice_scsi_controller_no_grandparent(self): |
262 | + """test of HALDevice.scsi_controller. |
263 | + |
264 | + Variant for a SCSI device without a grandparent device. |
265 | + """ |
266 | + devices = [ |
267 | + # The (fake or real) SCSI host of the storage device. |
268 | + { |
269 | + 'id': 1, |
270 | + 'udi': self.UDI_SATA_CONTROLLER_SCSI, |
271 | + 'properties': {}, |
272 | + }, |
273 | + # The (possibly fake) SCSI disk. |
274 | + { |
275 | + 'id': 2, |
276 | + 'udi': self.UDI_SATA_DISK, |
277 | + 'properties': { |
278 | + 'info.bus': ('scsi', 'str'), |
279 | + 'info.parent': (self.UDI_SATA_CONTROLLER_SCSI, 'str'), |
280 | + }, |
281 | + }, |
282 | + ] |
283 | + parsed_data = { |
284 | + 'hardware': { |
285 | + 'hal': { |
286 | + 'devices': devices, |
287 | + }, |
288 | + }, |
289 | + } |
290 | + |
291 | + parser = SubmissionParser(self.log) |
292 | + parser.submission_key = 'SCSI device without grandparent device' |
293 | + parser.buildDeviceList(parsed_data) |
294 | + |
295 | + scsi_device = parser.hal_devices[self.UDI_SATA_DISK] |
296 | + self.assertEqual(None, scsi_device.scsi_controller) |
297 | + self.assertWarningMessage( |
298 | + parser.submission_key, |
299 | + "Found SCSI device without a grandparent: %s." |
300 | + % self.UDI_SATA_DISK) |
301 | + |
302 | + def test_HALDevice_scsi_controller_no_parent(self): |
303 | + """test of HALDevice.scsi_controller. |
304 | + |
305 | + Variant for a SCSI device without a parent device. |
306 | + """ |
307 | + devices = [ |
308 | + # The (possibly fake) SCSI disk. |
309 | + { |
310 | + 'id': 1, |
311 | + 'udi': self.UDI_SATA_DISK, |
312 | + 'properties': { |
313 | + 'info.bus': ('scsi', 'str'), |
314 | + }, |
315 | + }, |
316 | + ] |
317 | + parsed_data = { |
318 | + 'hardware': { |
319 | + 'hal': { |
320 | + 'devices': devices, |
321 | + }, |
322 | + }, |
323 | + } |
324 | + |
325 | + parser = SubmissionParser(self.log) |
326 | + parser.submission_key = 'SCSI device without parent device' |
327 | + parser.buildDeviceList(parsed_data) |
328 | + |
329 | + scsi_device = parser.hal_devices[self.UDI_SATA_DISK] |
330 | + self.assertEqual(None, scsi_device.scsi_controller) |
331 | + self.assertWarningMessage( |
332 | + parser.submission_key, |
333 | + "Found SCSI device without a parent: %s." % self.UDI_SATA_DISK) |
334 | + |
335 | def testHALDeviceGetRealBus(self): |
336 | """Test of HALDevice.real_bus, generic case. |
337 | |
338 | @@ -2613,6 +2821,7 @@ |
339 | 'PCI_SUBSYS_ID': '10CF:1387', |
340 | 'PCI_SLOT_NAME': '0000:00:1f.2', |
341 | 'SUBSYSTEM': 'pci', |
342 | + 'DRIVER': 'ahci', |
343 | } |
344 | } |
345 | |
346 | @@ -2623,21 +2832,23 @@ |
347 | 'DEVTYPE': 'usb_device', |
348 | 'PRODUCT': '46d/a01/1013', |
349 | 'TYPE': '0/0/0', |
350 | + 'DRIVER': 'usb', |
351 | }, |
352 | } |
353 | |
354 | - scsi_device_data = { |
355 | - 'P': '/devices/pci0000:00/0000:00:1f.1/host4/target4:0:0/4:0:0:0', |
356 | + scsi_scanner_device_data = { |
357 | + 'P': ('/devices/pci0000:00/0000:00:1e.0/0000:08:03.0/0000:09:00.0/' |
358 | + 'host6/target6:0:1/6:0:1:0'), |
359 | 'E': { |
360 | + 'DEVTYPE': 'scsi_device', |
361 | 'SUBSYSTEM': 'scsi', |
362 | - 'DEVTYPE': 'scsi_device', |
363 | }, |
364 | } |
365 | |
366 | - scsi_device_sysfs_data = { |
367 | - 'vendor': 'MATSHITA', |
368 | - 'model': 'DVD-RAM UJ-841S', |
369 | - 'type': '5', |
370 | + scsi_scanner_device_sysfs_data = { |
371 | + 'vendor': 'FUJITSU', |
372 | + 'model': 'fi-5120Cdj', |
373 | + 'type': '6', |
374 | } |
375 | |
376 | no_subsystem_device_data = { |
377 | @@ -2790,7 +3001,8 @@ |
378 | def test_is_scsi_device(self): |
379 | """Test of UdevDevice.is_scsi_device.""" |
380 | device = UdevDevice( |
381 | - None, self.scsi_device_data, self.scsi_device_sysfs_data) |
382 | + None, self.scsi_scanner_device_data, |
383 | + self.scsi_scanner_device_sysfs_data) |
384 | self.assertTrue(device.is_scsi_device) |
385 | |
386 | device = UdevDevice(None, self.root_device) |
387 | @@ -2799,16 +3011,18 @@ |
388 | def test_scsi_vendor(self): |
389 | """Test of UdevDevice.scsi_vendor.""" |
390 | device = UdevDevice( |
391 | - None, self.scsi_device_data, self.scsi_device_sysfs_data, None) |
392 | - self.assertEqual('MATSHITA', device.scsi_vendor) |
393 | + None, self.scsi_scanner_device_data, |
394 | + self.scsi_scanner_device_sysfs_data) |
395 | + self.assertEqual('FUJITSU', device.scsi_vendor) |
396 | device = UdevDevice(None, self.root_device) |
397 | self.assertEqual(None, device.scsi_vendor) |
398 | |
399 | def test_scsi_model(self): |
400 | """Test of UdevDevice.scsi_model.""" |
401 | device = UdevDevice( |
402 | - None, self.scsi_device_data, self.scsi_device_sysfs_data) |
403 | - self.assertEqual('DVD-RAM UJ-841S', device.scsi_model) |
404 | + None, self.scsi_scanner_device_data, |
405 | + self.scsi_scanner_device_sysfs_data) |
406 | + self.assertEqual('fi-5120Cdj', device.scsi_model) |
407 | |
408 | device = UdevDevice(None, self.root_device) |
409 | self.assertEqual(None, device.scsi_model) |
410 | @@ -2847,10 +3061,10 @@ |
411 | self.assertEqual('Unknown', device.getVendorOrProduct('product')) |
412 | |
413 | device = UdevDevice( |
414 | - None, self.scsi_device_data, self.scsi_device_sysfs_data) |
415 | - self.assertEqual('MATSHITA', device.getVendorOrProduct('vendor')) |
416 | - self.assertEqual( |
417 | - 'DVD-RAM UJ-841S', device.getVendorOrProduct('product')) |
418 | + None, self.scsi_scanner_device_data, |
419 | + self.scsi_scanner_device_sysfs_data) |
420 | + self.assertEqual('FUJITSU', device.getVendorOrProduct('vendor')) |
421 | + self.assertEqual('fi-5120Cdj', device.getVendorOrProduct('product')) |
422 | |
423 | device = UdevDevice(None, self.no_subsystem_device_data) |
424 | self.assertEqual(None, device.getVendorOrProduct('vendor')) |
425 | @@ -2888,10 +3102,10 @@ |
426 | self.assertEqual(0xa01, device.getVendorOrProductID('product')) |
427 | |
428 | device = UdevDevice( |
429 | - None, self.scsi_device_data, self.scsi_device_sysfs_data) |
430 | - self.assertEqual('MATSHITA', device.getVendorOrProductID('vendor')) |
431 | - self.assertEqual( |
432 | - 'DVD-RAM UJ-841S', device.getVendorOrProductID('product')) |
433 | + None, self.scsi_scanner_device_data, |
434 | + self.scsi_scanner_device_sysfs_data) |
435 | + self.assertEqual('FUJITSU', device.getVendorOrProductID('vendor')) |
436 | + self.assertEqual('fi-5120Cdj', device.getVendorOrProductID('product')) |
437 | |
438 | device = UdevDevice( |
439 | None, self.no_subsystem_device_data) |
440 | @@ -2910,6 +3124,49 @@ |
441 | None, self.root_device, None, self.root_device_dmi_data) |
442 | self.assertEqual('LIFEBOOK E8210', device.product_id) |
443 | |
444 | + def test_vendor_id_for_db(self): |
445 | + """Test of UdevDevice.vendor_id_for_db.""" |
446 | + device = UdevDevice( |
447 | + None, self.root_device, None, self.root_device_dmi_data) |
448 | + self.assertEqual('FUJITSU SIEMENS', device.vendor_id_for_db) |
449 | + |
450 | + device = UdevDevice(None, self.pci_device_data) |
451 | + self.assertEqual('0x8086', device.vendor_id_for_db) |
452 | + |
453 | + device = UdevDevice(None, self.usb_device_data) |
454 | + self.assertEqual('0x046d', device.vendor_id_for_db) |
455 | + |
456 | + device = UdevDevice( |
457 | + None, self.scsi_scanner_device_data, |
458 | + self.scsi_scanner_device_sysfs_data) |
459 | + self.assertEqual('FUJITSU ', device.vendor_id_for_db) |
460 | + |
461 | + def test_product_id_for_db(self): |
462 | + """Test of UdevDevice.product_id_for_db.""" |
463 | + device = UdevDevice( |
464 | + None, self.root_device, None, self.root_device_dmi_data) |
465 | + self.assertEqual('LIFEBOOK E8210', device.product_id_for_db) |
466 | + |
467 | + device = UdevDevice(None, self.pci_device_data) |
468 | + self.assertEqual('0x27c5', device.product_id_for_db) |
469 | + |
470 | + device = UdevDevice(None, self.usb_device_data) |
471 | + self.assertEqual('0x0a01', device.product_id_for_db) |
472 | + |
473 | + device = UdevDevice( |
474 | + None, self.scsi_scanner_device_data, |
475 | + self.scsi_scanner_device_sysfs_data) |
476 | + self.assertEqual('fi-5120Cdj ', device.product_id_for_db) |
477 | + |
478 | + def test_driver_name(self): |
479 | + """Test of UdevDevice.driver_name.""" |
480 | + device = UdevDevice(None, self.pci_device_data) |
481 | + self.assertEqual('ahci', device.driver_name) |
482 | + |
483 | + device = UdevDevice( |
484 | + None, self.root_device, None, self.root_device_dmi_data) |
485 | + self.assertEqual(None, device.driver_name) |
486 | + |
487 | |
488 | class TestHWDBSubmissionTablePopulation(TestCaseHWDB): |
489 | """Tests of the HWDB popoluation with submitted data.""" |
Revision history for this message
Gavin Panella (allenap) wrote : | # |
review approve
merge approve
review:
Approve
Revision history for this message
Gavin Panella (allenap) wrote : | # |
Review sent by email but not arrived yet... but it's all good :)
review:
Approve
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'lib/canonical/launchpad/scripts/hwdbsubmissions.py' |
2 | --- lib/canonical/launchpad/scripts/hwdbsubmissions.py 2009-10-12 15:36:04 +0000 |
3 | +++ lib/canonical/launchpad/scripts/hwdbsubmissions.py 2009-10-14 15:20:31 +0000 |
4 | @@ -59,6 +59,7 @@ |
5 | re.VERBOSE) |
6 | |
7 | ROOT_UDI = '/org/freedesktop/Hal/devices/computer' |
8 | +UDEV_ROOT_PATH = '/devices/LNXSYSTM:00' |
9 | |
10 | # These UDIs appears in some submissions more than once. |
11 | KNOWN_DUPLICATE_UDIS = set(( |
12 | @@ -86,12 +87,14 @@ |
13 | 'pci': '0x%04x', |
14 | 'usb_device': '0x%04x', |
15 | 'scsi': '%-8s', |
16 | + 'scsi_device': '%-8s', |
17 | } |
18 | |
19 | DB_FORMAT_FOR_PRODUCT_ID = { |
20 | 'pci': '0x%04x', |
21 | 'usb_device': '0x%04x', |
22 | 'scsi': '%-16s', |
23 | + 'scsi_device': '%-16s', |
24 | } |
25 | |
26 | UDEV_USB_DEVICE_PROPERTIES = set(('DEVTYPE', 'PRODUCT', 'TYPE')) |
27 | @@ -1606,6 +1609,12 @@ |
28 | @property |
29 | def driver_name(self): |
30 | """The name of the driver contolling this device. May be None.""" |
31 | + raise NotImplementedError |
32 | + |
33 | + @property |
34 | + def scsi_controller(self): |
35 | + """Return the SCSI host controller for this device.""" |
36 | + raise NotImplementedError |
37 | |
38 | def translateScsiBus(self): |
39 | """Return the real bus of a device where raw_bus=='scsi'. |
40 | @@ -1615,37 +1624,27 @@ |
41 | for more details. This method determines the real bus |
42 | of a device accessed via the kernel's SCSI subsystem. |
43 | """ |
44 | - # While SCSI devices from valid submissions should have a |
45 | - # parent and a grandparent, we can't be sure for bogus or |
46 | - # broken submissions. |
47 | - parent = self.parent |
48 | - if parent is None: |
49 | - self.parser._logWarning( |
50 | - 'Found SCSI device without a parent: %s.' % self.device_id) |
51 | - return None |
52 | - grandparent = parent.parent |
53 | - if grandparent is None: |
54 | - self.parser._logWarning( |
55 | - 'Found SCSI device without a grandparent: %s.' |
56 | - % self.device_id) |
57 | + scsi_controller = self.scsi_controller |
58 | + if scsi_controller is None: |
59 | return None |
60 | |
61 | - grandparent_bus = grandparent.raw_bus |
62 | - if grandparent_bus == 'pci': |
63 | - if (grandparent.pci_class != PCI_CLASS_STORAGE): |
64 | + scsi_controller_bus = scsi_controller.raw_bus |
65 | + if scsi_controller_bus == 'pci': |
66 | + if (scsi_controller.pci_class != PCI_CLASS_STORAGE): |
67 | # This is not a storage class PCI device? This |
68 | # indicates a bug somewhere in HAL or in the hwdb |
69 | # client, or a fake submission. |
70 | - device_class = grandparent.pci_class |
71 | + device_class = scsi_controller.pci_class |
72 | self.parser._logWarning( |
73 | 'A (possibly fake) SCSI device %s is connected to ' |
74 | 'PCI device %s that has the PCI device class %s; ' |
75 | 'expected class 1 (storage).' |
76 | - % (self.device_id, grandparent.device_id, device_class)) |
77 | + % (self.device_id, scsi_controller.device_id, |
78 | + device_class)) |
79 | return None |
80 | - pci_subclass = grandparent.pci_subclass |
81 | + pci_subclass = scsi_controller.pci_subclass |
82 | return self.pci_storage_subclass_hwbus.get(pci_subclass) |
83 | - elif grandparent_bus == 'usb': |
84 | + elif scsi_controller_bus == 'usb': |
85 | # USB storage devices have the following HAL device hierarchy: |
86 | # - HAL node for the USB device. info.bus == 'usb_device', |
87 | # device class == 0, device subclass == 0 |
88 | @@ -2067,10 +2066,15 @@ |
89 | # it is hard to find a better heuristic to separate |
90 | # the vendor name from the product name. |
91 | splitted_name = self.scsi_model.split(' ', 1) |
92 | - if len(splitted_name) < 2: |
93 | - return 'ATA', splitted_name[0] |
94 | - return splitted_name |
95 | - return (vendor, self.scsi_model) |
96 | + if len(splitted_name) == 2: |
97 | + return { |
98 | + 'vendor': splitted_name[0], |
99 | + 'product': splitted_name[1], |
100 | + } |
101 | + return { |
102 | + 'vendor': vendor, |
103 | + 'product': self.scsi_model, |
104 | + } |
105 | |
106 | def getDriver(self): |
107 | """Return the HWDriver instance associated with this device. |
108 | @@ -2289,11 +2293,7 @@ |
109 | # below does not work properly. |
110 | return self.getProperty('system.hardware.' + type_) |
111 | elif bus == 'scsi': |
112 | - vendor, product = self.getScsiVendorAndModelName() |
113 | - if type_ == 'vendor': |
114 | - return vendor |
115 | - else: |
116 | - return product |
117 | + return self.getScsiVendorAndModelName()[type_] |
118 | else: |
119 | result = self.getProperty('info.' + type_) |
120 | if result is None: |
121 | @@ -2354,11 +2354,32 @@ |
122 | """See `BaseDevice`.""" |
123 | return self.getVendorOrProductID('product') |
124 | |
125 | + @property |
126 | + def scsi_controller(self): |
127 | + """See `BaseDevice`.""" |
128 | + # While SCSI devices from valid submissions should have a |
129 | + # parent and a grandparent, we can't be sure for bogus or |
130 | + # broken submissions. |
131 | + if self.raw_bus != 'scsi': |
132 | + return None |
133 | + parent = self.parent |
134 | + if parent is None: |
135 | + self.parser._logWarning( |
136 | + 'Found SCSI device without a parent: %s.' % self.device_id) |
137 | + return None |
138 | + grandparent = parent.parent |
139 | + if grandparent is None: |
140 | + self.parser._logWarning( |
141 | + 'Found SCSI device without a grandparent: %s.' |
142 | + % self.device_id) |
143 | + return None |
144 | + return grandparent |
145 | + |
146 | |
147 | class UdevDevice(BaseDevice): |
148 | """The representation of a udev device node.""" |
149 | |
150 | - def __init__(self, udev_data, sysfs_data, parser): |
151 | + def __init__(self, parser, udev_data, sysfs_data=None, dmi_data=None): |
152 | """HALDevice constructor. |
153 | |
154 | :param udevdata: The udev data for this device |
155 | @@ -2369,6 +2390,7 @@ |
156 | super(UdevDevice, self).__init__(parser) |
157 | self.udev = udev_data |
158 | self.sysfs = sysfs_data |
159 | + self.dmi = dmi_data |
160 | |
161 | @property |
162 | def device_id(self): |
163 | @@ -2376,6 +2398,14 @@ |
164 | return self.udev['P'] |
165 | |
166 | @property |
167 | + def root_device_ids(self): |
168 | + """The vendor and product IDs of the root device.""" |
169 | + return { |
170 | + 'vendor': self.dmi.get('/sys/class/dmi/id/sys_vendor'), |
171 | + 'product': self.dmi.get('/sys/class/dmi/id/product_name') |
172 | + } |
173 | + |
174 | + @property |
175 | def is_pci(self): |
176 | """True, if this is a PCI device, else False.""" |
177 | return self.udev['E'].get('SUBSYSTEM') == 'pci' |
178 | @@ -2410,6 +2440,30 @@ |
179 | return self.pci_class_info[1] |
180 | |
181 | @property |
182 | + def pci_ids(self): |
183 | + """The PCI vendor and product IDs. |
184 | + |
185 | + :return: A dictionary containing the vendor and product IDs. |
186 | + The IDs are set to None for Non-PCI devices. |
187 | + """ |
188 | + if self.is_pci: |
189 | + # SubmissionParser.checkUdevPciProperties() ensures that |
190 | + # each PCI device has the property PCI_ID and that is |
191 | + # consists of two 4-digit hexadecimal numbers, separated |
192 | + # by a ':'. |
193 | + id_string = self.udev['E']['PCI_ID'] |
194 | + ids = id_string.split(':') |
195 | + return { |
196 | + 'vendor': int(ids[0], 16), |
197 | + 'product': int(ids[1], 16), |
198 | + } |
199 | + else: |
200 | + return { |
201 | + 'vendor': None, |
202 | + 'product': None, |
203 | + } |
204 | + |
205 | + @property |
206 | def is_usb(self): |
207 | """True, if this is a USB device, else False.""" |
208 | return self.udev['E'].get('SUBSYSTEM') == 'usb' |
209 | @@ -2418,8 +2472,9 @@ |
210 | def usb_ids(self): |
211 | """The vendor ID, product ID, product version for USB devices. |
212 | |
213 | - :return: [vendor_id, product_id, version] for USB devices |
214 | - or [None, None, None] for other devices. |
215 | + :return: A dictionary containing the vendor and product IDs and |
216 | + the product version for USB devices. |
217 | + The IDs are set to None for Non-USB devices. |
218 | """ |
219 | if self.is_usb: |
220 | # udev represents USB device IDs as strings |
221 | @@ -2428,19 +2483,27 @@ |
222 | # SubmissionParser.checkUdevUsbProperties() ensures that |
223 | # the string PRODUCT is in the format required below. |
224 | product_info = self.udev['E']['PRODUCT'].split('/') |
225 | - return [int(part, 16) for part in product_info] |
226 | + return { |
227 | + 'vendor': int(product_info[0], 16), |
228 | + 'product': int(product_info[1], 16), |
229 | + 'version': int(product_info[2], 16), |
230 | + } |
231 | else: |
232 | - return [None, None, None] |
233 | + return { |
234 | + 'vendor': None, |
235 | + 'product': None, |
236 | + 'version': None, |
237 | + } |
238 | |
239 | @property |
240 | def usb_vendor_id(self): |
241 | """See `BaseDevice`.""" |
242 | - return self.usb_ids[0] |
243 | + return self.usb_ids['vendor'] |
244 | |
245 | @property |
246 | def usb_product_id(self): |
247 | """See `BaseDevice`.""" |
248 | - return self.usb_ids[1] |
249 | + return self.usb_ids['product'] |
250 | |
251 | @property |
252 | def is_scsi_device(self): |
253 | @@ -2476,6 +2539,107 @@ |
254 | else: |
255 | return None |
256 | |
257 | + @property |
258 | + def raw_bus(self): |
259 | + """See `BaseDevice`.""" |
260 | + # udev specifies the property SUBSYSTEM for most devices; |
261 | + # some devices have additionally the more specific property |
262 | + # DEVTYPE. DEVTYPE is preferable. |
263 | + # The root device has the subsystem/bus value "acpi", which |
264 | + # is a bit nonsensical. |
265 | + if self.device_id == UDEV_ROOT_PATH: |
266 | + return None |
267 | + properties = self.udev['E'] |
268 | + devtype = properties.get('DEVTYPE') |
269 | + if devtype is not None: |
270 | + return devtype |
271 | + return properties.get('SUBSYSTEM') |
272 | + |
273 | + def getVendorOrProduct(self, type_): |
274 | + """Return the vendor or product of this device. |
275 | + |
276 | + :return: The vendor or product data for this device. |
277 | + :param type_: 'vendor' or 'product' |
278 | + """ |
279 | + assert type_ in ('vendor', 'product'), ( |
280 | + 'Unexpected value of type_: %r' % type_) |
281 | + |
282 | + bus = self.raw_bus |
283 | + if self.device_id == UDEV_ROOT_PATH: |
284 | + # udev does not known about any product information for |
285 | + # the root device. We use DMI data instead. |
286 | + return self.root_device_ids[type_] |
287 | + elif bus == 'scsi_device': |
288 | + return self.getScsiVendorAndModelName()[type_] |
289 | + elif bus in ('pci', 'usb_device'): |
290 | + # XXX Abel Deuring 2009-10-13, bug 450480: udev does not |
291 | + # provide human-readable vendor and product names for |
292 | + # USB and PCI devices. We should retrieve these from |
293 | + # http://www.linux-usb.org/usb.ids and |
294 | + # http://pciids.sourceforge.net/v2.2/pci.ids |
295 | + return 'Unknown' |
296 | + else: |
297 | + # We don't process yet other devices than complete systems, |
298 | + # PCI, USB devices and those devices that are represented |
299 | + # in udev as SCSI devices: real SCSI devices, and |
300 | + # IDE/ATA/SATA devices. |
301 | + return None |
302 | + |
303 | + @property |
304 | + def vendor(self): |
305 | + """See `BaseDevice`.""" |
306 | + return self.getVendorOrProduct('vendor') |
307 | + |
308 | + @property |
309 | + def product(self): |
310 | + """See `BaseDevice`.""" |
311 | + return self.getVendorOrProduct('product') |
312 | + |
313 | + def getVendorOrProductID(self, type_): |
314 | + """Return the vendor or product ID of this device. |
315 | + |
316 | + :return: The vendor or product ID for this device. |
317 | + :param type_: 'vendor' or 'product' |
318 | + """ |
319 | + assert type_ in ('vendor', 'product'), ( |
320 | + 'Unexpected value of type_: %r' % type_) |
321 | + |
322 | + bus = self.raw_bus |
323 | + if self.device_id == UDEV_ROOT_PATH: |
324 | + # udev does not known about any product information for |
325 | + # the root device. We use DMI data instead. |
326 | + if type_ == 'vendor': |
327 | + return self.dmi.get('/sys/class/dmi/id/sys_vendor') |
328 | + else: |
329 | + return self.dmi.get('/sys/class/dmi/id/product_name') |
330 | + elif bus == 'scsi_device': |
331 | + return self.getScsiVendorAndModelName()[type_] |
332 | + elif bus == 'pci': |
333 | + return self.pci_ids[type_] |
334 | + elif bus == 'usb_device': |
335 | + return self.usb_ids[type_] |
336 | + else: |
337 | + # We don't process yet other devices than complete systems, |
338 | + # PCI, USB devices and those devices that are represented |
339 | + # in udev as SCSI devices: real SCSI devices, and |
340 | + # IDE/ATA/SATA devices. |
341 | + return None |
342 | + |
343 | + @property |
344 | + def vendor_id(self): |
345 | + """See `BaseDevice`.""" |
346 | + return self.getVendorOrProductID('vendor') |
347 | + |
348 | + @property |
349 | + def product_id(self): |
350 | + """See `BaseDevice`.""" |
351 | + return self.getVendorOrProductID('product') |
352 | + |
353 | + @property |
354 | + def driver_name(self): |
355 | + """See `BaseDevice`.""" |
356 | + return self.udev['E'].get('DRIVER') |
357 | + |
358 | |
359 | class ProcessingLoop(object): |
360 | """An `ITunableLoop` for processing HWDB submissions.""" |
361 | |
362 | === modified file 'lib/canonical/launchpad/scripts/tests/test_hwdb_submission_processing.py' |
363 | --- lib/canonical/launchpad/scripts/tests/test_hwdb_submission_processing.py 2009-10-12 14:50:22 +0000 |
364 | +++ lib/canonical/launchpad/scripts/tests/test_hwdb_submission_processing.py 2009-10-14 15:20:31 +0000 |
365 | @@ -539,6 +539,214 @@ |
366 | 'HAL property info.bus.') |
367 | |
368 | |
369 | + def test_HALDevice_scsi_controller_usb_storage_device(self): |
370 | + """test of HALDevice.scsi_controller. |
371 | + |
372 | + The physical device is a USB storage device. |
373 | + """ |
374 | + devices = [ |
375 | + # The main node of the USB storage device. |
376 | + { |
377 | + 'id': 1, |
378 | + 'udi': self.UDI_USB_STORAGE, |
379 | + 'properties': { |
380 | + 'info.bus': ('usb_device', 'str'), |
381 | + }, |
382 | + }, |
383 | + # The storage interface of the USB device. |
384 | + { |
385 | + 'id': 2, |
386 | + 'udi': self.UDI_USB_STORAGE_IF0, |
387 | + 'properties': { |
388 | + 'info.bus': ('usb', 'str'), |
389 | + 'info.parent': (self.UDI_USB_STORAGE, 'str'), |
390 | + }, |
391 | + }, |
392 | + # The fake SCSI host of the storage device. Note that HAL does |
393 | + # _not_ provide the info.bus property. |
394 | + { |
395 | + 'id': 3, |
396 | + 'udi': self.UDI_USB_STORAGE_SCSI_HOST, |
397 | + 'properties': { |
398 | + 'info.parent': (self.UDI_USB_STORAGE_IF0, 'str'), |
399 | + }, |
400 | + }, |
401 | + # The fake SCSI disk. |
402 | + { |
403 | + 'id': 3, |
404 | + 'udi': self.UDI_USB_STORAGE_SCSI_DEVICE, |
405 | + 'properties': { |
406 | + 'info.bus': ('scsi', 'str'), |
407 | + 'info.parent': (self.UDI_USB_STORAGE_SCSI_HOST, 'str'), |
408 | + }, |
409 | + }, |
410 | + ] |
411 | + parsed_data = { |
412 | + 'hardware': { |
413 | + 'hal': { |
414 | + 'devices': devices, |
415 | + }, |
416 | + }, |
417 | + } |
418 | + |
419 | + parser = SubmissionParser() |
420 | + parser.buildDeviceList(parsed_data) |
421 | + |
422 | + usb_fake_scsi_disk = parser.hal_devices[ |
423 | + self.UDI_USB_STORAGE_SCSI_DEVICE] |
424 | + usb_main_device = parser.hal_devices[self.UDI_USB_STORAGE_IF0] |
425 | + self.assertEqual(usb_main_device, usb_fake_scsi_disk.scsi_controller) |
426 | + |
427 | + def test_HALDevice_scsi_controller_pci_controller(self): |
428 | + """test of HALDevice.scsi_controller. |
429 | + |
430 | + Variant for a SCSI device connected to a PCI controller. |
431 | + """ |
432 | + devices = [ |
433 | + # The PCI host controller. |
434 | + { |
435 | + 'id': 1, |
436 | + 'udi': self.UDI_SATA_CONTROLLER, |
437 | + 'properties': { |
438 | + 'info.bus': ('pci', 'str'), |
439 | + 'pci.device_class': (PCI_CLASS_STORAGE, 'int'), |
440 | + 'pci.device_subclass': (PCI_SUBCLASS_STORAGE_SATA, |
441 | + 'int'), |
442 | + }, |
443 | + }, |
444 | + # The (fake or real) SCSI host of the storage device. |
445 | + { |
446 | + 'id': 2, |
447 | + 'udi': self.UDI_SATA_CONTROLLER_SCSI, |
448 | + 'properties': { |
449 | + 'info.parent': (self.UDI_SATA_CONTROLLER, 'str'), |
450 | + }, |
451 | + }, |
452 | + # The (possibly fake) SCSI disk. |
453 | + { |
454 | + 'id': 3, |
455 | + 'udi': self.UDI_SATA_DISK, |
456 | + 'properties': { |
457 | + 'info.bus': ('scsi', 'str'), |
458 | + 'info.parent': (self.UDI_SATA_CONTROLLER_SCSI, 'str'), |
459 | + }, |
460 | + }, |
461 | + ] |
462 | + parsed_data = { |
463 | + 'hardware': { |
464 | + 'hal': { |
465 | + 'devices': devices, |
466 | + }, |
467 | + }, |
468 | + } |
469 | + |
470 | + parser = SubmissionParser() |
471 | + parser.buildDeviceList(parsed_data) |
472 | + |
473 | + scsi_device = parser.hal_devices[self.UDI_SATA_DISK] |
474 | + controller = parser.hal_devices[self.UDI_SATA_CONTROLLER] |
475 | + self.assertEqual(controller, scsi_device.scsi_controller) |
476 | + |
477 | + def test_HALDevice_scsi_controller_non_scsi_device(self): |
478 | + """test of HALDevice.scsi_controller. |
479 | + |
480 | + Variant for non-SCSI devices. |
481 | + """ |
482 | + devices = [ |
483 | + { |
484 | + 'id': 1, |
485 | + 'udi': self.UDI_COMPUTER, |
486 | + 'properties': {}, |
487 | + }, |
488 | + ] |
489 | + parsed_data = { |
490 | + 'hardware': { |
491 | + 'hal': { |
492 | + 'devices': devices, |
493 | + }, |
494 | + }, |
495 | + } |
496 | + |
497 | + parser = SubmissionParser() |
498 | + parser.buildDeviceList(parsed_data) |
499 | + |
500 | + device = parser.hal_devices[self.UDI_COMPUTER] |
501 | + self.assertEqual(None, device.scsi_controller) |
502 | + |
503 | + def test_HALDevice_scsi_controller_no_grandparent(self): |
504 | + """test of HALDevice.scsi_controller. |
505 | + |
506 | + Variant for a SCSI device without a grandparent device. |
507 | + """ |
508 | + devices = [ |
509 | + # The (fake or real) SCSI host of the storage device. |
510 | + { |
511 | + 'id': 1, |
512 | + 'udi': self.UDI_SATA_CONTROLLER_SCSI, |
513 | + 'properties': {}, |
514 | + }, |
515 | + # The (possibly fake) SCSI disk. |
516 | + { |
517 | + 'id': 2, |
518 | + 'udi': self.UDI_SATA_DISK, |
519 | + 'properties': { |
520 | + 'info.bus': ('scsi', 'str'), |
521 | + 'info.parent': (self.UDI_SATA_CONTROLLER_SCSI, 'str'), |
522 | + }, |
523 | + }, |
524 | + ] |
525 | + parsed_data = { |
526 | + 'hardware': { |
527 | + 'hal': { |
528 | + 'devices': devices, |
529 | + }, |
530 | + }, |
531 | + } |
532 | + |
533 | + parser = SubmissionParser(self.log) |
534 | + parser.submission_key = 'SCSI device without grandparent device' |
535 | + parser.buildDeviceList(parsed_data) |
536 | + |
537 | + scsi_device = parser.hal_devices[self.UDI_SATA_DISK] |
538 | + self.assertEqual(None, scsi_device.scsi_controller) |
539 | + self.assertWarningMessage( |
540 | + parser.submission_key, |
541 | + "Found SCSI device without a grandparent: %s." |
542 | + % self.UDI_SATA_DISK) |
543 | + |
544 | + def test_HALDevice_scsi_controller_no_parent(self): |
545 | + """test of HALDevice.scsi_controller. |
546 | + |
547 | + Variant for a SCSI device without a parent device. |
548 | + """ |
549 | + devices = [ |
550 | + # The (possibly fake) SCSI disk. |
551 | + { |
552 | + 'id': 1, |
553 | + 'udi': self.UDI_SATA_DISK, |
554 | + 'properties': { |
555 | + 'info.bus': ('scsi', 'str'), |
556 | + }, |
557 | + }, |
558 | + ] |
559 | + parsed_data = { |
560 | + 'hardware': { |
561 | + 'hal': { |
562 | + 'devices': devices, |
563 | + }, |
564 | + }, |
565 | + } |
566 | + |
567 | + parser = SubmissionParser(self.log) |
568 | + parser.submission_key = 'SCSI device without parent device' |
569 | + parser.buildDeviceList(parsed_data) |
570 | + |
571 | + scsi_device = parser.hal_devices[self.UDI_SATA_DISK] |
572 | + self.assertEqual(None, scsi_device.scsi_controller) |
573 | + self.assertWarningMessage( |
574 | + parser.submission_key, |
575 | + "Found SCSI device without a parent: %s." % self.UDI_SATA_DISK) |
576 | + |
577 | def testHALDeviceGetRealBus(self): |
578 | """Test of HALDevice.real_bus, generic case. |
579 | |
580 | @@ -1598,18 +1806,16 @@ |
581 | parser = SubmissionParser(self.log) |
582 | parser.buildDeviceList(parsed_data) |
583 | device = parser.hal_devices[self.UDI_SCSI_DISK] |
584 | - vendor, model = device.getScsiVendorAndModelName() |
585 | + vendor_model = device.getScsiVendorAndModelName() |
586 | self.assertEqual( |
587 | - vendor, 'SHARP', |
588 | + { |
589 | + 'vendor': 'SHARP', |
590 | + 'product': 'JX250 SCSI', |
591 | + }, |
592 | + vendor_model, |
593 | 'Unexpected result of HWDevice.getScsiVendorAndModelName ' |
594 | 'for a regular SCSI device. Expected vendor name SHARP, got %r.' |
595 | - % vendor) |
596 | - self.assertEqual( |
597 | - model, 'JX250 SCSI', |
598 | - 'Unexpected result of HWDevice.getScsiVendorAndModelName ' |
599 | - 'for a regular SCSI device. Expected model name JX250 SCSI , ' |
600 | - 'got %r.' |
601 | - % model) |
602 | + % vendor_model) |
603 | |
604 | def testHALDeviceSCSIVendorModelNameATADiskShortModelName(self): |
605 | """Test of HALDevice.getScsiVendorAndModelName, ATA disk (1). |
606 | @@ -1639,18 +1845,16 @@ |
607 | parser = SubmissionParser(self.log) |
608 | parser.buildDeviceList(parsed_data) |
609 | device = parser.hal_devices[self.UDI_SCSI_DISK] |
610 | - vendor, model = device.getScsiVendorAndModelName() |
611 | - self.assertEqual( |
612 | - vendor, 'Hitachi', |
613 | - 'Unexpected result of HWDevice.getScsiVendorAndModelName ' |
614 | - 'for an ATA SCSI device. Expected vendor name Hitachi, got %r.' |
615 | - % vendor) |
616 | - self.assertEqual( |
617 | - model, 'HTS54161', |
618 | - 'Unexpected result of HWDevice.getScsiVendorAndModelName ' |
619 | - 'for a reguale SCSI device. Expected vendor name HTS54161, ' |
620 | - 'got %r.' |
621 | - % model) |
622 | + vendor_model = device.getScsiVendorAndModelName() |
623 | + self.assertEqual( |
624 | + { |
625 | + 'vendor': 'Hitachi', |
626 | + 'product': 'HTS54161', |
627 | + }, |
628 | + vendor_model, |
629 | + 'Unexpected result of HWDevice.getScsiVendorAndModelName ' |
630 | + 'for an ATA SCSI device: %r.' |
631 | + % vendor_model) |
632 | |
633 | def testHALDeviceSCSIVendorModelNameATADiskLongModelName(self): |
634 | """Test of HALDevice.getScsiVendorAndModelName, ATA disk (2). |
635 | @@ -1679,18 +1883,16 @@ |
636 | parser = SubmissionParser(self.log) |
637 | parser.buildDeviceList(parsed_data) |
638 | device = parser.hal_devices[self.UDI_SCSI_DISK] |
639 | - vendor, model = device.getScsiVendorAndModelName() |
640 | - self.assertEqual( |
641 | - vendor, 'ATA', |
642 | - 'Unexpected result of HWDevice.getScsiVendorAndModelName ' |
643 | - 'for a reguale SCSI device. Expected vendor name ATA, got %r.' |
644 | - % vendor) |
645 | - self.assertEqual( |
646 | - model, 'HTC426060G9AT00', |
647 | - 'Unexpected result of HWDevice.getScsiVendorAndModelName ' |
648 | - 'for a reguale SCSI device. Expected vendor name ' |
649 | - 'HTC426060G9AT00 , got %r.' |
650 | - % model) |
651 | + vendor_product = device.getScsiVendorAndModelName() |
652 | + self.assertEqual( |
653 | + { |
654 | + 'vendor': 'ATA', |
655 | + 'product': 'HTC426060G9AT00', |
656 | + }, |
657 | + vendor_product, |
658 | + 'Unexpected result of HWDevice.getScsiVendorAndModelName ' |
659 | + 'for a reguale SCSI device: %r.' |
660 | + % vendor_product) |
661 | |
662 | def testHALDeviceVendorFromInfoVendor(self): |
663 | """Test of HALDevice.vendor, regular case. |
664 | @@ -2606,6 +2808,11 @@ |
665 | } |
666 | } |
667 | |
668 | + root_device_dmi_data = { |
669 | + '/sys/class/dmi/id/sys_vendor': 'FUJITSU SIEMENS', |
670 | + '/sys/class/dmi/id/product_name': 'LIFEBOOK E8210', |
671 | + } |
672 | + |
673 | pci_device_data = { |
674 | 'P': '/devices/pci0000:00/0000:00:1f.2', |
675 | 'E': { |
676 | @@ -2614,6 +2821,7 @@ |
677 | 'PCI_SUBSYS_ID': '10CF:1387', |
678 | 'PCI_SLOT_NAME': '0000:00:1f.2', |
679 | 'SUBSYSTEM': 'pci', |
680 | + 'DRIVER': 'ahci', |
681 | } |
682 | } |
683 | |
684 | @@ -2624,114 +2832,168 @@ |
685 | 'DEVTYPE': 'usb_device', |
686 | 'PRODUCT': '46d/a01/1013', |
687 | 'TYPE': '0/0/0', |
688 | + 'DRIVER': 'usb', |
689 | }, |
690 | } |
691 | |
692 | - scsi_device_data = { |
693 | - 'P': '/devices/pci0000:00/0000:00:1f.1/host4/target4:0:0/4:0:0:0', |
694 | + scsi_scanner_device_data = { |
695 | + 'P': ('/devices/pci0000:00/0000:00:1e.0/0000:08:03.0/0000:09:00.0/' |
696 | + 'host6/target6:0:1/6:0:1:0'), |
697 | 'E': { |
698 | + 'DEVTYPE': 'scsi_device', |
699 | 'SUBSYSTEM': 'scsi', |
700 | - 'DEVTYPE': 'scsi_device', |
701 | }, |
702 | } |
703 | |
704 | - scsi_device_sysfs_data = { |
705 | - 'vendor': 'MATSHITA', |
706 | - 'model': 'DVD-RAM UJ-841S', |
707 | - 'type': '5', |
708 | + scsi_scanner_device_sysfs_data = { |
709 | + 'vendor': 'FUJITSU', |
710 | + 'model': 'fi-5120Cdj', |
711 | + 'type': '6', |
712 | + } |
713 | + |
714 | + no_subsystem_device_data = { |
715 | + 'P': '/devices/pnp0/00:00', |
716 | + 'E': {} |
717 | } |
718 | |
719 | def test_device_id(self): |
720 | """Test of UdevDevice.device_id.""" |
721 | - device = UdevDevice(self.pci_device_data, None, None) |
722 | + device = UdevDevice(None, self.pci_device_data) |
723 | self.assertEqual( |
724 | '/devices/pci0000:00/0000:00:1f.2', device.device_id, |
725 | 'Unexpected value of UdevDevice.device_id.') |
726 | |
727 | + def test_root_device_ids(self): |
728 | + device = UdevDevice( |
729 | + None, self.root_device, None, self.root_device_dmi_data) |
730 | + self.assertEqual( |
731 | + { |
732 | + 'vendor': 'FUJITSU SIEMENS', |
733 | + 'product': 'LIFEBOOK E8210', |
734 | + }, |
735 | + device.root_device_ids) |
736 | + |
737 | + device = UdevDevice( |
738 | + None, self.root_device, None, {}) |
739 | + self.assertEqual( |
740 | + { |
741 | + 'vendor': None, |
742 | + 'product': None, |
743 | + }, |
744 | + device.root_device_ids) |
745 | + |
746 | def test_is_pci(self): |
747 | """Test of UdevDevice.is_pci.""" |
748 | - device = UdevDevice(self.pci_device_data, None, None) |
749 | + device = UdevDevice(None, self.pci_device_data) |
750 | self.assertTrue(device.is_pci) |
751 | |
752 | - device = UdevDevice(self.root_device, None, None) |
753 | + device = UdevDevice(None, self.root_device) |
754 | self.assertFalse(device.is_pci) |
755 | |
756 | def test_pci_class_info(self): |
757 | """Test of UdevDevice.pci_class_info""" |
758 | - device = UdevDevice(self.pci_device_data, None, None) |
759 | + device = UdevDevice(None, self.pci_device_data) |
760 | self.assertEqual( |
761 | (1, 6, 2), device.pci_class_info, |
762 | 'Invalid value of UdevDevice.pci_class_info for PCI device.') |
763 | |
764 | - device = UdevDevice(self.root_device, None, None) |
765 | + device = UdevDevice(None, self.root_device) |
766 | self.assertEqual( |
767 | (None, None, None), device.pci_class_info, |
768 | 'Invalid value of UdevDevice.pci_class_info for Non-PCI device.') |
769 | |
770 | def test_pci_class(self): |
771 | """Test of UdevDevice.pci_class""" |
772 | - device = UdevDevice(self.pci_device_data, None, None) |
773 | + device = UdevDevice(None, self.pci_device_data) |
774 | self.assertEqual( |
775 | 1, device.pci_class, |
776 | 'Invalid value of UdevDevice.pci_class for PCI device.') |
777 | |
778 | - device = UdevDevice(self.root_device, None, None) |
779 | + device = UdevDevice(None, self.root_device) |
780 | self.assertEqual( |
781 | None, device.pci_class, |
782 | 'Invalid value of UdevDevice.pci_class for Non-PCI device.') |
783 | |
784 | def test_pci_subclass(self): |
785 | """Test of UdevDevice.pci_subclass""" |
786 | - device = UdevDevice(self.pci_device_data, None, None) |
787 | + device = UdevDevice(None, self.pci_device_data) |
788 | self.assertEqual( |
789 | 6, device.pci_subclass, |
790 | 'Invalid value of UdevDevice.pci_class for PCI device.') |
791 | |
792 | - device = UdevDevice(self.root_device, None, None) |
793 | + device = UdevDevice(None, self.root_device) |
794 | self.assertEqual( |
795 | None, device.pci_class, |
796 | 'Invalid value of UdevDevice.pci_class for Non-PCI device.') |
797 | |
798 | + def test_pci_ids(self): |
799 | + """Test of UdevDevice.pci_ids""" |
800 | + device = UdevDevice(None, self.pci_device_data) |
801 | + self.assertEqual( |
802 | + {'vendor': 0x8086, |
803 | + 'product': 0x27C5, |
804 | + }, |
805 | + device.pci_ids, |
806 | + 'Invalid value of UdevDevice.pci_ids for PCI device.') |
807 | + |
808 | + device = UdevDevice(None, self.usb_device_data) |
809 | + self.assertEqual( |
810 | + {'vendor': None, |
811 | + 'product': None, |
812 | + }, |
813 | + device.pci_ids, |
814 | + 'Invalid value of UdevDevice.pci_ids for Non-PCI device.') |
815 | + |
816 | def test_is_usb(self): |
817 | """Test of UdevDevice.is_usb""" |
818 | - device = UdevDevice(self.usb_device_data, None, None) |
819 | + device = UdevDevice(None, self.usb_device_data) |
820 | self.assertTrue(device.is_usb) |
821 | |
822 | - device = UdevDevice(self.pci_device_data, None, None) |
823 | + device = UdevDevice(None, self.pci_device_data) |
824 | self.assertFalse(device.is_usb) |
825 | |
826 | def test_usb_ids(self): |
827 | """Test of UdevDevice.usb_ids""" |
828 | - device = UdevDevice(self.usb_device_data, None, None) |
829 | + device = UdevDevice(None, self.usb_device_data) |
830 | self.assertEqual( |
831 | - [0x46d, 0xa01, 0x1013], device.usb_ids, |
832 | + { |
833 | + 'vendor': 0x46d, |
834 | + 'product': 0xa01, |
835 | + 'version': 0x1013, |
836 | + }, |
837 | + device.usb_ids, |
838 | 'Invalid value of UdevDevice.usb_ids for USB device.') |
839 | |
840 | - device = UdevDevice(self.root_device, None, None) |
841 | + device = UdevDevice(None, self.root_device) |
842 | self.assertEqual( |
843 | - [None, None, None], device.usb_ids, |
844 | + { |
845 | + 'vendor': None, |
846 | + 'product': None, |
847 | + 'version': None, |
848 | + }, |
849 | + device.usb_ids, |
850 | 'Invalid value of UdevDevice.usb_ids for Non-USB device.') |
851 | |
852 | def test_usb_vendor_id(self): |
853 | """Test of UdevDevice.usb_vendor_id""" |
854 | - device = UdevDevice(self.usb_device_data, None, None) |
855 | + device = UdevDevice(None, self.usb_device_data) |
856 | self.assertEqual( |
857 | 0x46d, device.usb_vendor_id, |
858 | 'Invalid value of UdevDevice.usb_vendor_id for USB device.') |
859 | |
860 | - device = UdevDevice(self.root_device, None, None) |
861 | + device = UdevDevice(None, self.root_device) |
862 | self.assertEqual( |
863 | None, device.usb_vendor_id, |
864 | 'Invalid value of UdevDevice.usb_vendor_id for Non-USB device.') |
865 | |
866 | def test_usb_product_id(self): |
867 | """Test of UdevDevice.usb_product_id""" |
868 | - device = UdevDevice(self.usb_device_data, None, None) |
869 | + device = UdevDevice(None, self.usb_device_data) |
870 | self.assertEqual( |
871 | 0xa01, device.usb_product_id, |
872 | 'Invalid value of UdevDevice.usb_product_id for USB device.') |
873 | |
874 | - device = UdevDevice(self.root_device, None, None) |
875 | + device = UdevDevice(None, self.root_device) |
876 | self.assertEqual( |
877 | None, device.usb_product_id, |
878 | 'Invalid value of UdevDevice.usb_product_id for Non-USB device.') |
879 | @@ -2739,29 +3001,173 @@ |
880 | def test_is_scsi_device(self): |
881 | """Test of UdevDevice.is_scsi_device.""" |
882 | device = UdevDevice( |
883 | - self.scsi_device_data, self.scsi_device_sysfs_data, None) |
884 | + None, self.scsi_scanner_device_data, |
885 | + self.scsi_scanner_device_sysfs_data) |
886 | self.assertTrue(device.is_scsi_device) |
887 | |
888 | - device = UdevDevice(self.root_device, None, None) |
889 | + device = UdevDevice(None, self.root_device) |
890 | self.assertFalse(device.is_scsi_device) |
891 | |
892 | def test_scsi_vendor(self): |
893 | """Test of UdevDevice.scsi_vendor.""" |
894 | device = UdevDevice( |
895 | - self.scsi_device_data, self.scsi_device_sysfs_data, None) |
896 | - self.assertEqual('MATSHITA', device.scsi_vendor) |
897 | - device = UdevDevice(self.root_device, None, None) |
898 | + None, self.scsi_scanner_device_data, |
899 | + self.scsi_scanner_device_sysfs_data) |
900 | + self.assertEqual('FUJITSU', device.scsi_vendor) |
901 | + device = UdevDevice(None, self.root_device) |
902 | self.assertEqual(None, device.scsi_vendor) |
903 | |
904 | def test_scsi_model(self): |
905 | """Test of UdevDevice.scsi_model.""" |
906 | device = UdevDevice( |
907 | - self.scsi_device_data, self.scsi_device_sysfs_data, None) |
908 | - self.assertEqual('DVD-RAM UJ-841S', device.scsi_model) |
909 | + None, self.scsi_scanner_device_data, |
910 | + self.scsi_scanner_device_sysfs_data) |
911 | + self.assertEqual('fi-5120Cdj', device.scsi_model) |
912 | |
913 | - device = UdevDevice(self.root_device, None, None) |
914 | + device = UdevDevice(None, self.root_device) |
915 | self.assertEqual(None, device.scsi_model) |
916 | |
917 | + def test_raw_bus(self): |
918 | + """Test of UdevDevice.raw_bus.""" |
919 | + device = UdevDevice(None, self.root_device) |
920 | + self.assertEqual(None, device.raw_bus) |
921 | + |
922 | + device = UdevDevice(None, self.pci_device_data) |
923 | + self.assertEqual('pci', device.raw_bus) |
924 | + |
925 | + device = UdevDevice(None, self.usb_device_data) |
926 | + self.assertEqual('usb_device', device.raw_bus) |
927 | + |
928 | + device = UdevDevice(None, self.no_subsystem_device_data) |
929 | + self.assertEqual(None, device.raw_bus) |
930 | + |
931 | + def test_getVendorOrProduct(self): |
932 | + """Test of UdevDevice.getVendorOrProduct().""" |
933 | + device = UdevDevice( |
934 | + None, self.root_device, None, self.root_device_dmi_data) |
935 | + self.assertEqual( |
936 | + 'FUJITSU SIEMENS', device.getVendorOrProduct('vendor')) |
937 | + self.assertEqual( |
938 | + 'LIFEBOOK E8210', device.getVendorOrProduct('product')) |
939 | + self.assertRaises( |
940 | + AssertionError, device.getVendorOrProduct, 'nonsense') |
941 | + |
942 | + device = UdevDevice(None, self.pci_device_data) |
943 | + self.assertEqual('Unknown', device.getVendorOrProduct('vendor')) |
944 | + self.assertEqual('Unknown', device.getVendorOrProduct('product')) |
945 | + |
946 | + device = UdevDevice(None, self.usb_device_data) |
947 | + self.assertEqual('Unknown', device.getVendorOrProduct('vendor')) |
948 | + self.assertEqual('Unknown', device.getVendorOrProduct('product')) |
949 | + |
950 | + device = UdevDevice( |
951 | + None, self.scsi_scanner_device_data, |
952 | + self.scsi_scanner_device_sysfs_data) |
953 | + self.assertEqual('FUJITSU', device.getVendorOrProduct('vendor')) |
954 | + self.assertEqual('fi-5120Cdj', device.getVendorOrProduct('product')) |
955 | + |
956 | + device = UdevDevice(None, self.no_subsystem_device_data) |
957 | + self.assertEqual(None, device.getVendorOrProduct('vendor')) |
958 | + self.assertEqual(None, device.getVendorOrProduct('product')) |
959 | + |
960 | + def test_vendor(self): |
961 | + """Test of UdevDevice.vendor.""" |
962 | + device = UdevDevice( |
963 | + None, self.root_device, None, self.root_device_dmi_data) |
964 | + self.assertEqual('FUJITSU SIEMENS', device.vendor) |
965 | + |
966 | + def test_product(self): |
967 | + """Test of UdevDevice.product.""" |
968 | + device = UdevDevice( |
969 | + None, self.root_device, None, self.root_device_dmi_data) |
970 | + self.assertEqual('LIFEBOOK E8210', device.product) |
971 | + |
972 | + def test_getVendorOrProductID(self): |
973 | + """Test of UdevDevice.getVendorOrProduct().""" |
974 | + device = UdevDevice( |
975 | + None, self.root_device, None, self.root_device_dmi_data) |
976 | + self.assertEqual( |
977 | + 'FUJITSU SIEMENS', device.getVendorOrProductID('vendor')) |
978 | + self.assertEqual( |
979 | + 'LIFEBOOK E8210', device.getVendorOrProductID('product')) |
980 | + self.assertRaises( |
981 | + AssertionError, device.getVendorOrProductID, 'nonsense') |
982 | + |
983 | + device = UdevDevice(None, self.pci_device_data) |
984 | + self.assertEqual(0x8086, device.getVendorOrProductID('vendor')) |
985 | + self.assertEqual(0x27C5, device.getVendorOrProductID('product')) |
986 | + |
987 | + device = UdevDevice(None, self.usb_device_data) |
988 | + self.assertEqual(0x46d, device.getVendorOrProductID('vendor')) |
989 | + self.assertEqual(0xa01, device.getVendorOrProductID('product')) |
990 | + |
991 | + device = UdevDevice( |
992 | + None, self.scsi_scanner_device_data, |
993 | + self.scsi_scanner_device_sysfs_data) |
994 | + self.assertEqual('FUJITSU', device.getVendorOrProductID('vendor')) |
995 | + self.assertEqual('fi-5120Cdj', device.getVendorOrProductID('product')) |
996 | + |
997 | + device = UdevDevice( |
998 | + None, self.no_subsystem_device_data) |
999 | + self.assertEqual(None, device.getVendorOrProductID('vendor')) |
1000 | + self.assertEqual(None, device.getVendorOrProductID('product')) |
1001 | + |
1002 | + def test_vendor_id(self): |
1003 | + """Test of UdevDevice.vendor_id.""" |
1004 | + device = UdevDevice( |
1005 | + None, self.root_device, None, self.root_device_dmi_data) |
1006 | + self.assertEqual('FUJITSU SIEMENS', device.vendor_id) |
1007 | + |
1008 | + def test_product_id(self): |
1009 | + """Test of UdevDevice.product_id.""" |
1010 | + device = UdevDevice( |
1011 | + None, self.root_device, None, self.root_device_dmi_data) |
1012 | + self.assertEqual('LIFEBOOK E8210', device.product_id) |
1013 | + |
1014 | + def test_vendor_id_for_db(self): |
1015 | + """Test of UdevDevice.vendor_id_for_db.""" |
1016 | + device = UdevDevice( |
1017 | + None, self.root_device, None, self.root_device_dmi_data) |
1018 | + self.assertEqual('FUJITSU SIEMENS', device.vendor_id_for_db) |
1019 | + |
1020 | + device = UdevDevice(None, self.pci_device_data) |
1021 | + self.assertEqual('0x8086', device.vendor_id_for_db) |
1022 | + |
1023 | + device = UdevDevice(None, self.usb_device_data) |
1024 | + self.assertEqual('0x046d', device.vendor_id_for_db) |
1025 | + |
1026 | + device = UdevDevice( |
1027 | + None, self.scsi_scanner_device_data, |
1028 | + self.scsi_scanner_device_sysfs_data) |
1029 | + self.assertEqual('FUJITSU ', device.vendor_id_for_db) |
1030 | + |
1031 | + def test_product_id_for_db(self): |
1032 | + """Test of UdevDevice.product_id_for_db.""" |
1033 | + device = UdevDevice( |
1034 | + None, self.root_device, None, self.root_device_dmi_data) |
1035 | + self.assertEqual('LIFEBOOK E8210', device.product_id_for_db) |
1036 | + |
1037 | + device = UdevDevice(None, self.pci_device_data) |
1038 | + self.assertEqual('0x27c5', device.product_id_for_db) |
1039 | + |
1040 | + device = UdevDevice(None, self.usb_device_data) |
1041 | + self.assertEqual('0x0a01', device.product_id_for_db) |
1042 | + |
1043 | + device = UdevDevice( |
1044 | + None, self.scsi_scanner_device_data, |
1045 | + self.scsi_scanner_device_sysfs_data) |
1046 | + self.assertEqual('fi-5120Cdj ', device.product_id_for_db) |
1047 | + |
1048 | + def test_driver_name(self): |
1049 | + """Test of UdevDevice.driver_name.""" |
1050 | + device = UdevDevice(None, self.pci_device_data) |
1051 | + self.assertEqual('ahci', device.driver_name) |
1052 | + |
1053 | + device = UdevDevice( |
1054 | + None, self.root_device, None, self.root_device_dmi_data) |
1055 | + self.assertEqual(None, device.driver_name) |
1056 | + |
1057 | + |
1058 | class TestHWDBSubmissionTablePopulation(TestCaseHWDB): |
1059 | """Tests of the HWDB popoluation with submitted data.""" |
1060 |
This branch is another step to prepare the BWDB submission processing script for submissions from Karmic's HWDB client.
- a fix of two properties for class UdevDevice:
BaseDevice. vendor_ id_for_ db and BaseDevice. product_ id_for_ db look up the dictionaries DB_FORMAT_ FOR_VENDOR_ ID and DB_FORMAT_ FOR_PRODUCT_ ID, respectively, using BaseDevice,raw_bus as the key. The udev data contains slightly different bus/subsystem data, so we get the raw_value "scsi_device" for submissions with udev data, while we have raw_bus == "scsi" for HAL-based submissions. Hence I added a "scsi_device" entry to the dicitionaries. Since the raw_bus value "scsi_device" is not used by HAL, there are no side effects for HAL-based submissions.
- a new property UdevDevice. driver_ name
- The method BaseDevice. translateScsiBu s() figures out, if a given device where rw_bus is "scsi" (submission with HAL data) or "scsi_device" (submissions with udev data) is a real SCSI device or if it is in fact a USB storage device or a IDE/ATA/SATA device. (Since most od today's storage devices understand SCSI commands, the Linux kernel accesses them via the SCSI layer.) We detect the real device type of given device with raw_bus in ("scsi", "scsi_device") by looking at the device that controls the given (fake) SCSI device: If the controller is a USB device, we have a memory stick, a card reader or a "real" IDE/SATA disk connected to USB adapter; if the controller is a PCI device, we have a real SCSI device, or an IDE/ATA/SATA device. What exactly ww have in the latter case, can be derived from the PCI class/subclass of the controller.
For submissions with HAL, the controller is the grandparent of the SCSI device, but for submissions with udev data, the controller is the grand-grand- grand-grand- grandparent (6th ancestor).
Since the core logic of translateScsiBus() is identical for HAL and udev data, I did not move the method to the two classes HALDevice, UdevDevice derived from BaseDevice. Instead, I defined a new property BaseDevice. scsi_controller that must be implemented by both HALDevice and UdevDevice.
A implementation of UdevDevice. scsi_controller is still missing -- when I started to write tests for that property, I noticed that the diff of the branch would probably exceed our 800 lines limit, so I left that for another sequel.
The change in test_hwdb_ submission_ processing. py: replace scsi_device_data by scsi_scanner_ device_ data may look a bit odd. There are two reasons for this change:
(1) I wanted a real-world SCSI vendor name that is shorter than 8 characters in order to have proper test data for UdevDevice. vendor_ id_for_ db, which right-pads vendor names with spaces to length 8.
(2) The old test device "MATSHITA DVD-RAM UJ-841S" is in fact an IDE device; it might show up as an IDE device later again in a test of BaseDevice. translateScsiBu s().
test: test_hwdb_ submission_ processing
./bin/test --test=
= Launchpad lint =
Checking for conflicts. and issues in doctests and templates.
Running jslint, xmllint, pyflakes, and pylint.
Using normal rules.
Linting changed files: /launchpad/ scripts/ hwdbsubmissions .py /launchpad/ scripts/ tests/test_ hwdb_submi. ..
lib/canonical
lib/canonical