blob: c666c96e21579230e3c0a21e54a0d5a003132a28 [file] [log] [blame]
Giampaolo Lauria1b837ce2013-05-01 11:22:07 -04001# Copyright 2013 IBM Corp.
2#
3# Licensed under the Apache License, Version 2.0 (the "License"); you may
4# not use this file except in compliance with the License. You may obtain
5# a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12# License for the specific language governing permissions and limitations
13# under the License.
14
Matthew Treinish662bc3c2014-04-07 17:55:39 -040015import os
Giampaolo Lauria1b837ce2013-05-01 11:22:07 -040016import re
17
Matthew Treinishaaa35952014-05-02 18:50:16 -040018import pep8
19
Giampaolo Lauria1b837ce2013-05-01 11:22:07 -040020
Matthew Treinish7d710f92014-03-15 21:29:08 -040021PYTHON_CLIENTS = ['cinder', 'glance', 'keystone', 'nova', 'swift', 'neutron',
22 'trove', 'ironic', 'savanna', 'heat', 'ceilometer',
Matthew Treinishfc112642016-02-18 17:42:15 -050023 'sahara']
Giampaolo Lauriab8424eb2013-05-23 15:56:21 -040024
Giampaolo Lauriab8424eb2013-05-23 15:56:21 -040025PYTHON_CLIENT_RE = re.compile('import (%s)client' % '|'.join(PYTHON_CLIENTS))
Matthew Treinish6ba951a2013-09-09 22:06:18 +000026TEST_DEFINITION = re.compile(r'^\s*def test.*')
Andrea Frittoli41fa16d2014-09-15 13:41:37 +010027SETUP_TEARDOWN_CLASS_DEFINITION = re.compile(r'^\s+def (setUp|tearDown)Class')
Matthew Treinish662bc3c2014-04-07 17:55:39 -040028SCENARIO_DECORATOR = re.compile(r'\s*@.*services\((.*)\)')
Masayuki Igawafcacf962014-02-19 14:00:01 +090029VI_HEADER_RE = re.compile(r"^#\s+vim?:.+")
Ken'ichi Ohmichi80369a92015-04-06 23:41:14 +000030RAND_NAME_HYPHEN_RE = re.compile(r".*rand_name\(.+[\-\_][\"\']\)")
Ghanshyam2a180b82014-06-16 13:54:22 +090031mutable_default_args = re.compile(r"^\s*def .+\((.+=\{\}|.+=\[\])")
John Warren3059a092015-08-31 15:34:49 -040032TESTTOOLS_SKIP_DECORATOR = re.compile(r'\s*@testtools\.skip\((.*)\)')
Ken'ichi Ohmichic0d96be2015-11-11 12:33:48 +000033METHOD = re.compile(r"^ def .+")
34METHOD_GET_RESOURCE = re.compile(r"^\s*def (list|show)\_.+")
Ken'ichi Ohmichib8461cb2015-11-20 08:10:51 +000035METHOD_DELETE_RESOURCE = re.compile(r"^\s*def delete_.+")
Ken'ichi Ohmichic0d96be2015-11-11 12:33:48 +000036CLASS = re.compile(r"^class .+")
Giampaolo Lauria1b837ce2013-05-01 11:22:07 -040037
38
ghanshyam50f19472014-11-26 17:04:37 +090039def import_no_clients_in_api_and_scenario_tests(physical_line, filename):
40 """Check for client imports from tempest/api & tempest/scenario tests
Giampaolo Lauria1b837ce2013-05-01 11:22:07 -040041
Giampaolo Lauriab8424eb2013-05-23 15:56:21 -040042 T102: Cannot import OpenStack python clients
43 """
Giampaolo Lauria1b837ce2013-05-01 11:22:07 -040044
ghanshyam50f19472014-11-26 17:04:37 +090045 if "tempest/api" in filename or "tempest/scenario" in filename:
Giampaolo Lauriab8424eb2013-05-23 15:56:21 -040046 res = PYTHON_CLIENT_RE.match(physical_line)
47 if res:
48 return (physical_line.find(res.group(1)),
49 ("T102: python clients import not allowed"
ghanshyam50f19472014-11-26 17:04:37 +090050 " in tempest/api/* or tempest/scenario/* tests"))
Giampaolo Lauriad50c27d2013-05-23 15:23:12 -040051
52
Matthew Treinish6ba951a2013-09-09 22:06:18 +000053def scenario_tests_need_service_tags(physical_line, filename,
54 previous_logical):
55 """Check that scenario tests have service tags
56
57 T104: Scenario tests require a services decorator
58 """
59
Matthew Treinishb12ad762014-06-19 10:18:05 -040060 if 'tempest/scenario/' in filename and '/test_' in filename:
Matthew Treinish6ba951a2013-09-09 22:06:18 +000061 if TEST_DEFINITION.match(physical_line):
62 if not SCENARIO_DECORATOR.match(previous_logical):
63 return (physical_line.find('def'),
64 "T104: Scenario tests require a service decorator")
65
66
Andrea Frittoli41fa16d2014-09-15 13:41:37 +010067def no_setup_teardown_class_for_tests(physical_line, filename):
Matthew Treinishaaa35952014-05-02 18:50:16 -040068
69 if pep8.noqa(physical_line):
70 return
71
Matthew Treinish9e26ca82016-02-23 11:43:20 -050072 if 'tempest/test.py' in filename or 'tempest/lib/' in filename:
73 return
74
75 if SETUP_TEARDOWN_CLASS_DEFINITION.match(physical_line):
76 return (physical_line.find('def'),
77 "T105: (setUp|tearDown)Class can not be used in tests")
Matthew Treinishecf212c2013-12-06 18:23:54 +000078
79
Masayuki Igawafcacf962014-02-19 14:00:01 +090080def no_vi_headers(physical_line, line_number, lines):
81 """Check for vi editor configuration in source files.
82
83 By default vi modelines can only appear in the first or
84 last 5 lines of a source file.
85
86 T106
87 """
88 # NOTE(gilliard): line_number is 1-indexed
89 if line_number <= 5 or line_number > len(lines) - 5:
90 if VI_HEADER_RE.match(physical_line):
91 return 0, "T106: Don't put vi configuration in source files"
92
93
Matthew Treinish662bc3c2014-04-07 17:55:39 -040094def service_tags_not_in_module_path(physical_line, filename):
95 """Check that a service tag isn't in the module path
96
97 A service tag should only be added if the service name isn't already in
98 the module path.
99
100 T107
101 """
102 # NOTE(mtreinish) Scenario tests always need service tags, but subdirs are
103 # created for services like heat which would cause false negatives for
104 # those tests, so just exclude the scenario tests.
105 if 'tempest/scenario' not in filename:
106 matches = SCENARIO_DECORATOR.match(physical_line)
107 if matches:
108 services = matches.group(1).split(',')
109 for service in services:
110 service_name = service.strip().strip("'")
111 modulepath = os.path.split(filename)[0]
112 if service_name in modulepath:
113 return (physical_line.find(service_name),
114 "T107: service tag should not be in path")
115
116
Ken'ichi Ohmichi80369a92015-04-06 23:41:14 +0000117def no_hyphen_at_end_of_rand_name(logical_line, filename):
118 """Check no hyphen at the end of rand_name() argument
119
120 T108
121 """
122 if './tempest/api/network/' in filename:
123 # Network API tests are migrating from Tempest to Neutron repo now.
124 # So here should avoid network API tests checks.
125 return
126
127 msg = "T108: hyphen should not be specified at the end of rand_name()"
128 if RAND_NAME_HYPHEN_RE.match(logical_line):
129 return 0, msg
130
131
Ghanshyam2a180b82014-06-16 13:54:22 +0900132def no_mutable_default_args(logical_line):
133 """Check that mutable object isn't used as default argument
134
135 N322: Method's default argument shouldn't be mutable
136 """
137 msg = "N322: Method's default argument shouldn't be mutable!"
138 if mutable_default_args.match(logical_line):
139 yield (0, msg)
140
141
John Warren3059a092015-08-31 15:34:49 -0400142def no_testtools_skip_decorator(logical_line):
143 """Check that methods do not have the testtools.skip decorator
144
145 T109
146 """
147 if TESTTOOLS_SKIP_DECORATOR.match(logical_line):
148 yield (0, "T109: Cannot use testtools.skip decorator; instead use "
149 "decorators.skip_because from tempest-lib")
150
151
Ken'ichi Ohmichi53346602015-11-20 07:23:54 +0000152def _common_service_clients_check(logical_line, physical_line, filename,
153 ignored_list_file=None):
154 if 'tempest/services/' not in filename:
155 return False
156
157 if ignored_list_file is not None:
158 ignored_list = []
159 with open('tempest/hacking/' + ignored_list_file) as f:
160 for line in f:
161 ignored_list.append(line.strip())
162
163 if filename in ignored_list:
164 return False
165
166 if not METHOD.match(physical_line):
167 return False
168
169 if pep8.noqa(physical_line):
170 return False
171
172 return True
173
174
Ken'ichi Ohmichic0d96be2015-11-11 12:33:48 +0000175def get_resources_on_service_clients(logical_line, physical_line, filename,
176 line_number, lines):
177 """Check that service client names of GET should be consistent
178
179 T110
180 """
Ken'ichi Ohmichi53346602015-11-20 07:23:54 +0000181 if not _common_service_clients_check(logical_line, physical_line,
182 filename, 'ignored_list_T110.txt'):
Ken'ichi Ohmichic0d96be2015-11-11 12:33:48 +0000183 return
184
185 for line in lines[line_number:]:
186 if METHOD.match(line) or CLASS.match(line):
187 # the end of a method
188 return
189
Ken'ichi Ohmichif878e6e2016-01-13 05:10:17 +0000190 if 'self.get(' not in line and ('self.show_resource(' not in line and
191 'self.list_resources(' not in line):
Ken'ichi Ohmichic0d96be2015-11-11 12:33:48 +0000192 continue
193
194 if METHOD_GET_RESOURCE.match(logical_line):
195 return
196
197 msg = ("T110: [GET /resources] methods should be list_<resource name>s"
198 " or show_<resource name>")
199 yield (0, msg)
200
201
Ken'ichi Ohmichib8461cb2015-11-20 08:10:51 +0000202def delete_resources_on_service_clients(logical_line, physical_line, filename,
203 line_number, lines):
204 """Check that service client names of DELETE should be consistent
205
206 T111
207 """
208 if not _common_service_clients_check(logical_line, physical_line,
209 filename, 'ignored_list_T111.txt'):
210 return
211
212 for line in lines[line_number:]:
213 if METHOD.match(line) or CLASS.match(line):
214 # the end of a method
215 return
216
Ken'ichi Ohmichif878e6e2016-01-13 05:10:17 +0000217 if 'self.delete(' not in line and 'self.delete_resource(' not in line:
Ken'ichi Ohmichib8461cb2015-11-20 08:10:51 +0000218 continue
219
220 if METHOD_DELETE_RESOURCE.match(logical_line):
221 return
222
223 msg = ("T111: [DELETE /resources/<id>] methods should be "
224 "delete_<resource name>")
225 yield (0, msg)
226
227
Giampaolo Lauriad50c27d2013-05-23 15:23:12 -0400228def factory(register):
ghanshyam50f19472014-11-26 17:04:37 +0900229 register(import_no_clients_in_api_and_scenario_tests)
Matthew Treinish6ba951a2013-09-09 22:06:18 +0000230 register(scenario_tests_need_service_tags)
Andrea Frittoli41fa16d2014-09-15 13:41:37 +0100231 register(no_setup_teardown_class_for_tests)
Masayuki Igawafcacf962014-02-19 14:00:01 +0900232 register(no_vi_headers)
Matthew Treinish662bc3c2014-04-07 17:55:39 -0400233 register(service_tags_not_in_module_path)
Ken'ichi Ohmichi80369a92015-04-06 23:41:14 +0000234 register(no_hyphen_at_end_of_rand_name)
Ghanshyam2a180b82014-06-16 13:54:22 +0900235 register(no_mutable_default_args)
John Warren3059a092015-08-31 15:34:49 -0400236 register(no_testtools_skip_decorator)
Ken'ichi Ohmichic0d96be2015-11-11 12:33:48 +0000237 register(get_resources_on_service_clients)
Ken'ichi Ohmichib8461cb2015-11-20 08:10:51 +0000238 register(delete_resources_on_service_clients)