Code Monkey home page Code Monkey logo

testcontainers / testcontainers-node Goto Github PK

View Code? Open in Web Editor NEW
1.9K 12.0 182.0 4.1 MB

Testcontainers is a NodeJS library that supports tests, providing lightweight, throwaway instances of common databases, Selenium web browsers, or anything else that can run in a Docker container.

Home Page: https://testcontainers.com

License: MIT License

JavaScript 0.88% TypeScript 97.95% Dockerfile 0.49% Shell 0.41% Handlebars 0.27%
node docker testcontainers testing

testcontainers-node's Introduction

testcontainers-node's People

Contributors

apokralipsa avatar bcaglayan avatar bonomat avatar castarco avatar committomaster avatar crickford avatar cristianrgreco avatar dependabot[bot] avatar djakielski avatar dmitri-gb avatar eddumelendez avatar henrinormak avatar ilopezluna avatar javierlopezdeancos avatar katerina-semikina avatar kincaidoneil avatar leocross avatar lnsd avatar ltwlf avatar mdelapenya avatar nikeee avatar nitsanavni avatar nushosinkupomoglitebetvoisankcii avatar omerlh avatar oskarwidmark avatar pscanf avatar raganw avatar silh avatar weyert avatar wjin17 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

testcontainers-node's Issues

TypeError: container.exec is not a function

Hi Folks,

i tried the example, "Running commands inside running container", from the README.md and i tumbled over the following issue.

TypeError: container.exec is not a function at somefile.js:17:54 at <anonymous> at process._tickCallback (internal/process/next_tick.js:189:7)

It is not part of the TestContainer interface so the GenericContainer is obviously not able to do this. Please adjust the README cause i'm now really sad cause i can not work around the getContainerIpAddress issue ;)

Cheers
Christian

Host expose ports is not supported

I would like to expose for example MySQL container ports, how can I define the container host ports? There is a function like in the Java package called .withFixedExposedPort(3306, 3306) where I can define the host and the container ports?

Waiting for host Port

Can you help me to solve this problem?? im runing version 2.0 .0 in a windows machine, yeah sad =/ but true. Here is the code:

const containers = {}
describe(`Integration Testing ${__filename}`, () => {
  before(async done => {
    containers.mysqlContainer = await new GenericContainer('mysql')
      .withEnv('MYSQL_ROOT_PASSWORD', 'test')
      .withExposedPorts(3306)
    await containers.mysqlContainer.start()
    process.env.DB_HOST_TEST = `mysql://test:test@localhost:${containers.mysqlContainer.getMappedPort(3306)}`
    done()
  })
...

The container start, i can see it running docker ps but when i run npm test, it fails.

the error code:

 Integration Testing 
  testcontainers INFO: Using Docker defaults +0ms
  testcontainers INFO: Creating container for image: mysql:latest +66ms
Redis conectado
  testcontainers INFO: Starting container with ID: 8e5214f4cabf114262aeb7a23811f01d0ab6caf04bb6448ae52021b4e2a8105d +173ms
  testcontainers DEBUG: Starting container health checks +1s
  testcontainers DEBUG: Waiting for host port :54979 +4ms
  testcontainers DEBUG: Waiting for internal port :3306 +5ms

And stops here, nothing responds. Any idea?

Thanks in advance.

Connection times out after spawning Docker

Using the following code I am unable to connect to the spawned Docker. Is there something I'm doing wrong?

const { createPool } = require('mysql2/promise')
const { GenericContainer, Wait } = require('testcontainers')
const mysqlContainer = async () => {
  const container = await new GenericContainer('mysql', '5.7')
    .withExposedPorts(3306)
    .withEnv('MYSQL_ALLOW_EMPTY_PASSWORD', '1')
    .withEnv('MYSQL_DATABASE', 'testdb')
    .withWaitStrategy(Wait.forLogMessage('mysqld: ready for connections.'))
    .start()
  console.log('Container started')
  return container
}

(async () => {
  const container = await mysqlContainer()
  try {
    const connection = await createPool({ host: 'localhost', user: 'root', password: '', port: container.getMappedPort(3306) })
    console.log('Connected to database')
    console.log(await (connection.query('SELECT count(*) FROM information_schema.columns')))
  } catch (e) {
    console.error(e, e.stack)
  }
  await container.stop()
})()

Support for tmpfs

It would be helpful to be able to specify a tmpfs setting, the same way you can with testcontainers-java:
testcontainers/testcontainers-java#673

My use case is that I'd like to point a test database's data volume at a tmpfs in order to make our unit tests run quicker.

Thanks.

Select which Dockerfile to build from (i.e. support -f flag)

In my application, I have to separate different test environments into different Dockerfile,
and name each of them in different Dockerfile names. (e.g. Dockerfile-a, Dockerfile-b, ...)

Can I achieve this?
Since I didn't find any fileName support from the GenericContainer.fromDockerfile api.

Thanks a lot!

Generic Test Container fails to start

Hi! I love this library, thanks for making it available!

I'm having an issue on one of my two machines but I can't figure out the root cause. I have been using the library for several months now and it was working however a few days ago, my test container wouldn't start on one of my machines. On another machine it still works well. I tried comparing the Docker versions but there doesn't seem to be an obvious difference. (I'm a relative docker n00b though.)

What's happening is that the start() method is throwing an error and not starting.

I'm not sure exactly what would be helpful for you to know so I'll put some relevant information below. I don't really think it's your library but I'm wondering what other dependencies I should look at to see what the issue is.

Thanks so much!


Here is a readout of my terminal output.

env DEBUG=testcontainers yarn app:corona test JobService.test.js
yarn run v1.15.2
$ yarn workspace corona-api-poc test JobService.test.js
$ jest JobService.test.js
Determining test suites to run...

  # TEST CONTAINERS DEBUG OUTPUT
  testcontainers INFO: Using default Docker configuration +0ms
  testcontainers INFO: Creating container for image: postgres:9.6 +21ms
  testcontainers INFO: Starting container with ID: 7b5d63d4f6cdd192a164b0a223c36cdb694a2d2b2a97fc94035978119df9bab5 +129ms
  testcontainers DEBUG: Starting container health checks +533ms

  # ERROR HAPPENS BECAUSE THE START() METHOD FAILED
{"level":"error"}
TypeError: container.getMappedPort is not a function
    at startTestDB (/Users/mitchconquer/Projects/corona/packages/corona-app/app/test/testDatabase/container.js:26:97)
    at process._tickCallback (internal/process/next_tick.js:68:7)
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
error Command failed.
Exit code: 1
Command: /Users/mitchconquer/.nvm/versions/node/v10.15.0/bin/node
Arguments: /usr/local/Cellar/yarn/1.15.2/libexec/lib/cli.js test JobService.test.js
Directory: /Users/mitchconquer/Projects/corona/packages/corona-app
Output:

info Visit https://yarnpkg.com/en/docs/cli/workspace for documentation about this command.
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

I have traced this back to the testcontainer library's generic-container.ts file's waitForContainer method. I have run the debug logs for testcontainer and it seems that the container health checks are starting but not completing.

I also do not see the logs from the wait strategy's waitUntilReady method so I believe the error is being thrown on the withStartupTimeout method or the early in the waitUntilReady method.

testcontainers Version

From yarn.lock

testcontainers@^1.1.19:
  version "1.1.19"
  resolved "https://registry.yarnpkg.com/testcontainers/-/testcontainers-1.1.19.tgz#0062682548b99c2ea93af07c71a86264510870e9"
  integrity sha512-Aa/X92Gv0EVNRuYzxkK3AEc5hnMAgiTBhB/MpouuFTjc1Dh675Xw4KQtysy5+5S85NnQjC8RlNwshqaWC6/ikA==
  dependencies:
    byline "^5.0.0"
    debug "^4.1.1"
    dockerode "^2.5.8"
    get-port "^4.1.0"
    node-duration "^1.0.2"
    stream-to-array "^2.3.0"
    tar-fs "^2.0.0"

Docker Version

# docker version
Client: Docker Engine - Community
 Version:           19.03.2
 API version:       1.40
 Go version:        go1.12.8
 Git commit:        6a30dfc
 Built:             Thu Aug 29 05:26:49 2019
 OS/Arch:           darwin/amd64
 Experimental:      false

Server: Docker Engine - Community
 Engine:
  Version:          19.03.2
  API version:      1.40 (minimum version 1.12)
  Go version:       go1.12.8
  Git commit:       6a30dfc
  Built:            Thu Aug 29 05:32:21 2019
  OS/Arch:          linux/amd64
  Experimental:     false
 containerd:
  Version:          v1.2.6
  GitCommit:        894b81a4b802e4eb2a91d1ce216b8817763c29fb
 runc:
  Version:          1.0.0-rc8
  GitCommit:        425e105d5a03fabd737a126ad93d62a9eeede87f
 docker-init:
  Version:          0.18.0
  GitCommit:        fec3683

package.json

{
  "name": "corona",
  "version": "0.1.0",
  "private": true,
  "main": "src/index.js",
  "engines": {
    "yarn": "0.27.5 || >=1.0.2",
    "node": "^10.0.0"
  },
  "dependencies": {
    "@google-cloud/debug-agent": "^3.2.0",
    "@google-cloud/logging-winston": "^0.11.1",
    "@google-cloud/pubsub": "^0.28.1",
    "@google-cloud/storage": "^2.5.0",
    "@google-cloud/trace-agent": "^3.6.1",
    "@material-ui/core": "^4.0.0-beta.0",
    "@material-ui/icons": "^3.0.2",
    "app-module-path": "^2.2.0",
    "async": "^2.6.2",
    "body-parser": "^1.19.0",
    "chalk": "^2.4.2",
    "classnames": "^2.2.6",
    "connect-busboy": "^0.0.2",
    "continuation-local-storage": "^3.2.1",
    "csv-stringify": "^5.3.0",
    "dotenv": "^8.0.0",
    "express": "^4.16.4",
    "express-winston": "^3.1.0",
    "fast-crc32c": "^1.0.4",
    "fast-csv": "^3.1.0",
    "inquirer": "^6.3.1",
    "jsrsasign": "^8.0.12",
    "multer": "^1.4.1",
    "nconf": "^0.10.0",
    "node-fetch": "^2.5.0",
    "node-sequelize-stream": "^1.0.9",
    "pg": "^7.11.0",
    "pg-hstore": "^2.3.2",
    "react": "^16.8",
    "react-dom": "^16.9",
    "react-dropzone": "^10.1.4",
    "react-router-dom": "^4.1.2",
    "react-scripts": "^3.0.0",
    "recharts": "^1.5.0",
    "request": "^2.88.0",
    "sendgrid": "^5.2.3",
    "sequelize": "^5.8.6",
    "sequelize-mock": "^0.10.2",
    "short-uuid": "^3.1.1",
    "styled-components": "^4.2.0",
    "through2": "^3.0.1",
    "unzipper": "^0.10.1",
    "winston": "^3.2.1"
  },
  "scripts": {
    "start": "node --max-old-space-size=8192 ./app/server.js",
    "dev": "nodemon ./app/server.js",
    "deploy": "gcloud app deploy app.yaml",
    "logs": "gcloud app logs tail -s default",
    "precommit": "react-scripts precommit",
    "add:mapping": "node ./app/scripts/add-mapping",
    "add:account": "node ./app/scripts/add-account",
    "logs:worker": "gcloud app logs tail -s worker",
    "test": "jest",
    "test:silent": "SILENT=true jest",
    "test:coverage": "jest --watchAll=false --coverage",
    "test:add-rev-usd": "node ./app/scripts/add-rev.js",
    "sequelize": "./node_modules/.bin/sequelize"
  },
  "proxy": "http://localhost:8080",
  "browserslist": {
    "production": [">0.2%", "not dead", "not op_mini all"],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  },
  "nodemonConfig": {
    "ignore": ["test/*", "docs/*"],
    "delay": "2500"
  },
  "devDependencies": {
    "babel-cli": "^6.26.0",
    "babel-preset-env": "^1.7.0",
    "dockerode": "^2.5.8",
    "faker": "^4.1.0",
    "http-proxy": "^1.17.0",
    "jest-serial-runner": "^1.1.0",
    "nodemon": "^1.19.0",
    "npm-run-all": "^4.1.5",
    "sequelize-cli": "^5.5.0",
    "superagent": "^5.1.0",
    "supertest": "^4.0.2",
    "testcontainers": "^1.1.19"
  }
}

container.js

Code that invokes testcontainer, failing in the startTestDB() method, line 31 because the container has not started. Says getMappedPort is not a function.

'use strict';

const { getAppPath } = require('../helpers');

require('app-module-path').addPath(getAppPath());

const { GenericContainer, Wait } = require('testcontainers');
const chalk = require('chalk');
const { logger } = require('../../utils/logging');

const testSqlPort = 5432;

let container;

async function startTestDB() {
  container = await new GenericContainer('postgres', '9.6')
    .withEnv('POSTGRES_PASSWORD', 'password')
    .withExposedPorts(testSqlPort)
    .withWaitStrategy(
      Wait.forLogMessage(
        'PostgreSQL init process complete; ready for start up.'
      )
    )
    .start()
    .catch(err => logger.error(err));

  // eslint-disable-next-line no-restricted-syntax
  console.log(
    chalk.green(
      '\nTest database container created with port',
      chalk.yellow(container.getMappedPort(testSqlPort))
    )
  );

  return container;
}

function stopTestDB() {
  if (!container) {
    throw new Error('Test database container not found');
  }
  return container
    .stop()
    .then(() =>
      // eslint-disable-next-line no-restricted-syntax
      console.log(chalk.green('Test database container closed successfully'))
    )
    .catch(err =>
      // eslint-disable-next-line no-restricted-syntax
      console.log(chalk.red('Error closing test database container'), err)
    );
}

module.exports = { startTestDB, stopTestDB, container };

Image creation fails with no meaningful errors

i'm trying to build an image with

    const buildContext = path.resolve(__dirname, '../../');
    try {
        const container = await GenericContainer.fromDockerfile(buildContext)
        .build();
    }
    catch (e) {
        console.log(e);
    }

and that just fails after ~40 seconds w/o giving any reasonable error message:

  testcontainers INFO: Using Docker defaults +0ms
  testcontainers INFO: Building image '4e0f7a06234ada9ac05edc4a278b7a09:1fb761b7a169152a983a78ee352eeafb' with context '/Users/me/project' +1ms
Error: Failed to build image
    at GenericContainerBuilder.<anonymous> (/Users/me/node_modules/testcontainers/dist/generic-container.js:44:23)
    at Generator.next (<anonymous>)
    at fulfilled (/Users/me/node_modules/testcontainers/dist/generic-container.js:4:58)
    at processTicksAndRejections (internal/process/task_queues.js:97:5)

i can see that the building starts, but cannot get logs from the 'build' container
Error response from daemon: configured logging driver does not support reading

running node v14.3.0 on macOS 10.13.6 and docker desktop 2.1.0.4 (39773) engine 19.03.4

building the container manually works fine.

is there a way to get logs from the 'build' container?

Allow to wait for log messages

Hello from the Rust universe! :)

Thanks for creating a node port of testcontainers!

Context: Some containers take quite a while to start up and open ports before they are actually ready (bitcoin for example).

Possible solution: One way that works well for us in testcontainers-rs is to wait for a particular log message to be emitted:

https://github.com/testcontainers/testcontainers-rs/blob/f2f94f247fbdb87605c8e7dc18a67fa409250578/images/coblox_bitcoincore/src/image.rs#L167-L172

It would be nice if testcontainers-node would support that aswell :)
Happy to send PR if you outline how you would like the library to be extended.

TestContainer fluent API returning 'this' type

Hello,
thanks for this useful library.
I am trying to extend (subclass) GenericContainer but the current typing for the withXxx method gets in the way. To be able to extend the fluent API, these methods should return the actual type of Container class, not the base TestContainer.
In other words, simply return a this type from the methods e.g.

export interface TestContainer {
  withEnv(key: EnvKey, value: EnvValue): this;
  withCmd(cmd: Command[]): this;
  // ...
}

Add support for checking container health status if using HEALTHCHECK

Docker supports defining a separate HEALTHCHECK command that can be run internally to check whether the container is "healthy".

testcontainers-node mentions doing its own "health checks" at

log.debug("Starting container health checks");

However, this seems to refer only to checking that ports are listening. In some cases such as starting a postgres container this is not enough. The port may be opening but the DB isn't ready to receive queries, resulting in the error: "error: the database system is starting up". Note: this is not 100% verified.

testcontainers-java has another wait strategy called Wait.forHealthcheck https://github.com/testcontainers/testcontainers-java/blob/f113979ad5207464490cc4f19f488bb27795802c/core/src/main/java/org/testcontainers/containers/wait/strategy/Wait.java#L69 which basically keeps checking the .State.Health.Status of the container until its true.

From my understanding of a quick check of the source code of testcontainers-node this does not seem to be supported. It is possible that healthchecks are implicitly included somewhere along the line, but based on the Java version needing an explicit healthcheck wait strategy I assume a similar strategy would be needed for the Node version.

So what we would like is something like:

new GenericContainer('postgres').withWaitStrategy(Wait.healthcheck()).start()

One issue that seems to come up here is that you can currently only have a single wait strategy. It might be the case that you want to wait for a combination of conditions, but let's keep that out of scope for this issue.

Join forces?

Hi @cristianrgreco !

We noticed that you've created this project - it's very nice that you've decided to bring the Testcontainers concept to Node 😄

A NodeJS implementation was something that I've wanted to do at some point but didn't get around to yet. As you've made a start, would it be possible for us to work together to develop, maintain and publicise this?

Perhaps we could discuss here or on the Testcontainers Slack team?

Thanks!
Richard

StartedGenericContainer is not exported

When using TypeScript with this project, we need StartedGenericContainer to be exported in order to define a container in a top level scope properly, and use the container without assigning it to any.

For example:

export let container: StartedGenericContainer;

export const start = async () => {
    container = await new GenericContainer('postgres', '11.2-alpine')
      .withExposedPorts(5432)
      .start();
};

This is currently not possible, and let container: any; must be used.

How does this work with couchdb?

Hi Im trying to get this to work with couchdb. However I keep getting an error. Here is my code

container = await new GenericContainer("couchdb")
            .withExposedPorts(5984)
            .start();

After running I get this error

 Error: Port :4369 not bound after 10000ms
      at retryStrategy.retryUntil (node_modules/testcontainers/dist/wait-strategy.js:59:23)
      at IntervalRetryStrategy.<anonymous> (node_modules/testcontainers/dist/retry-strategy.js:35:28)
      at Generator.next (<anonymous>)
      at fulfilled (node_modules/testcontainers/dist/retry-strategy.js:4:58)
      at <anonymous>
      at process._tickCallback (internal/process/next_tick.js:189:7)

Not entirely sure where port 4369 is coming from. Perhaps I misunderstand the purpose of withExposedPorts.

I also noticed that it does seem to start the container correctly when I do a docker ps I can see the started container

CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                                         NAMES
a4722698ad61        couchdb:latest      "tini -- /docker-ent…"   13 seconds ago      Up 12 seconds       4369/tcp, 9100/tcp, 0.0.0.0:35121->5984/tcp   epic_raman

UPDATE

I also tried with a simple mysql container, And I get more or less the same error as above. Code below

container = await new GenericContainer("mysql")
            .withEnv("MYSQL_ROOT_PASSWORD", "my-secret-pw")
            .withExposedPorts(3306)
            .start();

And error

Error: Port :3306 not bound after 10000ms
      at retryStrategy.retryUntil (node_modules/testcontainers/dist/wait-strategy.js:59:23)
      at IntervalRetryStrategy.<anonymous> (node_modules/testcontainers/dist/retry-strategy.js:35:28)
      at Generator.next (<anonymous>)
      at fulfilled (node_modules/testcontainers/dist/retry-strategy.js:4:58)
      at <anonymous>
      at process._tickCallback (internal/process/next_tick.js:189:7)

The only container that seems to work for me is the redis one in the main example on the readme

expose inspect result

I see there's an inspect method buried in the depths of private variables. Why not expose it? Also would be great to have access to the full response rather than very limited sub-set.

I was looking for a way to retrieve an internal ip of the container on the default bridge network. Might be useful, especially without support for user-defined networks.

[question] Startup hangs in Jenkins

I have been using testcontainers-java for the past couple of year and I love it. Hence I tried to give it a shot to node version (2.7.0) of it.

I have a fairly simple test setup:

jest.setTimeout(600000)
let pgContainer: any

beforeAll(async () => {
  pgContainer = await new GenericContainer('postgres')
    .withEnv('POSTGRES_USER', 'test')
    .withEnv('POSTGRES_PASSWORD', 'test')
    .withEnv('POSTGRES_DB', 'postgres')
    //added for testing purposes
    //.withStartupTimeout(new Duration(200, TemporalUnit.SECONDS))
    .withExposedPorts(5432)
    .start()

  expect(pgContainer).toBeTruthy()
  console.log(pgContainer.boundPorts)
})

afterAll(async () => {
  await pgContainer.stop()
})

describe('verify it works', function() { ... }

which works perfectly on my local machine:

2020-04-06T13:12:54.372Z testcontainers INFO: Using Docker defaults
2020-04-06T13:12:54.452Z testcontainers INFO: Creating container for image: postgres:latest
2020-04-06T13:12:54.586Z testcontainers INFO: Starting container with ID: 6647ae7575ff97de3be4444b704bec49edb68ffc74275f6b5be7b8e7e1ff7f79
2020-04-06T13:12:55.238Z testcontainers DEBUG: Waiting for container to be ready
2020-04-06T13:12:55.238Z testcontainers DEBUG: Waiting for host port 63608
2020-04-06T13:12:55.240Z testcontainers DEBUG: Waiting for internal port 5432
2020-04-06T13:12:57.996Z testcontainers DEBUG: Container is ready

But when I try to run it on my company's Jenkins slave (which sadly I have very limited access to)
it fails to start

$ DEBUG=testcontainers yarn test:unit
$ jest --config test/config.unit.json
2020-04-06T13:02:22.935Z testcontainers INFO: Using Docker in Docker method
2020-04-06T13:02:22.961Z testcontainers INFO: Pulling image: postgres:latest
2020-04-06T13:02:29.102Z testcontainers INFO: Creating container for image: postgres:latest
2020-04-06T13:02:30.761Z testcontainers INFO: Starting container with ID: 8735ecbb25cd26c084db2e009e6553fed518b2446e3d9a9a5edef1f9aec1b14c
2020-04-06T13:02:31.566Z testcontainers DEBUG: Waiting for container to be ready
2020-04-06T13:02:31.567Z testcontainers DEBUG: Waiting for host port 44063
2020-04-06T13:02:31.568Z testcontainers DEBUG: Waiting for internal port 5432
FAIL src/middleware/test/index.spec.ts
  ● Test suite failed to run

    TypeError: Cannot read property 'stop' of undefined

      26 | 
      27 | afterAll(async () => {
    > 28 |   await pgContainer.stop()
         |                     ^
      29 | })
      30 | 
      31 | describe('verify it works', function() {

      at ../src/middleware/clientAuth/index.spec.ts:28:21
      at ../src/middleware/clientAuth/index.spec.ts:8:71
      at Object.<anonymous>.__awaiter (../src/middleware/clientAuth/index.spec.ts:4:12)
      at Object.<anonymous>.afterAll (../src/middleware/clientAuth/index.spec.ts:27:21)

Jenkins pipeline that is responsible to orchestrate is something like this (I use NodeJS plugin with Node version of 10.19)

stage("test") {
                nodejs(nodeJSInstallationName: 'node_10') {
                    sh 'yarn && CI=1 yarn test'
                }   
            }

It looks like the similar issues that have been fixed in this repository but only thing that I can't make sense of is, this is pretty much the same setup I have in my Java project (which uses a Java plugin on Jenkins instead of a NodeJS one).

Is there any tip you could give me about further debugging this?
Thanks

TypeError: Cannot read property 'stop' of undefined

Hello,

First of all, thanks for the great library! 👍

I'm having a problem when running my test using jest - it happens only intermittently on my machine, but seems to happen all the time in CircleCI.

This is my test code:

let pgContainer: StartedTestContainer;
let pgPort: number;

beforeAll(async () => {
  pgContainer = await new GenericContainer("postgres", "11.5")
    .withEnv("POSTGRES_USER", "postgres")
    .withEnv("POSTGRES_PASSWORD", "postgres")
    .withExposedPorts(5432)
    .start();
  pgPort = pgContainer.getMappedPort(5432);
});

afterAll(async () => {
  await pgContainer.stop();
});

This is the error I get from jest:

Test suite failed to run

    TypeError: Cannot read property 'stop' of undefined

      20 | 
      21 | afterAll(async () => {
    > 22 |   await pgContainer.stop();
         |                     ^
      23 | });
      24 | 
      25 | describe("Database Integration", () => {

      at services/notifications/src/app.spec.ts:22:21
      at services/notifications/src/app.spec.ts:8:71
      at Object.<anonymous>.__awaiter (services/notifications/src/app.spec.ts:4:12)
      at Object.<anonymous> (services/notifications/src/app.spec.ts:21:21)

Thanks!

Container startup errors are muted

I recently ran into an issue where a container failed to start, and the problem was tricky to track down because testcontainers does not expose the error. Even when running with DEBUG=testcontainers, the output does not include errors at startup. In the end I had to manually start the container with docker run <image> in order to find the error.

We're starting the container with the following code (simplified):

try {
  logger.info('Starting container');
  const container = await new GenericContainer('image-name')
    .withCmd(['node', 'test-script'])
    .withExposedPorts(3000)
    .withWaitStrategy(Wait.forLogMessage('Ready on'))
    .start();

  /* ... stuff ... */
} catch (err) {
  logger.error('Failed to do stuff', err);
  process.exit(2);
}

The output I get from this is unhelpful:

$ DEBUG=testcontainers node do-stuff.js
[INFO] - Starting container...
  testcontainers INFO: Using Docker defaults +0ms
  testcontainers INFO: Creating container for image: image-name:latest +48ms
  testcontainers INFO: Starting container with ID: <hash> +53ms
  testcontainers DEBUG: Waiting for container to be ready +292ms
  testcontainers DEBUG: Waiting for log message "Ready on" +1ms
[ERROR] - Failed to do stuff

When I start the container manually with docker run image-name I get the actual error message (in my case, a simple syntax error in test-script.js).

Ideally the error would be exposed in the catch block in the code above. Currently err is undefined.

Support startup command

Hi, Would be nice to be able to run commands when creating a container. Something such as:

new GenericContainer("redis")
    .withCommand("redis-server --port 7777")

Is it already possible?

If not, I'd be glad to help with this or any other enhancement that might be in the roadmap.
Thanks!

Docker Compose ?

Hello,

is there any way to use with a set of services, using a docker-compose.yml ? or is there any plan to add this functionality ?

thanks for testcontainers-node !

Add option to remove volumes on stop

Feature Request

When running an official image (such as postgres) you're stuck with the VOLUMEs that it declares. This has the unfortunate effect of having your tests accumulate anonymous volumes, as can be seen with docker volume ls. It would be really helpful if there was an option to remove any associated volumes when a container is stopped (which would actually be handled by passing the option to the underlying call to dockerode's remove()):
https://docs.docker.com/engine/api/v1.37/#operation/ContainerDelete

Workaround:

It's pretty nasty, but you can set the underlying container's default options for remove (but obviously it would be better not to break the abstraction):

(pgContainer as any).container.container.defaultOptions.remove.v = true;

Allow arguments to container.stop()

Feature Request

It would be helpful to be able to pass arguments to to container.stop() which are propagated to the underlying dockerode container.stop(). This would allow specifying the timeout, t, that the container will wait before it is killed:
https://docs.docker.com/engine/api/v1.37/#operation/ContainerStop

When dealing with an ephemeral container for a test, you often don't care about it shutting down cleanly, since you'll be throwing it away. In order to achieve this in my tests I have to currently do a hacky (and brittle) workaround of setting the underlying container's default options for stop:

(testContainer as any).container.container.defaultOptions.stop.t = 1;
await testContainer.stop();

It would be much nicer to instead just call the top-level stop with arguments:

await testContainer.stop({ t: 1 });

Ability to restart a container

Adding a .restart() method on the StartedTestContainer interface would be really useful, and possibly more efficient/faster than having to .stop() and .start() in between tests.

e.g. Writing integration tests for a MySQL database where each test invocation is expected to have an empty database.

Can't connect to postgres container

I'm facing some troubles when trying to connect to Postgres container. In my integration tests, I'm using jest and supertest to run...

This is the error message

findAll() >> Error: Error: connect ECONNREFUSED 127.0.0.1:5432
          at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1083:14)

And here is my test class:

const { GenericContainer } = require('testcontainers');
const request = require('supertest');

const { Promise } = require('bluebird')
const cmd = require('node-cmd');

const app = require('../../app');

describe('User routes', () => {
  jest.setTimeout(45000);

  let container = '';

  beforeAll(async () => {
    container = await new GenericContainer('postgres', 'alpine')
      .withEnv('POSTGRES_USER', 'bidu')
      .withEnv('POSTGRES_PASSWORD', 'test')
      .withExposedPorts(5432)
      .start();

    process.env.DATABASE_URL = `postgres://bidu:test@localhost:${container.getMappedPort(
      5432
    )}/bidu`;

    const getAsync = Promise.promisify(cmd.get, { multiArgs: true, context: cmd })

    await getAsync('npm run migrate up').then(data => {
      console.log('cmd data', data)
    }).catch(err => {
      console.log('cmd err', err)
    });
  });

  afterAll(async () => {
    await container.stop();
  });

  test('should return 200 on get all users', async (done) => {
    request(app)
      .get('/v1.0/users/all')
      .end((err, res) => {
        console.log(res);
        expect(res).not.toBeNull();
        expect(res.statusCode).toBe(200);
        done();
      });
  });
});

Could you give more examples of how to connect with Postgres or something like that?

Use a Kafka container

Hi great library thanks for it.
Does it support to run a kafka server?
I tried a basic generic container but probably I don't understand how to do it correctly.

Thanks in advance for you answer.

Build from local Dockerfile

Hey,

Just a quick note asking if building images from a local Dockerfile was on your roadmap? From what I can see, that is not currently supported. To be clear, what I mean is creating a GenericContainer from a Dockerfile that you keep within the repository itself.

dynamodb-local inside Gitlab CI

I can't get amazon/dynamodb-local image work inside Gitlab CI. Note that it works locally without any problems. I haven't tried if this works in testcontainers-java, cc @rnorth

I'm using CI settings from docs.

My .gitlab-ci.yml:

image: node:12

stages:
  - prepare
  - test

# DinD service is required for Testcontainers
services:
  - docker:dind

variables:
  DOCKER_HOST: 'tcp://docker:2375'
  DOCKER_DRIVER: overlay2

install_packages_run_linters:
  stage: prepare
  script:
    - yarn install
    - yarn lint
  artifacts:
    expire_in: 1 hour
    paths:
      - ./node_modules

test:unit:
  stage: test
  script:
    - DEBUG=testcontainers yarn test --runInBand --coverage
  coverage: '/All files[^|]*\|[^|]*\s+([\d\.]+)/'
  dependencies:
    - install_packages_run_linters

I'm setting up container like this:

const startedContainer = new GenericContainer("amazon/dynamodb-local").withExposedPorts(8000).start()

Relevant CI output:

�[0KRunning with gitlab-runner 11.11.0-rc2 (7f58b1ec)
�[0;m�[0K  on docker-auto-scale 0277ea0f
�[0;msection_start:1557296045:prepare_executor
�[0K�[0KUsing Docker executor with image node:12 ...
�[0;m�[0KStarting service docker:dind ...
�[0;m�[0KPulling docker image docker:dind ...
�[0;m�[0KUsing docker image sha256:6204caf6c5927058f10fab0e4661b5f7a37d9a986a89b28a176a9958a0a5b7d3 for docker:dind ...
�[0;m�[0KWaiting for services to be up and running...
�[0;m�[0KPulling docker image node:12 ...
�[0;m�[0KUsing docker image sha256:c77f0d290562eefd2c9e5481cc1707f40a43d2dd5f7719384bd3b8f05699ffd7 for node:12 ...
�[0;msection_end:1557296093:prepare_executor
�[0Ksection_start:1557296093:prepare_script
�[0KRunning on runner-0277ea0f-project-12215658-concurrent-0 via runner-0277ea0f-srm-1557295996-5afcffc7...
section_end:1557296098:prepare_script
�[0Ksection_start:1557296098:get_sources
�[0KInitialized empty Git repository in /builds/Meemaw/meshwatch-backend-core/.git/
�[32;1mFetching changes...�[0;m
�[32;1mCreated fresh repository.�[0;m
From https://gitlab.com/Meemaw/meshwatch-backend-core
 * [new branch]      master     -> origin/master
�[32;1mChecking out fb1e6645 as master...�[0;m

�[32;1mSkipping Git submodules setup�[0;m
section_end:1557296100:get_sources
�[0Ksection_start:1557296100:restore_cache
�[0Ksection_end:1557296101:restore_cache
�[0Ksection_start:1557296101:download_artifacts
�[0K�[32;1mDownloading artifacts for install_packages_run_linters (208940828)...�[0;m
Downloading artifacts from coordinator... ok      �[0;m  id�[0;m=208940828 responseStatus�[0;m=200 OK token�[0;m=oi_pU5bU
section_end:1557296112:download_artifacts
�[0Ksection_start:1557296112:build_script
�[0K�[32;1m$ DEBUG=testcontainers yarn test --runInBand --coverage�[0;m
yarn run v1.15.2
warning package.json: No license field
$ tsdx test --verbose --runInBand --coverage
2019-05-08T06:15:26.975Z testcontainers Pulling image: amazon/dynamodb-local:latest
2019-05-08T06:15:44.045Z testcontainers Creating container for image: amazon/dynamodb-local:latest
2019-05-08T06:15:44.875Z testcontainers Starting container with ID: 32d5a7fed1d39799e6093fa46c52e8901156043e3b1bdf2bedd937d486133ff9
2019-05-08T06:15:46.372Z testcontainers Waiting for host port :39113
2019-05-08T06:15:46.376Z testcontainers Waiting for internal port :8000
FAIL test/monitoring-service.spec.ts (72.17s)
  MonitoringService
    with DynamoStorage
      bookmarkMonitor
        ✕ should_bookmarkMonitor_when_monitorIdPassed (14ms)
        ✕ should_return404_when_bookmarkMonitorWithRandomId
      deleteMonitor
        ✕ should_deleteMonitor__when_newlyCreatedMonitorParamsPassed (1ms)
        ✕ should_return404_when_deleteMonitorWithRandomId
      getMonitorsByScheduler
        ✕ should_getEmptyCollection_when_searchByRandomScheduler (1ms)
        ✕ should_getMonitors_when_searchByTestScheduler
      getMonitors
        ✕ should_getEmptyCollection_when_searchByRandomUserId
        ✕ should_getTestMonitors_when_searchByTestUserId (1ms)
      createMonitor
        ✕ should_createNewMonitor_when_createMonitorPayloadPassed
        ✕ should_returnBoomWithFieldError_when_invalidCreateMonitorPayloadPassed
        ✕ should_returnBoomWithFieldErrors_when_emptyObjectPassed (1ms)
      updateMonitor
        ✕ should_updateMonitor_when_updateMonitorPayloadIsPassed
        ✕ should_returnBoomWithFieldError_when_createMonitorPayloadPassed (1ms)

  � MonitoringService › with DynamoStorage › bookmarkMonitor › should_bookmarkMonitor_when_monitorIdPassed

    Port :39113 not bound after 40000ms
```

Option to remove a container

Hello,

Would it make sense to implement a wrapper around dockerode.remove()?

I want to clean up containers after tests have finished running. Instead of installing dockerode separately in my application, this could be a nice enhancement to the library. I think it's a quite straightforward feature, but just to provide an example, I'd like to be able to do something like this.

afterAll(() => {
	pgContainer.stop({ timeout: new Duration(10, TemporalUnit.SECONDS) })
	pgContainer.remove()
})

I'll be happy to create a PR if that gets approval from maintainers... :)

Support docker networks in order to resolve containers IPs by name

Hello!

I am trying to connect two containers but without any success. The only way I know to achieve this is using networks.

I've tried to add the feature myself but I am struggling a bit with typescript. Can I make this possible without networks?

I have this workaround using dockerode

const opts = {
    "limit": 1,
    "filters": `{"name": ["${mysql.getName()}"]}`
};
const container = (await dockerode.listContainers(opts))[0];
const mysqlContainer = dockerode.getContainer(container.Id);
const ins = await mysqlContainer.inspect();
console.log(`My working IP! ${ins.NetworkSettings.IPAddress}`);

Regards!

(HTTP code 400) bad parameter - Client sent an HTTP request to an HTTPS server.

I always run into this error when running npm run test

(HTTP code 400) bad parameter - Client sent an HTTP request to an HTTPS server.


      at node_modules/docker-modem/lib/modem.js:257:17
      at getCause (node_modules/docker-modem/lib/modem.js:287:7)
      at Modem.Object.<anonymous>.Modem.buildPayload (node_modules/docker-modem/lib/modem.js:256:5)
      at IncomingMessage.<anonymous> (node_modules/docker-modem/lib/modem.js:232:14)

I totally have no idea why.

a few info that may help

node: v10.16.1
Docker version 18.09.3, build 774a1f4eee -- using docker toolbox instead of desktop

cheers!

getContainerIpAddress() does not work as expected in Gitlab CI docker runner

I have a similar issue like #7

I am starting two docker containers in my tests (postgres and rabbitMQ). Then I construct the connection strings using container.getContainerIpAddress() and container.getMappedPort(). Everything works locally. However, in Gitlab CI I get the following error.

     Error: connect ECONNREFUSED 127.0.0.1:44937
      at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1056:14)

When checking the value of getContainerIpAddress() it always returns localhost even when run in the Gitlab CI docker runner. While the Java counter part of testcontainers returns a real IP address like 172.17.0.1 in Gitlab CI.

Can you adjust your code to behave like your Java counter part?

Stopping containers is really slow

I'm not sure if it's something I'm doing wrong, but I'm finding that stopping containers is really slow.

My code for this is:

        close: async () => {
            logger.info('Stopping test database');
            await postgres.stop();
            logger.info('Stopped test database');
        },

And the output from this is:

[2019-09-12 08:25:48.820 +0000] INFO (nuworlds.database.wrapper/51357 on xxxxxxxx.local): Stopping test database
2019-09-12T08:25:59.120Z modem Received:
2019-09-12T08:25:59.121Z modem Sending: {
  path: '/containers/ecebe4e47716f5a4bd67f355de63d7cb5eccfa8cf34e5926b8c6c07a3db95a0c?v=true',
  method: 'DELETE',
  headers: {},
  key: undefined,
  cert: undefined,
  ca: undefined,
  socketPath: '/var/run/docker.sock'
}
2019-09-12T08:25:59.180Z modem Received:
[2019-09-12 08:25:59.181 +0000] INFO (nuworlds.database.wrapper/51357 on xxxxxxxx.local): Stopped test database

Note the 11 seconds between my log statement and the actual call to delete the container. Given that this entire test ran in 15 seconds, this is a huge percentage of it.

Cheers

Cannot consume within typescript project

After installing testcontainers my typescript project no longer compiles. This is because testcontainerss types depend on @types/dockerode, however these are only a dev dependency of testcontainers and are thus not installed for consumers.

The fix is to convert @types/dockerode into a regular dependency.

See this thread for further explanation

complex shell commands fail with exec()

How does one exec complex commands on a container? Something like seq 5 | xargs -I INDEX echo "hi" for example? I tried all kind of things, but it fails, obviously command gets mingled on its way to the container. Escaping quotes or pipe characters doesn't seem to have any effect. Is this even possible?

Testcontainers should not run multiple disk checks at the same time

Hi,

I recently opened apocas/docker-modem#112 because I kept getting seemingly innocuous stack traces in my tests logs:

 console.error node_modules/jest-jasmine2/build/jasmine/Env.js:289
    Unhandled error

  console.error node_modules/jest-jasmine2/build/jasmine/Env.js:290
    Error: (HTTP code 500) server error - a disk usage operation is already running 
        at /home/jean/dev/startups/yupwego/src/yupwego/node_modules/docker-modem/lib/modem.js:257:17
        at getCause (/home/jean/dev/startups/yupwego/src/yupwego/node_modules/docker-modem/lib/modem.js:287:7)
        at Modem.Object.<anonymous>.Modem.buildPayload (/home/jean/dev/startups/yupwego/src/yupwego/node_modules/docker-modem/lib/modem.js:256:5)
        at IncomingMessage.<anonymous> (/home/jean/dev/startups/yupwego/src/yupwego/node_modules/docker-modem/lib/modem.js:232:14)
        at IncomingMessage.emit (events.js:187:15)
        at endReadableNT (_stream_readable.js:1094:12)
        at process._tickCallback (internal/process/next_tick.js:63:19)

@ehossack recently commented that he started observing these messages after upgrading from testcontainers 2.0.0 to testcontainers 2.1.0 and suggests it may be related to the changes in #42

It seems testcontainers is attempting to run multiple disk free checks. It's a bit surprising because I can reproduce it with a single jest test which starts the container in a beforeAll and stops it in an afterAll

Container version tags don't work as expected

When I'm using TestContainers with just an image name and nothing else, everything works fantastic. However, if I use a versioned image name then for some reason the container now no longer works.

For example, this works great:

    const postgres = await new GenericContainer('postgres')
        .withExposedPorts(5432)
        .start();

But this doesn't:

    const postgres = await new GenericContainer('postgres:11.5-alpine')
        .withExposedPorts(5432)
        .start();

On the second, I get the following output:

    (HTTP code 400) unexpected - invalid reference format

      at node_modules/docker-modem/lib/modem.js:257:17
      at getCause (node_modules/docker-modem/lib/modem.js:287:7)
      at Modem.Object.<anonymous>.Modem.buildPayload (node_modules/docker-modem/lib/modem.js:256:5)
      at IncomingMessage.<anonymous> (node_modules/docker-modem/lib/modem.js:232:14)

Cheers

Built container could not be found during tests

Hi,

I am currently facing the issue, that my freshly built container could not be found to start it for the tests.

const appPort: number = 3000

let appImage: GenericContainer = new GenericContainer(image)
if (!image) {
  appImage = await GenericContainer.fromDockerfile(path.resolve(__dirname, '..'))
}

const bully: StartedTestContainer = await appImage.withExposedPorts(appPort).start()

This fails with:

pull access denied for 5668e0a8f7a4fb86f08d814c41dc4402, repository does not exist or may require 'docker login'

The uuid 5668e0a8f7a4fb86f08d814c41dc4402 is the generated one.

Does somebody else had those issues before?
Is there a solution for it?

Can't run in AWS CodeBuild after version 1.3.1

When running versions higher than 1.3.1 in AWS CodeBuild I get an error saying "Error: Port :39195 not bound after 60000ms".

This is the full output running with "DEBUG=testcontainers":

2020-02-03T12:35:46.072Z testcontainers INFO: Using Docker in Docker method
2020-02-03T12:35:46.106Z testcontainers INFO: Pulling image: postgres:11.5
2020-02-03T12:35:58.817Z testcontainers INFO: Creating container for image: postgres:11.5
2020-02-03T12:36:00.850Z testcontainers INFO: Starting container with ID: 25734549ff033c92c0fb07ce168387f69d6d6e823f86e88467097dc1bf3f7707
2020-02-03T12:36:01.504Z testcontainers DEBUG: Starting container health checks
2020-02-03T12:36:01.505Z testcontainers DEBUG: Waiting for host port :39195
2020-02-03T12:36:01.508Z testcontainers DEBUG: Waiting for internal port :5432
Error: Port :39195 not bound after 60000ms
    at retryStrategy.retryUntil (/codebuild/output/src627916599/src/github.com/Pepins/pepinsx/lambda-js/node_modules/testcontainers/dist/wait-strategy.js:59:23)
    at IntervalRetryStrategy.<anonymous> (/codebuild/output/src627916599/src/github.com/Pepins/pepinsx/lambda-js/node_modules/testcontainers/dist/retry-strategy.js:35:28)
    at Generator.next (<anonymous>)
    at fulfilled (/codebuild/output/src627916599/src/github.com/Pepins/pepinsx/lambda-js/node_modules/testcontainers/dist/retry-strategy.js:4:58)
    at process._tickCallback (internal/process/next_tick.js:68:7)

My code looks like this:

dbContainer = await new GenericContainer('postgres', '11.5')
    .withEnv('POSTGRES_PASSWORD', 'xxxx')
    .withEnv('POSTGRES_USER', 'yyyy')
    .withExposedPorts(5432)
    .start();

I'm using the aws/codebuild/standard:1.0 image in AWS CodeBuild.

How can I view container logs?

Hi. I'm running two test containers during my integration tests using Jest. One is based on postgres and the other is for a migrations app based on a local Dockerfile. They both seem to be running correctly, but I would like to see their output (STDOUT) and it is not clear to me from the documentation how I can do this.

DEBUG=testcontainers only outputs docker image build and container creation.

withDefaultLogDriver has no effect.

container.stop() is not a function

Hi there, thanks for the great node lib!

I'm using it to run some tests with jest and getting the message:

Test suite failed to run
    TypeError: pgContainer.stop is not a function

My code:

/* eslint-disable no-undef */
const { GenericContainer } = require('testcontainers');
const pgContainer = new GenericContainer('postgres').withEnv('POSTGRES_USER', 'test').withEnv('POSTGRES_PASSWORD', 'test').withExposedPorts(5432);

beforeAll(async () => {
  await pgContainer.start();
});

afterAll(async () => {
  await pgContainer.stop();
});

describe('Controller' tests, () => {
  it('should create something', () => {
    expect(1).toEqual(1);
  });
});

Any ideas why is this happening?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.