testcontainers 7.20.4 → 7.22.0
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 +10 -0
- package/dist/docker/functions/container/remove-container.js +12 -3
- package/dist/docker/functions/container/start-container.js +12 -3
- package/dist/docker/get-docker-host.js +22 -30
- package/dist/docker-compose/default-docker-compose-options.js +2 -1
- package/dist/docker-compose/docker-compose-options.d.ts +0 -1
- package/dist/docker-compose/functions/container-name-resolver.d.ts +1 -1
- package/dist/docker-compose/functions/container-name-resolver.js +5 -4
- package/dist/docker-compose-environment/docker-compose-environment.d.ts +3 -3
- package/dist/docker-compose-environment/docker-compose-environment.js +16 -9
- package/dist/docker-ignore.js +11 -16
- package/dist/generic-container/started-generic-container.js +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +4 -1
- package/dist/modules/abstract-started-container.d.ts +1 -2
- package/dist/modules/kafka/kafka-container.js +1 -1
- package/dist/modules/mysql/mysql-container.d.ts +30 -0
- package/dist/modules/mysql/mysql-container.js +98 -0
- package/dist/network.d.ts +0 -1
- package/dist/network.js +1 -2
- package/dist/reaper.d.ts +0 -1
- package/dist/reaper.js +4 -10
- package/dist/wait-strategy.js +6 -11
- package/package.json +21 -20
package/README.md
CHANGED
|
@@ -523,6 +523,16 @@ const environment = await new DockerComposeEnvironment(composeFilePath, composeF
|
|
|
523
523
|
.up();
|
|
524
524
|
```
|
|
525
525
|
|
|
526
|
+
Specify not to re-create containers that are already running:
|
|
527
|
+
|
|
528
|
+
```javascript
|
|
529
|
+
const { DockerComposeEnvironment } = require("testcontainers");
|
|
530
|
+
|
|
531
|
+
const environment = await new DockerComposeEnvironment(composeFilePath, composeFile)
|
|
532
|
+
.withNoRecreate()
|
|
533
|
+
.up();
|
|
534
|
+
```
|
|
535
|
+
|
|
526
536
|
Bind environment variables to the docker-compose file. For example if we have the following docker-compose file:
|
|
527
537
|
|
|
528
538
|
```yaml
|
|
@@ -1,14 +1,23 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
2
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
12
|
exports.removeContainer = void 0;
|
|
4
13
|
const logger_1 = require("../../../logger");
|
|
5
|
-
const removeContainer = (container, options) => {
|
|
14
|
+
const removeContainer = (container, options) => __awaiter(void 0, void 0, void 0, function* () {
|
|
6
15
|
try {
|
|
7
|
-
|
|
16
|
+
yield container.remove({ v: options.removeVolumes });
|
|
8
17
|
}
|
|
9
18
|
catch (err) {
|
|
10
19
|
logger_1.log.error(`Failed to remove container ${container.id}: ${err}`);
|
|
11
20
|
throw err;
|
|
12
21
|
}
|
|
13
|
-
};
|
|
22
|
+
});
|
|
14
23
|
exports.removeContainer = removeContainer;
|
|
@@ -1,14 +1,23 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
2
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
12
|
exports.startContainer = void 0;
|
|
4
13
|
const logger_1 = require("../../../logger");
|
|
5
|
-
const startContainer = (container) => {
|
|
14
|
+
const startContainer = (container) => __awaiter(void 0, void 0, void 0, function* () {
|
|
6
15
|
try {
|
|
7
|
-
|
|
16
|
+
yield container.start();
|
|
8
17
|
}
|
|
9
18
|
catch (err) {
|
|
10
19
|
logger_1.log.error(`Failed to start container ${container.id}: ${err}`);
|
|
11
20
|
throw err;
|
|
12
21
|
}
|
|
13
|
-
};
|
|
22
|
+
});
|
|
14
23
|
exports.startContainer = startContainer;
|
|
@@ -21,48 +21,40 @@ const getDockerHost = (dockerode) => __awaiter(void 0, void 0, void 0, function*
|
|
|
21
21
|
if (process.env.DOCKER_HOST) {
|
|
22
22
|
logger_1.log.info(`Detected DOCKER_HOST environment variable: ${process.env.DOCKER_HOST}`);
|
|
23
23
|
}
|
|
24
|
-
for (const hostStrategy of hostStrategies(dockerode)) {
|
|
24
|
+
for (const [hostStrategyName, hostStrategy] of Object.entries(hostStrategies(dockerode))) {
|
|
25
25
|
const result = yield hostStrategy();
|
|
26
|
-
if (result
|
|
27
|
-
|
|
28
|
-
return result
|
|
26
|
+
if (result) {
|
|
27
|
+
logger_1.log.info(`Docker host strategy ${hostStrategyName}: ${result}`);
|
|
28
|
+
return result;
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
|
-
logger_1.log.info(`
|
|
31
|
+
logger_1.log.info(`Docker host strategy FALLBACK: ${DEFAULT_HOST}`);
|
|
32
32
|
return DEFAULT_HOST;
|
|
33
33
|
});
|
|
34
34
|
exports.getDockerHost = getDockerHost;
|
|
35
|
-
const hostStrategies = (dockerode) =>
|
|
36
|
-
() => __awaiter(void 0, void 0, void 0, function* () {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
}),
|
|
40
|
-
() => __awaiter(void 0, void 0, void 0, function* () {
|
|
41
|
-
const host = process.env["TESTCONTAINERS_HOST_OVERRIDE"];
|
|
42
|
-
return { host, callback: () => logger_1.log.info(`Using TESTCONTAINERS_HOST_OVERRIDE: ${host}`) };
|
|
43
|
-
}),
|
|
44
|
-
() => __awaiter(void 0, void 0, void 0, function* () {
|
|
35
|
+
const hostStrategies = (dockerode) => ({
|
|
36
|
+
MODEM: () => __awaiter(void 0, void 0, void 0, function* () { return dockerode.modem.host; }),
|
|
37
|
+
TESTCONTAINERS_HOST_OVERRIDE: () => __awaiter(void 0, void 0, void 0, function* () { return process.env["TESTCONTAINERS_HOST_OVERRIDE"]; }),
|
|
38
|
+
OUTSIDE_CONTAINER: () => __awaiter(void 0, void 0, void 0, function* () {
|
|
45
39
|
if (!isInContainer()) {
|
|
46
|
-
return
|
|
40
|
+
return DEFAULT_HOST;
|
|
47
41
|
}
|
|
48
42
|
}),
|
|
49
|
-
() => __awaiter(void 0, void 0, void 0, function* () {
|
|
43
|
+
INSIDE_CONTAINER_NO_IPAM: () => __awaiter(void 0, void 0, void 0, function* () {
|
|
50
44
|
const network = yield dockerode.getNetwork("bridge").inspect();
|
|
51
45
|
if (!network.IPAM || !network.IPAM.Config) {
|
|
52
|
-
return
|
|
53
|
-
host: DEFAULT_HOST,
|
|
54
|
-
callback: () => logger_1.log.info(`Using default Docker host from within container: ${DEFAULT_HOST}`),
|
|
55
|
-
};
|
|
56
|
-
}
|
|
57
|
-
const gateways = network.IPAM.Config.filter((config) => !!config.Gateway);
|
|
58
|
-
if (gateways.length > 0) {
|
|
59
|
-
const host = gateways[0].Gateway;
|
|
60
|
-
return { host, callback: () => logger_1.log.info(`Using Docker host from network gateway within container: ${host}`) };
|
|
46
|
+
return DEFAULT_HOST;
|
|
61
47
|
}
|
|
62
48
|
}),
|
|
63
|
-
() => __awaiter(void 0, void 0, void 0, function* () {
|
|
64
|
-
const
|
|
65
|
-
|
|
49
|
+
INSIDE_CONTAINER_IPAM: () => __awaiter(void 0, void 0, void 0, function* () {
|
|
50
|
+
const network = yield dockerode.getNetwork("bridge").inspect();
|
|
51
|
+
if (network.IPAM && network.IPAM.Config) {
|
|
52
|
+
const gateways = network.IPAM.Config.filter((config) => !!config.Gateway);
|
|
53
|
+
if (gateways.length > 0) {
|
|
54
|
+
return gateways[0].Gateway;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
66
57
|
}),
|
|
67
|
-
];
|
|
58
|
+
CONTAINER_GATEWAY: () => __awaiter(void 0, void 0, void 0, function* () { return run_in_container_1.runInContainer("alpine:3.5", ["sh", "-c", "ip route|awk '/default/ { print $3 }'"]); }),
|
|
59
|
+
});
|
|
68
60
|
const isInContainer = () => fs_1.default.existsSync("/.dockerenv");
|
|
@@ -12,6 +12,7 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
12
12
|
};
|
|
13
13
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
14
|
exports.defaultDockerComposeOptions = void 0;
|
|
15
|
+
const session_id_1 = require("../docker/session-id");
|
|
15
16
|
const defaultDockerComposeOptions = (_a) => {
|
|
16
17
|
var { env = {} } = _a, options = __rest(_a, ["env"]);
|
|
17
18
|
return {
|
|
@@ -19,7 +20,7 @@ const defaultDockerComposeOptions = (_a) => {
|
|
|
19
20
|
cwd: options.filePath,
|
|
20
21
|
config: options.files,
|
|
21
22
|
commandOptions: options.commandOptions,
|
|
22
|
-
env: Object.assign(Object.assign(Object.assign({}, process.env), { COMPOSE_PROJECT_NAME:
|
|
23
|
+
env: Object.assign(Object.assign(Object.assign({}, process.env), { COMPOSE_PROJECT_NAME: session_id_1.sessionId }), env),
|
|
23
24
|
};
|
|
24
25
|
};
|
|
25
26
|
exports.defaultDockerComposeOptions = defaultDockerComposeOptions;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const resolveContainerName: (
|
|
1
|
+
export declare const resolveContainerName: (containerName: string) => string;
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.resolveContainerName = void 0;
|
|
4
|
-
const
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
const session_id_1 = require("../../docker/session-id");
|
|
5
|
+
const resolveContainerName = (containerName) => {
|
|
6
|
+
if (containerName.includes(session_id_1.sessionId)) {
|
|
7
|
+
return containerName.substring(`/${session_id_1.sessionId}_`.length);
|
|
7
8
|
}
|
|
8
9
|
else if (containerName.startsWith("/")) {
|
|
9
10
|
return containerName.substring(1);
|
|
10
11
|
}
|
|
11
12
|
else {
|
|
12
|
-
throw new Error(`Unable to resolve container name for container name: "${containerName}",
|
|
13
|
+
throw new Error(`Unable to resolve container name for container name: "${containerName}", session ID: "${session_id_1.sessionId}"`);
|
|
13
14
|
}
|
|
14
15
|
};
|
|
15
16
|
exports.resolveContainerName = resolveContainerName;
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
import { WaitStrategy } from "../wait-strategy";
|
|
2
|
-
import { Uuid } from "../uuid";
|
|
3
2
|
import { EnvKey, EnvValue } from "../docker/types";
|
|
4
3
|
import { StartedDockerComposeEnvironment } from "./started-docker-compose-environment";
|
|
5
4
|
export declare class DockerComposeEnvironment {
|
|
6
|
-
private readonly projectName;
|
|
7
5
|
private readonly options;
|
|
8
6
|
private build;
|
|
7
|
+
private recreate;
|
|
9
8
|
private env;
|
|
10
9
|
private waitStrategy;
|
|
11
10
|
private startupTimeout;
|
|
12
|
-
constructor(composeFilePath: string, composeFiles: string | string[]
|
|
11
|
+
constructor(composeFilePath: string, composeFiles: string | string[]);
|
|
13
12
|
withBuild(): this;
|
|
14
13
|
withEnv(key: EnvKey, value: EnvValue): this;
|
|
14
|
+
withNoRecreate(): this;
|
|
15
15
|
withWaitStrategy(containerName: string, waitStrategy: WaitStrategy): this;
|
|
16
16
|
withStartupTimeout(startupTimeout: number): this;
|
|
17
17
|
up(services?: Array<string>): Promise<StartedDockerComposeEnvironment>;
|
|
@@ -17,7 +17,6 @@ const logger_1 = require("../logger");
|
|
|
17
17
|
const port_check_1 = require("../port-check");
|
|
18
18
|
const wait_strategy_1 = require("../wait-strategy");
|
|
19
19
|
const reaper_1 = require("../reaper");
|
|
20
|
-
const uuid_1 = require("../uuid");
|
|
21
20
|
const list_containers_1 = require("../docker/functions/container/list-containers");
|
|
22
21
|
const get_container_1 = require("../docker/functions/container/get-container");
|
|
23
22
|
const docker_host_1 = require("../docker/docker-host");
|
|
@@ -26,14 +25,15 @@ const container_logs_1 = require("../docker/functions/container/container-logs")
|
|
|
26
25
|
const started_docker_compose_environment_1 = require("./started-docker-compose-environment");
|
|
27
26
|
const docker_compose_down_1 = require("../docker-compose/functions/docker-compose-down");
|
|
28
27
|
const docker_compose_up_1 = require("../docker-compose/functions/docker-compose-up");
|
|
28
|
+
const session_id_1 = require("../docker/session-id");
|
|
29
29
|
class DockerComposeEnvironment {
|
|
30
|
-
constructor(composeFilePath, composeFiles
|
|
30
|
+
constructor(composeFilePath, composeFiles) {
|
|
31
31
|
this.build = false;
|
|
32
|
+
this.recreate = true;
|
|
32
33
|
this.env = {};
|
|
33
34
|
this.waitStrategy = {};
|
|
34
35
|
this.startupTimeout = 60000;
|
|
35
|
-
this.
|
|
36
|
-
this.options = { filePath: composeFilePath, files: composeFiles, projectName: this.projectName };
|
|
36
|
+
this.options = { filePath: composeFilePath, files: composeFiles };
|
|
37
37
|
}
|
|
38
38
|
withBuild() {
|
|
39
39
|
this.build = true;
|
|
@@ -43,6 +43,10 @@ class DockerComposeEnvironment {
|
|
|
43
43
|
this.env[key] = value;
|
|
44
44
|
return this;
|
|
45
45
|
}
|
|
46
|
+
withNoRecreate() {
|
|
47
|
+
this.recreate = false;
|
|
48
|
+
return this;
|
|
49
|
+
}
|
|
46
50
|
withWaitStrategy(containerName, waitStrategy) {
|
|
47
51
|
this.waitStrategy[containerName] = waitStrategy;
|
|
48
52
|
return this;
|
|
@@ -53,22 +57,25 @@ class DockerComposeEnvironment {
|
|
|
53
57
|
}
|
|
54
58
|
up(services) {
|
|
55
59
|
return __awaiter(this, void 0, void 0, function* () {
|
|
56
|
-
logger_1.log.info(`Starting DockerCompose environment
|
|
57
|
-
|
|
60
|
+
logger_1.log.info(`Starting DockerCompose environment`);
|
|
61
|
+
yield reaper_1.ReaperInstance.getInstance();
|
|
58
62
|
const commandOptions = [];
|
|
59
63
|
if (this.build) {
|
|
60
64
|
commandOptions.push("--build");
|
|
61
65
|
}
|
|
66
|
+
if (!this.recreate) {
|
|
67
|
+
commandOptions.push("--no-recreate");
|
|
68
|
+
}
|
|
62
69
|
yield docker_compose_up_1.dockerComposeUp(Object.assign(Object.assign({}, this.options), { commandOptions, env: this.env }), services);
|
|
63
|
-
const startedContainers = (yield list_containers_1.listContainers()).filter((container) => container.Labels["com.docker.compose.project"] ===
|
|
70
|
+
const startedContainers = (yield list_containers_1.listContainers()).filter((container) => container.Labels["com.docker.compose.project"] === session_id_1.sessionId);
|
|
64
71
|
const startedContainerNames = startedContainers.reduce((containerNames, startedContainer) => [
|
|
65
72
|
...containerNames,
|
|
66
73
|
startedContainer.Names.join(", "),
|
|
67
74
|
], []);
|
|
68
75
|
logger_1.log.info(`Started the following containers: ${startedContainerNames.join(", ")}`);
|
|
69
76
|
const startedGenericContainers = (yield Promise.all(startedContainers.map((startedContainer) => __awaiter(this, void 0, void 0, function* () {
|
|
70
|
-
const container =
|
|
71
|
-
const containerName = container_name_resolver_1.resolveContainerName(
|
|
77
|
+
const container = get_container_1.getContainerById(startedContainer.Id);
|
|
78
|
+
const containerName = container_name_resolver_1.resolveContainerName(startedContainer.Names[0]);
|
|
72
79
|
(yield container_logs_1.containerLogs(container))
|
|
73
80
|
.on("data", (data) => logger_1.containerLog.trace(`${containerName}: ${data}`))
|
|
74
81
|
.on("err", (data) => logger_1.containerLog.error(`${containerName}: ${data}`));
|
package/dist/docker-ignore.js
CHANGED
|
@@ -18,28 +18,23 @@ const os_1 = __importDefault(require("os"));
|
|
|
18
18
|
const glob_1 = __importDefault(require("glob"));
|
|
19
19
|
const path_1 = __importDefault(require("path"));
|
|
20
20
|
const findDockerIgnoreFiles = (context) => __awaiter(void 0, void 0, void 0, function* () {
|
|
21
|
-
const dockerIgnoreFiles = new Set();
|
|
22
21
|
const dockerIgnoreFilePath = path_1.default.join(context, ".dockerignore");
|
|
23
22
|
if (!fs_1.existsSync(dockerIgnoreFilePath)) {
|
|
24
|
-
return
|
|
23
|
+
return new Set();
|
|
25
24
|
}
|
|
26
25
|
const dockerIgnorePatterns = (yield fs_1.promises.readFile(dockerIgnoreFilePath, { encoding: "utf-8" }))
|
|
27
26
|
.toString()
|
|
28
27
|
.split(os_1.default.EOL)
|
|
29
28
|
.map((dockerIgnorePattern) => path_1.default.resolve(context, dockerIgnorePattern));
|
|
30
|
-
const dockerIgnoreMatches = yield Promise.all(dockerIgnorePatterns.map((
|
|
31
|
-
|
|
32
|
-
if (err) {
|
|
33
|
-
return reject(err);
|
|
34
|
-
}
|
|
35
|
-
else {
|
|
36
|
-
resolve(matches);
|
|
37
|
-
}
|
|
38
|
-
}));
|
|
39
|
-
}));
|
|
40
|
-
dockerIgnoreMatches.forEach((dockerIgnoreFileBatch) => {
|
|
41
|
-
dockerIgnoreFileBatch.forEach((dockerIgnoreFile) => dockerIgnoreFiles.add(dockerIgnoreFile));
|
|
42
|
-
});
|
|
43
|
-
return dockerIgnoreFiles;
|
|
29
|
+
const dockerIgnoreMatches = (yield Promise.all(dockerIgnorePatterns.map(findIgnoredFilesForPattern))).reduce((prev, next) => [...prev, ...next]);
|
|
30
|
+
return new Set(dockerIgnoreMatches);
|
|
44
31
|
});
|
|
45
32
|
exports.findDockerIgnoreFiles = findDockerIgnoreFiles;
|
|
33
|
+
const findIgnoredFilesForPattern = (dockerIgnorePattern) => new Promise((resolve, reject) => glob_1.default(dockerIgnorePattern, (err, matches) => {
|
|
34
|
+
if (err) {
|
|
35
|
+
return reject(err);
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
resolve(matches);
|
|
39
|
+
}
|
|
40
|
+
}));
|
package/dist/index.d.ts
CHANGED
|
@@ -14,3 +14,4 @@ export { KafkaContainer, StartedKafkaContainer } from "./modules/kafka/kafka-con
|
|
|
14
14
|
export { Neo4jContainer, StartedNeo4jContainer } from "./modules/neo4j/neo4j-container";
|
|
15
15
|
export { ArangoDBContainer, StartedArangoContainer } from "./modules/arangodb/arangodb-container";
|
|
16
16
|
export { ElasticsearchContainer, StartedElasticsearchContainer } from "./modules/elasticsearch/elasticsearch-container";
|
|
17
|
+
export { MySqlContainer, StartedMySqlContainer } from "./modules/mysql/mysql-container";
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.StartedElasticsearchContainer = exports.ElasticsearchContainer = exports.StartedArangoContainer = exports.ArangoDBContainer = exports.StartedNeo4jContainer = exports.Neo4jContainer = exports.StartedKafkaContainer = exports.KafkaContainer = exports.StartedPostgreSqlContainer = exports.PostgreSqlContainer = exports.AlwaysPullPolicy = exports.DefaultPullPolicy = exports.Wait = exports.StoppedNetwork = exports.StartedNetwork = exports.Network = exports.DownedDockerComposeEnvironment = exports.StoppedDockerComposeEnvironment = exports.StartedDockerComposeEnvironment = exports.DockerComposeEnvironment = exports.TestContainers = exports.GenericContainerBuilder = exports.GenericContainer = void 0;
|
|
3
|
+
exports.StartedMySqlContainer = exports.MySqlContainer = exports.StartedElasticsearchContainer = exports.ElasticsearchContainer = exports.StartedArangoContainer = exports.ArangoDBContainer = exports.StartedNeo4jContainer = exports.Neo4jContainer = exports.StartedKafkaContainer = exports.KafkaContainer = exports.StartedPostgreSqlContainer = exports.PostgreSqlContainer = exports.AlwaysPullPolicy = exports.DefaultPullPolicy = exports.Wait = exports.StoppedNetwork = exports.StartedNetwork = exports.Network = exports.DownedDockerComposeEnvironment = exports.StoppedDockerComposeEnvironment = exports.StartedDockerComposeEnvironment = exports.DockerComposeEnvironment = exports.TestContainers = exports.GenericContainerBuilder = exports.GenericContainer = void 0;
|
|
4
4
|
var generic_container_1 = require("./generic-container/generic-container");
|
|
5
5
|
Object.defineProperty(exports, "GenericContainer", { enumerable: true, get: function () { return generic_container_1.GenericContainer; } });
|
|
6
6
|
var generic_container_builder_1 = require("./generic-container/generic-container-builder");
|
|
@@ -39,3 +39,6 @@ Object.defineProperty(exports, "StartedArangoContainer", { enumerable: true, get
|
|
|
39
39
|
var elasticsearch_container_1 = require("./modules/elasticsearch/elasticsearch-container");
|
|
40
40
|
Object.defineProperty(exports, "ElasticsearchContainer", { enumerable: true, get: function () { return elasticsearch_container_1.ElasticsearchContainer; } });
|
|
41
41
|
Object.defineProperty(exports, "StartedElasticsearchContainer", { enumerable: true, get: function () { return elasticsearch_container_1.StartedElasticsearchContainer; } });
|
|
42
|
+
var mysql_container_1 = require("./modules/mysql/mysql-container");
|
|
43
|
+
Object.defineProperty(exports, "MySqlContainer", { enumerable: true, get: function () { return mysql_container_1.MySqlContainer; } });
|
|
44
|
+
Object.defineProperty(exports, "StartedMySqlContainer", { enumerable: true, get: function () { return mysql_container_1.StartedMySqlContainer; } });
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
2
|
import { StartedTestContainer, StopOptions, StoppedTestContainer } from "../test-container";
|
|
3
3
|
import { Port } from "../port";
|
|
4
|
-
import { ContainerName, Host, Id } from "../docker/types";
|
|
5
|
-
import { Command, ExecResult } from "../docker/types";
|
|
4
|
+
import { ContainerName, Host, Id, Command, ExecResult } from "../docker/types";
|
|
6
5
|
import { Readable } from "stream";
|
|
7
6
|
export declare class AbstractStartedContainer {
|
|
8
7
|
protected readonly startedTestContainer: StartedTestContainer;
|
|
@@ -63,7 +63,7 @@ class KafkaContainer extends generic_container_1.GenericContainer {
|
|
|
63
63
|
const zooKeeperHost = this.uuid.nextUuid();
|
|
64
64
|
zooKeeperPort = yield this.portGenerator.generatePort();
|
|
65
65
|
this.withEnv("KAFKA_ZOOKEEPER_CONNECT", `${zooKeeperHost}:${zooKeeperPort}`);
|
|
66
|
-
const zookeeperContainer =
|
|
66
|
+
const zookeeperContainer = new generic_container_1.GenericContainer(this.zooKeeperImage)
|
|
67
67
|
.withName(zooKeeperHost)
|
|
68
68
|
.withEnv("ZOOKEEPER_CLIENT_PORT", zooKeeperPort.toString());
|
|
69
69
|
if (this.networkMode !== undefined) {
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { GenericContainer } from "../../generic-container/generic-container";
|
|
2
|
+
import { StartedTestContainer } from "../../test-container";
|
|
3
|
+
import { AbstractStartedContainer } from "../abstract-started-container";
|
|
4
|
+
import { Port } from "../../port";
|
|
5
|
+
export declare class MySqlContainer extends GenericContainer {
|
|
6
|
+
private database;
|
|
7
|
+
private username;
|
|
8
|
+
private userPassword;
|
|
9
|
+
private rootPassword;
|
|
10
|
+
constructor(image?: string);
|
|
11
|
+
withDatabase(database: string): this;
|
|
12
|
+
withUsername(username: string): this;
|
|
13
|
+
withRootPassword(rootPassword: string): this;
|
|
14
|
+
withUserPassword(userPassword: string): this;
|
|
15
|
+
start(): Promise<StartedMySqlContainer>;
|
|
16
|
+
}
|
|
17
|
+
export declare class StartedMySqlContainer extends AbstractStartedContainer {
|
|
18
|
+
private readonly database;
|
|
19
|
+
private readonly username;
|
|
20
|
+
private readonly userPassword;
|
|
21
|
+
private readonly rootPassword;
|
|
22
|
+
private readonly port;
|
|
23
|
+
constructor(startedTestContainer: StartedTestContainer, database: string, username: string, userPassword: string, rootPassword: string);
|
|
24
|
+
getPort(): Port;
|
|
25
|
+
getDatabase(): string;
|
|
26
|
+
getUsername(): string;
|
|
27
|
+
getUserPassword(): string;
|
|
28
|
+
getRootPassword(): string;
|
|
29
|
+
executeQuery(query: string, additionalFlags?: string[]): Promise<string>;
|
|
30
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.StartedMySqlContainer = exports.MySqlContainer = void 0;
|
|
13
|
+
const generic_container_1 = require("../../generic-container/generic-container");
|
|
14
|
+
const uuid_1 = require("../../uuid");
|
|
15
|
+
const abstract_started_container_1 = require("../abstract-started-container");
|
|
16
|
+
class MySqlContainer extends generic_container_1.GenericContainer {
|
|
17
|
+
constructor(image = "mysql:8.0.26") {
|
|
18
|
+
super(image);
|
|
19
|
+
this.database = "test";
|
|
20
|
+
this.username = new uuid_1.RandomUuid().nextUuid();
|
|
21
|
+
this.userPassword = new uuid_1.RandomUuid().nextUuid();
|
|
22
|
+
this.rootPassword = new uuid_1.RandomUuid().nextUuid();
|
|
23
|
+
}
|
|
24
|
+
withDatabase(database) {
|
|
25
|
+
this.database = database;
|
|
26
|
+
return this;
|
|
27
|
+
}
|
|
28
|
+
withUsername(username) {
|
|
29
|
+
this.username = username;
|
|
30
|
+
return this;
|
|
31
|
+
}
|
|
32
|
+
withRootPassword(rootPassword) {
|
|
33
|
+
this.rootPassword = rootPassword;
|
|
34
|
+
return this;
|
|
35
|
+
}
|
|
36
|
+
withUserPassword(userPassword) {
|
|
37
|
+
this.userPassword = userPassword;
|
|
38
|
+
return this;
|
|
39
|
+
}
|
|
40
|
+
start() {
|
|
41
|
+
const _super = Object.create(null, {
|
|
42
|
+
start: { get: () => super.start }
|
|
43
|
+
});
|
|
44
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
45
|
+
this.withExposedPorts(3306)
|
|
46
|
+
.withEnv("MYSQL_DATABASE", this.database)
|
|
47
|
+
.withEnv("MYSQL_ROOT_PASSWORD", this.rootPassword)
|
|
48
|
+
.withEnv("MYSQL_USER", this.username)
|
|
49
|
+
.withEnv("MYSQL_PASSWORD", this.userPassword)
|
|
50
|
+
.withStartupTimeout(120000);
|
|
51
|
+
return new StartedMySqlContainer(yield _super.start.call(this), this.database, this.username, this.userPassword, this.rootPassword);
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
exports.MySqlContainer = MySqlContainer;
|
|
56
|
+
class StartedMySqlContainer extends abstract_started_container_1.AbstractStartedContainer {
|
|
57
|
+
constructor(startedTestContainer, database, username, userPassword, rootPassword) {
|
|
58
|
+
super(startedTestContainer);
|
|
59
|
+
this.database = database;
|
|
60
|
+
this.username = username;
|
|
61
|
+
this.userPassword = userPassword;
|
|
62
|
+
this.rootPassword = rootPassword;
|
|
63
|
+
this.port = startedTestContainer.getMappedPort(3306);
|
|
64
|
+
}
|
|
65
|
+
getPort() {
|
|
66
|
+
return this.port;
|
|
67
|
+
}
|
|
68
|
+
getDatabase() {
|
|
69
|
+
return this.database;
|
|
70
|
+
}
|
|
71
|
+
getUsername() {
|
|
72
|
+
return this.username;
|
|
73
|
+
}
|
|
74
|
+
getUserPassword() {
|
|
75
|
+
return this.userPassword;
|
|
76
|
+
}
|
|
77
|
+
getRootPassword() {
|
|
78
|
+
return this.rootPassword;
|
|
79
|
+
}
|
|
80
|
+
executeQuery(query, additionalFlags = []) {
|
|
81
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
82
|
+
const result = yield this.startedTestContainer.exec([
|
|
83
|
+
"mysql",
|
|
84
|
+
"-u",
|
|
85
|
+
this.username,
|
|
86
|
+
`-p${this.userPassword}`,
|
|
87
|
+
"-e",
|
|
88
|
+
`${query};`,
|
|
89
|
+
...additionalFlags,
|
|
90
|
+
]);
|
|
91
|
+
if (result.exitCode !== 0) {
|
|
92
|
+
throw new Error(`executeQuery failed with exit code ${result.exitCode} for query: ${query}`);
|
|
93
|
+
}
|
|
94
|
+
return result.output;
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
exports.StartedMySqlContainer = StartedMySqlContainer;
|
package/dist/network.d.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { Uuid } from "./uuid";
|
|
2
2
|
import { CreateNetworkOptions } from "./docker/functions/network/create-network";
|
|
3
3
|
export declare class Network {
|
|
4
|
-
private readonly uuid;
|
|
5
4
|
private readonly createNetworkOptions;
|
|
6
5
|
constructor(createNetworkOptions?: Partial<CreateNetworkOptions>, uuid?: Uuid);
|
|
7
6
|
start(): Promise<StartedNetwork>;
|
package/dist/network.js
CHANGED
|
@@ -17,8 +17,7 @@ const create_network_1 = require("./docker/functions/network/create-network");
|
|
|
17
17
|
const remove_network_1 = require("./docker/functions/network/remove-network");
|
|
18
18
|
class Network {
|
|
19
19
|
constructor(createNetworkOptions = {}, uuid = new uuid_1.RandomUuid()) {
|
|
20
|
-
this.
|
|
21
|
-
this.createNetworkOptions = Object.assign({ name: this.uuid.nextUuid(), driver: "bridge", checkDuplicate: true, internal: false, attachable: false, ingress: false, enableIPv6: false }, createNetworkOptions);
|
|
20
|
+
this.createNetworkOptions = Object.assign({ name: uuid.nextUuid(), driver: "bridge", checkDuplicate: true, internal: false, attachable: false, ingress: false, enableIPv6: false }, createNetworkOptions);
|
|
22
21
|
}
|
|
23
22
|
start() {
|
|
24
23
|
return __awaiter(this, void 0, void 0, function* () {
|
package/dist/reaper.d.ts
CHANGED
package/dist/reaper.js
CHANGED
|
@@ -17,14 +17,10 @@ const session_id_1 = require("./docker/session-id");
|
|
|
17
17
|
const docker_host_1 = require("./docker/docker-host");
|
|
18
18
|
const images_1 = require("./images");
|
|
19
19
|
class RealReaper {
|
|
20
|
-
constructor(
|
|
21
|
-
this.sessionId = sessionId;
|
|
20
|
+
constructor(container, socket) {
|
|
22
21
|
this.container = container;
|
|
23
22
|
this.socket = socket;
|
|
24
23
|
}
|
|
25
|
-
addProject(projectName) {
|
|
26
|
-
this.socket.write(`label=com.docker.compose.project=${projectName}\r\n`);
|
|
27
|
-
}
|
|
28
24
|
getContainerId() {
|
|
29
25
|
return this.container.getId();
|
|
30
26
|
}
|
|
@@ -33,9 +29,6 @@ class RealReaper {
|
|
|
33
29
|
}
|
|
34
30
|
}
|
|
35
31
|
class DisabledReaper {
|
|
36
|
-
addProject() {
|
|
37
|
-
// noop
|
|
38
|
-
}
|
|
39
32
|
stop() {
|
|
40
33
|
// noop
|
|
41
34
|
}
|
|
@@ -100,11 +93,12 @@ class ReaperInstance {
|
|
|
100
93
|
logger_1.log.warn(`Connection to Reaper ${container.getId()} closed`);
|
|
101
94
|
}
|
|
102
95
|
});
|
|
103
|
-
return
|
|
96
|
+
return new Promise((resolve) => {
|
|
104
97
|
socket.connect(port, host, () => {
|
|
105
98
|
logger_1.log.debug(`Connected to Reaper ${container.getId()}`);
|
|
106
99
|
socket.write(`label=org.testcontainers.session-id=${session_id_1.sessionId}\r\n`);
|
|
107
|
-
|
|
100
|
+
socket.write(`label=com.docker.compose.project=${session_id_1.sessionId}\r\n`);
|
|
101
|
+
const reaper = new RealReaper(container, socket);
|
|
108
102
|
resolve(reaper);
|
|
109
103
|
});
|
|
110
104
|
});
|
package/dist/wait-strategy.js
CHANGED
|
@@ -91,21 +91,16 @@ class LogWaitStrategy extends AbstractWaitStrategy {
|
|
|
91
91
|
return line.includes(this.message);
|
|
92
92
|
}
|
|
93
93
|
};
|
|
94
|
-
|
|
95
|
-
.on("data", (line) => {
|
|
96
|
-
if (comparisonFn(line)) {
|
|
97
|
-
stream.destroy();
|
|
98
|
-
clearTimeout(timeout);
|
|
99
|
-
resolve();
|
|
100
|
-
}
|
|
101
|
-
})
|
|
102
|
-
.on("err", (line) => {
|
|
94
|
+
const lineProcessor = (line) => {
|
|
103
95
|
if (comparisonFn(line)) {
|
|
104
96
|
stream.destroy();
|
|
105
97
|
clearTimeout(timeout);
|
|
106
98
|
resolve();
|
|
107
99
|
}
|
|
108
|
-
}
|
|
100
|
+
};
|
|
101
|
+
byline_1.default(stream)
|
|
102
|
+
.on("data", lineProcessor)
|
|
103
|
+
.on("err", lineProcessor)
|
|
109
104
|
.on("end", () => {
|
|
110
105
|
stream.destroy();
|
|
111
106
|
clearTimeout(timeout);
|
|
@@ -121,7 +116,7 @@ class HealthCheckWaitStrategy extends AbstractWaitStrategy {
|
|
|
121
116
|
return __awaiter(this, void 0, void 0, function* () {
|
|
122
117
|
logger_1.log.debug(`Waiting for health check`);
|
|
123
118
|
const retryStrategy = new retry_strategy_1.IntervalRetryStrategy(100);
|
|
124
|
-
const status = yield retryStrategy.retryUntil(() => __awaiter(this, void 0, void 0, function* () { return (yield inspect_container_1.inspectContainer(container)).healthCheckStatus; }), (
|
|
119
|
+
const status = yield retryStrategy.retryUntil(() => __awaiter(this, void 0, void 0, function* () { return (yield inspect_container_1.inspectContainer(container)).healthCheckStatus; }), (healthCheckStatus) => healthCheckStatus === "healthy" || healthCheckStatus === "unhealthy", () => {
|
|
125
120
|
const timeout = this.startupTimeout;
|
|
126
121
|
throw new Error(`Health check not healthy after ${timeout}ms for ${container.id}`);
|
|
127
122
|
}, this.startupTimeout);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "testcontainers",
|
|
3
3
|
"author": "Cristian Greco",
|
|
4
|
-
"version": "7.
|
|
4
|
+
"version": "7.22.0",
|
|
5
5
|
"main": "dist/index",
|
|
6
6
|
"types": "dist/index",
|
|
7
7
|
"keywords": [
|
|
@@ -37,41 +37,42 @@
|
|
|
37
37
|
"archiver": "^5.3.0",
|
|
38
38
|
"byline": "^5.0.0",
|
|
39
39
|
"debug": "^4.3.2",
|
|
40
|
-
"docker-compose": "^0.23.
|
|
41
|
-
"dockerode": "^3.3.
|
|
40
|
+
"docker-compose": "^0.23.13",
|
|
41
|
+
"dockerode": "^3.3.1",
|
|
42
42
|
"get-port": "^5.1.1",
|
|
43
|
-
"glob": "^7.
|
|
43
|
+
"glob": "^7.2.0",
|
|
44
44
|
"slash": "^3.0.0",
|
|
45
|
-
"ssh-remote-port-forward": "^1.0.
|
|
45
|
+
"ssh-remote-port-forward": "^1.0.4",
|
|
46
46
|
"tar-fs": "^2.1.1"
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
49
|
-
"@elastic/elasticsearch": "^7.
|
|
49
|
+
"@elastic/elasticsearch": "^7.14.1",
|
|
50
50
|
"@types/byline": "^4.2.33",
|
|
51
|
-
"@types/debug": "4.1.
|
|
51
|
+
"@types/debug": "4.1.7",
|
|
52
52
|
"@types/glob": "^7.1.4",
|
|
53
|
-
"@types/jest": "^
|
|
54
|
-
"@types/node": "^16.
|
|
53
|
+
"@types/jest": "^27.0.2",
|
|
54
|
+
"@types/node": "^16.9.6",
|
|
55
55
|
"@types/node-fetch": "^2.5.11",
|
|
56
56
|
"@types/pg": "^8.6.1",
|
|
57
57
|
"@types/tar-fs": "^2.0.1",
|
|
58
|
-
"@typescript-eslint/eslint-plugin": "^4.
|
|
59
|
-
"@typescript-eslint/parser": "^4.
|
|
58
|
+
"@typescript-eslint/eslint-plugin": "^4.31.2",
|
|
59
|
+
"@typescript-eslint/parser": "^4.31.2",
|
|
60
60
|
"arangojs": "^7.5.0",
|
|
61
61
|
"cross-env": "^7.0.3",
|
|
62
|
-
"eslint": "^7.
|
|
62
|
+
"eslint": "^7.32.0",
|
|
63
63
|
"eslint-config-prettier": "^8.3.0",
|
|
64
|
-
"husky": "^7.0.
|
|
65
|
-
"jest": "^27.
|
|
64
|
+
"husky": "^7.0.2",
|
|
65
|
+
"jest": "^27.2.1",
|
|
66
66
|
"kafkajs": "^1.15.0",
|
|
67
|
-
"lint-staged": "^
|
|
68
|
-
"
|
|
67
|
+
"lint-staged": "^11.1.2",
|
|
68
|
+
"mysql2": "^2.3.0",
|
|
69
|
+
"neo4j-driver": "^4.3.3",
|
|
69
70
|
"node-fetch": "^2.6.1",
|
|
70
|
-
"pg": "^8.
|
|
71
|
-
"prettier": "^2.
|
|
71
|
+
"pg": "^8.7.1",
|
|
72
|
+
"prettier": "^2.4.1",
|
|
72
73
|
"rimraf": "^3.0.2",
|
|
73
|
-
"ts-jest": "^27.0.
|
|
74
|
-
"ts-node": "^10.1
|
|
74
|
+
"ts-jest": "^27.0.5",
|
|
75
|
+
"ts-node": "^10.2.1",
|
|
75
76
|
"typescript": "^4.3.5",
|
|
76
77
|
"wait-for-expect": "^3.0.2"
|
|
77
78
|
},
|