testcontainers 9.6.0 → 9.8.0-beta.1
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 +12 -12
- package/dist/src/docker/{docker-client-config.d.ts → client/docker-client-config.d.ts} +1 -0
- package/dist/src/docker/client/docker-client-config.js +79 -0
- package/dist/src/docker/client/docker-client.d.ts +18 -0
- package/dist/src/docker/client/docker-client.js +90 -0
- package/dist/src/docker/client/strategy/configuration-strategy.d.ts +11 -0
- package/dist/src/docker/client/strategy/configuration-strategy.js +68 -0
- package/dist/src/docker/client/strategy/docker-client-strategy.d.ts +7 -0
- package/dist/src/docker/client/strategy/docker-client-strategy.js +2 -0
- package/dist/src/docker/client/strategy/npipe-socket-strategy.d.ts +7 -0
- package/dist/src/docker/client/strategy/npipe-socket-strategy.js +35 -0
- package/dist/src/docker/{rootless-unix-socket-strategy.d.ts → client/strategy/rootless-unix-socket-strategy.d.ts} +3 -2
- package/dist/src/docker/{rootless-unix-socket-strategy.js → client/strategy/rootless-unix-socket-strategy.js} +2 -1
- package/dist/src/docker/client/strategy/testcontainers-host-strategy.d.ts +9 -0
- package/dist/src/docker/client/strategy/testcontainers-host-strategy.js +52 -0
- package/dist/src/docker/client/strategy/unix-socket-strategy.d.ts +7 -0
- package/dist/src/docker/client/strategy/unix-socket-strategy.js +36 -0
- package/dist/src/docker/functions/container/attach-container.js +1 -1
- package/dist/src/docker/functions/container/container-logs.js +2 -2
- package/dist/src/docker/functions/container/create-container.js +8 -6
- package/dist/src/docker/functions/container/exec-container.d.ts +2 -3
- package/dist/src/docker/functions/container/exec-container.js +9 -7
- package/dist/src/docker/functions/container/get-container.js +4 -4
- package/dist/src/docker/functions/container/inspect-container.js +1 -1
- package/dist/src/docker/functions/container/list-containers.js +2 -2
- package/dist/src/docker/functions/container/put-container-archive.js +1 -1
- 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 +10 -5
- package/dist/src/docker/functions/image/pull-image.js +11 -4
- package/dist/src/docker/functions/network/connect-network.js +5 -4
- package/dist/src/docker/functions/network/create-network.js +4 -3
- package/dist/src/docker/functions/network/remove-network.js +5 -4
- package/dist/src/docker/functions/run-in-container.js +6 -6
- package/dist/src/docker/remote-docker-unix-socket-path.d.ts +6 -0
- package/dist/src/docker/remote-docker-unix-socket-path.js +22 -0
- package/dist/src/docker/resolve-host.d.ts +2 -2
- package/dist/src/docker/resolve-host.js +8 -6
- package/dist/src/docker/types.d.ts +1 -0
- package/dist/src/docker-compose/default-docker-compose-options.js +6 -4
- 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.js +5 -8
- package/dist/src/generic-container/generic-container-builder.js +4 -4
- package/dist/src/generic-container/generic-container.d.ts +4 -0
- package/dist/src/generic-container/generic-container.js +23 -12
- package/dist/src/generic-container/started-generic-container.js +13 -8
- 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/nats/nats-container.js +1 -1
- package/dist/src/network.js +6 -3
- package/dist/src/port-check.d.ts +3 -3
- package/dist/src/port-check.js +9 -5
- package/dist/src/port-forwarder.js +7 -5
- package/dist/src/reaper.js +16 -10
- 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 +1 -0
- package/dist/src/uuid.js +1 -1
- package/dist/src/wait-for-container.js +4 -4
- package/dist/src/wait-strategy/composite-wait-strategy.js +4 -4
- package/dist/src/wait-strategy/health-check-wait-strategy.js +8 -5
- package/dist/src/wait-strategy/host-port-wait-strategy.js +11 -11
- package/dist/src/wait-strategy/http-wait-strategy.js +9 -7
- package/dist/src/wait-strategy/log-wait-strategy.js +7 -7
- package/dist/src/wait-strategy/shell-wait-strategy.js +8 -8
- package/dist/src/wait-strategy/startup-check-strategy.js +8 -5
- package/dist/src/wait-strategy/wait-strategy.d.ts +6 -4
- package/dist/src/wait-strategy/wait-strategy.js +9 -2
- package/package.json +12 -12
- package/dist/src/docker/docker-client-config.js +0 -66
- package/dist/src/docker/docker-client.d.ts +0 -26
- package/dist/src/docker/docker-client.js +0 -156
- package/dist/src/docker/get-remote-docker-unix-socket-path.d.ts +0 -5
- package/dist/src/docker/get-remote-docker-unix-socket-path.js +0 -17
- package/dist/src/docker/pull-stream-parser.d.ts +0 -10
- package/dist/src/docker/pull-stream-parser.js +0 -20
package/dist/src/uuid.js
CHANGED
|
@@ -7,7 +7,7 @@ exports.RandomUuid = void 0;
|
|
|
7
7
|
const crypto_1 = __importDefault(require("crypto"));
|
|
8
8
|
class RandomUuid {
|
|
9
9
|
nextUuid() {
|
|
10
|
-
return crypto_1.default.randomUUID();
|
|
10
|
+
return crypto_1.default.createHash("md5").update(crypto_1.default.randomUUID()).digest("hex").substring(0, 12);
|
|
11
11
|
}
|
|
12
12
|
}
|
|
13
13
|
exports.RandomUuid = RandomUuid;
|
|
@@ -14,19 +14,19 @@ const logger_1 = require("./logger");
|
|
|
14
14
|
const stop_container_1 = require("./docker/functions/container/stop-container");
|
|
15
15
|
const remove_container_1 = require("./docker/functions/container/remove-container");
|
|
16
16
|
const waitForContainer = (container, waitStrategy, boundPorts, startTime) => __awaiter(void 0, void 0, void 0, function* () {
|
|
17
|
-
logger_1.log.debug(`Waiting for container to be ready:
|
|
17
|
+
logger_1.log.debug(`Waiting for container to be ready...`, { containerId: container.id });
|
|
18
18
|
try {
|
|
19
19
|
yield waitStrategy.waitUntilReady(container, boundPorts, startTime);
|
|
20
|
-
logger_1.log.info(`Container is ready:
|
|
20
|
+
logger_1.log.info(`Container is ready`, { containerId: container.id });
|
|
21
21
|
}
|
|
22
22
|
catch (err) {
|
|
23
|
-
logger_1.log.error(`Container failed to be ready: ${container.id
|
|
23
|
+
logger_1.log.error(`Container failed to be ready: ${err}`, { containerId: container.id });
|
|
24
24
|
try {
|
|
25
25
|
yield (0, stop_container_1.stopContainer)(container, { timeout: 0 });
|
|
26
26
|
yield (0, remove_container_1.removeContainer)(container, { removeVolumes: true });
|
|
27
27
|
}
|
|
28
28
|
catch (stopErr) {
|
|
29
|
-
logger_1.log.error(`Failed to stop container after it failed to be ready: ${container.id
|
|
29
|
+
logger_1.log.error(`Failed to stop container after it failed to be ready: ${stopErr}`, { containerId: container.id });
|
|
30
30
|
}
|
|
31
31
|
throw err;
|
|
32
32
|
}
|
|
@@ -19,13 +19,13 @@ class CompositeWaitStrategy extends wait_strategy_1.AbstractWaitStrategy {
|
|
|
19
19
|
}
|
|
20
20
|
waitUntilReady(container, boundPorts, startTime) {
|
|
21
21
|
return __awaiter(this, void 0, void 0, function* () {
|
|
22
|
-
logger_1.log.debug(`
|
|
22
|
+
logger_1.log.debug(`Waiting for composite...`, { containerId: container.id });
|
|
23
23
|
return new Promise((resolve, reject) => {
|
|
24
24
|
let deadlineTimeout;
|
|
25
25
|
if (this.deadline !== undefined) {
|
|
26
26
|
deadlineTimeout = setTimeout(() => {
|
|
27
|
-
const message = `Composite wait strategy not successful after ${this.deadline}ms
|
|
28
|
-
logger_1.log.error(message);
|
|
27
|
+
const message = `Composite wait strategy not successful after ${this.deadline}ms`;
|
|
28
|
+
logger_1.log.error(message, { containerId: container.id });
|
|
29
29
|
reject(new Error(message));
|
|
30
30
|
}, this.deadline);
|
|
31
31
|
}
|
|
@@ -42,7 +42,7 @@ class CompositeWaitStrategy extends wait_strategy_1.AbstractWaitStrategy {
|
|
|
42
42
|
}
|
|
43
43
|
withStartupTimeout(startupTimeout) {
|
|
44
44
|
this.waitStrategies
|
|
45
|
-
.filter((waitStrategy) => waitStrategy.
|
|
45
|
+
.filter((waitStrategy) => !waitStrategy.isStartupTimeoutSet())
|
|
46
46
|
.forEach((waitStrategy) => waitStrategy.withStartupTimeout(startupTimeout));
|
|
47
47
|
return this;
|
|
48
48
|
}
|
|
@@ -16,15 +16,18 @@ const inspect_container_1 = require("../docker/functions/container/inspect-conta
|
|
|
16
16
|
const wait_strategy_1 = require("./wait-strategy");
|
|
17
17
|
class HealthCheckWaitStrategy extends wait_strategy_1.AbstractWaitStrategy {
|
|
18
18
|
waitUntilReady(container) {
|
|
19
|
-
var _a;
|
|
20
19
|
return __awaiter(this, void 0, void 0, function* () {
|
|
21
|
-
logger_1.log.debug(`Waiting for health check
|
|
20
|
+
logger_1.log.debug(`Waiting for health check...`, { containerId: container.id });
|
|
22
21
|
const status = yield new retry_strategy_1.IntervalRetryStrategy(100).retryUntil(() => __awaiter(this, void 0, void 0, function* () { return (yield (0, inspect_container_1.inspectContainer)(container)).healthCheckStatus; }), (healthCheckStatus) => healthCheckStatus === "healthy" || healthCheckStatus === "unhealthy", () => {
|
|
23
22
|
const timeout = this.startupTimeout;
|
|
24
|
-
|
|
25
|
-
|
|
23
|
+
const message = `Health check not healthy after ${timeout}ms`;
|
|
24
|
+
logger_1.log.error(message, { containerId: container.id });
|
|
25
|
+
throw new Error(message);
|
|
26
|
+
}, this.startupTimeout);
|
|
26
27
|
if (status !== "healthy") {
|
|
27
|
-
|
|
28
|
+
const message = `Health check failed: ${status}`;
|
|
29
|
+
logger_1.log.error(message, { containerId: container.id });
|
|
30
|
+
throw new Error(message);
|
|
28
31
|
}
|
|
29
32
|
});
|
|
30
33
|
}
|
|
@@ -14,13 +14,13 @@ const port_check_1 = require("../port-check");
|
|
|
14
14
|
const logger_1 = require("../logger");
|
|
15
15
|
const retry_strategy_1 = require("../retry-strategy");
|
|
16
16
|
const wait_strategy_1 = require("./wait-strategy");
|
|
17
|
-
const docker_client_1 = require("../docker/docker-client");
|
|
17
|
+
const docker_client_1 = require("../docker/client/docker-client");
|
|
18
18
|
class HostPortWaitStrategy extends wait_strategy_1.AbstractWaitStrategy {
|
|
19
19
|
waitUntilReady(container, boundPorts) {
|
|
20
20
|
return __awaiter(this, void 0, void 0, function* () {
|
|
21
|
-
const { dockerode,
|
|
21
|
+
const { dockerode, containerRuntime, host } = yield (0, docker_client_1.getDockerClient)();
|
|
22
22
|
const hostPortCheck = new port_check_1.HostPortCheck(host);
|
|
23
|
-
const internalPortCheck = new port_check_1.InternalPortCheck(dockerode,
|
|
23
|
+
const internalPortCheck = new port_check_1.InternalPortCheck(dockerode, containerRuntime, container);
|
|
24
24
|
yield Promise.all([
|
|
25
25
|
this.waitForHostPorts(hostPortCheck, container, boundPorts),
|
|
26
26
|
this.waitForInternalPorts(internalPortCheck, container, boundPorts),
|
|
@@ -30,28 +30,28 @@ class HostPortWaitStrategy extends wait_strategy_1.AbstractWaitStrategy {
|
|
|
30
30
|
waitForHostPorts(portCheck, container, boundPorts) {
|
|
31
31
|
return __awaiter(this, void 0, void 0, function* () {
|
|
32
32
|
for (const [, hostPort] of boundPorts.iterator()) {
|
|
33
|
-
logger_1.log.debug(`Waiting for host port ${hostPort}
|
|
33
|
+
logger_1.log.debug(`Waiting for host port ${hostPort}...`, { containerId: container.id });
|
|
34
34
|
yield this.waitForPort(container, hostPort, portCheck);
|
|
35
|
-
logger_1.log.debug(`Host port ${hostPort} ready
|
|
35
|
+
logger_1.log.debug(`Host port ${hostPort} ready`, { containerId: container.id });
|
|
36
36
|
}
|
|
37
37
|
});
|
|
38
38
|
}
|
|
39
39
|
waitForInternalPorts(portCheck, container, boundPorts) {
|
|
40
40
|
return __awaiter(this, void 0, void 0, function* () {
|
|
41
41
|
for (const [internalPort] of boundPorts.iterator()) {
|
|
42
|
-
logger_1.log.debug(`Waiting for internal port ${internalPort}
|
|
42
|
+
logger_1.log.debug(`Waiting for internal port ${internalPort}...`, { containerId: container.id });
|
|
43
43
|
yield this.waitForPort(container, internalPort, portCheck);
|
|
44
|
-
logger_1.log.debug(`Internal port ${internalPort} ready
|
|
44
|
+
logger_1.log.debug(`Internal port ${internalPort} ready`, { containerId: container.id });
|
|
45
45
|
}
|
|
46
46
|
});
|
|
47
47
|
}
|
|
48
48
|
waitForPort(container, port, portCheck) {
|
|
49
|
-
var _a;
|
|
50
49
|
return __awaiter(this, void 0, void 0, function* () {
|
|
51
|
-
const startupTimeout = (_a = this.startupTimeout) !== null && _a !== void 0 ? _a : wait_strategy_1.DEFAULT_STARTUP_TIMEOUT;
|
|
52
50
|
yield new retry_strategy_1.IntervalRetryStrategy(100).retryUntil(() => portCheck.isBound(port), (isBound) => isBound, () => {
|
|
53
|
-
|
|
54
|
-
|
|
51
|
+
const message = `Port ${port} not bound after ${this.startupTimeout}ms`;
|
|
52
|
+
logger_1.log.error(message, { containerId: container.id });
|
|
53
|
+
throw new Error(message);
|
|
54
|
+
}, this.startupTimeout);
|
|
55
55
|
});
|
|
56
56
|
}
|
|
57
57
|
}
|
|
@@ -17,7 +17,8 @@ const wait_strategy_1 = require("./wait-strategy");
|
|
|
17
17
|
const retry_strategy_1 = require("../retry-strategy");
|
|
18
18
|
const node_fetch_1 = __importDefault(require("node-fetch"));
|
|
19
19
|
const https_1 = __importDefault(require("https"));
|
|
20
|
-
const docker_client_1 = require("../docker/docker-client");
|
|
20
|
+
const docker_client_1 = require("../docker/client/docker-client");
|
|
21
|
+
const logger_1 = require("../logger");
|
|
21
22
|
class HttpWaitStrategy extends wait_strategy_1.AbstractWaitStrategy {
|
|
22
23
|
constructor(path, port) {
|
|
23
24
|
super();
|
|
@@ -68,10 +69,9 @@ class HttpWaitStrategy extends wait_strategy_1.AbstractWaitStrategy {
|
|
|
68
69
|
return this;
|
|
69
70
|
}
|
|
70
71
|
waitUntilReady(container, boundPorts) {
|
|
71
|
-
var _a;
|
|
72
72
|
return __awaiter(this, void 0, void 0, function* () {
|
|
73
|
-
|
|
74
|
-
const
|
|
73
|
+
logger_1.log.debug(`Waiting for HTTP...`, { containerId: container.id });
|
|
74
|
+
const { host } = yield (0, docker_client_1.getDockerClient)();
|
|
75
75
|
yield new retry_strategy_1.IntervalRetryStrategy(this.readTimeout).retryUntil(() => __awaiter(this, void 0, void 0, function* () {
|
|
76
76
|
try {
|
|
77
77
|
const url = `${this.protocol}://${host}:${boundPorts.getBinding(this.port)}${this.path}`;
|
|
@@ -82,7 +82,7 @@ class HttpWaitStrategy extends wait_strategy_1.AbstractWaitStrategy {
|
|
|
82
82
|
agent: this.getAgent(),
|
|
83
83
|
});
|
|
84
84
|
}
|
|
85
|
-
catch (
|
|
85
|
+
catch (_a) {
|
|
86
86
|
return undefined;
|
|
87
87
|
}
|
|
88
88
|
}), (response) => __awaiter(this, void 0, void 0, function* () {
|
|
@@ -102,8 +102,10 @@ class HttpWaitStrategy extends wait_strategy_1.AbstractWaitStrategy {
|
|
|
102
102
|
return true;
|
|
103
103
|
}
|
|
104
104
|
}), () => {
|
|
105
|
-
|
|
106
|
-
|
|
105
|
+
const message = `URL ${this.path} not accessible after ${this.startupTimeout}ms`;
|
|
106
|
+
logger_1.log.error(message, { containerId: container.id });
|
|
107
|
+
throw new Error(message);
|
|
108
|
+
}, this.startupTimeout);
|
|
107
109
|
});
|
|
108
110
|
}
|
|
109
111
|
getAgent() {
|
|
@@ -24,17 +24,15 @@ class LogWaitStrategy extends wait_strategy_1.AbstractWaitStrategy {
|
|
|
24
24
|
this.times = times;
|
|
25
25
|
}
|
|
26
26
|
waitUntilReady(container, boundPorts, startTime) {
|
|
27
|
-
var _a;
|
|
28
27
|
return __awaiter(this, void 0, void 0, function* () {
|
|
29
|
-
logger_1.log.debug(`Waiting for log message "${this.message}"
|
|
30
|
-
const startupTimeout = (_a = this.startupTimeout) !== null && _a !== void 0 ? _a : wait_strategy_1.DEFAULT_STARTUP_TIMEOUT;
|
|
28
|
+
logger_1.log.debug(`Waiting for log message "${this.message}"...`, { containerId: container.id });
|
|
31
29
|
const stream = yield (0, container_logs_1.containerLogs)(container, { since: startTime });
|
|
32
30
|
return new Promise((resolve, reject) => {
|
|
33
31
|
const timeout = setTimeout(() => {
|
|
34
|
-
const message = `Log message "${this.message}" not received after ${startupTimeout}ms
|
|
35
|
-
logger_1.log.error(message);
|
|
32
|
+
const message = `Log message "${this.message}" not received after ${this.startupTimeout}ms`;
|
|
33
|
+
logger_1.log.error(message, { containerId: container.id });
|
|
36
34
|
reject(new Error(message));
|
|
37
|
-
}, startupTimeout);
|
|
35
|
+
}, this.startupTimeout);
|
|
38
36
|
const comparisonFn = (line) => {
|
|
39
37
|
if (this.message instanceof RegExp) {
|
|
40
38
|
return this.message.test(line);
|
|
@@ -59,7 +57,9 @@ class LogWaitStrategy extends wait_strategy_1.AbstractWaitStrategy {
|
|
|
59
57
|
.on("end", () => {
|
|
60
58
|
stream.destroy();
|
|
61
59
|
clearTimeout(timeout);
|
|
62
|
-
|
|
60
|
+
const message = `Log stream ended and message "${this.message}" was not received`;
|
|
61
|
+
logger_1.log.error(message, { containerId: container.id });
|
|
62
|
+
reject(new Error(message));
|
|
63
63
|
});
|
|
64
64
|
});
|
|
65
65
|
});
|
|
@@ -14,24 +14,24 @@ const logger_1 = require("../logger");
|
|
|
14
14
|
const wait_strategy_1 = require("./wait-strategy");
|
|
15
15
|
const retry_strategy_1 = require("../retry-strategy");
|
|
16
16
|
const exec_container_1 = require("../docker/functions/container/exec-container");
|
|
17
|
-
const docker_client_1 = require("../docker/docker-client");
|
|
17
|
+
const docker_client_1 = require("../docker/client/docker-client");
|
|
18
18
|
class ShellWaitStrategy extends wait_strategy_1.AbstractWaitStrategy {
|
|
19
19
|
constructor(command) {
|
|
20
20
|
super();
|
|
21
21
|
this.command = command;
|
|
22
22
|
}
|
|
23
23
|
waitUntilReady(container) {
|
|
24
|
-
var _a;
|
|
25
24
|
return __awaiter(this, void 0, void 0, function* () {
|
|
26
|
-
logger_1.log.debug(`Waiting for successful shell command ${this.command}
|
|
27
|
-
const { dockerode,
|
|
28
|
-
const startupTimeout = (_a = this.startupTimeout) !== null && _a !== void 0 ? _a : wait_strategy_1.DEFAULT_STARTUP_TIMEOUT;
|
|
25
|
+
logger_1.log.debug(`Waiting for successful shell command "${this.command}"...`, { containerId: container.id });
|
|
26
|
+
const { dockerode, containerRuntime } = yield (0, docker_client_1.getDockerClient)();
|
|
29
27
|
yield new retry_strategy_1.IntervalRetryStrategy(100).retryUntil(() => __awaiter(this, void 0, void 0, function* () {
|
|
30
|
-
const { exitCode } = yield (0, exec_container_1.execContainer)(dockerode,
|
|
28
|
+
const { exitCode } = yield (0, exec_container_1.execContainer)(dockerode, containerRuntime, container, ["/bin/sh", "-c", this.command], false);
|
|
31
29
|
return exitCode;
|
|
32
30
|
}), (exitCode) => exitCode === 0, () => {
|
|
33
|
-
|
|
34
|
-
|
|
31
|
+
const message = `Shell command "${this.command}" not successful after ${this.startupTimeout}ms`;
|
|
32
|
+
logger_1.log.error(message, { containerId: container.id });
|
|
33
|
+
throw new Error(message);
|
|
34
|
+
}, this.startupTimeout);
|
|
35
35
|
});
|
|
36
36
|
}
|
|
37
37
|
}
|
|
@@ -12,14 +12,17 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
12
12
|
exports.StartupCheckStrategy = void 0;
|
|
13
13
|
const wait_strategy_1 = require("./wait-strategy");
|
|
14
14
|
const retry_strategy_1 = require("../retry-strategy");
|
|
15
|
-
const docker_client_1 = require("../docker/docker-client");
|
|
15
|
+
const docker_client_1 = require("../docker/client/docker-client");
|
|
16
|
+
const logger_1 = require("../logger");
|
|
16
17
|
class StartupCheckStrategy extends wait_strategy_1.AbstractWaitStrategy {
|
|
17
18
|
waitUntilReady(container) {
|
|
18
|
-
var _a;
|
|
19
19
|
return __awaiter(this, void 0, void 0, function* () {
|
|
20
|
-
const { dockerode } = yield (0, docker_client_1.
|
|
21
|
-
const
|
|
22
|
-
|
|
20
|
+
const { dockerode } = yield (0, docker_client_1.getDockerClient)();
|
|
21
|
+
const startupStatus = yield new retry_strategy_1.IntervalRetryStrategy(1000).retryUntil(() => __awaiter(this, void 0, void 0, function* () { return yield this.checkStartupState(dockerode, container.id); }), (startupStatus) => startupStatus === "SUCCESS" || startupStatus === "FAIL", () => {
|
|
22
|
+
const message = `Container not accessible after ${this.startupTimeout}ms`;
|
|
23
|
+
logger_1.log.error(message, { containerId: container.id });
|
|
24
|
+
return new Error(message);
|
|
25
|
+
}, this.startupTimeout);
|
|
23
26
|
if (startupStatus instanceof Error) {
|
|
24
27
|
throw startupStatus;
|
|
25
28
|
}
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import { BoundPorts } from "../bound-ports";
|
|
2
2
|
import Dockerode from "dockerode";
|
|
3
|
-
export declare const DEFAULT_STARTUP_TIMEOUT = 60000;
|
|
4
3
|
export interface WaitStrategy {
|
|
5
4
|
waitUntilReady(container: Dockerode.Container, boundPorts: BoundPorts, startTime?: Date): Promise<void>;
|
|
6
5
|
withStartupTimeout(startupTimeout: number): WaitStrategy;
|
|
7
|
-
|
|
6
|
+
isStartupTimeoutSet(): boolean;
|
|
7
|
+
getStartupTimeout(): number;
|
|
8
8
|
}
|
|
9
9
|
export declare abstract class AbstractWaitStrategy implements WaitStrategy {
|
|
10
|
-
protected startupTimeout
|
|
10
|
+
protected startupTimeout: number;
|
|
11
|
+
private startupTimeoutSet;
|
|
11
12
|
abstract waitUntilReady(container: Dockerode.Container, boundPorts: BoundPorts, startTime?: Date): Promise<void>;
|
|
12
13
|
withStartupTimeout(startupTimeout: number): this;
|
|
13
|
-
|
|
14
|
+
isStartupTimeoutSet(): boolean;
|
|
15
|
+
getStartupTimeout(): number;
|
|
14
16
|
}
|
|
@@ -1,12 +1,19 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.AbstractWaitStrategy =
|
|
4
|
-
exports.DEFAULT_STARTUP_TIMEOUT = 60000;
|
|
3
|
+
exports.AbstractWaitStrategy = void 0;
|
|
5
4
|
class AbstractWaitStrategy {
|
|
5
|
+
constructor() {
|
|
6
|
+
this.startupTimeout = 60000;
|
|
7
|
+
this.startupTimeoutSet = false;
|
|
8
|
+
}
|
|
6
9
|
withStartupTimeout(startupTimeout) {
|
|
7
10
|
this.startupTimeout = startupTimeout;
|
|
11
|
+
this.startupTimeoutSet = true;
|
|
8
12
|
return this;
|
|
9
13
|
}
|
|
14
|
+
isStartupTimeoutSet() {
|
|
15
|
+
return this.startupTimeoutSet;
|
|
16
|
+
}
|
|
10
17
|
getStartupTimeout() {
|
|
11
18
|
return this.startupTimeout;
|
|
12
19
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "testcontainers",
|
|
3
3
|
"author": "Cristian Greco",
|
|
4
|
-
"version": "9.
|
|
4
|
+
"version": "9.8.0-beta.1",
|
|
5
5
|
"main": "dist/src/index",
|
|
6
6
|
"types": "dist/src/index",
|
|
7
7
|
"keywords": [
|
|
@@ -56,31 +56,31 @@
|
|
|
56
56
|
"@types/async-lock": "^1.4.0",
|
|
57
57
|
"@types/byline": "^4.2.33",
|
|
58
58
|
"@types/debug": "4.1.7",
|
|
59
|
-
"@types/jest": "^29.5.
|
|
60
|
-
"@types/node": "^18.
|
|
59
|
+
"@types/jest": "^29.5.1",
|
|
60
|
+
"@types/node": "^18.16.2",
|
|
61
61
|
"@types/node-fetch": "^2.6.3",
|
|
62
62
|
"@types/pg": "^8.6.6",
|
|
63
63
|
"@types/properties-reader": "^2.1.1",
|
|
64
64
|
"@types/tar-fs": "^2.0.1",
|
|
65
|
-
"@typescript-eslint/eslint-plugin": "^5.
|
|
66
|
-
"@typescript-eslint/parser": "^5.
|
|
67
|
-
"arangojs": "^8.2.
|
|
65
|
+
"@typescript-eslint/eslint-plugin": "^5.59.1",
|
|
66
|
+
"@typescript-eslint/parser": "^5.59.1",
|
|
67
|
+
"arangojs": "^8.2.1",
|
|
68
68
|
"cross-env": "^7.0.3",
|
|
69
|
-
"eslint": "^8.
|
|
69
|
+
"eslint": "^8.39.0",
|
|
70
70
|
"eslint-config-prettier": "^8.8.0",
|
|
71
71
|
"eslint-plugin-prettier": "^4.2.1",
|
|
72
72
|
"husky": "^8.0.3",
|
|
73
73
|
"jest": "^29.5.0",
|
|
74
74
|
"kafkajs": "^2.2.4",
|
|
75
|
-
"lint-staged": "^13.2.
|
|
76
|
-
"mongoose": "^6.10.
|
|
75
|
+
"lint-staged": "^13.2.2",
|
|
76
|
+
"mongoose": "^6.10.5",
|
|
77
77
|
"mysql2": "^2.3.3",
|
|
78
78
|
"nats": "^2.13.1",
|
|
79
|
-
"neo4j-driver": "^5.
|
|
79
|
+
"neo4j-driver": "^5.7.0",
|
|
80
80
|
"pg": "^8.10.0",
|
|
81
|
-
"prettier": "^2.8.
|
|
81
|
+
"prettier": "^2.8.8",
|
|
82
82
|
"rimraf": "^3.0.2",
|
|
83
|
-
"ts-jest": "^29.0
|
|
83
|
+
"ts-jest": "^29.1.0",
|
|
84
84
|
"ts-node": "^10.9.1",
|
|
85
85
|
"typescript": "^4.9.5",
|
|
86
86
|
"wait-for-expect": "^3.0.2"
|
|
@@ -1,66 +0,0 @@
|
|
|
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
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
-
};
|
|
14
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
-
exports.getDockerClientConfig = void 0;
|
|
16
|
-
const path_1 = __importDefault(require("path"));
|
|
17
|
-
const logger_1 = require("../logger");
|
|
18
|
-
const os_1 = require("os");
|
|
19
|
-
const fs_1 = require("fs");
|
|
20
|
-
const promises_1 = require("fs/promises");
|
|
21
|
-
const properties_reader_1 = __importDefault(require("properties-reader"));
|
|
22
|
-
const getDockerClientConfig = (env = process.env) => __awaiter(void 0, void 0, void 0, function* () {
|
|
23
|
-
let dockerHost;
|
|
24
|
-
let dockerTlsVerify;
|
|
25
|
-
let dockerCertPath;
|
|
26
|
-
const file = path_1.default.resolve((0, os_1.homedir)(), ".testcontainers.properties");
|
|
27
|
-
if ((0, fs_1.existsSync)(file)) {
|
|
28
|
-
logger_1.log.debug("Found .testcontainers.properties file");
|
|
29
|
-
const string = yield (0, promises_1.readFile)(file, { encoding: "utf-8" });
|
|
30
|
-
const properties = (0, properties_reader_1.default)("").read(string);
|
|
31
|
-
const host = properties.get("docker.host");
|
|
32
|
-
if (host !== null) {
|
|
33
|
-
dockerHost = host;
|
|
34
|
-
}
|
|
35
|
-
const tlsVerify = properties.get("docker.tls.verify");
|
|
36
|
-
if (tlsVerify !== null) {
|
|
37
|
-
dockerTlsVerify = `${tlsVerify}`;
|
|
38
|
-
}
|
|
39
|
-
const certPath = properties.get("docker.cert.path");
|
|
40
|
-
if (certPath !== null) {
|
|
41
|
-
dockerCertPath = certPath;
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
if (env["DOCKER_HOST"] !== undefined) {
|
|
45
|
-
dockerHost = env["DOCKER_HOST"];
|
|
46
|
-
}
|
|
47
|
-
if (env["DOCKER_TLS_VERIFY"] !== undefined) {
|
|
48
|
-
dockerTlsVerify = env["DOCKER_TLS_VERIFY"];
|
|
49
|
-
}
|
|
50
|
-
if (env["DOCKER_CERT_PATH"] !== undefined) {
|
|
51
|
-
dockerCertPath = env["DOCKER_CERT_PATH"];
|
|
52
|
-
}
|
|
53
|
-
let logStr = "Loaded properties: ";
|
|
54
|
-
if (dockerHost !== undefined) {
|
|
55
|
-
logStr += `dockerHost=${dockerHost}, `;
|
|
56
|
-
}
|
|
57
|
-
if (dockerTlsVerify !== undefined) {
|
|
58
|
-
logStr += `dockerTlsVerify=${dockerTlsVerify}, `;
|
|
59
|
-
}
|
|
60
|
-
if (dockerCertPath !== undefined) {
|
|
61
|
-
logStr += `dockerCertPath=${dockerCertPath}`;
|
|
62
|
-
}
|
|
63
|
-
logger_1.log.debug(logStr);
|
|
64
|
-
return { dockerHost, dockerTlsVerify, dockerCertPath };
|
|
65
|
-
});
|
|
66
|
-
exports.getDockerClientConfig = getDockerClientConfig;
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
/// <reference types="node" />
|
|
2
|
-
import Dockerode from "dockerode";
|
|
3
|
-
import { HostIps } from "./lookup-host-ips";
|
|
4
|
-
export type Provider = "docker" | "podman";
|
|
5
|
-
type DockerClient = {
|
|
6
|
-
uri: string;
|
|
7
|
-
provider: Provider;
|
|
8
|
-
host: string;
|
|
9
|
-
hostIps: HostIps;
|
|
10
|
-
dockerode: Dockerode;
|
|
11
|
-
indexServerAddress: string;
|
|
12
|
-
composeEnvironment: NodeJS.ProcessEnv;
|
|
13
|
-
};
|
|
14
|
-
export type DockerClientInit = {
|
|
15
|
-
uri: string;
|
|
16
|
-
dockerode: Dockerode;
|
|
17
|
-
composeEnvironment: NodeJS.ProcessEnv;
|
|
18
|
-
};
|
|
19
|
-
export interface DockerClientStrategy {
|
|
20
|
-
init?(): Promise<void>;
|
|
21
|
-
isApplicable(): boolean;
|
|
22
|
-
getDockerClient(): Promise<DockerClientInit>;
|
|
23
|
-
getName(): string;
|
|
24
|
-
}
|
|
25
|
-
export declare const dockerClient: () => Promise<DockerClient>;
|
|
26
|
-
export {};
|
|
@@ -1,156 +0,0 @@
|
|
|
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
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
-
};
|
|
14
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
-
exports.dockerClient = void 0;
|
|
16
|
-
const dockerode_1 = __importDefault(require("dockerode"));
|
|
17
|
-
const path_1 = __importDefault(require("path"));
|
|
18
|
-
const logger_1 = require("../logger");
|
|
19
|
-
const url_1 = require("url");
|
|
20
|
-
const fs_1 = require("fs");
|
|
21
|
-
const session_id_1 = require("./session-id");
|
|
22
|
-
const lookup_host_ips_1 = require("./lookup-host-ips");
|
|
23
|
-
const system_info_1 = require("../system-info");
|
|
24
|
-
const rootless_unix_socket_strategy_1 = require("./rootless-unix-socket-strategy");
|
|
25
|
-
const stream_utils_1 = require("../stream-utils");
|
|
26
|
-
const stream_1 = require("stream");
|
|
27
|
-
const docker_client_config_1 = require("./docker-client-config");
|
|
28
|
-
const resolve_host_1 = require("./resolve-host");
|
|
29
|
-
const getDockerClient = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
30
|
-
const strategies = [
|
|
31
|
-
new ConfigurationStrategy(),
|
|
32
|
-
new UnixSocketStrategy(),
|
|
33
|
-
new rootless_unix_socket_strategy_1.RootlessUnixSocketStrategy(),
|
|
34
|
-
new NpipeSocketStrategy(),
|
|
35
|
-
];
|
|
36
|
-
for (const strategy of strategies) {
|
|
37
|
-
if (strategy.init) {
|
|
38
|
-
yield strategy.init();
|
|
39
|
-
}
|
|
40
|
-
if (strategy.isApplicable()) {
|
|
41
|
-
logger_1.log.debug(`Found applicable Docker client strategy: ${strategy.getName()}`);
|
|
42
|
-
const { uri, dockerode, composeEnvironment } = yield strategy.getDockerClient();
|
|
43
|
-
logger_1.log.debug(`Testing Docker client strategy URI: ${uri}`);
|
|
44
|
-
if (yield isDockerDaemonReachable(dockerode)) {
|
|
45
|
-
const indexServerAddress = (yield (0, system_info_1.getSystemInfo)(dockerode)).dockerInfo.indexServerAddress;
|
|
46
|
-
const provider = uri.includes("podman.sock") ? "podman" : "docker";
|
|
47
|
-
const host = yield (0, resolve_host_1.resolveHost)(dockerode, provider, indexServerAddress, uri);
|
|
48
|
-
const hostIps = yield (0, lookup_host_ips_1.lookupHostIps)(host);
|
|
49
|
-
logger_1.log.info(`Using Docker client strategy: ${strategy.getName()}, Docker host: ${host} (${hostIps
|
|
50
|
-
.map((hostIp) => hostIp.address)
|
|
51
|
-
.join(", ")})`);
|
|
52
|
-
return { uri, provider, host, hostIps, dockerode, indexServerAddress, composeEnvironment };
|
|
53
|
-
}
|
|
54
|
-
else {
|
|
55
|
-
logger_1.log.warn(`Docker client strategy ${strategy.getName()} is not reachable`);
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
throw new Error("No Docker client strategy found");
|
|
60
|
-
});
|
|
61
|
-
const isDockerDaemonReachable = (dockerode) => __awaiter(void 0, void 0, void 0, function* () {
|
|
62
|
-
try {
|
|
63
|
-
const response = yield dockerode.ping();
|
|
64
|
-
return (yield (0, stream_utils_1.streamToString)(stream_1.Readable.from(response))) === "OK";
|
|
65
|
-
}
|
|
66
|
-
catch (err) {
|
|
67
|
-
logger_1.log.warn(`Docker daemon is not reachable: ${err}`);
|
|
68
|
-
return false;
|
|
69
|
-
}
|
|
70
|
-
});
|
|
71
|
-
class ConfigurationStrategy {
|
|
72
|
-
init() {
|
|
73
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
74
|
-
this.dockerConfig = yield (0, docker_client_config_1.getDockerClientConfig)();
|
|
75
|
-
});
|
|
76
|
-
}
|
|
77
|
-
getDockerClient() {
|
|
78
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
79
|
-
const { dockerHost, dockerTlsVerify, dockerCertPath } = this.dockerConfig;
|
|
80
|
-
const dockerOptions = { headers: { "x-tc-sid": session_id_1.sessionId } };
|
|
81
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
82
|
-
const { pathname, hostname, port } = new url_1.URL(dockerHost);
|
|
83
|
-
if (hostname !== "") {
|
|
84
|
-
dockerOptions.host = hostname;
|
|
85
|
-
dockerOptions.port = port;
|
|
86
|
-
}
|
|
87
|
-
else {
|
|
88
|
-
dockerOptions.socketPath = pathname;
|
|
89
|
-
}
|
|
90
|
-
if (dockerTlsVerify === "1" && dockerCertPath !== undefined) {
|
|
91
|
-
dockerOptions.ca = yield fs_1.promises.readFile(path_1.default.resolve(dockerCertPath, "ca.pem"));
|
|
92
|
-
dockerOptions.cert = yield fs_1.promises.readFile(path_1.default.resolve(dockerCertPath, "cert.pem"));
|
|
93
|
-
dockerOptions.key = yield fs_1.promises.readFile(path_1.default.resolve(dockerCertPath, "key.pem"));
|
|
94
|
-
}
|
|
95
|
-
return {
|
|
96
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
97
|
-
uri: dockerHost,
|
|
98
|
-
dockerode: new dockerode_1.default(dockerOptions),
|
|
99
|
-
composeEnvironment: {
|
|
100
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
101
|
-
DOCKER_HOST: dockerHost,
|
|
102
|
-
DOCKER_TLS_VERIFY: dockerTlsVerify,
|
|
103
|
-
DOCKER_CERT_PATH: dockerCertPath,
|
|
104
|
-
},
|
|
105
|
-
};
|
|
106
|
-
});
|
|
107
|
-
}
|
|
108
|
-
isApplicable() {
|
|
109
|
-
return this.dockerConfig.dockerHost !== undefined;
|
|
110
|
-
}
|
|
111
|
-
getName() {
|
|
112
|
-
return "ConfigurationStrategy";
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
class UnixSocketStrategy {
|
|
116
|
-
getDockerClient() {
|
|
117
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
118
|
-
return {
|
|
119
|
-
uri: "unix:///var/run/docker.sock",
|
|
120
|
-
dockerode: new dockerode_1.default({ socketPath: "/var/run/docker.sock" }),
|
|
121
|
-
composeEnvironment: {},
|
|
122
|
-
};
|
|
123
|
-
});
|
|
124
|
-
}
|
|
125
|
-
isApplicable() {
|
|
126
|
-
return (process.platform === "linux" || process.platform === "darwin") && (0, fs_1.existsSync)("/var/run/docker.sock");
|
|
127
|
-
}
|
|
128
|
-
getName() {
|
|
129
|
-
return "UnixSocketStrategy";
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
class NpipeSocketStrategy {
|
|
133
|
-
getDockerClient() {
|
|
134
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
135
|
-
return {
|
|
136
|
-
uri: "npipe:////./pipe/docker_engine",
|
|
137
|
-
dockerode: new dockerode_1.default({ socketPath: "//./pipe/docker_engine" }),
|
|
138
|
-
composeEnvironment: {},
|
|
139
|
-
};
|
|
140
|
-
});
|
|
141
|
-
}
|
|
142
|
-
isApplicable() {
|
|
143
|
-
return process.platform === "win32";
|
|
144
|
-
}
|
|
145
|
-
getName() {
|
|
146
|
-
return "NpipeSocketStrategy";
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
let _dockerClient;
|
|
150
|
-
const dockerClient = () => {
|
|
151
|
-
if (!_dockerClient) {
|
|
152
|
-
_dockerClient = getDockerClient();
|
|
153
|
-
}
|
|
154
|
-
return _dockerClient;
|
|
155
|
-
};
|
|
156
|
-
exports.dockerClient = dockerClient;
|