Merge lp:~rharding/charms/precise/juju-gui/remove-pyjuju into lp:~juju-gui/charms/precise/juju-gui/trunk

Proposed by Richard Harding
Status: Merged
Merged at revision: 148
Proposed branch: lp:~rharding/charms/precise/juju-gui/remove-pyjuju
Merge into: lp:~juju-gui/charms/precise/juju-gui/trunk
Diff against target: 1620 lines (+105/-777)
13 files modified
Dependencies.md (+1/-2)
README.md (+4/-26)
config.yaml (+4/-30)
config/haproxy.cfg.template (+3/-7)
config/juju-api-agent.conf.template (+0/-18)
config/juju-api-improv.conf.template (+0/-12)
hooks/backend.py (+3/-42)
hooks/utils.py (+16/-122)
tests/20-functional.test (+19/-73)
tests/helpers.py (+0/-31)
tests/test_backends.py (+41/-227)
tests/test_helpers.py (+0/-71)
tests/test_utils.py (+14/-116)
To merge this branch: bzr merge lp:~rharding/charms/precise/juju-gui/remove-pyjuju
Reviewer Review Type Date Requested Status
charmers Pending
Review via email: mp+201510@code.launchpad.net

Description of the change

Remove support for PyJuju and rapi from charm.

- Removes the support for running rapi/pyjuju.
- Removes the agent used to communicate with zookeeper.
- Removes anything pertaining to zookeeper.
- Attempts to clean up docs and such to make sense with pure juju-core.

Note:

- The functional test run was taking 62min to complete for me. The timeout is
bumped to 80min to help allow it to complete. This was against ec2.

https://codereview.appspot.com/52440043/

To post a comment you must log in.
Revision history for this message
Richard Harding (rharding) wrote :

Reviewers: mp+201510_code.launchpad.net,

Message:
Please take a look.

Description:
Remove support for PyJuju and rapi from charm.

WIP - couple of question points and failing functional legacy test.

https://code.launchpad.net/~rharding/charms/precise/juju-gui/remove-pyjuju/+merge/201510

(do not edit description out of merge proposal)

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

Affected files (+90, -499 lines):
   M Dependencies.md
   M README.md
   A [revision details]
   M config.yaml
   M config/haproxy.cfg.template
   D config/juju-api-improv.conf.template
   M hooks/backend.py
   M hooks/utils.py
   M tests/20-functional.test
   M tests/test_backends.py
   M tests/test_utils.py

150. By Richard Harding

Remove agent and zookeeper related functions

151. By Richard Harding

Fix lint

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

Reviewers: mp+201510_code.launchpad.net,

Message:
Please take a look.

Description:
Remove support for PyJuju and rapi from charm.

WIP - couple of question points and failing functional legacy test.

https://code.launchpad.net/~rharding/charms/precise/juju-gui/remove-pyjuju/+merge/201510

(do not edit description out of merge proposal)

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

Affected files (+92, -695 lines):
   M Dependencies.md
   M Makefile
   M README.md
   A [revision details]
   M config.yaml
   M config/haproxy.cfg.template
   D config/juju-api-agent.conf.template
   D config/juju-api-improv.conf.template
   M hooks/backend.py
   M hooks/utils.py
   M tests/20-functional.test
   M tests/test_backends.py
   M tests/test_utils.py

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

Reviewers: mp+201510_code.launchpad.net,

Message:
Please take a look.

Description:
Remove support for PyJuju and rapi from charm.

- Removes the support for running rapi/pyjuju.
- Removes the agent used to communicate with zookeeper.
- Removes anything pertaining to zookeeper.
- Attempts to clean up docs and such to make sense with pure juju-core.

Note:

- The functional test run was taking 62min to complete for me. The
timeout is
bumped to 80min to help allow it to complete. This was against ec2.

https://code.launchpad.net/~rharding/charms/precise/juju-gui/remove-pyjuju/+merge/201510

(do not edit description out of merge proposal)

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

Affected files (+92, -695 lines):
   M Dependencies.md
   M Makefile
   M README.md
   A [revision details]
   M config.yaml
   M config/haproxy.cfg.template
   D config/juju-api-agent.conf.template
   D config/juju-api-improv.conf.template
   M hooks/backend.py
   M hooks/utils.py
   M tests/20-functional.test
   M tests/test_backends.py
   M tests/test_utils.py

Revision history for this message
Francesco Banconi (frankban) wrote :
Download full text (4.0 KiB)

Thanks a lot for getting rid of all this pyJuju stuff Rick!
This branch is nice: please take a look at my comments below.
LGTM with changes.

https://codereview.appspot.com/51470044/diff/1/README.md
File README.md (right):

https://codereview.appspot.com/51470044/diff/1/README.md#newcode76
README.md:76: core) or "admin" (for pyjuju). The password is the same as
your Juju
We can remove the pyjuju reference here.

https://codereview.appspot.com/51470044/diff/1/README.md#newcode105
README.md:105: For both Juju Core and PyJuju, you must simply do the
following steps. Note
And here too...

https://codereview.appspot.com/51470044/diff/1/README.md#newcode162
README.md:162: #### pyjuju ####
We can get rid of this paragraph and of all the juju-jitsu stuff \o/

https://codereview.appspot.com/51470044/diff/1/config/haproxy.cfg.template
File config/haproxy.cfg.template (right):

https://codereview.appspot.com/51470044/diff/1/config/haproxy.cfg.template#newcode25
config/haproxy.cfg.template:25: # Replace "/ws/" with "/" in any request
path.
Nice.

https://codereview.appspot.com/51470044/diff/1/hooks/backend.py
File hooks/backend.py (left):

https://codereview.appspot.com/51470044/diff/1/hooks/backend.py#oldcode262
hooks/backend.py:262: raise ValueError('Unable to use staging with go
backend')
I am very happy we removed this ValueError for incompatible options.

https://codereview.appspot.com/51470044/diff/1/hooks/utils.py
File hooks/utils.py (right):

https://codereview.appspot.com/51470044/diff/1/hooks/utils.py#newcode87
hooks/utils.py:87: Serializer, su,
Please keep "su" in its own line.

https://codereview.appspot.com/51470044/diff/1/hooks/utils.py#newcode148
hooks/utils.py:148: return api_addresses.split()[0]
So you decided to stop supporting also old releases of juju-core.
I am not sure about this: at least we should document it more
explicitly.

https://codereview.appspot.com/51470044/diff/1/hooks/utils.py#newcode320
hooks/utils.py:320: password = password if password else None
Maybe rewrite those three lines like the following?
if not password:
     password = 'admin' if sandbox else None

https://codereview.appspot.com/51470044/diff/1/hooks/utils.py#newcode362
hooks/utils.py:362: # In PyJuju environments, use the same certificate
for both HTTPS and
Please remove this reference to PyJuju.

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

https://codereview.appspot.com/51470044/diff/1/tests/20-functional.test#newcode45
tests/20-functional.test:45: STAGING_SERVICES = ('haproxy', 'mediawiki',
'memcached', 'mysql', 'wordpress')
STAGING_SERVICES seems to be no longer required.

https://codereview.appspot.com/51470044/diff/1/tests/20-functional.test#newcode46
tests/20-functional.test:46: juju_version().major == 0
Can't we remove this line?
Moreover, can't we remove the juju_version function entirely?

https://codereview.appspot.com/51470044/diff/1/tests/20-functional.test#newcode69
tests/20-functional.test:69: # XXX 2012-11-29 frankban bug=872264:
This XXX comment is no longer required. We can remove all the
cleanup_services machinery.

https://codereview.appspot.com/51470044/diff/1/tests/2...

Read more...

152. By Richard Harding

Updated per review

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

Reviewers: mp+201510_code.launchpad.net,

Message:
Please take a look.

Description:
Remove support for PyJuju and rapi from charm.

- Removes the support for running rapi/pyjuju.
- Removes the agent used to communicate with zookeeper.
- Removes anything pertaining to zookeeper.
- Attempts to clean up docs and such to make sense with pure juju-core.

Note:

- The functional test run was taking 62min to complete for me. The
timeout is
bumped to 80min to help allow it to complete. This was against ec2.

https://code.launchpad.net/~rharding/charms/precise/juju-gui/remove-pyjuju/+merge/201510

(do not edit description out of merge proposal)

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

Affected files (+107, -847 lines):
   M Dependencies.md
   M Makefile
   M README.md
   A [revision details]
   M config.yaml
   M config/haproxy.cfg.template
   D config/juju-api-agent.conf.template
   D config/juju-api-improv.conf.template
   M hooks/backend.py
   M hooks/utils.py
   M tests/20-functional.test
   M tests/helpers.py
   M tests/test_backends.py
   M tests/test_helpers.py
   M tests/test_utils.py

Revision history for this message
Richard Harding (rharding) wrote :
Download full text (4.4 KiB)

I'm fighing lbox. When I updated this it put it over at a new url.

https://codereview.appspot.com/52440043

https://codereview.appspot.com/51470044/diff/1/README.md
File README.md (right):

https://codereview.appspot.com/51470044/diff/1/README.md#newcode76
README.md:76: core) or "admin" (for pyjuju). The password is the same as
your Juju
On 2014/01/14 17:26:36, frankban wrote:
> We can remove the pyjuju reference here.

Thanks, removed.

https://codereview.appspot.com/51470044/diff/1/README.md#newcode105
README.md:105: For both Juju Core and PyJuju, you must simply do the
following steps. Note
On 2014/01/14 17:26:36, frankban wrote:
> And here too...

Removed

https://codereview.appspot.com/51470044/diff/1/README.md#newcode162
README.md:162: #### pyjuju ####
On 2014/01/14 17:26:36, frankban wrote:
> We can get rid of this paragraph and of all the juju-jitsu stuff \o/

Removed

https://codereview.appspot.com/51470044/diff/1/hooks/utils.py
File hooks/utils.py (right):

https://codereview.appspot.com/51470044/diff/1/hooks/utils.py#newcode87
hooks/utils.py:87: Serializer, su,
On 2014/01/14 17:26:36, frankban wrote:
> Please keep "su" in its own line.

Mistake, thanks for the catch.

https://codereview.appspot.com/51470044/diff/1/hooks/utils.py#newcode148
hooks/utils.py:148: return api_addresses.split()[0]
On 2014/01/14 17:26:36, frankban wrote:
> So you decided to stop supporting also old releases of juju-core.
> I am not sure about this: at least we should document it more
explicitly.

Can you talk about this more? My understanding is that we got rid of the
agent bit and that was the conf file we've removed as part of that. Is
the machiner agent file something different?

https://codereview.appspot.com/51470044/diff/1/hooks/utils.py#newcode320
hooks/utils.py:320: password = password if password else None
On 2014/01/14 17:26:36, frankban wrote:
> Maybe rewrite those three lines like the following?
> if not password:
> password = 'admin' if sandbox else None

Tweaked.

https://codereview.appspot.com/51470044/diff/1/hooks/utils.py#newcode362
hooks/utils.py:362: # In PyJuju environments, use the same certificate
for both HTTPS and
On 2014/01/14 17:26:36, frankban wrote:
> Please remove this reference to PyJuju.

Removed

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

https://codereview.appspot.com/51470044/diff/1/tests/20-functional.test#newcode45
tests/20-functional.test:45: STAGING_SERVICES = ('haproxy', 'mediawiki',
'memcached', 'mysql', 'wordpress')
On 2014/01/14 17:26:36, frankban wrote:
> STAGING_SERVICES seems to be no longer required.

Wow, how did lint not catch that? Thanks.

https://codereview.appspot.com/51470044/diff/1/tests/20-functional.test#newcode46
tests/20-functional.test:46: juju_version().major == 0
On 2014/01/14 17:26:36, frankban wrote:
> Can't we remove this line?
> Moreover, can't we remove the juju_version function entirely?

Oh hmm, I didn't notice it was only used for pyjuju vs juju-core
distinction. Removing.

https://codereview.appspot.com/51470044/diff/1/tests/20-functional.test#newcode78
tests/20-functional.test:78: if options is None:
On 2014/0...

Read more...

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

https://codereview.appspot.com/51470044/diff/1/hooks/utils.py
File hooks/utils.py (right):

https://codereview.appspot.com/51470044/diff/1/hooks/utils.py#newcode148
hooks/utils.py:148: return api_addresses.split()[0]
On 2014/01/15 00:03:16, rharding wrote:
> On 2014/01/14 17:26:36, frankban wrote:
> > So you decided to stop supporting also old releases of juju-core.
> > I am not sure about this: at least we should document it more
explicitly.

> Can you talk about this more? My understanding is that we got rid of
the agent
> bit and that was the conf file we've removed as part of that. Is the
machiner
> agent file something different?

Those are two different concepts:
- the pyJuju API agent is the one that was started in the GUI node by
running the rapi-delta branch. The GUI used it as WebSocket server, and
the agent itself was connected to the bootstrap node Zookeper instance.
Your branch get rid of this machinery, and that's ok;
- the machiner agent file is a YAML created by juju-core which includes
the information required by the machiner worker. The API addresses are
part of that information. It must be considered an internal juju-core
detail, and for this reason we introduced the JUJU_API_ADDRESSES env
var, included in the hooks' execution context. But old versions of
juju-core don't support this, so the function strategy was:
   - try to use the environment variable;
   - if it is not present, parse the machiner agent file.
I am comfortable with that strategy, and I'd be inclined to preserve
that behavior. Anyway, as I mentioned, I can be ok in dropping support
for old juju-core releases if we clearly document it.

https://codereview.appspot.com/51470044/

153. By Richard Harding

Put back agent ip address sniffing

154. By Richard Harding

Fix the force_machine time

155. By Richard Harding

Update force machine and set timeout back to 40m.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'Dependencies.md'
--- Dependencies.md 2013-07-16 15:30:33 +0000
+++ Dependencies.md 2014-01-15 14:49:45 +0000
@@ -14,8 +14,7 @@
14a single PPA that the Juju GUI charm developers maintain.14a single PPA that the Juju GUI charm developers maintain.
1515
16The packages in our devel PPA provide a superset of all software the charm may16The packages in our devel PPA provide a superset of all software the charm may
17need for different deployment strategies, such as using the sandbox17need for different deployment strategies, such as using the sandbox or Go Juju.
18vs. improv, or Python Juju vs. Go Juju.
1918
20# Stable and Devel #19# Stable and Devel #
2120
2221
=== modified file 'README.md'
--- README.md 2013-10-08 15:30:04 +0000
+++ README.md 2014-01-15 14:49:45 +0000
@@ -72,9 +72,9 @@
72By default, the deployment uses self-signed certificates. The browser will ask72By default, the deployment uses self-signed certificates. The browser will ask
73you to accept a security exception once.73you to accept a security exception once.
7474
75You will see a login form with the username fixed to "user-admin" (for juju-75You will see a login form with the username fixed to "user-admin". The
76core) or "admin" (for pyjuju). The password is the same as your Juju76password is the same as your Juju environment's `admin-secret`, found in
77environment's `admin-secret`, found in `~/.juju/environments.yaml`.77`~/.juju/environments.yaml`.
7878
79### Deploying behind a firewall ###79### Deploying behind a firewall ###
8080
@@ -102,9 +102,6 @@
102deploy behind a firewall configuring the charm to pull the GUI release from a102deploy behind a firewall configuring the charm to pull the GUI release from a
103location you specify.103location you specify.
104104
105For both Juju Core and PyJuju, you must simply do the following steps. Note
106that PyJuju must do these steps, plus another set described further below.
107
108The config variable `juju-gui-source` allows a `url:` prefix which understands105The config variable `juju-gui-source` allows a `url:` prefix which understands
109both `http://` and `file://` protocols. We will use this to load a local copy106both `http://` and `file://` protocols. We will use this to load a local copy
110of the GUI source.107of the GUI source.
@@ -125,14 +122,7 @@
125122
126 `juju resolved --retry juju-gui/0`123 `juju resolved --retry juju-gui/0`
127124
128These steps are sufficient for Juju Core. If you are using PyJuju, you need to125These steps are sufficient for Juju Core.
129do another set of steps in addition.
130
1311. Use bzr to branch lp:~hazmat/juju/rapi-rollup locally ("bzr branch
132lp:~hazmat/juju/rapi-rollup") and copy the branch to the gui service machine.
133
1342. Use "juju set juju-gui juju-api-branch=PATH_TO_LOCAL_BZR_BRANCH" (where the
135path is *not* a file:// URI).
136126
1373. Retry as described in the step 3 above (`juju resolved --retry juju-gui/0`).1273. Retry as described in the step 3 above (`juju resolved --retry juju-gui/0`).
138128
@@ -166,18 +156,6 @@
166156
167 juju deploy --force-machine 0 cs:precise/juju-gui157 juju deploy --force-machine 0 cs:precise/juju-gui
168158
169#### pyjuju ####
170
171Colocation support is not included by default in the pyjuju implementation; to
172activate it, you will need to install Jitsu:
173
174 sudo apt-get install juju-jitsu
175
176and then replace "juju deploy cs:precise/juju-gui" from the previous
177instructions with this:
178
179 jitsu deploy-to 0 cs:precise/juju-gui
180
181## Contacting the Developers ##159## Contacting the Developers ##
182160
183If you run into problems with the charm, please feel free to contact us on the161If you run into problems with the charm, please feel free to contact us on the
184162
=== modified file 'config.yaml'
--- config.yaml 2014-01-09 21:48:27 +0000
+++ config.yaml 2014-01-15 14:49:45 +0000
@@ -36,7 +36,7 @@
36 deployed from the specified Bazaar branch. "http://"" prefixed branches36 deployed from the specified Bazaar branch. "http://"" prefixed branches
37 work as well. It is also possible to include the specific branch37 work as well. It is also possible to include the specific branch
38 revision, e.g. "lp:juju-gui:42" will checkout revno 42.38 revision, e.g. "lp:juju-gui:42" will checkout revno 42.
39 - a "url:"" prefixed url: The release found at the given URL39 - a "url:" prefixed url: The release found at the given URL
40 (ex: url:http://... or url:file://...) will be deployed.40 (ex: url:http://... or url:file://...) will be deployed.
41 type: string41 type: string
42 default: local42 default: local
@@ -45,30 +45,6 @@
45 Run Juju GUI in debug mode, serving the uncompressed GUI source files.45 Run Juju GUI in debug mode, serving the uncompressed GUI source files.
46 type: boolean46 type: boolean
47 default: false47 default: false
48 juju-api-branch:
49 description: |
50 The Juju API Bazaar branch (implementing the WebSocket server). Since
51 juju-core includes the WebSocket API server out of the box, this option
52 is ignored if the charm is deployed using juju-core.
53 type: string
54 default: lp:~hazmat/juju/rapi-rollup
55 staging:
56 description: |
57 Connect the Juju GUI to the staging backend (i.e. a simulated Juju
58 environment). Currently juju-core does not support the staging backend.
59 For this reason, an error is raised if this option is enabled in a
60 juju-core environment.
61 type: boolean
62 default: false
63 staging-environment:
64 description: |
65 The environment JSON export used by the staging server. This option can
66 be used to change the topology of the simulated Juju environment.
67 Possible values are 'sample' and 'large'. Currently juju-core does not
68 support the staging backend. For this reason, this option is ignored if
69 the charm is deployed using juju-core.
70 type: string
71 default: sample
72 juju-gui-console-enabled:48 juju-gui-console-enabled:
73 description: |49 description: |
74 Whether or not the console should be enabled for the browser.50 Whether or not the console should be enabled for the browser.
@@ -132,11 +108,9 @@
132 type: string108 type: string
133 sandbox:109 sandbox:
134 description: |110 description: |
135 Run using an in-memory sandbox rather than a real (or even improv) Juju111 Run using an in-memory sandbox rather than a real Juju backend. Sandbox
136 backend. Sandbox is a client side construct running entirely in the112 is a client side construct running entirely in the client. Sandbox does
137 client. Sandbox does not currently support imported environment113 not currently support imported environment simulation.
138 simulation and is exclusive to the staging: true configuration. If
139 staging is true it will be used in preference to sandbox at this time.
140 type: boolean114 type: boolean
141 default: false115 default: false
142 charmworld-url:116 charmworld-url:
143117
=== modified file 'config/haproxy.cfg.template'
--- config/haproxy.cfg.template 2013-03-28 09:39:45 +0000
+++ config/haproxy.cfg.template 2014-01-15 14:49:45 +0000
@@ -22,13 +22,9 @@
22backend juju22backend juju
23 # The Juju WebSocket backend.23 # The Juju WebSocket backend.
24 # Re-encrypt outgoing connections.24 # Re-encrypt outgoing connections.
25 {{if legacy_juju}}25 # Replace "/ws/" with "/" in any request path.
26 server ws1 {{api_address}} ssl ca-file {{api_pem}} verify required check-ssl inter 500ms26 reqrep ^([^\ ]*)\ /ws/ \1\ /
27 {{else}}27 server ws1 {{api_address}} ssl check-ssl inter 500ms
28 # Replace "/ws/" with "/" in any request path.
29 reqrep ^([^\ ]*)\ /ws/ \1\ /
30 server ws1 {{api_address}} ssl check-ssl inter 500ms
31 {{endif}}
3228
33backend web29backend web
34 # Web traffic.30 # Web traffic.
3531
=== removed file 'config/juju-api-agent.conf.template'
--- config/juju-api-agent.conf.template 2013-05-22 15:22:53 +0000
+++ config/juju-api-agent.conf.template 1970-01-01 00:00:00 +0000
@@ -1,18 +0,0 @@
1description "Juju API agent"
2author "Canonical"
3
4start on runlevel [2345]
5stop on runlevel [!2345]
6
7env JUJU_ZOOKEEPER={{zookeeper}}
8
9# Fix for bug 1130681: when the environment sets "juju-origin: lp:juju",
10# easy_install mucks sys.path and the juju libs are not found, unless we
11# change to their directory so that it comes first in sys.path.
12chdir {{juju_dir}}
13
14# Use --nodaemon so that upstart can correctly retrieve the process ID.
15exec /usr/bin/python -m juju.agents.api --nodaemon --port {{port}} \
16 --logfile /var/log/juju/api-agent.log \
17 --session-file /var/run/juju/api-agent.zksession \
18 --secure --keys {{keys}} {{if read_only}} --read-only {{endif}}
190
=== removed file 'config/juju-api-improv.conf.template'
--- config/juju-api-improv.conf.template 2013-02-04 17:26:32 +0000
+++ config/juju-api-improv.conf.template 1970-01-01 00:00:00 +0000
@@ -1,12 +0,0 @@
1description "Juju API staging"
2author "Canonical"
3
4start on runlevel [2345]
5stop on runlevel [!2345]
6
7setuid ubuntu
8env PYTHONPATH={{juju_dir}}:$PYTHONPATH
9
10exec /usr/bin/python {{juju_dir}}/improv.py --port {{port}} \
11 -f {{juju_dir}}/{{staging_env}}.json \
12 --secure --keys {{keys}}
130
=== modified file 'hooks/backend.py'
--- hooks/backend.py 2014-01-09 21:48:27 +0000
+++ hooks/backend.py 2014-01-15 14:49:45 +0000
@@ -67,43 +67,10 @@
67 shutil.rmtree(utils.BASE_DIR)67 shutil.rmtree(utils.BASE_DIR)
6868
6969
70class PythonInstallMixinBase(object):
71 """Provide a common "install" method to ImprovMixin and PythonMixin."""
72
73 def install(self, backend):
74 if (not os.path.exists(utils.JUJU_AGENT_DIR) or
75 backend.different('staging', 'juju-api-branch')):
76 utils.fetch_api(backend.config['juju-api-branch'])
77
78
79class ImprovMixin(PythonInstallMixinBase):
80 """Manage the improv backend when on staging."""
81
82 debs = ('zookeeper',)
83
84 def start(self, backend):
85 config = backend.config
86 utils.start_improv(
87 config['staging-environment'], config['ssl-cert-path'])
88
89 def stop(self, backend):
90 utils.stop_improv()
91
92
93class SandboxMixin(object):70class SandboxMixin(object):
94 pass71 pass
9572
9673
97class PythonMixin(PythonInstallMixinBase):
98 """Manage the real PyJuju backend."""
99
100 def start(self, backend):
101 utils.start_agent(backend.config['ssl-cert-path'])
102
103 def stop(self, backend):
104 utils.stop_agent()
105
106
107class GoMixin(object):74class GoMixin(object):
108 """Manage the real Go juju-core backend."""75 """Manage the real Go juju-core backend."""
109 pass76 pass
@@ -149,7 +116,7 @@
149 config['juju-gui-debug'], config['serve-tests'])116 config['juju-gui-debug'], config['serve-tests'])
150 utils.write_gui_config(117 utils.write_gui_config(
151 config['juju-gui-console-enabled'], config['login-help'],118 config['juju-gui-console-enabled'], config['login-help'],
152 config['read-only'], config['staging'], config['charmworld-url'],119 config['read-only'], config['charmworld-url'],
153 build_dir, secure=config['secure'], sandbox=config['sandbox'],120 build_dir, secure=config['secure'], sandbox=config['sandbox'],
154 ga_key=config['ga-key'],121 ga_key=config['ga-key'],
155 show_get_juju_button=config['show-get-juju-button'],122 show_get_juju_button=config['show-get-juju-button'],
@@ -255,16 +222,10 @@
255 self.prev_config = prev_config222 self.prev_config = prev_config
256 self.mixins = [SetUpMixin()]223 self.mixins = [SetUpMixin()]
257224
258 is_legacy_juju = utils.legacy_juju()225 if config['sandbox']:
259
260 if config['staging']:
261 if not is_legacy_juju:
262 raise ValueError('Unable to use staging with go backend')
263 self.mixins.append(ImprovMixin())
264 elif config['sandbox']:
265 self.mixins.append(SandboxMixin())226 self.mixins.append(SandboxMixin())
266 else:227 else:
267 mixin = PythonMixin() if is_legacy_juju else GoMixin()228 mixin = GoMixin()
268 self.mixins.append(mixin)229 self.mixins.append(mixin)
269230
270 # We always install and start the GUI.231 # We always install and start the GUI.
271232
=== modified file 'hooks/utils.py'
--- hooks/utils.py 2014-01-13 16:53:45 +0000
+++ hooks/utils.py 2014-01-15 14:49:45 +0000
@@ -21,14 +21,12 @@
21 'APACHE_PORTS',21 'APACHE_PORTS',
22 'API_PORT',22 'API_PORT',
23 'CURRENT_DIR',23 'CURRENT_DIR',
24 'JUJU_AGENT_DIR',
25 'JUJU_GUI_DIR',24 'JUJU_GUI_DIR',
26 'JUJU_PEM',25 'JUJU_PEM',
27 'WEB_PORT',26 'WEB_PORT',
28 'cmd_log',27 'cmd_log',
29 'compute_build_dir',28 'compute_build_dir',
30 'download_release',29 'download_release',
31 'fetch_api',
32 'fetch_gui_from_branch',30 'fetch_gui_from_branch',
33 'fetch_gui_release',31 'fetch_gui_release',
34 'find_missing_packages',32 'find_missing_packages',
@@ -37,9 +35,7 @@
37 'get_launchpad_release',35 'get_launchpad_release',
38 'get_npm_cache_archive_url',36 'get_npm_cache_archive_url',
39 'get_release_file_path',37 'get_release_file_path',
40 'get_zookeeper_address',
41 'install_missing_packages',38 'install_missing_packages',
42 'legacy_juju',
43 'log_hook',39 'log_hook',
44 'parse_source',40 'parse_source',
45 'prime_npm_cache',41 'prime_npm_cache',
@@ -50,14 +46,10 @@
50 'setup_apache_config',46 'setup_apache_config',
51 'setup_gui',47 'setup_gui',
52 'setup_haproxy_config',48 'setup_haproxy_config',
53 'start_agent',
54 'start_builtin_server',49 'start_builtin_server',
55 'start_haproxy_apache',50 'start_haproxy_apache',
56 'start_improv',
57 'stop_agent',
58 'stop_builtin_server',51 'stop_builtin_server',
59 'stop_haproxy_apache',52 'stop_haproxy_apache',
60 'stop_improv',
61 'write_gui_config',53 'write_gui_config',
62]54]
6355
@@ -72,18 +64,17 @@
72from subprocess import CalledProcessError64from subprocess import CalledProcessError
73import tempfile65import tempfile
74import urlparse66import urlparse
67import yaml
7568
76import apt69import apt
77from launchpadlib.launchpad import Launchpad70from launchpadlib.launchpad import Launchpad
78import tempita71import tempita
79import yaml
8072
81from charmhelpers import (73from charmhelpers import (
82 get_config,74 get_config,
83 log,75 log,
84 RESTART,76 RESTART,
85 service_control,77 service_control,
86 START,
87 STOP,78 STOP,
88 unit_get,79 unit_get,
89)80)
@@ -94,17 +85,14 @@
94 install_extra_repositories,85 install_extra_repositories,
95 run,86 run,
96 script_name,87 script_name,
97 search_file,
98 Serializer,88 Serializer,
99 su,89 su,
100)90)
10191
10292
103AGENT = 'juju-api-agent'
104APACHE = 'apache2'93APACHE = 'apache2'
105BUILTIN_SERVER = 'guiserver'94BUILTIN_SERVER = 'guiserver'
106HAPROXY = 'haproxy'95HAPROXY = 'haproxy'
107IMPROV = 'juju-api-improv'
10896
109API_PORT = 808097API_PORT = 8080
110WEB_PORT = 800098WEB_PORT = 8000
@@ -112,7 +100,6 @@
112BASE_DIR = '/var/lib/juju-gui'100BASE_DIR = '/var/lib/juju-gui'
113CURRENT_DIR = os.getcwd()101CURRENT_DIR = os.getcwd()
114CONFIG_DIR = os.path.join(CURRENT_DIR, 'config')102CONFIG_DIR = os.path.join(CURRENT_DIR, 'config')
115JUJU_AGENT_DIR = os.path.join(BASE_DIR, 'juju')
116JUJU_GUI_DIR = os.path.join(BASE_DIR, 'juju-gui')103JUJU_GUI_DIR = os.path.join(BASE_DIR, 'juju-gui')
117RELEASES_DIR = os.path.join(CURRENT_DIR, 'releases')104RELEASES_DIR = os.path.join(CURRENT_DIR, 'releases')
118SERVER_DIR = os.path.join(CURRENT_DIR, 'server')105SERVER_DIR = os.path.join(CURRENT_DIR, 'server')
@@ -123,10 +110,8 @@
123HAPROXY_CFG_PATH = os.path.join(os.path.sep, 'etc', 'haproxy', 'haproxy.cfg')110HAPROXY_CFG_PATH = os.path.join(os.path.sep, 'etc', 'haproxy', 'haproxy.cfg')
124111
125SYS_INIT_DIR = os.path.join(os.path.sep, 'etc', 'init')112SYS_INIT_DIR = os.path.join(os.path.sep, 'etc', 'init')
126AGENT_INIT_PATH = os.path.join(SYS_INIT_DIR, 'juju-api-agent.conf')
127GUISERVER_INIT_PATH = os.path.join(SYS_INIT_DIR, 'guiserver.conf')113GUISERVER_INIT_PATH = os.path.join(SYS_INIT_DIR, 'guiserver.conf')
128HAPROXY_INIT_PATH = os.path.join(SYS_INIT_DIR, 'haproxy.conf')114HAPROXY_INIT_PATH = os.path.join(SYS_INIT_DIR, 'haproxy.conf')
129IMPROV_INIT_PATH = os.path.join(SYS_INIT_DIR, 'juju-api-improv.conf')
130115
131JUJU_PEM = 'juju.includes-private-key.pem'116JUJU_PEM = 'juju.includes-private-key.pem'
132DEB_BUILD_DEPENDENCIES = (117DEB_BUILD_DEPENDENCIES = (
@@ -138,11 +123,6 @@
138config_json = Serializer(os.path.join(os.path.sep, 'tmp', 'config.json'))123config_json = Serializer(os.path.join(os.path.sep, 'tmp', 'config.json'))
139# Bazaar checkout command.124# Bazaar checkout command.
140bzr_checkout = command('bzr', 'co', '--lightweight')125bzr_checkout = command('bzr', 'co', '--lightweight')
141# Whether or not the charm is deployed using juju-core.
142# If juju-core has been used to deploy the charm, an agent.conf file must
143# be present in the charm parent directory.
144legacy_juju = lambda: not os.path.exists(
145 os.path.join(CURRENT_DIR, '..', 'agent.conf'))
146126
147bzr_url_expression = re.compile(r"""127bzr_url_expression = re.compile(r"""
148 ^ # Beginning of line.128 ^ # Beginning of line.
@@ -165,8 +145,6 @@
165def get_api_address(unit_dir=None):145def get_api_address(unit_dir=None):
166 """Return the Juju API address.146 """Return the Juju API address.
167147
168 If not present in the hook context as an environment variable, try to
169 retrieve the address parsing the machiner agent.conf file.
170 """148 """
171 api_addresses = os.getenv('JUJU_API_ADDRESSES')149 api_addresses = os.getenv('JUJU_API_ADDRESSES')
172 if api_addresses is not None:150 if api_addresses is not None:
@@ -187,6 +165,7 @@
187 raise IOError('Juju agent configuration file not found.')165 raise IOError('Juju agent configuration file not found.')
188 contents = yaml.load(open(agent_conf))166 contents = yaml.load(open(agent_conf))
189 return contents['apiinfo']['addrs'][0]167 return contents['apiinfo']['addrs'][0]
168 return api_addresses.split()[0]
190169
191170
192def first_path_in_dir(directory):171def first_path_in_dir(directory):
@@ -235,18 +214,6 @@
235 raise ValueError('%r: file not found' % release_version)214 raise ValueError('%r: file not found' % release_version)
236215
237216
238def get_zookeeper_address(agent_file_path):
239 """Retrieve the Zookeeper address contained in the given *agent_file_path*.
240
241 The *agent_file_path* is a path to a file containing a line similar to the
242 following::
243
244 env JUJU_ZOOKEEPER="address"
245 """
246 line = search_file('JUJU_ZOOKEEPER', agent_file_path).strip()
247 return line.split('=')[1].strip('"')
248
249
250@contextmanager217@contextmanager
251def log_hook():218def log_hook():
252 """Log when a hook starts and stops its execution.219 """Log when a hook starts and stops its execution.
@@ -346,60 +313,6 @@
346 results_log.info('\n' + results)313 results_log.info('\n' + results)
347314
348315
349def start_improv(staging_env, ssl_cert_path):
350 """Start a simulated juju environment using ``improv.py``."""
351 log('Setting up the staging Upstart script.')
352 context = {
353 'juju_dir': JUJU_AGENT_DIR,
354 'keys': ssl_cert_path,
355 'port': API_PORT,
356 'staging_env': staging_env,
357 }
358 render_to_file('juju-api-improv.conf.template', context, IMPROV_INIT_PATH)
359 log('Starting the staging backend.')
360 with su('root'):
361 service_control(IMPROV, START)
362
363
364def stop_improv():
365 """Stop a simulated Juju environment."""
366 log('Stopping the staging backend.')
367 with su('root'):
368 service_control(IMPROV, STOP)
369 log('Removing the staging Upstart script.')
370 cmd_log(run('rm', '-f', IMPROV_INIT_PATH))
371
372
373def start_agent(ssl_cert_path, read_only=False):
374 """Start the Juju agent and connect to the current environment."""
375 # Retrieve the Zookeeper address from the start up script.
376 unit_name = os.path.basename(
377 os.path.realpath(os.path.join(CURRENT_DIR, '..')))
378 agent_file = os.path.join(SYS_INIT_DIR, 'juju-{}.conf'.format(unit_name))
379 zookeeper = get_zookeeper_address(agent_file)
380 log('Setting up the API agent Upstart script.')
381 context = {
382 'juju_dir': JUJU_AGENT_DIR,
383 'keys': ssl_cert_path,
384 'port': API_PORT,
385 'zookeeper': zookeeper,
386 'read_only': read_only
387 }
388 render_to_file('juju-api-agent.conf.template', context, AGENT_INIT_PATH)
389 log('Starting the API agent.')
390 with su('root'):
391 service_control(AGENT, START)
392
393
394def stop_agent():
395 """Stop the Juju agent."""
396 log('Stopping the API agent.')
397 with su('root'):
398 service_control(AGENT, STOP)
399 log('Removing the API agent Upstart script.')
400 cmd_log(run('rm', '-f', AGENT_INIT_PATH))
401
402
403def compute_build_dir(juju_gui_debug, serve_tests):316def compute_build_dir(juju_gui_debug, serve_tests):
404 """Compute the build directory."""317 """Compute the build directory."""
405 with su('root'):318 with su('root'):
@@ -416,19 +329,21 @@
416329
417330
418def write_gui_config(331def write_gui_config(
419 console_enabled, login_help, readonly, in_staging, charmworld_url,332 console_enabled, login_help, readonly, charmworld_url,
420 build_dir, secure=True, sandbox=False,333 build_dir, secure=True, sandbox=False,
421 show_get_juju_button=False, config_js_path=None, ga_key='',334 show_get_juju_button=False, config_js_path=None, ga_key='',
422 password=None):335 password=None):
423 """Generate the GUI configuration file."""336 """Generate the GUI configuration file."""
424 log('Generating the Juju GUI configuration file.')337 log('Generating the Juju GUI configuration file.')
425 is_legacy_juju = legacy_juju()338 user = 'user-admin'
426 user = 'admin' if is_legacy_juju else 'user-admin'339 # Normalize empty string passwords to None. If sandbox is enabled then set
427 # Normalize empty string passwords to None.340 # the password to admin and it will auto login.
428 password = password if password else None341 if not password:
429 if password is None and ((is_legacy_juju and in_staging) or sandbox):342 if sandbox:
430 password = 'admin'343 password = 'admin'
431 api_backend = 'python' if (is_legacy_juju and not sandbox) else 'go'344 else:
345 password = None
346 api_backend = 'go'
432 if secure:347 if secure:
433 protocol = 'wss'348 protocol = 'wss'
434 else:349 else:
@@ -461,21 +376,12 @@
461 config_path = os.path.join(CONFIG_DIR, 'haproxy.conf')376 config_path = os.path.join(CONFIG_DIR, 'haproxy.conf')
462 shutil.copy(config_path, SYS_INIT_DIR)377 shutil.copy(config_path, SYS_INIT_DIR)
463 log('Generating haproxy configuration file.')378 log('Generating haproxy configuration file.')
464 is_legacy_juju = legacy_juju()379 # Retrieve the juju-core API server address.
465 if is_legacy_juju:380 api_address = get_api_address()
466 # The PyJuju API agent is listening on localhost.
467 api_address = '127.0.0.1:{}'.format(API_PORT)
468 else:
469 # Retrieve the juju-core API server address.
470 api_address = get_api_address()
471 context = {381 context = {
472 'api_address': api_address,382 'api_address': api_address,
473 'api_pem': JUJU_PEM,383 'api_pem': JUJU_PEM,
474 'legacy_juju': is_legacy_juju,
475 'ssl_cert_path': ssl_cert_path,384 'ssl_cert_path': ssl_cert_path,
476 # In PyJuju environments, use the same certificate for both HTTPS and
477 # WebSocket connections. In juju-core the system already has the proper
478 # certificate installed.
479 'web_pem': JUJU_PEM,385 'web_pem': JUJU_PEM,
480 'web_port': WEB_PORT,386 'web_port': WEB_PORT,
481 'secure': secure387 'secure': secure
@@ -577,14 +483,10 @@
577 'charmworld_url': charmworld_url,483 'charmworld_url': charmworld_url,
578 }484 }
579 if not sandbox:485 if not sandbox:
580 is_legacy_juju = legacy_juju()486 api_url = 'wss://{}'.format(get_api_address())
581 if is_legacy_juju:
582 api_url = 'wss://127.0.0.1:{}/ws'.format(API_PORT)
583 else:
584 api_url = 'wss://{}'.format(get_api_address())
585 context.update({487 context.update({
586 'api_url': api_url,488 'api_url': api_url,
587 'api_version': 'python' if is_legacy_juju else 'go',489 'api_version': 'go',
588 })490 })
589 if serve_tests:491 if serve_tests:
590 context['tests_root'] = os.path.join(JUJU_GUI_DIR, 'test', '')492 context['tests_root'] = os.path.join(JUJU_GUI_DIR, 'test', '')
@@ -737,14 +639,6 @@
737 return download_release(url, filename)639 return download_release(url, filename)
738640
739641
740def fetch_api(juju_api_branch):
741 """Retrieve the Juju branch, removing it first if already there."""
742 # Retrieve Juju API source checkout.
743 log('Retrieving Juju API source checkout.')
744 cmd_log(run('rm', '-rf', JUJU_AGENT_DIR))
745 cmd_log(bzr_checkout(juju_api_branch, JUJU_AGENT_DIR))
746
747
748def setup_gui(release_tarball):642def setup_gui(release_tarball):
749 """Set up Juju GUI."""643 """Set up Juju GUI."""
750 # Uncompress the release tarball.644 # Uncompress the release tarball.
751645
=== modified file 'tests/20-functional.test'
--- tests/20-functional.test 2013-11-27 15:20:58 +0000
+++ tests/20-functional.test 2014-01-15 14:49:45 +0000
@@ -35,16 +35,12 @@
35from helpers import (35from helpers import (
36 get_admin_secret,36 get_admin_secret,
37 juju_destroy_service,37 juju_destroy_service,
38 juju_version,
39 make_service_name,38 make_service_name,
40 stop_services,
41 WebSocketClient,39 WebSocketClient,
42)40)
43import example41import example
4442
45JUJU_GUI_TEST_BRANCH = 'lp:~juju-gui/juju-gui/charm-tests-branch'43JUJU_GUI_TEST_BRANCH = 'lp:~juju-gui/juju-gui/charm-tests-branch'
46STAGING_SERVICES = ('haproxy', 'mediawiki', 'memcached', 'mysql', 'wordpress')
47is_legacy_juju = juju_version().major == 0
48try:44try:
49 admin_secret = get_admin_secret()45 admin_secret = get_admin_secret()
50except ValueError as err:46except ValueError as err:
@@ -62,33 +58,18 @@
62 of services that are started in the Juju GUI unit and that must be58 of services that are started in the Juju GUI unit and that must be
63 manually stopped by tests. In juju-core, the services list is always empty.59 manually stopped by tests. In juju-core, the services list is always empty.
64 """60 """
65 force_machine = None if is_legacy_juju else 0
66 service_name = make_service_name(prefix='juju-gui-')61 service_name = make_service_name(prefix='juju-gui-')
67 unit_info = juju_deploy(62 unit_info = juju_deploy(
68 'juju-gui', service_name=service_name, options=options,63 'juju-gui', service_name=service_name, options=options,
69 force_machine=force_machine)64 force_machine=0)
70 # XXX 2012-11-29 frankban bug=872264:
71 # Just invoking ``juju destroy-service juju-gui`` in tearDown
72 # should execute the ``stop`` hook, stopping all the services
73 # started by the charm in the machine. Right now this does not
74 # work in pyJuju, so the desired effect is achieved by keeping
75 # track of started services and manually stopping them here.
76 # Once pyJuju works correctly or we drop support for it altogether, we
77 # can remove this shim.
78 cleanup_services = []65 cleanup_services = []
79 if is_legacy_juju:66 if options is None:
80 if options is None:67 options = {}
81 options = {}68 # Either stop the builtin server or the old apache2/haproxy setup.
82 # Either stop the builtin server or the old apache2/haproxy setup.69 if options.get('builtin-server') == 'true':
83 if options.get('builtin-server') == 'true':70 cleanup_services.append('guiserver')
84 cleanup_services.append('guiserver')71 else:
85 else:72 cleanup_services.extend(['haproxy', 'apache2'])
86 cleanup_services.extend(['haproxy', 'apache2'])
87 # Staging uses improv, otherwise the API agent is used.
88 if options.get('staging') == 'true':
89 cleanup_services.append('juju-api-improv')
90 else:
91 cleanup_services.append('juju-api-agent')
92 return service_name, unit_info, cleanup_services73 return service_name, unit_info, cleanup_services
9374
9475
@@ -177,19 +158,6 @@
177 services = self.wait_for(services_found, 'Services not displayed.')158 services = self.wait_for(services_found, 'Services not displayed.')
178 return set([element.text for element in services])159 return set([element.text for element in services])
179160
180 def deploy_gui(self, options=None):
181 """Shim in our additional cleanup for pyJuju."""
182 # Once pyJuju works correctly or we drop support for it altogether, we
183 # can remove this shim.
184 self.service_name, unit_info, cleanup_services = juju_deploy_gui(
185 options=options)
186 # XXX 2013-11-27 frankban bug=872264:
187 # See juju_deploy_gui above.
188 if is_legacy_juju:
189 hostname = unit_info['public-address']
190 self.addCleanup(stop_services, hostname, cleanup_services)
191 return unit_info
192
193 def get_builtin_server_info(self, hostname):161 def get_builtin_server_info(self, hostname):
194 """Return a dictionary of info as exposed by the builtin server."""162 """Return a dictionary of info as exposed by the builtin server."""
195 url = 'https://{}/gui-server-info'.format(hostname)163 url = 'https://{}/gui-server-info'.format(hostname)
@@ -205,26 +173,17 @@
205173
206 def test_stable_release(self):174 def test_stable_release(self):
207 # Ensure the stable Juju GUI release is correctly set up.175 # Ensure the stable Juju GUI release is correctly set up.
208 unit_info = self.deploy_gui(options={'juju-gui-source': 'stable'})176 self.service_name, unit_info, _ = juju_deploy_gui(
209 hostname = unit_info['public-address']177 options={'juju-gui-source': 'stable'})
210 self.navigate_to(hostname)178 hostname = unit_info['public-address']
211 self.handle_browser_warning()179 self.navigate_to(hostname)
212 self.assertEnvironmentIsConnected()180 self.handle_browser_warning()
213181 self.assertEnvironmentIsConnected()
214 @unittest.skipUnless(is_legacy_juju, 'staging only works in pyJuju')
215 def test_staging(self):
216 # Ensure the Juju GUI and staging services are correctly set up.
217 unit_info = self.deploy_gui(options={'staging': 'true'})
218 hostname = unit_info['public-address']
219 self.navigate_to(hostname)
220 self.handle_browser_warning()
221 self.assertEnvironmentIsConnected()
222 # The staging environment contains five deployed services.
223 self.assertSetEqual(set(STAGING_SERVICES), self.get_service_names())
224182
225 def test_sandbox(self):183 def test_sandbox(self):
226 # The GUI is correctly deployed and set up in sandbox mode.184 # The GUI is correctly deployed and set up in sandbox mode.
227 unit_info = self.deploy_gui(options={'sandbox': 'true'})185 self.service_name, unit_info, _ = juju_deploy_gui(
186 options={'sandbox': 'true'})
228 hostname = unit_info['public-address']187 hostname = unit_info['public-address']
229 self.navigate_to(hostname)188 self.navigate_to(hostname)
230 self.handle_browser_warning()189 self.handle_browser_warning()
@@ -236,7 +195,7 @@
236 def test_branch_source(self):195 def test_branch_source(self):
237 # Ensure the Juju GUI is correctly deployed from a Bazaar branch.196 # Ensure the Juju GUI is correctly deployed from a Bazaar branch.
238 options = {'juju-gui-source': JUJU_GUI_TEST_BRANCH}197 options = {'juju-gui-source': JUJU_GUI_TEST_BRANCH}
239 unit_info = self.deploy_gui(options=options)198 self.service_name, unit_info, _ = juju_deploy_gui(options=options)
240 hostname = unit_info['public-address']199 hostname = unit_info['public-address']
241 self.navigate_to(hostname)200 self.navigate_to(hostname)
242 self.handle_browser_warning()201 self.handle_browser_warning()
@@ -245,7 +204,8 @@
245 def test_legacy_server(self):204 def test_legacy_server(self):
246 # The legacy apache + haproxy server configuration works correctly.205 # The legacy apache + haproxy server configuration works correctly.
247 # Also make sure the correct cache headers are sent.206 # Also make sure the correct cache headers are sent.
248 unit_info = self.deploy_gui(options={'builtin-server': 'false'})207 self.service_name, unit_info, _ = juju_deploy_gui(
208 options={'builtin-server': 'false'})
249 hostname = unit_info['public-address']209 hostname = unit_info['public-address']
250 self.navigate_to(hostname)210 self.navigate_to(hostname)
251 self.handle_browser_warning()211 self.handle_browser_warning()
@@ -279,10 +239,6 @@
279 # Destroy the GUI service, and perform additional clean up in the case239 # Destroy the GUI service, and perform additional clean up in the case
280 # we are in a pyJuju environment.240 # we are in a pyJuju environment.
281 juju_destroy_service(cls.service_name)241 juju_destroy_service(cls.service_name)
282 # XXX 2013-11-27 frankban bug=872264:
283 # See juju_deploy_gui above.
284 if is_legacy_juju:
285 stop_services(cls.hostname, cls.cleanup_services)
286242
287 def make_websocket_client(self, authenticated=True):243 def make_websocket_client(self, authenticated=True):
288 """Create and return a WebSocket client connected to the Juju backend.244 """Create and return a WebSocket client connected to the Juju backend.
@@ -320,8 +276,6 @@
320 server_header = dict(headers)['server']276 server_header = dict(headers)['server']
321 self.assertIn('TornadoServer', server_header)277 self.assertIn('TornadoServer', server_header)
322278
323 @unittest.skipIf(
324 is_legacy_juju, 'bundle deployments are only supported in juju-core')
325 def test_deployer_not_authenticated(self):279 def test_deployer_not_authenticated(self):
326 # An error is returned trying to start a bundle deployment without280 # An error is returned trying to start a bundle deployment without
327 # being authenticated.281 # being authenticated.
@@ -337,8 +291,6 @@
337 'unauthorized access: no user logged in', response['Error'])291 'unauthorized access: no user logged in', response['Error'])
338292
339 @unittest.skipUnless(admin_secret, 'admin secret was not found')293 @unittest.skipUnless(admin_secret, 'admin secret was not found')
340 @unittest.skipIf(
341 is_legacy_juju, 'bundle deployments are only supported in juju-core')
342 def test_deployer_invalid_bundle_name(self):294 def test_deployer_invalid_bundle_name(self):
343 # An error is returned trying to deploy a bundle with an invalid name.295 # An error is returned trying to deploy a bundle with an invalid name.
344 client = self.make_websocket_client()296 client = self.make_websocket_client()
@@ -353,8 +305,6 @@
353 'invalid request: bundle no-such not found', response['Error'])305 'invalid request: bundle no-such not found', response['Error'])
354306
355 @unittest.skipUnless(admin_secret, 'admin secret was not found')307 @unittest.skipUnless(admin_secret, 'admin secret was not found')
356 @unittest.skipIf(
357 is_legacy_juju, 'bundle deployments are only supported in juju-core')
358 def test_deployer_invalid_bundle_yaml(self):308 def test_deployer_invalid_bundle_yaml(self):
359 # An error is returned trying to deploy an invalid bundle YAML.309 # An error is returned trying to deploy an invalid bundle YAML.
360 client = self.make_websocket_client()310 client = self.make_websocket_client()
@@ -369,8 +319,6 @@
369 'invalid request: invalid YAML contents', response['Error'])319 'invalid request: invalid YAML contents', response['Error'])
370320
371 @unittest.skipUnless(admin_secret, 'admin secret was not found')321 @unittest.skipUnless(admin_secret, 'admin secret was not found')
372 @unittest.skipIf(
373 is_legacy_juju, 'bundle deployments are only supported in juju-core')
374 def test_deployer_watch_unknown_deployment(self):322 def test_deployer_watch_unknown_deployment(self):
375 # An error is returned trying to watch an unknown deployment.323 # An error is returned trying to watch an unknown deployment.
376 client = self.make_websocket_client()324 client = self.make_websocket_client()
@@ -385,8 +333,6 @@
385 'invalid request: deployment not found', response['Error'])333 'invalid request: deployment not found', response['Error'])
386334
387 @unittest.skipUnless(admin_secret, 'admin secret was not found')335 @unittest.skipUnless(admin_secret, 'admin secret was not found')
388 @unittest.skipIf(
389 is_legacy_juju, 'bundle deployments are only supported in juju-core')
390 def test_deployer(self):336 def test_deployer(self):
391 # The builtin server supports deploying bundles using juju-deployer.337 # The builtin server supports deploying bundles using juju-deployer.
392 client = self.make_websocket_client()338 client = self.make_websocket_client()
393339
=== modified file 'tests/helpers.py'
--- tests/helpers.py 2013-11-27 14:37:06 +0000
+++ tests/helpers.py 2014-01-15 14:49:45 +0000
@@ -21,7 +21,6 @@
21import json21import json
22import os22import os
23import random23import random
24import re
25import string24import string
26import subprocess25import subprocess
27import time26import time
@@ -172,36 +171,6 @@
172 return json.loads(status)171 return json.loads(status)
173172
174173
175_juju_version_expression = re.compile(r"""
176 ^ # Beginning of line.
177 (?:juju\s+)? # Optional juju prefix.
178 (\d+)\.(\d+) # Major and minor versions.
179 (?:\.(\d+))? # Optional patch version.
180 .* # Optional suffix.
181 $ # End of line.
182""", re.VERBOSE)
183
184
185def juju_version():
186 """Return the currently used Juju version.
187
188 The version is returned as a named tuple (major, minor, patch).
189 If the patch number is missing, it is set to zero.
190 """
191 try:
192 # In pyJuju, version info is printed to stderr.
193 output = subprocess.check_output(
194 ['juju', '--version'], stderr=subprocess.STDOUT)
195 except subprocess.CalledProcessError:
196 # Current juju-core exposes a version subcommand.
197 output = subprocess.check_output(['juju', 'version'])
198 match = _juju_version_expression.match(output)
199 if match is None:
200 raise ValueError('invalid juju version: {!r}'.format(output))
201 to_int = lambda num: 0 if num is None else int(num)
202 return Version._make(map(to_int, match.groups()))
203
204
205def make_service_name(prefix='service-'):174def make_service_name(prefix='service-'):
206 """Generate a long, random service name."""175 """Generate a long, random service name."""
207 characters = string.ascii_lowercase176 characters = string.ascii_lowercase
208177
=== modified file 'tests/test_backends.py'
--- tests/test_backends.py 2014-01-09 21:48:27 +0000
+++ tests/test_backends.py 2014-01-15 14:49:45 +0000
@@ -38,10 +38,6 @@
38 'curl', 'openssl', 'python-bzrlib', 'python-pip')38 'curl', 'openssl', 'python-bzrlib', 'python-pip')
39EXPECTED_GO_BUILTIN_DEBS = ('curl', 'openssl', 'python-bzrlib', 'python-pip')39EXPECTED_GO_BUILTIN_DEBS = ('curl', 'openssl', 'python-bzrlib', 'python-pip')
4040
41simulate_pyjuju = mock.patch('utils.legacy_juju', mock.Mock(return_value=True))
42simulate_juju_core = mock.patch(
43 'utils.legacy_juju', mock.Mock(return_value=False))
44
4541
46class TestBackendProperties(unittest.TestCase):42class TestBackendProperties(unittest.TestCase):
47 """Ensure the correct mixins and property values are collected."""43 """Ensure the correct mixins and property values are collected."""
@@ -66,59 +62,14 @@
66 'builtin-server': False,62 'builtin-server': False,
67 'repository-location': 'ppa:my/location',63 'repository-location': 'ppa:my/location',
68 'sandbox': True,64 'sandbox': True,
69 'staging': False,
70 }65 }
71 test_backend = backend.Backend(config=config)66 test_backend = backend.Backend(config=config)
72 self.assert_mixins(expected_mixins, test_backend)67 self.assert_mixins(expected_mixins, test_backend)
73 self.assert_dependencies(68 self.assert_dependencies(
74 EXPECTED_PYTHON_LEGACY_DEBS, 'ppa:my/location', test_backend)69 EXPECTED_PYTHON_LEGACY_DEBS, 'ppa:my/location', test_backend)
7570
76 def test_python_staging_backend(self):
77 expected_mixins = (
78 'SetUpMixin', 'ImprovMixin', 'GuiMixin', 'HaproxyApacheMixin')
79 config = {
80 'builtin-server': False,
81 'repository-location': 'ppa:my/location',
82 'sandbox': False,
83 'staging': True,
84 }
85 with simulate_pyjuju:
86 test_backend = backend.Backend(config=config)
87 self.assert_mixins(expected_mixins, test_backend)
88 self.assert_dependencies(
89 EXPECTED_PYTHON_LEGACY_DEBS + ('zookeeper',),
90 'ppa:my/location', test_backend)
91
92 def test_go_staging_backend(self):
93 config = {'sandbox': False, 'staging': True, 'builtin-server': False}
94 with simulate_juju_core:
95 with self.assertRaises(ValueError) as context_manager:
96 backend.Backend(config=config)
97 error = str(context_manager.exception)
98 self.assertEqual('Unable to use staging with go backend', error)
99
100 def test_python_sandbox_backend(self):
101 with simulate_pyjuju:
102 self.check_sandbox_mode()
103
104 def test_go_sandbox_backend(self):71 def test_go_sandbox_backend(self):
105 with simulate_juju_core:72 self.check_sandbox_mode()
106 self.check_sandbox_mode()
107
108 def test_python_backend(self):
109 expected_mixins = (
110 'SetUpMixin', 'PythonMixin', 'GuiMixin', 'HaproxyApacheMixin')
111 config = {
112 'builtin-server': False,
113 'repository-location': 'ppa:my/location',
114 'sandbox': False,
115 'staging': False,
116 }
117 with simulate_pyjuju:
118 test_backend = backend.Backend(config=config)
119 self.assert_mixins(expected_mixins, test_backend)
120 self.assert_dependencies(
121 EXPECTED_PYTHON_LEGACY_DEBS, 'ppa:my/location', test_backend)
12273
123 def test_go_backend(self):74 def test_go_backend(self):
124 expected_mixins = (75 expected_mixins = (
@@ -127,58 +78,37 @@
127 'builtin-server': False,78 'builtin-server': False,
128 'repository-location': 'ppa:my/location',79 'repository-location': 'ppa:my/location',
129 'sandbox': False,80 'sandbox': False,
130 'staging': False,
131 }81 }
132 with simulate_juju_core:82 test_backend = backend.Backend(config=config)
133 test_backend = backend.Backend(config=config)83 self.assert_mixins(expected_mixins, test_backend)
134 self.assert_mixins(expected_mixins, test_backend)84 self.assert_dependencies(
135 self.assert_dependencies(85 EXPECTED_GO_LEGACY_DEBS, 'ppa:my/location', test_backend)
136 EXPECTED_GO_LEGACY_DEBS, 'ppa:my/location', test_backend)
13786
138 def test_go_builtin_server(self):87 def test_go_builtin_server(self):
139 config = {88 config = {
140 'builtin-server': True,89 'builtin-server': True,
141 'repository-location': 'ppa:my/location',90 'repository-location': 'ppa:my/location',
142 'sandbox': False,91 'sandbox': False,
143 'staging': False,
144 }92 }
145 expected_mixins = (93 expected_mixins = (
146 'SetUpMixin', 'GoMixin', 'GuiMixin', 'BuiltinServerMixin')94 'SetUpMixin', 'GoMixin', 'GuiMixin', 'BuiltinServerMixin')
147 with simulate_juju_core:95 test_backend = backend.Backend(config)
148 test_backend = backend.Backend(config)96 self.assert_mixins(expected_mixins, test_backend)
149 self.assert_mixins(expected_mixins, test_backend)97 self.assert_dependencies(
150 self.assert_dependencies(98 EXPECTED_GO_BUILTIN_DEBS, None, test_backend)
151 EXPECTED_GO_BUILTIN_DEBS, None, test_backend)
152
153 def test_python_builtin_server(self):
154 config = {
155 'builtin-server': True,
156 'repository-location': 'ppa:my/location',
157 'sandbox': False,
158 'staging': False,
159 }
160 expected_mixins = (
161 'SetUpMixin', 'PythonMixin', 'GuiMixin', 'BuiltinServerMixin')
162 with simulate_pyjuju:
163 test_backend = backend.Backend(config)
164 self.assert_mixins(expected_mixins, test_backend)
165 self.assert_dependencies(
166 EXPECTED_PYTHON_BUILTIN_DEBS, None, test_backend)
16799
168 def test_sandbox_builtin_server(self):100 def test_sandbox_builtin_server(self):
169 config = {101 config = {
170 'builtin-server': True,102 'builtin-server': True,
171 'repository-location': 'ppa:my/location',103 'repository-location': 'ppa:my/location',
172 'sandbox': True,104 'sandbox': True,
173 'staging': False,
174 }105 }
175 expected_mixins = (106 expected_mixins = (
176 'SetUpMixin', 'SandboxMixin', 'GuiMixin', 'BuiltinServerMixin')107 'SetUpMixin', 'SandboxMixin', 'GuiMixin', 'BuiltinServerMixin')
177 with simulate_juju_core:108 test_backend = backend.Backend(config)
178 test_backend = backend.Backend(config)109 self.assert_mixins(expected_mixins, test_backend)
179 self.assert_mixins(expected_mixins, test_backend)110 self.assert_dependencies(
180 self.assert_dependencies(111 EXPECTED_PYTHON_BUILTIN_DEBS, None, test_backend)
181 EXPECTED_PYTHON_BUILTIN_DEBS, None, test_backend)
182112
183113
184class TestBackendCommands(unittest.TestCase):114class TestBackendCommands(unittest.TestCase):
@@ -189,10 +119,8 @@
189 self.addCleanup(shutil.rmtree, self.playground)119 self.addCleanup(shutil.rmtree, self.playground)
190 self.base_dir = os.path.join(self.playground, 'juju-gui')120 self.base_dir = os.path.join(self.playground, 'juju-gui')
191 self.command_log_file = os.path.join(self.playground, 'logs')121 self.command_log_file = os.path.join(self.playground, 'logs')
192 self.juju_agent_dir = os.path.join(self.playground, 'juju-agent-dir')
193 self.ssl_cert_path = os.path.join(self.playground, 'ssl-cert-path')122 self.ssl_cert_path = os.path.join(self.playground, 'ssl-cert-path')
194 # Set up default values.123 # Set up default values.
195 self.juju_api_branch = 'lp:juju-api'
196 self.juju_gui_source = 'stable'124 self.juju_gui_source = 'stable'
197 self.repository_location = 'ppa:my/location'125 self.repository_location = 'ppa:my/location'
198 self.parse_source_return_value = ('stable', None)126 self.parse_source_return_value = ('stable', None)
@@ -205,7 +133,6 @@
205 'charmworld-url': 'http://charmworld.example.com/',133 'charmworld-url': 'http://charmworld.example.com/',
206 'command-log-file': self.command_log_file,134 'command-log-file': self.command_log_file,
207 'ga-key': 'my-key',135 'ga-key': 'my-key',
208 'juju-api-branch': self.juju_api_branch,
209 'juju-gui-debug': False,136 'juju-gui-debug': False,
210 'juju-gui-console-enabled': False,137 'juju-gui-console-enabled': False,
211 'juju-gui-source': self.juju_gui_source,138 'juju-gui-source': self.juju_gui_source,
@@ -217,7 +144,6 @@
217 'serve-tests': False,144 'serve-tests': False,
218 'show-get-juju-button': False,145 'show-get-juju-button': False,
219 'ssl-cert-path': self.ssl_cert_path,146 'ssl-cert-path': self.ssl_cert_path,
220 'staging': False,
221 }147 }
222 if options is not None:148 if options is not None:
223 config.update(options)149 config.update(options)
@@ -231,7 +157,6 @@
231 mocks = {157 mocks = {
232 'base_dir': mock.patch('backend.utils.BASE_DIR', self.base_dir),158 'base_dir': mock.patch('backend.utils.BASE_DIR', self.base_dir),
233 'compute_build_dir': mock.patch('backend.utils.compute_build_dir'),159 'compute_build_dir': mock.patch('backend.utils.compute_build_dir'),
234 'fetch_api': mock.patch('backend.utils.fetch_api'),
235 'fetch_gui_from_branch': mock.patch(160 'fetch_gui_from_branch': mock.patch(
236 'backend.utils.fetch_gui_from_branch'),161 'backend.utils.fetch_gui_from_branch'),
237 'fetch_gui_release': mock.patch('backend.utils.fetch_gui_release'),162 'fetch_gui_release': mock.patch('backend.utils.fetch_gui_release'),
@@ -239,8 +164,6 @@
239 'backend.utils.install_builtin_server'),164 'backend.utils.install_builtin_server'),
240 'install_missing_packages': mock.patch(165 'install_missing_packages': mock.patch(
241 'backend.utils.install_missing_packages'),166 'backend.utils.install_missing_packages'),
242 'juju_agent_dir': mock.patch(
243 'backend.utils.JUJU_AGENT_DIR', self.juju_agent_dir),
244 'log': mock.patch('backend.log'),167 'log': mock.patch('backend.log'),
245 'open_port': mock.patch('backend.open_port'),168 'open_port': mock.patch('backend.open_port'),
246 'parse_source': mock.patch(169 'parse_source': mock.patch(
@@ -248,12 +171,10 @@
248 'save_or_create_certificates': mock.patch(171 'save_or_create_certificates': mock.patch(
249 'backend.utils.save_or_create_certificates'),172 'backend.utils.save_or_create_certificates'),
250 'setup_gui': mock.patch('backend.utils.setup_gui'),173 'setup_gui': mock.patch('backend.utils.setup_gui'),
251 'start_agent': mock.patch('backend.utils.start_agent'),
252 'start_builtin_server': mock.patch(174 'start_builtin_server': mock.patch(
253 'backend.utils.start_builtin_server'),175 'backend.utils.start_builtin_server'),
254 'start_haproxy_apache': mock.patch(176 'start_haproxy_apache': mock.patch(
255 'backend.utils.start_haproxy_apache'),177 'backend.utils.start_haproxy_apache'),
256 'stop_agent': mock.patch('backend.utils.stop_agent'),
257 'stop_builtin_server': mock.patch(178 'stop_builtin_server': mock.patch(
258 'backend.utils.stop_builtin_server'),179 'backend.utils.stop_builtin_server'),
259 'stop_haproxy_apache': mock.patch(180 'stop_haproxy_apache': mock.patch(
@@ -271,7 +192,7 @@
271 """Ensure the mocked write_gui_config has been properly called."""192 """Ensure the mocked write_gui_config has been properly called."""
272 mocks.write_gui_config.assert_called_once_with(193 mocks.write_gui_config.assert_called_once_with(
273 config['juju-gui-console-enabled'], config['login-help'],194 config['juju-gui-console-enabled'], config['login-help'],
274 config['read-only'], config['staging'], config['charmworld-url'],195 config['read-only'], config['charmworld-url'],
275 mocks.compute_build_dir(), secure=config['secure'],196 mocks.compute_build_dir(), secure=config['secure'],
276 sandbox=config['sandbox'], ga_key=config['ga-key'],197 sandbox=config['sandbox'], ga_key=config['ga-key'],
277 show_get_juju_button=config['show-get-juju-button'], password=None)198 show_get_juju_button=config['show-get-juju-button'], password=None)
@@ -293,34 +214,14 @@
293 test_backend.destroy()214 test_backend.destroy()
294 self.assertFalse(os.path.exists(utils.BASE_DIR), utils.BASE_DIR)215 self.assertFalse(os.path.exists(utils.BASE_DIR), utils.BASE_DIR)
295216
296 def test_install_python_legacy_stable(self):
297 # Install a pyJuju backend with legacy server and stable release.
298 config = self.make_config({'builtin-server': False})
299 with simulate_pyjuju:
300 test_backend = backend.Backend(config=config)
301 with self.mock_all() as mocks:
302 test_backend.install()
303 mocks.install_missing_packages.assert_called_once_with(
304 set(EXPECTED_PYTHON_LEGACY_DEBS),
305 repository=self.repository_location)
306 mocks.fetch_api.assert_called_once_with(self.juju_api_branch)
307 mocks.parse_source.assert_called_once_with(self.juju_gui_source)
308 mocks.fetch_gui_release.assert_called_once_with(
309 *self.parse_source_return_value)
310 self.assertFalse(mocks.fetch_gui_from_branch.called)
311 mocks.setup_gui.assert_called_once_with(mocks.fetch_gui_release())
312 self.assertFalse(mocks.install_builtin_server.called)
313
314 def test_install_go_legacy_stable(self):217 def test_install_go_legacy_stable(self):
315 # Install a juju-core backend with legacy server and stable release.218 # Install a juju-core backend with legacy server and stable release.
316 config = self.make_config({'builtin-server': False})219 config = self.make_config({'builtin-server': False})
317 with simulate_juju_core:220 test_backend = backend.Backend(config=config)
318 test_backend = backend.Backend(config=config)221 with self.mock_all() as mocks:
319 with self.mock_all() as mocks:222 test_backend.install()
320 test_backend.install()
321 mocks.install_missing_packages.assert_called_once_with(223 mocks.install_missing_packages.assert_called_once_with(
322 set(EXPECTED_GO_LEGACY_DEBS), repository=self.repository_location)224 set(EXPECTED_GO_LEGACY_DEBS), repository=self.repository_location)
323 self.assertFalse(mocks.fetch_api.called)
324 mocks.parse_source.assert_called_once_with(self.juju_gui_source)225 mocks.parse_source.assert_called_once_with(self.juju_gui_source)
325 mocks.fetch_gui_release.assert_called_once_with(226 mocks.fetch_gui_release.assert_called_once_with(
326 *self.parse_source_return_value)227 *self.parse_source_return_value)
@@ -328,33 +229,14 @@
328 mocks.setup_gui.assert_called_once_with(mocks.fetch_gui_release())229 mocks.setup_gui.assert_called_once_with(mocks.fetch_gui_release())
329 self.assertFalse(mocks.install_builtin_server.called)230 self.assertFalse(mocks.install_builtin_server.called)
330231
331 def test_install_python_builtin_stable(self):
332 # Install a pyJuju backend with builtin server and stable release.
333 config = self.make_config({'builtin-server': True})
334 with simulate_pyjuju:
335 test_backend = backend.Backend(config=config)
336 with self.mock_all() as mocks:
337 test_backend.install()
338 mocks.install_missing_packages.assert_called_once_with(
339 set(EXPECTED_PYTHON_BUILTIN_DEBS), repository=None)
340 mocks.fetch_api.assert_called_once_with(self.juju_api_branch)
341 mocks.parse_source.assert_called_once_with(self.juju_gui_source)
342 mocks.fetch_gui_release.assert_called_once_with(
343 *self.parse_source_return_value)
344 self.assertFalse(mocks.fetch_gui_from_branch.called)
345 mocks.setup_gui.assert_called_once_with(mocks.fetch_gui_release())
346 mocks.install_builtin_server.assert_called_once_with()
347
348 def test_install_go_builtin_stable(self):232 def test_install_go_builtin_stable(self):
349 # Install a juju-core backend with builtin server and stable release.233 # Install a juju-core backend with builtin server and stable release.
350 config = self.make_config({'builtin-server': True})234 config = self.make_config({'builtin-server': True})
351 with simulate_juju_core:235 test_backend = backend.Backend(config=config)
352 test_backend = backend.Backend(config=config)236 with self.mock_all() as mocks:
353 with self.mock_all() as mocks:237 test_backend.install()
354 test_backend.install()
355 mocks.install_missing_packages.assert_called_once_with(238 mocks.install_missing_packages.assert_called_once_with(
356 set(EXPECTED_GO_BUILTIN_DEBS), repository=None)239 set(EXPECTED_GO_BUILTIN_DEBS), repository=None)
357 self.assertFalse(mocks.fetch_api.called)
358 mocks.parse_source.assert_called_once_with(self.juju_gui_source)240 mocks.parse_source.assert_called_once_with(self.juju_gui_source)
359 mocks.fetch_gui_release.assert_called_once_with(241 mocks.fetch_gui_release.assert_called_once_with(
360 *self.parse_source_return_value)242 *self.parse_source_return_value)
@@ -373,12 +255,10 @@
373 ),255 ),
374 ]256 ]
375 config = self.make_config({'builtin-server': True})257 config = self.make_config({'builtin-server': True})
376 with simulate_juju_core:258 test_backend = backend.Backend(config=config)
377 test_backend = backend.Backend(config=config)259 with self.mock_all() as mocks:
378 with self.mock_all() as mocks:260 test_backend.install()
379 test_backend.install()
380 mocks.install_missing_packages.assert_has_calls(expected_calls)261 mocks.install_missing_packages.assert_has_calls(expected_calls)
381 self.assertFalse(mocks.fetch_api.called)
382 mocks.parse_source.assert_called_once_with(self.juju_gui_source)262 mocks.parse_source.assert_called_once_with(self.juju_gui_source)
383 mocks.fetch_gui_from_branch.assert_called_once_with(263 mocks.fetch_gui_from_branch.assert_called_once_with(
384 'lp:juju-gui', 42, self.command_log_file)264 'lp:juju-gui', 42, self.command_log_file)
@@ -386,31 +266,12 @@
386 mocks.setup_gui.assert_called_once_with(mocks.fetch_gui_from_branch())266 mocks.setup_gui.assert_called_once_with(mocks.fetch_gui_from_branch())
387 mocks.install_builtin_server.assert_called_once_with()267 mocks.install_builtin_server.assert_called_once_with()
388268
389 def test_start_python_legacy(self):
390 # Start a pyJuju backend with legacy server.
391 config = self.make_config({'builtin-server': False})
392 with simulate_pyjuju:
393 test_backend = backend.Backend(config=config)
394 with self.mock_all() as mocks:
395 test_backend.start()
396 mocks.start_agent.assert_called_once_with(self.ssl_cert_path)
397 mocks.compute_build_dir.assert_called_with(
398 config['juju-gui-debug'], config['serve-tests'])
399 self.assert_write_gui_config_called(mocks, config)
400 mocks.open_port.assert_has_calls([mock.call(80), mock.call(443)])
401 mocks.start_haproxy_apache.assert_called_once_with(
402 mocks.compute_build_dir(), config['serve-tests'],
403 self.ssl_cert_path, config['secure'])
404 self.assertFalse(mocks.start_builtin_server.called)
405
406 def test_start_go_legacy(self):269 def test_start_go_legacy(self):
407 # Start a juju-core backend with legacy server.270 # Start a juju-core backend with legacy server.
408 config = self.make_config({'builtin-server': False})271 config = self.make_config({'builtin-server': False})
409 with simulate_juju_core:272 test_backend = backend.Backend(config=config)
410 test_backend = backend.Backend(config=config)273 with self.mock_all() as mocks:
411 with self.mock_all() as mocks:274 test_backend.start()
412 test_backend.start()
413 self.assertFalse(mocks.start_agent.called)
414 mocks.compute_build_dir.assert_called_with(275 mocks.compute_build_dir.assert_called_with(
415 config['juju-gui-debug'], config['serve-tests'])276 config['juju-gui-debug'], config['serve-tests'])
416 self.assert_write_gui_config_called(mocks, config)277 self.assert_write_gui_config_called(mocks, config)
@@ -420,33 +281,12 @@
420 self.ssl_cert_path, config['secure'])281 self.ssl_cert_path, config['secure'])
421 self.assertFalse(mocks.start_builtin_server.called)282 self.assertFalse(mocks.start_builtin_server.called)
422283
423 def test_start_python_builtin(self):
424 # Start a pyJuju backend with builtin server.
425 config = self.make_config({'builtin-server': True})
426 with simulate_pyjuju:
427 test_backend = backend.Backend(config=config)
428 with self.mock_all() as mocks:
429 test_backend.start()
430 mocks.start_agent.assert_called_once_with(self.ssl_cert_path)
431 mocks.compute_build_dir.assert_called_with(
432 config['juju-gui-debug'], config['serve-tests'])
433 self.assert_write_gui_config_called(mocks, config)
434 mocks.open_port.assert_has_calls([mock.call(80), mock.call(443)])
435 mocks.start_builtin_server.assert_called_once_with(
436 mocks.compute_build_dir(), self.ssl_cert_path,
437 config['serve-tests'], config['sandbox'],
438 config['builtin-server-logging'], not config['secure'],
439 config['charmworld-url'])
440 self.assertFalse(mocks.start_haproxy_apache.called)
441
442 def test_start_go_builtin(self):284 def test_start_go_builtin(self):
443 # Start a juju-core backend with builtin server.285 # Start a juju-core backend with builtin server.
444 config = self.make_config({'builtin-server': True})286 config = self.make_config({'builtin-server': True})
445 with simulate_juju_core:287 test_backend = backend.Backend(config=config)
446 test_backend = backend.Backend(config=config)288 with self.mock_all() as mocks:
447 with self.mock_all() as mocks:289 test_backend.start()
448 test_backend.start()
449 self.assertFalse(mocks.start_agent.called)
450 mocks.compute_build_dir.assert_called_with(290 mocks.compute_build_dir.assert_called_with(
451 config['juju-gui-debug'], config['serve-tests'])291 config['juju-gui-debug'], config['serve-tests'])
452 self.assert_write_gui_config_called(mocks, config)292 self.assert_write_gui_config_called(mocks, config)
@@ -458,47 +298,21 @@
458 config['charmworld-url'])298 config['charmworld-url'])
459 self.assertFalse(mocks.start_haproxy_apache.called)299 self.assertFalse(mocks.start_haproxy_apache.called)
460300
461 def test_stop_python_legacy(self):
462 # Stop a pyJuju backend with legacy server.
463 config = self.make_config({'builtin-server': False})
464 with simulate_pyjuju:
465 test_backend = backend.Backend(config=config)
466 with self.mock_all() as mocks:
467 test_backend.stop()
468 mocks.stop_agent.assert_called_once_with()
469 mocks.stop_haproxy_apache.assert_called_once_with()
470 self.assertFalse(mocks.stop_builtin_server.called)
471
472 def test_stop_go_legacy(self):301 def test_stop_go_legacy(self):
473 # Stop a juju-core backend with legacy server.302 # Stop a juju-core backend with legacy server.
474 config = self.make_config({'builtin-server': False})303 config = self.make_config({'builtin-server': False})
475 with simulate_juju_core:304 test_backend = backend.Backend(config=config)
476 test_backend = backend.Backend(config=config)305 with self.mock_all() as mocks:
477 with self.mock_all() as mocks:306 test_backend.stop()
478 test_backend.stop()
479 self.assertFalse(mocks.stop_agent.called)
480 mocks.stop_haproxy_apache.assert_called_once_with()307 mocks.stop_haproxy_apache.assert_called_once_with()
481 self.assertFalse(mocks.stop_builtin_server.called)308 self.assertFalse(mocks.stop_builtin_server.called)
482309
483 def test_stop_python_builtin(self):
484 # Stop a pyJuju backend with builtin server.
485 config = self.make_config({'builtin-server': True})
486 with simulate_pyjuju:
487 test_backend = backend.Backend(config=config)
488 with self.mock_all() as mocks:
489 test_backend.stop()
490 mocks.stop_agent.assert_called_once_with()
491 mocks.stop_builtin_server.assert_called_once_with()
492 self.assertFalse(mocks.stop_haproxy_apache.called)
493
494 def test_stop_go_builtin(self):310 def test_stop_go_builtin(self):
495 # Stop a juju-core backend with builtin server.311 # Stop a juju-core backend with builtin server.
496 config = self.make_config({'builtin-server': True})312 config = self.make_config({'builtin-server': True})
497 with simulate_juju_core:313 test_backend = backend.Backend(config=config)
498 test_backend = backend.Backend(config=config)314 with self.mock_all() as mocks:
499 with self.mock_all() as mocks:315 test_backend.stop()
500 test_backend.stop()
501 self.assertFalse(mocks.stop_agent.called)
502 mocks.stop_builtin_server.assert_called_once_with()316 mocks.stop_builtin_server.assert_called_once_with()
503 self.assertFalse(mocks.stop_haproxy_apache.called)317 self.assertFalse(mocks.stop_haproxy_apache.called)
504318
@@ -508,22 +322,22 @@
508 def test_same_config(self):322 def test_same_config(self):
509 test_backend = backend.Backend(323 test_backend = backend.Backend(
510 config={324 config={
511 'sandbox': False, 'staging': False, 'builtin-server': False},325 'sandbox': False, 'builtin-server': False},
512 prev_config={326 prev_config={
513 'sandbox': False, 'staging': False, 'builtin-server': False},327 'sandbox': False, 'builtin-server': False},
514 )328 )
515 self.assertFalse(test_backend.different('sandbox'))329 self.assertFalse(test_backend.different('sandbox'))
516 self.assertFalse(test_backend.different('staging'))330 self.assertFalse(test_backend.different('builtin-server'))
517331
518 def test_different_config(self):332 def test_different_config(self):
519 test_backend = backend.Backend(333 test_backend = backend.Backend(
520 config={334 config={
521 'sandbox': False, 'staging': False, 'builtin-server': False},335 'sandbox': False, 'builtin-server': False},
522 prev_config={336 prev_config={
523 'sandbox': True, 'staging': False, 'builtin-server': False},337 'sandbox': True, 'builtin-server': False},
524 )338 )
525 self.assertTrue(test_backend.different('sandbox'))339 self.assertTrue(test_backend.different('sandbox'))
526 self.assertFalse(test_backend.different('staging'))340 self.assertFalse(test_backend.different('builtin-server'))
527341
528342
529class TestCallMethods(unittest.TestCase):343class TestCallMethods(unittest.TestCase):
530344
=== modified file 'tests/test_helpers.py'
--- tests/test_helpers.py 2013-11-26 20:42:52 +0000
+++ tests/test_helpers.py 2014-01-15 14:49:45 +0000
@@ -20,7 +20,6 @@
20import json20import json
21import os21import os
22import shutil22import shutil
23import subprocess
24import tempfile23import tempfile
25import unittest24import unittest
2625
@@ -34,11 +33,9 @@
34 juju_destroy_service,33 juju_destroy_service,
35 juju_env,34 juju_env,
36 juju_status,35 juju_status,
37 juju_version,
38 ProcessError,36 ProcessError,
39 retry,37 retry,
40 stop_services,38 stop_services,
41 Version,
42 wait_for_unit,39 wait_for_unit,
43 WebSocketClient,40 WebSocketClient,
44)41)
@@ -203,74 +200,6 @@
203 mock_juju.assert_called_once_with('status', '--format', 'json')200 mock_juju.assert_called_once_with('status', '--format', 'json')
204201
205202
206@mock.patch('subprocess.check_output')
207class TestJujuVersion(unittest.TestCase):
208
209 error = subprocess.CalledProcessError(2, 'invalid flag', 'output')
210
211 def test_pyjuju(self, mock_check_output):
212 # The pyJuju version is correctly retrieved.
213 mock_check_output.return_value = '0.7.2'
214 version = juju_version()
215 self.assertEqual(Version(0, 7, 2), version)
216 mock_check_output.assert_called_once_with(
217 ['juju', '--version'], stderr=subprocess.STDOUT,
218 )
219
220 def test_juju_core(self, mock_check_output):
221 # The juju-core version is correctly retrieved.
222 mock_check_output.side_effect = (self.error, '1.12.3')
223 version = juju_version()
224 self.assertEqual(Version(1, 12, 3), version)
225 self.assertEqual(2, mock_check_output.call_count)
226 first_call, second_call = mock_check_output.call_args_list
227 self.assertEqual(
228 mock.call(['juju', '--version'], stderr=subprocess.STDOUT),
229 first_call,
230 )
231 self.assertEqual(mock.call(['juju', 'version']), second_call)
232
233 def test_not_semantic_versioning(self, mock_check_output):
234 # If the patch number is missing, it is set to zero.
235 mock_check_output.return_value = '0.7'
236 version = juju_version()
237 self.assertEqual(Version(0, 7, 0), version)
238
239 def test_prefix(self, mock_check_output):
240 # The function handles versions returned as "juju x.y.z".
241 mock_check_output.return_value = 'juju 0.8.3'
242 version = juju_version()
243 self.assertEqual(Version(0, 8, 3), version)
244
245 def test_suffix(self, mock_check_output):
246 # The function handles versions returned as "x.y.z-series-arch".
247 mock_check_output.return_value = '1.10.3-raring-amd64'
248 version = juju_version()
249 self.assertEqual(Version(1, 10, 3), version)
250
251 def test_all(self, mock_check_output):
252 # Additional information is correctly handled.
253 mock_check_output.side_effect = (self.error, 'juju 1.234-precise-i386')
254 version = juju_version()
255 self.assertEqual(Version(1, 234, 0), version)
256 self.assertEqual(2, mock_check_output.call_count)
257
258 def test_invalid_version(self, mock_check_output):
259 # A ValueError is raised if the returned version is not valid.
260 mock_check_output.return_value = '42'
261 with self.assertRaises(ValueError) as info:
262 juju_version()
263 self.assertEqual("invalid juju version: '42'", str(info.exception))
264
265 def test_failure(self, mock_check_output):
266 # A CalledProcessError is raised if the Juju version cannot be found.
267 mock_check_output.side_effect = (self.error, self.error)
268 with self.assertRaises(subprocess.CalledProcessError) as info:
269 juju_version()
270 self.assertIs(self.error, info.exception)
271 self.assertEqual(2, mock_check_output.call_count)
272
273
274class TestProcessError(unittest.TestCase):203class TestProcessError(unittest.TestCase):
275204
276 def test_str(self):205 def test_str(self):
277206
=== modified file 'tests/test_utils.py'
--- tests/test_utils.py 2014-01-09 21:48:27 +0000
+++ tests/test_utils.py 2014-01-15 14:49:45 +0000
@@ -23,15 +23,14 @@
23from subprocess import CalledProcessError23from subprocess import CalledProcessError
24import tempfile24import tempfile
25import unittest25import unittest
26import yaml
2627
27import charmhelpers28import charmhelpers
28import mock29import mock
29from shelltoolbox import environ30from shelltoolbox import environ
30import tempita31import tempita
31import yaml
3232
33from utils import (33from utils import (
34 API_PORT,
35 JUJU_GUI_DIR,34 JUJU_GUI_DIR,
36 JUJU_PEM,35 JUJU_PEM,
37 WEB_PORT,36 WEB_PORT,
@@ -45,10 +44,8 @@
45 get_launchpad_release,44 get_launchpad_release,
46 get_npm_cache_archive_url,45 get_npm_cache_archive_url,
47 get_release_file_path,46 get_release_file_path,
48 get_zookeeper_address,
49 install_builtin_server,47 install_builtin_server,
50 install_missing_packages,48 install_missing_packages,
51 legacy_juju,
52 log_hook,49 log_hook,
53 parse_source,50 parse_source,
54 remove_apache_setup,51 remove_apache_setup,
@@ -57,14 +54,10 @@
57 save_or_create_certificates,54 save_or_create_certificates,
58 setup_apache_config,55 setup_apache_config,
59 setup_haproxy_config,56 setup_haproxy_config,
60 start_agent,
61 start_builtin_server,57 start_builtin_server,
62 start_haproxy_apache,58 start_haproxy_apache,
63 start_improv,
64 stop_agent,
65 stop_builtin_server,59 stop_builtin_server,
66 stop_haproxy_apache,60 stop_haproxy_apache,
67 stop_improv,
68 write_builtin_server_startup,61 write_builtin_server_startup,
69 write_gui_config,62 write_gui_config,
70)63)
@@ -410,30 +403,6 @@
410 self.assertIsNone(path)403 self.assertIsNone(path)
411404
412405
413class TestLegacyJuju(unittest.TestCase):
414
415 def setUp(self):
416 self.base_dir = tempfile.mkdtemp()
417 self.addCleanup(shutil.rmtree, self.base_dir)
418 # Monkey patch utils.CURRENT_DIR.
419 self.original_current_dir = utils.CURRENT_DIR
420 utils.CURRENT_DIR = tempfile.mkdtemp(dir=self.base_dir)
421
422 def tearDown(self):
423 # Restore the original utils.CURRENT_DIR.
424 utils.CURRENT_DIR = self.original_current_dir
425
426 def test_jujucore(self):
427 # If the agent file is found this is a juju-core environment.
428 agent_path = os.path.join(self.base_dir, 'agent.conf')
429 open(agent_path, 'w').close()
430 self.assertFalse(legacy_juju())
431
432 def test_pyjuju(self):
433 # If the agent file does not exist this is a PyJuju environment.
434 self.assertTrue(legacy_juju())
435
436
437def make_collection(attr, values):406def make_collection(attr, values):
438 """Create a collection of objects having an attribute named *attr*.407 """Create a collection of objects having an attribute named *attr*.
439408
@@ -632,22 +601,6 @@
632 self.assertEqual('0.1.0.xz', name)601 self.assertEqual('0.1.0.xz', name)
633602
634603
635class TestGetZookeeperAddress(unittest.TestCase):
636
637 def setUp(self):
638 self.zookeeper_address = 'example.com:2000'
639 contents = 'env JUJU_ZOOKEEPER="{}"\n'.format(self.zookeeper_address)
640 with tempfile.NamedTemporaryFile(delete=False) as agent_file:
641 agent_file.write(contents)
642 self.agent_file_path = agent_file.name
643 self.addCleanup(os.remove, self.agent_file_path)
644
645 def test_get_zookeeper_address(self):
646 # Ensure the Zookeeper address is correctly retreived.
647 address = get_zookeeper_address(self.agent_file_path)
648 self.assertEqual(self.zookeeper_address, address)
649
650
651class TestLogHook(unittest.TestCase):604class TestLogHook(unittest.TestCase):
652605
653 def setUp(self):606 def setUp(self):
@@ -853,9 +806,6 @@
853 def su(user):806 def su(user):
854 yield None807 yield None
855808
856 def get_zookeeper_address_mock(fp):
857 return self.fake_zk_address
858
859 self.files = {}809 self.files = {}
860 orig_rtf = utils.render_to_file810 orig_rtf = utils.render_to_file
861811
@@ -872,8 +822,6 @@
872 run=(utils.run, run),822 run=(utils.run, run),
873 unit_get=(utils.unit_get, noop),823 unit_get=(utils.unit_get, noop),
874 render_to_file=(utils.render_to_file, render_to_file),824 render_to_file=(utils.render_to_file, render_to_file),
875 get_zookeeper_address=(
876 utils.get_zookeeper_address, get_zookeeper_address_mock),
877 get_api_address=(utils.get_api_address, noop),825 get_api_address=(utils.get_api_address, noop),
878 APACHE_PORTS=(utils.APACHE_PORTS, 'PORTS_NOT_THERE'),826 APACHE_PORTS=(utils.APACHE_PORTS, 'PORTS_NOT_THERE'),
879 APACHE_SITE=(utils.APACHE_SITE, 'SITE_NOT_THERE'),827 APACHE_SITE=(utils.APACHE_SITE, 'SITE_NOT_THERE'),
@@ -891,39 +839,6 @@
891 setattr(utils, fn, fcns[0])839 setattr(utils, fn, fcns[0])
892 shutil.copy = self.shutil_copy840 shutil.copy = self.shutil_copy
893841
894 def test_start_improv(self):
895 staging_env = 'large'
896 start_improv(staging_env, self.ssl_cert_path,)
897 conf = self.files['juju-api-improv.conf']
898 self.assertTrue('--port %s' % API_PORT in conf)
899 self.assertTrue(staging_env + '.json' in conf)
900 self.assertTrue(self.ssl_cert_path in conf)
901 self.assertEqual(self.svc_ctl_call_count, 1)
902 self.assertEqual(self.service_names, ['juju-api-improv'])
903 self.assertEqual(self.actions, [charmhelpers.START])
904
905 def test_stop_improv(self):
906 stop_improv()
907 self.assertEqual(self.svc_ctl_call_count, 1)
908 self.assertEqual(self.service_names, ['juju-api-improv'])
909 self.assertEqual(self.actions, [charmhelpers.STOP])
910
911 def test_start_agent(self):
912 start_agent(self.ssl_cert_path, 'config')
913 conf = self.files['juju-api-agent.conf']
914 self.assertTrue('--port %s' % API_PORT in conf)
915 self.assertTrue('JUJU_ZOOKEEPER=%s' % self.fake_zk_address in conf)
916 self.assertTrue(self.ssl_cert_path in conf)
917 self.assertEqual(self.svc_ctl_call_count, 1)
918 self.assertEqual(self.service_names, ['juju-api-agent'])
919 self.assertEqual(self.actions, [charmhelpers.START])
920
921 def test_stop_agent(self):
922 stop_agent()
923 self.assertEqual(self.svc_ctl_call_count, 1)
924 self.assertEqual(self.service_names, ['juju-api-agent'])
925 self.assertEqual(self.actions, [charmhelpers.STOP])
926
927 def test_compute_build_dir(self):842 def test_compute_build_dir(self):
928 for (juju_gui_debug, serve_tests, result) in (843 for (juju_gui_debug, serve_tests, result) in (
929 (False, False, 'build-prod'),844 (False, False, 'build-prod'),
@@ -941,9 +856,7 @@
941 haproxy_conf = self.files['haproxy.cfg']856 haproxy_conf = self.files['haproxy.cfg']
942 self.assertIn('ca-base {}'.format(self.ssl_cert_path), haproxy_conf)857 self.assertIn('ca-base {}'.format(self.ssl_cert_path), haproxy_conf)
943 self.assertIn('crt-base {}'.format(self.ssl_cert_path), haproxy_conf)858 self.assertIn('crt-base {}'.format(self.ssl_cert_path), haproxy_conf)
944 self.assertIn('ws1 127.0.0.1:{}'.format(API_PORT), haproxy_conf)
945 self.assertIn('web1 127.0.0.1:{}'.format(WEB_PORT), haproxy_conf)859 self.assertIn('web1 127.0.0.1:{}'.format(WEB_PORT), haproxy_conf)
946 self.assertIn('ca-file {}'.format(JUJU_PEM), haproxy_conf)
947 self.assertIn('crt {}'.format(JUJU_PEM), haproxy_conf)860 self.assertIn('crt {}'.format(JUJU_PEM), haproxy_conf)
948 self.assertIn('redirect scheme https', haproxy_conf)861 self.assertIn('redirect scheme https', haproxy_conf)
949862
@@ -988,8 +901,9 @@
988 guiserver_conf = self.files['guiserver.conf']901 guiserver_conf = self.files['guiserver.conf']
989 self.assertIn('description "GUIServer"', guiserver_conf)902 self.assertIn('description "GUIServer"', guiserver_conf)
990 self.assertIn('--logging="info"', guiserver_conf)903 self.assertIn('--logging="info"', guiserver_conf)
991 self.assertIn('--apiurl="wss://127.0.0.1:8080/ws"', guiserver_conf)904 # The get_api_address is noop'd in these tests so the addr is None.
992 self.assertIn('--apiversion="python"', guiserver_conf)905 self.assertIn('--apiurl="wss://None"', guiserver_conf)
906 self.assertIn('--apiversion="go"', guiserver_conf)
993 self.assertIn(907 self.assertIn(
994 '--testsroot="{}/test/"'.format(JUJU_GUI_DIR), guiserver_conf)908 '--testsroot="{}/test/"'.format(JUJU_GUI_DIR), guiserver_conf)
995 self.assertIn('--insecure', guiserver_conf)909 self.assertIn('--insecure', guiserver_conf)
@@ -1029,13 +943,13 @@
1029943
1030 def test_write_gui_config(self):944 def test_write_gui_config(self):
1031 write_gui_config(945 write_gui_config(
1032 False, 'This is login help.', True, True, self.charmworld_url,946 False, 'This is login help.', True, self.charmworld_url,
1033 self.build_dir, config_js_path='config',947 self.build_dir, config_js_path='config',
1034 ga_key='UA-123456')948 ga_key='UA-123456')
1035 js_conf = self.files['config']949 js_conf = self.files['config']
1036 self.assertIn('consoleEnabled: false', js_conf)950 self.assertIn('consoleEnabled: false', js_conf)
1037 self.assertIn('user: "admin"', js_conf)951 self.assertIn('user: "user-admin"', js_conf)
1038 self.assertIn('password: "admin"', js_conf)952 self.assertIn('password: null', js_conf)
1039 self.assertIn('login_help: "This is login help."', js_conf)953 self.assertIn('login_help: "This is login help."', js_conf)
1040 self.assertIn('readOnly: true', js_conf)954 self.assertIn('readOnly: true', js_conf)
1041 self.assertIn("socket_url: 'wss://", js_conf)955 self.assertIn("socket_url: 'wss://", js_conf)
@@ -1046,38 +960,22 @@
1046960
1047 def test_write_gui_config_insecure(self):961 def test_write_gui_config_insecure(self):
1048 write_gui_config(962 write_gui_config(
1049 False, 'This is login help.', True, True, self.charmworld_url,963 False, 'This is login help.', True, self.charmworld_url,
1050 self.build_dir, secure=False, config_js_path='config')964 self.build_dir, secure=False, config_js_path='config')
1051 js_conf = self.files['config']965 js_conf = self.files['config']
1052 self.assertIn("socket_url: 'ws://", js_conf)966 self.assertIn("socket_url: 'ws://", js_conf)
1053 self.assertIn('socket_protocol: "ws"', js_conf)967 self.assertIn('socket_protocol: "ws"', js_conf)
1054968
1055 @mock.patch('utils.legacy_juju')969 def test_write_gui_config_default_sandbox_backend(self):
1056 def test_write_gui_config_default_python_password(self, mock_legacy_juju):970 write_gui_config(
1057 mock_legacy_juju.return_value = True971 False, 'This is login help.', True, self.charmworld_url,
1058 write_gui_config(
1059 False, 'This is login help.', True, True, self.charmworld_url,
1060 self.build_dir, config_js_path='config',
1061 password='kumquat')
1062 js_conf = self.files['config']
1063 self.assertIn('user: "admin"', js_conf)
1064 self.assertIn('password: "kumquat"', js_conf)
1065
1066 @mock.patch('utils.legacy_juju')
1067 def test_write_gui_config_default_sandbox_backend(self, mock_legacy_juju):
1068 mock_legacy_juju.return_value = True
1069 write_gui_config(
1070 False, 'This is login help.', True, True, self.charmworld_url,
1071 self.build_dir, config_js_path='config',972 self.build_dir, config_js_path='config',
1072 password='kumquat', sandbox=True)973 password='kumquat', sandbox=True)
1073 js_conf = self.files['config']974 js_conf = self.files['config']
1074 # Because this is sandbox, the apiBackend is always go, even though it975 # Because this is sandbox, the apiBackend is always go.
1075 # is legacy_juju.
1076 self.assertIn('apiBackend: "go"', js_conf)976 self.assertIn('apiBackend: "go"', js_conf)
1077977
1078 @mock.patch('utils.legacy_juju')978 def test_write_gui_config_default_go_password(self):
1079 def test_write_gui_config_default_go_password(self, mock_legacy_juju):
1080 mock_legacy_juju.return_value = False
1081 write_gui_config(979 write_gui_config(
1082 False, 'This is login help.', True, True, self.charmworld_url,980 False, 'This is login help.', True, True, self.charmworld_url,
1083 self.build_dir, config_js_path='config',981 self.build_dir, config_js_path='config',
@@ -1097,7 +995,7 @@
1097 self.build_dir, sandbox=True, config_js_path='config')995 self.build_dir, sandbox=True, config_js_path='config')
1098 js_conf = self.files['config']996 js_conf = self.files['config']
1099 self.assertIn('sandbox: true', js_conf)997 self.assertIn('sandbox: true', js_conf)
1100 self.assertIn('user: "admin"', js_conf)998 self.assertIn('user: "user-admin"', js_conf)
1101 self.assertIn('password: "admin"', js_conf)999 self.assertIn('password: "admin"', js_conf)
11021000
1103 def test_write_gui_config_with_button(self):1001 def test_write_gui_config_with_button(self):

Subscribers

People subscribed via source and target branches