Continuous Integration

In this section we will setup continuous integrations to address the following:

  1. Have a basic CI task for each module: like running unitary tests, etc
  2. Automatically build and publish docker images: to update the images in a docker registry
  3. Run integration tests (docker composed): we basically want to have the integations tests that we dockerized automatically being run

Basic CI for our projects

To follow our example app from scratch we need to do step 1 but if you are using your own project and already have tests and CI then you can just skip this part.

Testing the frontend

First we need to create at least one test for our React component :P

So install dependencies to test

yarn add -D mocha chai enzyme react-dom react-test-renderer react-addons-test-utils

Then we need to setup babel (should have done this before :P) Edit .babelrc and add 'react' preset

{
  "presets": ["es2015", "stage-0", "react"],
  "plugins": [
    ["transform-runtime", {
      "polyfill": false,
      "regenerator": true
    }]
  ]
}

Now add a "test" script to package.json

"test": "mocha --compilers js:babel-register test/**/*_spec.js",

And lets create a test

First we need to edit the src/components/UsersList.jsx file in order to export the bare component (without artemisa decoration, so we don't test actual fetching). Add the following

export const UserListComponent = UsersList

Now create a test

mkdir test
touch test/UserListComponent_spec.js

With the content:

import React from 'react';
import { mount, shallow } from 'enzyme';
import { expect } from 'chai';

import { UserListComponent } from '../src/components/UsersList';

describe('<UserListComponent/>', () => {
  it('should render nothing if it is not fetched', () => {
    const wrapper = shallow(<UserListComponent users={{ state: 'fetching' }}/>)
    expect(wrapper.text()).to.contain('IdNameCreated')
  })

  it('should render two users', () => {
    const value = [
      { _id: 1, name: 'docker', created_at: '2017-01-01' },
      { _id: 2, name: 'dockerCompose', created_at: '2017-01-02' }
    ]
    const wrapper = shallow(<UserListComponent users={{ state: 'fetched', value }} />)
    expect(wrapper.contains(<td>docker</td>)).to.equal(true)
    expect(wrapper.contains(<td>dockerCompose</td>)).to.equal(true)
  })
})

And now just run:

yarn test

:)

CI for the frontend

Now we will use travis as CI service. So go ahead to https://travis-ci.org/ create an account if you don't have one, and give it permission to access your frontend's github repository.

Then create a file .travis.yml in the project with content

language: node_js
node_js:
  - "7"
cache: yarn

And add the badge to the README.md

[![Build Status](https://travis-ci.org/javierfernandes/docker-e2e-frontend.svg?branch=master)](https://travis-ci.org/javierfernandes/docker-e2e-frontend)

Now git push and you will see it building and the badge should be green like this

Build Status

Testing the backend

We should do the proper in the backend, like creating some mocha tests for routes and models. I'll skip that here.

Travis configuration is the same as we did for the frontend.

Building & Publishing Docker images from CI

Now the fun part, we want travis to build each project docker image and publish it in a repository.

First of all, before making this automatic we will do it manually, so, lets publish our images

Manually publishing docker images

First you will need to go to https://hub.docker.com/ and register.

Now go to your frontend repo folder and build the image manually (we are providing a name here for the image)

docker build -t e2e-frontend .

Now lets grab some information from it

docker images e2e-frontend

REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
e2e-frontend        latest              7380611160ab        49 seconds ago      768 MB

We will need the IMAGE ID to now tag it

docker tag 7380611160ab jfernandes/e2e-frontend

And now before pushing we need to provide credentials to the docker command

docker login --username=jfernandes

(of course change your username)_

Now lets publish it

docker push jfernandes/e2e-frontend

It will take some time to upload the layers, and after that you will be able to see the image in dockerhub

For example https://hub.docker.com/r/jfernandes/e2e-frontend/

That is it, we did a manual publishing of our frontend image. We should do the same with backend and e2e-tests modules.

Building Images from Travis

Now we will configure travis to do this automatically for us.

We need to edit .travis.yml. To be able to use docker we need to add

sudo: required
services:
  - docker

And then we will setup in the following way:

  • Only trigger executing on pushes to master branch
  • Build an image using travis build number (autonumeric) as the version
  • Publish that using user and password configured as env vars in travis.
after_success:
  - if [ "$TRAVIS_BRANCH" == "master" ]; then
    docker build -t jfernandes/e2e-frontend:$TRAVIS_BUILD_NUMBER .; 
    docker login --username="$DOCKER_USERNAME" --password="$DOCKER_PASSWORD";
    docker push jfernandes/e2e-frontend:$TRAVIS_BUILD_NUMBER;
    fi

Now you need to go to travis settings for this project and add two en vars DOCKER_USERNAME and DOCKER_PASSWORD

That is all, now just push the commit and it will run automatically. After execution you will see a new tag in dockerhub.

CI for e2e tests

Now for the e2e-tests module we need to use the same approach, just that travis configuration is different since we don't want to build the image, but just run it, and we also use docker-compose instead of docker with Dockerfile.

This is .travis.yml file

sudo: required

services:
  - docker

before_install:
  - docker-compose build 

script:
  - docker-compose run tests

Now again enable travis for this repo and push it. It should run the tests fine ! :)

Conclusion so far

We were able to automatize a couple of tasks for each module of the app: frontend, backend, and e2e-tests. Those tasks are:

  • what we usually (wrongly) call C.I., which is to run each individual module tests/checks.
  • build and publish each module's docker image into dockerhub registry (with some small changes this could also apply to private registries. See "Extras")
  • Automatically run e2e tests in a server (which is not so easy, since running GUI-dependent tests is not a trivial task. We were able to wrap those tests in a virtual environment by using docker, and that introduced the need to build docker images.

This is great, but we are still not done. We need to link each module development lifecycle so that e2e tests run upon changes to any of the modules besides itself. And ideally providing "acceptance" checks to Pull requests as the modules regular CI does by integrating with Github hooks/Status API.

Lets continue then !

< Back | Next >

results matching ""

    No results matching ""