@zukhruf/testing 0.3.8 → 0.3.10

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/README.md CHANGED
@@ -8,32 +8,33 @@ The words in these documents have one meaning each. See the glossary in [CONTEXT
8
8
 
9
9
  Each area has its own import path, so a test loads only the drivers it uses. The three drivers are optional peer dependencies: install the one an area names.
10
10
 
11
- | Import | Gives | Needs |
12
- | ----------------------------- | ------------------------------------------------------------------------------------------------------------ | ------------------------ |
13
- | `@zukhruf/testing/async` | `timebox`, `settleWithin` | |
14
- | `@zukhruf/testing/docker` | `Docker`, `Container`, `ServiceContainer`, `DockerVolume`, `DockerDirectory`, `TestRun`, `skipWithoutDocker` | Docker CLI |
15
- | `@zukhruf/testing/postgres` | `Postgres` | Docker CLI |
16
- | `@zukhruf/testing/mysql` | `Mysql` | Docker CLI |
17
- | `@zukhruf/testing/mariadb` | `Mariadb` | Docker CLI |
18
- | `@zukhruf/testing/sqlserver` | `SqlServer`, `SQL_SERVER_FULL_IMAGE`, `SQL_SERVER_EDGE_IMAGE` | Docker CLI, `mssql` |
19
- | `@zukhruf/testing/clickhouse` | `ClickHouse` | Docker CLI |
20
- | `@zukhruf/testing/sqlite` | `Sqlite` | |
21
- | `@zukhruf/testing/duckdb` | `DuckDB` | `@duckdb/node-api` |
22
- | `@zukhruf/testing/bigquery` | `BigQuery` | `@google-cloud/bigquery` |
23
- | `@zukhruf/testing/http` | `HttpServer` | |
24
- | `@zukhruf/testing/streams` | `StreamHarness` | |
11
+ | Import | Gives | Needs |
12
+ | ----------------------------- | --------------------------------------------------------------------------------------- | ------------------------ |
13
+ | `@zukhruf/testing/async` | `timebox`, `settleWithin` | |
14
+ | `@zukhruf/testing/docker` | `Docker`, `Container`, `ServiceContainer`, `DockerVolume`, `DockerDirectory`, `TestRun` | Docker CLI |
15
+ | `@zukhruf/testing/postgres` | `Postgres` | Docker CLI |
16
+ | `@zukhruf/testing/mysql` | `Mysql` | Docker CLI |
17
+ | `@zukhruf/testing/mariadb` | `Mariadb` | Docker CLI |
18
+ | `@zukhruf/testing/sqlserver` | `SqlServer`, `SQL_SERVER_FULL_IMAGE`, `SQL_SERVER_EDGE_IMAGE` | Docker CLI, `mssql` |
19
+ | `@zukhruf/testing/clickhouse` | `ClickHouse` | Docker CLI |
20
+ | `@zukhruf/testing/sqlite` | `Sqlite` | |
21
+ | `@zukhruf/testing/duckdb` | `DuckDB` | `@duckdb/node-api` |
22
+ | `@zukhruf/testing/bigquery` | `BigQuery` | `@google-cloud/bigquery` |
23
+ | `@zukhruf/testing/http` | `HttpServer` | |
24
+ | `@zukhruf/testing/streams` | `StreamHarness` | |
25
25
 
26
26
  ## Docker
27
27
 
28
- A `Docker` is the engine the Docker CLI selects. It resolves the engine once, on first use, and every handle it returns keeps that engine. It supports local Unix sockets, Docker Desktop's named pipe on Windows (`npipe://`), and SSH engines (`ssh://`). On Windows, volumes and containers are tested; `directory()` is not.
28
+ A `Docker` is the engine the Docker CLI selects. It resolves the engine once, on first use, and every handle it returns keeps that engine. It supports local Unix sockets, Docker Desktop's named pipe on Windows (`npipe://`), and SSH engines (`ssh://`).
29
+
30
+ A test that needs Docker has no skip option. When the engine does not answer, the first acquisition fails with "Docker is required for container-backed tests" and the engine's error as the cause. Start Docker to run these tests.
29
31
 
30
32
  ```ts
31
- import { Docker, TestRun, skipWithoutDocker } from '@zukhruf/testing/docker';
33
+ import { Docker, TestRun } from '@zukhruf/testing/docker';
32
34
 
33
35
  const docker = new Docker({ testRun: TestRun.fromEnvironment(process.env) });
34
- const skip = await skipWithoutDocker(docker, process.env);
35
36
 
36
- test('a holder in another container', { skip }, async () => {
37
+ test('a holder in another container', async () => {
37
38
  await using volume = await docker.volume();
38
39
  await using holder = await docker.start({
39
40
  image: 'node:lts-alpine',
@@ -61,7 +62,7 @@ test('a holder in another container', { skip }, async () => {
61
62
 
62
63
  Options: `image`, `command`, `name`, `hostname`, `env`, `labels`, `mounts`, `tmpfs`, `ipcHost`, `memory` (default `1g`), `cpus` (default `1`), `memorySwappiness`. `serve` and `reuse` also take `internalPort` and `healthy`, a function that throws until the server is ready; it runs on every acquisition. Use `timebox` for polling inside it.
63
64
 
64
- A `Container` has `containerId`, `exec(command)`, `logs()`, `kill(signal)` and `cleanup()`. Disposal removes it with its anonymous volumes. A `ServiceContainer` also has `host` and `port`; on an SSH engine the port is a local forward that belongs to the acquiring process. `disconnect()` closes that forward and leaves the container running for its other users.
65
+ A `Container` has `containerId`, `exec(command)`, `logs()`, `kill(signal)` and `cleanup()`. Disposal removes it with its anonymous volumes. A `ServiceContainer` also has `host` and `port`; on an SSH engine the port is a local forward that belongs to the acquiring process. `disconnect()` closes that forward and leaves the container running for its other users. If the forward ended before, for example because the SSH connection died, `disconnect()` rejects with what ssh printed. When the removal fails too, `cleanup()` rejects with a `SuppressedError` that holds both errors. Nothing is written to stderr.
65
66
 
66
67
  ### Shared servers
67
68
 
@@ -76,16 +77,6 @@ docker stop <container-id>
76
77
 
77
78
  They run with `--rm`, so stopping also removes them. The image tag is part of the configuration: stop the server to pick up a newer image behind the same tag.
78
79
 
79
- ### Skipping without Docker
80
-
81
- `skipWithoutDocker(docker, process.env)` returns the `skip` option of a test that needs Docker. `ZUKHRUF_TESTING_DOCKER` decides:
82
-
83
- | Value | Result |
84
- | ---------- | ------------------------------------------------------------------------------------- |
85
- | `required` | Runs. Throws when Docker does not answer, so a machine that must run the tests fails. |
86
- | `skip` | Skips. |
87
- | unset | Runs when Docker answers, skips with a reason when it does not. |
88
-
89
80
  ## The supervisor
90
81
 
91
82
  Disposal cleans up after a test that ends. A test process that is killed (a timeout, Ctrl-C, `--test-force-exit`) never disposes its handles, and a running container does not stop by itself. The `zukhruf-docker-tests` command runs `node --test` as one supervised run:
@@ -111,7 +102,7 @@ import { Postgres } from '@zukhruf/testing/postgres';
111
102
 
112
103
  const postgres = new Postgres({ docker });
113
104
 
114
- test('stores a record', { skip }, async () => {
105
+ test('stores a record', async () => {
115
106
  await using database = await postgres.database();
116
107
  // database.connectionString. Close your clients before the scope ends.
117
108
  });
@@ -156,4 +147,4 @@ npx nx run testing:test # builds, then runs the tests
156
147
  npx nx run testing:typecheck # formats, lints, then type checks
157
148
  ```
158
149
 
159
- The Docker-backed tests follow `ZUKHRUF_TESTING_DOCKER`. CI skips them on every operating system, and `.github/workflows/docker.yml` runs them with `required` when this package changes: on Linux, and on Windows through Docker Desktop for the mutex's container tests.
150
+ The tests that need Docker run on every machine, and fail when the engine does not answer. CI runs every test on Linux, where Docker runs Linux containers. The `test` target runs alone (`parallelism: false`): Nx starts no other task while it runs, because its database servers slow down the timing tests of the other projects.
@@ -24,6 +24,7 @@ export declare class ServiceContainer extends Container {
24
24
  /** Closes the forward and leaves the container running for its other users. */
25
25
  readonly disconnect: () => Promise<void>;
26
26
  constructor(containerId: string, port: number, command: DockerCommand, disconnect: () => Promise<void>);
27
+ /** Removes the container, then closes the forward; when both fail, a SuppressedError holds both. */
27
28
  cleanup(): Promise<void>;
28
29
  }
29
30
  //# sourceMappingURL=container.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"container.d.ts","sourceRoot":"","sources":["../../src/docker/container.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,MAAM,EAAmB,MAAM,YAAY,CAAC;AAE1D,wEAAwE;AACxE,MAAM,MAAM,aAAa,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;AAEhE,wFAAwF;AACxF,qBAAa,SAAU,YAAW,eAAe;IAC/C,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC;gBAEpB,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa;IAMvD,QAAQ,CAAC,IAAI,GAAI,SAAS,MAAM,EAAE,KAAG,OAAO,CAAC,MAAM,CAAC,CACG;IAEvD,gFAAgF;IAC1E,IAAI,IAAI,OAAO,CAAC,MAAM,CAAC;IAK7B,6EAA6E;IACvE,IAAI,CAAC,MAAM,SAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAIvC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAY9B,CAAC,MAAM,CAAC,YAAY,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC;CAGvC;AAED;;;GAGG;AACH,qBAAa,gBAAiB,SAAQ,SAAS;IAC7C,QAAQ,CAAC,IAAI,eAAe;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,+EAA+E;IAC/E,QAAQ,CAAC,UAAU,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;gBAGvC,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,aAAa,EACtB,UAAU,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC;IAOlB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;CAOxC"}
1
+ {"version":3,"file":"container.d.ts","sourceRoot":"","sources":["../../src/docker/container.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,MAAM,EAAmB,MAAM,YAAY,CAAC;AAE1D,wEAAwE;AACxE,MAAM,MAAM,aAAa,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;AAEhE,wFAAwF;AACxF,qBAAa,SAAU,YAAW,eAAe;IAC/C,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC;gBAEpB,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa;IAMvD,QAAQ,CAAC,IAAI,GAAI,SAAS,MAAM,EAAE,KAAG,OAAO,CAAC,MAAM,CAAC,CACG;IAEvD,gFAAgF;IAC1E,IAAI,IAAI,OAAO,CAAC,MAAM,CAAC;IAK7B,6EAA6E;IACvE,IAAI,CAAC,MAAM,SAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAIvC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAY9B,CAAC,MAAM,CAAC,YAAY,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC;CAGvC;AAED;;;GAGG;AACH,qBAAa,gBAAiB,SAAQ,SAAS;IAC7C,QAAQ,CAAC,IAAI,eAAe;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,+EAA+E;IAC/E,QAAQ,CAAC,UAAU,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;gBAGvC,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,aAAa,EACtB,UAAU,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC;IAOjC,oGAAoG;IACrF,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;CAKxC"}
@@ -43,13 +43,11 @@ export class ServiceContainer extends Container {
43
43
  this.port = port;
44
44
  this.disconnect = disconnect;
45
45
  }
46
+ /** Removes the container, then closes the forward; when both fail, a SuppressedError holds both. */
46
47
  async cleanup() {
47
- try {
48
- await super.cleanup();
49
- }
50
- finally {
51
- await this.disconnect();
52
- }
48
+ await using forward = new AsyncDisposableStack();
49
+ forward.defer(this.disconnect);
50
+ await super.cleanup();
53
51
  }
54
52
  }
55
53
  //# sourceMappingURL=container.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"container.js","sourceRoot":"","sources":["../../src/docker/container.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,eAAe,EAAE,MAAM,YAAY,CAAC;AAK1D,wFAAwF;AACxF,MAAM,OAAO,SAAS;IACX,WAAW,CAAS;IACpB,OAAO,CAAgB;IAEhC,YAAY,WAAmB,EAAE,OAAsB;QACrD,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;QAC/B,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACzB,CAAC;IAED,mDAAmD;IAC1C,IAAI,GAAG,CAAC,OAAiB,EAAmB,EAAE,CACrD,IAAI,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,IAAI,CAAC,WAAW,EAAE,GAAG,OAAO,CAAC,CAAC,CAAC;IAEvD,gFAAgF;IAChF,KAAK,CAAC,IAAI;QACR,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC;QAClE,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,6EAA6E;IAC7E,KAAK,CAAC,IAAI,CAAC,MAAM,GAAG,SAAS;QAC3B,MAAM,IAAI,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC;IACrE,CAAC;IAED,KAAK,CAAC,OAAO;QACX,MAAM,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,KAAK,CACxE,CAAC,KAAc,EAAE,EAAE;YACjB,IACE,CAAC,CAAC,KAAK,YAAY,eAAe,CAAC;gBACnC,CAAC,oBAAoB,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC;gBAExC,MAAM,KAAK,CAAC;QAChB,CAAC,CACF,CAAC;IACJ,CAAC;IAED,CAAC,MAAM,CAAC,YAAY,CAAC;QACnB,OAAO,IAAI,CAAC,OAAO,EAAE,CAAC;IACxB,CAAC;CACF;AAED;;;GAGG;AACH,MAAM,OAAO,gBAAiB,SAAQ,SAAS;IACpC,IAAI,GAAG,WAAW,CAAC;IACnB,IAAI,CAAS;IACtB,+EAA+E;IACtE,UAAU,CAAsB;IAEzC,YACE,WAAmB,EACnB,IAAY,EACZ,OAAsB,EACtB,UAA+B;QAE/B,KAAK,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;QAC5B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;IAC/B,CAAC;IAEQ,KAAK,CAAC,OAAO;QACpB,IAAI,CAAC;YACH,MAAM,KAAK,CAAC,OAAO,EAAE,CAAC;QACxB,CAAC;gBAAS,CAAC;YACT,MAAM,IAAI,CAAC,UAAU,EAAE,CAAC;QAC1B,CAAC;IACH,CAAC;CACF"}
1
+ {"version":3,"file":"container.js","sourceRoot":"","sources":["../../src/docker/container.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,eAAe,EAAE,MAAM,YAAY,CAAC;AAK1D,wFAAwF;AACxF,MAAM,OAAO,SAAS;IACX,WAAW,CAAS;IACpB,OAAO,CAAgB;IAEhC,YAAY,WAAmB,EAAE,OAAsB;QACrD,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;QAC/B,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACzB,CAAC;IAED,mDAAmD;IAC1C,IAAI,GAAG,CAAC,OAAiB,EAAmB,EAAE,CACrD,IAAI,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,IAAI,CAAC,WAAW,EAAE,GAAG,OAAO,CAAC,CAAC,CAAC;IAEvD,gFAAgF;IAChF,KAAK,CAAC,IAAI;QACR,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC;QAClE,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,6EAA6E;IAC7E,KAAK,CAAC,IAAI,CAAC,MAAM,GAAG,SAAS;QAC3B,MAAM,IAAI,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC;IACrE,CAAC;IAED,KAAK,CAAC,OAAO;QACX,MAAM,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,KAAK,CACxE,CAAC,KAAc,EAAE,EAAE;YACjB,IACE,CAAC,CAAC,KAAK,YAAY,eAAe,CAAC;gBACnC,CAAC,oBAAoB,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC;gBAExC,MAAM,KAAK,CAAC;QAChB,CAAC,CACF,CAAC;IACJ,CAAC;IAED,CAAC,MAAM,CAAC,YAAY,CAAC;QACnB,OAAO,IAAI,CAAC,OAAO,EAAE,CAAC;IACxB,CAAC;CACF;AAED;;;GAGG;AACH,MAAM,OAAO,gBAAiB,SAAQ,SAAS;IACpC,IAAI,GAAG,WAAW,CAAC;IACnB,IAAI,CAAS;IACtB,+EAA+E;IACtE,UAAU,CAAsB;IAEzC,YACE,WAAmB,EACnB,IAAY,EACZ,OAAsB,EACtB,UAA+B;QAE/B,KAAK,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;QAC5B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;IAC/B,CAAC;IAED,oGAAoG;IAC3F,KAAK,CAAC,OAAO;QACpB,YAAY,OAAO,GAAG,IAAI,oBAAoB,EAAE,CAAC;QACjD,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC/B,MAAM,KAAK,CAAC,OAAO,EAAE,CAAC;IACxB,CAAC;CACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"host.d.ts","sourceRoot":"","sources":["../../src/docker/host.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,KAAK,OAAO,EAAiB,MAAM,eAAe,CAAC;AAE5D,eAAO,MAAM,KAAK,GAAI,OAAO,MAAM,KAAG,MACC,CAAC;AAKxC,qFAAqF;AACrF,qBAAa,UAAU;IACrB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAE1B,OAAO;WAIM,OAAO,IAAI,OAAO,CAAC,UAAU,CAAC;IAgB3C,IAAI,MAAM,IAAI,OAAO,CAEpB;IAED,QAAQ,CAAC,OAAO,GAAI,MAAM,MAAM,EAAE,qCAI7B;IAEL,OAAO,CAAC,OAAO,GAAE,MAAM,EAAO,GAAG,MAAM,EAAE;IAqBzC,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM;IAO9B,OAAO,CACX,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,OAAO,GAAG,SAAS,GACvB,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;KAAE,CAAC;CAuHzD"}
1
+ {"version":3,"file":"host.d.ts","sourceRoot":"","sources":["../../src/docker/host.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,KAAK,OAAO,EAAiB,MAAM,eAAe,CAAC;AAE5D,eAAO,MAAM,KAAK,GAAI,OAAO,MAAM,KAAG,MACC,CAAC;AAKxC,qFAAqF;AACrF,qBAAa,UAAU;IACrB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAE1B,OAAO;WAIM,OAAO,IAAI,OAAO,CAAC,UAAU,CAAC;IAgB3C,IAAI,MAAM,IAAI,OAAO,CAEpB;IAED,QAAQ,CAAC,OAAO,GAAI,MAAM,MAAM,EAAE,qCAI7B;IAEL,OAAO,CAAC,OAAO,GAAE,MAAM,EAAO,GAAG,MAAM,EAAE;IAqBzC,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM;IAO9B,OAAO,CACX,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,OAAO,GAAG,SAAS,GACvB,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;KAAE,CAAC;CAuIzD"}
@@ -1,9 +1,8 @@
1
- import { spawn } from 'node:child_process';
2
1
  import { once } from 'node:events';
3
2
  import { mkdtempDisposable, stat } from 'node:fs/promises';
4
3
  import { connect, createServer } from 'node:net';
5
4
  import { join } from 'node:path';
6
- import command from 'nano-spawn';
5
+ import command, { SubprocessError } from 'nano-spawn';
7
6
  import { timebox } from "../async/timebox.js";
8
7
  import { forwardPrefix } from "./test-run.js";
9
8
  export const quote = (value) => `'${value.replaceAll("'", "'\\''")}'`;
@@ -93,7 +92,7 @@ export class DockerHost {
93
92
  // OpenSSH multiplexes client streams over one authenticated connection.
94
93
  // Node owns the ephemeral TCP listener, so no port-reservation race or
95
94
  // fresh SSH login is added to each database client's connect timeout.
96
- const child = spawn('ssh', this.sshArgs([
95
+ const ssh = command('ssh', this.sshArgs([
97
96
  '-N',
98
97
  '-S',
99
98
  'none',
@@ -105,29 +104,26 @@ export class DockerHost {
105
104
  'ExitOnForwardFailure=yes',
106
105
  '-L',
107
106
  `${path}:127.0.0.1:${port}`,
108
- ]), { stdio: ['ignore', 'ignore', 'pipe'] });
109
- let errorOutput = '';
110
- let spawnError;
111
- child.stderr.on('data', (data) => {
112
- errorOutput += data;
107
+ ]), { stdin: 'ignore', stdout: 'ignore' });
108
+ // How ssh ended, with what it printed: a Result for exit 0, or the
109
+ // SubprocessError for a failure or a signal.
110
+ const exit = ssh.then((result) => result, (error) => {
111
+ if (error instanceof SubprocessError)
112
+ return error;
113
+ throw error;
113
114
  });
114
- child.once('error', (error) => {
115
- spawnError = error;
116
- });
117
- const exited = new Promise((resolve) => child.once('close', (code) => {
118
- if (code && errorOutput)
119
- process.stderr.write(`Docker SSH forwarding: ${errorOutput}`);
115
+ void exit.then(() => {
120
116
  for (const socket of sockets)
121
117
  socket.destroy();
122
118
  if (server.listening)
123
119
  server.close();
124
- resolve();
125
- }));
120
+ });
121
+ const child = await ssh.nodeChildProcess;
126
122
  resources.defer(async () => {
127
123
  child.kill('SIGTERM');
128
124
  const deadline = setTimeout(() => child.kill('SIGKILL'), 1_000);
129
125
  try {
130
- await exited;
126
+ await exit;
131
127
  }
132
128
  finally {
133
129
  clearTimeout(deadline);
@@ -144,16 +140,32 @@ export class DockerHost {
144
140
  });
145
141
  // OpenSSH binds local forwards after authentication. Wait for that
146
142
  // listener before publishing the TCP port to a database client.
147
- await timebox(async () => {
148
- if (spawnError)
149
- throw spawnError;
150
- if (child.exitCode !== null || child.signalCode !== null)
151
- throw new Error(`Docker SSH forwarding exited: ${errorOutput.trim()}`);
152
- if (!(await stat(path)).isSocket())
153
- throw new Error('Docker SSH forwarding did not create a Unix socket');
154
- }, {
155
- maxRetryTime: 15_000,
156
- shouldRetry: ({ error }) => !spawnError && 'code' in error && error.code === 'ENOENT',
143
+ const waiting = new AbortController();
144
+ try {
145
+ await Promise.race([
146
+ timebox(async () => {
147
+ if (!(await stat(path)).isSocket())
148
+ throw new Error('Docker SSH forwarding did not create a Unix socket');
149
+ }, {
150
+ maxRetryTime: 15_000,
151
+ signal: waiting.signal,
152
+ shouldRetry: ({ error }) => 'code' in error && error.code === 'ENOENT',
153
+ }),
154
+ exit.then((outcome) => {
155
+ throw new Error(`Docker SSH forwarding exited: ${outcome.stderr.trim()}`, { cause: outcome });
156
+ }),
157
+ ]);
158
+ }
159
+ finally {
160
+ waiting.abort();
161
+ }
162
+ // Runs first on close, before ssh is stopped: an ssh that already
163
+ // exited ended the forward while it was in use.
164
+ resources.defer(async () => {
165
+ if (child.exitCode === null && child.signalCode === null)
166
+ return;
167
+ const outcome = await exit;
168
+ throw new Error(`Docker SSH forwarding was lost: ${outcome.stderr.trim()}`, { cause: outcome });
157
169
  });
158
170
  server.listen(0, '127.0.0.1');
159
171
  await once(server, 'listening');
@@ -1 +1 @@
1
- {"version":3,"file":"host.js","sourceRoot":"","sources":["../../src/docker/host.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"host.js","sourceRoot":"","sources":["../../src/docker/host.ts"],"names":[],"mappings":"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"}
@@ -1,7 +1,6 @@
1
1
  export { Container, type DockerCommand, ServiceContainer, } from './container.ts';
2
2
  export { DockerDirectory } from './directory.ts';
3
3
  export { type ContainerOptions, Docker, type DockerOptions, type Mount, type ServiceOptions, } from './docker.ts';
4
- export { DOCKER_TESTS, skipWithoutDocker } from './skip-without-docker.ts';
5
4
  export { TestRun } from './test-run.ts';
6
5
  export { DockerVolume } from './volume.ts';
7
6
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/docker/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,SAAS,EACT,KAAK,aAAa,EAClB,gBAAgB,GACjB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EACL,KAAK,gBAAgB,EACrB,MAAM,EACN,KAAK,aAAa,EAClB,KAAK,KAAK,EACV,KAAK,cAAc,GACpB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC3E,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/docker/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,SAAS,EACT,KAAK,aAAa,EAClB,gBAAgB,GACjB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EACL,KAAK,gBAAgB,EACrB,MAAM,EACN,KAAK,aAAa,EAClB,KAAK,KAAK,EACV,KAAK,cAAc,GACpB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC"}
@@ -1,7 +1,6 @@
1
1
  export { Container, ServiceContainer, } from "./container.js";
2
2
  export { DockerDirectory } from "./directory.js";
3
3
  export { Docker, } from "./docker.js";
4
- export { DOCKER_TESTS, skipWithoutDocker } from "./skip-without-docker.js";
5
4
  export { TestRun } from "./test-run.js";
6
5
  export { DockerVolume } from "./volume.js";
7
6
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/docker/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,SAAS,EAET,gBAAgB,GACjB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAEL,MAAM,GAIP,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC3E,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/docker/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,SAAS,EAET,gBAAgB,GACjB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAEL,MAAM,GAIP,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zukhruf/testing",
3
- "version": "0.3.8",
3
+ "version": "0.3.10",
4
4
  "description": "Disposable fixtures for integration tests: Docker containers and database servers, SQLite and DuckDB databases, HTTP servers and streams. A supervisor removes what a killed test run left behind.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -1,12 +0,0 @@
1
- import type { Docker } from './docker.ts';
2
- /** How tests treat Docker: `required`, `skip`, or unset to run when Docker answers. */
3
- export declare const DOCKER_TESTS = "ZUKHRUF_TESTING_DOCKER";
4
- /**
5
- * The `skip` option of a test that needs Docker, read from the environment the
6
- * host passes (`process.env`). With `ZUKHRUF_TESTING_DOCKER=required` it
7
- * throws when Docker does not answer, so a machine that must run the tests
8
- * fails instead of skipping them. With `skip` it always skips. Unset, it skips
9
- * only when Docker does not answer.
10
- */
11
- export declare function skipWithoutDocker(docker: Docker, environment: Readonly<Record<string, string | undefined>>): Promise<string | false>;
12
- //# sourceMappingURL=skip-without-docker.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"skip-without-docker.d.ts","sourceRoot":"","sources":["../../src/docker/skip-without-docker.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C,uFAAuF;AACvF,eAAO,MAAM,YAAY,2BAA2B,CAAC;AAErD;;;;;;GAMG;AACH,wBAAsB,iBAAiB,CACrC,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,GACxD,OAAO,CAAC,MAAM,GAAG,KAAK,CAAC,CAuBzB"}
@@ -1,31 +0,0 @@
1
- /** How tests treat Docker: `required`, `skip`, or unset to run when Docker answers. */
2
- export const DOCKER_TESTS = 'ZUKHRUF_TESTING_DOCKER';
3
- /**
4
- * The `skip` option of a test that needs Docker, read from the environment the
5
- * host passes (`process.env`). With `ZUKHRUF_TESTING_DOCKER=required` it
6
- * throws when Docker does not answer, so a machine that must run the tests
7
- * fails instead of skipping them. With `skip` it always skips. Unset, it skips
8
- * only when Docker does not answer.
9
- */
10
- export async function skipWithoutDocker(docker, environment) {
11
- const mode = environment[DOCKER_TESTS];
12
- switch (mode) {
13
- case 'skip':
14
- return `${DOCKER_TESTS}=skip`;
15
- case 'required':
16
- await docker.command(['info']).catch((cause) => {
17
- throw new Error(`${DOCKER_TESTS}=required, but Docker does not answer`, {
18
- cause,
19
- });
20
- });
21
- return false;
22
- case undefined:
23
- case '':
24
- return (await docker.isAvailable())
25
- ? false
26
- : `needs Docker; set ${DOCKER_TESTS}=required to fail instead of skipping`;
27
- default:
28
- throw new Error(`${DOCKER_TESTS} is "required" or "skip", not "${mode}"`);
29
- }
30
- }
31
- //# sourceMappingURL=skip-without-docker.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"skip-without-docker.js","sourceRoot":"","sources":["../../src/docker/skip-without-docker.ts"],"names":[],"mappings":"AAEA,uFAAuF;AACvF,MAAM,CAAC,MAAM,YAAY,GAAG,wBAAwB,CAAC;AAErD;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,MAAc,EACd,WAAyD;IAEzD,MAAM,IAAI,GAAG,WAAW,CAAC,YAAY,CAAC,CAAC;IACvC,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,MAAM;YACT,OAAO,GAAG,YAAY,OAAO,CAAC;QAChC,KAAK,UAAU;YACb,MAAM,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;gBACtD,MAAM,IAAI,KAAK,CACb,GAAG,YAAY,uCAAuC,EACtD;oBACE,KAAK;iBACN,CACF,CAAC;YACJ,CAAC,CAAC,CAAC;YACH,OAAO,KAAK,CAAC;QACf,KAAK,SAAS,CAAC;QACf,KAAK,EAAE;YACL,OAAO,CAAC,MAAM,MAAM,CAAC,WAAW,EAAE,CAAC;gBACjC,CAAC,CAAC,KAAK;gBACP,CAAC,CAAC,qBAAqB,YAAY,uCAAuC,CAAC;QAC/E;YACE,MAAM,IAAI,KAAK,CAAC,GAAG,YAAY,kCAAkC,IAAI,GAAG,CAAC,CAAC;IAC9E,CAAC;AACH,CAAC"}