testcontainers 7.22.1 → 7.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +28 -0
- package/dist/docker/functions/container/exec-container.js +16 -12
- package/dist/docker/functions/image/build-image.js +1 -1
- package/dist/docker-compose/default-docker-compose-options.js +1 -0
- package/dist/docker-compose/docker-compose-options.d.ts +1 -0
- package/dist/docker-compose-environment/docker-compose-environment.d.ts +2 -0
- package/dist/docker-compose-environment/docker-compose-environment.js +12 -2
- package/dist/docker-ignore.d.ts +1 -1
- package/dist/docker-ignore.js +2 -1
- package/dist/generic-container/generic-container.d.ts +2 -1
- package/dist/generic-container/generic-container.js +9 -1
- package/dist/test-container.d.ts +2 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
[](https://github.com/testcontainers/testcontainers-node/actions/workflows/node.js.yml)
|
|
6
6
|
[](https://www.npmjs.com/package/testcontainers)
|
|
7
7
|
[](https://www.npmjs.com/package/testcontainers)
|
|
8
|
+
[](https://foresight.thundra.live/testRuns/57175ecb-d5ac-4129-957a-9dd617fd27d0)
|
|
9
|
+
[](https://foresight.thundra.live/testruns/57175ecb-d5ac-4129-957a-9dd617fd27d0)
|
|
8
10
|
|
|
9
11
|
## Install
|
|
10
12
|
|
|
@@ -276,6 +278,22 @@ const fooContainer = await new GenericContainer("alpine")
|
|
|
276
278
|
expect((await container.exec(["nslookup", "foo"])).exitCode).toBe(0);
|
|
277
279
|
```
|
|
278
280
|
|
|
281
|
+
Add hostname mappings:
|
|
282
|
+
|
|
283
|
+
```javascript
|
|
284
|
+
const { GenericContainer } = require("testcontainers");
|
|
285
|
+
|
|
286
|
+
const container = await new GenericContainer("alpine")
|
|
287
|
+
.withExtraHosts([
|
|
288
|
+
{ host: "foo", ipAddress: "10.11.12.13" },
|
|
289
|
+
{ host: "bar", ipAddress: "11.12.13.14" }
|
|
290
|
+
])
|
|
291
|
+
.start();
|
|
292
|
+
|
|
293
|
+
expect((await container.exec(["nslookup", "foo"])).exitCode).toBe(0);
|
|
294
|
+
expect((await container.exec(["nslookup", "bar"])).exitCode).toBe(0);
|
|
295
|
+
```
|
|
296
|
+
|
|
279
297
|
Specifying a pull policy. Note that if omitted will use the `DefaultPullPolicy` which will use a locally cached image
|
|
280
298
|
if one already exists, this is usually the preferred option. In cases where there is a local image for a given tag
|
|
281
299
|
but the remote image with the same tag may have changed (for example when using the `latest` tag), you can tell
|
|
@@ -523,6 +541,16 @@ const environment = await new DockerComposeEnvironment(composeFilePath, composeF
|
|
|
523
541
|
.up();
|
|
524
542
|
```
|
|
525
543
|
|
|
544
|
+
Specify [profiles](https://docs.docker.com/compose/profiles/):
|
|
545
|
+
|
|
546
|
+
```javascript
|
|
547
|
+
const { DockerComposeEnvironment } = require("testcontainers");
|
|
548
|
+
|
|
549
|
+
const environment = await new DockerComposeEnvironment(composeFilePath, composeFile)
|
|
550
|
+
.withProfiles("profile1", "profile2")
|
|
551
|
+
.up();
|
|
552
|
+
```
|
|
553
|
+
|
|
526
554
|
Specify not to re-create containers that are already running:
|
|
527
555
|
|
|
528
556
|
```javascript
|
|
@@ -19,18 +19,11 @@ const execContainer = (container, command) => __awaiter(void 0, void 0, void 0,
|
|
|
19
19
|
AttachStderr: true,
|
|
20
20
|
});
|
|
21
21
|
const stream = yield startExec(exec);
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
if (!running) {
|
|
28
|
-
clearInterval(interval);
|
|
29
|
-
stream.destroy();
|
|
30
|
-
resolve({ output: chunks.join(""), exitCode });
|
|
31
|
-
}
|
|
32
|
-
}), 100);
|
|
33
|
-
});
|
|
22
|
+
const chunks = [];
|
|
23
|
+
stream.on("data", (chunk) => chunks.push(chunk));
|
|
24
|
+
const exitCode = yield waitForExec(exec);
|
|
25
|
+
stream.destroy();
|
|
26
|
+
return { output: chunks.join(""), exitCode };
|
|
34
27
|
}
|
|
35
28
|
catch (err) {
|
|
36
29
|
logger_1.log.error(`Failed to exec container ${container.id} with command "${command.join(" ")}": ${err}`);
|
|
@@ -72,3 +65,14 @@ const inspectExec = (exec) => __awaiter(void 0, void 0, void 0, function* () {
|
|
|
72
65
|
throw err;
|
|
73
66
|
}
|
|
74
67
|
});
|
|
68
|
+
const waitForExec = (exec) => __awaiter(void 0, void 0, void 0, function* () {
|
|
69
|
+
return new Promise((resolve) => {
|
|
70
|
+
const interval = setInterval(() => __awaiter(void 0, void 0, void 0, function* () {
|
|
71
|
+
const { running, exitCode } = yield inspectExec(exec);
|
|
72
|
+
if (!running) {
|
|
73
|
+
clearInterval(interval);
|
|
74
|
+
resolve(exitCode);
|
|
75
|
+
}
|
|
76
|
+
}), 100);
|
|
77
|
+
});
|
|
78
|
+
});
|
|
@@ -23,7 +23,7 @@ const create_labels_1 = require("../create-labels");
|
|
|
23
23
|
const buildImage = (options) => __awaiter(void 0, void 0, void 0, function* () {
|
|
24
24
|
try {
|
|
25
25
|
logger_1.log.info(`Building image '${options.imageName.toString()}' with context '${options.context}'`);
|
|
26
|
-
const dockerIgnoreFiles = yield docker_ignore_1.findDockerIgnoreFiles(options.context);
|
|
26
|
+
const dockerIgnoreFiles = yield docker_ignore_1.findDockerIgnoreFiles(options.context, options.dockerfileName);
|
|
27
27
|
const tarStream = tar_fs_1.default.pack(options.context, { ignore: (name) => dockerIgnoreFiles.has(slash_1.default(name)) });
|
|
28
28
|
return new Promise((resolve) => dockerode_1.dockerode
|
|
29
29
|
.buildImage(tarStream, {
|
|
@@ -18,6 +18,7 @@ const defaultDockerComposeOptions = (_a) => {
|
|
|
18
18
|
log: false,
|
|
19
19
|
cwd: options.filePath,
|
|
20
20
|
config: options.files,
|
|
21
|
+
composeOptions: options.composeOptions,
|
|
21
22
|
commandOptions: options.commandOptions,
|
|
22
23
|
env: Object.assign(Object.assign(Object.assign({}, process.env), { COMPOSE_PROJECT_NAME: options.projectName }), env),
|
|
23
24
|
};
|
|
@@ -8,12 +8,14 @@ export declare class DockerComposeEnvironment {
|
|
|
8
8
|
private projectName;
|
|
9
9
|
private build;
|
|
10
10
|
private recreate;
|
|
11
|
+
private profiles;
|
|
11
12
|
private env;
|
|
12
13
|
private waitStrategy;
|
|
13
14
|
private startupTimeout;
|
|
14
15
|
constructor(composeFilePath: string, composeFiles: string | string[], uuid?: Uuid);
|
|
15
16
|
withBuild(): this;
|
|
16
17
|
withEnv(key: EnvKey, value: EnvValue): this;
|
|
18
|
+
withProfiles(...profiles: string[]): this;
|
|
17
19
|
withNoRecreate(): this;
|
|
18
20
|
withWaitStrategy(containerName: string, waitStrategy: WaitStrategy): this;
|
|
19
21
|
withStartupTimeout(startupTimeout: number): this;
|
|
@@ -30,6 +30,7 @@ class DockerComposeEnvironment {
|
|
|
30
30
|
constructor(composeFilePath, composeFiles, uuid = new uuid_1.RandomUuid()) {
|
|
31
31
|
this.build = false;
|
|
32
32
|
this.recreate = true;
|
|
33
|
+
this.profiles = [];
|
|
33
34
|
this.env = {};
|
|
34
35
|
this.waitStrategy = {};
|
|
35
36
|
this.startupTimeout = 60000;
|
|
@@ -45,6 +46,10 @@ class DockerComposeEnvironment {
|
|
|
45
46
|
this.env[key] = value;
|
|
46
47
|
return this;
|
|
47
48
|
}
|
|
49
|
+
withProfiles(...profiles) {
|
|
50
|
+
this.profiles = profiles;
|
|
51
|
+
return this;
|
|
52
|
+
}
|
|
48
53
|
withNoRecreate() {
|
|
49
54
|
this.recreate = false;
|
|
50
55
|
this.projectName = "testcontainers-node";
|
|
@@ -74,7 +79,12 @@ class DockerComposeEnvironment {
|
|
|
74
79
|
if (!this.recreate) {
|
|
75
80
|
commandOptions.push("--no-recreate");
|
|
76
81
|
}
|
|
77
|
-
|
|
82
|
+
const composeOptions = [];
|
|
83
|
+
this.profiles.forEach((profile) => {
|
|
84
|
+
composeOptions.push("--profile");
|
|
85
|
+
composeOptions.push(profile);
|
|
86
|
+
});
|
|
87
|
+
yield docker_compose_up_1.dockerComposeUp(Object.assign(Object.assign({}, options), { commandOptions, composeOptions, env: this.env }), services);
|
|
78
88
|
const startedContainers = (yield list_containers_1.listContainers()).filter((container) => container.Labels["com.docker.compose.project"] === this.projectName);
|
|
79
89
|
const startedContainerNames = startedContainers.reduce((containerNames, startedContainer) => [
|
|
80
90
|
...containerNames,
|
|
@@ -110,7 +120,7 @@ class DockerComposeEnvironment {
|
|
|
110
120
|
return Object.assign(Object.assign({}, map), { [containerName]: startedGenericContainer });
|
|
111
121
|
}, {});
|
|
112
122
|
logger_1.log.info(`DockerCompose environment started: ${Object.keys(startedGenericContainers).join(", ")}`);
|
|
113
|
-
return new started_docker_compose_environment_1.StartedDockerComposeEnvironment(startedGenericContainers, options);
|
|
123
|
+
return new started_docker_compose_environment_1.StartedDockerComposeEnvironment(startedGenericContainers, Object.assign(Object.assign({}, options), { composeOptions, env: this.env }));
|
|
114
124
|
});
|
|
115
125
|
}
|
|
116
126
|
getBoundPorts(containerInfo) {
|
package/dist/docker-ignore.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const findDockerIgnoreFiles: (context: string) => Promise<Set<string>>;
|
|
1
|
+
export declare const findDockerIgnoreFiles: (context: string, dockerfileName: string) => Promise<Set<string>>;
|
package/dist/docker-ignore.js
CHANGED
|
@@ -17,7 +17,7 @@ const fs_1 = require("fs");
|
|
|
17
17
|
const os_1 = __importDefault(require("os"));
|
|
18
18
|
const glob_1 = __importDefault(require("glob"));
|
|
19
19
|
const path_1 = __importDefault(require("path"));
|
|
20
|
-
const findDockerIgnoreFiles = (context) => __awaiter(void 0, void 0, void 0, function* () {
|
|
20
|
+
const findDockerIgnoreFiles = (context, dockerfileName) => __awaiter(void 0, void 0, void 0, function* () {
|
|
21
21
|
const dockerIgnoreFilePath = path_1.default.join(context, ".dockerignore");
|
|
22
22
|
if (!fs_1.existsSync(dockerIgnoreFilePath)) {
|
|
23
23
|
return new Set();
|
|
@@ -25,6 +25,7 @@ const findDockerIgnoreFiles = (context) => __awaiter(void 0, void 0, void 0, fun
|
|
|
25
25
|
const dockerIgnorePatterns = (yield fs_1.promises.readFile(dockerIgnoreFilePath, { encoding: "utf-8" }))
|
|
26
26
|
.toString()
|
|
27
27
|
.split(os_1.default.EOL)
|
|
28
|
+
.filter((dockerIgnorePattern) => dockerIgnorePattern !== dockerfileName)
|
|
28
29
|
.map((dockerIgnorePattern) => path_1.default.resolve(context, dockerIgnorePattern));
|
|
29
30
|
const dockerIgnoreMatches = (yield Promise.all(dockerIgnorePatterns.map(findIgnoredFilesForPattern))).reduce((prev, next) => [...prev, ...next]);
|
|
30
31
|
return new Set(dockerIgnoreMatches);
|
|
@@ -6,7 +6,7 @@ import { PullPolicy } from "../pull-policy";
|
|
|
6
6
|
import { StartedTestContainer, TestContainer } from "../test-container";
|
|
7
7
|
import { WaitStrategy } from "../wait-strategy";
|
|
8
8
|
import { Readable } from "stream";
|
|
9
|
-
import { BindMode, BindMount, BuildContext, Command, ContainerName, Dir, Env, EnvKey, EnvValue, HealthCheck, NetworkMode, TmpFs } from "../docker/types";
|
|
9
|
+
import { BindMode, BindMount, BuildContext, Command, ContainerName, Dir, Env, EnvKey, EnvValue, ExtraHost, HealthCheck, NetworkMode, TmpFs } from "../docker/types";
|
|
10
10
|
import { GenericContainerBuilder } from "./generic-container-builder";
|
|
11
11
|
export declare class GenericContainer implements TestContainer {
|
|
12
12
|
readonly image: string;
|
|
@@ -38,6 +38,7 @@ export declare class GenericContainer implements TestContainer {
|
|
|
38
38
|
withTmpFs(tmpFs: TmpFs): this;
|
|
39
39
|
withNetworkMode(networkMode: NetworkMode): this;
|
|
40
40
|
withNetworkAliases(...networkAliases: string[]): this;
|
|
41
|
+
withExtraHosts(...extraHosts: ExtraHost[]): this;
|
|
41
42
|
withExposedPorts(...ports: Port[]): this;
|
|
42
43
|
withBindMount(source: Dir, target: Dir, bindMode?: BindMode): this;
|
|
43
44
|
withHealthCheck(healthCheck: HealthCheck): this;
|
|
@@ -94,7 +94,11 @@ class GenericContainer {
|
|
|
94
94
|
const portForwarderNetworkId = portForwarder.getNetworkId();
|
|
95
95
|
const excludedNetworks = [portForwarderNetworkId, "none", "host"];
|
|
96
96
|
if (!this.networkMode || !excludedNetworks.includes(this.networkMode)) {
|
|
97
|
-
yield connect_network_1.connectNetwork({
|
|
97
|
+
yield connect_network_1.connectNetwork({
|
|
98
|
+
containerId: container.id,
|
|
99
|
+
networkId: portForwarderNetworkId,
|
|
100
|
+
networkAliases: [],
|
|
101
|
+
});
|
|
98
102
|
}
|
|
99
103
|
}
|
|
100
104
|
if (this.networkMode && this.networkAliases.length > 0) {
|
|
@@ -142,6 +146,10 @@ class GenericContainer {
|
|
|
142
146
|
this.networkAliases = networkAliases;
|
|
143
147
|
return this;
|
|
144
148
|
}
|
|
149
|
+
withExtraHosts(...extraHosts) {
|
|
150
|
+
this.extraHosts.push(...extraHosts);
|
|
151
|
+
return this;
|
|
152
|
+
}
|
|
145
153
|
withExposedPorts(...ports) {
|
|
146
154
|
this.ports = ports;
|
|
147
155
|
return this;
|
package/dist/test-container.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { Port } from "./port";
|
|
|
3
3
|
import { PullPolicy } from "./pull-policy";
|
|
4
4
|
import { WaitStrategy } from "./wait-strategy";
|
|
5
5
|
import { Readable } from "stream";
|
|
6
|
-
import { BindMode, Command, ContainerName, Dir, EnvKey, EnvValue, ExecResult, Host, Id, NetworkMode, TmpFs } from "./docker/types";
|
|
6
|
+
import { BindMode, Command, ContainerName, Dir, EnvKey, EnvValue, ExecResult, ExtraHost, Host, Id, NetworkMode, TmpFs } from "./docker/types";
|
|
7
7
|
export interface TestContainer {
|
|
8
8
|
start(): Promise<StartedTestContainer>;
|
|
9
9
|
withEnv(key: EnvKey, value: EnvValue): this;
|
|
@@ -14,6 +14,7 @@ export interface TestContainer {
|
|
|
14
14
|
withWaitStrategy(waitStrategy: WaitStrategy): this;
|
|
15
15
|
withStartupTimeout(startupTimeout: number): this;
|
|
16
16
|
withNetworkMode(networkMode: NetworkMode): this;
|
|
17
|
+
withExtraHosts(...extraHosts: ExtraHost[]): this;
|
|
17
18
|
withDefaultLogDriver(): this;
|
|
18
19
|
withPrivilegedMode(): this;
|
|
19
20
|
withUser(user: string): this;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "testcontainers",
|
|
3
3
|
"author": "Cristian Greco",
|
|
4
|
-
"version": "7.
|
|
4
|
+
"version": "7.24.0",
|
|
5
5
|
"main": "dist/index",
|
|
6
6
|
"types": "dist/index",
|
|
7
7
|
"keywords": [
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"pre-commit": "lint-staged",
|
|
27
27
|
"build": "npm run clean && tsc",
|
|
28
28
|
"clean": "rimraf dist",
|
|
29
|
-
"test": "cross-env DEBUG=testcontainers jest --
|
|
29
|
+
"test": "cross-env DEBUG=testcontainers jest --runInBand",
|
|
30
30
|
"format": "prettier --write package.json \"src/**/*.ts\"",
|
|
31
31
|
"lint": "eslint --fix package.json \"src/**/*.ts\"",
|
|
32
32
|
"updateDeps": "npx npm-check-updates -u"
|