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

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

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

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

总结

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

设计初衷

测试管理器将测试作为动态子级启动,为其提供各种封闭/非封闭功能和树内运行程序。测试管理器的当前设计是使用一组静态内置测试运行程序和测试领域来运行。它不允许树外 (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、ya,bighcom

咨询人员

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

社交

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

设计

在这种设计中,产品所有者将决定测试应在何处运行,测试执行程序 (ffx test/run-test-suite) 会将所需信息传递给测试管理器。我们将在 RunBuilder 协议中添加一个名为 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 协议(作用域限定为“/”)路由到测试执行程序。

测试领域可以由平台本身编写,也可以由产品所有者使用某种现有/新机制编写。到目前为止,只有平台可以定义测试领域,这项工作旨在实现测试领域定义和管理的民主化。

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

  • 测试领域作者:此用户将创建和维护将运行测试的区域(他们应有权在拓扑中创建领域)。
  • 测试作者:将在领域作者创建的领域中运行的测试的作者。

Test Realm author 将创建一个测试领域,对其进行设置并与构建工具集成,以允许测试作者运行测试。他们需要在测试领域安装 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 作者将提供与构建工具的集成,以便测试执行程序可以在执行期间读取名称和测试集合。

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

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

测试执行器将使用 RealmQuery API 查询 Realm 对象,获取该大区以及测试集合的所有优惠,并使用建议的 AddSuiteInRealm API 将它们传递给测试管理器。

如果需要,它还将使用 LifecycleController API 解析名称。

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

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

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

测试管理器将收集所有工件,并在测试结束后上传测试结果。测试将可以访问其父级领域提供的任何功能,以及测试架构提供的所有封闭功能。

这种方法的优势

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

其他福利

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

这种解决方案的缺点是:

  • 开发者可以创建自己的非封闭领域来启动测试,因此我们最终可能会进行大量的非封闭测试,这些测试本可以不费吹灰之力即可实现封闭。
  • 直接使用 ffx test 的开发者需要向该工具提供其名称和集合名称。
    • ffx 测试是一种基础工具,因此开发者应使用其他调用 ffx 测试的工具,而不需要手动传递名称。

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

测试拓扑

实现

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

后续工作:

  • 将使用自定义测试类型的当前测试移植到它们自己的领域。
  • 探索如何消除对称谓的依赖。
  • 从被测管理器中移除所有测试领域,并将其发布到产品领域。

性能

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

工效学设计

本部分介绍了一些将名称和测试集合传递给测试执行器的解决方案。详细解决方案不在本文档的讨论范围内。

与 build 集成

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

向测试清单添加信息

我们可以在测试分面中嵌入名称和测试集合信息。测试执行程序需要解析并读取组件清单文件,以获取信息。

为实现更好的工效学设计,Test Realm author 将提供清单分片,测试作者可将其包含在测试清单中。

向后兼容性

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

安全注意事项

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

隐私注意事项

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

测试

当前测试以及新集成以及用于在自定义领域启动测试的单元测试应该对此功能进行全面测试。

文档

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

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

缺点、替代方案和未知情况

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

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

此解决方案的优势:

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

此解决方案的问题包括:

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

替代方案:子组件

子组件可以解决我们自带的测试运行程序的问题,但不如提出的解决方案那样灵活。

提议的解决方案使我们将来能够灵活地从测试管理器中移除所有硬编码测试领域,并将完全所有权提供给产品负责人。

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

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

此解决方案的优势:

  • 无需进行任何更改
  • 你可以立即实现这一目标

此解决方案的问题包括:

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

替代方案:测试配置

使用功能及其来源将测试参数化,然后将这些信息传送到测试领域本身。

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

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

此解决方案的优势:

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

此解决方案的问题包括:

  • 测试可能依赖于生产名称,因此它们将成为公开的 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 领域运行测试,而无需在平台中提供任何特定于产品的支持。