Merge lp:~frankban/charms/precise/juju-gui/ftests-bootstrap-node into lp:~juju-gui/charms/precise/juju-gui/trunk

Proposed by Francesco Banconi
Status: Merged
Merged at revision: 142
Proposed branch: lp:~frankban/charms/precise/juju-gui/ftests-bootstrap-node
Merge into: lp:~juju-gui/charms/precise/juju-gui/trunk
Diff against target: 499 lines (+139/-108)
7 files modified
Makefile (+1/-1)
server/guiserver/tests/test_auth.py (+1/-1)
tests/20-functional.test (+90/-72)
tests/deploy.py (+19/-18)
tests/example.py (+2/-0)
tests/helpers.py (+9/-0)
tests/test_deploy.py (+17/-16)
To merge this branch: bzr merge lp:~frankban/charms/precise/juju-gui/ftests-bootstrap-node
Reviewer Review Type Date Requested Status
charmers Pending
Review via email: mp+196954@code.launchpad.net

Description of the change

Deploy the GUI to machine 0 in functional tests.

Also added guiserver info checks, and fixed the
deploy module so that the previous behavior of
"make deploy" is restored and the resulting
service name is not random generated.

Removed test_local_release: that scenario is
already tested in TestBuiltinServerLocalRelease.

Moved test_nrpe_check_available to
TestBuiltinServerLocalRelease.

Tests: assuming ec2 is the name of your ec2
environment, run the following:
`time make ftest JUJU_ENV="ec2"`
Tests should pass and take ~25-30 minutes.

https://codereview.appspot.com/34130043/

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

Reviewers: mp+196954_code.launchpad.net,

Message:
Please take a look.

Description:
Deploy the GUI to machine 0 in functional tests.

Also added guiserver info checks, and fixed the
deploy module so that the previous behavior of
"make deploy" is restored and the resulting
service name is not random generated.

Removed test_local_release: that scenario is
already tested in TestBuiltinServerLocalRelease.

Moved test_nrpe_check_available to
TestBuiltinServerLocalRelease.

Tests: assuming ec2 is the name of your ec2
environment, run the following:
`time make ftest JUJU_ENV="ec2"`
Tests should pass and take ~25-30 minutes.

https://code.launchpad.net/~frankban/charms/precise/juju-gui/ftests-bootstrap-node/+merge/196954

(do not edit description out of merge proposal)

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

Affected files (+141, -108 lines):
   M Makefile
   A [revision details]
   M revision
   M tests/20-functional.test
   M tests/deploy.py
   M tests/example.py
   M tests/helpers.py
   M tests/test_deploy.py

Revision history for this message
Gary Poster (gary) wrote :

LGTM with trivial. Thank you!

https://codereview.appspot.com/34130043/diff/1/tests/20-functional.test
File tests/20-functional.test (right):

https://codereview.appspot.com/34130043/diff/1/tests/20-functional.test#newcode58
tests/20-functional.test:58: Deploy the charm in the bootstrap node if
possible in the current Juju
Suggest slight tweak for readability:

Deploy the charm, using the bootstrap node if the current Juju
implementation supports it.

https://codereview.appspot.com/34130043/

Revision history for this message
Madison Scott-Clary (makyo) wrote :

Code LGTMly, was not able to QA due to unrelated failures; can someone
else QA please?

https://codereview.appspot.com/34130043/

Revision history for this message
Gary Poster (gary) wrote :

Francesco, under the circumstances, I suggest that you either run the
test on another computer or in another virtual machine or something,
and then land it; or just land it. :-)

> On Nov 27, 2013, at 10:24 PM, Matthew Scott <email address hidden> wrote:
>
> Code LGTMly, was not able to QA due to unrelated failures; can someone
> else QA please?
>
> https://codereview.appspot.com/34130043/
>
> --
> https://code.launchpad.net/~frankban/charms/precise/juju-gui/ftests-bootstrap-node/+merge/196954
> Your team Juju GUI Hackers is subscribed to branch lp:~juju-gui/charms/precise/juju-gui/trunk.

Revision history for this message
Jeff Pihach (hatch) wrote :
142. By Francesco Banconi

Merged trunk.

143. By Francesco Banconi

Checkpoint.

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

*** Submitted:

Deploy the GUI to machine 0 in functional tests.

Also added guiserver info checks, and fixed the
deploy module so that the previous behavior of
"make deploy" is restored and the resulting
service name is not random generated.

Removed test_local_release: that scenario is
already tested in TestBuiltinServerLocalRelease.

Moved test_nrpe_check_available to
TestBuiltinServerLocalRelease.

Tests: assuming ec2 is the name of your ec2
environment, run the following:
`time make ftest JUJU_ENV="ec2"`
Tests should pass and take ~25-30 minutes.

R=gary.poster, matthew.scott, jeff.pihach
CC=
https://codereview.appspot.com/34130043

https://codereview.appspot.com/34130043/

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

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'Makefile'
2--- Makefile 2013-11-22 16:01:36 +0000
3+++ Makefile 2013-11-28 16:43:14 +0000
4@@ -14,7 +14,7 @@
5 # You should have received a copy of the GNU Affero General Public License
6 # along with this program. If not, see <http://www.gnu.org/licenses/>.
7
8-JUJUTEST = juju-test --timeout=120m -v -e "$(JUJU_ENV)"
9+JUJUTEST = yes | juju-test --timeout=40m -v -e "$(JUJU_ENV)"
10 VENV = tests/.venv
11 SYSDEPS = build-essential bzr libapt-pkg-dev libpython-dev python-virtualenv \
12 rsync xvfb
13
14=== modified file 'server/guiserver/tests/test_auth.py'
15--- server/guiserver/tests/test_auth.py 2013-11-25 14:02:15 +0000
16+++ server/guiserver/tests/test_auth.py 2013-11-28 16:43:14 +0000
17@@ -317,7 +317,7 @@
18 self.assertFalse(is_login, request)
19
20
21-class TestAuthenticationTokenHandler(unittest.TestCase):
22+class TestAuthenticationTokenHandler(LogTrapTestCase, unittest.TestCase):
23
24 def setUp(self):
25 super(TestAuthenticationTokenHandler, self).setUp()
26
27=== modified file 'tests/20-functional.test'
28--- tests/20-functional.test 2013-11-26 19:43:20 +0000
29+++ tests/20-functional.test 2013-11-28 16:43:14 +0000
30@@ -18,8 +18,10 @@
31
32 from __future__ import print_function
33 import httplib
34+import json
35 import itertools
36 import unittest
37+import urllib2
38 import urlparse
39
40 from selenium.webdriver import Firefox
41@@ -34,6 +36,7 @@
42 get_admin_secret,
43 juju_destroy_service,
44 juju_version,
45+ make_service_name,
46 stop_services,
47 WebSocketClient,
48 )
49@@ -49,9 +52,48 @@
50 print(err)
51
52
53+def juju_deploy_gui(options=None):
54+ """Deploy the Juju GUI charm with the given options.
55+
56+ Deploy the charm in the bootstrap node if possible in the current Juju
57+ implementation. Use a random service name.
58+
59+ Return a tuple containing the deployed service name, unit info and a list
60+ of services that are started in the Juju GUI unit and that must be
61+ manually stopped by tests. In juju-core, the services list is always empty.
62+ """
63+ force_machine = None if is_legacy_juju else 0
64+ service_name = make_service_name(prefix='juju-gui-')
65+ unit_info = juju_deploy(
66+ 'juju-gui', service_name=service_name, options=options,
67+ force_machine=force_machine)
68+ # XXX 2012-11-29 frankban bug=872264:
69+ # Just invoking ``juju destroy-service juju-gui`` in tearDown
70+ # should execute the ``stop`` hook, stopping all the services
71+ # started by the charm in the machine. Right now this does not
72+ # work in pyJuju, so the desired effect is achieved by keeping
73+ # track of started services and manually stopping them here.
74+ # Once pyJuju works correctly or we drop support for it altogether, we
75+ # can remove this shim.
76+ cleanup_services = []
77+ if is_legacy_juju:
78+ if options is None:
79+ options = {}
80+ # Either stop the builtin server or the old apache2/haproxy setup.
81+ if options.get('builtin-server') == 'true':
82+ cleanup_services.append('guiserver')
83+ else:
84+ cleanup_services.extend(['haproxy', 'apache2'])
85+ # Staging uses improv, otherwise the API agent is used.
86+ if options.get('staging') == 'true':
87+ cleanup_services.append('juju-api-improv')
88+ else:
89+ cleanup_services.append('juju-api-agent')
90+ return service_name, unit_info, cleanup_services
91+
92+
93 class DeployTestMixin(object):
94
95- charm = 'juju-gui'
96 port = '443'
97
98 def setUp(self):
99@@ -135,53 +177,35 @@
100 services = self.wait_for(services_found, 'Services not displayed.')
101 return set([element.text for element in services])
102
103- def juju_deploy(self, *args, **kwargs):
104+ def deploy_gui(self, options=None):
105 """Shim in our additional cleanup for pyJuju."""
106- # XXX 2012-11-29 frankban bug=872264:
107- # Just invoking ``juju destroy-service juju-gui`` in tearDown
108- # should execute the ``stop`` hook, stopping all the services
109- # started by the charm in the machine. Right now this does not
110- # work in pyJuju, so the desired effect is achieved by keeping
111- # track of started services and manually stopping them here.
112 # Once pyJuju works correctly or we drop support for it altogether, we
113 # can remove this shim.
114- unit_info, self.service_name = juju_deploy(*args, **kwargs)
115+ self.service_name, unit_info, cleanup_services = juju_deploy_gui(
116+ options=options)
117+ # XXX 2013-11-27 frankban bug=872264:
118+ # See juju_deploy_gui above.
119 if is_legacy_juju:
120 hostname = unit_info['public-address']
121- options = kwargs.get('options', {})
122- # Either stop the builtin server or the old apache2/haproxy setup.
123- if options.get('builtin-server') == 'true':
124- services = ['guiserver']
125- else:
126- services = ['haproxy', 'apache2']
127- # Staging uses improv, otherwise the API agent is used.
128- if options.get('staging') == 'true':
129- services.append('juju-api-improv')
130- else:
131- services.append('juju-api-agent')
132- self.addCleanup(stop_services, hostname, services)
133+ self.addCleanup(stop_services, hostname, cleanup_services)
134 return unit_info
135
136-
137-class TestDeploy(DeployTestMixin, unittest.TestCase):
138+ def get_builtin_server_info(self, hostname):
139+ """Return a dictionary of info as exposed by the builtin server."""
140+ url = 'https://{}/gui-server-info'.format(hostname)
141+ response = urllib2.urlopen(url)
142+ self.assertEqual(200, response.code)
143+ return json.load(response)
144+
145+
146+class TestDeployOptions(DeployTestMixin, unittest.TestCase):
147
148 def tearDown(self):
149 juju_destroy_service(self.service_name)
150
151- def test_local_release(self):
152- # Ensure the Juju GUI and API agent services are correctly set up when
153- # deploying the local release.
154- unit_info = self.juju_deploy(self.charm)
155- hostname = unit_info['public-address']
156- self.navigate_to(hostname)
157- self.handle_browser_warning()
158- self.assertEnvironmentIsConnected()
159-
160 def test_stable_release(self):
161- # Ensure the Juju GUI and API agent services are correctly set up when
162- # deploying the stable release.
163- options = {'juju-gui-source': 'stable'}
164- unit_info = self.juju_deploy(self.charm, options=options)
165+ # Ensure the stable Juju GUI release is correctly set up.
166+ unit_info = self.deploy_gui(options={'juju-gui-source': 'stable'})
167 hostname = unit_info['public-address']
168 self.navigate_to(hostname)
169 self.handle_browser_warning()
170@@ -189,8 +213,8 @@
171
172 @unittest.skipUnless(is_legacy_juju, 'staging only works in pyJuju')
173 def test_staging(self):
174- # Ensure the Juju GUI and improv services are correctly set up.
175- unit_info = self.juju_deploy(self.charm, options={'staging': 'true'})
176+ # Ensure the Juju GUI and staging services are correctly set up.
177+ unit_info = self.deploy_gui(options={'staging': 'true'})
178 hostname = unit_info['public-address']
179 self.navigate_to(hostname)
180 self.handle_browser_warning()
181@@ -200,16 +224,19 @@
182
183 def test_sandbox(self):
184 # The GUI is correctly deployed and set up in sandbox mode.
185- unit_info = self.juju_deploy(self.charm, options={'sandbox': 'true'})
186+ unit_info = self.deploy_gui(options={'sandbox': 'true'})
187 hostname = unit_info['public-address']
188 self.navigate_to(hostname)
189 self.handle_browser_warning()
190 self.assertEnvironmentIsConnected()
191+ # Ensure the builtin server is set up to run in sandbox mode.
192+ server_info = self.get_builtin_server_info(hostname)
193+ self.assertTrue(server_info['sandbox'])
194
195 def test_branch_source(self):
196 # Ensure the Juju GUI is correctly deployed from a Bazaar branch.
197 options = {'juju-gui-source': JUJU_GUI_TEST_BRANCH}
198- unit_info = self.juju_deploy(self.charm, options=options)
199+ unit_info = self.deploy_gui(options=options)
200 hostname = unit_info['public-address']
201 self.navigate_to(hostname)
202 self.handle_browser_warning()
203@@ -218,12 +245,11 @@
204 def test_legacy_server(self):
205 # The legacy apache + haproxy server configuration works correctly.
206 # Also make sure the correct cache headers are sent.
207- options = {
208- 'builtin-server': False,
209- 'juju-gui-source': JUJU_GUI_TEST_BRANCH,
210- }
211- unit_info = self.juju_deploy(self.charm, options=options)
212+ unit_info = self.deploy_gui(options={'builtin-server': 'false'})
213 hostname = unit_info['public-address']
214+ self.navigate_to(hostname)
215+ self.handle_browser_warning()
216+ self.assertEnvironmentIsConnected()
217 conn = httplib.HTTPSConnection(hostname)
218 conn.request('HEAD', '/')
219 headers = conn.getresponse().getheaders()
220@@ -236,34 +262,14 @@
221 self.assertIn('public', cache_directives)
222 self.assertIn('must-revalidate', cache_directives)
223
224- @unittest.skipIf(is_legacy_juju, 'force-machine only works in juju-core')
225- def test_force_machine(self):
226- # Ensure the Juju GUI is correctly set up in the Juju bootstrap node.
227- unit_info = self.juju_deploy(self.charm, force_machine=0)
228- self.assertEqual('0', unit_info['machine'])
229- self.navigate_to(unit_info['public-address'])
230- self.handle_browser_warning()
231- self.assertEnvironmentIsConnected()
232-
233- def test_nrpe_check_available(self):
234- # Make sure the check-app-access.sh script's ADDRESS is available.
235- options = {'juju-gui-source': JUJU_GUI_TEST_BRANCH}
236- unit_info = self.juju_deploy(self.charm, options=options)
237- hostname = unit_info['public-address']
238- conn = httplib.HTTPSConnection(hostname)
239- # This request matches the ADDRESS var in the script.
240- conn.request('GET', '/juju-ui/version.js')
241- message = 'ADDRESS in check-app-access.sh is not accessible.'
242- self.assertEqual(200, conn.getresponse().status, message)
243-
244-
245-class TestBuiltinServer(DeployTestMixin, unittest.TestCase):
246+
247+class TestBuiltinServerLocalRelease(DeployTestMixin, unittest.TestCase):
248
249 @classmethod
250 def setUpClass(cls):
251 # Deploy the charm. The resulting service is used by all the tests
252 # in this test case.
253- unit_info, cls.service_name = juju_deploy(cls.charm)
254+ cls.service_name, unit_info, cls.cleanup_services = juju_deploy_gui()
255 cls.hostname = unit_info['public-address']
256 # The counter is used to produce API request identifiers.
257 cls.counter = itertools.count()
258@@ -273,10 +279,10 @@
259 # Destroy the GUI service, and perform additional clean up in the case
260 # we are in a pyJuju environment.
261 juju_destroy_service(cls.service_name)
262+ # XXX 2013-11-27 frankban bug=872264:
263+ # See juju_deploy_gui above.
264 if is_legacy_juju:
265- # XXX 2012-11-29 frankban bug=872264:
266- # see DeployTestMixin.juju_deploy above.
267- stop_services(cls.hostname, ['guiserver', 'juju-api-agent'])
268+ stop_services(cls.hostname, cls.cleanup_services)
269
270 def make_websocket_client(self, authenticated=True):
271 """Create and return a WebSocket client connected to the Juju backend.
272@@ -297,10 +303,14 @@
273 return client
274
275 def test_environment_connection(self):
276- # Ensure the Juju GUI and builtin server are correctly set up.
277+ # Ensure the Juju GUI and builtin server are correctly set up using
278+ # the local release.
279 self.navigate_to(self.hostname)
280 self.handle_browser_warning()
281 self.assertEnvironmentIsConnected()
282+ # Ensure the builtin server is set up to be connected to the real env.
283+ server_info = self.get_builtin_server_info(self.hostname)
284+ self.assertFalse(server_info['sandbox'])
285
286 def test_headers(self):
287 # Ensure the Tornado headers are correctly sent.
288@@ -479,6 +489,14 @@
289 statuses = [change['Status'] for change in changes]
290 self.assertEqual(['completed', 'completed'], statuses)
291
292+ def test_nrpe_check_available(self):
293+ # Make sure the check-app-access.sh script's ADDRESS is available.
294+ conn = httplib.HTTPSConnection(self.hostname)
295+ # This request matches the ADDRESS var in the script.
296+ conn.request('GET', '/juju-ui/version.js')
297+ message = 'ADDRESS in check-app-access.sh is not accessible.'
298+ self.assertEqual(200, conn.getresponse().status, message)
299+
300
301 if __name__ == '__main__':
302 unittest.main(verbosity=2)
303
304=== modified file 'tests/deploy.py'
305--- tests/deploy.py 2013-11-26 20:42:52 +0000
306+++ tests/deploy.py 2013-11-28 16:43:14 +0000
307@@ -20,9 +20,8 @@
308
309
310 import json
311+import logging
312 import os
313-import random
314-import string
315 import tempfile
316
317 from charmhelpers import make_charm_config_file
318@@ -53,44 +52,46 @@
319 return repo
320
321
322-SERVICE_NAME_PREFIX = 'service-'
323-
324-
325-def make_service_name():
326- """Generate a long, random service name."""
327- characters = string.ascii_lowercase
328- suffix = ''.join([random.choice(characters) for x in xrange(20)])
329- return SERVICE_NAME_PREFIX + suffix
330-
331-
332 def juju_deploy(
333- charm, options=None, force_machine=None, charm_source=None,
334- series='precise'):
335+ charm_name, service_name=None, options=None, force_machine=None,
336+ charm_source=None, series='precise'):
337 """Deploy and expose the charm. Return the first unit's public address.
338
339 Also wait until the service is exposed and the first unit started.
340+
341+ If service_name is None, use the name of the charm.
342 If options are provided, they will be used when deploying the charm.
343 If force_machine is not None, create the unit in the specified machine.
344 If charm_source is None, dynamically retrieve the charm source directory.
345 """
346+ # Note: this function is used by both the functional tests and
347+ # "make deploy": see the "if main" section below.
348 if charm_source is None:
349 # Dynamically retrieve the charm source based on the path of this file.
350 charm_source = os.path.join(os.path.dirname(__file__), '..')
351- repo = setup_repository(charm, charm_source, series=series)
352+ logging.debug('setting up the charms repository')
353+ repo = setup_repository(charm_name, charm_source, series=series)
354 args = ['deploy', '--repository', repo]
355- service_name = make_service_name()
356+ if service_name is None:
357+ service_name = charm_name
358 if options is not None:
359 config_file = make_charm_config_file({service_name: options})
360 args.extend(['--config', config_file.name])
361 if force_machine is not None:
362 args.extend(['--to', str(force_machine)])
363- args.append('local:{}/{}'.format(series, charm))
364+ charm_url = 'local:{}/{}'.format(series, charm_name)
365+ args.append(charm_url)
366 args.append(service_name)
367+ logging.debug('deploying {} from the repository in {}'.format(
368+ charm_url, repo))
369 juju(*args)
370+ logging.debug('exposing {}'.format(service_name))
371 juju('expose', service_name)
372- return wait_for_unit(service_name), service_name
373+ logging.debug('waiting for the unit to be ready')
374+ return wait_for_unit(service_name)
375
376
377 if __name__ == '__main__':
378+ logging.getLogger().setLevel(logging.DEBUG)
379 unit = juju_deploy('juju-gui')
380 print(json.dumps(unit, indent=2))
381
382=== modified file 'tests/example.py'
383--- tests/example.py 2013-11-12 14:51:48 +0000
384+++ tests/example.py 2013-11-28 16:43:14 +0000
385@@ -24,6 +24,7 @@
386 wordpress:
387 charm: "cs:precise/wordpress-15"
388 num_units: 1
389+ to: '0'
390 options:
391 debug: "no"
392 engine: nginx
393@@ -67,6 +68,7 @@
394 mediawiki:
395 charm: "cs:precise/mediawiki-9"
396 num_units: 1
397+ to: '0'
398 options:
399 admins: ""
400 debug: false
401
402=== modified file 'tests/helpers.py'
403--- tests/helpers.py 2013-11-26 17:36:49 +0000
404+++ tests/helpers.py 2013-11-28 16:43:14 +0000
405@@ -20,7 +20,9 @@
406 from functools import wraps
407 import json
408 import os
409+import random
410 import re
411+import string
412 import subprocess
413 import time
414
415@@ -200,6 +202,13 @@
416 return Version._make(map(to_int, match.groups()))
417
418
419+def make_service_name(prefix='service-'):
420+ """Generate a long, random service name."""
421+ characters = string.ascii_lowercase
422+ suffix = ''.join([random.choice(characters) for _ in range(20)])
423+ return prefix + suffix
424+
425+
426 def stop_services(hostname, services):
427 """Stop the given upstart services running on hostname."""
428 target = 'ubuntu@{}'.format(hostname)
429
430=== modified file 'tests/test_deploy.py'
431--- tests/test_deploy.py 2013-11-26 20:42:52 +0000
432+++ tests/test_deploy.py 2013-11-28 16:43:14 +0000
433@@ -26,9 +26,7 @@
434 import deploy
435 from deploy import (
436 juju_deploy,
437- make_service_name,
438 setup_repository,
439- SERVICE_NAME_PREFIX,
440 )
441
442
443@@ -128,17 +126,18 @@
444 @mock.patch('deploy.wait_for_unit')
445 def call_deploy(
446 self, mock_wait_for_unit, mock_juju,
447- options=None, force_machine=None, charm_source=None,
448- series='precise'):
449+ service_name=None, options=None, force_machine=None,
450+ charm_source=None, series='precise'):
451 mock_wait_for_unit.return_value = self.unit_info
452 if charm_source is None:
453 expected_source = os.path.join(os.path.dirname(__file__), '..')
454 else:
455 expected_source = charm_source
456 deploy.setup_repository.reset_mock()
457- unit_info, service_name = juju_deploy(
458- self.charm, options=options, force_machine=force_machine,
459- charm_source=charm_source, series=series)
460+ unit_info = juju_deploy(
461+ self.charm, service_name=service_name, options=options,
462+ force_machine=force_machine, charm_source=charm_source,
463+ series=series)
464 deploy.setup_repository.assert_called_once_with(
465 self.charm, expected_source, series=series)
466 # The unit address is correctly returned.
467@@ -148,7 +147,7 @@
468 juju_calls = mock_juju.call_args_list
469 self.assertEqual(2, len(juju_calls))
470 # We expect a "juju expose" to have been called on the service.
471- expected_expose_call = mock.call('expose', service_name)
472+ expected_expose_call = mock.call('expose', service_name or self.charm)
473 deploy_call, expose_call = juju_calls
474 self.assertEqual(expected_expose_call, expose_call)
475 self.assertEqual(deploy_call[0][0], 'deploy')
476@@ -196,13 +195,15 @@
477 command = self.call_deploy(series='raring')
478 self.assertIn(charm_url, command)
479
480+ def test_no_service_name(self):
481+ # If the service name is not provided, the charm name is used.
482+ command = self.call_deploy()
483+ service_name = command[-1]
484+ self.assertEqual(self.charm, service_name)
485+
486 def test_service_name(self):
487- # A random service name is generated for each service started. That
488- # service name is provided to juju as the last argument.
489- command = self.call_deploy(series='raring')
490- # We'll take it as proof that the last argument is a random service
491- # name if it starts with the service name prefix and is the same
492- # length as another random service name.
493+ # A customized service name can be provided and it is passed to Juju as
494+ # the last argument.
495+ command = self.call_deploy(service_name='my-service')
496 service_name = command[-1]
497- self.assertTrue(service_name.startswith(SERVICE_NAME_PREFIX))
498- self.assertEqual(len(service_name), len(make_service_name()))
499+ self.assertEqual('my-service', service_name)

Subscribers

People subscribed via source and target branches