Merge lp:~canonical-platform-qa/snappy-ecosystem-tests/test-release-snap-multiple-channels into lp:snappy-ecosystem-tests
- test-release-snap-multiple-channels
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Omer Akram |
Approved revision: | 54 |
Merged at revision: | 55 |
Proposed branch: | lp:~canonical-platform-qa/snappy-ecosystem-tests/test-release-snap-multiple-channels |
Merge into: | lp:snappy-ecosystem-tests |
Diff against target: |
268 lines (+184/-10) 6 files modified
pylint.cfg (+1/-1) snappy_ecosystem_tests/helpers/snapcraft/client.py (+31/-1) snappy_ecosystem_tests/helpers/store_apis/rest_apis.py (+30/-5) snappy_ecosystem_tests/tests/test_push_snap.py (+100/-0) snappy_ecosystem_tests/tests/test_store_apis_login.py (+3/-3) snappy_ecosystem_tests/unittests/__init__.py (+19/-0) |
To merge this branch: | bzr merge lp:~canonical-platform-qa/snappy-ecosystem-tests/test-release-snap-multiple-channels |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Omer Akram (community) | Approve | ||
platform-qa-bot | continuous-integration | Approve | |
Review via email: mp+321342@code.launchpad.net |
Commit message
Adding test cases:
* Automate Push and release a snap to a multiple channels via command and verify it via RESTful and verify it is available in all channels where it was published
* Automate Snapcraft can push against a new snap registered via RESTful API
* Push an invalid snap file via command and check it was not updated via RESTful API
Description of the change
Automate the scenarios:
* Push and release a snap to a multiple channels via command and verify it via RESTful and verify it is available in all channels where it was published
* Snapcraft can push against a new snap registered via RESTful API
* Push an invalid snap file via command and check it was not updated via RESTful API
For details refer to:
https:/
https:/
https:/
@run_tests: snappy_
platform-qa-bot (platform-qa-bot) wrote : | # |
- 50. By Heber Parrucci
-
Adding test_push_snap and re-organizing files
platform-qa-bot (platform-qa-bot) wrote : | # |
PASSED: Continuous integration, rev:50
https:/
Executed test runs:
None: https:/
Click here to trigger a rebuild:
https:/
- 51. By Heber Parrucci
-
merge from trunk
platform-qa-bot (platform-qa-bot) wrote : | # |
PASSED: Continuous integration, rev:51
https:/
Executed test runs:
None: https:/
Click here to trigger a rebuild:
https:/
- 52. By Heber Parrucci
-
Adding test:
push invalid snap file
platform-qa-bot (platform-qa-bot) wrote : | # |
PASSED: Continuous integration, rev:52
https:/
Executed test runs:
None: https:/
Click here to trigger a rebuild:
https:/
Omer Akram (om26er) wrote : | # |
Code looks good to me, will wait for test results.
platform-qa-bot (platform-qa-bot) wrote : | # |
FAILED: Continuous integration, rev:52
https:/
Executed test runs:
FAILURE: https:/
None: https:/
Click here to trigger a rebuild:
https:/
platform-qa-bot (platform-qa-bot) wrote : | # |
FAILED: Continuous integration, rev:52
https:/
Executed test runs:
None: https:/
Click here to trigger a rebuild:
https:/
- 53. By Heber Parrucci
-
merge from trunk
platform-qa-bot (platform-qa-bot) wrote : | # |
FAILED: Continuous integration, rev:52
https:/
Executed test runs:
None: https:/
Click here to trigger a rebuild:
https:/
platform-qa-bot (platform-qa-bot) wrote : | # |
FAILED: Continuous integration, rev:52
https:/
Executed test runs:
FAILURE: https:/
None: https:/
Click here to trigger a rebuild:
https:/
platform-qa-bot (platform-qa-bot) wrote : | # |
FAILED: Continuous integration, rev:53
https:/
Executed test runs:
FAILURE: https:/
None: https:/
Click here to trigger a rebuild:
https:/
platform-qa-bot (platform-qa-bot) wrote : | # |
FAILED: Continuous integration, rev:52
https:/
Executed test runs:
FAILURE: https:/
None: https:/
Click here to trigger a rebuild:
https:/
- 54. By Heber Parrucci
-
merge from trunk
platform-qa-bot (platform-qa-bot) wrote : | # |
FAILED: Continuous integration, rev:54
https:/
Executed test runs:
FAILURE: https:/
None: https:/
Click here to trigger a rebuild:
https:/
platform-qa-bot (platform-qa-bot) wrote : | # |
PASSED: Continuous integration, rev:54
https:/
Executed test runs:
SUCCESS: https:/
None: https:/
Click here to trigger a rebuild:
https:/
Preview Diff
1 | === modified file 'pylint.cfg' | |||
2 | --- pylint.cfg 2017-03-08 17:59:46 +0000 | |||
3 | +++ pylint.cfg 2017-04-04 20:02:43 +0000 | |||
4 | @@ -280,7 +280,7 @@ | |||
5 | 280 | ignore-docstrings=yes | 280 | ignore-docstrings=yes |
6 | 281 | 281 | ||
7 | 282 | # Ignore imports when computing similarities. | 282 | # Ignore imports when computing similarities. |
9 | 283 | ignore-imports=no | 283 | ignore-imports=yes |
10 | 284 | 284 | ||
11 | 285 | 285 | ||
12 | 286 | [MISCELLANEOUS] | 286 | [MISCELLANEOUS] |
13 | 287 | 287 | ||
14 | === modified file 'snappy_ecosystem_tests/helpers/snapcraft/client.py' | |||
15 | --- snappy_ecosystem_tests/helpers/snapcraft/client.py 2017-03-30 16:38:42 +0000 | |||
16 | +++ snappy_ecosystem_tests/helpers/snapcraft/client.py 2017-04-04 20:02:43 +0000 | |||
17 | @@ -57,7 +57,7 @@ | |||
18 | 57 | 57 | ||
19 | 58 | COMMAND_REGISTER = 'register' | 58 | COMMAND_REGISTER = 'register' |
20 | 59 | COMMAND_LIST_REGISTERED = 'list-registered' | 59 | COMMAND_LIST_REGISTERED = 'list-registered' |
22 | 60 | 60 | COMMAND_PUSH = 'push' | |
23 | 61 | LOGGER = logging.getLogger(__name__) | 61 | LOGGER = logging.getLogger(__name__) |
24 | 62 | 62 | ||
25 | 63 | HOSTNAME, USERNAME, PORT = get_snapcraft_remote_host_credentials() | 63 | HOSTNAME, USERNAME, PORT = get_snapcraft_remote_host_credentials() |
26 | @@ -92,6 +92,7 @@ | |||
27 | 92 | GRADE_SNAP_DEFAULT = 'stable' | 92 | GRADE_SNAP_DEFAULT = 'stable' |
28 | 93 | CONFINEMENT_SNAP_DEFAULT = 'strict' | 93 | CONFINEMENT_SNAP_DEFAULT = 'strict' |
29 | 94 | 94 | ||
30 | 95 | |||
31 | 95 | class Snapcraft: | 96 | class Snapcraft: |
32 | 96 | """Contain Snapcraft specific functionality to use via command | 97 | """Contain Snapcraft specific functionality to use via command |
33 | 97 | line interface""" | 98 | line interface""" |
34 | @@ -311,6 +312,35 @@ | |||
35 | 311 | self.ssh.pull(remote_snap_path, output_path_absolute) | 312 | self.ssh.pull(remote_snap_path, output_path_absolute) |
36 | 312 | return output_path_absolute | 313 | return output_path_absolute |
37 | 313 | 314 | ||
38 | 315 | def push(self, snap_file, channels=None): | ||
39 | 316 | """ | ||
40 | 317 | Push a snap. If channels are provided it will release as well. | ||
41 | 318 | :param snap_file: the snap's full path | ||
42 | 319 | :param channels: the list of channels to release the snap. | ||
43 | 320 | """ | ||
44 | 321 | command = '{} {}'.format(COMMAND_PUSH, snap_file) | ||
45 | 322 | if channels: | ||
46 | 323 | command = '{} {} {}'.format(command, | ||
47 | 324 | '--release', ','.join(channels)) | ||
48 | 325 | self._run_snapcraft_command_ssh(command) | ||
49 | 326 | |||
50 | 327 | def make_dummy_snap_file(self, name, version, arch=None): | ||
51 | 328 | """ | ||
52 | 329 | Create an empty snap file | ||
53 | 330 | :param name: the snap name | ||
54 | 331 | :param version: the snap version | ||
55 | 332 | :param arch: the snap architecture, | ||
56 | 333 | if None it takes the host one. | ||
57 | 334 | :return: the snap file full path | ||
58 | 335 | """ | ||
59 | 336 | tempdir = self.ssh.run_command('mktemp -d') | ||
60 | 337 | file_name = '{name}_{version}_{arch}.snap'.format( | ||
61 | 338 | name=name, | ||
62 | 339 | version=version, | ||
63 | 340 | arch=arch or self.ssh.run_command('dpkg --print-architecture')) | ||
64 | 341 | self.ssh.run_command('touch {}'.format(file_name), cwd=tempdir) | ||
65 | 342 | return os.path.join(tempdir, file_name) | ||
66 | 343 | |||
67 | 314 | 344 | ||
68 | 315 | def build_snapcraft_command(*args, base_command=PATH_SNAPCRAFT): | 345 | def build_snapcraft_command(*args, base_command=PATH_SNAPCRAFT): |
69 | 316 | """ | 346 | """ |
70 | 317 | 347 | ||
71 | === modified file 'snappy_ecosystem_tests/helpers/store_apis/rest_apis.py' | |||
72 | --- snappy_ecosystem_tests/helpers/store_apis/rest_apis.py 2017-03-10 10:18:26 +0000 | |||
73 | +++ snappy_ecosystem_tests/helpers/store_apis/rest_apis.py 2017-04-04 20:02:43 +0000 | |||
74 | @@ -154,14 +154,10 @@ | |||
75 | 154 | if save: | 154 | if save: |
76 | 155 | self.conf.save() | 155 | self.conf.save() |
77 | 156 | 156 | ||
78 | 157 | @property | ||
79 | 158 | def config(self): | ||
80 | 159 | """Get current config""" | ||
81 | 160 | return self.conf | ||
82 | 161 | |||
83 | 162 | def load_config(self): | 157 | def load_config(self): |
84 | 163 | """Load current config""" | 158 | """Load current config""" |
85 | 164 | self.conf.load() | 159 | self.conf.load() |
86 | 160 | return self.conf | ||
87 | 165 | 161 | ||
88 | 166 | def _extract_caveat_id(self, root_macaroon): | 162 | def _extract_caveat_id(self, root_macaroon): |
89 | 167 | """Extract caveat id for the given macaroon | 163 | """Extract caveat id for the given macaroon |
90 | @@ -299,6 +295,35 @@ | |||
91 | 299 | 295 | ||
92 | 300 | return response | 296 | return response |
93 | 301 | 297 | ||
94 | 298 | def is_snap_published(self, snap_name, version, revision, channels, | ||
95 | 299 | series=None, arch=None, **kwargs): | ||
96 | 300 | """ | ||
97 | 301 | Check if snap revision and version is published in all given channels | ||
98 | 302 | |||
99 | 303 | :param snap_name: the snap to check | ||
100 | 304 | :param version: the snap version to check | ||
101 | 305 | :param revision: the snap revision to check | ||
102 | 306 | :param channels: the list of channels to check | ||
103 | 307 | :param series: the snap series | ||
104 | 308 | :param arch: the snap architecture | ||
105 | 309 | :return: True if the snap revision is published in all given channels, | ||
106 | 310 | False otherwise | ||
107 | 311 | """ | ||
108 | 312 | retries = kwargs.get('retries', 10) | ||
109 | 313 | wait = kwargs.get('wait', 2) | ||
110 | 314 | attempt = 0 | ||
111 | 315 | channels_published = [] | ||
112 | 316 | while attempt < retries: | ||
113 | 317 | status = self.get_snap_status(snap_name, series=series, arch=arch) | ||
114 | 318 | for arch, details in status.items(): | ||
115 | 319 | channels_published = [d['channel'] for d in details if d.get( | ||
116 | 320 | 'revision') == revision and d.get('version') == version] | ||
117 | 321 | if sorted(channels_published) == sorted(channels): | ||
118 | 322 | return True | ||
119 | 323 | sleep(wait) | ||
120 | 324 | attempt += 1 | ||
121 | 325 | return False | ||
122 | 326 | |||
123 | 302 | def close_channels(self, snap_id, channel_names): | 327 | def close_channels(self, snap_id, channel_names): |
124 | 303 | """Close channels for the given snap_id. | 328 | """Close channels for the given snap_id. |
125 | 304 | First refresh macaroon if necessary""" | 329 | First refresh macaroon if necessary""" |
126 | 305 | 330 | ||
127 | === added file 'snappy_ecosystem_tests/tests/test_push_snap.py' | |||
128 | --- snappy_ecosystem_tests/tests/test_push_snap.py 1970-01-01 00:00:00 +0000 | |||
129 | +++ snappy_ecosystem_tests/tests/test_push_snap.py 2017-04-04 20:02:43 +0000 | |||
130 | @@ -0,0 +1,100 @@ | |||
131 | 1 | # -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- | ||
132 | 2 | |||
133 | 3 | # | ||
134 | 4 | # Snappy Ecosystem Tests | ||
135 | 5 | # Copyright (C) 2017 Canonical | ||
136 | 6 | # | ||
137 | 7 | # This program is free software: you can redistribute it and/or modify | ||
138 | 8 | # it under the terms of the GNU General Public License as published by | ||
139 | 9 | # the Free Software Foundation, either version 3 of the License, or | ||
140 | 10 | # (at your option) any later version. | ||
141 | 11 | # | ||
142 | 12 | # This program is distributed in the hope that it will be useful, | ||
143 | 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
144 | 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
145 | 15 | # GNU General Public License for more details. | ||
146 | 16 | # | ||
147 | 17 | # You should have received a copy of the GNU General Public License | ||
148 | 18 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
149 | 19 | # | ||
150 | 20 | |||
151 | 21 | """Tests for pushing snaps to the store.""" | ||
152 | 22 | |||
153 | 23 | from testtools import ExpectedException | ||
154 | 24 | |||
155 | 25 | from snappy_ecosystem_tests.helpers.snapcraft.client import Snapcraft | ||
156 | 26 | from snappy_ecosystem_tests.helpers.store_apis.errors import ( | ||
157 | 27 | StoreSnapHistoryError | ||
158 | 28 | ) | ||
159 | 29 | from snappy_ecosystem_tests.helpers.store_apis.rest_apis import Store | ||
160 | 30 | from snappy_ecosystem_tests.helpers.test_base import SnappyEcosystemTestCase | ||
161 | 31 | from snappy_ecosystem_tests.tests.commons import get_random_snap_name | ||
162 | 32 | from snappy_ecosystem_tests.utils.storeconfig import get_store_credentials | ||
163 | 33 | |||
164 | 34 | |||
165 | 35 | class PushSnapTestCase(SnappyEcosystemTestCase): | ||
166 | 36 | |||
167 | 37 | def setUp(self): | ||
168 | 38 | super().setUp() | ||
169 | 39 | self.store = Store() | ||
170 | 40 | self.snapcraft = Snapcraft() | ||
171 | 41 | email, password = get_store_credentials() | ||
172 | 42 | self.assertTrue(self.snapcraft.login(email, password)) | ||
173 | 43 | self.addCleanup(self.snapcraft.logout) | ||
174 | 44 | self.store.login(email, password) | ||
175 | 45 | self.addCleanup(self.store.logout) | ||
176 | 46 | |||
177 | 47 | def test_push_snap(self): | ||
178 | 48 | """Verify that snapcraft can push a snap against a new snap registered | ||
179 | 49 | via RESTful API | ||
180 | 50 | """ | ||
181 | 51 | snap_name = get_random_snap_name() | ||
182 | 52 | revision = 1 | ||
183 | 53 | version = '0.1' | ||
184 | 54 | self.assertTrue(self.store.register(snap_name), | ||
185 | 55 | 'Unable to register snap') | ||
186 | 56 | # Push the snap via Snapcraft | ||
187 | 57 | self.snapcraft.push(self.snapcraft.build(snap_name, version)) | ||
188 | 58 | # Check using REST API if snap was pushed | ||
189 | 59 | snap_history = self.store.get_snap_history(snap_name) | ||
190 | 60 | self.assertEqual(1, len(snap_history)) | ||
191 | 61 | snap = snap_history[0] | ||
192 | 62 | self.assertEqual(revision, snap['revision']) | ||
193 | 63 | self.assertEqual(version, snap['version']) | ||
194 | 64 | |||
195 | 65 | def test_push_and_release_snap_multiple_channels(self): | ||
196 | 66 | """Test push and release a snap to multiple channels and verify REST API | ||
197 | 67 | and verify it was published via REST API | ||
198 | 68 | """ | ||
199 | 69 | snap_name = get_random_snap_name() | ||
200 | 70 | channels = ['candidate', 'stable'] | ||
201 | 71 | revision = 1 | ||
202 | 72 | version = '0.1' | ||
203 | 73 | self.assertTrue(self.store.register(snap_name), | ||
204 | 74 | 'Unable to register snap') | ||
205 | 75 | # Push and release the snap to multiple channels | ||
206 | 76 | self.snapcraft.push(self.snapcraft.build(snap_name, version), | ||
207 | 77 | channels=channels) | ||
208 | 78 | # Check using REST API if snap was released to all channels | ||
209 | 79 | self.assertTrue(self.store.is_snap_published(snap_name, | ||
210 | 80 | version, | ||
211 | 81 | revision, | ||
212 | 82 | channels)) | ||
213 | 83 | |||
214 | 84 | def test_push_invalid_snap(self): | ||
215 | 85 | """Push an invalid snap file via command and check it was not updated | ||
216 | 86 | via RESTful API | ||
217 | 87 | """ | ||
218 | 88 | snap_name = get_random_snap_name() | ||
219 | 89 | version = '0.1' | ||
220 | 90 | self.assertTrue(self.store.register(snap_name), | ||
221 | 91 | 'Unable to register snap') | ||
222 | 92 | # Create and Push the invalid snap via Snapcraft | ||
223 | 93 | snap_path = self.snapcraft.make_dummy_snap_file(snap_name, version) | ||
224 | 94 | with ExpectedException(ValueError, | ||
225 | 95 | value_re='.*Read on filesystem failed.*'): | ||
226 | 96 | self.snapcraft.push(snap_path) | ||
227 | 97 | # Verify that the snap was not pushed using REST API | ||
228 | 98 | with ExpectedException(StoreSnapHistoryError, | ||
229 | 99 | value_re='.*Snap not found.*'): | ||
230 | 100 | self.store.get_snap_history(snap_name) | ||
231 | 0 | 101 | ||
232 | === modified file 'snappy_ecosystem_tests/tests/test_store_apis_login.py' | |||
233 | --- snappy_ecosystem_tests/tests/test_store_apis_login.py 2017-02-17 18:30:58 +0000 | |||
234 | +++ snappy_ecosystem_tests/tests/test_store_apis_login.py 2017-04-04 20:02:43 +0000 | |||
235 | @@ -34,6 +34,6 @@ | |||
236 | 34 | def test_api_login_logout(self): | 34 | def test_api_login_logout(self): |
237 | 35 | """Test login and logout functionality in store REST APIs""" | 35 | """Test login and logout functionality in store REST APIs""" |
238 | 36 | self.client.login(*get_store_credentials()) | 36 | self.client.login(*get_store_credentials()) |
242 | 37 | self.client.load_config() | 37 | config = self.client.load_config() |
243 | 38 | self.assertIsNotNone(self.client.config.get('macaroon')) | 38 | self.assertIsNotNone(config.get('macaroon')) |
244 | 39 | self.assertIsNotNone(self.client.config.get('unbound_discharge')) | 39 | self.assertIsNotNone(config.get('unbound_discharge')) |
245 | 40 | 40 | ||
246 | === modified file 'snappy_ecosystem_tests/unittests/__init__.py' | |||
247 | --- snappy_ecosystem_tests/unittests/__init__.py 2017-02-10 18:18:45 +0000 | |||
248 | +++ snappy_ecosystem_tests/unittests/__init__.py 2017-04-04 20:02:43 +0000 | |||
249 | @@ -0,0 +1,19 @@ | |||
250 | 1 | # -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- | ||
251 | 2 | |||
252 | 3 | # | ||
253 | 4 | # Snappy Ecosystem Tests | ||
254 | 5 | # Copyright (C) 2017 Canonical | ||
255 | 6 | # | ||
256 | 7 | # This program is free software: you can redistribute it and/or modify | ||
257 | 8 | # it under the terms of the GNU General Public License as published by | ||
258 | 9 | # the Free Software Foundation, either version 3 of the License, or | ||
259 | 10 | # (at your option) any later version. | ||
260 | 11 | # | ||
261 | 12 | # This program is distributed in the hope that it will be useful, | ||
262 | 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
263 | 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
264 | 15 | # GNU General Public License for more details. | ||
265 | 16 | # | ||
266 | 17 | # You should have received a copy of the GNU General Public License | ||
267 | 18 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
268 | 19 | # |
PASSED: Continuous integration, rev:49 /platform- qa-jenkins. ubuntu. com/job/ snappy- ecosystem- tests-ci/ 315/ /platform- qa-jenkins. ubuntu. com/job/ generic- update- mp/2234/ console
https:/
Executed test runs:
None: https:/
Click here to trigger a rebuild: /platform- qa-jenkins. ubuntu. com/job/ snappy- ecosystem- tests-ci/ 315/rebuild
https:/