1import ./make-test-python.nix ({ pkgs, esr ? false, ... }: {
2 name = "firefox";
3 meta = with pkgs.lib.maintainers; {
4 maintainers = [ eelco shlevy ];
5 };
6
7 machine =
8 { pkgs, ... }:
9
10 { imports = [ ./common/x11.nix ];
11 environment.systemPackages =
12 (if esr then [ pkgs.firefox-esr ] else [ pkgs.firefox ])
13 ++ [ pkgs.xdotool ];
14
15 # Need some more memory to record audio.
16 virtualisation.memorySize = "500";
17
18 # Create a virtual sound device, with mixing
19 # and all, for recording audio.
20 boot.kernelModules = [ "snd-aloop" ];
21 sound.enable = true;
22 sound.extraConfig = ''
23 pcm.!default {
24 type plug
25 slave.pcm pcm.dmixer
26 }
27 pcm.dmixer {
28 type dmix
29 ipc_key 1
30 slave {
31 pcm "hw:Loopback,0,0"
32 rate 48000
33 periods 128
34 period_time 0
35 period_size 1024
36 buffer_size 8192
37 }
38 }
39 pcm.recorder {
40 type hw
41 card "Loopback"
42 device 1
43 subdevice 0
44 }
45 '';
46
47 systemd.services.audio-recorder = {
48 description = "Record NixOS test audio to /tmp/record.wav";
49 script = "${pkgs.alsaUtils}/bin/arecord -D recorder -f S16_LE -r48000 /tmp/record.wav";
50 };
51
52 };
53
54 testScript = ''
55 from contextlib import contextmanager
56
57
58 @contextmanager
59 def audio_recording(machine: Machine) -> None:
60 """
61 Perform actions while recording the
62 machine audio output.
63 """
64 machine.systemctl("start audio-recorder")
65 yield
66 machine.systemctl("stop audio-recorder")
67
68
69 def wait_for_sound(machine: Machine) -> None:
70 """
71 Wait until any sound has been emitted.
72 """
73 machine.wait_for_file("/tmp/record.wav")
74 while True:
75 # Get at most 2M of the recording
76 machine.execute("tail -c 2M /tmp/record.wav > /tmp/last")
77 # Get the exact size
78 size = int(machine.succeed("stat -c '%s' /tmp/last").strip())
79 # Compare it against /dev/zero using `cmp` (skipping 50B of WAVE header).
80 # If some non-NULL bytes are found it returns 1.
81 status, output = machine.execute(
82 f"cmp -i 50 -n {size - 50} /tmp/last /dev/zero 2>&1"
83 )
84 if status == 1:
85 break
86 machine.sleep(2)
87
88
89 machine.wait_for_x()
90
91 with subtest("Wait until Firefox has finished loading the Valgrind docs page"):
92 machine.execute(
93 "xterm -e 'firefox file://${pkgs.valgrind.doc}/share/doc/valgrind/html/index.html' &"
94 )
95 machine.wait_for_window("Valgrind")
96 machine.sleep(40)
97
98 with subtest("Check whether Firefox can play sound"):
99 with audio_recording(machine):
100 machine.succeed(
101 "firefox file://${pkgs.sound-theme-freedesktop}/share/sounds/freedesktop/stereo/phone-incoming-call.oga &"
102 )
103 wait_for_sound(machine)
104 machine.copy_from_vm("/tmp/record.wav")
105
106 with subtest("Close sound test tab"):
107 machine.execute("xdotool key ctrl+w")
108
109 with subtest("Close default browser prompt"):
110 machine.execute("xdotool key space")
111
112 with subtest("Wait until Firefox draws the developer tool panel"):
113 machine.sleep(10)
114 machine.succeed("xwininfo -root -tree | grep Valgrind")
115 machine.screenshot("screen")
116 '';
117
118})