@zukhruf/testing 0.3.3 → 0.3.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/README.md CHANGED
@@ -1,6 +1,6 @@
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 supervisor removes 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. A background server has no handle: it lives until the process exits. A supervisor removes 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
 
@@ -14,6 +14,7 @@ Each area has its own import path, so a test loads only the drivers it uses. The
14
14
  | `@zukhruf/testing/docker` | `Docker`, `Container`, `ServiceContainer`, `DockerVolume`, `DockerDirectory`, `TestRun`, `skipWithoutDocker` | Docker CLI |
15
15
  | `@zukhruf/testing/postgres` | `Postgres` | Docker CLI |
16
16
  | `@zukhruf/testing/mysql` | `Mysql` | Docker CLI |
17
+ | `@zukhruf/testing/mariadb` | `Mariadb` | Docker CLI |
17
18
  | `@zukhruf/testing/sqlserver` | `SqlServer`, `SQL_SERVER_FULL_IMAGE`, `SQL_SERVER_EDGE_IMAGE` | Docker CLI, `mssql` |
18
19
  | `@zukhruf/testing/clickhouse` | `ClickHouse` | Docker CLI |
19
20
  | `@zukhruf/testing/sqlite` | `Sqlite` | |
@@ -103,7 +104,7 @@ To pass the run to another container API, spread `docker.defaults`: it holds the
103
104
 
104
105
  ## Databases
105
106
 
106
- `Postgres`, `Mysql` and `SqlServer` take the `docker` to run on. Each `database()` call creates a fresh database on a shared server; disposal drops it. `start()` creates a dedicated server; disposal stops it.
107
+ `Postgres`, `Mysql`, `Mariadb` and `SqlServer` take the `docker` to run on. Each `database()` call creates a fresh database on a shared server; disposal drops it. `start()` creates a dedicated server; disposal stops it.
107
108
 
108
109
  ```ts
109
110
  import { Postgres } from '@zukhruf/testing/postgres';
@@ -116,7 +117,7 @@ test('stores a record', { skip }, async () => {
116
117
  });
117
118
  ```
118
119
 
119
- The handle has `connectionString`, `host`, `port`, `user`, `password`, `database`, `image` and `containerId`. `Mysql` handles also have `query(sql)`. Without an image, `SqlServer` picks Azure SQL Edge on an ARM engine and SQL Server 2022 elsewhere. `ClickHouse` takes an explicit `image` and starts a dedicated server, so a test can create server-wide users and functions.
120
+ The handle has `connectionString`, `host`, `port`, `user`, `password`, `database`, `image` and `containerId`. `Mysql` and `Mariadb` handles also have `query(sql)`. Without an image, `Mysql` runs `mysql:lts` and `Mariadb` runs `mariadb:lts`. MariaDB 11 and later have no `mysql` client, so use `Mariadb` for a MariaDB image. A `Mariadb` connection string starts with `mariadb://`, because the `mariadb` driver accepts no other scheme. Without an image, `SqlServer` picks Azure SQL Edge on an ARM engine and SQL Server 2022 elsewhere. `ClickHouse` takes an explicit `image` and starts a dedicated server, so a test can create server-wide users and functions.
120
121
 
121
122
  `Sqlite` creates a file-backed database in a temporary directory, with a native `DatabaseSync` connection. Disposal closes the connection and removes the directory, including WAL files. `writeLock(path, durationMs)` holds a write lock from another process, which releases it after `durationMs`, even while the caller blocks in a synchronous write.
122
123
 
@@ -128,6 +129,20 @@ The handle has `connectionString`, `host`, `port`, `user`, `password`, `database
128
129
 
129
130
  `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.
130
131
 
132
+ 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.
133
+
134
+ ```ts
135
+ import { HttpServer } from '@zukhruf/testing/http';
136
+
137
+ const keys = await new HttpServer().background((request, response) => {
138
+ response.end(JSON.stringify(jwks));
139
+ });
140
+ process.env.KEYS_URL = keys.origin;
141
+ const { verify } = await import('./verify.ts');
142
+ ```
143
+
144
+ 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`. 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.
145
+
131
146
  `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.
132
147
 
133
148
  ## Waiting
@@ -0,0 +1,16 @@
1
+ import type { DatabaseOptions } from './database.ts';
2
+ import { type MysqlFamilyDatabase, MysqlFamilyServer } from './mysql-family-server.ts';
3
+ export type { Database, DatabaseOptions } from './database.ts';
4
+ export type MariadbOptions = DatabaseOptions;
5
+ export type MariadbDatabase = MysqlFamilyDatabase;
6
+ export declare class Mariadb extends MysqlFamilyServer {
7
+ /** MariaDB 11 and later ship only the mariadb client, not mysql. */
8
+ protected readonly client = "mariadb";
9
+ protected readonly scheme = "mariadb";
10
+ constructor({ image, ...options }: MariadbOptions);
11
+ protected environment(password: string, database: string): {
12
+ MARIADB_ROOT_PASSWORD: string;
13
+ MARIADB_DATABASE: string;
14
+ };
15
+ }
16
+ //# sourceMappingURL=mariadb.d.ts.map
@@ -0,0 +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"}
@@ -0,0 +1,13 @@
1
+ import { MysqlFamilyServer, } from "./mysql-family-server.js";
2
+ export class Mariadb extends MysqlFamilyServer {
3
+ /** MariaDB 11 and later ship only the mariadb client, not mysql. */
4
+ client = 'mariadb';
5
+ scheme = 'mariadb';
6
+ constructor({ image = 'mariadb:lts', ...options }) {
7
+ super({ ...options, image });
8
+ }
9
+ environment(password, database) {
10
+ return { MARIADB_ROOT_PASSWORD: password, MARIADB_DATABASE: database };
11
+ }
12
+ }
13
+ //# sourceMappingURL=mariadb.js.map
@@ -0,0 +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"}
@@ -0,0 +1,24 @@
1
+ import type { Database, DatabaseOptions } from './database.ts';
2
+ export interface MysqlFamilyDatabase extends Database {
3
+ query: (sql: string) => Promise<Record<string, string | null>[]>;
4
+ }
5
+ /**
6
+ * A template method for servers that speak MySQL's protocol and client flags:
7
+ * 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.
10
+ */
11
+ export declare abstract class MysqlFamilyServer {
12
+ #private;
13
+ protected abstract readonly client: string;
14
+ protected abstract readonly scheme: string;
15
+ protected abstract environment(password: string, database: string): Record<string, string>;
16
+ constructor({ docker, image, password, database, labels, }: DatabaseOptions & {
17
+ image: string;
18
+ });
19
+ /** Create an isolated database on the persistent shared server. */
20
+ database(): Promise<MysqlFamilyDatabase>;
21
+ /** Start a dedicated server; the returned handle owns its container. */
22
+ start(): Promise<MysqlFamilyDatabase>;
23
+ }
24
+ //# sourceMappingURL=mysql-family-server.d.ts.map
@@ -0,0 +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;AAE/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,MAAM,EACN,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"}
@@ -0,0 +1,125 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { timebox } from "../async/timebox.js";
3
+ /** The image creates only root, from the root password in its environment. */
4
+ const user = 'root';
5
+ /**
6
+ * A template method for servers that speak MySQL's protocol and client flags:
7
+ * 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.
10
+ */
11
+ export class MysqlFamilyServer {
12
+ #docker;
13
+ #options;
14
+ constructor({ docker, image, password = 'testpassword', database = 'app', labels, }) {
15
+ this.#docker = docker;
16
+ this.#options = { image, password, database, labels };
17
+ }
18
+ /** Create an isolated database on the persistent shared server. */
19
+ async database() {
20
+ const container = await this.#acquire('app', 'reuse');
21
+ const database = `test_${randomUUID().replaceAll('-', '')}`;
22
+ try {
23
+ await this.#sql(container, `CREATE DATABASE \`${database}\``);
24
+ }
25
+ catch (error) {
26
+ await container.disconnect();
27
+ throw error;
28
+ }
29
+ return this.#handle(container, database, async () => {
30
+ await this.#sql(container, `DROP DATABASE IF EXISTS \`${database}\``).catch(() => {
31
+ /* Best-effort cleanup after external removal. */
32
+ });
33
+ await container.disconnect();
34
+ });
35
+ }
36
+ /** Start a dedicated server; the returned handle owns its container. */
37
+ async start() {
38
+ const { database } = this.#options;
39
+ const container = await this.#acquire(database, 'serve');
40
+ return this.#handle(container, database, () => container.cleanup());
41
+ }
42
+ #sql(container, sql) {
43
+ const { password } = this.#options;
44
+ return container.exec([
45
+ this.client,
46
+ `-u${user}`,
47
+ `-p${password}`,
48
+ '--execute',
49
+ sql,
50
+ ]);
51
+ }
52
+ async #query(container, database, sql) {
53
+ const { password } = this.#options;
54
+ const { stdout } = await container.exec([
55
+ this.client,
56
+ `-u${user}`,
57
+ `-p${password}`,
58
+ '--database',
59
+ database,
60
+ '--batch',
61
+ '--raw',
62
+ '--execute',
63
+ sql,
64
+ ]);
65
+ return this.#parseBatch(stdout);
66
+ }
67
+ #parseBatch(stdout) {
68
+ const [headerLine, ...rows] = stdout.trimEnd().split('\n').filter(Boolean);
69
+ if (headerLine === undefined)
70
+ return [];
71
+ const headers = headerLine.split('\t');
72
+ return rows.map((line) => {
73
+ const values = line.split('\t');
74
+ return Object.fromEntries(headers.map((header, index) => {
75
+ const value = values[index];
76
+ return [
77
+ header,
78
+ value === undefined || value === 'NULL' ? null : value,
79
+ ];
80
+ }));
81
+ });
82
+ }
83
+ #acquire(database, mode) {
84
+ const { image, password, labels } = this.#options;
85
+ return this.#docker[mode]({
86
+ image,
87
+ labels,
88
+ internalPort: 3306,
89
+ env: this.environment(password, database),
90
+ tmpfs: ['/var/lib/mysql:rw,size=512m'],
91
+ memorySwappiness: 0,
92
+ healthy: (container) => this.#ready(container),
93
+ });
94
+ }
95
+ #ready(container) {
96
+ const { password } = this.#options;
97
+ // TCP excludes the entrypoint's temporary, socket-only initialization server.
98
+ return timebox(() => container.exec([
99
+ this.client,
100
+ '-h',
101
+ '127.0.0.1',
102
+ `-u${user}`,
103
+ `-p${password}`,
104
+ '--execute',
105
+ 'SELECT 1',
106
+ ]), { maxRetryTime: 90_000 });
107
+ }
108
+ #handle(container, database, cleanup) {
109
+ const { image, password } = this.#options;
110
+ return {
111
+ connectionString: `${this.scheme}://${user}:${password}@${container.host}:${container.port}/${database}`,
112
+ image,
113
+ user,
114
+ password,
115
+ database,
116
+ containerId: container.containerId,
117
+ host: container.host,
118
+ port: container.port,
119
+ query: (sql) => this.#query(container, database, sql),
120
+ cleanup,
121
+ [Symbol.asyncDispose]: cleanup,
122
+ };
123
+ }
124
+ }
125
+ //# sourceMappingURL=mysql-family-server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mysql-family-server.js","sourceRoot":"","sources":["../../src/databases/mysql-family-server.ts"],"names":[],"mappings":"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"}
@@ -1,17 +1,15 @@
1
- import type { Database, DatabaseOptions } from './database.ts';
1
+ import type { DatabaseOptions } from './database.ts';
2
+ import { type MysqlFamilyDatabase, MysqlFamilyServer } from './mysql-family-server.ts';
2
3
  export type { Database, DatabaseOptions } from './database.ts';
3
- export interface MysqlOptions extends DatabaseOptions {
4
- user?: string;
5
- }
6
- export interface MysqlDatabase extends Database {
7
- query: (sql: string) => Promise<Record<string, string | null>[]>;
8
- }
9
- export declare class Mysql {
10
- #private;
11
- constructor({ docker, image, password, database, user, labels, }: MysqlOptions);
12
- /** Create an isolated database on the persistent shared server. */
13
- database(): Promise<MysqlDatabase>;
14
- /** Start a dedicated server; the returned handle owns its container. */
15
- start(): Promise<MysqlDatabase>;
4
+ export type MysqlOptions = DatabaseOptions;
5
+ export type MysqlDatabase = MysqlFamilyDatabase;
6
+ export declare class Mysql extends MysqlFamilyServer {
7
+ protected readonly client = "mysql";
8
+ protected readonly scheme = "mysql";
9
+ constructor({ image, ...options }: MysqlOptions);
10
+ protected environment(password: string, database: string): {
11
+ MYSQL_ROOT_PASSWORD: string;
12
+ MYSQL_DATABASE: string;
13
+ };
16
14
  }
17
15
  //# sourceMappingURL=mysql.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"mysql.d.ts","sourceRoot":"","sources":["../../src/databases/mysql.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAE/D,YAAY,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAE/D,MAAM,WAAW,YAAa,SAAQ,eAAe;IACnD,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,aAAc,SAAQ,QAAQ;IAC7C,KAAK,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC;CAClE;AAED,qBAAa,KAAK;;gBAIJ,EACV,MAAM,EACN,KAAmB,EACnB,QAAyB,EACzB,QAAgB,EAChB,IAAa,EACb,MAAM,GACP,EAAE,YAAY;IAKf,mEAAmE;IAC7D,QAAQ,IAAI,OAAO,CAAC,aAAa,CAAC;IAoBxC,wEAAwE;IAClE,KAAK,IAAI,OAAO,CAAC,aAAa,CAAC;CA4GtC"}
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,116 +1,12 @@
1
- import { randomUUID } from 'node:crypto';
2
- import { timebox } from "../async/timebox.js";
3
- export class Mysql {
4
- #docker;
5
- #options;
6
- constructor({ docker, image = 'mysql:8.4', password = 'testpassword', database = 'app', user = 'root', labels, }) {
7
- this.#docker = docker;
8
- this.#options = { image, password, database, user, labels };
9
- }
10
- /** Create an isolated database on the persistent shared server. */
11
- async database() {
12
- const container = await this.#acquire('app', 'reuse');
13
- const database = `test_${randomUUID().replaceAll('-', '')}`;
14
- try {
15
- await this.#sql(container, `CREATE DATABASE \`${database}\``);
16
- }
17
- catch (error) {
18
- await container.disconnect();
19
- throw error;
20
- }
21
- return this.#handle(container, database, async () => {
22
- await this.#sql(container, `DROP DATABASE IF EXISTS \`${database}\``).catch(() => {
23
- /* Best-effort cleanup after external removal. */
24
- });
25
- await container.disconnect();
26
- });
27
- }
28
- /** Start a dedicated server; the returned handle owns its container. */
29
- async start() {
30
- const { database } = this.#options;
31
- const container = await this.#acquire(database, 'serve');
32
- return this.#handle(container, database, () => container.cleanup());
33
- }
34
- #sql(container, sql) {
35
- const { user, password } = this.#options;
36
- return container.exec([
37
- 'mysql',
38
- `-u${user}`,
39
- `-p${password}`,
40
- '--execute',
41
- sql,
42
- ]);
43
- }
44
- async #query(container, database, sql) {
45
- const { user, password } = this.#options;
46
- const { stdout } = await container.exec([
47
- 'mysql',
48
- `-u${user}`,
49
- `-p${password}`,
50
- '--database',
51
- database,
52
- '--batch',
53
- '--raw',
54
- '--execute',
55
- sql,
56
- ]);
57
- return this.#parseBatch(stdout);
58
- }
59
- #parseBatch(stdout) {
60
- const [headerLine, ...rows] = stdout.trimEnd().split('\n').filter(Boolean);
61
- if (headerLine === undefined)
62
- return [];
63
- const headers = headerLine.split('\t');
64
- return rows.map((line) => {
65
- const values = line.split('\t');
66
- return Object.fromEntries(headers.map((header, index) => {
67
- const value = values[index];
68
- return [
69
- header,
70
- value === undefined || value === 'NULL' ? null : value,
71
- ];
72
- }));
73
- });
74
- }
75
- #acquire(database, mode) {
76
- const { image, password, labels } = this.#options;
77
- return this.#docker[mode]({
78
- image,
79
- labels,
80
- internalPort: 3306,
81
- env: { MYSQL_ROOT_PASSWORD: password, MYSQL_DATABASE: database },
82
- tmpfs: ['/var/lib/mysql:rw,size=512m'],
83
- memorySwappiness: 0,
84
- healthy: (container) => this.#ready(container),
85
- });
86
- }
87
- #ready(container) {
88
- const { user, password } = this.#options;
89
- return timebox(() => container.exec([
90
- 'mysqladmin',
91
- 'ping',
92
- '-h',
93
- '127.0.0.1',
94
- `-u${user}`,
95
- `-p${password}`,
96
- '--silent',
97
- ]), { maxRetryTime: 90_000 });
98
- }
99
- #handle(container, database, cleanup) {
100
- const { image, user, password } = this.#options;
101
- return {
102
- connectionString: `mysql://${user}:${password}@${container.host}:${container.port}/${database}`,
103
- image,
104
- user,
105
- password,
106
- database,
107
- containerId: container.containerId,
108
- host: container.host,
109
- port: container.port,
110
- query: (sql) => this.#query(container, database, sql),
111
- cleanup,
112
- [Symbol.asyncDispose]: cleanup,
113
- };
1
+ import { MysqlFamilyServer, } from "./mysql-family-server.js";
2
+ export class Mysql extends MysqlFamilyServer {
3
+ client = 'mysql';
4
+ scheme = 'mysql';
5
+ constructor({ image = 'mysql:lts', ...options }) {
6
+ super({ ...options, image });
7
+ }
8
+ environment(password, database) {
9
+ return { MYSQL_ROOT_PASSWORD: password, MYSQL_DATABASE: database };
114
10
  }
115
11
  }
116
12
  //# sourceMappingURL=mysql.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"mysql.js","sourceRoot":"","sources":["../../src/databases/mysql.ts"],"names":[],"mappings":"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"}
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"}
@@ -5,8 +5,14 @@ export interface HttpServerHandle extends AsyncDisposable {
5
5
  /** Stop accepting requests and close active HTTP connections. */
6
6
  cleanup: () => Promise<void>;
7
7
  }
8
+ /** A server whose scope is the process: nothing disposes it. */
9
+ export interface BackgroundHttpServer {
10
+ origin: string;
11
+ }
8
12
  /** Each acquisition owns a loopback HTTP server on an available port. */
9
13
  export declare class HttpServer {
10
14
  start(handler: RequestListener): Promise<HttpServerHandle>;
15
+ /** Serves until the process exits and never keeps it running, even while a connection is open. */
16
+ background(handler: RequestListener): Promise<BackgroundHttpServer>;
11
17
  }
12
18
  //# sourceMappingURL=http-server.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"http-server.d.ts","sourceRoot":"","sources":["../../src/http/http-server.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,eAAe,EAAE,KAAK,MAAM,EAAgB,MAAM,WAAW,CAAC;AAE5E,MAAM,WAAW,gBAAiB,SAAQ,eAAe;IACvD,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,iEAAiE;IACjE,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9B;AAED,yEAAyE;AACzE,qBAAa,UAAU;IACf,KAAK,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,gBAAgB,CAAC;CAwBjE"}
1
+ {"version":3,"file":"http-server.d.ts","sourceRoot":"","sources":["../../src/http/http-server.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,eAAe,EAAE,KAAK,MAAM,EAAgB,MAAM,WAAW,CAAC;AAE5E,MAAM,WAAW,gBAAiB,SAAQ,eAAe;IACvD,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,iEAAiE;IACjE,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9B;AAED,gEAAgE;AAChE,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,yEAAyE;AACzE,qBAAa,UAAU;IACf,KAAK,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAsBhE,kGAAkG;IAC5F,UAAU,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,oBAAoB,CAAC;CAO1E"}
@@ -6,24 +6,39 @@ export class HttpServer {
6
6
  async start(handler) {
7
7
  await using resources = new AsyncDisposableStack();
8
8
  const server = createServer(handler);
9
- const listening = once(server, 'listening');
10
- server.listen(0, '127.0.0.1');
11
- await listening;
9
+ await listen(server);
12
10
  resources.defer(async () => {
13
11
  const closed = server[Symbol.asyncDispose]();
14
12
  server.closeAllConnections();
15
13
  await closed;
16
14
  });
17
- const address = server.address();
18
- assert(address && typeof address === 'object');
15
+ const origin = originOf(server);
19
16
  const owned = resources.move();
20
17
  const cleanup = () => owned.disposeAsync();
21
18
  return {
22
- origin: `http://127.0.0.1:${address.port}`,
19
+ origin,
23
20
  server,
24
21
  cleanup,
25
22
  [Symbol.asyncDispose]: cleanup,
26
23
  };
27
24
  }
25
+ /** Serves until the process exits and never keeps it running, even while a connection is open. */
26
+ async background(handler) {
27
+ const server = createServer(handler);
28
+ server.on('connection', (socket) => socket.unref());
29
+ await listen(server);
30
+ server.unref();
31
+ return { origin: originOf(server) };
32
+ }
33
+ }
34
+ async function listen(server) {
35
+ const listening = once(server, 'listening');
36
+ server.listen(0, '127.0.0.1');
37
+ await listening;
38
+ }
39
+ function originOf(server) {
40
+ const address = server.address();
41
+ assert(address && typeof address === 'object');
42
+ return `http://127.0.0.1:${address.port}`;
28
43
  }
29
44
  //# sourceMappingURL=http-server.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"http-server.js","sourceRoot":"","sources":["../../src/http/http-server.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AACnC,OAAO,EAAqC,YAAY,EAAE,MAAM,WAAW,CAAC;AAS5E,yEAAyE;AACzE,MAAM,OAAO,UAAU;IACrB,KAAK,CAAC,KAAK,CAAC,OAAwB;QAClC,YAAY,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;QACnD,MAAM,MAAM,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC;QACrC,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;QAC5C,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC;QAC9B,MAAM,SAAS,CAAC;QAEhB,SAAS,CAAC,KAAK,CAAC,KAAK,IAAI,EAAE;YACzB,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,EAAE,CAAC;YAC7C,MAAM,CAAC,mBAAmB,EAAE,CAAC;YAC7B,MAAM,MAAM,CAAC;QACf,CAAC,CAAC,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC;QACjC,MAAM,CAAC,OAAO,IAAI,OAAO,OAAO,KAAK,QAAQ,CAAC,CAAC;QAC/C,MAAM,KAAK,GAAG,SAAS,CAAC,IAAI,EAAE,CAAC;QAC/B,MAAM,OAAO,GAAG,GAAG,EAAE,CAAC,KAAK,CAAC,YAAY,EAAE,CAAC;QAE3C,OAAO;YACL,MAAM,EAAE,oBAAoB,OAAO,CAAC,IAAI,EAAE;YAC1C,MAAM;YACN,OAAO;YACP,CAAC,MAAM,CAAC,YAAY,CAAC,EAAE,OAAO;SAC/B,CAAC;IACJ,CAAC;CACF"}
1
+ {"version":3,"file":"http-server.js","sourceRoot":"","sources":["../../src/http/http-server.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AACnC,OAAO,EAAqC,YAAY,EAAE,MAAM,WAAW,CAAC;AAc5E,yEAAyE;AACzE,MAAM,OAAO,UAAU;IACrB,KAAK,CAAC,KAAK,CAAC,OAAwB;QAClC,YAAY,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;QACnD,MAAM,MAAM,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC;QACrC,MAAM,MAAM,CAAC,MAAM,CAAC,CAAC;QAErB,SAAS,CAAC,KAAK,CAAC,KAAK,IAAI,EAAE;YACzB,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,EAAE,CAAC;YAC7C,MAAM,CAAC,mBAAmB,EAAE,CAAC;YAC7B,MAAM,MAAM,CAAC;QACf,CAAC,CAAC,CAAC;QACH,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC;QAChC,MAAM,KAAK,GAAG,SAAS,CAAC,IAAI,EAAE,CAAC;QAC/B,MAAM,OAAO,GAAG,GAAG,EAAE,CAAC,KAAK,CAAC,YAAY,EAAE,CAAC;QAE3C,OAAO;YACL,MAAM;YACN,MAAM;YACN,OAAO;YACP,CAAC,MAAM,CAAC,YAAY,CAAC,EAAE,OAAO;SAC/B,CAAC;IACJ,CAAC;IAED,kGAAkG;IAClG,KAAK,CAAC,UAAU,CAAC,OAAwB;QACvC,MAAM,MAAM,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC;QACrC,MAAM,CAAC,EAAE,CAAC,YAAY,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC;QACpD,MAAM,MAAM,CAAC,MAAM,CAAC,CAAC;QACrB,MAAM,CAAC,KAAK,EAAE,CAAC;QACf,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;IACtC,CAAC;CACF;AAED,KAAK,UAAU,MAAM,CAAC,MAAc;IAClC,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IAC5C,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC;IAC9B,MAAM,SAAS,CAAC;AAClB,CAAC;AAED,SAAS,QAAQ,CAAC,MAAc;IAC9B,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC;IACjC,MAAM,CAAC,OAAO,IAAI,OAAO,OAAO,KAAK,QAAQ,CAAC,CAAC;IAC/C,OAAO,oBAAoB,OAAO,CAAC,IAAI,EAAE,CAAC;AAC5C,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zukhruf/testing",
3
- "version": "0.3.3",
3
+ "version": "0.3.5",
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": {
@@ -19,6 +19,7 @@
19
19
  "docker",
20
20
  "postgres",
21
21
  "mysql",
22
+ "mariadb",
22
23
  "sql-server",
23
24
  "disposable"
24
25
  ],
@@ -48,6 +49,11 @@
48
49
  "import": "./dist/databases/mysql.js",
49
50
  "default": "./dist/databases/mysql.js"
50
51
  },
52
+ "./mariadb": {
53
+ "types": "./dist/databases/mariadb.d.ts",
54
+ "import": "./dist/databases/mariadb.js",
55
+ "default": "./dist/databases/mariadb.js"
56
+ },
51
57
  "./sqlserver": {
52
58
  "types": "./dist/databases/sqlserver.d.ts",
53
59
  "import": "./dist/databases/sqlserver.js",
@@ -98,7 +104,9 @@
98
104
  "@google-cloud/bigquery": "^8.3.1",
99
105
  "@types/mssql": "^12.3.0",
100
106
  "@types/pg": "^8.23.1",
107
+ "mariadb": "^3.5.4",
101
108
  "mssql": "^12.7.4",
109
+ "mysql2": "^3.24.5",
102
110
  "pg": "^8.23.1"
103
111
  },
104
112
  "dependencies": {