testcontainers 12.1.0 → 12.2.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/build/common/file-lock.js +3 -3
- package/build/common/hash.js +2 -2
- package/build/common/index.d.ts +2 -3
- package/build/common/index.js +2 -4
- package/build/common/retry.d.ts +1 -1
- package/build/common/uuid.js +2 -2
- package/build/container-runtime/auth/auths.d.ts +2 -2
- package/build/container-runtime/auth/cred-helpers.d.ts +1 -1
- package/build/container-runtime/auth/credential-provider.d.ts +2 -2
- package/build/container-runtime/auth/credential-provider.js +3 -3
- package/build/container-runtime/auth/creds-store.d.ts +2 -2
- package/build/container-runtime/auth/creds-store.js +1 -1
- package/build/container-runtime/auth/get-auth-config.d.ts +1 -1
- package/build/container-runtime/auth/get-auth-config.js +7 -7
- package/build/container-runtime/auth/registry-auth-locator.d.ts +1 -1
- package/build/container-runtime/auth/registry-matches.js +1 -1
- package/build/container-runtime/clients/client.d.ts +5 -5
- package/build/container-runtime/clients/compose/compose-client.d.ts +1 -1
- package/build/container-runtime/clients/compose/compose-client.js +1 -3
- package/build/container-runtime/clients/compose/default-compose-options.d.ts +2 -2
- package/build/container-runtime/clients/compose/default-compose-options.js +5 -3
- package/build/container-runtime/clients/compose/types.d.ts +3 -2
- package/build/container-runtime/clients/container/container-client.d.ts +5 -4
- package/build/container-runtime/clients/container/docker-container-client.d.ts +6 -5
- package/build/container-runtime/clients/container/docker-container-client.js +13 -9
- package/build/container-runtime/clients/container/types.d.ts +1 -3
- package/build/container-runtime/clients/image/docker-image-client.d.ts +4 -3
- package/build/container-runtime/clients/image/docker-image-client.js +11 -10
- package/build/container-runtime/clients/image/image-client.d.ts +2 -2
- package/build/container-runtime/clients/network/docker-network-client.d.ts +3 -2
- package/build/container-runtime/clients/network/network-client.d.ts +1 -1
- package/build/container-runtime/image-name.d.ts +2 -1
- package/build/container-runtime/image-name.js +23 -13
- package/build/container-runtime/index.d.ts +1 -1
- package/build/container-runtime/strategies/configuration-strategy.d.ts +2 -2
- package/build/container-runtime/strategies/configuration-strategy.js +7 -7
- package/build/container-runtime/strategies/npipe-socket-strategy.d.ts +2 -2
- package/build/container-runtime/strategies/rootless-unix-socket-strategy.d.ts +2 -2
- package/build/container-runtime/strategies/rootless-unix-socket-strategy.js +9 -9
- package/build/container-runtime/strategies/strategy.d.ts +1 -1
- package/build/container-runtime/strategies/testcontainers-host-strategy.d.ts +2 -2
- package/build/container-runtime/strategies/testcontainers-host-strategy.js +2 -2
- package/build/container-runtime/strategies/types.d.ts +1 -1
- package/build/container-runtime/strategies/unix-socket-strategy.d.ts +2 -2
- package/build/container-runtime/strategies/unix-socket-strategy.js +2 -2
- package/build/container-runtime/strategies/utils/config.js +12 -12
- package/build/container-runtime/utils/attach-container.d.ts +2 -2
- package/build/container-runtime/utils/demux-stream.d.ts +2 -2
- package/build/container-runtime/utils/demux-stream.js +2 -2
- package/build/container-runtime/utils/image-exists.d.ts +2 -2
- package/build/container-runtime/utils/lookup-host-ips.d.ts +1 -1
- package/build/container-runtime/utils/lookup-host-ips.js +4 -4
- package/build/container-runtime/utils/pull-image.d.ts +2 -2
- package/build/container-runtime/utils/remote-container-runtime-socket-path.d.ts +1 -1
- package/build/container-runtime/utils/remote-container-runtime-socket-path.js +2 -2
- package/build/container-runtime/utils/resolve-host.d.ts +2 -2
- package/build/container-runtime/utils/resolve-host.js +4 -4
- package/build/container-runtime/utils/run-in-container.d.ts +1 -1
- package/build/container-runtime/utils/run-in-container.js +2 -1
- package/build/container-runtime/utils/start-container.d.ts +1 -1
- package/build/docker-compose-environment/docker-compose-environment.d.ts +5 -5
- package/build/docker-compose-environment/docker-compose-environment.js +18 -8
- package/build/docker-compose-environment/started-docker-compose-environment.d.ts +2 -2
- package/build/docker-compose-environment/stopped-docker-compose-environment.d.ts +1 -1
- package/build/generic-container/abstract-started-container.d.ts +3 -3
- package/build/generic-container/abstract-stopped-container.d.ts +1 -1
- package/build/generic-container/generic-container-builder.d.ts +3 -3
- package/build/generic-container/generic-container-builder.js +11 -6
- package/build/generic-container/generic-container.d.ts +9 -9
- package/build/generic-container/generic-container.js +22 -8
- package/build/generic-container/inspect-container-util-ports-exposed.d.ts +1 -1
- package/build/generic-container/inspect-container-util-ports-exposed.js +1 -1
- package/build/generic-container/started-generic-container.d.ts +6 -5
- package/build/generic-container/started-generic-container.js +19 -16
- package/build/generic-container/stopped-generic-container.d.ts +2 -2
- package/build/index.d.ts +4 -4
- package/build/index.js +3 -3
- package/build/network/network.d.ts +3 -3
- package/build/port-forwarder/port-forwarder.d.ts +2 -3
- package/build/port-forwarder/port-forwarder.js +25 -19
- package/build/reaper/reaper.d.ts +1 -1
- package/build/reaper/reaper.js +21 -19
- package/build/socat/socat-container.d.ts +0 -2
- package/build/socat/socat-container.js +0 -3
- package/build/test-container.d.ts +6 -6
- package/build/test-containers.js +2 -1
- package/build/types.d.ts +3 -4
- package/build/utils/bound-ports.d.ts +3 -3
- package/build/utils/bound-ports.js +2 -2
- package/build/utils/dockerfile-parser.d.ts +1 -1
- package/build/utils/dockerfile-parser.js +2 -2
- package/build/utils/labels.d.ts +0 -2
- package/build/utils/labels.js +5 -5
- package/build/utils/map-inspect-result.d.ts +2 -2
- package/build/utils/map-inspect-result.js +12 -13
- package/build/utils/pull-policy.d.ts +2 -1
- package/build/utils/pull-policy.js +9 -0
- package/build/version.d.ts +1 -1
- package/build/version.js +1 -1
- package/build/wait-strategies/composite-wait-strategy.d.ts +3 -3
- package/build/wait-strategies/composite-wait-strategy.js +3 -1
- package/build/wait-strategies/health-check-wait-strategy.d.ts +1 -1
- package/build/wait-strategies/host-port-wait-strategy.d.ts +2 -2
- package/build/wait-strategies/http-wait-strategy.d.ts +2 -2
- package/build/wait-strategies/http-wait-strategy.js +4 -7
- package/build/wait-strategies/log-wait-strategy.d.ts +3 -3
- package/build/wait-strategies/log-wait-strategy.js +1 -1
- package/build/wait-strategies/one-shot-startup-startegy.d.ts +2 -2
- package/build/wait-strategies/shell-wait-strategy.d.ts +1 -1
- package/build/wait-strategies/startup-check-strategy.d.ts +1 -2
- package/build/wait-strategies/startup-check-strategy.js +0 -3
- package/build/wait-strategies/utils/health-check.d.ts +2 -4
- package/build/wait-strategies/utils/health-check.js +4 -6
- package/build/wait-strategies/utils/port-check.d.ts +2 -2
- package/build/wait-strategies/utils/port-check.js +2 -2
- package/build/wait-strategies/utils/undici-response-parser.d.ts +1 -1
- package/build/wait-strategies/utils/undici-response-parser.js +2 -2
- package/build/wait-strategies/utils/wait-strategy-selector.d.ts +4 -4
- package/build/wait-strategies/wait-for-container.d.ts +4 -4
- package/build/wait-strategies/wait-strategy.d.ts +2 -2
- package/build/wait-strategies/wait.d.ts +3 -3
- package/build/wait-strategies/wait.js +1 -0
- package/package.json +3 -4
- package/build/common/streams.d.ts +0 -6
- package/build/common/streams.js +0 -12
|
@@ -4,13 +4,15 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.GenericContainer = void 0;
|
|
7
|
+
const node_fs_1 = require("node:fs");
|
|
7
8
|
const archiver_1 = __importDefault(require("archiver"));
|
|
8
9
|
const async_lock_1 = __importDefault(require("async-lock"));
|
|
9
|
-
const fs_1 = require("fs");
|
|
10
10
|
const common_1 = require("../common");
|
|
11
11
|
const container_runtime_1 = require("../container-runtime");
|
|
12
12
|
const types_1 = require("../container-runtime/clients/container/types");
|
|
13
|
+
// biome-ignore lint/suspicious/noImportCycles: Ryuk and sshd run as GenericContainers; only dereferenced at runtime
|
|
13
14
|
const port_forwarder_1 = require("../port-forwarder/port-forwarder");
|
|
15
|
+
// biome-ignore lint/suspicious/noImportCycles: Ryuk and sshd run as GenericContainers; only dereferenced at runtime
|
|
14
16
|
const reaper_1 = require("../reaper/reaper");
|
|
15
17
|
const bound_ports_1 = require("../utils/bound-ports");
|
|
16
18
|
const labels_1 = require("../utils/labels");
|
|
@@ -19,8 +21,10 @@ const port_1 = require("../utils/port");
|
|
|
19
21
|
const pull_policy_1 = require("../utils/pull-policy");
|
|
20
22
|
const wait_strategy_selector_1 = require("../wait-strategies/utils/wait-strategy-selector");
|
|
21
23
|
const wait_for_container_1 = require("../wait-strategies/wait-for-container");
|
|
24
|
+
// biome-ignore lint/suspicious/noImportCycles: fromDockerfile() and build() construct each other; only dereferenced at runtime
|
|
22
25
|
const generic_container_builder_1 = require("./generic-container-builder");
|
|
23
26
|
const inspect_container_util_ports_exposed_1 = require("./inspect-container-util-ports-exposed");
|
|
27
|
+
// biome-ignore lint/suspicious/noImportCycles: Ryuk and sshd run as GenericContainers; only dereferenced at runtime
|
|
24
28
|
const started_generic_container_1 = require("./started-generic-container");
|
|
25
29
|
const reusableContainerCreationLock = new async_lock_1.default();
|
|
26
30
|
class GenericContainer {
|
|
@@ -59,11 +63,19 @@ class GenericContainer {
|
|
|
59
63
|
return this.imageName.string === (0, reaper_1.getReaperImage)();
|
|
60
64
|
}
|
|
61
65
|
async start() {
|
|
66
|
+
const shouldPull = this.pullPolicy.shouldPull();
|
|
62
67
|
const client = await (0, container_runtime_1.getContainerRuntimeClient)();
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
68
|
+
if (shouldPull === "never") {
|
|
69
|
+
if (!(await client.image.exists(this.imageName))) {
|
|
70
|
+
throw new Error(`Image "${this.imageName.string}" does not exist locally and pull policy is "never"`);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
await client.image.pull(this.imageName, {
|
|
75
|
+
force: shouldPull,
|
|
76
|
+
platform: this.createOpts.platform,
|
|
77
|
+
});
|
|
78
|
+
}
|
|
67
79
|
if (this.beforeContainerCreated) {
|
|
68
80
|
await this.beforeContainerCreated();
|
|
69
81
|
}
|
|
@@ -137,8 +149,10 @@ class GenericContainer {
|
|
|
137
149
|
}
|
|
138
150
|
if (this.filesToCopy.length > 0 || this.directoriesToCopy.length > 0 || this.contentsToCopy.length > 0) {
|
|
139
151
|
const archive = await this.createArchiveToCopyToContainer();
|
|
140
|
-
|
|
141
|
-
|
|
152
|
+
await Promise.all([
|
|
153
|
+
archive.finalize(),
|
|
154
|
+
client.container.putArchive(container, archive, "/", this.copyToContainerOptions),
|
|
155
|
+
]);
|
|
142
156
|
}
|
|
143
157
|
for (const archive of this.archivesToCopy) {
|
|
144
158
|
await client.container.putArchive(container, archive.tar, archive.target, this.copyToContainerOptions);
|
|
@@ -189,7 +203,7 @@ class GenericContainer {
|
|
|
189
203
|
const tar = (0, archiver_1.default)("tar");
|
|
190
204
|
const filesToCopyWithStats = await Promise.all(this.filesToCopy.map(async (fileToCopy) => ({
|
|
191
205
|
...fileToCopy,
|
|
192
|
-
stats: await
|
|
206
|
+
stats: await node_fs_1.promises.stat(fileToCopy.source),
|
|
193
207
|
})));
|
|
194
208
|
for (const { source, target, mode, stats } of filesToCopyWithStats) {
|
|
195
209
|
tar.file(source, { name: target, mode, stats });
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { ContainerInspectInfo } from "dockerode";
|
|
1
|
+
import type { ContainerInspectInfo } from "dockerode";
|
|
2
2
|
export declare function inspectContainerUntilPortsExposed(inspectFn: () => Promise<ContainerInspectInfo>, containerId: string, timeout?: number): Promise<ContainerInspectInfo>;
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.inspectContainerUntilPortsExposed = inspectContainerUntilPortsExposed;
|
|
4
4
|
const common_1 = require("../common");
|
|
5
|
-
async function inspectContainerUntilPortsExposed(inspectFn, containerId, timeout =
|
|
5
|
+
async function inspectContainerUntilPortsExposed(inspectFn, containerId, timeout = 30_000) {
|
|
6
6
|
const result = await new common_1.IntervalRetry(250).retryUntil(() => inspectFn(), (inspectResult) => {
|
|
7
7
|
const portBindings = inspectResult?.HostConfig?.PortBindings;
|
|
8
8
|
if (!portBindings)
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
1
|
+
import type { Readable } from "node:stream";
|
|
2
|
+
import type Dockerode from "dockerode";
|
|
3
|
+
import type { ContainerInspectInfo } from "dockerode";
|
|
4
|
+
import type { RestartOptions, StartedTestContainer, StopOptions, StoppedTestContainer } from "../test-container";
|
|
5
|
+
import type { CommitOptions, ContentToCopy, CopyToContainerOptions, DirectoryToCopy, ExecOptions, ExecResult, FileToCopy, Labels } from "../types";
|
|
5
6
|
import { BoundPorts } from "../utils/bound-ports";
|
|
6
|
-
import { WaitStrategy } from "../wait-strategies/wait-strategy";
|
|
7
|
+
import type { WaitStrategy } from "../wait-strategies/wait-strategy";
|
|
7
8
|
export declare class StartedGenericContainer implements StartedTestContainer {
|
|
8
9
|
private readonly container;
|
|
9
10
|
private readonly host;
|
|
@@ -4,11 +4,12 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.StartedGenericContainer = void 0;
|
|
7
|
+
const node_fs_1 = require("node:fs");
|
|
7
8
|
const archiver_1 = __importDefault(require("archiver"));
|
|
8
9
|
const async_lock_1 = __importDefault(require("async-lock"));
|
|
9
|
-
const fs_1 = require("fs");
|
|
10
10
|
const common_1 = require("../common");
|
|
11
11
|
const container_runtime_1 = require("../container-runtime");
|
|
12
|
+
// biome-ignore lint/suspicious/noImportCycles: Ryuk and sshd run as GenericContainers; only dereferenced at runtime
|
|
12
13
|
const reaper_1 = require("../reaper/reaper");
|
|
13
14
|
const bound_ports_1 = require("../utils/bound-ports");
|
|
14
15
|
const labels_1 = require("../utils/labels");
|
|
@@ -139,14 +140,13 @@ class StartedGenericContainer {
|
|
|
139
140
|
return this.getNetworkSettings()[networkName].ipAddress;
|
|
140
141
|
}
|
|
141
142
|
getNetworkSettings() {
|
|
142
|
-
return Object.entries(this.inspectResult.NetworkSettings.Networks)
|
|
143
|
-
|
|
144
|
-
|
|
143
|
+
return Object.fromEntries(Object.entries(this.inspectResult.NetworkSettings.Networks).map(([networkName, network]) => [
|
|
144
|
+
networkName,
|
|
145
|
+
{
|
|
145
146
|
networkId: network.NetworkID,
|
|
146
147
|
ipAddress: network.IPAddress,
|
|
147
148
|
},
|
|
148
|
-
|
|
149
|
-
.reduce((prev, next) => ({ ...prev, ...next }), {});
|
|
149
|
+
]));
|
|
150
150
|
}
|
|
151
151
|
async copyFilesToContainer(filesToCopy) {
|
|
152
152
|
common_1.log.debug(`Copying files to container...`, { containerId: this.container.id });
|
|
@@ -154,29 +154,32 @@ class StartedGenericContainer {
|
|
|
154
154
|
const tar = (0, archiver_1.default)("tar");
|
|
155
155
|
const filesToCopyWithStats = await Promise.all(filesToCopy.map(async (fileToCopy) => ({
|
|
156
156
|
...fileToCopy,
|
|
157
|
-
stats: await
|
|
157
|
+
stats: await node_fs_1.promises.stat(fileToCopy.source),
|
|
158
158
|
})));
|
|
159
|
-
filesToCopyWithStats.forEach(({ source, target, mode, stats }) =>
|
|
160
|
-
|
|
161
|
-
|
|
159
|
+
filesToCopyWithStats.forEach(({ source, target, mode, stats }) => {
|
|
160
|
+
tar.file(source, { name: target, mode, stats });
|
|
161
|
+
});
|
|
162
|
+
await Promise.all([tar.finalize(), client.container.putArchive(this.container, tar, "/")]);
|
|
162
163
|
common_1.log.debug(`Copied files to container`, { containerId: this.container.id });
|
|
163
164
|
}
|
|
164
165
|
async copyDirectoriesToContainer(directoriesToCopy) {
|
|
165
166
|
common_1.log.debug(`Copying directories to container...`, { containerId: this.container.id });
|
|
166
167
|
const client = await (0, container_runtime_1.getContainerRuntimeClient)();
|
|
167
168
|
const tar = (0, archiver_1.default)("tar");
|
|
168
|
-
directoriesToCopy.forEach(({ source, target }) =>
|
|
169
|
-
|
|
170
|
-
|
|
169
|
+
directoriesToCopy.forEach(({ source, target }) => {
|
|
170
|
+
tar.directory(source, target);
|
|
171
|
+
});
|
|
172
|
+
await Promise.all([tar.finalize(), client.container.putArchive(this.container, tar, "/")]);
|
|
171
173
|
common_1.log.debug(`Copied directories to container`, { containerId: this.container.id });
|
|
172
174
|
}
|
|
173
175
|
async copyContentToContainer(contentsToCopy) {
|
|
174
176
|
common_1.log.debug(`Copying content to container...`, { containerId: this.container.id });
|
|
175
177
|
const client = await (0, container_runtime_1.getContainerRuntimeClient)();
|
|
176
178
|
const tar = (0, archiver_1.default)("tar");
|
|
177
|
-
contentsToCopy.forEach(({ content, target, mode }) =>
|
|
178
|
-
|
|
179
|
-
|
|
179
|
+
contentsToCopy.forEach(({ content, target, mode }) => {
|
|
180
|
+
tar.append(content, { name: target, mode: mode });
|
|
181
|
+
});
|
|
182
|
+
await Promise.all([tar.finalize(), client.container.putArchive(this.container, tar, "/")]);
|
|
180
183
|
common_1.log.debug(`Copied content to container`, { containerId: this.container.id });
|
|
181
184
|
}
|
|
182
185
|
async copyArchiveToContainer(tar, target = "/", options) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import Dockerode from "dockerode";
|
|
2
|
-
import { StoppedTestContainer } from "../test-container";
|
|
1
|
+
import type Dockerode from "dockerode";
|
|
2
|
+
import type { StoppedTestContainer } from "../test-container";
|
|
3
3
|
export declare class StoppedGenericContainer implements StoppedTestContainer {
|
|
4
4
|
private readonly container;
|
|
5
5
|
constructor(container: Dockerode.Container);
|
package/build/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export { IntervalRetry, RandomUuid, Retry,
|
|
2
|
-
export { ContainerRuntimeClient,
|
|
1
|
+
export { IntervalRetry, log, RandomUuid, Retry, randomUuid, Uuid } from "./common";
|
|
2
|
+
export { ContainerRuntimeClient, getContainerRuntimeClient, ImageName } from "./container-runtime";
|
|
3
3
|
export { DockerComposeEnvironment } from "./docker-compose-environment/docker-compose-environment";
|
|
4
4
|
export { DownedDockerComposeEnvironment } from "./docker-compose-environment/downed-docker-compose-environment";
|
|
5
5
|
export { StartedDockerComposeEnvironment } from "./docker-compose-environment/started-docker-compose-environment";
|
|
@@ -13,10 +13,10 @@ export { getReaper } from "./reaper/reaper";
|
|
|
13
13
|
export { SocatContainer, StartedSocatContainer } from "./socat/socat-container";
|
|
14
14
|
export { RestartOptions, StartedTestContainer, StopOptions, StoppedTestContainer, TestContainer, } from "./test-container";
|
|
15
15
|
export { TestContainers } from "./test-containers";
|
|
16
|
-
export { CommitOptions, Content, CopyToContainerOptions, ExecOptions, ExecResult, InspectResult } from "./types";
|
|
16
|
+
export { BindMode, CommitOptions, Content, ContentToCopy, CopyToContainerOptions, Environment, ExecOptions, ExecResult, FileToCopy, HealthCheck, InspectResult, Labels, } from "./types";
|
|
17
17
|
export { BoundPorts } from "./utils/bound-ports";
|
|
18
18
|
export { LABEL_TESTCONTAINERS_SESSION_ID } from "./utils/labels";
|
|
19
|
-
export {
|
|
19
|
+
export { getContainerPort, hasHostBinding, PortWithBinding, PortWithOptionalBinding } from "./utils/port";
|
|
20
20
|
export { PortGenerator, RandomPortGenerator } from "./utils/port-generator";
|
|
21
21
|
export { ImagePullPolicy, PullPolicy } from "./utils/pull-policy";
|
|
22
22
|
export { HttpWaitStrategyOptions } from "./wait-strategies/http-wait-strategy";
|
package/build/index.js
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.waitForContainer = exports.Wait = exports.StartupCheckStrategy = exports.PullPolicy = exports.RandomPortGenerator = exports.hasHostBinding = exports.getContainerPort = exports.LABEL_TESTCONTAINERS_SESSION_ID = exports.BoundPorts = exports.TestContainers = exports.StartedSocatContainer = exports.SocatContainer = exports.getReaper = exports.StoppedNetwork = exports.StartedNetwork = exports.Network = exports.GenericContainerBuilder = exports.GenericContainer = exports.AbstractStoppedContainer = exports.AbstractStartedContainer = exports.StoppedDockerComposeEnvironment = exports.StartedDockerComposeEnvironment = exports.DownedDockerComposeEnvironment = exports.DockerComposeEnvironment = exports.
|
|
3
|
+
exports.waitForContainer = exports.Wait = exports.StartupCheckStrategy = exports.PullPolicy = exports.RandomPortGenerator = exports.hasHostBinding = exports.getContainerPort = exports.LABEL_TESTCONTAINERS_SESSION_ID = exports.BoundPorts = exports.TestContainers = exports.StartedSocatContainer = exports.SocatContainer = exports.getReaper = exports.StoppedNetwork = exports.StartedNetwork = exports.Network = exports.GenericContainerBuilder = exports.GenericContainer = exports.AbstractStoppedContainer = exports.AbstractStartedContainer = exports.StoppedDockerComposeEnvironment = exports.StartedDockerComposeEnvironment = exports.DownedDockerComposeEnvironment = exports.DockerComposeEnvironment = exports.ImageName = exports.getContainerRuntimeClient = exports.ContainerRuntimeClient = exports.randomUuid = exports.RandomUuid = exports.log = exports.IntervalRetry = void 0;
|
|
4
4
|
var common_1 = require("./common");
|
|
5
5
|
Object.defineProperty(exports, "IntervalRetry", { enumerable: true, get: function () { return common_1.IntervalRetry; } });
|
|
6
|
-
Object.defineProperty(exports, "RandomUuid", { enumerable: true, get: function () { return common_1.RandomUuid; } });
|
|
7
6
|
Object.defineProperty(exports, "log", { enumerable: true, get: function () { return common_1.log; } });
|
|
7
|
+
Object.defineProperty(exports, "RandomUuid", { enumerable: true, get: function () { return common_1.RandomUuid; } });
|
|
8
8
|
Object.defineProperty(exports, "randomUuid", { enumerable: true, get: function () { return common_1.randomUuid; } });
|
|
9
9
|
var container_runtime_1 = require("./container-runtime");
|
|
10
10
|
Object.defineProperty(exports, "ContainerRuntimeClient", { enumerable: true, get: function () { return container_runtime_1.ContainerRuntimeClient; } });
|
|
11
|
-
Object.defineProperty(exports, "ImageName", { enumerable: true, get: function () { return container_runtime_1.ImageName; } });
|
|
12
11
|
Object.defineProperty(exports, "getContainerRuntimeClient", { enumerable: true, get: function () { return container_runtime_1.getContainerRuntimeClient; } });
|
|
12
|
+
Object.defineProperty(exports, "ImageName", { enumerable: true, get: function () { return container_runtime_1.ImageName; } });
|
|
13
13
|
var docker_compose_environment_1 = require("./docker-compose-environment/docker-compose-environment");
|
|
14
14
|
Object.defineProperty(exports, "DockerComposeEnvironment", { enumerable: true, get: function () { return docker_compose_environment_1.DockerComposeEnvironment; } });
|
|
15
15
|
var downed_docker_compose_environment_1 = require("./docker-compose-environment/downed-docker-compose-environment");
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import Dockerode from "dockerode";
|
|
2
|
-
import { Uuid } from "../common";
|
|
3
|
-
import { ContainerRuntimeClient } from "../container-runtime";
|
|
1
|
+
import type Dockerode from "dockerode";
|
|
2
|
+
import { type Uuid } from "../common";
|
|
3
|
+
import { type ContainerRuntimeClient } from "../container-runtime";
|
|
4
4
|
export declare class Network {
|
|
5
5
|
private readonly uuid;
|
|
6
6
|
constructor(uuid?: Uuid);
|
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
import { SshConnection } from "ssh-remote-port-forward";
|
|
1
|
+
import { type SshConnection } from "ssh-remote-port-forward";
|
|
2
2
|
export declare const SSHD_IMAGE: string;
|
|
3
3
|
declare class PortForwarder {
|
|
4
4
|
private readonly sshConnection;
|
|
5
5
|
private readonly containerId;
|
|
6
6
|
private readonly networkId;
|
|
7
7
|
private readonly ipAddress;
|
|
8
|
-
|
|
9
|
-
constructor(sshConnection: SshConnection, containerId: string, networkId: string, ipAddress: string, networkName: string);
|
|
8
|
+
constructor(sshConnection: SshConnection, containerId: string, networkId: string, ipAddress: string);
|
|
10
9
|
exposeHostPort(port: number): Promise<void>;
|
|
11
10
|
getContainerId(): string;
|
|
12
11
|
getNetworkId(): string;
|
|
@@ -4,24 +4,24 @@ exports.PortForwarderInstance = exports.SSHD_IMAGE = void 0;
|
|
|
4
4
|
const ssh_remote_port_forward_1 = require("ssh-remote-port-forward");
|
|
5
5
|
const common_1 = require("../common");
|
|
6
6
|
const container_runtime_1 = require("../container-runtime");
|
|
7
|
+
// biome-ignore lint/suspicious/noImportCycles: Ryuk and sshd run as GenericContainers; only dereferenced at runtime
|
|
7
8
|
const generic_container_1 = require("../generic-container/generic-container");
|
|
9
|
+
// biome-ignore lint/suspicious/noImportCycles: Ryuk and sshd run as GenericContainers; only dereferenced at runtime
|
|
8
10
|
const reaper_1 = require("../reaper/reaper");
|
|
9
11
|
const labels_1 = require("../utils/labels");
|
|
10
|
-
exports.SSHD_IMAGE = process.env
|
|
11
|
-
? container_runtime_1.ImageName.fromString(process.env
|
|
12
|
+
exports.SSHD_IMAGE = process.env.SSHD_CONTAINER_IMAGE
|
|
13
|
+
? container_runtime_1.ImageName.fromString(process.env.SSHD_CONTAINER_IMAGE).string
|
|
12
14
|
: container_runtime_1.ImageName.fromString("testcontainers/sshd:1.4.0").string;
|
|
13
15
|
class PortForwarder {
|
|
14
16
|
sshConnection;
|
|
15
17
|
containerId;
|
|
16
18
|
networkId;
|
|
17
19
|
ipAddress;
|
|
18
|
-
|
|
19
|
-
constructor(sshConnection, containerId, networkId, ipAddress, networkName) {
|
|
20
|
+
constructor(sshConnection, containerId, networkId, ipAddress) {
|
|
20
21
|
this.sshConnection = sshConnection;
|
|
21
22
|
this.containerId = containerId;
|
|
22
23
|
this.networkId = networkId;
|
|
23
24
|
this.ipAddress = ipAddress;
|
|
24
|
-
this.networkName = networkName;
|
|
25
25
|
}
|
|
26
26
|
async exposeHostPort(port) {
|
|
27
27
|
common_1.log.info(`Exposing host port ${port}...`);
|
|
@@ -38,30 +38,31 @@ class PortForwarder {
|
|
|
38
38
|
return this.ipAddress;
|
|
39
39
|
}
|
|
40
40
|
}
|
|
41
|
+
// biome-ignore lint/complexity/noStaticOnlyClass: singleton holder with private static state
|
|
41
42
|
class PortForwarderInstance {
|
|
42
43
|
static USERNAME = "root";
|
|
43
44
|
static PASSWORD = "root";
|
|
44
45
|
static instance;
|
|
45
46
|
static isRunning() {
|
|
46
|
-
return
|
|
47
|
+
return PortForwarderInstance.instance !== undefined;
|
|
47
48
|
}
|
|
48
49
|
static async getInstance() {
|
|
49
|
-
if (!
|
|
50
|
+
if (!PortForwarderInstance.instance) {
|
|
50
51
|
await (0, common_1.withFileLock)("testcontainers-node-sshd.lock", async () => {
|
|
51
52
|
const client = await (0, container_runtime_1.getContainerRuntimeClient)();
|
|
52
53
|
const reaper = await (0, reaper_1.getReaper)(client);
|
|
53
54
|
const sessionId = reaper.sessionId;
|
|
54
|
-
const portForwarderContainer = await
|
|
55
|
+
const portForwarderContainer = await PortForwarderInstance.findPortForwarderContainer(client, sessionId);
|
|
55
56
|
if (portForwarderContainer) {
|
|
56
|
-
|
|
57
|
+
PortForwarderInstance.instance = PortForwarderInstance.reuseInstance(client, portForwarderContainer, sessionId);
|
|
57
58
|
}
|
|
58
59
|
else {
|
|
59
|
-
|
|
60
|
+
PortForwarderInstance.instance = PortForwarderInstance.createInstance();
|
|
60
61
|
}
|
|
61
|
-
await
|
|
62
|
+
await PortForwarderInstance.instance;
|
|
62
63
|
});
|
|
63
64
|
}
|
|
64
|
-
return
|
|
65
|
+
return PortForwarderInstance.instance;
|
|
65
66
|
}
|
|
66
67
|
static async findPortForwarderContainer(client, sessionId) {
|
|
67
68
|
const containers = await client.container.list();
|
|
@@ -72,7 +73,7 @@ class PortForwarderInstance {
|
|
|
72
73
|
static async reuseInstance(client, container, sessionId) {
|
|
73
74
|
common_1.log.debug(`Reusing existing PortForwarder for session "${sessionId}"...`);
|
|
74
75
|
const host = client.info.containerRuntime.host;
|
|
75
|
-
const port = container.Ports.find((port) => port.PrivatePort
|
|
76
|
+
const port = container.Ports.find((port) => port.PrivatePort === 22)?.PublicPort;
|
|
76
77
|
if (!port) {
|
|
77
78
|
throw new Error("Expected PortForwarder to map exposed port 22");
|
|
78
79
|
}
|
|
@@ -91,32 +92,37 @@ class PortForwarderInstance {
|
|
|
91
92
|
const networkName = networks[0][0];
|
|
92
93
|
const networkId = container.NetworkSettings.Networks[networkName].NetworkID;
|
|
93
94
|
const ipAddress = container.NetworkSettings.Networks[networkName].IPAddress;
|
|
94
|
-
return new PortForwarder(connection, containerId, networkId, ipAddress
|
|
95
|
+
return new PortForwarder(connection, containerId, networkId, ipAddress);
|
|
95
96
|
}
|
|
96
97
|
static async createInstance() {
|
|
97
98
|
common_1.log.debug(`Creating new Port Forwarder...`);
|
|
98
99
|
const client = await (0, container_runtime_1.getContainerRuntimeClient)();
|
|
99
100
|
const reaper = await (0, reaper_1.getReaper)(client);
|
|
100
|
-
const containerPort = process.env
|
|
101
|
-
? { container: 22, host: Number(process.env
|
|
101
|
+
const containerPort = process.env.TESTCONTAINERS_SSHD_PORT
|
|
102
|
+
? { container: 22, host: Number(process.env.TESTCONTAINERS_SSHD_PORT) }
|
|
102
103
|
: 22;
|
|
103
104
|
const container = await new generic_container_1.GenericContainer(exports.SSHD_IMAGE)
|
|
104
105
|
.withName(`testcontainers-port-forwarder-${reaper.sessionId}`)
|
|
105
106
|
.withExposedPorts(containerPort)
|
|
106
|
-
.withEnvironment({ PASSWORD:
|
|
107
|
+
.withEnvironment({ PASSWORD: PortForwarderInstance.PASSWORD })
|
|
107
108
|
.withLabels({ [labels_1.LABEL_TESTCONTAINERS_SSHD]: "true" })
|
|
108
109
|
.start();
|
|
109
110
|
const host = client.info.containerRuntime.host;
|
|
110
111
|
const port = container.getMappedPort(22);
|
|
111
112
|
common_1.log.debug(`Connecting to Port Forwarder on "${host}:${port}"...`);
|
|
112
|
-
const connection = await (0, ssh_remote_port_forward_1.createSshConnection)({
|
|
113
|
+
const connection = await (0, ssh_remote_port_forward_1.createSshConnection)({
|
|
114
|
+
host,
|
|
115
|
+
port,
|
|
116
|
+
username: PortForwarderInstance.USERNAME,
|
|
117
|
+
password: PortForwarderInstance.PASSWORD,
|
|
118
|
+
});
|
|
113
119
|
common_1.log.debug(`Connected to Port Forwarder on "${host}:${port}"`);
|
|
114
120
|
connection.unref();
|
|
115
121
|
const containerId = container.getId();
|
|
116
122
|
const networkName = container.getNetworkNames()[0];
|
|
117
123
|
const networkId = container.getNetworkId(networkName);
|
|
118
124
|
const ipAddress = container.getIpAddress(networkName);
|
|
119
|
-
return new PortForwarder(connection, containerId, networkId, ipAddress
|
|
125
|
+
return new PortForwarder(connection, containerId, networkId, ipAddress);
|
|
120
126
|
}
|
|
121
127
|
}
|
|
122
128
|
exports.PortForwarderInstance = PortForwarderInstance;
|
package/build/reaper/reaper.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ContainerRuntimeClient } from "../container-runtime";
|
|
1
|
+
import { type ContainerRuntimeClient } from "../container-runtime";
|
|
2
2
|
/**
|
|
3
3
|
* Resolve the Ryuk reaper image name. Read lazily so that callers (and tests)
|
|
4
4
|
* can set `process.env.RYUK_CONTAINER_IMAGE` _after_ this module is imported —
|
package/build/reaper/reaper.js
CHANGED
|
@@ -2,10 +2,11 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.getReaperImage = getReaperImage;
|
|
4
4
|
exports.getReaper = getReaper;
|
|
5
|
-
const
|
|
6
|
-
const
|
|
5
|
+
const node_net_1 = require("node:net");
|
|
6
|
+
const node_os_1 = require("node:os");
|
|
7
7
|
const common_1 = require("../common");
|
|
8
8
|
const container_runtime_1 = require("../container-runtime");
|
|
9
|
+
// biome-ignore lint/suspicious/noImportCycles: Ryuk and sshd run as GenericContainers; only dereferenced at runtime
|
|
9
10
|
const generic_container_1 = require("../generic-container/generic-container");
|
|
10
11
|
const labels_1 = require("../utils/labels");
|
|
11
12
|
const wait_1 = require("../wait-strategies/wait");
|
|
@@ -17,8 +18,8 @@ const wait_1 = require("../wait-strategies/wait");
|
|
|
17
18
|
* See https://github.com/testcontainers/testcontainers-node/issues/1310.
|
|
18
19
|
*/
|
|
19
20
|
function getReaperImage() {
|
|
20
|
-
return process.env
|
|
21
|
-
? container_runtime_1.ImageName.fromString(process.env
|
|
21
|
+
return process.env.RYUK_CONTAINER_IMAGE
|
|
22
|
+
? container_runtime_1.ImageName.fromString(process.env.RYUK_CONTAINER_IMAGE).string
|
|
22
23
|
: container_runtime_1.ImageName.fromString("testcontainers/ryuk:0.14.0").string;
|
|
23
24
|
}
|
|
24
25
|
let reaper;
|
|
@@ -27,7 +28,7 @@ async function getReaper(client) {
|
|
|
27
28
|
if (reaper) {
|
|
28
29
|
return reaper;
|
|
29
30
|
}
|
|
30
|
-
const userId = (0,
|
|
31
|
+
const userId = (0, node_os_1.userInfo)().uid;
|
|
31
32
|
reaper = await (0, common_1.withFileLock)(`testcontainers-node-${userId}.lock`, async () => {
|
|
32
33
|
const reaperContainers = await findReaperContainers(client);
|
|
33
34
|
if (process.env.TESTCONTAINERS_RYUK_DISABLED === "true") {
|
|
@@ -35,9 +36,8 @@ async function getReaper(client) {
|
|
|
35
36
|
return new DisabledReaper(sessionId, "");
|
|
36
37
|
}
|
|
37
38
|
for (const reaperContainer of reaperContainers) {
|
|
38
|
-
const existingSessionId = reaperContainer.Labels[labels_1.LABEL_TESTCONTAINERS_SESSION_ID] ?? new common_1.RandomUuid().nextUuid();
|
|
39
39
|
try {
|
|
40
|
-
sessionId =
|
|
40
|
+
sessionId = reaperContainer.Labels[labels_1.LABEL_TESTCONTAINERS_SESSION_ID];
|
|
41
41
|
return await useExistingReaper(reaperContainer, sessionId, client.info.containerRuntime.host);
|
|
42
42
|
}
|
|
43
43
|
catch (error) {
|
|
@@ -58,12 +58,14 @@ async function findReaperContainers(client) {
|
|
|
58
58
|
return containers
|
|
59
59
|
.filter((container) => container.State === "running" &&
|
|
60
60
|
container.Labels[labels_1.LABEL_TESTCONTAINERS_RYUK] === "true" &&
|
|
61
|
-
container.Labels[
|
|
61
|
+
container.Labels[labels_1.LABEL_TESTCONTAINERS_LANG] === "node" &&
|
|
62
|
+
!!container.Labels[labels_1.LABEL_TESTCONTAINERS_SESSION_ID] &&
|
|
63
|
+
container.Labels.TESTCONTAINERS_RYUK_TEST_LABEL !== "true")
|
|
62
64
|
.sort((a, b) => b.Created - a.Created);
|
|
63
65
|
}
|
|
64
66
|
async function useExistingReaper(reaperContainer, sessionId, host) {
|
|
65
67
|
common_1.log.debug(`Reusing existing Reaper for session "${sessionId}"...`);
|
|
66
|
-
const reaperPort = reaperContainer.Ports.find((port) => port.PrivatePort
|
|
68
|
+
const reaperPort = reaperContainer.Ports.find((port) => port.PrivatePort === 8080)?.PublicPort;
|
|
67
69
|
if (!reaperPort) {
|
|
68
70
|
throw new Error("Expected Reaper to map exposed port 8080");
|
|
69
71
|
}
|
|
@@ -74,22 +76,22 @@ async function createNewReaper(sessionId, remoteSocketPath) {
|
|
|
74
76
|
common_1.log.debug(`Creating new Reaper for session "${sessionId}" with socket path "${remoteSocketPath}"...`);
|
|
75
77
|
const container = new generic_container_1.GenericContainer(getReaperImage())
|
|
76
78
|
.withName(`testcontainers-ryuk-${sessionId}`)
|
|
77
|
-
.withExposedPorts(process.env
|
|
78
|
-
? { container: 8080, host: parseInt(process.env
|
|
79
|
+
.withExposedPorts(process.env.TESTCONTAINERS_RYUK_PORT
|
|
80
|
+
? { container: 8080, host: parseInt(process.env.TESTCONTAINERS_RYUK_PORT, 10) }
|
|
79
81
|
: 8080)
|
|
80
82
|
.withBindMounts([{ source: remoteSocketPath, target: "/var/run/docker.sock" }])
|
|
81
83
|
.withLabels({ [labels_1.LABEL_TESTCONTAINERS_SESSION_ID]: sessionId })
|
|
82
84
|
.withWaitStrategy(wait_1.Wait.forLogMessage(/.*Started.*/));
|
|
83
|
-
if (process.env
|
|
84
|
-
container.withEnvironment({ RYUK_VERBOSE: process.env
|
|
85
|
+
if (process.env.TESTCONTAINERS_RYUK_VERBOSE) {
|
|
86
|
+
container.withEnvironment({ RYUK_VERBOSE: process.env.TESTCONTAINERS_RYUK_VERBOSE });
|
|
85
87
|
}
|
|
86
|
-
if (process.env
|
|
87
|
-
container.withEnvironment({ RYUK_RECONNECTION_TIMEOUT: process.env
|
|
88
|
+
if (process.env.TESTCONTAINERS_RYUK_RECONNECTION_TIMEOUT) {
|
|
89
|
+
container.withEnvironment({ RYUK_RECONNECTION_TIMEOUT: process.env.TESTCONTAINERS_RYUK_RECONNECTION_TIMEOUT });
|
|
88
90
|
}
|
|
89
|
-
if (process.env
|
|
91
|
+
if (process.env.TESTCONTAINERS_RYUK_PRIVILEGED === "true") {
|
|
90
92
|
container.withPrivilegedMode();
|
|
91
93
|
}
|
|
92
|
-
if (process.env
|
|
94
|
+
if (process.env.TESTCONTAINERS_RYUK_TEST_LABEL === "true") {
|
|
93
95
|
container.withLabels({ TESTCONTAINERS_RYUK_TEST_LABEL: "true" });
|
|
94
96
|
}
|
|
95
97
|
const startedContainer = await container.start();
|
|
@@ -100,7 +102,7 @@ async function connectToReaperSocket(host, port, containerId) {
|
|
|
100
102
|
const retryResult = await new common_1.IntervalRetry(1000).retryUntil((attempt) => {
|
|
101
103
|
return new Promise((resolve) => {
|
|
102
104
|
common_1.log.debug(`Connecting to Reaper (attempt ${attempt + 1}) on "${host}:${port}"...`, { containerId });
|
|
103
|
-
const socket = new
|
|
105
|
+
const socket = new node_net_1.Socket();
|
|
104
106
|
socket
|
|
105
107
|
.unref()
|
|
106
108
|
.on("timeout", () => common_1.log.error(`Reaper ${containerId} socket timed out`))
|
|
@@ -124,7 +126,7 @@ async function connectToReaperSocket(host, port, containerId) {
|
|
|
124
126
|
common_1.log.error(message, { containerId });
|
|
125
127
|
return new Error(message);
|
|
126
128
|
}, 4000);
|
|
127
|
-
if (retryResult instanceof
|
|
129
|
+
if (retryResult instanceof node_net_1.Socket) {
|
|
128
130
|
return retryResult;
|
|
129
131
|
}
|
|
130
132
|
else {
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { AbstractStartedContainer } from "../generic-container/abstract-started-container";
|
|
2
2
|
import { GenericContainer } from "../generic-container/generic-container";
|
|
3
|
-
import { StartedTestContainer } from "../test-container";
|
|
4
3
|
export declare class SocatContainer extends GenericContainer {
|
|
5
4
|
private targets;
|
|
6
5
|
constructor(image?: string);
|
|
@@ -8,5 +7,4 @@ export declare class SocatContainer extends GenericContainer {
|
|
|
8
7
|
start(): Promise<StartedSocatContainer>;
|
|
9
8
|
}
|
|
10
9
|
export declare class StartedSocatContainer extends AbstractStartedContainer {
|
|
11
|
-
constructor(startedTestcontainers: StartedTestContainer);
|
|
12
10
|
}
|
|
@@ -26,8 +26,5 @@ class SocatContainer extends generic_container_1.GenericContainer {
|
|
|
26
26
|
}
|
|
27
27
|
exports.SocatContainer = SocatContainer;
|
|
28
28
|
class StartedSocatContainer extends abstract_started_container_1.AbstractStartedContainer {
|
|
29
|
-
constructor(startedTestcontainers) {
|
|
30
|
-
super(startedTestcontainers);
|
|
31
|
-
}
|
|
32
29
|
}
|
|
33
30
|
exports.StartedSocatContainer = StartedSocatContainer;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { Readable } from "stream";
|
|
2
|
-
import { StartedNetwork } from "./network/network";
|
|
3
|
-
import { ArchiveToCopy, BindMount, CommitOptions, ContentToCopy, CopyToContainerOptions, DirectoryToCopy, Environment, ExecOptions, ExecResult, ExtraHost, FileToCopy, Labels, ResourcesQuota, TmpFs, Ulimits } from "./types";
|
|
4
|
-
import { PortWithOptionalBinding } from "./utils/port";
|
|
5
|
-
import { ImagePullPolicy } from "./utils/pull-policy";
|
|
6
|
-
import { WaitStrategy } from "./wait-strategies/wait-strategy";
|
|
1
|
+
import type { Readable } from "node:stream";
|
|
2
|
+
import type { StartedNetwork } from "./network/network";
|
|
3
|
+
import type { ArchiveToCopy, BindMount, CommitOptions, ContentToCopy, CopyToContainerOptions, DirectoryToCopy, Environment, ExecOptions, ExecResult, ExtraHost, FileToCopy, Labels, ResourcesQuota, TmpFs, Ulimits } from "./types";
|
|
4
|
+
import type { PortWithOptionalBinding } from "./utils/port";
|
|
5
|
+
import type { ImagePullPolicy } from "./utils/pull-policy";
|
|
6
|
+
import type { WaitStrategy } from "./wait-strategies/wait-strategy";
|
|
7
7
|
export interface TestContainer {
|
|
8
8
|
start(): Promise<StartedTestContainer>;
|
|
9
9
|
withEnvironment(environment: Environment): this;
|
package/build/test-containers.js
CHANGED
|
@@ -4,11 +4,12 @@ exports.TestContainers = void 0;
|
|
|
4
4
|
const common_1 = require("./common");
|
|
5
5
|
const container_runtime_1 = require("./container-runtime");
|
|
6
6
|
const port_forwarder_1 = require("./port-forwarder/port-forwarder");
|
|
7
|
+
// biome-ignore lint/complexity/noStaticOnlyClass: public API surface, kept as a class for backwards compatibility
|
|
7
8
|
class TestContainers {
|
|
8
9
|
static async exposeHostPorts(...ports) {
|
|
9
10
|
const portForwarder = await port_forwarder_1.PortForwarderInstance.getInstance();
|
|
10
11
|
await Promise.all(ports.map((port) => portForwarder.exposeHostPort(port).catch(async (err) => {
|
|
11
|
-
if (await
|
|
12
|
+
if (await TestContainers.isHostPortExposed(portForwarder.getContainerId(), port)) {
|
|
12
13
|
common_1.log.debug(`Host port ${port} is already exposed`);
|
|
13
14
|
}
|
|
14
15
|
else {
|
package/build/types.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { Readable } from "stream";
|
|
2
|
-
import { AuthConfig } from "./container-runtime/auth/types";
|
|
3
|
-
import { ContainerCommitOptions } from "./container-runtime/clients/container/types";
|
|
1
|
+
import type { Readable } from "node:stream";
|
|
2
|
+
import type { AuthConfig } from "./container-runtime/auth/types";
|
|
3
|
+
import type { ContainerCommitOptions } from "./container-runtime/clients/container/types";
|
|
4
4
|
export type InspectResult = {
|
|
5
5
|
name: string;
|
|
6
6
|
hostname: string;
|
|
@@ -17,7 +17,6 @@ export type InspectResult = {
|
|
|
17
17
|
};
|
|
18
18
|
labels: Labels;
|
|
19
19
|
};
|
|
20
|
-
export type ContainerRuntime = "docker" | "podman";
|
|
21
20
|
export type Environment = {
|
|
22
21
|
[key in string]: string;
|
|
23
22
|
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { HostIp } from "../container-runtime";
|
|
2
|
-
import { HostPortBindings, InspectResult } from "../types";
|
|
3
|
-
import { PortWithOptionalBinding } from "./port";
|
|
1
|
+
import type { HostIp } from "../container-runtime";
|
|
2
|
+
import type { HostPortBindings, InspectResult } from "../types";
|
|
3
|
+
import { type PortWithOptionalBinding } from "./port";
|
|
4
4
|
export declare class BoundPorts {
|
|
5
5
|
private readonly ports;
|
|
6
6
|
getBinding(port: number | string, protocol?: string): number;
|
|
@@ -4,7 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.resolveHostPortBinding = exports.BoundPorts = void 0;
|
|
7
|
-
const
|
|
7
|
+
const node_net_1 = __importDefault(require("node:net"));
|
|
8
8
|
const port_1 = require("./port");
|
|
9
9
|
class BoundPorts {
|
|
10
10
|
ports = new Map();
|
|
@@ -79,7 +79,7 @@ const resolveHostPortBinding = (hostIps, hostPortBindings) => {
|
|
|
79
79
|
return hostPortBindings[0].hostPort;
|
|
80
80
|
}
|
|
81
81
|
for (const { family } of hostIps) {
|
|
82
|
-
const hostPortBinding = hostPortBindings.find(({ hostIp }) =>
|
|
82
|
+
const hostPortBinding = hostPortBindings.find(({ hostIp }) => node_net_1.default.isIP(hostIp) === family);
|
|
83
83
|
if (hostPortBinding !== undefined) {
|
|
84
84
|
return hostPortBinding.hostPort;
|
|
85
85
|
}
|