immich is quite demanding which leaves it out of reach if you have one core (e.g. on a laptop, when my EPYC P core was fine). Make the test look more like the test for immich.
165 lines
5.3 KiB
Nix
165 lines
5.3 KiB
Nix
{
|
|
lib,
|
|
...
|
|
}:
|
|
|
|
let
|
|
apiKeyFile = "/tmp/immich-api.key";
|
|
customInterval = 5;
|
|
user = "alice";
|
|
in
|
|
{
|
|
name = "immichframe";
|
|
|
|
meta.maintainers = with lib.maintainers; [
|
|
numinit
|
|
jfly
|
|
];
|
|
|
|
enableOCR = true;
|
|
|
|
nodes.machine =
|
|
{
|
|
config,
|
|
pkgs,
|
|
lib,
|
|
...
|
|
}:
|
|
{
|
|
imports = [
|
|
../common/user-account.nix
|
|
../common/x11.nix
|
|
];
|
|
|
|
# When setting memory to 2500 I got "Kernel panic - not syncing: Out of
|
|
# memory: compulsory panic_on_oom is enabled".
|
|
# Setting cores to 1 (the default) also makes immich take a long time to start up.
|
|
# If this breaks, keep synced with the immich test.
|
|
virtualisation = {
|
|
memorySize = 4096;
|
|
cores = 2;
|
|
};
|
|
hardware.graphics.enable = true;
|
|
environment.variables.XAUTHORITY = "/home/${user}/.Xauthority";
|
|
test-support.displayManager.auto.user = user;
|
|
|
|
environment.systemPackages = with pkgs; [
|
|
imagemagick
|
|
immich-cli
|
|
firefox
|
|
xdotool
|
|
];
|
|
|
|
fonts.packages = [ pkgs.liberation_ttf ];
|
|
|
|
services.immich = {
|
|
enable = true;
|
|
port = 2283;
|
|
openFirewall = true;
|
|
# Disable a bunch of features that aren't needed for this test.
|
|
machine-learning.enable = false;
|
|
settings = {
|
|
backup.database.enabled = false;
|
|
machineLearning.enabled = false;
|
|
map.enabled = false;
|
|
reverseGeocoding.enabled = false;
|
|
metadata.faces.import = false;
|
|
newVersionCheck.enabled = false;
|
|
notifications.smtp.enabled = false;
|
|
};
|
|
};
|
|
|
|
services.immichframe = {
|
|
enable = true;
|
|
port = 8002;
|
|
settings = {
|
|
General.Interval = customInterval;
|
|
Accounts = [
|
|
{
|
|
ImmichServerUrl = "http://localhost:${toString config.services.immich.port}";
|
|
ApiKeyFile = apiKeyFile;
|
|
}
|
|
];
|
|
};
|
|
};
|
|
};
|
|
|
|
testScript = /* python */ ''
|
|
import json
|
|
import tempfile
|
|
from shlex import quote
|
|
|
|
custom_interval = ${toString customInterval}
|
|
|
|
machine.wait_for_x()
|
|
machine.wait_for_unit("immich-server.service")
|
|
machine.wait_for_open_port(2283)
|
|
|
|
# Log in to Immich and create an access key.
|
|
machine.succeed("""
|
|
curl --no-progress-meter -f --json '{ "email": "test@example.com", "name": "Admin", "password": "admin" }' http://localhost:2283/api/auth/admin-sign-up
|
|
""")
|
|
res = machine.succeed("""
|
|
curl --no-progress-meter -f --json '{ "email": "test@example.com", "password": "admin" }' http://localhost:2283/api/auth/login
|
|
""")
|
|
token = json.loads(res)['accessToken']
|
|
res = machine.succeed("""
|
|
curl --no-progress-meter -f -H 'Cookie: immich_access_token=%s' --json '{ "name": "API Key", "permissions": ["all"] }' http://localhost:2283/api/api-keys
|
|
""" % token)
|
|
key = json.loads(res)['secret']
|
|
machine.succeed(f"immich login http://localhost:2283/api {key}")
|
|
res = machine.succeed("immich server-info")
|
|
print(res)
|
|
|
|
# Create the API key so ImmichFrame can start.
|
|
with tempfile.NamedTemporaryFile("w", delete_on_close=False) as f:
|
|
f.write(key)
|
|
f.close()
|
|
machine.copy_from_host(f.name, ${builtins.toJSON apiKeyFile})
|
|
|
|
# We finally have an api key! Make sure ImmichFrame starts up.
|
|
machine.wait_for_unit("immichframe.service")
|
|
machine.wait_for_open_port(8002)
|
|
|
|
# Check ImmichFrame's configuration.
|
|
res = machine.succeed("curl --no-progress-meter -f http://localhost:8002/api/Config")
|
|
frame_config = json.loads(res)
|
|
assert frame_config['interval'] == custom_interval, frame_config
|
|
|
|
# At this point, ImmichFrame should not find any images to serve.
|
|
res = machine.succeed("curl -f http://localhost:8002/api/Asset")
|
|
assets = json.loads(res)
|
|
assert len(assets) == 0, assets
|
|
|
|
# Repeat to make it easier for OCR to pick up given overlays
|
|
image_text = '\\n'.join(['reproduce this moment', 'with NixOS tests <3'] * 6)
|
|
|
|
# These settings make it display fine given potential cropping.
|
|
common_args = f"-gravity center -font Liberation-Mono -pointsize 50 -annotate 0 {quote(image_text)}"
|
|
|
|
# Upload some images to a new album.
|
|
album_title = '✨ Reproducible Moments ✨'
|
|
machine.succeed(f"magick -size 1920x1080 canvas:white -fill black {common_args} /tmp/white.png")
|
|
machine.succeed(f"immich upload -A {quote(album_title)} /tmp/white.png")
|
|
machine.succeed(f"magick -size 1920x1080 canvas:black -fill white {common_args} /tmp/black.png")
|
|
machine.succeed(f"immich upload -A {quote(album_title)} /tmp/black.png")
|
|
res = machine.succeed("immich server-info")
|
|
print(res)
|
|
|
|
# ImmichFrame should now find some assets.
|
|
# Note: we restart ImmichFrame because it has some caching that prevents it
|
|
# from immediately seeing the newly uploaded photos.
|
|
machine.succeed("systemctl restart immichframe.service")
|
|
machine.wait_for_open_port(8002)
|
|
res = machine.succeed("curl --no-progress-meter -f http://localhost:8002/api/Asset")
|
|
assets = json.loads(res)
|
|
assert len(assets) == 2, assets
|
|
|
|
# Wait for a photo to be displayed.
|
|
machine.execute("su - ${user} -c 'firefox --kiosk http://localhost:8002' >&2 & disown")
|
|
machine.wait_for_text('reproduce this moment')
|
|
machine.wait_for_text('with NixOS tests')
|
|
machine.screenshot("screen")
|
|
'';
|
|
}
|