Vishal Bhoj | dc338f6 | 2020-05-18 15:38:18 +0530 | [diff] [blame] | 1 | #!/usr/bin/env python3 |
Chase Qi | 09edc7f | 2016-08-18 13:18:50 +0800 | [diff] [blame] | 2 | import argparse |
| 3 | import csv |
Milosz Wasilewski | 2fea70e | 2016-11-11 12:16:09 +0000 | [diff] [blame] | 4 | import cmd |
Chase Qi | a158efe | 2017-11-17 12:35:11 +0800 | [diff] [blame] | 5 | import copy |
Chase Qi | 09edc7f | 2016-08-18 13:18:50 +0800 | [diff] [blame] | 6 | import json |
| 7 | import logging |
Vishal Bhoj | e94da4a | 2020-05-15 12:22:40 +0530 | [diff] [blame] | 8 | import netrc |
Chase Qi | 09edc7f | 2016-08-18 13:18:50 +0800 | [diff] [blame] | 9 | import os |
Chase Qi | 09edc7f | 2016-08-18 13:18:50 +0800 | [diff] [blame] | 10 | import re |
Milosz Wasilewski | 682120e | 2017-03-13 13:37:18 +0000 | [diff] [blame] | 11 | import shlex |
Chase Qi | 09edc7f | 2016-08-18 13:18:50 +0800 | [diff] [blame] | 12 | import shutil |
Milosz Wasilewski | 970431b | 2016-11-25 14:10:08 +0000 | [diff] [blame] | 13 | import subprocess |
Chase Qi | 09edc7f | 2016-08-18 13:18:50 +0800 | [diff] [blame] | 14 | import sys |
Milosz Wasilewski | 259ba19 | 2017-07-27 10:59:25 +0100 | [diff] [blame] | 15 | import textwrap |
Chase Qi | 09edc7f | 2016-08-18 13:18:50 +0800 | [diff] [blame] | 16 | import time |
Chase Qi | 09edc7f | 2016-08-18 13:18:50 +0800 | [diff] [blame] | 17 | from uuid import uuid4 |
Chase Qi | ea54335 | 2017-09-21 16:44:30 +0800 | [diff] [blame] | 18 | from distutils.spawn import find_executable |
Chase Qi | 09edc7f | 2016-08-18 13:18:50 +0800 | [diff] [blame] | 19 | |
| 20 | |
Chase Qi | faf7d28 | 2016-08-29 19:34:01 +0800 | [diff] [blame] | 21 | try: |
Vishal Bhoj | e94da4a | 2020-05-15 12:22:40 +0530 | [diff] [blame] | 22 | 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 |
| 26 | except ImportError as e: |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 27 | logger = logging.getLogger("RUNNER") |
| 28 | logger.warning("squad_client is needed if you want to upload to qa-reports") |
Vishal Bhoj | e94da4a | 2020-05-15 12:22:40 +0530 | [diff] [blame] | 29 | |
| 30 | |
| 31 | try: |
Chase Qi | faf7d28 | 2016-08-29 19:34:01 +0800 | [diff] [blame] | 32 | import pexpect |
| 33 | import yaml |
| 34 | except ImportError as e: |
| 35 | print(e) |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 36 | print("Please run the below command to install modules required") |
| 37 | print("pip3 install -r ${REPO_PATH}/automated/utils/requirements.txt") |
Chase Qi | faf7d28 | 2016-08-29 19:34:01 +0800 | [diff] [blame] | 38 | sys.exit(1) |
| 39 | |
| 40 | |
Milosz Wasilewski | 259ba19 | 2017-07-27 10:59:25 +0100 | [diff] [blame] | 41 | class StoreDictKeyPair(argparse.Action): |
| 42 | def __init__(self, option_strings, dest, nargs=None, **kwargs): |
| 43 | self._nargs = nargs |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 44 | super(StoreDictKeyPair, self).__init__( |
| 45 | option_strings, dest, nargs=nargs, **kwargs |
| 46 | ) |
Milosz Wasilewski | 259ba19 | 2017-07-27 10:59:25 +0100 | [diff] [blame] | 47 | |
| 48 | def __call__(self, parser, namespace, values, option_string=None): |
| 49 | my_dict = {} |
| 50 | for kv in values: |
Milosz Wasilewski | f9c8c06 | 2017-08-02 16:10:40 +0100 | [diff] [blame] | 51 | if "=" in kv: |
| 52 | k, v = kv.split("=", 1) |
| 53 | my_dict[k] = v |
| 54 | else: |
| 55 | print("Invalid parameter: %s" % kv) |
Milosz Wasilewski | 259ba19 | 2017-07-27 10:59:25 +0100 | [diff] [blame] | 56 | setattr(namespace, self.dest, my_dict) |
| 57 | |
| 58 | |
Milosz Wasilewski | df71a76 | 2017-07-20 13:26:21 +0100 | [diff] [blame] | 59 | # quit gracefully if the connection is closed by remote host |
| 60 | SSH_PARAMS = "-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ServerAliveInterval=5" |
Milosz Wasilewski | 682120e | 2017-03-13 13:37:18 +0000 | [diff] [blame] | 61 | |
| 62 | |
Dan Rue | a9eb01c | 2017-06-07 16:29:09 -0500 | [diff] [blame] | 63 | def 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 Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 70 | logger = logging.getLogger("RUNNER.run_command") |
Dan Rue | a9eb01c | 2017-06-07 16:29:09 -0500 | [diff] [blame] | 71 | logger.debug(run) |
Chase Qi | 3efa769 | 2017-06-26 15:54:05 +0800 | [diff] [blame] | 72 | if sys.version_info[0] < 3: |
| 73 | return subprocess.check_output(shlex.split(run)).strip() |
| 74 | else: |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 75 | return subprocess.check_output(shlex.split(run)).strip().decode("utf-8") |
Milosz Wasilewski | 682120e | 2017-03-13 13:37:18 +0000 | [diff] [blame] | 76 | |
| 77 | |
Chase Qi | 09edc7f | 2016-08-18 13:18:50 +0800 | [diff] [blame] | 78 | class TestPlan(object): |
| 79 | """ |
| 80 | Analysis args specified, then generate test plan. |
| 81 | """ |
| 82 | |
| 83 | def __init__(self, args): |
Chase Qi | 09edc7f | 2016-08-18 13:18:50 +0800 | [diff] [blame] | 84 | 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 Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 88 | self.logger = logging.getLogger("RUNNER.TestPlan") |
Chase Qi | a158efe | 2017-11-17 12:35:11 +0800 | [diff] [blame] | 89 | self.overlay = args.overlay |
| 90 | |
| 91 | def apply_overlay(self, test_list): |
| 92 | fixed_test_list = copy.deepcopy(test_list) |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 93 | logger = logging.getLogger("RUNNER.TestPlan.Overlay") |
Chase Qi | a158efe | 2017-11-17 12:35:11 +0800 | [diff] [blame] | 94 | with open(self.overlay) as f: |
| 95 | data = yaml.load(f) |
| 96 | |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 97 | if data.get("skip"): |
| 98 | skip_tests = data["skip"] |
Chase Qi | a158efe | 2017-11-17 12:35:11 +0800 | [diff] [blame] | 99 | for test in test_list: |
| 100 | for skip_test in skip_tests: |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 101 | if ( |
| 102 | test["path"] == skip_test["path"] |
| 103 | and test["repository"] == skip_test["repository"] |
| 104 | ): |
Chase Qi | a158efe | 2017-11-17 12:35:11 +0800 | [diff] [blame] | 105 | fixed_test_list.remove(test) |
| 106 | logger.info("Skipped: {}".format(test)) |
| 107 | else: |
| 108 | continue |
| 109 | |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 110 | if data.get("amend"): |
| 111 | amend_tests = data["amend"] |
Chase Qi | a158efe | 2017-11-17 12:35:11 +0800 | [diff] [blame] | 112 | for test in fixed_test_list: |
| 113 | for amend_test in amend_tests: |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 114 | 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 Qi | a158efe | 2017-11-17 12:35:11 +0800 | [diff] [blame] | 121 | else: |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 122 | test["parameters"] = amend_test["parameters"] |
| 123 | logger.info("Updated: {}".format(test)) |
Chase Qi | a158efe | 2017-11-17 12:35:11 +0800 | [diff] [blame] | 124 | else: |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 125 | logger.warning( |
| 126 | "'parameters' not found in {}, nothing to amend.".format( |
| 127 | amend_test |
| 128 | ) |
| 129 | ) |
Chase Qi | a158efe | 2017-11-17 12:35:11 +0800 | [diff] [blame] | 130 | |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 131 | if data.get("add"): |
| 132 | add_tests = data["add"] |
Chase Qi | a158efe | 2017-11-17 12:35:11 +0800 | [diff] [blame] | 133 | 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 Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 141 | del test["uuid"] |
Chase Qi | a158efe | 2017-11-17 12:35:11 +0800 | [diff] [blame] | 142 | |
| 143 | for add_test in unique_add_tests: |
| 144 | if add_test in test_list: |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 145 | logger.warning( |
| 146 | "{} already included in test plan, do nothing.".format(add_test) |
| 147 | ) |
Chase Qi | a158efe | 2017-11-17 12:35:11 +0800 | [diff] [blame] | 148 | else: |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 149 | add_test["uuid"] = str(uuid4()) |
Chase Qi | a158efe | 2017-11-17 12:35:11 +0800 | [diff] [blame] | 150 | fixed_test_list.append(add_test) |
| 151 | logger.info("Added: {}".format(add_test)) |
| 152 | |
| 153 | return fixed_test_list |
Chase Qi | 09edc7f | 2016-08-18 13:18:50 +0800 | [diff] [blame] | 154 | |
Milosz Wasilewski | 2fea70e | 2016-11-11 12:16:09 +0000 | [diff] [blame] | 155 | def test_list(self, kind="automated"): |
Chase Qi | 09edc7f | 2016-08-18 13:18:50 +0800 | [diff] [blame] | 156 | if self.test_def: |
| 157 | if not os.path.exists(self.test_def): |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 158 | self.logger.error(" %s NOT found, exiting..." % self.test_def) |
Chase Qi | 09edc7f | 2016-08-18 13:18:50 +0800 | [diff] [blame] | 159 | sys.exit(1) |
| 160 | |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 161 | 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 Qi | 09edc7f | 2016-08-18 13:18:50 +0800 | [diff] [blame] | 165 | elif self.test_plan: |
| 166 | if not os.path.exists(self.test_plan): |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 167 | self.logger.error(" %s NOT found, exiting..." % self.test_plan) |
Chase Qi | 09edc7f | 2016-08-18 13:18:50 +0800 | [diff] [blame] | 168 | sys.exit(1) |
| 169 | |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 170 | with open(self.test_plan, "r") as f: |
Chase Qi | 09edc7f | 2016-08-18 13:18:50 +0800 | [diff] [blame] | 171 | test_plan = yaml.safe_load(f) |
| 172 | try: |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 173 | plan_version = test_plan["metadata"].get("format") |
| 174 | self.logger.info("Test plan version: {}".format(plan_version)) |
Milosz Wasilewski | 8d64bb2 | 2019-06-18 12:32:08 +0100 | [diff] [blame] | 175 | tests = [] |
Chase Qi | dca4fb6 | 2017-11-22 12:09:42 +0800 | [diff] [blame] | 176 | if plan_version == "Linaro Test Plan v2": |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 177 | tests = test_plan["tests"][kind] |
Chase Qi | dca4fb6 | 2017-11-22 12:09:42 +0800 | [diff] [blame] | 178 | elif plan_version == "Linaro Test Plan v1" or plan_version is None: |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 179 | 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 Qi | dca4fb6 | 2017-11-22 12:09:42 +0800 | [diff] [blame] | 187 | tests.append(test) |
| 188 | |
Milosz Wasilewski | 2fea70e | 2016-11-11 12:16:09 +0000 | [diff] [blame] | 189 | test_list = [] |
Dan Rue | d9d7b65 | 2017-05-26 14:00:10 -0500 | [diff] [blame] | 190 | unique_tests = [] # List of test hashes |
Chase Qi | dca4fb6 | 2017-11-22 12:09:42 +0800 | [diff] [blame] | 191 | 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 Qi | 09edc7f | 2016-08-18 13:18:50 +0800 | [diff] [blame] | 199 | for test in test_list: |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 200 | test["uuid"] = str(uuid4()) |
Chase Qi | 09edc7f | 2016-08-18 13:18:50 +0800 | [diff] [blame] | 201 | except KeyError as e: |
| 202 | self.logger.error("%s is missing from test plan" % str(e)) |
| 203 | sys.exit(1) |
| 204 | else: |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 205 | self.logger.error("Plese specify a test or test plan.") |
Chase Qi | 09edc7f | 2016-08-18 13:18:50 +0800 | [diff] [blame] | 206 | sys.exit(1) |
| 207 | |
Chase Qi | a158efe | 2017-11-17 12:35:11 +0800 | [diff] [blame] | 208 | if self.overlay is None: |
| 209 | return test_list |
| 210 | else: |
| 211 | return self.apply_overlay(test_list) |
Chase Qi | 09edc7f | 2016-08-18 13:18:50 +0800 | [diff] [blame] | 212 | |
| 213 | |
| 214 | class TestSetup(object): |
| 215 | """ |
| 216 | Create directories required, then copy files needed to these directories. |
| 217 | """ |
| 218 | |
| 219 | def __init__(self, test, args): |
Milosz Wasilewski | 682120e | 2017-03-13 13:37:18 +0000 | [diff] [blame] | 220 | self.test = test |
| 221 | self.args = args |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 222 | self.logger = logging.getLogger("RUNNER.TestSetup") |
Milosz Wasilewski | 2fea70e | 2016-11-11 12:16:09 +0000 | [diff] [blame] | 223 | self.test_kind = args.kind |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 224 | self.test_version = test.get("version", None) |
Chase Qi | 09edc7f | 2016-08-18 13:18:50 +0800 | [diff] [blame] | 225 | |
| 226 | def validate_env(self): |
| 227 | # Inspect if environment set properly. |
| 228 | try: |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 229 | self.repo_path = os.environ["REPO_PATH"] |
Chase Qi | 09edc7f | 2016-08-18 13:18:50 +0800 | [diff] [blame] | 230 | except KeyError: |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 231 | self.logger.error("KeyError: REPO_PATH") |
| 232 | self.logger.error( |
| 233 | "Please run '. ./bin/setenv.sh' to setup test environment" |
| 234 | ) |
Chase Qi | 09edc7f | 2016-08-18 13:18:50 +0800 | [diff] [blame] | 235 | sys.exit(1) |
| 236 | |
| 237 | def create_dir(self): |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 238 | 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 Qi | 09edc7f | 2016-08-18 13:18:50 +0800 | [diff] [blame] | 241 | |
| 242 | def copy_test_repo(self): |
| 243 | self.validate_env() |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 244 | 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 Qi | 33eb765 | 2016-12-02 10:43:46 +0800 | [diff] [blame] | 249 | sys.exit(1) |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 250 | 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 Qi | 09edc7f | 2016-08-18 13:18:50 +0800 | [diff] [blame] | 252 | |
Milosz Wasilewski | 970431b | 2016-11-25 14:10:08 +0000 | [diff] [blame] | 253 | def checkout_version(self): |
| 254 | if self.test_version: |
| 255 | path = os.getcwd() |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 256 | os.chdir(self.test["test_path"]) |
Milosz Wasilewski | 970431b | 2016-11-25 14:10:08 +0000 | [diff] [blame] | 257 | subprocess.call("git checkout %s" % self.test_version, shell=True) |
| 258 | os.chdir(path) |
| 259 | |
Chase Qi | 09edc7f | 2016-08-18 13:18:50 +0800 | [diff] [blame] | 260 | def create_uuid_file(self): |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 261 | with open("%s/uuid" % self.test["test_path"], "w") as f: |
| 262 | f.write(self.test["uuid"]) |
Chase Qi | 09edc7f | 2016-08-18 13:18:50 +0800 | [diff] [blame] | 263 | |
| 264 | |
| 265 | class TestDefinition(object): |
| 266 | """ |
| 267 | Convert test definition to testdef.yaml, testdef_metadata and run.sh. |
| 268 | """ |
| 269 | |
| 270 | def __init__(self, test, args): |
Milosz Wasilewski | 2fea70e | 2016-11-11 12:16:09 +0000 | [diff] [blame] | 271 | self.test = test |
| 272 | self.args = args |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 273 | self.logger = logging.getLogger("RUNNER.TestDef") |
Chase Qi | 09edc7f | 2016-08-18 13:18:50 +0800 | [diff] [blame] | 274 | self.skip_install = args.skip_install |
Milosz Wasilewski | 2fea70e | 2016-11-11 12:16:09 +0000 | [diff] [blame] | 275 | self.is_manual = False |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 276 | if "skip_install" in test: |
| 277 | self.skip_install = test["skip_install"] |
Chase Qi | 09edc7f | 2016-08-18 13:18:50 +0800 | [diff] [blame] | 278 | self.custom_params = None |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 279 | if "parameters" in test: |
| 280 | self.custom_params = test["parameters"] |
| 281 | if "params" in test: |
| 282 | self.custom_params = test["params"] |
Milosz Wasilewski | 2fea70e | 2016-11-11 12:16:09 +0000 | [diff] [blame] | 283 | self.exists = False |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 284 | if os.path.isfile(self.test["path"]): |
Milosz Wasilewski | 2fea70e | 2016-11-11 12:16:09 +0000 | [diff] [blame] | 285 | self.exists = True |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 286 | with open(self.test["path"], "r") as f: |
Milosz Wasilewski | 2fea70e | 2016-11-11 12:16:09 +0000 | [diff] [blame] | 287 | self.testdef = yaml.safe_load(f) |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 288 | if self.testdef["metadata"]["format"].startswith( |
| 289 | "Manual Test Definition" |
| 290 | ): |
Milosz Wasilewski | 2fea70e | 2016-11-11 12:16:09 +0000 | [diff] [blame] | 291 | self.is_manual = True |
Nicolas Dechesne | 51b85a8 | 2017-02-04 00:45:48 +0100 | [diff] [blame] | 292 | if self.is_manual: |
| 293 | self.runner = ManualTestRun(test, args) |
Chase Qi | 43bb912 | 2017-05-23 14:37:48 +0800 | [diff] [blame] | 294 | elif self.args.target is not None: |
Nicolas Dechesne | 51b85a8 | 2017-02-04 00:45:48 +0100 | [diff] [blame] | 295 | self.runner = RemoteTestRun(test, args) |
Chase Qi | 43bb912 | 2017-05-23 14:37:48 +0800 | [diff] [blame] | 296 | else: |
| 297 | self.runner = AutomatedTestRun(test, args) |
Chase Qi | 09edc7f | 2016-08-18 13:18:50 +0800 | [diff] [blame] | 298 | |
| 299 | def definition(self): |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 300 | 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 Qi | 09edc7f | 2016-08-18 13:18:50 +0800 | [diff] [blame] | 302 | |
| 303 | def metadata(self): |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 304 | 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 Qi | 09edc7f | 2016-08-18 13:18:50 +0800 | [diff] [blame] | 310 | |
Nicolas Dechesne | 51b85a8 | 2017-02-04 00:45:48 +0100 | [diff] [blame] | 311 | def mkrun(self): |
Milosz Wasilewski | 2fea70e | 2016-11-11 12:16:09 +0000 | [diff] [blame] | 312 | if not self.is_manual: |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 313 | with open("%s/run.sh" % self.test["test_path"], "a") as f: |
| 314 | f.write("#!/bin/sh\n") |
Chase Qi | 09edc7f | 2016-08-18 13:18:50 +0800 | [diff] [blame] | 315 | |
Milosz Wasilewski | 2fea70e | 2016-11-11 12:16:09 +0000 | [diff] [blame] | 316 | self.parameters = self.handle_parameters() |
| 317 | if self.parameters: |
| 318 | for line in self.parameters: |
| 319 | f.write(line) |
Chase Qi | 09edc7f | 2016-08-18 13:18:50 +0800 | [diff] [blame] | 320 | |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 321 | f.write("set -e\n") |
| 322 | f.write("set -x\n") |
| 323 | f.write("export TESTRUN_ID=%s\n" % self.testdef["metadata"]["name"]) |
Milosz Wasilewski | 682120e | 2017-03-13 13:37:18 +0000 | [diff] [blame] | 324 | if self.args.target is None: |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 325 | f.write("cd %s\n" % (self.test["test_path"])) |
Milosz Wasilewski | 682120e | 2017-03-13 13:37:18 +0000 | [diff] [blame] | 326 | else: |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 327 | f.write("cd %s\n" % (self.test["target_test_path"])) |
| 328 | f.write("UUID=`cat uuid`\n") |
Milosz Wasilewski | 2fea70e | 2016-11-11 12:16:09 +0000 | [diff] [blame] | 329 | f.write('echo "<STARTRUN $TESTRUN_ID $UUID>"\n') |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 330 | 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 Wasilewski | 2fea70e | 2016-11-11 12:16:09 +0000 | [diff] [blame] | 334 | if steps: |
Dan Rue | b592da1 | 2017-06-07 16:32:43 -0500 | [diff] [blame] | 335 | for step in steps: |
| 336 | command = step |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 337 | 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 Wasilewski | 2fea70e | 2016-11-11 12:16:09 +0000 | [diff] [blame] | 340 | f.write('echo "<ENDRUN $TESTRUN_ID $UUID>"\n') |
Chase Qi | 09edc7f | 2016-08-18 13:18:50 +0800 | [diff] [blame] | 341 | |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 342 | os.chmod("%s/run.sh" % self.test["test_path"], 0o755) |
Milosz Wasilewski | 2fea70e | 2016-11-11 12:16:09 +0000 | [diff] [blame] | 343 | |
Nicolas Dechesne | 51b85a8 | 2017-02-04 00:45:48 +0100 | [diff] [blame] | 344 | def run(self): |
| 345 | self.runner.run() |
Chase Qi | 09edc7f | 2016-08-18 13:18:50 +0800 | [diff] [blame] | 346 | |
| 347 | def handle_parameters(self): |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 348 | ret_val = ["###default parameters from test definition###\n"] |
Chase Qi | 09edc7f | 2016-08-18 13:18:50 +0800 | [diff] [blame] | 349 | |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 350 | if "params" in self.testdef: |
| 351 | for def_param_name, def_param_value in list(self.testdef["params"].items()): |
Chase Qi | 09edc7f | 2016-08-18 13:18:50 +0800 | [diff] [blame] | 352 | # ?'yaml_line' |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 353 | if def_param_name == "yaml_line": |
Chase Qi | 09edc7f | 2016-08-18 13:18:50 +0800 | [diff] [blame] | 354 | continue |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 355 | 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 Qi | 09edc7f | 2016-08-18 13:18:50 +0800 | [diff] [blame] | 361 | continue |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 362 | ret_val.append("%s='%s'\n" % (def_param_name, def_param_value)) |
Chase Qi | 09edc7f | 2016-08-18 13:18:50 +0800 | [diff] [blame] | 363 | else: |
| 364 | return None |
| 365 | |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 366 | ret_val.append("######\n") |
Chase Qi | 09edc7f | 2016-08-18 13:18:50 +0800 | [diff] [blame] | 367 | |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 368 | ret_val.append("###custom parameters from test plan###\n") |
Chase Qi | 09edc7f | 2016-08-18 13:18:50 +0800 | [diff] [blame] | 369 | if self.custom_params: |
| 370 | for param_name, param_value in list(self.custom_params.items()): |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 371 | if param_name == "yaml_line": |
Chase Qi | 09edc7f | 2016-08-18 13:18:50 +0800 | [diff] [blame] | 372 | continue |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 373 | ret_val.append("%s='%s'\n" % (param_name, param_value)) |
Chase Qi | 09edc7f | 2016-08-18 13:18:50 +0800 | [diff] [blame] | 374 | |
| 375 | if self.skip_install: |
| 376 | ret_val.append('SKIP_INSTALL="True"\n') |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 377 | ret_val.append("######\n") |
Chase Qi | 09edc7f | 2016-08-18 13:18:50 +0800 | [diff] [blame] | 378 | |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 379 | ret_val.append("###custom parameters from command line###\n") |
Milosz Wasilewski | 259ba19 | 2017-07-27 10:59:25 +0100 | [diff] [blame] | 380 | if self.args.test_def_params: |
| 381 | for param_name, param_value in self.args.test_def_params.items(): |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 382 | ret_val.append("%s='%s'\n" % (param_name, param_value)) |
| 383 | ret_val.append("######\n") |
Chase Qi | 09edc7f | 2016-08-18 13:18:50 +0800 | [diff] [blame] | 384 | return ret_val |
| 385 | |
| 386 | |
| 387 | class TestRun(object): |
| 388 | def __init__(self, test, args): |
Milosz Wasilewski | 682120e | 2017-03-13 13:37:18 +0000 | [diff] [blame] | 389 | self.test = test |
| 390 | self.args = args |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 391 | self.logger = logging.getLogger("RUNNER.TestRun") |
Milosz Wasilewski | 682120e | 2017-03-13 13:37:18 +0000 | [diff] [blame] | 392 | self.test_timeout = self.args.timeout |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 393 | if "timeout" in test: |
| 394 | self.test_timeout = test["timeout"] |
Milosz Wasilewski | 2fea70e | 2016-11-11 12:16:09 +0000 | [diff] [blame] | 395 | |
| 396 | def run(self): |
| 397 | raise NotImplementedError |
| 398 | |
| 399 | def check_result(self): |
| 400 | raise NotImplementedError |
| 401 | |
| 402 | |
| 403 | class AutomatedTestRun(TestRun): |
| 404 | def run(self): |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 405 | 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 Wasilewski | 682120e | 2017-03-13 13:37:18 +0000 | [diff] [blame] | 411 | self.check_result() |
Chase Qi | 09edc7f | 2016-08-18 13:18:50 +0800 | [diff] [blame] | 412 | |
Milosz Wasilewski | 2fea70e | 2016-11-11 12:16:09 +0000 | [diff] [blame] | 413 | def check_result(self): |
Chase Qi | 09edc7f | 2016-08-18 13:18:50 +0800 | [diff] [blame] | 414 | if self.test_timeout: |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 415 | self.logger.info("Test timeout: %s" % self.test_timeout) |
Chase Qi | 09edc7f | 2016-08-18 13:18:50 +0800 | [diff] [blame] | 416 | test_end = time.time() + self.test_timeout |
| 417 | |
| 418 | while self.child.isalive(): |
| 419 | if self.test_timeout and time.time() > test_end: |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 420 | self.logger.warning( |
| 421 | "%s test timed out, killing test process..." |
| 422 | % self.test["test_uuid"] |
| 423 | ) |
Chase Qi | 09edc7f | 2016-08-18 13:18:50 +0800 | [diff] [blame] | 424 | self.child.terminate(force=True) |
| 425 | break |
| 426 | try: |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 427 | self.child.expect("\r\n") |
Milosz Wasilewski | d71f28a | 2020-06-10 20:05:13 +0100 | [diff] [blame] | 428 | print(self.child.before) |
Chase Qi | 09edc7f | 2016-08-18 13:18:50 +0800 | [diff] [blame] | 429 | except pexpect.TIMEOUT: |
| 430 | continue |
| 431 | except pexpect.EOF: |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 432 | self.logger.info("%s test finished.\n" % self.test["test_uuid"]) |
Chase Qi | 09edc7f | 2016-08-18 13:18:50 +0800 | [diff] [blame] | 433 | break |
| 434 | |
| 435 | |
Milosz Wasilewski | 682120e | 2017-03-13 13:37:18 +0000 | [diff] [blame] | 436 | class RemoteTestRun(AutomatedTestRun): |
| 437 | def copy_to_target(self): |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 438 | os.chdir(self.test["test_path"]) |
Milosz Wasilewski | 682120e | 2017-03-13 13:37:18 +0000 | [diff] [blame] | 439 | tarball_name = "target-test-files.tar" |
Dan Rue | a9eb01c | 2017-06-07 16:29:09 -0500 | [diff] [blame] | 440 | |
| 441 | self.logger.info("Archiving test files") |
| 442 | run_command( |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 443 | "tar -caf %s run.sh uuid automated/lib automated/bin automated/utils %s" |
| 444 | % (tarball_name, self.test["tc_relative_dir"]) |
| 445 | ) |
Dan Rue | a9eb01c | 2017-06-07 16:29:09 -0500 | [diff] [blame] | 446 | |
| 447 | self.logger.info("Creating test path") |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 448 | run_command("mkdir -p %s" % (self.test["target_test_path"]), self.args.target) |
Dan Rue | a9eb01c | 2017-06-07 16:29:09 -0500 | [diff] [blame] | 449 | |
| 450 | self.logger.info("Copying test archive to target host") |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 451 | 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 Rue | a9eb01c | 2017-06-07 16:29:09 -0500 | [diff] [blame] | 460 | |
| 461 | self.logger.info("Unarchiving test files on target") |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 462 | run_command( |
| 463 | "cd %s && tar -xf %s" % (self.test["target_test_path"], tarball_name), |
| 464 | self.args.target, |
| 465 | ) |
Dan Rue | a9eb01c | 2017-06-07 16:29:09 -0500 | [diff] [blame] | 466 | |
| 467 | self.logger.info("Removing test file archive from target") |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 468 | run_command( |
| 469 | "rm %s/%s" % (self.test["target_test_path"], tarball_name), self.args.target |
| 470 | ) |
Milosz Wasilewski | 682120e | 2017-03-13 13:37:18 +0000 | [diff] [blame] | 471 | |
| 472 | def run(self): |
| 473 | self.copy_to_target() |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 474 | 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 Wasilewski | d71f28a | 2020-06-10 20:05:13 +0100 | [diff] [blame] | 485 | self.child = pexpect.spawnu(shell_cmd) |
Milosz Wasilewski | 682120e | 2017-03-13 13:37:18 +0000 | [diff] [blame] | 486 | self.child.logfile = output |
| 487 | self.check_result() |
| 488 | |
| 489 | |
Milosz Wasilewski | 2fea70e | 2016-11-11 12:16:09 +0000 | [diff] [blame] | 490 | class ManualTestShell(cmd.Cmd): |
Nicolas Dechesne | 1945d3f | 2020-10-07 23:36:34 +0200 | [diff] [blame] | 491 | def __init__(self, test_dict, result_path, test_case_id): |
Milosz Wasilewski | 2fea70e | 2016-11-11 12:16:09 +0000 | [diff] [blame] | 492 | cmd.Cmd.__init__(self) |
| 493 | self.test_dict = test_dict |
Nicolas Dechesne | 1945d3f | 2020-10-07 23:36:34 +0200 | [diff] [blame] | 494 | self.test_case_id = test_case_id |
Milosz Wasilewski | 2fea70e | 2016-11-11 12:16:09 +0000 | [diff] [blame] | 495 | self.result_path = result_path |
| 496 | self.current_step_index = 0 |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 497 | 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 Wasilewski | 2fea70e | 2016-11-11 12:16:09 +0000 | [diff] [blame] | 503 | 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 Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 522 | print( |
| 523 | "Test result not recorded. Use -f to force. Forced quit records result as 'skip'" |
| 524 | ) |
Milosz Wasilewski | 2fea70e | 2016-11-11 12:16:09 +0000 | [diff] [blame] | 525 | |
| 526 | do_EOF = do_quit |
| 527 | |
| 528 | def do_description(self, line): |
| 529 | """ |
| 530 | Prints current test overall description |
| 531 | """ |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 532 | print(self.test_dict["metadata"]["description"]) |
Milosz Wasilewski | 2fea70e | 2016-11-11 12:16:09 +0000 | [diff] [blame] | 533 | |
| 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 Qi | c69235d | 2017-05-23 14:56:47 +0800 | [diff] [blame] | 539 | print("%s. %s" % (index, step)) |
Milosz Wasilewski | 2fea70e | 2016-11-11 12:16:09 +0000 | [diff] [blame] | 540 | |
| 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 Qi | c69235d | 2017-05-23 14:56:47 +0800 | [diff] [blame] | 546 | print("%s. %s" % (index, expected)) |
Milosz Wasilewski | 2fea70e | 2016-11-11 12:16:09 +0000 | [diff] [blame] | 547 | |
| 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 Qi | c69235d | 2017-05-23 14:56:47 +0800 | [diff] [blame] | 565 | print("%s. %s" % (self.current_step_index, self.steps[self.current_step_index])) |
Milosz Wasilewski | 2fea70e | 2016-11-11 12:16:09 +0000 | [diff] [blame] | 566 | |
| 567 | def _record_result(self, result): |
Chase Qi | c69235d | 2017-05-23 14:56:47 +0800 | [diff] [blame] | 568 | print("Recording %s in %s/stdout.log" % (result, self.result_path)) |
Milosz Wasilewski | 2fea70e | 2016-11-11 12:16:09 +0000 | [diff] [blame] | 569 | with open("%s/stdout.log" % self.result_path, "a") as f: |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 570 | f.write( |
| 571 | "<LAVA_SIGNAL_TESTCASE TEST_CASE_ID=%s RESULT=%s>" |
| 572 | % (self.test_case_id, result) |
| 573 | ) |
Milosz Wasilewski | 2fea70e | 2016-11-11 12:16:09 +0000 | [diff] [blame] | 574 | |
| 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 | |
| 600 | class ManualTestRun(TestRun, cmd.Cmd): |
| 601 | def run(self): |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 602 | print(self.test["test_name"]) |
| 603 | with open("%s/testdef.yaml" % self.test["test_path"], "r") as f: |
Milosz Wasilewski | 2fea70e | 2016-11-11 12:16:09 +0000 | [diff] [blame] | 604 | self.testdef = yaml.safe_load(f) |
| 605 | |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 606 | if "name" in self.test: |
| 607 | test_case_id = self.test["name"] |
Nicolas Dechesne | 1945d3f | 2020-10-07 23:36:34 +0200 | [diff] [blame] | 608 | else: |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 609 | test_case_id = self.testdef["metadata"]["name"] |
Nicolas Dechesne | 1945d3f | 2020-10-07 23:36:34 +0200 | [diff] [blame] | 610 | |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 611 | ManualTestShell(self.testdef, self.test["test_path"], test_case_id).cmdloop() |
Milosz Wasilewski | 2fea70e | 2016-11-11 12:16:09 +0000 | [diff] [blame] | 612 | |
| 613 | def check_result(self): |
| 614 | pass |
| 615 | |
| 616 | |
Dan Rue | a9eb01c | 2017-06-07 16:29:09 -0500 | [diff] [blame] | 617 | def 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 Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 639 | logger = logging.getLogger("RUNNER.get_packages") |
Dan Rue | a9eb01c | 2017-06-07 16:29:09 -0500 | [diff] [blame] | 640 | packages = [] |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 641 | if linux_distribution in ["debian", "ubuntu"]: |
Dan Rue | a9eb01c | 2017-06-07 16:29:09 -0500 | [diff] [blame] | 642 | # Debian (apt) based system |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 643 | packages = run_command( |
| 644 | "dpkg-query -W -f '${package}-${version}\n'", target |
| 645 | ).splitlines() |
Dan Rue | a9eb01c | 2017-06-07 16:29:09 -0500 | [diff] [blame] | 646 | |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 647 | elif linux_distribution in ["centos", "fedora"]: |
Dan Rue | a9eb01c | 2017-06-07 16:29:09 -0500 | [diff] [blame] | 648 | # RedHat (rpm) based system |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 649 | packages = run_command( |
| 650 | "rpm -qa --qf '%{NAME}-%{VERSION}-%{RELEASE}\n'", target |
| 651 | ).splitlines() |
Dan Rue | a9eb01c | 2017-06-07 16:29:09 -0500 | [diff] [blame] | 652 | else: |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 653 | logger.warning( |
| 654 | "Unknown linux distribution '{}'; package list not populated.".format( |
| 655 | linux_distribution |
| 656 | ) |
| 657 | ) |
Dan Rue | a9eb01c | 2017-06-07 16:29:09 -0500 | [diff] [blame] | 658 | |
| 659 | packages.sort() |
| 660 | return packages |
| 661 | |
| 662 | |
| 663 | def 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 Wasilewski | df71a76 | 2017-07-20 13:26:21 +0100 | [diff] [blame] | 690 | try: |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 691 | environment["linux_distribution"] = ( |
| 692 | run_command("grep ^ID= /etc/os-release", target) |
| 693 | .split("=")[-1] |
| 694 | .strip('"') |
| 695 | .lower() |
| 696 | ) |
Milosz Wasilewski | df71a76 | 2017-07-20 13:26:21 +0100 | [diff] [blame] | 697 | except subprocess.CalledProcessError: |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 698 | environment["linux_distribution"] = "" |
Milosz Wasilewski | df71a76 | 2017-07-20 13:26:21 +0100 | [diff] [blame] | 699 | |
| 700 | try: |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 701 | environment["kernel"] = run_command("uname -r", target) |
Milosz Wasilewski | df71a76 | 2017-07-20 13:26:21 +0100 | [diff] [blame] | 702 | except subprocess.CalledProcessError: |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 703 | environment["kernel"] = "" |
Milosz Wasilewski | df71a76 | 2017-07-20 13:26:21 +0100 | [diff] [blame] | 704 | |
| 705 | try: |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 706 | environment["uname"] = run_command("uname -a", target) |
Milosz Wasilewski | df71a76 | 2017-07-20 13:26:21 +0100 | [diff] [blame] | 707 | except subprocess.CalledProcessError: |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 708 | environment["uname"] = "" |
Dan Rue | a9eb01c | 2017-06-07 16:29:09 -0500 | [diff] [blame] | 709 | |
| 710 | try: |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 711 | environment["bios_version"] = run_command( |
| 712 | "cat /sys/devices/virtual/dmi/id/bios_version", target |
| 713 | ) |
Dan Rue | a9eb01c | 2017-06-07 16:29:09 -0500 | [diff] [blame] | 714 | except subprocess.CalledProcessError: |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 715 | environment["bios_version"] = "" |
Dan Rue | a9eb01c | 2017-06-07 16:29:09 -0500 | [diff] [blame] | 716 | |
| 717 | try: |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 718 | environment["board_vendor"] = run_command( |
| 719 | "cat /sys/devices/virtual/dmi/id/board_vendor", target |
| 720 | ) |
Dan Rue | a9eb01c | 2017-06-07 16:29:09 -0500 | [diff] [blame] | 721 | except subprocess.CalledProcessError: |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 722 | environment["board_vendor"] = "" |
Dan Rue | a9eb01c | 2017-06-07 16:29:09 -0500 | [diff] [blame] | 723 | |
| 724 | try: |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 725 | environment["board_name"] = run_command( |
| 726 | "cat /sys/devices/virtual/dmi/id/board_name", target |
| 727 | ) |
Dan Rue | a9eb01c | 2017-06-07 16:29:09 -0500 | [diff] [blame] | 728 | except subprocess.CalledProcessError: |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 729 | environment["board_name"] = "" |
Dan Rue | a9eb01c | 2017-06-07 16:29:09 -0500 | [diff] [blame] | 730 | |
Milosz Wasilewski | df71a76 | 2017-07-20 13:26:21 +0100 | [diff] [blame] | 731 | try: |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 732 | environment["packages"] = get_packages( |
| 733 | environment["linux_distribution"], target |
| 734 | ) |
Milosz Wasilewski | df71a76 | 2017-07-20 13:26:21 +0100 | [diff] [blame] | 735 | except subprocess.CalledProcessError: |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 736 | environment["packages"] = [] |
Dan Rue | a9eb01c | 2017-06-07 16:29:09 -0500 | [diff] [blame] | 737 | return environment |
| 738 | |
| 739 | |
Chase Qi | 09edc7f | 2016-08-18 13:18:50 +0800 | [diff] [blame] | 740 | class ResultParser(object): |
| 741 | def __init__(self, test, args): |
Milosz Wasilewski | 682120e | 2017-03-13 13:37:18 +0000 | [diff] [blame] | 742 | self.test = test |
| 743 | self.args = args |
Chase Qi | 09edc7f | 2016-08-18 13:18:50 +0800 | [diff] [blame] | 744 | self.metrics = [] |
| 745 | self.results = {} |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 746 | 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 Qi | e94ba52 | 2017-05-26 12:05:18 +0800 | [diff] [blame] | 754 | self.pattern = None |
| 755 | self.fixup = None |
Vishal Bhoj | e94da4a | 2020-05-15 12:22:40 +0530 | [diff] [blame] | 756 | 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 Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 760 | self.qa_reports_token = os.environ.get( |
| 761 | "QA_REPORTS_TOKEN", get_token_from_netrc(self.qa_reports_server) |
| 762 | ) |
Vishal Bhoj | e94da4a | 2020-05-15 12:22:40 +0530 | [diff] [blame] | 763 | 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 Wasilewski | b4b40de | 2020-06-11 12:54:18 +0100 | [diff] [blame] | 767 | self.qa_reports_disable_metadata = args.qa_reports_disable_metadata |
Milosz Wasilewski | 37848d3 | 2020-06-11 14:33:43 +0100 | [diff] [blame] | 768 | self.qa_reports_metadata = args.qa_reports_metadata |
Milosz Wasilewski | abe2dcc | 2020-06-12 10:54:46 +0100 | [diff] [blame] | 769 | self.qa_reports_metadata_file = args.qa_reports_metadata_file |
Vishal Bhoj | e94da4a | 2020-05-15 12:22:40 +0530 | [diff] [blame] | 770 | |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 771 | with open(os.path.join(self.test["test_path"], "testdef.yaml"), "r") as f: |
Milosz Wasilewski | a76e8dd | 2016-11-25 14:13:25 +0000 | [diff] [blame] | 772 | self.testdef = yaml.safe_load(f) |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 773 | 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 Dechesne | faa343d | 2017-10-23 00:33:10 +0200 | [diff] [blame] | 781 | if self.args.test_def_params: |
| 782 | for param_name, param_value in self.args.test_def_params.items(): |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 783 | 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 Qi | e94ba52 | 2017-05-26 12:05:18 +0800 | [diff] [blame] | 789 | self.logger.info("Enabling log parse pattern: %s" % self.pattern) |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 790 | 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 Wasilewski | 970431b | 2016-11-25 14:10:08 +0000 | [diff] [blame] | 801 | else: |
| 802 | path = os.getcwd() |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 803 | os.chdir(self.test["test_path"]) |
Chase Qi | 3efa769 | 2017-06-26 15:54:05 +0800 | [diff] [blame] | 804 | if sys.version_info[0] < 3: |
| 805 | test_version = subprocess.check_output("git rev-parse HEAD", shell=True) |
| 806 | else: |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 807 | test_version = subprocess.check_output( |
| 808 | "git rev-parse HEAD", shell=True |
| 809 | ).decode("utf-8") |
| 810 | self.results["version"] = test_version.rstrip() |
Milosz Wasilewski | 970431b | 2016-11-25 14:10:08 +0000 | [diff] [blame] | 811 | os.chdir(path) |
Chase Qi | ea54335 | 2017-09-21 16:44:30 +0800 | [diff] [blame] | 812 | self.lava_run = args.lava_run |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 813 | 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 Qi | ea54335 | 2017-09-21 16:44:30 +0800 | [diff] [blame] | 817 | self.lava_run = False |
Chase Qi | 09edc7f | 2016-08-18 13:18:50 +0800 | [diff] [blame] | 818 | |
| 819 | def run(self): |
| 820 | self.parse_stdout() |
Chase Qi | e94ba52 | 2017-05-26 12:05:18 +0800 | [diff] [blame] | 821 | if self.pattern: |
| 822 | self.parse_pattern() |
| 823 | # If 'metrics' is empty, add 'no-result-found fail'. |
| 824 | if not self.metrics: |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 825 | 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 Qi | 09edc7f | 2016-08-18 13:18:50 +0800 | [diff] [blame] | 834 | self.dict_to_json() |
| 835 | self.dict_to_csv() |
Vishal Bhoj | e94da4a | 2020-05-15 12:22:40 +0530 | [diff] [blame] | 836 | self.send_to_qa_reports() |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 837 | 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 Qi | 09edc7f | 2016-08-18 13:18:50 +0800 | [diff] [blame] | 840 | print(f.read()) |
| 841 | |
| 842 | def parse_stdout(self): |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 843 | with open("%s/stdout.log" % self.test["test_path"], "r") as f: |
Milosz Wasilewski | 5a4dd44 | 2016-12-07 15:01:57 +0000 | [diff] [blame] | 844 | 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 Qi | 09edc7f | 2016-08-18 13:18:50 +0800 | [diff] [blame] | 848 | for line in f: |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 849 | 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 Qi | 09edc7f | 2016-08-18 13:18:50 +0800 | [diff] [blame] | 857 | |
| 858 | for string in line: |
Milosz Wasilewski | ff69562 | 2016-12-05 16:00:06 +0000 | [diff] [blame] | 859 | 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 Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 864 | data["test_case_id"] = test_case_match.group(1) |
Milosz Wasilewski | ff69562 | 2016-12-05 16:00:06 +0000 | [diff] [blame] | 865 | if result_match: |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 866 | data["result"] = result_match.group(1) |
Milosz Wasilewski | ff69562 | 2016-12-05 16:00:06 +0000 | [diff] [blame] | 867 | if measurement_match: |
Nicolas Dechesne | 508a227 | 2020-10-03 11:10:37 +0200 | [diff] [blame] | 868 | try: |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 869 | data["measurement"] = float(measurement_match.group(1)) |
Nicolas Dechesne | 508a227 | 2020-10-03 11:10:37 +0200 | [diff] [blame] | 870 | except ValueError as e: |
| 871 | pass |
Milosz Wasilewski | ff69562 | 2016-12-05 16:00:06 +0000 | [diff] [blame] | 872 | if units_match: |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 873 | data["units"] = units_match.group(1) |
Chase Qi | 09edc7f | 2016-08-18 13:18:50 +0800 | [diff] [blame] | 874 | |
| 875 | self.metrics.append(data.copy()) |
| 876 | |
Chase Qi | ea54335 | 2017-09-21 16:44:30 +0800 | [diff] [blame] | 877 | if self.lava_run: |
| 878 | self.send_to_lava(data) |
| 879 | |
Chase Qi | e94ba52 | 2017-05-26 12:05:18 +0800 | [diff] [blame] | 880 | def parse_pattern(self): |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 881 | with open("%s/stdout.log" % self.test["test_path"], "r") as f: |
| 882 | rex_pattern = re.compile(r"%s" % self.pattern) |
Chase Qi | e94ba52 | 2017-05-26 12:05:18 +0800 | [diff] [blame] | 883 | for line in f: |
| 884 | data = {} |
AnÃbal Limón | c36cb79 | 2017-11-29 11:54:30 -0600 | [diff] [blame] | 885 | m = rex_pattern.search(line) |
Chase Qi | e94ba52 | 2017-05-26 12:05:18 +0800 | [diff] [blame] | 886 | if m: |
| 887 | data = m.groupdict() |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 888 | for x in ["measurement", "units"]: |
Chase Qi | e94ba52 | 2017-05-26 12:05:18 +0800 | [diff] [blame] | 889 | if x not in data: |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 890 | data[x] = "" |
| 891 | if self.fixup and data["result"] in self.fixup: |
| 892 | data["result"] = self.fixup[data["result"]] |
Chase Qi | 1f2a9a0 | 2017-03-09 15:45:04 +0100 | [diff] [blame] | 893 | |
Chase Qi | e94ba52 | 2017-05-26 12:05:18 +0800 | [diff] [blame] | 894 | self.metrics.append(data.copy()) |
Chase Qi | 09edc7f | 2016-08-18 13:18:50 +0800 | [diff] [blame] | 895 | |
Chase Qi | ea54335 | 2017-09-21 16:44:30 +0800 | [diff] [blame] | 896 | if self.lava_run: |
| 897 | self.send_to_lava(data) |
| 898 | |
| 899 | def send_to_lava(self, data): |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 900 | 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 Qi | ea54335 | 2017-09-21 16:44:30 +0800 | [diff] [blame] | 908 | subprocess.call(shlex.split(cmd)) |
| 909 | |
Vishal Bhoj | e94da4a | 2020-05-15 12:22:40 +0530 | [diff] [blame] | 910 | def send_to_qa_reports(self): |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 911 | 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 Bhoj | e94da4a | 2020-05-15 12:22:40 +0530 | [diff] [blame] | 922 | return |
| 923 | |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 924 | SquadApi.configure(url=self.qa_reports_server, token=self.qa_reports_token) |
Vishal Bhoj | e94da4a | 2020-05-15 12:22:40 +0530 | [diff] [blame] | 925 | tests = {} |
| 926 | metrics = {} |
| 927 | for metric in self.metrics: |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 928 | if metric["measurement"] != "": |
| 929 | metrics[ |
| 930 | "{}/{}".format(self.test["test_name"], metric["test_case_id"]) |
| 931 | ] = metric["measurement"] |
Vishal Bhoj | e94da4a | 2020-05-15 12:22:40 +0530 | [diff] [blame] | 932 | else: |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 933 | tests[ |
| 934 | "{}/{}".format(self.test["test_name"], metric["test_case_id"]) |
| 935 | ] = metric["result"] |
Vishal Bhoj | e94da4a | 2020-05-15 12:22:40 +0530 | [diff] [blame] | 936 | |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 937 | with open("{}/stdout.log".format(self.test["test_path"]), "r") as logfile: |
Vishal Bhoj | e94da4a | 2020-05-15 12:22:40 +0530 | [diff] [blame] | 938 | log = logfile.read() |
| 939 | |
Milosz Wasilewski | abe2dcc | 2020-06-12 10:54:46 +0100 | [diff] [blame] | 940 | metadata = {} |
Milosz Wasilewski | b00ceff | 2020-06-15 13:48:01 +0100 | [diff] [blame] | 941 | 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 Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 947 | loaded_metadata = yaml.load( |
| 948 | metadata_file, Loader=yaml.SafeLoader |
| 949 | ) |
Milosz Wasilewski | b00ceff | 2020-06-15 13:48:01 +0100 | [diff] [blame] | 950 | # 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 Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 961 | self.logger.warning( |
| 962 | "Insufficient permissions to open metadata file" |
| 963 | ) |
Milosz Wasilewski | f883f10 | 2020-06-11 12:46:58 +0100 | [diff] [blame] | 964 | if submit_results( |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 965 | 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 Wasilewski | f883f10 | 2020-06-11 12:46:58 +0100 | [diff] [blame] | 976 | self.logger.info("Results pushed to QA Reports") |
| 977 | else: |
| 978 | self.logger.warning("Results upload to QA Reports failed!") |
Vishal Bhoj | e94da4a | 2020-05-15 12:22:40 +0530 | [diff] [blame] | 979 | |
Chase Qi | 09edc7f | 2016-08-18 13:18:50 +0800 | [diff] [blame] | 980 | def dict_to_json(self): |
Chase Qi | 87f4f40 | 2016-11-07 15:32:01 +0800 | [diff] [blame] | 981 | # Save test results to output/test_id/result.json |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 982 | with open("%s/result.json" % self.test["test_path"], "w") as f: |
Chase Qi | 87f4f40 | 2016-11-07 15:32:01 +0800 | [diff] [blame] | 983 | json.dump([self.results], f, indent=4) |
| 984 | |
| 985 | # Collect test results of all tests in output/result.json |
| 986 | feeds = [] |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 987 | if os.path.isfile("%s/result.json" % self.test["output"]): |
| 988 | with open("%s/result.json" % self.test["output"], "r") as f: |
Chase Qi | 87f4f40 | 2016-11-07 15:32:01 +0800 | [diff] [blame] | 989 | feeds = json.load(f) |
| 990 | |
| 991 | feeds.append(self.results) |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 992 | with open("%s/result.json" % self.test["output"], "w") as f: |
Chase Qi | 87f4f40 | 2016-11-07 15:32:01 +0800 | [diff] [blame] | 993 | json.dump(feeds, f, indent=4) |
Chase Qi | 09edc7f | 2016-08-18 13:18:50 +0800 | [diff] [blame] | 994 | |
| 995 | def dict_to_csv(self): |
Chase Qi | ca15cf5 | 2016-11-10 17:00:22 +0800 | [diff] [blame] | 996 | # Convert dict self.results['params'] to a string. |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 997 | 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 Qi | 09edc7f | 2016-08-18 13:18:50 +0800 | [diff] [blame] | 1001 | |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 1002 | for metric in self.results["metrics"]: |
| 1003 | metric["name"] = self.results["name"] |
| 1004 | metric["test_params"] = test_params |
Chase Qi | ca15cf5 | 2016-11-10 17:00:22 +0800 | [diff] [blame] | 1005 | |
| 1006 | # Save test results to output/test_id/result.csv |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 1007 | 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 Qi | ca15cf5 | 2016-11-10 17:00:22 +0800 | [diff] [blame] | 1016 | writer = csv.DictWriter(f, fieldnames=fieldnames) |
Chase Qi | 09edc7f | 2016-08-18 13:18:50 +0800 | [diff] [blame] | 1017 | writer.writeheader() |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 1018 | for metric in self.results["metrics"]: |
Chase Qi | 09edc7f | 2016-08-18 13:18:50 +0800 | [diff] [blame] | 1019 | writer.writerow(metric) |
| 1020 | |
Chase Qi | 87f4f40 | 2016-11-07 15:32:01 +0800 | [diff] [blame] | 1021 | # Collect test results of all tests in output/result.csv |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 1022 | if not os.path.isfile("%s/result.csv" % self.test["output"]): |
| 1023 | with open("%s/result.csv" % self.test["output"], "w") as f: |
Chase Qi | 87f4f40 | 2016-11-07 15:32:01 +0800 | [diff] [blame] | 1024 | writer = csv.DictWriter(f, fieldnames=fieldnames) |
| 1025 | writer.writeheader() |
| 1026 | |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 1027 | with open("%s/result.csv" % self.test["output"], "a") as f: |
Chase Qi | 09edc7f | 2016-08-18 13:18:50 +0800 | [diff] [blame] | 1028 | writer = csv.DictWriter(f, fieldnames=fieldnames) |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 1029 | for metric in self.results["metrics"]: |
Chase Qi | 09edc7f | 2016-08-18 13:18:50 +0800 | [diff] [blame] | 1030 | writer.writerow(metric) |
| 1031 | |
| 1032 | |
Vishal Bhoj | e94da4a | 2020-05-15 12:22:40 +0530 | [diff] [blame] | 1033 | def 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 Qi | 09edc7f | 2016-08-18 13:18:50 +0800 | [diff] [blame] | 1046 | def get_args(): |
Milosz Wasilewski | 259ba19 | 2017-07-27 10:59:25 +0100 | [diff] [blame] | 1047 | parser = argparse.ArgumentParser(formatter_class=argparse.RawTextHelpFormatter) |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 1048 | parser.add_argument( |
| 1049 | "-o", |
| 1050 | "--output", |
| 1051 | default=os.getenv("HOME", "") + "/output", |
| 1052 | dest="output", |
| 1053 | help=textwrap.dedent( |
| 1054 | """\ |
Chase Qi | 09edc7f | 2016-08-18 13:18:50 +0800 | [diff] [blame] | 1055 | specify a directory to store test and result files. |
Nicolas Dechesne | f6c4c21 | 2017-01-18 17:30:04 +0100 | [diff] [blame] | 1056 | Default: $HOME/output |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 1057 | """ |
| 1058 | ), |
| 1059 | ) |
| 1060 | parser.add_argument( |
| 1061 | "-p", |
| 1062 | "--test_plan", |
| 1063 | default=None, |
| 1064 | dest="test_plan", |
| 1065 | help=textwrap.dedent( |
| 1066 | """\ |
Chase Qi | 09edc7f | 2016-08-18 13:18:50 +0800 | [diff] [blame] | 1067 | specify an test plan file which has tests and related |
| 1068 | params listed in yaml format. |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 1069 | """ |
| 1070 | ), |
| 1071 | ) |
| 1072 | parser.add_argument( |
| 1073 | "-d", |
| 1074 | "--test_def", |
| 1075 | default=None, |
| 1076 | dest="test_def", |
| 1077 | help=textwrap.dedent( |
| 1078 | """\ |
Chase Qi | 09edc7f | 2016-08-18 13:18:50 +0800 | [diff] [blame] | 1079 | 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 Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 1082 | """ |
| 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 Wasilewski | 259ba19 | 2017-07-27 10:59:25 +0100 | [diff] [blame] | 1095 | 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 Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 1099 | """ |
| 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 Wasilewski | 2fea70e | 2016-11-11 12:16:09 +0000 | [diff] [blame] | 1110 | Selects type of tests to be executed from the test plan. |
| 1111 | Possible options: automated, manual |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 1112 | """ |
| 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 Wasilewski | 682120e | 2017-03-13 13:37:18 +0000 | [diff] [blame] | 1130 | Specify SSH target to execute tests. |
| 1131 | Format: user@host |
| 1132 | Note: ssh authentication must be paswordless |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 1133 | """ |
| 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 Qi | a158efe | 2017-11-17 12:35:11 +0800 | [diff] [blame] | 1167 | Specify test plan ovelay file to: |
| 1168 | * skip tests |
| 1169 | * amend test parameters |
| 1170 | * add new tests |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 1171 | """ |
| 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 Bhoj | e94da4a | 2020-05-15 12:22:40 +0530 | [diff] [blame] | 1182 | 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 Wasilewski | b4b40de | 2020-06-11 12:54:18 +0100 | [diff] [blame] | 1218 | parser.add_argument( |
| 1219 | "--qa-reports-disable-metadata", |
| 1220 | dest="qa_reports_disable_metadata", |
| 1221 | default=False, |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 1222 | action="store_true", |
Milosz Wasilewski | 37848d3 | 2020-06-11 14:33:43 +0100 | [diff] [blame] | 1223 | 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 Wasilewski | b4b40de | 2020-06-11 12:54:18 +0100 | [diff] [blame] | 1233 | ) |
Milosz Wasilewski | abe2dcc | 2020-06-12 10:54:46 +0100 | [diff] [blame] | 1234 | 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 Wasilewski | b4b40de | 2020-06-11 12:54:18 +0100 | [diff] [blame] | 1240 | |
Chase Qi | 09edc7f | 2016-08-18 13:18:50 +0800 | [diff] [blame] | 1241 | args = parser.parse_args() |
| 1242 | return args |
| 1243 | |
| 1244 | |
| 1245 | def main(): |
Chase Qi | 0e9b36e | 2017-12-07 16:13:44 +0800 | [diff] [blame] | 1246 | args = get_args() |
| 1247 | |
Chase Qi | 09edc7f | 2016-08-18 13:18:50 +0800 | [diff] [blame] | 1248 | # Setup logger. |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 1249 | logger = logging.getLogger("RUNNER") |
Chase Qi | 0e9b36e | 2017-12-07 16:13:44 +0800 | [diff] [blame] | 1250 | logger.setLevel(logging.INFO) |
| 1251 | if args.verbose: |
| 1252 | logger.setLevel(logging.DEBUG) |
Chase Qi | 09edc7f | 2016-08-18 13:18:50 +0800 | [diff] [blame] | 1253 | ch = logging.StreamHandler() |
| 1254 | ch.setLevel(logging.DEBUG) |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 1255 | formatter = logging.Formatter("%(asctime)s - %(name)s: %(levelname)s: %(message)s") |
Chase Qi | 09edc7f | 2016-08-18 13:18:50 +0800 | [diff] [blame] | 1256 | ch.setFormatter(formatter) |
| 1257 | logger.addHandler(ch) |
| 1258 | |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 1259 | logger.debug("Test job arguments: %s" % args) |
Milosz Wasilewski | 682120e | 2017-03-13 13:37:18 +0000 | [diff] [blame] | 1260 | if args.kind != "manual" and args.target is None: |
Milosz Wasilewski | 2fea70e | 2016-11-11 12:16:09 +0000 | [diff] [blame] | 1261 | if os.geteuid() != 0: |
| 1262 | logger.error("Sorry, you need to run this as root") |
| 1263 | sys.exit(1) |
Chase Qi | 09edc7f | 2016-08-18 13:18:50 +0800 | [diff] [blame] | 1264 | |
Milosz Wasilewski | 682120e | 2017-03-13 13:37:18 +0000 | [diff] [blame] | 1265 | # Validate target argument format and connectivity. |
| 1266 | if args.target: |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 1267 | rex = re.compile(".+@.+") |
Milosz Wasilewski | 682120e | 2017-03-13 13:37:18 +0000 | [diff] [blame] | 1268 | if not rex.match(args.target): |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 1269 | logger.error("Usage: -g username@host") |
Milosz Wasilewski | 682120e | 2017-03-13 13:37:18 +0000 | [diff] [blame] | 1270 | sys.exit(1) |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 1271 | if pexpect.which("ssh") is None: |
| 1272 | logger.error("openssh client must be installed on the host.") |
Milosz Wasilewski | 682120e | 2017-03-13 13:37:18 +0000 | [diff] [blame] | 1273 | sys.exit(1) |
| 1274 | try: |
Dan Rue | a9eb01c | 2017-06-07 16:29:09 -0500 | [diff] [blame] | 1275 | run_command("exit", args.target) |
Milosz Wasilewski | 682120e | 2017-03-13 13:37:18 +0000 | [diff] [blame] | 1276 | except subprocess.CalledProcessError as e: |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 1277 | logger.error("ssh login failed.") |
Milosz Wasilewski | 682120e | 2017-03-13 13:37:18 +0000 | [diff] [blame] | 1278 | print(e) |
| 1279 | sys.exit(1) |
| 1280 | |
Chase Qi | 09edc7f | 2016-08-18 13:18:50 +0800 | [diff] [blame] | 1281 | # Generate test plan. |
Chase Qi | 09edc7f | 2016-08-18 13:18:50 +0800 | [diff] [blame] | 1282 | test_plan = TestPlan(args) |
Milosz Wasilewski | 2fea70e | 2016-11-11 12:16:09 +0000 | [diff] [blame] | 1283 | test_list = test_plan.test_list(args.kind) |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 1284 | logger.info("Tests to run:") |
Chase Qi | 09edc7f | 2016-08-18 13:18:50 +0800 | [diff] [blame] | 1285 | for test in test_list: |
| 1286 | print(test) |
| 1287 | |
| 1288 | # Run tests. |
| 1289 | for test in test_list: |
Milosz Wasilewski | 682120e | 2017-03-13 13:37:18 +0000 | [diff] [blame] | 1290 | # Set and save test params to test dictionary. |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 1291 | 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 Wasilewski | 682120e | 2017-03-13 13:37:18 +0000 | [diff] [blame] | 1297 | if args.target is not None: |
Chase Qi | 204b542 | 2017-04-06 11:01:58 +0800 | [diff] [blame] | 1298 | # 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 Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 1300 | tc_realpath = os.path.realpath(test["path"]) |
Chase Qi | 204b542 | 2017-04-06 11:01:58 +0800 | [diff] [blame] | 1301 | tc_dirname = os.path.dirname(tc_realpath) |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 1302 | test["tc_relative_dir"] = "%s%s" % ( |
| 1303 | args.kind, |
| 1304 | tc_dirname.split(args.kind)[1], |
| 1305 | ) |
Dan Rue | a9eb01c | 2017-06-07 16:29:09 -0500 | [diff] [blame] | 1306 | target_user_home = run_command("echo $HOME", args.target) |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 1307 | test["target_test_path"] = "%s/output/%s" % ( |
| 1308 | target_user_home, |
| 1309 | test["test_uuid"], |
| 1310 | ) |
| 1311 | logger.debug("Test parameters: %s" % test) |
Milosz Wasilewski | 682120e | 2017-03-13 13:37:18 +0000 | [diff] [blame] | 1312 | |
Chase Qi | 09edc7f | 2016-08-18 13:18:50 +0800 | [diff] [blame] | 1313 | # Create directories and copy files needed. |
| 1314 | setup = TestSetup(test, args) |
| 1315 | setup.create_dir() |
| 1316 | setup.copy_test_repo() |
Milosz Wasilewski | 970431b | 2016-11-25 14:10:08 +0000 | [diff] [blame] | 1317 | setup.checkout_version() |
Chase Qi | 09edc7f | 2016-08-18 13:18:50 +0800 | [diff] [blame] | 1318 | setup.create_uuid_file() |
| 1319 | |
| 1320 | # Convert test definition. |
| 1321 | test_def = TestDefinition(test, args) |
Milosz Wasilewski | 2fea70e | 2016-11-11 12:16:09 +0000 | [diff] [blame] | 1322 | if test_def.exists: |
| 1323 | test_def.definition() |
| 1324 | test_def.metadata() |
Nicolas Dechesne | 51b85a8 | 2017-02-04 00:45:48 +0100 | [diff] [blame] | 1325 | test_def.mkrun() |
Chase Qi | 09edc7f | 2016-08-18 13:18:50 +0800 | [diff] [blame] | 1326 | |
Milosz Wasilewski | 2fea70e | 2016-11-11 12:16:09 +0000 | [diff] [blame] | 1327 | # Run test. |
Nicolas Dechesne | 51b85a8 | 2017-02-04 00:45:48 +0100 | [diff] [blame] | 1328 | test_def.run() |
Chase Qi | 09edc7f | 2016-08-18 13:18:50 +0800 | [diff] [blame] | 1329 | |
Milosz Wasilewski | 2fea70e | 2016-11-11 12:16:09 +0000 | [diff] [blame] | 1330 | # Parse test output, save results in json and csv format. |
| 1331 | result_parser = ResultParser(test, args) |
| 1332 | result_parser.run() |
| 1333 | else: |
Benjamin Copeland | 15d743e | 2021-02-22 08:35:10 +0000 | [diff] [blame^] | 1334 | logger.warning("Requested test definition %s doesn't exist" % test["path"]) |
Chase Qi | 09edc7f | 2016-08-18 13:18:50 +0800 | [diff] [blame] | 1335 | |
Dan Rue | a9eb01c | 2017-06-07 16:29:09 -0500 | [diff] [blame] | 1336 | |
Chase Qi | 09edc7f | 2016-08-18 13:18:50 +0800 | [diff] [blame] | 1337 | if __name__ == "__main__": |
| 1338 | main() |