多设备模块

本文档提供了有关如何创建多设备模块的分步说明,并指明了目前已知的限制。

示例

我们提供了一个 CTS Wi-Fi 感知型多设备模块。它通过 Wi-Fi 从一台设备发送消息,并验证另一台设备是否收到了消息。

该模块的源代码位于 packages/modules/Wifi/tests/hostsidetests/multidevices/test/aware/

我们已为该示例尽可能添加我们认为有用的注解。

第 1 步:创建模块文件夹

建议在您的多设备模块所属的套件项目中为其创建一个文件夹。例如:cts/hostsidetests/multidevices/。 之所以建议您这样做,是为了确保所有多设备模块至少最初保持并置,使其能更轻松地发现示例。

此模块的所有文件都应放在相应模块文件夹中。例如:wifi_aware

第 2 步:创建测试

您将在这一步实现测试逻辑。测试逻辑在很大程度上取决于测试的对象。

创建 Mobly 测试源代码,如:wifi_aware_test.py

第 3 步:创建 build 文件 (Android.bp)

添加 Android .bp 文件,如 packages/modules/Wifi/tests/hostsidetests/multidevices/test/Android.bp。 定义一个 python_test_host 模块,如下所示:

python_test_host {
    name: "CtsWifiAwareTestCases",
    main: "wifi_aware_test.py",
    srcs: ["wifi_aware_test.py"],
    test_suites: [
        "cts",
        "general-tests",
    ],
    test_options: {
        unit_test: false,
    },
    data: [
          // Package the snippet with the mobly test
        ":wifi_aware_snippet",
    ],
}

使用数据字段为测试指定代码段,该代码段将与二进制文件一起打包,并可通过 ATest 或在连续执行期间找到并安装到测试中。

Mobly Bundled Snippets 在 Android 中位于 external/mobly-bundled-snippets/

可选:创建自定义代码段

某些多设备模块可能需要自定义 Mobly 代码段。示例测试包含 Wi-Fi 感知型代码段(位于 packages/modules/Wifi/tests/hostsidetests/multidevices/com.google.snippet.wifi/aware/WifiAwareSnippet.java),该代码段是使用 Mobly Snippet Lib(在 Android 中位于 external/mobly-snippet-lib/)构建的。

该代码段应该在 Android.bp 中使用 android_test 规则进行定义,就像标准插桩一样:

android_test {
    name: "wifi_aware_snippet",
    sdk_version: "current",
    srcs: [
        "CallbackUtils.java",
        "WifiAwareSnippet.java",
    ],
    manifest: "AndroidManifest.xml",
    static_libs: [
        "androidx.test.runner",
        "guava",
        "mobly-snippet-lib",
    ],
}

第 4 步:创建模块配置 (AndroidTest.xml)

添加 AndroidTest.xml 文件,如 packages/modules/Wifi/tests/hostsidetests/multidevices/test/aware/AndroidTest.xml。 在此测试配置中,您需要为测试指定两个设备,如下所示:

<configuration description="Config for CTS Wifi Aware test cases">
    <option name="test-suite-tag" value="cts" />
    <option name="config-descriptor:metadata" key="component" value="wifi" />
    <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
    <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
    <option name="config-descriptor:metadata" key="parameter" value="not_secondary_user" />

    <device name="device1">
        <!-- For coverage to work, the APK should not be uninstalled until after coverage is pulled.
             So it's a lot easier to install APKs outside the python code.
        -->
        <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
            <option name="test-file-name" value="wifi_aware_snippet.apk" />
        </target_preparer>
        <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
            <option name="run-command" value="input keyevent KEYCODE_WAKEUP" />
            <option name="run-command" value="wm dismiss-keyguard" />
        </target_preparer>
        <target_preparer class="com.android.tradefed.targetprep.PythonVirtualenvPreparer">
          <!-- Any python dependencies can be specified and will be installed with pip -->
          <option name="dep-module" value="mobly" />
        </target_preparer>
    </device>
    <device name="device2">
        <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
            <option name="test-file-name" value="wifi_aware_snippet.apk" />
        </target_preparer>
        <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
            <option name="run-command" value="input keyevent KEYCODE_WAKEUP" />
            <option name="run-command" value="wm dismiss-keyguard" />
        </target_preparer>
    </device>

    <test class="com.android.tradefed.testtype.mobly.MoblyBinaryHostTest">
      <!-- The mobly-par-file-name should match the module name -->
      <option name="mobly-par-file-name" value="CtsWifiAwareTestCases" />
      <!-- Timeout limit in milliseconds for all test cases of the python binary -->
      <option name="mobly-test-timeout" value="60000" />
    </test>
</configuration>

请注意:

  • 此示例测试依赖于 Mobly。您可以为 PythonVirtualenvPreparer 指定任何依赖项,并将使用 pip 进行安装。
  • MoblyBinaryHostTestmobly-par-file-name 必须与 Android .bp 中的模块名称相匹配。
  • 请务必为测试指定 mobly-test-timeout。此超时以毫秒为单位,适用于完整的 Python 二进制文件执行过程(所有测试用例)。 这样做是为了避免出现一些问题,导致测试用例永久挂起。
  • 每个 device 标记在每个设备上可能包含不同设置,Mobly 配置将按照 XML 中指定的顺序接收它们。

代码段 APK 安装相关注意事项

  • 鉴于与覆盖率团队的沟通,初始 POC 已更新为通过 target_preparer 安装代码段 APK:为了确保覆盖率测量结果不会过早删除,借助自动化测试框架(而不是 Python 二进制文件中的测试代码)进行卸载可在时间方面提供更好的保证。

第 5 步:在本地运行测试 (atest)

目前,多设备测试只能在实体设备上运行。在运行测试之前,请验证您的测试设备是否处于适当状态。命令 adb devices 应该报告已连接设备的列表。如果该列表包含不打算用于测试的设备,请使用 -s 标志指定用于测试的设备。

对于 Wi-Fi 测试,请确保为设备启用了 Wi-Fi(恢复出厂设置后)。

您可以使用 atest 在本地运行测试:

$ atest CtsWifiAwareTestCases

您应该会在 atest 输出的摘要标题中看到使用的设备数量,例如 Test executed with 2 device(s)

问题排查

如果测试在本地运行时由于以下原因失败:

Virtualenv 错误

java.io.IOException: Cannot run program
"virtualenv": error=2, No such file or directory

请确保 virtualenv 位于您的 PATH 中。将“~/.local/bin”添加到 PATH 中可以解决这一问题。如果未安装 virtualenv,请按以下页面上的说明操作:https://virtualenv.pypa.io/en/latest/installation.html

预计至少获得 2 个控制器对象,实际只获得了 1 个

测试模块要么是多设备模块,要么是单设备模块,没有混合模块。如果您在没有多台设备的情况下尝试运行多设备模块,就会看到此错误:

Expected to get at least 2 controller objects, got 1

在多设备模式下执行该模块可以解决此问题。

对于 CTS:您可以使用分片触发它(例如:--shard-count 2)或 run cts-multidevces