blob: 84c6d9a8283c82e238e4fb3e52f7efefb518f89b [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()
Prateek Aroraa028de12017-03-14 09:01:03 -0400163
Matthew Treinishf9902ec2018-02-22 12:11:46 -0500164 regex = self._build_regex(parsed_args)
Masayuki Igawaff07eac2018-02-22 16:53:09 +0900165 return_code = 0
Matthew Treinishf9902ec2018-02-22 12:11:46 -0500166 if parsed_args.list_tests:
167 return_code = commands.list_command(
168 filters=regex, whitelist_file=parsed_args.whitelist_file,
Matthew Treinish13869202018-02-22 13:46:02 -0500169 blacklist_file=parsed_args.blacklist_file,
170 black_regex=parsed_args.black_regex)
Matthew Treinishf9902ec2018-02-22 12:11:46 -0500171
ghanshyam29981172018-02-23 05:25:28 +0000172 else:
Chandan Kumar8a4396e2017-09-15 12:18:10 +0530173 serial = not parsed_args.parallel
174 return_code = commands.run_command(
175 filters=regex, subunit_out=parsed_args.subunit,
176 serial=serial, concurrency=parsed_args.concurrency,
177 blacklist_file=parsed_args.blacklist_file,
178 whitelist_file=parsed_args.whitelist_file,
Matthew Treinish13869202018-02-22 13:46:02 -0500179 black_regex=parsed_args.black_regex,
Chandan Kumar8a4396e2017-09-15 12:18:10 +0530180 load_list=parsed_args.load_list, combine=parsed_args.combine)
Matthew Treinish7d6e48c2017-03-03 12:44:50 -0500181 if return_code > 0:
182 sys.exit(return_code)
Chandan Kumar8a4396e2017-09-15 12:18:10 +0530183 return return_code
Matthew Treinisha051c222016-05-23 15:48:22 -0400184
185 def get_description(self):
186 return 'Run tempest'
187
Prateek Aroraa028de12017-03-14 09:01:03 -0400188 def _init_state(self):
189 print("Initializing saved state.")
190 data = {}
191 self.global_services = cleanup_service.get_global_cleanup_services()
ghanshyam009a1f62017-08-08 10:22:57 +0300192 self.admin_mgr = clients.Manager(
193 credentials.get_configured_admin_credentials())
Prateek Aroraa028de12017-03-14 09:01:03 -0400194 admin_mgr = self.admin_mgr
195 kwargs = {'data': data,
196 'is_dry_run': False,
197 'saved_state_json': data,
198 'is_preserve': False,
199 'is_save_state': True}
200 for service in self.global_services:
201 svc = service(admin_mgr, **kwargs)
202 svc.run()
203
204 with open(SAVED_STATE_JSON, 'w+') as f:
205 f.write(json.dumps(data,
206 sort_keys=True, indent=2, separators=(',', ': ')))
207
Matthew Treinisha051c222016-05-23 15:48:22 -0400208 def get_parser(self, prog_name):
209 parser = super(TempestRun, self).get_parser(prog_name)
210 parser = self._add_args(parser)
211 return parser
212
213 def _add_args(self, parser):
Matthew Treinishc89a9512016-06-09 17:43:35 -0400214 # workspace args
215 parser.add_argument('--workspace', default=None,
216 help='Name of tempest workspace to use for running'
217 ' tests. You can see a list of workspaces '
218 'with tempest workspace list')
219 parser.add_argument('--workspace-path', default=None,
220 dest='workspace_path',
221 help="The path to the workspace file, the default "
222 "is ~/.tempest/workspace.yaml")
Matthew Treinish30c9ee52016-06-09 17:58:47 -0400223 # Configuration flags
224 parser.add_argument('--config-file', default=None, dest='config_file',
225 help='Configuration file to run tempest with')
Matthew Treinisha051c222016-05-23 15:48:22 -0400226 # test selection args
227 regex = parser.add_mutually_exclusive_group()
Nicolas Bockff27d3b2017-01-11 13:30:32 -0700228 regex.add_argument('--smoke', '-s', action='store_true',
Matthew Treinisha051c222016-05-23 15:48:22 -0400229 help="Run the smoke tests only")
230 regex.add_argument('--regex', '-r', default='',
Chandan Kumar8a4396e2017-09-15 12:18:10 +0530231 help='A normal stestr selection regex used to '
Matthew Treinisha051c222016-05-23 15:48:22 -0400232 'specify a subset of tests to run')
Matthew Treinish13869202018-02-22 13:46:02 -0500233 parser.add_argument('--black-regex', dest='black_regex',
234 help='A regex to exclude tests that match it')
Matthew Treinish3e97aae2018-02-22 13:39:59 -0500235 parser.add_argument('--whitelist-file', '--whitelist_file',
236 help="Path to a whitelist file, this file "
237 "contains a separate regex on each "
238 "newline.")
239 parser.add_argument('--blacklist-file', '--blacklist_file',
240 help='Path to a blacklist file, this file '
241 'contains a separate regex exclude on '
242 'each newline')
243 parser.add_argument('--load-list', '--load_list',
244 help='Path to a non-regex whitelist file, '
baiwenteng781fe072018-06-11 17:39:20 +0800245 'this file contains a separate test '
Matthew Treinish3e97aae2018-02-22 13:39:59 -0500246 'on each newline. This command'
247 'supports files created by the tempest'
248 'run ``--list-tests`` command')
Matthew Treinisha051c222016-05-23 15:48:22 -0400249 # list only args
250 parser.add_argument('--list-tests', '-l', action='store_true',
251 help='List tests',
252 default=False)
Puneet Arora9ed41042016-07-05 19:46:06 +0000253 # execution args
Matthew Treinisha051c222016-05-23 15:48:22 -0400254 parser.add_argument('--concurrency', '-w',
255 help="The number of workers to use, defaults to "
256 "the number of cpus")
257 parallel = parser.add_mutually_exclusive_group()
258 parallel.add_argument('--parallel', dest='parallel',
259 action='store_true',
260 help='Run tests in parallel (this is the'
261 ' default)')
Nicolas Bockff27d3b2017-01-11 13:30:32 -0700262 parallel.add_argument('--serial', '-t', dest='parallel',
Matthew Treinisha051c222016-05-23 15:48:22 -0400263 action='store_false',
264 help='Run tests serially')
Prateek Aroraa028de12017-03-14 09:01:03 -0400265 parser.add_argument('--save-state', dest='state',
266 action='store_true',
267 help="To save the state of the cloud before "
268 "running tempest.")
Matthew Treinisha051c222016-05-23 15:48:22 -0400269 # output args
270 parser.add_argument("--subunit", action='store_true',
271 help='Enable subunit v2 output')
Matthew Treinish7d6e48c2017-03-03 12:44:50 -0500272 parser.add_argument("--combine", action='store_true',
273 help='Combine the output of this run with the '
274 "previous run's as a combined stream in the "
Chandan Kumar8a4396e2017-09-15 12:18:10 +0530275 "stestr repository after it finish")
Matthew Treinisha051c222016-05-23 15:48:22 -0400276
277 parser.set_defaults(parallel=True)
278 return parser
279
280 def _build_regex(self, parsed_args):
Chandan Kumar8a4396e2017-09-15 12:18:10 +0530281 regex = None
Matthew Treinisha051c222016-05-23 15:48:22 -0400282 if parsed_args.smoke:
Chandan Kumar8a4396e2017-09-15 12:18:10 +0530283 regex = ['smoke']
Matthew Treinisha051c222016-05-23 15:48:22 -0400284 elif parsed_args.regex:
Chandan Kumar8a4396e2017-09-15 12:18:10 +0530285 regex = parsed_args.regex.split()
Matthew Treinisha051c222016-05-23 15:48:22 -0400286 return regex