testcontainers 12.0.2 → 12.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/container-runtime/clients/container/docker-container-client.js +13 -5
- package/build/generic-container/generic-container.js +2 -2
- package/build/generic-container/started-generic-container.js +4 -4
- package/build/port-forwarder/port-forwarder.js +1 -1
- package/build/version.d.ts +1 -1
- package/build/version.js +1 -1
- package/build/wait-strategies/http-wait-strategy.d.ts +2 -2
- package/build/wait-strategies/http-wait-strategy.js +60 -49
- package/package.json +5 -5
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.DockerContainerClient = void 0;
|
|
4
4
|
const stream_1 = require("stream");
|
|
5
|
+
const promises_1 = require("stream/promises");
|
|
5
6
|
const common_1 = require("../../../common");
|
|
6
7
|
class DockerContainerClient {
|
|
7
8
|
dockerode;
|
|
@@ -216,11 +217,18 @@ class DockerContainerClient {
|
|
|
216
217
|
};
|
|
217
218
|
processStream(stdoutStream, stdoutChunks);
|
|
218
219
|
processStream(stderrStream, stderrChunks);
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
220
|
+
try {
|
|
221
|
+
await new Promise((res, rej) => {
|
|
222
|
+
stream.on("end", res);
|
|
223
|
+
stream.on("error", rej);
|
|
224
|
+
});
|
|
225
|
+
stdoutStream.end();
|
|
226
|
+
stderrStream.end();
|
|
227
|
+
await Promise.all([(0, promises_1.finished)(stdoutStream), (0, promises_1.finished)(stderrStream)]);
|
|
228
|
+
}
|
|
229
|
+
finally {
|
|
230
|
+
stream.destroy();
|
|
231
|
+
}
|
|
224
232
|
const inspectResult = await exec.inspect();
|
|
225
233
|
const exitCode = inspectResult.ExitCode ?? -1;
|
|
226
234
|
const output = outputChunks.join("");
|
|
@@ -4,7 +4,7 @@ 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 archiver_1 = require("archiver");
|
|
7
|
+
const archiver_1 = __importDefault(require("archiver"));
|
|
8
8
|
const async_lock_1 = __importDefault(require("async-lock"));
|
|
9
9
|
const fs_1 = require("fs");
|
|
10
10
|
const common_1 = require("../common");
|
|
@@ -186,7 +186,7 @@ class GenericContainer {
|
|
|
186
186
|
}
|
|
187
187
|
}
|
|
188
188
|
async createArchiveToCopyToContainer() {
|
|
189
|
-
const tar =
|
|
189
|
+
const tar = (0, archiver_1.default)("tar");
|
|
190
190
|
const filesToCopyWithStats = await Promise.all(this.filesToCopy.map(async (fileToCopy) => ({
|
|
191
191
|
...fileToCopy,
|
|
192
192
|
stats: await fs_1.promises.stat(fileToCopy.source),
|
|
@@ -4,7 +4,7 @@ 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 archiver_1 = require("archiver");
|
|
7
|
+
const archiver_1 = __importDefault(require("archiver"));
|
|
8
8
|
const async_lock_1 = __importDefault(require("async-lock"));
|
|
9
9
|
const fs_1 = require("fs");
|
|
10
10
|
const common_1 = require("../common");
|
|
@@ -151,7 +151,7 @@ class StartedGenericContainer {
|
|
|
151
151
|
async copyFilesToContainer(filesToCopy) {
|
|
152
152
|
common_1.log.debug(`Copying files to container...`, { containerId: this.container.id });
|
|
153
153
|
const client = await (0, container_runtime_1.getContainerRuntimeClient)();
|
|
154
|
-
const tar =
|
|
154
|
+
const tar = (0, archiver_1.default)("tar");
|
|
155
155
|
const filesToCopyWithStats = await Promise.all(filesToCopy.map(async (fileToCopy) => ({
|
|
156
156
|
...fileToCopy,
|
|
157
157
|
stats: await fs_1.promises.stat(fileToCopy.source),
|
|
@@ -164,7 +164,7 @@ class StartedGenericContainer {
|
|
|
164
164
|
async copyDirectoriesToContainer(directoriesToCopy) {
|
|
165
165
|
common_1.log.debug(`Copying directories to container...`, { containerId: this.container.id });
|
|
166
166
|
const client = await (0, container_runtime_1.getContainerRuntimeClient)();
|
|
167
|
-
const tar =
|
|
167
|
+
const tar = (0, archiver_1.default)("tar");
|
|
168
168
|
directoriesToCopy.forEach(({ source, target }) => tar.directory(source, target));
|
|
169
169
|
tar.finalize();
|
|
170
170
|
await client.container.putArchive(this.container, tar, "/");
|
|
@@ -173,7 +173,7 @@ class StartedGenericContainer {
|
|
|
173
173
|
async copyContentToContainer(contentsToCopy) {
|
|
174
174
|
common_1.log.debug(`Copying content to container...`, { containerId: this.container.id });
|
|
175
175
|
const client = await (0, container_runtime_1.getContainerRuntimeClient)();
|
|
176
|
-
const tar =
|
|
176
|
+
const tar = (0, archiver_1.default)("tar");
|
|
177
177
|
contentsToCopy.forEach(({ content, target, mode }) => tar.append(content, { name: target, mode: mode }));
|
|
178
178
|
tar.finalize();
|
|
179
179
|
await client.container.putArchive(this.container, tar, "/");
|
|
@@ -9,7 +9,7 @@ const reaper_1 = require("../reaper/reaper");
|
|
|
9
9
|
const labels_1 = require("../utils/labels");
|
|
10
10
|
exports.SSHD_IMAGE = process.env["SSHD_CONTAINER_IMAGE"]
|
|
11
11
|
? container_runtime_1.ImageName.fromString(process.env["SSHD_CONTAINER_IMAGE"]).string
|
|
12
|
-
: container_runtime_1.ImageName.fromString("testcontainers/sshd:1.
|
|
12
|
+
: container_runtime_1.ImageName.fromString("testcontainers/sshd:1.4.0").string;
|
|
13
13
|
class PortForwarder {
|
|
14
14
|
sshConnection;
|
|
15
15
|
containerId;
|
package/build/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const LIB_VERSION = "12.0.
|
|
1
|
+
export declare const LIB_VERSION = "12.0.4";
|
package/build/version.js
CHANGED
|
@@ -23,10 +23,10 @@ export declare class HttpWaitStrategy extends AbstractWaitStrategy {
|
|
|
23
23
|
[key: string]: string;
|
|
24
24
|
}): this;
|
|
25
25
|
withBasicCredentials(username: string, password: string): this;
|
|
26
|
-
withReadTimeout(
|
|
26
|
+
withReadTimeout(readTimeoutMs: number): this;
|
|
27
27
|
usingTls(): this;
|
|
28
28
|
allowInsecure(): this;
|
|
29
29
|
waitUntilReady(container: Dockerode.Container, boundPorts: BoundPorts): Promise<void>;
|
|
30
30
|
private handleContainerExit;
|
|
31
|
-
private
|
|
31
|
+
private createInsecureAgent;
|
|
32
32
|
}
|
|
@@ -47,8 +47,8 @@ class HttpWaitStrategy extends wait_strategy_1.AbstractWaitStrategy {
|
|
|
47
47
|
this.headers = { ...this.headers, Authorization: `Basic ${base64Encoded}` };
|
|
48
48
|
return this;
|
|
49
49
|
}
|
|
50
|
-
withReadTimeout(
|
|
51
|
-
this.readTimeoutMs =
|
|
50
|
+
withReadTimeout(readTimeoutMs) {
|
|
51
|
+
this.readTimeoutMs = readTimeoutMs;
|
|
52
52
|
return this;
|
|
53
53
|
}
|
|
54
54
|
usingTls() {
|
|
@@ -65,50 +65,60 @@ class HttpWaitStrategy extends wait_strategy_1.AbstractWaitStrategy {
|
|
|
65
65
|
let containerExited = false;
|
|
66
66
|
const client = await (0, container_runtime_1.getContainerRuntimeClient)();
|
|
67
67
|
const { abortOnContainerExit } = this.options;
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
68
|
+
// Scoped per invocation: one strategy instance can drive concurrent waits, so a shared
|
|
69
|
+
// agent would let one finished wait destroy a dispatcher another is still using.
|
|
70
|
+
const agent = this.createInsecureAgent();
|
|
71
|
+
try {
|
|
72
|
+
await new common_1.IntervalRetry(this.readTimeoutMs).retryUntil(async () => {
|
|
73
|
+
try {
|
|
74
|
+
const url = `${this.protocol}://${client.info.containerRuntime.host}:${boundPorts.getBinding(this.port)}${this.path}`;
|
|
75
|
+
if (abortOnContainerExit) {
|
|
76
|
+
const containerStatus = (await client.container.inspect(container)).State.Status;
|
|
77
|
+
if (containerStatus === exitStatus) {
|
|
78
|
+
containerExited = true;
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
76
81
|
}
|
|
82
|
+
return (0, undici_response_parser_1.undiciResponseToFetchResponse)(await (0, undici_1.request)(url, {
|
|
83
|
+
method: this.method,
|
|
84
|
+
signal: AbortSignal.timeout(this.readTimeoutMs),
|
|
85
|
+
headers: this.headers,
|
|
86
|
+
dispatcher: agent,
|
|
87
|
+
}));
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
return undefined;
|
|
91
|
+
}
|
|
92
|
+
}, async (response) => {
|
|
93
|
+
if (abortOnContainerExit && containerExited) {
|
|
94
|
+
return true;
|
|
95
|
+
}
|
|
96
|
+
if (response === undefined) {
|
|
97
|
+
return false;
|
|
77
98
|
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
}
|
|
88
|
-
}, async (response) => {
|
|
89
|
-
if (abortOnContainerExit && containerExited) {
|
|
90
|
-
return true;
|
|
91
|
-
}
|
|
92
|
-
if (response === undefined) {
|
|
93
|
-
return false;
|
|
94
|
-
}
|
|
95
|
-
else if (!this.predicates.length) {
|
|
96
|
-
return response.ok;
|
|
97
|
-
}
|
|
98
|
-
else {
|
|
99
|
-
for (const predicate of this.predicates) {
|
|
100
|
-
const result = await predicate(response);
|
|
101
|
-
if (!result) {
|
|
102
|
-
return false;
|
|
99
|
+
else if (!this.predicates.length) {
|
|
100
|
+
return response.ok;
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
for (const predicate of this.predicates) {
|
|
104
|
+
const result = await predicate(response);
|
|
105
|
+
if (!result) {
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
103
108
|
}
|
|
109
|
+
return true;
|
|
104
110
|
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
111
|
+
}, () => {
|
|
112
|
+
const message = `URL ${this.path} not accessible after ${this.startupTimeoutMs}ms`;
|
|
113
|
+
common_1.log.error(message, { containerId: container.id });
|
|
114
|
+
throw new Error(message);
|
|
115
|
+
}, this.startupTimeoutMs);
|
|
116
|
+
}
|
|
117
|
+
finally {
|
|
118
|
+
// Force-close: status-only predicates never read the body, so a graceful close() could
|
|
119
|
+
// hang waiting on unreleased connections. Nothing left to drain once the wait is done.
|
|
120
|
+
await agent?.destroy();
|
|
121
|
+
}
|
|
112
122
|
if (abortOnContainerExit && containerExited) {
|
|
113
123
|
return this.handleContainerExit(container);
|
|
114
124
|
}
|
|
@@ -132,14 +142,15 @@ class HttpWaitStrategy extends wait_strategy_1.AbstractWaitStrategy {
|
|
|
132
142
|
common_1.log.error(message, { containerId: container.id });
|
|
133
143
|
throw new Error(message);
|
|
134
144
|
}
|
|
135
|
-
|
|
136
|
-
if (this._allowInsecure) {
|
|
137
|
-
return
|
|
138
|
-
connect: {
|
|
139
|
-
rejectUnauthorized: false,
|
|
140
|
-
},
|
|
141
|
-
});
|
|
145
|
+
createInsecureAgent() {
|
|
146
|
+
if (!this._allowInsecure) {
|
|
147
|
+
return undefined;
|
|
142
148
|
}
|
|
149
|
+
return new undici_1.Agent({
|
|
150
|
+
connect: {
|
|
151
|
+
rejectUnauthorized: false,
|
|
152
|
+
},
|
|
153
|
+
});
|
|
143
154
|
}
|
|
144
155
|
}
|
|
145
156
|
exports.HttpWaitStrategy = HttpWaitStrategy;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "testcontainers",
|
|
3
|
-
"version": "12.0.
|
|
3
|
+
"version": "12.0.4",
|
|
4
4
|
"author": "Cristian Greco",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"keywords": [
|
|
@@ -32,22 +32,22 @@
|
|
|
32
32
|
"dependencies": {
|
|
33
33
|
"@balena/dockerignore": "^1.0.2",
|
|
34
34
|
"@types/dockerode": "^4.0.1",
|
|
35
|
-
"archiver": "^
|
|
35
|
+
"archiver": "^7.0.1",
|
|
36
36
|
"async-lock": "^1.4.1",
|
|
37
37
|
"byline": "^5.0.0",
|
|
38
38
|
"debug": "^4.4.3",
|
|
39
39
|
"docker-compose": "^1.4.2",
|
|
40
40
|
"dockerode": "^5.0.0",
|
|
41
|
-
"get-port": "^
|
|
41
|
+
"get-port": "^5.1.1",
|
|
42
42
|
"proper-lockfile": "^4.1.2",
|
|
43
43
|
"properties-reader": "^3.0.1",
|
|
44
44
|
"ssh-remote-port-forward": "^1.0.4",
|
|
45
45
|
"tar-fs": "^3.1.2",
|
|
46
46
|
"tmp": "^0.2.7",
|
|
47
|
-
"undici": "^8.
|
|
47
|
+
"undici": "^8.5.0"
|
|
48
48
|
},
|
|
49
49
|
"devDependencies": {
|
|
50
|
-
"@types/archiver": "^
|
|
50
|
+
"@types/archiver": "^7.0.0",
|
|
51
51
|
"@types/async-lock": "^1.4.2",
|
|
52
52
|
"@types/byline": "^4.2.36",
|
|
53
53
|
"@types/debug": "^4.1.13",
|