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