CTC 教育サービス
[IT研修]注目キーワード Python UiPath(RPA) 最新技術動向 Microsoft Azure Docker Kubernetes
今回からは、2017年に公開された論文「Taming Google-Scale Continuous Testing」をもとにして、Google社内の開発チームが活用する継続的インテグレーションの仕組み、その中でも特に、自動テストのインフラ環境を紹介していきます。この論文では特に、繰り返し実行される膨大な数のテストについて、その処理を効率化するための取り組みが解説されています。今回は、Googleの開発環境で用いられる自動テストのシステムについて、まずは、基本的な仕組みを説明します。
本連載の中で何度か触れたように、Google社内で開発されるソフトウェアのソースコードは、単一のリポジトリで管理されており、複数のプロジェクトにまたがってライブラリモジュールの共有が行われます。そして、あるモジュールのソースコードが変更されると、それに依存するすべてのソースコードに対するテストが自動的に再実行されます。このような自動テストは、「Test Automation Platform (TAP)」と呼ばれるシステムによって管理されており、冒頭の論文によると、1日あたり、約1万3千個のプロジェクトにおける、約80万回のビルド処理があり、それに伴うおよそ1億5千万個のテストが実行されるそうです。
ソフトウェアモジュールの依存関係は、Blazeと呼ばれる独自のビルドツールで管理されており、モジュール間の依存関係にもとづいたテストの実行計画が立てられます。例えば、図1の定義ファイルでは、「deps」で指定されたモジュール(パッケージ)に変更があった場合、このモジュール自身に対する「framework gradients test」という名前のテスト(framework/gradients_test.cc)が再実行されます。(Blazeをオープンソースとして再実装したツールは、現在、Bazelという名称で公開されています。)
図1 Blazeのビルドファイルの例(論文より抜粋)
そして、実際にあるモジュールの変更が行われると、TAPシステムは、リポジトリ上のすべてのモジュールのビルドファイルをスキャンして、再実行が必要なテストのリストを作成します。これは、より正確に言うと、次のような流れになります。まず、Google社内の開発環境では、ソースコードに対する一連の修正は、「Change List(CL)」と呼ばれる単位で管理されます。ソフトウェアエンジニアがひとまとまりの変更をサブミットすると、固有のID番号が割り当てられ、変更に対するレビューや最終的なコミット処理は、このCLの単位で行われます。そして、新たにCLがコミットされると、CLに含まれるそれぞれのファイルに対して、これに依存する他のファイルを逆にたどっていくことで、先ほどのテスト対象のリストが作成されます。
ただし、実際のテスト処理は、CLがコミットされたタイミングですぐに行われるわけではありません。あるCLに関連してテスト対象となったターゲットには、CLのIDと共に、「AFFECTED」というフラグがセットされます。複数のCLがコミットされていくと、このフラグがセットされたターゲットが増えていきます。図2は、cl1〜cl16のCLが順にコミットされた際に、それぞれでフラグがセットされたターゲットの様子を模式図に表したものです。
図2 CLのコミットによってフラグがセットされる様子(論文より抜粋)
この例では、最終的に、t1〜t14の14種類のターゲットに対してフラグがセットされていますが、1つのターゲットに対して、複数のCLが影響している点に注目してください。たとえば、t1は、cl1、cl3、および、cl16の3つのCLの影響を受けていることがわかります。このようにして、再実行が必要なテストがある程度たまると、これらに対する実際のテスト処理がまとめて行われます。このタイミングを「マイルストーン」と呼び、たとえば、開発のピーク時では、約45分ごとにマイルストーンが発生しています。図2の例からもわかるように、CLのコミットごとにテストを実行した場合、同じターゲットに対して何度もテストが再実行されますが、これらを一定期間のマイルストーンとしてまとめることにより、テストの実行回数を削減しているのです。
そして、テストの実行結果は、該当のターゲットに影響をあたえた最後のCLのIDと共に、「PASS(テスト成功)」、もしくは、「FAILED(テスト失敗)」のフラグとして登録されます。図2の例であれば、黒く塗られた箱が「PASS/FAILED」のフラグに対応します。あるターゲットのテストが失敗した場合、1つ前のマイルストーン以降に影響を与えた(「AFFECTED」のフラグがついた)CLのいずれかにその要因があることになります。なお、それぞれのテストの実行内容は、ターゲットの種類によって大幅に変わります。JUnitによる単体テストもあれば、複数の処理をエンドツーエンドで実行するテストスクリプトの場合もあり、それぞれの実行時間にも大きな幅があります。
以上がTAPシステムの概要となりますが、冒頭の論文では、このシステムの課題として、テストに必要なリソースとテスト結果を開発者にフィードバックするまでのタイムラグのトレードオフをあげています。たとえば、45分ごとにマイルストーンが発生した場合、ある変更によって何らかのテストが失敗したと開発者が気づくまでに、45分以上の時間がかかることになります。この時間を短縮するには、より短い間隔でマイルストーンを発生させればよいのですが、Googleの開発環境におけるソースコードの変更量、そして、それに伴うテストの実行量を考えると、これは容易なことではありません。テストの実行量が増えると、テストに必要なリソースが不足して、逆にテストが遅延するなどのリスクも上がります。実際、45分ごとのマイルストーンにおいても、あるテストが完了するまでに9時間近くかかったという特異な例が論文の中でも触れられています。
そこで、本論文を執筆したTAPシステムの改善チームでは、これまでのテストの実行状況のデータを解析して、この問題の解決に取り組みました。つまり、テストに必要なリソースを削減しながら、しかも、テスト結果をより短時間でソフトウェアエンジニアにフィードバックするという課題に取り組んだのです。
今回は、論文「Taming Google-Scale Continuous Testing」をもとにして、Google社内のテストシステムである「TAPシステム」を紹介しました。次回は、先ほど説明したTAPシステムの課題をどのように解決したのか、その具体的な手法を説明していきます。
Disclaimer:この記事は個人的なものです。ここで述べられていることは私の個人的な意見に基づくものであり、私の雇用者には関係はありません。
[IT研修]注目キーワード Python UiPath(RPA) 最新技術動向 Microsoft Azure Docker Kubernetes