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

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

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

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

摘要

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

设计初衷

测试管理器会将测试作为动态子项启动,并为其提供各种密封/非密封功能和树内运行程序。测试管理器的当前设计是使用一组静态的内置测试运行程序和测试领域运行。它不允许树外 (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 protocol 添加一个名为 AddSuiteInRealm 的新方法,并传入所需的领域信息。

  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 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",
              },
          ],
      },
  ]
}

领域作者将提供与构建工具的集成,以便测试执行器在执行期间读取 Moniker 和测试集合。

“工效学”部分简要介绍了一些将 Moniker 和测试集合名称传递给测试执行器的解决方案,详细讨论 超出了本文档的范围。

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

测试执行器将使用 RealmQuery API 查询领域对象,以获取领域和测试集合的所有产品,并使用建议的 AddSuiteInRealm API 将它们传递给测试管理器。

如果需要,它还会使用 LifecycleController API 来解析 Moniker。

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

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

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

测试结束后,测试管理器将收集所有制品并上传测试结果。测试将有权访问其父领域提供的任何功能以及测试架构提供的所有密封功能。

此方法的优点

  • 开发者可以自带运行程序。
  • 这现在就可以实现。无需等待任何其他功能。

其他福利

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

此解决方案的缺点是:

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

测试管理器可用作服务后,测试拓扑的图表。

测试拓扑

实现

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

未来的工作:

  • 将当前使用自定义测试类型的测试移植到自己的领域。
  • 探索移除对 Moniker 的依赖。
  • 从测试管理器下移除所有测试领域,并在产品领域内发布它们。

性能

此更改不会对性能产生任何影响或影响极小,因为它不会影响测试的启动方式,只会影响测试在拓扑中的启动位置。

工效学

本部分介绍了一些将 Moniker 和测试集合传递给测试执行器的解决方案。详细解决方案超出了本文档的范围。

与构建集成

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

向测试清单添加信息

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

为了提高工效学,测试领域作者 将提供清单分片,测试作者 可以将其包含在测试清单中。

向后兼容性

我们将继续支持当前测试,并且始终支持不需要自定义运行程序的封闭测试领域。

安全注意事项

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

隐私注意事项

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

测试

当前测试以及新的集成测试和单元测试(用于在自定义领域中启动测试)应全面测试此功能。

文档

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

此外,还记录了测试开发者使用自定义领域的方式。

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

替代方案:客户端启动自己的测试管理器

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

此解决方案的优势:

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

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

  • 测试管理器在各种拓扑和 OOT 中运行后,很难对其进行更改。这将极大地影响测试架构团队的速度。
  • 客户端需要将测试管理器所需的所有功能路由到自己的拓扑。
  • 客户端需要编写测试,以确保测试管理器在其拓扑中正常运行,并防止任何回归

替代方案:子程序集

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

建议的解决方案允许我们在未来灵活地从测试管理器中移除所有硬编码的测试领域,并将完全所有权提供给产品所有者。

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

测试可以打包自己的运行程序,并使用它们运行测试组件

此解决方案的优势:

  • 无需进行任何更改
  • 这现在就可以实现

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

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

替代方案:测试配置

使用功能和这些功能的来源对测试进行参数化,然后将这些功能管道化到测试领域本身。

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

对于可路由的功能,测试管理器可以使用 RealmQuery API 通过 Realm Builder 代理请求。对于运行程序,测试管理器可以使用 hub 代理运行程序协议。

此解决方案的优势:

  • 测试作为测试管理器的子项运行,因此测试管理器可以完全控制其功能。

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

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

替代方案:测试管理器使用 RealmQuery API

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

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

分片:

{
  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",
              ...
          ],
      },
      ...
  ],
}

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

测试拓扑

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

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

缺点

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

在先技术和参考文档

这是 Fuchsia 特有的概念,因此没有相同的在先技术。

未来的工作

  • 从测试管理器拓扑中移除所有非密封领域,并与我们的客户合作,将其测试移至他们自己的自定义测试领域。
  • 设计“自带测试管理器”作为测试领域的同级。这对于在会话或任何 OOT 领域下运行测试非常有用,而无需平台中的任何产品专用支持。