@norskvideo/ctl-test-harness 0.1.50 → 0.1.51
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/demo/harness.js +13 -0
- package/demo/run.d.ts +3 -0
- package/demo/run.js +2 -1
- package/launch.d.ts +7 -0
- package/launch.js +24 -5
- package/package.json +1 -1
- package/smoke.d.ts +3 -0
- package/smoke.js +11 -1
package/demo/harness.js
CHANGED
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
// program SRT listener, an HLS ladder), its config-schema port remap for a
|
|
15
15
|
// built template, and whatever sidecar its output points at.
|
|
16
16
|
import { netReachMode, STUDIO_INTERNAL_PORT, studioBaseFrom } from "../container-net.js";
|
|
17
|
+
import { ctlSupportsPublishDebugPorts } from "../launch.js";
|
|
17
18
|
import { pollUntil } from "../poll.js";
|
|
18
19
|
import { DemoGateFailure } from "./gates.js";
|
|
19
20
|
import { DemoSession, defaultDemoDeps, demoSlug, expandHome, resolveIngestPort, } from "./run.js";
|
|
@@ -146,6 +147,18 @@ export class ProductHarness {
|
|
|
146
147
|
launchArgv.push("--container-user", user);
|
|
147
148
|
if (internalOnly)
|
|
148
149
|
launchArgv.push("--internal-only");
|
|
150
|
+
// ctl binds a product's studio host port to 127.0.0.1. Every gate that
|
|
151
|
+
// fetches it names `s.host` — "the host every printed URL names" — so a
|
|
152
|
+
// non-loopback host is the harness's own statement that it will reach that
|
|
153
|
+
// port from elsewhere: a reused host-sibling daemon over the host-gateway
|
|
154
|
+
// alias, or an explicit --public-host. Derived from the host already
|
|
155
|
+
// computed rather than a second thing for a demo spec to remember to set,
|
|
156
|
+
// and probed because the CLI is `.strict()` and a released ctl predating
|
|
157
|
+
// the flag would abort the launch.
|
|
158
|
+
else if (s.host !== "localhost" && (await (deps.supportsPublishDebugPorts ?? ctlSupportsPublishDebugPorts)())) {
|
|
159
|
+
launchArgv.push("--publish-debug-ports");
|
|
160
|
+
deps.log(`studio host port re-opened on every interface for ${s.host} (--publish-debug-ports)`);
|
|
161
|
+
}
|
|
149
162
|
if (!this.launchedIds.includes(instanceId))
|
|
150
163
|
this.launchedIds.push(instanceId);
|
|
151
164
|
// The whole list each time, not an append: idempotent, and readable by
|
package/demo/run.d.ts
CHANGED
|
@@ -85,6 +85,9 @@ export interface DemoDeps {
|
|
|
85
85
|
storeExists(storeDir: string): boolean;
|
|
86
86
|
ensureNetwork(): ReturnType<typeof ensureRunnerOnNetwork>;
|
|
87
87
|
supportsNoPublish(): Promise<boolean>;
|
|
88
|
+
/** Does the resolved ctl advertise `--publish-debug-ports`? Optional so an
|
|
89
|
+
* existing custom-deps consumer keeps working; absent = probe the CLI. */
|
|
90
|
+
supportsPublishDebugPorts?(): Promise<boolean>;
|
|
88
91
|
containerUser(): string | undefined;
|
|
89
92
|
/** Symlinks under an exported workdir whose target does not exist, as
|
|
90
93
|
* `<link> -> <target>` lines. */
|
package/demo/run.js
CHANGED
|
@@ -32,7 +32,7 @@ import { parseManifestSeed, repoOf } from "@norskvideo/ctl-sdk/manifest-seed";
|
|
|
32
32
|
import { DOCKER_NETWORK_NAME, ensureRunnerOnNetwork, netReachMode } from "../container-net.js";
|
|
33
33
|
import { cleanupDaemon, requireLicenseFile, runCli, startDaemon, } from "../daemon.js";
|
|
34
34
|
import { hashSlot } from "../harness-config.js";
|
|
35
|
-
import { ctlSupportsNoPublish, runnerContainerUser } from "../launch.js";
|
|
35
|
+
import { ctlSupportsNoPublish, ctlSupportsPublishDebugPorts, runnerContainerUser } from "../launch.js";
|
|
36
36
|
import { pollUntil } from "../poll.js";
|
|
37
37
|
import { nukePathAsRoot, reportForeignOwners } from "../root-nuke.js";
|
|
38
38
|
import { startSrtSources } from "../source-pump.js";
|
|
@@ -300,6 +300,7 @@ export function defaultDemoDeps(cwd) {
|
|
|
300
300
|
storeExists: (storeDir) => existsSync(storeDir),
|
|
301
301
|
ensureNetwork: () => ensureRunnerOnNetwork(),
|
|
302
302
|
supportsNoPublish: ctlSupportsNoPublish,
|
|
303
|
+
supportsPublishDebugPorts: ctlSupportsPublishDebugPorts,
|
|
303
304
|
containerUser: runnerContainerUser,
|
|
304
305
|
brokenSymlinks: findBrokenSymlinks,
|
|
305
306
|
state: fileStateStore(cwd),
|
package/launch.d.ts
CHANGED
|
@@ -14,6 +14,13 @@ export declare function withContainerUser<T>(opts: T & {
|
|
|
14
14
|
};
|
|
15
15
|
/** True when the resolved norsk-ctl CLI understands `--internal-only`. Memoised. */
|
|
16
16
|
export declare function ctlSupportsNoPublish(): Promise<boolean>;
|
|
17
|
+
/** True when the resolved norsk-ctl CLI understands `--publish-debug-ports` —
|
|
18
|
+
* the flag that keeps a product's studio host port on every interface, which a
|
|
19
|
+
* harness reaching it from another host needs. Same probe for the same reason
|
|
20
|
+
* as `--internal-only` above: a released ctl that predates the flag would abort
|
|
21
|
+
* the launch under `.strict()`, and products pin a RELEASED ctl while picking
|
|
22
|
+
* the harness up separately, so the two versions genuinely diverge. */
|
|
23
|
+
export declare function ctlSupportsPublishDebugPorts(): Promise<boolean>;
|
|
17
24
|
/** In `direct` reach mode, ask the daemon to bind no host ports (`internalOnly`)
|
|
18
25
|
* so concurrent instances on a shared runner can't collide on the product's
|
|
19
26
|
* host-port bands — but only when the resolved ctl supports the flag (see
|
package/launch.js
CHANGED
|
@@ -42,8 +42,9 @@ export function withContainerUser(opts) {
|
|
|
42
42
|
// catches up — no cross-repo release ordering to get right. Cached: one `--help`
|
|
43
43
|
// spawn per process.
|
|
44
44
|
const INTERNAL_ONLY_FLAG = "--internal-only";
|
|
45
|
-
|
|
46
|
-
|
|
45
|
+
const PUBLISH_DEBUG_PORTS_FLAG = "--publish-debug-ports";
|
|
46
|
+
const flagSupport = new Map();
|
|
47
|
+
async function probeFlagSupport(flag) {
|
|
47
48
|
try {
|
|
48
49
|
const proc = Bun.spawn([...cliCommand, "instance", "launch-template", "--help"], {
|
|
49
50
|
stdout: "pipe",
|
|
@@ -51,16 +52,34 @@ async function probeInternalOnlySupport() {
|
|
|
51
52
|
});
|
|
52
53
|
const [out, errText] = await Promise.all([new Response(proc.stdout).text(), new Response(proc.stderr).text()]);
|
|
53
54
|
await proc.exited;
|
|
54
|
-
return `${out}${errText}`.includes(
|
|
55
|
+
return `${out}${errText}`.includes(flag);
|
|
55
56
|
}
|
|
56
57
|
catch {
|
|
57
58
|
return false;
|
|
58
59
|
}
|
|
59
60
|
}
|
|
61
|
+
/** True when the resolved norsk-ctl CLI advertises `flag` in its launch help.
|
|
62
|
+
* Memoised per flag: one `--help` spawn each, however many callers ask. */
|
|
63
|
+
function ctlSupportsFlag(flag) {
|
|
64
|
+
const cached = flagSupport.get(flag);
|
|
65
|
+
if (cached)
|
|
66
|
+
return cached;
|
|
67
|
+
const probe = probeFlagSupport(flag);
|
|
68
|
+
flagSupport.set(flag, probe);
|
|
69
|
+
return probe;
|
|
70
|
+
}
|
|
60
71
|
/** True when the resolved norsk-ctl CLI understands `--internal-only`. Memoised. */
|
|
61
72
|
export function ctlSupportsNoPublish() {
|
|
62
|
-
|
|
63
|
-
|
|
73
|
+
return ctlSupportsFlag(INTERNAL_ONLY_FLAG);
|
|
74
|
+
}
|
|
75
|
+
/** True when the resolved norsk-ctl CLI understands `--publish-debug-ports` —
|
|
76
|
+
* the flag that keeps a product's studio host port on every interface, which a
|
|
77
|
+
* harness reaching it from another host needs. Same probe for the same reason
|
|
78
|
+
* as `--internal-only` above: a released ctl that predates the flag would abort
|
|
79
|
+
* the launch under `.strict()`, and products pin a RELEASED ctl while picking
|
|
80
|
+
* the harness up separately, so the two versions genuinely diverge. */
|
|
81
|
+
export function ctlSupportsPublishDebugPorts() {
|
|
82
|
+
return ctlSupportsFlag(PUBLISH_DEBUG_PORTS_FLAG);
|
|
64
83
|
}
|
|
65
84
|
/** In `direct` reach mode, ask the daemon to bind no host ports (`internalOnly`)
|
|
66
85
|
* so concurrent instances on a shared runner can't collide on the product's
|
package/package.json
CHANGED
package/smoke.d.ts
CHANGED
|
@@ -142,6 +142,9 @@ export interface SmokeDeps {
|
|
|
142
142
|
storeExists(storeDir: string): boolean;
|
|
143
143
|
ensureNetwork(): ReturnType<typeof ensureRunnerOnNetwork>;
|
|
144
144
|
supportsNoPublish(): Promise<boolean>;
|
|
145
|
+
/** Does the resolved ctl advertise `--publish-debug-ports`? Optional so an
|
|
146
|
+
* existing custom-deps consumer keeps working; absent = probe the CLI. */
|
|
147
|
+
supportsPublishDebugPorts?(): Promise<boolean>;
|
|
145
148
|
containerUser(): string | undefined;
|
|
146
149
|
/** Diagnostic dump for a satisfied-phase timeout, taken while the instance
|
|
147
150
|
* is still up. Optional so an existing custom-deps consumer keeps working;
|
package/smoke.js
CHANGED
|
@@ -23,7 +23,7 @@ import { dumpInstanceContainerLogs, preserveEngineLogs } from "./container-logs.
|
|
|
23
23
|
import { ensureRunnerOnNetwork, netReachMode, STUDIO_INTERNAL_PORT, studioBaseFrom, } from "./container-net.js";
|
|
24
24
|
import { cleanupDaemon, requireLicenseFile, runCli, startDaemon, } from "./daemon.js";
|
|
25
25
|
import { hashSlot } from "./harness-config.js";
|
|
26
|
-
import { ctlSupportsNoPublish, runnerContainerUser } from "./launch.js";
|
|
26
|
+
import { ctlSupportsNoPublish, ctlSupportsPublishDebugPorts, runnerContainerUser } from "./launch.js";
|
|
27
27
|
import { pollUntil } from "./poll.js";
|
|
28
28
|
import { nukePathAsRoot, reportForeignOwners } from "./root-nuke.js";
|
|
29
29
|
import { startSrtSources } from "./source-pump.js";
|
|
@@ -72,6 +72,7 @@ export const defaultSmokeDeps = {
|
|
|
72
72
|
storeExists: (storeDir) => existsSync(storeDir),
|
|
73
73
|
ensureNetwork: () => ensureRunnerOnNetwork(),
|
|
74
74
|
supportsNoPublish: ctlSupportsNoPublish,
|
|
75
|
+
supportsPublishDebugPorts: ctlSupportsPublishDebugPorts,
|
|
75
76
|
containerUser: runnerContainerUser,
|
|
76
77
|
diagnose: (instanceId) => dumpInstanceContainerLogs(instanceId),
|
|
77
78
|
fetchProductRoute: async ({ daemonPort, product, route, storeDir }) => {
|
|
@@ -328,6 +329,15 @@ export async function runProductSmoke(slug, spec, deps = defaultSmokeDeps) {
|
|
|
328
329
|
launchArgv.push("--container-user", user);
|
|
329
330
|
if (internalOnly)
|
|
330
331
|
launchArgv.push("--internal-only");
|
|
332
|
+
// ctl binds a product's OPERATOR compose ports (STUDIO_HOST_PORT among
|
|
333
|
+
// them) to 127.0.0.1. `fetchStudio` dials NORSK_TEST_HOST in publish mode;
|
|
334
|
+
// when that is not loopback the test process is a container reaching a host
|
|
335
|
+
// sibling, which a loopback bind refuses. Derived from the host the
|
|
336
|
+
// fetchers already use rather than a second thing to configure.
|
|
337
|
+
else if ((process.env.NORSK_TEST_HOST ?? "localhost") !== "localhost" &&
|
|
338
|
+
(await (deps.supportsPublishDebugPorts ?? ctlSupportsPublishDebugPorts)())) {
|
|
339
|
+
launchArgv.push("--publish-debug-ports");
|
|
340
|
+
}
|
|
331
341
|
launched = true;
|
|
332
342
|
await cliOk(launchArgv);
|
|
333
343
|
await pollUntil(async () => {
|