Merge pull request #305886 from wegank/ocaml-jane-street-old-drop
[NixPkgs.git] / nixos / lib / testing / driver.nix
blob7eb06e023918bf0c0239c00f54f5ca2cbf18c70d
1 { config, lib, hostPkgs, ... }:
2 let
3   inherit (lib) mkOption types literalMD;
5   # Reifies and correctly wraps the python test driver for
6   # the respective qemu version and with or without ocr support
7   testDriver = hostPkgs.callPackage ../test-driver {
8     inherit (config) enableOCR extraPythonPackages;
9     qemu_pkg = config.qemu.package;
10     imagemagick_light = hostPkgs.imagemagick_light.override { inherit (hostPkgs) libtiff; };
11     tesseract4 = hostPkgs.tesseract4.override { enableLanguages = [ "eng" ]; };
12   };
15   vlans = map (m: (
16     m.virtualisation.vlans ++
17     (lib.mapAttrsToList (_: v: v.vlan) m.virtualisation.interfaces))) (lib.attrValues config.nodes);
18   vms = map (m: m.system.build.vm) (lib.attrValues config.nodes);
20   nodeHostNames =
21     let
22       nodesList = map (c: c.system.name) (lib.attrValues config.nodes);
23     in
24     nodesList ++ lib.optional (lib.length nodesList == 1 && !lib.elem "machine" nodesList) "machine";
26   pythonizeName = name:
27     let
28       head = lib.substring 0 1 name;
29       tail = lib.substring 1 (-1) name;
30     in
31       (if builtins.match "[A-z_]" head == null then "_" else head) +
32       lib.stringAsChars (c: if builtins.match "[A-z0-9_]" c == null then "_" else c) tail;
34   uniqueVlans = lib.unique (builtins.concatLists vlans);
35   vlanNames = map (i: "vlan${toString i}: VLan;") uniqueVlans;
36   pythonizedNames = map pythonizeName nodeHostNames;
37   machineNames = map (name: "${name}: Machine;") pythonizedNames;
39   withChecks = lib.warnIf config.skipLint "Linting is disabled";
41   driver =
42     hostPkgs.runCommand "nixos-test-driver-${config.name}"
43       {
44         # inherit testName; TODO (roberth): need this?
45         nativeBuildInputs = [
46           hostPkgs.makeWrapper
47         ] ++ lib.optionals (!config.skipTypeCheck) [ hostPkgs.mypy ];
48         buildInputs = [ testDriver ];
49         testScript = config.testScriptString;
50         preferLocalBuild = true;
51         passthru = config.passthru;
52         meta = config.meta // {
53           mainProgram = "nixos-test-driver";
54         };
55       }
56       ''
57         mkdir -p $out/bin
59         vmStartScripts=($(for i in ${toString vms}; do echo $i/bin/run-*-vm; done))
61         ${lib.optionalString (!config.skipTypeCheck) ''
62           # prepend type hints so the test script can be type checked with mypy
63           cat "${../test-script-prepend.py}" >> testScriptWithTypes
64           echo "${builtins.toString machineNames}" >> testScriptWithTypes
65           echo "${builtins.toString vlanNames}" >> testScriptWithTypes
66           echo -n "$testScript" >> testScriptWithTypes
68           echo "Running type check (enable/disable: config.skipTypeCheck)"
69           echo "See https://nixos.org/manual/nixos/stable/#test-opt-skipTypeCheck"
71           mypy  --no-implicit-optional \
72                 --pretty \
73                 --no-color-output \
74                 testScriptWithTypes
75         ''}
77         echo -n "$testScript" >> $out/test-script
79         ln -s ${testDriver}/bin/nixos-test-driver $out/bin/nixos-test-driver
81         ${testDriver}/bin/generate-driver-symbols
82         ${lib.optionalString (!config.skipLint) ''
83           echo "Linting test script (enable/disable: config.skipLint)"
84           echo "See https://nixos.org/manual/nixos/stable/#test-opt-skipLint"
86           PYFLAKES_BUILTINS="$(
87             echo -n ${lib.escapeShellArg (lib.concatStringsSep "," pythonizedNames)},
88             < ${lib.escapeShellArg "driver-symbols"}
89           )" ${hostPkgs.python3Packages.pyflakes}/bin/pyflakes $out/test-script
90         ''}
92         # set defaults through environment
93         # see: ./test-driver/test-driver.py argparse implementation
94         wrapProgram $out/bin/nixos-test-driver \
95           --set startScripts "''${vmStartScripts[*]}" \
96           --set testScript "$out/test-script" \
97           --set globalTimeout "${toString config.globalTimeout}" \
98           --set vlans '${toString vlans}' \
99           ${lib.escapeShellArgs (lib.concatMap (arg: ["--add-flags" arg]) config.extraDriverArgs)}
100       '';
104   options = {
106     driver = mkOption {
107       description = "Package containing a script that runs the test.";
108       type = types.package;
109       defaultText = literalMD "set by the test framework";
110     };
112     hostPkgs = mkOption {
113       description = "Nixpkgs attrset used outside the nodes.";
114       type = types.raw;
115       example = lib.literalExpression ''
116         import nixpkgs { inherit system config overlays; }
117       '';
118     };
120     qemu.package = mkOption {
121       description = "Which qemu package to use for the virtualisation of [{option}`nodes`](#test-opt-nodes).";
122       type = types.package;
123       default = hostPkgs.qemu_test;
124       defaultText = "hostPkgs.qemu_test";
125     };
127     globalTimeout = mkOption {
128       description = ''
129         A global timeout for the complete test, expressed in seconds.
130         Beyond that timeout, every resource will be killed and released and the test will fail.
132         By default, we use a 1 hour timeout.
133       '';
134       type = types.int;
135       default = 60 * 60;
136       example = 10 * 60;
137     };
139     enableOCR = mkOption {
140       description = ''
141         Whether to enable Optical Character Recognition functionality for
142         testing graphical programs. See [Machine objects](`ssec-machine-objects`).
143       '';
144       type = types.bool;
145       default = false;
146     };
148     extraPythonPackages = mkOption {
149       description = ''
150         Python packages to add to the test driver.
152         The argument is a Python package set, similar to `pkgs.pythonPackages`.
153       '';
154       example = lib.literalExpression ''
155         p: [ p.numpy ]
156       '';
157       type = types.functionTo (types.listOf types.package);
158       default = ps: [ ];
159     };
161     extraDriverArgs = mkOption {
162       description = ''
163         Extra arguments to pass to the test driver.
165         They become part of [{option}`driver`](#test-opt-driver) via `wrapProgram`.
166       '';
167       type = types.listOf types.str;
168       default = [];
169     };
171     skipLint = mkOption {
172       type = types.bool;
173       default = false;
174       description = ''
175         Do not run the linters. This may speed up your iteration cycle, but it is not something you should commit.
176       '';
177     };
179     skipTypeCheck = mkOption {
180       type = types.bool;
181       default = false;
182       description = ''
183         Disable type checking. This must not be enabled for new NixOS tests.
185         This may speed up your iteration cycle, unless you're working on the [{option}`testScript`](#test-opt-testScript).
186       '';
187     };
188   };
190   config = {
191     _module.args = {
192       hostPkgs =
193         # Comment is in nixos/modules/misc/nixpkgs.nix
194         lib.mkOverride lib.modules.defaultOverridePriority
195           config.hostPkgs.__splicedPackages;
196     };
198     driver = withChecks driver;
200     # make available on the test runner
201     passthru.driver = config.driver;
202   };