Railsコアテスト環境を作る

[mwedアドベントカレンダー](https://qiita.com/advent-calendar/2017/mwed)4日目の記事です。

## はじめに
railsそのもののテスト環境を自PC(Mac)上に作る手順と、そのときに引っかかったポイントについて書いています。

## ざっくりまとめ
中身は長ったらしいので、まとめると…。

VirtualBoxとVagrant、rails-dev-boxで仮想マシン上にrailsのテストが動く環境を作れる。
ハマるポイントとして、

1. 共有しているホスト側のファイルシステムが大文字小文字を区別しないためのテスト失敗
2. 共有ディスクへの高負荷による仮想マシンのカーネルパニック

があって、

1と2の問題を解決するために共有フォルダをrsyncにするのがポイントでした。

## ~~残っている課題~~
~~まだテストが全部グリーンになっていません…。~~
~~原因がわかったら、rails-dev-boxやrailsにプルリクを出そうと思います。~~

(追記)
@yahonda@github さんがこの記事を拾ってくれて、おなじように再現したということで、railsの[issue](https://github.com/rails/rails/issues/31351)を作り調査を進めてくれて、[@y_yagi](https://twitter.com/y_yagi) さんが[修正](https://github.com/rails/rails/commit/91a4a820feeb878dd1b388befa56dd469933d17c)してくれました。

ということで、今日時点ではこのrails-dev-boxでrailsのmasterのテストが通っています。

## 本文
### Railsコア開発環境の構築
[rails-dev-boxのREADME](https://github.com/rails/rails-dev-box/blob/master/README.md)のとおりにやっていきます。

#### 事前準備
VirtualBoxとVagrantをインストールします。

[VirtualBox](https://www.virtualbox.org/)はx86仮想マシンを管理するソフトウェア。
[Vagrant](https://www.vagrantup.com/)は仮想開発環境の構築ソフトウェア。
この2つを使って、rails-dev-boxはRailsコア開発環境を作ろうというわけです。

##### [VirtualBox](https://www.virtualbox.org/)
```
$ brew cask install virtualbox
```
自分はすでにインストール済みだったので、`reinstall`で最新版にしました。

##### [Vagrant](https://www.vagrantup.com/)
```bash
$ brew cask install vagrant
```
`brew install vagrant` とすると古いバージョンが入るので気をつけてください。

#### 仮想マシン構築
[rails-dev-box](https://github.com/rails/rails-dev-box)はVagrantの仕組みを使って、
Ubuntuの仮想マシンイメージから仮想マシンを準備、必要なパッケージをインストールしています。

```bash
$ git clone https://github.com/rails/rails-dev-box.git
$ cd rails-dev-box
$ vagrant up
```

このあと`vagrant ssh`すれば仮想マシンにログインできます。

自分は古いvagrantで最初やったので↓のようなエラーが出てできませんでした。
新しいvagrantを入れて、`.vagrant`以下を削除してやり直しました。

```
The provider 'VirtualBox' could not be found, but was requested to
back the machine 'default'. Please use a provider that exists.
```

#### Rails開発環境構築
rails-dev-boxのディレクトリは仮想マシンの`/vagrant`に共有ディスクとしてマウントされているので、
このディレクトリ内にrailsのリポジトリをクローンして、仮想マシン内で利用します。

```bash
$ git clone git@github.com:rails/rails.git
```

仮想マシンにログイン、railsのディレクトリで`bundle`

```bash
$ vagrant ssh
ubuntu@rails-dev-box:~$ cd /vagrant/rails
ubuntu@rails-dev-box:/vagrant/rails$ bundle
```

#### テスト実行
railsのディレクトリで`bundle exec rake test`とすればテストができるのですが、たくさんのテストがあって時間がとてもかかることと、結果になにかあっても見過ごしてしまいそうなので、コンポーネントごとに実行すると少し見やすくなります。

```
$ cd actioncable
$ bundle exec rake test
```

このようにしてひとつずつテストを実行していくと…
- `actionview`のテストでファイル名の大文字小文字が違うためにmissing templateになるというテストでしたが、OS Xのデフォルトではファイル名の大文字小文字を区別しないためでテストが失敗していました
- `railties`のテストでは仮想マシンがカーネルパニックを起こしました。おそらくvagrantの共有ディスクへのアクセスの負荷が高すぎたためだと思われます。

#### rsync
vagrantのファイル共有の方法にはいくつかありますが、それらのうちのrsyncで同期することにしました。
rsyncはホストPCのファイルシステムをそのまま共有せずに、ファイルのコピーによって同期するので、
仮想マシンではlinuxのext4が使われるのでファイル名の大文字小文字問題は解決されるし、
テスト実行時にrsyncをさせないでおけば、負荷が高くならないだろうという理由です。

Vagrantfileを下記のように修正します。

```
$ cat Vagrantfile
# -*- mode: ruby -*-
# vi: set ft=ruby :
Vagrant.configure('2') do |config|
  # FIXME: When upgrading to a future version of Ubuntu check if the workaround

  :
  :
    v.cpus   = ENV.fetch('RAILS_DEV_BOX_CPUS', 2).to_i
  end

  config.vm.synced_folder '.', '/vagrant', type: 'rsync'  # <- 共有方法にrsyncを指定
end$
```

Vagrantfileを修正した後に、`vagrant rsync`とすれば同期されます。
ファイルの編集を頻繁にするときには `vagrant rsync-auto`がわすれなくてよさそうです。

#### もう一度テスト実行

```bash
$ for f in actioncable actionmailer actionpack actionview activejob activemodel activerecord activestorage activesupport; do echo "+++++ $f +++++"; cd $f; time bundle exec rake test; echo "----- press enter -----"; read dmy; done
```

actionviewのテストは落ちなくなり、railstieのテストではカーネルパニックしなくなりました。

#### できていな~~い~~かったこと
(追記) 今はテストがパスするようになっています。

現状で、railstieの`test/application/server_test.rb`でエラーが出ていて、中身を見ているところです。
rails-dev-boxかrailsへのプルリクチャンスだと思って調べているところです…。

```
/usr/bin/ruby2.4 -w -Itest -Ilib -I../activesupport/lib -I../actionpack/lib -I../actionview/lib -I../activemodel/lib test/application/server_test.rb
Run options: --seed 21299

# Running:

.F

Failure:
ApplicationTests::ServerTest#test_restart_rails_server_with_custom_pid_file_path [test/application/server_test.rb:48]:
"Inherited" expected, but got:

...
/usr/local/lib/site_ruby/2.4.0/rubygems/core_ext/kernel_require.rb:59:in `require': cannot load such file -- rails/all (LoadError)
	from /usr/local/lib/site_ruby/2.4.0/rubygems/core_ext/kernel_require.rb:59:in `require'
	from /tmp/d20171127-27190-zh42ve/app/config/boot.rb:1:in `<top (required)>'
	from bin/rails:3:in `require_relative'
	from bin/rails:3:in `<main>'
.
Expected "...\r\n/usr/local/lib/site_ruby/2.4.0/rubygems/core_ext/kernel_require.rb:59:in `require': cannot load such file -- rails/all (LoadError)\r\n\tfrom /usr/local/lib/site_ruby/2.4.0/rubygems/core_ext/kernel_require.rb:59:in `require'\r\n\tfrom /tmp/d20171127-27190-zh42ve/app/config/boot.rb:1:in `<top (required)>'\r\n\tfrom bin/rails:3:in `require_relative'\r\n\tfrom bin/rails:3:in `<main>'\r\n" to include "Inherited".


bin/rails test test/application/server_test.rb:35



Finished in 13.999023s, 0.1429 runs/s, 0.5715 assertions/s.
2 runs, 8 assertions, 1 failures, 0 errors, 0 skips
```



## 参照
- [Railsコア開発環境の構築方法](https://railsguides.jp/development_dependencies_install.html)
- [rails-dev-box](https://github.com/rails/rails-dev-box)
- [test_restart_rails_server_with_custom_pid_file_path fails](https://github.com/rails/rails/issues/31351)
-[Ensure to use repo's Gemfile in application](https://github.com/rails/rails/commit/91a4a820feeb878dd1b388befa56dd469933d17c)

明日は[@koheiSG](https://qiita.com/koheiSG)さんの「読書会のはなし」です。