aboutsummaryrefslogtreecommitdiffstats
path: root/pkgs/populate/tests/default.nix
diff options
context:
space:
mode:
Diffstat (limited to 'pkgs/populate/tests/default.nix')
-rw-r--r--pkgs/populate/tests/default.nix135
1 files changed, 135 insertions, 0 deletions
diff --git a/pkgs/populate/tests/default.nix b/pkgs/populate/tests/default.nix
new file mode 100644
index 0000000..7b37bb3
--- /dev/null
+++ b/pkgs/populate/tests/default.nix
@@ -0,0 +1,135 @@
+# NixOS VM tests for populate: one test per source type, one for features
+# spanning sources, one for edge cases of flakes, and one for staying inside
+# the target directory. Each runs the program, with the sources as JSON
+# from populate's Nix library, and target strings, which leave the user and
+# whether the target is local to populate to decide. Build all with
+# nix-build in this directory, or one with, e.g., nix-build -A flake. The
+# exhaustive tests add the combinations of options that no code path tells
+# apart from the ones the others cover; build them with nix-build -A
+# exhaustive, or one with, e.g., nix-build -A exhaustive.flake. The smoke
+# test runs a few scenarios covering each source type and each kind of
+# target in a single VM test, for checking changes quickly; build it with
+# nix-build -A smoke. nix-build -A only --argstr only REGEX runs the
+# scenarios whose names match the regular expression REGEX in a single VM
+# test, e.g. --argstr only 'lock-hooks-.*'.
+{ pkgs ? import <nixpkgs> {}, only ? null }:
+
+let
+ inherit (pkgs) lib;
+
+ populate-unwrapped = pkgs.callPackage ../. {};
+ populateLib = import ../lib { inherit lib; };
+
+ inherit (import ./fixtures.nix) gitHead gitFirst;
+
+ remoteHost = "target";
+
+ # rsync versions the scenarios depending on rsync's version run with.
+ # callPackage adds override and overrideDerivation, which aren't versions.
+ rsyncs = lib.filterAttrs
+ (_: lib.isDerivation)
+ (pkgs.callPackage ./rsync.nix {});
+
+ # A script running populate for a phase, with the tools it runs in front
+ # of PATH, and the sources on a file descriptor of their own, so the
+ # commands populate runs keep standard input. Store paths in the sources
+ # stay dependencies of the script.
+ runWith = rsync: {
+ source, backup, force, prune, deploy, targetKind, targetPath,
+ }:
+ if deploy != null then throw "populate's tests don't deploy" else
+ pkgs.writers.writeDash "populate" /* sh */ ''
+ set -efu
+ PATH=${lib.makeBinPath (with pkgs; [
+ coreutils findutils git nix openssh pass passage rsync
+ ])}''${PATH:+:$PATH}
+ export PATH
+ exec ${populate-unwrapped}/bin/populate ${lib.escapeShellArgs (
+ lib.optional backup "--backup" ++
+ lib.optional force "--force" ++
+ lib.optional prune "--prune" ++
+ [ "/dev/fd/3" ] ++
+ {
+ local = [];
+ remote = [ "root@${remoteHost}" ];
+ sudo = [ "deploy@${remoteHost}" "--sudo" ];
+ }.${targetKind} ++
+ [ "--path" targetPath ]
+ )} 3<<'EOF'
+ ${builtins.toJSON source}
+ EOF
+ '';
+
+ # The scenarios, with populate using rsync.
+ scenariosWith = rsync: import ./scenarios.nix {
+ inherit lib;
+ inherit (populateLib) evalSource;
+ run = runWith rsync;
+ checksDuringEvaluation = false;
+ url = "http://deployer:8000";
+ gitUrl = "git://deployer/gitsrc.git";
+ inherit remoteHost;
+ agePath = "${pkgs.age}/bin/age";
+ inherit gitHead gitFirst;
+ rsyncVersion = rsync.version;
+ };
+ scenarios = scenariosWith pkgs.rsync;
+
+ vm = name: scenarios: rsync: import ./vm.nix {
+ inherit pkgs gitHead scenarios rsync;
+ name = "populate-${name}";
+ };
+
+ # VM tests of those of the groups of scenarios that are, or aren't,
+ # exhaustive, named after the groups with prefix in front.
+ testsOf = exhaustive: prefix: lib.mapAttrs
+ (name: scenarios: vm (prefix + name) scenarios pkgs.rsync)
+ (lib.filterAttrs (_: scenarios: scenarios != [])
+ (builtins.mapAttrs
+ (_: builtins.filter (scenario: scenario.exhaustive == exhaustive))
+ scenarios));
+
+ allScenarios = lib.concatLists (builtins.attrValues scenarios);
+
+ # The scenarios named names, failing if one is missing.
+ named = what: names: let
+ selected = builtins.filter (scenario: builtins.elem scenario.name names) allScenarios;
+ missing = lib.subtractLists (map (scenario: scenario.name) selected) names;
+ in
+ if missing != [] then
+ throw "tests: ${what} names missing scenarios: ${toString missing}"
+ else
+ selected;
+
+ # The scenarios whose names match the regular expression only.
+ onlyScenarios = let
+ selected = builtins.filter
+ (scenario: builtins.match only scenario.name != null)
+ allScenarios;
+ in
+ if only == null then
+ throw "tests: -A only needs --argstr only REGEX"
+ else if selected == [] then
+ throw "tests: no scenario's name matches ${builtins.toJSON only}"
+ else
+ selected;
+in
+ testsOf false ""
+ # Not built by nix-build either, which runs these scenarios anyway.
+ // {
+ smoke.smoke = vm "smoke" (named "smoke test" (import ./smoke.nix)) pkgs.rsync;
+ only.only = vm "only" onlyScenarios pkgs.rsync;
+ }
+ # An attribute set without recurseForDerivations, so nix-build doesn't
+ # build them.
+ // { exhaustive = testsOf true "exhaustive-"; }
+ // lib.mapAttrs'
+ (version: rsync: {
+ name = "rsync-${builtins.replaceStrings [ "." ] [ "-" ] version}";
+ value = vm "rsync-${version}"
+ (builtins.filter
+ (scenario: lib.hasInfix "insecureLinks" scenario.name)
+ (scenariosWith rsync).file)
+ rsync;
+ })
+ rsyncs