3 # Copyright (c) 2017 Huawei Technologies Co.,Ltd 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 """Refstack client testcase implemenation."""
12 from __future__ import division
23 from xtesting.core import testcase
24 from xtesting.energy import energy
26 from functest.opnfv_tests.openstack.tempest import conf_utils
27 from functest.opnfv_tests.openstack.tempest import tempest
28 from functest.utils import config
29 from functest.utils import functest_utils
32 __author__ = ("Matthew Li <matthew.lijun@huawei.com>,"
33 "Linda Wang <wangwulin@huawei.com>")
35 # logging configuration """
36 LOGGER = logging.getLogger(__name__)
39 class RefstackClient(testcase.TestCase):
40 """RefstackClient testcase implementation class."""
41 # pylint: disable=too-many-instance-attributes
43 defcorelist = os.path.join(
44 getattr(config.CONF, 'dir_refstack_data'), 'defcore.txt')
46 def __init__(self, **kwargs):
47 """Initialize RefstackClient testcase object."""
48 if "case_name" not in kwargs:
49 kwargs["case_name"] = "refstack_defcore"
50 super(RefstackClient, self).__init__(**kwargs)
51 self.resdir = os.path.join(
52 getattr(config.CONF, 'dir_results'), 'refstack')
53 self.conf_path = os.path.join(self.resdir, 'refstack_tempest.conf')
56 def run_defcore(conf, testlist):
57 """Run defcore sys command."""
59 if ('https' in os.environ['OS_AUTH_URL'] and
60 os.getenv('OS_INSECURE', '').lower() == 'true'):
62 cmd = ("refstack-client test {0} -c {1} -v --test-list {2}"
63 .format(insecure, conf, testlist))
64 LOGGER.info("Starting Refstack_defcore test case: '%s'.", cmd)
65 functest_utils.execute_command(cmd)
67 def run_defcore_default(self):
68 """Run default defcore sys command."""
70 if ('https' in os.environ['OS_AUTH_URL'] and
71 os.getenv('OS_INSECURE', '').lower() == 'true'):
73 options = ["-v"] if not insecure else ["-v", insecure]
74 cmd = (["refstack-client", "test", "-c", self.conf_path] +
75 options + ["--test-list", self.defcorelist])
76 LOGGER.info("Starting Refstack_defcore test case: '%s'.", cmd)
77 with open(os.path.join(self.resdir, "refstack.log"), 'w+') as f_stdout:
78 subprocess.call(cmd, shell=False, stdout=f_stdout,
79 stderr=subprocess.STDOUT)
81 def parse_refstack_result(self):
82 """Parse Refstack results."""
84 with open(os.path.join(self.resdir,
85 "refstack.log"), 'r') as logfile:
86 for line in logfile.readlines():
89 if re.search(r"\} tempest\.", line):
90 LOGGER.info(line.replace('\n', ''))
92 with open(os.path.join(self.resdir,
93 "refstack.log"), 'r') as logfile:
94 output = logfile.read()
96 for match in re.findall(r"Ran: (\d+) tests in (\d+\.\d{4}) sec.",
99 LOGGER.info("Ran: %s tests in %s sec.", num_tests, match[1])
100 for match in re.findall(r"(- Passed: )(\d+)", output):
101 num_success = match[1]
102 LOGGER.info("".join(match))
103 for match in re.findall(r"(- Skipped: )(\d+)", output):
104 num_skipped = match[1]
105 LOGGER.info("".join(match))
106 for match in re.findall(r"(- Failed: )(\d+)", output):
107 num_failures = match[1]
108 LOGGER.info("".join(match))
109 success_testcases = []
110 for match in re.findall(r"\{0\} (.*?) \.{3} ok", output):
111 success_testcases.append(match)
112 failed_testcases = []
113 for match in re.findall(r"\{0\} (.*?) \.{3} FAILED", output):
114 failed_testcases.append(match)
115 skipped_testcases = []
116 for match in re.findall(r"\{0\} (.*?) \.{3} SKIPPED:", output):
117 skipped_testcases.append(match)
119 num_executed = int(num_tests) - int(num_skipped)
122 self.result = 100 * int(num_success) / int(num_executed)
123 except ZeroDivisionError:
124 LOGGER.error("No test has been executed")
126 self.details = {"tests": int(num_tests),
127 "failures": int(num_failures),
128 "success": success_testcases,
129 "errors": failed_testcases,
130 "skipped": skipped_testcases}
131 except Exception: # pylint: disable=broad-except
133 LOGGER.info("Testcase %s success_rate is %s%%",
134 self.case_name, self.result)
136 def configure_tempest_defcore(self):
137 # pylint: disable=too-many-arguments
139 Add/update needed parameters into tempest.conf file
141 resources = tempest.TempestResourcesManager().create(
142 create_project=True, use_custom_images=True,
143 use_custom_flavors=True)
144 verifier_id = conf_utils.get_verifier_id()
145 deployment_id = conf_utils.get_verifier_deployment_id()
146 deployment_dir = conf_utils.get_verifier_deployment_dir(
147 verifier_id, deployment_id)
148 conf_file = conf_utils.configure_verifier(deployment_dir)
149 conf_utils.configure_tempest_update_params(
150 conf_file, resources.get("network_name"),
151 resources.get("image_id"), resources.get("flavor_id"))
153 "Updating selected tempest.conf parameters for defcore...")
154 rconfig = ConfigParser.RawConfigParser()
155 rconfig.read(conf_file)
157 'DEFAULT', 'log_file', '{}/tempest.log'.format(deployment_dir))
158 rconfig.set('oslo_concurrency', 'lock_path',
159 '{}/lock_files'.format(deployment_dir))
160 conf_utils.generate_test_accounts_file(
161 tenant_id=resources.get("project_id"))
162 rconfig.set('auth', 'test_accounts_file',
163 conf_utils.TEST_ACCOUNTS_FILE)
164 rconfig.set('scenario', 'img_dir', '{}'.format(deployment_dir))
165 rconfig.set('scenario', 'img_file', 'tempest-image')
166 rconfig.set('compute', 'image_ref', resources.get("image_id"))
167 rconfig.set('compute', 'image_ref_alt', resources.get("image_id_alt"))
168 rconfig.set('compute', 'flavor_ref', resources.get("flavor_id"))
169 rconfig.set('compute', 'flavor_ref_alt',
170 resources.get("flavor_id_alt"))
171 if not os.path.exists(self.resdir):
172 os.makedirs(self.resdir)
173 with open(self.conf_path, 'w') as config_fd:
174 rconfig.write(config_fd)
176 @energy.enable_recording
177 def run(self, **kwargs):
179 Start RefstackClient testcase.
181 used for functest command line,
182 functest testcase run refstack_defcore
184 self.start_time = time.time()
186 # Make sure that Tempest is configured
187 self.configure_tempest_defcore()
188 self.run_defcore_default()
189 self.parse_refstack_result()
190 res = testcase.TestCase.EX_OK
191 except Exception: # pylint: disable=broad-except
192 LOGGER.exception("Error with run")
193 res = testcase.TestCase.EX_RUN_ERROR
194 self.stop_time = time.time()
200 Execute RefstackClient testcase manually.
202 used for manually running,
203 python refstack_client.py -c <tempest_conf_path>
204 --testlist <testlist_path>
205 can generate a reference refstack_tempest.conf by
206 python tempest_conf.py
209 conf_path = kwargs['config']
210 if not os.path.isfile(conf_path):
211 LOGGER.error("Conf file not valid: %s", conf_path)
212 return testcase.TestCase.EX_RUN_ERROR
213 testlist = kwargs['testlist']
214 if not os.path.isfile(testlist):
215 LOGGER.error("testlist file not valid: %s", testlist)
216 return testcase.TestCase.EX_RUN_ERROR
217 except KeyError as exc:
218 LOGGER.error("Cannot run refstack client. Please check "
220 return testcase.TestCase.EX_RUN_ERROR
222 RefstackClient.run_defcore(conf_path, testlist)
223 except Exception as exc: # pylint: disable=broad-except
224 LOGGER.error('Error with run: %s', exc)
225 return testcase.TestCase.EX_RUN_ERROR
226 return testcase.TestCase.EX_OK
229 class RefstackClientParser(object): # pylint: disable=too-few-public-methods
230 """Command line argument parser helper."""
233 """Initialize helper object."""
234 self.parser = argparse.ArgumentParser()
235 self.parser.add_argument(
237 help='the file path of refstack_tempest.conf')
238 self.parser.add_argument(
240 help='Specify the file path or URL of a test list text file. '
241 'This test list will contain specific test cases that '
243 default=RefstackClient.defcorelist)
245 def parse_args(self, argv=None):
246 """Parse command line arguments."""
247 return vars(self.parser.parse_args(argv))
251 """Run RefstackClient testcase with CLI."""
252 logging.basicConfig()
253 refstackclient = RefstackClient()
254 parser = RefstackClientParser()
255 args = parser.parse_args(sys.argv[1:])
257 result = refstackclient.main(**args)
258 if result != testcase.TestCase.EX_OK:
260 except Exception: # pylint: disable=broad-except
261 return testcase.TestCase.EX_RUN_ERROR