b.liu | e958203 | 2025-04-17 19:18:16 +0800 | [diff] [blame^] | 1 | #!/usr/bin/env python3 |
| 2 | # |
| 3 | # Remote test case executor |
| 4 | # Copyright (c) 2016, Tieto Corporation |
| 5 | # |
| 6 | # This software may be distributed under the terms of the BSD license. |
| 7 | # See README for more details. |
| 8 | |
| 9 | import os |
| 10 | import re |
| 11 | import sys |
| 12 | import time |
| 13 | import traceback |
| 14 | import getopt |
| 15 | from datetime import datetime |
| 16 | from random import shuffle |
| 17 | |
| 18 | import logging |
| 19 | logger = logging.getLogger() |
| 20 | |
| 21 | scriptsdir = os.path.dirname(os.path.realpath(sys.modules[__name__].__file__)) |
| 22 | sys.path.append(os.path.join(scriptsdir, '..', '..', 'wpaspy')) |
| 23 | sys.path.append(os.path.join(scriptsdir, '..', 'hwsim')) |
| 24 | |
| 25 | import wpaspy |
| 26 | import config |
| 27 | from test_devices import show_devices |
| 28 | from test_devices import check_devices |
| 29 | from rutils import TestSkip |
| 30 | from utils import HwsimSkip |
| 31 | from hwsim_wrapper import run_hwsim_test |
| 32 | |
| 33 | def usage(): |
| 34 | print("USAGE: " + sys.argv[0] + " -t devices") |
| 35 | print("USAGE: " + sys.argv[0] + " -t check_devices") |
| 36 | print("USAGE: " + sys.argv[0] + " -d <dut_name> -t <all|sanity|tests_to_run> [-r <ref_name>] [-c <cfg_file.py>] [-m <all|monitor_name>] [-h hwsim_tests] [-f hwsim_modules][-R][-T][-P][-S][-v]") |
| 37 | print("USAGE: " + sys.argv[0]) |
| 38 | |
| 39 | def get_devices(devices, duts, refs, monitors): |
| 40 | for dut in duts: |
| 41 | config.get_device(devices, dut, lock=True) |
| 42 | for ref in refs: |
| 43 | config.get_device(devices, ref, lock=True) |
| 44 | for monitor in monitors: |
| 45 | if monitor == "all": |
| 46 | continue |
| 47 | if monitor in duts: |
| 48 | continue |
| 49 | if monitor in refs: |
| 50 | continue |
| 51 | config.get_device(devices, monitor, lock=True) |
| 52 | |
| 53 | def put_devices(devices, duts, refs, monitors): |
| 54 | for dut in duts: |
| 55 | config.put_device(devices, dut) |
| 56 | for ref in refs: |
| 57 | config.put_device(devices, ref) |
| 58 | for monitor in monitors: |
| 59 | if monitor == "all": |
| 60 | continue |
| 61 | if monitor in duts: |
| 62 | continue |
| 63 | if monitor in refs: |
| 64 | continue |
| 65 | config.put_device(devices, monitor) |
| 66 | |
| 67 | def main(): |
| 68 | duts = [] |
| 69 | refs = [] |
| 70 | monitors = [] |
| 71 | filter_keys = [] |
| 72 | requested_tests = ["help"] |
| 73 | requested_hwsim_tests = [] |
| 74 | hwsim_tests = [] |
| 75 | requested_modules = [] |
| 76 | modules_tests = [] |
| 77 | cfg_file = "cfg.py" |
| 78 | log_dir = "./logs/" |
| 79 | verbose = False |
| 80 | trace = False |
| 81 | restart = False |
| 82 | perf = False |
| 83 | shuffle_tests = False |
| 84 | |
| 85 | # parse input parameters |
| 86 | try: |
| 87 | opts, args = getopt.getopt(sys.argv[1:], "d:f:r:t:l:k:c:m:h:vRPTS", |
| 88 | ["dut=", "modules=", "ref=", "tests=", |
| 89 | "log-dir=", |
| 90 | "cfg=", "key=", "monitor=", "hwsim="]) |
| 91 | except getopt.GetoptError as err: |
| 92 | print(err) |
| 93 | usage() |
| 94 | sys.exit(2) |
| 95 | |
| 96 | for option, argument in opts: |
| 97 | if option == "-v": |
| 98 | verbose = True |
| 99 | elif option == "-R": |
| 100 | restart = True |
| 101 | elif option == "-T": |
| 102 | trace = True |
| 103 | elif option == "-P": |
| 104 | perf = True |
| 105 | elif option == "-S": |
| 106 | shuffle_tests = True |
| 107 | elif option in ("-d", "--dut"): |
| 108 | duts.append(argument) |
| 109 | elif option in ("-r", "--ref"): |
| 110 | refs.append(argument) |
| 111 | elif option in ("-t", "--tests"): |
| 112 | requested_tests = re.split('; | |, ', argument) |
| 113 | elif option in ("-l", "--log-dir"): |
| 114 | log_dir = argument |
| 115 | elif option in ("-k", "--key"): |
| 116 | filter_keys.append(argument) |
| 117 | elif option in ("-m", "--monitor"): |
| 118 | monitors.append(argument) |
| 119 | elif option in ("-c", "--cfg"): |
| 120 | cfg_file = argument |
| 121 | elif option in ("-h", "--hwsim"): |
| 122 | requested_hwsim_tests = re.split('; | |, ', argument) |
| 123 | elif option in ("-f", "--modules"): |
| 124 | requested_modules = re.split('; | |, ', argument) |
| 125 | else: |
| 126 | assert False, "unhandled option" |
| 127 | |
| 128 | # get env configuration |
| 129 | setup_params = config.get_setup_params(cfg_file) |
| 130 | devices = config.get_devices(cfg_file) |
| 131 | |
| 132 | # put logs in log_dir |
| 133 | symlink = os.path.join(log_dir, "current"); |
| 134 | if os.path.exists(symlink): |
| 135 | os.unlink(symlink) |
| 136 | log_dir = os.path.join(log_dir, time.strftime("%Y_%m_%d_%H_%M_%S")) |
| 137 | if not os.path.exists(log_dir): |
| 138 | os.makedirs(log_dir) |
| 139 | os.symlink(os.path.join("../", log_dir), symlink) |
| 140 | |
| 141 | # setup restart/trace/perf request |
| 142 | setup_params['local_log_dir'] = log_dir |
| 143 | setup_params['restart_device'] = restart |
| 144 | setup_params['trace'] = trace |
| 145 | setup_params['perf'] = perf |
| 146 | |
| 147 | # configure logger |
| 148 | logger.setLevel(logging.DEBUG) |
| 149 | |
| 150 | stdout_handler = logging.StreamHandler() |
| 151 | stdout_handler.setLevel(logging.WARNING) |
| 152 | if verbose: |
| 153 | stdout_handler.setLevel(logging.DEBUG) |
| 154 | logger.addHandler(stdout_handler) |
| 155 | |
| 156 | formatter = logging.Formatter('%(asctime)s - %(message)s') |
| 157 | file_name = os.path.join(log_dir, 'run-tests.log') |
| 158 | log_handler = logging.FileHandler(file_name) |
| 159 | log_handler.setLevel(logging.DEBUG) |
| 160 | log_handler.setFormatter(formatter) |
| 161 | logger.addHandler(log_handler) |
| 162 | |
| 163 | # import available tests |
| 164 | tests = [] |
| 165 | failed = [] |
| 166 | test_modules = [] |
| 167 | files = os.listdir(scriptsdir) |
| 168 | for t in files: |
| 169 | m = re.match(r'(test_.*)\.py$', t) |
| 170 | if m: |
| 171 | mod = __import__(m.group(1)) |
| 172 | test_modules.append(mod.__name__.replace('test_', '', 1)) |
| 173 | for key, val in mod.__dict__.items(): |
| 174 | if key.startswith("test_"): |
| 175 | tests.append(val) |
| 176 | test_names = list(set([t.__name__.replace('test_', '', 1) for t in tests])) |
| 177 | |
| 178 | # import test_* |
| 179 | files = os.listdir("../hwsim/") |
| 180 | for t in files: |
| 181 | m = re.match(r'(test_.*)\.py$', t) |
| 182 | if m: |
| 183 | mod = __import__(m.group(1)) |
| 184 | test_modules.append(mod.__name__.replace('test_', '', 1)) |
| 185 | for key, val in mod.__dict__.items(): |
| 186 | if key.startswith("test_"): |
| 187 | hwsim_tests.append(val) |
| 188 | |
| 189 | # setup hwsim tests |
| 190 | hwsim_tests_to_run = [] |
| 191 | if len(requested_hwsim_tests) > 0: |
| 192 | # apply filters |
| 193 | for filter_key in filter_keys: |
| 194 | filtered_tests = [] |
| 195 | for hwsim_test in hwsim_tests: |
| 196 | if re.search(filter_key, hwsim_test.__name__): |
| 197 | filtered_tests.append(hwsim_test) |
| 198 | hwsim_tests = filtered_tests |
| 199 | |
| 200 | # setup hwsim_test we should run |
| 201 | if requested_hwsim_tests[0] == "all": |
| 202 | hwsim_tests_to_run = hwsim_tests |
| 203 | elif requested_hwsim_tests[0] == "remote": |
| 204 | hwsim_tests_to_run = [t for t in hwsim_tests |
| 205 | if hasattr(t, "remote_compatible") and |
| 206 | t.remote_compatible] |
| 207 | else: |
| 208 | for test in requested_hwsim_tests: |
| 209 | t = None |
| 210 | for tt in hwsim_tests: |
| 211 | name = tt.__name__.replace('test_', '', 1) |
| 212 | if name == test: |
| 213 | t = tt |
| 214 | break |
| 215 | if not t: |
| 216 | logger.warning("hwsim test case: " + test + " NOT-FOUND") |
| 217 | continue |
| 218 | hwsim_tests_to_run.append(t) |
| 219 | |
| 220 | # import test_* from modules |
| 221 | files = os.listdir("../hwsim/") |
| 222 | for t in files: |
| 223 | m = re.match(r'(test_.*)\.py$', t) |
| 224 | if m: |
| 225 | mod = __import__(m.group(1)) |
| 226 | if mod.__name__.replace('test_', '', 1) not in requested_modules: |
| 227 | continue |
| 228 | for key, val in mod.__dict__.items(): |
| 229 | if key.startswith("test_"): |
| 230 | modules_tests.append(val) |
| 231 | |
| 232 | if len(requested_modules) > 0: |
| 233 | requested_hwsim_tests = modules_tests |
| 234 | hwsim_tests_to_run = modules_tests |
| 235 | |
| 236 | # sort the list |
| 237 | test_names.sort() |
| 238 | tests.sort(key=lambda t: t.__name__) |
| 239 | |
| 240 | # print help |
| 241 | if requested_tests[0] == "help" and len(requested_hwsim_tests) == 0: |
| 242 | usage() |
| 243 | print("\nAvailable Devices:") |
| 244 | for device in devices: |
| 245 | print("\t", device['name']) |
| 246 | print("\nAvailable tests:") |
| 247 | for test in test_names: |
| 248 | print("\t", test) |
| 249 | print("\nAvailable hwsim tests:") |
| 250 | for hwsim_test in hwsim_tests: |
| 251 | print("\t", hwsim_test.__name__.replace('test_', '', 1)) |
| 252 | return |
| 253 | |
| 254 | # show/check devices |
| 255 | if requested_tests[0] == "devices": |
| 256 | show_devices(devices, setup_params) |
| 257 | return |
| 258 | |
| 259 | # apply filters |
| 260 | for filter_key in filter_keys: |
| 261 | filtered_tests = [] |
| 262 | for test in tests: |
| 263 | if re.search(filter_key, test.__name__): |
| 264 | filtered_tests.append(test) |
| 265 | tests = filtered_tests |
| 266 | |
| 267 | # setup test we should run |
| 268 | tests_to_run = [] |
| 269 | if requested_tests[0] == "all": |
| 270 | tests_to_run = tests |
| 271 | if requested_tests[0] == "help": |
| 272 | pass |
| 273 | elif requested_tests[0] == "sanity": |
| 274 | for test in tests: |
| 275 | if test.__name__.startswith("test_sanity_"): |
| 276 | tests_to_run.append(test) |
| 277 | else: |
| 278 | for test in requested_tests: |
| 279 | t = None |
| 280 | for tt in tests: |
| 281 | name = tt.__name__.replace('test_', '', 1) |
| 282 | if name == test: |
| 283 | t = tt |
| 284 | break |
| 285 | if not t: |
| 286 | logger.warning("test case: " + test + " NOT-FOUND") |
| 287 | continue |
| 288 | tests_to_run.append(t) |
| 289 | |
| 290 | if shuffle_tests: |
| 291 | shuffle(tests_to_run) |
| 292 | shuffle(hwsim_tests_to_run) |
| 293 | |
| 294 | # lock devices |
| 295 | try: |
| 296 | get_devices(devices, duts, refs, monitors) |
| 297 | except Exception as e: |
| 298 | logger.warning("get devices failed: " + str(e)) |
| 299 | logger.info(traceback.format_exc()) |
| 300 | put_devices(devices, duts, refs, monitors) |
| 301 | return |
| 302 | except: |
| 303 | logger.warning("get devices failed") |
| 304 | logger.info(traceback.format_exc()) |
| 305 | put_devices(devices, duts, refs, monitors) |
| 306 | return |
| 307 | |
| 308 | # now run test cases |
| 309 | for dut in duts: |
| 310 | if len(requested_hwsim_tests) > 0: |
| 311 | logger.warning("DUT (apdev): " + str(dut)) |
| 312 | else: |
| 313 | logger.warning("DUT: " + str(dut)) |
| 314 | for ref in refs: |
| 315 | if len(requested_hwsim_tests) > 0: |
| 316 | logger.warning("REF (dev): " + str(ref)) |
| 317 | else: |
| 318 | logger.warning("REF: " + str(ref)) |
| 319 | for monitor in monitors: |
| 320 | logger.warning("MON: " + str(monitor)) |
| 321 | |
| 322 | # run check_devices at beginning |
| 323 | logger.warning("RUN check_devices") |
| 324 | try: |
| 325 | check_devices(devices, setup_params, refs, duts, monitors) |
| 326 | except Exception as e: |
| 327 | logger.warning("FAILED: " + str(e)) |
| 328 | logger.info(traceback.format_exc()) |
| 329 | put_devices(devices, duts, refs, monitors) |
| 330 | return |
| 331 | except: |
| 332 | logger.warning("FAILED") |
| 333 | logger.info(traceback.format_exc()) |
| 334 | put_devices(devices, duts, refs, monitors) |
| 335 | return |
| 336 | logger.warning("PASS") |
| 337 | |
| 338 | test_no = 1 |
| 339 | for test in tests_to_run: |
| 340 | try: |
| 341 | start = datetime.now() |
| 342 | setup_params['tc_name'] = test.__name__.replace('test_', '', 1) |
| 343 | logger.warning("START - " + setup_params['tc_name'] + " (" + str(test_no) + "/" + str(len(tests_to_run)) + ")") |
| 344 | if test.__doc__: |
| 345 | logger.info("Test: " + test.__doc__) |
| 346 | |
| 347 | # run tc |
| 348 | res = test(devices, setup_params, refs, duts, monitors) |
| 349 | |
| 350 | end = datetime.now() |
| 351 | logger.warning("PASS (" + res + ") - " + str((end - start).total_seconds()) + "s") |
| 352 | except KeyboardInterrupt: |
| 353 | put_devices(devices, duts, refs, monitors) |
| 354 | raise |
| 355 | except TestSkip as e: |
| 356 | end = datetime.now() |
| 357 | logger.warning("SKIP (" + str(e) + ") - " + str((end - start).total_seconds()) + "s") |
| 358 | except Exception as e: |
| 359 | end = datetime.now() |
| 360 | logger.warning("FAILED (" + str(e) + ") - " + str((end - start).total_seconds()) + "s") |
| 361 | logger.info(traceback.format_exc()) |
| 362 | failed.append(test.__name__.replace('test_', '', 1)) |
| 363 | except: |
| 364 | end = datetime.now() |
| 365 | logger.warning("FAILED - " + str((end - start).total_seconds()) + "s") |
| 366 | logger.info(traceback.format_exc()) |
| 367 | failed.append(test.__name__.replace('test_', '', 1)) |
| 368 | test_no += 1 |
| 369 | |
| 370 | test_no = 1 |
| 371 | for hwsim_test in hwsim_tests_to_run: |
| 372 | try: |
| 373 | start = datetime.now() |
| 374 | setup_params['tc_name'] = hwsim_test.__name__.replace('test_', '', 1) |
| 375 | logger.warning("START - " + setup_params['tc_name'] + " (" + str(test_no) + "/" + str(len(hwsim_tests_to_run)) + ")") |
| 376 | res = run_hwsim_test(devices, setup_params, refs, duts, monitors, hwsim_test) |
| 377 | end = datetime.now() |
| 378 | logger.warning("PASS (" + res + ") - " + str((end - start).total_seconds()) + "s") |
| 379 | except KeyboardInterrupt: |
| 380 | put_devices(devices, duts, refs, monitors) |
| 381 | raise |
| 382 | except HwsimSkip as e: |
| 383 | end = datetime.now() |
| 384 | logger.warning("SKIP (" + str(e) + ") - " + str((end - start).total_seconds()) + "s") |
| 385 | failed.append(hwsim_test.__name__.replace('test_', '', 1)) |
| 386 | except Exception as e: |
| 387 | end = datetime.now() |
| 388 | logger.warning("FAILED (" + str(e) + ") - " + str((end - start).total_seconds()) + "s") |
| 389 | logger.info(traceback.format_exc()) |
| 390 | failed.append(hwsim_test.__name__.replace('test_', '', 1)) |
| 391 | except: |
| 392 | end = datetime.now() |
| 393 | logger.warning("FAILED - " + str((end - start).total_seconds()) + "s") |
| 394 | logger.info(traceback.format_exc()) |
| 395 | failed.append(hwsim_test.__name__.replace('test_', '', 1)) |
| 396 | test_no += 1 |
| 397 | |
| 398 | # unlock devices |
| 399 | put_devices(devices, duts, refs, monitors) |
| 400 | |
| 401 | if len(failed) > 0: |
| 402 | logger.warning("Failed test cases:") |
| 403 | for test in failed: |
| 404 | logger.warning("\t" + test) |
| 405 | |
| 406 | |
| 407 | if __name__ == "__main__": |
| 408 | main() |