Integration tests - running the tests

Initial setup for running the integration tests. A basic test is
included to ensure this works, although it will be rewritten to follow
the Page Object pattern. Thanks to Daniel Korn for the initial test.

https://wiki.openstack.org/wiki/Horizon/Testing/UI

Implements blueprint: selenium-integration-testing

Change-Id: Id5b62cdeac5295667a3922f7bed1db3c7617f841
This commit is contained in:
Julie Pichon 2013-01-10 14:13:59 +00:00
parent 990f151cdc
commit b4b0e1a887
11 changed files with 245 additions and 1 deletions

View File

@ -70,6 +70,21 @@ To run just the `WorkflowsTests.test_workflow_view` test method::
./run_tests.sh horizon.test.tests.workflows:WorkflowsTests.test_workflow_view
Running the integration tests
-----------------------------
The Horizon integration tests treat Horizon as a black box, and similar
to Tempest must be run against an existing OpenStack system. These
tests are not run by default.
#. Update the configuration file
`openstack_dashboard/test/integration_tests/horizon.conf` as
required (the format is similar to the Tempest configuration file).
#. Run the tests with the following command: ::
$ ./run_tests.sh --integration
Using Dashboard and Panel Templates
===================================

View File

@ -0,0 +1,22 @@
Horizon Integration Tests
=========================
Horizon's integration tests treat Horizon as a black box.
Running the integration tests
-----------------------------
#. Set up an OpenStack server
#. Update the configuration file at `horizon.conf`
#. Run the tests. ::
$ ./run_tests.sh --integration
More information
----------------
https://wiki.openstack.org/wiki/Horizon/Testing/UI
https://wiki.mozilla.org/QA/Execution/Web_Testing/Docs/Automation/StyleGuide#Page_Objects

View File

@ -0,0 +1,66 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import os
from oslo.config import cfg
DashboardGroup = [
cfg.StrOpt('dashboard_url',
default='http://localhost/',
help="Where the dashboard can be found"),
cfg.StrOpt('login_url',
default='http://localhost/auth/login/',
help="Login page for the dashboard"),
cfg.IntOpt('page_timeout',
default=10,
help="Timeout in seconds"),
]
IdentityGroup = [
cfg.StrOpt('username',
default='demo',
help="Username to use for non-admin API requests."),
cfg.StrOpt('password',
default='pass',
help="API key to use when authenticating.",
secret=True),
cfg.StrOpt('admin_username',
default='admin',
help="Administrative Username to use for admin API "
"requests."),
cfg.StrOpt('admin_password',
default='pass',
help="API key to use when authenticating as admin.",
secret=True),
]
def _get_config_files():
conf_dir = os.path.join(
os.path.abspath(os.path.dirname(os.path.dirname(__file__))),
'integration_tests')
conf_file = os.environ.get('HORIZON_INTEGRATION_TESTS_CONFIG_FILE',
"%s/horizon.conf" % conf_dir)
return [conf_file]
def get_config():
cfg.CONF([], project='horizon', default_config_files=_get_config_files())
cfg.CONF.register_opts(DashboardGroup, group="dashboard")
cfg.CONF.register_opts(IdentityGroup, group="identity")
return cfg.CONF

View File

@ -0,0 +1,43 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import os
import selenium
from selenium.webdriver.support import ui
import testtools
from openstack_dashboard.test.integration_tests import config
class BaseTestCase(testtools.TestCase):
def setUp(self):
if os.environ.get('INTEGRATION_TESTS', False):
self.driver = selenium.webdriver.Firefox()
self.conf = config.get_config()
else:
msg = "The INTEGRATION_TESTS env variable is not set."
raise self.skipException(msg)
super(BaseTestCase, self).setUp()
def tearDown(self):
if os.environ.get('INTEGRATION_TESTS', False):
self.driver.close()
super(BaseTestCase, self).tearDown()
def wait_for_title(self):
timeout = self.conf.dashboard.page_timeout
ui.WebDriverWait(self.driver, timeout).until(lambda d:
self.driver.title)

View File

@ -0,0 +1,28 @@
#
# Configuration filed based on Tempest's tempest.conf.sample
#
[dashboard]
# Where the dashboard can be found (string value)
dashboard_url=http://localhost/
# Login page for the dashboard (string value)
login_url=http://localhost/auth/login/
# Timeout in seconds to wait for a page to become available
# (integer value)
page_timeout=10
[identity]
# Username to use for non-admin API requests. (string value)
username=demo
# API key to use when authenticating. (string value)
password=pass
# Administrative Username to use for admin API requests.
# (string value)
admin_username=admin
# API key to use when authenticating as admin. (string value)
admin_password=pass

View File

@ -0,0 +1,43 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import selenium.webdriver.common.keys as keys
from openstack_dashboard.test.integration_tests import helpers
class TestLoginPage(helpers.BaseTestCase):
"""This is a basic scenario test:
* checks that the login page is available
* logs in as a regular user
* checks that the user home page loads without error
FIXME(jpichon): This test will be rewritten using the Page Objects
pattern, which is much more maintainable.
"""
def test_login(self):
self.driver.get(self.conf.dashboard.login_url)
self.assertIn("Login", self.driver.title)
username = self.driver.find_element_by_name("username")
password = self.driver.find_element_by_name("password")
username.send_keys(self.conf.identity.username)
password.send_keys(self.conf.identity.password)
username.send_keys(keys.Keys.RETURN)
self.wait_for_title()
self.assertIn("Instance Overview", self.driver.title)

View File

@ -6,7 +6,7 @@ set -o errexit
# Increment me any time the environment should be rebuilt.
# This includes dependency changes, directory renames, etc.
# Simple integer sequence: 1, 2, 3...
environment_version=41
environment_version=42
#--------------------------------------------------------#
function usage {
@ -32,6 +32,8 @@ function usage {
echo " Implies -V if -N is not set."
echo " --only-selenium Run only the Selenium unit tests"
echo " --with-selenium Run unit tests including Selenium tests"
echo " --integration Run the integration tests (requires a running "
echo " OpenStack environment)"
echo " --runserver Run the Django development server for"
echo " openstack_dashboard in the virtual"
echo " environment."
@ -71,6 +73,7 @@ restore_env=0
runserver=0
only_selenium=0
with_selenium=0
integration=0
testopts=""
testargs=""
with_coverage=0
@ -104,6 +107,7 @@ function process_option {
--compilemessages) compilemessages=1;;
--only-selenium) only_selenium=1;;
--with-selenium) with_selenium=1;;
--integration) integration=1;;
--docs) just_docs=1;;
--runserver) runserver=1;;
--backup-environment) backup_env=1;;
@ -351,6 +355,14 @@ function run_tests_all {
exit $TEST_RESULT
}
function run_integration_tests {
export INTEGRATION_TESTS=1
echo "Running Horizon integration tests..."
${command_wrapper} nosetests openstack_dashboard/test/integration_tests/tests
exit 0
}
function run_makemessages {
OPTS="-l en --no-obsolete"
DASHBOARD_OPTS="--extension=html,txt,csv --ignore=openstack/common/*"
@ -465,6 +477,12 @@ if [ $just_tabs -eq 1 ]; then
exit $?
fi
# Integration tests
if [ $integration -eq 1 ]; then
run_integration_tests
exit $?
fi
# Django development server
if [ $runserver -eq 1 ]; then
run_server

View File

@ -15,3 +15,4 @@ sphinx>=1.1.2,<1.2
# for bug 1091333, remove after sphinx >1.1.3 is released.
docutils==0.9.1
oslo.sphinx
testtools>=0.9.34

View File

@ -30,6 +30,14 @@ basepython = python2.7
commands = pip install django==1.4
/bin/bash run_tests.sh -N --no-pep8
[testenv:py27integration]
basepython = python2.7
commands = /bin/bash run_tests.sh -N --integration
[testenv:py26integration]
basepython = python2.6
commands = /bin/bash run_tests.sh -N --integration
[tox:jenkins]
downloadcache = ~/cache/pip