From 0241d4d5902a4fdc4ee981650ae9403a0fd5b51c Mon Sep 17 00:00:00 2001 From: Sveske-Juice Date: Sun, 6 Apr 2025 03:29:59 +0200 Subject: [PATCH] tests dont work. need to debug kernel panic --- modules/config.nix | 63 ++++++++++++++++++++++++++++++ modules/default.db | Bin 0 -> 180224 bytes modules/options/default.nix | 1 + modules/options/users.nix | 4 +- tests/create_users.nix | 49 +++++++++++++++++++++++ tests/defaultdb.nix | 39 ++++++++++++++++++ tests/xml.nix | 76 +++++++++++++++++++----------------- 7 files changed, 193 insertions(+), 39 deletions(-) create mode 100755 modules/default.db create mode 100644 tests/create_users.nix create mode 100644 tests/defaultdb.nix diff --git a/modules/config.nix b/modules/config.nix index 0164ac2..e73aac7 100644 --- a/modules/config.nix +++ b/modules/config.nix @@ -84,6 +84,69 @@ in { ${commands} '' ); + + create-db = lib.stringAfter ["var"] ( + let + dbname = "jellyfin.db"; + defaultDB = ./default.db; + sq = "${pkgs.sqlite}/bin/sqlite3 \"${path}/${dbname}\" --"; + path = "/var/lib/jellyfin/data"; + + # ${sq} "INSERT INTO Users (Id, AudioLanguagePreference, AuthenticationProviderId, DisplayCollectionsView, DisplayMissingEpisodes, EnableAutoLogin, EnableLocalPassword, EnableNextEpisodeAutoPlay, EnableUserPreferenceAccess, HidePlayedInLatest, InternalId, LoginAttemptsBeforeLockout, MaxActiveSessions, MaxParentalAgeRating, Password, HashedPasswordFile, PasswordResetProviderId, PlayDefaultAudioTrack, RememberAudioSelections, RememberSubtitleSelections, RemoteClientBitrateLimit, SubtitleLanguagePreference, SubtitleMode, SyncPlayAccess, Username, CastReceiverId) \ + # VALUES(${user.})" + genUser = index: user: let + values = + builtins.mapAttrs (name: value: + if (isBool value) + then + if value + then "1" + else "0" + else value) + (cfg.Users + // { + Id = + if (builtins.hasAttr "Id" cfg.Users) + then cfg.Users.Id + else "$(${pkgs.libuuid}/bin/uuidgen | ${pkgs.coreutils}/bin/tr '[:lower:]' '[:upper:]')"; + InternalId = + if (builtins.hasAttr "InternalId" cfg.Users) + then cfg.Users.InternalId + else "$(($maxIndex+${index + 1}))"; + Password = + if (hasAttr "HashedPasswordFile" cfg.Users) + then "$(${pkgs.coreutils}/bin/cat \"${cfg.Users.HashedPasswordFile}\")" + else "$(${self.packages.${pkgs.system}.genhash}/bin/genhash -k \"${cfg.Users.Password}\" -i 210000 -l 128 -u)"; + }); + in + /* + bash + */ + '' + if [ -n $(${sq} "SELECT 1 FROM Users WHERE Username = '${user.Username}'") ]; then + # Create user + ${sq} "INSERT INTO Users (${concatStringsSep "," + (builtins.filter (x: x != "HashedPasswordFile") + (lib.attrsets.mapAttrsToList (name: value: "${name}") + options.services.declarative-jellyfin.Users.options))}) \\ + VALUES(${builtins.attrValues values})" + fi + ''; + in + /* + bash + */ + '' + mkdir -p ${path} + # Make sure there is a database + if [ -z "${path}/${dbname}" ] && cp ${defaultDB} "${path}/${dbname}" + + maxIndex=$(${sq} 'SELECT InternalId FROM Users ORDER BY InternalId DESC LIMIT 1') + if [ -n "$maxIndex" ] && maxIndex="1" + + + '' + ); }; }; } diff --git a/modules/default.db b/modules/default.db new file mode 100755 index 0000000000000000000000000000000000000000..ea8485f9021a7fa09582c54db17e581445e73c9a GIT binary patch literal 180224 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 Y0w4eaAOHd&00JNY0w4eaFG=A40Q5t0`v3p{ literal 0 HcmV?d00001 diff --git a/modules/options/default.nix b/modules/options/default.nix index e609ac3..3d3736c 100644 --- a/modules/options/default.nix +++ b/modules/options/default.nix @@ -5,6 +5,7 @@ with lib; { ./encoding.nix ./network.nix ./branding.nix + ./users.nix ]; options.services.declarative-jellyfin = { enable = mkEnableOption "Jellyfin Service"; diff --git a/modules/options/users.nix b/modules/options/users.nix index 4dafb18..206b34f 100644 --- a/modules/options/users.nix +++ b/modules/options/users.nix @@ -9,7 +9,6 @@ with lib; { Id = mkOption { type = types.str; # TODO: Limit the id to the pattern: "18B51E25-33FD-46B6-BBF8-DB4DD77D0679" description = "The ID of the user"; - default = "autogenerate"; example = "18B51E25-33FD-46B6-BBF8-DB4DD77D0679"; }; AudioLanguagePreference = mkOption { @@ -64,10 +63,9 @@ with lib; { example = false; }; InternalId = mkOption { - type = with types; either int str; # TODO: Limit string to "autogenerate" + type = types.int; # NOTE: index is 1-indexed! NOT 0-indexed. description = "The index of the user in the database. Be careful setting this option. 1 indexed."; - default = "autogenerate"; example = 69; }; LoginAttemptsBeforeLockout = mkOption { diff --git a/tests/create_users.nix b/tests/create_users.nix new file mode 100644 index 0000000..351cbc2 --- /dev/null +++ b/tests/create_users.nix @@ -0,0 +1,49 @@ +{pkgs ? import {}, ...}: let + name = "minimal"; +in { + inherit name; + test = pkgs.nixosTest { + inherit name; + nodes = { + machine = { + config, + pkgs, + ... + }: { + imports = [ + ../modules/default.nix + ]; + + virtualisation.memorySize = 1024; + + environment.systemPackages = [ + pkgs.sqlite + ]; + + services.declarative-jellyfin = { + enable = true; + Users = [ + { + Username = "admin"; + Password = "123"; + } + ]; + }; + }; + }; + + testScript = + /* + py + */ + '' + machine.start() + machine.wait_for_unit("multi-user.target"); + machine.succeed("file /var/lib/jellyfin/data/jellyfin.db") + users = machine.succeed("sqlite3 /var/lib/jellyfin/data/jellyfin.db -- \"SELECT * FROM Users WHERE Username = 'admin'\"") + print(users) + if users == "": + assert False, "User not in db" + ''; + }; +} diff --git a/tests/defaultdb.nix b/tests/defaultdb.nix new file mode 100644 index 0000000..6f80497 --- /dev/null +++ b/tests/defaultdb.nix @@ -0,0 +1,39 @@ +{pkgs ? import {}, ...}: let + name = "minimal"; +in { + inherit name; + test = pkgs.nixosTest { + inherit name; + nodes = { + machine = { + config, + pkgs, + ... + }: { + imports = [ + ../modules/default.nix + ]; + + services.jellyfin.enable = true; + + virtualisation.memorySize = 1024; + }; + }; + + testScript = + /* + py + */ + '' + machine.start() + machine.wait_for_unit("multi-user.target"); + machine.wait_for_unit("jellyfin.service"); + machine.wait_for_file("/var/lib/jellyfin/data/jellyfin.db", 60) + machine.succeed("sleep 10") + machine.systemctl("stop jellyfin.service") + machine.wait_until_fails("pgrep jellyfin") + machine.copy_from_vm("/var/lib/jellyfin/data/jellyfin.db", "jellyfin.db") + assert False + ''; + }; +} diff --git a/tests/xml.nix b/tests/xml.nix index 34edb49..d8c47c6 100644 --- a/tests/xml.nix +++ b/tests/xml.nix @@ -154,47 +154,51 @@ in { }; }; - testScript = '' - import xml.etree.ElementTree as ET + testScript = + /* + py + */ + '' + import xml.etree.ElementTree as ET - machine.wait_for_unit("multi-user.target"); + machine.wait_for_unit("multi-user.target"); - with subtest("network.xml"): - # stupid fucking hack because you cant open files in python for some reason - xml = machine.succeed("cat /var/lib/jellyfin/config/network.xml") - tree = ET.ElementTree(ET.fromstring(xml)) - root = tree.getroot() + with subtest("network.xml"): + # stupid fucking hack because you cant open files in python for some reason + xml = machine.succeed("cat /var/lib/jellyfin/config/network.xml") + tree = ET.ElementTree(ET.fromstring(xml)) + root = tree.getroot() - with subtest("PublishedServerUriBySubnet"): - for child in root: - if child.tag == "PublishedServerUriBySubnet": - try: - if child[0].text == "all=https://test.test.test": + with subtest("PublishedServerUriBySubnet"): + for child in root: + if child.tag == "PublishedServerUriBySubnet": + try: + if child[0].text == "all=https://test.test.test": + break + except: + print("An error occured when trying to parse xml") + print(xml) + assert False, "Exception occured, check output above" + else: + assert False, "The shit was not found. Full XML: " + xml + + with subtest("EnableHttps"): + for child in root: + if child.tag == "EnableHttps": + if child.text == "true": break - except: - print("An error occured when trying to parse xml") - print(xml) - assert False, "Exception occured, check output above" - else: - assert False, "The shit was not found. Full XML: " + xml + else: + assert False, "The shit was not found. Full XML: " + xml - with subtest("EnableHttps"): - for child in root: - if child.tag == "EnableHttps": - if child.text == "true": - break - else: - assert False, "The shit was not found. Full XML: " + xml + with subtest("RequireHttps"): + for child in root: + if child.tag == "RequireHttps": + if child.text == "true": + break + else: + assert False, "The shit was not found. Full XML: " + xml - with subtest("RequireHttps"): - for child in root: - if child.tag == "RequireHttps": - if child.text == "true": - break - else: - assert False, "The shit was not found. Full XML: " + xml - - machine.shutdown() - ''; + machine.shutdown() + ''; }; }