1let
2 makeTest = import ./make-test-python.nix;
3 imageDataDir = "gallery-app-sampledata";
4 imageLabel = "Image";
5
6 makeFormatTest =
7 {
8 file,
9 buttonIsOffset ? null,
10 customTest ? null,
11 }:
12
13 makeTest (
14 { pkgs, lib, ... }:
15
16 assert lib.asserts.assertMsg (
17 buttonIsOffset != null || customTest != null
18 ) "Must either clarify button position, or define custom test code";
19
20 let
21 format = lib.lists.last (lib.strings.splitString "." file);
22 in
23
24 {
25 name = "lomiri-gallery-app-standalone-format-${format}";
26 meta.maintainers = lib.teams.lomiri.members;
27
28 nodes.machine =
29 { config, pkgs, ... }:
30 {
31 imports = [ ./common/x11.nix ];
32
33 services.xserver.enable = true;
34
35 environment = {
36 etc."${imageDataDir}".source =
37 pkgs.runCommand imageDataDir
38 {
39 nativeBuildInputs = with pkgs; [
40 ffmpeg # make a video from the image
41 (imagemagick.override { ghostscriptSupport = true; }) # add label for OCR
42 ];
43 }
44 ''
45 mkdir -p $out/{Pictures,Videos}
46
47 # Setup example data, OCR-friendly:
48 # - White square, black text
49 # - Small text for display OCR
50 # - Big text for gallery preview OCR
51 # - uppercase extension
52 magick -size 500x500 -background white -fill black canvas:white \
53 -pointsize 20 -annotate +100+100 '${imageLabel}' \
54 -pointsize 70 -annotate +100+300 '${imageLabel}' \
55 $out/Pictures/output.PNG
56
57 # Different image formats
58 magick $out/Pictures/output.PNG $out/Pictures/output.JPG
59 magick $out/Pictures/output.PNG $out/Pictures/output.BMP
60 magick $out/Pictures/output.PNG $out/Pictures/output.GIF
61
62 # Video for dispatching
63 ffmpeg -loop 1 -r 1 -i $out/Pictures/output.PNG -t 100 -pix_fmt yuv420p $out/Videos/output.MP4
64 '';
65 systemPackages =
66 with pkgs;
67 [
68 glib # Poke thumbnailer to process media via gdbus
69 mpv # URI dispatching for video support
70 xdotool # mouse movement
71 ]
72 ++ (with pkgs.lomiri; [
73 suru-icon-theme
74 lomiri-gallery-app
75 lomiri-thumbnailer # finds new images & generates thumbnails
76 ]);
77 variables = {
78 UITK_ICON_THEME = "suru";
79 };
80 };
81
82 # Allow us to start thumbnailer ahead-of-time, hopefully let thumbnails get processed in peace
83 systemd.user.services."dbus-com.lomiri.Thumbnailer" = {
84 serviceConfig = {
85 Type = "dbus";
86 BusName = "com.lomiri.Thumbnailer";
87 ExecStart = "${pkgs.lomiri.lomiri-thumbnailer}/libexec/lomiri-thumbnailer/thumbnailer-service";
88 };
89 };
90
91 fonts = {
92 packages = with pkgs; [
93 # Intended font & helps with OCR
94 ubuntu-classic
95 ];
96 };
97 };
98
99 enableOCR = true;
100
101 testScript = ''
102 machine.wait_for_x()
103
104 machine.succeed("mkdir /root/${builtins.dirOf file}")
105 machine.succeed("cp -vr /etc/${imageDataDir}/${file} /root/${builtins.dirOf file}")
106
107 # Start thumbnailer, wait for idle shutdown
108 machine.systemctl("start dbus-com.lomiri.Thumbnailer", "root")
109 machine.wait_until_succeeds(
110 "env XDG_RUNTIME_DIR=/run/user/0 "
111 + "systemctl --user is-active dbus-com.lomiri.Thumbnailer"
112 )
113 machine.wait_for_console_text("thumbnail cache:")
114
115 # Request thumbnail processing, get initial thumbnail image into cache
116 # This can randomly take abit longer, just run it until it succeeds
117 # Touch file to invalidate failure cache
118 machine.wait_until_succeeds(
119 "touch '/root/${file}' && "
120 + "env XDG_RUNTIME_DIR=/run/user/0 "
121 + "gdbus call -e "
122 + "-d com.lomiri.Thumbnailer -o /com/lomiri/Thumbnailer "
123 + "-m com.lomiri.Thumbnailer.GetThumbnail "
124 + "'/root/${file}' "
125 # Same size as source, to reduce processing - we're very close to hitting 20s on slow hardware here
126 + "'@(ii) (500,500)'"
127 )
128
129 machine.wait_for_console_text("Idle timeout reached")
130 machine.wait_until_fails(
131 "env XDG_RUNTIME_DIR=/run/user/0 "
132 + "systemctl --user is-active dbus-com.lomiri.Thumbnailer"
133 )
134
135 with subtest("lomiri gallery finds files"):
136 machine.succeed("lomiri-gallery-app >&2 &")
137 machine.wait_for_console_text("qq= AlbumsOverview") # logged when album page actually gets loaded
138 machine.sleep(10)
139 machine.send_key("alt-f10")
140 machine.sleep(5)
141 machine.wait_for_text(r"(Albums|Events|Photos|${imageLabel})")
142
143 machine.succeed("xdotool mousemove 30 40 click 1") # burger menu for categories
144 machine.sleep(2)
145 machine.succeed("xdotool mousemove 30 180 click 1") # photos
146 machine.sleep(2)
147 machine.screenshot("lomiri-gallery_photos")
148
149 machine.succeed("xdotool mousemove 80 140 click 1") # select first one
150 machine.sleep(2)
151 machine.succeed("xdotool mousemove 80 140 click 1") # enable top-bar
152 machine.sleep(2)
153
154 ''
155 + (
156 if (customTest != null) then
157 customTest
158 else
159 ''
160 with subtest("lomiri gallery handles ${format}"):
161 machine.succeed("xdotool mousemove ${
162 if buttonIsOffset then "900" else "940"
163 } 50 click 1") # open media information
164 machine.sleep(2)
165 machine.screenshot("lomiri-gallery_${format}_info")
166 machine.send_key("esc")
167 machine.sleep(2)
168 machine.wait_for_text("${imageLabel}") # make sure media shows fine
169 ''
170 );
171
172 }
173 );
174 makeFormatTests =
175 detailsList:
176 builtins.listToAttrs (
177 builtins.map (
178 {
179 name,
180 file,
181 buttonIsOffset ? null,
182 customTest ? null,
183 }:
184 {
185 name = "format-${name}";
186 value = makeFormatTest {
187 inherit
188 file
189 buttonIsOffset
190 customTest
191 ;
192 };
193 }
194 ) detailsList
195 );
196in
197{
198 basic = makeTest (
199 { lib, ... }:
200 {
201 name = "lomiri-gallery-app-standalone-basic";
202 meta.maintainers = lib.teams.lomiri.members;
203
204 nodes.machine =
205 { config, pkgs, ... }:
206 {
207 imports = [ ./common/x11.nix ];
208
209 services.xserver.enable = true;
210
211 environment = {
212 systemPackages =
213 with pkgs;
214 [
215 xdotool # mouse movement
216 ]
217 ++ (with pkgs.lomiri; [
218 suru-icon-theme
219 lomiri-gallery-app
220 ]);
221 variables = {
222 UITK_ICON_THEME = "suru";
223 };
224 };
225
226 i18n.supportedLocales = [ "all" ];
227
228 fonts = {
229 packages = with pkgs; [
230 # Intended font & helps with OCR
231 ubuntu-classic
232 ];
233 };
234 };
235
236 enableOCR = true;
237
238 testScript = ''
239 machine.wait_for_x()
240
241 with subtest("lomiri gallery launches"):
242 machine.succeed("lomiri-gallery-app >&2 &")
243 machine.wait_for_console_text("qq= AlbumsOverview") # logged when album page actually gets loaded
244 machine.sleep(10)
245 machine.send_key("alt-f10")
246 machine.sleep(5)
247 machine.wait_for_text(r"(Albums|Events|Photos)")
248 machine.screenshot("lomiri-gallery_open")
249
250 machine.succeed("pgrep -afx lomiri-gallery-app >&2")
251 machine.succeed("pkill -efx lomiri-gallery-app >&2")
252 machine.wait_until_fails("pgrep -afx lomiri-gallery-app >&2")
253
254
255 with subtest("lomiri gallery localisation works"):
256 machine.succeed("env LANG=de_DE.UTF-8 lomiri-gallery-app >&2 &")
257 machine.wait_for_console_text("qq= AlbumsOverview") # logged when album page actually gets loaded
258 machine.sleep(10)
259 machine.send_key("alt-f10")
260 machine.sleep(5)
261 machine.wait_for_text(r"(Alben|Ereignisse|Fotos)")
262 machine.screenshot("lomiri-gallery_localised")
263 '';
264 }
265 );
266}
267// makeFormatTests [
268 {
269 name = "mp4";
270 file = "Videos/output.MP4";
271 # MP4 gets special treatment
272 customTest = ''
273 with subtest("lomiri gallery handles mp4"):
274 machine.succeed("xdotool mousemove 935 40 click 1") # open media information
275 machine.sleep(2)
276 machine.screenshot("lomiri-gallery_mp4_info")
277 machine.send_key("esc")
278 machine.sleep(2)
279
280 machine.wait_for_text("${imageLabel}") # make sure thumbnail processing worked
281 machine.screenshot("lomiri-gallery_mp4_thumbnail")
282
283 machine.succeed("xdotool mousemove 510 380 click 1") # dispatch to system's video handler
284 machine.wait_until_succeeds("pgrep -u root -f mpv") # wait for video to start
285 machine.sleep(10)
286 machine.succeed("pgrep -u root -f mpv") # should still be playing
287 machine.screenshot("lomiri-gallery_mp4_dispatch")
288 '';
289 }
290 {
291 name = "gif";
292 file = "Pictures/output.GIF";
293 buttonIsOffset = false;
294 }
295 {
296 name = "bmp";
297 file = "Pictures/output.BMP";
298 buttonIsOffset = true;
299 }
300 {
301 name = "jpg";
302 file = "Pictures/output.JPG";
303 buttonIsOffset = true;
304 }
305 {
306 name = "png";
307 file = "Pictures/output.PNG";
308 buttonIsOffset = true;
309 }
310]