3 # Copyright (c) 2016 Orange and others.
5 # All rights reserved. This program and the accompanying materials
6 # are made available under the terms of the Apache License, Version 2.0
7 # which accompanies this distribution, and is available at
8 # http://www.apache.org/licenses/LICENSE-2.0
10 """Define classes required to run ODL suites.
12 It has been designed for any context. But helpers are given for
13 running test suites in OPNFV environment.
19 from __future__ import division
31 from robot.errors import RobotError
33 from robot.utils.robottime import timestamp_to_secs
35 from functest.core import testcase
36 import functest.utils.openstack_utils as op_utils
38 __author__ = "Cedric Ollivier <cedric.ollivier@orange.com>"
41 class ODLResultVisitor(robot.api.ResultVisitor):
42 """Visitor to get result details."""
47 def visit_test(self, test):
49 output['name'] = test.name
50 output['parent'] = test.parent.name
51 output['status'] = test.status
52 output['starttime'] = test.starttime
53 output['endtime'] = test.endtime
54 output['critical'] = test.critical
55 output['text'] = test.message
56 output['elapsedtime'] = test.elapsedtime
57 self._data.append(output)
60 """Get the details of the result."""
64 class ODLTests(testcase.TestCase):
65 """ODL test runner."""
67 repos = "/home/opnfv/repos/"
68 odl_test_repo = os.path.join(repos, "odl_test")
69 neutron_suite_dir = os.path.join(odl_test_repo,
70 "csit/suites/openstack/neutron")
71 basic_suite_dir = os.path.join(odl_test_repo,
72 "csit/suites/integration/basic")
73 default_suites = [basic_suite_dir, neutron_suite_dir]
74 res_dir = '/home/opnfv/functest/results/odl/'
75 __logger = logging.getLogger(__name__)
78 def set_robotframework_vars(cls, odlusername="admin", odlpassword="admin"):
79 """Set credentials in csit/variables/Variables.py.
82 True if credentials are set.
85 odl_variables_files = os.path.join(cls.odl_test_repo,
86 'csit/variables/Variables.py')
88 for line in fileinput.input(odl_variables_files,
90 print re.sub("AUTH = .*",
91 ("AUTH = [u'" + odlusername + "', u'" +
95 except Exception as ex: # pylint: disable=broad-except
96 cls.__logger.error("Cannot set ODL creds: %s", str(ex))
99 def parse_results(self):
100 """Parse output.xml and get the details in it."""
101 xml_file = os.path.join(self.res_dir, 'output.xml')
102 result = robot.api.ExecutionResult(xml_file)
103 visitor = ODLResultVisitor()
104 result.visit(visitor)
106 self.result = 100 * (
107 result.suite.statistics.critical.passed /
108 result.suite.statistics.critical.total)
109 except ZeroDivisionError:
110 self.__logger.error("No test has been ran")
111 self.start_time = timestamp_to_secs(result.suite.starttime)
112 self.stop_time = timestamp_to_secs(result.suite.endtime)
114 self.details['description'] = result.suite.name
115 self.details['tests'] = visitor.get_data()
117 def main(self, suites=None, **kwargs):
118 """Run the test suites
120 It has been designed to be called in any context.
121 It requires the following keyword arguments:
135 * set all RobotFramework_variables,
136 * create the output directories if required,
137 * get the results in output.xml,
138 * delete temporary files.
141 kwargs: Arbitrary keyword arguments.
144 EX_OK if all suites ran well.
145 EX_RUN_ERROR otherwise.
149 suites = self.default_suites
150 odlusername = kwargs['odlusername']
151 odlpassword = kwargs['odlpassword']
152 osauthurl = kwargs['osauthurl']
153 keystoneip = urlparse.urlparse(osauthurl).hostname
154 variables = ['KEYSTONE:' + keystoneip,
155 'NEUTRON:' + kwargs['neutronip'],
156 'OS_AUTH_URL:"' + osauthurl + '"',
157 'OSUSERNAME:"' + kwargs['osusername'] + '"',
158 'OSTENANTNAME:"' + kwargs['ostenantname'] + '"',
159 'OSPASSWORD:"' + kwargs['ospassword'] + '"',
160 'ODL_SYSTEM_IP:' + kwargs['odlip'],
161 'PORT:' + kwargs['odlwebport'],
162 'RESTCONFPORT:' + kwargs['odlrestconfport']]
163 except KeyError as ex:
164 self.__logger.error("Cannot run ODL testcases. Please check "
166 return self.EX_RUN_ERROR
167 if self.set_robotframework_vars(odlusername, odlpassword):
169 os.makedirs(self.res_dir)
170 except OSError as ex:
171 if ex.errno != errno.EEXIST:
172 self.__logger.exception(
173 "Cannot create %s", self.res_dir)
174 return self.EX_RUN_ERROR
175 stdout_file = os.path.join(self.res_dir, 'stdout.txt')
176 output_dir = os.path.join(self.res_dir, 'output.xml')
177 with open(stdout_file, 'w+') as stdout:
178 robot.run(*suites, variable=variables,
184 self.__logger.info("\n" + stdout.read())
185 self.__logger.info("ODL results were successfully generated")
188 self.__logger.info("ODL results were successfully parsed")
189 except RobotError as ex:
190 self.__logger.error("Run tests before publishing: %s",
192 return self.EX_RUN_ERROR
194 os.remove(stdout_file)
196 self.__logger.warning("Cannot remove %s", stdout_file)
199 return self.EX_RUN_ERROR
201 def run(self, **kwargs):
202 """Run suites in OPNFV environment
204 It basically check env vars to call main() with the keywords
208 kwargs: Arbitrary keyword arguments.
211 EX_OK if all suites ran well.
212 EX_RUN_ERROR otherwise.
215 suites = self.default_suites
217 suites = kwargs["suites"]
220 neutron_url = op_utils.get_endpoint(service_type='network')
221 kwargs = {'neutronip': urlparse.urlparse(neutron_url).hostname}
222 kwargs['odlip'] = kwargs['neutronip']
223 kwargs['odlwebport'] = '8080'
224 kwargs['odlrestconfport'] = '8181'
225 kwargs['odlusername'] = 'admin'
226 kwargs['odlpassword'] = 'admin'
227 installer_type = None
228 if 'INSTALLER_TYPE' in os.environ:
229 installer_type = os.environ['INSTALLER_TYPE']
230 kwargs['osusername'] = os.environ['OS_USERNAME']
231 kwargs['ostenantname'] = os.environ['OS_TENANT_NAME']
232 kwargs['osauthurl'] = os.environ['OS_AUTH_URL']
233 kwargs['ospassword'] = os.environ['OS_PASSWORD']
234 if installer_type == 'fuel':
235 kwargs['odlwebport'] = '8282'
236 elif installer_type == 'apex' or installer_type == 'netvirt':
237 kwargs['odlip'] = os.environ['SDN_CONTROLLER_IP']
238 kwargs['odlwebport'] = '8081'
239 kwargs['odlrestconfport'] = '8081'
240 elif installer_type == 'joid':
241 kwargs['odlip'] = os.environ['SDN_CONTROLLER']
242 elif installer_type == 'compass':
243 kwargs['odlwebport'] = '8181'
245 kwargs['odlip'] = os.environ['SDN_CONTROLLER_IP']
246 except KeyError as ex:
247 self.__logger.error("Cannot run ODL testcases. "
248 "Please check env var: "
250 return self.EX_RUN_ERROR
251 except Exception: # pylint: disable=broad-except
252 self.__logger.exception("Cannot run ODL testcases.")
253 return self.EX_RUN_ERROR
255 return self.main(suites, **kwargs)
258 class ODLParser(object): # pylint: disable=too-few-public-methods
259 """Parser to run ODL test suites."""
262 self.parser = argparse.ArgumentParser()
263 self.parser.add_argument(
264 '-n', '--neutronip', help='Neutron IP',
266 self.parser.add_argument(
267 '-k', '--osauthurl', help='OS_AUTH_URL as defined by OpenStack',
268 default='http://127.0.0.1:5000/v2.0')
269 self.parser.add_argument(
270 '-a', '--osusername', help='Username for OpenStack',
272 self.parser.add_argument(
273 '-b', '--ostenantname', help='Tenantname for OpenStack',
275 self.parser.add_argument(
276 '-c', '--ospassword', help='Password for OpenStack',
278 self.parser.add_argument(
279 '-o', '--odlip', help='OpenDaylight IP',
281 self.parser.add_argument(
282 '-w', '--odlwebport', help='OpenDaylight Web Portal Port',
284 self.parser.add_argument(
285 '-r', '--odlrestconfport', help='OpenDaylight RESTConf Port',
287 self.parser.add_argument(
288 '-d', '--odlusername', help='Username for ODL',
290 self.parser.add_argument(
291 '-e', '--odlpassword', help='Password for ODL',
293 self.parser.add_argument(
294 '-p', '--pushtodb', help='Push results to DB',
297 def parse_args(self, argv=None):
300 It can call sys.exit if arguments are incorrect.
303 the arguments from cmdline
307 return vars(self.parser.parse_args(argv))
310 if __name__ == '__main__':
311 logging.basicConfig()
314 ARGS = PARSER.parse_args(sys.argv[1:])
316 RESULT = ODL.main(ODLTests.default_suites, **ARGS)
317 if RESULT != testcase.TestCase.EX_OK:
320 sys.exit(ODL.push_to_db())
321 except Exception: # pylint: disable=broad-except
322 sys.exit(testcase.TestCase.EX_RUN_ERROR)