インフラ・DevOps
LinuxからDisposable VMを使用してWindowsデスクトップテストを実行する
Running Windows desktop tests from Linux with disposable VMs (qawolf.com)
要約
この記事では、Linux環境からWindowsデスクトップアプリケーションをテストする際の課題、特に従来の仮想マシンの遅さと状態管理の問題について論じています。Qawolfは、Windowsマシンをサーバーではなく「使い捨ての電話」のように扱い、テストごとにクリーンなVMをプロビジョニングして破棄するアプローチを採用することで、この問題を解決しました。これにより、テストの高速化と安定性の向上が実現されています。
全文翻訳
LinuxからWindowsデスクトップアプリのテストを実行する理由の1つは、世界中の誰も毎月数千回の実行を並列化できるインフラストラクチャを持っていないことです。Webテストのインフラストラクチャは比較的簡単です。ヘッドレスブラウザは、Linuxコンテナ内で数秒で起動し、実行コストはわずか数セントで、テスト終了時に破棄されます。Windowsデスクトップアプリのテストには、これに相当するものはありません。
Windowsアプリのテストでは、各テストに完全なVMが必要です。なぜなら、Windowsコンテナにはアプリを実行するためのグラフィカルデスクトップが含まれていないからです。マシンは起動が遅いです。コールドスタートのWindows VMは、起動に2〜3分かかります。ブラウザコンテナは数秒です。
誰かがログインしている必要があります。テストツールがボタンやフィールドを見つけるために使用するアクセシビリティインターフェイスであるWindows UI Automation(UIA)は、アクティブでログイン済みのデスクトップセッション内でのみ機能します。単に電源が入っているだけでは不十分です。
マシンは記憶します。インストールされたファイル、レジストリキー、ユーザープロファイル、保存されたログイン情報、および一時的なプロセスはすべて、実行間で維持されます。各アプリは独自の環境を持ち込みます。インストーラー、管理者プロンプト、ライセンスされた依存関係、初回実行ダイアログ、サインインなどです。組み込みの可視性がありません。ブラウザはトレース、ログ、スクリーンショットを提供しますが、リモートのWindowsマシンは、自分で構築しない限り何も提供しません。
ツールはLinuxを想定しています。Kubernetes、CIランナー、およびほとんどのテストインフラストラクチャは、Linuxコンテナを中心に設計されています。
私たちの答えは、Windowsマシンをサーバーとして扱うのをやめ、電話のように扱うことでした。つまり、1つのテストが要求し、一度使用し、破棄するデバイスです。
アーキテクチャ
基本的なアーキテクチャは、モバイルテストインフラストラクチャから借用しています。なぜなら、モバイルテストも同様の制約を抱えているからです。テストコードは、テスト対象のデバイスで実行できず、各テストは実行中にデバイスを専有する必要があります。
WindowsマシンはKubernetes内でデバイスとしてモデル化されているため、テストはカスタムデバイススケジューラにDeviceClaimを持つVMを要求し、その接続情報を取得し、WebdriverIOとAppiumを介してデバイスをリモートで制御し、テストが完了したらマシンを解放できます。
Windowsには、デバイスモデルに2つの拡張機能が必要でした。デバイスはもはやKubernetesクラスター内に存在する必要はありません(GCE VMは完全に外部に存在します)。また、クレームはデスクトップの接続アドレス(ブラウザの場合はCDPを含む)を返すことができます。
それ以外の場合、Windowsランナーはモバイルランナーのライフサイクルステップをステップごとに(クレーム、ハートビート、記録、接続、実行、解放)従い、テストは同じWebdriverIOとAppiumのペアリングを介してネイティブアプリと通信し、プライベートWindowsプールはプライベートiOSデバイスと同じように機能します。
モバイルシステムと同様に、3つの部分から構成されます。
Kubernetesで実行されるコントローラー。Google Compute Engine(GCE)上のWindows VMのプールを維持し、テストに配布します。
テストコードを実行するLinuxポッドであるランナー。
テスト対象のアプリ、自動化ツール、および小さなデスクトップエージェントを実行するWindows VM。
ランナーは3つの接続を介してVMと通信します。
ブラウザ内のすべてのものに対して、PlaywrightはCDP(Chrome DevTools Protocol)を介して接続します。
AppiumはネイティブWindowsアプリを処理します。
WebRTC(Web Real-Time Communication)ストリームは画面を運び、人々はテストをライブで視聴し、後で録画を確認できます。
Androidエミュレータと同様に、各Windows VMは使い捨てです。誰もそれにログインせず、パッチを適用せず、数週間も実行し続けません。テストはそれを要求し、一度使用し、返却し、新しいVMがその場所を引き継ぎます。
Linuxランナーポッドはテストコード(@qawolf/flows/windows)を実行します。
ステップ1:テストはデバイススケジューラからデバイスを要求します。これは、Kubernetesコントローラー内のWindows VMレコンサイラと共に実行されます。
ステップ2:スケジューラは、Google Compute Engine(GCE)上の準備完了のWindows VMをテストに割り当てます。スケジューラは、GCE APIを介してウォームなWindows VMのプールも準備しておきます。
ステップ3:テストは、ブラウザの場合はCDP(Playwright)、ネイティブWindowsアプリの場合はAppium(WebDriver)を介して、要求されたVMと3つの接続で通信します。
ステップ4:VM上のGoデスクトップエージェントは、WebRTC画面ストリームをランナーに送り返します。
したがって、ユーザーが実行を開始すると、テストはLinuxランナーポッドで開始され、Windowsデバイスが要求されます。スケジューラは、すでに起動およびログイン済みのマシンのプールからVMを割り当てます。ランナーは、CDP、Appium、および画面ストリーミングのVMの接続アドレスを受け取ります。テスト対象のアプリがVMに配信され、起動されます。テストが実行されます。画面はライブでストリーミングされ、録画されます。テストが終了すると、クレームは解放され、VMは破棄されます。新しいVMがプール内の場所を引き継ぎます。
ステップ1/6
テストはLinuxランナーポッドで開始され、Windowsデバイスが要求されます。
ランナーポッド(テストコード)、デバイススケジューラ(Kubernetes)、およびウォームプールからのWindows VM間のシーケンス。
ステップ1:ランナーはスケジューラにDeviceClaimを送信します。
ステップ2:スケジューラは準備完了のVMを割り当てます。
ステップ3:スケジューラはVMの接続アドレス(CDP、Appium、および画面ストリーム用)を返します。
ステップ4:ランナーはstartApp()を呼び出します。VMは署名付きURLでアプリをダウンロードし、インストールして起動します。
ステップ5:ランナーはCDPおよびAppiumコマンドを送信します。VMはWebRTC経由で画面をライブ表示と録画のためにストリーミングし、スケジューラにハートビートを送信します。スケジューラは、60秒間無音の場合にVMを回収します。
ステップ6:ランナーはクレームを解放し、スケジューラはVMを破棄してウォームプール用に新しいVMを作成します。
オンデマンドでのWindowsマシンのレンタル
Windowsテストが最初に行うことは、Windowsマシンを要求することです。それらを配布するのは、Androidエミュレータをすでに配布している社内サービスであるデバイススケジューラの仕事です。
Windowsのために、2つの新しいジョブを教えました。Google Compute EngineからVMの在庫を借りておくこと、そして要求する各テストに1つを提供することです。
スケジューラは、3つの新しいKubernetesカスタムリソースを使用してフリートを追跡します。
WindowsVMTemplateは、VMがどのように見えるかを記述します。マシンイメージ、サイズ、構成。
WindowsVMPoolは、指定されたテンプレートのために準備完了のVMをいくつ保持するかを記述します。
WindowsVMは1台のマシンを表します。
これらのレコードは、デバイススケジューラがエミュレータを管理する方法であり、Windows VMは別のシステムなしでそれに適合します。また、フリートの状態を永続的かつ可視的に保ちます。スケジューラが再起動した場合、レコードを読み取り、中断したところから再開します。エンジニアは標準のKubernetesツールで任意のプールまたはVMを検査できます。
マシンを配布することは、テストがエミュレータを要求するために使用するのと同じオブジェクトであるDeviceClaimから始まります。スケジューラはクレームを適切なプールから準備完了のVMに一致させ、そのVMの接続アドレスをランナーに返します。ブラウザの場合はCDP、ネイティブアプリの場合はAppium、画面ストリームです。
マシンを在庫に保持するのは、スケジューラ内のレコンサイラ(調整プログラム)の仕事です。これは、レコードと実際にGCEで実行されているものを比較し続け、ギャップを埋めます。プールが3台不足している場合、3台作成します。
テストがクレームを解放すると、そのVMは削除されます。Windows VMは作成と起動に数分かかるため、レコンサイラは短いパス全体で各ステップを1つずつ進め、VMのレコードに進捗を書き込みます。遅い起動は、スケジューラが管理する他のものを決して遅らせません。
クリーンなVMを迅速に供給する
デスクトップテストインフラストラクチャにおける中心的な緊張は、クリーンなマシンは遅く、高速なマシンはクリーンではないということです。新しいイメージから再起動するには数分かかり、マシンを再利用することは、各テストが前のテストが残したものを引き継ぐことを意味します。
私たちのシステムは両方の側面を処理します。
各VMはシングルユースです。VMはテスト後に再利用されることはありません。どのテストも他のテストのファイル、設定、またはログインを見ることができないため、「単独ではパスするが、スイートでは失敗する」という問題のカテゴリ全体が発生しません。
ウォームプールは起動時間を吸収します。各プールはVMを起動済み、ログイン済み、待機状態に保つため、テストはすでに準備ができているマシンを要求し、2〜3分のコールドスタートをスキップします。
プールは、テストが使用するにつれてマシンを置き換えます。
放棄されたマシンは回収されます。要求されたVMは、テスト中にアクティビティを報告します。