2021-12-06 12:49:23 +00:00
|
|
|
import argparse
|
|
|
|
import os
|
|
|
|
import time
|
2023-09-30 08:18:47 +00:00
|
|
|
from pathlib import Path
|
|
|
|
|
|
|
|
import ptpython.repl
|
2021-12-06 12:49:23 +00:00
|
|
|
|
|
|
|
from test_driver.driver import Driver
|
2023-09-30 08:18:47 +00:00
|
|
|
from test_driver.logger import rootlog
|
2021-12-06 12:49:23 +00:00
|
|
|
|
|
|
|
|
|
|
|
class EnvDefault(argparse.Action):
|
|
|
|
"""An argpars Action that takes values from the specified
|
|
|
|
environment variable as the flags default value.
|
|
|
|
"""
|
|
|
|
|
|
|
|
def __init__(self, envvar, required=False, default=None, nargs=None, **kwargs): # type: ignore
|
|
|
|
if not default and envvar:
|
|
|
|
if envvar in os.environ:
|
|
|
|
if nargs is not None and (nargs.isdigit() or nargs in ["*", "+"]):
|
|
|
|
default = os.environ[envvar].split()
|
|
|
|
else:
|
|
|
|
default = os.environ[envvar]
|
|
|
|
kwargs["help"] = (
|
|
|
|
kwargs["help"] + f" (default from environment: {default})"
|
|
|
|
)
|
|
|
|
if required and default:
|
|
|
|
required = False
|
2023-09-30 08:18:47 +00:00
|
|
|
super().__init__(default=default, required=required, nargs=nargs, **kwargs)
|
2021-12-06 12:49:23 +00:00
|
|
|
|
|
|
|
def __call__(self, parser, namespace, values, option_string=None): # type: ignore
|
|
|
|
setattr(namespace, self.dest, values)
|
|
|
|
|
|
|
|
|
2022-01-25 09:21:33 +00:00
|
|
|
def writeable_dir(arg: str) -> Path:
|
|
|
|
"""Raises an ArgumentTypeError if the given argument isn't a writeable directory
|
2022-01-25 00:15:16 +00:00
|
|
|
Note: We want to fail as early as possible if a directory isn't writeable,
|
|
|
|
since an executed nixos-test could fail (very late) because of the test-driver
|
|
|
|
writing in a directory without proper permissions.
|
|
|
|
"""
|
2022-01-25 09:21:33 +00:00
|
|
|
path = Path(arg)
|
2022-01-25 00:15:16 +00:00
|
|
|
if not path.is_dir():
|
2022-12-29 20:47:58 +00:00
|
|
|
raise argparse.ArgumentTypeError(f"{path} is not a directory")
|
2022-01-25 00:15:16 +00:00
|
|
|
if not os.access(path, os.W_OK):
|
2022-12-29 20:47:58 +00:00
|
|
|
raise argparse.ArgumentTypeError(f"{path} is not a writeable directory")
|
2022-01-25 09:21:33 +00:00
|
|
|
return path
|
2022-01-07 14:45:30 +00:00
|
|
|
|
|
|
|
|
2021-12-06 12:49:23 +00:00
|
|
|
def main() -> None:
|
|
|
|
arg_parser = argparse.ArgumentParser(prog="nixos-test-driver")
|
|
|
|
arg_parser.add_argument(
|
|
|
|
"-K",
|
|
|
|
"--keep-vm-state",
|
|
|
|
help="re-use a VM state coming from a previous run",
|
|
|
|
action="store_true",
|
|
|
|
)
|
|
|
|
arg_parser.add_argument(
|
|
|
|
"-I",
|
|
|
|
"--interactive",
|
|
|
|
help="drop into a python repl and run the tests interactively",
|
2022-01-26 10:27:01 +00:00
|
|
|
action=argparse.BooleanOptionalAction,
|
2021-12-06 12:49:23 +00:00
|
|
|
)
|
|
|
|
arg_parser.add_argument(
|
|
|
|
"--start-scripts",
|
|
|
|
metavar="START-SCRIPT",
|
|
|
|
action=EnvDefault,
|
|
|
|
envvar="startScripts",
|
|
|
|
nargs="*",
|
|
|
|
help="start scripts for participating virtual machines",
|
|
|
|
)
|
|
|
|
arg_parser.add_argument(
|
|
|
|
"--vlans",
|
|
|
|
metavar="VLAN",
|
|
|
|
action=EnvDefault,
|
|
|
|
envvar="vlans",
|
|
|
|
nargs="*",
|
|
|
|
help="vlans to span by the driver",
|
|
|
|
)
|
2022-01-07 14:45:30 +00:00
|
|
|
arg_parser.add_argument(
|
2022-01-25 00:15:16 +00:00
|
|
|
"-o",
|
|
|
|
"--output_directory",
|
2022-01-07 14:45:30 +00:00
|
|
|
help="""The path to the directory where outputs copied from the VM will be placed.
|
|
|
|
By e.g. Machine.copy_from_vm or Machine.screenshot""",
|
2022-01-25 00:15:16 +00:00
|
|
|
default=Path.cwd(),
|
2022-01-25 09:21:33 +00:00
|
|
|
type=writeable_dir,
|
2022-01-07 14:45:30 +00:00
|
|
|
)
|
2021-12-06 12:49:23 +00:00
|
|
|
arg_parser.add_argument(
|
|
|
|
"testscript",
|
|
|
|
action=EnvDefault,
|
|
|
|
envvar="testScript",
|
|
|
|
help="the test script to run",
|
|
|
|
type=Path,
|
|
|
|
)
|
|
|
|
|
|
|
|
args = arg_parser.parse_args()
|
|
|
|
|
|
|
|
if not args.keep_vm_state:
|
|
|
|
rootlog.info("Machine state will be reset. To keep it, pass --keep-vm-state")
|
|
|
|
|
|
|
|
with Driver(
|
2022-01-07 14:45:30 +00:00
|
|
|
args.start_scripts,
|
|
|
|
args.vlans,
|
|
|
|
args.testscript.read_text(),
|
2022-01-25 00:15:16 +00:00
|
|
|
args.output_directory.resolve(),
|
2022-01-07 14:45:30 +00:00
|
|
|
args.keep_vm_state,
|
2021-12-06 12:49:23 +00:00
|
|
|
) as driver:
|
|
|
|
if args.interactive:
|
2023-07-27 11:57:52 +00:00
|
|
|
history_dir = os.getcwd()
|
|
|
|
history_path = os.path.join(history_dir, ".nixos-test-history")
|
|
|
|
ptpython.repl.embed(
|
|
|
|
driver.test_symbols(),
|
|
|
|
{},
|
|
|
|
history_filename=history_path,
|
|
|
|
)
|
2021-12-06 12:49:23 +00:00
|
|
|
else:
|
|
|
|
tic = time.time()
|
|
|
|
driver.run_tests()
|
|
|
|
toc = time.time()
|
|
|
|
rootlog.info(f"test script finished in {(toc-tic):.2f}s")
|
|
|
|
|
|
|
|
|
|
|
|
def generate_driver_symbols() -> None:
|
|
|
|
"""
|
|
|
|
This generates a file with symbols of the test-driver code that can be used
|
|
|
|
in user's test scripts. That list is then used by pyflakes to lint those
|
|
|
|
scripts.
|
|
|
|
"""
|
2022-01-07 14:45:30 +00:00
|
|
|
d = Driver([], [], "", Path())
|
2021-12-06 12:49:23 +00:00
|
|
|
test_symbols = d.test_symbols()
|
|
|
|
with open("driver-symbols", "w") as fp:
|
|
|
|
fp.write(",".join(test_symbols.keys()))
|