RFC-0202:测试管理器即服务

RFC-0202:测试管理器即服务
状态已接受
区域
  • 测试
说明

为测试管理器即服务设计。

问题
Gerrit 更改
作者
审核人
提交日期(年-月-日)2022-07-22
审核日期(年-月-日)2022-12-14

摘要

目前,Fuchsia 上的测试作为测试管理器的动态子级执行。此设计使 Test Manager 能够在任何领域(产品所有者有权创建)中启动测试,从而使测试作者能够路由所需的运行程序和功能,而无需更改 Test Manager。

设计初衷

测试管理器会启动测试作为动态子级,并为其提供各种 hermetic/non-hermetic 功能和树内运行程序。测试管理器的当前设计是使用一组静态的内置测试运行程序和测试领域来运行。它不允许树外 (OOT) 和树内客户包含自己的测试运行程序和所需的功能,但随着客户数量的增加,我们将需要支持他们的使用情形。本文档提出了“测试管理器即服务”的概念,该服务将允许客户在他们选择的测试领域(可能在测试管理器的领域之外)中运行测试。这减轻了测试管理器在将所需系统功能路由到测试方面的责任。

利益相关方

教员:davemoore@google.com

审核者:geb@google.com、shayba@google.com、richkadel@google.com、kjharland@google.com、crjohns@google.com、cgonyeo@google.com、aaronwood@google.com、satsukiu@google.com、xbhatnag@google.com、yaneury@google.com、hjfreyer@google.com、akbiggs@google.com

已咨询

就此设计中使用的功能路由、框架和测试 API 相关问题咨询了组件框架团队。

共同化

此 RFC 已通过测试架构和组件框架团队的设计审核。

设计

在此设计中,产品所有者将决定测试应在何处运行,测试执行器 (ffx test/run-test-suite) 会将所需信息传递给测试管理器。我们将向 RunBuilder 协议添加一个名为 AddSuiteInRealm 的新方法,并传入所需的 realm 信息。

  AddSuiteInRealm(resource struct {
      // The realm which contains the collection to launch the test in
      realm client_end:fuchsia.component.Realm;
      // All offers from the realm to the test collection
      offers: Vec<Capabilities>
      // the test collection to launch the test in.
      test_collection: string

      // ... existing fields from AddSuite
  });

测试管理器将使用上述信息,通过 Realm Builder 在指定集合中启动测试,同时提供隔离的记录器、覆盖率收集、树内运行程序等来支持测试执行。组件管理器会将 LifecycleController 和 RealmQuery 协议(范围限定为“/”)路由到测试执行器。

测试 realm 可以由平台本身创建,也可以由产品所有者使用一些现有/新机制创建。到目前为止,只有平台可以定义测试领域,而这项工作旨在普及测试领域定义和管理。

此设计假设存在两种类型的用户。

  • 测试 Realm 作者:此用户将创建并维护运行测试的 Realm(他们应有权在拓扑中创建 Realm)。
  • 测试作者:测试的作者,测试将在由 realm 作者创建的 realm 中运行。

测试 Realm 作者将创建测试 Realm、对其进行设置并与 build 工具集成,以允许测试作者运行测试。他们需要在测试 Realm 中安装 Realm Builder 分片,才能实现此功能。

测试版领域示例:

{
  include: [
      "sys/component/realm_builder.shard.cml",
  ],
  collections: [
      // The collection to launch test in
      {
          name: "tests",
          environment: "#test_env",
          durability: "transient",
      },
  ],
  offer: [
      {
          protocol: [
              // Some system or mocked protocol
              "fuchsia.foo.bar",
              ...
          ],
          from: "parent",
          to: [
              "#tests",
          ],
      },
      ...
  ],
  environments: [
      {
          name: "test_env",
          extends: "realm",
          runners: [
              // Offer some OOT runner to the test
              {
                  runner: "fuchsia_oot_runner",
                  from: "parent",
              },
              // TODO(https://fxbug.dev/42063673): Abstract out into a shard.
              // This is important so that Realm Builder can work.
              {
                  runner: "realm_builder",
                  from: "#realm_builder_server",
              },
          ],
          resolvers: [
              // This is important so that Realm Builder can work.
              {
                  resolver: "realm_builder_resolver",
                  from: "#realm_builder_server",
                  scheme: "realm-builder",
              },
          ],
      },
  ]
}

Realm 作者将提供与 build 工具的集成,以便测试执行器在执行期间读取 moniker 和测试集合。

“人体工程学”部分简要介绍了一些将标识名和测试集合名称传递给测试执行器的解决方案,但详细讨论不在本文档的范围内。

测试作者将使用某种人体工程学解决方案(待定)来运行测试,该解决方案会将信息传递给测试执行器以运行测试。

测试执行器将使用 RealmQuery API 查询 realm 对象,以获取 realm 和测试集合的所有优惠,并使用提议的 AddSuiteInRealm API 将它们传递给 Test Manager。

它还将使用 LifecycleController API 在需要时解析 moniker。

此设计需要进行以下更改:

  • 修改 RealmQuery API 以读取“提供”声明。
  • 将修改 Realm Builder Rust 客户端库,以允许使用提供的 fuchsia.component/Realm 代理构建 realm。
  • 测试管理器将使用 Realm Builder 库中的新方法,以启动使用 Realm Builder(范围限定为自定义 Realm)的测试实例。
  • 测试管理器将使用提供的 offers 并使用 Realm Builder 对其进行路由。
  • Test Manager 将在测试环境中设置隔离的记录器、调试数据协议、树内运行程序等。

测试管理器现在可以连接到测试 realm 中的所有功能,因为它现在具有组件实例的句柄。

测试结束后,Test Manager 将收集所有制品并上传测试结果。测试将有权访问其父界限提供的任何功能,以及测试架构提供的所有封闭功能。

这种方法的优势

  • 开发者可以自带跑步机。
  • 您现在就可以实现此目标。无需等待任何其他功能。

其他福利

  • 开发者可以根据自己的需求配置测试领域,而无需更改核心产品或测试架构。
  • 无需支持自定义测试类型。

此解决方案的缺点包括:

  • 开发者可以创建自己的非密封 realm 来启动测试,因此我们最终可能会得到大量非密封测试,而这些测试只需稍加努力就能变成密封测试。
  • 直接使用 ffx test 的开发者需要向该工具提供其 moniker 和集合名称。
    • ffx test 是一种基础工具,因此开发者应使用其他调用 ffx test 的工具,而无需手动传递别名。

测试拓扑的图表(在 Test Manager 可用作服务后)。

测试拓扑

实现

  • 更改了 Realm Builder,使其能够通过接受 fuchsia.component.Realm 对象在任意 Realm 中启动组件。
  • 更改了测试执行器,以接受 realm 信息查询,获取所需的 moniker 信息。
  • 更改了测试管理器,以实现新的 FIDL API 并在提供的 realm 和集合中启动测试。
  • 记录更改和帮助指南
  • 与 OOT 开发者合作,创建包含 OOT 跑者的领域。
  • 将当前 OOT 测试移植到新 realm

未来工作:

  • 将使用自定义测试类型的当前测试移植到自己的 Realm。
  • 探索如何移除对别名的依赖。
  • 从测试管理器下移除所有测试 realm,并将它们发布到产品 realm 中。

性能

此项更改对性能的影响很小或没有影响,因为这不会影响测试的启动方式,只会影响测试在拓扑中的启动位置。

工效学设计

本部分介绍了一些将监控程序和测试集合传递给测试执行器的解决方案。本文档不涉及详细的解决方案。

与 build 集成

定义自定义 realm 后,产品所有者可以在其 build 系统中定义测试类别。测试作者将使用该类别,并且构建系统将生成相应的 moniker 和测试集合作为测试执行器的输入。

向测试清单添加信息

我们可以将别名和测试集合信息嵌入到测试功能中。测试执行器需要解析并读取组件清单文件才能获取信息。

为了提高人体工程学效果,测试 Realm 作者将提供清单分片,测试作者可将其包含在测试清单中。

向后兼容性

我们将继续支持当前测试,并且始终支持不需要自定义 runner 的封闭式测试 realm。

安全注意事项

  • 开发者可以在系统中的任何 realm 中启动测试,但由于测试将在 eng build 上运行,因此用户设备不会受到此更改的影响。
    • 我们还将在测试执行器中添加一个标志,以在某些共享机器和 build 上停用该功能。
  • 我们需要将 RealmQuery 和 LifecycleController 路由到所有测试执行器。这可能会引发安全问题,具体取决于我们决定如何执行此操作。 我们将在下一份文档中讨论此问题,届时我们将设计测试执行器如何访问此信息。

隐私注意事项

我们不会收集任何个人数据,因此这种设计不会产生任何隐私影响。

测试

当前测试以及用于在自定义 realm 中启动测试的新集成测试和单元测试应能充分测试此功能。

文档

记录此功能,说明用例和实现指南,以便开发者创建自己的测试领域。

还记录了测试开发者使用自定义 realm 的方式。

缺点、替代方案和未知因素

替代方案:客户自行启动测试管理器

测试开发者将在其拓扑中启动自己的 Test Manager。ffx 测试将使用 RCS 连接到 fuchsia.test.manager.RunBuilder 协议,以执行测试并收集测试结果。

此解决方案的优势:

  • 我们只需更改 ffx 测试即可支持此功能
  • 开发者可以使用当前的 Test Manager 代码及其自定义清单,以便在其拓扑中使用 Test Manager 组件

此解决方案存在以下问题:

  • 一旦测试管理器在各种拓扑和 OOT 中运行,就很难更改。这将极大地影响测试架构团队的效率。
  • 客户端需要将测试管理器所需的所有功能路由到其自身的拓扑。
  • 客户需要编写测试,以确保 Test Manager 在其拓扑中正常运行,并防止出现任何回归问题

替代方案:子组件

子程序集可以解决自带测试运行程序的问题,但不如建议的解决方案灵活。

借助提议的解决方案,我们可以在未来灵活地从测试管理器中移除所有硬编码的测试 realm,并向产品所有者提供完全所有权。

替代方案:测试自行打包运行程序

测试可以打包自己的 runner,并使用这些 runner 运行测试组件

此解决方案的优势:

  • 无需进行任何更改
  • 现在即可实现

此解决方案存在以下问题:

  • 为每个测试运行新运行程序带来的性能影响。
  • 需要将运行程序所需的功能路由到测试(破坏了密封性并削弱了我们的保证)。
  • 需要为每个新 runner 创建一个自定义 realm(由于功能路由要求)。这会加剧技术债务。

替代方案:测试配置

使用功能和这些功能的来源对测试进行参数化,然后将这些参数传递给测试 realm 本身。

"fuchsia.test.additional_capabilities": {
  "runner": "dart_runner",
  "source": "/core/dart/runner"
}

对于可路由的功能,Test Manager 可以使用 RealmQuery API 通过 Realm Builder 代理请求。对于 runner,Test Manager 可以使用 hub 来代理 runner 协议。

此解决方案的优势:

  • 测试作为 Test Manager 的子级运行,因此 Test Manager 可以完全控制其功能。

此解决方案存在以下问题:

  • 测试可能依赖于正式版别名,因此会成为公开 API 的一部分。
  • 使用 Hub 代理 Runner 请求只是一种短期解决方案,我们最终需要嵌套或链接的 Runner。
  • 测试将能够访问任何系统功能,这可能会导致安全问题,破坏显式路由,从而在远处创建操作。

替代方案:Test Manager 使用 RealmQuery API

在此设计中,测试管理器将有权访问 RealmQuery API,并使用该 API 从测试 Realm 查询所需信息以启动测试。

测试作者将使用分片在其测试清单中包含 realm 和测试集合信息。

分片:

{
  facets: {
    "fuchsia.test": {
      launch: {
        realm: "/core/foo/bar/test_realm",
        collection: "tests" // default is "tests", can be omitted.
      }
    },
  },
}

test.cml:

{
    include: [
        "syslog/client.shard.cml",
        "//some/path/oot_runner/default.shard.cml",
        "//some/path/test_realm/default.shard.cml",
    ],
    program: {
        binary: "bin/sample_test",
    },
    use: [
      {
          protocol: [
              "fuchsia.foo.bar",
              ...
          ],
      },
      ...
  ],
}

测试管理器将读取功能方面,并使用提供的功能在指定的测试 realm 中查询和启动测试。

测试拓扑

替代方案:测试管理器在拓扑中的一个已知位置运行系统测试

此设计建议在拓扑中设置一个通用的已知位置(例如 /core/tests),以便测试管理器可以在其中执行所有系统测试。平台开发者将创建并维护此已知 realm,而 Test Manager 将仅提供执行测试和收集测试制品的机制。

缺点

  • 可配置性较低,如果未来需要多个位置来运行测试,则无法扩缩。
  • 我们希望将来能够拥有嵌套的测试管理器,以便在同级 realm 中运行测试。此设计会阻止用户这样做。
  • 我们可以使用此 RFC 中的设计来实现相同的功能,并将 /core/tests 作为应运行测试的 realm。此 RFC 提供了我们认为有用的进一步灵活性。

在先技术和参考资料

这是 Fuchsia 独有的概念,因此没有相关现有技术。

未来工作

  • 从测试管理器拓扑中移除所有非密封 realm,并与我们的客户合作,将他们的测试迁移到他们自己的自定义测试 realm。
  • 将“自带测试管理器”设计为测试 realm 的同级。这有助于在会话或任何 OOT Realm 下运行测试,而无需平台提供任何产品特定的支持。