launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #25015
[Merge] ~cjwatson/launchpad:hwdb-remove-submission-parser into launchpad:master
Colin Watson has proposed merging ~cjwatson/launchpad:hwdb-remove-submission-parser into launchpad:master.
Commit message:
Remove hardware DB submission parser
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
For more details, see:
https://code.launchpad.net/~cjwatson/launchpad/+git/launchpad/+merge/387320
We no longer accept or process submissions.
This is a very large branch and will overflow the limit for merge proposal diffs, but it's almost entirely removals. It's probably best to look at the diff on git.launchpad.net directly.
--
The attached diff has been truncated due to its size.
Your team Launchpad code reviewers is requested to review the proposed merge of ~cjwatson/launchpad:hwdb-remove-submission-parser into launchpad:master.
diff --git a/lib/lp/app/stories/basics/xx-offsite-form-post.txt b/lib/lp/app/stories/basics/xx-offsite-form-post.txt
index a58154b..4b1bcc8 100644
--- a/lib/lp/app/stories/basics/xx-offsite-form-post.txt
+++ b/lib/lp/app/stories/basics/xx-offsite-form-post.txt
@@ -100,11 +100,6 @@ To support apport, we allow it for +storeblob.
>>> browser.post('http://launchpad.test/+storeblob', 'x=1')
-Similary, we exempt the URL /+hwdb/+submit in order to allow checkbox
-to submit HWDB reports.
-
- >>> browser.post('http://launchpad.test/+hwdb/+submit', 'x=1')
-
To support old versions of launchpadlib, we also let POST requests
without a REFERER header go through to +request-token and
+access-token.
diff --git a/lib/lp/bugs/browser/bugtarget.py b/lib/lp/bugs/browser/bugtarget.py
index 45f45fa..e25187c 100644
--- a/lib/lp/bugs/browser/bugtarget.py
+++ b/lib/lp/bugs/browser/bugtarget.py
@@ -121,7 +121,6 @@ from lp.bugs.model.structuralsubscription import (
get_structural_subscriptions_for_target,
)
from lp.bugs.utilities.filebugdataparser import FileBugData
-from lp.hardwaredb.interfaces.hwdb import IHWSubmissionSet
from lp.registry.browser.product import ProductConfigureBase
from lp.registry.interfaces.distribution import IDistribution
from lp.registry.interfaces.distributionsourcepackage import (
@@ -652,13 +651,6 @@ class FileBugViewBase(LaunchpadFormView):
'%s has been subscribed to this bug.' %
person.displayname)
- submission_set = getUtility(IHWSubmissionSet)
- for submission_key in extra_data.hwdb_submission_keys:
- submission = submission_set.getBySubmissionKey(
- submission_key, self.user)
- if submission is not None:
- bug.linkHWSubmission(submission)
-
# Give the user some feedback on the bug just opened.
for notification in notifications:
self.request.response.addNotification(notification)
diff --git a/lib/lp/bugs/doc/filebug-data-parser.txt b/lib/lp/bugs/doc/filebug-data-parser.txt
index 9d34645..39e7c38 100644
--- a/lib/lp/bugs/doc/filebug-data-parser.txt
+++ b/lib/lp/bugs/doc/filebug-data-parser.txt
@@ -187,28 +187,6 @@ automatically.
[u'sub-one', u'sub-two']
-==== HWDB submission keys ====
-
-The HWDB-Submission key is turned into a list of strings, available
-through the hwdb_submission_keys attribute.
-
- >>> data = FileBugData()
- >>> parser._setDataFromHeaders(
- ... data, {'HWDB-Submission': 'submission-one'})
- >>> list(data.hwdb_submission_keys)
- [u'submission-one']
-
-Two or more submission keys may be specified, separated by a comma,
-optionally followed by space characters.
-
- >>> data = FileBugData()
- >>> parser._setDataFromHeaders(
- ... data,
- ... {'HWDB-Submission': ' submission-one, two\t,three , \nfour '})
- >>> data.hwdb_submission_keys
- [u'four', u'submission-one', u'three', u'two']
-
-
=== Message Parts ===
Different parts of the message gets treated differently. In short, we
diff --git a/lib/lp/bugs/interfaces/bug.py b/lib/lp/bugs/interfaces/bug.py
index dab809d..74def4b 100644
--- a/lib/lp/bugs/interfaces/bug.py
+++ b/lib/lp/bugs/interfaces/bug.py
@@ -1251,7 +1251,6 @@ class IFileBugData(Interface):
subscribers = Attribute("The initial subscribers for the bug.")
comments = Attribute("Comments to add to the bug.")
attachments = Attribute("Attachments to add to the bug.")
- hwdb_submission_keys = Attribute("HWDB submission keys for the bug.")
class IBugMute(Interface):
diff --git a/lib/lp/bugs/model/apportjob.py b/lib/lp/bugs/model/apportjob.py
index a2f16e0..fdbc847 100644
--- a/lib/lp/bugs/model/apportjob.py
+++ b/lib/lp/bugs/model/apportjob.py
@@ -270,7 +270,6 @@ class ProcessApportBlobJob(ApportJobDerived):
subscribers=processed_data['subscribers'],
extra_description=processed_data['extra_description'],
comments=processed_data['comments'],
- hwdb_submission_keys=processed_data['hwdb_submission_keys'],
attachments=attachment_data)
else:
return FileBugData()
diff --git a/lib/lp/bugs/model/bug.py b/lib/lp/bugs/model/bug.py
index 98169c6..9fa5155 100644
--- a/lib/lp/bugs/model/bug.py
+++ b/lib/lp/bugs/model/bug.py
@@ -2796,8 +2796,7 @@ class FileBugData:
def __init__(self, initial_summary=None, initial_tags=None,
private=None, subscribers=None, extra_description=None,
- comments=None, attachments=None,
- hwdb_submission_keys=None):
+ comments=None, attachments=None):
if initial_tags is None:
initial_tags = []
if subscribers is None:
@@ -2806,8 +2805,6 @@ class FileBugData:
comments = []
if attachments is None:
attachments = []
- if hwdb_submission_keys is None:
- hwdb_submission_keys = []
self.initial_summary = initial_summary
self.private = private
@@ -2816,7 +2813,6 @@ class FileBugData:
self.subscribers = subscribers
self.comments = comments
self.attachments = attachments
- self.hwdb_submission_keys = hwdb_submission_keys
def asDict(self):
"""Return the FileBugData instance as a dict."""
diff --git a/lib/lp/bugs/stories/guided-filebug/xx-bug-reporting-tools.txt b/lib/lp/bugs/stories/guided-filebug/xx-bug-reporting-tools.txt
index 3a42491..705f57f 100644
--- a/lib/lp/bugs/stories/guided-filebug/xx-bug-reporting-tools.txt
+++ b/lib/lp/bugs/stories/guided-filebug/xx-bug-reporting-tools.txt
@@ -238,55 +238,3 @@ that will get their tags set as well.
>>> tags = find_tag_by_id(user_browser.contents, 'bug-tags')
>>> print(extract_text(tags))
Tags: bar foo...
-
-
-References to HWDB submissions
-------------------------------
-
-The uploaded message may contain a header "HWDB-Submission", its value
-should be a sequence of HWDB submission keys, separated by ', *'.
-If the message contains this header, the referenced HWDB submissions are
-linked to the new bug.
-
-Our test data contains such a header, mentioning two HWDB submision key.
-The database knows only the first key.
-
- >>> extra_filebug_data_with_hwdb_submission = open(
- ... os.path.join(testfiles, 'extra_filebug_data_hwdb_submission.msg'),
- ... 'rb')
- >>> print(
- ... extra_filebug_data_with_hwdb_submission.read()
- ... .decode('UTF-8').split('\n')[2])
- HWDB-Submission: sample-submission, non-existing-submission-key
-
-Once we submit the bug report...
-
- >>> extra_filebug_data_with_hwdb_submission.seek(0)
- >>> anon_browser.open('http://launchpad.test/+storeblob')
- >>> anon_browser.getControl(name='field.blob').add_file( # Don't change!
- ... extra_filebug_data_with_hwdb_submission, 'not/important',
- ... 'not.important')
- >>> anon_browser.getControl(name='FORM_SUBMIT').click() # Don't change!
- >>> blob_token = six.ensure_text(
- ... anon_browser.headers['X-Launchpad-Blob-Token'])
- >>> process_blob(blob_token)
-
- >>> filebug_url = (
- ... 'http://launchpad.test/ubuntu/+source/mozilla-firefox/+filebug/'
- ... '%s' % blob_token)
- >>> user_browser.open(filebug_url)
- >>> user_browser.getControl('Summary', index=0).value = 'Another summary'
- >>> user_browser.getControl('Continue').click()
- >>> user_browser.getControl('Further information').value = (
- ... 'A bug description.')
- >>> user_browser.getControl('Submit Bug Report').click()
-
-...the existing HWDB submission is linked to the new bug.
-
- >>> bug_id = user_browser.url.split('/')[-1]
- >>> bug_url = '/bugs/%s' % bug_id
- >>> linked_submissions = webservice.named_get(
- ... bug_url, 'getHWSubmissions').jsonBody()
- >>> for submission in linked_submissions['entries']:
- ... print(submission['submission_key'])
- sample-submission
diff --git a/lib/lp/bugs/tests/test_apportjob.py b/lib/lp/bugs/tests/test_apportjob.py
index 9f5baa7..3074097 100644
--- a/lib/lp/bugs/tests/test_apportjob.py
+++ b/lib/lp/bugs/tests/test_apportjob.py
@@ -120,10 +120,6 @@ class ProcessApportBlobJobTestCase(TestCaseWithFactory):
self.assertEqual(
filebug_data.comments, data_dict['comments'],
"Values for comments do not match")
- self.assertEqual(
- filebug_data.hwdb_submission_keys,
- data_dict['hwdb_submission_keys'],
- "Values for hwdb_submission_keys do not match")
# The attachments list of the data_dict dict will be of
# the same length as the attachments list in the filebug_data
diff --git a/lib/lp/bugs/tests/testfiles/extra_filebug_data_hwdb_submission.msg b/lib/lp/bugs/tests/testfiles/extra_filebug_data_hwdb_submission.msg
deleted file mode 100644
index 5bbbdfc..0000000
--- a/lib/lp/bugs/tests/testfiles/extra_filebug_data_hwdb_submission.msg
+++ /dev/null
@@ -1,11 +0,0 @@
-MIME-Version: 1.0
-Content-type: multipart/mixed; boundary=boundary
-HWDB-Submission: sample-submission, non-existing-submission-key
-
---boundary
-Content-disposition: inline
-Content-type: text/plain; charset=utf-8
-
-This should be added to the description.
-
---boundary--
diff --git a/lib/lp/bugs/utilities/filebugdataparser.py b/lib/lp/bugs/utilities/filebugdataparser.py
index f1266d6..7ab6540 100644
--- a/lib/lp/bugs/utilities/filebugdataparser.py
+++ b/lib/lp/bugs/utilities/filebugdataparser.py
@@ -88,10 +88,6 @@ class FileBugDataParser:
if 'Subscribers' in headers:
subscribers_string = unicode(headers['Subscribers'])
data.subscribers = subscribers_string.lower().split()
- if 'HWDB-Submission' in headers:
- submission_string = unicode(headers['HWDB-Submission'])
- data.hwdb_submission_keys = sorted(
- part.strip() for part in submission_string.split(','))
def parse(self):
"""Parse the message and return a FileBugData instance.
diff --git a/lib/lp/hardwaredb/browser/configure.zcml b/lib/lp/hardwaredb/browser/configure.zcml
index 4d06052..ed130e5 100644
--- a/lib/lp/hardwaredb/browser/configure.zcml
+++ b/lib/lp/hardwaredb/browser/configure.zcml
@@ -12,18 +12,6 @@
for="lp.hardwaredb.interfaces.hwdb.IHWDBApplication"
path_expression="string:+hwdb"
parent_utility="lp.services.webapp.interfaces.ILaunchpadRoot"/>
- <browser:page
- for="lp.hardwaredb.interfaces.hwdb.IHWDBApplication"
- class="lp.hardwaredb.browser.hwdb.HWDBUploadView"
- permission="zope.Public"
- name="+submit"
- template="../templates/hwdb-submit-hardware-data.pt"/>
- <browser:page
- for="lp.hardwaredb.interfaces.hwdb.HWSubmissionsDisabledError"
- class="lp.hardwaredb.browser.hwdb.HWDBSubmissionsDisabledView"
- name="index.html"
- permission="zope.Public"
- template="../templates/hwdb-submissions-disabled.pt"/>
<browser:url
for="lp.hardwaredb.interfaces.hwdb.IHWSystemFingerprint"
path_expression="string:+fingerprint/${fingerprint}"
diff --git a/lib/lp/hardwaredb/browser/hwdb.py b/lib/lp/hardwaredb/browser/hwdb.py
index bbd1ee6..03bf04c 100644
--- a/lib/lp/hardwaredb/browser/hwdb.py
+++ b/lib/lp/hardwaredb/browser/hwdb.py
@@ -7,9 +7,7 @@ __all__ = [
'HWDBApplicationNavigation',
'HWDBFingerprintSetView',
'HWDBPersonSubmissionsView',
- 'HWDBSubmissionsDisabledView',
'HWDBSubmissionTextView',
- 'HWDBUploadView',
]
from textwrap import dedent
@@ -19,10 +17,6 @@ from zope.component import getUtility
from zope.interface import implementer
from zope.publisher.interfaces.browser import IBrowserPublisher
-from lp.app.browser.launchpadform import (
- action,
- LaunchpadFormView,
- )
from lp.app.errors import NotFoundError
from lp.hardwaredb.interfaces.hwdb import (
IHWDBApplication,
@@ -30,140 +24,18 @@ from lp.hardwaredb.interfaces.hwdb import (
IHWDeviceSet,
IHWDriverSet,
IHWSubmissionDeviceSet,
- IHWSubmissionForm,
IHWSubmissionSet,
- IHWSystemFingerprintSet,
IHWVendorIDSet,
)
-from lp.registry.interfaces.distribution import IDistributionSet
from lp.services.webapp import (
LaunchpadView,
Navigation,
stepthrough,
)
from lp.services.webapp.batching import BatchNavigator
-from lp.services.webapp.error import GoneView
from lp.services.webapp.interfaces import ILaunchBag
-class HWDBUploadView(LaunchpadFormView):
- """View class for hardware database submissions."""
-
- schema = IHWSubmissionForm
- label = 'Hardware Database Submission'
- page_title = 'Submit New Data to the Launchpad Hardware Database'
-
- @action(u'Upload', name='upload')
- def upload_action(self, action, data):
- """Create a record in the HWSubmission table."""
- # We expect that the data submitted by the client contains
- # data for all fields defined in the form. The main client
- # which POSTs data to this URL, checkbox, sometimes omits
- # some fields (see bug 357316). The absence of required
- # fields is not caught by Zope's form validation -- it only
- # checks if required fields are not empty, and does this only
- # if these fields are present in the form data. Absent fields
- # are not detected, so let's do that here.
- expected_fields = set(self.schema.names())
- submitted_fields = set(data)
- missing_fields = expected_fields.difference(submitted_fields)
- if len(missing_fields) > 0:
- missing_fields = ', '.join(sorted(missing_fields))
- self.addCustomHeader(
- 'Error: Required fields not contained in POST data: '
- + missing_fields)
- return
-
- distributionset = getUtility(IDistributionSet)
- distribution = distributionset.getByName(data['distribution'].lower())
- if distribution is not None:
- release = data['distroseries']
- architecture = data['architecture']
- try:
- distroseries = distribution.getSeries(release)
- except NotFoundError:
- self.addErrorHeader("distroseries",
- "%s isn't a valid distribution series"
- % data['distroseries'])
- return
-
- try:
- distroarchseries = distroseries[architecture]
- except NotFoundError:
- self.addErrorHeader("distroarchseries",
- "%s isn't a valid distribution architecture"
- % data['architecture'])
- return
- else:
- distroarchseries = None
-
- fingerprintset = getUtility(IHWSystemFingerprintSet)
- fingerprint = fingerprintset.getByName(data['system'])
- if fingerprint is None:
- fingerprint = fingerprintset.createFingerprint(data['system'])
-
- filesize = len(data['submission_data'])
- submission_file = self.request.form[
- self.widgets['submission_data'].name]
- submission_file.seek(0)
- # convert a filename with "path elements" to a regular filename
- filename = submission_file.filename.replace('/', '-')
-
- hw_submissionset = getUtility(IHWSubmissionSet)
- hw_submissionset.createSubmission(
- date_created=data['date_created'],
- format=data['format'],
- private=data['private'],
- contactable=data['contactable'],
- submission_key=data['submission_key'],
- emailaddress=data['emailaddress'],
- distroarchseries=distroarchseries,
- raw_submission=submission_file,
- filename=filename,
- filesize=filesize,
- system_fingerprint=data['system'])
-
- self.addCustomHeader('OK data stored')
- self.request.response.addNotification(
- "Thank you for your submission.")
-
- def render(self):
- """See ILaunchpadFormView."""
- if self.errors:
- self.setHeadersForHWDBClient()
- return LaunchpadFormView.render(self)
-
- def setHeadersForHWDBClient(self):
- """Add headers that help the HWDB client detect a successful upload.
-
- An upload is normally not made by a regular web browser, but by the
- HWDB client. In order to allow the client to easily detect a
- successful as well as an failed request, add some HTTP headers
- to the response.
- """
- for field in self.form_fields:
- field_name = field.__name__
- error = self.getFieldError(field_name)
- if error:
- self.addErrorHeader(field_name, error)
-
- def addErrorHeader(self, field_name, error):
- """Adds a header informing an error to automated clients."""
- return self.addCustomHeader(u"Error in field '%s' - %s" %
- (field_name, error))
-
- def addCustomHeader(self, value):
- """Adds a custom header to HWDB clients."""
- self.request.response.setHeader(
- u'X-Launchpad-HWDB-Submission', value)
-
-
-class HWDBSubmissionsDisabledView(GoneView):
- """View to indicate that new submissions are disabled."""
-
- page_title = "Hardware database submissions disabled"
-
-
class HWDBPersonSubmissionsView(LaunchpadView):
"""View class for preseting HWDB submissions by a person."""
diff --git a/lib/lp/hardwaredb/doc/hwdb-submission.txt b/lib/lp/hardwaredb/doc/hwdb-submission.txt
deleted file mode 100644
index 13f3edc..0000000
--- a/lib/lp/hardwaredb/doc/hwdb-submission.txt
+++ /dev/null
@@ -1,215 +0,0 @@
-Submissions to the hardware database
-====================================
-
-The hardware database client collects information from various sources,
-and submits it in an HTTP POST request to the hardware database server.
-The POST data consists of the following fields:
-
- * date_created (see hwdb.txt)
- * format (see hwdb.txt)
- * private (see hwdb.txt)
- * contactable (see hwdb.txt)
- * submission_key (see hwdb.txt)
- * emailaddress (see hwdb.txt)
- * distribution: The distribution name. The value should match a value
- in the SQL table Distribution, column name.
- * distroseries: The distroseries version. The value should match a value
- in the SQL table distroseries, column version
- * processorfamily: The name of the processorfamily. The value should
- match a value in the SQL table Processorfamily, column name.
- * system: The system name as returned by HAL (system.vendor, system.product)
- * submission_data: An XML file containing the collected data. This file is
- simply stored as a Librarian file, and parsed later by a cron job.
-
- >>> import io
- >>> from zope.component import getUtility
- >>> from lp.hardwaredb.interfaces.hwdb import IHWDBApplication
- >>> data = io.BytesIO(b'some data.')
- >>> data.filename = 'hardware-info'
- >>> form={'field.date_created': u'2007-08-01',
- ... 'field.format': u'VERSION_1',
- ... 'field.private': u'',
- ... 'field.contactable': u'',
- ... 'field.submission_key': u'unique-id-1',
- ... 'field.emailaddress': u'test@xxxxxxxxxxxxx',
- ... 'field.distribution': u'ubuntu',
- ... 'field.distroseries': u'5.04',
- ... 'field.architecture': u'i386',
- ... 'field.system': u'HP 6543',
- ... 'field.submission_data': data,
- ... 'field.actions.upload': u'Upload'}
-
- >>> app = getUtility(IHWDBApplication)
- >>> submit_view = create_initialized_view(app, name='+submit', form=form)
- >>> submit_view.errors
- []
-
-The request created an entry in the HWDBSubmissions table.
-
- >>> from lp.hardwaredb.interfaces.hwdb import IHWSubmissionSet
- >>> submission_set = getUtility(IHWSubmissionSet)
- >>> submission = submission_set.getBySubmissionKey(u'unique-id-1')
- >>> submission.date_created, submission.format.name
- (datetime.datetime(2007, 8, 1, 0, 0, tzinfo=<UTC>), 'VERSION_1')
- >>> submission.private, submission.contactable
- (False, False)
- >>> submission.submission_key
- u'unique-id-1'
- >>> submission.system_fingerprint.fingerprint
- u'HP 6543'
-
-The submitted data is stored in raw_submission.
-
- >>> import transaction
- >>> transaction.commit()
- >>> submission.raw_submission.read()
- 'some data.'
-
-A reference to distroarchseries is created for the fields distribution,
-distroseries, architecture.
-
- >>> submission.distroarchseries.distroseries.distribution.name
- u'ubuntu'
- >>> submission.distroarchseries.distroseries.version
- u'5.04'
- >>> submission.distroarchseries.architecturetag
- u'i386'
-
-Each submission must have a distinct submission_key, hence an attempt to submit
-identical data a second time leads to an error.
-
- >>> submit_view = create_initialized_view(app, name='+submit', form=form)
- >>> for error in submit_view.errors:
- ... print(error.doc())
- Submission key already exists.
-
-If the field distribution contains a name which is not known in the
-Launchpad database, the distroarchseries field is None.
-
- >>> form['field.submission_key'] = u'unique-id-2'
- >>> invalid_form = form.copy()
- >>> invalid_form['field.distribution'] = 'no distribution'
- >>> submit_view = create_initialized_view(
- ... app, name='+submit', form=invalid_form)
- >>> submission = submission_set.getBySubmissionKey(u'unique-id-2')
- >>> print(submission.distroarchseries)
- None
-
-If distribution is known, but distroseries or architecture are unknown
-to Launchpad, we refuse the submissions.
-
- >>> form['field.submission_key'] = u'unique-id-3'
- >>> invalid_form = form.copy()
- >>> invalid_form['field.distroseries'] = 'no release'
- >>> submit_view = create_initialized_view(
- ... app, name='+submit', form=invalid_form)
- >>> print(submission_set.getBySubmissionKey(u'unique-id-3'))
- None
-
- >>> form['field.submission_key'] = u'unique-id-4'
- >>> invalid_form = form.copy()
- >>> invalid_form['field.architecture'] = 'no architecture'
- >>> submit_view = create_initialized_view(
- ... app, name='+submit', form=invalid_form)
- >>> print(submission_set.getBySubmissionKey(u'unique-id-4'))
- None
-
-The `date_created` field must contain a valid date.
-
- >>> form['field.submission_key'] = u'unique-id-5'
- >>> invalid_form = form.copy()
- >>> invalid_form['field.date_created'] = '2007-05-35'
- >>> submit_view = create_initialized_view(
- ... app, name='+submit', form=invalid_form)
- >>> for error in submit_view.errors:
- ... print(error.doc())
- Invalid datetime data
-
-The `format` field must contain a value that matches the DBEnumeratedType
-HWDBSubmissionFormat.
-
- >>> invalid_form = form.copy()
- >>> invalid_form['field.format'] = u'VERSION_42'
- >>> submit_view = create_initialized_view(
- ... app, name='+submit', form=invalid_form)
- >>> for error in submit_view.errors:
- ... print(error.doc())
- Invalid value
-
-The field `submission_key` may contain only ASCII data.
-
- >>> invalid_form = form.copy()
- >>> invalid_form['field.submission_key'] = u'wrong id \x81'
- >>> submit_view = create_initialized_view(
- ... app, name='+submit', form=invalid_form)
- >>> for error in submit_view.errors:
- ... print(error.doc())
- Invalid textual data
-
-The field `emailaddress` must contain a formally valid email address.
-
- >>> invalid_form = form.copy()
- >>> invalid_form['field.emailaddress'] = u'beeblebrox'
- >>> submit_view = create_initialized_view(
- ... app, name='+submit', form=invalid_form)
- >>> for error in submit_view.errors:
- ... print(error.doc())
- Invalid email address
-
-All fields are required. With normal form processing, it's impossible not to
-have values for field.format, field.private, or field.contactable because
-those widgets are checkboxes and menus.
-
- >>> for field in (
- ... 'field.date_created', 'field.submission_key',
- ... 'field.emailaddress', 'field.distribution',
- ... 'field.distroseries', 'field.architecture',
- ... 'field.system', 'field.submission_data',
- ... ):
- ... invalid_form = form.copy()
- ... del invalid_form[field]
- ... invalid_form[field] = u''
- ... submit_view = create_initialized_view(
- ... app, name='+submit', form=invalid_form)
- ... print(field)
- ... for error in submit_view.errors:
- ... field_name = error.field_name
- ... print(' ', field_name,
- ... submit_view.getFieldError(field_name))
- field.date_created
- date_created Required input is missing.
- field.submission_key
- submission_key Required input is missing.
- field.emailaddress
- emailaddress Required input is missing.
- field.distribution
- distribution Required input is missing.
- field.distroseries
- distroseries Required input is missing.
- field.architecture
- architecture Required input is missing.
- field.system
- system Required input is missing.
- field.submission_data
- submission_data Required input is missing.
-
-Teams can be owners of submissions.
-
- >>> import os
- >>> from lp.services.config import config
- >>> team_form = form.copy()
- >>> team_form['field.emailaddress'] = 'support@xxxxxxxxxx'
- >>> team_form['field.submission_key'] = u'unique-id-68'
- >>> valid_sample_data_path = os.path.join(
- ... config.root,
- ... 'lib/lp/hardwaredb/scripts/tests/'
- ... 'simple_valid_hwdb_submission.xml')
- >>> valid_sample_data = io.BytesIO(
- ... open(valid_sample_data_path, 'rb').read())
- >>> valid_sample_data.filename = 'simple_valid_hwdb_submission.xml'
- >>> team_form['field.submission_data'] = valid_sample_data
- >>> submit_view = create_initialized_view(
- ... app, name='+submit', form=team_form)
- >>> submission = submission_set.getBySubmissionKey(u'unique-id-68')
- >>> submission.owner.displayname
- u'Ubuntu Team'
diff --git a/lib/lp/hardwaredb/scripts/__init__.py b/lib/lp/hardwaredb/scripts/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/lib/lp/hardwaredb/scripts/__init__.py
+++ /dev/null
diff --git a/lib/lp/hardwaredb/scripts/hardware-1_0.rng b/lib/lp/hardwaredb/scripts/hardware-1_0.rng
deleted file mode 100644
index aabe1e7..0000000
--- a/lib/lp/hardwaredb/scripts/hardware-1_0.rng
+++ /dev/null
@@ -1,539 +0,0 @@
-<?xml version="1.0" ?>
-<grammar xmlns="http://relaxng.org/ns/structure/1.0"
- datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes"
- xmlns:a="http://launchpad.net/annotation">
- <start>
- <element name="system">
- <attribute name="version">
- <value>1.0</value>
- </attribute>
- <interleave>
- <element name="summary">
- <ref name="summarySection"/>
- </element>
- <element name="hardware">
- <ref name="hardwareSection"/>
- </element>
- <element name="software">
- <ref name="softwareSection"/>
- </element>
- <element name="questions">
- <ref name="questionsSection"/>
- </element>
- <optional>
- <element name="context">
- <ref name="contextSection"/>
- </element>
- </optional>
- </interleave>
- </element>
- </start>
-
- <define name="summarySection">
- <interleave>
- <element name="live_cd">
- <attribute name="value">
- <ref name="booleanValue"/>
- </attribute>
- <empty/>
- </element>
- <element name="system_id">
- <attribute name="value">
- <text/>
- </attribute>
- <empty/>
- </element>
- <element name="distribution">
- <attribute name="value">
- <text/>
- </attribute>
- <empty/>
- </element>
- <element name="distroseries">
- <attribute name="value">
- <text/>
- </attribute>
- <empty/>
- </element>
- <element name="architecture">
- <attribute name="value">
- <text/>
- </attribute>
- <empty/>
- </element>
- <element name="private">
- <attribute name="value">
- <ref name="booleanValue"/>
- </attribute>
- <empty/>
- </element>
- <element name="contactable">
- <attribute name="value">
- <ref name="booleanValue"/>
- </attribute>
- <empty/>
- </element>
- <element name="date_created">
- <attribute name="value">
- <data type="dateTime"/>
- </attribute>
- <empty/>
- </element>
- <element name="client">
- <attribute name="name">
- <text/>
- </attribute>
- <attribute name="version">
- <text/>
- </attribute>
- <empty/>
- <zeroOrMore>
- <element name="plugin">
- <attribute name="name">
- <text/>
- </attribute>
- <attribute name="version">
- <text/>
- </attribute>
- </element>
- </zeroOrMore>
- </element>
- <optional>
- <element name="kernel-release">
- <attribute name="value">
- <text/>
- </attribute>
- </element>
- </optional>
- </interleave>
- </define>
-
- <define name="hardwareSection">
- <interleave>
- <choice>
- <element name="hal">
- <attribute name="version">
- <text/>
- </attribute>
- <oneOrMore>
- <element name="device">
- <attribute name="id">
- <data type="integer">
- <except>
- <value/>
- </except>
- </data>
- </attribute>
- <attribute name="udi">
- <text/>
- </attribute>
- <optional>
- <attribute name="parent">
- <data type="integer"/>
- </attribute>
- </optional>
- <!-- XXX: Abel Deuring 2007-12-07:
- specify a set of required properties? -->
- <oneOrMore>
- <ref name="property"/>
- </oneOrMore>
- </element>
- </oneOrMore>
- </element>
- <group>
- <interleave>
- <element name="udev">
- <text/>
- </element>
- <element name="dmi">
- <text/>
- </element>
- <optional>
- <!-- Unfortunately, the checkbox version in
- Maverick and Natty do not provide sysfs
- data.
- -->
- <element name="sysfs-attributes">
- <zeroOrMore>
- <text/>
- </zeroOrMore>
- </element>
- </optional>
- </interleave>
- </group>
- </choice>
- <element name="processors">
- <oneOrMore>
- <element name="processor">
- <attribute name="id">
- <data type="integer">
- <except>
- <value/>
- </except>
- </data>
- </attribute>
- <attribute name="name">
- <text/>
- </attribute>
- <oneOrMore>
- <ref name="property"/>
- </oneOrMore>
- </element>
- </oneOrMore>
- </element>
- <optional>
- <element name="aliases">
- <zeroOrMore>
- <element name="alias">
- <attribute name="target">
- <text/>
- </attribute>
- <interleave>
- <element name="vendor">
- <text/>
- </element>
- <element name="model">
- <text/>
- </element>
- </interleave>
- </element>
- </zeroOrMore>
- </element>
- </optional>
- </interleave>
- </define>
-
- <define name="softwareSection">
- <interleave>
- <element name="lsbrelease">
- <!-- XXX: Abel Deuring 2007-12-07:
- specify a more restrictive set of allowed
- and/or required properties?
- -->
- <oneOrMore>
- <ref name="property"/>
- </oneOrMore>
- </element>
- <optional>
- <element name="packages">
- <zeroOrMore>
- <element name="package">
- <attribute name="name"/>
- <attribute name="id">
- <data type="integer">
- <except>
- <value/>
- </except>
- </data>
- </attribute>
- <oneOrMore>
- <ref name="property"/>
- </oneOrMore>
- </element>
- </zeroOrMore>
- </element>
- </optional>
- <optional>
- <element name="xorg">
- <attribute name="version">
- <text/>
- </attribute>
- <zeroOrMore>
- <element name="driver">
- <optional>
- <attribute name="device">
- <data type="integer"/>
- </attribute>
- </optional>
- <attribute name="name">
- <text/>
- </attribute>
- <optional>
- <attribute name="version">
- <text/>
- </attribute>
- </optional>
- <attribute name="class">
- <text/>
- </attribute>
- </element>
- </zeroOrMore>
- </element>
- </optional>
- </interleave>
- </define>
-
- <define name="questionsSection">
- <zeroOrMore>
- <element name="question">
- <attribute name="name">
- <text/>
- </attribute>
- <a:comment>
- The attribute "plugin" must be set, if the question
- is generated by a plugin.
- </a:comment>
- <optional>
- <attribute name="plugin">
- <text/>
- </attribute>
- </optional>
- <interleave>
- <optional>
- <element name="command">
- <text/>
- </element>
- </optional>
- <choice>
- <interleave>
- <element name="answer">
- <attribute name="type">
- <value>multiple_choice</value>
- </attribute>
- <optional>
- <attribute name="unit">
- <text/>
- </attribute>
- </optional>
- <text/>
- </element>
- <element name="answer_choices">
- <oneOrMore>
- <ref name="value"/>
- </oneOrMore>
- </element>
- </interleave>
- <element name="answer">
- <attribute name="type">
- <value>measurement</value>
- </attribute>
- <optional>
- <attribute name="unit">
- <text/>
- </attribute>
- </optional>
- <data type="decimal"/>
- </element>
- </choice>
- <zeroOrMore>
- <element name="target">
- <attribute name="id">
- <text/>
- </attribute>
- <interleave>
- <zeroOrMore>
- <element name="driver">
- <text/>
- </element>
- </zeroOrMore>
- </interleave>
- </element>
- </zeroOrMore>
- <optional>
- <element name="comment">
- <text/>
- </element>
- </optional>
- </interleave>
- </element>
- </zeroOrMore>
- </define>
-
- <define name="contextSection">
- <zeroOrMore>
- <element name="info">
- <attribute name="command">
- <text/>
- </attribute>
- <text/>
- </element>
- </zeroOrMore>
- </define>
-
- <a:comment>
- convenience for Python code: 'True'/'False' for boolean values
- instead of 'true'/'false' as defined by
- http://www.w3.org/2001/XMLSchema-datatypes .
- </a:comment>
- <define name="booleanValue">
- <choice>
- <value>True</value>
- <value>False</value>
- </choice>
- </define>
-
- <define name="propertyAndValueContent">
- <a:comment>
- Allowed types and values:
- The dbus... data types are used for HAL properties; the data
- types are specified in
- http://dbus.freedesktop.org/doc/dbus-specification.html
- The other data types are Python data types, defined in
- http://docs.python.org/lib/types.html
- </a:comment>
- <choice>
- <group>
- <attribute name="type">
- <choice>
- <value>dbus.Boolean</value>
- <value>bool</value>
- </choice>
- </attribute>
- <ref name="booleanValue"/>
- </group>
- <group>
- <attribute name="type">
- <choice>
- <value>dbus.String</value>
- <value>dbus.UTF8String</value>
- <value>str</value>
- </choice>
- </attribute>
- <text/>
- </group>
- <group>
- <attribute name="type">
- <value>dbus.Byte</value>
- </attribute>
- <data type="unsignedByte">
- <except>
- <value/>
- </except>
- </data>
- </group>
- <group>
- <attribute name="type">
- <value>dbus.Int16</value>
- </attribute>
- <data type="short">
- <except>
- <value/>
- </except>
- </data>
- </group>
- <group>
- <attribute name="type">
- <value>dbus.Int32</value>
- </attribute>
- <data type="int">
- <except>
- <value/>
- </except>
- </data>
- </group>
- <group>
- <attribute name="type">
- <value>dbus.Int64</value>
- </attribute>
- <data type="long">
- <except>
- <value/>
- </except>
- </data>
- </group>
- <group>
- <attribute name="type">
- <value>dbus.UInt16</value>
- </attribute>
- <data type="unsignedShort">
- <except>
- <value/>
- </except>
- </data>
- </group>
- <group>
- <attribute name="type">
- <value>dbus.UInt32</value>
- </attribute>
- <data type="unsignedInt">
- <except>
- <value/>
- </except>
- </data>
- </group>
- <group>
- <attribute name="type">
- <value>dbus.UInt64</value>
- </attribute>
- <data type="unsignedLong">
- <except>
- <value/>
- </except>
- </data>
- </group>
- <group>
- <attribute name="type">
- <value>int</value>
- </attribute>
- <data type="long">
- <except>
- <value/>
- </except>
- </data>
- </group>
- <group>
- <attribute name="type">
- <value>long</value>
- </attribute>
- <data type="integer">
- <except>
- <value/>
- </except>
- </data>
- </group>
- <group>
- <attribute name="type">
- <choice>
- <value>dbus.Double</value>
- <value>float</value>
- </choice>
- </attribute>
- <data type="decimal"/>
- </group>
- <group>
- <attribute name="type">
- <choice>
- <value>dbus.Array</value>
- <value>list</value>
- </choice>
- </attribute>
- <zeroOrMore>
- <element name="value">
- <ref name="propertyAndValueContent"/>
- </element>
- </zeroOrMore>
- </group>
- <group>
- <attribute name="type">
- <choice>
- <value>dbus.Dictionary</value>
- <value>dict</value>
- </choice>
- </attribute>
- <zeroOrMore>
- <element name="value">
- <attribute name="name">
- <text/>
- </attribute>
- <ref name="propertyAndValueContent"/>
- </element>
- </zeroOrMore>
- </group>
- </choice>
- </define>
-
- <define name="property">
- <element name="property">
- <attribute name="name">
- <text/>
- </attribute>
- <ref name="propertyAndValueContent"/>
- </element>
- </define>
-
- <define name="value">
- <element name="value">
- <ref name="propertyAndValueContent"/>
- </element>
- </define>
-</grammar>
diff --git a/lib/lp/hardwaredb/scripts/hwdbsubmissions.py b/lib/lp/hardwaredb/scripts/hwdbsubmissions.py
deleted file mode 100644
index 07ff095..0000000
--- a/lib/lp/hardwaredb/scripts/hwdbsubmissions.py
+++ /dev/null
@@ -1,2952 +0,0 @@
-# Copyright 2009-2019 Canonical Ltd. This software is licensed under the
-# GNU Affero General Public License version 3 (see the file LICENSE).
-
-"""Parse Hardware Database submissions.
-
-Base classes, intended to be used both for the commercial certification
-data and for the community test submissions.
-"""
-
-__metaclass__ = type
-__all__ = [
- 'SubmissionParser',
- ]
-
-import bz2
-from datetime import (
- datetime,
- timedelta,
- )
-import io
-from logging import getLogger
-import os
-import re
-
-import defusedxml.cElementTree as etree
-import pytz
-from zope.component import getUtility
-
-from lp.hardwaredb.interfaces.hwdb import (
- HWBus,
- IHWDeviceDriverLinkSet,
- IHWDeviceSet,
- IHWDriverSet,
- IHWSubmissionDeviceSet,
- IHWVendorIDSet,
- IHWVendorNameSet,
- )
-from lp.services.config import config
-from lp.services.propertycache import cachedproperty
-from lp.services.scripts.base import disable_oops_handler
-from lp.services.xml import RelaxNGValidator
-
-
-_relax_ng_files = {
- '1.0': 'hardware-1_0.rng', }
-
-_time_regex = re.compile(r"""
- ^(?P<year>\d\d\d\d)-(?P<month>\d\d)-(?P<day>\d\d)
- T(?P<hour>\d\d):(?P<minute>\d\d):(?P<second>\d\d)
- (?:\.(?P<second_fraction>\d{0,6}))?
- (?P<tz>
- (?:(?P<tz_sign>[-+])(?P<tz_hour>\d\d):(?P<tz_minute>\d\d))
- | Z)?$
- """,
- re.VERBOSE)
-
-_broken_comment_nodes_re = re.compile(br'(<comment>.*?</comment>)', re.DOTALL)
-_missing_udev_node_data = re.compile(
- br'<info command="udevadm info --export-db">(.*?)</info>', re.DOTALL)
-_missing_dmi_node_data = re.compile(
- br'<info command="grep -r \. /sys/class/dmi/id/ 2>/dev/null">(.*?)'
- br'</info>', re.DOTALL)
-_udev_node_exists = re.compile(
- br'<hardware>.*?<udev>.*?</hardware>', re.DOTALL)
-_dmi_node_exists = re.compile(br'<hardware>.*?<dmi>.*?</hardware>', re.DOTALL)
-
-ROOT_UDI = '/org/freedesktop/Hal/devices/computer'
-UDEV_ROOT_PATH = '/devices/LNXSYSTM:00'
-
-# These UDIs appears in some submissions more than once.
-KNOWN_DUPLICATE_UDIS = set((
- '/org/freedesktop/Hal/devices/ssb__null_',
- '/org/freedesktop/Hal/devices/uinput',
- '/org/freedesktop/Hal/devices/ignored-device',
- ))
-
-# See include/linux/pci_ids.h in the Linux kernel sources for a complete
-# list of PCI class and subclass codes.
-PCI_CLASS_STORAGE = 1
-PCI_SUBCLASS_STORAGE_SATA = 6
-
-PCI_CLASS_BRIDGE = 6
-PCI_SUBCLASS_BRIDGE_PCI = 4
-PCI_SUBCLASS_BRIDGE_CARDBUS = 7
-
-PCI_CLASS_SERIALBUS_CONTROLLER = 12
-PCI_SUBCLASS_SERIALBUS_USB = 3
-
-DB_FORMAT_FOR_VENDOR_ID = {
- 'pci': '0x%04x',
- 'usb_device': '0x%04x',
- 'scsi': '%-8s',
- 'scsi_device': '%-8s',
- }
-
-DB_FORMAT_FOR_PRODUCT_ID = {
- 'pci': '0x%04x',
- 'usb_device': '0x%04x',
- 'scsi': '%-16s',
- 'scsi_device': '%-16s',
- }
-
-UDEV_USB_DEVICE_PROPERTIES = set(('DEVTYPE', 'PRODUCT', 'TYPE'))
-UDEV_USB_PRODUCT_RE = re.compile(
- '^[0-9a-f]{1,4}/[0-9a-f]{1,4}/[0-9a-f]{1,4}$', re.I)
-UDEV_USB_TYPE_RE = re.compile('^[0-9]{1,3}/[0-9]{1,3}/[0-9]{1,3}$')
-SYSFS_SCSI_DEVICE_ATTRIBUTES = set(('vendor', 'model', 'type'))
-
-
-class SubmissionParser(object):
- """A Parser for the submissions to the hardware database."""
-
- def __init__(self, logger=None, record_warnings=True):
- if logger is None:
- logger = getLogger()
- self.logger = logger
- self._logged_warnings = set()
-
- self.validator = {}
- directory = os.path.join(
- config.root, 'lib', 'lp', 'hardwaredb', 'scripts')
- for version, relax_ng_filename in _relax_ng_files.items():
- path = os.path.join(directory, relax_ng_filename)
- self.validator[version] = RelaxNGValidator(path)
- self._setMainSectionParsers()
- self._setHardwareSectionParsers()
- self._setSoftwareSectionParsers()
- self.record_warnings = record_warnings
-
- def _logError(self, message, submission_key, create_oops=True):
- """Log `message` for an error in submission submission_key`."""
- msg = 'Parsing submission %s: %s' % (submission_key, message)
- if not create_oops:
- with disable_oops_handler(self.logger):
- self.logger.error(msg)
- else:
- self.logger.error(msg)
-
- def _logWarning(self, message, warning_id=None):
- """Log `message` for a warning in submission submission_key`."""
- if not self.record_warnings:
- return
- if warning_id is None:
- issue_warning = True
- elif warning_id not in self._logged_warnings:
- issue_warning = True
- self._logged_warnings.add(warning_id)
- else:
- issue_warning = False
- if issue_warning:
- self.logger.warning(
- 'Parsing submission %s: %s' % (self.submission_key, message))
-
- def fixFrequentErrors(self, submission):
- """Fixes for frequent formal errors in the submissions.
- """
- # A considerable number of reports for Lucid has ESC characters
- # in comment nodes. We don't need the comment nodes at all, so
- # we can simply empty them.
- submission = _broken_comment_nodes_re.sub(b'<comment/>', submission)
-
- # Submissions from Natty don't have the nodes <dmi> and <udev>
- # as children of the <hardware> node. Fortunately, they provide
- # this data in
- #
- # <context>
- # <info command="grep -r . /sys/class/dmi/id/ 2>/dev/null">
- # ...
- # </info>
- # <info command="udevadm info --export-db">
- # ...
- # </info>
- # </context>
- #
- # We can try to find the two relevant <info> nodes inside <context>
- # and move their content into the proper subnodes of <hardware>.
- if _udev_node_exists.search(submission) is None:
- mo = _missing_udev_node_data.search(submission)
- if mo is not None:
- missing_data = mo.group(1)
- missing_data = b'<udev>%s</udev>\n</hardware>' % missing_data
- submission = submission.replace(b'</hardware>', missing_data)
- if _dmi_node_exists.search(submission) is None:
- mo = _missing_dmi_node_data.search(submission)
- if mo is not None:
- missing_data = mo.group(1)
- missing_data = b'<dmi>%s</dmi>\n</hardware>' % missing_data
- submission = submission.replace(b'</hardware>', missing_data)
- return submission
-
- def _getValidatedEtree(self, submission, submission_key):
- """Create an etree doc from the XML string submission and validate it.
-
- :return: an `lxml.etree` instance representation of a valid
- submission or None for invalid submissions.
- """
- submission = self.fixFrequentErrors(submission)
- try:
- tree = etree.parse(io.BytesIO(submission), forbid_dtd=True)
- except SyntaxError as error_value:
- self._logError(error_value, submission_key)
- return None
-
- submission_doc = tree.getroot()
- if submission_doc.tag != 'system':
- self._logError("root node is not '<system>'", submission_key)
- return None
- version = submission_doc.attrib.get('version', None)
- if not version in self.validator.keys():
- self._logError(
- 'invalid submission format version: %s' % repr(version),
- submission_key)
- return None
-
- validator = self.validator[version]
- if not validator.validate(submission):
- self._logError(
- 'Relax NG validation failed.\n%s' % validator.error_log,
- submission_key,
- create_oops=False)
- return None
- return submission_doc
-
- def _getValueAttributeAsBoolean(self, node):
- """Return the value of the attribute "value" as a boolean."""
- value = node.attrib['value']
- # Paranoia check: The Relax NG validation already ensures that the
- # attribute value is either 'True' or 'False'.
- assert value in ('True', 'False'), (
- 'Parsing submission %s: Boolean value for attribute "value" '
- 'expected in tag <%s>' % (self.submission_key, node.tag))
- return value == 'True'
-
- def _getValueAttributeAsString(self, node):
- """Return the value of the attribute "value"."""
- # The Relax NG validation ensures that the attribute exists.
- return node.attrib['value']
-
- def _getValueAttributeAsDateTime(self, time_node):
- """Convert a "value" attribute into a datetime object."""
- time_text = time_node.get('value')
-
- # we cannot use time.strptime: this function accepts neither fractions
- # of a second nor a time zone given e.g. as '+02:30'.
- mo = _time_regex.search(time_text)
-
- # The Relax NG schema allows a leading minus sign and year numbers
- # with more than four digits, which are not "covered" by _time_regex.
- if mo is None:
- raise ValueError(
- 'Timestamp with unreasonable value: %s' % time_text)
-
- time_parts = mo.groupdict()
-
- year = int(time_parts['year'])
- month = int(time_parts['month'])
- day = int(time_parts['day'])
- hour = int(time_parts['hour'])
- minute = int(time_parts['minute'])
- second = int(time_parts['second'])
- second_fraction = time_parts['second_fraction']
- if second_fraction is not None:
- milliseconds = second_fraction + '0' * (6 - len(second_fraction))
- milliseconds = int(milliseconds)
- else:
- milliseconds = 0
-
- # The Relax NG validator accepts leap seconds, but the datetime
- # constructor rejects them. The time values submitted by the HWDB
- # client are not necessarily very precise, hence we can round down
- # to 59.999999 seconds without losing any real precision.
- if second > 59:
- second = 59
- milliseconds = 999999
-
- timestamp = datetime(year, month, day, hour, minute, second,
- milliseconds, tzinfo=pytz.timezone('utc'))
-
- tz_sign = time_parts['tz_sign']
- tz_hour = time_parts['tz_hour']
- tz_minute = time_parts['tz_minute']
- if tz_sign in ('-', '+'):
- delta = timedelta(hours=int(tz_hour), minutes=int(tz_minute))
- if tz_sign == '-':
- timestamp = timestamp + delta
- else:
- timestamp = timestamp - delta
- return timestamp
-
- def _getClientData(self, client_node):
- """Parse the <client> node in the <summary> section.
-
- :return: A dictionary with keys 'name', 'version', 'plugins'.
- Name and version describe the client program that
- produced the submission. Pugins is a list with one
- entry per client plugin; each entry is dictionary with
- the keys 'name' and 'version'.
- """
- result = {'name': client_node.get('name'),
- 'version': client_node.get('version')}
- plugins = result['plugins'] = []
- for node in client_node.getchildren():
- # Ensured by the Relax NG validation: The only allowed sub-tag
- # of <client> is <plugin>, which has the attributes 'name' and
- # 'version'.
- plugins.append({'name': node.get('name'),
- 'version': node.get('version')})
- return result
-
- _parse_summary_section = {
- 'live_cd': _getValueAttributeAsBoolean,
- 'system_id': _getValueAttributeAsString,
- 'distribution': _getValueAttributeAsString,
- 'distroseries': _getValueAttributeAsString,
- 'architecture': _getValueAttributeAsString,
- 'private': _getValueAttributeAsBoolean,
- 'contactable': _getValueAttributeAsBoolean,
- 'date_created': _getValueAttributeAsDateTime,
- 'client': _getClientData,
- 'kernel-release': _getValueAttributeAsString,
- }
-
- def _parseSummary(self, summary_node):
- """Parse the <summary> part of a submission.
-
- :return: A dictionary with the keys 'live_cd', 'system_id',
- 'distribution', 'distroseries', 'architecture',
- 'private', 'contactable', 'date_created', 'client'.
- See the sample XML file tests/hardwaretest.xml for
- detailed description of the values.
- """
- summary = {}
- # The Relax NG validation ensures that we have exactly those
- # sub-nodes that are listed in _parse_summary_section.
- for node in summary_node.getchildren():
- parser = self._parse_summary_section[node.tag]
- summary[node.tag] = parser(self, node)
- return summary
-
- def _getValueAndType(self, node):
- """Return (value, type) of a <property> or <value> node."""
- type_ = node.get('type')
- if type_ in ('dbus.Boolean', 'bool'):
- value = node.text.strip()
- # Pure paranoia: The Relax NG validation ensures that <property>
- # and <value> tags have only the allowed values.
- assert value in ('True', 'False'), (
- 'Parsing submission %s: Invalid bool value for <property> or '
- '<value>: %s' % (self.submission_key, repr(value)))
- return (value == 'True', type_)
- elif type_ in ('str', 'dbus.String', 'dbus.UTF8String'):
- return (node.text.strip(), type_)
- elif type_ in ('dbus.Byte', 'dbus.Int16', 'dbus.Int32', 'dbus.Int64',
- 'dbus.UInt16', 'dbus.UInt32', 'dbus.UInt64', 'int',
- 'long'):
- value = node.text.strip()
- return (int(value), type_)
- elif type_ in ('dbus.Double', 'float'):
- value = node.text.strip()
- return (float(value), type_)
- elif type_ in ('dbus.Array', 'list'):
- value = []
- for sub_node in node.getchildren():
- value.append(self._getValueAndType(sub_node))
- return (value, type_)
- elif type_ in ('dbus.Dictionary', 'dict'):
- value = {}
- for sub_node in node.getchildren():
- value[sub_node.get('name')] = self._getValueAndType(sub_node)
- return (value, type_)
- else:
- # This should not happen: The Relax NG validation ensures
- # that we have only those values for type_ that appear in
- # the if/elif expressions above.
- raise AssertionError(
- 'Parsing submission %s: Unexpected <property> or <value> '
- 'type: %s' % (self.submission_key, type_))
-
- def _parseProperty(self, property_node):
- """Parse a <property> node.
-
- :return: (name, (value, type)) of a property.
- """
- return (property_node.get('name'),
- self._getValueAndType(property_node))
-
- def _parseProperties(self, properties_node):
- """Parse <property> sub-nodes of properties_node.
-
- :return: A dictionary, where each key is the name of a property;
- the values are the tuples (value, type) of a property.
- """
- properties = {}
- for property_node in properties_node.getchildren():
- # Paranoia check: The Relax NG schema ensures that a node
- # with <property> sub-nodes has no other sub-nodes
- assert property_node.tag == 'property', (
- 'Parsing submission %s: Found <%s> node, expected <property>'
- % (self.submission_key, property_node.tag))
- property_name, property_value = self._parseProperty(property_node)
- if property_name in properties.keys():
- raise ValueError(
- '<property name="%s"> found more than once in <%s>'
- % (property_name, properties_node.tag))
- properties[property_name] = property_value
- return properties
-
- def _parseDevice(self, device_node):
- """Parse a HAL <device> node.
-
- :return: A dictionary d with the keys 'id', 'udi', 'parent',
- 'properties'. d['id'] is an ID of the device d['udi']
- is the HAL UDI of the device; d['properties'] is a
- dictionary with the properties of the device (see
- _parseProperties for details).
- """
- # The Relax NG validation ensures that the attributes "id" and
- # "udi" exist; it also ensures that "id" contains an integer.
- device_data = {'id': int(device_node.get('id')),
- 'udi': device_node.get('udi')}
- parent = device_node.get('parent', None)
- if parent is not None:
- parent = int(parent.strip())
- device_data['parent'] = parent
- device_data['properties'] = self._parseProperties(device_node)
- return device_data
-
- def _parseHAL(self, hal_node):
- """Parse the <hal> section of a submission.
-
- :return: A list, where each entry is the result of a _parseDevice
- call.
- """
- # The Relax NG validation ensures that <hal> has the attribute
- # "version"
- hal_data = {'version': hal_node.get('version')}
- hal_data['devices'] = devices = []
- for device_node in hal_node.getchildren():
- # Pure paranoia: The Relax NG validation ensures already
- # that we have only <device> tags within <hal>
- assert device_node.tag == 'device', (
- 'Parsing submission %s: Unexpected tag <%s> in <hal>'
- % (self.submission_key, device_node.tag))
- devices.append(self._parseDevice(device_node))
- return hal_data
-
- def _parseProcessors(self, processors_node):
- """Parse the <processors> node.
-
- :return: A list of dictionaries, where each dictionary d contains
- the data of a <processor> node. The dictionary keys are
- 'id', 'name', 'properties'. d['id'] is an ID of a
- <processor> node, d['name'] its name, and d['properties']
- contains the properties of a processor (see
- _parseProperties for details).
- """
- result = []
- for processor_node in processors_node.getchildren():
- # Pure paranoia: The Relax NG valiation ensures already
- # the we have only <processor> as sub-tags of <processors>.
- assert processor_node.tag == 'processor', (
- 'Parsing submission %s: Unexpected tag <%s> in <processors>'
- % (self.submission_key, processors_node.tag))
- processor = {}
- # The RelaxNG validation ensures that the attribute "id" exists
- # and that it contains an integer.
- processor['id'] = int(processor_node.get('id'))
- processor['name'] = processor_node.get('name')
- processor['properties'] = self._parseProperties(processor_node)
- result.append(processor)
- return result
-
- def _parseAliases(self, aliases_node):
- """Parse the <aliases> node.
-
- :return: A list of dictionaries, where each dictionary d has the
- keys 'id', 'vendor', 'model'. d['id'] is the ID of a
- HAL device; d['vendor'] is an alternative vendor name of
- the device; d['model'] is an alternative model name.
-
- See tests/hardwaretest.xml more more details.
- """
- aliases = []
- for alias_node in aliases_node.getchildren():
- # Pure paranoia: The Relax NG valiation ensures already
- # the we have only <alias> tags within <aliases>
- assert alias_node.tag == 'alias', (
- 'Parsing submission %s: Unexpected tag <%s> in <aliases>'
- % (self.submission_key, alias_node.tag))
- # The RelaxNG validation ensures that the attribute "target"
- # exists and that it contains an integer.
- alias = {'target': int(alias_node.get('target'))}
- for sub_node in alias_node.getchildren():
- # The Relax NG svalidation ensures that we have exactly
- # two subnodes: <vendor> and <model>
- alias[sub_node.tag] = sub_node.text.strip()
- aliases.append(alias)
- return aliases
-
- def _parseUdev(self, udev_node):
- """Parse the <udev> node.
-
- :return: A list of dictionaries, where each dictionary
- describes a udev device.
-
- The <udev> node contains the output produced by
- "udevadm info --export-db". Each entry of the dictionaries
- represents the data of the key:value pairs as they appear
- in this data. The value of d['S'] is a list of strings,
- the value s['E'] is a dictionary containing the key=value
- pairs of the "E:" lines.
- """
- # We get the plain text as produced by "udevadm info --export-db"
- # This data looks like:
- #
- # P: /devices/LNXSYSTM:00
- # E: UDEV_LOG=3
- # E: DEVPATH=/devices/LNXSYSTM:00
- # E: MODALIAS=acpi:LNXSYSTM:
- #
- # P: /devices/LNXSYSTM:00/ACPI_CPU:00
- # E: UDEV_LOG=3
- # E: DEVPATH=/devices/LNXSYSTM:00/ACPI_CPU:00
- # E: DRIVER=processor
- # E: MODALIAS=acpi:ACPI_CPU:
- #
- # Data for different devices is separated by empty lines.
- # Each line for a device consists of key:value pairs.
- # The following keys are defined:
- #
- # A: udev_device_get_num_fake_partitions()
- # E: udev_device_get_properties_list_entry()
- # L: the device link priority (udev_device_get_devlink_priority())
- # N: the device node file name (udev_device_get_devnode())
- # P: the device path (udev_device_get_devpath())
- # R: udev_device_get_ignore_remove()
- # S: udev_get_dev_path()
- # W: udev_device_get_watch_handle()
- #
- # The key P is always present; the keys A, L, N, R, W appear at
- # most once per device; the keys E and S may appear more than
- # once.
- # The values of the E records have the format "key=value"
- #
- # See also the libudev reference manual:
- # http://www.kernel.org/pub/linux/utils/kernel/hotplug/libudev/
- # and the udev file udevadm-info.c, function print_record()
-
- udev_data = udev_node.text.split('\n')
- devices = []
- device = None
- line_number = 0
- device_id = 0
-
- for line_number, line in enumerate(udev_data):
- if len(line) == 0:
- device = None
- continue
- record = line.split(':', 1)
- if len(record) != 2:
- self._logError(
- 'Line %i in <udev>: No valid key:value data: %r'
- % (line_number, line),
- self.submission_key)
- return None
-
- key, value = record
- if device is None:
- device_id += 1
- device = {
- 'E': {},
- 'S': [],
- 'id': device_id,
- }
- devices.append(device)
- # Some attribute lines have a space character after the
- # ':', others don't have it (see udevadm-info.c).
- value = value.lstrip()
-
- if key == 'E':
- property_data = value.split('=', 1)
- if len(property_data) != 2:
- self._logError(
- 'Line %i in <udev>: Property without valid key=value '
- 'data: %r' % (line_number, line),
- self.submission_key)
- return None
- property_key, property_value = property_data
- device['E'][property_key] = property_value
- elif key == 'S':
- device['S'].append(value)
- else:
- if key in device:
- self._logWarning(
- 'Line %i in <udev>: Duplicate attribute key: %r'
- % (line_number, line),
- self.submission_key)
- device[key] = value
- return devices
-
- def _parseDmi(self, dmi_node):
- """Parse the <dmi> node.
-
- :return: A dictionary containing the key:value pairs of the DMI data.
- """
- dmi_data = {}
- dmi_text = dmi_node.text.strip().split('\n')
- for line_number, line in enumerate(dmi_text):
- record = line.split(':', 1)
- if len(record) != 2:
- self._logError(
- 'Line %i in <dmi>: No valid key:value data: %r'
- % (line_number, line),
- self.submission_key)
- return None
- dmi_data[record[0]] = record[1]
- return dmi_data
-
- def _parseSysfsAttributes(self, sysfs_node):
- """Parse the <sysfs-attributes> node.
-
- :return: A dictionary {path: attrs, ...} where path is the
- path is the path of a sysfs directory, and where attrs
- is a dictionary containing attribute names and values.
-
- A sample of the input data:
-
- P: /devices/LNXSYSTM:00/LNXPWRBN:00/input/input0
- A: modalias=input:b0019v0000p0001e0000-e0,1,k74,ramlsfw
- A: uniq=
- A: phys=LNXPWRBN/button/input0
- A: name=Power Button
-
- P: /devices/LNXSYSTM:00/device:00/PNP0A08:00/device:03/input/input8
- A: modalias=input:b0019v0000p0006e0000-e0,1,kE0,E1,E3,F0,F1
- A: uniq=
- A: phys=/video/input0
- A: name=Video Bus
-
- Data for different devices is separated by empty lines. The data
- for each device starts with a line 'P: /devices/LNXSYSTM...',
- specifying the sysfs path of a device, followed by zero or more
- lines of the form 'A: key=value'
- """
- sysfs_lines = sysfs_node.text.split('\n')
- sysfs_data = {}
- attributes = None
-
- for line_number, line in enumerate(sysfs_lines):
- if len(line) == 0:
- attributes = None
- continue
- record = line.split(': ', 1)
- if len(record) != 2:
- self._logError(
- 'Line %i in <sysfs-attributes>: No valid key:value data: '
- '%r' % (line_number, line),
- self.submission_key)
- return None
-
- key, value = record
- if key == 'P':
- if attributes is not None:
- self._logError(
- "Line %i in <sysfs-attributes>: duplicate 'P' line "
- "found: %r" % (line_number, line),
- self.submission_key)
- return None
- attributes = {}
- sysfs_data[value] = attributes
- elif key == 'A':
- if attributes is None:
- self._logError(
- "Line %i in <sysfs-attributes>: Block for a device "
- "does not start with 'P:': %r" % (line_number, line),
- self.submission_key)
- return None
- attribute_data = value.split('=', 1)
- if len(attribute_data) != 2:
- self._logError(
- 'Line %i in <sysfs-attributes>: Attribute line does '
- 'not contain key=value data: %r'
- % (line_number, line),
- self.submission_key)
- return None
- attributes[attribute_data[0]] = attribute_data[1]
- else:
- self._logError(
- 'Line %i in <sysfs-attributes>: Unexpected key: %r'
- % (line_number, line),
- self.submission_key)
- return None
- return sysfs_data
-
- def _setHardwareSectionParsers(self):
- self._parse_hardware_section = {
- 'hal': self._parseHAL,
- 'processors': self._parseProcessors,
- 'aliases': self._parseAliases,
- 'udev': self._parseUdev,
- 'dmi': self._parseDmi,
- 'sysfs-attributes': self._parseSysfsAttributes,
- }
-
- def _parseHardware(self, hardware_node):
- """Parse the <hardware> part of a submission.
-
- :return: A dictionary with the keys 'hal', 'processors', 'aliases',
- where the values are the parsing results of _parseHAL,
- _parseProcessors, _parseAliases.
- """
- # Submissions from checkbox for Lucid, Maverick and Natty
- # unfortunately do not contain a <sysfs-attributes> node.
- # A default value here allows us to mark these submissions.
- # See also bug 835103.
- hardware_data = {
- 'sysfs-attributes': None,
- }
- for node in hardware_node.getchildren():
- parser = self._parse_hardware_section[node.tag]
- result = parser(node)
- if result is None:
- return None
- hardware_data[node.tag] = result
- return hardware_data
-
- def _parseLSBRelease(self, lsb_node):
- """Parse the <lsb_release> part of a submission.
-
- :return: A dictionary with the content of the <properta> nodes
- within the <lsb> node. See tests/hardwaretest.xml for
- details.
- """
- return self._parseProperties(lsb_node)
-
- def _parsePackages(self, packages_node):
- """Parse the <packages> part of a submission.
-
- :return: A dictionary with one entry per <package> sub-node.
- The key is the package name, the value a dictionary
- containing the content of the <property> nodes within
- <package>. See tests/hardwaretest.xml for more details.
- """
- packages = {}
- for package_node in packages_node.getchildren():
- # Pure paranoia: The Relax NG validation ensures already
- # that we have only <package> tags within <packages>.
- assert package_node.tag == 'package', (
- 'Parsing submission %s: Unexpected tag <%s> in <packages>'
- % (self.submission_key, package_node.tag))
- package_name = package_node.get('name')
- if package_name in packages.keys():
- raise ValueError(
- '<package name="%s"> appears more than once in <packages>'
- % package_name)
- # The RelaxNG validation ensures that the attribute "id" exists
- # and that it contains an integer.
- package_data = {'id': int(package_node.get('id'))}
- package_data['properties'] = self._parseProperties(package_node)
- packages[package_name] = package_data
- return packages
-
- def _parseXOrg(self, xorg_node):
- """Parse the <xorg> part of a submission.
-
- :return: A dictionary with the keys 'version' and 'drivers'.
- d['version'] is the xorg version; d['drivers'] is
- a dictionary with one entry for each <driver> sub-node,
- where the key is the driver name, the value is a dictionary
- containing the attributes of the <driver> node. See
- tests/hardwaretest.xml for more details.
- """
- xorg_data = {'version': xorg_node.get('version')}
- xorg_data['drivers'] = xorg_drivers = {}
- for driver_node in xorg_node.getchildren():
- # Pure paranoia: The Relax NG validation ensures already
- # that we have only <driver> tags within <xorg>.
- assert driver_node.tag == 'driver', (
- 'Parsing submission %s: Unexpected tag <%s> in <xorg>'
- % (self.submission_key, driver_node.tag))
- driver_info = dict(driver_node.attrib)
- if 'device' in driver_info:
- # The Relax NG validation ensures that driver_info['device']
- # consists of only digits, if present.
- driver_info['device'] = int(driver_info['device'])
- driver_name = driver_info['name']
- if driver_name in xorg_drivers.keys():
- raise ValueError(
- '<driver name="%s"> appears more than once in <xorg>'
- % driver_name)
- xorg_drivers[driver_name] = driver_info
- return xorg_data
-
- _parse_software_section = {
- 'lsbrelease': _parseLSBRelease,
- 'packages': _parsePackages,
- 'xorg': _parseXOrg}
-
- def _setSoftwareSectionParsers(self):
- self._parse_software_section = {
- 'lsbrelease': self._parseLSBRelease,
- 'packages': self._parsePackages,
- 'xorg': self._parseXOrg}
-
- def _parseSoftware(self, software_node):
- """Parse the <software> section of a submission.
-
- :return: A dictionary with the keys 'lsbrelease', 'packages',
- 'xorg', containing the parsing results of the respective
- sub-nodes. The key 'lsbrelease' exists always; 'xorg'
- and 'packages' are optional. See _parseLSBRelease,
- _parsePackages, _parseXOrg for more details.
- """
- software_data = {}
- for node in software_node.getchildren():
- parser = self._parse_software_section[node.tag]
- result = parser(node)
- software_data[node.tag] = result
- # The nodes <packages> and <xorg> are optional. Ensure that
- # we have dummy entries in software_data for these nodes, if
- # the nodes do not appear in a submission in order to avoid
- # KeyErrors elsewhere in this module.
- for node_name in ('packages', 'xorg'):
- if node_name not in software_data:
- software_data[node_name] = {}
- return software_data
-
- def _parseQuestions(self, questions_node):
- """Parse the <questions> part of a submission.
-
- :return: A list, where each entry is a dictionary containing
- the parsing result of the <question> sub-nodes.
-
- Content of a list entry d (see tests/hardwaretest.xml
- for a more detailed description):
- d['name']:
- The name of a question. (Always present)
- d['plugin']:
- The name of the client plugin which is
- "responsible" for the question. (Optional)
- d['targets']:
- A list, where each entry is a dicitionary
- describing a target device for this question.
- This list is always present, but may be empty.
-
- The contents of each list entry t is:
-
- t['id']:
- The ID of a HAL <device> node of a
- target device.
- t['drivers']:
- A list of driver names, possibly empty.
- d['answer']:
- The answer to this question. The value is a
- dictionary a:
- a['value']:
- The value of the answer. (Always present)
-
- For questions of type muliple_choice,
- the value should match one of the
- entries of the answer_choices list,
-
- For questions of type measurement, the
- value is a numerical value.
- a['type']:
- This is either 'multiple_choice' or
- 'measurement'. (Always present)
- a['unit']:
- The unit of a measurement value.
- (Optional)
- d['answer_choices']:
- A list of choices from which the user can select
- an answer. This list is always present, but should
- be empty for questions of type measurement.
- d['command']:
- The command line of a test script which was
- run for this question. (Optional)
- d['comment']:
- A comment the user has typed when running the
- client. (Optional)
-
- A consistency check of the content of d is done in
- method _checkSubmissionConsistency.
- """
- questions = []
- for question_node in questions_node.getchildren():
- # Pure paranoia: The Relax NG validation ensures already
- # that we have only <driver> tags within <xorg>
- assert question_node.tag == 'question', (
- 'Parsing submission %s: Unexpected tag <%s> in <questions>'
- % (self.submission_key, question_node.tag))
- question = {'name': question_node.get('name')}
- plugin = question_node.get('plugin', None)
- if plugin is not None:
- question['plugin'] = plugin
- question['targets'] = targets = []
- answer_choices = []
-
- for sub_node in question_node.getchildren():
- sub_tag = sub_node.tag
- if sub_tag == 'answer':
- question['answer'] = answer = {}
- answer['type'] = sub_node.get('type')
- if answer['type'] == 'multiple_choice':
- question['answer_choices'] = answer_choices
- unit = sub_node.get('unit', None)
- if unit is not None:
- answer['unit'] = unit
- answer['value'] = sub_node.text.strip()
- elif sub_tag == 'answer_choices':
- for value_node in sub_node.getchildren():
- answer_choices.append(
- self._getValueAndType(value_node))
- elif sub_tag == 'target':
- # The Relax NG schema ensures that the attribute
- # id exists and that it is an integer
- target = {'id': int(sub_node.get('id'))}
- target['drivers'] = drivers = []
- for driver_node in sub_node.getchildren():
- drivers.append(driver_node.text.strip())
- targets.append(target)
- elif sub_tag in('comment', 'command'):
- data = sub_node.text
- if data is not None:
- question[sub_tag] = data.strip()
- else:
- # This should not happen: The Relax NG validation
- # ensures that we have only those tags which appear
- # in the if/elif expressions.
- raise AssertionError(
- 'Parsing submission %s: Unexpected node <%s> in '
- '<question>' % (self.submission_key, sub_tag))
- questions.append(question)
- return questions
-
- def _parseContext(self, context_node):
- """Parse the <context> part of a submission.
-
- We don't do anything real right now, but simply log a warning
- that this submission contains a <context> section, so that
- we can parse it again later, once we have the SQL tables needed
- to store the data.
- """
- self._logWarning('Submission contains unprocessed <context> data.')
- return {}
-
- def _setMainSectionParsers(self):
- self._parse_system = {
- 'summary': self._parseSummary,
- 'hardware': self._parseHardware,
- 'software': self._parseSoftware,
- 'questions': self._parseQuestions,
- 'context': self._parseContext,
- }
-
- def parseMainSections(self, submission_doc):
- # The RelaxNG validation ensures that submission_doc has exactly
- # four sub-nodes and that the names of the sub-nodes appear in the
- # keys of self._parse_system.
- submission_data = {}
- try:
- for node in submission_doc.getchildren():
- parser = self._parse_system[node.tag]
- result = parser(node)
- if result is None:
- return None
- submission_data[node.tag] = result
- except ValueError as value:
- self._logError(value, self.submission_key)
- return None
- return submission_data
-
- def parseSubmission(self, submission, submission_key):
- """Parse the data of a HWDB submission.
-
- :return: A dictionary with the keys 'summary', 'hardware',
- 'software', 'questions'. See _parseSummary,
- _parseHardware, _parseSoftware, _parseQuestions for
- the content.
- """
- self.submission_key = submission_key
- submission_doc = self._getValidatedEtree(submission, submission_key)
- if submission_doc is None:
- return None
-
- return self.parseMainSections(submission_doc)
-
- def _findDuplicates(self, all_ids, test_ids):
- """Search for duplicate elements in test_ids.
-
- :return: A set of those elements in the sequence test_ids that
- are elements of the set all_ids or that appear more than once
- in test_ids.
-
- all_ids is updated with test_ids.
- """
- duplicates = set()
- # Note that test_ids itself may contain an ID more than once.
- for test_id in test_ids:
- if test_id in all_ids:
- duplicates.add(test_id)
- else:
- all_ids.add(test_id)
- return duplicates
-
- def findDuplicateIDs(self, parsed_data):
- """Return the set of duplicate IDs.
-
- The IDs of devices, processors and software packages should be
- unique; this method returns a list of duplicate IDs found in a
- submission.
- """
- all_ids = set()
- if 'hal' in parsed_data['hardware']:
- duplicates = self._findDuplicates(
- all_ids,
- [device['id']
- for device in parsed_data['hardware']['hal']['devices']])
- else:
- duplicates = self._findDuplicates(
- all_ids,
- [device['P']
- for device in parsed_data['hardware']['udev']])
- duplicates.update(self._findDuplicates(
- all_ids,
- [processor['id']
- for processor in parsed_data['hardware']['processors']]))
- duplicates.update(self._findDuplicates(
- all_ids,
- [package['id']
- for package in parsed_data['software']['packages'].values()]))
- return duplicates
-
- def _getIDMap(self, parsed_data):
- """Return a dictionary ID -> devices, processors and packages."""
- id_map = {}
- if 'hal' in parsed_data['hardware']:
- hal_devices = parsed_data['hardware']['hal']['devices']
- for device in hal_devices:
- id_map[device['id']] = device
- else:
- udev_devices = parsed_data['hardware']['udev']
- for device in udev_devices:
- id_map[device['P']] = device
-
- for processor in parsed_data['hardware']['processors']:
- id_map[processor['id']] = processor
-
- for package in parsed_data['software']['packages'].values():
- id_map[package['id']] = package
-
- return id_map
-
- def findInvalidIDReferences(self, parsed_data):
- """Return the set of invalid references to IDs.
-
- The sub-tag <target> of <question> references a device, processor
- of package node by its ID; the submission must contain a <device>,
- <processor> or <software> tag with this ID. This method returns a
- set of those IDs mentioned in <target> nodes that have no
- corresponding device or processor node.
- """
- id_device_map = self._getIDMap(parsed_data)
- known_ids = set(id_device_map.keys())
- questions = parsed_data['questions']
- target_lists = [question['targets'] for question in questions]
- all_targets = []
- for target_list in target_lists:
- all_targets.extend(target_list)
- all_target_ids = set(target['id'] for target in all_targets)
- return all_target_ids.difference(known_ids)
-
- def getUDIDeviceMap(self, devices):
- """Return a dictionary which maps UDIs to HAL devices.
-
- Also check, if a UDI is used more than once.
-
- Generally, a duplicate UDI indicates a bad or bogus submission,
- but we have some UDIs where the duplicate UDI is caused by a
- bug in HAL, see
- http://lists.freedesktop.org/archives/hal/2009-April/013250.html
- In these cases, we simply remove the duplicates, otherwise, a
- ValueError is raised.
- """
- udi_device_map = {}
- duplicates = []
- for index in range(len(devices)):
- device = devices[index]
- udi = device['udi']
- if udi in udi_device_map:
- if 'info.parent' in device['properties']:
- parent_udi = device['properties']['info.parent'][0]
- else:
- parent_udi = None
- if (udi in KNOWN_DUPLICATE_UDIS or
- parent_udi in KNOWN_DUPLICATE_UDIS):
- duplicates.append(index)
- continue
- else:
- raise ValueError('Duplicate UDI: %s' % device['udi'])
- else:
- udi_device_map[udi] = device
- duplicates.reverse()
- for index in duplicates:
- devices.pop(index)
- return udi_device_map
-
- def _getIDUDIMaps(self, devices):
- """Return two mappings describing the relation between IDs and UDIs.
-
- :return: two dictionaries id_to_udi and udi_to_id, where
- id_2_udi has IDs as keys and UDI as values, and where
- udi_to_id has UDIs as keys and IDs as values.
- """
- id_to_udi = {}
- udi_to_id = {}
- for device in devices:
- id = device['id']
- udi = device['udi']
- id_to_udi[id] = udi
- udi_to_id[udi] = id
- return id_to_udi, udi_to_id
-
- def getUDIChildren(self, udi_device_map):
- """Build lists of all children of a UDI.
-
- :return: A dictionary that maps UDIs to lists of children.
-
- If any info.parent property points to a non-existing existing
- device, a ValueError is raised.
- """
- # Each HAL device references its parent device (HAL attribute
- # info.parent), except for the "root node", which has no parent.
- children = {}
- known_udis = set(udi_device_map.keys())
- for device in udi_device_map.values():
- parent_property = device['properties'].get('info.parent', None)
- if parent_property is not None:
- parent = parent_property[0]
- if not parent in known_udis:
- raise ValueError(
- 'Unknown parent UDI %s in <device id="%s">'
- % (parent, device['id']))
- if parent in children:
- children[parent].append(device)
- else:
- children[parent] = [device]
- else:
- # A node without a parent is a root node. Only one root node
- # is allowed, which must have the UDI
- # "/org/freedesktop/Hal/devices/computer".
- # Other nodes without a parent UDI indicate an error, as well
- # as a non-existing root node.
- if device['udi'] != ROOT_UDI:
- raise ValueError(
- 'root device node found with unexpected UDI: '
- '<device id="%s" udi="%s">' % (device['id'],
- device['udi']))
-
- if not ROOT_UDI in children:
- raise ValueError('No root device found')
- return children
-
- def _removeChildren(self, udi, udi_test):
- """Remove recursively all children of the device named udi."""
- if udi in udi_test:
- children = udi_test[udi]
- for child in children:
- self._removeChildren(child['udi'], udi_test)
- del udi_test[udi]
-
- def checkHALDevicesParentChildConsistency(self, udi_children):
- """Ensure that HAL devices are represented in exactly one tree.
-
- :return: A list of those UDIs that are not "connected" to the root
- node /org/freedesktop/Hal/devices/computer
-
- HAL devices "know" their parent device; each device has a parent,
- except the root element. This means that it is possible to traverse
- all existing devices, beginning at the root node.
-
- Several inconsistencies are possible:
-
- (a) we may have more than one root device (i.e., one without a
- parent)
- (b) we may have no root element
- (c) circular parent/child references may exist.
-
- (a) and (b) are already checked in _getUDIChildren; this method
- implements (c),
- """
- # If we build a copy of udi_children and if we remove, starting at
- # the root UDI, recursively all children from this copy, we should
- # get a dictionary, where all values are empty lists. Any remaining
- # nodes must have circular parent references.
-
- udi_test = {}
- for udi, children in udi_children.items():
- udi_test[udi] = children[:]
- self._removeChildren(ROOT_UDI, udi_test)
- return udi_test.keys()
-
- def checkUdevDictsHavePathKey(self, udev_nodes):
- """Ensure that each udev dictionary has a 'P' key.
-
- The 'P' (path) key identifies a device.
- """
- for node in udev_nodes:
- if not 'P' in node:
- self._logError('udev node found without a "P" key',
- self.submission_key)
- 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.
-
- :param udev_data: A list of dicitionaries describing udev
- devices, as returned by _parseUdev()
- :return: True if all checks pass, else False.
-
- 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 ':'.
- """
- for device in udev_data:
- properties = device['E']
- property_names = set(properties)
- 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
- # formally valid.
- if self.pci_class_re.search(properties['PCI_CLASS']) is None:
- self._logError(
- 'Invalid udev PCI class: %r %r'
- % (properties['PCI_CLASS'], device['P']),
- self.submission_key)
- return False
- for pci_id in (properties['PCI_ID'],
- properties['PCI_SUBSYS_ID']):
- if self.pci_id_re.search(pci_id) is None:
- self._logError(
- 'Invalid udev PCI device ID: %r %r'
- % (pci_id, device['P']),
- self.submission_key)
- return False
- else:
- if len(existing_pci_properties) > 0:
- self._logError(
- 'Non-PCI udev device with PCI properties: %r %r'
- % (existing_pci_properties, device['P']),
- self.submission_key)
- return False
- return True
-
- def checkUdevUsbProperties(self, udev_data):
- """Validation of udev USB devices.
-
- USB devices must either have the three properties DEVTYPE
- (value 'usb_device' or 'usb_interface'), PRODUCT and TYPE,
- or they must have none of them.
-
- PRODUCT must be a tuple of three integers in hexadecimal
- representation, separates by '/'. TYPE must be a a tuple of
- three integers in decimal representation, separated by '/'.
- usb_interface nodes must additionally have a property
- INTERFACE, containing three integers in the same format as
- TYPE.
- """
- for device in udev_data:
- subsystem = device['E'].get('SUBSYSTEM')
- if subsystem != 'usb':
- continue
- properties = device['E']
- property_names = set(properties)
- existing_usb_properties = property_names.intersection(
- UDEV_USB_DEVICE_PROPERTIES)
-
- if len(existing_usb_properties) == 0:
- continue
-
- if existing_usb_properties != UDEV_USB_DEVICE_PROPERTIES:
- missing_properties = UDEV_USB_DEVICE_PROPERTIES.difference(
- existing_usb_properties)
- self._logError(
- 'USB udev device found without required properties: %r %r'
- % (missing_properties, device['P']),
- self.submission_key)
- return False
- if UDEV_USB_PRODUCT_RE.search(properties['PRODUCT']) is None:
- self._logError(
- 'USB udev device found with invalid product ID: %r %r'
- % (properties['PRODUCT'], device['P']),
- self.submission_key)
- return False
- if UDEV_USB_TYPE_RE.search(properties['TYPE']) is None:
- self._logError(
- 'USB udev device found with invalid type data: %r %r'
- % (properties['TYPE'], device['P']),
- self.submission_key)
- return False
-
- device_type = properties['DEVTYPE']
- if device_type not in ('usb_device', 'usb_interface'):
- self._logError(
- 'USB udev device found with invalid udev type data: %r %r'
- % (device_type, device['P']),
- self.submission_key)
- return False
- if device_type == 'usb_interface':
- interface_type = properties.get('INTERFACE')
- if interface_type is None:
- self._logError(
- 'USB interface udev device found without INTERFACE '
- 'property: %r'
- % device['P'],
- self.submission_key)
- return False
- if UDEV_USB_TYPE_RE.search(interface_type) is None:
- self._logError(
- 'USB Interface udev device found with invalid '
- 'INTERFACE property: %r %r'
- % (interface_type, device['P']),
- self.submission_key)
- return False
- return True
-
- def checkUdevScsiProperties(self, udev_data, sysfs_data):
- """Validation of udev SCSI devices.
-
- Each udev node where SUBSYSTEM is 'scsi' should have the
- property DEVTYPE; nodes where DEVTYPE is 'scsi_device'
- should have a corresponding sysfs node, and this node should
- define the attributes 'vendor', 'model', 'type'.
- """
- # Broken submissions from Lucid, Maverick and Natty. We'll have
- # to deal with incomplete data for SCSI devices in this case if
- # we don't want to drop the entire submission, so just pretend
- # that things are fine.
- # See also bug 835103.
- if sysfs_data is None:
- return True
- for device in udev_data:
- subsystem = device['E'].get('SUBSYSTEM')
- if subsystem != 'scsi':
- continue
- properties = device['E']
- if 'DEVTYPE' not in properties:
- self._logError(
- 'SCSI udev node found without DEVTYPE property: %r'
- % device['P'],
- self.submission_key)
- return False
- if properties['DEVTYPE'] == 'scsi_device':
- device_path = device['P']
- if device_path not in sysfs_data:
- self._logError(
- 'SCSI udev device node found without related '
- 'sysfs record: %r' % device_path,
- self.submission_key)
- return False
- sysfs_attributes = sysfs_data[device_path]
- sysfs_attribute_names = set(sysfs_attributes)
- if SYSFS_SCSI_DEVICE_ATTRIBUTES.intersection(
- sysfs_attribute_names) != SYSFS_SCSI_DEVICE_ATTRIBUTES:
- missing_attributes = (
- SYSFS_SCSI_DEVICE_ATTRIBUTES.difference(
- sysfs_attribute_names))
- self._logError(
- 'SCSI udev device found without required sysfs '
- 'attributes: %r %r'
- % (missing_attributes, device_path),
- self.submission_key)
- return False
- return True
-
- def checkUdevDmiData(self, dmi_data):
- """Consistency check for DMI data.
-
- All keys of the dictionary dmi_data should start with
- '/sys/class/dmi/id/'.
- """
- for dmi_key in dmi_data:
- if not dmi_key.startswith('/sys/class/dmi/id/'):
- self._logError(
- 'Invalid DMI key: %r' % dmi_key, self.submission_key)
- return False
- return True
-
- def checkConsistentUdevDeviceData(self, udev_data, sysfs_data, dmi_data):
- """Consistency checks for udev data."""
- return (
- self.checkUdevDictsHavePathKey(udev_data) and
- self.checkUdevPciProperties(udev_data) and
- self.checkUdevUsbProperties(udev_data) and
- self.checkUdevScsiProperties(udev_data, sysfs_data) and
- self.checkUdevDmiData(dmi_data))
-
- def checkConsistency(self, parsed_data):
- """Run consistency checks on the submitted data.
-
- :return: True, if the data looks consistent, otherwise False.
- :param: parsed_data: parsed submission data, as returned by
- parseSubmission
- """
- if ('udev' in parsed_data['hardware']
- and not self.checkConsistentUdevDeviceData(
- parsed_data['hardware']['udev'],
- parsed_data['hardware']['sysfs-attributes'],
- parsed_data['hardware']['dmi'],)):
- return False
- duplicate_ids = self.findDuplicateIDs(parsed_data)
- if duplicate_ids:
- self._logError('Duplicate IDs found: %s' % duplicate_ids,
- self.submission_key)
- return False
-
- invalid_id_references = self.findInvalidIDReferences(parsed_data)
- if invalid_id_references:
- self._logError(
- 'Invalid ID references found: %s' % invalid_id_references,
- self.submission_key)
- return False
-
- if 'hal' in parsed_data['hardware']:
- try:
- udi_device_map = self.getUDIDeviceMap(
- parsed_data['hardware']['hal']['devices'])
- udi_children = self.getUDIChildren(udi_device_map)
- except ValueError as value:
- self._logError(value, self.submission_key)
- return False
-
- circular = self.checkHALDevicesParentChildConsistency(
- udi_children)
- if circular:
- self._logError('Found HAL devices with circular parent/child '
- 'relationship: %s' % circular,
- self.submission_key)
- return False
-
- return True
-
- def buildDeviceList(self, parsed_data):
- """Create a list of devices from a submission."""
- if 'hal' in parsed_data['hardware']:
- return self.buildHalDeviceList(parsed_data)
- else:
- return self.buildUdevDeviceList(parsed_data)
-
- def buildHalDeviceList(self, parsed_data):
- """Create a list of devices from the HAL data of a submission."""
- self.devices = {}
- for hal_data in parsed_data['hardware']['hal']['devices']:
- udi = hal_data['udi']
- self.devices[udi] = HALDevice(hal_data['id'], udi,
- hal_data['properties'], self)
- for device in self.devices.values():
- parent_udi = device.parent_udi
- if parent_udi is not None:
- self.devices[parent_udi].addChild(device)
- return True
-
- def buildUdevDeviceList(self, parsed_data):
- """Create a list of devices from the udev data of a submission."""
- self.devices = {}
- sysfs_data = parsed_data['hardware']['sysfs-attributes']
- dmi_data = parsed_data['hardware']['dmi']
- for udev_data in parsed_data['hardware']['udev']:
- device_path = udev_data['P']
- if sysfs_data is not None:
- sysfs_data_for_device = sysfs_data.get(device_path)
- else:
- # broken Lucid, Maverick and Natty submissions.
- # See also bug 835103.
- sysfs_data_for_device = None
- if device_path == UDEV_ROOT_PATH:
- device = UdevDevice(
- self, udev_data, sysfs_data=sysfs_data_for_device,
- dmi_data=dmi_data)
- else:
- device = UdevDevice(
- self, udev_data, sysfs_data=sysfs_data_for_device)
- self.devices[device_path] = device
-
- # The parent-child relations are derived from the path names of
- # the devices. If A and B are the path names of two devices,
- # the device with path name A is an ancestor of the device with
- # path name B, iff B.startswith(A). If C is the set of the path
- # names of all ancestors of A, the element with the longest path
- # name belongs to the parent of A.
- #
- # There is one exception to this rule: The root node has the
- # the path name '/devices/LNXSYSTM:00', while the path names
- # of PCI devices start with '/devices/pci'. We'll temporarily
- # change the path name of the root device so that the rule
- # holds for all devices.
- if UDEV_ROOT_PATH not in self.devices:
- self._logError('No udev root device defined', self.submission_key)
- return False
- self.devices['/devices'] = self.devices[UDEV_ROOT_PATH]
- del self.devices[UDEV_ROOT_PATH]
-
- path_names = sorted(self.devices, key=len, reverse=True)
- for path_index, path_name in enumerate(path_names[:-1]):
- # Ensure that the last ancestor of each device is our
- # root node.
- if not path_name.startswith('/devices'):
- self._logError(
- 'Invalid device path name: %r' % path_name,
- self.submission_key)
- return False
- for parent_path in path_names[path_index + 1:]:
- if path_name.startswith(parent_path):
- self.devices[parent_path].addChild(
- self.devices[path_name])
- break
- self.devices[UDEV_ROOT_PATH] = self.devices['/devices']
- del self.devices['/devices']
- return True
-
- @cachedproperty
- def kernel_package_name(self):
- """The kernel package name for the submission."""
- if ROOT_UDI in self.devices:
- root_hal_device = self.devices[ROOT_UDI]
- kernel_version = root_hal_device.getProperty(
- 'system.kernel.version')
- else:
- kernel_version = self.parsed_data['summary'].get('kernel-release')
- if kernel_version is None:
- self._logWarning(
- 'Submission does not provide property system.kernel.version '
- 'for /org/freedesktop/Hal/devices/computer or a summary '
- 'sub-node <kernel-release>.')
- return None
- kernel_package_name = 'linux-image-' + kernel_version
- packages = self.parsed_data['software']['packages']
- # The submission is not required to provide any package data...
- if packages and kernel_package_name not in packages:
- # ...but if we have it, we want it to be consistent with
- # the HAL root node property.
- self._logWarning(
- 'Inconsistent kernel version data: According to HAL the '
- 'kernel is %s, but the submission does not know about a '
- 'kernel package %s'
- % (kernel_version, kernel_package_name))
- return None
- return kernel_package_name
-
- def processSubmission(self, submission):
- """Process a submisson.
-
- :return: True, if the submission could be sucessfully processed,
- otherwise False.
- :param submission: An IHWSubmission instance.
- """
- raw_submission = submission.raw_submission
- # This script runs once per day and can need a few hours to run.
- # Short-lived Librarian server failures or a server restart should
- # not break this script, so let's wait for 10 minutes for a
- # response from the Librarian.
- raw_submission.open(timeout=600)
- submission_data = raw_submission.read(timeout=600)
- raw_submission.close()
-
- # We assume that the data has been sent bzip2-compressed,
- # but this is not checked when the data is submitted.
- expanded_data = None
- try:
- expanded_data = bz2.decompress(submission_data)
- except IOError:
- # An IOError is raised, if the data is not BZip2-compressed.
- # We assume in this case that valid uncompressed data has been
- # submitted. If this assumption is wrong, parseSubmission()
- # or checkConsistency() will complain, hence we don't check
- # anything else here.
- pass
- if expanded_data is not None:
- submission_data = expanded_data
-
- parsed_data = self.parseSubmission(
- submission_data, submission.submission_key)
- if parsed_data is None:
- return False
- self.parsed_data = parsed_data
- if not self.checkConsistency(parsed_data):
- return False
- if not self.buildDeviceList(parsed_data):
- return False
- self.root_device.createDBData(submission, None)
- return True
-
- @property
- def root_device(self):
- """The HALDevice of UdevDevice node of the root device."""
- # checkConsistency ensures that we have either a device with the
- # key ROOT_UDI or a device with the key UDEV_ROOT_PATH.
- if ROOT_UDI in self.devices:
- return self.devices[ROOT_UDI]
- else:
- return self.devices[UDEV_ROOT_PATH]
-
-
-class BaseDevice:
- """A base class to represent device data from HAL and udev."""
-
- def __init__(self, parser):
- self.children = []
- self.parser = parser
- self.parent = None
-
- # Translation of the HAL info.bus/info.subsystem property and the
- # udev property SUBSYSTEM to HWBus enumerated buses.
- subsystem_hwbus = {
- 'pcmcia': HWBus.PCMCIA,
- 'usb_device': HWBus.USB,
- 'ide': HWBus.IDE,
- 'serio': HWBus.SERIAL,
- }
-
- def addChild(self, child):
- """Add a child device and set the child's parent."""
- assert type(child) == type(self)
- self.children.append(child)
- child.parent = self
-
- # Translation of subclasses of the PCI class storage to HWBus
- # enumerated buses. The Linux kernel accesses IDE and SATA disks
- # and CDROM drives via the SCSI system; we want to know the real bus
- # of the drive. See for example the file include/linux/pci_ids.h
- # in the Linux kernel sources for a list of PCI device classes and
- # subclasses. Note that the subclass 4 (RAID) is missing. While it
- # may make sense to declare a RAID storage class for PCI devices,
- # "RAID" does not tell us anything about the bus of the storage
- # devices.
- pci_storage_subclass_hwbus = {
- 0: HWBus.SCSI,
- 1: HWBus.IDE,
- 2: HWBus.FLOPPY,
- 3: HWBus.IPI, # Intelligent Peripheral Interface.
- 5: HWBus.ATA,
- 6: HWBus.SATA,
- 7: HWBus.SAS,
- }
-
- @property
- def device_id(self):
- """A unique ID for this device."""
- raise NotImplementedError
-
- @property
- def pci_class(self):
- """The PCI device class of the device or None for Non-PCI devices."""
- raise NotImplementedError
-
- @property
- def pci_subclass(self):
- """The PCI device sub-class of the device or None for Non-PCI devices.
- """
- raise NotImplementedError
-
- @property
- def usb_vendor_id(self):
- """The USB vendor ID of the device or None for Non-USB devices."""
- raise NotImplementedError
-
- @property
- def usb_product_id(self):
- """The USB product ID of the device or None for Non-USB devices."""
- raise NotImplementedError
-
- @property
- def scsi_vendor(self):
- """The SCSI vendor name of the device or None for Non-SCSI devices."""
- raise NotImplementedError
-
- @property
- def scsi_model(self):
- """The SCSI model name of the device or None for Non-SCSI devices."""
- raise NotImplementedError
-
- @property
- def vendor(self):
- """The vendor of this device."""
- raise NotImplementedError
-
- @property
- def product(self):
- """The vendor of this device."""
- raise NotImplementedError
-
- @property
- def vendor_id(self):
- """The vendor ID of this device."""
- raise NotImplementedError
-
- @property
- def product_id(self):
- """The product ID of this device."""
- raise NotImplementedError
-
- @property
- def vendor_id_for_db(self):
- """The vendor ID in the representation needed for the HWDB tables.
-
- USB and PCI IDs are represented in the database in hexadecimal,
- while the IDs provided by HAL are integers.
-
- The SCSI vendor name is right-padded with spaces to 8 bytes.
- """
- bus = self.raw_bus
- format = DB_FORMAT_FOR_VENDOR_ID.get(bus)
- if format is None:
- return self.vendor_id
- else:
- return format % self.vendor_id
-
- @property
- def product_id_for_db(self):
- """The product ID in the representation needed for the HWDB tables.
-
- USB and PCI IDs are represented in the database in hexadecimal,
- while the IDs provided by HAL are integers.
-
- The SCSI product name is right-padded with spaces to 16 bytes.
- """
- bus = self.raw_bus
- format = DB_FORMAT_FOR_PRODUCT_ID.get(bus)
- if format is None:
- return self.product_id
- else:
- return format % self.product_id
-
- @property
- def driver_name(self):
- """The name of the driver contolling this device. May be None."""
- raise NotImplementedError
-
- @property
- def scsi_controller(self):
- """Return the SCSI host controller for this device."""
- raise NotImplementedError
-
- def translateScsiBus(self):
- """Return the real bus of a device where raw_bus=='scsi'.
-
- The kernel uses the SCSI layer to access storage devices
- connected via the USB, IDE, SATA buses. See `is_real_device`
- for more details. This method determines the real bus
- of a device accessed via the kernel's SCSI subsystem.
- """
- scsi_controller = self.scsi_controller
- if scsi_controller is None:
- return None
-
- scsi_controller_bus = scsi_controller.raw_bus
- if scsi_controller_bus == 'pci':
- if (scsi_controller.pci_class != PCI_CLASS_STORAGE):
- # This is not a storage class PCI device? This
- # indicates a bug somewhere in HAL or in the hwdb
- # client, or a fake submission.
- device_class = scsi_controller.pci_class
- self.parser._logWarning(
- 'A (possibly fake) SCSI device %s is connected to '
- 'PCI device %s that has the PCI device class %s; '
- 'expected class 1 (storage).'
- % (self.device_id, scsi_controller.device_id,
- device_class))
- return None
- pci_subclass = scsi_controller.pci_subclass
- return self.pci_storage_subclass_hwbus.get(pci_subclass)
- 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
- # - HAL node for the USB storage interface. info.bus == 'usb',
- # interface class 8, interface subclass 6
- # (see http://www.usb.org/developers/devclass_docs
- # /usb_msc_overview_1.2.pdf)
- # - HAL node for the (fake) SCSI host. raw_bus is None
- # - HAL node for the (fake) SCSI device. raw_bus == 'scsi'
- # - HAL node for the mass storage device
- #
- # Physically, the storage device can be:
- # (1) a genuine USB device, like a memory stick
- # (2) a IDE/SATA hard disk, connected to a USB -> SATA/IDE
- # bridge
- # (3) a card reader
- # There is no formal way to distinguish cases (1) and (2):
- # The device and interface classes are in both cases
- # identical; the only way to figure out, if we have a USB
- # hard disk enclosure or a USB memory stick would be to
- # look at the vendor or product names, or to look up some
- # external data sources. Of course, we can also ask the
- # submitter in the future.
- #
- # The cases (1) and (2) differ from (3) in the property
- # the property storage.removable. For (1) and (2), this
- # property is False, for (3) it is True. Since we do not
- # store at present any device characteristics in the HWDB,
- # so there is no point to distinguish between (1), (2) on
- # one side and (3) on the other side. Distinguishing
- # between (1) and (2) might be more interesting, because
- # a hard disk is clearly a separate device, but as written,
- # it is hard to distinguish between (1) and (2)
- #
- # To sum up: we cannot get any interesting and reliable
- # information about the details of USB storage device,
- # so we'll treat those devices as "black boxes".
- return None
- else:
- return HWBus.SCSI
-
- def translatePciBus(self):
- # Cardbus (aka PCCard, sometimes also incorrectly called
- # PCMCIA) devices are treated as PCI devices by the kernel.
- # We can detect PCCards by checking that the parent device
- # is a PCI bridge (device class 6) for the Cardbus (device
- # subclass 7).
- # XXX Abel Deuring 2005-05-14 How can we detect ExpressCards?
- # I do not have any such card at present...
- parent_class = self.parent.pci_class
- parent_subclass = self.parent.pci_subclass
- if (parent_class == PCI_CLASS_BRIDGE
- and parent_subclass == PCI_SUBCLASS_BRIDGE_CARDBUS):
- return HWBus.PCCARD
- else:
- 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
-
- @property
- def real_bus(self):
- """Return the bus this device connects to on the host side.
-
- :return: A bus as enumerated in HWBus or None, if the bus
- cannot be determined.
- """
- device_bus = self.raw_bus
- result = self.subsystem_hwbus.get(device_bus)
- if result is not None:
- return result
-
- if device_bus in ('scsi', 'scsi_device'):
- return self.translateScsiBus()
- elif device_bus == 'pci':
- return self.translatePciBus()
- 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
- # UDI.
- return HWBus.SYSTEM
- else:
- self.parser._logWarning(
- 'Unknown bus %r for device %s' % (device_bus, self.device_id))
- return None
-
- @property
- def is_real_device(self):
- """True, if the HAL device correspends to a real device.
-
- In many cases HAL has more than one device entry for the
- same physical device. We are only interested in real, physical,
- devices but not in the fine details, how HAL represents different
- aspects of them.
-
- For example, the HAL device node hiearchy for a SATA disk and
- its host controller looks like this:
-
- HAL device node of the host controller
- udi: .../pci_8086_27c5
- HAL properties:
- info.bus: pci
- pci.device_class: 1 (storage)
- pci.device_subclass: 6 (SATA)
- info.linux.driver: ahci
-
- HAL device node of the "output aspect" of the host controller
- udi: .../pci_8086_27c5_scsi_host
- HAL properties:
- info.bus: n/a
- info.driver: n/a
- info.parent: .../pci_8086_27c5
-
- HAL device node of a hard disk.
- udi: .../pci_8086_27c5_scsi_host_scsi_device_lun0
- HAL properties:
- info.bus: scsi
- info.driver: sd
- info.parent: .../pci_8086_27c5_scsi_host
-
- HAL device node of the "storage aspect" of the hard disk
- udi: .../storage_serial_1ATA_Hitachi_HTS541616J9SA00_SB...
- HAL properties
- info.driver: n/a
- info.parent: .../pci_8086_27c5_scsi_host_scsi_device_lun0
-
- HAL device node of a disk partition:
- udi: .../volume_uuid_0ee803cf_...
- HAL properties
- info.driver: n/a
- info.parent: .../storage_serial_1ATA_Hitachi_HTS541616J...
-
- (optionally more nodes for more partitions)
-
- HAL device node of the "generic SCSI aspect" of the hard disk:
- udi: .../pci_8086_27c5_scsi_host_scsi_device_lun0_scsi_generic
- info.driver: n/a
- info.parent: .../pci_8086_27c5_scsi_host_scsi_device_lun0
-
- This disk is _not_ a SCSI disk, but a SATA disk. In other words,
- the SCSI details are in this case just an artifact of the Linux
- kernel, which uses its SCSI subsystem as a "central hub" to access
- IDE, SATA, USB, IEEE1394 storage devices. The only interesting
- detail for us is that the sd driver is involved in accesses to the
- disk.
-
- Heuristics:
-
- - Most real devices have the property info.bus; we consider only
- those devices to be real which have this property set.
-
- - As written above, the SCSI bus often appears as an artifact;
- for PCI host controllers, their properties pci.device_class
- and pci.device_subclass tell us if we have a real SCSI host
- controller: pci.device_class == 1 means a storage controller,
- pci.device_subclass == 0 means a SCSI controller. This works
- too for PCCard controllers, which use the PCI device class
- numbers too.
-
- - The value "usb_device" of the HAL property info.bus identifies
- USB devices, with one exception: The USB host controller, which
- itself has an info.bus property with the value "pci", has a
- sub-device with info.bus='usb_device' for its "output aspect".
- These sub-devices can be identified by the device class their
- parent and by their USB vendor/product IDs, which are 0:0.
-
- Several info.bus/info.subsystem values always relate to HAL nodes
- which describe only "aspects" of physical devcies which are
- represented by other HAL nodes:
-
- - bus is None for a number of "virtual components", like
- /org/freedesktop/Hal/devices/computer_alsa_timer or
- /org/freedesktop/Hal/devices/computer_oss_sequencer, so
- we ignore them. (The real sound devices appear with
- other UDIs in HAL.)
-
- XXX Abel Deuring 20080425: This ignores a few components
- like laptop batteries or the CPU, where info.bus is None.
- Since these components are not the most important ones
- for the HWDB, we'll ignore them for now. Bug 237038.
-
- - 'disk' is used udev submissions for a node related to the
- sd or sr driver of (real or fake) SCSI block devices.
-
- - info.bus == 'drm' is used by the HAL for the direct
- rendering interface of a graphics card.
-
- - info.bus == 'dvb' is used by HAL for the "input aspect"
- of DVB receivers
-
- - info.bus == 'memstick_host' is used by HAL for the "output aspect"
- of memory sticks.
-
- - info.bus == 'net' is used by the HAL version in
- Intrepid for the "output aspects" of network devices.
-
- - 'partition' is used in udev submissions for a node
- related to disk partition
-
- - 'scsi_disk' is used in udev submissions for a sub-node of
- the real device node.
-
- info.bus == 'scsi_generic' is used by the HAL version in
- Intrepid for a HAL node representing the generic
- interface of a SCSI device.
-
- info.bus == 'scsi_host' is used by the HAL version in
- Intrepid for real and "fake" SCSI host controllers.
- (On Hardy, these nodes have no info.bus property.)
- HAL nodes with this bus value are sub-nodes for the
- "SCSI aspect" of another HAL node which represents the
- real device.
-
- 'scsi_target' is used in udev data for SCSI target nodes,
- the parent of a SCSI device (or LUN) node.
-
- 'spi_transport' (SCSI Parallel Transport) is used in
- udev data for a sub-node of real SCSI devices.
-
- info.bus == 'sound' is used by the HAL version in
- Intrepid for "aspects" of sound devices.
-
- info.bus == 'ssb' is used for "aspects" of Broadcom
- Ethernet and WLAN devices, but like 'usb', they do not
- represent separate devices.
-
- info.bus == 'tty' is used for the "output aspect"
- of serial output devices (RS232, modems etc). It appears
- for USB and PCI devices as well as for legacy devices
- like the 8250/16450/16550 controllers.
-
- info.bus == 'usb' is used for end points of USB devices;
- the root node of a USB device has info.bus == 'usb_device'.
-
- 'usb_interface' is used in udv submissions for interface
- nodes of USB devices.
-
- info.bus == 'video4linux' is used for the "input aspect"
- of video devices.
-
- 'ac97' is used in submissions with udev data for a sub-node
- of sound devices.
-
- 'hid' is used in submissions with udev data for a sub-node
- of USB input devices.
-
- 'drm_minor', 'pci_express', 'tifm_adapter', 'gameport',
- 'spi_host', 'tifm', 'wlan' are used in submissions with
- udev data for sub-nodes of PCI devices.
-
- 'pcmcia_socket' is used in submissions with udev data for
- a sub-node of PC Card and PCMCIA bridges.
-
- 'ieee80211' is used in submissions with udev data for
- sub-nodes IEEE 802.11 WLAN devices.
-
- 'host', 'link' are used in submissions with udev data for
- sub.nodes of bluetooth devices.
-
- 'usb_host' and 'usbmon' are used in submissions with udev
- data for sub-nodes of USB controllers.
-
- 'usb_endpoint', 'usb-serial', 'lirc' are used in
- submissions with udev data for sub-nodes of USB devices.
-
- 'enclosure' is used in submissions with udev data for a
- sub.node of SCSI devices.
-
- 'graphics' is used in submissions with udev data for a
- sub-node of graphics cards.
-
- 'hwmon' is is used in submissions with udev data in
- many sub-nodes.
-
- 'sas_phy', 'sas_device', 'sas_end_device', 'sas_port',
- 'sas_host' is used in submissions with udev data for
- details of SAS controllers.
-
- 'mISDN' is used in submissions with udev data for the
- I/O aspects of ISDN adapters.
-
- 'pvrusb2' is used in submissions with udev data for the
- input aspect of some DVB adapters.
-
- 'memstick' is used in submissions with udev data for the
- I/O aspect of memory stick controllers.
-
- 'bttv-sub' is used in submissions with udev data for the
- I/O aspects of some TV receivers.
-
- 'scsi_tape' is used in submissions with udev data for
- details of SCSI tape drives.
- """
- # The root node is always a real device, but its raw_bus
- # property can have different values: None or 'Unknown' in
- # submissions with HAL data, 'acpi' for submissions with udev
- # data.
- if self.is_root_device:
- return True
-
- bus = self.raw_bus
- # This set of buses is only used once; it's easier to have it
- # here than to put it elsewhere and have to document its
- # location and purpose.
- if bus in (None, 'ac97', 'bttv-sub', 'disk', 'drm', 'drm_minor',
- 'dvb', 'enclosure', 'gameport', 'graphics', 'hid', 'host',
- 'hwmon', 'ieee80211', 'link', 'lirc', 'mISDN', 'memstick',
- 'memstick_host', 'net', 'partition', 'pci_express',
- 'pcmcia_socket', 'pvrusb2', 'sas_device', 'sas_end_device',
- 'sas_host', 'sas_phy', 'sas_port', 'scsi_disk',
- 'scsi_generic', 'scsi_host', 'scsi_tape', 'scsi_target',
- 'sound', 'spi_host', 'spi_transport', 'ssb', 'tifm',
- 'tifm_adapter', 'tty', 'usb', 'usb-serial', 'usb_endpoint',
- 'usb_host', 'usb_interface', 'usbmon', 'video4linux',
- 'wlan'):
- return False
- elif bus == 'usb_device':
- vendor_id = self.usb_vendor_id
- product_id = self.usb_product_id
- if vendor_id == 0 and product_id == 0:
- # double-check: The parent device should be a PCI host
- # controller, identifiable by its device class and subclass.
- # XXX Abel Deuring 2008-04-28 Bug=237039: This ignores other
- # possible bridges, like ISA->USB..
- parent = self.parent
- parent_bus = parent.raw_bus
- parent_class = parent.pci_class
- parent_subclass = parent.pci_subclass
- if (parent_bus == 'pci'
- and parent_class == PCI_CLASS_SERIALBUS_CONTROLLER
- and parent_subclass == PCI_SUBCLASS_SERIALBUS_USB):
- return False
- else:
- self.parser._logWarning(
- 'USB device found with vendor ID==0, product ID==0, '
- 'where the parent device does not look like a USB '
- 'host controller: %s' % self.device_id)
- return False
- return True
- elif bus in ('scsi', 'scsi_device'):
- # Ensure consistency with HALDevice.real_bus
- return self.real_bus is not None
- else:
- return True
-
- def getRealChildren(self):
- """Return the list of real child devices of this devices.
-
- The list of real child devices consists of the direct child
- devices of this device where child.is_real_device == True, and
- of the (recursively collected) list of real sub-devices of
- those child devices where child.is_real_device == False.
- """
- result = []
- for sub_device in self.children:
- if sub_device.is_real_device:
- # XXX Abel Deuring 2008-05-06: IEEE1394 devices are a bit
- # nasty: The standard does not define any specification
- # for product IDs or product names, hence HAL often
- # uses the value 0 for the property ieee1394.product_id
- # and a value like "Unknown (0x00d04b)" for
- # ieee.product, where 0x00d04b is the vendor ID. I have
- # currently no idea how to find or generate something
- # that could be used as the product ID, so IEEE1394
- # devices are at present simply dropped from the list of
- # devices. Otherwise, we'd pollute the HWDB with
- # unreliable data. Bug 237044.
- if sub_device.raw_bus != 'ieee1394':
- result.append(sub_device)
- else:
- result.extend(sub_device.getRealChildren())
- return result
-
- @property
- def has_reliable_data(self):
- """Can this device be stored in the HWDB?
-
- Devices are identifed by (bus, vendor_id, product_id).
- At present we cannot generate reliable vendor and/or product
- IDs for devices with the following values of the HAL
- property info.bus resp. info.subsystem.
-
- info.bus == 'backlight' is used by the HAL version in
- Intrepid for the LC display. Useful vendor and product names
- are not available.
-
- info.bus == 'bluetooth': HAL does not provide any vendor/product
- ID data, so we can't store these devices in HWDevice.
-
- info.bus == 'input' is used by the HAL version in
- Intrepid for quite different devices like keyboards, mice,
- special laptop switches and buttons, sometimes with odd
- product names like "Video Bus".
-
- info.bus == 'misc' and info.bus == 'unknown' are obviously
- not very useful, except for the computer itself, which has
- the bus 'unknown'.
-
- info.bus in ('mmc', 'mmc_host') is used for SD/MMC cards resp.
- the "output aspect" of card readers. We do not not have at
- present enough background information to properly extract a
- vendor and product ID from these cards.
-
- info.bus == 'platform' is used for devices like the i8042
- which controls keyboard and mouse; HAL has no vendor
- information for these devices, so there is no point to
- treat them as real devices.
-
- info.bus == 'pnp' is used for components like the ancient
- AT DMA controller or the keyboard. Like for the bus
- 'platform', HAL does not provide any vendor data.
-
- info.bus == 'power_supply' is used by the HAL version in
- Intrepid for AC adapters an laptop batteries. We don't have
- at present enough information about possible problems with
- missing vendor/product information in order to store the
- data reliably in the HWDB.
-
- raw_bus == 'acpi' is used in udev data for the main system,
- for CPUs, power supply etc. Except for the main sytsem, none
- of them provides a vendor or product id, so we ignore them.
-
- raw_bus == 'video_output', 'thermal', 'vtconsole', 'bdi',
- 'mem', 'ppp', 'vc', 'dmi', 'hidraw', 'hwmon', 'heci', 'rfkill',
- 'i2c-adapter', 'ttm', 'ppdev', 'printer', 'cardman_4040', 'msr',
- 'ieee1394_protocol', 'dahdi', 'atm', 'asus_oled', 'pktcdvd' is
- used in submissions with udev data for virtual devices.
-
- 'pci_bus' is used in submissions with udev data for a node
- describing a PCI bus.
-
- 'leds' is used in submissions with udev data to describe LEDs.
-
- XXX Abel Deuring 2008-05-06: IEEE1394 devices are a bit
- nasty: The standard does not define any specification
- for product IDs or product names, hence HAL often uses
- the value 0 for the property ieee1394.product_id and a
- value like "Unknown (0x00d04b)" for ieee.product, where
- 0x00d04b is the vendor ID. I have currently no idea how
- to find or generate something that could be used as the
- product ID, so IEEE1394 devices are at present simply
- not stored in the HWDB. Otherwise, we'd pollute the HWDB
- with unreliable data. Bug #237044.
-
- While PCMCIA devices have a manufacturer ID, at least its
- value as provided by HAL in pcmcia.manf_id it is not very
- reliable. The HAL property pcmcia.prod_id1 is too not
- reliable. Sometimes it contains a useful vendor name like
- "O2Micro" or "ATMEL", but sometimes useless values like
- "IEEE 802.11b". See for example
- drivers/net/wireless/atmel_cs.c in the Linux kernel sources.
-
- Provided that a device is not excluded by the above criteria,
- ensure that we have vendor ID, product ID and product name.
- """
- bus = self.raw_bus
- if bus in ('unknown', 'acpi') and not self.is_root_device:
- # The root node is course a real device; storing data
- # about other devices with the bus "unkown" is pointless.
- return False
- if bus in ('asus_oled', 'atm', 'backlight', 'bdi', 'bluetooth',
- 'cardman_4040', 'dahdi', 'dmi', 'heci', 'hidraw', 'hwmon',
- 'i2c-adapter', 'ieee1394', 'ieee1394_protocol', 'input',
- 'leds', 'mem', 'misc', 'mmc', 'mmc_host', 'msr', 'pci_bus',
- 'pcmcia', 'pktcdvd', 'platform', 'pnp', 'power_supply',
- 'ppdev', 'ppp', 'printer', 'rfkill', 'thermal', 'ttm',
- 'vc', 'video_output', 'vtconsole'):
- return False
-
- # We identify devices by bus, vendor ID and product ID;
- # additionally, we need a product name. If any of these
- # are not available, we can't store information for this
- # device.
- if (self.real_bus is None or self.vendor_id is None
- or self.product_id is None or self.product is None):
- # Many IDE devices don't provide useful vendor and product
- # data. We don't want to clutter the log with warnings
- # about this problem -- there is nothing we can do to fix
- # it.
- if self.real_bus != HWBus.IDE:
- self.parser._logWarning(
- 'A %s that is supposed to be a real device does '
- 'not provide bus, vendor ID, product ID or product name: '
- '%r %r %r %r %s'
- % (self.__class__.__name__, self.real_bus, self.vendor_id,
- self.product_id, self.product, self.device_id),
- self.parser.submission_key)
- return False
- return True
-
- def getScsiVendorAndModelName(self):
- """Separate vendor and model name of SCSI decvices.
-
- SCSI devcies are identified by an 8 charcter vendor name
- and an 16 character model name. The Linux kernel use the
- the SCSI command set to access block devices connected
- via USB, IEEE1394 and ATA buses too.
-
- For ATA disks, the Linux kernel sets the vendor name to "ATA"
- and prepends the model name with the real vendor name, but only
- if the combined length if not larger than 16. Otherwise the
- real vendor name is omitted.
-
- This method provides a safe way to retrieve the the SCSI vendor
- and model name.
-
- If the vendor name is 'ATA', and if the model name contains
- at least one ' ' character, the string before the first ' ' is
- returned as the vendor name, and the string after the first
- ' ' is returned as the model name.
-
- In all other cases, vendor and model name are returned unmodified.
- """
- vendor = self.scsi_vendor
- if vendor == 'ATA':
- # The assumption below that the vendor name does not
- # contain any spaces is not necessarily correct, but
- # it is hard to find a better heuristic to separate
- # the vendor name from the product name.
- splitted_name = self.scsi_model.split(' ', 1)
- if len(splitted_name) == 2:
- return {
- 'vendor': splitted_name[0],
- 'product': splitted_name[1],
- }
- return {
- 'vendor': vendor,
- 'product': self.scsi_model,
- }
-
- def getDriver(self):
- """Return the HWDriver instance associated with this device.
-
- Create a HWDriver record, if it does not already exist.
- """
- # HAL and the HWDB client know at present only about kernel
- # drivers, so there is currently no need to search for
- # for user space printer drivers, for example.
- if self.driver_name is not None:
- db_driver_set = getUtility(IHWDriverSet)
- return db_driver_set.getOrCreate(
- self.parser.kernel_package_name, self.driver_name)
- else:
- return None
-
- def ensureVendorIDVendorNameExists(self):
- """Ensure that a useful HWVendorID record for self.vendor_id exists.
-
- A vendor ID is associated with a vendor name. For many devices
- we rely on the information from the submission to create this
- association in the HWVendorID table.
-
- We do _not_ use the submitted vendor name for USB, PCI and
- PCCard devices, because we can get them from independent
- sources. See l/c/l/doc/hwdb-device-tables.txt.
- """
- bus = self.real_bus
- if (self.vendor is not None and
- bus not in (HWBus.PCI, HWBus.PCCARD, HWBus.USB)):
- hw_vendor_id_set = getUtility(IHWVendorIDSet)
- hw_vendor_id = hw_vendor_id_set.getByBusAndVendorID(
- bus, self.vendor_id_for_db)
- if hw_vendor_id is None:
- hw_vendor_name_set = getUtility(IHWVendorNameSet)
- hw_vendor_name = hw_vendor_name_set.getByName(self.vendor)
- if hw_vendor_name is None:
- hw_vendor_name = hw_vendor_name_set.create(self.vendor)
- hw_vendor_id_set.create(
- self.real_bus, self.vendor_id_for_db, hw_vendor_name)
-
- def createDBData(self, submission, parent_submission_device):
- """Create HWDB records for this HAL device and its children.
-
- A HWDevice record for (bus, vendor ID, product ID) of this
- device and a HWDeviceDriverLink record (device, None) are
- created, if they do not already exist.
-
- A HWSubmissionDevice record is created for (HWDeviceDriverLink,
- submission).
-
- HWSubmissionDevice records and missing HWDeviceDriverLink
- records for known drivers of this device are created.
-
- createDBData is called recursively for all real child devices.
-
- This method may only be called, if self.real_device == True.
- """
- assert self.is_real_device, ('HALDevice.createDBData must be called '
- 'for real devices only.')
- if not self.has_reliable_data:
- return
- bus = self.real_bus
- vendor_id = self.vendor_id_for_db
- product_id = self.product_id_for_db
- product_name = self.product
-
- self.ensureVendorIDVendorNameExists()
-
- db_device = getUtility(IHWDeviceSet).getOrCreate(
- bus, vendor_id, product_id, product_name)
- # Create a HWDeviceDriverLink record without an associated driver
- # for each real device. This will allow us to relate tests and
- # bugs to a device in general as well as to a specific
- # combination of a device and a driver.
- device_driver_link = getUtility(IHWDeviceDriverLinkSet).getOrCreate(
- db_device, None)
- submission_device = getUtility(IHWSubmissionDeviceSet).create(
- device_driver_link, submission, parent_submission_device,
- self.id)
- self.createDBDriverData(submission, db_device, submission_device)
-
- def createDBDriverData(self, submission, db_device, submission_device):
- """Create HWDB records for drivers of this device and its children.
-
- This method creates HWDeviceDriverLink and HWSubmissionDevice
- records for this device and its children.
- """
- driver = self.getDriver()
- if driver is not None:
- device_driver_link_set = getUtility(IHWDeviceDriverLinkSet)
- device_driver_link = device_driver_link_set.getOrCreate(
- db_device, driver)
- submission_device = getUtility(IHWSubmissionDeviceSet).create(
- device_driver_link, submission, submission_device, self.id)
- for sub_device in self.children:
- if sub_device.is_real_device:
- sub_device.createDBData(submission, submission_device)
- else:
- sub_device.createDBDriverData(submission, db_device,
- submission_device)
-
-
-class HALDevice(BaseDevice):
- """The representation of a HAL device node."""
-
- def __init__(self, id, udi, properties, parser):
- """HALDevice constructor.
-
- :param id: The ID of the HAL device in the submission data as
- specified in <device id=...>.
- :type id: int
- :param udi: The UDI of the HAL device.
- :type udi: string
- :param properties: The HAL properties of the device.
- :type properties: dict
- :param parser: The parser processing a submission.
- :type parser: SubmissionParser
- """
- super(HALDevice, self).__init__(parser)
- self.id = id
- self.udi = udi
- self.properties = properties
-
- def getProperty(self, property_name):
- """Return the HAL property property_name.
-
- Note that there is no check of the property type.
- """
- if property_name not in self.properties:
- return None
- name, type_ = self.properties[property_name]
- return name
-
- @property
- def parent_udi(self):
- """The UDI of the parent device."""
- return self.getProperty('info.parent')
-
- @property
- def device_id(self):
- """See `BaseDevice`."""
- return self.udi
-
- @property
- def pci_class(self):
- """See `BaseDevice`."""
- return self.getProperty('pci.device_class')
-
- @property
- def pci_subclass(self):
- """The PCI device sub-class of the device or None for Non-PCI devices.
- """
- return self.getProperty('pci.device_subclass')
-
- @property
- def usb_vendor_id(self):
- """See `BaseDevice`."""
- return self.getProperty('usb_device.vendor_id')
-
- @property
- def usb_product_id(self):
- """See `BaseDevice`."""
- return self.getProperty('usb_device.product_id')
-
- @property
- def scsi_vendor(self):
- """See `BaseDevice`."""
- return self.getProperty('scsi.vendor')
-
- @property
- def scsi_model(self):
- """See `BaseDevice`."""
- return self.getProperty('scsi.model')
-
- @property
- def driver_name(self):
- """See `BaseDevice`."""
- return self.getProperty('info.linux.driver')
-
- @property
- def raw_bus(self):
- """See `BaseDevice`."""
- # Older versions of HAL stored this value in the property
- # info.bus; newer versions store it in info.subsystem.
- #
- # Note that info.bus is gone for all devices except the
- # USB bus. For USB devices, the property info.bus returns more
- # detailed data: info.subsystem has the value 'usb' for all
- # HAL nodes belonging to USB devices, while info.bus has the
- # value 'usb_device' for the root node of a USB device, and the
- # value 'usb' for sub-nodes of a USB device. We use these
- # different value to to find the root USB device node, hence
- # try to read info.bus first.
- result = self.getProperty('info.bus')
- if result is not None:
- 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.
-
- :return: The vendor or product data for this device.
- :param type_: 'vendor' or 'product'
- """
- # HAL does not store vendor data very consistently. Try to find
- # the data in several places.
- assert type_ in ('vendor', 'product'), (
- 'Unexpected value of type_: %r' % type_)
-
- bus = self.raw_bus
- if self.udi == ROOT_UDI:
- # HAL sets info.product to "Computer", provides no property
- # info.vendor and raw_bus is "unknown", hence the logic
- # below does not work properly.
- return self.getProperty('system.hardware.' + type_)
- elif bus == 'scsi':
- return self.getScsiVendorAndModelName()[type_]
- else:
- result = self.getProperty('info.' + type_)
- if result is None:
- if bus is None:
- return None
- else:
- return self.getProperty('%s.%s' % (bus, type_))
- else:
- return result
-
- @property
- def vendor(self):
- """See `BaseDevice`."""
- return self.getVendorOrProduct('vendor')
-
- @property
- def product(self):
- """See `BaseDevice`."""
- return self.getVendorOrProduct('product')
-
- def getVendorOrProductID(self, type_):
- """Return the vendor or product ID for this device.
-
- :return: The vendor or product ID for this device.
- :param type_: 'vendor' or 'product'
- """
- assert type_ in ('vendor', 'product'), (
- 'Unexpected value of type_: %r' % type_)
- bus = self.raw_bus
- if self.udi == ROOT_UDI:
- # HAL does not provide IDs for a system itself, we use the
- # vendor resp. product name instead.
- return self.getVendorOrProduct(type_)
- elif bus is None:
- return None
- elif bus == 'scsi' or self.udi == ROOT_UDI:
- # The SCSI specification does not distinguish between a
- # vendor/model ID and vendor/model name: the SCSI INQUIRY
- # command returns an 8 byte string as the vendor name and
- # a 16 byte string as the model name. We use these strings
- # as the vendor/product name as well as the vendor/product
- # ID.
- #
- # Similary, HAL does not provide a vendor or product ID
- # for the host system itself, so we use the vendor resp.
- # product name as the vendor/product ID for systems too.
- return self.getVendorOrProduct(type_)
- else:
- return self.getProperty('%s.%s_id' % (bus, type_))
-
- @property
- def vendor_id(self):
- """See `BaseDevice`."""
- return self.getVendorOrProductID('vendor')
-
- @property
- def product_id(self):
- """See `BaseDevice`."""
- return self.getVendorOrProductID('product')
-
- @property
- def scsi_controller(self):
- """See `BaseDevice`."""
- # While SCSI devices from valid submissions should have a
- # parent and a grandparent, we can't be sure for bogus or
- # broken submissions.
- if self.raw_bus != 'scsi':
- return None
- parent = self.parent
- if parent is None:
- self.parser._logWarning(
- 'Found SCSI device without a parent: %s.' % self.device_id)
- return None
- grandparent = parent.parent
- if grandparent is None:
- self.parser._logWarning(
- 'Found SCSI device without a grandparent: %s.'
- % self.device_id)
- return None
- return grandparent
-
-
-class UdevDevice(BaseDevice):
- """The representation of a udev device node."""
-
- def __init__(self, parser, udev_data, sysfs_data=None, dmi_data=None):
- """HALDevice constructor.
-
- :param udevdata: The udev data for this device
- :param sysfs_data: sysfs data for this device.
- :param parser: The parser processing a submission.
- :type parser: SubmissionParser
- """
- super(UdevDevice, self).__init__(parser)
- self.udev = udev_data
- self.sysfs = sysfs_data
- self.dmi = dmi_data
-
- @property
- def device_id(self):
- """See `BaseDevice`."""
- return self.udev['P']
-
- @property
- def root_device_ids(self):
- """The vendor and product IDs of the root device."""
- return {
- 'vendor': self.dmi.get('/sys/class/dmi/id/sys_vendor'),
- 'product': self.dmi.get('/sys/class/dmi/id/product_name')
- }
-
- @property
- def is_pci(self):
- """True, if this is a PCI device, else False."""
- return self.udev['E'].get('SUBSYSTEM') == 'pci'
-
- @property
- def pci_class_info(self):
- """Parse the udev property PCI_SUBSYS_ID.
-
- :return: (PCI class, PCI sub-class, version) for a PCI device
- or (None, None, None) for other devices.
- """
- if self.is_pci:
- # SubmissionParser.checkConsistentUdevDeviceData() ensures
- # that PCI_CLASS is a 24 bit integer in hexadecimal
- # representation.
- # Bits 16..23 of the number are the man PCI class,
- # bits 8..15 are the sub-class, bits 0..7 are the version.
- class_info = int(self.udev['E']['PCI_CLASS'], 16)
- return (class_info >> 16, (class_info >> 8) & 0xFF,
- class_info & 0xFF)
- else:
- return (None, None, None)
-
- @property
- def pci_class(self):
- """See `BaseDevice`."""
- return self.pci_class_info[0]
-
- @property
- def pci_subclass(self):
- """See `BaseDevice`."""
- return self.pci_class_info[1]
-
- @property
- def pci_ids(self):
- """The PCI vendor and product IDs.
-
- :return: A dictionary containing the vendor and product IDs.
- The IDs are set to None for Non-PCI devices.
- """
- if self.is_pci:
- # SubmissionParser.checkUdevPciProperties() ensures that
- # each PCI device has the property PCI_ID and that is
- # consists of two 4-digit hexadecimal numbers, separated
- # by a ':'.
- id_string = self.udev['E']['PCI_ID']
- ids = id_string.split(':')
- return {
- 'vendor': int(ids[0], 16),
- 'product': int(ids[1], 16),
- }
- else:
- return {
- 'vendor': None,
- 'product': None,
- }
-
- @property
- def is_usb(self):
- """True, if this is a USB device, else False."""
- return self.udev['E'].get('SUBSYSTEM') == 'usb'
-
- @property
- def usb_ids(self):
- """The vendor ID, product ID, product version for USB devices.
-
- :return: A dictionary containing the vendor and product IDs and
- the product version for USB devices.
- The IDs are set to None for Non-USB devices.
- """
- if self.is_usb:
- # udev represents USB device IDs as strings
- # vendor_id/product_id/version, where each part is
- # a hexadecimal number.
- # SubmissionParser.checkUdevUsbProperties() ensures that
- # the string PRODUCT is in the format required below.
- product_info = self.udev['E']['PRODUCT'].split('/')
- return {
- 'vendor': int(product_info[0], 16),
- 'product': int(product_info[1], 16),
- 'version': int(product_info[2], 16),
- }
- else:
- return {
- 'vendor': None,
- 'product': None,
- 'version': None,
- }
-
- @property
- def usb_vendor_id(self):
- """See `BaseDevice`."""
- return self.usb_ids['vendor']
-
- @property
- def usb_product_id(self):
- """See `BaseDevice`."""
- return self.usb_ids['product']
-
- @property
- def is_scsi_device(self):
- """True, if this is a SCSI device, else False."""
- # udev sets the property SUBSYSTEM to "scsi" for a number of
- # different nodes: SCSI hosts, SCSI targets and SCSI devices.
- # They are distiguished by the property DEVTYPE.
-
- # Hack for broken submissions from Lucid, Maverick and Natty:
- # If we don't have sysfs information, pretend that no SCSI
- # related node corresponds to a real device.
- # See also bug 835103.
- if self.sysfs is None:
- return False
- properties = self.udev['E']
- return (properties.get('SUBSYSTEM') == 'scsi' and
- properties.get('DEVTYPE') == 'scsi_device')
-
- @property
- def scsi_vendor(self):
- """The SCSI vendor name of the device or None for Non-SCSI devices."""
- if self.is_scsi_device:
- # SubmissionParser.checkUdevScsiProperties() ensures that
- # each SCSI device has a record in self.sysfs and that
- # the attribute 'vendor' exists.
- return self.sysfs['vendor']
- else:
- return None
-
- @property
- def scsi_model(self):
- """The SCSI model name of the device or None for Non-SCSI devices."""
- if self.is_scsi_device:
- # SubmissionParser.checkUdevScsiProperties() ensures that
- # each SCSI device has a record in self.sysfs and that
- # the attribute 'model' exists.
- return self.sysfs['model']
- else:
- return None
-
- @property
- def raw_bus(self):
- """See `BaseDevice`."""
- # udev specifies the property SUBSYSTEM for most devices;
- # some devices have additionally the more specific property
- # DEVTYPE. DEVTYPE is preferable.
- # The root device has the subsystem/bus value "acpi", which
- # is a bit nonsensical.
- if self.is_root_device:
- return None
- properties = self.udev['E']
- devtype = properties.get('DEVTYPE')
- if devtype is not None:
- return devtype
- subsystem = properties.get('SUBSYSTEM')
- # A real mess: The main node of a SCSI device has
- # SUBSYSTEM = 'scsi' and DEVTYPE = 'scsi_device', while
- # a sub-node has SUBSYSTEM='scsi_device'. We don't want
- # the two to be confused. The latter node is not of any
- # interest for us, so we return None. This ensures that
- # is_real_device returns False for the sub-node.
- if subsystem != 'scsi_device':
- return subsystem
- else:
- return None
-
- @property
- def is_root_device(self):
- """See `BaseDevice`."""
- return self.udev['P'] == UDEV_ROOT_PATH
-
- def getVendorOrProduct(self, type_):
- """Return the vendor or product of this device.
-
- :return: The vendor or product data for this device.
- :param type_: 'vendor' or 'product'
- """
- assert type_ in ('vendor', 'product'), (
- 'Unexpected value of type_: %r' % type_)
-
- bus = self.raw_bus
- if self.is_root_device:
- # udev does not known about any product information for
- # the root device. We use DMI data instead.
- return self.root_device_ids[type_]
- elif bus == 'scsi_device':
- return self.getScsiVendorAndModelName()[type_]
- elif bus in ('pci', 'usb_device'):
- # XXX Abel Deuring 2009-10-13, bug 450480: udev does not
- # provide human-readable vendor and product names for
- # USB and PCI devices. We should retrieve these from
- # http://www.linux-usb.org/usb.ids and
- # http://pciids.sourceforge.net/v2.2/pci.ids
- return 'Unknown'
- else:
- # We don't process yet other devices than complete systems,
- # PCI, USB devices and those devices that are represented
- # in udev as SCSI devices: real SCSI devices, and
- # IDE/ATA/SATA devices.
- return None
-
- @property
- def vendor(self):
- """See `BaseDevice`."""
- return self.getVendorOrProduct('vendor')
-
- @property
- def product(self):
- """See `BaseDevice`."""
- return self.getVendorOrProduct('product')
-
- def getVendorOrProductID(self, type_):
- """Return the vendor or product ID of this device.
-
- :return: The vendor or product ID for this device.
- :param type_: 'vendor' or 'product'
- """
- assert type_ in ('vendor', 'product'), (
- 'Unexpected value of type_: %r' % type_)
-
- bus = self.raw_bus
- if self.is_root_device:
- # udev does not known about any product information for
- # the root device. We use DMI data instead.
- if type_ == 'vendor':
- return self.dmi.get('/sys/class/dmi/id/sys_vendor')
- else:
- return self.dmi.get('/sys/class/dmi/id/product_name')
- elif bus == 'scsi_device':
- return self.getScsiVendorAndModelName()[type_]
- elif bus == 'pci':
- return self.pci_ids[type_]
- elif bus == 'usb_device':
- return self.usb_ids[type_]
- else:
- # We don't process yet other devices than complete systems,
- # PCI, USB devices and those devices that are represented
- # in udev as SCSI devices: real SCSI devices, and
- # IDE/ATA/SATA devices.
- return None
-
- @property
- def vendor_id(self):
- """See `BaseDevice`."""
- return self.getVendorOrProductID('vendor')
-
- @property
- def product_id(self):
- """See `BaseDevice`."""
- return self.getVendorOrProductID('product')
-
- @property
- def driver_name(self):
- """See `BaseDevice`."""
- return self.udev['E'].get('DRIVER')
-
- @property
- def scsi_controller(self):
- """See `BaseDevice`."""
- if self.raw_bus != 'scsi_device':
- return None
-
- # While SCSI devices from valid submissions should have four
- # ancestors, we can't be sure for bogus or broken submissions.
- try:
- controller = self.parent.parent.parent
- except AttributeError:
- controller = None
- if controller is None:
- self.parser._logWarning(
- 'Found a SCSI device without a sufficient number of '
- 'ancestors: %s' % self.device_id)
- return None
- return controller
-
- @property
- def id(self):
- return self.udev['id']
diff --git a/lib/lp/hardwaredb/scripts/tests/__init__.py b/lib/lp/hardwaredb/scripts/tests/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/lib/lp/hardwaredb/scripts/tests/__init__.py
+++ /dev/null
diff --git a/lib/lp/hardwaredb/scripts/tests/hardwaretest-natty.xml b/lib/lp/hardwaredb/scripts/tests/hardwaretest-natty.xml
deleted file mode 100644
index d09d178..0000000
--- a/lib/lp/hardwaredb/scripts/tests/hardwaretest-natty.xml
+++ /dev/null
@@ -1,473 +0,0 @@
-<?xml version="1.0" ?>
-<system version="1.0">
-
- <!-- Reports coming from the checkbox version in Natty do not
- have the tags <udev> and <dmi> inside <hardware>. Instead,
- they store the data expected in these tags in the tags
-
- <info command="udevadm info - -export-db"> and
- <info command="grep -r . /sys/class/dmi/id/ 2>/dev/null">
-
- inside <
- -->
- <!-- summary: generic information about the submission -->
- <summary>
-
- <!-- live_cd: Was this submission made on a system running an Ubuntu Live
- CD or on a regular Ubuntu/Linux installation?
- -->
- <live_cd value="False"/>
-
- <!-- system_id: A hash of the "system identifier". This value is intended
- to identify the tested computer model; the value should
- be derived from the properties
- system.product, system.vendor of the HAL UDI
- /org/freedesktop/Hal/devices/computer.
- -->
- <system_id value="f982bb1ab536469cebfd6eaadcea0ffc"/>
-
- <!-- distribution, distroseries: These values are retrieved from
- /etc/lsb-release, parameters DISTRIB_ID and DISTRIB_RELEASE.
- -->
- <distribution value="Ubuntu"/>
- <distroseries value="7.04"/>
-
- <!-- architecture: The processor architecture of the operating system.
- -->
- <architecture value="amd64"/>
-
- <!-- private: If False, this submission is publicly accessible from
- Launchpad, else it is only accesible by the submitter, by
- Launchpad administrators and by scripts running with
- administrator rights. Submissions marked "private" should
- only be used to gather statistical data.
- -->
- <private value="False"/>
-
- <!-- contactable: If True, the owner agrees to be contacted by other
- persons about devices which appear in their submission.
- Example of a use case: Developers can ask device owners
- to perform tests.
- -->
- <contactable value="False"/>
-
- <!-- date_created: Date and time (UTC) of the submission.
- -->
- <date_created value="2007-09-28T16:09:20.126842"/>
-
- <!-- client: The name and version of the program that created the
- submission data.
- -->
- <client name="hwtest" version="0.9">
-
- <!-- plugin: name and version of a plugin used by the client.
- This tag may appear more than once.
- -->
- <plugin name="architecture_info" version="1.1"/>
- <plugin name="find_network_controllers" version="2.34"/>
- <plugin name="internet_ping" version="1.1"/>
- <plugin name="harddisk_speed" version="0.7"/>
- </client>
-
- <!-- The kernel name and version, as shown by "uname -r"
- -->
- <kernel-release value="2.6.28-14-generic"/>
- </summary>
-
- <!-- hardware: data about the hardware the submission was made on.
- -->
- <hardware>
-
- <!-- udev: The output of running "udevadm info - -export-db" -->
-
-
- <!-- Additional data for SCSI devices: vendor, model, type
-
- For each udev node which has DEVTYPE=scsi_device, we need
- the content of the sysfs files vendor, model, type. The data
- is stored in the same format as the DMI data:
- /path/to/file:filecontent
- -->
- <sysfs-attributes>
-P: /devices/LNXSYSTM:00/LNXPWRBN:00/input/input0
-A: modalias=input:b0019v0000p0001e0000-e0,1,k74,ramlsfw
-A: uniq=
-A: phys=LNXPWRBN/button/input0
-A: name=Power Button
-
-P: /devices/LNXSYSTM:00/device:00/PNP0A08:00/device:03/input/input8
-A: modalias=input:b0019v0000p0006e0000-e0,1,kE0,E1,E3,F0,F1,F2,F3,F4,F5,ramlsfw
-A: uniq=
-A: phys=/video/input0
-A: name=Video Bus
-</sysfs-attributes>
-
- <!-- processors: Data about processors installed in a system.
- The data is retrieved from /proc/cpuinfo.
- -->
- <processors>
-
- <!-- processor: Data from /proc/cpuinfo about a single processor.
- -->
- <processor id="123" name="0">
-
- <!-- property: The data of one line of /proc/cpuinfo.
- attribute name: The name of the property
- (the text left of the ':' in a line of /proc/cpuinfo)
- attribute type: A Python type appropriate for the value.
- -->
- <property name="wp" type="bool">
- True
- </property>
- <property name="flags" type="list">
- <value type="str">
- fpu
- </value>
- <value type="str">
- vme
- </value>
- <value type="str">
- de
- </value>
- </property>
- <property name="cpu_mhz" type="float">
- 1000.0
- </property>
- </processor>
- </processors>
-
- <!-- aliases: optional data provided by the user:
- The name of a peripheral, PCI card etc as shown by a label on
- the device. OEM devices are often sold under different names
- by different vendors; having a set of alias names for a device
- allows users of the HWDB to search for information by these
- "marketing names".
- -->
- <aliases>
- <!-- alias: The "label name" of a device or system.
- attribute target: The sysfs path of a device as given
- in <udev>.
- -->
- <alias target="/devices/pci0000:00/0000:00:1f.1/host3/target3:0:0/3:0:0:0">
-
- <!-- vendor: The vendor name shown on the device label.
- -->
- <vendor>Medion</vendor>
-
- <!-- model: The model name of shown on the label.
- -->
- <model>QuickPrint 9876</model>
- </alias>
- </aliases>
- </hardware>
-
- <!-- software: Data about the software installed on the system.
- -->
- <software>
-
- <!-- lsbrelease: The data from /etc/lsb-release.
- -->
- <lsbrelease>
-
- <!-- property: the data from one line of /etc/lsb-release.
- attribute type: A Python type appropriate for this
- property (str).
- -->
- <property name="release" type="str">
- 7.04
- </property>
- <property name="codename" type="str">
- feisty
- </property>
- <property name="distributor-id" type="str">
- Ubuntu
- </property>
- <property name="description" type="str">
- Ubuntu 7.04
- </property>
- <property name="dict_example" type="dict">
- <value name="a" type="str">value for key a</value>
- <value name="b" type="int">1234</value>
- </property>
- </lsbrelease>
-
- <!-- packages: Data about the installed software packages.
- -->
- <packages>
-
- <!-- package: Data about a single package.
- The <property> sub-tags contain the DEB properties
- "name", "priority", "section", "source", "version",
- "installed_size", "size", "summary".
-
- XXX Abel Deuring 2007-12-12: What about submissions
- from RPM-based Linux versions? (And "exotic" variants
- like Gentoo?)
- -->
- <package name="metacity" id="200">
- <property name="installed_size" type="int">
- 868352
- </property>
- <property name="section" type="str">
- x11
- </property>
- <property name="summary" type="str">
- A lightweight GTK2 based Window Manager
- </property>
- <property name="priority" type="str">
- optional
- </property>
- <property name="source" type="str">
- metacity
- </property>
- <property name="version" type="str">
- 1:2.18.2-0ubuntu1.1
- </property>
- <property name="size" type="int">
- 429128
- </property>
- </package>
- </packages>
- <!-- Information extracted from Xorg.0.log.
- HAL does not provide any information about Xorg drivers, so
- we retrieve that from the xserver's log file.
- -->
- <xorg version="1.3.0">
- <!-- driver: Data about a driver.
- (optional)
- attribute name: The name of the driver.
- attribute version: The version of the driver.
- attribute class: The module class of the driver
- attribute device: The ID of a device driven by this driver.
- -->
- <driver name="fglrx" version="1.23" class="X.Org Video Driver"
- device="12"/>
- </xorg>
- </software>
-
- <!-- questions: User's answers to questions asked by the client.
- -->
- <questions>
-
- <!-- question: Data of a question.
- attribute name: The unique name of the question.
- attribute plugin: The name of the plugin which asked
- the question.
- attribute version: The version of the question.
- attribute type: Allowed values are "manual" and "automatic".
- A "manual" question requires user input for the answer;
- an "automatic" question gets the answer automatically.
- -->
- <question name="detected_network_controllers"
- plugin="find_network_controllers">
-
- <!-- target: Information about a device or software package the
- question is about. The attribute "id" is the sysfs path of
- a device as given in <udev>, or the ID of a software package
- node.
- This node may appear multiple times.
- -->
- <target id="/devices/pci0000:00/0000:00:1a.0/usb3/3-0:1.0/usb_endpoint/usbdev3.1_ep81">
- <!-- driver: The driver which controls the target device. This tag
- may appear more than once.
-
- While we are working on a project called "Hardware Database",
- we are not that much interested in the question, if a device
- works "as such", but if their Linux driver(s) work.
-
- It is not in every case possible to identify the used driver
- from HAL data, so we need another way to add this information.
- (example: HAL does not know, which driver is used for the
- graphics card.)
-
- Example for multiple drivers: Some scanners have a SCSI _and_
- a USB interface; if such a scanner is tested, we not only want
- to know, which Sane backend is used, but also, which interface
- is used.
-
- Also, it might be interesting to know for many USB 2.0 devices,
- if a USB 1 (uhci_hcd or ohci_hcd driver) or the USB 2 driver
- (ehci_hcd) was used. A USB 1 driver might for example explain
- latency problems.
- -->
- <driver>ipw3945</driver>
- </target>
-
- <!-- ID of the 88E8055 PCI-E Gigabit Ethernet Controller -->
- <target id="/devices/pci0000:00/0000:00:1f.1"/>
-
- <!-- command: The command line of an external command required to
- ask this question.
- -->
- <command/>
-
- <!-- answer: The answer to the question. Two types of answers are
- defined, "multiple_choice" and "measurement". (See below
- for an example of the latter.)
- attribute type: Must be "multiple_choice" or "measurement".
- -->
- <answer type="multiple_choice">pass</answer>
-
- <!-- answer_choices: The list of possible choices.
- The data should only be used for consistency
- checks and to detect variants of the question.
- -->
- <answer_choices>
- <value type="str">fail</value>
- <value type="str">pass</value>
- <value type="str">skip</value>
- </answer_choices>
-
- <!-- A user comment about the device or about the test.
- -->
- <comment>
- The WLAN adapter drops the connection very frequently.
- </comment>
- </question>
-
- <question name="internet_ping"
- plugin="internet_ping">
- <target id="/devices/pci0000:00/0000:00:1f.1"/>
- <command/>
- <answer type="multiple_choice">pass</answer>
- <answer_choices>
- <value type="str">fail</value>
- <value type="str">pass</value>
- <value type="str">skip</value>
- </answer_choices>
- </question>
-
- <!-- example for a "measurement question"
- -->
- <question name="harddisk_speed"
- plugin="harddisk_speed">
- <target id="/devices/pci0000:00/0000:00:1f.1/host3/target3:0:0/3:0:0:0"/>
- <command>hdparm -t /dev/sda</command>
- <!-- answer: The answer to a "measurement question".
- attribute type: See above.
- attribute unit: The unit of the result of the measurement.
- XXX Abel Deuring 2007-12-12 bug=175978 We should
- enumerate a list of allowed units, in order to avoid
- multiple units for the same dimension. e.g., B/sec,
- MB/sec or inch, cm, foot.
-
- For dimensionless values, the attribute unit is omitted.
-
- "Percentage" and similar "convenience pseudo-units" like
- ppm are _not_ allowed; instead a dimensionless
- value must be used, where 0 is equivalent 0% and 1.0 is
- equivalent to 100%.
- -->
- <answer type="measurement" unit="MB/sec">38.4</answer>
- </question>
- </questions>
- <!-- miscellaneous additional text data.
- -->
- <context>
- <info command="udevadm info --export-db">P: /devices/LNXSYSTM:00
-E: UDEV_LOG=3
-E: DEVPATH=/devices/LNXSYSTM:00
-E: MODALIAS=acpi:LNXSYSTM:
-
-P: /devices/pci0000:00/0000:00:1a.0
-E: UDEV_LOG=3
-E: DEVPATH=/devices/pci0000:00/0000:00:1a.0
-E: DRIVER=uhci_hcd
-E: PCI_CLASS=C0300
-E: PCI_ID=8086:2834
-E: PCI_SUBSYS_ID=17AA:20AA
-E: PCI_SLOT_NAME=0000:00:1a.0
-E: MODALIAS=pci:v00008086d00002834sv000017AAsd000020AAbc0Csc03i00
-
-P: /devices/pci0000:00/0000:00:1a.0/usb3
-N: bus/usb/003/001
-S: char/189:256
-E: UDEV_LOG=3
-E: DEVPATH=/devices/pci0000:00/0000:00:1a.0/usb3
-E: MAJOR=189
-E: MINOR=256
-E: DEVTYPE=usb_device
-E: DRIVER=usb
-E: DEVICE=/proc/bus/usb/003/001
-E: PRODUCT=1d6b/1/206
-E: TYPE=9/0/0
-E: BUSNUM=003
-E: DEVNUM=001
-E: DEVNAME=/dev/bus/usb/003/001
-E: DEVLINKS=/dev/char/189:256
-
-P: /devices/pci0000:00/0000:00:1a.0/usb3/3-0:1.0
-E: UDEV_LOG=3
-E: DEVPATH=/devices/pci0000:00/0000:00:1a.0/usb3/3-0:1.0
-E: DEVTYPE=usb_interface
-E: DRIVER=hub
-E: DEVICE=/proc/bus/usb/003/001
-E: PRODUCT=1d6b/1/206
-E: TYPE=9/0/0
-E: INTERFACE=9/0/0
-E: MODALIAS=usb:v1D6Bp0001d0206dc09dsc00dp00ic09isc00ip00
-
-P: /devices/pci0000:00/0000:00:1a.0/usb3/3-0:1.0/usb_endpoint/usbdev3.1_ep81
-N: usbdev3.1_ep81
-S: char/252:4
-E: UDEV_LOG=3
-E: DEVPATH=/devices/pci0000:00/0000:00:1a.0/usb3/3-0:1.0/usb_endpoint/usbdev3.1_ep81
-E: MAJOR=252
-E: MINOR=4
-E: DEVNAME=/dev/usbdev3.1_ep81
-E: DEVLINKS=/dev/char/252:4
-
-P: /devices/pci0000:00/0000:00:1f.1
-E: UDEV_LOG=3
-E: DEVPATH=/devices/pci0000:00/0000:00:1f.1
-E: DRIVER=ata_piix
-E: PCI_CLASS=1018A
-E: PCI_ID=8086:2850
-E: PCI_SUBSYS_ID=17AA:20A6
-E: PCI_SLOT_NAME=0000:00:1f.1
-E: MODALIAS=pci:v00008086d00002850sv000017AAsd000020A6bc01sc01i8a
-
-P: /devices/pci0000:00/0000:00:1f.1/host3
-E: UDEV_LOG=3
-E: DEVPATH=/devices/pci0000:00/0000:00:1f.1/host3
-E: DEVTYPE=scsi_host
-
-P: /devices/pci0000:00/0000:00:1f.1/host3/scsi_host/host3
-E: UDEV_LOG=3
-E: DEVPATH=/devices/pci0000:00/0000:00:1f.1/host3/scsi_host/host3
-
-P: /devices/pci0000:00/0000:00:1f.1/host3/target3:0:0
-E: UDEV_LOG=3
-E: DEVPATH=/devices/pci0000:00/0000:00:1f.1/host3/target3:0:0
-E: DEVTYPE=scsi_target
-
-P: /devices/pci0000:00/0000:00:1f.1/host3/target3:0:0/3:0:0:0
-E: UDEV_LOG=3
-E: DEVPATH=/devices/pci0000:00/0000:00:1f.1/host3/target3:0:0/3:0:0:0
-E: DEVTYPE=scsi_device
-E: DRIVER=sr
-E: MODALIAS=scsi:t-0x05
-</info>
-
- <!-- The content of publicly accessible files in /sys/class/dmi/id/
- format: filename:content
- as for example generated by "grep -r . /sys/class/dmi/id/"
- -->
-
- <info command="grep -r . /sys/class/dmi/id/ 2>/dev/null">/sys/class/dmi/id/bios_vendor:LENOVO
-/sys/class/dmi/id/bios_version:7LETB9WW (2.19 )
-/sys/class/dmi/id/bios_date:06/06/2008
-/sys/class/dmi/id/sys_vendor:LENOVO
-/sys/class/dmi/id/product_name:6457BAG
-/sys/class/dmi/id/product_version:ThinkPad T61
-/sys/class/dmi/id/board_vendor:LENOVO
-/sys/class/dmi/id/board_name:6457BAG
-/sys/class/dmi/id/board_version:Not Available
-/sys/class/dmi/id/chassis_vendor:LENOVO
-/sys/class/dmi/id/chassis_type:10
-/sys/class/dmi/id/chassis_version:Not Available
-/sys/class/dmi/id/chassis_asset_tag:No Asset Information
-/sys/class/dmi/id/modalias:dmi:bvnLENOVO:bvr7LETB9WW(2.19)
-</info>
- </context>
-</system>
diff --git a/lib/lp/hardwaredb/scripts/tests/hardwaretest-udev.xml b/lib/lp/hardwaredb/scripts/tests/hardwaretest-udev.xml
deleted file mode 100644
index 3cd340f..0000000
--- a/lib/lp/hardwaredb/scripts/tests/hardwaretest-udev.xml
+++ /dev/null
@@ -1,462 +0,0 @@
-<?xml version="1.0" ?>
-<system version="1.0">
-
- <!-- summary: generic information about the submission -->
- <summary>
-
- <!-- live_cd: Was this submission made on a system running an Ubuntu Live
- CD or on a regular Ubuntu/Linux installation?
- -->
- <live_cd value="False"/>
-
- <!-- system_id: A hash of the "system identifier". This value is intended
- to identify the tested computer model; the value should
- be derived from the properties
- system.product, system.vendor of the HAL UDI
- /org/freedesktop/Hal/devices/computer.
- -->
- <system_id value="f982bb1ab536469cebfd6eaadcea0ffc"/>
-
- <!-- distribution, distroseries: These values are retrieved from
- /etc/lsb-release, parameters DISTRIB_ID and DISTRIB_RELEASE.
- -->
- <distribution value="Ubuntu"/>
- <distroseries value="7.04"/>
-
- <!-- architecture: The processor architecture of the operating system.
- -->
- <architecture value="amd64"/>
-
- <!-- private: If False, this submission is publicly accessible from
- Launchpad, else it is only accesible by the submitter, by
- Launchpad administrators and by scripts running with
- administrator rights. Submissions marked "private" should
- only be used to gather statistical data.
- -->
- <private value="False"/>
-
- <!-- contactable: If True, the owner agrees to be contacted by other
- persons about devices which appear in their submission.
- Example of a use case: Developers can ask device owners
- to perform tests.
- -->
- <contactable value="False"/>
-
- <!-- date_created: Date and time (UTC) of the submission.
- -->
- <date_created value="2007-09-28T16:09:20.126842"/>
-
- <!-- client: The name and version of the program that created the
- submission data.
- -->
- <client name="hwtest" version="0.9">
-
- <!-- plugin: name and version of a plugin used by the client.
- This tag may appear more than once.
- -->
- <plugin name="architecture_info" version="1.1"/>
- <plugin name="find_network_controllers" version="2.34"/>
- <plugin name="internet_ping" version="1.1"/>
- <plugin name="harddisk_speed" version="0.7"/>
- </client>
-
- <!-- The kernel name and version, as shown by "uname -r"
- -->
- <kernel-release value="2.6.28-14-generic"/>
- </summary>
-
- <!-- hardware: data about the hardware the submission was made on.
- -->
- <hardware>
-
- <!-- udev: The output of running "udevadm info - -export-db" -->
-
- <udev>P: /devices/LNXSYSTM:00
-E: UDEV_LOG=3
-E: DEVPATH=/devices/LNXSYSTM:00
-E: MODALIAS=acpi:LNXSYSTM:
-
-P: /devices/pci0000:00/0000:00:1a.0
-E: UDEV_LOG=3
-E: DEVPATH=/devices/pci0000:00/0000:00:1a.0
-E: DRIVER=uhci_hcd
-E: PCI_CLASS=C0300
-E: PCI_ID=8086:2834
-E: PCI_SUBSYS_ID=17AA:20AA
-E: PCI_SLOT_NAME=0000:00:1a.0
-E: MODALIAS=pci:v00008086d00002834sv000017AAsd000020AAbc0Csc03i00
-
-P: /devices/pci0000:00/0000:00:1a.0/usb3
-N: bus/usb/003/001
-S: char/189:256
-E: UDEV_LOG=3
-E: DEVPATH=/devices/pci0000:00/0000:00:1a.0/usb3
-E: MAJOR=189
-E: MINOR=256
-E: DEVTYPE=usb_device
-E: DRIVER=usb
-E: DEVICE=/proc/bus/usb/003/001
-E: PRODUCT=1d6b/1/206
-E: TYPE=9/0/0
-E: BUSNUM=003
-E: DEVNUM=001
-E: DEVNAME=/dev/bus/usb/003/001
-E: DEVLINKS=/dev/char/189:256
-
-P: /devices/pci0000:00/0000:00:1a.0/usb3/3-0:1.0
-E: UDEV_LOG=3
-E: DEVPATH=/devices/pci0000:00/0000:00:1a.0/usb3/3-0:1.0
-E: DEVTYPE=usb_interface
-E: DRIVER=hub
-E: DEVICE=/proc/bus/usb/003/001
-E: PRODUCT=1d6b/1/206
-E: TYPE=9/0/0
-E: INTERFACE=9/0/0
-E: MODALIAS=usb:v1D6Bp0001d0206dc09dsc00dp00ic09isc00ip00
-
-P: /devices/pci0000:00/0000:00:1a.0/usb3/3-0:1.0/usb_endpoint/usbdev3.1_ep81
-N: usbdev3.1_ep81
-S: char/252:4
-E: UDEV_LOG=3
-E: DEVPATH=/devices/pci0000:00/0000:00:1a.0/usb3/3-0:1.0/usb_endpoint/usbdev3.1_ep81
-E: MAJOR=252
-E: MINOR=4
-E: DEVNAME=/dev/usbdev3.1_ep81
-E: DEVLINKS=/dev/char/252:4
-
-P: /devices/pci0000:00/0000:00:1f.1
-E: UDEV_LOG=3
-E: DEVPATH=/devices/pci0000:00/0000:00:1f.1
-E: DRIVER=ata_piix
-E: PCI_CLASS=1018A
-E: PCI_ID=8086:2850
-E: PCI_SUBSYS_ID=17AA:20A6
-E: PCI_SLOT_NAME=0000:00:1f.1
-E: MODALIAS=pci:v00008086d00002850sv000017AAsd000020A6bc01sc01i8a
-
-P: /devices/pci0000:00/0000:00:1f.1/host3
-E: UDEV_LOG=3
-E: DEVPATH=/devices/pci0000:00/0000:00:1f.1/host3
-E: DEVTYPE=scsi_host
-
-P: /devices/pci0000:00/0000:00:1f.1/host3/scsi_host/host3
-E: UDEV_LOG=3
-E: DEVPATH=/devices/pci0000:00/0000:00:1f.1/host3/scsi_host/host3
-
-P: /devices/pci0000:00/0000:00:1f.1/host3/target3:0:0
-E: UDEV_LOG=3
-E: DEVPATH=/devices/pci0000:00/0000:00:1f.1/host3/target3:0:0
-E: DEVTYPE=scsi_target
-
-P: /devices/pci0000:00/0000:00:1f.1/host3/target3:0:0/3:0:0:0
-E: UDEV_LOG=3
-E: DEVPATH=/devices/pci0000:00/0000:00:1f.1/host3/target3:0:0/3:0:0:0
-E: DEVTYPE=scsi_device
-E: DRIVER=sr
-E: MODALIAS=scsi:t-0x05
-</udev>
-
- <!-- The content of publicly accessible files in /sys/class/dmi/id/
- format: filename:content
- as for example generated by "grep -r . /sys/class/dmi/id/"
- -->
-
- <dmi>/sys/class/dmi/id/bios_vendor:LENOVO
-/sys/class/dmi/id/bios_version:7LETB9WW (2.19 )
-/sys/class/dmi/id/bios_date:06/06/2008
-/sys/class/dmi/id/sys_vendor:LENOVO
-/sys/class/dmi/id/product_name:6457BAG
-/sys/class/dmi/id/product_version:ThinkPad T61
-/sys/class/dmi/id/board_vendor:LENOVO
-/sys/class/dmi/id/board_name:6457BAG
-/sys/class/dmi/id/board_version:Not Available
-/sys/class/dmi/id/chassis_vendor:LENOVO
-/sys/class/dmi/id/chassis_type:10
-/sys/class/dmi/id/chassis_version:Not Available
-/sys/class/dmi/id/chassis_asset_tag:No Asset Information
-/sys/class/dmi/id/modalias:dmi:bvnLENOVO:bvr7LETB9WW(2.19)
-</dmi>
-
- <!-- Additional data for SCSI devices: vendor, model, type
-
- For each udev node which has DEVTYPE=scsi_device, we need
- the content of the sysfs files vendor, model, type. The data
- is stored in the same format as the DMI data:
- /path/to/file:filecontent
- -->
- <sysfs-attributes>
-P: /devices/LNXSYSTM:00/LNXPWRBN:00/input/input0
-A: modalias=input:b0019v0000p0001e0000-e0,1,k74,ramlsfw
-A: uniq=
-A: phys=LNXPWRBN/button/input0
-A: name=Power Button
-
-P: /devices/LNXSYSTM:00/device:00/PNP0A08:00/device:03/input/input8
-A: modalias=input:b0019v0000p0006e0000-e0,1,kE0,E1,E3,F0,F1,F2,F3,F4,F5,ramlsfw
-A: uniq=
-A: phys=/video/input0
-A: name=Video Bus
-</sysfs-attributes>
-
- <!-- processors: Data about processors installed in a system.
- The data is retrieved from /proc/cpuinfo.
- -->
- <processors>
-
- <!-- processor: Data from /proc/cpuinfo about a single processor.
- -->
- <processor id="123" name="0">
-
- <!-- property: The data of one line of /proc/cpuinfo.
- attribute name: The name of the property
- (the text left of the ':' in a line of /proc/cpuinfo)
- attribute type: A Python type appropriate for the value.
- -->
- <property name="wp" type="bool">
- True
- </property>
- <property name="flags" type="list">
- <value type="str">
- fpu
- </value>
- <value type="str">
- vme
- </value>
- <value type="str">
- de
- </value>
- </property>
- <property name="cpu_mhz" type="float">
- 1000.0
- </property>
- </processor>
- </processors>
-
- <!-- aliases: optional data provided by the user:
- The name of a peripheral, PCI card etc as shown by a label on
- the device. OEM devices are often sold under different names
- by different vendors; having a set of alias names for a device
- allows users of the HWDB to search for information by these
- "marketing names".
- -->
- <aliases>
- <!-- alias: The "label name" of a device or system.
- attribute target: The sysfs path of a device as given
- in <udev>.
- -->
- <alias target="/devices/pci0000:00/0000:00:1f.1/host3/target3:0:0/3:0:0:0">
-
- <!-- vendor: The vendor name shown on the device label.
- -->
- <vendor>Medion</vendor>
-
- <!-- model: The model name of shown on the label.
- -->
- <model>QuickPrint 9876</model>
- </alias>
- </aliases>
- </hardware>
-
- <!-- software: Data about the software installed on the system.
- -->
- <software>
-
- <!-- lsbrelease: The data from /etc/lsb-release.
- -->
- <lsbrelease>
-
- <!-- property: the data from one line of /etc/lsb-release.
- attribute type: A Python type appropriate for this
- property (str).
- -->
- <property name="release" type="str">
- 7.04
- </property>
- <property name="codename" type="str">
- feisty
- </property>
- <property name="distributor-id" type="str">
- Ubuntu
- </property>
- <property name="description" type="str">
- Ubuntu 7.04
- </property>
- <property name="dict_example" type="dict">
- <value name="a" type="str">value for key a</value>
- <value name="b" type="int">1234</value>
- </property>
- </lsbrelease>
-
- <!-- packages: Data about the installed software packages.
- -->
- <packages>
-
- <!-- package: Data about a single package.
- The <property> sub-tags contain the DEB properties
- "name", "priority", "section", "source", "version",
- "installed_size", "size", "summary".
-
- XXX Abel Deuring 2007-12-12: What about submissions
- from RPM-based Linux versions? (And "exotic" variants
- like Gentoo?)
- -->
- <package name="metacity" id="200">
- <property name="installed_size" type="int">
- 868352
- </property>
- <property name="section" type="str">
- x11
- </property>
- <property name="summary" type="str">
- A lightweight GTK2 based Window Manager
- </property>
- <property name="priority" type="str">
- optional
- </property>
- <property name="source" type="str">
- metacity
- </property>
- <property name="version" type="str">
- 1:2.18.2-0ubuntu1.1
- </property>
- <property name="size" type="int">
- 429128
- </property>
- </package>
- </packages>
- <!-- Information extracted from Xorg.0.log.
- HAL does not provide any information about Xorg drivers, so
- we retrieve that from the xserver's log file.
- -->
- <xorg version="1.3.0">
- <!-- driver: Data about a driver.
- (optional)
- attribute name: The name of the driver.
- attribute version: The version of the driver.
- attribute class: The module class of the driver
- attribute device: The ID of a device driven by this driver.
- -->
- <driver name="fglrx" version="1.23" class="X.Org Video Driver"
- device="12"/>
- </xorg>
- </software>
-
- <!-- questions: User's answers to questions asked by the client.
- -->
- <questions>
-
- <!-- question: Data of a question.
- attribute name: The unique name of the question.
- attribute plugin: The name of the plugin which asked
- the question.
- attribute version: The version of the question.
- attribute type: Allowed values are "manual" and "automatic".
- A "manual" question requires user input for the answer;
- an "automatic" question gets the answer automatically.
- -->
- <question name="detected_network_controllers"
- plugin="find_network_controllers">
-
- <!-- target: Information about a device or software package the
- question is about. The attribute "id" is the sysfs path of
- a device as given in <udev>, or the ID of a software package
- node.
- This node may appear multiple times.
- -->
- <target id="/devices/pci0000:00/0000:00:1a.0/usb3/3-0:1.0/usb_endpoint/usbdev3.1_ep81">
- <!-- driver: The driver which controls the target device. This tag
- may appear more than once.
-
- While we are working on a project called "Hardware Database",
- we are not that much interested in the question, if a device
- works "as such", but if their Linux driver(s) work.
-
- It is not in every case possible to identify the used driver
- from HAL data, so we need another way to add this information.
- (example: HAL does not know, which driver is used for the
- graphics card.)
-
- Example for multiple drivers: Some scanners have a SCSI _and_
- a USB interface; if such a scanner is tested, we not only want
- to know, which Sane backend is used, but also, which interface
- is used.
-
- Also, it might be interesting to know for many USB 2.0 devices,
- if a USB 1 (uhci_hcd or ohci_hcd driver) or the USB 2 driver
- (ehci_hcd) was used. A USB 1 driver might for example explain
- latency problems.
- -->
- <driver>ipw3945</driver>
- </target>
-
- <!-- ID of the 88E8055 PCI-E Gigabit Ethernet Controller -->
- <target id="/devices/pci0000:00/0000:00:1f.1"/>
-
- <!-- command: The command line of an external command required to
- ask this question.
- -->
- <command/>
-
- <!-- answer: The answer to the question. Two types of answers are
- defined, "multiple_choice" and "measurement". (See below
- for an example of the latter.)
- attribute type: Must be "multiple_choice" or "measurement".
- -->
- <answer type="multiple_choice">pass</answer>
-
- <!-- answer_choices: The list of possible choices.
- The data should only be used for consistency
- checks and to detect variants of the question.
- -->
- <answer_choices>
- <value type="str">fail</value>
- <value type="str">pass</value>
- <value type="str">skip</value>
- </answer_choices>
-
- <!-- A user comment about the device or about the test.
- -->
- <comment>
- The WLAN adapter drops the connection very frequently.
- </comment>
- </question>
-
- <question name="internet_ping"
- plugin="internet_ping">
- <target id="/devices/pci0000:00/0000:00:1f.1"/>
- <command/>
- <answer type="multiple_choice">pass</answer>
- <answer_choices>
- <value type="str">fail</value>
- <value type="str">pass</value>
- <value type="str">skip</value>
- </answer_choices>
- </question>
-
- <!-- example for a "measurement question"
- -->
- <question name="harddisk_speed"
- plugin="harddisk_speed">
- <target id="/devices/pci0000:00/0000:00:1f.1/host3/target3:0:0/3:0:0:0"/>
- <command>hdparm -t /dev/sda</command>
- <!-- answer: The answer to a "measurement question".
- attribute type: See above.
- attribute unit: The unit of the result of the measurement.
- XXX Abel Deuring 2007-12-12 bug=175978 We should
- enumerate a list of allowed units, in order to avoid
- multiple units for the same dimension. e.g., B/sec,
- MB/sec or inch, cm, foot.
-
- For dimensionless values, the attribute unit is omitted.
-
- "Percentage" and similar "convenience pseudo-units" like
- ppm are _not_ allowed; instead a dimensionless
- value must be used, where 0 is equivalent 0% and 1.0 is
- equivalent to 100%.
- -->
- <answer type="measurement" unit="MB/sec">38.4</answer>
- </question>
- </questions>
- <!-- miscellaneous additional text data.
- -->
-</system>
diff --git a/lib/lp/hardwaredb/scripts/tests/hardwaretest.xml b/lib/lp/hardwaredb/scripts/tests/hardwaretest.xml
deleted file mode 100644
index 35d24b6..0000000
--- a/lib/lp/hardwaredb/scripts/tests/hardwaretest.xml
+++ /dev/null
@@ -1,426 +0,0 @@
-<?xml version="1.0" ?>
-<system version="1.0">
-
- <!-- summary: generic information about the submission -->
- <summary>
-
- <!-- live_cd: Was this submission made on a system running an Ubuntu Live
- CD or on a regular Ubuntu/Linux installation?
- -->
- <live_cd value="False"/>
-
- <!-- system_id: A hash of the "system identifier". This value is intended
- to identify the tested computer model; the value should
- be derived from the properties
- system.product, system.vendor of the HAL UDI
- /org/freedesktop/Hal/devices/computer.
- -->
- <system_id value="f982bb1ab536469cebfd6eaadcea0ffc"/>
-
- <!-- distribution, distroseries: These values are retrieved from
- /etc/lsb-release, parameters DISTRIB_ID and DISTRIB_RELEASE.
- -->
- <distribution value="Ubuntu"/>
- <distroseries value="7.04"/>
-
- <!-- architecture: The processor architecture of the operating system.
- -->
- <architecture value="amd64"/>
-
- <!-- private: If False, this submission is publicly accessible from
- Launchpad, else it is only accesible by the submitter, by
- Launchpad administrators and by scripts running with
- administrator rights. Submissions marked "private" should
- only be used to gather statistical data.
- -->
- <private value="False"/>
-
- <!-- contactable: If True, the owner agrees to be contacted by other
- persons about devices which appear in their submission.
- Example of a use case: Developers can ask device owners
- to perform tests.
- -->
- <contactable value="False"/>
-
- <!-- date_created: Date and time (UTC) of the submission.
- -->
- <date_created value="2007-09-28T16:09:20.126842"/>
-
- <!-- client: The name and version of the program that created the
- submission data.
- -->
- <client name="hwtest" version="0.9">
-
- <!-- plugin: name and version of a plugin used by the client.
- This tag may appear more than once.
- -->
- <plugin name="architecture_info" version="1.1"/>
- <plugin name="find_network_controllers" version="2.34"/>
- <plugin name="internet_ping" version="1.1"/>
- <plugin name="harddisk_speed" version="0.7"/>
- </client>
- </summary>
-
- <!-- hardware: data about the hardware the submission was made on.
- -->
- <hardware>
-
- <!-- hal: data collected from HAL.
- attribute version: The version of the HAL daemon.
- -->
- <hal version="0.5.8.1">
-
- <!-- device: The data of a HAL device object.
- attribute id: A unique identifier created by th client.
- attribute udi: the HAL UDI of the device. Privacy sensitive
- UDIs (e.g., those containing UUID, MAC addresses, serial
- numbers) should be obscured.
- attribute parent: The ID of the parent HAL node of this
- device
- -->
- <device id="0" parent="130" udi="/org/freedesktop/Hal/devices/platform_bluetooth">
- <!-- property: A HAL device property.
- attribute name: The name of the property.
- attribute type: The DBus type of the property.
-
- The value of a property is stored as CTEXT, except
- for properties of the dictionary- and list-like
- types.
-
- For list-like types, the values are stored in sub-tags
- <value>, which have the required attribute "type".
-
- For dictionary-like types, the values are stored in
- sub-tags value, which have the required attributes
- "type" and "name".
-
- The "type" attribute contains the DBus type of a value.
- -->
- <property name="info.parent" type="dbus.String">
- /org/freedesktop/Hal/devices/computer
- </property>
- <property name="info.bus" type="dbus.String">
- platform
- </property>
- <property name="button.has_state" type="dbus.Boolean">
- False
- </property>
- <property name="info.capabilities" type="dbus.Array">
- <value type="dbus.String">
- button
- </value>
- </property>
- <property name="linux.acpi_type" type="dbus.Int32">
- 11
- </property>
-
- <property name="storage.size" type="dbus.UInt64">
- 0
- </property>
- <!-- pure theory/for possible new feature in future HAL versions:
- The data type dbus.Dictionary is at present (Nov 2007) not
- used by HAL.
- -->
- <property name="test.only" type="dbus.Dictionary">
- <value name="foo" type="dbus.String">bar</value>
- <value name="blah" type="dbus.Int32">1234</value>
- </property>
- </device>
- <device id="130" udi="/org/freedesktop/Hal/devices/computer">
- <property name="info.bus" type="dbus.String">
- unknown
- </property>
- </device>
- </hal>
-
- <!-- processors: Data about processors installed in a system.
- The data is retrieved from /proc/cpuinfo.
- -->
- <processors>
-
- <!-- processor: Data from /proc/cpuinfo about a single processor.
- -->
- <processor id="123" name="0">
-
- <!-- property: The data of one line of /proc/cpuinfo.
- attribute name: The name of the property
- (the text left of the ':' in a line of /proc/cpuinfo)
- attribute type: A Python type appropriate for the value.
- -->
- <property name="wp" type="bool">
- True
- </property>
- <property name="flags" type="list">
- <value type="str">
- fpu
- </value>
- <value type="str">
- vme
- </value>
- <value type="str">
- de
- </value>
- </property>
- <property name="cpu_mhz" type="float">
- 1000.0
- </property>
- </processor>
- </processors>
-
- <!-- aliases: optional data provided by the user:
- The name of a peripheral, PCI card etc as shown by a label on
- the device. OEM devices are often sold under different names
- by different vendors; having a set of alias names for a device
- allows users of the HWDB to search for information by these
- "marketing names".
- -->
- <aliases>
- <!-- alias: The "label name" of a device or system.
- attribute target: The ID of the HAL node of the device
- or system.
- -->
- <alias target="65">
-
- <!-- vendor: The vendor name shown on the device label.
- -->
- <vendor>Medion</vendor>
-
- <!-- model: The model name of shown on the label.
- -->
- <model>QuickPrint 9876</model>
- </alias>
- </aliases>
- </hardware>
-
- <!-- software: Data about the software installed on the system.
- -->
- <software>
-
- <!-- lsbrelease: The data from /etc/lsb-release.
- -->
- <lsbrelease>
-
- <!-- property: the data from one line of /etc/lsb-release.
- attribute type: A Python type appropriate for this
- property (str).
- -->
- <property name="release" type="str">
- 7.04
- </property>
- <property name="codename" type="str">
- feisty
- </property>
- <property name="distributor-id" type="str">
- Ubuntu
- </property>
- <property name="description" type="str">
- Ubuntu 7.04
- </property>
- <property name="dict_example" type="dict">
- <value name="a" type="str">value for key a</value>
- <value name="b" type="int">1234</value>
- </property>
- </lsbrelease>
-
- <!-- packages: Data about the installed software packages.
- -->
- <packages>
-
- <!-- package: Data about a single package.
- The <property> sub-tags contain the DEB properties
- "name", "priority", "section", "source", "version",
- "installed_size", "size", "summary".
-
- XXX Abel Deuring 2007-12-12: What about submissions
- from RPM-based Linux versions? (And "exotic" variants
- like Gentoo?)
- -->
- <package name="metacity" id="200">
- <property name="installed_size" type="int">
- 868352
- </property>
- <property name="section" type="str">
- x11
- </property>
- <property name="summary" type="str">
- A lightweight GTK2 based Window Manager
- </property>
- <property name="priority" type="str">
- optional
- </property>
- <property name="source" type="str">
- metacity
- </property>
- <property name="version" type="str">
- 1:2.18.2-0ubuntu1.1
- </property>
- <property name="size" type="int">
- 429128
- </property>
- </package>
- </packages>
- <!-- Information extracted from Xorg.0.log.
- HAL does not provide any information about Xorg drivers, so
- we retrieve that from the xserver's log file.
- -->
- <xorg version="1.3.0">
- <!-- driver: Data about a driver.
- (optional)
- attribute name: The name of the driver.
- attribute version: The version of the driver.
- attribute class: The module class of the driver
- attribute device: The ID of a device driven by this driver.
- -->
- <driver name="fglrx" version="1.23" class="X.Org Video Driver"
- device="12"/>
- </xorg>
- </software>
-
- <!-- questions: User's answers to questions asked by the client.
- -->
- <questions>
-
- <!-- question: Data of a question.
- attribute name: The unique name of the question.
- attribute plugin: The name of the plugin which asked
- the question.
- attribute version: The version of the question.
- attribute type: Allowed values are "manual" and "automatic".
- A "manual" question requires user input for the answer;
- an "automatic" question gets the answer automatically.
- -->
- <question name="detected_network_controllers"
- plugin="find_network_controllers">
-
- <!-- target: Information about a device or software package the
- question is about. The attribute "id" is the ID of a HAL device
- node or of a software package.
- This node may appear multiple times.
- -->
- <target id="42">
- <!-- driver: The driver which controls the target device. This tag
- may appear more than once.
-
- While we are working on a project called "Hardware Database",
- we are not that much interested in the question, if a device
- works "as such", but if their Linux driver(s) work.
-
- It is not in every case possible to identify the used driver
- from HAL data, so we need another way to add this information.
- (example: HAL does not know, which driver is used for the
- graphics card.)
-
- Example for multiple drivers: Some scanners have a SCSI _and_
- a USB interface; if such a scanner is tested, we not only want
- to know, which Sane backend is used, but also, which interface
- is used.
-
- Also, it might be interesting to know for many USB 2.0 devices,
- if a USB 1 (uhci_hcd or ohci_hcd driver) or the USB 2 driver
- (ehci_hcd) was used. A USB 1 driver might for example explain
- latency problems.
- -->
- <driver>ipw3945</driver>
- </target>
-
- <!-- ID of the 88E8055 PCI-E Gigabit Ethernet Controller -->
- <target id="43"/>
-
- <!-- command: The command line of an external command required to
- ask this question.
- -->
- <command/>
-
- <!-- answer: The answer to the question. Two types of answers are
- defined, "multiple_choice" and "measurement". (See below
- for an example of the latter.)
- attribute type: Must be "multiple_choice" or "measurement".
- -->
- <answer type="multiple_choice">pass</answer>
-
- <!-- answer_choices: The list of possible choices.
- The data should only be used for consistency
- checks and to detect variants of the question.
- -->
- <answer_choices>
- <value type="str">fail</value>
- <value type="str">pass</value>
- <value type="str">skip</value>
- </answer_choices>
-
- <!-- A user comment about the device or about the test.
- -->
- <comment>
- The WLAN adapter drops the connection very frequently.
- </comment>
- </question>
-
- <question name="internet_ping"
- plugin="internet_ping">
- <target id="23"/>
- <command/>
- <answer type="multiple_choice">pass</answer>
- <answer_choices>
- <value type="str">fail</value>
- <value type="str">pass</value>
- <value type="str">skip</value>
- </answer_choices>
- </question>
-
- <!-- example for a "measurement question"
- -->
- <question name="harddisk_speed"
- plugin="harddisk_speed">
- <target id="87"/>
- <command>hdparm -t /dev/sda</command>
- <!-- answer: The answer to a "measurement question".
- attribute type: See above.
- attribute unit: The unit of the result of the measurement.
- XXX Abel Deuring 2007-12-12 bug=175978 We should
- enumerate a list of allowed units, in order to avoid
- multiple units for the same dimension. e.g., B/sec,
- MB/sec or inch, cm, foot.
-
- For dimensionless values, the attribute unit is omitted.
-
- "Percentage" and similar "convenience pseudo-units" like
- ppm are _not_ allowed; instead a dimensionless
- value must be used, where 0 is equivalent 0% and 1.0 is
- equivalent to 100%.
- -->
- <answer type="measurement" unit="MB/sec">38.4</answer>
- </question>
- </questions>
- <!-- miscellaneous additional text data.
- -->
- <context>
- <!-- info: The text output of the command specified in the "command"
- attribute. The "commmand" attribute must contain the complote
- command line used to produce the text output, including
- parameters used to invoke a program.
- -->
- <info command="dmidecode">
-# dmidecode 2.9
-SMBIOS 2.4 present.
-73 structures occupying 2436 bytes.
-Table at 0x000E0010.
-
-Handle 0x0000, DMI type 0, 24 bytes
-BIOS Information
- Vendor: LENOVO
- </info>
-
- <info command="lspci -vvn">
-00:00.0 0600: 8086:2a00 (rev 0c)
- Subsystem: 17aa:20b1
- Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop-
- Status: Cap+ 66MHz- UDF- FastB2B+ ParErr- >TAbort- <TAbort-
- Latency: 0
- Capabilities: [e0] Vendor Specific Information >?<
- Kernel modules: intel-agp
-
-00:01.0 0604: 8086:2a01 (rev 0c)
- Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV-
- </info>
- </context>
-</system>
diff --git a/lib/lp/hardwaredb/scripts/tests/test_hwdb_submission_parser.py b/lib/lp/hardwaredb/scripts/tests/test_hwdb_submission_parser.py
deleted file mode 100644
index e8b5e36..0000000
--- a/lib/lp/hardwaredb/scripts/tests/test_hwdb_submission_parser.py
+++ /dev/null
@@ -1,2618 +0,0 @@
-# Copyright 2009-2019 Canonical Ltd. This software is licensed under the
-# GNU Affero General Public License version 3 (see the file LICENSE).
-
-"""Tests of the HWDB submissions parser."""
-
-from __future__ import absolute_import, print_function, unicode_literals
-
-from datetime import datetime
-import io
-import logging
-import os
-from textwrap import dedent
-from xml.etree.cElementTree import Element
-
-import defusedxml.cElementTree as etree
-import pytz
-from zope.testing.loghandler import Handler
-
-from lp.hardwaredb.scripts.hwdbsubmissions import (
- ROOT_UDI,
- SubmissionParser,
- )
-from lp.services.config import config
-from lp.testing import (
- TestCase,
- validate_mock_class,
- )
-from lp.testing.layers import BaseLayer
-
-
-class SubmissionParserTestParseSoftware(SubmissionParser):
- """A Variant used to test SubmissionParser._parseSoftware.
-
- This class can be used to test the regular case of
- submission data.
- """
-
- def __init__(self, test, logger=None):
- super(SubmissionParserTestParseSoftware, self).__init__(logger)
- self.test = test
-
- def _parseLSBRelease(self, node):
- self.test.assertEqual(node.tag, 'lsbrelease')
- return 'parsed lsb release'
-
- def _parsePackages(self, node):
- self.test.assertEqual(node.tag, 'packages')
- return 'parsed packages'
-
- def _parseXOrg(self, node):
- self.test.assertEqual(node.tag, 'xorg')
- return 'parsed xorg'
-
-
-class SubmissionParserTestParseSoftwareNoXorgNode(SubmissionParser):
- """A Variant used to test SubmissionParser._parseSoftware.
-
- This class is intended to test submission data that does not contain
- a <xorg> node.
- """
-
- def __init__(self, test, logger=None):
- super(SubmissionParserTestParseSoftwareNoXorgNode, self).__init__(
- logger)
- self.test = test
-
- def _parseLSBRelease(self, node):
- self.test.assertEqual(node.tag, 'lsbrelease')
- return 'parsed lsb release'
-
- def _parsePackages(self, node):
- self.test.assertEqual(node.tag, 'packages')
- return 'parsed packages'
-
-
-class SubmissionParserTestParseSoftwareNoPackagesNode(SubmissionParser):
- """A Variant used to test SubmissionParser._parseSoftware.
-
- This class is intended to test submission data that does not contain
- a <packages> node.
- """
-
- def __init__(self, test, logger=None):
- super(SubmissionParserTestParseSoftwareNoPackagesNode, self).__init__(
- logger)
- self.test = test
-
- def _parseLSBRelease(self, node):
- self.test.assertEqual(node.tag, 'lsbrelease')
- return 'parsed lsb release'
-
- def _parseXOrg(self, node):
- self.test.assertEqual(node.tag, 'xorg')
- return 'parsed xorg'
-
-
-class TestHWDBSubmissionParser(TestCase):
- """Tests of the HWDB submission parser."""
-
- layer = BaseLayer
-
- def setUp(self):
- """Setup the test environment."""
- super(TestHWDBSubmissionParser, self).setUp()
- self.log = logging.getLogger('test_hwdb_submission_parser')
- self.log.setLevel(logging.INFO)
- self.handler = Handler(self)
- self.handler.add(self.log.name)
- self.udev_root_device = {
- 'P': '/devices/LNXSYSTM:00',
- 'E': {'SUBSYSTEM': 'acpi'},
- }
- self.udev_pci_device = {
- 'P': '/devices/pci0000:00/0000:00:1f.2',
- 'E': {
- 'SUBSYSTEM': 'pci',
- 'PCI_CLASS': '10601',
- 'PCI_ID': '8086:27C5',
- 'PCI_SUBSYS_ID': '10CF:1387',
- 'PCI_SLOT_NAME': '0000:00:1f.2',
- }
- }
- self.udev_usb_device = {
- 'P': '/devices/pci0000:00/0000:00:1d.1/usb3/3-2',
- 'E': {
- 'SUBSYSTEM': 'usb',
- 'DEVTYPE': 'usb_device',
- 'PRODUCT': '46d/a01/1013',
- 'TYPE': '0/0/0',
- },
- }
- self.udev_usb_interface = {
- 'P': '/devices/pci0000:00/0000:00:1d.1/usb3/3-2/3-2:1.1',
- 'E': {
- 'SUBSYSTEM': 'usb',
- 'DEVTYPE': 'usb_interface',
- 'PRODUCT': '46d/a01/1013',
- 'TYPE': '0/0/0',
- 'INTERFACE': '1/2/0',
- },
- }
-
- self.udev_scsi_device = {
- 'P': '/devices/pci0000:00/0000:00:1f.1/host4/target4:0:0/4:0:0:0',
- 'E': {
- 'SUBSYSTEM': 'scsi',
- 'DEVTYPE': 'scsi_device',
- },
- }
-
- self.sysfs_scsi_device = {
- 'vendor': 'MATSHITA',
- 'model': 'DVD-RAM UJ-841S',
- 'type': '5',
- }
-
- def getTimestampETreeNode(self, time_string):
- """Return an Elementtree node for an XML tag with a timestamp."""
- return Element('date_created', value=time_string)
-
- def testTimeConversion(self):
- """Test of the conversion of a "time string" into datetime object."""
- # Year, month, day, hour, minute, second are required.
- # We assume that such a value without timezone information is UTC.
- parser = SubmissionParser(self.log)
- utc_tz = pytz.timezone('UTC')
-
- time_node = self.getTimestampETreeNode('2008-01-02T03:04:05')
- self.assertEqual(parser._getValueAttributeAsDateTime(time_node),
- datetime(2008, 1, 2, 3, 4, 5, tzinfo=utc_tz))
-
- # The timezone value 'Z' means UTC
- time_node = self.getTimestampETreeNode('2008-01-02T03:04:05Z')
- self.assertEqual(parser._getValueAttributeAsDateTime(time_node),
- datetime(2008, 1, 2, 3, 4, 5, tzinfo=utc_tz))
-
- # A time zone offset is added to the given time, so that the resulting
- # time stamp is in UTC.
- time_node = self.getTimestampETreeNode('2008-01-02T03:04:05+01:00')
- self.assertEqual(parser._getValueAttributeAsDateTime(time_node),
- datetime(2008, 1, 2, 2, 4, 5, tzinfo=utc_tz))
-
- time_node = self.getTimestampETreeNode('2008-01-02T03:04:05-01:00')
- self.assertEqual(parser._getValueAttributeAsDateTime(time_node),
- datetime(2008, 1, 2, 4, 4, 5, tzinfo=utc_tz))
-
- # time values may be given with microsecond resolution.
- time_node = self.getTimestampETreeNode('2008-01-02T03:04:05.123')
- self.assertEqual(parser._getValueAttributeAsDateTime(time_node),
- datetime(2008, 1, 2, 3, 4, 5, 123000, tzinfo=utc_tz))
-
- time_node = self.getTimestampETreeNode('2008-01-02T03:04:05.123456')
- self.assertEqual(parser._getValueAttributeAsDateTime(time_node),
- datetime(2008, 1, 2, 3, 4, 5, 123456, tzinfo=utc_tz))
-
- # The time zone offset may be given with "minute resolution".
- time_node = self.getTimestampETreeNode('2008-01-02T03:04:05+00:01')
- self.assertEqual(parser._getValueAttributeAsDateTime(time_node),
- datetime(2008, 1, 2, 3, 3, 5, tzinfo=utc_tz))
-
- time_node = self.getTimestampETreeNode('2008-01-02T03:04:05-00:01')
- self.assertEqual(parser._getValueAttributeAsDateTime(time_node),
- datetime(2008, 1, 2, 3, 5, 5, tzinfo=utc_tz))
-
- # Leap seconds are rounded down to 59.999999 seconds.
- time_node = self.getTimestampETreeNode('2008-01-02T23:59:60.999')
- self.assertEqual(parser._getValueAttributeAsDateTime(time_node),
- datetime(2008, 1, 2, 23, 59, 59, 999999,
- tzinfo=utc_tz))
-
- # "Negative" time values raise a ValueError.
- time_node = self.getTimestampETreeNode('-1000-01-02/03:04:05')
- parser.submission_key = 'testing negative time stamps'
- self.assertRaises(
- ValueError, parser._getValueAttributeAsDateTime, time_node)
-
- # Time values with years values with five or more digits raise
- # a ValueError.
- time_node = self.getTimestampETreeNode('12345-01-02/03:04:05')
- parser.submission_key = 'testing negative time stamps'
- self.assertRaises(
- ValueError, parser._getValueAttributeAsDateTime, time_node)
-
- def testSummary(self):
- node = etree.fromstring("""
- <summary>
- <live_cd value="False"/>
- <system_id value="f982bb1ab536469cebfd6eaadcea0ffc"/>
- <distribution value="Ubuntu"/>
- <distroseries value="7.04"/>
- <architecture value="amd64"/>
- <private value="False"/>
- <contactable value="False"/>
- <date_created value="2007-09-28T16:09:20.126842"/>
- <client name="hwtest" version="0.9">
- <plugin name="architecture_info" version="1.1"/>
- <plugin name="find_network_controllers" version="2.34"/>
- </client>
- </summary>
- """)
- parser = SubmissionParser(self.log)
- summary = parser._parseSummary(node)
- expected_data = {
- 'live_cd': False,
- 'system_id': 'f982bb1ab536469cebfd6eaadcea0ffc',
- 'distribution': 'Ubuntu',
- 'distroseries': '7.04',
- 'architecture': 'amd64',
- 'private': False,
- 'contactable': False,
- 'date_created': datetime(2007, 9, 28, 16, 9, 20, 126842,
- tzinfo=pytz.UTC),
- 'client': {
- 'name': 'hwtest',
- 'version': '0.9',
- 'plugins': [
- {'name': 'architecture_info',
- 'version': '1.1'},
- {'name': 'find_network_controllers',
- 'version': '2.34'}]},
- }
- self.assertEqual(
- summary, expected_data,
- 'SubmissionParser.parseSummary returned an unexpected result')
-
- def testSummaryNodeWithKernelRelease(self):
- """The <summary> node may contain the sub-node <kernel-release>."""
- node = etree.fromstring("""
- <summary>
- <live_cd value="False"/>
- <system_id value="f982bb1ab536469cebfd6eaadcea0ffc"/>
- <distribution value="Ubuntu"/>
- <distroseries value="7.04"/>
- <architecture value="amd64"/>
- <private value="False"/>
- <contactable value="False"/>
- <date_created value="2007-09-28T16:09:20.126842"/>
- <client name="hwtest" version="0.9">
- <plugin name="architecture_info" version="1.1"/>
- <plugin name="find_network_controllers" version="2.34"/>
- </client>
- <kernel-release value="2.6.28-15-generic"/>
- </summary>
- """)
- parser = SubmissionParser(self.log)
- summary = parser._parseSummary(node)
- expected_data = {
- 'live_cd': False,
- 'system_id': 'f982bb1ab536469cebfd6eaadcea0ffc',
- 'distribution': 'Ubuntu',
- 'distroseries': '7.04',
- 'architecture': 'amd64',
- 'private': False,
- 'contactable': False,
- 'date_created': datetime(2007, 9, 28, 16, 9, 20, 126842,
- tzinfo=pytz.UTC),
- 'client': {
- 'name': 'hwtest',
- 'version': '0.9',
- 'plugins': [
- {
- 'name': 'architecture_info',
- 'version': '1.1',
- },
- {
- 'name': 'find_network_controllers',
- 'version': '2.34'
- }
- ]
- },
- 'kernel-release': '2.6.28-15-generic',
- }
- self.assertEqual(
- summary, expected_data,
- 'SubmissionParser.parseSummary returned an unexpected result')
-
- def _runPropertyTest(self, xml):
- parser = SubmissionParser(self.log)
- node = etree.fromstring(xml)
- return parser._parseProperty(node)
-
- def testBooleanPropertyTypes(self):
- """Test the parsing result for a boolean property."""
- for property_type in ('bool', 'dbus.Boolean'):
- for value in (True, False):
- xml = ('<property type="%s" name="foo">%s</property>'
- % (property_type, value))
- result = self._runPropertyTest(xml)
- self.assertEqual(
- result, ('foo', (value, property_type)),
- 'Invalid parsing result for boolean property type %s, '
- 'expected %s, got %s'
- % (property_type, value, result))
-
- def testStringPropertyTypes(self):
- """String properties are converted into (name, (value, type))."""
- xml_template = '<property type="%s" name="foo">some text</property>'
- for property_type in ('str', 'dbus.String', 'dbus.UTF8String'):
- xml = xml_template % property_type
- result = self._runPropertyTest(xml)
- self.assertEqual(
- result, ('foo', ('some text', property_type)),
- 'Invalid parsing result for string property type %s, '
- 'expected "some text", got "%s"'
- % (property_type, result))
-
- def testStringPropertyEncoding(self):
- """Different encodings are properly handled."""
- xml_template = u'''<?xml version="1.0" encoding="%s"?>
- <property type="str" name="foo">%s</property>'''
- umlaut = u'\xe4'
- parser = SubmissionParser()
- for encoding in ('utf-8', 'iso-8859-1'):
- xml = (xml_template % (encoding, umlaut)).encode(encoding)
- tree = etree.parse(io.BytesIO(xml))
- node = tree.getroot()
- result = parser._parseProperty(node)
- self.assertEqual(result, ('foo', (umlaut, 'str')),
- 'Invalid parsing result for string encoding %s, '
- 'expected an umlaut (\xe4), got %s'
- % (encoding, repr(result)))
-
- def testIntegerPropertyTypes(self):
- """Int properties are converted into (name, (value, type_string)).
-
- type(value) is int or long, depending on the value.
- """
- xml_template = '<property name="inttest" type="%s">123</property>'
- for property_type in ('dbus.Byte', 'dbus.Int16', 'dbus.Int32',
- 'dbus.Int64', 'dbus.UInt16', 'dbus.UInt32',
- 'dbus.UInt64', 'int', 'long'):
- xml = xml_template % property_type
- result = self._runPropertyTest(xml)
- self.assertEqual(result, ('inttest', (123, property_type)),
- 'Invalid parsing result for integer property '
- 'type %s' % property_type)
- # If the value is too large for an int, a Python long is returned.
- xml = """
- <property name="inttest" type="long">
- 12345678901234567890
- </property>"""
- properties = self._runPropertyTest(xml)
- self.assertEqual(properties,
- ('inttest', (12345678901234567890L, 'long')),
- 'Invalid parsing result for integer property with '
- 'a large value')
-
- def testFloatPropertyTypes(self):
- """Float properties are converted into ('name', (value, type_string)).
-
- type(value) is float.
- """
- xml_template = ('<property name="floattest" type="%s">'
- '1.25</property>')
- for property_type in ('dbus.Double', 'float'):
- xml = xml_template % property_type
- result = self._runPropertyTest(xml)
- self.assertEqual(result, ('floattest', (1.25, property_type)),
- 'Invalid parsing result for float property'
- 'type: %s' % property_type)
-
- def testListPropertyTypes(self):
- """List properties are converted into ('name', a_list).
-
- a_list is a Python list, where the list elements represent the
- values of the <value> sub-nodes of the <property>.
- """
- xml_template = """
- <property name="listtest" type="%s">
- <value type="int">1</value>
- <value type="str">a</value>
- <value type="list">
- <value type="int">2</value>
- <value type="float">3.4</value>
- </value>
- <value type="dict">
- <value name="one" type="int">2</value>
- <value name="two" type="str">b</value>
- </value>
- </property>
- """
- for property_type in ('dbus.Array', 'list'):
- xml = xml_template % property_type
- result = self._runPropertyTest(xml)
- self.assertEqual(result,
- ('listtest', ([(1, 'int'),
- ('a', 'str'),
- ([(2, 'int'),
- (3.4, 'float')], 'list'),
- ({'one': (2, 'int'),
- 'two': ('b', 'str')}, 'dict')],
- property_type)),
- 'Invalid parsing result for list property: '
- '%s' % xml)
-
- def testDictPropertyTypes(self):
- """Dict properties are converted into ('name', a_dict).
-
- a_dict is a Python dictionary, where the items represent the
- values of the <value> sub-nodes of the <property>.
- """
- xml_template = """
- <property name="dicttest" type="%s">
- <value name="one" type="int">1</value>
- <value name="two" type="str">a</value>
- <value name="three" type="list">
- <value type="int">2</value>
- <value type="float">3.4</value>
- </value>
- <value name="four" type="dict">
- <value name="five" type="int">2</value>
- <value name="six" type="str">b</value>
- </value>
- </property>
- """
- for property_type in ('dbus.Dictionary', 'dict'):
- xml = xml_template % property_type
- result = self._runPropertyTest(xml)
- self.assertEqual(
- result,
- ('dicttest', ({'one': (1, 'int'),
- 'two': ('a', 'str'),
- 'three': ([(2, 'int'),
- (3.4, 'float')], 'list'),
- 'four': ({'five': (2, 'int'),
- 'six': ('b', 'str')}, 'dict')},
- property_type)),
- 'Invalid parsing result for dict property: %s' % xml)
-
- def testProperties(self):
- """A set of properties is converted into a dictionary."""
- node = etree.fromstring("""
- <container>
- <property name="one" type="int">1</property>
- <property name="two" type="str">a</property>
- </container>
- """)
- parser = SubmissionParser(self.log)
- result = parser._parseProperties(node)
- self.assertEqual(result,
- {'one': (1, 'int'),
- 'two': ('a', 'str')},
- 'Invalid parsing result for a property set')
-
- # Duplicate property names raise a ValueError
- node = etree.fromstring("""
- <container>
- <property name="one" type="int">1</property>
- <property name="one" type="str">a</property>
- </container>
- """)
- self.assertRaises(ValueError, parser._parseProperties, node)
-
- def testDevice(self):
- """A device node is converted into a dictionary."""
- test = self
-
- def _parseProperties(self, node):
- test.assertTrue(isinstance(self, SubmissionParser))
- test.assertEqual(node.tag, 'device')
- return 'parsed properties'
- parser = SubmissionParser(self.log)
- parser._parseProperties = lambda node: _parseProperties(parser, node)
-
- node = etree.fromstring("""
- <device id="2" udi="/org/freedesktop/Hal/devices/acpi_CPU0"
- parent="1">
- <property name="info.product" type="str">
- Intel(R) Core(TM)2 CPU
- </property>
- </device>
- """)
- result = parser._parseDevice(node)
- self.assertEqual(result,
- {'id': 2,
- 'udi': '/org/freedesktop/Hal/devices/acpi_CPU0',
- 'parent': 1,
- 'properties': 'parsed properties'},
- 'Invalid parsing result for <device> (2)')
-
- # the attribute "parent" may be omitted.
- node = etree.fromstring("""
- <device id="1" udi="/org/freedesktop/Hal/devices/computer">
- <property name="info.product" type="str">Computer</property>
- </device>
- """)
- result = parser._parseDevice(node)
- self.assertEqual(result,
- {'id': 1,
- 'udi': ROOT_UDI,
- 'parent': None,
- 'properties': 'parsed properties'},
- 'Invalid parsing result for <device> (1)')
-
- def testHal(self):
- """The <hal> node is converted into a Python dict."""
- test = self
-
- def _parseDevice(self, node):
- test.assertTrue(isinstance(self, SubmissionParser))
- test.assertEqual(node.tag, 'device')
- return 'parsed device node'
- parser = SubmissionParser(self.log)
- parser._parseDevice = lambda node: _parseDevice(parser, node)
-
- node = etree.fromstring("""
- <hal version="0.5.9.1">
- <device/>
- <device/>
- </hal>
- """)
- result = parser._parseHAL(node)
- self.assertEqual(result,
- {'version': '0.5.9.1',
- 'devices': ['parsed device node',
- 'parsed device node']},
- 'Invalid parsing result for <hal>')
-
- def testProcessors(self):
- """The <processors> node is converted into a Python list.
-
- The list elements represent the <processor> nodes.
- """
- test = self
-
- def _parseProperties(self, node):
- test.assertTrue(isinstance(self, SubmissionParser))
- test.assertEqual(node.tag, 'processor')
- return 'parsed properties'
- parser = SubmissionParser(self.log)
- parser._parseProperties = lambda node: _parseProperties(parser, node)
-
- node = etree.fromstring("""
- <processors>
- <processor id="123" name="0">
- <property/>
- </processor>
- <processor id="124" name="1">
- <property/>
- </processor>
- </processors>
- """)
- result = parser._parseProcessors(node)
- self.assertEqual(result,
- [{'id': 123,
- 'name': '0',
- 'properties': 'parsed properties'},
- {'id': 124,
- 'name': '1',
- 'properties': 'parsed properties'}],
- 'Invalid parsing result for <processors>')
-
- def testAliases(self):
- """The <aliases> node is converted into a Python list.
-
- The list elements represent the <alias> nodes.
- """
- parser = SubmissionParser(self.log)
- node = etree.fromstring("""
- <aliases>
- <alias target="1">
- <vendor>Artec</vendor>
- <model>Ultima 2000</model>
- </alias>
- <alias target="2">
- <vendor>Medion</vendor>
- <model>MD 4394</model>
- </alias>
- </aliases>
- """)
- result = parser._parseAliases(node)
- self.assertEqual(result,
- [{'target': 1,
- 'vendor': 'Artec',
- 'model': 'Ultima 2000'},
- {'target': 2,
- 'vendor': 'Medion',
- 'model': 'MD 4394'}],
- 'Invalid parsing result for <aliases>')
-
- def testUdev(self):
- """The content of the <udev> node is converted into a list of dicts.
- """
- parser = SubmissionParser(self.log)
- node = etree.fromstring("""
-<udev>P: /devices/LNXSYSTM:00
-E: UDEV_LOG=3
-E: DEVPATH=/devices/LNXSYSTM:00
-E: MODALIAS=acpi:LNXSYSTM:
-
-P: /devices/pci0000:00/0000:00:1a.0
-E: UDEV_LOG=3
-E: DEVPATH=/devices/pci0000:00/0000:00:1a.0
-S: char/189:256
-</udev>
-""")
- result = parser._parseUdev(node)
- self.assertEqual(
- [
- {
- 'P': '/devices/LNXSYSTM:00',
- 'E': {
- 'UDEV_LOG': '3',
- 'DEVPATH': '/devices/LNXSYSTM:00',
- 'MODALIAS': 'acpi:LNXSYSTM:',
- },
- 'S': [],
- 'id': 1,
- },
- {
- 'P': '/devices/pci0000:00/0000:00:1a.0',
- 'E': {
- 'UDEV_LOG': '3',
- 'DEVPATH': '/devices/pci0000:00/0000:00:1a.0',
- },
- 'S': ['char/189:256'],
- 'id': 2,
- },
- ],
- result,
- 'Invalid parsing result for <udev>')
-
- def testUdevLineWithoutColon(self):
- """<udev> nodes with lines not in key: value format are rejected."""
- parser = SubmissionParser(self.log)
- parser.submission_key = 'Detect udev lines not in key:value format'
- node = etree.fromstring("""
-<udev>P: /devices/LNXSYSTM:00
-bad line
-</udev>
-""")
- result = parser._parseUdev(node)
- self.assertEqual(
- None, result,
- 'Invalid parsing result for a <udev> node with a line not having '
- 'the key: value format.')
- self.assertErrorMessage(
- parser.submission_key,
- "Line 1 in <udev>: No valid key:value data: 'bad line'")
-
- def testUdevPropertyLineWithoutEqualSign(self):
- """<udev> nodes with lines not in key: value format are rejected."""
- parser = SubmissionParser(self.log)
- parser.submission_key = (
- 'Detect udev property lines not in key=value format')
- node = etree.fromstring("""
-<udev>P: /devices/LNXSYSTM:00
-E: bad property
-</udev>
-""")
- result = parser._parseUdev(node)
- self.assertEqual(
- None, result,
- 'Invalid parsing result for a <udev> node with a property line '
- 'not having the key=value format.')
- self.assertErrorMessage(
- parser.submission_key,
- "Line 1 in <udev>: Property without valid key=value data: "
- "'E: bad property'")
-
- def testUdevDataWithDuplicateKey(self):
- """<udev> nodes with lines not in key: value format are rejected."""
- parser = SubmissionParser(self.log)
- parser.submission_key = 'Detect duplactae attributes in udev data'
- node = etree.fromstring("""
-<udev>P: /devices/LNXSYSTM:00
-W:1
-W:2
-</udev>
-""")
- result = parser._parseUdev(node)
- self.assertEqual(
- [
- {
- 'P': '/devices/LNXSYSTM:00',
- 'E': {},
- 'S': [],
- 'W': '2',
- 'id': 1,
- },
- ],
- result,
- 'Invalid parsing result for a <udev> node with a duplicate '
- 'attribute.')
- self.assertWarningMessage(
- parser.submission_key,
- "Line 2 in <udev>: Duplicate attribute key: 'W:2'")
-
- def testDmi(self):
- """The content of the <udev> node is converted into a dictionary."""
- parser = SubmissionParser(self.log)
- node = etree.fromstring("""<dmi>/sys/class/dmi/id/bios_vendor:LENOVO
-/sys/class/dmi/id/bios_version:7LETB9WW (2.19 )
-/sys/class/dmi/id/sys_vendor:LENOVO
-/sys/class/dmi/id/modalias:dmi:bvnLENOVO:bvr7LETB9WW
-</dmi>""")
- result = parser._parseDmi(node)
- self.assertEqual(
- {
- '/sys/class/dmi/id/bios_vendor': 'LENOVO',
- '/sys/class/dmi/id/bios_version': '7LETB9WW (2.19 )',
- '/sys/class/dmi/id/sys_vendor': 'LENOVO',
- '/sys/class/dmi/id/modalias': 'dmi:bvnLENOVO:bvr7LETB9WW',
- },
- result,
- 'Invalid parsing result for <dmi>.')
-
- def testDmiInvalidData(self):
- """<dmi> nodes with lines not in key:value format are rejected."""
- parser = SubmissionParser(self.log)
- parser.submission_key = 'Invalid DMI data'
- node = etree.fromstring("""<dmi>/sys/class/dmi/id/bios_vendor:LENOVO
-invalid line
-</dmi>""")
- result = parser._parseDmi(node)
- self.assertEqual(
- None, result,
- '<dmi> node with invalid data not deteced.')
- self.assertErrorMessage(
- parser.submission_key,
- "Line 1 in <dmi>: No valid key:value data: 'invalid line'")
-
- def testSysfsAttributes(self):
- """Test of SubmissionParser._parseSysfsAttributes().
-
- The content of the <sys-attributes> node is converted into
- a dictionary.
- """
- parser = SubmissionParser(self.log)
- node = etree.fromstring(dedent("""
- <sysfs-attributes>
- P: /devices/LNXSYSTM:00/LNXPWRBN:00/input/input0
- A: modalias=input:b0019v0000p0001e0000-e0,1,k74
- A: uniq=
- A: phys=LNXPWRBN/button/input0
- A: name=Power Button
-
- P: /devices/LNXSYSTM:00/device:00/PNP0A08:00/device:03
- A: uniq=
- A: phys=/video/input0
- A: name=Video Bus
- </sysfs-attributes>
- """))
- result = parser._parseSysfsAttributes(node)
- self.assertEqual(
- {
- '/devices/LNXSYSTM:00/LNXPWRBN:00/input/input0': {
- 'modalias': 'input:b0019v0000p0001e0000-e0,1,k74',
- 'uniq': '',
- 'phys': 'LNXPWRBN/button/input0',
- 'name': 'Power Button',
- },
- '/devices/LNXSYSTM:00/device:00/PNP0A08:00/device:03': {
- 'uniq': '',
- 'phys': '/video/input0',
- 'name': 'Video Bus',
- },
-
- },
- result,
- 'Invalid parsing result of <sysfs-attributes> node.')
-
- def testSysfsAttributesLineWithoutKeyValueData(self):
- """Test of SubmissionParser._parseSysfsAttributes().
-
- Lines not in key: value format are rejected.
- """
- parser = SubmissionParser(self.log)
- parser.submission_key = (
- 'Detect <sysfs-attributes> lines not in key:value format')
- node = etree.fromstring(dedent("""
- <sysfs-attributes>
- P: /devices/LNXSYSTM:00/LNXPWRBN:00/input/input0
- A: modalias=input:b0019v0000p0001e0000-e0,1,k74
- invalid line
- </sysfs-attributes>
- """))
- result = parser._parseSysfsAttributes(node)
- self.assertEqual(
- None, result,
- 'Invalid parsing result of a <sysfs-attributes> node containing '
- 'a line not in key:value format.')
- self.assertErrorMessage(
- parser.submission_key,
- "Line 3 in <sysfs-attributes>: No valid key:value data: "
- "'invalid line'")
-
- def testSysfsAttributesDuplicatePLine(self):
- """Test of SubmissionParser._parseSysfsAttributes().
-
- A line starting with "P:" must be the first line of a device block.
- """
- parser = SubmissionParser(self.log)
- parser.submission_key = (
- 'Detect <sysfs-attributes> node with duplicate P: line')
- node = etree.fromstring(dedent("""
- <sysfs-attributes>
- P: /devices/LNXSYSTM:00/LNXPWRBN:00/input/input0
- A: modalias=input:b0019v0000p0001e0000-e0,1,k74
- P: /devices/LNXSYSTM:00/LNXPWRBN:00/input/input0
- </sysfs-attributes>
- """))
- result = parser._parseSysfsAttributes(node)
- self.assertEqual(
- None, result,
- 'Invalid parsing result of a <sysfs-attributes> node containing '
- 'a duplicate P: line.')
- self.assertErrorMessage(
- parser.submission_key,
- "Line 3 in <sysfs-attributes>: duplicate 'P' line found: "
- "'P: /devices/LNXSYSTM:00/LNXPWRBN:00/input/input0'")
-
- def testSysfsAttributesNoPLineAtDeviceStart(self):
- """Test of SubmissionParser._parseSysfsAttributes().
-
- The data for a device must start with a "P:" line.
- """
- parser = SubmissionParser(self.log)
- parser.submission_key = (
- 'Detect <sysfs-attributes> node without leading P: line')
- node = etree.fromstring(dedent("""
- <sysfs-attributes>
- A: modalias=input:b0019v0000p0001e0000-e0,1,k74
- </sysfs-attributes>
- """))
- result = parser._parseSysfsAttributes(node)
- self.assertEqual(
- None, result,
- 'Invalid parsing result of a <sysfs-attributes> node where a '
- 'device block does not start with a "P": line.')
- self.assertErrorMessage(
- parser.submission_key,
- "Line 1 in <sysfs-attributes>: Block for a device does not "
- "start with 'P:': "
- "'A: modalias=input:b0019v0000p0001e0000-e0,1,k74'")
-
- def testSysfsAttributesNoAttributeKeyValue(self):
- """Test of SubmissionParser._parseSysfsAttributes().
-
- A line starting with "A:" must be in key=value format.
- """
- parser = SubmissionParser(self.log)
- parser.submission_key = (
- 'Detect <sysfs-attributes> node with A: line not in key=value '
- 'format')
- node = etree.fromstring(dedent("""
- <sysfs-attributes>
- P: /devices/LNXSYSTM:00/LNXPWRBN:00/input/input0
- A: equal sign is missing
- </sysfs-attributes>
- """))
- result = parser._parseSysfsAttributes(node)
- self.assertEqual(
- None, result,
- 'Invalid parsing result of a <sysfs-attributes> node with A: '
- 'line not in key=value format.')
- self.assertErrorMessage(
- parser.submission_key,
- "Line 2 in <sysfs-attributes>: Attribute line does not contain "
- "key=value data: 'A: equal sign is missing'")
-
- def testSysfsAttributesInvalidMainKey(self):
- """Test of SubmissionParser._parseSysfsAttributes().
-
- All lines must start with "P:" or "A:".
- """
- parser = SubmissionParser(self.log)
- parser.submission_key = (
- 'Detect <sysfs-attributes> node with invalid main key.')
- node = etree.fromstring(dedent("""
- <sysfs-attributes>
- P: /devices/LNXSYSTM:00/LNXPWRBN:00/input/input0
- X: an invalid line
- </sysfs-attributes>
- """))
- result = parser._parseSysfsAttributes(node)
- self.assertEqual(
- None, result,
- 'Invalid parsing result of a <sysfs-attributes> node containg '
- 'a line that does not start with "A:" or "P:".')
- self.assertErrorMessage(
- parser.submission_key,
- "Line 2 in <sysfs-attributes>: Unexpected key: "
- "'X: an invalid line'")
-
- class MockSubmissionParserParseHardwareTest(SubmissionParser):
- """A SubmissionParser variant for testing checkCOnsistentData()
-
- All "method substitutes" return a valid result.
- """
-
- def __init__(self, logger=None, record_warnings=True):
- super(self.__class__, self).__init__(logger)
- self.hal_result = 'parsed HAL data'
- self.processors_result = 'parsed processor data'
- self.aliases_result = 'parsed alias data'
- self.udev_result = 'parsed udev data'
- self.dmi_result = 'parsed DMI data'
- self.sysfs_result = 'parsed sysfs data'
-
- def _parseHAL(self, hal_node):
- """See `SubmissionParser`."""
- return self.hal_result
-
- def _parseProcessors(self, processors_node):
- """See `SubmissionParser`."""
- return self.processors_result
-
- def _parseAliases(self, aliases_node):
- """See `SubmissionParser`."""
- return self.aliases_result
-
- def _parseUdev(self, udev_node):
- """See `SubmissionParser`."""
- return self.udev_result
-
- def _parseDmi(self, dmi_node):
- """See `SubmissionParser`."""
- return self.dmi_result
-
- def _parseSysfsAttributes(self, sysfs_node):
- """See `SubmissionParser`."""
- return self.sysfs_result
-
- validate_mock_class(MockSubmissionParserParseHardwareTest)
-
- def testHardware(self):
- """The <hardware> tag is converted into a dictionary."""
- parser = self.MockSubmissionParserParseHardwareTest(self.log)
-
- node = etree.fromstring("""
- <hardware>
- <hal/>
- <processors/>
- <aliases/>
- <udev/>
- <dmi/>
- <sysfs-attributes/>
- </hardware>
- """)
- result = parser._parseHardware(node)
- self.assertEqual({
- 'hal': 'parsed HAL data',
- 'processors': 'parsed processor data',
- 'aliases': 'parsed alias data',
- 'udev': 'parsed udev data',
- 'dmi': 'parsed DMI data',
- 'sysfs-attributes': 'parsed sysfs data',
- },
- result,
- 'Invalid parsing result for <hardware>')
-
- def testHardware_no_sysfs_node(self):
- """If teh <sysfs-attributes> node is missing, parseHardware()
- returns a dicitionary where the entry for this node is None.
- """
- parser = self.MockSubmissionParserParseHardwareTest(self.log)
-
- node = etree.fromstring("""
- <hardware>
- <hal/>
- <processors/>
- <aliases/>
- <udev/>
- <dmi/>
- </hardware>
- """)
- result = parser._parseHardware(node)
- self.assertEqual({
- 'hal': 'parsed HAL data',
- 'processors': 'parsed processor data',
- 'aliases': 'parsed alias data',
- 'udev': 'parsed udev data',
- 'dmi': 'parsed DMI data',
- 'sysfs-attributes': None,
- },
- result,
- 'Invalid parsing result for <hardware>')
-
- def test_parseHardware_sub_parsers_fail(self):
- """Test of SubmissionParser._parseHardware().
-
- If one of the sub-parsers returns None, _parseHardware() returns
- None.
- """
- node = etree.fromstring("""
- <hardware>
- <hal/>
- <processors/>
- <aliases/>
- <udev/>
- <dmi/>
- <sysfs-attributes/>
- </hardware>
- """)
-
- submission_parser = self.MockSubmissionParserParseHardwareTest()
- submission_parser.hal_result = None
- self.assertIs(None, submission_parser._parseHardware(node))
-
- submission_parser = self.MockSubmissionParserParseHardwareTest()
- submission_parser.processors_result = None
- self.assertIs(None, submission_parser._parseHardware(node))
-
- submission_parser = self.MockSubmissionParserParseHardwareTest()
- submission_parser.aliases_result = None
- self.assertIs(None, submission_parser._parseHardware(node))
-
- submission_parser = self.MockSubmissionParserParseHardwareTest()
- submission_parser.udev_result = None
- self.assertIs(None, submission_parser._parseHardware(node))
-
- submission_parser = self.MockSubmissionParserParseHardwareTest()
- submission_parser.dmi_result = None
- self.assertIs(None, submission_parser._parseHardware(node))
-
- submission_parser = self.MockSubmissionParserParseHardwareTest()
- submission_parser.sysfs_result = None
- self.assertIs(None, submission_parser._parseHardware(node))
-
- def testLsbRelease(self):
- """The <lsbrelease> node is converted into a Python dictionary.
-
- Each dict item represents a <property> sub-node.
- """
- node = etree.fromstring("""
- <lsbrelease>
- <property name="release" type="str">
- 7.04
- </property>
- <property name="codename" type="str">
- feisty
- </property>
- <property name="distributor-id" type="str">
- Ubuntu
- </property>
- <property name="description" type="str">
- Ubuntu 7.04
- </property>
- </lsbrelease>
- """)
- parser = SubmissionParser(self.log)
- result = parser._parseLSBRelease(node)
- self.assertEqual(result,
- {'distributor-id': ('Ubuntu', 'str'),
- 'release': ('7.04', 'str'),
- 'codename': ('feisty', 'str'),
- 'description': ('Ubuntu 7.04', 'str')},
- 'Invalid parsing result for <lsbrelease>')
-
- def testPackages(self):
- """The <packages> node is converted into a Python dictionary.
-
- Each dict item represents a <package> sub-node as
- (package_name, package_data), where package_data
- is a dictionary representing the <property> sub-nodes of a
- <package> node.
- """
- node = etree.fromstring("""
- <packages>
- <package name="metacity" id="1">
- <property name="installed_size" type="int">
- 868352
- </property>
- <property name="section" type="str">
- x11
- </property>
- <property name="summary" type="str">
- A lightweight GTK2 based Window Manager
- </property>
- <property name="priority" type="str">
- optional
- </property>
- <property name="source" type="str">
- metacity
- </property>
- <property name="version" type="str">
- 1:2.18.2-0ubuntu1.1
- </property>
- <property name="size" type="int">
- 429128
- </property>
- </package>
- </packages>
- """)
- parser = SubmissionParser(self.log)
- result = parser._parsePackages(node)
- self.assertEqual(result,
- {'metacity':
- {'id': 1,
- 'properties':
- {'installed_size': (868352, 'int'),
- 'priority': ('optional', 'str'),
- 'section': ('x11', 'str'),
- 'size': (429128, 'int'),
- 'source': ('metacity', 'str'),
- 'summary':
- ('A lightweight GTK2 based Window Manager',
- 'str'),
- 'version': ('1:2.18.2-0ubuntu1.1', 'str')}}},
- 'Invalid parsing result for <packages>')
-
- def testDuplicatePackage(self):
- """Two <package> nodes with the same name are rejected."""
- node = etree.fromstring("""
- <packages>
- <package name="foo" id="1">
- <property name="size" type="int">10000</property>
- </package>
- <package name="foo" id="1">
- <property name="size" type="int">10000</property>
- </package>
- </packages>
- """)
- self.assertRaises(ValueError, SubmissionParser()._parsePackages, node)
-
- def testXorg(self):
- """The <xorg> node is converted into a Python dictionary."""
- node = etree.fromstring("""
- <xorg version="1.1">
- <driver name="fglrx" version="1.23"
- class="X.Org Video Driver" device="12"/>
- <driver name="kbd" version="1.2.1"
- class="X.Org XInput driver" device="15"/>
-
- </xorg>
- """)
- parser = SubmissionParser(self.log)
- result = parser._parseXOrg(node)
- self.assertEqual(result,
- {'version': '1.1',
- 'drivers': {'fglrx': {'name': 'fglrx',
- 'version': '1.23',
- 'class': 'X.Org Video Driver',
- 'device': 12},
- 'kbd': {'name': 'kbd',
- 'version': '1.2.1',
- 'class': 'X.Org XInput driver',
- 'device': 15}}},
- 'Invalid parsing result for <xorg>')
-
- def testDuplicateXorgDriver(self):
- """Two <driver> nodes in <xorg> with the same name are rejected."""
- node = etree.fromstring("""
- <xorg>
- <driver name="mouse" class="X.Org XInput driver"/>
- <driver name="mouse" class="X.Org XInput driver"/>
- </xorg>
- """)
- self.assertRaises(ValueError, SubmissionParser()._parseXOrg, node)
-
- def test_parseSoftware(self):
- """Test SubmissionParser._parseSoftware
-
- Ensure that all sub-parsers are properly called.
- """
- parser = SubmissionParserTestParseSoftware(self)
-
- node = etree.fromstring("""
- <software>
- <lsbrelease/>
- <packages/>
- <xorg/>
- </software>
- """)
- result = parser._parseSoftware(node)
- self.assertEqual(result,
- {'lsbrelease': 'parsed lsb release',
- 'packages': 'parsed packages',
- 'xorg': 'parsed xorg'},
- 'Invalid parsing result for <software>')
-
- def test_parseSoftware_without_xorg_node(self):
- """Test SubmissionParser._parseSoftware
-
- Ensure that _parseSoftware creates an entry in its
- result for <xorg> even if the submitted data does not
- contains this node.
- """
- parser = SubmissionParserTestParseSoftwareNoXorgNode(self)
-
- node = etree.fromstring("""
- <software>
- <lsbrelease/>
- <packages/>
- </software>
- """)
- result = parser._parseSoftware(node)
- self.assertEqual(
- result,
- {
- 'lsbrelease': 'parsed lsb release',
- 'packages': 'parsed packages',
- 'xorg': {},
- },
- 'Invalid parsing result for <software> without <xorg> sub-node')
-
- def test_parseSoftware_without_packages_node(self):
- """Test SubmissionParser._parseSoftware
-
- Ensure that _parseSoftware creates an entry in its
- result for <packages> even if the submitted data does not
- contains this node.
- """
- parser = SubmissionParserTestParseSoftwareNoPackagesNode(self)
-
- node = etree.fromstring("""
- <software>
- <lsbrelease/>
- <xorg/>
- </software>
- """)
- result = parser._parseSoftware(node)
- self.assertEqual(
- result,
- {
- 'lsbrelease': 'parsed lsb release',
- 'packages': {},
- 'xorg': 'parsed xorg',
- },
- 'Invalid parsing result for <software> without <packages> '
- 'sub-node')
-
- def testMultipleChoiceQuestion(self):
- """The <questions> node is converted into a Python dictionary."""
- node = etree.fromstring("""
- <questions>
- <question name="detected_network_controllers"
- plugin="find_network_controllers">
- <target id="42">
- <driver>ipw3945</driver>
- </target>
- <target id="43"/>
- <command/>
- <answer type="multiple_choice">pass</answer>
- <answer_choices>
- <value type="str">fail</value>
- <value type="str">pass</value>
- <value type="str">skip</value>
- </answer_choices>
- <comment>
- The WLAN adapter drops the connection very frequently.
- </comment>
- </question>
- </questions>
- """)
- parser = SubmissionParser()
- result = parser._parseQuestions(node)
- self.assertEqual(
- result,
- [{'name': 'detected_network_controllers',
- 'plugin': 'find_network_controllers',
- 'targets': [{'id': 42,
- 'drivers': ['ipw3945']},
- {'id': 43,
- 'drivers': []}],
- 'answer': {'type': 'multiple_choice',
- 'value': 'pass'},
- 'answer_choices': [('fail', 'str'),
- ('pass', 'str'),
- ('skip', 'str')],
- 'comment': 'The WLAN adapter drops the connection very '
- 'frequently.'}],
- 'Invalid parsing result for multiple choice question')
-
- def testMeasurementQuestion(self):
- """The <questions> node is converted into a Python dictionary."""
- node = etree.fromstring("""
- <questions>
- <question name="harddisk_speed"
- plugin="harddisk_speed">
- <target id="87"/>
- <command>hdparm -t /dev/sda</command>
- <answer type="measurement" unit="MB/sec">38.4</answer>
- </question>
- </questions>
- """)
- parser = SubmissionParser()
- result = parser._parseQuestions(node)
- self.assertEqual(
- result,
- [{
- 'name': 'harddisk_speed',
- 'plugin': 'harddisk_speed',
- 'answer': {'type': 'measurement',
- 'value': '38.4',
- 'unit': 'MB/sec'},
- 'targets': [{'drivers': [],
- 'id': 87}],
- 'command': 'hdparm -t /dev/sda'}],
- 'Invalid parsing result for measurement question')
-
- def testContext(self):
- """The content of the <context> node is currently not processed.
-
- Instead, a log warning is issued.
- """
- parser = SubmissionParser(self.log)
- parser.submission_key = 'Test of <context> parsing'
- node = etree.fromstring('<context/>')
- parser._parseContext(node)
- self.assertEqual({}, parser._parseContext(node))
- self.assertWarningMessage(
- parser.submission_key,
- 'Submission contains unprocessed <context> data.')
-
- class MockSubmissionParserMainParserTest(SubmissionParser):
- """A SubmissionParser variant for testing checkCOnsistentData()
-
- All "method substitutes" return a valid result.
- """
-
- def __init__(self, logger=None, record_warnings=True):
- SubmissionParser.__init__(self, logger)
- self.summary_result = 'parsed summary'
- self.hardware_result = 'parsed hardware'
- self.software_result = 'parsed software'
- self.questions_result = 'parsed questions'
- self.context_result = 'parsed context'
-
- def _parseSummary(self, summary_node):
- """See `SubmissionParser`."""
- return self.summary_result
-
- def _parseHardware(self, hardware_node):
- """See `SubmissionParser`."""
- return self.hardware_result
-
- def _parseSoftware(self, software_node):
- """See `SubmissionParser`."""
- return self.software_result
-
- def _parseQuestions(self, questions_node):
- """See `SubmissionParser`."""
- return self.questions_result
-
- def _parseContext(self, context_node):
- """See `SubmissionParser`."""
- return self.context_result
-
- validate_mock_class(MockSubmissionParserMainParserTest)
-
- def testMainParser(self):
- """Test SubmissionParser.parseMainSections
-
- Ensure that all sub-parsers are properly called.
- """
- parser = self.MockSubmissionParserMainParserTest()
-
- node = etree.fromstring("""
- <system>
- <summary/>
- <hardware/>
- <software/>
- <questions/>
- <context/>
- </system>
- """)
-
- expected_data = {
- 'summary': 'parsed summary',
- 'hardware': 'parsed hardware',
- 'software': 'parsed software',
- 'questions': 'parsed questions',
- 'context': 'parsed context',
- }
-
- result = parser.parseMainSections(node)
- self.assertEqual(result, expected_data,
- 'SubmissionParser.parseSubmission returned an unexpected result')
-
- parser = self.MockSubmissionParserMainParserTest()
- parser.summary_result = None
- self.assertIs(None, parser.parseMainSections(node))
-
- parser = self.MockSubmissionParserMainParserTest()
- parser.hardware_result = None
- self.assertIs(None, parser.parseMainSections(node))
-
- parser = self.MockSubmissionParserMainParserTest()
- parser.software_result = None
- self.assertIs(None, parser.parseMainSections(node))
-
- parser = self.MockSubmissionParserMainParserTest()
- parser.questions_result = None
- self.assertIs(None, parser.parseMainSections(node))
-
- parser = self.MockSubmissionParserMainParserTest()
- parser.context_result = None
- self.assertIs(None, parser.parseMainSections(node))
-
- def testSubmissionParser(self):
- """Test the entire parser."""
- sample_data_path = os.path.join(
- config.root, 'lib', 'lp', 'hardwaredb', 'scripts',
- 'tests', 'hardwaretest.xml')
- sample_data = open(sample_data_path, 'rb').read()
- parser = SubmissionParser()
- result = parser.parseSubmission(sample_data, 'parser test 1')
- self.assertNotEqual(result, None,
- 'Valid submission data rejected by '
- 'SubmissionParser.parseSubmission')
-
- # parseSubmission returns None, if the submitted data is not
- # well-formed XML...
- result = parser.parseSubmission(
- sample_data.replace(b'<summary', b'<inconsitent_opening_tag'),
- 'parser test 2')
- self.assertEqual(result, None,
- 'Not-well-formed XML data accepted by '
- 'SubmissionParser.parseSubmission')
-
- # ...or if RelaxNG validation fails...
- result = parser.parseSubmission(
- sample_data.replace(b'<summary', b'<summary foo="bar"'),
- 'parser test 3')
- self.assertEqual(result, None,
- 'XML data that does pass the Relax NG validation '
- 'accepted by SubmissionParser.parseSubmission')
-
- # ...or if the parser detects an inconsistency, like a
- # property set containing two properties with the same name.
- result = parser.parseSubmission(
- sample_data.replace(
- b'<property name="info.parent"',
- b"""<property name="info.parent" type="dbus.String">
- foo
- </property>
- <property name="info.parent"
- """,
- 1),
- 'parser test 4')
- self.assertEqual(result, None,
- 'XML data that does pass the Relax NG validation '
- 'accepted by SubmissionParser.parseSubmission')
-
- def testFindDuplicates(self):
- """Test of SubmissionParser._findDuplicates."""
- # If all_ids is empty before the call of _findDuplicates, all
- # elements of test_ids is copied to all_ids. Since test_ids does
- # not contains duplicates, the return value of _findDuplicates
- # is empty.
- all_ids = set()
- test_ids = [1, 2, 3]
- parser = SubmissionParser()
- result = parser._findDuplicates(all_ids, test_ids)
- self.assertEqual(result, set(),
- '_findDuplicates found duplicates where none exist')
- self.assertEqual(all_ids, set((1, 2, 3)),
- '_findDuplicates did not update all_ids properly'
- 'with unique elements (1, 2, 3)')
-
- # An element that appears both in all_ids and test_ids is included
- # in the return value.
- test_ids = [3, 4]
- result = parser._findDuplicates(all_ids, test_ids)
- self.assertEqual(result, set((3,)),
- '_findDuplicates did not detect an element in '
- 'test_ids which already existed in all_ids')
- self.assertEqual(all_ids, set((1, 2, 3, 4)),
- '_findDuplicates did not update all_ids with '
- 'test_ids (3, 4)')
-
- # If an element exists twice in test_ids, it is detected as a
- # duplicate.
- test_ids = [5, 5]
- result = parser._findDuplicates(all_ids, test_ids)
- self.assertEqual(result, set((5,)),
- '_findDuplicates did not detect a element which '
- 'exists twice in test_ids')
- self.assertEqual(all_ids, set((1, 2, 3, 4, 5)),
- '_findDuplicates did not update all_ids with a '
- 'duplicate element of test_ids')
-
- def testFindDuplicateIDs(self):
- """SubmissionParser.findDuplicateIDs lists duplicate IDS.
-
- The IDs of HAL devices, processors and packages should be
- unique.
- """
- devices = [{'id': 1},
- {'id': 2}]
- processors = [{'id': 3},
- {'id': 4}]
- packages = {'bzr': {'id': 5},
- 'python-dev': {'id': 6}}
- submission = {
- 'hardware': {
- 'hal': {'devices': devices},
- 'processors': processors},
- 'software': {'packages': packages}}
-
- parser = SubmissionParser()
- duplicates = parser.findDuplicateIDs(submission)
- self.assertEqual(
- duplicates, set(),
- 'Duplicate IDs detected, where no duplicates exist.')
-
- for duplicate_entry in ({'id': 1},
- {'id': 3},
- {'id': 5}):
- devices.append(duplicate_entry)
- duplicates = parser.findDuplicateIDs(submission)
- self.assertEqual(
- duplicates, set((duplicate_entry['id'],)),
- 'Duplicate ID %i in HAL devices not detected.'
- % duplicate_entry['id'])
- devices.pop()
-
- processors.append(duplicate_entry)
- duplicates = parser.findDuplicateIDs(submission)
- self.assertEqual(
- duplicates, set((duplicate_entry['id'],)),
- 'Duplicate ID %i in processors not detected.'
- % duplicate_entry['id'])
- processors.pop()
-
- packages['python-xml'] = duplicate_entry
- duplicates = parser.findDuplicateIDs(submission)
- self.assertEqual(
- duplicates, set((duplicate_entry['id'],)),
- 'Duplicate ID %i in packages not detected.'
- % duplicate_entry['id'])
- del packages['python-xml']
-
- def testFindDuplicateIDsUdev(self):
- """SubmissionParser.findDuplicateIDs lists duplicate IDS.
-
- The IDs of udev devices, processors and packages should be
- unique.
- """
- udev = [
- {'P': '/devices/LNXSYSTM:00'},
- {'P': '/devices/LNXSYSTM:00/ACPI_CPU:00'},
- ]
- sysfs_attributes = [
- {'P': '/devices/LNXSYSTM:00'},
- ]
- processors = [
- {'id': 1},
- {'id': 2},
- ]
- packages = {
- 'bzr': {'id': 4},
- 'python-dev': {'id': 6},
- }
- submission = {
- 'hardware': {
- 'udev': udev,
- 'sysfs-attributes': sysfs_attributes,
- 'processors': processors,
- },
- 'software': {
- 'packages': packages
- }
- }
-
- parser = SubmissionParser()
- duplicates = parser.findDuplicateIDs(submission)
- self.assertEqual(
- set(), duplicates,
- 'Duplicate IDs for udev submission detected, where no duplicates '
- 'exist.')
-
- def testFindDuplicateIDsDuplicateUdevNode(self):
- """SubmissionParser.findDuplicateIDs lists duplicate IDS.
-
- Two udev dictionaries with the same device['P'] value are
- invalid.
- """
- udev = [
- {'P': '/devices/LNXSYSTM:00'},
- {'P': '/devices/LNXSYSTM:00'},
- ]
- sysfs_attributes = [
- {'P': '/devices/LNXSYSTM:00'},
- ]
- processors = [
- {'id': 1},
- {'id': 2},
- ]
- packages = {
- 'bzr': {'id': 4},
- 'python-dev': {'id': 6},
- }
- submission = {
- 'hardware': {
- 'udev': udev,
- 'sysfs-attributes': sysfs_attributes,
- 'processors': processors,
- },
- 'software': {
- 'packages': packages
- }
- }
-
- parser = SubmissionParser()
- duplicates = parser.findDuplicateIDs(submission)
- self.assertEqual(
- set(('/devices/LNXSYSTM:00', )), duplicates,
- 'Duplicate udev nodes not detected.')
-
- def testIDMap(self):
- """Test of SubmissionParser._getIDMap."""
- devices = [{'id': 1},
- {'id': 2}]
- processors = [{'id': 3},
- {'id': 4}]
- packages = {'bzr': {'id': 5},
- 'python-dev': {'id': 6}}
- submission = {
- 'hardware': {
- 'hal': {'devices': devices},
- 'processors': processors},
- 'software': {'packages': packages}}
-
- parser = SubmissionParser()
- result = parser._getIDMap(submission)
- self.assertEqual(result,
- {1: devices[0],
- 2: devices[1],
- 3: processors[0],
- 4: processors[1],
- 5: packages['bzr'],
- 6: packages['python-dev']},
- 'Invalid result of SubmissionParser._getIDMap')
-
- def testIDMapUdev(self):
- """Test of SubmissionParser._getIDMap.
-
- Variant for submissions with udev data.
- """
- devices = [
- {'P': '/devices/LNXSYSTM:00'},
- {'P': '/devices/LNXSYSTM:00/ACPI_CPU:00'},
- ]
- processors = [
- {'id': 3},
- {'id': 4},
- ]
- packages = {
- 'bzr': {'id': 5},
- }
- submission = {
- 'hardware': {
- 'udev': devices,
- 'processors': processors,
- },
- 'software': {
- 'packages': packages
- }
- }
-
- parser = SubmissionParser()
- result = parser._getIDMap(submission)
- self.assertEqual(
- {
- '/devices/LNXSYSTM:00': devices[0],
- '/devices/LNXSYSTM:00/ACPI_CPU:00': devices[1],
- 3: processors[0],
- 4: processors[1],
- 5: packages['bzr'],
- },
- result,
- 'Invalid result of SubmissionParser._getIDMap')
-
- def testInvalidIDReferencesUdev(self):
- """Test of SubmissionParser.checkIDReferences.
-
- Variant for submissions containing udev data.
- """
- devices = [{'id': 1},
- {'id': 2}]
- processors = [{'id': 3},
- {'id': 4}]
- packages = {'bzr': {'id': 5},
- 'python-dev': {'id': 6}}
- processors = [{'id': 3},
- {'id': 4}]
- questions = [{'targets': [{'id': 1}]},
- {'targets': [{'id': 2},
- {'id': 3}]}]
- submission = {
- 'hardware': {
- 'hal': {'devices': devices},
- 'processors': processors},
- 'software': {'packages': packages},
- 'questions': questions}
- parser = SubmissionParser()
- invalid_ids = parser.findInvalidIDReferences(submission)
- self.assertEqual(invalid_ids, set(),
- 'Invalid ID references detected where none exist')
-
- questions.append({'targets': [{'id': -1}]})
- invalid_ids = parser.findInvalidIDReferences(submission)
- self.assertEqual(invalid_ids, set([-1]),
- 'Invalid ID reference not detected')
-
- DEVICE_2_UDI = '/org/freedesktop/Hal/devices/acpi_AC'
- DEVICE_3_UDI = '/org/freedesktop/Hal/devices/pci_8086_27c5'
- DEVICE_4_UDI = '/org/freedesktop/Hal/devices/usb_device_0_0_0000_00_1d_7'
- _udi_device_test_data = [
- {'udi': ROOT_UDI,
- 'properties': {}},
- {'udi': DEVICE_2_UDI,
- 'properties': {
- 'info.parent': (ROOT_UDI,
- 'dbus.String')}}]
-
- def testUDIDeviceMap(self):
- """Test the creation of the mapping UDI -> device."""
- SSB_UDI = '/org/freedesktop/Hal/devices/ssb__null_'
- SSB_CHILD_UDI = '/org/freedesktop/Hal/devices/net_00_1a_73_a3_8f_a4_0'
- device1 = {
- 'id': 1,
- 'udi': ROOT_UDI,
- }
- device2 = {
- 'id': 2,
- 'udi': self.DEVICE_2_UDI,
- 'properties': {
- 'info.parent': (ROOT_UDI, 'str'),
- },
- }
- device3 = {
- 'id': 3,
- 'udi': SSB_UDI,
- 'properties': {
- 'info.parent': (ROOT_UDI, 'str'),
- },
- }
- device4 = {
- 'id': 4,
- 'udi': SSB_CHILD_UDI,
- 'properties': {
- 'info.parent': (SSB_UDI, 'str'),
- },
- }
-
- devices = [device1, device2]
-
- parser = SubmissionParser()
- udi_devices = parser.getUDIDeviceMap(devices)
- self.assertEqual(udi_devices,
- {ROOT_UDI: device1,
- self.DEVICE_2_UDI: device2},
- 'Invalid result of SubmissionParser.getUDIDeviceMap')
-
- # Generally, duplicate UDIs raise a ValueError.
- devices.append(device2)
- self.assertRaises(ValueError, parser.getUDIDeviceMap, devices)
-
- # Exceptions are devices with certain UDIs which are known
- # to appear sometimes more than once in HWDB submissions.
- devices = [device1, device2, device3, device4, device3, device4]
- udi_devices = parser.getUDIDeviceMap(devices)
- self.assertEqual(
- udi_devices,
- {
- ROOT_UDI: device1,
- self.DEVICE_2_UDI: device2,
- SSB_UDI: device3,
- SSB_CHILD_UDI: device4,
- },
- 'Unexpected result of processing a device list with duplicate '
- 'SSB UDIs')
- self.assertEqual(
- devices, [device1, device2, device3, device4],
- 'Unexpected list of devices after removing duplicates.')
-
- def testIDUDIMaps(self):
- """Test of SubmissionParser._getIDUDIMaps."""
- device1 = {'id': 1,
- 'udi': ROOT_UDI}
- device2 = {'id': 2,
- 'udi': self.DEVICE_2_UDI}
- devices = [device1, device2]
-
- parser = SubmissionParser()
- id_to_udi, udi_to_id = parser._getIDUDIMaps(devices)
- self.assertEqual(id_to_udi,
- {1: ROOT_UDI,
- 2: self.DEVICE_2_UDI},
- '_getIDUDIMaps returned invalid ID -> UDI map')
- self.assertEqual(udi_to_id,
- {ROOT_UDI: 1,
- self.DEVICE_2_UDI: 2},
- '_getIDUDIMaps returned invalid UDI -> ID map')
-
- def testUDIChildren(self):
- """Test of SubmissionParser.getUDIChildren."""
- device1 = {'id': 1,
- 'udi': ROOT_UDI,
- 'properties': {}}
- device2 = {'id': 2,
- 'udi': self.DEVICE_2_UDI,
- 'properties':
- {'info.parent':
- (ROOT_UDI, 'str')}}
- device3 = {'id': 3,
- 'udi': self.DEVICE_3_UDI,
- 'properties':
- {'info.parent':
- (ROOT_UDI, 'str')}}
- device4 = {'id': 4,
- 'udi': self.DEVICE_4_UDI,
- 'properties':
- {'info.parent':
- (self.DEVICE_2_UDI,
- 'str')}}
- devices = [device1, device2, device3, device4]
-
- parser = SubmissionParser()
- udi_device_map = parser.getUDIDeviceMap(devices)
- udi_children = parser.getUDIChildren(udi_device_map)
- expected_data = {ROOT_UDI: [device2, device3],
- self.DEVICE_2_UDI: [device4]}
-
- # The order of the children lists returned by getUDIChildren
- # depends on the order of dict.items(), hence sort the children
- # lists before comparing them.
- for children in udi_children.values():
- children.sort()
- for children in expected_data.values():
- children.sort()
-
- self.assertEqual(udi_children, expected_data,
- 'Invalid result of SubmissionParser.getUDIChildren')
-
- def testUDIDeviceMapInvalidRootNode(self):
- """The root node of the devices must have a special UDI.
-
- getUDIChildren ensures that the only device without an info.parent
- property has the UDI /org/freedesktop/Hal/devices/computer (ROOT_UDI).
- """
- device1 = {'id': 1,
- 'udi': 'invalid_root_node',
- 'properties': {}}
- device2 = {'id': 2,
- 'udi': self.DEVICE_2_UDI,
- 'properties':
- {'info.parent':
- ('invalid_root_node', 'str')}}
- devices = [device1, device2]
-
- parser = SubmissionParser()
- udi_device_map = parser.getUDIDeviceMap(devices)
- self.assertRaises(ValueError, parser.getUDIChildren, udi_device_map)
-
- def testUDIDeviceMapMissingRootNode(self):
- """If no root node exists, getUDIChildren raises a ValueError."""
- device1 = {'id': 1,
- 'udi': self.DEVICE_2_UDI,
- 'properties':
- {'info.parent':
- (self.DEVICE_3_UDI, 'str')}}
- device2 = {'id': 2,
- 'udi': self.DEVICE_3_UDI,
- 'properties':
- {'info.parent':
- (self.DEVICE_2_UDI, 'str')}}
- devices = [device1, device2]
-
- parser = SubmissionParser()
- udi_device_map = parser.getUDIDeviceMap(devices)
- self.assertRaises(ValueError, parser.getUDIChildren, udi_device_map)
-
- CIRCULAR_UDI_1 = '/org/freedesktop/Hal/devices/nonsense_1'
- CIRCULAR_UDI_2 = '/org/freedesktop/Hal/devices/nonsense_2'
-
- def testParentChildInconsistency(self):
- """Test of SubmissionParser.checkHALDevicesParentChildConsistency."""
- device1 = {'id': 1,
- 'udi': ROOT_UDI,
- 'properties': {}}
- device2 = {'id': 2,
- 'udi': self.DEVICE_2_UDI,
- 'properties':
- {'info.parent':
- (ROOT_UDI, 'str')}}
- circular_device1 = {
- 'id': 3,
- 'udi': self.CIRCULAR_UDI_1,
- 'properties':
- {'info.parent':
- (self.CIRCULAR_UDI_2, 'str')}}
- circular_device2 = {
- 'id': 4,
- 'udi': self.CIRCULAR_UDI_2,
- 'properties':
- {'info.parent':
- (self.CIRCULAR_UDI_1, 'str')}}
- devices = [device1, device2, circular_device1, circular_device2]
- parser = SubmissionParser()
- udi_device_map = parser.getUDIDeviceMap(devices)
- udi_children = parser.getUDIChildren(udi_device_map)
- circular_udis = sorted(parser.checkHALDevicesParentChildConsistency(
- udi_children))
- self.assertEqual(circular_udis,
- [self.CIRCULAR_UDI_1, self.CIRCULAR_UDI_2],
- 'Circular parent/child relationship in UDIs not '
- 'detected')
-
- def testCheckUdevDictsHavePathKey(self):
- """Test of SubmissionParser.checkNodesHavePathKey()"""
- # Each dict for a udev device must have a 'P' key.
- parser = SubmissionParser(self.log)
- devices = [
- {'P': '/devices/LNXSYSTM:00'},
- {'P': '/devices/LNXSYSTM:00/ACPI_CPU:00'},
- ]
- self.assertTrue(parser.checkUdevDictsHavePathKey(devices))
-
- parser = SubmissionParser(self.log)
- parser.submission_key = 'Submission having udev data without "P" key'
- devices = [
- {'P': '/devices/LNXSYSTM:00'},
- {},
- ]
- self.assertFalse(parser.checkUdevDictsHavePathKey(devices))
-
- self.assertErrorMessage(
- parser.submission_key, 'udev node found without a "P" key')
-
- def testCheckUdevPciProperties(self):
- """Test of SubmissionParser.checkUdevPciProperties()."""
- # udev PCI devices must have the properties PCI_CLASS, PCI_ID,
- # PCI_SUBSYS_ID, PCI_SLOT_NAME; other devices must not have
- # these properties.
- parser = SubmissionParser()
- self.assertTrue(parser.checkUdevPciProperties(
- [self.udev_root_device, self.udev_pci_device]))
-
- def testCheckUdevPciPropertiesNonPciDeviceWithPciProperties(self):
- """Test of SubmissionParser.checkUdevPciProperties().
-
- A non-PCI device having PCI properties makes a submission invalid.
- """
- self.udev_root_device['E']['PCI_SLOT_NAME'] = '0000:00:1f.2'
- parser = SubmissionParser(self.log)
- parser.submission_key = 'invalid non-PCI device'
- self.assertFalse(parser.checkUdevPciProperties(
- [self.udev_root_device, self.udev_pci_device]))
- self.assertErrorMessage(
- parser.submission_key,
- "Non-PCI udev device with PCI properties: set([u'PCI_SLOT_NAME']) "
- "u'/devices/LNXSYSTM:00'")
-
- def testCheckUdevPciPropertiesPciDeviceWithoutRequiredProperties(self):
- """Test of SubmissionParser.checkUdevPciProperties().
-
- A PCI device not having a required PCI property makes a submission
- invalid.
- """
- del self.udev_pci_device['E']['PCI_CLASS']
- parser = SubmissionParser(self.log)
- parser.submission_key = 'invalid PCI device'
- self.assertFalse(parser.checkUdevPciProperties(
- [self.udev_root_device, self.udev_pci_device]))
- self.assertErrorMessage(
- parser.submission_key,
- "PCI udev device without required PCI properties: "
- "set(['PCI_CLASS']) u'/devices/pci0000:00/0000:00:1f.2'")
-
- def testCheckUdevPciPropertiesPciDeviceWithNonIntegerPciClass(self):
- """Test of SubmissionParser.checkUdevPciProperties().
-
- A PCI device with a non-integer class value makes a submission
- invalid.
- """
- self.udev_pci_device['E']['PCI_CLASS'] = 'not-an-integer'
- parser = SubmissionParser(self.log)
- parser.submission_key = 'invalid PCI class value'
- self.assertFalse(parser.checkUdevPciProperties(
- [self.udev_root_device, self.udev_pci_device]))
- self.assertErrorMessage(
- parser.submission_key,
- "Invalid udev PCI class: u'not-an-integer' "
- "u'/devices/pci0000:00/0000:00:1f.2'")
-
- def testCheckUdevPciPropertiesPciDeviceWithInvalidPciClassValue(self):
- """Test of SubmissionParser.checkUdevPciProperties().
-
- A PCI device with invalid class data makes a submission
- invalid.
- """
- self.udev_pci_device['E']['PCI_CLASS'] = '1234567'
- parser = SubmissionParser(self.log)
- parser.submission_key = 'too large PCI class value'
- self.assertFalse(parser.checkUdevPciProperties(
- [self.udev_root_device, self.udev_pci_device]))
- self.assertErrorMessage(
- parser.submission_key,
- "Invalid udev PCI class: u'1234567' "
- "u'/devices/pci0000:00/0000:00:1f.2'")
-
- def testCheckUdevPciPropertiesPciDeviceWithInvalidDeviceID(self):
- """Test of SubmissionParser.checkUdevPciProperties().
-
- A PCI device with an invalid device ID makes a submission
- invalid.
- """
- self.udev_pci_device['E']['PCI_ID'] = 'not-an-id'
- parser = SubmissionParser(self.log)
- parser.submission_key = 'invalid PCI ID'
- self.assertFalse(parser.checkUdevPciProperties(
- [self.udev_root_device, self.udev_pci_device]))
- self.assertErrorMessage(
- parser.submission_key,
- "Invalid udev PCI device ID: u'not-an-id' "
- "u'/devices/pci0000:00/0000:00:1f.2'")
-
- def testCheckUdevPciPropertiesPciDeviceWithInvalidSubsystemID(self):
- """Test of SubmissionParser.checkUdevPciProperties().
-
- A PCI device with an invalid subsystem ID makes a submission
- invalid.
- """
- self.udev_pci_device['E']['PCI_SUBSYS_ID'] = 'not-a-subsystem-id'
- parser = SubmissionParser(self.log)
- parser.submission_key = 'invalid PCI subsystem ID'
- self.assertFalse(parser.checkUdevPciProperties(
- [self.udev_root_device, self.udev_pci_device]))
- self.assertErrorMessage(
- parser.submission_key,
- "Invalid udev PCI device ID: u'not-a-subsystem-id' "
- "u'/devices/pci0000:00/0000:00:1f.2'")
-
- def testCheckUdevUsbProperties(self):
- """Test of SubmissionParser.checkUdevUsbProperties().
-
- udev nodes for USB devices must define the three properties
- DEVTYPE, PRODUCT, TYPE or none of them.
- """
- parser = SubmissionParser()
- self.assertTrue(parser.checkUdevUsbProperties(
- [self.udev_root_device, self.udev_usb_device,
- self.udev_usb_interface]))
-
- for property_name in ('DEVTYPE', 'PRODUCT', 'TYPE'):
- del self.udev_usb_device['E'][property_name]
- self.assertTrue(parser.checkUdevUsbProperties(
- [self.udev_root_device, self.udev_usb_device,
- self.udev_usb_interface]))
-
- def testCheckUdevUsbProperties_missing_required_property(self):
- """Test of SubmissionParser.checkUdevUsbProperties().
-
- A USB device where some but not all of the properties DEVTYPE,
- PRODUCT, TYPE are defined makes a submission invalid.
- """
- for property_name in ('DEVTYPE', 'PRODUCT', 'TYPE'):
- saved_property = self.udev_usb_device['E'].pop(property_name)
- parser = SubmissionParser(self.log)
- parser.submission_key = (
- 'USB device without %s property' % property_name)
- self.assertFalse(parser.checkUdevUsbProperties(
- [self.udev_root_device, self.udev_usb_device]))
- self.assertErrorMessage(
- parser.submission_key,
- "USB udev device found without required properties: "
- "set(['%s']) u'/devices/pci0000:00/0000:00:1d.1/usb3/3-2'"
- % property_name)
- self.udev_usb_device['E'][property_name] = saved_property
-
- def testCheckUdevUsbProperties_with_invalid_product_id(self):
- """Test of SubmissionParser.checkUdevUsbProperties().
-
- A USB device with an invalid product ID makes a submission
- invalid.
- """
- self.udev_usb_device['E']['PRODUCT'] = 'not-a-valid-usb-product-id'
- parser = SubmissionParser(self.log)
- parser.submission_key = 'USB device with invalid product ID'
- self.assertFalse(parser.checkUdevUsbProperties(
- [self.udev_root_device, self.udev_usb_device]))
- self.assertErrorMessage(
- parser.submission_key,
- "USB udev device found with invalid product ID: "
- "u'not-a-valid-usb-product-id' "
- "u'/devices/pci0000:00/0000:00:1d.1/usb3/3-2'")
-
- def testCheckUdevUsbProperties_with_invalid_type_data(self):
- """Test of SubmmissionParser.checkUdevUsbProperties().
-
- A USB device with invalid type data makes a submission invalid.
- """
- self.udev_usb_device['E']['TYPE'] = 'no-type'
- parser = SubmissionParser(self.log)
- parser.submission_key = 'USB device with invalid type data'
- self.assertFalse(parser.checkUdevUsbProperties(
- [self.udev_root_device, self.udev_usb_device]))
- self.assertErrorMessage(
- parser.submission_key,
- "USB udev device found with invalid type data: u'no-type' "
- "u'/devices/pci0000:00/0000:00:1d.1/usb3/3-2'")
-
- def testCheckUdevUsbProperties_with_invalid_devtype(self):
- """Test of SubmmissionParser.checkUdevUsbProperties().
-
- A udev USB device must have DEVTYPE set to 'usb_device' or
- 'usb_interface'.
- """
- self.udev_usb_device['E']['DEVTYPE'] = 'nonsense'
- parser = SubmissionParser(self.log)
- parser.submission_key = 'USB device with invalid DEVTYPE'
- self.assertFalse(parser.checkUdevUsbProperties(
- [self.udev_root_device, self.udev_usb_device]))
- self.assertErrorMessage(
- parser.submission_key,
- "USB udev device found with invalid udev type data: u'nonsense' "
- "u'/devices/pci0000:00/0000:00:1d.1/usb3/3-2'")
-
- def testCheckUdevUsbProperties_interface_without_interface_property(self):
- """Test of SubmmissionParser.checkUdevUsbProperties().
-
- A udev USB device for a USB interface have the property INTERFACE.
- """
- del self.udev_usb_interface['E']['INTERFACE']
- parser = SubmissionParser(self.log)
- parser.submission_key = 'USB interface without INTERFACE property'
- self.assertFalse(parser.checkUdevUsbProperties(
- [self.udev_root_device, self.udev_usb_interface]))
- self.assertErrorMessage(
- parser.submission_key,
- "USB interface udev device found without INTERFACE property: "
- "u'/devices/pci0000:00/0000:00:1d.1/usb3/3-2/3-2:1.1'")
-
- def testCheckUdevUsbProperties_interface_invalid_interface_property(self):
- """Test of SubmmissionParser.checkUdevUsbProperties().
-
- The INTERFACE proeprty of A udev USB device for a USB interface
- must have value in the format main_class/sub_class/version
- """
- self.udev_usb_interface['E']['INTERFACE'] = 'nonsense'
- parser = SubmissionParser(self.log)
- parser.submission_key = 'USB interface with invalid INTERFACE data'
- self.assertFalse(parser.checkUdevUsbProperties(
- [self.udev_root_device, self.udev_usb_interface]))
- self.assertErrorMessage(
- parser.submission_key,
- "USB Interface udev device found with invalid INTERFACE "
- "property: u'nonsense' "
- "u'/devices/pci0000:00/0000:00:1d.1/usb3/3-2/3-2:1.1'")
-
- def testCheckUdevScsiProperties(self):
- """Test of SubmissionParser.checkUdevScsiProperties()."""
- parser = SubmissionParser()
- sysfs_data = {
- self.udev_scsi_device['P']: self.sysfs_scsi_device,
- }
- self.assertTrue(
- parser.checkUdevScsiProperties(
- [self.udev_root_device, self.udev_scsi_device], sysfs_data))
-
- def testCheckUdevScsiProperties_data_is_none(self):
- """Test of SubmissionParser.checkUdevScsiProperties().
-
- checkUdevScsiProperties() even if no sysfs properties are
- available.
- """
- parser = SubmissionParser()
- self.assertTrue(
- parser.checkUdevScsiProperties(
- [self.udev_root_device, self.udev_scsi_device], None))
-
- def testCheckUdevScsiProperties_missing_devtype(self):
- """Test of SubmissionParser.checkUdevScsiProperties().
-
- Each udev SCSI node must define the DEVTYPE property.
- """
- del self.udev_scsi_device['E']['DEVTYPE']
- parser = SubmissionParser(self.log)
- parser.submission_key = 'udev SCSI device without DEVTYPE'
- sysfs_data = {
- self.udev_scsi_device['P']: self.sysfs_scsi_device,
- }
- self.assertFalse(
- parser.checkUdevScsiProperties(
- [self.udev_root_device, self.udev_scsi_device], sysfs_data))
- self.assertErrorMessage(
- parser.submission_key,
- "SCSI udev node found without DEVTYPE property: "
- "u'/devices/pci0000:00/0000:00:1f.1/host4/target4:0:0/4:0:0:0'")
-
- def testCheckUdevScsiProperties_no_sysfs_data(self):
- """Test of SubmissionParser.checkUdevScsiProperties().
-
- Each udev SCSI node must have a corresponding sysfs node.
- """
- parser = SubmissionParser(self.log)
- parser.submission_key = 'udev SCSI device without sysfs data'
- sysfs_data = {}
- self.assertFalse(
- parser.checkUdevScsiProperties(
- [self.udev_root_device, self.udev_scsi_device], sysfs_data))
- self.assertErrorMessage(
- parser.submission_key,
- "SCSI udev device node found without related sysfs record: "
- "u'/devices/pci0000:00/0000:00:1f.1/host4/target4:0:0/4:0:0:0'")
-
- def testCheckUdevScsiProperties_missing_sysfs_attributes(self):
- """Test of SubmissionParser.checkUdevScsiProperties().
-
- Each sysfs node for a udev SCSI node must have a the attribues
- vendor, model and type.
- """
- del self.sysfs_scsi_device['model']
- parser = SubmissionParser(self.log)
- parser.submission_key = 'udev SCSI device with incomplete sysfs data'
- sysfs_data = {
- self.udev_scsi_device['P']: self.sysfs_scsi_device,
- }
- self.assertFalse(
- parser.checkUdevScsiProperties(
- [self.udev_root_device, self.udev_scsi_device], sysfs_data))
- self.assertErrorMessage(
- parser.submission_key,
- "SCSI udev device found without required sysfs attributes: "
- "set(['model']) "
- "u'/devices/pci0000:00/0000:00:1f.1/host4/target4:0:0/4:0:0:0'")
-
- class UdevTestSubmissionParser(SubmissionParser):
- """A variant of SubmissionParser that shortcuts udev related tests.
-
- All shortcut methods return True.
- """
- def checkUdevDictsHavePathKey(self, udev_nodes):
- """See `SubmissionParser`."""
- return True
-
- def checkUdevPciProperties(self, udev_data):
- """See `SubmissionParser`."""
- return True
-
- def checkUdevUsbProperties(self, udev_data):
- """See `SubmissionParser`."""
- return True
-
- def checkUdevScsiProperties(self, udev_data, sysfs_data):
- """See `SubmissionParser`."""
- return True
-
- def checkUdevDmiData(self, dmi_data):
- """See `SubmissionParser`."""
- return True
-
- validate_mock_class(UdevTestSubmissionParser)
-
- def testCheckConsistentUdevDeviceData(self):
- """Test of SubmissionParser.checkConsistentUdevDeviceData(),"""
- parser = self.UdevTestSubmissionParser()
- self.assertTrue(parser.checkConsistentUdevDeviceData(
- None, None, None))
-
- def testCheckConsistentUdevDeviceData_invalid_path_data(self):
- """Test of SubmissionParser.checkConsistentUdevDeviceData(),
-
- Detection of invalid path data lets the check fail.
- """
- class SubmissionParserUdevPathCheckFails(
- self.UdevTestSubmissionParser):
- """A SubmissionPaser where checkUdevDictsHavePathKey() fails."""
-
- def checkUdevDictsHavePathKey(self, udev_nodes):
- """See `SubmissionParser`."""
- return False
-
- validate_mock_class(SubmissionParserUdevPathCheckFails)
-
- parser = SubmissionParserUdevPathCheckFails()
- self.assertFalse(parser.checkConsistentUdevDeviceData(
- None, None, None))
-
- def testCheckConsistentUdevDeviceData_invalid_pci_data(self):
- """Test of SubmissionParser.checkConsistentUdevDeviceData(),
-
- Detection of invalid PCI data lets the check fail.
- """
- class SubmissionParserUdevPciCheckFails(
- self.UdevTestSubmissionParser):
- """A SubmissionPaser where checkUdevPciProperties() fails."""
-
- def checkUdevPciProperties(self, udev_data):
- """See `SubmissionParser`."""
- return False
-
- validate_mock_class(SubmissionParserUdevPciCheckFails)
-
- parser = SubmissionParserUdevPciCheckFails()
- self.assertFalse(parser.checkConsistentUdevDeviceData(
- None, None, None))
-
- def testCheckConsistentUdevDeviceData_invalid_usb_data(self):
- """Test of SubmissionParser.checkConsistentUdevDeviceData(),
-
- Detection of invalid USB data lets the check fail.
- """
- class SubmissionParserUdevUsbCheckFails(
- self.UdevTestSubmissionParser):
- """A SubmissionPaser where checkUdevUsbProperties() fails."""
-
- def checkUdevUsbProperties(self, udev_data):
- """See `SubmissionParser`."""
- return False
-
- validate_mock_class(SubmissionParserUdevUsbCheckFails)
-
- parser = SubmissionParserUdevUsbCheckFails()
- self.assertFalse(parser.checkConsistentUdevDeviceData(
- None, None, None))
-
- def testCheckConsistentUdevDeviceData_invalid_scsi_data(self):
- """Test of SubmissionParser.checkConsistentUdevDeviceData(),
-
- Detection of invalid SCSI data lets the check fail.
- """
- class SubmissionParserUdevUsbCheckFails(
- self.UdevTestSubmissionParser):
- """A SubmissionPaser where checkUdevScsiProperties() fails."""
-
- def checkUdevScsiProperties(self, udev_data, sysfs_data):
- """See `SubmissionParser`."""
- return False
-
- validate_mock_class(SubmissionParserUdevUsbCheckFails)
-
- parser = SubmissionParserUdevUsbCheckFails()
- self.assertFalse(parser.checkConsistentUdevDeviceData(
- None, None, None))
-
- def testCheckConsistentUdevDeviceData_invalid_dmi_data(self):
- """Test of SubmissionParser.checkConsistentUdevDeviceData(),
-
- Detection of invalid DMI data lets the check fail.
- """
- class SubmissionParserUdevUsbCheckFails(
- self.UdevTestSubmissionParser):
- """A SubmissionPaser where checkUdevDmiData() fails."""
-
- def checkUdevDmiData(self, dmi_data):
- """See `SubmissionParser`."""
- return False
-
- validate_mock_class(SubmissionParserUdevUsbCheckFails)
-
- parser = SubmissionParserUdevUsbCheckFails()
- self.assertFalse(parser.checkConsistentUdevDeviceData(
- None, None, None))
-
- class MockSubmissionParser(SubmissionParser):
- """A SubmissionParser variant for testing checkCOnsistentData()
-
- All "method substitutes" return a valid result.
- """
-
- def findDuplicateIDs(self, parsed_data):
- return set()
-
- def findInvalidIDReferences(self, parsed_data):
- return set()
-
- def getUDIDeviceMap(self, devices):
- return {}
-
- def getUDIChildren(self, udi_device_map):
- return {}
-
- def checkHALDevicesParentChildConsistency(self, udi_children):
- return []
-
- def checkConsistentUdevDeviceData(
- self, udev_data, sysfs_data, dmi_data):
- return True
-
- validate_mock_class(MockSubmissionParser)
-
- def assertErrorMessage(self, submission_key, log_message):
- """Search for message in the log entries for submission_key.
-
- assertErrorMessage requires that
- (a) a log message starts with "Parsing submisson <submission_key>:"
- (b) the error message passed as the parameter message appears
- in a log string that matches (a)
- (c) result, which is supposed to contain an object representing
- the result of parsing a submission, is None.
- (d) the log level is ERROR.
-
- If all four criteria match, assertErrormessage does not raise any
- exception.
- """
- expected_message = ('Parsing submission %s: %s'
- % (submission_key, log_message))
- for r in self.handler.records:
- if r.levelno != logging.ERROR:
- continue
- candidate = r.getMessage()
- if candidate == expected_message:
- return
- raise AssertionError('No log message found: %s' % expected_message)
-
- def assertWarningMessage(self, submission_key, log_message):
- """Search for message in the log entries for submission_key.
-
- assertErrorMessage requires that
- (a) a log message starts with "Parsing submisson <submission_key>:"
- (b) the error message passed as the parameter message appears
- in a log string that matches (a)
- (c) result, which is supposed to contain an object representing
- the result of parsing a submission, is None.
- (d) the log level is WARNING.
-
- If all four criteria match, assertWarningMessage does not raise any
- exception.
- """
- expected_message = ('Parsing submission %s: %s'
- % (submission_key, log_message))
- for r in self.handler.records:
- if r.levelno != logging.WARNING:
- continue
- candidate = r.getMessage()
- if candidate == expected_message:
- return
- raise AssertionError('No log message found: %s' % expected_message)
-
- def testConsistencyCheck(self):
- """Test of SubmissionParser.checkConsistency."""
- parser = self.MockSubmissionParser()
- result = parser.checkConsistency({'hardware':
- {'hal': {'devices': []}}})
- self.assertEqual(result, True,
- 'checkConsistency failed, but all partial checks '
- 'succeeded')
-
- def testConsistencyCheckValidUdevData(self):
- """Test of SubmissionParser.checkConsistency."""
- parser = self.MockSubmissionParser()
- self.assertTrue(parser.checkConsistency(
- {
- 'hardware': {
- 'udev': None,
- 'sysfs-attributes': None,
- 'dmi': None,
- }
- }
- ))
-
- def testConsistencyCheck_invalid_udev_data(self):
- """Test of SubmissionParser.checkConsistency."""
- class MockSubmissionParserBadUdevDeviceData(
- self.MockSubmissionParser):
- """A parser where checkConsistentUdevDeviceData() fails."""
-
- def checkConsistentUdevDeviceData(self, udev_data, sysfs_data,
- dmi_data):
- return False
-
- validate_mock_class(MockSubmissionParserBadUdevDeviceData)
-
- parser = MockSubmissionParserBadUdevDeviceData()
- self.assertFalse(parser.checkConsistency(
- {
- 'hardware': {
- 'udev': None,
- 'sysfs-attributes': None,
- 'dmi': None,
- }
- }
- ))
-
- def testConsistencyCheckWithDuplicateIDs(self):
- """SubmissionParser.checkConsistency detects duplicate IDs."""
- class MockSubmissionParserDuplicateIds(
- self.MockSubmissionParser):
- """A parser where findDuplicateIDs() fails."""
-
- def findDuplicateIDs(self, parsed_data):
- return set([1])
-
- validate_mock_class(MockSubmissionParserDuplicateIds)
-
- parser = MockSubmissionParserDuplicateIds(self.log)
- parser.submission_key = 'Consistency check detects duplicate IDs'
- result = parser.checkConsistency({'hardware':
- {'hal': {'devices': []}}})
- self.assertEqual(result, False,
- 'checkConsistency did not detect duplicate IDs')
- self.assertErrorMessage('Consistency check detects duplicate IDs',
- 'Duplicate IDs found: set([1])')
-
- def testConsistencyCheckWithInvalidIDReferences(self):
- """SubmissionParser.checkConsistency detects invalid ID references."""
- class MockSubmissionParserInvalidIDReferences(
- self.MockSubmissionParser):
- """A parser where findInvalidIDReferences() fails."""
- def findInvalidIDReferences(self, parsed_data):
- return set([1])
-
- validate_mock_class(MockSubmissionParserInvalidIDReferences)
-
- parser = MockSubmissionParserInvalidIDReferences(self.log)
- parser.submission_key = 'Consistency check detects invalid ID refs'
- result = parser.checkConsistency({'hardware':
- {'hal': {'devices': []}}})
- self.assertEqual(result, False,
- 'checkConsistency did not detect invalid ID refs')
- self.assertErrorMessage('Consistency check detects invalid ID refs',
- 'Invalid ID references found: set([1])')
-
- def testConsistencyCheckWithDuplicateUDI(self):
- """SubmissionParser.checkConsistency detects duplicate UDIs."""
- class MockSubmissionParserUDIDeviceMapFails(
- self.MockSubmissionParser):
- """A parser where getUDIDeviceMap() fails."""
-
- def getUDIDeviceMap(self, devices):
- raise ValueError(
- 'Duplicate UDI: /org/freedesktop/Hal/devices/computer')
-
- validate_mock_class(MockSubmissionParserUDIDeviceMapFails)
-
- parser = MockSubmissionParserUDIDeviceMapFails(self.log)
- parser.submission_key = 'Consistency check detects invalid ID refs'
- result = parser.checkConsistency({'hardware':
- {'hal': {'devices': []}}})
- self.assertEqual(result, False,
- 'checkConsistency did not detect duplicate UDIs')
- self.assertErrorMessage(
- 'Consistency check detects invalid ID refs',
- 'Duplicate UDI: /org/freedesktop/Hal/devices/computer')
-
- def testConsistencyCheckChildUDIWithoutParent(self):
- """SubmissionParser.checkConsistency detects "orphaned" devices."""
- class MockSubmissionParserUDIChildrenFails(
- self.MockSubmissionParser):
- """A parser where getUDIChildren() fails."""
-
- def getUDIChildren(self, udi_device_map):
- raise ValueError('Unknown parent UDI /foo in <device id="3">')
-
- validate_mock_class(MockSubmissionParserUDIChildrenFails)
-
- parser = MockSubmissionParserUDIChildrenFails(self.log)
- parser.submission_key = 'Consistency check detects invalid ID refs'
- result = parser.checkConsistency({'hardware':
- {'hal': {'devices': []}}})
- self.assertEqual(result, False,
- 'checkConsistency did not detect orphaned devices')
- self.assertErrorMessage(
- 'Consistency check detects invalid ID refs',
- 'Unknown parent UDI /foo in <device id="3">')
-
- def testConsistencyCheckCircularParentChildRelation(self):
- """SubmissionParser.checkConsistency detects "orphaned" devices."""
- class MockSubmissionParserHALDevicesParentChildConsistency(
- self.MockSubmissionParser):
- """A parser where checkHALDevicesParentChildConsistency() fails.
- """
-
- def checkHALDevicesParentChildConsistency(self, udi_children):
- return ['/foo', '/bar']
-
- validate_mock_class(
- MockSubmissionParserHALDevicesParentChildConsistency)
-
- parser = MockSubmissionParserHALDevicesParentChildConsistency(
- self.log)
- parser.submission_key = ('Consistency check detects circular '
- 'parent-child relationships')
- result = parser.checkConsistency({'hardware':
- {'hal': {'devices': []}}})
- self.assertEqual(result, False,
- 'checkConsistency did not detect circular parent/'
- 'child relationship')
- self.assertErrorMessage(
- 'Consistency check detects circular parent-child relationships',
- "Found HAL devices with circular parent/child "
- "relationship: [u'/foo', u'/bar']")
diff --git a/lib/lp/hardwaredb/scripts/tests/test_hwdb_submission_processing.py b/lib/lp/hardwaredb/scripts/tests/test_hwdb_submission_processing.py
deleted file mode 100644
index e0961d5..0000000
--- a/lib/lp/hardwaredb/scripts/tests/test_hwdb_submission_processing.py
+++ /dev/null
@@ -1,5373 +0,0 @@
-# Copyright 2009-2011 Canonical Ltd. This software is licensed under the
-# GNU Affero General Public License version 3 (see the file LICENSE).
-
-"""Tests of the HWDB submissions parser."""
-
-from __future__ import absolute_import, print_function, unicode_literals
-
-import bz2
-from copy import deepcopy
-from datetime import datetime
-import io
-import logging
-import os
-
-import pytz
-from zope.component import getUtility
-from zope.testing.loghandler import Handler
-
-from lp.hardwaredb.interfaces.hwdb import (
- HWBus,
- HWSubmissionFormat,
- IHWDeviceDriverLinkSet,
- IHWDeviceSet,
- IHWDriverSet,
- IHWSubmissionDeviceSet,
- IHWSubmissionSet,
- IHWVendorIDSet,
- IHWVendorNameSet,
- )
-from lp.hardwaredb.scripts.hwdbsubmissions import (
- HALDevice,
- PCI_CLASS_BRIDGE,
- PCI_CLASS_SERIALBUS_CONTROLLER,
- PCI_CLASS_STORAGE,
- PCI_SUBCLASS_BRIDGE_CARDBUS,
- PCI_SUBCLASS_BRIDGE_PCI,
- PCI_SUBCLASS_SERIALBUS_USB,
- PCI_SUBCLASS_STORAGE_SATA,
- SubmissionParser,
- UdevDevice,
- )
-from lp.services.config import config
-from lp.testing import (
- TestCase,
- validate_mock_class,
- )
-from lp.testing.dbuser import switch_dbuser
-from lp.testing.layers import (
- BaseLayer,
- LaunchpadZopelessLayer,
- )
-
-
-def evaluate_property(value):
- """Evaluate a property.
-
- This function does nothing in itself; passing it a property evaluates the
- property. But it lets the code express that the evaluation is all that's
- needed, without assigning to an unused variable etc.
- """
- return value
-
-
-class TestCaseHWDB(TestCase):
- """Common base class for HWDB processing tests."""
-
- layer = BaseLayer
-
- PCI_SUBCLASS_STORAGE_SCSI = 0
-
- UDI_COMPUTER = '/org/freedesktop/Hal/devices/computer'
- UDI_SATA_CONTROLLER = '/org/freedesktop/Hal/devices/pci_8086_27c5'
- UDI_SATA_CONTROLLER_SCSI = ('/org/freedesktop/Hal/devices/'
- 'pci_8086_27c5_scsi_host')
- UDI_SATA_DISK = ('org/freedesktop/Hal/devices/'
- 'pci_8086_27c5_scsi_host_scsi_device_lun0')
- UDI_USB_CONTROLLER_PCI_SIDE = '/org/freedesktop/Hal/devices/pci_8086_27cc'
- UDI_USB_CONTROLLER_USB_SIDE = ('/org/freedesktop/Hal/devices/'
- 'usb_device_0_0_0000_00_1d_7')
- UDI_USB_CONTROLLER_USB_SIDE_RAW = ('/org/freedesktop/Hal/devices/'
- 'usb_device_0_0_0000_00_1d_7_usbraw')
- UDI_USB_STORAGE = '/org/freedesktop/Hal/devices/usb_device_1307_163_07'
- UDI_USB_STORAGE_IF0 = ('/org/freedesktop/Hal/devices/'
- 'usb_device_1307_163_07_if0')
- UDI_USB_STORAGE_SCSI_HOST = ('/org/freedesktop/Hal/devices/'
- 'usb_device_1307_163_07_if0scsi_host')
- UDI_USB_STORAGE_SCSI_DEVICE = ('/org/freedesktop/Hal/devices/'
- 'usb_device_1307_163_07_if0'
- 'scsi_host_scsi_device_lun0')
- UDI_USB_HUB = '/org/freedesktop/Hal/devices/usb_device_409_5a_noserial'
- UDI_USB_HUB_IF0 = ('/org/freedesktop/Hal/devices/'
- 'usb_dev_409_5a_noserial_if0')
- UDI_PCI_PCI_BRIDGE = '/org/freedesktop/Hal/devices/pci_8086_2448'
- UDI_PCI_PCCARD_BRIDGE = '/org/freedesktop/Hal/devices/pci_1217_7134'
- UDI_PCCARD_DEVICE = '/org/freedesktop/Hal/devices/pci_9004_6075'
-
- UDI_SCSI_CONTROLLER_PCI_SIDE = (
- '/org/freedesktop/Hal/devices/pci_9004_6075')
- UDI_SCSI_CONTROLLER_SCSI_SIDE = (
- '/org/freedesktop/Hal/devices/pci_9004_6075_scsi_host')
- UDI_SCSI_DISK = '/org/freedesktop/Hal/devices/scsi_disk'
-
- PCI_VENDOR_ID_INTEL = 0x8086
- PCI_VENDOR_ID_ADAPTEC = 0x9004
- PCI_PROD_ID_PCI_PCCARD_BRIDGE = 0x7134
- PCI_PROD_ID_PCCARD_DEVICE = 0x6075
- PCI_PROD_ID_USB_CONTROLLER = 0x27cc
- PCI_PROD_ID_AIC1480 = 0x6075
-
- USB_VENDOR_ID_NEC = 0x0409
- USB_PROD_ID_NEC_HUB = 0x005a
-
- USB_VENDOR_ID_USBEST = 0x1307
- USB_PROD_ID_USBBEST_MEMSTICK = 0x0163
-
- KERNEL_VERSION = '2.6.24-19-generic'
- KERNEL_PACKAGE = 'linux-image-' + KERNEL_VERSION
-
- def setUp(self):
- """Setup the test environment."""
- super(TestCaseHWDB, self).setUp()
- self.log = logging.getLogger('test_hwdb_submission_parser')
- self.log.setLevel(logging.INFO)
- self.handler = Handler(self)
- self.handler.add(self.log.name)
-
- def assertWarningMessage(self, submission_key, log_message):
- """Search for message in the log entries for submission_key.
-
- :raise: AssertionError if no log message exists that starts with
- "Parsing submission <submission_key>:" and that contains
- the text passed as the parameter message.
- """
- expected_message = 'Parsing submission %s: %s' % (
- submission_key, log_message)
-
- for record in self.handler.records:
- if record.levelno != logging.WARNING:
- continue
- candidate = record.getMessage()
- if candidate == expected_message:
- return
- raise AssertionError('No log message found: %s' % expected_message)
-
- def assertErrorMessage(self, submission_key, log_message):
- """Search for log_message in the log entries for submission_key.
-
- :raise: AssertionError if no log message exists that starts with
- "Parsing submission <submission_key>:" and that contains
- the text passed as the parameter message.
- """
- expected_message = 'Parsing submission %s: %s' % (
- submission_key, log_message)
-
- for record in self.handler.records:
- if record.levelno != logging.ERROR:
- continue
- candidate = record.getMessage()
- if candidate == expected_message:
- return
- raise AssertionError('No log message found: %s' % expected_message)
-
-
-class TestHWDBSubmissionProcessing(TestCaseHWDB):
- """Tests for processing of HWDB submissions."""
-
- def test_buildDeviceList(self):
- """Test of SubmissionParser.buildDeviceList()."""
- class MockSubmissionParser(SubmissionParser):
- """A SubmissionParser variant for testing."""
-
- def __init__(self, hal_result, udev_result):
- super(MockSubmissionParser, self).__init__()
- self.hal_result = hal_result
- self.udev_result = udev_result
-
- def buildHalDeviceList(self, parsed_data):
- """See `SubmissionParser`."""
- return self.hal_result
-
- def buildUdevDeviceList(self, parsed_data):
- """See `SubmissionParser`."""
- return self.udev_result
-
- parsed_data_hal = {
- 'hardware': {'hal': None}
- }
-
- parser = MockSubmissionParser(True, True)
- self.assertTrue(parser.buildDeviceList(parsed_data_hal))
-
- parser = MockSubmissionParser(False, True)
- self.assertFalse(parser.buildDeviceList(parsed_data_hal))
-
- parsed_data_udev = {
- 'hardware': {'udev': None}
- }
- parser = MockSubmissionParser(True, True)
- self.assertTrue(parser.buildDeviceList(parsed_data_udev))
-
- parser = MockSubmissionParser(True, False)
- self.assertFalse(parser.buildDeviceList(parsed_data_udev))
-
- def test_buildHalDeviceList(self):
- """Test the creation of list HALDevice instances for a submission."""
- devices = [
- {
- 'id': 1,
- 'udi': self.UDI_COMPUTER,
- 'properties': {},
- },
- {
- 'id': 2,
- 'udi': self.UDI_SATA_CONTROLLER,
- 'properties': {
- 'info.parent': (self.UDI_COMPUTER, 'str')
- },
- },
- ]
- parsed_data = {
- 'hardware': {
- 'hal': {
- 'devices': devices,
- },
- },
- }
- parser = SubmissionParser(self.log)
- parser.buildHalDeviceList(parsed_data)
- self.assertEqual(len(parser.devices), len(devices),
- 'Numbers of devices in parser.devices and in '
- 'sample data are different')
- root_device = parser.devices[self.UDI_COMPUTER]
- self.assertEqual(root_device.id, 1,
- 'Unexpected value of root device ID.')
- self.assertEqual(root_device.udi, self.UDI_COMPUTER,
- 'Unexpected value of root device UDI.')
- self.assertEqual(root_device.properties,
- devices[0]['properties'],
- 'Unexpected properties of root device.')
- child_device = parser.devices[self.UDI_SATA_CONTROLLER]
- self.assertEqual(child_device.id, 2,
- 'Unexpected value of child device ID.')
- self.assertEqual(child_device.udi, self.UDI_SATA_CONTROLLER,
- 'Unexpected value of child device UDI.')
- self.assertEqual(child_device.properties,
- devices[1]['properties'],
- 'Unexpected properties of child device.')
-
- parent = parser.devices[self.UDI_COMPUTER]
- child = parser.devices[self.UDI_SATA_CONTROLLER]
- self.assertEqual(parent.children, [child],
- 'Child missing in parent.children.')
- self.assertEqual(child.parent, parent,
- 'Invalid value of child.parent.')
-
- def makeUdevDeviceParsedData(self, paths, sysfs_data=None):
- """Build test data that can be passed to buildUdevDevice()."""
- def makeUdevDevice(path):
- """Make a trivial UdevInstance with the given device path."""
- return {
- 'P': path,
- 'E': {}
- }
- udev_device_data = [makeUdevDevice(path) for path in paths]
- if sysfs_data is None:
- sysfs_data = {}
- parsed_data = {
- 'hardware': {
- 'udev': udev_device_data,
- 'sysfs-attributes': sysfs_data,
- 'dmi': {'/sys/class/dmi/id/sys_vendor': 'FUJITSU SIEMENS'},
- }
- }
- return parsed_data
-
- def test_buildUdevDeviceList(self):
- """Test the creation of UdevDevice instances for a submission."""
- root_device_path = '/devices/LNXSYSTM:00'
- pci_pci_bridge_path = '/devices/pci0000:00/0000:00:1c.0'
- pci_ethernet_controller_path = (
- '/devices/pci0000:00/0000:00:1c.0/0000:02:00.0')
- pci_usb_controller_path = '/devices/pci0000:00/0000:00:1d.7'
- pci_usb_controller_usb_hub_path = (
- '/devices/pci0000:00/0000:00:1d.7/usb1')
- usb_storage_device_path = '/devices/pci0000:00/0000:00:1d.7/usb1/1-1'
- udev_paths = (
- root_device_path, pci_pci_bridge_path,
- pci_ethernet_controller_path, pci_usb_controller_path,
- pci_usb_controller_usb_hub_path, usb_storage_device_path,
- )
-
- parsed_data = self.makeUdevDeviceParsedData(udev_paths)
- parser = SubmissionParser()
- self.assertTrue(parser.buildUdevDeviceList(parsed_data))
-
- self.assertEqual(len(udev_paths), len(parser.devices))
- for path in udev_paths:
- self.assertEqual(path, parser.devices[path].device_id)
-
- devices = parser.devices
-
- root_device = parser.devices[root_device_path]
- expected_children = set(
- (devices[pci_pci_bridge_path], devices[pci_usb_controller_path]))
- self.assertEqual(expected_children, set(root_device.children))
-
- pci_pci_bridge = devices[pci_pci_bridge_path]
- self.assertEqual(
- [devices[pci_ethernet_controller_path]], pci_pci_bridge.children)
-
- usb_controller = devices[pci_usb_controller_path]
- usb_hub = devices[pci_usb_controller_usb_hub_path]
- self.assertEqual([usb_hub], usb_controller.children)
-
- usb_storage = devices[usb_storage_device_path]
- self.assertEqual([usb_storage], usb_hub.children)
-
- def test_buildUdevDeviceList_root_node_has_dmi_data(self):
- """The root node of a udev submissions has DMI data."""
- root_device_path = '/devices/LNXSYSTM:00'
- pci_pci_bridge_path = '/devices/pci0000:00/0000:00:1c.0'
- udev_paths = (root_device_path, pci_pci_bridge_path)
-
- parsed_data = self.makeUdevDeviceParsedData(udev_paths)
- parser = SubmissionParser()
- parser.buildUdevDeviceList(parsed_data)
-
- self.assertEqual(
- {'/sys/class/dmi/id/sys_vendor': 'FUJITSU SIEMENS'},
- parser.devices[root_device_path].dmi)
-
- self.assertIs(None, parser.devices[pci_pci_bridge_path].dmi)
-
- def test_buildUdevDeviceList_sysfs_data(self):
- """Optional sysfs data is passed to UdevDevice instances."""
- root_device_path = '/devices/LNXSYSTM:00'
- pci_pci_bridge_path = '/devices/pci0000:00/0000:00:1c.0'
- pci_ethernet_controller_path = (
- '/devices/pci0000:00/0000:00:1c.0/0000:02:00.0')
-
- udev_paths = (
- root_device_path, pci_pci_bridge_path,
- pci_ethernet_controller_path)
-
- sysfs_data = {
- pci_pci_bridge_path: 'sysfs-data',
- }
-
- parsed_data = self.makeUdevDeviceParsedData(udev_paths, sysfs_data)
- parser = SubmissionParser()
- parser.buildUdevDeviceList(parsed_data)
-
- self.assertEqual(
- 'sysfs-data', parser.devices[pci_pci_bridge_path].sysfs)
-
- self.assertIs(
- None, parser.devices[pci_ethernet_controller_path].sysfs)
-
- def test_buildUdevDeviceList_no_sysfs_data(self):
- """Sysfs data is not required (maverick and natty submissions)."""
- root_device_path = '/devices/LNXSYSTM:00'
- pci_pci_bridge_path = '/devices/pci0000:00/0000:00:1c.0'
- pci_ethernet_controller_path = (
- '/devices/pci0000:00/0000:00:1c.0/0000:02:00.0')
-
- udev_paths = (
- root_device_path, pci_pci_bridge_path,
- pci_ethernet_controller_path)
-
- sysfs_data = None
-
- parsed_data = self.makeUdevDeviceParsedData(udev_paths, sysfs_data)
- parser = SubmissionParser()
- parser.buildUdevDeviceList(parsed_data)
-
- self.assertIs(
- None, parser.devices[pci_pci_bridge_path].sysfs)
-
- self.assertIs(
- None, parser.devices[pci_ethernet_controller_path].sysfs)
-
- def test_buildUdevDeviceList_invalid_device_path(self):
- """Test the creation of UdevDevice instances for a submission.
-
- All device paths must start with '/devices'. Any other
- device path makes the submission invalid.
- """
- root_device_path = '/devices/LNXSYSTM:00'
- bad_device_path = '/nonsense'
- udev_paths = (root_device_path, bad_device_path)
-
- parsed_data = self.makeUdevDeviceParsedData(udev_paths)
- parser = SubmissionParser(self.log)
- parser.submission_key = 'udev device with invalid path'
- self.assertFalse(parser.buildUdevDeviceList(parsed_data))
- self.assertErrorMessage(
- parser.submission_key, "Invalid device path name: u'/nonsense'")
-
- def test_buildUdevDeviceList_missing_root_device(self):
- """Test the creation of UdevDevice instances for a submission.
-
- Each submission must contain a udev node for the root device.
- """
- pci_pci_bridge_path = '/devices/pci0000:00/0000:00:1c.0'
- udev_paths = (pci_pci_bridge_path, )
-
- parsed_data = self.makeUdevDeviceParsedData(udev_paths)
- parser = SubmissionParser(self.log)
- parser.submission_key = 'no udev root device'
- self.assertFalse(parser.buildUdevDeviceList(parsed_data))
- self.assertErrorMessage(
- parser.submission_key, "No udev root device defined")
-
- def test_kernel_package_name_hal_data(self):
- """Test of SubmissionParser.kernel_package_name.
-
- Regular case.
- """
- parser = SubmissionParser(self.log)
- devices = [
- {
- 'id': 1,
- 'udi': self.UDI_COMPUTER,
- 'properties': {
- 'system.kernel.version': (self.KERNEL_VERSION, 'str'),
- },
- },
- ]
- parser.parsed_data = {
- 'hardware': {
- 'hal': {
- 'devices': devices,
- },
- },
- 'software': {
- 'packages': {
- self.KERNEL_PACKAGE: {},
- },
- },
- }
- parser.buildDeviceList(parser.parsed_data)
- kernel_package = parser.kernel_package_name
- self.assertEqual(
- self.KERNEL_PACKAGE, kernel_package,
- 'Unexpected value of SubmissionParser.kernel_package_name. '
- 'Expected linux-image-2.6.24-19-generic, got %r' % kernel_package)
-
- self.assertEqual(
- 0, len(self.handler.records),
- 'One or more warning messages were logged by '
- 'SubmissionParser.kernel_package_name, where zero was expected.')
-
- def test_kernel_package_hal_data_name_inconsistent(self):
- """Test of SubmissionParser.kernel_package_name.
-
- Test a name inconsistency.
- """
- parser = SubmissionParser(self.log)
- devices = [
- {
- 'id': 1,
- 'udi': self.UDI_COMPUTER,
- 'properties': {
- 'system.kernel.version': (self.KERNEL_VERSION, 'str'),
- },
- },
- ]
- parser.parsed_data = {
- 'hardware': {
- 'hal': {
- 'devices': devices,
- },
- },
- 'software': {
- 'packages': {
- 'linux-image-from-obscure-external-source': {},
- },
- },
- }
- parser.submission_key = 'Test of inconsistent kernel package name'
- parser.buildDeviceList(parser.parsed_data)
- kernel_package = parser.kernel_package_name
- self.assertIs(None, kernel_package)
- self.assertWarningMessage(
- parser.submission_key,
- 'Inconsistent kernel version data: According to HAL the '
- 'kernel is 2.6.24-19-generic, but the submission does not '
- 'know about a kernel package linux-image-2.6.24-19-generic')
- # The warning appears only once per submission, even if the
- # property kernel_package_name is accessed more than once.
- num_warnings = len(self.handler.records)
- evaluate_property(parser.kernel_package_name)
- self.assertEqual(
- num_warnings, len(self.handler.records),
- 'Warning for missing HAL property system.kernel.version '
- 'repeated.')
-
- def test_kernel_package_name_hal_data_no_kernel_version_in_hal_data(self):
- """Test of SubmissionParser.kernel_package_name.
-
- Test without HAL property system.kernel.version.
- """
- parser = SubmissionParser(self.log)
- devices = [
- {
- 'id': 1,
- 'udi': self.UDI_COMPUTER,
- 'properties': {},
- },
- ]
- parser.parsed_data = {
- 'hardware': {
- 'hal': {
- 'devices': devices,
- },
- },
- 'software': {
- 'packages': {
- 'linux-image-from-obscure-external-source': {},
- },
- },
- }
- parser.submission_key = 'Test: missing property system.kernel.version'
- parser.buildDeviceList(parser.parsed_data)
- self.assertIs(None, parser.kernel_package_name)
- self.assertWarningMessage(
- parser.submission_key,
- 'Submission does not provide property system.kernel.version '
- 'for /org/freedesktop/Hal/devices/computer or a summary '
- 'sub-node <kernel-release>.')
- # The warning appears only once per submission, even if the
- # property kernel_package_name is accessed more than once.
- num_warnings = len(self.handler.records)
- evaluate_property(parser.kernel_package_name)
- self.assertEqual(
- num_warnings, len(self.handler.records),
- 'Warning for missing HAL property system.kernel.version '
- 'repeated.')
-
- def test_kernel_package_name_hal_data_no_package_data(self):
- """Test of SubmissionParser.kernel_package_name.
-
- Test without any package data. In this case,
- SubmissionParser.kernel_package_name is the value of the property
- system.kernel.version if the root HAL device. No further checks
- are done.
- """
- parser = SubmissionParser(self.log)
- devices = [
- {
- 'id': 1,
- 'udi': self.UDI_COMPUTER,
- 'properties': {
- 'system.kernel.version': (self.KERNEL_VERSION, 'str'),
- },
- },
- ]
- parser.parsed_data = {
- 'hardware': {
- 'hal': {
- 'devices': devices,
- },
- },
- 'software': {
- 'packages': {},
- },
- }
- parser.submission_key = 'Test: missing property system.kernel.version'
- parser.buildDeviceList(parser.parsed_data)
- kernel_package = parser.kernel_package_name
- self.assertEqual(
- self.KERNEL_PACKAGE, kernel_package,
- 'Unexpected result of SubmissionParser.getKernelPackageName, '
- 'test without any package data. Expected None, got %r'
- % kernel_package)
-
- def test_kernel_package_name_udev_data(self):
- """Test of SubmissionParser.kernel_package_name for udev data.
-
- Variant for udev data, regular case.
- """
- parser = SubmissionParser(self.log)
- parser.parsed_data = {
- 'hardware': {
- 'udev': [
- {'P': '/devices/LNXSYSTM:00'}
- ],
- 'sysfs-attributes': {},
- 'dmi': {},
- },
- 'software': {
- 'packages': {
- self.KERNEL_PACKAGE: {},
- },
- },
- 'summary': {
- 'kernel-release': self.KERNEL_VERSION,
- },
- }
- parser.buildDeviceList(parser.parsed_data)
- kernel_package = parser.kernel_package_name
- self.assertEqual(
- self.KERNEL_PACKAGE, kernel_package,
- 'Unexpected value of SubmissionParser.kernel_package_name. '
- 'Expected linux-image-2.6.24-19-generic, got %r' % kernel_package)
-
- self.assertEqual(
- 0, len(self.handler.records),
- 'One or more warning messages were logged by '
- 'SubmissionParser.kernel_package_name, where zero was expected.')
-
- def test_kernel_package_udev_data_name_inconsistent(self):
- """Test of SubmissionParser.kernel_package_name.
-
- Variant for udev data, name inconsistency.
- """
- parser = SubmissionParser(self.log)
- parser.parsed_data = {
- 'hardware': {
- 'udev': [
- {'P': '/devices/LNXSYSTM:00'}
- ],
- 'sysfs-attributes': {},
- 'dmi': {},
- },
- 'software': {
- 'packages': {
- 'linux-image-from-obscure-external-source': {},
- },
- },
- 'summary': {
- 'kernel-release': self.KERNEL_VERSION,
- },
- }
- parser.submission_key = 'Test of inconsistent kernel package name'
- parser.buildDeviceList(parser.parsed_data)
- kernel_package = parser.kernel_package_name
- self.assertIs(None, kernel_package)
- self.assertWarningMessage(
- parser.submission_key,
- 'Inconsistent kernel version data: According to HAL the '
- 'kernel is 2.6.24-19-generic, but the submission does not '
- 'know about a kernel package linux-image-2.6.24-19-generic')
- # The warning appears only once per submission, even if the
- # property kernel_package_name is accessed more than once.
- num_warnings = len(self.handler.records)
- evaluate_property(parser.kernel_package_name)
- self.assertEqual(
- num_warnings, len(self.handler.records),
- 'Warning for missing HAL property system.kernel.version '
- 'repeated.')
-
- def test_kernel_package_name_udev_data_no_kernel_version_in_summary(self):
- """Test of SubmissionParser.kernel_package_name.
-
- Test without the summary sub-node <kernel-release>.
- """
- parser = SubmissionParser(self.log)
- parser.parsed_data = {
- 'hardware': {
- 'udev': [
- {'P': '/devices/LNXSYSTM:00'}
- ],
- 'sysfs-attributes': {},
- 'dmi': {},
- },
- 'software': {
- 'packages': {
- self.KERNEL_PACKAGE: {},
- },
- },
- 'summary': {},
- }
- parser.submission_key = 'Test: missing property system.kernel.version'
- parser.buildDeviceList(parser.parsed_data)
- self.assertIs(None, parser.kernel_package_name)
- self.assertWarningMessage(
- parser.submission_key,
- 'Submission does not provide property system.kernel.version '
- 'for /org/freedesktop/Hal/devices/computer or a summary '
- 'sub-node <kernel-release>.')
- # The warning appears only once per submission, even if the
- # property kernel_package_name is accessed more than once.
- num_warnings = len(self.handler.records)
- evaluate_property(parser.kernel_package_name)
- self.assertEqual(
- num_warnings, len(self.handler.records),
- 'Warning for missing HAL property system.kernel.version '
- 'repeated.')
-
- def test_kernel_package_name_udev_data_no_package_data(self):
- """Test of SubmissionParser.kernel_package_name.
-
- Variant for udev data, test without any package data. In this case,
- SubmissionParser.kernel_package_name is the value of the property
- system.kernel.version if the root HAL device. No further checks
- are done.
- """
- parser = SubmissionParser(self.log)
- parser.parsed_data = {
- 'hardware': {
- 'udev': [
- {'P': '/devices/LNXSYSTM:00'},
- ],
- 'sysfs-attributes': {},
- 'dmi': {},
- },
- 'software': {
- 'packages': {},
- },
- 'summary': {
- 'kernel-release': self.KERNEL_VERSION,
- },
- }
- parser.submission_key = 'Test: missing property system.kernel.version'
- parser.buildDeviceList(parser.parsed_data)
- kernel_package = parser.kernel_package_name
- self.assertEqual(
- self.KERNEL_PACKAGE, kernel_package,
- 'Unexpected result of SubmissionParser.getKernelPackageName, '
- 'test without any package data. Expected None, got %r'
- % kernel_package)
-
- def testHALDeviceConstructor(self):
- """Test of the HALDevice constructor."""
- properties = {
- 'info.bus': ('scsi', 'str'),
- }
- parser = SubmissionParser(self.log)
- device = HALDevice(1, '/some/udi/path', properties, parser)
-
- self.assertEqual(device.id, 1, 'Unexpected device ID')
- self.assertEqual(device.udi, '/some/udi/path',
- 'Unexpected device UDI.')
- self.assertEqual(device.properties, properties,
- 'Unexpected device properties.')
- self.assertEqual(device.parser, parser,
- 'Unexpected device parser.')
-
- def testHALDeviceGetProperty(self):
- """Test of HALDevice.getProperty."""
- properties = {
- 'info.bus': ('scsi', 'str'),
- }
- parser = SubmissionParser(self.log)
- device = HALDevice(1, '/some/udi/path', properties, parser)
-
- # HALDevice.getProperty returns the value of a HAL property.
- # Note that the property type is _not_ returned
- self.assertEqual(device.getProperty('info.bus'), 'scsi',
- 'Unexpected result of calling HALDevice.getProperty.')
- # If a property of the given name does not exist, None is returned.
- self.assertEqual(device.getProperty('does-not-exist'), None,
- 'Unexpected result of calling HALDevice.getProperty for a '
- 'non-existing property.')
-
- def testHALDeviceParentUDI(self):
- """Test of HALDevice.parent_udi."""
- properties = {
- 'info.bus': ('scsi', 'str'),
- 'info.parent': ('/another/udi', 'str'),
- }
- parser = SubmissionParser(self.log)
- device = HALDevice(1, '/some/udi/path', properties, parser)
- self.assertEqual(device.parent_udi, '/another/udi',
- 'Unexpected value of HALDevice.parent_udi.')
-
- properties = {
- 'info.bus': ('scsi', 'str'),
- }
- parser = SubmissionParser(self.log)
- device = HALDevice(1, '/some/udi/path', properties, parser)
- self.assertEqual(device.parent_udi, None,
- 'Unexpected value of HALDevice.parent_udi, '
- 'when no parent information available.')
-
- def testHALDeviceDeviceId(self):
- """Test of HALDevice.device_id."""
- properties = {}
- parser = SubmissionParser(self.log)
- device = HALDevice(1, '/some/udi/path', properties, parser)
- self.assertEqual(
- '/some/udi/path', device.device_id,
- 'Unexpected value of HALDevice.device_id')
-
- def testHALDevicePciClass(self):
- """Test of HALDevice.pci_class."""
- properties = {
- 'pci.device_class': (1, 'int'),
- }
- parser = SubmissionParser(self.log)
- device = HALDevice(1, '/some/udi/path', properties, parser)
- self.assertEqual(
- 1, device.pci_class,
- 'Unexpected value of HALDevice.pci_class.')
-
- properties = {}
- parser = SubmissionParser(self.log)
- device = HALDevice(1, '/some/udi/path', properties, parser)
- self.assertEqual(
- None, device.pci_class,
- 'Unexpected value of HALDevice.pci_class for Non-PCI device.')
-
- def testHALDevicePciSubClass(self):
- """Test of HALDevice.pci_subclass."""
- properties = {
- 'pci.device_subclass': (1, 'int'),
- }
- parser = SubmissionParser(self.log)
- device = HALDevice(1, '/some/udi/path', properties, parser)
- self.assertEqual(
- 1, device.pci_subclass,
- 'Unexpected value of HALDevice.pci_subclass.')
-
- properties = {}
- parser = SubmissionParser(self.log)
- device = HALDevice(1, '/some/udi/path', properties, parser)
- self.assertEqual(
- None, device.pci_subclass,
- 'Unexpected value of HALDevice.pci_sub_class for Non-PCI device.')
-
- def testHALDeviceUsbVendorId(self):
- """Test of HALDevice.usb_vendor_id."""
- properties = {
- 'usb_device.vendor_id': (1, 'int'),
- }
- parser = SubmissionParser(self.log)
- device = HALDevice(1, '/some/udi/path', properties, parser)
- self.assertEqual(
- 1, device.usb_vendor_id,
- 'Unexpected value of HALDevice.usb_vendor_id.')
-
- properties = {}
- parser = SubmissionParser(self.log)
- device = HALDevice(1, '/some/udi/path', properties, parser)
- self.assertEqual(
- None, device.usb_vendor_id,
- 'Unexpected value of HALDevice.usb_vendor_id for Non-USB device.')
-
- def testHALDeviceUsbProductId(self):
- """Test of HALDevice.usb_product_id."""
- properties = {
- 'usb_device.product_id': (1, 'int'),
- }
- parser = SubmissionParser(self.log)
- device = HALDevice(1, '/some/udi/path', properties, parser)
- self.assertEqual(
- 1, device.usb_product_id,
- 'Unexpected value of HALDevice.usb_product_id.')
-
- properties = {}
- parser = SubmissionParser(self.log)
- device = HALDevice(1, '/some/udi/path', properties, parser)
- self.assertEqual(
- None, device.usb_product_id,
- 'Unexpected value of HALDevice.usb_product_id for Non-USB '
- 'device.')
-
- def testHALDeviceScsiVendor(self):
- """Test of HALDevice.scsi_vendor."""
- properties = {
- 'scsi.vendor': ('SEAGATE', 'string'),
- }
- parser = SubmissionParser(self.log)
- device = HALDevice(1, '/some/udi/path', properties, parser)
- self.assertEqual(
- 'SEAGATE', device.scsi_vendor,
- 'Unexpected value of HALDevice.scsi_vendor.')
-
- properties = {}
- parser = SubmissionParser(self.log)
- device = HALDevice(1, '/some/udi/path', properties, parser)
- self.assertEqual(
- None, device.scsi_vendor,
- 'Unexpected value of HALDevice.scsi_vendor for Non-SCSI device.')
-
- def testHALDeviceScsiModel(self):
- """Test of HALDevice.scsi_model."""
- properties = {
- 'scsi.model': ('ST1234567', 'string'),
- }
- parser = SubmissionParser(self.log)
- device = HALDevice(1, '/some/udi/path', properties, parser)
- self.assertEqual(
- 'ST1234567', device.scsi_model,
- 'Unexpected value of HALDevice.scsi_model.')
-
- properties = {}
- parser = SubmissionParser(self.log)
- device = HALDevice(1, '/some/udi/path', properties, parser)
- self.assertEqual(
- None, device.scsi_model,
- 'Unexpected value of HALDevice.scsi_model for Non-SCSI device.')
-
- def testHALDeviceDriverName(self):
- """Test of HALDevice.driver_name."""
- properties = {
- 'info.linux.driver': ('ahci', 'string'),
- }
- parser = SubmissionParser(self.log)
- device = HALDevice(1, '/some/udi/path', properties, parser)
- self.assertEqual(
- 'ahci', device.driver_name,
- 'Unexpected value of HALDevice.driver_name.')
-
- properties = {}
- parser = SubmissionParser(self.log)
- device = HALDevice(1, '/some/udi/path', properties, parser)
- self.assertEqual(
- None, device.driver_name,
- 'Unexpected value of HALDevice.driver_name for Non-SCSI device.')
-
- def testHalDeviceRawBus(self):
- """test of HALDevice.raw_bus."""
- properties = {
- 'info.bus': ('scsi', 'str'),
- 'info.parent': ('/another/udi', 'str'),
- }
- parser = SubmissionParser(self.log)
- device = HALDevice(1, '/some/udi/path', properties, parser)
- self.assertEqual(device.raw_bus, 'scsi',
- 'Unexpected value of HALDevice.raw_bus for '
- 'HAL property info.bus.')
-
- properties = {
- 'info.subsystem': ('scsi', 'str'),
- 'info.parent': ('/another/udi', 'str'),
- }
- parser = SubmissionParser(self.log)
- device = HALDevice(1, '/some/udi/path', properties, parser)
- self.assertEqual(device.raw_bus, 'scsi',
- 'Unexpected value of HALDevice.raw_bus for '
- 'HAL property info.bus.')
-
- def test_HALDevice_scsi_controller_usb_storage_device(self):
- """test of HALDevice.scsi_controller.
-
- The physical device is a USB storage device.
- """
- devices = [
- # The main node of the USB storage device.
- {
- 'id': 1,
- 'udi': self.UDI_USB_STORAGE,
- 'properties': {
- 'info.bus': ('usb_device', 'str'),
- },
- },
- # The storage interface of the USB device.
- {
- 'id': 2,
- 'udi': self.UDI_USB_STORAGE_IF0,
- 'properties': {
- 'info.bus': ('usb', 'str'),
- 'info.parent': (self.UDI_USB_STORAGE, 'str'),
- },
- },
- # The fake SCSI host of the storage device. Note that HAL does
- # _not_ provide the info.bus property.
- {
- 'id': 3,
- 'udi': self.UDI_USB_STORAGE_SCSI_HOST,
- 'properties': {
- 'info.parent': (self.UDI_USB_STORAGE_IF0, 'str'),
- },
- },
- # The fake SCSI disk.
- {
- 'id': 3,
- 'udi': self.UDI_USB_STORAGE_SCSI_DEVICE,
- 'properties': {
- 'info.bus': ('scsi', 'str'),
- 'info.parent': (self.UDI_USB_STORAGE_SCSI_HOST, 'str'),
- },
- },
- ]
- parsed_data = {
- 'hardware': {
- 'hal': {
- 'devices': devices,
- },
- },
- }
-
- parser = SubmissionParser()
- parser.buildHalDeviceList(parsed_data)
-
- usb_fake_scsi_disk = parser.devices[self.UDI_USB_STORAGE_SCSI_DEVICE]
- usb_main_device = parser.devices[self.UDI_USB_STORAGE_IF0]
- self.assertEqual(usb_main_device, usb_fake_scsi_disk.scsi_controller)
-
- def test_HALDevice_scsi_controller_pci_controller(self):
- """test of HALDevice.scsi_controller.
-
- Variant for a SCSI device connected to a PCI controller.
- """
- devices = [
- # The PCI host controller.
- {
- 'id': 1,
- 'udi': self.UDI_SATA_CONTROLLER,
- 'properties': {
- 'info.bus': ('pci', 'str'),
- 'pci.device_class': (PCI_CLASS_STORAGE, 'int'),
- 'pci.device_subclass': (PCI_SUBCLASS_STORAGE_SATA,
- 'int'),
- },
- },
- # The (fake or real) SCSI host of the storage device.
- {
- 'id': 2,
- 'udi': self.UDI_SATA_CONTROLLER_SCSI,
- 'properties': {
- 'info.parent': (self.UDI_SATA_CONTROLLER, 'str'),
- },
- },
- # The (possibly fake) SCSI disk.
- {
- 'id': 3,
- 'udi': self.UDI_SATA_DISK,
- 'properties': {
- 'info.bus': ('scsi', 'str'),
- 'info.parent': (self.UDI_SATA_CONTROLLER_SCSI, 'str'),
- },
- },
- ]
- parsed_data = {
- 'hardware': {
- 'hal': {
- 'devices': devices,
- },
- },
- }
-
- parser = SubmissionParser()
- parser.buildHalDeviceList(parsed_data)
-
- scsi_device = parser.devices[self.UDI_SATA_DISK]
- controller = parser.devices[self.UDI_SATA_CONTROLLER]
- self.assertEqual(controller, scsi_device.scsi_controller)
-
- def test_HALDevice_scsi_controller_non_scsi_device(self):
- """test of HALDevice.scsi_controller.
-
- Variant for non-SCSI devices.
- """
- devices = [
- {
- 'id': 1,
- 'udi': self.UDI_COMPUTER,
- 'properties': {},
- },
- ]
- parsed_data = {
- 'hardware': {
- 'hal': {
- 'devices': devices,
- },
- },
- }
-
- parser = SubmissionParser()
- parser.buildHalDeviceList(parsed_data)
-
- device = parser.devices[self.UDI_COMPUTER]
- self.assertEqual(None, device.scsi_controller)
-
- def test_HALDevice_scsi_controller_no_grandparent(self):
- """test of HALDevice.scsi_controller.
-
- Variant for a SCSI device without a grandparent device.
- """
- devices = [
- # The (fake or real) SCSI host of the storage device.
- {
- 'id': 1,
- 'udi': self.UDI_SATA_CONTROLLER_SCSI,
- 'properties': {},
- },
- # The (possibly fake) SCSI disk.
- {
- 'id': 2,
- 'udi': self.UDI_SATA_DISK,
- 'properties': {
- 'info.bus': ('scsi', 'str'),
- 'info.parent': (self.UDI_SATA_CONTROLLER_SCSI, 'str'),
- },
- },
- ]
- parsed_data = {
- 'hardware': {
- 'hal': {
- 'devices': devices,
- },
- },
- }
-
- parser = SubmissionParser(self.log)
- parser.submission_key = 'SCSI device without grandparent device'
- parser.buildHalDeviceList(parsed_data)
-
- scsi_device = parser.devices[self.UDI_SATA_DISK]
- self.assertEqual(None, scsi_device.scsi_controller)
- self.assertWarningMessage(
- parser.submission_key,
- "Found SCSI device without a grandparent: %s."
- % self.UDI_SATA_DISK)
-
- def test_HALDevice_scsi_controller_no_parent(self):
- """test of HALDevice.scsi_controller.
-
- Variant for a SCSI device without a parent device.
- """
- devices = [
- # The (possibly fake) SCSI disk.
- {
- 'id': 1,
- 'udi': self.UDI_SATA_DISK,
- 'properties': {
- 'info.bus': ('scsi', 'str'),
- },
- },
- ]
- parsed_data = {
- 'hardware': {
- 'hal': {
- 'devices': devices,
- },
- },
- }
-
- parser = SubmissionParser(self.log)
- parser.submission_key = 'SCSI device without parent device'
- parser.buildHalDeviceList(parsed_data)
-
- scsi_device = parser.devices[self.UDI_SATA_DISK]
- self.assertEqual(None, scsi_device.scsi_controller)
- self.assertWarningMessage(
- parser.submission_key,
- "Found SCSI device without a parent: %s." % self.UDI_SATA_DISK)
-
- def testHALDeviceGetRealBus(self):
- """Test of HALDevice.real_bus, generic case.
-
- For most buses as "seen" by HAL, HALDevice.real_bus returns a
- unique HWBus value.
- """
- for hal_bus, real_bus in (('usb_device', HWBus.USB),
- ('pcmcia', HWBus.PCMCIA),
- ('ide', HWBus.IDE),
- ('serio', HWBus.SERIAL),
- ):
- UDI_TEST_DEVICE = '/org/freedesktop/Hal/devices/test_device'
- devices = [
- {
- 'id': 1,
- 'udi': UDI_TEST_DEVICE,
- 'properties': {
- 'info.bus': (hal_bus, 'str'),
- },
- },
- ]
- parsed_data = {
- 'hardware': {
- 'hal': {
- 'devices': devices,
- },
- },
- }
- parser = SubmissionParser(self.log)
- parser.buildHalDeviceList(parsed_data)
- test_device = parser.devices[UDI_TEST_DEVICE]
- test_bus = test_device.real_bus
- self.assertEqual(test_bus, real_bus,
- 'Unexpected result of HALDevice.real_bus for '
- 'HAL bus %s: %s.' % (hal_bus, test_bus.title))
-
- def testHALDeviceGetRealBusSystem(self):
- """Test of HALDevice.real_bus, for the tested machine itself."""
-
- devices = [
- {
- 'id': 1,
- 'udi': self.UDI_COMPUTER,
- 'properties': {
- 'info.bus': ('unknown', 'str'),
- },
- },
- ]
- parsed_data = {
- 'hardware': {
- 'hal': {
- 'devices': devices,
- },
- },
- }
- parser = SubmissionParser(self.log)
- parser.buildHalDeviceList(parsed_data)
- test_device = parser.devices[self.UDI_COMPUTER]
- test_bus = test_device.real_bus
- self.assertEqual(test_bus, HWBus.SYSTEM,
- 'Unexpected result of HALDevice.real_bus for '
- 'a system: %s' % test_bus.title)
-
- def testHALDeviceGetRealBusScsiUsb(self):
- """Test of HALDevice.real_bus for info.bus=='scsi' and a USB device.
-
- Memory sticks, card readers and USB->IDE/SATA adapters use SCSI
- emulation; HALDevice.real_bus treats these devices as "black boxes",
- and thus returns None.
- """
- devices = [
- # The main node of the USB storage device.
- {
- 'id': 1,
- 'udi': self.UDI_USB_STORAGE,
- 'properties': {
- 'info.bus': ('usb_device', 'str'),
- },
- },
- # The storage interface of the USB device.
- {
- 'id': 2,
- 'udi': self.UDI_USB_STORAGE_IF0,
- 'properties': {
- 'info.bus': ('usb', 'str'),
- 'info.parent': (self.UDI_USB_STORAGE, 'str'),
- },
- },
- # The fake SCSI host of the storage device. Note that HAL does
- # _not_ provide the info.bus property.
- {
- 'id': 3,
- 'udi': self.UDI_USB_STORAGE_SCSI_HOST,
- 'properties': {
- 'info.parent': (self.UDI_USB_STORAGE_IF0, 'str'),
- },
- },
- # The fake SCSI disk.
- {
- 'id': 3,
- 'udi': self.UDI_USB_STORAGE_SCSI_DEVICE,
- 'properties': {
- 'info.bus': ('scsi', 'str'),
- 'info.parent': (self.UDI_USB_STORAGE_SCSI_HOST, 'str'),
- },
- },
- ]
- parsed_data = {
- 'hardware': {
- 'hal': {
- 'devices': devices,
- },
- },
- }
-
- parser = SubmissionParser(self.log)
- parser.buildHalDeviceList(parsed_data)
-
- usb_fake_scsi_disk = parser.devices[self.UDI_USB_STORAGE_SCSI_DEVICE]
- self.assertEqual(usb_fake_scsi_disk.real_bus, None,
- 'Unexpected result of HALDevice.real_bus for the fake SCSI '
- 'disk HAL node of a USB storage device bus.')
-
- def testHALDeviceGetRealBusScsiPci(self):
- """Test of HALDevice.real_bus for info.bus=='scsi'.
-
- Many non-SCSI devices support the SCSI command, and the Linux
- kernel can treat them like SCSI devices. The real bus of these
- devices can be found by looking at the PCI class and subclass
- of the host controller of the possibly fake SCSI device.
- The real bus of these device can be IDE, ATA, SATA or SCSI.
- """
- devices = [
- # The PCI host controller.
- {
- 'id': 1,
- 'udi': self.UDI_SATA_CONTROLLER,
- 'properties': {
- 'info.bus': ('pci', 'str'),
- 'pci.device_class': (PCI_CLASS_STORAGE, 'int'),
- 'pci.device_subclass': (PCI_SUBCLASS_STORAGE_SATA,
- 'int'),
- },
- },
- # The fake SCSI host of the storage device. Note that HAL does
- # _not_ provide the info.bus property.
- {
- 'id': 2,
- 'udi': self.UDI_SATA_CONTROLLER_SCSI,
- 'properties': {
- 'info.parent': (self.UDI_SATA_CONTROLLER, 'str'),
- },
- },
- # The (possibly fake) SCSI disk.
- {
- 'id': 3,
- 'udi': self.UDI_SATA_DISK,
- 'properties': {
- 'info.bus': ('scsi', 'str'),
- 'info.parent': (self.UDI_SATA_CONTROLLER_SCSI, 'str'),
- },
- },
- ]
- parsed_data = {
- 'hardware': {
- 'hal': {
- 'devices': devices,
- },
- },
- }
-
- pci_subclass_bus = (
- (0, HWBus.SCSI),
- (1, HWBus.IDE),
- (2, HWBus.FLOPPY),
- (3, HWBus.IPI),
- (4, None), # subclass RAID is ignored.
- (5, HWBus.ATA),
- (6, HWBus.SATA),
- (7, HWBus.SAS),
- )
-
- parser = SubmissionParser(self.log)
- parser.buildHalDeviceList(parsed_data)
-
- for device_subclass, expected_bus in pci_subclass_bus:
- devices[0]['properties']['pci.device_subclass'] = (
- device_subclass, 'int')
- fake_scsi_disk = parser.devices[self.UDI_SATA_DISK]
- found_bus = fake_scsi_disk.real_bus
- self.assertEqual(found_bus, expected_bus,
- 'Unexpected result of HWDevice.real_bus for PCI storage '
- 'class device, subclass %i: %r.' % (device_subclass,
- found_bus))
-
- def testHALDeviceGetRealBusScsiDeviceWithoutGrandparent(self):
- """Test of HALDevice.real_bus for a device without a grandparent."""
- devices = [
- # A SCSI host conrtoller.
- {
- 'id': 2,
- 'udi': self.UDI_SATA_CONTROLLER_SCSI,
- 'properties': {},
- },
- # A SCSI disk.
- {
- 'id': 3,
- 'udi': self.UDI_SCSI_DISK,
- 'properties': {
- 'info.bus': ('scsi', 'str'),
- 'info.parent': (self.UDI_SATA_CONTROLLER_SCSI, 'str'),
- },
- },
- ]
- parsed_data = {
- 'hardware': {
- 'hal': {
- 'devices': devices,
- },
- },
- }
- parser = SubmissionParser(self.log)
- parser.submission_key = 'Test SCSI disk without a grandparent'
- parser.buildHalDeviceList(parsed_data)
- scsi_disk = parser.devices[self.UDI_SCSI_DISK]
- bus = scsi_disk.real_bus
- self.assertEqual(bus, None,
- 'Unexpected result of HALDevice.real_bus for a SCSI device '
- 'without a grandparent. Expected None, got %r' % bus)
- self.assertWarningMessage(parser.submission_key,
- 'Found SCSI device without a grandparent: %s.'
- % self.UDI_SCSI_DISK)
-
- def testHALDeviceGetRealBusScsiDeviceWithoutParent(self):
- """Test of HALDevice.real_bus for a device without a parent."""
- devices = [
- {
- 'id': 3,
- 'udi': self.UDI_SCSI_DISK,
- 'properties': {
- 'info.bus': ('scsi', 'str'),
- },
- },
- ]
- parsed_data = {
- 'hardware': {
- 'hal': {
- 'devices': devices,
- },
- },
- }
- parser = SubmissionParser(self.log)
- parser.submission_key = 'Test SCSI disk without a parent'
- parser.buildHalDeviceList(parsed_data)
- scsi_disk = parser.devices[self.UDI_SCSI_DISK]
- bus = scsi_disk.real_bus
- self.assertEqual(bus, None,
- 'Unexpected result of HALDevice.real_bus for a SCSI device '
- 'without a parent. Expected None, got %r' % bus)
- self.assertWarningMessage(parser.submission_key,
- 'Found SCSI device without a parent: %s.'
- % self.UDI_SCSI_DISK)
-
- def testHALDeviceGetRealBusScsiDeviceWithBogusPciGrandparent(self):
- """Test of HALDevice.real_bus for a device with a bogus grandparent.
-
- The PCI device class must be PCI_CLASS_STORAGE.
- """
- devices = [
- # The PCI host controller. The PCI device class is invalid.
- {
- 'id': 1,
- 'udi': self.UDI_SATA_CONTROLLER,
- 'properties': {
- 'info.bus': ('pci', 'str'),
- 'pci.device_class': (-1, 'int'),
- 'pci.device_subclass': (PCI_SUBCLASS_STORAGE_SATA, 'int'),
- },
- },
- # The fake SCSI host of the storage device. Note that HAL does
- # _not_ provide the info.bus property.
- {
- 'id': 2,
- 'udi': self.UDI_SATA_CONTROLLER_SCSI,
- 'properties': {
- 'info.parent': (self.UDI_SATA_CONTROLLER, 'str'),
- },
- },
- # The (possibly fake) SCSI disk.
- {
- 'id': 3,
- 'udi': self.UDI_SATA_DISK,
- 'properties': {
- 'info.bus': ('scsi', 'str'),
- 'info.parent': (self.UDI_SATA_CONTROLLER_SCSI, 'str'),
- },
- },
- ]
- parsed_data = {
- 'hardware': {
- 'hal': {
- 'devices': devices,
- },
- },
- }
- parser = SubmissionParser(self.log)
- parser.submission_key = (
- 'Test SCSI disk with invalid controller device class')
- parser.buildHalDeviceList(parsed_data)
- scsi_disk = parser.devices[self.UDI_SATA_DISK]
- bus = scsi_disk.real_bus
- self.assertEqual(bus, None,
- 'Unexpected result of HALDevice.real_bus for a SCSI device '
- 'without a parent. Expected None, got %r' % bus)
- self.assertWarningMessage(parser.submission_key,
- 'A (possibly fake) SCSI device %s is connected to PCI device '
- '%s that has the PCI device class -1; expected class 1 (storage).'
- % (self.UDI_SATA_DISK, self.UDI_SATA_CONTROLLER))
-
- def testHALDeviceGetRealBusPci(self):
- """Test of HALDevice.real_bus for info.bus=='pci'.
-
- If info.bus == 'pci', we may have a real PCI device or a PCCard.
- """
- # possible parent device for the tested device,
- parent_devices = [
- # The host itself.
- {
- 'id': 1,
- 'udi': self.UDI_COMPUTER,
- 'properties': {
- 'info.bus': ('unknown', 'str'),
- },
- },
- # A PCI->PCI bridge.
- {
- 'id': 2,
- 'udi': self.UDI_PCI_PCI_BRIDGE,
- 'properties': {
- 'info.parent': (self.UDI_COMPUTER, 'str'),
- 'info.bus': ('pci', 'str'),
- 'pci.device_class': (PCI_CLASS_BRIDGE, 'int'),
- 'pci.device_subclass': (PCI_SUBCLASS_BRIDGE_PCI, 'int'),
- },
- },
- # A PCI->PCCard bridge.
- {
- 'id': 3,
- 'udi': self.UDI_PCI_PCCARD_BRIDGE,
- 'properties': {
- 'info.parent': (self.UDI_PCI_PCI_BRIDGE, 'str'),
- 'info.bus': ('pci', 'str'),
- 'pci.device_class': (PCI_CLASS_BRIDGE, 'int'),
- 'pci.device_subclass': (PCI_SUBCLASS_BRIDGE_CARDBUS,
- 'int'),
- },
- },
- ]
- tested_device = {
- 'id': 4,
- 'udi': self.UDI_PCCARD_DEVICE,
- 'properties': {
- 'info.bus': ('pci', 'str'),
- },
- }
- parsed_data = {
- 'hardware': {
- 'hal': {},
- },
- }
- expected_result_for_parent_device = {
- self.UDI_COMPUTER: HWBus.PCI,
- self.UDI_PCI_PCI_BRIDGE: HWBus.PCI,
- self.UDI_PCI_PCCARD_BRIDGE: HWBus.PCCARD,
- }
-
- parser = SubmissionParser(self.log)
-
- for parent_device in parent_devices:
- devices = parent_devices[:]
- tested_device['properties']['info.parent'] = (
- parent_device['udi'], 'str')
- devices.append(tested_device)
- parsed_data['hardware']['hal']['devices'] = devices
- parser.buildHalDeviceList(parsed_data)
- tested_hal_device = parser.devices[self.UDI_PCCARD_DEVICE]
- found_bus = tested_hal_device.real_bus
- expected_bus = expected_result_for_parent_device[
- parent_device['udi']]
- self.assertEqual(found_bus, expected_bus,
- 'Unexpected result of HWDevice.real_bus for a '
- 'PCI or PCCard device: Expected %r, got %r.'
- % (expected_bus, found_bus))
-
- def testHALDeviceGetRealBusUnknown(self):
- """Test of HALDevice.real_bus for unknown values of info.bus."""
- devices = [
- {
- 'id': 1,
- 'udi': self.UDI_PCCARD_DEVICE,
- 'properties': {
- 'info.bus': ('nonsense', 'str'),
- },
- },
- ]
- parsed_data = {
- 'hardware': {
- 'hal': {
- 'devices': devices,
- },
- },
- }
-
- parser = SubmissionParser(self.log)
- parser.submission_key = 'Test of unknown bus name'
- parser.buildHalDeviceList(parsed_data)
- found_bus = parser.devices[self.UDI_PCCARD_DEVICE].real_bus
- self.assertEqual(found_bus, None,
- 'Unexpected result of HWDevice.real_bus for an '
- 'unknown bus name: Expected None, got %r.'
- % found_bus)
- self.assertWarningMessage(
- parser.submission_key,
- "Unknown bus u'nonsense' for device " + self.UDI_PCCARD_DEVICE)
-
- def test_HALDevice_is_root_device_for_root_device(self):
- """Test of HALDevice.is_root_device for the root device."""
- devices = [
- {
- 'id': 1,
- 'udi': self.UDI_COMPUTER,
- 'properties': {},
- },
- ]
- parsed_data = {
- 'hardware': {
- 'hal': {
- 'devices': devices,
- },
- },
- }
-
- parser = SubmissionParser()
- parser.submission_key = 'Test of HALDevice.is_root_device'
- parser.buildHalDeviceList(parsed_data)
- self.assertTrue(parser.devices[self.UDI_COMPUTER].is_root_device)
-
- def test_HALDevice_is_root_device_for_non_root_device(self):
- """Test of HALDevice.is_root_device for a non-root device."""
- devices = [
- {
- 'id': 1,
- 'udi': self.UDI_PCCARD_DEVICE,
- 'properties': {},
- },
- ]
- parsed_data = {
- 'hardware': {
- 'hal': {
- 'devices': devices,
- },
- },
- }
-
- parser = SubmissionParser()
- parser.submission_key = 'Test of HALDevice.is_root_device'
- parser.buildHalDeviceList(parsed_data)
- self.assertFalse(
- parser.devices[self.UDI_PCCARD_DEVICE].is_root_device)
-
- def renameInfoBusToInfoSubsystem(self, devices):
- """Rename the property info.bus in a device list to info.subsystem.
-
- Older HAL version store the device bus in the property info.bus;
- newer versions store the bus in info.subsystem.
-
- The parameter devices is a list of dictionaries as used in the
- methods below. This method replaces all dictionary entries with
- the key info.bus by entries with the key info.subsystem in order
- to allow easy testing of both variants.
- """
- for device in devices:
- if 'info.bus' in device['properties']:
- bus = device['properties']['info.bus']
- device['properties']['info.subsystem'] = bus
- del device['properties']['info.bus']
-
- def testHALDeviceRealDeviceRegularBus(self):
- """Test of HALDevice.is_real_device: regular info.bus property.
-
- See below for exceptions, if info.bus == 'usb_device' or if
- info.bus == 'usb'.
- """
- # If a HAL device has the property info.bus, it is considered
- # to be a real device.
- devices = [
- {
- 'id': 1,
- 'udi': self.UDI_USB_CONTROLLER_PCI_SIDE,
- 'properties': {
- 'info.bus': ('pci', 'str'),
- 'pci.device_class': (PCI_CLASS_SERIALBUS_CONTROLLER,
- 'int'),
- 'pci.device_subclass': (PCI_SUBCLASS_SERIALBUS_USB,
- 'int'),
- },
- },
- ]
- parsed_data = {
- 'hardware': {
- 'hal': {
- 'devices': devices,
- },
- },
- }
- parser = SubmissionParser(self.log)
- parser.buildHalDeviceList(parsed_data)
- device = parser.devices[self.UDI_USB_CONTROLLER_PCI_SIDE]
- self.assertTrue(device.is_real_device,
- 'Device with info.bus property not treated as a '
- 'real device.')
- self.renameInfoBusToInfoSubsystem(devices)
- parser.buildHalDeviceList(parsed_data)
- device = parser.devices[self.UDI_USB_CONTROLLER_PCI_SIDE]
- self.assertTrue(device.is_real_device,
- 'Device with info.subsystem property not treated as '
- 'a real device.')
-
- def testHALDeviceRealDeviceNoBus(self):
- """Test of HALDevice.is_real_device: No info.bus property."""
- UDI_HAL_STORAGE_DEVICE = '/org/freedesktop/Hal/devices/storage...'
- devices = [
- {
- 'id': 1,
- 'udi': UDI_HAL_STORAGE_DEVICE,
- 'properties': {},
- },
- ]
- parsed_data = {
- 'hardware': {
- 'hal': {
- 'devices': devices,
- },
- },
- }
-
- parser = SubmissionParser(self.log)
- parser.buildHalDeviceList(parsed_data)
- device = parser.devices[UDI_HAL_STORAGE_DEVICE]
- self.assertFalse(device.is_real_device,
- 'Device without info.bus property treated as a '
- 'real device')
-
- def testHALDeviceRealDeviceHALBusValueIgnored(self):
- """Test of HALDevice.is_real_device: ignored values of info.bus.
-
- A HAL device is considered to not be a real device, if its
- info.bus proerty is 'drm', 'dvb', 'memstick_host', 'net',
- 'scsi_generic', 'scsi_host', 'sound', 'ssb', 'tty', 'usb'
- or 'video4linux'.
- """
- devices = [
- {
- 'id': 1,
- 'udi': self.UDI_USB_HUB_IF0,
- 'properties': {
- 'info.bus': ('usb', 'str'),
- },
- },
- ]
- parsed_data = {
- 'hardware': {
- 'hal': {
- 'devices': devices,
- },
- },
- }
-
- properties = devices[0]['properties']
- parser = SubmissionParser(self.log)
-
- ignored_buses = (
- 'ac97', 'bttv-sub', 'disk', 'drm', 'drm_minor', 'dvb',
- 'enclosure', 'gameport', 'graphics', 'hid', 'host', 'hwmon',
- 'ieee80211', 'link', 'lirc', 'mISDN', 'memstick', 'memstick_host',
- 'net', 'partition', 'pci_express', 'pcmcia_socket', 'pvrusb2',
- 'sas_device', 'sas_end_device', 'sas_host', 'sas_phy', 'sas_port',
- 'scsi_disk', 'scsi_generic', 'scsi_host', 'scsi_tape',
- 'scsi_target', 'sound', 'spi_host', 'spi_transport', 'ssb',
- 'tifm', 'tifm_adapter', 'tty', 'usb', 'usb-serial',
- 'usb_endpoint', 'usb_host', 'usb_interface', 'usbmon',
- 'video4linux', 'wlan')
- for tested_bus in ignored_buses:
- properties['info.bus'] = (tested_bus, 'str')
- parser.buildHalDeviceList(parsed_data)
- device = parser.devices[self.UDI_USB_HUB_IF0]
- self.assertFalse(
- device.is_real_device,
- 'Device with info.bus=%s treated as a real device'
- % tested_bus)
-
- del properties['info.bus']
- for tested_bus in ignored_buses:
- properties['info.subsystem'] = (tested_bus, 'str')
- parser.buildHalDeviceList(parsed_data)
- device = parser.devices[self.UDI_USB_HUB_IF0]
- self.assertFalse(
- device.is_real_device,
- 'Device with info.subsystem=%s treated as a real device'
- % tested_bus)
-
- def runTestHALDeviceRealDeviceScsiDevicesPciController(
- self, devices, bus_property_name):
- """Test of HALDevice.is_real_device: info.bus == 'scsi'.
-
- The (fake or real) SCSI device is connected to a PCI controller.
- Though the real bus may not be SCSI, all devices for the busses
- SCSI, IDE, ATA, SATA, SAS are treated as real devices.
- """
- parsed_data = {
- 'hardware': {
- 'hal': {
- 'devices': devices,
- },
- },
- }
-
- pci_subclass_bus = (
- (0, True), # a real SCSI controller
- (1, True), # an IDE device
- (4, False), # subclass RAID is ignored.
- (5, True), # an ATA device
- (6, True), # a SATA device
- (7, True), # a SAS device
- )
-
- parser = SubmissionParser(self.log)
- parser.buildHalDeviceList(parsed_data)
-
- for device_subclass, expected_is_real in pci_subclass_bus:
- devices[0]['properties']['pci.device_subclass'] = (
- device_subclass, 'int')
- scsi_device = parser.devices[self.UDI_SATA_DISK]
- found_is_real = scsi_device.is_real_device
- self.assertEqual(found_is_real, expected_is_real,
- 'Unexpected result of HWDevice.is_real_device for a HAL SCSI '
- 'connected to PCI controller, subclass %i: %r; testing '
- 'property %s'
- % (device_subclass, found_is_real, bus_property_name))
-
- def testHALDeviceRealDeviceScsiDevicesPciController(self):
- """Test of HALDevice.is_real_device: info.bus == 'scsi'.
-
- The (fake or real) SCSI device is connected to a PCI controller.
- Though the real bus may not be SCSI, all devices for the busses
- SCSI, IDE, ATA, SATA, SAS are treated as real devices.
- """
- devices = [
- # The PCI host controller.
- {
- 'id': 1,
- 'udi': self.UDI_SATA_CONTROLLER,
- 'properties': {
- 'info.bus': ('pci', 'str'),
- 'pci.device_class': (PCI_CLASS_STORAGE, 'int'),
- 'pci.device_subclass': (PCI_SUBCLASS_STORAGE_SATA, 'int'),
- },
- },
- # The (possibly fake) SCSI host of the storage device.
- {
- 'id': 3,
- 'udi': self.UDI_SATA_CONTROLLER_SCSI,
- 'properties': {
- 'info.parent': (self.UDI_SATA_CONTROLLER,
- 'str'),
- },
- },
- # The (possibly fake) SCSI disk.
- {
- 'id': 3,
- 'udi': self.UDI_SATA_DISK,
- 'properties': {
- 'info.bus': ('scsi', 'str'),
- 'info.parent': (self.UDI_SATA_CONTROLLER_SCSI, 'str'),
- },
- },
- ]
-
- self.runTestHALDeviceRealDeviceScsiDevicesPciController(
- devices, 'info.bus')
- self.renameInfoBusToInfoSubsystem(devices)
- self.runTestHALDeviceRealDeviceScsiDevicesPciController(
- devices, 'info.subsystem')
-
- def testHALDeviceRealDeviceScsiDeviceUsbStorage(self):
- """Test of HALDevice.is_real_device: info.bus == 'scsi'.
-
- USB storage devices are treated as SCSI devices by HAL;
- we do not consider them to be real devices.
- """
- devices = [
- # The main node of the USB storage device.
- {
- 'id': 1,
- 'udi': self.UDI_USB_STORAGE,
- 'properties': {
- 'info.bus': ('usb_device', 'str'),
- },
- },
- # The storage interface of the USB device.
- {
- 'id': 2,
- 'udi': self.UDI_USB_STORAGE_IF0,
- 'properties': {
- 'info.bus': ('usb', 'str'),
- 'info.parent': (self.UDI_USB_STORAGE, 'str'),
- },
- },
- # The fake SCSI host of the storage device. Note that HAL does
- # _not_ provide the info.bus property.
- {
- 'id': 3,
- 'udi': self.UDI_USB_STORAGE_SCSI_HOST,
- 'properties': {
- 'info.parent': (self.UDI_USB_STORAGE_IF0, 'str'),
- },
- },
- # The fake SCSI disk.
- {
- 'id': 3,
- 'udi': self.UDI_USB_STORAGE_SCSI_DEVICE,
- 'properties': {
- 'info.bus': ('scsi', 'str'),
- 'info.parent': (self.UDI_USB_STORAGE_SCSI_HOST, 'str'),
- },
- },
- ]
- parsed_data = {
- 'hardware': {
- 'hal': {
- 'devices': devices,
- },
- },
- }
-
- parser = SubmissionParser(self.log)
- parser.buildHalDeviceList(parsed_data)
-
- scsi_device = parser.devices[self.UDI_USB_STORAGE_SCSI_DEVICE]
- self.assertFalse(scsi_device.is_real_device,
- 'Unexpected result of HWDevice.is_real_device for a HAL SCSI '
- 'device as a subdevice of a USB storage device.')
-
- self.renameInfoBusToInfoSubsystem(devices)
- scsi_device = parser.devices[self.UDI_USB_STORAGE_SCSI_DEVICE]
- self.assertFalse(scsi_device.is_real_device,
- 'Unexpected result of HWDevice.is_real_device for a HAL SCSI '
- 'device as a subdevice of a USB storage device.')
-
- def testHALDeviceRealDeviceRootDevice(self):
- """Test of HALDevice.is_real_device for the root node."""
- devices = [
- {
- 'id': 1,
- 'udi': self.UDI_COMPUTER,
- 'properties': {},
- },
- ]
- parsed_data = {
- 'hardware': {
- 'hal': {
- 'devices': devices,
- },
- },
- }
-
- parser = SubmissionParser(self.log)
- parser.buildHalDeviceList(parsed_data)
- device = parser.devices[self.UDI_COMPUTER]
- self.assertTrue(device.is_real_device,
- 'Root device not treated as a real device')
-
- def testHALDeviceRealChildren(self):
- """Test of HALDevice.getRealChildren."""
- # An excerpt of a real world HAL device tree. We have three "real"
- # devices, and two "unreal" devices (ID 3 and 4)
- #
- # the host itself. Treated as a real device.
- devices = [
- {
- 'id': 1,
- 'udi': self.UDI_COMPUTER,
- 'properties': {}
- },
- # A PCI->USB bridge.
- {
- 'id': 2,
- 'udi': self.UDI_USB_CONTROLLER_PCI_SIDE,
- 'properties': {
- 'info.parent': (self.UDI_COMPUTER, 'str'),
- 'info.bus': ('pci', 'str'),
- 'pci.device_class': (PCI_CLASS_SERIALBUS_CONTROLLER,
- 'int'),
- 'pci.device_subclass': (PCI_SUBCLASS_SERIALBUS_USB,
- 'int'),
- }
- },
- # The "output aspect" of the PCI->USB bridge. Not a real
- # device.
- {
- 'id': 3,
- 'udi': self.UDI_USB_CONTROLLER_USB_SIDE,
- 'properties': {
- 'info.parent': (self.UDI_USB_CONTROLLER_PCI_SIDE, 'str'),
- 'info.bus': ('usb_device', 'str'),
- 'usb_device.vendor_id': (0, 'int'),
- 'usb_device.product_id': (0, 'int'),
- },
- },
- # The HAL node for raw USB data access of the bridge. Not a
- # real device.
- {
- 'id': 4,
- 'udi': self.UDI_USB_CONTROLLER_USB_SIDE_RAW,
- 'properties': {
- 'info.parent': (self.UDI_USB_CONTROLLER_USB_SIDE, 'str'),
- },
- },
- # The HAL node of a USB device connected to the bridge.
- {
- 'id': 5,
- 'udi': self.UDI_USB_HUB,
- 'properties': {
- 'info.parent': (self.UDI_USB_CONTROLLER_USB_SIDE, 'str'),
- 'info.bus': ('usb_device', 'str'),
- 'usb_device.vendor_id': (self.USB_VENDOR_ID_NEC, 'int'),
- 'usb_device.product_id': (self.USB_PROD_ID_NEC_HUB,
- 'int'),
- },
- },
- ]
- parsed_data = {
- 'hardware': {
- 'hal': {
- 'devices': devices,
- },
- },
- }
-
- parser = SubmissionParser(self.log)
- parser.buildHalDeviceList(parsed_data)
-
- # The PCI-USB bridge is a child of the system.
- root_device = parser.devices[self.UDI_COMPUTER]
- pci_usb_bridge = parser.devices[self.UDI_USB_CONTROLLER_PCI_SIDE]
- self.assertEqual(root_device.getRealChildren(), [pci_usb_bridge],
- 'Unexpected list of real children of the root '
- 'device')
-
- # The "output aspect" of the PCI->USB bridge and the node for
- # raw USB access do not appear as childs of the PCI->USB bridge,
- # but the node for the USB device is considered to be a child
- # of the bridge.
-
- usb_device = parser.devices[self.UDI_USB_HUB]
- self.assertEqual(pci_usb_bridge.getRealChildren(), [usb_device],
- 'Unexpected list of real children of the PCI-> '
- 'USB bridge')
-
- def testHasReliableDataRegularCase(self):
- """Test of HALDevice.has_reliable_data, regular case."""
- devices = [
- {
- 'id': 1,
- 'udi': self.UDI_COMPUTER,
- 'properties': {}
- },
- {
- 'id': 2,
- 'udi': self.UDI_SATA_CONTROLLER,
- 'properties': {
- 'info.parent': (self.UDI_COMPUTER, 'str'),
- 'info.bus': ('pci', 'str'),
- 'pci.vendor_id': (self.PCI_VENDOR_ID_INTEL, 'int'),
- 'pci.product_id': (self.PCI_PROD_ID_PCI_PCCARD_BRIDGE,
- 'int'),
- 'info.product': ('Intel PCCard bridge 1234', 'str'),
- },
- },
- ]
- parsed_data = {
- 'hardware': {
- 'hal': {
- 'devices': devices,
- },
- },
- }
- parser = SubmissionParser(self.log)
- parser.buildHalDeviceList(parsed_data)
- device = parser.devices[self.UDI_SATA_CONTROLLER]
- self.assertTrue(
- device.has_reliable_data,
- 'Regular device treated as not having reliable data.')
-
- def testHasReliableDataNotProcessible(self):
- """Test of HALDevice.has_reliable_data, bus without reliable data."""
- devices = [
- {
- 'id': 1,
- 'udi': self.UDI_SATA_CONTROLLER,
- 'properties': {},
- },
- ]
- parsed_data = {
- 'hardware': {
- 'hal': {
- 'devices': devices,
- },
- },
- }
- parser = SubmissionParser(self.log)
- properties = devices[0]['properties']
- for bus in ('asus_oled', 'atm', 'backlight', 'bdi', 'bluetooth',
- 'cardman_4040', 'dahdi', 'dmi', 'heci', 'hidraw',
- 'hwmon', 'i2c-adapter', 'ieee1394', 'ieee1394_protocol',
- 'input', 'leds', 'mem', 'misc', 'mmc', 'mmc_host', 'msr',
- 'pci_bus', 'pcmcia', 'pktcdvd', 'platform', 'pnp',
- 'power_supply', 'ppdev', 'ppp', 'printer', 'rfkill',
- 'thermal', 'ttm', 'vc', 'video_output', 'vtconsole'):
- properties['info.bus'] = (bus, 'str')
- parser.buildHalDeviceList(parsed_data)
- device = parser.devices[self.UDI_SATA_CONTROLLER]
- self.assertFalse(device.has_reliable_data,
- 'Device with bus=%s treated as having reliable data.' % bus)
-
- def testHasReliableDataRootDevice(self):
- """Test of HALDevice.has_reliable_data, root device.
-
- The root device has the info.subsystem or info.bus property set
- to 'unknown'. While we treat other devices with ths bus value
- as useless, the root device is real.
- """
- devices = [
- {
- 'id': 1,
- 'udi': self.UDI_COMPUTER,
- 'properties': {
- 'info.subsystem': ('unknown', 'str'),
- 'system.hardware.vendor': ('FUJITSU SIEMENS', 'str'),
- 'system.hardware.product': ('LIFEBOOK E8210', 'str'),
- },
- },
- ]
- parsed_data = {
- 'hardware': {
- 'hal': {
- 'devices': devices,
- },
- },
- }
- parser = SubmissionParser(self.log)
- parser.buildHalDeviceList(parsed_data)
- device = parser.devices[self.UDI_COMPUTER]
- self.assertTrue(
- device.has_reliable_data,
- "Root device not treated as having reliable data.")
-
- def testHasReliableDataForInsuffientData(self):
- """Test of HALDevice.has_reliable_data, insufficent device data.
-
- Test for a HAL device that should be processible but does
- not provide enough data. Aside from a bus, we need a vendor ID,
- a product ID and a product name.
- """
- devices = [
- {
- 'id': 1,
- 'udi': self.UDI_COMPUTER,
- 'properties': {}
- },
- {
- 'id': 2,
- 'udi': self.UDI_SATA_CONTROLLER,
- 'properties': {
- 'info.parent': (self.UDI_COMPUTER, 'str'),
- 'info.bus': ('pci', 'str'),
- 'pci.vendor_id': (self.PCI_VENDOR_ID_INTEL, 'int'),
- 'pci.product_id': (self.PCI_PROD_ID_PCI_PCCARD_BRIDGE,
- 'int'),
- 'info.product': ('Intel PCCard bridge 1234', 'str'),
- },
- },
- ]
- parsed_data = {
- 'hardware': {
- 'hal': {
- 'devices': devices,
- },
- },
- }
-
- missing_data_log_message = (
- ('pci.vendor_id',
- "A HALDevice that is supposed to be a real device does not "
- "provide bus, vendor ID, product ID or product name: <DBItem "
- "HWBus.PCI, (1) PCI> None 28980 u'Intel PCCard bridge 1234' "
- "/org/freedesktop/Hal/devices/pci_8086_27c5"
- ),
- ('pci.product_id',
- "A HALDevice that is supposed to be a real device does not "
- "provide bus, vendor ID, product ID or product name: "
- "<DBItem HWBus.PCI, (1) PCI> 32902 None u'Intel PCCard bridge "
- "1234' /org/freedesktop/Hal/devices/pci_8086_27c5"
- ),
- ('info.product',
- "A HALDevice that is supposed to be a real device does not "
- "provide bus, vendor ID, product ID or product name: "
- "<DBItem HWBus.PCI, (1) PCI> 32902 28980 None "
- "/org/freedesktop/Hal/devices/pci_8086_27c5"
- ),
- )
-
- for (missing_data, expected_log_message) in missing_data_log_message:
- test_parsed_data = deepcopy(parsed_data)
- test_device = test_parsed_data['hardware']['hal']['devices'][1]
- del test_device['properties'][missing_data]
-
- parser = SubmissionParser(self.log)
- submission_key = 'test_missing_%s' % missing_data
- parser.submission_key = submission_key
- parser.buildHalDeviceList(test_parsed_data)
- device = parser.devices[self.UDI_SATA_CONTROLLER]
- self.assertFalse(
- device.has_reliable_data,
- 'Device with missing property %s treated as having reliable'
- 'data.' % missing_data)
- self.assertWarningMessage(submission_key, expected_log_message)
-
- def testHasReliableDataIDEDevice(self):
- """Test of HALDevice.has_reliable_data, for IDE devices.
-
- Many IDE devices do not provide vendor and product IDs. This is
- a known problem and hence not worth a log message.
- """
- devices = [
- {
- 'id': 1,
- 'udi': self.UDI_COMPUTER,
- 'properties': {}
- },
- {
- 'id': 2,
- 'udi': self.UDI_SATA_CONTROLLER,
- 'properties': {
- 'info.parent': (self.UDI_COMPUTER, 'str'),
- 'info.bus': ('pci', 'str'),
- 'pci.vendor_id': (self.PCI_VENDOR_ID_INTEL, 'int'),
- 'pci.product_id': (self.PCI_PROD_ID_PCI_PCCARD_BRIDGE,
- 'int'),
- 'info.product': ('Intel PCCard bridge 1234', 'str'),
- },
- },
- {
- 'id': 3,
- 'udi': self.UDI_SATA_DISK,
- 'properties': {
- 'info.parent': (self.UDI_SATA_CONTROLLER, 'str'),
- 'info.bus': ('ide', 'str'),
- },
- },
- ]
- parsed_data = {
- 'hardware': {
- 'hal': {
- 'devices': devices,
- },
- },
- }
-
- parser = SubmissionParser(self.log)
- parser.buildHalDeviceList(parsed_data)
- device = parser.devices[self.UDI_SATA_DISK]
- self.assertFalse(
- device.has_reliable_data,
- 'IDE Device with missing properties vendor ID, product ID, '
- 'product name treated as having reliabledata.')
- self.assertEqual(
- len(self.handler.records), 0,
- 'Warning messages exist for processing an IDE device where '
- 'no messages are expected.')
-
- def testHALDeviceSCSIVendorModelNameRegularCase(self):
- """Test of HALDevice.getScsiVendorAndModelName, regular case."""
- devices = [
- {
- 'id': 1,
- 'udi': self.UDI_SCSI_DISK,
- 'properties': {
- 'info.bus': ('scsi', 'str'),
- 'scsi.vendor': ('SHARP', 'str'),
- 'scsi.model': ('JX250 SCSI', 'str'),
- },
- },
- ]
- parsed_data = {
- 'hardware': {
- 'hal': {
- 'devices': devices,
- },
- },
- }
- parser = SubmissionParser(self.log)
- parser.buildHalDeviceList(parsed_data)
- device = parser.devices[self.UDI_SCSI_DISK]
- vendor_model = device.getScsiVendorAndModelName()
- self.assertEqual(
- {
- 'vendor': 'SHARP',
- 'product': 'JX250 SCSI',
- },
- vendor_model,
- 'Unexpected result of HWDevice.getScsiVendorAndModelName '
- 'for a regular SCSI device. Expected vendor name SHARP, got %r.'
- % vendor_model)
-
- def testHALDeviceSCSIVendorModelNameATADiskShortModelName(self):
- """Test of HALDevice.getScsiVendorAndModelName, ATA disk (1).
-
- Test of an ATA disk with a short model name. The Linux kenrel
- sets the vendor name to "ATA" and inserts the real vendor
- name into the model string.
- """
- devices = [
- {
- 'id': 1,
- 'udi': self.UDI_SCSI_DISK,
- 'properties': {
- 'info.bus': ('scsi', 'str'),
- 'scsi.vendor': ('ATA', 'str'),
- 'scsi.model': ('Hitachi HTS54161', 'str'),
- },
- },
- ]
- parsed_data = {
- 'hardware': {
- 'hal': {
- 'devices': devices,
- },
- },
- }
- parser = SubmissionParser(self.log)
- parser.buildHalDeviceList(parsed_data)
- device = parser.devices[self.UDI_SCSI_DISK]
- vendor_model = device.getScsiVendorAndModelName()
- self.assertEqual(
- {
- 'vendor': 'Hitachi',
- 'product': 'HTS54161',
- },
- vendor_model,
- 'Unexpected result of HWDevice.getScsiVendorAndModelName '
- 'for an ATA SCSI device: %r.'
- % vendor_model)
-
- def testHALDeviceSCSIVendorModelNameATADiskLongModelName(self):
- """Test of HALDevice.getScsiVendorAndModelName, ATA disk (2).
-
- Test of an ATA disk with a short model name. The Linux kenrel
- sets the vendor name to "ATA" and ignores the real vendor name,
- """
- devices = [
- {
- 'id': 1,
- 'udi': self.UDI_SCSI_DISK,
- 'properties': {
- 'info.bus': ('scsi', 'str'),
- 'scsi.vendor': ('ATA', 'str'),
- 'scsi.model': ('HTC426060G9AT00', 'str'),
- },
- },
- ]
- parsed_data = {
- 'hardware': {
- 'hal': {
- 'devices': devices,
- },
- },
- }
- parser = SubmissionParser(self.log)
- parser.buildHalDeviceList(parsed_data)
- device = parser.devices[self.UDI_SCSI_DISK]
- vendor_product = device.getScsiVendorAndModelName()
- self.assertEqual(
- {
- 'vendor': 'ATA',
- 'product': 'HTC426060G9AT00',
- },
- vendor_product,
- 'Unexpected result of HWDevice.getScsiVendorAndModelName '
- 'for a reguale SCSI device: %r.'
- % vendor_product)
-
- def testHALDeviceVendorFromInfoVendor(self):
- """Test of HALDevice.vendor, regular case.
-
- The value is copied from info.vendor, if available."""
- devices = [
- {
- 'id': 1,
- 'udi': self.UDI_SATA_CONTROLLER,
- 'properties': {
- 'info.bus': ('pci', 'str'),
- 'info.vendor': ('Intel Corporation', 'str'),
- 'pci.vendor': ('should not be used', 'str'),
- }
- },
- ]
- parsed_data = {
- 'hardware': {
- 'hal': {
- 'devices': devices,
- },
- },
- }
- parser = SubmissionParser(self.log)
- parser.buildHalDeviceList(parsed_data)
- found_vendor = parser.devices[self.UDI_SATA_CONTROLLER].vendor
- self.assertEqual(found_vendor, 'Intel Corporation',
- 'Unexpected result of HWDevice.vendor. '
- 'Expected Intel Corporation, got %r.'
- % found_vendor)
-
- def testHALDeviceVendorFromBusVendor(self):
- """Test of HALDevice.vendor, value copied from ${bus}.vendor.
-
- If the property info.vendor does not exist, ${bus}.vendor
- is tried.
- """
- devices = [
- {
- 'id': 1,
- 'udi': self.UDI_SATA_CONTROLLER,
- 'properties': {
- 'info.bus': ('pci', 'str'),
- 'pci.vendor': ('Intel Corporation', 'str'),
- },
- },
- ]
- parsed_data = {
- 'hardware': {
- 'hal': {
- 'devices': devices,
- },
- },
- }
- parser = SubmissionParser(self.log)
- parser.buildHalDeviceList(parsed_data)
- found_vendor = parser.devices[self.UDI_SATA_CONTROLLER].vendor
- self.assertEqual(found_vendor, 'Intel Corporation',
- 'Unexpected result of HWDevice.vendor, '
- 'if info.vendor does not exist. '
- 'Expected Intel Corporation, got %r.'
- % found_vendor)
-
- def testHALDeviceVendorScsi(self):
- """Test of HALDevice.vendor for SCSI devices: regular case."""
- devices = [
- {
- 'id': 1,
- 'udi': self.UDI_SCSI_DISK,
- 'properties': {
- 'info.bus': ('scsi', 'str'),
- 'scsi.vendor': ('SEAGATE', 'str'),
- },
- },
- ]
- parsed_data = {
- 'hardware': {
- 'hal': {
- 'devices': devices,
- },
- },
- }
- parser = SubmissionParser(self.log)
- parser.buildHalDeviceList(parsed_data)
- found_vendor = parser.devices[self.UDI_SCSI_DISK].vendor
- self.assertEqual(found_vendor, 'SEAGATE',
- 'Unexpected result of HWDevice.vendor '
- 'for SCSI device. Expected SEAGATE, got %r.'
- % found_vendor)
-
- def testHALDeviceVendorScsiAta(self):
- """Test of HALDevice.vendor for SCSI devices: fake IDE/SATA disks."""
- devices = [
- {
- 'id': 1,
- 'udi': self.UDI_SCSI_DISK,
- 'properties': {
- 'info.bus': ('scsi', 'str'),
- 'scsi.vendor': ('ATA', 'str'),
- 'scsi.model': ('Hitachi HTS54161', 'str'),
- },
- },
- ]
- parsed_data = {
- 'hardware': {
- 'hal': {
- 'devices': devices,
- },
- },
- }
- parser = SubmissionParser(self.log)
- parser.buildHalDeviceList(parsed_data)
- found_vendor = parser.devices[self.UDI_SCSI_DISK].vendor
- self.assertEqual(found_vendor, 'Hitachi',
- 'Unexpected result of HWDevice.vendor, for fake '
- 'SCSI device. Expected Hitachi, got %r.'
- % found_vendor)
-
- def testHALDeviceVendorSystem(self):
- """Test of HALDevice.vendor for the machine itself."""
- # HAL does not provide info.vendor for the root UDI
- # /org/freedesktop/Hal/devices/computer, hence HALDevice.vendor
- # reads the vendor name from system.vendor
- devices = [
- {
- 'id': 1,
- 'udi': self.UDI_COMPUTER,
- 'properties': {
- 'info.bus': ('unknown', 'str'),
- 'system.hardware.vendor': ('FUJITSU SIEMENS', 'str'),
- },
- },
- ]
- parsed_data = {
- 'hardware': {
- 'hal': {
- 'devices': devices,
- },
- },
- }
- parser = SubmissionParser(self.log)
- parser.buildHalDeviceList(parsed_data)
- found_vendor = parser.devices[self.UDI_COMPUTER].vendor
- self.assertEqual(found_vendor, 'FUJITSU SIEMENS',
- 'Unexpected result of HWDevice.vendor for a '
- 'system. Expected FUJITSU SIEMENS, got %r.'
- % found_vendor)
-
- def testHALDeviceProductFromInfoProduct(self):
- """Test of HALDevice.product, regular case.
-
- The value is copied from info.product, if available."""
- # The product name is copied from the HAL property info.product,
- # if it is avaliable.
- devices = [
- {
- 'id': 1,
- 'udi': self.UDI_SATA_CONTROLLER,
- 'properties': {
- 'info.bus': ('pci', 'str'),
- 'info.product': ('82801GBM/GHM SATA AHCI Controller',
- 'str'),
- 'pci.product': ('should not be used', 'str'),
- },
- },
- ]
- parsed_data = {
- 'hardware': {
- 'hal': {
- 'devices': devices,
- },
- },
- }
- parser = SubmissionParser(self.log)
- parser.buildHalDeviceList(parsed_data)
- found_product = parser.devices[self.UDI_SATA_CONTROLLER].product
- self.assertEqual(found_product, '82801GBM/GHM SATA AHCI Controller',
- 'Unexpected result of HWDevice.product. '
- 'Expected 82801GBM/GHM SATA AHCI Controller, got %r.'
- % found_product)
-
- def testHALDeviceProductFromBusProduct(self):
- """Test of HALDevice.product, value copied from ${bus}.product.
-
- If the property info.product does not exist, ${bus}.product
- """
- devices = [
- {
- 'id': 1,
- 'udi': self.UDI_SATA_CONTROLLER,
- 'properties': {
- 'info.bus': ('pci', 'str'),
- 'pci.product': ('82801GBM/GHM SATA AHCI Controller',
- 'str'),
- },
- },
- ]
- parsed_data = {
- 'hardware': {
- 'hal': {
- 'devices': devices,
- },
- },
- }
- parser = SubmissionParser(self.log)
- parser.buildHalDeviceList(parsed_data)
- found_product = parser.devices[self.UDI_SATA_CONTROLLER].product
- self.assertEqual(found_product, '82801GBM/GHM SATA AHCI Controller',
- 'Unexpected result of HWDevice.product, '
- 'if info.product does not exist. '
- 'Expected 82801GBM/GHM SATA AHCI Controller, got %r.'
- % found_product)
-
- def testHALDeviceProductScsi(self):
- """Test of HALDevice.product for SCSI devices: regular case."""
- # The name of SCSI device is copied from the property scsi.model.
- devices = [
- {
- 'id': 1,
- 'udi': self.UDI_SCSI_DISK,
- 'properties': {
- 'info.bus': ('scsi', 'str'),
- 'scsi.vendor': ('SEAGATE', 'str'),
- 'scsi.model': ('ST36530N', 'str'),
- },
- },
- ]
- parsed_data = {
- 'hardware': {
- 'hal': {
- 'devices': devices,
- },
- },
- }
- parser = SubmissionParser(self.log)
- parser.buildHalDeviceList(parsed_data)
- found_product = parser.devices[self.UDI_SCSI_DISK].product
- self.assertEqual(found_product, 'ST36530N',
- 'Unexpected result of HWDevice.product '
- 'for SCSI device. Expected ST36530N, got %r.'
- % found_product)
-
- def testHALDeviceProductScsiAta(self):
- """Test of HALDevice.product for SCSI devices: fake IDE/SATA disks."""
- devices = [
- {
- 'id': 1,
- 'udi': self.UDI_SCSI_DISK,
- 'properties': {
- 'info.bus': ('scsi', 'str'),
- 'scsi.vendor': ('ATA', 'str'),
- 'scsi.model': ('Hitachi HTS54161', 'str'),
- },
- },
- ]
- parsed_data = {
- 'hardware': {
- 'hal': {
- 'devices': devices,
- },
- },
- }
- parser = SubmissionParser(self.log)
- parser.buildHalDeviceList(parsed_data)
- found_product = parser.devices[self.UDI_SCSI_DISK].product
- self.assertEqual(found_product, 'HTS54161',
- 'Unexpected result of HWDevice.product, for fake '
- 'SCSI device. Expected HTS54161, got %r.'
- % found_product)
-
- def testHALDeviceProductSystem(self):
- """Test of HALDevice.product for the machine itself."""
- # HAL sets info.product to "Computer" for the root UDI
- # /org/freedesktop/Hal/devices/computer, hence HALDevice.product
- # reads the product name from system.product.
- devices = [
- {
- 'id': 1,
- 'udi': self.UDI_COMPUTER,
- 'properties': {
- 'info.bus': ('unknown', 'str'),
- 'system.hardware.product': ('LIFEBOOK E8210', 'str'),
- },
- },
- ]
- parsed_data = {
- 'hardware': {
- 'hal': {
- 'devices': devices,
- },
- },
- }
- parser = SubmissionParser(self.log)
- parser.buildHalDeviceList(parsed_data)
- found_product = parser.devices[self.UDI_COMPUTER].product
- self.assertEqual(found_product, 'LIFEBOOK E8210',
- 'Unexpected result of HWDevice.product, '
- 'if info.product does not exist. '
- 'Expected LIFEBOOK E8210, got %r.'
- % found_product)
-
- def testHALDeviceVendorId(self):
- """Test of HALDevice.vendor_id.
-
- Many buses have a numerical vendor ID. Except for the special
- cases tested below, HWDevice.vendor_id returns the HAL property
- ${bus}.vendor_id.
- """
- devices = [
- {
- 'id': 1,
- 'udi': self.UDI_SATA_CONTROLLER,
- 'properties': {
- 'info.bus': ('pci', 'str'),
- 'pci.vendor_id': (self.PCI_VENDOR_ID_INTEL, 'int'),
- },
- },
- ]
- parsed_data = {
- 'hardware': {
- 'hal': {
- 'devices': devices,
- },
- },
- }
- parser = SubmissionParser(self.log)
- parser.buildHalDeviceList(parsed_data)
- found_vendor_id = parser.devices[
- self.UDI_SATA_CONTROLLER].vendor_id
- self.assertEqual(found_vendor_id, self.PCI_VENDOR_ID_INTEL,
- 'Unexpected result of HWDevice.vendor_id. '
- 'Expected 0x8086, got 0x%x.'
- % found_vendor_id)
-
- def testHALDeviceVendorIdScsi(self):
- """Test of HALDevice.vendor_id for SCSI devices.
-
- The SCSI specification does not know about a vendor ID,
- we use the vendor string as returned by INQUIRY command
- as the ID.
- """
- devices = [
- {
- 'id': 1,
- 'udi': self.UDI_SCSI_DISK,
- 'properties': {
- 'info.bus': ('scsi', 'str'),
- 'scsi.vendor': ('SEAGATE', 'str'),
- },
- },
- ]
- parsed_data = {
- 'hardware': {
- 'hal': {
- 'devices': devices,
- },
- },
- }
- parser = SubmissionParser(self.log)
- parser.buildHalDeviceList(parsed_data)
- found_vendor_id = parser.devices[self.UDI_SCSI_DISK].vendor_id
- self.assertEqual(found_vendor_id, 'SEAGATE',
- 'Unexpected result of HWDevice.vendor_id for a. '
- 'SCSI device. Expected SEAGATE, got %r.'
- % found_vendor_id)
-
- def testHALDeviceVendorIdScsiAta(self):
- """Test of HALDevice.vendor_id for SCSI devices: fake IDE/SATA disks.
- """
- devices = [
- {
- 'id': 1,
- 'udi': self.UDI_SCSI_DISK,
- 'properties': {
- 'info.bus': ('scsi', 'str'),
- 'scsi.vendor': ('ATA', 'str'),
- 'scsi.model': ('Hitachi HTS54161', 'str'),
- },
- },
- ]
- parsed_data = {
- 'hardware': {
- 'hal': {
- 'devices': devices,
- },
- },
- }
- parser = SubmissionParser(self.log)
- parser.buildHalDeviceList(parsed_data)
- found_vendor_id = parser.devices[self.UDI_SCSI_DISK].vendor_id
- self.assertEqual(found_vendor_id, 'Hitachi',
- 'Unexpected result of HWDevice.vendor_id for a. '
- 'fake SCSI device. Expected Hitachi, got %r.'
- % found_vendor_id)
-
- def testHALDeviceVendorIdSystem(self):
- """Test of HALDevice.vendor_id for the machine itself."""
- # HAL does not provide the property info.vendor_id for the
- # root UDI /org/freedesktop/Hal/devices/computer. We use
- # HALDevice.vendor instead.
- devices = [
- {
- 'id': 1,
- 'udi': self.UDI_COMPUTER,
- 'properties': {
- 'info.bus': ('unknown', 'str'),
- 'system.hardware.vendor': ('FUJITSU SIEMENS', 'str'),
- },
- },
- ]
- parsed_data = {
- 'hardware': {
- 'hal': {
- 'devices': devices,
- },
- },
- }
- parser = SubmissionParser(self.log)
- parser.buildHalDeviceList(parsed_data)
- found_vendor_id = parser.devices[self.UDI_COMPUTER].vendor_id
- self.assertEqual(found_vendor_id, 'FUJITSU SIEMENS',
- 'Unexpected result of HWDevice.vendor_id for a '
- 'system. Expected FUJITSU SIEMENS, got %r.'
- % found_vendor_id)
-
- def testHALDeviceProductId(self):
- """Test of HALDevice.product_id.
-
- Many buses have a numerical product ID. Except for the special
- cases tested below, HWDevice.product_id returns the HAL property
- ${bus}.product_id.
- """
- devices = [
- {
- 'id': 1,
- 'udi': self.UDI_SATA_CONTROLLER,
- 'properties': {
- 'info.bus': ('pci', 'str'),
- 'pci.product_id': (0x27c5, 'int'),
- },
- },
- ]
- parsed_data = {
- 'hardware': {
- 'hal': {
- 'devices': devices,
- },
- },
- }
- parser = SubmissionParser(self.log)
- parser.buildHalDeviceList(parsed_data)
- found_product_id = parser.devices[self.UDI_SATA_CONTROLLER].product_id
- self.assertEqual(found_product_id, 0x27c5,
- 'Unexpected result of HWDevice.product_id. '
- 'Expected 0x27c5, got 0x%x.'
- % found_product_id)
-
- def testHALDeviceProductIdScsi(self):
- """Test of HALDevice.product_id for SCSI devices.
-
- The SCSI specification does not know about a product ID,
- we use the product string as returned by INQUIRY command
- as the ID.
- """
- devices = [
- {
- 'id': 1,
- 'udi': self.UDI_SCSI_DISK,
- 'properties': {
- 'info.bus': ('scsi', 'str'),
- 'scsi.vendor': ('SEAGATE', 'str'),
- 'scsi.model': ('ST36530N', 'str'),
- },
- },
- ]
- parsed_data = {
- 'hardware': {
- 'hal': {
- 'devices': devices,
- },
- },
- }
- parser = SubmissionParser(self.log)
- parser.buildHalDeviceList(parsed_data)
- found_product_id = parser.devices[self.UDI_SCSI_DISK].product_id
- self.assertEqual(found_product_id, 'ST36530N',
- 'Unexpected result of HWDevice.product_id for a. '
- 'SCSI device. Expected ST35630N, got %r.'
- % found_product_id)
-
- def testHALDeviceProductIdScsiAta(self):
- """Test of HALDevice.product_id for SCSI devices: fake IDE/SATA disks.
- """
- devices = [
- {
- 'id': 1,
- 'udi': self.UDI_SCSI_DISK,
- 'properties': {
- 'info.bus': ('scsi', 'str'),
- 'scsi.vendor': ('ATA', 'str'),
- 'scsi.model': ('Hitachi HTS54161', 'str'),
- },
- },
- ]
- parsed_data = {
- 'hardware': {
- 'hal': {
- 'devices': devices,
- },
- },
- }
- parser = SubmissionParser(self.log)
- parser.buildHalDeviceList(parsed_data)
- found_product_id = parser.devices[self.UDI_SCSI_DISK].product_id
- self.assertEqual(found_product_id, 'HTS54161',
- 'Unexpected result of HWDevice.product_id for a. '
- 'fake SCSI device. Expected HTS54161, got %r.'
- % found_product_id)
-
- def testHALDeviceProductIdSystem(self):
- """Test of HALDevice.product_id for the machine itself."""
- # HAL does not provide info.product_id for the root UDI
- # /org/freedesktop/Hal/devices/computer. We use
- # HALDevice.product instead.
- devices = [
- {
- 'id': 1,
- 'udi': self.UDI_COMPUTER,
- 'properties': {
- 'info.bus': ('unknown', 'str'),
- 'system.hardware.product': ('LIFEBOOK E8210', 'str'),
- },
- },
- ]
- parsed_data = {
- 'hardware': {
- 'hal': {
- 'devices': devices,
- },
- },
- }
- parser = SubmissionParser(self.log)
- parser.buildHalDeviceList(parsed_data)
- found_product_id = parser.devices[self.UDI_COMPUTER].product_id
- self.assertEqual(found_product_id, 'LIFEBOOK E8210',
- 'Unexpected result of HWDevice.product_id for a '
- 'system. Expected LIFEBOOK E8210, got %r.'
- % found_product_id)
-
- def testVendorIDForDB(self):
- """Test of HALDevice.vendor_id_for_db."""
- devices = [
- {
- 'id': 1,
- 'udi': self.UDI_SATA_DISK,
- 'properties': {},
- },
- ]
- parsed_data = {
- 'hardware': {
- 'hal': {
- 'devices': devices,
- },
- },
- }
- properties = devices[0]['properties']
- parser = SubmissionParser(self.log)
- # SCSI vendor names have a length of exactly 8 bytes; we use
- # this format for HWDevice.bus_product_id too.
- testdata = (('pci', (0x123, 'int'), '0x0123'),
- ('usb_device', (0x234, 'int'), '0x0234'),
- ('scsi', ('SEAGATE', 'str'), 'SEAGATE '),
- )
- for bus, vendor_id, expected_vendor_id in testdata:
- properties['info.bus'] = (bus, 'str')
- if bus == 'scsi':
- properties['%s.vendor' % bus] = vendor_id
- else:
- properties['%s.vendor_id' % bus] = vendor_id
- parser.buildHalDeviceList(parsed_data)
- found_vendor_id = parser.devices[
- self.UDI_SATA_DISK].vendor_id_for_db
- self.assertEqual(found_vendor_id, expected_vendor_id,
- 'Unexpected result of HWDevice.vendor_id_for_db for bus '
- '"%s". Expected %r, got %r.'
- % (bus, expected_vendor_id, found_vendor_id))
-
- def testVendorIDForDBSystem(self):
- """Test of HALDevice.vendor_id_for_db."""
- devices = [
- {
- 'id': 1,
- 'udi': self.UDI_COMPUTER,
- 'properties': {
- 'system.hardware.vendor': ('FUJITSU SIEMENS', 'str'),
- },
- },
- ]
- parsed_data = {
- 'hardware': {
- 'hal': {
- 'devices': devices,
- },
- },
- }
- parser = SubmissionParser(self.log)
- parser.buildHalDeviceList(parsed_data)
- found_vendor_id = parser.devices[self.UDI_COMPUTER].vendor_id_for_db
- self.assertEqual(found_vendor_id, 'FUJITSU SIEMENS',
- 'Unexpected result of HWDevice.vendor_id_for_db for system. '
- 'Expected FUJITSU SIEMENS, got %r.' % found_vendor_id)
-
- def testProductIDForDB(self):
- """Test of HALDevice.product_id_for_db."""
- devices = [
- {
- 'id': 1,
- 'udi': self.UDI_SATA_DISK,
- 'properties': {},
- },
- ]
- parsed_data = {
- 'hardware': {
- 'hal': {
- 'devices': devices,
- },
- },
- }
- properties = devices[0]['properties']
- parser = SubmissionParser(self.log)
- # SCSI product names (called "model" in the SCSI specifications)
- # have a length of exactly 16 bytes; we use this format for
- # HWDevice.bus_product_id too.
- testdata = (('pci', (0x123, 'int'), '0x0123'),
- ('usb_device', (0x234, 'int'), '0x0234'),
- ('scsi', ('ST1234567890', 'str'), 'ST1234567890 '),
- )
- for bus, product_id, expected_product_id in testdata:
- properties['info.bus'] = (bus, 'str')
- if bus == 'scsi':
- properties['%s.model' % bus] = product_id
- else:
- properties['%s.product_id' % bus] = product_id
- parser.buildHalDeviceList(parsed_data)
- found_product_id = parser.devices[
- self.UDI_SATA_DISK].product_id_for_db
- self.assertEqual(found_product_id, expected_product_id,
- 'Unexpected result of HWDevice.product_id_for_db for bus '
- '"%s". Expected %r, got %r.'
- % (bus, expected_product_id, found_product_id))
-
- def testProductIDForDBSystem(self):
- """Test of HALDevice.product_id_for_db."""
- devices = [
- {
- 'id': 1,
- 'udi': self.UDI_COMPUTER,
- 'properties': {
- 'system.hardware.product': ('E8210', 'str'),
- },
- },
- ]
- parsed_data = {
- 'hardware': {
- 'hal': {
- 'devices': devices,
- },
- },
- }
- parser = SubmissionParser(self.log)
- parser.buildHalDeviceList(parsed_data)
- found_product_id = parser.devices[self.UDI_COMPUTER].product_id_for_db
- self.assertEqual(found_product_id, 'E8210',
- 'Unexpected result of HWDevice.product_id_for_db for system. '
- 'Expected FUJITSU SIEMENS, got %r.' % found_product_id)
-
-
-class TestHALDeviceUSBDevices(TestCaseHWDB):
- """Tests for HALDevice.is_real_device: USB devices."""
-
- def setUp(self):
- """Setup the test environment."""
- super(TestHALDeviceUSBDevices, self).setUp()
- self.usb_controller_pci_side = {
- 'id': 1,
- 'udi': self.UDI_USB_CONTROLLER_PCI_SIDE,
- 'properties': {
- 'info.bus': ('pci', 'str'),
- 'pci.device_class': (PCI_CLASS_SERIALBUS_CONTROLLER, 'int'),
- 'pci.device_subclass': (PCI_SUBCLASS_SERIALBUS_USB, 'int'),
- },
- }
- self.usb_controller_usb_side = {
- 'id': 2,
- 'udi': self.UDI_USB_CONTROLLER_USB_SIDE,
- 'properties': {
- 'info.parent': (self.UDI_USB_CONTROLLER_PCI_SIDE, 'str'),
- 'info.bus': ('usb_device', 'str'),
- 'usb_device.vendor_id': (0, 'int'),
- 'usb_device.product_id': (0, 'int'),
- },
- }
- self.usb_storage_device = {
- 'id': 3,
- 'udi': self.UDI_USB_STORAGE,
- 'properties': {
- 'info.parent': (self.UDI_USB_CONTROLLER_USB_SIDE, 'str'),
- 'info.bus': ('usb_device', 'str'),
- 'usb_device.vendor_id': (self.USB_VENDOR_ID_USBEST, 'int'),
- 'usb_device.product_id': (self.USB_PROD_ID_USBBEST_MEMSTICK,
- 'int'),
- },
- }
- self.parsed_data = {
- 'hardware': {
- 'hal': {
- 'devices': [
- self.usb_controller_pci_side,
- self.usb_controller_usb_side,
- self.usb_storage_device,
- ],
- },
- },
- }
-
- def renameInfoBusToInfoSubsystem(self):
- for device in self.parsed_data['hardware']['hal']['devices']:
- properties = device['properties']
- properties['info.subsystem'] = properties['info.bus']
- del properties['info.bus']
-
- def testUSBDeviceRegularCase(self):
- """Test of HALDevice.is_real_device: info.bus == 'usb_device'."""
- parser = SubmissionParser(self.log)
- parser.buildHalDeviceList(self.parsed_data)
- device = parser.devices[self.UDI_USB_STORAGE]
- self.assertTrue(
- device.is_real_device,
- 'Testing info.bus property: Regular USB Device not treated '
- 'as a real device.')
-
- self.renameInfoBusToInfoSubsystem()
- parser.buildHalDeviceList(self.parsed_data)
- device = parser.devices[self.UDI_USB_STORAGE]
- self.assertTrue(
- device.is_real_device,
- 'Testing info.subsystem property: Regular USB Device not treated '
- 'as a real device.')
-
- def testUSBHostController(self):
- """Test of HALDevice.is_real_device: info.bus == 'usb_device'.
-
- Special case: vendor ID and product ID of the device are zero;
- the parent device is a PCI/USB host controller.
- """
-
- parser = SubmissionParser(self.log)
- parser.buildHalDeviceList(self.parsed_data)
- device = parser.devices[self.UDI_USB_CONTROLLER_USB_SIDE]
- self.assertFalse(
- device.is_real_device,
- 'Testing info.bus property: USB Device with vendor/product '
- 'ID 0:0 property treated as a real device.')
-
- self.renameInfoBusToInfoSubsystem()
- parser.buildHalDeviceList(self.parsed_data)
- device = parser.devices[self.UDI_USB_CONTROLLER_USB_SIDE]
- self.assertFalse(
- device.is_real_device,
- 'Testing info.subsystem property: USB Device with vendor/product '
- 'ID 0:0 property treated as a real device.')
-
- def testUSBHostControllerInvalidParentClass(self):
- """Test of HALDevice.is_real_device: info.bus == 'usb_device'.
-
- Special case: vendor ID and product ID of the device are zero;
- the parent device cannot be identified as a PCI/USB host
- controller: Wrong PCI device class of the parent device.
- """
- parent_properties = self.usb_controller_pci_side['properties']
- parent_properties['pci.device_class'] = (PCI_CLASS_STORAGE, 'int')
- parser = SubmissionParser(self.log)
- parser.submission_key = 'USB device test 1'
- parser.buildHalDeviceList(self.parsed_data)
- device = parser.devices[self.UDI_USB_CONTROLLER_USB_SIDE]
- self.assertFalse(
- device.is_real_device,
- 'Testing info.bus property: USB Device with vendor/product '
- 'ID 0:0 property treated as a real device.')
- self.assertWarningMessage(
- parser.submission_key,
- 'USB device found with vendor ID==0, product ID==0, where the '
- 'parent device does not look like a USB host controller: '
- + self.UDI_USB_CONTROLLER_USB_SIDE)
-
- self.renameInfoBusToInfoSubsystem()
- parser.buildHalDeviceList(self.parsed_data)
- device = parser.devices[self.UDI_USB_CONTROLLER_USB_SIDE]
- self.assertFalse(
- device.is_real_device,
- 'Testing info.subsystem property: USB Device with vendor/product '
- 'ID 0:0 property treated as a real device.')
- self.assertWarningMessage(
- parser.submission_key,
- 'USB device found with vendor ID==0, product ID==0, where the '
- 'parent device does not look like a USB host controller: '
- + self.UDI_USB_CONTROLLER_USB_SIDE)
-
- def testUSBHostControllerInvalidParentSubClass(self):
- """Test of HALDevice.is_real_device: info.bus == 'usb_device'.
-
- Special case: vendor ID and product ID of the device are zero;
- the parent device cannot be identified as a PCI/USB host
- controller: Wrong PCI device subclass of the parent device.
- """
- parent_properties = self.usb_controller_pci_side['properties']
- parent_properties['pci.device_subclass'] = (1, 'int')
- parser = SubmissionParser(self.log)
- parser.submission_key = 'USB device test 2'
- parser.buildHalDeviceList(self.parsed_data)
- device = parser.devices[self.UDI_USB_CONTROLLER_USB_SIDE]
- self.assertFalse(
- device.is_real_device,
- 'Testing info.bus property: USB Device with vendor/product '
- 'ID 0:0 property treated as a real device.')
- self.assertWarningMessage(
- parser.submission_key,
- 'USB device found with vendor ID==0, product ID==0, where the '
- 'parent device does not look like a USB host controller: '
- + self.UDI_USB_CONTROLLER_USB_SIDE)
-
- self.renameInfoBusToInfoSubsystem()
- parser.buildHalDeviceList(self.parsed_data)
- device = parser.devices[self.UDI_USB_CONTROLLER_USB_SIDE]
- self.assertFalse(
- device.is_real_device,
- 'Testing info.subsystem property: USB Device with vendor/product '
- 'ID 0:0 property treated as a real device.')
- self.assertWarningMessage(
- parser.submission_key,
- 'USB device found with vendor ID==0, product ID==0, where the '
- 'parent device does not look like a USB host controller: '
- + self.UDI_USB_CONTROLLER_USB_SIDE)
-
- def testUSBHostControllerUnexpectedParentBus(self):
- """Test of HALDevice.is_real_device: info.bus == 'usb_device'.
-
- Special case: vendor ID and product ID of the device are zero;
- the parent device cannot be identified as a PCI/USB host
- controller: Wrong bus of the parent device.
- """
- parent_properties = self.usb_controller_pci_side['properties']
- parent_properties['info.bus'] = ('not pci', 'str')
- parser = SubmissionParser(self.log)
- parser.submission_key = 'USB device test 3'
- parser.buildHalDeviceList(self.parsed_data)
- device = parser.devices[self.UDI_USB_CONTROLLER_USB_SIDE]
- self.assertFalse(
- device.is_real_device,
- 'Testing info.bus property: USB Device with vendor/product '
- 'ID 0:0 property treated as a real device.')
- self.assertWarningMessage(
- parser.submission_key,
- 'USB device found with vendor ID==0, product ID==0, where the '
- 'parent device does not look like a USB host controller: '
- + self.UDI_USB_CONTROLLER_USB_SIDE)
-
- # All other devices which have an info.bus property return True
- # for HALDevice.is_real_device. The USB host controller in the
- # test data is an example.
- device = parser.devices[self.UDI_USB_CONTROLLER_PCI_SIDE]
- self.assertTrue(
- device.is_real_device,
- 'Testing info.bus property: Device with existing info.bus '
- 'property not treated as a real device.')
-
- self.renameInfoBusToInfoSubsystem()
- parser.buildHalDeviceList(self.parsed_data)
- device = parser.devices[self.UDI_USB_CONTROLLER_USB_SIDE]
- self.assertFalse(
- device.is_real_device,
- 'Testing info.subsystem property: USB Device with vendor/product '
- 'ID 0:0 property treated as a real device.')
- self.assertWarningMessage(
- parser.submission_key,
- 'USB device found with vendor ID==0, product ID==0, where the '
- 'parent device does not look like a USB host controller: '
- + self.UDI_USB_CONTROLLER_USB_SIDE)
-
- device = parser.devices[self.UDI_USB_CONTROLLER_PCI_SIDE]
- self.assertTrue(
- device.is_real_device,
- 'Testing info.subsystem property: Device with existing info.bus '
- 'property not treated as a real device.')
-
-
-class TestUdevDevice(TestCaseHWDB):
- """Tests of class UdevDevice."""
-
- def setUp(self):
- """Setup the test environment."""
- super(TestUdevDevice, self).setUp()
- self.root_device = {
- 'P': '/devices/LNXSYSTM:00',
- 'E': {
- 'UDEV_LOG': '3',
- 'DEVPATH': '/devices/LNXSYSTM:00',
- 'MODALIAS': 'acpi:LNXSYSTM:',
- 'SUBSYSTEM': 'acpi',
- },
- 'id': 1,
- }
-
- self.root_device_dmi_data = {
- '/sys/class/dmi/id/sys_vendor': 'FUJITSU SIEMENS',
- '/sys/class/dmi/id/product_name': 'LIFEBOOK E8210',
- }
-
- self.usb_device_data = {
- 'P': '/devices/pci0000:00/0000:00:1d.1/usb3/3-2',
- 'E': {
- 'SUBSYSTEM': 'usb',
- 'DEVTYPE': 'usb_device',
- 'PRODUCT': '46d/a01/1013',
- 'TYPE': '0/0/0',
- 'DRIVER': 'usb',
- },
- }
-
- self.pci_pccard_bridge_path = (
- '/devices/pci0000:00/0000:00:1e.0/0000:08:03.0')
- self.pci_pccard_bridge = {
- 'P': self.pci_pccard_bridge_path,
- 'E': {
- 'DRIVER': 'yenta_cardbus',
- 'PCI_CLASS': '60700',
- 'PCI_ID': '1217:7134',
- 'PCI_SUBSYS_ID': '10CF:131E',
- 'PCI_SLOT_NAME': '0000:08:03.0',
- 'SUBSYSTEM': 'pci',
- }
- }
-
- self.pccard_scsi_controller_path = (
- '/devices/pci0000:00/0000:00:1e.0/0000:08:03.0/0000:09:00.0')
- self.pccard_scsi_controller_data = {
- 'P': self.pccard_scsi_controller_path,
- 'E': {
- 'DRIVER': 'aic7xxx',
- 'PCI_CLASS': '10000',
- 'PCI_ID': '9004:6075',
- 'PCI_SUBSYS_ID': '9004:7560',
- 'SUBSYSTEM': 'pci',
- },
- }
-
- self.pci_scsi_controller_scsi_side_1 = {
- 'P': ('/devices/pci0000:00/0000:00:1e.0/0000:08:03.0/'
- '0000:09:00.0/host6'),
- 'E': {
- 'DEVTYPE': 'scsi_host',
- 'SUBSYSTEM': 'scsi',
- },
- }
-
- self.pci_bridge_pccard_hierarchy_data = [
- {'udev_data': self.root_device},
- {'udev_data': self.pci_pccard_bridge},
- {'udev_data': self.pccard_scsi_controller_data},
- ]
-
- self.pci_scsi_controller_scsi_side_2 = {
- 'P': ('/devices/pci0000:00/0000:00:1e.0/0000:08:03.0/'
- '0000:09:00.0/host6/scsi_host/host6'),
- 'E': {
- 'SUBSYSTEM': 'scsi_host',
- },
- }
-
- self.scsi_scanner_target_data = {
- 'P': ('/devices/pci0000:00/0000:00:1e.0/0000:08:03.0/'
- '0000:09:00.0/host6/target6:0:1'),
- 'E': {
- 'DEVTYPE': 'scsi_target',
- 'SUBSYSTEM': 'scsi'
- },
- }
-
- self.scsi_scanner_device_path = (
- '/devices/pci0000:00/0000:00:1e.0/0000:08:03.0/0000:09:00.0/'
- 'host6/target6:0:1/6:0:1:0')
- self.scsi_scanner_device_data = {
- 'P': self.scsi_scanner_device_path,
- 'E': {
- 'DEVTYPE': 'scsi_device',
- 'SUBSYSTEM': 'scsi',
- },
- }
-
- self.scsi_scanner_device_sysfs_data = {
- 'vendor': 'FUJITSU',
- 'model': 'fi-5120Cdj',
- 'type': '6',
- }
-
- self.scsi_scanner_device_data_2 = {
- 'P': ('/devices/pci0000:00/0000:00:1e.0/0000:08:03.0/'
- '0000:09:00.0/host6/target6:0:1/6:0:1:0/scsi_device/'
- '6:0:1:0'),
- 'E': {
- 'SUBSYSTEM': 'scsi_device',
- },
- }
-
- self.scsi_scanner_scsi_generic = {
- 'P': ('/devices/pci0000:00/0000:00:1e.0/0000:08:03.0/'
- '0000:09:00.0/host6/target6:0:1/6:0:1:0/scsi_generic/sg2'),
- 'E': {
- 'SUBSYSTEM': 'scsi_generic',
- },
- }
-
- self.scsi_scanner_spi = {
- 'P': ('/devices/pci0000:00/0000:00:1e.0/0000:08:03.0/'
- '0000:09:00.0/host6/target6:0:1/spi_transport/target6:0:1'),
- 'E': {
- 'SUBSYSTEM': 'spi_transport',
- },
- }
-
- self.scsi_device_hierarchy_data = [
- {'udev_data': self.pccard_scsi_controller_data},
- {'udev_data': self.pci_scsi_controller_scsi_side_1},
- {'udev_data': self.pci_scsi_controller_scsi_side_2},
- {'udev_data': self.scsi_scanner_target_data},
- {
- 'udev_data': self.scsi_scanner_device_data,
- 'sysfs_data': self.scsi_scanner_device_sysfs_data,
- },
- {'udev_data': self.scsi_scanner_device_data_2},
- {'udev_data': self.scsi_scanner_scsi_generic},
- {'udev_data': self.scsi_scanner_spi},
- ]
-
- self.pci_ide_controller_path = '/devices/pci0000:00/0000:00:1f.1'
- self.pci_ide_controller = {
- 'P': self.pci_ide_controller_path,
- 'E': {
- 'DRIVER': 'ata_piix',
- 'PCI_CLASS': '1018A',
- 'PCI_ID': '8086:27DF',
- 'PCI_SUBSYS_ID': '10CF:1385',
- 'SUBSYSTEM': 'pci',
- },
- }
-
- self.pci_ide_controller_scsi_side_1 = {
- 'P': '/devices/pci0000:00/0000:00:1f.1/host4',
- 'E': {
- 'DEVTYPE': 'scsi_host',
- 'SUBSYSTEM': 'scsi',
- },
- }
-
- self.pci_ide_controller_scsi_side_2 = {
- 'P': '/devices/pci0000:00/0000:00:1f.1/host4/scsi_host/host4',
- 'E': {
- 'SUBSYSTEM': 'scsi_host',
- },
- }
-
- self.ide_device_target_data = {
- 'P': '/devices/pci0000:00/0000:00:1f.1/host4/target4:0:0',
- 'E': {
- 'DEVTYPE': 'scsi_target',
- 'SUBSYSTEM': 'scsi',
- },
- }
-
- self.ide_cdrom_device_path = (
- '/devices/pci0000:00/0000:00:1f.1/host4/target4:0:0/4:0:0:0')
- self.ide_cdrom_device_data = {
- 'P': self.ide_cdrom_device_path,
- 'E': {
- 'SUBSYSTEM': 'scsi',
- 'DEVTYPE': 'scsi_device',
- 'DRIVER': 'sr',
- },
- }
-
- self.ide_cdrom_device_sysfs_data = {
- 'vendor': 'MATSHITA',
- 'model': 'DVD-RAM UJ-841S',
- 'type': '5',
- }
-
- self.ide_cdrom_sr_data = {
- 'P': ('/devices/pci0000:00/0000:00:1f.1/host4/target4:0:0/'
- '4:0:0:0/block/sr0'),
- 'E': {
- 'DEVTYPE': 'disk',
- 'SUBSYSTEM': 'block',
- },
- }
-
- self.ide_cdrom_device_data_2 = {
- 'P': ('/devices/pci0000:00/0000:00:1f.1/host4/target4:0:0/'
- '4:0:0:0/scsi_device/4:0:0:0'),
- 'E': {
- 'SUBSYSTEM': 'scsi_device',
- },
- }
-
- self.ide_cdrom_scsi_generic_data = {
- 'P': ('/devices/pci0000:00/0000:00:1f.1/host4/target4:0:0/'
- '4:0:0:0/scsi_generic/sg1'),
- 'E': {
- 'SUBSYSTEM': 'scsi_generic',
- },
- }
-
- self.ide_device_hierarchy_data = [
- {'udev_data': self.pci_ide_controller},
- {'udev_data': self.pci_ide_controller_scsi_side_1},
- {'udev_data': self.pci_ide_controller_scsi_side_2},
- {'udev_data': self.ide_device_target_data},
- {
- 'udev_data': self.ide_cdrom_device_data,
- 'sysfs_data': self.ide_cdrom_device_sysfs_data,
- },
- {'udev_data': self.ide_cdrom_sr_data},
- {'udev_data': self.ide_cdrom_device_data_2},
- {'udev_data': self.ide_cdrom_scsi_generic_data},
- ]
-
- self.pci_sata_controller_path = '/devices/pci0000:00/0000:00:1f.2'
- self.pci_sata_controller = {
- 'P': self.pci_sata_controller_path,
- 'E': {
- 'PCI_CLASS': '10602',
- 'PCI_ID': '8086:27C5',
- 'PCI_SUBSYS_ID': '10CF:1387',
- 'PCI_SLOT_NAME': '0000:00:1f.2',
- 'SUBSYSTEM': 'pci',
- 'DRIVER': 'ahci',
- }
- }
-
- self.pci_sata_controller_scsi_side_1 = {
- 'P': '/devices/pci0000:00/0000:00:1f.2/host0',
- 'E': {
- 'DEVTYPE': 'scsi_host',
- 'SUBSYSTEM': 'scsi',
- },
- }
-
- self.pci_sata_controller_scsi_side_2 = {
- 'P': '/devices/pci0000:00/0000:00:1f.2/host0/scsi_host/host0',
- 'E': {
- 'SUBSYSTEM': 'scsi_host',
- },
- }
-
- self.sata_disk_target_data = {
- 'P': '/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0',
- 'E': {
- 'DEVTYPE': 'scsi_target',
- 'SUBSYSTEM': 'scsi',
- },
- }
-
- self.sata_disk_device_path = (
- '/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0')
- self.sata_disk_device_data = {
- 'P': self.sata_disk_device_path,
- 'E': {
- 'DEVTYPE': 'scsi_device',
- 'DRIVER': 'sd',
- 'SUBSYSTEM': 'scsi',
- },
- }
-
- self.sata_disk_device_sysfs_data = {
- 'vendor': 'ATA',
- 'model': 'Hitachi HTS54251',
- 'type': '0',
- }
-
- self.sata_disk_device_data_2 = {
- 'P': ('/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/'
- '0:0:0:0/scsi_device/0:0:0:0'),
- 'E': {
- 'SUBSYSTEM': 'scsi_device',
- },
- }
-
- self.sata_disk_device_scsi_disk_data = {
- 'P': ('/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/'
- '0:0:0:0/scsi_disk/0:0:0:0'),
- 'E': {
- 'SUBSYSTEM': 'scsi_disk',
- },
- }
-
- self.sata_disk_device_scsi_generic_data = {
- 'P': ('/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/'
- '0:0:0:0/scsi_generic/sg0'),
- 'E': {
- 'SUBSYSTEM': 'scsi_generic'
- },
- }
-
- self.sata_disk_block_data = {
- 'P': ('/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/'
- '0:0:0:0/block/sda'),
- 'E': {
- 'DEVTYPE': 'disk',
- 'SUBSYSTEM': 'block',
- },
- }
-
- self.sata_disk_partition_data = {
- 'P': ('/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/'
- '0:0:0:0/block/sda/sda1'),
- 'E': {
- 'DEVTYPE': 'partition',
- 'SUBSYSTEM': 'block',
- },
- }
-
- self.sata_device_hierarchy_data = [
- {'udev_data': self.pci_sata_controller},
- {'udev_data': self.pci_sata_controller_scsi_side_1},
- {'udev_data': self.pci_sata_controller_scsi_side_2},
- {'udev_data': self.sata_disk_target_data},
- {'udev_data': self.sata_disk_device_data},
- {
- 'udev_data': self.sata_disk_device_data,
- 'sysfs_data': self.sata_disk_device_sysfs_data,
- },
- {'udev_data': self.sata_disk_device_data_2},
- {'udev_data': self.sata_disk_device_scsi_disk_data},
- {'udev_data': self.sata_disk_device_scsi_generic_data},
- {'udev_data': self.sata_disk_block_data},
- {'udev_data': self.sata_disk_partition_data},
- ]
-
- self.usb_storage_usb_device_path = (
- '/devices/pci0000:00/0000:00:1d.7/usb1/1-1')
- self.usb_storage_usb_device_data = {
- 'P': self.usb_storage_usb_device_path,
- 'E': {
- 'DEVTYPE': 'usb_device',
- 'DRIVER': 'usb',
- 'PRODUCT': '1307/163/100',
- 'TYPE': '0/0/0',
- 'SUBSYSTEM': 'usb',
- },
- }
-
- self.usb_storage_usb_interface = {
- 'P': '/devices/pci0000:00/0000:00:1d.7/usb1/1-1/1-1:1.0',
- 'E': {
- 'DRIVER': 'usb-storage',
- 'PRODUCT': '1307/163/100',
- 'TYPE': '0/0/0',
- 'INTERFACE': '8/6/80',
- 'DEVTYPE': 'usb_interface',
- 'SUBSYSTEM': 'usb',
- },
- }
-
- self.usb_storage_scsi_host_1 = {
- 'P': '/devices/pci0000:00/0000:00:1d.7/usb1/1-1/1-1:1.0/host7',
- 'E': {
- 'DEVTYPE': 'scsi_host',
- 'SUBSYSTEM': 'scsi',
- },
- }
-
- self.usb_storage_scsi_host_2 = {
- 'P': ('/devices/pci0000:00/0000:00:1d.7/usb1/1-1/1-1:1.0/host7/'
- 'scsi_host/host7'),
- 'E': {
- 'SUBSYSTEM': 'scsi_host',
- },
- }
-
- self.usb_storage_scsi_target = {
- 'P': ('/devices/pci0000:00/0000:00:1d.7/usb1/1-1/1-1:1.0/host7/'
- 'target7:0:0'),
- 'E': {
- 'DEVTYPE': 'scsi_target',
- 'SUBSYSTEM': 'scsi',
- },
- }
-
- self.usb_storage_scsi_device_path = (
- '/devices/pci0000:00/0000:00:1d.7/usb1/1-1/1-1:1.0/host7/'
- 'target7:0:0/7:0:0:0')
- self.usb_storage_scsi_device = {
- 'P': self.usb_storage_scsi_device_path,
- 'E': {
- 'DEVTYPE': 'scsi_device',
- 'DRIVER': 'sd',
- 'SUBSYSTEM': 'scsi',
- },
- }
-
- self.usb_storage_scsi_device_sysfs = {
- 'vendor': 'Ut163',
- 'model': 'USB2FlashStorage',
- 'type': '0',
- }
-
- self.usb_storage_scsi_device_2 = {
- 'P': ('/devices/pci0000:00/0000:00:1d.7/usb1/1-1/1-1:1.0/host7/'
- 'target7:0:0/7:0:0:0/scsi_device/7:0:0:0'),
- 'E': {
- 'SUBSYSTEM': 'scsi_device',
- },
- }
-
- self.usb_storage_scsi_disk = {
- 'P': ('/devices/pci0000:00/0000:00:1d.7/usb1/1-1/1-1:1.0/host7/'
- 'target7:0:0/7:0:0:0/scsi_disk/7:0:0:0'),
- 'E': {
- 'SUBSYSTEM': 'scsi_disk',
- },
- }
-
- self.usb_storage_scsi_generic = {
- 'P': ('/devices/pci0000:00/0000:00:1d.7/usb1/1-1/1-1:1.0/host7/'
- 'target7:0:0/7:0:0:0/scsi_generic/sg3'),
- 'E': {
- 'SUBSYSTEM': 'scsi_generic',
- },
- }
-
- self.usb_storage_block_device_data = {
- 'P': ('/devices/pci0000:00/0000:00:1d.7/usb1/1-1/1-1:1.0/host7/'
- 'target7:0:0/7:0:0:0/block/sdb'),
- 'E': {
- 'DEVTYPE': 'disk',
- 'SUBSYSTEM': 'block',
- },
- }
-
- self.usb_storage_block_partition_data = {
- 'P': ('/devices/pci0000:00/0000:00:1d.7/usb1/1-1/1-1:1.0/host7/'
- 'target7:0:0/7:0:0:0/block/sdb/sdb1'),
- 'E': {
- 'DEVTYPE': 'partition',
- 'SUBSYSTEM': 'block',
- },
- }
-
- self.usb_storage_hierarchy_data = [
- {'udev_data': self.usb_storage_usb_device_data},
- {'udev_data': self.usb_storage_usb_interface},
- {'udev_data': self.usb_storage_scsi_host_1},
- {'udev_data': self.usb_storage_scsi_host_2},
- {'udev_data': self.usb_storage_scsi_target},
- {
- 'udev_data': self.usb_storage_scsi_device,
- 'sysfs_data': self.usb_storage_scsi_device_sysfs,
- },
- {'udev_data': self.usb_storage_scsi_device_2},
- {'udev_data': self.usb_storage_scsi_disk},
- {'udev_data': self.usb_storage_scsi_generic},
- {'udev_data': self.usb_storage_block_device_data},
- {'udev_data': self.usb_storage_block_partition_data},
- ]
-
- self.usb_hub_path = '/devices/pci0000:00/0000:00:1d.0/usb2'
- self.usb_hub = {
- 'P': self.usb_hub_path,
- 'E': {
- 'DEVTYPE': 'usb_device',
- 'DRIVER': 'usb',
- 'PRODUCT': '0/0/0',
- 'TYPE': '9/0/0',
- 'SUBSYSTEM': 'usb',
- },
- }
-
- self.usb_hub_with_odd_parent_hierarchy_data = [
- {'udev_data': self.root_device},
- {'udev_data': self.usb_hub},
- ]
-
- self.no_subsystem_device_data = {
- 'P': '/devices/pnp0/00:00',
- 'E': {}
- }
-
- self.cpu_device_data = {
- 'P': '/devices/LNXSYSTM:00/LNXCPU:00',
- 'E': {
- 'DRIVER': 'processor',
- 'SUBSYSTEM': 'acpi',
- },
- }
-
- self.platform_device_data = {
- 'P': '/devices/platform/dock.0',
- 'E': {
- 'SUBSYSTEM': 'platform',
- },
- }
-
- def test_device_device_id(self):
- """Test of UdevDevice.device_id."""
- device = UdevDevice(None, self.pci_sata_controller)
- self.assertEqual(
- '/devices/pci0000:00/0000:00:1f.2', device.device_id,
- 'Unexpected value of UdevDevice.device_id.')
-
- def test_root_device_ids(self):
- device = UdevDevice(
- None, self.root_device, None, self.root_device_dmi_data)
- self.assertEqual(
- {
- 'vendor': 'FUJITSU SIEMENS',
- 'product': 'LIFEBOOK E8210',
- },
- device.root_device_ids)
-
- device = UdevDevice(
- None, self.root_device, None, {})
- self.assertEqual(
- {
- 'vendor': None,
- 'product': None,
- },
- device.root_device_ids)
-
- def test_is_pci(self):
- """Test of UdevDevice.is_pci."""
- device = UdevDevice(None, self.pci_sata_controller)
- self.assertTrue(device.is_pci)
-
- device = UdevDevice(None, self.root_device)
- self.assertFalse(device.is_pci)
-
- def test_pci_class_info(self):
- """Test of UdevDevice.pci_class_info"""
- device = UdevDevice(None, self.pci_sata_controller)
- self.assertEqual(
- (1, 6, 2), device.pci_class_info,
- 'Invalid value of UdevDevice.pci_class_info for PCI device.')
-
- device = UdevDevice(None, self.root_device)
- self.assertEqual(
- (None, None, None), device.pci_class_info,
- 'Invalid value of UdevDevice.pci_class_info for Non-PCI device.')
-
- def test_pci_class(self):
- """Test of UdevDevice.pci_class"""
- device = UdevDevice(None, self.pci_sata_controller)
- self.assertEqual(
- 1, device.pci_class,
- 'Invalid value of UdevDevice.pci_class for PCI device.')
-
- device = UdevDevice(None, self.root_device)
- self.assertEqual(
- None, device.pci_class,
- 'Invalid value of UdevDevice.pci_class for Non-PCI device.')
-
- def test_pci_subclass(self):
- """Test of UdevDevice.pci_subclass"""
- device = UdevDevice(None, self.pci_sata_controller)
- self.assertEqual(
- 6, device.pci_subclass,
- 'Invalid value of UdevDevice.pci_class for PCI device.')
-
- device = UdevDevice(None, self.root_device)
- self.assertEqual(
- None, device.pci_class,
- 'Invalid value of UdevDevice.pci_class for Non-PCI device.')
-
- def test_pci_ids(self):
- """Test of UdevDevice.pci_ids"""
- device = UdevDevice(None, self.pci_sata_controller)
- self.assertEqual(
- {'vendor': 0x8086,
- 'product': 0x27C5,
- },
- device.pci_ids,
- 'Invalid value of UdevDevice.pci_ids for PCI device.')
-
- device = UdevDevice(None, self.usb_device_data)
- self.assertEqual(
- {'vendor': None,
- 'product': None,
- },
- device.pci_ids,
- 'Invalid value of UdevDevice.pci_ids for Non-PCI device.')
-
- def test_is_usb(self):
- """Test of UdevDevice.is_usb"""
- device = UdevDevice(None, self.usb_device_data)
- self.assertTrue(device.is_usb)
-
- device = UdevDevice(None, self.pci_sata_controller)
- self.assertFalse(device.is_usb)
-
- def test_usb_ids(self):
- """Test of UdevDevice.usb_ids"""
- device = UdevDevice(None, self.usb_device_data)
- self.assertEqual(
- {
- 'vendor': 0x46d,
- 'product': 0xa01,
- 'version': 0x1013,
- },
- device.usb_ids,
- 'Invalid value of UdevDevice.usb_ids for USB device.')
-
- device = UdevDevice(None, self.root_device)
- self.assertEqual(
- {
- 'vendor': None,
- 'product': None,
- 'version': None,
- },
- device.usb_ids,
- 'Invalid value of UdevDevice.usb_ids for Non-USB device.')
-
- def test_usb_vendor_id(self):
- """Test of UdevDevice.usb_vendor_id"""
- device = UdevDevice(None, self.usb_device_data)
- self.assertEqual(
- 0x46d, device.usb_vendor_id,
- 'Invalid value of UdevDevice.usb_vendor_id for USB device.')
-
- device = UdevDevice(None, self.root_device)
- self.assertEqual(
- None, device.usb_vendor_id,
- 'Invalid value of UdevDevice.usb_vendor_id for Non-USB device.')
-
- def test_usb_product_id(self):
- """Test of UdevDevice.usb_product_id"""
- device = UdevDevice(None, self.usb_device_data)
- self.assertEqual(
- 0xa01, device.usb_product_id,
- 'Invalid value of UdevDevice.usb_product_id for USB device.')
-
- device = UdevDevice(None, self.root_device)
- self.assertEqual(
- None, device.usb_product_id,
- 'Invalid value of UdevDevice.usb_product_id for Non-USB device.')
-
- def test_is_scsi_device(self):
- """Test of UdevDevice.is_scsi_device."""
- device = UdevDevice(
- None, self.scsi_scanner_device_data,
- self.scsi_scanner_device_sysfs_data)
- self.assertTrue(device.is_scsi_device)
-
- device = UdevDevice(None, self.root_device)
- self.assertFalse(device.is_scsi_device)
-
- def test_is_scsi_device__no_sysfs_data(self):
- """Test of UdevDevice.is_scsi_device.
-
- If there is no sysfs data for a real SCSI device, is it not
- considered as a real SCSI device.
-
- Reason: Without sysfs data, we don't know the vendor and
- model name, making it impossible to store data about the
- device in the database.
- """
- device = UdevDevice(
- None, self.scsi_scanner_device_data, None)
- self.assertFalse(device.is_scsi_device)
-
- def test_scsi_vendor(self):
- """Test of UdevDevice.scsi_vendor."""
- device = UdevDevice(
- None, self.scsi_scanner_device_data,
- self.scsi_scanner_device_sysfs_data)
- self.assertEqual('FUJITSU', device.scsi_vendor)
- device = UdevDevice(None, self.root_device)
- self.assertEqual(None, device.scsi_vendor)
-
- def test_scsi_model(self):
- """Test of UdevDevice.scsi_model."""
- device = UdevDevice(
- None, self.scsi_scanner_device_data,
- self.scsi_scanner_device_sysfs_data)
- self.assertEqual('fi-5120Cdj', device.scsi_model)
-
- device = UdevDevice(None, self.root_device)
- self.assertEqual(None, device.scsi_model)
-
- def test_raw_bus(self):
- """Test of UdevDevice.raw_bus."""
- device = UdevDevice(None, self.root_device)
- self.assertEqual(None, device.raw_bus)
-
- device = UdevDevice(None, self.pci_sata_controller)
- self.assertEqual('pci', device.raw_bus)
-
- device = UdevDevice(None, self.usb_device_data)
- self.assertEqual('usb_device', device.raw_bus)
-
- device = UdevDevice(None, self.no_subsystem_device_data)
- self.assertEqual(None, device.raw_bus)
-
- def test_is_root_device(self):
- """Test of UdevDevice.is_root_device."""
- device = UdevDevice(None, self.root_device)
- self.assertTrue(device.is_root_device)
-
- device = UdevDevice(None, self.pci_sata_controller)
- self.assertFalse(device.is_root_device)
-
- def test_getVendorOrProduct(self):
- """Test of UdevDevice.getVendorOrProduct()."""
- device = UdevDevice(
- None, self.root_device, None, self.root_device_dmi_data)
- self.assertEqual(
- 'FUJITSU SIEMENS', device.getVendorOrProduct('vendor'))
- self.assertEqual(
- 'LIFEBOOK E8210', device.getVendorOrProduct('product'))
- self.assertRaises(
- AssertionError, device.getVendorOrProduct, 'nonsense')
-
- device = UdevDevice(None, self.pci_sata_controller)
- self.assertEqual('Unknown', device.getVendorOrProduct('vendor'))
- self.assertEqual('Unknown', device.getVendorOrProduct('product'))
-
- device = UdevDevice(None, self.usb_device_data)
- self.assertEqual('Unknown', device.getVendorOrProduct('vendor'))
- self.assertEqual('Unknown', device.getVendorOrProduct('product'))
-
- device = UdevDevice(
- None, self.scsi_scanner_device_data,
- self.scsi_scanner_device_sysfs_data)
- self.assertEqual('FUJITSU', device.getVendorOrProduct('vendor'))
- self.assertEqual('fi-5120Cdj', device.getVendorOrProduct('product'))
-
- device = UdevDevice(None, self.no_subsystem_device_data)
- self.assertEqual(None, device.getVendorOrProduct('vendor'))
- self.assertEqual(None, device.getVendorOrProduct('product'))
-
- def test_vendor(self):
- """Test of UdevDevice.vendor."""
- device = UdevDevice(
- None, self.root_device, None, self.root_device_dmi_data)
- self.assertEqual('FUJITSU SIEMENS', device.vendor)
-
- def test_product(self):
- """Test of UdevDevice.product."""
- device = UdevDevice(
- None, self.root_device, None, self.root_device_dmi_data)
- self.assertEqual('LIFEBOOK E8210', device.product)
-
- def test_getVendorOrProductID(self):
- """Test of UdevDevice.getVendorOrProduct()."""
- device = UdevDevice(
- None, self.root_device, None, self.root_device_dmi_data)
- self.assertEqual(
- 'FUJITSU SIEMENS', device.getVendorOrProductID('vendor'))
- self.assertEqual(
- 'LIFEBOOK E8210', device.getVendorOrProductID('product'))
- self.assertRaises(
- AssertionError, device.getVendorOrProductID, 'nonsense')
-
- device = UdevDevice(None, self.pci_sata_controller)
- self.assertEqual(0x8086, device.getVendorOrProductID('vendor'))
- self.assertEqual(0x27C5, device.getVendorOrProductID('product'))
-
- device = UdevDevice(None, self.usb_device_data)
- self.assertEqual(0x46d, device.getVendorOrProductID('vendor'))
- self.assertEqual(0xa01, device.getVendorOrProductID('product'))
-
- device = UdevDevice(
- None, self.scsi_scanner_device_data,
- self.scsi_scanner_device_sysfs_data)
- self.assertEqual('FUJITSU', device.getVendorOrProductID('vendor'))
- self.assertEqual('fi-5120Cdj', device.getVendorOrProductID('product'))
-
- device = UdevDevice(
- None, self.no_subsystem_device_data)
- self.assertEqual(None, device.getVendorOrProductID('vendor'))
- self.assertEqual(None, device.getVendorOrProductID('product'))
-
- def test_vendor_id(self):
- """Test of UdevDevice.vendor_id."""
- device = UdevDevice(
- None, self.root_device, None, self.root_device_dmi_data)
- self.assertEqual('FUJITSU SIEMENS', device.vendor_id)
-
- def test_product_id(self):
- """Test of UdevDevice.product_id."""
- device = UdevDevice(
- None, self.root_device, None, self.root_device_dmi_data)
- self.assertEqual('LIFEBOOK E8210', device.product_id)
-
- def test_vendor_id_for_db(self):
- """Test of UdevDevice.vendor_id_for_db."""
- device = UdevDevice(
- None, self.root_device, None, self.root_device_dmi_data)
- self.assertEqual('FUJITSU SIEMENS', device.vendor_id_for_db)
-
- device = UdevDevice(None, self.pci_sata_controller)
- self.assertEqual('0x8086', device.vendor_id_for_db)
-
- device = UdevDevice(None, self.usb_device_data)
- self.assertEqual('0x046d', device.vendor_id_for_db)
-
- device = UdevDevice(
- None, self.scsi_scanner_device_data,
- self.scsi_scanner_device_sysfs_data)
- self.assertEqual('FUJITSU ', device.vendor_id_for_db)
-
- def test_product_id_for_db(self):
- """Test of UdevDevice.product_id_for_db."""
- device = UdevDevice(
- None, self.root_device, None, self.root_device_dmi_data)
- self.assertEqual('LIFEBOOK E8210', device.product_id_for_db)
-
- device = UdevDevice(None, self.pci_sata_controller)
- self.assertEqual('0x27c5', device.product_id_for_db)
-
- device = UdevDevice(None, self.usb_device_data)
- self.assertEqual('0x0a01', device.product_id_for_db)
-
- device = UdevDevice(
- None, self.scsi_scanner_device_data,
- self.scsi_scanner_device_sysfs_data)
- self.assertEqual('fi-5120Cdj ', device.product_id_for_db)
-
- def test_driver_name(self):
- """Test of UdevDevice.driver_name."""
- device = UdevDevice(None, self.pci_sata_controller)
- self.assertEqual('ahci', device.driver_name)
-
- device = UdevDevice(
- None, self.root_device, None, self.root_device_dmi_data)
- self.assertEqual(None, device.driver_name)
-
- def buildUdevDeviceHierarchy(self, device_data, parser=None):
- """Build a UdevDevice hierarchy from device_data.
-
- :param device_data: A sequence of arguments that are passed
- to the UdevDevice constructor. Each element must be a
- dictionary that can be used as a **kwargs argument.
-
- Element N of the sequence is the parent of element N+1.
- :param parser: A SubmissionParser instance to be passed to
- the constructor of UdevDevice.
- """
- devices = {}
- for kwargs in device_data:
- device = UdevDevice(parser, **kwargs)
- devices[device.device_id] = device
-
- # Build the parent-child relations so that the parent device
- # is that device which has the longest path matching the
- # start of the child's path.
- #
- # There is one exception of this rule: The root device has
- # the path "/devices/LNXSYSTM:00", but the paths of most of
- # our test deviies start with "/devices/pci". Well patch the
- # index temporarily in order to find children of the root
- # device.
- if '/devices/LNXSYSTM:00' in devices:
- devices['/devices'] = devices['/devices/LNXSYSTM:00']
- del devices['/devices/LNXSYSTM:00']
-
- device_paths = sorted(devices, key=len, reverse=True)
- for path_index, path in enumerate(device_paths):
- for parent_path in device_paths[path_index + 1:]:
- if path.startswith(parent_path):
- devices[parent_path].addChild(devices[path])
- break
- if '/devices' in devices:
- devices['/devices/LNXSYSTM:00'] = devices['/devices']
- del devices['/devices']
- return devices
-
- def test_scsi_controller(self):
- """Test of UdevDevice.scsi_controller for a PCI controller."""
- devices = self.buildUdevDeviceHierarchy(
- self.scsi_device_hierarchy_data)
- controller = devices[self.pccard_scsi_controller_path]
- scsi_device = devices[self.scsi_scanner_device_path]
- self.assertEqual(controller, scsi_device.scsi_controller)
-
- def test_scsi_controller_insufficient_anchestors(self):
- """Test of UdevDevice.scsi_controller for a PCI controller.
-
- If a SCSI device does not have a sufficient number of ancestors,
- UdevDevice.scsi_controller returns None.
- """
- parser = SubmissionParser(self.log)
- parser.submission_key = 'UdevDevice.scsi_controller ancestor missing'
- devices = self.buildUdevDeviceHierarchy(
- self.scsi_device_hierarchy_data[1:], parser)
- scsi_device = devices[self.scsi_scanner_device_path]
- self.assertEqual(None, scsi_device.scsi_controller)
- self.assertWarningMessage(
- parser.submission_key,
- 'Found a SCSI device without a sufficient number of ancestors: '
- '/devices/pci0000:00/0000:00:1e.0/0000:08:03.0/0000:09:00.0/'
- 'host6/target6:0:1/6:0:1:0')
-
- def test_scsi_controller_no_scsi_device(self):
- """Test of UdevDevice.scsi_controller for a PCI controller.
-
- For non-SCSI devices, this property is None.
- """
- device = UdevDevice(None, self.pci_sata_controller)
- self.assertEqual(None, device.scsi_controller)
-
- def test_translateScsiBus_real_scsi_device(self):
- """Test of UdevDevice.translateScsiBus() with a real SCSI device."""
- devices = self.buildUdevDeviceHierarchy(
- self.scsi_device_hierarchy_data)
- scsi_device = devices[self.scsi_scanner_device_path]
- self.assertEqual(
- HWBus.SCSI, scsi_device.translateScsiBus())
-
- def test_translateScsiBus_ide_device(self):
- """Test of UdevDevice.translateScsiBus() with an IDE device."""
- devices = self.buildUdevDeviceHierarchy(
- self.ide_device_hierarchy_data)
- ide_device = devices[self.ide_cdrom_device_path]
- self.assertEqual(HWBus.IDE, ide_device.translateScsiBus())
-
- def test_translateScsiBus_usb_device(self):
- """Test of UdevDevice.translateScsiBus() with a USB device."""
- devices = self.buildUdevDeviceHierarchy(
- self.usb_storage_hierarchy_data)
- usb_scsi_device = devices[self.usb_storage_scsi_device_path]
- self.assertEqual(None, usb_scsi_device.translateScsiBus())
-
- def test_translateScsiBus_non_scsi_device(self):
- """Test of UdevDevice.translateScsiBus() for a non-SCSI device."""
- device = UdevDevice(None, self.root_device)
- self.assertEqual(None, device.translateScsiBus())
-
- def test_translatePciBus(self):
- """Test of UdevDevice.translatePciBus()."""
- devices = self.buildUdevDeviceHierarchy(
- self.pci_bridge_pccard_hierarchy_data)
- pci_device = devices[self.pci_pccard_bridge_path]
- pccard_device = devices[self.pccard_scsi_controller_path]
- self.assertEqual(HWBus.PCI, pci_device.translatePciBus())
- self.assertEqual(HWBus.PCCARD, pccard_device.translatePciBus())
-
- def test_real_bus_usb_device(self):
- """Test of UdevDevice.real_bus for a USB device."""
- usb_device = UdevDevice(None, self.usb_device_data)
- self.assertEqual(HWBus.USB, usb_device.real_bus)
-
- def test_real_bus_usb_interface(self):
- """Test of UdevDevice.real_bus for a USB interface."""
- parser = SubmissionParser(self.log)
- parser.submission_key = 'UdevDevice.real_bus for a not-real device'
- usb_interface = UdevDevice(parser, self.usb_storage_usb_interface)
- self.assertEqual(None, usb_interface.real_bus)
- # UdevDevice.real_bus should only be accessed for real devices,
- # which a USB is not. Hence we get a warning.
- self.assertWarningMessage(
- parser.submission_key,
- "Unknown bus u'usb_interface' for device "
- "/devices/pci0000:00/0000:00:1d.7/usb1/1-1/1-1:1.0")
-
- def test_real_bus_pci(self):
- """Test of UdevDevice.real_bus for PCI devices."""
- devices = self.buildUdevDeviceHierarchy(
- self.pci_bridge_pccard_hierarchy_data)
- pci_device = devices[self.pci_pccard_bridge_path]
- pccard_device = devices[self.pccard_scsi_controller_path]
- self.assertEqual(HWBus.PCI, pci_device.real_bus)
- self.assertEqual(HWBus.PCCARD, pccard_device.real_bus)
-
- def test_real_bus_scsi(self):
- """Test of UdevDevice.real_bus for a SCSI device."""
- devices = self.buildUdevDeviceHierarchy(
- self.scsi_device_hierarchy_data)
- scsi_device = devices[self.scsi_scanner_device_path]
- self.assertEqual(HWBus.SCSI, scsi_device.real_bus)
-
- def test_real_bus_system(self):
- """Test of UdevDevice.real_bus for a system."""
- root_device = UdevDevice(None, self.root_device)
- self.assertEqual(HWBus.SYSTEM, root_device.real_bus)
-
- def test_is_real_device_root_device(self):
- """Test of UdevDevice._is_real_device for the root device."""
- root_device = UdevDevice(None, self.root_device)
- self.assertTrue(root_device.is_real_device)
-
- def test_is_real_device_pci_device(self):
- """Test of UdevDevice._is_real_device for a PCI device."""
- pci_device = UdevDevice(None, self.pci_sata_controller)
- self.assertTrue(pci_device.is_real_device)
-
- def test_is_real_device_scsi_device_related_nodes(self):
- """Test of UdevDevice._is_real_device for SCSI related nodes.
-
- A SCSI device and its controller are represented by several
- nodes which describe different aspects. Only the controller
- itself and the node representing the SCSI device are
- considered to be real devices.
- """
- devices = self.buildUdevDeviceHierarchy(
- self.scsi_device_hierarchy_data)
- real_devices = (
- self.pccard_scsi_controller_path, self.scsi_scanner_device_path
- )
- for device in devices.values():
- self.assertEqual(
- device.device_id in real_devices, device.is_real_device,
- 'Invalid result of UdevDevice.is_real_device for %s '
- 'Expected %s, got %s'
- % (device.device_id, device.device_id in real_devices,
- device.is_real_device))
-
- def test_is_real_device_ide_device_related_nodes(self):
- """Test of UdevDevice._is_real_device for IDE related nodes.
-
- An IDE device and its controller are represented by several
- nodes which describe different aspects. Only the controller
- itself and the node representing the IDE device are
- considered to be real devices.
- """
- devices = self.buildUdevDeviceHierarchy(
- self.ide_device_hierarchy_data)
- real_devices = (
- self.pci_ide_controller_path, self.ide_cdrom_device_path,
- )
- for device in devices.values():
- self.assertEqual(
- device.device_id in real_devices, device.is_real_device,
- 'Invalid result of UdevDevice.is_real_device for %s '
- 'Expected %s, got %s'
- % (device.device_id, device.device_id in real_devices,
- device.is_real_device))
-
- def test_is_real_device_ata_device_related_nodes(self):
- """Test of UdevDevice._is_real_device for IDE related nodes.
-
- An IDE device and its controller are represented by several
- nodes which describe different aspects. Only the controller
- itself and the node representing the IDE device are
- considered to be real devices.
- """
- devices = self.buildUdevDeviceHierarchy(
- self.sata_device_hierarchy_data)
- real_devices = (
- self.pci_sata_controller_path, self.sata_disk_device_path,
- )
- for device in devices.values():
- self.assertEqual(
- device.device_id in real_devices, device.is_real_device,
- 'Invalid result of UdevDevice.is_real_device for %s '
- 'Expected %s, got %s'
- % (device.device_id, device.device_id in real_devices,
- device.is_real_device))
-
- def test_is_real_device_usb_storage_device_related_nodes(self):
- """Test of UdevDevice._is_real_device for USB storage related nodes.
-
- A USB storage device is represented by several nodes which
- describe different aspects. Only the main USB device is
- considered to be real devices.
- """
- devices = self.buildUdevDeviceHierarchy(
- self.usb_storage_hierarchy_data)
- for device in devices.values():
- self.assertEqual(
- device.device_id == self.usb_storage_usb_device_path,
- device.is_real_device,
- 'Invalid result of UdevDevice.is_real_device for %s '
- 'Expected %s, got %s'
- % (device.device_id,
- device.device_id == self.usb_storage_usb_device_path,
- device.is_real_device))
-
- def test_is_real_device_usb_hub_with_odd_parent(self):
- """Test of UdevDevice._is_real_device for USB storage related nodes.
-
- If called for USB hub node with vendor ID == 0 and product_id == 0
- which is not the child of a PCI device, we get a warning.
- """
- parser = SubmissionParser(self.log)
- parser.submission_key = (
- 'UdevDevice.is_real_device, USB hub with odd parent.')
- devices = self.buildUdevDeviceHierarchy(
- self.usb_hub_with_odd_parent_hierarchy_data, parser)
- usb_hub = devices[self.usb_hub_path]
- self.assertFalse(usb_hub.is_real_device)
- self.assertWarningMessage(
- parser.submission_key,
- 'USB device found with vendor ID==0, product ID==0, '
- 'where the parent device does not look like a USB '
- 'host controller: %s' % self.usb_hub_path)
-
- def test_has_reliable_data_system(self):
- """Test of UdevDevice.has_reliable_data for a system."""
- root_device = UdevDevice(
- None, self.root_device, dmi_data=self.root_device_dmi_data)
- self.assertTrue(root_device.has_reliable_data)
-
- def test_has_reliable_data_system_no_vendor_name(self):
- """Test of UdevDevice.has_reliable_data for a system.
-
- If the DMI data does not provide vendor name, has_reliable_data
- is False.
- """
- del self.root_device_dmi_data['/sys/class/dmi/id/sys_vendor']
- root_device = UdevDevice(
- None, self.root_device, dmi_data=self.root_device_dmi_data)
- parser = SubmissionParser(self.log)
- parser.submission_key = 'root device without vendor name'
- root_device.parser = parser
- self.assertFalse(root_device.has_reliable_data)
- self.assertWarningMessage(
- parser.submission_key,
- "A UdevDevice that is supposed to be a real device does not "
- "provide bus, vendor ID, product ID or product name: "
- "<DBItem HWBus.SYSTEM, (0) System> None u'LIFEBOOK E8210' "
- "u'LIFEBOOK E8210' /devices/LNXSYSTM:00")
-
- def test_has_reliable_data_system_no_product_name(self):
- """Test of UdevDevice.has_reliable_data for a system.
-
- If the DMI data does not provide product name, has_reliable_data
- is False.
- """
- del self.root_device_dmi_data['/sys/class/dmi/id/product_name']
- root_device = UdevDevice(
- None, self.root_device, dmi_data=self.root_device_dmi_data)
- parser = SubmissionParser(self.log)
- parser.submission_key = 'root device without product name'
- root_device.parser = parser
- self.assertFalse(root_device.has_reliable_data)
- self.assertWarningMessage(
- parser.submission_key,
- "A UdevDevice that is supposed to be a real device does not "
- "provide bus, vendor ID, product ID or product name: "
- "<DBItem HWBus.SYSTEM, (0) System> u'FUJITSU SIEMENS' None None "
- "/devices/LNXSYSTM:00")
-
- def test_has_reliable_data_acpi_device(self):
- """Test of UdevDevice.has_reliable_data for an ACPI device.
-
- APCI devices are considered not to have reliable data. The only
- exception is the root device, see test_has_reliable_data_system.
- """
- acpi_device = UdevDevice(None, self.cpu_device_data)
- self.assertEqual('acpi', acpi_device.raw_bus)
- self.assertFalse(acpi_device.has_reliable_data)
-
- def test_has_reliable_data_platform_device(self):
- """Test of UdevDevice.has_reliable_data for a "platform" device.
-
- devices with raw_bus == 'platform' are considered not to have
- reliable data.
- """
- platform_device = UdevDevice(None, self.platform_device_data)
- self.assertFalse(platform_device.has_reliable_data)
-
- def test_has_reliable_data_pci_device(self):
- """Test of UdevDevice.has_reliable_data for a PCI device."""
- devices = self.buildUdevDeviceHierarchy(
- self.pci_bridge_pccard_hierarchy_data)
- pci_device = devices[self.pci_pccard_bridge_path]
- self.assertTrue(pci_device.has_reliable_data)
-
- def test_has_reliable_data_usb_device(self):
- """Test of UdevDevice.has_reliable_data for a USB device."""
- usb_device = UdevDevice(None, self.usb_storage_usb_device_data)
- self.assertTrue(usb_device.has_reliable_data)
-
- def test_has_reliable_data_scsi_device(self):
- """Test of UdevDevice.has_reliable_data for a SCSI device."""
- devices = self.buildUdevDeviceHierarchy(
- self.scsi_device_hierarchy_data)
- scsi_device = devices[self.scsi_scanner_device_path]
- self.assertTrue(scsi_device.has_reliable_data)
-
- def test_has_reliable_data_usb_interface_device(self):
- """Test of UdevDevice.has_reliable_data for a USB interface.
-
- UdevDevice.has_reliable_data should only be called for nodes
- where is_rel_device is True. If called for other nodes, we
- may get a warning because they do not provide reqired data,
- like a bus, vendor or product ID.
- """
- parser = SubmissionParser(self.log)
- parser.submission_key = (
- 'UdevDevice.has_reliable_data for a USB interface')
- usb_interface = UdevDevice(parser, self.usb_storage_usb_interface)
- self.assertFalse(usb_interface.has_reliable_data)
- self.assertWarningMessage(
- parser.submission_key,
- 'A UdevDevice that is supposed to be a real device does not '
- 'provide bus, vendor ID, product ID or product name: None None '
- 'None None /devices/pci0000:00/0000:00:1d.7/usb1/1-1/1-1:1.0')
-
- def test_warnings_not_suppressed(self):
- """Logging of warnings can be allowed."""
- parser = SubmissionParser(self.log)
- parser.submission_key = "log_with_warnings"
- parser._logWarning("This message is logged.")
- self.assertWarningMessage(
- parser.submission_key, "This message is logged.")
-
- def test_warnings_suppressed(self):
- """Logging of warnings can be suppressed."""
- number_of_existing_log_messages = len(self.handler.records)
- parser = SubmissionParser(self.log, record_warnings=False)
- parser.submission_key = "log_without_warnings"
- parser._logWarning("This message is not logged.")
- # No new warnings are recorded
- self.assertEqual(
- number_of_existing_log_messages, len(self.handler.records))
-
- def test_device_id(self):
- """Each UdevDevice has a property 'id'."""
- device = UdevDevice(None, self.root_device)
- self.assertEqual(1, device.id)
-
-
-class TestHWDBSubmissionTablePopulation(TestCaseHWDB):
- """Tests of the HWDB popoluation with submitted data."""
-
- layer = LaunchpadZopelessLayer
-
- HAL_COMPUTER = {
- 'id': 1,
- 'udi': TestCaseHWDB.UDI_COMPUTER,
- 'properties': {
- 'system.hardware.vendor': ('Lenovo', 'str'),
- 'system.hardware.product': ('T41', 'str'),
- 'system.kernel.version': (TestCaseHWDB.KERNEL_VERSION, 'str'),
- },
- }
-
- HAL_PCI_PCCARD_BRIDGE = {
- 'id': 2,
- 'udi': TestCaseHWDB.UDI_PCI_PCCARD_BRIDGE,
- 'properties': {
- 'info.bus': ('pci', 'str'),
- 'info.linux.driver': ('yenta_cardbus', 'str'),
- 'info.parent': (TestCaseHWDB.UDI_COMPUTER, 'str'),
- 'info.product': ('OZ711MP1/MS1 MemoryCardBus Controller', 'str'),
- 'pci.device_class': (PCI_CLASS_BRIDGE, 'int'),
- 'pci.device_subclass': (PCI_SUBCLASS_BRIDGE_CARDBUS, 'int'),
- 'pci.vendor_id': (TestCaseHWDB.PCI_VENDOR_ID_INTEL, 'int'),
- 'pci.product_id': (TestCaseHWDB.PCI_PROD_ID_PCI_PCCARD_BRIDGE,
- 'int'),
- },
- }
-
- HAL_PCCARD_DEVICE = {
- 'id': 3,
- 'udi': TestCaseHWDB.UDI_PCCARD_DEVICE,
- 'properties': {
- 'info.bus': ('pci', 'str'),
- 'info.parent': (TestCaseHWDB.UDI_PCI_PCCARD_BRIDGE, 'str'),
- 'info.product': ('ISL3890/ISL3886', 'str'),
- 'pci.device_class': (PCI_CLASS_SERIALBUS_CONTROLLER, 'int'),
- 'pci.device_subclass': (PCI_SUBCLASS_SERIALBUS_USB, 'int'),
- 'pci.vendor_id': (TestCaseHWDB.PCI_VENDOR_ID_INTEL, 'int'),
- 'pci.product_id': (TestCaseHWDB.PCI_PROD_ID_PCCARD_DEVICE, 'int'),
- },
- }
-
- HAL_USB_CONTROLLER_PCI_SIDE = {
- 'id': 4,
- 'udi': TestCaseHWDB.UDI_USB_CONTROLLER_PCI_SIDE,
- 'properties': {
- 'info.bus': ('pci', 'str'),
- 'info.linux.driver': ('ehci_hcd', 'str'),
- 'info.parent': (TestCaseHWDB.UDI_COMPUTER, 'str'),
- 'info.product': ('82801G (ICH7 Family) USB2 EHCI Controller',
- 'str'),
- 'pci.device_class': (PCI_CLASS_SERIALBUS_CONTROLLER, 'int'),
- 'pci.device_subclass': (PCI_SUBCLASS_SERIALBUS_USB, 'int'),
- 'pci.vendor_id': (TestCaseHWDB.PCI_VENDOR_ID_INTEL, 'int'),
- 'pci.product_id': (TestCaseHWDB.PCI_PROD_ID_USB_CONTROLLER,
- 'int'),
- },
- }
-
- HAL_USB_CONTROLLER_USB_SIDE = {
- 'id': 5,
- 'udi': TestCaseHWDB.UDI_USB_CONTROLLER_USB_SIDE,
- 'properties': {
- 'info.bus': ('usb_device', 'str'),
- 'info.linux.driver': ('usb', 'str'),
- 'info.parent': (TestCaseHWDB.UDI_USB_CONTROLLER_PCI_SIDE, 'str'),
- 'info.product': ('EHCI Host Controller', 'str'),
- 'usb_device.vendor_id': (0, 'int'),
- 'usb_device.product_id': (0, 'int'),
- },
- }
-
- HAL_USB_STORAGE_DEVICE = {
- 'id': 6,
- 'udi': TestCaseHWDB.UDI_USB_STORAGE,
- 'properties': {
- 'info.bus': ('usb_device', 'str'),
- 'info.linux.driver': ('usb', 'str'),
- 'info.parent': (TestCaseHWDB.UDI_USB_CONTROLLER_USB_SIDE, 'str'),
- 'info.product': ('USB Mass Storage Device', 'str'),
- 'usb_device.vendor_id': (TestCaseHWDB.USB_VENDOR_ID_USBEST,
- 'int'),
- 'usb_device.product_id': (
- TestCaseHWDB.USB_PROD_ID_USBBEST_MEMSTICK, 'int'),
- },
- }
-
- HAL_SCSI_CONTROLLER_PCI_SIDE = {
- 'id': 7,
- 'udi': TestCaseHWDB.UDI_SCSI_CONTROLLER_PCI_SIDE,
- 'properties': {
- 'info.bus': ('pci', 'str'),
- 'info.linux.driver': ('aic7xxx', 'str'),
- 'info.parent': (TestCaseHWDB.UDI_COMPUTER, 'str'),
- 'info.product': ('AIC-1480 / APA-1480', 'str'),
- 'pci.device_class': (PCI_CLASS_STORAGE, 'int'),
- 'pci.device_subclass': (TestCaseHWDB.PCI_SUBCLASS_STORAGE_SCSI,
- 'int'),
- 'pci.vendor_id': (TestCaseHWDB.PCI_VENDOR_ID_ADAPTEC, 'int'),
- 'pci.product_id': (TestCaseHWDB.PCI_PROD_ID_AIC1480, 'int'),
- },
- }
-
- HAL_SCSI_CONTROLLER_SCSI_SIDE = {
- 'id': 8,
- 'udi': TestCaseHWDB.UDI_SCSI_CONTROLLER_SCSI_SIDE,
- 'properties': {
- 'info.bus': ('scsi_host', 'str'),
- 'info.parent': (TestCaseHWDB.UDI_SCSI_CONTROLLER_PCI_SIDE, 'str'),
- 'info.linux.driver': ('sd', 'str'),
- }
- }
-
- HAL_SCSI_STORAGE_DEVICE = {
- 'id': 9,
- 'udi': TestCaseHWDB.UDI_SCSI_DISK,
- 'properties': {
- 'info.bus': ('scsi', 'str'),
- 'info.linux.driver': ('sd', 'str'),
- 'info.parent': (TestCaseHWDB.UDI_SCSI_CONTROLLER_SCSI_SIDE,
- 'str'),
- 'scsi.vendor': ('WDC', 'str'),
- 'scsi.model': ('WD12345678', 'str'),
- },
- }
-
- parsed_data = {
- 'hardware': {
- 'hal': {},
- },
- 'software': {
- 'packages': {
- TestCaseHWDB.KERNEL_PACKAGE: {},
- },
- },
- }
-
- def setUp(self):
- """Setup the test environment."""
- super(TestHWDBSubmissionTablePopulation, self).setUp()
- self.log = logging.getLogger('test_hwdb_submission_parser')
- self.log.setLevel(logging.INFO)
- self.handler = Handler(self)
- self.handler.add(self.log.name)
- switch_dbuser('hwdb-submission-processor')
-
- def getLogData(self):
- messages = [record.getMessage() for record in self.handler.records]
- return '\n'.join(messages)
-
- def setHALDevices(self, devices):
- self.parsed_data['hardware']['hal']['devices'] = devices
-
- def testGetDriverNoDriverInfo(self):
- """Test of HALDevice.getDriver()."""
- devices = [
- self.HAL_COMPUTER,
- ]
- self.setHALDevices(devices)
- parser = SubmissionParser(self.log)
- parser.buildDeviceList(self.parsed_data)
- device = parser.devices[self.UDI_COMPUTER]
- self.assertEqual(device.getDriver(), None,
- 'HALDevice.getDriver found a driver where none is expected.')
-
- def testGetDriverWithDriverInfo(self):
- """Test of HALDevice.getDriver()."""
- devices = [
- self.HAL_COMPUTER,
- self.HAL_PCI_PCCARD_BRIDGE,
- ]
- self.setHALDevices(devices)
- parser = SubmissionParser(self.log)
- parser.parsed_data = self.parsed_data
- parser.buildDeviceList(self.parsed_data)
- device = parser.devices[self.UDI_PCI_PCCARD_BRIDGE]
- driver = device.getDriver()
- self.assertNotEqual(driver, None,
- 'HALDevice.getDriver did not find a driver where one '
- 'is expected.')
- self.assertEqual(driver.name, 'yenta_cardbus',
- 'Unexpected result for driver.name. Got %r, expected '
- 'yenta_cardbus.' % driver.name)
- self.assertEqual(driver.package_name, self.KERNEL_PACKAGE,
- 'Unexpected result for driver.package_name. Got %r, expected '
- 'linux-image-2.6.24-19-generic' % driver.name)
-
- def testEnsureVendorIDVendorNameExistsRegularCase(self):
- """Test of ensureVendorIDVendorNameExists(self), regular case."""
- devices = [
- self.HAL_COMPUTER,
- ]
- self.setHALDevices(devices)
- parser = SubmissionParser(self.log)
- parser.parsed_data = self.parsed_data
- parser.buildDeviceList(self.parsed_data)
-
- # The database does not know yet about the vendor name
- # 'Lenovo'...
- vendor_name_set = getUtility(IHWVendorNameSet)
- vendor_name = vendor_name_set.getByName('Lenovo')
- self.assertEqual(vendor_name, None,
- 'Expected None looking up vendor name "Lenovo" in '
- 'HWVendorName, got %r.' % vendor_name)
-
- # ...as well as the vendor ID (which is identical to the vendor
- # name for systems).
- vendor_id_set = getUtility(IHWVendorIDSet)
- vendor_id = vendor_id_set.getByBusAndVendorID(HWBus.SYSTEM, 'Lenovo')
- self.assertEqual(vendor_id, None,
- 'Expected None looking up vendor ID "Lenovo" in '
- 'HWVendorID, got %r.' % vendor_id)
-
- # HALDevice.ensureVendorIDVendorNameExists() creates these
- # records.
- hal_system = parser.devices[self.UDI_COMPUTER]
- hal_system.ensureVendorIDVendorNameExists()
-
- vendor_name = vendor_name_set.getByName('Lenovo')
- self.assertEqual(vendor_name.name, 'Lenovo',
- 'Expected to find vendor name "Lenovo" in '
- 'HWVendorName, got %r.' % vendor_name.name)
-
- vendor_id = vendor_id_set.getByBusAndVendorID(HWBus.SYSTEM, 'Lenovo')
- self.assertEqual(vendor_id.vendor_id_for_bus, 'Lenovo',
- 'Expected "Lenovo" as vendor_id_for_bus, '
- 'got %r.' % vendor_id.vendor_id_for_bus)
- self.assertEqual(vendor_id.bus, HWBus.SYSTEM,
- 'Expected HWBUS.SYSTEM as bus, got %s.'
- % vendor_id.bus.title)
-
- def runTestEnsureVendorIDVendorNameExistsVendorNameUnknown(
- self, devices, test_bus, test_vendor_id, test_udi):
- """Test of ensureVendorIDVendorNameExists(self), special case.
-
- A HWVendorID record is not created by
- HALDevice.ensureVendorIDVendorNameExists for certain buses.
- """
- self.setHALDevices(devices)
- parser = SubmissionParser(self.log)
- parser.parsed_data = self.parsed_data
- parser.buildDeviceList(self.parsed_data)
-
- hal_device = parser.devices[test_udi]
- hal_device.ensureVendorIDVendorNameExists()
-
- vendor_id_set = getUtility(IHWVendorIDSet)
- vendor_id = vendor_id_set.getByBusAndVendorID(
- test_bus, test_vendor_id)
- self.assertEqual(vendor_id, None,
- 'Expected None looking up vendor ID %s for bus %s in HWVendorID, '
- 'got %r.' % (test_vendor_id, test_bus.title, vendor_id))
-
- def testEnsureVendorIDVendorNameExistsVendorPCI(self):
- """Test of ensureVendorIDVendorNameExists(self), PCI bus."""
- devices = [
- self.HAL_COMPUTER,
- self.HAL_PCI_PCCARD_BRIDGE
- ]
- self.runTestEnsureVendorIDVendorNameExistsVendorNameUnknown(
- devices, HWBus.PCI, '0x8086', self.UDI_PCI_PCCARD_BRIDGE)
-
- def testEnsureVendorIDVendorNameExistsVendorPCCARD(self):
- """Test of ensureVendorIDVendorNameExists(self), PCCARD bus."""
- devices = [
- self.HAL_COMPUTER,
- self.HAL_PCI_PCCARD_BRIDGE,
- self.HAL_PCCARD_DEVICE,
- ]
- self.runTestEnsureVendorIDVendorNameExistsVendorNameUnknown(
- devices, HWBus.PCCARD, '0x8086', self.UDI_PCCARD_DEVICE)
-
- def testEnsureVendorIDVendorNameExistVendorUSB(self):
- """Test of ensureVendorIDVendorNameExists(self), USB bus."""
- devices = [
- self.HAL_COMPUTER,
- self.HAL_USB_CONTROLLER_PCI_SIDE,
- self.HAL_USB_CONTROLLER_USB_SIDE,
- self.HAL_USB_STORAGE_DEVICE,
- ]
- self.runTestEnsureVendorIDVendorNameExistsVendorNameUnknown(
- devices, HWBus.USB, '0x1307', self.UDI_USB_STORAGE)
-
- def testEnsureVendorIDVendorNameExistVendorSCSI(self):
- """Test of ensureVendorIDVendorNameExists(self), SCSI bus."""
- devices = [
- self.HAL_COMPUTER,
- self.HAL_SCSI_CONTROLLER_PCI_SIDE,
- self.HAL_SCSI_CONTROLLER_SCSI_SIDE,
- self.HAL_SCSI_STORAGE_DEVICE,
- ]
-
- self.setHALDevices(devices)
- parser = SubmissionParser(self.log)
- parser.parsed_data = self.parsed_data
- parser.buildDeviceList(self.parsed_data)
-
- # The database does not know yet about the vendor name
- # 'WDC'...
- vendor_name_set = getUtility(IHWVendorNameSet)
- vendor_name = vendor_name_set.getByName('WDC')
- self.assertEqual(vendor_name, None,
- 'Expected None looking up vendor name "WDC" in '
- 'HWVendorName, got %r.' % vendor_name)
-
- # ...as well as the vendor ID (which is identical to the vendor
- # name for SCSI devices).
- vendor_id_set = getUtility(IHWVendorIDSet)
- # Note that we must provide a string with exactly 8 characters
- # as the vendor ID of a SCSI device.
- vendor_id = vendor_id_set.getByBusAndVendorID(HWBus.SCSI, 'WDC ')
- self.assertEqual(vendor_id, None,
- 'Expected None looking up vendor ID "WDC " in '
- 'HWVendorID for the SCSI bus, got %r.' % vendor_id)
-
- # HALDevice.ensureVendorIDVendorNameExists() creates these
- # records.
- scsi_disk = parser.devices[self.UDI_SCSI_DISK]
- scsi_disk.ensureVendorIDVendorNameExists()
-
- vendor_name = vendor_name_set.getByName('WDC')
- self.assertEqual(vendor_name.name, 'WDC',
- 'Expected to find vendor name "WDC" in '
- 'HWVendorName, got %r.' % vendor_name.name)
-
- vendor_id = vendor_id_set.getByBusAndVendorID(HWBus.SCSI, 'WDC ')
- self.assertEqual(vendor_id.vendor_id_for_bus, 'WDC ',
- 'Expected "WDC " as vendor_id_for_bus, '
- 'got %r.' % vendor_id.vendor_id_for_bus)
- self.assertEqual(vendor_id.bus, HWBus.SCSI,
- 'Expected HWBUS.SCSI as bus, got %s.'
- % vendor_id.bus.title)
-
- def testCreateDBDataForSimpleDevice(self):
- """Test of HALDevice.createDBData.
-
- Test for a HAL device without driver data.
- """
- devices = [
- self.HAL_COMPUTER,
- ]
- self.setHALDevices(devices)
-
- parser = SubmissionParser(self.log)
- parser.buildDeviceList(self.parsed_data)
-
- submission_set = getUtility(IHWSubmissionSet)
- submission = submission_set.getBySubmissionKey('test_submission_id_1')
-
- hal_device = parser.devices[self.UDI_COMPUTER]
- hal_device.createDBData(submission, None)
-
- # HALDevice.createDBData created a HWDevice record.
- vendor_id_set = getUtility(IHWVendorIDSet)
- vendor_id = vendor_id_set.getByBusAndVendorID(HWBus.SYSTEM, 'Lenovo')
- hw_device_set = getUtility(IHWDeviceSet)
- hw_device = hw_device_set.getByDeviceID(
- hal_device.real_bus, hal_device.vendor_id,
- hal_device.product_id)
- self.assertEqual(hw_device.bus_vendor, vendor_id,
- 'Expected vendor ID (HWBus.SYSTEM, Lenovo) as the vendor ID, '
- 'got %s %r' % (hw_device.bus_vendor.bus,
- hw_device.bus_vendor.vendor_name.name))
- self.assertEqual(hw_device.bus_product_id, 'T41',
- 'Expected product ID T41, got %r.' % hw_device.bus_product_id)
- self.assertEqual(hw_device.name, 'T41',
- 'Expected device name T41, got %r.' % hw_device.name)
-
- # One HWDeviceDriverLink record is created...
- device_driver_link_set = getUtility(IHWDeviceDriverLinkSet)
- device_driver_link = device_driver_link_set.getByDeviceAndDriver(
- hw_device, None)
- self.assertEqual(device_driver_link.device, hw_device,
- 'Expected HWDevice record for Lenovo T41 in HWDeviceDriverLink, '
- 'got %s %r'
- % (device_driver_link.device.bus_vendor.bus,
- device_driver_link.device.bus_vendor.vendor_name.name))
- self.assertEqual(device_driver_link.driver, None,
- 'Expected None as driver in HWDeviceDriverLink')
-
- # ...and one HWSubmissionDevice record linking the HWDeviceSriverLink
- # to the submission.
- submission_device_set = getUtility(IHWSubmissionDeviceSet)
- submission_devices = submission_device_set.getDevices(submission)
- self.assertEqual(len(list(submission_devices)), 1,
- 'Unexpected number of submission devices: %i, expected 1.'
- % len(list(submission_devices)))
- submission_device = submission_devices[0]
- self.assertEqual(
- submission_device.device_driver_link, device_driver_link,
- 'Invalid device_driver_link field in HWSubmissionDevice.')
- self.assertEqual(
- submission_device.parent, None,
- 'Invalid parent field in HWSubmissionDevice.')
- self.assertEqual(
- submission_device.hal_device_id, 1,
- 'Invalid haL-device_id field in HWSubmissionDevice.')
-
- def testCreateDBDataForDeviceWithOneDriver(self):
- """Test of HALDevice.createDBData.
-
- Test of a HAL device with one driver.
- """
- devices = [
- self.HAL_COMPUTER,
- self.HAL_PCI_PCCARD_BRIDGE,
- ]
- self.setHALDevices(devices)
-
- parser = SubmissionParser(self.log)
- parser.buildDeviceList(self.parsed_data)
- parser.parsed_data = self.parsed_data
-
- submission_set = getUtility(IHWSubmissionSet)
- submission = submission_set.getBySubmissionKey('test_submission_id_1')
-
- hal_root_device = parser.devices[self.UDI_COMPUTER]
- hal_root_device.createDBData(submission, None)
-
- # We now have a HWDevice record for the PCCard bridge...
- device_set = getUtility(IHWDeviceSet)
- pccard_bridge = device_set.getByDeviceID(
- HWBus.PCI, '0x%04x' % self.PCI_VENDOR_ID_INTEL,
- '0x%04x' % self.PCI_PROD_ID_PCI_PCCARD_BRIDGE)
-
- # ...and a HWDriver record for the yenta_cardbus driver.
- driver_set = getUtility(IHWDriverSet)
- yenta_driver = driver_set.getByPackageAndName(
- self.KERNEL_PACKAGE, 'yenta_cardbus')
- self.assertEqual(
- yenta_driver.name, 'yenta_cardbus',
- 'Unexpected driver name: %r' % yenta_driver.name)
- self.assertEqual(
- yenta_driver.package_name, self.KERNEL_PACKAGE,
- 'Unexpected package name: %r' % yenta_driver.package_name)
-
- # The PCCard bridge has one HWDeviceDriverLink record without
- # an associated driver...
- device_driver_link_set = getUtility(IHWDeviceDriverLinkSet)
- pccard_link_no_driver = device_driver_link_set.getByDeviceAndDriver(
- pccard_bridge, None)
- self.assertEqual(
- pccard_link_no_driver.device, pccard_bridge,
- 'Unexpected value of pccard_link_no_driver.device')
- self.assertEqual(
- pccard_link_no_driver.driver, None,
- 'Unexpected value of pccard_link_no_driver.driver')
-
- # ...and another one with the yenta driver.
- pccard_link_yenta = device_driver_link_set.getByDeviceAndDriver(
- pccard_bridge, yenta_driver)
- self.assertEqual(
- pccard_link_yenta.device, pccard_bridge,
-