fix test_RO paths. Add timeout, failfast options.
[osm/RO.git] / test / test_RO.py
1 #!/usr/bin/env python2
2 # -*- coding: utf-8 -*-
3
4 ##
5 # Copyright 2015 Telefónica Investigación y Desarrollo, S.A.U.
6 # This file is part of openmano
7 # All Rights Reserved.
8 #
9 # Licensed under the Apache License, Version 2.0 (the "License"); you may
10 # not use this file except in compliance with the License. You may obtain
11 # a copy of the License at
12 #
13 # http://www.apache.org/licenses/LICENSE-2.0
14 #
15 # Unless required by applicable law or agreed to in writing, software
16 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
17 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
18 # License for the specific language governing permissions and limitations
19 # under the License.
20 #
21 # For those usages not covered by the Apache License, Version 2.0 please
22 # contact with: nfvlabs@tid.es
23 ##
24
25 '''
26 Module for testing openmano functionality. It uses openmanoclient.py for invoking openmano
27 '''
28 __author__="Pablo Montes, Alfonso Tierno"
29 __date__ ="$16-Feb-2017 17:08:16$"
30 __version__="0.0.2"
31 version_date="May 2017"
32
33 import logging
34 import imp
35 import os
36 from optparse import OptionParser
37 import unittest
38 import string
39 import inspect
40 import random
41 import traceback
42 import glob
43 import yaml
44 import sys
45 import time
46
47 global test_number
48 global test_directory
49 global scenario_test_folder
50 global test_image_name
51 global timeout
52 global management_network
53 global manual
54
55 def check_instance_scenario_active(uuid):
56 instance = client.get_instance(uuid=uuid)
57
58 for net in instance['nets']:
59 status = net['status']
60 if status != 'ACTIVE':
61 return (False, status)
62
63 for vnf in instance['vnfs']:
64 for vm in vnf['vms']:
65 status = vm['status']
66 if status != 'ACTIVE':
67 return (False, status)
68
69 return (True, None)
70
71 '''
72 IMPORTANT NOTE
73 All unittest classes for code based tests must have prefix 'test_' in order to be taken into account for tests
74 '''
75 class test_tenant_operations(unittest.TestCase):
76 test_index = 1
77 tenant_name = None
78 test_text = None
79
80 @classmethod
81 def setUpClass(cls):
82 logger.info("{}. {}".format(test_number, cls.__name__))
83
84 @classmethod
85 def tearDownClass(cls):
86 globals().__setitem__('test_number', globals().__getitem__('test_number') + 1)
87
88 def tearDown(self):
89 exec_info = sys.exc_info()
90 if exec_info == (None, None, None):
91 logger.info(self.__class__.test_text+" -> TEST OK")
92 else:
93 logger.warning(self.__class__.test_text+" -> TEST NOK")
94 error_trace = traceback.format_exception(exec_info[0], exec_info[1], exec_info[2])
95 msg = ""
96 for line in error_trace:
97 msg = msg + line
98 logger.critical("{}".format(msg))
99
100 def test_000_create_RO_tenant(self):
101 self.__class__.tenant_name = _get_random_string(20)
102 self.__class__.test_text = "{}.{}. TEST {}".format(test_number, self.__class__.test_index,
103 inspect.currentframe().f_code.co_name)
104 self.__class__.test_index += 1
105 tenant = client.create_tenant(name=self.__class__.tenant_name, description=self.__class__.tenant_name)
106 logger.debug("{}".format(tenant))
107 self.assertEqual(tenant.get('tenant', {}).get('name', ''), self.__class__.tenant_name)
108
109 def test_010_list_RO_tenant(self):
110 self.__class__.test_text = "{}.{}. TEST {}".format(test_number, self.__class__.test_index,
111 inspect.currentframe().f_code.co_name)
112 self.__class__.test_index += 1
113 tenant = client.get_tenant(name=self.__class__.tenant_name)
114 logger.debug("{}".format(tenant))
115 self.assertEqual(tenant.get('tenant', {}).get('name', ''), self.__class__.tenant_name)
116
117 def test_020_delete_RO_tenant(self):
118 self.__class__.test_text = "{}.{}. TEST {}".format(test_number, self.__class__.test_index,
119 inspect.currentframe().f_code.co_name)
120 self.__class__.test_index += 1
121 tenant = client.delete_tenant(name=self.__class__.tenant_name)
122 logger.debug("{}".format(tenant))
123 assert('deleted' in tenant.get('result',""))
124
125 class test_datacenter_operations(unittest.TestCase):
126 test_index = 1
127 datacenter_name = None
128 test_text = None
129
130 @classmethod
131 def setUpClass(cls):
132 logger.info("{}. {}".format(test_number, cls.__name__))
133
134 @classmethod
135 def tearDownClass(cls):
136 globals().__setitem__('test_number', globals().__getitem__('test_number') + 1)
137
138 def tearDown(self):
139 exec_info = sys.exc_info()
140 if exec_info == (None, None, None):
141 logger.info(self.__class__.test_text+" -> TEST OK")
142 else:
143 logger.warning(self.__class__.test_text+" -> TEST NOK")
144 error_trace = traceback.format_exception(exec_info[0], exec_info[1], exec_info[2])
145 msg = ""
146 for line in error_trace:
147 msg = msg + line
148 logger.critical("{}".format(msg))
149
150 def test_000_create_datacenter(self):
151 self.__class__.test_text = "{}.{}. TEST {}".format(test_number, self.__class__.test_index,
152 inspect.currentframe().f_code.co_name)
153 self.__class__.datacenter_name = _get_random_string(20)
154 self.__class__.test_index += 1
155 self.datacenter = client.create_datacenter(name=self.__class__.datacenter_name, vim_url="http://fakeurl/fake")
156 logger.debug("{}".format(self.datacenter))
157 self.assertEqual (self.datacenter.get('datacenter', {}).get('name',''), self.__class__.datacenter_name)
158
159 def test_010_list_datacenter(self):
160 self.__class__.test_text = "{}.{}. TEST {}".format(test_number, self.__class__.test_index,
161 inspect.currentframe().f_code.co_name)
162
163 self.__class__.test_index += 1
164 self.datacenter = client.get_datacenter(all_tenants=True, name=self.__class__.datacenter_name)
165 logger.debug("{}".format(self.datacenter))
166 self.assertEqual (self.datacenter.get('datacenter', {}).get('name', ''), self.__class__.datacenter_name)
167
168 def test_020_attach_datacenter(self):
169 self.__class__.test_text = "{}.{}. TEST {}".format(test_number, self.__class__.test_index,
170 inspect.currentframe().f_code.co_name)
171
172 self.__class__.test_index += 1
173 self.datacenter = client.attach_datacenter(name=self.__class__.datacenter_name, vim_tenant_name='fake')
174 logger.debug("{}".format(self.datacenter))
175 assert ('vim_tenants' in self.datacenter.get('datacenter', {}))
176
177 def test_030_list_attached_datacenter(self):
178 self.__class__.test_text = "{}.{}. TEST {}".format(test_number, self.__class__.test_index,
179 inspect.currentframe().f_code.co_name)
180
181 self.__class__.test_index += 1
182 self.datacenter = client.get_datacenter(all_tenants=False, name=self.__class__.datacenter_name)
183 logger.debug("{}".format(self.datacenter))
184 self.assertEqual (self.datacenter.get('datacenter', {}).get('name', ''), self.__class__.datacenter_name)
185
186 def test_040_detach_datacenter(self):
187 self.__class__.test_text = "{}.{}. TEST {}".format(test_number, self.__class__.test_index,
188 inspect.currentframe().f_code.co_name)
189
190 self.__class__.test_index += 1
191 self.datacenter = client.detach_datacenter(name=self.__class__.datacenter_name)
192 logger.debug("{}".format(self.datacenter))
193 assert ('detached' in self.datacenter.get('result', ""))
194
195 def test_050_delete_datacenter(self):
196 self.__class__.test_text = "{}.{}. TEST {}".format(test_number, self.__class__.test_index,
197 inspect.currentframe().f_code.co_name)
198
199 self.__class__.test_index += 1
200 self.datacenter = client.delete_datacenter(name=self.__class__.datacenter_name)
201 logger.debug("{}".format(self.datacenter))
202 assert('deleted' in self.datacenter.get('result',""))
203
204 class test_VIM_network_operations(unittest.TestCase):
205 test_index = 1
206 vim_network_name = None
207 test_text = None
208 vim_network_uuid = None
209
210 @classmethod
211 def setUpClass(cls):
212 logger.info("{}. {}".format(test_number, cls.__name__))
213
214 @classmethod
215 def tearDownClass(cls):
216 globals().__setitem__('test_number', globals().__getitem__('test_number') + 1)
217
218 def tearDown(self):
219 exec_info = sys.exc_info()
220 if exec_info == (None, None, None):
221 logger.info(self.__class__.test_text + " -> TEST OK")
222 else:
223 logger.warning(self.__class__.test_text + " -> TEST NOK")
224 error_trace = traceback.format_exception(exec_info[0], exec_info[1], exec_info[2])
225 msg = ""
226 for line in error_trace:
227 msg = msg + line
228 logger.critical("{}".format(msg))
229
230 def test_000_create_VIM_network(self):
231 self.__class__.test_text = "{}.{}. TEST {}".format(test_number, self.__class__.test_index,
232 inspect.currentframe().f_code.co_name)
233 self.__class__.vim_network_name = _get_random_string(20)
234 self.__class__.test_index += 1
235 network = client.vim_action("create", "networks", name=self.__class__.vim_network_name)
236 logger.debug("{}".format(network))
237 self.__class__.vim_network_uuid = network["network"]["id"]
238 self.assertEqual(network.get('network', {}).get('name', ''), self.__class__.vim_network_name)
239
240 def test_010_list_VIM_networks(self):
241 self.__class__.test_text = "{}.{}. TEST {}".format(test_number, self.__class__.test_index,
242 inspect.currentframe().f_code.co_name)
243 self.__class__.test_index += 1
244 networks = client.vim_action("list", "networks")
245 logger.debug("{}".format(networks))
246
247 def test_020_get_VIM_network_by_uuid(self):
248 self.__class__.test_text = "{}.{}. TEST {}".format(test_number, self.__class__.test_index,
249 inspect.currentframe().f_code.co_name)
250
251 self.__class__.test_index += 1
252 network = client.vim_action("show", "networks", uuid=self.__class__.vim_network_uuid)
253 logger.debug("{}".format(network))
254 self.assertEqual(network.get('network', {}).get('name', ''), self.__class__.vim_network_name)
255
256 def test_030_delete_VIM_network_by_uuid(self):
257 self.__class__.test_text = "{}.{}. TEST {}".format(test_number, self.__class__.test_index,
258 inspect.currentframe().f_code.co_name)
259
260 self.__class__.test_index += 1
261 network = client.vim_action("delete", "networks", uuid=self.__class__.vim_network_uuid)
262 logger.debug("{}".format(network))
263 assert ('deleted' in network.get('result', ""))
264
265 class test_VIM_image_operations(unittest.TestCase):
266 test_index = 1
267 test_text = None
268
269 @classmethod
270 def setUpClass(cls):
271 logger.info("{}. {}".format(test_number, cls.__name__))
272
273 @classmethod
274 def tearDownClass(cls):
275 globals().__setitem__('test_number', globals().__getitem__('test_number') + 1)
276
277 def tearDown(self):
278 exec_info = sys.exc_info()
279 if exec_info == (None, None, None):
280 logger.info(self.__class__.test_text + " -> TEST OK")
281 else:
282 logger.warning(self.__class__.test_text + " -> TEST NOK")
283 error_trace = traceback.format_exception(exec_info[0], exec_info[1], exec_info[2])
284 msg = ""
285 for line in error_trace:
286 msg = msg + line
287 logger.critical("{}".format(msg))
288
289 def test_000_list_VIM_images(self):
290 self.__class__.test_text = "{}.{}. TEST {}".format(test_number, self.__class__.test_index,
291 inspect.currentframe().f_code.co_name)
292 self.__class__.test_index += 1
293 images = client.vim_action("list", "images")
294 logger.debug("{}".format(images))
295
296 '''
297 The following is a non critical test that will fail most of the times.
298 In case of OpenStack datacenter these tests will only success if RO has access to the admin endpoint
299 This test will only be executed in case it is specifically requested by the user
300 '''
301 class test_VIM_tenant_operations(unittest.TestCase):
302 test_index = 1
303 vim_tenant_name = None
304 test_text = None
305 vim_tenant_uuid = None
306
307 @classmethod
308 def setUpClass(cls):
309 logger.info("{}. {}".format(test_number, cls.__name__))
310 logger.warning("In case of OpenStack datacenter these tests will only success "
311 "if RO has access to the admin endpoint")
312
313 @classmethod
314 def tearDownClass(cls):
315 globals().__setitem__('test_number', globals().__getitem__('test_number') + 1)
316
317 def tearDown(self):
318 exec_info = sys.exc_info()
319 if exec_info == (None, None, None):
320 logger.info(self.__class__.test_text + " -> TEST OK")
321 else:
322 logger.warning(self.__class__.test_text + " -> TEST NOK")
323 error_trace = traceback.format_exception(exec_info[0], exec_info[1], exec_info[2])
324 msg = ""
325 for line in error_trace:
326 msg = msg + line
327 logger.critical("{}".format(msg))
328
329 def test_000_create_VIM_tenant(self):
330 self.__class__.test_text = "{}.{}. TEST {}".format(test_number, self.__class__.test_index,
331 inspect.currentframe().f_code.co_name)
332 self.__class__.vim_tenant_name = _get_random_string(20)
333 self.__class__.test_index += 1
334 tenant = client.vim_action("create", "tenants", name=self.__class__.vim_tenant_name)
335 logger.debug("{}".format(tenant))
336 self.__class__.vim_tenant_uuid = tenant["tenant"]["id"]
337 self.assertEqual(tenant.get('tenant', {}).get('name', ''), self.__class__.vim_tenant_name)
338
339 def test_010_list_VIM_tenants(self):
340 self.__class__.test_text = "{}.{}. TEST {}".format(test_number, self.__class__.test_index,
341 inspect.currentframe().f_code.co_name)
342 self.__class__.test_index += 1
343 tenants = client.vim_action("list", "tenants")
344 logger.debug("{}".format(tenants))
345
346 def test_020_get_VIM_tenant_by_uuid(self):
347 self.__class__.test_text = "{}.{}. TEST {}".format(test_number, self.__class__.test_index,
348 inspect.currentframe().f_code.co_name)
349
350 self.__class__.test_index += 1
351 tenant = client.vim_action("show", "tenants", uuid=self.__class__.vim_tenant_uuid)
352 logger.debug("{}".format(tenant))
353 self.assertEqual(tenant.get('tenant', {}).get('name', ''), self.__class__.vim_tenant_name)
354
355 def test_030_delete_VIM_tenant_by_uuid(self):
356 self.__class__.test_text = "{}.{}. TEST {}".format(test_number, self.__class__.test_index,
357 inspect.currentframe().f_code.co_name)
358
359 self.__class__.test_index += 1
360 tenant = client.vim_action("delete", "tenants", uuid=self.__class__.vim_tenant_uuid)
361 logger.debug("{}".format(tenant))
362 assert ('deleted' in tenant.get('result', ""))
363
364 '''
365 IMPORTANT NOTE
366 The following unittest class does not have the 'test_' on purpose. This test is the one used for the
367 scenario based tests.
368 '''
369 class descriptor_based_scenario_test(unittest.TestCase):
370 test_index = 0
371 test_text = None
372 scenario_test_path = None
373 scenario_uuid = None
374 instance_scenario_uuid = None
375 to_delete_list = []
376
377 @classmethod
378 def setUpClass(cls):
379 cls.test_index = 1
380 cls.to_delete_list = []
381 cls.scenario_test_path = test_directory + '/' + scenario_test_folder
382 logger.info("{}. {} {}".format(test_number, cls.__name__, scenario_test_folder))
383
384 @classmethod
385 def tearDownClass(cls):
386 globals().__setitem__('test_number', globals().__getitem__('test_number') + 1)
387
388 def tearDown(self):
389 exec_info = sys.exc_info()
390 if exec_info == (None, None, None):
391 logger.info(self.__class__.test_text + " -> TEST OK")
392 else:
393 logger.warning(self.__class__.test_text + " -> TEST NOK")
394 error_trace = traceback.format_exception(exec_info[0], exec_info[1], exec_info[2])
395 msg = ""
396 for line in error_trace:
397 msg = msg + line
398 logger.critical("{}".format(msg))
399
400
401 def test_000_load_scenario(self):
402 self.__class__.test_text = "{}.{}. TEST {} {}".format(test_number, self.__class__.test_index,
403 inspect.currentframe().f_code.co_name,
404 scenario_test_folder)
405 self.__class__.test_index += 1
406 vnfd_files = glob.glob(self.__class__.scenario_test_path+'/vnfd_*.yaml')
407 scenario_file = glob.glob(self.__class__.scenario_test_path + '/scenario_*.yaml')
408 if len(vnfd_files) == 0 or len(scenario_file) > 1:
409 raise Exception('Test '+scenario_test_folder+' not valid. It must contain an scenario file and at least one'
410 ' vnfd file')
411
412 #load all vnfd
413 for vnfd in vnfd_files:
414 with open(vnfd, 'r') as stream:
415 vnf_descriptor = yaml.load(stream)
416
417 vnfc_list = vnf_descriptor['vnf']['VNFC']
418 for vnfc in vnfc_list:
419 vnfc['image name'] = test_image_name
420 devices = vnfc.get('devices',[])
421 for device in devices:
422 if device['type'] == 'disk' and 'image name' in device:
423 device['image name'] = test_image_name
424
425 logger.debug("VNF descriptor: {}".format(vnf_descriptor))
426 vnf = client.create_vnf(descriptor=vnf_descriptor)
427 logger.debug(vnf)
428 self.__class__.to_delete_list.insert(0, {"item": "vnf", "function": client.delete_vnf,
429 "params": {"uuid": vnf['vnf']['uuid']}})
430
431 #load the scenario definition
432 with open(scenario_file[0], 'r') as stream:
433 scenario_descriptor = yaml.load(stream)
434 networks = scenario_descriptor['scenario']['networks']
435 networks[management_network] = networks.pop('mgmt')
436 logger.debug("Scenario descriptor: {}".format(scenario_descriptor))
437 scenario = client.create_scenario(descriptor=scenario_descriptor)
438 logger.debug(scenario)
439 self.__class__.to_delete_list.insert(0,{"item": "scenario", "function": client.delete_scenario,
440 "params":{"uuid": scenario['scenario']['uuid']} })
441 self.__class__.scenario_uuid = scenario['scenario']['uuid']
442
443 def test_010_instantiate_scenario(self):
444 self.__class__.test_text = "{}.{}. TEST {} {}".format(test_number, self.__class__.test_index,
445 inspect.currentframe().f_code.co_name,
446 scenario_test_folder)
447 self.__class__.test_index += 1
448
449 instance = client.create_instance(scenario_id=self.__class__.scenario_uuid, name=self.__class__.test_text)
450 self.__class__.instance_scenario_uuid = instance['uuid']
451 logger.debug(instance)
452 self.__class__.to_delete_list.insert(0, {"item": "instance", "function": client.delete_instance,
453 "params": {"uuid": instance['uuid']}})
454
455 def test_020_check_deployent(self):
456 self.__class__.test_text = "{}.{}. TEST {} {}".format(test_number, self.__class__.test_index,
457 inspect.currentframe().f_code.co_name,
458 scenario_test_folder)
459 self.__class__.test_index += 1
460
461 if manual:
462 raw_input('Scenario has been deployed. Perform manual check and press any key to resume')
463 return
464
465 keep_waiting = timeout
466 instance_active = False
467 while True:
468 result = check_instance_scenario_active(self.__class__.instance_scenario_uuid)
469 if result[0]:
470 break
471 elif 'ERROR' in result[1]:
472 msg = 'Got error while waiting for the instance to get active: '+result[1]
473 logging.error(msg)
474 raise Exception(msg)
475
476 if keep_waiting >= 5:
477 time.sleep(5)
478 keep_waiting -= 5
479 elif keep_waiting > 0:
480 time.sleep(keep_waiting)
481 keep_waiting = 0
482 else:
483 msg = 'Timeout reached while waiting instance scenario to get active'
484 logging.error(msg)
485 raise Exception(msg)
486
487 def test_030_clean_deployment(self):
488 self.__class__.test_text = "{}.{}. TEST {} {}".format(test_number, self.__class__.test_index,
489 inspect.currentframe().f_code.co_name,
490 scenario_test_folder)
491 self.__class__.test_index += 1
492 #At the moment if you delete an scenario right after creating it, in openstack datacenters
493 #sometimes scenario ports get orphaned. This sleep is just a dirty workaround
494 time.sleep(5)
495 for item in self.__class__.to_delete_list:
496 response = item["function"](**item["params"])
497 logger.debug(response)
498
499 def _get_random_string(maxLength):
500 '''generates a string with random characters string.letters and string.digits
501 with a random length up to maxLength characters. If maxLength is <15 it will be changed automatically to 15
502 '''
503 prefix = 'testing_'
504 min_string = 15
505 minLength = min_string - len(prefix)
506 if maxLength < min_string: maxLength = min_string
507 maxLength -= len(prefix)
508 length = random.randint(minLength,maxLength)
509 return 'testing_'+"".join([random.choice(string.letters+string.digits) for i in xrange(length)])
510
511 if __name__=="__main__":
512 sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + "/osm_ro")
513 import openmanoclient
514
515 parser = OptionParser()
516
517 #Mandatory arguments
518 parser.add_option('-d', '--datacenter', dest='datacenter_name', help='MANDATORY, Set the datacenter name to test')
519 parser.add_option("-i", '--image-name', dest='image-name', help='MANDATORY. Image name of an Ubuntu 16.04 image '
520 'that will be used for testing available in the '
521 'datacenter.')
522 parser.add_option("-n", '--mgmt-net-name', dest='mgmt-net', help='MANDATORY. Set the vim management network to use')
523 parser.add_option("-t", '--tenant', dest='tenant_name', help='MANDATORY. Set the tenant name to test')
524
525 #Optional arguments
526 parser.add_option('--debug', help='Set logs to debug level', dest='debug', action="store_true", default=False)
527 parser.add_option('--failfast', help='Stop when a test fails rather than execute all tests',
528 dest='failfast', action="store_true", default=False)
529 parser.add_option('--failed', help='Set logs to show only failed tests. --debug disables this option',
530 dest='failed', action="store_true", default=False)
531 default_logger_file = os.path.dirname(__file__)+'/'+os.path.splitext(os.path.basename(__file__))[0]+'.log'
532 parser.add_option('--list-tests', help='List all available tests', dest='list-tests', action="store_true",
533 default=False)
534 parser.add_option('--logger_file', dest='logger_file', help='Set the logger file. By default '+default_logger_file,
535 default=default_logger_file)
536 parser.add_option('-m', '--manual-check', help='Pause execution once deployed to allow manual checking of the '
537 'deployed instance scenario',
538 dest='manual', action="store_true", default=False)
539 parser.add_option('--timeout', help='Specify the instantiation timeout in seconds. By default 300',
540 dest='timeout', type='int', default=300)
541 parser.add_option('--test', '--tests', help='Specify the tests to run', dest='tests', default=None)
542 parser.add_option('-u', '--url', dest='endpoint_url', help='Set the openmano server url. By default '
543 'http://localhost:9090/openmano',
544 default='http://localhost:9090/openmano')
545 parser.add_option("-v",'--version', help='Show current version', dest='version', action="store_true", default=False)
546
547 (options, args) = parser.parse_args()
548
549 # default logger level is INFO. Options --debug and --failed override this, being --debug prioritary
550 logger_level = 'INFO'
551 if options.__dict__['debug']:
552 logger_level = 'DEBUG'
553 elif options.__dict__['failed']:
554 logger_level = 'WARNING'
555 logger_name = os.path.basename(__file__)
556 logger = logging.getLogger(logger_name)
557 logger.setLevel(logger_level)
558 failfast = options.__dict__['failfast']
559
560 # Configure a logging handler to store in a logging file
561 fileHandler = logging.FileHandler(options.__dict__['logger_file'])
562 formatter_fileHandler = logging.Formatter('%(asctime)s %(name)s %(levelname)s: %(message)s')
563 fileHandler.setFormatter(formatter_fileHandler)
564 logger.addHandler(fileHandler)
565
566 # Configure a handler to print to stdout
567 consoleHandler = logging.StreamHandler(sys.stdout)
568 formatter_consoleHandler = logging.Formatter('%(message)s')
569 consoleHandler.setFormatter(formatter_consoleHandler)
570 logger.addHandler(consoleHandler)
571
572 logger.debug('Program started with the following arguments: ' + str(options.__dict__))
573
574 # If version is required print it and exit
575 if options.__dict__['version']:
576 logger.info("{}".format((sys.argv[0], __version__+" version", version_date)))
577 logger.info("(c) Copyright Telefonica")
578 sys.exit(0)
579
580 test_directory = os.path.dirname(__file__) + "/RO_tests"
581 test_directory_content = os.listdir(test_directory)
582 clsmembers = inspect.getmembers(sys.modules[__name__], inspect.isclass)
583
584 # If only want to obtain a tests list print it and exit
585 if options.__dict__['list-tests']:
586 tests_names = []
587 for cls in clsmembers:
588 if cls[0].startswith('test_'):
589 tests_names.append(cls[0])
590
591 msg = "The code based tests are:\n\t" + ', '.join(sorted(tests_names)) + \
592 "\nThe descriptor based tests are:\n\t" + ', '.join(sorted(test_directory_content)) + \
593 "\nNOTE: The test test_VIM_tenant_operations will fail in case the used datacenter is type OpenStack " \
594 "unless RO has access to the admin endpoint. Therefore this test is excluded by default"
595
596 logger.info(msg)
597 sys.exit(0)
598
599 # Make sure required arguments are present
600 required = "tenant_name datacenter_name image-name mgmt-net".split()
601 error = False
602 for r in required:
603 if options.__dict__[r] is None:
604 print ("ERROR: parameter "+r+" is required")
605 error = True
606 if error:
607 parser.print_help()
608 sys.exit(1)
609
610 # set test image name and management network
611 test_image_name = options.__dict__['image-name']
612 management_network = options.__dict__['mgmt-net']
613 manual = options.__dict__['manual']
614 timeout = options.__dict__['timeout']
615
616 # Create the list of tests to be run
617 descriptor_based_tests = []
618 code_based_tests = []
619 if options.__dict__['tests'] is not None:
620 tests = sorted(options.__dict__['tests'].split(','))
621 for test in tests:
622 matches_code_based_tests = [item for item in clsmembers if item[0] == test]
623 if test in test_directory_content:
624 descriptor_based_tests.append(test)
625 elif len(matches_code_based_tests) > 0:
626 code_based_tests.append(matches_code_based_tests[0][1])
627 else:
628 logger.critical("Test {} is not among the possible ones".format(test))
629 sys.exit(1)
630 else:
631 # include all tests
632 descriptor_based_tests = test_directory_content
633 for cls in clsmembers:
634 # We exclude 'test_VIM_tenant_operations' unless it is specifically requested by the user
635 if cls[0].startswith('test_') and cls[0] != 'test_VIM_tenant_operations':
636 code_based_tests.append(cls[1])
637
638 logger.debug("descriptor_based_tests to be executed: {}".format(descriptor_based_tests))
639 logger.debug("code_based_tests to be executed: {}".format(code_based_tests))
640
641 # import openmanoclient from relative path
642 client = openmanoclient.openmanoclient(
643 endpoint_url=options.__dict__['endpoint_url'],
644 tenant_name=options.__dict__['tenant_name'],
645 datacenter_name=options.__dict__['datacenter_name'],
646 debug=options.__dict__['debug'], logger=logger_name)
647
648 # TextTestRunner stream is set to /dev/null in order to avoid the method to directly print the result of tests.
649 # This is handled in the tests using logging.
650 stream = open('/dev/null', 'w')
651 test_number = 1
652 executed = 0
653 failed = 0
654
655 # Run code based tests
656 basic_tests_suite = unittest.TestSuite()
657 for test in code_based_tests:
658 basic_tests_suite.addTest(unittest.makeSuite(test))
659 result = unittest.TextTestRunner(stream=stream, failfast=failfast).run(basic_tests_suite)
660 executed += result.testsRun
661 failed += len(result.failures) + len(result.errors)
662 if failfast and failed:
663 sys.exit(1)
664 if len(result.failures) > 0:
665 logger.debug("failures : {}".format(result.failures))
666 if len(result.errors) > 0:
667 logger.debug("errors : {}".format(result.errors))
668
669 # Additionally to the previous tests, scenario based tests will be executed.
670 # This scenario based tests are defined as directories inside the directory defined in 'test_directory'
671 for test in descriptor_based_tests:
672 scenario_test_folder = test
673 test_suite = unittest.TestSuite()
674 test_suite.addTest(unittest.makeSuite(descriptor_based_scenario_test))
675 result = unittest.TextTestRunner(stream=stream, failfast=False).run(test_suite)
676 executed += result.testsRun
677 failed += len(result.failures) + len(result.errors)
678 if failfast and failed:
679 sys.exit(1)
680 if len(result.failures) > 0:
681 logger.debug("failures : {}".format(result.failures))
682 if len(result.errors) > 0:
683 logger.debug("errors : {}".format(result.errors))
684
685 # Log summary
686 logger.warning("Total number of tests: {}; Total number of failures/errors: {}".format(executed, failed))
687 sys.exit(1 if failed else 0)