ALPHA: wire is a tool to deploy nixos systems
wire.althaea.zone/
1# SPDX-License-Identifier: AGPL-3.0-or-later
2# Copyright 2024-2025 wire Contributors
3
4{
5 self,
6 config,
7 lib,
8 inputs,
9 ...
10}:
11let
12 inherit (lib)
13 mkOption
14 mapAttrsToList
15 flatten
16 cartesianProduct
17 ;
18 inherit (lib.types)
19 submodule
20 lines
21 attrsOf
22 anything
23 lazyAttrsOf
24 ;
25 cfg = config.wire.testing;
26in
27{
28 imports = [
29 ./suite/test_remote_deploy
30 ./suite/test_local_deploy
31 ./suite/test_keys
32 ./suite/test_stdin
33 ./suite/test_rollback
34 ];
35 options.wire.testing = mkOption {
36 type = attrsOf (
37 submodule (
38 { name, ... }:
39 {
40 options = {
41 nodes = mkOption {
42 type = lazyAttrsOf anything;
43 };
44 testScript = mkOption {
45 type = lines;
46 default = '''';
47 description = "test script for runNixOSTest";
48 };
49 testDir = mkOption {
50 default = "${self}/tests/nix/suite/${name}";
51 readOnly = true;
52 };
53 };
54 }
55 )
56 );
57 description = "A set of test cases for wire VM testing suite";
58 };
59
60 config.perSystem =
61 {
62 pkgs,
63 self',
64 inputs',
65 ...
66 }:
67 let
68 nixNixpkgsCombos = cartesianProduct {
69 nixpkgs = [
70 inputs'.nixpkgs
71 inputs'.nixpkgs_current_stable
72 # inputs'.nixpkgs_prev_stable
73 ];
74 # TODO: Update once #126 is solved.
75 nix = [
76 # "nix"
77 "lix"
78 ];
79 testName = builtins.attrNames cfg;
80 };
81 mkTest =
82 {
83 testName,
84 opts,
85 nixpkgs,
86 }:
87 let
88 # TODO: Update once #126 is solved.
89 nixPackage = nixpkgs.legacyPackages.lix;
90 sanitiseName =
91 str: lib.strings.sanitizeDerivationName (builtins.replaceStrings [ "." ] [ "_" ] str);
92 identifier = sanitiseName "${nixpkgs.legacyPackages.lib.trivial.release}-${nixPackage.name}";
93 path = "tests/nix/suite/${testName}";
94
95 flakeDirFileset = lib.fileset.toSource {
96 root = ../..;
97 fileset = lib.fileset.union ./. (
98 lib.fileset.fileFilter (file: (file.hasExt "nix") || (file.hasExt "lock")) ../..
99 );
100 };
101
102 injectedFlakeDir = pkgs.runCommand "injected-flake-dir" { } ''
103 cp -r ${flakeDirFileset} $out
104 chmod -R +w $out
105 substituteInPlace $out/${path}/hive.nix --replace-fail @IDENT@ ${identifier}
106 '';
107 in
108 rec {
109 name = "vm-${testName}-${identifier}";
110 value = pkgs.testers.runNixOSTest {
111 inherit (opts) nodes;
112 inherit name;
113 defaults =
114 {
115 pkgs,
116 ...
117 }:
118 let
119 hive = builtins.scopedImport {
120 __nixPath = _b: null;
121 __findFile = _path: name: if name == "nixpkgs" then pkgs.path else throw "oops!!";
122 } "${injectedFlakeDir}/${path}/hive.nix";
123 nodes = mapAttrsToList (_: val: val.config.system.build.toplevel.drvPath) hive.nodes;
124 # fetch **all** dependencies of a flake
125 # it's called fetchLayer because my naming skills are awful
126 fetchLayer =
127 input:
128 let
129 subLayers = if input ? inputs then map fetchLayer (builtins.attrValues input.inputs) else [ ];
130 in
131 [
132 input.outPath
133 ]
134 ++ subLayers;
135 in
136 {
137 imports = [ ./test-opts.nix ];
138 nix = {
139 nixPath = [ "nixpkgs=${pkgs.path}" ];
140 settings.substituters = lib.mkForce [ ];
141 package = nixPackage;
142 };
143
144 environment.systemPackages = [ pkgs.ripgrep ];
145 environment.variables.XDG_RUNTIME_DIR = "/tmp";
146 virtualisation.memorySize = 4096;
147 virtualisation.additionalPaths = flatten [
148 injectedFlakeDir
149 nodes
150 (mapAttrsToList (_: fetchLayer) inputs)
151 ];
152 };
153 node.specialArgs = {
154 testName = name;
155 snakeOil = import "${pkgs.path}/nixos/tests/ssh-keys.nix" pkgs;
156 inherit (opts) testDir;
157 inherit (self'.packages) wire-small-dev;
158 };
159 # NOTE: there is surely a better way of doing this in a more
160 # "controlled" manner, but until a need is asked for, this will remain
161 # as is.
162 testScript = ''
163 start_all()
164
165 TEST_DIR="${injectedFlakeDir}/${path}"
166
167 ${builtins.readFile ./tools.py}
168 ''
169 + lib.concatStringsSep "\n" (mapAttrsToList (_: value: value._wire.testScript) value.nodes)
170 + opts.testScript;
171 };
172 };
173 in
174 {
175 checks = builtins.listToAttrs (
176 builtins.map (
177 {
178 nixpkgs,
179 testName,
180 ...
181 }:
182 let
183 opts = cfg.${testName};
184 in
185 mkTest {
186 inherit
187 testName
188 opts
189 nixpkgs
190 ;
191 }
192 ) nixNixpkgsCombos
193 );
194 };
195}