blob: a27425c2bf70d8d1fa33732e96c235b7e9dfa24a [file] [log] [blame]
Matthew Treinisha051c222016-05-23 15:48:22 -04001# Licensed under the Apache License, Version 2.0 (the "License"); you may
2# not use this file except in compliance with the License. You may obtain
3# a copy of the License at
4#
5# http://www.apache.org/licenses/LICENSE-2.0
6#
7# Unless required by applicable law or agreed to in writing, software
8# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10# License for the specific language governing permissions and limitations
11# under the License.
12
13"""
14Runs tempest tests
15
16This command is used for running the tempest tests
17
18Test Selection
19==============
20Tempest run has several options:
21
Chandan Kumar8a4396e2017-09-15 12:18:10 +053022 * **--regex/-r**: This is a selection regex like what stestr uses. It will run
23 any tests that match on re.match() with the regex
24 * **--smoke/-s**: Run all the tests tagged as smoke
Matthew Treinish13869202018-02-22 13:46:02 -050025 * **--black-regex**: It allows to do simple test exclusion via passing a
26 rejection/black regexp
Matthew Treinisha051c222016-05-23 15:48:22 -040027
Masayuki Igawabbbaad62017-11-21 16:04:03 +090028There are also the ``--blacklist-file`` and ``--whitelist-file`` options that
Matthew Treinisha6b4da92016-05-23 17:24:12 -040029let you pass a filepath to tempest run with the file format being a line
zhangyanxian68d31b82016-07-13 01:48:33 +000030separated regex, with '#' used to signify the start of a comment on a line.
Matthew Treinisha6b4da92016-05-23 17:24:12 -040031For example::
32
33 # Regex file
34 ^regex1 # Match these tests
35 .*regex2 # Match those tests
36
Matthew Treinish3e97aae2018-02-22 13:39:59 -050037These arguments are just passed into stestr, you can refer to the stestr
38selection docs for more details on how these operate:
39http://stestr.readthedocs.io/en/latest/MANUAL.html#test-selection
Matthew Treinisha6b4da92016-05-23 17:24:12 -040040
Masayuki Igawabbbaad62017-11-21 16:04:03 +090041You can also use the ``--list-tests`` option in conjunction with selection
Matthew Treinisha051c222016-05-23 15:48:22 -040042arguments to list which tests will be run.
43
Masayuki Igawabbbaad62017-11-21 16:04:03 +090044You can also use the ``--load-list`` option that lets you pass a filepath to
ubuntu0dba54c2017-07-25 15:25:22 -050045tempest run with the file format being in a non-regex format, similar to the
Masayuki Igawabbbaad62017-11-21 16:04:03 +090046tests generated by the ``--list-tests`` option. You can specify target tests
ubuntu0dba54c2017-07-25 15:25:22 -050047by removing unnecessary tests from a list file which is generated from
Masayuki Igawabbbaad62017-11-21 16:04:03 +090048``--list-tests`` option.
ubuntu0dba54c2017-07-25 15:25:22 -050049
Matthew Treinisha051c222016-05-23 15:48:22 -040050Test Execution
51==============
52There are several options to control how the tests are executed. By default
53tempest will run in parallel with a worker for each CPU present on the machine.
Masayuki Igawabbbaad62017-11-21 16:04:03 +090054If you want to adjust the number of workers use the ``--concurrency`` option
55and if you want to run tests serially use ``--serial/-t``
Matthew Treinisha051c222016-05-23 15:48:22 -040056
Matthew Treinishc89a9512016-06-09 17:43:35 -040057Running with Workspaces
58-----------------------
59Tempest run enables you to run your tempest tests from any setup tempest
60workspace it relies on you having setup a tempest workspace with either the
61``tempest init`` or ``tempest workspace`` commands. Then using the
62``--workspace`` CLI option you can specify which one of your workspaces you
63want to run tempest from. Using this option you don't have to run Tempest
64directly with you current working directory being the workspace, Tempest will
65take care of managing everything to be executed from there.
66
Matthew Treinish30c9ee52016-06-09 17:58:47 -040067Running from Anywhere
68---------------------
69Tempest run provides you with an option to execute tempest from anywhere on
70your system. You are required to provide a config file in this case with the
Chandan Kumar8a4396e2017-09-15 12:18:10 +053071``--config-file`` option. When run tempest will create a .stestr
72directory and a .stestr.conf file in your current working directory. This way
73you can use stestr commands directly to inspect the state of the previous run.
Matthew Treinish30c9ee52016-06-09 17:58:47 -040074
Matthew Treinisha051c222016-05-23 15:48:22 -040075Test Output
76===========
77By default tempest run's output to STDOUT will be generated using the
78subunit-trace output filter. But, if you would prefer a subunit v2 stream be
Masayuki Igawabbbaad62017-11-21 16:04:03 +090079output to STDOUT use the ``--subunit`` flag
Matthew Treinisha051c222016-05-23 15:48:22 -040080
Matthew Treinish7d6e48c2017-03-03 12:44:50 -050081Combining Runs
82==============
83
84There are certain situations in which you want to split a single run of tempest
85across 2 executions of tempest run. (for example to run part of the tests
86serially and others in parallel) To accomplish this but still treat the results
Masayuki Igawabbbaad62017-11-21 16:04:03 +090087as a single run you can leverage the ``--combine`` option which will append
Matthew Treinish7d6e48c2017-03-03 12:44:50 -050088the current run's results with the previous runs.
Matthew Treinisha051c222016-05-23 15:48:22 -040089"""
90
Matthew Treinisha051c222016-05-23 15:48:22 -040091import os
92import sys
Matthew Treinisha051c222016-05-23 15:48:22 -040093
94from cliff import command
Prateek Aroraa028de12017-03-14 09:01:03 -040095from oslo_serialization import jsonutils as json
Davanum Srinivas00e3f452017-01-05 12:40:45 -050096import six
Chandan Kumar8a4396e2017-09-15 12:18:10 +053097from stestr import commands
Matthew Treinisha051c222016-05-23 15:48:22 -040098
ghanshyam009a1f62017-08-08 10:22:57 +030099from tempest import clients
Prateek Aroraa028de12017-03-14 09:01:03 -0400100from tempest.cmd import cleanup_service
Matthew Treinish30c9ee52016-06-09 17:58:47 -0400101from tempest.cmd import init
Matthew Treinishc89a9512016-06-09 17:43:35 -0400102from tempest.cmd import workspace
Prateek Aroraa028de12017-03-14 09:01:03 -0400103from tempest.common import credentials_factory as credentials
Matthew Treinisha051c222016-05-23 15:48:22 -0400104from tempest import config
105
106
Matthew Treinisha051c222016-05-23 15:48:22 -0400107CONF = config.CONF
Prateek Aroraa028de12017-03-14 09:01:03 -0400108SAVED_STATE_JSON = "saved_state.json"
Matthew Treinisha051c222016-05-23 15:48:22 -0400109
110
111class TempestRun(command.Command):
112
Matthew Treinish30c9ee52016-06-09 17:58:47 -0400113 def _set_env(self, config_file=None):
114 if config_file:
115 CONF.set_config_path(os.path.abspath(config_file))
Chandan Kumar8a4396e2017-09-15 12:18:10 +0530116 # NOTE(mtreinish): This is needed so that stestr doesn't gobble up any
Matthew Treinisha051c222016-05-23 15:48:22 -0400117 # stacktraces on failure.
118 if 'TESTR_PDB' in os.environ:
119 return
120 else:
121 os.environ["TESTR_PDB"] = ""
Chandan Kumar8a4396e2017-09-15 12:18:10 +0530122 # NOTE(dims): most of our .stestr.conf try to test for PYTHON
Davanum Srinivas00e3f452017-01-05 12:40:45 -0500123 # environment variable and fall back to "python", under python3
124 # if it does not exist. we should set it to the python3 executable
125 # to deal with this situation better for now.
126 if six.PY3 and 'PYTHON' not in os.environ:
127 os.environ['PYTHON'] = sys.executable
Matthew Treinisha051c222016-05-23 15:48:22 -0400128
Chandan Kumar8a4396e2017-09-15 12:18:10 +0530129 def _create_stestr_conf(self):
Matthew Treinish30c9ee52016-06-09 17:58:47 -0400130 top_level_path = os.path.dirname(os.path.dirname(__file__))
131 discover_path = os.path.join(top_level_path, 'test_discover')
Chandan Kumar8a4396e2017-09-15 12:18:10 +0530132 file_contents = init.STESTR_CONF % (discover_path, top_level_path)
133 with open('.stestr.conf', 'w+') as stestr_conf_file:
134 stestr_conf_file.write(file_contents)
Matthew Treinish30c9ee52016-06-09 17:58:47 -0400135
Matthew Treinisha051c222016-05-23 15:48:22 -0400136 def take_action(self, parsed_args):
Matthew Treinish30c9ee52016-06-09 17:58:47 -0400137 if parsed_args.config_file:
138 self._set_env(parsed_args.config_file)
139 else:
140 self._set_env()
Matthew Treinishc89a9512016-06-09 17:43:35 -0400141 # Workspace execution mode
142 if parsed_args.workspace:
143 workspace_mgr = workspace.WorkspaceManager(
144 parsed_args.workspace_path)
145 path = workspace_mgr.get_workspace(parsed_args.workspace)
Brant Knudson6a090f42016-10-13 12:51:49 -0500146 if not path:
147 sys.exit(
148 "The %r workspace isn't registered in "
149 "%r. Use 'tempest init' to "
150 "register the workspace." %
151 (parsed_args.workspace, workspace_mgr.path))
Matthew Treinishc89a9512016-06-09 17:43:35 -0400152 os.chdir(path)
Chandan Kumar8a4396e2017-09-15 12:18:10 +0530153 if not os.path.isfile('.stestr.conf'):
154 self._create_stestr_conf()
Matthew Treinish30c9ee52016-06-09 17:58:47 -0400155 # local execution with config file mode
Masayuki Igawaff07eac2018-02-22 16:53:09 +0900156 elif parsed_args.config_file and not os.path.isfile('.stestr.conf'):
Chandan Kumar8a4396e2017-09-15 12:18:10 +0530157 self._create_stestr_conf()
Chandan Kumar8a4396e2017-09-15 12:18:10 +0530158 elif not os.path.isfile('.stestr.conf'):
159 print("No .stestr.conf file was found for local execution")
Matthew Treinisha051c222016-05-23 15:48:22 -0400160 sys.exit(2)
Prateek Aroraa028de12017-03-14 09:01:03 -0400161 if parsed_args.state:
162 self._init_state()
163 else:
164 pass
165
Matthew Treinishf9902ec2018-02-22 12:11:46 -0500166 regex = self._build_regex(parsed_args)
Masayuki Igawaff07eac2018-02-22 16:53:09 +0900167 return_code = 0
Matthew Treinishf9902ec2018-02-22 12:11:46 -0500168 if parsed_args.list_tests:
169 return_code = commands.list_command(
170 filters=regex, whitelist_file=parsed_args.whitelist_file,
Matthew Treinish13869202018-02-22 13:46:02 -0500171 blacklist_file=parsed_args.blacklist_file,
172 black_regex=parsed_args.black_regex)
Matthew Treinishf9902ec2018-02-22 12:11:46 -0500173
ghanshyam29981172018-02-23 05:25:28 +0000174 else:
Chandan Kumar8a4396e2017-09-15 12:18:10 +0530175 serial = not parsed_args.parallel
176 return_code = commands.run_command(
177 filters=regex, subunit_out=parsed_args.subunit,
178 serial=serial, concurrency=parsed_args.concurrency,
179 blacklist_file=parsed_args.blacklist_file,
180 whitelist_file=parsed_args.whitelist_file,
Matthew Treinish13869202018-02-22 13:46:02 -0500181 black_regex=parsed_args.black_regex,
Chandan Kumar8a4396e2017-09-15 12:18:10 +0530182 load_list=parsed_args.load_list, combine=parsed_args.combine)
Matthew Treinish7d6e48c2017-03-03 12:44:50 -0500183 if return_code > 0:
184 sys.exit(return_code)
Chandan Kumar8a4396e2017-09-15 12:18:10 +0530185 return return_code
Matthew Treinisha051c222016-05-23 15:48:22 -0400186
187 def get_description(self):
188 return 'Run tempest'
189
Prateek Aroraa028de12017-03-14 09:01:03 -0400190 def _init_state(self):
191 print("Initializing saved state.")
192 data = {}
193 self.global_services = cleanup_service.get_global_cleanup_services()
ghanshyam009a1f62017-08-08 10:22:57 +0300194 self.admin_mgr = clients.Manager(
195 credentials.get_configured_admin_credentials())
Prateek Aroraa028de12017-03-14 09:01:03 -0400196 admin_mgr = self.admin_mgr
197 kwargs = {'data': data,
198 'is_dry_run': False,
199 'saved_state_json': data,
200 'is_preserve': False,
201 'is_save_state': True}
202 for service in self.global_services:
203 svc = service(admin_mgr, **kwargs)
204 svc.run()
205
206 with open(SAVED_STATE_JSON, 'w+') as f:
207 f.write(json.dumps(data,
208 sort_keys=True, indent=2, separators=(',', ': ')))
209
Matthew Treinisha051c222016-05-23 15:48:22 -0400210 def get_parser(self, prog_name):
211 parser = super(TempestRun, self).get_parser(prog_name)
212 parser = self._add_args(parser)
213 return parser
214
215 def _add_args(self, parser):
Matthew Treinishc89a9512016-06-09 17:43:35 -0400216 # workspace args
217 parser.add_argument('--workspace', default=None,
218 help='Name of tempest workspace to use for running'
219 ' tests. You can see a list of workspaces '
220 'with tempest workspace list')
221 parser.add_argument('--workspace-path', default=None,
222 dest='workspace_path',
223 help="The path to the workspace file, the default "
224 "is ~/.tempest/workspace.yaml")
Matthew Treinish30c9ee52016-06-09 17:58:47 -0400225 # Configuration flags
226 parser.add_argument('--config-file', default=None, dest='config_file',
227 help='Configuration file to run tempest with')
Matthew Treinisha051c222016-05-23 15:48:22 -0400228 # test selection args
229 regex = parser.add_mutually_exclusive_group()
Nicolas Bockff27d3b2017-01-11 13:30:32 -0700230 regex.add_argument('--smoke', '-s', action='store_true',
Matthew Treinisha051c222016-05-23 15:48:22 -0400231 help="Run the smoke tests only")
232 regex.add_argument('--regex', '-r', default='',
Chandan Kumar8a4396e2017-09-15 12:18:10 +0530233 help='A normal stestr selection regex used to '
Matthew Treinisha051c222016-05-23 15:48:22 -0400234 'specify a subset of tests to run')
Matthew Treinish13869202018-02-22 13:46:02 -0500235 parser.add_argument('--black-regex', dest='black_regex',
236 help='A regex to exclude tests that match it')
Matthew Treinish3e97aae2018-02-22 13:39:59 -0500237 parser.add_argument('--whitelist-file', '--whitelist_file',
238 help="Path to a whitelist file, this file "
239 "contains a separate regex on each "
240 "newline.")
241 parser.add_argument('--blacklist-file', '--blacklist_file',
242 help='Path to a blacklist file, this file '
243 'contains a separate regex exclude on '
244 'each newline')
245 parser.add_argument('--load-list', '--load_list',
246 help='Path to a non-regex whitelist file, '
baiwenteng781fe072018-06-11 17:39:20 +0800247 'this file contains a separate test '
Matthew Treinish3e97aae2018-02-22 13:39:59 -0500248 'on each newline. This command'
249 'supports files created by the tempest'
250 'run ``--list-tests`` command')
Matthew Treinisha051c222016-05-23 15:48:22 -0400251 # list only args
252 parser.add_argument('--list-tests', '-l', action='store_true',
253 help='List tests',
254 default=False)
Puneet Arora9ed41042016-07-05 19:46:06 +0000255 # execution args
Matthew Treinisha051c222016-05-23 15:48:22 -0400256 parser.add_argument('--concurrency', '-w',
257 help="The number of workers to use, defaults to "
258 "the number of cpus")
259 parallel = parser.add_mutually_exclusive_group()
260 parallel.add_argument('--parallel', dest='parallel',
261 action='store_true',
262 help='Run tests in parallel (this is the'
263 ' default)')
Nicolas Bockff27d3b2017-01-11 13:30:32 -0700264 parallel.add_argument('--serial', '-t', dest='parallel',
Matthew Treinisha051c222016-05-23 15:48:22 -0400265 action='store_false',
266 help='Run tests serially')
Prateek Aroraa028de12017-03-14 09:01:03 -0400267 parser.add_argument('--save-state', dest='state',
268 action='store_true',
269 help="To save the state of the cloud before "
270 "running tempest.")
Matthew Treinisha051c222016-05-23 15:48:22 -0400271 # output args
272 parser.add_argument("--subunit", action='store_true',
273 help='Enable subunit v2 output')
Matthew Treinish7d6e48c2017-03-03 12:44:50 -0500274 parser.add_argument("--combine", action='store_true',
275 help='Combine the output of this run with the '
276 "previous run's as a combined stream in the "
Chandan Kumar8a4396e2017-09-15 12:18:10 +0530277 "stestr repository after it finish")
Matthew Treinisha051c222016-05-23 15:48:22 -0400278
279 parser.set_defaults(parallel=True)
280 return parser
281
282 def _build_regex(self, parsed_args):
Chandan Kumar8a4396e2017-09-15 12:18:10 +0530283 regex = None
Matthew Treinisha051c222016-05-23 15:48:22 -0400284 if parsed_args.smoke:
Chandan Kumar8a4396e2017-09-15 12:18:10 +0530285 regex = ['smoke']
Matthew Treinisha051c222016-05-23 15:48:22 -0400286 elif parsed_args.regex:
Chandan Kumar8a4396e2017-09-15 12:18:10 +0530287 regex = parsed_args.regex.split()
Matthew Treinisha051c222016-05-23 15:48:22 -0400288 return regex