@norskvideo/ctl-test-harness 0.1.22 → 0.1.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/compose-advancing.d.ts +14 -2
- package/compose-advancing.js +26 -10
- package/demo/gates.js +3 -1
- package/demo/run.js +6 -0
- package/package.json +1 -1
package/compose-advancing.d.ts
CHANGED
|
@@ -2,9 +2,19 @@ export type FetchLike = (url: string, init?: RequestInit) => Promise<Response>;
|
|
|
2
2
|
export declare const DEFAULT_COMPOSE_NODE = "video_compose";
|
|
3
3
|
/** The highest mediaIn across every node of that name; 0 when none. */
|
|
4
4
|
export declare function maxNodeMediaIn(summary: unknown, node: string): number;
|
|
5
|
+
export interface ComposeSample {
|
|
6
|
+
frames: number;
|
|
7
|
+
/** Why the sample is 0 when it is: the visualiser was unreachable, and how. */
|
|
8
|
+
error?: string;
|
|
9
|
+
}
|
|
5
10
|
/** One sample: the highest mediaIn of `node` across every root workflow under
|
|
6
|
-
* `base` (`.../visualiser`). An unreachable visualiser reads as 0
|
|
7
|
-
* caller's second sample, not a throw, decides. */
|
|
11
|
+
* `base` (`.../visualiser`). An unreachable visualiser reads as 0 with the
|
|
12
|
+
* reason beside it — the caller's second sample, not a throw, decides. */
|
|
13
|
+
export declare function composeSample(opts: {
|
|
14
|
+
fetch: FetchLike;
|
|
15
|
+
base: string;
|
|
16
|
+
node?: string;
|
|
17
|
+
}): Promise<ComposeSample>;
|
|
8
18
|
export declare function composeFrames(opts: {
|
|
9
19
|
fetch: FetchLike;
|
|
10
20
|
base: string;
|
|
@@ -15,6 +25,8 @@ export interface ComposeAdvancingResult {
|
|
|
15
25
|
before: number;
|
|
16
26
|
after: number;
|
|
17
27
|
node: string;
|
|
28
|
+
/** Set when a sample could not read the visualiser at all. */
|
|
29
|
+
error?: string;
|
|
18
30
|
}
|
|
19
31
|
/** Two samples `settleMs` apart: advancing when the second is above the first
|
|
20
32
|
* and above zero — the fallback card and a stalled feed both read flat. */
|
package/compose-advancing.js
CHANGED
|
@@ -28,12 +28,18 @@ async function getJson(fetch, url) {
|
|
|
28
28
|
const r = await fetch(url, { signal: AbortSignal.timeout(5000) });
|
|
29
29
|
if (!r.ok)
|
|
30
30
|
throw new Error(`GET ${url} -> ${r.status}`);
|
|
31
|
-
|
|
31
|
+
const text = await r.text();
|
|
32
|
+
try {
|
|
33
|
+
return JSON.parse(text);
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
throw new Error(`GET ${url} -> ${r.status}, not JSON (a sign-in page? the route needs no auth): ${text.slice(0, 80)}`);
|
|
37
|
+
}
|
|
32
38
|
}
|
|
33
39
|
/** One sample: the highest mediaIn of `node` across every root workflow under
|
|
34
|
-
* `base` (`.../visualiser`). An unreachable visualiser reads as 0
|
|
35
|
-
* caller's second sample, not a throw, decides. */
|
|
36
|
-
export async function
|
|
40
|
+
* `base` (`.../visualiser`). An unreachable visualiser reads as 0 with the
|
|
41
|
+
* reason beside it — the caller's second sample, not a throw, decides. */
|
|
42
|
+
export async function composeSample(opts) {
|
|
37
43
|
const node = opts.node ?? DEFAULT_COMPOSE_NODE;
|
|
38
44
|
try {
|
|
39
45
|
const wf = (await getJson(opts.fetch, `${opts.base}/workflow`));
|
|
@@ -44,18 +50,28 @@ export async function composeFrames(opts) {
|
|
|
44
50
|
const summary = await getJson(opts.fetch, `${opts.base}/workflow/${encodeURIComponent(root.wfid)}/summary`);
|
|
45
51
|
max = Math.max(max, maxNodeMediaIn(summary, node));
|
|
46
52
|
}
|
|
47
|
-
return max;
|
|
53
|
+
return { frames: max };
|
|
48
54
|
}
|
|
49
|
-
catch {
|
|
50
|
-
return 0;
|
|
55
|
+
catch (e) {
|
|
56
|
+
return { frames: 0, error: e instanceof Error ? e.message : String(e) };
|
|
51
57
|
}
|
|
52
58
|
}
|
|
59
|
+
export async function composeFrames(opts) {
|
|
60
|
+
return (await composeSample(opts)).frames;
|
|
61
|
+
}
|
|
53
62
|
/** Two samples `settleMs` apart: advancing when the second is above the first
|
|
54
63
|
* and above zero — the fallback card and a stalled feed both read flat. */
|
|
55
64
|
export async function composeAdvancing(opts) {
|
|
56
65
|
const node = opts.node ?? DEFAULT_COMPOSE_NODE;
|
|
57
|
-
const before = await
|
|
66
|
+
const before = await composeSample({ fetch: opts.fetch, base: opts.base, node });
|
|
58
67
|
await new Promise((r) => setTimeout(r, opts.settleMs ?? DEFAULT_SETTLE_MS));
|
|
59
|
-
const after = await
|
|
60
|
-
|
|
68
|
+
const after = await composeSample({ fetch: opts.fetch, base: opts.base, node });
|
|
69
|
+
const error = after.error ?? before.error;
|
|
70
|
+
return {
|
|
71
|
+
advancing: after.frames > before.frames && after.frames > 0,
|
|
72
|
+
before: before.frames,
|
|
73
|
+
after: after.frames,
|
|
74
|
+
node,
|
|
75
|
+
...(error !== undefined ? { error } : {}),
|
|
76
|
+
};
|
|
61
77
|
}
|
package/demo/gates.js
CHANGED
|
@@ -48,7 +48,9 @@ export function composeAdvancingGate(opts = {}) {
|
|
|
48
48
|
node,
|
|
49
49
|
...(opts.settleMs !== undefined ? { settleMs: opts.settleMs } : {}),
|
|
50
50
|
});
|
|
51
|
-
if (
|
|
51
|
+
if (r.error)
|
|
52
|
+
ctx.log(`visualiser unreachable at ${base}: ${r.error}`);
|
|
53
|
+
else if (!r.advancing)
|
|
52
54
|
ctx.log(`${node} not advancing yet (${r.before} -> ${r.after})`);
|
|
53
55
|
return r.advancing;
|
|
54
56
|
},
|
package/demo/run.js
CHANGED
|
@@ -421,6 +421,12 @@ export class DemoSession {
|
|
|
421
421
|
join(this.storeDir, "norsk-runtime"),
|
|
422
422
|
"--proxy-port",
|
|
423
423
|
String(this.ports.proxyPort),
|
|
424
|
+
// A throwaway daemon on a banded port has nothing to protect, and its
|
|
425
|
+
// /instance/<id>/... routes (the visualiser a gate reads, the `open`
|
|
426
|
+
// URLs) must answer without a session: with oauth on, the compose gate
|
|
427
|
+
// read the sign-in page as "0 frames" for 180s (playout CI, 2026-08-29).
|
|
428
|
+
"--proxy-auth",
|
|
429
|
+
"none",
|
|
424
430
|
"--no-http-redirect",
|
|
425
431
|
"--no-start-server",
|
|
426
432
|
...(this.publicHost ? ["--public-host", this.publicHost] : []),
|