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
=== modified file 'HACKING'
--- HACKING 2013-09-24 15:38:01 +0000
+++ HACKING 2013-12-10 14:54:36 +0000
@@ -60,7 +60,7 @@
60 sudo apt-get update60 sudo apt-get update
61 sudo apt-get install nodejs imagemagick python-sphinx python-yaml \61 sudo apt-get install nodejs imagemagick python-sphinx python-yaml \
62 python-tz python-virtualenv python-shelltoolbox python-selenium \62 python-tz python-virtualenv python-shelltoolbox python-selenium \
63 python-tornado python-gflags g++63 python-tornado python-gflags g++ xvfb
6464
65See :ref:`Browser Testing <browser-testing>` if you are curious about the65See :ref:`Browser Testing <browser-testing>` if you are curious about the
66reason for ``python-shelltoolbox`` and ``python-selenium``.66reason for ``python-shelltoolbox`` and ``python-selenium``.
6767
=== modified file 'Makefile'
--- Makefile 2013-10-31 19:12:42 +0000
+++ Makefile 2013-12-10 14:54:36 +0000
@@ -405,7 +405,7 @@
405prep: beautify lint405prep: beautify lint
406406
407# XXX bac: the order of test-debug and test-prod seems to affect the execution407# XXX bac: the order of test-debug and test-prod seems to affect the execution
408# of this target when called by lbox. Please do note change.408# of this target when called by lbox. Please do not change.
409check: lint test-debug test-prod test-misc docs409check: lint test-debug test-prod test-misc docs
410410
411test/extracted_startup_code: app/index.html411test/extracted_startup_code: app/index.html
@@ -426,6 +426,7 @@
426test-prep: test/test_startup.js426test-prep: test/test_startup.js
427427
428test-filtering:428test-filtering:
429 # Ensure no tests are disabled.
429 ./bin/test-filtering430 ./bin/test-filtering
430431
431test-debug: build-debug test-prep432test-debug: build-debug test-prep
@@ -441,10 +442,34 @@
441 ./test-server.sh prod true442 ./test-server.sh prod true
442443
443test-misc:444test-misc:
444 PYTHONPATH=lib python test/test_websocketreplay.py445 PYTHONPATH=lib virtualenv/bin/python test/test_websocketreplay.py
445 PYTHONPATH=lib python test/test_browser.py446 PYTHONPATH=lib virtualenv/bin/python test/test_browser.py
446 PYTHONPATH=lib python test/test_deploy_charm_for_testing.py447 PYTHONPATH=lib virtualenv/bin/python \
447 PYTHONPATH=bin python test/test_http_server.py448 test/test_deploy_charm_for_testing.py
449 PYTHONPATH=bin virtualenv/bin/python test/test_http_server.py
450
451test-browser: build-devel
452 # Tests that run in the browser. A server has to be running on
453 # localhost:8888 for this to work.
454 # Make sure no display :34 exists before we start one.
455 DISPLAY=:34 xdpyinfo > /dev/null || exit 1
456 # Start Xvfb as a background process, capturing its PID.
457 $(eval xvfb_pid := $(shell Xvfb :34 2> /dev/null & echo $$!))
458 # Wait for the display to be accessible.
459 until (DISPLAY=:34 xdpyinfo > /dev/null); \
460 do \
461 echo "Waiting for Xvfb"; \
462 sleep 1; \
463 done
464 # Run the tests inside the virtual frame buffer, capturing the result
465 # of the test run.
466 $(eval result := $(shell \
467 DISPLAY=:34 virtualenv/bin/python test/test_browser.py; \
468 echo $$?))
469 # Stop the background processes.
470 kill $(xvfb_pid)
471 # Report the result of the test run.
472 exit $(result)
448473
449test:474test:
450 @echo "Deprecated. Please run either 'make test-prod' or 'make"475 @echo "Deprecated. Please run either 'make test-prod' or 'make"
451476
=== modified file 'test/browser.py'
--- test/browser.py 2013-09-19 14:31:53 +0000
+++ test/browser.py 2013-12-10 14:54:36 +0000
@@ -211,7 +211,6 @@
211 capabilities = get_capabilities(name)211 capabilities = get_capabilities(name)
212 driver = make_local_driver(name, capabilities)212 driver = make_local_driver(name, capabilities)
213 cls.remote_driver = False213 cls.remote_driver = False
214 printerr('* Platform: local {}'.format(get_platform(driver)))
215 else:214 else:
216 # Otherwise, set up a Saucelabs remote driver.215 # Otherwise, set up a Saucelabs remote driver.
217 capabilities = get_capabilities(browser_name)216 capabilities = get_capabilities(browser_name)
@@ -232,7 +231,7 @@
232 driver.implicitly_wait(20)231 driver.implicitly_wait(20)
233 driver.set_script_timeout(30)232 driver.set_script_timeout(30)
234 # We want to tell saucelabs when all the tests are done.233 # We want to tell saucelabs when all the tests are done.
235 cls.app_url = os.environ['APP_URL']234 cls.app_url = os.environ.get('APP_URL', 'http://localhost:8888')
236 cls.driver = driver235 cls.driver = driver
237236
238 @classmethod237 @classmethod
239238
=== added file 'test/test_browser.py'
--- test/test_browser.py 1970-01-01 00:00:00 +0000
+++ test/test_browser.py 2013-12-10 14:54:36 +0000
@@ -0,0 +1,95 @@
1# This file is part of the Juju GUI, which lets users view and manage Juju
2# environments within a graphical interface (https://launchpad.net/juju-gui).
3# Copyright (C) 2012-2013 Canonical Ltd.
4#
5# This program is free software: you can redistribute it and/or modify it under
6# the terms of the GNU Affero General Public License version 3, as published by
7# the Free Software Foundation.
8#
9# This program is distributed in the hope that it will be useful, but WITHOUT
10# ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
11# SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12# Affero General Public License for more details.
13#
14# You should have received a copy of the GNU Affero General Public License
15# along with this program. If not, see <http://www.gnu.org/licenses/>.
16
17from __future__ import print_function
18import unittest
19
20from selenium.common import exceptions
21
22import browser
23
24
25class TestBasics(browser.TestCase):
26
27 def test_title(self):
28 self.load()
29 self.assertTrue('Juju Admin' in self.driver.title)
30
31 def test_environment_name(self):
32 self.load()
33 self.handle_browser_warning()
34 # The next line attempts to work around an IE 10 fragility.
35 # The symptom we are trying to avoid is an error as follows:
36 # "JavaScript error (WARNING: The server did not provide any stacktrace
37 # information)""
38 self.wait_for_css_selector('svg')
39 body = self.driver.find_element_by_xpath('//body')
40 self.assertTrue('Environment on ' in body.text)
41
42 def test_environment_connection(self):
43 # The GUI connects to the API backend.
44 self.load()
45 self.handle_browser_warning()
46 # The next line attempts to work around an IE 10 fragility.
47 # The symptom we are trying to avoid is an error as follows:
48 # "JavaScript error (WARNING: The server did not provide any stacktrace
49 # information)""
50 self.wait_for_css_selector('svg')
51 script = 'return app && app.env && app.env.get("connected");'
52 self.wait_for_script(script, 'Environment not connected.')
53
54
55class TestAuthentication(browser.TestCase):
56
57 def is_authenticated(self):
58 """Return True if the user is authenticated, False otherwise."""
59 script = 'return app.env.userIsAuthenticated;'
60 return self.driver.execute_script(script)
61
62 def process_path(self, path):
63 """Load the given path, log out, log in again."""
64 self.load(path)
65 self.handle_browser_warning()
66 self.handle_login()
67 # Check the initial URL.
68 self.wait_for_path(path, error='Not in the initial path.')
69 self.assertTrue(self.is_authenticated(), 'initial state')
70 # Logout.
71 self.logout()
72 # Check redirection to /login/.
73 self.wait_for_path('/login/', error='Redirection to /login/ failed.')
74 self.assertFalse(self.is_authenticated(), 'after logging out')
75 # Login.
76 self.login()
77 # Ensure we are in the initial URL again.
78 self.wait_for_path(path, error='Post login redirection failed.')
79 self.assertTrue(self.is_authenticated(), 'after logging in again')
80
81 def test_root_page(self):
82 # It is possible to login to and logout from the root page.
83 self.process_path('/')
84
85 def test_service_page(self):
86 # It is possible to login to and logout from the service detail view.
87 self.process_path('/:gui:/service/haproxy/')
88
89 def test_unit_page(self):
90 # It is possible to login to and logout from the unit detail view.
91 self.process_path('/:gui:/unit/haproxy-0/')
92
93if __name__ == '__main__':
94 browser.browser_name = 'local-firefox'
95 unittest.main()
096
=== renamed file 'test/test_browser.py' => 'test/test_browser_errors.py'
=== modified file 'test/test_charm_running.py'
--- test/test_charm_running.py 2013-10-29 22:30:57 +0000
+++ test/test_charm_running.py 2013-12-10 14:54:36 +0000
@@ -22,34 +22,7 @@
22import browser22import browser
2323
2424
25class TestBasics(browser.TestCase):25class TestTests(browser.TestCase):
26
27 def test_title(self):
28 self.load()
29 self.assertTrue('Juju Admin' in self.driver.title)
30
31 def test_environment_name(self):
32 self.load()
33 self.handle_browser_warning()
34 # The next line attempts to work around an IE 10 fragility.
35 # The symptom we are trying to avoid is an error as follows:
36 # "JavaScript error (WARNING: The server did not provide any stacktrace
37 # information)""
38 self.wait_for_css_selector('svg')
39 body = self.driver.find_element_by_xpath('//body')
40 self.assertTrue('Environment on ' in body.text)
41
42 def test_environment_connection(self):
43 # The GUI connects to the API backend.
44 self.load()
45 self.handle_browser_warning()
46 # The next line attempts to work around an IE 10 fragility.
47 # The symptom we are trying to avoid is an error as follows:
48 # "JavaScript error (WARNING: The server did not provide any stacktrace
49 # information)""
50 self.wait_for_css_selector('svg')
51 script = 'return app && app.env && app.env.get("connected");'
52 self.wait_for_script(script, 'Environment not connected.')
5326
54 def test_gui_unit_tests(self):27 def test_gui_unit_tests(self):
55 # Ensure Juju GUI unit tests pass.28 # Ensure Juju GUI unit tests pass.
@@ -216,6 +189,7 @@
216 # The service name is arbitrary, and connected to the charm name only189 # The service name is arbitrary, and connected to the charm name only
217 # by default/convention. Since charms are deployed using the default190 # by default/convention. Since charms are deployed using the default
218 # name, it is safe to reuse one of the service names here.191 # name, it is safe to reuse one of the service names here.
192 self.deploy('mysql')
219 service = self.get_service_names().pop()193 service = self.get_service_names().pop()
220 self.deploy(service)194 self.deploy(service)
221 notifications = self.get_notifications()195 notifications = self.get_notifications()
@@ -274,45 +248,6 @@
274 self.assertEqual('haproxy/0', unit_name)248 self.assertEqual('haproxy/0', unit_name)
275249
276250
277class TestAuthentication(browser.TestCase):
278
279 def is_authenticated(self):
280 """Return True if the user is authenticated, False otherwise."""
281 script = 'return app.env.userIsAuthenticated;'
282 return self.driver.execute_script(script)
283
284 def process_path(self, path):
285 """Load the given path, log out, log in again."""
286 self.load(path)
287 self.handle_browser_warning()
288 self.handle_login()
289 # Check the initial URL.
290 self.wait_for_path(path, error='Not in the initial path.')
291 self.assertTrue(self.is_authenticated(), 'initial state')
292 # Logout.
293 self.logout()
294 # Check redirection to /login/.
295 self.wait_for_path('/login/', error='Redirection to /login/ failed.')
296 self.assertFalse(self.is_authenticated(), 'after logging out')
297 # Login.
298 self.login()
299 # Ensure we are in the initial URL again.
300 self.wait_for_path(path, error='Post login redirection failed.')
301 self.assertTrue(self.is_authenticated(), 'after logging in again')
302
303 def test_root_page(self):
304 # It is possible to login to and logout from the root page.
305 self.process_path('/')
306
307 def test_service_page(self):
308 # It is possible to login to and logout from the service detail view.
309 self.process_path('/:gui:/service/haproxy/')
310
311 def test_unit_page(self):
312 # It is possible to login to and logout from the unit detail view.
313 self.process_path('/:gui:/unit/haproxy-0/')
314
315
316class TestSandbox(browser.TestCase, DeployTestMixin):251class TestSandbox(browser.TestCase, DeployTestMixin):
317252
318 @classmethod253 @classmethod
319254
=== modified file 'test/test_deploy_charm_for_testing.py'
--- test/test_deploy_charm_for_testing.py 2013-08-06 13:21:03 +0000
+++ test/test_deploy_charm_for_testing.py 2013-12-10 14:54:36 +0000
@@ -54,6 +54,7 @@
5454
55 def sleep(seconds):55 def sleep(seconds):
56 raise ZZZZ56 raise ZZZZ
57
57 with self.assertRaises(ZZZZ):58 with self.assertRaises(ZZZZ):
58 wait_for_service(get_service_state, sleep)59 wait_for_service(get_service_state, sleep)
5960

Subscribers

People subscribed via source and target branches