@norskvideo/ctl-test-harness 0.1.15 → 0.1.16

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.
Files changed (3) hide show
  1. package/package.json +1 -1
  2. package/smoke.d.ts +2 -0
  3. package/smoke.js +21 -5
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@norskvideo/ctl-test-harness",
3
- "version": "0.1.15",
3
+ "version": "0.1.16",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": {
package/smoke.d.ts CHANGED
@@ -125,6 +125,8 @@ export interface SmokeDeps {
125
125
  /** Docker leaves root-owned bind-mount targets under the store; a non-root
126
126
  * runner cannot rm them, so they go from a throwaway root container. */
127
127
  nukeStoreAsRoot(storeDir: string): void;
128
+ /** After the nuke: is the store still there? (Then the nuke did not work.) */
129
+ storeExists(storeDir: string): boolean;
128
130
  ensureNetwork(): ReturnType<typeof ensureRunnerOnNetwork>;
129
131
  supportsNoPublish(): Promise<boolean>;
130
132
  containerUser(): string | undefined;
package/smoke.js CHANGED
@@ -18,7 +18,7 @@
18
18
  // not a dependency of this package (daemon.ts's cleanupDaemon has the same
19
19
  // rule); a product wanting typed commands bridges with toArgv in its own spec.
20
20
  import { spawnSync } from "node:child_process";
21
- import { writeFileSync } from "node:fs";
21
+ import { existsSync, writeFileSync } from "node:fs";
22
22
  import { basename, dirname, join } from "node:path";
23
23
  import { ensureRunnerOnNetwork, netReachMode, STUDIO_INTERNAL_PORT, studioBaseFrom, } from "./container-net.js";
24
24
  import { cleanupDaemon, requireLicenseFile, runCli, startDaemon, } from "./daemon.js";
@@ -77,6 +77,7 @@ export const defaultSmokeDeps = {
77
77
  `rm -rf /base/${basename(storeDir)}`,
78
78
  ]);
79
79
  },
80
+ storeExists: (storeDir) => existsSync(storeDir),
80
81
  ensureNetwork: () => ensureRunnerOnNetwork(),
81
82
  supportsNoPublish: ctlSupportsNoPublish,
82
83
  containerUser: runnerContainerUser,
@@ -186,6 +187,7 @@ export async function runProductSmoke(slug, spec, deps = defaultSmokeDeps) {
186
187
  let daemon = null;
187
188
  let launched = false;
188
189
  let handles = [];
190
+ let journeyError;
189
191
  try {
190
192
  // The same zero point as the guides: `init` on a virgin store, not a seeded
191
193
  // config.yaml. No http redirect (port 80 needs root) and a banded proxy port
@@ -319,9 +321,15 @@ export async function runProductSmoke(slug, spec, deps = defaultSmokeDeps) {
319
321
  deps.log(`${slug}: cleared phase passed for ${phased.length} observation(s)`);
320
322
  }
321
323
  }
322
- finally {
323
- if (handles.length)
324
- await deps.stopSources(handles).catch(() => { });
324
+ catch (e) {
325
+ journeyError = e;
326
+ }
327
+ if (handles.length)
328
+ await deps.stopSources(handles).catch(() => { });
329
+ // cleanupDaemon ends with rmSync(storeDir); Docker's root-owned bind-mount
330
+ // targets make that EACCES on a non-root runner. Expected: the root nuke
331
+ // below is what removes them. Only a store that survives the nuke fails.
332
+ try {
325
333
  await deps.cleanup({
326
334
  deleteInstance: (id) => cli(["instance", "delete", id, "--purge"]),
327
335
  stopDaemon: () => cli(["shutdown", "--daemon-only"]),
@@ -330,6 +338,14 @@ export async function runProductSmoke(slug, spec, deps = defaultSmokeDeps) {
330
338
  storeDir,
331
339
  containers: [`norsk-inst-${instanceId}-studio`, `norsk-inst-${instanceId}-media`],
332
340
  });
333
- deps.nukeStoreAsRoot(storeDir);
341
+ }
342
+ catch (e) {
343
+ deps.log(`${slug}: cleanup could not remove the store itself (${e instanceof Error ? e.message : String(e)}); nuking as root`);
344
+ }
345
+ deps.nukeStoreAsRoot(storeDir);
346
+ if (journeyError !== undefined)
347
+ throw journeyError;
348
+ if (deps.storeExists(storeDir)) {
349
+ throw new Error(`${slug}: store ${storeDir} still present after the root-container nuke`);
334
350
  }
335
351
  }