@zukhruf/testing 0.3.41 → 0.3.43

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 (61) hide show
  1. package/README.md +103 -15
  2. package/dist/databases/clickhouse.d.ts.map +1 -1
  3. package/dist/databases/clickhouse.js +5 -1
  4. package/dist/databases/clickhouse.js.map +1 -1
  5. package/dist/databases/collector.d.ts +34 -0
  6. package/dist/databases/collector.d.ts.map +1 -0
  7. package/dist/databases/collector.js +20 -0
  8. package/dist/databases/collector.js.map +1 -0
  9. package/dist/databases/mariadb.d.ts +1 -2
  10. package/dist/databases/mariadb.d.ts.map +1 -1
  11. package/dist/databases/mariadb.js +2 -2
  12. package/dist/databases/mariadb.js.map +1 -1
  13. package/dist/databases/mysql-family-collector.d.ts +16 -0
  14. package/dist/databases/mysql-family-collector.d.ts.map +1 -0
  15. package/dist/databases/mysql-family-collector.js +36 -0
  16. package/dist/databases/mysql-family-collector.js.map +1 -0
  17. package/dist/databases/mysql-family-server.d.ts +5 -3
  18. package/dist/databases/mysql-family-server.d.ts.map +1 -1
  19. package/dist/databases/mysql-family-server.js +22 -15
  20. package/dist/databases/mysql-family-server.js.map +1 -1
  21. package/dist/databases/mysql.d.ts +1 -1
  22. package/dist/databases/mysql.d.ts.map +1 -1
  23. package/dist/databases/mysql.js +2 -1
  24. package/dist/databases/mysql.js.map +1 -1
  25. package/dist/databases/postgres-collector.d.ts +9 -0
  26. package/dist/databases/postgres-collector.d.ts.map +1 -0
  27. package/dist/databases/postgres-collector.js +28 -0
  28. package/dist/databases/postgres-collector.js.map +1 -0
  29. package/dist/databases/postgres.d.ts.map +1 -1
  30. package/dist/databases/postgres.js +13 -8
  31. package/dist/databases/postgres.js.map +1 -1
  32. package/dist/databases/sqlite.d.ts.map +1 -1
  33. package/dist/databases/sqlite.js +2 -3
  34. package/dist/databases/sqlite.js.map +1 -1
  35. package/dist/databases/sqlserver-collector.d.ts +13 -0
  36. package/dist/databases/sqlserver-collector.d.ts.map +1 -0
  37. package/dist/databases/sqlserver-collector.js +42 -0
  38. package/dist/databases/sqlserver-collector.js.map +1 -0
  39. package/dist/databases/sqlserver.d.ts.map +1 -1
  40. package/dist/databases/sqlserver.js +15 -20
  41. package/dist/databases/sqlserver.js.map +1 -1
  42. package/dist/databases/succeeded.d.ts +3 -3
  43. package/dist/databases/succeeded.d.ts.map +1 -1
  44. package/dist/databases/succeeded.js +2 -2
  45. package/dist/databases/succeeded.js.map +1 -1
  46. package/dist/fs/temporary-files.d.ts +15 -0
  47. package/dist/fs/temporary-files.d.ts.map +1 -0
  48. package/dist/fs/temporary-files.js +21 -0
  49. package/dist/fs/temporary-files.js.map +1 -0
  50. package/dist/http/http-server.d.ts +0 -6
  51. package/dist/http/http-server.d.ts.map +1 -1
  52. package/dist/http/http-server.js +0 -8
  53. package/dist/http/http-server.js.map +1 -1
  54. package/dist/msw/msw.d.ts +15 -0
  55. package/dist/msw/msw.d.ts.map +1 -0
  56. package/dist/msw/msw.js +17 -0
  57. package/dist/msw/msw.js.map +1 -0
  58. package/dist/scripts/run-cleanup.d.ts.map +1 -1
  59. package/dist/scripts/run-cleanup.js +96 -0
  60. package/dist/scripts/run-cleanup.js.map +1 -1
  61. package/package.json +21 -4
package/README.md CHANGED
@@ -1,12 +1,12 @@
1
1
  # @zukhruf/testing
2
2
 
3
- Disposable fixtures for integration tests on Node.js: Docker containers and database servers, SQLite and DuckDB databases, BigQuery datasets, HTTP servers and controlled streams. Each acquisition returns a handle that `await using` cleans up, also when the test fails. A background server has no handle: it lives until the process exits. Node's global setup and global teardown remove what a killed test run left behind.
3
+ Disposable fixtures for integration tests on Node.js: Docker containers and database servers, SQLite and DuckDB databases, BigQuery datasets, HTTP servers and controlled streams. Each acquisition returns a handle that `await using` cleans up, also when the test fails. Node's global setup and global teardown remove what a killed test run left behind.
4
4
 
5
5
  The words in these documents have one meaning each. See the glossary in [CONTEXT.md](./CONTEXT.md).
6
6
 
7
7
  ## Areas
8
8
 
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.
9
+ Each area has its own import path, so a test loads only the drivers it uses. The four drivers are optional peer dependencies: install the one an area names.
10
10
 
11
11
  | Import | Gives | Needs |
12
12
  | ----------------------------- | ------------------------------------------------------------------ | ------------------------ |
@@ -23,6 +23,8 @@ Each area has its own import path, so a test loads only the drivers it uses. The
23
23
  | `@zukhruf/testing/bigquery` | `BigQuery` | `@google-cloud/bigquery` |
24
24
  | `@zukhruf/testing/http` | `HttpServer` | |
25
25
  | `@zukhruf/testing/streams` | `StreamHarness` | |
26
+ | `@zukhruf/testing/fs` | `TemporaryFiles` | |
27
+ | `@zukhruf/testing/msw` | `Msw` | `msw` |
26
28
 
27
29
  ## Parameterized tests
28
30
 
@@ -140,9 +142,9 @@ Then give the file to `node --test`. The value is a path relative to the working
140
142
  node --test --test-force-exit --test-global-setup=src/testing/docker-global-setup.ts "src/**/*.test.ts"
141
143
  ```
142
144
 
143
- The global setup sets `ZUKHRUF_TESTING_RUN_ID` and `ZUKHRUF_TESTING_RUN_DIR` for the test processes. A `DockerFixtures` reads them from its `environment` and labels what it creates with the run. It records SSH forwards and host directories in the run's directory. It also writes a process record for its test process, and for each SSH command that it starts, while that command runs. While it asks the engine to create a container, it writes a creating record.
145
+ The global setup sets `ZUKHRUF_TESTING_RUN_ID` and `ZUKHRUF_TESTING_RUN_DIR` for the test processes. A `DockerFixtures` reads them from its `environment` and labels what it creates with the run. It records SSH forwards and host directories in the run's directory. It also writes a process record for its test process, and for each SSH command that it starts, while that command runs. While it asks the engine to create a container, it writes a creating record. In a run, `database()` puts the run's id in the name of each database that it creates on a shared server: `test_<run id>_<16 hex>`.
144
146
 
145
- The global teardown removes the labeled containers with their anonymous volumes, the labeled volumes and the recorded paths. It never removes shared servers. The teardown is synchronous, because Node does not wait for an asynchronous teardown under `--test-force-exit`. When every recorded process has ended, the teardown deletes the run's records. A recorded process that still runs can still create a container. The engine can also finish a create after the test process that sent it was killed. Then the teardown keeps the records, and a later run removes what is left after that process ends.
147
+ The global teardown removes the labeled containers with their anonymous volumes, the labeled volumes and the recorded paths. On each running shared server of `Postgres`, `Mysql`, `Mariadb` and `SqlServer`, it drops the databases whose name has the run's id ([ADR 0011](./docs/adr/0011-the-run-id-in-a-databases-name-is-its-owner-reference-and-one-collector-for-each-kind-drops-a-dead-runs-databases.md)). It skips a kind whose driver the project did not install. It never removes shared servers. The teardown is synchronous, because Node does not wait for an asynchronous teardown under `--test-force-exit`. When every recorded process has ended, the teardown deletes the run's records. A recorded process that still runs can still create a container. The engine can also finish a create after the test process that sent it was killed. Then the teardown keeps the records, and a later run removes what is left after that process ends.
146
148
 
147
149
  If cleanup fails, for example because the engine is unreachable, the global teardown prints the error, keeps the run's records, and sets exit code 1. The next run on the same engine removes what the run left, from any project of this user. This is recovery. Recovery does not touch a run while its runner or one of its recorded processes lives. The records are in `$XDG_STATE_HOME/zukhruf-testing/docker-runs` (`~/.local/state/zukhruf-testing/docker-runs` by default). Do not delete a record to hide a cleanup failure.
148
150
 
@@ -154,7 +156,7 @@ To pass the run to another container API, spread `docker.defaults`: it holds the
154
156
 
155
157
  ## Databases
156
158
 
157
- `Postgres`, `Mysql`, `Mariadb`, `SqlServer` and `ClickHouse` take the `environment`, such as `process.env`. The environment selects the engine and the run. Each instance makes its own `DockerFixtures` from it. Each `database()` call creates a fresh database on a shared server; disposal drops it. `start()` creates a dedicated server; disposal stops it.
159
+ `Postgres`, `Mysql`, `Mariadb`, `SqlServer` and `ClickHouse` take the `environment`, such as `process.env`. The environment selects the engine and the run. Each instance makes its own `DockerFixtures` from it. Each `database()` call creates a fresh database on a shared server; disposal drops it. In a run, the name of the database has the run's id. When a test process is killed before its disposal, or a drop in disposal fails, the global teardown drops the database (see [A killed run](#a-killed-run)). Outside a run, only disposal drops it. `start()` creates a dedicated server; disposal stops it.
158
160
 
159
161
  ```ts
160
162
  import { Postgres } from '@zukhruf/testing/postgres';
@@ -179,25 +181,111 @@ The handle has `connectionString`, `host`, `port`, `user`, `password`, `database
179
181
 
180
182
  `new HttpServer().start(handler)` listens on `127.0.0.1` on a free port and resolves once it listens. The handle has `origin` and the native `server`. Disposal closes active connections and waits for the server to close.
181
183
 
182
- Some modules read an origin when they load, so every test in the file uses the same server. `background(handler)` starts a background server for them. It listens until the process exits and never keeps the process running, also while a connection to it is open. It returns only `origin`, because nothing disposes it. Use `start` when only one test reads the origin.
184
+ The handler is a Node.js request listener. A web framework gives one for its fetch handler: `getRequestListener((request) => app.fetch(request))` from `@hono/node-server`, or `toNodeHandler((request) => auth.handler(request))` from `better-auth/node`. The handler can be async. When it rejects, the rejection stays unhandled and fails the process, as a throw does. The server never answers for a handler that failed. A handler that needs the origin can read a `const` that the test declares after the acquisition: no request arrives before the test gives the origin to a client.
185
+
186
+ `StreamHarness` gives a controlled producer, `source<T>()`, with `enqueue`, `close`, `error` and a read-only `state`, and a disposable `reader(stream)` that locks a stream without reading ahead. `collectUntilError()` returns the remaining chunks and either `completed` or `errored` with the error.
187
+
188
+ ## Waiting
189
+
190
+ `timebox(fn, options)` retries `fn` until it stops throwing, every 250 ms for at most 30 seconds by default. It takes every p-retry option. `settleWithin(promise, label, ms)` rejects when a promise that cannot be cancelled does not settle in time. When an operation accepts an `AbortSignal`, pass `AbortSignal.timeout(ms)` to it instead.
191
+
192
+ ## Temporary directories
193
+
194
+ `new TemporaryFiles().directory(prefix)` creates an empty directory in `os.tmpdir()`. Its name starts with `prefix`. The handle has `path` and `cleanup`. Disposal removes the directory and all that it holds.
183
195
 
184
196
  ```ts
185
- import { HttpServer } from '@zukhruf/testing/http';
197
+ import { TemporaryFiles } from '@zukhruf/testing/fs';
198
+
199
+ const files = new TemporaryFiles();
186
200
 
187
- const keys = await new HttpServer().background((request, response) => {
188
- response.end(JSON.stringify(jwks));
201
+ test('writes the report', async (t) => {
202
+ await using directory = await files.directory('report-');
203
+ await writeReport(join(directory.path, 'report.json'));
204
+ t.assert.ok(existsSync(join(directory.path, 'report.json')));
189
205
  });
190
- process.env.KEYS_URL = keys.origin;
191
- const { verify } = await import('./verify.ts');
192
206
  ```
193
207
 
194
- The handler is a Node.js request listener. A web framework gives one for its fetch handler: `getRequestListener((request) => app.fetch(request))` from `@hono/node-server`, or `toNodeHandler((request) => auth.handler(request))` from `better-auth/node`. The handler can be async. When it rejects, the rejection stays unhandled and fails the process, as a throw does. The server never answers for a handler that failed. A handler that needs the origin can read a `const` that the test declares after the acquisition: no request arrives before the test gives the origin to a client.
208
+ `path` is the real path: the acquisition resolves symbolic links. On macOS, `os.tmpdir()` is below `/var`, and `/var` is a link to `/private/var`. git, a child process and a bind mount give the resolved path. Thus a test can compare their output with `path` directly.
195
209
 
196
- `StreamHarness` gives a controlled producer, `source<T>()`, with `enqueue`, `close`, `error` and a read-only `state`, and a disposable `reader(stream)` that locks a stream without reading ahead. `collectUntilError()` returns the remaining chunks and either `completed` or `errored` with the error.
210
+ On Windows, a process that still holds a file open stops its removal for a short time. Thus disposal retries the removal on `EBUSY`, `EMFILE`, `ENFILE`, `ENOTEMPTY` and `EPERM`. It retries 8 times, and it waits 50 ms longer before each retry: 50 + 100 + … + 400 = 1.8 s at most. A removal that does not fail does not wait. When the last retry fails, disposal rejects with the error.
197
211
 
198
- ## Waiting
212
+ The only option is `parent`, the directory that holds the new directory. The default is `os.tmpdir()`. A Unix socket path has a limit of 104 bytes on macOS and 108 bytes on Linux. On macOS, the real path of `os.tmpdir()` uses 56 of them. Thus give a short parent, such as `/tmp`, for a socket. Node resolves a package from the parent directories of the file that imports it. Thus give a parent in the repository when a file in the directory imports a package of the repository.
199
213
 
200
- `timebox(fn, options)` retries `fn` until it stops throwing, every 250 ms for at most 30 seconds by default. It takes every p-retry option. `settleWithin(promise, label, ms)` rejects when a promise that cannot be cancelled does not settle in time. When an operation accepts an `AbortSignal`, pass `AbortSignal.timeout(ms)` to it instead.
214
+ ## Environment variables
215
+
216
+ A test does not change `process.env`. Tests in one file can run at the same time, and `process.env` is one object for the whole process. Thus a value that one test sets is also the value of the other tests. [ADR 0009](./docs/adr/0009-a-test-never-changes-the-environment-of-its-process.md) records this decision.
217
+
218
+ Give the environment, or the value, to the code under test. `new Postgres({ environment })` takes the environment in this way ([ADR 0007](./docs/adr/0007-a-database-fixture-takes-the-environment.md)). Give a time zone as the `timeZone` of `Intl.DateTimeFormat`. Give a home directory as a parameter. Do not read it from `os.homedir()` in the test.
219
+
220
+ A child process gets its own environment when it starts. Give the values to the child as `env`:
221
+
222
+ ```ts
223
+ import { spawn } from 'node:child_process';
224
+
225
+ spawn(command, args, { env: { ...process.env, REGION: 'eu-west-1' } });
226
+ ```
227
+
228
+ To put a directory first on the `PATH` of a child, join it with `path.delimiter`, which is `:` on Unix and `;` on Windows. Remove an unset `PATH` before the join. On Unix, an empty entry is the current directory:
229
+
230
+ ```ts
231
+ import path from 'node:path';
232
+
233
+ spawn(command, args, {
234
+ env: {
235
+ ...process.env,
236
+ PATH: [binDirectory, process.env.PATH].filter(Boolean).join(path.delimiter),
237
+ },
238
+ });
239
+ ```
240
+
241
+ ## Intercepted requests
242
+
243
+ `new Msw().intercept(...handlers)` starts an msw server in this process with the handlers, and returns an interception. The handle has `server`, `requests` and `cleanup`. Disposal closes the server.
244
+
245
+ ```ts
246
+ import { HttpResponse, http } from 'msw';
247
+
248
+ import { Msw } from '@zukhruf/testing/msw';
249
+
250
+ const msw = new Msw();
251
+
252
+ test('sends the token', async (t) => {
253
+ using interception = msw.intercept(
254
+ http.get('https://api.example.com/user', () =>
255
+ HttpResponse.json({ id: 1 }),
256
+ ),
257
+ );
258
+ await fetchUser('token');
259
+ t.assert.equal(
260
+ interception.requests[0].headers.get('authorization'),
261
+ 'Bearer token',
262
+ );
263
+ });
264
+ ```
265
+
266
+ An interception is always strict: the server listens with `onUnhandledFrame: 'error'`. A request that no handler answers fails: `fetch` rejects, and the cause is the msw error "Cannot bypass a request when using the "error" strategy". msw also prints the method and the URL of the request. There is no option for a different strategy.
267
+
268
+ `requests` holds a clone of each request that the server receives, in the order of arrival. A clone keeps its body, so the test can read the body after a handler read the original.
269
+
270
+ `server` is the msw server, of the type `SetupServer` from `msw/node`. Use `interception.server.use(...handlers)` to add handlers for a part of the test.
271
+
272
+ An interception also receives the requests to a local server, such as an `HttpServer` of the same test. To send them to that server, give a handler for the origin of that server. The handler passes each of its requests through:
273
+
274
+ ```ts
275
+ import { http, passthrough } from 'msw';
276
+
277
+ import { HttpServer } from '@zukhruf/testing/http';
278
+
279
+ await using local = await new HttpServer().start(handler);
280
+ using interception = msw.intercept(
281
+ http.all(`${local.origin}/*`, () => passthrough()),
282
+ http.get('https://api.example.com/user', () => HttpResponse.json({ id: 1 })),
283
+ );
284
+ ```
285
+
286
+ Do not use a catch-all handler, such as `http.all('*', …)`, that returns nothing for some requests. msw then sends each of those requests to the network, and the strict strategy has no effect. msw 3.0.2 does this.
287
+
288
+ The driver is msw 3 (`msw ^3.0.3`), which needs Node.js 22.12 or later. Install it next to this package.
201
289
 
202
290
  ## Development
203
291
 
@@ -1 +1 @@
1
- {"version":3,"file":"clickhouse.d.ts","sourceRoot":"","sources":["../../src/databases/clickhouse.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,KAAK,qBAAqB,EAC3B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AAGvE,kFAAkF;AAClF,qBAAa,UAAU;;gBAIT,EACV,WAAW,EACX,KAAK,GACN,EAAE,qBAAqB,GAAG;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE;IAK5C,KAAK,IAAI,OAAO,CAAC,gBAAgB,CAAC;CAcnC"}
1
+ {"version":3,"file":"clickhouse.d.ts","sourceRoot":"","sources":["../../src/databases/clickhouse.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,KAAK,qBAAqB,EAC3B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AAGvE,kFAAkF;AAClF,qBAAa,UAAU;;gBAIT,EACV,WAAW,EACX,KAAK,GACN,EAAE,qBAAqB,GAAG;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE;IAK5C,KAAK,IAAI,OAAO,CAAC,gBAAgB,CAAC;CAkBnC"}
@@ -15,7 +15,11 @@ export class ClickHouse {
15
15
  internalPort: 8123,
16
16
  memory: '2g',
17
17
  env: { CLICKHOUSE_SKIP_USER_SETUP: '1' },
18
- healthy: (service) => timebox(() => succeeded(service, ['clickhouse-client', '--query', 'SELECT 1']), { maxRetryTime: 60_000 }),
18
+ healthy: (service) => timebox(() => succeeded(service.container, [
19
+ 'clickhouse-client',
20
+ '--query',
21
+ 'SELECT 1',
22
+ ]), { maxRetryTime: 60_000 }),
19
23
  });
20
24
  }
21
25
  }
@@ -1 +1 @@
1
- {"version":3,"file":"clickhouse.js","sourceRoot":"","sources":["../../src/databases/clickhouse.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAC9C,OAAO,EACL,cAAc,GAEf,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE3C,kFAAkF;AAClF,MAAM,OAAO,UAAU;IACZ,OAAO,CAAiB;IACxB,MAAM,CAAS;IAExB,YAAY,EACV,WAAW,EACX,KAAK,GACqC;QAC1C,IAAI,CAAC,OAAO,GAAG,IAAI,cAAc,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC;QACnD,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;IACtB,CAAC;IAED,KAAK;QACH,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC;YACxB,KAAK,EAAE,IAAI,CAAC,MAAM;YAClB,YAAY,EAAE,IAAI;YAClB,MAAM,EAAE,IAAI;YACZ,GAAG,EAAE,EAAE,0BAA0B,EAAE,GAAG,EAAE;YACxC,OAAO,EAAE,CAAC,OAAO,EAAE,EAAE,CACnB,OAAO,CACL,GAAG,EAAE,CACH,SAAS,CAAC,OAAO,EAAE,CAAC,mBAAmB,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC,EAClE,EAAE,YAAY,EAAE,MAAM,EAAE,CACzB;SACJ,CAAC,CAAC;IACL,CAAC;CACF"}
1
+ {"version":3,"file":"clickhouse.js","sourceRoot":"","sources":["../../src/databases/clickhouse.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAC9C,OAAO,EACL,cAAc,GAEf,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE3C,kFAAkF;AAClF,MAAM,OAAO,UAAU;IACZ,OAAO,CAAiB;IACxB,MAAM,CAAS;IAExB,YAAY,EACV,WAAW,EACX,KAAK,GACqC;QAC1C,IAAI,CAAC,OAAO,GAAG,IAAI,cAAc,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC;QACnD,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;IACtB,CAAC;IAED,KAAK;QACH,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC;YACxB,KAAK,EAAE,IAAI,CAAC,MAAM;YAClB,YAAY,EAAE,IAAI;YAClB,MAAM,EAAE,IAAI;YACZ,GAAG,EAAE,EAAE,0BAA0B,EAAE,GAAG,EAAE;YACxC,OAAO,EAAE,CAAC,OAAO,EAAE,EAAE,CACnB,OAAO,CACL,GAAG,EAAE,CACH,SAAS,CAAC,OAAO,CAAC,SAAS,EAAE;gBAC3B,mBAAmB;gBACnB,SAAS;gBACT,UAAU;aACX,CAAC,EACJ,EAAE,YAAY,EAAE,MAAM,EAAE,CACzB;SACJ,CAAC,CAAC;IACL,CAAC;CACF"}
@@ -0,0 +1,34 @@
1
+ import type { Container } from '@zukhruf/docker';
2
+ import type { DockerHost } from '../docker/host.ts';
3
+ import type { TestRun } from '../docker/test-run.ts';
4
+ /** The kind of a database fixture's shared server: it names the collector of the server. */
5
+ export declare const KIND_LABEL = "dev.zukhruf.testing.kind";
6
+ export type Kind = 'postgres' | 'mysql' | 'mariadb' | 'sqlserver';
7
+ /**
8
+ * The name of a database that `database()` creates. In a run, the name holds
9
+ * the run's id, its owner reference (ADR 0011).
10
+ */
11
+ export declare const databaseName: (run: TestRun | undefined) => string;
12
+ /**
13
+ * The databases of one server kind: `list` gives the names of the server's
14
+ * test databases, and `drop` drops one. Disposal and the run's cleanup both
15
+ * drop with `drop`.
16
+ */
17
+ export interface Collector<Server> {
18
+ readonly kind: Kind;
19
+ /**
20
+ * The running shared server `container`, with the credentials of
21
+ * `environment`, its `Config.Env`. Disposal closes what it opened.
22
+ */
23
+ open(container: Container, environment: Record<string, string>, host: DockerHost): Promise<Server & AsyncDisposable>;
24
+ /** Each database whose name starts with `test`, a superset of a run's. */
25
+ list(server: Server): Promise<string[]>;
26
+ /** Drops the database `name` if it exists. */
27
+ drop(server: Server, name: string): Promise<void>;
28
+ }
29
+ /**
30
+ * Whether `name` is a database of the run `runId`. `_` is a wildcard of
31
+ * SQL's LIKE, so only the exact name pattern proves a run's database.
32
+ */
33
+ export declare const ownedBy: (runId: string) => (name: string) => boolean;
34
+ //# sourceMappingURL=collector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"collector.d.ts","sourceRoot":"","sources":["../../src/databases/collector.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAEjD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAErD,4FAA4F;AAC5F,eAAO,MAAM,UAAU,6BAA6B,CAAC;AAErD,MAAM,MAAM,IAAI,GAAG,UAAU,GAAG,OAAO,GAAG,SAAS,GAAG,WAAW,CAAC;AAIlE;;;GAGG;AACH,eAAO,MAAM,YAAY,GAAI,KAAK,OAAO,GAAG,SAAS,KAAG,MAGvB,CAAC;AAElC;;;;GAIG;AACH,MAAM,WAAW,SAAS,CAAC,MAAM;IAC/B,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;IACpB;;;OAGG;IACH,IAAI,CACF,SAAS,EAAE,SAAS,EACpB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EACnC,IAAI,EAAE,UAAU,GACf,OAAO,CAAC,MAAM,GAAG,eAAe,CAAC,CAAC;IACrC,0EAA0E;IAC1E,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IACxC,8CAA8C;IAC9C,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACnD;AAED;;;GAGG;AACH,eAAO,MAAM,OAAO,GACjB,OAAO,MAAM,MACb,MAAM,MAAM,KAAG,OAKf,CAAC"}
@@ -0,0 +1,20 @@
1
+ import { randomBytes, randomUUID } from 'node:crypto';
2
+ /** The kind of a database fixture's shared server: it names the collector of the server. */
3
+ export const KIND_LABEL = 'dev.zukhruf.testing.kind';
4
+ const hex = (runId) => runId.replaceAll('-', '');
5
+ /**
6
+ * The name of a database that `database()` creates. In a run, the name holds
7
+ * the run's id, its owner reference (ADR 0011).
8
+ */
9
+ export const databaseName = (run) => run
10
+ ? `test_${hex(run.id)}_${randomBytes(8).toString('hex')}`
11
+ : `test_${hex(randomUUID())}`;
12
+ /**
13
+ * Whether `name` is a database of the run `runId`. `_` is a wildcard of
14
+ * SQL's LIKE, so only the exact name pattern proves a run's database.
15
+ */
16
+ export const ownedBy = (runId) => (name) => {
17
+ const prefix = `test_${hex(runId)}_`;
18
+ return (name.startsWith(prefix) && /^[\da-f]{16}$/.test(name.slice(prefix.length)));
19
+ };
20
+ //# sourceMappingURL=collector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"collector.js","sourceRoot":"","sources":["../../src/databases/collector.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAOtD,4FAA4F;AAC5F,MAAM,CAAC,MAAM,UAAU,GAAG,0BAA0B,CAAC;AAIrD,MAAM,GAAG,GAAG,CAAC,KAAa,EAAU,EAAE,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;AAEjE;;;GAGG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,GAAwB,EAAU,EAAE,CAC/D,GAAG;IACD,CAAC,CAAC,QAAQ,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,WAAW,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE;IACzD,CAAC,CAAC,QAAQ,GAAG,CAAC,UAAU,EAAE,CAAC,EAAE,CAAC;AAwBlC;;;GAGG;AACH,MAAM,CAAC,MAAM,OAAO,GAClB,CAAC,KAAa,EAAE,EAAE,CAClB,CAAC,IAAY,EAAW,EAAE;IACxB,MAAM,MAAM,GAAG,QAAQ,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC;IACrC,OAAO,CACL,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAC3E,CAAC;AACJ,CAAC,CAAC"}
@@ -4,8 +4,7 @@ export type { Database, DatabaseOptions } from './database.ts';
4
4
  export type MariadbOptions = DatabaseOptions;
5
5
  export type MariadbDatabase = MysqlFamilyDatabase;
6
6
  export declare class Mariadb extends MysqlFamilyServer {
7
- /** MariaDB 11 and later ship only the mariadb client, not mysql. */
8
- protected readonly client = "mariadb";
7
+ protected readonly collector: import("./mysql-family-collector.ts").MysqlFamilyCollector;
9
8
  protected readonly scheme = "mariadb";
10
9
  constructor({ image, ...options }: MariadbOptions);
11
10
  protected environment(password: string, database: string): {
@@ -1 +1 @@
1
- {"version":3,"file":"mariadb.d.ts","sourceRoot":"","sources":["../../src/databases/mariadb.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,EACL,KAAK,mBAAmB,EACxB,iBAAiB,EAClB,MAAM,0BAA0B,CAAC;AAElC,YAAY,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAE/D,MAAM,MAAM,cAAc,GAAG,eAAe,CAAC;AAE7C,MAAM,MAAM,eAAe,GAAG,mBAAmB,CAAC;AAElD,qBAAa,OAAQ,SAAQ,iBAAiB;IAC5C,oEAAoE;IACpE,mBAA4B,MAAM,aAAa;IAC/C,mBAA4B,MAAM,aAAa;gBAEnC,EAAE,KAAqB,EAAE,GAAG,OAAO,EAAE,EAAE,cAAc;cAI9C,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM;;;;CAGlE"}
1
+ {"version":3,"file":"mariadb.d.ts","sourceRoot":"","sources":["../../src/databases/mariadb.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAErD,OAAO,EACL,KAAK,mBAAmB,EACxB,iBAAiB,EAClB,MAAM,0BAA0B,CAAC;AAElC,YAAY,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAE/D,MAAM,MAAM,cAAc,GAAG,eAAe,CAAC;AAE7C,MAAM,MAAM,eAAe,GAAG,mBAAmB,CAAC;AAElD,qBAAa,OAAQ,SAAQ,iBAAiB;IAC5C,mBAA4B,SAAS,6DAAW;IAChD,mBAA4B,MAAM,aAAa;gBAEnC,EAAE,KAAqB,EAAE,GAAG,OAAO,EAAE,EAAE,cAAc;cAI9C,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM;;;;CAGlE"}
@@ -1,7 +1,7 @@
1
+ import { mariadb } from "./mysql-family-collector.js";
1
2
  import { MysqlFamilyServer, } from "./mysql-family-server.js";
2
3
  export class Mariadb extends MysqlFamilyServer {
3
- /** MariaDB 11 and later ship only the mariadb client, not mysql. */
4
- client = 'mariadb';
4
+ collector = mariadb;
5
5
  scheme = 'mariadb';
6
6
  constructor({ image = 'mariadb:lts', ...options }) {
7
7
  super({ ...options, image });
@@ -1 +1 @@
1
- {"version":3,"file":"mariadb.js","sourceRoot":"","sources":["../../src/databases/mariadb.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,iBAAiB,GAClB,MAAM,0BAA0B,CAAC;AAQlC,MAAM,OAAO,OAAQ,SAAQ,iBAAiB;IAC5C,oEAAoE;IACxC,MAAM,GAAG,SAAS,CAAC;IACnB,MAAM,GAAG,SAAS,CAAC;IAE/C,YAAY,EAAE,KAAK,GAAG,aAAa,EAAE,GAAG,OAAO,EAAkB;QAC/D,KAAK,CAAC,EAAE,GAAG,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;IAC/B,CAAC;IAEkB,WAAW,CAAC,QAAgB,EAAE,QAAgB;QAC/D,OAAO,EAAE,qBAAqB,EAAE,QAAQ,EAAE,gBAAgB,EAAE,QAAQ,EAAE,CAAC;IACzE,CAAC;CACF"}
1
+ {"version":3,"file":"mariadb.js","sourceRoot":"","sources":["../../src/databases/mariadb.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,6BAA6B,CAAC;AACtD,OAAO,EAEL,iBAAiB,GAClB,MAAM,0BAA0B,CAAC;AAQlC,MAAM,OAAO,OAAQ,SAAQ,iBAAiB;IAChB,SAAS,GAAG,OAAO,CAAC;IACpB,MAAM,GAAG,SAAS,CAAC;IAE/C,YAAY,EAAE,KAAK,GAAG,aAAa,EAAE,GAAG,OAAO,EAAkB;QAC/D,KAAK,CAAC,EAAE,GAAG,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;IAC/B,CAAC;IAEkB,WAAW,CAAC,QAAgB,EAAE,QAAgB;QAC/D,OAAO,EAAE,qBAAqB,EAAE,QAAQ,EAAE,gBAAgB,EAAE,QAAQ,EAAE,CAAC;IACzE,CAAC;CACF"}
@@ -0,0 +1,16 @@
1
+ import type { Container } from '@zukhruf/docker';
2
+ import type { Collector } from './collector.ts';
3
+ export interface MysqlFamilyServer {
4
+ container: Container;
5
+ password: string;
6
+ }
7
+ /** The image creates only root, from the root password in its environment. */
8
+ export declare const user = "root";
9
+ export interface MysqlFamilyCollector extends Collector<MysqlFamilyServer> {
10
+ /** The client in the image. */
11
+ readonly client: string;
12
+ }
13
+ export declare const mysql: MysqlFamilyCollector;
14
+ /** MariaDB 11 and later ship only the mariadb client, not mysql. */
15
+ export declare const mariadb: MysqlFamilyCollector;
16
+ //# sourceMappingURL=mysql-family-collector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mysql-family-collector.d.ts","sourceRoot":"","sources":["../../src/databases/mysql-family-collector.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAEjD,OAAO,KAAK,EAAE,SAAS,EAAQ,MAAM,gBAAgB,CAAC;AAGtD,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,SAAS,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,8EAA8E;AAC9E,eAAO,MAAM,IAAI,SAAS,CAAC;AAE3B,MAAM,WAAW,oBAAqB,SAAQ,SAAS,CAAC,iBAAiB,CAAC;IACxE,+BAA+B;IAC/B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAyCD,eAAO,MAAM,KAAK,sBAAuD,CAAC;AAC1E,oEAAoE;AACpE,eAAO,MAAM,OAAO,sBAInB,CAAC"}
@@ -0,0 +1,36 @@
1
+ import { succeeded } from "./succeeded.js";
2
+ /** The image creates only root, from the root password in its environment. */
3
+ export const user = 'root';
4
+ /** Runs the image's client in the server's container. */
5
+ function mysqlFamily(kind, client, passwordVariable) {
6
+ const execute = ({ container, password }, args) => succeeded(container, [client, `-u${user}`, `-p${password}`, ...args]);
7
+ return {
8
+ kind,
9
+ client,
10
+ async open(container, environment) {
11
+ const password = environment[passwordVariable];
12
+ if (password === undefined)
13
+ throw new Error(`The ${kind} server ${container.id} has no ${passwordVariable}`);
14
+ return { container, password, [Symbol.asyncDispose]: async () => { } };
15
+ },
16
+ async list(server) {
17
+ const stdout = await execute(server, [
18
+ '--batch',
19
+ '--skip-column-names',
20
+ '--execute',
21
+ "SHOW DATABASES LIKE 'test%'",
22
+ ]);
23
+ return stdout.split('\n').filter(Boolean);
24
+ },
25
+ async drop(server, name) {
26
+ await execute(server, [
27
+ '--execute',
28
+ `DROP DATABASE IF EXISTS \`${name}\``,
29
+ ]);
30
+ },
31
+ };
32
+ }
33
+ export const mysql = mysqlFamily('mysql', 'mysql', 'MYSQL_ROOT_PASSWORD');
34
+ /** MariaDB 11 and later ship only the mariadb client, not mysql. */
35
+ export const mariadb = mysqlFamily('mariadb', 'mariadb', 'MARIADB_ROOT_PASSWORD');
36
+ //# sourceMappingURL=mysql-family-collector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mysql-family-collector.js","sourceRoot":"","sources":["../../src/databases/mysql-family-collector.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAO3C,8EAA8E;AAC9E,MAAM,CAAC,MAAM,IAAI,GAAG,MAAM,CAAC;AAO3B,yDAAyD;AACzD,SAAS,WAAW,CAClB,IAAU,EACV,MAAc,EACd,gBAAwB;IAExB,MAAM,OAAO,GAAG,CACd,EAAE,SAAS,EAAE,QAAQ,EAAqB,EAC1C,IAAc,EACd,EAAE,CAAC,SAAS,CAAC,SAAS,EAAE,CAAC,MAAM,EAAE,KAAK,IAAI,EAAE,EAAE,KAAK,QAAQ,EAAE,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC;IAC3E,OAAO;QACL,IAAI;QACJ,MAAM;QACN,KAAK,CAAC,IAAI,CAAC,SAAS,EAAE,WAAW;YAC/B,MAAM,QAAQ,GAAG,WAAW,CAAC,gBAAgB,CAAC,CAAC;YAC/C,IAAI,QAAQ,KAAK,SAAS;gBACxB,MAAM,IAAI,KAAK,CACb,OAAO,IAAI,WAAW,SAAS,CAAC,EAAE,WAAW,gBAAgB,EAAE,CAChE,CAAC;YACJ,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC,MAAM,CAAC,YAAY,CAAC,EAAE,KAAK,IAAI,EAAE,GAAE,CAAC,EAAE,CAAC;QACxE,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,MAAM;YACf,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,MAAM,EAAE;gBACnC,SAAS;gBACT,qBAAqB;gBACrB,WAAW;gBACX,6BAA6B;aAC9B,CAAC,CAAC;YACH,OAAO,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAC5C,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI;YACrB,MAAM,OAAO,CAAC,MAAM,EAAE;gBACpB,WAAW;gBACX,6BAA6B,IAAI,IAAI;aACtC,CAAC,CAAC;QACL,CAAC;KACF,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,MAAM,KAAK,GAAG,WAAW,CAAC,OAAO,EAAE,OAAO,EAAE,qBAAqB,CAAC,CAAC;AAC1E,oEAAoE;AACpE,MAAM,CAAC,MAAM,OAAO,GAAG,WAAW,CAChC,SAAS,EACT,SAAS,EACT,uBAAuB,CACxB,CAAC"}
@@ -1,16 +1,18 @@
1
1
  import type { Database, DatabaseOptions } from './database.ts';
2
+ import { type MysqlFamilyCollector } from './mysql-family-collector.ts';
2
3
  export interface MysqlFamilyDatabase extends Database {
3
4
  query: (sql: string) => Promise<Record<string, string | null>[]>;
4
5
  }
5
6
  /**
6
7
  * A template method for servers that speak MySQL's protocol and client flags:
7
8
  * acquisitions, readiness, queries and the batch parser stay the same. A
8
- * subclass names the client in its image, the connection string's scheme and
9
- * the environment, and passes its default image to this constructor.
9
+ * subclass names its collector (its kind and the client in its image), the
10
+ * connection string's scheme and the environment, and passes its default
11
+ * image to this constructor.
10
12
  */
11
13
  export declare abstract class MysqlFamilyServer {
12
14
  #private;
13
- protected abstract readonly client: string;
15
+ protected abstract readonly collector: MysqlFamilyCollector;
14
16
  protected abstract readonly scheme: string;
15
17
  protected abstract environment(password: string, database: string): Record<string, string>;
16
18
  constructor({ environment, image, password, database, labels, }: DatabaseOptions & {
@@ -1 +1 @@
1
- {"version":3,"file":"mysql-family-server.d.ts","sourceRoot":"","sources":["../../src/databases/mysql-family-server.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAG/D,MAAM,WAAW,mBAAoB,SAAQ,QAAQ;IACnD,KAAK,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC;CAClE;AAKD;;;;;GAKG;AACH,8BAAsB,iBAAiB;;IAIrC,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAC3C,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAC3C,SAAS,CAAC,QAAQ,CAAC,WAAW,CAC5B,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,GACf,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;gBAEb,EACV,WAAW,EACX,KAAK,EACL,QAAyB,EACzB,QAAgB,EAChB,MAAM,GACP,EAAE,eAAe,GAAG;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE;IAKtC,mEAAmE;IAC7D,QAAQ,IAAI,OAAO,CAAC,mBAAmB,CAAC;IAoB9C,wEAAwE;IAClE,KAAK,IAAI,OAAO,CAAC,mBAAmB,CAAC;CA6G5C"}
1
+ {"version":3,"file":"mysql-family-server.d.ts","sourceRoot":"","sources":["../../src/databases/mysql-family-server.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAC/D,OAAO,EAAE,KAAK,oBAAoB,EAAQ,MAAM,6BAA6B,CAAC;AAG9E,MAAM,WAAW,mBAAoB,SAAQ,QAAQ;IACnD,KAAK,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC;CAClE;AAED;;;;;;GAMG;AACH,8BAAsB,iBAAiB;;IAKrC,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,SAAS,EAAE,oBAAoB,CAAC;IAC5D,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAC3C,SAAS,CAAC,QAAQ,CAAC,WAAW,CAC5B,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,GACf,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;gBAEb,EACV,WAAW,EACX,KAAK,EACL,QAAyB,EACzB,QAAgB,EAChB,MAAM,GACP,EAAE,eAAe,GAAG;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE;IAMtC,mEAAmE;IAC7D,QAAQ,IAAI,OAAO,CAAC,mBAAmB,CAAC;IAqB9C,wEAAwE;IAClE,KAAK,IAAI,OAAO,CAAC,mBAAmB,CAAC;CA6G5C"}
@@ -1,26 +1,33 @@
1
- import { randomUUID } from 'node:crypto';
2
1
  import { timebox } from "../async/timebox.js";
3
2
  import { DockerFixtures } from "../docker/fixtures.js";
3
+ import { TestRun } from "../docker/test-run.js";
4
+ import { KIND_LABEL, databaseName } from "./collector.js";
5
+ import { user } from "./mysql-family-collector.js";
4
6
  import { succeeded } from "./succeeded.js";
5
- /** The image creates only root, from the root password in its environment. */
6
- const user = 'root';
7
7
  /**
8
8
  * A template method for servers that speak MySQL's protocol and client flags:
9
9
  * acquisitions, readiness, queries and the batch parser stay the same. A
10
- * subclass names the client in its image, the connection string's scheme and
11
- * the environment, and passes its default image to this constructor.
10
+ * subclass names its collector (its kind and the client in its image), the
11
+ * connection string's scheme and the environment, and passes its default
12
+ * image to this constructor.
12
13
  */
13
14
  export class MysqlFamilyServer {
14
15
  #docker;
16
+ #run;
15
17
  #options;
16
18
  constructor({ environment, image, password = 'testpassword', database = 'app', labels, }) {
17
19
  this.#docker = new DockerFixtures({ environment });
20
+ this.#run = TestRun.fromEnvironment(environment);
18
21
  this.#options = { image, password, database, labels };
19
22
  }
20
23
  /** Create an isolated database on the persistent shared server. */
21
24
  async database() {
22
25
  const container = await this.#acquire('app', 'reuse');
23
- const database = `test_${randomUUID().replaceAll('-', '')}`;
26
+ const database = databaseName(this.#run);
27
+ const server = {
28
+ container: container.container,
29
+ password: this.#options.password,
30
+ };
24
31
  try {
25
32
  await this.#sql(container, `CREATE DATABASE \`${database}\``);
26
33
  }
@@ -29,8 +36,8 @@ export class MysqlFamilyServer {
29
36
  throw error;
30
37
  }
31
38
  return this.#handle(container, database, async () => {
32
- await this.#sql(container, `DROP DATABASE IF EXISTS \`${database}\``).catch(() => {
33
- /* Best-effort cleanup after external removal. */
39
+ await this.collector.drop(server, database).catch(() => {
40
+ /* Best-effort: the run's cleanup drops a database that disposal left. */
34
41
  });
35
42
  await container.disconnect();
36
43
  });
@@ -43,8 +50,8 @@ export class MysqlFamilyServer {
43
50
  }
44
51
  #sql(container, sql) {
45
52
  const { password } = this.#options;
46
- return succeeded(container, [
47
- this.client,
53
+ return succeeded(container.container, [
54
+ this.collector.client,
48
55
  `-u${user}`,
49
56
  `-p${password}`,
50
57
  '--execute',
@@ -53,8 +60,8 @@ export class MysqlFamilyServer {
53
60
  }
54
61
  async #query(container, database, sql) {
55
62
  const { password } = this.#options;
56
- const stdout = await succeeded(container, [
57
- this.client,
63
+ const stdout = await succeeded(container.container, [
64
+ this.collector.client,
58
65
  `-u${user}`,
59
66
  `-p${password}`,
60
67
  '--database',
@@ -86,7 +93,7 @@ export class MysqlFamilyServer {
86
93
  const { image, password, labels } = this.#options;
87
94
  return this.#docker[mode]({
88
95
  image,
89
- labels,
96
+ labels: { ...labels, [KIND_LABEL]: this.collector.kind },
90
97
  internalPort: 3306,
91
98
  env: this.environment(password, database),
92
99
  tmpfs: ['/var/lib/mysql:rw,size=512m'],
@@ -97,8 +104,8 @@ export class MysqlFamilyServer {
97
104
  #ready(container) {
98
105
  const { password } = this.#options;
99
106
  // TCP excludes the entrypoint's temporary, socket-only initialization server.
100
- return timebox(() => succeeded(container, [
101
- this.client,
107
+ return timebox(() => succeeded(container.container, [
108
+ this.collector.client,
102
109
  '-h',
103
110
  '127.0.0.1',
104
111
  `-u${user}`,
@@ -1 +1 @@
1
- {"version":3,"file":"mysql-family-server.js","sourceRoot":"","sources":["../../src/databases/mysql-family-server.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"mysql-family-server.js","sourceRoot":"","sources":["../../src/databases/mysql-family-server.ts"],"names":[],"mappings":"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"}
@@ -4,7 +4,7 @@ export type { Database, DatabaseOptions } from './database.ts';
4
4
  export type MysqlOptions = DatabaseOptions;
5
5
  export type MysqlDatabase = MysqlFamilyDatabase;
6
6
  export declare class Mysql extends MysqlFamilyServer {
7
- protected readonly client = "mysql";
7
+ protected readonly collector: import("./mysql-family-collector.ts").MysqlFamilyCollector;
8
8
  protected readonly scheme = "mysql";
9
9
  constructor({ image, ...options }: MysqlOptions);
10
10
  protected environment(password: string, database: string): {
@@ -1 +1 @@
1
- {"version":3,"file":"mysql.d.ts","sourceRoot":"","sources":["../../src/databases/mysql.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,EACL,KAAK,mBAAmB,EACxB,iBAAiB,EAClB,MAAM,0BAA0B,CAAC;AAElC,YAAY,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAE/D,MAAM,MAAM,YAAY,GAAG,eAAe,CAAC;AAE3C,MAAM,MAAM,aAAa,GAAG,mBAAmB,CAAC;AAEhD,qBAAa,KAAM,SAAQ,iBAAiB;IAC1C,mBAA4B,MAAM,WAAW;IAC7C,mBAA4B,MAAM,WAAW;gBAEjC,EAAE,KAAmB,EAAE,GAAG,OAAO,EAAE,EAAE,YAAY;cAI1C,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM;;;;CAGlE"}
1
+ {"version":3,"file":"mysql.d.ts","sourceRoot":"","sources":["../../src/databases/mysql.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAErD,OAAO,EACL,KAAK,mBAAmB,EACxB,iBAAiB,EAClB,MAAM,0BAA0B,CAAC;AAElC,YAAY,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAE/D,MAAM,MAAM,YAAY,GAAG,eAAe,CAAC;AAE3C,MAAM,MAAM,aAAa,GAAG,mBAAmB,CAAC;AAEhD,qBAAa,KAAM,SAAQ,iBAAiB;IAC1C,mBAA4B,SAAS,6DAAS;IAC9C,mBAA4B,MAAM,WAAW;gBAEjC,EAAE,KAAmB,EAAE,GAAG,OAAO,EAAE,EAAE,YAAY;cAI1C,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM;;;;CAGlE"}
@@ -1,6 +1,7 @@
1
+ import { mysql } from "./mysql-family-collector.js";
1
2
  import { MysqlFamilyServer, } from "./mysql-family-server.js";
2
3
  export class Mysql extends MysqlFamilyServer {
3
- client = 'mysql';
4
+ collector = mysql;
4
5
  scheme = 'mysql';
5
6
  constructor({ image = 'mysql:lts', ...options }) {
6
7
  super({ ...options, image });
@@ -1 +1 @@
1
- {"version":3,"file":"mysql.js","sourceRoot":"","sources":["../../src/databases/mysql.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,iBAAiB,GAClB,MAAM,0BAA0B,CAAC;AAQlC,MAAM,OAAO,KAAM,SAAQ,iBAAiB;IACd,MAAM,GAAG,OAAO,CAAC;IACjB,MAAM,GAAG,OAAO,CAAC;IAE7C,YAAY,EAAE,KAAK,GAAG,WAAW,EAAE,GAAG,OAAO,EAAgB;QAC3D,KAAK,CAAC,EAAE,GAAG,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;IAC/B,CAAC;IAEkB,WAAW,CAAC,QAAgB,EAAE,QAAgB;QAC/D,OAAO,EAAE,mBAAmB,EAAE,QAAQ,EAAE,cAAc,EAAE,QAAQ,EAAE,CAAC;IACrE,CAAC;CACF"}
1
+ {"version":3,"file":"mysql.js","sourceRoot":"","sources":["../../src/databases/mysql.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,EAAE,MAAM,6BAA6B,CAAC;AACpD,OAAO,EAEL,iBAAiB,GAClB,MAAM,0BAA0B,CAAC;AAQlC,MAAM,OAAO,KAAM,SAAQ,iBAAiB;IACd,SAAS,GAAG,KAAK,CAAC;IAClB,MAAM,GAAG,OAAO,CAAC;IAE7C,YAAY,EAAE,KAAK,GAAG,WAAW,EAAE,GAAG,OAAO,EAAgB;QAC3D,KAAK,CAAC,EAAE,GAAG,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;IAC/B,CAAC;IAEkB,WAAW,CAAC,QAAgB,EAAE,QAAgB;QAC/D,OAAO,EAAE,mBAAmB,EAAE,QAAQ,EAAE,cAAc,EAAE,QAAQ,EAAE,CAAC;IACrE,CAAC;CACF"}
@@ -0,0 +1,9 @@
1
+ import type { Container } from '@zukhruf/docker';
2
+ import type { Collector } from './collector.ts';
3
+ export interface PostgresServer {
4
+ container: Container;
5
+ user: string;
6
+ }
7
+ /** Runs `psql` in the server's container. */
8
+ export declare const postgres: Collector<PostgresServer>;
9
+ //# sourceMappingURL=postgres-collector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"postgres-collector.d.ts","sourceRoot":"","sources":["../../src/databases/postgres-collector.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAEjD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAGhD,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,SAAS,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;CACd;AAKD,6CAA6C;AAC7C,eAAO,MAAM,QAAQ,EAAE,SAAS,CAAC,cAAc,CAuB9C,CAAC"}
@@ -0,0 +1,28 @@
1
+ import { succeeded } from "./succeeded.js";
2
+ const psql = ({ container, user }, args) => succeeded(container, ['psql', '-U', user, '-d', 'postgres', ...args]);
3
+ /** Runs `psql` in the server's container. */
4
+ export const postgres = {
5
+ kind: 'postgres',
6
+ async open(container, environment) {
7
+ return {
8
+ container,
9
+ user: environment.POSTGRES_USER ?? 'postgres',
10
+ [Symbol.asyncDispose]: async () => { },
11
+ };
12
+ },
13
+ async list(server) {
14
+ const stdout = await psql(server, [
15
+ '-At',
16
+ '-c',
17
+ "SELECT datname FROM pg_database WHERE datname LIKE 'test%'",
18
+ ]);
19
+ return stdout.split('\n').filter(Boolean);
20
+ },
21
+ async drop(server, name) {
22
+ await psql(server, [
23
+ '-c',
24
+ `DROP DATABASE IF EXISTS "${name}" WITH (FORCE)`,
25
+ ]);
26
+ },
27
+ };
28
+ //# sourceMappingURL=postgres-collector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"postgres-collector.js","sourceRoot":"","sources":["../../src/databases/postgres-collector.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAO3C,MAAM,IAAI,GAAG,CAAC,EAAE,SAAS,EAAE,IAAI,EAAkB,EAAE,IAAc,EAAE,EAAE,CACnE,SAAS,CAAC,SAAS,EAAE,CAAC,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC;AAExE,6CAA6C;AAC7C,MAAM,CAAC,MAAM,QAAQ,GAA8B;IACjD,IAAI,EAAE,UAAU;IAChB,KAAK,CAAC,IAAI,CAAC,SAAS,EAAE,WAAW;QAC/B,OAAO;YACL,SAAS;YACT,IAAI,EAAE,WAAW,CAAC,aAAa,IAAI,UAAU;YAC7C,CAAC,MAAM,CAAC,YAAY,CAAC,EAAE,KAAK,IAAI,EAAE,GAAE,CAAC;SACtC,CAAC;IACJ,CAAC;IACD,KAAK,CAAC,IAAI,CAAC,MAAM;QACf,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,EAAE;YAChC,KAAK;YACL,IAAI;YACJ,4DAA4D;SAC7D,CAAC,CAAC;QACH,OAAO,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAC5C,CAAC;IACD,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI;QACrB,MAAM,IAAI,CAAC,MAAM,EAAE;YACjB,IAAI;YACJ,4BAA4B,IAAI,gBAAgB;SACjD,CAAC,CAAC;IACL,CAAC;CACF,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"postgres.d.ts","sourceRoot":"","sources":["../../src/databases/postgres.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAG/D,YAAY,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAE/D,MAAM,WAAW,eAAgB,SAAQ,eAAe;IACtD,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,qFAAqF;AACrF,qBAAa,QAAQ;;gBAIP,EACV,WAAW,EACX,KAA4B,EAC5B,QAAyB,EACzB,QAAmB,EACnB,IAAiB,EACjB,MAAM,GACP,EAAE,eAAe;IAKlB,mEAAmE;IAC7D,QAAQ,IAAI,OAAO,CAAC,QAAQ,CAAC;IAoBnC,wEAAwE;IAClE,KAAK,IAAI,OAAO,CAAC,QAAQ,CAAC;CAqFjC"}
1
+ {"version":3,"file":"postgres.d.ts","sourceRoot":"","sources":["../../src/databases/postgres.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAI/D,YAAY,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAE/D,MAAM,WAAW,eAAgB,SAAQ,eAAe;IACtD,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,qFAAqF;AACrF,qBAAa,QAAQ;;gBAKP,EACV,WAAW,EACX,KAA4B,EAC5B,QAAyB,EACzB,QAAmB,EACnB,IAAiB,EACjB,MAAM,GACP,EAAE,eAAe;IAMlB,mEAAmE;IAC7D,QAAQ,IAAI,OAAO,CAAC,QAAQ,CAAC;IAkBnC,wEAAwE;IAClE,KAAK,IAAI,OAAO,CAAC,QAAQ,CAAC;CAqFjC"}