Run code before starting a non-primary container


#1

I would like to run some integration tests for an application (A) which relies on another (internal) application (B) to be running (also inside a container). Application B requires some schema to be setup in a cassandra database (also running in a non-primary container) before it starts.

I’ve written one of the build steps to setup the cassandra database with the required schema, but I don’t know how to make the application B container run only after this step. Right now, it starts immediately after the cassandra container, and it errors because it can’t find the required schema.

Is there any way to execute some steps before starting one of the non-primary containers?


#2

If the things it is waiting for are all containerised, then you could containerise your tests as well, and then use Docker Compose to start everything. In DC you can set up dependencies between containers. I do this, and it works well - my integration test container is set to depend on all other containers.

Alternatively, you could set up a wait in your tests to check for the availability of database tables before it starts. In PHPUnit (which I will use an example because I am familiar with it) this is called a bootstrap, and is commonly used to set up autoloaders or do miscellaneous initialisation tasks.

Does your test framework allow for such a thing? You could set it up so it only does this test if an env var is a particular value, such that your tests do not perform the test when you run them locally.


#3

Docker Compose might be the way to go, but from what I’ve gathered it’s not very well supported by CircleCI.

This is not what I want. The tests can already wait. My problem is that I need to run some code before starting one of the non-primary containers.

Here’s how it looks like right now:

  1. cassandra container starts
  2. container with application B starts (and fails because cassandra is not setup)
  3. build step which sets up the cassandra database
  4. build step for tests for application A

Here’s how I want it:

  1. cassandra container starts
  2. set up cassandra database
  3. start container with application B
  4. run tests for application A

#4

It works for me just fine.

I am having trouble visualising how you are launching your containers (assuming that you’re not using Docker Compose). Would it help if readers could see your config.yml file?


#5

Here’s a simplified version, does this help?

version: 2
jobs:
  build:
    docker:
      - image: cassandra:2.0.14
      - image: application-B:0.0.1
  steps:
    - checkout
    - run:
        name: Setup database
        command: make setupdb
    - run:
        name: Run tests
        command: make test

#6

Ah cool, I didn’t know the docker key could take multiple entries :-).

Well alright then - the run commands are run in a strict sequence. Can you add one in the middle that contains a script or shell command that waits until it can retrieve something from the database? Maybe a quick bit of Python/PHP/etc, or even a shell loop?

Edit: or you could add it in front of your tests:

command: waitForCassandra && make test

#7

I feel like we’re going in circles. It’s the container with application B that fails to start because it needs the database to be setup, not the tests.


#8

Ah, yes, my bad. So, put a wait device inside application B? If it cannot connect to Cassandra, keep trying for X seconds.


#9

Even if I did that, the required schema would not be there. The code to setup the schema is in the current repository and I want it to run every time the CI runs, so I cannot put it in ApplicationB’s container either.


#10

Sounds like you need a combination then. Put a wait inside application B, and then run some code to set up the schema, perhaps in a new run section. Good luck!


#11

This topic was automatically closed 41 days after the last reply. New replies are no longer allowed.