マルチデバイス テスト

VTS は、複数の Android デバイス間での通信を必要とするテストに対応しています。

アーキテクチャ

VTS は、TradeFed フレームワークを使用してデバイス シリアルを取得し、テスト モジュールに渡します。

図 1. デバイス シリアルを渡す VTS

デバイス数やデバイスタイプなどのデバイス要件は、テストプランの設定で指定します。たとえば、Sailfish ビルド ターゲットを持つ 2 台の Android デバイスが必要なテストプランを指定できます。

デバイスの割り当て

テスト インフラストラクチャ(通常はテスト スケジューラ)は、テストプラン設定で指定された要件を満たす使用可能なデバイスを VTS フレームワークに割り当てます。割り当てられたデバイスは、テスト モジュールが使用していない場合でもテストプラン用に予約されます。VTS エージェントのバイナリは、実行しないように明確に指定されていない限り、すべての割り当てられたデバイスに転送されて実行されます。これにより、シェルコマンドと HAL RPC の TCP 接続がテスト スクリプト内ですべてのデバイスから使用可能になります。

テスト作成ツール

フレームワークは、シリアル番号を受信したすべてのデバイスでテスト作成ツールを実行します。単一デバイスとマルチデバイスのいずれもターゲット作成ツールとして使用できます。

  • 単一デバイス ターゲット作成ツール(VtsDeviceInfoCollector の例):
    • 必須デバイスリストが指定されたテストプラン設定でのみ指定できます。今後のバージョンでモジュール レベルの設定が可能になります。
    • デバイス シリアルを 1 つだけ受け取ります。
    • 特定のデバイスに対して準備タスクとクリーンアップ タスクを実行します。
  • マルチデバイス ターゲット作成ツール(VtsPythonVirtualenvPreparer の例):
    • テストプラン設定またはテスト モジュール設定で指定できます。
    • すべてのデバイス シリアル番号を受け取ります。
    • 各デバイスまたはすべてのデバイスに対して準備タスクとクリーンアップ タスクを実行します。

テスト モジュール

テスト モジュールは、テスト作成ツールがホストとデバイスのセットアップを完了してから、デバイスのリストを取得します。ホスト側の Python テスト モジュールは、マルチデバイス テスト モジュールごとに 1 つずつ実行されます。割り当てられた Android デバイスは、Python テスト モジュールから AndroidDevice オブジェクトのリストとしてアクセスできます。

devices = self.android_devices
device1 = devices[0]
device1_serial = device1.serial

プラン内のテスト モジュールが使用しているデバイスが 1 台のみの場合でも、割り当てられたすべてのデバイスがテストプラン用に予約されます。

テスト中のデバイスの通信

有効なマルチ Android テストでは、割り当てられたデバイス間の通信が必要です。そのようなテストを開発する際は、割り当てられたデバイス間の通信方法を決定する必要があります。以降のセクションでは、通信の例を 3 つ示します。ただし、テスト デベロッパーは他のモデルを自由に設計できます。

タイプ 1: ホスト側の HAL テスト

ホスト側の HAL テストでは、デフォルトでデバイスに転送される VTS HAL ドライバを使用できます。

図 2. ホスト側の HAL テスト

次のようになります。

  • テストロジックはホストで実行されます。
  • ホスト側のテスト スクリプトが、各デバイスのドライバへの RPC 呼び出しを発行します。
  • ホスト側がデバイス間のやり取りを調整します。

タイプ 2: ホスト側のエージェント ベースのテスト

ホスト側のテストでは、デバイス上で VTS エージェントを使用する代わりに、各デバイスに独自のエージェント(アプリまたはバイナリ)を転送することもできます。

図 3. ホスト側、エージェント ベースのテスト

次のようになります。

  • テストロジックはホストで実行されます。
  • エージェント アプリ(またはバイナリ)を各デバイスにインストールします。
  • ホスト側のテスト スクリプトが各デバイスのアプリにコマンドを発行します。
  • ホスト側がデバイス間のやり取りを調整します。

たとえば、現在の VTS リポジトリにある Next Billion User のテストは、ホスト側、アプリベース、マルチデバイスのテストです。

タイプ 3: ターゲット側の HIDL テスト

ターゲット側のマルチデバイス HIDL テストでは、すべてのテストロジックをデバイス側のテストバイナリに持たせます。このため、テスト実行中にデバイスを同期させる必要があります。

図 4. ターゲット ベースの HIDL テスト

次のようになります。

  • テストロジックはデバイス上で実行されます。
  • ホスト側のフレームワークが初期デバイス ID を指定します。
  • ターゲット側のテストバイナリの同期が必要です。
    • すべてのデバイスで同じテストバイナリ。
    • ロールごとに異なるテストバイナリ。

例: マルチデバイス テストプラン

次の例では、2 台のデバイスの設定を指定します。

  • デバイス 1 には、ビルド プロバイダと VtsDeviceInfoCollector ターゲット作成ツールが含まれています。
  • デバイス 2 には、これらに加えて、ホスト駆動に関連したファイルのグループを転送する FilePusher 作成ツールが含まれています。
<configuration description="VTS Codelab Plan">
  ...
<device name="device1">
<build_provider class="com.android.compatibility.common.tradefed.build.CompatibilityBuildProvider" />
<target_preparer class="com.android.tradefed.targetprep.VtsDeviceInfoCollector" />
</device>
<device name="device2" >
<build_provider class="com.android.compatibility.common.tradefed.build.CompatibilityBuildProvider" />
<target_preparer class="com.android.tradefed.targetprep.VtsDeviceInfoCollector" />
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.VtsFilePusher">
<option name="push-group" value="HostDrivenTest.push" />
</target_preparer>
</device>
<option name="compatibility:include-filter" value="VtsCodelabHelloWorldMultiDeviceTest" />
</configuration>

例: ホスト側の Python テスト スクリプト

テスト作成ツールの詳細と例については、テスト作成ツールをご覧ください。ホスト側のマルチデバイスの完全な例については、hello_world_multi codelab をご覧ください。

def setUpClass(self):
logging.info('number of device: %s', self.android_devices)
asserts.assertEqual(len(self.android_devices), 2, 'number of device is wrong.')
self.dut1 = self.android_devices[0]
self.dut2 = self.android_devices[1]
self.shell1 = self.dut1.shell
self.shell2 = self.dut2.shell

def testSerialNotEqual(self):
'''Checks serial number from two device not being equal.'''
command = 'getprop | grep ro.serial'
res1 = self.shell1.Execute(command)
res2 = self.shell2.Execute(command)

def getSerialFromShellOutput(output):
'''Get serial from getprop query'''
return output[const.STDOUT][0].strip().split(' ')[-1][1:-1]
serial1 = getSerialFromShellOutput(res1)
serial2 = getSerialFromShellOutput(res2)

logging.info('Serial number of device 1 shell output: %s', serial1)
logging.info('Serial number of device 2 shell output: %s', serial2)
asserts.assertNotEqual(serial1, serial2, 'serials from two devices should not be the same')
asserts.assertEqual(serial1, self.dut1.serial, 'serial got from device system property is different from allocated serial')
asserts.assertEqual(serial2, self.dut2.serial, 'serial got from device system property is different from allocated serial')