Merge lp:~adeuring/launchpad/hwdb-class-udev-device-7 into lp:launchpad

Proposed by Abel Deuring
Status: Merged
Merged at revision: not available
Proposed branch: lp:~adeuring/launchpad/hwdb-class-udev-device-7
Merge into: lp:launchpad
Diff against target: 1070 lines
2 files modified
lib/canonical/launchpad/scripts/hwdbsubmissions.py (+83/-26)
lib/canonical/launchpad/scripts/tests/test_hwdb_submission_processing.py (+702/-70)
To merge this branch: bzr merge lp:~adeuring/launchpad/hwdb-class-udev-device-7
Reviewer Review Type Date Requested Status
Michael Nelson (community) code Approve
Review via email: mp+13413@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Abel Deuring (adeuring) wrote :

This branch has several small improvements for the HWDB submission
processing script for submissions with udev data:

- it fixes a bug in the udev test data for USB storage devices: The udev
  property DEVTYPE was missing.

  This uncovered a (now fixed) bug in BaseDevice.translateScsiBus()
  Up to now, the detection of a USB storage device pretending to be a
  SCSI device was based on the value "usb" of the property raw_bus of an
  ancestor node of the fake SCSI device, but the real value of
  ancestor.raw_bus for udev submissions is "usb_interface". Since this
  value is not used in submissions with HAL data, there are no bad
  side-effects.

- it defines a new property BaseDevice.is_root_device, implemented in
  the derived classes HALDevice and UdevDevice. There are a few places
  in the code, were the root device needs to be treated specially. Up to
  now, the decision "is this device the root device" was based on a
  comparison of the HAL-specific property "udi".

- it modifies the property BaseDevice.real_bus to properly deal with
  udev submissions. If we have a SCSI device, is now detected by
  comparing the value self.raw_bus with 'scsi' and 'scsi_device'. Again,
  HAL does not use the new value 'scsi_device', so there are no bad side
  effects.

- it adds tests for UdevDevice.real_bus and UdevDevice.translatePciBus()

test: ./bin/test --test=test_hwdb_submission_processing

= Launchpad lint =

Checking for conflicts. and issues in doctests and templates.
Running jslint, xmllint, pyflakes, and pylint.
Using normal rules.

Linting changed files:
  lib/canonical/launchpad/scripts/hwdbsubmissions.py
  lib/canonical/launchpad/scripts/tests/test_hwdb_submission_processing.py

== Pyflakes notices ==

lib/canonical/launchpad/scripts/hwdbsubmissions.py
    22: redefinition of unused 'etree' from line 20

== Pylint notices ==

lib/canonical/launchpad/scripts/hwdbsubmissions.py
    20: [F0401] Unable to import 'xml.etree.cElementTree' (No module
named etree)

The complaint is not related to my changes.

Revision history for this message
Michael Nelson (michael.nelson) wrote :
Download full text (11.4 KiB)

Great! The addition of the is_root_device property makes the code much
more readable.

As usual, just one or two comments below, in particular, one change for which I couldn't see the cause...

Thanks!

> === modified file 'lib/canonical/launchpad/scripts/hwdbsubmissions.py'
> --- lib/canonical/launchpad/scripts/hwdbsubmissions.py 2009-10-15 13:22:14 +0000
> +++ lib/canonical/launchpad/scripts/hwdbsubmissions.py 2009-10-15 13:59:33 +0000
> @@ -1644,7 +1644,7 @@
> return None
> pci_subclass = scsi_controller.pci_subclass
> return self.pci_storage_subclass_hwbus.get(pci_subclass)
> - elif scsi_controller_bus == 'usb':
> + elif scsi_controller_bus in ('usb', 'usb_interface'):
> # USB storage devices have the following HAL device hierarchy:
> # - HAL node for the USB device. info.bus == 'usb_device',
> # device class == 0, device subclass == 0
> @@ -1703,6 +1703,12 @@
> return HWBus.PCI
>
> @property
> + def is_root_device(self):
> + """Return True is this is the root node of all devicese, else False.
> + """
> + raise NotImplementedError
> +
> + @property
> def raw_bus(self):
> """Return the device bus as specified by HAL or udev."""
> raise NotImplementedError
> @@ -1719,11 +1725,11 @@
> if result is not None:
> return result
>
> - if device_bus == 'scsi':
> + if device_bus in ('scsi', 'scsi_device'):
> return self.translateScsiBus()
> elif device_bus == 'pci':
> return self.translatePciBus()
> - elif self.udi == ROOT_UDI:
> + elif self.is_root_device:
> # The computer itself. In Hardy, HAL provides no info.bus
> # for the machine itself; older versions set info.bus to
> # 'unknown', hence it is better to use the machine's
> @@ -1731,7 +1737,7 @@
> return HWBus.SYSTEM
> else:
> self.parser._logWarning(
> - 'Unknown bus %r for device %s' % (device_bus, self.udi))
> + 'Unknown bus %r for device %s' % (device_bus, self.device_id))
> return None
>
> @property
> @@ -2275,6 +2281,11 @@
> return result
> return self.getProperty('info.subsystem')
>
> + @property
> + def is_root_device(self):
> + """See `BaseDevice`."""
> + return self.udi == ROOT_UDI
> +
> def getVendorOrProduct(self, type_):
> """Return the vendor or product of this device.
>
> @@ -2547,7 +2558,7 @@
> # DEVTYPE. DEVTYPE is preferable.
> # The root device has the subsystem/bus value "acpi", which
> # is a bit nonsensical.
> - if self.device_id == UDEV_ROOT_PATH:
> + if self.is_root_device:
> return None
> properties = self.udev['E']
> devtype = properties.get('DEVTYPE')
> @@ -2555,6 +2566,11 @@
> return devtype
> return properties.get('SUBSYSTEM')
>
> + @property
> + def is_root_device(self):
> + """See `BaseDevice`."""
> + return self.udev[...

review: Approve (code)
Revision history for this message
Abel Deuring (adeuring) wrote :
Download full text (9.2 KiB)

Hi Michael,

thanks for your review!

> Great! The addition of the is_root_device property makes the code much
> more readable.
>
> As usual, just one or two comments below, in particular, one change for which
> I couldn't see the cause...
>
> Thanks!
>
> > === modified file 'lib/canonical/launchpad/scripts/hwdbsubmissions.py'
> > --- lib/canonical/launchpad/scripts/hwdbsubmissions.py 2009-10-15
> 13:22:14 +0000
> > +++ lib/canonical/launchpad/scripts/hwdbsubmissions.py 2009-10-15
> 13:59:33 +0000
> > @@ -1644,7 +1644,7 @@
> > return None
> > pci_subclass = scsi_controller.pci_subclass
> > return self.pci_storage_subclass_hwbus.get(pci_subclass)
> > - elif scsi_controller_bus == 'usb':
> > + elif scsi_controller_bus in ('usb', 'usb_interface'):
> > # USB storage devices have the following HAL device hierarchy:
> > # - HAL node for the USB device. info.bus == 'usb_device',
> > # device class == 0, device subclass == 0
> > @@ -1703,6 +1703,12 @@
> > return HWBus.PCI
> >
> > @property
> > + def is_root_device(self):
> > + """Return True is this is the root node of all devicese, else
> False.
> > + """
> > + raise NotImplementedError
> > +
> > + @property
> > def raw_bus(self):
> > """Return the device bus as specified by HAL or udev."""
> > raise NotImplementedError
> > @@ -1719,11 +1725,11 @@
> > if result is not None:
> > return result
> >
> > - if device_bus == 'scsi':
> > + if device_bus in ('scsi', 'scsi_device'):
> > return self.translateScsiBus()
> > elif device_bus == 'pci':
> > return self.translatePciBus()
> > - elif self.udi == ROOT_UDI:
> > + elif self.is_root_device:
> > # The computer itself. In Hardy, HAL provides no info.bus
> > # for the machine itself; older versions set info.bus to
> > # 'unknown', hence it is better to use the machine's
> > @@ -1731,7 +1737,7 @@
> > return HWBus.SYSTEM
> > else:
> > self.parser._logWarning(
> > - 'Unknown bus %r for device %s' % (device_bus, self.udi))
> > + 'Unknown bus %r for device %s' % (device_bus,
> self.device_id))
> > return None
> >
> > @property
> > @@ -2275,6 +2281,11 @@
> > return result
> > return self.getProperty('info.subsystem')
> >
> > + @property
> > + def is_root_device(self):
> > + """See `BaseDevice`."""
> > + return self.udi == ROOT_UDI
> > +
> > def getVendorOrProduct(self, type_):
> > """Return the vendor or product of this device.
> >
> > @@ -2547,7 +2558,7 @@
> > # DEVTYPE. DEVTYPE is preferable.
> > # The root device has the subsystem/bus value "acpi", which
> > # is a bit nonsensical.
> > - if self.device_id == UDEV_ROOT_PATH:
> > + if self.is_root_device:
> > return None
> > properties = self.udev['E']
> > devtype = properties.get('DEVTYPE')
> > @@ -2555,6...

Read more...

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-13 21:03:31 +0000
3+++ lib/canonical/launchpad/scripts/hwdbsubmissions.py 2009-10-15 17:00:35 +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 in ('usb', 'usb_interface'):
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@@ -1706,6 +1703,12 @@
80 return HWBus.PCI
81
82 @property
83+ def is_root_device(self):
84+ """Return True is this is the root node of all devicese, else False.
85+ """
86+ raise NotImplementedError
87+
88+ @property
89 def raw_bus(self):
90 """Return the device bus as specified by HAL or udev."""
91 raise NotImplementedError
92@@ -1722,11 +1725,11 @@
93 if result is not None:
94 return result
95
96- if device_bus == 'scsi':
97+ if device_bus in ('scsi', 'scsi_device'):
98 return self.translateScsiBus()
99 elif device_bus == 'pci':
100 return self.translatePciBus()
101- elif self.udi == ROOT_UDI:
102+ elif self.is_root_device:
103 # The computer itself. In Hardy, HAL provides no info.bus
104 # for the machine itself; older versions set info.bus to
105 # 'unknown', hence it is better to use the machine's
106@@ -1734,7 +1737,7 @@
107 return HWBus.SYSTEM
108 else:
109 self.parser._logWarning(
110- 'Unknown bus %r for device %s' % (device_bus, self.udi))
111+ 'Unknown bus %r for device %s' % (device_bus, self.device_id))
112 return None
113
114 @property
115@@ -2278,6 +2281,11 @@
116 return result
117 return self.getProperty('info.subsystem')
118
119+ @property
120+ def is_root_device(self):
121+ """See `BaseDevice`."""
122+ return self.udi == ROOT_UDI
123+
124 def getVendorOrProduct(self, type_):
125 """Return the vendor or product of this device.
126
127@@ -2357,6 +2365,27 @@
128 """See `BaseDevice`."""
129 return self.getVendorOrProductID('product')
130
131+ @property
132+ def scsi_controller(self):
133+ """See `BaseDevice`."""
134+ # While SCSI devices from valid submissions should have a
135+ # parent and a grandparent, we can't be sure for bogus or
136+ # broken submissions.
137+ if self.raw_bus != 'scsi':
138+ return None
139+ parent = self.parent
140+ if parent is None:
141+ self.parser._logWarning(
142+ 'Found SCSI device without a parent: %s.' % self.device_id)
143+ return None
144+ grandparent = parent.parent
145+ if grandparent is None:
146+ self.parser._logWarning(
147+ 'Found SCSI device without a grandparent: %s.'
148+ % self.device_id)
149+ return None
150+ return grandparent
151+
152
153 class UdevDevice(BaseDevice):
154 """The representation of a udev device node."""
155@@ -2529,7 +2558,7 @@
156 # DEVTYPE. DEVTYPE is preferable.
157 # The root device has the subsystem/bus value "acpi", which
158 # is a bit nonsensical.
159- if self.device_id == UDEV_ROOT_PATH:
160+ if self.is_root_device:
161 return None
162 properties = self.udev['E']
163 devtype = properties.get('DEVTYPE')
164@@ -2537,6 +2566,11 @@
165 return devtype
166 return properties.get('SUBSYSTEM')
167
168+ @property
169+ def is_root_device(self):
170+ """See `BaseDevice`."""
171+ return self.udev['P'] == UDEV_ROOT_PATH
172+
173 def getVendorOrProduct(self, type_):
174 """Return the vendor or product of this device.
175
176@@ -2547,7 +2581,7 @@
177 'Unexpected value of type_: %r' % type_)
178
179 bus = self.raw_bus
180- if self.device_id == UDEV_ROOT_PATH:
181+ if self.is_root_device:
182 # udev does not known about any product information for
183 # the root device. We use DMI data instead.
184 return self.root_device_ids[type_]
185@@ -2587,7 +2621,7 @@
186 'Unexpected value of type_: %r' % type_)
187
188 bus = self.raw_bus
189- if self.device_id == UDEV_ROOT_PATH:
190+ if self.is_root_device:
191 # udev does not known about any product information for
192 # the root device. We use DMI data instead.
193 if type_ == 'vendor':
194@@ -2617,6 +2651,29 @@
195 """See `BaseDevice`."""
196 return self.getVendorOrProductID('product')
197
198+ @property
199+ def driver_name(self):
200+ """See `BaseDevice`."""
201+ return self.udev['E'].get('DRIVER')
202+
203+ @property
204+ def scsi_controller(self):
205+ """See `BaseDevice`."""
206+ if self.raw_bus != 'scsi_device':
207+ return None
208+
209+ # While SCSI devices from valid submissions should have four
210+ # ancestors, we can't be sure for bogus or broken submissions.
211+ try:
212+ controller = self.parent.parent.parent.parent
213+ except AttributeError:
214+ controller = None
215+ if controller is None:
216+ self.parser._logWarning(
217+ 'Found a SCSI device without a sufficient number of '
218+ 'ancestors: %s' % self.device_id)
219+ return None
220+ return controller
221
222 class ProcessingLoop(object):
223 """An `ITunableLoop` for processing HWDB submissions."""
224
225=== modified file 'lib/canonical/launchpad/scripts/tests/test_hwdb_submission_processing.py'
226--- lib/canonical/launchpad/scripts/tests/test_hwdb_submission_processing.py 2009-10-13 21:02:35 +0000
227+++ lib/canonical/launchpad/scripts/tests/test_hwdb_submission_processing.py 2009-10-15 17:00:35 +0000
228@@ -539,6 +539,214 @@
229 'HAL property info.bus.')
230
231
232+ def test_HALDevice_scsi_controller_usb_storage_device(self):
233+ """test of HALDevice.scsi_controller.
234+
235+ The physical device is a USB storage device.
236+ """
237+ devices = [
238+ # The main node of the USB storage device.
239+ {
240+ 'id': 1,
241+ 'udi': self.UDI_USB_STORAGE,
242+ 'properties': {
243+ 'info.bus': ('usb_device', 'str'),
244+ },
245+ },
246+ # The storage interface of the USB device.
247+ {
248+ 'id': 2,
249+ 'udi': self.UDI_USB_STORAGE_IF0,
250+ 'properties': {
251+ 'info.bus': ('usb', 'str'),
252+ 'info.parent': (self.UDI_USB_STORAGE, 'str'),
253+ },
254+ },
255+ # The fake SCSI host of the storage device. Note that HAL does
256+ # _not_ provide the info.bus property.
257+ {
258+ 'id': 3,
259+ 'udi': self.UDI_USB_STORAGE_SCSI_HOST,
260+ 'properties': {
261+ 'info.parent': (self.UDI_USB_STORAGE_IF0, 'str'),
262+ },
263+ },
264+ # The fake SCSI disk.
265+ {
266+ 'id': 3,
267+ 'udi': self.UDI_USB_STORAGE_SCSI_DEVICE,
268+ 'properties': {
269+ 'info.bus': ('scsi', 'str'),
270+ 'info.parent': (self.UDI_USB_STORAGE_SCSI_HOST, 'str'),
271+ },
272+ },
273+ ]
274+ parsed_data = {
275+ 'hardware': {
276+ 'hal': {
277+ 'devices': devices,
278+ },
279+ },
280+ }
281+
282+ parser = SubmissionParser()
283+ parser.buildDeviceList(parsed_data)
284+
285+ usb_fake_scsi_disk = parser.hal_devices[
286+ self.UDI_USB_STORAGE_SCSI_DEVICE]
287+ usb_main_device = parser.hal_devices[self.UDI_USB_STORAGE_IF0]
288+ self.assertEqual(usb_main_device, usb_fake_scsi_disk.scsi_controller)
289+
290+ def test_HALDevice_scsi_controller_pci_controller(self):
291+ """test of HALDevice.scsi_controller.
292+
293+ Variant for a SCSI device connected to a PCI controller.
294+ """
295+ devices = [
296+ # The PCI host controller.
297+ {
298+ 'id': 1,
299+ 'udi': self.UDI_SATA_CONTROLLER,
300+ 'properties': {
301+ 'info.bus': ('pci', 'str'),
302+ 'pci.device_class': (PCI_CLASS_STORAGE, 'int'),
303+ 'pci.device_subclass': (PCI_SUBCLASS_STORAGE_SATA,
304+ 'int'),
305+ },
306+ },
307+ # The (fake or real) SCSI host of the storage device.
308+ {
309+ 'id': 2,
310+ 'udi': self.UDI_SATA_CONTROLLER_SCSI,
311+ 'properties': {
312+ 'info.parent': (self.UDI_SATA_CONTROLLER, 'str'),
313+ },
314+ },
315+ # The (possibly fake) SCSI disk.
316+ {
317+ 'id': 3,
318+ 'udi': self.UDI_SATA_DISK,
319+ 'properties': {
320+ 'info.bus': ('scsi', 'str'),
321+ 'info.parent': (self.UDI_SATA_CONTROLLER_SCSI, 'str'),
322+ },
323+ },
324+ ]
325+ parsed_data = {
326+ 'hardware': {
327+ 'hal': {
328+ 'devices': devices,
329+ },
330+ },
331+ }
332+
333+ parser = SubmissionParser()
334+ parser.buildDeviceList(parsed_data)
335+
336+ scsi_device = parser.hal_devices[self.UDI_SATA_DISK]
337+ controller = parser.hal_devices[self.UDI_SATA_CONTROLLER]
338+ self.assertEqual(controller, scsi_device.scsi_controller)
339+
340+ def test_HALDevice_scsi_controller_non_scsi_device(self):
341+ """test of HALDevice.scsi_controller.
342+
343+ Variant for non-SCSI devices.
344+ """
345+ devices = [
346+ {
347+ 'id': 1,
348+ 'udi': self.UDI_COMPUTER,
349+ 'properties': {},
350+ },
351+ ]
352+ parsed_data = {
353+ 'hardware': {
354+ 'hal': {
355+ 'devices': devices,
356+ },
357+ },
358+ }
359+
360+ parser = SubmissionParser()
361+ parser.buildDeviceList(parsed_data)
362+
363+ device = parser.hal_devices[self.UDI_COMPUTER]
364+ self.assertEqual(None, device.scsi_controller)
365+
366+ def test_HALDevice_scsi_controller_no_grandparent(self):
367+ """test of HALDevice.scsi_controller.
368+
369+ Variant for a SCSI device without a grandparent device.
370+ """
371+ devices = [
372+ # The (fake or real) SCSI host of the storage device.
373+ {
374+ 'id': 1,
375+ 'udi': self.UDI_SATA_CONTROLLER_SCSI,
376+ 'properties': {},
377+ },
378+ # The (possibly fake) SCSI disk.
379+ {
380+ 'id': 2,
381+ 'udi': self.UDI_SATA_DISK,
382+ 'properties': {
383+ 'info.bus': ('scsi', 'str'),
384+ 'info.parent': (self.UDI_SATA_CONTROLLER_SCSI, 'str'),
385+ },
386+ },
387+ ]
388+ parsed_data = {
389+ 'hardware': {
390+ 'hal': {
391+ 'devices': devices,
392+ },
393+ },
394+ }
395+
396+ parser = SubmissionParser(self.log)
397+ parser.submission_key = 'SCSI device without grandparent device'
398+ parser.buildDeviceList(parsed_data)
399+
400+ scsi_device = parser.hal_devices[self.UDI_SATA_DISK]
401+ self.assertEqual(None, scsi_device.scsi_controller)
402+ self.assertWarningMessage(
403+ parser.submission_key,
404+ "Found SCSI device without a grandparent: %s."
405+ % self.UDI_SATA_DISK)
406+
407+ def test_HALDevice_scsi_controller_no_parent(self):
408+ """test of HALDevice.scsi_controller.
409+
410+ Variant for a SCSI device without a parent device.
411+ """
412+ devices = [
413+ # The (possibly fake) SCSI disk.
414+ {
415+ 'id': 1,
416+ 'udi': self.UDI_SATA_DISK,
417+ 'properties': {
418+ 'info.bus': ('scsi', 'str'),
419+ },
420+ },
421+ ]
422+ parsed_data = {
423+ 'hardware': {
424+ 'hal': {
425+ 'devices': devices,
426+ },
427+ },
428+ }
429+
430+ parser = SubmissionParser(self.log)
431+ parser.submission_key = 'SCSI device without parent device'
432+ parser.buildDeviceList(parsed_data)
433+
434+ scsi_device = parser.hal_devices[self.UDI_SATA_DISK]
435+ self.assertEqual(None, scsi_device.scsi_controller)
436+ self.assertWarningMessage(
437+ parser.submission_key,
438+ "Found SCSI device without a parent: %s." % self.UDI_SATA_DISK)
439+
440 def testHALDeviceGetRealBus(self):
441 """Test of HALDevice.real_bus, generic case.
442
443@@ -965,6 +1173,51 @@
444 parser.submission_key,
445 "Unknown bus 'nonsense' for device " + self.UDI_PCCARD_DEVICE)
446
447+ def test_HALDevice_is_root_device_for_root_device(self):
448+ """Test of HALDevice.is_root_device for the root device."""
449+ devices = [
450+ {
451+ 'id': 1,
452+ 'udi': self.UDI_COMPUTER,
453+ 'properties': {},
454+ },
455+ ]
456+ parsed_data = {
457+ 'hardware': {
458+ 'hal': {
459+ 'devices': devices,
460+ },
461+ },
462+ }
463+
464+ parser = SubmissionParser()
465+ parser.submission_key = 'Test of HALDevice.is_root_device'
466+ parser.buildDeviceList(parsed_data)
467+ self.assertTrue(parser.hal_devices[self.UDI_COMPUTER].is_root_device)
468+
469+ def test_HALDevice_is_root_device_for_non_root_device(self):
470+ """Test of HALDevice.is_root_device for a non-root device."""
471+ devices = [
472+ {
473+ 'id': 1,
474+ 'udi': self.UDI_PCCARD_DEVICE,
475+ 'properties': {},
476+ },
477+ ]
478+ parsed_data = {
479+ 'hardware': {
480+ 'hal': {
481+ 'devices': devices,
482+ },
483+ },
484+ }
485+
486+ parser = SubmissionParser()
487+ parser.submission_key = 'Test of HALDevice.is_root_device'
488+ parser.buildDeviceList(parsed_data)
489+ self.assertFalse(
490+ parser.hal_devices[self.UDI_PCCARD_DEVICE].is_root_device)
491+
492 def renameInfoBusToInfoSubsystem(self, devices):
493 """Rename the property info.bus in a device list to info.subsystem.
494
495@@ -2585,65 +2838,260 @@
496 'property not treated as a real device.')
497
498
499-class TestUdevDevice(TestCase):
500+class TestUdevDevice(TestCaseHWDB):
501 """Tests of class UdevDevice."""
502
503- layer = BaseLayer
504-
505- root_device = {
506- 'P': '/devices/LNXSYSTM:00',
507- 'E': {
508- 'UDEV_LOG': '3',
509- 'DEVPATH': '/devices/LNXSYSTM:00',
510- 'MODALIAS': 'acpi:LNXSYSTM:',
511- 'SUBSYSTEM': 'acpi',
512- }
513- }
514-
515- root_device_dmi_data = {
516- '/sys/class/dmi/id/sys_vendor': 'FUJITSU SIEMENS',
517- '/sys/class/dmi/id/product_name': 'LIFEBOOK E8210',
518- }
519-
520- pci_device_data = {
521- 'P': '/devices/pci0000:00/0000:00:1f.2',
522- 'E': {
523- 'PCI_CLASS': '10602',
524- 'PCI_ID': '8086:27C5',
525- 'PCI_SUBSYS_ID': '10CF:1387',
526- 'PCI_SLOT_NAME': '0000:00:1f.2',
527- 'SUBSYSTEM': 'pci',
528- }
529- }
530-
531- usb_device_data = {
532- 'P': '/devices/pci0000:00/0000:00:1d.1/usb3/3-2',
533- 'E': {
534- 'SUBSYSTEM': 'usb',
535- 'DEVTYPE': 'usb_device',
536- 'PRODUCT': '46d/a01/1013',
537- 'TYPE': '0/0/0',
538- },
539- }
540-
541- scsi_device_data = {
542- 'P': '/devices/pci0000:00/0000:00:1f.1/host4/target4:0:0/4:0:0:0',
543- 'E': {
544- 'SUBSYSTEM': 'scsi',
545- 'DEVTYPE': 'scsi_device',
546- },
547- }
548-
549- scsi_device_sysfs_data = {
550- 'vendor': 'MATSHITA',
551- 'model': 'DVD-RAM UJ-841S',
552- 'type': '5',
553- }
554-
555- no_subsystem_device_data = {
556- 'P': '/devices/pnp0/00:00',
557- 'E': {}
558- }
559+ def setUp(self):
560+ """Setup the test environment."""
561+ super(TestUdevDevice, self).setUp()
562+ self.root_device = {
563+ 'P': '/devices/LNXSYSTM:00',
564+ 'E': {
565+ 'UDEV_LOG': '3',
566+ 'DEVPATH': '/devices/LNXSYSTM:00',
567+ 'MODALIAS': 'acpi:LNXSYSTM:',
568+ 'SUBSYSTEM': 'acpi',
569+ }
570+ }
571+
572+ self.root_device_dmi_data = {
573+ '/sys/class/dmi/id/sys_vendor': 'FUJITSU SIEMENS',
574+ '/sys/class/dmi/id/product_name': 'LIFEBOOK E8210',
575+ }
576+
577+ self.pci_device_data = {
578+ 'P': '/devices/pci0000:00/0000:00:1f.2',
579+ 'E': {
580+ 'PCI_CLASS': '10602',
581+ 'PCI_ID': '8086:27C5',
582+ 'PCI_SUBSYS_ID': '10CF:1387',
583+ 'PCI_SLOT_NAME': '0000:00:1f.2',
584+ 'SUBSYSTEM': 'pci',
585+ 'DRIVER': 'ahci',
586+ }
587+ }
588+
589+ self.usb_device_data = {
590+ 'P': '/devices/pci0000:00/0000:00:1d.1/usb3/3-2',
591+ 'E': {
592+ 'SUBSYSTEM': 'usb',
593+ 'DEVTYPE': 'usb_device',
594+ 'PRODUCT': '46d/a01/1013',
595+ 'TYPE': '0/0/0',
596+ 'DRIVER': 'usb',
597+ },
598+ }
599+
600+ self.pci_pccard_bridge = {
601+ 'P': '/devices/pci0000:00/0000:00:1e.0/0000:08:03.0',
602+ 'E': {
603+ 'DRIVER': 'yenta_cardbus',
604+ 'PCI_CLASS': '60700',
605+ 'PCI_ID': '1217:7134',
606+ 'PCI_SUBSYS_ID': '10CF:131E',
607+ 'PCI_SLOT_NAME': '0000:08:03.0',
608+ 'SUBSYSTEM': 'pci',
609+ }
610+ }
611+
612+ self.pccard_scsi_controller_data = {
613+ 'P': '/devices/pci0000:00/0000:00:1e.0/0000:08:03.0/0000:09:00.0',
614+ 'E': {
615+ 'DRIVER': 'aic7xxx',
616+ 'PCI_CLASS': '10000',
617+ 'PCI_ID': '9004:6075',
618+ 'PCI_SUBSYS_ID': '9004:7560',
619+ 'SUBSYSTEM': 'pci',
620+ },
621+ }
622+
623+ self.pci_scsi_controller_scsi_side_1 = {
624+ 'P': ('/devices/pci0000:00/0000:00:1e.0/0000:08:03.0/'
625+ '0000:09:00.0/host6'),
626+ 'E': {
627+ 'DEVTYPE': 'scsi_host',
628+ 'SUBSYSTEM': 'scsi',
629+ },
630+ }
631+
632+ self.pci_bridge_pccard_hierarchy_data = [
633+ {'udev_data': self.root_device},
634+ {'udev_data': self.pci_pccard_bridge},
635+ {'udev_data': self.pccard_scsi_controller_data},
636+ ]
637+
638+ self.pci_scsi_controller_scsi_side_2 = {
639+ 'P': ('/devices/pci0000:00/0000:00:1e.0/0000:08:03.0/'
640+ '0000:09:00.0/host6/scsi_host/host6'),
641+ 'E': {
642+ 'SUBSYSTEM': 'scsi_host',
643+ },
644+ }
645+
646+ self.scsi_scanner_target_data = {
647+ 'P': ('/devices/pci0000:00/0000:00:1e.0/0000:08:03.0/'
648+ '0000:09:00.0/host6/target6:0:1'),
649+ 'E': {
650+ 'DEVTYPE': 'scsi_target',
651+ 'SUBSYSTEM': 'scsi'
652+ },
653+ }
654+
655+ self.scsi_scanner_device_data = {
656+ 'P': ('/devices/pci0000:00/0000:00:1e.0/0000:08:03.0/'
657+ '0000:09:00.0/host6/target6:0:1/6:0:1:0'),
658+ 'E': {
659+ 'DEVTYPE': 'scsi_device',
660+ 'SUBSYSTEM': 'scsi',
661+ },
662+ }
663+
664+ self.scsi_scanner_device_sysfs_data = {
665+ 'vendor': 'FUJITSU',
666+ 'model': 'fi-5120Cdj',
667+ 'type': '6',
668+ }
669+
670+ self.scsi_device_hierarchy_data = [
671+ {'udev_data': self.pccard_scsi_controller_data},
672+ {'udev_data': self.pci_scsi_controller_scsi_side_1},
673+ {'udev_data': self.pci_scsi_controller_scsi_side_2},
674+ {'udev_data': self.scsi_scanner_target_data},
675+ {
676+ 'udev_data': self.scsi_scanner_device_data,
677+ 'sysfs_data': self.scsi_scanner_device_sysfs_data,
678+ },
679+ ]
680+
681+ self.pci_ide_controller = {
682+ 'P': '/devices/pci0000:00/0000:00:1f.1',
683+ 'E': {
684+ 'DRIVER': 'ata_piix',
685+ 'PCI_CLASS': '1018A',
686+ 'PCI_ID': '8086:27DF',
687+ 'PCI_SUBSYS_ID': '10CF:1385',
688+ 'SUBSYSTEM': 'pci',
689+ },
690+ }
691+
692+ self.pci_ide_controller_scsi_side_1 = {
693+ 'P': '/devices/pci0000:00/0000:00:1f.1/host4',
694+ 'E': {
695+ 'DEVTYPE': 'scsi_host',
696+ 'SUBSYSTEM': 'scsi',
697+ },
698+ }
699+
700+ self.pci_ide_controller_scsi_side_2 = {
701+ 'P': '/devices/pci0000:00/0000:00:1f.1/host4/scsi_host/host4',
702+ 'E': {
703+ 'SUBSYSTEM': 'scsi_host',
704+ },
705+ }
706+
707+ self.ide_device_target_data = {
708+ 'P': '/devices/pci0000:00/0000:00:1f.1/host4/target4:0:0',
709+ 'E': {
710+ 'DEVTYPE': 'scsi_target',
711+ 'SUBSYSTEM': 'scsi',
712+ },
713+ }
714+
715+ self.ide_cdrom_device_data = {
716+ 'P': ('/devices/pci0000:00/0000:00:1f.1/host4/target4:0:0/'
717+ '4:0:0:0'),
718+ 'E': {
719+ 'SUBSYSTEM': 'scsi',
720+ 'DEVTYPE': 'scsi_device',
721+ 'DRIVER': 'sr',
722+ },
723+ }
724+
725+ self.ide_cdrom_device_sysfs_data = {
726+ 'vendor': 'MATSHITA',
727+ 'model': 'DVD-RAM UJ-841S',
728+ 'type': '5',
729+ }
730+
731+ self.ide_device_hierarchy_data = [
732+ {'udev_data': self.pci_ide_controller},
733+ {'udev_data': self.pci_ide_controller_scsi_side_1},
734+ {'udev_data': self.pci_ide_controller_scsi_side_2},
735+ {'udev_data': self.ide_device_target_data},
736+ {
737+ 'udev_data': self.ide_cdrom_device_data,
738+ 'sysfs_data': self.ide_cdrom_device_sysfs_data,
739+ },
740+ ]
741+
742+ self.usb_storage_usb_interface = {
743+ 'P': '/devices/pci0000:00/0000:00:1d.7/usb1/1-1/1-1:1.0',
744+ 'E': {
745+ 'DRIVER': 'usb-storage',
746+ 'PRODUCT': '1307/163/100',
747+ 'TYPE': '0/0/0',
748+ 'INTERFACE': '8/6/80',
749+ 'DEVTYPE': 'usb_interface',
750+ 'SUBSYSTEM': 'usb',
751+ },
752+ }
753+
754+ self.usb_storage_scsi_host_1 = {
755+ 'P': '/devices/pci0000:00/0000:00:1d.7/usb1/1-1/1-1:1.0/host7',
756+ 'E': {
757+ 'DEVTYPE': 'scsi_host',
758+ 'SUBSYSTEM': 'scsi',
759+ },
760+ }
761+
762+ self.usb_storage_scsi_host_2 = {
763+ 'P': ('/devices/pci0000:00/0000:00:1d.7/usb1/1-1/1-1:1.0/host7/'
764+ 'scsi_host/host7'),
765+ 'E': {
766+ 'SUBSYSTEM': 'scsi_host',
767+ },
768+ }
769+
770+ self.usb_storage_scsi_target = {
771+ 'P': ('/devices/pci0000:00/0000:00:1d.7/usb1/1-1/1-1:1.0/host7/'
772+ 'target7:0:0'),
773+ 'E': {
774+ 'DEVTYPE': 'scsi_target',
775+ 'SUBSYSTEM': 'scsi',
776+ },
777+ }
778+
779+ self.usb_storage_scsi_device = {
780+ 'P': ('/devices/pci0000:00/0000:00:1d.7/usb1/1-1/1-1:1.0/host7/'
781+ 'target7:0:0/7:0:0:0'),
782+ 'E': {
783+ 'DEVTYPE': 'scsi_device',
784+ 'DRIVER': 'sd',
785+ 'SUBSYSTEM': 'scsi',
786+ },
787+ }
788+
789+ self.usb_storage_scsi_device_sysfs = {
790+ 'vendor': 'Ut163',
791+ 'model': 'USB2FlashStorage',
792+ 'type': '0',
793+ }
794+
795+ self.usb_storage_hierarchy_data = [
796+ {'udev_data': self.usb_storage_usb_interface},
797+ {'udev_data': self.usb_storage_scsi_host_1},
798+ {'udev_data': self.usb_storage_scsi_host_2},
799+ {'udev_data': self.usb_storage_scsi_target},
800+ {
801+ 'udev_data': self.usb_storage_scsi_device,
802+ 'sysfs_data': self.usb_storage_scsi_device_sysfs,
803+ },
804+ ]
805+
806+ self.no_subsystem_device_data = {
807+ 'P': '/devices/pnp0/00:00',
808+ 'E': {}
809+ }
810
811 def test_device_id(self):
812 """Test of UdevDevice.device_id."""
813@@ -2790,7 +3238,8 @@
814 def test_is_scsi_device(self):
815 """Test of UdevDevice.is_scsi_device."""
816 device = UdevDevice(
817- None, self.scsi_device_data, self.scsi_device_sysfs_data)
818+ None, self.scsi_scanner_device_data,
819+ self.scsi_scanner_device_sysfs_data)
820 self.assertTrue(device.is_scsi_device)
821
822 device = UdevDevice(None, self.root_device)
823@@ -2799,16 +3248,18 @@
824 def test_scsi_vendor(self):
825 """Test of UdevDevice.scsi_vendor."""
826 device = UdevDevice(
827- None, self.scsi_device_data, self.scsi_device_sysfs_data, None)
828- self.assertEqual('MATSHITA', device.scsi_vendor)
829+ None, self.scsi_scanner_device_data,
830+ self.scsi_scanner_device_sysfs_data)
831+ self.assertEqual('FUJITSU', device.scsi_vendor)
832 device = UdevDevice(None, self.root_device)
833 self.assertEqual(None, device.scsi_vendor)
834
835 def test_scsi_model(self):
836 """Test of UdevDevice.scsi_model."""
837 device = UdevDevice(
838- None, self.scsi_device_data, self.scsi_device_sysfs_data)
839- self.assertEqual('DVD-RAM UJ-841S', device.scsi_model)
840+ None, self.scsi_scanner_device_data,
841+ self.scsi_scanner_device_sysfs_data)
842+ self.assertEqual('fi-5120Cdj', device.scsi_model)
843
844 device = UdevDevice(None, self.root_device)
845 self.assertEqual(None, device.scsi_model)
846@@ -2827,6 +3278,14 @@
847 device = UdevDevice(None, self.no_subsystem_device_data)
848 self.assertEqual(None, device.raw_bus)
849
850+ def test_is_root_device(self):
851+ """Test of UdevDevice.is_root_device."""
852+ device = UdevDevice(None, self.root_device)
853+ self.assertTrue(device.is_root_device)
854+
855+ device = UdevDevice(None, self.pci_device_data)
856+ self.assertFalse(device.is_root_device)
857+
858 def test_getVendorOrProduct(self):
859 """Test of UdevDevice.getVendorOrProduct()."""
860 device = UdevDevice(
861@@ -2847,10 +3306,10 @@
862 self.assertEqual('Unknown', device.getVendorOrProduct('product'))
863
864 device = UdevDevice(
865- None, self.scsi_device_data, self.scsi_device_sysfs_data)
866- self.assertEqual('MATSHITA', device.getVendorOrProduct('vendor'))
867- self.assertEqual(
868- 'DVD-RAM UJ-841S', device.getVendorOrProduct('product'))
869+ None, self.scsi_scanner_device_data,
870+ self.scsi_scanner_device_sysfs_data)
871+ self.assertEqual('FUJITSU', device.getVendorOrProduct('vendor'))
872+ self.assertEqual('fi-5120Cdj', device.getVendorOrProduct('product'))
873
874 device = UdevDevice(None, self.no_subsystem_device_data)
875 self.assertEqual(None, device.getVendorOrProduct('vendor'))
876@@ -2888,10 +3347,10 @@
877 self.assertEqual(0xa01, device.getVendorOrProductID('product'))
878
879 device = UdevDevice(
880- None, self.scsi_device_data, self.scsi_device_sysfs_data)
881- self.assertEqual('MATSHITA', device.getVendorOrProductID('vendor'))
882- self.assertEqual(
883- 'DVD-RAM UJ-841S', device.getVendorOrProductID('product'))
884+ None, self.scsi_scanner_device_data,
885+ self.scsi_scanner_device_sysfs_data)
886+ self.assertEqual('FUJITSU', device.getVendorOrProductID('vendor'))
887+ self.assertEqual('fi-5120Cdj', device.getVendorOrProductID('product'))
888
889 device = UdevDevice(
890 None, self.no_subsystem_device_data)
891@@ -2910,6 +3369,179 @@
892 None, self.root_device, None, self.root_device_dmi_data)
893 self.assertEqual('LIFEBOOK E8210', device.product_id)
894
895+ def test_vendor_id_for_db(self):
896+ """Test of UdevDevice.vendor_id_for_db."""
897+ device = UdevDevice(
898+ None, self.root_device, None, self.root_device_dmi_data)
899+ self.assertEqual('FUJITSU SIEMENS', device.vendor_id_for_db)
900+
901+ device = UdevDevice(None, self.pci_device_data)
902+ self.assertEqual('0x8086', device.vendor_id_for_db)
903+
904+ device = UdevDevice(None, self.usb_device_data)
905+ self.assertEqual('0x046d', device.vendor_id_for_db)
906+
907+ device = UdevDevice(
908+ None, self.scsi_scanner_device_data,
909+ self.scsi_scanner_device_sysfs_data)
910+ self.assertEqual('FUJITSU ', device.vendor_id_for_db)
911+
912+ def test_product_id_for_db(self):
913+ """Test of UdevDevice.product_id_for_db."""
914+ device = UdevDevice(
915+ None, self.root_device, None, self.root_device_dmi_data)
916+ self.assertEqual('LIFEBOOK E8210', device.product_id_for_db)
917+
918+ device = UdevDevice(None, self.pci_device_data)
919+ self.assertEqual('0x27c5', device.product_id_for_db)
920+
921+ device = UdevDevice(None, self.usb_device_data)
922+ self.assertEqual('0x0a01', device.product_id_for_db)
923+
924+ device = UdevDevice(
925+ None, self.scsi_scanner_device_data,
926+ self.scsi_scanner_device_sysfs_data)
927+ self.assertEqual('fi-5120Cdj ', device.product_id_for_db)
928+
929+ def test_driver_name(self):
930+ """Test of UdevDevice.driver_name."""
931+ device = UdevDevice(None, self.pci_device_data)
932+ self.assertEqual('ahci', device.driver_name)
933+
934+ device = UdevDevice(
935+ None, self.root_device, None, self.root_device_dmi_data)
936+ self.assertEqual(None, device.driver_name)
937+
938+ def buildUdevDeviceHierarchy(self, device_data, parser=None):
939+ """Build a UdevDevice hierarchy from device_data.
940+
941+ :param device_data: A sequence of arguments that are passed
942+ to the UdevDevice constructor. Each element must be a
943+ dictionary that can be used as a **kwargs argument.
944+
945+ Element N of the sequence is the parent of element N+1.
946+ :param parser: A SubmissionParser instance to be passed to
947+ the constructor of UdevDevice.
948+ """
949+ parent = None
950+ devices = []
951+ for kwargs in device_data:
952+ device = UdevDevice(parser, **kwargs)
953+ devices.append(device)
954+ if parent is not None:
955+ parent.addChild(device)
956+ parent = device
957+ return devices
958+
959+ def test_scsi_controller(self):
960+ """Test of UdevDevice.scsi_controller for a PCI controller."""
961+ devices = self.buildUdevDeviceHierarchy(
962+ self.scsi_device_hierarchy_data)
963+ controller = devices[0]
964+ scsi_device = devices[-1]
965+ self.assertEqual(controller, scsi_device.scsi_controller)
966+
967+ def test_scsi_controller_insufficient_anchestors(self):
968+ """Test of UdevDevice.scsi_controller for a PCI controller.
969+
970+ If a SCSI device does not have a sufficient number of ancestors,
971+ UdevDevice.scsi_controller returns None.
972+ """
973+ parser = SubmissionParser(self.log)
974+ parser.submission_key = 'UdevDevice.scsi_controller ancestor missing'
975+ devices = self.buildUdevDeviceHierarchy(
976+ self.scsi_device_hierarchy_data[1:], parser)
977+ scsi_device = devices[-1]
978+ self.assertEqual(None, scsi_device.scsi_controller)
979+ self.assertWarningMessage(
980+ parser.submission_key,
981+ 'Found a SCSI device without a sufficient number of ancestors: '
982+ '/devices/pci0000:00/0000:00:1e.0/0000:08:03.0/0000:09:00.0/'
983+ 'host6/target6:0:1/6:0:1:0')
984+
985+ def test_scsi_controller_no_scsi_device(self):
986+ """Test of UdevDevice.scsi_controller for a PCI controller.
987+
988+ For non-SCSI devices, this property is None.
989+ """
990+ device = UdevDevice(None, self.pci_device_data)
991+ self.assertEqual(None, device.scsi_controller)
992+
993+ def test_translateScsiBus_real_scsi_device(self):
994+ """Test of UdevDevice.translateScsiBus() with a real SCSI device."""
995+ devices = self.buildUdevDeviceHierarchy(
996+ self.scsi_device_hierarchy_data)
997+ scsi_device = devices[-1]
998+ self.assertEqual(
999+ HWBus.SCSI, scsi_device.translateScsiBus())
1000+
1001+ def test_translateScsiBus_ide_device(self):
1002+ """Test of UdevDevice.translateScsiBus() with an IDE device."""
1003+ devices = self.buildUdevDeviceHierarchy(
1004+ self.ide_device_hierarchy_data)
1005+ ide_device = devices[-1]
1006+ self.assertEqual(HWBus.IDE, ide_device.translateScsiBus())
1007+
1008+ def test_translateScsiBus_usb_device(self):
1009+ """Test of UdevDevice.translateScsiBus() with a USB device."""
1010+ devices = self.buildUdevDeviceHierarchy(
1011+ self.usb_storage_hierarchy_data)
1012+ usb_scsi_device = devices[-1]
1013+ self.assertEqual(None, usb_scsi_device.translateScsiBus())
1014+
1015+ def test_translateScsiBus_non_scsi_device(self):
1016+ """Test of UdevDevice.translateScsiBus() for a non-SCSI device."""
1017+ device = UdevDevice(None, self.root_device)
1018+ self.assertEqual(None, device.translateScsiBus())
1019+
1020+ def test_translatePciBus(self):
1021+ """Test of UdevDevice.translatePciBus()."""
1022+ devices = self.buildUdevDeviceHierarchy(
1023+ self.pci_bridge_pccard_hierarchy_data)
1024+ pci_device = devices[1]
1025+ pccard_device = devices[2]
1026+ self.assertEqual(HWBus.PCI, pci_device.translatePciBus())
1027+ self.assertEqual(HWBus.PCCARD, pccard_device.translatePciBus())
1028+
1029+ def test_real_bus_usb_device(self):
1030+ """Test of UdevDevice.real_bus for a USB device."""
1031+ usb_device = UdevDevice(None, self.usb_device_data)
1032+ self.assertEqual(HWBus.USB, usb_device.real_bus)
1033+
1034+ def test_real_bus_usb_interface(self):
1035+ """Test of UdevDevice.real_bus for a USB interface."""
1036+ parser = SubmissionParser(self.log)
1037+ parser.submission_key = 'UdevDevice.real_bus for a not-real device'
1038+ usb_interface = UdevDevice(parser, self.usb_storage_usb_interface)
1039+ self.assertEqual(None, usb_interface.real_bus)
1040+ # UdevDevice.real_bus should only be accessed for real devices,
1041+ # which a USB is not. Hence we get a warning.
1042+ self.assertWarningMessage(
1043+ parser.submission_key,
1044+ "Unknown bus 'usb_interface' for device "
1045+ "/devices/pci0000:00/0000:00:1d.7/usb1/1-1/1-1:1.0")
1046+
1047+ def test_real_bus_pci(self):
1048+ """Test of UdevDevice.real_bus for PCI devices."""
1049+ devices = self.buildUdevDeviceHierarchy(
1050+ self.pci_bridge_pccard_hierarchy_data)
1051+ pci_device = devices[1]
1052+ pccard_device = devices[2]
1053+ self.assertEqual(HWBus.PCI, pci_device.real_bus)
1054+ self.assertEqual(HWBus.PCCARD, pccard_device.real_bus)
1055+
1056+ def test_real_bus_scsi(self):
1057+ """Test of UdevDevice.real_bus for a SCSI device."""
1058+ devices = self.buildUdevDeviceHierarchy(
1059+ self.scsi_device_hierarchy_data)
1060+ scsi_device = devices[-1]
1061+ self.assertEqual(HWBus.SCSI, scsi_device.real_bus)
1062+
1063+ def test_real_bus_system(self):
1064+ """Test of UdevDevice.real_bus for a system."""
1065+ root_device = UdevDevice(None, self.root_device)
1066+ self.assertEqual(HWBus.SYSTEM, root_device.real_bus)
1067+
1068
1069 class TestHWDBSubmissionTablePopulation(TestCaseHWDB):
1070 """Tests of the HWDB popoluation with submitted data."""