Merge "Basic starter scenario for testing the dashboard"
diff --git a/etc/tempest.conf.sample b/etc/tempest.conf.sample
index 92371e8..033bc82 100644
--- a/etc/tempest.conf.sample
+++ b/etc/tempest.conf.sample
@@ -321,6 +321,13 @@
# any key, which will generate a keypair for each test class
#keypair_name = heat_key
+[dashboard]
+# URL where to find the dashboard home page
+dashboard_url = 'http://localhost/'
+
+# URL where to submit the login form
+login_url = 'http://localhost/auth/login/'
+
[scenario]
# Directory containing image files
img_dir = /opt/stack/new/devstack/files/images/cirros-0.3.1-x86_64-uec
@@ -360,3 +367,5 @@
nova = True
# Whether or not Heat is expected to be available
heat = false
+# Whether or not horizon is expected to be available
+horizon = True
diff --git a/tempest/config.py b/tempest/config.py
index eeb7b9d..a918d0b 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -414,6 +414,26 @@
for opt in OrchestrationGroup:
conf.register_opt(opt, group='orchestration')
+
+dashboard_group = cfg.OptGroup(name="dashboard",
+ title="Dashboard options")
+
+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"),
+]
+
+
+def register_dashboard_opts(conf):
+ conf.register_group(scenario_group)
+ for opt in DashboardGroup:
+ conf.register_opt(opt, group='dashboard')
+
+
boto_group = cfg.OptGroup(name='boto',
title='EC2/S3 options')
BotoConfig = [
@@ -558,6 +578,9 @@
cfg.BoolOpt('heat',
default=False,
help="Whether or not Heat is expected to be available"),
+ cfg.BoolOpt('horizon',
+ default=True,
+ help="Whether or not Horizon is expected to be available"),
]
@@ -613,6 +636,7 @@
register_volume_opts(cfg.CONF)
register_object_storage_opts(cfg.CONF)
register_orchestration_opts(cfg.CONF)
+ register_dashboard_opts(cfg.CONF)
register_boto_opts(cfg.CONF)
register_compute_admin_opts(cfg.CONF)
register_stress_opts(cfg.CONF)
@@ -626,6 +650,7 @@
self.volume = cfg.CONF.volume
self.object_storage = cfg.CONF['object-storage']
self.orchestration = cfg.CONF.orchestration
+ self.dashboard = cfg.CONF.dashboard
self.boto = cfg.CONF.boto
self.compute_admin = cfg.CONF['compute-admin']
self.stress = cfg.CONF.stress
diff --git a/tempest/scenario/test_dashboard_basic_ops.py b/tempest/scenario/test_dashboard_basic_ops.py
new file mode 100644
index 0000000..9a45572
--- /dev/null
+++ b/tempest/scenario/test_dashboard_basic_ops.py
@@ -0,0 +1,72 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# All Rights Reserved.
+#
+# 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 urllib
+import urllib2
+
+from lxml import html
+
+from tempest.scenario import manager
+
+
+class TestDashboardBasicOps(manager.OfficialClientTest):
+
+ """
+ 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
+ """
+
+ @classmethod
+ def setUpClass(cls):
+ super(TestDashboardBasicOps, cls).setUpClass()
+
+ if not cls.config.service_available.horizon:
+ raise cls.skipException("Horizon support is required")
+
+ def check_login_page(self):
+ response = urllib2.urlopen(self.config.dashboard.dashboard_url)
+ self.assertIn("<h3>Log In</h3>", response.read())
+
+ def user_login(self):
+ self.opener = urllib2.build_opener(urllib2.HTTPCookieProcessor())
+ response = self.opener.open(self.config.dashboard.dashboard_url).read()
+
+ # Grab the CSRF token and default region
+ csrf_token = html.fromstring(response).xpath(
+ '//input[@name="csrfmiddlewaretoken"]/@value')[0]
+ region = html.fromstring(response).xpath(
+ '//input[@name="region"]/@value')[0]
+
+ # Prepare login form request
+ req = urllib2.Request(self.config.dashboard.login_url)
+ req.add_header('Content-type', 'application/x-www-form-urlencoded')
+ req.add_header('Referer', self.config.dashboard.dashboard_url)
+ params = {'username': self.config.identity.username,
+ 'password': self.config.identity.password,
+ 'region': region,
+ 'csrfmiddlewaretoken': csrf_token}
+ self.opener.open(req, urllib.urlencode(params))
+
+ def check_home_page(self):
+ response = self.opener.open(self.config.dashboard.dashboard_url)
+ self.assertIn('Overview', response.read())
+
+ def test_basic_scenario(self):
+ self.check_login_page()
+ self.user_login()
+ self.check_home_page()