Removed the use-keystone option for running tests.
[snaps.git] / snaps / test_runner.py
1 # Copyright (c) 2017 Cable Television Laboratories, Inc. ("CableLabs")
2 #                    and others.  All rights reserved.
3 #
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain 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,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15 import argparse
16 import logging
17 import unittest
18 from concurrencytest import ConcurrentTestSuite, fork_for_tests
19
20 from snaps import file_utils
21 from snaps import test_suite_builder as tsb
22 from snaps.openstack.tests import openstack_tests
23
24 __author__ = 'spisarski'
25
26 logger = logging.getLogger('test_runner')
27
28 ARG_NOT_SET = "argument not set"
29 LOG_LEVELS = {'FATAL': logging.FATAL, 'CRITICAL': logging.CRITICAL,
30               'ERROR': logging.ERROR, 'WARN': logging.WARN,
31               'INFO': logging.INFO, 'DEBUG': logging.DEBUG}
32
33
34 def __create_concurrent_test_suite(
35         source_filename, ext_net_name, proxy_settings, ssh_proxy_cmd,
36         run_unit_tests, run_connection_tests, run_api_tests,
37         run_integration_tests, run_staging_tests, flavor_metadata,
38         image_metadata, use_floating_ips, continuous_integration, log_level):
39     """
40     Compiles the tests that can be run concurrently
41     :param source_filename: the OpenStack credentials file (required)
42     :param ext_net_name: the name of the external network to use for floating
43                          IPs (required)
44     :param run_unit_tests: when true, the tests not requiring OpenStack will be
45                            added to the test suite
46     :param run_connection_tests: when true, the tests that perform simple
47                                  connections to OpenStack are executed
48     :param run_api_tests: when true, the tests that perform simple API calls to
49                           OpenStack are executed
50     :param run_integration_tests: when true, the integration tests are executed
51     :param run_staging_tests: when true, the staging tests are executed
52     :param proxy_settings: <host>:<port> of the proxy server (optional)
53     :param ssh_proxy_cmd: the command used to connect via SSH over some proxy
54                           server (optional)
55     :param flavor_metadata: dict() object containing the metadata for flavors
56                             created for test VM instance
57     :param image_metadata: dict() object containing the metadata for overriding
58                            default images within the tests
59     :param use_floating_ips: when true, tests requiring floating IPs will be
60                              executed
61     :param continuous_integration: when true, tests for CI will be run
62     :param log_level: the logging level
63     :return:
64     """
65     suite = unittest.TestSuite()
66
67     os_creds = openstack_tests.get_credentials(
68         os_env_file=source_filename, proxy_settings_str=proxy_settings,
69         ssh_proxy_cmd=ssh_proxy_cmd)
70
71     # Tests that do not require a remote connection to an OpenStack cloud
72     if run_unit_tests:
73         tsb.add_unit_tests(suite)
74
75     # Basic connection tests
76     if run_connection_tests:
77         tsb.add_openstack_client_tests(
78             suite=suite, os_creds=os_creds, ext_net_name=ext_net_name,
79             use_keystone=True, log_level=log_level)
80
81     # Tests the OpenStack API calls
82     if run_api_tests:
83         tsb.add_openstack_api_tests(
84             suite=suite, os_creds=os_creds, ext_net_name=ext_net_name,
85             use_keystone=True, flavor_metadata=flavor_metadata,
86             image_metadata=image_metadata, log_level=log_level)
87
88     # Long running integration type tests
89     if run_integration_tests:
90         tsb.add_openstack_integration_tests(
91             suite=suite, os_creds=os_creds, ext_net_name=ext_net_name,
92             use_keystone=True, flavor_metadata=flavor_metadata,
93             image_metadata=image_metadata, use_floating_ips=use_floating_ips,
94             log_level=log_level)
95
96     if run_staging_tests:
97         tsb.add_openstack_staging_tests(
98             suite=suite, os_creds=os_creds, ext_net_name=ext_net_name,
99             log_level=log_level)
100
101     if continuous_integration:
102         tsb.add_openstack_ci_tests(
103             suite=suite, os_creds=os_creds, ext_net_name=ext_net_name,
104             use_keystone=True, flavor_metadata=flavor_metadata,
105             image_metadata=image_metadata, use_floating_ips=use_floating_ips,
106             log_level=log_level)
107     return suite
108
109
110 def __create_sequential_test_suite(
111         source_filename, ext_net_name, proxy_settings, ssh_proxy_cmd,
112         run_integration_tests, flavor_metadata, image_metadata,
113         use_floating_ips, log_level):
114     """
115     Compiles the tests that cannot be run in parallel
116     :param source_filename: the OpenStack credentials file (required)
117     :param ext_net_name: the name of the external network to use for floating
118                          IPs (required)
119     :param run_integration_tests: when true, the integration tests are executed
120     :param proxy_settings: <host>:<port> of the proxy server (optional)
121     :param ssh_proxy_cmd: the command used to connect via SSH over some proxy
122                           server (optional)
123     :param flavor_metadata: dict() object containing the metadata for flavors
124                             created for test VM instance
125     :param image_metadata: dict() object containing the metadata for overriding
126                            default images within the tests
127     :param use_floating_ips: when true, tests requiring floating IPs will be
128                              executed
129     :param log_level: the logging level
130     :return:
131     """
132     if use_floating_ips and run_integration_tests:
133         suite = unittest.TestSuite()
134
135         os_creds = openstack_tests.get_credentials(
136             os_env_file=source_filename, proxy_settings_str=proxy_settings,
137             ssh_proxy_cmd=ssh_proxy_cmd)
138
139         tsb.add_ansible_integration_tests(
140                 suite=suite, os_creds=os_creds, ext_net_name=ext_net_name,
141                 use_keystone=True, flavor_metadata=flavor_metadata,
142                 image_metadata=image_metadata, log_level=log_level)
143
144         return suite
145
146
147 def __output_results(results):
148     """
149     Sends the test results to the logger
150     :param results:
151     :return:
152     """
153
154     if results.errors:
155         logger.error('Number of errors in test suite - %s',
156                      len(results.errors))
157         for test, message in results.errors:
158             logger.error(str(test) + " ERROR with " + message)
159
160     if results.failures:
161         logger.error('Number of failures in test suite - %s',
162                      len(results.failures))
163         for test, message in results.failures:
164             logger.error(str(test) + " FAILED with " + message)
165
166
167 def main(arguments):
168     """
169     Begins running unit tests.
170     argv[1] if used must be the source filename else os_env.yaml will be
171     leveraged instead
172     argv[2] if used must be the proxy server <host>:<port>
173     """
174     logger.info('Starting test suite')
175
176     log_level = LOG_LEVELS.get(arguments.log_level, logging.DEBUG)
177
178     flavor_metadata = None
179     if arguments.flavor_metadata:
180         flavor_metadata = {
181             'metadata': {'hw:mem_page_size': arguments.flavor_metadata}}
182
183     image_metadata = None
184     if arguments.image_metadata_file:
185         image_metadata = file_utils.read_yaml(arguments.image_metadata_file)
186
187     concurrent_suite = None
188     sequential_suite = None
189
190     if arguments.env and arguments.ext_net:
191         unit = arguments.include_unit != ARG_NOT_SET
192         connection = arguments.include_connection != ARG_NOT_SET
193         api = arguments.include_api != ARG_NOT_SET
194         integration = arguments.include_integration != ARG_NOT_SET
195         ci = arguments.continuous_integration != ARG_NOT_SET
196         staging = arguments.include_staging != ARG_NOT_SET
197         if (not unit and not connection and not api and not integration
198                 and not staging and not ci):
199             unit = True
200             connection = True
201             api = True
202             integration = True
203
204         concurrent_suite = __create_concurrent_test_suite(
205             arguments.env, arguments.ext_net, arguments.proxy,
206             arguments.ssh_proxy_cmd, unit, connection, api,
207             integration, staging, flavor_metadata, image_metadata,
208             arguments.floating_ips != ARG_NOT_SET,
209             ci, log_level)
210
211         if (arguments.include_integration != ARG_NOT_SET
212                 and arguments.floating_ips != ARG_NOT_SET):
213             sequential_suite = __create_sequential_test_suite(
214                 arguments.env, arguments.ext_net, arguments.proxy,
215                 arguments.ssh_proxy_cmd, integration, flavor_metadata,
216                 image_metadata,
217                 arguments.floating_ips != ARG_NOT_SET, log_level)
218     else:
219         logger.error('Environment file or external network not defined')
220         exit(1)
221
222     i = 0
223     while i < int(arguments.num_runs):
224         i += 1
225
226         if concurrent_suite:
227             logger.info('Running Concurrent Tests')
228             concurrent_runner = unittest.TextTestRunner(verbosity=2)
229             concurrent_suite = ConcurrentTestSuite(
230                 concurrent_suite, fork_for_tests(int(arguments.threads)))
231             concurrent_results = concurrent_runner.run(concurrent_suite)
232             __output_results(concurrent_results)
233
234             if ((concurrent_results.errors
235                     and len(concurrent_results.errors) > 0)
236                     or (concurrent_results.failures
237                         and len(concurrent_results.failures) > 0)):
238                 logger.error('See above for test failures')
239                 exit(1)
240             else:
241                 logger.info(
242                     'Concurrent tests completed successfully in run #%s', i)
243
244         if sequential_suite:
245             logger.info('Running Sequential Tests')
246             sequential_runner = unittest.TextTestRunner(verbosity=2)
247             sequential_results = sequential_runner.run(sequential_suite)
248             __output_results(sequential_results)
249
250             if ((sequential_results.errors
251                     and len(sequential_results.errors) > 0)
252                 or (sequential_results.failures
253                     and len(sequential_results.failures) > 0)):
254                 logger.error('See above for test failures')
255                 exit(1)
256             else:
257                 logger.info(
258                     'Sequential tests completed successfully in run #%s', i)
259
260     logger.info('Successful completion of %s test runs', i)
261     exit(0)
262
263
264 if __name__ == '__main__':
265     parser = argparse.ArgumentParser()
266     parser.add_argument(
267         '-e', '--env', dest='env', required=True,
268         help='OpenStack credentials file')
269     parser.add_argument(
270         '-n', '--net', dest='ext_net', required=True,
271         help='External network name')
272     parser.add_argument(
273         '-p', '--proxy', dest='proxy', nargs='?', default=None,
274         help='Optonal HTTP proxy socket (<host>:<port>)')
275     parser.add_argument(
276         '-s', '--ssh-proxy-cmd', dest='ssh_proxy_cmd', nargs='?', default=None,
277         help='Optonal SSH proxy command value')
278     parser.add_argument(
279         '-l', '--log-level', dest='log_level', default='INFO',
280         help='Logging Level (FATAL|CRITICAL|ERROR|WARN|INFO|DEBUG)')
281     parser.add_argument(
282         '-u', '--unit-tests', dest='include_unit', default=ARG_NOT_SET,
283         nargs='?', help='When argument is set, all tests not requiring '
284                         'OpenStack will be executed')
285     parser.add_argument(
286         '-c', '--connection-tests', dest='include_connection',
287         default=ARG_NOT_SET, nargs='?',
288         help='When argument is set, simple OpenStack connection tests will be '
289              'executed')
290     parser.add_argument(
291         '-a', '--api-tests', dest='include_api', default=ARG_NOT_SET,
292         nargs='?',
293         help='When argument is set, OpenStack API tests will be executed')
294     parser.add_argument(
295         '-i', '--integration-tests', dest='include_integration',
296         default=ARG_NOT_SET, nargs='?',
297         help='When argument is set, OpenStack integrations tests will be '
298              'executed')
299     parser.add_argument(
300         '-st', '--staging-tests', dest='include_staging', default=ARG_NOT_SET,
301         nargs='?',
302         help='When argument is set, OpenStack staging tests will be executed')
303     parser.add_argument(
304         '-f', '--floating-ips', dest='floating_ips', default=ARG_NOT_SET,
305         nargs='?', help='When argument is set, all integration tests requiring'
306                         ' Floating IPs will be executed')
307     parser.add_argument(
308         '-fm', '--flavor-meta', dest='flavor_metadata',
309         help='hw:mem_page_size flavor setting value (i.e. large). '
310              'Required for DPDK')
311     parser.add_argument(
312         '-im', '--image-meta', dest='image_metadata_file', default=None,
313         help='Location of YAML file containing the image metadata')
314     parser.add_argument(
315         '-ci', '--continuous-integration', dest='continuous_integration',
316         default=ARG_NOT_SET, nargs='?',
317         help='When argument is set, OpenStack integrations tests will be '
318              'executed')
319     parser.add_argument(
320         '-r', '--num-runs', dest='num_runs', default=1,
321         help='Number of test runs to execute (default 1)')
322     parser.add_argument(
323         '-t', '--threads', dest='threads', default=4,
324         help='Number of threads to execute the tests (default 4)')
325
326     args = parser.parse_args()
327
328     main(args)