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

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

This branch adds some sanity checks for HWDB submission containing udev data (as sent by the HWDB client in Karmic), and it defines a new class UdevDevice, representing a device described by udev data. (The class is quite rudimentary at present.)

The idea of class UdevDevice is to "mangle" the raw data provided in a submission so that we cana populate the HWDB tables from this data. (See the base class BaseDevice and sibling class HALDevice for details.)

A new method SubmissionParser.checkUdevPciProperties() ensures that udev data for PCI devices have certain properties and that these properties have useful data, thus allowing class UdevDevice to make some assumptions about the data it is based on, for example, that the value of the property PCI_CLASS is an integer represented as a hexdecimal string.

SubmissionParser.checkConsistency() now calls checkConsistentUdevDeviceData(). The former method also assumed that the data for each submission contains a dictionary for data from HAL, which is no longer true, so some sanity checks specific for submissions with HAL data are now skipped for submissinos with udev data.

tests:

./bin/test -t test_hwdb_submission_parser
./bin/test -t 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_parser.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

lib/canonical/launchpad/scripts/tests/test_hwdb_submission_parser.py
    11: redefinition of unused 'etree' from line 9

== Pylint notices ==

lib/canonical/launchpad/scripts/hwdbsubmissions.py
    1160: [C0301] Line too long (79/78)
    20: [F0401] Unable to import 'xml.etree.cElementTree' (No module named etree)

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

These etree-related complaints are not caused by the changes in this branch.

Revision history for this message
Abel Deuring (adeuring) wrote :

oops, I missed the lint complaint about the too long line. Fixed in r9648

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

> This branch adds some sanity checks for HWDB submission containing udev data
> (as sent by the HWDB client in Karmic), and it defines a new class UdevDevice,
> representing a device described by udev data. (The class is quite rudimentary
> at present.)

Wow - I learned lots of great stuff through this branch - sorry it took me so long to review!

After we found a better way of creating test versions of some of your classes (thanks Bjorn) I've only got comments and some test suggestions left.

Great work!

> === modified file 'lib/canonical/launchpad/scripts/hwdbsubmissions.py'
> --- lib/canonical/launchpad/scripts/hwdbsubmissions.py 2009-10-06 08:37:11 +0000
> +++ lib/canonical/launchpad/scripts/hwdbsubmissions.py 2009-10-08 09:38:16 +0000
> @@ -1141,6 +1141,75 @@
> return False
> return True
>
> + PCI_PROPERTIES = set(
> + ('PCI_CLASS', 'PCI_ID', 'PCI_SUBSYS_ID', 'PCI_SLOT_NAME'))
> + pci_class_re = re.compile('^[0-9a-f]{1,6}$', re.I)
> + pci_id_re = re.compile('^[0-9a-f]{4}:[0-9a-f]{4}$', re.I)
> +
> + def checkUdevPciProperties(self, udev_data):
> + """Validation of udev PCI devices.
> +
> + Each PCI device must have the properties PCI_CLASS, PCI_ID,
> + PCI_SUBSYS_ID, PCI_SLOT_NAME. Non-PCI devices must not have
> + them.
> +
> + The value of PCI class must be a 24 bit integer in
> + hexadecimal representation.
> +
> + The values of PCI_ID and PCI_SUBSYS_ID must be two 16 bit
> + integers, separated by a ':'.

Barry would say: could you please use the :param: etc. like you have below
for UDevDevice.

> + """
> + for device in udev_data:
> + properties = device['E']
> + property_names = set(properties.keys())

I think this method could do with a few comments in general... maybe
a lot of it is completely obvious to you, but I have to spend time
interpreting the code, for example,...

> + existing_pci_properties = property_names.intersection(
> + self.PCI_PROPERTIES)
> + subsystem = device['E'].get('SUBSYSTEM')
> + if subsystem is None:
> + self._logError(
> + 'udev device without SUBSYSTEM property found.',
> + self.submission_key)
> + return False
> + if subsystem == 'pci':

# Check whether any of the standard pci properties were missing.
> + if existing_pci_properties != self.PCI_PROPERTIES:
> + missing_properties = self.PCI_PROPERTIES.difference(
> + existing_pci_properties)
> +
> + self._logError(
> + 'PCI udev device without required PCI properties: '
> + '%r %r'
> + % (missing_properties, device['P']),
> + self.submission_key)
> + return False

# Ensure that the pci class and ids for this device are valid.
> + if self.pci_class_re.search(properties['PCI_CLASS']) is None:
> + self._logError(
> + 'Invalid udev PCI class: %...

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

Hi Michael,

thanks for your review!

On 08.10.2009 13:35, Michael Nelson wrote:
> Review: Approve code
>> This branch adds some sanity checks for HWDB submission containing udev data
>> (as sent by the HWDB client in Karmic), and it defines a new class UdevDevice,
>> representing a device described by udev data. (The class is quite rudimentary
>> at present.)
>
> Wow - I learned lots of great stuff through this branch - sorry it took me so long to review!
>
> After we found a better way of creating test versions of some of your classes (thanks Bjorn) I've only got comments and some test suggestions left.
>
> Great work!
>
>> === modified file 'lib/canonical/launchpad/scripts/hwdbsubmissions.py'
>> --- lib/canonical/launchpad/scripts/hwdbsubmissions.py 2009-10-06 08:37:11 +0000
>> +++ lib/canonical/launchpad/scripts/hwdbsubmissions.py 2009-10-08 09:38:16 +0000
>> @@ -1141,6 +1141,75 @@
>> return False
>> return True
>>
>> + PCI_PROPERTIES = set(
>> + ('PCI_CLASS', 'PCI_ID', 'PCI_SUBSYS_ID', 'PCI_SLOT_NAME'))
>> + pci_class_re = re.compile('^[0-9a-f]{1,6}$', re.I)
>> + pci_id_re = re.compile('^[0-9a-f]{4}:[0-9a-f]{4}$', re.I)
>> +
>> + def checkUdevPciProperties(self, udev_data):
>> + """Validation of udev PCI devices.
>> +
>> + Each PCI device must have the properties PCI_CLASS, PCI_ID,
>> + PCI_SUBSYS_ID, PCI_SLOT_NAME. Non-PCI devices must not have
>> + them.
>> +
>> + The value of PCI class must be a 24 bit integer in
>> + hexadecimal representation.
>> +
>> + The values of PCI_ID and PCI_SUBSYS_ID must be two 16 bit
>> + integers, separated by a ':'.
>
> Barry would say: could you please use the :param: etc. like you have below
> for UDevDevice.

Done.

>
>> + """
>> + for device in udev_data:
>> + properties = device['E']
>> + property_names = set(properties.keys())
>
> I think this method could do with a few comments in general... maybe
> a lot of it is completely obvious to you, but I have to spend time
> interpreting the code, for example,...

yeah, sorry, I forgot to mention how you can see the data yourself:

 udevadm info --export-db

produces the data we are talking about. Might have made it easier for
you to get an idea what all this is about...

>
>> + existing_pci_properties = property_names.intersection(
>> + self.PCI_PROPERTIES)
>> + subsystem = device['E'].get('SUBSYSTEM')
>> + if subsystem is None:
>> + self._logError(
>> + 'udev device without SUBSYSTEM property found.',
>> + self.submission_key)
>> + return False
>> + if subsystem == 'pci':
>
> # Check whether any of the standard pci properties were missing.

Added.

>> + if existing_pci_properties != self.PCI_PROPERTIES:
>> + missing_properties = self.PCI_PROPERTIES.difference(
>> + existing_pci_properties)
>> +
>> + self._logError(
>> + 'PCI udev device without required PCI properties: '
>> + ...

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'lib/canonical/launchpad/scripts/hwdbsubmissions.py'
--- lib/canonical/launchpad/scripts/hwdbsubmissions.py 2009-10-06 08:37:11 +0000
+++ lib/canonical/launchpad/scripts/hwdbsubmissions.py 2009-10-08 13:44:12 +0000
@@ -1141,6 +1141,83 @@
1141 return False1141 return False
1142 return True1142 return True
11431143
1144 PCI_PROPERTIES = set(
1145 ('PCI_CLASS', 'PCI_ID', 'PCI_SUBSYS_ID', 'PCI_SLOT_NAME'))
1146 pci_class_re = re.compile('^[0-9a-f]{1,6}$', re.I)
1147 pci_id_re = re.compile('^[0-9a-f]{4}:[0-9a-f]{4}$', re.I)
1148
1149 def checkUdevPciProperties(self, udev_data):
1150 """Validation of udev PCI devices.
1151
1152 :param udev_data: A list of dicitionaries describing udev
1153 devices, as returned by _parseUdev()
1154 :return: True if all checks pass, else False.
1155
1156 Each PCI device must have the properties PCI_CLASS, PCI_ID,
1157 PCI_SUBSYS_ID, PCI_SLOT_NAME. Non-PCI devices must not have
1158 them.
1159
1160 The value of PCI class must be a 24 bit integer in
1161 hexadecimal representation.
1162
1163 The values of PCI_ID and PCI_SUBSYS_ID must be two 16 bit
1164 integers, separated by a ':'.
1165 """
1166 for device in udev_data:
1167 properties = device['E']
1168 property_names = set(properties.keys())
1169 existing_pci_properties = property_names.intersection(
1170 self.PCI_PROPERTIES)
1171 subsystem = device['E'].get('SUBSYSTEM')
1172 if subsystem is None:
1173 self._logError(
1174 'udev device without SUBSYSTEM property found.',
1175 self.submission_key)
1176 return False
1177 if subsystem == 'pci':
1178 # Check whether any of the standard pci properties were
1179 # missing.
1180 if existing_pci_properties != self.PCI_PROPERTIES:
1181 missing_properties = self.PCI_PROPERTIES.difference(
1182 existing_pci_properties)
1183
1184 self._logError(
1185 'PCI udev device without required PCI properties: '
1186 '%r %r'
1187 % (missing_properties, device['P']),
1188 self.submission_key)
1189 return False
1190 # Ensure that the pci class and ids for this device are
1191 # formally valid.
1192 if self.pci_class_re.search(properties['PCI_CLASS']) is None:
1193 self._logError(
1194 'Invalid udev PCI class: %r %r'
1195 % (properties['PCI_CLASS'], device['P']),
1196 self.submission_key)
1197 return False
1198 for pci_id in (properties['PCI_ID'],
1199 properties['PCI_SUBSYS_ID']):
1200 if self.pci_id_re.search(pci_id) is None:
1201 self._logError(
1202 'Invalid udev PCI device ID: %r %r'
1203 % (pci_id, device['P']),
1204 self.submission_key)
1205 return False
1206 else:
1207 if len(existing_pci_properties) > 0:
1208 self._logError(
1209 'Non-PCI udev device with PCI properties: %r %r'
1210 % (existing_pci_properties, device['P']),
1211 self.submission_key)
1212 return False
1213 return True
1214
1215 def checkConsistentUdevDeviceData(self, udev_data):
1216 """Consistency checks for udev data."""
1217 if not self.checkUdevDictsHavePathKey(udev_data):
1218 return False
1219 return self.checkUdevPciProperties(udev_data)
1220
1144 def checkConsistency(self, parsed_data):1221 def checkConsistency(self, parsed_data):
1145 """Run consistency checks on the submitted data.1222 """Run consistency checks on the submitted data.
11461223
@@ -1148,10 +1225,10 @@
1148 :param: parsed_data: parsed submission data, as returned by1225 :param: parsed_data: parsed submission data, as returned by
1149 parseSubmission1226 parseSubmission
1150 """1227 """
1151 if 'udev' in parsed_data['hardware']:1228 if ('udev' in parsed_data['hardware']
1152 if not self.checkUdevDictsHavePathKey(1229 and not self.checkConsistentUdevDeviceData(
1153 parsed_data['hardware']['udev']):1230 parsed_data['hardware']['udev'])):
1154 return False1231 return False
1155 duplicate_ids = self.findDuplicateIDs(parsed_data)1232 duplicate_ids = self.findDuplicateIDs(parsed_data)
1156 if duplicate_ids:1233 if duplicate_ids:
1157 self._logError('Duplicate IDs found: %s' % duplicate_ids,1234 self._logError('Duplicate IDs found: %s' % duplicate_ids,
@@ -1174,7 +1251,8 @@
1174 self._logError(value, self.submission_key)1251 self._logError(value, self.submission_key)
1175 return False1252 return False
11761253
1177 circular = self.checkHALDevicesParentChildConsistency(udi_children)1254 circular = self.checkHALDevicesParentChildConsistency(
1255 udi_children)
1178 if circular:1256 if circular:
1179 self._logError('Found HAL devices with circular parent/child '1257 self._logError('Found HAL devices with circular parent/child '
1180 'relationship: %s' % circular,1258 'relationship: %s' % circular,
@@ -2146,6 +2224,61 @@
2146 return self.getVendorOrProductID('product')2224 return self.getVendorOrProductID('product')
21472225
21482226
2227class UdevDevice(BaseDevice):
2228 """The representation of a udev device node."""
2229
2230 def __init__(self, udev_data, sysfs_data, parser):
2231 """HALDevice constructor.
2232
2233 :param udevdata: The udev data for this device
2234 :param sysfs_data: sysfs data for this device.
2235 :param parser: The parser processing a submission.
2236 :type parser: SubmissionParser
2237 """
2238 super(UdevDevice, self).__init__(parser)
2239 self.udev = udev_data
2240 self.sysfs = sysfs_data
2241
2242 @property
2243 def device_id(self):
2244 """See `BaseDevice`."""
2245 return self.udev['P']
2246
2247 @property
2248 def is_pci(self):
2249 """True, if this is a PCI device, else False."""
2250 return self.udev['E'].get('SUBSYSTEM') == 'pci'
2251
2252 @property
2253 def pci_class_info(self):
2254 """Parse the udev property PCI_SUBSYS_ID.
2255
2256 :return: (PCI class, PCI sub-class, version) for a PCI device
2257 or (None, None, None) for other devices.
2258 """
2259 if self.is_pci:
2260 # SubmissionParser.checkConsistentUdevDeviceData() ensures
2261 # that PCI_CLASS is a 24 bit integer in hexadecimal
2262 # representation.
2263 # Bits 16..23 of the number are the man PCI class,
2264 # bits 8..15 are the sub-class, bits 0..7 are the version.
2265 class_info = int(self.udev['E']['PCI_CLASS'], 16)
2266 return (class_info >> 16, (class_info >> 8) & 0xFF,
2267 class_info & 0xFF)
2268 else:
2269 return (None, None, None)
2270
2271 @property
2272 def pci_class(self):
2273 """See `BaseDevice`."""
2274 return self.pci_class_info[0]
2275
2276 @property
2277 def pci_subclass(self):
2278 """See `BaseDevice`."""
2279 return self.pci_class_info[1]
2280
2281
2149class ProcessingLoop(object):2282class ProcessingLoop(object):
2150 """An `ITunableLoop` for processing HWDB submissions."""2283 """An `ITunableLoop` for processing HWDB submissions."""
21512284
21522285
=== modified file 'lib/canonical/launchpad/scripts/tests/test_hwdb_submission_parser.py'
--- lib/canonical/launchpad/scripts/tests/test_hwdb_submission_parser.py 2009-10-06 09:31:32 +0000
+++ lib/canonical/launchpad/scripts/tests/test_hwdb_submission_parser.py 2009-10-08 13:44:12 +0000
@@ -98,6 +98,20 @@
98 self.log.setLevel(logging.INFO)98 self.log.setLevel(logging.INFO)
99 self.handler = Handler(self)99 self.handler = Handler(self)
100 self.handler.add(self.log.name)100 self.handler.add(self.log.name)
101 self.udev_root_device = {
102 'P': '/devices/LNXSYSTM:00',
103 'E': {'SUBSYSTEM': 'acpi'},
104 }
105 self.udev_pci_device = {
106 'P': '/devices/pci0000:00/0000:00:1f.2',
107 'E': {
108 'SUBSYSTEM': 'pci',
109 'PCI_CLASS': '10601',
110 'PCI_ID': '8086:27C5',
111 'PCI_SUBSYS_ID': '10CF:1387',
112 'PCI_SLOT_NAME': '0000:00:1f.2',
113 }
114 }
101115
102 def getTimestampETreeNode(self, time_string):116 def getTimestampETreeNode(self, time_string):
103 """Return an Elementtree node for an XML tag with a timestamp."""117 """Return an Elementtree node for an XML tag with a timestamp."""
@@ -1773,6 +1787,160 @@
1773 self.assertErrorMessage(1787 self.assertErrorMessage(
1774 parser.submission_key, 'udev node found without a "P" key')1788 parser.submission_key, 'udev node found without a "P" key')
17751789
1790 def testCheckUdevPciProperties(self):
1791 """Test of SubmmissionParser.checkUdevPciProperties()."""
1792 # udev PCI devices must have the properties PCI_CLASS, PCI_ID,
1793 # PCI_SUBSYS_ID, PCI_SLOT_NAME; other devices must not have
1794 # these properties.
1795 parser = SubmissionParser()
1796 self.assertTrue(parser.checkUdevPciProperties(
1797 [self.udev_root_device, self.udev_pci_device]))
1798
1799 def testCheckUdevPciPropertiesNonPciDeviceWithPciProperties(self):
1800 """Test of SubmmissionParser.checkUdevPciProperties().
1801
1802 A non-PCI device having PCI properties makes a submission invalid.
1803 """
1804 self.udev_root_device['E']['PCI_SLOT_NAME'] = '0000:00:1f.2'
1805 parser = SubmissionParser(self.log)
1806 parser.submission_key = 'invalid non-PCI device'
1807 self.assertFalse(parser.checkUdevPciProperties(
1808 [self.udev_root_device, self.udev_pci_device]))
1809 self.assertErrorMessage(
1810 parser.submission_key,
1811 "Non-PCI udev device with PCI properties: set(['PCI_SLOT_NAME']) "
1812 "'/devices/LNXSYSTM:00'")
1813
1814 def testCheckUdevPciPropertiesPciDeviceWithoutRequiredProperties(self):
1815 """Test of SubmmissionParser.checkUdevPciProperties().
1816
1817 A PCI device not having a required PCI property makes a submission
1818 invalid.
1819 """
1820 del self.udev_pci_device['E']['PCI_CLASS']
1821 parser = SubmissionParser(self.log)
1822 parser.submission_key = 'invalid PCI device'
1823 self.assertFalse(parser.checkUdevPciProperties(
1824 [self.udev_root_device, self.udev_pci_device]))
1825 self.assertErrorMessage(
1826 parser.submission_key,
1827 "PCI udev device without required PCI properties: "
1828 "set(['PCI_CLASS']) '/devices/pci0000:00/0000:00:1f.2'")
1829
1830 def testCheckUdevPciPropertiesPciDeviceWithNonIntegerPciClass(self):
1831 """Test of SubmmissionParser.checkUdevPciProperties().
1832
1833 A PCI device with a non-integer class value makes a submission
1834 invalid.
1835 """
1836 self.udev_pci_device['E']['PCI_CLASS'] = 'not-an-integer'
1837 parser = SubmissionParser(self.log)
1838 parser.submission_key = 'invalid PCI class value'
1839 self.assertFalse(parser.checkUdevPciProperties(
1840 [self.udev_root_device, self.udev_pci_device]))
1841 self.assertErrorMessage(
1842 parser.submission_key,
1843 "Invalid udev PCI class: 'not-an-integer' "
1844 "'/devices/pci0000:00/0000:00:1f.2'")
1845
1846 def testCheckUdevPciPropertiesPciDeviceWithInvalidPciClassValue(self):
1847 """Test of SubmmissionParser.checkUdevPciProperties().
1848
1849 A PCI device with invalid class data makes a submission
1850 invalid.
1851 """
1852 self.udev_pci_device['E']['PCI_CLASS'] = '1234567'
1853 parser = SubmissionParser(self.log)
1854 parser.submission_key = 'too large PCI class value'
1855 self.assertFalse(parser.checkUdevPciProperties(
1856 [self.udev_root_device, self.udev_pci_device]))
1857 self.assertErrorMessage(
1858 parser.submission_key,
1859 "Invalid udev PCI class: '1234567' "
1860 "'/devices/pci0000:00/0000:00:1f.2'")
1861
1862 def testCheckUdevPciPropertiesPciDeviceWithInvalidDeviceID(self):
1863 """Test of SubmmissionParser.checkUdevPciProperties().
1864
1865 A PCI device with an invalid device ID makes a submission
1866 invalid.
1867 """
1868 self.udev_pci_device['E']['PCI_ID'] = 'not-an-id'
1869 parser = SubmissionParser(self.log)
1870 parser.submission_key = 'invalid PCI ID'
1871 self.assertFalse(parser.checkUdevPciProperties(
1872 [self.udev_root_device, self.udev_pci_device]))
1873 self.assertErrorMessage(
1874 parser.submission_key,
1875 "Invalid udev PCI device ID: 'not-an-id' "
1876 "'/devices/pci0000:00/0000:00:1f.2'")
1877
1878 def testCheckUdevPciPropertiesPciDeviceWithInvalidSubsystemID(self):
1879 """Test of SubmmissionParser.checkUdevPciProperties().
1880
1881 A PCI device with an invalid subsystem ID makes a submission
1882 invalid.
1883 """
1884 self.udev_pci_device['E']['PCI_SUBSYS_ID'] = 'not-a-subsystem-id'
1885 parser = SubmissionParser(self.log)
1886 parser.submission_key = 'invalid PCI subsystem ID'
1887 self.assertFalse(parser.checkUdevPciProperties(
1888 [self.udev_root_device, self.udev_pci_device]))
1889 self.assertErrorMessage(
1890 parser.submission_key,
1891 "Invalid udev PCI device ID: 'not-a-subsystem-id' "
1892 "'/devices/pci0000:00/0000:00:1f.2'")
1893
1894 class UdevTestSubmissionParser(SubmissionParser):
1895 """A variant of SubmissionParser that shortcuts udev related tests.
1896
1897 All shortcut methods return True.
1898 """
1899 def checkUdevDictsHavePathKey(self, udev_data):
1900 """See `SubmissionParser`."""
1901 return True
1902
1903 def checkUdevPciProperties(self, udev_data):
1904 """See `SubmissionParser`."""
1905 return True
1906
1907 def testCheckConsistentUdevDeviceData(self):
1908 """Test of SubmissionParser.checkConsistentUdevDeviceData(),"""
1909 parser = self.UdevTestSubmissionParser()
1910 self.assertTrue(parser.checkConsistentUdevDeviceData(None))
1911
1912 def testCheckConsistentUdevDeviceData_invalid_path_data(self):
1913 """Test of SubmissionParser.checkConsistentUdevDeviceData(),
1914
1915 Detection of invalid path data lets the check fail.
1916 """
1917 class SubmissionParserUdevPathCheckFails(
1918 self.UdevTestSubmissionParser):
1919 """A SubmissionPaser where checkUdevDictsHavePathKey() fails."""
1920
1921 def checkUdevDictsHavePathKey(self, udev_data):
1922 """See `SubmissionParser`."""
1923 return False
1924
1925 parser = SubmissionParserUdevPathCheckFails()
1926 self.assertFalse(parser.checkConsistentUdevDeviceData(None))
1927
1928 def testCheckConsistentUdevDeviceData_invalid_pci_data(self):
1929 """Test of SubmissionParser.checkConsistentUdevDeviceData(),
1930
1931 Detection of invalid PCI data lets the check fail.
1932 """
1933 class SubmissionParserUdevPciCheckFails(
1934 self.UdevTestSubmissionParser):
1935 """A SubmissionPaser where checkUdevPciProperties() fails."""
1936
1937 def checkUdevPciProperties(self, udev_data):
1938 """See `SubmissionParser`."""
1939 return False
1940
1941 parser = SubmissionParserUdevPciCheckFails()
1942 self.assertFalse(parser.checkConsistentUdevDeviceData(None))
1943
1776 def _setupConsistencyCheckParser(self):1944 def _setupConsistencyCheckParser(self):
1777 """Prepare and return a SubmissionParser instance.1945 """Prepare and return a SubmissionParser instance.
17781946
@@ -1799,6 +1967,9 @@
1799 test.assertTrue(isinstance(self, SubmissionParser))1967 test.assertTrue(isinstance(self, SubmissionParser))
1800 return []1968 return []
18011969
1970 def checkConsistentUdevDeviceData(self, udev_data):
1971 return True
1972
1802 parser = SubmissionParser(self.log)1973 parser = SubmissionParser(self.log)
1803 parser.findDuplicateIDs = (1974 parser.findDuplicateIDs = (
1804 lambda parsed_data: findDuplicateIDs(parser, parsed_data))1975 lambda parsed_data: findDuplicateIDs(parser, parsed_data))
@@ -1811,6 +1982,9 @@
1811 parser.checkHALDevicesParentChildConsistency = (1982 parser.checkHALDevicesParentChildConsistency = (
1812 lambda udi_children: checkHALDevicesParentChildConsistency(1983 lambda udi_children: checkHALDevicesParentChildConsistency(
1813 parser, udi_children))1984 parser, udi_children))
1985 parser.checkConsistentUdevDeviceData = (
1986 lambda udev_data: checkConsistentUdevDeviceData(
1987 parser, udev_data))
1814 return parser1988 return parser
18151989
1816 def assertErrorMessage(self, submission_key, log_message):1990 def assertErrorMessage(self, submission_key, log_message):
@@ -1882,10 +2056,15 @@
1882 }2056 }
1883 ))2057 ))
18842058
1885 def testConsistencyCheckInvalidUdevData(self):2059 def testConsistencyCheck_invalid_udev_data(self):
1886 """Test of SubmissionParser.checkConsistency."""2060 """Test of SubmissionParser.checkConsistency."""
2061 def checkConsistentUdevDeviceData(self, udev_data):
2062 return False
2063
1887 parser = self._setupConsistencyCheckParser()2064 parser = self._setupConsistencyCheckParser()
1888 parser.submission_key = 'Consistency check with invalid udev data'2065 parser.checkConsistentUdevDeviceData = (
2066 lambda udev_data: checkConsistentUdevDeviceData(
2067 parser, udev_data))
1889 self.assertFalse(parser.checkConsistency(2068 self.assertFalse(parser.checkConsistency(
1890 {2069 {
1891 'hardware': {2070 'hardware': {
@@ -1894,8 +2073,6 @@
1894 }2073 }
1895 }2074 }
1896 ))2075 ))
1897 self.assertErrorMessage(
1898 parser.submission_key, 'udev node found without a "P" key')
18992076
1900 def testConsistencyCheckWithDuplicateIDs(self):2077 def testConsistencyCheckWithDuplicateIDs(self):
1901 """SubmissionParser.checkConsistency detects duplicate IDs."""2078 """SubmissionParser.checkConsistency detects duplicate IDs."""
19022079
=== modified file 'lib/canonical/launchpad/scripts/tests/test_hwdb_submission_processing.py'
--- lib/canonical/launchpad/scripts/tests/test_hwdb_submission_processing.py 2009-10-01 14:48:33 +0000
+++ lib/canonical/launchpad/scripts/tests/test_hwdb_submission_processing.py 2009-10-08 13:44:12 +0000
@@ -27,8 +27,8 @@
27from canonical.launchpad.scripts.hwdbsubmissions import (27from canonical.launchpad.scripts.hwdbsubmissions import (
28 HALDevice, PCI_CLASS_BRIDGE, PCI_CLASS_SERIALBUS_CONTROLLER,28 HALDevice, PCI_CLASS_BRIDGE, PCI_CLASS_SERIALBUS_CONTROLLER,
29 PCI_CLASS_STORAGE, PCI_SUBCLASS_BRIDGE_CARDBUS, PCI_SUBCLASS_BRIDGE_PCI,29 PCI_CLASS_STORAGE, PCI_SUBCLASS_BRIDGE_CARDBUS, PCI_SUBCLASS_BRIDGE_PCI,
30 PCI_SUBCLASS_SERIALBUS_USB, PCI_SUBCLASS_STORAGE_SATA, SubmissionParser,30 PCI_SUBCLASS_SERIALBUS_USB, PCI_SUBCLASS_STORAGE_SATA,
31 process_pending_submissions)31 process_pending_submissions, SubmissionParser, UdevDevice)
32from canonical.launchpad.webapp.errorlog import ErrorReportingUtility32from canonical.launchpad.webapp.errorlog import ErrorReportingUtility
33from canonical.testing import BaseLayer, LaunchpadZopelessLayer33from canonical.testing import BaseLayer, LaunchpadZopelessLayer
3434
@@ -2591,6 +2591,84 @@
2591 'property not treated as a real device.')2591 'property not treated as a real device.')
25922592
25932593
2594class TestUdevDevice(TestCase):
2595 """Tests of class UdevDevice."""
2596
2597 layer = BaseLayer
2598
2599 root_device = {
2600 'P': '/devices/LNXSYSTM:00',
2601 'E': {
2602 'UDEV_LOG': '3',
2603 'DEVPATH': '/devices/LNXSYSTM:00',
2604 'MODALIAS': 'acpi:LNXSYSTM:',
2605 'SUBSYSTEM': 'acpi',
2606 }
2607 }
2608
2609 pci_device_data = {
2610 'P': '/devices/pci0000:00/0000:00:1f.2',
2611 'E': {
2612 'PCI_CLASS': '10602',
2613 'PCI_ID': '8086:27C5',
2614 'PCI_SUBSYS_ID': '10CF:1387',
2615 'PCI_SLOT_NAME': '0000:00:1f.2',
2616 'SUBSYSTEM': 'pci',
2617 }
2618 }
2619
2620 def test_device_id(self):
2621 """Test of UdevDevice.device_id."""
2622 device = UdevDevice(self.pci_device_data, None, None)
2623 self.assertEqual(
2624 '/devices/pci0000:00/0000:00:1f.2', device.device_id,
2625 'Unexpected value of UdevDevice.device_id.')
2626
2627 def test_is_pci(self):
2628 """Test of UdevDevice.is_pci."""
2629 device = UdevDevice(self.pci_device_data, None, None)
2630 self.assertTrue(device.is_pci)
2631
2632 device = UdevDevice(self.root_device, None, None)
2633 self.assertFalse(device.is_pci)
2634
2635 def test_pci_class_info(self):
2636 """Test of UdevDevice.pci_class_info"""
2637 device = UdevDevice(self.pci_device_data, None, None)
2638 self.assertEqual(
2639 (1, 6, 2), device.pci_class_info,
2640 'Invalid value of UdevDevice.pci_class_info for PCI device.')
2641
2642 device = UdevDevice(self.root_device, None, None)
2643 self.assertEqual(
2644 (None, None, None), device.pci_class_info,
2645 'Invalid value of UdevDevice.pci_class_info for Non-PCI device.')
2646
2647 def test_pci_class(self):
2648 """Test of UdevDevice.pci_class"""
2649 device = UdevDevice(self.pci_device_data, None, None)
2650 self.assertEqual(
2651 1, device.pci_class,
2652 'Invalid value of UdevDevice.pci_class for PCI device.')
2653
2654 device = UdevDevice(self.root_device, None, None)
2655 self.assertEqual(
2656 None, device.pci_class,
2657 'Invalid value of UdevDevice.pci_class for Non-PCI device.')
2658
2659 def test_pci_subclass(self):
2660 """Test of UdevDevice.pci_subclass"""
2661 device = UdevDevice(self.pci_device_data, None, None)
2662 self.assertEqual(
2663 6, device.pci_subclass,
2664 'Invalid value of UdevDevice.pci_class for PCI device.')
2665
2666 device = UdevDevice(self.root_device, None, None)
2667 self.assertEqual(
2668 None, device.pci_class,
2669 'Invalid value of UdevDevice.pci_class for Non-PCI device.')
2670
2671
2594class TestHWDBSubmissionTablePopulation(TestCaseHWDB):2672class TestHWDBSubmissionTablePopulation(TestCaseHWDB):
2595 """Tests of the HWDB popoluation with submitted data."""2673 """Tests of the HWDB popoluation with submitted data."""
25962674