Merge lp:~brendan-donegan/ubuntu/raring/checkbox/0.15.4 into lp:ubuntu/raring/checkbox

Proposed by Brendan Donegan
Status: Merged
Merged at revision: 1880
Proposed branch: lp:~brendan-donegan/ubuntu/raring/checkbox/0.15.4
Merge into: lp:ubuntu/raring/checkbox
Diff against target: 7070 lines (+2426/-817)
170 files modified
Vagrantfile (+14/-9)
checkbox/parsers/tests/test_submission.py (+2/-2)
checkbox/parsers/udevadm.py (+21/-0)
debian/changelog (+18/-0)
debian/po/ast.po (+2/-2)
debian/po/cs.po (+2/-2)
debian/po/de.po (+2/-2)
debian/po/en_AU.po (+2/-2)
debian/po/en_GB.po (+2/-2)
debian/po/es.po (+2/-2)
debian/po/fr.po (+2/-2)
debian/po/gl.po (+2/-2)
debian/po/he.po (+2/-2)
debian/po/hu.po (+2/-2)
debian/po/id.po (+2/-2)
debian/po/it.po (+2/-2)
debian/po/ja.po (+2/-2)
debian/po/nl.po (+2/-2)
debian/po/oc.po (+2/-2)
debian/po/pl.po (+2/-2)
debian/po/pt_BR.po (+2/-2)
debian/po/ro.po (+2/-2)
debian/po/ru.po (+2/-2)
debian/po/tr.po (+2/-2)
debian/po/uk.po (+2/-2)
debian/po/zh_CN.po (+2/-2)
debian/po/zh_TW.po (+2/-2)
jobs/graphics.txt.in (+2/-1)
jobs/input.txt.in (+1/-0)
jobs/optical.txt.in (+4/-4)
jobs/suspend.txt.in (+1/-1)
plainbox/docs/changelog.rst (+32/-0)
plainbox/docs/dev/architecture.rst (+337/-0)
plainbox/docs/dev/index.rst (+14/-0)
plainbox/docs/dev/intro.rst (+238/-0)
plainbox/docs/dev/reference.rst (+154/-0)
plainbox/docs/glossary.rst (+104/-0)
plainbox/docs/index.rst (+46/-6)
plainbox/docs/usage.rst (+69/-0)
plainbox/plainbox/__init__.py (+4/-4)
plainbox/plainbox/abc.py (+2/-4)
plainbox/plainbox/impl/__init__.py (+6/-4)
plainbox/plainbox/impl/box.py (+55/-14)
plainbox/plainbox/impl/checkbox.py (+9/-9)
plainbox/plainbox/impl/commands/__init__.py (+6/-6)
plainbox/plainbox/impl/commands/selftest.py (+6/-6)
plainbox/plainbox/impl/depmgr.py (+17/-15)
plainbox/plainbox/impl/exporter/__init__.py (+20/-9)
plainbox/plainbox/impl/exporter/json.py (+5/-6)
plainbox/plainbox/impl/exporter/rfc822.py (+6/-6)
plainbox/plainbox/impl/exporter/test_init.py (+16/-12)
plainbox/plainbox/impl/exporter/text.py (+6/-6)
plainbox/plainbox/impl/integration_tests.py (+20/-4)
plainbox/plainbox/impl/job.py (+18/-8)
plainbox/plainbox/impl/mock_job.py (+36/-0)
plainbox/plainbox/impl/resource.py (+7/-7)
plainbox/plainbox/impl/result.py (+42/-12)
plainbox/plainbox/impl/rfc822.py (+10/-7)
plainbox/plainbox/impl/runner.py (+76/-19)
plainbox/plainbox/impl/session.py (+115/-52)
plainbox/plainbox/impl/test_box.py (+110/-14)
plainbox/plainbox/impl/test_job.py (+3/-3)
plainbox/plainbox/impl/test_result.py (+22/-18)
plainbox/plainbox/impl/test_runner.py (+5/-5)
plainbox/plainbox/impl/test_session.py (+188/-14)
plainbox/plainbox/impl/testing_utils.py (+18/-6)
plainbox/plainbox/impl/utils.py.moved (+0/-58)
plainbox/plainbox/public.py (+2/-2)
plainbox/plainbox/testing_utils/__init__.py (+2/-4)
plainbox/plainbox/testing_utils/cwd.py (+2/-2)
plainbox/plainbox/testing_utils/io.py (+2/-2)
plainbox/plainbox/testing_utils/testcases.py (+3/-3)
plainbox/plainbox/tests.py (+2/-4)
plainbox/plainbox/vendor/__init__.py (+28/-0)
plainbox/plainbox/vendor/extcmd/__init__.py (+2/-2)
plainbox/setup.py (+3/-0)
po/ace.po (+4/-4)
po/af.po (+4/-4)
po/am.po (+4/-4)
po/ar.po (+4/-4)
po/ast.po (+4/-4)
po/az.po (+4/-4)
po/be.po (+4/-4)
po/bg.po (+4/-4)
po/bn.po (+4/-4)
po/bo.po (+4/-4)
po/br.po (+4/-4)
po/bs.po (+4/-4)
po/ca.po (+4/-4)
po/ca@valencia.po (+4/-4)
po/ckb.po (+4/-4)
po/cs.po (+4/-4)
po/cy.po (+4/-4)
po/da.po (+4/-4)
po/de.po (+5/-5)
po/dv.po (+4/-4)
po/el.po (+4/-4)
po/en_AU.po (+4/-4)
po/en_CA.po (+4/-4)
po/en_GB.po (+4/-4)
po/eo.po (+4/-4)
po/es.po (+4/-4)
po/et.po (+4/-4)
po/eu.po (+4/-4)
po/fa.po (+4/-4)
po/fi.po (+4/-4)
po/fr.po (+4/-4)
po/ga.po (+4/-4)
po/gd.po (+4/-4)
po/gl.po (+4/-4)
po/he.po (+4/-4)
po/hi.po (+4/-4)
po/hr.po (+4/-4)
po/hu.po (+4/-4)
po/hy.po (+4/-4)
po/id.po (+4/-4)
po/is.po (+4/-4)
po/it.po (+4/-4)
po/ja.po (+4/-4)
po/jbo.po (+4/-4)
po/ka.po (+4/-4)
po/kk.po (+4/-4)
po/km.po (+4/-4)
po/kn.po (+4/-4)
po/ko.po (+4/-4)
po/ku.po (+4/-4)
po/ky.po (+4/-4)
po/lt.po (+4/-4)
po/lv.po (+4/-4)
po/mk.po (+4/-4)
po/ml.po (+4/-4)
po/mr.po (+4/-4)
po/ms.po (+4/-4)
po/my.po (+4/-4)
po/nb.po (+4/-4)
po/nds.po (+4/-4)
po/ne.po (+4/-4)
po/nl.po (+4/-4)
po/nn.po (+4/-4)
po/oc.po (+4/-4)
po/pl.po (+4/-4)
po/ps.po (+4/-4)
po/pt.po (+4/-4)
po/pt_BR.po (+4/-4)
po/ro.po (+4/-4)
po/ru.po (+4/-4)
po/sd.po (+4/-4)
po/shn.po (+4/-4)
po/si.po (+4/-4)
po/sk.po (+4/-4)
po/sl.po (+4/-4)
po/sq.po (+4/-4)
po/sr.po (+4/-4)
po/sv.po (+4/-4)
po/ta.po (+4/-4)
po/te.po (+4/-4)
po/th.po (+4/-4)
po/tr.po (+22/-7)
po/ug.po (+4/-4)
po/uk.po (+4/-4)
po/ur.po (+4/-4)
po/uz.po (+4/-4)
po/vi.po (+4/-4)
po/zh_CN.po (+4/-4)
po/zh_HK.po (+4/-4)
po/zh_TW.po (+4/-4)
scripts/network_device_info (+56/-35)
scripts/udev_resource (+1/-1)
test (+4/-0)
test-in-vagrant.sh (+9/-1)
To merge this branch: bzr merge lp:~brendan-donegan/ubuntu/raring/checkbox/0.15.4
Reviewer Review Type Date Requested Status
Daniel Manrique (community) Approve
Review via email: mp+152211@code.launchpad.net

Description of the change

checkbox (0.15.4) raring; urgency=low

  * New upstream release (LP: #1152223)

  [ Daniel Manrique ]
  * Added pipefail option to a few jobs using ansi_parser (LP: #1131598)

  [ Jeff Marcom ]
  * jobs/input.txt.in Added job requirement for accelerometer test (LP: #1135832)

  [Sylvain Pineau]
  * scripts/network_device_info, scripts/udev_resource,
    checkbox/parsers/udevadm.py: Use udev to categorise network devices instead
    of lspci (LP: #1091633)

 -- Brendan Donegan <email address hidden> Thu, 07 Mar 2013 15:43:13 +0000

To post a comment you must log in.
Revision history for this message
Daniel Manrique (roadmr) wrote :

Thanks, merged.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'Vagrantfile'
--- Vagrantfile 2013-02-22 16:26:25 +0000
+++ Vagrantfile 2013-03-07 16:10:38 +0000
@@ -5,24 +5,29 @@
55
6 # Define a Ubuntu Server image (cloud) for the 12.10 release (quantal)6 # Define a Ubuntu Server image (cloud) for the 12.10 release (quantal)
7 config.vm.define :quantal do |quantal_config|7 config.vm.define :quantal do |quantal_config|
8 quantal_config.vm.box = "quantal-cloud-amd64"8 quantal_config.vm.box = "quantal-cloud-i386"
9 quantal_config.vm.box_url = "http://cloud-images.ubuntu.com/vagrant/quantal/current/quantal-server-cloudimg-amd64-vagrant-disk1.box"9 quantal_config.vm.box_url = "http://cloud-images.ubuntu.com/vagrant/quantal/current/quantal-server-cloudimg-i386-vagrant-disk1.box"
10 end10 end
1111
12 # Define a Ubuntu Server image (cloud) for the 12.04 release (precise)12 # Define a Ubuntu Server image (cloud) for the 12.04 release (precise)
13 config.vm.define :precise do |precise_config|13 config.vm.define :precise do |precise_config|
14 precise_config.vm.box = "precise-cloud-amd64"14 precise_config.vm.box = "precise-cloud-i386"
15 precise_config.vm.box_url = "http://cloud-images.ubuntu.com/vagrant/precise/current/precise-server-cloudimg-amd64-vagrant-disk1.box"15 precise_config.vm.box_url = "http://cloud-images.ubuntu.com/vagrant/precise/current/precise-server-cloudimg-i386-vagrant-disk1.box"
16 end16 end
1717
18 # For debugging and later future GUI testing18 # For debugging and later future GUI testing
19 # config.vm.boot_mode = :gui19 # config.vm.boot_mode = :gui
2020
21 # Update to have the latest packages21 # Update to have the latest packages, this is needed because the image comes
22 # Commented out for now, we don't really need it22 # with an old (and no longer working) apt cache and links to many packages no
23 # config.vm.provision :shell, :inline => "apt-get update && apt-get dist-upgrade"23 # longer work.
24 config.vm.provision :shell, :inline => "apt-get update && apt-get dist-upgrade --yes"
24 # Install dependencies from native packages25 # Install dependencies from native packages
25 config.vm.provision :shell, :inline => "apt-get install --yes python3-setuptools python3-yaml python3-lxml"26 config.vm.provision :shell, :inline => "apt-get install --yes python3-setuptools python3-lxml"
27 # Install python3-mock so that we can create mock objects for testing
28 config.vm.provision :shell, :inline => "apt-get install --yes python3-mock"
29 # Install policykit-1 so that we have pkexec
30 config.vm.provision :shell, :inline => "apt-get install --yes policykit-1"
26 # Install some checkbox script dependencies:31 # Install some checkbox script dependencies:
27 # Later on those could be installed on demand to test how we behave without32 # Later on those could be installed on demand to test how we behave without
28 # them but for now that's good enough. Little by little...33 # them but for now that's good enough. Little by little...
@@ -38,5 +43,5 @@
38 # Develop plainbox so that we have it in $PATH43 # Develop plainbox so that we have it in $PATH
39 config.vm.provision :shell, :inline => "cd /vagrant/plainbox/ && python3 setup.py develop"44 config.vm.provision :shell, :inline => "cd /vagrant/plainbox/ && python3 setup.py develop"
40 # Create a cool symlink so that everyone knows where to go to45 # Create a cool symlink so that everyone knows where to go to
41 config.vm.provision :shell, :inline => "ln -s /vagrant /home/vagrant/checkbox"46 config.vm.provision :shell, :inline => "ln -fs /vagrant /home/vagrant/checkbox"
42end47end
4348
=== modified file 'checkbox/parsers/tests/test_submission.py'
--- checkbox/parsers/tests/test_submission.py 2012-10-12 21:39:01 +0000
+++ checkbox/parsers/tests/test_submission.py 2013-03-07 16:10:38 +0000
@@ -153,13 +153,13 @@
153 """Device states can be in the udev element."""153 """Device states can be in the udev element."""
154 result = self.getResult("submission_udev.xml")154 result = self.getResult("submission_udev.xml")
155 self.assertTrue("device_states" in result)155 self.assertTrue("device_states" in result)
156 self.assertEquals(len(result["device_states"]), 77)156 self.assertEquals(len(result["device_states"]), 82)
157157
158 def test_device_udevadm(self):158 def test_device_udevadm(self):
159 """Device states can be in a udevadm info element."""159 """Device states can be in a udevadm info element."""
160 result = self.getResult("submission_info_udevadm.xml")160 result = self.getResult("submission_info_udevadm.xml")
161 self.assertTrue("device_states" in result)161 self.assertTrue("device_states" in result)
162 self.assertEquals(len(result["device_states"]), 77)162 self.assertEquals(len(result["device_states"]), 82)
163163
164 def test_device_dmidecode(self):164 def test_device_dmidecode(self):
165 """Device states can be in a dmidecode info element."""165 """Device states can be in a dmidecode info element."""
166166
=== modified file 'checkbox/parsers/udevadm.py'
--- checkbox/parsers/udevadm.py 2012-11-12 09:59:00 +0000
+++ checkbox/parsers/udevadm.py 2013-03-07 16:10:38 +0000
@@ -92,8 +92,15 @@
92 @property92 @property
93 def category(self):93 def category(self):
94 if "IFINDEX" in self._environment:94 if "IFINDEX" in self._environment:
95 if "DEVTYPE" in self._environment:
96 devtype = self._environment["DEVTYPE"]
97 if devtype == "wlan":
98 return "WIRELESS"
95 return "NETWORK"99 return "NETWORK"
96100
101 if self.bus == "sound":
102 return "AUDIO"
103
97 if self.bus == "ieee80211":104 if self.bus == "ieee80211":
98 return "WIRELESS"105 return "WIRELESS"
99106
@@ -383,6 +390,9 @@
383 if self.driver == "floppy":390 if self.driver == "floppy":
384 return "Platform Device"391 return "Platform Device"
385392
393 if "ID_MODEL_FROM_DATABASE" in self._environment:
394 return self._environment["ID_MODEL_FROM_DATABASE"]
395
386 return None396 return None
387397
388 @property398 @property
@@ -407,6 +417,17 @@
407 and "ID_VENDOR_ENC" in self._environment:417 and "ID_VENDOR_ENC" in self._environment:
408 return decode_id(self._environment["ID_VENDOR_ENC"])418 return decode_id(self._environment["ID_VENDOR_ENC"])
409419
420 if "ID_VENDOR_FROM_DATABASE" in self._environment:
421 return self._environment["ID_VENDOR_FROM_DATABASE"]
422
423 return None
424
425 @property
426 def interface(self):
427 if self.category in ("NETWORK", "WIRELESS") \
428 and "INTERFACE" in self._environment:
429 return self._environment["INTERFACE"]
430
410 return None431 return None
411432
412433
413434
=== modified file 'debian/changelog'
--- debian/changelog 2013-02-22 16:41:55 +0000
+++ debian/changelog 2013-03-07 16:10:38 +0000
@@ -1,7 +1,25 @@
1checkbox (0.15.4) raring; urgency=low
2
3 * New upstream release (LP: #1152223)
4
5 [ Daniel Manrique ]
6 * Added pipefail option to a few jobs using ansi_parser (LP: #1131598)
7
8 [ Jeff Marcom ]
9 * jobs/input.txt.in Added job requirement for accelerometer test (LP: #1135832)
10
11 [Sylvain Pineau]
12 * scripts/network_device_info, scripts/udev_resource,
13 checkbox/parsers/udevadm.py: Use udev to categorise network devices instead
14 of lspci (LP: #1091633)
15
16 -- Brendan Donegan <brendan.donegan@ubuntu.com> Thu, 07 Mar 2013 15:43:13 +0000
17
1checkbox (0.15.3) raring; urgency=low18checkbox (0.15.3) raring; urgency=low
219
3 * New upstream release (LP: #1131801)20 * New upstream release (LP: #1131801)
421
22 [ Daniel Manrique ]
5 * scripts/pts_run: modified to output the full log from phoronix-test-suite23 * scripts/pts_run: modified to output the full log from phoronix-test-suite
6 (LP: #1102819)24 (LP: #1102819)
725
826
=== modified file 'debian/po/ast.po'
--- debian/po/ast.po 2013-02-22 16:26:25 +0000
+++ debian/po/ast.po 2013-03-07 16:10:38 +0000
@@ -14,8 +14,8 @@
14"MIME-Version: 1.0\n"14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"16"Content-Transfer-Encoding: 8bit\n"
17"X-Launchpad-Export-Date: 2013-02-15 04:35+0000\n"17"X-Launchpad-Export-Date: 2013-02-23 04:42+0000\n"
18"X-Generator: Launchpad (build 16491)\n"18"X-Generator: Launchpad (build 16506)\n"
1919
20#. Type: string20#. Type: string
21#. Description21#. Description
2222
=== modified file 'debian/po/cs.po'
--- debian/po/cs.po 2013-02-22 16:26:25 +0000
+++ debian/po/cs.po 2013-03-07 16:10:38 +0000
@@ -14,8 +14,8 @@
14"MIME-Version: 1.0\n"14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"16"Content-Transfer-Encoding: 8bit\n"
17"X-Launchpad-Export-Date: 2013-02-15 04:35+0000\n"17"X-Launchpad-Export-Date: 2013-02-23 04:42+0000\n"
18"X-Generator: Launchpad (build 16491)\n"18"X-Generator: Launchpad (build 16506)\n"
1919
20#. Type: string20#. Type: string
21#. Description21#. Description
2222
=== modified file 'debian/po/de.po'
--- debian/po/de.po 2013-02-22 16:26:25 +0000
+++ debian/po/de.po 2013-03-07 16:10:38 +0000
@@ -14,8 +14,8 @@
14"MIME-Version: 1.0\n"14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"16"Content-Transfer-Encoding: 8bit\n"
17"X-Launchpad-Export-Date: 2013-02-15 04:35+0000\n"17"X-Launchpad-Export-Date: 2013-02-23 04:42+0000\n"
18"X-Generator: Launchpad (build 16491)\n"18"X-Generator: Launchpad (build 16506)\n"
1919
20#. Type: string20#. Type: string
21#. Description21#. Description
2222
=== modified file 'debian/po/en_AU.po'
--- debian/po/en_AU.po 2013-02-22 16:26:25 +0000
+++ debian/po/en_AU.po 2013-03-07 16:10:38 +0000
@@ -14,8 +14,8 @@
14"MIME-Version: 1.0\n"14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"16"Content-Transfer-Encoding: 8bit\n"
17"X-Launchpad-Export-Date: 2013-02-15 04:35+0000\n"17"X-Launchpad-Export-Date: 2013-02-23 04:42+0000\n"
18"X-Generator: Launchpad (build 16491)\n"18"X-Generator: Launchpad (build 16506)\n"
1919
20#. Type: string20#. Type: string
21#. Description21#. Description
2222
=== modified file 'debian/po/en_GB.po'
--- debian/po/en_GB.po 2013-02-22 16:26:25 +0000
+++ debian/po/en_GB.po 2013-03-07 16:10:38 +0000
@@ -14,8 +14,8 @@
14"MIME-Version: 1.0\n"14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"16"Content-Transfer-Encoding: 8bit\n"
17"X-Launchpad-Export-Date: 2013-02-15 04:35+0000\n"17"X-Launchpad-Export-Date: 2013-02-23 04:42+0000\n"
18"X-Generator: Launchpad (build 16491)\n"18"X-Generator: Launchpad (build 16506)\n"
1919
20#. Type: string20#. Type: string
21#. Description21#. Description
2222
=== modified file 'debian/po/es.po'
--- debian/po/es.po 2013-02-22 16:26:25 +0000
+++ debian/po/es.po 2013-03-07 16:10:38 +0000
@@ -14,8 +14,8 @@
14"MIME-Version: 1.0\n"14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"16"Content-Transfer-Encoding: 8bit\n"
17"X-Launchpad-Export-Date: 2013-02-15 04:35+0000\n"17"X-Launchpad-Export-Date: 2013-02-23 04:42+0000\n"
18"X-Generator: Launchpad (build 16491)\n"18"X-Generator: Launchpad (build 16506)\n"
1919
20#. Type: string20#. Type: string
21#. Description21#. Description
2222
=== modified file 'debian/po/fr.po'
--- debian/po/fr.po 2013-02-22 16:26:25 +0000
+++ debian/po/fr.po 2013-03-07 16:10:38 +0000
@@ -14,8 +14,8 @@
14"MIME-Version: 1.0\n"14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"16"Content-Transfer-Encoding: 8bit\n"
17"X-Launchpad-Export-Date: 2013-02-15 04:35+0000\n"17"X-Launchpad-Export-Date: 2013-02-23 04:42+0000\n"
18"X-Generator: Launchpad (build 16491)\n"18"X-Generator: Launchpad (build 16506)\n"
1919
20#. Type: string20#. Type: string
21#. Description21#. Description
2222
=== modified file 'debian/po/gl.po'
--- debian/po/gl.po 2013-02-22 16:26:25 +0000
+++ debian/po/gl.po 2013-03-07 16:10:38 +0000
@@ -14,8 +14,8 @@
14"MIME-Version: 1.0\n"14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"16"Content-Transfer-Encoding: 8bit\n"
17"X-Launchpad-Export-Date: 2013-02-15 04:35+0000\n"17"X-Launchpad-Export-Date: 2013-02-23 04:42+0000\n"
18"X-Generator: Launchpad (build 16491)\n"18"X-Generator: Launchpad (build 16506)\n"
1919
20#. Type: string20#. Type: string
21#. Description21#. Description
2222
=== modified file 'debian/po/he.po'
--- debian/po/he.po 2013-02-22 16:26:25 +0000
+++ debian/po/he.po 2013-03-07 16:10:38 +0000
@@ -14,8 +14,8 @@
14"MIME-Version: 1.0\n"14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"16"Content-Transfer-Encoding: 8bit\n"
17"X-Launchpad-Export-Date: 2013-02-15 04:35+0000\n"17"X-Launchpad-Export-Date: 2013-02-23 04:42+0000\n"
18"X-Generator: Launchpad (build 16491)\n"18"X-Generator: Launchpad (build 16506)\n"
1919
20#. Type: string20#. Type: string
21#. Description21#. Description
2222
=== modified file 'debian/po/hu.po'
--- debian/po/hu.po 2013-02-22 16:26:25 +0000
+++ debian/po/hu.po 2013-03-07 16:10:38 +0000
@@ -14,8 +14,8 @@
14"MIME-Version: 1.0\n"14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"16"Content-Transfer-Encoding: 8bit\n"
17"X-Launchpad-Export-Date: 2013-02-15 04:35+0000\n"17"X-Launchpad-Export-Date: 2013-02-23 04:42+0000\n"
18"X-Generator: Launchpad (build 16491)\n"18"X-Generator: Launchpad (build 16506)\n"
1919
20#. Type: string20#. Type: string
21#. Description21#. Description
2222
=== modified file 'debian/po/id.po'
--- debian/po/id.po 2013-02-22 16:26:25 +0000
+++ debian/po/id.po 2013-03-07 16:10:38 +0000
@@ -14,8 +14,8 @@
14"MIME-Version: 1.0\n"14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"16"Content-Transfer-Encoding: 8bit\n"
17"X-Launchpad-Export-Date: 2013-02-15 04:35+0000\n"17"X-Launchpad-Export-Date: 2013-02-23 04:42+0000\n"
18"X-Generator: Launchpad (build 16491)\n"18"X-Generator: Launchpad (build 16506)\n"
1919
20#. Type: string20#. Type: string
21#. Description21#. Description
2222
=== modified file 'debian/po/it.po'
--- debian/po/it.po 2013-02-22 16:26:25 +0000
+++ debian/po/it.po 2013-03-07 16:10:38 +0000
@@ -14,8 +14,8 @@
14"MIME-Version: 1.0\n"14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"16"Content-Transfer-Encoding: 8bit\n"
17"X-Launchpad-Export-Date: 2013-02-15 04:35+0000\n"17"X-Launchpad-Export-Date: 2013-02-23 04:42+0000\n"
18"X-Generator: Launchpad (build 16491)\n"18"X-Generator: Launchpad (build 16506)\n"
1919
20#. Type: string20#. Type: string
21#. Description21#. Description
2222
=== modified file 'debian/po/ja.po'
--- debian/po/ja.po 2013-02-22 16:26:25 +0000
+++ debian/po/ja.po 2013-03-07 16:10:38 +0000
@@ -14,8 +14,8 @@
14"MIME-Version: 1.0\n"14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"16"Content-Transfer-Encoding: 8bit\n"
17"X-Launchpad-Export-Date: 2013-02-15 04:35+0000\n"17"X-Launchpad-Export-Date: 2013-02-23 04:42+0000\n"
18"X-Generator: Launchpad (build 16491)\n"18"X-Generator: Launchpad (build 16506)\n"
1919
20#. Type: string20#. Type: string
21#. Description21#. Description
2222
=== modified file 'debian/po/nl.po'
--- debian/po/nl.po 2013-02-22 16:26:25 +0000
+++ debian/po/nl.po 2013-03-07 16:10:38 +0000
@@ -14,8 +14,8 @@
14"MIME-Version: 1.0\n"14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"16"Content-Transfer-Encoding: 8bit\n"
17"X-Launchpad-Export-Date: 2013-02-15 04:35+0000\n"17"X-Launchpad-Export-Date: 2013-02-23 04:42+0000\n"
18"X-Generator: Launchpad (build 16491)\n"18"X-Generator: Launchpad (build 16506)\n"
1919
20#. Type: string20#. Type: string
21#. Description21#. Description
2222
=== modified file 'debian/po/oc.po'
--- debian/po/oc.po 2013-02-22 16:26:25 +0000
+++ debian/po/oc.po 2013-03-07 16:10:38 +0000
@@ -14,8 +14,8 @@
14"MIME-Version: 1.0\n"14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"16"Content-Transfer-Encoding: 8bit\n"
17"X-Launchpad-Export-Date: 2013-02-15 04:35+0000\n"17"X-Launchpad-Export-Date: 2013-02-23 04:42+0000\n"
18"X-Generator: Launchpad (build 16491)\n"18"X-Generator: Launchpad (build 16506)\n"
1919
20#. Type: string20#. Type: string
21#. Description21#. Description
2222
=== modified file 'debian/po/pl.po'
--- debian/po/pl.po 2013-02-22 16:26:25 +0000
+++ debian/po/pl.po 2013-03-07 16:10:38 +0000
@@ -14,8 +14,8 @@
14"MIME-Version: 1.0\n"14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"16"Content-Transfer-Encoding: 8bit\n"
17"X-Launchpad-Export-Date: 2013-02-15 04:35+0000\n"17"X-Launchpad-Export-Date: 2013-02-23 04:42+0000\n"
18"X-Generator: Launchpad (build 16491)\n"18"X-Generator: Launchpad (build 16506)\n"
1919
20#. Type: string20#. Type: string
21#. Description21#. Description
2222
=== modified file 'debian/po/pt_BR.po'
--- debian/po/pt_BR.po 2013-02-22 16:26:25 +0000
+++ debian/po/pt_BR.po 2013-03-07 16:10:38 +0000
@@ -14,8 +14,8 @@
14"MIME-Version: 1.0\n"14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"16"Content-Transfer-Encoding: 8bit\n"
17"X-Launchpad-Export-Date: 2013-02-15 04:35+0000\n"17"X-Launchpad-Export-Date: 2013-02-23 04:42+0000\n"
18"X-Generator: Launchpad (build 16491)\n"18"X-Generator: Launchpad (build 16506)\n"
1919
20#. Type: string20#. Type: string
21#. Description21#. Description
2222
=== modified file 'debian/po/ro.po'
--- debian/po/ro.po 2013-02-22 16:26:25 +0000
+++ debian/po/ro.po 2013-03-07 16:10:38 +0000
@@ -14,8 +14,8 @@
14"MIME-Version: 1.0\n"14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"16"Content-Transfer-Encoding: 8bit\n"
17"X-Launchpad-Export-Date: 2013-02-15 04:35+0000\n"17"X-Launchpad-Export-Date: 2013-02-23 04:42+0000\n"
18"X-Generator: Launchpad (build 16491)\n"18"X-Generator: Launchpad (build 16506)\n"
1919
20#. Type: string20#. Type: string
21#. Description21#. Description
2222
=== modified file 'debian/po/ru.po'
--- debian/po/ru.po 2013-02-22 16:26:25 +0000
+++ debian/po/ru.po 2013-03-07 16:10:38 +0000
@@ -14,8 +14,8 @@
14"MIME-Version: 1.0\n"14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"16"Content-Transfer-Encoding: 8bit\n"
17"X-Launchpad-Export-Date: 2013-02-15 04:35+0000\n"17"X-Launchpad-Export-Date: 2013-02-23 04:42+0000\n"
18"X-Generator: Launchpad (build 16491)\n"18"X-Generator: Launchpad (build 16506)\n"
1919
20#. Type: string20#. Type: string
21#. Description21#. Description
2222
=== modified file 'debian/po/tr.po'
--- debian/po/tr.po 2013-02-22 16:26:25 +0000
+++ debian/po/tr.po 2013-03-07 16:10:38 +0000
@@ -14,8 +14,8 @@
14"MIME-Version: 1.0\n"14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"16"Content-Transfer-Encoding: 8bit\n"
17"X-Launchpad-Export-Date: 2013-02-15 04:35+0000\n"17"X-Launchpad-Export-Date: 2013-02-23 04:42+0000\n"
18"X-Generator: Launchpad (build 16491)\n"18"X-Generator: Launchpad (build 16506)\n"
1919
20#. Type: string20#. Type: string
21#. Description21#. Description
2222
=== modified file 'debian/po/uk.po'
--- debian/po/uk.po 2013-02-22 16:26:25 +0000
+++ debian/po/uk.po 2013-03-07 16:10:38 +0000
@@ -14,8 +14,8 @@
14"MIME-Version: 1.0\n"14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"16"Content-Transfer-Encoding: 8bit\n"
17"X-Launchpad-Export-Date: 2013-02-15 04:35+0000\n"17"X-Launchpad-Export-Date: 2013-02-23 04:42+0000\n"
18"X-Generator: Launchpad (build 16491)\n"18"X-Generator: Launchpad (build 16506)\n"
1919
20#. Type: string20#. Type: string
21#. Description21#. Description
2222
=== modified file 'debian/po/zh_CN.po'
--- debian/po/zh_CN.po 2013-02-22 16:26:25 +0000
+++ debian/po/zh_CN.po 2013-03-07 16:10:38 +0000
@@ -14,8 +14,8 @@
14"MIME-Version: 1.0\n"14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"16"Content-Transfer-Encoding: 8bit\n"
17"X-Launchpad-Export-Date: 2013-02-15 04:35+0000\n"17"X-Launchpad-Export-Date: 2013-02-23 04:42+0000\n"
18"X-Generator: Launchpad (build 16491)\n"18"X-Generator: Launchpad (build 16506)\n"
1919
20#. Type: string20#. Type: string
21#. Description21#. Description
2222
=== modified file 'debian/po/zh_TW.po'
--- debian/po/zh_TW.po 2013-02-22 16:26:25 +0000
+++ debian/po/zh_TW.po 2013-03-07 16:10:38 +0000
@@ -14,8 +14,8 @@
14"MIME-Version: 1.0\n"14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"16"Content-Transfer-Encoding: 8bit\n"
17"X-Launchpad-Export-Date: 2013-02-15 04:35+0000\n"17"X-Launchpad-Export-Date: 2013-02-23 04:42+0000\n"
18"X-Generator: Launchpad (build 16491)\n"18"X-Generator: Launchpad (build 16506)\n"
1919
20#. Type: string20#. Type: string
21#. Description21#. Description
2222
=== modified file 'jobs/graphics.txt.in'
--- jobs/graphics.txt.in 2012-12-12 12:59:22 +0000
+++ jobs/graphics.txt.in 2013-03-07 16:10:38 +0000
@@ -170,7 +170,7 @@
170plugin: shell170plugin: shell
171name: graphics/screenshot171name: graphics/screenshot
172requires: package.name == 'fswebcam'172requires: package.name == 'fswebcam'
173command: camera_test still --device=/dev/external_webcam -f ${CHECKBOX_DATA}/screenshot.jpg -q 2>&1 | ansi_parser173command: set -o pipefail; camera_test still --device=/dev/external_webcam -f ${CHECKBOX_DATA}/screenshot.jpg -q 2>&1 | ansi_parser
174_description:174_description:
175 PURPOSE:175 PURPOSE:
176 Take a screengrab of the current screen (logged on Unity desktop)176 Take a screengrab of the current screen (logged on Unity desktop)
@@ -191,6 +191,7 @@
191command:191command:
192 dbus-launch gsettings set org.gnome.totem repeat true192 dbus-launch gsettings set org.gnome.totem repeat true
193 totem --fullscreen ${CHECKBOX_SHARE}/data/video/Ogg_Theora_Video.ogv 2>/dev/null &193 totem --fullscreen ${CHECKBOX_SHARE}/data/video/Ogg_Theora_Video.ogv 2>/dev/null &
194 set -o pipefail
194 sleep 15 && camera_test still --device=/dev/external_webcam -f ${CHECKBOX_DATA}/screenshot_fullscreen_video.jpg -q 2>&1 | ansi_parser195 sleep 15 && camera_test still --device=/dev/external_webcam -f ${CHECKBOX_DATA}/screenshot_fullscreen_video.jpg -q 2>&1 | ansi_parser
195 sleep 5 && totem --quit 2>/dev/null196 sleep 5 && totem --quit 2>/dev/null
196 dbus-launch gsettings set org.gnome.totem repeat false197 dbus-launch gsettings set org.gnome.totem repeat false
197198
=== modified file 'jobs/input.txt.in'
--- jobs/input.txt.in 2013-02-22 16:26:25 +0000
+++ jobs/input.txt.in 2013-03-07 16:10:38 +0000
@@ -44,6 +44,7 @@
44plugin: user-interact44plugin: user-interact
45name: input/accelerometer45name: input/accelerometer
46user: root46user: root
47requires: module.name in ['hdaps', 'hp_accel']
47command: accelerometer_test -m48command: accelerometer_test -m
48_description:49_description:
49 PURPOSE:50 PURPOSE:
5051
=== modified file 'jobs/optical.txt.in'
--- jobs/optical.txt.in 2012-10-11 20:48:55 +0000
+++ jobs/optical.txt.in 2013-03-07 16:10:38 +0000
@@ -58,7 +58,7 @@
58 name: optical/cdrom-write_`ls /sys$path/block`58 name: optical/cdrom-write_`ls /sys$path/block`
59 requires: device.path == "$path"59 requires: device.path == "$path"
60 user: root60 user: root
61 command: optical_write_test /dev/`ls /sys$path/block` | ansi_parser61 command: set -o pipefail; optical_write_test /dev/`ls /sys$path/block` | ansi_parser
62 description:62 description:
63 PURPOSE:63 PURPOSE:
64 This test will check your system's $product CD writing capabilities. This test requires a blank CD-R or CD+R. If you do not have a blank disk, skip this test.64 This test will check your system's $product CD writing capabilities. This test requires a blank CD-R or CD+R. If you do not have a blank disk, skip this test.
@@ -80,7 +80,7 @@
80 name: optical/cdrom-write-automated_`ls /sys$path/block`80 name: optical/cdrom-write-automated_`ls /sys$path/block`
81 requires: device.path == "$path"81 requires: device.path == "$path"
82 user: root82 user: root
83 command: optical_write_test /dev/`ls /sys$path/block` | ansi_parser83 command: set -o pipefail; optical_write_test /dev/`ls /sys$path/block` | ansi_parser
84 description:84 description:
85 This is an automated version of optical/cdrom-write. It assumes you have already inserted a data CD into your optical drive prior to running Checkbox.85 This is an automated version of optical/cdrom-write. It assumes you have already inserted a data CD into your optical drive prior to running Checkbox.
86 EOF86 EOF
@@ -116,7 +116,7 @@
116 name: optical/dvd-write_`ls /sys$path/block`116 name: optical/dvd-write_`ls /sys$path/block`
117 requires: device.path == "$path"117 requires: device.path == "$path"
118 user: root118 user: root
119 command: optical_write_test /dev/`ls /sys$path/block` | ansi_parser119 command: set -o pipefail; optical_write_test /dev/`ls /sys$path/block` | ansi_parser
120 description:120 description:
121 PURPOSE:121 PURPOSE:
122 This test will check your system's $product writing capabilities. This test requires a blank DVD-R or DVD+R. If you do not have a blank DVD disk, skip this test.122 This test will check your system's $product writing capabilities. This test requires a blank DVD-R or DVD+R. If you do not have a blank DVD disk, skip this test.
@@ -140,7 +140,7 @@
140 name: optical/dvd-write-automated_`ls /sys$path/block`140 name: optical/dvd-write-automated_`ls /sys$path/block`
141 requires: device.path == "$path"141 requires: device.path == "$path"
142 user: root142 user: root
143 command: optical_write_test /dev/`ls /sys$path/block` | ansi_parser143 command: set -o pipefail; optical_write_test /dev/`ls /sys$path/block` | ansi_parser
144 description:144 description:
145 This is an automated version of optical/dvd-write. It assumes you have already inserted a data DVD into your optical drive prior to running Checkbox.145 This is an automated version of optical/dvd-write. It assumes you have already inserted a data DVD into your optical drive prior to running Checkbox.
146 EOF146 EOF
147147
=== modified file 'jobs/suspend.txt.in'
--- jobs/suspend.txt.in 2013-01-30 21:43:05 +0000
+++ jobs/suspend.txt.in 2013-03-07 16:10:38 +0000
@@ -790,7 +790,7 @@
790name: suspend/screenshot_after_suspend790name: suspend/screenshot_after_suspend
791depends: suspend/suspend_advanced_auto791depends: suspend/suspend_advanced_auto
792requires: package.name == 'fswebcam'792requires: package.name == 'fswebcam'
793command: camera_test still --device=/dev/external_webcam -f ${CHECKBOX_DATA}/screenshot_after_suspend.jpg -q 2>&1 | ansi_parser793command: set -o pipefail; camera_test still --device=/dev/external_webcam -f ${CHECKBOX_DATA}/screenshot_after_suspend.jpg -q 2>&1 | ansi_parser
794_description:794_description:
795 PURPOSE:795 PURPOSE:
796 Take a screengrab of the current screen after suspend (logged on Unity desktop)796 Take a screengrab of the current screen after suspend (logged on Unity desktop)
797797
=== added file 'plainbox/docs/changelog.rst'
--- plainbox/docs/changelog.rst 1970-01-01 00:00:00 +0000
+++ plainbox/docs/changelog.rst 2013-03-07 16:10:38 +0000
@@ -0,0 +1,32 @@
1ChangeLog
2=========
3
4.. note::
5 This changelog contains only a summary of changes. For a more accurate
6 accounting of development history please inspect the source history
7 directly.
8
9PlainBox 0.3 (Unreleased)
10^^^^^^^^^^^^^^^^^^^^^^^^^
11
12* Added support for all job types (manual, user-interact, user-verify, attachment, local)
13* Added support for running as another user
14* Added support for creating session checkpoints and resuming testing across reboots
15* Added support for exporting test results to JSON, plain text and XML
16* Added support for handling binary data (eg, binary attachments)
17* Added support for using sub-commands to the main plainbox executable
18* Added documentation to the project
19* Numerous internal re-factorings, changes and improvements.
20* Improved unit and integration testing coverage
21
22PlainBox 0.2
23^^^^^^^^^^^^
24
25* Last release made from the standalone github tree.
26* Added support for discovering dependencies and automatic dependency
27 resolution (for both job dependencies and resource dependencies)
28
29PlainBox 0.1
30^^^^^^^^^^^^
31
32* Initial release
033
=== added directory 'plainbox/docs/dev'
=== added file 'plainbox/docs/dev/architecture.rst'
--- plainbox/docs/dev/architecture.rst 1970-01-01 00:00:00 +0000
+++ plainbox/docs/dev/architecture.rst 2013-03-07 16:10:38 +0000
@@ -0,0 +1,337 @@
1PlainBox Architecture
2=====================
3
4This document explains the architecture of PlainBox internals. It should be
5always up-to-date and accurate to the extent of the scope of this overview.
6
7General design considerations
8^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
9
10PlainBox is a reimplementation of CheckBox that replaces a reactor / event /
11plugin architecture with a monolithic core and tightly integrated components.
12
13The implementation models a few of the externally-visible concepts such as
14jobs, resources and resource programs but also has some additional design that
15was not present in CheckBox before.
16
17The goal of the rewrite is to provide the right model and APIs for user
18interfaces in order to build the kind of end-user solution that we could not
19build with CheckBox.
20
21This is expressed by additional functionality that is there only to provide the
22higher layers with the right data (failure reason, descriptions, etc.). The
23code is also intended to be highly testable. Test coverage at the time of
24writing this document was exceeding 80%
25
26The core requirement for the current phase of PlainBox development is feature
27parity with CheckBox and gradual shift from one to another in the daily
28responsibilities of the Hardware Certification team. Currently PlainBox
29implements a large chunk of core / essential features from CheckBox. While not
30all features are present the core is considered almost feature complete at this
31stage.
32
33Application Skeleton
34^^^^^^^^^^^^^^^^^^^^
35
36This skeleton represents a typical application based on PlainBox. It enumerates
37the essential parts of the APIs from the point of view of an application
38developer.
39
401. Instantiate :class:`plainbox.impl.checkbox.CheckBox` then call
41 :meth:`plainbox.impl.checkbox.CheckBox.get_builtin_jobs()` to discover all
42 known jobs. In the future this might be replaced by a step that obtains jobs
43 from a named provider.
44
453. Instantiate :class:`plainbox.impl.runner.JobRunner` so that we can run jobs
46
474. Instantiate :class:`plainbox.impl.session.SessionState` so that we can keep
48 track of application state.
49
50 - Potentially restore an earlier, interrupted, testing session by calling
51 :meth:`plainbox.impl.session.SessionState.restore()`
52
53 - Potentially remove an earlier, interrupted, testing session by calling
54 :meth:`plainbox.impl.session.SessionState.discard()`
55
56 - Potentially start a new test session by calling
57 :meth:`plainbox.impl.session.SessionState.open()`
58
595. Allow the user to select jobs that should be executed and update session
60 state by calling
61 :meth:`plainbox.impl.session.SessionState.update_desired_job_list()`
62
636. For each job in :attr:`plainbox.impl.SessionState.run_list`:
64
65 1. Check if we want to run the job (if we have a result for it from previous
66 runs) or if we must run it (for jobs that cannot be persisted across
67 suspend)
68
69 2. Check if the job can be started by looking at
70 :meth:`plainbox.impl.session.JobState.can_start()`
71
72 - optionally query for additional data on why a job cannot be started and
73 present that to the user.
74
75 - optionally abort the sequence and go to step 5 or the outer loop.
76
77 3. Call :meth:`plainbox.impl.runner.JobRunner.run_job()` with the current
78 job and store the result.
79
80 - optionally ask the user to perform some manipulation
81
82 - optionally ask the user to qualify the outcome
83
84 - optionally ask the user for additional comments
85
86 4. Call :meth:`plainbox.impl.session.SessionState.update_job_result()` to
87 update readiness of jobs that depend on the outcome or output of current
88 job.
89
90 5. Call :meth:`plainbox.impl.session.SessionState.checkpoint()` to ensure
91 that testing can resume after system crash or shutdown.
92
937. Instantiate the selected state exporter, for example
94 :class:`plainbox.impl.exporters.json.JSONSessionStateExporter` so that we
95 can use it to save test results.
96
97 - optionally pass configuration options to customize the subset and the
98 presentation of the session state
99
1008. Call
101 :meth:`plainbox.impl.exporters.SessionStateExporterBase.get_session_data_subset()`
102 followed by :meth:`plainbox.impl.exporters.SessionStateExporterBase.dump()`
103 to save results to a file.
104
1059. Call :meth:`plainbox.impl.session.SessionState.close()` to remove any
106 nonvolatile temporary storage that was needed for the session.
107
108Essential classes
109=================
110
111:class:`~plainbox.impl.session.SessionState`
112^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
113
114Class representing all state needed during a single program session.
115
116Usage
117-----
118
119The general idea is that you feed the session with a list of known jobs and
120a subset of jobs that you want to run and in return get an ordered list of
121jobs to run.
122
123It is expected that the user will select / deselect and run jobs. This
124class can react to both actions by recomputing the dependency graph and
125updating the read states accordingly.
126
127As the user runs subsequent jobs the results of those jobs are exposed to
128the session with :meth:`update_job_result()`. This can cause subsequent
129jobs to become available (not inhibited by anything). Note that there is no
130notification of changes at this time.
131
132The session does almost nothing by itself, it learns about everything by
133observing job results coming from the job runner
134(:class:`plainbox.impl.runner.JobRunner`) that applications need to
135instantiate.
136
137Suspend and resume
138------------------
139
140The session can save check-point data after each job is executed. This
141allows the system to survive and continue after a catastrophic failure
142(broken suspend, power failure) or continue across tests that require the
143machine to reboot.
144
145.. todo::
146
147 Create a section on suspend/resume design
148
149Implementation notes
150--------------------
151
152Internally it ties into :class:`plainbox.impl.depmgr.DependencySolver` for
153resolving dependencies. The way the session objects are used allows them to
154return various problems back to the UI level - those are all the error
155classes from :mod:`plainbox.impl.depmgr`:
156
157 - :class:`plainbox.impl.depmgr.DependencyCycleError`
158
159 - :class:`plainbox.impl.depmgr.DependencyDuplicateError`
160
161 - :class:`plainbox.impl.depmgr.DependencyMissingError`
162
163Normally *none* of those errors should ever happen, they are only provided
164so that we don't choke when a problem really happens. Everything is checked
165and verified early before starting a job so typical unit and integration
166testing should capture broken job definitions (for example, with cyclic
167dependencies) being added to the repository.
168
169Implementation issues
170---------------------
171
172There are two issues that are known at this time:
173
174* There is too much checkbox-specific knowledge which really belongs
175 elsewhere. We are working to remove that so that non-checkbox jobs
176 can be introduced later. There is a branch in progress that entirely
177 removes that and moves it to a new concept called SessionController.
178 In that design the session delegates understanding of results to a
179 per-job session controller and exposes some APIs to alter the state
180 that was previously internal (most notably a way to add new jobs and
181 resources).
182
183* The way jobs are currently selected is unfortunate because of local jobs
184 that can add new jobs to the system. This causes considerable complexity
185 at the application level where the application must check if each
186 executed job is a 'local' job and re-compute the desired_job_list. This
187 should be replaced by a matcher function that can be passed to
188 SessionState once so that desired_job_list is re-evaluated internally
189 whenever job_list changes.
190
191
192:class:`~plainbox.impl.job.JobDefinition`
193^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
194
195:term:`CheckBox` has a concept of a :term:`job`. Jobs are named units of
196testing work that can be executed. Typical jobs range from automated CPU power
197management checks, BIOS tests, semi-automated peripherals testing to all manual
198validation by following a script (intended for humans).
199
200Jobs are distributed in plain text files, formated as a loose RFC822 documents
201where typically a single text file contains a few dozen different jobs that
202belong to one topic, for example, all bluetooth tests.
203
204Tests have a number of properties that will not be discussed in detail here,
205they are all documented in :class:`plainbox.impl.job.JobDefinition`. From the
206architecture point of view the four essential properties of a job are *name*,
207*plugin* and *requires* and *depends*. Those are discussed in detail below.
208
209JobDefinition.name
210------------------
211
212The *name* field must be unique and is referred to by other parts of the system
213(such as whitelists). Typically jobs follow a simple naming pattern
214'category/detail', eg, 'networking/modem_connection'. The name must be _unique_
215and this is enforced by the core.
216
217JobDefinition.plugin
218--------------------
219
220The *plugin* field is an archaism from CheckBox and a misnomer (as PlainBox
221does not have any plugins). In the CheckBox architecture it would instruct the
222core which plugin should process that job. In PlainBox it is a way to encode
223what type of a job is being processed. There is a finite set of types that are
224documented below.
225
226plugin == "shell"
227#################
228
229This value is used for fully automated jobs. Everything the job needs to do is
230automated (preparation, execution, verification) and fully handled by the
231command that is associated with a job.
232
233plugin == "manual"
234##################
235
236This value is used for fully manual jobs. It has no special handling in the core
237apart from requiring a human-provided outcome (pass/fail classification)
238
239plugin == "local"
240#################
241
242This value is used for special job generator jobs. The output of such jobs is
243interpreted as additional jobs and is identical in effect to loading such jobs
244from a job definition file.
245
246There are two practical uses for such jobs:
247
248* Some local jobs are used to generate a number of jobs for each object.
249 This is needed where the tested machine may have a number of such objects
250 and each requires unique testing. A good example is a computer where all
251 network tests are explicitly "instantiated" for each network card
252 present.
253
254 This is a valid use case but is rather unfortunate for architecture of
255 PlainBox and there is a desire to replace it with equally-expressive
256 pattern jobs. The advantage is that unlike local jobs (which cannot be
257 "discovered" without enduring any potential side effects that may be
258 caused by the job script command) pattern jobs would allow the core to
259 determine the names of jobs that can be generated and, for example,
260 automatically determine that a pattern job needs to be executed as a
261 dependency of a phantom (yet undetermined) job with a given name.
262
263 The solution with "pattern" jobs may be executed in future phases of
264 PlainBox development. Currently there is no support for that at all.
265
266 Currently PlainBox cannot determine job dependencies across local jobs.
267 That is, unless a local job is explicitly requested (in the desired job
268 list) PlainBox will not be able to run a job that is generated by a local
269 job at all and will treat it as if that job never existed.
270
271* Some local jobs are used to create a form of informal "category".
272 Typically all such jobs have a leading and trailing double underscore,
273 for example '__audio__'. This is currently being used by CheckBox for
274 building a hierarchical tree of tests that the user may select.
275
276 Since this has the same flaws as described above (for pattern jobs) it
277 will likely be replaced by an explicit category field that can be
278 specified each job.
279
280plugin == "resource"
281####################
282
283This value is used for special "data" or "environment" jobs. Their output is
284parsed as a list of RFC822 records and is kept by the core during a testing session.
285
286They are primarily used to determine if a given job can be started. For
287example, a particular bluetooth test may use the _requires_ field to indicate
288that it depends (via a resource dependency) on a job that enumerates devices
289and that one of those devices must be a bluetooth device.
290
291plugin == "user-interact"
292#########################
293
294For all intents and purposes it is equivalent to "manual". The actual
295difference is that a user is expected to perform some physical manipulation
296before an automated test.
297
298plugin == "user-verify"
299#######################
300
301For all intents and purposes it is equivalent to "manual". The actual
302difference is that a user is expected to perform manual verification after an
303automated test.
304
305JobDefinition.depends
306---------------------
307
308The *depends* field is used to express dependencies between two jobs. If job A
309has depends on job B then A cannot start if B is not both finished and
310successful. PlainBox understands this dependency and can automatically sort and
311execute jobs in proper order. In many places of the code this is referred to as
312a "direct dependency" (in contrast to "resource dependency")
313
314The actual syntax is not strictly specified, PlainBox interprets this field as
315a list of tokens delimited by comma or any whitespace (including newlines).
316
317A job may depend on any number of other jobs. There are a number of failure
318modes associated with this feature, all of which are detected and handled by
319PlainBox. Typically they only arise when during CheckBox job development
320(editing actual job files) and are always a sign of a human error. No released
321version of CheckBox or PlainBox should ever encounter any of those issues.
322
323The actual problems are:
324
325* dependency cycles, where job either directly or indirectly depends on
326 itself
327
328* missing dependencies where some job refers to a job that is not defined
329 anywhere.
330
331* duplicate jobs where two jobs with the same name (but different
332 definition) are being introduced to the system.
333
334In all of those cases the core removes the offending job and tries to work
335regardless of the problem. This is intended more as a development aid rather
336than a reliability feature as no released versions of either project should
337cause this problem.
0338
=== added file 'plainbox/docs/dev/index.rst'
--- plainbox/docs/dev/index.rst 1970-01-01 00:00:00 +0000
+++ plainbox/docs/dev/index.rst 2013-03-07 16:10:38 +0000
@@ -0,0 +1,14 @@
1Developers
2==========
3
4The PlainBox project hopes to be a friendly developer environment. We invested
5in a lot of tools to make your life easier. Despite being a business-centric
6software project we welcome and encourage contributions from both Canonical and
7Community members.
8
9.. toctree::
10 :maxdepth: 3
11
12 intro.rst
13 architecture.rst
14 reference.rst
015
=== added file 'plainbox/docs/dev/intro.rst'
--- plainbox/docs/dev/intro.rst 1970-01-01 00:00:00 +0000
+++ plainbox/docs/dev/intro.rst 2013-03-07 16:10:38 +0000
@@ -0,0 +1,238 @@
1Getting started with development
2^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
3
4PlainBox uses python3 for development. The core is really system independent
5but you will need Ubuntu to really make the best of it and experience it as we
6do. We encourage everyone to use the most recent Ubuntu release for
7development. Usually this brings the best, most recent tools without having to
8search for software on the Internet.
9
10PlainBox has almost no dependencies itself, almost, because we depend on the
11mighty :term:`CheckBox` project to provide us with a lot of existing
12infrastructure. Testing PlainBox requires additional packages and some
13non-packaged software. You will typically want to install it and take advantage
14of the integration we provide.
15
16.. note::
17
18 If you are working with the source please be aware that PlainBox requires
19 an installed copy of CheckBox. CheckBox in turns is has many scripts that
20 depend on various system packages, including python packages that cannot be
21 installed from pypi. If you were planning on using :command:`virtualenv`
22 then please make sure to create it with the ``--system-site-packages``
23 option.
24
25Get the tools
26-------------
27
28First, you need to install the basic development tools:
29
30.. code-block:: bash
31
32 $ sudo apt-get install bzr python3-setuptools python3-dev python3-doc python3-sphinx python-virtualenv
33
34While developing PlainBox you will often need to run potentially dangerous
35commands on your system, such as asking it to suspend and wake up
36automatically. We also need to support a range of Ubuntu releases, going all
37the way back to Ubuntu 12.04. This may cause compatibility issues that are
38unnoticed all until they hit our CI system. To minimize this PlainBox uses
39:term:`Vagrant` to create lightweight execution environments that transparently
40share your source tree and allow you to quickly create and share testing
41environment that can be deployed by any developer in minutes. Vagrant uses
42:term:`VirtualBox` and while both are packaged in Ubuntu, unless you are
43running Ubuntu 13.04 you should download and install the software from their
44upstream projects.
45
46If you are running Ubuntu 13.04
47
48.. code-block:: bash
49
50 $ sudo apt-get install vagrant
51
52If you are running earlier version of Ubuntu follow those two links to get started:
53
54 * http://downloads.vagrantup.com/
55 * https://www.virtualbox.org/wiki/Downloads
56
57If you have not installed VirtualBox before, you must add yourself to the
58``vboxusers`` group, log out and log back in again.
59
60.. code-block:: bash
61
62 $ sudo usermod -G vboxusers -a $USER
63
64Get the source
65--------------
66
67Now that you have all the tools, you can get the source:
68
69.. code-block:: bash
70
71 $ bzr branch lp:checkbox
72
73.. note::
74 If you would rather use ``git`` you can also do that (and in fact, some of
75 us already do). Head to `git-lp homepage <http://zyga.github.com/git-lp/>`_
76 and follow the guide there to use git-lp with this project.
77
78Initialize virtualenv
79---------------------
80
81PlainBox will use a few unpackaged and bleeding-edge releases from :term:`pypi`
82those are installed by additional script. By default the script assumes you
83have a /ramdisk directory but you can pass any path as an argument for an
84alternate location.
85
86.. code-block:: bash
87
88 $ ./mk-venv.sh
89
90After everything is set up you can activate the virtualenv environment with the
91dot command. Note that there *is* a space between the dot and the forward
92slash. You can repeat this command in as many shells as you like.
93
94.. code-block:: bash
95
96 $ . /ramdisk/venv/bin/activate
97
98Once virtualenv is activated your shell prompt will be changed to reflect that.
99You should now be able to run :command:`plainbox --help` to ensure everything
100is working properly.
101
102Initialize vagrant
103------------------
104
105Vagrant allows us to ship a tiny text file :file:`Vagrantfile` that describes
106the development and testing environment. This file tells :command:`vagrant` how
107to prepare a virtual machine for testing. If you never used it before you may
108want to keep a tab open on `vagrant getting started guide
109<http:`http://docs.vagrantup.com/v1/docs/getting-started/index.html>`_
110
111We did all the hard work so that you don't have to, to get everything ready
112just run one command:
113
114.. code-block:: bash
115
116 $ vagrant up
117
118This will download vanilla Ubuntu cloud images, initialize VirtualBox,
119provision virtual machines (one for each supported Ubuntu release) and allow
120you to ssh into them for testing with one command.
121
122This will take a moment, depending on the speed of your network. Once that is
123done you should be able to log into, say, ``precise`` and run
124:command:`plainbox --help` to see if everything is all right.
125
126.. code-block:: bash
127
128 $ vagrant ssh precise
129 vagrant@vagrant-ubuntu-precise-32:~$ plainbox --help
130 usage: plainbox [-h] [-v] {run,special,self-test} ...
131
132 positional arguments:
133 {run,special,self-test}
134 run run a test job
135 special special/internal commands
136 self-test run integration tests
137
138 optional arguments:
139 -h, --help show this help message and exit
140 -v, --version show program's version number and exit
141 $ exit
142
143Running PlainBox tests
144^^^^^^^^^^^^^^^^^^^^^^
145
146PlainBox is designed to be testable so it would be silly if it was hard to run
147tests. Actually, there are many different ways to run tests. They all run the
148same code so don't worry.
149
150To test the current code you are working on you can:
151
152- Run the :command:`./test-in-vagrant.sh` from the plainbox directory. This
153 will take the longes but will go over *all* the tests on *all* the supported
154 versions of Ubuntu. It will run CheckBox unit-tests, PlainBox unit-tests and
155 it will even run integration tests that actually execute jobs.
156
157- Run :command:`plainbox self-test --unit-tests` or
158 :command:`plainbox self-test --integration-tests`. This will execute all the
159 tests right on your machine, without any virtualization (well, unless you do
160 that after running :command:`vagrant ssh`). Typically you would run unit
161 tests while being in a ``virtualenv`` with the ``plainbox`` package in
162 development mode, as created by running :command:`python setup.py develop`
163
164- Run :command:`./setup.py test` this will install any required test
165 dependencies from pypi and run unit tests.
166
167- Run the script :command:`test-with-coverage.sh` while being in a virtualenv.
168 This will also compute testing code coverage and is very much recommended
169 while working on new code and tests.
170
171Submitting Patches
172^^^^^^^^^^^^^^^^^^
173
174We use `Launchpad <https://launchpad.net>`_ for most of our project management.
175All code changes should be submitted as merge requests. Launchpad has
176`extensive documentation <https://help.launchpad.net/>`_ on how to use various
177facilities it provides.
178
179In general we are open to contributions but we reserve the right to reject
180patches if they don't fit into the needs of the :term:`Hardware Certification`.
181If you have an idea go and talk to us on :abbr:`IRC (Internet Relay Chat)` on
182the `#ubuntu-quality <irc://freenode.net:8001/#ubuntu-quality>`_ channel.
183
184We have some basic rules patch acceptance:
185
1860. Be prepare to alter your changes.
187
188 This is a meta-rule. One of the points of code reviews is to improve the
189 proposal. That implies the proposal may need to change. You must be prepared
190 and able to change your code after getting feedback.
191
192 To do that efficiently you must structure your work in a way where each
193 committed change works for you rather than against you. The rules listed
194 below are a reflection of this.
195
1961. Each patch should be a single logical change that can be applied.
197
198 Don't clump lots of changes into one big patch. That will only delay review,
199 make accepting feedback difficult and annoying. This may mean that the history
200 has many small patches that can land in trunk in a FIFO mode. The oldest patch
201 of your branch may be allowed to land and should make sense. This has
202 implications on how general code editing should be performed. If you break some
203 APIs then firsts introduce a working replacement, then change usage of the API
204 and lastly remove any dead code.
205
2062. Don't keep junk patches in your branch.
207
208 Don't keep patches such as "fix typo" in your branch, that makes the review
209 process more difficult as some reviewers will read your patches one by one.
210 This is especially important if your changes are substantial.
211
2123. Don't merge with trunk, rebase on trunk.
213
214 This way you can keep your local delta as a collection of meaningful,
215 readable patches. Reading the full diff and following the complex merge
216 history (especially for long-lived branches) is difficult in practice.
217
2184. Keep unrelated changes in separate branches.
219
220 If you ware working on something and found a bug that needed immediate
221 fixing, typo or anything else that is small and quick to fix, do it. Then
222 take that patch out of your development branch and into a dedicated branch
223 and propose it. As the small change is reviewed and lands you can remove
224 that patch from your development branch.
225
226 This is intended to help both the developer and the reviewer. Seemingly
227 trivial patches may turn out to be more complicated than initially assumed
228 (and may have their own feedback cycle and iterations). The reviewer can
229 focus on logical changes and not on a collection of unrelated alterations.
230 Lastly we may need to apply some fixes to other supported branches and
231 release those.
232
2335. Don't propose untested code.
234
235 We generally like tests for new code. This is not a super-strict requirement
236 but unless writing tests is incredibly hard we'd rather wait. If testing is
237 hard we'd rather invest some time in refactoring the code or building
238 required support infrastructure.
0239
=== added file 'plainbox/docs/dev/reference.rst'
--- plainbox/docs/dev/reference.rst 1970-01-01 00:00:00 +0000
+++ plainbox/docs/dev/reference.rst 2013-03-07 16:10:38 +0000
@@ -0,0 +1,154 @@
1.. _code_reference:
2
3.. toctree::
4 :maxdepth: 2
5
6Code reference
7==============
8
9.. note::
10
11 Unless stated otherwise all API is unstable. PlainBox does not offer
12 general API stability at this time.
13
14.. automodule:: plainbox
15 :members:
16 :undoc-members:
17 :show-inheritance:
18
19.. automodule:: plainbox.public
20 :members:
21 :undoc-members:
22 :show-inheritance:
23
24.. automodule:: plainbox.abc
25 :members:
26 :undoc-members:
27 :show-inheritance:
28
29.. automodule:: plainbox.tests
30 :members:
31 :undoc-members:
32 :show-inheritance:
33
34.. automodule:: plainbox.testing_utils
35 :members:
36 :undoc-members:
37 :show-inheritance:
38
39.. automodule:: plainbox.testing_utils.cwd
40 :members:
41 :undoc-members:
42 :show-inheritance:
43
44.. automodule:: plainbox.testing_utils.io
45 :members:
46 :undoc-members:
47 :show-inheritance:
48
49.. automodule:: plainbox.testing_utils.testcases
50 :members:
51 :undoc-members:
52 :show-inheritance:
53
54.. automodule:: plainbox.vendor
55 :members:
56
57.. automodule:: plainbox.vendor.extcmd
58 :members:
59 :undoc-members:
60 :show-inheritance:
61
62.. automodule:: plainbox.impl
63 :members:
64 :undoc-members:
65 :show-inheritance:
66
67.. automodule:: plainbox.impl.commands
68 :members:
69 :undoc-members:
70 :show-inheritance:
71
72.. automodule:: plainbox.impl.commands.selftest
73 :members:
74 :undoc-members:
75 :show-inheritance:
76
77.. automodule:: plainbox.impl.exporter
78 :members:
79 :undoc-members:
80 :show-inheritance:
81
82.. automodule:: plainbox.impl.exporter.json
83 :members:
84 :undoc-members:
85 :show-inheritance:
86
87.. automodule:: plainbox.impl.exporter.rfc822
88 :members:
89 :undoc-members:
90 :show-inheritance:
91
92.. automodule:: plainbox.impl.exporter.text
93 :members:
94 :undoc-members:
95 :show-inheritance:
96
97.. automodule:: plainbox.impl.box
98 :members:
99 :undoc-members:
100 :show-inheritance:
101
102.. automodule:: plainbox.impl.checkbox
103 :members:
104 :undoc-members:
105 :show-inheritance:
106
107.. automodule:: plainbox.impl.depmgr
108 :members:
109 :undoc-members:
110 :show-inheritance:
111
112.. automodule:: plainbox.impl.integration_tests
113 :members:
114 :undoc-members:
115 :show-inheritance:
116
117.. automodule:: plainbox.impl.job
118 :members:
119 :undoc-members:
120 :show-inheritance:
121
122.. automodule:: plainbox.impl.mock_job
123 :members:
124 :undoc-members:
125 :show-inheritance:
126
127.. automodule:: plainbox.impl.resource
128 :members:
129 :undoc-members:
130 :show-inheritance:
131
132.. automodule:: plainbox.impl.result
133 :members:
134 :undoc-members:
135 :show-inheritance:
136
137.. automodule:: plainbox.impl.rfc822
138 :members:
139 :show-inheritance:
140
141.. automodule:: plainbox.impl.runner
142 :members:
143 :undoc-members:
144 :show-inheritance:
145
146.. automodule:: plainbox.impl.session
147 :members:
148 :undoc-members:
149 :show-inheritance:
150
151.. automodule:: plainbox.impl.testing_utils
152 :members:
153 :undoc-members:
154 :show-inheritance:
0155
=== added file 'plainbox/docs/glossary.rst'
--- plainbox/docs/glossary.rst 1970-01-01 00:00:00 +0000
+++ plainbox/docs/glossary.rst 2013-03-07 16:10:38 +0000
@@ -0,0 +1,104 @@
1Glossary
2========
3
4.. glossary::
5
6 hardware certification
7
8 A process of ensuring that a specific device works well with Ubuntu.
9 For more details see our certification program:
10
11 http://www.canonical.com/engineering-services/certification/hardware-certification
12
13 hardware certification team
14
15 A team inside Canonical working on :term:`Hardware Certification`.
16
17 CheckBox
18
19 CheckBox is a hardware testing tool developed by Canonical for
20 certifying hardware with Ubuntu. CheckBox is free software and is
21 available at http://launchpad.net/checkbox. The ``checkbox`` package is
22 pre-installed on all Ubuntu systems
23
24 PlainBox
25
26 PlainBox is a rewrite of CheckBox with the aim of improving internal
27 architecture, testability, robustness, quality and speed. It is
28 currently under active development. It is not pre-installed on Ubuntu.
29 It is developed inside CheckBox code repository.
30
31 white list
32
33 White lists are text files used by CheckBox to select Jobs for
34 execution. They can include simple regular expressions to match and
35 pick many similar jobs at once.
36
37 job
38
39 Jobs are smallest units of testing that can be performed by either
40 CheckBox or PlainBox. All jobs have an unique name. There are many
41 types of jobs, some are fully automated others are fully manual. Some
42 jobs are only an implementation detail and a part of the internal
43 architecture of CheckBox
44
45 resources
46
47 Resources are collections of key-value data sets that are generated by
48 special resource jobs. They are extensively used to indicate hardware
49 or software dependencies. For example a bluetooth test may indicate it
50 requires bluetooth hardware and appropriate software packages
51 installed.
52
53 requirement program
54
55 Requirement programs are small (one to few lines) programs that use a
56 subset of python to execute some code against resources. They are what
57 actually describes the relationship of a Job to some Resources. For
58 example a resource program ``package.name == "bluez"`` indicates that
59 at least one resource generated by the ``package`` job has a key
60 ``name`` equal to the string ``bluez``.
61
62 attachment
63
64 Attachments are a special type of a Job that can creates an attachment
65 record in the submission.xml file. They are commonly used to include
66 basic system information files and output of certain commands which can
67 aid in system certification.
68
69 certification website
70
71 The website https://certification.canonical.com/
72
73 Canonical ID
74
75 A number assigned to the specific device (laptop, desktop or server) by
76 Canonical. This number is used on the Certification Website and by the
77 Hardware Certification Team. It is an internal bookkeeping identifier
78 used in our labs.
79
80 Secure ID
81
82 An identifier, similar to Canonical ID, used for hardware
83 certification. This identifier is used when interacting with the
84 Certification Website, it does not reveal anything about the actual
85 hardware (like the manufacturer name or device name)
86
87 pypi
88
89 The Python Package Index where any developer can share their python
90 programs and libraries. Pypi is available at:
91 https://pypi.python.org/pypi.
92
93 Vagrant
94
95 Vagrant is command line program intended for software developers to
96 quickly create portable virtual environments for testing their software
97 in a production operating system. Vagrant is free software and is
98 available at http://www.vagrantup.com/
99
100 VirtualBox
101
102 VirtualBox is a free, powerful desktop vitalization software.
103 VirtualBox is available in the Ubuntu Software Center and at
104 https://www.virtualbox.org/
0105
=== modified file 'plainbox/docs/index.rst'
--- plainbox/docs/index.rst 2013-02-22 16:26:25 +0000
+++ plainbox/docs/index.rst 2013-03-07 16:10:38 +0000
@@ -3,15 +3,56 @@
3 You can adapt this file completely to your liking, but it should at least3 You can adapt this file completely to your liking, but it should at least
4 contain the root `toctree` directive.4 contain the root `toctree` directive.
55
6Welcome to PlainBox's documentation!6PlainBox
7====================================7========
88
9Contents:9:term:`PlainBox` is a hardware testing tool useful for certifying laptops,
10desktops and servers with Ubuntu. It is a replacement for the current
11certification tool, :term:`CheckBox`.
12
13PlainBox *complements* CheckBox. It uses all the hardware test definitions,
14scripts and libraries from CheckBox. PlainBox is currently in **alpha** stages,
15having mostly but not entirely complete core and a developer-centric command
16line interface.
17
18Installation
19^^^^^^^^^^^^
20
21PlainBox can be installed from a :abbr:`PPA (Personal Package Archive)`
22(recommended) or :abbr:`pypi (python package index)` on Ubuntu Precise (12.04)
23or newer.
24
25.. code-block:: bash
26
27 $ sudo add-apt-repository ppa:checkbox-dev/ppa && sudo apt-get update && sudo apt-get install plainbox
28
29
30Testing your hardware
31^^^^^^^^^^^^^^^^^^^^^
32
33To test your hardware with the default set of tests run this command.
34
35.. code-block:: bash
36
37 $ plainbox run --whitelist=default --output-format=xml --output-file=submission.xml
38
39The :file:`submission.xml` you get in the end can be submitted to the
40:term:`certification website`. For more details see :ref:`usage`
41
42.. todo::
43 This example is bad because it is fake. We should improve the core so that
44 a whitelist can referred to by name alone (not by a full path).
45
46Table of contents
47=================
1048
11.. toctree::49.. toctree::
12 :maxdepth: 250 :maxdepth: 2
1351
1452 usage.rst
53 dev/index.rst
54 glossary.rst
55 changelog.rst
1556
16Indices and tables57Indices and tables
17==================58==================
@@ -19,4 +60,3 @@
19* :ref:`genindex`60* :ref:`genindex`
20* :ref:`modindex`61* :ref:`modindex`
21* :ref:`search`62* :ref:`search`
22
2363
=== added file 'plainbox/docs/usage.rst'
--- plainbox/docs/usage.rst 1970-01-01 00:00:00 +0000
+++ plainbox/docs/usage.rst 2013-03-07 16:10:38 +0000
@@ -0,0 +1,69 @@
1.. _usage:
2
3Usage
4=====
5
6Currently :term:`PlainBox` has no graphical user interface. To use it you need
7to use the command line.
8
9Basically there is just one command that does everything we can do so far, that
10is :command:`plainbox run`. It has a number of options that tell it which
11:term:`job` to run and what to do with results.
12
13PlainBox has built-in help system so running :command:`plainbox run --help`
14will give you instant information about all the various arguments and options
15that are available. This document is not intended to replace that.
16
17Running a specific job
18^^^^^^^^^^^^^^^^^^^^^^
19
20To run a specific :term:`job` pass it to the ``--include-pattern`` or ``-i``
21option.
22
23For example, to run the ``cpu/scaling_test`` job:
24
25.. code-block:: bash
26
27 $ plainbox run -i cpu/scaling_test
28
29.. note::
30
31 The option ``-i`` can be provided any number of times.
32
33Running jobs related to a specific area
34^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
35
36PlainBox has no concept of job categories but you can simulate that by
37running all jobs that follow a specific naming pattern. For example, to run
38all of the USB tests you can run the following command:
39
40.. code-block:: bash
41
42 $ plainbox run -i 'usb/'
43
44Running a white list
45^^^^^^^^^^^^^^^^^^^^
46
47To run a :term:`white list` pass the ``--whitelist`` or ``-w`` option.
48
49For example, to run the default white list run:
50
51.. code-block:: bash
52
53 $ plainbox run -w default
54
55Saving test results as XML
56^^^^^^^^^^^^^^^^^^^^^^^^^^
57
58To send test results to the :term:`certification website` you need to pass two
59additional options:
60
611. ``--output-format=xml``
622. ``--output-file=NAME`` where *NAME* is a file name
63
64For example, to get the default certification tests ready to be submitted
65run this command:
66
67.. code-block:: bash
68
69 $ plainbox run -w default -f xml -o submission.xml
070
=== modified file 'plainbox/plainbox/__init__.py'
--- plainbox/plainbox/__init__.py 2012-11-29 00:59:03 +0000
+++ plainbox/plainbox/__init__.py 2013-03-07 16:10:38 +0000
@@ -18,13 +18,13 @@
18# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.18# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
1919
20"""20"""
21plainbox21:mod:`plainbox` -- main package
22========22===============================
2323
24Simple checkbox redesign, without the complex message passing24Simple checkbox redesign, without the complex message passing
2525
26All public API is in the 'public' module.26All public API is in :mod:`plainbox.public`.
27All abstract base classes are in the 'abc' module.27All abstract base classes are in :mod:`plainbox.abc`.
28"""28"""
2929
30import sys30import sys
3131
=== modified file 'plainbox/plainbox/abc.py'
--- plainbox/plainbox/abc.py 2012-11-29 18:40:46 +0000
+++ plainbox/plainbox/abc.py 2013-03-07 16:10:38 +0000
@@ -18,10 +18,8 @@
18# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.18# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
1919
20"""20"""
21plainbox.abc21:mod:`plainbox.abc` -- abstract base classes
22============22============================================
23
24Abstract base classes used by plainbox
2523
26Those classes are actually implemented in the plainbox.impl package. This24Those classes are actually implemented in the plainbox.impl package. This
27module is here so that the essential API concepts are in a single spot and are25module is here so that the essential API concepts are in a single spot and are
2826
=== modified file 'plainbox/plainbox/impl/__init__.py'
--- plainbox/plainbox/impl/__init__.py 2012-11-19 10:45:46 +0000
+++ plainbox/plainbox/impl/__init__.py 2013-03-07 16:10:38 +0000
@@ -18,10 +18,12 @@
18# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.18# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
1919
20"""20"""
21plainbox.impl21:mod:`plainbox.impl` -- implementation package
22=============22==============================================
2323
24 * THIS MODULE DOES NOT HAVE STABLE PUBLIC API *24.. warning::
25
26 THIS MODULE DOES NOT HAVE STABLE PUBLIC API
25"""27"""
2628
27from functools import wraps29from functools import wraps
2830
=== modified file 'plainbox/plainbox/impl/box.py'
--- plainbox/plainbox/impl/box.py 2013-02-22 16:26:25 +0000
+++ plainbox/plainbox/impl/box.py 2013-03-07 16:10:38 +0000
@@ -18,12 +18,12 @@
18# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.18# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
1919
20"""20"""
21plainbox.impl.box21:mod:`plainbox.impl.box` -- command line interface
22=================22==================================================
2323
24Internal implementation of plainbox24.. warning::
2525
26 * THIS MODULE DOES NOT HAVE STABLE PUBLIC API *26 THIS MODULE DOES NOT HAVE STABLE PUBLIC API
27"""27"""
2828
29from argparse import ArgumentParser29from argparse import ArgumentParser
@@ -34,6 +34,7 @@
34from logging import getLogger34from logging import getLogger
35from os.path import join35from os.path import join
36import argparse36import argparse
37import re
37import sys38import sys
3839
39from plainbox import __version__ as version40from plainbox import __version__ as version
@@ -71,10 +72,16 @@
71 group.add_argument(72 group.add_argument(
72 '-i', '--include-pattern', action="append",73 '-i', '--include-pattern', action="append",
73 metavar='PATTERN', default=[], dest='include_pattern_list',74 metavar='PATTERN', default=[], dest='include_pattern_list',
74 help="Run jobs matching the given pattern")75 help=("Run jobs matching the given regular expression. Matches "
76 "from the start to the end of the line."))
77 group.add_argument(
78 '-x', '--exclude-pattern', action="append",
79 metavar="PATTERN", default=[], dest='exclude_pattern_list',
80 help=("Do not run jobs matching the given regular expression. "
81 "Matches from the start to the end of the line."))
75 # TODO: Find a way to handle the encoding of the file82 # TODO: Find a way to handle the encoding of the file
76 group.add_argument(83 group.add_argument(
77 '-W', '--whitelist',84 '-w', '--whitelist',
78 metavar="WHITELIST",85 metavar="WHITELIST",
79 type=FileType("rt"),86 type=FileType("rt"),
80 help="Load whitelist containing run patterns")87 help="Load whitelist containing run patterns")
@@ -88,18 +95,36 @@
88 def _get_matching_job_list(self, ns, job_list):95 def _get_matching_job_list(self, ns, job_list):
89 # Find jobs that matched patterns96 # Find jobs that matched patterns
90 matching_job_list = []97 matching_job_list = []
98 # Pre-seed the include pattern list with data read from
99 # the whitelist file.
91 if ns.whitelist:100 if ns.whitelist:
92 ns.include_pattern_list.extend([pattern.strip() for pattern in101 ns.include_pattern_list.extend([
93 ns.whitelist.readlines()])102 pattern.strip()
103 for pattern in ns.whitelist.readlines()])
104 # Decide which of the known jobs to include
94 for job in job_list:105 for job in job_list:
95 for pattern in ns.include_pattern_list:106 # Reject all jobs that match any of the exclude
96 if fnmatch(job.name, pattern):107 # patterns, matching strictly from the start to
97 matching_job_list.append(job)108 # the end of the line.
109 for pattern in ns.exclude_pattern_list:
110 if re.match(r"^{pattern}$".format(pattern=pattern), job.name):
98 break111 break
112 else:
113 # Then accept (include) all job that matches
114 # any of include patterns, matching strictly
115 # from the start to the end of the line.
116 for pattern in ns.include_pattern_list:
117 if re.match(r"^{pattern}$".format(pattern=pattern),
118 job.name):
119 matching_job_list.append(job)
120 break
99 return matching_job_list121 return matching_job_list
100122
101123
102class SpecialCommand(PlainBoxCommand, CheckBoxCommandMixIn):124class SpecialCommand(PlainBoxCommand, CheckBoxCommandMixIn):
125 """
126 Implementation of ``$ plainbox special``
127 """
103128
104 def invoked(self, ns):129 def invoked(self, ns):
105 job_list = self.get_job_list(ns)130 job_list = self.get_job_list(ns)
@@ -261,6 +286,17 @@
261 raise SystemExit(str(exc))286 raise SystemExit(str(exc))
262 return exporter287 return exporter
263288
289 def ask_for_resume(self, prompt=None, allowed=None):
290 # FIXME: Add support/callbacks for a GUI
291 if prompt is None:
292 prompt = "Do you want to resume the previous session [Y/n]? "
293 if allowed is None:
294 allowed = ('', 'y', 'Y', 'n', 'N')
295 answer = None
296 while answer not in allowed:
297 answer = input(prompt)
298 return False if answer in ('n', 'N') else True
299
264 def _run_jobs(self, ns, job_list, exporter):300 def _run_jobs(self, ns, job_list, exporter):
265 # Compute the run list, this can give us notification about problems in301 # Compute the run list, this can give us notification about problems in
266 # the selected jobs. Currently we just display each problem302 # the selected jobs. Currently we just display each problem
@@ -268,8 +304,13 @@
268 print("[ Analyzing Jobs ]".center(80, '='))304 print("[ Analyzing Jobs ]".center(80, '='))
269 # Create a session that handles most of the stuff needed to run jobs305 # Create a session that handles most of the stuff needed to run jobs
270 session = SessionState(job_list)306 session = SessionState(job_list)
271 self._update_desired_job_list(session, matching_job_list)
272 with session.open():307 with session.open():
308 if session.previous_session_file():
309 if self.ask_for_resume():
310 session.resume()
311 else:
312 session.clean()
313 self._update_desired_job_list(session, matching_job_list)
273 if (sys.stdin.isatty() and sys.stdout.isatty() and not314 if (sys.stdin.isatty() and sys.stdout.isatty() and not
274 ns.not_interactive):315 ns.not_interactive):
275 outcome_callback = self.ask_for_outcome316 outcome_callback = self.ask_for_outcome
276317
=== modified file 'plainbox/plainbox/impl/checkbox.py'
--- plainbox/plainbox/impl/checkbox.py 2013-02-22 16:26:25 +0000
+++ plainbox/plainbox/impl/checkbox.py 2013-03-07 16:10:38 +0000
@@ -18,12 +18,12 @@
18# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.18# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
1919
20"""20"""
21plainbox.impl.checkbox21:mod:`plainbox.impl.checkbox` -- CheckBox integration
22======================22=====================================================
2323
24Internal implementation of plainbox24.. warning::
2525
26 * THIS MODULE DOES NOT HAVE STABLE PUBLIC API *26 THIS MODULE DOES NOT HAVE STABLE PUBLIC API
27"""27"""
2828
29import io29import io
@@ -102,7 +102,7 @@
102 """102 """
103 Return the required value of CHECKBOX_SHARE environment variable.103 Return the required value of CHECKBOX_SHARE environment variable.
104104
105 ..note::105 .. note::
106 This variable is only required by one script.106 This variable is only required by one script.
107 It would be nice to remove this later on.107 It would be nice to remove this later on.
108 """108 """
@@ -119,7 +119,7 @@
119 This entry is required for CheckBox scripts to import the correct119 This entry is required for CheckBox scripts to import the correct
120 CheckBox python libraries.120 CheckBox python libraries.
121121
122 ..note::122 .. note::
123 The result may be None123 The result may be None
124 """124 """
125 # NOTE: When CheckBox is installed then all the scripts should not use125 # NOTE: When CheckBox is installed then all the scripts should not use
@@ -159,7 +159,7 @@
159 """159 """
160 Return an absolute path of the scripts directory160 Return an absolute path of the scripts directory
161161
162 ..note::162 .. note::
163 The scripts may not work without setting PYTHONPATH and163 The scripts may not work without setting PYTHONPATH and
164 CHECKBOX_SHARE.164 CHECKBOX_SHARE.
165 """165 """
166166
=== modified file 'plainbox/plainbox/impl/commands/__init__.py'
--- plainbox/plainbox/impl/commands/__init__.py 2013-01-30 21:43:05 +0000
+++ plainbox/plainbox/impl/commands/__init__.py 2013-03-07 16:10:38 +0000
@@ -18,12 +18,12 @@
18# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.18# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
1919
20"""20"""
21plainbox.impl.commands21:mod:`plainbox.impl.commands` -- shared code for plainbox sub-commands
22======================22======================================================================
2323
24Internal implementation of plainbox24.. warning::
2525
26 * THIS MODULE DOES NOT HAVE STABLE PUBLIC API *26 THIS MODULE DOES NOT HAVE STABLE PUBLIC API
27"""27"""
2828
29from abc import abstractmethod, ABCMeta29from abc import abstractmethod, ABCMeta
3030
=== modified file 'plainbox/plainbox/impl/commands/selftest.py'
--- plainbox/plainbox/impl/commands/selftest.py 2013-02-08 17:02:12 +0000
+++ plainbox/plainbox/impl/commands/selftest.py 2013-03-07 16:10:38 +0000
@@ -19,12 +19,12 @@
19# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.19# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
2020
21"""21"""
22plainbox.impl.commands.selftest22:mod:`plainbox.impl.commands.selftest` -- selftest sub-command
23===============================23==============================================================
2424
25Internal implementation of plainbox25.. warning::
2626
27 * THIS MODULE DOES NOT HAVE STABLE PUBLIC API *27 THIS MODULE DOES NOT HAVE STABLE PUBLIC API
28"""28"""
29from unittest.runner import TextTestRunner29from unittest.runner import TextTestRunner
3030
3131
=== modified file 'plainbox/plainbox/impl/depmgr.py'
--- plainbox/plainbox/impl/depmgr.py 2012-11-29 18:59:46 +0000
+++ plainbox/plainbox/impl/depmgr.py 2013-03-07 16:10:38 +0000
@@ -18,12 +18,12 @@
18# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.18# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
1919
20"""20"""
21plainbox.impl.depmgr21:mod:`plainbox.impl.depmgr` -- dependency solver
22====================22================================================
2323
24Internal implementation of plainbox24.. warning::
2525
26 * THIS MODULE DOES NOT HAVE STABLE PUBLIC API *26 THIS MODULE DOES NOT HAVE STABLE PUBLIC API
27"""27"""
2828
29from abc import ABCMeta29from abc import ABCMeta
@@ -148,15 +148,17 @@
148 @classmethod148 @classmethod
149 def resolve_dependencies(cls, job_list, visit_list=None):149 def resolve_dependencies(cls, job_list, visit_list=None):
150 """150 """
151 Solve the dependency graph expressed as a list of job definitions. The151 Solve the dependency graph expressed as a list of job definitions.
152 visit_list, if specified, allows to consider only a part of the graph152
153 while still having access and knowledge of all jobs.153 :param list job_list: list of known jobs
154154 :param list visit_list: (optional) list of jobs to solve
155 Returns the solution (a list of jobs to execute in order)155
156156 The visit_list, if specified, allows to consider only a part of the
157 raises DependencyCycleError if a cyclic dependency is present.157 graph while still having access and knowledge of all jobs.
158158
159 raises DependencyMissingErorr if a required job does not exist.159 :returns list: the solution (a list of jobs to execute in order)
160 :raises DependencyCycleError: if a cyclic dependency is present.
161 :raises DependencyMissingErorr: if a required job does not exist.
160 """162 """
161 return cls(job_list)._solve(visit_list)163 return cls(job_list)._solve(visit_list)
162164
163165
=== modified file 'plainbox/plainbox/impl/exporter/__init__.py'
--- plainbox/plainbox/impl/exporter/__init__.py 2013-02-22 16:26:25 +0000
+++ plainbox/plainbox/impl/exporter/__init__.py 2013-03-07 16:10:38 +0000
@@ -18,10 +18,12 @@
18# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.18# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
1919
20"""20"""
21plainbox.impl.exporter21:mod:`plainbox.impl.exporter` -- shared code for session state exporters
22======================22========================================================================
2323
24 * THIS MODULE DOES NOT HAVE STABLE PUBLIC API *24.. warning::
25
26 THIS MODULE DOES NOT HAVE STABLE PUBLIC API
25"""27"""
2628
27from abc import ABCMeta, abstractmethod29from abc import ABCMeta, abstractmethod
@@ -38,11 +40,6 @@
38class classproperty:40class classproperty:
39 """41 """
40 Class property.42 Class property.
41
42 @property
43 @classmethod
44 def foo(cls):
45 ...
46 """43 """
47 # I wish it was in the standard library or that the composition worked44 # I wish it was in the standard library or that the composition worked
4845
@@ -75,6 +72,7 @@
75 OPTION_WITH_DESIRED_JOB_LIST = 'with-job-list'72 OPTION_WITH_DESIRED_JOB_LIST = 'with-job-list'
76 OPTION_WITH_RESOURCE_MAP = 'with-resource-map'73 OPTION_WITH_RESOURCE_MAP = 'with-resource-map'
77 OPTION_WITH_JOB_DEFS = 'with-job-defs'74 OPTION_WITH_JOB_DEFS = 'with-job-defs'
75 OPTION_WITH_ATTACHMENTS = 'with-attachments'
7876
79 SUPPORTED_OPTION_LIST = (77 SUPPORTED_OPTION_LIST = (
80 OPTION_WITH_IO_LOG,78 OPTION_WITH_IO_LOG,
@@ -84,6 +82,7 @@
84 OPTION_WITH_JOB_LIST,82 OPTION_WITH_JOB_LIST,
85 OPTION_WITH_RESOURCE_MAP,83 OPTION_WITH_RESOURCE_MAP,
86 OPTION_WITH_JOB_DEFS,84 OPTION_WITH_JOB_DEFS,
85 OPTION_WITH_ATTACHMENTS,
87 )86 )
8887
89 def __init__(self, option_list=None):88 def __init__(self, option_list=None):
@@ -133,6 +132,8 @@
133 # TODO: turn session._resource_map to a public property132 # TODO: turn session._resource_map to a public property
134 for resource_name, resource_list in session._resource_map.items()133 for resource_name, resource_list in session._resource_map.items()
135 }134 }
135 if self.OPTION_WITH_ATTACHMENTS in self._option_list:
136 data['attachment_map'] = {}
136 for job_name, job_state in session.job_state_map.items():137 for job_name, job_state in session.job_state_map.items():
137 if job_state.result.outcome is None:138 if job_state.result.outcome is None:
138 continue139 continue
@@ -151,6 +152,16 @@
151 continue152 continue
152 data['result_map'][job_name][prop] = \153 data['result_map'][job_name][prop] = \
153 getattr(job_state.result.job, prop)154 getattr(job_state.result.job, prop)
155
156 # Add Attachements if requested
157 if job_state.result.job.plugin == 'attachment':
158 if self.OPTION_WITH_ATTACHMENTS in self._option_list:
159 raw_bytes = b''.join((record[2] for record in
160 job_state.result.io_log if record[1] == 'stdout'))
161 data['attachment_map'][job_name] = \
162 base64.standard_b64encode(raw_bytes).decode('ASCII')
163 continue # Don't add attachments IO logs to the result_map
164
154 # Add IO log if requested165 # Add IO log if requested
155 if self.OPTION_WITH_IO_LOG in self._option_list:166 if self.OPTION_WITH_IO_LOG in self._option_list:
156 # If requested, squash the IO log so that only textual data is167 # If requested, squash the IO log so that only textual data is
157168
=== modified file 'plainbox/plainbox/impl/exporter/json.py'
--- plainbox/plainbox/impl/exporter/json.py 2012-12-10 12:38:50 +0000
+++ plainbox/plainbox/impl/exporter/json.py 2013-03-07 16:10:38 +0000
@@ -18,12 +18,11 @@
18# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.18# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
1919
20"""20"""
21plainbox.impl.exporter.json21:mod:`plainbox.impl.exporter.json` -- JSON exporter
22===========================22===================================================
2323
24Internal implementation of plainbox24.. warning::
2525 THIS MODULE DOES NOT HAVE STABLE PUBLIC API
26 * THIS MODULE DOES NOT HAVE STABLE PUBLIC API *
27"""26"""
2827
29import json28import json
3029
=== modified file 'plainbox/plainbox/impl/exporter/rfc822.py'
--- plainbox/plainbox/impl/exporter/rfc822.py 2013-01-04 13:31:02 +0000
+++ plainbox/plainbox/impl/exporter/rfc822.py 2013-03-07 16:10:38 +0000
@@ -18,12 +18,12 @@
18# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.18# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
1919
20"""20"""
21plainbox.impl.exporter.rfc82221:mod:`plainbox.impl.exporter.rfc822` -- RFC822 exporter
22===========================22=======================================================
2323
24Internal implementation of plainbox24.. warning::
2525
26 * THIS MODULE DOES NOT HAVE STABLE PUBLIC API *26 THIS MODULE DOES NOT HAVE STABLE PUBLIC API
27"""27"""
2828
2929
3030
=== modified file 'plainbox/plainbox/impl/exporter/test_init.py'
--- plainbox/plainbox/impl/exporter/test_init.py 2013-02-22 16:26:25 +0000
+++ plainbox/plainbox/impl/exporter/test_init.py 2013-03-07 16:10:38 +0000
@@ -24,6 +24,7 @@
24Test definitions for plainbox.impl.exporter module24Test definitions for plainbox.impl.exporter module
25"""25"""
2626
27from tempfile import TemporaryDirectory
27from unittest import TestCase28from unittest import TestCase
2829
29from plainbox.impl.exporter import SessionStateExporterBase30from plainbox.impl.exporter import SessionStateExporterBase
@@ -31,7 +32,7 @@
31from plainbox.impl.session import SessionState32from plainbox.impl.session import SessionState
32from plainbox.impl.job import JobDefinition33from plainbox.impl.job import JobDefinition
33from plainbox.impl.result import JobResult, IOLogRecord34from plainbox.impl.result import JobResult, IOLogRecord
34from plainbox.impl.testing_utils import make_job, make_job_result35from plainbox.impl.testing_utils import make_io_log, make_job, make_job_result
3536
3637
37class ClassPropertyTests(TestCase):38class ClassPropertyTests(TestCase):
@@ -95,7 +96,7 @@
95 }96 }
96 self.assertEqual(data, expected_data)97 self.assertEqual(data, expected_data)
9798
98 def make_realistic_test_session(self):99 def make_realistic_test_session(self, session_dir):
99 # Create a more realistic session with two jobs but with richer set100 # Create a more realistic session with two jobs but with richer set
100 # of data in the actual jobs and results.101 # of data in the actual jobs and results.
101 job_a = JobDefinition({102 job_a = JobDefinition({
@@ -115,17 +116,17 @@
115 'job': job_a,116 'job': job_a,
116 'outcome': 'pass',117 'outcome': 'pass',
117 'return_code': 0,118 'return_code': 0,
118 'io_log': (119 'io_log': make_io_log(
119 IOLogRecord(0, 'stdout', b'testing\n'),120 (IOLogRecord(0, 'stdout', b'testing\n'),),
120 )121 session_dir)
121 })122 })
122 result_b = JobResult({123 result_b = JobResult({
123 'job': job_b,124 'job': job_b,
124 'outcome': 'pass',125 'outcome': 'pass',
125 'return_code': 0,126 'return_code': 0,
126 'io_log': (127 'io_log': make_io_log(
127 IOLogRecord(0, 'stdout', b'ready: yes\n'),128 (IOLogRecord(0, 'stdout', b'ready: yes\n'),),
128 )129 session_dir)
129 })130 })
130 session.update_job_result(job_a, result_a)131 session.update_job_result(job_a, result_a)
131 session.update_job_result(job_b, result_b)132 session.update_job_result(job_b, result_b)
@@ -139,10 +140,11 @@
139 # - OPTION_FLATTEN_IO_LOG140 # - OPTION_FLATTEN_IO_LOG
140 # The implementation favours SQUASH_IO_LOG141 # The implementation favours SQUASH_IO_LOG
141 # and thus the code below tests that option142 # and thus the code below tests that option
142 exporter = self.TestSessionStateExporter(143 with TemporaryDirectory() as scratch_dir:
143 self.TestSessionStateExporter.supported_option_list)144 exporter = self.TestSessionStateExporter(
144 session = self.make_realistic_test_session()145 self.TestSessionStateExporter.supported_option_list)
145 data = exporter.get_session_data_subset(session)146 session = self.make_realistic_test_session(scratch_dir)
147 data = exporter.get_session_data_subset(session)
146 expected_data = {148 expected_data = {
147 'job_list': ['job_a', 'job_b'],149 'job_list': ['job_a', 'job_b'],
148 'run_list': ['job_b', 'job_a'],150 'run_list': ['job_b', 'job_a'],
@@ -166,6 +168,8 @@
166 'command': 'echo ready: yes',168 'command': 'echo ready: yes',
167 'io_log': ['cmVhZHk6IHllcwo='],169 'io_log': ['cmVhZHk6IHllcwo='],
168 }170 }
171 },
172 'attachment_map': {
169 }173 }
170 }174 }
171 # This is just to make debugging easier175 # This is just to make debugging easier
172176
=== modified file 'plainbox/plainbox/impl/exporter/text.py'
--- plainbox/plainbox/impl/exporter/text.py 2012-12-10 12:38:50 +0000
+++ plainbox/plainbox/impl/exporter/text.py 2013-03-07 16:10:38 +0000
@@ -18,12 +18,12 @@
18# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.18# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
1919
20"""20"""
21plainbox.impl.exporter.text21:mod:`plainbox.impl.exporter.text` -- plain text exporter
22===========================22=========================================================
2323
24Internal implementation of plainbox24.. warning::
2525
26 * THIS MODULE DOES NOT HAVE STABLE PUBLIC API *26 THIS MODULE DOES NOT HAVE STABLE PUBLIC API
27"""27"""
2828
2929
3030
=== modified file 'plainbox/plainbox/impl/integration_tests.py'
--- plainbox/plainbox/impl/integration_tests.py 2013-02-22 16:26:25 +0000
+++ plainbox/plainbox/impl/integration_tests.py 2013-03-07 16:10:38 +0000
@@ -18,16 +18,20 @@
18# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.18# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
1919
20"""20"""
21plainbox.impl.integration_tests21:mod:`plainbox.impl.integration_tests` -- integration tests
22===============================22===========================================================
2323
24Integration tests for checkbox scripts24.. warning::
25
26 THIS MODULE DOES NOT HAVE STABLE PUBLIC API
25"""27"""
2628
27from tempfile import TemporaryDirectory29from tempfile import TemporaryDirectory
28from unittest import TestCase30from unittest import TestCase
29import json31import json
30import os32import os
33import shutil
34import tempfile
3135
32from pkg_resources import resource_filename, resource_isdir, resource_listdir36from pkg_resources import resource_filename, resource_isdir, resource_listdir
3337
@@ -41,6 +45,14 @@
4145
42 parameter_names = ('job_name',)46 parameter_names = ('job_name',)
4347
48 def setUp(self):
49 # session data are kept in XDG_CACHE_HOME/plainbox/.session
50 # To avoid resuming a real session, we have to select a temporary
51 # location instead
52 self._sandbox = tempfile.mkdtemp()
53 self._env = os.environ
54 os.environ['XDG_CACHE_HOME'] = self._sandbox
55
44 @classmethod56 @classmethod
45 def _gen_job_name_values(cls, package='plainbox', root='data/'):57 def _gen_job_name_values(cls, package='plainbox', root='data/'):
46 """58 """
@@ -94,3 +106,7 @@
94 expected_result = json.load(stream)106 expected_result = json.load(stream)
95 # Check that results match expected values107 # Check that results match expected values
96 self.assertEqual(actual_result, expected_result)108 self.assertEqual(actual_result, expected_result)
109
110 def tearDown(self):
111 shutil.rmtree(self._sandbox)
112 os.environ = self._env
97113
=== modified file 'plainbox/plainbox/impl/job.py'
--- plainbox/plainbox/impl/job.py 2013-02-22 16:26:25 +0000
+++ plainbox/plainbox/impl/job.py 2013-03-07 16:10:38 +0000
@@ -18,12 +18,12 @@
18# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.18# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
1919
20"""20"""
21plainbox.impl.job21:mod:`plainbox.impl.job` -- job definition
22=================22==========================================
2323
24Internal implementation of plainbox24.. warning::
2525
26 * THIS MODULE DOES NOT HAVE STABLE PUBLIC API *26 THIS MODULE DOES NOT HAVE STABLE PUBLIC API
27"""27"""
2828
29import collections29import collections
@@ -41,6 +41,11 @@
4141
4242
43class JobDefinition(IJobDefinition):43class JobDefinition(IJobDefinition):
44 """
45 Job definition class.
46
47 Thin wrapper around the RFC822 record that defines a checkbox job definition
48 """
4449
45 @property50 @property
46 def plugin(self):51 def plugin(self):
@@ -120,10 +125,15 @@
120 def _get_persistance_subset(self):125 def _get_persistance_subset(self):
121 state = {}126 state = {}
122 state['data'] = {}127 state['data'] = {}
123 state['data']['plugin'] = self.plugin128 for key, value in self._data.items():
124 state['data']['name'] = self.name129 state['data'][key] = value
125 return state130 return state
126131
132 def __eq__(self, other):
133 if not isinstance(other, JobDefinition):
134 return False
135 return self.get_checksum() == other.get_checksum()
136
127 def get_resource_program(self):137 def get_resource_program(self):
128 """138 """
129 Return a ResourceProgram based on the 'requires' expression.139 Return a ResourceProgram based on the 'requires' expression.
130140
=== added file 'plainbox/plainbox/impl/mock_job.py'
--- plainbox/plainbox/impl/mock_job.py 1970-01-01 00:00:00 +0000
+++ plainbox/plainbox/impl/mock_job.py 2013-03-07 16:10:38 +0000
@@ -0,0 +1,36 @@
1# This file is part of Checkbox.
2#
3# Copyright 2013 Canonical Ltd.
4# Written by:
5# Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
6#
7# Checkbox is free software: you can redistribute it and/or modify
8# it under the terms of the GNU General Public License as published by
9# the Free Software Foundation, either version 3 of the License, or
10# (at your option) any later version.
11#
12# Checkbox is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU General Public License for more details.
16#
17# You should have received a copy of the GNU General Public License
18# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
19
20"""
21:mod:`plainbox.impl.mock_job` -- mock jobs
22==========================================
23"""
24
25from mock import Mock
26
27from plainbox.impl.job import JobDefinition
28
29
30def MockJobDefinition(name,*args, **kwargs):
31 """
32 Mock for JobDefinition class
33 """
34 job = Mock(*args, spec_set=JobDefinition, **kwargs)
35 job.name = name
36 return job
037
=== modified file 'plainbox/plainbox/impl/resource.py'
--- plainbox/plainbox/impl/resource.py 2013-02-22 16:26:25 +0000
+++ plainbox/plainbox/impl/resource.py 2013-03-07 16:10:38 +0000
@@ -18,12 +18,12 @@
18# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.18# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
1919
20"""20"""
21plainbox.impl.resource21:mod:`plainbox.impl.resource` -- job resources
22======================22==============================================
2323
24Internal implementation of plainbox24.. warning::
2525
26 * THIS MODULE DOES NOT HAVE STABLE PUBLIC API *26 THIS MODULE DOES NOT HAVE STABLE PUBLIC API
27"""27"""
2828
29import ast29import ast
@@ -221,7 +221,7 @@
221 """221 """
222 A NodeVisitor subclass used to analyze requirement expressions.222 A NodeVisitor subclass used to analyze requirement expressions.
223223
224 ..warning::224 .. warning::
225225
226 Implementation of this class requires understanding of226 Implementation of this class requires understanding of
227 some of the lower levels of python. The general idea is227 some of the lower levels of python. The general idea is
228228
=== modified file 'plainbox/plainbox/impl/result.py'
--- plainbox/plainbox/impl/result.py 2013-02-22 16:26:25 +0000
+++ plainbox/plainbox/impl/result.py 2013-03-07 16:10:38 +0000
@@ -18,16 +18,19 @@
18# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.18# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
1919
20"""20"""
21plainbox.impl.result21:mod:`plainbox.impl.result` -- job result
22====================22=========================================
2323
24Internal implementation of plainbox24.. warning::
2525
26 * THIS MODULE DOES NOT HAVE STABLE PUBLIC API *26 THIS MODULE DOES NOT HAVE STABLE PUBLIC API
27"""27"""
2828
29from collections import namedtuple29from collections import namedtuple
30import base64
31import json
30import logging32import logging
33import os
3134
32from plainbox.abc import IJobResult35from plainbox.abc import IJobResult
3336
@@ -48,6 +51,9 @@
4851
4952
50class JobResult(IJobResult):53class JobResult(IJobResult):
54 """
55 Result of running a JobDefinition.
56 """
5157
52 # The outcome of a job is a one-word classification how how it ran. There58 # The outcome of a job is a one-word classification how how it ran. There
53 # are several values that were not used in the original implementation but59 # are several values that were not used in the original implementation but
@@ -112,7 +118,11 @@
112118
113 @property119 @property
114 def io_log(self):120 def io_log(self):
115 return self._data.get('io_log', ())121 if os.path.exists(self._data.get('io_log', '')):
122 with open(self._data.get('io_log')) as f:
123 return json.load(f, cls=IoLogDecoder)
124 else:
125 return ()
116126
117 @property127 @property
118 def return_code(self):128 def return_code(self):
@@ -121,11 +131,8 @@
121 def _get_persistance_subset(self):131 def _get_persistance_subset(self):
122 state = {}132 state = {}
123 state['data'] = {}133 state['data'] = {}
124 state['data']['job'] = self._data['job']134 for key, value in self._data.items():
125 state['data']['outcome'] = self._data.get('outcome', None)135 state['data'][key] = value
126 state['data']['comments'] = self._data.get('comments')
127 state['data']['return_code'] = self._data.get('return_code')
128 # io_log are stored on disk, see session.jobs_io_log_dir
129 return state136 return state
130137
131 @classmethod138 @classmethod
@@ -134,3 +141,26 @@
134 Create a JobResult instance from JSON record141 Create a JobResult instance from JSON record
135 """142 """
136 return cls(record['data'])143 return cls(record['data'])
144
145
146class IoLogEncoder(json.JSONEncoder):
147 """
148 JSON Serialize helper to encode binary io logs
149 """
150
151 def default(self, obj):
152 return base64.standard_b64encode(obj).decode('ASCII')
153
154
155class IoLogDecoder(json.JSONDecoder):
156 """
157 JSON Decoder helper for io logs objects
158 """
159
160 def decode(self, obj):
161 return tuple([IOLogRecord(
162 # io logs namedtuple are recorded as list in json, using _asdict()
163 # would require too much space for little benefit.
164 # IOLogRecord are re created using the list ordering
165 log[0], log[1], base64.standard_b64decode(log[2].encode('ASCII')))
166 for log in super().decode(obj)])
137167
=== modified file 'plainbox/plainbox/impl/rfc822.py'
--- plainbox/plainbox/impl/rfc822.py 2012-12-18 00:26:03 +0000
+++ plainbox/plainbox/impl/rfc822.py 2013-03-07 16:10:38 +0000
@@ -18,12 +18,14 @@
18# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.18# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
1919
20"""20"""
21plainbox.impl.rfc82221:mod:`plainbox.impl.rfc822` -- RFC822 parser
22====================22============================================
2323
24Implementation of rfc822 serializer and deserializer.24Implementation of rfc822 serializer and deserializer.
2525
26 * THIS MODULE DOES NOT HAVE STABLE PUBLIC API *26.. warning::
27
28 THIS MODULE DOES NOT HAVE STABLE PUBLIC API
27"""29"""
2830
29import logging31import logging
@@ -37,10 +39,11 @@
37 """39 """
38 Simple class for tracking where something came from40 Simple class for tracking where something came from
3941
40 It has three attributes:42 :ivar filename: the name of the file
41 filename - the name of the file43
42 line_start - the number of the line where the record begins44 :ivar line_start: the number of the line where the record begins
43 line_end - the number of the line where the record ends45
46 :ivar line_end: the number of the line where the record ends
44 """47 """
4548
46 __slots__ = ['filename', 'line_start', 'line_end']49 __slots__ = ['filename', 'line_start', 'line_end']
4750
=== modified file 'plainbox/plainbox/impl/runner.py'
--- plainbox/plainbox/impl/runner.py 2013-02-22 16:26:25 +0000
+++ plainbox/plainbox/impl/runner.py 2013-03-07 16:10:38 +0000
@@ -18,16 +18,17 @@
18# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.18# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
1919
20"""20"""
21plainbox.impl.runner21:mod:`plainbox.impl.runner` -- job runner
22====================22=========================================
2323
24Internal implementation of plainbox24.. warning::
2525
26 * THIS MODULE DOES NOT HAVE STABLE PUBLIC API *26 THIS MODULE DOES NOT HAVE STABLE PUBLIC API
27"""27"""
2828
29import collections29import collections
30import datetime30import datetime
31import json
31import logging32import logging
32import os33import os
33import string34import string
@@ -35,7 +36,7 @@
35from plainbox.vendor import extcmd36from plainbox.vendor import extcmd
3637
37from plainbox.abc import IJobRunner38from plainbox.abc import IJobRunner
38from plainbox.impl.result import JobResult, IOLogRecord39from plainbox.impl.result import JobResult, IOLogRecord, IoLogEncoder
3940
40logger = logging.getLogger("plainbox.runner")41logger = logging.getLogger("plainbox.runner")
4142
@@ -50,6 +51,15 @@
50 return ''.join(c if c in valid_chars else '_' for c in _string)51 return ''.join(c if c in valid_chars else '_' for c in _string)
5152
5253
54def io_log_write(log, stream):
55 """
56 JSON call to serialize io_log objects to disk
57 """
58 json.dump(
59 log, stream, ensure_ascii=False, indent=None, cls=IoLogEncoder,
60 separators=(',', ':'))
61
62
53class CommandIOLogBuilder(extcmd.DelegateBase):63class CommandIOLogBuilder(extcmd.DelegateBase):
54 """64 """
55 Delegate for extcmd that builds io_log entries.65 Delegate for extcmd that builds io_log entries.
@@ -146,15 +156,24 @@
146 def __init__(self, prompt):156 def __init__(self, prompt):
147 self._prompt = prompt157 self._prompt = prompt
148 self._lineno = collections.defaultdict(int)158 self._lineno = collections.defaultdict(int)
159 self._abort = False
149160
150 def on_line(self, stream_name, line):161 def on_line(self, stream_name, line):
162 if self._abort:
163 return
151 self._lineno[stream_name] += 1164 self._lineno[stream_name] += 1
152 print("(job {}, <{}:{:05}>) {}".format(165 try:
153 self._prompt, stream_name, self._lineno[stream_name],166 print("(job {}, <{}:{:05}>) {}".format(
154 line.rstrip()))167 self._prompt, stream_name, self._lineno[stream_name],
168 line.decode('UTF-8').rstrip()))
169 except UnicodeDecodeError:
170 self._abort = True
155171
156172
157class JobRunner(IJobRunner):173class JobRunner(IJobRunner):
174 """
175 Runner for jobs - executes jobs and produces results
176 """
158177
159 def __init__(self, session_dir, jobs_io_log_dir,178 def __init__(self, session_dir, jobs_io_log_dir,
160 command_io_delegate=None, outcome_callback=None):179 command_io_delegate=None, outcome_callback=None):
@@ -173,6 +192,9 @@
173 self._outcome_callback = outcome_callback192 self._outcome_callback = outcome_callback
174193
175 def run_job(self, job):194 def run_job(self, job):
195 """
196 Run the specified job an return the result
197 """
176 logger.info("Running %r", job)198 logger.info("Running %r", job)
177 func_name = "_plugin_" + job.plugin.replace('-', '_')199 func_name = "_plugin_" + job.plugin.replace('-', '_')
178 try:200 try:
@@ -189,6 +211,8 @@
189 def _plugin_shell(self, job):211 def _plugin_shell(self, job):
190 return self._just_run_command(job)212 return self._just_run_command(job)
191213
214 _plugin_attachment = _plugin_shell
215
192 def _plugin_resource(self, job):216 def _plugin_resource(self, job):
193 return self._just_run_command(job)217 return self._just_run_command(job)
194218
@@ -227,7 +251,7 @@
227 'io_log': io_log251 'io_log': io_log
228 })252 })
229253
230 def _get_script_env(self, job):254 def _get_script_env(self, job, only_changes=True):
231 """255 """
232 Compute the environment the script will be executed in256 Compute the environment the script will be executed in
233 """257 """
@@ -237,7 +261,17 @@
237 env['LANG'] = 'C.UTF-8'261 env['LANG'] = 'C.UTF-8'
238 # Allow the job to customize anything262 # Allow the job to customize anything
239 job.modify_execution_environment(env, self._session_dir)263 job.modify_execution_environment(env, self._session_dir)
240 return env264 # If a differential environment is requested return only the subset
265 # that has been altered.
266 #
267 # XXX: This will effectively give the root user our PATH which _may_ be
268 # good bud _might_ be dangerous. This will need some peer review.
269 if only_changes:
270 return {key: value
271 for key, value in env.items()
272 if key not in os.environ or os.environ[key] != value}
273 else:
274 return env
241275
242 def _run_command(self, job):276 def _run_command(self, job):
243 """277 """
@@ -278,7 +312,7 @@
278 # Send the third copy to the output writer that writes everything to312 # Send the third copy to the output writer that writes everything to
279 # disk.313 # disk.
280 delegate = extcmd.Chain([314 delegate = extcmd.Chain([
281 extcmd.Decode(ui_io_delegate),315 ui_io_delegate,
282 io_log_builder,316 io_log_builder,
283 output_writer])317 output_writer])
284 logger.debug("job[%s] extcmd delegate: %r", job.name, delegate)318 logger.debug("job[%s] extcmd delegate: %r", job.name, delegate)
@@ -291,14 +325,37 @@
291 # threads although all callbacks will be fired from a single325 # threads although all callbacks will be fired from a single
292 # thread (which is _not_ the main thread)326 # thread (which is _not_ the main thread)
293 logger.debug("job[%s] starting command: %s", job.name, job.command)327 logger.debug("job[%s] starting command: %s", job.name, job.command)
294 return_code = logging_popen.call(328 # XXX: sadly using /bin/sh results in broken output
295 # XXX: sadly using /bin/sh results in broken output329 # XXX: maybe run it both ways and raise exceptions on differences?
296 # XXX: maybe run it both ways and raise exceptions on differences?330 cmd = ['bash', '-c', job.command]
297 ['bash', '-c', job.command],331 if job.user is not None:
298 env=self._get_script_env(job))332 # When the job requires to run as root then elevate our permissions
333 # via pkexec(1). Since pkexec resets environment we need to somehow
334 # pass the extra things we require. To do that we use the env(1)
335 # command and pass it the list of changed environment variables.
336 #
337 # The whole pkexec and env part gets prepended to the command we
338 # were supposed to run.
339 cmd = ['pkexec', '--user', job.user, 'env'] + [
340 "{key}={value}".format(key=key, value=value)
341 for key, value in self._get_script_env(
342 job, only_changes=True
343 ).items()
344 ] + cmd
345 logging.debug("job[%s] executing %r", job.name, cmd)
346 return_code = logging_popen.call(cmd)
347 else:
348 logging.debug("job[%s] executing %r", job.name, cmd)
349 return_code = logging_popen.call(
350 cmd, env=self._get_script_env(job))
299 logger.debug("job[%s] command return code: %r",351 logger.debug("job[%s] command return code: %r",
300 job.name, return_code)352 job.name, return_code)
301 # XXX: Perhaps handle process dying from signals here353 # XXX: Perhaps handle process dying from signals here
302 # When the process is killed proc.returncode is not set354 # When the process is killed proc.returncode is not set
303 # and another (cannot remember now) attribute is set355 # and another (cannot remember now) attribute is set
304 return return_code, io_log_builder.io_log356 fjson = os.path.join(self._jobs_io_log_dir, "{}.json".format(slug))
357 with open(fjson, "wt") as stream:
358 io_log_write(io_log_builder.io_log, stream)
359 stream.flush()
360 os.fsync(stream.fileno())
361 return return_code, fjson
305362
=== modified file 'plainbox/plainbox/impl/session.py'
--- plainbox/plainbox/impl/session.py 2013-02-22 16:26:25 +0000
+++ plainbox/plainbox/impl/session.py 2013-03-07 16:10:38 +0000
@@ -18,12 +18,12 @@
18# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.18# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
1919
20"""20"""
21plainbox.impl.session21:mod:`plainbox.impl.session` -- session state handling
22=====================22======================================================
2323
24Internal implementation of plainbox24.. warning::
2525
26 * THIS MODULE DOES NOT HAVE STABLE PUBLIC API *26 THIS MODULE DOES NOT HAVE STABLE PUBLIC API
27"""27"""
28import json28import json
29import logging29import logging
@@ -165,7 +165,7 @@
165 """165 """
166 Class representing the state of a job in a session.166 Class representing the state of a job in a session.
167167
168 Contains two basic properties of each job (either of which can be None):168 Contains two basic properties of each job:
169169
170 * the readiness_inhibitor_list that prevent the job form starting170 * the readiness_inhibitor_list that prevent the job form starting
171 * the result (outcome) of the run (IJobResult)171 * the result (outcome) of the run (IJobResult)
@@ -223,7 +223,7 @@
223 return self._result223 return self._result
224224
225 def fset(self, value):225 def fset(self, value):
226 if value.job is not self.job:226 if value.job.get_checksum() != self.job.get_checksum():
227 raise ValueError("result job does not match")227 raise ValueError("result job does not match")
228 self._result = value228 self._result = value
229229
@@ -278,53 +278,79 @@
278 """278 """
279 Class representing all state needed during a single program session.279 Class representing all state needed during a single program session.
280280
281 This is the central glue/entry-point for applications. It connects user
282 intents to the rest of the system / plumbing and keeps all of the state in
283 one place.
284
281 The set of utility methods and properties allow applications to easily285 The set of utility methods and properties allow applications to easily
282 handle the lower levels of dependencies, resources and ready states.286 handle the lower levels of dependencies, resources and ready states.
283287
284 Once instantiated with a list of known jobs it is ready to react to288 SessionState has the following instance variables, all of which are
285 UI-driven changes. It is expected that the user will select / unselect289 currently exposed as properties.
286 and run jobs. This class can react to both actions by recomputing the290
287 dependency graph and updating the read states accordingly.291 :ivar list job_list: A list of all known jobs
288292
289 Ready states (one for each job) allow the UI to take simple decisions293 Not all the jobs from this list are going to be executed (or selected
290 (either can or cannot run)294 for execution) by the user.
295
296 It may change at runtime because of local jobs. Note that in upcoming
297 changes this will start out empty and will be changeable dynamically.
298 It can still change due to local jobs but there is no API yes.
299
300 :ivar dict job_state_map: mapping that tracks the state of each job
301
302 Mapping from job name to :class:`JobState`. This basically has the test
303 result and the inhibitor of each job. It also serves as a
304 :attr:`plainbox.impl.job.JobDefinition.name`-> job lookup helper.
305
306 Directly exposed with the intent to fuel part of the UI. This is a way
307 to get at the readiness state, result and readiness inhibitors, if any.
308
309 XXX: this can loose data job_list has jobs with the same name. It would
310 be better to use job id as the keys here. A separate map could be used
311 for the name->job lookup. This will be fixed when session controller
312 branch lands in trunk as then jobs are dynamically added to the system
313 one at a time and proper error conditions can be detected and reported.
314
315 :ivar list desired_job_list: subset of jobs selected for execution
316
317 This is used to compute :attr:`run_list`. It can only be changed by
318 calling :meth:`update_desired_job_list()` which returns meaningful
319 values so this is not a settable property.
320
321 :ivar list run_list: sorted list of jobs to execute
322
323 This is basically a superset of desired_job_list and a subset of
324 job_list that is topologically sorted to allowing all desired jobs to
325 run. This property is updated whenever desired_job_list is changed.
326
327 :ivar dict resource_map: all known resources
328
329 A mapping from resource name to a list of
330 :class:`plainbox.impl.resource.Resource` objects. This encapsulates all
331 "knowledge" about the system plainbox is running on.
332
333 It is needed to compute job readiness (as it stores resource data
334 needed by resource programs). It is also available to exporters.
335
336 This is computed internally from the output of checkbox resource jobs,
337 it can only be changed by calling :meth:`update_job_result()`
291 """338 """
292339
293 session_data_filename = 'session.json'340 session_data_filename = 'session.json'
294341
295 def __init__(self, job_list):342 def __init__(self, job_list):
296 # The original list of job that the system knows about.
297 # Not all jobs from this list are going to be executed
298 # (or selected for execution) by the user.
299 self._job_list = job_list343 self._job_list = job_list
300 # State of each job, see JobState for details but it basically
301 # has the test result and the inhibitor of each job. It also serves
302 # as a job.name -> job lookup helper.
303 #
304 # Directly exposed with the intent to fuel part of the UI.
305 #
306 # XXX: this can loose data job_list has jobs with the same name. It
307 # would be better to use job id as the keys here. A separate map could
308 # be used for the name->job lookup.
309 self._job_state_map = {job.name: JobState(job)344 self._job_state_map = {job.name: JobState(job)
310 for job in self._job_list}345 for job in self._job_list}
311 # A subset of job_list that was selected by the user for execution.
312 # Used to compute run_list. Can be changed at will during lifetime
313 # of this object
314 self._desired_job_list = []346 self._desired_job_list = []
315 # Copy of desired_job_list that was topologically sorted by the
316 # dependency solver. Jobs must run in this order (although not all jobs
317 # may actually run or will actually be successful)
318 self._run_list = []347 self._run_list = []
319 # A collection of known resources. Mapping resource job name to a list
320 # of resource objects. Needed to compute task readiness (as it stores
321 # resource data needed by resource programs). Currently not exposed
322 # outside of this class.
323 self._resource_map = {}348 self._resource_map = {}
324 # Temporary directory used as 'scratch space' for running jobs. Removed349 # Temporary directory used as 'scratch space' for running jobs. Removed
325 # entirely when session is terminated. Internally this is exposed as350 # entirely when session is terminated. Internally this is exposed as
326 # $CHECKBOX_DATA to script environment.351 # $CHECKBOX_DATA to script environment.
327 self._session_dir = None352 self._session_dir = None
353
328 # Directory used to store jobs IO logs.354 # Directory used to store jobs IO logs.
329 self._jobs_io_log_dir = None355 self._jobs_io_log_dir = None
330356
@@ -355,28 +381,34 @@
355 if self._session_dir is None:381 if self._session_dir is None:
356 xdg_cache_home = os.environ.get('XDG_CACHE_HOME') or \382 xdg_cache_home = os.environ.get('XDG_CACHE_HOME') or \
357 os.path.join(os.path.expanduser('~'), '.cache')383 os.path.join(os.path.expanduser('~'), '.cache')
358 temp_dir = os.path.join(xdg_cache_home, 'plainbox')384 self._session_dir = os.path.join(xdg_cache_home, 'plainbox')
359 if not os.path.isdir(temp_dir):385 if not os.path.isdir(self._session_dir):
360 os.makedirs(temp_dir)386 os.makedirs(self._session_dir)
361 self._session_dir = tempfile.mkdtemp(dir=temp_dir)
362 if self._jobs_io_log_dir is None:387 if self._jobs_io_log_dir is None:
363 self._jobs_io_log_dir = os.path.join(self._session_dir, 'io-logs')388 self._jobs_io_log_dir = os.path.join(self._session_dir, 'io-logs')
364 if not os.path.isdir(self._jobs_io_log_dir):389 if not os.path.isdir(self._jobs_io_log_dir):
365 os.makedirs(self._jobs_io_log_dir)390 os.makedirs(self._jobs_io_log_dir)
366 return self391 return self
367392
368 def close(self):393 def clean(self):
369 """394 """
370 Close the session and remove temporary disk state.395 Clean the session directory.
371
372 This function removes the directory created by .open() and all the data
373 that was placed there. It is automatically called by __exit__, the
374 context manager exit function. Care should be taken to ensure that all
375 session data, particularly attachments, were saved before.
376 """396 """
377 if self._session_dir is not None:397 if self._session_dir is not None:
378 shutil.rmtree(self._session_dir)398 shutil.rmtree(self._session_dir)
379 self._session_dir = None399 self._session_dir = None
400 self._jobs_io_log_dir = None
401 self.open()
402
403 def close(self):
404 """
405 Close the session.
406
407 It is automatically called by __exit__, the context manager exit
408 function.
409 """
410 self._session_dir = None
411 self._jobs_io_log_dir = None
380412
381 def update_desired_job_list(self, desired_job_list):413 def update_desired_job_list(self, desired_job_list):
382 """414 """
@@ -405,7 +437,7 @@
405 # resources or runtime complexity.437 # resources or runtime complexity.
406 try:438 try:
407 self._run_list = DependencySolver.resolve_dependencies(439 self._run_list = DependencySolver.resolve_dependencies(
408 self._job_list, desired_job_list)440 self._job_list, self._desired_job_list)
409 except DependencyError as exc:441 except DependencyError as exc:
410 # When a dependency error is detected remove the affected job442 # When a dependency error is detected remove the affected job
411 # form _desired_job_list and try again.443 # form _desired_job_list and try again.
@@ -457,11 +489,22 @@
457 # Update all job readiness state489 # Update all job readiness state
458 self._recompute_job_readiness()490 self._recompute_job_readiness()
459491
492 def previous_session_file(self):
493 """
494 Check the filesystem for previous session data
495 Returns the full pathname to the session file if it exists
496 """
497 session_filename = os.path.join(self._session_dir,
498 self.session_data_filename)
499 if os.path.exists(session_filename):
500 return session_filename
501 else:
502 return None
503
460 def persistent_save(self):504 def persistent_save(self):
461 """505 """
462 Save to disk the minimum needed to resume plainbox where it stopped506 Save to disk the minimum needed to resume plainbox where it stopped
463 """507 """
464
465 # Ensure an atomic update of the session file:508 # Ensure an atomic update of the session file:
466 # - create a new temp file (on the same file system!)509 # - create a new temp file (on the same file system!)
467 # - write data to the temp file510 # - write data to the temp file
@@ -472,7 +515,6 @@
472 # directory containing the file has also reached disk.515 # directory containing the file has also reached disk.
473 # For that an explicit fsync() on a file descriptor for the directory516 # For that an explicit fsync() on a file descriptor for the directory
474 # is also needed.517 # is also needed.
475
476 filename = os.path.join(self._session_dir,518 filename = os.path.join(self._session_dir,
477 self.session_data_filename)519 self.session_data_filename)
478520
@@ -493,6 +535,28 @@
493 os.fsync(session_dir_fd)535 os.fsync(session_dir_fd)
494 os.close(session_dir_fd)536 os.close(session_dir_fd)
495537
538 def resume(self):
539 """
540 Erase the job_state_map and desired_job_list with the saved ones
541 """
542 with open(self.previous_session_file(), 'r') as f:
543 previous_session = json.load(
544 f, object_hook=SessionStateEncoder().dict_to_object)
545 self._job_state_map = previous_session._job_state_map
546 desired_job_list = []
547 for job in previous_session._desired_job_list:
548 if job in self._job_list:
549 desired_job_list.extend(
550 [j for j in self._job_list if j == job])
551 elif (previous_session._job_state_map[job.name].result.outcome !=
552 JobResult.OUTCOME_NONE):
553 # Keep jobs results from the previous session without a
554 # definition in the current job_list only if they have
555 # a valid result
556 desired_job_list.append(job)
557 self.update_desired_job_list(desired_job_list)
558 # FIXME: Restore io_logs from files
559
496 def _process_resource_result(self, result):560 def _process_resource_result(self, result):
497 new_resource_list = []561 new_resource_list = []
498 for record in self._gen_rfc822_records_from_io_log(result):562 for record in self._gen_rfc822_records_from_io_log(result):
@@ -686,7 +750,6 @@
686 job_state.readiness_inhibitor_list.append(inhibitor)750 job_state.readiness_inhibitor_list.append(inhibitor)
687751
688 def __enter__(self):752 def __enter__(self):
689 self.open()
690 return self753 return self
691754
692 def __exit__(self, *args):755 def __exit__(self, *args):
693756
=== modified file 'plainbox/plainbox/impl/test_box.py'
--- plainbox/plainbox/impl/test_box.py 2013-02-22 16:26:25 +0000
+++ plainbox/plainbox/impl/test_box.py 2013-03-07 16:10:38 +0000
@@ -24,15 +24,91 @@
24Test definitions for plainbox.impl.box module24Test definitions for plainbox.impl.box module
25"""25"""
2626
27import os
28import shutil
29import tempfile
30
31from inspect import cleandoc
32from mock import Mock
27from unittest import TestCase33from unittest import TestCase
28from inspect import cleandoc
29
3034
31from plainbox import __version__ as version35from plainbox import __version__ as version
32from plainbox.impl.box import main36from plainbox.impl.box import main, CheckBoxCommandMixIn
37from plainbox.impl.mock_job import MockJobDefinition
33from plainbox.testing_utils.io import TestIO38from plainbox.testing_utils.io import TestIO
3439
3540
41class MiscTests(TestCase):
42
43 def setUp(self):
44 self.job_foo = MockJobDefinition(name='foo')
45 self.job_bar = MockJobDefinition(name='bar')
46 self.obj = CheckBoxCommandMixIn(Mock(name="checkbox"))
47
48 def test_matching_job_list(self):
49 # Nothing gets selected automatically
50 ns = Mock()
51 ns.whitelist = None
52 ns.include_pattern_list = []
53 ns.exclude_pattern_list = []
54 observed = self.obj._get_matching_job_list(ns, [
55 self.job_foo, self.job_bar])
56 self.assertEqual(observed, [])
57
58 def test_matching_job_list_including(self):
59 # Including jobs with glob pattern works
60 ns = Mock()
61 ns.whitelist = None
62 ns.include_pattern_list = ['f.+']
63 ns.exclude_pattern_list = []
64 observed = self.obj._get_matching_job_list(ns, [
65 self.job_foo, self.job_bar])
66 self.assertEqual(observed, [self.job_foo])
67
68 def test_matching_job_list_excluding(self):
69 # Excluding jobs with glob pattern works
70 ns = Mock()
71 ns.whitelist = None
72 ns.include_pattern_list = ['.+']
73 ns.exclude_pattern_list = ['f.+']
74 observed = self.obj._get_matching_job_list(ns, [
75 self.job_foo, self.job_bar])
76 self.assertEqual(observed, [self.job_bar])
77
78 def test_matching_job_list_whitelist(self):
79 # whitelists contain list of include patterns
80 # that are read and interpreted as usual
81 whitelist = Mock()
82 whitelist.readlines.return_value = ['foo']
83 ns = Mock()
84 ns.whitelist = whitelist
85 ns.include_pattern_list = []
86 ns.exclude_pattern_list = []
87 observed = self.obj._get_matching_job_list(ns, [
88 self.job_foo, self.job_bar])
89 self.assertEqual(observed, [self.job_foo])
90
91 def test_no_prefix_matching_including(self):
92 # Include patterns should only match whole job name
93 ns = Mock()
94 ns.whitelist = None
95 ns.include_pattern_list = ['fo', 'ba.+']
96 ns.exclude_pattern_list = []
97 observed = self.obj._get_matching_job_list(ns, [self.job_foo,
98 self.job_bar])
99 self.assertEqual(observed, [self.job_bar])
100
101 def test_no_prefix_matching_excluding(self):
102 # Exclude patterns should only match whole job name
103 ns = Mock()
104 ns.whitelist = None
105 ns.include_pattern_list = ['.+']
106 ns.exclude_pattern_list = ['fo', 'ba.+']
107 observed = self.obj._get_matching_job_list(ns, [self.job_foo,
108 self.job_bar])
109 self.assertEqual(observed, [self.job_foo])
110
111
36class TestMain(TestCase):112class TestMain(TestCase):
37113
38 def test_version(self):114 def test_version(self):
@@ -85,7 +161,7 @@
85 self.maxDiff = None161 self.maxDiff = None
86 expected = """162 expected = """
87 usage: plainbox special [-h] (-j | -e | -d) [--dot-resources] [-i PATTERN]163 usage: plainbox special [-h] (-j | -e | -d) [--dot-resources] [-i PATTERN]
88 [-W WHITELIST]164 [-x PATTERN] [-w WHITELIST]
89165
90 optional arguments:166 optional arguments:
91 -h, --help show this help message and exit167 -h, --help show this help message and exit
@@ -97,8 +173,12 @@
97173
98 job definition options:174 job definition options:
99 -i PATTERN, --include-pattern PATTERN175 -i PATTERN, --include-pattern PATTERN
100 Run jobs matching the given pattern176 Run jobs matching the given regular expression.
101 -W WHITELIST, --whitelist WHITELIST177 Matches from the start to the end of the line.
178 -x PATTERN, --exclude-pattern PATTERN
179 Do not run jobs matching the given regular expression.
180 Matches from the start to the end of the line.
181 -w WHITELIST, --whitelist WHITELIST
102 Load whitelist containing run patterns182 Load whitelist containing run patterns
103 """183 """
104 self.assertEqual(io.combined, cleandoc(expected) + "\n")184 self.assertEqual(io.combined, cleandoc(expected) + "\n")
@@ -110,7 +190,7 @@
110 self.assertEqual(call.exception.args, (2,))190 self.assertEqual(call.exception.args, (2,))
111 expected = """191 expected = """
112 usage: plainbox special [-h] (-j | -e | -d) [--dot-resources] [-i PATTERN]192 usage: plainbox special [-h] (-j | -e | -d) [--dot-resources] [-i PATTERN]
113 [-W WHITELIST]193 [-x PATTERN] [-w WHITELIST]
114 plainbox special: error: one of the arguments -j/--list-jobs -e/--list-expressions -d/--dot is required194 plainbox special: error: one of the arguments -j/--list-jobs -e/--list-expressions -d/--dot is required
115 """195 """
116 self.assertEqual(io.combined, cleandoc(expected) + "\n")196 self.assertEqual(io.combined, cleandoc(expected) + "\n")
@@ -130,7 +210,7 @@
130 def test_run_list_jobs_with_filtering(self):210 def test_run_list_jobs_with_filtering(self):
131 with TestIO() as io:211 with TestIO() as io:
132 with self.assertRaises(SystemExit) as call:212 with self.assertRaises(SystemExit) as call:
133 main(['special', '--include-pattern=usb3*', '--list-jobs'])213 main(['special', '--include-pattern=usb3.+', '--list-jobs'])
134 self.assertEqual(call.exception.args, (0,))214 self.assertEqual(call.exception.args, (0,))
135 # Test that usb3 insertion test was listed but the usb (2.0) test was not215 # Test that usb3 insertion test was listed but the usb (2.0) test was not
136 self.assertIn("usb3/insert", io.stdout.splitlines())216 self.assertIn("usb3/insert", io.stdout.splitlines())
@@ -181,6 +261,14 @@
181261
182class TestRun(TestCase):262class TestRun(TestCase):
183263
264 def setUp(self):
265 # session data are kept in XDG_CACHE_HOME/plainbox/.session
266 # To avoid resuming a real session, we have to select a temporary
267 # location instead
268 self._sandbox = tempfile.mkdtemp()
269 self._env = os.environ
270 os.environ['XDG_CACHE_HOME'] = self._sandbox
271
184 def test_help(self):272 def test_help(self):
185 with TestIO(combined=True) as io:273 with TestIO(combined=True) as io:
186 with self.assertRaises(SystemExit) as call:274 with self.assertRaises(SystemExit) as call:
@@ -189,7 +277,7 @@
189 self.maxDiff = None277 self.maxDiff = None
190 expected = """278 expected = """
191 usage: plainbox run [-h] [--not-interactive] [-n] [-f FORMAT] [-p OPTIONS]279 usage: plainbox run [-h] [--not-interactive] [-n] [-f FORMAT] [-p OPTIONS]
192 [-o FILE] [-i PATTERN] [-W WHITELIST]280 [-o FILE] [-i PATTERN] [-x PATTERN] [-w WHITELIST]
193281
194 optional arguments:282 optional arguments:
195 -h, --help show this help message and exit283 -h, --help show this help message and exit
@@ -211,8 +299,12 @@
211299
212 job definition options:300 job definition options:
213 -i PATTERN, --include-pattern PATTERN301 -i PATTERN, --include-pattern PATTERN
214 Run jobs matching the given pattern302 Run jobs matching the given regular expression.
215 -W WHITELIST, --whitelist WHITELIST303 Matches from the start to the end of the line.
304 -x PATTERN, --exclude-pattern PATTERN
305 Do not run jobs matching the given regular expression.
306 Matches from the start to the end of the line.
307 -w WHITELIST, --whitelist WHITELIST
216 Load whitelist containing run patterns308 Load whitelist containing run patterns
217 """309 """
218 self.assertEqual(io.combined, cleandoc(expected) + "\n")310 self.assertEqual(io.combined, cleandoc(expected) + "\n")
@@ -246,8 +338,12 @@
246 self.assertEqual(call.exception.args, (0,))338 self.assertEqual(call.exception.args, (0,))
247 expected = """339 expected = """
248 Each format may support a different set of options340 Each format may support a different set of options
249 json: with-io-log, squash-io-log, flatten-io-log, with-run-list, with-job-list, with-resource-map, with-job-defs, machine-json341 json: with-io-log, squash-io-log, flatten-io-log, with-run-list, with-job-list, with-resource-map, with-job-defs, with-attachments, machine-json
250 rfc822: with-io-log, squash-io-log, flatten-io-log, with-run-list, with-job-list, with-resource-map, with-job-defs342 rfc822: with-io-log, squash-io-log, flatten-io-log, with-run-list, with-job-list, with-resource-map, with-job-defs, with-attachments
251 text: with-io-log, squash-io-log, flatten-io-log, with-run-list, with-job-list, with-resource-map, with-job-defs343 text: with-io-log, squash-io-log, flatten-io-log, with-run-list, with-job-list, with-resource-map, with-job-defs, with-attachments
252 """344 """
253 self.assertEqual(io.combined, cleandoc(expected) + "\n")345 self.assertEqual(io.combined, cleandoc(expected) + "\n")
346
347 def tearDown(self):
348 shutil.rmtree(self._sandbox)
349 os.environ = self._env
254350
=== modified file 'plainbox/plainbox/impl/test_job.py'
--- plainbox/plainbox/impl/test_job.py 2013-02-22 16:26:25 +0000
+++ plainbox/plainbox/impl/test_job.py 2013-03-07 16:10:38 +0000
@@ -239,8 +239,7 @@
239 job_enc = job._get_persistance_subset()239 job_enc = job._get_persistance_subset()
240 self.assertEqual(job_enc['data']['plugin'], job.plugin)240 self.assertEqual(job_enc['data']['plugin'], job.plugin)
241 self.assertEqual(job_enc['data']['name'], job.name)241 self.assertEqual(job_enc['data']['name'], job.name)
242 with self.assertRaises(KeyError):242 self.assertEqual(job_enc['data']['requires'], job.requires)
243 job_enc['requires']
244 with self.assertRaises(KeyError):243 with self.assertRaises(KeyError):
245 job_enc['depends']244 job_enc['depends']
246 with self.assertRaises(KeyError):245 with self.assertRaises(KeyError):
@@ -280,7 +279,8 @@
280 "plugin": "user-verify"279 "plugin": "user-verify"
281 }280 }
282 }"""281 }"""
283 job_dec = json.loads(raw_json, object_hook=SessionStateEncoder().dict_to_object)282 job_dec = json.loads(raw_json,
283 object_hook=SessionStateEncoder().dict_to_object)
284 self.assertIsInstance(job_dec, JobDefinition)284 self.assertIsInstance(job_dec, JobDefinition)
285 self.assertEqual(job_dec.name, "camera/still")285 self.assertEqual(job_dec.name, "camera/still")
286 self.assertEqual(job_dec.plugin, "user-verify")286 self.assertEqual(job_dec.plugin, "user-verify")
287287
=== modified file 'plainbox/plainbox/impl/test_result.py'
--- plainbox/plainbox/impl/test_result.py 2013-02-22 16:26:25 +0000
+++ plainbox/plainbox/impl/test_result.py 2013-03-07 16:10:38 +0000
@@ -25,10 +25,11 @@
25"""25"""
26import json26import json
2727
28from tempfile import TemporaryDirectory
28from unittest import TestCase29from unittest import TestCase
2930
30from plainbox.impl.result import JobResult31from plainbox.impl.result import JobResult
31from plainbox.impl.testing_utils import make_job32from plainbox.impl.testing_utils import make_io_log, make_job
32from plainbox.impl.session import SessionStateEncoder33from plainbox.impl.session import SessionStateEncoder
3334
3435
@@ -50,22 +51,24 @@
50 self.assertIsNone(result.return_code)51 self.assertIsNone(result.return_code)
5152
52 def test_everything(self):53 def test_everything(self):
53 result = JobResult({54 with TemporaryDirectory() as scratch_dir:
54 'job': self.job,55 result = JobResult({
55 'outcome': JobResult.OUTCOME_PASS,56 'job': self.job,
56 'comments': "it said blah",57 'outcome': JobResult.OUTCOME_PASS,
57 'io_log': ((0, 'stdout', b'blah\n'),),58 'comments': "it said blah",
58 'return_code': 059 'io_log': make_io_log(((0, 'stdout', b'blah\n'),),
59 })60 scratch_dir),
60 self.assertEqual(str(result), "A: pass")61 'return_code': 0
61 self.assertEqual(repr(result), (62 })
62 "<JobResult job:<JobDefinition name:'A' plugin:'dummy'>"63 self.assertEqual(str(result), "A: pass")
63 " outcome:'pass'>"))64 self.assertEqual(repr(result), (
64 self.assertIs(result.job, self.job)65 "<JobResult job:<JobDefinition name:'A' plugin:'dummy'>"
65 self.assertEqual(result.outcome, JobResult.OUTCOME_PASS)66 " outcome:'pass'>"))
66 self.assertEqual(result.comments, "it said blah")67 self.assertIs(result.job, self.job)
67 self.assertEqual(result.io_log, ((0, 'stdout', b'blah\n'),))68 self.assertEqual(result.outcome, JobResult.OUTCOME_PASS)
68 self.assertEqual(result.return_code, 0)69 self.assertEqual(result.comments, "it said blah")
70 self.assertEqual(result.io_log, ((0, 'stdout', b'blah\n'),))
71 self.assertEqual(result.return_code, 0)
6972
70 def test_encode(self):73 def test_encode(self):
71 result = JobResult({74 result = JobResult({
@@ -99,7 +102,8 @@
99 "return_code": 0102 "return_code": 0
100 }103 }
101 }"""104 }"""
102 result_dec = json.loads(raw_json, object_hook=SessionStateEncoder().dict_to_object)105 result_dec = json.loads(raw_json,
106 object_hook=SessionStateEncoder().dict_to_object)
103 self.assertIsInstance(result_dec, JobResult)107 self.assertIsInstance(result_dec, JobResult)
104 self.assertEqual(result_dec.job.name, "__audio__")108 self.assertEqual(result_dec.job.name, "__audio__")
105 self.assertEqual(result_dec.outcome, JobResult.OUTCOME_PASS)109 self.assertEqual(result_dec.outcome, JobResult.OUTCOME_PASS)
106110
=== modified file 'plainbox/plainbox/impl/test_runner.py'
--- plainbox/plainbox/impl/test_runner.py 2013-02-22 16:26:25 +0000
+++ plainbox/plainbox/impl/test_runner.py 2013-03-07 16:10:38 +0000
@@ -73,11 +73,11 @@
73 with TestIO(combined=False) as io:73 with TestIO(combined=False) as io:
74 obj = FallbackCommandOutputPrinter("example")74 obj = FallbackCommandOutputPrinter("example")
75 # Whatever gets printed by the job...75 # Whatever gets printed by the job...
76 obj.on_line('stdout', 'line 1\n')76 obj.on_line('stdout', b'line 1\n')
77 obj.on_line('stderr', 'line 1\n')77 obj.on_line('stderr', b'line 1\n')
78 obj.on_line('stdout', 'line 2\n')78 obj.on_line('stdout', b'line 2\n')
79 obj.on_line('stdout', 'line 3\n')79 obj.on_line('stdout', b'line 3\n')
80 obj.on_line('stderr', 'line 2\n')80 obj.on_line('stderr', b'line 2\n')
81 # Gets printed to stdout _only_, stderr is combined with stdout here81 # Gets printed to stdout _only_, stderr is combined with stdout here
82 self.assertEqual(io.stdout, (82 self.assertEqual(io.stdout, (
83 "(job example, <stdout:00001>) line 1\n"83 "(job example, <stdout:00001>) line 1\n"
8484
=== modified file 'plainbox/plainbox/impl/test_session.py'
--- plainbox/plainbox/impl/test_session.py 2013-02-22 16:26:25 +0000
+++ plainbox/plainbox/impl/test_session.py 2013-03-07 16:10:38 +0000
@@ -25,18 +25,22 @@
25"""25"""
2626
27import json27import json
28import os
29import tempfile
30import shutil
2831
32from tempfile import TemporaryDirectory
29from unittest import TestCase33from unittest import TestCase
3034
35from plainbox.impl.depmgr import DependencyMissingError
31from plainbox.impl.resource import Resource36from plainbox.impl.resource import Resource
32from plainbox.impl.result import JobResult37from plainbox.impl.result import JobResult
33from plainbox.impl.session import JobReadinessInhibitor38from plainbox.impl.session import JobReadinessInhibitor
34from plainbox.impl.session import JobState39from plainbox.impl.session import JobState
35from plainbox.impl.session import SessionState40from plainbox.impl.session import SessionState
41from plainbox.impl.session import SessionStateEncoder
36from plainbox.impl.session import UndesiredJobReadinessInhibitor42from plainbox.impl.session import UndesiredJobReadinessInhibitor
37from plainbox.impl.session import SessionStateEncoder43from plainbox.impl.testing_utils import make_io_log, make_job, make_job_result
38from plainbox.impl.testing_utils import make_job
39from plainbox.impl.testing_utils import make_job_result
4044
4145
42class JobReadinessInhibitorTests(TestCase):46class JobReadinessInhibitorTests(TestCase):
@@ -236,7 +240,8 @@
236 }240 }
237 }241 }
238 }"""242 }"""
239 job_dec = json.loads(raw_json, object_hook=SessionStateEncoder().dict_to_object)243 job_dec = json.loads(raw_json,
244 object_hook=SessionStateEncoder().dict_to_object)
240 self.assertIsInstance(job_dec, JobState)245 self.assertIsInstance(job_dec, JobState)
241 self.assertEqual(repr(job_dec._result),246 self.assertEqual(repr(job_dec._result),
242 ("<JobResult job:<JobDefinition name:'X'"247 ("<JobResult job:<JobDefinition name:'X'"
@@ -271,6 +276,23 @@
271 self.assertIsNone(self.session_state.session_dir)276 self.assertIsNone(self.session_state.session_dir)
272277
273278
279class RegressionTests(TestCase):
280 # Tests for bugfixes
281
282 def test_crash_in_update_desired_job_list(self):
283 # This checks if a DependencyError can cause crash
284 # update_desired_job_list() with a ValueError, in certain conditions.
285 A = make_job('A', depends='X')
286 L = make_job('L', plugin='local')
287 session = SessionState([A, L])
288 problems = session.update_desired_job_list([A, L])
289 # We should get exactly one DependencyMissingError related to job A and
290 # the undefined job X (that is presumably defined by the local job L)
291 self.assertEqual(len(problems), 1)
292 self.assertIsInstance(problems[0], DependencyMissingError)
293 self.assertIs(problems[0].affected_job, A)
294
295
274class SessionStateSpecialTests(TestCase):296class SessionStateSpecialTests(TestCase):
275297
276 # NOTE: those tests are essential. They allow testing the behavior of298 # NOTE: those tests are essential. They allow testing the behavior of
@@ -326,6 +348,7 @@
326 self.job_Y = make_job("Y")348 self.job_Y = make_job("Y")
327 self.job_list = [self.job_A, self.job_R, self.job_X, self.job_Y]349 self.job_list = [self.job_A, self.job_R, self.job_X, self.job_Y]
328 self.session = SessionState(self.job_list)350 self.session = SessionState(self.job_list)
351 self.scratch_dir = TemporaryDirectory()
329352
330 def job_state(self, name):353 def job_state(self, name):
331 # A helper function to avoid overly long expressions354 # A helper function to avoid overly long expressions
@@ -391,7 +414,8 @@
391 # session.414 # session.
392 result_R = JobResult({415 result_R = JobResult({
393 'job': self.job_R,416 'job': self.job_R,
394 'io_log': ((0, 'stdout', b"attr: value\n"),)417 'io_log': make_io_log(((0, 'stdout', b"attr: value\n"),),
418 self.scratch_dir)
395 })419 })
396 self.session.update_job_result(self.job_R, result_R)420 self.session.update_job_result(self.job_R, result_R)
397 # The most obvious thing that can happen, is that the result is simply421 # The most obvious thing that can happen, is that the result is simply
@@ -439,12 +463,13 @@
439 # another proper record in that order.463 # another proper record in that order.
440 result_R = JobResult({464 result_R = JobResult({
441 'job': self.job_R,465 'job': self.job_R,
442 'io_log': (466 'io_log': make_io_log((
443 (0, 'stdout', b"attr: value-1\n"),467 (0, 'stdout', b"attr: value-1\n"),
444 (1, 'stdout', b"\n"),468 (1, 'stdout', b"\n"),
445 (1, 'stdout', b"I-sound-like-a-broken-record\n"),469 (1, 'stdout', b"I-sound-like-a-broken-record\n"),
446 (1, 'stdout', b"\n"),470 (1, 'stdout', b"\n"),
447 (1, 'stdout', b"attr: value-2\n"))471 (1, 'stdout', b"attr: value-2\n")),
472 self.scratch_dir)
448 })473 })
449 # Since we cannot control the output of scripts and people indeed make474 # Since we cannot control the output of scripts and people indeed make
450 # mistakes a warning is issued but no exception is raised to the475 # mistakes a warning is issued but no exception is raised to the
@@ -521,7 +546,8 @@
521 self.session.update_desired_job_list([self.job_A])546 self.session.update_desired_job_list([self.job_A])
522 result_R = JobResult({547 result_R = JobResult({
523 'job': self.job_R,548 'job': self.job_R,
524 'io_log': ((0, 'stdout', b'attr: wrong value\n'),)549 'io_log': make_io_log(((0, 'stdout', b'attr: wrong value\n'),),
550 self.scratch_dir)
525 })551 })
526 self.session.update_job_result(self.job_R, result_R)552 self.session.update_job_result(self.job_R, result_R)
527 # Now A is inhibited by FAILED_RESOURCE553 # Now A is inhibited by FAILED_RESOURCE
@@ -538,7 +564,8 @@
538 # presented to a session that has some resources from that job already.564 # presented to a session that has some resources from that job already.
539 result_R_old = JobResult({565 result_R_old = JobResult({
540 'job': self.job_R,566 'job': self.job_R,
541 'io_log': ((0, 'stdout', b"attr: old value\n"),)567 'io_log': make_io_log(((0, 'stdout', b"attr: old value\n"),),
568 self.scratch_dir)
542 })569 })
543 self.session.update_job_result(self.job_R, result_R_old)570 self.session.update_job_result(self.job_R, result_R_old)
544 # So here the old result is stored into a new 'R' resource571 # So here the old result is stored into a new 'R' resource
@@ -547,7 +574,8 @@
547 # Now we present the second result for the same job574 # Now we present the second result for the same job
548 result_R_new = JobResult({575 result_R_new = JobResult({
549 'job': self.job_R,576 'job': self.job_R,
550 'io_log': ((0, 'stdout', b"attr: new value\n"),)577 'io_log': make_io_log(((0, 'stdout', b"attr: new value\n"),),
578 self.scratch_dir)
551 })579 })
552 self.session.update_job_result(self.job_R, result_R_new)580 self.session.update_job_result(self.job_R, result_R_new)
553 # What should happen here is that the R resource is entirely replaced581 # What should happen here is that the R resource is entirely replaced
@@ -557,3 +585,149 @@
557 self.assertEqual(self.session._resource_map, expected_after)585 self.assertEqual(self.session._resource_map, expected_after)
558586
559 # TODO: add tests for local jobs587 # TODO: add tests for local jobs
588
589 def tearDown(self):
590 self.scratch_dir.cleanup()
591
592
593class SessionStateLocalStorageTests(TestCase):
594
595 def setUp(self):
596 # session data are kept in XDG_CACHE_HOME/plainbox/.session
597 # To avoid resuming a real session, we have to select a temporary
598 # location instead
599 self._sandbox = tempfile.mkdtemp()
600 self._env = os.environ
601 os.environ['XDG_CACHE_HOME'] = self._sandbox
602
603 def job_state(self, name):
604 # A helper function to avoid overly long expressions
605 return self.session.job_state_map[name]
606
607 def test_persistent_save(self):
608 self.job_A = make_job("A")
609 self.job_list = [self.job_A]
610 self.session = SessionState(self.job_list)
611 result_A = JobResult({
612 'job': self.job_A,
613 'outcome': JobResult.OUTCOME_PASS,
614 'comments': 'All good',
615 'return_code': 0,
616 'io_log': ((0, 'stdout', "Success !\n"),)
617 })
618 session_json_text = """{
619 "_job_state_map": {
620 "A": {
621 "_job": {
622 "data": {
623 "name": "A",
624 "plugin": "dummy",
625 "requires": null,
626 "depends": null
627 },
628 "_class_id": "JOB_DEFINITION"
629 },
630 "_result": {
631 "data": {
632 "job": {
633 "data": {
634 "name": "A",
635 "plugin": "dummy",
636 "requires": null,
637 "depends": null
638 },
639 "_class_id": "JOB_DEFINITION"
640 },
641 "outcome": "pass",
642 "return_code": 0,
643 "comments": "All good",
644 "io_log": [
645 [
646 0,
647 "stdout",
648 "Success !\\n"
649 ]
650 ]
651 },
652 "_class_id": "JOB_RESULT"
653 },
654 "_class_id": "JOB_STATE"
655 }
656 },
657 "_desired_job_list": [
658 {
659 "data": {
660 "name": "A",
661 "plugin": "dummy",
662 "requires": null,
663 "depends": null
664 },
665 "_class_id": "JOB_DEFINITION"
666 }
667 ],
668 "_class_id": "SESSION_STATE"
669 }"""
670 self.session.open()
671 self.session.update_desired_job_list([self.job_A])
672 self.session.update_job_result(self.job_A, result_A)
673 self.session.persistent_save()
674 session_file = self.session.previous_session_file()
675 self.session.close()
676 self.assertIsNotNone(session_file)
677 with open(session_file) as f:
678 raw_json = json.load(f)
679 self.maxDiff = None
680 self.assertEqual(raw_json, json.loads(session_json_text))
681
682 def test_resume_session(self):
683 # All of the tests below are using one session. The session has four
684 # jobs, Job A depends on a resource provided by job R which has no
685 # dependencies at all. Both Job X and Y depend on job A.
686 #
687 # A -(resource dependency)-> R
688 #
689 # X -(direct dependency) -> A
690 #
691 # Y -(direct dependency) -> A
692 self.job_A = make_job("A", requires="R.attr == 'value'")
693 self.job_A_expr = self.job_A.get_resource_program().expression_list[0]
694 self.job_R = make_job("R", plugin="resource")
695 self.job_X = make_job("X", depends='A')
696 self.job_Y = make_job("Y", depends='A')
697 self.job_list = [self.job_A, self.job_R, self.job_X, self.job_Y]
698 # Create a new session (session_dir is empty)
699 self.session = SessionState(self.job_list)
700 result_R = JobResult({
701 'job': self.job_R,
702 'io_log': make_io_log(((0, 'stdout', b"attr: value\n"),),
703 self._sandbox)
704 })
705 result_A = JobResult({
706 'job': self.job_A,
707 'outcome': JobResult.OUTCOME_PASS
708 })
709 result_X = JobResult({
710 'job': self.job_X,
711 'outcome': JobResult.OUTCOME_PASS
712 })
713 # Job Y can't start as it requires job A
714 self.assertFalse(self.job_state('Y').can_start())
715 self.session.update_desired_job_list([self.job_X, self.job_Y])
716 self.session.open()
717 self.session.update_job_result(self.job_R, result_R)
718 self.session.update_job_result(self.job_A, result_A)
719 self.session.update_job_result(self.job_X, result_X)
720 self.session.persistent_save()
721 self.session.close()
722 # Create a new session (session_dir should contain session data)
723 self.session = SessionState(self.job_list)
724 self.session.open()
725 # Resume the previous session
726 self.session.resume()
727 # This time job Y can start
728 self.assertTrue(self.job_state('Y').can_start())
729 self.session.close()
730
731 def tearDown(self):
732 shutil.rmtree(self._sandbox)
733 os.environ = self._env
560734
=== modified file 'plainbox/plainbox/impl/testing_utils.py'
--- plainbox/plainbox/impl/testing_utils.py 2013-01-30 21:43:05 +0000
+++ plainbox/plainbox/impl/testing_utils.py 2013-03-07 16:10:38 +0000
@@ -18,19 +18,31 @@
18# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.18# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
1919
20"""20"""
21plainbox.impl.testing_utils21:mod:`plainbox.impl.testing_utils` -- plainbox specific test tools
22===========================22==================================================================
2323
24Internal implementation of plainbox24.. warning::
2525
26 * THIS MODULE DOES NOT HAVE STABLE PUBLIC API *26 THIS MODULE DOES NOT HAVE STABLE PUBLIC API
27"""27"""
2828
29import inspect29import inspect
30from tempfile import NamedTemporaryFile
3031
31from plainbox.impl.job import JobDefinition32from plainbox.impl.job import JobDefinition
32from plainbox.impl.result import JobResult33from plainbox.impl.result import JobResult
33from plainbox.impl.rfc822 import Origin34from plainbox.impl.rfc822 import Origin
35from plainbox.impl.runner import io_log_write
36
37
38def make_io_log(io_log, io_log_dir):
39 """
40 Make the io logs serialization to json and return the saved file pathname
41 WARNING: The caller has to remove the file once done with it!
42 """
43 with NamedTemporaryFile(mode='w+t', delete=False) as stream:
44 io_log_write(io_log, stream)
45 return stream.name
3446
3547
36def make_job(name, plugin="dummy", requires=None, depends=None):48def make_job(name, plugin="dummy", requires=None, depends=None):
3749
=== removed file 'plainbox/plainbox/impl/utils.py.moved'
--- plainbox/plainbox/impl/utils.py.moved 2013-02-22 16:26:25 +0000
+++ plainbox/plainbox/impl/utils.py.moved 1970-01-01 00:00:00 +0000
@@ -1,58 +0,0 @@
1# This file is part of Checkbox.
2#
3# Copyright 2012 Canonical Ltd.
4# Written by:
5# Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
6#
7# Checkbox is free software: you can redistribute it and/or modify
8# it under the terms of the GNU General Public License as published by
9# the Free Software Foundation, either version 3 of the License, or
10# (at your option) any later version.
11#
12# Checkbox is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU General Public License for more details.
16#
17# You should have received a copy of the GNU General Public License
18# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
19
20"""
21plainbox.impl.utils
22===================
23
24Internal implementation of plainbox
25
26 * THIS MODULE DOES NOT HAVE STABLE PUBLIC API *
27"""
28
29from io import TextIOWrapper
30from logging import getLogger
31
32from plainbox.impl.job import JobDefinition
33from plainbox.impl.rfc822 import load_rfc822_records
34
35
36logger = getLogger("plainbox.utils")
37
38
39def load(somewhere):
40 if isinstance(somewhere, str):
41 # Load data from a file with the given name
42 filename = somewhere
43 with open(filename, 'rt', encoding='UTF-8') as stream:
44 return load(stream)
45 if isinstance(somewhere, TextIOWrapper):
46 stream = somewhere
47 logger.debug("Loading jobs definitions from %r...", stream.name)
48 record_list = load_rfc822_records(stream)
49 job_list = []
50 for record in record_list:
51 job = JobDefinition.from_rfc822_record(record)
52 logger.debug("Loaded %r", job)
53 job_list.append(job)
54 return job_list
55 else:
56 raise TypeError(
57 "Unsupported type of 'somewhere': {!r}".format(
58 type(somewhere)))
590
=== modified file 'plainbox/plainbox/public.py'
--- plainbox/plainbox/public.py 2013-02-22 16:26:25 +0000
+++ plainbox/plainbox/public.py 2013-03-07 16:10:38 +0000
@@ -18,8 +18,8 @@
18# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.18# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
1919
20"""20"""
21plainbox.public21:mod:`plainbox.public` -- public, stable API
22===============22============================================
2323
24Public, high-level API for third party developers.24Public, high-level API for third party developers.
2525
2626
=== modified file 'plainbox/plainbox/testing_utils/__init__.py'
--- plainbox/plainbox/testing_utils/__init__.py 2013-01-30 21:43:05 +0000
+++ plainbox/plainbox/testing_utils/__init__.py 2013-03-07 16:10:38 +0000
@@ -18,8 +18,6 @@
18# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.18# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
1919
20"""20"""
21plainbox.testing_utils21:mod:`plainbox.testing_utils` - generic testing utilities
22======================22=========================================================
23
24Testing utilities for internals of plainbox
25"""23"""
2624
=== modified file 'plainbox/plainbox/testing_utils/cwd.py'
--- plainbox/plainbox/testing_utils/cwd.py 2013-01-30 21:43:05 +0000
+++ plainbox/plainbox/testing_utils/cwd.py 2013-03-07 16:10:38 +0000
@@ -18,8 +18,8 @@
18# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.18# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
1919
20"""20"""
21plainbox.testing_utils.cwd21:mod:`plainbox.testing_utils.cwd` -- tools for testing in another directory
22==========================22===========================================================================
2323
24Implementation of context managers for working in another directory24Implementation of context managers for working in another directory
25"""25"""
2626
=== modified file 'plainbox/plainbox/testing_utils/io.py'
--- plainbox/plainbox/testing_utils/io.py 2013-01-30 21:43:05 +0000
+++ plainbox/plainbox/testing_utils/io.py 2013-03-07 16:10:38 +0000
@@ -18,8 +18,8 @@
18# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.18# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
1919
20"""20"""
21plainbox.testing_utils.io21:mod:`plainbox.testing_utils.io` -- tools for testing IO
22=========================22========================================================
2323
24Implementation of context managers for observing IO24Implementation of context managers for observing IO
25"""25"""
2626
=== modified file 'plainbox/plainbox/testing_utils/testcases.py'
--- plainbox/plainbox/testing_utils/testcases.py 2013-01-30 21:43:05 +0000
+++ plainbox/plainbox/testing_utils/testcases.py 2013-03-07 16:10:38 +0000
@@ -18,8 +18,8 @@
18# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.18# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
1919
20"""20"""
21plainbox.testing_utils.testcases21:mod:`plainbox.testing_utils.testcases` -- additional TestCase classes
22================================22======================================================================
2323
24Implementation of additional TestCase classes that aid in testing.24Implementation of additional TestCase classes that aid in testing.
25"""25"""
@@ -114,7 +114,7 @@
114 parameter values, otherwise this test will behave as if it never existed114 parameter values, otherwise this test will behave as if it never existed
115 (analogous how multiplication by zero works).115 (analogous how multiplication by zero works).
116116
117 ..note::117 .. note::
118 Technical note for tinkerers and subclass authors. Python unittest118 Technical note for tinkerers and subclass authors. Python unittest
119 framework is pretty annoying to work with or extend. In practice you119 framework is pretty annoying to work with or extend. In practice you
120 should always keep the source code (of a particular python version)120 should always keep the source code (of a particular python version)
121121
=== modified file 'plainbox/plainbox/tests.py'
--- plainbox/plainbox/tests.py 2013-02-08 17:02:12 +0000
+++ plainbox/plainbox/tests.py 2013-03-07 16:10:38 +0000
@@ -18,10 +18,8 @@
18# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.18# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
1919
20"""20"""
21plainbox.tests21:mod:`plainbox.tests` -- auxiliary test loaders for plainbox
22==============22============================================================
23
24Auxiliary test loader for plainbox
25"""23"""
2624
27from unittest.loader import defaultTestLoader25from unittest.loader import defaultTestLoader
2826
=== modified file 'plainbox/plainbox/vendor/__init__.py'
--- plainbox/plainbox/vendor/__init__.py 2012-11-29 18:59:46 +0000
+++ plainbox/plainbox/vendor/__init__.py 2013-03-07 16:10:38 +0000
@@ -0,0 +1,28 @@
1# This file is part of Checkbox.
2#
3# Copyright 2013 Canonical Ltd.
4# Written by:
5# Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
6#
7# Checkbox is free software: you can redistribute it and/or modify
8# it under the terms of the GNU General Public License as published by
9# the Free Software Foundation, either version 3 of the License, or
10# (at your option) any later version.
11#
12# Checkbox is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU General Public License for more details.
16#
17# You should have received a copy of the GNU General Public License
18# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
19
20"""
21:mod:`plainbox.vendor` -- vendorized packages
22=============================================
23
24This module contains external packages that were vendorized (shipped with a
25tree of another project) to simplify dependency management. There is no problem
26with expressing those dependencies at pypi level but it would be annoying to
27have to first package and introduce them to Ubuntu.
28"""
029
=== modified file 'plainbox/plainbox/vendor/extcmd/__init__.py'
--- plainbox/plainbox/vendor/extcmd/__init__.py 2013-02-22 16:26:25 +0000
+++ plainbox/plainbox/vendor/extcmd/__init__.py 2013-03-07 16:10:38 +0000
@@ -18,8 +18,8 @@
18# along with this program. If not, see <http://www.gnu.org/licenses/>.18# along with this program. If not, see <http://www.gnu.org/licenses/>.
1919
20"""20"""
21extcmd - subprocess with advanced output processing21:mod:`plainbox.vendor.extcmd` - subprocess with advanced output processing
22===================================================22^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2323
24Unlike subprocess, which just gives you a lump of output at the end, extcmd24Unlike subprocess, which just gives you a lump of output at the end, extcmd
25allows you to get callbacks (via a delegate class) on all IO.25allows you to get callbacks (via a delegate class) on all IO.
2626
=== modified file 'plainbox/setup.py'
--- plainbox/setup.py 2013-02-22 16:26:25 +0000
+++ plainbox/setup.py 2013-03-07 16:10:38 +0000
@@ -31,6 +31,9 @@
31 author_email="zygmunt.krynicki@canonical.com",31 author_email="zygmunt.krynicki@canonical.com",
32 license="GPLv3+",32 license="GPLv3+",
33 description="Simple replacement for checkbox",33 description="Simple replacement for checkbox",
34 tests_require=[
35 'mock',
36 ],
34 entry_points={37 entry_points={
35 'console_scripts': [38 'console_scripts': [
36 'plainbox=plainbox.public:main',39 'plainbox=plainbox.public:main',
3740
=== modified file 'po/ace.po'
--- po/ace.po 2013-02-22 16:26:25 +0000
+++ po/ace.po 2013-03-07 16:10:38 +0000
@@ -14,8 +14,8 @@
14"MIME-Version: 1.0\n"14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"16"Content-Transfer-Encoding: 8bit\n"
17"X-Launchpad-Export-Date: 2013-02-15 04:31+0000\n"17"X-Launchpad-Export-Date: 2013-02-23 04:38+0000\n"
18"X-Generator: Launchpad (build 16491)\n"18"X-Generator: Launchpad (build 16506)\n"
1919
20#. Title of the user interface20#. Title of the user interface
21#: ../gtk/checkbox-gtk.ui.h:1 ../qt/checkbox-qt.desktop.in.h:121#: ../gtk/checkbox-gtk.ui.h:1 ../qt/checkbox-qt.desktop.in.h:1
@@ -964,7 +964,7 @@
964msgstr ""964msgstr ""
965965
966#. description966#. description
967#: ../jobs/input.txt.in:23967#: ../jobs/input.txt.in:22
968msgid ""968msgid ""
969"PURPOSE:\n"969"PURPOSE:\n"
970" This test will test your pointing device\n"970" This test will test your pointing device\n"
@@ -976,7 +976,7 @@
976msgstr ""976msgstr ""
977977
978#. description978#. description
979#: ../jobs/input.txt.in:36979#: ../jobs/input.txt.in:35
980msgid ""980msgid ""
981"PURPOSE:\n"981"PURPOSE:\n"
982" This test will test your keyboard\n"982" This test will test your keyboard\n"
983983
=== modified file 'po/af.po'
--- po/af.po 2013-02-22 16:26:25 +0000
+++ po/af.po 2013-03-07 16:10:38 +0000
@@ -14,8 +14,8 @@
14"MIME-Version: 1.0\n"14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"16"Content-Transfer-Encoding: 8bit\n"
17"X-Launchpad-Export-Date: 2013-02-15 04:31+0000\n"17"X-Launchpad-Export-Date: 2013-02-23 04:38+0000\n"
18"X-Generator: Launchpad (build 16491)\n"18"X-Generator: Launchpad (build 16506)\n"
1919
20#. Title of the user interface20#. Title of the user interface
21#: ../gtk/checkbox-gtk.ui.h:1 ../qt/checkbox-qt.desktop.in.h:121#: ../gtk/checkbox-gtk.ui.h:1 ../qt/checkbox-qt.desktop.in.h:1
@@ -964,7 +964,7 @@
964msgstr ""964msgstr ""
965965
966#. description966#. description
967#: ../jobs/input.txt.in:23967#: ../jobs/input.txt.in:22
968msgid ""968msgid ""
969"PURPOSE:\n"969"PURPOSE:\n"
970" This test will test your pointing device\n"970" This test will test your pointing device\n"
@@ -976,7 +976,7 @@
976msgstr ""976msgstr ""
977977
978#. description978#. description
979#: ../jobs/input.txt.in:36979#: ../jobs/input.txt.in:35
980msgid ""980msgid ""
981"PURPOSE:\n"981"PURPOSE:\n"
982" This test will test your keyboard\n"982" This test will test your keyboard\n"
983983
=== modified file 'po/am.po'
--- po/am.po 2013-02-22 16:26:25 +0000
+++ po/am.po 2013-03-07 16:10:38 +0000
@@ -14,8 +14,8 @@
14"MIME-Version: 1.0\n"14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"16"Content-Transfer-Encoding: 8bit\n"
17"X-Launchpad-Export-Date: 2013-02-15 04:31+0000\n"17"X-Launchpad-Export-Date: 2013-02-23 04:38+0000\n"
18"X-Generator: Launchpad (build 16491)\n"18"X-Generator: Launchpad (build 16506)\n"
1919
20#. Title of the user interface20#. Title of the user interface
21#: ../gtk/checkbox-gtk.ui.h:1 ../qt/checkbox-qt.desktop.in.h:121#: ../gtk/checkbox-gtk.ui.h:1 ../qt/checkbox-qt.desktop.in.h:1
@@ -964,7 +964,7 @@
964msgstr ""964msgstr ""
965965
966#. description966#. description
967#: ../jobs/input.txt.in:23967#: ../jobs/input.txt.in:22
968msgid ""968msgid ""
969"PURPOSE:\n"969"PURPOSE:\n"
970" This test will test your pointing device\n"970" This test will test your pointing device\n"
@@ -976,7 +976,7 @@
976msgstr ""976msgstr ""
977977
978#. description978#. description
979#: ../jobs/input.txt.in:36979#: ../jobs/input.txt.in:35
980msgid ""980msgid ""
981"PURPOSE:\n"981"PURPOSE:\n"
982" This test will test your keyboard\n"982" This test will test your keyboard\n"
983983
=== modified file 'po/ar.po'
--- po/ar.po 2013-02-22 16:26:25 +0000
+++ po/ar.po 2013-03-07 16:10:38 +0000
@@ -14,8 +14,8 @@
14"MIME-Version: 1.0\n"14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"16"Content-Transfer-Encoding: 8bit\n"
17"X-Launchpad-Export-Date: 2013-02-15 04:31+0000\n"17"X-Launchpad-Export-Date: 2013-02-23 04:38+0000\n"
18"X-Generator: Launchpad (build 16491)\n"18"X-Generator: Launchpad (build 16506)\n"
1919
20#. Title of the user interface20#. Title of the user interface
21#: ../gtk/checkbox-gtk.ui.h:1 ../qt/checkbox-qt.desktop.in.h:121#: ../gtk/checkbox-gtk.ui.h:1 ../qt/checkbox-qt.desktop.in.h:1
@@ -1139,7 +1139,7 @@
1139msgstr ""1139msgstr ""
11401140
1141#. description1141#. description
1142#: ../jobs/input.txt.in:231142#: ../jobs/input.txt.in:22
1143msgid ""1143msgid ""
1144"PURPOSE:\n"1144"PURPOSE:\n"
1145" This test will test your pointing device\n"1145" This test will test your pointing device\n"
@@ -1151,7 +1151,7 @@
1151msgstr ""1151msgstr ""
11521152
1153#. description1153#. description
1154#: ../jobs/input.txt.in:361154#: ../jobs/input.txt.in:35
1155msgid ""1155msgid ""
1156"PURPOSE:\n"1156"PURPOSE:\n"
1157" This test will test your keyboard\n"1157" This test will test your keyboard\n"
11581158
=== modified file 'po/ast.po'
--- po/ast.po 2013-02-22 16:26:25 +0000
+++ po/ast.po 2013-03-07 16:10:38 +0000
@@ -14,8 +14,8 @@
14"MIME-Version: 1.0\n"14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"16"Content-Transfer-Encoding: 8bit\n"
17"X-Launchpad-Export-Date: 2013-02-15 04:31+0000\n"17"X-Launchpad-Export-Date: 2013-02-23 04:38+0000\n"
18"X-Generator: Launchpad (build 16491)\n"18"X-Generator: Launchpad (build 16506)\n"
19"Language: ast\n"19"Language: ast\n"
2020
21#. Title of the user interface21#. Title of the user interface
@@ -1324,7 +1324,7 @@
1324msgstr "Axunta'l rexistru de depuración del instalador si existe."1324msgstr "Axunta'l rexistru de depuración del instalador si existe."
13251325
1326#. description1326#. description
1327#: ../jobs/input.txt.in:231327#: ../jobs/input.txt.in:22
1328msgid ""1328msgid ""
1329"PURPOSE:\n"1329"PURPOSE:\n"
1330" This test will test your pointing device\n"1330" This test will test your pointing device\n"
@@ -1343,7 +1343,7 @@
1343" ¿Comportóse'l preséu de punteru s'esperaba?"1343" ¿Comportóse'l preséu de punteru s'esperaba?"
13441344
1345#. description1345#. description
1346#: ../jobs/input.txt.in:361346#: ../jobs/input.txt.in:35
1347msgid ""1347msgid ""
1348"PURPOSE:\n"1348"PURPOSE:\n"
1349" This test will test your keyboard\n"1349" This test will test your keyboard\n"
13501350
=== modified file 'po/az.po'
--- po/az.po 2013-02-22 16:26:25 +0000
+++ po/az.po 2013-03-07 16:10:38 +0000
@@ -14,8 +14,8 @@
14"MIME-Version: 1.0\n"14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"16"Content-Transfer-Encoding: 8bit\n"
17"X-Launchpad-Export-Date: 2013-02-15 04:31+0000\n"17"X-Launchpad-Export-Date: 2013-02-23 04:38+0000\n"
18"X-Generator: Launchpad (build 16491)\n"18"X-Generator: Launchpad (build 16506)\n"
1919
20#. Title of the user interface20#. Title of the user interface
21#: ../gtk/checkbox-gtk.ui.h:1 ../qt/checkbox-qt.desktop.in.h:121#: ../gtk/checkbox-gtk.ui.h:1 ../qt/checkbox-qt.desktop.in.h:1
@@ -967,7 +967,7 @@
967msgstr ""967msgstr ""
968968
969#. description969#. description
970#: ../jobs/input.txt.in:23970#: ../jobs/input.txt.in:22
971msgid ""971msgid ""
972"PURPOSE:\n"972"PURPOSE:\n"
973" This test will test your pointing device\n"973" This test will test your pointing device\n"
@@ -979,7 +979,7 @@
979msgstr ""979msgstr ""
980980
981#. description981#. description
982#: ../jobs/input.txt.in:36982#: ../jobs/input.txt.in:35
983msgid ""983msgid ""
984"PURPOSE:\n"984"PURPOSE:\n"
985" This test will test your keyboard\n"985" This test will test your keyboard\n"
986986
=== modified file 'po/be.po'
--- po/be.po 2013-02-22 16:26:25 +0000
+++ po/be.po 2013-03-07 16:10:38 +0000
@@ -14,8 +14,8 @@
14"MIME-Version: 1.0\n"14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"16"Content-Transfer-Encoding: 8bit\n"
17"X-Launchpad-Export-Date: 2013-02-15 04:31+0000\n"17"X-Launchpad-Export-Date: 2013-02-23 04:38+0000\n"
18"X-Generator: Launchpad (build 16491)\n"18"X-Generator: Launchpad (build 16506)\n"
1919
20#. Title of the user interface20#. Title of the user interface
21#: ../gtk/checkbox-gtk.ui.h:1 ../qt/checkbox-qt.desktop.in.h:121#: ../gtk/checkbox-gtk.ui.h:1 ../qt/checkbox-qt.desktop.in.h:1
@@ -971,7 +971,7 @@
971msgstr ""971msgstr ""
972972
973#. description973#. description
974#: ../jobs/input.txt.in:23974#: ../jobs/input.txt.in:22
975msgid ""975msgid ""
976"PURPOSE:\n"976"PURPOSE:\n"
977" This test will test your pointing device\n"977" This test will test your pointing device\n"
@@ -983,7 +983,7 @@
983msgstr ""983msgstr ""
984984
985#. description985#. description
986#: ../jobs/input.txt.in:36986#: ../jobs/input.txt.in:35
987msgid ""987msgid ""
988"PURPOSE:\n"988"PURPOSE:\n"
989" This test will test your keyboard\n"989" This test will test your keyboard\n"
990990
=== modified file 'po/bg.po'
--- po/bg.po 2013-02-22 16:26:25 +0000
+++ po/bg.po 2013-03-07 16:10:38 +0000
@@ -14,8 +14,8 @@
14"MIME-Version: 1.0\n"14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"16"Content-Transfer-Encoding: 8bit\n"
17"X-Launchpad-Export-Date: 2013-02-15 04:32+0000\n"17"X-Launchpad-Export-Date: 2013-02-23 04:38+0000\n"
18"X-Generator: Launchpad (build 16491)\n"18"X-Generator: Launchpad (build 16506)\n"
1919
20#. Title of the user interface20#. Title of the user interface
21#: ../gtk/checkbox-gtk.ui.h:1 ../qt/checkbox-qt.desktop.in.h:121#: ../gtk/checkbox-gtk.ui.h:1 ../qt/checkbox-qt.desktop.in.h:1
@@ -968,7 +968,7 @@
968msgstr ""968msgstr ""
969969
970#. description970#. description
971#: ../jobs/input.txt.in:23971#: ../jobs/input.txt.in:22
972msgid ""972msgid ""
973"PURPOSE:\n"973"PURPOSE:\n"
974" This test will test your pointing device\n"974" This test will test your pointing device\n"
@@ -980,7 +980,7 @@
980msgstr ""980msgstr ""
981981
982#. description982#. description
983#: ../jobs/input.txt.in:36983#: ../jobs/input.txt.in:35
984msgid ""984msgid ""
985"PURPOSE:\n"985"PURPOSE:\n"
986" This test will test your keyboard\n"986" This test will test your keyboard\n"
987987
=== modified file 'po/bn.po'
--- po/bn.po 2013-02-22 16:26:25 +0000
+++ po/bn.po 2013-03-07 16:10:38 +0000
@@ -14,8 +14,8 @@
14"MIME-Version: 1.0\n"14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"16"Content-Transfer-Encoding: 8bit\n"
17"X-Launchpad-Export-Date: 2013-02-15 04:31+0000\n"17"X-Launchpad-Export-Date: 2013-02-23 04:38+0000\n"
18"X-Generator: Launchpad (build 16491)\n"18"X-Generator: Launchpad (build 16506)\n"
1919
20#. Title of the user interface20#. Title of the user interface
21#: ../gtk/checkbox-gtk.ui.h:1 ../qt/checkbox-qt.desktop.in.h:121#: ../gtk/checkbox-gtk.ui.h:1 ../qt/checkbox-qt.desktop.in.h:1
@@ -1215,7 +1215,7 @@
1215msgstr "ইনস্টলার ডিবাগ লগ বিদ্যমান থাকলে সংযুক্ত করা হয়।"1215msgstr "ইনস্টলার ডিবাগ লগ বিদ্যমান থাকলে সংযুক্ত করা হয়।"
12161216
1217#. description1217#. description
1218#: ../jobs/input.txt.in:231218#: ../jobs/input.txt.in:22
1219msgid ""1219msgid ""
1220"PURPOSE:\n"1220"PURPOSE:\n"
1221" This test will test your pointing device\n"1221" This test will test your pointing device\n"
@@ -1234,7 +1234,7 @@
1234" পয়েন্টকৃত ডিভাইসটি কি প্রত্যাশিত ভাবে কাজ করছে?"1234" পয়েন্টকৃত ডিভাইসটি কি প্রত্যাশিত ভাবে কাজ করছে?"
12351235
1236#. description1236#. description
1237#: ../jobs/input.txt.in:361237#: ../jobs/input.txt.in:35
1238msgid ""1238msgid ""
1239"PURPOSE:\n"1239"PURPOSE:\n"
1240" This test will test your keyboard\n"1240" This test will test your keyboard\n"
12411241
=== modified file 'po/bo.po'
--- po/bo.po 2013-02-22 16:26:25 +0000
+++ po/bo.po 2013-03-07 16:10:38 +0000
@@ -14,8 +14,8 @@
14"MIME-Version: 1.0\n"14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"16"Content-Transfer-Encoding: 8bit\n"
17"X-Launchpad-Export-Date: 2013-02-15 04:34+0000\n"17"X-Launchpad-Export-Date: 2013-02-23 04:41+0000\n"
18"X-Generator: Launchpad (build 16491)\n"18"X-Generator: Launchpad (build 16506)\n"
1919
20#. Title of the user interface20#. Title of the user interface
21#: ../gtk/checkbox-gtk.ui.h:1 ../qt/checkbox-qt.desktop.in.h:121#: ../gtk/checkbox-gtk.ui.h:1 ../qt/checkbox-qt.desktop.in.h:1
@@ -964,7 +964,7 @@
964msgstr ""964msgstr ""
965965
966#. description966#. description
967#: ../jobs/input.txt.in:23967#: ../jobs/input.txt.in:22
968msgid ""968msgid ""
969"PURPOSE:\n"969"PURPOSE:\n"
970" This test will test your pointing device\n"970" This test will test your pointing device\n"
@@ -976,7 +976,7 @@
976msgstr ""976msgstr ""
977977
978#. description978#. description
979#: ../jobs/input.txt.in:36979#: ../jobs/input.txt.in:35
980msgid ""980msgid ""
981"PURPOSE:\n"981"PURPOSE:\n"
982" This test will test your keyboard\n"982" This test will test your keyboard\n"
983983
=== modified file 'po/br.po'
--- po/br.po 2013-02-22 16:26:25 +0000
+++ po/br.po 2013-03-07 16:10:38 +0000
@@ -14,8 +14,8 @@
14"MIME-Version: 1.0\n"14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"16"Content-Transfer-Encoding: 8bit\n"
17"X-Launchpad-Export-Date: 2013-02-15 04:32+0000\n"17"X-Launchpad-Export-Date: 2013-02-23 04:38+0000\n"
18"X-Generator: Launchpad (build 16491)\n"18"X-Generator: Launchpad (build 16506)\n"
1919
20#. Title of the user interface20#. Title of the user interface
21#: ../gtk/checkbox-gtk.ui.h:1 ../qt/checkbox-qt.desktop.in.h:121#: ../gtk/checkbox-gtk.ui.h:1 ../qt/checkbox-qt.desktop.in.h:1
@@ -964,7 +964,7 @@
964msgstr ""964msgstr ""
965965
966#. description966#. description
967#: ../jobs/input.txt.in:23967#: ../jobs/input.txt.in:22
968msgid ""968msgid ""
969"PURPOSE:\n"969"PURPOSE:\n"
970" This test will test your pointing device\n"970" This test will test your pointing device\n"
@@ -976,7 +976,7 @@
976msgstr ""976msgstr ""
977977
978#. description978#. description
979#: ../jobs/input.txt.in:36979#: ../jobs/input.txt.in:35
980msgid ""980msgid ""
981"PURPOSE:\n"981"PURPOSE:\n"
982" This test will test your keyboard\n"982" This test will test your keyboard\n"
983983
=== modified file 'po/bs.po'
--- po/bs.po 2013-02-22 16:26:25 +0000
+++ po/bs.po 2013-03-07 16:10:38 +0000
@@ -14,8 +14,8 @@
14"MIME-Version: 1.0\n"14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"16"Content-Transfer-Encoding: 8bit\n"
17"X-Launchpad-Export-Date: 2013-02-15 04:32+0000\n"17"X-Launchpad-Export-Date: 2013-02-23 04:38+0000\n"
18"X-Generator: Launchpad (build 16491)\n"18"X-Generator: Launchpad (build 16506)\n"
1919
20#. Title of the user interface20#. Title of the user interface
21#: ../gtk/checkbox-gtk.ui.h:1 ../qt/checkbox-qt.desktop.in.h:121#: ../gtk/checkbox-gtk.ui.h:1 ../qt/checkbox-qt.desktop.in.h:1
@@ -1271,7 +1271,7 @@
1271msgstr "Prilaže instalerski debug dnevnik ako postoji."1271msgstr "Prilaže instalerski debug dnevnik ako postoji."
12721272
1273#. description1273#. description
1274#: ../jobs/input.txt.in:231274#: ../jobs/input.txt.in:22
1275msgid ""1275msgid ""
1276"PURPOSE:\n"1276"PURPOSE:\n"
1277" This test will test your pointing device\n"1277" This test will test your pointing device\n"
@@ -1290,7 +1290,7 @@
1290"    Da li radi pokazivački uređaj kao što je očekivano?"1290"    Da li radi pokazivački uređaj kao što je očekivano?"
12911291
1292#. description1292#. description
1293#: ../jobs/input.txt.in:361293#: ../jobs/input.txt.in:35
1294msgid ""1294msgid ""
1295"PURPOSE:\n"1295"PURPOSE:\n"
1296" This test will test your keyboard\n"1296" This test will test your keyboard\n"
12971297
=== modified file 'po/ca.po'
--- po/ca.po 2013-02-22 16:26:25 +0000
+++ po/ca.po 2013-03-07 16:10:38 +0000
@@ -14,8 +14,8 @@
14"MIME-Version: 1.0\n"14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"16"Content-Transfer-Encoding: 8bit\n"
17"X-Launchpad-Export-Date: 2013-02-15 04:32+0000\n"17"X-Launchpad-Export-Date: 2013-02-23 04:38+0000\n"
18"X-Generator: Launchpad (build 16491)\n"18"X-Generator: Launchpad (build 16506)\n"
1919
20#~ msgid "$output"20#~ msgid "$output"
21#~ msgstr "$resultat"21#~ msgstr "$resultat"
@@ -989,7 +989,7 @@
989msgstr ""989msgstr ""
990990
991#. description991#. description
992#: ../jobs/input.txt.in:23992#: ../jobs/input.txt.in:22
993msgid ""993msgid ""
994"PURPOSE:\n"994"PURPOSE:\n"
995" This test will test your pointing device\n"995" This test will test your pointing device\n"
@@ -1001,7 +1001,7 @@
1001msgstr ""1001msgstr ""
10021002
1003#. description1003#. description
1004#: ../jobs/input.txt.in:361004#: ../jobs/input.txt.in:35
1005msgid ""1005msgid ""
1006"PURPOSE:\n"1006"PURPOSE:\n"
1007" This test will test your keyboard\n"1007" This test will test your keyboard\n"
10081008
=== modified file 'po/ca@valencia.po'
--- po/ca@valencia.po 2013-02-22 16:26:25 +0000
+++ po/ca@valencia.po 2013-03-07 16:10:38 +0000
@@ -14,8 +14,8 @@
14"MIME-Version: 1.0\n"14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"16"Content-Transfer-Encoding: 8bit\n"
17"X-Launchpad-Export-Date: 2013-02-15 04:35+0000\n"17"X-Launchpad-Export-Date: 2013-02-23 04:42+0000\n"
18"X-Generator: Launchpad (build 16491)\n"18"X-Generator: Launchpad (build 16506)\n"
1919
20#. Title of the user interface20#. Title of the user interface
21#: ../gtk/checkbox-gtk.ui.h:1 ../qt/checkbox-qt.desktop.in.h:121#: ../gtk/checkbox-gtk.ui.h:1 ../qt/checkbox-qt.desktop.in.h:1
@@ -986,7 +986,7 @@
986msgstr ""986msgstr ""
987987
988#. description988#. description
989#: ../jobs/input.txt.in:23989#: ../jobs/input.txt.in:22
990msgid ""990msgid ""
991"PURPOSE:\n"991"PURPOSE:\n"
992" This test will test your pointing device\n"992" This test will test your pointing device\n"
@@ -998,7 +998,7 @@
998msgstr ""998msgstr ""
999999
1000#. description1000#. description
1001#: ../jobs/input.txt.in:361001#: ../jobs/input.txt.in:35
1002msgid ""1002msgid ""
1003"PURPOSE:\n"1003"PURPOSE:\n"
1004" This test will test your keyboard\n"1004" This test will test your keyboard\n"
10051005
=== modified file 'po/ckb.po'
--- po/ckb.po 2013-02-22 16:26:25 +0000
+++ po/ckb.po 2013-03-07 16:10:38 +0000
@@ -14,8 +14,8 @@
14"MIME-Version: 1.0\n"14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"16"Content-Transfer-Encoding: 8bit\n"
17"X-Launchpad-Export-Date: 2013-02-15 04:35+0000\n"17"X-Launchpad-Export-Date: 2013-02-23 04:41+0000\n"
18"X-Generator: Launchpad (build 16491)\n"18"X-Generator: Launchpad (build 16506)\n"
1919
20#. Title of the user interface20#. Title of the user interface
21#: ../gtk/checkbox-gtk.ui.h:1 ../qt/checkbox-qt.desktop.in.h:121#: ../gtk/checkbox-gtk.ui.h:1 ../qt/checkbox-qt.desktop.in.h:1
@@ -964,7 +964,7 @@
964msgstr ""964msgstr ""
965965
966#. description966#. description
967#: ../jobs/input.txt.in:23967#: ../jobs/input.txt.in:22
968msgid ""968msgid ""
969"PURPOSE:\n"969"PURPOSE:\n"
970" This test will test your pointing device\n"970" This test will test your pointing device\n"
@@ -976,7 +976,7 @@
976msgstr ""976msgstr ""
977977
978#. description978#. description
979#: ../jobs/input.txt.in:36979#: ../jobs/input.txt.in:35
980msgid ""980msgid ""
981"PURPOSE:\n"981"PURPOSE:\n"
982" This test will test your keyboard\n"982" This test will test your keyboard\n"
983983
=== modified file 'po/cs.po'
--- po/cs.po 2013-02-22 16:26:25 +0000
+++ po/cs.po 2013-03-07 16:10:38 +0000
@@ -14,8 +14,8 @@
14"MIME-Version: 1.0\n"14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"16"Content-Transfer-Encoding: 8bit\n"
17"X-Launchpad-Export-Date: 2013-02-15 04:32+0000\n"17"X-Launchpad-Export-Date: 2013-02-23 04:38+0000\n"
18"X-Generator: Launchpad (build 16491)\n"18"X-Generator: Launchpad (build 16506)\n"
1919
20#: ../gtk/checkbox-gtk.ui.h:2 ../checkbox_gtk/gtk_interface.py:56120#: ../gtk/checkbox-gtk.ui.h:2 ../checkbox_gtk/gtk_interface.py:561
21msgid "_Test"21msgid "_Test"
@@ -1215,7 +1215,7 @@
1215msgstr "Existuje-li, připojí ladicí záznam instalátoru"1215msgstr "Existuje-li, připojí ladicí záznam instalátoru"
12161216
1217#. description1217#. description
1218#: ../jobs/input.txt.in:231218#: ../jobs/input.txt.in:22
1219msgid ""1219msgid ""
1220"PURPOSE:\n"1220"PURPOSE:\n"
1221" This test will test your pointing device\n"1221" This test will test your pointing device\n"
@@ -1234,7 +1234,7 @@
1234" Fungovalo dotykové zařízení dle očekávání?"1234" Fungovalo dotykové zařízení dle očekávání?"
12351235
1236#. description1236#. description
1237#: ../jobs/input.txt.in:361237#: ../jobs/input.txt.in:35
1238msgid ""1238msgid ""
1239"PURPOSE:\n"1239"PURPOSE:\n"
1240" This test will test your keyboard\n"1240" This test will test your keyboard\n"
12411241
=== modified file 'po/cy.po'
--- po/cy.po 2013-02-22 16:26:25 +0000
+++ po/cy.po 2013-03-07 16:10:38 +0000
@@ -14,8 +14,8 @@
14"MIME-Version: 1.0\n"14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"16"Content-Transfer-Encoding: 8bit\n"
17"X-Launchpad-Export-Date: 2013-02-15 04:34+0000\n"17"X-Launchpad-Export-Date: 2013-02-23 04:41+0000\n"
18"X-Generator: Launchpad (build 16491)\n"18"X-Generator: Launchpad (build 16506)\n"
1919
20#. Title of the user interface20#. Title of the user interface
21#: ../gtk/checkbox-gtk.ui.h:1 ../qt/checkbox-qt.desktop.in.h:121#: ../gtk/checkbox-gtk.ui.h:1 ../qt/checkbox-qt.desktop.in.h:1
@@ -964,7 +964,7 @@
964msgstr ""964msgstr ""
965965
966#. description966#. description
967#: ../jobs/input.txt.in:23967#: ../jobs/input.txt.in:22
968msgid ""968msgid ""
969"PURPOSE:\n"969"PURPOSE:\n"
970" This test will test your pointing device\n"970" This test will test your pointing device\n"
@@ -976,7 +976,7 @@
976msgstr ""976msgstr ""
977977
978#. description978#. description
979#: ../jobs/input.txt.in:36979#: ../jobs/input.txt.in:35
980msgid ""980msgid ""
981"PURPOSE:\n"981"PURPOSE:\n"
982" This test will test your keyboard\n"982" This test will test your keyboard\n"
983983
=== modified file 'po/da.po'
--- po/da.po 2013-02-22 16:26:25 +0000
+++ po/da.po 2013-03-07 16:10:38 +0000
@@ -14,8 +14,8 @@
14"MIME-Version: 1.0\n"14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"16"Content-Transfer-Encoding: 8bit\n"
17"X-Launchpad-Export-Date: 2013-02-15 04:32+0000\n"17"X-Launchpad-Export-Date: 2013-02-23 04:38+0000\n"
18"X-Generator: Launchpad (build 16491)\n"18"X-Generator: Launchpad (build 16506)\n"
19"X-Poedit-Language: Danish\n"19"X-Poedit-Language: Danish\n"
2020
21#. Title of the user interface21#. Title of the user interface
@@ -1131,7 +1131,7 @@
1131msgstr ""1131msgstr ""
11321132
1133#. description1133#. description
1134#: ../jobs/input.txt.in:231134#: ../jobs/input.txt.in:22
1135msgid ""1135msgid ""
1136"PURPOSE:\n"1136"PURPOSE:\n"
1137" This test will test your pointing device\n"1137" This test will test your pointing device\n"
@@ -1143,7 +1143,7 @@
1143msgstr ""1143msgstr ""
11441144
1145#. description1145#. description
1146#: ../jobs/input.txt.in:361146#: ../jobs/input.txt.in:35
1147msgid ""1147msgid ""
1148"PURPOSE:\n"1148"PURPOSE:\n"
1149" This test will test your keyboard\n"1149" This test will test your keyboard\n"
11501150
=== modified file 'po/de.po'
--- po/de.po 2013-02-22 16:26:25 +0000
+++ po/de.po 2013-03-07 16:10:38 +0000
@@ -14,8 +14,8 @@
14"MIME-Version: 1.0\n"14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"16"Content-Transfer-Encoding: 8bit\n"
17"X-Launchpad-Export-Date: 2013-02-15 04:32+0000\n"17"X-Launchpad-Export-Date: 2013-02-23 04:39+0000\n"
18"X-Generator: Launchpad (build 16491)\n"18"X-Generator: Launchpad (build 16506)\n"
1919
20#: ../gtk/checkbox-gtk.ui.h:2 ../checkbox_gtk/gtk_interface.py:56120#: ../gtk/checkbox-gtk.ui.h:2 ../checkbox_gtk/gtk_interface.py:561
21msgid "_Test"21msgid "_Test"
@@ -83,7 +83,7 @@
8383
84#: ../gtk/checkbox-gtk.ui.h:584#: ../gtk/checkbox-gtk.ui.h:5
85msgid "_Skip this test"85msgid "_Skip this test"
86msgstr "Test _überspringen"86msgstr "_Diesen Test überspringen"
8787
88#: ../gtk/checkbox-gtk.ui.h:6 ../checkbox_cli/cli_interface.py:46088#: ../gtk/checkbox-gtk.ui.h:6 ../checkbox_cli/cli_interface.py:460
89#: ../checkbox_urwid/urwid_interface.py:28989#: ../checkbox_urwid/urwid_interface.py:289
@@ -1425,7 +1425,7 @@
1425"als Anlage bei, falls vorhanden."1425"als Anlage bei, falls vorhanden."
14261426
1427#. description1427#. description
1428#: ../jobs/input.txt.in:231428#: ../jobs/input.txt.in:22
1429msgid ""1429msgid ""
1430"PURPOSE:\n"1430"PURPOSE:\n"
1431" This test will test your pointing device\n"1431" This test will test your pointing device\n"
@@ -1445,7 +1445,7 @@
1445" Arbeitete das Zeigegerät so, wie es vorgesehen ist?"1445" Arbeitete das Zeigegerät so, wie es vorgesehen ist?"
14461446
1447#. description1447#. description
1448#: ../jobs/input.txt.in:361448#: ../jobs/input.txt.in:35
1449msgid ""1449msgid ""
1450"PURPOSE:\n"1450"PURPOSE:\n"
1451" This test will test your keyboard\n"1451" This test will test your keyboard\n"
14521452
=== modified file 'po/dv.po'
--- po/dv.po 2013-02-22 16:26:25 +0000
+++ po/dv.po 2013-03-07 16:10:38 +0000
@@ -14,8 +14,8 @@
14"MIME-Version: 1.0\n"14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"16"Content-Transfer-Encoding: 8bit\n"
17"X-Launchpad-Export-Date: 2013-02-15 04:32+0000\n"17"X-Launchpad-Export-Date: 2013-02-23 04:38+0000\n"
18"X-Generator: Launchpad (build 16491)\n"18"X-Generator: Launchpad (build 16506)\n"
1919
20#. Title of the user interface20#. Title of the user interface
21#: ../gtk/checkbox-gtk.ui.h:1 ../qt/checkbox-qt.desktop.in.h:121#: ../gtk/checkbox-gtk.ui.h:1 ../qt/checkbox-qt.desktop.in.h:1
@@ -964,7 +964,7 @@
964msgstr ""964msgstr ""
965965
966#. description966#. description
967#: ../jobs/input.txt.in:23967#: ../jobs/input.txt.in:22
968msgid ""968msgid ""
969"PURPOSE:\n"969"PURPOSE:\n"
970" This test will test your pointing device\n"970" This test will test your pointing device\n"
@@ -976,7 +976,7 @@
976msgstr ""976msgstr ""
977977
978#. description978#. description
979#: ../jobs/input.txt.in:36979#: ../jobs/input.txt.in:35
980msgid ""980msgid ""
981"PURPOSE:\n"981"PURPOSE:\n"
982" This test will test your keyboard\n"982" This test will test your keyboard\n"
983983
=== modified file 'po/el.po'
--- po/el.po 2013-02-22 16:26:25 +0000
+++ po/el.po 2013-03-07 16:10:38 +0000
@@ -14,8 +14,8 @@
14"MIME-Version: 1.0\n"14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=utf-8\n"15"Content-Type: text/plain; charset=utf-8\n"
16"Content-Transfer-Encoding: 8bit\n"16"Content-Transfer-Encoding: 8bit\n"
17"X-Launchpad-Export-Date: 2013-02-15 04:32+0000\n"17"X-Launchpad-Export-Date: 2013-02-23 04:39+0000\n"
18"X-Generator: Launchpad (build 16491)\n"18"X-Generator: Launchpad (build 16506)\n"
1919
20#: ../gtk/checkbox-gtk.ui.h:2 ../checkbox_gtk/gtk_interface.py:56120#: ../gtk/checkbox-gtk.ui.h:2 ../checkbox_gtk/gtk_interface.py:561
21msgid "_Test"21msgid "_Test"
@@ -1389,7 +1389,7 @@
1389msgstr "Επισύναψη της καταγραφής αποσφαλμάτωσης του εγκαταστάτη αν υπάρχει."1389msgstr "Επισύναψη της καταγραφής αποσφαλμάτωσης του εγκαταστάτη αν υπάρχει."
13901390
1391#. description1391#. description
1392#: ../jobs/input.txt.in:231392#: ../jobs/input.txt.in:22
1393msgid ""1393msgid ""
1394"PURPOSE:\n"1394"PURPOSE:\n"
1395" This test will test your pointing device\n"1395" This test will test your pointing device\n"
@@ -1409,7 +1409,7 @@
1409" Λειτούργησε η συσκευή κατάδειξης όπως θα περιμένατε;"1409" Λειτούργησε η συσκευή κατάδειξης όπως θα περιμένατε;"
14101410
1411#. description1411#. description
1412#: ../jobs/input.txt.in:361412#: ../jobs/input.txt.in:35
1413msgid ""1413msgid ""
1414"PURPOSE:\n"1414"PURPOSE:\n"
1415" This test will test your keyboard\n"1415" This test will test your keyboard\n"
14161416
=== modified file 'po/en_AU.po'
--- po/en_AU.po 2013-02-22 16:26:25 +0000
+++ po/en_AU.po 2013-03-07 16:10:38 +0000
@@ -14,8 +14,8 @@
14"MIME-Version: 1.0\n"14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"16"Content-Transfer-Encoding: 8bit\n"
17"X-Launchpad-Export-Date: 2013-02-15 04:34+0000\n"17"X-Launchpad-Export-Date: 2013-02-23 04:41+0000\n"
18"X-Generator: Launchpad (build 16491)\n"18"X-Generator: Launchpad (build 16506)\n"
1919
20#. Title of the user interface20#. Title of the user interface
21#: ../gtk/checkbox-gtk.ui.h:1 ../qt/checkbox-qt.desktop.in.h:121#: ../gtk/checkbox-gtk.ui.h:1 ../qt/checkbox-qt.desktop.in.h:1
@@ -1254,7 +1254,7 @@
1254msgstr "Attaches the installer debug log if it exists."1254msgstr "Attaches the installer debug log if it exists."
12551255
1256#. description1256#. description
1257#: ../jobs/input.txt.in:231257#: ../jobs/input.txt.in:22
1258msgid ""1258msgid ""
1259"PURPOSE:\n"1259"PURPOSE:\n"
1260" This test will test your pointing device\n"1260" This test will test your pointing device\n"
@@ -1273,7 +1273,7 @@
1273" Did the pointing device work as expected?"1273" Did the pointing device work as expected?"
12741274
1275#. description1275#. description
1276#: ../jobs/input.txt.in:361276#: ../jobs/input.txt.in:35
1277msgid ""1277msgid ""
1278"PURPOSE:\n"1278"PURPOSE:\n"
1279" This test will test your keyboard\n"1279" This test will test your keyboard\n"
12801280
=== modified file 'po/en_CA.po'
--- po/en_CA.po 2013-02-22 16:26:25 +0000
+++ po/en_CA.po 2013-03-07 16:10:38 +0000
@@ -14,8 +14,8 @@
14"MIME-Version: 1.0\n"14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"16"Content-Transfer-Encoding: 8bit\n"
17"X-Launchpad-Export-Date: 2013-02-15 04:35+0000\n"17"X-Launchpad-Export-Date: 2013-02-23 04:41+0000\n"
18"X-Generator: Launchpad (build 16491)\n"18"X-Generator: Launchpad (build 16506)\n"
1919
20#. Title of the user interface20#. Title of the user interface
21#: ../gtk/checkbox-gtk.ui.h:1 ../qt/checkbox-qt.desktop.in.h:121#: ../gtk/checkbox-gtk.ui.h:1 ../qt/checkbox-qt.desktop.in.h:1
@@ -964,7 +964,7 @@
964msgstr ""964msgstr ""
965965
966#. description966#. description
967#: ../jobs/input.txt.in:23967#: ../jobs/input.txt.in:22
968msgid ""968msgid ""
969"PURPOSE:\n"969"PURPOSE:\n"
970" This test will test your pointing device\n"970" This test will test your pointing device\n"
@@ -976,7 +976,7 @@
976msgstr ""976msgstr ""
977977
978#. description978#. description
979#: ../jobs/input.txt.in:36979#: ../jobs/input.txt.in:35
980msgid ""980msgid ""
981"PURPOSE:\n"981"PURPOSE:\n"
982" This test will test your keyboard\n"982" This test will test your keyboard\n"
983983
=== modified file 'po/en_GB.po'
--- po/en_GB.po 2013-02-22 16:26:25 +0000
+++ po/en_GB.po 2013-03-07 16:10:38 +0000
@@ -14,8 +14,8 @@
14"MIME-Version: 1.0\n"14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"16"Content-Transfer-Encoding: 8bit\n"
17"X-Launchpad-Export-Date: 2013-02-15 04:34+0000\n"17"X-Launchpad-Export-Date: 2013-02-23 04:41+0000\n"
18"X-Generator: Launchpad (build 16491)\n"18"X-Generator: Launchpad (build 16506)\n"
1919
20#~ msgid "Do you see color bars and static?"20#~ msgid "Do you see color bars and static?"
21#~ msgstr "Do you see colour bars and static?"21#~ msgstr "Do you see colour bars and static?"
@@ -1257,7 +1257,7 @@
1257msgstr "Attaches the installer debug log if it exists."1257msgstr "Attaches the installer debug log if it exists."
12581258
1259#. description1259#. description
1260#: ../jobs/input.txt.in:231260#: ../jobs/input.txt.in:22
1261msgid ""1261msgid ""
1262"PURPOSE:\n"1262"PURPOSE:\n"
1263" This test will test your pointing device\n"1263" This test will test your pointing device\n"
@@ -1276,7 +1276,7 @@
1276" Did the pointing device work as expected?"1276" Did the pointing device work as expected?"
12771277
1278#. description1278#. description
1279#: ../jobs/input.txt.in:361279#: ../jobs/input.txt.in:35
1280msgid ""1280msgid ""
1281"PURPOSE:\n"1281"PURPOSE:\n"
1282" This test will test your keyboard\n"1282" This test will test your keyboard\n"
12831283
=== modified file 'po/eo.po'
--- po/eo.po 2013-02-22 16:26:25 +0000
+++ po/eo.po 2013-03-07 16:10:38 +0000
@@ -14,8 +14,8 @@
14"MIME-Version: 1.0\n"14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"16"Content-Transfer-Encoding: 8bit\n"
17"X-Launchpad-Export-Date: 2013-02-15 04:32+0000\n"17"X-Launchpad-Export-Date: 2013-02-23 04:39+0000\n"
18"X-Generator: Launchpad (build 16491)\n"18"X-Generator: Launchpad (build 16506)\n"
1919
20#: ../checkbox/application.py:6620#: ../checkbox/application.py:66
21msgid "Usage: checkbox [OPTIONS]"21msgid "Usage: checkbox [OPTIONS]"
@@ -1017,7 +1017,7 @@
1017msgstr ""1017msgstr ""
10181018
1019#. description1019#. description
1020#: ../jobs/input.txt.in:231020#: ../jobs/input.txt.in:22
1021msgid ""1021msgid ""
1022"PURPOSE:\n"1022"PURPOSE:\n"
1023" This test will test your pointing device\n"1023" This test will test your pointing device\n"
@@ -1029,7 +1029,7 @@
1029msgstr ""1029msgstr ""
10301030
1031#. description1031#. description
1032#: ../jobs/input.txt.in:361032#: ../jobs/input.txt.in:35
1033msgid ""1033msgid ""
1034"PURPOSE:\n"1034"PURPOSE:\n"
1035" This test will test your keyboard\n"1035" This test will test your keyboard\n"
10361036
=== modified file 'po/es.po'
--- po/es.po 2013-02-22 16:26:25 +0000
+++ po/es.po 2013-03-07 16:10:38 +0000
@@ -14,8 +14,8 @@
14"MIME-Version: 1.0\n"14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"16"Content-Transfer-Encoding: 8bit\n"
17"X-Launchpad-Export-Date: 2013-02-15 04:34+0000\n"17"X-Launchpad-Export-Date: 2013-02-23 04:41+0000\n"
18"X-Generator: Launchpad (build 16491)\n"18"X-Generator: Launchpad (build 16506)\n"
1919
20#: ../checkbox/application.py:7020#: ../checkbox/application.py:70
21msgid "Print version information and exit."21msgid "Print version information and exit."
@@ -1418,7 +1418,7 @@
1418msgstr "Adjunta el registro de depuración del instalador si existe."1418msgstr "Adjunta el registro de depuración del instalador si existe."
14191419
1420#. description1420#. description
1421#: ../jobs/input.txt.in:231421#: ../jobs/input.txt.in:22
1422msgid ""1422msgid ""
1423"PURPOSE:\n"1423"PURPOSE:\n"
1424" This test will test your pointing device\n"1424" This test will test your pointing device\n"
@@ -1438,7 +1438,7 @@
1438" ¿Se comportó el dispositivo de puntero como se esperaba?"1438" ¿Se comportó el dispositivo de puntero como se esperaba?"
14391439
1440#. description1440#. description
1441#: ../jobs/input.txt.in:361441#: ../jobs/input.txt.in:35
1442msgid ""1442msgid ""
1443"PURPOSE:\n"1443"PURPOSE:\n"
1444" This test will test your keyboard\n"1444" This test will test your keyboard\n"
14451445
=== modified file 'po/et.po'
--- po/et.po 2013-02-22 16:26:25 +0000
+++ po/et.po 2013-03-07 16:10:38 +0000
@@ -14,8 +14,8 @@
14"MIME-Version: 1.0\n"14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"16"Content-Transfer-Encoding: 8bit\n"
17"X-Launchpad-Export-Date: 2013-02-15 04:32+0000\n"17"X-Launchpad-Export-Date: 2013-02-23 04:39+0000\n"
18"X-Generator: Launchpad (build 16491)\n"18"X-Generator: Launchpad (build 16506)\n"
1919
20#. Title of the user interface20#. Title of the user interface
21#: ../gtk/checkbox-gtk.ui.h:1 ../qt/checkbox-qt.desktop.in.h:121#: ../gtk/checkbox-gtk.ui.h:1 ../qt/checkbox-qt.desktop.in.h:1
@@ -964,7 +964,7 @@
964msgstr ""964msgstr ""
965965
966#. description966#. description
967#: ../jobs/input.txt.in:23967#: ../jobs/input.txt.in:22
968msgid ""968msgid ""
969"PURPOSE:\n"969"PURPOSE:\n"
970" This test will test your pointing device\n"970" This test will test your pointing device\n"
@@ -976,7 +976,7 @@
976msgstr ""976msgstr ""
977977
978#. description978#. description
979#: ../jobs/input.txt.in:36979#: ../jobs/input.txt.in:35
980msgid ""980msgid ""
981"PURPOSE:\n"981"PURPOSE:\n"
982" This test will test your keyboard\n"982" This test will test your keyboard\n"
983983
=== modified file 'po/eu.po'
--- po/eu.po 2013-02-22 16:26:25 +0000
+++ po/eu.po 2013-03-07 16:10:38 +0000
@@ -14,8 +14,8 @@
14"MIME-Version: 1.0\n"14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"16"Content-Transfer-Encoding: 8bit\n"
17"X-Launchpad-Export-Date: 2013-02-15 04:31+0000\n"17"X-Launchpad-Export-Date: 2013-02-23 04:38+0000\n"
18"X-Generator: Launchpad (build 16491)\n"18"X-Generator: Launchpad (build 16506)\n"
1919
20#. Title of the user interface20#. Title of the user interface
21#: ../gtk/checkbox-gtk.ui.h:1 ../qt/checkbox-qt.desktop.in.h:121#: ../gtk/checkbox-gtk.ui.h:1 ../qt/checkbox-qt.desktop.in.h:1
@@ -964,7 +964,7 @@
964msgstr ""964msgstr ""
965965
966#. description966#. description
967#: ../jobs/input.txt.in:23967#: ../jobs/input.txt.in:22
968msgid ""968msgid ""
969"PURPOSE:\n"969"PURPOSE:\n"
970" This test will test your pointing device\n"970" This test will test your pointing device\n"
@@ -976,7 +976,7 @@
976msgstr ""976msgstr ""
977977
978#. description978#. description
979#: ../jobs/input.txt.in:36979#: ../jobs/input.txt.in:35
980msgid ""980msgid ""
981"PURPOSE:\n"981"PURPOSE:\n"
982" This test will test your keyboard\n"982" This test will test your keyboard\n"
983983
=== modified file 'po/fa.po'
--- po/fa.po 2013-02-22 16:26:25 +0000
+++ po/fa.po 2013-03-07 16:10:38 +0000
@@ -14,8 +14,8 @@
14"MIME-Version: 1.0\n"14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"16"Content-Transfer-Encoding: 8bit\n"
17"X-Launchpad-Export-Date: 2013-02-15 04:33+0000\n"17"X-Launchpad-Export-Date: 2013-02-23 04:40+0000\n"
18"X-Generator: Launchpad (build 16491)\n"18"X-Generator: Launchpad (build 16506)\n"
1919
20#. Title of the user interface20#. Title of the user interface
21#: ../gtk/checkbox-gtk.ui.h:1 ../qt/checkbox-qt.desktop.in.h:121#: ../gtk/checkbox-gtk.ui.h:1 ../qt/checkbox-qt.desktop.in.h:1
@@ -964,7 +964,7 @@
964msgstr ""964msgstr ""
965965
966#. description966#. description
967#: ../jobs/input.txt.in:23967#: ../jobs/input.txt.in:22
968msgid ""968msgid ""
969"PURPOSE:\n"969"PURPOSE:\n"
970" This test will test your pointing device\n"970" This test will test your pointing device\n"
@@ -976,7 +976,7 @@
976msgstr ""976msgstr ""
977977
978#. description978#. description
979#: ../jobs/input.txt.in:36979#: ../jobs/input.txt.in:35
980msgid ""980msgid ""
981"PURPOSE:\n"981"PURPOSE:\n"
982" This test will test your keyboard\n"982" This test will test your keyboard\n"
983983
=== modified file 'po/fi.po'
--- po/fi.po 2013-02-22 16:26:25 +0000
+++ po/fi.po 2013-03-07 16:10:38 +0000
@@ -14,8 +14,8 @@
14"MIME-Version: 1.0\n"14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"16"Content-Transfer-Encoding: 8bit\n"
17"X-Launchpad-Export-Date: 2013-02-15 04:32+0000\n"17"X-Launchpad-Export-Date: 2013-02-23 04:39+0000\n"
18"X-Generator: Launchpad (build 16491)\n"18"X-Generator: Launchpad (build 16506)\n"
1919
20#. Title of the user interface20#. Title of the user interface
21#: ../gtk/checkbox-gtk.ui.h:1 ../qt/checkbox-qt.desktop.in.h:121#: ../gtk/checkbox-gtk.ui.h:1 ../qt/checkbox-qt.desktop.in.h:1
@@ -1240,7 +1240,7 @@
1240msgstr ""1240msgstr ""
12411241
1242#. description1242#. description
1243#: ../jobs/input.txt.in:231243#: ../jobs/input.txt.in:22
1244msgid ""1244msgid ""
1245"PURPOSE:\n"1245"PURPOSE:\n"
1246" This test will test your pointing device\n"1246" This test will test your pointing device\n"
@@ -1260,7 +1260,7 @@
1260" Toimiko osoitinlaite odotetulla tavalla?"1260" Toimiko osoitinlaite odotetulla tavalla?"
12611261
1262#. description1262#. description
1263#: ../jobs/input.txt.in:361263#: ../jobs/input.txt.in:35
1264msgid ""1264msgid ""
1265"PURPOSE:\n"1265"PURPOSE:\n"
1266" This test will test your keyboard\n"1266" This test will test your keyboard\n"
12671267
=== modified file 'po/fr.po'
--- po/fr.po 2013-02-22 16:26:25 +0000
+++ po/fr.po 2013-03-07 16:10:38 +0000
@@ -13,8 +13,8 @@
13"MIME-Version: 1.0\n"13"MIME-Version: 1.0\n"
14"Content-Type: text/plain; charset=UTF-8\n"14"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Transfer-Encoding: 8bit\n"15"Content-Transfer-Encoding: 8bit\n"
16"X-Launchpad-Export-Date: 2013-02-15 04:32+0000\n"16"X-Launchpad-Export-Date: 2013-02-23 04:39+0000\n"
17"X-Generator: Launchpad (build 16491)\n"17"X-Generator: Launchpad (build 16506)\n"
1818
19#. Title of the user interface19#. Title of the user interface
20#: ../gtk/checkbox-gtk.ui.h:1 ../qt/checkbox-qt.desktop.in.h:120#: ../gtk/checkbox-gtk.ui.h:1 ../qt/checkbox-qt.desktop.in.h:1
@@ -1363,7 +1363,7 @@
1363msgstr "Joint le journal de débogage de l'installateur s'il existe."1363msgstr "Joint le journal de débogage de l'installateur s'il existe."
13641364
1365#. description1365#. description
1366#: ../jobs/input.txt.in:231366#: ../jobs/input.txt.in:22
1367msgid ""1367msgid ""
1368"PURPOSE:\n"1368"PURPOSE:\n"
1369" This test will test your pointing device\n"1369" This test will test your pointing device\n"
@@ -1383,7 +1383,7 @@
1383" Est-ce que le périphérique de pointage a fonctionné correctement ?"1383" Est-ce que le périphérique de pointage a fonctionné correctement ?"
13841384
1385#. description1385#. description
1386#: ../jobs/input.txt.in:361386#: ../jobs/input.txt.in:35
1387msgid ""1387msgid ""
1388"PURPOSE:\n"1388"PURPOSE:\n"
1389" This test will test your keyboard\n"1389" This test will test your keyboard\n"
13901390
=== modified file 'po/ga.po'
--- po/ga.po 2013-02-22 16:26:25 +0000
+++ po/ga.po 2013-03-07 16:10:38 +0000
@@ -14,8 +14,8 @@
14"MIME-Version: 1.0\n"14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"16"Content-Transfer-Encoding: 8bit\n"
17"X-Launchpad-Export-Date: 2013-02-15 04:32+0000\n"17"X-Launchpad-Export-Date: 2013-02-23 04:39+0000\n"
18"X-Generator: Launchpad (build 16491)\n"18"X-Generator: Launchpad (build 16506)\n"
1919
20#. Title of the user interface20#. Title of the user interface
21#: ../gtk/checkbox-gtk.ui.h:1 ../qt/checkbox-qt.desktop.in.h:121#: ../gtk/checkbox-gtk.ui.h:1 ../qt/checkbox-qt.desktop.in.h:1
@@ -964,7 +964,7 @@
964msgstr ""964msgstr ""
965965
966#. description966#. description
967#: ../jobs/input.txt.in:23967#: ../jobs/input.txt.in:22
968msgid ""968msgid ""
969"PURPOSE:\n"969"PURPOSE:\n"
970" This test will test your pointing device\n"970" This test will test your pointing device\n"
@@ -976,7 +976,7 @@
976msgstr ""976msgstr ""
977977
978#. description978#. description
979#: ../jobs/input.txt.in:36979#: ../jobs/input.txt.in:35
980msgid ""980msgid ""
981"PURPOSE:\n"981"PURPOSE:\n"
982" This test will test your keyboard\n"982" This test will test your keyboard\n"
983983
=== modified file 'po/gd.po'
--- po/gd.po 2013-02-22 16:26:25 +0000
+++ po/gd.po 2013-03-07 16:10:38 +0000
@@ -14,8 +14,8 @@
14"MIME-Version: 1.0\n"14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"16"Content-Transfer-Encoding: 8bit\n"
17"X-Launchpad-Export-Date: 2013-02-15 04:32+0000\n"17"X-Launchpad-Export-Date: 2013-02-23 04:39+0000\n"
18"X-Generator: Launchpad (build 16491)\n"18"X-Generator: Launchpad (build 16506)\n"
1919
20#. Title of the user interface20#. Title of the user interface
21#: ../gtk/checkbox-gtk.ui.h:1 ../qt/checkbox-qt.desktop.in.h:121#: ../gtk/checkbox-gtk.ui.h:1 ../qt/checkbox-qt.desktop.in.h:1
@@ -1295,7 +1295,7 @@
1295msgstr "A' ceangal log dì-bhugaich an stàlaichear ma tha e ann."1295msgstr "A' ceangal log dì-bhugaich an stàlaichear ma tha e ann."
12961296
1297#. description1297#. description
1298#: ../jobs/input.txt.in:231298#: ../jobs/input.txt.in:22
1299msgid ""1299msgid ""
1300"PURPOSE:\n"1300"PURPOSE:\n"
1301" This test will test your pointing device\n"1301" This test will test your pointing device\n"
@@ -1315,7 +1315,7 @@
1315" An do dh'obraich an innleachd comharraich mar a bha dùil?"1315" An do dh'obraich an innleachd comharraich mar a bha dùil?"
13161316
1317#. description1317#. description
1318#: ../jobs/input.txt.in:361318#: ../jobs/input.txt.in:35
1319msgid ""1319msgid ""
1320"PURPOSE:\n"1320"PURPOSE:\n"
1321" This test will test your keyboard\n"1321" This test will test your keyboard\n"
13221322
=== modified file 'po/gl.po'
--- po/gl.po 2013-02-22 16:26:25 +0000
+++ po/gl.po 2013-03-07 16:10:38 +0000
@@ -15,8 +15,8 @@
15"MIME-Version: 1.0\n"15"MIME-Version: 1.0\n"
16"Content-Type: text/plain; charset=UTF-8\n"16"Content-Type: text/plain; charset=UTF-8\n"
17"Content-Transfer-Encoding: 8bit\n"17"Content-Transfer-Encoding: 8bit\n"
18"X-Launchpad-Export-Date: 2013-02-15 04:32+0000\n"18"X-Launchpad-Export-Date: 2013-02-23 04:39+0000\n"
19"X-Generator: Launchpad (build 16491)\n"19"X-Generator: Launchpad (build 16506)\n"
2020
21#. Title of the user interface21#. Title of the user interface
22#: ../gtk/checkbox-gtk.ui.h:1 ../qt/checkbox-qt.desktop.in.h:122#: ../gtk/checkbox-gtk.ui.h:1 ../qt/checkbox-qt.desktop.in.h:1
@@ -1285,7 +1285,7 @@
1285msgstr "Anexa o rexistro de depuración do instalador se existe."1285msgstr "Anexa o rexistro de depuración do instalador se existe."
12861286
1287#. description1287#. description
1288#: ../jobs/input.txt.in:231288#: ../jobs/input.txt.in:22
1289msgid ""1289msgid ""
1290"PURPOSE:\n"1290"PURPOSE:\n"
1291" This test will test your pointing device\n"1291" This test will test your pointing device\n"
@@ -1305,7 +1305,7 @@
1305" Comportouse o dispositivo de punteiro como se agardaba?"1305" Comportouse o dispositivo de punteiro como se agardaba?"
13061306
1307#. description1307#. description
1308#: ../jobs/input.txt.in:361308#: ../jobs/input.txt.in:35
1309msgid ""1309msgid ""
1310"PURPOSE:\n"1310"PURPOSE:\n"
1311" This test will test your keyboard\n"1311" This test will test your keyboard\n"
13121312
=== modified file 'po/he.po'
--- po/he.po 2013-02-22 16:26:25 +0000
+++ po/he.po 2013-03-07 16:10:38 +0000
@@ -14,8 +14,8 @@
14"MIME-Version: 1.0\n"14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"16"Content-Transfer-Encoding: 8bit\n"
17"X-Launchpad-Export-Date: 2013-02-15 04:32+0000\n"17"X-Launchpad-Export-Date: 2013-02-23 04:39+0000\n"
18"X-Generator: Launchpad (build 16491)\n"18"X-Generator: Launchpad (build 16506)\n"
1919
20#: ../gtk/checkbox-gtk.ui.h:420#: ../gtk/checkbox-gtk.ui.h:4
21msgid "_No"21msgid "_No"
@@ -1095,7 +1095,7 @@
1095msgstr ""1095msgstr ""
10961096
1097#. description1097#. description
1098#: ../jobs/input.txt.in:231098#: ../jobs/input.txt.in:22
1099msgid ""1099msgid ""
1100"PURPOSE:\n"1100"PURPOSE:\n"
1101" This test will test your pointing device\n"1101" This test will test your pointing device\n"
@@ -1107,7 +1107,7 @@
1107msgstr ""1107msgstr ""
11081108
1109#. description1109#. description
1110#: ../jobs/input.txt.in:361110#: ../jobs/input.txt.in:35
1111msgid ""1111msgid ""
1112"PURPOSE:\n"1112"PURPOSE:\n"
1113" This test will test your keyboard\n"1113" This test will test your keyboard\n"
11141114
=== modified file 'po/hi.po'
--- po/hi.po 2013-02-22 16:26:25 +0000
+++ po/hi.po 2013-03-07 16:10:38 +0000
@@ -14,8 +14,8 @@
14"MIME-Version: 1.0\n"14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"16"Content-Transfer-Encoding: 8bit\n"
17"X-Launchpad-Export-Date: 2013-02-15 04:32+0000\n"17"X-Launchpad-Export-Date: 2013-02-23 04:39+0000\n"
18"X-Generator: Launchpad (build 16491)\n"18"X-Generator: Launchpad (build 16506)\n"
1919
20#. Title of the user interface20#. Title of the user interface
21#: ../gtk/checkbox-gtk.ui.h:1 ../qt/checkbox-qt.desktop.in.h:121#: ../gtk/checkbox-gtk.ui.h:1 ../qt/checkbox-qt.desktop.in.h:1
@@ -966,7 +966,7 @@
966msgstr ""966msgstr ""
967967
968#. description968#. description
969#: ../jobs/input.txt.in:23969#: ../jobs/input.txt.in:22
970msgid ""970msgid ""
971"PURPOSE:\n"971"PURPOSE:\n"
972" This test will test your pointing device\n"972" This test will test your pointing device\n"
@@ -978,7 +978,7 @@
978msgstr ""978msgstr ""
979979
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches