Merge "Change "$>" to "$" as CLI prompt"
diff --git a/HACKING.rst b/HACKING.rst
index ec7ff6a..480650c 100644
--- a/HACKING.rst
+++ b/HACKING.rst
@@ -21,6 +21,7 @@
- [T111] Check that service client names of DELETE should be consistent
- [T112] Check that tempest.lib should not import local tempest code
- [T113] Check that tests use data_utils.rand_uuid() instead of uuid.uuid4()
+- [T114] Check that tempest.lib does not use tempest config
- [N322] Method's default argument shouldn't be mutable
Test Data/Configuration
diff --git a/releasenotes/notes/remove-integrated-horizon-bb57551c1e5f5be3.yaml b/releasenotes/notes/remove-integrated-horizon-bb57551c1e5f5be3.yaml
new file mode 100644
index 0000000..294f6d9
--- /dev/null
+++ b/releasenotes/notes/remove-integrated-horizon-bb57551c1e5f5be3.yaml
@@ -0,0 +1,7 @@
+---
+upgrade:
+ - The integrated dashboard scenario test has been
+ removed and is now in a separate tempest plugin
+ tempest-horizon. The removed test coverage can be
+ used by installing tempest-horizon on the server
+ where you run tempest.
diff --git a/tempest/config.py b/tempest/config.py
index 71b25d0..3810ceb 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -841,21 +841,6 @@
help="Value must match heat configuration of the same name."),
]
-
-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",
- deprecated_for_removal=True),
-]
-
-
data_processing_group = cfg.OptGroup(name="data-processing",
title="Data Processing options")
@@ -986,9 +971,6 @@
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"),
cfg.BoolOpt('sahara',
default=False,
help="Whether or not Sahara is expected to be available"),
@@ -1131,7 +1113,6 @@
(object_storage_feature_group, ObjectStoreFeaturesGroup),
(database_group, DatabaseGroup),
(orchestration_group, OrchestrationGroup),
- (dashboard_group, DashboardGroup),
(data_processing_group, DataProcessingGroup),
(data_processing_feature_group, DataProcessingFeaturesGroup),
(stress_group, StressGroup),
@@ -1199,7 +1180,6 @@
'object-storage-feature-enabled']
self.database = _CONF.database
self.orchestration = _CONF.orchestration
- self.dashboard = _CONF.dashboard
self.data_processing = _CONF['data-processing']
self.data_processing_feature_enabled = _CONF[
'data-processing-feature-enabled']
diff --git a/tempest/hacking/checks.py b/tempest/hacking/checks.py
index aff9dee..09106d1 100644
--- a/tempest/hacking/checks.py
+++ b/tempest/hacking/checks.py
@@ -256,6 +256,23 @@
yield (0, msg)
+def dont_use_config_in_tempest_lib(logical_line, filename):
+ """Check that tempest.lib doesn't use tempest config
+
+ T114
+ """
+
+ if 'tempest/lib/' not in filename:
+ return
+
+ if ('tempest.config' in logical_line
+ or 'from tempest import config' in logical_line
+ or 'oslo_config' in logical_line):
+ msg = ('T114: tempest.lib can not have any dependency on tempest '
+ 'config.')
+ yield(0, msg)
+
+
def factory(register):
register(import_no_clients_in_api_and_scenario_tests)
register(scenario_tests_need_service_tags)
@@ -268,4 +285,5 @@
register(get_resources_on_service_clients)
register(delete_resources_on_service_clients)
register(dont_import_local_tempest_into_lib)
+ register(dont_use_config_in_tempest_lib)
register(use_rand_uuid_instead_of_uuid4)
diff --git a/tempest/scenario/test_dashboard_basic_ops.py b/tempest/scenario/test_dashboard_basic_ops.py
deleted file mode 100644
index 5d4f7b3..0000000
--- a/tempest/scenario/test_dashboard_basic_ops.py
+++ /dev/null
@@ -1,120 +0,0 @@
-# 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.
-
-from six.moves import html_parser as HTMLParser
-from six.moves.urllib import parse
-from six.moves.urllib import request
-
-from tempest import config
-from tempest.scenario import manager
-from tempest import test
-
-CONF = config.CONF
-
-
-class HorizonHTMLParser(HTMLParser.HTMLParser):
- csrf_token = None
- region = None
- login = None
-
- def _find_name(self, attrs, name):
- for attrpair in attrs:
- if attrpair[0] == 'name' and attrpair[1] == name:
- return True
- return False
-
- def _find_value(self, attrs):
- for attrpair in attrs:
- if attrpair[0] == 'value':
- return attrpair[1]
- return None
-
- def _find_attr_value(self, attrs, attr_name):
- for attrpair in attrs:
- if attrpair[0] == attr_name:
- return attrpair[1]
- return None
-
- def handle_starttag(self, tag, attrs):
- if tag == 'input':
- if self._find_name(attrs, 'csrfmiddlewaretoken'):
- self.csrf_token = self._find_value(attrs)
- if self._find_name(attrs, 'region'):
- self.region = self._find_value(attrs)
- if tag == 'form':
- self.login = self._find_attr_value(attrs, 'action')
-
-
-class TestDashboardBasicOps(manager.ScenarioTest):
-
- """The test suite for dashboard basic operations
-
- 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 skip_checks(cls):
- super(TestDashboardBasicOps, cls).skip_checks()
- if not CONF.service_available.horizon:
- raise cls.skipException("Horizon support is required")
-
- @classmethod
- def setup_credentials(cls):
- cls.set_network_resources()
- super(TestDashboardBasicOps, cls).setup_credentials()
-
- def check_login_page(self):
- response = request.urlopen(CONF.dashboard.dashboard_url)
- self.assertIn("id_username", response.read())
-
- def user_login(self, username, password):
- self.opener = request.build_opener(request.HTTPCookieProcessor())
- response = self.opener.open(CONF.dashboard.dashboard_url).read()
-
- # Grab the CSRF token and default region
- parser = HorizonHTMLParser()
- parser.feed(response)
-
- # construct login url for dashboard, discovery accommodates non-/ web
- # root for dashboard
- login_url = parse.urljoin(CONF.dashboard.dashboard_url, parser.login)
-
- # Prepare login form request
- req = request.Request(login_url)
- req.add_header('Content-type', 'application/x-www-form-urlencoded')
- req.add_header('Referer', CONF.dashboard.dashboard_url)
-
- # Pass the default domain name regardless of the auth version in order
- # to test the scenario of when horizon is running with keystone v3
- params = {'username': username,
- 'password': password,
- 'region': parser.region,
- 'domain': CONF.auth.default_credentials_domain_name,
- 'csrfmiddlewaretoken': parser.csrf_token}
- self.opener.open(req, parse.urlencode(params))
-
- def check_home_page(self):
- response = self.opener.open(CONF.dashboard.dashboard_url)
- self.assertIn('Overview', response.read())
-
- @test.idempotent_id('4f8851b1-0e69-482b-b63b-84c6e76f6c80')
- @test.services('dashboard')
- def test_basic_scenario(self):
- creds = self.os.credentials
- self.check_login_page()
- self.user_login(creds.username, creds.password)
- self.check_home_page()
diff --git a/tempest/test.py b/tempest/test.py
index aefe1a9..d31c509 100644
--- a/tempest/test.py
+++ b/tempest/test.py
@@ -77,7 +77,6 @@
'network': True,
'identity': True,
'object_storage': CONF.service_available.swift,
- 'dashboard': CONF.service_available.horizon,
'data_processing': CONF.service_available.sahara,
'database': CONF.service_available.trove
}
@@ -92,8 +91,8 @@
"""
def decorator(f):
services = ['compute', 'image', 'baremetal', 'volume', 'orchestration',
- 'network', 'identity', 'object_storage', 'dashboard',
- 'data_processing', 'database']
+ 'network', 'identity', 'object_storage', 'data_processing',
+ 'database']
for service in args:
if service not in services:
raise exceptions.InvalidServiceTag('%s is not a valid '
diff --git a/tempest/tests/test_hacking.py b/tempest/tests/test_hacking.py
index aba2aab..f005c21 100644
--- a/tempest/tests/test_hacking.py
+++ b/tempest/tests/test_hacking.py
@@ -167,3 +167,16 @@
self.assertEqual(1, len(list(checks.dont_import_local_tempest_into_lib(
"import tempest.exception",
'./tempest/lib/common/compute.py'))))
+
+ def test_dont_use_config_in_tempest_lib(self):
+ self.assertFalse(list(checks.dont_use_config_in_tempest_lib(
+ 'from tempest import config', './tempest/common/compute.py')))
+ self.assertFalse(list(checks.dont_use_config_in_tempest_lib(
+ 'from oslo_concurrency import lockutils',
+ './tempest/lib/auth.py')))
+ self.assertTrue(list(checks.dont_use_config_in_tempest_lib(
+ 'from tempest import config', './tempest/lib/auth.py')))
+ self.assertTrue(list(checks.dont_use_config_in_tempest_lib(
+ 'from oslo_config import cfg', './tempest/lib/decorators.py')))
+ self.assertTrue(list(checks.dont_use_config_in_tempest_lib(
+ 'import tempest.config', './tempest/lib/common/rest_client.py')))
diff --git a/tools/check_logs.py b/tools/check_logs.py
index e34dec3..caad85c 100755
--- a/tools/check_logs.py
+++ b/tools/check_logs.py
@@ -20,8 +20,8 @@
import os
import re
import six
+import six.moves.urllib.request as urlreq
import sys
-import urllib2
import yaml
@@ -67,9 +67,9 @@
logs_with_errors.append(name)
for (name, url) in url_specs:
whitelist = whitelists.get(name, [])
- req = urllib2.Request(url)
+ req = urlreq.Request(url)
req.add_header('Accept-Encoding', 'gzip')
- page = urllib2.urlopen(req)
+ page = urlreq.urlopen(req)
buf = six.StringIO(page.read())
f = gzip.GzipFile(fileobj=buf)
if scan_content(name, f.read().splitlines(), regexp, whitelist):
@@ -95,7 +95,7 @@
def collect_url_logs(url):
- page = urllib2.urlopen(url)
+ page = urlreq.urlopen(url)
content = page.read()
logs = re.findall('(screen-[\w-]+\.txt\.gz)</a>', content)
return logs
diff --git a/tools/find_stack_traces.py b/tools/find_stack_traces.py
index 49a42fe..f2da27a 100755
--- a/tools/find_stack_traces.py
+++ b/tools/find_stack_traces.py
@@ -19,8 +19,8 @@
import pprint
import re
import six
+import six.moves.urllib.request as urlreq
import sys
-import urllib2
pp = pprint.PrettyPrinter()
@@ -65,9 +65,9 @@
def hunt_for_stacktrace(url):
"""Return TRACE or ERROR lines out of logs."""
- req = urllib2.Request(url)
+ req = urlreq.Request(url)
req.add_header('Accept-Encoding', 'gzip')
- page = urllib2.urlopen(req)
+ page = urlreq.urlopen(req)
buf = six.StringIO(page.read())
f = gzip.GzipFile(fileobj=buf)
content = f.read()
@@ -105,7 +105,7 @@
def collect_logs(url):
- page = urllib2.urlopen(url)
+ page = urlreq.urlopen(url)
content = page.read()
logs = re.findall('(screen-[\w-]+\.txt\.gz)</a>', content)
return logs