···2526## Testing changes to the test framework {#sec-test-the-test-framework}
270028When making significant changes to the test framework, we run the tests on Hydra, to avoid disrupting the larger NixOS project.
2930For this, we use the `python-test-refactoring` branch in the `NixOS/nixpkgs` repository, and its [corresponding Hydra jobset](https://hydra.nixos.org/jobset/nixos/python-test-refactoring).
···2526## Testing changes to the test framework {#sec-test-the-test-framework}
2728+We currently have limited unit tests for the framework itself. You may run these with `nix-build -A nixosTests.nixos-test-driver`.
29+30When making significant changes to the test framework, we run the tests on Hydra, to avoid disrupting the larger NixOS project.
3132For this, we use the `python-test-refactoring` branch in the `NixOS/nixpkgs` repository, and its [corresponding Hydra jobset](https://hydra.nixos.org/jobset/nixos/python-test-refactoring).
···130start_all()
131```
13200000133## Machine objects {#ssec-machine-objects}
134135The following methods are available on machine objects:
···130start_all()
131```
132133+If the hostname of a node contains characters that can't be used in a
134+Python variable name, those characters will be replaced with
135+underscores in the variable name, so `nodes.machine-a` will be exposed
136+to Python as `machine_a`.
137+138## Machine objects {#ssec-machine-objects}
139140The following methods are available on machine objects:
+6-1
nixos/lib/test-driver/test_driver/driver.py
···2from pathlib import Path
3from typing import Any, Dict, Iterator, List, Union, Optional, Callable, ContextManager
4import os
05import tempfile
67from test_driver.logger import rootlog
···26 f"The directory defined by TMPDIR, TEMP, TMP, or CWD: {tmp_dir} is not writeable"
27 )
28 return tmp_dir
0000293031class Driver:
···113 polling_condition=self.polling_condition,
114 Machine=Machine, # for typing
115 )
116- machine_symbols = {m.name: m for m in self.machines}
117 # If there's exactly one machine, make it available under the name
118 # "machine", even if it's not called that.
119 if len(self.machines) == 1:
···2from pathlib import Path
3from typing import Any, Dict, Iterator, List, Union, Optional, Callable, ContextManager
4import os
5+import re
6import tempfile
78from test_driver.logger import rootlog
···27 f"The directory defined by TMPDIR, TEMP, TMP, or CWD: {tmp_dir} is not writeable"
28 )
29 return tmp_dir
30+31+32+def pythonize_name(name: str) -> str:
33+ return re.sub(r"^[^A-z_]|[^A-z0-9_]", "_", name)
343536class Driver:
···118 polling_condition=self.polling_condition,
119 Machine=Machine, # for typing
120 )
121+ machine_symbols = {pythonize_name(m.name): m for m in self.machines}
122 # If there's exactly one machine, make it available under the name
123 # "machine", even if it's not called that.
124 if len(self.machines) == 1:
+11-20
nixos/lib/testing/driver.nix
···21 in
22 nodesList ++ lib.optional (lib.length nodesList == 1 && !lib.elem "machine" nodesList) "machine";
2324- # TODO: This is an implementation error and needs fixing
25- # the testing famework cannot legitimately restrict hostnames further
26- # beyond RFC1035
27- invalidNodeNames = lib.filter
28- (node: builtins.match "^[A-z_]([A-z0-9_]+)?$" node == null)
29- nodeHostNames;
03031 uniqueVlans = lib.unique (builtins.concatLists vlans);
32 vlanNames = map (i: "vlan${toString i}: VLan;") uniqueVlans;
33- machineNames = map (name: "${name}: Machine;") nodeHostNames;
03435- withChecks =
36- if lib.length invalidNodeNames > 0 then
37- throw ''
38- Cannot create machines out of (${lib.concatStringsSep ", " invalidNodeNames})!
39- All machines are referenced as python variables in the testing framework which will break the
40- script when special characters are used.
41-42- This is an IMPLEMENTATION ERROR and needs to be fixed. Meanwhile,
43- please stick to alphanumeric chars and underscores as separation.
44- ''
45- else
46- lib.warnIf config.skipLint "Linting is disabled";
4748 driver =
49 hostPkgs.runCommand "nixos-test-driver-${config.name}"
···87 ${testDriver}/bin/generate-driver-symbols
88 ${lib.optionalString (!config.skipLint) ''
89 PYFLAKES_BUILTINS="$(
90- echo -n ${lib.escapeShellArg (lib.concatStringsSep "," nodeHostNames)},
91 < ${lib.escapeShellArg "driver-symbols"}
92 )" ${hostPkgs.python3Packages.pyflakes}/bin/pyflakes $out/test-script
93 ''}
···1+{
2+ name = "nixos-test-driver.node-name";
3+ nodes = {
4+ "ok" = { };
5+6+ # Valid node name, but not a great host name.
7+ "one_two" = { };
8+9+ # Valid node name, good host name
10+ "a-b" = { };
11+12+ # TODO: would be nice to test these eval failures
13+ # Not allowed by lib/testing/network.nix (yet?)
14+ # "foo.bar" = { };
15+ # Not allowed.
16+ # "not ok" = { }; # not ok
17+ };
18+19+ testScript = ''
20+ start_all()
21+22+ with subtest("python vars exist and machines are reachable through test backdoor"):
23+ ok.succeed("true")
24+ one_two.succeed("true")
25+ a_b.succeed("true")
26+27+ with subtest("hostname is derived from the node name"):
28+ ok.succeed("hostname | tee /dev/stderr | grep '^ok$'")
29+ one_two.succeed("hostname | tee /dev/stderr | grep '^onetwo$'")
30+ a_b.succeed("hostname | tee /dev/stderr | grep '^a-b$'")
31+32+ '';
33+}
···28 "--with-long-double-128"
29 "--with-long-double-format=${gcc.long-double-format or "ieee"}"
30 ]))
031]
···28 "--with-long-double-128"
29 "--with-long-double-format=${gcc.long-double-format or "ieee"}"
30 ]))
31+ (lib.optional targetPlatform.isMips64n32 "--disable-libsanitizer") # libsanitizer does not compile on mips64n32
32]
···89stdenv.mkDerivation rec {
10 pname = "openfortivpn";
11- version = "1.20.1";
1213 src = fetchFromGitHub {
14 owner = "adrienverge";
15 repo = pname;
16 rev = "v${version}";
17- sha256 = "sha256-xsH/Nb1/69R2EvAisDnrHWehjDIMBmElCV6evuTwBIQ=";
18 };
1920 # we cannot write the config file to /etc and as we don't need the file, so drop it
···89stdenv.mkDerivation rec {
10 pname = "openfortivpn";
11+ version = "1.20.2";
1213 src = fetchFromGitHub {
14 owner = "adrienverge";
15 repo = pname;
16 rev = "v${version}";
17+ sha256 = "sha256-Ml1aVvF+kqlSTuzZeHG8Ry+BA24YdWACwQNlO2K+FGo=";
18 };
1920 # we cannot write the config file to /etc and as we don't need the file, so drop it