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