Merge pull request #164660 from ncfavier/tests-restrict-arguments

nixos/testing: restrict arguments to makeTest

+3 -2
lib/default.nix
···
bitNot boolToString mergeAttrs flip mapNullable inNixShell isFloat min max
importJSON importTOML warn warnIf throwIfNot checkListOfEnum
info showWarnings nixpkgsVersion version isInOldestRelease
-
mod compare splitByAndCompare functionArgs setFunctionArgs isFunction
toHexString toBaseDigits;
inherit (self.fixedPoints) fix fix' converge extends composeExtensions
composeManyExtensions makeExtensible makeExtensibleWithCustomName;
···
commitIdFromGitRepo cleanSourceWith pathHasContext
canCleanSource pathIsRegularFile pathIsGitRepo;
inherit (self.modules) evalModules setDefaultModuleLocation
-
unifyModuleSyntax applyIfFunction mergeModules
mergeModules' mergeOptionDecls evalOptionValue mergeDefinitions
pushDownProperties dischargeProperties filterOverrides
sortProperties fixupOptionType mkIf mkAssert mkMerge mkOverride
···
bitNot boolToString mergeAttrs flip mapNullable inNixShell isFloat min max
importJSON importTOML warn warnIf throwIfNot checkListOfEnum
info showWarnings nixpkgsVersion version isInOldestRelease
+
mod compare splitByAndCompare
+
functionArgs setFunctionArgs isFunction toFunction
toHexString toBaseDigits;
inherit (self.fixedPoints) fix fix' converge extends composeExtensions
composeManyExtensions makeExtensible makeExtensibleWithCustomName;
···
commitIdFromGitRepo cleanSourceWith pathHasContext
canCleanSource pathIsRegularFile pathIsGitRepo;
inherit (self.modules) evalModules setDefaultModuleLocation
+
unifyModuleSyntax applyModuleArgsIfFunction mergeModules
mergeModules' mergeOptionDecls evalOptionValue mergeDefinitions
pushDownProperties dischargeProperties filterOverrides
sortProperties fixupOptionType mkIf mkAssert mkMerge mkOverride
+3 -3
lib/modules.nix
···
# Like unifyModuleSyntax, but also imports paths and calls functions if necessary
loadModule = args: fallbackFile: fallbackKey: m:
if isFunction m || isAttrs m then
-
unifyModuleSyntax fallbackFile fallbackKey (applyIfFunction fallbackKey m args)
else if isList m then
let defs = [{ file = fallbackFile; value = m; }]; in
throw "Module imports can't be nested lists. Perhaps you meant to remove one level of lists? Definitions: ${showDefs defs}"
-
else unifyModuleSyntax (toString m) (toString m) (applyIfFunction (toString m) (import m) args);
/*
Collects all modules recursively into the form
···
config = addFreeformType (addMeta (removeAttrs m ["_file" "key" "disabledModules" "require" "imports" "freeformType"]));
};
-
applyIfFunction = key: f: args@{ config, options, lib, ... }: if isFunction f then
let
# Module arguments are resolved in a strict manner when attribute set
# deconstruction is used. As the arguments are now defined with the
···
# Like unifyModuleSyntax, but also imports paths and calls functions if necessary
loadModule = args: fallbackFile: fallbackKey: m:
if isFunction m || isAttrs m then
+
unifyModuleSyntax fallbackFile fallbackKey (applyModuleArgsIfFunction fallbackKey m args)
else if isList m then
let defs = [{ file = fallbackFile; value = m; }]; in
throw "Module imports can't be nested lists. Perhaps you meant to remove one level of lists? Definitions: ${showDefs defs}"
+
else unifyModuleSyntax (toString m) (toString m) (applyModuleArgsIfFunction (toString m) (import m) args);
/*
Collects all modules recursively into the form
···
config = addFreeformType (addMeta (removeAttrs m ["_file" "key" "disabledModules" "require" "imports" "freeformType"]));
};
+
applyModuleArgsIfFunction = key: f: args@{ config, options, lib, ... }: if isFunction f then
let
# Module arguments are resolved in a strict manner when attribute set
# deconstruction is used. As the arguments are now defined with the
+19
lib/trivial.nix
···
isFunction = f: builtins.isFunction f ||
(f ? __functor && isFunction (f.__functor f));
/* Convert the given positive integer to a string of its hexadecimal
representation. For example:
···
isFunction = f: builtins.isFunction f ||
(f ? __functor && isFunction (f.__functor f));
+
/*
+
Turns any non-callable values into constant functions.
+
Returns callable values as is.
+
+
Example:
+
+
nix-repl> lib.toFunction 1 2
+
1
+
+
nix-repl> lib.toFunction (x: x + 1) 2
+
3
+
*/
+
toFunction =
+
# Any value
+
v:
+
if isFunction v
+
then v
+
else k: v;
+
/* Convert the given positive integer to a string of its hexadecimal
representation. For example:
+14 -16
nixos/lib/testing-python.nix
···
# Make a full-blown test
makeTest =
-
{ testScript
, enableOCR ? false
, name ? "unnamed"
# Skip linting (mainly intended for faster dev cycles)
, skipLint ? false
, passthru ? {}
, # For meta.position
pos ? # position used in error messages and for meta.position
-
(if t.meta.description or null != null
-
then builtins.unsafeGetAttrPos "description" t.meta
else builtins.unsafeGetAttrPos "testScript" t)
-
, ...
} @ t:
let
-
nodes = qemu_pkg:
let
testScript' =
# Call the test script with the computed nodes.
if lib.isFunction testScript
-
then testScript { nodes = nodes qemu_pkg; }
else testScript;
build-vms = import ./build-vms.nix {
···
};
in
build-vms.buildVirtualNetwork (
-
t.nodes or (if t ? machine then { machine = t.machine; } else { })
);
driver = setupDriverForTest {
inherit testScript enableOCR skipLint passthru;
testName = name;
qemu_pkg = pkgs.qemu_test;
-
nodes = nodes pkgs.qemu_test;
};
driverInteractive = setupDriverForTest {
inherit testScript enableOCR skipLint passthru;
testName = name;
qemu_pkg = pkgs.qemu;
-
nodes = nodes pkgs.qemu;
interactive = true;
};
-
test =
-
let
-
passMeta = drv: drv // lib.optionalAttrs (t ? meta) {
-
meta = (drv.meta or { }) // t.meta;
-
};
-
in passMeta (runTests { inherit driver pos driverInteractive; });
in
test // {
-
inherit test driver driverInteractive nodes;
};
abortForFunction = functionName: abort ''The ${functionName} function was
···
# Make a full-blown test
makeTest =
+
{ machine ? null
+
, nodes ? {}
+
, testScript
, enableOCR ? false
, name ? "unnamed"
# Skip linting (mainly intended for faster dev cycles)
, skipLint ? false
, passthru ? {}
+
, meta ? {}
, # For meta.position
pos ? # position used in error messages and for meta.position
+
(if meta.description or null != null
+
then builtins.unsafeGetAttrPos "description" meta
else builtins.unsafeGetAttrPos "testScript" t)
} @ t:
let
+
mkNodes = qemu_pkg:
let
testScript' =
# Call the test script with the computed nodes.
if lib.isFunction testScript
+
then testScript { nodes = mkNodes qemu_pkg; }
else testScript;
build-vms = import ./build-vms.nix {
···
};
in
build-vms.buildVirtualNetwork (
+
nodes // lib.optionalAttrs (machine != null) { inherit machine; }
);
driver = setupDriverForTest {
inherit testScript enableOCR skipLint passthru;
testName = name;
qemu_pkg = pkgs.qemu_test;
+
nodes = mkNodes pkgs.qemu_test;
};
driverInteractive = setupDriverForTest {
inherit testScript enableOCR skipLint passthru;
testName = name;
qemu_pkg = pkgs.qemu;
+
nodes = mkNodes pkgs.qemu;
interactive = true;
};
+
test = lib.addMetaAttrs meta (runTests { inherit driver pos driverInteractive; });
in
test // {
+
inherit test driver driverInteractive;
+
inherit (driver) nodes;
};
abortForFunction = functionName: abort ''The ${functionName} function was
+1 -1
nixos/modules/installer/tools/tools.nix
···
'';
};
-
config = lib.mkIf (!config.system.disableInstallerTools) {
system.nixos-generate-config.configuration = mkDefault ''
# Edit this configuration file to define what should be installed on
···
'';
};
+
config = lib.mkIf (config.nix.enable && !config.system.disableInstallerTools) {
system.nixos-generate-config.configuration = mkDefault ''
# Edit this configuration file to define what should be installed on
+7 -1
nixos/modules/services/misc/nix-gc.nix
···
###### implementation
config = {
-
systemd.services.nix-gc = {
description = "Nix Garbage Collector";
script = "exec ${config.nix.package.out}/bin/nix-collect-garbage ${cfg.options}";
startAt = optional cfg.automatic cfg.dates;
···
###### implementation
config = {
+
assertions = [
+
{
+
assertion = cfg.automatic -> config.nix.enable;
+
message = ''nix.gc.automatic requires nix.enable'';
+
}
+
];
+
systemd.services.nix-gc = lib.mkIf config.nix.enable {
description = "Nix Garbage Collector";
script = "exec ${config.nix.package.out}/bin/nix-collect-garbage ${cfg.options}";
startAt = optional cfg.automatic cfg.dates;
+7 -1
nixos/modules/services/misc/nix-optimise.nix
···
###### implementation
config = {
-
systemd.services.nix-optimise =
{ description = "Nix Store Optimiser";
# No point this if the nix daemon (and thus the nix store) is outside
unitConfig.ConditionPathIsReadWrite = "/nix/var/nix/daemon-socket";
···
###### implementation
config = {
+
assertions = [
+
{
+
assertion = cfg.automatic -> config.nix.enable;
+
message = ''nix.optimise.automatic requires nix.enable'';
+
}
+
];
+
systemd.services.nix-optimise = lib.mkIf config.nix.enable
{ description = "Nix Store Optimiser";
# No point this if the nix daemon (and thus the nix store) is outside
unitConfig.ConditionPathIsReadWrite = "/nix/var/nix/daemon-socket";
+1 -1
nixos/modules/virtualisation/qemu-vm.nix
···
# allow `system.build.toplevel' to be included. (If we had a direct
# reference to ${regInfo} here, then we would get a cyclic
# dependency.)
-
boot.postBootCommands =
''
if [[ "$(cat /proc/cmdline)" =~ regInfo=([^ ]*) ]]; then
${config.nix.package.out}/bin/nix-store --load-db < ''${BASH_REMATCH[1]}
···
# allow `system.build.toplevel' to be included. (If we had a direct
# reference to ${regInfo} here, then we would get a cyclic
# dependency.)
+
boot.postBootCommands = lib.mkIf config.nix.enable
''
if [[ "$(cat /proc/cmdline)" =~ regInfo=([^ ]*) ]]; then
${config.nix.package.out}/bin/nix-store --load-db < ''${BASH_REMATCH[1]}
-1
nixos/tests/boot.nix
···
} // extraConfig);
in
makeTest {
-
inherit iso;
name = "boot-" + name;
nodes = { };
testScript =
···
} // extraConfig);
in
makeTest {
name = "boot-" + name;
nodes = { };
testScript =
+3 -3
nixos/tests/caddy.nix
···
nodes = {
webserver = { pkgs, lib, ... }: {
services.caddy.enable = true;
-
services.caddy.config = ''
http://localhost {
encode gzip
···
'';
specialisation.etag.configuration = {
-
services.caddy.config = lib.mkForce ''
http://localhost {
encode gzip
···
};
specialisation.config-reload.configuration = {
-
services.caddy.config = ''
http://localhost:8080 {
}
'';
···
nodes = {
webserver = { pkgs, lib, ... }: {
services.caddy.enable = true;
+
services.caddy.extraConfig = ''
http://localhost {
encode gzip
···
'';
specialisation.etag.configuration = {
+
services.caddy.extraConfig = lib.mkForce ''
http://localhost {
encode gzip
···
};
specialisation.config-reload.configuration = {
+
services.caddy.extraConfig = ''
http://localhost:8080 {
}
'';
+1 -1
nixos/tests/ceph-multi-node.nix
···
sudo
ceph
xfsprogs
-
netcat-openbsd
];
boot.kernelModules = [ "xfs" ];
···
sudo
ceph
xfsprogs
+
libressl.nc
];
boot.kernelModules = [ "xfs" ];
+20 -18
nixos/tests/chromium.nix
···
with import ../lib/testing-python.nix { inherit system pkgs; };
with pkgs.lib;
-
mapAttrs (channel: chromiumPkg: makeTest rec {
-
name = "chromium-${channel}";
-
meta = {
-
maintainers = with maintainers; [ aszlig primeos ];
-
# https://github.com/NixOS/hydra/issues/591#issuecomment-435125621
-
inherit (chromiumPkg.meta) timeout;
-
};
-
-
enableOCR = true;
-
user = "alice";
-
-
machine.imports = [ ./common/user-account.nix ./common/x11.nix ];
-
machine.virtualisation.memorySize = 2047;
-
machine.test-support.displayManager.auto.user = user;
-
machine.environment = {
-
systemPackages = [ chromiumPkg ];
-
variables."XAUTHORITY" = "/home/alice/.Xauthority";
-
};
startupHTML = pkgs.writeText "chromium-startup.html" ''
<!DOCTYPE html>
···
</body>
</html>
'';
testScript = let
xdo = name: text: let
···
with import ../lib/testing-python.nix { inherit system pkgs; };
with pkgs.lib;
+
let
user = "alice";
startupHTML = pkgs.writeText "chromium-startup.html" ''
<!DOCTYPE html>
···
</body>
</html>
'';
+
in
+
+
mapAttrs (channel: chromiumPkg: makeTest {
+
name = "chromium-${channel}";
+
meta = {
+
maintainers = with maintainers; [ aszlig primeos ];
+
# https://github.com/NixOS/hydra/issues/591#issuecomment-435125621
+
inherit (chromiumPkg.meta) timeout;
+
};
+
+
enableOCR = true;
+
+
machine.imports = [ ./common/user-account.nix ./common/x11.nix ];
+
machine.virtualisation.memorySize = 2047;
+
machine.test-support.displayManager.auto.user = user;
+
machine.environment = {
+
systemPackages = [ chromiumPkg ];
+
variables."XAUTHORITY" = "/home/alice/.Xauthority";
+
};
testScript = let
xdo = name: text: let
+1 -1
nixos/tests/cri-o.nix
···
# This test runs CRI-O and verifies via critest
import ./make-test-python.nix ({ pkgs, ... }: {
name = "cri-o";
-
maintainers = with pkgs.lib.maintainers; teams.podman.members;
nodes = {
crio = {
···
# This test runs CRI-O and verifies via critest
import ./make-test-python.nix ({ pkgs, ... }: {
name = "cri-o";
+
meta.maintainers = with pkgs.lib.maintainers; teams.podman.members;
nodes = {
crio = {
+1 -1
nixos/tests/gitolite-fcgiwrap.nix
···
nodes = {
server =
-
{ ... }:
{
networking.firewall.allowedTCPPorts = [ 80 ];
···
nodes = {
server =
+
{ config, ... }:
{
networking.firewall.allowedTCPPorts = [ 80 ];
+2 -2
nixos/tests/jitsi-meet.nix
···
forceSSL = true;
};
-
security.acme.email = "me@example.org";
security.acme.acceptTerms = true;
-
security.acme.server = "https://example.com"; # self-signed only
};
};
···
forceSSL = true;
};
security.acme.acceptTerms = true;
+
security.acme.defaults.email = "me@example.org";
+
security.acme.defaults.server = "https://example.com"; # self-signed only
};
};
+3 -3
nixos/tests/misc.nix
···
# Miscellaneous small tests that don't warrant their own VM run.
-
import ./make-test-python.nix ({ pkgs, ...} : rec {
name = "misc";
meta = with pkgs.lib.maintainers; {
maintainers = [ eelco ];
};
-
-
foo = pkgs.writeText "foo" "Hello World";
machine =
{ lib, ... }:
···
# Miscellaneous small tests that don't warrant their own VM run.
+
import ./make-test-python.nix ({ pkgs, ...} : let
+
foo = pkgs.writeText "foo" "Hello World";
+
in {
name = "misc";
meta = with pkgs.lib.maintainers; {
maintainers = [ eelco ];
};
machine =
{ lib, ... }:
-6
nixos/tests/rstudio-server.nix
···
};
};
-
users.testuser = {
-
uid = 1000;
-
group = "testgroup";
-
};
-
groups.testgroup.gid = 1000;
-
testScript = ''
machine.wait_for_unit("rstudio-server.service")
machine.succeed("curl -f -vvv -s http://127.0.0.1:8787")
···
};
};
testScript = ''
machine.wait_for_unit("rstudio-server.service")
machine.succeed("curl -f -vvv -s http://127.0.0.1:8787")
+2 -2
nixos/tests/step-ca.nix
···
caclient =
{ config, pkgs, ... }: {
-
security.acme.server = "https://caserver:8443/acme/acme/directory";
-
security.acme.email = "root@example.org";
security.acme.acceptTerms = true;
security.pki.certificateFiles = [ "${test-certificates}/root_ca.crt" ];
···
caclient =
{ config, pkgs, ... }: {
+
security.acme.defaults.server = "https://caserver:8443/acme/acme/directory";
+
security.acme.defaults.email = "root@example.org";
security.acme.acceptTerms = true;
security.pki.certificateFiles = [ "${test-certificates}/root_ca.crt" ];
+10 -15
nixos/tests/tor.nix
···
import ./make-test-python.nix ({ lib, ... }: with lib;
-
rec {
name = "tor";
meta.maintainers = with maintainers; [ joachifm ];
-
common =
-
{ ... }:
-
{ boot.kernelParams = [ "audit=0" "apparmor=0" "quiet" ];
-
networking.firewall.enable = false;
-
networking.useDHCP = false;
-
};
-
nodes.client =
-
{ pkgs, ... }:
-
{ imports = [ common ];
-
environment.systemPackages = with pkgs; [ netcat ];
-
services.tor.enable = true;
-
services.tor.client.enable = true;
-
services.tor.settings.ControlPort = 9051;
-
};
testScript = ''
client.wait_for_unit("tor.service")
···
import ./make-test-python.nix ({ lib, ... }: with lib;
+
{
name = "tor";
meta.maintainers = with maintainers; [ joachifm ];
+
nodes.client = { pkgs, ... }: {
+
boot.kernelParams = [ "audit=0" "apparmor=0" "quiet" ];
+
networking.firewall.enable = false;
+
networking.useDHCP = false;
+
environment.systemPackages = with pkgs; [ netcat ];
+
services.tor.enable = true;
+
services.tor.client.enable = true;
+
services.tor.settings.ControlPort = 9051;
+
};
testScript = ''
client.wait_for_unit("tor.service")
+15 -6
nixos/tests/without-nix.nix
···
maintainers = [ ericson2314 ];
};
-
nixpkgs.overlays = [
-
(self: super: {
-
nix = throw "don't want to use this";
-
})
-
];
-
nodes.machine = { ... }: {
nix.enable = false;
};
testScript = ''
···
maintainers = [ ericson2314 ];
};
nodes.machine = { ... }: {
nix.enable = false;
+
nixpkgs.overlays = [
+
(self: super: {
+
nix = throw "don't want to use pkgs.nix";
+
nixVersions = lib.mapAttrs (k: throw "don't want to use pkgs.nixVersions.${k}") super.nixVersions;
+
# aliases, some deprecated
+
nix_2_3 = throw "don't want to use pkgs.nix_2_3";
+
nix_2_4 = throw "don't want to use pkgs.nix_2_4";
+
nix_2_5 = throw "don't want to use pkgs.nix_2_5";
+
nix_2_6 = throw "don't want to use pkgs.nix_2_6";
+
nixFlakes = throw "don't want to use pkgs.nixFlakes";
+
nixStable = throw "don't want to use pkgs.nixStable";
+
nixUnstable = throw "don't want to use pkgs.nixUnstable";
+
nixStatic = throw "don't want to use pkgs.nixStatic";
+
})
+
];
};
testScript = ''
+3 -3
pkgs/test/nixos-functions/default.nix
···
fileSystems."/".device = "/dev/null";
}).toplevel;
-
nixosTest-test = pkgs.nixosTest ({ lib, pkgs, ... }: {
name = "nixosTest-test";
machine = { pkgs, ... }: {
system.nixos = dummyVersioning;
-
environment.systemPackages = [ pkgs.hello ];
};
testScript = ''
-
machine.succeed("hello")
'';
});
···
fileSystems."/".device = "/dev/null";
}).toplevel;
+
nixosTest-test = pkgs.nixosTest ({ lib, pkgs, figlet, ... }: {
name = "nixosTest-test";
machine = { pkgs, ... }: {
system.nixos = dummyVersioning;
+
environment.systemPackages = [ pkgs.hello figlet ];
};
testScript = ''
+
machine.succeed("hello | figlet >/dev/console")
'';
});
+1 -3
pkgs/top-level/all-packages.nix
···
loadedTest = if builtins.typeOf test == "path"
then import test
else test;
-
calledTest = if lib.isFunction loadedTest
-
then callPackage loadedTest {}
-
else loadedTest;
in
nixosTesting.makeTest calledTest;
···
loadedTest = if builtins.typeOf test == "path"
then import test
else test;
+
calledTest = lib.toFunction loadedTest pkgs;
in
nixosTesting.makeTest calledTest;