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