[WIP] Wercker × parallel_tests

# why

Wercker上でのspecテスト完遂に30分ほど要するが、その時間を短縮して開発効率を改善したい。

※Wercker：Oracle提供のCIツール

# what

テストを並列実行する。

# how
```:環境
Ruby：2.2.3
Rails：5.0.0.1
RSpec：3.5.2
MYSQL2:0.4.5 
```

## local開発環境での実行
### テスト並列実行用のgem "[parallel_tests](https://gist.github.com/oleksiilevzhynskyi/2557639)" を導入。

`gemfile` に parallel_test を追加。

```:Gemfile
group :development, :test do
  gem 'parallel_tests'
end
```

### gemパッケージをインストール。

```
$ bundle install
```

### test用DB名に テスト環境変数 を追加

```ruby:config/database.yml
test:
  database: yourproject_test<%= ENV['TEST_ENV_NUMBER'] %>
```

### テスト用DB：yourproject_testの複製

`config/database.yml` の設定に応じてDBを作成。

```
$ bundle exec rake parallel:create RAILS_ENV=test
```

### schemaコピー

```
$ bundle exec rake parallel:prepare[4]
```

### rspec_test実行

```
$ bundle exec rake parallel:spec[4]
```
※`[]`は並列実行させるプロセス数


## Wercker環境での実行
### WerckerのdockerコンテナにDB作成
#### services

> The services statement allows you to start additional Docker containers and have them available (on the same Docker network) for your main container, i.e. the one that is running your pipeline.

> Services may be specified at the top level, in which case they will be available to all pipelines defined in the wercker.yml, or you can define them inside a particular pipeline statement.

> Each entry in the list follows the same syntax as the box statement.







DBを使う場合、 `service`にDB用の docker イメージを選択。
DBの設定は `env` オプションで指定。

```wercker.yml
services:
  - id: mysql:<version>
    env:
      MYSQL_USER: *** # DBのuser名
      MYSQL_PASSWORD: *** # DBのpassword
      MYSQL_DATABASE: *** # DBの名前
```

後の `rails-database-yml` コマンドは `services/env` プロパティで指定した内容の `database.yml` （DB名、ユーザー名、パスワードのDB）を作成。

```
build:
  steps:
    - rails-database-yml
```

### Werckerの同一dockerコンテナでDB複製

> Initializing a fresh instance
When a container is started for the first time, a new database with the specified name will be created and initialized with the provided configuration variables. Furthermore, it will execute files with extensions .sh, .sql and .sql.gz that are found in /docker-entrypoint-initdb.d. Files will be executed in alphabetical order. You can easily populate your mysql services by mounting a SQL dump into that directory and provide custom images with contributed data. SQL files will be imported by default to the database specified by the MYSQL_DATABASE variable.

> コンテナーが初めて開始されると、指定された名前の新しいデータベースが作成され、提供されている構成変数で初期化されます。 さらに、/ docker-entrypoint-initdb.dにある拡張子.sh、.sql、および.sql.gzのファイルを実行します。 ファイルはアルファベット順に実行されます。

> というわけで、 `/docker-entrypoint-initdb.d` にSQLファイルを置いたりすればいい感じにできます。
が、SQLファイルでは、 `MYSQL_DATABASE` に指定したDBに対してダンプファイルを流すだけですので、他のDBを作ったりすることはできません。

```wercker.yml
services:
  - id: mysql:5.7.21
    env:
      MYSQL_ROOT_PASSWORD: root_password
      MYSQL_USER: testuser
      MYSQL_PASSWORD: testuser
      MYSQL_DATABASE: testdb
    volumes:
      - "./mysql:/var/lib/mysql"
      - "./mysql/init:/docker-entrypoint-initdb.d"
```
DB は `1_create_db.sql` にて作成

```1_create_db.sql
create database test_db1;
create database test_db2;
```

```file_organization.
+ wercker.yml
+- mysql
    +- init
        + 1_create_db.sql
```
### 実行結果=failed
```rails-database-yml.output
config/database.yml already exists and will be overwritten
Auto detecting service
failed: Unable to auto detect service; please set "service" option
```
### box

Rubyのdockerイメージを選択する。

### volumes

```
volumes = docker run -v ./host/path:/container/path my_image
```
[volumes で指定したホストのディレクトリがマウントされるタイミング　＝　コンテナが起動した時](https://kuroeveryday.blogspot.com/2016/11/docker-compose-volumes.html)


### volumesのインデントを services に合わせる

```wercker.yml
services:
  - id: mysql:5.7.21
    env:
      MYSQL_ROOT_PASSWORD: ***
      MYSQL_USER: ***
      MYSQL_PASSWORD: ***
      MYSQL_DATABASE: ***
volumes:
  - ./sql:/docker-entrypoint-initdb.d
```



```output.rails-database-yml
ActiveRecord::AdapterNotSpecified: 'development' database is not configured. Available: ["test"]
```
このとき `rails-database-yml` のレスポンスは下記

```file_organization.
+ wercker.yml
+- sql
    + 000_create_db.sql
```

```rails-database-yml.output
config/database.yml already exists and will be overwritten
Auto detecting service
Generating mysql docker template
test:
    adapter: mysql2
    encoding: utf8
    database: <%= ENV['MYSQL_ENV_MYSQL_DATABASE'] %><%= ENV['TEST_ENV_NUMBER'] %>
    username: <%= ENV['MYSQL_ENV_MYSQL_USER'] %>
    password: <%= ENV['MYSQL_ENV_MYSQL_PASSWORD'] %>
    host: <%= ENV['MYSQL_PORT_3306_TCP_ADDR'] %>
    port: <%= ENV['MYSQL_PORT_3306_TCP_PORT'] %>
```

### DB schema load

```Command.
RAILS_ENV=test bundle exec rake db:migrate:reset
```

```Output.
Mysql2::Error: Access denied for user 'testuser'@'%' to database '***'
```

### multiple services
[ Wercker Documentation > Administration > Services ](https://devcenter.wercker.com/administration/services/) を参考に修正

> Services are separate containers that run alongside your Pipelines. Examples of services are testing databases and message queues. You specify service containers in your wercker.yml file through the services section:

```wercker.yml
services:
  - name: testdb
    id: mysql:5.7.21
    env:
      MYSQL_ROOT_PASSWORD: root_password
      MYSQL_USER: testuser
      MYSQL_PASSWORD: testuser
      MYSQL_DATABASES: testdb
  - name: testdb2
    id: mysql:5.7.21
    env:
      MYSQL_ROOT_PASSWORD: root_password
      MYSQL_USER: testuser
      MYSQL_PASSWORD: testuser
      MYSQL_DATABASES: testdb
  - name: testdb3
    id: mysql:5.7.21
    env:
      MYSQL_ROOT_PASSWORD: root_password
      MYSQL_USER: testuser
      MYSQL_PASSWORD: testuser
      MYSQL_DATABASES: testdb
  - name: testdb4
    id: mysql:5.7.21
    env:
      MYSQL_ROOT_PASSWORD: root_password
      MYSQL_USER: testuser
      MYSQL_PASSWORD: testuser
      MYSQL_DATABASES: testdb
```

```Output.
failed: Unable to auto detect service; please set "service" option
```

### 参考

1. [docker-composeでmysql使うとき初回起動時に複数のDBを作る方法](https://qiita.com/takyam/items/de87252fca60a9c914c6)
2. [MySQL Docker Official Images](https://hub.docker.com/_/mysql/)
3. [wercker/docker-compose support? #63](https://github.com/wercker/wercker/issues/63)
4. [DockerでMySQL/PostgreSQLの初期データが生成されないときに確認すること](https://qiita.com/enta0701/items/8e1fd797178c372769c7)
5. [github/docker-library/mysql/5.5/docker-entrypoint.sh](https://github.com/docker-library/mysql/blob/78c736cef063f6c69256aa34f87ee463949af34f/5.5/docker-entrypoint.sh)
6. [Docker MySQL公式イメージを使用してDBに初期データを流し込む](https://qiita.com/furu8ma/items/75e5b1df29fef04ec7f1)
7. ×　[RSpec + parallel_tests + CircleCIで並列テストする](https://qiita.com/h-sakano/items/98c3fdd718010f48740b)
8. [ユーザ権限の確認・追加](https://qiita.com/pinohara/items/481c95dc4c8c2568bf8d)
9. [ Wercker Documentation > Administration > Services ](https://devcenter.wercker.com/administration/services/)