Automatically prepare the bundled Navidrome sidecar and replace demo content with real-library scan states and polling
Hop-State: A_06FNEE4FJ502PSGDYQ3272G Hop-Proposal: R_06FNED6AR1ZZM7CJH7ETC9G Hop-Task: T_06FNEAPFW0DYEP35V3BMAHG Hop-Attempt: AT_06FNEAPFW1QY3KAF1QM61N0
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import { pollForLibrary } from "./librarySync";
|
||||
|
||||
describe("pollForLibrary", () => {
|
||||
it("waits until Navidrome returns indexed tracks", async () => {
|
||||
const load = vi.fn()
|
||||
.mockRejectedValueOnce(new Error("server is still starting"))
|
||||
.mockResolvedValueOnce({ tracks: [] })
|
||||
.mockResolvedValueOnce({ tracks: [] })
|
||||
.mockResolvedValueOnce({ tracks: [{ id: "real-track" }] });
|
||||
const wait = vi.fn().mockResolvedValue(undefined);
|
||||
|
||||
await expect(pollForLibrary(load, { attempts: 5, wait })).resolves.toEqual({
|
||||
tracks: [{ id: "real-track" }],
|
||||
});
|
||||
expect(load).toHaveBeenCalledTimes(4);
|
||||
expect(wait).toHaveBeenCalledTimes(3);
|
||||
});
|
||||
|
||||
it("returns null when the scan never yields a track", async () => {
|
||||
const load = vi.fn().mockResolvedValue({ tracks: [] });
|
||||
const wait = vi.fn().mockResolvedValue(undefined);
|
||||
|
||||
await expect(pollForLibrary(load, { attempts: 3, wait })).resolves.toBeNull();
|
||||
expect(load).toHaveBeenCalledTimes(3);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,27 @@
|
||||
export interface LibrarySnapshot<TTrack> {
|
||||
tracks: readonly TTrack[];
|
||||
}
|
||||
|
||||
interface PollOptions {
|
||||
attempts?: number;
|
||||
delayMs?: number;
|
||||
wait?: (delayMs: number) => Promise<void>;
|
||||
}
|
||||
|
||||
const waitFor = (delayMs: number) => new Promise<void>((resolve) => window.setTimeout(resolve, delayMs));
|
||||
|
||||
export async function pollForLibrary<T extends LibrarySnapshot<unknown>>(
|
||||
load: () => Promise<T>,
|
||||
{ attempts = 120, delayMs = 1_000, wait = waitFor }: PollOptions = {},
|
||||
): Promise<T | null> {
|
||||
for (let attempt = 0; attempt < attempts; attempt += 1) {
|
||||
try {
|
||||
const snapshot = await load();
|
||||
if (snapshot.tracks.length > 0) return snapshot;
|
||||
} catch (error) {
|
||||
if (attempt === attempts - 1) throw error;
|
||||
}
|
||||
if (attempt < attempts - 1) await wait(delayMs);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
Reference in New Issue
Block a user