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.
28 from robot.errors import RobotError
30 from robot.utils.robottime import timestamp_to_secs
32 from functest.core import testcase
33 import functest.utils.functest_logger as ft_logger
34 import functest.utils.openstack_utils as op_utils
36 __author__ = "Cedric Ollivier <cedric.ollivier@orange.com>"
39 class ODLResultVisitor(robot.api.ResultVisitor):
40 """Visitor to get result details."""
45 def visit_test(self, test):
47 output['name'] = test.name
48 output['parent'] = test.parent.name
49 output['status'] = test.status
50 output['starttime'] = test.starttime
51 output['endtime'] = test.endtime
52 output['critical'] = test.critical
53 output['text'] = test.message
54 output['elapsedtime'] = test.elapsedtime
55 self._data.append(output)
58 """Get the details of the result."""
62 class ODLTests(testcase.TestCase):
63 """ODL test runner."""
65 repos = "/home/opnfv/repos/"
66 odl_test_repo = os.path.join(repos, "odl_test")
67 neutron_suite_dir = os.path.join(odl_test_repo,
68 "csit/suites/openstack/neutron")
69 basic_suite_dir = os.path.join(odl_test_repo,
70 "csit/suites/integration/basic")
71 default_suites = [basic_suite_dir, neutron_suite_dir]
72 res_dir = '/home/opnfv/functest/results/odl/'
73 logger = ft_logger.Logger("opendaylight").getLogger()
76 testcase.TestCase.__init__(self)
77 self.case_name = "odl"
80 def set_robotframework_vars(cls, odlusername="admin", odlpassword="admin"):
81 """Set credentials in csit/variables/Variables.py.
84 True if credentials are set.
87 odl_variables_files = os.path.join(cls.odl_test_repo,
88 'csit/variables/Variables.py')
90 for line in fileinput.input(odl_variables_files,
92 print re.sub("AUTH = .*",
93 ("AUTH = [u'" + odlusername + "', u'" +
97 except Exception as ex: # pylint: disable=broad-except
98 cls.logger.error("Cannot set ODL creds: %s", str(ex))
101 def parse_results(self):
102 """Parse output.xml and get the details in it."""
103 xml_file = os.path.join(self.res_dir, 'output.xml')
104 result = robot.api.ExecutionResult(xml_file)
105 visitor = ODLResultVisitor()
106 result.visit(visitor)
107 self.criteria = result.suite.status
108 self.start_time = timestamp_to_secs(result.suite.starttime)
109 self.stop_time = timestamp_to_secs(result.suite.endtime)
111 self.details['description'] = result.suite.name
112 self.details['tests'] = visitor.get_data()
114 def main(self, suites=None, **kwargs):
115 """Run the test suites
117 It has been designed to be called in any context.
118 It requires the following keyword arguments:
131 * set all RobotFramework_variables,
132 * create the output directories if required,
133 * get the results in output.xml,
134 * delete temporary files.
137 **kwargs: Arbitrary keyword arguments.
140 EX_OK if all suites ran well.
141 EX_RUN_ERROR otherwise.
145 suites = self.default_suites
146 odlusername = kwargs['odlusername']
147 odlpassword = kwargs['odlpassword']
148 osauthurl = kwargs['osauthurl']
149 keystoneip = urlparse.urlparse(osauthurl).hostname
150 variables = ['KEYSTONE:' + keystoneip,
151 'NEUTRON:' + kwargs['neutronip'],
152 'OS_AUTH_URL:"' + osauthurl + '"',
153 'OSUSERNAME:"' + kwargs['osusername'] + '"',
154 'OSTENANTNAME:"' + kwargs['ostenantname'] + '"',
155 'OSPASSWORD:"' + kwargs['ospassword'] + '"',
156 'ODL_SYSTEM_IP:' + kwargs['odlip'],
157 'PORT:' + kwargs['odlwebport'],
158 'RESTCONFPORT:' + kwargs['odlrestconfport']]
159 except KeyError as ex:
160 self.logger.error("Cannot run ODL testcases. Please check "
162 return self.EX_RUN_ERROR
163 if self.set_robotframework_vars(odlusername, odlpassword):
165 os.makedirs(self.res_dir)
166 except OSError as ex:
167 if ex.errno != errno.EEXIST:
168 self.logger.exception(
169 "Cannot create %s", self.res_dir)
170 return self.EX_RUN_ERROR
171 stdout_file = os.path.join(self.res_dir, 'stdout.txt')
172 output_dir = os.path.join(self.res_dir, 'output.xml')
173 with open(stdout_file, 'w+') as stdout:
174 robot.run(*suites, variable=variables,
180 self.logger.info("\n" + stdout.read())
181 self.logger.info("ODL results were successfully generated")
184 self.logger.info("ODL results were successfully parsed")
185 except RobotError as ex:
186 self.logger.error("Run tests before publishing: %s",
188 return self.EX_RUN_ERROR
190 os.remove(stdout_file)
192 self.logger.warning("Cannot remove %s", stdout_file)
195 return self.EX_RUN_ERROR
197 def run(self, **kwargs):
198 """Run suites in OPNFV environment
200 It basically check env vars to call main() with the keywords
204 **kwargs: Arbitrary keyword arguments.
207 EX_OK if all suites ran well.
208 EX_RUN_ERROR otherwise.
211 suites = self.default_suites
213 suites = kwargs["suites"]
216 neutron_url = op_utils.get_endpoint(service_type='network')
217 kwargs = {'neutronip': urlparse.urlparse(neutron_url).hostname}
218 kwargs['odlip'] = kwargs['neutronip']
219 kwargs['odlwebport'] = '8080'
220 kwargs['odlrestconfport'] = '8181'
221 kwargs['odlusername'] = 'admin'
222 kwargs['odlpassword'] = 'admin'
223 installer_type = None
224 if 'INSTALLER_TYPE' in os.environ:
225 installer_type = os.environ['INSTALLER_TYPE']
226 kwargs['osusername'] = os.environ['OS_USERNAME']
227 kwargs['ostenantname'] = os.environ['OS_TENANT_NAME']
228 kwargs['osauthurl'] = os.environ['OS_AUTH_URL']
229 kwargs['ospassword'] = os.environ['OS_PASSWORD']
230 if installer_type == 'fuel':
231 kwargs['odlwebport'] = '8282'
232 elif installer_type == 'apex' or installer_type == 'netvirt':
233 kwargs['odlip'] = os.environ['SDN_CONTROLLER_IP']
234 kwargs['odlwebport'] = '8081'
235 kwargs['odlrestconfport'] = '8081'
236 elif installer_type == 'joid':
237 kwargs['odlip'] = os.environ['SDN_CONTROLLER']
238 elif installer_type == 'compass':
239 kwargs['odlwebport'] = '8181'
241 kwargs['odlip'] = os.environ['SDN_CONTROLLER_IP']
242 except KeyError as ex:
243 self.logger.error("Cannot run ODL testcases. "
244 "Please check env var: "
246 return self.EX_RUN_ERROR
247 except Exception: # pylint: disable=broad-except
248 self.logger.exception("Cannot run ODL testcases.")
249 return self.EX_RUN_ERROR
251 return self.main(suites, **kwargs)
254 class ODLParser(object): # pylint: disable=too-few-public-methods
255 """Parser to run ODL test suites."""
258 self.parser = argparse.ArgumentParser()
259 self.parser.add_argument(
260 '-n', '--neutronip', help='Neutron IP',
262 self.parser.add_argument(
263 '-k', '--osauthurl', help='OS_AUTH_URL as defined by OpenStack',
264 default='http://127.0.0.1:5000/v2.0')
265 self.parser.add_argument(
266 '-a', '--osusername', help='Username for OpenStack',
268 self.parser.add_argument(
269 '-b', '--ostenantname', help='Tenantname for OpenStack',
271 self.parser.add_argument(
272 '-c', '--ospassword', help='Password for OpenStack',
274 self.parser.add_argument(
275 '-o', '--odlip', help='OpenDaylight IP',
277 self.parser.add_argument(
278 '-w', '--odlwebport', help='OpenDaylight Web Portal Port',
280 self.parser.add_argument(
281 '-r', '--odlrestconfport', help='OpenDaylight RESTConf Port',
283 self.parser.add_argument(
284 '-d', '--odlusername', help='Username for ODL',
286 self.parser.add_argument(
287 '-e', '--odlpassword', help='Password for ODL',
289 self.parser.add_argument(
290 '-p', '--pushtodb', help='Push results to DB',
293 def parse_args(self, argv=None):
296 It can call sys.exit if arguments are incorrect.
299 the arguments from cmdline
303 return vars(self.parser.parse_args(argv))
306 if __name__ == '__main__':
309 ARGS = PARSER.parse_args(sys.argv[1:])
311 RESULT = ODL.main(ODLTests.default_suites, **ARGS)
312 if RESULT != testcase.TestCase.EX_OK:
315 sys.exit(ODL.push_to_db())
316 except Exception: # pylint: disable=broad-except
317 sys.exit(testcase.TestCase.EX_RUN_ERROR)