summaryrefslogtreecommitdiffstats
path: root/nixos/tests/lomiri-music-app.nix
blob: b44251e75bb45be9f3d2703bfd035e8a2bc703cc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
{ lib, ... }:
let
  ocrContent = "Music Test";
  musicFileName = "Example";
  musicFile = "${musicFileName}.mp3";

  ocrPauseColor = "#FF00FF";
  ocrStartColor = "#00FFFF";
in
{
  name = "lomiri-music-app-standalone";
  meta.maintainers = lib.teams.lomiri.members;

  nodes.machine =
    { config, pkgs, ... }:
    {
      imports = [
        ./common/auto.nix
        ./common/user-account.nix
        ./common/x11.nix
      ];

      services.xserver.enable = true;

      environment = {
        # Setup video
        etc."${musicFile}".source =
          pkgs.runCommand musicFile
            {
              nativeBuildInputs = with pkgs; [
                ffmpeg # produce music
                (imagemagick.override { ghostscriptSupport = true; }) # produce OCR-able cover image
              ];
            }
            ''
              magick -size 400x400 canvas:white -pointsize 40 -fill black -annotate +100+100 '${ocrContent}' output.png
              ffmpeg -re \
                -f lavfi -i anullsrc=channel_layout=mono:sample_rate=44100 \
                -i output.png \
                -map 0:0 -map 1:0 \
                -id3v2_version 3 \
                -metadata:s:v title="Album cover" \
                -metadata:s:v comment="Cover (front)" \
                -t 120 \
                $out -loglevel fatal
            '';

        systemPackages =
          with pkgs;
          [
            xdg-user-dirs # generate XDG dirs
            xdotool # mouse movement
          ]
          ++ (with pkgs.lomiri; [
            mediascanner2
            lomiri-music-app
            lomiri-thumbnailer
            # To check if playback actually works, or is broken due to missing codecs, we need to make the app's icons more OCR-able
            (lib.meta.hiPrio (
              suru-icon-theme.overrideAttrs (old: {
                # Colour the background in special colours, which we can OCR for
                postPatch = (old.postPatch or "") + ''
                  substituteInPlace suru/actions/scalable/media-playback-pause.svg \
                    --replace-fail 'fill:none' 'fill:${ocrPauseColor}'

                  substituteInPlace suru/actions/scalable/media-playback-start.svg \
                    --replace-fail 'fill:none' 'fill:${ocrStartColor}'
                '';
              })
            ))
          ]);

        variables = {
          UITK_ICON_THEME = "suru";
        };
      };

      # Get mediascanner-2.0.service
      services.desktopManager.lomiri.enable = lib.mkForce true;

      # ...but stick with icewm
      services.displayManager.defaultSession = lib.mkForce "none+icewm";

      systemd.tmpfiles.settings = {
        "10-lomiri-music-app-test-setup" = {
          "/root/Music".d = {
            mode = "0755";
            user = "root";
            group = "root";
          };
          "/root/Music/${musicFile}"."C+".argument = "/etc/${musicFile}";
        };
      };

      i18n.supportedLocales = [ "all" ];
    };

  enableOCR = true;

  testScript = ''
    from collections.abc import Callable
    import tempfile
    import subprocess

    pauseColor: str = "${ocrPauseColor}"
    startColor: str = "${ocrStartColor}"

    # Based on terminal-emulators.nix' check_for_pink
    def check_for_color(color: str) -> Callable[[bool], bool]:
        def check_for_color_retry(final=False) -> bool:
            with tempfile.NamedTemporaryFile() as tmpin:
                machine.send_monitor_command("screendump {}".format(tmpin.name))

                cmd = 'convert {} -define histogram:unique-colors=true -format "%c" histogram:info:'.format(
                    tmpin.name
                )
                ret = subprocess.run(cmd, shell=True, capture_output=True)
                if ret.returncode != 0:
                    raise Exception(
                        "image analysis failed with exit code {}".format(ret.returncode)
                    )

                text = ret.stdout.decode("utf-8")
                return color in text

        return check_for_color_retry

    machine.wait_for_x()

    # mediascanner2 needs XDG dirs to exist
    machine.succeed("xdg-user-dirs-update")

    # mediascanner2 needs to have run, is only started automatically by Lomiri
    machine.systemctl("start mediascanner-2.0.service", "root")

    # Need to wait abit to make sure our test file gets scanned & added to the database.
    # No good feedback on when this is done... Prolly some time after extractor sub-service is started.
    machine.wait_for_console_text("Started \S*com.lomiri.MediaScanner2.Extractor")
    machine.sleep(10)

    with subtest("lomiri music launches"):
        machine.succeed("lomiri-music-app >&2 &")
        machine.wait_for_console_text("Queue is empty")
        machine.sleep(10)
        machine.send_key("alt-f10")
        machine.sleep(2)
        machine.wait_for_text("favorite music")
        machine.screenshot("lomiri-music")

    with subtest("lomiri music plays music"):
        machine.succeed("xdotool mousemove 30 720 click 1") # Skip intro
        machine.sleep(2)
        machine.wait_for_window("Albums")
        machine.succeed("xdotool mousemove 25 45 click 1") # Open categories
        machine.sleep(2)
        machine.succeed("xdotool mousemove 25 240 click 1") # Switch to Tracks category
        machine.sleep(2)
        machine.wait_for_window("Tracks")
        machine.screenshot("lomiri-music_listing")

        # Ensure pause colours isn't present already
        assert (
            check_for_color(pauseColor)(True) == False
        ), "pauseColor {} was present on the screen before we selected anything!".format(pauseColor)

        machine.succeed("xdotool mousemove 25 120 click 1") # Select the track

        # Waiting for pause icon to be displayed
        with machine.nested("Waiting for the screen to have pauseColor {} on it:".format(pauseColor)):
            retry(check_for_color(pauseColor))

        machine.screenshot("lomiri-music_playback")

        # Ensure play colours isn't present already
        assert (
            check_for_color(startColor)(True) == False
        ), "startColor {} was present on the screen before we were expecting it to be!".format(startColor)

        machine.succeed("xdotool mousemove 860 480 click 1") # Pause track (only works if app can actually decode the file)

        # Waiting for play icon to be displayed
        with machine.nested("Waiting for the screen to have startColor {} on it:".format(startColor)):
            retry(check_for_color(startColor))

        machine.screenshot("lomiri-music_paused")

        # Lastly, check if song details like title & generated cover image got extracted properly
        # if not, indicates an issue with mediascanner / lomiri-thumbnailer
        machine.wait_for_text("${musicFileName}")
        machine.wait_for_text("${ocrContent}")

    machine.succeed("pkill -f lomiri-music-app")

    with subtest("lomiri music localisation works"):
        machine.succeed("env LANG=de_DE.UTF-8 lomiri-music-app .mp4 >&2 &")
        machine.wait_for_console_text("Restoring library queue")
        machine.sleep(10)
        machine.send_key("alt-f10")
        machine.sleep(2)
        machine.wait_for_window("Titel")
        machine.screenshot("lomiri-music_localised")
  '';
}