blob: 9c09884cd5c4b1c757353131761f8da7085a9a12 [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
Milosz Wasilewski31ac9852021-11-18 11:21:28 +000018from datetime import datetime
Chase Qiea543352017-09-21 16:44:30 +080019from distutils.spawn import find_executable
Chase Qi09edc7f2016-08-18 13:18:50 +080020
21
Chase Qifaf7d282016-08-29 19:34:01 +080022try:
Vishal Bhoje94da4a2020-05-15 12:22:40 +053023 from squad_client.core.api import SquadApi
24 from squad_client.shortcuts import submit_results
25 from squad_client.core.models import Squad
26 from urllib.parse import urlparse
27except ImportError as e:
Benjamin Copeland15d743e2021-02-22 08:35:10 +000028 logger = logging.getLogger("RUNNER")
29 logger.warning("squad_client is needed if you want to upload to qa-reports")
Vishal Bhoje94da4a2020-05-15 12:22:40 +053030
31
32try:
Chase Qifaf7d282016-08-29 19:34:01 +080033 import pexpect
34 import yaml
35except ImportError as e:
36 print(e)
Benjamin Copeland15d743e2021-02-22 08:35:10 +000037 print("Please run the below command to install modules required")
38 print("pip3 install -r ${REPO_PATH}/automated/utils/requirements.txt")
Chase Qifaf7d282016-08-29 19:34:01 +080039 sys.exit(1)
40
41
Milosz Wasilewski259ba192017-07-27 10:59:25 +010042class StoreDictKeyPair(argparse.Action):
43 def __init__(self, option_strings, dest, nargs=None, **kwargs):
44 self._nargs = nargs
Benjamin Copeland15d743e2021-02-22 08:35:10 +000045 super(StoreDictKeyPair, self).__init__(
46 option_strings, dest, nargs=nargs, **kwargs
47 )
Milosz Wasilewski259ba192017-07-27 10:59:25 +010048
49 def __call__(self, parser, namespace, values, option_string=None):
50 my_dict = {}
51 for kv in values:
Milosz Wasilewskif9c8c062017-08-02 16:10:40 +010052 if "=" in kv:
53 k, v = kv.split("=", 1)
54 my_dict[k] = v
55 else:
56 print("Invalid parameter: %s" % kv)
Milosz Wasilewski259ba192017-07-27 10:59:25 +010057 setattr(namespace, self.dest, my_dict)
58
59
Milosz Wasilewskidf71a762017-07-20 13:26:21 +010060# quit gracefully if the connection is closed by remote host
61SSH_PARAMS = "-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ServerAliveInterval=5"
Milosz Wasilewski682120e2017-03-13 13:37:18 +000062
63
Dan Ruea9eb01c2017-06-07 16:29:09 -050064def run_command(command, target=None):
Anders Roxelld5c6cab2021-04-29 00:52:35 +020065 """Run a shell command. If target is specified, ssh to the given target first."""
Dan Ruea9eb01c2017-06-07 16:29:09 -050066
67 run = command
68 if target:
69 run = 'ssh {} {} "{}"'.format(SSH_PARAMS, target, command)
70
Benjamin Copeland15d743e2021-02-22 08:35:10 +000071 logger = logging.getLogger("RUNNER.run_command")
Dan Ruea9eb01c2017-06-07 16:29:09 -050072 logger.debug(run)
Chase Qi3efa7692017-06-26 15:54:05 +080073 if sys.version_info[0] < 3:
74 return subprocess.check_output(shlex.split(run)).strip()
75 else:
Benjamin Copeland15d743e2021-02-22 08:35:10 +000076 return subprocess.check_output(shlex.split(run)).strip().decode("utf-8")
Milosz Wasilewski682120e2017-03-13 13:37:18 +000077
78
Chase Qi09edc7f2016-08-18 13:18:50 +080079class TestPlan(object):
80 """
81 Analysis args specified, then generate test plan.
82 """
83
84 def __init__(self, args):
Chase Qi09edc7f2016-08-18 13:18:50 +080085 self.test_def = args.test_def
86 self.test_plan = args.test_plan
87 self.timeout = args.timeout
88 self.skip_install = args.skip_install
Benjamin Copeland15d743e2021-02-22 08:35:10 +000089 self.logger = logging.getLogger("RUNNER.TestPlan")
Chase Qia158efe2017-11-17 12:35:11 +080090 self.overlay = args.overlay
91
92 def apply_overlay(self, test_list):
93 fixed_test_list = copy.deepcopy(test_list)
Benjamin Copeland15d743e2021-02-22 08:35:10 +000094 logger = logging.getLogger("RUNNER.TestPlan.Overlay")
Chase Qia158efe2017-11-17 12:35:11 +080095 with open(self.overlay) as f:
96 data = yaml.load(f)
97
Benjamin Copeland15d743e2021-02-22 08:35:10 +000098 if data.get("skip"):
99 skip_tests = data["skip"]
Chase Qia158efe2017-11-17 12:35:11 +0800100 for test in test_list:
101 for skip_test in skip_tests:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000102 if (
103 test["path"] == skip_test["path"]
104 and test["repository"] == skip_test["repository"]
105 ):
Chase Qia158efe2017-11-17 12:35:11 +0800106 fixed_test_list.remove(test)
107 logger.info("Skipped: {}".format(test))
108 else:
109 continue
110
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000111 if data.get("amend"):
112 amend_tests = data["amend"]
Chase Qia158efe2017-11-17 12:35:11 +0800113 for test in fixed_test_list:
114 for amend_test in amend_tests:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000115 if (
116 test["path"] == amend_test["path"]
117 and test["repository"] == skip_test["repository"]
118 ):
119 if amend_test.get("parameters"):
120 if test.get("parameters"):
121 test["parameters"].update(amend_test["parameters"])
Chase Qia158efe2017-11-17 12:35:11 +0800122 else:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000123 test["parameters"] = amend_test["parameters"]
124 logger.info("Updated: {}".format(test))
Chase Qia158efe2017-11-17 12:35:11 +0800125 else:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000126 logger.warning(
127 "'parameters' not found in {}, nothing to amend.".format(
128 amend_test
129 )
130 )
Chase Qia158efe2017-11-17 12:35:11 +0800131
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000132 if data.get("add"):
133 add_tests = data["add"]
Chase Qia158efe2017-11-17 12:35:11 +0800134 unique_add_tests = []
135 for test in add_tests:
136 if test not in unique_add_tests:
137 unique_add_tests.append(test)
138 else:
139 logger.warning("Skipping duplicate test {}".format(test))
140
141 for test in test_list:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000142 del test["uuid"]
Chase Qia158efe2017-11-17 12:35:11 +0800143
144 for add_test in unique_add_tests:
145 if add_test in test_list:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000146 logger.warning(
147 "{} already included in test plan, do nothing.".format(add_test)
148 )
Chase Qia158efe2017-11-17 12:35:11 +0800149 else:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000150 add_test["uuid"] = str(uuid4())
Chase Qia158efe2017-11-17 12:35:11 +0800151 fixed_test_list.append(add_test)
152 logger.info("Added: {}".format(add_test))
153
154 return fixed_test_list
Chase Qi09edc7f2016-08-18 13:18:50 +0800155
Milosz Wasilewski2fea70e2016-11-11 12:16:09 +0000156 def test_list(self, kind="automated"):
Chase Qi09edc7f2016-08-18 13:18:50 +0800157 if self.test_def:
158 if not os.path.exists(self.test_def):
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000159 self.logger.error(" %s NOT found, exiting..." % self.test_def)
Chase Qi09edc7f2016-08-18 13:18:50 +0800160 sys.exit(1)
161
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000162 test_list = [{"path": self.test_def}]
163 test_list[0]["uuid"] = str(uuid4())
164 test_list[0]["timeout"] = self.timeout
165 test_list[0]["skip_install"] = self.skip_install
Chase Qi09edc7f2016-08-18 13:18:50 +0800166 elif self.test_plan:
167 if not os.path.exists(self.test_plan):
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000168 self.logger.error(" %s NOT found, exiting..." % self.test_plan)
Chase Qi09edc7f2016-08-18 13:18:50 +0800169 sys.exit(1)
170
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000171 with open(self.test_plan, "r") as f:
Chase Qi09edc7f2016-08-18 13:18:50 +0800172 test_plan = yaml.safe_load(f)
173 try:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000174 plan_version = test_plan["metadata"].get("format")
175 self.logger.info("Test plan version: {}".format(plan_version))
Milosz Wasilewski8d64bb22019-06-18 12:32:08 +0100176 tests = []
Chase Qidca4fb62017-11-22 12:09:42 +0800177 if plan_version == "Linaro Test Plan v2":
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000178 tests = test_plan["tests"][kind]
Chase Qidca4fb62017-11-22 12:09:42 +0800179 elif plan_version == "Linaro Test Plan v1" or plan_version is None:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000180 for requirement in test_plan["requirements"]:
181 if "tests" in requirement.keys():
182 if (
183 requirement["tests"]
184 and kind in requirement["tests"].keys()
185 and requirement["tests"][kind]
186 ):
187 for test in requirement["tests"][kind]:
Chase Qidca4fb62017-11-22 12:09:42 +0800188 tests.append(test)
189
Milosz Wasilewski2fea70e2016-11-11 12:16:09 +0000190 test_list = []
Dan Rued9d7b652017-05-26 14:00:10 -0500191 unique_tests = [] # List of test hashes
Chase Qidca4fb62017-11-22 12:09:42 +0800192 for test in tests:
193 test_hash = hash(json.dumps(test, sort_keys=True))
194 if test_hash in unique_tests:
195 # Test is already in the test_list; don't add it again.
196 self.logger.warning("Skipping duplicate test {}".format(test))
197 continue
198 unique_tests.append(test_hash)
199 test_list.append(test)
Chase Qi09edc7f2016-08-18 13:18:50 +0800200 for test in test_list:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000201 test["uuid"] = str(uuid4())
Chase Qi09edc7f2016-08-18 13:18:50 +0800202 except KeyError as e:
203 self.logger.error("%s is missing from test plan" % str(e))
204 sys.exit(1)
205 else:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000206 self.logger.error("Plese specify a test or test plan.")
Chase Qi09edc7f2016-08-18 13:18:50 +0800207 sys.exit(1)
208
Chase Qia158efe2017-11-17 12:35:11 +0800209 if self.overlay is None:
210 return test_list
211 else:
212 return self.apply_overlay(test_list)
Chase Qi09edc7f2016-08-18 13:18:50 +0800213
214
215class TestSetup(object):
216 """
217 Create directories required, then copy files needed to these directories.
218 """
219
220 def __init__(self, test, args):
Milosz Wasilewski682120e2017-03-13 13:37:18 +0000221 self.test = test
222 self.args = args
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000223 self.logger = logging.getLogger("RUNNER.TestSetup")
Milosz Wasilewski2fea70e2016-11-11 12:16:09 +0000224 self.test_kind = args.kind
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000225 self.test_version = test.get("version", None)
Chase Qi09edc7f2016-08-18 13:18:50 +0800226
227 def validate_env(self):
228 # Inspect if environment set properly.
229 try:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000230 self.repo_path = os.environ["REPO_PATH"]
Chase Qi09edc7f2016-08-18 13:18:50 +0800231 except KeyError:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000232 self.logger.error("KeyError: REPO_PATH")
233 self.logger.error(
234 "Please run '. ./bin/setenv.sh' to setup test environment"
235 )
Chase Qi09edc7f2016-08-18 13:18:50 +0800236 sys.exit(1)
237
238 def create_dir(self):
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000239 if not os.path.exists(self.test["output"]):
240 os.makedirs(self.test["output"])
241 self.logger.info("Output directory created: %s" % self.test["output"])
Chase Qi09edc7f2016-08-18 13:18:50 +0800242
243 def copy_test_repo(self):
244 self.validate_env()
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000245 shutil.rmtree(self.test["test_path"], ignore_errors=True)
246 if self.repo_path in self.test["test_path"]:
247 self.logger.error(
248 "Cannot copy repository into itself. Please choose output directory outside repository path"
249 )
Chase Qi33eb7652016-12-02 10:43:46 +0800250 sys.exit(1)
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000251 shutil.copytree(self.repo_path, self.test["test_path"], symlinks=True)
252 self.logger.info("Test repo copied to: %s" % self.test["test_path"])
Chase Qi09edc7f2016-08-18 13:18:50 +0800253
Milosz Wasilewski970431b2016-11-25 14:10:08 +0000254 def checkout_version(self):
255 if self.test_version:
256 path = os.getcwd()
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000257 os.chdir(self.test["test_path"])
Milosz Wasilewski970431b2016-11-25 14:10:08 +0000258 subprocess.call("git checkout %s" % self.test_version, shell=True)
259 os.chdir(path)
260
Chase Qi09edc7f2016-08-18 13:18:50 +0800261 def create_uuid_file(self):
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000262 with open("%s/uuid" % self.test["test_path"], "w") as f:
263 f.write(self.test["uuid"])
Chase Qi09edc7f2016-08-18 13:18:50 +0800264
265
266class TestDefinition(object):
267 """
268 Convert test definition to testdef.yaml, testdef_metadata and run.sh.
269 """
270
271 def __init__(self, test, args):
Milosz Wasilewski2fea70e2016-11-11 12:16:09 +0000272 self.test = test
273 self.args = args
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000274 self.logger = logging.getLogger("RUNNER.TestDef")
Chase Qi09edc7f2016-08-18 13:18:50 +0800275 self.skip_install = args.skip_install
Milosz Wasilewski2fea70e2016-11-11 12:16:09 +0000276 self.is_manual = False
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000277 if "skip_install" in test:
278 self.skip_install = test["skip_install"]
Chase Qi09edc7f2016-08-18 13:18:50 +0800279 self.custom_params = None
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000280 if "parameters" in test:
281 self.custom_params = test["parameters"]
282 if "params" in test:
283 self.custom_params = test["params"]
Milosz Wasilewski2fea70e2016-11-11 12:16:09 +0000284 self.exists = False
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000285 if os.path.isfile(self.test["path"]):
Milosz Wasilewski2fea70e2016-11-11 12:16:09 +0000286 self.exists = True
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000287 with open(self.test["path"], "r") as f:
Milosz Wasilewski2fea70e2016-11-11 12:16:09 +0000288 self.testdef = yaml.safe_load(f)
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000289 if self.testdef["metadata"]["format"].startswith(
290 "Manual Test Definition"
291 ):
Milosz Wasilewski2fea70e2016-11-11 12:16:09 +0000292 self.is_manual = True
Nicolas Dechesne51b85a82017-02-04 00:45:48 +0100293 if self.is_manual:
294 self.runner = ManualTestRun(test, args)
Chase Qi43bb9122017-05-23 14:37:48 +0800295 elif self.args.target is not None:
Nicolas Dechesne51b85a82017-02-04 00:45:48 +0100296 self.runner = RemoteTestRun(test, args)
Chase Qi43bb9122017-05-23 14:37:48 +0800297 else:
298 self.runner = AutomatedTestRun(test, args)
Chase Qi09edc7f2016-08-18 13:18:50 +0800299
300 def definition(self):
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000301 with open("%s/testdef.yaml" % self.test["test_path"], "wb") as f:
302 f.write(yaml.dump(self.testdef, encoding="utf-8", allow_unicode=True))
Chase Qi09edc7f2016-08-18 13:18:50 +0800303
304 def metadata(self):
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000305 with open("%s/testdef_metadata" % self.test["test_path"], "wb") as f:
306 f.write(
307 yaml.dump(
308 self.testdef["metadata"], encoding="utf-8", allow_unicode=True
309 )
310 )
Chase Qi09edc7f2016-08-18 13:18:50 +0800311
Nicolas Dechesne51b85a82017-02-04 00:45:48 +0100312 def mkrun(self):
Milosz Wasilewski2fea70e2016-11-11 12:16:09 +0000313 if not self.is_manual:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000314 with open("%s/run.sh" % self.test["test_path"], "a") as f:
315 f.write("#!/bin/sh\n")
Chase Qi09edc7f2016-08-18 13:18:50 +0800316
Milosz Wasilewski2fea70e2016-11-11 12:16:09 +0000317 self.parameters = self.handle_parameters()
318 if self.parameters:
319 for line in self.parameters:
320 f.write(line)
Chase Qi09edc7f2016-08-18 13:18:50 +0800321
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000322 f.write("set -e\n")
323 f.write("set -x\n")
324 f.write("export TESTRUN_ID=%s\n" % self.testdef["metadata"]["name"])
Milosz Wasilewski682120e2017-03-13 13:37:18 +0000325 if self.args.target is None:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000326 f.write("cd %s\n" % (self.test["test_path"]))
Milosz Wasilewski682120e2017-03-13 13:37:18 +0000327 else:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000328 f.write("cd %s\n" % (self.test["target_test_path"]))
329 f.write("UUID=`cat uuid`\n")
Milosz Wasilewski2fea70e2016-11-11 12:16:09 +0000330 f.write('echo "<STARTRUN $TESTRUN_ID $UUID>"\n')
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000331 f.write(
332 "export PATH=/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin\n"
333 )
334 steps = self.testdef["run"].get("steps", [])
Milosz Wasilewski2fea70e2016-11-11 12:16:09 +0000335 if steps:
Dan Rueb592da12017-06-07 16:32:43 -0500336 for step in steps:
337 command = step
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000338 if "--cmd" in step or "--shell" in step:
339 command = re.sub(r"\$(\d+)\b", r"\\$\1", step)
340 f.write("%s\n" % command)
Milosz Wasilewski2fea70e2016-11-11 12:16:09 +0000341 f.write('echo "<ENDRUN $TESTRUN_ID $UUID>"\n')
Chase Qi09edc7f2016-08-18 13:18:50 +0800342
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000343 os.chmod("%s/run.sh" % self.test["test_path"], 0o755)
Milosz Wasilewski2fea70e2016-11-11 12:16:09 +0000344
Nicolas Dechesne51b85a82017-02-04 00:45:48 +0100345 def run(self):
346 self.runner.run()
Chase Qi09edc7f2016-08-18 13:18:50 +0800347
348 def handle_parameters(self):
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000349 ret_val = ["###default parameters from test definition###\n"]
Chase Qi09edc7f2016-08-18 13:18:50 +0800350
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000351 if "params" in self.testdef:
352 for def_param_name, def_param_value in list(self.testdef["params"].items()):
Chase Qi09edc7f2016-08-18 13:18:50 +0800353 # ?'yaml_line'
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000354 if def_param_name == "yaml_line":
Chase Qi09edc7f2016-08-18 13:18:50 +0800355 continue
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000356 ret_val.append("%s='%s'\n" % (def_param_name, def_param_value))
357 elif "parameters" in self.testdef:
358 for def_param_name, def_param_value in list(
359 self.testdef["parameters"].items()
360 ):
361 if def_param_name == "yaml_line":
Chase Qi09edc7f2016-08-18 13:18:50 +0800362 continue
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000363 ret_val.append("%s='%s'\n" % (def_param_name, def_param_value))
Chase Qi09edc7f2016-08-18 13:18:50 +0800364 else:
365 return None
366
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000367 ret_val.append("######\n")
Chase Qi09edc7f2016-08-18 13:18:50 +0800368
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000369 ret_val.append("###custom parameters from test plan###\n")
Chase Qi09edc7f2016-08-18 13:18:50 +0800370 if self.custom_params:
371 for param_name, param_value in list(self.custom_params.items()):
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000372 if param_name == "yaml_line":
Chase Qi09edc7f2016-08-18 13:18:50 +0800373 continue
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000374 ret_val.append("%s='%s'\n" % (param_name, param_value))
Chase Qi09edc7f2016-08-18 13:18:50 +0800375
376 if self.skip_install:
377 ret_val.append('SKIP_INSTALL="True"\n')
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000378 ret_val.append("######\n")
Chase Qi09edc7f2016-08-18 13:18:50 +0800379
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000380 ret_val.append("###custom parameters from command line###\n")
Milosz Wasilewski259ba192017-07-27 10:59:25 +0100381 if self.args.test_def_params:
382 for param_name, param_value in self.args.test_def_params.items():
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000383 ret_val.append("%s='%s'\n" % (param_name, param_value))
384 ret_val.append("######\n")
Chase Qi09edc7f2016-08-18 13:18:50 +0800385 return ret_val
386
387
388class TestRun(object):
389 def __init__(self, test, args):
Milosz Wasilewski682120e2017-03-13 13:37:18 +0000390 self.test = test
391 self.args = args
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000392 self.logger = logging.getLogger("RUNNER.TestRun")
Milosz Wasilewski682120e2017-03-13 13:37:18 +0000393 self.test_timeout = self.args.timeout
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000394 if "timeout" in test:
395 self.test_timeout = test["timeout"]
Milosz Wasilewski2fea70e2016-11-11 12:16:09 +0000396
397 def run(self):
398 raise NotImplementedError
399
400 def check_result(self):
401 raise NotImplementedError
402
403
404class AutomatedTestRun(TestRun):
405 def run(self):
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000406 self.logger.info("Executing %s/run.sh" % self.test["test_path"])
407 shell_cmd = "%s/run.sh 2>&1 | tee %s/stdout.log" % (
408 self.test["test_path"],
409 self.test["test_path"],
410 )
411 self.child = pexpect.spawnu("/bin/sh", ["-c", shell_cmd])
Milosz Wasilewski682120e2017-03-13 13:37:18 +0000412 self.check_result()
Chase Qi09edc7f2016-08-18 13:18:50 +0800413
Milosz Wasilewski2fea70e2016-11-11 12:16:09 +0000414 def check_result(self):
Chase Qi09edc7f2016-08-18 13:18:50 +0800415 if self.test_timeout:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000416 self.logger.info("Test timeout: %s" % self.test_timeout)
Chase Qi09edc7f2016-08-18 13:18:50 +0800417 test_end = time.time() + self.test_timeout
418
419 while self.child.isalive():
420 if self.test_timeout and time.time() > test_end:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000421 self.logger.warning(
422 "%s test timed out, killing test process..."
423 % self.test["test_uuid"]
424 )
Chase Qi09edc7f2016-08-18 13:18:50 +0800425 self.child.terminate(force=True)
426 break
427 try:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000428 self.child.expect("\r\n")
Milosz Wasilewskid71f28a2020-06-10 20:05:13 +0100429 print(self.child.before)
Chase Qi09edc7f2016-08-18 13:18:50 +0800430 except pexpect.TIMEOUT:
431 continue
432 except pexpect.EOF:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000433 self.logger.info("%s test finished.\n" % self.test["test_uuid"])
Chase Qi09edc7f2016-08-18 13:18:50 +0800434 break
435
436
Milosz Wasilewski682120e2017-03-13 13:37:18 +0000437class RemoteTestRun(AutomatedTestRun):
438 def copy_to_target(self):
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000439 os.chdir(self.test["test_path"])
Milosz Wasilewski682120e2017-03-13 13:37:18 +0000440 tarball_name = "target-test-files.tar"
Dan Ruea9eb01c2017-06-07 16:29:09 -0500441
442 self.logger.info("Archiving test files")
443 run_command(
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000444 "tar -caf %s run.sh uuid automated/lib automated/bin automated/utils %s"
445 % (tarball_name, self.test["tc_relative_dir"])
446 )
Dan Ruea9eb01c2017-06-07 16:29:09 -0500447
448 self.logger.info("Creating test path")
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000449 run_command("mkdir -p %s" % (self.test["target_test_path"]), self.args.target)
Dan Ruea9eb01c2017-06-07 16:29:09 -0500450
451 self.logger.info("Copying test archive to target host")
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000452 run_command(
453 "scp %s ./%s %s:%s"
454 % (
455 SSH_PARAMS,
456 tarball_name,
457 self.args.target,
458 self.test["target_test_path"],
459 )
460 )
Dan Ruea9eb01c2017-06-07 16:29:09 -0500461
462 self.logger.info("Unarchiving test files on target")
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000463 run_command(
464 "cd %s && tar -xf %s" % (self.test["target_test_path"], tarball_name),
465 self.args.target,
466 )
Dan Ruea9eb01c2017-06-07 16:29:09 -0500467
468 self.logger.info("Removing test file archive from target")
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000469 run_command(
470 "rm %s/%s" % (self.test["target_test_path"], tarball_name), self.args.target
471 )
Milosz Wasilewski682120e2017-03-13 13:37:18 +0000472
473 def run(self):
474 self.copy_to_target()
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000475 self.logger.info(
476 "Executing %s/run.sh remotely on %s"
477 % (self.test["target_test_path"], self.args.target)
478 )
479 shell_cmd = 'ssh %s %s "%s/run.sh 2>&1"' % (
480 SSH_PARAMS,
481 self.args.target,
482 self.test["target_test_path"],
483 )
484 self.logger.debug("shell_cmd: %s" % shell_cmd)
485 output = open("%s/stdout.log" % self.test["test_path"], "w")
Milosz Wasilewskid71f28a2020-06-10 20:05:13 +0100486 self.child = pexpect.spawnu(shell_cmd)
Milosz Wasilewski682120e2017-03-13 13:37:18 +0000487 self.child.logfile = output
488 self.check_result()
489
490
Milosz Wasilewski2fea70e2016-11-11 12:16:09 +0000491class ManualTestShell(cmd.Cmd):
Nicolas Dechesne1945d3f2020-10-07 23:36:34 +0200492 def __init__(self, test_dict, result_path, test_case_id):
Milosz Wasilewski2fea70e2016-11-11 12:16:09 +0000493 cmd.Cmd.__init__(self)
494 self.test_dict = test_dict
Nicolas Dechesne1945d3f2020-10-07 23:36:34 +0200495 self.test_case_id = test_case_id
Milosz Wasilewski2fea70e2016-11-11 12:16:09 +0000496 self.result_path = result_path
497 self.current_step_index = 0
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000498 self.steps = self.test_dict["run"]["steps"]
499 self.expected = self.test_dict["run"]["expected"]
500 self.prompt = "%s[%s] > " % (
501 self.test_dict["metadata"]["name"],
502 self.test_case_id,
503 )
Milosz Wasilewski2fea70e2016-11-11 12:16:09 +0000504 self.result = None
505 self.intro = """
506 Welcome to manual test executor. Type 'help' for available commands.
507 This shell is meant to be executed on your computer, not on the system
508 under test. Please execute the steps from the test case, compare to
509 expected result and record the test result as 'pass' or 'fail'. If there
510 is an issue that prevents from executing the step, please record the result
511 as 'skip'.
512 """
513
514 def do_quit(self, line):
515 """
516 Exit test execution
517 """
518 if self.result is not None:
519 return True
520 if line.find("-f") >= 0:
521 self._record_result("skip")
522 return True
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000523 print(
524 "Test result not recorded. Use -f to force. Forced quit records result as 'skip'"
525 )
Milosz Wasilewski2fea70e2016-11-11 12:16:09 +0000526
527 do_EOF = do_quit
528
529 def do_description(self, line):
530 """
531 Prints current test overall description
532 """
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000533 print(self.test_dict["metadata"]["description"])
Milosz Wasilewski2fea70e2016-11-11 12:16:09 +0000534
535 def do_steps(self, line):
536 """
537 Prints all steps of the current test case
538 """
539 for index, step in enumerate(self.steps):
Chase Qic69235d2017-05-23 14:56:47 +0800540 print("%s. %s" % (index, step))
Milosz Wasilewski2fea70e2016-11-11 12:16:09 +0000541
542 def do_expected(self, line):
543 """
544 Prints all expected results of the current test case
545 """
546 for index, expected in enumerate(self.expected):
Chase Qic69235d2017-05-23 14:56:47 +0800547 print("%s. %s" % (index, expected))
Milosz Wasilewski2fea70e2016-11-11 12:16:09 +0000548
549 def do_current(self, line):
550 """
551 Prints current test step
552 """
553 self._print_step()
554
555 do_start = do_current
556
557 def do_next(self, line):
558 """
559 Prints next test step
560 """
561 if len(self.steps) > self.current_step_index + 1:
562 self.current_step_index += 1
563 self._print_step()
564
565 def _print_step(self):
Chase Qic69235d2017-05-23 14:56:47 +0800566 print("%s. %s" % (self.current_step_index, self.steps[self.current_step_index]))
Milosz Wasilewski2fea70e2016-11-11 12:16:09 +0000567
568 def _record_result(self, result):
Chase Qic69235d2017-05-23 14:56:47 +0800569 print("Recording %s in %s/stdout.log" % (result, self.result_path))
Milosz Wasilewski2fea70e2016-11-11 12:16:09 +0000570 with open("%s/stdout.log" % self.result_path, "a") as f:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000571 f.write(
572 "<LAVA_SIGNAL_TESTCASE TEST_CASE_ID=%s RESULT=%s>"
573 % (self.test_case_id, result)
574 )
Milosz Wasilewski2fea70e2016-11-11 12:16:09 +0000575
576 def do_pass(self, line):
577 """
578 Records PASS as test result
579 """
580 self.result = "pass"
581 self._record_result(self.result)
582 return True
583
584 def do_fail(self, line):
585 """
586 Records FAIL as test result
587 """
588 self.result = "fail"
589 self._record_result(self.result)
590 return True
591
592 def do_skip(self, line):
593 """
594 Records SKIP as test result
595 """
596 self.result = "skip"
597 self._record_result(self.result)
598 return True
599
600
601class ManualTestRun(TestRun, cmd.Cmd):
602 def run(self):
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000603 print(self.test["test_name"])
604 with open("%s/testdef.yaml" % self.test["test_path"], "r") as f:
Milosz Wasilewski2fea70e2016-11-11 12:16:09 +0000605 self.testdef = yaml.safe_load(f)
606
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000607 if "name" in self.test:
608 test_case_id = self.test["name"]
Nicolas Dechesne1945d3f2020-10-07 23:36:34 +0200609 else:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000610 test_case_id = self.testdef["metadata"]["name"]
Nicolas Dechesne1945d3f2020-10-07 23:36:34 +0200611
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000612 ManualTestShell(self.testdef, self.test["test_path"], test_case_id).cmdloop()
Milosz Wasilewski2fea70e2016-11-11 12:16:09 +0000613
614 def check_result(self):
615 pass
616
617
Dan Ruea9eb01c2017-06-07 16:29:09 -0500618def get_packages(linux_distribution, target=None):
Benjamin Copelande7debbe2021-02-22 09:31:14 +0000619 """Return a list of installed packages with versions
Dan Ruea9eb01c2017-06-07 16:29:09 -0500620
Benjamin Copelande7debbe2021-02-22 09:31:14 +0000621 linux_distribution is a string that may be 'debian',
622 'ubuntu', 'centos', or 'fedora'.
Dan Ruea9eb01c2017-06-07 16:29:09 -0500623
Benjamin Copelande7debbe2021-02-22 09:31:14 +0000624 For example (ubuntu):
625 'packages': ['acl-2.2.52-2',
626 'adduser-3.113+nmu3',
627 ...
628 'zlib1g:amd64-1:1.2.8.dfsg-2+b1',
629 'zlib1g-dev:amd64-1:1.2.8.dfsg-2+b1']
Dan Ruea9eb01c2017-06-07 16:29:09 -0500630
Benjamin Copelande7debbe2021-02-22 09:31:14 +0000631 (centos):
632 "packages": ["acl-2.2.51-12.el7",
633 "apr-1.4.8-3.el7",
634 ...
635 "zlib-1.2.7-17.el7",
636 "zlib-devel-1.2.7-17.el7"
637 ]
Dan Ruea9eb01c2017-06-07 16:29:09 -0500638 """
639
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000640 logger = logging.getLogger("RUNNER.get_packages")
Dan Ruea9eb01c2017-06-07 16:29:09 -0500641 packages = []
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000642 if linux_distribution in ["debian", "ubuntu"]:
Dan Ruea9eb01c2017-06-07 16:29:09 -0500643 # Debian (apt) based system
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000644 packages = run_command(
645 "dpkg-query -W -f '${package}-${version}\n'", target
646 ).splitlines()
Dan Ruea9eb01c2017-06-07 16:29:09 -0500647
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000648 elif linux_distribution in ["centos", "fedora"]:
Dan Ruea9eb01c2017-06-07 16:29:09 -0500649 # RedHat (rpm) based system
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000650 packages = run_command(
651 "rpm -qa --qf '%{NAME}-%{VERSION}-%{RELEASE}\n'", target
652 ).splitlines()
Dan Ruea9eb01c2017-06-07 16:29:09 -0500653 else:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000654 logger.warning(
655 "Unknown linux distribution '{}'; package list not populated.".format(
656 linux_distribution
657 )
658 )
Dan Ruea9eb01c2017-06-07 16:29:09 -0500659
660 packages.sort()
661 return packages
662
663
664def get_environment(target=None, skip_collection=False):
Benjamin Copelande7debbe2021-02-22 09:31:14 +0000665 """Return a dictionary with environmental information
Dan Ruea9eb01c2017-06-07 16:29:09 -0500666
Benjamin Copelande7debbe2021-02-22 09:31:14 +0000667 target: optional ssh host string to gather environment remotely.
668 skip_collection: Skip data collection and return an empty dictionary.
Dan Ruea9eb01c2017-06-07 16:29:09 -0500669
Benjamin Copelande7debbe2021-02-22 09:31:14 +0000670 For example (on a HiSilicon D03):
671 {
672 "bios_version": "Hisilicon D03 UEFI 16.12 Release",
673 "board_name": "D03",
674 "board_vendor": "Huawei",
675 "kernel": "4.9.0-20.gitedc2a1c.linaro.aarch64",
676 "linux_distribution": "centos",
677 "packages": [
678 "GeoIP-1.5.0-11.el7",
679 "NetworkManager-1.4.0-20.el7_3",
680 ...
681 "yum-plugin-fastestmirror-1.1.31-40.el7",
682 "zlib-1.2.7-17.el7"
683 ],
684 "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"
685 }
Dan Ruea9eb01c2017-06-07 16:29:09 -0500686 """
687
688 environment = {}
689 if skip_collection:
690 return environment
Milosz Wasilewskidf71a762017-07-20 13:26:21 +0100691 try:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000692 environment["linux_distribution"] = (
693 run_command("grep ^ID= /etc/os-release", target)
694 .split("=")[-1]
695 .strip('"')
696 .lower()
697 )
Milosz Wasilewskidf71a762017-07-20 13:26:21 +0100698 except subprocess.CalledProcessError:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000699 environment["linux_distribution"] = ""
Milosz Wasilewskidf71a762017-07-20 13:26:21 +0100700
701 try:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000702 environment["kernel"] = run_command("uname -r", target)
Milosz Wasilewskidf71a762017-07-20 13:26:21 +0100703 except subprocess.CalledProcessError:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000704 environment["kernel"] = ""
Milosz Wasilewskidf71a762017-07-20 13:26:21 +0100705
706 try:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000707 environment["uname"] = run_command("uname -a", target)
Milosz Wasilewskidf71a762017-07-20 13:26:21 +0100708 except subprocess.CalledProcessError:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000709 environment["uname"] = ""
Dan Ruea9eb01c2017-06-07 16:29:09 -0500710
711 try:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000712 environment["bios_version"] = run_command(
713 "cat /sys/devices/virtual/dmi/id/bios_version", target
714 )
Dan Ruea9eb01c2017-06-07 16:29:09 -0500715 except subprocess.CalledProcessError:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000716 environment["bios_version"] = ""
Dan Ruea9eb01c2017-06-07 16:29:09 -0500717
718 try:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000719 environment["board_vendor"] = run_command(
720 "cat /sys/devices/virtual/dmi/id/board_vendor", target
721 )
Dan Ruea9eb01c2017-06-07 16:29:09 -0500722 except subprocess.CalledProcessError:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000723 environment["board_vendor"] = ""
Dan Ruea9eb01c2017-06-07 16:29:09 -0500724
725 try:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000726 environment["board_name"] = run_command(
727 "cat /sys/devices/virtual/dmi/id/board_name", target
728 )
Dan Ruea9eb01c2017-06-07 16:29:09 -0500729 except subprocess.CalledProcessError:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000730 environment["board_name"] = ""
Dan Ruea9eb01c2017-06-07 16:29:09 -0500731
Milosz Wasilewskidf71a762017-07-20 13:26:21 +0100732 try:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000733 environment["packages"] = get_packages(
734 environment["linux_distribution"], target
735 )
Milosz Wasilewskidf71a762017-07-20 13:26:21 +0100736 except subprocess.CalledProcessError:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000737 environment["packages"] = []
Dan Ruea9eb01c2017-06-07 16:29:09 -0500738 return environment
739
740
Chase Qi09edc7f2016-08-18 13:18:50 +0800741class ResultParser(object):
742 def __init__(self, test, args):
Milosz Wasilewski682120e2017-03-13 13:37:18 +0000743 self.test = test
744 self.args = args
Chase Qi09edc7f2016-08-18 13:18:50 +0800745 self.metrics = []
746 self.results = {}
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000747 self.results["test"] = test["test_name"]
748 self.results["id"] = test["test_uuid"]
749 self.results["test_plan"] = args.test_plan
750 self.results["environment"] = get_environment(
751 target=self.args.target, skip_collection=self.args.skip_environment
752 )
753 self.logger = logging.getLogger("RUNNER.ResultParser")
754 self.results["params"] = {}
Chase Qie94ba522017-05-26 12:05:18 +0800755 self.pattern = None
756 self.fixup = None
Vishal Bhoje94da4a2020-05-15 12:22:40 +0530757 self.qa_reports_server = args.qa_reports_server
758 if args.qa_reports_token is not None:
759 self.qa_reports_token = args.qa_reports_token
760 else:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000761 self.qa_reports_token = os.environ.get(
762 "QA_REPORTS_TOKEN", get_token_from_netrc(self.qa_reports_server)
763 )
Vishal Bhoje94da4a2020-05-15 12:22:40 +0530764 self.qa_reports_project = args.qa_reports_project
765 self.qa_reports_group = args.qa_reports_group
766 self.qa_reports_env = args.qa_reports_env
767 self.qa_reports_build_version = args.qa_reports_build_version
Milosz Wasilewskib4b40de2020-06-11 12:54:18 +0100768 self.qa_reports_disable_metadata = args.qa_reports_disable_metadata
Milosz Wasilewski37848d32020-06-11 14:33:43 +0100769 self.qa_reports_metadata = args.qa_reports_metadata
Milosz Wasilewskiabe2dcc2020-06-12 10:54:46 +0100770 self.qa_reports_metadata_file = args.qa_reports_metadata_file
Vishal Bhoje94da4a2020-05-15 12:22:40 +0530771
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000772 with open(os.path.join(self.test["test_path"], "testdef.yaml"), "r") as f:
Milosz Wasilewskia76e8dd2016-11-25 14:13:25 +0000773 self.testdef = yaml.safe_load(f)
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000774 self.results["name"] = ""
775 if (
776 "metadata" in self.testdef.keys()
777 and "name" in self.testdef["metadata"].keys()
778 ):
779 self.results["name"] = self.testdef["metadata"]["name"]
780 if "params" in self.testdef.keys():
781 self.results["params"] = self.testdef["params"]
Nicolas Dechesnefaa343d2017-10-23 00:33:10 +0200782 if self.args.test_def_params:
783 for param_name, param_value in self.args.test_def_params.items():
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000784 self.results["params"][param_name] = param_value
785 if (
786 "parse" in self.testdef.keys()
787 and "pattern" in self.testdef["parse"].keys()
788 ):
789 self.pattern = self.testdef["parse"]["pattern"]
Chase Qie94ba522017-05-26 12:05:18 +0800790 self.logger.info("Enabling log parse pattern: %s" % self.pattern)
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000791 if "fixupdict" in self.testdef["parse"].keys():
792 self.fixup = self.testdef["parse"]["fixupdict"]
793 self.logger.info(
794 "Enabling log parse pattern fixup: %s" % self.fixup
795 )
796 if "parameters" in test.keys():
797 self.results["params"].update(test["parameters"])
798 if "params" in test.keys():
799 self.results["params"].update(test["params"])
800 if "version" in test.keys():
801 self.results["version"] = test["version"]
Milosz Wasilewski970431b2016-11-25 14:10:08 +0000802 else:
803 path = os.getcwd()
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000804 os.chdir(self.test["test_path"])
Chase Qi3efa7692017-06-26 15:54:05 +0800805 if sys.version_info[0] < 3:
806 test_version = subprocess.check_output("git rev-parse HEAD", shell=True)
807 else:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000808 test_version = subprocess.check_output(
809 "git rev-parse HEAD", shell=True
810 ).decode("utf-8")
811 self.results["version"] = test_version.rstrip()
Milosz Wasilewski970431b2016-11-25 14:10:08 +0000812 os.chdir(path)
Chase Qiea543352017-09-21 16:44:30 +0800813 self.lava_run = args.lava_run
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000814 if self.lava_run and not find_executable("lava-test-case"):
815 self.logger.info(
816 "lava-test-case not found, '-l' or '--lava_run' option ignored'"
817 )
Chase Qiea543352017-09-21 16:44:30 +0800818 self.lava_run = False
Chase Qi09edc7f2016-08-18 13:18:50 +0800819
820 def run(self):
821 self.parse_stdout()
Chase Qie94ba522017-05-26 12:05:18 +0800822 if self.pattern:
823 self.parse_pattern()
824 # If 'metrics' is empty, add 'no-result-found fail'.
825 if not self.metrics:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000826 self.metrics = [
827 {
828 "test_case_id": "no-result-found",
829 "result": "fail",
830 "measurement": "",
831 "units": "",
832 }
833 ]
834 self.results["metrics"] = self.metrics
Chase Qi09edc7f2016-08-18 13:18:50 +0800835 self.dict_to_json()
836 self.dict_to_csv()
Vishal Bhoje94da4a2020-05-15 12:22:40 +0530837 self.send_to_qa_reports()
Milosz Wasilewski31ac9852021-11-18 11:21:28 +0000838 self.send_to_fiotest()
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000839 self.logger.info("Result files saved to: %s" % self.test["test_path"])
840 print("--- Printing result.csv ---")
841 with open("%s/result.csv" % self.test["test_path"]) as f:
Chase Qi09edc7f2016-08-18 13:18:50 +0800842 print(f.read())
843
844 def parse_stdout(self):
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000845 with open("%s/stdout.log" % self.test["test_path"], "r") as f:
Milosz Wasilewski5a4dd442016-12-07 15:01:57 +0000846 test_case_re = re.compile("TEST_CASE_ID=(.*)")
847 result_re = re.compile("RESULT=(.*)")
848 measurement_re = re.compile("MEASUREMENT=(.*)")
849 units_re = re.compile("UNITS=(.*)")
Chase Qi09edc7f2016-08-18 13:18:50 +0800850 for line in f:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000851 if re.match(r"\<(|LAVA_SIGNAL_TESTCASE )TEST_CASE_ID=.*", line):
852 line = line.strip("\n").strip("\r").strip("<>").split(" ")
853 data = {
854 "test_case_id": "",
855 "result": "",
856 "measurement": "",
857 "units": "",
858 }
Chase Qi09edc7f2016-08-18 13:18:50 +0800859
860 for string in line:
Milosz Wasilewskiff695622016-12-05 16:00:06 +0000861 test_case_match = test_case_re.match(string)
862 result_match = result_re.match(string)
863 measurement_match = measurement_re.match(string)
864 units_match = units_re.match(string)
865 if test_case_match:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000866 data["test_case_id"] = test_case_match.group(1)
Milosz Wasilewskiff695622016-12-05 16:00:06 +0000867 if result_match:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000868 data["result"] = result_match.group(1)
Milosz Wasilewskiff695622016-12-05 16:00:06 +0000869 if measurement_match:
Nicolas Dechesne508a2272020-10-03 11:10:37 +0200870 try:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000871 data["measurement"] = float(measurement_match.group(1))
Nicolas Dechesne508a2272020-10-03 11:10:37 +0200872 except ValueError as e:
873 pass
Milosz Wasilewskiff695622016-12-05 16:00:06 +0000874 if units_match:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000875 data["units"] = units_match.group(1)
Chase Qi09edc7f2016-08-18 13:18:50 +0800876
877 self.metrics.append(data.copy())
878
Chase Qiea543352017-09-21 16:44:30 +0800879 if self.lava_run:
880 self.send_to_lava(data)
881
Chase Qie94ba522017-05-26 12:05:18 +0800882 def parse_pattern(self):
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000883 with open("%s/stdout.log" % self.test["test_path"], "r") as f:
884 rex_pattern = re.compile(r"%s" % self.pattern)
Chase Qie94ba522017-05-26 12:05:18 +0800885 for line in f:
886 data = {}
Aníbal Limónc36cb792017-11-29 11:54:30 -0600887 m = rex_pattern.search(line)
Chase Qie94ba522017-05-26 12:05:18 +0800888 if m:
889 data = m.groupdict()
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000890 for x in ["measurement", "units"]:
Chase Qie94ba522017-05-26 12:05:18 +0800891 if x not in data:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000892 data[x] = ""
893 if self.fixup and data["result"] in self.fixup:
894 data["result"] = self.fixup[data["result"]]
Chase Qi1f2a9a02017-03-09 15:45:04 +0100895
Chase Qie94ba522017-05-26 12:05:18 +0800896 self.metrics.append(data.copy())
Chase Qi09edc7f2016-08-18 13:18:50 +0800897
Chase Qiea543352017-09-21 16:44:30 +0800898 if self.lava_run:
899 self.send_to_lava(data)
900
901 def send_to_lava(self, data):
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000902 cmd = "lava-test-case {} --result {}".format(
903 data["test_case_id"], data["result"]
904 )
905 if data["measurement"]:
906 cmd = "{} --measurement {} --units {}".format(
907 cmd, data["measurement"], data["units"]
908 )
909 self.logger.debug("lava-run: cmd: {}".format(cmd))
Chase Qiea543352017-09-21 16:44:30 +0800910 subprocess.call(shlex.split(cmd))
911
Milosz Wasilewski31ac9852021-11-18 11:21:28 +0000912 def send_to_fiotest(self):
913 """
914 This method saves results as filesystem tree. This is required by
915 fiotest: https://github.com/foundriesio/fiotest/
916 """
917 # check if TEST_DIR variable is set
918 test_path = os.environ.get("TEST_DIR")
919 if not test_path:
Milosz Wasilewskid92aff12021-11-18 11:21:28 +0000920 self.logger.debug("TEST_DIR is not set")
921 self.logger.debug("NOT reporting result to fiotest")
Milosz Wasilewski31ac9852021-11-18 11:21:28 +0000922 return
923 # create directory with test name
924 try:
925 for metric in self.metrics:
926 local_ts = datetime.now()
927 dir_name = "{}-{}".format(local_ts.timestamp(), metric["test_case_id"])
928 os.makedirs(os.path.join(test_path, dir_name), exist_ok=True)
929 if metric["measurement"] != "":
930 metrics_dir = os.path.join(test_path, dir_name, "metrics")
931 os.makedirs(metrics_dir, exist_ok=True)
932 with open(os.path.join(metrics_dir, "value"), "w") as value_file:
933 value_file.write(metric["measurement"])
934 else:
935 if metric["result"] == "fail":
936 os.makedirs(
937 os.path.join(test_path, dir_name, "failed"), exist_ok=True
938 )
939 if metric["result"] == "skip":
940 os.makedirs(
941 os.path.join(test_path, dir_name, "skipped"), exist_ok=True
942 )
943 except PermissionError:
944 self.logger.error(
945 "Unable to prepare fiotest results due to lack of permissions"
946 )
947
Vishal Bhoje94da4a2020-05-15 12:22:40 +0530948 def send_to_qa_reports(self):
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000949 if None in (
950 self.qa_reports_server,
951 self.qa_reports_token,
952 self.qa_reports_group,
953 self.qa_reports_project,
954 self.qa_reports_build_version,
955 self.qa_reports_env,
956 ):
957 self.logger.warning(
958 "All parameters for qa reports are not set, results will not be pushed to qa reports"
959 )
Vishal Bhoje94da4a2020-05-15 12:22:40 +0530960 return
961
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000962 SquadApi.configure(url=self.qa_reports_server, token=self.qa_reports_token)
Vishal Bhoje94da4a2020-05-15 12:22:40 +0530963 tests = {}
964 metrics = {}
965 for metric in self.metrics:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000966 if metric["measurement"] != "":
967 metrics[
968 "{}/{}".format(self.test["test_name"], metric["test_case_id"])
969 ] = metric["measurement"]
Vishal Bhoje94da4a2020-05-15 12:22:40 +0530970 else:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000971 tests[
972 "{}/{}".format(self.test["test_name"], metric["test_case_id"])
973 ] = metric["result"]
Vishal Bhoje94da4a2020-05-15 12:22:40 +0530974
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000975 with open("{}/stdout.log".format(self.test["test_path"]), "r") as logfile:
Vishal Bhoje94da4a2020-05-15 12:22:40 +0530976 log = logfile.read()
977
Milosz Wasilewskiabe2dcc2020-06-12 10:54:46 +0100978 metadata = {}
Milosz Wasilewskib00ceff2020-06-15 13:48:01 +0100979 if not self.qa_reports_disable_metadata:
980 if self.qa_reports_metadata:
981 metadata.update(self.qa_reports_metadata)
982 if self.qa_reports_metadata_file:
983 try:
984 with open(self.qa_reports_metadata_file, "r") as metadata_file:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000985 loaded_metadata = yaml.load(
986 metadata_file, Loader=yaml.SafeLoader
987 )
Milosz Wasilewskib00ceff2020-06-15 13:48:01 +0100988 # check if loaded metadata is key=value and both are strings
989 for key, value in loaded_metadata.items():
990 if type(key) == str and type(value) == str:
991 # only update metadata with simple keys
992 # ignore all other items in the dictionary
993 metadata.update({key: value})
994 else:
995 self.logger.warning("Ignoring key: %s" % key)
996 except FileNotFoundError:
997 self.logger.warning("Metadata file not found")
998 except PermissionError:
Benjamin Copeland15d743e2021-02-22 08:35:10 +0000999 self.logger.warning(
1000 "Insufficient permissions to open metadata file"
1001 )
Milosz Wasilewskif883f102020-06-11 12:46:58 +01001002 if submit_results(
Benjamin Copeland15d743e2021-02-22 08:35:10 +00001003 group_project_slug="{}/{}".format(
1004 self.qa_reports_group, self.qa_reports_project
1005 ),
1006 build_version=self.qa_reports_build_version,
1007 env_slug=self.qa_reports_env,
1008 tests=tests,
1009 metrics=metrics,
1010 log=log,
1011 metadata=metadata,
1012 attachments=None,
1013 ):
Milosz Wasilewskif883f102020-06-11 12:46:58 +01001014 self.logger.info("Results pushed to QA Reports")
1015 else:
1016 self.logger.warning("Results upload to QA Reports failed!")
Vishal Bhoje94da4a2020-05-15 12:22:40 +05301017
Chase Qi09edc7f2016-08-18 13:18:50 +08001018 def dict_to_json(self):
Chase Qi87f4f402016-11-07 15:32:01 +08001019 # Save test results to output/test_id/result.json
Benjamin Copeland15d743e2021-02-22 08:35:10 +00001020 with open("%s/result.json" % self.test["test_path"], "w") as f:
Chase Qi87f4f402016-11-07 15:32:01 +08001021 json.dump([self.results], f, indent=4)
1022
1023 # Collect test results of all tests in output/result.json
1024 feeds = []
Benjamin Copeland15d743e2021-02-22 08:35:10 +00001025 if os.path.isfile("%s/result.json" % self.test["output"]):
1026 with open("%s/result.json" % self.test["output"], "r") as f:
Chase Qi87f4f402016-11-07 15:32:01 +08001027 feeds = json.load(f)
1028
1029 feeds.append(self.results)
Benjamin Copeland15d743e2021-02-22 08:35:10 +00001030 with open("%s/result.json" % self.test["output"], "w") as f:
Chase Qi87f4f402016-11-07 15:32:01 +08001031 json.dump(feeds, f, indent=4)
Chase Qi09edc7f2016-08-18 13:18:50 +08001032
1033 def dict_to_csv(self):
Chase Qica15cf52016-11-10 17:00:22 +08001034 # Convert dict self.results['params'] to a string.
Benjamin Copeland15d743e2021-02-22 08:35:10 +00001035 test_params = ""
1036 if self.results["params"]:
1037 params_dict = self.results["params"]
1038 test_params = ";".join(["%s=%s" % (k, v) for k, v in params_dict.items()])
Chase Qi09edc7f2016-08-18 13:18:50 +08001039
Benjamin Copeland15d743e2021-02-22 08:35:10 +00001040 for metric in self.results["metrics"]:
1041 metric["name"] = self.results["name"]
1042 metric["test_params"] = test_params
Chase Qica15cf52016-11-10 17:00:22 +08001043
1044 # Save test results to output/test_id/result.csv
Benjamin Copeland15d743e2021-02-22 08:35:10 +00001045 fieldnames = [
1046 "name",
1047 "test_case_id",
1048 "result",
1049 "measurement",
1050 "units",
1051 "test_params",
1052 ]
1053 with open("%s/result.csv" % self.test["test_path"], "w") as f:
Chase Qica15cf52016-11-10 17:00:22 +08001054 writer = csv.DictWriter(f, fieldnames=fieldnames)
Chase Qi09edc7f2016-08-18 13:18:50 +08001055 writer.writeheader()
Benjamin Copeland15d743e2021-02-22 08:35:10 +00001056 for metric in self.results["metrics"]:
Chase Qi09edc7f2016-08-18 13:18:50 +08001057 writer.writerow(metric)
1058
Chase Qi87f4f402016-11-07 15:32:01 +08001059 # Collect test results of all tests in output/result.csv
Benjamin Copeland15d743e2021-02-22 08:35:10 +00001060 if not os.path.isfile("%s/result.csv" % self.test["output"]):
1061 with open("%s/result.csv" % self.test["output"], "w") as f:
Chase Qi87f4f402016-11-07 15:32:01 +08001062 writer = csv.DictWriter(f, fieldnames=fieldnames)
1063 writer.writeheader()
1064
Benjamin Copeland15d743e2021-02-22 08:35:10 +00001065 with open("%s/result.csv" % self.test["output"], "a") as f:
Chase Qi09edc7f2016-08-18 13:18:50 +08001066 writer = csv.DictWriter(f, fieldnames=fieldnames)
Benjamin Copeland15d743e2021-02-22 08:35:10 +00001067 for metric in self.results["metrics"]:
Chase Qi09edc7f2016-08-18 13:18:50 +08001068 writer.writerow(metric)
1069
1070
Vishal Bhoje94da4a2020-05-15 12:22:40 +05301071def get_token_from_netrc(qa_reports_server):
1072 if qa_reports_server is None:
1073 return
1074 parse = urlparse(qa_reports_server)
1075 netrc_local = netrc.netrc()
1076 authTokens = netrc_local.authenticators("{}".format(parse.netloc))
1077 if authTokens is not None:
1078 hostname, username, authToken = authTokens
1079 return authToken
1080 # Unable to find Token hence returning None
1081 return
1082
1083
Chase Qi09edc7f2016-08-18 13:18:50 +08001084def get_args():
Milosz Wasilewski259ba192017-07-27 10:59:25 +01001085 parser = argparse.ArgumentParser(formatter_class=argparse.RawTextHelpFormatter)
Benjamin Copeland15d743e2021-02-22 08:35:10 +00001086 parser.add_argument(
1087 "-o",
1088 "--output",
1089 default=os.getenv("HOME", "") + "/output",
1090 dest="output",
1091 help=textwrap.dedent(
1092 """\
Chase Qi09edc7f2016-08-18 13:18:50 +08001093 specify a directory to store test and result files.
Nicolas Dechesnef6c4c212017-01-18 17:30:04 +01001094 Default: $HOME/output
Benjamin Copeland15d743e2021-02-22 08:35:10 +00001095 """
1096 ),
1097 )
1098 parser.add_argument(
1099 "-p",
1100 "--test_plan",
1101 default=None,
1102 dest="test_plan",
1103 help=textwrap.dedent(
1104 """\
Chase Qi09edc7f2016-08-18 13:18:50 +08001105 specify an test plan file which has tests and related
1106 params listed in yaml format.
Benjamin Copeland15d743e2021-02-22 08:35:10 +00001107 """
1108 ),
1109 )
1110 parser.add_argument(
1111 "-d",
1112 "--test_def",
1113 default=None,
1114 dest="test_def",
1115 help=textwrap.dedent(
1116 """\
Chase Qi09edc7f2016-08-18 13:18:50 +08001117 base on test definition repo location, specify relative
1118 path to the test definition to run.
1119 Format example: "ubuntu/smoke-tests-basic.yaml"
Benjamin Copeland15d743e2021-02-22 08:35:10 +00001120 """
1121 ),
1122 )
1123 parser.add_argument(
1124 "-r",
1125 "--test_def_params",
1126 default={},
1127 dest="test_def_params",
1128 action=StoreDictKeyPair,
1129 nargs="+",
1130 metavar="KEY=VALUE",
1131 help=textwrap.dedent(
1132 """\
Milosz Wasilewski259ba192017-07-27 10:59:25 +01001133 Set additional parameters when using test definition without
1134 a test plan. The name values are set similarily to environment
1135 variables:
1136 --test_def_params KEY1=VALUE1 KEY2=VALUE2 ...
Benjamin Copeland15d743e2021-02-22 08:35:10 +00001137 """
1138 ),
1139 )
1140 parser.add_argument(
1141 "-k",
1142 "--kind",
1143 default="automated",
1144 dest="kind",
1145 choices=["automated", "manual"],
1146 help=textwrap.dedent(
1147 """\
Milosz Wasilewski2fea70e2016-11-11 12:16:09 +00001148 Selects type of tests to be executed from the test plan.
1149 Possible options: automated, manual
Benjamin Copeland15d743e2021-02-22 08:35:10 +00001150 """
1151 ),
1152 )
1153 parser.add_argument(
1154 "-t",
1155 "--timeout",
1156 type=int,
1157 default=None,
1158 dest="timeout",
1159 help="Specify test timeout",
1160 )
1161 parser.add_argument(
1162 "-g",
1163 "--target",
1164 default=None,
1165 dest="target",
1166 help=textwrap.dedent(
1167 """\
Milosz Wasilewski682120e2017-03-13 13:37:18 +00001168 Specify SSH target to execute tests.
1169 Format: user@host
1170 Note: ssh authentication must be paswordless
Benjamin Copeland15d743e2021-02-22 08:35:10 +00001171 """
1172 ),
1173 )
1174 parser.add_argument(
1175 "-s",
1176 "--skip_install",
1177 dest="skip_install",
1178 default=False,
1179 action="store_true",
1180 help="skip install section defined in test definition.",
1181 )
1182 parser.add_argument(
1183 "-e",
1184 "--skip_environment",
1185 dest="skip_environment",
1186 default=False,
1187 action="store_true",
1188 help="skip environmental data collection (board name, distro, etc)",
1189 )
1190 parser.add_argument(
1191 "-l",
1192 "--lava_run",
1193 dest="lava_run",
1194 default=False,
1195 action="store_true",
1196 help="send test result to LAVA with lava-test-case.",
1197 )
1198 parser.add_argument(
1199 "-O",
1200 "--overlay",
1201 default=None,
1202 dest="overlay",
1203 help=textwrap.dedent(
1204 """\
Chase Qia158efe2017-11-17 12:35:11 +08001205 Specify test plan ovelay file to:
1206 * skip tests
1207 * amend test parameters
1208 * add new tests
Benjamin Copeland15d743e2021-02-22 08:35:10 +00001209 """
1210 ),
1211 )
1212 parser.add_argument(
1213 "-v",
1214 "--verbose",
1215 action="store_true",
1216 dest="verbose",
1217 default=False,
1218 help="Set log level to DEBUG.",
1219 )
Vishal Bhoje94da4a2020-05-15 12:22:40 +05301220 parser.add_argument(
1221 "--qa-reports-server",
1222 dest="qa_reports_server",
1223 default=None,
1224 help="qa reports server where the results have to be sent",
1225 )
1226 parser.add_argument(
1227 "--qa-reports-token",
1228 dest="qa_reports_token",
1229 default=None,
1230 help="qa reports token to upload the results to qa_reports_server",
1231 )
1232 parser.add_argument(
1233 "--qa-reports-project",
1234 dest="qa_reports_project",
1235 default=None,
1236 help="qa reports projects to which the results have to be uploaded",
1237 )
1238 parser.add_argument(
1239 "--qa-reports-group",
1240 dest="qa_reports_group",
1241 default=None,
1242 help="qa reports group in which the results have to be stored",
1243 )
1244 parser.add_argument(
1245 "--qa-reports-env",
1246 dest="qa_reports_env",
1247 default=None,
1248 help="qa reports environment for the results that have to be stored",
1249 )
1250 parser.add_argument(
1251 "--qa-reports-build-version",
1252 dest="qa_reports_build_version",
1253 default=None,
1254 help="qa reports build id for the result set",
1255 )
Milosz Wasilewskib4b40de2020-06-11 12:54:18 +01001256 parser.add_argument(
1257 "--qa-reports-disable-metadata",
1258 dest="qa_reports_disable_metadata",
1259 default=False,
Benjamin Copeland15d743e2021-02-22 08:35:10 +00001260 action="store_true",
Milosz Wasilewski37848d32020-06-11 14:33:43 +01001261 help="Disable sending metadata to SQUAD. Default: false",
1262 )
1263 parser.add_argument(
1264 "--qa-reports-metadata",
1265 dest="qa_reports_metadata",
1266 default={},
1267 action=StoreDictKeyPair,
1268 nargs="+",
1269 metavar="KEY=VALUE",
1270 help="List of metadata key=value pairs to be sent to SQUAD",
Milosz Wasilewskib4b40de2020-06-11 12:54:18 +01001271 )
Milosz Wasilewskiabe2dcc2020-06-12 10:54:46 +01001272 parser.add_argument(
1273 "--qa-reports-metadata-file",
1274 dest="qa_reports_metadata_file",
1275 default=None,
1276 help="YAML file that defines metadata to be reported to SQUAD",
1277 )
Milosz Wasilewskib4b40de2020-06-11 12:54:18 +01001278
Chase Qi09edc7f2016-08-18 13:18:50 +08001279 args = parser.parse_args()
1280 return args
1281
1282
1283def main():
Chase Qi0e9b36e2017-12-07 16:13:44 +08001284 args = get_args()
1285
Chase Qi09edc7f2016-08-18 13:18:50 +08001286 # Setup logger.
Benjamin Copeland15d743e2021-02-22 08:35:10 +00001287 logger = logging.getLogger("RUNNER")
Chase Qi0e9b36e2017-12-07 16:13:44 +08001288 logger.setLevel(logging.INFO)
1289 if args.verbose:
1290 logger.setLevel(logging.DEBUG)
Chase Qi09edc7f2016-08-18 13:18:50 +08001291 ch = logging.StreamHandler()
1292 ch.setLevel(logging.DEBUG)
Benjamin Copeland15d743e2021-02-22 08:35:10 +00001293 formatter = logging.Formatter("%(asctime)s - %(name)s: %(levelname)s: %(message)s")
Chase Qi09edc7f2016-08-18 13:18:50 +08001294 ch.setFormatter(formatter)
1295 logger.addHandler(ch)
1296
Benjamin Copeland15d743e2021-02-22 08:35:10 +00001297 logger.debug("Test job arguments: %s" % args)
Milosz Wasilewski682120e2017-03-13 13:37:18 +00001298 if args.kind != "manual" and args.target is None:
Milosz Wasilewski2fea70e2016-11-11 12:16:09 +00001299 if os.geteuid() != 0:
1300 logger.error("Sorry, you need to run this as root")
1301 sys.exit(1)
Chase Qi09edc7f2016-08-18 13:18:50 +08001302
Milosz Wasilewski682120e2017-03-13 13:37:18 +00001303 # Validate target argument format and connectivity.
1304 if args.target:
Benjamin Copeland15d743e2021-02-22 08:35:10 +00001305 rex = re.compile(".+@.+")
Milosz Wasilewski682120e2017-03-13 13:37:18 +00001306 if not rex.match(args.target):
Benjamin Copeland15d743e2021-02-22 08:35:10 +00001307 logger.error("Usage: -g username@host")
Milosz Wasilewski682120e2017-03-13 13:37:18 +00001308 sys.exit(1)
Benjamin Copeland15d743e2021-02-22 08:35:10 +00001309 if pexpect.which("ssh") is None:
1310 logger.error("openssh client must be installed on the host.")
Milosz Wasilewski682120e2017-03-13 13:37:18 +00001311 sys.exit(1)
1312 try:
Dan Ruea9eb01c2017-06-07 16:29:09 -05001313 run_command("exit", args.target)
Milosz Wasilewski682120e2017-03-13 13:37:18 +00001314 except subprocess.CalledProcessError as e:
Benjamin Copeland15d743e2021-02-22 08:35:10 +00001315 logger.error("ssh login failed.")
Milosz Wasilewski682120e2017-03-13 13:37:18 +00001316 print(e)
1317 sys.exit(1)
1318
Chase Qi09edc7f2016-08-18 13:18:50 +08001319 # Generate test plan.
Chase Qi09edc7f2016-08-18 13:18:50 +08001320 test_plan = TestPlan(args)
Milosz Wasilewski2fea70e2016-11-11 12:16:09 +00001321 test_list = test_plan.test_list(args.kind)
Benjamin Copeland15d743e2021-02-22 08:35:10 +00001322 logger.info("Tests to run:")
Chase Qi09edc7f2016-08-18 13:18:50 +08001323 for test in test_list:
1324 print(test)
1325
1326 # Run tests.
1327 for test in test_list:
Milosz Wasilewski682120e2017-03-13 13:37:18 +00001328 # Set and save test params to test dictionary.
Benjamin Copeland15d743e2021-02-22 08:35:10 +00001329 test["test_name"] = os.path.splitext(test["path"].split("/")[-1])[0]
1330 test["test_uuid"] = "%s_%s" % (test["test_name"], test["uuid"])
1331 test["output"] = os.path.realpath(args.output)
1332 if args.target is not None and "-o" not in sys.argv:
1333 test["output"] = os.path.join(test["output"], args.target)
1334 test["test_path"] = os.path.join(test["output"], test["test_uuid"])
Milosz Wasilewski682120e2017-03-13 13:37:18 +00001335 if args.target is not None:
Chase Qi204b5422017-04-06 11:01:58 +08001336 # Get relative directory path of yaml file for partial file copy.
1337 # '-d' takes any relative paths to the yaml file, so get the realpath first.
Benjamin Copeland15d743e2021-02-22 08:35:10 +00001338 tc_realpath = os.path.realpath(test["path"])
Chase Qi204b5422017-04-06 11:01:58 +08001339 tc_dirname = os.path.dirname(tc_realpath)
Benjamin Copeland15d743e2021-02-22 08:35:10 +00001340 test["tc_relative_dir"] = "%s%s" % (
1341 args.kind,
1342 tc_dirname.split(args.kind)[1],
1343 )
Dan Ruea9eb01c2017-06-07 16:29:09 -05001344 target_user_home = run_command("echo $HOME", args.target)
Benjamin Copeland15d743e2021-02-22 08:35:10 +00001345 test["target_test_path"] = "%s/output/%s" % (
1346 target_user_home,
1347 test["test_uuid"],
1348 )
1349 logger.debug("Test parameters: %s" % test)
Milosz Wasilewski682120e2017-03-13 13:37:18 +00001350
Chase Qi09edc7f2016-08-18 13:18:50 +08001351 # Create directories and copy files needed.
1352 setup = TestSetup(test, args)
1353 setup.create_dir()
1354 setup.copy_test_repo()
Milosz Wasilewski970431b2016-11-25 14:10:08 +00001355 setup.checkout_version()
Chase Qi09edc7f2016-08-18 13:18:50 +08001356 setup.create_uuid_file()
1357
1358 # Convert test definition.
1359 test_def = TestDefinition(test, args)
Milosz Wasilewski2fea70e2016-11-11 12:16:09 +00001360 if test_def.exists:
1361 test_def.definition()
1362 test_def.metadata()
Nicolas Dechesne51b85a82017-02-04 00:45:48 +01001363 test_def.mkrun()
Chase Qi09edc7f2016-08-18 13:18:50 +08001364
Milosz Wasilewski2fea70e2016-11-11 12:16:09 +00001365 # Run test.
Nicolas Dechesne51b85a82017-02-04 00:45:48 +01001366 test_def.run()
Chase Qi09edc7f2016-08-18 13:18:50 +08001367
Milosz Wasilewski2fea70e2016-11-11 12:16:09 +00001368 # Parse test output, save results in json and csv format.
1369 result_parser = ResultParser(test, args)
1370 result_parser.run()
1371 else:
Benjamin Copeland15d743e2021-02-22 08:35:10 +00001372 logger.warning("Requested test definition %s doesn't exist" % test["path"])
Chase Qi09edc7f2016-08-18 13:18:50 +08001373
Dan Ruea9eb01c2017-06-07 16:29:09 -05001374
Chase Qi09edc7f2016-08-18 13:18:50 +08001375if __name__ == "__main__":
1376 main()