Merge "Update unit test related to vyos_vrouter"
[functest.git] / functest / opnfv_tests / openstack / refstack_client / refstack_client.py
1 #!/usr/bin/env python
2
3 # Copyright (c) 2017 Huawei Technologies Co.,Ltd and others.
4 #
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
9
10 """Refstack client testcase implemenation."""
11
12 from __future__ import division
13
14 import argparse
15 import logging
16 import os
17 import re
18 import sys
19 import subprocess
20 import time
21
22 import pkg_resources
23
24 from functest.core import testcase
25 from functest.energy import energy
26 from functest.opnfv_tests.openstack.refstack_client.tempest_conf \
27     import TempestConf
28 from functest.opnfv_tests.openstack.tempest import conf_utils
29 from functest.utils.constants import CONST
30 import functest.utils.functest_utils as ft_utils
31
32 __author__ = ("Matthew Li <matthew.lijun@huawei.com>,"
33               "Linda Wang <wangwulin@huawei.com>")
34
35 # logging configuration """
36 LOGGER = logging.getLogger(__name__)
37
38
39 class RefstackClient(testcase.TestCase):
40     """RefstackClient testcase implementation class."""
41
42     def __init__(self, **kwargs):
43         """Initialize RefstackClient testcase object."""
44         if "case_name" not in kwargs:
45             kwargs["case_name"] = "refstack_defcore"
46         super(RefstackClient, self).__init__(**kwargs)
47         self.tempestconf = None
48         self.conf_path = pkg_resources.resource_filename(
49             'functest',
50             'opnfv_tests/openstack/refstack_client/refstack_tempest.conf')
51         self.functest_test = pkg_resources.resource_filename(
52             'functest', 'opnfv_tests')
53         self.defcore_list = 'openstack/refstack_client/defcore.txt'
54         self.confpath = os.path.join(self.functest_test,
55                                      self.conf_path)
56         self.defcorelist = pkg_resources.resource_filename(
57             'functest', 'opnfv_tests/openstack/refstack_client/defcore.txt')
58         self.testlist = None
59         self.insecure = ''
60         if ('https' in CONST.__getattribute__('OS_AUTH_URL') and
61                 CONST.__getattribute__('OS_INSECURE').lower() == 'true'):
62             self.insecure = '-k'
63
64     def generate_conf(self):
65         if not os.path.exists(conf_utils.REFSTACK_RESULTS_DIR):
66             os.makedirs(conf_utils.REFSTACK_RESULTS_DIR)
67
68         self.tempestconf = TempestConf()
69         self.tempestconf.generate_tempestconf()
70
71     def run_defcore(self, conf, testlist):
72         """Run defcore sys command."""
73         cmd = ("refstack-client test {0} -c {1} -v --test-list {2}"
74                .format(self.insecure, conf, testlist))
75         LOGGER.info("Starting Refstack_defcore test case: '%s'.", cmd)
76         ft_utils.execute_command(cmd)
77
78     def run_defcore_default(self):
79         """Run default defcore sys command."""
80         options = ["-v"] if not self.insecure else ["-v", self.insecure]
81         cmd = (["refstack-client", "test", "-c", self.confpath] +
82                options + ["--test-list", self.defcorelist])
83         LOGGER.info("Starting Refstack_defcore test case: '%s'.", cmd)
84
85         with open(os.path.join(conf_utils.REFSTACK_RESULTS_DIR,
86                                "environment.log"), 'w+') as f_env:
87             f_env.write(
88                 ("Refstack environment:\n"
89                  "  SUT: {}\n  Scenario: {}\n  Node: {}\n  Date: {}\n").format(
90                     CONST.__getattribute__('INSTALLER_TYPE'),
91                     CONST.__getattribute__('DEPLOY_SCENARIO'),
92                     CONST.__getattribute__('NODE_NAME'),
93                     time.strftime("%a %b %d %H:%M:%S %Z %Y")))
94
95         with open(os.path.join(conf_utils.REFSTACK_RESULTS_DIR,
96                                "refstack.log"), 'w+') as f_stdout:
97             subprocess.call(cmd, shell=False, stdout=f_stdout,
98                             stderr=subprocess.STDOUT)
99
100     def parse_refstack_result(self):
101         """Parse Refstack results."""
102         try:
103             with open(os.path.join(conf_utils.REFSTACK_RESULTS_DIR,
104                                    "refstack.log"), 'r') as logfile:
105                 for line in logfile.readlines():
106                     if 'Tests' in line:
107                         break
108                     if re.search(r"\} tempest\.", line):
109                         LOGGER.info(line.replace('\n', ''))
110
111             with open(os.path.join(conf_utils.REFSTACK_RESULTS_DIR,
112                                    "refstack.log"), 'r') as logfile:
113                 output = logfile.read()
114
115             for match in re.findall(r"Ran: (\d+) tests in (\d+\.\d{4}) sec.",
116                                     output):
117                 num_tests = match[0]
118                 LOGGER.info("Ran: %s tests in %s sec.", num_tests, match[1])
119             for match in re.findall(r"(- Passed: )(\d+)", output):
120                 num_success = match[1]
121                 LOGGER.info("".join(match))
122             for match in re.findall(r"(- Skipped: )(\d+)", output):
123                 num_skipped = match[1]
124                 LOGGER.info("".join(match))
125             for match in re.findall(r"(- Failed: )(\d+)", output):
126                 num_failures = match[1]
127                 LOGGER.info("".join(match))
128             success_testcases = []
129             for match in re.findall(r"\{0\} (.*?)[. ]*ok", output):
130                 success_testcases.append(match)
131             failed_testcases = []
132             for match in re.findall(r"\{0\} (.*?)[. ]*FAILED", output):
133                 failed_testcases.append(match)
134             skipped_testcases = []
135             for match in re.findall(r"\{0\} (.*?)[. ]*SKIPPED:", output):
136                 skipped_testcases.append(match)
137
138             num_executed = int(num_tests) - int(num_skipped)
139
140             try:
141                 self.result = 100 * int(num_success) / int(num_executed)
142             except ZeroDivisionError:
143                 LOGGER.error("No test has been executed")
144
145             self.details = {"tests": int(num_tests),
146                             "failures": int(num_failures),
147                             "success": success_testcases,
148                             "errors": failed_testcases,
149                             "skipped": skipped_testcases}
150         except Exception:
151             self.result = 0
152
153         LOGGER.info("Testcase %s success_rate is %s%%",
154                     self.case_name, self.result)
155
156     @energy.enable_recording
157     def run(self, **kwargs):
158         """
159         Start RefstackClient testcase.
160
161         used for functest command line,
162         functest testcase run refstack_defcore
163         """
164         self.start_time = time.time()
165
166         try:
167             # Make sure that Tempest is configured
168             if not self.tempestconf:
169                 self.generate_conf()
170             self.run_defcore_default()
171             self.parse_refstack_result()
172             res = testcase.TestCase.EX_OK
173         except Exception:
174             LOGGER.exception("Error with run")
175             res = testcase.TestCase.EX_RUN_ERROR
176         finally:
177             self.tempestconf.clean()
178
179         self.stop_time = time.time()
180         return res
181
182     def _prep_test(self):
183         """Check that the config file exists."""
184         if not os.path.isfile(self.confpath):
185             LOGGER.error("Conf file not valid: %s", self.confpath)
186         if not os.path.isfile(self.testlist):
187             LOGGER.error("testlist file not valid: %s", self.testlist)
188
189     def main(self, **kwargs):
190         """
191         Execute RefstackClient testcase manually.
192
193         used for manually running,
194            python refstack_client.py -c <tempest_conf_path>
195            --testlist <testlist_path>
196            can generate a reference refstack_tempest.conf by
197            python tempest_conf.py
198         """
199         try:
200             self.confpath = kwargs['config']
201             self.testlist = kwargs['testlist']
202         except KeyError as exc:
203             LOGGER.error("Cannot run refstack client. Please check "
204                          "%s", exc)
205             return self.EX_RUN_ERROR
206         try:
207             self._prep_test()
208             self.run_defcore(self.confpath, self.testlist)
209             res = testcase.TestCase.EX_OK
210         except Exception as exc:
211             LOGGER.error('Error with run: %s', exc)
212             res = testcase.TestCase.EX_RUN_ERROR
213
214         return res
215
216
217 class RefstackClientParser(object):  # pylint: disable=too-few-public-methods
218     """Command line argument parser helper."""
219
220     def __init__(self):
221         """Initialize helper object."""
222         self.functest_test = pkg_resources.resource_filename(
223             'functest', 'opnfv_tests')
224         self.conf_path = pkg_resources.resource_filename(
225             'functest',
226             'opnfv_tests/openstack/refstack_client/refstack_tempest.conf')
227         self.defcore_list = pkg_resources.resource_filename(
228             'functest', 'opnfv_tests/openstack/refstack_client/defcore.txt')
229         self.confpath = os.path.join(self.functest_test,
230                                      self.conf_path)
231         self.defcorelist = os.path.join(self.functest_test,
232                                         self.defcore_list)
233         self.parser = argparse.ArgumentParser()
234         self.parser.add_argument(
235             '-c', '--config',
236             help='the file path of refstack_tempest.conf',
237             default=self.confpath)
238         self.parser.add_argument(
239             '-t', '--testlist',
240             help='Specify the file path or URL of a test list text file. '
241                  'This test list will contain specific test cases that '
242                  'should be tested.',
243             default=self.defcorelist)
244
245     def parse_args(self, argv=None):
246         """Parse command line arguments."""
247         return vars(self.parser.parse_args(argv))
248
249
250 def main():
251     """Run RefstackClient testcase with CLI."""
252     logging.basicConfig()
253     refstackclient = RefstackClient()
254     parser = RefstackClientParser()
255     args = parser.parse_args(sys.argv[1:])
256     try:
257         result = refstackclient.main(**args)
258         if result != testcase.TestCase.EX_OK:
259             return result
260     except Exception:
261         return testcase.TestCase.EX_RUN_ERROR