Merge lp:~frankban/juju-quickstart/apt-update-fixes into lp:juju-quickstart

Proposed by Francesco Banconi
Status: Merged
Merged at revision: 124
Proposed branch: lp:~frankban/juju-quickstart/apt-update-fixes
Merge into: lp:juju-quickstart
Diff against target: 363 lines (+102/-23)
6 files modified
quickstart/models/bundles.py (+9/-6)
quickstart/platform_support.py (+6/-2)
quickstart/tests/models/test_bundles.py (+48/-6)
quickstart/tests/test_app.py (+26/-4)
quickstart/tests/test_utils.py (+12/-5)
quickstart/utils.py (+1/-0)
To merge this branch: bzr merge lp:~frankban/juju-quickstart/apt-update-fixes
Reviewer Review Type Date Requested Status
Juju GUI Hackers Pending
Review via email: mp+252430@code.launchpad.net

Description of the change

Always retrieve bundle from new cs endpoint.

This is a follow up from previous branch,
and also includes the remaining bits before
2.0.1 release.

Even if a legacy bundle is specified, and even
if the legacy bundle data is retrieved for name
validation, always use the new bundle.yaml
charm store endpoint when returning the bundle
contents.

This branch also include a drive by fix to always
run `apt-get update` before installing packages,
even in the case --distro-only is enabled.

Tests: `make check`.

QA:
install bundles with quickstart:
`devenv/bin/juju-quickstart {bundle}`
Try the following bundles:
- devenv/bin/juju-quickstart mediawiki-single
- devenv/bin/juju-quickstart u/bigdata-dev/apache-analytics-sql
- devenv/bin/juju-quickstart bundle:mediawiki/scalable
- devenv/bin/juju-quickstart bundle:~landscape/landscape-dense-maas/landscape-dense-maas
- devenv/bin/juju-quickstart bundle:django/example-single

Those instead should return errors:
- devenv/bin/juju-quickstart mediawiki/trusty
- devenv/bin/juju-quickstart mediawiki-nosuch
- devenv/bin/juju-quickstart no-such
- devenv/bin/juju-quickstart bundle:no/such
- devenv/bin/juju-quickstart bundle:invalid
- devenv/bin/juju-quickstart bundle:~landscape/landscape-dense-maas/landscape

Thank you!

https://codereview.appspot.com/215750043/

To post a comment you must log in.
Revision history for this message
Francesco Banconi (frankban) wrote :

Reviewers: mp+252430_code.launchpad.net,

Message:
Please take a look.

Description:
Always retrieve bundle from new cs endpoint.

This is a follow up from previous branch,
and also includes the remaining bits before
2.0.1 release.

Even if a legacy bundle is specified, and even
if the legacy bundle data is retrieved for name
validation, always use the new bundle.yaml
charm store endpoint when returning the bundle
contents.

This branch also include a drive by fix to always
run `apt-get update` before installing packages,
even in the case --distro-only is enabled.

Tests: `make check`.

QA:
install bundles with quickstart:
`devenv/bin/juju-quickstart {bundle}`
Try the following bundles:
- devenv/bin/juju-quickstart mediawiki-single
- devenv/bin/juju-quickstart u/bigdata-dev/apache-analytics-sql
- devenv/bin/juju-quickstart bundle:mediawiki/scalable
- devenv/bin/juju-quickstart
bundle:~landscape/landscape-dense-maas/landscape-dense-maas
- devenv/bin/juju-quickstart bundle:django/example-single

Those instead should return errors:
- devenv/bin/juju-quickstart mediawiki/trusty
- devenv/bin/juju-quickstart mediawiki-nosuch
- devenv/bin/juju-quickstart no-such
- devenv/bin/juju-quickstart bundle:no/such
- devenv/bin/juju-quickstart bundle:invalid
- devenv/bin/juju-quickstart
bundle:~landscape/landscape-dense-maas/landscape

Thank you!

https://code.launchpad.net/~frankban/juju-quickstart/apt-update-fixes/+merge/252430

(do not edit description out of merge proposal)

Please review this at https://codereview.appspot.com/215750043/

Affected files (+104, -23 lines):
   A [revision details]
   M quickstart/models/bundles.py
   M quickstart/platform_support.py
   M quickstart/tests/models/test_bundles.py
   M quickstart/tests/test_app.py
   M quickstart/tests/test_utils.py
   M quickstart/utils.py

Revision history for this message
Brad Crittenden (bac) wrote :
Revision history for this message
Richard Harding (rharding) wrote :
Revision history for this message
Richard Harding (rharding) wrote :

On 2015/03/10 13:55:46, rharding wrote:
> LGTM no qa atm

QA OK thanks!

https://codereview.appspot.com/215750043/

Revision history for this message
Francesco Banconi (frankban) wrote :

*** Submitted:

Always retrieve bundle from new cs endpoint.

This is a follow up from previous branch,
and also includes the remaining bits before
2.0.1 release.

Even if a legacy bundle is specified, and even
if the legacy bundle data is retrieved for name
validation, always use the new bundle.yaml
charm store endpoint when returning the bundle
contents.

This branch also include a drive by fix to always
run `apt-get update` before installing packages,
even in the case --distro-only is enabled.

Tests: `make check`.

QA:
install bundles with quickstart:
`devenv/bin/juju-quickstart {bundle}`
Try the following bundles:
- devenv/bin/juju-quickstart mediawiki-single
- devenv/bin/juju-quickstart u/bigdata-dev/apache-analytics-sql
- devenv/bin/juju-quickstart bundle:mediawiki/scalable
- devenv/bin/juju-quickstart
bundle:~landscape/landscape-dense-maas/landscape-dense-maas
- devenv/bin/juju-quickstart bundle:django/example-single

Those instead should return errors:
- devenv/bin/juju-quickstart mediawiki/trusty
- devenv/bin/juju-quickstart mediawiki-nosuch
- devenv/bin/juju-quickstart no-such
- devenv/bin/juju-quickstart bundle:no/such
- devenv/bin/juju-quickstart bundle:invalid
- devenv/bin/juju-quickstart
bundle:~landscape/landscape-dense-maas/landscape

Thank you!

R=bac, rharding
CC=
https://codereview.appspot.com/215750043

https://codereview.appspot.com/215750043/

Revision history for this message
Francesco Banconi (frankban) wrote :

Thanks for the quick reviews and QA Brad and Rick!

https://codereview.appspot.com/215750043/

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'quickstart/models/bundles.py'
--- quickstart/models/bundles.py 2015-03-10 10:18:58 +0000
+++ quickstart/models/bundles.py 2015-03-10 13:22:58 +0000
@@ -142,7 +142,10 @@
142 """142 """
143 if source.startswith('bundle:'):143 if source.startswith('bundle:'):
144 # The source refers to an old style bundle URL.144 # The source refers to an old style bundle URL.
145 return _bundle_from_charmworld_url(source)145 try:
146 return _bundle_from_charmworld_url(source)
147 except charmstore.NotFoundError as err:
148 raise IOError(bytes(err))
146149
147 has_extension = source.endswith('.yaml') or source.endswith('.json')150 has_extension = source.endswith('.yaml') or source.endswith('.json')
148 is_remote = source.startswith('http://') or source.startswith('https://')151 is_remote = source.startswith('http://') or source.startswith('https://')
@@ -200,6 +203,7 @@
200 content is not valid.203 content is not valid.
201 Raise a IOError if a problem is encountered while fetching the YAML204 Raise a IOError if a problem is encountered while fetching the YAML
202 content from the charm store.205 content from the charm store.
206 Raise a charmstore.NotFoundError if the bundle is not found.
203 """207 """
204 match = _charmworld_url_expression.match(url)208 match = _charmworld_url_expression.match(url)
205 if match is None:209 if match is None:
@@ -224,11 +228,10 @@
224 # in the original YAML is also required.228 # in the original YAML is also required.
225 reference = references.Reference(229 reference = references.Reference(
226 'cs', user, 'bundle', basket, revision)230 'cs', user, 'bundle', basket, revision)
227 try:231 # Validate the bundle name is included in the legacy data.
228 data = charmstore.get_legacy_bundle_data(reference)232 _flatten_data(charmstore.get_legacy_bundle_data(reference), name)
229 except charmstore.NotFoundError as err:233 # Retrieve the new bundle data corresponding to the shorter reference.
230 raise IOError(bytes(err))234 data = charmstore.get_bundle_data(reference)
231 data = _flatten_data(data, name)
232235
233 validate(data)236 validate(data)
234 # XXX frankban 2015-02-26: remove this when switching to the new bundle237 # XXX frankban 2015-02-26: remove this when switching to the new bundle
235238
=== modified file 'quickstart/platform_support.py'
--- quickstart/platform_support.py 2015-01-30 15:27:07 +0000
+++ quickstart/platform_support.py 2015-03-10 13:22:58 +0000
@@ -83,10 +83,14 @@
83 print('sudo privileges will be used for the installation of \n'83 print('sudo privileges will be used for the installation of \n'
84 'the following packages: {}\n'84 'the following packages: {}\n'
85 'this can take a while...'.format(', '.join(required_packages)))85 'this can take a while...'.format(', '.join(required_packages)))
86 if distro_only:
87 retcode, _, error = utils.call('sudo', '/usr/bin/apt-get', 'update')
88 if retcode:
89 raise OSError(error.encode('utf-8'))
86 retcode, _, error = utils.call(90 retcode, _, error = utils.call(
87 'sudo', '/usr/bin/apt-get', 'install', '-y', *required_packages)91 'sudo', '/usr/bin/apt-get', 'install', '-y', *required_packages)
88 if retcode:92 if retcode:
89 raise OSError(bytes(error))93 raise OSError(error.encode('utf-8'))
9094
9195
92def _installer_osx(distro_only, required_packages):96def _installer_osx(distro_only, required_packages):
@@ -102,7 +106,7 @@
102 retcode, _, error = utils.call(106 retcode, _, error = utils.call(
103 '/usr/local/bin/brew', 'install', *required_packages)107 '/usr/local/bin/brew', 'install', *required_packages)
104 if retcode:108 if retcode:
105 raise OSError(bytes(error))109 raise OSError(error.encode('utf-8'))
106110
107111
108INSTALLERS = {112INSTALLERS = {
109113
=== modified file 'quickstart/tests/models/test_bundles.py'
--- quickstart/tests/models/test_bundles.py 2015-03-09 17:50:28 +0000
+++ quickstart/tests/models/test_bundles.py 2015-03-10 13:22:58 +0000
@@ -121,8 +121,10 @@
121 side_effect = [121 side_effect = [
122 # A first call urlread returns a not found error.122 # A first call urlread returns a not found error.
123 netutils.NotFoundError('boo!'),123 netutils.NotFoundError('boo!'),
124 # A second call succeeds.124 # A second call to retrieve the legacy data succeeds.
125 self.legacy_bundle_content,125 self.legacy_bundle_content,
126 # The third call to retrieve the new data succeeds.
127 self.bundle_content,
126 ]128 ]
127 with self.patch_urlread(error=side_effect) as mock_urlread:129 with self.patch_urlread(error=side_effect) as mock_urlread:
128 bundle = bundles.from_source('bundle:mediawiki/bundle1')130 bundle = bundles.from_source('bundle:mediawiki/bundle1')
@@ -132,10 +134,11 @@
132 # XXX frankban 2015-03-09: remove this check once we get rid of the134 # XXX frankban 2015-03-09: remove this check once we get rid of the
133 # charmworld id concept.135 # charmworld id concept.
134 self.assertEqual('mediawiki/bundle1', bundle.reference.charmworld_id)136 self.assertEqual('mediawiki/bundle1', bundle.reference.charmworld_id)
135 # The urlread function has been called two times: the first time137 # The urlread function has been called three times: the first time
136 # including both the basket and the bundle name, the second time138 # including both the basket and the bundle name, the second time
137 # to retrieve the legacy bundle yaml, only including the basket.139 # to retrieve the legacy bundle YAML, the third time to retrieve the
138 self.assertEqual(mock_urlread.call_count, 2)140 # new bundle YAML (this time without including the basket name).
141 self.assertEqual(len(side_effect), mock_urlread.call_count)
139 mock_urlread.assert_has_calls([142 mock_urlread.assert_has_calls([
140 mock.call(143 mock.call(
141 settings.CHARMSTORE_API +144 settings.CHARMSTORE_API +
@@ -143,6 +146,9 @@
143 mock.call(146 mock.call(
144 settings.CHARMSTORE_API +147 settings.CHARMSTORE_API +
145 'bundle/mediawiki/archive/bundles.yaml.orig'),148 'bundle/mediawiki/archive/bundles.yaml.orig'),
149 mock.call(
150 settings.CHARMSTORE_API +
151 'bundle/mediawiki/archive/bundle.yaml'),
146 ])152 ])
147153
148 def test_charmworld_bundle_deprecation_warning(self):154 def test_charmworld_bundle_deprecation_warning(self):
@@ -193,7 +199,7 @@
193 # The urlread function has been called two times: the first time199 # The urlread function has been called two times: the first time
194 # including both the basket and the bundle name, the second time200 # including both the basket and the bundle name, the second time
195 # to retrieve the legacy bundle yaml, only including the basket.201 # to retrieve the legacy bundle yaml, only including the basket.
196 self.assertEqual(mock_urlread.call_count, 2)202 self.assertEqual(2, mock_urlread.call_count)
197 mock_urlread.assert_has_calls([203 mock_urlread.assert_has_calls([
198 mock.call(204 mock.call(
199 settings.CHARMSTORE_API +205 settings.CHARMSTORE_API +
@@ -220,7 +226,7 @@
220 # The urlread function has been called two times: the first time226 # The urlread function has been called two times: the first time
221 # including both the basket and the bundle name, the second time227 # including both the basket and the bundle name, the second time
222 # to retrieve the legacy bundle yaml, only including the basket.228 # to retrieve the legacy bundle yaml, only including the basket.
223 self.assertEqual(mock_urlread.call_count, 2)229 self.assertEqual(len(side_effect), mock_urlread.call_count)
224 mock_urlread.assert_has_calls([230 mock_urlread.assert_has_calls([
225 mock.call(231 mock.call(
226 settings.CHARMSTORE_API +232 settings.CHARMSTORE_API +
@@ -230,6 +236,42 @@
230 'bundle/django/archive/bundles.yaml.orig'),236 'bundle/django/archive/bundles.yaml.orig'),
231 ])237 ])
232238
239 def test_charmworld_bundle_from_legacy_not_found_error(self):
240 # An IOError is raised if the legacy bundle cannot be found.
241 side_effect = [
242 # A first call urlread returns a not found error.
243 netutils.NotFoundError('boo!'),
244 # A second call to retrieve the legacy bundle data succeeds.
245 self.legacy_bundle_content,
246 # The third call to get the bundle from the new API endpoint fails.
247 # Note that this is unlikely to happen.
248 netutils.NotFoundError('what!'),
249 ]
250 expected_error = (
251 'charm store resource not found at '
252 '{}bundle/django/archive/bundle.yaml: '
253 'what!'.format(settings.CHARMSTORE_API))
254 with self.patch_urlread(error=side_effect) as mock_urlread:
255 with self.assertRaises(IOError) as ctx:
256 bundles.from_source('bundle:django/bundle1')
257 self.assertEqual(expected_error, bytes(ctx.exception))
258 # The urlread function has been called three times: the first time
259 # including both the basket and the bundle name, the second time
260 # to retrieve the legacy bundle YAML, the third time to retrieve the
261 # new bundle YAML (this time without including the basket name).
262 self.assertEqual(len(side_effect), mock_urlread.call_count)
263 mock_urlread.assert_has_calls([
264 mock.call(
265 settings.CHARMSTORE_API +
266 'bundle/django-bundle1/archive/bundle.yaml'),
267 mock.call(
268 settings.CHARMSTORE_API +
269 'bundle/django/archive/bundles.yaml.orig'),
270 mock.call(
271 settings.CHARMSTORE_API +
272 'bundle/django/archive/bundle.yaml'),
273 ])
274
233 def test_jujucharms_bundle(self):275 def test_jujucharms_bundle(self):
234 # A bundle instance is properly returned from a jujucharms.com id.276 # A bundle instance is properly returned from a jujucharms.com id.
235 with self.patch_urlread(contents=self.bundle_content) as mock_urlread:277 with self.patch_urlread(contents=self.bundle_content) as mock_urlread:
236278
=== modified file 'quickstart/tests/test_app.py'
--- quickstart/tests/test_app.py 2015-03-09 17:50:28 +0000
+++ quickstart/tests/test_app.py 2015-03-10 13:22:58 +0000
@@ -98,9 +98,10 @@
98 side_effects = (98 side_effects = (
99 (127, '', 'no juju'), # Retrieve the Juju version.99 (127, '', 'no juju'), # Retrieve the Juju version.
100 (0, 'saucy', ''), # Retrieve the Ubuntu release codename.100 (0, 'saucy', ''), # Retrieve the Ubuntu release codename.
101 (0, 'update 1', ''), # Update the repository with new sources.
101 (0, 'install add repo', ''), # Install add-apt-repository.102 (0, 'install add repo', ''), # Install add-apt-repository.
102 (0, 'add repo', ''), # Add the juju stable repository.103 (0, 'add repo', ''), # Add the juju stable repository.
103 (0, 'update', ''), # Update the repository with new sources.104 (0, 'update 2', ''), # Update the repository with new sources.
104 (0, 'install', ''), # Install missing packages.105 (0, 'install', ''), # Install missing packages.
105 (0, '1.18.0', ''), # Retrieve the version again.106 (0, '1.18.0', ''), # Retrieve the version again.
106 )107 )
@@ -109,6 +110,7 @@
109 mock_call.assert_has_calls([110 mock_call.assert_has_calls([
110 mock.call(self.juju_command, 'version'),111 mock.call(self.juju_command, 'version'),
111 mock.call('lsb_release', '-cs'),112 mock.call('lsb_release', '-cs'),
113 mock.call('sudo', self.apt_get, 'update'),
112 mock.call('sudo', self.apt_get, 'install', '-y',114 mock.call('sudo', self.apt_get, 'install', '-y',
113 'software-properties-common'),115 'software-properties-common'),
114 mock.call('sudo', self.add_repository, '-y', 'ppa:juju/stable'),116 mock.call('sudo', self.add_repository, '-y', 'ppa:juju/stable'),
@@ -161,6 +163,7 @@
161 # All the missing packages are installed from the distro repository.163 # All the missing packages are installed from the distro repository.
162 side_effects = (164 side_effects = (
163 (127, '', 'no juju'), # Retrieve the Juju version.165 (127, '', 'no juju'), # Retrieve the Juju version.
166 (0, 'update', ''), # Update the repository with new sources.
164 (0, 'install', ''), # Install missing packages.167 (0, 'install', ''), # Install missing packages.
165 (0, '1.17.42', ''), # Retrieve the version again.168 (0, '1.17.42', ''), # Retrieve the version again.
166 )169 )
@@ -169,6 +172,7 @@
169 self.assertEqual(len(side_effects), mock_call.call_count)172 self.assertEqual(len(side_effects), mock_call.call_count)
170 mock_call.assert_has_calls([173 mock_call.assert_has_calls([
171 mock.call(self.juju_command, 'version'),174 mock.call(self.juju_command, 'version'),
175 mock.call('sudo', self.apt_get, 'update'),
172 mock.call('sudo', self.apt_get, 'install', '-y',176 mock.call('sudo', self.apt_get, 'install', '-y',
173 'juju-core', 'juju-local'),177 'juju-core', 'juju-local'),
174 mock.call(self.juju_command, 'version'),178 mock.call(self.juju_command, 'version'),
@@ -199,9 +203,10 @@
199 (0, '1.16.42', ''), # Check the juju command.203 (0, '1.16.42', ''), # Check the juju command.
200 (127, '', 'no lxc'), # Check the lxc-ls command.204 (127, '', 'no lxc'), # Check the lxc-ls command.
201 (0, 'saucy', ''), # Retrieve the Ubuntu release codename.205 (0, 'saucy', ''), # Retrieve the Ubuntu release codename.
206 (0, 'update 1', ''), # Update the repository with new sources.
202 (0, 'install add repo', ''), # Install add-apt-repository.207 (0, 'install add repo', ''), # Install add-apt-repository.
203 (0, 'add repo', ''), # Add the juju stable repository.208 (0, 'add repo', ''), # Add the juju stable repository.
204 (0, 'update', ''), # Update the repository with new sources.209 (0, 'update 2', ''), # Update the repository with new sources.
205 (0, 'install', ''), # Install missing packages.210 (0, 'install', ''), # Install missing packages.
206 )211 )
207 mock_call, juju_version = self.call_ensure_dependencies(side_effects)212 mock_call, juju_version = self.call_ensure_dependencies(side_effects)
@@ -210,6 +215,7 @@
210 mock.call(self.juju_command, 'version'),215 mock.call(self.juju_command, 'version'),
211 mock.call('/usr/bin/lxc-ls'),216 mock.call('/usr/bin/lxc-ls'),
212 mock.call('lsb_release', '-cs'),217 mock.call('lsb_release', '-cs'),
218 mock.call('sudo', self.apt_get, 'update'),
213 mock.call('sudo', self.apt_get, 'install', '-y',219 mock.call('sudo', self.apt_get, 'install', '-y',
214 'software-properties-common'),220 'software-properties-common'),
215 mock.call('sudo', self.add_repository, '-y', 'ppa:juju/stable'),221 mock.call('sudo', self.add_repository, '-y', 'ppa:juju/stable'),
@@ -231,6 +237,7 @@
231 side_effects = (237 side_effects = (
232 (0, '1.16.42', ''), # Check the juju command.238 (0, '1.16.42', ''), # Check the juju command.
233 (127, '', 'no lxc'), # Check the lxc-ls command.239 (127, '', 'no lxc'), # Check the lxc-ls command.
240 (0, 'update', ''), # Update the repository with new sources.
234 (0, 'install', ''), # Install missing packages.241 (0, 'install', ''), # Install missing packages.
235 )242 )
236 mock_call, juju_version = self.call_ensure_dependencies(243 mock_call, juju_version = self.call_ensure_dependencies(
@@ -239,6 +246,7 @@
239 mock_call.assert_has_calls([246 mock_call.assert_has_calls([
240 mock.call(self.juju_command, 'version'),247 mock.call(self.juju_command, 'version'),
241 mock.call('/usr/bin/lxc-ls'),248 mock.call('/usr/bin/lxc-ls'),
249 mock.call('sudo', self.apt_get, 'update'),
242 mock.call('sudo', self.apt_get, 'install', '-y', 'juju-local'),250 mock.call('sudo', self.apt_get, 'install', '-y', 'juju-local'),
243 ])251 ])
244 mock_print.assert_called_once_with(252 mock_print.assert_called_once_with(
@@ -252,6 +260,7 @@
252 side_effects = (260 side_effects = (
253 (127, '', 'no juju'), # Check the juju command.261 (127, '', 'no juju'), # Check the juju command.
254 (0, 'saucy', ''), # Retrieve the Ubuntu release codename.262 (0, 'saucy', ''), # Retrieve the Ubuntu release codename.
263 (0, 'update', ''), # Update the repository with new sources.
255 (0, 'install add repo', ''), # Install add-apt-repository.264 (0, 'install add repo', ''), # Install add-apt-repository.
256 (1, '', 'add repo error'), # Add the juju stable repository.265 (1, '', 'add repo error'), # Add the juju stable repository.
257 )266 )
@@ -264,15 +273,27 @@
264 side_effects = (273 side_effects = (
265 (127, '', 'no juju'), # Check the juju command.274 (127, '', 'no juju'), # Check the juju command.
266 (0, 'saucy', ''), # Retrieve the Ubuntu release codename.275 (0, 'saucy', ''), # Retrieve the Ubuntu release codename.
276 (0, 'update 1', ''), # Update the repository with new sources.
267 (0, 'install add repo', ''), # Install add-apt-repository.277 (0, 'install add repo', ''), # Install add-apt-repository.
268 (0, 'add repo', ''), # Add the juju stable repository.278 (0, 'add repo', ''), # Add the juju stable repository.
269 (0, 'update', ''), # Update the repository with new sources.279 (0, 'update 2', ''), # Update the repository with new sources.
270 (1, '', 'install error'), # Install missing packages.280 (1, '', 'install error'), # Install missing packages.
271 )281 )
272 with self.assert_program_exit('install error'):282 with self.assert_program_exit('install error'):
273 mock_call = self.call_ensure_dependencies(side_effects)[0]283 mock_call = self.call_ensure_dependencies(side_effects)[0]
274 self.assertEqual(3, mock_call.call_count)284 self.assertEqual(3, mock_call.call_count)
275285
286 def test_distro_only_update_failure_apt(self, mock_print):
287 # A ProgramExit is raised if updating APT sources fails.
288 side_effects = (
289 (127, '', 'no juju'), # Retrieve the Juju version.
290 (1, '', 'update error'), # Update the repository with new sources.
291 )
292 with self.assert_program_exit('update error'):
293 mock_call = self.call_ensure_dependencies(
294 side_effects, distro_only=True)[0]
295 self.assertEqual(2, mock_call.call_count)
296
276 def test_failed_install_osx(self, mock_print):297 def test_failed_install_osx(self, mock_print):
277 # A ProgramExit is raised if the packages installation fails.298 # A ProgramExit is raised if the packages installation fails.
278 side_effects = (299 side_effects = (
@@ -292,9 +313,10 @@
292 side_effects = (313 side_effects = (
293 (127, '', 'no juju'), # Check the juju command.314 (127, '', 'no juju'), # Check the juju command.
294 (0, 'saucy', ''), # Retrieve the Ubuntu release codename.315 (0, 'saucy', ''), # Retrieve the Ubuntu release codename.
316 (0, 'update 1', ''), # Update the repository with new sources.
295 (0, 'install add repo', ''), # Install add-apt-repository.317 (0, 'install add repo', ''), # Install add-apt-repository.
296 (0, 'add repo', ''), # Add the juju stable repository.318 (0, 'add repo', ''), # Add the juju stable repository.
297 (0, 'update', ''), # Update the repository with new sources.319 (0, 'update 2', ''), # Update the repository with new sources.
298 (0, 'install', ''), # Install missing packages.320 (0, 'install', ''), # Install missing packages.
299 (127, '', 'no juju (again)'), # Retrieve the Juju version.321 (127, '', 'no juju (again)'), # Retrieve the Juju version.
300 )322 )
301323
=== modified file 'quickstart/tests/test_utils.py'
--- quickstart/tests/test_utils.py 2015-02-09 12:34:33 +0000
+++ quickstart/tests/test_utils.py 2015-03-10 13:22:58 +0000
@@ -40,9 +40,10 @@
40 apt_get = '/usr/bin/apt-get'40 apt_get = '/usr/bin/apt-get'
41 repository = 'ppa:good/stuff'41 repository = 'ppa:good/stuff'
42 side_effects = (42 side_effects = (
43 (0, 'first update', ''), # Update the global repository.
43 (0, 'apt-get install', ''), # Install add-apt-repository.44 (0, 'apt-get install', ''), # Install add-apt-repository.
44 (0, 'add-apt-repository', ''), # Add the repository.45 (0, 'add-apt-repository', ''), # Add the repository.
45 (0, 'update', ''), # Update the global repository46 (0, 'second update', ''), # Update the global repository.
46 )47 )
4748
48 def patch_codename(self, codename):49 def patch_codename(self, codename):
@@ -59,6 +60,7 @@
59 mock_get_ubuntu_codename.assert_called_once_with()60 mock_get_ubuntu_codename.assert_called_once_with()
60 self.assertEqual(len(self.side_effects), mock_call.call_count)61 self.assertEqual(len(self.side_effects), mock_call.call_count)
61 mock_call.assert_has_calls([62 mock_call.assert_has_calls([
63 mock.call('sudo', self.apt_get, 'update'),
62 mock.call('sudo', self.apt_get, 'install', '-y',64 mock.call('sudo', self.apt_get, 'install', '-y',
63 'python-software-properties'),65 'python-software-properties'),
64 mock.call('sudo', self.apt_add_repository, '-y', self.repository),66 mock.call('sudo', self.apt_add_repository, '-y', self.repository),
@@ -73,6 +75,7 @@
73 mock_get_ubuntu_codename.assert_called_once_with()75 mock_get_ubuntu_codename.assert_called_once_with()
74 self.assertEqual(len(self.side_effects), mock_call.call_count)76 self.assertEqual(len(self.side_effects), mock_call.call_count)
75 mock_call.assert_has_calls([77 mock_call.assert_has_calls([
78 mock.call('sudo', self.apt_get, 'update'),
76 mock.call('sudo', self.apt_get, 'install', '-y',79 mock.call('sudo', self.apt_get, 'install', '-y',
77 'software-properties-common'),80 'software-properties-common'),
78 mock.call('sudo', self.apt_add_repository, '-y', self.repository),81 mock.call('sudo', self.apt_add_repository, '-y', self.repository),
@@ -92,15 +95,19 @@
9295
93 def test_command_error(self, mock_print):96 def test_command_error(self, mock_print):
94 # An OSError is raised if a command error occurs.97 # An OSError is raised if a command error occurs.
95 side_effects = [(1, '', 'apt-get install error')]98 side_effects = [(0, 'update', ''), (1, '', 'apt-get install error')]
96 with self.patch_codename('quantal') as mock_get_ubuntu_codename:99 with self.patch_codename('quantal') as mock_get_ubuntu_codename:
97 with self.patch_multiple_calls(side_effects) as mock_call:100 with self.patch_multiple_calls(side_effects) as mock_call:
98 with self.assertRaises(OSError) as context_manager:101 with self.assertRaises(OSError) as context_manager:
99 utils.add_apt_repository(self.repository)102 utils.add_apt_repository(self.repository)
100 mock_get_ubuntu_codename.assert_called_once_with()103 mock_get_ubuntu_codename.assert_called_once_with()
101 mock_call.assert_called_once_with(104 self.assertEqual(len(side_effects), mock_call.call_count)
102 'sudo', self.apt_get, 'install', '-y',105 mock_call.assert_has_calls([
103 'software-properties-common')106 mock.call('sudo', self.apt_get, 'update'),
107 mock.call(
108 'sudo', self.apt_get, 'install', '-y',
109 'software-properties-common'),
110 ])
104 self.assertEqual(111 self.assertEqual(
105 'apt-get install error', bytes(context_manager.exception))112 'apt-get install error', bytes(context_manager.exception))
106113
107114
=== modified file 'quickstart/utils.py'
--- quickstart/utils.py 2015-03-10 10:18:58 +0000
+++ quickstart/utils.py 2015-03-10 13:22:58 +0000
@@ -48,6 +48,7 @@
48 if get_ubuntu_codename() == 'precise':48 if get_ubuntu_codename() == 'precise':
49 add_repository_package = 'python-software-properties'49 add_repository_package = 'python-software-properties'
50 commands = (50 commands = (
51 ('/usr/bin/apt-get', 'update'),
51 ('/usr/bin/apt-get', 'install', '-y', add_repository_package),52 ('/usr/bin/apt-get', 'install', '-y', add_repository_package),
52 ('/usr/bin/add-apt-repository', '-y', repository),53 ('/usr/bin/add-apt-repository', '-y', repository),
53 ('/usr/bin/apt-get', 'update'),54 ('/usr/bin/apt-get', 'update'),

Subscribers

People subscribed via source and target branches