selfhostblocks/test/services/jellyfin.nix
2025-12-01 00:03:36 +01:00

271 lines
7 KiB
Nix

{ pkgs, shb, ... }:
let
port = 9096;
commonTestScript = shb.test.mkScripts {
hasSSL = { node, ... }: !(isNull node.config.shb.jellyfin.ssl);
waitForServices =
{ ... }:
[
"jellyfin.service"
"nginx.service"
];
waitForPorts =
{ node, ... }:
[
port
];
waitForUrls =
{ proto_fqdn, ... }:
[
"${proto_fqdn}/System/Info/Public"
];
extraScript =
{ node, ... }:
''
headers = unline_with(" ", """
-H 'Content-Type: application/json'
-H 'Authorization: MediaBrowser Client="Android TV", Device="Nvidia Shield", DeviceId="ZQ9YQHHrUzk24vV", Version="0.15.3"'
""")
with subtest("api login success"):
response = curl(client, """{"code":%{response_code}}""", "${node.config.test.proto_fqdn}/Users/AuthenticateByName",
data="""{"Username": "jellyfin", "Pw": "admin"}""",
extra=headers)
if response['code'] != 200:
raise Exception(f"Expected success, got: {response['code']}")
with subtest("api login failure"):
response = curl(client, """{"code":%{response_code}}""", "${node.config.test.proto_fqdn}/Users/AuthenticateByName",
data="""{"Username": "jellyfin", "Pw": "badpassword"}""",
extra=headers)
if response['code'] != 401:
raise Exception(f"Expected failure, got: {response['code']}")
'';
};
basic =
{ config, ... }:
{
imports = [
shb.test.baseModule
../../modules/services/jellyfin.nix
];
test = {
subdomain = "j";
};
shb.jellyfin = {
enable = true;
inherit (config.test) subdomain domain;
inherit port;
admin = {
username = "jellyfin";
password.result = config.shb.hardcodedsecret.jellyfinAdminPassword.result;
};
debug = true;
};
shb.hardcodedsecret.jellyfinAdminPassword = {
request = config.shb.jellyfin.admin.password.request;
settings.content = "admin";
};
environment.systemPackages = [
pkgs.sqlite
];
};
clientLogin =
{ config, ... }:
{
imports = [
shb.test.clientLoginModule
];
virtualisation.memorySize = 4096;
test = {
subdomain = "j";
};
test.login = {
browser = "firefox";
# I tried without the path part but it randomly selects either the wizard
# or the page that selects a server.
# startUrl = "${config.test.proto}://${config.test.fqdn}/web/#/wizardstart.html";
# startUrl = "${config.test.proto}://${config.test.fqdn}";
startUrl = "${config.test.proto}://${config.test.fqdn}/web/#/login.html";
usernameFieldLabelRegex = "[Uu]ser";
loginButtonNameRegex = "Sign In";
testLoginWith = [
# I just couldn't make this work. It's very flaky.
# Most of the time, the login jellyfin page doesn't even load
# and the playwright browser is stuck on the splash page.
# I resorted to test the API directly.
# { username = "jellyfin"; password = "badpassword"; nextPageExpect = [
# "expect(page).to_have_title(re.compile('Jellyfin'))"
# "expect(page.get_by_text(re.compile('[Ii]nvalid'))).to_be_visible(timeout=30000)"
# ]; }
# { username = "jellyfin"; password = "admin"; nextPageExpect = [
# "expect(page).to_have_title(re.compile('Jellyfin'))"
# "expect(page.get_by_text(re.compile('[Ii]nvalid'))).not_to_be_visible(timeout=30000)"
# "expect(page.get_by_role('label', re.compile('[Uu]ser'))).not_to_be_visible(timeout=30000)"
# "expect(page.get_by_text(re.compile('[Pp]assword'))).not_to_be_visible(timeout=30000)"
# ]; }
];
};
};
https =
{ config, ... }:
{
shb.jellyfin = {
ssl = config.shb.certs.certs.selfsigned.n;
};
test = {
hasSSL = true;
};
};
ldap =
{ config, ... }:
{
shb.jellyfin = {
ldap = {
enable = true;
host = "127.0.0.1";
port = config.shb.lldap.ldapPort;
dcdomain = config.shb.lldap.dcdomain;
adminPassword.result = config.shb.hardcodedsecret.jellyfinLdapUserPassword.result;
};
};
shb.hardcodedsecret.jellyfinLdapUserPassword = {
request = config.shb.jellyfin.ldap.adminPassword.request;
settings.content = "ldapUserPassword";
};
};
sso =
{ config, ... }:
{
shb.jellyfin = {
sso = {
enable = true;
endpoint = "https://${config.shb.authelia.subdomain}.${config.shb.authelia.domain}";
sharedSecret.result = config.shb.hardcodedsecret.jellyfinSSOPassword.result;
sharedSecretForAuthelia.result = config.shb.hardcodedsecret.jellyfinSSOPasswordAuthelia.result;
};
};
shb.hardcodedsecret.jellyfinSSOPassword = {
request = config.shb.jellyfin.sso.sharedSecret.request;
settings.content = "ssoPassword";
};
shb.hardcodedsecret.jellyfinSSOPasswordAuthelia = {
request = config.shb.jellyfin.sso.sharedSecretForAuthelia.request;
settings.content = "ssoPassword";
};
};
jellyfinTest =
name:
{ nodes, testScript }:
shb.test.runNixOSTest {
name = "jellyfin_${name}";
interactive.nodes.server = {
environment.systemPackages = [
pkgs.sqlite
];
};
inherit nodes;
inherit testScript;
};
in
{
basic = jellyfinTest "basic" {
nodes.server = {
imports = [
basic
clientLogin
];
};
# Client login does not work without SSL.
# At least, I couldn't make it work.
nodes.client = { };
testScript = commonTestScript.access;
};
backup = jellyfinTest "backup" {
nodes.server =
{ config, ... }:
{
imports = [
basic
(shb.test.backup config.shb.jellyfin.backup)
];
};
nodes.client = { };
testScript = commonTestScript.backup;
};
https = jellyfinTest "https" {
nodes.server = {
imports = [
basic
shb.test.certs
https
];
};
nodes.client =
{ config, lib, ... }:
{
imports = [
shb.test.baseModule
clientLogin
];
};
testScript = commonTestScript.access;
};
ldap = jellyfinTest "ldap" {
nodes.server = {
imports = [
basic
shb.test.ldap
ldap
];
};
nodes.client = { };
testScript = commonTestScript.access;
};
sso = jellyfinTest "sso" {
nodes.server =
{ config, pkgs, ... }:
{
imports = [
basic
shb.test.certs
https
shb.test.ldap
(shb.test.sso config.shb.certs.certs.selfsigned.n)
sso
];
};
nodes.client = { };
testScript = commonTestScript.access;
};
}