Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

nixos/tests: follow-up to the closure reduction PR #101598

Merged
merged 5 commits into from
Oct 26, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
266 changes: 146 additions & 120 deletions nixos/lib/testing-python.nix
Original file line number Diff line number Diff line change
Expand Up @@ -3,56 +3,55 @@
# Use a minimal kernel?
, minimal ? false
# Ignored
, config ? {}
, config ? { }
# !!! See comment about args in lib/modules.nix
, specialArgs ? {}
, specialArgs ? { }
# Modules to add to each VM
, extraConfigurations ? [] }:
, extraConfigurations ? [ ]
}:

with import ./build-vms.nix { inherit system pkgs minimal specialArgs extraConfigurations; };
with pkgs;

rec {

inherit pkgs;


mkTestDriver = let
testDriverScript = ./test-driver/test-driver.py;
in qemu_pkg: stdenv.mkDerivation {
name = "nixos-test-driver";

nativeBuildInputs = [ makeWrapper ];
buildInputs = [ (python3.withPackages (p: [ p.ptpython ])) ];
checkInputs = with python3Packages; [ pylint black mypy ];

dontUnpack = true;
mkTestDriver =
let
testDriverScript = ./test-driver/test-driver.py;
in
qemu_pkg: stdenv.mkDerivation {
name = "nixos-test-driver";

preferLocalBuild = true;
nativeBuildInputs = [ makeWrapper ];
buildInputs = [ (python3.withPackages (p: [ p.ptpython ])) ];
checkInputs = with python3Packages; [ pylint black mypy ];

doCheck = true;
checkPhase = ''
mypy --disallow-untyped-defs \
--no-implicit-optional \
--ignore-missing-imports ${testDriverScript}
pylint --errors-only ${testDriverScript}
black --check --diff ${testDriverScript}
'';
dontUnpack = true;

installPhase =
''
mkdir -p $out/bin
cp ${testDriverScript} $out/bin/nixos-test-driver
chmod u+x $out/bin/nixos-test-driver
# TODO: copy user script part into this file (append)
preferLocalBuild = true;

wrapProgram $out/bin/nixos-test-driver \
--prefix PATH : "${lib.makeBinPath [ qemu_pkg vde2 netpbm coreutils ]}" \
doCheck = true;
checkPhase = ''
mypy --disallow-untyped-defs \
--no-implicit-optional \
--ignore-missing-imports ${testDriverScript}
pylint --errors-only ${testDriverScript}
black --check --diff ${testDriverScript}
'';
};

testDriver = mkTestDriver qemu_test;
testDriverInteractive = mkTestDriver qemu_kvm;
installPhase =
''
mkdir -p $out/bin
cp ${testDriverScript} $out/bin/nixos-test-driver
chmod u+x $out/bin/nixos-test-driver
# TODO: copy user script part into this file (append)

wrapProgram $out/bin/nixos-test-driver \
--prefix PATH : "${lib.makeBinPath [ qemu_pkg vde2 netpbm coreutils ]}" \
'';
};

# Run an automated test suite in the given virtual network.
# `driver' is the script that runs the network.
Expand All @@ -75,11 +74,10 @@ rec {
{ testScript
, enableOCR ? false
, name ? "unnamed"
# Skip linting (mainly intended for faster dev cycles)
# Skip linting (mainly intended for faster dev cycles)
, skipLint ? false
, ...
} @ t:

let
# A standard store path to the vm monitor is built like this:
# /tmp/nix-build-vm-test-run-$name.drv-0/vm-state-machine/monitor
Expand All @@ -88,25 +86,7 @@ rec {
maxTestNameLen = 50;
testNameLen = builtins.stringLength name;

testDriverName = with builtins;
if testNameLen > maxTestNameLen then
abort ("The name of the test '${name}' must not be longer than ${toString maxTestNameLen} " +
"it's currently ${toString testNameLen} characters long.")
else
"nixos-test-driver-${name}";

nodes = buildVirtualNetwork (
t.nodes or (if t ? machine then { machine = t.machine; } else { }));

testScript' =
# Call the test script with the computed nodes.
if lib.isFunction testScript
then testScript { inherit nodes; }
else testScript;

vlans = map (m: m.config.virtualisation.vlans) (lib.attrValues nodes);

vms = map (m: m.config.system.build.vm) (lib.attrValues nodes);

ocrProg = tesseract4.override { enableLanguages = [ "eng" ]; };

Expand All @@ -115,78 +95,124 @@ rec {
# Generate convenience wrappers for running the test driver
# interactively with the specified network, and for starting the
# VMs from the command line.
driver = testDriver:
mkDriver = qemu_pkg:
let
build-vms = import ./build-vms.nix {
inherit system pkgs minimal specialArgs;
extraConfigurations = extraConfigurations ++ (pkgs.lib.optional (qemu_pkg != null)
{
virtualisation.qemu.package = qemu_pkg;
}
);
};

# FIXME: get this pkg from the module system
testDriver = mkTestDriver (if qemu_pkg == null then pkgs.qemu_test else qemu_pkg);

nodes = build-vms.buildVirtualNetwork (
t.nodes or (if t ? machine then { machine = t.machine; } else { })
);
vlans = map (m: m.config.virtualisation.vlans) (lib.attrValues nodes);
vms = map (m: m.config.system.build.vm) (lib.attrValues nodes);

testScript' =
# Call the test script with the computed nodes.
if lib.isFunction testScript
then testScript { inherit nodes; }
else testScript;

testDriverName = with builtins;
if testNameLen > maxTestNameLen then
abort
("The name of the test '${name}' must not be longer than ${toString maxTestNameLen} " +
"it's currently ${toString testNameLen} characters long.")
else
"nixos-test-driver-${name}";

warn = if skipLint then lib.warn "Linting is disabled!" else lib.id;
in
warn (runCommand testDriverName
{ buildInputs = [ makeWrapper];
testScript = testScript';
preferLocalBuild = true;
testName = name;
}
''
mkdir -p $out/bin

echo -n "$testScript" > $out/test-script
${lib.optionalString (!skipLint) ''
${python3Packages.black}/bin/black --check --diff $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))
wrapProgram $out/bin/nixos-test-driver \
--add-flags "''${vms[*]}" \
${lib.optionalString enableOCR
"--prefix PATH : '${ocrProg}/bin:${imagemagick_tiff}/bin'"} \
--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[*]}" \
${lib.optionalString enableOCR "--prefix PATH : '${ocrProg}/bin'"} \
--set tests 'start_all(); join_all();' \
--set VLANS '${toString vlans}' \
${lib.optionalString (builtins.length vms == 1) "--set USE_SERIAL 1"}
''); # "
{
buildInputs = [ makeWrapper ];
testScript = testScript';
preferLocalBuild = true;
testName = name;
passthru = {
inherit nodes;
};
}
''
mkdir -p $out/bin

echo -n "$testScript" > $out/test-script
${lib.optionalString (!skipLint) ''
${python3Packages.black}/bin/black --check --diff $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))
wrapProgram $out/bin/nixos-test-driver \
--add-flags "''${vms[*]}" \
${lib.optionalString enableOCR
"--prefix PATH : '${ocrProg}/bin:${imagemagick_tiff}/bin'"} \
--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[*]}" \
${lib.optionalString enableOCR "--prefix PATH : '${ocrProg}/bin'"} \
--set tests 'start_all(); join_all();' \
--set VLANS '${toString vlans}' \
${lib.optionalString (builtins.length vms == 1) "--set USE_SERIAL 1"}
''); # "

passMeta = drv: drv // lib.optionalAttrs (t ? meta) {
meta = (drv.meta or {}) // t.meta;
meta = (drv.meta or { }) // t.meta;
};

test = passMeta (runTests (driver testDriver));
driver = mkDriver null;
driverInteractive = mkDriver pkgs.qemu;

nodeNames = builtins.attrNames nodes;
test = passMeta (runTests driver);

nodeNames = builtins.attrNames driver.nodes;
invalidNodeNames = lib.filter
(node: builtins.match "^[A-z_]([A-z0-9_]+)?$" node == null) nodeNames;
(node: builtins.match "^[A-z_]([A-z0-9_]+)?$" node == null)
nodeNames;

in
if lib.length invalidNodeNames > 0 then
throw ''
Cannot create machines out of (${lib.concatStringsSep ", " invalidNodeNames})!
All machines are referenced as python variables in the testing framework which will break the
script when special characters are used.
if lib.length invalidNodeNames > 0 then
throw ''
Cannot create machines out of (${lib.concatStringsSep ", " invalidNodeNames})!
All machines are referenced as python variables in the testing framework which will break the
script when special characters are used.

Please stick to alphanumeric chars and underscores as separation.
''
else
test // {
inherit nodes test;
driver = driver testDriver;
driverInteractive = driver testDriverInteractive;
};
Please stick to alphanumeric chars and underscores as separation.
''
else
test // {
inherit test driver driverInteractive;
inherit (test) nodes;
};

runInMachine =
{ drv
, machine
, preBuild ? ""
, postBuild ? ""
, qemu ? pkgs.qemu_test
, ... # ???
}:
let
vm = buildVM { }
[ machine
{ key = "run-in-machine";
build-vms = import ./build-vms.nix {
inherit system pkgs minimal specialArgs extraConfigurations;
};

vm = build-vms.buildVM { }
[
machine
{
key = "run-in-machine";
networking.hostName = "client";
nix.readOnlyStore = false;
virtualisation.writableStore = false;
Expand Down Expand Up @@ -229,20 +255,20 @@ rec {
unset xchg

export tests='${testScript}'
${testDriver}/bin/nixos-test-driver ${vm.config.system.build.vm}/bin/run-*-vm
${mkTestDriver qemu}/bin/nixos-test-driver --keep-vm-state ${vm.config.system.build.vm}/bin/run-*-vm
andir marked this conversation as resolved.
Show resolved Hide resolved
''; # */

in
lib.overrideDerivation drv (attrs: {
requiredSystemFeatures = [ "kvm" ];
builder = "${bash}/bin/sh";
args = ["-e" vmRunCommand];
origArgs = attrs.args;
origBuilder = attrs.builder;
});
lib.overrideDerivation drv (attrs: {
requiredSystemFeatures = [ "kvm" ];
builder = "${bash}/bin/sh";
args = [ "-e" vmRunCommand ];
origArgs = attrs.args;
origBuilder = attrs.builder;
});


runInMachineWithX = { require ? [], ... } @ args:
runInMachineWithX = { require ? [ ], ... } @ args:
let
client =
{ ... }:
Expand All @@ -258,13 +284,13 @@ rec {
services.xserver.windowManager.icewm.enable = true;
};
in
runInMachine ({
machine = client;
preBuild =
''
client.wait_for_x()
'';
} // args);
runInMachine ({
machine = client;
preBuild =
''
client.wait_for_x()
'';
} // args);


simpleTest = as: (makeTest as).test;
Expand Down
9 changes: 2 additions & 7 deletions nixos/modules/installer/tools/nixos-build-vms/build-vms.nix
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,7 @@
let
nodes = builtins.mapAttrs (vm: module: {
_file = "${networkExpr}@node-${vm}";
imports = [
module
({ pkgs, ... }: {
virtualisation.qemu.package = pkgs.qemu;
})
];
imports = [ module ];
}) (import networkExpr);
in

Expand All @@ -20,4 +15,4 @@ with import ../../../../lib/testing-python.nix {
pkgs = import ../../../../.. { inherit system config; };
};

(makeTest { inherit nodes; testScript = ""; }).driver
(makeTest { inherit nodes; testScript = ""; }).driverInteractive