aboutsummaryrefslogtreecommitdiffstats
path: root/tests/default.nix
blob: 475ab5dd6da9d5028754c77930bcb4b80e293f99 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# NixOS VM tests for krops, with the VM machinery and the scenarios of
# populate's tests, in ../pkgs/populate/tests: deploy, for writeDeploy's
# arguments to nixos-rebuild, and populate, for pkgs.populate, running
# populate's scenarios that expect populate to refuse its arguments, which
# pkgs.populate does during evaluation here, and the scenarios of
# populate's smoke test, with target attribute sets as mkTarget returns
# them.  Build all with nix-build tests, or one with, e.g., nix-build tests
# -A deploy.  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 tests -A exhaustive.  The smoke test runs a few scenarios of
# each in a single VM test; build it with nix-build tests -A smoke.
# nix-build tests -A only --argstr only REGEX runs the scenarios whose
# names match the regular expression REGEX, of all of populate's scenarios
# and krops' own, in a single VM test, e.g. --argstr only 'lock-hooks-.*'.
# populate's own tests run the program directly; see
# ../pkgs/populate/README.md.
{ pkgs ? import ../pkgs {}, only ? null }:

let
  inherit (pkgs) lib;
  krops = import ../lib;
  populateTests = ../pkgs/populate/tests;

  inherit (import (populateTests + "/fixtures.nix")) gitHead gitFirst;

  remoteHost = "target";

  # Targets of each kind for a path, as mkTarget returns them.
  targets = {
    local = path: krops.mkTarget "" // { host = "localhost"; inherit path; };
    remote = path: {
      user = "root"; host = remoteHost; port = null; inherit path;
      sudo = false; extraOptions = [];
    };
    sudo = path: {
      user = "deploy"; host = remoteHost; port = null; inherit path;
      sudo = true; extraOptions = [];
    };
  };

  # A phase runs pkgs.populate, or writeDeploy with a stand-in for
  # nixos-rebuild.
  run = {
    source, backup, force, prune, deploy, targetKind, targetPath,
  }: let
    args = {
      inherit source backup force prune;
      target = targets.${targetKind} targetPath;
    };
  in
    if deploy == null then pkgs.populate args
    else pkgs.krops.writeDeploy "deploy"
      (args // { useNixOutputMonitor = false; } // deploy);

  builderArgs = {
    inherit lib run;
    inherit (krops) evalSource;
    checksDuringEvaluation = true;
    url = "http://deployer:8000";
    gitUrl = "git://deployer/gitsrc.git";
    inherit remoteHost;
    agePath = "${pkgs.age}/bin/age";
    inherit gitHead gitFirst;
    rsyncVersion = pkgs.rsync.version;
  };

  populateScenarios = lib.concatLists (builtins.attrValues
    (import (populateTests + "/scenarios.nix") builderArgs));
  kropsScenarios = import ./scenarios.nix (builderArgs // { inherit targets; });

  # Names of the scenarios of the smoke test, besides populate's.
  smokeNames = import (populateTests + "/smoke.nix") ++ [
    "deploy-local-buildTarget0-etcFlake0-flakefile"
    "deploy-sudo-allocateTTY"
  ];

  scenarios = {
    inherit (kropsScenarios) deploy;
    populate = builtins.filter
      (scenario: scenario.refusals || builtins.elem scenario.name smokeNames)
      populateScenarios;
  };
  allScenarios = populateScenarios ++ lib.concatLists (builtins.attrValues kropsScenarios);

  # The stand-in for nixos-rebuild replaces it on both machines.
  module = { pkgs, ... }: {
    environment.systemPackages = [
      (pkgs.writeScriptBin "nixos-rebuild" (builtins.readFile ./nixos-rebuild.sh))
    ];
    system.disableInstallerTools = true;
  };

  vm = name: scenarios: import (populateTests + "/vm.nix") {
    inherit pkgs gitHead scenarios module;
    name = "krops-${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)
    (lib.filterAttrs (_: scenarios: scenarios != [])
      (builtins.mapAttrs
        (_: builtins.filter (scenario: scenario.exhaustive == exhaustive))
        scenarios));

  smokeScenarios = let
    selected = builtins.filter (scenario: builtins.elem scenario.name smokeNames) allScenarios;
    missing = lib.subtractLists (map (scenario: scenario.name) selected) smokeNames;
  in
    if missing != [] then
      throw "tests: smoke test 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

# The remote target must not count as local wherever this gets evaluated.
assert !(krops.isLocalTarget (targets.remote "/"));

  testsOf false ""
  # Not built by nix-build tests either, which runs these scenarios anyway.
  // {
    smoke.smoke = vm "smoke" smokeScenarios;
    only.only = vm "only" onlyScenarios;
  }
  # An attribute set without recurseForDerivations, so nix-build tests
  # doesn't build them.
  // { exhaustive = testsOf true "exhaustive-"; }