testcontainers 8.14.0 → 8.16.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.
Files changed (27) hide show
  1. package/README.md +82 -2
  2. package/dist/docker/functions/container/create-container.d.ts +5 -1
  3. package/dist/docker/functions/container/create-container.js +14 -0
  4. package/dist/docker/functions/container/exec-container.d.ts +7 -1
  5. package/dist/docker/functions/container/exec-container.js +12 -13
  6. package/dist/docker/functions/image/build-image.d.ts +1 -0
  7. package/dist/docker/functions/image/build-image.js +14 -9
  8. package/dist/docker/types.d.ts +6 -0
  9. package/dist/docker-compose/functions/docker-compose-down.d.ts +2 -1
  10. package/dist/docker-compose/functions/docker-compose-down.js +12 -2
  11. package/dist/docker-compose/functions/docker-compose-up.js +1 -1
  12. package/dist/docker-compose-environment/docker-compose-environment.js +1 -1
  13. package/dist/docker-compose-environment/started-docker-compose-environment.d.ts +2 -1
  14. package/dist/docker-compose-environment/started-docker-compose-environment.js +3 -2
  15. package/dist/docker-compose-environment/stopped-docker-compose-environment.d.ts +2 -1
  16. package/dist/docker-compose-environment/stopped-docker-compose-environment.js +3 -2
  17. package/dist/generic-container/generic-container-builder.d.ts +2 -0
  18. package/dist/generic-container/generic-container-builder.js +6 -0
  19. package/dist/generic-container/generic-container.d.ts +9 -1
  20. package/dist/generic-container/generic-container.js +20 -0
  21. package/dist/generic-container/started-generic-container.d.ts +2 -2
  22. package/dist/generic-container/started-generic-container.js +4 -4
  23. package/dist/logger.d.ts +1 -0
  24. package/dist/logger.js +2 -1
  25. package/dist/port-check.js +1 -1
  26. package/dist/test-container.d.ts +15 -2
  27. package/package.json +1 -1
package/README.md CHANGED
@@ -5,8 +5,6 @@
5
5
  [![Node.js CI](https://github.com/testcontainers/testcontainers-node/actions/workflows/node.js.yml/badge.svg?branch=master)](https://github.com/testcontainers/testcontainers-node/actions/workflows/node.js.yml)
6
6
  [![npm version](https://badge.fury.io/js/testcontainers.svg)](https://www.npmjs.com/package/testcontainers)
7
7
  [![npm version](https://img.shields.io/npm/dm/testcontainers.svg)](https://www.npmjs.com/package/testcontainers)
8
- [![Thundra Foresight](https://thundra-assets-prod.s3.us-west-2.amazonaws.com/images/badges/thundra-foresight-badge-enabled.svg)](https://foresight.thundra.live/testRuns/57175ecb-d5ac-4129-957a-9dd617fd27d0)
9
- [![Foresight Test Summary](https://foresight.service.thundra.us/public/api/v1/badge/test/57175ecb-d5ac-4129-957a-9dd617fd27d0)](https://foresight.thundra.live/testruns/57175ecb-d5ac-4129-957a-9dd617fd27d0)
10
8
 
11
9
  ## Install
12
10
 
@@ -22,8 +20,11 @@ The following environment variables are supported:
22
20
 
23
21
  - `DEBUG=testcontainers` Enable testcontainers logs
24
22
  - `DEBUG=testcontainers:containers` Enable container logs
23
+ - `DEBUG=testcontainers:exec` Enable container exec logs
25
24
  - `DEBUG=testcontainers*` Enable all logs
26
25
 
26
+ Note that you can enable specific loggers, e.g: `DEBUG=testcontainers,testcontainers:exec`.
27
+
27
28
  ### Docker
28
29
 
29
30
  - `DOCKER_HOST=tcp://docker:2375` Sets the URL of the docker daemon
@@ -134,6 +135,16 @@ const container = await GenericContainer.fromDockerfile(buildContext, "my-docker
134
135
  .build();
135
136
  ```
136
137
 
138
+ Build the image without using the cache:
139
+
140
+ ```javascript
141
+ const { GenericContainer } = require("testcontainers");
142
+
143
+ const container = await GenericContainer.fromDockerfile(buildContext, "my-dockerfile")
144
+ .withCache(false)
145
+ .build();
146
+ ```
147
+
137
148
  Creating a container with multiple exposed ports:
138
149
 
139
150
  ```javascript
@@ -193,6 +204,16 @@ const container = await new GenericContainer("alpine")
193
204
  .start();
194
205
  ```
195
206
 
207
+ Creating a container with entrypoint:
208
+
209
+ ```javascript
210
+ const { GenericContainer } = require("testcontainers");
211
+
212
+ const container = await new GenericContainer("alpine")
213
+ .withEntrypoint(["cat"])
214
+ .start();
215
+ ```
216
+
196
217
  Execute commands inside a running container:
197
218
 
198
219
  ```javascript
@@ -242,6 +263,41 @@ const container = await new GenericContainer("postgres")
242
263
  .start();
243
264
  ```
244
265
 
266
+ Creating a container with ulimits:
267
+
268
+ ```javascript
269
+ const { GenericContainer } = require("testcontainers");
270
+
271
+ const container = await new GenericContainer("aline")
272
+ .withUlimits({
273
+ memlock: {
274
+ hard: -1,
275
+ soft: -1
276
+ }
277
+ })
278
+ .start();
279
+ ```
280
+
281
+ Creating a container with added [capabilities](https://man7.org/linux/man-pages/man7/capabilities.7.html):
282
+
283
+ ```javascript
284
+ const { GenericContainer } = require("testcontainers");
285
+
286
+ const container = await new GenericContainer("aline")
287
+ .withAddedCapabilities("NET_ADMIN", "IPC_LOCK")
288
+ .start();
289
+ ```
290
+
291
+ Creating a container with dropped [capabilities](https://man7.org/linux/man-pages/man7/capabilities.7.html):
292
+
293
+ ```javascript
294
+ const { GenericContainer } = require("testcontainers");
295
+
296
+ const container = await new GenericContainer("aline")
297
+ .withDroppedCapabilities("NET_ADMIN", "IPC_LOCK")
298
+ .start();
299
+ ```
300
+
245
301
  Copy a file to a container before it is started:
246
302
 
247
303
  ```javascript
@@ -666,6 +722,30 @@ const environment = await new DockerComposeEnvironment(composeFilePath, composeF
666
722
  .up();
667
723
  ```
668
724
 
725
+ Testcontainers will not wait for an environment to down, to override:
726
+
727
+ ```javascript
728
+ const { GenericContainer } = require("testcontainers");
729
+
730
+ const environment = await new DockerComposeEnvironment(composeFilePath, composeFile).up();
731
+
732
+ await environment.down({
733
+ timeout: 10000
734
+ });
735
+ ```
736
+
737
+ Testcontainers will remove associated volumes created by the environment when downed, to override:
738
+
739
+ ```javascript
740
+ const { GenericContainer } = require("testcontainers");
741
+
742
+ const environment = await new DockerComposeEnvironment(composeFilePath, composeFile).up();
743
+
744
+ await environment.down({
745
+ removeVolumes: false
746
+ });
747
+ ```
748
+
669
749
  ## Wait Strategies
670
750
 
671
751
  Ordinarily Testcontainers will wait for up to 60 seconds for the container's mapped network ports to start listening.
@@ -1,11 +1,12 @@
1
1
  import { DockerImageName } from "../../../docker-image-name";
2
2
  import Dockerode from "dockerode";
3
3
  import { PortWithOptionalBinding } from "../../../port";
4
- import { BindMount, Command, ContainerName, Env, ExtraHost, HealthCheck, Labels, NetworkMode, TmpFs } from "../../types";
4
+ import { BindMount, Command, ContainerName, Env, ExtraHost, HealthCheck, Labels, NetworkMode, TmpFs, Ulimits } from "../../types";
5
5
  export declare type CreateContainerOptions = {
6
6
  imageName: DockerImageName;
7
7
  env: Env;
8
8
  cmd: Command[];
9
+ entrypoint?: string[];
9
10
  bindMounts: BindMount[];
10
11
  tmpFs: TmpFs;
11
12
  exposedPorts: PortWithOptionalBinding[];
@@ -19,6 +20,9 @@ export declare type CreateContainerOptions = {
19
20
  autoRemove: boolean;
20
21
  extraHosts: ExtraHost[];
21
22
  ipcMode?: string;
23
+ ulimits?: Ulimits;
24
+ addedCapabilities?: string[];
25
+ droppedCapabilities?: string[];
22
26
  user?: string;
23
27
  };
24
28
  export declare const createContainer: (options: CreateContainerOptions) => Promise<Dockerode.Container>;
@@ -25,6 +25,7 @@ const createContainer = (options) => __awaiter(void 0, void 0, void 0, function*
25
25
  Env: getEnv(options.env),
26
26
  ExposedPorts: getExposedPorts(options.exposedPorts),
27
27
  Cmd: options.cmd,
28
+ Entrypoint: options.entrypoint,
28
29
  Labels: (0, create_labels_1.createLabels)(options.reusable, options.imageName, options.labels),
29
30
  // @ts-ignore
30
31
  Healthcheck: getHealthCheck(options.healthCheck),
@@ -38,6 +39,9 @@ const createContainer = (options) => __awaiter(void 0, void 0, void 0, function*
38
39
  Tmpfs: options.tmpFs,
39
40
  LogConfig: getLogConfig(options.useDefaultLogDriver),
40
41
  Privileged: options.privilegedMode,
42
+ Ulimits: getUlimits(options.ulimits),
43
+ CapAdd: options.addedCapabilities,
44
+ CapDrop: options.droppedCapabilities,
41
45
  },
42
46
  });
43
47
  }
@@ -95,3 +99,13 @@ const getLogConfig = (useDefaultLogDriver) => {
95
99
  Config: {},
96
100
  };
97
101
  };
102
+ const getUlimits = (ulimits) => {
103
+ if (!ulimits) {
104
+ return undefined;
105
+ }
106
+ return Object.entries(ulimits).map(([key, value]) => ({
107
+ Name: key,
108
+ Hard: value.hard,
109
+ Soft: value.soft,
110
+ }));
111
+ };
@@ -1,3 +1,9 @@
1
1
  import { Command, ExecResult } from "../../types";
2
2
  import Dockerode from "dockerode";
3
- export declare const execContainer: (container: Dockerode.Container, command: Command[]) => Promise<ExecResult>;
3
+ declare type ExecContainerOptions = {
4
+ tty: boolean;
5
+ stdin: boolean;
6
+ detach: boolean;
7
+ };
8
+ export declare const execContainer: (container: Dockerode.Container, command: Command[], options: ExecContainerOptions, shouldLog?: boolean) => Promise<ExecResult>;
9
+ export {};
@@ -8,39 +8,38 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
8
8
  step((generator = generator.apply(thisArg, _arguments || [])).next());
9
9
  });
10
10
  };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
11
14
  Object.defineProperty(exports, "__esModule", { value: true });
12
15
  exports.execContainer = void 0;
13
16
  const logger_1 = require("../../../logger");
14
- const execContainer = (container, command) => __awaiter(void 0, void 0, void 0, function* () {
17
+ const byline_1 = __importDefault(require("byline"));
18
+ const execContainer = (container, command, options, shouldLog = true) => __awaiter(void 0, void 0, void 0, function* () {
19
+ const chunks = [];
15
20
  try {
16
21
  const exec = yield container.exec({
17
22
  Cmd: command,
18
23
  AttachStdout: true,
19
24
  AttachStderr: true,
20
25
  });
21
- const stream = yield startExec(exec);
22
- const chunks = [];
26
+ const stream = yield startExec(exec, options);
23
27
  stream.on("data", (chunk) => chunks.push(chunk));
28
+ if (shouldLog) {
29
+ (0, byline_1.default)(stream).on("data", (line) => logger_1.execLog.trace(`${container.id}: ${line}`));
30
+ }
24
31
  const exitCode = yield waitForExec(exec);
25
32
  stream.destroy();
26
33
  return { output: chunks.join(""), exitCode };
27
34
  }
28
35
  catch (err) {
29
- logger_1.log.error(`Failed to exec container ${container.id} with command "${command.join(" ")}": ${err}`);
36
+ logger_1.log.error(`Failed to exec container ${container.id} with command "${command.join(" ")}": ${err}. Container output: ${chunks.join("")}`);
30
37
  throw err;
31
38
  }
32
39
  });
33
40
  exports.execContainer = execContainer;
34
- const startExec = (exec) => __awaiter(void 0, void 0, void 0, function* () {
41
+ const startExec = (exec, options) => __awaiter(void 0, void 0, void 0, function* () {
35
42
  try {
36
- const options = {
37
- Detach: false,
38
- Tty: true,
39
- stream: true,
40
- stdin: true,
41
- stdout: true,
42
- stderr: true,
43
- };
44
43
  const stream = yield exec.start(options);
45
44
  stream.setEncoding("utf-8");
46
45
  return stream;
@@ -8,5 +8,6 @@ export declare type BuildImageOptions = {
8
8
  buildArgs: BuildArgs;
9
9
  pullPolicy: PullPolicy;
10
10
  registryConfig: RegistryConfig;
11
+ cache: boolean;
11
12
  };
12
13
  export declare const buildImage: (options: BuildImageOptions) => Promise<void>;
@@ -37,21 +37,26 @@ const buildImage = (options) => __awaiter(void 0, void 0, void 0, function* () {
37
37
  },
38
38
  });
39
39
  const { dockerode } = yield (0, docker_client_1.dockerClient)();
40
- return new Promise((resolve) => dockerode
41
- .buildImage(tarStream, {
40
+ const buildImageOptions = {
42
41
  dockerfile: options.dockerfileName,
42
+ // @ts-ignore
43
+ nocache: !options.cache,
43
44
  buildargs: options.buildArgs,
44
45
  t: options.imageName.toString(),
45
46
  labels: (0, create_labels_1.createLabels)(false, options.imageName),
46
47
  registryconfig: options.registryConfig,
47
48
  pull: options.pullPolicy.shouldPull() ? "any" : undefined,
48
- })
49
- .then((stream) => (0, byline_1.default)(stream))
50
- .then((stream) => {
51
- stream.setEncoding("utf-8");
52
- stream.on("data", (line) => logger_1.log.trace(`${options.imageName.toString()}: ${line}`));
53
- stream.on("end", () => resolve());
54
- }));
49
+ };
50
+ return new Promise((resolve) => {
51
+ dockerode
52
+ .buildImage(tarStream, buildImageOptions)
53
+ .then((stream) => (0, byline_1.default)(stream))
54
+ .then((stream) => {
55
+ stream.setEncoding("utf-8");
56
+ stream.on("data", (line) => logger_1.log.trace(`${options.imageName.toString()}: ${line}`));
57
+ stream.on("end", () => resolve());
58
+ });
59
+ });
55
60
  }
56
61
  catch (err) {
57
62
  logger_1.log.error(`Failed to build image: ${err}`);
@@ -15,6 +15,12 @@ export declare type BindMount = {
15
15
  export declare type TmpFs = {
16
16
  [dir in Dir]: Dir;
17
17
  };
18
+ export declare type Ulimits = {
19
+ [name: string]: {
20
+ hard: number | undefined;
21
+ soft: number | undefined;
22
+ };
23
+ };
18
24
  export declare type HealthCheck = {
19
25
  test: string;
20
26
  interval?: number;
@@ -1,2 +1,3 @@
1
1
  import { DockerComposeOptions } from "../docker-compose-options";
2
- export declare const dockerComposeDown: (options: DockerComposeOptions) => Promise<void>;
2
+ import { DockerComposeDownOptions } from "../../test-container";
3
+ export declare const dockerComposeDown: (options: DockerComposeOptions, downOptions: DockerComposeDownOptions) => Promise<void>;
@@ -13,10 +13,10 @@ exports.dockerComposeDown = void 0;
13
13
  const logger_1 = require("../../logger");
14
14
  const default_docker_compose_options_1 = require("../default-docker-compose-options");
15
15
  const docker_compose_1 = require("../docker-compose");
16
- const dockerComposeDown = (options) => __awaiter(void 0, void 0, void 0, function* () {
16
+ const dockerComposeDown = (options, downOptions) => __awaiter(void 0, void 0, void 0, function* () {
17
17
  logger_1.log.info(`Downing DockerCompose environment`);
18
18
  try {
19
- yield (0, docker_compose_1.down)(Object.assign(Object.assign({}, (0, default_docker_compose_options_1.defaultDockerComposeOptions)(options)), { commandOptions: ["-v"] }));
19
+ yield (0, docker_compose_1.down)(Object.assign(Object.assign({}, (0, default_docker_compose_options_1.defaultDockerComposeOptions)(options)), { commandOptions: commandOptions(downOptions) }));
20
20
  logger_1.log.info(`Downed DockerCompose environment`);
21
21
  }
22
22
  catch (err) {
@@ -26,3 +26,13 @@ const dockerComposeDown = (options) => __awaiter(void 0, void 0, void 0, functio
26
26
  }
27
27
  });
28
28
  exports.dockerComposeDown = dockerComposeDown;
29
+ const commandOptions = (options) => {
30
+ const result = [];
31
+ if (options.removeVolumes) {
32
+ result.push("-v");
33
+ }
34
+ if (options.timeout) {
35
+ result.push("-t", `${options.timeout / 1000}`);
36
+ }
37
+ return result;
38
+ };
@@ -29,7 +29,7 @@ const dockerComposeUp = (options, services) => __awaiter(void 0, void 0, void 0,
29
29
  const errorMessage = err.err || err.message || err;
30
30
  logger_1.log.error(`Failed to up DockerCompose environment: ${errorMessage}`);
31
31
  try {
32
- yield (0, docker_compose_down_1.dockerComposeDown)(options);
32
+ yield (0, docker_compose_down_1.dockerComposeDown)(options, { removeVolumes: true, timeout: 0 });
33
33
  }
34
34
  catch (_a) {
35
35
  logger_1.log.warn(`Failed to down DockerCompose environment after failed up`);
@@ -112,7 +112,7 @@ class DockerComposeEnvironment {
112
112
  catch (err) {
113
113
  logger_1.log.error(`Container ${containerName} failed to be ready: ${err}`);
114
114
  try {
115
- yield (0, docker_compose_down_1.dockerComposeDown)(options);
115
+ yield (0, docker_compose_down_1.dockerComposeDown)(options, { removeVolumes: true, timeout: 0 });
116
116
  }
117
117
  catch (_a) {
118
118
  logger_1.log.warn(`Failed to stop DockerCompose environment after failed up`);
@@ -2,6 +2,7 @@ import { StartedGenericContainer } from "../generic-container/started-generic-co
2
2
  import { StoppedDockerComposeEnvironment } from "./stopped-docker-compose-environment";
3
3
  import { DownedDockerComposeEnvironment } from "./downed-docker-compose-environment";
4
4
  import { DockerComposeOptions } from "../docker-compose/docker-compose-options";
5
+ import { DockerComposeDownOptions } from "../test-container";
5
6
  export declare class StartedDockerComposeEnvironment {
6
7
  private readonly startedGenericContainers;
7
8
  private readonly options;
@@ -9,6 +10,6 @@ export declare class StartedDockerComposeEnvironment {
9
10
  [containerName: string]: StartedGenericContainer;
10
11
  }, options: DockerComposeOptions);
11
12
  stop(): Promise<StoppedDockerComposeEnvironment>;
12
- down(): Promise<DownedDockerComposeEnvironment>;
13
+ down(options?: Partial<DockerComposeDownOptions>): Promise<DownedDockerComposeEnvironment>;
13
14
  getContainer(containerName: string): StartedGenericContainer;
14
15
  }
@@ -26,9 +26,10 @@ class StartedDockerComposeEnvironment {
26
26
  return new stopped_docker_compose_environment_1.StoppedDockerComposeEnvironment(this.options);
27
27
  });
28
28
  }
29
- down() {
29
+ down(options = {}) {
30
30
  return __awaiter(this, void 0, void 0, function* () {
31
- yield (0, docker_compose_down_1.dockerComposeDown)(this.options);
31
+ const downOptions = Object.assign({ timeout: 0, removeVolumes: true }, options);
32
+ yield (0, docker_compose_down_1.dockerComposeDown)(this.options, downOptions);
32
33
  return new downed_docker_compose_environment_1.DownedDockerComposeEnvironment();
33
34
  });
34
35
  }
@@ -1,7 +1,8 @@
1
1
  import { DownedDockerComposeEnvironment } from "./downed-docker-compose-environment";
2
2
  import { DockerComposeOptions } from "../docker-compose/docker-compose-options";
3
+ import { DockerComposeDownOptions } from "../test-container";
3
4
  export declare class StoppedDockerComposeEnvironment {
4
5
  private readonly options;
5
6
  constructor(options: DockerComposeOptions);
6
- down(): Promise<DownedDockerComposeEnvironment>;
7
+ down(options?: Partial<DockerComposeDownOptions>): Promise<DownedDockerComposeEnvironment>;
7
8
  }
@@ -16,9 +16,10 @@ class StoppedDockerComposeEnvironment {
16
16
  constructor(options) {
17
17
  this.options = options;
18
18
  }
19
- down() {
19
+ down(options = {}) {
20
20
  return __awaiter(this, void 0, void 0, function* () {
21
- yield (0, docker_compose_down_1.dockerComposeDown)(this.options);
21
+ const resolvedOptions = Object.assign({ timeout: 0, removeVolumes: true }, options);
22
+ yield (0, docker_compose_down_1.dockerComposeDown)(this.options, resolvedOptions);
22
23
  return new downed_docker_compose_environment_1.DownedDockerComposeEnvironment();
23
24
  });
24
25
  }
@@ -8,9 +8,11 @@ export declare class GenericContainerBuilder {
8
8
  private readonly uuid;
9
9
  private buildArgs;
10
10
  private pullPolicy;
11
+ private cache;
11
12
  constructor(context: BuildContext, dockerfileName: string, uuid?: Uuid);
12
13
  withBuildArg(key: string, value: string): GenericContainerBuilder;
13
14
  withPullPolicy(pullPolicy: PullPolicy): this;
15
+ withCache(cache: boolean): this;
14
16
  build(image?: string): Promise<GenericContainer>;
15
17
  private getRegistryConfig;
16
18
  }
@@ -32,6 +32,7 @@ class GenericContainerBuilder {
32
32
  this.uuid = uuid;
33
33
  this.buildArgs = {};
34
34
  this.pullPolicy = new pull_policy_1.DefaultPullPolicy();
35
+ this.cache = true;
35
36
  }
36
37
  withBuildArg(key, value) {
37
38
  this.buildArgs[key] = value;
@@ -41,6 +42,10 @@ class GenericContainerBuilder {
41
42
  this.pullPolicy = pullPolicy;
42
43
  return this;
43
44
  }
45
+ withCache(cache) {
46
+ this.cache = cache;
47
+ return this;
48
+ }
44
49
  build(image = `${this.uuid.nextUuid()}:${this.uuid.nextUuid()}`) {
45
50
  return __awaiter(this, void 0, void 0, function* () {
46
51
  const imageName = docker_image_name_1.DockerImageName.fromString(image);
@@ -55,6 +60,7 @@ class GenericContainerBuilder {
55
60
  dockerfileName: this.dockerfileName,
56
61
  buildArgs: this.buildArgs,
57
62
  pullPolicy: this.pullPolicy,
63
+ cache: this.cache,
58
64
  registryConfig,
59
65
  });
60
66
  const container = new generic_container_1.GenericContainer(imageName.toString());
@@ -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, ExtraHost, HealthCheck, NetworkMode, TmpFs, Labels } from "../docker/types";
9
+ import { BindMode, BindMount, BuildContext, Command, ContainerName, Dir, Env, EnvKey, EnvValue, ExtraHost, HealthCheck, NetworkMode, TmpFs, Labels, Ulimits } from "../docker/types";
10
10
  import { InspectResult } from "../docker/functions/container/inspect-container";
11
11
  import { GenericContainerBuilder } from "./generic-container-builder";
12
12
  export declare class GenericContainer implements TestContainer {
@@ -18,6 +18,7 @@ export declare class GenericContainer implements TestContainer {
18
18
  protected networkAliases: string[];
19
19
  protected ports: PortWithOptionalBinding[];
20
20
  protected cmd: Command[];
21
+ protected entrypoint?: string[];
21
22
  protected bindMounts: BindMount[];
22
23
  protected name?: ContainerName;
23
24
  protected labels: Labels;
@@ -28,6 +29,9 @@ export declare class GenericContainer implements TestContainer {
28
29
  protected useDefaultLogDriver: boolean;
29
30
  protected privilegedMode: boolean;
30
31
  protected ipcMode?: string;
32
+ protected ulimits?: Ulimits;
33
+ protected addedCapabilities?: string[];
34
+ protected droppedCapabilities?: string[];
31
35
  protected user?: string;
32
36
  protected pullPolicy: PullPolicy;
33
37
  protected reuse: boolean;
@@ -41,10 +45,14 @@ export declare class GenericContainer implements TestContainer {
41
45
  protected postStart?(container: StartedTestContainer, inspectResult: InspectResult, boundPorts: BoundPorts): Promise<void>;
42
46
  protected get hasExposedPorts(): boolean;
43
47
  withCmd(cmd: Command[]): this;
48
+ withEntrypoint(entrypoint: string[]): this;
44
49
  withName(name: ContainerName): this;
45
50
  withLabels(labels: Labels): this;
46
51
  withEnv(key: EnvKey, value: EnvValue): this;
47
52
  withTmpFs(tmpFs: TmpFs): this;
53
+ withUlimits(ulimits: Ulimits): this;
54
+ withAddedCapabilities(...capabilities: string[]): this;
55
+ withDroppedCapabilities(...capabilities: string[]): this;
48
56
  withNetworkMode(networkMode: NetworkMode): this;
49
57
  withNetworkAliases(...networkAliases: string[]): this;
50
58
  withExtraHosts(...extraHosts: ExtraHost[]): this;
@@ -80,6 +80,7 @@ class GenericContainer {
80
80
  imageName: this.imageName,
81
81
  env: this.env,
82
82
  cmd: this.cmd,
83
+ entrypoint: this.entrypoint,
83
84
  bindMounts: this.bindMounts,
84
85
  tmpFs: this.tmpFs,
85
86
  exposedPorts: this.ports,
@@ -93,6 +94,9 @@ class GenericContainer {
93
94
  autoRemove: this.imageName.isReaper(),
94
95
  extraHosts: this.extraHosts,
95
96
  ipcMode: this.ipcMode,
97
+ ulimits: this.ulimits,
98
+ addedCapabilities: this.addedCapabilities,
99
+ droppedCapabilities: this.droppedCapabilities,
96
100
  user: this.user,
97
101
  };
98
102
  if (this.reuse) {
@@ -170,6 +174,10 @@ class GenericContainer {
170
174
  this.cmd = cmd;
171
175
  return this;
172
176
  }
177
+ withEntrypoint(entrypoint) {
178
+ this.entrypoint = entrypoint;
179
+ return this;
180
+ }
173
181
  withName(name) {
174
182
  this.name = name;
175
183
  return this;
@@ -186,6 +194,18 @@ class GenericContainer {
186
194
  this.tmpFs = tmpFs;
187
195
  return this;
188
196
  }
197
+ withUlimits(ulimits) {
198
+ this.ulimits = ulimits;
199
+ return this;
200
+ }
201
+ withAddedCapabilities(...capabilities) {
202
+ this.addedCapabilities = capabilities;
203
+ return this;
204
+ }
205
+ withDroppedCapabilities(...capabilities) {
206
+ this.droppedCapabilities = capabilities;
207
+ return this;
208
+ }
189
209
  withNetworkMode(networkMode) {
190
210
  this.networkMode = networkMode;
191
211
  return this;
@@ -1,5 +1,5 @@
1
1
  /// <reference types="node" />
2
- import { RestartOptions, StartedTestContainer, StopOptions, StoppedTestContainer } from "../test-container";
2
+ import { RestartOptions, StartedTestContainer, StopOptions, ExecOptions, StoppedTestContainer } from "../test-container";
3
3
  import Dockerode from "dockerode";
4
4
  import { Command, ContainerName, ExecResult, Host, Id as ContainerId, Labels } from "../docker/types";
5
5
  import { InspectResult } from "../docker/functions/container/inspect-container";
@@ -27,6 +27,6 @@ export declare class StartedGenericContainer implements StartedTestContainer {
27
27
  getNetworkNames(): string[];
28
28
  getNetworkId(networkName: string): string;
29
29
  getIpAddress(networkName: string): string;
30
- exec(command: Command[]): Promise<ExecResult>;
30
+ exec(command: Command[], options?: Partial<ExecOptions>): Promise<ExecResult>;
31
31
  logs(): Promise<Readable>;
32
32
  }
@@ -37,9 +37,8 @@ class StartedGenericContainer {
37
37
  return __awaiter(this, void 0, void 0, function* () {
38
38
  const resolvedOptions = Object.assign({ timeout: 0 }, options);
39
39
  yield (0, restart_container_1.restartContainer)(this.container, resolvedOptions);
40
- // Inspect the restarted container and update the bound ports
41
40
  this.inspectResult = yield (0, inspect_container_1.inspectContainer)(this.container);
42
- this.boundPorts = yield bound_ports_1.BoundPorts.fromInspectResult(this.inspectResult).filter(Array.from(this.boundPorts.iterator()).map((port) => port[0]));
41
+ this.boundPorts = bound_ports_1.BoundPorts.fromInspectResult(this.inspectResult).filter(Array.from(this.boundPorts.iterator()).map((port) => port[0]));
43
42
  yield this.waitForContainer(this.container, this.boundPorts);
44
43
  });
45
44
  }
@@ -96,8 +95,9 @@ class StartedGenericContainer {
96
95
  getIpAddress(networkName) {
97
96
  return this.inspectResult.networkSettings[networkName].ipAddress;
98
97
  }
99
- exec(command) {
100
- return (0, exec_container_1.execContainer)(this.container, command);
98
+ exec(command, options = {}) {
99
+ const resolvedOptions = Object.assign({ stdin: true, detach: false, tty: true }, options);
100
+ return (0, exec_container_1.execContainer)(this.container, command, resolvedOptions);
101
101
  }
102
102
  logs() {
103
103
  return (0, container_logs_1.containerLogs)(this.container);
package/dist/logger.d.ts CHANGED
@@ -29,4 +29,5 @@ export declare class FakeLogger implements Logger {
29
29
  }
30
30
  export declare const log: DebugLogger;
31
31
  export declare const containerLog: DebugLogger;
32
+ export declare const execLog: DebugLogger;
32
33
  export {};
package/dist/logger.js CHANGED
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.containerLog = exports.log = exports.FakeLogger = void 0;
6
+ exports.execLog = exports.containerLog = exports.log = exports.FakeLogger = void 0;
7
7
  const debug_1 = __importDefault(require("debug"));
8
8
  class DebugLogger {
9
9
  constructor(namespace) {
@@ -52,3 +52,4 @@ class FakeLogger {
52
52
  exports.FakeLogger = FakeLogger;
53
53
  exports.log = new DebugLogger("testcontainers");
54
54
  exports.containerLog = new DebugLogger("testcontainers:containers");
55
+ exports.execLog = new DebugLogger("testcontainers:exec");
@@ -52,7 +52,7 @@ class InternalPortCheck {
52
52
  ["/bin/sh", "-c", `nc -vz -w 1 localhost ${port}`],
53
53
  ["/bin/bash", "-c", `</dev/tcp/localhost/${port}`],
54
54
  ];
55
- const commandResults = yield Promise.all(commands.map((command) => (0, exec_container_1.execContainer)(this.container, command)));
55
+ const commandResults = yield Promise.all(commands.map((command) => (0, exec_container_1.execContainer)(this.container, command, { stdin: true, detach: false, tty: true }, false)));
56
56
  const isBound = commandResults.some((result) => result.exitCode === 0);
57
57
  if (!isBound) {
58
58
  const shellExists = commandResults.some((result) => result.exitCode !== 126);
@@ -3,12 +3,16 @@ import { Port, PortWithOptionalBinding } 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, ExtraHost, Host, Id, NetworkMode, TmpFs, Labels } from "./docker/types";
6
+ import { BindMode, Command, ContainerName, Dir, EnvKey, EnvValue, ExecResult, ExtraHost, Host, Id, NetworkMode, TmpFs, Labels, Ulimits } from "./docker/types";
7
7
  export interface TestContainer {
8
8
  start(): Promise<StartedTestContainer>;
9
9
  withEnv(key: EnvKey, value: EnvValue): this;
10
10
  withCmd(cmd: Command[]): this;
11
+ withEntrypoint(entrypoint: string[]): this;
11
12
  withTmpFs(tmpFs: TmpFs): this;
13
+ withUlimits(ulimits: Ulimits): this;
14
+ withAddedCapabilities(...capabilities: string[]): this;
15
+ withDroppedCapabilities(...capabilities: string[]): this;
12
16
  withExposedPorts(...ports: PortWithOptionalBinding[]): this;
13
17
  withBindMount(source: Dir, target: Dir, bindMode: BindMode): this;
14
18
  withWaitStrategy(waitStrategy: WaitStrategy): this;
@@ -30,6 +34,15 @@ export interface StopOptions {
30
34
  timeout: number;
31
35
  removeVolumes: boolean;
32
36
  }
37
+ export interface DockerComposeDownOptions {
38
+ timeout: number;
39
+ removeVolumes: boolean;
40
+ }
41
+ export interface ExecOptions {
42
+ tty: boolean;
43
+ detach: boolean;
44
+ stdin: boolean;
45
+ }
33
46
  export interface StartedTestContainer {
34
47
  stop(options?: Partial<StopOptions>): Promise<StoppedTestContainer>;
35
48
  restart(options?: Partial<RestartOptions>): Promise<void>;
@@ -41,7 +54,7 @@ export interface StartedTestContainer {
41
54
  getNetworkNames(): string[];
42
55
  getNetworkId(networkName: string): string;
43
56
  getIpAddress(networkName: string): string;
44
- exec(command: Command[]): Promise<ExecResult>;
57
+ exec(command: Command[], options?: Partial<ExecOptions>): Promise<ExecResult>;
45
58
  logs(): Promise<Readable>;
46
59
  }
47
60
  export interface StoppedTestContainer {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "testcontainers",
3
3
  "author": "Cristian Greco",
4
- "version": "8.14.0",
4
+ "version": "8.16.0",
5
5
  "main": "dist/index",
6
6
  "types": "dist/index",
7
7
  "keywords": [