summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRick Bartra <rb560u@att.com>2018-08-20 17:26:18 -0400
committerRick Bartra <rb560u@att.com>2018-08-21 16:25:32 -0400
commit9f473f288a6f8d42c32e54da7d9c4679c0cd40cc (patch)
tree7e69138f75314f5f6a2daf9bd6584dd76cf5e08a
parente7807b4caf37ce47818602759dbf382fb3f0f283 (diff)
Add Additional RBAC Test Coverage for Shipyard
This commit does the following: - Add test coverage for: - Actions API - Airflow Monitoring API - Log Retrieval API - Add tox.ini - Add hacking checks - Fix pep8 issues Future work needed to fix some of the Actions API RBAC tests Change-Id: I6e17ffa3ecc3c8a181790bdb79ad6b29fe127114
-rw-r--r--airship_tempest_plugin/config.py7
-rw-r--r--airship_tempest_plugin/hacking/__init__.py0
-rw-r--r--airship_tempest_plugin/hacking/checks.py209
-rw-r--r--airship_tempest_plugin/plugin.py2
-rw-r--r--airship_tempest_plugin/services/shipyard/json/actions_client.py44
-rw-r--r--airship_tempest_plugin/services/shipyard/json/airflow_monitoring_client.py9
-rw-r--r--airship_tempest_plugin/services/shipyard/json/document_staging_client.py9
-rw-r--r--airship_tempest_plugin/services/shipyard/json/log_retrieval_client.py33
-rw-r--r--airship_tempest_plugin/tests/api/common/rbac_roles.yaml40
-rw-r--r--airship_tempest_plugin/tests/api/shipyard/base.py22
-rw-r--r--airship_tempest_plugin/tests/api/shipyard/rbac/rbac_base.py2
-rw-r--r--airship_tempest_plugin/tests/api/shipyard/rbac/test_actions_rbac.py76
-rw-r--r--airship_tempest_plugin/tests/api/shipyard/rbac/test_airflow_monitoring_rbac.py30
-rw-r--r--airship_tempest_plugin/tests/api/shipyard/rbac/test_document_staging_rbac.py70
-rw-r--r--airship_tempest_plugin/tests/api/shipyard/rbac/test_log_retrieval_rbac.py39
-rw-r--r--airship_tempest_plugin/tests/unit/__init__.py0
-rw-r--r--requirements.txt9
-rw-r--r--test-requirements.txt10
-rw-r--r--tox.ini104
19 files changed, 641 insertions, 74 deletions
diff --git a/airship_tempest_plugin/config.py b/airship_tempest_plugin/config.py
index 73287b2..e6d0bcb 100644
--- a/airship_tempest_plugin/config.py
+++ b/airship_tempest_plugin/config.py
@@ -24,7 +24,7 @@ ServiceAvailableGroup = [
24] 24]
25 25
26shipyard_group = cfg.OptGroup(name='shipyard', 26shipyard_group = cfg.OptGroup(name='shipyard',
27 title='Shipyard service options') 27 title='Shipyard service options')
28 28
29ShipyardGroup = [ 29ShipyardGroup = [
30 cfg.StrOpt('endpoint_type', 30 cfg.StrOpt('endpoint_type',
@@ -36,10 +36,9 @@ ShipyardGroup = [
36 help="Catalog type of the Shipyard service"), 36 help="Catalog type of the Shipyard service"),
37] 37]
38 38
39
39def get_opt_lists(self, conf): 40def get_opt_lists(self, conf):
40 """ 41 """Get a list of options for sample config generation"""
41 Get a list of options for sample config generation
42 """
43 return [ 42 return [
44 (service_available_group, ServiceAvailableGroup), 43 (service_available_group, ServiceAvailableGroup),
45 (shipyard_group, ShipyardGroup) 44 (shipyard_group, ShipyardGroup)
diff --git a/airship_tempest_plugin/hacking/__init__.py b/airship_tempest_plugin/hacking/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/airship_tempest_plugin/hacking/__init__.py
diff --git a/airship_tempest_plugin/hacking/checks.py b/airship_tempest_plugin/hacking/checks.py
new file mode 100644
index 0000000..1491f2d
--- /dev/null
+++ b/airship_tempest_plugin/hacking/checks.py
@@ -0,0 +1,209 @@
1# Copyright 2013 IBM Corp.
2# Copyright 2017 AT&T Corporation.
3# All Rights Reserved.
4#
5# Licensed under the Apache License, Version 2.0 (the "License"); you may
6# not use this file except in compliance with the License. You may obtain
7# a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14# License for the specific language governing permissions and limitations
15# under the License.
16
17import os
18import re
19
20import pycodestyle
21
22
23PYTHON_CLIENTS = ['cinder', 'glance', 'keystone', 'nova', 'swift', 'neutron',
24 'ironic', 'heat', 'sahara']
25
26PYTHON_CLIENT_RE = re.compile('import (%s)client' % '|'.join(PYTHON_CLIENTS))
27TEST_DEFINITION = re.compile(r'^\s*def test.*')
28SETUP_TEARDOWN_CLASS_DEFINITION = re.compile(r'^\s+def (setUp|tearDown)Class')
29SCENARIO_DECORATOR = re.compile(r'\s*@.*services\((.*)\)')
30VI_HEADER_RE = re.compile(r"^#\s+vim?:.+")
31RAND_NAME_HYPHEN_RE = re.compile(r".*rand_name\(.+[\-\_][\"\']\)")
32MUTABLE_DEFAULT_ARGS = re.compile(r"^\s*def .+\((.+=\{\}|.+=\[\])")
33TESTTOOLS_SKIP_DECORATOR = re.compile(r'\s*@testtools\.skip\((.*)\)')
34CLASS = re.compile(r"^class .+")
35RBAC_CLASS_NAME_RE = re.compile(r'class .+RbacTest')
36RULE_VALIDATION_DECORATOR = re.compile(
37 r'\s*@rbac_rule_validation.action\(.*')
38IDEMPOTENT_ID_DECORATOR = re.compile(r'\s*@decorators\.idempotent_id\((.*)\)')
39
40have_rbac_decorator = False
41
42
43def import_no_clients_in_api_tests(physical_line, filename):
44 """Check for client imports from airship_tempest_plugin/tests/api
45 T102: Cannot import OpenStack python clients
46 """
47 if "airship_tempest_plugin/tests/api" in filename:
48 res = PYTHON_CLIENT_RE.match(physical_line)
49 if res:
50 return (physical_line.find(res.group(1)),
51 ("T102: python clients import not allowed "
52 "in airship_tempest_plugin/tests/api/* or "
53 "airship_tempest_plugin/tests/scenario/* tests"))
54
55
56def no_setup_teardown_class_for_tests(physical_line, filename):
57 """Check that tests do not use setUpClass/tearDownClass
58 T105: Tests cannot use setUpClass/tearDownClass
59 """
60 if pycodestyle.noqa(physical_line):
61 return
62
63 if SETUP_TEARDOWN_CLASS_DEFINITION.match(physical_line):
64 return (physical_line.find('def'),
65 "T105: (setUp|tearDown)Class can not be used in tests")
66
67
68def no_vi_headers(physical_line, line_number, lines):
69 """Check for vi editor configuration in source files.
70 By default vi modelines can only appear in the first or
71 last 5 lines of a source file.
72 T106
73 """
74 # NOTE(gilliard): line_number is 1-indexed
75 if line_number <= 5 or line_number > len(lines) - 5:
76 if VI_HEADER_RE.match(physical_line):
77 return 0, "T106: Don't put vi configuration in source files"
78
79
80def service_tags_not_in_module_path(physical_line, filename):
81 """Check that a service tag isn't in the module path
82 A service tag should only be added if the service name isn't already in
83 the module path.
84 T107
85 """
86 matches = SCENARIO_DECORATOR.match(physical_line)
87 if matches:
88 services = matches.group(1).split(',')
89 for service in services:
90 service_name = service.strip().strip("'")
91 modulepath = os.path.split(filename)[0]
92 if service_name in modulepath:
93 return (physical_line.find(service_name),
94 "T107: service tag should not be in path")
95
96
97def no_hyphen_at_end_of_rand_name(logical_line, filename):
98 """Check no hyphen at the end of rand_name() argument
99 T108
100 """
101 msg = "T108: hyphen should not be specified at the end of rand_name()"
102 if RAND_NAME_HYPHEN_RE.match(logical_line):
103 return 0, msg
104
105
106def no_mutable_default_args(logical_line):
107 """Check that mutable object isn't used as default argument
108 N322: Method's default argument shouldn't be mutable
109 """
110 msg = "N322: Method's default argument shouldn't be mutable!"
111 if MUTABLE_DEFAULT_ARGS.match(logical_line):
112 yield (0, msg)
113
114
115def no_testtools_skip_decorator(logical_line):
116 """Check that methods do not have the testtools.skip decorator
117 T109
118 """
119 if TESTTOOLS_SKIP_DECORATOR.match(logical_line):
120 yield (0, "T109: Cannot use testtools.skip decorator; instead use "
121 "decorators.skip_because from tempest.lib")
122
123
124def use_rand_uuid_instead_of_uuid4(logical_line, filename):
125 """Check that tests use data_utils.rand_uuid() instead of uuid.uuid4()
126 T113
127 """
128 if 'uuid.uuid4()' not in logical_line:
129 return
130
131 msg = ("T113: Tests should use data_utils.rand_uuid()/rand_uuid_hex() "
132 "instead of uuid.uuid4()/uuid.uuid4().hex")
133 yield (0, msg)
134
135
136def no_rbac_rule_validation_decorator(physical_line, filename):
137 """Check that each test has the ``rbac_rule_validation.action`` decorator.
138 Checks whether the test function has "@rbac_rule_validation.action"
139 above it; otherwise checks that it has "@decorators.idempotent_id" above
140 it and "@rbac_rule_validation.action" above that.
141 Assumes that ``rbac_rule_validation.action`` decorator is either the first
142 or second decorator above the test function; otherwise this check fails.
143 P100
144 """
145 global have_rbac_decorator
146
147 if ("airship_tempest_plugin/tests/api" in filename or
148 "airship_tempest_plugin/tests/scenario" in filename):
149
150 if RULE_VALIDATION_DECORATOR.match(physical_line):
151 have_rbac_decorator = True
152 return
153
154 if TEST_DEFINITION.match(physical_line):
155 if not have_rbac_decorator:
156 return (0, "Must use rbac_rule_validation.action "
157 "decorator for API and scenario tests")
158
159 have_rbac_decorator = False
160
161
162def no_rbac_suffix_in_test_filename(filename):
163 """Check that RBAC filenames end with "_rbac" suffix.
164 P101
165 """
166 if "airship_tempest_plugin/tests/api" in filename:
167
168 if filename.endswith('rbac_base.py'):
169 return
170
171 if not filename.endswith('_rbac.py'):
172 return 0, "RBAC test filenames must end in _rbac suffix"
173
174
175def no_rbac_test_suffix_in_test_class_name(physical_line, filename):
176 """Check that RBAC class names end with "RbacTest"
177 P102
178 """
179 if "airship_tempest_plugin/tests/api" in filename:
180
181 if filename.endswith('rbac_base.py'):
182 return
183
184 if CLASS.match(physical_line):
185 if not RBAC_CLASS_NAME_RE.match(physical_line):
186 return 0, "RBAC test class names must end in 'RbacTest'"
187
188
189def no_client_alias_in_test_cases(logical_line, filename):
190 """Check that test cases don't use "self.client" to define a client.
191 P103
192 """
193 if "airship_tempest_plugin/tests/api" in filename:
194 if "self.client" in logical_line or "cls.client" in logical_line:
195 return 0, "Do not use 'self.client' as a service client alias"
196
197
198def factory(register):
199 register(import_no_clients_in_api_tests)
200 register(no_setup_teardown_class_for_tests)
201 register(no_vi_headers)
202 register(no_hyphen_at_end_of_rand_name)
203 register(no_mutable_default_args)
204 register(no_testtools_skip_decorator)
205 register(use_rand_uuid_instead_of_uuid4)
206 register(service_tags_not_in_module_path)
207 register(no_rbac_rule_validation_decorator)
208 register(no_rbac_suffix_in_test_filename)
209 register(no_rbac_test_suffix_in_test_class_name)
diff --git a/airship_tempest_plugin/plugin.py b/airship_tempest_plugin/plugin.py
index d7056c0..2f437a8 100644
--- a/airship_tempest_plugin/plugin.py
+++ b/airship_tempest_plugin/plugin.py
@@ -34,7 +34,9 @@ class AirshipRbacPlugin(plugins.TempestPlugin):
34 config.register_opt_group(conf, project_config.service_available_group, 34 config.register_opt_group(conf, project_config.service_available_group,
35 project_config.ServiceAvailableGroup) 35 project_config.ServiceAvailableGroup)
36 config.register_opt_group(conf, project_config.shipyard_group, 36 config.register_opt_group(conf, project_config.shipyard_group,
37
37 project_config.ShipyardGroup) 38 project_config.ShipyardGroup)
39
38 def get_opt_lists(self): 40 def get_opt_lists(self):
39 return [ 41 return [
40 (project_config.service_available_group.name, 42 (project_config.service_available_group.name,
diff --git a/airship_tempest_plugin/services/shipyard/json/actions_client.py b/airship_tempest_plugin/services/shipyard/json/actions_client.py
index f45517c..08f74a3 100644
--- a/airship_tempest_plugin/services/shipyard/json/actions_client.py
+++ b/airship_tempest_plugin/services/shipyard/json/actions_client.py
@@ -19,16 +19,56 @@ http://airship-shipyard.readthedocs.io/en/latest/API.html#action-api
19""" 19"""
20 20
21from oslo_serialization import jsonutils as json 21from oslo_serialization import jsonutils as json
22from six.moves.urllib import parse as urllib
23 22
24from tempest.lib.common import rest_client 23from tempest.lib.common import rest_client
25 24
25# NOTE(rb560u): The following will need to be rewritten in the future if
26# functional testing is desired:
27# - 'def post_actions`
28# This initial implementation is just to meet the first use case which is RBAC
29# testing. For RBAC testing, we only need to hit the API endpoint and check
30# role permission to that API.
31
26 32
27class ActionsClient(rest_client.RestClient): 33class ActionsClient(rest_client.RestClient):
28 api_version = "v1.0" 34 api_version = "v1.0"
29 35
30 def get_actions(self): 36 def list_actions(self):
31 resp, body = self.get('actions') 37 resp, body = self.get('actions')
32 self.expected_success(200, resp.status) 38 self.expected_success(200, resp.status)
33 body = json.loads(body) 39 body = json.loads(body)
34 return rest_client.ResponseBody(resp, body) 40 return rest_client.ResponseBody(resp, body)
41
42 def create_action(self):
43 url = "actions"
44 post_body = json.dumps({})
45 resp, body = self.post(url, post_body)
46 self.expected_success(201, resp.status)
47 body = json.loads(body)
48 return rest_client.ResponseBody(resp, body)
49
50 def get_action(self):
51 resp, body = self.get('actions/1')
52 self.expected_success(200, resp.status)
53 body = json.loads(body)
54 return rest_client.ResponseBody(resp, body)
55
56 def get_action_validation(self):
57 resp, body = self.get('actions/1/validationdetails/1')
58 self.expected_success(200, resp.status)
59 body = json.loads(body)
60 return rest_client.ResponseBody(resp, body)
61
62 def get_action_step(self):
63 resp, body = self.get('actions/1/steps/1')
64 self.expected_success(200, resp.status)
65 body = json.loads(body)
66 return rest_client.ResponseBody(resp, body)
67
68 def invoke_action_control(self):
69 url = "actions/1/pause"
70 post_body = json.dumps({})
71 resp, body = self.post(url, post_body)
72 self.expected_success(202, resp.status)
73 body = json.loads(body)
74 return rest_client.ResponseBody(resp, body)
diff --git a/airship_tempest_plugin/services/shipyard/json/airflow_monitoring_client.py b/airship_tempest_plugin/services/shipyard/json/airflow_monitoring_client.py
index e6ec292..2646ca0 100644
--- a/airship_tempest_plugin/services/shipyard/json/airflow_monitoring_client.py
+++ b/airship_tempest_plugin/services/shipyard/json/airflow_monitoring_client.py
@@ -19,7 +19,6 @@ http://airship-shipyard.readthedocs.io/en/latest/API.html#airflow-monitoring-api
19""" 19"""
20 20
21from oslo_serialization import jsonutils as json 21from oslo_serialization import jsonutils as json
22from six.moves.urllib import parse as urllib
23 22
24from tempest.lib.common import rest_client 23from tempest.lib.common import rest_client
25 24
@@ -27,8 +26,14 @@ from tempest.lib.common import rest_client
27class AirflowMonitoringClient(rest_client.RestClient): 26class AirflowMonitoringClient(rest_client.RestClient):
28 api_version = "v1.0" 27 api_version = "v1.0"
29 28
30 def get_workflows(self): 29 def list_workflows(self):
31 resp, body = self.get('workflows') 30 resp, body = self.get('workflows')
32 self.expected_success(200, resp.status) 31 self.expected_success(200, resp.status)
33 body = json.loads(body) 32 body = json.loads(body)
34 return rest_client.ResponseBody(resp, body) 33 return rest_client.ResponseBody(resp, body)
34
35 def get_workflow(self):
36 resp, body = self.get('workflows/1')
37 self.expected_success(200, resp.status)
38 body = json.loads(body)
39 return rest_client.ResponseBody(resp, body)
diff --git a/airship_tempest_plugin/services/shipyard/json/document_staging_client.py b/airship_tempest_plugin/services/shipyard/json/document_staging_client.py
index 353464b..039e82a 100644
--- a/airship_tempest_plugin/services/shipyard/json/document_staging_client.py
+++ b/airship_tempest_plugin/services/shipyard/json/document_staging_client.py
@@ -19,7 +19,6 @@ http://airship-shipyard.readthedocs.io/en/latest/API.html#document-staging-api
19""" 19"""
20 20
21from oslo_serialization import jsonutils as json 21from oslo_serialization import jsonutils as json
22from six.moves.urllib import parse as urllib
23 22
24from tempest.lib.common import rest_client 23from tempest.lib.common import rest_client
25 24
@@ -36,13 +35,13 @@ from tempest.lib.common import rest_client
36class DocumentStagingClient(rest_client.RestClient): 35class DocumentStagingClient(rest_client.RestClient):
37 api_version = "v1.0" 36 api_version = "v1.0"
38 37
39 def get_configdocs(self): 38 def get_configdocs_status(self):
40 resp, body = self.get('configdocs') 39 resp, body = self.get('configdocs')
41 self.expected_success(200, resp.status) 40 self.expected_success(200, resp.status)
42 body = json.loads(body) 41 body = json.loads(body)
43 return rest_client.ResponseBody(resp, body) 42 return rest_client.ResponseBody(resp, body)
44 43
45 def post_configdocs(self): 44 def create_configdocs(self):
46 url = "configdocs/1" 45 url = "configdocs/1"
47 post_body = json.dumps({}) 46 post_body = json.dumps({})
48 resp, body = self.post(url, post_body) 47 resp, body = self.post(url, post_body)
@@ -50,7 +49,7 @@ class DocumentStagingClient(rest_client.RestClient):
50 body = json.loads(body) 49 body = json.loads(body)
51 return rest_client.ResponseBody(resp, body) 50 return rest_client.ResponseBody(resp, body)
52 51
53 def get_configdocs_within_collection(self): 52 def get_configdocs(self):
54 resp, body = self.get('configdocs/1') 53 resp, body = self.get('configdocs/1')
55 self.expected_success(200, resp.status) 54 self.expected_success(200, resp.status)
56 body = json.loads(body) 55 body = json.loads(body)
@@ -62,7 +61,7 @@ class DocumentStagingClient(rest_client.RestClient):
62 body = json.loads(body) 61 body = json.loads(body)
63 return rest_client.ResponseBody(resp, body) 62 return rest_client.ResponseBody(resp, body)
64 63
65 def post_commitconfigdocs(self): 64 def commit_configdocs(self):
66 post_body = json.dumps({}) 65 post_body = json.dumps({})
67 resp, body = self.post("commitconfigdocs", post_body) 66 resp, body = self.post("commitconfigdocs", post_body)
68 self.expected_success(200, resp.status) 67 self.expected_success(200, resp.status)
diff --git a/airship_tempest_plugin/services/shipyard/json/log_retrieval_client.py b/airship_tempest_plugin/services/shipyard/json/log_retrieval_client.py
new file mode 100644
index 0000000..c6239ac
--- /dev/null
+++ b/airship_tempest_plugin/services/shipyard/json/log_retrieval_client.py
@@ -0,0 +1,33 @@
1# Copyright 2018 AT&T Corp
2# All Rights Reserved.
3#
4# Licensed under the Apache License, Version 2.0 (the "License"); you may
5# not use this file except in compliance with the License. You may obtain
6# a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13# License for the specific language governing permissions and limitations
14# under the License.
15#
16
17"""
18http://airship-shipyard.readthedocs.io/en/latest/API.html#airflow-monitoring-api
19"""
20
21from oslo_serialization import jsonutils as json
22
23from tempest.lib.common import rest_client
24
25
26class LogRetrievalClient(rest_client.RestClient):
27 api_version = "v1.0"
28
29 def get_action_step_logs(self):
30 resp, body = self.get('actions/1/steps/1/logs')
31 self.expected_success(200, resp.status)
32 body = json.loads(body)
33 return rest_client.ResponseBody(resp, body)
diff --git a/airship_tempest_plugin/tests/api/common/rbac_roles.yaml b/airship_tempest_plugin/tests/api/common/rbac_roles.yaml
index 4f6fed4..3cb5401 100644
--- a/airship_tempest_plugin/tests/api/common/rbac_roles.yaml
+++ b/airship_tempest_plugin/tests/api/common/rbac_roles.yaml
@@ -1,28 +1,54 @@
1shipyard: 1shipyard:
2 get_actions: 2 workflow_orchestrator:list_actions:
3 - admin 3 - admin
4 - admin_ucp 4 - admin_ucp
5 - admin_ucp_viewer 5 - admin_ucp_viewer
6 get_configdocs: 6 workflow_orchestrator:create_action:
7 - admin
8 - admin_ucp
9 workflow_orchestrator:get_action:
10 - admin
11 - admin_ucp
12 - admin_ucp_viewer
13 workflow_orchestrator:get_action_validation:
7 - admin 14 - admin
8 - admin_ucp 15 - admin_ucp
9 - admin_ucp_viewer 16 - admin_ucp_viewer
10 get_workflows: 17 workflow_orchestrator:get_action_step:
18 - admin
19 - admin_ucp
20 - admin_ucp_viewer
21 workflow_orchestrator:invoke_action_control:
22 - admin
23 - admin_ucp
24 workflow_orchestrator:get_action_step_logs:
11 - admin 25 - admin
12 - admin_ucp 26 - admin_ucp
13 - admin_ucp_viewer 27 - admin_ucp_viewer
14 post_configdocs: 28 workflow_orchestrator:get_configdocs:
15 - admin 29 - admin
16 - admin_ucp 30 - admin_ucp
17 get_configdocs_within_collection: 31 - admin_ucp_viewer
32 workflow_orchestrator:create_configdocs:
33 - admin
34 - admin_ucp
35 workflow_orchestrator:get_configdocs_status:
36 - admin
37 - admin_ucp
38 - admin_ucp_viewer
39 workflow_orchestrator:get_renderedconfigdocs:
40 - admin
41 - admin_ucp
42 - admin_ucp_viewer
43 workflow_orchestrator:commit_configdocs:
18 - admin 44 - admin
19 - admin_ucp 45 - admin_ucp
20 - admin_ucp_viewer 46 - admin_ucp_viewer
21 get_renderedconfigdocs: 47 workflow_orchestrator:list_workflows:
22 - admin 48 - admin
23 - admin_ucp 49 - admin_ucp
24 - admin_ucp_viewer 50 - admin_ucp_viewer
25 post_commitconfigdocs: 51 workflow_orchestrator:get_workflow:
26 - admin 52 - admin
27 - admin_ucp 53 - admin_ucp
28 - admin_ucp_viewer 54 - admin_ucp_viewer
diff --git a/airship_tempest_plugin/tests/api/shipyard/base.py b/airship_tempest_plugin/tests/api/shipyard/base.py
index 88f8233..6414463 100644
--- a/airship_tempest_plugin/tests/api/shipyard/base.py
+++ b/airship_tempest_plugin/tests/api/shipyard/base.py
@@ -14,17 +14,21 @@
14# under the License. 14# under the License.
15# 15#
16 16
17from airship_tempest_plugin.services.shipyard.json.actions_client import ActionsClient 17from airship_tempest_plugin.services.shipyard.json.actions_client \
18from airship_tempest_plugin.services.shipyard.json.document_staging_client import DocumentStagingClient 18 import ActionsClient
19from airship_tempest_plugin.services.shipyard.json.airflow_monitoring_client import AirflowMonitoringClient 19from airship_tempest_plugin.services.shipyard.json.airflow_monitoring_client \
20 import AirflowMonitoringClient
21from airship_tempest_plugin.services.shipyard.json.document_staging_client \
22 import DocumentStagingClient
23from airship_tempest_plugin.services.shipyard.json.log_retrieval_client \
24 import LogRetrievalClient
20 25
21from tempest import config 26from tempest import config
22from tempest import test 27from tempest import test
23 28
24from patrole_tempest_plugin import rbac_utils
25
26CONF = config.CONF 29CONF = config.CONF
27 30
31
28class BaseShipyardTest(test.BaseTestCase): 32class BaseShipyardTest(test.BaseTestCase):
29 """Base class for Shipyard tests.""" 33 """Base class for Shipyard tests."""
30 credentials = ['primary', 'admin'] 34 credentials = ['primary', 'admin']
@@ -33,7 +37,8 @@ class BaseShipyardTest(test.BaseTestCase):
33 def skip_checks(cls): 37 def skip_checks(cls):
34 super(BaseShipyardTest, cls).skip_checks() 38 super(BaseShipyardTest, cls).skip_checks()
35 if not CONF.service_available.shipyard: 39 if not CONF.service_available.shipyard:
36 raise cls.skipException("Shipyard is not enabled in the deployment") 40 raise cls.skipException("Shipyard is not enabled in "
41 "the deployment")
37 42
38 @classmethod 43 @classmethod
39 def setup_clients(cls): 44 def setup_clients(cls):
@@ -55,3 +60,8 @@ class BaseShipyardTest(test.BaseTestCase):
55 CONF.shipyard.catalog_type, 60 CONF.shipyard.catalog_type,
56 CONF.identity.region, 61 CONF.identity.region,
57 CONF.shipyard.endpoint_type) 62 CONF.shipyard.endpoint_type)
63 cls.shipyard_log_retrieval_client = LogRetrievalClient(
64 cls.auth_provider,
65 CONF.shipyard.catalog_type,
66 CONF.identity.region,
67 CONF.shipyard.endpoint_type)
diff --git a/airship_tempest_plugin/tests/api/shipyard/rbac/rbac_base.py b/airship_tempest_plugin/tests/api/shipyard/rbac/rbac_base.py
index 655a21f..1074771 100644
--- a/airship_tempest_plugin/tests/api/shipyard/rbac/rbac_base.py
+++ b/airship_tempest_plugin/tests/api/shipyard/rbac/rbac_base.py
@@ -14,7 +14,6 @@
14# under the License. 14# under the License.
15# 15#
16 16
17from airship_tempest_plugin.services.shipyard.json.actions_client import ActionsClient
18from airship_tempest_plugin.tests.api.shipyard import base 17from airship_tempest_plugin.tests.api.shipyard import base
19 18
20from tempest import config 19from tempest import config
@@ -23,6 +22,7 @@ from patrole_tempest_plugin import rbac_utils
23 22
24CONF = config.CONF 23CONF = config.CONF
25 24
25
26class BaseShipyardRbacTest(rbac_utils.RbacUtilsMixin, 26class BaseShipyardRbacTest(rbac_utils.RbacUtilsMixin,
27 base.BaseShipyardTest): 27 base.BaseShipyardTest):
28 """Base class for Shipyard RBAC tests.""" 28 """Base class for Shipyard RBAC tests."""
diff --git a/airship_tempest_plugin/tests/api/shipyard/rbac/test_actions_rbac.py b/airship_tempest_plugin/tests/api/shipyard/rbac/test_actions_rbac.py
index 84c95b1..9ef398a 100644
--- a/airship_tempest_plugin/tests/api/shipyard/rbac/test_actions_rbac.py
+++ b/airship_tempest_plugin/tests/api/shipyard/rbac/test_actions_rbac.py
@@ -18,18 +18,78 @@ from airship_tempest_plugin.tests.api.shipyard.rbac import rbac_base
18 18
19from patrole_tempest_plugin import rbac_rule_validation 19from patrole_tempest_plugin import rbac_rule_validation
20 20
21from tempest.common import utils
22from tempest.lib import decorators 21from tempest.lib import decorators
23from tempest.lib.common.utils import data_utils 22from tempest.lib import exceptions
24from tempest.lib.common.utils import test_utils
25 23
26from tempest.api.identity import base
27 24
28class ActionsRbacTest(rbac_base.BaseShipyardRbacTest): 25class ActionsRbacTest(rbac_base.BaseShipyardRbacTest):
29 26
30 @rbac_rule_validation.action(service="shipyard", 27 @rbac_rule_validation.action(
31 rules=["get_actions"]) 28 service="shipyard",
29 rules=["workflow_orchestrator:list_actions"])
32 @decorators.idempotent_id('183dd007-8a97-4070-afc3-9318401ebad7') 30 @decorators.idempotent_id('183dd007-8a97-4070-afc3-9318401ebad7')
33 def test_get_actions(self): 31 def test_list_actions(self):
34 with self.rbac_utils.override_role(self): 32 with self.rbac_utils.override_role(self):
35 self.shipyard_actions_client.get_actions() 33 self.shipyard_actions_client.list_actions()
34
35 @rbac_rule_validation.action(
36 service="shipyard",
37 rules=["workflow_orchestrator:create_action"])
38 @decorators.idempotent_id('fff43c6f-b6ed-44dd-b47b-02c45d7bdb8c')
39 def test_create_action(self):
40 with self.rbac_utils.override_role(self):
41 # As this is a RBAC test, we only care about whether the role has
42 # permission or not. Role permission is checked prior to validating
43 # the post body, therefore we will ignore a BadRequest exception
44 try:
45 self.shipyard_actions_client.create_action()
46 except exceptions.BadRequest:
47 pass
48
49 @rbac_rule_validation.action(
50 service="shipyard",
51 rules=["workflow_orchestrator:get_action"])
52 @decorators.idempotent_id('68e2f10f-0676-41bb-8f47-bc695e1aa536')
53 def test_get_action(self):
54 with self.rbac_utils.override_role(self):
55 # As this is a RBAC test, we only care about whether the role has
56 # permission or not. Role permission is checked prior to validating
57 # the post body, therefore we will ignore a NotFound exception
58 try:
59 self.shipyard_actions_client.get_action()
60 except exceptions.NotFound:
61 pass
62
63 ''' NEEDS REWORK AS SHIPYARD NOT DOING POLICY ENFORCEMENT FIRST
64 @rbac_rule_validation.action(
65 service="shipyard",
66 rules=["workflow_orchestrator:get_action_validation"])
67 @decorators.idempotent_id('a5156dcd-2674-4295-aa6a-d8db1bd4cf4b')
68 def test_get_action_validation(self):
69 with self.rbac_utils.override_role(self):
70 self.shipyard_actions_client.get_action_validation()
71 '''
72
73 @rbac_rule_validation.action(
74 service="shipyard",
75 rules=["workflow_orchestrator:get_action_step"])
76 @decorators.idempotent_id('6243d2ff-f88e-41cf-8169-140a551834a4')
77 def test_get_action_step(self):
78 with self.rbac_utils.override_role(self):
79 # As this is a RBAC test, we only care about whether the role has
80 # permission or not. Role permission is checked prior to validating
81 # the post body, therefore we will ignore a NotFound exception
82 try:
83 self.shipyard_actions_client.get_action_step()
84 except exceptions.NotFound:
85 pass
86
87 ''' NEEDS REWORK AS SHIPYARD NOT DOING POLICY ENFORCEMENT FIRST
88 @rbac_rule_validation.action(
89 service="shipyard",
90 rules=["workflow_orchestrator:invoke_action_control"])
91 @decorators.idempotent_id('4f6b6564-ff1d-463a-aee8-ed2d51e2a286')
92 def test_invoke_action_control(self):
93 with self.rbac_utils.override_role(self):
94 self.shipyard_actions_client.invoke_action_control()
95 '''
diff --git a/airship_tempest_plugin/tests/api/shipyard/rbac/test_airflow_monitoring_rbac.py b/airship_tempest_plugin/tests/api/shipyard/rbac/test_airflow_monitoring_rbac.py
index 74fd2d3..d320dfe 100644
--- a/airship_tempest_plugin/tests/api/shipyard/rbac/test_airflow_monitoring_rbac.py
+++ b/airship_tempest_plugin/tests/api/shipyard/rbac/test_airflow_monitoring_rbac.py
@@ -18,18 +18,30 @@ from airship_tempest_plugin.tests.api.shipyard.rbac import rbac_base
18 18
19from patrole_tempest_plugin import rbac_rule_validation 19from patrole_tempest_plugin import rbac_rule_validation
20 20
21from tempest.common import utils
22from tempest.lib import decorators 21from tempest.lib import decorators
23from tempest.lib.common.utils import data_utils 22from tempest.lib import exceptions
24from tempest.lib.common.utils import test_utils
25 23
26from tempest.api.identity import base
27 24
28class AirflowMonitoringRbacTest(rbac_base.BaseShipyardRbacTest): 25class AirflowMonitoringRbacTest(rbac_base.BaseShipyardRbacTest):
29 26
30 @rbac_rule_validation.action(service="shipyard", 27 @rbac_rule_validation.action(
31 rules=["get_configdocs"]) 28 service="shipyard",
32 @decorators.idempotent_id('0ab53b15-bce9-494f-9a11-34dd2c44d699') 29 rules=["workflow_orchestrator:list_workflows"])
33 def test_get_workflows(self): 30 @decorators.idempotent_id('fc75a269-04cb-4a8d-a627-907f72081b8a')
31 def test_list_workflows(self):
34 with self.rbac_utils.override_role(self): 32 with self.rbac_utils.override_role(self):
35 self.shipyard_airflow_monitoring_client.get_workflows() 33 self.shipyard_airflow_monitoring_client.list_workflows()
34
35 @rbac_rule_validation.action(
36 service="shipyard",
37 rules=["workflow_orchestrator:get_workflow"])
38 @decorators.idempotent_id('1679c5fa-571a-4af8-8f14-ca0c0a49761b')
39 def test_get_workflow(self):
40 with self.rbac_utils.override_role(self):
41 # As this is a RBAC test, we only care about whether the role has
42 # permission or not. Role permission is checked prior to validating
43 # the post body, therefore we will ignore a BadRequest exception
44 try:
45 self.shipyard_airflow_monitoring_client.get_workflow()
46 except exceptions.BadRequest:
47 pass
diff --git a/airship_tempest_plugin/tests/api/shipyard/rbac/test_document_staging_rbac.py b/airship_tempest_plugin/tests/api/shipyard/rbac/test_document_staging_rbac.py
index 26970fa..d7a02f2 100644
--- a/airship_tempest_plugin/tests/api/shipyard/rbac/test_document_staging_rbac.py
+++ b/airship_tempest_plugin/tests/api/shipyard/rbac/test_document_staging_rbac.py
@@ -18,71 +18,81 @@ from airship_tempest_plugin.tests.api.shipyard.rbac import rbac_base
18 18
19from patrole_tempest_plugin import rbac_rule_validation 19from patrole_tempest_plugin import rbac_rule_validation
20 20
21from tempest.common import utils
22from tempest.lib import decorators 21from tempest.lib import decorators
23from tempest.lib import exceptions 22from tempest.lib import exceptions
24from tempest.lib.common.utils import data_utils
25from tempest.lib.common.utils import test_utils
26 23
27from tempest.api.identity import base
28 24
29class DocumentStagingRbacTest(rbac_base.BaseShipyardRbacTest): 25class DocumentStagingRbacTest(rbac_base.BaseShipyardRbacTest):
30 26
31 @rbac_rule_validation.action(service="shipyard", 27 @rbac_rule_validation.action(
32 rules=["get_configdocs"]) 28 service="shipyard",
29 rules=["workflow_orchestrator:get_configdocs_status"])
33 @decorators.idempotent_id('0ab53b15-bce9-494f-9a11-34dd2c44d699') 30 @decorators.idempotent_id('0ab53b15-bce9-494f-9a11-34dd2c44d699')
34 def test_get_configdocs(self): 31 def test_get_configdocs_status(self):
35 with self.rbac_utils.override_role(self): 32 with self.rbac_utils.override_role(self):
36 self.shipyard_document_staging_client.get_configdocs() 33 # As this is a RBAC test, we only care about whether the role has
34 # permission or not. Role permission is checked prior to validating
35 # the request body, therefore we will ignore a ValueError exception
36 try:
37 self.shipyard_document_staging_client.get_configdocs_status()
38 except ValueError:
39 pass
37 40
38 @rbac_rule_validation.action(service="shipyard", 41 @rbac_rule_validation.action(
39 rules=["post_configdocs"]) 42 service="shipyard",
43 rules=["workflow_orchestrator:create_configdocs"])
40 @decorators.idempotent_id('1a0daf92-9dba-470c-a317-66b41c0b3df7') 44 @decorators.idempotent_id('1a0daf92-9dba-470c-a317-66b41c0b3df7')
41 def test_post_configdocs(self): 45 def test_create_configdocs(self):
42 with self.rbac_utils.override_role(self): 46 with self.rbac_utils.override_role(self):
43 # As this is a RBAC test, we only care about whether the role has 47 # As this is a RBAC test, we only care about whether the role has
44 # permission or not. Role permission is checked prior to validating 48 # permission or not. Role permission is checked prior to validating
45 # the post body, therefore we will ignore a BadRequest exception 49 # the request body, therefore we will ignore a BadRequest exception
50 # and Conflict exception
46 try: 51 try:
47 self.shipyard_document_staging_client.post_configdocs() 52 self.shipyard_document_staging_client.create_configdocs()
48 except exceptions.BadRequest: 53 except (exceptions.BadRequest, exceptions.Conflict):
49 pass 54 pass
50 55
51 @rbac_rule_validation.action(service="shipyard", 56 @rbac_rule_validation.action(
52 rules=["get_configdocs_within_collection"]) 57 service="shipyard",
58 rules=["workflow_orchestrator:get_configdocs"])
53 @decorators.idempotent_id('d64cfa75-3bbe-4688-8849-db5a54ce98ea') 59 @decorators.idempotent_id('d64cfa75-3bbe-4688-8849-db5a54ce98ea')
54 def test_get_configdocs_within_collection(self): 60 def test_get_configdocs(self):
55 with self.rbac_utils.override_role(self): 61 with self.rbac_utils.override_role(self):
56 # As this is a RBAC test, we only care about whether the role has 62 # As this is a RBAC test, we only care about whether the role has
57 # permission or not. Role permission is checked prior to validating 63 # permission or not. Role permission is checked prior to validating
58 # the post body, therefore we will ignore a NotFound exception 64 # the request body, therefore we will ignore a NotFound exception
59 try: 65 try:
60 self.shipyard_document_staging_client.get_configdocs_within_collection() 66 self.shipyard_document_staging_client.get_configdocs()
61 except exceptions.NotFound: 67 except exceptions.NotFound:
62 pass 68 pass
63 69
64 @rbac_rule_validation.action(service="shipyard", 70 @rbac_rule_validation.action(
65 rules=["get_renderedconfigdocs"]) 71 service="shipyard",
66 @decorators.idempotent_id('0ab53b15-bce9-494f-9a11-34dd2c44d699') 72 rules=["workflow_orchestrator:get_renderedconfigdocs"])
73 @decorators.idempotent_id('76e81d8d-4e06-42f8-9c9d-082020674994')
67 def test_get_renderedconfigdocs(self): 74 def test_get_renderedconfigdocs(self):
68 with self.rbac_utils.override_role(self): 75 with self.rbac_utils.override_role(self):
69 # As this is a RBAC test, we only care about whether the role has 76 # As this is a RBAC test, we only care about whether the role has
70 # permission or not. Role permission is checked prior to validating 77 # permission or not. Role permission is checked prior to validating
71 # the post body, therefore we will ignore a NotFound exception 78 # the request body, therefore we will ignore a NotFound exception
79 # and ServerFault exception
72 try: 80 try:
73 self.shipyard_document_staging_client.get_renderedconfigdocs() 81 self.shipyard_document_staging_client.get_renderedconfigdocs()
74 except exceptions.NotFound: 82 except (exceptions.NotFound, exceptions.ServerFault):
75 pass 83 pass
76 84
77 @rbac_rule_validation.action(service="shipyard", 85 @rbac_rule_validation.action(
78 rules=["post_commitconfigdocs"]) 86 service="shipyard",
87 rules=["workflow_orchestrator:commit_configdocs"])
79 @decorators.idempotent_id('200d1cbf-ca11-4b92-9cfd-6cd2a90bc919') 88 @decorators.idempotent_id('200d1cbf-ca11-4b92-9cfd-6cd2a90bc919')
80 def test_post_commitconfigdocs(self): 89 def test_commit_configdocs(self):
81 with self.rbac_utils.override_role(self): 90 with self.rbac_utils.override_role(self):
82 # As this is a RBAC test, we only care about whether the role has 91 # As this is a RBAC test, we only care about whether the role has
83 # permission or not. Role permission is checked prior to validating 92 # permission or not. Role permission is checked prior to validating
84 # the post body, therefore we will ignore a Conflict exception 93 # the request body, therefore we will ignore a Conflict exception
94 # and BadRequest exception
85 try: 95 try:
86 self.shipyard_document_staging_client.post_commitconfigdocs() 96 self.shipyard_document_staging_client.commit_configdocs()
87 except exceptions.Conflict: 97 except (exceptions.Conflict, exceptions.BadRequest):
88 pass 98 pass
diff --git a/airship_tempest_plugin/tests/api/shipyard/rbac/test_log_retrieval_rbac.py b/airship_tempest_plugin/tests/api/shipyard/rbac/test_log_retrieval_rbac.py
new file mode 100644
index 0000000..c83a284
--- /dev/null
+++ b/airship_tempest_plugin/tests/api/shipyard/rbac/test_log_retrieval_rbac.py
@@ -0,0 +1,39 @@
1# Copyright 2018 AT&T Corp
2# All Rights Reserved.
3#
4# Licensed under the Apache License, Version 2.0 (the "License"); you may
5# not use this file except in compliance with the License. You may obtain
6# a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13# License for the specific language governing permissions and limitations
14# under the License.
15#
16
17from airship_tempest_plugin.tests.api.shipyard.rbac import rbac_base
18
19from patrole_tempest_plugin import rbac_rule_validation
20
21from tempest.lib import decorators
22from tempest.lib import exceptions
23
24
25class LogRetrievalRbacTest(rbac_base.BaseShipyardRbacTest):
26
27 @rbac_rule_validation.action(
28 service="shipyard",
29 rules=["workflow_orchestrator:get_action_step_logs"])
30 @decorators.idempotent_id('5fd2c572-a226-482d-bdce-70d3ffcd7495')
31 def test_get_action_step_logs(self):
32 with self.rbac_utils.override_role(self):
33 # As this is a RBAC test, we only care about whether the role has
34 # permission or not. Role permission is checked prior to validating
35 # the post body, therefore we will ignore a BadRequest exception
36 try:
37 self.shipyard_log_retrieval_client.get_action_step_logs()
38 except exceptions.BadRequest:
39 pass
diff --git a/airship_tempest_plugin/tests/unit/__init__.py b/airship_tempest_plugin/tests/unit/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/airship_tempest_plugin/tests/unit/__init__.py
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 0000000..cc13aa9
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1,9 @@
1# The order of packages is significant, because pip processes them in the order
2# of appearance. Changing the order has an impact on the overall integration
3# process, which may cause wedges in the gate later.
4pbr!=2.1.0,>=2.0.0 # Apache-2.0
5oslo.log>=3.36.0 # Apache-2.0
6oslo.config>=5.2.0 # Apache-2.0
7oslo.policy>=1.30.0 # Apache-2.0
8tempest>=17.1.0 # Apache-2.0
9stevedore>=1.20.0 # Apache-2.0
diff --git a/test-requirements.txt b/test-requirements.txt
new file mode 100644
index 0000000..9085c07
--- /dev/null
+++ b/test-requirements.txt
@@ -0,0 +1,10 @@
1# The order of packages is significant, because pip processes them in the order
2# of appearance. Changing the order has an impact on the overall integration
3# process, which may cause wedges in the gate later.
4hacking>=1.1.0,<1.2.0 # Apache-2.0
5fixtures>=3.0.0 # Apache-2.0/BSD
6mock>=2.0.0 # BSD
7coverage!=4.4,>=4.0 # Apache-2.0
8nose>=1.3.7 # LGPL
9nosexcover>=1.0.10 # BSD
10oslotest>=3.2.0 # Apache-2.0
diff --git a/tox.ini b/tox.ini
new file mode 100644
index 0000000..3086344
--- /dev/null
+++ b/tox.ini
@@ -0,0 +1,104 @@
1[tox]
2minversion = 1.6
3envlist = pep8,py35,py27
4skipsdist = True
5
6[testenv]
7usedevelop = True
8install_command = pip install -c{env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt} {opts} {packages}
9setenv =
10 VIRTUAL_ENV={envdir}
11 OS_TEST_PATH=./airship_tempest_plugin/tests/unit
12 LANGUAGE=en_US
13 LC_ALL=en_US.utf-8
14 PYTHONWARNINGS=default::DeprecationWarning
15passenv = OS_STDOUT_CAPTURE OS_STDERR_CAPTURE OS_TEST_TIMEOUT OS_TEST_LOCK_PATH http_proxy HTTP_PROXY https_proxy HTTPS_PROXY no_proxy NO_PROXY
16whitelist_externals = find
17deps = -r{toxinidir}/requirements.txt
18 -r{toxinidir}/test-requirements.txt
19commands =
20 find . -type f -name "*.pyc" -delete
21 stestr --test-path ./airship_tempest_plugin/tests/unit run {posargs}
22
23[testenv:pep8]
24basepython = python3
25commands = flake8 {posargs}
26 check-uuid --package airship_tempest_plugin.tests.api
27
28[testenv:uuidgen]
29basepython = python3
30commands = check-uuid --package airship_tempest_plugin.tests.api --fix
31
32[testenv:venv]
33basepython = python3
34commands = {posargs}
35
36[testenv:cover]
37basepython = python3
38commands = rm -rf *.pyc
39 rm -rf cover
40 rm -f .coverage
41 nosetests {posargs}
42setenv = VIRTUAL_ENV={envdir}
43 NOSE_WITH_COVERAGE=1
44 NOSE_COVER_BRANCHES=1
45 NOSE_COVER_PACKAGE=airship_tempest_plugin
46 NOSE_COVER_HTML=1
47 NOSE_COVER_HTML_DIR={toxinidir}/cover
48 NOSE_WHERE=airship_tempest_plugin/tests/unit
49whitelist_externals = nosetests
50 rm
51
52[testenv:docs]
53basepython = python3
54deps =
55 -c{env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt}
56 -r{toxinidir}/requirements.txt
57 -r{toxinidir}/doc/requirements.txt
58commands =
59 rm -rf doc/build
60 sphinx-build -W -b html doc/source doc/build/html
61whitelist_externals = rm
62
63[testenv:releasenotes]
64basepython = python3
65deps =
66 -c{env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt}
67 -r{toxinidir}/requirements.txt
68 -r{toxinidir}/doc/requirements.txt
69commands =
70 rm -rf releasenotes/build
71 sphinx-build -a -E -W -d releasenotes/build/doctrees -b html releasenotes/source releasenotes/build/html
72whitelist_externals = rm
73
74[testenv:debug]
75basepython = python3
76commands = oslo_debug_helper -t airship_tempest_plugin/tests {posargs}
77
78[flake8]
79# [H106] Don't put vim configuration in source files.
80# [H203] Use assertIs(Not)None to check for None.
81# [H204] Use assert(Not)Equal to check for equality.
82# [H205] Use assert(Greater|Less)(Equal) for comparison.
83# [H210] Require 'autospec', 'spec', or 'spec_set' in mock.patch/mock.patch.object calls
84# [H904] Delay string interpolations at logging calls.
85enable-extensions = H106,H203,H204,H205,H210,H904
86show-source = True
87# E123, E125 skipped as they are invalid PEP-8.
88#
89# H405 is another one that is good as a guideline, but sometimes
90# multiline doc strings just don't have a natural summary
91# line. Rejecting code for this reason is wrong.
92ignore = E123,E125,H405
93builtins = _
94exclude=.venv,.git,.tox,dist,doc,*lib/python*,*egg,build
95
96[hacking]
97local-check-factory = airship_tempest_plugin.hacking.checks.factory
98
99[testenv:lower-constraints]
100basepython = python3
101deps =
102 -c{toxinidir}/lower-constraints.txt
103 -r{toxinidir}/test-requirements.txt
104 -r{toxinidir}/requirements.txt