Merge lp:~benji/juju-gui/sandboxify-tests into lp:juju-gui/experimental

Proposed by Benji York
Status: Work in progress
Proposed branch: lp:~benji/juju-gui/sandboxify-tests
Merge into: lp:juju-gui/experimental
Diff against target: 299 lines (+130/-75)
6 files modified
HACKING (+1/-1)
Makefile (+30/-5)
test/browser.py (+1/-2)
test/test_browser.py (+95/-0)
test/test_charm_running.py (+2/-67)
test/test_deploy_charm_for_testing.py (+1/-0)
To merge this branch: bzr merge lp:~benji/juju-gui/sandboxify-tests
Reviewer Review Type Date Requested Status
Juju GUI Hackers Pending
Review via email: mp+198410@code.launchpad.net

Description of the change

Add the ability to run local browser tests.

Some existing tests were moved from charm-requiring tests to local browser
tests.

https://codereview.appspot.com/40190043/

To post a comment you must log in.
Revision history for this message
Benji York (benji) wrote :

Reviewers: mp+198410_code.launchpad.net,

Message:
Pre-review comments.

https://codereview.appspot.com/40190043/diff/1/Makefile
File Makefile (right):

https://codereview.appspot.com/40190043/diff/1/Makefile#newcode408
Makefile:408: # of this target when called by lbox. Please do not
change.
Typo fix, I think.

https://codereview.appspot.com/40190043/diff/1/Makefile#newcode445
Makefile:445: PYTHONPATH=lib virtualenv/bin/python
test/test_websocketreplay.py
We were using the system Python here.

https://codereview.appspot.com/40190043/diff/1/Makefile#newcode458
Makefile:458: # Wait for the display to be accessible.
Avoid racing with Xvfb to start up.

https://codereview.appspot.com/40190043/diff/1/test/browser.py
File test/browser.py (left):

https://codereview.appspot.com/40190043/diff/1/test/browser.py#oldcode214
test/browser.py:214: printerr('* Platform: local
{}'.format(get_platform(driver)))
This was annoying and non-useful.

https://codereview.appspot.com/40190043/diff/1/test/test_browser.py
File test/test_browser.py (right):

https://codereview.appspot.com/40190043/diff/1/test/test_browser.py#newcode1
test/test_browser.py:1: # This file is part of the Juju GUI, which lets
users view and manage Juju
These tests were moved here, unchanged.

https://codereview.appspot.com/40190043/diff/1/test/test_charm_running.py
File test/test_charm_running.py (left):

https://codereview.appspot.com/40190043/diff/1/test/test_charm_running.py#oldcode25
test/test_charm_running.py:25: class TestBasics(browser.TestCase):
These were moved elsewhere.

https://codereview.appspot.com/40190043/diff/1/test/test_charm_running.py#oldcode277
test/test_charm_running.py:277: class
TestAuthentication(browser.TestCase):
Moved.

https://codereview.appspot.com/40190043/diff/1/test/test_charm_running.py
File test/test_charm_running.py (right):

https://codereview.appspot.com/40190043/diff/1/test/test_charm_running.py#newcode192
test/test_charm_running.py:192: self.deploy('mysql')
This change made the tests start working when the GUI is not run from a
charm (as in the sandbox).

Description:
Add the ability to run local browser tests.

Some existing tests were moved from charm-requiring tests to local
browser
tests.

https://code.launchpad.net/~benji/juju-gui/sandboxify-tests/+merge/198410

(do not edit description out of merge proposal)

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

Affected files (+131, -74 lines):
   M HACKING
   M Makefile
   A [revision details]
   M test/browser.py
   A test/test_browser.py
   M test/test_browser_errors.py
   M test/test_charm_running.py
   M test/test_deploy_charm_for_testing.py

Unmerged revisions

1224. By Benji York

words

1223. By Benji York

reinstate tests

1222. By Benji York

abandon hope of starting the server automatically

1221. By Benji York

checkpoint

1220. By Benji York

merge from trunk

1219. By Benji York

checkpoint

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'HACKING'
2--- HACKING 2013-09-24 15:38:01 +0000
3+++ HACKING 2013-12-10 14:54:36 +0000
4@@ -60,7 +60,7 @@
5 sudo apt-get update
6 sudo apt-get install nodejs imagemagick python-sphinx python-yaml \
7 python-tz python-virtualenv python-shelltoolbox python-selenium \
8- python-tornado python-gflags g++
9+ python-tornado python-gflags g++ xvfb
10
11 See :ref:`Browser Testing <browser-testing>` if you are curious about the
12 reason for ``python-shelltoolbox`` and ``python-selenium``.
13
14=== modified file 'Makefile'
15--- Makefile 2013-10-31 19:12:42 +0000
16+++ Makefile 2013-12-10 14:54:36 +0000
17@@ -405,7 +405,7 @@
18 prep: beautify lint
19
20 # XXX bac: the order of test-debug and test-prod seems to affect the execution
21-# of this target when called by lbox. Please do note change.
22+# of this target when called by lbox. Please do not change.
23 check: lint test-debug test-prod test-misc docs
24
25 test/extracted_startup_code: app/index.html
26@@ -426,6 +426,7 @@
27 test-prep: test/test_startup.js
28
29 test-filtering:
30+ # Ensure no tests are disabled.
31 ./bin/test-filtering
32
33 test-debug: build-debug test-prep
34@@ -441,10 +442,34 @@
35 ./test-server.sh prod true
36
37 test-misc:
38- PYTHONPATH=lib python test/test_websocketreplay.py
39- PYTHONPATH=lib python test/test_browser.py
40- PYTHONPATH=lib python test/test_deploy_charm_for_testing.py
41- PYTHONPATH=bin python test/test_http_server.py
42+ PYTHONPATH=lib virtualenv/bin/python test/test_websocketreplay.py
43+ PYTHONPATH=lib virtualenv/bin/python test/test_browser.py
44+ PYTHONPATH=lib virtualenv/bin/python \
45+ test/test_deploy_charm_for_testing.py
46+ PYTHONPATH=bin virtualenv/bin/python test/test_http_server.py
47+
48+test-browser: build-devel
49+ # Tests that run in the browser. A server has to be running on
50+ # localhost:8888 for this to work.
51+ # Make sure no display :34 exists before we start one.
52+ DISPLAY=:34 xdpyinfo > /dev/null || exit 1
53+ # Start Xvfb as a background process, capturing its PID.
54+ $(eval xvfb_pid := $(shell Xvfb :34 2> /dev/null & echo $$!))
55+ # Wait for the display to be accessible.
56+ until (DISPLAY=:34 xdpyinfo > /dev/null); \
57+ do \
58+ echo "Waiting for Xvfb"; \
59+ sleep 1; \
60+ done
61+ # Run the tests inside the virtual frame buffer, capturing the result
62+ # of the test run.
63+ $(eval result := $(shell \
64+ DISPLAY=:34 virtualenv/bin/python test/test_browser.py; \
65+ echo $$?))
66+ # Stop the background processes.
67+ kill $(xvfb_pid)
68+ # Report the result of the test run.
69+ exit $(result)
70
71 test:
72 @echo "Deprecated. Please run either 'make test-prod' or 'make"
73
74=== modified file 'test/browser.py'
75--- test/browser.py 2013-09-19 14:31:53 +0000
76+++ test/browser.py 2013-12-10 14:54:36 +0000
77@@ -211,7 +211,6 @@
78 capabilities = get_capabilities(name)
79 driver = make_local_driver(name, capabilities)
80 cls.remote_driver = False
81- printerr('* Platform: local {}'.format(get_platform(driver)))
82 else:
83 # Otherwise, set up a Saucelabs remote driver.
84 capabilities = get_capabilities(browser_name)
85@@ -232,7 +231,7 @@
86 driver.implicitly_wait(20)
87 driver.set_script_timeout(30)
88 # We want to tell saucelabs when all the tests are done.
89- cls.app_url = os.environ['APP_URL']
90+ cls.app_url = os.environ.get('APP_URL', 'http://localhost:8888')
91 cls.driver = driver
92
93 @classmethod
94
95=== added file 'test/test_browser.py'
96--- test/test_browser.py 1970-01-01 00:00:00 +0000
97+++ test/test_browser.py 2013-12-10 14:54:36 +0000
98@@ -0,0 +1,95 @@
99+# This file is part of the Juju GUI, which lets users view and manage Juju
100+# environments within a graphical interface (https://launchpad.net/juju-gui).
101+# Copyright (C) 2012-2013 Canonical Ltd.
102+#
103+# This program is free software: you can redistribute it and/or modify it under
104+# the terms of the GNU Affero General Public License version 3, as published by
105+# the Free Software Foundation.
106+#
107+# This program is distributed in the hope that it will be useful, but WITHOUT
108+# ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
109+# SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
110+# Affero General Public License for more details.
111+#
112+# You should have received a copy of the GNU Affero General Public License
113+# along with this program. If not, see <http://www.gnu.org/licenses/>.
114+
115+from __future__ import print_function
116+import unittest
117+
118+from selenium.common import exceptions
119+
120+import browser
121+
122+
123+class TestBasics(browser.TestCase):
124+
125+ def test_title(self):
126+ self.load()
127+ self.assertTrue('Juju Admin' in self.driver.title)
128+
129+ def test_environment_name(self):
130+ self.load()
131+ self.handle_browser_warning()
132+ # The next line attempts to work around an IE 10 fragility.
133+ # The symptom we are trying to avoid is an error as follows:
134+ # "JavaScript error (WARNING: The server did not provide any stacktrace
135+ # information)""
136+ self.wait_for_css_selector('svg')
137+ body = self.driver.find_element_by_xpath('//body')
138+ self.assertTrue('Environment on ' in body.text)
139+
140+ def test_environment_connection(self):
141+ # The GUI connects to the API backend.
142+ self.load()
143+ self.handle_browser_warning()
144+ # The next line attempts to work around an IE 10 fragility.
145+ # The symptom we are trying to avoid is an error as follows:
146+ # "JavaScript error (WARNING: The server did not provide any stacktrace
147+ # information)""
148+ self.wait_for_css_selector('svg')
149+ script = 'return app && app.env && app.env.get("connected");'
150+ self.wait_for_script(script, 'Environment not connected.')
151+
152+
153+class TestAuthentication(browser.TestCase):
154+
155+ def is_authenticated(self):
156+ """Return True if the user is authenticated, False otherwise."""
157+ script = 'return app.env.userIsAuthenticated;'
158+ return self.driver.execute_script(script)
159+
160+ def process_path(self, path):
161+ """Load the given path, log out, log in again."""
162+ self.load(path)
163+ self.handle_browser_warning()
164+ self.handle_login()
165+ # Check the initial URL.
166+ self.wait_for_path(path, error='Not in the initial path.')
167+ self.assertTrue(self.is_authenticated(), 'initial state')
168+ # Logout.
169+ self.logout()
170+ # Check redirection to /login/.
171+ self.wait_for_path('/login/', error='Redirection to /login/ failed.')
172+ self.assertFalse(self.is_authenticated(), 'after logging out')
173+ # Login.
174+ self.login()
175+ # Ensure we are in the initial URL again.
176+ self.wait_for_path(path, error='Post login redirection failed.')
177+ self.assertTrue(self.is_authenticated(), 'after logging in again')
178+
179+ def test_root_page(self):
180+ # It is possible to login to and logout from the root page.
181+ self.process_path('/')
182+
183+ def test_service_page(self):
184+ # It is possible to login to and logout from the service detail view.
185+ self.process_path('/:gui:/service/haproxy/')
186+
187+ def test_unit_page(self):
188+ # It is possible to login to and logout from the unit detail view.
189+ self.process_path('/:gui:/unit/haproxy-0/')
190+
191+if __name__ == '__main__':
192+ browser.browser_name = 'local-firefox'
193+ unittest.main()
194
195=== renamed file 'test/test_browser.py' => 'test/test_browser_errors.py'
196=== modified file 'test/test_charm_running.py'
197--- test/test_charm_running.py 2013-10-29 22:30:57 +0000
198+++ test/test_charm_running.py 2013-12-10 14:54:36 +0000
199@@ -22,34 +22,7 @@
200 import browser
201
202
203-class TestBasics(browser.TestCase):
204-
205- def test_title(self):
206- self.load()
207- self.assertTrue('Juju Admin' in self.driver.title)
208-
209- def test_environment_name(self):
210- self.load()
211- self.handle_browser_warning()
212- # The next line attempts to work around an IE 10 fragility.
213- # The symptom we are trying to avoid is an error as follows:
214- # "JavaScript error (WARNING: The server did not provide any stacktrace
215- # information)""
216- self.wait_for_css_selector('svg')
217- body = self.driver.find_element_by_xpath('//body')
218- self.assertTrue('Environment on ' in body.text)
219-
220- def test_environment_connection(self):
221- # The GUI connects to the API backend.
222- self.load()
223- self.handle_browser_warning()
224- # The next line attempts to work around an IE 10 fragility.
225- # The symptom we are trying to avoid is an error as follows:
226- # "JavaScript error (WARNING: The server did not provide any stacktrace
227- # information)""
228- self.wait_for_css_selector('svg')
229- script = 'return app && app.env && app.env.get("connected");'
230- self.wait_for_script(script, 'Environment not connected.')
231+class TestTests(browser.TestCase):
232
233 def test_gui_unit_tests(self):
234 # Ensure Juju GUI unit tests pass.
235@@ -216,6 +189,7 @@
236 # The service name is arbitrary, and connected to the charm name only
237 # by default/convention. Since charms are deployed using the default
238 # name, it is safe to reuse one of the service names here.
239+ self.deploy('mysql')
240 service = self.get_service_names().pop()
241 self.deploy(service)
242 notifications = self.get_notifications()
243@@ -274,45 +248,6 @@
244 self.assertEqual('haproxy/0', unit_name)
245
246
247-class TestAuthentication(browser.TestCase):
248-
249- def is_authenticated(self):
250- """Return True if the user is authenticated, False otherwise."""
251- script = 'return app.env.userIsAuthenticated;'
252- return self.driver.execute_script(script)
253-
254- def process_path(self, path):
255- """Load the given path, log out, log in again."""
256- self.load(path)
257- self.handle_browser_warning()
258- self.handle_login()
259- # Check the initial URL.
260- self.wait_for_path(path, error='Not in the initial path.')
261- self.assertTrue(self.is_authenticated(), 'initial state')
262- # Logout.
263- self.logout()
264- # Check redirection to /login/.
265- self.wait_for_path('/login/', error='Redirection to /login/ failed.')
266- self.assertFalse(self.is_authenticated(), 'after logging out')
267- # Login.
268- self.login()
269- # Ensure we are in the initial URL again.
270- self.wait_for_path(path, error='Post login redirection failed.')
271- self.assertTrue(self.is_authenticated(), 'after logging in again')
272-
273- def test_root_page(self):
274- # It is possible to login to and logout from the root page.
275- self.process_path('/')
276-
277- def test_service_page(self):
278- # It is possible to login to and logout from the service detail view.
279- self.process_path('/:gui:/service/haproxy/')
280-
281- def test_unit_page(self):
282- # It is possible to login to and logout from the unit detail view.
283- self.process_path('/:gui:/unit/haproxy-0/')
284-
285-
286 class TestSandbox(browser.TestCase, DeployTestMixin):
287
288 @classmethod
289
290=== modified file 'test/test_deploy_charm_for_testing.py'
291--- test/test_deploy_charm_for_testing.py 2013-08-06 13:21:03 +0000
292+++ test/test_deploy_charm_for_testing.py 2013-12-10 14:54:36 +0000
293@@ -54,6 +54,7 @@
294
295 def sleep(seconds):
296 raise ZZZZ
297+
298 with self.assertRaises(ZZZZ):
299 wait_for_service(get_service_state, sleep)
300

Subscribers

People subscribed via source and target branches