Merge lp:~canonical-platform-qa/snappy-ecosystem-tests/test-release-snap-multiple-channels into lp:snappy-ecosystem-tests

Proposed by Heber Parrucci
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
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://prod.practitest.com/p/2505/tests/781225/edit
https://prod.practitest.com/p/2505/tests/781207/edit
https://prod.practitest.com/p/2505/tests/781219/edit

@run_tests: snappy_ecosystem_tests/tests/test_push_snap.py::PushSnapTestCase

To post a comment you must log in.
Revision history for this message
platform-qa-bot (platform-qa-bot) wrote :
review: Approve (continuous-integration)
50. By Heber Parrucci

Adding test_push_snap and re-organizing files

Revision history for this message
platform-qa-bot (platform-qa-bot) wrote :
review: Approve (continuous-integration)
51. By Heber Parrucci

merge from trunk

Revision history for this message
platform-qa-bot (platform-qa-bot) wrote :
review: Approve (continuous-integration)
52. By Heber Parrucci

Adding test:
push invalid snap file

Revision history for this message
platform-qa-bot (platform-qa-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
Omer Akram (om26er) wrote :

Code looks good to me, will wait for test results.

Revision history for this message
platform-qa-bot (platform-qa-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
platform-qa-bot (platform-qa-bot) wrote :
review: Needs Fixing (continuous-integration)
53. By Heber Parrucci

merge from trunk

Revision history for this message
platform-qa-bot (platform-qa-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
platform-qa-bot (platform-qa-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
platform-qa-bot (platform-qa-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
platform-qa-bot (platform-qa-bot) wrote :
review: Needs Fixing (continuous-integration)
54. By Heber Parrucci

merge from trunk

Revision history for this message
platform-qa-bot (platform-qa-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
platform-qa-bot (platform-qa-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
Omer Akram (om26er) wrote :

\o/

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'pylint.cfg'
--- pylint.cfg 2017-03-08 17:59:46 +0000
+++ pylint.cfg 2017-04-04 20:02:43 +0000
@@ -280,7 +280,7 @@
280ignore-docstrings=yes280ignore-docstrings=yes
281281
282# Ignore imports when computing similarities.282# Ignore imports when computing similarities.
283ignore-imports=no283ignore-imports=yes
284284
285285
286[MISCELLANEOUS]286[MISCELLANEOUS]
287287
=== modified file 'snappy_ecosystem_tests/helpers/snapcraft/client.py'
--- snappy_ecosystem_tests/helpers/snapcraft/client.py 2017-03-30 16:38:42 +0000
+++ snappy_ecosystem_tests/helpers/snapcraft/client.py 2017-04-04 20:02:43 +0000
@@ -57,7 +57,7 @@
5757
58COMMAND_REGISTER = 'register'58COMMAND_REGISTER = 'register'
59COMMAND_LIST_REGISTERED = 'list-registered'59COMMAND_LIST_REGISTERED = 'list-registered'
6060COMMAND_PUSH = 'push'
61LOGGER = logging.getLogger(__name__)61LOGGER = logging.getLogger(__name__)
6262
63HOSTNAME, USERNAME, PORT = get_snapcraft_remote_host_credentials()63HOSTNAME, USERNAME, PORT = get_snapcraft_remote_host_credentials()
@@ -92,6 +92,7 @@
92GRADE_SNAP_DEFAULT = 'stable'92GRADE_SNAP_DEFAULT = 'stable'
93CONFINEMENT_SNAP_DEFAULT = 'strict'93CONFINEMENT_SNAP_DEFAULT = 'strict'
9494
95
95class Snapcraft:96class Snapcraft:
96 """Contain Snapcraft specific functionality to use via command97 """Contain Snapcraft specific functionality to use via command
97 line interface"""98 line interface"""
@@ -311,6 +312,35 @@
311 self.ssh.pull(remote_snap_path, output_path_absolute)312 self.ssh.pull(remote_snap_path, output_path_absolute)
312 return output_path_absolute313 return output_path_absolute
313314
315 def push(self, snap_file, channels=None):
316 """
317 Push a snap. If channels are provided it will release as well.
318 :param snap_file: the snap's full path
319 :param channels: the list of channels to release the snap.
320 """
321 command = '{} {}'.format(COMMAND_PUSH, snap_file)
322 if channels:
323 command = '{} {} {}'.format(command,
324 '--release', ','.join(channels))
325 self._run_snapcraft_command_ssh(command)
326
327 def make_dummy_snap_file(self, name, version, arch=None):
328 """
329 Create an empty snap file
330 :param name: the snap name
331 :param version: the snap version
332 :param arch: the snap architecture,
333 if None it takes the host one.
334 :return: the snap file full path
335 """
336 tempdir = self.ssh.run_command('mktemp -d')
337 file_name = '{name}_{version}_{arch}.snap'.format(
338 name=name,
339 version=version,
340 arch=arch or self.ssh.run_command('dpkg --print-architecture'))
341 self.ssh.run_command('touch {}'.format(file_name), cwd=tempdir)
342 return os.path.join(tempdir, file_name)
343
314344
315def build_snapcraft_command(*args, base_command=PATH_SNAPCRAFT):345def build_snapcraft_command(*args, base_command=PATH_SNAPCRAFT):
316 """346 """
317347
=== modified file 'snappy_ecosystem_tests/helpers/store_apis/rest_apis.py'
--- snappy_ecosystem_tests/helpers/store_apis/rest_apis.py 2017-03-10 10:18:26 +0000
+++ snappy_ecosystem_tests/helpers/store_apis/rest_apis.py 2017-04-04 20:02:43 +0000
@@ -154,14 +154,10 @@
154 if save:154 if save:
155 self.conf.save()155 self.conf.save()
156156
157 @property
158 def config(self):
159 """Get current config"""
160 return self.conf
161
162 def load_config(self):157 def load_config(self):
163 """Load current config"""158 """Load current config"""
164 self.conf.load()159 self.conf.load()
160 return self.conf
165161
166 def _extract_caveat_id(self, root_macaroon):162 def _extract_caveat_id(self, root_macaroon):
167 """Extract caveat id for the given macaroon163 """Extract caveat id for the given macaroon
@@ -299,6 +295,35 @@
299295
300 return response296 return response
301297
298 def is_snap_published(self, snap_name, version, revision, channels,
299 series=None, arch=None, **kwargs):
300 """
301 Check if snap revision and version is published in all given channels
302
303 :param snap_name: the snap to check
304 :param version: the snap version to check
305 :param revision: the snap revision to check
306 :param channels: the list of channels to check
307 :param series: the snap series
308 :param arch: the snap architecture
309 :return: True if the snap revision is published in all given channels,
310 False otherwise
311 """
312 retries = kwargs.get('retries', 10)
313 wait = kwargs.get('wait', 2)
314 attempt = 0
315 channels_published = []
316 while attempt < retries:
317 status = self.get_snap_status(snap_name, series=series, arch=arch)
318 for arch, details in status.items():
319 channels_published = [d['channel'] for d in details if d.get(
320 'revision') == revision and d.get('version') == version]
321 if sorted(channels_published) == sorted(channels):
322 return True
323 sleep(wait)
324 attempt += 1
325 return False
326
302 def close_channels(self, snap_id, channel_names):327 def close_channels(self, snap_id, channel_names):
303 """Close channels for the given snap_id.328 """Close channels for the given snap_id.
304 First refresh macaroon if necessary"""329 First refresh macaroon if necessary"""
305330
=== added file 'snappy_ecosystem_tests/tests/test_push_snap.py'
--- snappy_ecosystem_tests/tests/test_push_snap.py 1970-01-01 00:00:00 +0000
+++ snappy_ecosystem_tests/tests/test_push_snap.py 2017-04-04 20:02:43 +0000
@@ -0,0 +1,100 @@
1# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
2
3#
4# Snappy Ecosystem Tests
5# Copyright (C) 2017 Canonical
6#
7# This program 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# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
19#
20
21"""Tests for pushing snaps to the store."""
22
23from testtools import ExpectedException
24
25from snappy_ecosystem_tests.helpers.snapcraft.client import Snapcraft
26from snappy_ecosystem_tests.helpers.store_apis.errors import (
27 StoreSnapHistoryError
28)
29from snappy_ecosystem_tests.helpers.store_apis.rest_apis import Store
30from snappy_ecosystem_tests.helpers.test_base import SnappyEcosystemTestCase
31from snappy_ecosystem_tests.tests.commons import get_random_snap_name
32from snappy_ecosystem_tests.utils.storeconfig import get_store_credentials
33
34
35class PushSnapTestCase(SnappyEcosystemTestCase):
36
37 def setUp(self):
38 super().setUp()
39 self.store = Store()
40 self.snapcraft = Snapcraft()
41 email, password = get_store_credentials()
42 self.assertTrue(self.snapcraft.login(email, password))
43 self.addCleanup(self.snapcraft.logout)
44 self.store.login(email, password)
45 self.addCleanup(self.store.logout)
46
47 def test_push_snap(self):
48 """Verify that snapcraft can push a snap against a new snap registered
49 via RESTful API
50 """
51 snap_name = get_random_snap_name()
52 revision = 1
53 version = '0.1'
54 self.assertTrue(self.store.register(snap_name),
55 'Unable to register snap')
56 # Push the snap via Snapcraft
57 self.snapcraft.push(self.snapcraft.build(snap_name, version))
58 # Check using REST API if snap was pushed
59 snap_history = self.store.get_snap_history(snap_name)
60 self.assertEqual(1, len(snap_history))
61 snap = snap_history[0]
62 self.assertEqual(revision, snap['revision'])
63 self.assertEqual(version, snap['version'])
64
65 def test_push_and_release_snap_multiple_channels(self):
66 """Test push and release a snap to multiple channels and verify REST API
67 and verify it was published via REST API
68 """
69 snap_name = get_random_snap_name()
70 channels = ['candidate', 'stable']
71 revision = 1
72 version = '0.1'
73 self.assertTrue(self.store.register(snap_name),
74 'Unable to register snap')
75 # Push and release the snap to multiple channels
76 self.snapcraft.push(self.snapcraft.build(snap_name, version),
77 channels=channels)
78 # Check using REST API if snap was released to all channels
79 self.assertTrue(self.store.is_snap_published(snap_name,
80 version,
81 revision,
82 channels))
83
84 def test_push_invalid_snap(self):
85 """Push an invalid snap file via command and check it was not updated
86 via RESTful API
87 """
88 snap_name = get_random_snap_name()
89 version = '0.1'
90 self.assertTrue(self.store.register(snap_name),
91 'Unable to register snap')
92 # Create and Push the invalid snap via Snapcraft
93 snap_path = self.snapcraft.make_dummy_snap_file(snap_name, version)
94 with ExpectedException(ValueError,
95 value_re='.*Read on filesystem failed.*'):
96 self.snapcraft.push(snap_path)
97 # Verify that the snap was not pushed using REST API
98 with ExpectedException(StoreSnapHistoryError,
99 value_re='.*Snap not found.*'):
100 self.store.get_snap_history(snap_name)
0101
=== modified file 'snappy_ecosystem_tests/tests/test_store_apis_login.py'
--- snappy_ecosystem_tests/tests/test_store_apis_login.py 2017-02-17 18:30:58 +0000
+++ snappy_ecosystem_tests/tests/test_store_apis_login.py 2017-04-04 20:02:43 +0000
@@ -34,6 +34,6 @@
34 def test_api_login_logout(self):34 def test_api_login_logout(self):
35 """Test login and logout functionality in store REST APIs"""35 """Test login and logout functionality in store REST APIs"""
36 self.client.login(*get_store_credentials())36 self.client.login(*get_store_credentials())
37 self.client.load_config()37 config = self.client.load_config()
38 self.assertIsNotNone(self.client.config.get('macaroon'))38 self.assertIsNotNone(config.get('macaroon'))
39 self.assertIsNotNone(self.client.config.get('unbound_discharge'))39 self.assertIsNotNone(config.get('unbound_discharge'))
4040
=== modified file 'snappy_ecosystem_tests/unittests/__init__.py'
--- snappy_ecosystem_tests/unittests/__init__.py 2017-02-10 18:18:45 +0000
+++ snappy_ecosystem_tests/unittests/__init__.py 2017-04-04 20:02:43 +0000
@@ -0,0 +1,19 @@
1# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
2
3#
4# Snappy Ecosystem Tests
5# Copyright (C) 2017 Canonical
6#
7# This program 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# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
19#

Subscribers

People subscribed via source and target branches