testcontainers 6.1.1 → 6.4.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/README.md CHANGED
@@ -23,6 +23,8 @@ The following environment variables are supported:
23
23
  | `DEBUG` | `testcontainers*` | See all output |
24
24
  | `DOCKER_HOST` | `tcp://docker:2375` | Override the Docker host |
25
25
  | `TESTCONTAINERS_RYUK_DISABLED` | `true` | Disable [ryuk](#ryuk) |
26
+ | `RYUK_CONTAINER_IMAGE` | `registry.mycompany.com/mirror/ryuk:0.3.0` | Custom image for [ryuk](#ryuk) |
27
+ | `SSHD_CONTAINER_IMAGE` | `registry.mycompany.com/mirror/sshd:1.0.0` | Custom image for [SSHd](#SSHd) |
26
28
 
27
29
  ## Modules
28
30
 
@@ -508,13 +510,37 @@ const container = await new GenericContainer("redis")
508
510
  .start();
509
511
  ```
510
512
 
511
- ## ryuk
513
+ ## Sidecars
512
514
 
513
- Testcontainers will start a sidecar container called ryuk whenever a container, docker-compose environment or network is started. This container keeps track of containers/images/networks/volumes created by testcontainers and will automatically clean up these resources 10s after connectivity with testcontainers is lost.
515
+ Testcontainers may need to create sidecar containers to provide its functionality.
514
516
 
515
- This is useful for example if a test starts a container and then terminates unexpectedly, as these dangling resources will be automatically removed.
517
+ To avoid Docker pull limits, you can host your own images and use them by setting the appropriate environment variables:
516
518
 
517
- ryuk must be run with privileged mode; in CI environments such as Bit Bucket where this isn't supported, ryuk can be disabled by setting the environment variable `TESTCONTAINERS_RYUK_DISABLED` to `true`.
519
+ | Sidecar | Environment Variable | Default
520
+ | --- | --- | --- |
521
+ | ryuk | `RYUK_CONTAINER_IMAGE` | `testcontainers/ryuk:0.3.0` |
522
+ | SSHd | `SSHD_CONTAINER_IMAGE` | `testcontainers/sshd:1.0.0` |
523
+
524
+ ### ryuk
525
+
526
+ Testcontainers will start ryuk whenever a container, docker-compose environment or network is started.
527
+
528
+ Once started, this container keeps track of containers/images/networks/volumes created by testcontainers and will
529
+ automatically clean them up 10s after connectivity with testcontainers is lost. This is useful for example if a test
530
+ starts a container and then terminates unexpectedly, as it will be automatically removed.
531
+
532
+ ryuk must be run with privileged mode; in CI environments such as Bit Bucket where this isn't supported, ryuk can be
533
+ disabled by setting the environment variable `TESTCONTAINERS_RYUK_DISABLED` to `true`.
534
+
535
+ ### SSHd
536
+
537
+ Testcontainers will start SSHd when using the expose host port functionality.
538
+
539
+ Once started, any container that is created will have a host mapping of `host.testcontainers.internal` that points to
540
+ the SSHd container, as well as being connected to its network.
541
+
542
+ When we then expose a host port, we remote port forward our local port to the SSHd container, which the other
543
+ containers will then be able to access at `host.testcontainers.internal:<exposed-port>`.
518
544
 
519
545
  ## Common Issues
520
546
 
@@ -533,4 +559,4 @@ It can take a few seconds up to a few minutes to pull and run certain Docker ima
533
559
  depending on file sizes and network constraints. It's unlikely that the default
534
560
  timeouts set by test frameworks are sufficient.
535
561
 
536
- - Increase the test timeout via the methods provided by the testing framework.
562
+ - Increase the test timeout via the methods provided by the testing framework.
package/dist/container.js CHANGED
@@ -115,6 +115,9 @@ class DockerodeExec {
115
115
  if (err) {
116
116
  return reject(err);
117
117
  }
118
+ else if (!stream) {
119
+ return reject(new Error("Unexpected error occurred, stream is undefined"));
120
+ }
118
121
  return resolve(stream);
119
122
  });
120
123
  });
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.resolveDockerComposeContainerName = void 0;
4
- exports.resolveDockerComposeContainerName = (projectName, containerName) => {
4
+ const resolveDockerComposeContainerName = (projectName, containerName) => {
5
5
  if (containerName.includes(projectName)) {
6
6
  return containerName.substring(`/${projectName}_`.length);
7
7
  }
@@ -12,3 +12,4 @@ exports.resolveDockerComposeContainerName = (projectName, containerName) => {
12
12
  throw new Error(`Unable to resolve container name for container name: "${containerName}", project name: "${projectName}"`);
13
13
  }
14
14
  };
15
+ exports.resolveDockerComposeContainerName = resolveDockerComposeContainerName;
@@ -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
- exports.findDockerIgnoreFiles = (context) => __awaiter(void 0, void 0, void 0, function* () {
20
+ const findDockerIgnoreFiles = (context) => __awaiter(void 0, void 0, void 0, function* () {
21
21
  const dockerIgnoreFiles = new Set();
22
22
  const dockerIgnoreFilePath = path_1.default.join(context, ".dockerignore");
23
23
  if (!fs_1.existsSync(dockerIgnoreFilePath)) {
@@ -42,3 +42,4 @@ exports.findDockerIgnoreFiles = (context) => __awaiter(void 0, void 0, void 0, f
42
42
  });
43
43
  return dockerIgnoreFiles;
44
44
  });
45
+ exports.findDockerIgnoreFiles = findDockerIgnoreFiles;
@@ -12,6 +12,8 @@ export declare class KafkaContainer extends GenericContainer {
12
12
  readonly image: Image;
13
13
  readonly tag: Tag;
14
14
  readonly host?: string | undefined;
15
+ readonly zooKeeperImage: Image;
16
+ readonly zooKeeperTag: Tag;
15
17
  private readonly uuid;
16
18
  private readonly portClient;
17
19
  private isZooKeeperProvided;
@@ -19,7 +21,7 @@ export declare class KafkaContainer extends GenericContainer {
19
21
  private zooKeeperPort?;
20
22
  private network?;
21
23
  private zooKeeperContainer?;
22
- constructor(image?: Image, tag?: Tag, host?: string | undefined);
24
+ constructor(image?: Image, tag?: Tag, host?: string | undefined, zooKeeperImage?: Image, zooKeeperTag?: Tag);
23
25
  withZooKeeper(host: Host, port: Port): this;
24
26
  protected preCreate(dockerClient: DockerClient, boundPorts: BoundPorts): Promise<void>;
25
27
  start(): Promise<StartedKafkaContainer>;
@@ -17,11 +17,13 @@ const uuid_1 = require("../../uuid");
17
17
  const logger_1 = require("../../logger");
18
18
  const abstract_started_container_1 = require("../abstract-started-container");
19
19
  class KafkaContainer extends generic_container_1.GenericContainer {
20
- constructor(image = "confluentinc/cp-kafka", tag = "latest", host) {
20
+ constructor(image = "confluentinc/cp-kafka", tag = "latest", host, zooKeeperImage = "confluentinc/cp-zookeeper", zooKeeperTag = "latest") {
21
21
  super(image, tag);
22
22
  this.image = image;
23
23
  this.tag = tag;
24
24
  this.host = host;
25
+ this.zooKeeperImage = zooKeeperImage;
26
+ this.zooKeeperTag = zooKeeperTag;
25
27
  this.uuid = new uuid_1.RandomUuid();
26
28
  this.portClient = new port_client_1.RandomPortClient();
27
29
  this.isZooKeeperProvided = false;
@@ -53,7 +55,7 @@ class KafkaContainer extends generic_container_1.GenericContainer {
53
55
  const zooKeeperHost = this.uuid.nextUuid();
54
56
  const zooKeeperPort = yield this.portClient.getPort();
55
57
  this.withEnv("KAFKA_ZOOKEEPER_CONNECT", `${zooKeeperHost}:${zooKeeperPort}`);
56
- const zookeeperContainer = yield new generic_container_1.GenericContainer("confluentinc/cp-zookeeper", "latest")
58
+ const zookeeperContainer = yield new generic_container_1.GenericContainer(this.zooKeeperImage, this.zooKeeperTag)
57
59
  .withName(zooKeeperHost)
58
60
  .withEnv("ZOOKEEPER_CLIENT_PORT", zooKeeperPort.toString());
59
61
  if (this.networkMode !== undefined) {
@@ -16,6 +16,8 @@ export declare class PortForwarderInstance {
16
16
  static IMAGE_VERSION: string;
17
17
  private static instance;
18
18
  static isRunning(): boolean;
19
+ private static getImageName;
20
+ private static getImageVersion;
19
21
  static getInstance(dockerClient: DockerClient): Promise<PortForwarder>;
20
22
  private static createInstance;
21
23
  }
@@ -40,6 +40,18 @@ class PortForwarderInstance {
40
40
  static isRunning() {
41
41
  return this.instance !== undefined;
42
42
  }
43
+ static getImageName() {
44
+ if (process.env.SSHD_CONTAINER_IMAGE !== undefined) {
45
+ this.IMAGE_NAME = process.env.SSHD_CONTAINER_IMAGE.split(/:/)[0];
46
+ }
47
+ return this.IMAGE_NAME;
48
+ }
49
+ static getImageVersion() {
50
+ if (process.env.SSHD_CONTAINER_IMAGE !== undefined) {
51
+ this.IMAGE_VERSION = process.env.SSHD_CONTAINER_IMAGE.split(/:/)[1];
52
+ }
53
+ return this.IMAGE_VERSION;
54
+ }
43
55
  static getInstance(dockerClient) {
44
56
  return __awaiter(this, void 0, void 0, function* () {
45
57
  if (!this.instance) {
@@ -53,7 +65,7 @@ class PortForwarderInstance {
53
65
  logger_1.log.debug(`Creating new Port Forwarder`);
54
66
  const username = "root";
55
67
  const password = new uuid_1.RandomUuid().nextUuid();
56
- const container = yield new generic_container_1.GenericContainer(this.IMAGE_NAME, this.IMAGE_VERSION)
68
+ const container = yield new generic_container_1.GenericContainer(this.getImageName(), this.getImageVersion())
57
69
  .withName(`testcontainers-port-forwarder-${dockerClient.getSessionId()}`)
58
70
  .withDaemonMode()
59
71
  .withExposedPorts(22)
package/dist/reaper.d.ts CHANGED
@@ -8,6 +8,8 @@ export declare class ReaperInstance {
8
8
  private static instance;
9
9
  static getInstance(dockerClient: DockerClient): Promise<Reaper>;
10
10
  private static isEnabled;
11
+ private static getImageName;
12
+ private static getImageVersion;
11
13
  private static createDisabledInstance;
12
14
  private static createRealInstance;
13
15
  }
package/dist/reaper.js CHANGED
@@ -46,6 +46,18 @@ class ReaperInstance {
46
46
  static isEnabled() {
47
47
  return process.env.TESTCONTAINERS_RYUK_DISABLED !== "true";
48
48
  }
49
+ static getImageName() {
50
+ if (process.env.RYUK_CONTAINER_IMAGE !== undefined) {
51
+ this.IMAGE_NAME = process.env.RYUK_CONTAINER_IMAGE.split(/:/)[0];
52
+ }
53
+ return this.IMAGE_NAME;
54
+ }
55
+ static getImageVersion() {
56
+ if (process.env.RYUK_CONTAINER_IMAGE !== undefined) {
57
+ this.IMAGE_VERSION = process.env.RYUK_CONTAINER_IMAGE.split(/:/)[1];
58
+ }
59
+ return this.IMAGE_VERSION;
60
+ }
49
61
  static createDisabledInstance(dockerClient) {
50
62
  const sessionId = dockerClient.getSessionId();
51
63
  logger_1.log.debug(`Not creating new Reaper for session: ${sessionId}`);
@@ -55,7 +67,7 @@ class ReaperInstance {
55
67
  return __awaiter(this, void 0, void 0, function* () {
56
68
  const sessionId = dockerClient.getSessionId();
57
69
  logger_1.log.debug(`Creating new Reaper for session: ${sessionId}`);
58
- const container = yield new generic_container_1.GenericContainer(this.IMAGE_NAME, this.IMAGE_VERSION)
70
+ const container = yield new generic_container_1.GenericContainer(this.getImageName(), this.getImageVersion())
59
71
  .withName(`testcontainers-ryuk-${sessionId}`)
60
72
  .withExposedPorts(8080)
61
73
  .withWaitStrategy(wait_1.Wait.forLogMessage("Started!"))
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "testcontainers",
3
3
  "author": "Cristian Greco",
4
- "version": "6.1.1",
4
+ "version": "6.4.1",
5
5
  "main": "dist/index",
6
6
  "types": "dist/index",
7
7
  "keywords": [
@@ -31,9 +31,9 @@
31
31
  "updateDeps": "npx npm-check-updates -u"
32
32
  },
33
33
  "dependencies": {
34
- "@types/dockerode": "^2.5.34",
34
+ "@types/dockerode": "^3.2.1",
35
35
  "byline": "^5.0.0",
36
- "debug": "^4.1.1",
36
+ "debug": "^4.3.1",
37
37
  "docker-compose": "^0.23.5",
38
38
  "dockerode": "^3.2.1",
39
39
  "get-port": "^5.1.1",
@@ -41,35 +41,35 @@
41
41
  "slash": "^3.0.0",
42
42
  "ssh-remote-port-forward": "^1.0.3",
43
43
  "stream-to-array": "^2.3.0",
44
- "tar-fs": "^2.1.0"
44
+ "tar-fs": "^2.1.1"
45
45
  },
46
46
  "devDependencies": {
47
- "@elastic/elasticsearch": "^7.9.1",
47
+ "@elastic/elasticsearch": "^7.10.0",
48
48
  "@types/byline": "^4.2.32",
49
49
  "@types/debug": "4.1.5",
50
50
  "@types/glob": "^7.1.3",
51
- "@types/jest": "^26.0.13",
52
- "@types/node": "^14.10.1",
51
+ "@types/jest": "^26.0.19",
52
+ "@types/node": "^14.14.14",
53
53
  "@types/node-fetch": "^2.5.7",
54
54
  "@types/stream-to-array": "^2.3.0",
55
55
  "@types/tar-fs": "^2.0.0",
56
- "@typescript-eslint/eslint-plugin": "^4.1.1",
57
- "@typescript-eslint/parser": "^4.1.1",
58
- "arangojs": "^6.14.1",
59
- "cross-env": "^7.0.2",
60
- "eslint": "^7.9.0",
61
- "eslint-config-prettier": "^6.11.0",
62
- "husky": "^4.3.0",
63
- "jest": "^26.4.2",
64
- "kafkajs": "^1.13.0",
65
- "lint-staged": "^10.3.0",
66
- "neo4j-driver": "^4.1.2",
56
+ "@typescript-eslint/eslint-plugin": "^4.11.0",
57
+ "@typescript-eslint/parser": "^4.11.0",
58
+ "arangojs": "^7.2.0",
59
+ "cross-env": "^7.0.3",
60
+ "eslint": "^7.16.0",
61
+ "eslint-config-prettier": "^7.1.0",
62
+ "husky": "^4.3.6",
63
+ "jest": "^26.6.3",
64
+ "kafkajs": "^1.15.0",
65
+ "lint-staged": "^10.5.3",
66
+ "neo4j-driver": "^4.2.1",
67
67
  "node-fetch": "^2.6.1",
68
- "prettier": "^2.1.1",
68
+ "prettier": "^2.2.1",
69
69
  "rimraf": "^3.0.2",
70
- "ts-jest": "^26.3.0",
71
- "ts-node": "^9.0.0",
72
- "typescript": "^4.0.2"
70
+ "ts-jest": "^26.4.4",
71
+ "ts-node": "^9.1.1",
72
+ "typescript": "^4.1.3"
73
73
  },
74
74
  "husky": {
75
75
  "hooks": {