集成测试

由于 ffx 主要为开发者设计,因此它会检查当前环境的配置,并在后台启动守护程序以协调与 Fuchsia 设备的通信。这会使编写使用 ffx 的自动化测试变得更加复杂,因为配置和守护程序应该进行隔离,以避免测试之间的副作用或来自全局环境的干扰。

为了解决此问题,ffx 可以在隔离的环境中运行,以在集成测试中使用。

手动隔离设置

为了实现这种隔离,ffx 支持使用隔离目录。此功能指定了供 ffx 运行的新隔离环境,包括用户级配置。ascendd 套接字(与 ffx 守护程序的连接)也在此目录中创建。

所有使用隔离的 ffx 调用都必须在 ffx 命令行中使用 --isolate-dir 选项指定隔离环境。这也可以通过设置 __FFX_ISOLATE_DIR__ 环境变量来指定。

以下伪 shell 脚本详细介绍了配置步骤和命令,以确保 ffx 是封闭的:

# Write all configuration and state to the isolate directory, using mktemp or
# something similar.
export FFX_ISOLATE_DIR = ...

# Disable analytics:
ffx config set ffx.analytics.disabled true
# Don't discover devices via mDNS:
ffx config set discovery.mdns.enabled false
# Don't discover fastboot devices connected via USB:
ffx config set fastboot.usb.disabled true
# Require manual process management for the daemon:
ffx config set daemon.autostart false

# If needed, start daemon:
# ffx outputs log files under $FUCHSIA_TEST_OUTDIR/ffx_logs by default.
LOG_DIR = "$FUCHSIA_TEST_OUTDIR/ffx_logs"
# Redirect stdout and stderr to the log file
ffx daemon start > "$LOG_DIR/ffx.daemon.log" 2> "$LOG_DIR/ffx.daemon.log" &

# If interacting with a device:
ffx config target.default "$FUCHSIA_DEVICE_ADDR"
ffx target add "$FUCHSIA_DEVICE_ADDR"

测试完成后,测试作者需要清理隔离目录。删除目录会关闭守护程序;建议使用 ffx daemon stop,但不强制要求。我们不建议您终止守护程序进程,因为它可能会导致日志文件中遗漏信息。

树内 Rust 隔离库

在 Fuchsia 源代码树中,使用 Rust 编程语言的开发者应在测试中使用 //src/developer/ffx/lib/isolate,以创建隔离目录并与其交互。

隔离库会自动遵循上述手动设置准则,并在拖放时清理隔离目录。

初始化测试的全局上下文

为避免从主机环境初始化全局上下文,测试需要创建一个测试环境来初始化全局数据。当返回值被丢弃时,环境将被清理,因此它必须在测试生命周期的范围内。

let test_env = ffx_config::test_init().await?;

创建隔离

您可以通过两种方法创建新的隔离,具体取决于 ffx 运行的环境。对于在树内测试中运行且依赖于 build 输出目录结构的测试,请使用 Isolate::new_in_test()。对于属于 ffx 子工具或基于 SDK 的测试,请使用 Isolate::new_in_sdk()。如果测试与外部预配的设备交互,则也应该传入 SSH 私钥的路径。如果测试是初始化设备或启动模拟器,则系统会根据需要生成 SSH 密钥,但需要在创建隔离后配置密钥的存储位置。

隔离被丢弃时,系统会清理隔离目录,因此该目录必须在整个测试中都存在。

Isolate::new_in_test() 示例

  let test_case_name = "my test";
  let ssh_path = std::env::var("FUCHSIA_SSH_KEY").unwrap().into();
  let test_env = ffx_config::test_init().await
      .expect("Setting up test environment");
  // This takes advantage of knowing that Rust tests are down one level from the
  // build output root directory.
  let build_root =
        std::env::current_exe().unwrap().canonicalize().unwrap().parent().unwrap().to_owned();
  let isolate = ffx_isolate::Isolate::new_in_test(test_case_name,
                                                  build_root,
                                                  ssh_path,
                                                  &test_env.context).await
            .expect("create isolate");

Isolate::new_in_sdk() 示例

  let test_case_name = "my test";
  let ssh_path = std::env::var("FUCHSIA_SSH_KEY").unwrap().into();
  let test_env = ffx_config::test_init().await
      .expect("Setting up test environment");
  let isolate = ffx_isolate::Isolate::new_with_sdk(test_case_name, ssh_path, &test_env.context)
            .await
            .expect("create isolate");

启动 ffx 守护程序

ffx 守护程序必须通过 Isolate::start_daemon() 方法手动启动。并非所有命令都依赖于该守护程序,并且某些命令(如 ffx config set)可能需要在启动该守护程序之前运行。

let _ = isolate.start_daemon().await?;

注意:直接运行 ffx daemon start 不会启动可正常运行的守护程序。

运行 ffx 命令

如需在隔离环境中运行命令,请使用 Isolate::ffx() 方法。此封装容器会将正确的选项添加到 ffx 命令行,以使用隔离目录。

let output = isolate.ffx(&["target", "list"]).await?;

隔离中的配置

您可以使用 ffx config 命令行在隔离中配置 ffx 的值和默认值:

let args = ["config", "set", "ssh.pub", &path_to_ssh_authorized_keys.to_string_lossy()];
let output = isolate.ffx(&args).await?;

日志文件

使用隔离时,系统会在创建隔离时配置 ffx 的日志文件路径。一种常见做法是,让测试框架为需要可作为测试输出访问的文件设置环境变量 __FUCHSIA_TEST_OUTDIR__。如果已配置,系统会在 __FUCHSIA_TEST_OUTDIR__ 的子目录中创建日志目录。可使用 log_dir() 访问日志目录的路径。

let log_dir = isolate.log_dir();

默认目标

某些测试框架可能会为运行测试分配设备。该隔离会读取 __FUCHSIA_DEVICE_ADDR__ 环境变量,并将其设置为配置中的默认目标。

Analytics(分析)配置

该隔离会通过配置停用 Analytics 数据收集。