testcontainers 8.13.1 → 8.14.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.
@@ -35,7 +35,7 @@ const getDockerClient = () => __awaiter(void 0, void 0, void 0, function* () {
35
35
  if (yield isDockerDaemonReachable(dockerode)) {
36
36
  const host = yield resolveHost(dockerode, uri);
37
37
  logger_1.log.info(`Using Docker client strategy: ${strategy.getName()}, Docker host: ${host}`);
38
- (0, log_system_diagnostics_1.logSystemDiagnostics)();
38
+ (0, log_system_diagnostics_1.logSystemDiagnostics)(dockerode);
39
39
  return { host, dockerode };
40
40
  }
41
41
  else {
@@ -148,10 +148,14 @@ const resolveHost = (dockerode, uri) => __awaiter(void 0, void 0, void 0, functi
148
148
  });
149
149
  const findGateway = (dockerode) => __awaiter(void 0, void 0, void 0, function* () {
150
150
  var _a, _b, _c;
151
+ logger_1.log.debug(`Checking gateway for Docker host`);
151
152
  const inspectResult = yield dockerode.getNetwork("bridge").inspect();
152
153
  return (_c = (_b = (_a = inspectResult === null || inspectResult === void 0 ? void 0 : inspectResult.IPAM) === null || _a === void 0 ? void 0 : _a.Config) === null || _b === void 0 ? void 0 : _b.find((config) => config.Gateway !== undefined)) === null || _c === void 0 ? void 0 : _c.Gateway;
153
154
  });
154
- const findDefaultGateway = (dockerode) => __awaiter(void 0, void 0, void 0, function* () { return (0, run_in_container_1.runInContainer)(dockerode, "alpine:3.14", ["sh", "-c", "ip route|awk '/default/ { print $3 }'"]); });
155
+ const findDefaultGateway = (dockerode) => __awaiter(void 0, void 0, void 0, function* () {
156
+ logger_1.log.debug(`Checking default gateway for Docker host`);
157
+ return (0, run_in_container_1.runInContainer)(dockerode, "alpine:3.14", ["sh", "-c", "ip route|awk '/default/ { print $3 }'"]);
158
+ });
155
159
  const isInContainer = () => (0, fs_1.existsSync)("/.dockerenv");
156
160
  let _dockerClient;
157
161
  const dockerClient = () => {
@@ -1,3 +1,3 @@
1
1
  import { Readable } from "stream";
2
2
  import Dockerode from "dockerode";
3
- export declare const attachContainer: (container: Dockerode.Container) => Promise<Readable>;
3
+ export declare const attachContainer: (dockerode: Dockerode, container: Dockerode.Container) => Promise<Readable>;
@@ -12,10 +12,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.attachContainer = void 0;
13
13
  const demux_stream_1 = require("../demux-stream");
14
14
  const logger_1 = require("../../../logger");
15
- const attachContainer = (container) => __awaiter(void 0, void 0, void 0, function* () {
15
+ const attachContainer = (dockerode, container) => __awaiter(void 0, void 0, void 0, function* () {
16
16
  try {
17
17
  const stream = (yield container.attach({ stream: true, stdout: true, stderr: true }));
18
- return (0, demux_stream_1.demuxStream)(stream);
18
+ return (0, demux_stream_1.demuxStream)(dockerode, stream);
19
19
  }
20
20
  catch (err) {
21
21
  logger_1.log.error(`Failed to attach to container ${container.id}: ${err}`);
@@ -12,6 +12,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.containerLogs = void 0;
13
13
  const logger_1 = require("../../../logger");
14
14
  const demux_stream_1 = require("../demux-stream");
15
+ const docker_client_1 = require("../../docker-client");
15
16
  const containerLogs = (container) => __awaiter(void 0, void 0, void 0, function* () {
16
17
  try {
17
18
  const options = {
@@ -21,7 +22,7 @@ const containerLogs = (container) => __awaiter(void 0, void 0, void 0, function*
21
22
  };
22
23
  const stream = (yield container.logs(options));
23
24
  stream.socket.unref();
24
- return (0, demux_stream_1.demuxStream)(stream);
25
+ return (0, demux_stream_1.demuxStream)((yield (0, docker_client_1.dockerClient)()).dockerode, stream);
25
26
  }
26
27
  catch (err) {
27
28
  logger_1.log.error(`Failed to get container logs: ${err}`);
@@ -1,2 +1,3 @@
1
1
  import { Readable } from "stream";
2
- export declare const demuxStream: (stream: Readable) => Promise<Readable>;
2
+ import Dockerode from "dockerode";
3
+ export declare const demuxStream: (dockerode: Dockerode, stream: Readable) => Promise<Readable>;
@@ -12,11 +12,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.demuxStream = void 0;
13
13
  const stream_1 = require("stream");
14
14
  const logger_1 = require("../../logger");
15
- const docker_client_1 = require("../docker-client");
16
- const demuxStream = (stream) => __awaiter(void 0, void 0, void 0, function* () {
15
+ const demuxStream = (dockerode, stream) => __awaiter(void 0, void 0, void 0, function* () {
17
16
  try {
18
17
  const demuxedStream = new stream_1.PassThrough({ autoDestroy: true, encoding: "utf-8" });
19
- const { dockerode } = yield (0, docker_client_1.dockerClient)();
20
18
  dockerode.modem.demuxStream(stream, demuxedStream, demuxedStream);
21
19
  stream.on("end", () => demuxedStream.end());
22
20
  demuxedStream.on("close", () => {
@@ -1,3 +1,4 @@
1
+ import Dockerode from "dockerode";
1
2
  declare type DockerInfo = {
2
3
  serverVersion: number;
3
4
  operatingSystem: string;
@@ -6,5 +7,5 @@ declare type DockerInfo = {
6
7
  cpus: number;
7
8
  memory: number;
8
9
  };
9
- export declare const getDockerInfo: () => Promise<DockerInfo>;
10
+ export declare const getDockerInfo: (dockerode: Dockerode) => Promise<DockerInfo>;
10
11
  export {};
@@ -10,9 +10,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.getDockerInfo = void 0;
13
- const docker_client_1 = require("../docker-client");
14
- const getDockerInfo = () => __awaiter(void 0, void 0, void 0, function* () {
15
- const { dockerode } = yield (0, docker_client_1.dockerClient)();
13
+ const getDockerInfo = (dockerode) => __awaiter(void 0, void 0, void 0, function* () {
16
14
  const info = yield dockerode.info();
17
15
  return {
18
16
  serverVersion: info.ServerVersion,
@@ -1,2 +1,3 @@
1
1
  import { DockerImageName } from "../../../docker-image-name";
2
- export declare const imageExists: (imageName: DockerImageName) => Promise<boolean>;
2
+ import Dockerode from "dockerode";
3
+ export declare const imageExists: (dockerode: Dockerode, imageName: DockerImageName) => Promise<boolean>;
@@ -11,7 +11,9 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.imageExists = void 0;
13
13
  const list_images_1 = require("./list-images");
14
- const imageExists = (imageName) => __awaiter(void 0, void 0, void 0, function* () {
15
- return (yield (0, list_images_1.listImages)()).some((image) => image.equals(imageName));
14
+ const logger_1 = require("../../../logger");
15
+ const imageExists = (dockerode, imageName) => __awaiter(void 0, void 0, void 0, function* () {
16
+ logger_1.log.debug(`Checking if image exists: ${imageName}`);
17
+ return (yield (0, list_images_1.listImages)(dockerode)).some((image) => image.equals(imageName));
16
18
  });
17
19
  exports.imageExists = imageExists;
@@ -1,2 +1,3 @@
1
1
  import { DockerImageName } from "../../../docker-image-name";
2
- export declare const listImages: () => Promise<DockerImageName[]>;
2
+ import Dockerode from "dockerode";
3
+ export declare const listImages: (dockerode: Dockerode) => Promise<DockerImageName[]>;
@@ -11,11 +11,9 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.listImages = void 0;
13
13
  const docker_image_name_1 = require("../../../docker-image-name");
14
- const docker_client_1 = require("../../docker-client");
15
14
  const logger_1 = require("../../../logger");
16
- const listImages = () => __awaiter(void 0, void 0, void 0, function* () {
15
+ const listImages = (dockerode) => __awaiter(void 0, void 0, void 0, function* () {
17
16
  try {
18
- const { dockerode } = yield (0, docker_client_1.dockerClient)();
19
17
  const images = yield dockerode.listImages();
20
18
  return images.reduce((dockerImageNames, image) => {
21
19
  var _a;
@@ -1,8 +1,9 @@
1
1
  import { DockerImageName } from "../../../docker-image-name";
2
2
  import { AuthConfig } from "../../types";
3
+ import Dockerode from "dockerode";
3
4
  export declare type PullImageOptions = {
4
5
  imageName: DockerImageName;
5
6
  force: boolean;
6
7
  authConfig?: AuthConfig;
7
8
  };
8
- export declare const pullImage: (options: PullImageOptions) => Promise<void>;
9
+ export declare const pullImage: (dockerode: Dockerode, options: PullImageOptions) => Promise<void>;
@@ -12,16 +12,14 @@ Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.pullImage = void 0;
13
13
  const logger_1 = require("../../../logger");
14
14
  const pull_stream_parser_1 = require("../../pull-stream-parser");
15
- const docker_client_1 = require("../../docker-client");
16
15
  const image_exists_1 = require("./image-exists");
17
- const pullImage = (options) => __awaiter(void 0, void 0, void 0, function* () {
16
+ const pullImage = (dockerode, options) => __awaiter(void 0, void 0, void 0, function* () {
18
17
  try {
19
- if ((yield (0, image_exists_1.imageExists)(options.imageName)) && !options.force) {
18
+ if ((yield (0, image_exists_1.imageExists)(dockerode, options.imageName)) && !options.force) {
20
19
  logger_1.log.debug(`Not pulling image as it already exists: ${options.imageName}`);
21
20
  return;
22
21
  }
23
22
  logger_1.log.info(`Pulling image: ${options.imageName}`);
24
- const { dockerode } = yield (0, docker_client_1.dockerClient)();
25
23
  const stream = yield dockerode.pull(options.imageName.toString(), { authconfig: options.authConfig });
26
24
  yield new pull_stream_parser_1.PullStreamParser(options.imageName, logger_1.log).consume(stream);
27
25
  }
@@ -19,11 +19,11 @@ const inspect_container_1 = require("./container/inspect-container");
19
19
  const runInContainer = (dockerode, image, command) => __awaiter(void 0, void 0, void 0, function* () {
20
20
  try {
21
21
  const imageName = docker_image_name_1.DockerImageName.fromString(image);
22
- yield (0, pull_image_1.pullImage)({ imageName, force: false });
22
+ yield (0, pull_image_1.pullImage)(dockerode, { imageName, force: false });
23
23
  logger_1.log.debug(`Creating container: ${image} with command: ${command.join(" ")}`);
24
24
  const container = yield dockerode.createContainer({ Image: image, Cmd: command, HostConfig: { AutoRemove: true } });
25
25
  logger_1.log.debug(`Attaching to container: ${container.id}`);
26
- const stream = yield (0, attach_container_1.attachContainer)(container);
26
+ const stream = yield (0, attach_container_1.attachContainer)(dockerode, container);
27
27
  const promise = new Promise((resolve) => {
28
28
  const interval = setInterval(() => __awaiter(void 0, void 0, void 0, function* () {
29
29
  const inspect = yield (0, inspect_container_1.inspectContainer)(container);
@@ -24,6 +24,7 @@ const build_image_1 = require("../docker/functions/image/build-image");
24
24
  const image_exists_1 = require("../docker/functions/image/image-exists");
25
25
  const registry_auth_locator_1 = require("../registry-auth-locator");
26
26
  const generic_container_1 = require("./generic-container");
27
+ const docker_client_1 = require("../docker/docker-client");
27
28
  class GenericContainerBuilder {
28
29
  constructor(context, dockerfileName, uuid = new uuid_1.RandomUuid()) {
29
30
  this.context = context;
@@ -57,7 +58,7 @@ class GenericContainerBuilder {
57
58
  registryConfig,
58
59
  });
59
60
  const container = new generic_container_1.GenericContainer(imageName.toString());
60
- if (!(yield (0, image_exists_1.imageExists)(imageName))) {
61
+ if (!(yield (0, image_exists_1.imageExists)((yield (0, docker_client_1.dockerClient)()).dockerode, imageName))) {
61
62
  throw new Error("Failed to build image");
62
63
  }
63
64
  return Promise.resolve(container);
@@ -61,7 +61,7 @@ class GenericContainer {
61
61
  }
62
62
  start() {
63
63
  return __awaiter(this, void 0, void 0, function* () {
64
- yield (0, pull_image_1.pullImage)({
64
+ yield (0, pull_image_1.pullImage)((yield (0, docker_client_1.dockerClient)()).dockerode, {
65
65
  imageName: this.imageName,
66
66
  force: this.pullPolicy.shouldPull(),
67
67
  authConfig: yield (0, registry_auth_locator_1.getAuthConfig)(this.imageName.registry),
@@ -1 +1,2 @@
1
- export declare const logSystemDiagnostics: () => Promise<void>;
1
+ import Dockerode from "dockerode";
2
+ export declare const logSystemDiagnostics: (dockerode: Dockerode) => Promise<void>;
@@ -13,10 +13,11 @@ exports.logSystemDiagnostics = void 0;
13
13
  const logger_1 = require("./logger");
14
14
  const docker_compose_1 = require("./docker-compose/docker-compose");
15
15
  const get_info_1 = require("./docker/functions/get-info");
16
- const logSystemDiagnostics = () => __awaiter(void 0, void 0, void 0, function* () {
16
+ const logSystemDiagnostics = (dockerode) => __awaiter(void 0, void 0, void 0, function* () {
17
+ logger_1.log.debug("Fetching system diagnostics");
17
18
  const info = {
18
19
  node: getNodeInfo(),
19
- docker: yield (0, get_info_1.getDockerInfo)(),
20
+ docker: yield (0, get_info_1.getDockerInfo)(dockerode),
20
21
  dockerCompose: yield getDockerComposeInfo(),
21
22
  };
22
23
  logger_1.log.debug(`System diagnostics: ${JSON.stringify(info)}`);
@@ -36,7 +37,7 @@ const getDockerComposeInfo = () => __awaiter(void 0, void 0, void 0, function* (
36
37
  };
37
38
  }
38
39
  catch (err) {
39
- logger_1.log.warn(`Unable to detect docker-compose version, is it installed? ${err}`);
40
+ logger_1.log.info(`Unable to detect docker-compose version, is it installed? ${err}`);
40
41
  return undefined;
41
42
  }
42
43
  });
@@ -11,6 +11,9 @@ export declare class HostPortCheck implements PortCheck {
11
11
  }
12
12
  export declare class InternalPortCheck implements PortCheck {
13
13
  private readonly container;
14
+ private isDistroless;
15
+ private commandOutputs;
14
16
  constructor(container: Dockerode.Container);
15
17
  isBound(port: Port): Promise<boolean>;
18
+ private commandOutputsKey;
16
19
  }
@@ -12,6 +12,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.InternalPortCheck = exports.HostPortCheck = void 0;
13
13
  const net_1 = require("net");
14
14
  const exec_container_1 = require("./docker/functions/container/exec-container");
15
+ const logger_1 = require("./logger");
15
16
  class HostPortCheck {
16
17
  constructor(host) {
17
18
  this.host = host;
@@ -40,6 +41,8 @@ exports.HostPortCheck = HostPortCheck;
40
41
  class InternalPortCheck {
41
42
  constructor(container) {
42
43
  this.container = container;
44
+ this.isDistroless = false;
45
+ this.commandOutputs = new Set();
43
46
  }
44
47
  isBound(port) {
45
48
  return __awaiter(this, void 0, void 0, function* () {
@@ -50,8 +53,32 @@ class InternalPortCheck {
50
53
  ["/bin/bash", "-c", `</dev/tcp/localhost/${port}`],
51
54
  ];
52
55
  const commandResults = yield Promise.all(commands.map((command) => (0, exec_container_1.execContainer)(this.container, command)));
53
- return commandResults.some((result) => result.exitCode === 0);
56
+ const isBound = commandResults.some((result) => result.exitCode === 0);
57
+ if (!isBound) {
58
+ const shellExists = commandResults.some((result) => result.exitCode !== 126);
59
+ if (!shellExists) {
60
+ if (!this.isDistroless) {
61
+ this.isDistroless = true;
62
+ logger_1.log.error(`The HostPortWaitStrategy will not work on a distroless image, use an alternate wait strategy for container ${this.container.id}`);
63
+ }
64
+ }
65
+ else {
66
+ commandResults
67
+ .map((result) => (Object.assign(Object.assign({}, result), { output: result.output.trim() })))
68
+ .filter((result) => result.exitCode !== 126 && result.output.length > 0)
69
+ .forEach((result) => {
70
+ if (!this.commandOutputs.has(this.commandOutputsKey(result.output))) {
71
+ logger_1.log.trace(`Port check result for container ${this.container.id} exit code ${result.exitCode}: ${result.output}`);
72
+ this.commandOutputs.add(this.commandOutputsKey(result.output));
73
+ }
74
+ });
75
+ }
76
+ }
77
+ return isBound;
54
78
  });
55
79
  }
80
+ commandOutputsKey(output) {
81
+ return `${this.container.id}:${output}`;
82
+ }
56
83
  }
57
84
  exports.InternalPortCheck = InternalPortCheck;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "testcontainers",
3
3
  "author": "Cristian Greco",
4
- "version": "8.13.1",
4
+ "version": "8.14.0",
5
5
  "main": "dist/index",
6
6
  "types": "dist/index",
7
7
  "keywords": [