mirror of
https://github.com/austinried/subtracks.git
synced 2026-11-11 07:29:14 +01:00
tidy the integration harness and its comments
Trim the explanatory comments to short quirk notes, drop the module headers, and fail cleanly: navidrome/gonic now kill their process if they never become ready and the entrypoint always tears down. The prune test waits for the removal to appear in the album list rather than for the scan flag. Correct the AGENTS token-auth note (lms answers 42, Nextcloud 41) and give CI more headroom.
This commit is contained in:
+10
-16
@@ -1,8 +1,6 @@
|
||||
#!/usr/bin/env nu
|
||||
|
||||
# Starts the test servers, prepares the fixture data the Kotlin integration tests expect, runs
|
||||
# them, then tears everything down. Enter the integration shell first:
|
||||
#
|
||||
# Run inside the integration shell:
|
||||
# nix develop .#integration --command nu tools/integration-test.nu
|
||||
|
||||
use ./integration/util.nu [port-in-use]
|
||||
@@ -21,15 +19,16 @@ def main [] {
|
||||
|
||||
let work = (^mktemp -d | str trim)
|
||||
|
||||
print "starting navidrome"
|
||||
let nav = (start-navidrome $work)
|
||||
print "starting gonic"
|
||||
let gonic = (start-gonic $work)
|
||||
|
||||
mut nav = -1
|
||||
mut gonic = -1
|
||||
mut lms = -1
|
||||
mut nc = -1
|
||||
mut prune = -1
|
||||
let outcome = (try {
|
||||
print "starting navidrome"
|
||||
$nav = (start-navidrome $work)
|
||||
print "starting gonic"
|
||||
$gonic = (start-gonic $work)
|
||||
print "starting lms"
|
||||
$lms = (start-lms $work)
|
||||
print "starting nextcloud"
|
||||
@@ -50,14 +49,9 @@ def main [] {
|
||||
($env.LAST_EXIT_CODE? | default 1)
|
||||
})
|
||||
|
||||
let lms_id = $lms
|
||||
let nc_id = $nc
|
||||
let prune_id = $prune
|
||||
do -i { job kill $nav }
|
||||
do -i { job kill $gonic }
|
||||
if $lms_id >= 0 { do -i { job kill $lms_id } }
|
||||
if $nc_id >= 0 { do -i { job kill $nc_id } }
|
||||
if $prune_id >= 0 { do -i { job kill $prune_id } }
|
||||
for id in [$nav $gonic $lms $nc $prune] {
|
||||
if $id >= 0 { do -i { job kill $id } }
|
||||
}
|
||||
rm -rf $work
|
||||
|
||||
exit $outcome
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
# Test servers: fixtures, lifecycle and the credentials the tests rely on.
|
||||
|
||||
use ./util.nu *
|
||||
use ./subsonic.nu *
|
||||
|
||||
@@ -19,8 +17,7 @@ const MUSIC = [
|
||||
{ id: 321, name: "Brad Sucks - I Don't Know What I'm Doing", songs: 12 }
|
||||
]
|
||||
|
||||
# The servers the Kotlin integration tests and the fixtures below share. Keep this in step with
|
||||
# TestServers.kt.
|
||||
# Keep in step with TestServers.kt.
|
||||
export def test-servers [] {
|
||||
[
|
||||
{ name: "navidrome", base: $"http://localhost:($NAV_PORT)/", user: "admin", pass: "password" }
|
||||
@@ -55,10 +52,14 @@ export def start-navidrome [work: string] {
|
||||
let data = ($work | path join "navidrome")
|
||||
mkdir $data
|
||||
let daemon = (job spawn { ^navidrome --address 127.0.0.1 --port $NAV_PORT --musicfolder $LIB --datafolder $data --loglevel warn out+err> ($work | path join "navidrome.log") })
|
||||
poll "navidrome" {||
|
||||
try { http get -m 5sec $"http://127.0.0.1:($NAV_PORT)/rest/ping.view?u=x&p=x&v=1.13.0&c=test" | ignore; true } catch { null }
|
||||
}
|
||||
http post -m 10sec -t application/json $"http://127.0.0.1:($NAV_PORT)/auth/createAdmin" { username: "admin", password: "password" } | ignore
|
||||
let ready = (try {
|
||||
poll "navidrome" {||
|
||||
try { http get -m 5sec $"http://127.0.0.1:($NAV_PORT)/rest/ping.view?u=x&p=x&v=1.13.0&c=test" | ignore; true } catch { null }
|
||||
}
|
||||
http post -m 10sec -t application/json $"http://127.0.0.1:($NAV_PORT)/auth/createAdmin" { username: "admin", password: "password" } | ignore
|
||||
true
|
||||
} catch { false })
|
||||
if not $ready { do -i { job kill $daemon }; error make { msg: "navidrome did not become ready" } }
|
||||
$daemon
|
||||
}
|
||||
|
||||
@@ -67,9 +68,13 @@ export def start-gonic [work: string] {
|
||||
let daemon = (job spawn {
|
||||
^gonic -music-path $LIB -listen-addr $"127.0.0.1:($GONIC_PORT)" -db-path ($work | path join "gonic.db") -cache-path ($work | path join "gonic-cache") -playlists-path ($work | path join "gonic-playlists") -podcast-path ($work | path join "gonic-podcasts") -scan-at-start-enabled -http-log=false out+err> ($work | path join "gonic.log")
|
||||
})
|
||||
poll "gonic" {||
|
||||
try { http get -m 5sec $"http://127.0.0.1:($GONIC_PORT)/rest/ping.view?u=x&p=x&v=1.13.0&c=test" | ignore; true } catch { null }
|
||||
}
|
||||
let ready = (try {
|
||||
poll "gonic" {||
|
||||
try { http get -m 5sec $"http://127.0.0.1:($GONIC_PORT)/rest/ping.view?u=x&p=x&v=1.13.0&c=test" | ignore; true } catch { null }
|
||||
}
|
||||
true
|
||||
} catch { false })
|
||||
if not $ready { do -i { job kill $daemon }; error make { msg: "gonic did not become ready" } }
|
||||
$daemon
|
||||
}
|
||||
|
||||
@@ -84,7 +89,7 @@ export def start-lms [work: string] {
|
||||
| str replace --all 'listen-addr = "0.0.0.0"' 'listen-addr = "127.0.0.1"'
|
||||
| save -f $conf
|
||||
|
||||
# The first start creates and migrates the database; stop it before seeding, then run for real.
|
||||
# Seed after the first start has migrated the schema, then run for real.
|
||||
let bootstrap = (job spawn { ^$lms_bin $conf out+err> ($dir | path join "bootstrap.log") })
|
||||
let ready = (try {
|
||||
poll -n 60 "lms database" {||
|
||||
@@ -152,8 +157,7 @@ export def start-nextcloud [work: string] {
|
||||
$daemon
|
||||
}
|
||||
|
||||
# A second, disposable navidrome over a private copy of two albums. The prune test deletes one
|
||||
# of them and rescans, so this must not share a library with the servers above.
|
||||
# The prune test deletes an album from this private copy and rescans, so it must not be shared.
|
||||
export def start-prune [work: string] {
|
||||
let dir = ($work | path join "prune")
|
||||
let music = ($dir | path join "music")
|
||||
@@ -181,8 +185,7 @@ export def start-prune [work: string] {
|
||||
$daemon
|
||||
}
|
||||
|
||||
# Wait for a server to index the fixture music, then star an album and artist and add a playlist
|
||||
# and scrobbles. The Kotlin integration tests assert against this state.
|
||||
# Wait for the library, then leave the star/playlist/scrobble state the Kotlin tests assert on.
|
||||
export def prepare-fixtures [server: record] {
|
||||
let base = $server.base
|
||||
let user = $server.user
|
||||
|
||||
@@ -1,21 +1,14 @@
|
||||
# Thin Subsonic API client used to inspect and prepare the test servers.
|
||||
|
||||
# Nextcloud's Music app reads repeated (array) parameters straight from the raw query string
|
||||
# without URL-decoding them, so ids must be sent with their unreserved characters intact.
|
||||
export def url-escape [value: string] {
|
||||
# Nextcloud reads repeated (array) params from the raw query string without URL-decoding, so ids
|
||||
# must keep their unreserved characters.
|
||||
def url-escape [value: string] {
|
||||
$value
|
||||
| url encode
|
||||
| str replace --all '%2D' '-'
|
||||
| str replace --all '%2d' '-'
|
||||
| str replace --all '%2E' '.'
|
||||
| str replace --all '%2e' '.'
|
||||
| str replace --all '%5F' '_'
|
||||
| str replace --all '%5f' '_'
|
||||
| str replace --all '%7E' '~'
|
||||
| str replace --all '%7e' '~'
|
||||
}
|
||||
|
||||
export def sub-url [base: string, user: string, pass: string, method: string, params: list<any>] {
|
||||
def sub-url [base: string, user: string, pass: string, method: string, params: list<any>] {
|
||||
let all = ([["u" $user] ["p" $pass] ["v" "1.16.1"] ["c" "subtracks-test"] ["f" "json"]] | append $params)
|
||||
let query = ($all | each {|p| $"($p.0)=(url-escape ($p.1 | into string))" } | str join "&")
|
||||
$"($base)rest/($method).view?($query)"
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
# Shared helpers for the integration harness: waiting and port checks.
|
||||
|
||||
export def poll [label: string, check: closure, --attempts (-n): int = 120] {
|
||||
for attempt in 0..<$attempts {
|
||||
let value = (try { do $check } catch { null })
|
||||
|
||||
Reference in New Issue
Block a user