@zukhruf/testing 0.3.3 → 0.3.4
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/dist/databases/mysql-family-server.d.ts +24 -0
- package/dist/databases/mysql-family-server.d.ts.map +1 -0
- package/dist/databases/mysql-family-server.js +125 -0
- package/dist/databases/mysql-family-server.js.map +1 -0
- package/dist/databases/mysql.d.ts +12 -14
- package/dist/databases/mysql.d.ts.map +1 -1
- package/dist/databases/mysql.js +9 -113
- package/dist/databases/mysql.js.map +1 -1
- package/package.json +1 -1
|
@@ -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 {
|
|
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
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
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":"
|
|
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"}
|
package/dist/databases/mysql.js
CHANGED
|
@@ -1,116 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
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":"
|
|
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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zukhruf/testing",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.4",
|
|
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": {
|