Merge lp:~adeuring/launchpad/hwdb-class-udev-device-1 into lp:launchpad
- hwdb-class-udev-device-1
- Merge into devel
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 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Michael Nelson (community) | code | Approve | |
Review via email: mp+13051@code.launchpad.net |
Commit message
Description of the change
Abel Deuring (adeuring) wrote : | # |
Abel Deuring (adeuring) wrote : | # |
oops, I missed the lint complaint about the too long line. Fixed in r9648
Michael Nelson (michael.nelson) 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.)
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/
> --- lib/canonical/
> +++ lib/canonical/
> @@ -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(
> + pci_id_re = re.compile(
> +
> + def checkUdevPciPro
> + """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.
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_
> + self.PCI_
> + subsystem = device[
> + if subsystem is None:
> + self._logError(
> + 'udev device without SUBSYSTEM property found.',
> + self.submission
> + return False
> + if subsystem == 'pci':
# Check whether any of the standard pci properties were missing.
> + if existing_
> + missing_properties = self.PCI_
> + existing_
> +
> + self._logError(
> + 'PCI udev device without required PCI properties: '
> + '%r %r'
> + % (missing_
> + self.submission
> + return False
# Ensure that the pci class and ids for this device are valid.
> + if self.pci_
> + self._logError(
> + 'Invalid udev PCI class: %...
Abel Deuring (adeuring) wrote : | # |
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/
>> --- lib/canonical/
>> +++ lib/canonical/
>> @@ -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(
>> + pci_id_re = re.compile(
>> +
>> + def checkUdevPciPro
>> + """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.
>
> 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_
>> + self.PCI_
>> + subsystem = device[
>> + if subsystem is None:
>> + self._logError(
>> + 'udev device without SUBSYSTEM property found.',
>> + self.submission
>> + return False
>> + if subsystem == 'pci':
>
> # Check whether any of the standard pci properties were missing.
Added.
>> + if existing_
>> + missing_properties = self.PCI_
>> + existing_
>> +
>> + self._logError(
>> + 'PCI udev device without required PCI properties: '
>> + ...
Preview Diff
1 | === modified file 'lib/canonical/launchpad/scripts/hwdbsubmissions.py' |
2 | --- lib/canonical/launchpad/scripts/hwdbsubmissions.py 2009-10-06 08:37:11 +0000 |
3 | +++ lib/canonical/launchpad/scripts/hwdbsubmissions.py 2009-10-08 13:44:12 +0000 |
4 | @@ -1141,6 +1141,83 @@ |
5 | return False |
6 | return True |
7 | |
8 | + PCI_PROPERTIES = set( |
9 | + ('PCI_CLASS', 'PCI_ID', 'PCI_SUBSYS_ID', 'PCI_SLOT_NAME')) |
10 | + pci_class_re = re.compile('^[0-9a-f]{1,6}$', re.I) |
11 | + pci_id_re = re.compile('^[0-9a-f]{4}:[0-9a-f]{4}$', re.I) |
12 | + |
13 | + def checkUdevPciProperties(self, udev_data): |
14 | + """Validation of udev PCI devices. |
15 | + |
16 | + :param udev_data: A list of dicitionaries describing udev |
17 | + devices, as returned by _parseUdev() |
18 | + :return: True if all checks pass, else False. |
19 | + |
20 | + Each PCI device must have the properties PCI_CLASS, PCI_ID, |
21 | + PCI_SUBSYS_ID, PCI_SLOT_NAME. Non-PCI devices must not have |
22 | + them. |
23 | + |
24 | + The value of PCI class must be a 24 bit integer in |
25 | + hexadecimal representation. |
26 | + |
27 | + The values of PCI_ID and PCI_SUBSYS_ID must be two 16 bit |
28 | + integers, separated by a ':'. |
29 | + """ |
30 | + for device in udev_data: |
31 | + properties = device['E'] |
32 | + property_names = set(properties.keys()) |
33 | + existing_pci_properties = property_names.intersection( |
34 | + self.PCI_PROPERTIES) |
35 | + subsystem = device['E'].get('SUBSYSTEM') |
36 | + if subsystem is None: |
37 | + self._logError( |
38 | + 'udev device without SUBSYSTEM property found.', |
39 | + self.submission_key) |
40 | + return False |
41 | + if subsystem == 'pci': |
42 | + # Check whether any of the standard pci properties were |
43 | + # missing. |
44 | + if existing_pci_properties != self.PCI_PROPERTIES: |
45 | + missing_properties = self.PCI_PROPERTIES.difference( |
46 | + existing_pci_properties) |
47 | + |
48 | + self._logError( |
49 | + 'PCI udev device without required PCI properties: ' |
50 | + '%r %r' |
51 | + % (missing_properties, device['P']), |
52 | + self.submission_key) |
53 | + return False |
54 | + # Ensure that the pci class and ids for this device are |
55 | + # formally valid. |
56 | + if self.pci_class_re.search(properties['PCI_CLASS']) is None: |
57 | + self._logError( |
58 | + 'Invalid udev PCI class: %r %r' |
59 | + % (properties['PCI_CLASS'], device['P']), |
60 | + self.submission_key) |
61 | + return False |
62 | + for pci_id in (properties['PCI_ID'], |
63 | + properties['PCI_SUBSYS_ID']): |
64 | + if self.pci_id_re.search(pci_id) is None: |
65 | + self._logError( |
66 | + 'Invalid udev PCI device ID: %r %r' |
67 | + % (pci_id, device['P']), |
68 | + self.submission_key) |
69 | + return False |
70 | + else: |
71 | + if len(existing_pci_properties) > 0: |
72 | + self._logError( |
73 | + 'Non-PCI udev device with PCI properties: %r %r' |
74 | + % (existing_pci_properties, device['P']), |
75 | + self.submission_key) |
76 | + return False |
77 | + return True |
78 | + |
79 | + def checkConsistentUdevDeviceData(self, udev_data): |
80 | + """Consistency checks for udev data.""" |
81 | + if not self.checkUdevDictsHavePathKey(udev_data): |
82 | + return False |
83 | + return self.checkUdevPciProperties(udev_data) |
84 | + |
85 | def checkConsistency(self, parsed_data): |
86 | """Run consistency checks on the submitted data. |
87 | |
88 | @@ -1148,10 +1225,10 @@ |
89 | :param: parsed_data: parsed submission data, as returned by |
90 | parseSubmission |
91 | """ |
92 | - if 'udev' in parsed_data['hardware']: |
93 | - if not self.checkUdevDictsHavePathKey( |
94 | - parsed_data['hardware']['udev']): |
95 | - return False |
96 | + if ('udev' in parsed_data['hardware'] |
97 | + and not self.checkConsistentUdevDeviceData( |
98 | + parsed_data['hardware']['udev'])): |
99 | + return False |
100 | duplicate_ids = self.findDuplicateIDs(parsed_data) |
101 | if duplicate_ids: |
102 | self._logError('Duplicate IDs found: %s' % duplicate_ids, |
103 | @@ -1174,7 +1251,8 @@ |
104 | self._logError(value, self.submission_key) |
105 | return False |
106 | |
107 | - circular = self.checkHALDevicesParentChildConsistency(udi_children) |
108 | + circular = self.checkHALDevicesParentChildConsistency( |
109 | + udi_children) |
110 | if circular: |
111 | self._logError('Found HAL devices with circular parent/child ' |
112 | 'relationship: %s' % circular, |
113 | @@ -2146,6 +2224,61 @@ |
114 | return self.getVendorOrProductID('product') |
115 | |
116 | |
117 | +class UdevDevice(BaseDevice): |
118 | + """The representation of a udev device node.""" |
119 | + |
120 | + def __init__(self, udev_data, sysfs_data, parser): |
121 | + """HALDevice constructor. |
122 | + |
123 | + :param udevdata: The udev data for this device |
124 | + :param sysfs_data: sysfs data for this device. |
125 | + :param parser: The parser processing a submission. |
126 | + :type parser: SubmissionParser |
127 | + """ |
128 | + super(UdevDevice, self).__init__(parser) |
129 | + self.udev = udev_data |
130 | + self.sysfs = sysfs_data |
131 | + |
132 | + @property |
133 | + def device_id(self): |
134 | + """See `BaseDevice`.""" |
135 | + return self.udev['P'] |
136 | + |
137 | + @property |
138 | + def is_pci(self): |
139 | + """True, if this is a PCI device, else False.""" |
140 | + return self.udev['E'].get('SUBSYSTEM') == 'pci' |
141 | + |
142 | + @property |
143 | + def pci_class_info(self): |
144 | + """Parse the udev property PCI_SUBSYS_ID. |
145 | + |
146 | + :return: (PCI class, PCI sub-class, version) for a PCI device |
147 | + or (None, None, None) for other devices. |
148 | + """ |
149 | + if self.is_pci: |
150 | + # SubmissionParser.checkConsistentUdevDeviceData() ensures |
151 | + # that PCI_CLASS is a 24 bit integer in hexadecimal |
152 | + # representation. |
153 | + # Bits 16..23 of the number are the man PCI class, |
154 | + # bits 8..15 are the sub-class, bits 0..7 are the version. |
155 | + class_info = int(self.udev['E']['PCI_CLASS'], 16) |
156 | + return (class_info >> 16, (class_info >> 8) & 0xFF, |
157 | + class_info & 0xFF) |
158 | + else: |
159 | + return (None, None, None) |
160 | + |
161 | + @property |
162 | + def pci_class(self): |
163 | + """See `BaseDevice`.""" |
164 | + return self.pci_class_info[0] |
165 | + |
166 | + @property |
167 | + def pci_subclass(self): |
168 | + """See `BaseDevice`.""" |
169 | + return self.pci_class_info[1] |
170 | + |
171 | + |
172 | class ProcessingLoop(object): |
173 | """An `ITunableLoop` for processing HWDB submissions.""" |
174 | |
175 | |
176 | === modified file 'lib/canonical/launchpad/scripts/tests/test_hwdb_submission_parser.py' |
177 | --- lib/canonical/launchpad/scripts/tests/test_hwdb_submission_parser.py 2009-10-06 09:31:32 +0000 |
178 | +++ lib/canonical/launchpad/scripts/tests/test_hwdb_submission_parser.py 2009-10-08 13:44:12 +0000 |
179 | @@ -98,6 +98,20 @@ |
180 | self.log.setLevel(logging.INFO) |
181 | self.handler = Handler(self) |
182 | self.handler.add(self.log.name) |
183 | + self.udev_root_device = { |
184 | + 'P': '/devices/LNXSYSTM:00', |
185 | + 'E': {'SUBSYSTEM': 'acpi'}, |
186 | + } |
187 | + self.udev_pci_device = { |
188 | + 'P': '/devices/pci0000:00/0000:00:1f.2', |
189 | + 'E': { |
190 | + 'SUBSYSTEM': 'pci', |
191 | + 'PCI_CLASS': '10601', |
192 | + 'PCI_ID': '8086:27C5', |
193 | + 'PCI_SUBSYS_ID': '10CF:1387', |
194 | + 'PCI_SLOT_NAME': '0000:00:1f.2', |
195 | + } |
196 | + } |
197 | |
198 | def getTimestampETreeNode(self, time_string): |
199 | """Return an Elementtree node for an XML tag with a timestamp.""" |
200 | @@ -1773,6 +1787,160 @@ |
201 | self.assertErrorMessage( |
202 | parser.submission_key, 'udev node found without a "P" key') |
203 | |
204 | + def testCheckUdevPciProperties(self): |
205 | + """Test of SubmmissionParser.checkUdevPciProperties().""" |
206 | + # udev PCI devices must have the properties PCI_CLASS, PCI_ID, |
207 | + # PCI_SUBSYS_ID, PCI_SLOT_NAME; other devices must not have |
208 | + # these properties. |
209 | + parser = SubmissionParser() |
210 | + self.assertTrue(parser.checkUdevPciProperties( |
211 | + [self.udev_root_device, self.udev_pci_device])) |
212 | + |
213 | + def testCheckUdevPciPropertiesNonPciDeviceWithPciProperties(self): |
214 | + """Test of SubmmissionParser.checkUdevPciProperties(). |
215 | + |
216 | + A non-PCI device having PCI properties makes a submission invalid. |
217 | + """ |
218 | + self.udev_root_device['E']['PCI_SLOT_NAME'] = '0000:00:1f.2' |
219 | + parser = SubmissionParser(self.log) |
220 | + parser.submission_key = 'invalid non-PCI device' |
221 | + self.assertFalse(parser.checkUdevPciProperties( |
222 | + [self.udev_root_device, self.udev_pci_device])) |
223 | + self.assertErrorMessage( |
224 | + parser.submission_key, |
225 | + "Non-PCI udev device with PCI properties: set(['PCI_SLOT_NAME']) " |
226 | + "'/devices/LNXSYSTM:00'") |
227 | + |
228 | + def testCheckUdevPciPropertiesPciDeviceWithoutRequiredProperties(self): |
229 | + """Test of SubmmissionParser.checkUdevPciProperties(). |
230 | + |
231 | + A PCI device not having a required PCI property makes a submission |
232 | + invalid. |
233 | + """ |
234 | + del self.udev_pci_device['E']['PCI_CLASS'] |
235 | + parser = SubmissionParser(self.log) |
236 | + parser.submission_key = 'invalid PCI device' |
237 | + self.assertFalse(parser.checkUdevPciProperties( |
238 | + [self.udev_root_device, self.udev_pci_device])) |
239 | + self.assertErrorMessage( |
240 | + parser.submission_key, |
241 | + "PCI udev device without required PCI properties: " |
242 | + "set(['PCI_CLASS']) '/devices/pci0000:00/0000:00:1f.2'") |
243 | + |
244 | + def testCheckUdevPciPropertiesPciDeviceWithNonIntegerPciClass(self): |
245 | + """Test of SubmmissionParser.checkUdevPciProperties(). |
246 | + |
247 | + A PCI device with a non-integer class value makes a submission |
248 | + invalid. |
249 | + """ |
250 | + self.udev_pci_device['E']['PCI_CLASS'] = 'not-an-integer' |
251 | + parser = SubmissionParser(self.log) |
252 | + parser.submission_key = 'invalid PCI class value' |
253 | + self.assertFalse(parser.checkUdevPciProperties( |
254 | + [self.udev_root_device, self.udev_pci_device])) |
255 | + self.assertErrorMessage( |
256 | + parser.submission_key, |
257 | + "Invalid udev PCI class: 'not-an-integer' " |
258 | + "'/devices/pci0000:00/0000:00:1f.2'") |
259 | + |
260 | + def testCheckUdevPciPropertiesPciDeviceWithInvalidPciClassValue(self): |
261 | + """Test of SubmmissionParser.checkUdevPciProperties(). |
262 | + |
263 | + A PCI device with invalid class data makes a submission |
264 | + invalid. |
265 | + """ |
266 | + self.udev_pci_device['E']['PCI_CLASS'] = '1234567' |
267 | + parser = SubmissionParser(self.log) |
268 | + parser.submission_key = 'too large PCI class value' |
269 | + self.assertFalse(parser.checkUdevPciProperties( |
270 | + [self.udev_root_device, self.udev_pci_device])) |
271 | + self.assertErrorMessage( |
272 | + parser.submission_key, |
273 | + "Invalid udev PCI class: '1234567' " |
274 | + "'/devices/pci0000:00/0000:00:1f.2'") |
275 | + |
276 | + def testCheckUdevPciPropertiesPciDeviceWithInvalidDeviceID(self): |
277 | + """Test of SubmmissionParser.checkUdevPciProperties(). |
278 | + |
279 | + A PCI device with an invalid device ID makes a submission |
280 | + invalid. |
281 | + """ |
282 | + self.udev_pci_device['E']['PCI_ID'] = 'not-an-id' |
283 | + parser = SubmissionParser(self.log) |
284 | + parser.submission_key = 'invalid PCI ID' |
285 | + self.assertFalse(parser.checkUdevPciProperties( |
286 | + [self.udev_root_device, self.udev_pci_device])) |
287 | + self.assertErrorMessage( |
288 | + parser.submission_key, |
289 | + "Invalid udev PCI device ID: 'not-an-id' " |
290 | + "'/devices/pci0000:00/0000:00:1f.2'") |
291 | + |
292 | + def testCheckUdevPciPropertiesPciDeviceWithInvalidSubsystemID(self): |
293 | + """Test of SubmmissionParser.checkUdevPciProperties(). |
294 | + |
295 | + A PCI device with an invalid subsystem ID makes a submission |
296 | + invalid. |
297 | + """ |
298 | + self.udev_pci_device['E']['PCI_SUBSYS_ID'] = 'not-a-subsystem-id' |
299 | + parser = SubmissionParser(self.log) |
300 | + parser.submission_key = 'invalid PCI subsystem ID' |
301 | + self.assertFalse(parser.checkUdevPciProperties( |
302 | + [self.udev_root_device, self.udev_pci_device])) |
303 | + self.assertErrorMessage( |
304 | + parser.submission_key, |
305 | + "Invalid udev PCI device ID: 'not-a-subsystem-id' " |
306 | + "'/devices/pci0000:00/0000:00:1f.2'") |
307 | + |
308 | + class UdevTestSubmissionParser(SubmissionParser): |
309 | + """A variant of SubmissionParser that shortcuts udev related tests. |
310 | + |
311 | + All shortcut methods return True. |
312 | + """ |
313 | + def checkUdevDictsHavePathKey(self, udev_data): |
314 | + """See `SubmissionParser`.""" |
315 | + return True |
316 | + |
317 | + def checkUdevPciProperties(self, udev_data): |
318 | + """See `SubmissionParser`.""" |
319 | + return True |
320 | + |
321 | + def testCheckConsistentUdevDeviceData(self): |
322 | + """Test of SubmissionParser.checkConsistentUdevDeviceData(),""" |
323 | + parser = self.UdevTestSubmissionParser() |
324 | + self.assertTrue(parser.checkConsistentUdevDeviceData(None)) |
325 | + |
326 | + def testCheckConsistentUdevDeviceData_invalid_path_data(self): |
327 | + """Test of SubmissionParser.checkConsistentUdevDeviceData(), |
328 | + |
329 | + Detection of invalid path data lets the check fail. |
330 | + """ |
331 | + class SubmissionParserUdevPathCheckFails( |
332 | + self.UdevTestSubmissionParser): |
333 | + """A SubmissionPaser where checkUdevDictsHavePathKey() fails.""" |
334 | + |
335 | + def checkUdevDictsHavePathKey(self, udev_data): |
336 | + """See `SubmissionParser`.""" |
337 | + return False |
338 | + |
339 | + parser = SubmissionParserUdevPathCheckFails() |
340 | + self.assertFalse(parser.checkConsistentUdevDeviceData(None)) |
341 | + |
342 | + def testCheckConsistentUdevDeviceData_invalid_pci_data(self): |
343 | + """Test of SubmissionParser.checkConsistentUdevDeviceData(), |
344 | + |
345 | + Detection of invalid PCI data lets the check fail. |
346 | + """ |
347 | + class SubmissionParserUdevPciCheckFails( |
348 | + self.UdevTestSubmissionParser): |
349 | + """A SubmissionPaser where checkUdevPciProperties() fails.""" |
350 | + |
351 | + def checkUdevPciProperties(self, udev_data): |
352 | + """See `SubmissionParser`.""" |
353 | + return False |
354 | + |
355 | + parser = SubmissionParserUdevPciCheckFails() |
356 | + self.assertFalse(parser.checkConsistentUdevDeviceData(None)) |
357 | + |
358 | def _setupConsistencyCheckParser(self): |
359 | """Prepare and return a SubmissionParser instance. |
360 | |
361 | @@ -1799,6 +1967,9 @@ |
362 | test.assertTrue(isinstance(self, SubmissionParser)) |
363 | return [] |
364 | |
365 | + def checkConsistentUdevDeviceData(self, udev_data): |
366 | + return True |
367 | + |
368 | parser = SubmissionParser(self.log) |
369 | parser.findDuplicateIDs = ( |
370 | lambda parsed_data: findDuplicateIDs(parser, parsed_data)) |
371 | @@ -1811,6 +1982,9 @@ |
372 | parser.checkHALDevicesParentChildConsistency = ( |
373 | lambda udi_children: checkHALDevicesParentChildConsistency( |
374 | parser, udi_children)) |
375 | + parser.checkConsistentUdevDeviceData = ( |
376 | + lambda udev_data: checkConsistentUdevDeviceData( |
377 | + parser, udev_data)) |
378 | return parser |
379 | |
380 | def assertErrorMessage(self, submission_key, log_message): |
381 | @@ -1882,10 +2056,15 @@ |
382 | } |
383 | )) |
384 | |
385 | - def testConsistencyCheckInvalidUdevData(self): |
386 | + def testConsistencyCheck_invalid_udev_data(self): |
387 | """Test of SubmissionParser.checkConsistency.""" |
388 | + def checkConsistentUdevDeviceData(self, udev_data): |
389 | + return False |
390 | + |
391 | parser = self._setupConsistencyCheckParser() |
392 | - parser.submission_key = 'Consistency check with invalid udev data' |
393 | + parser.checkConsistentUdevDeviceData = ( |
394 | + lambda udev_data: checkConsistentUdevDeviceData( |
395 | + parser, udev_data)) |
396 | self.assertFalse(parser.checkConsistency( |
397 | { |
398 | 'hardware': { |
399 | @@ -1894,8 +2073,6 @@ |
400 | } |
401 | } |
402 | )) |
403 | - self.assertErrorMessage( |
404 | - parser.submission_key, 'udev node found without a "P" key') |
405 | |
406 | def testConsistencyCheckWithDuplicateIDs(self): |
407 | """SubmissionParser.checkConsistency detects duplicate IDs.""" |
408 | |
409 | === modified file 'lib/canonical/launchpad/scripts/tests/test_hwdb_submission_processing.py' |
410 | --- lib/canonical/launchpad/scripts/tests/test_hwdb_submission_processing.py 2009-10-01 14:48:33 +0000 |
411 | +++ lib/canonical/launchpad/scripts/tests/test_hwdb_submission_processing.py 2009-10-08 13:44:12 +0000 |
412 | @@ -27,8 +27,8 @@ |
413 | from canonical.launchpad.scripts.hwdbsubmissions import ( |
414 | HALDevice, PCI_CLASS_BRIDGE, PCI_CLASS_SERIALBUS_CONTROLLER, |
415 | PCI_CLASS_STORAGE, PCI_SUBCLASS_BRIDGE_CARDBUS, PCI_SUBCLASS_BRIDGE_PCI, |
416 | - PCI_SUBCLASS_SERIALBUS_USB, PCI_SUBCLASS_STORAGE_SATA, SubmissionParser, |
417 | - process_pending_submissions) |
418 | + PCI_SUBCLASS_SERIALBUS_USB, PCI_SUBCLASS_STORAGE_SATA, |
419 | + process_pending_submissions, SubmissionParser, UdevDevice) |
420 | from canonical.launchpad.webapp.errorlog import ErrorReportingUtility |
421 | from canonical.testing import BaseLayer, LaunchpadZopelessLayer |
422 | |
423 | @@ -2591,6 +2591,84 @@ |
424 | 'property not treated as a real device.') |
425 | |
426 | |
427 | +class TestUdevDevice(TestCase): |
428 | + """Tests of class UdevDevice.""" |
429 | + |
430 | + layer = BaseLayer |
431 | + |
432 | + root_device = { |
433 | + 'P': '/devices/LNXSYSTM:00', |
434 | + 'E': { |
435 | + 'UDEV_LOG': '3', |
436 | + 'DEVPATH': '/devices/LNXSYSTM:00', |
437 | + 'MODALIAS': 'acpi:LNXSYSTM:', |
438 | + 'SUBSYSTEM': 'acpi', |
439 | + } |
440 | + } |
441 | + |
442 | + pci_device_data = { |
443 | + 'P': '/devices/pci0000:00/0000:00:1f.2', |
444 | + 'E': { |
445 | + 'PCI_CLASS': '10602', |
446 | + 'PCI_ID': '8086:27C5', |
447 | + 'PCI_SUBSYS_ID': '10CF:1387', |
448 | + 'PCI_SLOT_NAME': '0000:00:1f.2', |
449 | + 'SUBSYSTEM': 'pci', |
450 | + } |
451 | + } |
452 | + |
453 | + def test_device_id(self): |
454 | + """Test of UdevDevice.device_id.""" |
455 | + device = UdevDevice(self.pci_device_data, None, None) |
456 | + self.assertEqual( |
457 | + '/devices/pci0000:00/0000:00:1f.2', device.device_id, |
458 | + 'Unexpected value of UdevDevice.device_id.') |
459 | + |
460 | + def test_is_pci(self): |
461 | + """Test of UdevDevice.is_pci.""" |
462 | + device = UdevDevice(self.pci_device_data, None, None) |
463 | + self.assertTrue(device.is_pci) |
464 | + |
465 | + device = UdevDevice(self.root_device, None, None) |
466 | + self.assertFalse(device.is_pci) |
467 | + |
468 | + def test_pci_class_info(self): |
469 | + """Test of UdevDevice.pci_class_info""" |
470 | + device = UdevDevice(self.pci_device_data, None, None) |
471 | + self.assertEqual( |
472 | + (1, 6, 2), device.pci_class_info, |
473 | + 'Invalid value of UdevDevice.pci_class_info for PCI device.') |
474 | + |
475 | + device = UdevDevice(self.root_device, None, None) |
476 | + self.assertEqual( |
477 | + (None, None, None), device.pci_class_info, |
478 | + 'Invalid value of UdevDevice.pci_class_info for Non-PCI device.') |
479 | + |
480 | + def test_pci_class(self): |
481 | + """Test of UdevDevice.pci_class""" |
482 | + device = UdevDevice(self.pci_device_data, None, None) |
483 | + self.assertEqual( |
484 | + 1, device.pci_class, |
485 | + 'Invalid value of UdevDevice.pci_class for PCI device.') |
486 | + |
487 | + device = UdevDevice(self.root_device, None, None) |
488 | + self.assertEqual( |
489 | + None, device.pci_class, |
490 | + 'Invalid value of UdevDevice.pci_class for Non-PCI device.') |
491 | + |
492 | + def test_pci_subclass(self): |
493 | + """Test of UdevDevice.pci_subclass""" |
494 | + device = UdevDevice(self.pci_device_data, None, None) |
495 | + self.assertEqual( |
496 | + 6, device.pci_subclass, |
497 | + 'Invalid value of UdevDevice.pci_class for PCI device.') |
498 | + |
499 | + device = UdevDevice(self.root_device, None, None) |
500 | + self.assertEqual( |
501 | + None, device.pci_class, |
502 | + 'Invalid value of UdevDevice.pci_class for Non-PCI device.') |
503 | + |
504 | + |
505 | class TestHWDBSubmissionTablePopulation(TestCaseHWDB): |
506 | """Tests of the HWDB popoluation with submitted data.""" |
507 |
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 SubmissionParse r.checkUdevPciP roperties( ) 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.
SubmissionParse r.checkConsiste ncy() now calls checkConsistent UdevDeviceData( ). 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 submission_ processing
./bin/test -t test_hwdb_
= 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_submission _parser. py /launchpad/ scripts/ tests/test_ hwdb_submission _processing. py
lib/canonical
lib/canonical
lib/canonical
== 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 cElementTree' (No module named etree)
1160: [C0301] Line too long (79/78)
20: [F0401] Unable to import 'xml.etree.
lib/canonical/ launchpad/ scripts/ tests/test_ hwdb_submission _parser. py cElementTree' (No module named etree)
9: [F0401] Unable to import 'xml.etree.
These etree-related complaints are not caused by the changes in this branch.