testcontainers 9.5.0 → 9.7.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/dist/package.json +14 -14
- package/dist/src/docker/docker-client-config.js +42 -36
- package/dist/src/docker/docker-client.d.ts +2 -0
- package/dist/src/docker/docker-client.js +6 -5
- package/dist/src/docker/functions/container/attach-container.js +1 -1
- package/dist/src/docker/functions/container/create-container.js +6 -4
- package/dist/src/docker/functions/container/exec-container.d.ts +2 -1
- package/dist/src/docker/functions/container/exec-container.js +15 -8
- package/dist/src/docker/functions/container/get-container.js +1 -1
- package/dist/src/docker/functions/container/inspect-container.js +1 -1
- package/dist/src/docker/functions/container/put-container-archive.js +5 -2
- package/dist/src/docker/functions/container/remove-container.js +1 -1
- package/dist/src/docker/functions/container/restart-container.js +1 -1
- package/dist/src/docker/functions/container/start-container.js +1 -1
- package/dist/src/docker/functions/container/stop-container.js +2 -2
- package/dist/src/docker/functions/create-labels.js +0 -3
- package/dist/src/docker/functions/image/build-image.js +8 -3
- package/dist/src/docker/functions/image/image-exists.js +11 -8
- package/dist/src/docker/functions/image/pull-image.js +3 -3
- package/dist/src/docker/functions/network/connect-network.js +3 -2
- package/dist/src/docker/functions/network/create-network.js +2 -1
- package/dist/src/docker/functions/network/remove-network.js +3 -2
- package/dist/src/docker/functions/run-in-container.js +6 -6
- package/dist/src/docker/pull-stream-parser.d.ts +0 -1
- package/dist/src/docker/pull-stream-parser.js +2 -41
- package/dist/src/docker/resolve-host.d.ts +2 -1
- package/dist/src/docker/resolve-host.js +7 -6
- package/dist/src/docker-compose/default-docker-compose-options.js +4 -2
- package/dist/src/docker-compose/docker-compose-options.d.ts +2 -0
- package/dist/src/docker-compose/functions/docker-compose-down.js +1 -1
- package/dist/src/docker-compose/functions/docker-compose-pull.js +4 -4
- package/dist/src/docker-compose/functions/docker-compose-stop.js +1 -1
- package/dist/src/docker-compose/functions/docker-compose-up.js +1 -1
- package/dist/src/docker-compose-environment/docker-compose-environment.d.ts +1 -1
- package/dist/src/docker-compose-environment/docker-compose-environment.js +11 -10
- package/dist/src/generic-container/generic-container-builder.js +1 -1
- package/dist/src/generic-container/generic-container.d.ts +6 -2
- package/dist/src/generic-container/generic-container.js +30 -17
- package/dist/src/generic-container/started-generic-container.d.ts +2 -0
- package/dist/src/generic-container/started-generic-container.js +26 -7
- package/dist/src/images.js +1 -1
- package/dist/src/logger.d.ts +20 -31
- package/dist/src/logger.js +32 -42
- package/dist/src/modules/elasticsearch/elasticsearch-container.js +1 -1
- package/dist/src/modules/nats/nats-container.js +1 -1
- package/dist/src/network.d.ts +1 -0
- package/dist/src/network.js +11 -5
- package/dist/src/port-check.d.ts +4 -1
- package/dist/src/port-check.js +10 -4
- package/dist/src/port-forwarder.js +5 -3
- package/dist/src/reaper.js +11 -7
- package/dist/src/registry-auth-locator/credential-provider.js +3 -5
- package/dist/src/registry-auth-locator/get-auth-config.js +3 -3
- package/dist/src/system-info.js +2 -5
- package/dist/src/test-container.d.ts +2 -6
- package/dist/src/uuid.js +1 -1
- package/dist/src/wait-for-container.d.ts +1 -1
- package/dist/src/wait-for-container.js +6 -6
- package/dist/src/wait-strategy/composite-wait-strategy.d.ts +11 -0
- package/dist/src/wait-strategy/composite-wait-strategy.js +54 -0
- package/dist/src/wait-strategy/health-check-wait-strategy.js +7 -3
- package/dist/src/wait-strategy/host-port-wait-strategy.d.ts +1 -5
- package/dist/src/wait-strategy/host-port-wait-strategy.js +21 -17
- package/dist/src/wait-strategy/http-wait-strategy.d.ts +1 -1
- package/dist/src/wait-strategy/http-wait-strategy.js +8 -2
- package/dist/src/wait-strategy/log-wait-strategy.d.ts +1 -1
- package/dist/src/wait-strategy/log-wait-strategy.js +8 -7
- package/dist/src/wait-strategy/shell-wait-strategy.js +7 -4
- package/dist/src/wait-strategy/startup-check-strategy.js +6 -1
- package/dist/src/wait-strategy/wait-strategy.d.ts +8 -3
- package/dist/src/wait-strategy/wait-strategy.js +8 -0
- package/dist/src/wait-strategy/wait.d.ts +3 -0
- package/dist/src/wait-strategy/wait.js +8 -0
- package/package.json +14 -14
- package/dist/src/docker/functions/image/list-images.d.ts +0 -3
- package/dist/src/docker/functions/image/list-images.js +0 -34
- package/dist/src/wait-strategy/default-wait-strategy.d.ts +0 -3
- package/dist/src/wait-strategy/default-wait-strategy.js +0 -7
|
@@ -3,4 +3,5 @@
|
|
|
3
3
|
/// <reference types="node" />
|
|
4
4
|
/// <reference types="node" />
|
|
5
5
|
import Dockerode from "dockerode";
|
|
6
|
-
|
|
6
|
+
import { Provider } from "./docker-client";
|
|
7
|
+
export declare const resolveHost: (dockerode: Dockerode, provider: Provider, indexServerAddress: string, uri: string, env?: NodeJS.ProcessEnv) => Promise<string>;
|
|
@@ -14,7 +14,7 @@ const url_1 = require("url");
|
|
|
14
14
|
const logger_1 = require("../logger");
|
|
15
15
|
const run_in_container_1 = require("./functions/run-in-container");
|
|
16
16
|
const fs_1 = require("fs");
|
|
17
|
-
const resolveHost = (dockerode, indexServerAddress, uri, env = process.env) => __awaiter(void 0, void 0, void 0, function* () {
|
|
17
|
+
const resolveHost = (dockerode, provider, indexServerAddress, uri, env = process.env) => __awaiter(void 0, void 0, void 0, function* () {
|
|
18
18
|
if (env.TESTCONTAINERS_HOST_OVERRIDE !== undefined) {
|
|
19
19
|
return env.TESTCONTAINERS_HOST_OVERRIDE;
|
|
20
20
|
}
|
|
@@ -27,7 +27,8 @@ const resolveHost = (dockerode, indexServerAddress, uri, env = process.env) => _
|
|
|
27
27
|
case "unix:":
|
|
28
28
|
case "npipe:": {
|
|
29
29
|
if (isInContainer()) {
|
|
30
|
-
const
|
|
30
|
+
const networkName = provider === "podman" ? "podman" : "bridge";
|
|
31
|
+
const gateway = yield findGateway(dockerode, networkName);
|
|
31
32
|
if (gateway !== undefined) {
|
|
32
33
|
return gateway;
|
|
33
34
|
}
|
|
@@ -43,14 +44,14 @@ const resolveHost = (dockerode, indexServerAddress, uri, env = process.env) => _
|
|
|
43
44
|
}
|
|
44
45
|
});
|
|
45
46
|
exports.resolveHost = resolveHost;
|
|
46
|
-
const findGateway = (dockerode) => __awaiter(void 0, void 0, void 0, function* () {
|
|
47
|
+
const findGateway = (dockerode, networkName) => __awaiter(void 0, void 0, void 0, function* () {
|
|
47
48
|
var _a, _b, _c;
|
|
48
|
-
logger_1.log.debug(`Checking gateway for Docker host
|
|
49
|
-
const inspectResult = yield dockerode.getNetwork(
|
|
49
|
+
logger_1.log.debug(`Checking gateway for Docker host...`);
|
|
50
|
+
const inspectResult = yield dockerode.getNetwork(networkName).inspect();
|
|
50
51
|
return (_c = (_b = (_a = inspectResult === null || inspectResult === void 0 ? void 0 : inspectResult.IPAM) === null || _a === void 0 ? void 0 : _a.Config) === null || _b === void 0 ? void 0 : _b.find((config) => config.Gateway !== undefined)) === null || _c === void 0 ? void 0 : _c.Gateway;
|
|
51
52
|
});
|
|
52
53
|
const findDefaultGateway = (dockerode, indexServerAddress) => __awaiter(void 0, void 0, void 0, function* () {
|
|
53
|
-
logger_1.log.debug(`Checking default gateway for Docker host
|
|
54
|
+
logger_1.log.debug(`Checking default gateway for Docker host...`);
|
|
54
55
|
return (0, run_in_container_1.runInContainer)(dockerode, indexServerAddress, "alpine:3.14", [
|
|
55
56
|
"sh",
|
|
56
57
|
"-c",
|
|
@@ -26,17 +26,19 @@ const logger_1 = require("../logger");
|
|
|
26
26
|
const os_1 = require("os");
|
|
27
27
|
const type_guards_1 = require("../type-guards");
|
|
28
28
|
const defaultDockerComposeOptions = (_a) => __awaiter(void 0, void 0, void 0, function* () {
|
|
29
|
+
var _b;
|
|
29
30
|
var { environment = {} } = _a, options = __rest(_a, ["environment"]);
|
|
30
31
|
const { composeEnvironment } = yield (0, docker_client_1.dockerClient)();
|
|
32
|
+
const log = (_b = options.logger) !== null && _b !== void 0 ? _b : logger_1.composeLog;
|
|
31
33
|
return {
|
|
32
34
|
log: false,
|
|
33
|
-
callback:
|
|
35
|
+
callback: log.enabled()
|
|
34
36
|
? (chunk) => {
|
|
35
37
|
chunk
|
|
36
38
|
.toString()
|
|
37
39
|
.split(os_1.EOL)
|
|
38
40
|
.filter(type_guards_1.isNotEmptyString)
|
|
39
|
-
.forEach((line) =>
|
|
41
|
+
.forEach((line) => log.trace(line.trim()));
|
|
40
42
|
}
|
|
41
43
|
: undefined,
|
|
42
44
|
cwd: options.filePath,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Environment } from "../docker/types";
|
|
2
|
+
import { Logger } from "../logger";
|
|
2
3
|
export type DockerComposeOptions = {
|
|
3
4
|
filePath: string;
|
|
4
5
|
files: string | string[];
|
|
@@ -6,4 +7,5 @@ export type DockerComposeOptions = {
|
|
|
6
7
|
commandOptions?: string[];
|
|
7
8
|
composeOptions?: string[];
|
|
8
9
|
environment?: Environment;
|
|
10
|
+
logger?: Logger;
|
|
9
11
|
};
|
|
@@ -14,7 +14,7 @@ const logger_1 = require("../../logger");
|
|
|
14
14
|
const default_docker_compose_options_1 = require("../default-docker-compose-options");
|
|
15
15
|
const docker_compose_1 = require("docker-compose");
|
|
16
16
|
const dockerComposeDown = (options, downOptions) => __awaiter(void 0, void 0, void 0, function* () {
|
|
17
|
-
logger_1.log.info(`Downing DockerCompose environment
|
|
17
|
+
logger_1.log.info(`Downing DockerCompose environment...`);
|
|
18
18
|
try {
|
|
19
19
|
yield (0, docker_compose_1.down)(Object.assign(Object.assign({}, (yield (0, default_docker_compose_options_1.defaultDockerComposeOptions)(options))), { commandOptions: commandOptions(downOptions) }));
|
|
20
20
|
logger_1.log.info(`Downed DockerCompose environment`);
|
|
@@ -16,12 +16,12 @@ const default_docker_compose_options_1 = require("../default-docker-compose-opti
|
|
|
16
16
|
const dockerComposePull = (options, services) => __awaiter(void 0, void 0, void 0, function* () {
|
|
17
17
|
try {
|
|
18
18
|
if (services) {
|
|
19
|
-
logger_1.log.info(`Pulling DockerCompose environment images
|
|
20
|
-
yield (0, docker_compose_1.pullMany)(services, yield (0, default_docker_compose_options_1.defaultDockerComposeOptions)(options));
|
|
19
|
+
logger_1.log.info(`Pulling DockerCompose environment images "${services.join('", "')}"...`);
|
|
20
|
+
yield (0, docker_compose_1.pullMany)(services, yield (0, default_docker_compose_options_1.defaultDockerComposeOptions)(Object.assign(Object.assign({}, options), { logger: logger_1.pullLog })));
|
|
21
21
|
}
|
|
22
22
|
else {
|
|
23
|
-
logger_1.log.info(`Pulling DockerCompose environment images
|
|
24
|
-
yield (0, docker_compose_1.pullAll)(yield (0, default_docker_compose_options_1.defaultDockerComposeOptions)(options));
|
|
23
|
+
logger_1.log.info(`Pulling DockerCompose environment images...`);
|
|
24
|
+
yield (0, docker_compose_1.pullAll)(yield (0, default_docker_compose_options_1.defaultDockerComposeOptions)(Object.assign(Object.assign({}, options), { logger: logger_1.pullLog })));
|
|
25
25
|
}
|
|
26
26
|
logger_1.log.info(`Pulled DockerCompose environment`);
|
|
27
27
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
@@ -14,7 +14,7 @@ const logger_1 = require("../../logger");
|
|
|
14
14
|
const docker_compose_1 = require("docker-compose");
|
|
15
15
|
const default_docker_compose_options_1 = require("../default-docker-compose-options");
|
|
16
16
|
const dockerComposeStop = (options) => __awaiter(void 0, void 0, void 0, function* () {
|
|
17
|
-
logger_1.log.info(`Stopping DockerCompose environment
|
|
17
|
+
logger_1.log.info(`Stopping DockerCompose environment...`);
|
|
18
18
|
try {
|
|
19
19
|
yield (0, docker_compose_1.stop)(yield (0, default_docker_compose_options_1.defaultDockerComposeOptions)(options));
|
|
20
20
|
logger_1.log.info(`Stopped DockerCompose environment`);
|
|
@@ -15,7 +15,7 @@ const docker_compose_1 = require("docker-compose");
|
|
|
15
15
|
const default_docker_compose_options_1 = require("../default-docker-compose-options");
|
|
16
16
|
const docker_compose_down_1 = require("./docker-compose-down");
|
|
17
17
|
const dockerComposeUp = (options, services) => __awaiter(void 0, void 0, void 0, function* () {
|
|
18
|
-
logger_1.log.info(`Upping DockerCompose environment
|
|
18
|
+
logger_1.log.info(`Upping DockerCompose environment...`);
|
|
19
19
|
try {
|
|
20
20
|
if (services) {
|
|
21
21
|
yield (0, docker_compose_1.upMany)(services, yield (0, default_docker_compose_options_1.defaultDockerComposeOptions)(options));
|
|
@@ -14,7 +14,7 @@ export declare class DockerComposeEnvironment {
|
|
|
14
14
|
private environment;
|
|
15
15
|
private pullPolicy;
|
|
16
16
|
private waitStrategy;
|
|
17
|
-
private startupTimeout
|
|
17
|
+
private startupTimeout?;
|
|
18
18
|
constructor(composeFilePath: string, composeFiles: string | string[], uuid?: Uuid);
|
|
19
19
|
withBuild(): this;
|
|
20
20
|
withEnvironment(environment: Environment): this;
|
|
@@ -25,9 +25,9 @@ const started_docker_compose_environment_1 = require("./started-docker-compose-e
|
|
|
25
25
|
const docker_compose_down_1 = require("../docker-compose/functions/docker-compose-down");
|
|
26
26
|
const docker_compose_up_1 = require("../docker-compose/functions/docker-compose-up");
|
|
27
27
|
const wait_for_container_1 = require("../wait-for-container");
|
|
28
|
-
const default_wait_strategy_1 = require("../wait-strategy/default-wait-strategy");
|
|
29
28
|
const pull_policy_1 = require("../pull-policy");
|
|
30
29
|
const docker_compose_pull_1 = require("../docker-compose/functions/docker-compose-pull");
|
|
30
|
+
const wait_1 = require("../wait-strategy/wait");
|
|
31
31
|
class DockerComposeEnvironment {
|
|
32
32
|
constructor(composeFilePath, composeFiles, uuid = new uuid_1.RandomUuid()) {
|
|
33
33
|
this.build = false;
|
|
@@ -37,7 +37,6 @@ class DockerComposeEnvironment {
|
|
|
37
37
|
this.environment = {};
|
|
38
38
|
this.pullPolicy = new pull_policy_1.DefaultPullPolicy();
|
|
39
39
|
this.waitStrategy = {};
|
|
40
|
-
this.startupTimeout = 60000;
|
|
41
40
|
this.composeFilePath = composeFilePath;
|
|
42
41
|
this.composeFiles = composeFiles;
|
|
43
42
|
this.projectName = `testcontainers-${uuid.nextUuid()}`;
|
|
@@ -77,7 +76,7 @@ class DockerComposeEnvironment {
|
|
|
77
76
|
}
|
|
78
77
|
up(services) {
|
|
79
78
|
return __awaiter(this, void 0, void 0, function* () {
|
|
80
|
-
logger_1.log.info(`Starting DockerCompose environment
|
|
79
|
+
logger_1.log.info(`Starting DockerCompose environment "${this.projectName}"...`);
|
|
81
80
|
(yield reaper_1.ReaperInstance.getInstance()).addProject(this.projectName);
|
|
82
81
|
const options = {
|
|
83
82
|
filePath: this.composeFilePath,
|
|
@@ -105,26 +104,28 @@ class DockerComposeEnvironment {
|
|
|
105
104
|
...containerNames,
|
|
106
105
|
startedContainer.Names.join(", "),
|
|
107
106
|
], []);
|
|
108
|
-
logger_1.log.info(`Started
|
|
107
|
+
logger_1.log.info(`Started containers "${startedContainerNames.join('", "')}"`);
|
|
109
108
|
const startedGenericContainers = (yield Promise.all(startedContainers.map((startedContainer) => __awaiter(this, void 0, void 0, function* () {
|
|
110
109
|
const container = yield (0, get_container_1.getContainerById)(startedContainer.Id);
|
|
111
110
|
const containerName = (0, container_name_resolver_1.resolveContainerName)(this.projectName, startedContainer.Names[0]);
|
|
112
111
|
const { host, hostIps } = yield (0, docker_client_1.dockerClient)();
|
|
113
112
|
const inspectResult = yield (0, inspect_container_1.inspectContainer)(container);
|
|
114
113
|
const boundPorts = bound_ports_1.BoundPorts.fromInspectResult(hostIps, inspectResult);
|
|
115
|
-
const waitStrategy =
|
|
114
|
+
const waitStrategy = this.waitStrategy[containerName]
|
|
115
|
+
? this.waitStrategy[containerName]
|
|
116
|
+
: wait_1.Wait.forListeningPorts();
|
|
117
|
+
if (this.startupTimeout !== undefined) {
|
|
118
|
+
waitStrategy.withStartupTimeout(this.startupTimeout);
|
|
119
|
+
}
|
|
116
120
|
if (logger_1.containerLog.enabled()) {
|
|
117
121
|
(yield (0, container_logs_1.containerLogs)(container))
|
|
118
122
|
.on("data", (data) => logger_1.containerLog.trace(`${containerName}: ${data.trim()}`))
|
|
119
123
|
.on("err", (data) => logger_1.containerLog.error(`${containerName}: ${data.trim()}`));
|
|
120
124
|
}
|
|
121
125
|
try {
|
|
122
|
-
|
|
123
|
-
yield (0, wait_for_container_1.waitForContainer)(container, waitStrategy, host, boundPorts);
|
|
124
|
-
logger_1.log.info(`Container ${containerName} is ready`);
|
|
126
|
+
yield (0, wait_for_container_1.waitForContainer)(container, waitStrategy, boundPorts);
|
|
125
127
|
}
|
|
126
128
|
catch (err) {
|
|
127
|
-
logger_1.log.error(`Container ${containerName} failed to be ready: ${err}`);
|
|
128
129
|
try {
|
|
129
130
|
yield (0, docker_compose_down_1.dockerComposeDown)(options, { removeVolumes: true, timeout: 0 });
|
|
130
131
|
}
|
|
@@ -138,7 +139,7 @@ class DockerComposeEnvironment {
|
|
|
138
139
|
const containerName = startedGenericContainer.getName();
|
|
139
140
|
return Object.assign(Object.assign({}, map), { [containerName]: startedGenericContainer });
|
|
140
141
|
}, {});
|
|
141
|
-
logger_1.log.info(`DockerCompose environment started
|
|
142
|
+
logger_1.log.info(`DockerCompose environment started`);
|
|
142
143
|
return new started_docker_compose_environment_1.StartedDockerComposeEnvironment(startedGenericContainers, Object.assign(Object.assign({}, options), { composeOptions, environment: this.environment }));
|
|
143
144
|
});
|
|
144
145
|
}
|
|
@@ -52,7 +52,7 @@ class GenericContainerBuilder {
|
|
|
52
52
|
const imageName = docker_image_name_1.DockerImageName.fromString(image);
|
|
53
53
|
yield reaper_1.ReaperInstance.getInstance();
|
|
54
54
|
const dockerfile = path_1.default.resolve(this.context, this.dockerfileName);
|
|
55
|
-
logger_1.log.debug(`Preparing to build Dockerfile
|
|
55
|
+
logger_1.log.debug(`Preparing to build Dockerfile "${dockerfile}" as image "${imageName}"...`);
|
|
56
56
|
const imageNames = yield (0, dockerfile_parser_1.getDockerfileImages)(dockerfile, this.buildArgs);
|
|
57
57
|
const { dockerode, indexServerAddress } = yield (0, docker_client_1.dockerClient)();
|
|
58
58
|
const registryConfig = yield this.getRegistryConfig(indexServerAddress, imageNames);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
1
2
|
import archiver from "archiver";
|
|
2
3
|
import { BoundPorts } from "../bound-ports";
|
|
3
4
|
import { PortWithOptionalBinding } from "../port";
|
|
@@ -9,16 +10,18 @@ import { CreateContainerOptions } from "../docker/functions/container/create-con
|
|
|
9
10
|
import { InspectResult } from "../docker/functions/container/inspect-container";
|
|
10
11
|
import { GenericContainerBuilder } from "./generic-container-builder";
|
|
11
12
|
import { StartedNetwork } from "../network";
|
|
13
|
+
import { Readable } from "stream";
|
|
12
14
|
export declare class GenericContainer implements TestContainer {
|
|
13
15
|
readonly image: string;
|
|
14
16
|
static fromDockerfile(context: string, dockerfileName?: string): GenericContainerBuilder;
|
|
15
17
|
protected opts: CreateContainerOptions;
|
|
16
|
-
protected startupTimeout
|
|
17
|
-
protected waitStrategy
|
|
18
|
+
protected startupTimeout?: number;
|
|
19
|
+
protected waitStrategy: WaitStrategy;
|
|
18
20
|
protected tarToCopy?: archiver.Archiver;
|
|
19
21
|
protected networkMode?: string;
|
|
20
22
|
protected networkAliases: string[];
|
|
21
23
|
protected pullPolicy: PullPolicy;
|
|
24
|
+
protected logConsumer?: (stream: Readable) => unknown;
|
|
22
25
|
constructor(image: string);
|
|
23
26
|
/**
|
|
24
27
|
* @deprecated Since version 9.4.0. Will be removed in version 10.0.0. Use `beforeContainerStarted` instead.
|
|
@@ -65,4 +68,5 @@ export declare class GenericContainer implements TestContainer {
|
|
|
65
68
|
protected getTarToCopy(): archiver.Archiver;
|
|
66
69
|
withWorkingDir(workingDir: string): this;
|
|
67
70
|
withResourcesQuota({ memory, cpu }: ResourcesQuota): this;
|
|
71
|
+
withLogConsumer(logConsumer: (stream: Readable) => unknown): this;
|
|
68
72
|
}
|
|
@@ -36,7 +36,7 @@ const get_container_1 = require("../docker/functions/container/get-container");
|
|
|
36
36
|
const labels_1 = require("../labels");
|
|
37
37
|
const wait_for_container_1 = require("../wait-for-container");
|
|
38
38
|
const create_container_options_1 = require("./create-container-options");
|
|
39
|
-
const
|
|
39
|
+
const wait_1 = require("../wait-strategy/wait");
|
|
40
40
|
const reusableContainerCreationLock = new async_lock_1.default();
|
|
41
41
|
class GenericContainer {
|
|
42
42
|
static fromDockerfile(context, dockerfileName = "Dockerfile") {
|
|
@@ -44,7 +44,7 @@ class GenericContainer {
|
|
|
44
44
|
}
|
|
45
45
|
constructor(image) {
|
|
46
46
|
this.image = image;
|
|
47
|
-
this.
|
|
47
|
+
this.waitStrategy = wait_1.Wait.forListeningPorts();
|
|
48
48
|
this.networkAliases = [];
|
|
49
49
|
this.pullPolicy = new pull_policy_1.DefaultPullPolicy();
|
|
50
50
|
const imageName = docker_image_name_1.DockerImageName.fromString(image);
|
|
@@ -79,14 +79,14 @@ class GenericContainer {
|
|
|
79
79
|
if (this.opts.reusable) {
|
|
80
80
|
const containerHash = (0, hash_1.hash)(JSON.stringify(this.opts));
|
|
81
81
|
this.opts.labels = Object.assign(Object.assign({}, this.opts.labels), { [labels_1.LABEL_TESTCONTAINERS_CONTAINER_HASH]: containerHash });
|
|
82
|
-
logger_1.log.debug(`Container reuse has been enabled
|
|
82
|
+
logger_1.log.debug(`Container reuse has been enabled with hash "${containerHash}"`);
|
|
83
83
|
// We might have several async processes try to create a reusable container
|
|
84
84
|
// at once, to avoid possibly creating too many of these, use a lock
|
|
85
85
|
// on the containerHash, this ensures that only single reusable instance is created
|
|
86
86
|
return reusableContainerCreationLock.acquire(containerHash, () => __awaiter(this, void 0, void 0, function* () {
|
|
87
87
|
const container = yield (0, get_container_1.getContainerByHash)(containerHash);
|
|
88
88
|
if (container !== undefined) {
|
|
89
|
-
logger_1.log.debug(`Found container to reuse with hash
|
|
89
|
+
logger_1.log.debug(`Found container to reuse with hash "${containerHash}"`, { containerId: container.id });
|
|
90
90
|
return this.reuseContainer(container);
|
|
91
91
|
}
|
|
92
92
|
else {
|
|
@@ -101,17 +101,18 @@ class GenericContainer {
|
|
|
101
101
|
});
|
|
102
102
|
}
|
|
103
103
|
reuseContainer(container) {
|
|
104
|
-
var _a;
|
|
105
104
|
return __awaiter(this, void 0, void 0, function* () {
|
|
106
105
|
const { host, hostIps } = yield (0, docker_client_1.dockerClient)();
|
|
107
106
|
const inspectResult = yield (0, inspect_container_1.inspectContainer)(container);
|
|
108
107
|
const boundPorts = bound_ports_1.BoundPorts.fromInspectResult(hostIps, inspectResult).filter(this.opts.exposedPorts);
|
|
109
|
-
|
|
108
|
+
if (this.startupTimeout !== undefined) {
|
|
109
|
+
this.waitStrategy.withStartupTimeout(this.startupTimeout);
|
|
110
|
+
}
|
|
110
111
|
if (this.containerStarting) {
|
|
111
112
|
yield this.containerStarting(inspectResult, true);
|
|
112
113
|
}
|
|
113
|
-
yield (0, wait_for_container_1.waitForContainer)(container, waitStrategy,
|
|
114
|
-
const startedContainer = new started_generic_container_1.StartedGenericContainer(container, host, inspectResult, boundPorts, inspectResult.name, waitStrategy);
|
|
114
|
+
yield (0, wait_for_container_1.waitForContainer)(container, this.waitStrategy, boundPorts);
|
|
115
|
+
const startedContainer = new started_generic_container_1.StartedGenericContainer(container, host, inspectResult, boundPorts, inspectResult.name, this.waitStrategy);
|
|
115
116
|
if (this.containerStarted) {
|
|
116
117
|
yield this.containerStarted(startedContainer, inspectResult, true);
|
|
117
118
|
}
|
|
@@ -122,7 +123,6 @@ class GenericContainer {
|
|
|
122
123
|
});
|
|
123
124
|
}
|
|
124
125
|
startContainer(createContainerOptions) {
|
|
125
|
-
var _a;
|
|
126
126
|
return __awaiter(this, void 0, void 0, function* () {
|
|
127
127
|
const container = yield (0, create_container_1.createContainer)(createContainerOptions);
|
|
128
128
|
if (!this.opts.imageName.isHelperContainer() && port_forwarder_1.PortForwarderInstance.isRunning()) {
|
|
@@ -148,25 +148,34 @@ class GenericContainer {
|
|
|
148
148
|
this.tarToCopy.finalize();
|
|
149
149
|
yield (0, put_container_archive_1.putContainerArchive)({ container, stream: this.tarToCopy, containerPath: "/" });
|
|
150
150
|
}
|
|
151
|
-
logger_1.log.info(`Starting container ${this.opts.imageName}
|
|
151
|
+
logger_1.log.info(`Starting container for image "${this.opts.imageName}"...`, { containerId: container.id });
|
|
152
152
|
if (this.containerCreated) {
|
|
153
153
|
yield this.containerCreated(container.id);
|
|
154
154
|
}
|
|
155
155
|
yield (0, start_container_1.startContainer)(container);
|
|
156
|
+
logger_1.log.info(`Started container for image "${this.opts.imageName}"`, { containerId: container.id });
|
|
156
157
|
const { host, hostIps } = yield (0, docker_client_1.dockerClient)();
|
|
157
158
|
const inspectResult = yield (0, inspect_container_1.inspectContainer)(container);
|
|
158
159
|
const boundPorts = bound_ports_1.BoundPorts.fromInspectResult(hostIps, inspectResult).filter(this.opts.exposedPorts);
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
160
|
+
if (this.startupTimeout !== undefined) {
|
|
161
|
+
this.waitStrategy.withStartupTimeout(this.startupTimeout);
|
|
162
|
+
}
|
|
163
|
+
if (logger_1.containerLog.enabled() || this.logConsumer !== undefined) {
|
|
164
|
+
const logStream = yield (0, container_logs_1.containerLogs)(container);
|
|
165
|
+
if (this.logConsumer !== undefined) {
|
|
166
|
+
this.logConsumer(logStream);
|
|
167
|
+
}
|
|
168
|
+
if (logger_1.containerLog.enabled()) {
|
|
169
|
+
logStream
|
|
170
|
+
.on("data", (data) => logger_1.containerLog.trace(data.trim(), { containerId: container.id }))
|
|
171
|
+
.on("err", (data) => logger_1.containerLog.error(data.trim(), { containerId: container.id }));
|
|
172
|
+
}
|
|
164
173
|
}
|
|
165
174
|
if (this.containerStarting) {
|
|
166
175
|
yield this.containerStarting(inspectResult, false);
|
|
167
176
|
}
|
|
168
|
-
yield (0, wait_for_container_1.waitForContainer)(container, waitStrategy,
|
|
169
|
-
const startedContainer = new started_generic_container_1.StartedGenericContainer(container, host, inspectResult, boundPorts, inspectResult.name, waitStrategy);
|
|
177
|
+
yield (0, wait_for_container_1.waitForContainer)(container, this.waitStrategy, boundPorts);
|
|
178
|
+
const startedContainer = new started_generic_container_1.StartedGenericContainer(container, host, inspectResult, boundPorts, inspectResult.name, this.waitStrategy);
|
|
170
179
|
if (this.containerStarted) {
|
|
171
180
|
yield this.containerStarted(startedContainer, inspectResult, false);
|
|
172
181
|
}
|
|
@@ -305,5 +314,9 @@ class GenericContainer {
|
|
|
305
314
|
this.opts.resourcesQuota = { memory: ram, cpu: cpuQuota };
|
|
306
315
|
return this;
|
|
307
316
|
}
|
|
317
|
+
withLogConsumer(logConsumer) {
|
|
318
|
+
this.logConsumer = logConsumer;
|
|
319
|
+
return this;
|
|
320
|
+
}
|
|
308
321
|
}
|
|
309
322
|
exports.GenericContainer = GenericContainer;
|
|
@@ -13,6 +13,8 @@ export declare class StartedGenericContainer implements StartedTestContainer {
|
|
|
13
13
|
private boundPorts;
|
|
14
14
|
private readonly name;
|
|
15
15
|
private readonly waitStrategy;
|
|
16
|
+
private stoppedContainer?;
|
|
17
|
+
private stopContainerLock;
|
|
16
18
|
constructor(container: Dockerode.Container, host: string, inspectResult: InspectResult, boundPorts: BoundPorts, name: string, waitStrategy: WaitStrategy);
|
|
17
19
|
protected containerIsStopping?(): Promise<void>;
|
|
18
20
|
stop(options?: Partial<StopOptions>): Promise<StoppedTestContainer>;
|
|
@@ -8,6 +8,9 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
8
8
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
11
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
15
|
exports.StartedGenericContainer = void 0;
|
|
13
16
|
const inspect_container_1 = require("../docker/functions/container/inspect-container");
|
|
@@ -21,6 +24,7 @@ const stop_container_1 = require("../docker/functions/container/stop-container")
|
|
|
21
24
|
const restart_container_1 = require("../docker/functions/container/restart-container");
|
|
22
25
|
const wait_for_container_1 = require("../wait-for-container");
|
|
23
26
|
const docker_client_1 = require("../docker/docker-client");
|
|
27
|
+
const async_lock_1 = __importDefault(require("async-lock"));
|
|
24
28
|
class StartedGenericContainer {
|
|
25
29
|
constructor(container, host, inspectResult, boundPorts, name, waitStrategy) {
|
|
26
30
|
this.container = container;
|
|
@@ -29,38 +33,47 @@ class StartedGenericContainer {
|
|
|
29
33
|
this.boundPorts = boundPorts;
|
|
30
34
|
this.name = name;
|
|
31
35
|
this.waitStrategy = waitStrategy;
|
|
36
|
+
this.stopContainerLock = new async_lock_1.default();
|
|
32
37
|
}
|
|
33
38
|
stop(options = {}) {
|
|
34
39
|
return __awaiter(this, void 0, void 0, function* () {
|
|
35
|
-
return this.
|
|
40
|
+
return this.stopContainerLock.acquire("stop", () => __awaiter(this, void 0, void 0, function* () {
|
|
41
|
+
if (this.stoppedContainer) {
|
|
42
|
+
return this.stoppedContainer;
|
|
43
|
+
}
|
|
44
|
+
this.stoppedContainer = yield this.stopContainer(options);
|
|
45
|
+
return this.stoppedContainer;
|
|
46
|
+
}));
|
|
36
47
|
});
|
|
37
48
|
}
|
|
38
49
|
restart(options = {}) {
|
|
39
50
|
return __awaiter(this, void 0, void 0, function* () {
|
|
40
51
|
const resolvedOptions = Object.assign({ timeout: 0 }, options);
|
|
41
|
-
logger_1.log.info(`Restarting container
|
|
52
|
+
logger_1.log.info(`Restarting container...`, { containerId: this.container.id });
|
|
42
53
|
yield (0, restart_container_1.restartContainer)(this.container, resolvedOptions);
|
|
43
54
|
const { hostIps } = yield (0, docker_client_1.dockerClient)();
|
|
44
55
|
this.inspectResult = yield (0, inspect_container_1.inspectContainer)(this.container);
|
|
45
56
|
const startTime = this.inspectResult.state.startedAt;
|
|
46
57
|
if (logger_1.containerLog.enabled()) {
|
|
47
58
|
(yield (0, container_logs_1.containerLogs)(this.container, { since: startTime }))
|
|
48
|
-
.on("data", (data) => logger_1.containerLog.trace(
|
|
49
|
-
.on("err", (data) => logger_1.containerLog.error(
|
|
59
|
+
.on("data", (data) => logger_1.containerLog.trace(data.trim(), { containerId: this.container.id }))
|
|
60
|
+
.on("err", (data) => logger_1.containerLog.error(data.trim(), { containerId: this.container.id }));
|
|
50
61
|
}
|
|
51
62
|
this.boundPorts = bound_ports_1.BoundPorts.fromInspectResult(hostIps, this.inspectResult).filter(Array.from(this.boundPorts.iterator()).map((port) => port[0]));
|
|
52
|
-
yield (0, wait_for_container_1.waitForContainer)(this.container, this.waitStrategy, this.
|
|
63
|
+
yield (0, wait_for_container_1.waitForContainer)(this.container, this.waitStrategy, this.boundPorts, startTime);
|
|
64
|
+
logger_1.log.info(`Restarted container`, { containerId: this.container.id });
|
|
53
65
|
});
|
|
54
66
|
}
|
|
55
67
|
stopContainer(options = {}) {
|
|
56
68
|
return __awaiter(this, void 0, void 0, function* () {
|
|
57
|
-
logger_1.log.info(`Stopping container
|
|
69
|
+
logger_1.log.info(`Stopping container...`, { containerId: this.container.id });
|
|
58
70
|
if (this.containerIsStopping) {
|
|
59
71
|
yield this.containerIsStopping();
|
|
60
72
|
}
|
|
61
73
|
const resolvedOptions = Object.assign({ timeout: 0, removeVolumes: true }, options);
|
|
62
74
|
yield (0, stop_container_1.stopContainer)(this.container, { timeout: resolvedOptions.timeout });
|
|
63
75
|
yield (0, remove_container_1.removeContainer)(this.container, { removeVolumes: resolvedOptions.removeVolumes });
|
|
76
|
+
logger_1.log.info(`Stopped container`, { containerId: this.container.id });
|
|
64
77
|
if (this.containerIsStopped) {
|
|
65
78
|
yield this.containerIsStopped();
|
|
66
79
|
}
|
|
@@ -95,7 +108,13 @@ class StartedGenericContainer {
|
|
|
95
108
|
return this.inspectResult.networkSettings[networkName].ipAddress;
|
|
96
109
|
}
|
|
97
110
|
exec(command) {
|
|
98
|
-
return (0,
|
|
111
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
112
|
+
const { dockerode, provider } = yield (0, docker_client_1.dockerClient)();
|
|
113
|
+
logger_1.log.debug(`Executing command "${command.join(" ")}"...`, { containerId: this.container.id });
|
|
114
|
+
const output = yield (0, exec_container_1.execContainer)(dockerode, provider, this.container, command);
|
|
115
|
+
logger_1.log.debug(`Executed command "${command.join(" ")}"...`, { containerId: this.container.id });
|
|
116
|
+
return output;
|
|
117
|
+
});
|
|
99
118
|
}
|
|
100
119
|
logs() {
|
|
101
120
|
return (0, container_logs_1.containerLogs)(this.container);
|
package/dist/src/images.js
CHANGED
|
@@ -2,5 +2,5 @@
|
|
|
2
2
|
var _a, _b;
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
4
|
exports.SSHD_IMAGE = exports.REAPER_IMAGE = void 0;
|
|
5
|
-
exports.REAPER_IMAGE = (_a = process.env["RYUK_CONTAINER_IMAGE"]) !== null && _a !== void 0 ? _a : "testcontainers/ryuk:0.
|
|
5
|
+
exports.REAPER_IMAGE = (_a = process.env["RYUK_CONTAINER_IMAGE"]) !== null && _a !== void 0 ? _a : "testcontainers/ryuk:0.4.0";
|
|
6
6
|
exports.SSHD_IMAGE = (_b = process.env["SSHD_CONTAINER_IMAGE"]) !== null && _b !== void 0 ? _b : "testcontainers/sshd:1.1.0";
|
package/dist/src/logger.d.ts
CHANGED
|
@@ -1,36 +1,25 @@
|
|
|
1
1
|
type Message = string;
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
error(message: Message): void;
|
|
9
|
-
}
|
|
10
|
-
declare class DebugLogger implements Logger {
|
|
2
|
+
type Options = {
|
|
3
|
+
containerId?: string;
|
|
4
|
+
imageName?: string;
|
|
5
|
+
};
|
|
6
|
+
export declare class Logger {
|
|
7
|
+
private readonly showLevel;
|
|
11
8
|
private readonly logger;
|
|
12
|
-
constructor(namespace: string);
|
|
13
|
-
enabled(): boolean;
|
|
14
|
-
trace(message: Message): void;
|
|
15
|
-
debug(message: Message): void;
|
|
16
|
-
info(message: Message): void;
|
|
17
|
-
warn(message: Message): void;
|
|
18
|
-
error(message: Message): void;
|
|
19
|
-
}
|
|
20
|
-
export declare class FakeLogger implements Logger {
|
|
21
|
-
readonly traceLogs: Message[];
|
|
22
|
-
readonly debugLogs: Message[];
|
|
23
|
-
readonly infoLogs: Message[];
|
|
24
|
-
readonly warnLogs: Message[];
|
|
25
|
-
readonly errorLogs: Message[];
|
|
9
|
+
constructor(namespace: string, showLevel?: boolean);
|
|
26
10
|
enabled(): boolean;
|
|
27
|
-
trace(message: Message): void;
|
|
28
|
-
debug(message: Message): void;
|
|
29
|
-
info(message: Message): void;
|
|
30
|
-
warn(message: Message): void;
|
|
31
|
-
error(message: Message): void;
|
|
11
|
+
trace(message: Message, options?: Options): void;
|
|
12
|
+
debug(message: Message, options?: Options): void;
|
|
13
|
+
info(message: Message, options?: Options): void;
|
|
14
|
+
warn(message: Message, options?: Options): void;
|
|
15
|
+
error(message: Message, options?: Options): void;
|
|
16
|
+
private formatMessage;
|
|
17
|
+
private renderOptions;
|
|
32
18
|
}
|
|
33
|
-
export declare const log:
|
|
34
|
-
export declare const containerLog:
|
|
35
|
-
export declare const
|
|
19
|
+
export declare const log: Logger;
|
|
20
|
+
export declare const containerLog: Logger;
|
|
21
|
+
export declare const composeLog: Logger;
|
|
22
|
+
export declare const buildLog: Logger;
|
|
23
|
+
export declare const pullLog: Logger;
|
|
24
|
+
export declare const execLog: Logger;
|
|
36
25
|
export {};
|
package/dist/src/logger.js
CHANGED
|
@@ -3,59 +3,49 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.execLog = exports.containerLog = exports.log = exports.
|
|
6
|
+
exports.execLog = exports.pullLog = exports.buildLog = exports.composeLog = exports.containerLog = exports.log = exports.Logger = void 0;
|
|
7
7
|
const debug_1 = __importDefault(require("debug"));
|
|
8
|
-
class
|
|
9
|
-
constructor(namespace) {
|
|
8
|
+
class Logger {
|
|
9
|
+
constructor(namespace, showLevel = true) {
|
|
10
|
+
this.showLevel = showLevel;
|
|
10
11
|
this.logger = (0, debug_1.default)(namespace);
|
|
11
12
|
}
|
|
12
13
|
enabled() {
|
|
13
14
|
return this.logger.enabled;
|
|
14
15
|
}
|
|
15
|
-
trace(message) {
|
|
16
|
-
this.logger(
|
|
16
|
+
trace(message, options) {
|
|
17
|
+
this.logger(this.formatMessage(message, "TRACE", options));
|
|
17
18
|
}
|
|
18
|
-
debug(message) {
|
|
19
|
-
this.logger(
|
|
19
|
+
debug(message, options) {
|
|
20
|
+
this.logger(this.formatMessage(message, "DEBUG", options));
|
|
20
21
|
}
|
|
21
|
-
info(message) {
|
|
22
|
-
this.logger(
|
|
22
|
+
info(message, options) {
|
|
23
|
+
this.logger(this.formatMessage(message, "INFO", options));
|
|
23
24
|
}
|
|
24
|
-
warn(message) {
|
|
25
|
-
this.logger(
|
|
25
|
+
warn(message, options) {
|
|
26
|
+
this.logger(this.formatMessage(message, "WARN", options));
|
|
26
27
|
}
|
|
27
|
-
error(message) {
|
|
28
|
-
this.logger(
|
|
28
|
+
error(message, options) {
|
|
29
|
+
this.logger(this.formatMessage(message, "ERROR", options));
|
|
29
30
|
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
constructor() {
|
|
33
|
-
this.traceLogs = [];
|
|
34
|
-
this.debugLogs = [];
|
|
35
|
-
this.infoLogs = [];
|
|
36
|
-
this.warnLogs = [];
|
|
37
|
-
this.errorLogs = [];
|
|
38
|
-
}
|
|
39
|
-
enabled() {
|
|
40
|
-
return true;
|
|
41
|
-
}
|
|
42
|
-
trace(message) {
|
|
43
|
-
this.traceLogs.push(message);
|
|
44
|
-
}
|
|
45
|
-
debug(message) {
|
|
46
|
-
this.debugLogs.push(message);
|
|
47
|
-
}
|
|
48
|
-
info(message) {
|
|
49
|
-
this.infoLogs.push(message);
|
|
50
|
-
}
|
|
51
|
-
warn(message) {
|
|
52
|
-
this.warnLogs.push(message);
|
|
31
|
+
formatMessage(message, level, options) {
|
|
32
|
+
return `${this.showLevel ? `[${level}] ` : ""}${this.renderOptions(options)}${message}`;
|
|
53
33
|
}
|
|
54
|
-
|
|
55
|
-
|
|
34
|
+
renderOptions(options) {
|
|
35
|
+
let str = "";
|
|
36
|
+
if (options === null || options === void 0 ? void 0 : options.containerId) {
|
|
37
|
+
str += `[${options.containerId.substring(0, 12)}] `;
|
|
38
|
+
}
|
|
39
|
+
if (options === null || options === void 0 ? void 0 : options.imageName) {
|
|
40
|
+
str += `[${options.imageName}] `;
|
|
41
|
+
}
|
|
42
|
+
return str;
|
|
56
43
|
}
|
|
57
44
|
}
|
|
58
|
-
exports.
|
|
59
|
-
exports.log = new
|
|
60
|
-
exports.containerLog = new
|
|
61
|
-
exports.
|
|
45
|
+
exports.Logger = Logger;
|
|
46
|
+
exports.log = new Logger("testcontainers");
|
|
47
|
+
exports.containerLog = new Logger("testcontainers:containers", false);
|
|
48
|
+
exports.composeLog = new Logger("testcontainers:compose", false);
|
|
49
|
+
exports.buildLog = new Logger("testcontainers:build", false);
|
|
50
|
+
exports.pullLog = new Logger("testcontainers:pull", false);
|
|
51
|
+
exports.execLog = new Logger("testcontainers:exec", false);
|