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