🔦

Goのテストにかかった時間を前回と比較するツールを作った

2022/02/06に公開

はじめに

データ量が開発環境と違い,本番にデプロイしてからパフォーマンス問題を引き起こすことってありますよね?(僕はやりました)
負荷試験を頻繁に行うことは難しくとも,テストは書かれていることが多いのではないかと思い,テストの所要時間を比べることでパフォーマンス悪化の兆候を掴めないかと考えました.

そうして出来上がったのが「goppa」です.
https://github.com/masibw/goppa

デモ

まずは通常時のテスト結果を保存します.

go test ./... -v |tee prev.log

何かしらの変更を加え,同じくテスト結果を保存します.

go test ./... -v |tee current.log

この2つをgoppaを用いて比較します.

goppa --previous ./prev.log --current ./current.log

変更後のテストにパフォーマンス悪化があった場合は通知されます.

some tests are slower than previous.
'TestAdd', prev: 0s, current: 2s
'TestAdd/Can_add_up_two_numbers(includes_negative_value).', prev: 0s, current: 1s

ちなみに, --border 2.0のようなフラグを渡すことで,前回より何倍遅くなったら検知するかを設定できます.

技術的な話

正直goppaの開発部分ではそんなに複雑なところはありませんでした.
テストの結果文字列を1行ずつ読み込んで,前回の結果と比較するだけです.問題は,どうやってこれを継続的に実行するかということです.

結論

goppaの実行には以前のテスト結果が必要なので,まずはテスト結果を保存するように設定します.

name: test
on:
  pull_request:
  push:
    branches:
      - main
jobs:
  test:
    name: Test local sources
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Sources
        uses: actions/checkout@v2
      - name: Setup Go
        uses: actions/setup-go@v2
        with:
          go-version: 1.17.6
      - name: Restore cache
        uses: actions/cache@v2
        with:
          path: ~/go/pkg/mod
          key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
          restore-keys: |
            ${{ runner.os }}-go-
      - name: Get dependencies
        run: go mod download -x
      - name: Test
        run: go test -v ./... |tee ./test-${{ github.sha }}.log
      - name: Save test results
        uses: actions/cache@v2
        with:
          key: test-${{ github.sha }}
          path: ./test-${{ github.sha }}.log

テスト結果を保存するようにしたら,goppaの実行部分も組み込み,マージ先ブランチと変更を加えたものを比較できるようにします.

name: test
on:
  pull_request:
  push:
    branches:
      - main
jobs:
  test:
    name: Test local sources
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Sources
        uses: actions/checkout@v2
      - name: Setup Go
        uses: actions/setup-go@v2
        with:
          go-version: 1.17.6
      - name: Restore cache
        uses: actions/cache@v2
        with:
          path: ~/go/pkg/mod
          key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
          restore-keys: |
            ${{ runner.os }}-go-
      - name: Get dependencies
        run: go mod download -x
      - name: Test
        run: go test -v ./...  |tee ./test-${{ github.sha }}.log
      - name: Save test results
        uses: actions/cache@v2
        with:
          key: test-${{ github.sha }}
          path: ./test-${{ github.sha }}.log

  goppa:
    if: ${{ github.event_name == 'pull_request' }}
    needs: test
    runs-on: ubuntu-latest
    steps:
      - name: Setup Go
        uses: actions/setup-go@v2
        with:
          go-version: 1.17.6
      - name: Install goppa
        run: go install github.com/masibw/goppa@latest
      - name: Load previous test result
        uses: actions/cache@v2
        with:
          key: test-${{ github.event.pull_request.base.sha }}
          path: ./test-${{ github.event.pull_request.base.sha }}.log
      - name: Load current test result
        uses: actions/cache@v2
        with:
          key: test-${{ github.sha }}
          path: ./test-${{ github.sha }}.log
      - name: Run goppa
        run: goppa --previous ./test-${{ github.event.pull_request.base.sha }}.log --current ./test-${{ github.sha }}.log

テスト結果の保存に困った

GitHub ActionsなどのCI環境で継続的に実行したいのですが,テスト結果をどこかに保存しておく必要があります.
GitHub ActionsにはArtifactsというものがありますが,どうやら前回の実行で保存したものを次回に取り出せはしないようです(多分)
そのため,実行をまたいでも取得できるcacheを用いて保存しました.(テスト結果がcacheかと言われるとうーん..という気はしますが)

また,ファイル名についても最初はブランチ名が分かりやすくて良いかと思いましたが,/が入っているとファイルの保存先がややこしくなるのでcommit hashにしました.

改善が必要な箇所

テスト結果の保存

上で書いたように,cacheを保存場所にしていますが,あまり頻繁にアップデートされないプロジェクトでは前回の結果が消えてしまうと思います.逆に,実行回数が多すぎても容量の制限にかかってしまうかもしれません.
この辺は使う側でなんとかして欲しい気持ちと,楽に使えるようにしたい気持ちが戦っています.

以前のテストがない場合

前回のテスト結果と比べているので,元々テストがなかった機能のパフォーマンス問題は検知できません.
これはコンセプト的にどうしようもないので,別の手段を考える必要があります.

より詳細な設定

現在は「前回から○倍遅くなったら検知する」ことしかできませんが,「テスト実行時間が○秒を超えたら検知する」や,一律の閾値ではなく細かく設定できる機能を増やせたらいいなと思っています.

最後に

作ったはいいですが,本当にパフォーマンス悪化の兆候をテストの所要時間で検知できるかはわかりません(ぇ)
ぜひ使ってみて感想や,機能追加の要望をください.お待ちしてます

Discussion