diff --git a/nixos/doc/manual/development/running-nixos-tests-interactively.section.md b/nixos/doc/manual/development/running-nixos-tests-interactively.section.md
index 3ba4e16e77f4..f87298201791 100644
--- a/nixos/doc/manual/development/running-nixos-tests-interactively.section.md
+++ b/nixos/doc/manual/development/running-nixos-tests-interactively.section.md
@@ -5,7 +5,7 @@ when developing or debugging a test:
```ShellSession
$ nix-build nixos/tests/login.nix -A driverInteractive
-$ ./result/bin/nixos-test-driver
+$ ./result/bin/nixos-test-driver --interactive
starting VDE switch for network 1
>
```
@@ -24,20 +24,11 @@ back into the test driver command line upon its completion. This allows
you to inspect the state of the VMs after the test (e.g. to debug the
test script).
-To just start and experiment with the VMs, run:
-
-```ShellSession
-$ nix-build nixos/tests/login.nix -A driverInteractive
-$ ./result/bin/nixos-run-vms
-```
-
-The script `nixos-run-vms` starts the virtual machines defined by test.
-
You can re-use the VM states coming from a previous run by setting the
`--keep-vm-state` flag.
```ShellSession
-$ ./result/bin/nixos-run-vms --keep-vm-state
+$ ./result/bin/nixos-test-driver --interactive --keep-vm-state
```
The machine state is stored in the `$TMPDIR/vm-state-machinename`
diff --git a/nixos/doc/manual/from_md/development/running-nixos-tests-interactively.section.xml b/nixos/doc/manual/from_md/development/running-nixos-tests-interactively.section.xml
index a2030e9c0739..17003cbcbfdc 100644
--- a/nixos/doc/manual/from_md/development/running-nixos-tests-interactively.section.xml
+++ b/nixos/doc/manual/from_md/development/running-nixos-tests-interactively.section.xml
@@ -6,7 +6,7 @@
$ nix-build nixos/tests/login.nix -A driverInteractive
-$ ./result/bin/nixos-test-driver
+$ ./result/bin/nixos-test-driver --interactive
starting VDE switch for network 1
>
@@ -25,23 +25,12 @@ starting VDE switch for network 1
completion. This allows you to inspect the state of the VMs after
the test (e.g. to debug the test script).
-
- To just start and experiment with the VMs, run:
-
-
-$ nix-build nixos/tests/login.nix -A driverInteractive
-$ ./result/bin/nixos-run-vms
-
-
- The script nixos-run-vms starts the virtual
- machines defined by test.
-
You can re-use the VM states coming from a previous run by setting
the --keep-vm-state flag.
-$ ./result/bin/nixos-run-vms --keep-vm-state
+$ ./result/bin/nixos-test-driver --interactive --keep-vm-state
The machine state is stored in the
diff --git a/nixos/lib/test-driver/test-driver.py b/nixos/lib/test-driver/test-driver.py
old mode 100644
new mode 100755
index 2a3e4d94b948..1720e553d733
--- a/nixos/lib/test-driver/test-driver.py
+++ b/nixos/lib/test-driver/test-driver.py
@@ -24,7 +24,6 @@ import sys
import telnetlib
import tempfile
import time
-import traceback
import unicodedata
CHAR_TO_KEY = {
@@ -930,29 +929,16 @@ def join_all() -> None:
machine.wait_for_shutdown()
-def test_script() -> None:
- exec(os.environ["testScript"])
-
-
-def run_tests() -> None:
+def run_tests(interactive: bool = False) -> None:
global machines
- tests = os.environ.get("tests", None)
- if tests is not None:
- with log.nested("running the VM test script"):
- try:
- exec(tests, globals())
- except Exception as e:
- eprint("error: ")
- traceback.print_exc()
- sys.exit(1)
+ if interactive:
+ ptpython.repl.embed(globals(), locals())
else:
- ptpython.repl.embed(locals(), globals())
-
- # TODO: Collect coverage data
-
- for machine in machines:
- if machine.is_up():
- machine.execute("sync")
+ test_script()
+ # TODO: Collect coverage data
+ for machine in machines:
+ if machine.is_up():
+ machine.execute("sync")
def serial_stdout_on() -> None:
@@ -965,6 +951,31 @@ def serial_stdout_off() -> None:
log._print_serial_logs = False
+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
+ super(EnvDefault, self).__init__(
+ default=default, required=required, nargs=nargs, **kwargs
+ )
+
+ def __call__(self, parser, namespace, values, option_string=None): # type: ignore
+ setattr(namespace, self.dest, values)
+
+
@contextmanager
def subtest(name: str) -> Iterator[None]:
with log.nested(name):
@@ -986,18 +997,52 @@ if __name__ == "__main__":
help="re-use a VM state coming from a previous run",
action="store_true",
)
- (cli_args, vm_scripts) = arg_parser.parse_known_args()
+ arg_parser.add_argument(
+ "-I",
+ "--interactive",
+ help="drop into a python repl and run the tests interactively",
+ action="store_true",
+ )
+ 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",
+ )
+ arg_parser.add_argument(
+ "testscript",
+ action=EnvDefault,
+ envvar="testScript",
+ help="the test script to run",
+ type=pathlib.Path,
+ )
+
+ args = arg_parser.parse_args()
+ global test_script
+
+ def test_script() -> None:
+ with log.nested("running the VM test script"):
+ exec(pathlib.Path(args.testscript).read_text(), globals())
log = Logger()
- vlan_nrs = list(dict.fromkeys(os.environ.get("VLANS", "").split()))
- vde_sockets = [create_vlan(v) for v in vlan_nrs]
+ vde_sockets = [create_vlan(v) for v in args.vlans]
for nr, vde_socket, _, _ in vde_sockets:
os.environ["QEMU_VDE_SOCKET_{}".format(nr)] = vde_socket
machines = [
- create_machine({"startCommand": s, "keepVmState": cli_args.keep_vm_state})
- for s in vm_scripts
+ create_machine({"startCommand": s, "keepVmState": args.keep_vm_state})
+ for s in args.start_scripts
]
machine_eval = [
"{0} = machines[{1}]".format(m.name, idx) for idx, m in enumerate(machines)
@@ -1017,6 +1062,6 @@ if __name__ == "__main__":
log.close()
tic = time.time()
- run_tests()
+ run_tests(args.interactive)
toc = time.time()
print("test script finished in {:.2f}s".format(toc - tic))
diff --git a/nixos/lib/testing-python.nix b/nixos/lib/testing-python.nix
index 768f1dc2a170..87a30f7f8b72 100644
--- a/nixos/lib/testing-python.nix
+++ b/nixos/lib/testing-python.nix
@@ -83,7 +83,10 @@ rec {
''
mkdir -p $out
- LOGFILE=/dev/null tests='exec(os.environ["testScript"])' ${driver}/bin/nixos-test-driver
+ # effectively mute the XMLLogger
+ export LOGFILE=/dev/null
+
+ ${driver}/bin/nixos-test-driver
'';
passthru = driver.passthru // {
@@ -161,7 +164,10 @@ rec {
''
mkdir -p $out/bin
+ vmStartScripts=($(for i in ${toString vms}; do echo $i/bin/run-*-vm; done))
echo -n "$testScript" > $out/test-script
+ ln -s ${testDriver}/bin/nixos-test-driver $out/bin/nixos-test-driver
+
${lib.optionalString (!skipLint) ''
PYFLAKES_BUILTINS="$(
echo -n ${lib.escapeShellArg (lib.concatStringsSep "," nodeHostNames)},
@@ -169,17 +175,12 @@ rec {
)" ${python3Packages.pyflakes}/bin/pyflakes $out/test-script
''}
- ln -s ${testDriver}/bin/nixos-test-driver $out/bin/
- vms=($(for i in ${toString vms}; do echo $i/bin/run-*-vm; done))
+ # set defaults through environment
+ # see: ./test-driver/test-driver.py argparse implementation
wrapProgram $out/bin/nixos-test-driver \
- --add-flags "''${vms[*]}" \
- --run "export testScript=\"\$(${coreutils}/bin/cat $out/test-script)\"" \
- --set VLANS '${toString vlans}'
- ln -s ${testDriver}/bin/nixos-test-driver $out/bin/nixos-run-vms
- wrapProgram $out/bin/nixos-run-vms \
- --add-flags "''${vms[*]}" \
- --set tests 'start_all(); join_all();' \
- --set VLANS '${toString vlans}'
+ --set startScripts "''${vmStartScripts[*]}" \
+ --set testScript "$out/test-script" \
+ --set vlans '${toString vlans}'
'');
# Make a full-blown test