Merge ~sylvain-pineau/checkbox-ng:xml-removal into checkbox-ng:master
- Git
- lp:~sylvain-pineau/checkbox-ng
- xml-removal
- Merge into master
Proposed by
Sylvain Pineau
Status: | Merged |
---|---|
Approved by: | Sylvain Pineau |
Approved revision: | 8e701f5f659050cccc355b9080e22a9feb73a2e7 |
Merged at revision: | 29dd46691720384c6f99a452fb5e5fcdcf1061db |
Proposed branch: | ~sylvain-pineau/checkbox-ng:xml-removal |
Merge into: | checkbox-ng:master |
Diff against target: |
592 lines (+40/-263) 10 files modified
checkbox_ng/certification.py (+2/-146) checkbox_ng/launcher/subcommands.py (+11/-38) checkbox_ng/test_certification.py (+19/-42) dev/null (+0/-1) docs/conf.py (+1/-3) docs/index.rst (+0/-18) docs/launcher-tutorial.rst (+6/-9) docs/stack.rst (+1/-3) requirements/deb-core.txt (+0/-1) setup.py (+0/-2) |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Sylvain Pineau (community) | Needs Resubmitting | ||
Maciej Kisielewski (community) | Approve | ||
Review via email:
|
Commit message
Description of the change
Remove XML/HEXR exporter support from checkbox-ng
Requires: https:/
To post a comment you must log in.
Revision history for this message
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Sylvain Pineau (sylvain-pineau) wrote : | # |
sample_xml -> sample_archive
review:
Needs Resubmitting
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | diff --git a/checkbox_ng/certification.py b/checkbox_ng/certification.py | |||
2 | index c46956a..bccae83 100644 | |||
3 | --- a/checkbox_ng/certification.py | |||
4 | +++ b/checkbox_ng/certification.py | |||
5 | @@ -23,7 +23,7 @@ | |||
6 | 23 | ============================================================================= | 23 | ============================================================================= |
7 | 24 | 24 | ||
8 | 25 | This module contains a PlainBox transport that knows how to send the | 25 | This module contains a PlainBox transport that knows how to send the |
10 | 26 | certification XML data to the Canonical certification database. | 26 | certification tarball to the Canonical certification database. |
11 | 27 | """ | 27 | """ |
12 | 28 | 28 | ||
13 | 29 | from gettext import gettext as _ | 29 | from gettext import gettext as _ |
14 | @@ -41,147 +41,6 @@ import requests | |||
15 | 41 | logger = getLogger("checkbox.ng.certification") | 41 | logger = getLogger("checkbox.ng.certification") |
16 | 42 | 42 | ||
17 | 43 | 43 | ||
18 | 44 | class CertificationTransport(TransportBase): | ||
19 | 45 | """ | ||
20 | 46 | Transport for sending data to certification database. | ||
21 | 47 | - POSTs data to a http(s) endpoint | ||
22 | 48 | - Adds a header with a hardware identifier | ||
23 | 49 | - Payload can be in: | ||
24 | 50 | * checkbox xml-compatible format. | ||
25 | 51 | This means it will work best with a stream produced by the xml | ||
26 | 52 | exporter. | ||
27 | 53 | """ | ||
28 | 54 | |||
29 | 55 | def __init__(self, where, options): | ||
30 | 56 | """ | ||
31 | 57 | Initialize the Certification Transport. | ||
32 | 58 | |||
33 | 59 | The options string may contain 'secure_id' which must be | ||
34 | 60 | a 15-character (or longer) alphanumeric ID for the system. | ||
35 | 61 | |||
36 | 62 | It may also contain a submit_to_hexr boolean, set to 1 | ||
37 | 63 | to enable submission to hexr. | ||
38 | 64 | """ | ||
39 | 65 | super().__init__(where, options) | ||
40 | 66 | # Interpret this setting here | ||
41 | 67 | submit_to_hexr = self.options.get('submit_to_hexr') | ||
42 | 68 | self._submit_to_hexr = False | ||
43 | 69 | try: | ||
44 | 70 | if submit_to_hexr and (submit_to_hexr.lower() in | ||
45 | 71 | ('yes', 'true') or | ||
46 | 72 | int(submit_to_hexr) == 1): | ||
47 | 73 | self._submit_to_hexr = True | ||
48 | 74 | except ValueError: | ||
49 | 75 | # Just leave it at False | ||
50 | 76 | pass | ||
51 | 77 | self._secure_id = self.options.get('secure_id') | ||
52 | 78 | if self._secure_id is not None: | ||
53 | 79 | self._validate_secure_id(self._secure_id) | ||
54 | 80 | |||
55 | 81 | def send(self, data, config=None, session_state=None): | ||
56 | 82 | """ | ||
57 | 83 | Sends data to the specified server. | ||
58 | 84 | |||
59 | 85 | :param data: | ||
60 | 86 | Data containing the xml dump to be sent to the server. This | ||
61 | 87 | can be either bytes or a file-like object (BytesIO works fine too). | ||
62 | 88 | If this is a file-like object, it will be read and streamed "on | ||
63 | 89 | the fly". | ||
64 | 90 | :param config: | ||
65 | 91 | Optional PlainBoxConfig object. If http_proxy and https_proxy | ||
66 | 92 | values are set in this config object, they will be used to send | ||
67 | 93 | data via the specified protocols. Note that the transport also | ||
68 | 94 | honors the http_proxy and https_proxy environment variables. | ||
69 | 95 | Proxy string format is http://[user:password@]<proxy-ip>:port | ||
70 | 96 | :param session_state: | ||
71 | 97 | The session for which this transport is associated with | ||
72 | 98 | the data being sent (optional) | ||
73 | 99 | :returns: | ||
74 | 100 | A dictionary with responses from the server if submission | ||
75 | 101 | was successful. This should contain an 'id' key, however | ||
76 | 102 | the server response may change, so the only guarantee | ||
77 | 103 | we make is that this will be non-False if the server | ||
78 | 104 | accepted the data. Returns empty dictionary otherwise. | ||
79 | 105 | :raises requests.exceptions.Timeout: | ||
80 | 106 | If sending timed out. | ||
81 | 107 | :raises requests.exceptions.ConnectionError: | ||
82 | 108 | If connection failed outright. | ||
83 | 109 | :raises requests.exceptions.HTTPError: | ||
84 | 110 | If the server returned a non-success result code | ||
85 | 111 | """ | ||
86 | 112 | proxies = None | ||
87 | 113 | if config and config.environment is not Unset: | ||
88 | 114 | proxies = { | ||
89 | 115 | proto[:-len("_proxy")]: config.environment[proto] | ||
90 | 116 | for proto in ['http_proxy', 'https_proxy'] | ||
91 | 117 | if proto in config.environment | ||
92 | 118 | } | ||
93 | 119 | # Find the effective value of secure_id: | ||
94 | 120 | # - use the configuration object (if available) | ||
95 | 121 | # - override with secure_id= option (if defined) | ||
96 | 122 | secure_id = None | ||
97 | 123 | if config is not None and hasattr(config, 'secure_id'): | ||
98 | 124 | secure_id = config.secure_id | ||
99 | 125 | if self._secure_id is not None: | ||
100 | 126 | secure_id = self._secure_id | ||
101 | 127 | if secure_id is None: | ||
102 | 128 | raise InvalidSecureIDError(_("Secure ID not specified")) | ||
103 | 129 | self._validate_secure_id(secure_id) | ||
104 | 130 | logger.debug( | ||
105 | 131 | _("Sending to %s, Secure ID is %s"), self.url, secure_id) | ||
106 | 132 | headers = {"X_HARDWARE_ID": secure_id} | ||
107 | 133 | # Similar handling for submit_to_hexr | ||
108 | 134 | submit_to_hexr = False | ||
109 | 135 | if config is not None and hasattr(config, 'submit_to_hexr'): | ||
110 | 136 | submit_to_hexr = config.submit_to_hexr | ||
111 | 137 | logger.debug(_("submit_to_hexr set to %s by config"), | ||
112 | 138 | submit_to_hexr) | ||
113 | 139 | if self._submit_to_hexr: | ||
114 | 140 | submit_to_hexr = self._submit_to_hexr | ||
115 | 141 | logger.debug(_("submit_to_hexr set to %s by UI"), submit_to_hexr) | ||
116 | 142 | # We could always set this header since hexr will only process a value | ||
117 | 143 | # of 'True', but this avoids injecting that extraneous knowledge into | ||
118 | 144 | # the tests. | ||
119 | 145 | # Note that hexr will only process a submission with this header's | ||
120 | 146 | # value set to 'True', so this boolean conversion should be ok. | ||
121 | 147 | if submit_to_hexr: | ||
122 | 148 | headers["X-Share-With-HEXR"] = submit_to_hexr | ||
123 | 149 | |||
124 | 150 | # Requests takes care of properly handling a file-like data. | ||
125 | 151 | form_payload = {"data": data} | ||
126 | 152 | try: | ||
127 | 153 | response = requests.post( | ||
128 | 154 | self.url, files=form_payload, headers=headers, proxies=proxies) | ||
129 | 155 | except requests.exceptions.Timeout as exc: | ||
130 | 156 | raise TransportError( | ||
131 | 157 | _("Request to {0} timed out: {1}").format(self.url, exc)) | ||
132 | 158 | except requests.exceptions.InvalidSchema as exc: | ||
133 | 159 | raise TransportError( | ||
134 | 160 | _("Invalid destination URL: {0}").format(exc)) | ||
135 | 161 | except requests.exceptions.ConnectionError as exc: | ||
136 | 162 | raise TransportError( | ||
137 | 163 | _("Unable to connect to {0}: {1}").format(self.url, exc)) | ||
138 | 164 | if response is not None: | ||
139 | 165 | try: | ||
140 | 166 | # This will raise HTTPError for status != 20x | ||
141 | 167 | response.raise_for_status() | ||
142 | 168 | except requests.exceptions.RequestException as exc: | ||
143 | 169 | raise TransportError(str(exc)) | ||
144 | 170 | logger.debug("Success! Server said %s", response.text) | ||
145 | 171 | try: | ||
146 | 172 | return response.json() | ||
147 | 173 | except Exception as exc: | ||
148 | 174 | raise TransportError(str(exc)) | ||
149 | 175 | |||
150 | 176 | # ISessionStateTransport.send must return dictionary | ||
151 | 177 | return {} | ||
152 | 178 | |||
153 | 179 | def _validate_secure_id(self, secure_id): | ||
154 | 180 | if not re.match(SECURE_ID_PATTERN, secure_id): | ||
155 | 181 | raise InvalidSecureIDError( | ||
156 | 182 | _("secure_id must be 15-character (or more) alphanumeric string")) | ||
157 | 183 | |||
158 | 184 | |||
159 | 185 | class SubmissionServiceTransport(TransportBase): | 44 | class SubmissionServiceTransport(TransportBase): |
160 | 186 | """ | 45 | """ |
161 | 187 | Transport for sending data to certification database. | 46 | Transport for sending data to certification database. |
162 | @@ -197,9 +56,6 @@ class SubmissionServiceTransport(TransportBase): | |||
163 | 197 | 56 | ||
164 | 198 | The options string may contain 'secure_id' which must be | 57 | The options string may contain 'secure_id' which must be |
165 | 199 | a 15-character (or longer) alphanumeric ID for the system. | 58 | a 15-character (or longer) alphanumeric ID for the system. |
166 | 200 | |||
167 | 201 | It may also contain a submit_to_hexr boolean, set to 1 | ||
168 | 202 | to enable submission to hexr. | ||
169 | 203 | """ | 59 | """ |
170 | 204 | super().__init__(where, options) | 60 | super().__init__(where, options) |
171 | 205 | self._secure_id = self.options.get('secure_id') | 61 | self._secure_id = self.options.get('secure_id') |
172 | @@ -211,7 +67,7 @@ class SubmissionServiceTransport(TransportBase): | |||
173 | 211 | Sends data to the specified server. | 67 | Sends data to the specified server. |
174 | 212 | 68 | ||
175 | 213 | :param data: | 69 | :param data: |
177 | 214 | Data containing the xml dump to be sent to the server. This | 70 | Data containing the session dump to be sent to the server. This |
178 | 215 | can be either bytes or a file-like object (BytesIO works fine too). | 71 | can be either bytes or a file-like object (BytesIO works fine too). |
179 | 216 | If this is a file-like object, it will be read and streamed "on | 72 | If this is a file-like object, it will be read and streamed "on |
180 | 217 | the fly". | 73 | the fly". |
181 | diff --git a/checkbox_ng/launcher/subcommands.py b/checkbox_ng/launcher/subcommands.py | |||
182 | index af8ce9c..ce5a2e6 100644 | |||
183 | --- a/checkbox_ng/launcher/subcommands.py | |||
184 | +++ b/checkbox_ng/launcher/subcommands.py | |||
185 | @@ -98,19 +98,8 @@ class Submit(Command): | |||
186 | 98 | if ctx.args.staging: | 98 | if ctx.args.staging: |
187 | 99 | url = ('https://certification.staging.canonical.com/' | 99 | url = ('https://certification.staging.canonical.com/' |
188 | 100 | 'api/v1/submission/{}/'.format(ctx.args.secure_id)) | 100 | 'api/v1/submission/{}/'.format(ctx.args.secure_id)) |
202 | 101 | if ctx.args.submission.endswith('xml'): | 101 | from checkbox_ng.certification import SubmissionServiceTransport |
203 | 102 | from checkbox_ng.certification import CertificationTransport | 102 | transport_cls = SubmissionServiceTransport |
191 | 103 | transport_cls = CertificationTransport | ||
192 | 104 | mode = 'r' | ||
193 | 105 | enc = 'utf-8' | ||
194 | 106 | url = ('https://certification.canonical.com/' | ||
195 | 107 | 'submissions/submit/') | ||
196 | 108 | if ctx.args.staging: | ||
197 | 109 | url = ('https://certification.staging.canonical.com/' | ||
198 | 110 | 'submissions/submit/') | ||
199 | 111 | else: | ||
200 | 112 | from checkbox_ng.certification import SubmissionServiceTransport | ||
201 | 113 | transport_cls = SubmissionServiceTransport | ||
204 | 114 | transport = transport_cls(url, options_string) | 103 | transport = transport_cls(url, options_string) |
205 | 115 | try: | 104 | try: |
206 | 116 | with open(ctx.args.submission, mode, encoding=enc) as subm_file: | 105 | with open(ctx.args.submission, mode, encoding=enc) as subm_file: |
207 | @@ -587,24 +576,24 @@ class Launcher(Command, MainLoopStage): | |||
208 | 587 | self.launcher.reports['1_text_to_screen'] = { | 576 | self.launcher.reports['1_text_to_screen'] = { |
209 | 588 | 'transport': 'stdout', 'exporter': 'text', 'forced': 'yes'} | 577 | 'transport': 'stdout', 'exporter': 'text', 'forced': 'yes'} |
210 | 589 | elif report == 'certification': | 578 | elif report == 'certification': |
213 | 590 | self.launcher.exporters['hexr'] = { | 579 | self.launcher.exporters['tar'] = { |
214 | 591 | 'unit': 'com.canonical.plainbox::hexr'} | 580 | 'unit': 'com.canonical.plainbox::tar'} |
215 | 592 | self.launcher.transports['c3'] = { | 581 | self.launcher.transports['c3'] = { |
217 | 593 | 'type': 'certification', | 582 | 'type': 'submission-service', |
218 | 594 | 'secure_id': self.launcher.transports.get('c3', {}).get( | 583 | 'secure_id': self.launcher.transports.get('c3', {}).get( |
219 | 595 | 'secure_id', None)} | 584 | 'secure_id', None)} |
220 | 596 | self.launcher.reports['upload to certification'] = { | 585 | self.launcher.reports['upload to certification'] = { |
222 | 597 | 'transport': 'c3', 'exporter': 'hexr'} | 586 | 'transport': 'c3', 'exporter': 'tar'} |
223 | 598 | elif report == 'certification-staging': | 587 | elif report == 'certification-staging': |
226 | 599 | self.launcher.exporters['hexr'] = { | 588 | self.launcher.exporters['tar'] = { |
227 | 600 | 'unit': 'com.canonical.plainbox::hexr'} | 589 | 'unit': 'com.canonical.plainbox::tar'} |
228 | 601 | self.launcher.transports['c3-staging'] = { | 590 | self.launcher.transports['c3-staging'] = { |
230 | 602 | 'type': 'certification', | 591 | 'type': 'submission-service', |
231 | 603 | 'secure_id': self.launcher.transports.get('c3', {}).get( | 592 | 'secure_id': self.launcher.transports.get('c3', {}).get( |
232 | 604 | 'secure_id', None), | 593 | 'secure_id', None), |
233 | 605 | 'staging': 'yes'} | 594 | 'staging': 'yes'} |
234 | 606 | self.launcher.reports['upload to certification-staging'] = { | 595 | self.launcher.reports['upload to certification-staging'] = { |
236 | 607 | 'transport': 'c3-staging', 'exporter': 'hexr'} | 596 | 'transport': 'c3-staging', 'exporter': 'tar'} |
237 | 608 | elif report == 'submission_files': | 597 | elif report == 'submission_files': |
238 | 609 | # LP:1585326 maintain isoformat but removing ':' chars that cause | 598 | # LP:1585326 maintain isoformat but removing ':' chars that cause |
239 | 610 | # issues when copying files. | 599 | # issues when copying files. |
240 | @@ -612,7 +601,7 @@ class Launcher(Command, MainLoopStage): | |||
241 | 612 | timestamp = datetime.datetime.utcnow().strftime(isoformat) | 601 | timestamp = datetime.datetime.utcnow().strftime(isoformat) |
242 | 613 | if not os.path.exists(self.base_dir): | 602 | if not os.path.exists(self.base_dir): |
243 | 614 | os.makedirs(self.base_dir) | 603 | os.makedirs(self.base_dir) |
245 | 615 | for exporter, file_ext in [('hexr', '.xml'), ('html', '.html'), | 604 | for exporter, file_ext in [('html', '.html'), |
246 | 616 | ('junit', '.junit.xml'), | 605 | ('junit', '.junit.xml'), |
247 | 617 | ('xlsx', '.xlsx'), ('tar', '.tar.xz')]: | 606 | ('xlsx', '.xlsx'), ('tar', '.tar.xz')]: |
248 | 618 | path = os.path.join(self.base_dir, ''.join( | 607 | path = os.path.join(self.base_dir, ''.join( |
249 | @@ -652,22 +641,6 @@ class Launcher(Command, MainLoopStage): | |||
250 | 652 | elif tr_type == 'stream': | 641 | elif tr_type == 'stream': |
251 | 653 | self.transports[transport] = cls( | 642 | self.transports[transport] = cls( |
252 | 654 | self.launcher.transports[transport]['stream']) | 643 | self.launcher.transports[transport]['stream']) |
253 | 655 | elif tr_type == 'certification': | ||
254 | 656 | if self.launcher.transports[transport].get('staging', False): | ||
255 | 657 | url = ('https://certification.staging.canonical.com/' | ||
256 | 658 | 'submissions/submit/') | ||
257 | 659 | else: | ||
258 | 660 | url = ('https://certification.canonical.com/' | ||
259 | 661 | 'submissions/submit/') | ||
260 | 662 | secure_id = self.launcher.transports[transport].get( | ||
261 | 663 | 'secure_id', None) | ||
262 | 664 | if not secure_id and self.is_interactive: | ||
263 | 665 | secure_id = input(self.C.BLUE(_('Enter secure-id:'))) | ||
264 | 666 | if secure_id: | ||
265 | 667 | options = "secure_id={}".format(secure_id) | ||
266 | 668 | else: | ||
267 | 669 | options = "" | ||
268 | 670 | self.transports[transport] = cls(url, options) | ||
269 | 671 | elif tr_type == 'submission-service': | 644 | elif tr_type == 'submission-service': |
270 | 672 | secure_id = self.launcher.transports[transport].get( | 645 | secure_id = self.launcher.transports[transport].get( |
271 | 673 | 'secure_id', None) | 646 | 'secure_id', None) |
272 | diff --git a/checkbox_ng/test_certification.py b/checkbox_ng/test_certification.py | |||
273 | index e2d558e..2c61bab 100644 | |||
274 | --- a/checkbox_ng/test_certification.py | |||
275 | +++ b/checkbox_ng/test_certification.py | |||
276 | @@ -1,9 +1,10 @@ | |||
277 | 1 | # This file is part of Checkbox. | 1 | # This file is part of Checkbox. |
278 | 2 | # | 2 | # |
280 | 3 | # Copyright 2012, 2013 Canonical Ltd. | 3 | # Copyright 2012, 2017 Canonical Ltd. |
281 | 4 | # Written by: | 4 | # Written by: |
282 | 5 | # Zygmunt Krynicki <zygmunt.krynicki@canonical.com> | 5 | # Zygmunt Krynicki <zygmunt.krynicki@canonical.com> |
283 | 6 | # Daniel Manrique <roadmr@ubuntu.com> | 6 | # Daniel Manrique <roadmr@ubuntu.com> |
284 | 7 | # Sylvain Pineau <sylvain.pineau@canonical.com> | ||
285 | 7 | # | 8 | # |
286 | 8 | # Checkbox is free software: you can redistribute it and/or modify | 9 | # Checkbox is free software: you can redistribute it and/or modify |
287 | 9 | # it under the terms of the GNU General Public License version 3, | 10 | # it under the terms of the GNU General Public License version 3, |
288 | @@ -37,10 +38,10 @@ from plainbox.vendor.mock import MagicMock | |||
289 | 37 | from requests.exceptions import ConnectionError, InvalidSchema, HTTPError | 38 | from requests.exceptions import ConnectionError, InvalidSchema, HTTPError |
290 | 38 | import requests | 39 | import requests |
291 | 39 | 40 | ||
293 | 40 | from checkbox_ng.certification import CertificationTransport | 41 | from checkbox_ng.certification import SubmissionServiceTransport |
294 | 41 | 42 | ||
295 | 42 | 43 | ||
297 | 43 | class CertificationTransportTests(TestCase): | 44 | class SubmissionServiceTransportTests(TestCase): |
298 | 44 | 45 | ||
299 | 45 | # URL are just here to exemplify, since we mock away all network access, | 46 | # URL are just here to exemplify, since we mock away all network access, |
300 | 46 | # they're not really used. | 47 | # they're not really used. |
301 | @@ -51,39 +52,34 @@ class CertificationTransportTests(TestCase): | |||
302 | 51 | valid_option_string = "secure_id={}".format(valid_secure_id) | 52 | valid_option_string = "secure_id={}".format(valid_secure_id) |
303 | 52 | 53 | ||
304 | 53 | def setUp(self): | 54 | def setUp(self): |
307 | 54 | self.sample_xml = BytesIO(resource_string( | 55 | self.sample_archive = BytesIO(resource_string( |
308 | 55 | "plainbox", "test-data/xml-exporter/example-data.xml" | 56 | "plainbox", "test-data/tar-exporter/example-data.tar.xz" |
309 | 56 | )) | 57 | )) |
310 | 57 | self.patcher = mock.patch('requests.post') | 58 | self.patcher = mock.patch('requests.post') |
311 | 58 | self.mock_requests = self.patcher.start() | 59 | self.mock_requests = self.patcher.start() |
312 | 59 | 60 | ||
313 | 60 | def test_parameter_parsing(self): | 61 | def test_parameter_parsing(self): |
314 | 61 | # Makes sense since I'm overriding the base class's constructor. | 62 | # Makes sense since I'm overriding the base class's constructor. |
316 | 62 | transport = CertificationTransport( | 63 | transport = SubmissionServiceTransport( |
317 | 63 | self.valid_url, self.valid_option_string) | 64 | self.valid_url, self.valid_option_string) |
318 | 64 | self.assertEqual(self.valid_url, transport.url) | 65 | self.assertEqual(self.valid_url, transport.url) |
319 | 65 | self.assertEqual(self.valid_secure_id, | 66 | self.assertEqual(self.valid_secure_id, |
320 | 66 | transport.options['secure_id']) | 67 | transport.options['secure_id']) |
321 | 67 | 68 | ||
322 | 68 | def test_submit_to_hexr_interpretation(self): | ||
323 | 69 | transport = CertificationTransport( | ||
324 | 70 | self.valid_url, "submit_to_hexr=1") | ||
325 | 71 | self.assertTrue(transport._submit_to_hexr is True) | ||
326 | 72 | |||
327 | 73 | def test_invalid_length_secure_id_are_rejected(self): | 69 | def test_invalid_length_secure_id_are_rejected(self): |
328 | 74 | length = 14 | 70 | length = 14 |
329 | 75 | dummy_id = "a" * length | 71 | dummy_id = "a" * length |
330 | 76 | option_string = "secure_id={}".format(dummy_id) | 72 | option_string = "secure_id={}".format(dummy_id) |
331 | 77 | with self.assertRaises(InvalidSecureIDError): | 73 | with self.assertRaises(InvalidSecureIDError): |
333 | 78 | CertificationTransport(self.valid_url, option_string) | 74 | SubmissionServiceTransport(self.valid_url, option_string) |
334 | 79 | 75 | ||
335 | 80 | def test_invalid_characters_in_secure_id_are_rejected(self): | 76 | def test_invalid_characters_in_secure_id_are_rejected(self): |
336 | 81 | option_string = "secure_id=aA0#" | 77 | option_string = "secure_id=aA0#" |
337 | 82 | with self.assertRaises(InvalidSecureIDError): | 78 | with self.assertRaises(InvalidSecureIDError): |
339 | 83 | CertificationTransport(self.valid_url, option_string) | 79 | SubmissionServiceTransport(self.valid_url, option_string) |
340 | 84 | 80 | ||
341 | 85 | def test_invalid_url(self): | 81 | def test_invalid_url(self): |
343 | 86 | transport = CertificationTransport( | 82 | transport = SubmissionServiceTransport( |
344 | 87 | self.invalid_url, self.valid_option_string) | 83 | self.invalid_url, self.valid_option_string) |
345 | 88 | dummy_data = BytesIO(b"some data to send") | 84 | dummy_data = BytesIO(b"some data to send") |
346 | 89 | requests.post.side_effect = InvalidSchema | 85 | requests.post.side_effect = InvalidSchema |
347 | @@ -92,12 +88,11 @@ class CertificationTransportTests(TestCase): | |||
348 | 92 | result = transport.send(dummy_data) | 88 | result = transport.send(dummy_data) |
349 | 93 | self.assertIsNotNone(result) | 89 | self.assertIsNotNone(result) |
350 | 94 | requests.post.assert_called_with( | 90 | requests.post.assert_called_with( |
353 | 95 | self.invalid_url, files={'data': dummy_data}, | 91 | self.invalid_url, data=dummy_data, proxies=None) |
352 | 96 | headers={'X_HARDWARE_ID': self.valid_secure_id}, proxies=None) | ||
354 | 97 | 92 | ||
355 | 98 | @mock.patch('checkbox_ng.certification.logger') | 93 | @mock.patch('checkbox_ng.certification.logger') |
356 | 99 | def test_valid_url_cant_connect(self, mock_logger): | 94 | def test_valid_url_cant_connect(self, mock_logger): |
358 | 100 | transport = CertificationTransport( | 95 | transport = SubmissionServiceTransport( |
359 | 101 | self.unreachable_url, self.valid_option_string) | 96 | self.unreachable_url, self.valid_option_string) |
360 | 102 | dummy_data = BytesIO(b"some data to send") | 97 | dummy_data = BytesIO(b"some data to send") |
361 | 103 | requests.post.side_effect = ConnectionError | 98 | requests.post.side_effect = ConnectionError |
362 | @@ -105,37 +100,20 @@ class CertificationTransportTests(TestCase): | |||
363 | 105 | result = transport.send(dummy_data) | 100 | result = transport.send(dummy_data) |
364 | 106 | self.assertIsNotNone(result) | 101 | self.assertIsNotNone(result) |
365 | 107 | requests.post.assert_called_with(self.unreachable_url, | 102 | requests.post.assert_called_with(self.unreachable_url, |
384 | 108 | files={'data': dummy_data}, | 103 | data=dummy_data, |
367 | 109 | headers={'X_HARDWARE_ID': | ||
368 | 110 | self.valid_secure_id}, | ||
369 | 111 | proxies=None) | ||
370 | 112 | |||
371 | 113 | @mock.patch('checkbox_ng.certification.logger') | ||
372 | 114 | def test_share_with_hexr_header_sent(self, mock_logger): | ||
373 | 115 | transport = CertificationTransport( | ||
374 | 116 | self.valid_url, self.valid_option_string+",submit_to_hexr=1") | ||
375 | 117 | dummy_data = BytesIO(b"some data to send") | ||
376 | 118 | result = transport.send(dummy_data) | ||
377 | 119 | self.assertIsNotNone(result) | ||
378 | 120 | requests.post.assert_called_with(self.valid_url, | ||
379 | 121 | files={'data': dummy_data}, | ||
380 | 122 | headers={'X_HARDWARE_ID': | ||
381 | 123 | self.valid_secure_id, | ||
382 | 124 | 'X-Share-With-HEXR': | ||
383 | 125 | True}, | ||
385 | 126 | proxies=None) | 104 | proxies=None) |
386 | 127 | 105 | ||
387 | 128 | def test_send_success(self): | 106 | def test_send_success(self): |
389 | 129 | transport = CertificationTransport( | 107 | transport = SubmissionServiceTransport( |
390 | 130 | self.valid_url, self.valid_option_string) | 108 | self.valid_url, self.valid_option_string) |
391 | 131 | requests.post.return_value = MagicMock(name='response') | 109 | requests.post.return_value = MagicMock(name='response') |
392 | 132 | requests.post.return_value.status_code = 200 | 110 | requests.post.return_value.status_code = 200 |
393 | 133 | requests.post.return_value.text = '{"id": 768}' | 111 | requests.post.return_value.text = '{"id": 768}' |
395 | 134 | result = transport.send(self.sample_xml) | 112 | result = transport.send(self.sample_archive) |
396 | 135 | self.assertTrue(result) | 113 | self.assertTrue(result) |
397 | 136 | 114 | ||
398 | 137 | def test_send_failure(self): | 115 | def test_send_failure(self): |
400 | 138 | transport = CertificationTransport( | 116 | transport = SubmissionServiceTransport( |
401 | 139 | self.valid_url, self.valid_option_string) | 117 | self.valid_url, self.valid_option_string) |
402 | 140 | requests.post.return_value = MagicMock(name='response') | 118 | requests.post.return_value = MagicMock(name='response') |
403 | 141 | requests.post.return_value.status_code = 412 | 119 | requests.post.return_value.status_code = 412 |
404 | @@ -145,7 +123,7 @@ class CertificationTransportTests(TestCase): | |||
405 | 145 | requests.post.return_value.raise_for_status = MagicMock( | 123 | requests.post.return_value.raise_for_status = MagicMock( |
406 | 146 | side_effect=HTTPError) | 124 | side_effect=HTTPError) |
407 | 147 | with self.assertRaises(TransportError): | 125 | with self.assertRaises(TransportError): |
409 | 148 | transport.send(self.sample_xml) | 126 | transport.send(self.sample_archive) |
410 | 149 | 127 | ||
411 | 150 | def proxy_test(self, environment, proxies): | 128 | def proxy_test(self, environment, proxies): |
412 | 151 | test_environment = environment | 129 | test_environment = environment |
413 | @@ -153,7 +131,7 @@ class CertificationTransportTests(TestCase): | |||
414 | 153 | test_config = PlainBoxConfig() | 131 | test_config = PlainBoxConfig() |
415 | 154 | test_config.environment = test_environment | 132 | test_config.environment = test_environment |
416 | 155 | 133 | ||
418 | 156 | transport = CertificationTransport( | 134 | transport = SubmissionServiceTransport( |
419 | 157 | self.valid_url, self.valid_option_string) | 135 | self.valid_url, self.valid_option_string) |
420 | 158 | dummy_data = BytesIO(b"some data to send") | 136 | dummy_data = BytesIO(b"some data to send") |
421 | 159 | 137 | ||
422 | @@ -163,8 +141,7 @@ class CertificationTransportTests(TestCase): | |||
423 | 163 | result = transport.send(dummy_data, config=test_config) | 141 | result = transport.send(dummy_data, config=test_config) |
424 | 164 | self.assertTrue(result) | 142 | self.assertTrue(result) |
425 | 165 | requests.post.assert_called_with( | 143 | requests.post.assert_called_with( |
428 | 166 | self.valid_url, files={'data': dummy_data}, | 144 | self.valid_url, data=dummy_data, |
427 | 167 | headers={'X_HARDWARE_ID': self.valid_secure_id}, | ||
429 | 168 | proxies=test_proxies) | 145 | proxies=test_proxies) |
430 | 169 | 146 | ||
431 | 170 | def test_set_only_one_proxy(self): | 147 | def test_set_only_one_proxy(self): |
432 | diff --git a/contrib/com.canonical.certification.PlainBox1.service b/contrib/com.canonical.certification.PlainBox1.service | |||
433 | 171 | deleted file mode 100644 | 148 | deleted file mode 100644 |
434 | index a40cf65..0000000 | |||
435 | --- a/contrib/com.canonical.certification.PlainBox1.service | |||
436 | +++ /dev/null | |||
437 | @@ -1,3 +0,0 @@ | |||
438 | 1 | [D-BUS Service] | ||
439 | 2 | Name=com.canonical.certification.PlainBox1 | ||
440 | 3 | Exec=/usr/bin/checkbox service | ||
441 | diff --git a/docs/conf.py b/docs/conf.py | |||
442 | index 970bfc7..58b6dba 100644 | |||
443 | --- a/docs/conf.py | |||
444 | +++ b/docs/conf.py | |||
445 | @@ -24,9 +24,7 @@ else: | |||
446 | 24 | # Inject mock modules so that we can build the | 24 | # Inject mock modules so that we can build the |
447 | 25 | # documentation without having the real stuff available | 25 | # documentation without having the real stuff available |
448 | 26 | from plainbox.vendor import mock | 26 | from plainbox.vendor import mock |
452 | 27 | for mod_name in ['lxml', 'xlsxwriter', 'dbus', 'dbus.lowlevel', | 27 | for mod_name in ['xlsxwriter']: |
450 | 28 | 'dbus.exceptions', 'dbus._compat', 'dbus.service', | ||
451 | 29 | '_dbus_bindings']: | ||
453 | 30 | sys.modules[mod_name] = mock.Mock() | 28 | sys.modules[mod_name] = mock.Mock() |
454 | 31 | print("Mocked {}".format(mod_name)) | 29 | print("Mocked {}".format(mod_name)) |
455 | 32 | try: | 30 | try: |
456 | diff --git a/docs/index.rst b/docs/index.rst | |||
457 | index 844f14f..ea4a5df 100644 | |||
458 | --- a/docs/index.rst | |||
459 | +++ b/docs/index.rst | |||
460 | @@ -31,24 +31,6 @@ or newer. | |||
461 | 31 | 31 | ||
462 | 32 | $ sudo add-apt-repository ppa:hardware-certification/public && sudo apt-get update && sudo apt-get install checkbox-ng | 32 | $ sudo add-apt-repository ppa:hardware-certification/public && sudo apt-get update && sudo apt-get install checkbox-ng |
463 | 33 | 33 | ||
464 | 34 | Running stable release update tests | ||
465 | 35 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
466 | 36 | |||
467 | 37 | Checkbox has special support for running stable release updates tests in an | ||
468 | 38 | automated manner. This runs all the jobs from the *sru.test plan* and sends the | ||
469 | 39 | results to the certification website. | ||
470 | 40 | |||
471 | 41 | To run SRU tests you will need to know the so-called :term:`Secure ID` of the | ||
472 | 42 | device you are testing. Once you know that all you need to do is run: | ||
473 | 43 | |||
474 | 44 | .. code-block:: bash | ||
475 | 45 | |||
476 | 46 | $ checkbox sru $secure_id submission.xml | ||
477 | 47 | |||
478 | 48 | The second argument, submission.xml, is a name of the fallback file that is | ||
479 | 49 | only created when sending the data to the certification website fails to work | ||
480 | 50 | for any reason. | ||
481 | 51 | |||
482 | 52 | Table of contents | 34 | Table of contents |
483 | 53 | ================= | 35 | ================= |
484 | 54 | 36 | ||
485 | diff --git a/docs/launcher-tutorial.rst b/docs/launcher-tutorial.rst | |||
486 | index 74dcf0d..d6dd71d 100644 | |||
487 | --- a/docs/launcher-tutorial.rst | |||
488 | +++ b/docs/launcher-tutorial.rst | |||
489 | @@ -99,7 +99,7 @@ number of the stock ones. In launchers version 1 there are 4 stock reports you | |||
490 | 99 | may use: | 99 | may use: |
491 | 100 | 100 | ||
492 | 101 | * ``text`` - print results as text on standard output | 101 | * ``text`` - print results as text on standard output |
494 | 102 | * ``submission_files`` - write ``html``, ``xlsx``, ``json`` and ``xml`` | 102 | * ``submission_files`` - write ``html``, ``xlsx``, ``json`` and ``tar.xz`` |
495 | 103 | files to ``$XDG_DATA_HOME`` directory (or to ``~/.local/share/`` if | 103 | files to ``$XDG_DATA_HOME`` directory (or to ``~/.local/share/`` if |
496 | 104 | ``$XDG_DATA_HOME`` is not defined. | 104 | ``$XDG_DATA_HOME`` is not defined. |
497 | 105 | * ``certification`` - send results to certification site | 105 | * ``certification`` - send results to certification site |
498 | @@ -485,7 +485,7 @@ report to standard output. | |||
499 | 485 | exporter = text | 485 | exporter = text |
500 | 486 | 486 | ||
501 | 487 | 2) Interactive testing of FooBar project. Report should be uploaded to the | 487 | 2) Interactive testing of FooBar project. Report should be uploaded to the |
503 | 488 | staging version of certification site and saved to /tmp/submission.xml | 488 | staging version of certification site and saved to /tmp/submission.tar.xz |
504 | 489 | 489 | ||
505 | 490 | :: | 490 | :: |
506 | 491 | 491 | ||
507 | @@ -512,15 +512,12 @@ staging version of certification site and saved to /tmp/submission.xml | |||
508 | 512 | 512 | ||
509 | 513 | [transport:local_file] | 513 | [transport:local_file] |
510 | 514 | type = file | 514 | type = file |
515 | 515 | path = /tmp/submission.xml | 515 | path = /tmp/submission.tar.xz |
512 | 516 | |||
513 | 517 | [exporter:xml] | ||
514 | 518 | unit = com.canonical.plainbox::hexr | ||
516 | 519 | 516 | ||
517 | 520 | [report:c3-staging] | 517 | [report:c3-staging] |
520 | 521 | transport = outfile | 518 | transport = certification |
521 | 522 | exporter = xml | 519 | exporter = tar |
522 | 523 | 520 | ||
523 | 524 | [report:file] | 521 | [report:file] |
524 | 525 | transport = local_file | 522 | transport = local_file |
526 | 526 | exporter = xml | 523 | exporter = tar |
527 | diff --git a/docs/stack.rst b/docs/stack.rst | |||
528 | index 7e8a6aa..8e36841 100644 | |||
529 | --- a/docs/stack.rst | |||
530 | +++ b/docs/stack.rst | |||
531 | @@ -71,11 +71,9 @@ Component Descriptions | |||
532 | 71 | | Checkbox (CLI) | - The python command-line interface | Application | | 71 | | Checkbox (CLI) | - The python command-line interface | Application | |
533 | 72 | | | | | | 72 | | | | | |
534 | 73 | | | - the text user interface | | | 73 | | | - the text user interface | | |
535 | 74 | | | - the SRU testing command | | | ||
536 | 75 | | | | | | 74 | | | | | |
537 | 76 | | | - Additional certification APIs | | | 75 | | | - Additional certification APIs | | |
538 | 77 | | | | | | 76 | | | | | |
539 | 78 | | | - sending data to Launchpad | | | ||
540 | 79 | | | - sending data to HEXR | | | 77 | | | - sending data to HEXR | | |
541 | 80 | +------------------------+---------------------------------------+-------------+ | 78 | +------------------------+---------------------------------------+-------------+ |
542 | 81 | | Client Certification | - canonical-certification-client | Provider | | 79 | | Client Certification | - canonical-certification-client | Provider | |
543 | @@ -107,7 +105,7 @@ Component Descriptions | |||
544 | 107 | | | - Trusted launcher | | | 105 | | | - Trusted launcher | | |
545 | 108 | | | - Dependency resolver | | | 106 | | | - Dependency resolver | | |
546 | 109 | | | - Command line handling | | | 107 | | | - Command line handling | | |
548 | 110 | | | - The XML, HTML and XSLX exporters | | | 108 | | | - The HTML and XSLX exporters | | |
549 | 111 | | | - and more... | | | 109 | | | - and more... | | |
550 | 112 | | | | | | 110 | | | | | |
551 | 113 | | | - Provider development toolkit | | | 111 | | | - Provider development toolkit | | |
552 | diff --git a/requirements/deb-core.txt b/requirements/deb-core.txt | |||
553 | index 5806499..18a7ef6 100644 | |||
554 | --- a/requirements/deb-core.txt | |||
555 | +++ b/requirements/deb-core.txt | |||
556 | @@ -1,2 +1 @@ | |||
557 | 1 | python3-guacamole | 1 | python3-guacamole |
558 | 2 | python3-lxml | ||
559 | diff --git a/requirements/deb-dbus.txt b/requirements/deb-dbus.txt | |||
560 | 3 | deleted file mode 100644 | 2 | deleted file mode 100644 |
561 | index a1d5df0..0000000 | |||
562 | --- a/requirements/deb-dbus.txt | |||
563 | +++ /dev/null | |||
564 | @@ -1 +0,0 @@ | |||
565 | 1 | python3-dbus | ||
566 | diff --git a/requirements/pip-dbus.txt b/requirements/pip-dbus.txt | |||
567 | 2 | deleted file mode 100644 | 0 | deleted file mode 100644 |
568 | index 43e3c72..0000000 | |||
569 | --- a/requirements/pip-dbus.txt | |||
570 | +++ /dev/null | |||
571 | @@ -1 +0,0 @@ | |||
572 | 1 | funcsigs==0.3 | ||
573 | diff --git a/requirements/rpm-dbus.txt b/requirements/rpm-dbus.txt | |||
574 | 2 | deleted file mode 100644 | 0 | deleted file mode 100644 |
575 | index a1d5df0..0000000 | |||
576 | --- a/requirements/rpm-dbus.txt | |||
577 | +++ /dev/null | |||
578 | @@ -1 +0,0 @@ | |||
579 | 1 | python3-dbus | ||
580 | diff --git a/setup.py b/setup.py | |||
581 | index 2b7bfaa..ac86e70 100755 | |||
582 | --- a/setup.py | |||
583 | +++ b/setup.py | |||
584 | @@ -70,8 +70,6 @@ setup( | |||
585 | 70 | 'checkbox-cli=checkbox_ng.launcher.checkbox_cli:main', | 70 | 'checkbox-cli=checkbox_ng.launcher.checkbox_cli:main', |
586 | 71 | ], | 71 | ], |
587 | 72 | 'plainbox.transport': [ | 72 | 'plainbox.transport': [ |
588 | 73 | 'certification=' | ||
589 | 74 | 'checkbox_ng.certification:CertificationTransport', | ||
590 | 75 | 'submission-service=' | 73 | 'submission-service=' |
591 | 76 | 'checkbox_ng.certification:SubmissionServiceTransport', | 74 | 'checkbox_ng.certification:SubmissionServiceTransport', |
592 | 77 | ], | 75 | ], |
+1.
I found one additional change worth considering. See inline.