Configurando um CI

Como já temos a estrutura central de nosso projeto pronta (autenticação com postgres, gerenciamento de dados com DynamoDB e middlewares) podemos começar a pensar em um CI. Para isso, devemos considerar as restrições que temos no nosso make test, que executamos contra um container docker do psotgres:

db:
	docker run -i --rm --name auth-db -p 5432:5432 -e POSTGRES_USER=auth -e POSTGRES_PASSWORD=secret -d postgres

int: db
	sleep 2
	diesel setup
	diesel migration run
	cargo test --test lib --no-fail-fast --features "dbtest" -- --test-threads 3
	diesel migration redo


unit:
	cargo test --locked  --no-fail-fast --lib -- --test-threads 3

test: unit int

Nosso Makefile para testes consistem em 3 alvos int para testes de integração, unit para testes unitários e test para executar os dois. Algo que podemos ficar em dúvida é o porquê deles estarem separados em int e unit, o motivo é simplesmente que é mais fácil executar os testes unitários e eles são executados mais rapidamente que os de integração. Bom, vamos aos nossos alvos de teste. o alvo unit possui as flags --lib que executa somente os testes encontrados nos módulos de lib.rs e a flag --no-fail-fast que executa todos os testes mesmo que algum deles falhe. Para um CI é bastante útil esta flag de --no-fail-fast, pois queremos saber tudo que precisamos corrigir e, assim, não precisarmos ficar corrigindo a cada commit para a branch. Já o teste de integração possui diversos passos:

  1. executa o target db, que sobe um container docker com postgres.
  2. sleep 2 pausa o processo por 2 segundos até que o container se estabilize.
  3. diesel setup, falamos anteriormente, mas ajuda o diesel a configurar o banco recém gerado (pode não ser necessário).
  4. disel migration run, executa as migrações para o banco.
  5. cargo test, os testes em si.
  6. diesel migration redo, não precisa estar presente no CI, pois o contaienr com postgres será destruido depois da execução, não necessitando fazer rollback das migrações.

Agora vamos entender o item 5. Executamos o cargo test com a flag --test que indica que vamos executar os testes de integração apenas do arquivo lib.rs, que contém nossos módulos. Depois ativamos a feature dbtest com --features "dbtest". Agora que sabemos os passos que precisamos executar no CI podemos começar a pensar em sua criação.

Travis-CI

O modelo de CI que escolhi para este projeto é o Travis-CI, pois acredito que seja bem simples e executa tudo que precisamos fazer, build e testes. Para executar o travis-ci é necessário entrar no site deles, https://travis-ci.org/, se registrar e dar permissão para o seu github, existe um botão que já faz a autorização e o registro Sign in with github. Caso seus repositórios não apareçam, sugiro clicar em profile, imagem no canto superior direito, e na página de profile clicar em sync account. Agora basta você dar permissão para os repositórios específicos clicando nas chaves ao lado do nome dos repositórios.

Uma vez que esse processo de registro estiver pronto, você vai precisar adicionar um arquivo .travis.yml ao seu repositório. Este arquivo é uma sequencia de comandos que o CI precisará executar. No nosso caso, este arquivo terá o seguinte formato:

language: rust
rust:
  - nightly
  - 1.40.0
  - stable
cache: cargo
services:
- postgresql
before_script:
- psql -c 'create database auth_db;' -U postgres
- echo "DATABASE_URL=postgres://postgres@localhost/auth_db" > .env
- cargo install diesel_cli --no-default-features --features=postgres
- diesel migration run
script:
- cargo build --verbose --all
- cargo test --locked  --no-fail-fast --lib
- cargo test --test lib --no-fail-fast --features "dbtest"

O primeiro passo é declarar qual linguagem que estamos utilizando, no nosso caso rust, language: rust. Depois disso, definimos quais targets de rust vamos executar nosso código. Como a versão de rust que eu estou suando é a 1.40, espero que o código tenha que passar pelo menos nesta versão, além disso, gostaria de testar em nightly e na última stable sob a chave rust:. Precisamos do cargo também, para isso salvamos seu conteúdo em cache com cache: cargo. O serviço que vamos utilizar como banco de dados é o postgres, assim é necessário declará-lo em services: - postgresql. O próximo passo corresponde aos scripts q devemos executar antes dos nossos cenários de teste, para isso utilizamos a chave before_script com os seguintes ítens:

  • psql -c 'create database auth_db;' -U postgres, corresponde ao diesel setup e nos permite criar a base de dados auth_db no postgres.
  • echo "DATABASE_URL=postgres://postgres@localhost/auth_db" > .env é preciso ter o campo DATABASE_URL configurado em seu .env para executar o DbExecutor, assim utilizamos o echo <campo exportado> > .env para enviar o campo exportado para .env.
  • cargo install diesel_cli --no-default-features --features=postgres instalamos o diesel_cli para poder executar as migrações.
  • diesel migration run, executamos as migrações.

Por último, definimos os scripts que vamos executar com a chave script::

  • cargo build --verbose --all, testar se o build funciona.
  • cargo test --locked --no-fail-fast --lib executar os testes unitários.
  • cargo test --test lib --no-fail-fast --features "dbtest", executar os testes de integração.

Quando comitarmos isso e habilitarmos o travis ler este repositório, teremos um resultado como este:

Resultado do Travis CI para o Todo Server

Agora podemos terminar nosso todo sever implementando um get by id.