tests: extract shared jellyfin test helpers and use real jellyfin in annotations test
This commit is contained in:
@@ -5,10 +5,7 @@
|
||||
...
|
||||
}:
|
||||
let
|
||||
payloads = {
|
||||
auth = pkgs.writeText "auth.json" (builtins.toJSON { Username = "jellyfin"; });
|
||||
empty = pkgs.writeText "empty.json" (builtins.toJSON { });
|
||||
};
|
||||
jfLib = import ./jellyfin-test-lib.nix { inherit pkgs lib; };
|
||||
in
|
||||
pkgs.testers.runNixOSTest {
|
||||
name = "jellyfin-qbittorrent-monitor";
|
||||
@@ -18,11 +15,10 @@ pkgs.testers.runNixOSTest {
|
||||
{ ... }:
|
||||
{
|
||||
imports = [
|
||||
jfLib.jellyfinTestConfig
|
||||
inputs.vpn-confinement.nixosModules.default
|
||||
];
|
||||
|
||||
services.jellyfin.enable = true;
|
||||
|
||||
# Real qBittorrent service
|
||||
services.qbittorrent = {
|
||||
enable = true;
|
||||
@@ -56,11 +52,6 @@ pkgs.testers.runNixOSTest {
|
||||
};
|
||||
};
|
||||
|
||||
environment.systemPackages = with pkgs; [
|
||||
curl
|
||||
ffmpeg
|
||||
];
|
||||
virtualisation.diskSize = 3 * 1024;
|
||||
networking.firewall.allowedTCPPorts = [
|
||||
8096
|
||||
8080
|
||||
@@ -106,20 +97,17 @@ pkgs.testers.runNixOSTest {
|
||||
testScript = ''
|
||||
import json
|
||||
import time
|
||||
from urllib.parse import urlencode
|
||||
|
||||
import importlib.util
|
||||
_spec = importlib.util.spec_from_file_location("jf_helpers", "${jfLib.helpers}")
|
||||
assert _spec and _spec.loader
|
||||
_jf = importlib.util.module_from_spec(_spec)
|
||||
_spec.loader.exec_module(_jf)
|
||||
setup_jellyfin = _jf.setup_jellyfin
|
||||
jellyfin_api = _jf.jellyfin_api
|
||||
|
||||
auth_header = 'MediaBrowser Client="NixOS Test", DeviceId="test-1337", Device="TestDevice", Version="1.0"'
|
||||
|
||||
def api_get(path, token=None):
|
||||
header = auth_header + (f", Token={token}" if token else "")
|
||||
return f"curl -sf 'http://server:8096{path}' -H 'X-Emby-Authorization:{header}'"
|
||||
|
||||
def api_post(path, json_file=None, token=None):
|
||||
header = auth_header + (f", Token={token}" if token else "")
|
||||
if json_file:
|
||||
return f"curl -sf -X POST 'http://server:8096{path}' -d '@{json_file}' -H 'Content-Type:application/json' -H 'X-Emby-Authorization:{header}'"
|
||||
return f"curl -sf -X POST 'http://server:8096{path}' -H 'X-Emby-Authorization:{header}'"
|
||||
|
||||
def is_throttled():
|
||||
return server.succeed("curl -s http://localhost:8080/api/v2/transfer/speedLimitsMode").strip() == "1"
|
||||
|
||||
@@ -137,57 +125,15 @@ pkgs.testers.runNixOSTest {
|
||||
return False
|
||||
return all(t["state"].startswith("stopped") for t in torrents)
|
||||
|
||||
movie_id: str = ""
|
||||
media_source_id: str = ""
|
||||
|
||||
start_all()
|
||||
server.wait_for_unit("jellyfin.service")
|
||||
server.wait_for_open_port(8096)
|
||||
server.wait_until_succeeds("curl -sf http://localhost:8096/health | grep -q Healthy", timeout=60)
|
||||
server.wait_for_unit("qbittorrent.service")
|
||||
server.wait_for_open_port(8080)
|
||||
|
||||
# Wait for qBittorrent WebUI to be responsive
|
||||
server.wait_until_succeeds("curl -sf http://localhost:8080/api/v2/app/version", timeout=30)
|
||||
|
||||
with subtest("Complete Jellyfin setup wizard"):
|
||||
server.wait_until_succeeds(api_get("/Startup/Configuration"))
|
||||
server.succeed(api_get("/Startup/FirstUser"))
|
||||
server.succeed(api_post("/Startup/Complete"))
|
||||
|
||||
with subtest("Authenticate and get token"):
|
||||
auth_result = json.loads(server.succeed(api_post("/Users/AuthenticateByName", "${payloads.auth}")))
|
||||
token = auth_result["AccessToken"]
|
||||
user_id = auth_result["User"]["Id"]
|
||||
|
||||
with subtest("Create test video library"):
|
||||
tempdir = server.succeed("mktemp -d -p /var/lib/jellyfin").strip()
|
||||
server.succeed(f"chmod 755 '{tempdir}'")
|
||||
server.succeed(f"ffmpeg -f lavfi -i testsrc2=duration=5 '{tempdir}/Test Movie (2024) [1080p].mkv'")
|
||||
|
||||
add_folder_query = urlencode({
|
||||
"name": "Test Library",
|
||||
"collectionType": "Movies",
|
||||
"paths": tempdir,
|
||||
"refreshLibrary": "true",
|
||||
})
|
||||
server.succeed(api_post(f"/Library/VirtualFolders?{add_folder_query}", "${payloads.empty}", token))
|
||||
|
||||
def is_library_ready(_):
|
||||
folders = json.loads(server.succeed(api_get("/Library/VirtualFolders", token)))
|
||||
return all(f.get("RefreshStatus") == "Idle" for f in folders)
|
||||
retry(is_library_ready, timeout=60)
|
||||
|
||||
def get_movie(_):
|
||||
global movie_id, media_source_id
|
||||
items = json.loads(server.succeed(api_get(f"/Users/{user_id}/Items?IncludeItemTypes=Movie&Recursive=true", token)))
|
||||
if items["TotalRecordCount"] > 0:
|
||||
movie_id = items["Items"][0]["Id"]
|
||||
item_info = json.loads(server.succeed(api_get(f"/Users/{user_id}/Items/{movie_id}", token)))
|
||||
media_source_id = item_info["MediaSources"][0]["Id"]
|
||||
return True
|
||||
return False
|
||||
retry(get_movie, timeout=60)
|
||||
token, user_id, movie_id, media_source_id = setup_jellyfin(
|
||||
server, retry, auth_header,
|
||||
"${jfLib.payloads.auth}", "${jfLib.payloads.empty}",
|
||||
)
|
||||
|
||||
with subtest("Start monitor service"):
|
||||
python = "${pkgs.python3.withPackages (ps: [ ps.requests ])}/bin/python"
|
||||
@@ -214,12 +160,12 @@ pkgs.testers.runNixOSTest {
|
||||
server_ip = "192.168.1.1"
|
||||
|
||||
with subtest("Client authenticates from external network"):
|
||||
auth_cmd = f"curl -sf -X POST 'http://{server_ip}:8096/Users/AuthenticateByName' -d '@${payloads.auth}' -H 'Content-Type:application/json' -H 'X-Emby-Authorization:{client_auth}'"
|
||||
auth_cmd = f"curl -sf -X POST 'http://{server_ip}:8096/Users/AuthenticateByName' -d '@${jfLib.payloads.auth}' -H 'Content-Type:application/json' -H 'X-Emby-Authorization:{client_auth}'"
|
||||
client_auth_result = json.loads(client.succeed(auth_cmd))
|
||||
client_token = client_auth_result["AccessToken"]
|
||||
|
||||
with subtest("Second client authenticates from external network"):
|
||||
auth_cmd2 = f"curl -sf -X POST 'http://{server_ip}:8096/Users/AuthenticateByName' -d '@${payloads.auth}' -H 'Content-Type:application/json' -H 'X-Emby-Authorization:{client_auth2}'"
|
||||
auth_cmd2 = f"curl -sf -X POST 'http://{server_ip}:8096/Users/AuthenticateByName' -d '@${jfLib.payloads.auth}' -H 'Content-Type:application/json' -H 'X-Emby-Authorization:{client_auth2}'"
|
||||
client_auth_result2 = json.loads(client.succeed(auth_cmd2))
|
||||
client_token2 = client_auth_result2["AccessToken"]
|
||||
|
||||
@@ -430,7 +376,7 @@ pkgs.testers.runNixOSTest {
|
||||
with subtest("Local playback does NOT trigger throttling"):
|
||||
local_auth = 'MediaBrowser Client="Local Client", DeviceId="local-1111", Device="LocalDevice", Version="1.0"'
|
||||
local_auth_result = json.loads(server.succeed(
|
||||
f"curl -sf -X POST 'http://localhost:8096/Users/AuthenticateByName' -d '@${payloads.auth}' -H 'Content-Type:application/json' -H 'X-Emby-Authorization:{local_auth}'"
|
||||
f"curl -sf -X POST 'http://localhost:8096/Users/AuthenticateByName' -d '@${jfLib.payloads.auth}' -H 'Content-Type:application/json' -H 'X-Emby-Authorization:{local_auth}'"
|
||||
))
|
||||
local_token = local_auth_result["AccessToken"]
|
||||
|
||||
@@ -527,11 +473,11 @@ pkgs.testers.runNixOSTest {
|
||||
|
||||
# Re-authenticate (old token invalid after restart)
|
||||
client_auth_result = json.loads(client.succeed(
|
||||
f"curl -sf -X POST 'http://{server_ip}:8096/Users/AuthenticateByName' -d '@${payloads.auth}' -H 'Content-Type:application/json' -H 'X-Emby-Authorization:{client_auth}'"
|
||||
f"curl -sf -X POST 'http://{server_ip}:8096/Users/AuthenticateByName' -d '@${jfLib.payloads.auth}' -H 'Content-Type:application/json' -H 'X-Emby-Authorization:{client_auth}'"
|
||||
))
|
||||
client_token = client_auth_result["AccessToken"]
|
||||
client_auth_result2 = json.loads(client.succeed(
|
||||
f"curl -sf -X POST 'http://{server_ip}:8096/Users/AuthenticateByName' -d '@${payloads.auth}' -H 'Content-Type:application/json' -H 'X-Emby-Authorization:{client_auth2}'"
|
||||
f"curl -sf -X POST 'http://{server_ip}:8096/Users/AuthenticateByName' -d '@${jfLib.payloads.auth}' -H 'Content-Type:application/json' -H 'X-Emby-Authorization:{client_auth2}'"
|
||||
))
|
||||
client_token2 = client_auth_result2["AccessToken"]
|
||||
|
||||
@@ -542,11 +488,11 @@ pkgs.testers.runNixOSTest {
|
||||
with subtest("Monitor recovers after Jellyfin temporary unavailability"):
|
||||
# Re-authenticate with fresh token
|
||||
client_auth_result = json.loads(client.succeed(
|
||||
f"curl -sf -X POST 'http://{server_ip}:8096/Users/AuthenticateByName' -d '@${payloads.auth}' -H 'Content-Type:application/json' -H 'X-Emby-Authorization:{client_auth}'"
|
||||
f"curl -sf -X POST 'http://{server_ip}:8096/Users/AuthenticateByName' -d '@${jfLib.payloads.auth}' -H 'Content-Type:application/json' -H 'X-Emby-Authorization:{client_auth}'"
|
||||
))
|
||||
client_token = client_auth_result["AccessToken"]
|
||||
client_auth_result2 = json.loads(client.succeed(
|
||||
f"curl -sf -X POST 'http://{server_ip}:8096/Users/AuthenticateByName' -d '@${payloads.auth}' -H 'Content-Type:application/json' -H 'X-Emby-Authorization:{client_auth2}'"
|
||||
f"curl -sf -X POST 'http://{server_ip}:8096/Users/AuthenticateByName' -d '@${jfLib.payloads.auth}' -H 'Content-Type:application/json' -H 'X-Emby-Authorization:{client_auth2}'"
|
||||
))
|
||||
client_token2 = client_auth_result2["AccessToken"]
|
||||
|
||||
|
||||
Reference in New Issue
Block a user