かまたま日記3

プログラミングメイン、たまに日常

GitHub Actionsでテストを分割する

やりたいこと

GitHub Actionsでテストケースを分割して、複数ノードで実行する

CircleCIだとプラットフォーム側で対応してくれていますがGH Actionsだと見当たらなかったので同等のことをやるための設定のメモです。

設定例

  rspec:
    runs-on: ubuntu-latest
    strategy:
      max-parallel: 2
      matrix:
        ci_node_total: [2]
        ci_node_index: [0, 1]
    steps:
      - uses: actions/checkout@v2
      - uses: ruby/setup-ruby@v1
      - name: Bundle install
        run: bundle install
      - name: DB setup
        run: bundle exec rake db:setup
      - name: Rspec
        run: |
          ruby -e 'Dir.glob("spec/**/*_spec.rb").each{|f| puts f}' | awk "NR%${CI_NODE_TOTAL}==${CI_NODE_INDEX} {print}" > /tmp/tests-to-run
          cat /tmp/tests-to-run
          bundle exec rspec $(cat /tmp/tests-to-run)
        env:
          CI_NODE_TOTAL: ${{ matrix.ci_node_total }}
          CI_NODE_INDEX: ${{ matrix.ci_node_index }}

GitHub ActionsにはBuild Matrix という機能があって、本来はOSのバージョンと言語のバージョンの複数のマトリクステストを実施するための機能なのですが、これを使って ci_node_totalci_node_index という2つのパラメタを登録します。

  • ci_node_total: ノードの合計, max-parallel と同じ数にする必要がある
  • ci_node_index: ノードのインデックス, 0始まりで ci_node_total-1 で終わる配列

これで、 rspec のJobは (2, 0) と (2, 1) という2つの設定で実施されることになります

f:id:kamatama_41:20200518161853p:plain

あとはindex毎にspec配下のファイルを分割してrspecコマンドに渡すだけです。CircleCIだとsizeの大きさとか各exampleのかかった時間とかでいい感じに平準化してくれますが、GitHub Actionsにはそういう機能は無いので、単にspecファイルを2分割して渡すのみです。

ちなみに、Go言語の場合はこんな感じでテストを分割実行できます

$ go test $(go list ./... | awk "NR%${CI_NODE_TOTAL}==${CI_NODE_INDEX} {print}")