1{
2 pkgs,
3 runTest,
4 ...
5}:
6
7let
8 assertions = rec {
9 path = program: path: ''
10 with subtest("The path of ${program} should be ${path}"):
11 p = machine.succeed("type -p \"${program}\" | head -c -1")
12 assert p == "${path}", f"${program} is {p}, expected ${path}"
13 '';
14 unit = name: state: ''
15 with subtest("Unit ${name} should be ${state}"):
16 if "${state}" == "active":
17 machine.wait_for_unit("${name}")
18 else:
19 machine.require_unit_state("${name}", "${state}")
20 '';
21 version = ''
22 import re
23
24 with subtest("binary should report the correct version"):
25 pkgver = "${pkgs.atop.version}"
26 ver = re.sub(r'(?s)^Version: (\d+\.\d+\.\d+).*', r'\1', machine.succeed("atop -V"))
27 assert ver == pkgver, f"Version is `{ver}`, expected `{pkgver}`"
28 '';
29 atoprc =
30 contents:
31 if builtins.stringLength contents > 0 then
32 ''
33 with subtest("/etc/atoprc should have the correct contents"):
34 f = machine.succeed("cat /etc/atoprc")
35 assert f == "${contents}", f"/etc/atoprc contents: '{f}', expected '${contents}'"
36 ''
37 else
38 ''
39 with subtest("/etc/atoprc should not be present"):
40 machine.succeed("test ! -e /etc/atoprc")
41 '';
42 wrapper =
43 present:
44 if present then
45 path "atop" "/run/wrappers/bin/atop"
46 + ''
47 with subtest("Wrapper should be setuid root"):
48 stat = machine.succeed("stat --printf '%a %u' /run/wrappers/bin/atop")
49 assert stat == "4511 0", f"Wrapper stat is {stat}, expected '4511 0'"
50 ''
51 else
52 path "atop" "/run/current-system/sw/bin/atop";
53 atopService =
54 present:
55 if present then
56 unit "atop.service" "active"
57 + ''
58 with subtest("atop.service should write some data to /var/log/atop"):
59
60 def has_data_files(last: bool) -> bool:
61 files = int(machine.succeed("ls -1 /var/log/atop | wc -l"))
62 if files == 0:
63 machine.log("Did not find at least one 1 data file")
64 if not last:
65 machine.log("Will retry...")
66 return False
67 return True
68
69 with machine.nested("Waiting for data files"):
70 retry(has_data_files)
71 ''
72 else
73 unit "atop.service" "inactive";
74 atopRotateTimer = present: unit "atop-rotate.timer" (if present then "active" else "inactive");
75 atopacctService =
76 present:
77 if present then
78 unit "atopacct.service" "active"
79 + ''
80 with subtest("atopacct.service should enable process accounting"):
81 machine.wait_until_succeeds("test -f /run/pacct_source")
82
83 with subtest("atopacct.service should write data to /run/pacct_shadow.d"):
84
85 def has_data_files(last: bool) -> bool:
86 files = int(machine.succeed("ls -1 /run/pacct_shadow.d | wc -l"))
87 if files == 0:
88 machine.log("Did not find at least one 1 data file")
89 if not last:
90 machine.log("Will retry...")
91 return False
92 return True
93
94 with machine.nested("Waiting for data files"):
95 retry(has_data_files)
96 ''
97 else
98 unit "atopacct.service" "inactive";
99 netatop =
100 present:
101 if present then
102 unit "netatop.service" "active"
103 + ''
104 with subtest("The netatop kernel module should be loaded"):
105 out = machine.succeed("modprobe -n -v netatop")
106 assert out == "", f"Module should be loaded already, but modprobe would have done {out}."
107 ''
108 else
109 ''
110 with subtest("The netatop kernel module should be absent"):
111 machine.fail("modprobe -n -v netatop")
112 '';
113 atopgpu =
114 present:
115 if present then
116 (unit "atopgpu.service" "active") + (path "atopgpud" "/run/current-system/sw/bin/atopgpud")
117 else
118 (unit "atopgpu.service" "inactive")
119 + ''
120 with subtest("atopgpud should not be present"):
121 machine.fail("type -p atopgpud")
122 '';
123 };
124 meta = {
125 timeout = 600;
126 };
127in
128{
129 justThePackage = runTest {
130 name = "atop-justThePackage";
131 nodes.machine = {
132 environment.systemPackages = [ pkgs.atop ];
133 };
134 testScript =
135 with assertions;
136 builtins.concatStringsSep "\n" [
137 version
138 (atoprc "")
139 (wrapper false)
140 (atopService false)
141 (atopRotateTimer false)
142 (atopacctService false)
143 (netatop false)
144 (atopgpu false)
145 ];
146 inherit meta;
147 };
148 defaults = runTest {
149 name = "atop-defaults";
150 nodes.machine = {
151 programs.atop = {
152 enable = true;
153 };
154 };
155 testScript =
156 with assertions;
157 builtins.concatStringsSep "\n" [
158 version
159 (atoprc "")
160 (wrapper false)
161 (atopService true)
162 (atopRotateTimer true)
163 (atopacctService true)
164 (netatop false)
165 (atopgpu false)
166 ];
167 inherit meta;
168 };
169 minimal = runTest {
170 name = "atop-minimal";
171 nodes.machine = {
172 programs.atop = {
173 enable = true;
174 atopService.enable = false;
175 atopRotateTimer.enable = false;
176 atopacctService.enable = false;
177 };
178 };
179 testScript =
180 with assertions;
181 builtins.concatStringsSep "\n" [
182 version
183 (atoprc "")
184 (wrapper false)
185 (atopService false)
186 (atopRotateTimer false)
187 (atopacctService false)
188 (netatop false)
189 (atopgpu false)
190 ];
191 inherit meta;
192 };
193 netatop = runTest {
194 name = "atop-netatop";
195 nodes.machine = {
196 programs.atop = {
197 enable = true;
198 netatop.enable = true;
199 };
200 };
201 testScript =
202 with assertions;
203 builtins.concatStringsSep "\n" [
204 version
205 (atoprc "")
206 (wrapper false)
207 (atopService true)
208 (atopRotateTimer true)
209 (atopacctService true)
210 (netatop true)
211 (atopgpu false)
212 ];
213 inherit meta;
214 };
215 atopgpu = runTest {
216 name = "atop-atopgpu";
217 nodes.machine = {
218 programs.atop = {
219 enable = true;
220 atopgpu.enable = true;
221 };
222 };
223 testScript =
224 with assertions;
225 builtins.concatStringsSep "\n" [
226 version
227 (atoprc "")
228 (wrapper false)
229 (atopService true)
230 (atopRotateTimer true)
231 (atopacctService true)
232 (netatop false)
233 (atopgpu true)
234 ];
235 inherit meta;
236 };
237 everything = runTest {
238 name = "atop-everything";
239 nodes.machine = {
240 programs.atop = {
241 enable = true;
242 settings = {
243 flags = "faf1";
244 interval = 2;
245 };
246 setuidWrapper.enable = true;
247 netatop.enable = true;
248 atopgpu.enable = true;
249 };
250 };
251 testScript =
252 with assertions;
253 builtins.concatStringsSep "\n" [
254 version
255 (atoprc "flags faf1\\ninterval 2\\n")
256 (wrapper true)
257 (atopService true)
258 (atopRotateTimer true)
259 (atopacctService true)
260 (netatop true)
261 (atopgpu true)
262 ];
263 inherit meta;
264 };
265}