Merge lp:~roadmr/ubuntu/oneiric/checkbox/0.13 into lp:ubuntu/oneiric/checkbox

Proposed by Daniel Manrique
Status: Superseded
Proposed branch: lp:~roadmr/ubuntu/oneiric/checkbox/0.13
Merge into: lp:ubuntu/oneiric/checkbox
Diff against target: 18858 lines (+9936/-3266)
93 files modified
checkbox/application.py (+5/-5)
checkbox/contrib/persist.py (+5/-4)
checkbox/dispatcher.py (+201/-0)
checkbox/lib/bit.py (+5/-4)
checkbox/lib/config.py (+15/-2)
checkbox/lib/conversion.py (+131/-42)
checkbox/lib/dmi.py (+169/-18)
checkbox/lib/safe.py (+5/-0)
checkbox/lib/template.py (+1/-1)
checkbox/message.py (+4/-3)
checkbox/parsers/cpuinfo.py (+30/-41)
checkbox/parsers/cputable (+40/-0)
checkbox/parsers/cputable.py (+42/-0)
checkbox/parsers/deferred.py (+27/-0)
checkbox/parsers/dmidecode.py (+123/-0)
checkbox/parsers/meminfo.py (+46/-0)
checkbox/parsers/submission.py (+474/-383)
checkbox/parsers/udevadm.py (+178/-317)
checkbox_cli/cli_interface.py (+9/-1)
checkbox_gtk/gtk_interface.py (+4/-4)
data/whitelists/default.whitelist (+1/-0)
debian/changelog (+59/-0)
debian/po/ro.po (+118/-0)
examples/checkbox.ini (+1/-1)
gtk/checkbox-gtk.ui (+37/-37)
jobs/apport.txt.in (+0/-5)
jobs/audio.txt.in (+44/-24)
jobs/autotest.txt.in (+4/-2)
jobs/bluetooth.txt.in (+64/-52)
jobs/camera.txt.in (+19/-12)
jobs/codecs.txt.in (+16/-38)
jobs/cpu.txt.in (+3/-3)
jobs/daemons.txt.in (+11/-11)
jobs/disk.txt.in (+6/-5)
jobs/evolution.txt.in (+0/-26)
jobs/fingerprint.txt.in (+24/-20)
jobs/firewire.txt.in (+9/-8)
jobs/gcalctool.txt.in (+0/-52)
jobs/gedit.txt.in (+0/-22)
jobs/gnome-terminal.txt.in (+0/-12)
jobs/graphics.txt.in (+63/-51)
jobs/hibernate.txt.in (+9/-7)
jobs/info.txt.in (+47/-27)
jobs/input.txt.in (+15/-7)
jobs/install.txt.in (+1/-1)
jobs/keys.txt.in (+58/-45)
jobs/local.txt.in (+41/-6)
jobs/ltp.txt.in (+3/-2)
jobs/mago.txt.in (+4/-2)
jobs/mediacard.txt.in (+106/-84)
jobs/memory.txt.in (+8/-5)
jobs/miscellanea.txt.in (+19/-8)
jobs/monitor.txt.in (+43/-24)
jobs/networking.txt.in (+31/-32)
jobs/optical.txt.in (+56/-42)
jobs/panel_clock_test.txt.in (+18/-15)
jobs/panel_reboot.txt.in (+8/-6)
jobs/pcmcia-pcix.txt.in (+6/-3)
jobs/peripheral.txt.in (+27/-22)
jobs/phoronix.txt.in (+4/-2)
jobs/power-management.txt.in (+32/-18)
jobs/qa_regression.txt.in (+4/-2)
jobs/resource.txt.in (+15/-0)
jobs/screenshot.txt.in (+0/-13)
jobs/server-services.txt.in (+12/-12)
jobs/stress.txt.in (+18/-10)
jobs/suspend.txt.in (+52/-31)
jobs/usb.txt.in (+55/-36)
jobs/user_apps.txt.in (+337/-110)
jobs/wireless.txt.in (+9/-9)
plugins/apport_prompt.py (+1/-1)
plugins/launchpad_report.py (+6/-4)
plugins/persist_info.py (+2/-1)
plugins/resource_info.py (+14/-1)
plugins/system_info.py (+2/-2)
po/POTFILES.in (+0/-6)
po/ca@valencia.po (+2897/-0)
po/el.po (+229/-293)
po/en_GB.po (+240/-240)
po/gd.po (+2606/-0)
po/ja.po (+297/-335)
po/lt.po (+294/-357)
po/tr.po (+217/-177)
scripts/connect_wireless (+1/-1)
scripts/cpuinfo_resource (+13/-17)
scripts/dmi_resource (+55/-0)
scripts/hal_resource (+0/-5)
scripts/meminfo_resource (+15/-27)
scripts/package_resource (+6/-0)
scripts/udev_resource (+2/-2)
scripts/usb_test (+5/-3)
setup.cfg (+1/-7)
setup.py (+2/-0)
To merge this branch: bzr merge lp:~roadmr/ubuntu/oneiric/checkbox/0.13
Reviewer Review Type Date Requested Status
Ubuntu Sponsors Pending
Review via email: mp+82719@code.launchpad.net

This proposal has been superseded by a proposal from 2011-11-24.

To post a comment you must log in.
Revision history for this message
Sebastien Bacher (seb128) wrote :

Thank you for your work, I'm sponsoring it to precise but I can't set the merge request to merged since you targetted oneiric which is the wrong serie and launchpad will not let me edit it, could you do that?

Unmerged revisions

36. By Daniel Manrique

New upstream release (LP: #892268):
* Generate a submission.xml file that contains all device and attachment
* Write the report before reporting the validation error.
* Changed device.product to dmi.product for the formfactor (LP: #875312)
* Use gettext for string (LP: #869267)
* Move progress indicator to main checkbox dialog instead of a
  transient window (LP: #868995)
* Ignore malformed dpkg entries in package_resource (LP: #794747)
* Reset window title after finishing a manual test (LP: #874690)
* Handle "@" in locale names (as in ca@valencia).
* Went through all the job files and:
  * Updated descriptions to match Unity UI structure
  * Added descriptions where necessary
  * Added further details to some descriptions
  * Moved some jobs to more appropriate files
  * Fixed job names in older job files to match new naming scheme
    (suite/testname)
  * Added jobs to local.txt to ensure all job files are now parsed
    (this allows easier addition of existing tests to whitelists)
  * Changed remaining manual job descriptions to match the new format
* Updated CD and DVD write tests to be more clear about when to skip
  them (LP: #772794)
* Rewrote all job descriptions to match OEM QA syntax
* Fix the code that assigns keys in checkbox-cli so that it never assigns
  keys which have other uses. (LP: #877467)
* Show details of unmet job requirements (LP: #855852)
* Ensure that connect_wireless chooses a wireless connection from the list
  of available connections (LP: #877752)
* Have the bluetooth/detect tests require a device with the category
  BLUETOOTH to run, thus preventing the test from failing on systems with
  no Bluetooth device (LP: #862322)
* Rename attachment jobs to not have a forward slash in their name
  (LP: #887964)
* Guard against trying to write files to logical partitions on USB sticks
  (which will obviously fail) in usb_test (LP: #887049)
* Make the OpenGL test ignore the return value of glxgears and improve
  the test description (LP: #890725)
* Allow input/mouse test to run if a TOUCH device is present
  (LP: #886129)
* Broken job dependencies fixed (LP: #888447)
* Regex support when specifying blacklists and whitelists on the
  commandline (LP: #588647)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'checkbox/application.py'
--- checkbox/application.py 2011-02-14 18:19:27 +0000
+++ checkbox/application.py 2011-11-18 18:04:27 +0000
@@ -81,13 +81,13 @@
81 default=[],81 default=[],
82 help=_("Configuration override parameters."))82 help=_("Configuration override parameters."))
83 parser.add_option("-b", "--blacklist",83 parser.add_option("-b", "--blacklist",
84 help=_("Shorthand for --config=checkbox/plugins/jobs_info/blacklist."))84 help=_("Shorthand for --config=.*/jobs_info/blacklist."))
85 parser.add_option("-B", "--blacklist-file",85 parser.add_option("-B", "--blacklist-file",
86 help=_("Shorthand for --config=checkbox/plugins/jobs_info/blacklist_file."))86 help=_("Shorthand for --config=.*/jobs_info/blacklist_file."))
87 parser.add_option("-w", "--whitelist",87 parser.add_option("-w", "--whitelist",
88 help=_("Shorthand for --config=checkbox/plugins/jobs_info/whitelist."))88 help=_("Shorthand for --config=.*/jobs_info/whitelist."))
89 parser.add_option("-W", "--whitelist-file",89 parser.add_option("-W", "--whitelist-file",
90 help=_("Shorthand for --config=checkbox/plugins/jobs_info/whitelist_file."))90 help=_("Shorthand for --config=.*/jobs_info/whitelist_file."))
91 return parser.parse_args(args)91 return parser.parse_args(args)
9292
93 def create_application(self, args=sys.argv):93 def create_application(self, args=sys.argv):
@@ -102,7 +102,7 @@
102102
103 # Replace shorthands103 # Replace shorthands
104 for shorthand in "blacklist", "blacklist_file", "whitelist", "whitelist_file":104 for shorthand in "blacklist", "blacklist_file", "whitelist", "whitelist_file":
105 key = "checkbox/plugins/jobs_info/%s" % shorthand105 key = ".*/jobs_info/%s" % shorthand
106 value = getattr(options, shorthand)106 value = getattr(options, shorthand)
107 if value:107 if value:
108 options.config.append("=".join([key, value]))108 options.config.append("=".join([key, value]))
109109
=== modified file 'checkbox/contrib/persist.py'
--- checkbox/contrib/persist.py 2011-02-14 18:19:27 +0000
+++ checkbox/contrib/persist.py 2011-11-18 18:04:27 +0000
@@ -23,6 +23,7 @@
23import re23import re
24import posixpath24import posixpath
2525
26from checkbox.lib.safe import safe_close
2627
27__all__ = ["Persist", "MemoryBackend", "PickleBackend", "BPickleBackend",28__all__ = ["Persist", "MemoryBackend", "PickleBackend", "BPickleBackend",
28 "path_string_to_tuple", "path_tuple_to_string", "RootedPersist",29 "path_string_to_tuple", "path_tuple_to_string", "RootedPersist",
@@ -517,14 +518,14 @@
517 try:518 try:
518 return self._pickle.load(file)519 return self._pickle.load(file)
519 finally:520 finally:
520 file.close()521 safe_close(file)
521522
522 def save(self, filepath, map):523 def save(self, filepath, map):
523 file = open(filepath, "w")524 file = open(filepath, "w")
524 try:525 try:
525 self._pickle.dump(map, file, 2)526 self._pickle.dump(map, file, 2)
526 finally:527 finally:
527 file.close()528 safe_close(file)
528529
529530
530class BPickleBackend(Backend):531class BPickleBackend(Backend):
@@ -538,11 +539,11 @@
538 try:539 try:
539 return self._bpickle.loads(file.read())540 return self._bpickle.loads(file.read())
540 finally:541 finally:
541 file.close()542 safe_close(file)
542543
543 def save(self, filepath, map):544 def save(self, filepath, map):
544 file = open(filepath, "w")545 file = open(filepath, "w")
545 try:546 try:
546 file.write(self._bpickle.dumps(map))547 file.write(self._bpickle.dumps(map))
547 finally:548 finally:
548 file.close()549 safe_close(file)
549550
=== added file 'checkbox/dispatcher.py'
--- checkbox/dispatcher.py 1970-01-01 00:00:00 +0000
+++ checkbox/dispatcher.py 2011-11-18 18:04:27 +0000
@@ -0,0 +1,201 @@
1# Copyright 2010-2011 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).
3
4__metaclass__ = type
5
6__all__ = [
7 "Dispatcher",
8 "DispatcherList",
9 "DispatcherQueue",
10 ]
11
12import logging
13
14from itertools import product
15
16
17class Event:
18 """Event payload containing the positional and keywoard arguments
19 passed to the handler in the event listener."""
20
21 def __init__(self, type, *args, **kwargs):
22 self.type = type
23 self.args = args
24 self.kwargs = kwargs
25
26
27class Listener:
28 """Event listener notified when events are published by the dispatcher."""
29
30 def __init__(self, event_type, handler, count):
31 self.event_type = event_type
32 self.handler = handler
33 self.count = count
34
35 def notify(self, event):
36 """Notify the handler with the payload of the event.
37
38 :param event: The event containint the payload for the handler.
39 """
40 if self.count is None or self.count:
41 self.handler(*event.args, **event.kwargs)
42 if self.count:
43 self.count -= 1
44
45
46class ListenerList(Listener):
47 """Event listener notified for lists of events."""
48
49 def __init__(self, *args, **kwargs):
50 super(ListenerList, self).__init__(*args, **kwargs)
51 self.event_types = set(self.event_type)
52 self.kwargs = {}
53
54 def notify(self, event):
55 """Only notify the handler when all the events for this listener
56 have been published by the dispatcher. When duplicate events
57 occur, the latest event is preserved and the previous one are
58 overwritten until all events have been published.
59 """
60 if self.count is None or self.count:
61 self.kwargs[event.type] = event.args[0]
62 if self.event_types.issubset(self.kwargs):
63 self.handler(**self.kwargs)
64 if self.count:
65 self.count -= 1
66
67
68class ListenerQueue(ListenerList):
69
70 def notify(self, event):
71 """Only notify the handler when all the events for this listener
72 have been published by the dispatcher. Duplicate events are enqueued
73 and dequeued only when all events have been published.
74 """
75 arg = event.args[0]
76 queue = self.kwargs.setdefault(event.type, [])
77
78 # Strip duplicates from the queue.
79 if arg not in queue:
80 queue.append(arg)
81
82 # Once the queue has handler has been called, the queue
83 # then behaves like a list using the latest events.
84 if self.event_types.issubset(self.kwargs):
85 self.notify = notify = super(ListenerQueue, self).notify
86 keys = self.kwargs.keys()
87 for values in product(*self.kwargs.values()):
88 self.kwargs = dict(zip(keys, values))
89 notify(event)
90
91
92class Dispatcher:
93 """Register handlers and publish events for them identified by strings."""
94
95 listener_factory = Listener
96
97 def __init__(self, listener_factory=None):
98 self._event_listeners = {}
99
100 if listener_factory is not None:
101 self.listener_factory = listener_factory
102
103 def registerHandler(self, event_type, handler, count=None):
104 """Register an event handler and return its listener.
105
106 :param event_type: The name of the event type to handle.
107 :param handler: The function handling the given event type.
108 :param count: Optionally, the number times to call the handler.
109 """
110 listener = self.listener_factory(event_type, handler, count)
111
112 listeners = self._event_listeners.setdefault(event_type, [])
113 listeners.append(listener)
114
115 return listener
116
117 def unregisterHandler(self, handler):
118 """Unregister a handler.
119
120 :param handler: The handler to unregister.
121 """
122 for event_type, listeners in self._event_listeners.items():
123 listeners = [
124 listener for listener in listeners
125 if listener.handler == handler]
126 if listeners:
127 self._event_listeners[event_type] = listeners
128 else:
129 del self._event_listeners[event_type]
130
131 def unregisterListener(self, listener, event_type=None):
132 """Unregister a listener.
133
134 :param listener: The listener of the handler to unregister.
135 :param event_type: Optionally, the event_type to unregister.
136 """
137 if event_type is None:
138 event_type = listener.event_type
139
140 self._event_listeners[event_type].remove(listener)
141 if not self._event_listeners[event_type]:
142 del self._event_listeners[event_type]
143
144 def publishEvent(self, event_type, *args, **kwargs):
145 """Publish an event of a given type and notify all listeners.
146
147 :param event_type: The name of the event type to publish.
148 :param args: Positional arguments to pass to the registered handlers.
149 :param kwargs: Keyword arguments to pass to the registered handlers.
150 """
151 if event_type in self._event_listeners:
152 event = Event(event_type, *args, **kwargs)
153 for listener in list(self._event_listeners[event_type]):
154 try:
155 listener.notify(event)
156 if listener.count is not None and not listener.count:
157 self.unregisterListener(listener)
158 except:
159 logging.exception(
160 "Error running event handler for %r with args %r %r",
161 event_type, args, kwargs)
162
163
164class DispatcherList(Dispatcher):
165 """
166 Register handlers and publish events for them identified by lists
167 of strings.
168 """
169
170 listener_factory = ListenerList
171
172 def registerHandler(self, event_types, handler, count=None):
173 """See Dispatcher."""
174 if not isinstance(event_types, (list, tuple,)):
175 event_types = (event_types,)
176
177 listener = self.listener_factory(event_types, handler, count)
178 for event_type in event_types:
179 listeners = self._event_listeners.setdefault(event_type, [])
180 listeners.append(listener)
181
182 return listener
183
184 def unregisterListener(self, listener):
185 """See Dispatcher."""
186 for event_type in listener.event_types:
187 super(DispatcherList, self).unregisterListener(
188 listener, event_type)
189
190 def publishEvent(self, event_type, arg):
191 """See Dispatcher."""
192 super(DispatcherList, self).publishEvent(event_type, arg)
193
194
195class DispatcherQueue(DispatcherList):
196 """
197 Register handlers and publish events for them identified by lists
198 of strings in queue order.
199 """
200
201 listener_factory = ListenerQueue
0202
=== modified file 'checkbox/lib/bit.py'
--- checkbox/lib/bit.py 2011-02-14 18:19:27 +0000
+++ checkbox/lib/bit.py 2011-11-18 18:04:27 +0000
@@ -36,10 +36,11 @@
3636
37 return bitcount37 return bitcount
3838
39def test_bit(bit, bitmask):39def test_bit(bit, bitmask, bits=None):
40 bits_per_long = calcsize("l") * 840 if bits is None:
41 offset = bit % bits_per_long41 bits = calcsize("l") * 8
42 long = int(bit / bits_per_long)42 offset = bit % bits
43 long = int(bit / bits)
43 if long >= len(bitmask):44 if long >= len(bitmask):
44 return 045 return 0
45 return (bitmask[long] >> offset) & 146 return (bitmask[long] >> offset) & 1
4647
=== modified file 'checkbox/lib/config.py'
--- checkbox/lib/config.py 2011-07-01 11:37:27 +0000
+++ checkbox/lib/config.py 2011-11-18 18:04:27 +0000
@@ -122,10 +122,23 @@
122 raise Exception, "Invalid config string: %s" % config122 raise Exception, "Invalid config string: %s" % config
123123
124 (name, option, value) = match.groups()124 (name, option, value) = match.groups()
125 if not self._parser.has_section(name):125
126 # Match section names
127 name_regex = re.compile(name)
128 sections = [section for section in self._parser.sections()
129 if name_regex.match(section)]
130
131 if not sections:
126 self._parser.add_section(name)132 self._parser.add_section(name)
133 sections.append(name)
127134
128 self._parser.set(name, option, value)135 for section in sections:
136 logging.debug('Setting configuration parameter: '
137 '%(section)s/%(option)s = %(value)s'
138 % {'section': section,
139 'option': option,
140 'value': value})
141 self._parser.set(section, option, value)
129142
130 def read_file(self, file, filename="<stream>"):143 def read_file(self, file, filename="<stream>"):
131 logging.info("Reading configurations from: %s", filename)144 logging.info("Reading configurations from: %s", filename)
132145
=== modified file 'checkbox/lib/conversion.py'
--- checkbox/lib/conversion.py 2009-01-20 18:55:20 +0000
+++ checkbox/lib/conversion.py 2011-11-18 18:04:27 +0000
@@ -18,48 +18,110 @@
18#18#
19import re19import re
2020
2121from dateutil import tz
22def string_to_type(value):22from datetime import (
23 conversion_table = (23 datetime,
24 ("(yes|true)", lambda v: True),24 timedelta,
25 ("(no|false)", lambda v: False),25 )
26 ("\d+", lambda v: int(v.group(0))),26
27 ("\d+\.\d+", lambda v: float(v.group(0))),27
28 ("(\d+) ?([kmgt]?b?)", lambda v: int(v.group(1))),28DATETIME_RE = re.compile(r"""
29 ("(\d+\.\d+) ?([kmgt]?b?)", lambda v: float(v.group(1))),29 ^(?P<year>\d\d\d\d)-?(?P<month>\d\d)-?(?P<day>\d\d)
30 ("(\d+) ?([kmgt]?hz?)", lambda v: int(v.group(1))),30 T(?P<hour>\d\d):?(?P<minute>\d\d):?(?P<second>\d\d)
31 ("(\d+\.\d+) ?([kmgt]?hz?)", lambda v: float(v.group(1))))31 (?:\.(?P<second_fraction>\d{0,6}))?
3232 (?P<tz>
33 multiplier_table = (33 (?:(?P<tz_sign>[-+])(?P<tz_hour>\d\d):(?P<tz_minute>\d\d))
34 ("b", 1),34 | Z)?$
35 ("kb?", 1024),35 """, re.VERBOSE)
36 ("mb?", 1024 * 1024),36
37 ("gb?", 1024 * 1024 * 1024),37TYPE_FORMATS = (
38 ("tb?", 1024 * 1024 * 1024 * 1024),38 (r"(yes|true)", lambda v: True),
39 ("hz", 1),39 (r"(no|false)", lambda v: False),
40 ("khz?", 1024),40 (r"-?\d+", lambda v: int(v.group(0))),
41 ("mhz?", 1024 * 1024),41 (r"-?\d+\.\d+", lambda v: float(v.group(0))),
42 ("ghz?", 1024 * 1024 * 1024),42 (r"(-?\d+) ?([kmgt]?b?)", lambda v: int(v.group(1))),
43 ("thz?", 1024 * 1024 * 1024 * 1024))43 (r"(-?\d+\.\d+) ?([kmgt]?b?)", lambda v: float(v.group(1))),
4444 (r"(-?\d+) ?([kmgt]?hz)", lambda v: int(v.group(1))),
45 if isinstance(value, basestring):45 (r"(-?\d+\.\d+) ?([kmgt]?hz)", lambda v: float(v.group(1))))
46 for regex, conversion in conversion_table:46TYPE_FORMATS = tuple(
47 match = re.match("^%s$" % regex, value, re.IGNORECASE)47 (re.compile(r"^%s$" % pattern, re.IGNORECASE), format)
48 if match:48 for pattern, format in TYPE_FORMATS)
49 value = conversion(match)49
50 if len(match.groups()) < 2:50TYPE_MULTIPLIERS = (
51 return value51 (r"b", 1),
5252 (r"kb?", 1024),
53 unit = match.group(2)53 (r"mb?", 1024 * 1024),
54 for regex, multiplier in multiplier_table:54 (r"gb?", 1024 * 1024 * 1024),
55 match = re.match("^%s$" % regex, unit, re.IGNORECASE)55 (r"tb?", 1024 * 1024 * 1024 * 1024),
56 if match:56 (r"hz", 1),
57 value *= multiplier57 (r"khz?", 1024),
58 return value58 (r"mhz?", 1024 * 1024),
59 else:59 (r"ghz?", 1024 * 1024 * 1024),
60 raise Exception, "Unknown multiplier: %s" % unit60 (r"thz?", 1024 * 1024 * 1024 * 1024))
6161TYPE_MULTIPLIERS = tuple(
62 return value62 (re.compile(r"^%s$" % pattern, re.IGNORECASE), multiplier)
63 for pattern, multiplier in TYPE_MULTIPLIERS)
64
65
66def datetime_to_string(dt):
67 """Return a consistent string representation for a given datetime.
68
69 :param dt: The datetime object.
70 """
71 return dt.isoformat()
72
73def string_to_datetime(string):
74 """Return a datetime object from a consistent string representation.
75
76 :param string: The string representation.
77 """
78 # we cannot use time.strptime: this function accepts neither fractions
79 # of a second nor a time zone given e.g. as '+02:30'.
80 match = DATETIME_RE.match(string)
81
82 # The Relax NG schema allows a leading minus sign and year numbers
83 # with more than four digits, which are not "covered" by _time_regex.
84 if not match:
85 raise ValueError("Datetime with unreasonable value: %s" % string)
86
87 time_parts = match.groupdict()
88
89 year = int(time_parts['year'])
90 month = int(time_parts['month'])
91 day = int(time_parts['day'])
92 hour = int(time_parts['hour'])
93 minute = int(time_parts['minute'])
94 second = int(time_parts['second'])
95 second_fraction = time_parts['second_fraction']
96 if second_fraction is not None:
97 milliseconds = second_fraction + '0' * (6 - len(second_fraction))
98 milliseconds = int(milliseconds)
99 else:
100 milliseconds = 0
101
102 # The Relax NG validator accepts leap seconds, but the datetime
103 # constructor rejects them. The time values submitted by the HWDB
104 # client are not necessarily very precise, hence we can round down
105 # to 59.999999 seconds without losing any real precision.
106 if second > 59:
107 second = 59
108 milliseconds = 999999
109
110 dt = datetime(
111 year, month, day, hour, minute, second, milliseconds,
112 tzinfo=tz.tzutc())
113
114 tz_sign = time_parts['tz_sign']
115 tz_hour = time_parts['tz_hour']
116 tz_minute = time_parts['tz_minute']
117 if tz_sign in ('-', '+'):
118 delta = timedelta(hours=int(tz_hour), minutes=int(tz_minute))
119 if tz_sign == '-':
120 dt = dt + delta
121 else:
122 dt = dt - delta
123
124 return dt
63125
64def sizeof_bytes(bytes):126def sizeof_bytes(bytes):
65 for x in ["bytes", "KB", "MB", "GB", "TB"]:127 for x in ["bytes", "KB", "MB", "GB", "TB"]:
@@ -78,3 +140,30 @@
78 hertz /= 1000.0140 hertz /= 1000.0
79141
80 return string142 return string
143
144def string_to_type(string):
145 """Return a typed representation for the given string.
146
147 The result might be a bool, int or float. The string might also be
148 supplemented by a multiplier like KB which would return an int or
149 float multiplied by 1024 for example.
150
151 :param string: The string representation.
152 """
153 if isinstance(string, basestring):
154 for regex, formatter in TYPE_FORMATS:
155 match = regex.match(string)
156 if match:
157 string = formatter(match)
158 if len(match.groups()) > 1:
159 unit = match.group(2)
160 for regex, multiplier in TYPE_MULTIPLIERS:
161 match = regex.match(unit)
162 if match:
163 string *= multiplier
164 break
165 else:
166 raise ValueError("Unknown multiplier: %s" % unit)
167 break
168
169 return string
81170
=== modified file 'checkbox/lib/dmi.py'
--- checkbox/lib/dmi.py 2009-09-08 23:01:38 +0000
+++ checkbox/lib/dmi.py 2011-11-18 18:04:27 +0000
@@ -16,13 +16,15 @@
16# You should have received a copy of the GNU General Public License16# You should have received a copy of the GNU General Public License
17# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.17# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
18#18#
19import os
20
1921
20# See also 3.3.4.1 of the "System Management BIOS Reference Specification,22# See also 3.3.4.1 of the "System Management BIOS Reference Specification,
21# Version 2.6.1" (Preliminary Standard) document, available from23# Version 2.6.1" (Preliminary Standard) document, available from
22# http://www.dmtf.org/standards/smbios.24# http://www.dmtf.org/standards/smbios.
23class Dmi:25class Dmi:
24 chassis = (26 chassis = (
25 ("Undefined", "unknown"), # 0x0027 ("Undefined", "unknown"), # 0x00
26 ("Other", "unknown"),28 ("Other", "unknown"),
27 ("Unknown", "unknown"),29 ("Unknown", "unknown"),
28 ("Desktop", "desktop"),30 ("Desktop", "desktop"),
@@ -53,22 +55,171 @@
53 ("Blade", "server"),55 ("Blade", "server"),
54 ("Blade Enclosure", "unknown"))56 ("Blade Enclosure", "unknown"))
5557
56 chassis_names = [c[0] for c in chassis]58 chassis_names = tuple(c[0] for c in chassis)
57 chassis_types = [c[1] for c in chassis]59 chassis_types = tuple(c[1] for c in chassis)
58 chassis_name_to_type = dict(chassis)60 chassis_name_to_type = dict(chassis)
5961
6062 type_names = (
61class DmiNotAvailable(object):63 "BIOS", # 0x00
62 def __init__(self, function):64 "System",
63 self._function = function65 "Base Board",
6466 "Chassis",
65 def __get__(self, instance, cls=None):67 "Processor",
66 self._instance = instance68 "Memory Controller",
67 return self69 "Memory Module",
6870 "Cache",
69 def __call__(self, *args, **kwargs):71 "Port Connector",
70 name = self._function(self._instance, *args, **kwargs)72 "System Slots",
71 if name == "Not Available":73 "On Board Devices",
72 name = None74 "OEM Strings",
7375 "System Configuration Options",
74 return name76 "BIOS Language",
77 "Group Associations",
78 "System Event Log",
79 "Physical Memory Array",
80 "Memory Device",
81 "32-bit Memory Error",
82 "Memory Array Mapped Address",
83 "Memory Device Mapped Address",
84 "Built-in Pointing Device",
85 "Portable Battery",
86 "System Reset",
87 "Hardware Security",
88 "System Power Controls",
89 "Voltage Probe",
90 "Cooling Device",
91 "Temperature Probe",
92 "Electrical Current Probe",
93 "Out-of-band Remote Access",
94 "Boot Integrity Services",
95 "System Boot",
96 "64-bit Memory Error",
97 "Management Device",
98 "Management Device Component",
99 "Management Device Threshold Data",
100 "Memory Channel",
101 "IPMI Device",
102 "Power Supply",
103 )
104
105
106class DmiDevice:
107
108 bus = "dmi"
109 driver = None
110 product_id = None
111 vendor_id = None
112
113 _product_blacklist = (
114 "<BAD INDEX>",
115 "N/A",
116 "Not Available",
117 "INVALID",
118 "OEM",
119 "Product Name",
120 "System Product Name",
121 "To be filled by O.E.M.",
122 "To Be Filled By O.E.M.",
123 "To Be Filled By O.E.M. by More String",
124 "Unknown",
125 "Uknown",
126 "Unknow",
127 "xxxxxxxxxxxxxx",
128 )
129 _vendor_blacklist = (
130 "<BAD INDEX>",
131 "Not Available",
132 "OEM",
133 "OEM Manufacturer",
134 "System manufacturer",
135 "System Manufacturer",
136 "System Name",
137 "To be filled by O.E.M.",
138 "To Be Filled By O.E.M.",
139 "To Be Filled By O.E.M. by More String",
140 "Unknow", # XXX This is correct mispelling
141 "Unknown",
142 )
143 _serial_blacklist = (
144 "0",
145 "00000000",
146 "00 00 00 00 00 00 00 00",
147 "0123456789",
148 "Base Board Serial Number",
149 "Chassis Serial Number",
150 "N/A",
151 "None",
152 "Not Applicable",
153 "Not Available",
154 "Not Specified",
155 "OEM",
156 "System Serial Number",
157 )
158 _version_blacklist = (
159 "-1",
160 "<BAD INDEX>",
161 "N/A",
162 "None",
163 "Not Applicable",
164 "Not Available",
165 "Not Specified",
166 "OEM",
167 "System Version",
168 "Unknown",
169 "x.x",
170 )
171
172 def __init__(self, attributes, category):
173 self._attributes = attributes
174 self.category = category
175
176 @property
177 def path(self):
178 path = "/devices/virtual/dmi/id"
179 return os.path.join(path, self.category.lower())
180
181 @property
182 def product(self):
183 if self.category == "CHASSIS":
184 type_string = self._attributes.get("chassis_type", "0")
185 try:
186 type_index = int(type_string)
187 return Dmi.chassis_names[type_index]
188 except ValueError:
189 return type_string
190
191 for name in "name", "version":
192 attribute = "%s_%s" % (self.category.lower(), name)
193 product = self._attributes.get(attribute)
194 if product and product not in self._product_blacklist:
195 return product
196
197 return None
198
199 @property
200 def vendor(self):
201 for name in "manufacturer", "vendor":
202 attribute = "%s_%s" % (self.category.lower(), name)
203 vendor = self._attributes.get(attribute)
204 if vendor and vendor not in self._vendor_blacklist:
205 return vendor
206
207 return None
208
209 @property
210 def serial(self):
211 attribute = "%s_serial" % self.category.lower()
212 serial = self._attributes.get(attribute)
213 if serial and serial not in self._serial_blacklist:
214 return serial
215
216 return None
217
218 @property
219 def version(self):
220 attribute = "%s_version" % self.category.lower()
221 version = self._attributes.get(attribute)
222 if version and version not in self._version_blacklist:
223 return version
224
225 return None
75226
=== modified file 'checkbox/lib/safe.py'
--- checkbox/lib/safe.py 2009-03-17 09:46:16 +0000
+++ checkbox/lib/safe.py 2011-11-18 18:04:27 +0000
@@ -94,3 +94,8 @@
94 md5sum = digest.hexdigest()94 md5sum = digest.hexdigest()
9595
96 return md5sum96 return md5sum
97
98def safe_close(file):
99 file.flush()
100 os.fsync(file.fileno())
101 file.close()
97102
=== modified file 'checkbox/lib/template.py'
--- checkbox/lib/template.py 2010-04-06 14:17:46 +0000
+++ checkbox/lib/template.py 2011-11-18 18:04:27 +0000
@@ -95,7 +95,7 @@
95 if line.startswith("#"):95 if line.startswith("#"):
96 continue96 continue
9797
98 match = re.search(r"^([-_.A-Za-z0-9]*):\s?(.*)", line)98 match = re.search(r"^([-_.A-Za-z0-9@]*):\s?(.*)", line)
99 if match:99 if match:
100 _save(field, value, extended)100 _save(field, value, extended)
101 field = match.groups()[0].lower()101 field = match.groups()[0].lower()
102102
=== modified file 'checkbox/message.py'
--- checkbox/message.py 2010-03-09 16:58:36 +0000
+++ checkbox/message.py 2011-11-18 18:04:27 +0000
@@ -22,7 +22,7 @@
22import posixpath22import posixpath
2323
24from checkbox.contrib import bpickle24from checkbox.contrib import bpickle
2525from checkbox.lib.safe import safe_close
2626
27HELD = "h"27HELD = "h"
28BROKEN = "b"28BROKEN = "b"
@@ -215,7 +215,7 @@
215 try:215 try:
216 return file.read()216 return file.read()
217 finally:217 finally:
218 file.close()218 safe_close(file)
219219
220 def _get_flags(self, path):220 def _get_flags(self, path):
221 basename = posixpath.basename(path)221 basename = posixpath.basename(path)
@@ -253,7 +253,8 @@
253253
254 file = open(filename + ".tmp", "w")254 file = open(filename + ".tmp", "w")
255 file.write(message_data)255 file.write(message_data)
256 file.close()256 safe_close(file)
257
257 os.rename(filename + ".tmp", filename)258 os.rename(filename + ".tmp", filename)
258259
259 # For now we use the inode as the message id, as it will work260 # For now we use the inode as the message id, as it will work
260261
=== modified file 'checkbox/parsers/cpuinfo.py'
--- checkbox/parsers/cpuinfo.py 2011-06-13 14:22:39 +0000
+++ checkbox/parsers/cpuinfo.py 2011-11-18 18:04:27 +0000
@@ -16,24 +16,26 @@
16# You should have received a copy of the GNU General Public License16# You should have received a copy of the GNU General Public License
17# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.17# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
18#18#
19import os
20import re19import re
2120
21from os import uname
22
22from checkbox.lib.conversion import string_to_type23from checkbox.lib.conversion import string_to_type
23from checkbox.parsers.utils import implement_from_dict24
2425
2526class CpuinfoParser:
26class CpuinfoParser(object):27 """Parser for the /proc/cpuinfo file."""
2728
28 def __init__(self, stream, uname=None):29 def __init__(self, stream, machine=None):
29 self.stream = stream30 self.stream = stream
30 self.uname = uname or os.uname()[4].lower()31 self.machine = machine or uname()[4].lower()
3132
32 def getAttributes(self):33 def getAttributes(self):
33 count = 034 count = 0
34 attributes = {}35 attributes = {}
35 cpuinfo = self.stream.read()36 cpuinfo = self.stream.read()
36 for block in cpuinfo.split("\n\n"):37 for block in re.split(r"\n{2,}", cpuinfo):
38 block = block.strip()
37 if not block:39 if not block:
38 continue40 continue
3941
@@ -54,19 +56,23 @@
5456
55 attributes[key.lower()] = value57 attributes[key.lower()] = value
5658
57 attributes["count"] = count59 if attributes:
60 attributes["count"] = count
61
58 return attributes62 return attributes
5963
60 def run(self, result):64 def run(self, result):
61 uname = self.uname
62 attributes = self.getAttributes()65 attributes = self.getAttributes()
66 if not attributes:
67 return
6368
64 # Default values69 # Default values
70 machine = self.machine
65 processor = {71 processor = {
66 "platform": uname,72 "platform": machine,
67 "count": 1,73 "count": 1,
68 "type": self.uname,74 "type": machine,
69 "model": self.uname,75 "model": machine,
70 "model_number": "",76 "model_number": "",
71 "model_version": "",77 "model_version": "",
72 "model_revision": "",78 "model_revision": "",
@@ -113,7 +119,6 @@
113 "type": "platform",119 "type": "platform",
114 "model": "cpu",120 "model": "cpu",
115 "model_version": "revision",121 "model_version": "revision",
116 "vendor": "machine",
117 "speed": "clock"},122 "speed": "clock"},
118 ("sparc64", "sparc",): {123 ("sparc64", "sparc",): {
119 "count": "ncpus probed",124 "count": "ncpus probed",
@@ -126,7 +131,7 @@
126 bogompips_string = attributes.get("bogomips", "0.0")131 bogompips_string = attributes.get("bogomips", "0.0")
127 processor["bogomips"] = int(round(float(bogompips_string)))132 processor["bogomips"] = int(round(float(bogompips_string)))
128 for platform, conversion in platform_to_conversion.iteritems():133 for platform, conversion in platform_to_conversion.iteritems():
129 if uname in platform:134 if machine in platform:
130 for pkey, ckey in conversion.iteritems():135 for pkey, ckey in conversion.iteritems():
131 if isinstance(ckey, (list, tuple)):136 if isinstance(ckey, (list, tuple)):
132 processor[pkey] = "/".join([attributes[k]137 processor[pkey] = "/".join([attributes[k]
@@ -134,13 +139,11 @@
134 elif ckey in attributes:139 elif ckey in attributes:
135 processor[pkey] = attributes[ckey]140 processor[pkey] = attributes[ckey]
136141
137 # Adjust platform and vendor142 # Adjust platform
138 if uname[0] == "i" and uname[-2:] == "86":143 if machine[0] == "i" and machine[-2:] == "86":
139 processor["platform"] = "i386"144 processor["platform"] = u"i386"
140 elif uname[:5] == "alpha":145 elif machine[:5] == "alpha":
141 processor["platform"] = "alpha"146 processor["platform"] = u"alpha"
142 elif uname[:5] == "sparc":
143 processor["vendor"] = "sun"
144147
145 # Adjust cache148 # Adjust cache
146 if processor["cache"]:149 if processor["cache"]:
@@ -148,14 +151,14 @@
148151
149 # Adjust speed152 # Adjust speed
150 try:153 try:
151 if uname[:5] == "alpha":154 if machine[:5] == "alpha":
152 speed = processor["speed"].split()[0]155 speed = processor["speed"].split()[0]
153 processor["speed"] = int(round(float(speed))) / 1000000156 processor["speed"] = int(round(float(speed))) / 1000000
154 elif uname[:5] == "sparc":157 elif machine[:5] == "sparc":
155 speed = processor["speed"]158 speed = processor["speed"]
156 processor["speed"] = int(round(float(speed))) / 2159 processor["speed"] = int(round(float(speed))) / 2
157 else:160 else:
158 if uname[:3] == "ppc":161 if machine[:3] == "ppc":
159 # String is appended with "mhz"162 # String is appended with "mhz"
160 speed = processor["speed"][:-3]163 speed = processor["speed"][:-3]
161 else:164 else:
@@ -174,18 +177,4 @@
174 if processor["count"] == 0:177 if processor["count"] == 0:
175 processor["count"] = 1178 processor["count"] = 1
176179
177 for key, value in processor.iteritems():180 result.setProcessor(processor)
178 camel_case = key.replace("_", " ").title().replace(" ", "")
179 method_name = "set%s" % camel_case
180 method = getattr(result, method_name)
181 method(value)
182
183
184class CpuinfoResult(dict):
185
186 def __getattr__(self, name):
187 name = re.sub(r"([A-Z])", "_\\1", name)[4:].lower()
188 def setAll(value):
189 self[name] = value
190
191 return setAll
192181
=== added file 'checkbox/parsers/cputable'
--- checkbox/parsers/cputable 1970-01-01 00:00:00 +0000
+++ checkbox/parsers/cputable 2011-11-18 18:04:27 +0000
@@ -0,0 +1,40 @@
1# This file contains the table of known CPU names.
2#
3# Architecture names are formed as a combination of the system name
4# (from ostable) and CPU name (from this table) after mapping from
5# the Debian triplet (from triplettable). A list of architecture
6# names in the Debian ‘sid’ distribution can be found in the archtable
7# file.
8#
9# Column 1 is the Debian name for the CPU, used to form the cpu part in
10# the Debian triplet.
11# Column 2 is the GNU name for the CPU, used to output build and host
12# targets in ‘dpkg-architecture’.
13# Column 3 is an extended regular expression used to match against the
14# CPU part of the output of the GNU config.guess script.
15# Column 4 is the size (in bits) of the integers/pointers
16# Column 5 is the endianness (byte ordering in numbers)
17#
18# <Debian name> <GNU name> <config.guess regex> <Bits> <Endianness>
19i386 i686 (i[3456]86|pentium) 32 little
20ia64 ia64 ia64 64 little
21alpha alpha alpha.* 64 little
22amd64 x86_64 x86_64 64 little
23armeb armeb arm.*b 32 big
24arm arm arm.* 32 little
25avr32 avr32 avr32 32 big
26hppa hppa hppa.* 32 big
27m32r m32r m32r 32 big
28m68k m68k m68k 32 big
29mips mips mips(eb)? 32 big
30mipsel mipsel mipsel 32 little
31powerpc powerpc (powerpc|ppc) 32 big
32ppc64 powerpc64 (powerpc|ppc)64 64 big
33s390 s390 s390 32 big
34s390x s390x s390x 64 big
35sh3 sh3 sh3 32 little
36sh3eb sh3eb sh3eb 32 big
37sh4 sh4 sh4 32 little
38sh4eb sh4eb sh4eb 32 big
39sparc sparc sparc 32 big
40sparc64 sparc64 sparc64 64 big
041
=== added file 'checkbox/parsers/cputable.py'
--- checkbox/parsers/cputable.py 1970-01-01 00:00:00 +0000
+++ checkbox/parsers/cputable.py 2011-11-18 18:04:27 +0000
@@ -0,0 +1,42 @@
1#
2# This file is part of Checkbox.
3#
4# Copyright 2011 Canonical Ltd.
5#
6# Checkbox is free software: you can redistribute it and/or modify
7# it under the terms of the GNU General Public License as published by
8# the Free Software Foundation, either version 3 of the License, or
9# (at your option) any later version.
10#
11# Checkbox is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
18#
19import re
20
21
22CPUTABLE_RE = re.compile(
23 r"^(?!\#)(?P<debian_name>\S+)"
24 r"\s+(?P<gnu_name>\S+)"
25 r"\s+(?P<regex>\S+)"
26 r"\s+(?P<bits>\d+)"
27 r"\s+(?P<endianness>big|little)")
28
29
30class CputableParser:
31 """Parser for the /usr/share/dpkg/cputable file."""
32
33 def __init__(self, stream):
34 self.stream = stream
35
36 def run(self, result):
37 for line in self.stream.readlines():
38 match = CPUTABLE_RE.match(line)
39 if match:
40 cpu = match.groupdict()
41 cpu["bits"] = int(cpu["bits"])
42 result.addCpu(cpu)
043
=== added file 'checkbox/parsers/deferred.py'
--- checkbox/parsers/deferred.py 1970-01-01 00:00:00 +0000
+++ checkbox/parsers/deferred.py 2011-11-18 18:04:27 +0000
@@ -0,0 +1,27 @@
1#
2# This file is part of Checkbox.
3#
4# Copyright 2011 Canonical Ltd.
5#
6# Checkbox is free software: you can redistribute it and/or modify
7# it under the terms of the GNU General Public License as published by
8# the Free Software Foundation, either version 3 of the License, or
9# (at your option) any later version.
10#
11# Checkbox is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
18#
19class DeferredParser:
20 """Parser for deferred dispatching of events."""
21
22 def __init__(self, dispatcher, event_type="result"):
23 self.dispatcher = dispatcher
24 self.event_type = event_type
25
26 def run(self, result):
27 self.dispatcher.publishEvent(self.event_type, result)
028
=== added file 'checkbox/parsers/dmidecode.py'
--- checkbox/parsers/dmidecode.py 1970-01-01 00:00:00 +0000
+++ checkbox/parsers/dmidecode.py 2011-11-18 18:04:27 +0000
@@ -0,0 +1,123 @@
1#
2# This file is part of Checkbox.
3#
4# Copyright 2011 Canonical Ltd.
5#
6# Checkbox is free software: you can redistribute it and/or modify
7# it under the terms of the GNU General Public License as published by
8# the Free Software Foundation, either version 3 of the License, or
9# (at your option) any later version.
10#
11# Checkbox is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
18#
19import re
20
21from string import (
22 hexdigits,
23 uppercase,
24 )
25
26from checkbox.lib.dmi import (
27 Dmi,
28 DmiDevice,
29 )
30
31
32HANDLE_RE = re.compile(
33 r"^Handle (?P<handle>0x[%s]{4}), "
34 r"DMI type (?P<type>\d+), "
35 r"(?P<size>\d+) bytes$"
36 % hexdigits)
37KEY_VALUE_RE = re.compile(
38 r"^\t(?P<key>[%s].+):( (?P<value>.+))?$"
39 % uppercase)
40
41
42class DmidecodeParser:
43 """Parser for the dmidecode command."""
44
45 _key_map = {
46 "ID": "serial",
47 "Manufacturer": "vendor",
48 "Product Name": "name",
49 "Serial Number": "serial",
50 "Type": "type",
51 "Vendor": "vendor",
52 "Version": "version",
53 }
54
55 def __init__(self, stream):
56 self.stream = stream
57
58 def _parseKey(self, key):
59 return self._key_map.get(key)
60
61 def _parseValue(self, value):
62 if value is not None:
63 value = value.strip()
64 if not value:
65 value = None
66
67 return value
68
69 def run(self, result):
70 output = self.stream.read()
71 for record in re.split(r"\n{2,}", output):
72 record = record.strip()
73 # Skip empty records
74 if not record:
75 continue
76
77 # Skip header record
78 lines = record.split("\n")
79 line = lines.pop(0)
80 if line.startswith("#"):
81 continue
82
83 # Skip records with an unsupported handle
84 match = HANDLE_RE.match(line)
85 if not match:
86 continue
87
88 # Skip records that are empty or inactive
89 if not lines or lines.pop(0) == "Inactive":
90 continue
91
92 # Skip disabled entries and end-of-table marker
93 type_index = int(match.group("type"))
94 if type_index >= len(Dmi.type_names):
95 continue
96
97 category = Dmi.type_names[type_index]
98 category = category.upper().split(" ")[-1]
99 if category not in (
100 "BOARD", "BIOS", "CHASSIS", "PROCESSOR", "SYSTEM"):
101 continue
102
103 # Parse attributes
104 attributes = {}
105 for line in lines:
106 # Skip lines with an unsupported key/value pair
107 match = KEY_VALUE_RE.match(line)
108 if not match:
109 continue
110
111 # Skip lines with an unsupported key
112 key = self._parseKey(match.group("key"))
113 if not key:
114 continue
115
116 key = "%s_%s" % (category.lower(), key)
117 value = self._parseValue(match.group("value"))
118 attributes[key] = value
119
120 device = DmiDevice(attributes, category)
121 result.addDmiDevice(device)
122
123 return result
0124
=== added file 'checkbox/parsers/meminfo.py'
--- checkbox/parsers/meminfo.py 1970-01-01 00:00:00 +0000
+++ checkbox/parsers/meminfo.py 2011-11-18 18:04:27 +0000
@@ -0,0 +1,46 @@
1#
2# This file is part of Checkbox.
3#
4# Copyright 2011 Canonical Ltd.
5#
6# Checkbox is free software: you can redistribute it and/or modify
7# it under the terms of the GNU General Public License as published by
8# the Free Software Foundation, either version 3 of the License, or
9# (at your option) any later version.
10#
11# Checkbox is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
18#
19import re
20
21
22class MeminfoParser:
23 """Parser for the /proc/meminfo file."""
24
25 def __init__(self, stream):
26 self.stream = stream
27
28 def run(self, result):
29 key_value_pattern = re.compile(r"(?P<key>.*):\s+(?P<value>.*)")
30 meminfo_map = {
31 "MemTotal": "total",
32 "SwapTotal": "swap"}
33
34 meminfo = {}
35 for line in self.stream.readlines():
36 line = line.strip()
37 match = key_value_pattern.match(line)
38 if match:
39 key = match.group("key")
40 if key in meminfo_map:
41 key = meminfo_map[key]
42 value = match.group("value")
43 (integer, factor) = value.split()
44 meminfo[key] = int(integer) * 1024
45
46 result.setMemory(meminfo)
047
=== modified file 'checkbox/parsers/submission.py'
--- checkbox/parsers/submission.py 2011-06-13 14:22:39 +0000
+++ checkbox/parsers/submission.py 2011-11-18 18:04:27 +0000
@@ -16,430 +16,521 @@
16# You should have received a copy of the GNU General Public License16# You should have received a copy of the GNU General Public License
17# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.17# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
18#18#
19import re
20
21import logging
22
23from datetime import (
24 datetime,
25 timedelta,
26 )
27from dateutil import tz
28
29from checkbox.parsers.device import DeviceResult
30from checkbox.parsers.udev import UdevParser
31from checkbox.parsers.utils import implement_from_dict
32
33try:19try:
34 import xml.etree.cElementTree as etree20 import xml.etree.cElementTree as etree
35except ImportError:21except ImportError:
36 import cElementTree as etree22 import cElementTree as etree
3723
3824from StringIO import StringIO
39_time_regex = re.compile(r"""25from logging import getLogger
40 ^(?P<year>\d\d\d\d)-(?P<month>\d\d)-(?P<day>\d\d)26from pkg_resources import resource_string
41 T(?P<hour>\d\d):(?P<minute>\d\d):(?P<second>\d\d)27
42 (?:\.(?P<second_fraction>\d{0,6}))?28from checkbox.lib.conversion import string_to_datetime
43 (?P<tz>29
44 (?:(?P<tz_sign>[-+])(?P<tz_hour>\d\d):(?P<tz_minute>\d\d))30from checkbox import parsers
45 | Z)?$31from checkbox.dispatcher import DispatcherQueue
46 """,32from checkbox.parsers.cpuinfo import CpuinfoParser
47 re.VERBOSE)33from checkbox.parsers.cputable import CputableParser
4834from checkbox.parsers.deferred import DeferredParser
49_xml_illegal_regex = re.compile(35from checkbox.parsers.dmidecode import DmidecodeParser
50 u"([\u0000-\u0008\u000b-\u000c\u000e-\u001f\ufffe-\uffff])"36from checkbox.parsers.meminfo import MeminfoParser
51 + u"|([%s-%s][^%s-%s])|([^%s-%s][%s-%s])|([%s-%s]$)|(^[%s-%s])" % (37from checkbox.parsers.udevadm import UdevadmParser
52 unichr(0xd800),unichr(0xdbff),unichr(0xdc00),unichr(0xdfff),38from checkbox.job import (FAIL, PASS, UNINITIATED, UNRESOLVED,
53 unichr(0xd800),unichr(0xdbff),unichr(0xdc00),unichr(0xdfff),39 UNSUPPORTED, UNTESTED)
54 unichr(0xd800),unichr(0xdbff),unichr(0xdc00),unichr(0xdfff)))40
5541
5642class SubmissionResult:
57class HALDevice(object):43
5844 def __init__(self, test_run_factory, **kwargs):
59 def __init__(self, id, udi, properties):45 self.test_run_factory = test_run_factory
60 self.id = id46 self.test_run_kwargs = kwargs
61 self.udi = udi47 self.dispatcher = DispatcherQueue()
62 self.properties = properties48
6349 # Register handlers to incrementally add information
6450 register = self.dispatcher.registerHandler
65class SubmissionStream(object):51 register(("cpu", "architecture",), self.addCpuArchitecture)
6652 register(("identifier",), self.addIdentifier)
67 default_size = 409653 register(("test_run", "attachment",), self.addAttachment)
6854 register(("test_run", "device",), self.addDeviceState)
69 def __init__(self, stream):55 register(("test_run", "distribution",), self.setDistribution)
70 self.stream = stream56 register(("test_run", "package_version",), self.addPackageVersion)
71 self._buffer = ""57 register(("test_run", "test_result",), self.addTestResult)
72 self._buffers = []58
7359 # Register handlers to set information once
74 def read(self, size=None):60 register(("architecture",), self.setArchitecture, count=1)
75 if size is None:61 register(
76 size = self.default_size62 ("cpuinfo", "machine", "cpuinfo_result",),
7763 self.setCpuinfo, count=1)
78 info_start_regex = re.compile("^<info .*>$")64 register(
79 info_end_regex = re.compile("^</info>$")65 ("meminfo", "meminfo_result",),
8066 self.setMeminfo, count=1)
81 in_info = False67 register(
82 length = sum(len(buffer) for buffer in self._buffers)68 ("project", "series",),
8369 self.setTestRun, count=1)
84 while length < size:70 register(
85 try:71 ("test_run", "architecture",),
86 buffer = self.stream.next()72 self.setArchitectureState, count=1)
87 except StopIteration:73 register(
88 break74 ("test_run", "memory",),
8975 self.setMemoryState, count=1)
90 if not in_info:76 register(
91 if info_start_regex.match(buffer):77 ("test_run", "processor",),
92 in_info = True78 self.setProcessorState, count=1)
93 self._buffer += "".join(self._buffers)79 register(
94 self._buffers = [buffer]80 ("udevadm", "bits", "udevadm_result",),
95 else:81 self.setUdevadm, count=1)
96 length += len(buffer)82
97 self._buffers.append(buffer)83 # Publish events passed as keyword arguments
98 else:84 if "project" in kwargs:
99 self._buffers.append(buffer)85 self.dispatcher.publishEvent("project", kwargs.pop("project"))
100 if info_end_regex.match(buffer):86 self.dispatcher.publishEvent("series", kwargs.pop("series", None))
101 in_info = False87
10288 def addAttachment(self, test_run, attachment):
103 buffer = "".join(self._buffers)89 test_run.addAttachment(**attachment)
104 self._buffers = []90
10591 def addContext(self, text, command=None):
106 if not _xml_illegal_regex.search(buffer):92 if text.strip() == "Command not found.":
107 length += len(buffer)93 return
108 self._buffer += buffer94
10995 self.dispatcher.publishEvent(
110 if self._buffers:96 "attachment", {"name": command, "content": text })
111 self._buffer += "".join(self._buffers)97
112 self._buffers = []98 parsers = {
11399 "cat /proc/cpuinfo": self.parseCpuinfo,
114 if not self._buffer:100 "cat /proc/meminfo": self.parseMeminfo,
115 return None101 "dmidecode": DmidecodeParser,
116102 "udevadm info --export-db": self.parseUdevadm,
117 data = self._buffer[:size]103 }
118 self._buffers = [self._buffer[size:]]104 parser = parsers.get(command)
119 self._buffer = ""105 if parser:
120106 if not isinstance(text, unicode):
121 return data107 text = text.decode("utf-8")
122108 stream = StringIO(text)
123109 p = parser(stream)
124class SubmissionParser(object):110 p.run(self)
125111
126 default_name = "unknown"112 def addCpu(self, cpu):
127113 self.dispatcher.publishEvent("cpu", cpu)
128 def __init__(self, stream, name=None):114
129 self.stream = SubmissionStream(stream)115 def addCpuArchitecture(self, cpu, architecture):
130 self.name = name or self.default_name116 if cpu["debian_name"] == architecture:
117 self.dispatcher.publishEvent("machine", cpu["gnu_name"])
118 self.dispatcher.publishEvent("bits", cpu["bits"])
119
120 def addDevice(self, device):
121 self.dispatcher.publishEvent("device", device)
122
123 def addDeviceState(self, test_run, device):
124 test_run.addDeviceState(
125 bus_name=device.bus, category_name=device.category,
126 product_name=device.product, vendor_name=device.vendor,
127 product_id=device.product_id, vendor_id=device.vendor_id,
128 subproduct_id=device.subproduct_id,
129 subvendor_id=device.subvendor_id,
130 driver_name=device.driver, path=device.path)
131
132 def addDmiDevice(self, device):
133 if device.serial:
134 self.dispatcher.publishEvent("identifier", device.serial)
135
136 if device.category in ("BOARD", "SYSTEM") \
137 and device.vendor != device.product \
138 and device.product is not None:
139 self.dispatcher.publishEvent("model", device.product)
140 self.dispatcher.publishEvent("make", device.vendor)
141 self.dispatcher.publishEvent("version", device.version)
142
143 def addIdentifier(self, identifier):
144 try:
145 self.identifiers.append(identifier)
146 except AttributeError:
147 self.identifiers = [identifier]
148 self.dispatcher.publishEvent("identifiers", self.identifiers)
149
150 def addPackage(self, package):
151 package_version = {
152 "name": package["name"],
153 "version": package["properties"]["version"],
154 }
155 self.dispatcher.publishEvent("package_version", package_version)
156
157 def addPackageVersion(self, test_run, package_version):
158 test_run.addPackageVersion(**package_version)
159
160 def addQuestion(self, question):
161 answer_to_status = {
162 "fail": FAIL,
163 "no": FAIL,
164 "pass": PASS,
165 "skip": UNTESTED,
166 "uninitiated": UNINITIATED,
167 "unresolved": UNRESOLVED,
168 "unsupported": UNSUPPORTED,
169 "untested": UNTESTED,
170 "yes": PASS,
171 }
172
173 test_result = dict(
174 name=question["name"],
175 output=question["comment"],
176 status=answer_to_status[question["answer"]["value"]],
177 )
178 test_result.update(self.test_run_kwargs)
179 self.dispatcher.publishEvent("test_result", test_result)
180
181 def addTestResult(self, test_run, test_result):
182 test_run.addTestResult(**test_result)
183
184 def addSummary(self, name, value):
185 if name == "architecture":
186 self.dispatcher.publishEvent("architecture", value)
187 elif name == "distribution":
188 self.dispatcher.publishEvent("project", value)
189 elif name == "distroseries":
190 self.dispatcher.publishEvent("series", value)
191
192 def parseCpuinfo(self, cpuinfo):
193 self.dispatcher.publishEvent("cpuinfo", cpuinfo)
194 return DeferredParser(self.dispatcher, "cpuinfo_result")
195
196 def parseMeminfo(self, meminfo):
197 self.dispatcher.publishEvent("meminfo", meminfo)
198 return DeferredParser(self.dispatcher, "meminfo_result")
199
200 def parseUdevadm(self, udevadm):
201 self.dispatcher.publishEvent("udevadm", udevadm)
202 return DeferredParser(self.dispatcher, "udevadm_result")
203
204 def setArchitecture(self, architecture):
205 string = resource_string(parsers.__name__, "cputable")
206 stream = StringIO(string.decode("utf-8"))
207 parser = CputableParser(stream)
208 parser.run(self)
209
210 def setArchitectureState(self, test_run, architecture):
211 test_run.setArchitectureState(architecture)
212
213 def setCpuinfo(self, cpuinfo, machine, cpuinfo_result):
214 parser = CpuinfoParser(cpuinfo, machine)
215 parser.run(cpuinfo_result)
216
217 def setMeminfo(self, meminfo, meminfo_result):
218 parser = MeminfoParser(meminfo)
219 parser.run(meminfo_result)
220
221 def setDistribution(self, test_run, distribution):
222 test_run.setDistribution(**distribution)
223
224 def setLSBRelease(self, lsb_release):
225 self.dispatcher.publishEvent("distribution", lsb_release)
226
227 def setMemory(self, memory):
228 self.dispatcher.publishEvent("memory", memory)
229
230 def setMemoryState(self, test_run, memory):
231 test_run.setMemoryState(**memory)
232
233 def setProcessor(self, processor):
234 self.dispatcher.publishEvent("processor", processor)
235
236 def setProcessorState(self, test_run, processor):
237 test_run.setProcessorState(
238 platform_name=processor["platform"],
239 make=processor["type"], model=processor["model"],
240 model_number=processor["model_number"],
241 model_version=processor["model_version"],
242 model_revision=processor["model_revision"],
243 cache=processor["cache"], other=processor["other"],
244 bogomips=processor["bogomips"], speed=processor["speed"],
245 count=processor["count"])
246
247 def setTestRun(self, project, series):
248 test_run = self.test_run_factory(
249 **self.test_run_kwargs)
250 self.dispatcher.publishEvent("test_run", test_run)
251
252 def setUdevadm(self, udevadm, bits, udevadm_result):
253 parser = UdevadmParser(udevadm, bits)
254 parser.run(udevadm_result)
255
256
257class SubmissionParser:
258
259 def __init__(self, file):
260 self.file = file
261 self.logger = getLogger()
131262
132 def _getClient(self, node):263 def _getClient(self, node):
133 return "_".join([node.get('name'), node.get('version')])264 """Return a dictionary with the name and version of the client."""
265 return {
266 "name": node.get("name"),
267 "version": node.get("version"),
268 }
134269
135 def _getProperty(self, node):270 def _getProperty(self, node):
136 """Parse a <property> node.271 """Return the (name, value) of a property."""
137272 return (node.get("name"), self._getValueAsType(node))
138 :return: (name, (value, type)) of a property.
139 """
140 return (node.get('name'), self._getValueAttribute(node))
141273
142 def _getProperties(self, node):274 def _getProperties(self, node):
143 """Parse <property> sub-nodes of node.275 """Return a dictionary of properties."""
144
145 :return: A dictionary, where each key is the name of a property;
146 the values are the tuples (value, type) of a property.
147 """
148 properties = {}276 properties = {}
149 for child in node.getchildren():277 for child in node.getchildren():
278 assert child.tag == "property", \
279 "Unexpected tag <%s>, expected <property>" % child.tag
150 name, value = self._getProperty(child)280 name, value = self._getProperty(child)
151 if name in properties:
152 raise ValueError(
153 '<property name="%s"> found more than once in <%s>'
154 % (name, node.tag))
155 properties[name] = value281 properties[name] = value
156282
157 return properties283 return properties
158284
159 def _getValueAttribute(self, node):285 def _getValueAsType(self, node):
160 """Return (value, type) of a <property> or <value> node."""286 """Return value of a node as the type attribute."""
161 type_ = node.get('type')287 type_ = node.get("type")
162 if type_ in ('dbus.Boolean', 'bool'):288 if type_ in ("bool",):
163 value = node.text.strip() == 'True'
164
165 elif type_ in ('str', 'dbus.String', 'dbus.UTF8String'):
166 value = node.text.strip()289 value = node.text.strip()
167290 assert value in ("True", "False",), \
168 elif type_ in ('dbus.Byte', 'dbus.Int16', 'dbus.Int32', 'dbus.Int64',291 "Unexpected boolean value '%s' in <%s>" % (value, node.tag)
169 'dbus.UInt16', 'dbus.UInt32', 'dbus.UInt64', 'int',292 return value == "True"
170 'long'):293 elif type_ in ("str",):
171 value = int(node.text.strip())294 return unicode(node.text.strip())
172295 elif type_ in ("int", "long",):
173 elif type_ in ('dbus.Double', 'float'):296 return int(node.text.strip())
174 value = float(node.text.strip())297 elif type_ in ("float",):
175298 return float(node.text.strip())
176 elif type_ in ('dbus.Array', 'list'):299 elif type_ in ("list",):
177 value = [self._getValueAttribute(child)300 return list(self._getValueAsType(child)
178 for child in node.getchildren()]301 for child in node.getchildren())
179302 elif type_ in ("dict",):
180 elif type_ in ('dbus.Dictionary', 'dict'):303 return dict((child.get("name"), self._getValueAsType(child))
181 value = dict((child.get('name'), self._getValueAttribute(child))304 for child in node.getchildren())
182 for child in node.getchildren())
183
184 else:305 else:
185 # This should not happen.
186 raise AssertionError(306 raise AssertionError(
187 'Unexpected <property> or <value> type: %s' % type_)307 "Unexpected type '%s' in <%s>" % (type_, node.tag))
188308
189 return value309 def _getValueAsBoolean(self, node):
190
191 def _getValueAttributeAsBoolean(self, node):
192 """Return the value of the attribute "value" as a boolean."""310 """Return the value of the attribute "value" as a boolean."""
193 return node.attrib['value'] == "True"311 value = node.attrib["value"]
194312 assert value in ("True", "False",), \
195 def _getValueAttributeAsString(self, node):313 "Unexpected boolean value '%s' in tag <%s>" % (value, node.tag)
314 return value == "True"
315
316 def _getValueAsDatetime(self, node):
317 """Return the value of the attribute "value" as a datetime."""
318 string = node.attrib["value"]
319 return string_to_datetime(string)
320
321 def _getValueAsString(self, node):
196 """Return the value of the attribute "value"."""322 """Return the value of the attribute "value"."""
197 return node.attrib['value']323 return unicode(node.attrib["value"])
198324
199 def _getValueAttributeAsDateTime(self, node):325 def parseContext(self, result, node):
200 """Convert a "value" attribute into a datetime object."""326 """Parse the <context> part of a submission."""
201 time_text = node.get('value')327 duplicates = set()
202328 for child in node.getchildren():
203 # we cannot use time.strptime: this function accepts neither fractions329 assert child.tag == "info", \
204 # of a second nor a time zone given e.g. as '+02:30'.330 "Unexpected tag <%s>, expected <info>" % child.tag
205 match = _time_regex.search(time_text)331 command = child.get("command")
206332 if command not in duplicates:
207 if match is None:333 duplicates.add(command)
208 raise ValueError(334 result.addContext(child.text, command)
209 'Timestamp with unreasonable value: %s' % time_text)335 else:
210336 self.logger.debug(
211 time_parts = match.groupdict()337 "Duplicate command found in tag <info>: %s" % command)
212338
213 year = int(time_parts['year'])339 def parseHardware(self, result, node):
214 month = int(time_parts['month'])340 """Parse the <hardware> section of a submission."""
215 day = int(time_parts['day'])341 parsers = {
216 hour = int(time_parts['hour'])342 "dmi": DmidecodeParser,
217 minute = int(time_parts['minute'])343 "processors": self.parseProcessors,
218 second = int(time_parts['second'])344 "udev": result.parseUdevadm,
219 second_fraction = time_parts['second_fraction']345 }
220 if second_fraction is not None:346
221 milliseconds = second_fraction + '0' * (6 - len(second_fraction))347 for child in node.getchildren():
222 milliseconds = int(milliseconds)348 parser = parsers.get(child.tag)
223 else:349 if parser:
224 milliseconds = 0350 if child.getchildren():
225351 parser(result, child)
226 if second > 59:352 else:
227 second = 59353 text = child.text
228 milliseconds = 999999354 if not isinstance(text, unicode):
229355 text = text.decode("utf-8")
230 timestamp = datetime(year, month, day, hour, minute, second,356 stream = StringIO(text)
231 milliseconds, tzinfo=tz.tzutc())357 p = parser(stream)
232358 p.run(result)
233 tz_sign = time_parts['tz_sign']359 else:
234 tz_hour = time_parts['tz_hour']360 self.logger.debug(
235 tz_minute = time_parts['tz_minute']361 "Unsupported tag <%s> in <hardware>" % child.tag)
236 if tz_sign in ('-', '+'):362
237 delta = timedelta(hours=int(tz_hour), minutes=int(tz_minute))363 def parseLSBRelease(self, result, node):
238 if tz_sign == '-':364 """Parse the <lsbrelease> part of a submission."""
239 timestamp = timestamp + delta
240 else:
241 timestamp = timestamp - delta
242
243 return timestamp
244
245 def _parseHAL(self, result, node):
246 result.startDevices()
247 for child in node.getchildren():
248 id = int(child.get('id'))
249 udi = child.get('udi')
250 properties = self._getProperties(child)
251 device = HALDevice(id, udi, properties)
252 result.addDevice(device)
253
254 result.endDevices()
255
256 def _parseInfo(self, result, node):
257 command = node.attrib['command']
258 if command == "udevadm info --export-db":
259 self._parseUdev(result, node)
260
261 result.addInfo(command, node.text)
262
263 def _parseUdev(self, result, node):
264 result.startDevices()
265
266 stream = StringIO(node.text)
267 udev = UdevParser(stream)
268 udev.run(result)
269
270 result.endDevices()
271
272 def _parseProcessors(self, result, node):
273 result.startProcessors()
274
275 for child in node.getchildren():
276 id = int(child.get('id'))
277 name = child.get('name')
278 properties = self._getProperties(child)
279 result.addProcessor(id, name, properties)
280
281 result.endProcessors()
282
283 def _parseRoot(self, result, node):
284 parsers = {
285 "summary": self._parseSummary,
286 "hardware": self._parseHardware,
287 "software": self._parseSoftware,
288 "questions": self._parseQuestions,
289 "context": self._parseContext,
290 }
291
292 for child in node.getchildren():
293 parser = parsers.get(child.tag, self._parseNone)
294 parser(result, child)
295
296 def _parseSummary(self, result, node):
297 parsers = {
298 'live_cd': self._getValueAttributeAsBoolean,
299 'system_id': self._getValueAttributeAsString,
300 'distribution': self._getValueAttributeAsString,
301 'distroseries': self._getValueAttributeAsString,
302 'architecture': self._getValueAttributeAsString,
303 'private': self._getValueAttributeAsBoolean,
304 'contactable': self._getValueAttributeAsBoolean,
305 'date_created': self._getValueAttributeAsDateTime,
306 'client': self._getClient,
307 'kernel-release': self._getValueAttributeAsString,
308 }
309
310 for child in node.getchildren():
311 parser = parsers.get(child.tag, self._parseNone)
312 value = parser(child)
313 result.addSummary(child.tag, value)
314
315 def _parseHardware(self, result, node):
316 parsers = {
317 'hal': self._parseHAL,
318 'processors': self._parseProcessors,
319 'udev': self._parseUdev,
320 }
321
322 for child in node.getchildren():
323 parser = parsers.get(child.tag, self._parseNone)
324 parser(result, child)
325
326 def _parseLSBRelease(self, result, node):
327 properties = self._getProperties(node)365 properties = self._getProperties(node)
328 result.setDistribution(**properties)366 result.setLSBRelease(properties)
329367
330 def _parsePackages(self, result, node):368 def parsePackages(self, result, node):
331 result.startPackages()369 """Parse the <packages> part of a submission."""
332370 for child in node.getchildren():
333 for child in node.getchildren():371 assert child.tag == "package", \
334 id = int(child.get('id'))372 "Unexpected tag <%s>, expected <package>" % child.tag
335 name = child.get('name')373
374 package = {
375 "name": child.get("name"),
376 "properties": self._getProperties(child),
377 }
378 result.addPackage(package)
379
380 def parseProcessors(self, result, node):
381 """Parse the <processors> part of a submission."""
382 processors = []
383 for child in node.getchildren():
384 assert child.tag == "processor", \
385 "Unexpected tag <%s>, expected <processor>" % child.tag
386
387 # Convert lists to space separated strings.
336 properties = self._getProperties(child)388 properties = self._getProperties(child)
337389 for key, value in properties.iteritems():
338 result.addPackage(id, name, properties)390 if key in ("bogomips", "cache", "count", "speed",):
339391 properties[key] = int(value)
340 result.endPackages()392 elif isinstance(value, list):
341393 properties[key] = u" ".join(value)
342 def _parseXOrg(self, result, node):394 processors.append(properties)
343 drivers = {}395
344 for child in node.getchildren():396 # Check if /proc/cpuinfo was parsed already.
345 info = dict(child.attrib)397 if any("platform" in processor for processor in processors):
346 if 'device' in info:398 result.setProcessor(processors[0])
347 info['device'] = int(info['device'])399 else:
348400 lines = []
349 name = info['name']401 for processor in processors:
350 if name in drivers:402 # Convert some keys with underscores to spaces instead.
351 raise ValueError(403 for key, value in processor.iteritems():
352 '<driver name="%s"> appears more than once in <xorg>'404 if "_" in key and key != "vendor_id":
353 % name)405 key = key.replace("_", " ")
354406
355 drivers[name] = info407 lines.append(u"%s: %s" % (key, value))
356408
357 version = node.get('version')409 lines.append(u"")
358 result.addXorg(version, drivers)410
359411 stream = StringIO(u"\n".join(lines))
360 def _parseSoftware(self, result, node):412 parser = result.parseCpuinfo(stream)
361 parsers = {413 parser.run(result)
362 'lsbrelease': self._parseLSBRelease,414
363 'packages': self._parsePackages,415 def parseQuestions(self, result, node):
364 'xorg': self._parseXOrg,416 """Parse the <questions> part of a submission."""
365 }417 for child in node.getchildren():
366418 assert child.tag == "question", \
367 for child in node.getchildren():419 "Unexpected tag <%s>, expected <question>" % child.tag
368 parser = parsers.get(child.tag, self._parseNone)420 question = {
369 parser(result, child)421 "name": child.get("name"),
370422 "targets": [],
371 def _parseQuestions(self, result, node):423 }
372 result.startQuestions()424 plugin = child.get("plugin", None)
373
374 for child in node.getchildren():
375 question = {'name': child.get('name')}
376 plugin = child.get('plugin', None)
377 if plugin is not None:425 if plugin is not None:
378 question['plugin'] = plugin426 question["plugin"] = plugin
379 question['targets'] = targets = []427
380 answer_choices = []428 answer_choices = []
381
382 for sub_node in child.getchildren():429 for sub_node in child.getchildren():
383 sub_tag = sub_node.tag430 sub_tag = sub_node.tag
384 if sub_tag == 'answer':431 if sub_tag == "answer":
385 question['answer'] = answer = {}432 question["answer"] = answer = {}
386 answer['type'] = sub_node.get('type')433 answer["type"] = sub_node.get("type")
387 if answer['type'] == 'multiple_choice':434 if answer["type"] == "multiple_choice":
388 question['answer_choices'] = answer_choices435 question["answer_choices"] = answer_choices
389 unit = sub_node.get('unit', None)436 unit = sub_node.get("unit", None)
390 if unit is not None:437 if unit is not None:
391 answer['unit'] = unit438 answer["unit"] = unit
392 answer['value'] = sub_node.text.strip()439 answer["value"] = sub_node.text.strip()
393 elif sub_tag == 'answer_choices':440
441 elif sub_tag == "answer_choices":
394 for value_node in sub_node.getchildren():442 for value_node in sub_node.getchildren():
395 answer_choices.append(443 answer_choices.append(
396 self._getValueAttribute(value_node))444 self._getValueAsType(value_node))
397 elif sub_tag == 'target':445
398 target = {'id': int(sub_node.get('id'))}446 elif sub_tag == "target":
399 target['drivers'] = drivers = []447 # The Relax NG schema ensures that the attribute
448 # id exists and that it is an integer
449 target = {"id": int(sub_node.get("id"))}
450 target["drivers"] = drivers = []
400 for driver_node in sub_node.getchildren():451 for driver_node in sub_node.getchildren():
401 drivers.append(driver_node.text.strip())452 drivers.append(driver_node.text.strip())
402 targets.append(target)453 question["targets"].append(target)
403 elif sub_tag in('comment', 'command'):454
455 elif sub_tag in ("comment", "command",):
404 data = sub_node.text456 data = sub_node.text
405 if data is not None:457 if data is not None:
406 question[sub_tag] = data.strip()458 question[sub_tag] = data.strip()
407459
460 else:
461 raise AssertionError(
462 "Unexpected tag <%s> in <question>" % sub_tag)
463
408 result.addQuestion(question)464 result.addQuestion(question)
409465
410 result.endQuestions()466 def parseSoftware(self, result, node):
411467 """Parse the <software> section of a submission."""
412 def _parseContext(self, result, node):468 parsers = {
413 parsers = {469 "lsbrelease": self.parseLSBRelease,
414 'info': self._parseInfo,470 "packages": self.parsePackages,
415 }471 }
416472
417 for child in node.getchildren():473 for child in node.getchildren():
418 parser = parsers.get(child.tag, self._parseNone)474 parser = parsers.get(child.tag)
419 parser(result, child)475 if parser:
420476 parser(result, child)
421 def _parseNone(self, result, node):477 else:
422 pass478 self.logger.debug(
423479 "Unsupported tag <%s> in <software>" % child.tag)
424 def run(self, result):480
481 def parseSummary(self, result, node):
482 """Parse the <summary> section of a submission."""
483 parsers = {
484 "architecture": self._getValueAsString,
485 "client": self._getClient,
486 "contactable": self._getValueAsBoolean,
487 "date_created": self._getValueAsDatetime,
488 "distribution": self._getValueAsString,
489 "distroseries": self._getValueAsString,
490 "kernel-release": self._getValueAsString,
491 "live_cd": self._getValueAsBoolean,
492 "private": self._getValueAsBoolean,
493 "system_id": self._getValueAsString,
494 }
495
496 for child in node.getchildren():
497 parser = parsers.get(child.tag)
498 if parser:
499 value = parser(child)
500 result.addSummary(child.tag, value)
501 else:
502 self.logger.debug(
503 "Unsupported tag <%s> in <summary>" % child.tag)
504
505 def parseRoot(self, result, node):
506 """Parse the <system> root of a submission."""
507 parsers = {
508 "context": self.parseContext,
509 "hardware": self.parseHardware,
510 "questions": self.parseQuestions,
511 "software": self.parseSoftware,
512 "summary": self.parseSummary,
513 }
514
515 # Iterate over the root children, "summary" first
516 for child in node.getchildren():
517 parser = parsers.get(child.tag)
518 if parser:
519 parser(result, child)
520 else:
521 self.logger.debug(
522 "Unsupported tag <%s> in <system>" % child.tag)
523
524 def run(self, test_run_factory, **kwargs):
425 parser = etree.XMLParser()525 parser = etree.XMLParser()
426526
427 try:527 tree = etree.parse(self.file, parser=parser)
428 tree = etree.parse(self.stream, parser=parser)
429 except SyntaxError, error:
430 logging.error(error)
431 return
432
433 root = tree.getroot()528 root = tree.getroot()
434 if root.tag != "system":529 if root.tag != "system":
435 logging.error("Root node is not '<system>'")530 raise AssertionError(
436 return531 "Unexpected tag <%s> at root, expected <system>" % root.tag)
437532
438 self._parseRoot(result, root)533 result = SubmissionResult(test_run_factory, **kwargs)
439534 self.parseRoot(result, root)
440535
441SubmissionResult = implement_from_dict("SubmissionResult", [536 return result
442 "startDevices", "endDevices", "addDevice", "startPackages",
443 "endPackages", "addPackage", "startProcessors", "endProcessors",
444 "addProcessor", "startQuestions", "endQuestions", "addQuestion",
445 "addInfo", "addSummary", "addXorg", "setDistribution"], DeviceResult)
446537
=== renamed file 'checkbox/parsers/udev.py' => 'checkbox/parsers/udevadm.py'
--- checkbox/parsers/udev.py 2011-09-14 21:16:02 +0000
+++ checkbox/parsers/udevadm.py 2011-11-18 18:04:27 +0000
@@ -16,38 +16,78 @@
16# You should have received a copy of the GNU General Public License16# You should have received a copy of the GNU General Public License
17# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.17# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
18#18#
19import os
20import re19import re
21import string20import string
22import posixpath21
2322from checkbox.lib.bit import (
24from curses.ascii import isprint23 get_bitmask,
2524 test_bit,
26from checkbox.lib.bit import get_bitmask, test_bit25 )
27from checkbox.lib.dmi import Dmi, DmiNotAvailable
28from checkbox.lib.input import Input26from checkbox.lib.input import Input
29from checkbox.lib.pci import Pci27from checkbox.lib.pci import Pci
30from checkbox.lib.usb import Usb28from checkbox.lib.usb import Usb
3129
3230
33class UdevDevice(object):31PCI_RE = re.compile(
34 __slots__ = ("_environment", "_attributes", "_stack")32 r"^pci:"
3533 r"v(?P<vendor_id>[%(hex)s]{8})"
36 def __init__(self, environment, attributes, stack=[]):34 r"d(?P<product_id>[%(hex)s]{8})"
37 super(UdevDevice, self).__init__()35 r"sv(?P<subvendor_id>[%(hex)s]{8})"
36 r"sd(?P<subproduct_id>[%(hex)s]{8})"
37 r"bc(?P<class>[%(hex)s]{2})"
38 r"sc(?P<subclass>[%(hex)s]{2})"
39 r"i(?P<interface>[%(hex)s]{2})"
40 % {"hex": string.hexdigits})
41PNP_RE = re.compile(
42 r"^acpi:"
43 r"(?P<vendor_name>[%(upper)s]{3})"
44 r"(?P<product_id>[%(hex)s]{4}):"
45 % {"upper": string.uppercase, "hex": string.hexdigits})
46USB_RE = re.compile(
47 r"^usb:"
48 r"v(?P<vendor_id>[%(hex)s]{4})"
49 r"p(?P<product_id>[%(hex)s]{4})"
50 r"d(?P<revision>[%(hex)s]{4})"
51 r"dc(?P<class>[%(hex)s]{2})"
52 r"dsc(?P<subclass>[%(hex)s]{2})"
53 r"dp(?P<protocol>[%(hex)s]{2})"
54 r"ic(?P<interface_class>[%(hex)s]{2})"
55 r"isc(?P<interface_subclass>[%(hex)s]{2})"
56 r"ip(?P<interface_protocol>[%(hex)s]{2})"
57 % {"hex": string.hexdigits})
58SCSI_RE = re.compile(
59 r"^scsi:"
60 r"t-0x(?P<type>[%(hex)s]{2})"
61 % {"hex": string.hexdigits})
62
63
64class UdevadmDevice:
65 __slots__ = ("_environment", "_bits", "_stack",)
66
67 def __init__(self, environment, bits=None, stack=[]):
38 self._environment = environment68 self._environment = environment
39 self._attributes = attributes69 self._bits = bits
40 self._stack = stack70 self._stack = stack
4171
42 @property72 @property
43 def bus(self):73 def bus(self):
44 return self._environment.get("SUBSYSTEM")74 # Change the bus from 'acpi' to 'pnp' for some devices
75 if PNP_RE.match(self._environment.get("MODALIAS", "")) \
76 and self.path.endswith(":00"):
77 return "pnp"
78
79 # Change the bus from 'block' to parent
80 if self._environment.get("DEVTYPE") == "disk" and self._stack:
81 return self._stack[-1]._environment.get("SUBSYSTEM")
82
83 bus = self._environment.get("SUBSYSTEM")
84 if bus == "pnp":
85 return None
86
87 return bus
4588
46 @property89 @property
47 def category(self):90 def category(self):
48 if "sys_vendor" in self._attributes:
49 return "SYSTEM"
50
51 if "IFINDEX" in self._environment:91 if "IFINDEX" in self._environment:
52 return "NETWORK"92 return "NETWORK"
5393
@@ -69,7 +109,10 @@
69 return "NETWORK"109 return "NETWORK"
70110
71 if class_id == Pci.BASE_CLASS_DISPLAY:111 if class_id == Pci.BASE_CLASS_DISPLAY:
72 return "VIDEO"112 if subclass_id == Pci.CLASS_DISPLAY_VGA:
113 return "VIDEO"
114 else:
115 return "OTHER"
73116
74 if class_id == Pci.BASE_CLASS_SERIAL \117 if class_id == Pci.BASE_CLASS_SERIAL \
75 and subclass_id == Pci.CLASS_SERIAL_USB:118 and subclass_id == Pci.CLASS_SERIAL_USB:
@@ -113,13 +156,9 @@
113 or subclass_id == Pci.CLASS_BRIDGE_CARDBUS):156 or subclass_id == Pci.CLASS_BRIDGE_CARDBUS):
114 return "SOCKET"157 return "SOCKET"
115158
116 if "bInterfaceClass" in self._attributes:159 if "TYPE" in self._environment and "INTERFACE" in self._environment:
117 interface_class = int(160 interface_class, interface_subclass, interface_protocol = (
118 self._attributes["bInterfaceClass"], 16)161 int(i) for i in self._environment["INTERFACE"].split("/"))
119 interface_subclass = int(
120 self._attributes["bInterfaceSubClass"], 16)
121 interface_protocol = int(
122 self._attributes["bInterfaceProtocol"], 16)
123162
124 if interface_class == Usb.BASE_CLASS_AUDIO:163 if interface_class == Usb.BASE_CLASS_AUDIO:
125 return "AUDIO"164 return "AUDIO"
@@ -143,6 +182,25 @@
143 else:182 else:
144 return "WIRELESS"183 return "WIRELESS"
145184
185 if "KEY" in self._environment:
186 key = self._environment["KEY"].strip("=")
187 bitmask = get_bitmask(key)
188
189 for i in range(Input.KEY_Q, Input.KEY_P + 1):
190 if not test_bit(i, bitmask, self._bits):
191 break
192 else:
193 return "KEYBOARD"
194
195 if test_bit(Input.KEY_CAMERA, bitmask, self._bits):
196 return "CAPTURE"
197
198 if test_bit(Input.BTN_TOUCH, bitmask, self._bits):
199 return "TOUCH"
200
201 if test_bit(Input.BTN_MOUSE, bitmask, self._bits):
202 return "MOUSE"
203
146 if "ID_TYPE" in self._environment:204 if "ID_TYPE" in self._environment:
147 id_type = self._environment["ID_TYPE"]205 id_type = self._environment["ID_TYPE"]
148206
@@ -155,22 +213,6 @@
155 if id_type == "video":213 if id_type == "video":
156 return "VIDEO"214 return "VIDEO"
157215
158 if "KEY" in self._environment:
159 key = self._environment["KEY"].strip("=")
160 bitmask = get_bitmask(key)
161
162 for i in range(Input.KEY_Q, Input.KEY_P + 1):
163 if not test_bit(i, bitmask):
164 break
165 else:
166 return "KEYBOARD"
167
168 if test_bit(Input.BTN_TOUCH, bitmask):
169 return "TOUCH"
170
171 if test_bit(Input.BTN_MOUSE, bitmask):
172 return "MOUSE"
173
174 if "DEVTYPE" in self._environment:216 if "DEVTYPE" in self._environment:
175 devtype = self._environment["DEVTYPE"]217 devtype = self._environment["DEVTYPE"]
176 if devtype == "disk":218 if devtype == "disk":
@@ -181,8 +223,10 @@
181 return "FLOPPY"223 return "FLOPPY"
182224
183 if devtype == "scsi_device":225 if devtype == "scsi_device":
184 type = int(self._attributes.get("type", "-1"))226 match = SCSI_RE.match(self._environment.get("MODALIAS", ""))
185 # Check for FLASH drives, see /lib/udev/rules.d/80-udisks.rules227 type = int(match.group("type"), 16) if match else -1
228
229 # Check FLASH drives, see /lib/udev/rules.d/80-udisks.rules
186 if type in (0, 7, 14) \230 if type in (0, 7, 14) \
187 and not any(d.driver == "rts_pstor" for d in self._stack):231 and not any(d.driver == "rts_pstor" for d in self._stack):
188 return "DISK"232 return "DISK"
@@ -216,8 +260,11 @@
216 if "DRIVER" in self._environment:260 if "DRIVER" in self._environment:
217 return self._environment["DRIVER"]261 return self._environment["DRIVER"]
218262
219 if "ID_USB_DRIVER" in self._environment:263 # Check parent device for driver
220 return self._environment["ID_USB_DRIVER"]264 if self._stack:
265 parent = self._stack[-1]
266 if "DRIVER" in parent._environment:
267 return parent._environment["DRIVER"]
221268
222 return None269 return None
223270
@@ -228,48 +275,36 @@
228 @property275 @property
229 def product_id(self):276 def product_id(self):
230 # pci277 # pci
231 if "PCI_ID" in self._environment:278 match = PCI_RE.match(self._environment.get("MODALIAS", ""))
232 vendor_id, product_id = self._environment["PCI_ID"].split(":")279 if match:
233 return int(product_id, 16)280 return int(match.group("product_id"), 16)
234281
235 # usb interface282 # usb
236 if "PRODUCT" in self._environment \283 match = USB_RE.match(self._environment.get("MODALIAS", ""))
237 and self._environment.get("DEVTYPE") == "usb_interface":284 if match:
238 vendor_id, product_id, revision \285 return int(match.group("product_id"), 16)
239 = self._environment["PRODUCT"].split("/")
240 return int(product_id, 16)
241
242 # usb device and ieee1394
243 for attribute in "idProduct", "model_id":
244 if attribute in self._attributes:
245 return int(self._attributes[attribute], 16)
246286
247 # pnp287 # pnp
248 if "id" in self._attributes:288 match = PNP_RE.match(self._environment.get("MODALIAS", ""))
249 match = re.match(r"^(?P<vendor_name>.*)(?P<product_id>[%s]{4})$"289 if match:
250 % string.hexdigits, self._attributes["id"])290 product_id = int(match.group("product_id"), 16)
251 if match:291 # Ignore interrupt controllers
252 return int(match.group("product_id"), 16)292 if product_id > 0x0100:
293 return product_id
253294
254 return None295 return None
255296
256 @property297 @property
257 def vendor_id(self):298 def vendor_id(self):
258 # pci299 # pci
259 if "PCI_ID" in self._environment:300 match = PCI_RE.match(self._environment.get("MODALIAS", ""))
260 vendor_id, product_id = self._environment["PCI_ID"].split(":")301 if match:
261 return int(vendor_id, 16)302 return int(match.group("vendor_id"), 16)
262303
263 # usb interface304 # usb
264 if "PRODUCT" in self._environment \305 match = USB_RE.match(self._environment.get("MODALIAS", ""))
265 and self._environment.get("DEVTYPE") == "usb_interface":306 if match:
266 vendor_id, product_id, revision \307 return int(match.group("vendor_id"), 16)
267 = self._environment["PRODUCT"].split("/")
268 return int(vendor_id, 16)
269
270 # usb device
271 if "idVendor" in self._attributes:
272 return int(self._attributes["idVendor"], 16)
273308
274 return None309 return None
275310
@@ -299,16 +334,19 @@
299 if element in self._environment:334 if element in self._environment:
300 return self._environment[element].strip('"')335 return self._environment[element].strip('"')
301336
302 for attribute in ("description",337 # disk
303 "model_name_kv",338 if self._environment.get("DEVTYPE") == "scsi_device":
304 "model",339 for device in reversed(self._stack):
305 "product_name"):340 if device._environment.get("ID_BUS") == "usb":
306 if attribute in self._attributes:341 return decode_id(device._environment["ID_MODEL_ENC"])
307 return self._attributes[attribute]342
343 if self._environment.get("DEVTYPE") == "disk" \
344 and self._environment.get("ID_BUS") == "ata":
345 return decode_id(self._environment["ID_MODEL_ENC"])
308346
309 # floppy347 # floppy
310 if self.driver == "floppy":348 if self.driver == "floppy":
311 return "Platform Device"349 return u"Platform Device"
312350
313 return None351 return None
314352
@@ -320,168 +358,28 @@
320 if "POWER_SUPPLY_MANUFACTURER" in self._environment:358 if "POWER_SUPPLY_MANUFACTURER" in self._environment:
321 return self._environment["POWER_SUPPLY_MANUFACTURER"]359 return self._environment["POWER_SUPPLY_MANUFACTURER"]
322360
323 if "vendor" in self._attributes:
324 vendor = self._attributes["vendor"]
325 if not re.match(r"^0x[%s]{4}$" % string.hexdigits, vendor):
326 return vendor
327
328 # dmi
329 if "sys_vendor" in self._attributes:
330 return self._attributes["sys_vendor"]
331
332 # pnp361 # pnp
333 if "id" in self._attributes:362 match = PNP_RE.match(self._environment.get("MODALIAS", ""))
334 match = re.match(r"^(?P<vendor_name>.*)(?P<product_id>[%s]{4})$"363 if match:
335 % string.hexdigits, self._attributes["id"])364 return match.group("vendor_name")
336 if match:365
337 return match.group("vendor_name")366 # disk
338367 if self._environment.get("DEVTYPE") == "scsi_device":
339 return None368 for device in reversed(self._stack):
340369 if device._environment.get("ID_BUS") == "usb":
341370 return decode_id(device._environment["ID_VENDOR_ENC"])
342class UdevLocalDevice(UdevDevice):371
343372 return None
344 @property373
345 def bus(self):374
346 sys_path = posixpath.join(375class UdevadmParser:
347 "/sys%s" % self._environment["DEVPATH"], "subsystem")376 """Parser for the udevadm command."""
348 if posixpath.islink(sys_path):377
349 link = os.readlink(sys_path)378 device_factory = UdevadmDevice
350 if "/" in link:379
351 return posixpath.basename(link)380 def __init__(self, stream, bits=None):
352
353 return None
354
355 @property
356 def vendor_id(self):
357 vendor_id = super(UdevLocalDevice, self).vendor_id
358 if vendor_id is not None:
359 return vendor_id
360
361 # ieee1394
362 vendor_id_path = posixpath.join(self.path, "../vendor_id")
363 if posixpath.exists(vendor_id_path):
364 vendor_id = open(vendor_id_path, "r").read().strip()
365 return int(vendor_id, 16)
366
367 return None
368
369 @property
370 def product(self):
371 product = super(UdevLocalDevice, self).product
372 if product is not None:
373 return product
374
375 # sound
376 bus = self.bus
377 if bus == "sound":
378 device = posixpath.basename(self._environment["DEVPATH"])
379 match = re.match(
380 r"(card|controlC|hwC|midiC)(?P<card>\d+)", device)
381 if match:
382 card = match.group("card")
383 in_card = False
384 file = open("/proc/asound/cards", "r")
385 for line in file.readlines():
386 line = line.strip()
387 match = re.match(r"(?P<card>\d+) \[", line)
388 if match:
389 in_card = match.group("card") == card
390
391 if in_card:
392 match = re.match(r"""(?P<name>.*) """
393 """at (?P<address>0x[%s]{8}) """
394 """irq (?P<irq>\d+)""" % string.hexdigits, line)
395 if match:
396 return match.group("name")
397
398 path = None
399 match = re.match(
400 r"pcmC(?P<card>\d+)D(?P<device>\d+)(?P<type>\w)", device)
401 if match:
402 path = "/proc/asound/card%s/pcm%s%c/info" % match.groups()
403
404 match = re.match(
405 r"(dsp|adsp|midi|amidi|audio|mixer)(?P<card>\d+)?", device)
406 if match:
407 card = match.group("card") or 0
408 path = "/proc/asound/card%s/pcm0p/info" % card
409
410 if path and posixpath.exists(path):
411 file = open(path, "r")
412 for line in file.readlines():
413 match = re.match(r"name: (?P<name>.*)", line)
414 if match:
415 return match.group("name")
416
417 return None
418
419 @property
420 def vendor(self):
421 vendor = super(UdevLocalDevice, self).vendor
422 if vendor is not None:
423 return vendor
424
425 # ieee1394
426 vendor_path = posixpath.join(self.path, "../vendor_oui")
427 if posixpath.exists(vendor_path):
428 return open(vendor_path, "r").read().strip()
429
430 return None
431
432
433class UdevDmiDevice(UdevDevice):
434
435 def __init__(self, environment, attributes, category):
436 super(UdevDmiDevice, self).__init__(environment, attributes)
437 self._category = category
438
439 @property
440 def category(self):
441 return self._category
442
443 @property
444 def path(self):
445 path = super(UdevDmiDevice, self).path
446 return posixpath.join(path, self._category.lower())
447
448 @property
449 def product(self):
450 if self._category == "CHASSIS":
451 type_string = self._attributes.get("chassis_type", "0")
452 type_index = int(type_string)
453 return Dmi.chassis_names[type_index]
454
455 for name in "name", "version":
456 attribute = "%s_%s" % (self._category.lower(), name)
457 product = self._attributes.get(attribute)
458 if product and product != "Not Available":
459 return product
460
461 return None
462
463 @DmiNotAvailable
464 def _getVendor(self):
465 attribute = "%s_vendor" % self._category.lower()
466 if attribute in self._attributes:
467 return self._attributes[attribute]
468
469 return None
470
471 @property
472 def vendor(self):
473 return self._getVendor()
474
475
476class UdevParser(object):
477 """udevadm parser."""
478
479 device_factory = UdevDevice
480 dmi_device_factory = UdevDmiDevice
481
482 def __init__(self, stream):
483 self.stream = stream381 self.stream = stream
484 self.stack = []382 self.bits = bits
485383
486 def _ignoreDevice(self, device):384 def _ignoreDevice(self, device):
487 # Ignore devices without bus information385 # Ignore devices without bus information
@@ -499,9 +397,8 @@
499 and device.subvendor_id is None)):397 and device.subvendor_id is None)):
500 return True398 return True
501399
502 # Ignore virtual devices except for dmi information400 # Ignore ACPI devices
503 if device.bus != "dmi" \401 if device.bus == "acpi":
504 and "virtual" in device.path.split(posixpath.sep):
505 return True402 return True
506403
507 return False404 return False
@@ -510,96 +407,60 @@
510 return {}407 return {}
511408
512 def run(self, result):409 def run(self, result):
513 line_pattern = re.compile(r"(?P<key>\w):\s*(?P<value>.*)")410 # Some attribute lines have a space character after the
411 # ':', others don't have it (see udevadm-info.c).
412 line_pattern = re.compile(r"(?P<key>[A-Z]):\s*(?P<value>.*)")
514 multi_pattern = re.compile(r"(?P<key>[^=]+)=(?P<value>.*)")413 multi_pattern = re.compile(r"(?P<key>[^=]+)=(?P<value>.*)")
515414
415 stack = []
516 output = self.stream.read()416 output = self.stream.read()
517 for record in output.split("\n\n"):417 for record in re.split("\n{2,}", output):
418 record = record.strip()
518 if not record:419 if not record:
519 continue420 continue
520421
521 # Determine path and environment422 # Determine path and environment
522 path = None423 path = None
424 element = None
523 environment = {}425 environment = {}
524 for line in record.split("\n"):426 for line in record.split("\n"):
525 if not line:427 line_match = line_pattern.match(line)
428 if not line_match:
429 if environment:
430 # Append to last environment element
431 environment[element] += line
526 continue432 continue
527433
528 match = line_pattern.match(line)434 key = line_match.group("key")
529 if not match:435 value = line_match.group("value")
530 raise Exception(
531 "Device line not supported: %s" % line)
532
533 key = match.group("key")
534 value = match.group("value")
535436
536 if key == "P":437 if key == "P":
537 path = value438 path = value
538 elif key == "E":439 elif key == "E":
539 match = multi_pattern.match(value)440 key_match = multi_pattern.match(value)
540 if not match:441 if not key_match:
541 raise Exception(442 raise Exception(
542 "Device property not supported: %s" % value)443 "Device property not supported: %s" % value)
543 environment[match.group("key")] = match.group("value")444 element = key_match.group("key")
445 environment[element] = key_match.group("value")
544446
545 # Update stack447 # Update stack
546 while self.stack:448 while stack:
547 if self.stack[-1].path + "/" in path:449 if stack[-1].path + "/" in path:
548 break450 break
549 self.stack.pop()451 stack.pop()
550452
551 # Set default DEVPATH453 # Set default DEVPATH
552 environment.setdefault("DEVPATH", path)454 environment.setdefault("DEVPATH", path)
553455
554 # Determine attributes456 device = self.device_factory(environment, self.bits, list(stack))
555 attributes = self.getAttributes(path)457 if not self._ignoreDevice(device):
556458 result.addDevice(device)
557 if path == "/devices/virtual/dmi/id":459
558 device = self.device_factory(environment, attributes)460 stack.append(device)
559 if not self._ignoreDevice(device):461
560 result.addDevice(device)462
561 for category in "BIOS", "BOARD", "CHASSIS":463def decode_id(id):
562 device = self.dmi_device_factory(464 encoded_id = id.encode("utf-8")
563 environment, attributes, category)465 decoded_id = encoded_id.decode("string-escape").decode("utf-8")
564 if not self._ignoreDevice(device):466 return decoded_id.strip()
565 result.addDevice(device)
566 else:
567 device = self.device_factory(environment, attributes, self.stack)
568 if not self._ignoreDevice(device):
569 result.addDevice(device)
570
571 self.stack.append(device)
572
573
574class UdevLocalParser(UdevParser):
575
576 device_factory = UdevLocalDevice
577
578 def getAttributes(self, path):
579 attributes = {}
580 sys_path = "/sys%s" % path
581 try:
582 names = os.listdir(sys_path)
583 except OSError:
584 return attributes
585
586 for name in names:
587 name_path = posixpath.join(sys_path, name)
588 if name[0] == "." \
589 or name in ["dev", "uevent"] \
590 or posixpath.isdir(name_path) \
591 or posixpath.islink(name_path):
592 continue
593
594 try:
595 value = open(name_path, "r").read().strip()
596 except IOError:
597 continue
598
599 value = value.split("\n")[0]
600 if [c for c in value if not isprint(c)]:
601 continue
602
603 attributes[name] = value
604
605 return attributes
606467
=== modified file 'checkbox_cli/cli_interface.py'
--- checkbox_cli/cli_interface.py 2011-06-13 14:22:39 +0000
+++ checkbox_cli/cli_interface.py 2011-11-18 18:04:27 +0000
@@ -145,7 +145,15 @@
145145
146 def add_option(self, option, key=None):146 def add_option(self, option, key=None):
147 if key is None:147 if key is None:
148 for key in option.lower()+string.lowercase:148 keys = option.lower() + \
149 string.ascii_letters + \
150 string.digits + \
151 string.punctuation
152
153 keys = keys.replace(' ','')
154 keys = keys.replace('+', '')
155
156 for key in keys:
149 if key not in self.keys:157 if key not in self.keys:
150 break158 break
151 self.keys.append(key)159 self.keys.append(key)
152160
=== modified file 'checkbox_gtk/gtk_interface.py'
--- checkbox_gtk/gtk_interface.py 2011-09-29 13:12:01 +0000
+++ checkbox_gtk/gtk_interface.py 2011-11-18 18:04:27 +0000
@@ -102,10 +102,8 @@
102 image_head.connect("expose-event",self.draw_image_head)102 image_head.connect("expose-event",self.draw_image_head)
103103
104 # Set wait transient for dialog104 # Set wait transient for dialog
105 self._wait = self._get_widget("window_wait")105 self._wait = self._get_widget("box_wait")
106 self._wait.set_transient_for(self._dialog)106 self._wait.hide()
107 self._wait.realize()
108 self._wait.get_window().set_functions(Gdk.WMFunction.MOVE)
109107
110 # Set shorthand for notebook108 # Set shorthand for notebook
111 self._notebook = self._get_widget("notebook_main")109 self._notebook = self._get_widget("notebook_main")
@@ -539,6 +537,8 @@
539 test["data"] = self._get_text_view("text_view_comment")537 test["data"] = self._get_text_view("text_view_comment")
540 test["status"] = self._get_radio_button(BUTTON_TO_STATUS)538 test["status"] = self._get_radio_button(BUTTON_TO_STATUS)
541539
540 self._set_main_title()
541
542 def show_info(self, text, options=[], default=None):542 def show_info(self, text, options=[], default=None):
543 message_dialog = Gtk.MessageDialog(parent=self._dialog,543 message_dialog = Gtk.MessageDialog(parent=self._dialog,
544 type=Gtk.MessageType.INFO,544 type=Gtk.MessageType.INFO,
545545
=== modified file 'data/whitelists/default.whitelist'
--- data/whitelists/default.whitelist 2011-09-29 13:12:01 +0000
+++ data/whitelists/default.whitelist 2011-11-18 18:04:27 +0000
@@ -1,6 +1,7 @@
1cdimage1cdimage
2cpuinfo2cpuinfo
3device3device
4dmi
4dpkg5dpkg
5gconf6gconf
6lsb7lsb
78
=== modified file 'debian/changelog'
--- debian/changelog 2011-09-29 13:12:01 +0000
+++ debian/changelog 2011-11-18 18:04:27 +0000
@@ -1,3 +1,62 @@
1checkbox (0.13) precise; urgency=low
2
3 New upstream release (LP: #892268):
4
5 [Marc Tardif]
6 * Generate a submission.xml file that contains all device and attachment
7 * Write the report before reporting the validation error.
8 * Changed device.product to dmi.product for the formfactor (LP: #875312)
9
10 [Daniel Manrique]
11 * Use gettext for string (LP: #869267)
12 * Move progress indicator to main checkbox dialog instead of a
13 transient window (LP: #868995)
14 * Ignore malformed dpkg entries in package_resource (LP: #794747)
15 * Reset window title after finishing a manual test (LP: #874690)
16 * Handle "@" in locale names (as in ca@valencia).
17
18 [Jeff Lane]
19 * Went through all the job files and:
20 * Updated descriptions to match Unity UI structure
21 * Added descriptions where necessary
22 * Added further details to some descriptions
23 * Moved some jobs to more appropriate files
24 * Fixed job names in older job files to match new naming scheme
25 (suite/testname)
26 * Added jobs to local.txt to ensure all job files are now parsed
27 (this allows easier addition of existing tests to whitelists)
28 * Changed remaining manual job descriptions to match the new format
29 * Updated CD and DVD write tests to be more clear about when to skip
30 them (LP: #772794)
31
32 [Ara Pulido]
33 * Rewrote all job descriptions to match OEM QA syntax
34
35 [Brendan Donegan]
36 * Fix the code that assigns keys in checkbox-cli so that it never assigns
37 keys which have other uses. (LP: #877467)
38 * Show details of unmet job requirements (LP: #855852)
39 * Ensure that connect_wireless chooses a wireless connection from the list
40 of available connections (LP: #877752)
41 * Have the bluetooth/detect tests require a device with the category
42 BLUETOOTH to run, thus preventing the test from failing on systems with
43 no Bluetooth device (LP: #862322)
44 * Rename attachment jobs to not have a forward slash in their name
45 (LP: #887964)
46 * Guard against trying to write files to logical partitions on USB sticks
47 (which will obviously fail) in usb_test (LP: #887049)
48 * Make the OpenGL test ignore the return value of glxgears and improve
49 the test description (LP: #890725)
50 * Allow input/mouse test to run if a TOUCH device is present
51 (LP: #886129)
52
53 [ Javier Collado ]
54 * Broken job dependencies fixed (LP: #888447)
55 * Regex support when specifying blacklists and whitelists on the
56 commandline (LP: #588647)
57
58 -- Daniel Manrique <daniel.manrique@canonical.com> Thu, 18 Nov 2011 12:46:21 -0500
59
1checkbox (0.12.8) oneiric; urgency=low60checkbox (0.12.8) oneiric; urgency=low
261
3 New upstream release (LP: #862579):62 New upstream release (LP: #862579):
463
=== added file 'debian/po/ro.po'
--- debian/po/ro.po 1970-01-01 00:00:00 +0000
+++ debian/po/ro.po 2011-11-18 18:04:27 +0000
@@ -0,0 +1,118 @@
1# Romanian translation for checkbox
2# Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011
3# This file is distributed under the same license as the checkbox package.
4# FIRST AUTHOR <EMAIL@ADDRESS>, 2011.
5#
6msgid ""
7msgstr ""
8"Project-Id-Version: checkbox\n"
9"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10"POT-Creation-Date: 2011-03-29 15:19+0200\n"
11"PO-Revision-Date: 2011-10-27 20:38+0000\n"
12"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
13"Language-Team: Romanian <ro@li.org>\n"
14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
17"X-Launchpad-Export-Date: 2011-10-28 05:11+0000\n"
18"X-Generator: Launchpad (build 14197)\n"
19
20#. Type: boolean
21#. Description
22#: ../checkbox.templates:1001
23msgid "Enable bug reporting by default? "
24msgstr ""
25
26#. Type: boolean
27#. Description
28#: ../checkbox.templates:1001
29msgid ""
30"If this option is set to Yes, then checkbox will ask if the user wants to "
31"file a bug for failing tests, even if apport is not enabled."
32msgstr ""
33
34#. Type: string
35#. Description
36#: ../checkbox.templates:2001
37msgid "Default package to report bugs against:"
38msgstr ""
39
40#. Type: string
41#. Description
42#: ../checkbox.templates:2001
43msgid ""
44"When filing a new bug through checkbox, if it does not guess the package, "
45"the default package that the bug will be file against."
46msgstr ""
47
48#. Type: string
49#. Description
50#: ../checkbox.templates:3001
51msgid "Test suite blacklist:"
52msgstr ""
53
54#. Type: string
55#. Description
56#: ../checkbox.templates:3001
57msgid "List of job files to never run when testing with checkbox."
58msgstr ""
59
60#. Type: string
61#. Description
62#: ../checkbox.templates:4001
63msgid "Test suite whitelist:"
64msgstr ""
65
66#. Type: string
67#. Description
68#: ../checkbox.templates:4001
69msgid "List of jobs to run when testing with checkbox."
70msgstr ""
71
72#. Type: string
73#. Description
74#: ../checkbox.templates:5001
75msgid "Transport URL:"
76msgstr ""
77
78#. Type: string
79#. Description
80#: ../checkbox.templates:5001
81msgid "URL where to send submissions."
82msgstr ""
83
84#. Type: string
85#. Description
86#: ../checkbox.templates:6001
87msgid "Launchpad E-mail:"
88msgstr ""
89
90#. Type: string
91#. Description
92#: ../checkbox.templates:6001
93msgid "E-mail address used to sign in to Launchpad."
94msgstr ""
95
96#. Type: string
97#. Description
98#: ../checkbox.templates:7001
99msgid "HTTP Proxy:"
100msgstr ""
101
102#. Type: string
103#. Description
104#: ../checkbox.templates:7001
105msgid "HTTP proxy to use instead of the one specified in environment."
106msgstr ""
107
108#. Type: string
109#. Description
110#: ../checkbox.templates:8001
111msgid "HTTPS Proxy:"
112msgstr ""
113
114#. Type: string
115#. Description
116#: ../checkbox.templates:8001
117msgid "HTTPS proxy to use instead of the one specified in environment."
118msgstr ""
0119
=== modified file 'examples/checkbox.ini'
--- examples/checkbox.ini 2010-03-09 16:58:36 +0000
+++ examples/checkbox.ini 2011-11-18 18:04:27 +0000
@@ -22,5 +22,5 @@
22[checkbox/plugins/jobs_info]22[checkbox/plugins/jobs_info]
2323
24# Blacklist of jobs that are potentially dangerous24# Blacklist of jobs that are potentially dangerous
25blacklist = autotest ltp phoronix qa-regression-testing25blacklist = autotest/full_suite ltp phoronix qa-regression-testing
26 clone06.1 ioctl03.1 lchown02.* swapon03.126 clone06.1 ioctl03.1 lchown02.* swapon03.1
2727
=== modified file 'gtk/checkbox-gtk.ui'
--- gtk/checkbox-gtk.ui 2011-06-13 14:22:39 +0000
+++ gtk/checkbox-gtk.ui 2011-11-18 18:04:27 +0000
@@ -374,6 +374,43 @@
374 <property name="position">2</property>374 <property name="position">2</property>
375 </packing>375 </packing>
376 </child>376 </child>
377 <child>
378 <object class="GtkBox" id="box_wait">
379 <property name="visible">True</property>
380 <property name="can_focus">False</property>
381 <property name="orientation">vertical</property>
382 <child>
383 <object class="GtkLabel" id="label_wait">
384 <property name="visible">True</property>
385 <property name="can_focus">False</property>
386 </object>
387 <packing>
388 <property name="expand">False</property>
389 <property name="fill">False</property>
390 <property name="position">0</property>
391 </packing>
392 </child>
393 <child>
394 <object class="GtkProgressBar" id="progressbar_wait">
395 <property name="visible">True</property>
396 <property name="can_focus">False</property>
397 <property name="pulse_step">0.10000000149</property>
398 </object>
399 <packing>
400 <property name="expand">False</property>
401 <property name="fill">False</property>
402 <property name="position">1</property>
403 </packing>
404 </child>
405 </object>
406 <packing>
407 <property name="expand">False</property>
408 <property name="fill">True</property>
409 <property name="position">3</property>
410 </packing>
411 </child>
412
413
377 <child internal-child="action_area">414 <child internal-child="action_area">
378 <object class="GtkHButtonBox" id="dialog-action_area">415 <object class="GtkHButtonBox" id="dialog-action_area">
379 <property name="visible">True</property>416 <property name="visible">True</property>
@@ -452,41 +489,4 @@
452 <action-widget response="1">button_next</action-widget>489 <action-widget response="1">button_next</action-widget>
453 </action-widgets>490 </action-widgets>
454 </object>491 </object>
455 <object class="GtkWindow" id="window_wait">
456 <property name="title" translatable="yes"></property>
457 <property name="border_width">6</property>
458 <property name="resizable">False</property>
459 <property name="modal">True</property>
460 <property name="window_position">center-on-parent</property>
461 <property name="type_hint">dialog</property>
462 <property name="skip_taskbar_hint">True</property>
463 <property name="skip_pager_hint">True</property>
464 <child>
465 <object class="GtkVBox" id="vbox_wait">
466 <property name="visible">True</property>
467 <property name="spacing">12</property>
468 <child>
469 <object class="GtkLabel" id="label_wait">
470 <property name="visible">True</property>
471 </object>
472 <packing>
473 <property name="expand">False</property>
474 <property name="fill">False</property>
475 <property name="position">0</property>
476 </packing>
477 </child>
478 <child>
479 <object class="GtkProgressBar" id="progressbar_wait">
480 <property name="visible">True</property>
481 <property name="pulse_step">0.10000000149</property>
482 </object>
483 <packing>
484 <property name="expand">False</property>
485 <property name="fill">False</property>
486 <property name="position">1</property>
487 </packing>
488 </child>
489 </object>
490 </child>
491 </object>
492</interface>492</interface>
493493
=== removed file 'jobs/apport.txt.in'
--- jobs/apport.txt.in 2011-07-01 11:37:27 +0000
+++ jobs/apport.txt.in 1970-01-01 00:00:00 +0000
@@ -1,5 +0,0 @@
1plugin: shell
2name: apport-directory
3requires: package.name == 'apport'
4command: ! test -d /var/crash || test $(find /var/crash -type f | wc -l) -eq 0
5_description: Test that the /var/crash directory doesn't contain anything.
60
=== modified file 'jobs/audio.txt.in'
--- jobs/audio.txt.in 2011-09-01 12:23:07 +0000
+++ jobs/audio.txt.in 2011-11-18 18:04:27 +0000
@@ -1,15 +1,10 @@
1plugin: manual1plugin: shell
2name: audio/list_devices2name: audio/list_devices
3requires:3requires:
4 device.category == 'AUDIO'4 device.category == 'AUDIO'
5 package.name == 'alsa-base'5 package.name == 'alsa-base'
6command: cat /proc/asound/cards6command: cat /proc/asound/cards
7_description:7_description: Test to detect audio devices
8 Detecting your sound device(s):
9 .
10 $output
11 .
12 Is this correct?
138
14plugin: manual9plugin: manual
15name: audio/playback_auto10name: audio/playback_auto
@@ -19,9 +14,14 @@
19 package.name == 'alsa-base' and package.name == 'python-gst0.10'14 package.name == 'alsa-base' and package.name == 'python-gst0.10'
20command: gst_pipeline_test -t 2 'audiotestsrc wave=sine freq=512 ! audioconvert ! audioresample ! gconfaudiosink'15command: gst_pipeline_test -t 2 'audiotestsrc wave=sine freq=512 ! audioconvert ! audioresample ! gconfaudiosink'
21_description:16_description:
22 Select Test to play a sound on the automatically detected playback device.17 PURPOSE:
23 .18 This test will check that internal speakers work correctly
24 Did you hear a sound and was that sound free of any distortion, clicks or other strange noises?19 STEPS:
20 1. Make sure that no external speakers or headphones are connected
21 If testing a desktop, external speakers are allowed
22 2. Click the Test button to play a brief tone on your audio device
23 VERIFICATION:
24 Did you hear a tone?
2525
26plugin: manual26plugin: manual
27name: audio/playback_headphones27name: audio/playback_headphones
@@ -31,11 +31,13 @@
31 package.name == 'alsa-base' and package.name == 'python-gst0.10'31 package.name == 'alsa-base' and package.name == 'python-gst0.10'
32command: gst_pipeline_test -t 2 'audiotestsrc wave=sine freq=512 ! audioconvert ! audioresample ! gconfaudiosink'32command: gst_pipeline_test -t 2 'audiotestsrc wave=sine freq=512 ! audioconvert ! audioresample ! gconfaudiosink'
33_description:33_description:
34 Please connect a pair of headphones to your audio device.34 PURPOSE:
35 .35 This test will check that headphones connector works correctly
36 Select Test to play a sound on the automatically detected playback device.36 STEPS:
37 .37 1. Connect a pair of headphones to your audio device
38 Did you hear a sound through the headphones and did the sound play without any distortion, clicks or other strange noises from your headphones?38 2. Click the Test button to play a sound to your audio device
39 VERIFICATION:
40 Did you hear a sound through the headphones and did the sound play without any distortion, clicks or other strange noises from your headphones?
3941
40plugin: manual42plugin: manual
41name: audio/alsa_record_playback_internal43name: audio/alsa_record_playback_internal
@@ -45,9 +47,14 @@
45 package.name == 'alsa-base'47 package.name == 'alsa-base'
46command: alsa_record_playback48command: alsa_record_playback
47_description:49_description:
48 Disconnect any external microphones that you have plugged in. Select Test, then speak into your internal microphone. After a few seconds, your speech will be played back to you.50 PURPOSE:
49 .51 This test will check that recording sound using the onboard microphone works correctly
50 Did you hear your speech played back?52 STEPS:
53 1. Disconnect any external microphones that you have plugged in
54 2. Click "Test", then speak into your internal microphone
55 3. After a few seconds, your speech will be played back to you.
56 VERIFICATION:
57 Did you hear your speech played back?
5158
52plugin: manual59plugin: manual
53name: audio/alsa_record_playback_external60name: audio/alsa_record_playback_external
@@ -57,9 +64,14 @@
57 package.name == 'alsa-base'64 package.name == 'alsa-base'
58command: alsa_record_playback65command: alsa_record_playback
59_description:66_description:
60 Connect a microphone to your microphone port. Select Test, then speak into the microphone. After a few seconds, your speech will be played back to you.67 PURPOSE:
61 .68 This test will check that recording sound using an external microphone works correctly
62 Did you hear your speech played back?69 STEPS:
70 1. Connect a microphone to your microphone port
71 2. Click "Test", then speak into the external microphone
72 3. After a few seconds, your speech will be played back to you
73 VERIFICATION:
74 Did you hear your speech played back?
6375
64plugin: manual76plugin: manual
65name: audio/alsa_record_playback_usb77name: audio/alsa_record_playback_usb
@@ -68,9 +80,17 @@
68 package.name == 'alsa-base'80 package.name == 'alsa-base'
69command: alsa_record_playback81command: alsa_record_playback
70_description:82_description:
71 Connect a USB audio device to your system. Then open the volume control application by left-clicking on the speaker icon in the panel and selecting "Sound Preferences". Select the "Input" tab and choose your USB device. Select the "Output" tab and choose your USB device. When you are done, select Test, then speak into the microphone. After a few seconds, your speech will be played back to you.83 PURPOSE:
72 .84 This test will check that a USB audio device works correctly
73 Did you hear your speech played back?85 STEPS:
86 1. Connect a USB audio device to your system
87 2. Open the volume control application by left-clicking on the speaker icon in the panel and selecting "Sound Settings"
88 3. Select the "Input" tab and choose your USB device
89 4. Select the "Output" tab and choose your USB device
90 5. Click "Test", then speak into the microphone
91 6. After a few seconds, your speech will be played back to you
92 VERIFICATION:
93 Did you hear your speech played back through the USB headphones?
7494
75plugin: shell95plugin: shell
76name: audio/alsa_record_playback_automated96name: audio/alsa_record_playback_automated
7797
=== modified file 'jobs/autotest.txt.in'
--- jobs/autotest.txt.in 2010-03-09 16:58:36 +0000
+++ jobs/autotest.txt.in 2011-11-18 18:04:27 +0000
@@ -1,6 +1,8 @@
1name: autotest1name: autotest/full_suite
2plugin: remote2plugin: remote
3_description: Autotest suite (destructive)
4user: root3user: root
5timeout: 12004timeout: 1200
6command: autotest_suite5command: autotest_suite
6_description:
7 PURPOSE:
8 This test will attempt to install and run the Autotest Suite. These tests can be destructive, so this test is blacklisted by default.
79
=== modified file 'jobs/bluetooth.txt.in'
--- jobs/bluetooth.txt.in 2011-09-01 12:23:07 +0000
+++ jobs/bluetooth.txt.in 2011-11-18 18:04:27 +0000
@@ -1,88 +1,100 @@
1plugin: shell 1plugin: shell
2name: bluetooth/detect2name: bluetooth/detect
3requires: package.name == 'bluez'3requires:
4 package.name == 'bluez'
5 device.category == 'BLUETOOTH'
4command: hcitool dev | tail -n+2 | awk '{print $2}' |grep -E "^([0-9a-fA-F]{2}\:){5}[0-9a-fA-F]{2}$"6command: hcitool dev | tail -n+2 | awk '{print $2}' |grep -E "^([0-9a-fA-F]{2}\:){5}[0-9a-fA-F]{2}$"
5_description:7_description:
6 Output address of detected Bluetooth device, if any, or exits with error if none is found.8 This test will detect your Bluetooth device and output the device's hardware address. If no device is found, the test will exit with an error.
79
8plugin: shell10plugin: shell
9name: bluetooth/detect-output11name: bluetooth/detect-output
10requires: package.name == 'bluez'12requires:
13 package.name == 'bluez'
14 device.category == 'BLUETOOTH'
11command: hcitool dev | tail -n+2 | awk '{print $2}'; hcitool dev | tail -n+2 | awk '{print $2}' > $CHECKBOX_DATA/bluetooth_address15command: hcitool dev | tail -n+2 | awk '{print $2}'; hcitool dev | tail -n+2 | awk '{print $2}' > $CHECKBOX_DATA/bluetooth_address
12_description:16_description:
13 Automated test to store output in checkbox report17 Automated test to store bluetooth device information in checkbox report
1418
15plugin: manual19plugin: manual
16name: bluetooth/browse-files20name: bluetooth/browse-files
17depends: bluetooth/detect21depends: bluetooth/detect
18_description:22_description:
19 Bluetooth browse files procedure:23 PURPOSE:
20 1.- Enable bluetooth on any mobile device (PDA, smartphone, etc.)24 This test will check that bluetooth connection works correctly
21 2.- Click on the bluetooth icon in the menu bar25 STEPS:
22 3.- Select 'Setup new device'26 1. Enable bluetooth on any mobile device (PDA, smartphone, etc.)
23 3.- Look for the device in the list and select it27 2. Click on the bluetooth icon in the menu bar
24 4.- In the device write the PIN code automatically chosen by the wizard28 3. Select 'Setup new device'
25 5.- The device should pair with the computer29 4. Look for the device in the list and select it
26 6.- Right-click on the bluetooth icon and select browse files30 5. In the device write the PIN code automatically chosen by the wizard
27 7.- Authorize the computer to browse the files in the device if needed31 6. The device should pair with the computer
28 8.- You should be able to browse the files32 7. Right-click on the bluetooth icon and select browse files
29 .33 8. Authorize the computer to browse the files in the device if needed
30 Did all the steps work?34 9. You should be able to browse the files
35 VERIFICATION:
36 Did all the steps work?
3137
32plugin: manual38plugin: manual
33name: bluetooth/file-transfer39name: bluetooth/file-transfer
34depends: bluetooth/browse-files bluetooth/detect40depends: bluetooth/browse-files bluetooth/detect
35_description:41_description:
36 Bluetooth file transfer procedure:42 PURPOSE:
37 1.- Make sure that you're able to browse the files in your mobile device43 This test will check that you can transfer information through a bluetooth connection
38 2.- Copy a file from the computer to the mobile device44 STEPS:
39 3.- Verify that the file was correctly copied45 1. Make sure that you're able to browse the files in your mobile device
40 4.- Copy a file from the mobile device to the computer46 2. Copy a file from the computer to the mobile device
41 5.- Verify that the file was correctly copied47 3. Copy a file from the mobile device to the computer
42 .48 VERIFICATION:
43 Did all the steps work?49 Were all files copied correctly?
4450
45plugin: manual51plugin: manual
46name: bluetooth/audio52name: bluetooth/audio
47depends: bluetooth/detect53depends: bluetooth/detect
48requires: package.name == 'alsa-utils'
49command: arecord -d 5 -D bluetooth -f S16_LE | aplay -D bluetooth -f S16_LE54command: arecord -d 5 -D bluetooth -f S16_LE | aplay -D bluetooth -f S16_LE
50_description:55_description:
51 Bluetooth audio procedure:56 PURPOSE:
52 1.- Enable the bluetooth headset57 This test will check that you can record and hear audio using a bluetooth audio device
53 2.- Click on the bluetooth icon in the menu bar58 STEPS:
54 3.- Select 'Setup new device'59 1. Enable the bluetooth headset
55 4.- Look for the device in the list and select it60 2. Click on the bluetooth icon in the menu bar
56 5.- In the device write the PIN code automatically chosen by the wizard61 3. Select 'Setup new device'
57 6.- The device should pair with the computer62 4. Look for the device in the list and select it
58 7.- Select Test to record for five seconds and reproduce in the bluetooth device63 5. In the device write the PIN code automatically chosen by the wizard
59 .64 6. The device should pair with the computer
60 Did all the steps work?65 7. Click "Test" to record for five seconds and reproduce in the bluetooth device
66 VERIFICATION:
67 Did you hear the sound you recorded in the bluetooth
6168
62plugin: manual69plugin: manual
63name: bluetooth/keyboard70name: bluetooth/keyboard
64command: keyboard_test71command: keyboard_test
65depends: bluetooth/detect72depends: bluetooth/detect
66_description:73_description:
67 Bluetooth keyboard procedure:74 PURPOSE:
68 1.- Enable the bluetooth keyboard75 This test will check that you can use a bluetooth keyboard
69 2.- Click on the bluetooth icon in the menu bar76 STEPS:
70 3.- Select 'Setup new device'77 1. Enable the bluetooth keyboard
71 4.- Look for the device in the list and select it78 2. Click on the bluetooth icon in the menu bar
72 5.- Select Test to enter text79 3. Select 'Setup new device'
73 .80 4. Look for the device in the list and select it
74 Did all the steps work?81 5. Click "Test"
82 6. Enter some text
83 VERIFICATION:
84 Were you able to enter some text with the bluetooth keyboard?
7585
76plugin: manual86plugin: manual
77name: bluetooth/mouse87name: bluetooth/mouse
78depends: bluetooth/detect88depends: bluetooth/detect
79_description:89_description:
80 Bluetooth mouse procedure:90 PURPOSE:
81 1.- Enable the bluetooth mouse91 This test will check that you can use a bluetooth mouse
82 2.- Click on the bluetooth icon in the menu bar92 STEPS:
83 3.- Select 'Setup new device'93 1. Enable the bluetooth mouse
84 4.- Look for the device in the list and select it94 2. Click on the bluetooth icon in the menu bar
85 5.- Move the mouse around the screen95 3. Select 'Setup new device'
86 6.- Perform some single/double/right click operations96 4. Look for the device in the list and select it
87 .97 5. Move the mouse around the screen
88 Did all the steps work?98 6. Perform some single/double/right click operations
99 VERIFICATION:
100 Did the mouse work as expected?
89101
=== modified file 'jobs/camera.txt.in'
--- jobs/camera.txt.in 2011-07-01 11:37:27 +0000
+++ jobs/camera.txt.in 2011-11-18 18:04:27 +0000
@@ -4,7 +4,7 @@
4 package.name == 'xawtv'4 package.name == 'xawtv'
5 device.category == 'CAPTURE'5 device.category == 'CAPTURE'
6command: camera_test -t detect6command: camera_test -t detect
7_description: Automated test case that attempts to detect a camera7_description: This Automated test attempts to detect a camera.
88
9plugin: manual9plugin: manual
10name: camera/display10name: camera/display
@@ -14,9 +14,12 @@
14 device.category == 'CAPTURE'14 device.category == 'CAPTURE'
15command: camera_test -t display15command: camera_test -t display
16_description:16_description:
17 Select Test to display a video capture from the camera17 PURPOSE:
18 .18 This test will check that the built-in camera works
19 Did you see the video capture?19 STEPS:
20 1. Click on Test to display a video capture from the camera
21 VERIFICATION:
22 Did you see the video capture?
2023
21plugin: manual24plugin: manual
22name: camera/still25name: camera/still
@@ -28,9 +31,12 @@
28 device.category == 'CAPTURE'31 device.category == 'CAPTURE'
29command: camera_test -t still32command: camera_test -t still
30_description:33_description:
31 Select Test to display a still image from the camera34 PURPOSE:
32 .35 This test will check that the built-in camera works
33 Did you see the image?36 STEPS:
37 1. Click on Test to display a still image from the camera
38 VERIFICATION:
39 Did you see the image?
3440
35plugin: manual41plugin: manual
36name: camera/video42name: camera/video
@@ -41,8 +47,9 @@
41 device.category == 'CAPTURE'47 device.category == 'CAPTURE'
42command: camera_test -t video48command: camera_test -t video
43_description:49_description:
44 Select Test to capture video to a file and open it in totem.50 PURPOSE:
45 Please make sure that both audio and video is captured.51 This test will check that you can capture video with the built-in camera
46 .52 STEPS:
47 Did you see/hear the capture?53 1. Click on Test to capture video to a file (it will automatically open in Totem)
4854 VERIFICATION:
55 Did you see and hear the capture?
4956
=== modified file 'jobs/codecs.txt.in'
--- jobs/codecs.txt.in 2011-07-01 11:37:27 +0000
+++ jobs/codecs.txt.in 2011-11-18 18:04:27 +0000
@@ -1,51 +1,29 @@
1plugin: manual1plugin: manual
2name: codecs-ogg-vorbis2name: codecs/ogg-vorbis
3requires:3requires:
4 package.name == 'gstreamer0.10-plugins-base'4 package.name == 'gstreamer0.10-plugins-base'
5 package.name == 'totem' and package.name == 'ubuntu-sounds'5 package.name == 'totem' and package.name == 'ubuntu-sounds'
6command: totem /usr/share/sounds/ubuntu/stereo/system-ready.ogg6command: totem /usr/share/sounds/ubuntu/stereo/system-ready.ogg
7_description:7_description:
8 Select Test to play an Ogg Vorbis file (.ogg)8 PURPOSE:
9 .9 This test will verify your system's ability to play Ogg Vorbis audio files.
10 (Please close Movie Player to proceed.)10 STEPS:
11 .11 1. Click Test to play an Ogg Vorbis file (.ogg)
12 Did the sample play correctly?12 2. Please close the player to proceed.
13 VERIFICATION:
14 Did the sample play correctly?
1315
14plugin: manual16plugin: manual
15name: codecs-wav17name: codecs/wav
16requires:18requires:
17 package.name == 'gstreamer0.10-plugins-good'19 package.name == 'gstreamer0.10-plugins-good'
18 package.name == 'totem' and package.name == 'alsa-utils'20 package.name == 'totem' and package.name == 'alsa-utils'
19command: totem /usr/share/sounds/alsa/Noise.wav21command: totem /usr/share/sounds/alsa/Noise.wav
20_description:22_description:
21 Select Test to play a Wave Audio format file (.wav)23 PURPOSE:
22 .24 This test will verify your system's ability to play Wave Audio files.
23 (Please close Movie Player to proceed.)25 STEPS:
24 .26 1. Select Test to play a Wave Audio format file (.wav)
25 Did the sample play correctly?27 2. Please close the player to proceed.
2628 VERIFICATION:
27plugin: manual29 Did the sample play correctly?
28name: media-pause-audio
29requires:
30 package.name == 'totem'
31 package.name == 'gstreamer0.10-plugins-base'
32command: totem $CHECKBOX_SHARE/data/FrustrationBlues-ColinRoss.oga
33_description:
34 Select 'Test' to play some audio, and try pausing and resuming playback while the it is playing.
35 .
36 (Please close Movie Player to proceed.)
37 .
38 Did the audio play and pause as expected?
39
40plugin: manual
41name: media-pause-video
42requires:
43 package.name == 'totem'
44 package.name == 'gstreamer0.10-plugins-base'
45command: totem $CHECKBOX_SHARE/data/UbuntuIsHumanity.ogv
46_description:
47 Select 'Test' to play a video, and try pausing and resuming playback while the video is playing.
48 .
49 (Please close Movie Player to proceed.)
50 .
51 Did the video play and pause as expected?
5230
=== modified file 'jobs/cpu.txt.in'
--- jobs/cpu.txt.in 2011-08-10 21:09:56 +0000
+++ jobs/cpu.txt.in 2011-11-18 18:04:27 +0000
@@ -6,7 +6,7 @@
6user: root6user: root
7command: fwts_test -c -l $CHECKBOX_DATA/cpu_scaling_test.log7command: fwts_test -c -l $CHECKBOX_DATA/cpu_scaling_test.log
8_description:8_description:
9 Test the CPU scaling capabilities using Colin King's Firmware Test Suite tool.9 Test the CPU scaling capabilities using Firmware Test Suite (fwts cpufreq).
1010
11plugin: shell11plugin: shell
12name: cpu/clocktest12name: cpu/clocktest
@@ -28,7 +28,7 @@
28requires: int(cpuinfo.count) > 1 and (cpuinfo.platform == 'i386' or cpuinfo.platform == 'x86_64')28requires: int(cpuinfo.count) > 1 and (cpuinfo.platform == 'i386' or cpuinfo.platform == 'x86_64')
29command: cpu_topology29command: cpu_topology
30_description:30_description:
31 Checks cpu topology for accuracy31 This test checks cpu topology for accuracy
3232
33plugin: shell33plugin: shell
34name: cpu/frequency_governors34name: cpu/frequency_governors
@@ -36,4 +36,4 @@
36user: root36user: root
37command: nice -n -20 cpu_scaling_test 37command: nice -n -20 cpu_scaling_test
38_description:38_description:
39 Checks that CPU frequency governors are obeyed when set.39 This test checks that CPU frequency governors are obeyed when set.
4040
=== modified file 'jobs/daemons.txt.in'
--- jobs/daemons.txt.in 2011-07-01 11:37:27 +0000
+++ jobs/daemons.txt.in 2011-11-18 18:04:27 +0000
@@ -1,59 +1,59 @@
1plugin: shell1plugin: shell
2name: atd2name: daemons/atd
3requires: package.name == 'at'3requires: package.name == 'at'
4command: pgrep -f '/usr/sbin/atd' >/dev/null4command: pgrep -f '/usr/sbin/atd' >/dev/null
5_description: Test if the atd daemon is running when the package is installed.5_description: Test if the atd daemon is running when the package is installed.
66
7plugin: shell7plugin: shell
8name: cron8name: daemons/cron
9requires: package.name == 'cron'9requires: package.name == 'cron'
10command: pgrep -f '/usr/sbin/cron' >/dev/null10command: pgrep -f '/usr/sbin/cron' >/dev/null
11_description: Test if the cron daemon is running when the package is installed.11_description: Test if the cron daemon is running when the package is installed.
1212
13plugin: shell13plugin: shell
14name: cupsd14name: daemons/cupsd
15requires: package.name == 'cupsys'15requires: package.name == 'cupsys'
16command: pgrep -f '/usr/sbin/cupsd' >/dev/null16command: pgrep -f '/usr/sbin/cupsd' >/dev/null
17_description: Test if the cupsd daemon is running when the package is installed.17_description: Test if the cupsd daemon is running when the package is installed.
1818
19plugin: shell19plugin: shell
20name: getty20name: daemons/getty
21requires: package.name == 'util-linux'21requires: package.name == 'util-linux'
22command: pgrep -f '/sbin/getty' >/dev/null22command: pgrep -f '/sbin/getty' >/dev/null
23_description: Test if the getty daemon is running when the package is installed.23_description: Test if the getty daemon is running when the package is installed.
2424
25plugin: shell25plugin: shell
26name: init26name: daemons/init
27requires: package.name == 'upstart'27requires: package.name == 'upstart'
28command: pgrep -f '/sbin/init' >/dev/null28command: pgrep -f '/sbin/init' >/dev/null
29_description: Test if the init daemon is running when the package is installed.29_description: Test if the init daemon is running when the package is installed.
3030
31plugin: shell31plugin: shell
32name: klogd32name: daemons/klogd
33requires: package.name == 'klogd'33requires: package.name == 'klogd'
34command: pgrep -f '/sbin/klogd' >/dev/null34command: pgrep -f '/sbin/klogd' >/dev/null
35_description: Test if the klogd daemon is running when the package is installed.35_description: Test if the klogd daemon is running when the package is installed.
3636
37plugin: shell37plugin: shell
38name: nmbd38name: daemons/nmbd
39requires: package.name == 'samba'39requires: package.name == 'samba'
40command: pgrep -f '/usr/sbin/nmbd' >/dev/null40command: pgrep -f '/usr/sbin/nmbd' >/dev/null
41_description: Test if the nmbd daemon is running when the package is installed.41_description: Test if the nmbd daemon is running when the package is installed.
4242
43plugin: shell43plugin: shell
44name: smbd44name: daemons/smbd
45requires: package.name == 'samba'45requires: package.name == 'samba'
46command: pgrep -f '/usr/sbin/smbd' >/dev/null46command: pgrep -f '/usr/sbin/smbd' >/dev/null
47_description: Test if the smbd daemon is running when the package is installed.47_description: Test if the smbd daemon is running when the package is installed.
4848
49plugin: shell49plugin: shell
50name: syslogd50name: daemons/syslogd
51requires: package.name == 'syslogd'51requires: package.name == 'syslogd'
52command: pgrep -f '/sbin/syslogd' >/dev/null52command: pgrep -f '/sbin/syslogd' >/dev/null
53_description: Test if the syslogd daemon is running when the package is installed.53_description: Test if the syslogd daemon is running when the package is installed.
5454
55plugin: shell55plugin: shell
56name: udevd56name: daemons/udevd
57requires:57requires:
58 package.name == 'udevd'58 package.name == 'udevd'
59 package.name == 'linux'59 package.name == 'linux'
@@ -61,7 +61,7 @@
61_description: Test if the udevd daemon is running when the package is installed.61_description: Test if the udevd daemon is running when the package is installed.
6262
63plugin: shell63plugin: shell
64name: winbindd64name: daemons/winbindd
65requires: package.name == 'winbind'65requires: package.name == 'winbind'
66command: pgrep -f '/usr/sbin/winbindd' >/dev/null66command: pgrep -f '/usr/sbin/winbindd' >/dev/null
67_description: Test if the winbindd daemon is running when the package is installed.67_description: Test if the winbindd daemon is running when the package is installed.
6868
=== modified file 'jobs/disk.txt.in'
--- jobs/disk.txt.in 2011-09-14 21:16:02 +0000
+++ jobs/disk.txt.in 2011-11-18 18:04:27 +0000
@@ -14,7 +14,7 @@
14 requires: device.path == "$path" and package.name == 'linux'14 requires: device.path == "$path" and package.name == 'linux'
15 user: root15 user: root
16 command: hdparm -tT /dev/`ls /sys$path/block` | sed 's/:.*= */ = /' | grep -v "^$"16 command: hdparm -tT /dev/`ls /sys$path/block` | sed 's/:.*= */ = /' | grep -v "^$"
17 description: Benchmark for $path 17 description: This test runs hdparm timing tests as a benchmark for $path
18 EOF18 EOF
1919
20plugin: local20plugin: local
@@ -29,7 +29,8 @@
29 plugin: shell29 plugin: shell
30 name: disk/smart_`ls /sys$path/block`30 name: disk/smart_`ls /sys$path/block`
31 requires: device.path == "$path"31 requires: device.path == "$path"
32 description: SMART test for $product32 description:
33 This tests the SMART capabilities for $product (Note that this test will not work against removable media (USB, Firewire) and hardware RAID)
33 user: root34 user: root
34 command: disk_smart -b /dev/`ls /sys$path/block` -s 13035 command: disk_smart -b /dev/`ls /sys$path/block` -s 130
35 EOF36 EOF
@@ -44,7 +45,7 @@
44 plugin: shell45 plugin: shell
45 name: disk/max_diskspace_used_`ls /sys$path/block`46 name: disk/max_diskspace_used_`ls /sys$path/block`
46 requires: device.path == "$path"47 requires: device.path == "$path"
47 description: Max disk space test for $product48 description: Maximum disk space test for $product
48 user: root49 user: root
49 command: max_diskspace_used `ls /sys$path/block`50 command: max_diskspace_used `ls /sys$path/block`
50 EOF51 EOF
@@ -61,7 +62,7 @@
61 requires:62 requires:
62 device.path == "$path"63 device.path == "$path"
63 package.name == 'linux'64 package.name == 'linux'
64 description: Disk performance for $product65 description: Disk performance test for $product
65 user: root66 user: root
66 command: disk_read_performance_test `ls /sys$path/block`67 command: disk_read_performance_test `ls /sys$path/block`
67 EOF68 EOF
@@ -79,6 +80,6 @@
79 requires:80 requires:
80 device.path == "$path"81 device.path == "$path"
81 package.name == 'linux'82 package.name == 'linux'
82 description: I/O stress test for $product83 description: Disk I/O stress test for $product
83 command: storage_test `ls /sys$path/block`84 command: storage_test `ls /sys$path/block`
84 EOF85 EOF
8586
=== removed file 'jobs/evolution.txt.in'
--- jobs/evolution.txt.in 2011-07-01 11:37:27 +0000
+++ jobs/evolution.txt.in 1970-01-01 00:00:00 +0000
@@ -1,26 +0,0 @@
1plugin: manual
2name: applications-evolution-pop3
3requires: package.name == "evolution"
4command: evolution
5_description:
6 Click the "Test" button to launch Evolution, then configure it to connect to a POP3 account.
7 .
8 Were you able to receive and read e-mail correctly?
9
10plugin: manual
11name: applications-evolution-imap
12requires: package.name == "evolution"
13command: evolution
14_description:
15 Click the "Test" button to launch Evolution, then configure it to connect to a IMAP account.
16 .
17 Were you able to receive and read e-mail correctly?
18
19plugin: manual
20name: applications-evolution-smtp
21requires: package.name == "evolution"
22command: evolution
23_description:
24 Click the "Test" button to launch Evolution, then configure it to connect to a SMTP account.
25 .
26 Were you able to send e-mail without errors?
270
=== modified file 'jobs/fingerprint.txt.in'
--- jobs/fingerprint.txt.in 2011-08-10 21:09:56 +0000
+++ jobs/fingerprint.txt.in 2011-11-18 18:04:27 +0000
@@ -1,27 +1,31 @@
1plugin: manual1plugin: manual
2name: fingerprint/login2name: fingerprint/login
3_description:3_description:
4 Prerequisites: This test case assumes that there's a testing account from which test cases are run and a personal account that the tester uses to verify the fingerprint reader4 PURPOSE:
5 .5 This test will verify that a fingerprint reader will work properly for logging into your system.
6 Fingerprint login verification procedure:6 PREREQUISITES:
7 1.- Click on the user switcher applet.7 This test case assumes that there's a testing account from which test cases are run and a personal account that the tester uses to verify the fingerprint reader
8 2.- Select your user name.8 STEPS:
9 3.- A window should appear that provides the ability to login either typing your password or using fingerprint authentication.9 1. Click on the user switcher applet.
10 4.- Use the fingerprint reader to login.10 2. Select your user name.
11 5.- Click on the user switcher applet.11 3. A window should appear that provides the ability to login either typing your password or using fingerprint authentication.
12 6.- Select the testing account to continue running tests.12 4. Use the fingerprint reader to login.
13 .13 5. Click on the user switcher applet.
14 Did the authentication procedure work correctly?14 6. Select the testing account to continue running tests.
15 VERIFICATION:
16 Did the authentication procedure work correctly?
1517
16plugin: manual18plugin: manual
17name: fingerprint/unlock19name: fingerprint/unlock
18_description:20_description:
19 Fingerprint unlock verification procedure:21 PURPOSE:
20 1.- Click on the user switcher applet.22 This test will verify that a fingerprint reader can be used to unlock a locked system.
21 2.- Select 'Lock screen'.23 STEPS:
22 3.- Press any key or move the mouse.24 1. Click on the user switcher applet.
23 4.- A window should appear that provides the ability to unlock either typing your password or using fingerprint authentication.25 2. Select 'Lock screen'.
24 5.- Use the fingerprint reader to unlock.26 3. Press any key or move the mouse.
25 6.- Your screen should be unlocked.27 4. A window should appear that provides the ability to unlock either typing your password or using fingerprint authentication.
26 .28 5. Use the fingerprint reader to unlock.
27 Did the authentication procedure work correctly?29 6. Your screen should be unlocked.
30 VERIFICATION:
31 Did the authentication procedure work correctly?
2832
=== modified file 'jobs/firewire.txt.in'
--- jobs/firewire.txt.in 2011-08-10 21:09:56 +0000
+++ jobs/firewire.txt.in 2011-11-18 18:04:27 +0000
@@ -1,11 +1,12 @@
1plugin: manual1plugin: manual
2name: firewire/hdd2name: firewire/hdd
3_description:3_description:
4 Firewire HDD verification procedure:4 PURPOSE:
5 1.- Plug a Firewire HDD into the computer.5 This test will check that the firewire port works
6 2.- A window should be opened asking which action should be performed (open folder, photo manager, etc).6 STEPS:
7 3.- Copy some files from your internal HDD to the firewire HDD.7 1. Plug a Firewire HDD into the computer
8 4.- Copy some files from the firewire HDD to your internal HDD.8 2. Either a window asking which action should be performed (open folder, photo manager, etc) or a file browser will open.
9 .9 3. Copy some files from your internal HDD to the firewire HDD
10 Do the copy operations work as expected?10 4. Copy some files from the firewire HDD to your internal HDD
1111 VERIFICATION:
12 Do the copy operations work as expected?
1213
=== removed file 'jobs/gcalctool.txt.in'
--- jobs/gcalctool.txt.in 2011-07-01 11:37:27 +0000
+++ jobs/gcalctool.txt.in 1970-01-01 00:00:00 +0000
@@ -1,52 +0,0 @@
1plugin: manual
2name: applications-gcalctool
3requires: package.name == "gcalctool"
4command: gcalctool
5_description:
6 Click the "Test" button to open the calculator.
7 .
8 Did it launch correctly?
9
10plugin: manual
11name: applications-gcalctool-functions
12depends: applications-gcalctool
13requires: package.name == "gcalctool"
14command: gcalctool
15_description:
16 Click the "Test" button to open the calculator and perform:
17 .
18 1. Simple math functions (+,-,/,*)
19 2. Nested math functions ((,))
20 3. Fractional math
21 4. Decimal math
22 .
23 Did the functions perform as expected?
24
25plugin: manual
26name: applications-gcalctool-memory
27depends: applications-gcalctool
28requires: package.name == "gcalctool"
29command: gcalctool
30_description:
31 Click the "Test" button to open the calculator and perform:
32 .
33 1. Memory set
34 2. Memory reset
35 3. Memory last clear
36 4. Memory clear
37 .
38 Did the functions perform as expected?
39
40plugin: manual
41name: applications-gcalctool-clipboard
42depends: applications-gcalctool
43requires: package.name == "gcalctool"
44command: gcalctool
45_description:
46 Click the "Test" button to open the calculator and perform:
47 .
48 1. Cut
49 2. Copy
50 3. Paste
51 .
52 Did the functions perform as expected?
530
=== removed file 'jobs/gedit.txt.in'
--- jobs/gedit.txt.in 2011-07-01 11:37:27 +0000
+++ jobs/gedit.txt.in 1970-01-01 00:00:00 +0000
@@ -1,22 +0,0 @@
1plugin: manual
2name: applications-gedit
3requires: package.name == "gedit"
4command: gedit
5_description:
6 Click the "Test" button to open gedit.
7 .
8 Enter some text and save the file (make a note of the file name you use), then close gedit.
9 .
10 Did this perform as expected?
11
12plugin: manual
13name: applications-gedit-read
14depends: applications-gedit
15requires: package.name == "gedit"
16command: gedit
17_description:
18 Click the "Test" button to open gedit, and re-open the file you created previously.
19 .
20 Edit then save the file, then close gedit.
21 .
22 Did this perform as expected?
230
=== removed file 'jobs/gnome-terminal.txt.in'
--- jobs/gnome-terminal.txt.in 2011-07-01 11:37:27 +0000
+++ jobs/gnome-terminal.txt.in 1970-01-01 00:00:00 +0000
@@ -1,12 +0,0 @@
1plugin: manual
2name: applications-gnome-terminal
3requires: package.name == "gnome-terminal"
4command: gnome-terminal
5_description:
6 Click the "Test" button to open Terminal.
7 .
8 Type 'ls' and press enter. You should see a list of files and folder in your home directory.
9 .
10 Close the terminal window.
11 .
12 Did this perform as expected?
130
=== modified file 'jobs/graphics.txt.in'
--- jobs/graphics.txt.in 2011-08-10 21:09:56 +0000
+++ jobs/graphics.txt.in 2011-11-18 18:04:27 +0000
@@ -1,12 +1,8 @@
1plugin: manual1plugin: shell
2name: graphics/xorg-version2name: graphics/xorg-version
3requires: package.name == "x11-utils"3requires: package.name == "x11-utils"
4command: xdpyinfo | grep "^X.Org version" | cut -d ':' -f 2 | tr -d ' '4command: xdpyinfo | grep "^X.Org version" | cut -d ':' -f 2 | tr -d ' '
5_description:5_description: Test to output the Xorg version
6 2d graphics appears to be working, your running X.Org version is:
7 $output
8 .
9 Is this correct?
106
11plugin: shell7plugin: shell
12name: graphics/xorg-version-output8name: graphics/xorg-version-output
@@ -19,41 +15,40 @@
19name: graphics/gtkperf15name: graphics/gtkperf
20depends: graphics/xorg-version-output16depends: graphics/xorg-version-output
21requires: package.name == 'gtkperf'17requires: package.name == 'gtkperf'
22command: gtkperf -a18command: gtkperf -a | grep "Total time:"
23_description:19_description:
24 Run gtkperf to make sure that GTK based test cases work20 Run gtkperf to make sure that GTK based test cases work
25 .
26 In the future add the returned time as a benchmark result to the checkbox report
2721
28plugin: manual22plugin: manual
29name: graphics/resolution-change23name: graphics/resolution-change
30depends: graphics/xorg-version-output24depends: graphics/xorg-version-output
31_description:25_description:
32 Display resolution change procedure:26 PURPOSE:
33 1.- Open System->Preferences->Monitors27 This test will verify that the GUI is usable after manually changing resolution
34 2.- Select a new resolution from the dropdown list28 STEPS:
35 3.- Click on Apply29 1. Open the Displays application
36 4.- The resolution should change30 2. Select a new resolution from the dropdown list
37 5.- Select the original resolution from the dropdown list31 3. Click on Apply
38 6.- Click on Apply32 4. Select the original resolution from the dropdown list
39 7.- The resolution should change again33 5. Click on Apply
40 .34 VERIFICATION:
41 Did the resolution change as expected?35 Did the resolution change as expected?
4236
43plugin: manual37plugin: manual
44name: graphics/rotation38name: graphics/rotation
45depends: graphics/xorg-version-output39depends: graphics/xorg-version-output
46_description:40_description:
47 Display rotation verification procedure:41 PURPOSE:
48 1.- Open System->Preferences->Monitors42 This test will test display rotation
49 2.- Select a new rotation value from the dropdown list43 STEPS:
50 3.- Click on Apply44 1. Open the Displays application
51 4.- The display should be rotated according to the new configuration value45 2. Select a new rotation value from the dropdown list
52 5.- Click on Restore Previous Configuration46 3. Click on Apply
53 6.- The display configuration change should be reverted47 4. Click on Restore Previous Configuration
54 7.- Repeat 2-6 for different rotation values48 5. Click on Apply
55 .49 6. Repeat 2-5 for different rotation values
56 Did the display rotation change as expected?50 VERIFICATION:
51 Did the display rotation change as expected?
5752
58plugin: shell53plugin: shell
59name: graphics/xorg-process54name: graphics/xorg-process
@@ -72,7 +67,7 @@
72requires: package.name == 'xorg' and device.driver == 'i915'67requires: package.name == 'xorg' and device.driver == 'i915'
73user: root68user: root
74command: xorg_memory_test xeyes69command: xorg_memory_test xeyes
75_description: Test that X does not leak memory when running programs.70_description: Test that X does not leak memory when running programs on systems with intel based graphics.
7671
77plugin: manual72plugin: manual
78name: graphics/resolution73name: graphics/resolution
@@ -80,11 +75,14 @@
80 device.category == 'VIDEO'75 device.category == 'VIDEO'
81command: resolution_test76command: resolution_test
82_description:77_description:
83 This display is using the following resolution:78 PURPOSE:
84 .79 This test will verify the default display resolution
85 $output80 STEPS:
86 .81 1. This display is using the following resolution:
87 Is this acceptable for your display?82 INFO:
83 $output
84 VERIFICATION:
85 Is this acceptable for your display?
8886
89plugin: shell87plugin: shell
90name: graphics/minimum_resolution88name: graphics/minimum_resolution
@@ -102,30 +100,39 @@
102requires: package.name == 'xorg' and package.name == 'python-gst0.10'100requires: package.name == 'xorg' and package.name == 'python-gst0.10'
103command: gst_pipeline_test -t 2 'videotestsrc ! ffmpegcolorspace ! gconfvideosink'101command: gst_pipeline_test -t 2 'videotestsrc ! ffmpegcolorspace ! gconfvideosink'
104_description:102_description:
105 Select Test to display a video test.103 PURPOSE:
106 .104 This test will test the default display
107 Do you see color bars and static?105 STEPS:
106 1. Click "Test" to display a video test.
107 VERIFICATION:
108 Do you see color bars and static?
108109
109plugin: manual110plugin: manual
110name: graphics/xrandr_detect_modes111name: graphics/xrandr_detect_modes
111requires: package.name == 'xorg'112requires: package.name == 'xorg'
112command: xrandr113command: xrandr
113_description:114_description:
114 The following screens and video modes have been detected on your system:115 PURPOSE:
115 .116 This test checks the detected video modes
116 $output117 STEPS:
117 .118 1. The following screens and video modes have been detected on your system
118 Is this correct?119 INFO:
120 $output
121 VERIFICATION:
122 Are those correct?
119123
120plugin: manual124plugin: manual
121name: graphics/cycle_resolution125name: graphics/cycle_resolution
122requires: package.name == 'xorg'126requires: package.name == 'xorg'
123depends: xrandr_detect_modes127depends: graphics/xrandr_detect_modes
124command: xrandr_cycle128command: xrandr_cycle
125_description:129_description:
126 Select Test to cycle through the detected video modes for your system.130 PURPOSE:
127 .131 This test cycles through the detected video modes
128 Did the screen appear to be working for each mode?132 STEPS:
133 1. Click "Test" to start cycling through the video modes
134 VERIFICATION:
135 Did the screen appear to be working for each mode?
129136
130plugin: shell137plugin: shell
131name: graphics/compiz_check138name: graphics/compiz_check
@@ -136,8 +143,13 @@
136plugin: manual143plugin: manual
137name: graphics/glxgears144name: graphics/glxgears
138requires: package.name == 'mesa-utils'145requires: package.name == 'mesa-utils'
139command: glxgears146command: glxgears; true
140_description:147_description:
141 Select Test to execute glxgears to ensure that minimal 3d graphics support is in place.148 PURPOSE:
142 .149 This test tests the basic 3D capabilities of your video card
143 Did the 3d animation appear?150 STEPS:
151 1. Click "Test" to execute an OpenGL demo. Press ESC at any time to close.
152 2. Verify that the animation is not jerky or slow.
153 VERIFICATION:
154 1. Did the 3d animation appear?
155 2. Was the animation free from slowness/jerkiness?
144156
=== modified file 'jobs/hibernate.txt.in'
--- jobs/hibernate.txt.in 2011-09-01 12:23:07 +0000
+++ jobs/hibernate.txt.in 2011-11-18 18:04:27 +0000
@@ -5,10 +5,12 @@
5user: root5user: root
6command: sleep_test -s disk -w 120 --debug6command: sleep_test -s disk -w 120 --debug
7_description:7_description:
8 This will check to make sure your system can successfully hibernate (if supported).8 PURPOSE:
9 .9 This test will check to make sure your system can successfully hibernate (if supported)
10 Select Test to begin. The system will hibernate and should wake itself within 5 minutes. If your system does not wake itself after 5 minutes, please press the power button to wake the system manually. If the system fails to resume from hibernate, please restart System Testing and mark this test as Failed.10 STEPS:
11 .11 1. Click on Test
12 Did the system successfully hibernate and did it work properly after waking up?12 2. The system will hibernate and should wake itself within 5 minutes
1313 3. If your system does not wake itself after 5 minutes, please press the power button to wake the system manually
1414 4. If the system fails to resume from hibernate, please restart System Testing and mark this test as Failed
15 VERIFICATION:
16 Did the system successfully hibernate and did it work properly after waking up?
1517
=== modified file 'jobs/info.txt.in'
--- jobs/info.txt.in 2011-09-14 21:16:02 +0000
+++ jobs/info.txt.in 2011-11-18 18:04:27 +0000
@@ -1,44 +1,57 @@
11name: codecs_attachment
2name: info/codecs_attachment
3plugin: attachment2plugin: attachment
4requires: device.driver == 'HDA Intel'3requires: device.driver == 'HDA Intel'
5command: cat /proc/asound/card*/codec#*4command: cat /proc/asound/card*/codec#*
5_description: Attaches a report of installed codecs for Intel HDA
66
7name: info/cpuinfo_attachment7name: cpuinfo_attachment
8plugin: attachment8plugin: attachment
9command: cat /proc/cpuinfo9command: cat /proc/cpuinfo
10_description: Attaches a report of CPU information
1011
11name: info/dmesg_attachment12name: dmesg_attachment
12plugin: attachment13plugin: attachment
13command: cat /var/log/dmesg | ansi_parser14command: cat /var/log/dmesg | ansi_parser
15_description: Attaches a copy of /var/log/dmesg to the test results
1416
15name: info/dmi_attachment17name: dmi_attachment
16plugin: attachment18plugin: attachment
17command: grep -r . /sys/class/dmi/id/ 2>/dev/null19command: grep -r . /sys/class/dmi/id/ 2>/dev/null
20_description: Attaches info on DMI
1821
19name: info/dmidecode_attachment22name: dmidecode_attachment
20plugin: attachment23plugin: attachment
21user: root24user: root
22command: dmidecode25command: dmidecode
26_description: Attaches dmidecode output
2327
24name: info/lspci_attachment28name: lspci_attachment
25plugin: attachment29plugin: attachment
26command: lspci -vvnn30command: lspci -vvnn
2731_description: Attaches very verbose lspci output.
28name: info/modprobe_attachment32
33name: meminfo_attachment
34plugin: attachment
35command: cat /proc/meminfo
36
37name: modprobe_attachment
29plugin: attachment38plugin: attachment
30command: find /etc/modprobe.* -name \*.conf | xargs cat39command: find /etc/modprobe.* -name \*.conf | xargs cat
40_description: Attaches the contents of the various modprobe conf files.
3141
32name: info/modules_attachment42name: modules_attachment
33plugin: attachment43plugin: attachment
34command: cat /etc/modules44command: cat /etc/modules
45_description: Attaches the contents of the /etc/modules file.
3546
36name: info/sysctl_attachment47name: sysctl_attachment
37plugin: attachment48plugin: attachment
38command: find /etc/sysctl.* -name \*.conf | xargs cat49command: find /etc/sysctl.* -name \*.conf | xargs cat
50_description: attaches the contents of various sysctl config files.
3951
40name: info/sysfs_attachment52name: sysfs_attachment
41plugin: attachment53plugin: attachment
54_description: Attaches a report of sysfs attributes.
42command:55command:
43 for i in `udevadm info --export-db | sed -n 's/^P: //p'`; do56 for i in `udevadm info --export-db | sed -n 's/^P: //p'`; do
44 echo "P: $i"57 echo "P: $i"
@@ -46,19 +59,22 @@
46 echo59 echo
47 done60 done
4861
49name: info/udev_attachment62name: udev_attachment
50plugin: attachment63plugin: attachment
51command: udevadm info --export-db64command: udevadm info --export-db
65_description: Attaches a dump of the udev database showing system hardware information.
5266
53name: info/gcov_attachment67name: gcov_attachment
54plugin: attachment68plugin: attachment
55requires: package.name == 'lcov'69requires: package.name == 'lcov'
56user: root70user: root
57command: gcov_tarball71command: gcov_tarball
72_description: Attaches a tarball of gcov data if present.
5873
59name: info/lsmod_attachment74name: lsmod_attachment
60plugin: attachment75plugin: attachment
61command: lsmod76command: lsmod
77_description: Attaches a list of the currently running kernel modules.
6278
63plugin: shell79plugin: shell
64name: info/screenshot80name: info/screenshot
@@ -66,25 +82,25 @@
66 package.name == 'xorg'82 package.name == 'xorg'
67 package.name == 'imagemagick'83 package.name == 'imagemagick'
68command: import -window root ${CHECKBOX_DATA}/screenshot.png84command: import -window root ${CHECKBOX_DATA}/screenshot.png
69_description:85_description: Captures a screenshot.
70 Captures a screenshot.
7186
72plugin: attachment87plugin: attachment
73name: info/screenshot.png88name: screenshot.png
74depends: screenshot89depends: screenshot
75command: cat ${CHECKBOX_DATA}/screenshot.png90command: cat ${CHECKBOX_DATA}/screenshot.png
91_description: Attaches the screenshot captured in info/screenshot.
7692
77plugin: attachment93plugin: attachment
78name: info/fwts_log94name: fwts_log
79depends: fwts_test95depends: fwts_test
80_description:96_description: Gather log from the Firmware Test Suite run.
81 Gather log from the firmware test suite run
82command:97command:
83 cat $CHECKBOX_DATA/fwts_results.log98 cat $CHECKBOX_DATA/fwts_results.log
8499
85plugin: attachment100plugin: attachment
86name: info/acpi_sleep_attachment101name: acpi_sleep_attachment
87command: cat /proc/acpi/sleep102command: [ -e /proc/acpi/sleep ] && cat /proc/acpi/sleep
103_description: Attaches the contents of /proc/acpi/sleep if it exists.
88104
89plugin: local105plugin: local
90name: info/bootchart106name: info/bootchart
@@ -111,25 +127,29 @@
111 EOF127 EOF
112128
113plugin: attachment129plugin: attachment
114name: info/bootchart.png130name: bootchart.png
115depends: info/bootchart131depends: info/bootchart
116requires: (package.name == 'bootchart' and float(lsb.release) < 9.04) or package.name == 'pybootchartgui'132requires: (package.name == 'bootchart' and float(lsb.release) < 9.04) or package.name == 'pybootchartgui'
133_description: Attaches the bootchart png file for bootchart runs
117command:134command:
118 file=`ls /var/log/bootchart/*.png 2>/dev/null | tail -1`; \135 file=`ls /var/log/bootchart/*.png 2>/dev/null | tail -1`; \
119 [ -e "$file" ] && cat "$file"136 [ -e "$file" ] && cat "$file"
120137
121plugin: attachment138plugin: attachment
122name: info/bootchart.tgz139name: bootchart.tgz
123depends: info/bootchart140depends: info/bootchart
124requires: package.name == 'bootchart' and float(lsb.release) >= 9.04141requires: package.name == 'bootchart' and float(lsb.release) >= 9.04
142_description: Attaches the bootchart log for bootchart test runs.
125command:143command:
126 file=`ls /var/log/bootchart/*.tgz 2>/dev/null | tail -1`; \144 file=`ls /var/log/bootchart/*.tgz 2>/dev/null | tail -1`; \
127 [ -e "$file" ] && cat "$file"145 [ -e "$file" ] && cat "$file"
128146
129plugin: attachment147plugin: attachment
130name: info/installer_bootchart.tgz148name: installer_bootchart.tgz
131command: [ -e /var/log/installer/bootchart.tgz ] && cat /var/log/installer/bootchart.tgz149command: [ -e /var/log/installer/bootchart.tgz ] && cat /var/log/installer/bootchart.tgz
150_description: installs the installer bootchart tarball if it exists.
132151
133plugin: attachment152plugin: attachment
134name: info/installer_debug.gz153name: installer_debug.gz
135command: [ -e /var/log/installer/debug ] && gzip -9 -c /var/log/installer/debug154command: [ -e /var/log/installer/debug ] && gzip -9 -c /var/log/installer/debug
155_description: Attaches the installer debug log if it exists.
136156
=== modified file 'jobs/input.txt.in'
--- jobs/input.txt.in 2011-08-10 21:09:56 +0000
+++ jobs/input.txt.in 2011-11-18 18:04:27 +0000
@@ -1,16 +1,24 @@
1plugin: manual1plugin: manual
2name: input/mouse2name: input/mouse
3requires: device.category == 'MOUSE'3requires: device.category == 'MOUSE' or device.category == 'TOUCH'
4_description:4_description:
5 Moving the mouse should move the cursor on the screen.5 PURPOSE:
6 .6 This test will test your pointing device
7 Is your mouse working properly?7 STEPS:
8 1. Move the cursor using the pointing device or touch the screen.
9 2. Perform some single/double/right click operations.
10 VERIFICATION:
11 Did the pointing device work as expected?
812
9plugin: manual13plugin: manual
10name: input/keyboard14name: input/keyboard
11command: keyboard_test15command: keyboard_test
12requires: device.category == 'KEYBOARD'16requires: device.category == 'KEYBOARD'
13_description:17_description:
14 Select Test to open a text area where to type keys on your keyboard.18 PURPOSE:
15 .19 This test will test your keyboard
16 Is your keyboard working properly?20 STEPS:
21 1. Click on Test
22 2. On the open text area, use your keyboard to type something
23 VERIFICATION:
24 Is your keyboard working properly?
1725
=== modified file 'jobs/install.txt.in'
--- jobs/install.txt.in 2011-09-01 12:23:07 +0000
+++ jobs/install.txt.in 2011-11-18 18:04:27 +0000
@@ -4,4 +4,4 @@
4user: root4user: root
5command: apt-get -d -y --force-yes dist-upgrade && true || false5command: apt-get -d -y --force-yes dist-upgrade && true || false
6_description: 6_description:
7 Tests to see that apt can access repositories and get updates (does not install updates)7 Tests to see that apt can access repositories and get updates (does not install updates). This is done to confirm that you could recover from an incomplete or broken update.
88
=== modified file 'jobs/keys.txt.in'
--- jobs/keys.txt.in 2011-09-01 12:23:07 +0000
+++ jobs/keys.txt.in 2011-11-18 18:04:27 +0000
@@ -1,73 +1,86 @@
1plugin: manual1plugin: manual
2name: keys/brightness2name: keys/brightness
3requires: device.product in ['Notebook','Laptop','Portable']3requires: dmi.product in ['Notebook','Laptop','Portable']
4_description:4_description:
5 Press the brightness buttons on the keyboard. A status window should \5 PURPOSE:
6 appear and the brightness should change.6 This test will test the brightness key
7 .7 STEPS:
8 Do the buttons work?8 1. Press the brightness buttons on the keyboard
9 VERIFICATION:
10 Did the brightness change following to your key presses?
911
10plugin: manual12plugin: manual
11name: keys/volume13name: keys/volume
12_description:14_description:
13 Press the volume buttons on the keyboard. A status window should \15 PURPOSE:
14 appear and the volume should change.16 This test will test the volume keys
15 .17 STEPS:
16 Do the buttons work?18 1. Press the volume buttons on the keyboard
19 VERIFICATION:
20 Did the volume change following to your key presses?
1721
18plugin: manual22plugin: manual
19name: keys/mute23name: keys/mute
20requires: device.product in ['Notebook','Laptop','Portable']24requires: dmi.product in ['Notebook','Laptop','Portable']
21_description:25_description:
22 Press the mute key on the keyboard. A status window should appear \26 PURPOSE:
23 and the volume should mute/unmute when pressed multiple times.27 This test will test the mute key
24 .28 STEPS:
25 Does the key work?29 1. Press the mute button on the keyboard
30 VERIFICATION:
31 Did the volume mute following your key presses?
2632
27plugin: manual33plugin: manual
28name: keys/sleep34name: keys/sleep
29requires: device.product in ['Notebook','Laptop','Portable']35requires: dmi.product in ['Notebook','Laptop','Portable']
30depends: suspend/suspend_advanced36depends: suspend/suspend_advanced
31_description:37_description:
32 Press the sleep key on the keyboard. The computer should suspend and, \38 PURPOSE:
33 after pressing the power button, resume successfully.39 This test will test the sleep key
34 .40 STEPS:
35 Does the key work?41 1. Press the sleep key on the keyboard
42 2. Wake your system up by pressing the power button
43 VERIFICATION:
44 Did the system go to sleep after pressing the sleep key?
3645
37plugin: manual46plugin: manual
38name: keys/battery-info47name: keys/battery-info
39requires: device.product in ['Notebook','Laptop','Portable']48requires: dmi.product in ['Notebook','Laptop','Portable']
40_description:49_description:
41 Press the battery information key on the keyboard. A status window \50 PURPOSE:
42 should appear and the amount of battery remaining should be displayed.51 This test will test the battery information key
43 .52 STEPS:
44 Does the key work?53 1. Press the battery information key on the keyboard
54 VERIFICATION:
55 Did a notification appear showing the battery status?
4556
46plugin: manual57plugin: manual
47name: keys/wireless58name: keys/wireless
48requires: device.product in ['Notebook','Laptop','Portable']59requires: dmi.product in ['Notebook','Laptop','Portable']
49_description:60_description:
50 Press the wireless networking key on the keyboard. The bluetooth icon \61 PURPOSE:
51 and the network connnection should go down if connected through the \62 This test will test the wireless key
52 wifi interface.63 STEPS:
53 .64 1. Press the wireless key on the keyboard
54 Press the same key again and check that bluetooth icon is again \65 2. Press the same key again
55 displayed and that the network connection is re-established \66 VERIFICATION:
56 automatically.67 Did the wireless go off on the first press and on again on the second?
57 .
58 Does the key work?
5968
60plugin: manual69plugin: manual
61name: keys/media-control70name: keys/media-control
62requires: device.category == 'KEYBOARD'71requires:
72 device.category == 'KEYBOARD'
73 package.name == 'totem'
74 package.name == 'gstreamer0.10-plugins-base'
75command: totem /usr/share/example-content/Ubuntu_Free_Culture_Showcase/*
63_description:76_description:
64 The keyboard may have dedicated keys for controlling media as follows:77 PURPOSE:
65 .78 This test will test the media keys of your keyboard
66 * Play/Pause79 STEPS:
67 * Stop80 1. Click test to launch the media player
68 * Forward81 2. Press the play/pause key on the keyboard
69 * Backward (Rewind)82 3. Press the forward key on the keyboard
70 .83 4. Press the backward key on the keyboard
71 Play a media file and press each key in turn.84 5. Press stop key on the keyboard
72 .85 VERIFICATION:
73 Do the keys work as expected?86 Do the keys work as expected?
7487
=== modified file 'jobs/local.txt.in'
--- jobs/local.txt.in 2011-09-01 12:23:07 +0000
+++ jobs/local.txt.in 2011-11-18 18:04:27 +0000
@@ -3,6 +3,11 @@
3_description: Audio tests3_description: Audio tests
4command: cat $CHECKBOX_SHARE/jobs/audio.txt*4command: cat $CHECKBOX_SHARE/jobs/audio.txt*
55
6name: __autotest__
7plugin: local
8_description: Autotest Suite tests
9command: cat $CHECKBOX_SHARE/jobs/autotest.txt*
10
6name: __bluetooth__11name: __bluetooth__
7plugin: local12plugin: local
8_description: Bluetooth tests13_description: Bluetooth tests
@@ -13,7 +18,7 @@
13_description: Camera tests18_description: Camera tests
14command: cat $CHECKBOX_SHARE/jobs/camera.txt*19command: cat $CHECKBOX_SHARE/jobs/camera.txt*
1520
16name: codecs21name: __codecs__
17plugin: local22plugin: local
18_description: Codec tests23_description: Codec tests
19command: cat $CHECKBOX_SHARE/jobs/codecs.txt*24command: cat $CHECKBOX_SHARE/jobs/codecs.txt*
@@ -23,7 +28,7 @@
23_description: CPU tests28_description: CPU tests
24command: cat $CHECKBOX_SHARE/jobs/cpu.txt*29command: cat $CHECKBOX_SHARE/jobs/cpu.txt*
2530
26name: daemon31name: __daemons__
27plugin: local32plugin: local
28_description: System Daemon tests33_description: System Daemon tests
29command: cat $CHECKBOX_SHARE/jobs/daemons.txt*34command: cat $CHECKBOX_SHARE/jobs/daemons.txt*
@@ -53,6 +58,11 @@
53_description: Graphics tests58_description: Graphics tests
54command: cat $CHECKBOX_SHARE/jobs/graphics.txt*59command: cat $CHECKBOX_SHARE/jobs/graphics.txt*
5560
61name: __hibernate__
62plugin: local
63_description: Hibernation tests
64command: cat $CHECKBOX_SHARE/jobs/hibernate.txt*
65
56name: __info__66name: __info__
57plugin: local67plugin: local
58_description: Informational tests68_description: Informational tests
@@ -73,10 +83,15 @@
73_description: Hotkey tests83_description: Hotkey tests
74command: cat $CHECKBOX_SHARE/jobs/keys.txt*84command: cat $CHECKBOX_SHARE/jobs/keys.txt*
7585
76name: __hibernate__86name: __ltp__
77plugin: local87plugin: local
78_description: Hibernation tests88_description: Linux Test Project tests
79command: cat $CHECKBOX_SHARE/jobs/hibernate.txt*89command: cat $CHECKBOX_SHARE/jobs/ltp.txt*
90
91name: __mago__
92plugin: local
93_description: Mago Automated Desktop Testing
94command: cat $CHECKBOX_SHARE/jobs/mago.txt*
8095
81name: __mediacard__96name: __mediacard__
82plugin: local97plugin: local
@@ -108,6 +123,11 @@
108_description: Optical Drive tests123_description: Optical Drive tests
109command: cat $CHECKBOX_SHARE/jobs/optical.txt*124command: cat $CHECKBOX_SHARE/jobs/optical.txt*
110125
126name: __panel_clock__
127plugin: local
128_description: Panel Clock Verification tests
129command: cat $CHECKBOX_SHARE/jobs/panel_clock_test.txt*
130
111name: __pcmcia-pcix__131name: __pcmcia-pcix__
112plugin: local132plugin: local
113_description: PCMCIA/PCIX Card tests133_description: PCMCIA/PCIX Card tests
@@ -118,11 +138,26 @@
118_description: Peripheral tests138_description: Peripheral tests
119command: cat $CHECKBOX_SHARE/jobs/peripheral.txt*139command: cat $CHECKBOX_SHARE/jobs/peripheral.txt*
120140
141name: __phoronix__
142plugin: local
143_description: Phoronix Test Suite tests
144command: cat $CHECKBOX_SHARE/jobs/peripheral.txt*
145
121name: __power-management__146name: __power-management__
122plugin: local147plugin: local
123_description: Power Management tests148_description: Power Management tests
124command: cat $CHECKBOX_SHARE/jobs/power-management.txt*149command: cat $CHECKBOX_SHARE/jobs/power-management.txt*
125150
151name: __qa__
152plugin: local
153_description: QA Regression tests
154command: cat $CHECKBOX_SHARE/jobs/qa_regression.txt*
155
156name: __server-services__
157plugin: local
158_description: Server Services checks
159command: cat $CHECKBOX_SHARE/jobs/server-services.txt*
160
126name: __suspend__161name: __suspend__
127plugin: local162plugin: local
128_description: Suspend tests163_description: Suspend tests
129164
=== modified file 'jobs/ltp.txt.in'
--- jobs/ltp.txt.in 2010-03-09 16:58:36 +0000
+++ jobs/ltp.txt.in 2011-11-18 18:04:27 +0000
@@ -1,6 +1,7 @@
1name: ltp1name: ltp/syscalls
2plugin: remote2plugin: remote
3_description: Linux Test Project3_description:
4 This test installs and runs Linux Test Project syscalls test. This can be destructive, thus this test is blacklisted by default.
4requires:5requires:
5 package.alias == 'linux'6 package.alias == 'linux'
6 package.name == 'cvs'7 package.name == 'cvs'
78
=== modified file 'jobs/mago.txt.in'
--- jobs/mago.txt.in 2011-07-01 11:37:27 +0000
+++ jobs/mago.txt.in 2011-11-18 18:04:27 +0000
@@ -1,8 +1,10 @@
1plugin: remote1plugin: remote
2name: mago2name: mago/suite
3_description: Automated desktop testing
4requires:3requires:
5 package.name == 'bzr'4 package.name == 'bzr'
6 package.name == 'python-ldtp'5 package.name == 'python-ldtp'
7 desktop.gnome.interface.accessibility == True6 desktop.gnome.interface.accessibility == True
8command: mago_suite7command: mago_suite
8_description:
9 PURPOSE:
10 This test installs and runs the Mago Automated Desktop Testing suite.
911
=== modified file 'jobs/mediacard.txt.in'
--- jobs/mediacard.txt.in 2011-09-29 13:12:01 +0000
+++ jobs/mediacard.txt.in 2011-11-18 18:04:27 +0000
@@ -1,137 +1,159 @@
1plugin: manual1plugin: manual
2name: mediacard/sd2name: mediacard/sd
3_description:3_description:
4 Secure Digital (SD) media card support verification:4 PURPOSE:
5 1.- Plug a SD media card into the computer.5 This test will check your system Secure Digital (SD) media card support
6 2.- An icon should appear on the desktop and in the "Places" menu at the top of the screen.6 STEPS:
7 3.- Right click on the deskop icon and select "Safely Remove Drive".7 1. Plug a SD media card into the computer
8 4.- The icon should disappear of both the deskop and the "Places" menu.8 2. An icon should appear on the Launcher
9 .9 3. Right click on the Launcher icon and select "Safely Remove Drive"
10 Does the icon automatically appear/disappear?10 4. The icon should disappear from the Launcher
11 VERIFICATION:
12 Does the icon automatically appear/disappear?
1113
12plugin: manual14plugin: manual
13name: mediacard/sd_after_suspend15name: mediacard/sd_after_suspend
14depends: suspend/suspend_advanced mediacard/sd16depends: suspend/suspend_advanced mediacard/sd
15_description:17_description:
16 Secure Digital (SD) media card support re-verification:18 PURPOSE:
17 1.- Plug a SD media card into the computer.19 This test will check your system Secure Digital (SD) media card support after suspend
18 2.- An icon should appear on the desktop and in the "Places" menu at the top of the screen.20 STEPS:
19 3.- Right click on the deskop icon and select "Safely Remove Drive".21 1. Plug a SD media card into the computer
20 4.- The icon should disappear of both the deskop and the "Places" menu.22 2. An icon should appear on the Launcher
21 .23 3. Right click on the Launcher icon and select "Safely Remove Drive"
22 Does the icon automatically appear/disappear?24 4. The icon should disappear from the Launcher
25 VERIFICATION:
26 Does the icon automatically appear/disappear?
2327
24plugin: manual28plugin: manual
25name: mediacard/sdhc29name: mediacard/sdhc
26_description:30_description:
27 Secure Digital High Capacity (SDHC) media card support verification:31 PURPOSE:
28 1.- Plug a SDHC media card into the computer.32 This test will check your system Secure Digital High Capacity (SDHC) media card support
29 2.- An icon should appear on the desktop and in the "Places" menu at the top of the screen.33 STEPS:
30 3.- Right click on the deskop icon and select "Safely Remove Drive".34 1. Plug a SDHC media card into the computer
31 4.- The icon should disappear of both the deskop and the "Places" menu.35 2. An icon should appear on the Launcher
32 .36 3. Right click on the Launcher icon and select "Safely Remove Drive"
33 Does the icon automatically appear/disappear?37 4. The icon should disappear from the Launcher
38 VERIFICATION:
39 Does the icon automatically appear/disappear?
3440
35plugin: manual41plugin: manual
36name: mediacard/sdhc_after_suspend42name: mediacard/sdhc_after_suspend
37depends: suspend/suspend_advanced mediacard/sdhc43depends: suspend/suspend_advanced mediacard/sdhc
38_description:44_description:
39 Secure Digital High Capacity (SDHC) media card support re-verification:45 This test will check your system Secure Digital High Capacity (SDHC) media card support after suspend
40 1.- Plug a SDHC media card into the computer.46 STEPS:
41 2.- An icon should appear on the desktop and in the "Places" menu at the top of the screen.47 1. Plug a SDHC media card into the computer
42 3.- Right click on the deskop icon and select "Safely Remove Drive".48 2. An icon should appear on the Launcher
43 4.- The icon should disappear of both the deskop and the "Places" menu.49 3. Right click on the Launcher icon and select "Safely Remove Drive"
44 .50 4. The icon should disappear from the Launcher
45 Does the icon automatically appear/disappear?51 VERIFICATION:
52 Does the icon automatically appear/disappear?
4653
47plugin: manual54plugin: manual
48name: mediacard/mmc55name: mediacard/mmc
49_description:56_description:
50 Multi Media Card (MMC) media card support verification:57 PURPOSE:
51 1.- Plug a MMC media card into the computer.58 This test will check your system Multi Media Card (MMC) media card support
52 2.- An icon should appear on the desktop and in the "Places" menu at the top of the screen.59 STEPS:
53 3.- Right click on the deskop icon and select "Safely Remove Drive".60 1. Plug a MMC media card into the computer
54 4.- The icon should disappear of both the deskop and the "Places" menu.61 2. An icon should appear on the Launcher
55 .62 3. Right click on the Launcher icon and select "Safely Remove Drive"
56 Does the icon automatically appear/disappear?63 4. The icon should disappear from the Launcher
64 VERIFICATION:
65 Does the icon automatically appear/disappear?
5766
58plugin: manual67plugin: manual
59name: mediacard/mmc_after_suspend68name: mediacard/mmc_after_suspend
60depends: suspend/suspend_advanced mediacard/mmc69depends: suspend/suspend_advanced mediacard/mmc
61_description:70_description:
62 Multi Media Card (MMC) media card support re-verification:71 PURPOSE:
63 1.- Plug a MMC media card into the computer.72 This test will check your system Multi Media Card (MMC) media card support after suspend
64 2.- An icon should appear on the desktop and in the "Places" menu at the top of the screen.73 STEPS:
65 3.- Right click on the deskop icon and select "Safely Remove Drive".74 1. Plug a MMC media card into the computer
66 4.- The icon should disappear of both the deskop and the "Places" menu.75 2. An icon should appear on the Launcher
67 .76 3. Right click on the Launcher icon and select "Safely Remove Drive"
68 Does the icon automatically appear/disappear?77 4. The icon should disappear from the Launcher
78 VERIFICATION:
79 Does the icon automatically appear/disappear?
6980
70plugin: manual81plugin: manual
71name: mediacard/ms82name: mediacard/ms
72_description:83_description:
73 Memory Stick (MS) media card support verification:84 PURPOSE:
74 1.- Plug a MS media card into the computer.85 This test will check your system Memory Stick (MS) media card support
75 2.- An icon should appear on the desktop and in the "Places" menu at the top of the screen.86 STEPS:
76 3.- Right click on the deskop icon and select "Safely Remove Drive".87 1. Plug a MS media card into the computer
77 4.- The icon should disappear of both the deskop and the "Places" menu.88 2. An icon should appear on the Launcher
78 .89 3. Right click on the Launcher icon and select "Safely Remove Drive"
79 Does the icon automatically appear/disappear?90 4. The icon should disappear from the Launcher
91 VERIFICATION:
92 Does the icon automatically appear/disappear?
8093
81plugin: manual94plugin: manual
82name: mediacard/ms_after_suspend95name: mediacard/ms_after_suspend
83depends: suspend/suspend_advanced mediacard/ms96depends: suspend/suspend_advanced mediacard/ms
84_description:97_description:
85 Memory Stick (MS) media card support re-verification:98 PURPOSE:
86 1.- Plug a MS media card into the computer.99 This test will check your system Memory Stick (MS) media card support after suspend
87 2.- An icon should appear on the desktop and in the "Places" menu at the top of the screen.100 STEPS:
88 3.- Right click on the deskop icon and select "Safely Remove Drive".101 1. Plug a MS media card into the computer
89 4.- The icon should disappear of both the deskop and the "Places" menu.102 2. An icon should appear on the Launcher
90 .103 3. Right click on the Launcher icon and select "Safely Remove Drive"
91 Does the icon automatically appear/disappear?104 4. The icon should disappear from the Launcher
105 VERIFICATION:
106 Does the icon automatically appear/disappear?
92107
93plugin: manual108plugin: manual
94name: mediacard/msp109name: mediacard/msp
95_description:110_description:
96 Memory Stick Pro (MSP) media card support verification:111 PURPOSE:
97 1.- Plug a MSP media card into the computer.112 This test will check your system Memory Stick Pro (MSP) media card support
98 2.- An icon should appear on the desktop and in the "Places" menu at the top of the screen.113 STEPS:
99 3.- Right click on the deskop icon and select "Safely Remove Drive".114 1. Plug a MSP media card into the computer
100 4.- The icon should disappear of both the deskop and the "Places" menu.115 2. An icon should appear on the Launcher
101 .116 3. Right click on the Launcher icon and select "Safely Remove Drive"
102 Does the icon automatically appear/disappear?117 4. The icon should disappear from the Launcher
118 VERIFICATION:
119 Does the icon automatically appear/disappear?
103120
104plugin: manual121plugin: manual
105name: mediacard/msp_after_suspend122name: mediacard/msp_after_suspend
106depends: suspend/suspend_advanced mediacard/msp123depends: suspend/suspend_advanced mediacard/msp
107_description:124_description:
108 Memory Stick Pro (MSP) media card support re-verification:125 PURPOSE:
109 1.- Plug a MSP media card into the computer.126 This test will check your system Memory Stick Pro (MSP) media card support after suspend
110 2.- An icon should appear on the desktop and in the "Places" menu at the top of the screen.127 STEPS:
111 3.- Right click on the deskop icon and select "Safely Remove Drive".128 1. Plug a MSP media card into the computer
112 4.- The icon should disappear of both the deskop and the "Places" menu.129 2. An icon should appear on the Launcher
113 .130 3. Right click on the Launcher icon and select "Safely Remove Drive"
114 Does the icon automatically appear/disappear?131 4. The icon should disappear from the Launcher
132 VERIFICATION:
133 Does the icon automatically appear/disappear?
115134
116plugin: manual135plugin: manual
117name: mediacard/cf136name: mediacard/cf
118_description:137_description:
119 Compact Flash (CF) media card support verification:138 PURPOSE:
120 1.- Plug a CF media card into the computer.139 This test will check your system Compact Flash (CF) media card support
121 2.- An icon should appear on the desktop and in the "Places" menu at the top of the screen.140 STEPS:
122 3.- Right click on the deskop icon and select "Safely Remove Drive".141 1. Plug a CF media card into the computer
123 4.- The icon should disappear of both the deskop and the "Places" menu.142 2. An icon should appear on the Launcher
124 .143 3. Right click on the Launcher icon and select "Safely Remove Drive"
125 Does the icon automatically appear/disappear?144 4. The icon should disappear from the Launcher
145 VERIFICATION:
146 Does the icon automatically appear/disappear?
126147
127plugin: manual148plugin: manual
128name: mediacard/cf_after_suspend149name: mediacard/cf_after_suspend
129depends: suspend/suspend_advanced mediacard/cf150depends: suspend/suspend_advanced mediacard/cf
130_description:151_description:
131 Compact Flash (CF) media card support re-verification:152 This test will check your system Compact Flash (CF) media card support after suspend
132 1.- Plug a CF media card into the computer.153 STEPS:
133 2.- An icon should appear on the desktop and in the "Places" menu at the top of the screen.154 1. Plug a CF media card into the computer
134 3.- Right click on the deskop icon and select "Safely Remove Drive".155 2. An icon should appear on the Launcher
135 4.- The icon should disappear of both the deskop and the "Places" menu.156 3. Right click on the Launcher icon and select "Safely Remove Drive"
136 .157 4. The icon should disappear from the Launcher
137 Does the icon automatically appear/disappear?158 VERIFICATION:
159 Does the icon automatically appear/disappear?
138160
=== modified file 'jobs/memory.txt.in'
--- jobs/memory.txt.in 2011-09-14 21:16:02 +0000
+++ jobs/memory.txt.in 2011-11-18 18:04:27 +0000
@@ -2,11 +2,14 @@
2name: memory/info2name: memory/info
3command: memory_info3command: memory_info
4_description:4_description:
5 The following amount of memory was detected:5 PURPOSE:
6 .6 This test checks the amount of memory that is detected
7 $output7 STEPS:
8 .8 1. Click Test to see the amount of detected memory
9 Is this correct?9 INFO:
10 $output
11 VERIFICATION:
12 Is the amount of detected memory correct?
1013
11plugin: shell14plugin: shell
12name: memory/check15name: memory/check
1316
=== modified file 'jobs/miscellanea.txt.in'
--- jobs/miscellanea.txt.in 2011-09-29 13:12:01 +0000
+++ jobs/miscellanea.txt.in 2011-11-18 18:04:27 +0000
@@ -6,11 +6,12 @@
6user: root6user: root
7command: cycle_vts7command: cycle_vts
8_description:8_description:
9 Select Test to switch to another virtual terminal and then back to X. Your screen will change temporarily to a text console and then switch back to your current session.9 PURPOSE:
10 .10 This test will check that the system can switch to a virtual terminal and back to X
11 Note that this test may require you to enter your password.11 STEPS:
12 .12 1. Click "Test" to switch to another virtual terminal and then back to X
13 Did the screen change temporarily to a text console?13 VERIFICATION:
14 Did your screen change temporarily to a text console and then switch back to your current session?
1415
15plugin: shell16plugin: shell
16name: miscellanea/fwts_test17name: miscellanea/fwts_test
@@ -18,7 +19,7 @@
18 package.name == 'linux'19 package.name == 'linux'
19 package.name == 'fwts'20 package.name == 'fwts'
20_description:21_description:
21 Run Colin King's Firmware Test Suite automated tests.22 Run Firmware Test Suite (fwts) automated tests.
22command:23command:
23 fwts_test -l $CHECKBOX_DATA/fwts_results.log24 fwts_test -l $CHECKBOX_DATA/fwts_results.log
2425
@@ -39,6 +40,16 @@
39plugin: manual40plugin: manual
40name: miscellanea/is_laptop41name: miscellanea/is_laptop
41_description:42_description:
42 Is your system a laptop (or netbook)?43 PURPOSE:
44 This is to determine if we need to run tests specific to portable computers that may not apply to desktops.
45 STEPS:
46 Select "Yes" if your system is a laptop or netbook. Otherwise, select "No"
47
48plugin: shell
49name: miscellanea/apport-directory
50requires: package.name == 'apport'
51command: ! test -d /var/crash || test $(find /var/crash -type f | wc -l) -eq 0
52_description:
53 This test checks /var/crash to see if there are any crash reports present.
43 .54 .
44 Selecting Yes here will allow us to run tests specific to portable computers that may not apply to desktops.55 If there are, this test will fail.
4556
=== modified file 'jobs/monitor.txt.in'
--- jobs/monitor.txt.in 2011-09-14 21:16:02 +0000
+++ jobs/monitor.txt.in 2011-11-18 18:04:27 +0000
@@ -1,52 +1,71 @@
1plugin: manual1plugin: manual
2name: monitor/vga2name: monitor/vga
3_description:3_description:
4 If your system does not have a VGA port, please skip this test.4 PURPOSE:
5 .5 This test will check your VGA port. Skip if your system does not have a VGA port.
6 Connect a display (if not already connected) to the VGA port on your system. Is the image displayed correctly?6 STEPS:
7 1. Connect a display (if not already connected) to the VGA port on your system
8 VERIFICATION:
9 Was the desktop displayed correctly on both screens?
710
8plugin: manual11plugin: manual
9name: monitor/dvi12name: monitor/dvi
10_description:13_description:
11 If your system does not have a DVI port, please skip this test.14 PURPOSE:
12 .15 This test will check your DVI port. Skip if your system does not have a DVI port
13 Connect a display (if not already connected) to the DVI port on your system. Is the image displayed correctly?16 STEPS:
17 1. Connect a display (if not already connected) to the DVI port on your system
18 VERIFICATION:
19 Was the desktop displayed correctly on both screens?
1420
15plugin: manual21plugin: manual
16name: monitor/displayport22name: monitor/displayport
17_description:23_description:
18 If your system does not have DisplayPort, please skip this test.24 PURPOSE:
19 .25 This test will check your DisplayPort port. Skip if your system does not have a DisplayPort port
20 Connect a display (if not already connected) to the DisplayPort on your system. Is the image displayed correctly?26 STEPS:
27 1. Connect a display (if not already connected) to the DisplayPort port on your system
28 VERIFICATION:
29 Was the desktop displayed correctly on both screens?
2130
22plugin: manual31plugin: manual
23name: monitor/hdmi32name: monitor/hdmi
24_description:33_description:
25 If your system does not have a HDMI port, please skip this test.34 PURPOSE:
26 .35 This test will check your HDMI port. Skip if your system does not have a HDMI port
27 Connect a display (if not already connected) to the HDMI port on your system. Is the image displayed correctly?36 STEPS:
37 1. Connect a display (if not already connected) to the HDMI port on your system
38 VERIFICATION:
39 Was the desktop displayed correctly on both screens?
2840
29plugin: manual41plugin: manual
30name: monitor/svideo42name: monitor/svideo
31_description:43_description:
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches