Testing your Elixir + Phoenix + Postgres app with Github CI
Tags: elixir, github, ci, phoenix
Published: 2019-08-29 15:38:43


Originally posted on [nickvernij.nl](https://nickvernij.nl/blog/github-ci-elixir.html?ref=dev.to)

GitHub released their own CI recently, its UI and marketing look very fancy. I had to set up a new Elixir + Phoenix project and decided to give it a shot. 

It took me a full morning to get a green check, because the default elixir template is very minimal and the documentation for creating workflows is quite a lot of reading to get through.

There are some nooks and crannies to get through, but when you get it to work it's very powerful. Essentially, the default Elixir workflow is fine for testing your average Elixir library, however a Phoenix app will need some additional setup and services. In my example I needed to set-up a PostgreSQL service.

First of all we want to set the `MIX_ENV` environment variable, so when we use ecto, it knows it should setup the test database. We can define global environment variables when defining the container in which our tests will run.

```yaml
    container:
      image: elixir:1.9.1-slim
      env:
        MIX_ENV: test
```

## Setting up a database

But to use ecto we actually need a database. In the workflow definition we can define a list of services. These are docker images that are prerequisites for our our test steps to run.

This is what my services configuration looks like:
```yaml
    services:
      postgres:
        image: postgres
        ports:
          - 5432:5432
        env:
          POSTGRES_PASSWORD: postgres
          POSTGRES_USER: postgres
        options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 3
```

**Let's go through this service definition rule-by-rule:**

`image: postgres` defines which docker image to pull in, in my case I am using the official docker image for Postgres: [https://hub.docker.com/_/postgres](https://hub.docker.com/_/postgres)

```yaml
ports:
	- 5432:5432
```

We always have to define which ports we want to expose for our docker container. In this case I am just exposing the default Postgres port

```yaml
env:
  POSTGRES_PASSWORD: postgres
  POSTGRES_USER: postgres
```

The docker container we use has some environment variables defined, which it will use to configure the Postgres server. A full list of those variables can be found in the [Postgres Docker Hub description](https://hub.docker.com/_/postgres).

```yaml
options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
```

Lastly, we have to pass some additional options. These options will directly map to the `docker create` command. The reason we need to add this health check is because `docker create` exits before the container is actually ready to be used.

Luckily for us, there is a simple command `pg_isready` available, which we can check. As soon as the Postgres container is ready, your test run will continue.

## Connecting with the database

The default Elixir workflow should already have some `steps` defined. We are modifying the `Run Tests` step a bit so it will create a database and pass some additional environment variables.

All services defined will create a virtual host on the network, named after the service. This means you cannot simply reach the Postgres on localhost.

I have added an environment variable in my run step that exposes the name of the services.

```yaml
    - name: Run Tests
      run: mix test
      env:
        DB_HOST: postgres  
```

Additionally I modified my Mix test configuration to read this variable and fall back on localhost by default

```elixir
# Configure your database
config :myapp, MyApp.Repo,
  username: "postgres",
  password: "postgres",
  database: "myapp_test",
  hostname: System.get_env("DB_HOST", "localhost"),
  pool: Ecto.Adapters.SQL.Sandbox
```

## Running your tests
By default phoenix apps should have an alias for `mix run test` that runs `ecto.setup`, `ecto.migrate` and `test`. 

When pushing new commits to your repository, the workflow should trigger, do all kinds of magic and run this command for you.

You can find the full file in this gist: [https://gist.github.com/Nickforall/e49f5f3c37414e05f9a6c604accf2c3e](https://gist.github.com/Nickforall/e49f5f3c37414e05f9a6c604accf2c3e) 

If you have any questions feel free to hit me up on [twitter](https://twitter.com/nickforallnl)

### References
- [Use Github CI for Elixir Projects](http://rocket-science.ru/hacking/2019/08/19/use-github-ci-for-elixir-projects?utm_campaign=elixir_radar_204&utm_medium=email&utm_source=RD+Station) 
- [https://help.github.com/en/articles/workflow-syntax-for-github-actions#jobsjob_idservices](https://help.github.com/en/articles/workflow-syntax-for-github-actions#jobsjob_idservices) referenced August 29, 2019