at 23.05-pre 4.1 kB view raw
1from pathlib import Path 2import argparse 3import ptpython.repl 4import os 5import time 6 7from test_driver.logger import rootlog 8from test_driver.driver import Driver 9 10 11class EnvDefault(argparse.Action): 12 """An argpars Action that takes values from the specified 13 environment variable as the flags default value. 14 """ 15 16 def __init__(self, envvar, required=False, default=None, nargs=None, **kwargs): # type: ignore 17 if not default and envvar: 18 if envvar in os.environ: 19 if nargs is not None and (nargs.isdigit() or nargs in ["*", "+"]): 20 default = os.environ[envvar].split() 21 else: 22 default = os.environ[envvar] 23 kwargs["help"] = ( 24 kwargs["help"] + f" (default from environment: {default})" 25 ) 26 if required and default: 27 required = False 28 super(EnvDefault, self).__init__( 29 default=default, required=required, nargs=nargs, **kwargs 30 ) 31 32 def __call__(self, parser, namespace, values, option_string=None): # type: ignore 33 setattr(namespace, self.dest, values) 34 35 36def writeable_dir(arg: str) -> Path: 37 """Raises an ArgumentTypeError if the given argument isn't a writeable directory 38 Note: We want to fail as early as possible if a directory isn't writeable, 39 since an executed nixos-test could fail (very late) because of the test-driver 40 writing in a directory without proper permissions. 41 """ 42 path = Path(arg) 43 if not path.is_dir(): 44 raise argparse.ArgumentTypeError("{0} is not a directory".format(path)) 45 if not os.access(path, os.W_OK): 46 raise argparse.ArgumentTypeError( 47 "{0} is not a writeable directory".format(path) 48 ) 49 return path 50 51 52def main() -> None: 53 arg_parser = argparse.ArgumentParser(prog="nixos-test-driver") 54 arg_parser.add_argument( 55 "-K", 56 "--keep-vm-state", 57 help="re-use a VM state coming from a previous run", 58 action="store_true", 59 ) 60 arg_parser.add_argument( 61 "-I", 62 "--interactive", 63 help="drop into a python repl and run the tests interactively", 64 action=argparse.BooleanOptionalAction, 65 ) 66 arg_parser.add_argument( 67 "--start-scripts", 68 metavar="START-SCRIPT", 69 action=EnvDefault, 70 envvar="startScripts", 71 nargs="*", 72 help="start scripts for participating virtual machines", 73 ) 74 arg_parser.add_argument( 75 "--vlans", 76 metavar="VLAN", 77 action=EnvDefault, 78 envvar="vlans", 79 nargs="*", 80 help="vlans to span by the driver", 81 ) 82 arg_parser.add_argument( 83 "-o", 84 "--output_directory", 85 help="""The path to the directory where outputs copied from the VM will be placed. 86 By e.g. Machine.copy_from_vm or Machine.screenshot""", 87 default=Path.cwd(), 88 type=writeable_dir, 89 ) 90 arg_parser.add_argument( 91 "testscript", 92 action=EnvDefault, 93 envvar="testScript", 94 help="the test script to run", 95 type=Path, 96 ) 97 98 args = arg_parser.parse_args() 99 100 if not args.keep_vm_state: 101 rootlog.info("Machine state will be reset. To keep it, pass --keep-vm-state") 102 103 with Driver( 104 args.start_scripts, 105 args.vlans, 106 args.testscript.read_text(), 107 args.output_directory.resolve(), 108 args.keep_vm_state, 109 ) as driver: 110 if args.interactive: 111 ptpython.repl.embed(driver.test_symbols(), {}) 112 else: 113 tic = time.time() 114 driver.run_tests() 115 toc = time.time() 116 rootlog.info(f"test script finished in {(toc-tic):.2f}s") 117 118 119def generate_driver_symbols() -> None: 120 """ 121 This generates a file with symbols of the test-driver code that can be used 122 in user's test scripts. That list is then used by pyflakes to lint those 123 scripts. 124 """ 125 d = Driver([], [], "", Path()) 126 test_symbols = d.test_symbols() 127 with open("driver-symbols", "w") as fp: 128 fp.write(",".join(test_symbols.keys()))