@norskvideo/ctl-test-harness 0.1.3 → 0.1.5
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/daemon.d.ts +1 -0
- package/daemon.js +10 -1
- package/package.json +20 -1
- package/studio-load.d.ts +11 -0
- package/studio-load.js +70 -0
package/daemon.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { pollUntil } from "./poll.js";
|
|
2
2
|
import { makeStoreDir, makeTempDir, TEST_TMP_BASE } from "./temp-dir.js";
|
|
3
3
|
export declare const HEALTH_TIMEOUT_MS = 120000;
|
|
4
|
+
export declare const DAEMON_READY_TIMEOUT_MS = 60000;
|
|
4
5
|
export { makeStoreDir, makeTempDir, pollUntil, TEST_TMP_BASE };
|
|
5
6
|
export declare function requireLicenseFile(): string;
|
|
6
7
|
export declare function runCli(storeDir: string, ...args: string[]): Promise<{
|
package/daemon.js
CHANGED
|
@@ -11,6 +11,15 @@ import { pollUntil } from "./poll.js";
|
|
|
11
11
|
import { makeStoreDir, makeTempDir, TEST_TMP_BASE } from "./temp-dir.js";
|
|
12
12
|
process.env.NORSK_CTL_NO_MEDIA_DOWNLOAD = "1";
|
|
13
13
|
export const HEALTH_TIMEOUT_MS = 120_000;
|
|
14
|
+
// The daemon's readiness probe (/api/ready) cannot answer until `serve` has
|
|
15
|
+
// brought up its oauth2-proxy + nginx sidecar CONTAINERS — /api/* redirects
|
|
16
|
+
// through the proxy. On a cold or contended CI runner that bring-up finishes
|
|
17
|
+
// just past 10s (observed ~10.5s on the GPU box under nightly load), so a 10s
|
|
18
|
+
// window lost the photo-finish and failed every test at setup with "Daemon did
|
|
19
|
+
// not become ready ... Unable to connect". A healthy daemon still answers in
|
|
20
|
+
// under a second, so the wider window only costs wall-clock when startup is
|
|
21
|
+
// genuinely slow.
|
|
22
|
+
export const DAEMON_READY_TIMEOUT_MS = 60_000;
|
|
14
23
|
export { makeStoreDir, makeTempDir, pollUntil, TEST_TMP_BASE };
|
|
15
24
|
function splitLines(text) {
|
|
16
25
|
return text
|
|
@@ -89,7 +98,7 @@ export function startDaemon(storeDir, options) {
|
|
|
89
98
|
const ready = pollUntil(async () => {
|
|
90
99
|
const res = await fetch(`http://localhost:${port}/api/ready`, { signal: AbortSignal.timeout(1000) });
|
|
91
100
|
return res.ok;
|
|
92
|
-
}, { timeoutMs:
|
|
101
|
+
}, { timeoutMs: DAEMON_READY_TIMEOUT_MS, intervalMs: 500, label: "Daemon did not become ready" });
|
|
93
102
|
return { daemon, ready };
|
|
94
103
|
}
|
|
95
104
|
function runningContainers(names) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@norskvideo/ctl-test-harness",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
"./daemon": {
|
|
@@ -18,6 +18,25 @@
|
|
|
18
18
|
"./harness-config": {
|
|
19
19
|
"types": "./harness-config.d.ts",
|
|
20
20
|
"default": "./harness-config.js"
|
|
21
|
+
},
|
|
22
|
+
"./studio-load": {
|
|
23
|
+
"types": "./studio-load.d.ts",
|
|
24
|
+
"default": "./studio-load.js"
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"@norskvideo/ctl-sdk": "^0.1.0"
|
|
29
|
+
},
|
|
30
|
+
"peerDependencies": {
|
|
31
|
+
"@norskvideo/norsk-studio": "*",
|
|
32
|
+
"@norskvideo/norsk-studio-built-ins": "*"
|
|
33
|
+
},
|
|
34
|
+
"peerDependenciesMeta": {
|
|
35
|
+
"@norskvideo/norsk-studio": {
|
|
36
|
+
"optional": true
|
|
37
|
+
},
|
|
38
|
+
"@norskvideo/norsk-studio-built-ins": {
|
|
39
|
+
"optional": true
|
|
21
40
|
}
|
|
22
41
|
},
|
|
23
42
|
"publishConfig": {
|
package/studio-load.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { load } from "@norskvideo/norsk-studio/lib/runtime/document";
|
|
2
|
+
import { RuntimeSystem } from "@norskvideo/norsk-studio/lib/runtime/system";
|
|
3
|
+
export type CompiledDocument = ReturnType<typeof load>;
|
|
4
|
+
export interface StudioLoadOptions {
|
|
5
|
+
stubs?: string[];
|
|
6
|
+
register?: (runtime: RuntimeSystem) => void | Promise<void>;
|
|
7
|
+
filename?: string;
|
|
8
|
+
loadOptions?: Parameters<typeof load>[3];
|
|
9
|
+
}
|
|
10
|
+
export declare function loadsInStudio(yamlText: string, opts?: StudioLoadOptions): Promise<CompiledDocument>;
|
|
11
|
+
export declare function assertLoadsInStudio(yamlText: string, opts?: StudioLoadOptions): Promise<CompiledDocument>;
|
package/studio-load.js
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
// The cheap Layer 4 tier, packaged: run an emitted workflow YAML through
|
|
2
|
+
// Studio's REAL document.load() so every built-ins component's zod schema
|
|
3
|
+
// validates what the composer actually emits — not just the local factory
|
|
4
|
+
// typing. Synchronous validation path only; no Norsk media engine, no Docker.
|
|
5
|
+
//
|
|
6
|
+
// This generalises probe's _util/studio-load.ts (11 scenarios) so no product
|
|
7
|
+
// has to re-derive the fiddly parts:
|
|
8
|
+
// - built-ins registerAll sits at .default.default when bundled and .default
|
|
9
|
+
// when externalised; callableDefault tolerates both.
|
|
10
|
+
// - document.load() records "Unknown node type" and STOPS at the first
|
|
11
|
+
// component it can't resolve, so one custom component would mask every
|
|
12
|
+
// error after it. Out-of-library components (a product's own, or alpha
|
|
13
|
+
// ones absent from @norskvideo/norsk-studio-built-ins) are stub-registered
|
|
14
|
+
// via `stubs` — permissive, config not validated (there is no schema to
|
|
15
|
+
// validate against), passing input streams through so downstream built-ins
|
|
16
|
+
// still resolve subscriptions.
|
|
17
|
+
//
|
|
18
|
+
// Lives in ctl-test-harness (not dev-kit: it needs the norsk-studio packages,
|
|
19
|
+
// which are optional peers here — the products that use it already pin them;
|
|
20
|
+
// dev-kit stays dependency-lean).
|
|
21
|
+
import { callableDefault } from "@norskvideo/ctl-sdk";
|
|
22
|
+
import { load } from "@norskvideo/norsk-studio/lib/runtime/document";
|
|
23
|
+
import { RuntimeSystem } from "@norskvideo/norsk-studio/lib/runtime/system";
|
|
24
|
+
import * as builtInsModule from "@norskvideo/norsk-studio-built-ins";
|
|
25
|
+
const registerAll = callableDefault(builtInsModule, "@norskvideo/norsk-studio-built-ins");
|
|
26
|
+
function registerStub(runtime, identifier) {
|
|
27
|
+
const info = {
|
|
28
|
+
identifier,
|
|
29
|
+
name: identifier,
|
|
30
|
+
category: "Output",
|
|
31
|
+
// load() reads info.configForm.global (global-config map) and iterates
|
|
32
|
+
// info.configForm.form (per-field config patching); an empty non-global
|
|
33
|
+
// form is all a stub needs.
|
|
34
|
+
configForm: { global: false, form: {} },
|
|
35
|
+
subscription: {
|
|
36
|
+
accepts: {
|
|
37
|
+
type: "simple-stream",
|
|
38
|
+
video: true,
|
|
39
|
+
audio: true,
|
|
40
|
+
subtitle: true,
|
|
41
|
+
ancillary: true,
|
|
42
|
+
playlist: true,
|
|
43
|
+
acceptsTransient: true,
|
|
44
|
+
},
|
|
45
|
+
produces: { type: "dynamic-streams", streams: (_cfg, inputs) => inputs },
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
const definition = {
|
|
49
|
+
create: async () => { },
|
|
50
|
+
schemas: async () => ({ config: { type: "object", additionalProperties: true } }),
|
|
51
|
+
};
|
|
52
|
+
runtime.registerComponent(definition, info, "", undefined, "studio-load-stubs");
|
|
53
|
+
}
|
|
54
|
+
export async function loadsInStudio(yamlText, opts = {}) {
|
|
55
|
+
const runtime = new RuntimeSystem();
|
|
56
|
+
await registerAll(runtime);
|
|
57
|
+
for (const id of opts.stubs ?? [])
|
|
58
|
+
registerStub(runtime, id);
|
|
59
|
+
await opts.register?.(runtime);
|
|
60
|
+
return load(opts.filename ?? "workflow.yml", runtime, yamlText, { resolveConfig: true, ...opts.loadOptions });
|
|
61
|
+
}
|
|
62
|
+
// Throwing form for tests: one assertion per scenario, every load error listed.
|
|
63
|
+
export async function assertLoadsInStudio(yamlText, opts = {}) {
|
|
64
|
+
const compiled = await loadsInStudio(yamlText, opts);
|
|
65
|
+
if (compiled.errors.length > 0) {
|
|
66
|
+
const listed = compiled.errors.map((e, i) => ` [${i}] ${e.message}`).join("\n");
|
|
67
|
+
throw new Error(`${opts.filename ?? "workflow.yml"} failed Studio document.load():\n${listed}`);
|
|
68
|
+
}
|
|
69
|
+
return compiled;
|
|
70
|
+
}
|