flakyテスト奮闘記 〜 Deno Deployの場合

10.5K Views

September 11, 24

スライド概要

2024/09/11 RustのWebアプリ開発 LT道場 〜テスト編〜
https://findy.connpass.com/event/327824/

profile-image

Working at Deno Land, Studying at Georgia Tech

シェア

またはPlayer版

埋め込む »CMSなどでJSが使えない場合

関連スライド

各ページのテキスト
1.

flakyテスト奮闘記 〜 Deno Deployの場合 2024/09/11 RustのWebアプリ開発 LT道場 〜テスト編〜 Yusuke Tanaka

2.

Who am I 米ジョージア工科大学のオンライン修士 課程に通いながらDeno Land Inc.で Deno Deployを作っています🦕 ← リアルで会った方にはもれなくこの名 刺をプレゼント! GitHub: https://github.com/magurotuna 𝕏: https://x.com/yusuktan

3.

今日の内容

4.

Deno Deploy開発における 😈 flaky test 😈

5.

Rustに関わる話、 Rustに限らない話、 ざっくばらんにご紹介

6.

What is a flaky test?

8.

What’s wrong with it?

9.

flaky testの問題点 ● 「とりあえずrerunしとこ」のマインドになってしまう ○ reliableに失敗するテストに気づくのが遅れる ○ CIで多大な時間を要することになり、生産性が落ちる ● 往々にして単体では発生確率が低いので、再現方法や原因が分かりにく く、直すのが大変がち

10.

What’s Deno Deploy?

11.

Deno Deployとは? ● Node.jsの作者Ryan Dahlが反省 を踏まえて作り直したJS/TSランタ イムDeno ● それをベースにしたサーバーレス サービス ● Cloudflare Workers, AWS Lambda, Vercel のような感じ ● Netlify, SupabaseなどのEdge Functionの実行基盤でもある

12.

Architecture?

13.

Deno Deploy アーキテクチャ だいぶ省略してます

14.

flaky tests breakdowns

15.

1. 依存している外部サービスの不安定性

16.

1. 依存している外部サービスの不安定性 ● 例: GitHub OAuthによるサインイン

17.

1. 依存している外部サービスの不安定性 ● 例: GitHub OAuthによるサインイン ○ Deno DeployのE2Eテストのシナリオでは、GitHub OAuthによる ログイン処理が必要

18.

1. 依存している外部サービスの不安定性 ● 例: GitHub OAuthによるサインイン ○ Deno DeployのE2Eテストのシナリオでは、GitHub OAuthによる ログイン処理が必要 ○ ヘッドレスブラウザによりユーザーの操作フローを再現

19.

1. 依存している外部サービスの不安定性 ● 例: GitHub OAuthによるサインイン ○ Deno DeployのE2Eテストのシナリオでは、GitHub OAuthによる ログイン処理が必要 ○ ヘッドレスブラウザによりユーザーの操作フローを再現 ○ 😨 GitHub側の実装に依存してしまう ■ Passkeyを使いませんか?の画面が突然追加される ■ 入力フォームのname属性の値が変わる

20.

1. 依存している外部サービスの不安定性 ● 例: GitHub OAuthによるサインイン ○ Deno DeployのE2Eテストのシナリオでは、GitHub OAuthによる ログイン処理が必要 ○ ヘッドレスブラウザによりユーザーの操作フローを再現 ○ 😨 GitHub側の実装に依存してしまう ■ Passkeyを使いませんか?の画面が突然追加される ■ 入力フォームのname属性の値が変わる ■ なんかたまに落ちる ← 一番厄介

21.

1. 依存している外部サービスの不安定性 ● 例: GitHub OAuthによるサインイン ○ 😨 GitHub側の実装に依存してしまう ■ なんかたまに落ちる ← 一番厄介 ● 対策: ヘッドレスブラウザを録画してGitHub ActionsのArtifactとして保 存するようにした ○ デバッグがしやすくなった 🥳 ○ 人間がやるとワンタイムパスワード入力後自動で次の画面に遷移す るのが、ヘッドレスブラウザ上だと遷移していなかった

22.

2. 非同期で動く複数コンポーネント間の不整合

23.

2. 非同期で動く複数コンポーネント間の不整合 ● 例: Deno Deployでユーザーのコードが console.log などで吐いた ログが保存されていることを確認するテスト

24.

2. 非同期で動く複数コンポーネント間の不整合 ● 例: Deno Deployでユーザーのコードが console.log などで吐いた ログが保存されていることを確認するテスト ○ 複数のレイヤーでバッファリングされる (runner, origin, etc.)

25.

2. 非同期で動く複数コンポーネント間の不整合 ● 例: Deno Deployでユーザーのコードが console.log などで吐いた ログが保存されていることを確認するテスト ○ 複数のレイヤーでバッファリングされる (runner, origin, etc.) ○ console.log を実行した時刻 t1、ログストレージに格納される時 刻 t2 の関係について、不正確な仮定のもとテストを書くとflakyにな る (1秒sleepするとか)

26.

2. 非同期で動く複数コンポーネント間の不整合 ● 例: Deno Deployでユーザーのコードが console.log などで吐いた ログが保存されていることを確認するテスト ○ 複数のレイヤーでバッファリングされる (runner, origin, etc.) ○ console.log を実行した時刻 t1、ログストレージに格納される時 刻 t2 の関係について、不正確な仮定のもとテストを書くとflakyにな る (1秒sleepするとか) ● 対策: 期待される結果が得られるまで、複数回リトライする

27.

2. 非同期で動く複数コンポーネント間の不整合 ● 例: Deno Deployでユーザーのコードが console.log などで吐いた ログが保存されていることを確認するテスト ● 対策1: 期待される結果が得られるまで、複数回リトライする ○ 無限リトライする場合は必ずタイムアウトを設ける ○ #[flaky_test] マクロ from flaky_test クレート

28.

2. 非同期で動く複数コンポーネント間の不整合 ● 例: Deno Deployでユーザーのコードが console.log などで吐いた ログが保存されていることを確認するテスト ● 対策2: 各コンポーネントで、キーとなるアクション (e.g. ログのflush) が 実行されたときに標準出力などにログを吐くようにして、それをもとに同期 をとる 💡 とにかく雑な tokio::time::sleep を避けるようにする

29.

3. 依存ライブラリ内の実装ミス

30.

3. 依存ライブラリ内の実装ミス ● 例: 同じホストに対して fetch を大量の並行で実行するとき、たまに HTTP/2のストリームに関するエラーが起きる

31.

3. 依存ライブラリ内の実装ミス ● 例: 同じホストに対して fetch を大量の並行で実行するとき、たまに HTTP/2のストリームに関するエラーが起きる ● 原因: Denoのfetchの実装で利用されていたRustのHTTPライブラリ reqwest の実装がまずかった ○ HTTP/2のコネクション確立後少しの間、サーバー側の MAX_CONCURRENT_STREAMS (同時に開くことが許されるストリー ム数) を超過してしまうことがありうる実装になっていた

32.

3. 依存ライブラリ内の実装ミス ● 例: 同じホストに対して fetch を大量の並行で実行するとき、たまに HTTP/2のストリームに関するエラーが起きる ● 原因: Denoのfetchの実装で利用されていたRustのHTTPライブラリ reqwest の実装がまずかった ○ HTTP/2のコネクション確立後少しの間、サーバー側の MAX_CONCURRENT_STREAMS (同時に開くことが許されるストリー ム数) を超過してしまうことがありうる実装になっていた ● 対応: ライブラリにパッチを送った

33.

flaky testの追跡と集計

34.

flaky testの追跡と集計 ● そもそもflaky testがflakyである と認知するためには、複数回のテ ストスイート実行結果の保存、集 計、比較が必要 ● BuildPulseなどのSaaSがある ● cargo-nextestを使うとテスト結 果をJUnit形式で出力でき、あらゆ るSaaSと統合可能

35.

もっと根本的な対策

36.

テストはできるだけ smallに!

37.

テストはできるだけ smallに! ● “Test Size” によるテスト分類 (by Google) において、Largeより Medium、MediumよりSmallな テストでカバーできないかを深く検 討する ● サイズを下げる方向にモックを活 用する https://testing.googleblog.com/2010/12/test-sizes.html

38.

🦁 t-wadaさんのプレゼン とても学びが多いのでおすすめです https://levtech.jp/media/article/c olumn/detail_496/

39.

俺たちの戦いはこれからだ! まだまだ大量にあるOpen状態なflaky ラベル付きissueたち 奮闘の日々は続く…… To be continued