1{
2 system ? builtins.currentSystem,
3 config ? { },
4 pkgs ? import ../.. { inherit system config; },
5 channelMap ? {
6 # Maps "channels" to packages
7 stable = pkgs.chromium;
8 beta = pkgs.chromiumBeta;
9 dev = pkgs.chromiumDev;
10 ungoogled = pkgs.ungoogled-chromium;
11 chrome-stable = pkgs.google-chrome;
12 chrome-beta = pkgs.google-chrome-beta;
13 chrome-dev = pkgs.google-chrome-dev;
14 },
15}:
16
17with import ../lib/testing-python.nix { inherit system pkgs; };
18with pkgs.lib;
19
20let
21 user = "alice";
22
23 startupHTML = pkgs.writeText "chromium-startup.html" ''
24 <!DOCTYPE html>
25 <html>
26 <head>
27 <meta charset="UTF-8">
28 <title>Chromium startup notifier</title>
29 </head>
30 <body onload="javascript:document.title='startup done'">
31 <img src="file://${
32 pkgs.fetchurl {
33 url = "https://nixos.org/logo/nixos-hex.svg";
34 sha256 = "07ymq6nw8kc22m7kzxjxldhiq8gzmc7f45kq2bvhbdm0w5s112s4";
35 }
36 }" />
37 </body>
38 </html>
39 '';
40in
41
42mapAttrs (
43 channel: chromiumPkg:
44 makeTest {
45 name = "chromium-${channel}";
46 meta = {
47 maintainers = with maintainers; [
48 aszlig
49 ];
50 }
51 // optionalAttrs (chromiumPkg.meta ? timeout) {
52 # https://github.com/NixOS/hydra/issues/591#issuecomment-435125621
53 # Note: optionalAttrs is used since meta.timeout is not set for Google Chrome
54 inherit (chromiumPkg.meta) timeout;
55 };
56
57 enableOCR = true;
58
59 nodes.machine =
60 { ... }:
61 {
62 imports = [
63 ./common/user-account.nix
64 ./common/x11.nix
65 ];
66 virtualisation.memorySize = 2047;
67 test-support.displayManager.auto.user = user;
68 environment = {
69 systemPackages = [ chromiumPkg ];
70 variables."XAUTHORITY" = "/home/alice/.Xauthority";
71 };
72 };
73
74 testScript =
75 let
76 xdo =
77 name: text:
78 let
79 xdoScript = pkgs.writeText "${name}.xdo" text;
80 in
81 "${pkgs.xdotool}/bin/xdotool ${xdoScript}";
82 in
83 ''
84 import shlex
85 import re
86 from contextlib import contextmanager
87
88
89 major_version = "${versions.major (getVersion chromiumPkg.name)}"
90
91
92 # Run as user alice
93 def ru(cmd):
94 return "su - ${user} -c " + shlex.quote(cmd)
95
96
97 def launch_browser():
98 """Launches the web browser with the correct options."""
99 # Determine the name of the binary:
100 pname = "${getName chromiumPkg.name}"
101 if pname.find("chromium") != -1:
102 binary = "chromium" # Same name for all channels and ungoogled-chromium
103 elif pname == "google-chrome":
104 binary = "google-chrome-stable"
105 elif pname == "google-chrome-dev":
106 binary = "google-chrome-unstable"
107 else: # For google-chrome-beta and as fallback:
108 binary = pname
109 # Add optional CLI options:
110 options = []
111 if major_version > "95" and not pname.startswith("google-chrome"):
112 # Workaround to avoid a GPU crash:
113 options.append("--use-gl=swiftshader")
114 # Launch the process:
115 options.append("file://${startupHTML}")
116 machine.succeed(ru(f'ulimit -c unlimited; {binary} {shlex.join(options)} >&2 & disown'))
117 if binary.startswith("google-chrome"):
118 # Need to click away the first window:
119 machine.wait_for_text("Make Google Chrome the default browser")
120 machine.screenshot("google_chrome_default_browser_prompt")
121 machine.send_key("ret")
122
123
124 def create_new_win():
125 """Creates a new Chromium window."""
126 with machine.nested("Creating a new Chromium window"):
127 machine.wait_until_succeeds(
128 ru(
129 "${xdo "create_new_win-select_main_window" ''
130 search --onlyvisible --name "startup done"
131 windowfocus --sync
132 windowactivate --sync
133 ''}"
134 )
135 )
136 machine.send_key("ctrl-n")
137 # Wait until the new window appears:
138 machine.wait_until_succeeds(
139 ru(
140 "${xdo "create_new_win-wait_for_window" ''
141 search --onlyvisible --name "New Tab"
142 windowfocus --sync
143 windowactivate --sync
144 ''}"
145 )
146 )
147
148
149 def close_new_tab_win():
150 """Closes the Chromium window with the title "New Tab"."""
151 machine.wait_until_succeeds(
152 ru(
153 "${xdo "close_new_tab_win-select_main_window" ''
154 search --onlyvisible --name "New Tab"
155 windowfocus --sync
156 windowactivate --sync
157 ''}"
158 )
159 )
160 machine.send_key("ctrl-w")
161 # Wait until the closed window disappears:
162 machine.wait_until_fails(
163 ru(
164 "${xdo "close_new_tab_win-wait_for_close" ''
165 search --onlyvisible --name "New Tab"
166 ''}"
167 )
168 )
169
170
171 @contextmanager
172 def test_new_win(description, url, window_name):
173 create_new_win()
174 machine.wait_for_window("New Tab")
175 machine.send_chars(f"{url}\n")
176 machine.wait_for_window(window_name)
177 machine.screenshot(description)
178 machine.succeed(
179 ru(
180 "${xdo "copy-all" ''
181 key --delay 1000 Ctrl+a Ctrl+c
182 ''}"
183 )
184 )
185 clipboard = machine.succeed(
186 ru("${pkgs.xclip}/bin/xclip -o")
187 )
188 if url == "chrome://gpu":
189 clipboard = "" # TODO: We cannot copy the text via Ctrl+a
190 print(f"{description} window content:\n{clipboard}")
191 with machine.nested(description):
192 yield clipboard
193 # Close the newly created window:
194 machine.send_key("ctrl-w")
195
196
197 machine.wait_for_x()
198
199 launch_browser()
200
201 machine.wait_for_text("startup done")
202 machine.wait_until_succeeds(
203 ru(
204 "${xdo "check-startup" ''
205 search --sync --onlyvisible --name "startup done"
206 # close first start help popup
207 key -delay 1000 Escape
208 windowfocus --sync
209 windowactivate --sync
210 ''}"
211 )
212 )
213
214 create_new_win()
215 # Optional: Wait for the new tab page to fully load before taking the screenshot:
216 machine.wait_for_text("Web Store")
217 machine.screenshot("empty_windows")
218 close_new_tab_win()
219
220 machine.screenshot("startup_done")
221
222 with test_new_win("sandbox_info", "chrome://sandbox", "Sandbox Status") as clipboard:
223 filters = [
224 "layer 1 sandbox.*namespace",
225 "pid namespaces.*yes",
226 "network namespaces.*yes",
227 "seccomp.*sandbox.*yes",
228 "you are adequately sandboxed",
229 ]
230 if not all(
231 re.search(filter, clipboard, flags=re.DOTALL | re.IGNORECASE)
232 for filter in filters
233 ):
234 assert False, f"sandbox not working properly: {clipboard}"
235
236 machine.sleep(1)
237 machine.succeed(
238 ru(
239 "${xdo "find-window-after-copy" ''
240 search --onlyvisible --name "Sandbox Status"
241 ''}"
242 )
243 )
244
245 clipboard = machine.succeed(
246 ru(
247 "echo void | ${pkgs.xclip}/bin/xclip -i >&2"
248 )
249 )
250 machine.succeed(
251 ru(
252 "${xdo "copy-sandbox-info" ''
253 key --delay 1000 Ctrl+a Ctrl+c
254 ''}"
255 )
256 )
257
258 clipboard = machine.succeed(
259 ru("${pkgs.xclip}/bin/xclip -o")
260 )
261 if not all(
262 re.search(filter, clipboard, flags=re.DOTALL | re.IGNORECASE)
263 for filter in filters
264 ):
265 assert False, f"copying twice in a row does not work properly: {clipboard}"
266
267 machine.screenshot("after_copy_from_chromium")
268
269
270 with test_new_win("gpu_info", "chrome://gpu", "GPU Internals"):
271 # To check the text rendering (catches regressions like #131074):
272 machine.wait_for_text("Graphics Feature Status")
273 # TODO: Fix copying all of the text to the clipboard
274
275
276 with test_new_win("version_info", "chrome://version", "About Version") as clipboard:
277 filters = [
278 r"${chromiumPkg.version} \(Official Build",
279 ]
280 if not all(
281 re.search(filter, clipboard) for filter in filters
282 ):
283 assert False, "Version info not correct."
284
285
286 machine.shutdown()
287 '';
288 }
289) channelMap