blob: c6d3a54cfa719c082ec862068284fc7eeaa17d28 [file] [log] [blame]
Vishal Bhojdc338f62020-05-18 15:38:18 +05301#!/usr/bin/env python3
Chase Qi09edc7f2016-08-18 13:18:50 +08002import argparse
3import csv
Milosz Wasilewski2fea70e2016-11-11 12:16:09 +00004import cmd
Chase Qia158efe2017-11-17 12:35:11 +08005import copy
Chase Qi09edc7f2016-08-18 13:18:50 +08006import json
7import logging
Vishal Bhoje94da4a2020-05-15 12:22:40 +05308import netrc
Chase Qi09edc7f2016-08-18 13:18:50 +08009import os
Chase Qi09edc7f2016-08-18 13:18:50 +080010import re
Milosz Wasilewski682120e2017-03-13 13:37:18 +000011import shlex
Chase Qi09edc7f2016-08-18 13:18:50 +080012import shutil
Milosz Wasilewski970431b2016-11-25 14:10:08 +000013import subprocess
Chase Qi09edc7f2016-08-18 13:18:50 +080014import sys
Milosz Wasilewski259ba192017-07-27 10:59:25 +010015import textwrap
Chase Qi09edc7f2016-08-18 13:18:50 +080016import time
Chase Qi09edc7f2016-08-18 13:18:50 +080017from uuid import uuid4
Chase Qiea543352017-09-21 16:44:30 +080018from distutils.spawn import find_executable
Chase Qi09edc7f2016-08-18 13:18:50 +080019
20
Chase Qifaf7d282016-08-29 19:34:01 +080021try:
Vishal Bhoje94da4a2020-05-15 12:22:40 +053022 from squad_client.core.api import SquadApi
23 from squad_client.shortcuts import submit_results
24 from squad_client.core.models import Squad
25 from urllib.parse import urlparse
26except ImportError as e:
Benjamin Copeland15d743e2021-02-22 08:35:10 +000027 logger = logging.getLogger("RUNNER")
28 logger.warning("squad_client is needed if you want to upload to qa-reports")
Vishal Bhoje94da4a2020-05-15 12:22:40 +053029
30
31try:
Chase Qifaf7d282016-08-29 19:34:01 +080032 import pexpect
33 import yaml
34except ImportError as e:
35 print(e)
Benjamin Copeland15d743e2021-02-22 08:35:10 +000036 print("Please run the below command to install modules required")
37 print("pip3 install -r ${REPO_PATH}/automated/utils/requirements.txt")
Chase Qifaf7d282016-08-29 19:34:01 +080038 sys.exit(1)
39
40
Milosz Wasilewski259ba192017-07-27 10:59:25 +010041class StoreDictKeyPair(argparse.Action):
42 def __init__(self, option_strings, dest, nargs=None, **kwargs):
43 self._nargs = nargs
Benjamin Copeland15d743e2021-02-22 08:35:10 +000044 super(StoreDictKeyPair, self).__init__(
45 option_strings, dest, nargs=nargs, **kwargs
46 )
Milosz Wasilewski259ba192017-07-27 10:59:25 +010047
48 def __call__(self, parser, namespace, values, option_string=None):
49 my_dict = {}
50 for kv in values:
Milosz Wasilewskif9c8c062017-08-02 16:10:40 +010051 if "=" in kv:
52 k, v = kv.split("=", 1)
53 my_dict[k] = v
54 else:
55 print("Invalid parameter: %s" % kv)
Milosz Wasilewski259ba192017-07-27 10:59:25 +010056 setattr(namespace, self.dest, my_dict)
57
58
Milosz Wasilewskidf71a762017-07-20 13:26:21 +010059# quit gracefully if the connection is closed by remote host
60SSH_PARAMS = "-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ServerAliveInterval=5"
Milosz Wasilewski682120e2017-03-13 13:37:18 +000061
62
Dan Ruea9eb01c2017-06-07 16:29:09 -050063def run_command(command, target=None):
64 """ Run a shell command. If target is specified, ssh to the given target first. """
65
66 run = command
67 if target:
68 run = 'ssh {} {} "{}"'.format(SSH_PARAMS, target, command)
69
Benjamin Copeland15d743e2021-02-22 08:35:10 +000070 logger = logging.getLogger("RUNNER.run_command")
Dan Ruea9eb01c2017-06-07 16:29:09 -050071 logger.debug(run)
Chase Qi3efa7692017-06-26 15:54:05 +080072 if sys.version_info[0] < 3:
73 return subprocess.check_output(shlex.split(run)).strip()
74 else:
Benjamin Copeland15d743e2021-02-22 08:35:10 +000075 return subprocess.check_output(shlex.split(run)).strip().decode("utf-8")
Milosz Wasilewski682120e2017-03-13 13:37:18 +000076
77
Chase Qi09edc7f2016-08-18 13:18:50 +080078class TestPlan(object):
79 """
80 Analysis args specified, then generate test plan.
81 """
82
83 def __init__(self, args):
Chase Qi09edc7f2016-08-18 13:18:50 +080084 self.test_def = args.test_def
85 self.test_plan = args.test_plan
86 self.timeout = args.timeout
87 self.skip_install = args.skip_install
Benjamin Copeland15d743e2021-02-22 08:35:10 +000088 self.logger = logging.getLogger("RUNNER.TestPlan")
Chase Qia158efe2017-11-17 12:35:11 +080089 self.overlay = args.overlay
90
91 def apply_overlay(self, test_list):
92 fixed_test_list = copy.deepcopy(test_list)
Benjamin Copeland15d743e2021-02-22 08:35:10 +000093 logger = logging.getLogger("RUNNER.TestPlan.Overlay")
Chase Qia158efe2017-11-17 12:35:11 +080094 with open(self.overlay) as f:
95 data = yaml.load(f)
96
Benjamin Copeland15d743e2021-02-22 08:35:10 +000097 if data.get("skip"):
98 skip_tests = data["skip"]
Chase Qia158efe2017-11-17 12:35:11 +080099 for test in test_list:
100 for skip_test in skip_tests:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000101 if (
102 test["path"] == skip_test["path"]
103 and test["repository"] == skip_test["repository"]
104 ):
Chase Qia158efe2017-11-17 12:35:11 +0800105 fixed_test_list.remove(test)
106 logger.info("Skipped: {}".format(test))
107 else:
108 continue
109
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000110 if data.get("amend"):
111 amend_tests = data["amend"]
Chase Qia158efe2017-11-17 12:35:11 +0800112 for test in fixed_test_list:
113 for amend_test in amend_tests:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000114 if (
115 test["path"] == amend_test["path"]
116 and test["repository"] == skip_test["repository"]
117 ):
118 if amend_test.get("parameters"):
119 if test.get("parameters"):
120 test["parameters"].update(amend_test["parameters"])
Chase Qia158efe2017-11-17 12:35:11 +0800121 else:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000122 test["parameters"] = amend_test["parameters"]
123 logger.info("Updated: {}".format(test))
Chase Qia158efe2017-11-17 12:35:11 +0800124 else:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000125 logger.warning(
126 "'parameters' not found in {}, nothing to amend.".format(
127 amend_test
128 )
129 )
Chase Qia158efe2017-11-17 12:35:11 +0800130
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000131 if data.get("add"):
132 add_tests = data["add"]
Chase Qia158efe2017-11-17 12:35:11 +0800133 unique_add_tests = []
134 for test in add_tests:
135 if test not in unique_add_tests:
136 unique_add_tests.append(test)
137 else:
138 logger.warning("Skipping duplicate test {}".format(test))
139
140 for test in test_list:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000141 del test["uuid"]
Chase Qia158efe2017-11-17 12:35:11 +0800142
143 for add_test in unique_add_tests:
144 if add_test in test_list:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000145 logger.warning(
146 "{} already included in test plan, do nothing.".format(add_test)
147 )
Chase Qia158efe2017-11-17 12:35:11 +0800148 else:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000149 add_test["uuid"] = str(uuid4())
Chase Qia158efe2017-11-17 12:35:11 +0800150 fixed_test_list.append(add_test)
151 logger.info("Added: {}".format(add_test))
152
153 return fixed_test_list
Chase Qi09edc7f2016-08-18 13:18:50 +0800154
Milosz Wasilewski2fea70e2016-11-11 12:16:09 +0000155 def test_list(self, kind="automated"):
Chase Qi09edc7f2016-08-18 13:18:50 +0800156 if self.test_def:
157 if not os.path.exists(self.test_def):
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000158 self.logger.error(" %s NOT found, exiting..." % self.test_def)
Chase Qi09edc7f2016-08-18 13:18:50 +0800159 sys.exit(1)
160
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000161 test_list = [{"path": self.test_def}]
162 test_list[0]["uuid"] = str(uuid4())
163 test_list[0]["timeout"] = self.timeout
164 test_list[0]["skip_install"] = self.skip_install
Chase Qi09edc7f2016-08-18 13:18:50 +0800165 elif self.test_plan:
166 if not os.path.exists(self.test_plan):
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000167 self.logger.error(" %s NOT found, exiting..." % self.test_plan)
Chase Qi09edc7f2016-08-18 13:18:50 +0800168 sys.exit(1)
169
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000170 with open(self.test_plan, "r") as f:
Chase Qi09edc7f2016-08-18 13:18:50 +0800171 test_plan = yaml.safe_load(f)
172 try:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000173 plan_version = test_plan["metadata"].get("format")
174 self.logger.info("Test plan version: {}".format(plan_version))
Milosz Wasilewski8d64bb22019-06-18 12:32:08 +0100175 tests = []
Chase Qidca4fb62017-11-22 12:09:42 +0800176 if plan_version == "Linaro Test Plan v2":
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000177 tests = test_plan["tests"][kind]
Chase Qidca4fb62017-11-22 12:09:42 +0800178 elif plan_version == "Linaro Test Plan v1" or plan_version is None:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000179 for requirement in test_plan["requirements"]:
180 if "tests" in requirement.keys():
181 if (
182 requirement["tests"]
183 and kind in requirement["tests"].keys()
184 and requirement["tests"][kind]
185 ):
186 for test in requirement["tests"][kind]:
Chase Qidca4fb62017-11-22 12:09:42 +0800187 tests.append(test)
188
Milosz Wasilewski2fea70e2016-11-11 12:16:09 +0000189 test_list = []
Dan Rued9d7b652017-05-26 14:00:10 -0500190 unique_tests = [] # List of test hashes
Chase Qidca4fb62017-11-22 12:09:42 +0800191 for test in tests:
192 test_hash = hash(json.dumps(test, sort_keys=True))
193 if test_hash in unique_tests:
194 # Test is already in the test_list; don't add it again.
195 self.logger.warning("Skipping duplicate test {}".format(test))
196 continue
197 unique_tests.append(test_hash)
198 test_list.append(test)
Chase Qi09edc7f2016-08-18 13:18:50 +0800199 for test in test_list:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000200 test["uuid"] = str(uuid4())
Chase Qi09edc7f2016-08-18 13:18:50 +0800201 except KeyError as e:
202 self.logger.error("%s is missing from test plan" % str(e))
203 sys.exit(1)
204 else:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000205 self.logger.error("Plese specify a test or test plan.")
Chase Qi09edc7f2016-08-18 13:18:50 +0800206 sys.exit(1)
207
Chase Qia158efe2017-11-17 12:35:11 +0800208 if self.overlay is None:
209 return test_list
210 else:
211 return self.apply_overlay(test_list)
Chase Qi09edc7f2016-08-18 13:18:50 +0800212
213
214class TestSetup(object):
215 """
216 Create directories required, then copy files needed to these directories.
217 """
218
219 def __init__(self, test, args):
Milosz Wasilewski682120e2017-03-13 13:37:18 +0000220 self.test = test
221 self.args = args
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000222 self.logger = logging.getLogger("RUNNER.TestSetup")
Milosz Wasilewski2fea70e2016-11-11 12:16:09 +0000223 self.test_kind = args.kind
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000224 self.test_version = test.get("version", None)
Chase Qi09edc7f2016-08-18 13:18:50 +0800225
226 def validate_env(self):
227 # Inspect if environment set properly.
228 try:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000229 self.repo_path = os.environ["REPO_PATH"]
Chase Qi09edc7f2016-08-18 13:18:50 +0800230 except KeyError:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000231 self.logger.error("KeyError: REPO_PATH")
232 self.logger.error(
233 "Please run '. ./bin/setenv.sh' to setup test environment"
234 )
Chase Qi09edc7f2016-08-18 13:18:50 +0800235 sys.exit(1)
236
237 def create_dir(self):
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000238 if not os.path.exists(self.test["output"]):
239 os.makedirs(self.test["output"])
240 self.logger.info("Output directory created: %s" % self.test["output"])
Chase Qi09edc7f2016-08-18 13:18:50 +0800241
242 def copy_test_repo(self):
243 self.validate_env()
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000244 shutil.rmtree(self.test["test_path"], ignore_errors=True)
245 if self.repo_path in self.test["test_path"]:
246 self.logger.error(
247 "Cannot copy repository into itself. Please choose output directory outside repository path"
248 )
Chase Qi33eb7652016-12-02 10:43:46 +0800249 sys.exit(1)
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000250 shutil.copytree(self.repo_path, self.test["test_path"], symlinks=True)
251 self.logger.info("Test repo copied to: %s" % self.test["test_path"])
Chase Qi09edc7f2016-08-18 13:18:50 +0800252
Milosz Wasilewski970431b2016-11-25 14:10:08 +0000253 def checkout_version(self):
254 if self.test_version:
255 path = os.getcwd()
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000256 os.chdir(self.test["test_path"])
Milosz Wasilewski970431b2016-11-25 14:10:08 +0000257 subprocess.call("git checkout %s" % self.test_version, shell=True)
258 os.chdir(path)
259
Chase Qi09edc7f2016-08-18 13:18:50 +0800260 def create_uuid_file(self):
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000261 with open("%s/uuid" % self.test["test_path"], "w") as f:
262 f.write(self.test["uuid"])
Chase Qi09edc7f2016-08-18 13:18:50 +0800263
264
265class TestDefinition(object):
266 """
267 Convert test definition to testdef.yaml, testdef_metadata and run.sh.
268 """
269
270 def __init__(self, test, args):
Milosz Wasilewski2fea70e2016-11-11 12:16:09 +0000271 self.test = test
272 self.args = args
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000273 self.logger = logging.getLogger("RUNNER.TestDef")
Chase Qi09edc7f2016-08-18 13:18:50 +0800274 self.skip_install = args.skip_install
Milosz Wasilewski2fea70e2016-11-11 12:16:09 +0000275 self.is_manual = False
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000276 if "skip_install" in test:
277 self.skip_install = test["skip_install"]
Chase Qi09edc7f2016-08-18 13:18:50 +0800278 self.custom_params = None
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000279 if "parameters" in test:
280 self.custom_params = test["parameters"]
281 if "params" in test:
282 self.custom_params = test["params"]
Milosz Wasilewski2fea70e2016-11-11 12:16:09 +0000283 self.exists = False
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000284 if os.path.isfile(self.test["path"]):
Milosz Wasilewski2fea70e2016-11-11 12:16:09 +0000285 self.exists = True
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000286 with open(self.test["path"], "r") as f:
Milosz Wasilewski2fea70e2016-11-11 12:16:09 +0000287 self.testdef = yaml.safe_load(f)
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000288 if self.testdef["metadata"]["format"].startswith(
289 "Manual Test Definition"
290 ):
Milosz Wasilewski2fea70e2016-11-11 12:16:09 +0000291 self.is_manual = True
Nicolas Dechesne51b85a82017-02-04 00:45:48 +0100292 if self.is_manual:
293 self.runner = ManualTestRun(test, args)
Chase Qi43bb9122017-05-23 14:37:48 +0800294 elif self.args.target is not None:
Nicolas Dechesne51b85a82017-02-04 00:45:48 +0100295 self.runner = RemoteTestRun(test, args)
Chase Qi43bb9122017-05-23 14:37:48 +0800296 else:
297 self.runner = AutomatedTestRun(test, args)
Chase Qi09edc7f2016-08-18 13:18:50 +0800298
299 def definition(self):
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000300 with open("%s/testdef.yaml" % self.test["test_path"], "wb") as f:
301 f.write(yaml.dump(self.testdef, encoding="utf-8", allow_unicode=True))
Chase Qi09edc7f2016-08-18 13:18:50 +0800302
303 def metadata(self):
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000304 with open("%s/testdef_metadata" % self.test["test_path"], "wb") as f:
305 f.write(
306 yaml.dump(
307 self.testdef["metadata"], encoding="utf-8", allow_unicode=True
308 )
309 )
Chase Qi09edc7f2016-08-18 13:18:50 +0800310
Nicolas Dechesne51b85a82017-02-04 00:45:48 +0100311 def mkrun(self):
Milosz Wasilewski2fea70e2016-11-11 12:16:09 +0000312 if not self.is_manual:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000313 with open("%s/run.sh" % self.test["test_path"], "a") as f:
314 f.write("#!/bin/sh\n")
Chase Qi09edc7f2016-08-18 13:18:50 +0800315
Milosz Wasilewski2fea70e2016-11-11 12:16:09 +0000316 self.parameters = self.handle_parameters()
317 if self.parameters:
318 for line in self.parameters:
319 f.write(line)
Chase Qi09edc7f2016-08-18 13:18:50 +0800320
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000321 f.write("set -e\n")
322 f.write("set -x\n")
323 f.write("export TESTRUN_ID=%s\n" % self.testdef["metadata"]["name"])
Milosz Wasilewski682120e2017-03-13 13:37:18 +0000324 if self.args.target is None:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000325 f.write("cd %s\n" % (self.test["test_path"]))
Milosz Wasilewski682120e2017-03-13 13:37:18 +0000326 else:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000327 f.write("cd %s\n" % (self.test["target_test_path"]))
328 f.write("UUID=`cat uuid`\n")
Milosz Wasilewski2fea70e2016-11-11 12:16:09 +0000329 f.write('echo "<STARTRUN $TESTRUN_ID $UUID>"\n')
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000330 f.write(
331 "export PATH=/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin\n"
332 )
333 steps = self.testdef["run"].get("steps", [])
Milosz Wasilewski2fea70e2016-11-11 12:16:09 +0000334 if steps:
Dan Rueb592da12017-06-07 16:32:43 -0500335 for step in steps:
336 command = step
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000337 if "--cmd" in step or "--shell" in step:
338 command = re.sub(r"\$(\d+)\b", r"\\$\1", step)
339 f.write("%s\n" % command)
Milosz Wasilewski2fea70e2016-11-11 12:16:09 +0000340 f.write('echo "<ENDRUN $TESTRUN_ID $UUID>"\n')
Chase Qi09edc7f2016-08-18 13:18:50 +0800341
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000342 os.chmod("%s/run.sh" % self.test["test_path"], 0o755)
Milosz Wasilewski2fea70e2016-11-11 12:16:09 +0000343
Nicolas Dechesne51b85a82017-02-04 00:45:48 +0100344 def run(self):
345 self.runner.run()
Chase Qi09edc7f2016-08-18 13:18:50 +0800346
347 def handle_parameters(self):
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000348 ret_val = ["###default parameters from test definition###\n"]
Chase Qi09edc7f2016-08-18 13:18:50 +0800349
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000350 if "params" in self.testdef:
351 for def_param_name, def_param_value in list(self.testdef["params"].items()):
Chase Qi09edc7f2016-08-18 13:18:50 +0800352 # ?'yaml_line'
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000353 if def_param_name == "yaml_line":
Chase Qi09edc7f2016-08-18 13:18:50 +0800354 continue
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000355 ret_val.append("%s='%s'\n" % (def_param_name, def_param_value))
356 elif "parameters" in self.testdef:
357 for def_param_name, def_param_value in list(
358 self.testdef["parameters"].items()
359 ):
360 if def_param_name == "yaml_line":
Chase Qi09edc7f2016-08-18 13:18:50 +0800361 continue
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000362 ret_val.append("%s='%s'\n" % (def_param_name, def_param_value))
Chase Qi09edc7f2016-08-18 13:18:50 +0800363 else:
364 return None
365
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000366 ret_val.append("######\n")
Chase Qi09edc7f2016-08-18 13:18:50 +0800367
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000368 ret_val.append("###custom parameters from test plan###\n")
Chase Qi09edc7f2016-08-18 13:18:50 +0800369 if self.custom_params:
370 for param_name, param_value in list(self.custom_params.items()):
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000371 if param_name == "yaml_line":
Chase Qi09edc7f2016-08-18 13:18:50 +0800372 continue
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000373 ret_val.append("%s='%s'\n" % (param_name, param_value))
Chase Qi09edc7f2016-08-18 13:18:50 +0800374
375 if self.skip_install:
376 ret_val.append('SKIP_INSTALL="True"\n')
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000377 ret_val.append("######\n")
Chase Qi09edc7f2016-08-18 13:18:50 +0800378
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000379 ret_val.append("###custom parameters from command line###\n")
Milosz Wasilewski259ba192017-07-27 10:59:25 +0100380 if self.args.test_def_params:
381 for param_name, param_value in self.args.test_def_params.items():
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000382 ret_val.append("%s='%s'\n" % (param_name, param_value))
383 ret_val.append("######\n")
Chase Qi09edc7f2016-08-18 13:18:50 +0800384 return ret_val
385
386
387class TestRun(object):
388 def __init__(self, test, args):
Milosz Wasilewski682120e2017-03-13 13:37:18 +0000389 self.test = test
390 self.args = args
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000391 self.logger = logging.getLogger("RUNNER.TestRun")
Milosz Wasilewski682120e2017-03-13 13:37:18 +0000392 self.test_timeout = self.args.timeout
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000393 if "timeout" in test:
394 self.test_timeout = test["timeout"]
Milosz Wasilewski2fea70e2016-11-11 12:16:09 +0000395
396 def run(self):
397 raise NotImplementedError
398
399 def check_result(self):
400 raise NotImplementedError
401
402
403class AutomatedTestRun(TestRun):
404 def run(self):
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000405 self.logger.info("Executing %s/run.sh" % self.test["test_path"])
406 shell_cmd = "%s/run.sh 2>&1 | tee %s/stdout.log" % (
407 self.test["test_path"],
408 self.test["test_path"],
409 )
410 self.child = pexpect.spawnu("/bin/sh", ["-c", shell_cmd])
Milosz Wasilewski682120e2017-03-13 13:37:18 +0000411 self.check_result()
Chase Qi09edc7f2016-08-18 13:18:50 +0800412
Milosz Wasilewski2fea70e2016-11-11 12:16:09 +0000413 def check_result(self):
Chase Qi09edc7f2016-08-18 13:18:50 +0800414 if self.test_timeout:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000415 self.logger.info("Test timeout: %s" % self.test_timeout)
Chase Qi09edc7f2016-08-18 13:18:50 +0800416 test_end = time.time() + self.test_timeout
417
418 while self.child.isalive():
419 if self.test_timeout and time.time() > test_end:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000420 self.logger.warning(
421 "%s test timed out, killing test process..."
422 % self.test["test_uuid"]
423 )
Chase Qi09edc7f2016-08-18 13:18:50 +0800424 self.child.terminate(force=True)
425 break
426 try:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000427 self.child.expect("\r\n")
Milosz Wasilewskid71f28a2020-06-10 20:05:13 +0100428 print(self.child.before)
Chase Qi09edc7f2016-08-18 13:18:50 +0800429 except pexpect.TIMEOUT:
430 continue
431 except pexpect.EOF:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000432 self.logger.info("%s test finished.\n" % self.test["test_uuid"])
Chase Qi09edc7f2016-08-18 13:18:50 +0800433 break
434
435
Milosz Wasilewski682120e2017-03-13 13:37:18 +0000436class RemoteTestRun(AutomatedTestRun):
437 def copy_to_target(self):
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000438 os.chdir(self.test["test_path"])
Milosz Wasilewski682120e2017-03-13 13:37:18 +0000439 tarball_name = "target-test-files.tar"
Dan Ruea9eb01c2017-06-07 16:29:09 -0500440
441 self.logger.info("Archiving test files")
442 run_command(
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000443 "tar -caf %s run.sh uuid automated/lib automated/bin automated/utils %s"
444 % (tarball_name, self.test["tc_relative_dir"])
445 )
Dan Ruea9eb01c2017-06-07 16:29:09 -0500446
447 self.logger.info("Creating test path")
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000448 run_command("mkdir -p %s" % (self.test["target_test_path"]), self.args.target)
Dan Ruea9eb01c2017-06-07 16:29:09 -0500449
450 self.logger.info("Copying test archive to target host")
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000451 run_command(
452 "scp %s ./%s %s:%s"
453 % (
454 SSH_PARAMS,
455 tarball_name,
456 self.args.target,
457 self.test["target_test_path"],
458 )
459 )
Dan Ruea9eb01c2017-06-07 16:29:09 -0500460
461 self.logger.info("Unarchiving test files on target")
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000462 run_command(
463 "cd %s && tar -xf %s" % (self.test["target_test_path"], tarball_name),
464 self.args.target,
465 )
Dan Ruea9eb01c2017-06-07 16:29:09 -0500466
467 self.logger.info("Removing test file archive from target")
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000468 run_command(
469 "rm %s/%s" % (self.test["target_test_path"], tarball_name), self.args.target
470 )
Milosz Wasilewski682120e2017-03-13 13:37:18 +0000471
472 def run(self):
473 self.copy_to_target()
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000474 self.logger.info(
475 "Executing %s/run.sh remotely on %s"
476 % (self.test["target_test_path"], self.args.target)
477 )
478 shell_cmd = 'ssh %s %s "%s/run.sh 2>&1"' % (
479 SSH_PARAMS,
480 self.args.target,
481 self.test["target_test_path"],
482 )
483 self.logger.debug("shell_cmd: %s" % shell_cmd)
484 output = open("%s/stdout.log" % self.test["test_path"], "w")
Milosz Wasilewskid71f28a2020-06-10 20:05:13 +0100485 self.child = pexpect.spawnu(shell_cmd)
Milosz Wasilewski682120e2017-03-13 13:37:18 +0000486 self.child.logfile = output
487 self.check_result()
488
489
Milosz Wasilewski2fea70e2016-11-11 12:16:09 +0000490class ManualTestShell(cmd.Cmd):
Nicolas Dechesne1945d3f2020-10-07 23:36:34 +0200491 def __init__(self, test_dict, result_path, test_case_id):
Milosz Wasilewski2fea70e2016-11-11 12:16:09 +0000492 cmd.Cmd.__init__(self)
493 self.test_dict = test_dict
Nicolas Dechesne1945d3f2020-10-07 23:36:34 +0200494 self.test_case_id = test_case_id
Milosz Wasilewski2fea70e2016-11-11 12:16:09 +0000495 self.result_path = result_path
496 self.current_step_index = 0
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000497 self.steps = self.test_dict["run"]["steps"]
498 self.expected = self.test_dict["run"]["expected"]
499 self.prompt = "%s[%s] > " % (
500 self.test_dict["metadata"]["name"],
501 self.test_case_id,
502 )
Milosz Wasilewski2fea70e2016-11-11 12:16:09 +0000503 self.result = None
504 self.intro = """
505 Welcome to manual test executor. Type 'help' for available commands.
506 This shell is meant to be executed on your computer, not on the system
507 under test. Please execute the steps from the test case, compare to
508 expected result and record the test result as 'pass' or 'fail'. If there
509 is an issue that prevents from executing the step, please record the result
510 as 'skip'.
511 """
512
513 def do_quit(self, line):
514 """
515 Exit test execution
516 """
517 if self.result is not None:
518 return True
519 if line.find("-f") >= 0:
520 self._record_result("skip")
521 return True
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000522 print(
523 "Test result not recorded. Use -f to force. Forced quit records result as 'skip'"
524 )
Milosz Wasilewski2fea70e2016-11-11 12:16:09 +0000525
526 do_EOF = do_quit
527
528 def do_description(self, line):
529 """
530 Prints current test overall description
531 """
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000532 print(self.test_dict["metadata"]["description"])
Milosz Wasilewski2fea70e2016-11-11 12:16:09 +0000533
534 def do_steps(self, line):
535 """
536 Prints all steps of the current test case
537 """
538 for index, step in enumerate(self.steps):
Chase Qic69235d2017-05-23 14:56:47 +0800539 print("%s. %s" % (index, step))
Milosz Wasilewski2fea70e2016-11-11 12:16:09 +0000540
541 def do_expected(self, line):
542 """
543 Prints all expected results of the current test case
544 """
545 for index, expected in enumerate(self.expected):
Chase Qic69235d2017-05-23 14:56:47 +0800546 print("%s. %s" % (index, expected))
Milosz Wasilewski2fea70e2016-11-11 12:16:09 +0000547
548 def do_current(self, line):
549 """
550 Prints current test step
551 """
552 self._print_step()
553
554 do_start = do_current
555
556 def do_next(self, line):
557 """
558 Prints next test step
559 """
560 if len(self.steps) > self.current_step_index + 1:
561 self.current_step_index += 1
562 self._print_step()
563
564 def _print_step(self):
Chase Qic69235d2017-05-23 14:56:47 +0800565 print("%s. %s" % (self.current_step_index, self.steps[self.current_step_index]))
Milosz Wasilewski2fea70e2016-11-11 12:16:09 +0000566
567 def _record_result(self, result):
Chase Qic69235d2017-05-23 14:56:47 +0800568 print("Recording %s in %s/stdout.log" % (result, self.result_path))
Milosz Wasilewski2fea70e2016-11-11 12:16:09 +0000569 with open("%s/stdout.log" % self.result_path, "a") as f:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000570 f.write(
571 "<LAVA_SIGNAL_TESTCASE TEST_CASE_ID=%s RESULT=%s>"
572 % (self.test_case_id, result)
573 )
Milosz Wasilewski2fea70e2016-11-11 12:16:09 +0000574
575 def do_pass(self, line):
576 """
577 Records PASS as test result
578 """
579 self.result = "pass"
580 self._record_result(self.result)
581 return True
582
583 def do_fail(self, line):
584 """
585 Records FAIL as test result
586 """
587 self.result = "fail"
588 self._record_result(self.result)
589 return True
590
591 def do_skip(self, line):
592 """
593 Records SKIP as test result
594 """
595 self.result = "skip"
596 self._record_result(self.result)
597 return True
598
599
600class ManualTestRun(TestRun, cmd.Cmd):
601 def run(self):
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000602 print(self.test["test_name"])
603 with open("%s/testdef.yaml" % self.test["test_path"], "r") as f:
Milosz Wasilewski2fea70e2016-11-11 12:16:09 +0000604 self.testdef = yaml.safe_load(f)
605
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000606 if "name" in self.test:
607 test_case_id = self.test["name"]
Nicolas Dechesne1945d3f2020-10-07 23:36:34 +0200608 else:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000609 test_case_id = self.testdef["metadata"]["name"]
Nicolas Dechesne1945d3f2020-10-07 23:36:34 +0200610
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000611 ManualTestShell(self.testdef, self.test["test_path"], test_case_id).cmdloop()
Milosz Wasilewski2fea70e2016-11-11 12:16:09 +0000612
613 def check_result(self):
614 pass
615
616
Dan Ruea9eb01c2017-06-07 16:29:09 -0500617def get_packages(linux_distribution, target=None):
618 """ Return a list of installed packages with versions
619
620 linux_distribution is a string that may be 'debian',
621 'ubuntu', 'centos', or 'fedora'.
622
623 For example (ubuntu):
624 'packages': ['acl-2.2.52-2',
625 'adduser-3.113+nmu3',
626 ...
627 'zlib1g:amd64-1:1.2.8.dfsg-2+b1',
628 'zlib1g-dev:amd64-1:1.2.8.dfsg-2+b1']
629
630 (centos):
631 "packages": ["acl-2.2.51-12.el7",
632 "apr-1.4.8-3.el7",
633 ...
634 "zlib-1.2.7-17.el7",
635 "zlib-devel-1.2.7-17.el7"
636 ]
637 """
638
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000639 logger = logging.getLogger("RUNNER.get_packages")
Dan Ruea9eb01c2017-06-07 16:29:09 -0500640 packages = []
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000641 if linux_distribution in ["debian", "ubuntu"]:
Dan Ruea9eb01c2017-06-07 16:29:09 -0500642 # Debian (apt) based system
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000643 packages = run_command(
644 "dpkg-query -W -f '${package}-${version}\n'", target
645 ).splitlines()
Dan Ruea9eb01c2017-06-07 16:29:09 -0500646
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000647 elif linux_distribution in ["centos", "fedora"]:
Dan Ruea9eb01c2017-06-07 16:29:09 -0500648 # RedHat (rpm) based system
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000649 packages = run_command(
650 "rpm -qa --qf '%{NAME}-%{VERSION}-%{RELEASE}\n'", target
651 ).splitlines()
Dan Ruea9eb01c2017-06-07 16:29:09 -0500652 else:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000653 logger.warning(
654 "Unknown linux distribution '{}'; package list not populated.".format(
655 linux_distribution
656 )
657 )
Dan Ruea9eb01c2017-06-07 16:29:09 -0500658
659 packages.sort()
660 return packages
661
662
663def get_environment(target=None, skip_collection=False):
664 """ Return a dictionary with environmental information
665
666 target: optional ssh host string to gather environment remotely.
667 skip_collection: Skip data collection and return an empty dictionary.
668
669 For example (on a HiSilicon D03):
670 {
671 "bios_version": "Hisilicon D03 UEFI 16.12 Release",
672 "board_name": "D03",
673 "board_vendor": "Huawei",
674 "kernel": "4.9.0-20.gitedc2a1c.linaro.aarch64",
675 "linux_distribution": "centos",
676 "packages": [
677 "GeoIP-1.5.0-11.el7",
678 "NetworkManager-1.4.0-20.el7_3",
679 ...
680 "yum-plugin-fastestmirror-1.1.31-40.el7",
681 "zlib-1.2.7-17.el7"
682 ],
683 "uname": "Linux localhost.localdomain 4.9.0-20.gitedc2a1c.linaro.aarch64 #1 SMP Wed Dec 14 17:50:15 UTC 2016 aarch64 aarch64 aarch64 GNU/Linux"
684 }
685 """
686
687 environment = {}
688 if skip_collection:
689 return environment
Milosz Wasilewskidf71a762017-07-20 13:26:21 +0100690 try:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000691 environment["linux_distribution"] = (
692 run_command("grep ^ID= /etc/os-release", target)
693 .split("=")[-1]
694 .strip('"')
695 .lower()
696 )
Milosz Wasilewskidf71a762017-07-20 13:26:21 +0100697 except subprocess.CalledProcessError:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000698 environment["linux_distribution"] = ""
Milosz Wasilewskidf71a762017-07-20 13:26:21 +0100699
700 try:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000701 environment["kernel"] = run_command("uname -r", target)
Milosz Wasilewskidf71a762017-07-20 13:26:21 +0100702 except subprocess.CalledProcessError:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000703 environment["kernel"] = ""
Milosz Wasilewskidf71a762017-07-20 13:26:21 +0100704
705 try:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000706 environment["uname"] = run_command("uname -a", target)
Milosz Wasilewskidf71a762017-07-20 13:26:21 +0100707 except subprocess.CalledProcessError:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000708 environment["uname"] = ""
Dan Ruea9eb01c2017-06-07 16:29:09 -0500709
710 try:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000711 environment["bios_version"] = run_command(
712 "cat /sys/devices/virtual/dmi/id/bios_version", target
713 )
Dan Ruea9eb01c2017-06-07 16:29:09 -0500714 except subprocess.CalledProcessError:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000715 environment["bios_version"] = ""
Dan Ruea9eb01c2017-06-07 16:29:09 -0500716
717 try:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000718 environment["board_vendor"] = run_command(
719 "cat /sys/devices/virtual/dmi/id/board_vendor", target
720 )
Dan Ruea9eb01c2017-06-07 16:29:09 -0500721 except subprocess.CalledProcessError:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000722 environment["board_vendor"] = ""
Dan Ruea9eb01c2017-06-07 16:29:09 -0500723
724 try:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000725 environment["board_name"] = run_command(
726 "cat /sys/devices/virtual/dmi/id/board_name", target
727 )
Dan Ruea9eb01c2017-06-07 16:29:09 -0500728 except subprocess.CalledProcessError:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000729 environment["board_name"] = ""
Dan Ruea9eb01c2017-06-07 16:29:09 -0500730
Milosz Wasilewskidf71a762017-07-20 13:26:21 +0100731 try:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000732 environment["packages"] = get_packages(
733 environment["linux_distribution"], target
734 )
Milosz Wasilewskidf71a762017-07-20 13:26:21 +0100735 except subprocess.CalledProcessError:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000736 environment["packages"] = []
Dan Ruea9eb01c2017-06-07 16:29:09 -0500737 return environment
738
739
Chase Qi09edc7f2016-08-18 13:18:50 +0800740class ResultParser(object):
741 def __init__(self, test, args):
Milosz Wasilewski682120e2017-03-13 13:37:18 +0000742 self.test = test
743 self.args = args
Chase Qi09edc7f2016-08-18 13:18:50 +0800744 self.metrics = []
745 self.results = {}
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000746 self.results["test"] = test["test_name"]
747 self.results["id"] = test["test_uuid"]
748 self.results["test_plan"] = args.test_plan
749 self.results["environment"] = get_environment(
750 target=self.args.target, skip_collection=self.args.skip_environment
751 )
752 self.logger = logging.getLogger("RUNNER.ResultParser")
753 self.results["params"] = {}
Chase Qie94ba522017-05-26 12:05:18 +0800754 self.pattern = None
755 self.fixup = None
Vishal Bhoje94da4a2020-05-15 12:22:40 +0530756 self.qa_reports_server = args.qa_reports_server
757 if args.qa_reports_token is not None:
758 self.qa_reports_token = args.qa_reports_token
759 else:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000760 self.qa_reports_token = os.environ.get(
761 "QA_REPORTS_TOKEN", get_token_from_netrc(self.qa_reports_server)
762 )
Vishal Bhoje94da4a2020-05-15 12:22:40 +0530763 self.qa_reports_project = args.qa_reports_project
764 self.qa_reports_group = args.qa_reports_group
765 self.qa_reports_env = args.qa_reports_env
766 self.qa_reports_build_version = args.qa_reports_build_version
Milosz Wasilewskib4b40de2020-06-11 12:54:18 +0100767 self.qa_reports_disable_metadata = args.qa_reports_disable_metadata
Milosz Wasilewski37848d32020-06-11 14:33:43 +0100768 self.qa_reports_metadata = args.qa_reports_metadata
Milosz Wasilewskiabe2dcc2020-06-12 10:54:46 +0100769 self.qa_reports_metadata_file = args.qa_reports_metadata_file
Vishal Bhoje94da4a2020-05-15 12:22:40 +0530770
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000771 with open(os.path.join(self.test["test_path"], "testdef.yaml"), "r") as f:
Milosz Wasilewskia76e8dd2016-11-25 14:13:25 +0000772 self.testdef = yaml.safe_load(f)
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000773 self.results["name"] = ""
774 if (
775 "metadata" in self.testdef.keys()
776 and "name" in self.testdef["metadata"].keys()
777 ):
778 self.results["name"] = self.testdef["metadata"]["name"]
779 if "params" in self.testdef.keys():
780 self.results["params"] = self.testdef["params"]
Nicolas Dechesnefaa343d2017-10-23 00:33:10 +0200781 if self.args.test_def_params:
782 for param_name, param_value in self.args.test_def_params.items():
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000783 self.results["params"][param_name] = param_value
784 if (
785 "parse" in self.testdef.keys()
786 and "pattern" in self.testdef["parse"].keys()
787 ):
788 self.pattern = self.testdef["parse"]["pattern"]
Chase Qie94ba522017-05-26 12:05:18 +0800789 self.logger.info("Enabling log parse pattern: %s" % self.pattern)
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000790 if "fixupdict" in self.testdef["parse"].keys():
791 self.fixup = self.testdef["parse"]["fixupdict"]
792 self.logger.info(
793 "Enabling log parse pattern fixup: %s" % self.fixup
794 )
795 if "parameters" in test.keys():
796 self.results["params"].update(test["parameters"])
797 if "params" in test.keys():
798 self.results["params"].update(test["params"])
799 if "version" in test.keys():
800 self.results["version"] = test["version"]
Milosz Wasilewski970431b2016-11-25 14:10:08 +0000801 else:
802 path = os.getcwd()
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000803 os.chdir(self.test["test_path"])
Chase Qi3efa7692017-06-26 15:54:05 +0800804 if sys.version_info[0] < 3:
805 test_version = subprocess.check_output("git rev-parse HEAD", shell=True)
806 else:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000807 test_version = subprocess.check_output(
808 "git rev-parse HEAD", shell=True
809 ).decode("utf-8")
810 self.results["version"] = test_version.rstrip()
Milosz Wasilewski970431b2016-11-25 14:10:08 +0000811 os.chdir(path)
Chase Qiea543352017-09-21 16:44:30 +0800812 self.lava_run = args.lava_run
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000813 if self.lava_run and not find_executable("lava-test-case"):
814 self.logger.info(
815 "lava-test-case not found, '-l' or '--lava_run' option ignored'"
816 )
Chase Qiea543352017-09-21 16:44:30 +0800817 self.lava_run = False
Chase Qi09edc7f2016-08-18 13:18:50 +0800818
819 def run(self):
820 self.parse_stdout()
Chase Qie94ba522017-05-26 12:05:18 +0800821 if self.pattern:
822 self.parse_pattern()
823 # If 'metrics' is empty, add 'no-result-found fail'.
824 if not self.metrics:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000825 self.metrics = [
826 {
827 "test_case_id": "no-result-found",
828 "result": "fail",
829 "measurement": "",
830 "units": "",
831 }
832 ]
833 self.results["metrics"] = self.metrics
Chase Qi09edc7f2016-08-18 13:18:50 +0800834 self.dict_to_json()
835 self.dict_to_csv()
Vishal Bhoje94da4a2020-05-15 12:22:40 +0530836 self.send_to_qa_reports()
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000837 self.logger.info("Result files saved to: %s" % self.test["test_path"])
838 print("--- Printing result.csv ---")
839 with open("%s/result.csv" % self.test["test_path"]) as f:
Chase Qi09edc7f2016-08-18 13:18:50 +0800840 print(f.read())
841
842 def parse_stdout(self):
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000843 with open("%s/stdout.log" % self.test["test_path"], "r") as f:
Milosz Wasilewski5a4dd442016-12-07 15:01:57 +0000844 test_case_re = re.compile("TEST_CASE_ID=(.*)")
845 result_re = re.compile("RESULT=(.*)")
846 measurement_re = re.compile("MEASUREMENT=(.*)")
847 units_re = re.compile("UNITS=(.*)")
Chase Qi09edc7f2016-08-18 13:18:50 +0800848 for line in f:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000849 if re.match(r"\<(|LAVA_SIGNAL_TESTCASE )TEST_CASE_ID=.*", line):
850 line = line.strip("\n").strip("\r").strip("<>").split(" ")
851 data = {
852 "test_case_id": "",
853 "result": "",
854 "measurement": "",
855 "units": "",
856 }
Chase Qi09edc7f2016-08-18 13:18:50 +0800857
858 for string in line:
Milosz Wasilewskiff695622016-12-05 16:00:06 +0000859 test_case_match = test_case_re.match(string)
860 result_match = result_re.match(string)
861 measurement_match = measurement_re.match(string)
862 units_match = units_re.match(string)
863 if test_case_match:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000864 data["test_case_id"] = test_case_match.group(1)
Milosz Wasilewskiff695622016-12-05 16:00:06 +0000865 if result_match:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000866 data["result"] = result_match.group(1)
Milosz Wasilewskiff695622016-12-05 16:00:06 +0000867 if measurement_match:
Nicolas Dechesne508a2272020-10-03 11:10:37 +0200868 try:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000869 data["measurement"] = float(measurement_match.group(1))
Nicolas Dechesne508a2272020-10-03 11:10:37 +0200870 except ValueError as e:
871 pass
Milosz Wasilewskiff695622016-12-05 16:00:06 +0000872 if units_match:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000873 data["units"] = units_match.group(1)
Chase Qi09edc7f2016-08-18 13:18:50 +0800874
875 self.metrics.append(data.copy())
876
Chase Qiea543352017-09-21 16:44:30 +0800877 if self.lava_run:
878 self.send_to_lava(data)
879
Chase Qie94ba522017-05-26 12:05:18 +0800880 def parse_pattern(self):
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000881 with open("%s/stdout.log" % self.test["test_path"], "r") as f:
882 rex_pattern = re.compile(r"%s" % self.pattern)
Chase Qie94ba522017-05-26 12:05:18 +0800883 for line in f:
884 data = {}
Aníbal Limónc36cb792017-11-29 11:54:30 -0600885 m = rex_pattern.search(line)
Chase Qie94ba522017-05-26 12:05:18 +0800886 if m:
887 data = m.groupdict()
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000888 for x in ["measurement", "units"]:
Chase Qie94ba522017-05-26 12:05:18 +0800889 if x not in data:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000890 data[x] = ""
891 if self.fixup and data["result"] in self.fixup:
892 data["result"] = self.fixup[data["result"]]
Chase Qi1f2a9a02017-03-09 15:45:04 +0100893
Chase Qie94ba522017-05-26 12:05:18 +0800894 self.metrics.append(data.copy())
Chase Qi09edc7f2016-08-18 13:18:50 +0800895
Chase Qiea543352017-09-21 16:44:30 +0800896 if self.lava_run:
897 self.send_to_lava(data)
898
899 def send_to_lava(self, data):
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000900 cmd = "lava-test-case {} --result {}".format(
901 data["test_case_id"], data["result"]
902 )
903 if data["measurement"]:
904 cmd = "{} --measurement {} --units {}".format(
905 cmd, data["measurement"], data["units"]
906 )
907 self.logger.debug("lava-run: cmd: {}".format(cmd))
Chase Qiea543352017-09-21 16:44:30 +0800908 subprocess.call(shlex.split(cmd))
909
Vishal Bhoje94da4a2020-05-15 12:22:40 +0530910 def send_to_qa_reports(self):
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000911 if None in (
912 self.qa_reports_server,
913 self.qa_reports_token,
914 self.qa_reports_group,
915 self.qa_reports_project,
916 self.qa_reports_build_version,
917 self.qa_reports_env,
918 ):
919 self.logger.warning(
920 "All parameters for qa reports are not set, results will not be pushed to qa reports"
921 )
Vishal Bhoje94da4a2020-05-15 12:22:40 +0530922 return
923
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000924 SquadApi.configure(url=self.qa_reports_server, token=self.qa_reports_token)
Vishal Bhoje94da4a2020-05-15 12:22:40 +0530925 tests = {}
926 metrics = {}
927 for metric in self.metrics:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000928 if metric["measurement"] != "":
929 metrics[
930 "{}/{}".format(self.test["test_name"], metric["test_case_id"])
931 ] = metric["measurement"]
Vishal Bhoje94da4a2020-05-15 12:22:40 +0530932 else:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000933 tests[
934 "{}/{}".format(self.test["test_name"], metric["test_case_id"])
935 ] = metric["result"]
Vishal Bhoje94da4a2020-05-15 12:22:40 +0530936
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000937 with open("{}/stdout.log".format(self.test["test_path"]), "r") as logfile:
Vishal Bhoje94da4a2020-05-15 12:22:40 +0530938 log = logfile.read()
939
Milosz Wasilewskiabe2dcc2020-06-12 10:54:46 +0100940 metadata = {}
Milosz Wasilewskib00ceff2020-06-15 13:48:01 +0100941 if not self.qa_reports_disable_metadata:
942 if self.qa_reports_metadata:
943 metadata.update(self.qa_reports_metadata)
944 if self.qa_reports_metadata_file:
945 try:
946 with open(self.qa_reports_metadata_file, "r") as metadata_file:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000947 loaded_metadata = yaml.load(
948 metadata_file, Loader=yaml.SafeLoader
949 )
Milosz Wasilewskib00ceff2020-06-15 13:48:01 +0100950 # check if loaded metadata is key=value and both are strings
951 for key, value in loaded_metadata.items():
952 if type(key) == str and type(value) == str:
953 # only update metadata with simple keys
954 # ignore all other items in the dictionary
955 metadata.update({key: value})
956 else:
957 self.logger.warning("Ignoring key: %s" % key)
958 except FileNotFoundError:
959 self.logger.warning("Metadata file not found")
960 except PermissionError:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000961 self.logger.warning(
962 "Insufficient permissions to open metadata file"
963 )
Milosz Wasilewskif883f102020-06-11 12:46:58 +0100964 if submit_results(
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000965 group_project_slug="{}/{}".format(
966 self.qa_reports_group, self.qa_reports_project
967 ),
968 build_version=self.qa_reports_build_version,
969 env_slug=self.qa_reports_env,
970 tests=tests,
971 metrics=metrics,
972 log=log,
973 metadata=metadata,
974 attachments=None,
975 ):
Milosz Wasilewskif883f102020-06-11 12:46:58 +0100976 self.logger.info("Results pushed to QA Reports")
977 else:
978 self.logger.warning("Results upload to QA Reports failed!")
Vishal Bhoje94da4a2020-05-15 12:22:40 +0530979
Chase Qi09edc7f2016-08-18 13:18:50 +0800980 def dict_to_json(self):
Chase Qi87f4f402016-11-07 15:32:01 +0800981 # Save test results to output/test_id/result.json
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000982 with open("%s/result.json" % self.test["test_path"], "w") as f:
Chase Qi87f4f402016-11-07 15:32:01 +0800983 json.dump([self.results], f, indent=4)
984
985 # Collect test results of all tests in output/result.json
986 feeds = []
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000987 if os.path.isfile("%s/result.json" % self.test["output"]):
988 with open("%s/result.json" % self.test["output"], "r") as f:
Chase Qi87f4f402016-11-07 15:32:01 +0800989 feeds = json.load(f)
990
991 feeds.append(self.results)
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000992 with open("%s/result.json" % self.test["output"], "w") as f:
Chase Qi87f4f402016-11-07 15:32:01 +0800993 json.dump(feeds, f, indent=4)
Chase Qi09edc7f2016-08-18 13:18:50 +0800994
995 def dict_to_csv(self):
Chase Qica15cf52016-11-10 17:00:22 +0800996 # Convert dict self.results['params'] to a string.
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000997 test_params = ""
998 if self.results["params"]:
999 params_dict = self.results["params"]
1000 test_params = ";".join(["%s=%s" % (k, v) for k, v in params_dict.items()])
Chase Qi09edc7f2016-08-18 13:18:50 +08001001
Benjamin Copeland15d743e2021-02-22 08:35:10 +00001002 for metric in self.results["metrics"]:
1003 metric["name"] = self.results["name"]
1004 metric["test_params"] = test_params
Chase Qica15cf52016-11-10 17:00:22 +08001005
1006 # Save test results to output/test_id/result.csv
Benjamin Copeland15d743e2021-02-22 08:35:10 +00001007 fieldnames = [
1008 "name",
1009 "test_case_id",
1010 "result",
1011 "measurement",
1012 "units",
1013 "test_params",
1014 ]
1015 with open("%s/result.csv" % self.test["test_path"], "w") as f:
Chase Qica15cf52016-11-10 17:00:22 +08001016 writer = csv.DictWriter(f, fieldnames=fieldnames)
Chase Qi09edc7f2016-08-18 13:18:50 +08001017 writer.writeheader()
Benjamin Copeland15d743e2021-02-22 08:35:10 +00001018 for metric in self.results["metrics"]:
Chase Qi09edc7f2016-08-18 13:18:50 +08001019 writer.writerow(metric)
1020
Chase Qi87f4f402016-11-07 15:32:01 +08001021 # Collect test results of all tests in output/result.csv
Benjamin Copeland15d743e2021-02-22 08:35:10 +00001022 if not os.path.isfile("%s/result.csv" % self.test["output"]):
1023 with open("%s/result.csv" % self.test["output"], "w") as f:
Chase Qi87f4f402016-11-07 15:32:01 +08001024 writer = csv.DictWriter(f, fieldnames=fieldnames)
1025 writer.writeheader()
1026
Benjamin Copeland15d743e2021-02-22 08:35:10 +00001027 with open("%s/result.csv" % self.test["output"], "a") as f:
Chase Qi09edc7f2016-08-18 13:18:50 +08001028 writer = csv.DictWriter(f, fieldnames=fieldnames)
Benjamin Copeland15d743e2021-02-22 08:35:10 +00001029 for metric in self.results["metrics"]:
Chase Qi09edc7f2016-08-18 13:18:50 +08001030 writer.writerow(metric)
1031
1032
Vishal Bhoje94da4a2020-05-15 12:22:40 +05301033def get_token_from_netrc(qa_reports_server):
1034 if qa_reports_server is None:
1035 return
1036 parse = urlparse(qa_reports_server)
1037 netrc_local = netrc.netrc()
1038 authTokens = netrc_local.authenticators("{}".format(parse.netloc))
1039 if authTokens is not None:
1040 hostname, username, authToken = authTokens
1041 return authToken
1042 # Unable to find Token hence returning None
1043 return
1044
1045
Chase Qi09edc7f2016-08-18 13:18:50 +08001046def get_args():
Milosz Wasilewski259ba192017-07-27 10:59:25 +01001047 parser = argparse.ArgumentParser(formatter_class=argparse.RawTextHelpFormatter)
Benjamin Copeland15d743e2021-02-22 08:35:10 +00001048 parser.add_argument(
1049 "-o",
1050 "--output",
1051 default=os.getenv("HOME", "") + "/output",
1052 dest="output",
1053 help=textwrap.dedent(
1054 """\
Chase Qi09edc7f2016-08-18 13:18:50 +08001055 specify a directory to store test and result files.
Nicolas Dechesnef6c4c212017-01-18 17:30:04 +01001056 Default: $HOME/output
Benjamin Copeland15d743e2021-02-22 08:35:10 +00001057 """
1058 ),
1059 )
1060 parser.add_argument(
1061 "-p",
1062 "--test_plan",
1063 default=None,
1064 dest="test_plan",
1065 help=textwrap.dedent(
1066 """\
Chase Qi09edc7f2016-08-18 13:18:50 +08001067 specify an test plan file which has tests and related
1068 params listed in yaml format.
Benjamin Copeland15d743e2021-02-22 08:35:10 +00001069 """
1070 ),
1071 )
1072 parser.add_argument(
1073 "-d",
1074 "--test_def",
1075 default=None,
1076 dest="test_def",
1077 help=textwrap.dedent(
1078 """\
Chase Qi09edc7f2016-08-18 13:18:50 +08001079 base on test definition repo location, specify relative
1080 path to the test definition to run.
1081 Format example: "ubuntu/smoke-tests-basic.yaml"
Benjamin Copeland15d743e2021-02-22 08:35:10 +00001082 """
1083 ),
1084 )
1085 parser.add_argument(
1086 "-r",
1087 "--test_def_params",
1088 default={},
1089 dest="test_def_params",
1090 action=StoreDictKeyPair,
1091 nargs="+",
1092 metavar="KEY=VALUE",
1093 help=textwrap.dedent(
1094 """\
Milosz Wasilewski259ba192017-07-27 10:59:25 +01001095 Set additional parameters when using test definition without
1096 a test plan. The name values are set similarily to environment
1097 variables:
1098 --test_def_params KEY1=VALUE1 KEY2=VALUE2 ...
Benjamin Copeland15d743e2021-02-22 08:35:10 +00001099 """
1100 ),
1101 )
1102 parser.add_argument(
1103 "-k",
1104 "--kind",
1105 default="automated",
1106 dest="kind",
1107 choices=["automated", "manual"],
1108 help=textwrap.dedent(
1109 """\
Milosz Wasilewski2fea70e2016-11-11 12:16:09 +00001110 Selects type of tests to be executed from the test plan.
1111 Possible options: automated, manual
Benjamin Copeland15d743e2021-02-22 08:35:10 +00001112 """
1113 ),
1114 )
1115 parser.add_argument(
1116 "-t",
1117 "--timeout",
1118 type=int,
1119 default=None,
1120 dest="timeout",
1121 help="Specify test timeout",
1122 )
1123 parser.add_argument(
1124 "-g",
1125 "--target",
1126 default=None,
1127 dest="target",
1128 help=textwrap.dedent(
1129 """\
Milosz Wasilewski682120e2017-03-13 13:37:18 +00001130 Specify SSH target to execute tests.
1131 Format: user@host
1132 Note: ssh authentication must be paswordless
Benjamin Copeland15d743e2021-02-22 08:35:10 +00001133 """
1134 ),
1135 )
1136 parser.add_argument(
1137 "-s",
1138 "--skip_install",
1139 dest="skip_install",
1140 default=False,
1141 action="store_true",
1142 help="skip install section defined in test definition.",
1143 )
1144 parser.add_argument(
1145 "-e",
1146 "--skip_environment",
1147 dest="skip_environment",
1148 default=False,
1149 action="store_true",
1150 help="skip environmental data collection (board name, distro, etc)",
1151 )
1152 parser.add_argument(
1153 "-l",
1154 "--lava_run",
1155 dest="lava_run",
1156 default=False,
1157 action="store_true",
1158 help="send test result to LAVA with lava-test-case.",
1159 )
1160 parser.add_argument(
1161 "-O",
1162 "--overlay",
1163 default=None,
1164 dest="overlay",
1165 help=textwrap.dedent(
1166 """\
Chase Qia158efe2017-11-17 12:35:11 +08001167 Specify test plan ovelay file to:
1168 * skip tests
1169 * amend test parameters
1170 * add new tests
Benjamin Copeland15d743e2021-02-22 08:35:10 +00001171 """
1172 ),
1173 )
1174 parser.add_argument(
1175 "-v",
1176 "--verbose",
1177 action="store_true",
1178 dest="verbose",
1179 default=False,
1180 help="Set log level to DEBUG.",
1181 )
Vishal Bhoje94da4a2020-05-15 12:22:40 +05301182 parser.add_argument(
1183 "--qa-reports-server",
1184 dest="qa_reports_server",
1185 default=None,
1186 help="qa reports server where the results have to be sent",
1187 )
1188 parser.add_argument(
1189 "--qa-reports-token",
1190 dest="qa_reports_token",
1191 default=None,
1192 help="qa reports token to upload the results to qa_reports_server",
1193 )
1194 parser.add_argument(
1195 "--qa-reports-project",
1196 dest="qa_reports_project",
1197 default=None,
1198 help="qa reports projects to which the results have to be uploaded",
1199 )
1200 parser.add_argument(
1201 "--qa-reports-group",
1202 dest="qa_reports_group",
1203 default=None,
1204 help="qa reports group in which the results have to be stored",
1205 )
1206 parser.add_argument(
1207 "--qa-reports-env",
1208 dest="qa_reports_env",
1209 default=None,
1210 help="qa reports environment for the results that have to be stored",
1211 )
1212 parser.add_argument(
1213 "--qa-reports-build-version",
1214 dest="qa_reports_build_version",
1215 default=None,
1216 help="qa reports build id for the result set",
1217 )
Milosz Wasilewskib4b40de2020-06-11 12:54:18 +01001218 parser.add_argument(
1219 "--qa-reports-disable-metadata",
1220 dest="qa_reports_disable_metadata",
1221 default=False,
Benjamin Copeland15d743e2021-02-22 08:35:10 +00001222 action="store_true",
Milosz Wasilewski37848d32020-06-11 14:33:43 +01001223 help="Disable sending metadata to SQUAD. Default: false",
1224 )
1225 parser.add_argument(
1226 "--qa-reports-metadata",
1227 dest="qa_reports_metadata",
1228 default={},
1229 action=StoreDictKeyPair,
1230 nargs="+",
1231 metavar="KEY=VALUE",
1232 help="List of metadata key=value pairs to be sent to SQUAD",
Milosz Wasilewskib4b40de2020-06-11 12:54:18 +01001233 )
Milosz Wasilewskiabe2dcc2020-06-12 10:54:46 +01001234 parser.add_argument(
1235 "--qa-reports-metadata-file",
1236 dest="qa_reports_metadata_file",
1237 default=None,
1238 help="YAML file that defines metadata to be reported to SQUAD",
1239 )
Milosz Wasilewskib4b40de2020-06-11 12:54:18 +01001240
Chase Qi09edc7f2016-08-18 13:18:50 +08001241 args = parser.parse_args()
1242 return args
1243
1244
1245def main():
Chase Qi0e9b36e2017-12-07 16:13:44 +08001246 args = get_args()
1247
Chase Qi09edc7f2016-08-18 13:18:50 +08001248 # Setup logger.
Benjamin Copeland15d743e2021-02-22 08:35:10 +00001249 logger = logging.getLogger("RUNNER")
Chase Qi0e9b36e2017-12-07 16:13:44 +08001250 logger.setLevel(logging.INFO)
1251 if args.verbose:
1252 logger.setLevel(logging.DEBUG)
Chase Qi09edc7f2016-08-18 13:18:50 +08001253 ch = logging.StreamHandler()
1254 ch.setLevel(logging.DEBUG)
Benjamin Copeland15d743e2021-02-22 08:35:10 +00001255 formatter = logging.Formatter("%(asctime)s - %(name)s: %(levelname)s: %(message)s")
Chase Qi09edc7f2016-08-18 13:18:50 +08001256 ch.setFormatter(formatter)
1257 logger.addHandler(ch)
1258
Benjamin Copeland15d743e2021-02-22 08:35:10 +00001259 logger.debug("Test job arguments: %s" % args)
Milosz Wasilewski682120e2017-03-13 13:37:18 +00001260 if args.kind != "manual" and args.target is None:
Milosz Wasilewski2fea70e2016-11-11 12:16:09 +00001261 if os.geteuid() != 0:
1262 logger.error("Sorry, you need to run this as root")
1263 sys.exit(1)
Chase Qi09edc7f2016-08-18 13:18:50 +08001264
Milosz Wasilewski682120e2017-03-13 13:37:18 +00001265 # Validate target argument format and connectivity.
1266 if args.target:
Benjamin Copeland15d743e2021-02-22 08:35:10 +00001267 rex = re.compile(".+@.+")
Milosz Wasilewski682120e2017-03-13 13:37:18 +00001268 if not rex.match(args.target):
Benjamin Copeland15d743e2021-02-22 08:35:10 +00001269 logger.error("Usage: -g username@host")
Milosz Wasilewski682120e2017-03-13 13:37:18 +00001270 sys.exit(1)
Benjamin Copeland15d743e2021-02-22 08:35:10 +00001271 if pexpect.which("ssh") is None:
1272 logger.error("openssh client must be installed on the host.")
Milosz Wasilewski682120e2017-03-13 13:37:18 +00001273 sys.exit(1)
1274 try:
Dan Ruea9eb01c2017-06-07 16:29:09 -05001275 run_command("exit", args.target)
Milosz Wasilewski682120e2017-03-13 13:37:18 +00001276 except subprocess.CalledProcessError as e:
Benjamin Copeland15d743e2021-02-22 08:35:10 +00001277 logger.error("ssh login failed.")
Milosz Wasilewski682120e2017-03-13 13:37:18 +00001278 print(e)
1279 sys.exit(1)
1280
Chase Qi09edc7f2016-08-18 13:18:50 +08001281 # Generate test plan.
Chase Qi09edc7f2016-08-18 13:18:50 +08001282 test_plan = TestPlan(args)
Milosz Wasilewski2fea70e2016-11-11 12:16:09 +00001283 test_list = test_plan.test_list(args.kind)
Benjamin Copeland15d743e2021-02-22 08:35:10 +00001284 logger.info("Tests to run:")
Chase Qi09edc7f2016-08-18 13:18:50 +08001285 for test in test_list:
1286 print(test)
1287
1288 # Run tests.
1289 for test in test_list:
Milosz Wasilewski682120e2017-03-13 13:37:18 +00001290 # Set and save test params to test dictionary.
Benjamin Copeland15d743e2021-02-22 08:35:10 +00001291 test["test_name"] = os.path.splitext(test["path"].split("/")[-1])[0]
1292 test["test_uuid"] = "%s_%s" % (test["test_name"], test["uuid"])
1293 test["output"] = os.path.realpath(args.output)
1294 if args.target is not None and "-o" not in sys.argv:
1295 test["output"] = os.path.join(test["output"], args.target)
1296 test["test_path"] = os.path.join(test["output"], test["test_uuid"])
Milosz Wasilewski682120e2017-03-13 13:37:18 +00001297 if args.target is not None:
Chase Qi204b5422017-04-06 11:01:58 +08001298 # Get relative directory path of yaml file for partial file copy.
1299 # '-d' takes any relative paths to the yaml file, so get the realpath first.
Benjamin Copeland15d743e2021-02-22 08:35:10 +00001300 tc_realpath = os.path.realpath(test["path"])
Chase Qi204b5422017-04-06 11:01:58 +08001301 tc_dirname = os.path.dirname(tc_realpath)
Benjamin Copeland15d743e2021-02-22 08:35:10 +00001302 test["tc_relative_dir"] = "%s%s" % (
1303 args.kind,
1304 tc_dirname.split(args.kind)[1],
1305 )
Dan Ruea9eb01c2017-06-07 16:29:09 -05001306 target_user_home = run_command("echo $HOME", args.target)
Benjamin Copeland15d743e2021-02-22 08:35:10 +00001307 test["target_test_path"] = "%s/output/%s" % (
1308 target_user_home,
1309 test["test_uuid"],
1310 )
1311 logger.debug("Test parameters: %s" % test)
Milosz Wasilewski682120e2017-03-13 13:37:18 +00001312
Chase Qi09edc7f2016-08-18 13:18:50 +08001313 # Create directories and copy files needed.
1314 setup = TestSetup(test, args)
1315 setup.create_dir()
1316 setup.copy_test_repo()
Milosz Wasilewski970431b2016-11-25 14:10:08 +00001317 setup.checkout_version()
Chase Qi09edc7f2016-08-18 13:18:50 +08001318 setup.create_uuid_file()
1319
1320 # Convert test definition.
1321 test_def = TestDefinition(test, args)
Milosz Wasilewski2fea70e2016-11-11 12:16:09 +00001322 if test_def.exists:
1323 test_def.definition()
1324 test_def.metadata()
Nicolas Dechesne51b85a82017-02-04 00:45:48 +01001325 test_def.mkrun()
Chase Qi09edc7f2016-08-18 13:18:50 +08001326
Milosz Wasilewski2fea70e2016-11-11 12:16:09 +00001327 # Run test.
Nicolas Dechesne51b85a82017-02-04 00:45:48 +01001328 test_def.run()
Chase Qi09edc7f2016-08-18 13:18:50 +08001329
Milosz Wasilewski2fea70e2016-11-11 12:16:09 +00001330 # Parse test output, save results in json and csv format.
1331 result_parser = ResultParser(test, args)
1332 result_parser.run()
1333 else:
Benjamin Copeland15d743e2021-02-22 08:35:10 +00001334 logger.warning("Requested test definition %s doesn't exist" % test["path"])
Chase Qi09edc7f2016-08-18 13:18:50 +08001335
Dan Ruea9eb01c2017-06-07 16:29:09 -05001336
Chase Qi09edc7f2016-08-18 13:18:50 +08001337if __name__ == "__main__":
1338 main()