We had a great experience using Docker Compose to orchestrate Notes application deployment. The whole system, with four independent services, is easily described in compose/docker-compose.yml. What we'll do is duplicate the Compose file, then make a couple of small changes required to support test execution.
Let's start by making a new directory, test-compose, as a sibling to the notes, users, and compose directories. Copy compose/docker-compose.yml to the newly created test-compose directory. We'll be making several changes to this file and a couple of small changes to the existing Dockerfiles.
We want to change the container and network names so our test infrastructure doesn't clobber the production infrastructure. We'll constantly delete and recreate the test containers, so as to keep the developers happy, we'll leave development infrastructure alone and perform testing on separate infrastructure. By maintaining separate test containers and networks, our test scripts can do anything they like without disturbing the development or production containers.
Consider this change to the db-auth and db-notes containers:
db-userauth-test:
build: ../authnet
container_name: db-userauth-test
networks:
- authnet-test
environment:
MYSQL_RANDOM_ROOT_PASSWORD: "true"
MYSQL_USER: userauth-test
MYSQL_PASSWORD: userauth-test
MYSQL_DATABASE: userauth-test
volumes:
- db-userauth-test-data:/var/lib/mysql
restart: always .. db-notes-test:
build: ../frontnet
container_name: db-notes-test
networks:
- frontnet-test
environment:
MYSQL_RANDOM_ROOT_PASSWORD: "true"
MYSQL_USER: notes-test
MYSQL_PASSWORD: notes12345
MYSQL_DATABASE: notes-test
volumes:
- db-notes-test-data:/var/lib/mysql
restart: always
This is the same as earlier, but with -test appended to container and network names.
That's the first change we must make, append -test to every container and network name in test-compose/docker-compose.yml. Everything we'll do with tests will run on completely separate containers, hostnames, and networks from those of the development instance.
This change will affect the notes-test and userauth-test services because the database server hostnames are now db-auth-test and db-notest-test. There are several environment variables or configuration files to update.
Another consideration is the environment variables required to configure the services. Previously, we defined all environment variables in the Dockerfiles. It's extremely useful to reuse those Dockerfiles so we know we're testing the same deployment as is used in production. But we need to tweak the configuration settings to match the test infrastructure.
The database configuration shown here is an example. The same Dockerfiles are used, but we also define environment variables in test-compose/docker-compose.yml. As you might expect, this overrides the Dockerfile environment variables with the values set here:
userauth-test:
build: ../users
container_name: userauth-test
depends_on:
- db-userauth-test
networks:
- authnet-test
- frontnet-test
environment:
DEBUG: ""
NODE_ENV: "test"
SEQUELIZE_CONNECT: "sequelize-docker-test-mysql.yaml"
HOST_USERS_TEST: "localhost"
restart: always
volumes:
- ./reports-userauth:/reports .. notes-test:
build: ../notes
container_name: notes-test
depends_on:
- db-notes-test
networks:
- frontnet-test
ports:
- "3000:3000"
restart: always
environment:
NODE_ENV: "test"
SEQUELIZE_CONNECT: "test/sequelize-mysql.yaml"
USER_SERVICE_URL: "http://userauth-test:3333"
volumes:
- ./reports-notes:/reports
...
networks:
frontnet-test:
driver: bridge
authnet-test:
driver: bridge
volumes:
db-userauth-test-data:
db-notes-test-data:
Again, we changed the container and network names to append -test. We moved some of the environment variables from Dockerfile to test-compose/docker-compose.yml. Finally, we added some data volumes to mount host directories inside the container.
Another thing to do is to set up directories to store test code. A common practice in Node.js projects is to put test code in the same directory as the application code. Earlier in this chapter, we did so, implementing a small test suite in the notes/test directory. As it stands, notes/Dockerfile does not copy that directory into the container. The test code must exist in the container to execute the tests. Another issue is it's helpful to not deploy test code in production.
What we can do is to ensure that test-compose/docker-compose.yml mounts notes/test into the container:
notes-test:
...
volumes:
- ./reports-notes:/reports
- ../notes/test:/notesapp/test
This gives us the best of both worlds.
- The test code is in notes/test where it belongs
- The test code is not copied into the production container
- In test mode, the test directory appears where it belongs
We have a couple of configuration files remaining for the Sequelize database connection to set up.
For the userauth-test container, the SEQUELIZE_CONNECT variable now refers to a configuration file that does not exist, thanks to overriding the variable in user/Dockerfile. Let's create that file as test-compose/userauth/sequelize-docker-mysql.yaml, containing the following:
dbname: userauth-test
username: userauth-test
password: userauth-test
params:
host: db-userauth-test
port: 3306
dialect: mysql
The values match the variables passed to the db-userauth-test container. Then we must ensure this configuration file is mounted into the userauth-test container:
userauth-test:
...
volumes:
- ./reports-userauth:/reports
- ./userauth/sequelize-docker-test-mysql.yaml:/userauth/sequelize-
docker-test-mysql.yaml
For notes-test we have a configuration file, test/sequelize-mysql.yaml, to put in the notes/test directory:
dbname: notes-test
username: notes-test
password: notes12345
params:
host: db-notes-test
port: 3306
dialect: mysql
logging: false
Again, this matches the configuration variables in db-notes-test. In test-compose/docker-compose.yml, we mount that file into the container.