Docs cover 1774 commands; tests cover 185; usage covers 300. Tests is the bottleneck — every Completed command needs all three. Closing the largest group would move 93% of the debt — the biggest single shift available.
Coverage counts the docs that exist; depth weighs what they actually say — from full behavioral prose down to a bare signature stub.
How far the non-reference docs have fallen behind the code — measured in days, from git commit timestamps.
{
"command": "ffx",
"options": [
{
"description": "set config values (key=value, JSON string, or file path).",
"option": "config",
"shorthand": "c",
"value_type": "string"
},
{
"description": "override path to environment config file.",
"option": "env",
N/A
N/A
N/A
{
"command": "ffx",
"options": [
{
"description": "set config values (key=value, JSON string, or file path).",
"option": "config",
"shorthand": "c",
"value_type": "string"
},
{
"description": "override path to environment config file.",
"option": "env",
// Copyright 2021 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use crate::assert_eq;
use crate::test::new_isolate;
use anyhow::*;
use ffx_config::EnvironmentContext;
use fuchsia_async::MonotonicDuration;
use nix::sys::signal;
use nix::unistd::Pid;
use std::path::PathBuf;
use std::thread::sleep;
use std::time::Duration as StdDuration;
pub(crate) async fn test_echo(context: EnvironmentContext) -> Result<()> {
let isolate = new_isolate(&context, "daemon-echo").await?;
isolate.start_daemon().await?;
let out = isolate.ffx(&["daemon", "echo"]).await?;
let want = "SUCCESS: received \"Ffx\"\n";
assert_eq!(out.stdout, want);
Ok(())
}
```posix-terminal
```posix-terminal
```posix-terminal
N/A
{
"command": "ffx",
"options": [
{
"description": "set config values (key=value, JSON string, or file path).",
"option": "config",
"shorthand": "c",
"value_type": "string"
},
{
"description": "override path to environment config file.",
"option": "env",
N/A
N/A
N/A
{
"command": "ffx",
"options": [
{
"description": "set config values (key=value, JSON string, or file path).",
"option": "config",
"shorthand": "c",
"value_type": "string"
},
{
"description": "override path to environment config file.",
"option": "env",
N/A
N/A
N/A
{
"command": "ffx",
"options": [
{
"description": "set config values (key=value, JSON string, or file path).",
"option": "config",
"shorthand": "c",
"value_type": "string"
},
{
"description": "override path to environment config file.",
"option": "env",
N/A
N/A
{
"command": "ffx",
"options": [
{
"description": "set config values (key=value, JSON string, or file path).",
"option": "config",
"shorthand": "c",
"value_type": "string"
},
{
"description": "override path to environment config file.",
"option": "env",
N/A
N/A
N/A
{
"command": "ffx",
"options": [
{
"description": "set config values (key=value, JSON string, or file path).",
"option": "config",
"shorthand": "c",
"value_type": "string"
},
{
"description": "override path to environment config file.",
"option": "env",
N/A
N/A
N/A
{
"command": "ffx",
"options": [
{
"description": "set config values (key=value, JSON string, or file path).",
"option": "config",
"shorthand": "c",
"value_type": "string"
},
{
"description": "override path to environment config file.",
"option": "env",
// Copyright 2021 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use crate::assert_eq;
use crate::test::new_isolate;
use anyhow::*;
use ffx_config::EnvironmentContext;
use fuchsia_async::MonotonicDuration;
use nix::sys::signal;
use nix::unistd::Pid;
use std::path::PathBuf;
use std::thread::sleep;
use std::time::Duration as StdDuration;
pub(crate) async fn test_echo(context: EnvironmentContext) -> Result<()> {
let isolate = new_isolate(&context, "daemon-echo").await?;
isolate.start_daemon().await?;
let out = isolate.ffx(&["daemon", "echo"]).await?;
let want = "SUCCESS: received \"Ffx\"\n";
assert_eq!(out.stdout, want);
Ok(())
}
// Copyright 2023 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#[cfg(test)]
mod tests {
use ffx_command::CliArgsInfo;
use ffx_testing::{TestContext, base_fixture};
use fixture::fixture;
use std::collections::HashSet;
// base_fixture sets up the test environment this test
#[fixture(base_fixture)]
#[fuchsia::test]
async fn test_top_level(ctx: TestContext) {
// Get the top level help and make sure all the commands in `ffx commands` are listed.
let (builtins, externals) = parse_top_level_commands(&ctx).await;
// We're not concerned in this test how many commands were returned, just that a reasonable number was.
assert!(builtins.len() >= 5, "Expected at least 5 builtin commands, got {builtins:?}");
assert!(externals.len() >= 1, "Expected at least 1 external command, got {externals:?}");
// Now get the json help and make sure all the commands are referenced.
let output = ctx.isolate().ffx(&["--machine", "json", "--help"]).await.expect("help");
assert!(output.status.success());
let info: CliArgsInfo = serde_json::from_str(&output.stdout).expect("parsing json");
assert_eq!("Ffx", info.name);
// look for --machine and --help and --verbose, which are _some_ of the flags, just
// making sure the flags were populated.
#[fuchsia::test]
async fn test_top_level(ctx: TestContext) {
// Get the top level help and make sure all the commands in `ffx commands` are listed.
let (builtins, externals) = parse_top_level_commands(&ctx).await;
// We're not concerned in this test how many commands were returned, just that a reasonable number was.
assert!(builtins.len() >= 5, "Expected at least 5 builtin commands, got {builtins:?}");
assert!(externals.len() >= 1, "Expected at least 1 external command, got {externals:?}");
// Now get the json help and make sure all the commands are referenced.
let output = ctx.isolate().ffx(&["--machine", "json", "--help"]).await.expect("help");
assert!(output.status.success());
let info: CliArgsInfo = serde_json::from_str(&output.stdout).expect("parsing json");
assert_eq!("Ffx", info.name);
// look for --machine and --help and --verbose, which are _some_ of the flags, just
// making sure the flags were populated.
assert!(info.flags.iter().any(|f| f.long == "--machine"), "expected --machine flag");
assert!(info.flags.iter().any(|f| f.long == "--help"), "expected --help flag");
assert!(info.flags.iter().any(|f| f.long == "--verbose"), "expected --verbose flag");
// now check all the built-in commands are present
for cmd in builtins {
assert!(
info.commands.iter().any(|c| c.name == cmd),
"expected builtin {cmd} subcommand"
);
}
// now check all the built-in commands are present
for cmd in externals {
```posix-terminal
N/A
{
"command": "ffx",
"options": [
{
"description": "set config values (key=value, JSON string, or file path).",
"option": "config",
"shorthand": "c",
"value_type": "string"
},
{
"description": "override path to environment config file.",
"option": "env",
N/A
N/A
N/A
{
"command": "ffx",
"options": [
{
"description": "set config values (key=value, JSON string, or file path).",
"option": "config",
"shorthand": "c",
"value_type": "string"
},
{
"description": "override path to environment config file.",
"option": "env",
N/A
N/A
N/A
{
"command": "ffx",
"options": [
{
"description": "set config values (key=value, JSON string, or file path).",
"option": "config",
"shorthand": "c",
"value_type": "string"
},
{
"description": "override path to environment config file.",
"option": "env",
N/A
N/A
N/A
{
"command": "ffx",
"options": [
{
"description": "set config values (key=value, JSON string, or file path).",
"option": "config",
"shorthand": "c",
"value_type": "string"
},
{
"description": "override path to environment config file.",
"option": "env",
This is only _required_ when a command supports `ffx --strict`, which will verify that the target is specified on the command line, unless the tool has this declaration. However, it is good practice to add this attribute to any tool that does not interact with a target device.
N/A
N/A
N/A
{
"command": "ffx",
"options": [
{
"description": "set config values (key=value, JSON string, or file path).",
"option": "config",
"shorthand": "c",
"value_type": "string"
},
{
"description": "override path to environment config file.",
"option": "env",
// Copyright 2021 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use crate::test::*;
use anyhow::*;
use ffx_config::EnvironmentContext;
pub mod include_target {
use super::*;
pub(crate) async fn test_list(context: EnvironmentContext) -> Result<()> {
let isolate = new_isolate(&context, "component-list").await?;
isolate.start_daemon().await?;
let target_nodeaddr = get_target_addr();
let out = isolate.ffx(&["--target", &target_nodeaddr, "component", "list"]).await?;
ensure!(out.status.success(), "status is unexpected: {:?}", out);
ensure!(!out.stdout.is_empty(), "stdout is unexpectedly empty: {:?}", out);
ensure!(out.stderr.lines().count() == 0, "stderr is unexpected: {:?}", out);
Ok(())
}
}
// Copyright 2021 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use crate::test::*;
use anyhow::*;
use ffx_config::EnvironmentContext;
use std::time::Duration;
pub(crate) async fn test_manual_add_target_list(context: EnvironmentContext) -> Result<()> {
let isolate = new_isolate(&context, "target-manual-add-target-list").await?;
isolate.start_daemon().await?;
let _ = isolate.ffx(&["target", "add", "--nowait", "[::1]:8022"]).await?;
let out = isolate
.ffx(&["--target", "[::1]:8022", "target", "list", "--format", "a", "--no-probe"])
.await?;
ensure!(out.stdout.contains("[::1]:8022"), "stdout is unexpected: {:?}", out);
ensure!(out.stderr.lines().count() == 0, "stderr is unexpected: {:?}", out);
// TODO: establish a good way to assert against the whole target address.
Ok(())
}
```posix-terminal
```posix-terminal
```posix-terminal
N/A
{
"command": "ffx",
"options": [
{
"description": "set config values (key=value, JSON string, or file path).",
"option": "config",
"shorthand": "c",
"value_type": "string"
},
{
"description": "override path to environment config file.",
"option": "env",
N/A
N/A
N/A
{
"command": "ffx",
"options": [
{
"description": "set config values (key=value, JSON string, or file path).",
"option": "config",
"shorthand": "c",
"value_type": "string"
},
{
"description": "override path to environment config file.",
"option": "env",
N/A
N/A
N/A
{
"command": "ffx assembly",
"options": [],
"short": "Assemble images"
}
#[test]
fn test_error_source_flatten_no_context() {
assert_eq!(
"Some Operation Failed",
make_flattened_error_display_string(anyhow!("Some Operation"))
);
}
#[test]
fn test_error_source_flatten_one_context() {
let expected = "Some Other Operation Failed\n 1. some failure";
let error = anyhow!("some failure");
let error = error.context("Some Other Operation");
assert_eq!(expected, make_flattened_error_display_string(error));
}
#[test]
fn test_error_source_flatten_two_contexts() {
let expected = "Some Operation Failed\n 1. some context\n 2. some failure";
let error = anyhow!("some failure");
let error = error.context("some context");
let error = error.context("Some Operation");
assert_eq!(expected, make_flattened_error_display_string(error));
}
N/A
{
"command": "ffx assembly board-input-bundle",
"options": [
{
"description": "the directory to write the board input bundle to.",
"option": "outdir",
"shorthand": "",
"value_type": "string"
},
{
"description": "the path to write a depfile to, which contains all the files read in the process of creating the bundle. The output file listed in the depfile is '$outdir/board_input_bundle.json'.",
"option": "depfile",
N/A
N/A
N/A
{
"command": "ffx assembly board-input-bundle",
"options": [
{
"description": "the directory to write the board input bundle to.",
"option": "outdir",
"shorthand": "",
"value_type": "string"
},
{
"description": "the path to write a depfile to, which contains all the files read in the process of creating the bundle. The output file listed in the depfile is '$outdir/board_input_bundle.json'.",
"option": "depfile",
N/A
N/A
N/A
{
"command": "ffx assembly board-input-bundle",
"options": [
{
"description": "the directory to write the board input bundle to.",
"option": "outdir",
"shorthand": "",
"value_type": "string"
},
{
"description": "the path to write a depfile to, which contains all the files read in the process of creating the bundle. The output file listed in the depfile is '$outdir/board_input_bundle.json'.",
"option": "depfile",
N/A
N/A
N/A
{
"command": "ffx assembly board-input-bundle",
"options": [
{
"description": "the directory to write the board input bundle to.",
"option": "outdir",
"shorthand": "",
"value_type": "string"
},
{
"description": "the path to write a depfile to, which contains all the files read in the process of creating the bundle. The output file listed in the depfile is '$outdir/board_input_bundle.json'.",
"option": "depfile",
N/A
N/A
N/A
{
"command": "ffx assembly board-input-bundle",
"options": [
{
"description": "the directory to write the board input bundle to.",
"option": "outdir",
"shorthand": "",
"value_type": "string"
},
{
"description": "the path to write a depfile to, which contains all the files read in the process of creating the bundle. The output file listed in the depfile is '$outdir/board_input_bundle.json'.",
"option": "depfile",
N/A
N/A
N/A
{
"command": "ffx assembly board-input-bundle",
"options": [
{
"description": "the directory to write the board input bundle to.",
"option": "outdir",
"shorthand": "",
"value_type": "string"
},
{
"description": "the path to write a depfile to, which contains all the files read in the process of creating the bundle. The output file listed in the depfile is '$outdir/board_input_bundle.json'.",
"option": "depfile",
N/A
N/A
N/A
{
"command": "ffx assembly board-input-bundle",
"options": [
{
"description": "the directory to write the board input bundle to.",
"option": "outdir",
"shorthand": "",
"value_type": "string"
},
{
"description": "the path to write a depfile to, which contains all the files read in the process of creating the bundle. The output file listed in the depfile is '$outdir/board_input_bundle.json'.",
"option": "depfile",
N/A
N/A
N/A
{
"command": "ffx assembly board-input-bundle",
"options": [
{
"description": "the directory to write the board input bundle to.",
"option": "outdir",
"shorthand": "",
"value_type": "string"
},
{
"description": "the path to write a depfile to, which contains all the files read in the process of creating the bundle. The output file listed in the depfile is '$outdir/board_input_bundle.json'.",
"option": "depfile",
N/A
N/A
N/A
{
"command": "ffx assembly board-input-bundle",
"options": [
{
"description": "the directory to write the board input bundle to.",
"option": "outdir",
"shorthand": "",
"value_type": "string"
},
{
"description": "the path to write a depfile to, which contains all the files read in the process of creating the bundle. The output file listed in the depfile is '$outdir/board_input_bundle.json'.",
"option": "depfile",
N/A
N/A
N/A
{
"command": "ffx assembly board-input-bundle",
"options": [
{
"description": "the directory to write the board input bundle to.",
"option": "outdir",
"shorthand": "",
"value_type": "string"
},
{
"description": "the path to write a depfile to, which contains all the files read in the process of creating the bundle. The output file listed in the depfile is '$outdir/board_input_bundle.json'.",
"option": "depfile",
N/A
N/A
N/A
{
"command": "ffx assembly board-input-bundle",
"options": [
{
"description": "the directory to write the board input bundle to.",
"option": "outdir",
"shorthand": "",
"value_type": "string"
},
{
"description": "the path to write a depfile to, which contains all the files read in the process of creating the bundle. The output file listed in the depfile is '$outdir/board_input_bundle.json'.",
"option": "depfile",
N/A
N/A
N/A
{
"command": "ffx assembly board-input-bundle",
"options": [
{
"description": "the directory to write the board input bundle to.",
"option": "outdir",
"shorthand": "",
"value_type": "string"
},
{
"description": "the path to write a depfile to, which contains all the files read in the process of creating the bundle. The output file listed in the depfile is '$outdir/board_input_bundle.json'.",
"option": "depfile",
N/A
N/A
N/A
{
"command": "ffx assembly board-input-bundle",
"options": [
{
"description": "the directory to write the board input bundle to.",
"option": "outdir",
"shorthand": "",
"value_type": "string"
},
{
"description": "the path to write a depfile to, which contains all the files read in the process of creating the bundle. The output file listed in the depfile is '$outdir/board_input_bundle.json'.",
"option": "depfile",
N/A
N/A
N/A
{
"command": "ffx assembly board-input-bundle",
"options": [
{
"description": "the directory to write the board input bundle to.",
"option": "outdir",
"shorthand": "",
"value_type": "string"
},
{
"description": "the path to write a depfile to, which contains all the files read in the process of creating the bundle. The output file listed in the depfile is '$outdir/board_input_bundle.json'.",
"option": "depfile",
N/A
N/A
N/A
{
"command": "ffx assembly board-input-bundle",
"options": [
{
"description": "the directory to write the board input bundle to.",
"option": "outdir",
"shorthand": "",
"value_type": "string"
},
{
"description": "the path to write a depfile to, which contains all the files read in the process of creating the bundle. The output file listed in the depfile is '$outdir/board_input_bundle.json'.",
"option": "depfile",
N/A
N/A
N/A
{
"command": "ffx assembly create-system",
"options": [
{
"description": "the platform artifacts directory. this is needed in order to retrieve the assembly binary.",
"option": "platform",
"shorthand": "",
"value_type": "string"
},
{
"description": "the configuration file that specifies the packages, binaries, and settings specific to the product being assembled.",
"option": "image-assembly-config",
N/A
N/A
{
"command": "ffx assembly create-system",
"options": [
{
"description": "the platform artifacts directory. this is needed in order to retrieve the assembly binary.",
"option": "platform",
"shorthand": "",
"value_type": "string"
},
{
"description": "the configuration file that specifies the packages, binaries, and settings specific to the product being assembled.",
"option": "image-assembly-config",
N/A
N/A
N/A
{
"command": "ffx assembly create-system",
"options": [
{
"description": "the platform artifacts directory. this is needed in order to retrieve the assembly binary.",
"option": "platform",
"shorthand": "",
"value_type": "string"
},
{
"description": "the configuration file that specifies the packages, binaries, and settings specific to the product being assembled.",
"option": "image-assembly-config",
N/A
N/A
N/A
{
"command": "ffx assembly create-system",
"options": [
{
"description": "the platform artifacts directory. this is needed in order to retrieve the assembly binary.",
"option": "platform",
"shorthand": "",
"value_type": "string"
},
{
"description": "the configuration file that specifies the packages, binaries, and settings specific to the product being assembled.",
"option": "image-assembly-config",
N/A
N/A
N/A
{
"command": "ffx assembly create-system",
"options": [
{
"description": "the platform artifacts directory. this is needed in order to retrieve the assembly binary.",
"option": "platform",
"shorthand": "",
"value_type": "string"
},
{
"description": "the configuration file that specifies the packages, binaries, and settings specific to the product being assembled.",
"option": "image-assembly-config",
N/A
N/A
N/A
{
"command": "ffx assembly create-system",
"options": [
{
"description": "the platform artifacts directory. this is needed in order to retrieve the assembly binary.",
"option": "platform",
"shorthand": "",
"value_type": "string"
},
{
"description": "the configuration file that specifies the packages, binaries, and settings specific to the product being assembled.",
"option": "image-assembly-config",
N/A
N/A
N/A
{
"command": "ffx assembly create-system",
"options": [
{
"description": "the platform artifacts directory. this is needed in order to retrieve the assembly binary.",
"option": "platform",
"shorthand": "",
"value_type": "string"
},
{
"description": "the configuration file that specifies the packages, binaries, and settings specific to the product being assembled.",
"option": "image-assembly-config",
N/A
N/A
N/A
{
"command": "ffx assembly create-system",
"options": [
{
"description": "the platform artifacts directory. this is needed in order to retrieve the assembly binary.",
"option": "platform",
"shorthand": "",
"value_type": "string"
},
{
"description": "the configuration file that specifies the packages, binaries, and settings specific to the product being assembled.",
"option": "image-assembly-config",
N/A
N/A
N/A
{
"command": "ffx assembly create-update",
"options": [
{
"description": "path to a partitions config, which specifies where in the partition table the images are put.",
"option": "partitions",
"shorthand": "",
"value_type": "string"
},
{
"description": "path to an images manifest, which specifies images to put in slot A.",
"option": "system-a",
N/A
N/A
{
"command": "ffx assembly create-update",
"options": [
{
"description": "path to a partitions config, which specifies where in the partition table the images are put.",
"option": "partitions",
"shorthand": "",
"value_type": "string"
},
{
"description": "path to an images manifest, which specifies images to put in slot A.",
"option": "system-a",
N/A
N/A
N/A
{
"command": "ffx assembly create-update",
"options": [
{
"description": "path to a partitions config, which specifies where in the partition table the images are put.",
"option": "partitions",
"shorthand": "",
"value_type": "string"
},
{
"description": "path to an images manifest, which specifies images to put in slot A.",
"option": "system-a",
N/A
N/A
N/A
{
"command": "ffx assembly create-update",
"options": [
{
"description": "path to a partitions config, which specifies where in the partition table the images are put.",
"option": "partitions",
"shorthand": "",
"value_type": "string"
},
{
"description": "path to an images manifest, which specifies images to put in slot A.",
"option": "system-a",
N/A
N/A
N/A
{
"command": "ffx assembly create-update",
"options": [
{
"description": "path to a partitions config, which specifies where in the partition table the images are put.",
"option": "partitions",
"shorthand": "",
"value_type": "string"
},
{
"description": "path to an images manifest, which specifies images to put in slot A.",
"option": "system-a",
N/A
N/A
N/A
{
"command": "ffx assembly create-update",
"options": [
{
"description": "path to a partitions config, which specifies where in the partition table the images are put.",
"option": "partitions",
"shorthand": "",
"value_type": "string"
},
{
"description": "path to an images manifest, which specifies images to put in slot A.",
"option": "system-a",
N/A
N/A
N/A
{
"command": "ffx assembly create-update",
"options": [
{
"description": "path to a partitions config, which specifies where in the partition table the images are put.",
"option": "partitions",
"shorthand": "",
"value_type": "string"
},
{
"description": "path to an images manifest, which specifies images to put in slot A.",
"option": "system-a",
N/A
N/A
N/A
{
"command": "ffx assembly create-update",
"options": [
{
"description": "path to a partitions config, which specifies where in the partition table the images are put.",
"option": "partitions",
"shorthand": "",
"value_type": "string"
},
{
"description": "path to an images manifest, which specifies images to put in slot A.",
"option": "system-a",
N/A
N/A
N/A
{
"command": "ffx assembly create-update",
"options": [
{
"description": "path to a partitions config, which specifies where in the partition table the images are put.",
"option": "partitions",
"shorthand": "",
"value_type": "string"
},
{
"description": "path to an images manifest, which specifies images to put in slot A.",
"option": "system-a",
N/A
N/A
N/A
{
"command": "ffx assembly create-update",
"options": [
{
"description": "path to a partitions config, which specifies where in the partition table the images are put.",
"option": "partitions",
"shorthand": "",
"value_type": "string"
},
{
"description": "path to an images manifest, which specifies images to put in slot A.",
"option": "system-a",
N/A
N/A
N/A
{
"command": "ffx assembly create-update",
"options": [
{
"description": "path to a partitions config, which specifies where in the partition table the images are put.",
"option": "partitions",
"shorthand": "",
"value_type": "string"
},
{
"description": "path to an images manifest, which specifies images to put in slot A.",
"option": "system-a",
N/A
N/A
N/A
{
"command": "ffx assembly create-update",
"options": [
{
"description": "path to a partitions config, which specifies where in the partition table the images are put.",
"option": "partitions",
"shorthand": "",
"value_type": "string"
},
{
"description": "path to an images manifest, which specifies images to put in slot A.",
"option": "system-a",
N/A
N/A
N/A
{
"command": "ffx assembly product",
"options": [
{
"description": "the product configuration directory.",
"option": "product",
"shorthand": "",
"value_type": "string"
},
{
"description": "the board configuration directory.",
"option": "board-config",
#[test]
fn extract_blob_contents_test() -> Result<()> {
let blobfs_contents = BlobfsContents {
packages: PackagesMetadata {
base: PackageSetMetadata {
metadata: vec![PackageMetadata {
name: "hello".to_string(),
manifest: "path".into(),
blobs: Default::default(),
abi_revision: Some(version_history::AbiRevision::from_u64(1234)),
}],
},
cache: PackageSetMetadata { metadata: vec![] },
},
maximum_contents_size: Some(1234),
};
let mut assembled_system = AssembledSystem {
images: vec![Image::VBMeta("a/b/c".into()), Image::FVM("x/y/z".into())],
board_name: "my_board".into(),
partitions_config: None,
system_release_info: SystemReleaseInfo::new_for_testing(),
platform_tools: vec![],
};
assert_eq!(extract_blob_contents(&assembled_system), None);
assembled_system
.images
.push(Image::BlobFS { path: "path/to/blob.blk".into(), contents: blobfs_contents });
let blobfs_contents =
extract_blob_contents(&assembled_system).expect("blobfs contents is found");
#[test]
fn gerrit_report_test() {
let gerrit_report = create_gerrit_report(
&SizeResult { consumed_bytes: 151, consumed_bytes_resources: 30 },
200,
20,
50,
);
assert_eq!(
gerrit_report,
json!({
TOTAL_BLOBFS_GERRIT_COMPONENT_NAME: 121,
format!("{TOTAL_BLOBFS_GERRIT_COMPONENT_NAME}.budget"): 150,
format!("{TOTAL_BLOBFS_GERRIT_COMPONENT_NAME}.creepBudget"): 20,
TOTAL_RESOURCES_GERRIT_COMPONENT_NAME: 30,
format!("{TOTAL_RESOURCES_GERRIT_COMPONENT_NAME}.budget"): 50,
format!("{TOTAL_RESOURCES_GERRIT_COMPONENT_NAME}.creepBudget"): 2097152,
})
)
}
N/A
N/A
{
"command": "ffx assembly product",
"options": [
{
"description": "the product configuration directory.",
"option": "product",
"shorthand": "",
"value_type": "string"
},
{
"description": "the board configuration directory.",
"option": "board-config",
N/A
N/A
N/A
{
"command": "ffx assembly product",
"options": [
{
"description": "the product configuration directory.",
"option": "product",
"shorthand": "",
"value_type": "string"
},
{
"description": "the board configuration directory.",
"option": "board-config",
N/A
N/A
N/A
{
"command": "ffx assembly product",
"options": [
{
"description": "the product configuration directory.",
"option": "product",
"shorthand": "",
"value_type": "string"
},
{
"description": "the board configuration directory.",
"option": "board-config",
N/A
N/A
N/A
{
"command": "ffx assembly product",
"options": [
{
"description": "the product configuration directory.",
"option": "product",
"shorthand": "",
"value_type": "string"
},
{
"description": "the board configuration directory.",
"option": "board-config",
N/A
N/A
N/A
{
"command": "ffx assembly product",
"options": [
{
"description": "the product configuration directory.",
"option": "product",
"shorthand": "",
"value_type": "string"
},
{
"description": "the board configuration directory.",
"option": "board-config",
N/A
N/A
N/A
{
"command": "ffx assembly product",
"options": [
{
"description": "the product configuration directory.",
"option": "product",
"shorthand": "",
"value_type": "string"
},
{
"description": "the board configuration directory.",
"option": "board-config",
N/A
N/A
N/A
{
"command": "ffx assembly product",
"options": [
{
"description": "the product configuration directory.",
"option": "product",
"shorthand": "",
"value_type": "string"
},
{
"description": "the board configuration directory.",
"option": "board-config",
N/A
N/A
N/A
{
"command": "ffx assembly product",
"options": [
{
"description": "the product configuration directory.",
"option": "product",
"shorthand": "",
"value_type": "string"
},
{
"description": "the board configuration directory.",
"option": "board-config",
N/A
N/A
N/A
{
"command": "ffx assembly product",
"options": [
{
"description": "the product configuration directory.",
"option": "product",
"shorthand": "",
"value_type": "string"
},
{
"description": "the board configuration directory.",
"option": "board-config",
N/A
N/A
N/A
{
"command": "ffx assembly product",
"options": [
{
"description": "the product configuration directory.",
"option": "product",
"shorthand": "",
"value_type": "string"
},
{
"description": "the board configuration directory.",
"option": "board-config",
N/A
N/A
N/A
{
"command": "ffx assembly product",
"options": [
{
"description": "the product configuration directory.",
"option": "product",
"shorthand": "",
"value_type": "string"
},
{
"description": "the board configuration directory.",
"option": "board-config",
N/A
N/A
N/A
{
"command": "ffx assembly product",
"options": [
{
"description": "the product configuration directory.",
"option": "product",
"shorthand": "",
"value_type": "string"
},
{
"description": "the board configuration directory.",
"option": "board-config",
N/A
N/A
N/A
{
"command": "ffx assembly product",
"options": [
{
"description": "the product configuration directory.",
"option": "product",
"shorthand": "",
"value_type": "string"
},
{
"description": "the board configuration directory.",
"option": "board-config",
N/A
N/A
N/A
{
"command": "ffx assembly product",
"options": [
{
"description": "the product configuration directory.",
"option": "product",
"shorthand": "",
"value_type": "string"
},
{
"description": "the board configuration directory.",
"option": "board-config",
N/A
N/A
N/A
{
"command": "ffx assembly size-check",
"options": [],
"short": "Perform size checks (on packages or product based on the sub-command)."
}
N/A
N/A
N/A
{
"command": "ffx assembly size-check package",
"options": [
{
"description": "path to a JSON file containing the list of size budgets. Each size budget has a `name`, a `size` which is the maximum number of bytes, and `packages` a list of path to manifest files.",
"option": "budgets",
"shorthand": "",
"value_type": "string"
},
{
"description": "path to a `blobs.json` file. It provides the size of each blob composing the package on device.",
"option": "blob-sizes",
#[test]
fn default_creep() {
let budgets: BudgetConfig = serde_json::from_value(json!({
"package_set_budgets":[
{
"name": "budget_name",
"budget_bytes": 10,
"packages": [],
},
]}))
.unwrap();
assert_eq!(budgets.package_set_budgets.len(), 1);
let package_set_budget = &budgets.package_set_budgets[0];
assert_eq!(package_set_budget.creep_budget_bytes, 0);
}
#[test]
fn fails_because_of_missing_blobs_file() {
let test_fs = TestFs::new();
test_fs.write("size_budgets.json", json!({}));
let err = verify_budgets_with_tools(
PackageSizeCheckArgs {
blobfs_layout: BlobfsLayout::Compact,
budgets: test_fs.path("size_budgets.json"),
blob_sizes: [test_fs.path("blobs.json")].to_vec(),
gerrit_output: None,
verbose: false,
verbose_json_output: None,
},
Box::new(FakeToolProvider::default()),
);
assert_failed(err, "Packages budget is empty");
}
#[test]
fn fails_because_of_missing_budget_file() {
let test_fs = TestFs::new();
test_fs.write("blobs.json", json!([]));
let err = verify_budgets_with_tools(
PackageSizeCheckArgs {
blobfs_layout: BlobfsLayout::Compact,
budgets: test_fs.path("size_budgets.json"),
blob_sizes: [test_fs.path("blobs.json")].to_vec(),
gerrit_output: None,
verbose: false,
verbose_json_output: None,
},
Box::new(FakeToolProvider::default()),
);
assert_eq!(err.exit_code(), 1);
assert_failed(err, "Unable to open file:");
}
N/A
N/A
{
"command": "ffx assembly size-check package",
"options": [
{
"description": "path to a JSON file containing the list of size budgets. Each size budget has a `name`, a `size` which is the maximum number of bytes, and `packages` a list of path to manifest files.",
"option": "budgets",
"shorthand": "",
"value_type": "string"
},
{
"description": "path to a `blobs.json` file. It provides the size of each blob composing the package on device.",
"option": "blob-sizes",
N/A
N/A
N/A
{
"command": "ffx assembly size-check package",
"options": [
{
"description": "path to a JSON file containing the list of size budgets. Each size budget has a `name`, a `size` which is the maximum number of bytes, and `packages` a list of path to manifest files.",
"option": "budgets",
"shorthand": "",
"value_type": "string"
},
{
"description": "path to a `blobs.json` file. It provides the size of each blob composing the package on device.",
"option": "blob-sizes",
N/A
N/A
N/A
{
"command": "ffx assembly size-check package",
"options": [
{
"description": "path to a JSON file containing the list of size budgets. Each size budget has a `name`, a `size` which is the maximum number of bytes, and `packages` a list of path to manifest files.",
"option": "budgets",
"shorthand": "",
"value_type": "string"
},
{
"description": "path to a `blobs.json` file. It provides the size of each blob composing the package on device.",
"option": "blob-sizes",
N/A
N/A
N/A
{
"command": "ffx assembly size-check package",
"options": [
{
"description": "path to a JSON file containing the list of size budgets. Each size budget has a `name`, a `size` which is the maximum number of bytes, and `packages` a list of path to manifest files.",
"option": "budgets",
"shorthand": "",
"value_type": "string"
},
{
"description": "path to a `blobs.json` file. It provides the size of each blob composing the package on device.",
"option": "blob-sizes",
N/A
N/A
N/A
{
"command": "ffx assembly size-check package",
"options": [
{
"description": "path to a JSON file containing the list of size budgets. Each size budget has a `name`, a `size` which is the maximum number of bytes, and `packages` a list of path to manifest files.",
"option": "budgets",
"shorthand": "",
"value_type": "string"
},
{
"description": "path to a `blobs.json` file. It provides the size of each blob composing the package on device.",
"option": "blob-sizes",
N/A
N/A
N/A
{
"command": "ffx assembly size-check package",
"options": [
{
"description": "path to a JSON file containing the list of size budgets. Each size budget has a `name`, a `size` which is the maximum number of bytes, and `packages` a list of path to manifest files.",
"option": "budgets",
"shorthand": "",
"value_type": "string"
},
{
"description": "path to a `blobs.json` file. It provides the size of each blob composing the package on device.",
"option": "blob-sizes",
N/A
N/A
N/A
{
"command": "ffx assembly size-check product",
"options": [
{
"description": "use specific auth mode for oauth2 (see examples; default: pkce).",
"option": "auth",
"shorthand": "",
"value_type": "string"
},
{
"description": "path to the images.json.",
"option": "assembly-manifest",
#[test]
fn extract_blob_contents_test() -> Result<()> {
let blobfs_contents = BlobfsContents {
packages: PackagesMetadata {
base: PackageSetMetadata {
metadata: vec![PackageMetadata {
name: "hello".to_string(),
manifest: "path".into(),
blobs: Default::default(),
abi_revision: Some(version_history::AbiRevision::from_u64(1234)),
}],
},
cache: PackageSetMetadata { metadata: vec![] },
},
maximum_contents_size: Some(1234),
};
let mut assembled_system = AssembledSystem {
images: vec![Image::VBMeta("a/b/c".into()), Image::FVM("x/y/z".into())],
board_name: "my_board".into(),
partitions_config: None,
system_release_info: SystemReleaseInfo::new_for_testing(),
platform_tools: vec![],
};
assert_eq!(extract_blob_contents(&assembled_system), None);
assembled_system
.images
.push(Image::BlobFS { path: "path/to/blob.blk".into(), contents: blobfs_contents });
let blobfs_contents =
extract_blob_contents(&assembled_system).expect("blobfs contents is found");
#[test]
fn gerrit_report_test() {
let gerrit_report = create_gerrit_report(
&SizeResult { consumed_bytes: 151, consumed_bytes_resources: 30 },
200,
20,
50,
);
assert_eq!(
gerrit_report,
json!({
TOTAL_BLOBFS_GERRIT_COMPONENT_NAME: 121,
format!("{TOTAL_BLOBFS_GERRIT_COMPONENT_NAME}.budget"): 150,
format!("{TOTAL_BLOBFS_GERRIT_COMPONENT_NAME}.creepBudget"): 20,
TOTAL_RESOURCES_GERRIT_COMPONENT_NAME: 30,
format!("{TOTAL_RESOURCES_GERRIT_COMPONENT_NAME}.budget"): 50,
format!("{TOTAL_RESOURCES_GERRIT_COMPONENT_NAME}.creepBudget"): 2097152,
})
)
}
N/A
N/A
{
"command": "ffx assembly size-check product",
"options": [
{
"description": "use specific auth mode for oauth2 (see examples; default: pkce).",
"option": "auth",
"shorthand": "",
"value_type": "string"
},
{
"description": "path to the images.json.",
"option": "assembly-manifest",
N/A
N/A
N/A
{
"command": "ffx assembly size-check product",
"options": [
{
"description": "use specific auth mode for oauth2 (see examples; default: pkce).",
"option": "auth",
"shorthand": "",
"value_type": "string"
},
{
"description": "path to the images.json.",
"option": "assembly-manifest",
N/A
N/A
N/A
{
"command": "ffx assembly size-check product",
"options": [
{
"description": "use specific auth mode for oauth2 (see examples; default: pkce).",
"option": "auth",
"shorthand": "",
"value_type": "string"
},
{
"description": "path to the images.json.",
"option": "assembly-manifest",
N/A
N/A
N/A
{
"command": "ffx assembly size-check product",
"options": [
{
"description": "use specific auth mode for oauth2 (see examples; default: pkce).",
"option": "auth",
"shorthand": "",
"value_type": "string"
},
{
"description": "path to the images.json.",
"option": "assembly-manifest",
N/A
N/A
N/A
{
"command": "ffx assembly size-check product",
"options": [
{
"description": "use specific auth mode for oauth2 (see examples; default: pkce).",
"option": "auth",
"shorthand": "",
"value_type": "string"
},
{
"description": "path to the images.json.",
"option": "assembly-manifest",
N/A
N/A
N/A
{
"command": "ffx assembly size-check product",
"options": [
{
"description": "use specific auth mode for oauth2 (see examples; default: pkce).",
"option": "auth",
"shorthand": "",
"value_type": "string"
},
{
"description": "path to the images.json.",
"option": "assembly-manifest",
N/A
N/A
N/A
{
"command": "ffx assembly size-check product",
"options": [
{
"description": "use specific auth mode for oauth2 (see examples; default: pkce).",
"option": "auth",
"shorthand": "",
"value_type": "string"
},
{
"description": "path to the images.json.",
"option": "assembly-manifest",
N/A
N/A
N/A
{
"command": "ffx assembly size-check product",
"options": [
{
"description": "use specific auth mode for oauth2 (see examples; default: pkce).",
"option": "auth",
"shorthand": "",
"value_type": "string"
},
{
"description": "path to the images.json.",
"option": "assembly-manifest",
N/A
N/A
N/A
{
"command": "ffx assembly size-check product",
"options": [
{
"description": "use specific auth mode for oauth2 (see examples; default: pkce).",
"option": "auth",
"shorthand": "",
"value_type": "string"
},
{
"description": "path to the images.json.",
"option": "assembly-manifest",
N/A
N/A
N/A
{
"command": "ffx audio",
"options": [],
"short": "Interact with the audio subsystem."
}
commands and data from `ffx audio` commands to audio devices and `audio_core`.
`ffx audio` commands, except for `gen`, interact with the target through the [fuchsia.audio.controller][fidl-fuchsia-audio-controller] FIDL protocols, served by the `audio_ffx_daemon` component.
`ffx audio` commands, except for `gen`, interact with the target through the [fuchsia.audio.controller][fidl-fuchsia-audio-controller] FIDL protocols, served by the `audio_ffx_daemon` component.
#[test]
fn test_audio_cmd() {
// Test input arguments are generated to according struct.
let render = "background";
let source = "system";
let level = "0.6";
let not_muted = "false";
let args = &["-t", render, "-s", source, "-l", level, "-v", not_muted];
assert_eq!(
Audio::from_args(CMD_NAME, args),
Ok(Audio {
stream: Some(str_to_audio_stream(render).unwrap()),
source: Some(str_to_audio_source(source).unwrap()),
level: Some(0.6),
volume_muted: Some(false),
})
)
}
#[fuchsia::test]
async fn test_run_command() {
let client = fdomain_local::local_client_empty();
let proxy = fake_proxy(client, move |req| match req {
AudioRequest::Set { .. } => {
panic!("Unexpected call to set");
}
AudioRequest::Watch { .. } => {
panic!("Unexpected call to watch");
}
AudioRequest::Set2 { responder, .. } => {
let _ = responder.send(Ok(()));
}
AudioRequest::Watch2 { .. } => {
panic!("Unexpected call to watch2");
}
AudioRequest::_UnknownMethod { .. } => {
panic!("Unexpected call to unknown method");
}
});
let audio = Audio {
stream: Some(AudioRenderUsage2::Background),
source: Some(fdomain_fuchsia_settings::AudioStreamSettingSource::User),
level: Some(0.5),
volume_muted: Some(false),
};
let response = run_command(proxy, audio, &mut vec![]).await;
assert!(response.is_ok());
#[fuchsia::test]
async fn validate_audio_set_output(expected_audio: Audio) -> Result<()> {
let client = fdomain_local::local_client_empty();
let proxy = fake_proxy(client, move |req| match req {
AudioRequest::Set { .. } => {
panic!("Unexpected call to set");
}
AudioRequest::Watch { .. } => {
panic!("Unexpected call to watch");
}
AudioRequest::Set2 { responder, .. } => {
let _ = responder.send(Ok(()));
}
AudioRequest::Watch2 { .. } => {
panic!("Unexpected call to watch2");
}
AudioRequest::_UnknownMethod { .. } => {
panic!("Unexpected call to unknown method");
}
});
let output = utils::assert_set!(command(proxy, expected_audio));
assert_eq!(output, format!("Successfully set Audio to {:?}", expected_audio));
Ok(())
}
N/A
{
"command": "ffx audio device",
"options": [
{
"description": "device devfs node name. e.g. 3d99d780 for the devfs path /dev/class/audio-input/3d99d780.",
"option": "name",
"shorthand": "",
"value_type": "string"
},
{
"description": "device token ID, for a device in the audio device registry. Only applies if the audio device registry is available on the target.",
"option": "token-id",
#[fuchsia::test]
pub async fn test_play_success() -> Result<()> {
let client = fdomain_local::local_client_empty();
let audio_player = ffx_audio_common::tests::fake_audio_player(client.clone());
let test_buffers = TestBuffers::default();
let writer: MachineWriter<DeviceResult> = MachineWriter::new_test(None, &test_buffers);
let selector = Selector::from(fac::Devfs {
name: "abc123".to_string(),
device_type: fac::DeviceType::Output,
});
let ring_buffer_element_id = Some(DEFAULT_RING_BUFFER_ELEMENT_ID);
let ring_buffer_active_channels_bitmask = Some(1);
let (play_remote, play_local) = client.create_datagram_socket();
let async_play_local =
play_local.duplicate_handle(fidl::Rights::SAME_RIGHTS).await.unwrap();
async_play_local.fdomain_write_all(ffx_audio_common::tests::WAV_HEADER_EXT).await.unwrap();
device_play(
audio_player,
selector,
ring_buffer_element_id,
ring_buffer_active_channels_bitmask,
play_local,
play_remote,
#[fuchsia::test]
pub async fn test_play_from_file_success() -> Result<()> {
let client = fdomain_local::local_client_empty();
let audio_player = ffx_audio_common::tests::fake_audio_player(client.clone());
let test_buffers = TestBuffers::default();
let writer: MachineWriter<DeviceResult> = MachineWriter::new_test(None, &test_buffers);
let test_dir = TempDir::new().unwrap();
let test_dir_path = test_dir.path().to_path_buf();
let test_wav_path = test_dir_path.join("sine.wav");
let wav_path = test_wav_path.clone().into_os_string().into_string().unwrap();
// Create valid WAV file.
fs::File::create(&test_wav_path)
.unwrap()
.write_all(ffx_audio_common::tests::SINE_WAV)
.unwrap();
fs::set_permissions(&test_wav_path, fs::Permissions::from_mode(0o770)).unwrap();
let file_reader = std::fs::File::open(&test_wav_path)
.with_bug_context(|| format!("Error trying to open file \"{}\"", wav_path))?;
let (play_remote, play_local) = client.create_datagram_socket();
let selector = Selector::from(fac::Devfs {
name: "abc123".to_string(),
device_type: fac::DeviceType::Output,
});
#[fuchsia::test]
pub async fn test_record_no_cancel() -> Result<()> {
let client = fdomain_local::local_client_empty();
// Test without sending a cancel message. Still set up the canceling proxy and server,
// but never send the message from proxy to daemon to cancel. Test daemon should
// exit after duration (real daemon exits after sending all duration amount of packets).
let controller = ffx_audio_common::tests::fake_audio_recorder(client);
let test_buffers = TestBuffers::default();
let mut result_writer: SimpleWriter = SimpleWriter::new_test(&test_buffers);
let record_command = RecordCommand {
duration: Some(std::time::Duration::from_nanos(500)),
format: Format {
sample_type: SampleType::Uint8,
frames_per_second: 48000,
channels: 1,
},
element_id: Some(DEFAULT_RING_BUFFER_ELEMENT_ID),
};
let selector = Selector::from(fac::Devfs {
name: "abc123".to_string(),
device_type: fac::DeviceType::Input,
});
let (cancel_proxy, cancel_server) =
controller.domain().create_proxy::<fac::RecordCancelerMarker>();
let test_stdout = TestBuffer::default();
N/A
{
"command": "ffx audio device",
"options": [
{
"description": "device devfs node name. e.g. 3d99d780 for the devfs path /dev/class/audio-input/3d99d780.",
"option": "name",
"shorthand": "",
"value_type": "string"
},
{
"description": "device token ID, for a device in the audio device registry. Only applies if the audio device registry is available on the target.",
"option": "token-id",
N/A
```posix-terminal
```posix-terminal
N/A
{
"command": "ffx audio device",
"options": [
{
"description": "device devfs node name. e.g. 3d99d780 for the devfs path /dev/class/audio-input/3d99d780.",
"option": "name",
"shorthand": "",
"value_type": "string"
},
{
"description": "device token ID, for a device in the audio device registry. Only applies if the audio device registry is available on the target.",
"option": "token-id",
N/A
N/A
{
"command": "ffx audio device",
"options": [
{
"description": "device devfs node name. e.g. 3d99d780 for the devfs path /dev/class/audio-input/3d99d780.",
"option": "name",
"shorthand": "",
"value_type": "string"
},
{
"description": "device token ID, for a device in the audio device registry. Only applies if the audio device registry is available on the target.",
"option": "token-id",
N/A
```posix-terminal
N/A
{
"command": "ffx audio device",
"options": [
{
"description": "device devfs node name. e.g. 3d99d780 for the devfs path /dev/class/audio-input/3d99d780.",
"option": "name",
"shorthand": "",
"value_type": "string"
},
{
"description": "device token ID, for a device in the audio device registry. Only applies if the audio device registry is available on the target.",
"option": "token-id",
N/A
```posix-terminal
```posix-terminal
N/A
{
"command": "ffx audio device agc",
"options": [],
"short": "Request to enable or disable automatic gain control for the stream."
}
N/A
N/A
N/A
{
"command": "ffx audio device gain",
"options": [
{
"description": "gain, in decibels, to set the stream to.",
"option": "gain",
"shorthand": "",
"value_type": "string"
}
],
"short": "Request to set the gain of the stream, in decibels."
}
N/A
N/A
N/A
{
"command": "ffx audio device gain",
"options": [
{
"description": "gain, in decibels, to set the stream to.",
"option": "gain",
"shorthand": "",
"value_type": "string"
}
],
"short": "Request to set the gain of the stream, in decibels."
}
N/A
N/A
N/A
{
"command": "ffx audio device info",
"options": [],
"short": "Show information about a specific audio device."
}
#[test]
fn test_info_result_table() {
let output = TEST_INFO_RESULT.to_string();
let expected = r#"
Name: 0c8301e0
Token ID: 68
Path: /dev/class/audio-input/0c8301e0
Unique ID: 000102030405060708090a0b0c0d0e0f
Manufacturer: Test manufacturer
Product: Test product
Current gain: -3 dB (unmuted, AGC off)
Gain capabilities: Gain range: [-100 dB, 0 dB]
Gain step: 0 dB step (continuous)
Mute: ✅ Can Mute
AGC: ❌ Cannot AGC
Plug state: Plugged at 123456789
Plug detection: Hardwired
Clock domain: 0 (monotonic)
Signal processing topology: 1
DAI formats:
• Element 1 has 1 DAI format set:
┌───────────────────────────────────────────────────────────────────────────────────────────┐
│ Number of channels: 1, 2 │
│ Sample formats: pcm_signed, pcm_unsigned │
│ Frame formats: stereo_left │
│ stereo_right │
│ Frame rates: 16000 Hz, 22050 Hz, 32000 Hz, 44100 Hz, 48000 Hz, 88200 Hz, 96000 Hz │
#[test]
pub fn test_info_result_json() {
let output = serde_json::to_value(&*TEST_INFO_RESULT).unwrap();
let expected = json!({
"device_name": "0c8301e0",
"token_id": 68,
"device_path": "/dev/class/audio-input/0c8301e0",
"unique_id": "000102030405060708090a0b0c0d0e0f",
"manufacturer": "Test manufacturer",
"product_name": "Test product",
"gain_state": {
"gain_db": -3.0,
"muted": false,
"agc_enabled": false
},
"gain_capabilities": {
"min_gain_db": -100.0,
"max_gain_db": 0.0,
"gain_step_db": 0.0,
"can_mute": true,
"can_agc": false
},
"plug_event": {
"state": "Plugged",
"time": 123456789,
},
"plug_detect_capabilities": "Hardwired",
"clock_domain": 0,
N/A
N/A
{
"command": "ffx audio device list",
"options": [],
"short": "Lists audio devices."
}
N/A
```posix-terminal
```posix-terminal
N/A
{
"command": "ffx audio device mute",
"options": [],
"short": "Request to mute a stream."
}
N/A
N/A
N/A
{
"command": "ffx audio device play",
"options": [
{
"description": "file in WAV format containing audio signal. If not specified, ffx command will read from stdin.",
"option": "file",
"shorthand": "",
"value_type": "string"
},
{
"description": "signal processing element ID, for an Endpoint element of type RingBuffer",
"option": "element-id",
N/A
```posix-terminal
```posix-terminal
N/A
{
"command": "ffx audio device play",
"options": [
{
"description": "file in WAV format containing audio signal. If not specified, ffx command will read from stdin.",
"option": "file",
"shorthand": "",
"value_type": "string"
},
{
"description": "signal processing element ID, for an Endpoint element of type RingBuffer",
"option": "element-id",
N/A
N/A
N/A
{
"command": "ffx audio device play",
"options": [
{
"description": "file in WAV format containing audio signal. If not specified, ffx command will read from stdin.",
"option": "file",
"shorthand": "",
"value_type": "string"
},
{
"description": "signal processing element ID, for an Endpoint element of type RingBuffer",
"option": "element-id",
N/A
N/A
N/A
{
"command": "ffx audio device play",
"options": [
{
"description": "file in WAV format containing audio signal. If not specified, ffx command will read from stdin.",
"option": "file",
"shorthand": "",
"value_type": "string"
},
{
"description": "signal processing element ID, for an Endpoint element of type RingBuffer",
"option": "element-id",
N/A
N/A
N/A
{
"command": "ffx audio device record",
"options": [
{
"description": "duration of output signal. Examples: 5ms or 3s. If not specified, press ENTER to stop recording.",
"option": "duration",
"shorthand": "",
"value_type": "string"
},
{
"description": "output format (see 'ffx audio help' for more information).",
"option": "format",
N/A
N/A
N/A
{
"command": "ffx audio device record",
"options": [
{
"description": "duration of output signal. Examples: 5ms or 3s. If not specified, press ENTER to stop recording.",
"option": "duration",
"shorthand": "",
"value_type": "string"
},
{
"description": "output format (see 'ffx audio help' for more information).",
"option": "format",
N/A
N/A
N/A
{
"command": "ffx audio device record",
"options": [
{
"description": "duration of output signal. Examples: 5ms or 3s. If not specified, press ENTER to stop recording.",
"option": "duration",
"shorthand": "",
"value_type": "string"
},
{
"description": "output format (see 'ffx audio help' for more information).",
"option": "format",
N/A
N/A
N/A
{
"command": "ffx audio device record",
"options": [
{
"description": "duration of output signal. Examples: 5ms or 3s. If not specified, press ENTER to stop recording.",
"option": "duration",
"shorthand": "",
"value_type": "string"
},
{
"description": "output format (see 'ffx audio help' for more information).",
"option": "format",
N/A
N/A
N/A
{
"command": "ffx audio device reset",
"options": [],
"short": "Reset device hardware."
}
N/A
N/A
N/A
{
"command": "ffx audio device set",
"options": [],
"short": "Set a device property."
}
N/A
```posix-terminal
N/A
{
"command": "ffx audio device set dai-format",
"options": [
{
"description": "signal processing element ID, for an Endpoint element of type Dai",
"option": "element-id",
"shorthand": "",
"value_type": "string"
}
],
"short": "Set the DAI format of device or signal processing element."
}
N/A
N/A
N/A
{
"command": "ffx audio device set dai-format",
"options": [
{
"description": "signal processing element ID, for an Endpoint element of type Dai",
"option": "element-id",
"shorthand": "",
"value_type": "string"
}
],
"short": "Set the DAI format of device or signal processing element."
}
N/A
N/A
N/A
{
"command": "ffx audio device start",
"options": [],
"short": "Start device hardware."
}
N/A
N/A
N/A
{
"command": "ffx audio device stop",
"options": [],
"short": "Stop device hardware."
}
N/A
N/A
N/A
{
"command": "ffx audio device unmute",
"options": [],
"short": "Request to unmute a stream."
}
N/A
N/A
N/A
{
"command": "ffx audio gen",
"options": [],
"short": "Generate an audio signal. Outputs a WAV file written to stdout."
}
#[test]
fn test_silence() {
let mut cursor_writer = io::Cursor::new(Vec::<u8>::new());
write_signal(example_signals().sine_int16_min_amp, &mut cursor_writer).unwrap();
cursor_writer.set_position(0);
let mut reader = WavReader::new(cursor_writer).unwrap();
reader.samples::<i16>().for_each(|s| assert_eq!(0.0, s.unwrap() as f64));
}
#[test]
fn test_u8_sine_wave_max_amp() {
let mut cursor_writer = io::Cursor::new(Vec::<u8>::new());
let signal = example_signals().sine_u8_max_amp;
let frames_per_period = signal.format.frames_per_second as u64 / signal.frequency.unwrap();
write_signal(signal, &mut cursor_writer).unwrap();
cursor_writer.set_position(0);
let mut reader = WavReader::new(cursor_writer).unwrap();
reader.samples::<i8>().for_each(|s| {
let r = s.unwrap();
println!("{}", r);
});
reader.seek(0).unwrap();
// Silence every half period, starting from beginning
reader.samples::<i8>().step_by((frames_per_period / 2) as usize).for_each(|s| {
let r = s.unwrap();
assert_eq!(0, r);
});
reader.seek(0).unwrap();
// Peaks
reader
.samples::<i8>()
#[test]
fn test_u8_sine_wave_mid_amp() {
let mut cursor_writer = io::Cursor::new(Vec::<u8>::new());
let signal = example_signals().sine_u8_mid_amp;
let frames_per_period = signal.format.frames_per_second as u64 / signal.frequency.unwrap();
write_signal(signal, &mut cursor_writer).unwrap();
cursor_writer.set_position(0);
let mut reader = WavReader::new(cursor_writer).unwrap();
reader.samples::<i8>().for_each(|s| {
let r = s.unwrap();
println!("{}", r);
});
reader.seek(0).unwrap();
// Silence every half period, starting from beginning
reader.samples::<i8>().step_by((frames_per_period / 2) as usize).for_each(|s| {
let r = s.unwrap();
assert_eq!(0, r);
});
reader.seek(0).unwrap();
// Peaks
reader
.samples::<i8>()
N/A
{
"command": "ffx audio gen pink-noise",
"options": [
{
"description": "duration of output signal. Examples: 5ms or 3s.",
"option": "duration",
"shorthand": "",
"value_type": "string"
},
{
"description": "signal amplitude in range [0, 1.0]. Default: 1.0.",
"option": "amplitude",
N/A
N/A
N/A
{
"command": "ffx audio gen pink-noise",
"options": [
{
"description": "duration of output signal. Examples: 5ms or 3s.",
"option": "duration",
"shorthand": "",
"value_type": "string"
},
{
"description": "signal amplitude in range [0, 1.0]. Default: 1.0.",
"option": "amplitude",
N/A
N/A
N/A
{
"command": "ffx audio gen pink-noise",
"options": [
{
"description": "duration of output signal. Examples: 5ms or 3s.",
"option": "duration",
"shorthand": "",
"value_type": "string"
},
{
"description": "signal amplitude in range [0, 1.0]. Default: 1.0.",
"option": "amplitude",
N/A
N/A
N/A
{
"command": "ffx audio gen pink-noise",
"options": [
{
"description": "duration of output signal. Examples: 5ms or 3s.",
"option": "duration",
"shorthand": "",
"value_type": "string"
},
{
"description": "signal amplitude in range [0, 1.0]. Default: 1.0.",
"option": "amplitude",
N/A
N/A
N/A
{
"command": "ffx audio gen sawtooth",
"options": [
{
"description": "duration of output signal. Examples: 5ms or 3s.",
"option": "duration",
"shorthand": "",
"value_type": "string"
},
{
"description": "frequency of output wave in Hz.",
"option": "frequency",
N/A
N/A
N/A
{
"command": "ffx audio gen sawtooth",
"options": [
{
"description": "duration of output signal. Examples: 5ms or 3s.",
"option": "duration",
"shorthand": "",
"value_type": "string"
},
{
"description": "frequency of output wave in Hz.",
"option": "frequency",
N/A
N/A
N/A
{
"command": "ffx audio gen sawtooth",
"options": [
{
"description": "duration of output signal. Examples: 5ms or 3s.",
"option": "duration",
"shorthand": "",
"value_type": "string"
},
{
"description": "frequency of output wave in Hz.",
"option": "frequency",
N/A
N/A
N/A
{
"command": "ffx audio gen sawtooth",
"options": [
{
"description": "duration of output signal. Examples: 5ms or 3s.",
"option": "duration",
"shorthand": "",
"value_type": "string"
},
{
"description": "frequency of output wave in Hz.",
"option": "frequency",
N/A
N/A
N/A
{
"command": "ffx audio gen sawtooth",
"options": [
{
"description": "duration of output signal. Examples: 5ms or 3s.",
"option": "duration",
"shorthand": "",
"value_type": "string"
},
{
"description": "frequency of output wave in Hz.",
"option": "frequency",
N/A
N/A
N/A
{
"command": "ffx audio gen sine",
"options": [
{
"description": "duration of output signal. Examples: 5ms or 3s.",
"option": "duration",
"shorthand": "",
"value_type": "string"
},
{
"description": "frequency of output wave in Hz.",
"option": "frequency",
N/A
```posix-terminal
```posix-terminal
```posix-terminal
N/A
{
"command": "ffx audio gen sine",
"options": [
{
"description": "duration of output signal. Examples: 5ms or 3s.",
"option": "duration",
"shorthand": "",
"value_type": "string"
},
{
"description": "frequency of output wave in Hz.",
"option": "frequency",
N/A
```posix-terminal
```posix-terminal
N/A
{
"command": "ffx audio gen sine",
"options": [
{
"description": "duration of output signal. Examples: 5ms or 3s.",
"option": "duration",
"shorthand": "",
"value_type": "string"
},
{
"description": "frequency of output wave in Hz.",
"option": "frequency",
N/A
```posix-terminal
```posix-terminal
```posix-terminal
N/A
{
"command": "ffx audio gen sine",
"options": [
{
"description": "duration of output signal. Examples: 5ms or 3s.",
"option": "duration",
"shorthand": "",
"value_type": "string"
},
{
"description": "frequency of output wave in Hz.",
"option": "frequency",
N/A
```posix-terminal
```posix-terminal
```posix-terminal
N/A
{
"command": "ffx audio gen sine",
"options": [
{
"description": "duration of output signal. Examples: 5ms or 3s.",
"option": "duration",
"shorthand": "",
"value_type": "string"
},
{
"description": "frequency of output wave in Hz.",
"option": "frequency",
N/A
```posix-terminal
```posix-terminal
```posix-terminal
N/A
{
"command": "ffx audio gen square",
"options": [
{
"description": "duration of output signal. Examples: 5ms or 3s.",
"option": "duration",
"shorthand": "",
"value_type": "string"
},
{
"description": "frequency of output wave in Hz.",
"option": "frequency",
N/A
N/A
N/A
{
"command": "ffx audio gen square",
"options": [
{
"description": "duration of output signal. Examples: 5ms or 3s.",
"option": "duration",
"shorthand": "",
"value_type": "string"
},
{
"description": "frequency of output wave in Hz.",
"option": "frequency",
N/A
N/A
N/A
{
"command": "ffx audio gen square",
"options": [
{
"description": "duration of output signal. Examples: 5ms or 3s.",
"option": "duration",
"shorthand": "",
"value_type": "string"
},
{
"description": "frequency of output wave in Hz.",
"option": "frequency",
N/A
N/A
N/A
{
"command": "ffx audio gen square",
"options": [
{
"description": "duration of output signal. Examples: 5ms or 3s.",
"option": "duration",
"shorthand": "",
"value_type": "string"
},
{
"description": "frequency of output wave in Hz.",
"option": "frequency",
N/A
N/A
N/A
{
"command": "ffx audio gen square",
"options": [
{
"description": "duration of output signal. Examples: 5ms or 3s.",
"option": "duration",
"shorthand": "",
"value_type": "string"
},
{
"description": "frequency of output wave in Hz.",
"option": "frequency",
N/A
N/A
N/A
{
"command": "ffx audio gen square",
"options": [
{
"description": "duration of output signal. Examples: 5ms or 3s.",
"option": "duration",
"shorthand": "",
"value_type": "string"
},
{
"description": "frequency of output wave in Hz.",
"option": "frequency",
N/A
N/A
N/A
{
"command": "ffx audio gen triangle",
"options": [
{
"description": "duration of output signal. Examples: 5ms or 3s.",
"option": "duration",
"shorthand": "",
"value_type": "string"
},
{
"description": "frequency of output wave in Hz.",
"option": "frequency",
N/A
N/A
N/A
{
"command": "ffx audio gen triangle",
"options": [
{
"description": "duration of output signal. Examples: 5ms or 3s.",
"option": "duration",
"shorthand": "",
"value_type": "string"
},
{
"description": "frequency of output wave in Hz.",
"option": "frequency",
N/A
N/A
N/A
{
"command": "ffx audio gen triangle",
"options": [
{
"description": "duration of output signal. Examples: 5ms or 3s.",
"option": "duration",
"shorthand": "",
"value_type": "string"
},
{
"description": "frequency of output wave in Hz.",
"option": "frequency",
N/A
N/A
N/A
{
"command": "ffx audio gen triangle",
"options": [
{
"description": "duration of output signal. Examples: 5ms or 3s.",
"option": "duration",
"shorthand": "",
"value_type": "string"
},
{
"description": "frequency of output wave in Hz.",
"option": "frequency",
N/A
N/A
N/A
{
"command": "ffx audio gen triangle",
"options": [
{
"description": "duration of output signal. Examples: 5ms or 3s.",
"option": "duration",
"shorthand": "",
"value_type": "string"
},
{
"description": "frequency of output wave in Hz.",
"option": "frequency",
N/A
N/A
N/A
{
"command": "ffx audio gen white-noise",
"options": [
{
"description": "duration of output signal. Examples: 5ms or 3s.",
"option": "duration",
"shorthand": "",
"value_type": "string"
},
{
"description": "signal amplitude in range [0, 1.0]. Default: 1.0.",
"option": "amplitude",
N/A
N/A
N/A
{
"command": "ffx audio gen white-noise",
"options": [
{
"description": "duration of output signal. Examples: 5ms or 3s.",
"option": "duration",
"shorthand": "",
"value_type": "string"
},
{
"description": "signal amplitude in range [0, 1.0]. Default: 1.0.",
"option": "amplitude",
N/A
N/A
N/A
{
"command": "ffx audio gen white-noise",
"options": [
{
"description": "duration of output signal. Examples: 5ms or 3s.",
"option": "duration",
"shorthand": "",
"value_type": "string"
},
{
"description": "signal amplitude in range [0, 1.0]. Default: 1.0.",
"option": "amplitude",
N/A
N/A
N/A
{
"command": "ffx audio gen white-noise",
"options": [
{
"description": "duration of output signal. Examples: 5ms or 3s.",
"option": "duration",
"shorthand": "",
"value_type": "string"
},
{
"description": "signal amplitude in range [0, 1.0]. Default: 1.0.",
"option": "amplitude",
N/A
N/A
N/A
{
"command": "ffx audio list-devices",
"options": [],
"short": "Prints all available audio devices on target"
}
N/A
```posix-terminal
N/A
{
"command": "ffx audio play",
"options": [
{
"description": "purpose of the audio being played. Accepted values: ACCESSIBILITY (and A11Y), BACKGROUND, COMMUNICATION, INTERRUPTION, MEDIA, SYSTEM-AGENT, ULTRASOUND. Default: MEDIA.",
"option": "usage",
"shorthand": "",
"value_type": "string"
},
{
"description": "buffer size (bytes) to allocate on device VMO. Used to send audio data from ffx tool to AudioRenderer. Defaults to size that holds 1 second of audio data.",
"option": "buffer-size",
#[test]
fn test_str_to_usage() {
// We test a variety of upper- and lower-case inputs.
assert_eq!(
str_to_usage("ACCESSIBILITY").unwrap(),
AudioRenderUsageExtended::Accessibility(fmedia::AudioRenderUsage2::Accessibility)
);
assert_eq!(
str_to_usage("A11y").unwrap(),
AudioRenderUsageExtended::Accessibility(fmedia::AudioRenderUsage2::Accessibility)
);
assert_eq!(
str_to_usage("background").unwrap(),
AudioRenderUsageExtended::Background(fmedia::AudioRenderUsage2::Background)
);
assert_eq!(
str_to_usage("COMMUNICATION").unwrap(),
AudioRenderUsageExtended::Communication(fmedia::AudioRenderUsage2::Communication)
);
assert_eq!(
str_to_usage("Media").unwrap(),
AudioRenderUsageExtended::Media(fmedia::AudioRenderUsage2::Media)
);
assert_eq!(
str_to_usage("system-agent").unwrap(),
AudioRenderUsageExtended::SystemAgent(fmedia::AudioRenderUsage2::SystemAgent)
);
assert_eq!(str_to_usage("UltraSound").unwrap(), AudioRenderUsageExtended::Ultrasound);
assert!(str_to_usage("invalid").is_err());
#[test]
fn test_str_to_clock() {
assert_eq!(str_to_clock("flexible").unwrap(), fac::ClockType::Flexible(fac::Flexible));
assert_eq!(
str_to_clock("monotonic").unwrap(),
fac::ClockType::SystemMonotonic(fac::SystemMonotonic)
);
assert_eq!(
str_to_clock("custom,123,456").unwrap(),
fac::ClockType::Custom(fac::CustomClockConfig {
rate_adjust: Some(123),
offset: Some(456),
..Default::default()
})
);
assert_eq!(
str_to_clock("custom,789").unwrap(),
fac::ClockType::Custom(fac::CustomClockConfig {
rate_adjust: Some(789),
offset: None,
..Default::default()
})
);
assert_eq!(
str_to_clock("custom,,321").unwrap(),
fac::ClockType::Custom(fac::CustomClockConfig {
rate_adjust: None,
#[fuchsia::test]
pub async fn test_play() -> Result<(), fho::Error> {
let client = fdomain_local::local_client_empty();
let controller = ffx_audio_common::tests::fake_audio_player(client.clone());
let test_buffers = TestBuffers::default();
let writer: MachineWriter<PlayResult> = MachineWriter::new_test(None, &test_buffers);
let stdin_command = PlayCommand {
usage: AudioRenderUsageExtended::Media(fmedia::AudioRenderUsage2::Media),
buffer_size: Some(48000),
packet_count: None,
file: None,
gain: 0.0,
mute: false,
clock: fac::ClockType::Flexible(fac::Flexible),
};
let (play_remote, play_local) = client.create_datagram_socket();
play_local.fdomain_write_all(ffx_audio_common::tests::WAV_HEADER_EXT).await.unwrap();
let result = play_impl(
controller.clone(),
play_local,
play_remote,
stdin_command,
Box::new(&ffx_audio_common::tests::WAV_HEADER_EXT[..]),
writer,
)
.await;
```posix-terminal
```posix-terminal
```posix-terminal
N/A
{
"command": "ffx audio play",
"options": [
{
"description": "purpose of the audio being played. Accepted values: ACCESSIBILITY (and A11Y), BACKGROUND, COMMUNICATION, INTERRUPTION, MEDIA, SYSTEM-AGENT, ULTRASOUND. Default: MEDIA.",
"option": "usage",
"shorthand": "",
"value_type": "string"
},
{
"description": "buffer size (bytes) to allocate on device VMO. Used to send audio data from ffx tool to AudioRenderer. Defaults to size that holds 1 second of audio data.",
"option": "buffer-size",
N/A
N/A
N/A
{
"command": "ffx audio play",
"options": [
{
"description": "purpose of the audio being played. Accepted values: ACCESSIBILITY (and A11Y), BACKGROUND, COMMUNICATION, INTERRUPTION, MEDIA, SYSTEM-AGENT, ULTRASOUND. Default: MEDIA.",
"option": "usage",
"shorthand": "",
"value_type": "string"
},
{
"description": "buffer size (bytes) to allocate on device VMO. Used to send audio data from ffx tool to AudioRenderer. Defaults to size that holds 1 second of audio data.",
"option": "buffer-size",
N/A
N/A
N/A
{
"command": "ffx audio play",
"options": [
{
"description": "purpose of the audio being played. Accepted values: ACCESSIBILITY (and A11Y), BACKGROUND, COMMUNICATION, INTERRUPTION, MEDIA, SYSTEM-AGENT, ULTRASOUND. Default: MEDIA.",
"option": "usage",
"shorthand": "",
"value_type": "string"
},
{
"description": "buffer size (bytes) to allocate on device VMO. Used to send audio data from ffx tool to AudioRenderer. Defaults to size that holds 1 second of audio data.",
"option": "buffer-size",
N/A
```posix-terminal
```posix-terminal
N/A
{
"command": "ffx audio play",
"options": [
{
"description": "purpose of the audio being played. Accepted values: ACCESSIBILITY (and A11Y), BACKGROUND, COMMUNICATION, INTERRUPTION, MEDIA, SYSTEM-AGENT, ULTRASOUND. Default: MEDIA.",
"option": "usage",
"shorthand": "",
"value_type": "string"
},
{
"description": "buffer size (bytes) to allocate on device VMO. Used to send audio data from ffx tool to AudioRenderer. Defaults to size that holds 1 second of audio data.",
"option": "buffer-size",
N/A
N/A
N/A
{
"command": "ffx audio play",
"options": [
{
"description": "purpose of the audio being played. Accepted values: ACCESSIBILITY (and A11Y), BACKGROUND, COMMUNICATION, INTERRUPTION, MEDIA, SYSTEM-AGENT, ULTRASOUND. Default: MEDIA.",
"option": "usage",
"shorthand": "",
"value_type": "string"
},
{
"description": "buffer size (bytes) to allocate on device VMO. Used to send audio data from ffx tool to AudioRenderer. Defaults to size that holds 1 second of audio data.",
"option": "buffer-size",
N/A
N/A
N/A
{
"command": "ffx audio play",
"options": [
{
"description": "purpose of the audio being played. Accepted values: ACCESSIBILITY (and A11Y), BACKGROUND, COMMUNICATION, INTERRUPTION, MEDIA, SYSTEM-AGENT, ULTRASOUND. Default: MEDIA.",
"option": "usage",
"shorthand": "",
"value_type": "string"
},
{
"description": "buffer size (bytes) to allocate on device VMO. Used to send audio data from ffx tool to AudioRenderer. Defaults to size that holds 1 second of audio data.",
"option": "buffer-size",
N/A
N/A
N/A
{
"command": "ffx audio play",
"options": [
{
"description": "purpose of the audio being played. Accepted values: ACCESSIBILITY (and A11Y), BACKGROUND, COMMUNICATION, INTERRUPTION, MEDIA, SYSTEM-AGENT, ULTRASOUND. Default: MEDIA.",
"option": "usage",
"shorthand": "",
"value_type": "string"
},
{
"description": "buffer size (bytes) to allocate on device VMO. Used to send audio data from ffx tool to AudioRenderer. Defaults to size that holds 1 second of audio data.",
"option": "buffer-size",
N/A
```posix-terminal
N/A
{
"command": "ffx audio record",
"options": [
{
"description": "duration of output signal. Examples: 5ms or 3s. If not specified, press ENTER to stop recording.",
"option": "duration",
"shorthand": "",
"value_type": "string"
},
{
"description": "output format (see 'ffx audio help' for more information).",
"option": "format",
#[test]
fn test_str_to_usage() {
assert_eq!(
str_to_usage("BACKGROUND").unwrap(),
AudioCaptureUsageExtended::Background(fmedia::AudioCaptureUsage2::Background)
);
assert_eq!(
str_to_usage("foreground").unwrap(),
AudioCaptureUsageExtended::Foreground(fmedia::AudioCaptureUsage2::Foreground)
);
assert_eq!(
str_to_usage("SYSTEM-AGENT").unwrap(),
AudioCaptureUsageExtended::SystemAgent(fmedia::AudioCaptureUsage2::SystemAgent)
);
assert_eq!(
str_to_usage("communication").unwrap(),
AudioCaptureUsageExtended::Communication(fmedia::AudioCaptureUsage2::Communication)
);
assert_eq!(str_to_usage("ULTRASOUND").unwrap(), AudioCaptureUsageExtended::Ultrasound);
assert_eq!(str_to_usage("loopback").unwrap(), AudioCaptureUsageExtended::Loopback);
assert!(str_to_usage("invalid").is_err());
}
#[fuchsia::test]
pub async fn test_record_no_cancel() -> Result<(), fho::Error> {
// Test without sending a cancel message. Still set up the canceling proxy and server,
// but never send the message from proxy to daemon to cancel. Test daemon should
// exit after duration (real daemon exits after sending all duration amount of packets).
let client = fdomain_local::local_client_empty();
let controller = ffx_audio_common::tests::fake_audio_recorder(client.clone());
let test_buffers = TestBuffers::default();
let result_writer: SimpleWriter = SimpleWriter::new_test(&test_buffers);
let (cancel_proxy, cancel_server) = client.create_proxy::<fac::RecordCancelerMarker>();
let test_stdout = TestBuffer::default();
let (record_remote, record_local) = client.create_datagram_socket();
let request = fac::RecorderRecordRequest {
source: None,
stream_type: None,
duration: Some(500),
canceler: Some(cancel_server),
gain_settings: None,
buffer_size: None,
wav_data: Some(record_remote),
..Default::default()
};
// Pass a future that will never complete as an input waiter.
let keypress_waiter =
ffx_audio_common::cancel_on_keypress(cancel_proxy, futures::future::pending().fuse());
#[fuchsia::test]
pub async fn test_record_immediate_cancel() -> Result<(), fho::Error> {
let client = fdomain_local::local_client_empty();
let controller = ffx_audio_common::tests::fake_audio_recorder(client.clone());
let test_buffers = TestBuffers::default();
let result_writer: SimpleWriter = SimpleWriter::new_test(&test_buffers);
let (cancel_proxy, cancel_server) = client.create_proxy::<fac::RecordCancelerMarker>();
let test_stdout = TestBuffer::default();
let (record_remote, record_local) = client.create_datagram_socket();
let request = fac::RecorderRecordRequest {
source: None,
stream_type: None,
duration: None,
canceler: Some(cancel_server),
gain_settings: None,
buffer_size: None,
wav_data: Some(record_remote),
..Default::default()
};
// Test canceler signaling. Not concerned with how much data gets back through socket.
// Test failing is never finishing execution before timeout.
let keypress_waiter =
ffx_audio_common::cancel_on_keypress(cancel_proxy, futures::future::ready(Ok(())));
let _res = record_impl(
```posix-terminal
```posix-terminal
```posix-terminal
N/A
{
"command": "ffx audio record",
"options": [
{
"description": "duration of output signal. Examples: 5ms or 3s. If not specified, press ENTER to stop recording.",
"option": "duration",
"shorthand": "",
"value_type": "string"
},
{
"description": "output format (see 'ffx audio help' for more information).",
"option": "format",
N/A
N/A
N/A
{
"command": "ffx audio record",
"options": [
{
"description": "duration of output signal. Examples: 5ms or 3s. If not specified, press ENTER to stop recording.",
"option": "duration",
"shorthand": "",
"value_type": "string"
},
{
"description": "output format (see 'ffx audio help' for more information).",
"option": "format",
N/A
N/A
N/A
{
"command": "ffx audio record",
"options": [
{
"description": "duration of output signal. Examples: 5ms or 3s. If not specified, press ENTER to stop recording.",
"option": "duration",
"shorthand": "",
"value_type": "string"
},
{
"description": "output format (see 'ffx audio help' for more information).",
"option": "format",
N/A
```posix-terminal
```posix-terminal
N/A
{
"command": "ffx audio record",
"options": [
{
"description": "duration of output signal. Examples: 5ms or 3s. If not specified, press ENTER to stop recording.",
"option": "duration",
"shorthand": "",
"value_type": "string"
},
{
"description": "output format (see 'ffx audio help' for more information).",
"option": "format",
N/A
```posix-terminal
```posix-terminal
N/A
{
"command": "ffx audio record",
"options": [
{
"description": "duration of output signal. Examples: 5ms or 3s. If not specified, press ENTER to stop recording.",
"option": "duration",
"shorthand": "",
"value_type": "string"
},
{
"description": "output format (see 'ffx audio help' for more information).",
"option": "format",
N/A
N/A
N/A
{
"command": "ffx audio record",
"options": [
{
"description": "duration of output signal. Examples: 5ms or 3s. If not specified, press ENTER to stop recording.",
"option": "duration",
"shorthand": "",
"value_type": "string"
},
{
"description": "output format (see 'ffx audio help' for more information).",
"option": "format",
N/A
N/A
N/A
{
"command": "ffx audio record",
"options": [
{
"description": "duration of output signal. Examples: 5ms or 3s. If not specified, press ENTER to stop recording.",
"option": "duration",
"shorthand": "",
"value_type": "string"
},
{
"description": "output format (see 'ffx audio help' for more information).",
"option": "format",
N/A
```posix-terminal
```posix-terminal
N/A
{
"command": "ffx completion",
"options": [],
"short": "Generate shell completions for ffx"
}
N/A
```posix-terminal
N/A
{
"command": "ffx component",
"options": [],
"short": "Discover and manage components"
}
// Copyright 2023 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use ffx_e2e_emu::IsolatedEmulator;
use log::info;
#[fuchsia::test(logging = true)]
async fn override_echo_greeting_and_observe_in_logs() {
let emu = IsolatedEmulator::start("test-ffx-create-parent-overrides").await.unwrap();
let moniker = "/core/ffx-laboratory:create-parent-override-echo";
let url = "fuchsia-pkg://fuchsia.com/ffx_create_parent_overrides_echo#meta/echo_config.cm";
let expected_greeting = "Hello from ffx parent overrides!";
info!("running test component with a config override...");
emu.ffx(&[
"component",
"create",
moniker,
url,
"--config",
&format!("greeting=\"{expected_greeting}\""),
])
.await
.unwrap();
emu.ffx(&["component", "start", moniker]).await.unwrap();
info!("checking for expected log message...");
'log_search: loop {
#[fuchsia::test(logging = true)]
async fn override_echo_greeting_and_observe_in_logs() {
let emu = IsolatedEmulator::start("test-ffx-create-parent-overrides").await.unwrap();
let moniker = "/core/ffx-laboratory:create-parent-override-echo";
let url = "fuchsia-pkg://fuchsia.com/ffx_create_parent_overrides_echo#meta/echo_config.cm";
let expected_greeting = "Hello from ffx parent overrides!";
info!("running test component with a config override...");
emu.ffx(&[
"component",
"create",
moniker,
url,
"--config",
&format!("greeting=\"{expected_greeting}\""),
])
.await
.unwrap();
emu.ffx(&["component", "start", moniker]).await.unwrap();
info!("checking for expected log message...");
'log_search: loop {
for message in emu.logs_for_moniker(moniker).await.unwrap() {
if message.msg() == Some(expected_greeting) {
info!("found expected log message!");
break 'log_search;
}
}
// Copyright 2023 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use ffx_e2e_emu::IsolatedEmulator;
use futures::StreamExt;
use log::info;
#[fuchsia::test(logging = true)]
async fn override_echo_greeting_and_observe_in_logs() {
let emu = IsolatedEmulator::start("test-ffx-run-parent-overrides").await.unwrap();
let moniker = "/core/ffx-laboratory:run-parent-override-echo";
let url = "fuchsia-pkg://fuchsia.com/ffx_run_parent_overrides_echo#meta/echo_config.cm";
let expected_greeting = "Hello from ffx parent overrides!";
info!("running test component with a config override...");
emu.ffx(&[
"component",
"run",
moniker,
url,
"--config",
&format!("greeting=\"{expected_greeting}\""),
])
.await
.unwrap();
info!("checking for expected log message...");
let mut stream = std::pin::pin!(emu.log_stream_for_moniker(moniker).await.unwrap());
N/A
{
"command": "ffx component capability",
"options": [],
"short": "Lists component instances that reference a capability"
}
if capability not in self.ffx.run(
["component", "capability", capability],
# TODO(b/474143046) update to JSON when ffx supports it
machine=ffx_types.MachineFormat.RAW,
):
_LOGGER.warning(
"All available netstack component capabilities:\n%s",
self.ffx.run(
["component", "capability", "fuchsia.net"],
# TODO(b/474143046) update to JSON when ffx supports it
machine=ffx_types.MachineFormat.RAW,
),
)
raise errors.NotSupportedError(
f'Component capability "{capability}" not exposed by device '
if capability not in self._ffx.run(
["component", "capability", capability],
# TODO(b/474143046) update to JSON when ffx supports it
machine=ffx_types.MachineFormat.RAW,
):
_LOGGER.warning(
"All available WLAN component capabilities:\n%s",
self._ffx.run(
["component", "capability", "fuchsia.wlan"],
# TODO(b/474143046) update to JSON when ffx supports it
machine=ffx_types.MachineFormat.RAW,
),
)
raise errors.NotSupportedError(
f'Component capability "{capability}" not exposed by device '
if capability not in self._ffx.run(
["component", "capability", capability],
# TODO(b/474143046) update to JSON when ffx supports it
machine=ffx_types.MachineFormat.RAW,
):
_LOGGER.warning(
"All available WLAN component capabilities:\n%s",
self._ffx.run(
["component", "capability", "fuchsia.wlan"],
# TODO(b/474143046) update to JSON when ffx supports it
machine=ffx_types.MachineFormat.RAW,
),
)
raise errors.NotSupportedError(
f'Component capability "{capability}" not exposed by device '
```posix-terminal
N/A
{
"command": "ffx component collection",
"options": [],
"short": "Manages collections in the component topology"
}
N/A
N/A
N/A
{
"command": "ffx component collection list",
"options": [],
"short": "List all collections in the component topology"
}
N/A
N/A
N/A
{
"command": "ffx component collection show",
"options": [],
"short": "Shows detailed information about a collection in the component topology"
}
N/A
N/A
N/A
{
"command": "ffx component config",
"options": [],
"short": "Manages configuration capability override values for components"
}
N/A
```posix-terminal
```posix-terminal
N/A
{
"command": "ffx component config list",
"options": [],
"short": "Lists structured configuration values for the specified component"
}
N/A
N/A
N/A
{
"command": "ffx component config set",
"options": [
{
"description": "if enabled, component instance will be immediately reloaded so overrides take effect.",
"option": "reload",
"shorthand": "r",
"value_type": "bool"
}
],
"short": "Sets configuration capability override values for the specified component"
}
N/A
```posix-terminal
N/A
{
"command": "ffx component config set",
"options": [
{
"description": "if enabled, component instance will be immediately reloaded so overrides take effect.",
"option": "reload",
"shorthand": "r",
"value_type": "bool"
}
],
"short": "Sets configuration capability override values for the specified component"
}
N/A
```posix-terminal
N/A
{
"command": "ffx component config unset",
"options": [
{
"description": "if enabled, component instance will be immediately reloaded so overrides take effect.",
"option": "reload",
"shorthand": "r",
"value_type": "bool"
}
],
"short": "Unsets structured configuration override values for the specified component"
}
N/A
```posix-terminal
N/A
{
"command": "ffx component config unset",
"options": [
{
"description": "if enabled, component instance will be immediately reloaded so overrides take effect.",
"option": "reload",
"shorthand": "r",
"value_type": "bool"
}
],
"short": "Unsets structured configuration override values for the specified component"
}
N/A
N/A
N/A
{
"command": "ffx component copy",
"options": [
{
"description": "verbose output: outputs a line for each file copied.",
"option": "verbose",
"shorthand": "v",
"value_type": "bool"
}
],
"short": "copies files to/from directories associated with a component. \nPaths may be any combination of local or remote paths."
}
Assuming that the instructions from above have been completed, the moniker of the component to be `/core/ffx-laboratory:test-driver`, which is what we will use for our `ffx component copy` example commands.
This component is used a test component for `ffx component copy`. Data/files will be copied from and to this component for testing purposes.
N/A
```posix-terminal
N/A
{
"command": "ffx component copy",
"options": [
{
"description": "verbose output: outputs a line for each file copied.",
"option": "verbose",
"shorthand": "v",
"value_type": "bool"
}
],
"short": "copies files to/from directories associated with a component. \nPaths may be any combination of local or remote paths."
}
N/A
N/A
N/A
{
"command": "ffx component create",
"options": [
{
"description": "provide a configuration override to the component being run. Requires `mutability: [ \"parent\" ]` on the configuration field. Specified in the format `KEY=VALUE` where `VALUE` is a JSON string which can be resolved as the correct type of configuration value.",
"option": "config",
"shorthand": "",
"value_type": "string"
}
],
"short": "Creates a dynamic component instance, adding it to the collection designated by <moniker>"
}
// Copyright 2023 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use ffx_e2e_emu::IsolatedEmulator;
use log::info;
#[fuchsia::test(logging = true)]
async fn override_echo_greeting_and_observe_in_logs() {
let emu = IsolatedEmulator::start("test-ffx-create-parent-overrides").await.unwrap();
let moniker = "/core/ffx-laboratory:create-parent-override-echo";
let url = "fuchsia-pkg://fuchsia.com/ffx_create_parent_overrides_echo#meta/echo_config.cm";
let expected_greeting = "Hello from ffx parent overrides!";
info!("running test component with a config override...");
emu.ffx(&[
"component",
"create",
moniker,
url,
"--config",
&format!("greeting=\"{expected_greeting}\""),
])
.await
.unwrap();
emu.ffx(&["component", "start", moniker]).await.unwrap();
info!("checking for expected log message...");
'log_search: loop {
#[fuchsia::test(logging = true)]
async fn override_echo_greeting_and_observe_in_logs() {
let emu = IsolatedEmulator::start("test-ffx-create-parent-overrides").await.unwrap();
let moniker = "/core/ffx-laboratory:create-parent-override-echo";
let url = "fuchsia-pkg://fuchsia.com/ffx_create_parent_overrides_echo#meta/echo_config.cm";
let expected_greeting = "Hello from ffx parent overrides!";
info!("running test component with a config override...");
emu.ffx(&[
"component",
"create",
moniker,
url,
"--config",
&format!("greeting=\"{expected_greeting}\""),
])
.await
.unwrap();
emu.ffx(&["component", "start", moniker]).await.unwrap();
info!("checking for expected log message...");
'log_search: loop {
for message in emu.logs_for_moniker(moniker).await.unwrap() {
if message.msg() == Some(expected_greeting) {
info!("found expected log message!");
break 'log_search;
}
}
```posix-terminal
N/A
{
"command": "ffx component create",
"options": [
{
"description": "provide a configuration override to the component being run. Requires `mutability: [ \"parent\" ]` on the configuration field. Specified in the format `KEY=VALUE` where `VALUE` is a JSON string which can be resolved as the correct type of configuration value.",
"option": "config",
"shorthand": "",
"value_type": "string"
}
],
"short": "Creates a dynamic component instance, adding it to the collection designated by <moniker>"
}
// Copyright 2023 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use ffx_e2e_emu::IsolatedEmulator;
use log::info;
#[fuchsia::test(logging = true)]
async fn override_echo_greeting_and_observe_in_logs() {
let emu = IsolatedEmulator::start("test-ffx-create-parent-overrides").await.unwrap();
let moniker = "/core/ffx-laboratory:create-parent-override-echo";
let url = "fuchsia-pkg://fuchsia.com/ffx_create_parent_overrides_echo#meta/echo_config.cm";
let expected_greeting = "Hello from ffx parent overrides!";
info!("running test component with a config override...");
emu.ffx(&[
"component",
"create",
moniker,
url,
"--config",
&format!("greeting=\"{expected_greeting}\""),
])
.await
.unwrap();
emu.ffx(&["component", "start", moniker]).await.unwrap();
info!("checking for expected log message...");
'log_search: loop {
#[fuchsia::test(logging = true)]
async fn override_echo_greeting_and_observe_in_logs() {
let emu = IsolatedEmulator::start("test-ffx-create-parent-overrides").await.unwrap();
let moniker = "/core/ffx-laboratory:create-parent-override-echo";
let url = "fuchsia-pkg://fuchsia.com/ffx_create_parent_overrides_echo#meta/echo_config.cm";
let expected_greeting = "Hello from ffx parent overrides!";
info!("running test component with a config override...");
emu.ffx(&[
"component",
"create",
moniker,
url,
"--config",
&format!("greeting=\"{expected_greeting}\""),
])
.await
.unwrap();
emu.ffx(&["component", "start", moniker]).await.unwrap();
info!("checking for expected log message...");
'log_search: loop {
for message in emu.logs_for_moniker(moniker).await.unwrap() {
if message.msg() == Some(expected_greeting) {
info!("found expected log message!");
break 'log_search;
}
}
N/A
N/A
{
"command": "ffx component debug",
"options": [],
"short": "Debug a running component with zxdb."
}
N/A
```posix-terminal
N/A
{
"command": "ffx component destroy",
"options": [],
"short": "Destroys a dynamic component instance, removing it from the collection designated by <moniker>"
}
#[fuchsia::test]
async fn test_delete() {
struct Impl;
impl DestroyCmdImpl for Impl {
async fn get_cml_moniker_from_query(
&mut self,
_query: &str,
_realm_query: &fsys::RealmQueryProxy,
) -> anyhow::Result<Moniker> {
Ok(Moniker::parse_str("core/foo:foo").unwrap())
}
async fn destroy_instance_in_collection(
&mut self,
_lifecycle_controller: &fsys::LifecycleControllerProxy,
_parent: &Moniker,
_collection: &BorrowedName,
_child_name: &BorrowedLongName,
) -> Result<(), DestroyError> {
Ok(())
}
}
let client = fdomain_local::local_client_empty();
let (lifecycle_controller, _) =
client.create_proxy_and_stream::<fsys::LifecycleControllerMarker>();
let (realm_query, _) = client.create_proxy_and_stream::<fsys::RealmQueryMarker>();
#[fuchsia::test]
async fn test_root_moniker() {
struct Impl;
impl DestroyCmdImpl for Impl {
async fn get_cml_moniker_from_query(
&mut self,
_query: &str,
_realm_query: &fsys::RealmQueryProxy,
) -> anyhow::Result<Moniker> {
Ok(Moniker::parse_str("foo").unwrap())
}
async fn destroy_instance_in_collection(
&mut self,
_lifecycle_controller: &fsys::LifecycleControllerProxy,
_parent: &Moniker,
_collection: &BorrowedName,
_child_name: &BorrowedLongName,
) -> Result<(), DestroyError> {
Ok(())
}
}
let client = fdomain_local::local_client_empty();
let (lifecycle_controller, _) =
client.create_proxy_and_stream::<fsys::LifecycleControllerMarker>();
let (realm_query, _) = client.create_proxy_and_stream::<fsys::RealmQueryMarker>();
// Copyright 2022 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use anyhow::{Result, anyhow};
```posix-terminal
N/A
{
"command": "ffx component doctor",
"options": [
{
"description": "whether or not to display the output without color and wrapping.",
"option": "plain",
"shorthand": "p",
"value_type": "bool"
}
],
"short": "Perform diagnostic checks on a component at runtime."
}
N/A
```posix-terminal
N/A
{
"command": "ffx component doctor",
"options": [
{
"description": "whether or not to display the output without color and wrapping.",
"option": "plain",
"shorthand": "p",
"value_type": "bool"
}
],
"short": "Perform diagnostic checks on a component at runtime."
}
N/A
N/A
N/A
{
"command": "ffx component explore",
"options": [
{
"description": "list of URLs of tools packages to include in the shell environment. the PATH variable will be updated to include binaries from these tools packages. repeat `--tools url` for each package to be included. The path preference is given by command line order.",
"option": "tools",
"shorthand": "",
"value_type": "string"
},
{
"description": "execute a command instead of reading from stdin. the exit code of the command will be forwarded to the host.",
"option": "command",
N/A
```posix-terminal
N/A
{
"command": "ffx component explore",
"options": [
{
"description": "list of URLs of tools packages to include in the shell environment. the PATH variable will be updated to include binaries from these tools packages. repeat `--tools url` for each package to be included. The path preference is given by command line order.",
"option": "tools",
"shorthand": "",
"value_type": "string"
},
{
"description": "execute a command instead of reading from stdin. the exit code of the command will be forwarded to the host.",
"option": "command",
N/A
N/A
N/A
{
"command": "ffx component explore",
"options": [
{
"description": "list of URLs of tools packages to include in the shell environment. the PATH variable will be updated to include binaries from these tools packages. repeat `--tools url` for each package to be included. The path preference is given by command line order.",
"option": "tools",
"shorthand": "",
"value_type": "string"
},
{
"description": "execute a command instead of reading from stdin. the exit code of the command will be forwarded to the host.",
"option": "command",
N/A
N/A
N/A
{
"command": "ffx component explore",
"options": [
{
"description": "list of URLs of tools packages to include in the shell environment. the PATH variable will be updated to include binaries from these tools packages. repeat `--tools url` for each package to be included. The path preference is given by command line order.",
"option": "tools",
"shorthand": "",
"value_type": "string"
},
{
"description": "execute a command instead of reading from stdin. the exit code of the command will be forwarded to the host.",
"option": "command",
N/A
N/A
N/A
{
"command": "ffx component graph",
"options": [
{
"description": "filter the instance list by a criteria: ancestor, descendant, relative",
"option": "only",
"shorthand": "o",
"value_type": "string"
},
{
"description": "changes the visual orientation of the graph's nodes. Allowed values are \"lefttoright\"/\"lr\" and \"toptobottom\"/\"tb\".",
"option": "orientation",
N/A
```posix-terminal
N/A
{
"command": "ffx component graph",
"options": [
{
"description": "filter the instance list by a criteria: ancestor, descendant, relative",
"option": "only",
"shorthand": "o",
"value_type": "string"
},
{
"description": "changes the visual orientation of the graph's nodes. Allowed values are \"lefttoright\"/\"lr\" and \"toptobottom\"/\"tb\".",
"option": "orientation",
N/A
```posix-terminal
N/A
{
"command": "ffx component graph",
"options": [
{
"description": "filter the instance list by a criteria: ancestor, descendant, relative",
"option": "only",
"shorthand": "o",
"value_type": "string"
},
{
"description": "changes the visual orientation of the graph's nodes. Allowed values are \"lefttoright\"/\"lr\" and \"toptobottom\"/\"tb\".",
"option": "orientation",
N/A
```posix-terminal
N/A
{
"command": "ffx component list",
"options": [
{
"description": "filter the instance list by a criteria: running, stopped, ancestors:<component_name>, descendants:<component_name>, or relatives:<component_name>",
"option": "only",
"shorthand": "o",
"value_type": "string"
},
{
"description": "show detailed information about each instance",
"option": "verbose",
#[fuchsia::test]
async fn test_schema() -> Result<()> {
let client = fdomain_local::local_client_empty();
let cmd = ComponentListCommand { filter: None, verbose: false };
let tool = ListTool {
cmd,
rcs: testing_lib::setup_fake_rcs(client, testing_lib::FakeRcsConfig::default()).into(),
};
let buffers = TestBuffers::default();
let writer = <ListTool as FfxMain>::Writer::new_test(Some(Format::Json), &buffers);
let result = tool.main(writer).await;
assert!(result.is_ok());
let output = buffers.into_stdout_str();
let err = format!("schema not valid {output}");
let json = serde_json::from_str(&output).expect(&err);
let err = format!("json must adhere to schema: {json}");
<ListTool as FfxMain>::Writer::verify_schema(&json).expect(&err);
let want = ListOutput {
instances: vec![
Instance {
environment: None,
moniker: Moniker::parse_str("example/component")?,
resolved_info: Some(ResolvedInfo {
execution_info: None,
output = self._ffx_transport.run(
["--machine", "json", "component", "list"]
)
component_list = json.loads(output)
instances = component_list.get("instances", [])
if not any(
instance.get("moniker") == _MEDIA_SESSION_COMPONENT
for instance in instances
):
raise errors.NotSupportedError(
f"{_MEDIA_SESSION_COMPONENT} is not available in device {self._name}"
res = self._ffx.run(
["component", "list"], machine=ffx_types.MachineFormat.RAW
)
components = res.splitlines()
for component in components:
if component.startswith(ELEMENT_PREFIX):
name = component[len(ELEMENT_PREFIX) :]
# Starnix's element naming starts with main. Not sure how to remove them yet,
# `ffx session remove` seems not work.
if not name.startswith("main"):
_LOGGER.info(
"remove component on device %s: %s",
self._name,
name,
)
self._ffx.run(
["session", "remove", name],
machine=ffx_types.MachineFormat.RAW,
)
except ffx_errors.FfxCommandError as err:
# TODO(b/406501041): Handle potential "NotFound" error. If multiple components share the
# same URL, removing one will implicitly remove all others with that URL. Subsequent
# attempts to remove components with the same URL will result in a "NotFound" error.
if "Error: NotFound" not in str(err):
raise session_errors.SessionError(err)
```posix-terminal
N/A
{
"command": "ffx component list",
"options": [
{
"description": "filter the instance list by a criteria: running, stopped, ancestors:<component_name>, descendants:<component_name>, or relatives:<component_name>",
"option": "only",
"shorthand": "o",
"value_type": "string"
},
{
"description": "show detailed information about each instance",
"option": "verbose",
N/A
```posix-terminal
N/A
{
"command": "ffx component list",
"options": [
{
"description": "filter the instance list by a criteria: running, stopped, ancestors:<component_name>, descendants:<component_name>, or relatives:<component_name>",
"option": "only",
"shorthand": "o",
"value_type": "string"
},
{
"description": "show detailed information about each instance",
"option": "verbose",
N/A
N/A
N/A
{
"command": "ffx component reload",
"options": [],
"short": "Recursively stops, unresolves, and starts a component instance, updating the code and topology while preserving resources"
}
N/A
```posix-terminal
N/A
{
"command": "ffx component resolve",
"options": [],
"short": "Resolves a component instance"
}
N/A
```posix-terminal
N/A
{
"command": "ffx component route",
"options": [],
"short": "Perform capability routing on a component at runtime."
}
N/A
```posix-terminal
N/A
{
"command": "ffx component run",
"options": [
{
"description": "destroy and recreate the component instance if it already exists",
"option": "recreate",
"shorthand": "r",
"value_type": "bool"
},
{
"description": "start printing logs from the started component after it has started",
"option": "follow-logs",
Use `ffx component run` to launch this component into a restricted realm for development purposes:
// Copyright 2023 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use ffx_e2e_emu::IsolatedEmulator;
use futures::StreamExt;
use log::info;
#[fuchsia::test(logging = true)]
async fn override_echo_greeting_and_observe_in_logs() {
let emu = IsolatedEmulator::start("test-ffx-run-parent-overrides").await.unwrap();
let moniker = "/core/ffx-laboratory:run-parent-override-echo";
let url = "fuchsia-pkg://fuchsia.com/ffx_run_parent_overrides_echo#meta/echo_config.cm";
let expected_greeting = "Hello from ffx parent overrides!";
info!("running test component with a config override...");
emu.ffx(&[
"component",
"run",
moniker,
url,
"--config",
&format!("greeting=\"{expected_greeting}\""),
])
.await
.unwrap();
info!("checking for expected log message...");
let mut stream = std::pin::pin!(emu.log_stream_for_moniker(moniker).await.unwrap());
#[fuchsia::test(logging = true)]
async fn override_echo_greeting_and_observe_in_logs() {
let emu = IsolatedEmulator::start("test-ffx-run-parent-overrides").await.unwrap();
let moniker = "/core/ffx-laboratory:run-parent-override-echo";
let url = "fuchsia-pkg://fuchsia.com/ffx_run_parent_overrides_echo#meta/echo_config.cm";
let expected_greeting = "Hello from ffx parent overrides!";
info!("running test component with a config override...");
emu.ffx(&[
"component",
"run",
moniker,
url,
"--config",
&format!("greeting=\"{expected_greeting}\""),
])
.await
.unwrap();
info!("checking for expected log message...");
let mut stream = std::pin::pin!(emu.log_stream_for_moniker(moniker).await.unwrap());
while let Some(message) = stream.next().await {
if message.unwrap().msg() == Some(expected_greeting) {
info!("found expected log message!");
break;
}
}
}
// Copyright 2023 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use anyhow::{Context, Result, bail};
```posix-terminal
N/A
{
"command": "ffx component run",
"options": [
{
"description": "destroy and recreate the component instance if it already exists",
"option": "recreate",
"shorthand": "r",
"value_type": "bool"
},
{
"description": "start printing logs from the started component after it has started",
"option": "follow-logs",
// Copyright 2023 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use ffx_e2e_emu::IsolatedEmulator;
use futures::StreamExt;
use log::info;
#[fuchsia::test(logging = true)]
async fn override_echo_greeting_and_observe_in_logs() {
let emu = IsolatedEmulator::start("test-ffx-run-parent-overrides").await.unwrap();
let moniker = "/core/ffx-laboratory:run-parent-override-echo";
let url = "fuchsia-pkg://fuchsia.com/ffx_run_parent_overrides_echo#meta/echo_config.cm";
let expected_greeting = "Hello from ffx parent overrides!";
info!("running test component with a config override...");
emu.ffx(&[
"component",
"run",
moniker,
url,
"--config",
&format!("greeting=\"{expected_greeting}\""),
])
.await
.unwrap();
info!("checking for expected log message...");
let mut stream = std::pin::pin!(emu.log_stream_for_moniker(moniker).await.unwrap());
#[fuchsia::test(logging = true)]
async fn override_echo_greeting_and_observe_in_logs() {
let emu = IsolatedEmulator::start("test-ffx-run-parent-overrides").await.unwrap();
let moniker = "/core/ffx-laboratory:run-parent-override-echo";
let url = "fuchsia-pkg://fuchsia.com/ffx_run_parent_overrides_echo#meta/echo_config.cm";
let expected_greeting = "Hello from ffx parent overrides!";
info!("running test component with a config override...");
emu.ffx(&[
"component",
"run",
moniker,
url,
"--config",
&format!("greeting=\"{expected_greeting}\""),
])
.await
.unwrap();
info!("checking for expected log message...");
let mut stream = std::pin::pin!(emu.log_stream_for_moniker(moniker).await.unwrap());
while let Some(message) = stream.next().await {
if message.unwrap().msg() == Some(expected_greeting) {
info!("found expected log message!");
break;
}
}
}
N/A
N/A
{
"command": "ffx component run",
"options": [
{
"description": "destroy and recreate the component instance if it already exists",
"option": "recreate",
"shorthand": "r",
"value_type": "bool"
},
{
"description": "start printing logs from the started component after it has started",
"option": "follow-logs",
N/A
N/A
N/A
{
"command": "ffx component run",
"options": [
{
"description": "destroy and recreate the component instance if it already exists",
"option": "recreate",
"shorthand": "r",
"value_type": "bool"
},
{
"description": "start printing logs from the started component after it has started",
"option": "follow-logs",
N/A
N/A
N/A
{
"command": "ffx component run",
"options": [
{
"description": "destroy and recreate the component instance if it already exists",
"option": "recreate",
"shorthand": "r",
"value_type": "bool"
},
{
"description": "start printing logs from the started component after it has started",
"option": "follow-logs",
N/A
N/A
N/A
{
"command": "ffx component show",
"options": [],
"short": "Shows detailed information about a component instance"
}
#[fuchsia::test]
async fn test_show_unknown_component_search() {
let test_buffers = TestBuffers::default();
let mut writer = MachineWriter::new_test(Some(Format::Json), &test_buffers);
let cmd = ShowCommand {
data: vec![],
selectors: vec!["some-bad-moniker".to_string()],
accessor: None,
name: None,
};
let lifecycle_data = inspect_accessor_data(
ClientSelectorConfiguration::SelectAll(true),
make_inspects_for_lifecycle(),
);
let inspects = make_inspects();
let inspect_data =
inspect_accessor_data(ClientSelectorConfiguration::SelectAll(true), inspects.clone());
let client = fdomain_local::local_client_empty();
let rcs_proxy = setup_fake_rcs(client.clone(), vec![]);
let accessor_proxy = setup_fake_archive_accessor(client, vec![lifecycle_data, inspect_data]);
assert!(
run_command(rcs_proxy, accessor_proxy, ShowCommand::from(cmd), &mut writer)
.await
.unwrap_err()
.ffx_error()
.is_some()
);
}
#[fuchsia::test]
async fn test_show_with_component_search() {
let test_buffers = TestBuffers::default();
let mut writer = MachineWriter::new_test(Some(Format::Json), &test_buffers);
let cmd = ShowCommand {
selectors: vec!["moniker1".to_string()],
accessor: None,
name: None,
data: vec![],
};
let lifecycle_data = inspect_accessor_data(
ClientSelectorConfiguration::SelectAll(true),
make_inspects_for_lifecycle(),
);
let mut inspects = vec![
make_inspect_with_length("test/moniker1", 1, 20),
make_inspect_with_length("test/moniker1", 3, 10),
make_inspect_with_length("test/moniker1", 6, 30),
];
let inspect_data = inspect_accessor_data(
ClientSelectorConfiguration::Selectors(vec![SelectorArgument::StructuredSelector(
selectors::parse_verbose("test/moniker1:[...]root").unwrap(),
)]),
inspects.clone(),
);
let client = fdomain_local::local_client_empty();
let rcs_proxy = setup_fake_rcs(client.clone(), vec!["test/moniker1"]);
let accessor_proxy = setup_fake_archive_accessor(client, vec![lifecycle_data, inspect_data]);
run_command(rcs_proxy, accessor_proxy, ShowCommand::from(cmd), &mut writer).await.unwrap();
```posix-terminal
N/A
{
"command": "ffx component start",
"options": [
{
"description": "start the component in the debugger. To debug a component that is already running, consider `ffx component debug`.",
"option": "debug",
"shorthand": "",
"value_type": "bool"
}
],
"short": "Starts a component"
}
// Copyright 2023 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use ffx_e2e_emu::IsolatedEmulator;
use log::info;
#[fuchsia::test(logging = true)]
async fn override_echo_greeting_and_observe_in_logs() {
let emu = IsolatedEmulator::start("test-ffx-create-parent-overrides").await.unwrap();
let moniker = "/core/ffx-laboratory:create-parent-override-echo";
let url = "fuchsia-pkg://fuchsia.com/ffx_create_parent_overrides_echo#meta/echo_config.cm";
let expected_greeting = "Hello from ffx parent overrides!";
info!("running test component with a config override...");
emu.ffx(&[
"component",
"create",
moniker,
url,
"--config",
&format!("greeting=\"{expected_greeting}\""),
])
.await
.unwrap();
emu.ffx(&["component", "start", moniker]).await.unwrap();
info!("checking for expected log message...");
'log_search: loop {
#[fuchsia::test(logging = true)]
async fn override_echo_greeting_and_observe_in_logs() {
let emu = IsolatedEmulator::start("test-ffx-create-parent-overrides").await.unwrap();
let moniker = "/core/ffx-laboratory:create-parent-override-echo";
let url = "fuchsia-pkg://fuchsia.com/ffx_create_parent_overrides_echo#meta/echo_config.cm";
let expected_greeting = "Hello from ffx parent overrides!";
info!("running test component with a config override...");
emu.ffx(&[
"component",
"create",
moniker,
url,
"--config",
&format!("greeting=\"{expected_greeting}\""),
])
.await
.unwrap();
emu.ffx(&["component", "start", moniker]).await.unwrap();
info!("checking for expected log message...");
'log_search: loop {
for message in emu.logs_for_moniker(moniker).await.unwrap() {
if message.msg() == Some(expected_greeting) {
info!("found expected log message!");
break 'log_search;
}
}
```posix-terminal
N/A
{
"command": "ffx component start",
"options": [
{
"description": "start the component in the debugger. To debug a component that is already running, consider `ffx component debug`.",
"option": "debug",
"shorthand": "",
"value_type": "bool"
}
],
"short": "Starts a component"
}
N/A
```posix-terminal
N/A
{
"command": "ffx component stop",
"options": [],
"short": "Stops a component instance"
}
#[fuchsia::test]
async fn test_stop() -> anyhow::Result<()> {
let client = fdomain_local::local_client_empty();
let moniker = "core/test".to_string();
let mut capability_handlers = std::collections::HashMap::new();
// Handler for RealmQuery
let client_clone = client.clone();
capability_handlers.insert(
"svc/fuchsia.sys2.RealmQuery.root".to_string(),
Box::new(move |server_channel| {
let client = client_clone.clone();
let mut rq_stream =
ServerEnd::<fsys_f::RealmQueryMarker>::new(server_channel).into_stream();
fuchsia_async::Task::local(async move {
while let Ok(Some(rq_req)) = rq_stream.try_next().await {
match rq_req {
fsys_f::RealmQueryRequest::GetAllInstances { responder } => {
let (client_end, mut iterator_stream) =
client
.create_request_stream::<fsys_f::InstanceIteratorMarker>();
fuchsia_async::Task::local(async move {
if let Ok(Some(fsys_f::InstanceIteratorRequest::Next {
responder,
})) = iterator_stream.try_next().await
{
responder
.send(&[fsys_f::Instance {
```posix-terminal
N/A
{
"command": "ffx component storage",
"options": [
{
"description": "the moniker of the storage provider component. Defaults to \"/core\"",
"option": "provider",
"shorthand": "",
"value_type": "string"
},
{
"description": "the capability name of the storage to use. Examples: \"data\", \"cache\", \"tmp\" Defaults to \"data\"",
"option": "capability",
#[fuchsia::test]
async fn test_storage_list_machine() {
let client = fdomain_local::local_client_empty();
let (rcs_proxy, _) = client.create_proxy_and_stream::<rc::RemoteControlMarker>();
let rcs = rcs_proxy.into();
let tool = StorageTool {
cmd: StorageCommand {
subcommand: SubCommandEnum::List(ListArgs { path: "123456::.".to_string() }),
provider: "/core".to_string(),
capability: "data".to_string(),
},
rcs,
};
let test_buffers = TestBuffers::default();
let writer = MachineWriter::new_test(Some(ffx_writer::Format::Json), &test_buffers);
let result = tool.main(writer).await;
assert!(result.is_err());
}
N/A
{
"command": "ffx component storage",
"options": [
{
"description": "the moniker of the storage provider component. Defaults to \"/core\"",
"option": "provider",
"shorthand": "",
"value_type": "string"
},
{
"description": "the capability name of the storage to use. Examples: \"data\", \"cache\", \"tmp\" Defaults to \"data\"",
"option": "capability",
N/A
```posix-terminal
```posix-terminal
```posix-terminal
N/A
{
"command": "ffx component storage",
"options": [
{
"description": "the moniker of the storage provider component. Defaults to \"/core\"",
"option": "provider",
"shorthand": "",
"value_type": "string"
},
{
"description": "the capability name of the storage to use. Examples: \"data\", \"cache\", \"tmp\" Defaults to \"data\"",
"option": "capability",
N/A
```posix-terminal
```posix-terminal
```posix-terminal
N/A
{
"command": "ffx component storage copy",
"options": [],
"short": "Copy files to/from a component's storage. If the file already exists at the destination it is overwritten."
}
N/A
```posix-terminal
N/A
{
"command": "ffx component storage delete",
"options": [],
"short": "Delete files from a component's storage."
}
N/A
```posix-terminal
N/A
{
"command": "ffx component storage delete-all",
"options": [],
"short": "Delete the contents of the storage for a specific component."
}
N/A
```posix-terminal
N/A
{
"command": "ffx component storage list",
"options": [],
"short": "List the contents of a component's storage."
}
N/A
```posix-terminal
N/A
{
"command": "ffx component storage make-directory",
"options": [],
"short": "Create a new directory in a component's storage. If the directory already exists, this operation is a no-op."
}
N/A
```posix-terminal
N/A
{
"command": "ffx config",
"options": [],
"short": "View and switch default and user configurations"
}
Manual targets are configured via `ffx target add` or `ffx config`. This is currently done by address only.
Configuring values and defaults for `ffx` inside the isolate is done using the `ffx config` commandline:
#[test]
fn test_config_levels_make_sense_from_first() {
let mut found_set = HashSet::new();
let mut from_first = None;
for _ in 0..ConfigLevel::_COUNT + 1 {
if let Some(next) = ConfigLevel::next(from_first) {
let entry = found_set.get(&next);
assert!(entry.is_none(), "Found duplicate config level while iterating: {next:?}");
found_set.insert(next);
from_first = Some(next);
} else {
break;
}
}
assert_eq!(
ConfigLevel::_COUNT,
found_set.len(),
"A config level was missing from the forward iteration of levels: {found_set:?}"
);
}
#[test]
fn test_converting_array() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let c = |val: Value| -> ConfigValue { ConfigValue(Some(val)) };
let conv_elem: Vec<String> = <_>::try_convert(c(json!("test")))?;
assert_eq!(1, conv_elem.len());
let conv_string: Vec<String> = <_>::try_convert(c(json!(["test", "test2"])))?;
assert_eq!(2, conv_string.len());
let conv_bool: Vec<bool> = <_>::try_convert(c(json!([true, "false", false])))?;
assert_eq!(3, conv_bool.len());
let conv_bool_2: Vec<bool> = <_>::try_convert(c(json!([36, "false", false])))?;
assert_eq!(2, conv_bool_2.len());
let conv_num: Vec<u64> = <_>::try_convert(c(json!([3, "36", 1000])))?;
assert_eq!(3, conv_num.len());
let conv_num_2: Vec<u64> = <_>::try_convert(c(json!([3, "false", 1000])))?;
assert_eq!(2, conv_num_2.len());
let bad_elem: Result<Vec<u64>, ConfigError> = <_>::try_convert(c(json!("test")));
assert!(bad_elem.is_err());
let bad_elem_2: Result<Vec<u64>, ConfigError> = <_>::try_convert(c(json!(["test"])));
assert!(bad_elem_2.is_err());
Ok(())
}
#[test]
fn test_validating_types() {
let c = |val: Value| -> ConfigValue { ConfigValue(Some(val)) };
assert!(<String>::try_convert(c(json!("test"))).is_ok());
assert!(<String>::try_convert(c(json!(1))).is_err());
assert!(<String>::try_convert(c(json!(false))).is_err());
assert!(<String>::try_convert(c(json!(true))).is_err());
assert!(<String>::try_convert(c(json!({"test": "whatever"}))).is_err());
assert!(<String>::try_convert(c(json!(["test", "test2"]))).is_err());
assert!(<bool>::try_convert(c(json!(true))).is_ok());
assert!(<bool>::try_convert(c(json!(false))).is_ok());
assert!(<bool>::try_convert(c(json!("true"))).is_ok());
assert!(<bool>::try_convert(c(json!("false"))).is_ok());
assert!(<bool>::try_convert(c(json!(1))).is_err());
assert!(<bool>::try_convert(c(json!("test"))).is_err());
assert!(<bool>::try_convert(c(json!({"test": "whatever"}))).is_err());
assert!(<bool>::try_convert(c(json!(["test", "test2"]))).is_err());
assert!(<u64>::try_convert(c(json!(2))).is_ok());
assert!(<u64>::try_convert(c(json!(100))).is_ok());
assert!(<u64>::try_convert(c(json!("100"))).is_ok());
assert!(<u64>::try_convert(c(json!("0"))).is_ok());
assert!(<u64>::try_convert(c(json!(true))).is_err());
assert!(<u64>::try_convert(c(json!("test"))).is_err());
assert!(<u64>::try_convert(c(json!({"test": "whatever"}))).is_err());
assert!(<u64>::try_convert(c(json!(["test", "test2"]))).is_err());
assert!(<PathBuf>::try_convert(c(json!("/"))).is_ok());
assert!(<PathBuf>::try_convert(c(json!("test"))).is_ok());
assert!(<PathBuf>::try_convert(c(json!(true))).is_err());
assert!(<PathBuf>::try_convert(c(json!({"test": "whatever"}))).is_err());
N/A
{
"command": "ffx config add",
"options": [],
"short": "add config value the end of an array"
}
N/A
N/A
N/A
{
"command": "ffx config analytics",
"options": [],
"short": "enable or disable analytics"
}
N/A
N/A
N/A
{
"command": "ffx config analytics disable",
"options": [],
"short": "disable analytics"
}
N/A
N/A
N/A
{
"command": "ffx config analytics enable",
"options": [],
"short": "enable basic (redacted) analytics"
}
N/A
N/A
N/A
{
"command": "ffx config analytics enable-enhanced",
"options": [],
"short": "enable enhanced analytics (Googlers only)"
}
N/A
N/A
N/A
{
"command": "ffx config analytics show",
"options": [],
"short": "show analytics"
}
N/A
N/A
N/A
{
"command": "ffx config check-ssh-keys",
"options": [],
"short": "check the ssh key configuration and create keys if needed."
}
N/A
N/A
N/A
{
"command": "ffx config env",
"options": [],
"short": "list environment settings"
}
The command collection `ffx config env` is used to manage the configuration of how to locate the various configuration level data files.
// Copyright 2021 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use crate::test::new_isolate;
use crate::{assert, assert_eq};
```posix-terminal
N/A
{
"command": "ffx config env get",
"options": [],
"short": "list environment for a given level"
}
// Copyright 2021 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use crate::test::new_isolate;
use crate::{assert, assert_eq};
N/A
N/A
{
"command": "ffx config env set",
"options": [
{
"description": "config level. Possible values are \"user\", \"build\", \"global\". Defaults to \"user\".",
"option": "level",
"shorthand": "l",
"value_type": "string"
}
],
"short": "set environment settings"
}
N/A
```posix-terminal
N/A
{
"command": "ffx config env set",
"options": [
{
"description": "config level. Possible values are \"user\", \"build\", \"global\". Defaults to \"user\".",
"option": "level",
"shorthand": "l",
"value_type": "string"
}
],
"short": "set environment settings"
}
N/A
```posix-terminal
N/A
{
"command": "ffx config get",
"options": [
{
"description": "how to process results. Possible values are \"r/raw\", \"s/sub/substitute\", or \"f/file\". Defaults to \"substitute\". Currently only supported if a name is given. The process type \"file\" returns a scalar value. In the case of the configuration being a list, it is treated as an ordered list of alternatives and takes the first value that exists.",
"option": "process",
"shorthand": "p",
"value_type": "string"
},
{
"description": "how to collect results. Possible values are \"first\" and \"all\". Defaults to \"first\". If the value is \"first\", the first value found in terms of priority is returned. If the value is \"all\", all values across all configuration levels are aggregrated and returned. Currently only supported if a name is given.",
"option": "select",
workflow. Existing configurations can be accessed via `ffx config get`.
| | large list -- use `ffx config get` | | | to see the default categories. | | `triage.config_paths` | Contains the list of default triage| | | configs. Must be set in out-of-tree| | | environments. | | `tunnels` | Contains the list of tunnels as | | | specified by Tunnel::ForwardPort | | | requests. Default: empty | | `watchdogs.host_pipe.enabled` | Specifies whether to run | | | "watchdogs" on daemon host-pipes, | | | in order to debug whether ssh | | | failures are due to the Rust | | | executor getting stuck. |
// Copyright 2021 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use crate::test::new_isolate;
use crate::{assert, assert_eq};
// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use crate::test::*;
use anyhow::Result;
use errors::ffx_error;
use ffx_config::EnvironmentContext;
use ffx_selftest_args::SelftestCommand;
use ffx_writer::SimpleWriter;
use fho::{FfxMain, FfxTool};
// Copyright 2023 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#[cfg(test)]
mod tests {
use ffx_command::CliArgsInfo;
use ffx_testing::{TestContext, base_fixture};
use fixture::fixture;
use std::collections::HashSet;
// base_fixture sets up the test environment this test
#[fixture(base_fixture)]
#[fuchsia::test]
async fn test_top_level(ctx: TestContext) {
// Get the top level help and make sure all the commands in `ffx commands` are listed.
let (builtins, externals) = parse_top_level_commands(&ctx).await;
// We're not concerned in this test how many commands were returned, just that a reasonable number was.
assert!(builtins.len() >= 5, "Expected at least 5 builtin commands, got {builtins:?}");
assert!(externals.len() >= 1, "Expected at least 1 external command, got {externals:?}");
// Now get the json help and make sure all the commands are referenced.
let output = ctx.isolate().ffx(&["--machine", "json", "--help"]).await.expect("help");
assert!(output.status.success());
let info: CliArgsInfo = serde_json::from_str(&output.stdout).expect("parsing json");
assert_eq!("Ffx", info.name);
// look for --machine and --help and --verbose, which are _some_ of the flags, just
// making sure the flags were populated.
```posix-terminal
N/A
{
"command": "ffx config get",
"options": [
{
"description": "how to process results. Possible values are \"r/raw\", \"s/sub/substitute\", or \"f/file\". Defaults to \"substitute\". Currently only supported if a name is given. The process type \"file\" returns a scalar value. In the case of the configuration being a list, it is treated as an ordered list of alternatives and takes the first value that exists.",
"option": "process",
"shorthand": "p",
"value_type": "string"
},
{
"description": "how to collect results. Possible values are \"first\" and \"all\". Defaults to \"first\". If the value is \"first\", the first value found in terms of priority is returned. If the value is \"all\", all values across all configuration levels are aggregrated and returned. Currently only supported if a name is given.",
"option": "select",
N/A
N/A
N/A
{
"command": "ffx config get",
"options": [
{
"description": "how to process results. Possible values are \"r/raw\", \"s/sub/substitute\", or \"f/file\". Defaults to \"substitute\". Currently only supported if a name is given. The process type \"file\" returns a scalar value. In the case of the configuration being a list, it is treated as an ordered list of alternatives and takes the first value that exists.",
"option": "process",
"shorthand": "p",
"value_type": "string"
},
{
"description": "how to collect results. Possible values are \"first\" and \"all\". Defaults to \"first\". If the value is \"first\", the first value found in terms of priority is returned. If the value is \"all\", all values across all configuration levels are aggregrated and returned. Currently only supported if a name is given.",
"option": "select",
N/A
N/A
N/A
{
"command": "ffx config remove",
"options": [],
"short": "remove user level config values"
}
N/A
N/A
N/A
{
"command": "ffx config set",
"options": [],
"short": "set config settings"
}
all commands depend on the daemon, and some commands (like `ffx config set`) may need to be run before starting the daemon.
2. [User level configuration (set by `ffx config set`)](#user-configuration) 3. [Build directory level configuration (generated by the build)](#build-configuration) 2. [Global level configuration variables](#global-configuration) 3. [Default configuration (compiled into ffx)](#default-configuration)
// Copyright 2023 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use anyhow::{Context as _, ensure};
// Copyright 2023 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use anyhow::{Context, Result, bail};
#[fuchsia::test(logging = true)]
async fn test_ffx_profile_heapdump() {
let scratch_dir = tempdir().expect("Failed to create a temporary directory");
let emu = IsolatedEmulator::start("test-ffx-profile-heapdump").await.unwrap();
// Enable heapdump's experimental plugin.
emu.ffx(&["config", "set", "ffx_profile_heapdump", "true"]).await.unwrap();
info!("Starting heapdump's example component...");
let moniker = "/core/ffx-laboratory:heapdump-example";
let url = "fuchsia-pkg://fuchsia.com/heapdump-example#meta/heapdump-example.cm";
emu.ffx(&["component", "run", moniker, url]).await.unwrap();
// Wait for the example component to have completed its execution *and* the collector to have
// received all the eight stored snapshots it produces. Note that, after generating the eight
// stored snapshots, the test program enters pause() so that it stays alive until killed.
const NUM_EXPECTED_SNAPSHOTS: usize = 8;
let stored_snapshots =
wait_at_least_n_stored_snapshots(&emu, NUM_EXPECTED_SNAPSHOTS).await.unwrap();
// Verify that the snapshot names match those produced by the example program.
info!("Validating list of stored snapshots...");
for (i, snapshot) in stored_snapshots.iter().enumerate() {
assert_eq!(snapshot.snapshot_name, format!("fib-{}", i));
assert_eq!(snapshot.process_name, "heapdump-example.cm");
}
// Verify that a stored snapshot can be downloaded and parsed successfully.
info!("Validating the last stored snapshot...");
{
N/A
{
"command": "ffx coverage",
"options": [
{
"description": "path to ffx test output directory",
"option": "test-output-dir",
"shorthand": "",
"value_type": "string"
},
{
"description": "path to clang directory, llvm-profdata and llvm-cov are expected in clang_dir/bin",
"option": "clang-dir",
#[test]
fn test_glob_profraws() {
let test_dir = TempDir::new().unwrap();
create_dir(test_dir.path().join("nested")).unwrap();
File::create(test_dir.path().join("foo.profraw")).unwrap();
File::create(test_dir.path().join("nested").join("bar.profraw")).unwrap();
File::create(test_dir.path().join("foo.not_profraw")).unwrap();
File::create(test_dir.path().join("nested").join("baz.not_profraw")).unwrap();
assert_eq!(
glob_profraws(&test_dir.path().to_path_buf()).unwrap(),
vec![
PathBuf::from(test_dir.path().join("foo.profraw")),
PathBuf::from(test_dir.path().join("nested").join("bar.profraw")),
],
);
}
#[fuchsia::test]
async fn test_coverage() {
let _env = ffx_config::test_init().unwrap();
let test_dir = TempDir::new().unwrap();
let test_dir_path = test_dir.path().to_path_buf();
let test_bin_dir = test_dir_path.join("bin");
create_dir(&test_bin_dir).unwrap();
// Create an empty symbol index for testing.
let test_symbol_index_json = test_dir.path().join("symbol_index.json");
File::create(&test_symbol_index_json).unwrap().write_all(b"{}").unwrap();
// Missing both llvm-profdata and llvm-cov.
assert!(
coverage(CoverageCommand {
test_output_dir: PathBuf::from(&test_dir_path),
clang_dir: PathBuf::from(&test_dir_path),
symbol_index_json: Some(PathBuf::from(&test_symbol_index_json)),
export_html: None,
export_lcov: None,
export_json: None,
path_remappings: Vec::new(),
compilation_dir: None,
src_files: Vec::new(),
verbose: false,
})
.await
.is_err()
#[test]
fn test_find_binaries_single_match() {
let test_dir = TempDir::new().unwrap();
create_dir(test_dir.path().join("fo")).unwrap();
let debug_file = test_dir.path().join("fo").join("obar.debug");
File::create(&debug_file).unwrap();
let profraw = PathBuf::from("test.profraw");
let profdata_cmd = ProfdataRunner::new(PathBuf::new(), VerboseMode::NotVerbose);
let mut mocks = HashMap::new();
mocks.insert(profraw.clone(), vec!["foobar".to_string()]);
profdata_cmd.add_mock_binary_ids(mocks);
assert_eq!(
profdata_cmd
.find_binaries(
&SymbolIndex {
build_id_dirs: vec![BuildIdDir {
path: test_dir.path().to_str().unwrap().to_string(),
build_dir: None,
}],
includes: Vec::new(),
ids_txts: Vec::new(),
gcs_flat: Vec::new(),
debuginfod: Vec::new(),
},
&[profraw],
)
.unwrap(),
N/A
N/A
{
"command": "ffx coverage",
"options": [
{
"description": "path to ffx test output directory",
"option": "test-output-dir",
"shorthand": "",
"value_type": "string"
},
{
"description": "path to clang directory, llvm-profdata and llvm-cov are expected in clang_dir/bin",
"option": "clang-dir",
N/A
N/A
N/A
{
"command": "ffx coverage",
"options": [
{
"description": "path to ffx test output directory",
"option": "test-output-dir",
"shorthand": "",
"value_type": "string"
},
{
"description": "path to clang directory, llvm-profdata and llvm-cov are expected in clang_dir/bin",
"option": "clang-dir",
N/A
N/A
N/A
{
"command": "ffx coverage",
"options": [
{
"description": "path to ffx test output directory",
"option": "test-output-dir",
"shorthand": "",
"value_type": "string"
},
{
"description": "path to clang directory, llvm-profdata and llvm-cov are expected in clang_dir/bin",
"option": "clang-dir",
N/A
N/A
N/A
{
"command": "ffx coverage",
"options": [
{
"description": "path to ffx test output directory",
"option": "test-output-dir",
"shorthand": "",
"value_type": "string"
},
{
"description": "path to clang directory, llvm-profdata and llvm-cov are expected in clang_dir/bin",
"option": "clang-dir",
N/A
N/A
N/A
{
"command": "ffx coverage",
"options": [
{
"description": "path to ffx test output directory",
"option": "test-output-dir",
"shorthand": "",
"value_type": "string"
},
{
"description": "path to clang directory, llvm-profdata and llvm-cov are expected in clang_dir/bin",
"option": "clang-dir",
N/A
N/A
N/A
{
"command": "ffx coverage",
"options": [
{
"description": "path to ffx test output directory",
"option": "test-output-dir",
"shorthand": "",
"value_type": "string"
},
{
"description": "path to clang directory, llvm-profdata and llvm-cov are expected in clang_dir/bin",
"option": "clang-dir",
N/A
N/A
N/A
{
"command": "ffx coverage",
"options": [
{
"description": "path to ffx test output directory",
"option": "test-output-dir",
"shorthand": "",
"value_type": "string"
},
{
"description": "path to clang directory, llvm-profdata and llvm-cov are expected in clang_dir/bin",
"option": "clang-dir",
N/A
N/A
N/A
{
"command": "ffx coverage",
"options": [
{
"description": "path to ffx test output directory",
"option": "test-output-dir",
"shorthand": "",
"value_type": "string"
},
{
"description": "path to clang directory, llvm-profdata and llvm-cov are expected in clang_dir/bin",
"option": "clang-dir",
N/A
N/A
N/A
{
"command": "ffx coverage",
"options": [
{
"description": "path to ffx test output directory",
"option": "test-output-dir",
"shorthand": "",
"value_type": "string"
},
{
"description": "path to clang directory, llvm-profdata and llvm-cov are expected in clang_dir/bin",
"option": "clang-dir",
N/A
N/A
N/A
{
"command": "ffx daemon",
"options": [],
"short": "Interact with/control the ffx daemon"
}
by the `ffx daemon`. The daemon will eventually be deprecated and removed, however, due to its complexity and statefulness. It is possible, meanwhile, to make a connection without going through the daemon, by passing the `-d`/`--direct` flag, e.g.
#[fuchsia::test]
async fn test_open_rcs_on_fastboot_error() {
let env = ffx_config::test_init().unwrap();
let (_proxy, daemon, _task) = spawn_test_daemon(&env).await;
let target = Target::new_for_usb(&env.context, "abc");
daemon.target_collection.merge_insert(target);
let result = daemon.open_remote_control(None).await;
assert!(result.is_err());
}
#[fuchsia::test]
async fn test_open_rcs_on_zedboot_error() {
let env = ffx_config::test_init().unwrap();
let (_proxy, daemon, _task) = spawn_test_daemon(&env).await;
let target = Target::new_with_netsvc_addrs(
&env.context,
Some("abc"),
BTreeSet::from_iter(
vec![TargetIpAddr::from_str("[fe80::1%1]:22").unwrap()].into_iter(),
),
);
daemon.target_collection.merge_insert(target);
let result = daemon.open_remote_control(None).await;
assert!(result.is_err());
}
#[fuchsia::test]
async fn test_get_target_empty() {
let env = ffx_config::test_init().unwrap();
let tempdir = tempfile::tempdir().expect("Creating tempdir");
let socket_path = tempdir.path().join("ascendd.sock");
let d = Daemon::new(env.context.clone(), socket_path);
let nodename = "where-is-my-hasenpfeffer";
let t = Target::new_autoconnected(&env.context, nodename);
d.target_collection.merge_insert(t.clone());
assert_eq!(nodename, d.get_target(None).await.unwrap().nodename().unwrap());
}
N/A
{
"command": "ffx daemon crash",
"options": [],
"short": "crash the daemon"
}
#[fuchsia::test]
async fn test_crash_with_no_text() {
// XXX(raggi): if we can bound the lifetime of the testing proxy setup as
// desired by the test, then we could avoid the need for the static.
static CRASHED: AtomicBool = AtomicBool::new(false);
let proxy = fake_proxy(|req| match req {
TestingRequest::Crash { .. } => {
CRASHED.store(true, Ordering::SeqCst);
}
_ => assert!(false),
});
let tool = DaemonCrashTool { cmd: CrashCommand {}, testing_proxy: proxy };
let buffers = ffx_writer::TestBuffers::default();
let writer = SimpleWriter::new_test(&buffers);
assert!(tool.main(writer).await.is_ok());
assert!(CRASHED.load(Ordering::SeqCst));
}
N/A
N/A
{
"command": "ffx daemon disconnect",
"options": [],
"short": "Disconnect from a target"
}
#[fuchsia::test]
async fn disconnect_invoked() {
disconnect_impl(&setup_fake_target_server(), DisconnectCommand {})
.await
.expect("disconnect failed");
}
N/A
N/A
{
"command": "ffx daemon echo",
"options": [],
"short": "run echo test against the daemon"
}
#[fuchsia::test]
async fn test_echo_with_no_text() -> Result<()> {
let output = run_echo_test(EchoCommand { text: None }).await;
assert_eq!("SUCCESS: received \"Ffx\"\n".to_string(), output);
Ok(())
}
#[fuchsia::test]
async fn test_echo_with_text() -> Result<()> {
let output = run_echo_test(EchoCommand { text: Some("test".to_string()) }).await;
assert_eq!("SUCCESS: received \"test\"\n".to_string(), output);
Ok(())
}
#[fuchsia::test]
async fn test_echo_with_text_machine() {
let echo_proxy = setup_fake_echo_proxy();
let tool = EchoTool { cmd: EchoCommand { text: Some("test".to_string()) }, echo_proxy };
let buffers = TestBuffers::default();
let writer = <EchoTool as FfxMain>::Writer::new_test(Some(Format::Json), &buffers);
let result = tool.main(writer).await;
assert!(result.is_ok());
let output = buffers.into_stdout_str();
let err = format!("schema not valid {output}");
let json = serde_json::from_str(&output).expect(&err);
let err = format!("json must adhere to schema: {json}");
<EchoTool as FfxMain>::Writer::verify_schema(&json).expect(&err);
let want = EchoResult::Ok("SUCCESS: received \"test\"".into());
assert_eq!(json, json!(want))
}
N/A
N/A
{
"command": "ffx daemon hang",
"options": [],
"short": "hang the daemon"
}
#[fuchsia::test]
async fn test_hang_with_no_text() {
static HUNG: AtomicBool = AtomicBool::new(false);
let proxy = fake_proxy(|req| match req {
TestingRequest::Hang { .. } => {
HUNG.store(true, Ordering::SeqCst);
}
_ => assert!(false),
});
let tool = DaemonHangTool { cmd: HangCommand {}, testing_proxy: proxy };
let buffers = ffx_writer::TestBuffers::default();
let writer = SimpleWriter::new_test(&buffers);
assert!(tool.main(writer).await.is_ok());
assert!(HUNG.load(Ordering::SeqCst));
}
N/A
N/A
{
"command": "ffx daemon log",
"options": [
{
"description": "print appended logs as they happen",
"option": "follow",
"shorthand": "f",
"value_type": "bool"
},
{
"description": "display most recent log lines.",
"option": "line-count",
#[test]
fn display_x_most_recent_from_many_logs() {
let mut tmp = tempfile::NamedTempFile::new().unwrap();
write_log(&mut tmp, 1..20);
let mut log_file = LogFile::new(tmp.path());
let mut actual = vec![];
log_file.write_all_tail(&mut actual, 10).unwrap();
let mut expected = vec![];
write_log(&mut expected, 10..20);
assert_eq!(std::str::from_utf8(&actual).unwrap(), std::str::from_utf8(&expected).unwrap());
}
#[test]
fn display_0_most_recent_from_many_logs() {
let mut tmp = tempfile::NamedTempFile::new().unwrap();
write_log(&mut tmp, 1..20);
let mut log_file = LogFile::new(tmp.path());
let mut actual = vec![];
log_file.write_all_tail(&mut actual, 0).unwrap();
assert_eq!(std::str::from_utf8(&actual).unwrap(), "");
}
#[fuchsia::test]
async fn display_x_most_recent_from_not_enough_logs() {
let mut tmp = tempfile::NamedTempFile::new().unwrap();
write_log(&mut tmp, 1..5);
let mut log_file = LogFile::new(tmp.path());
let mut actual = vec![];
log_file.write_all_tail(&mut actual, 10).unwrap();
let mut expected = vec![];
write_log(&mut expected, 1..5);
assert_eq!(std::str::from_utf8(&actual).unwrap(), std::str::from_utf8(&expected).unwrap());
}
N/A
N/A
{
"command": "ffx daemon log",
"options": [
{
"description": "print appended logs as they happen",
"option": "follow",
"shorthand": "f",
"value_type": "bool"
},
{
"description": "display most recent log lines.",
"option": "line-count",
N/A
N/A
N/A
{
"command": "ffx daemon log",
"options": [
{
"description": "print appended logs as they happen",
"option": "follow",
"shorthand": "f",
"value_type": "bool"
},
{
"description": "display most recent log lines.",
"option": "line-count",
N/A
N/A
N/A
{
"command": "ffx daemon socket",
"options": [],
"short": "query information about the daemon socket without connecting to it"
}
// Copyright 2021 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use crate::assert_eq;
use crate::test::new_isolate;
use anyhow::*;
use ffx_config::EnvironmentContext;
use fuchsia_async::MonotonicDuration;
use nix::sys::signal;
use nix::unistd::Pid;
use std::path::PathBuf;
use std::thread::sleep;
use std::time::Duration as StdDuration;
pub(crate) async fn test_echo(context: EnvironmentContext) -> Result<()> {
let isolate = new_isolate(&context, "daemon-echo").await?;
isolate.start_daemon().await?;
let out = isolate.ffx(&["daemon", "echo"]).await?;
let want = "SUCCESS: received \"Ffx\"\n";
assert_eq!(out.stdout, want);
Ok(())
}
N/A
N/A
{
"command": "ffx daemon start",
"options": [
{
"description": "override the path the socket will be bound to",
"option": "path",
"shorthand": "",
"value_type": "string"
},
{
"description": "runs the daemon in the background. Returns after verifying daemon connection. No-op if the daemon is already running.",
"option": "background",
NOTE: Running `ffx daemon start` directly will not start a functional daemon.
#[fuchsia::test]
async fn test_background_start_succeeds() {
let config_env = ffx_config::test_init().unwrap();
let cmd = StartCommand { path: None, background: true };
let fho_env = create_fake_injector_with_result(&config_env.context, true).await;
let tool = DaemonStartTool { cmd, fho_env };
let test_buffers = ffx_writer::TestBuffers::default();
let writer = ffx_writer::SimpleWriter::new_test(&test_buffers);
tool.main(writer).await.unwrap();
}
#[fuchsia::test]
async fn test_background_start_fails() {
let config_env = ffx_config::test_init().unwrap();
let cmd = StartCommand { path: None, background: true };
let fho_env = create_fake_injector_with_result(&config_env.context, false).await;
let tool = DaemonStartTool { cmd, fho_env };
let test_buffers = ffx_writer::TestBuffers::default();
let writer = ffx_writer::SimpleWriter::new_test(&test_buffers);
tool.main(writer).await.unwrap_err();
}
N/A
{
"command": "ffx daemon start",
"options": [
{
"description": "override the path the socket will be bound to",
"option": "path",
"shorthand": "",
"value_type": "string"
},
{
"description": "runs the daemon in the background. Returns after verifying daemon connection. No-op if the daemon is already running.",
"option": "background",
N/A
N/A
N/A
{
"command": "ffx daemon start",
"options": [
{
"description": "override the path the socket will be bound to",
"option": "path",
"shorthand": "",
"value_type": "string"
},
{
"description": "runs the daemon in the background. Returns after verifying daemon connection. No-op if the daemon is already running.",
"option": "background",
N/A
N/A
N/A
{
"command": "ffx daemon stop",
"options": [
{
"description": "wait indefinitely for the daemon to stop before exiting (should not be used in automated systems)",
"option": "wait",
"shorthand": "w",
"value_type": "bool"
},
{
"description": "do not wait for daemon to stop (default behavior -- eventually to be deprecated)",
"option": "no-wait",
the directory shuts down the daemon; `ffx daemon stop` is recommended but not required. Killing the daemon process is not recommended as it may leave out information in the log file.
#[fuchsia::test]
async fn run_stop_test() {
let config_env = ffx_config::test_init().unwrap();
let buffers = TestBuffers::default();
let writer = <StopTool as FfxMain>::Writer::new_test(None, &buffers);
let tool = StopTool {
cmd: StopCommand { wait: false, no_wait: true, timeout_ms: None },
daemon_proxy: Ok(setup_fake_daemon_server().into()),
context: config_env.context.clone(),
};
let result = tool.main(writer).await;
assert!(result.is_ok());
let output = buffers.into_stdout_str();
assert!(output.ends_with("Stopped daemon.\n"), "Missing magic phrase in {output}");
}
#[fuchsia::test]
async fn run_stop_test_machine() {
let config_env = ffx_config::test_init().unwrap();
let test_stdout = TestBuffer::default();
let writer = <StopTool as FfxMain>::Writer::new_buffers(
Some(Format::Json),
test_stdout.clone(),
Vec::new(),
);
let tool = StopTool {
cmd: StopCommand { wait: false, no_wait: true, timeout_ms: None },
daemon_proxy: Ok(setup_fake_daemon_server().into()),
context: config_env.context.clone(),
};
let result = tool.main(writer).await;
assert!(result.is_ok());
let output = test_stdout.into_string();
let err = format!("schema not valid {output}");
let json = serde_json::from_str(&output).expect(&err);
let err = format!("json must adhere to schema: {json}");
<StopTool as FfxMain>::Writer::verify_schema(&json).expect(&err);
let want = CommandStatus::Ok { message: None };
assert_eq!(json, json!(want));
}
// Copyright 2021 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use crate::assert_eq;
use crate::test::new_isolate;
use anyhow::*;
use ffx_config::EnvironmentContext;
use fuchsia_async::MonotonicDuration;
use nix::sys::signal;
use nix::unistd::Pid;
use std::path::PathBuf;
use std::thread::sleep;
use std::time::Duration as StdDuration;
pub(crate) async fn test_echo(context: EnvironmentContext) -> Result<()> {
let isolate = new_isolate(&context, "daemon-echo").await?;
isolate.start_daemon().await?;
let out = isolate.ffx(&["daemon", "echo"]).await?;
let want = "SUCCESS: received \"Ffx\"\n";
assert_eq!(out.stdout, want);
Ok(())
}
N/A
N/A
{
"command": "ffx daemon stop",
"options": [
{
"description": "wait indefinitely for the daemon to stop before exiting (should not be used in automated systems)",
"option": "wait",
"shorthand": "w",
"value_type": "bool"
},
{
"description": "do not wait for daemon to stop (default behavior -- eventually to be deprecated)",
"option": "no-wait",
N/A
N/A
N/A
{
"command": "ffx daemon stop",
"options": [
{
"description": "wait indefinitely for the daemon to stop before exiting (should not be used in automated systems)",
"option": "wait",
"shorthand": "w",
"value_type": "bool"
},
{
"description": "do not wait for daemon to stop (default behavior -- eventually to be deprecated)",
"option": "no-wait",
N/A
N/A
N/A
{
"command": "ffx daemon stop",
"options": [
{
"description": "wait indefinitely for the daemon to stop before exiting (should not be used in automated systems)",
"option": "wait",
"shorthand": "w",
"value_type": "bool"
},
{
"description": "do not wait for daemon to stop (default behavior -- eventually to be deprecated)",
"option": "no-wait",
N/A
N/A
N/A
{
"command": "ffx debug",
"options": [],
"short": "Start a debugging session."
}
// Copyright 2023 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use anyhow::{Context as _, ensure};
N/A
N/A
{
"command": "ffx debug connect",
"options": [
{
"description": "start zxdb in another debugger. Currently, the only valid option is \"lldb\".",
"option": "debugger",
"shorthand": "",
"value_type": "string"
},
{
"description": "only start the debug agent but not the zxdb. The path to the UNIX socket will be printed and can be connected via \"connect -u\" in zxdb shell.",
"option": "agent-only",
N/A
N/A
N/A
{
"command": "ffx debug connect",
"options": [
{
"description": "start zxdb in another debugger. Currently, the only valid option is \"lldb\".",
"option": "debugger",
"shorthand": "",
"value_type": "string"
},
{
"description": "only start the debug agent but not the zxdb. The path to the UNIX socket will be printed and can be connected via \"connect -u\" in zxdb shell.",
"option": "agent-only",
N/A
N/A
N/A
{
"command": "ffx debug connect",
"options": [
{
"description": "start zxdb in another debugger. Currently, the only valid option is \"lldb\".",
"option": "debugger",
"shorthand": "",
"value_type": "string"
},
{
"description": "only start the debug agent but not the zxdb. The path to the UNIX socket will be printed and can be connected via \"connect -u\" in zxdb shell.",
"option": "agent-only",
N/A
N/A
N/A
{
"command": "ffx debug connect",
"options": [
{
"description": "start zxdb in another debugger. Currently, the only valid option is \"lldb\".",
"option": "debugger",
"shorthand": "",
"value_type": "string"
},
{
"description": "only start the debug agent but not the zxdb. The path to the UNIX socket will be printed and can be connected via \"connect -u\" in zxdb shell.",
"option": "agent-only",
N/A
N/A
N/A
{
"command": "ffx debug connect",
"options": [
{
"description": "start zxdb in another debugger. Currently, the only valid option is \"lldb\".",
"option": "debugger",
"shorthand": "",
"value_type": "string"
},
{
"description": "only start the debug agent but not the zxdb. The path to the UNIX socket will be printed and can be connected via \"connect -u\" in zxdb shell.",
"option": "agent-only",
N/A
N/A
N/A
{
"command": "ffx debug connect",
"options": [
{
"description": "start zxdb in another debugger. Currently, the only valid option is \"lldb\".",
"option": "debugger",
"shorthand": "",
"value_type": "string"
},
{
"description": "only start the debug agent but not the zxdb. The path to the UNIX socket will be printed and can be connected via \"connect -u\" in zxdb shell.",
"option": "agent-only",
N/A
N/A
N/A
{
"command": "ffx debug core",
"options": [
{
"description": "extra arguments passed to zxdb.",
"option": "zxdb-args",
"shorthand": "",
"value_type": "string"
}
],
"short": "start the debugger and open a minidump"
}
N/A
N/A
N/A
{
"command": "ffx debug core",
"options": [
{
"description": "extra arguments passed to zxdb.",
"option": "zxdb-args",
"shorthand": "",
"value_type": "string"
}
],
"short": "start the debugger and open a minidump"
}
N/A
N/A
N/A
{
"command": "ffx debug crash",
"options": [],
"short": "catch a crashing process on the target"
}
N/A
N/A
N/A
{
"command": "ffx debug fidl",
"options": [
{
"description": "specifies the source. Source can be: device: this is the default input. The input comes from the live monitoring of one or several processes. At least one of '--remote-pid', '--remote-name', '--remote-job-id', --'remote-job-name', 'run' must be specified. dump: The input comes from stdin which is the log output of one or several programs. The lines in the log which dump syscalls are decoded and replaced by the decoded version. All other lines are unchanged. <path>: playback. Used to replay a session previously recorded with --to <path> (protobuf format). Path gives the name of the file to read. If path is '-' then the standard input is used. This option must be used at most once.",
"option": "from",
"shorthand": "",
"value_type": "string"
},
{
"description": "the session is saved to the specified file (binary protobuf format). When a session is saved, you can replay it using \"--from <path>\". The raw data is saved. That means that the data saved is independent from what is displayed.",
"option": "to",
N/A
N/A
N/A
{
"command": "ffx debug fidl",
"options": [
{
"description": "specifies the source. Source can be: device: this is the default input. The input comes from the live monitoring of one or several processes. At least one of '--remote-pid', '--remote-name', '--remote-job-id', --'remote-job-name', 'run' must be specified. dump: The input comes from stdin which is the log output of one or several programs. The lines in the log which dump syscalls are decoded and replaced by the decoded version. All other lines are unchanged. <path>: playback. Used to replay a session previously recorded with --to <path> (protobuf format). Path gives the name of the file to read. If path is '-' then the standard input is used. This option must be used at most once.",
"option": "from",
"shorthand": "",
"value_type": "string"
},
{
"description": "the session is saved to the specified file (binary protobuf format). When a session is saved, you can replay it using \"--from <path>\". The raw data is saved. That means that the data saved is independent from what is displayed.",
"option": "to",
N/A
N/A
N/A
{
"command": "ffx debug fidl",
"options": [
{
"description": "specifies the source. Source can be: device: this is the default input. The input comes from the live monitoring of one or several processes. At least one of '--remote-pid', '--remote-name', '--remote-job-id', --'remote-job-name', 'run' must be specified. dump: The input comes from stdin which is the log output of one or several programs. The lines in the log which dump syscalls are decoded and replaced by the decoded version. All other lines are unchanged. <path>: playback. Used to replay a session previously recorded with --to <path> (protobuf format). Path gives the name of the file to read. If path is '-' then the standard input is used. This option must be used at most once.",
"option": "from",
"shorthand": "",
"value_type": "string"
},
{
"description": "the session is saved to the specified file (binary protobuf format). When a session is saved, you can replay it using \"--from <path>\". The raw data is saved. That means that the data saved is independent from what is displayed.",
"option": "to",
N/A
N/A
N/A
{
"command": "ffx debug fidl",
"options": [
{
"description": "specifies the source. Source can be: device: this is the default input. The input comes from the live monitoring of one or several processes. At least one of '--remote-pid', '--remote-name', '--remote-job-id', --'remote-job-name', 'run' must be specified. dump: The input comes from stdin which is the log output of one or several programs. The lines in the log which dump syscalls are decoded and replaced by the decoded version. All other lines are unchanged. <path>: playback. Used to replay a session previously recorded with --to <path> (protobuf format). Path gives the name of the file to read. If path is '-' then the standard input is used. This option must be used at most once.",
"option": "from",
"shorthand": "",
"value_type": "string"
},
{
"description": "the session is saved to the specified file (binary protobuf format). When a session is saved, you can replay it using \"--from <path>\". The raw data is saved. That means that the data saved is independent from what is displayed.",
"option": "to",
N/A
N/A
N/A
{
"command": "ffx debug fidl",
"options": [
{
"description": "specifies the source. Source can be: device: this is the default input. The input comes from the live monitoring of one or several processes. At least one of '--remote-pid', '--remote-name', '--remote-job-id', --'remote-job-name', 'run' must be specified. dump: The input comes from stdin which is the log output of one or several programs. The lines in the log which dump syscalls are decoded and replaced by the decoded version. All other lines are unchanged. <path>: playback. Used to replay a session previously recorded with --to <path> (protobuf format). Path gives the name of the file to read. If path is '-' then the standard input is used. This option must be used at most once.",
"option": "from",
"shorthand": "",
"value_type": "string"
},
{
"description": "the session is saved to the specified file (binary protobuf format). When a session is saved, you can replay it using \"--from <path>\". The raw data is saved. That means that the data saved is independent from what is displayed.",
"option": "to",
N/A
N/A
N/A
{
"command": "ffx debug fidl",
"options": [
{
"description": "specifies the source. Source can be: device: this is the default input. The input comes from the live monitoring of one or several processes. At least one of '--remote-pid', '--remote-name', '--remote-job-id', --'remote-job-name', 'run' must be specified. dump: The input comes from stdin which is the log output of one or several programs. The lines in the log which dump syscalls are decoded and replaced by the decoded version. All other lines are unchanged. <path>: playback. Used to replay a session previously recorded with --to <path> (protobuf format). Path gives the name of the file to read. If path is '-' then the standard input is used. This option must be used at most once.",
"option": "from",
"shorthand": "",
"value_type": "string"
},
{
"description": "the session is saved to the specified file (binary protobuf format). When a session is saved, you can replay it using \"--from <path>\". The raw data is saved. That means that the data saved is independent from what is displayed.",
"option": "to",
N/A
N/A
N/A
{
"command": "ffx debug fidl",
"options": [
{
"description": "specifies the source. Source can be: device: this is the default input. The input comes from the live monitoring of one or several processes. At least one of '--remote-pid', '--remote-name', '--remote-job-id', --'remote-job-name', 'run' must be specified. dump: The input comes from stdin which is the log output of one or several programs. The lines in the log which dump syscalls are decoded and replaced by the decoded version. All other lines are unchanged. <path>: playback. Used to replay a session previously recorded with --to <path> (protobuf format). Path gives the name of the file to read. If path is '-' then the standard input is used. This option must be used at most once.",
"option": "from",
"shorthand": "",
"value_type": "string"
},
{
"description": "the session is saved to the specified file (binary protobuf format). When a session is saved, you can replay it using \"--from <path>\". The raw data is saved. That means that the data saved is independent from what is displayed.",
"option": "to",
N/A
N/A
N/A
{
"command": "ffx debug fidl",
"options": [
{
"description": "specifies the source. Source can be: device: this is the default input. The input comes from the live monitoring of one or several processes. At least one of '--remote-pid', '--remote-name', '--remote-job-id', --'remote-job-name', 'run' must be specified. dump: The input comes from stdin which is the log output of one or several programs. The lines in the log which dump syscalls are decoded and replaced by the decoded version. All other lines are unchanged. <path>: playback. Used to replay a session previously recorded with --to <path> (protobuf format). Path gives the name of the file to read. If path is '-' then the standard input is used. This option must be used at most once.",
"option": "from",
"shorthand": "",
"value_type": "string"
},
{
"description": "the session is saved to the specified file (binary protobuf format). When a session is saved, you can replay it using \"--from <path>\". The raw data is saved. That means that the data saved is independent from what is displayed.",
"option": "to",
N/A
N/A
N/A
{
"command": "ffx debug fidl",
"options": [
{
"description": "specifies the source. Source can be: device: this is the default input. The input comes from the live monitoring of one or several processes. At least one of '--remote-pid', '--remote-name', '--remote-job-id', --'remote-job-name', 'run' must be specified. dump: The input comes from stdin which is the log output of one or several programs. The lines in the log which dump syscalls are decoded and replaced by the decoded version. All other lines are unchanged. <path>: playback. Used to replay a session previously recorded with --to <path> (protobuf format). Path gives the name of the file to read. If path is '-' then the standard input is used. This option must be used at most once.",
"option": "from",
"shorthand": "",
"value_type": "string"
},
{
"description": "the session is saved to the specified file (binary protobuf format). When a session is saved, you can replay it using \"--from <path>\". The raw data is saved. That means that the data saved is independent from what is displayed.",
"option": "to",
N/A
N/A
N/A
{
"command": "ffx debug fidl",
"options": [
{
"description": "specifies the source. Source can be: device: this is the default input. The input comes from the live monitoring of one or several processes. At least one of '--remote-pid', '--remote-name', '--remote-job-id', --'remote-job-name', 'run' must be specified. dump: The input comes from stdin which is the log output of one or several programs. The lines in the log which dump syscalls are decoded and replaced by the decoded version. All other lines are unchanged. <path>: playback. Used to replay a session previously recorded with --to <path> (protobuf format). Path gives the name of the file to read. If path is '-' then the standard input is used. This option must be used at most once.",
"option": "from",
"shorthand": "",
"value_type": "string"
},
{
"description": "the session is saved to the specified file (binary protobuf format). When a session is saved, you can replay it using \"--from <path>\". The raw data is saved. That means that the data saved is independent from what is displayed.",
"option": "to",
N/A
N/A
N/A
{
"command": "ffx debug fidl",
"options": [
{
"description": "specifies the source. Source can be: device: this is the default input. The input comes from the live monitoring of one or several processes. At least one of '--remote-pid', '--remote-name', '--remote-job-id', --'remote-job-name', 'run' must be specified. dump: The input comes from stdin which is the log output of one or several programs. The lines in the log which dump syscalls are decoded and replaced by the decoded version. All other lines are unchanged. <path>: playback. Used to replay a session previously recorded with --to <path> (protobuf format). Path gives the name of the file to read. If path is '-' then the standard input is used. This option must be used at most once.",
"option": "from",
"shorthand": "",
"value_type": "string"
},
{
"description": "the session is saved to the specified file (binary protobuf format). When a session is saved, you can replay it using \"--from <path>\". The raw data is saved. That means that the data saved is independent from what is displayed.",
"option": "to",
N/A
N/A
N/A
{
"command": "ffx debug fidl",
"options": [
{
"description": "specifies the source. Source can be: device: this is the default input. The input comes from the live monitoring of one or several processes. At least one of '--remote-pid', '--remote-name', '--remote-job-id', --'remote-job-name', 'run' must be specified. dump: The input comes from stdin which is the log output of one or several programs. The lines in the log which dump syscalls are decoded and replaced by the decoded version. All other lines are unchanged. <path>: playback. Used to replay a session previously recorded with --to <path> (protobuf format). Path gives the name of the file to read. If path is '-' then the standard input is used. This option must be used at most once.",
"option": "from",
"shorthand": "",
"value_type": "string"
},
{
"description": "the session is saved to the specified file (binary protobuf format). When a session is saved, you can replay it using \"--from <path>\". The raw data is saved. That means that the data saved is independent from what is displayed.",
"option": "to",
N/A
N/A
N/A
{
"command": "ffx debug fidl",
"options": [
{
"description": "specifies the source. Source can be: device: this is the default input. The input comes from the live monitoring of one or several processes. At least one of '--remote-pid', '--remote-name', '--remote-job-id', --'remote-job-name', 'run' must be specified. dump: The input comes from stdin which is the log output of one or several programs. The lines in the log which dump syscalls are decoded and replaced by the decoded version. All other lines are unchanged. <path>: playback. Used to replay a session previously recorded with --to <path> (protobuf format). Path gives the name of the file to read. If path is '-' then the standard input is used. This option must be used at most once.",
"option": "from",
"shorthand": "",
"value_type": "string"
},
{
"description": "the session is saved to the specified file (binary protobuf format). When a session is saved, you can replay it using \"--from <path>\". The raw data is saved. That means that the data saved is independent from what is displayed.",
"option": "to",
N/A
N/A
N/A
{
"command": "ffx debug fidl",
"options": [
{
"description": "specifies the source. Source can be: device: this is the default input. The input comes from the live monitoring of one or several processes. At least one of '--remote-pid', '--remote-name', '--remote-job-id', --'remote-job-name', 'run' must be specified. dump: The input comes from stdin which is the log output of one or several programs. The lines in the log which dump syscalls are decoded and replaced by the decoded version. All other lines are unchanged. <path>: playback. Used to replay a session previously recorded with --to <path> (protobuf format). Path gives the name of the file to read. If path is '-' then the standard input is used. This option must be used at most once.",
"option": "from",
"shorthand": "",
"value_type": "string"
},
{
"description": "the session is saved to the specified file (binary protobuf format). When a session is saved, you can replay it using \"--from <path>\". The raw data is saved. That means that the data saved is independent from what is displayed.",
"option": "to",
N/A
N/A
N/A
{
"command": "ffx debug fidl",
"options": [
{
"description": "specifies the source. Source can be: device: this is the default input. The input comes from the live monitoring of one or several processes. At least one of '--remote-pid', '--remote-name', '--remote-job-id', --'remote-job-name', 'run' must be specified. dump: The input comes from stdin which is the log output of one or several programs. The lines in the log which dump syscalls are decoded and replaced by the decoded version. All other lines are unchanged. <path>: playback. Used to replay a session previously recorded with --to <path> (protobuf format). Path gives the name of the file to read. If path is '-' then the standard input is used. This option must be used at most once.",
"option": "from",
"shorthand": "",
"value_type": "string"
},
{
"description": "the session is saved to the specified file (binary protobuf format). When a session is saved, you can replay it using \"--from <path>\". The raw data is saved. That means that the data saved is independent from what is displayed.",
"option": "to",
N/A
N/A
N/A
{
"command": "ffx debug fidl",
"options": [
{
"description": "specifies the source. Source can be: device: this is the default input. The input comes from the live monitoring of one or several processes. At least one of '--remote-pid', '--remote-name', '--remote-job-id', --'remote-job-name', 'run' must be specified. dump: The input comes from stdin which is the log output of one or several programs. The lines in the log which dump syscalls are decoded and replaced by the decoded version. All other lines are unchanged. <path>: playback. Used to replay a session previously recorded with --to <path> (protobuf format). Path gives the name of the file to read. If path is '-' then the standard input is used. This option must be used at most once.",
"option": "from",
"shorthand": "",
"value_type": "string"
},
{
"description": "the session is saved to the specified file (binary protobuf format). When a session is saved, you can replay it using \"--from <path>\". The raw data is saved. That means that the data saved is independent from what is displayed.",
"option": "to",
N/A
N/A
N/A
{
"command": "ffx debug fidl",
"options": [
{
"description": "specifies the source. Source can be: device: this is the default input. The input comes from the live monitoring of one or several processes. At least one of '--remote-pid', '--remote-name', '--remote-job-id', --'remote-job-name', 'run' must be specified. dump: The input comes from stdin which is the log output of one or several programs. The lines in the log which dump syscalls are decoded and replaced by the decoded version. All other lines are unchanged. <path>: playback. Used to replay a session previously recorded with --to <path> (protobuf format). Path gives the name of the file to read. If path is '-' then the standard input is used. This option must be used at most once.",
"option": "from",
"shorthand": "",
"value_type": "string"
},
{
"description": "the session is saved to the specified file (binary protobuf format). When a session is saved, you can replay it using \"--from <path>\". The raw data is saved. That means that the data saved is independent from what is displayed.",
"option": "to",
N/A
N/A
N/A
{
"command": "ffx debug fidl",
"options": [
{
"description": "specifies the source. Source can be: device: this is the default input. The input comes from the live monitoring of one or several processes. At least one of '--remote-pid', '--remote-name', '--remote-job-id', --'remote-job-name', 'run' must be specified. dump: The input comes from stdin which is the log output of one or several programs. The lines in the log which dump syscalls are decoded and replaced by the decoded version. All other lines are unchanged. <path>: playback. Used to replay a session previously recorded with --to <path> (protobuf format). Path gives the name of the file to read. If path is '-' then the standard input is used. This option must be used at most once.",
"option": "from",
"shorthand": "",
"value_type": "string"
},
{
"description": "the session is saved to the specified file (binary protobuf format). When a session is saved, you can replay it using \"--from <path>\". The raw data is saved. That means that the data saved is independent from what is displayed.",
"option": "to",
N/A
N/A
N/A
{
"command": "ffx debug fidl",
"options": [
{
"description": "specifies the source. Source can be: device: this is the default input. The input comes from the live monitoring of one or several processes. At least one of '--remote-pid', '--remote-name', '--remote-job-id', --'remote-job-name', 'run' must be specified. dump: The input comes from stdin which is the log output of one or several programs. The lines in the log which dump syscalls are decoded and replaced by the decoded version. All other lines are unchanged. <path>: playback. Used to replay a session previously recorded with --to <path> (protobuf format). Path gives the name of the file to read. If path is '-' then the standard input is used. This option must be used at most once.",
"option": "from",
"shorthand": "",
"value_type": "string"
},
{
"description": "the session is saved to the specified file (binary protobuf format). When a session is saved, you can replay it using \"--from <path>\". The raw data is saved. That means that the data saved is independent from what is displayed.",
"option": "to",
N/A
N/A
N/A
{
"command": "ffx debug fidl",
"options": [
{
"description": "specifies the source. Source can be: device: this is the default input. The input comes from the live monitoring of one or several processes. At least one of '--remote-pid', '--remote-name', '--remote-job-id', --'remote-job-name', 'run' must be specified. dump: The input comes from stdin which is the log output of one or several programs. The lines in the log which dump syscalls are decoded and replaced by the decoded version. All other lines are unchanged. <path>: playback. Used to replay a session previously recorded with --to <path> (protobuf format). Path gives the name of the file to read. If path is '-' then the standard input is used. This option must be used at most once.",
"option": "from",
"shorthand": "",
"value_type": "string"
},
{
"description": "the session is saved to the specified file (binary protobuf format). When a session is saved, you can replay it using \"--from <path>\". The raw data is saved. That means that the data saved is independent from what is displayed.",
"option": "to",
N/A
N/A
N/A
{
"command": "ffx debug fidl",
"options": [
{
"description": "specifies the source. Source can be: device: this is the default input. The input comes from the live monitoring of one or several processes. At least one of '--remote-pid', '--remote-name', '--remote-job-id', --'remote-job-name', 'run' must be specified. dump: The input comes from stdin which is the log output of one or several programs. The lines in the log which dump syscalls are decoded and replaced by the decoded version. All other lines are unchanged. <path>: playback. Used to replay a session previously recorded with --to <path> (protobuf format). Path gives the name of the file to read. If path is '-' then the standard input is used. This option must be used at most once.",
"option": "from",
"shorthand": "",
"value_type": "string"
},
{
"description": "the session is saved to the specified file (binary protobuf format). When a session is saved, you can replay it using \"--from <path>\". The raw data is saved. That means that the data saved is independent from what is displayed.",
"option": "to",
N/A
N/A
N/A
{
"command": "ffx debug limbo",
"options": [],
"short": "control the process limbo on the target"
}
N/A
N/A
N/A
{
"command": "ffx debug limbo disable",
"options": [],
"short": "disable the process limbo. Will free any pending processes waiting in it."
}
N/A
N/A
N/A
{
"command": "ffx debug limbo enable",
"options": [],
"short": "enable the process limbo. It will now begin to capture crashing processes."
}
N/A
N/A
N/A
{
"command": "ffx debug limbo list",
"options": [],
"short": "lists the processes currently waiting on limbo. The limbo must be active."
}
N/A
N/A
N/A
{
"command": "ffx debug limbo release",
"options": [],
"short": "release a process from limbo. The limbo must be active."
}
N/A
N/A
N/A
{
"command": "ffx debug limbo status",
"options": [],
"short": "query the status of the process limbo."
}
N/A
N/A
N/A
{
"command": "ffx debug symbol-index",
"options": [],
"short": "manage symbol sources used by other debug commands"
}
// Copyright 2023 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use anyhow::{Context as _, ensure};
#[fuchsia::test]
async fn test_list_no_aggregate() {
let cmd = SymbolIndexCommand {
sub_command: SymbolIndexSubCommand::List(ListCommand { aggregated: false }),
};
let path = SymbolIndexPath { inner: LIST_RESULT_MAIN_PATH.to_owned() };
let tool = SymbolIndexTool { cmd, path };
let machine_buffers = TestBuffers::default();
let machine_writer =
VerifiedMachineWriter::<CommandStatus>::new_test(Some(Format::Json), &machine_buffers);
tool.main(machine_writer).await.expect("command success");
let (stdout, _stderr) = machine_buffers.into_strings();
let data: CommandStatus = serde_json::from_str(&stdout).unwrap();
let list_result = data.index().expect("data index");
let output = serde_json::to_string_pretty(&list_result).unwrap();
let expected_idx = SymbolIndex::load(LIST_RESULT_MAIN_PATH).unwrap();
let expected_out = serde_json::to_string_pretty(&expected_idx).unwrap();
assert_eq!(expected_out, output);
}
#[fuchsia::test]
async fn test_list_aggregate() {
let cmd = SymbolIndexCommand {
sub_command: SymbolIndexSubCommand::List(ListCommand { aggregated: true }),
};
let path = SymbolIndexPath { inner: LIST_RESULT_MAIN_PATH.to_owned() };
let tool = SymbolIndexTool { cmd, path };
let machine_buffers = TestBuffers::default();
let machine_writer =
VerifiedMachineWriter::<CommandStatus>::new_test(Some(Format::Json), &machine_buffers);
tool.main(machine_writer).await.expect("command success");
let (stdout, _stderr) = machine_buffers.into_strings();
let data: CommandStatus = serde_json::from_str(&stdout).unwrap();
let list_result = data.index().expect("data index");
let output = serde_json::to_string_pretty(&list_result).unwrap();
let expected_idx = SymbolIndex::load_aggregate(LIST_RESULT_MAIN_PATH).unwrap();
let expected_out = serde_json::to_string_pretty(&expected_idx).unwrap();
assert_eq!(expected_out, output);
}
N/A
N/A
{
"command": "ffx debug symbol-index add",
"options": [
{
"description": "optional build directory used by zxdb to locate the source code",
"option": "build-dir",
"shorthand": "",
"value_type": "string"
}
],
"short": "add a path or url to the symbol index"
}
// Copyright 2023 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use anyhow::{Context as _, ensure};
N/A
N/A
{
"command": "ffx debug symbol-index add",
"options": [
{
"description": "optional build directory used by zxdb to locate the source code",
"option": "build-dir",
"shorthand": "",
"value_type": "string"
}
],
"short": "add a path or url to the symbol index"
}
N/A
N/A
N/A
{
"command": "ffx debug symbol-index clean",
"options": [],
"short": "remove all non-existent paths"
}
N/A
N/A
N/A
{
"command": "ffx debug symbol-index list",
"options": [
{
"description": "show the aggregated symbol index",
"option": "aggregated",
"shorthand": "a",
"value_type": "bool"
}
],
"short": "show the content in symbol index"
}
N/A
N/A
N/A
{
"command": "ffx debug symbol-index list",
"options": [
{
"description": "show the aggregated symbol index",
"option": "aggregated",
"shorthand": "a",
"value_type": "bool"
}
],
"short": "show the content in symbol index"
}
N/A
N/A
N/A
{
"command": "ffx debug symbol-index remove",
"options": [],
"short": "remove a path from the symbol index"
}
N/A
N/A
N/A
{
"command": "ffx debug symbolize",
"options": [
{
"description": "start the authentication process.",
"option": "auth",
"shorthand": "",
"value_type": "bool"
},
{
"description": "do not prettify the backtraces.",
"option": "no-prettify",
N/A
N/A
N/A
{
"command": "ffx debug symbolize",
"options": [
{
"description": "start the authentication process.",
"option": "auth",
"shorthand": "",
"value_type": "bool"
},
{
"description": "do not prettify the backtraces.",
"option": "no-prettify",
N/A
N/A
N/A
{
"command": "ffx debug symbolize",
"options": [
{
"description": "start the authentication process.",
"option": "auth",
"shorthand": "",
"value_type": "bool"
},
{
"description": "do not prettify the backtraces.",
"option": "no-prettify",
N/A
N/A
N/A
{
"command": "ffx doctor",
"options": [
{
"description": "generates an output zip file with logs",
"option": "record",
"shorthand": "",
"value_type": "bool"
},
{
"description": "do not include the ffx configuration file",
"option": "no-config",
#[fuchsia::test]
async fn test_single_try_no_daemon_running_no_targets_with_default_target() {
let test_env = ffx_config::test_env().build().unwrap();
setup_ssh_keys(&test_env).await.expect("setting up ssh test keys");
setup_emu_dir(&test_env).expect("setting up emulator data");
setup_driver_socket_file(&test_env).await.expect("setting up fake driver socket file");
let fake = FakeDaemonManager::new(
vec![false],
vec![Ok(false)],
vec![Ok(())],
vec![Ok(setup_responsive_daemon_server())],
vec![],
);
let mut handler = FakeStepHandler::new();
let ledger_view = Box::new(FakeLedgerView::new());
let mut ledger = DoctorLedger::<MockWriter>::new(
MockWriter::new(),
ledger_view,
LedgerViewMode::Verbose,
);
let mock_driver_finder = default_mock_driver_finder();
doctor(
&mut handler,
&mut ledger,
false,
&fake,
#[fuchsia::test]
async fn test_usb_driver_not_running() {
let test_env = ffx_config::test_env().build().unwrap();
setup_ssh_keys(&test_env).await.expect("setting up ssh test keys");
setup_emu_dir(&test_env).expect("setting up emulator data");
let fake = FakeDaemonManager::new(
vec![true],
vec![],
vec![],
vec![Ok(setup_responsive_daemon_server())],
vec![Ok(vec![1])],
);
let mut handler = FakeStepHandler::new();
let ledger_view = Box::new(FakeLedgerView::new());
let mut ledger = DoctorLedger::<MockWriter>::new(
MockWriter::new(),
ledger_view,
LedgerViewMode::Verbose,
);
let mut mock_driver_finder = MockUsbDriverFinder::new();
mock_driver_finder
.expect_find()
.times(1)
.returning(|| Err(FindUsbDriverError::DriverIsNotRunning));
doctor(
&mut handler,
#[fuchsia::test]
async fn test_single_try_daemon_running_no_targets() {
let test_env = ffx_config::test_env().build().unwrap();
setup_ssh_keys(&test_env).await.expect("setting up ssh test keys");
setup_emu_dir(&test_env).expect("setting up emulator data");
setup_driver_socket_file(&test_env).await.expect("setting up fake driver socket file");
let fake = FakeDaemonManager::new(
vec![true],
vec![],
vec![],
vec![Ok(setup_responsive_daemon_server())],
vec![Ok(vec![1])],
);
let mut handler = FakeStepHandler::new();
let ledger_view = Box::new(FakeLedgerView::new());
let mut ledger = DoctorLedger::<MockWriter>::new(
MockWriter::new(),
ledger_view,
LedgerViewMode::Verbose,
);
let mock_driver_finder = default_mock_driver_finder();
doctor(
&mut handler,
&mut ledger,
false,
&fake,
"",
```posix-terminal
N/A
{
"command": "ffx doctor",
"options": [
{
"description": "generates an output zip file with logs",
"option": "record",
"shorthand": "",
"value_type": "bool"
},
{
"description": "do not include the ffx configuration file",
"option": "no-config",
N/A
N/A
N/A
{
"command": "ffx doctor",
"options": [
{
"description": "generates an output zip file with logs",
"option": "record",
"shorthand": "",
"value_type": "bool"
},
{
"description": "do not include the ffx configuration file",
"option": "no-config",
N/A
```posix-terminal
N/A
{
"command": "ffx doctor",
"options": [
{
"description": "generates an output zip file with logs",
"option": "record",
"shorthand": "",
"value_type": "bool"
},
{
"description": "do not include the ffx configuration file",
"option": "no-config",
N/A
```posix-terminal
N/A
{
"command": "ffx doctor",
"options": [
{
"description": "generates an output zip file with logs",
"option": "record",
"shorthand": "",
"value_type": "bool"
},
{
"description": "do not include the ffx configuration file",
"option": "no-config",
N/A
N/A
N/A
{
"command": "ffx doctor",
"options": [
{
"description": "generates an output zip file with logs",
"option": "record",
"shorthand": "",
"value_type": "bool"
},
{
"description": "do not include the ffx configuration file",
"option": "no-config",
N/A
N/A
N/A
{
"command": "ffx doctor",
"options": [
{
"description": "generates an output zip file with logs",
"option": "record",
"shorthand": "",
"value_type": "bool"
},
{
"description": "do not include the ffx configuration file",
"option": "no-config",
N/A
N/A
N/A
{
"command": "ffx doctor",
"options": [
{
"description": "generates an output zip file with logs",
"option": "record",
"shorthand": "",
"value_type": "bool"
},
{
"description": "do not include the ffx configuration file",
"option": "no-config",
N/A
N/A
N/A
{
"command": "ffx doctor",
"options": [
{
"description": "generates an output zip file with logs",
"option": "record",
"shorthand": "",
"value_type": "bool"
},
{
"description": "do not include the ffx configuration file",
"option": "no-config",
N/A
N/A
N/A
{
"command": "ffx driver",
"options": [
{
"description": "if this exists, the user will be prompted for a component to select.",
"option": "select",
"shorthand": "s",
"value_type": "bool"
}
],
"short": "Support driver development workflows"
}
driver_list = self.dut.ffx.run(["driver", "list"])
if driver_list.find("iwlwifi") != -1:
phy_ids = await self.dut.wlan_core.get_phy_id_list()
iface_ids = await self.dut.wlan_core.get_iface_id_list()
iface_id = await self.dut.wlan_core.create_iface(
phy_id=phy_ids[0], role=f_wlan_common.WlanMacRole.CLIENT
)
query_resp = await self.dut.wlan_core.query_iface(iface_id)
asserts.assert_equal(
query_resp.role, f_wlan_common.WlanMacRole.CLIENT
)
asserts.assert_equal(query_resp.id_, iface_id)
asserts.assert_equal(query_resp.phy_id, phy_ids[0])
await self.dut.wlan_core.destroy_iface(iface_id)
expected_iface_ids = await self.dut.wlan_core.get_iface_id_list()
asserts.assert_equal(iface_ids, expected_iface_ids)
else:
phy_ids = await self.dut.wlan_core.get_phy_id_list()
iface_ids = await self.dut.wlan_core.get_iface_id_list()
if iface_ids:
await self.dut.wlan_core.destroy_iface(iface_ids[0])
async def test_phy_response_to_country_code_change(self) -> None:
"""Tests that all phys respond to a country code setting change."""
async def check_country_code(
N/A
N/A
{
"command": "ffx driver",
"options": [
{
"description": "if this exists, the user will be prompted for a component to select.",
"option": "select",
"shorthand": "s",
"value_type": "bool"
}
],
"short": "Support driver development workflows"
}
N/A
N/A
N/A
{
"command": "ffx driver composite",
"options": [],
"short": "Commands to interact with composite node specs."
}
N/A
N/A
N/A
{
"command": "ffx driver composite list",
"options": [
{
"description": "shows the composite's state and bound driver url if one exists.",
"option": "verbose",
"shorthand": "v",
"value_type": "bool"
},
{
"description": "filter the list by a criteria: bound, unbound, incomplete",
"option": "only",
N/A
N/A
N/A
{
"command": "ffx driver composite list",
"options": [
{
"description": "shows the composite's state and bound driver url if one exists.",
"option": "verbose",
"shorthand": "v",
"value_type": "bool"
},
{
"description": "filter the list by a criteria: bound, unbound, incomplete",
"option": "only",
N/A
N/A
N/A
{
"command": "ffx driver composite list",
"options": [
{
"description": "shows the composite's state and bound driver url if one exists.",
"option": "verbose",
"shorthand": "v",
"value_type": "bool"
},
{
"description": "filter the list by a criteria: bound, unbound, incomplete",
"option": "only",
N/A
N/A
N/A
{
"command": "ffx driver composite show",
"options": [],
"short": "Show detailed information for a composite node spec"
}
N/A
N/A
N/A
{
"command": "ffx driver disable",
"options": [
{
"description": "if this exists, the user will be prompted for a component to select.",
"option": "select",
"shorthand": "s",
"value_type": "bool"
}
],
"short": "Disables the given driver, and restart its nodes with rematching."
}
N/A
N/A
N/A
{
"command": "ffx driver disable",
"options": [
{
"description": "if this exists, the user will be prompted for a component to select.",
"option": "select",
"shorthand": "s",
"value_type": "bool"
}
],
"short": "Disables the given driver, and restart its nodes with rematching."
}
N/A
N/A
N/A
{
"command": "ffx driver doctor",
"options": [
{
"description": "URL or a substring of the URL of the driver to diagnose. The command will fail if multiple drivers match.",
"option": "driver",
"shorthand": "",
"value_type": "string"
},
{
"description": "moniker of the node to diagnose.",
"option": "node",
N/A
N/A
N/A
{
"command": "ffx driver doctor",
"options": [
{
"description": "URL or a substring of the URL of the driver to diagnose. The command will fail if multiple drivers match.",
"option": "driver",
"shorthand": "",
"value_type": "string"
},
{
"description": "moniker of the node to diagnose.",
"option": "node",
N/A
N/A
N/A
{
"command": "ffx driver doctor",
"options": [
{
"description": "URL or a substring of the URL of the driver to diagnose. The command will fail if multiple drivers match.",
"option": "driver",
"shorthand": "",
"value_type": "string"
},
{
"description": "moniker of the node to diagnose.",
"option": "node",
N/A
N/A
N/A
{
"command": "ffx driver doctor",
"options": [
{
"description": "URL or a substring of the URL of the driver to diagnose. The command will fail if multiple drivers match.",
"option": "driver",
"shorthand": "",
"value_type": "string"
},
{
"description": "moniker of the node to diagnose.",
"option": "node",
N/A
N/A
N/A
{
"command": "ffx driver doctor",
"options": [
{
"description": "URL or a substring of the URL of the driver to diagnose. The command will fail if multiple drivers match.",
"option": "driver",
"shorthand": "",
"value_type": "string"
},
{
"description": "moniker of the node to diagnose.",
"option": "node",
N/A
N/A
N/A
{
"command": "ffx driver dump",
"options": [
{
"description": "output device graph in dot language so that it may be viewed",
"option": "graph",
"shorthand": "g",
"value_type": "bool"
},
{
"description": "if this exists, the user will be prompted for a component to select.",
"option": "select",
N/A
N/A
N/A
{
"command": "ffx driver dump",
"options": [
{
"description": "output device graph in dot language so that it may be viewed",
"option": "graph",
"shorthand": "g",
"value_type": "bool"
},
{
"description": "if this exists, the user will be prompted for a component to select.",
"option": "select",
N/A
N/A
N/A
{
"command": "ffx driver dump",
"options": [
{
"description": "output device graph in dot language so that it may be viewed",
"option": "graph",
"shorthand": "g",
"value_type": "bool"
},
{
"description": "if this exists, the user will be prompted for a component to select.",
"option": "select",
N/A
N/A
N/A
{
"command": "ffx driver host",
"options": [],
"short": "Commands to interact with driver framework driver hosts."
}
N/A
N/A
N/A
{
"command": "ffx driver host list",
"options": [],
"short": "List driver hosts and drivers loaded within them"
}
N/A
N/A
N/A
{
"command": "ffx driver host show",
"options": [
{
"description": "if this exists, the user will be prompted for a component to select.",
"option": "select",
"shorthand": "s",
"value_type": "bool"
},
{
"description": "whether to print driver runtime info for the driver host.",
"option": "runtime",
N/A
N/A
N/A
{
"command": "ffx driver host show",
"options": [
{
"description": "if this exists, the user will be prompted for a component to select.",
"option": "select",
"shorthand": "s",
"value_type": "bool"
},
{
"description": "whether to print driver runtime info for the driver host.",
"option": "runtime",
N/A
N/A
N/A
{
"command": "ffx driver host show",
"options": [
{
"description": "if this exists, the user will be prompted for a component to select.",
"option": "select",
"shorthand": "s",
"value_type": "bool"
},
{
"description": "whether to print driver runtime info for the driver host.",
"option": "runtime",
N/A
N/A
N/A
{
"command": "ffx driver host show",
"options": [
{
"description": "if this exists, the user will be prompted for a component to select.",
"option": "select",
"shorthand": "s",
"value_type": "bool"
},
{
"description": "whether to print driver runtime info for the driver host.",
"option": "runtime",
N/A
N/A
N/A
{
"command": "ffx driver list",
"options": [
{
"description": "[Deprecated] Use `ffx driver show` instead. List all driver properties.",
"option": "verbose",
"shorthand": "v",
"value_type": "bool"
},
{
"description": "only list loaded drivers",
"option": "loaded",
driver_list = self.dut.ffx.run(["driver", "list"])
if driver_list.find("iwlwifi") != -1:
phy_ids = await self.dut.wlan_core.get_phy_id_list()
iface_ids = await self.dut.wlan_core.get_iface_id_list()
iface_id = await self.dut.wlan_core.create_iface(
phy_id=phy_ids[0], role=f_wlan_common.WlanMacRole.CLIENT
)
query_resp = await self.dut.wlan_core.query_iface(iface_id)
asserts.assert_equal(
query_resp.role, f_wlan_common.WlanMacRole.CLIENT
)
asserts.assert_equal(query_resp.id_, iface_id)
asserts.assert_equal(query_resp.phy_id, phy_ids[0])
await self.dut.wlan_core.destroy_iface(iface_id)
expected_iface_ids = await self.dut.wlan_core.get_iface_id_list()
asserts.assert_equal(iface_ids, expected_iface_ids)
else:
phy_ids = await self.dut.wlan_core.get_phy_id_list()
iface_ids = await self.dut.wlan_core.get_iface_id_list()
if iface_ids:
await self.dut.wlan_core.destroy_iface(iface_ids[0])
async def test_phy_response_to_country_code_change(self) -> None:
"""Tests that all phys respond to a country code setting change."""
async def check_country_code(
N/A
N/A
{
"command": "ffx driver list",
"options": [
{
"description": "[Deprecated] Use `ffx driver show` instead. List all driver properties.",
"option": "verbose",
"shorthand": "v",
"value_type": "bool"
},
{
"description": "only list loaded drivers",
"option": "loaded",
N/A
N/A
N/A
{
"command": "ffx driver list",
"options": [
{
"description": "[Deprecated] Use `ffx driver show` instead. List all driver properties.",
"option": "verbose",
"shorthand": "v",
"value_type": "bool"
},
{
"description": "only list loaded drivers",
"option": "loaded",
N/A
N/A
N/A
{
"command": "ffx driver list",
"options": [
{
"description": "[Deprecated] Use `ffx driver show` instead. List all driver properties.",
"option": "verbose",
"shorthand": "v",
"value_type": "bool"
},
{
"description": "only list loaded drivers",
"option": "loaded",
N/A
N/A
N/A
{
"command": "ffx driver list-composite-node-specs",
"options": [
{
"description": "list all driver properties.",
"option": "verbose",
"shorthand": "v",
"value_type": "bool"
},
{
"description": "only show the spec with this name.",
"option": "name",
N/A
N/A
N/A
{
"command": "ffx driver list-composite-node-specs",
"options": [
{
"description": "list all driver properties.",
"option": "verbose",
"shorthand": "v",
"value_type": "bool"
},
{
"description": "only show the spec with this name.",
"option": "name",
N/A
N/A
N/A
{
"command": "ffx driver list-composite-node-specs",
"options": [
{
"description": "list all driver properties.",
"option": "verbose",
"shorthand": "v",
"value_type": "bool"
},
{
"description": "only show the spec with this name.",
"option": "name",
N/A
N/A
N/A
{
"command": "ffx driver list-composite-node-specs",
"options": [
{
"description": "list all driver properties.",
"option": "verbose",
"shorthand": "v",
"value_type": "bool"
},
{
"description": "only show the spec with this name.",
"option": "name",
N/A
N/A
N/A
{
"command": "ffx driver list-composites",
"options": [
{
"description": "list all the properties of a composite.",
"option": "verbose",
"shorthand": "v",
"value_type": "bool"
},
{
"description": "if this exists, the user will be prompted for a component to select.",
"option": "select",
N/A
N/A
N/A
{
"command": "ffx driver list-composites",
"options": [
{
"description": "list all the properties of a composite.",
"option": "verbose",
"shorthand": "v",
"value_type": "bool"
},
{
"description": "if this exists, the user will be prompted for a component to select.",
"option": "select",
N/A
N/A
N/A
{
"command": "ffx driver list-composites",
"options": [
{
"description": "list all the properties of a composite.",
"option": "verbose",
"shorthand": "v",
"value_type": "bool"
},
{
"description": "if this exists, the user will be prompted for a component to select.",
"option": "select",
N/A
N/A
N/A
{
"command": "ffx driver list-devices",
"options": [
{
"description": "if this exists, the user will be prompted for a component to select.",
"option": "select",
"shorthand": "s",
"value_type": "bool"
},
{
"description": "list all device properties.",
"option": "verbose",
N/A
N/A
N/A
{
"command": "ffx driver list-devices",
"options": [
{
"description": "if this exists, the user will be prompted for a component to select.",
"option": "select",
"shorthand": "s",
"value_type": "bool"
},
{
"description": "list all device properties.",
"option": "verbose",
N/A
N/A
N/A
{
"command": "ffx driver list-devices",
"options": [
{
"description": "if this exists, the user will be prompted for a component to select.",
"option": "select",
"shorthand": "s",
"value_type": "bool"
},
{
"description": "list all device properties.",
"option": "verbose",
N/A
N/A
N/A
{
"command": "ffx driver list-devices",
"options": [
{
"description": "if this exists, the user will be prompted for a component to select.",
"option": "select",
"shorthand": "s",
"value_type": "bool"
},
{
"description": "list all device properties.",
"option": "verbose",
N/A
N/A
N/A
{
"command": "ffx driver list-devices",
"options": [
{
"description": "if this exists, the user will be prompted for a component to select.",
"option": "select",
"shorthand": "s",
"value_type": "bool"
},
{
"description": "list all device properties.",
"option": "verbose",
N/A
N/A
N/A
{
"command": "ffx driver list-devices",
"options": [
{
"description": "if this exists, the user will be prompted for a component to select.",
"option": "select",
"shorthand": "s",
"value_type": "bool"
},
{
"description": "list all device properties.",
"option": "verbose",
N/A
N/A
N/A
{
"command": "ffx driver list-hosts",
"options": [
{
"description": "if this exists, the user will be prompted for a component to select.",
"option": "select",
"shorthand": "s",
"value_type": "bool"
}
],
"short": "List driver hosts and drivers loaded within them"
}
N/A
N/A
N/A
{
"command": "ffx driver list-hosts",
"options": [
{
"description": "if this exists, the user will be prompted for a component to select.",
"option": "select",
"shorthand": "s",
"value_type": "bool"
}
],
"short": "List driver hosts and drivers loaded within them"
}
N/A
N/A
N/A
{
"command": "ffx driver node",
"options": [],
"short": "Commands to interact with driver framework nodes."
}
N/A
N/A
N/A
{
"command": "ffx driver node add",
"options": [],
"short": "Add a node with a given bind property"
}
N/A
N/A
N/A
{
"command": "ffx driver node graph",
"options": [
{
"description": "filter the nodes by a criteria: bound, unbound, ancestors:<node_name>, primary_ancestors:<node_name>, descendants:<node_name>, relatives:<node_name>, primary_relatives:<node_name>, siblings:<node_name>, or primary_siblings:<node_name>. the primary variants indicate to only traverse primary parents when encountering composites",
"option": "only",
"shorthand": "o",
"value_type": "string"
},
{
"description": "changes the visual orientation of the graph's nodes. Allowed values are \"lefttoright\"/\"lr\" and \"toptobottom\"/\"tb\".",
"option": "orientation",
N/A
N/A
N/A
{
"command": "ffx driver node graph",
"options": [
{
"description": "filter the nodes by a criteria: bound, unbound, ancestors:<node_name>, primary_ancestors:<node_name>, descendants:<node_name>, relatives:<node_name>, primary_relatives:<node_name>, siblings:<node_name>, or primary_siblings:<node_name>. the primary variants indicate to only traverse primary parents when encountering composites",
"option": "only",
"shorthand": "o",
"value_type": "string"
},
{
"description": "changes the visual orientation of the graph's nodes. Allowed values are \"lefttoright\"/\"lr\" and \"toptobottom\"/\"tb\".",
"option": "orientation",
N/A
N/A
N/A
{
"command": "ffx driver node graph",
"options": [
{
"description": "filter the nodes by a criteria: bound, unbound, ancestors:<node_name>, primary_ancestors:<node_name>, descendants:<node_name>, relatives:<node_name>, primary_relatives:<node_name>, siblings:<node_name>, or primary_siblings:<node_name>. the primary variants indicate to only traverse primary parents when encountering composites",
"option": "only",
"shorthand": "o",
"value_type": "string"
},
{
"description": "changes the visual orientation of the graph's nodes. Allowed values are \"lefttoright\"/\"lr\" and \"toptobottom\"/\"tb\".",
"option": "orientation",
N/A
N/A
N/A
{
"command": "ffx driver node graph",
"options": [
{
"description": "filter the nodes by a criteria: bound, unbound, ancestors:<node_name>, primary_ancestors:<node_name>, descendants:<node_name>, relatives:<node_name>, primary_relatives:<node_name>, siblings:<node_name>, or primary_siblings:<node_name>. the primary variants indicate to only traverse primary parents when encountering composites",
"option": "only",
"shorthand": "o",
"value_type": "string"
},
{
"description": "changes the visual orientation of the graph's nodes. Allowed values are \"lefttoright\"/\"lr\" and \"toptobottom\"/\"tb\".",
"option": "orientation",
N/A
N/A
N/A
{
"command": "ffx driver node graph",
"options": [
{
"description": "filter the nodes by a criteria: bound, unbound, ancestors:<node_name>, primary_ancestors:<node_name>, descendants:<node_name>, relatives:<node_name>, primary_relatives:<node_name>, siblings:<node_name>, or primary_siblings:<node_name>. the primary variants indicate to only traverse primary parents when encountering composites",
"option": "only",
"shorthand": "o",
"value_type": "string"
},
{
"description": "changes the visual orientation of the graph's nodes. Allowed values are \"lefttoright\"/\"lr\" and \"toptobottom\"/\"tb\".",
"option": "orientation",
N/A
N/A
N/A
{
"command": "ffx driver node graph",
"options": [
{
"description": "filter the nodes by a criteria: bound, unbound, ancestors:<node_name>, primary_ancestors:<node_name>, descendants:<node_name>, relatives:<node_name>, primary_relatives:<node_name>, siblings:<node_name>, or primary_siblings:<node_name>. the primary variants indicate to only traverse primary parents when encountering composites",
"option": "only",
"shorthand": "o",
"value_type": "string"
},
{
"description": "changes the visual orientation of the graph's nodes. Allowed values are \"lefttoright\"/\"lr\" and \"toptobottom\"/\"tb\".",
"option": "orientation",
N/A
N/A
N/A
{
"command": "ffx driver node list",
"options": [
{
"description": "shows the node's state and bound driver url if one exists.",
"option": "verbose",
"shorthand": "v",
"value_type": "bool"
},
{
"description": "return a non-zero exit code if no matching devices are found.",
"option": "fail-on-missing",
N/A
N/A
N/A
{
"command": "ffx driver node list",
"options": [
{
"description": "shows the node's state and bound driver url if one exists.",
"option": "verbose",
"shorthand": "v",
"value_type": "bool"
},
{
"description": "return a non-zero exit code if no matching devices are found.",
"option": "fail-on-missing",
N/A
N/A
N/A
{
"command": "ffx driver node list",
"options": [
{
"description": "shows the node's state and bound driver url if one exists.",
"option": "verbose",
"shorthand": "v",
"value_type": "bool"
},
{
"description": "return a non-zero exit code if no matching devices are found.",
"option": "fail-on-missing",
N/A
N/A
N/A
{
"command": "ffx driver node list",
"options": [
{
"description": "shows the node's state and bound driver url if one exists.",
"option": "verbose",
"shorthand": "v",
"value_type": "bool"
},
{
"description": "return a non-zero exit code if no matching devices are found.",
"option": "fail-on-missing",
N/A
N/A
N/A
{
"command": "ffx driver node remove",
"options": [],
"short": "Remove a node that was previously added using driver node add."
}
N/A
N/A
N/A
{
"command": "ffx driver node show",
"options": [],
"short": "Show a specific node in the driver framework"
}
N/A
N/A
N/A
{
"command": "ffx driver register",
"options": [
{
"description": "if this exists, the user will be prompted for a component to select.",
"option": "select",
"shorthand": "s",
"value_type": "bool"
}
],
"short": "Informs the driver manager that a new driver package is available. The driver manager will cache a copy of the driver"
}
N/A
N/A
N/A
{
"command": "ffx driver register",
"options": [
{
"description": "if this exists, the user will be prompted for a component to select.",
"option": "select",
"shorthand": "s",
"value_type": "bool"
}
],
"short": "Informs the driver manager that a new driver package is available. The driver manager will cache a copy of the driver"
}
N/A
N/A
N/A
{
"command": "ffx driver restart",
"options": [
{
"description": "if this exists, the user will be prompted for a component to select.",
"option": "select",
"shorthand": "s",
"value_type": "bool"
}
],
"short": "Restart all driver hosts containing the driver specified by driver_path."
}
N/A
N/A
N/A
{
"command": "ffx driver restart",
"options": [
{
"description": "if this exists, the user will be prompted for a component to select.",
"option": "select",
"shorthand": "s",
"value_type": "bool"
}
],
"short": "Restart all driver hosts containing the driver specified by driver_path."
}
N/A
N/A
N/A
{
"command": "ffx driver show",
"options": [
{
"description": "if this exists, the user will be prompted for a component to select.",
"option": "select",
"shorthand": "s",
"value_type": "bool"
}
],
"short": "Show driver details"
}
N/A
N/A
N/A
{
"command": "ffx driver show",
"options": [
{
"description": "if this exists, the user will be prompted for a component to select.",
"option": "select",
"shorthand": "s",
"value_type": "bool"
}
],
"short": "Show driver details"
}
N/A
N/A
N/A
{
"command": "ffx driver static-checks",
"options": [
{
"description": "the path to the driver's FAR file",
"option": "driver",
"shorthand": "",
"value_type": "string"
}
],
"short": "Run static checks against a driver file."
}
N/A
N/A
N/A
{
"command": "ffx driver static-checks",
"options": [
{
"description": "the path to the driver's FAR file",
"option": "driver",
"shorthand": "",
"value_type": "string"
}
],
"short": "Run static checks against a driver file."
}
N/A
N/A
N/A
{
"command": "ffx driver test-node",
"options": [
{
"description": "if this exists, the user will be prompted for a component to select.",
"option": "select",
"shorthand": "s",
"value_type": "bool"
}
],
"short": "Commands to interact with test nodes."
}
N/A
N/A
N/A
{
"command": "ffx driver test-node",
"options": [
{
"description": "if this exists, the user will be prompted for a component to select.",
"option": "select",
"shorthand": "s",
"value_type": "bool"
}
],
"short": "Commands to interact with test nodes."
}
N/A
N/A
N/A
{
"command": "ffx driver test-node add",
"options": [],
"short": "Add a test node with a given bind property"
}
N/A
N/A
N/A
{
"command": "ffx driver test-node remove",
"options": [],
"short": "Remove a test node."
}
N/A
N/A
N/A
{
"command": "ffx efi",
"options": [],
"short": "Manipulate efi partition"
}
N/A
N/A
N/A
{
"command": "ffx efi create",
"options": [
{
"description": "target file/disk to write EFI partition to",
"option": "output",
"shorthand": "o",
"value_type": "string"
},
{
"description": "optional path to source file for zircon.bin",
"option": "zircon",
N/A
N/A
N/A
{
"command": "ffx efi create",
"options": [
{
"description": "target file/disk to write EFI partition to",
"option": "output",
"shorthand": "o",
"value_type": "string"
},
{
"description": "optional path to source file for zircon.bin",
"option": "zircon",
N/A
N/A
N/A
{
"command": "ffx efi create",
"options": [
{
"description": "target file/disk to write EFI partition to",
"option": "output",
"shorthand": "o",
"value_type": "string"
},
{
"description": "optional path to source file for zircon.bin",
"option": "zircon",
N/A
N/A
N/A
{
"command": "ffx efi create",
"options": [
{
"description": "target file/disk to write EFI partition to",
"option": "output",
"shorthand": "o",
"value_type": "string"
},
{
"description": "optional path to source file for zircon.bin",
"option": "zircon",
N/A
N/A
N/A
{
"command": "ffx efi create",
"options": [
{
"description": "target file/disk to write EFI partition to",
"option": "output",
"shorthand": "o",
"value_type": "string"
},
{
"description": "optional path to source file for zircon.bin",
"option": "zircon",
N/A
N/A
N/A
{
"command": "ffx efi create",
"options": [
{
"description": "target file/disk to write EFI partition to",
"option": "output",
"shorthand": "o",
"value_type": "string"
},
{
"description": "optional path to source file for zircon.bin",
"option": "zircon",
N/A
N/A
N/A
{
"command": "ffx efi create",
"options": [
{
"description": "target file/disk to write EFI partition to",
"option": "output",
"shorthand": "o",
"value_type": "string"
},
{
"description": "optional path to source file for zircon.bin",
"option": "zircon",
N/A
N/A
N/A
{
"command": "ffx emu",
"options": [],
"short": "Start and manage Fuchsia emulators."
}
Emulator discovery is passive: It watches for changes to a directory `ffx emu` manages.
* `ffx emu` integration by merging with `ffx_e2e_emu` (b/295230484)
// Copyright 2023 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use anyhow::{Context as _, ensure};
N/A
{
"command": "ffx emu console",
"options": [
{
"description": "selector for which console to attach to. Accepted values are: command machine serial",
"option": "console-type",
"shorthand": "",
"value_type": "string"
},
{
"description": "attach to the user-interactive command console. Equivalent to \"--console-type command\".",
"option": "command",
N/A
```posix-terminal
N/A
{
"command": "ffx emu console",
"options": [
{
"description": "selector for which console to attach to. Accepted values are: command machine serial",
"option": "console-type",
"shorthand": "",
"value_type": "string"
},
{
"description": "attach to the user-interactive command console. Equivalent to \"--console-type command\".",
"option": "command",
N/A
N/A
N/A
{
"command": "ffx emu console",
"options": [
{
"description": "selector for which console to attach to. Accepted values are: command machine serial",
"option": "console-type",
"shorthand": "",
"value_type": "string"
},
{
"description": "attach to the user-interactive command console. Equivalent to \"--console-type command\".",
"option": "command",
N/A
N/A
N/A
{
"command": "ffx emu console",
"options": [
{
"description": "selector for which console to attach to. Accepted values are: command machine serial",
"option": "console-type",
"shorthand": "",
"value_type": "string"
},
{
"description": "attach to the user-interactive command console. Equivalent to \"--console-type command\".",
"option": "command",
N/A
N/A
N/A
{
"command": "ffx emu console",
"options": [
{
"description": "selector for which console to attach to. Accepted values are: command machine serial",
"option": "console-type",
"shorthand": "",
"value_type": "string"
},
{
"description": "attach to the user-interactive command console. Equivalent to \"--console-type command\".",
"option": "command",
N/A
N/A
N/A
{
"command": "ffx emu list",
"options": [
{
"description": "list only the emulators that are currently in the \"running\" state.",
"option": "only-running",
"shorthand": "r",
"value_type": "bool"
}
],
"short": "List running Fuchsia emulators."
}
N/A
N/A
N/A
{
"command": "ffx emu list",
"options": [
{
"description": "list only the emulators that are currently in the \"running\" state.",
"option": "only-running",
"shorthand": "r",
"value_type": "bool"
}
],
"short": "List running Fuchsia emulators."
}
N/A
N/A
N/A
{
"command": "ffx emu screenshot",
"options": [
{
"description": "path to save the screenshot. Relative (to the current directory) or absolute paths are both supported. The output will always be in PNG format.",
"option": "output",
"shorthand": "o",
"value_type": "string"
}
],
"short": "Take a screenshot of the emulator's primary display."
}
N/A
```posix-terminal
N/A
{
"command": "ffx emu screenshot",
"options": [
{
"description": "path to save the screenshot. Relative (to the current directory) or absolute paths are both supported. The output will always be in PNG format.",
"option": "output",
"shorthand": "o",
"value_type": "string"
}
],
"short": "Take a screenshot of the emulator's primary display."
}
N/A
```posix-terminal
N/A
{
"command": "ffx emu show",
"options": [
{
"description": "show all of the available details, which is the default.",
"option": "all",
"shorthand": "",
"value_type": "bool"
},
{
"description": "show the command line used to launch the emulator.",
"option": "cmd",
N/A
N/A
N/A
{
"command": "ffx emu show",
"options": [
{
"description": "show all of the available details, which is the default.",
"option": "all",
"shorthand": "",
"value_type": "bool"
},
{
"description": "show the command line used to launch the emulator.",
"option": "cmd",
N/A
N/A
N/A
{
"command": "ffx emu show",
"options": [
{
"description": "show all of the available details, which is the default.",
"option": "all",
"shorthand": "",
"value_type": "bool"
},
{
"description": "show the command line used to launch the emulator.",
"option": "cmd",
N/A
N/A
N/A
{
"command": "ffx emu show",
"options": [
{
"description": "show all of the available details, which is the default.",
"option": "all",
"shorthand": "",
"value_type": "bool"
},
{
"description": "show the command line used to launch the emulator.",
"option": "cmd",
N/A
N/A
N/A
{
"command": "ffx emu show",
"options": [
{
"description": "show all of the available details, which is the default.",
"option": "all",
"shorthand": "",
"value_type": "bool"
},
{
"description": "show the command line used to launch the emulator.",
"option": "cmd",
N/A
N/A
N/A
{
"command": "ffx emu show",
"options": [
{
"description": "show all of the available details, which is the default.",
"option": "all",
"shorthand": "",
"value_type": "bool"
},
{
"description": "show the command line used to launch the emulator.",
"option": "cmd",
N/A
N/A
N/A
{
"command": "ffx emu show",
"options": [
{
"description": "show all of the available details, which is the default.",
"option": "all",
"shorthand": "",
"value_type": "bool"
},
{
"description": "show the command line used to launch the emulator.",
"option": "cmd",
N/A
N/A
N/A
{
"command": "ffx emu start",
"options": [
{
"description": "virtualization acceleration. Valid choices are \"none\" to disable acceleration, \"hyper\" to use the host's hypervisor interface (KVM on Linux and HVF on MacOS), or \"auto\" to use the hypervisor if detected. The default value is \"auto\".",
"option": "accel",
"shorthand": "",
"value_type": "string"
},
{
"description": "specify a configuration file to populate the command line flags for the emulator. Defaults to a Handlebars config specified in the Product Bundle manifest.",
"option": "config",
| | `ffx emu start`. Defaults to `femu`| | | but can be overridden by the user. | | `emu.gpu` | The default gpu type to use in | | | `ffx emu start`. Defaults to | | | `auto`, but can be overridden by | | | the user. | | `emu.instance_dir` | The root directory for storing | | | instance specific data. Instances | | | should create a subdirectory in | | | this directory to store data. | | | Defaults to `$DATA/emu/instances` | | `emu.kvm_path` | The filesystem path to the | | | system's KVM device. Must be | | | writable by the running process to | | | utilize KVM for acceleration. | | | Default…
| | `ffx emu start`. Defaults to | | | `auto`, but can be overridden by | | | the user. | | `emu.instance_dir` | The root directory for storing | | | instance specific data. Instances | | | should create a subdirectory in | | | this directory to store data. | | | Defaults to `$DATA/emu/instances` | | `emu.kvm_path` | The filesystem path to the | | | system's KVM device. Must be | | | writable by the running process to | | | utilize KVM for acceleration. | | | Defaults to `/dev/kvm` | | `emu.start.timeout` | The duration (in seconds) to | | | attempt to establish an RCS | | | connection with a …
// Copyright 2023 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use anyhow::{Context as _, ensure};
```posix-terminal
N/A
{
"command": "ffx emu start",
"options": [
{
"description": "virtualization acceleration. Valid choices are \"none\" to disable acceleration, \"hyper\" to use the host's hypervisor interface (KVM on Linux and HVF on MacOS), or \"auto\" to use the hypervisor if detected. The default value is \"auto\".",
"option": "accel",
"shorthand": "",
"value_type": "string"
},
{
"description": "specify a configuration file to populate the command line flags for the emulator. Defaults to a Handlebars config specified in the Product Bundle manifest.",
"option": "config",
N/A
N/A
N/A
{
"command": "ffx emu start",
"options": [
{
"description": "virtualization acceleration. Valid choices are \"none\" to disable acceleration, \"hyper\" to use the host's hypervisor interface (KVM on Linux and HVF on MacOS), or \"auto\" to use the hypervisor if detected. The default value is \"auto\".",
"option": "accel",
"shorthand": "",
"value_type": "string"
},
{
"description": "specify a configuration file to populate the command line flags for the emulator. Defaults to a Handlebars config specified in the Product Bundle manifest.",
"option": "config",
N/A
N/A
N/A
{
"command": "ffx emu start",
"options": [
{
"description": "virtualization acceleration. Valid choices are \"none\" to disable acceleration, \"hyper\" to use the host's hypervisor interface (KVM on Linux and HVF on MacOS), or \"auto\" to use the hypervisor if detected. The default value is \"auto\".",
"option": "accel",
"shorthand": "",
"value_type": "string"
},
{
"description": "specify a configuration file to populate the command line flags for the emulator. Defaults to a Handlebars config specified in the Product Bundle manifest.",
"option": "config",
N/A
N/A
N/A
{
"command": "ffx emu start",
"options": [
{
"description": "virtualization acceleration. Valid choices are \"none\" to disable acceleration, \"hyper\" to use the host's hypervisor interface (KVM on Linux and HVF on MacOS), or \"auto\" to use the hypervisor if detected. The default value is \"auto\".",
"option": "accel",
"shorthand": "",
"value_type": "string"
},
{
"description": "specify a configuration file to populate the command line flags for the emulator. Defaults to a Handlebars config specified in the Product Bundle manifest.",
"option": "config",
N/A
N/A
N/A
{
"command": "ffx emu start",
"options": [
{
"description": "virtualization acceleration. Valid choices are \"none\" to disable acceleration, \"hyper\" to use the host's hypervisor interface (KVM on Linux and HVF on MacOS), or \"auto\" to use the hypervisor if detected. The default value is \"auto\".",
"option": "accel",
"shorthand": "",
"value_type": "string"
},
{
"description": "specify a configuration file to populate the command line flags for the emulator. Defaults to a Handlebars config specified in the Product Bundle manifest.",
"option": "config",
N/A
N/A
N/A
{
"command": "ffx emu start",
"options": [
{
"description": "virtualization acceleration. Valid choices are \"none\" to disable acceleration, \"hyper\" to use the host's hypervisor interface (KVM on Linux and HVF on MacOS), or \"auto\" to use the hypervisor if detected. The default value is \"auto\".",
"option": "accel",
"shorthand": "",
"value_type": "string"
},
{
"description": "specify a configuration file to populate the command line flags for the emulator. Defaults to a Handlebars config specified in the Product Bundle manifest.",
"option": "config",
N/A
N/A
N/A
{
"command": "ffx emu start",
"options": [
{
"description": "virtualization acceleration. Valid choices are \"none\" to disable acceleration, \"hyper\" to use the host's hypervisor interface (KVM on Linux and HVF on MacOS), or \"auto\" to use the hypervisor if detected. The default value is \"auto\".",
"option": "accel",
"shorthand": "",
"value_type": "string"
},
{
"description": "specify a configuration file to populate the command line flags for the emulator. Defaults to a Handlebars config specified in the Product Bundle manifest.",
"option": "config",
N/A
N/A
N/A
{
"command": "ffx emu start",
"options": [
{
"description": "virtualization acceleration. Valid choices are \"none\" to disable acceleration, \"hyper\" to use the host's hypervisor interface (KVM on Linux and HVF on MacOS), or \"auto\" to use the hypervisor if detected. The default value is \"auto\".",
"option": "accel",
"shorthand": "",
"value_type": "string"
},
{
"description": "specify a configuration file to populate the command line flags for the emulator. Defaults to a Handlebars config specified in the Product Bundle manifest.",
"option": "config",
N/A
N/A
N/A
{
"command": "ffx emu start",
"options": [
{
"description": "virtualization acceleration. Valid choices are \"none\" to disable acceleration, \"hyper\" to use the host's hypervisor interface (KVM on Linux and HVF on MacOS), or \"auto\" to use the hypervisor if detected. The default value is \"auto\".",
"option": "accel",
"shorthand": "",
"value_type": "string"
},
{
"description": "specify a configuration file to populate the command line flags for the emulator. Defaults to a Handlebars config specified in the Product Bundle manifest.",
"option": "config",
N/A
N/A
N/A
{
"command": "ffx emu start",
"options": [
{
"description": "virtualization acceleration. Valid choices are \"none\" to disable acceleration, \"hyper\" to use the host's hypervisor interface (KVM on Linux and HVF on MacOS), or \"auto\" to use the hypervisor if detected. The default value is \"auto\".",
"option": "accel",
"shorthand": "",
"value_type": "string"
},
{
"description": "specify a configuration file to populate the command line flags for the emulator. Defaults to a Handlebars config specified in the Product Bundle manifest.",
"option": "config",
N/A
N/A
N/A
{
"command": "ffx emu start",
"options": [
{
"description": "virtualization acceleration. Valid choices are \"none\" to disable acceleration, \"hyper\" to use the host's hypervisor interface (KVM on Linux and HVF on MacOS), or \"auto\" to use the hypervisor if detected. The default value is \"auto\".",
"option": "accel",
"shorthand": "",
"value_type": "string"
},
{
"description": "specify a configuration file to populate the command line flags for the emulator. Defaults to a Handlebars config specified in the Product Bundle manifest.",
"option": "config",
N/A
N/A
N/A
{
"command": "ffx emu start",
"options": [
{
"description": "virtualization acceleration. Valid choices are \"none\" to disable acceleration, \"hyper\" to use the host's hypervisor interface (KVM on Linux and HVF on MacOS), or \"auto\" to use the hypervisor if detected. The default value is \"auto\".",
"option": "accel",
"shorthand": "",
"value_type": "string"
},
{
"description": "specify a configuration file to populate the command line flags for the emulator. Defaults to a Handlebars config specified in the Product Bundle manifest.",
"option": "config",
interface support, run `ffx emu start --headless`.
// Copyright 2023 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use anyhow::{Context as _, ensure};
N/A
N/A
{
"command": "ffx emu start",
"options": [
{
"description": "virtualization acceleration. Valid choices are \"none\" to disable acceleration, \"hyper\" to use the host's hypervisor interface (KVM on Linux and HVF on MacOS), or \"auto\" to use the hypervisor if detected. The default value is \"auto\".",
"option": "accel",
"shorthand": "",
"value_type": "string"
},
{
"description": "specify a configuration file to populate the command line flags for the emulator. Defaults to a Handlebars config specified in the Product Bundle manifest.",
"option": "config",
N/A
N/A
N/A
{
"command": "ffx emu start",
"options": [
{
"description": "virtualization acceleration. Valid choices are \"none\" to disable acceleration, \"hyper\" to use the host's hypervisor interface (KVM on Linux and HVF on MacOS), or \"auto\" to use the hypervisor if detected. The default value is \"auto\".",
"option": "accel",
"shorthand": "",
"value_type": "string"
},
{
"description": "specify a configuration file to populate the command line flags for the emulator. Defaults to a Handlebars config specified in the Product Bundle manifest.",
"option": "config",
// Copyright 2023 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use anyhow::{Context as _, ensure};
N/A
N/A
{
"command": "ffx emu start",
"options": [
{
"description": "virtualization acceleration. Valid choices are \"none\" to disable acceleration, \"hyper\" to use the host's hypervisor interface (KVM on Linux and HVF on MacOS), or \"auto\" to use the hypervisor if detected. The default value is \"auto\".",
"option": "accel",
"shorthand": "",
"value_type": "string"
},
{
"description": "specify a configuration file to populate the command line flags for the emulator. Defaults to a Handlebars config specified in the Product Bundle manifest.",
"option": "config",
// Copyright 2023 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use anyhow::{Context as _, ensure};
N/A
N/A
{
"command": "ffx emu start",
"options": [
{
"description": "virtualization acceleration. Valid choices are \"none\" to disable acceleration, \"hyper\" to use the host's hypervisor interface (KVM on Linux and HVF on MacOS), or \"auto\" to use the hypervisor if detected. The default value is \"auto\".",
"option": "accel",
"shorthand": "",
"value_type": "string"
},
{
"description": "specify a configuration file to populate the command line flags for the emulator. Defaults to a Handlebars config specified in the Product Bundle manifest.",
"option": "config",
// Copyright 2023 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use anyhow::{Context as _, ensure};
N/A
{
"command": "ffx emu start",
"options": [
{
"description": "virtualization acceleration. Valid choices are \"none\" to disable acceleration, \"hyper\" to use the host's hypervisor interface (KVM on Linux and HVF on MacOS), or \"auto\" to use the hypervisor if detected. The default value is \"auto\".",
"option": "accel",
"shorthand": "",
"value_type": "string"
},
{
"description": "specify a configuration file to populate the command line flags for the emulator. Defaults to a Handlebars config specified in the Product Bundle manifest.",
"option": "config",
// Copyright 2023 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use anyhow::{Context as _, ensure};
N/A
{
"command": "ffx emu start",
"options": [
{
"description": "virtualization acceleration. Valid choices are \"none\" to disable acceleration, \"hyper\" to use the host's hypervisor interface (KVM on Linux and HVF on MacOS), or \"auto\" to use the hypervisor if detected. The default value is \"auto\".",
"option": "accel",
"shorthand": "",
"value_type": "string"
},
{
"description": "specify a configuration file to populate the command line flags for the emulator. Defaults to a Handlebars config specified in the Product Bundle manifest.",
"option": "config",
N/A
N/A
N/A
{
"command": "ffx emu start",
"options": [
{
"description": "virtualization acceleration. Valid choices are \"none\" to disable acceleration, \"hyper\" to use the host's hypervisor interface (KVM on Linux and HVF on MacOS), or \"auto\" to use the hypervisor if detected. The default value is \"auto\".",
"option": "accel",
"shorthand": "",
"value_type": "string"
},
{
"description": "specify a configuration file to populate the command line flags for the emulator. Defaults to a Handlebars config specified in the Product Bundle manifest.",
"option": "config",
N/A
N/A
N/A
{
"command": "ffx emu start",
"options": [
{
"description": "virtualization acceleration. Valid choices are \"none\" to disable acceleration, \"hyper\" to use the host's hypervisor interface (KVM on Linux and HVF on MacOS), or \"auto\" to use the hypervisor if detected. The default value is \"auto\".",
"option": "accel",
"shorthand": "",
"value_type": "string"
},
{
"description": "specify a configuration file to populate the command line flags for the emulator. Defaults to a Handlebars config specified in the Product Bundle manifest.",
"option": "config",
N/A
N/A
N/A
{
"command": "ffx emu start",
"options": [
{
"description": "virtualization acceleration. Valid choices are \"none\" to disable acceleration, \"hyper\" to use the host's hypervisor interface (KVM on Linux and HVF on MacOS), or \"auto\" to use the hypervisor if detected. The default value is \"auto\".",
"option": "accel",
"shorthand": "",
"value_type": "string"
},
{
"description": "specify a configuration file to populate the command line flags for the emulator. Defaults to a Handlebars config specified in the Product Bundle manifest.",
"option": "config",
N/A
N/A
N/A
{
"command": "ffx emu start",
"options": [
{
"description": "virtualization acceleration. Valid choices are \"none\" to disable acceleration, \"hyper\" to use the host's hypervisor interface (KVM on Linux and HVF on MacOS), or \"auto\" to use the hypervisor if detected. The default value is \"auto\".",
"option": "accel",
"shorthand": "",
"value_type": "string"
},
{
"description": "specify a configuration file to populate the command line flags for the emulator. Defaults to a Handlebars config specified in the Product Bundle manifest.",
"option": "config",
N/A
N/A
N/A
{
"command": "ffx emu start",
"options": [
{
"description": "virtualization acceleration. Valid choices are \"none\" to disable acceleration, \"hyper\" to use the host's hypervisor interface (KVM on Linux and HVF on MacOS), or \"auto\" to use the hypervisor if detected. The default value is \"auto\".",
"option": "accel",
"shorthand": "",
"value_type": "string"
},
{
"description": "specify a configuration file to populate the command line flags for the emulator. Defaults to a Handlebars config specified in the Product Bundle manifest.",
"option": "config",
// Copyright 2023 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use anyhow::{Context as _, ensure};
N/A
N/A
{
"command": "ffx emu start",
"options": [
{
"description": "virtualization acceleration. Valid choices are \"none\" to disable acceleration, \"hyper\" to use the host's hypervisor interface (KVM on Linux and HVF on MacOS), or \"auto\" to use the hypervisor if detected. The default value is \"auto\".",
"option": "accel",
"shorthand": "",
"value_type": "string"
},
{
"description": "specify a configuration file to populate the command line flags for the emulator. Defaults to a Handlebars config specified in the Product Bundle manifest.",
"option": "config",
N/A
N/A
N/A
{
"command": "ffx emu start",
"options": [
{
"description": "virtualization acceleration. Valid choices are \"none\" to disable acceleration, \"hyper\" to use the host's hypervisor interface (KVM on Linux and HVF on MacOS), or \"auto\" to use the hypervisor if detected. The default value is \"auto\".",
"option": "accel",
"shorthand": "",
"value_type": "string"
},
{
"description": "specify a configuration file to populate the command line flags for the emulator. Defaults to a Handlebars config specified in the Product Bundle manifest.",
"option": "config",
N/A
N/A
N/A
{
"command": "ffx emu start",
"options": [
{
"description": "virtualization acceleration. Valid choices are \"none\" to disable acceleration, \"hyper\" to use the host's hypervisor interface (KVM on Linux and HVF on MacOS), or \"auto\" to use the hypervisor if detected. The default value is \"auto\".",
"option": "accel",
"shorthand": "",
"value_type": "string"
},
{
"description": "specify a configuration file to populate the command line flags for the emulator. Defaults to a Handlebars config specified in the Product Bundle manifest.",
"option": "config",
N/A
N/A
N/A
{
"command": "ffx emu start",
"options": [
{
"description": "virtualization acceleration. Valid choices are \"none\" to disable acceleration, \"hyper\" to use the host's hypervisor interface (KVM on Linux and HVF on MacOS), or \"auto\" to use the hypervisor if detected. The default value is \"auto\".",
"option": "accel",
"shorthand": "",
"value_type": "string"
},
{
"description": "specify a configuration file to populate the command line flags for the emulator. Defaults to a Handlebars config specified in the Product Bundle manifest.",
"option": "config",
N/A
N/A
N/A
{
"command": "ffx emu stop",
"options": [
{
"description": "shut down and clean up all emulator instances running on the device.",
"option": "all",
"shorthand": "",
"value_type": "bool"
},
{
"description": "don't remove the state directory on stop, just terminate the emulator.",
"option": "persist",
N/A
```posix-terminal
N/A
{
"command": "ffx emu stop",
"options": [
{
"description": "shut down and clean up all emulator instances running on the device.",
"option": "all",
"shorthand": "",
"value_type": "bool"
},
{
"description": "don't remove the state directory on stop, just terminate the emulator.",
"option": "persist",
N/A
```posix-terminal
N/A
{
"command": "ffx emu stop",
"options": [
{
"description": "shut down and clean up all emulator instances running on the device.",
"option": "all",
"shorthand": "",
"value_type": "bool"
},
{
"description": "don't remove the state directory on stop, just terminate the emulator.",
"option": "persist",
N/A
N/A
N/A
{
"command": "ffx fuzz",
"options": [],
"short": "Start and manage fuzzers."
}
#[fuchsia::test]
async fn test_shell() {
assert_eq!(get_session("shell"), Session::Interactive(None));
assert_eq!(get_session("shell -j foo"), Session::Interactive(Some("foo".to_string())));
assert_eq!(
get_session("shell --json-file bar"),
Session::Interactive(Some("bar".to_string()))
);
}
#[fuchsia::test]
async fn test_list() {
let expected = shell_cmds(vec![
FuzzShellSubcommand::List(ListSubcommand { json_file: None, pattern: None }),
FuzzShellSubcommand::Exit(ExitShellSubcommand {}),
]);
assert_eq!(get_session("list"), Session::Verbose(expected));
let expected = shell_cmds(vec![
FuzzShellSubcommand::List(ListSubcommand {
json_file: Some("foo".to_string()),
pattern: None,
}),
FuzzShellSubcommand::Exit(ExitShellSubcommand {}),
]);
assert_eq!(get_session("list -j foo"), Session::Verbose(expected));
let expected = shell_cmds(vec![
FuzzShellSubcommand::List(ListSubcommand {
json_file: Some("bar".to_string()),
pattern: None,
}),
FuzzShellSubcommand::Exit(ExitShellSubcommand {}),
]);
assert_eq!(get_session("list --json-file bar"), Session::Verbose(expected));
let expected = shell_cmds(vec![
FuzzShellSubcommand::List(ListSubcommand {
json_file: None,
#[fuchsia::test]
async fn test_get() {
let cmdline = format!("get {}", TEST_URL);
let cmd = FuzzShellSubcommand::Get(GetShellSubcommand { name: None });
let expected = create_session_commands(&cmd, None);
assert_eq!(get_session(cmdline), Session::Verbose(expected));
let cmdline = format!("get --output path -q {} key", TEST_URL);
let cmd = FuzzShellSubcommand::Get(GetShellSubcommand { name: Some("key".to_string()) });
let expected = create_session_commands(&cmd, Some("path"));
assert_eq!(get_session(cmdline), Session::Quiet(expected.clone()));
let cmdline = format!("get {} --quiet key -o path", TEST_URL);
assert_eq!(get_session(cmdline), Session::Quiet(expected));
}
N/A
N/A
{
"command": "ffx fuzz add",
"options": [
{
"description": "where to send fuzzer logs and artifacts; default is stdout and the current directory",
"option": "output",
"shorthand": "o",
"value_type": "string"
},
{
"description": "if present, suppress non-error output from the ffx tool itself",
"option": "quiet",
N/A
N/A
N/A
{
"command": "ffx fuzz add",
"options": [
{
"description": "where to send fuzzer logs and artifacts; default is stdout and the current directory",
"option": "output",
"shorthand": "o",
"value_type": "string"
},
{
"description": "if present, suppress non-error output from the ffx tool itself",
"option": "quiet",
N/A
N/A
N/A
{
"command": "ffx fuzz add",
"options": [
{
"description": "where to send fuzzer logs and artifacts; default is stdout and the current directory",
"option": "output",
"shorthand": "o",
"value_type": "string"
},
{
"description": "if present, suppress non-error output from the ffx tool itself",
"option": "quiet",
N/A
N/A
N/A
{
"command": "ffx fuzz add",
"options": [
{
"description": "where to send fuzzer logs and artifacts; default is stdout and the current directory",
"option": "output",
"shorthand": "o",
"value_type": "string"
},
{
"description": "if present, suppress non-error output from the ffx tool itself",
"option": "quiet",
N/A
N/A
N/A
{
"command": "ffx fuzz add",
"options": [
{
"description": "where to send fuzzer logs and artifacts; default is stdout and the current directory",
"option": "output",
"shorthand": "o",
"value_type": "string"
},
{
"description": "if present, suppress non-error output from the ffx tool itself",
"option": "quiet",
N/A
N/A
N/A
{
"command": "ffx fuzz add",
"options": [
{
"description": "where to send fuzzer logs and artifacts; default is stdout and the current directory",
"option": "output",
"shorthand": "o",
"value_type": "string"
},
{
"description": "if present, suppress non-error output from the ffx tool itself",
"option": "quiet",
N/A
N/A
N/A
{
"command": "ffx fuzz add",
"options": [
{
"description": "where to send fuzzer logs and artifacts; default is stdout and the current directory",
"option": "output",
"shorthand": "o",
"value_type": "string"
},
{
"description": "if present, suppress non-error output from the ffx tool itself",
"option": "quiet",
N/A
N/A
N/A
{
"command": "ffx fuzz cleanse",
"options": [
{
"description": "where to send fuzzer logs and artifacts; default is stdout and the current directory",
"option": "output",
"shorthand": "o",
"value_type": "string"
},
{
"description": "if present, suppress non-error output from the ffx tool itself",
"option": "quiet",
N/A
N/A
N/A
{
"command": "ffx fuzz cleanse",
"options": [
{
"description": "where to send fuzzer logs and artifacts; default is stdout and the current directory",
"option": "output",
"shorthand": "o",
"value_type": "string"
},
{
"description": "if present, suppress non-error output from the ffx tool itself",
"option": "quiet",
N/A
N/A
N/A
{
"command": "ffx fuzz cleanse",
"options": [
{
"description": "where to send fuzzer logs and artifacts; default is stdout and the current directory",
"option": "output",
"shorthand": "o",
"value_type": "string"
},
{
"description": "if present, suppress non-error output from the ffx tool itself",
"option": "quiet",
N/A
N/A
N/A
{
"command": "ffx fuzz cleanse",
"options": [
{
"description": "where to send fuzzer logs and artifacts; default is stdout and the current directory",
"option": "output",
"shorthand": "o",
"value_type": "string"
},
{
"description": "if present, suppress non-error output from the ffx tool itself",
"option": "quiet",
N/A
N/A
N/A
{
"command": "ffx fuzz cleanse",
"options": [
{
"description": "where to send fuzzer logs and artifacts; default is stdout and the current directory",
"option": "output",
"shorthand": "o",
"value_type": "string"
},
{
"description": "if present, suppress non-error output from the ffx tool itself",
"option": "quiet",
N/A
N/A
N/A
{
"command": "ffx fuzz cleanse",
"options": [
{
"description": "where to send fuzzer logs and artifacts; default is stdout and the current directory",
"option": "output",
"shorthand": "o",
"value_type": "string"
},
{
"description": "if present, suppress non-error output from the ffx tool itself",
"option": "quiet",
N/A
N/A
N/A
{
"command": "ffx fuzz fetch",
"options": [
{
"description": "where to send fuzzer logs and artifacts; default is stdout and the current directory",
"option": "output",
"shorthand": "o",
"value_type": "string"
},
{
"description": "if present, suppress non-error output from the ffx tool itself",
"option": "quiet",
N/A
N/A
N/A
{
"command": "ffx fuzz fetch",
"options": [
{
"description": "where to send fuzzer logs and artifacts; default is stdout and the current directory",
"option": "output",
"shorthand": "o",
"value_type": "string"
},
{
"description": "if present, suppress non-error output from the ffx tool itself",
"option": "quiet",
N/A
N/A
N/A
{
"command": "ffx fuzz fetch",
"options": [
{
"description": "where to send fuzzer logs and artifacts; default is stdout and the current directory",
"option": "output",
"shorthand": "o",
"value_type": "string"
},
{
"description": "if present, suppress non-error output from the ffx tool itself",
"option": "quiet",
N/A
N/A
N/A
{
"command": "ffx fuzz fetch",
"options": [
{
"description": "where to send fuzzer logs and artifacts; default is stdout and the current directory",
"option": "output",
"shorthand": "o",
"value_type": "string"
},
{
"description": "if present, suppress non-error output from the ffx tool itself",
"option": "quiet",
N/A
N/A
N/A
{
"command": "ffx fuzz fetch",
"options": [
{
"description": "where to send fuzzer logs and artifacts; default is stdout and the current directory",
"option": "output",
"shorthand": "o",
"value_type": "string"
},
{
"description": "if present, suppress non-error output from the ffx tool itself",
"option": "quiet",
N/A
N/A
N/A
{
"command": "ffx fuzz fetch",
"options": [
{
"description": "where to send fuzzer logs and artifacts; default is stdout and the current directory",
"option": "output",
"shorthand": "o",
"value_type": "string"
},
{
"description": "if present, suppress non-error output from the ffx tool itself",
"option": "quiet",
N/A
N/A
N/A
{
"command": "ffx fuzz fetch",
"options": [
{
"description": "where to send fuzzer logs and artifacts; default is stdout and the current directory",
"option": "output",
"shorthand": "o",
"value_type": "string"
},
{
"description": "if present, suppress non-error output from the ffx tool itself",
"option": "quiet",
N/A
N/A
N/A
{
"command": "ffx fuzz get",
"options": [
{
"description": "where to send fuzzer logs and artifacts; default is stdout and the current directory",
"option": "output",
"shorthand": "o",
"value_type": "string"
},
{
"description": "if present, suppress non-error output from the ffx tool itself",
"option": "quiet",
N/A
N/A
N/A
{
"command": "ffx fuzz get",
"options": [
{
"description": "where to send fuzzer logs and artifacts; default is stdout and the current directory",
"option": "output",
"shorthand": "o",
"value_type": "string"
},
{
"description": "if present, suppress non-error output from the ffx tool itself",
"option": "quiet",
N/A
N/A
N/A
{
"command": "ffx fuzz get",
"options": [
{
"description": "where to send fuzzer logs and artifacts; default is stdout and the current directory",
"option": "output",
"shorthand": "o",
"value_type": "string"
},
{
"description": "if present, suppress non-error output from the ffx tool itself",
"option": "quiet",
N/A
N/A
N/A
{
"command": "ffx fuzz get",
"options": [
{
"description": "where to send fuzzer logs and artifacts; default is stdout and the current directory",
"option": "output",
"shorthand": "o",
"value_type": "string"
},
{
"description": "if present, suppress non-error output from the ffx tool itself",
"option": "quiet",
N/A
N/A
N/A
{
"command": "ffx fuzz get",
"options": [
{
"description": "where to send fuzzer logs and artifacts; default is stdout and the current directory",
"option": "output",
"shorthand": "o",
"value_type": "string"
},
{
"description": "if present, suppress non-error output from the ffx tool itself",
"option": "quiet",
N/A
N/A
N/A
{
"command": "ffx fuzz get",
"options": [
{
"description": "where to send fuzzer logs and artifacts; default is stdout and the current directory",
"option": "output",
"shorthand": "o",
"value_type": "string"
},
{
"description": "if present, suppress non-error output from the ffx tool itself",
"option": "quiet",
N/A
N/A
N/A
{
"command": "ffx fuzz list",
"options": [
{
"description": "path to JSON file describing fuzzers; looks for tests.json under $FUCHSIA_DIR by default",
"option": "json-file",
"shorthand": "j",
"value_type": "string"
},
{
"description": "list all fuzzers matching shell-style glob pattern; default is to list all fuzzers",
"option": "pattern",
N/A
N/A
N/A
{
"command": "ffx fuzz list",
"options": [
{
"description": "path to JSON file describing fuzzers; looks for tests.json under $FUCHSIA_DIR by default",
"option": "json-file",
"shorthand": "j",
"value_type": "string"
},
{
"description": "list all fuzzers matching shell-style glob pattern; default is to list all fuzzers",
"option": "pattern",
N/A
N/A
N/A
{
"command": "ffx fuzz list",
"options": [
{
"description": "path to JSON file describing fuzzers; looks for tests.json under $FUCHSIA_DIR by default",
"option": "json-file",
"shorthand": "j",
"value_type": "string"
},
{
"description": "list all fuzzers matching shell-style glob pattern; default is to list all fuzzers",
"option": "pattern",
N/A
N/A
N/A
{
"command": "ffx fuzz merge",
"options": [
{
"description": "where to send fuzzer logs and artifacts; default is stdout and the current directory",
"option": "output",
"shorthand": "o",
"value_type": "string"
},
{
"description": "if present, suppress non-error output from the ffx tool itself",
"option": "quiet",
N/A
N/A
N/A
{
"command": "ffx fuzz merge",
"options": [
{
"description": "where to send fuzzer logs and artifacts; default is stdout and the current directory",
"option": "output",
"shorthand": "o",
"value_type": "string"
},
{
"description": "if present, suppress non-error output from the ffx tool itself",
"option": "quiet",
N/A
N/A
N/A
{
"command": "ffx fuzz merge",
"options": [
{
"description": "where to send fuzzer logs and artifacts; default is stdout and the current directory",
"option": "output",
"shorthand": "o",
"value_type": "string"
},
{
"description": "if present, suppress non-error output from the ffx tool itself",
"option": "quiet",
N/A
N/A
N/A
{
"command": "ffx fuzz merge",
"options": [
{
"description": "where to send fuzzer logs and artifacts; default is stdout and the current directory",
"option": "output",
"shorthand": "o",
"value_type": "string"
},
{
"description": "if present, suppress non-error output from the ffx tool itself",
"option": "quiet",
N/A
N/A
N/A
{
"command": "ffx fuzz merge",
"options": [
{
"description": "where to send fuzzer logs and artifacts; default is stdout and the current directory",
"option": "output",
"shorthand": "o",
"value_type": "string"
},
{
"description": "if present, suppress non-error output from the ffx tool itself",
"option": "quiet",
N/A
N/A
N/A
{
"command": "ffx fuzz merge",
"options": [
{
"description": "where to send fuzzer logs and artifacts; default is stdout and the current directory",
"option": "output",
"shorthand": "o",
"value_type": "string"
},
{
"description": "if present, suppress non-error output from the ffx tool itself",
"option": "quiet",
N/A
N/A
N/A
{
"command": "ffx fuzz minimize",
"options": [
{
"description": "where to send fuzzer logs and artifacts; default is stdout and the current directory",
"option": "output",
"shorthand": "o",
"value_type": "string"
},
{
"description": "if present, suppress non-error output from the ffx tool itself",
"option": "quiet",
N/A
N/A
N/A
{
"command": "ffx fuzz minimize",
"options": [
{
"description": "where to send fuzzer logs and artifacts; default is stdout and the current directory",
"option": "output",
"shorthand": "o",
"value_type": "string"
},
{
"description": "if present, suppress non-error output from the ffx tool itself",
"option": "quiet",
N/A
N/A
N/A
{
"command": "ffx fuzz minimize",
"options": [
{
"description": "where to send fuzzer logs and artifacts; default is stdout and the current directory",
"option": "output",
"shorthand": "o",
"value_type": "string"
},
{
"description": "if present, suppress non-error output from the ffx tool itself",
"option": "quiet",
N/A
N/A
N/A
{
"command": "ffx fuzz minimize",
"options": [
{
"description": "where to send fuzzer logs and artifacts; default is stdout and the current directory",
"option": "output",
"shorthand": "o",
"value_type": "string"
},
{
"description": "if present, suppress non-error output from the ffx tool itself",
"option": "quiet",
N/A
N/A
N/A
{
"command": "ffx fuzz minimize",
"options": [
{
"description": "where to send fuzzer logs and artifacts; default is stdout and the current directory",
"option": "output",
"shorthand": "o",
"value_type": "string"
},
{
"description": "if present, suppress non-error output from the ffx tool itself",
"option": "quiet",
N/A
N/A
N/A
{
"command": "ffx fuzz minimize",
"options": [
{
"description": "where to send fuzzer logs and artifacts; default is stdout and the current directory",
"option": "output",
"shorthand": "o",
"value_type": "string"
},
{
"description": "if present, suppress non-error output from the ffx tool itself",
"option": "quiet",
N/A
N/A
N/A
{
"command": "ffx fuzz minimize",
"options": [
{
"description": "where to send fuzzer logs and artifacts; default is stdout and the current directory",
"option": "output",
"shorthand": "o",
"value_type": "string"
},
{
"description": "if present, suppress non-error output from the ffx tool itself",
"option": "quiet",
N/A
N/A
N/A
{
"command": "ffx fuzz minimize",
"options": [
{
"description": "where to send fuzzer logs and artifacts; default is stdout and the current directory",
"option": "output",
"shorthand": "o",
"value_type": "string"
},
{
"description": "if present, suppress non-error output from the ffx tool itself",
"option": "quiet",
N/A
N/A
N/A
{
"command": "ffx fuzz run",
"options": [
{
"description": "where to send fuzzer logs and artifacts; default is stdout and the current directory",
"option": "output",
"shorthand": "o",
"value_type": "string"
},
{
"description": "if present, suppress non-error output from the ffx tool itself",
"option": "quiet",
N/A
N/A
N/A
{
"command": "ffx fuzz run",
"options": [
{
"description": "where to send fuzzer logs and artifacts; default is stdout and the current directory",
"option": "output",
"shorthand": "o",
"value_type": "string"
},
{
"description": "if present, suppress non-error output from the ffx tool itself",
"option": "quiet",
N/A
N/A
N/A
{
"command": "ffx fuzz run",
"options": [
{
"description": "where to send fuzzer logs and artifacts; default is stdout and the current directory",
"option": "output",
"shorthand": "o",
"value_type": "string"
},
{
"description": "if present, suppress non-error output from the ffx tool itself",
"option": "quiet",
N/A
N/A
N/A
{
"command": "ffx fuzz run",
"options": [
{
"description": "where to send fuzzer logs and artifacts; default is stdout and the current directory",
"option": "output",
"shorthand": "o",
"value_type": "string"
},
{
"description": "if present, suppress non-error output from the ffx tool itself",
"option": "quiet",
N/A
N/A
N/A
{
"command": "ffx fuzz run",
"options": [
{
"description": "where to send fuzzer logs and artifacts; default is stdout and the current directory",
"option": "output",
"shorthand": "o",
"value_type": "string"
},
{
"description": "if present, suppress non-error output from the ffx tool itself",
"option": "quiet",
N/A
N/A
N/A
{
"command": "ffx fuzz run",
"options": [
{
"description": "where to send fuzzer logs and artifacts; default is stdout and the current directory",
"option": "output",
"shorthand": "o",
"value_type": "string"
},
{
"description": "if present, suppress non-error output from the ffx tool itself",
"option": "quiet",
N/A
N/A
N/A
{
"command": "ffx fuzz run",
"options": [
{
"description": "where to send fuzzer logs and artifacts; default is stdout and the current directory",
"option": "output",
"shorthand": "o",
"value_type": "string"
},
{
"description": "if present, suppress non-error output from the ffx tool itself",
"option": "quiet",
N/A
N/A
N/A
{
"command": "ffx fuzz run",
"options": [
{
"description": "where to send fuzzer logs and artifacts; default is stdout and the current directory",
"option": "output",
"shorthand": "o",
"value_type": "string"
},
{
"description": "if present, suppress non-error output from the ffx tool itself",
"option": "quiet",
N/A
N/A
N/A
{
"command": "ffx fuzz set",
"options": [
{
"description": "where to send fuzzer logs and artifacts; default is stdout and the current directory",
"option": "output",
"shorthand": "o",
"value_type": "string"
},
{
"description": "if present, suppress non-error output from the ffx tool itself",
"option": "quiet",
N/A
N/A
N/A
{
"command": "ffx fuzz set",
"options": [
{
"description": "where to send fuzzer logs and artifacts; default is stdout and the current directory",
"option": "output",
"shorthand": "o",
"value_type": "string"
},
{
"description": "if present, suppress non-error output from the ffx tool itself",
"option": "quiet",
N/A
N/A
N/A
{
"command": "ffx fuzz set",
"options": [
{
"description": "where to send fuzzer logs and artifacts; default is stdout and the current directory",
"option": "output",
"shorthand": "o",
"value_type": "string"
},
{
"description": "if present, suppress non-error output from the ffx tool itself",
"option": "quiet",
N/A
N/A
N/A
{
"command": "ffx fuzz set",
"options": [
{
"description": "where to send fuzzer logs and artifacts; default is stdout and the current directory",
"option": "output",
"shorthand": "o",
"value_type": "string"
},
{
"description": "if present, suppress non-error output from the ffx tool itself",
"option": "quiet",
N/A
N/A
N/A
{
"command": "ffx fuzz set",
"options": [
{
"description": "where to send fuzzer logs and artifacts; default is stdout and the current directory",
"option": "output",
"shorthand": "o",
"value_type": "string"
},
{
"description": "if present, suppress non-error output from the ffx tool itself",
"option": "quiet",
N/A
N/A
N/A
{
"command": "ffx fuzz set",
"options": [
{
"description": "where to send fuzzer logs and artifacts; default is stdout and the current directory",
"option": "output",
"shorthand": "o",
"value_type": "string"
},
{
"description": "if present, suppress non-error output from the ffx tool itself",
"option": "quiet",
N/A
N/A
N/A
{
"command": "ffx fuzz shell",
"options": [
{
"description": "path to JSON file describing fuzzers; looks for tests.json under $FUCHSIA_DIR by default",
"option": "json-file",
"shorthand": "j",
"value_type": "string"
}
],
"short": "Starts an interactive fuzzing session."
}
#[fuchsia::test]
async fn test_empty() -> Result<()> {
let env = ffx_config::test_init()?;
let mut test = Test::try_new()?;
let mut script = ShellScript::try_new(&mut test)?;
script.add(&mut test, "");
script.add(&mut test, " ");
script.add(&mut test, "# a comment");
script.add(&mut test, " # another comment");
script.run(&env.context, &mut test).await?;
test.verify_output()
}
#[fuchsia::test]
async fn test_invalid() -> Result<()> {
let env = ffx_config::test_init()?;
let mut test = Test::try_new()?;
let mut script = ShellScript::try_new(&mut test)?;
script.add(&mut test, "foobar");
test.output_includes("Unrecognized argument: foobar");
test.output_matches("Command is unrecognized or invalid for the current state.");
test.output_matches("Try 'help' to list recognized.");
test.output_matches("Try 'status' to check the current state.");
script.run(&env.context, &mut test).await?;
test.verify_output()
}
#[fuchsia::test]
async fn test_list() -> Result<()> {
let env = ffx_config::test_init()?;
let mut test = Test::try_new()?;
let mut script = ShellScript::try_new(&mut test)?;
// Can 'list' when detached. Try both empty and non-empty lists of URLs.
let urls: Vec<&str> = vec![];
test.create_tests_json(urls.iter())?;
script.add(&mut test, "list");
test.output_matches("Empty list: did you include '-fuzz-with' in your 'fx set' command ?");
test.output_matches("[]");
script.run(&env.context, &mut test).await?;
test.verify_output()?;
let mut script = ShellScript::try_new(&mut test)?;
let urls = vec![
"fuchsia-pkg://fuchsia.com/test-fuzzers#meta/foo-fuzzer.cm",
"fuchsia-pkg://fuchsia.com/test-fuzzers#meta/bar-fuzzer.cm",
"fuchsia-pkg://fuchsia.com/test-fuzzers#meta/baz-fuzzer.cm",
];
test.create_tests_json(urls.iter())?;
script.add(&mut test, "list");
test.output_matches("[");
test.output_matches(format!("\"{}\",", urls[0]));
test.output_matches(format!("\"{}\",", urls[1]));
test.output_matches(format!("\"{}\"", urls[2]));
test.output_matches("]");
script.run(&env.context, &mut test).await?;
N/A
N/A
{
"command": "ffx fuzz shell",
"options": [
{
"description": "path to JSON file describing fuzzers; looks for tests.json under $FUCHSIA_DIR by default",
"option": "json-file",
"shorthand": "j",
"value_type": "string"
}
],
"short": "Starts an interactive fuzzing session."
}
N/A
N/A
N/A
{
"command": "ffx fuzz status",
"options": [
{
"description": "where to send fuzzer logs and artifacts; default is stdout and the current directory",
"option": "output",
"shorthand": "o",
"value_type": "string"
},
{
"description": "if present, suppress non-error output from the ffx tool itself",
"option": "quiet",
N/A
N/A
N/A
{
"command": "ffx fuzz status",
"options": [
{
"description": "where to send fuzzer logs and artifacts; default is stdout and the current directory",
"option": "output",
"shorthand": "o",
"value_type": "string"
},
{
"description": "if present, suppress non-error output from the ffx tool itself",
"option": "quiet",
N/A
N/A
N/A
{
"command": "ffx fuzz status",
"options": [
{
"description": "where to send fuzzer logs and artifacts; default is stdout and the current directory",
"option": "output",
"shorthand": "o",
"value_type": "string"
},
{
"description": "if present, suppress non-error output from the ffx tool itself",
"option": "quiet",
N/A
N/A
N/A
{
"command": "ffx fuzz status",
"options": [
{
"description": "where to send fuzzer logs and artifacts; default is stdout and the current directory",
"option": "output",
"shorthand": "o",
"value_type": "string"
},
{
"description": "if present, suppress non-error output from the ffx tool itself",
"option": "quiet",
N/A
N/A
N/A
{
"command": "ffx fuzz status",
"options": [
{
"description": "where to send fuzzer logs and artifacts; default is stdout and the current directory",
"option": "output",
"shorthand": "o",
"value_type": "string"
},
{
"description": "if present, suppress non-error output from the ffx tool itself",
"option": "quiet",
N/A
N/A
N/A
{
"command": "ffx fuzz status",
"options": [
{
"description": "where to send fuzzer logs and artifacts; default is stdout and the current directory",
"option": "output",
"shorthand": "o",
"value_type": "string"
},
{
"description": "if present, suppress non-error output from the ffx tool itself",
"option": "quiet",
N/A
N/A
N/A
{
"command": "ffx fuzz stop",
"options": [
{
"description": "if present, suppress non-error output from the ffx tool itself",
"option": "quiet",
"shorthand": "q",
"value_type": "bool"
}
],
"short": "Stops a fuzzer."
}
N/A
N/A
N/A
{
"command": "ffx fuzz stop",
"options": [
{
"description": "if present, suppress non-error output from the ffx tool itself",
"option": "quiet",
"shorthand": "q",
"value_type": "bool"
}
],
"short": "Stops a fuzzer."
}
N/A
N/A
N/A
{
"command": "ffx fuzz try",
"options": [
{
"description": "where to send fuzzer logs and artifacts; default is stdout and the current directory",
"option": "output",
"shorthand": "o",
"value_type": "string"
},
{
"description": "if present, suppress non-error output from the ffx tool itself",
"option": "quiet",
N/A
N/A
N/A
{
"command": "ffx fuzz try",
"options": [
{
"description": "where to send fuzzer logs and artifacts; default is stdout and the current directory",
"option": "output",
"shorthand": "o",
"value_type": "string"
},
{
"description": "if present, suppress non-error output from the ffx tool itself",
"option": "quiet",
N/A
N/A
N/A
{
"command": "ffx fuzz try",
"options": [
{
"description": "where to send fuzzer logs and artifacts; default is stdout and the current directory",
"option": "output",
"shorthand": "o",
"value_type": "string"
},
{
"description": "if present, suppress non-error output from the ffx tool itself",
"option": "quiet",
N/A
N/A
N/A
{
"command": "ffx fuzz try",
"options": [
{
"description": "where to send fuzzer logs and artifacts; default is stdout and the current directory",
"option": "output",
"shorthand": "o",
"value_type": "string"
},
{
"description": "if present, suppress non-error output from the ffx tool itself",
"option": "quiet",
N/A
N/A
N/A
{
"command": "ffx fuzz try",
"options": [
{
"description": "where to send fuzzer logs and artifacts; default is stdout and the current directory",
"option": "output",
"shorthand": "o",
"value_type": "string"
},
{
"description": "if present, suppress non-error output from the ffx tool itself",
"option": "quiet",
N/A
N/A
N/A
{
"command": "ffx fuzz try",
"options": [
{
"description": "where to send fuzzer logs and artifacts; default is stdout and the current directory",
"option": "output",
"shorthand": "o",
"value_type": "string"
},
{
"description": "if present, suppress non-error output from the ffx tool itself",
"option": "quiet",
N/A
N/A
N/A
{
"command": "ffx guest",
"options": [],
"short": "Manage guest operating systems"
}
N/A
N/A
N/A
{
"command": "ffx inspect",
"options": [],
"short": "Query data exposed by components via the Inspect API."
}
inspect_data_json_str: str = self.ffx.run(
cmd=cmd,
log_output=False,
)
_LOGGER.info(
"Collected the inspect data from %s.", self.device_name
)
inspect_data_json_obj: list[dict[str, Any]] = json.loads(
inspect_data_json_str
)
return fuchsia_inspect.InspectDataCollection.from_list(
inspect_data_json_obj
)
except (
ffx_errors.FfxCommandError,
errors.DeviceNotConnectedError,
fuchsia_inspect.InspectDataError,
) as err:
raise errors.InspectError(
f"Failed to collect the inspect data from {self.device_name}"
txt_output = self._ffx.run(
cmd=["--machine", "json", "inspect", "show", selector],
log_output=False,
)
json_output: list[dict[str, Any]] = json.loads(txt_output)
return json_output
def show_from_component(
self,
component_query: str,
) -> list[dict[str, Any]]:
"""Issues an `ffx inspect show [manifest]` command, returning the parsed json output"""
# This creates a lot of log spam: b/326273353
txt_output = self._ffx.run(
cmd=[
"--machine",
"json",
"inspect",
"show",
component_query,
],
log_output=False,
)
json_output: list[dict[str, Any]] = json.loads(txt_output)
return json_output
def show_text(self, selector: str) -> str:
"""Issues an `ffx inspect show [selector]` command, returning the parsed json output"""
# This creates a lot of log spam: b/326273353
return self._ffx.run(
txt_output = self._ffx.run(
cmd=[
"--machine",
"json",
"inspect",
"show",
component_query,
],
log_output=False,
)
json_output: list[dict[str, Any]] = json.loads(txt_output)
return json_output
def show_text(self, selector: str) -> str:
"""Issues an `ffx inspect show [selector]` command, returning the parsed json output"""
# This creates a lot of log spam: b/326273353
return self._ffx.run(
cmd=["inspect", "show", selector],
log_output=False,
)
N/A
N/A
{
"command": "ffx inspect apply-selectors",
"options": [
{
"description": "path to the inspect json file to read this file contains inspect.json data from snapshot.zip. If not provided, DiagnosticsProvider will be used to get inspect data.",
"option": "snapshot-file",
"shorthand": "",
"value_type": "string"
},
{
"description": "moniker of the component to apply the command.",
"option": "moniker",
N/A
N/A
N/A
{
"command": "ffx inspect apply-selectors",
"options": [
{
"description": "path to the inspect json file to read this file contains inspect.json data from snapshot.zip. If not provided, DiagnosticsProvider will be used to get inspect data.",
"option": "snapshot-file",
"shorthand": "",
"value_type": "string"
},
{
"description": "moniker of the component to apply the command.",
"option": "moniker",
N/A
N/A
N/A
{
"command": "ffx inspect apply-selectors",
"options": [
{
"description": "path to the inspect json file to read this file contains inspect.json data from snapshot.zip. If not provided, DiagnosticsProvider will be used to get inspect data.",
"option": "snapshot-file",
"shorthand": "",
"value_type": "string"
},
{
"description": "moniker of the component to apply the command.",
"option": "moniker",
N/A
N/A
N/A
{
"command": "ffx inspect apply-selectors",
"options": [
{
"description": "path to the inspect json file to read this file contains inspect.json data from snapshot.zip. If not provided, DiagnosticsProvider will be used to get inspect data.",
"option": "snapshot-file",
"shorthand": "",
"value_type": "string"
},
{
"description": "moniker of the component to apply the command.",
"option": "moniker",
N/A
N/A
N/A
{
"command": "ffx inspect list",
"options": [
{
"description": "a fuzzy-search query. May include URL, moniker, or manifest fragments. a fauzzy-search query for the component we are interested in. May include URL, moniker, or manifest fragments. If this is provided, the output will only contain monikers for components that matched the query.",
"option": "component",
"shorthand": "",
"value_type": "string"
},
{
"description": "also print the URL of the component.",
"option": "with-url",
#[fuchsia::test]
async fn test_list_empty() {
let params = StreamParameters {
stream_mode: Some(StreamMode::Snapshot),
data_type: Some(DataType::Inspect),
format: Some(fdomain_fuchsia_diagnostics::Format::Json),
client_selector_configuration: Some(ClientSelectorConfiguration::SelectAll(true)),
..Default::default()
};
let expected_responses = Rc::new(vec![]);
let test_buffers = TestBuffers::default();
let mut writer = MachineWriter::new_test(Some(Format::Json), &test_buffers);
let cmd = ListCommand { component: None, with_url: false, accessor: None };
let client = fdomain_local::local_client_empty();
let rcs_proxy = setup_fake_rcs(client.clone(), vec![]);
let accessor_proxy = setup_fake_archive_accessor(
client,
vec![FakeAccessorData::new(params, expected_responses.clone())],
);
run_command(rcs_proxy, accessor_proxy, ListCommand::from(cmd), &mut writer).await.unwrap();
let output = test_buffers.into_stdout_str();
assert_eq!(output.trim_end(), String::from("[]"));
}
#[fuchsia::test]
async fn test_list_with_data() {
let params = StreamParameters {
stream_mode: Some(StreamMode::Snapshot),
data_type: Some(DataType::Inspect),
format: Some(fdomain_fuchsia_diagnostics::Format::Json),
client_selector_configuration: Some(ClientSelectorConfiguration::SelectAll(true)),
..Default::default()
};
let lifecycles = make_inspects_for_lifecycle();
let value = serde_json::to_string(&lifecycles).unwrap();
let expected_responses = Rc::new(vec![FakeArchiveIteratorResponse::new_with_value(value)]);
let test_buffers = TestBuffers::default();
let mut writer = MachineWriter::new_test(Some(Format::Json), &test_buffers);
let cmd = ListCommand { component: None, with_url: false, accessor: None };
let client = fdomain_local::local_client_empty();
let rcs_proxy = setup_fake_rcs(client.clone(), vec![]);
let accessor_proxy = setup_fake_archive_accessor(
client,
vec![FakeAccessorData::new(params, expected_responses.clone())],
);
run_command(rcs_proxy, accessor_proxy, ListCommand::from(cmd), &mut writer).await.unwrap();
let expected =
serde_json::to_string(&vec![String::from("test/moniker1"), String::from("test/moniker3")])
.unwrap();
let output = test_buffers.into_stdout_str();
assert_eq!(output.trim_end(), expected);
}
#[fuchsia::test]
async fn test_list_with_data_with_url() {
let params = StreamParameters {
stream_mode: Some(StreamMode::Snapshot),
data_type: Some(DataType::Inspect),
format: Some(fdomain_fuchsia_diagnostics::Format::Json),
client_selector_configuration: Some(ClientSelectorConfiguration::SelectAll(true)),
..Default::default()
};
let lifecycles = make_inspects_for_lifecycle();
let value = serde_json::to_string(&lifecycles).unwrap();
let expected_responses = Rc::new(vec![FakeArchiveIteratorResponse::new_with_value(value)]);
let test_buffers = TestBuffers::default();
let mut writer = MachineWriter::new_test(Some(Format::Json), &test_buffers);
let cmd = ListCommand { component: None, with_url: true, accessor: None };
let client = fdomain_local::local_client_empty();
let rcs_proxy = setup_fake_rcs(client.clone(), vec![]);
let accessor_proxy = setup_fake_archive_accessor(
client,
vec![FakeAccessorData::new(params, expected_responses.clone())],
);
run_command(rcs_proxy, accessor_proxy, ListCommand::from(cmd), &mut writer).await.unwrap();
let expected = serde_json::to_string(&vec![
iquery_fdomain::commands::MonikerWithUrl {
moniker: String::from("test/moniker1"),
component_url: String::from("fake-url://test/moniker1"),
},
iquery_fdomain::commands::MonikerWithUrl {
N/A
N/A
{
"command": "ffx inspect list",
"options": [
{
"description": "a fuzzy-search query. May include URL, moniker, or manifest fragments. a fauzzy-search query for the component we are interested in. May include URL, moniker, or manifest fragments. If this is provided, the output will only contain monikers for components that matched the query.",
"option": "component",
"shorthand": "",
"value_type": "string"
},
{
"description": "also print the URL of the component.",
"option": "with-url",
N/A
N/A
N/A
{
"command": "ffx inspect list",
"options": [
{
"description": "a fuzzy-search query. May include URL, moniker, or manifest fragments. a fauzzy-search query for the component we are interested in. May include URL, moniker, or manifest fragments. If this is provided, the output will only contain monikers for components that matched the query.",
"option": "component",
"shorthand": "",
"value_type": "string"
},
{
"description": "also print the URL of the component.",
"option": "with-url",
N/A
N/A
N/A
{
"command": "ffx inspect list",
"options": [
{
"description": "a fuzzy-search query. May include URL, moniker, or manifest fragments. a fauzzy-search query for the component we are interested in. May include URL, moniker, or manifest fragments. If this is provided, the output will only contain monikers for components that matched the query.",
"option": "component",
"shorthand": "",
"value_type": "string"
},
{
"description": "also print the URL of the component.",
"option": "with-url",
N/A
N/A
N/A
{
"command": "ffx inspect list-accessors",
"options": [],
"short": "Lists all available ArchiveAccessor in the system and their selector for use in \"accessor\" arguments in other sub-commands."
}
#[fuchsia::test]
async fn test_list_accessors() {
let test_buffers = TestBuffers::default();
let mut writer = MachineWriter::new_test(Some(Format::Json), &test_buffers);
let cmd = ListAccessorsCommand {};
let client = fdomain_local::local_client_empty();
let rcs_proxy = setup_fake_rcs(client.clone(), vec![]);
let accessor_proxy = setup_fake_archive_accessor(client, vec![]);
run_command(rcs_proxy, accessor_proxy, ListAccessorsCommand::from(cmd), &mut writer)
.await
.unwrap();
let expected = serde_json::to_string(&vec![
String::from("example/component:fuchsia.diagnostics.ArchiveAccessor"),
String::from("foo/bar/thing:instance:fuchsia.diagnostics.ArchiveAccessor.feedback"),
String::from("foo/component:fuchsia.diagnostics.ArchiveAccessor.feedback"),
])
.unwrap();
let output = test_buffers.into_stdout_str();
assert_eq!(output.trim_end(), expected);
}
N/A
N/A
{
"command": "ffx inspect selectors",
"options": [
{
"description": "tree selectors to splice onto a component query specified as a positional argument For example, `show foo.cm --data root:bar` becomes the selector `path/to/foo:root:bar`.",
"option": "data",
"shorthand": "",
"value_type": "string"
},
{
"description": "a string specifying what `fuchsia.diagnostics.ArchiveAccessor` to connect to. This can be copied from the output of `ffx inspect list-accessors`. The selector will be in the form of: <moniker>:fuchsia.diagnostics.ArchiveAccessor.pipeline_name",
"option": "accessor",
#[fuchsia::test]
async fn test_selectors_no_parameters() {
let params = StreamParameters {
stream_mode: Some(StreamMode::Snapshot),
data_type: Some(DataType::Inspect),
client_selector_configuration: Some(ClientSelectorConfiguration::SelectAll(true)),
..Default::default()
};
let expected_responses = Rc::new(vec![]);
let test_buffers = TestBuffers::default();
let mut writer = MachineWriter::new_test(Some(Format::Json), &test_buffers);
let cmd = SelectorsCommand { data: vec![], selectors: vec![], accessor: None };
let client = fdomain_local::local_client_empty();
let rcs_proxy = setup_fake_rcs(client.clone(), vec![]);
let accessor_proxy = setup_fake_archive_accessor(
client,
vec![FakeAccessorData::new(params, expected_responses.clone())],
);
assert!(
run_command(rcs_proxy, accessor_proxy, SelectorsCommand::from(cmd), &mut writer)
.await
.unwrap_err()
.ffx_error()
.is_some()
);
}
#[fuchsia::test]
async fn test_selectors_with_unknown_component_search() {
let params = StreamParameters {
stream_mode: Some(StreamMode::Snapshot),
data_type: Some(DataType::Inspect),
format: Some(fdomain_fuchsia_diagnostics::Format::Json),
client_selector_configuration: Some(ClientSelectorConfiguration::SelectAll(true)),
..Default::default()
};
let expected_responses = Rc::new(vec![]);
let test_buffers = TestBuffers::default();
let mut writer = MachineWriter::new_test(Some(Format::Json), &test_buffers);
let cmd = SelectorsCommand {
selectors: vec!["some-bad-moniker".to_string()],
accessor: None,
data: vec![],
};
let client = fdomain_local::local_client_empty();
let rcs_proxy = setup_fake_rcs(client.clone(), vec![]);
let accessor_proxy = setup_fake_archive_accessor(
client,
vec![FakeAccessorData::new(params, expected_responses.clone())],
);
assert!(
run_command(rcs_proxy, accessor_proxy, SelectorsCommand::from(cmd), &mut writer)
.await
.unwrap_err()
.ffx_error()
.is_some()
#[fuchsia::test]
async fn test_selectors_with_unknown_manifest() {
let params = StreamParameters {
stream_mode: Some(StreamMode::Snapshot),
data_type: Some(DataType::Inspect),
format: Some(fdomain_fuchsia_diagnostics::Format::Json),
client_selector_configuration: Some(ClientSelectorConfiguration::SelectAll(true)),
..Default::default()
};
let expected_responses = Rc::new(vec![]);
let test_buffers = TestBuffers::default();
let mut writer = MachineWriter::new_test(Some(Format::Json), &test_buffers);
let cmd = SelectorsCommand {
selectors: vec!["some-bad-moniker".to_string()],
accessor: None,
data: vec![],
};
let client = fdomain_local::local_client_empty();
let rcs_proxy = setup_fake_rcs(client.clone(), vec![]);
let accessor_proxy = setup_fake_archive_accessor(
client,
vec![FakeAccessorData::new(params, expected_responses.clone())],
);
assert!(
run_command(rcs_proxy, accessor_proxy, SelectorsCommand::from(cmd), &mut writer)
.await
.unwrap_err()
.ffx_error()
.is_some()
N/A
N/A
{
"command": "ffx inspect selectors",
"options": [
{
"description": "tree selectors to splice onto a component query specified as a positional argument For example, `show foo.cm --data root:bar` becomes the selector `path/to/foo:root:bar`.",
"option": "data",
"shorthand": "",
"value_type": "string"
},
{
"description": "a string specifying what `fuchsia.diagnostics.ArchiveAccessor` to connect to. This can be copied from the output of `ffx inspect list-accessors`. The selector will be in the form of: <moniker>:fuchsia.diagnostics.ArchiveAccessor.pipeline_name",
"option": "accessor",
N/A
N/A
N/A
{
"command": "ffx inspect selectors",
"options": [
{
"description": "tree selectors to splice onto a component query specified as a positional argument For example, `show foo.cm --data root:bar` becomes the selector `path/to/foo:root:bar`.",
"option": "data",
"shorthand": "",
"value_type": "string"
},
{
"description": "a string specifying what `fuchsia.diagnostics.ArchiveAccessor` to connect to. This can be copied from the output of `ffx inspect list-accessors`. The selector will be in the form of: <moniker>:fuchsia.diagnostics.ArchiveAccessor.pipeline_name",
"option": "accessor",
N/A
N/A
N/A
{
"command": "ffx inspect show",
"options": [
{
"description": "tree selectors to splice onto a component query specified as a positional argument For example, `show foo.cm --data root:bar` becomes the selector `path/to/foo:root:bar`.",
"option": "data",
"shorthand": "",
"value_type": "string"
},
{
"description": "string specifying what `fuchsia.diagnostics.ArchiveAccessor` to connect to. This can be copied from the output of `ffx inspect list-accessors`. The selector will be in the form of: <moniker>:fuchsia.diagnostics.ArchiveAccessorName",
"option": "accessor",
#[fuchsia::test]
async fn test_show_no_parameters() {
let test_buffers = TestBuffers::default();
let mut writer = MachineWriter::new_test(Some(Format::Json), &test_buffers);
let cmd = ShowCommand { data: vec![], selectors: vec![], accessor: None, name: None };
let mut inspects = make_inspects();
let inspect_data =
inspect_accessor_data(ClientSelectorConfiguration::SelectAll(true), inspects.clone());
let client = fdomain_local::local_client_empty();
let rcs_proxy = setup_fake_rcs(client.clone(), vec![]);
let accessor_proxy = setup_fake_archive_accessor(client, vec![inspect_data]);
run_command(rcs_proxy, accessor_proxy, ShowCommand::from(cmd), &mut writer).await.unwrap();
inspects.sort_by(|a, b| a.moniker.cmp(&b.moniker));
let expected = serde_json::to_string(&inspects).unwrap();
let output = test_buffers.into_stdout_str();
assert_eq!(output.trim_end(), expected);
}
#[fuchsia::test]
async fn test_show_unknown_component_search() {
let test_buffers = TestBuffers::default();
let mut writer = MachineWriter::new_test(Some(Format::Json), &test_buffers);
let cmd = ShowCommand {
data: vec![],
selectors: vec!["some-bad-moniker".to_string()],
accessor: None,
name: None,
};
let lifecycle_data = inspect_accessor_data(
ClientSelectorConfiguration::SelectAll(true),
make_inspects_for_lifecycle(),
);
let inspects = make_inspects();
let inspect_data =
inspect_accessor_data(ClientSelectorConfiguration::SelectAll(true), inspects.clone());
let client = fdomain_local::local_client_empty();
let rcs_proxy = setup_fake_rcs(client.clone(), vec![]);
let accessor_proxy = setup_fake_archive_accessor(client, vec![lifecycle_data, inspect_data]);
assert!(
run_command(rcs_proxy, accessor_proxy, ShowCommand::from(cmd), &mut writer)
.await
.unwrap_err()
.ffx_error()
.is_some()
);
}
#[fuchsia::test]
async fn test_show_unknown_manifest() {
let test_buffers = TestBuffers::default();
let mut writer = MachineWriter::new_test(Some(Format::Json), &test_buffers);
let cmd = ShowCommand {
data: vec![],
selectors: vec!["some-bad-moniker".to_string()],
accessor: None,
name: None,
};
let lifecycle_data = inspect_accessor_data(
ClientSelectorConfiguration::SelectAll(true),
make_inspects_for_lifecycle(),
);
let inspects = make_inspects();
let inspect_data =
inspect_accessor_data(ClientSelectorConfiguration::SelectAll(true), inspects.clone());
let client = fdomain_local::local_client_empty();
let rcs_proxy = setup_fake_rcs(client.clone(), vec![]);
let accessor_proxy = setup_fake_archive_accessor(client, vec![lifecycle_data, inspect_data]);
assert!(
run_command(rcs_proxy, accessor_proxy, ShowCommand::from(cmd), &mut writer)
.await
.unwrap_err()
.ffx_error()
.is_some()
);
}
N/A
N/A
{
"command": "ffx inspect show",
"options": [
{
"description": "tree selectors to splice onto a component query specified as a positional argument For example, `show foo.cm --data root:bar` becomes the selector `path/to/foo:root:bar`.",
"option": "data",
"shorthand": "",
"value_type": "string"
},
{
"description": "string specifying what `fuchsia.diagnostics.ArchiveAccessor` to connect to. This can be copied from the output of `ffx inspect list-accessors`. The selector will be in the form of: <moniker>:fuchsia.diagnostics.ArchiveAccessorName",
"option": "accessor",
N/A
N/A
N/A
{
"command": "ffx inspect show",
"options": [
{
"description": "tree selectors to splice onto a component query specified as a positional argument For example, `show foo.cm --data root:bar` becomes the selector `path/to/foo:root:bar`.",
"option": "data",
"shorthand": "",
"value_type": "string"
},
{
"description": "string specifying what `fuchsia.diagnostics.ArchiveAccessor` to connect to. This can be copied from the output of `ffx inspect list-accessors`. The selector will be in the form of: <moniker>:fuchsia.diagnostics.ArchiveAccessorName",
"option": "accessor",
N/A
N/A
N/A
{
"command": "ffx inspect show",
"options": [
{
"description": "tree selectors to splice onto a component query specified as a positional argument For example, `show foo.cm --data root:bar` becomes the selector `path/to/foo:root:bar`.",
"option": "data",
"shorthand": "",
"value_type": "string"
},
{
"description": "string specifying what `fuchsia.diagnostics.ArchiveAccessor` to connect to. This can be copied from the output of `ffx inspect list-accessors`. The selector will be in the form of: <moniker>:fuchsia.diagnostics.ArchiveAccessorName",
"option": "accessor",
N/A
N/A
N/A
{
"command": "ffx log",
"options": [
{
"description": "filter for a string in either the message, component or url. May be repeated.",
"option": "filter",
"shorthand": "",
"value_type": "string"
},
{
"description": "DEPRECATED: use --component",
"option": "moniker",
This means that when you view logs using `ffx log`, logs are actually read from the cache on the host machine, not directly from the target device. In general, this should not add any noticeable delay to the log viewer, except in rare cases where the device is producing extremely large log volumes.
Log filters modify how the captured logs are displayed by `ffx log`, but they do not affect the log entries emitted by components on the target device. Use the `--set-severity` option to send a request to configure the [log settings][fidl-logsettings] of specific components during the logging session. This adjusts the log level applied to any component matching the provided [component selector][component-select] for recording logs.
#[test]
fn display_x_most_recent_from_many_logs() {
let mut tmp = tempfile::NamedTempFile::new().unwrap();
write_log(&mut tmp, 1..20);
let mut log_file = LogFile::new(tmp.path());
let mut actual = vec![];
log_file.write_all_tail(&mut actual, 10).unwrap();
let mut expected = vec![];
write_log(&mut expected, 10..20);
assert_eq!(std::str::from_utf8(&actual).unwrap(), std::str::from_utf8(&expected).unwrap());
}
#[test]
fn display_0_most_recent_from_many_logs() {
let mut tmp = tempfile::NamedTempFile::new().unwrap();
write_log(&mut tmp, 1..20);
let mut log_file = LogFile::new(tmp.path());
let mut actual = vec![];
log_file.write_all_tail(&mut actual, 0).unwrap();
assert_eq!(std::str::from_utf8(&actual).unwrap(), "");
}
#[fuchsia::test]
async fn display_x_most_recent_from_not_enough_logs() {
let mut tmp = tempfile::NamedTempFile::new().unwrap();
write_log(&mut tmp, 1..5);
let mut log_file = LogFile::new(tmp.path());
let mut actual = vec![];
log_file.write_all_tail(&mut actual, 10).unwrap();
let mut expected = vec![];
write_log(&mut expected, 1..5);
assert_eq!(std::str::from_utf8(&actual).unwrap(), std::str::from_utf8(&expected).unwrap());
}
N/A
{
"command": "ffx log",
"options": [
{
"description": "filter for a string in either the message, component or url. May be repeated.",
"option": "filter",
"shorthand": "",
"value_type": "string"
},
{
"description": "DEPRECATED: use --component",
"option": "moniker",
N/A
N/A
N/A
{
"command": "ffx log",
"options": [
{
"description": "filter for a string in either the message, component or url. May be repeated.",
"option": "filter",
"shorthand": "",
"value_type": "string"
},
{
"description": "DEPRECATED: use --component",
"option": "moniker",
N/A
N/A
N/A
{
"command": "ffx log",
"options": [
{
"description": "filter for a string in either the message, component or url. May be repeated.",
"option": "filter",
"shorthand": "",
"value_type": "string"
},
{
"description": "DEPRECATED: use --component",
"option": "moniker",
N/A
N/A
N/A
{
"command": "ffx log",
"options": [
{
"description": "filter for a string in either the message, component or url. May be repeated.",
"option": "filter",
"shorthand": "",
"value_type": "string"
},
{
"description": "DEPRECATED: use --component",
"option": "moniker",
N/A
N/A
N/A
{
"command": "ffx log",
"options": [
{
"description": "filter for a string in either the message, component or url. May be repeated.",
"option": "filter",
"shorthand": "",
"value_type": "string"
},
{
"description": "DEPRECATED: use --component",
"option": "moniker",
N/A
```posix-terminal
N/A
{
"command": "ffx log",
"options": [
{
"description": "filter for a string in either the message, component or url. May be repeated.",
"option": "filter",
"shorthand": "",
"value_type": "string"
},
{
"description": "DEPRECATED: use --component",
"option": "moniker",
N/A
N/A
N/A
{
"command": "ffx log",
"options": [
{
"description": "filter for a string in either the message, component or url. May be repeated.",
"option": "filter",
"shorthand": "",
"value_type": "string"
},
{
"description": "DEPRECATED: use --component",
"option": "moniker",
N/A
```posix-terminal
```posix-terminal
N/A
{
"command": "ffx log",
"options": [
{
"description": "filter for a string in either the message, component or url. May be repeated.",
"option": "filter",
"shorthand": "",
"value_type": "string"
},
{
"description": "DEPRECATED: use --component",
"option": "moniker",
N/A
N/A
N/A
{
"command": "ffx log",
"options": [
{
"description": "filter for a string in either the message, component or url. May be repeated.",
"option": "filter",
"shorthand": "",
"value_type": "string"
},
{
"description": "DEPRECATED: use --component",
"option": "moniker",
N/A
N/A
N/A
{
"command": "ffx log",
"options": [
{
"description": "filter for a string in either the message, component or url. May be repeated.",
"option": "filter",
"shorthand": "",
"value_type": "string"
},
{
"description": "DEPRECATED: use --component",
"option": "moniker",
N/A
N/A
N/A
{
"command": "ffx log",
"options": [
{
"description": "filter for a string in either the message, component or url. May be repeated.",
"option": "filter",
"shorthand": "",
"value_type": "string"
},
{
"description": "DEPRECATED: use --component",
"option": "moniker",
N/A
N/A
N/A
{
"command": "ffx log",
"options": [
{
"description": "filter for a string in either the message, component or url. May be repeated.",
"option": "filter",
"shorthand": "",
"value_type": "string"
},
{
"description": "DEPRECATED: use --component",
"option": "moniker",
N/A
N/A
N/A
{
"command": "ffx log",
"options": [
{
"description": "filter for a string in either the message, component or url. May be repeated.",
"option": "filter",
"shorthand": "",
"value_type": "string"
},
{
"description": "DEPRECATED: use --component",
"option": "moniker",
N/A
N/A
N/A
{
"command": "ffx log",
"options": [
{
"description": "filter for a string in either the message, component or url. May be repeated.",
"option": "filter",
"shorthand": "",
"value_type": "string"
},
{
"description": "DEPRECATED: use --component",
"option": "moniker",
N/A
N/A
N/A
{
"command": "ffx log",
"options": [
{
"description": "filter for a string in either the message, component or url. May be repeated.",
"option": "filter",
"shorthand": "",
"value_type": "string"
},
{
"description": "DEPRECATED: use --component",
"option": "moniker",
N/A
N/A
N/A
{
"command": "ffx log",
"options": [
{
"description": "filter for a string in either the message, component or url. May be repeated.",
"option": "filter",
"shorthand": "",
"value_type": "string"
},
{
"description": "DEPRECATED: use --component",
"option": "moniker",
N/A
N/A
N/A
{
"command": "ffx log",
"options": [
{
"description": "filter for a string in either the message, component or url. May be repeated.",
"option": "filter",
"shorthand": "",
"value_type": "string"
},
{
"description": "DEPRECATED: use --component",
"option": "moniker",
N/A
```posix-terminal
```posix-terminal
N/A
{
"command": "ffx log",
"options": [
{
"description": "filter for a string in either the message, component or url. May be repeated.",
"option": "filter",
"shorthand": "",
"value_type": "string"
},
{
"description": "DEPRECATED: use --component",
"option": "moniker",
N/A
```posix-terminal
```posix-terminal
N/A
{
"command": "ffx log",
"options": [
{
"description": "filter for a string in either the message, component or url. May be repeated.",
"option": "filter",
"shorthand": "",
"value_type": "string"
},
{
"description": "DEPRECATED: use --component",
"option": "moniker",
N/A
N/A
N/A
{
"command": "ffx log",
"options": [
{
"description": "filter for a string in either the message, component or url. May be repeated.",
"option": "filter",
"shorthand": "",
"value_type": "string"
},
{
"description": "DEPRECATED: use --component",
"option": "moniker",
N/A
N/A
N/A
{
"command": "ffx log",
"options": [
{
"description": "filter for a string in either the message, component or url. May be repeated.",
"option": "filter",
"shorthand": "",
"value_type": "string"
},
{
"description": "DEPRECATED: use --component",
"option": "moniker",
N/A
```posix-terminal
N/A
{
"command": "ffx log",
"options": [
{
"description": "filter for a string in either the message, component or url. May be repeated.",
"option": "filter",
"shorthand": "",
"value_type": "string"
},
{
"description": "DEPRECATED: use --component",
"option": "moniker",
N/A
N/A
N/A
{
"command": "ffx log",
"options": [
{
"description": "filter for a string in either the message, component or url. May be repeated.",
"option": "filter",
"shorthand": "",
"value_type": "string"
},
{
"description": "DEPRECATED: use --component",
"option": "moniker",
N/A
N/A
N/A
{
"command": "ffx log",
"options": [
{
"description": "filter for a string in either the message, component or url. May be repeated.",
"option": "filter",
"shorthand": "",
"value_type": "string"
},
{
"description": "DEPRECATED: use --component",
"option": "moniker",
N/A
N/A
N/A
{
"command": "ffx log",
"options": [
{
"description": "filter for a string in either the message, component or url. May be repeated.",
"option": "filter",
"shorthand": "",
"value_type": "string"
},
{
"description": "DEPRECATED: use --component",
"option": "moniker",
N/A
N/A
N/A
{
"command": "ffx log",
"options": [
{
"description": "filter for a string in either the message, component or url. May be repeated.",
"option": "filter",
"shorthand": "",
"value_type": "string"
},
{
"description": "DEPRECATED: use --component",
"option": "moniker",
N/A
```posix-terminal
N/A
{
"command": "ffx log",
"options": [
{
"description": "filter for a string in either the message, component or url. May be repeated.",
"option": "filter",
"shorthand": "",
"value_type": "string"
},
{
"description": "DEPRECATED: use --component",
"option": "moniker",
N/A
N/A
N/A
{
"command": "ffx log dump",
"options": [],
"short": "Dumps all log from a given target's session."
}
You can use `ffx log dump` to view logs from a previous session. For example, to view logs from your device's previous boot:
N/A
```posix-terminal
N/A
{
"command": "ffx log set-severity",
"options": [
{
"description": "if true, doesn't persist the interest setting and blocks forever, keeping the connection open. Interest settings will be reset when the command exits.",
"option": "no-persist",
"shorthand": "",
"value_type": "bool"
},
{
"description": "if enabled, selectors will be passed directly to Archivist without any filtering. If disabled and no matching components are found, the user will be prompted to either enable this or be given a list of selectors to choose from.",
"option": "force",
N/A
N/A
N/A
{
"command": "ffx log set-severity",
"options": [
{
"description": "if true, doesn't persist the interest setting and blocks forever, keeping the connection open. Interest settings will be reset when the command exits.",
"option": "no-persist",
"shorthand": "",
"value_type": "bool"
},
{
"description": "if enabled, selectors will be passed directly to Archivist without any filtering. If disabled and no matching components are found, the user will be prompted to either enable this or be given a list of selectors to choose from.",
"option": "force",
N/A
N/A
N/A
{
"command": "ffx log set-severity",
"options": [
{
"description": "if true, doesn't persist the interest setting and blocks forever, keeping the connection open. Interest settings will be reset when the command exits.",
"option": "no-persist",
"shorthand": "",
"value_type": "bool"
},
{
"description": "if enabled, selectors will be passed directly to Archivist without any filtering. If disabled and no matching components are found, the user will be prompted to either enable this or be given a list of selectors to choose from.",
"option": "force",
N/A
N/A
N/A
{
"command": "ffx log watch",
"options": [],
"short": "Watches for and prints logs from a target. Default if no sub-command is specified."
}
N/A
N/A
N/A
{
"command": "ffx monitor",
"options": [],
"short": "Start a local server to monitor status."
}
#[test]
fn test_get_log_path() {
let default_dir = Some("/default/dir".to_string());
// Absolute path
let abs_path = "/tmp/log.json";
let res = get_log_path(&Some(abs_path.to_string()), &default_dir).unwrap();
assert_eq!(res.unwrap().as_path(), Path::new(abs_path));
// Relative path with log_dir
let res = get_log_path(&Some("log.json".to_string()), &default_dir).unwrap();
assert_eq!(res.unwrap().as_path(), Path::new("/default/dir/log.json"));
// Relative path without log_dir should fail
let res = get_log_path(&Some("log.json".to_string()), &None);
assert!(res.is_err());
// None path
let res = get_log_path(&None, &default_dir).unwrap();
assert!(res.is_none());
}
#[test]
fn test_compute_aggregations_reappearing_device() {
let mut state = AggregationsState::default();
state.update(&make_entry(0, 100, vec![make_target("A", "Y")]));
state.update(&make_entry(1000, 100, vec![]));
state.update(&make_entry(2000, 100, vec![make_target("A", "Y")]));
let result = state.finalize();
let dev_a = &result.device_aggregations[0];
assert_eq!(dev_a.nodename, "A");
assert_eq!(dev_a.metrics.target_vanished_count, 1);
assert_eq!(dev_a.metrics.disconnected_ms, 1000);
assert_eq!(dev_a.metrics.active_ms, 1000);
}
#[test]
fn test_compute_aggregations_intentional_disconnect() {
let mut state = AggregationsState::default();
let mut intentional_disconnect_records = Vec::new();
// Time 0: A is active
state.update(&make_entry(0, 100, vec![make_target("A", "Y")]));
// Time 1000: A drops unexpectedly
state.update(&make_entry(1000, 100, vec![]));
// Time 1500: A still dropped (Unexpected persistence)
state.update(&make_entry(1500, 100, vec![]));
// Time 2000: A recovers
state.update(&make_entry(2000, 100, vec![make_target("A", "N")]));
// Time 2500: Intentional disconnect requested (Record 1)
intentional_disconnect_records
.push(IntentionalDisconnectRecord { nodename: "A".to_string(), timestamp: 2500 });
state.pending_intentional_disconnects.insert("A".to_string());
// Time 2600: Redundant Intentional disconnect requested (Record 2)
intentional_disconnect_records
.push(IntentionalDisconnectRecord { nodename: "A".to_string(), timestamp: 2600 });
state.pending_intentional_disconnects.insert("A".to_string());
// Time 3000: A drops intentionally
state.update(&make_entry(3000, 100, vec![]));
```posix-terminal
N/A
{
"command": "ffx monitor start",
"options": [
{
"description": "the port to listen on",
"option": "port",
"shorthand": "p",
"value_type": "string"
}
],
"short": "Start the monitor server"
}
N/A
```posix-terminal
N/A
{
"command": "ffx monitor start",
"options": [
{
"description": "the port to listen on",
"option": "port",
"shorthand": "p",
"value_type": "string"
}
],
"short": "Start the monitor server"
}
N/A
```posix-terminal
N/A
{
"command": "ffx monitor stop",
"options": [],
"short": "Stop the monitor server"
}
N/A
N/A
N/A
{
"command": "ffx net",
"options": [
{
"description": "a realm to target when sending commands. Defaults to the core network realm.",
"option": "realm",
"shorthand": "",
"value_type": "string"
}
],
"short": "View and manage target network configuration"
}
N/A
N/A
N/A
{
"command": "ffx net",
"options": [
{
"description": "a realm to target when sending commands. Defaults to the core network realm.",
"option": "realm",
"shorthand": "",
"value_type": "string"
}
],
"short": "View and manage target network configuration"
}
N/A
N/A
N/A
{
"command": "ffx net dhcp",
"options": [],
"short": "commands for an interfaces dhcp client"
}
N/A
N/A
N/A
{
"command": "ffx net dhcp start",
"options": [],
"short": "starts a dhcp client on the interface"
}
N/A
N/A
N/A
{
"command": "ffx net dhcp stop",
"options": [],
"short": "stops the dhcp client on the interface"
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd",
"options": [],
"short": "commands to control a dhcp server"
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd clear-leases",
"options": [],
"short": "A primary command to clear the leases maintained by dhcpd."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get",
"options": [],
"short": "A primary command to retrieve the value of a DHCP option or server parameter."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option",
"options": [],
"short": "A secondary command indicating a DHCP option argument."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option all-subnets-local",
"options": [
{
"description": "a flag indicating if all subents of the IP network to which the client is connected have the same MTU.",
"option": "local",
"shorthand": "",
"value_type": "bool"
}
],
"short": "Flag indicating if all subnets of the connected network have the same MTU."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option all-subnets-local",
"options": [
{
"description": "a flag indicating if all subents of the IP network to which the client is connected have the same MTU.",
"option": "local",
"shorthand": "",
"value_type": "bool"
}
],
"short": "Flag indicating if all subnets of the connected network have the same MTU."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option arp-cache-timeout",
"options": [
{
"description": "the timeout for ARP cache entries, in seconds.",
"option": "timeout",
"shorthand": "",
"value_type": "string"
}
],
"short": "Timeout for ARP cache entries."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option arp-cache-timeout",
"options": [
{
"description": "the timeout for ARP cache entries, in seconds.",
"option": "timeout",
"shorthand": "",
"value_type": "string"
}
],
"short": "Timeout for ARP cache entries."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option boot-file-size",
"options": [
{
"description": "the size of the client's default boot image in 512-octet blocks.",
"option": "size",
"shorthand": "",
"value_type": "string"
}
],
"short": "Size of the default boot image for the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option boot-file-size",
"options": [
{
"description": "the size of the client's default boot image in 512-octet blocks.",
"option": "size",
"shorthand": "",
"value_type": "string"
}
],
"short": "Size of the default boot image for the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option bootfile-name",
"options": [
{
"description": "the bootfile name for the client. This option should be used when the `file` field has been overloaded to carry options.",
"option": "name",
"shorthand": "",
"value_type": "string"
}
],
"short": "Bootfile name for the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option bootfile-name",
"options": [
{
"description": "the bootfile name for the client. This option should be used when the `file` field has been overloaded to carry options.",
"option": "name",
"shorthand": "",
"value_type": "string"
}
],
"short": "Bootfile name for the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option broadcast-address",
"options": [
{
"description": "the broadcast address of the client's subnet. Legal values are defined in RFC 1122.",
"option": "addr",
"shorthand": "",
"value_type": "string"
}
],
"short": "Broadcast address of the client's subnet."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option broadcast-address",
"options": [
{
"description": "the broadcast address of the client's subnet. Legal values are defined in RFC 1122.",
"option": "addr",
"shorthand": "",
"value_type": "string"
}
],
"short": "Broadcast address of the client's subnet."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option cookie-server",
"options": [
{
"description": "a list of RFC 865 Cookie servers available to the client, in order of preference.",
"option": "cookie-servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "RFC 865 Cookie servers available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option cookie-server",
"options": [
{
"description": "a list of RFC 865 Cookie servers available to the client, in order of preference.",
"option": "cookie-servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "RFC 865 Cookie servers available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option default-finger-server",
"options": [
{
"description": "a list of default Finger server addresses available to the client, listed in order of preference.",
"option": "finger-servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "Default Finger servers available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option default-finger-server",
"options": [
{
"description": "a list of default Finger server addresses available to the client, listed in order of preference.",
"option": "finger-servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "Default Finger servers available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option default-ip-ttl",
"options": [
{
"description": "the default time-to-live to use on outgoing IP datagrams. The value must be between 1 and 255.",
"option": "ttl",
"shorthand": "",
"value_type": "string"
}
],
"short": "Default time-to-live to use on outgoing IP datagrams."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option default-ip-ttl",
"options": [
{
"description": "the default time-to-live to use on outgoing IP datagrams. The value must be between 1 and 255.",
"option": "ttl",
"shorthand": "",
"value_type": "string"
}
],
"short": "Default time-to-live to use on outgoing IP datagrams."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option default-irc-server",
"options": [
{
"description": "a list of Internet Relay Chat server addresses available to the client, listed in order of preference.",
"option": "irc-servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "Default IRC servers available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option default-irc-server",
"options": [
{
"description": "a list of Internet Relay Chat server addresses available to the client, listed in order of preference.",
"option": "irc-servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "Default IRC servers available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option default-www-server",
"options": [
{
"description": "a list of default World Wide Web (WWW) server addresses available to the client, listed in order of preference.",
"option": "www-servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "Default WWW servers available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option default-www-server",
"options": [
{
"description": "a list of default World Wide Web (WWW) server addresses available to the client, listed in order of preference.",
"option": "www-servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "Default WWW servers available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option domain-name",
"options": [
{
"description": "the client's domain name for use in resolving hostnames in the DNS.",
"option": "name",
"shorthand": "",
"value_type": "string"
}
],
"short": "Domain name of the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option domain-name",
"options": [
{
"description": "the client's domain name for use in resolving hostnames in the DNS.",
"option": "name",
"shorthand": "",
"value_type": "string"
}
],
"short": "Domain name of the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option domain-name-server",
"options": [
{
"description": "a list of DNS servers available to the client, in order of preference;",
"option": "domain-name-servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "Domain Name System servers available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option domain-name-server",
"options": [
{
"description": "a list of DNS servers available to the client, in order of preference;",
"option": "domain-name-servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "Domain Name System servers available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option ethernet-encapsulation",
"options": [
{
"description": "a flag specifying that the client should use Ethernet v2 encapsulation when false, and IEEE 802.3 encapsulation when true.",
"option": "encapsulate",
"shorthand": "",
"value_type": "bool"
}
],
"short": "Flag specifying whether the client should use Ethernet v2 or IEEE 802.3 encapsulation."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option ethernet-encapsulation",
"options": [
{
"description": "a flag specifying that the client should use Ethernet v2 encapsulation when false, and IEEE 802.3 encapsulation when true.",
"option": "encapsulate",
"shorthand": "",
"value_type": "bool"
}
],
"short": "Flag specifying whether the client should use Ethernet v2 or IEEE 802.3 encapsulation."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option extensions-path",
"options": [
{
"description": "the path name to a TFTP-retrievable file. This file contains data which can be interpreted as the BOOTP vendor-extension field. Unlike the BOOTP vendor-extension field, this file has an unconstrained length and any references to Tag 18 are ignored.",
"option": "path",
"shorthand": "",
"value_type": "string"
}
],
"short": "Path name to a TFTP-retrievable file containing vendor-extension information."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option extensions-path",
"options": [
{
"description": "the path name to a TFTP-retrievable file. This file contains data which can be interpreted as the BOOTP vendor-extension field. Unlike the BOOTP vendor-extension field, this file has an unconstrained length and any references to Tag 18 are ignored.",
"option": "path",
"shorthand": "",
"value_type": "string"
}
],
"short": "Path name to a TFTP-retrievable file containing vendor-extension information."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option host-name",
"options": [
{
"description": "the name of client, which may or may not be qualified with the local domain name.",
"option": "name",
"shorthand": "",
"value_type": "string"
}
],
"short": "Name of the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option host-name",
"options": [
{
"description": "the name of client, which may or may not be qualified with the local domain name.",
"option": "name",
"shorthand": "",
"value_type": "string"
}
],
"short": "Name of the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option impress-server",
"options": [
{
"description": "a list of Imagen Impress servers available to the client, in order of preference.",
"option": "impress-servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "Imagen Impress servers available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option impress-server",
"options": [
{
"description": "a list of Imagen Impress servers available to the client, in order of preference.",
"option": "impress-servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "Imagen Impress servers available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option interface-mtu",
"options": [
{
"description": "the MTU for the client's interface. Minimum value of 68.",
"option": "mtu",
"shorthand": "",
"value_type": "string"
}
],
"short": "MTU for the client's interface."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option interface-mtu",
"options": [
{
"description": "the MTU for the client's interface. Minimum value of 68.",
"option": "mtu",
"shorthand": "",
"value_type": "string"
}
],
"short": "MTU for the client's interface."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option ip-forwarding",
"options": [
{
"description": "a flag which will enabled IP layer packet forwarding when true.",
"option": "enabled",
"shorthand": "",
"value_type": "bool"
}
],
"short": "Flag enabling/disabling IP layer packet forwarding."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option ip-forwarding",
"options": [
{
"description": "a flag which will enabled IP layer packet forwarding when true.",
"option": "enabled",
"shorthand": "",
"value_type": "bool"
}
],
"short": "Flag enabling/disabling IP layer packet forwarding."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option log-server",
"options": [
{
"description": "a list of MIT-LCS UDP Log servers available to the client, in order of preference.",
"option": "log-servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "MIT-LCS UDP Log servers available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option log-server",
"options": [
{
"description": "a list of MIT-LCS UDP Log servers available to the client, in order of preference.",
"option": "log-servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "MIT-LCS UDP Log servers available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option lpr-server",
"options": [
{
"description": "a list of RFC 1179 Line Printer servers available to the client, in order of preference.",
"option": "lpr-servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "RFC 1179 Line Printer servers available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option lpr-server",
"options": [
{
"description": "a list of RFC 1179 Line Printer servers available to the client, in order of preference.",
"option": "lpr-servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "RFC 1179 Line Printer servers available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option mask-supplier",
"options": [
{
"description": "a flag indicating whether the client should respond to subnet mask discovery requests via ICMP.",
"option": "supplier",
"shorthand": "",
"value_type": "bool"
}
],
"short": "Flag indicating whether the client should respond to subnet mask discovery requests via ICMP."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option mask-supplier",
"options": [
{
"description": "a flag indicating whether the client should respond to subnet mask discovery requests via ICMP.",
"option": "supplier",
"shorthand": "",
"value_type": "bool"
}
],
"short": "Flag indicating whether the client should respond to subnet mask discovery requests via ICMP."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option max-datagram-reassembly-size",
"options": [
{
"description": "the maximum sized datagram that the client should be able to reassemble, in octets. The minimum legal value is 576.",
"option": "size",
"shorthand": "",
"value_type": "string"
}
],
"short": "Maximum sized datagram that the client should be able to reassemble."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option max-datagram-reassembly-size",
"options": [
{
"description": "the maximum sized datagram that the client should be able to reassemble, in octets. The minimum legal value is 576.",
"option": "size",
"shorthand": "",
"value_type": "string"
}
],
"short": "Maximum sized datagram that the client should be able to reassemble."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option max-message-size",
"options": [
{
"description": "the maximum length in octets of a DHCP message that the participant is willing to accept. The minimum value is 576.",
"option": "length",
"shorthand": "",
"value_type": "string"
}
],
"short": "Maximum length of a DHCP message that the participant is willing to accept."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option max-message-size",
"options": [
{
"description": "the maximum length in octets of a DHCP message that the participant is willing to accept. The minimum value is 576.",
"option": "length",
"shorthand": "",
"value_type": "string"
}
],
"short": "Maximum length of a DHCP message that the participant is willing to accept."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option merit-dump-file",
"options": [
{
"description": "the path name to the client's core dump in the event the client crashes.",
"option": "path",
"shorthand": "",
"value_type": "string"
}
],
"short": "Path name of a core dump file."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option merit-dump-file",
"options": [
{
"description": "the path name to the client's core dump in the event the client crashes.",
"option": "path",
"shorthand": "",
"value_type": "string"
}
],
"short": "Path name of a core dump file."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option mobile-ip-home-agent",
"options": [
{
"description": "a list of mobile IP home agent addresses available to the client, listed in order of preference.",
"option": "home-agents",
"shorthand": "",
"value_type": "string"
}
],
"short": "Mobile IP home agents available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option mobile-ip-home-agent",
"options": [
{
"description": "a list of mobile IP home agent addresses available to the client, listed in order of preference.",
"option": "home-agents",
"shorthand": "",
"value_type": "string"
}
],
"short": "Mobile IP home agents available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option name-server",
"options": [
{
"description": "a list of IEN 116 Name servers available to the client, in order of preference.",
"option": "name-servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "IEN 116 Name servers available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option name-server",
"options": [
{
"description": "a list of IEN 116 Name servers available to the client, in order of preference.",
"option": "name-servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "IEN 116 Name servers available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option net-bios-over-tcpip-distribution-server",
"options": [
{
"description": "a list of NetBIOS datagram distribution servers available to the client, listed in order of preference.",
"option": "servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "NetBIOS datagram distribution servers available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option net-bios-over-tcpip-distribution-server",
"options": [
{
"description": "a list of NetBIOS datagram distribution servers available to the client, listed in order of preference.",
"option": "servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "NetBIOS datagram distribution servers available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option net-bios-over-tcpip-name-server",
"options": [
{
"description": "a list of NetBIOS name server addresses available to the client, listed in order of preference.",
"option": "servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "NetBIOS name servers available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option net-bios-over-tcpip-name-server",
"options": [
{
"description": "a list of NetBIOS name server addresses available to the client, listed in order of preference.",
"option": "servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "NetBIOS name servers available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option net-bios-over-tcpip-node-type",
"options": [],
"short": "The NetBIOS node type which should be used by the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option net-bios-over-tcpip-node-type b-node",
"options": [],
"short": "A B node type."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option net-bios-over-tcpip-node-type h-node",
"options": [],
"short": "A H node type."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option net-bios-over-tcpip-node-type m-node",
"options": [],
"short": "A M node type."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option net-bios-over-tcpip-node-type p-node",
"options": [],
"short": "A P node type."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option net-bios-over-tcpip-scope",
"options": [
{
"description": "the NetBIOS over TCP/IP scope parameter, as defined in RFC 1001, for the client.",
"option": "scope",
"shorthand": "",
"value_type": "string"
}
],
"short": "NetBIOS scope parameter for the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option net-bios-over-tcpip-scope",
"options": [
{
"description": "the NetBIOS over TCP/IP scope parameter, as defined in RFC 1001, for the client.",
"option": "scope",
"shorthand": "",
"value_type": "string"
}
],
"short": "NetBIOS scope parameter for the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option network-information-servers",
"options": [
{
"description": "a list of Network Information Service server addresses available to the client, listed in order of preference.",
"option": "servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "Network Information Service servers available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option network-information-servers",
"options": [
{
"description": "a list of Network Information Service server addresses available to the client, listed in order of preference.",
"option": "servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "Network Information Service servers available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option network-information-service-domain",
"options": [
{
"description": "the name of the client's Network Information Service domain.",
"option": "domain-name",
"shorthand": "",
"value_type": "string"
}
],
"short": "Name of the client's Network Information Service domain."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option network-information-service-domain",
"options": [
{
"description": "the name of the client's Network Information Service domain.",
"option": "domain-name",
"shorthand": "",
"value_type": "string"
}
],
"short": "Name of the client's Network Information Service domain."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option network-information-service-plus-domain",
"options": [
{
"description": "the name of the client's Network Information System+ domain.",
"option": "domain-name",
"shorthand": "",
"value_type": "string"
}
],
"short": "Network Information System+ domain name."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option network-information-service-plus-domain",
"options": [
{
"description": "the name of the client's Network Information System+ domain.",
"option": "domain-name",
"shorthand": "",
"value_type": "string"
}
],
"short": "Network Information System+ domain name."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option network-information-service-plus-servers",
"options": [
{
"description": "a list of Network Information System+ server addresses available to the client, listed in order of preference.",
"option": "servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "Network Information System+ servers available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option network-information-service-plus-servers",
"options": [
{
"description": "a list of Network Information System+ server addresses available to the client, listed in order of preference.",
"option": "servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "Network Information System+ servers available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option network-time-protocol-servers",
"options": [
{
"description": "a list of Network Time Protocol (NTP) server addresses available to the client, listed in order of preference.",
"option": "servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "Network Time Protocol servers available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option network-time-protocol-servers",
"options": [
{
"description": "a list of Network Time Protocol (NTP) server addresses available to the client, listed in order of preference.",
"option": "servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "Network Time Protocol servers available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option nntp-server",
"options": [
{
"description": "a list Network News Transport Protocol (NNTP) server addresses available to the client, listed in order of preference.",
"option": "nntp-servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "NNTP servers available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option nntp-server",
"options": [
{
"description": "a list Network News Transport Protocol (NNTP) server addresses available to the client, listed in order of preference.",
"option": "nntp-servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "NNTP servers available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option non-local-source-routing",
"options": [
{
"description": "a flag which will enable forwarding of IP packets with non-local source routes.",
"option": "enabled",
"shorthand": "",
"value_type": "bool"
}
],
"short": "Flag enabling/disabling forwarding of IP packets with non-local source routes."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option non-local-source-routing",
"options": [
{
"description": "a flag which will enable forwarding of IP packets with non-local source routes.",
"option": "enabled",
"shorthand": "",
"value_type": "bool"
}
],
"short": "Flag enabling/disabling forwarding of IP packets with non-local source routes."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option path-mtu-aging-timeout",
"options": [
{
"description": "the timeout, in seconds, to be used when again Path MTU values by the mechanism in RFC 1191.",
"option": "timeout",
"shorthand": "",
"value_type": "string"
}
],
"short": "Timeout to use when aging Path MTU values."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option path-mtu-aging-timeout",
"options": [
{
"description": "the timeout, in seconds, to be used when again Path MTU values by the mechanism in RFC 1191.",
"option": "timeout",
"shorthand": "",
"value_type": "string"
}
],
"short": "Timeout to use when aging Path MTU values."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option path-mtu-plateau-table",
"options": [
{
"description": "a list of MTU sizes, ordered from smallest to largest. The smallest value cannot be smaller than 68.",
"option": "mtu-sizes",
"shorthand": "",
"value_type": "string"
}
],
"short": "Table of MTU sizes for Path MTU Discovery."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option path-mtu-plateau-table",
"options": [
{
"description": "a list of MTU sizes, ordered from smallest to largest. The smallest value cannot be smaller than 68.",
"option": "mtu-sizes",
"shorthand": "",
"value_type": "string"
}
],
"short": "Table of MTU sizes for Path MTU Discovery."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option perform-mask-discovery",
"options": [
{
"description": "a flag indicating whether the client should perform subnet mask discovery via ICMP.",
"option": "do-discovery",
"shorthand": "",
"value_type": "bool"
}
],
"short": "Flag indicating whether the client should perform subnet mask discovery via ICMP."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option perform-mask-discovery",
"options": [
{
"description": "a flag indicating whether the client should perform subnet mask discovery via ICMP.",
"option": "do-discovery",
"shorthand": "",
"value_type": "bool"
}
],
"short": "Flag indicating whether the client should perform subnet mask discovery via ICMP."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option perform-router-discovery",
"options": [
{
"description": "a flag indicating whether the client should solicit routers using Router Discovery as defined in RFC 1256.",
"option": "do-discovery",
"shorthand": "",
"value_type": "bool"
}
],
"short": "Flag indicating whether the client should solicit routers using Router Discovery."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option perform-router-discovery",
"options": [
{
"description": "a flag indicating whether the client should solicit routers using Router Discovery as defined in RFC 1256.",
"option": "do-discovery",
"shorthand": "",
"value_type": "bool"
}
],
"short": "Flag indicating whether the client should solicit routers using Router Discovery."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option policy-filter",
"options": [
{
"description": "a list of IP Address and Subnet Mask pairs. If an incoming source-routed packet has a next-hop that does not match one of these pairs, then the packet will be dropped.",
"option": "addresses",
"shorthand": "",
"value_type": "string"
}
],
"short": "Policy filters for non-local source routing."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option policy-filter",
"options": [
{
"description": "a list of IP Address and Subnet Mask pairs. If an incoming source-routed packet has a next-hop that does not match one of these pairs, then the packet will be dropped.",
"option": "addresses",
"shorthand": "",
"value_type": "string"
}
],
"short": "Policy filters for non-local source routing."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option pop3-server",
"options": [
{
"description": "a list of Post Office Protocol (POP3) server addresses available to the client, listed in order of preference.",
"option": "pop3-servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "POP3 servers available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option pop3-server",
"options": [
{
"description": "a list of Post Office Protocol (POP3) server addresses available to the client, listed in order of preference.",
"option": "pop3-servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "POP3 servers available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option rebinding-time-value",
"options": [
{
"description": "the time interval, in seconds, after address assignment at which the client will transition to the Rebinding state.",
"option": "interval",
"shorthand": "",
"value_type": "string"
}
],
"short": "Time interval from address assignment at which the client transitions to a Rebinding state."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option rebinding-time-value",
"options": [
{
"description": "the time interval, in seconds, after address assignment at which the client will transition to the Rebinding state.",
"option": "interval",
"shorthand": "",
"value_type": "string"
}
],
"short": "Time interval from address assignment at which the client transitions to a Rebinding state."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option renewal-time-value",
"options": [
{
"description": "the time interval, in seconds, after address assignment at which the client will transition to the Renewing state.",
"option": "interval",
"shorthand": "",
"value_type": "string"
}
],
"short": "Time interval from address assignment at which the client transitions to a Renewing state."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option renewal-time-value",
"options": [
{
"description": "the time interval, in seconds, after address assignment at which the client will transition to the Renewing state.",
"option": "interval",
"shorthand": "",
"value_type": "string"
}
],
"short": "Time interval from address assignment at which the client transitions to a Renewing state."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option resource-location-server",
"options": [
{
"description": "a list of RFC 887 Resource Location servers available to the client, in order of preference.",
"option": "resource-location-servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "RFC 887 Resource Location servers available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option resource-location-server",
"options": [
{
"description": "a list of RFC 887 Resource Location servers available to the client, in order of preference.",
"option": "resource-location-servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "RFC 887 Resource Location servers available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option root-path",
"options": [
{
"description": "the path name to a TFTP-retrievable file. This file contains data which can be interpreted as the BOOTP vendor-extension field. Unlike the BOOTP vendor-extension field, this file has an unconstrained length and any references to Tag 18 are ignored.",
"option": "path",
"shorthand": "",
"value_type": "string"
}
],
"short": "Path name to a TFTP-retrievable file containing vendor-extension information."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option root-path",
"options": [
{
"description": "the path name to a TFTP-retrievable file. This file contains data which can be interpreted as the BOOTP vendor-extension field. Unlike the BOOTP vendor-extension field, this file has an unconstrained length and any references to Tag 18 are ignored.",
"option": "path",
"shorthand": "",
"value_type": "string"
}
],
"short": "Path name to a TFTP-retrievable file containing vendor-extension information."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option router",
"options": [
{
"description": "a list of the routers in a client's subnet, listed in order of preference.",
"option": "routers",
"shorthand": "",
"value_type": "string"
}
],
"short": "The routers within a client's subnet."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option router",
"options": [
{
"description": "a list of the routers in a client's subnet, listed in order of preference.",
"option": "routers",
"shorthand": "",
"value_type": "string"
}
],
"short": "The routers within a client's subnet."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option router-solicitation-address",
"options": [
{
"description": "the address to which the client should transmit Router Solicitation requests.",
"option": "addr",
"shorthand": "",
"value_type": "string"
}
],
"short": "Destination address for Router Solicitation requests."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option router-solicitation-address",
"options": [
{
"description": "the address to which the client should transmit Router Solicitation requests.",
"option": "addr",
"shorthand": "",
"value_type": "string"
}
],
"short": "Destination address for Router Solicitation requests."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option smtp-server",
"options": [
{
"description": "a list of Simple Mail Transport Protocol (SMTP) server address available to the client, listed in order of preference.",
"option": "smtp-servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "SMTP servers available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option smtp-server",
"options": [
{
"description": "a list of Simple Mail Transport Protocol (SMTP) server address available to the client, listed in order of preference.",
"option": "smtp-servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "SMTP servers available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option static-route",
"options": [
{
"description": "a list of Destination address/Next-hop address pairs defining static routes for the client's routing table. The routes should be listed in descending order of priority. It is illegal to use 0.0.0.0 as the destination in a static route.",
"option": "routes",
"shorthand": "",
"value_type": "string"
}
],
"short": "Static Routes which the client should put in its routing cache."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option static-route",
"options": [
{
"description": "a list of Destination address/Next-hop address pairs defining static routes for the client's routing table. The routes should be listed in descending order of priority. It is illegal to use 0.0.0.0 as the destination in a static route.",
"option": "routes",
"shorthand": "",
"value_type": "string"
}
],
"short": "Static Routes which the client should put in its routing cache."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option stda-server",
"options": [
{
"description": "a list of StreetTalk Directory Assistance server addresses available to the client, listed in order of preference.",
"option": "stda-servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "StreetTalk Directory Assistance servers available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option stda-server",
"options": [
{
"description": "a list of StreetTalk Directory Assistance server addresses available to the client, listed in order of preference.",
"option": "stda-servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "StreetTalk Directory Assistance servers available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option street-talk-server",
"options": [
{
"description": "a list of StreetTalk server addresses available to the client, listed in order of preference.",
"option": "streettalk-servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "StreetTalk servers available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option street-talk-server",
"options": [
{
"description": "a list of StreetTalk server addresses available to the client, listed in order of preference.",
"option": "streettalk-servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "StreetTalk servers available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option subnet-mask",
"options": [
{
"description": "a 32-bit IPv4 subnet mask.",
"option": "mask",
"shorthand": "",
"value_type": "string"
}
],
"short": "The client's subnet mask."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option subnet-mask",
"options": [
{
"description": "a 32-bit IPv4 subnet mask.",
"option": "mask",
"shorthand": "",
"value_type": "string"
}
],
"short": "The client's subnet mask."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option swap-server",
"options": [
{
"description": "the address of the client's swap server.",
"option": "address",
"shorthand": "",
"value_type": "string"
}
],
"short": "Address of the client's swap server."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option swap-server",
"options": [
{
"description": "the address of the client's swap server.",
"option": "address",
"shorthand": "",
"value_type": "string"
}
],
"short": "Address of the client's swap server."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option tcp-default-ttl",
"options": [
{
"description": "the default time-to-live that the client should use for outgoing TCP segments. The minimum value is 1.",
"option": "ttl",
"shorthand": "",
"value_type": "string"
}
],
"short": "Default time-to-live for outgoing TCP segments."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option tcp-default-ttl",
"options": [
{
"description": "the default time-to-live that the client should use for outgoing TCP segments. The minimum value is 1.",
"option": "ttl",
"shorthand": "",
"value_type": "string"
}
],
"short": "Default time-to-live for outgoing TCP segments."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option tcp-keepalive-garbage",
"options": [
{
"description": "a flag specifying whether the client should send TCP keepalive messages with an octet of garbage for compatibility with older implementations.",
"option": "send-garbage",
"shorthand": "",
"value_type": "bool"
}
],
"short": "Flag specifying whether the client should send TCP keepalive messages with an octet of garbage."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option tcp-keepalive-garbage",
"options": [
{
"description": "a flag specifying whether the client should send TCP keepalive messages with an octet of garbage for compatibility with older implementations.",
"option": "send-garbage",
"shorthand": "",
"value_type": "bool"
}
],
"short": "Flag specifying whether the client should send TCP keepalive messages with an octet of garbage."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option tcp-keepalive-interval",
"options": [
{
"description": "the interval, in seconds, the client should wait before sending a TCP keepalive message. A value of 0 indicates that the client should not send keepalive messages unless specifically requested by an application.",
"option": "interval",
"shorthand": "",
"value_type": "string"
}
],
"short": "Interval the client should wait before sending a TCP keepalive message."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option tcp-keepalive-interval",
"options": [
{
"description": "the interval, in seconds, the client should wait before sending a TCP keepalive message. A value of 0 indicates that the client should not send keepalive messages unless specifically requested by an application.",
"option": "interval",
"shorthand": "",
"value_type": "string"
}
],
"short": "Interval the client should wait before sending a TCP keepalive message."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option tftp-server-name",
"options": [
{
"description": "the TFTP server name available to the client. This option should be used when the `sname` field has been overloaded to carry options.",
"option": "name",
"shorthand": "",
"value_type": "string"
}
],
"short": "TFTP server available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option tftp-server-name",
"options": [
{
"description": "the TFTP server name available to the client. This option should be used when the `sname` field has been overloaded to carry options.",
"option": "name",
"shorthand": "",
"value_type": "string"
}
],
"short": "TFTP server available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option time-offset",
"options": [
{
"description": "the client's offset from UTC in seconds. A positive offset is east of the zero meridian, and a negative offset is west of the zero meridian.",
"option": "offset",
"shorthand": "",
"value_type": "string"
}
],
"short": "The client's offset from UTC."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option time-offset",
"options": [
{
"description": "the client's offset from UTC in seconds. A positive offset is east of the zero meridian, and a negative offset is west of the zero meridian.",
"option": "offset",
"shorthand": "",
"value_type": "string"
}
],
"short": "The client's offset from UTC."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option time-server",
"options": [
{
"description": "a list of time servers available to the client, in order of preference.",
"option": "time-servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "Time Protocol servers available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option time-server",
"options": [
{
"description": "a list of time servers available to the client, in order of preference.",
"option": "time-servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "Time Protocol servers available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option trailer-encapsulation",
"options": [
{
"description": "a flag specifying whether the client negotiate the use of trailers when using ARP, per RFC 893.",
"option": "trailers",
"shorthand": "",
"value_type": "bool"
}
],
"short": "Flag specifying whether the client should negotiate the use of trailers in ARP."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option trailer-encapsulation",
"options": [
{
"description": "a flag specifying whether the client negotiate the use of trailers when using ARP, per RFC 893.",
"option": "trailers",
"shorthand": "",
"value_type": "bool"
}
],
"short": "Flag specifying whether the client should negotiate the use of trailers in ARP."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option vendor-specific-information",
"options": [
{
"description": "an opaque object of octets for exchanging vendor-specific information.",
"option": "data",
"shorthand": "",
"value_type": "string"
}
],
"short": "Option for exchanging vendor-specific information between the DHCP client and DHCP server."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option vendor-specific-information",
"options": [
{
"description": "an opaque object of octets for exchanging vendor-specific information.",
"option": "data",
"shorthand": "",
"value_type": "string"
}
],
"short": "Option for exchanging vendor-specific information between the DHCP client and DHCP server."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option x-window-system-display-manager",
"options": [
{
"description": "a list of X Window System Display Manager system addresses available to the client, listed in order of preference.",
"option": "display-servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "X window System Display Manager systems available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option x-window-system-display-manager",
"options": [
{
"description": "a list of X Window System Display Manager system addresses available to the client, listed in order of preference.",
"option": "display-servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "X window System Display Manager systems available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option x-window-system-font-server",
"options": [
{
"description": "a list of X Window System Font server addresses available to the client, listed in order of preference.",
"option": "servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "X Window System Font servers available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get option x-window-system-font-server",
"options": [
{
"description": "a list of X Window System Font server addresses available to the client, listed in order of preference.",
"option": "servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "X Window System Font servers available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get parameter",
"options": [],
"short": "A secondary command indicating a server parameter argument."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get parameter address-pool",
"options": [
{
"description": "the prefix length of the network's subnet mask",
"option": "prefix-length",
"shorthand": "",
"value_type": "string"
},
{
"description": "the starting address, inclusive, of the range of addresses which the DHCP server will lease to clients",
"option": "range-start",
N/A
N/A
N/A
{
"command": "ffx net dhcpd get parameter address-pool",
"options": [
{
"description": "the prefix length of the network's subnet mask",
"option": "prefix-length",
"shorthand": "",
"value_type": "string"
},
{
"description": "the starting address, inclusive, of the range of addresses which the DHCP server will lease to clients",
"option": "range-start",
N/A
N/A
N/A
{
"command": "ffx net dhcpd get parameter address-pool",
"options": [
{
"description": "the prefix length of the network's subnet mask",
"option": "prefix-length",
"shorthand": "",
"value_type": "string"
},
{
"description": "the starting address, inclusive, of the range of addresses which the DHCP server will lease to clients",
"option": "range-start",
N/A
N/A
N/A
{
"command": "ffx net dhcpd get parameter address-pool",
"options": [
{
"description": "the prefix length of the network's subnet mask",
"option": "prefix-length",
"shorthand": "",
"value_type": "string"
},
{
"description": "the starting address, inclusive, of the range of addresses which the DHCP server will lease to clients",
"option": "range-start",
N/A
N/A
N/A
{
"command": "ffx net dhcpd get parameter arp-probe",
"options": [
{
"description": "enables server behavior where the server ARPs an IP address prior to issuing it in a lease. If the server receives a response, the server will mark the address as in-use and try again with a different address. By default, this behavior is disabled.",
"option": "enabled",
"shorthand": "",
"value_type": "bool"
}
],
"short": "Enables server behavior where the server ARPs an IP address prior to issuing it in a lease."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get parameter arp-probe",
"options": [
{
"description": "enables server behavior where the server ARPs an IP address prior to issuing it in a lease. If the server receives a response, the server will mark the address as in-use and try again with a different address. By default, this behavior is disabled.",
"option": "enabled",
"shorthand": "",
"value_type": "bool"
}
],
"short": "Enables server behavior where the server ARPs an IP address prior to issuing it in a lease."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get parameter bound-device-names",
"options": [],
"short": "The names of the network devices on which the server will listen."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get parameter ip-addrs",
"options": [
{
"description": "a list of IPv4 Addresses to which the server is bound.",
"option": "addrs",
"shorthand": "",
"value_type": "string"
}
],
"short": "The IPv4 addresses to which the server is bound."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get parameter ip-addrs",
"options": [
{
"description": "a list of IPv4 Addresses to which the server is bound.",
"option": "addrs",
"shorthand": "",
"value_type": "string"
}
],
"short": "The IPv4 addresses to which the server is bound."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get parameter lease-length",
"options": [
{
"description": "the default lease length, in seconds, to be issued to clients.",
"option": "default",
"shorthand": "",
"value_type": "string"
},
{
"description": "the maximum lease length value, in seconds, which the server will issue to clients who have requested a specific lease length. With the default value of 0, the max lease length is equivalent to the default lease length.",
"option": "max",
N/A
N/A
N/A
{
"command": "ffx net dhcpd get parameter lease-length",
"options": [
{
"description": "the default lease length, in seconds, to be issued to clients.",
"option": "default",
"shorthand": "",
"value_type": "string"
},
{
"description": "the maximum lease length value, in seconds, which the server will issue to clients who have requested a specific lease length. With the default value of 0, the max lease length is equivalent to the default lease length.",
"option": "max",
N/A
N/A
N/A
{
"command": "ffx net dhcpd get parameter lease-length",
"options": [
{
"description": "the default lease length, in seconds, to be issued to clients.",
"option": "default",
"shorthand": "",
"value_type": "string"
},
{
"description": "the maximum lease length value, in seconds, which the server will issue to clients who have requested a specific lease length. With the default value of 0, the max lease length is equivalent to the default lease length.",
"option": "max",
N/A
N/A
N/A
{
"command": "ffx net dhcpd get parameter permitted-macs",
"options": [
{
"description": "the client MAC addresses which the server will issue leases to. By default, the server will not have a permitted MAC list, in which case it will attempt to issue a lease to every client which requests one. If permitted_macs has a non-zero length then the server will only respond to lease requests from clients with a MAC in the list.",
"option": "macs",
"shorthand": "",
"value_type": "string"
}
],
"short": "The client MAC addresses which the server will issue leases to."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get parameter permitted-macs",
"options": [
{
"description": "the client MAC addresses which the server will issue leases to. By default, the server will not have a permitted MAC list, in which case it will attempt to issue a lease to every client which requests one. If permitted_macs has a non-zero length then the server will only respond to lease requests from clients with a MAC in the list.",
"option": "macs",
"shorthand": "",
"value_type": "string"
}
],
"short": "The client MAC addresses which the server will issue leases to."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd get parameter statically-assigned-addrs",
"options": [
{
"description": "hosts which will be leased the addresses reserved by `assigned_addrs`.",
"option": "hosts",
"shorthand": "",
"value_type": "string"
},
{
"description": "addresses in the AddressPool which will not be leased to clients. Typically, a network administrator will statically assign these addresses to always-on network devices which should always have the same IP address, such as network printers.",
"option": "assigned-addrs",
N/A
N/A
N/A
{
"command": "ffx net dhcpd get parameter statically-assigned-addrs",
"options": [
{
"description": "hosts which will be leased the addresses reserved by `assigned_addrs`.",
"option": "hosts",
"shorthand": "",
"value_type": "string"
},
{
"description": "addresses in the AddressPool which will not be leased to clients. Typically, a network administrator will statically assign these addresses to always-on network devices which should always have the same IP address, such as network printers.",
"option": "assigned-addrs",
N/A
N/A
N/A
{
"command": "ffx net dhcpd get parameter statically-assigned-addrs",
"options": [
{
"description": "hosts which will be leased the addresses reserved by `assigned_addrs`.",
"option": "hosts",
"shorthand": "",
"value_type": "string"
},
{
"description": "addresses in the AddressPool which will not be leased to clients. Typically, a network administrator will statically assign these addresses to always-on network devices which should always have the same IP address, such as network printers.",
"option": "assigned-addrs",
N/A
N/A
N/A
{
"command": "ffx net dhcpd list",
"options": [],
"short": "A primary command to list the values of all DHCP options or server parameters."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd list option",
"options": [],
"short": "Perform the command on DHCP options."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd list parameter",
"options": [],
"short": "Perform the command on server parameters."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd reset",
"options": [],
"short": "A primary command to reset the values of all DHCP options or server parameters."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd reset option",
"options": [],
"short": "Perform the command on DHCP options."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd reset parameter",
"options": [],
"short": "Perform the command on server parameters."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set",
"options": [],
"short": "A primary command to set the value of a DHCP option or server parameter."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option",
"options": [],
"short": "A secondary command indicating a DHCP option argument."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option all-subnets-local",
"options": [
{
"description": "a flag indicating if all subents of the IP network to which the client is connected have the same MTU.",
"option": "local",
"shorthand": "",
"value_type": "bool"
}
],
"short": "Flag indicating if all subnets of the connected network have the same MTU."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option all-subnets-local",
"options": [
{
"description": "a flag indicating if all subents of the IP network to which the client is connected have the same MTU.",
"option": "local",
"shorthand": "",
"value_type": "bool"
}
],
"short": "Flag indicating if all subnets of the connected network have the same MTU."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option arp-cache-timeout",
"options": [
{
"description": "the timeout for ARP cache entries, in seconds.",
"option": "timeout",
"shorthand": "",
"value_type": "string"
}
],
"short": "Timeout for ARP cache entries."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option arp-cache-timeout",
"options": [
{
"description": "the timeout for ARP cache entries, in seconds.",
"option": "timeout",
"shorthand": "",
"value_type": "string"
}
],
"short": "Timeout for ARP cache entries."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option boot-file-size",
"options": [
{
"description": "the size of the client's default boot image in 512-octet blocks.",
"option": "size",
"shorthand": "",
"value_type": "string"
}
],
"short": "Size of the default boot image for the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option boot-file-size",
"options": [
{
"description": "the size of the client's default boot image in 512-octet blocks.",
"option": "size",
"shorthand": "",
"value_type": "string"
}
],
"short": "Size of the default boot image for the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option bootfile-name",
"options": [
{
"description": "the bootfile name for the client. This option should be used when the `file` field has been overloaded to carry options.",
"option": "name",
"shorthand": "",
"value_type": "string"
}
],
"short": "Bootfile name for the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option bootfile-name",
"options": [
{
"description": "the bootfile name for the client. This option should be used when the `file` field has been overloaded to carry options.",
"option": "name",
"shorthand": "",
"value_type": "string"
}
],
"short": "Bootfile name for the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option broadcast-address",
"options": [
{
"description": "the broadcast address of the client's subnet. Legal values are defined in RFC 1122.",
"option": "addr",
"shorthand": "",
"value_type": "string"
}
],
"short": "Broadcast address of the client's subnet."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option broadcast-address",
"options": [
{
"description": "the broadcast address of the client's subnet. Legal values are defined in RFC 1122.",
"option": "addr",
"shorthand": "",
"value_type": "string"
}
],
"short": "Broadcast address of the client's subnet."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option cookie-server",
"options": [
{
"description": "a list of RFC 865 Cookie servers available to the client, in order of preference.",
"option": "cookie-servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "RFC 865 Cookie servers available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option cookie-server",
"options": [
{
"description": "a list of RFC 865 Cookie servers available to the client, in order of preference.",
"option": "cookie-servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "RFC 865 Cookie servers available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option default-finger-server",
"options": [
{
"description": "a list of default Finger server addresses available to the client, listed in order of preference.",
"option": "finger-servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "Default Finger servers available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option default-finger-server",
"options": [
{
"description": "a list of default Finger server addresses available to the client, listed in order of preference.",
"option": "finger-servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "Default Finger servers available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option default-ip-ttl",
"options": [
{
"description": "the default time-to-live to use on outgoing IP datagrams. The value must be between 1 and 255.",
"option": "ttl",
"shorthand": "",
"value_type": "string"
}
],
"short": "Default time-to-live to use on outgoing IP datagrams."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option default-ip-ttl",
"options": [
{
"description": "the default time-to-live to use on outgoing IP datagrams. The value must be between 1 and 255.",
"option": "ttl",
"shorthand": "",
"value_type": "string"
}
],
"short": "Default time-to-live to use on outgoing IP datagrams."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option default-irc-server",
"options": [
{
"description": "a list of Internet Relay Chat server addresses available to the client, listed in order of preference.",
"option": "irc-servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "Default IRC servers available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option default-irc-server",
"options": [
{
"description": "a list of Internet Relay Chat server addresses available to the client, listed in order of preference.",
"option": "irc-servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "Default IRC servers available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option default-www-server",
"options": [
{
"description": "a list of default World Wide Web (WWW) server addresses available to the client, listed in order of preference.",
"option": "www-servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "Default WWW servers available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option default-www-server",
"options": [
{
"description": "a list of default World Wide Web (WWW) server addresses available to the client, listed in order of preference.",
"option": "www-servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "Default WWW servers available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option domain-name",
"options": [
{
"description": "the client's domain name for use in resolving hostnames in the DNS.",
"option": "name",
"shorthand": "",
"value_type": "string"
}
],
"short": "Domain name of the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option domain-name",
"options": [
{
"description": "the client's domain name for use in resolving hostnames in the DNS.",
"option": "name",
"shorthand": "",
"value_type": "string"
}
],
"short": "Domain name of the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option domain-name-server",
"options": [
{
"description": "a list of DNS servers available to the client, in order of preference;",
"option": "domain-name-servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "Domain Name System servers available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option domain-name-server",
"options": [
{
"description": "a list of DNS servers available to the client, in order of preference;",
"option": "domain-name-servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "Domain Name System servers available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option ethernet-encapsulation",
"options": [
{
"description": "a flag specifying that the client should use Ethernet v2 encapsulation when false, and IEEE 802.3 encapsulation when true.",
"option": "encapsulate",
"shorthand": "",
"value_type": "bool"
}
],
"short": "Flag specifying whether the client should use Ethernet v2 or IEEE 802.3 encapsulation."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option ethernet-encapsulation",
"options": [
{
"description": "a flag specifying that the client should use Ethernet v2 encapsulation when false, and IEEE 802.3 encapsulation when true.",
"option": "encapsulate",
"shorthand": "",
"value_type": "bool"
}
],
"short": "Flag specifying whether the client should use Ethernet v2 or IEEE 802.3 encapsulation."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option extensions-path",
"options": [
{
"description": "the path name to a TFTP-retrievable file. This file contains data which can be interpreted as the BOOTP vendor-extension field. Unlike the BOOTP vendor-extension field, this file has an unconstrained length and any references to Tag 18 are ignored.",
"option": "path",
"shorthand": "",
"value_type": "string"
}
],
"short": "Path name to a TFTP-retrievable file containing vendor-extension information."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option extensions-path",
"options": [
{
"description": "the path name to a TFTP-retrievable file. This file contains data which can be interpreted as the BOOTP vendor-extension field. Unlike the BOOTP vendor-extension field, this file has an unconstrained length and any references to Tag 18 are ignored.",
"option": "path",
"shorthand": "",
"value_type": "string"
}
],
"short": "Path name to a TFTP-retrievable file containing vendor-extension information."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option host-name",
"options": [
{
"description": "the name of client, which may or may not be qualified with the local domain name.",
"option": "name",
"shorthand": "",
"value_type": "string"
}
],
"short": "Name of the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option host-name",
"options": [
{
"description": "the name of client, which may or may not be qualified with the local domain name.",
"option": "name",
"shorthand": "",
"value_type": "string"
}
],
"short": "Name of the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option impress-server",
"options": [
{
"description": "a list of Imagen Impress servers available to the client, in order of preference.",
"option": "impress-servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "Imagen Impress servers available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option impress-server",
"options": [
{
"description": "a list of Imagen Impress servers available to the client, in order of preference.",
"option": "impress-servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "Imagen Impress servers available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option interface-mtu",
"options": [
{
"description": "the MTU for the client's interface. Minimum value of 68.",
"option": "mtu",
"shorthand": "",
"value_type": "string"
}
],
"short": "MTU for the client's interface."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option interface-mtu",
"options": [
{
"description": "the MTU for the client's interface. Minimum value of 68.",
"option": "mtu",
"shorthand": "",
"value_type": "string"
}
],
"short": "MTU for the client's interface."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option ip-forwarding",
"options": [
{
"description": "a flag which will enabled IP layer packet forwarding when true.",
"option": "enabled",
"shorthand": "",
"value_type": "bool"
}
],
"short": "Flag enabling/disabling IP layer packet forwarding."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option ip-forwarding",
"options": [
{
"description": "a flag which will enabled IP layer packet forwarding when true.",
"option": "enabled",
"shorthand": "",
"value_type": "bool"
}
],
"short": "Flag enabling/disabling IP layer packet forwarding."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option log-server",
"options": [
{
"description": "a list of MIT-LCS UDP Log servers available to the client, in order of preference.",
"option": "log-servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "MIT-LCS UDP Log servers available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option log-server",
"options": [
{
"description": "a list of MIT-LCS UDP Log servers available to the client, in order of preference.",
"option": "log-servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "MIT-LCS UDP Log servers available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option lpr-server",
"options": [
{
"description": "a list of RFC 1179 Line Printer servers available to the client, in order of preference.",
"option": "lpr-servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "RFC 1179 Line Printer servers available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option lpr-server",
"options": [
{
"description": "a list of RFC 1179 Line Printer servers available to the client, in order of preference.",
"option": "lpr-servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "RFC 1179 Line Printer servers available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option mask-supplier",
"options": [
{
"description": "a flag indicating whether the client should respond to subnet mask discovery requests via ICMP.",
"option": "supplier",
"shorthand": "",
"value_type": "bool"
}
],
"short": "Flag indicating whether the client should respond to subnet mask discovery requests via ICMP."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option mask-supplier",
"options": [
{
"description": "a flag indicating whether the client should respond to subnet mask discovery requests via ICMP.",
"option": "supplier",
"shorthand": "",
"value_type": "bool"
}
],
"short": "Flag indicating whether the client should respond to subnet mask discovery requests via ICMP."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option max-datagram-reassembly-size",
"options": [
{
"description": "the maximum sized datagram that the client should be able to reassemble, in octets. The minimum legal value is 576.",
"option": "size",
"shorthand": "",
"value_type": "string"
}
],
"short": "Maximum sized datagram that the client should be able to reassemble."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option max-datagram-reassembly-size",
"options": [
{
"description": "the maximum sized datagram that the client should be able to reassemble, in octets. The minimum legal value is 576.",
"option": "size",
"shorthand": "",
"value_type": "string"
}
],
"short": "Maximum sized datagram that the client should be able to reassemble."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option max-message-size",
"options": [
{
"description": "the maximum length in octets of a DHCP message that the participant is willing to accept. The minimum value is 576.",
"option": "length",
"shorthand": "",
"value_type": "string"
}
],
"short": "Maximum length of a DHCP message that the participant is willing to accept."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option max-message-size",
"options": [
{
"description": "the maximum length in octets of a DHCP message that the participant is willing to accept. The minimum value is 576.",
"option": "length",
"shorthand": "",
"value_type": "string"
}
],
"short": "Maximum length of a DHCP message that the participant is willing to accept."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option merit-dump-file",
"options": [
{
"description": "the path name to the client's core dump in the event the client crashes.",
"option": "path",
"shorthand": "",
"value_type": "string"
}
],
"short": "Path name of a core dump file."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option merit-dump-file",
"options": [
{
"description": "the path name to the client's core dump in the event the client crashes.",
"option": "path",
"shorthand": "",
"value_type": "string"
}
],
"short": "Path name of a core dump file."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option mobile-ip-home-agent",
"options": [
{
"description": "a list of mobile IP home agent addresses available to the client, listed in order of preference.",
"option": "home-agents",
"shorthand": "",
"value_type": "string"
}
],
"short": "Mobile IP home agents available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option mobile-ip-home-agent",
"options": [
{
"description": "a list of mobile IP home agent addresses available to the client, listed in order of preference.",
"option": "home-agents",
"shorthand": "",
"value_type": "string"
}
],
"short": "Mobile IP home agents available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option name-server",
"options": [
{
"description": "a list of IEN 116 Name servers available to the client, in order of preference.",
"option": "name-servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "IEN 116 Name servers available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option name-server",
"options": [
{
"description": "a list of IEN 116 Name servers available to the client, in order of preference.",
"option": "name-servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "IEN 116 Name servers available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option net-bios-over-tcpip-distribution-server",
"options": [
{
"description": "a list of NetBIOS datagram distribution servers available to the client, listed in order of preference.",
"option": "servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "NetBIOS datagram distribution servers available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option net-bios-over-tcpip-distribution-server",
"options": [
{
"description": "a list of NetBIOS datagram distribution servers available to the client, listed in order of preference.",
"option": "servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "NetBIOS datagram distribution servers available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option net-bios-over-tcpip-name-server",
"options": [
{
"description": "a list of NetBIOS name server addresses available to the client, listed in order of preference.",
"option": "servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "NetBIOS name servers available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option net-bios-over-tcpip-name-server",
"options": [
{
"description": "a list of NetBIOS name server addresses available to the client, listed in order of preference.",
"option": "servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "NetBIOS name servers available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option net-bios-over-tcpip-node-type",
"options": [],
"short": "The NetBIOS node type which should be used by the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option net-bios-over-tcpip-node-type b-node",
"options": [],
"short": "A B node type."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option net-bios-over-tcpip-node-type h-node",
"options": [],
"short": "A H node type."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option net-bios-over-tcpip-node-type m-node",
"options": [],
"short": "A M node type."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option net-bios-over-tcpip-node-type p-node",
"options": [],
"short": "A P node type."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option net-bios-over-tcpip-scope",
"options": [
{
"description": "the NetBIOS over TCP/IP scope parameter, as defined in RFC 1001, for the client.",
"option": "scope",
"shorthand": "",
"value_type": "string"
}
],
"short": "NetBIOS scope parameter for the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option net-bios-over-tcpip-scope",
"options": [
{
"description": "the NetBIOS over TCP/IP scope parameter, as defined in RFC 1001, for the client.",
"option": "scope",
"shorthand": "",
"value_type": "string"
}
],
"short": "NetBIOS scope parameter for the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option network-information-servers",
"options": [
{
"description": "a list of Network Information Service server addresses available to the client, listed in order of preference.",
"option": "servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "Network Information Service servers available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option network-information-servers",
"options": [
{
"description": "a list of Network Information Service server addresses available to the client, listed in order of preference.",
"option": "servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "Network Information Service servers available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option network-information-service-domain",
"options": [
{
"description": "the name of the client's Network Information Service domain.",
"option": "domain-name",
"shorthand": "",
"value_type": "string"
}
],
"short": "Name of the client's Network Information Service domain."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option network-information-service-domain",
"options": [
{
"description": "the name of the client's Network Information Service domain.",
"option": "domain-name",
"shorthand": "",
"value_type": "string"
}
],
"short": "Name of the client's Network Information Service domain."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option network-information-service-plus-domain",
"options": [
{
"description": "the name of the client's Network Information System+ domain.",
"option": "domain-name",
"shorthand": "",
"value_type": "string"
}
],
"short": "Network Information System+ domain name."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option network-information-service-plus-domain",
"options": [
{
"description": "the name of the client's Network Information System+ domain.",
"option": "domain-name",
"shorthand": "",
"value_type": "string"
}
],
"short": "Network Information System+ domain name."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option network-information-service-plus-servers",
"options": [
{
"description": "a list of Network Information System+ server addresses available to the client, listed in order of preference.",
"option": "servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "Network Information System+ servers available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option network-information-service-plus-servers",
"options": [
{
"description": "a list of Network Information System+ server addresses available to the client, listed in order of preference.",
"option": "servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "Network Information System+ servers available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option network-time-protocol-servers",
"options": [
{
"description": "a list of Network Time Protocol (NTP) server addresses available to the client, listed in order of preference.",
"option": "servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "Network Time Protocol servers available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option network-time-protocol-servers",
"options": [
{
"description": "a list of Network Time Protocol (NTP) server addresses available to the client, listed in order of preference.",
"option": "servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "Network Time Protocol servers available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option nntp-server",
"options": [
{
"description": "a list Network News Transport Protocol (NNTP) server addresses available to the client, listed in order of preference.",
"option": "nntp-servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "NNTP servers available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option nntp-server",
"options": [
{
"description": "a list Network News Transport Protocol (NNTP) server addresses available to the client, listed in order of preference.",
"option": "nntp-servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "NNTP servers available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option non-local-source-routing",
"options": [
{
"description": "a flag which will enable forwarding of IP packets with non-local source routes.",
"option": "enabled",
"shorthand": "",
"value_type": "bool"
}
],
"short": "Flag enabling/disabling forwarding of IP packets with non-local source routes."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option non-local-source-routing",
"options": [
{
"description": "a flag which will enable forwarding of IP packets with non-local source routes.",
"option": "enabled",
"shorthand": "",
"value_type": "bool"
}
],
"short": "Flag enabling/disabling forwarding of IP packets with non-local source routes."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option path-mtu-aging-timeout",
"options": [
{
"description": "the timeout, in seconds, to be used when again Path MTU values by the mechanism in RFC 1191.",
"option": "timeout",
"shorthand": "",
"value_type": "string"
}
],
"short": "Timeout to use when aging Path MTU values."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option path-mtu-aging-timeout",
"options": [
{
"description": "the timeout, in seconds, to be used when again Path MTU values by the mechanism in RFC 1191.",
"option": "timeout",
"shorthand": "",
"value_type": "string"
}
],
"short": "Timeout to use when aging Path MTU values."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option path-mtu-plateau-table",
"options": [
{
"description": "a list of MTU sizes, ordered from smallest to largest. The smallest value cannot be smaller than 68.",
"option": "mtu-sizes",
"shorthand": "",
"value_type": "string"
}
],
"short": "Table of MTU sizes for Path MTU Discovery."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option path-mtu-plateau-table",
"options": [
{
"description": "a list of MTU sizes, ordered from smallest to largest. The smallest value cannot be smaller than 68.",
"option": "mtu-sizes",
"shorthand": "",
"value_type": "string"
}
],
"short": "Table of MTU sizes for Path MTU Discovery."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option perform-mask-discovery",
"options": [
{
"description": "a flag indicating whether the client should perform subnet mask discovery via ICMP.",
"option": "do-discovery",
"shorthand": "",
"value_type": "bool"
}
],
"short": "Flag indicating whether the client should perform subnet mask discovery via ICMP."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option perform-mask-discovery",
"options": [
{
"description": "a flag indicating whether the client should perform subnet mask discovery via ICMP.",
"option": "do-discovery",
"shorthand": "",
"value_type": "bool"
}
],
"short": "Flag indicating whether the client should perform subnet mask discovery via ICMP."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option perform-router-discovery",
"options": [
{
"description": "a flag indicating whether the client should solicit routers using Router Discovery as defined in RFC 1256.",
"option": "do-discovery",
"shorthand": "",
"value_type": "bool"
}
],
"short": "Flag indicating whether the client should solicit routers using Router Discovery."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option perform-router-discovery",
"options": [
{
"description": "a flag indicating whether the client should solicit routers using Router Discovery as defined in RFC 1256.",
"option": "do-discovery",
"shorthand": "",
"value_type": "bool"
}
],
"short": "Flag indicating whether the client should solicit routers using Router Discovery."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option policy-filter",
"options": [
{
"description": "a list of IP Address and Subnet Mask pairs. If an incoming source-routed packet has a next-hop that does not match one of these pairs, then the packet will be dropped.",
"option": "addresses",
"shorthand": "",
"value_type": "string"
}
],
"short": "Policy filters for non-local source routing."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option policy-filter",
"options": [
{
"description": "a list of IP Address and Subnet Mask pairs. If an incoming source-routed packet has a next-hop that does not match one of these pairs, then the packet will be dropped.",
"option": "addresses",
"shorthand": "",
"value_type": "string"
}
],
"short": "Policy filters for non-local source routing."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option pop3-server",
"options": [
{
"description": "a list of Post Office Protocol (POP3) server addresses available to the client, listed in order of preference.",
"option": "pop3-servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "POP3 servers available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option pop3-server",
"options": [
{
"description": "a list of Post Office Protocol (POP3) server addresses available to the client, listed in order of preference.",
"option": "pop3-servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "POP3 servers available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option rebinding-time-value",
"options": [
{
"description": "the time interval, in seconds, after address assignment at which the client will transition to the Rebinding state.",
"option": "interval",
"shorthand": "",
"value_type": "string"
}
],
"short": "Time interval from address assignment at which the client transitions to a Rebinding state."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option rebinding-time-value",
"options": [
{
"description": "the time interval, in seconds, after address assignment at which the client will transition to the Rebinding state.",
"option": "interval",
"shorthand": "",
"value_type": "string"
}
],
"short": "Time interval from address assignment at which the client transitions to a Rebinding state."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option renewal-time-value",
"options": [
{
"description": "the time interval, in seconds, after address assignment at which the client will transition to the Renewing state.",
"option": "interval",
"shorthand": "",
"value_type": "string"
}
],
"short": "Time interval from address assignment at which the client transitions to a Renewing state."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option renewal-time-value",
"options": [
{
"description": "the time interval, in seconds, after address assignment at which the client will transition to the Renewing state.",
"option": "interval",
"shorthand": "",
"value_type": "string"
}
],
"short": "Time interval from address assignment at which the client transitions to a Renewing state."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option resource-location-server",
"options": [
{
"description": "a list of RFC 887 Resource Location servers available to the client, in order of preference.",
"option": "resource-location-servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "RFC 887 Resource Location servers available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option resource-location-server",
"options": [
{
"description": "a list of RFC 887 Resource Location servers available to the client, in order of preference.",
"option": "resource-location-servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "RFC 887 Resource Location servers available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option root-path",
"options": [
{
"description": "the path name to a TFTP-retrievable file. This file contains data which can be interpreted as the BOOTP vendor-extension field. Unlike the BOOTP vendor-extension field, this file has an unconstrained length and any references to Tag 18 are ignored.",
"option": "path",
"shorthand": "",
"value_type": "string"
}
],
"short": "Path name to a TFTP-retrievable file containing vendor-extension information."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option root-path",
"options": [
{
"description": "the path name to a TFTP-retrievable file. This file contains data which can be interpreted as the BOOTP vendor-extension field. Unlike the BOOTP vendor-extension field, this file has an unconstrained length and any references to Tag 18 are ignored.",
"option": "path",
"shorthand": "",
"value_type": "string"
}
],
"short": "Path name to a TFTP-retrievable file containing vendor-extension information."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option router",
"options": [
{
"description": "a list of the routers in a client's subnet, listed in order of preference.",
"option": "routers",
"shorthand": "",
"value_type": "string"
}
],
"short": "The routers within a client's subnet."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option router",
"options": [
{
"description": "a list of the routers in a client's subnet, listed in order of preference.",
"option": "routers",
"shorthand": "",
"value_type": "string"
}
],
"short": "The routers within a client's subnet."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option router-solicitation-address",
"options": [
{
"description": "the address to which the client should transmit Router Solicitation requests.",
"option": "addr",
"shorthand": "",
"value_type": "string"
}
],
"short": "Destination address for Router Solicitation requests."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option router-solicitation-address",
"options": [
{
"description": "the address to which the client should transmit Router Solicitation requests.",
"option": "addr",
"shorthand": "",
"value_type": "string"
}
],
"short": "Destination address for Router Solicitation requests."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option smtp-server",
"options": [
{
"description": "a list of Simple Mail Transport Protocol (SMTP) server address available to the client, listed in order of preference.",
"option": "smtp-servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "SMTP servers available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option smtp-server",
"options": [
{
"description": "a list of Simple Mail Transport Protocol (SMTP) server address available to the client, listed in order of preference.",
"option": "smtp-servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "SMTP servers available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option static-route",
"options": [
{
"description": "a list of Destination address/Next-hop address pairs defining static routes for the client's routing table. The routes should be listed in descending order of priority. It is illegal to use 0.0.0.0 as the destination in a static route.",
"option": "routes",
"shorthand": "",
"value_type": "string"
}
],
"short": "Static Routes which the client should put in its routing cache."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option static-route",
"options": [
{
"description": "a list of Destination address/Next-hop address pairs defining static routes for the client's routing table. The routes should be listed in descending order of priority. It is illegal to use 0.0.0.0 as the destination in a static route.",
"option": "routes",
"shorthand": "",
"value_type": "string"
}
],
"short": "Static Routes which the client should put in its routing cache."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option stda-server",
"options": [
{
"description": "a list of StreetTalk Directory Assistance server addresses available to the client, listed in order of preference.",
"option": "stda-servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "StreetTalk Directory Assistance servers available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option stda-server",
"options": [
{
"description": "a list of StreetTalk Directory Assistance server addresses available to the client, listed in order of preference.",
"option": "stda-servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "StreetTalk Directory Assistance servers available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option street-talk-server",
"options": [
{
"description": "a list of StreetTalk server addresses available to the client, listed in order of preference.",
"option": "streettalk-servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "StreetTalk servers available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option street-talk-server",
"options": [
{
"description": "a list of StreetTalk server addresses available to the client, listed in order of preference.",
"option": "streettalk-servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "StreetTalk servers available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option subnet-mask",
"options": [
{
"description": "a 32-bit IPv4 subnet mask.",
"option": "mask",
"shorthand": "",
"value_type": "string"
}
],
"short": "The client's subnet mask."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option subnet-mask",
"options": [
{
"description": "a 32-bit IPv4 subnet mask.",
"option": "mask",
"shorthand": "",
"value_type": "string"
}
],
"short": "The client's subnet mask."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option swap-server",
"options": [
{
"description": "the address of the client's swap server.",
"option": "address",
"shorthand": "",
"value_type": "string"
}
],
"short": "Address of the client's swap server."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option swap-server",
"options": [
{
"description": "the address of the client's swap server.",
"option": "address",
"shorthand": "",
"value_type": "string"
}
],
"short": "Address of the client's swap server."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option tcp-default-ttl",
"options": [
{
"description": "the default time-to-live that the client should use for outgoing TCP segments. The minimum value is 1.",
"option": "ttl",
"shorthand": "",
"value_type": "string"
}
],
"short": "Default time-to-live for outgoing TCP segments."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option tcp-default-ttl",
"options": [
{
"description": "the default time-to-live that the client should use for outgoing TCP segments. The minimum value is 1.",
"option": "ttl",
"shorthand": "",
"value_type": "string"
}
],
"short": "Default time-to-live for outgoing TCP segments."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option tcp-keepalive-garbage",
"options": [
{
"description": "a flag specifying whether the client should send TCP keepalive messages with an octet of garbage for compatibility with older implementations.",
"option": "send-garbage",
"shorthand": "",
"value_type": "bool"
}
],
"short": "Flag specifying whether the client should send TCP keepalive messages with an octet of garbage."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option tcp-keepalive-garbage",
"options": [
{
"description": "a flag specifying whether the client should send TCP keepalive messages with an octet of garbage for compatibility with older implementations.",
"option": "send-garbage",
"shorthand": "",
"value_type": "bool"
}
],
"short": "Flag specifying whether the client should send TCP keepalive messages with an octet of garbage."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option tcp-keepalive-interval",
"options": [
{
"description": "the interval, in seconds, the client should wait before sending a TCP keepalive message. A value of 0 indicates that the client should not send keepalive messages unless specifically requested by an application.",
"option": "interval",
"shorthand": "",
"value_type": "string"
}
],
"short": "Interval the client should wait before sending a TCP keepalive message."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option tcp-keepalive-interval",
"options": [
{
"description": "the interval, in seconds, the client should wait before sending a TCP keepalive message. A value of 0 indicates that the client should not send keepalive messages unless specifically requested by an application.",
"option": "interval",
"shorthand": "",
"value_type": "string"
}
],
"short": "Interval the client should wait before sending a TCP keepalive message."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option tftp-server-name",
"options": [
{
"description": "the TFTP server name available to the client. This option should be used when the `sname` field has been overloaded to carry options.",
"option": "name",
"shorthand": "",
"value_type": "string"
}
],
"short": "TFTP server available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option tftp-server-name",
"options": [
{
"description": "the TFTP server name available to the client. This option should be used when the `sname` field has been overloaded to carry options.",
"option": "name",
"shorthand": "",
"value_type": "string"
}
],
"short": "TFTP server available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option time-offset",
"options": [
{
"description": "the client's offset from UTC in seconds. A positive offset is east of the zero meridian, and a negative offset is west of the zero meridian.",
"option": "offset",
"shorthand": "",
"value_type": "string"
}
],
"short": "The client's offset from UTC."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option time-offset",
"options": [
{
"description": "the client's offset from UTC in seconds. A positive offset is east of the zero meridian, and a negative offset is west of the zero meridian.",
"option": "offset",
"shorthand": "",
"value_type": "string"
}
],
"short": "The client's offset from UTC."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option time-server",
"options": [
{
"description": "a list of time servers available to the client, in order of preference.",
"option": "time-servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "Time Protocol servers available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option time-server",
"options": [
{
"description": "a list of time servers available to the client, in order of preference.",
"option": "time-servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "Time Protocol servers available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option trailer-encapsulation",
"options": [
{
"description": "a flag specifying whether the client negotiate the use of trailers when using ARP, per RFC 893.",
"option": "trailers",
"shorthand": "",
"value_type": "bool"
}
],
"short": "Flag specifying whether the client should negotiate the use of trailers in ARP."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option trailer-encapsulation",
"options": [
{
"description": "a flag specifying whether the client negotiate the use of trailers when using ARP, per RFC 893.",
"option": "trailers",
"shorthand": "",
"value_type": "bool"
}
],
"short": "Flag specifying whether the client should negotiate the use of trailers in ARP."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option vendor-specific-information",
"options": [
{
"description": "an opaque object of octets for exchanging vendor-specific information.",
"option": "data",
"shorthand": "",
"value_type": "string"
}
],
"short": "Option for exchanging vendor-specific information between the DHCP client and DHCP server."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option vendor-specific-information",
"options": [
{
"description": "an opaque object of octets for exchanging vendor-specific information.",
"option": "data",
"shorthand": "",
"value_type": "string"
}
],
"short": "Option for exchanging vendor-specific information between the DHCP client and DHCP server."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option x-window-system-display-manager",
"options": [
{
"description": "a list of X Window System Display Manager system addresses available to the client, listed in order of preference.",
"option": "display-servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "X window System Display Manager systems available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option x-window-system-display-manager",
"options": [
{
"description": "a list of X Window System Display Manager system addresses available to the client, listed in order of preference.",
"option": "display-servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "X window System Display Manager systems available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option x-window-system-font-server",
"options": [
{
"description": "a list of X Window System Font server addresses available to the client, listed in order of preference.",
"option": "servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "X Window System Font servers available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set option x-window-system-font-server",
"options": [
{
"description": "a list of X Window System Font server addresses available to the client, listed in order of preference.",
"option": "servers",
"shorthand": "",
"value_type": "string"
}
],
"short": "X Window System Font servers available to the client."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set parameter",
"options": [],
"short": "A secondary command indicating a server parameter argument."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set parameter address-pool",
"options": [
{
"description": "the prefix length of the network's subnet mask",
"option": "prefix-length",
"shorthand": "",
"value_type": "string"
},
{
"description": "the starting address, inclusive, of the range of addresses which the DHCP server will lease to clients",
"option": "range-start",
N/A
N/A
N/A
{
"command": "ffx net dhcpd set parameter address-pool",
"options": [
{
"description": "the prefix length of the network's subnet mask",
"option": "prefix-length",
"shorthand": "",
"value_type": "string"
},
{
"description": "the starting address, inclusive, of the range of addresses which the DHCP server will lease to clients",
"option": "range-start",
N/A
N/A
N/A
{
"command": "ffx net dhcpd set parameter address-pool",
"options": [
{
"description": "the prefix length of the network's subnet mask",
"option": "prefix-length",
"shorthand": "",
"value_type": "string"
},
{
"description": "the starting address, inclusive, of the range of addresses which the DHCP server will lease to clients",
"option": "range-start",
N/A
N/A
N/A
{
"command": "ffx net dhcpd set parameter address-pool",
"options": [
{
"description": "the prefix length of the network's subnet mask",
"option": "prefix-length",
"shorthand": "",
"value_type": "string"
},
{
"description": "the starting address, inclusive, of the range of addresses which the DHCP server will lease to clients",
"option": "range-start",
N/A
N/A
N/A
{
"command": "ffx net dhcpd set parameter arp-probe",
"options": [
{
"description": "enables server behavior where the server ARPs an IP address prior to issuing it in a lease. If the server receives a response, the server will mark the address as in-use and try again with a different address. By default, this behavior is disabled.",
"option": "enabled",
"shorthand": "",
"value_type": "bool"
}
],
"short": "Enables server behavior where the server ARPs an IP address prior to issuing it in a lease."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set parameter arp-probe",
"options": [
{
"description": "enables server behavior where the server ARPs an IP address prior to issuing it in a lease. If the server receives a response, the server will mark the address as in-use and try again with a different address. By default, this behavior is disabled.",
"option": "enabled",
"shorthand": "",
"value_type": "bool"
}
],
"short": "Enables server behavior where the server ARPs an IP address prior to issuing it in a lease."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set parameter bound-device-names",
"options": [],
"short": "The names of the network devices on which the server will listen."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set parameter ip-addrs",
"options": [
{
"description": "a list of IPv4 Addresses to which the server is bound.",
"option": "addrs",
"shorthand": "",
"value_type": "string"
}
],
"short": "The IPv4 addresses to which the server is bound."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set parameter ip-addrs",
"options": [
{
"description": "a list of IPv4 Addresses to which the server is bound.",
"option": "addrs",
"shorthand": "",
"value_type": "string"
}
],
"short": "The IPv4 addresses to which the server is bound."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set parameter lease-length",
"options": [
{
"description": "the default lease length, in seconds, to be issued to clients.",
"option": "default",
"shorthand": "",
"value_type": "string"
},
{
"description": "the maximum lease length value, in seconds, which the server will issue to clients who have requested a specific lease length. With the default value of 0, the max lease length is equivalent to the default lease length.",
"option": "max",
N/A
N/A
N/A
{
"command": "ffx net dhcpd set parameter lease-length",
"options": [
{
"description": "the default lease length, in seconds, to be issued to clients.",
"option": "default",
"shorthand": "",
"value_type": "string"
},
{
"description": "the maximum lease length value, in seconds, which the server will issue to clients who have requested a specific lease length. With the default value of 0, the max lease length is equivalent to the default lease length.",
"option": "max",
N/A
N/A
N/A
{
"command": "ffx net dhcpd set parameter lease-length",
"options": [
{
"description": "the default lease length, in seconds, to be issued to clients.",
"option": "default",
"shorthand": "",
"value_type": "string"
},
{
"description": "the maximum lease length value, in seconds, which the server will issue to clients who have requested a specific lease length. With the default value of 0, the max lease length is equivalent to the default lease length.",
"option": "max",
N/A
N/A
N/A
{
"command": "ffx net dhcpd set parameter permitted-macs",
"options": [
{
"description": "the client MAC addresses which the server will issue leases to. By default, the server will not have a permitted MAC list, in which case it will attempt to issue a lease to every client which requests one. If permitted_macs has a non-zero length then the server will only respond to lease requests from clients with a MAC in the list.",
"option": "macs",
"shorthand": "",
"value_type": "string"
}
],
"short": "The client MAC addresses which the server will issue leases to."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set parameter permitted-macs",
"options": [
{
"description": "the client MAC addresses which the server will issue leases to. By default, the server will not have a permitted MAC list, in which case it will attempt to issue a lease to every client which requests one. If permitted_macs has a non-zero length then the server will only respond to lease requests from clients with a MAC in the list.",
"option": "macs",
"shorthand": "",
"value_type": "string"
}
],
"short": "The client MAC addresses which the server will issue leases to."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd set parameter statically-assigned-addrs",
"options": [
{
"description": "hosts which will be leased the addresses reserved by `assigned_addrs`.",
"option": "hosts",
"shorthand": "",
"value_type": "string"
},
{
"description": "addresses in the AddressPool which will not be leased to clients. Typically, a network administrator will statically assign these addresses to always-on network devices which should always have the same IP address, such as network printers.",
"option": "assigned-addrs",
N/A
N/A
N/A
{
"command": "ffx net dhcpd set parameter statically-assigned-addrs",
"options": [
{
"description": "hosts which will be leased the addresses reserved by `assigned_addrs`.",
"option": "hosts",
"shorthand": "",
"value_type": "string"
},
{
"description": "addresses in the AddressPool which will not be leased to clients. Typically, a network administrator will statically assign these addresses to always-on network devices which should always have the same IP address, such as network printers.",
"option": "assigned-addrs",
N/A
N/A
N/A
{
"command": "ffx net dhcpd set parameter statically-assigned-addrs",
"options": [
{
"description": "hosts which will be leased the addresses reserved by `assigned_addrs`.",
"option": "hosts",
"shorthand": "",
"value_type": "string"
},
{
"description": "addresses in the AddressPool which will not be leased to clients. Typically, a network administrator will statically assign these addresses to always-on network devices which should always have the same IP address, such as network printers.",
"option": "assigned-addrs",
N/A
N/A
N/A
{
"command": "ffx net dhcpd start",
"options": [],
"short": "A primary command to start the DHCP server."
}
N/A
N/A
N/A
{
"command": "ffx net dhcpd stop",
"options": [],
"short": "A primary command to stop the DHCP server."
}
N/A
N/A
N/A
{
"command": "ffx net dns",
"options": [],
"short": "commands to control the dns resolver"
}
N/A
N/A
N/A
{
"command": "ffx net dns lookup",
"options": [
{
"description": "include ipv4 results (defaults to true)",
"option": "ipv4",
"shorthand": "",
"value_type": "string"
},
{
"description": "include ipv6 results (defaults to true)",
"option": "ipv6",
N/A
N/A
N/A
{
"command": "ffx net dns lookup",
"options": [
{
"description": "include ipv4 results (defaults to true)",
"option": "ipv4",
"shorthand": "",
"value_type": "string"
},
{
"description": "include ipv6 results (defaults to true)",
"option": "ipv6",
N/A
N/A
N/A
{
"command": "ffx net dns lookup",
"options": [
{
"description": "include ipv4 results (defaults to true)",
"option": "ipv4",
"shorthand": "",
"value_type": "string"
},
{
"description": "include ipv6 results (defaults to true)",
"option": "ipv6",
N/A
N/A
N/A
{
"command": "ffx net dns lookup",
"options": [
{
"description": "include ipv4 results (defaults to true)",
"option": "ipv4",
"shorthand": "",
"value_type": "string"
},
{
"description": "include ipv6 results (defaults to true)",
"option": "ipv6",
N/A
N/A
N/A
{
"command": "ffx net filter",
"options": [],
"short": "commands for configuring packet filtering"
}
N/A
N/A
N/A
{
"command": "ffx net filter create",
"options": [
{
"description": "the name of the controller to create (or connect to, if existing)",
"option": "controller",
"shorthand": "",
"value_type": "string"
},
{
"description": "whether the resource creation should be idempotent, i.e. succeed even if the resource already exists",
"option": "idempotent",
N/A
N/A
N/A
{
"command": "ffx net filter create",
"options": [
{
"description": "the name of the controller to create (or connect to, if existing)",
"option": "controller",
"shorthand": "",
"value_type": "string"
},
{
"description": "whether the resource creation should be idempotent, i.e. succeed even if the resource already exists",
"option": "idempotent",
N/A
N/A
N/A
{
"command": "ffx net filter create",
"options": [
{
"description": "the name of the controller to create (or connect to, if existing)",
"option": "controller",
"shorthand": "",
"value_type": "string"
},
{
"description": "whether the resource creation should be idempotent, i.e. succeed even if the resource already exists",
"option": "idempotent",
N/A
N/A
N/A
{
"command": "ffx net filter create namespace",
"options": [
{
"description": "the name of the namespace",
"option": "name",
"shorthand": "",
"value_type": "string"
},
{
"description": "the IP domain of the namespace",
"option": "domain",
N/A
N/A
N/A
{
"command": "ffx net filter create namespace",
"options": [
{
"description": "the name of the namespace",
"option": "name",
"shorthand": "",
"value_type": "string"
},
{
"description": "the IP domain of the namespace",
"option": "domain",
N/A
N/A
N/A
{
"command": "ffx net filter create namespace",
"options": [
{
"description": "the name of the namespace",
"option": "name",
"shorthand": "",
"value_type": "string"
},
{
"description": "the IP domain of the namespace",
"option": "domain",
N/A
N/A
N/A
{
"command": "ffx net filter create routine",
"options": [
{
"description": "the namespace that contains the routine",
"option": "namespace",
"shorthand": "",
"value_type": "string"
},
{
"description": "the name of the routine",
"option": "name",
N/A
N/A
N/A
{
"command": "ffx net filter create routine",
"options": [
{
"description": "the namespace that contains the routine",
"option": "namespace",
"shorthand": "",
"value_type": "string"
},
{
"description": "the name of the routine",
"option": "name",
N/A
N/A
N/A
{
"command": "ffx net filter create routine",
"options": [
{
"description": "the namespace that contains the routine",
"option": "namespace",
"shorthand": "",
"value_type": "string"
},
{
"description": "the name of the routine",
"option": "name",
N/A
N/A
N/A
{
"command": "ffx net filter create routine",
"options": [
{
"description": "the namespace that contains the routine",
"option": "namespace",
"shorthand": "",
"value_type": "string"
},
{
"description": "the name of the routine",
"option": "name",
N/A
N/A
N/A
{
"command": "ffx net filter create routine",
"options": [
{
"description": "the namespace that contains the routine",
"option": "namespace",
"shorthand": "",
"value_type": "string"
},
{
"description": "the name of the routine",
"option": "name",
N/A
N/A
N/A
{
"command": "ffx net filter create routine",
"options": [
{
"description": "the namespace that contains the routine",
"option": "namespace",
"shorthand": "",
"value_type": "string"
},
{
"description": "the name of the routine",
"option": "name",
N/A
N/A
N/A
{
"command": "ffx net filter create rule",
"options": [
{
"description": "the namespace that contains the rule",
"option": "namespace",
"shorthand": "",
"value_type": "string"
},
{
"description": "the routine that contains the rule",
"option": "routine",
N/A
N/A
N/A
{
"command": "ffx net filter create rule",
"options": [
{
"description": "the namespace that contains the rule",
"option": "namespace",
"shorthand": "",
"value_type": "string"
},
{
"description": "the routine that contains the rule",
"option": "routine",
N/A
N/A
N/A
{
"command": "ffx net filter create rule",
"options": [
{
"description": "the namespace that contains the rule",
"option": "namespace",
"shorthand": "",
"value_type": "string"
},
{
"description": "the routine that contains the rule",
"option": "routine",
N/A
N/A
N/A
{
"command": "ffx net filter create rule",
"options": [
{
"description": "the namespace that contains the rule",
"option": "namespace",
"shorthand": "",
"value_type": "string"
},
{
"description": "the routine that contains the rule",
"option": "routine",
N/A
N/A
N/A
{
"command": "ffx net filter create rule",
"options": [
{
"description": "the namespace that contains the rule",
"option": "namespace",
"shorthand": "",
"value_type": "string"
},
{
"description": "the routine that contains the rule",
"option": "routine",
N/A
N/A
N/A
{
"command": "ffx net filter create rule",
"options": [
{
"description": "the namespace that contains the rule",
"option": "namespace",
"shorthand": "",
"value_type": "string"
},
{
"description": "the routine that contains the rule",
"option": "routine",
N/A
N/A
N/A
{
"command": "ffx net filter create rule",
"options": [
{
"description": "the namespace that contains the rule",
"option": "namespace",
"shorthand": "",
"value_type": "string"
},
{
"description": "the routine that contains the rule",
"option": "routine",
N/A
N/A
N/A
{
"command": "ffx net filter create rule",
"options": [
{
"description": "the namespace that contains the rule",
"option": "namespace",
"shorthand": "",
"value_type": "string"
},
{
"description": "the routine that contains the rule",
"option": "routine",
N/A
N/A
N/A
{
"command": "ffx net filter create rule",
"options": [
{
"description": "the namespace that contains the rule",
"option": "namespace",
"shorthand": "",
"value_type": "string"
},
{
"description": "the routine that contains the rule",
"option": "routine",
N/A
N/A
N/A
{
"command": "ffx net filter create rule",
"options": [
{
"description": "the namespace that contains the rule",
"option": "namespace",
"shorthand": "",
"value_type": "string"
},
{
"description": "the routine that contains the rule",
"option": "routine",
N/A
N/A
N/A
{
"command": "ffx net filter create rule",
"options": [
{
"description": "the namespace that contains the rule",
"option": "namespace",
"shorthand": "",
"value_type": "string"
},
{
"description": "the routine that contains the rule",
"option": "routine",
N/A
N/A
N/A
{
"command": "ffx net filter create rule accept",
"options": [],
"short": "The `fuchsia.net.filter/Action.Accept` action."
}
N/A
N/A
N/A
{
"command": "ffx net filter create rule drop",
"options": [],
"short": "The `fuchsia.net.filter/Action.Drop` action."
}
N/A
N/A
N/A
{
"command": "ffx net filter create rule jump",
"options": [],
"short": "The `fuchsia.net.filter/Action.Jump` action."
}
N/A
N/A
N/A
{
"command": "ffx net filter create rule masquerade",
"options": [
{
"description": "the source port range used to rewrite the packet (optional)",
"option": "src-port",
"shorthand": "",
"value_type": "string"
}
],
"short": "The `fuchsia.net.filter/Action.Masquerade` action. The source port range to use to rewrite the packet is optional, but --min-src-port and --max-src-port must either both be specified, or neither."
}
N/A
N/A
N/A
{
"command": "ffx net filter create rule masquerade",
"options": [
{
"description": "the source port range used to rewrite the packet (optional)",
"option": "src-port",
"shorthand": "",
"value_type": "string"
}
],
"short": "The `fuchsia.net.filter/Action.Masquerade` action. The source port range to use to rewrite the packet is optional, but --min-src-port and --max-src-port must either both be specified, or neither."
}
N/A
N/A
N/A
{
"command": "ffx net filter create rule redirect",
"options": [
{
"description": "the destination port range used to rewrite the packet (optional)",
"option": "dst-port",
"shorthand": "",
"value_type": "string"
}
],
"short": "The `fuchsia.net.filter/Action.Redirect` action. The destination port range to which to redirect the packet is optional, but --min-dst-port and --max-dst-port must either both be specified, or neither."
}
N/A
N/A
N/A
{
"command": "ffx net filter create rule redirect",
"options": [
{
"description": "the destination port range used to rewrite the packet (optional)",
"option": "dst-port",
"shorthand": "",
"value_type": "string"
}
],
"short": "The `fuchsia.net.filter/Action.Redirect` action. The destination port range to which to redirect the packet is optional, but --min-dst-port and --max-dst-port must either both be specified, or neither."
}
N/A
N/A
N/A
{
"command": "ffx net filter create rule return",
"options": [],
"short": "The `fuchsia.net.filter/Action.Return` action."
}
N/A
N/A
N/A
{
"command": "ffx net filter create rule tproxy",
"options": [
{
"description": "the bound address of the local socket to redirect the packet to (optional)",
"option": "addr",
"shorthand": "",
"value_type": "string"
},
{
"description": "the bound port of the local socket to redirect the packet to (optional, must be nonzero)",
"option": "port",
N/A
N/A
N/A
{
"command": "ffx net filter create rule tproxy",
"options": [
{
"description": "the bound address of the local socket to redirect the packet to (optional)",
"option": "addr",
"shorthand": "",
"value_type": "string"
},
{
"description": "the bound port of the local socket to redirect the packet to (optional, must be nonzero)",
"option": "port",
N/A
N/A
N/A
{
"command": "ffx net filter create rule tproxy",
"options": [
{
"description": "the bound address of the local socket to redirect the packet to (optional)",
"option": "addr",
"shorthand": "",
"value_type": "string"
},
{
"description": "the bound port of the local socket to redirect the packet to (optional, must be nonzero)",
"option": "port",
N/A
N/A
N/A
{
"command": "ffx net filter list",
"options": [],
"short": "A command to list filtering configuration."
}
N/A
N/A
N/A
{
"command": "ffx net filter remove",
"options": [
{
"description": "the name of the controller that owns the resource",
"option": "controller",
"shorthand": "",
"value_type": "string"
},
{
"description": "whether the resource removal should be idempotent, i.e. succeed even if the resource does not exist",
"option": "idempotent",
N/A
N/A
N/A
{
"command": "ffx net filter remove",
"options": [
{
"description": "the name of the controller that owns the resource",
"option": "controller",
"shorthand": "",
"value_type": "string"
},
{
"description": "whether the resource removal should be idempotent, i.e. succeed even if the resource does not exist",
"option": "idempotent",
N/A
N/A
N/A
{
"command": "ffx net filter remove",
"options": [
{
"description": "the name of the controller that owns the resource",
"option": "controller",
"shorthand": "",
"value_type": "string"
},
{
"description": "whether the resource removal should be idempotent, i.e. succeed even if the resource does not exist",
"option": "idempotent",
N/A
N/A
N/A
{
"command": "ffx net filter remove namespace",
"options": [
{
"description": "the name of the namespace",
"option": "name",
"shorthand": "",
"value_type": "string"
}
],
"short": "A command to identify a filtering namespace"
}
N/A
N/A
N/A
{
"command": "ffx net filter remove namespace",
"options": [
{
"description": "the name of the namespace",
"option": "name",
"shorthand": "",
"value_type": "string"
}
],
"short": "A command to identify a filtering namespace"
}
N/A
N/A
N/A
{
"command": "ffx net filter remove routine",
"options": [
{
"description": "the namespace that contains the routine",
"option": "namespace",
"shorthand": "",
"value_type": "string"
},
{
"description": "the name of the routine",
"option": "name",
N/A
N/A
N/A
{
"command": "ffx net filter remove routine",
"options": [
{
"description": "the namespace that contains the routine",
"option": "namespace",
"shorthand": "",
"value_type": "string"
},
{
"description": "the name of the routine",
"option": "name",
N/A
N/A
N/A
{
"command": "ffx net filter remove routine",
"options": [
{
"description": "the namespace that contains the routine",
"option": "namespace",
"shorthand": "",
"value_type": "string"
},
{
"description": "the name of the routine",
"option": "name",
N/A
N/A
N/A
{
"command": "ffx net filter remove rule",
"options": [
{
"description": "the namespace that contains the rule",
"option": "namespace",
"shorthand": "",
"value_type": "string"
},
{
"description": "the routine that contains the rule",
"option": "routine",
N/A
N/A
N/A
{
"command": "ffx net filter remove rule",
"options": [
{
"description": "the namespace that contains the rule",
"option": "namespace",
"shorthand": "",
"value_type": "string"
},
{
"description": "the routine that contains the rule",
"option": "routine",
N/A
N/A
N/A
{
"command": "ffx net filter remove rule",
"options": [
{
"description": "the namespace that contains the rule",
"option": "namespace",
"shorthand": "",
"value_type": "string"
},
{
"description": "the routine that contains the rule",
"option": "routine",
N/A
N/A
N/A
{
"command": "ffx net filter remove rule",
"options": [
{
"description": "the namespace that contains the rule",
"option": "namespace",
"shorthand": "",
"value_type": "string"
},
{
"description": "the routine that contains the rule",
"option": "routine",
N/A
N/A
N/A
{
"command": "ffx net filter-deprecated",
"options": [],
"short": "commands for configuring packet filtering with the deprecated API"
}
N/A
N/A
N/A
{
"command": "ffx net filter-deprecated get-nat-rules",
"options": [],
"short": "gets nat rules"
}
N/A
N/A
N/A
{
"command": "ffx net filter-deprecated get-rdr-rules",
"options": [],
"short": "gets rdr rules"
}
N/A
N/A
N/A
{
"command": "ffx net filter-deprecated get-rules",
"options": [],
"short": "gets filter rules"
}
N/A
N/A
N/A
{
"command": "ffx net filter-deprecated set-nat-rules",
"options": [],
"short": "sets nat rules (see the netfilter::parser library for the NAT rules format)"
}
N/A
N/A
N/A
{
"command": "ffx net filter-deprecated set-rdr-rules",
"options": [],
"short": "sets rdr rules (see the netfilter::parser library for the RDR rules format)"
}
N/A
N/A
N/A
{
"command": "ffx net filter-deprecated set-rules",
"options": [],
"short": "sets filter rules (see the netfilter::parser library for the rules format)"
}
N/A
N/A
N/A
{
"command": "ffx net if",
"options": [],
"short": "commands for network interfaces"
}
N/A
N/A
N/A
{
"command": "ffx net if add",
"options": [],
"short": "add interfaces"
}
N/A
N/A
N/A
{
"command": "ffx net if add blackhole",
"options": [],
"short": "add a blackhole interface"
}
N/A
N/A
N/A
{
"command": "ffx net if addr",
"options": [],
"short": "commands for updating network interface addresses"
}
N/A
N/A
N/A
{
"command": "ffx net if addr add",
"options": [
{
"description": "skip adding a local subnet route for this interface and address",
"option": "no-subnet-route",
"shorthand": "",
"value_type": "bool"
}
],
"short": "adds an address to the network interface"
}
N/A
N/A
N/A
{
"command": "ffx net if addr add",
"options": [
{
"description": "skip adding a local subnet route for this interface and address",
"option": "no-subnet-route",
"shorthand": "",
"value_type": "bool"
}
],
"short": "adds an address to the network interface"
}
N/A
N/A
N/A
{
"command": "ffx net if addr del",
"options": [],
"short": "deletes an address from the network interface"
}
N/A
N/A
N/A
{
"command": "ffx net if addr wait",
"options": [
{
"description": "wait for an IPv6 address",
"option": "ipv6",
"shorthand": "",
"value_type": "bool"
}
],
"short": "waits for an address to be assigned on the network interface. by default waits for any address; if --ipv6 is specified, waits for an IPv6 address."
}
N/A
N/A
N/A
{
"command": "ffx net if addr wait",
"options": [
{
"description": "wait for an IPv6 address",
"option": "ipv6",
"shorthand": "",
"value_type": "bool"
}
],
"short": "waits for an address to be assigned on the network interface. by default waits for any address; if --ipv6 is specified, waits for an IPv6 address."
}
N/A
N/A
N/A
{
"command": "ffx net if bridge",
"options": [],
"short": "creates a bridge between network interfaces"
}
N/A
N/A
N/A
{
"command": "ffx net if config",
"options": [],
"short": "get or set interface configuration"
}
N/A
N/A
N/A
{
"command": "ffx net if config get",
"options": [],
"short": "get interface configuration"
}
N/A
N/A
N/A
{
"command": "ffx net if config set",
"options": [],
"short": "set interface configuration\n\nConfiguration parameters and the values to be set to should be passed\nin pairs. The names of the configuration parameters are taken from\nthe structure of fuchsia.net.interfaces.admin/Configuration.\n\nThe list of supported parameters are:\n ipv6.ndp.slaac.temporary_address_enabled\n bool\n Whether temporary addresses should be generated."
}
N/A
N/A
N/A
{
"command": "ffx net if disable",
"options": [],
"short": "disables a network interface"
}
N/A
N/A
N/A
{
"command": "ffx net if enable",
"options": [],
"short": "enables a network interface"
}
N/A
N/A
N/A
{
"command": "ffx net if get",
"options": [],
"short": "queries a network interface"
}
N/A
N/A
N/A
{
"command": "ffx net if igmp",
"options": [],
"short": "get or set IGMP configuration"
}
N/A
N/A
N/A
{
"command": "ffx net if igmp get",
"options": [],
"short": "get IGMP configuration for an interface"
}
N/A
N/A
N/A
{
"command": "ffx net if igmp set",
"options": [
{
"description": "the version of IGMP to perform.",
"option": "version",
"shorthand": "",
"value_type": "string"
}
],
"short": "set IGMP configuration for an interface"
}
N/A
N/A
N/A
{
"command": "ffx net if igmp set",
"options": [
{
"description": "the version of IGMP to perform.",
"option": "version",
"shorthand": "",
"value_type": "string"
}
],
"short": "set IGMP configuration for an interface"
}
N/A
N/A
N/A
{
"command": "ffx net if ip-forward",
"options": [],
"short": "get or set IP forwarding for an interface"
}
N/A
N/A
N/A
{
"command": "ffx net if ip-forward get",
"options": [],
"short": "get IP forwarding for an interface"
}
N/A
N/A
N/A
{
"command": "ffx net if ip-forward set",
"options": [],
"short": "set IP forwarding for an interface"
}
N/A
N/A
N/A
{
"command": "ffx net if list",
"options": [],
"short": "lists network interfaces (supports ffx machine output)"
}
N/A
N/A
N/A
{
"command": "ffx net if mld",
"options": [],
"short": "get or set MLD configuration"
}
N/A
N/A
N/A
{
"command": "ffx net if mld get",
"options": [],
"short": "get MLD configuration for an interface"
}
N/A
N/A
N/A
{
"command": "ffx net if mld set",
"options": [
{
"description": "the version of MLD to perform.",
"option": "version",
"shorthand": "",
"value_type": "string"
}
],
"short": "set MLD configuration for an interface"
}
N/A
N/A
N/A
{
"command": "ffx net if mld set",
"options": [
{
"description": "the version of MLD to perform.",
"option": "version",
"shorthand": "",
"value_type": "string"
}
],
"short": "set MLD configuration for an interface"
}
N/A
N/A
N/A
{
"command": "ffx net if remove",
"options": [],
"short": "remove interfaces"
}
N/A
N/A
N/A
{
"command": "ffx net log",
"options": [],
"short": "commands for logging"
}
N/A
N/A
N/A
{
"command": "ffx net log set-packets",
"options": [],
"short": "log packets to stdout"
}
N/A
N/A
N/A
{
"command": "ffx net migration",
"options": [],
"short": "controls netstack selection for migration from netstack2 to netstack3"
}
N/A
N/A
N/A
{
"command": "ffx net migration clear",
"options": [],
"short": "clears netstack version for migration configuration."
}
N/A
N/A
N/A
{
"command": "ffx net migration get",
"options": [],
"short": "prints the currently configured netstack version for migration."
}
N/A
N/A
N/A
{
"command": "ffx net migration set",
"options": [],
"short": "sets the netstack version at next boot to |ns2| or |ns3|."
}
N/A
N/A
N/A
{
"command": "ffx net neigh",
"options": [],
"short": "commands for neighbor tables"
}
N/A
N/A
N/A
{
"command": "ffx net neigh add",
"options": [],
"short": "adds an entry to the neighbor table"
}
N/A
N/A
N/A
{
"command": "ffx net neigh clear",
"options": [],
"short": "removes all entries associated with a network interface from the neighbor table"
}
N/A
N/A
N/A
{
"command": "ffx net neigh config",
"options": [],
"short": "commands for the Neighbor Unreachability Detection configuration"
}
N/A
N/A
N/A
{
"command": "ffx net neigh config get",
"options": [],
"short": "returns the current NUD configuration options for the provided interface"
}
N/A
N/A
N/A
{
"command": "ffx net neigh config update",
"options": [
{
"description": "a base duration, in nanoseconds, for computing the random reachable time",
"option": "base-reachable-time",
"shorthand": "",
"value_type": "string"
}
],
"short": "updates the current NUD configuration options for the provided interface"
}
N/A
N/A
N/A
{
"command": "ffx net neigh config update",
"options": [
{
"description": "a base duration, in nanoseconds, for computing the random reachable time",
"option": "base-reachable-time",
"shorthand": "",
"value_type": "string"
}
],
"short": "updates the current NUD configuration options for the provided interface"
}
N/A
N/A
N/A
{
"command": "ffx net neigh del",
"options": [],
"short": "removes an entry from the neighbor table"
}
N/A
N/A
N/A
{
"command": "ffx net neigh list",
"options": [],
"short": "lists neighbor table entries (supports ffx machine output)"
}
N/A
N/A
N/A
{
"command": "ffx net neigh watch",
"options": [],
"short": "watches neighbor table entries for state changes (supports ffx machine output)"
}
N/A
N/A
N/A
{
"command": "ffx net route",
"options": [],
"short": "commands for routing tables"
}
N/A
N/A
N/A
{
"command": "ffx net route add",
"options": [
{
"description": "the network id of the destination network",
"option": "destination",
"shorthand": "",
"value_type": "string"
},
{
"description": "the netmask or prefix length corresponding to destination",
"option": "netmask",
N/A
N/A
N/A
{
"command": "ffx net route add",
"options": [
{
"description": "the network id of the destination network",
"option": "destination",
"shorthand": "",
"value_type": "string"
},
{
"description": "the netmask or prefix length corresponding to destination",
"option": "netmask",
N/A
N/A
N/A
{
"command": "ffx net route add",
"options": [
{
"description": "the network id of the destination network",
"option": "destination",
"shorthand": "",
"value_type": "string"
},
{
"description": "the netmask or prefix length corresponding to destination",
"option": "netmask",
N/A
N/A
N/A
{
"command": "ffx net route add",
"options": [
{
"description": "the network id of the destination network",
"option": "destination",
"shorthand": "",
"value_type": "string"
},
{
"description": "the netmask or prefix length corresponding to destination",
"option": "netmask",
N/A
N/A
N/A
{
"command": "ffx net route add",
"options": [
{
"description": "the network id of the destination network",
"option": "destination",
"shorthand": "",
"value_type": "string"
},
{
"description": "the netmask or prefix length corresponding to destination",
"option": "netmask",
N/A
N/A
N/A
{
"command": "ffx net route add",
"options": [
{
"description": "the network id of the destination network",
"option": "destination",
"shorthand": "",
"value_type": "string"
},
{
"description": "the netmask or prefix length corresponding to destination",
"option": "netmask",
N/A
N/A
N/A
{
"command": "ffx net route del",
"options": [
{
"description": "the network id of the destination network",
"option": "destination",
"shorthand": "",
"value_type": "string"
},
{
"description": "the netmask or prefix length corresponding to destination",
"option": "netmask",
N/A
N/A
N/A
{
"command": "ffx net route del",
"options": [
{
"description": "the network id of the destination network",
"option": "destination",
"shorthand": "",
"value_type": "string"
},
{
"description": "the netmask or prefix length corresponding to destination",
"option": "netmask",
N/A
N/A
N/A
{
"command": "ffx net route del",
"options": [
{
"description": "the network id of the destination network",
"option": "destination",
"shorthand": "",
"value_type": "string"
},
{
"description": "the netmask or prefix length corresponding to destination",
"option": "netmask",
N/A
N/A
N/A
{
"command": "ffx net route del",
"options": [
{
"description": "the network id of the destination network",
"option": "destination",
"shorthand": "",
"value_type": "string"
},
{
"description": "the netmask or prefix length corresponding to destination",
"option": "netmask",
N/A
N/A
N/A
{
"command": "ffx net route del",
"options": [
{
"description": "the network id of the destination network",
"option": "destination",
"shorthand": "",
"value_type": "string"
},
{
"description": "the netmask or prefix length corresponding to destination",
"option": "netmask",
N/A
N/A
N/A
{
"command": "ffx net route del",
"options": [
{
"description": "the network id of the destination network",
"option": "destination",
"shorthand": "",
"value_type": "string"
},
{
"description": "the netmask or prefix length corresponding to destination",
"option": "netmask",
N/A
N/A
N/A
{
"command": "ffx net route list",
"options": [],
"short": "lists routes (supports ffx machine output)"
}
N/A
N/A
N/A
{
"command": "ffx net rule",
"options": [],
"short": "commands for policy-based-routing rules"
}
N/A
N/A
N/A
{
"command": "ffx net rule list",
"options": [],
"short": "lists rules (supports ffx machine output)"
}
N/A
N/A
N/A
{
"command": "ffx package",
"options": [],
"short": "Create and publish Fuchsia packages"
}
#[test]
fn default_creep() {
let budgets: BudgetConfig = serde_json::from_value(json!({
"package_set_budgets":[
{
"name": "budget_name",
"budget_bytes": 10,
"packages": [],
},
]}))
.unwrap();
assert_eq!(budgets.package_set_budgets.len(), 1);
let package_set_budget = &budgets.package_set_budgets[0];
assert_eq!(package_set_budget.creep_budget_bytes, 0);
}
#[test]
fn fails_because_of_missing_blobs_file() {
let test_fs = TestFs::new();
test_fs.write("size_budgets.json", json!({}));
let err = verify_budgets_with_tools(
PackageSizeCheckArgs {
blobfs_layout: BlobfsLayout::Compact,
budgets: test_fs.path("size_budgets.json"),
blob_sizes: [test_fs.path("blobs.json")].to_vec(),
gerrit_output: None,
verbose: false,
verbose_json_output: None,
},
Box::new(FakeToolProvider::default()),
);
assert_failed(err, "Packages budget is empty");
}
#[test]
fn fails_because_of_missing_budget_file() {
let test_fs = TestFs::new();
test_fs.write("blobs.json", json!([]));
let err = verify_budgets_with_tools(
PackageSizeCheckArgs {
blobfs_layout: BlobfsLayout::Compact,
budgets: test_fs.path("size_budgets.json"),
blob_sizes: [test_fs.path("blobs.json")].to_vec(),
gerrit_output: None,
verbose: false,
verbose_json_output: None,
},
Box::new(FakeToolProvider::default()),
);
assert_eq!(err.exit_code(), 1);
assert_failed(err, "Unable to open file:");
}
N/A
N/A
{
"command": "ffx package archive",
"options": [],
"short": "Archive Fuchsia packages"
}
#[test]
fn read_file_entries_handles_duplicate_content_blobs() {
let mut mockreader = MockFarListReader::new();
mockreader.expect_list_contents().returning(|| {
Ok(vec![ArchiveEntry { name: BLOB1.into(), path: BLOB1.into(), length: Some(1) }])
});
mockreader.expect_list_meta_contents().returning(|| {
Ok((
vec![],
MetaContents::from([
("first-copy", BLOB1.parse().unwrap()),
("second-copy", BLOB1.parse().unwrap()),
]),
))
});
let mut entries = read_file_entries(&mut mockreader).unwrap();
entries.sort_unstable();
// Both package entries that are backed by BLOB1 will be present and have the correct size.
assert_eq!(
entries,
vec![
ArchiveEntry { name: "first-copy".into(), path: BLOB1.into(), length: Some(1) },
ArchiveEntry { name: "second-copy".into(), path: BLOB1.into(), length: Some(1) }
]
);
}
#[test]
fn read_file_entries_missing_content_blob() {
let mut mockreader = MockFarListReader::new();
mockreader.expect_list_contents().returning(|| Ok(vec![]));
mockreader.expect_list_meta_contents().returning(|| {
Ok((vec![], MetaContents::from([("missing-blob", BLOB1.parse().unwrap())])))
});
let entries = read_file_entries(&mut mockreader).unwrap();
assert_eq!(
entries,
vec![ArchiveEntry { name: "missing-blob".into(), path: BLOB1.into(), length: None },]
);
}
N/A
N/A
{
"command": "ffx package archive add",
"options": [
{
"description": "package archive",
"option": "archive",
"shorthand": "a",
"value_type": "string"
},
{
"description": "file to add to the package archive",
"option": "file-to-add",
N/A
N/A
N/A
{
"command": "ffx package archive add",
"options": [
{
"description": "package archive",
"option": "archive",
"shorthand": "a",
"value_type": "string"
},
{
"description": "file to add to the package archive",
"option": "file-to-add",
N/A
N/A
N/A
{
"command": "ffx package archive add",
"options": [
{
"description": "package archive",
"option": "archive",
"shorthand": "a",
"value_type": "string"
},
{
"description": "file to add to the package archive",
"option": "file-to-add",
N/A
N/A
N/A
{
"command": "ffx package archive add",
"options": [
{
"description": "package archive",
"option": "archive",
"shorthand": "a",
"value_type": "string"
},
{
"description": "file to add to the package archive",
"option": "file-to-add",
N/A
N/A
N/A
{
"command": "ffx package archive add",
"options": [
{
"description": "package archive",
"option": "archive",
"shorthand": "a",
"value_type": "string"
},
{
"description": "file to add to the package archive",
"option": "file-to-add",
N/A
N/A
N/A
{
"command": "ffx package archive add",
"options": [
{
"description": "package archive",
"option": "archive",
"shorthand": "a",
"value_type": "string"
},
{
"description": "file to add to the package archive",
"option": "file-to-add",
N/A
N/A
N/A
{
"command": "ffx package archive cat",
"options": [],
"short": "write the contents of <far_path> inside the Fuchsia package archive file to stdout"
}
#[test]
fn test_cat_filename() -> Result<()> {
let cmd = CatCommand {
archive: PathBuf::from("some.far"),
far_path: PathBuf::from(LIB_RUN_SO_PATH),
};
let mut output: Vec<u8> = vec![];
let expected = test_contents(LIB_RUN_SO_BLOB);
cat_implementation(cmd, &mut output, &mut create_mockreader())?;
assert_eq!(expected, output);
Ok(())
}
N/A
N/A
{
"command": "ffx package archive create",
"options": [
{
"description": "output package archive",
"option": "out",
"shorthand": "o",
"value_type": "string"
},
{
"description": "root directory for paths in package_manifest.json",
"option": "root-dir",
N/A
N/A
N/A
{
"command": "ffx package archive create",
"options": [
{
"description": "output package archive",
"option": "out",
"shorthand": "o",
"value_type": "string"
},
{
"description": "root directory for paths in package_manifest.json",
"option": "root-dir",
N/A
N/A
N/A
{
"command": "ffx package archive create",
"options": [
{
"description": "output package archive",
"option": "out",
"shorthand": "o",
"value_type": "string"
},
{
"description": "root directory for paths in package_manifest.json",
"option": "root-dir",
N/A
N/A
N/A
{
"command": "ffx package archive create",
"options": [
{
"description": "output package archive",
"option": "out",
"shorthand": "o",
"value_type": "string"
},
{
"description": "root directory for paths in package_manifest.json",
"option": "root-dir",
N/A
N/A
N/A
{
"command": "ffx package archive edit",
"options": [
{
"description": "package archive",
"option": "archive",
"shorthand": "a",
"value_type": "string"
},
{
"description": "if specified, change the name of the package (i.e., what appears in meta/package) to <package_name>.",
"option": "package-name",
N/A
N/A
N/A
{
"command": "ffx package archive edit",
"options": [
{
"description": "package archive",
"option": "archive",
"shorthand": "a",
"value_type": "string"
},
{
"description": "if specified, change the name of the package (i.e., what appears in meta/package) to <package_name>.",
"option": "package-name",
N/A
N/A
N/A
{
"command": "ffx package archive edit",
"options": [
{
"description": "package archive",
"option": "archive",
"shorthand": "a",
"value_type": "string"
},
{
"description": "if specified, change the name of the package (i.e., what appears in meta/package) to <package_name>.",
"option": "package-name",
N/A
N/A
N/A
{
"command": "ffx package archive edit",
"options": [
{
"description": "package archive",
"option": "archive",
"shorthand": "a",
"value_type": "string"
},
{
"description": "if specified, change the name of the package (i.e., what appears in meta/package) to <package_name>.",
"option": "package-name",
N/A
N/A
N/A
{
"command": "ffx package archive edit",
"options": [
{
"description": "package archive",
"option": "archive",
"shorthand": "a",
"value_type": "string"
},
{
"description": "if specified, change the name of the package (i.e., what appears in meta/package) to <package_name>.",
"option": "package-name",
N/A
N/A
N/A
{
"command": "ffx package archive extract",
"options": [
{
"description": "output directory for writing the extracted files. Defaults to the current directory.",
"option": "out",
"shorthand": "o",
"value_type": "string"
},
{
"description": "repository of the package",
"option": "repository",
N/A
N/A
N/A
{
"command": "ffx package archive extract",
"options": [
{
"description": "output directory for writing the extracted files. Defaults to the current directory.",
"option": "out",
"shorthand": "o",
"value_type": "string"
},
{
"description": "repository of the package",
"option": "repository",
N/A
N/A
N/A
{
"command": "ffx package archive extract",
"options": [
{
"description": "output directory for writing the extracted files. Defaults to the current directory.",
"option": "out",
"shorthand": "o",
"value_type": "string"
},
{
"description": "repository of the package",
"option": "repository",
N/A
N/A
N/A
{
"command": "ffx package archive extract",
"options": [
{
"description": "output directory for writing the extracted files. Defaults to the current directory.",
"option": "out",
"shorthand": "o",
"value_type": "string"
},
{
"description": "repository of the package",
"option": "repository",
N/A
N/A
N/A
{
"command": "ffx package archive extract",
"options": [
{
"description": "output directory for writing the extracted files. Defaults to the current directory.",
"option": "out",
"shorthand": "o",
"value_type": "string"
},
{
"description": "repository of the package",
"option": "repository",
N/A
N/A
N/A
{
"command": "ffx package archive list",
"options": [
{
"description": "show long information for each entry",
"option": "long-format",
"shorthand": "l",
"value_type": "bool"
}
],
"short": "List the contents of Fuchia package archive file"
}
#[test]
fn test_list_empty() -> Result<()> {
let mut mockreader = MockFarListReader::new();
mockreader.expect_list_contents().returning(|| Ok(vec![]));
mockreader.expect_list_meta_contents().returning(|| Ok((vec![], MetaContents::new())));
let cmd = ListCommand { archive: PathBuf::from("some_empty.far"), long_format: false };
let buffers = TestBuffers::default();
let mut writer = <ArchiveListTool as FfxMain>::Writer::new_test(None, &buffers);
list_implementation(cmd, &mut writer, &mut mockreader)?;
assert_eq!(buffers.into_stdout_str(), "\n".to_string());
Ok(())
}
#[test]
/// Tests reading the "meta.far" directly vs. when part of a
/// larger archive.
fn test_list_with_no_meta() -> Result<()> {
let mut mockreader = MockFarListReader::new();
mockreader.expect_list_contents().returning(|| {
Ok(vec![
ArchiveEntry {
name: "meta/the_component.cm".to_string(),
path: "meta/the_component.cm".to_string(),
length: Some(100),
},
ArchiveEntry {
name: "meta/package".to_string(),
path: "meta/package".to_string(),
length: Some(25),
},
ArchiveEntry {
name: "meta/contents".to_string(),
path: "meta/contents".to_string(),
length: Some(55),
},
])
});
mockreader.expect_list_meta_contents().returning(|| Ok((vec![], MetaContents::new())));
let cmd = ListCommand { archive: PathBuf::from("just_meta.far"), long_format: false };
let buffers = TestBuffers::default();
#[test]
fn test_list_with_meta() -> Result<()> {
let cmd = ListCommand { archive: PathBuf::from("just_meta.far"), long_format: false };
let buffers = TestBuffers::default();
let mut writer = <ArchiveListTool as FfxMain>::Writer::new_test(None, &buffers);
list_implementation(cmd, &mut writer, &mut create_mockreader())?;
let expected = r#"
data/missing_blob
data/some_file
lib/run.so
meta.far
meta/contents
meta/package
meta/the_component.cm
run_me
"#[1..]
.to_string();
assert_eq!(buffers.into_stdout_str(), expected);
Ok(())
}
N/A
N/A
{
"command": "ffx package archive list",
"options": [
{
"description": "show long information for each entry",
"option": "long-format",
"shorthand": "l",
"value_type": "bool"
}
],
"short": "List the contents of Fuchia package archive file"
}
N/A
N/A
N/A
{
"command": "ffx package archive remove",
"options": [
{
"description": "package archive",
"option": "archive",
"shorthand": "a",
"value_type": "string"
},
{
"description": "file to add to the package archive",
"option": "file-to-remove",
N/A
N/A
N/A
{
"command": "ffx package archive remove",
"options": [
{
"description": "package archive",
"option": "archive",
"shorthand": "a",
"value_type": "string"
},
{
"description": "file to add to the package archive",
"option": "file-to-remove",
N/A
N/A
N/A
{
"command": "ffx package archive remove",
"options": [
{
"description": "package archive",
"option": "archive",
"shorthand": "a",
"value_type": "string"
},
{
"description": "file to add to the package archive",
"option": "file-to-remove",
N/A
N/A
N/A
{
"command": "ffx package archive remove",
"options": [
{
"description": "package archive",
"option": "archive",
"shorthand": "a",
"value_type": "string"
},
{
"description": "file to add to the package archive",
"option": "file-to-remove",
N/A
N/A
N/A
{
"command": "ffx package blob",
"options": [],
"short": "Work with Fuchsia blob files."
}
N/A
N/A
N/A
{
"command": "ffx package blob compress",
"options": [
{
"description": "delivery blob type",
"option": "type",
"shorthand": "t",
"value_type": "string"
},
{
"description": "output compressed blobs into this directory",
"option": "output",
#[fuchsia::test]
async fn compress_single_blob() {
let test_data = [("first_file", &"0123456789".repeat(1024))];
let dir = create_test_files(&test_data);
let dir_path = Utf8PathBuf::from_path_buf(dir.path().to_owned()).unwrap();
let paths = test_data.iter().map(|(name, _)| dir_path.join(name)).collect();
let cmd = CompressCommand {
paths,
output: dir_path.join("compressed"),
hash_as_name: false,
delivery_type: Type1,
};
let buffers = ffx_writer::TestBuffers::default();
let writer = <CompressTool as FfxMain>::Writer::new_test(None, &buffers);
CompressTool { cmd }.main(writer).await.expect("success");
let (out, err) = &buffers.into_strings();
let expected_output = format!("{0}/first_file => {0}/compressed\n", dir_path);
assert_eq!(out, &expected_output);
assert_eq!(err, "");
let expected_bytes = delivery_blob::generate(Type1, test_data[0].1.as_ref());
assert_eq!(std::fs::read(&dir_path.join("compressed")).unwrap(), expected_bytes);
}
#[fuchsia::test]
async fn compress_multiple_blobs() {
let test_data = [
("first_file", ""),
("second_file", "Hello world!"),
("third_file", &"0123456789".repeat(1024)),
];
let dir = create_test_files(&test_data);
let dir_path = Utf8PathBuf::from_path_buf(dir.path().to_owned()).unwrap();
let paths = test_data.iter().map(|(name, _)| dir_path.join(name)).collect();
let out_dir = dir_path.join("compressed");
std::fs::create_dir(&out_dir).unwrap();
let cmd = CompressCommand {
paths,
output: out_dir.clone(),
hash_as_name: false,
delivery_type: Type1,
};
let buffers = ffx_writer::TestBuffers::default();
let writer = <CompressTool as FfxMain>::Writer::new_test(None, &buffers);
CompressTool { cmd }.main(writer).await.expect("success");
let (out, err) = &buffers.into_strings();
let expected_output = format!(
"\
{0}/first_file => {0}/compressed/first_file
#[fuchsia::test]
async fn compress_multiple_blobs_hash_as_name() {
let test_data = [
("first_file", ""),
("second_file", "Hello world!"),
("third_file", &"0123456789".repeat(1024)),
];
let dir = create_test_files(&test_data);
let dir_path = Utf8PathBuf::from_path_buf(dir.path().to_owned()).unwrap();
let paths = test_data.iter().map(|(name, _)| dir_path.join(name)).collect();
let out_dir = dir_path.join("compressed");
std::fs::create_dir(&out_dir).unwrap();
let cmd = CompressCommand {
paths,
output: out_dir.clone(),
hash_as_name: true,
delivery_type: Type1,
};
let buffers = ffx_writer::TestBuffers::default();
let writer = <CompressTool as FfxMain>::Writer::new_test(None, &buffers);
CompressTool { cmd }.main(writer).await.expect("success");
let (out, err) = &buffers.into_strings();
let expected_output = format!(
"\
{0}/first_file => {0}/compressed/15ec7bf0b50732b49f8228e07d24365338f9e3ab994b00af08e5a3bffe55fd8b
N/A
N/A
{
"command": "ffx package blob compress",
"options": [
{
"description": "delivery blob type",
"option": "type",
"shorthand": "t",
"value_type": "string"
},
{
"description": "output compressed blobs into this directory",
"option": "output",
N/A
N/A
N/A
{
"command": "ffx package blob compress",
"options": [
{
"description": "delivery blob type",
"option": "type",
"shorthand": "t",
"value_type": "string"
},
{
"description": "output compressed blobs into this directory",
"option": "output",
N/A
N/A
N/A
{
"command": "ffx package blob compress",
"options": [
{
"description": "delivery blob type",
"option": "type",
"shorthand": "t",
"value_type": "string"
},
{
"description": "output compressed blobs into this directory",
"option": "output",
N/A
N/A
N/A
{
"command": "ffx package blob decompress",
"options": [
{
"description": "output decompressed blobs into this directory",
"option": "output",
"shorthand": "o",
"value_type": "string"
}
],
"short": "Decompress one or more blobs"
}
#[fuchsia::test]
async fn decompress_single_blob() {
let test_data = [("first_file", &"0123456789".repeat(1024))];
let dir = create_test_files(&test_data);
let dir_path = Utf8PathBuf::from_path_buf(dir.path().to_owned()).unwrap();
let paths = test_data.iter().map(|(name, _)| dir_path.join(name)).collect();
let cmd = DecompressCommand { paths, output: dir_path.join("decompressed") };
let buffers = ffx_writer::TestBuffers::default();
let writer = <DecompressTool as FfxMain>::Writer::new_test(None, &buffers);
DecompressTool { cmd }.main(writer).await.expect("success");
let (out, err) = &buffers.into_strings();
let expected_output = format!("{0}/first_file => {0}/decompressed\n", dir_path);
assert_eq!(out, &expected_output);
assert_eq!(err, "");
assert_eq!(
std::fs::read(&dir_path.join("decompressed")).unwrap(),
test_data[0].1.as_bytes()
);
}
#[fuchsia::test]
async fn decompress_multiple_blobs() {
let test_data = [
("first_file", ""),
("second_file", "Hello world!"),
("third_file", &"0123456789".repeat(1024)),
];
let dir = create_test_files(&test_data);
let dir_path = Utf8PathBuf::from_path_buf(dir.path().to_owned()).unwrap();
let paths = test_data.iter().map(|(name, _)| dir_path.join(name)).collect();
let out_dir = dir_path.join("decompressed");
std::fs::create_dir(&out_dir).unwrap();
let cmd = DecompressCommand { paths, output: out_dir.clone() };
let buffers = ffx_writer::TestBuffers::default();
let writer = <DecompressTool as FfxMain>::Writer::new_test(None, &buffers);
DecompressTool { cmd }.main(writer).await.expect("success");
let (out, err) = &buffers.into_strings();
let expected_output = format!(
"\
{0}/first_file => {0}/decompressed/first_file
{0}/second_file => {0}/decompressed/second_file
{0}/third_file => {0}/decompressed/third_file
",
dir_path,
);
#[fuchsia::test]
async fn decompress_multiple_blobs_machine_mode() {
let test_data = [
("first_file", ""),
("second_file", "Hello world!"),
("third_file", &"0123456789".repeat(1024)),
];
let dir = create_test_files(&test_data);
let dir_path = Utf8PathBuf::from_path_buf(dir.path().to_owned()).unwrap();
let paths = test_data.iter().map(|(name, _)| dir_path.join(name)).collect();
let out_dir = dir_path.join("decompressed");
std::fs::create_dir(&out_dir).unwrap();
let cmd = DecompressCommand { paths, output: out_dir.clone() };
let buffers = ffx_writer::TestBuffers::default();
let writer =
<DecompressTool as FfxMain>::Writer::new_test(Some(ffx_writer::Format::Json), &buffers);
DecompressTool { cmd }.main(writer).await.expect("success");
let (out, err) = &buffers.into_strings();
let expected_output = format!(
concat!(
r#"{{"ok":{{"data":["#,
r#"{{"src":"{0}/first_file","dst":"{0}/decompressed/first_file"}},"#,
r#"{{"src":"{0}/second_file","dst":"{0}/decompressed/second_file"}},"#,
r#"{{"src":"{0}/third_file","dst":"{0}/decompressed/third_file"}}"#,
r#"]}}}}"#,
N/A
N/A
{
"command": "ffx package blob decompress",
"options": [
{
"description": "output decompressed blobs into this directory",
"option": "output",
"shorthand": "o",
"value_type": "string"
}
],
"short": "Decompress one or more blobs"
}
N/A
N/A
N/A
{
"command": "ffx package blob hash",
"options": [
{
"description": "blobs are uncompressed instead of delivery blobs",
"option": "uncompressed",
"shorthand": "u",
"value_type": "bool"
}
],
"short": "Compute the merkle tree root hash of one or more delivery blobs or uncompressed blobs."
}
#[fuchsia::test]
async fn validate_output() {
let test_data = [
("first_file", ""),
("second_file", "Hello world!"),
("third_file", &"0123456789".repeat(1024)),
];
let dir = create_test_files(&test_data);
let dir_path = Utf8PathBuf::from_path_buf(dir.path().to_owned()).unwrap();
let paths = test_data.iter().map(|(name, _)| dir_path.join(name)).collect();
let cmd = HashCommand { paths, uncompressed: true };
let buffers = ffx_writer::TestBuffers::default();
let writer = <BlobHashTool as FfxMain>::Writer::new_test(None, &buffers);
BlobHashTool { cmd }.main(writer).await.expect("success");
let (out, err) = &buffers.into_strings();
let expected_output = format!(
"\
15ec7bf0b50732b49f8228e07d24365338f9e3ab994b00af08e5a3bffe55fd8b {0}/first_file
e6a73dbd2d88e51ccdaa648cbf49b3939daac8a3e370169bc85e0324a41adbc2 {0}/second_file
f5a0dff4578d0150d3dace71b08733d5cd8cbe63a322633445c9ff0d9041b9c4 {0}/third_file
",
dir_path,
);
assert_eq!(out, &expected_output);
assert_eq!(err, "");
#[fuchsia::test]
async fn validate_delivery_blob_output() {
let test_data = [
("first_file", ""),
("second_file", "Hello world!"),
("third_file", &"0123456789".repeat(1024)),
]
.map(|(name, content)| {
(
name,
delivery_blob::generate(delivery_blob::DeliveryBlobType::Type1, content.as_bytes()),
)
});
let dir = create_test_files(&test_data);
let dir_path = Utf8PathBuf::from_path_buf(dir.path().to_owned()).unwrap();
let paths = test_data.iter().map(|(name, _)| dir_path.join(name)).collect();
let cmd = HashCommand { paths, uncompressed: false };
let buffers = ffx_writer::TestBuffers::default();
let writer = <BlobHashTool as FfxMain>::Writer::new_test(None, &buffers);
BlobHashTool { cmd }.main(writer).await.expect("success");
let (out, err) = &buffers.into_strings();
let expected_output = format!(
"\
15ec7bf0b50732b49f8228e07d24365338f9e3ab994b00af08e5a3bffe55fd8b {0}/first_file
e6a73dbd2d88e51ccdaa648cbf49b3939daac8a3e370169bc85e0324a41adbc2 {0}/second_file
f5a0dff4578d0150d3dace71b08733d5cd8cbe63a322633445c9ff0d9041b9c4 {0}/third_file
#[fuchsia::test]
async fn validate_output_machine_mode() {
let test_data = [
("first_file", ""),
("second_file", "Hello world!"),
("third_file", &"0123456789".repeat(1024)),
];
let dir = create_test_files(&test_data);
let dir_path = Utf8PathBuf::from_path_buf(dir.path().to_owned()).unwrap();
let paths = test_data.iter().map(|(name, _)| dir_path.join(name)).collect();
let cmd = HashCommand { paths, uncompressed: true };
let buffers = ffx_writer::TestBuffers::default();
let writer =
<BlobHashTool as FfxMain>::Writer::new_test(Some(ffx_writer::Format::Json), &buffers);
BlobHashTool { cmd }.main(writer).await.expect("success");
let (out, err) = buffers.into_strings();
let expected_output = format!(
concat!(
r#"{{"ok":{{"data":["#,
r#"{{"path":"{0}/first_file","hash":"15ec7bf0b50732b49f8228e07d24365338f9e3ab994b00af08e5a3bffe55fd8b"}},"#,
r#"{{"path":"{0}/second_file","hash":"e6a73dbd2d88e51ccdaa648cbf49b3939daac8a3e370169bc85e0324a41adbc2"}},"#,
r#"{{"path":"{0}/third_file","hash":"f5a0dff4578d0150d3dace71b08733d5cd8cbe63a322633445c9ff0d9041b9c4"}}"#,
r#"]}}}}"#,
"\n"
),
dir_path,
);
N/A
N/A
{
"command": "ffx package blob hash",
"options": [
{
"description": "blobs are uncompressed instead of delivery blobs",
"option": "uncompressed",
"shorthand": "u",
"value_type": "bool"
}
],
"short": "Compute the merkle tree root hash of one or more delivery blobs or uncompressed blobs."
}
N/A
N/A
N/A
{
"command": "ffx package build",
"options": [
{
"description": "directory to save package artifacts",
"option": "out",
"shorthand": "o",
"value_type": "string"
},
{
"description": "package API level",
"option": "api-level",
N/A
N/A
N/A
{
"command": "ffx package build",
"options": [
{
"description": "directory to save package artifacts",
"option": "out",
"shorthand": "o",
"value_type": "string"
},
{
"description": "package API level",
"option": "api-level",
N/A
N/A
N/A
{
"command": "ffx package build",
"options": [
{
"description": "directory to save package artifacts",
"option": "out",
"shorthand": "o",
"value_type": "string"
},
{
"description": "package API level",
"option": "api-level",
N/A
N/A
N/A
{
"command": "ffx package build",
"options": [
{
"description": "directory to save package artifacts",
"option": "out",
"shorthand": "o",
"value_type": "string"
},
{
"description": "package API level",
"option": "api-level",
N/A
N/A
N/A
{
"command": "ffx package build",
"options": [
{
"description": "directory to save package artifacts",
"option": "out",
"shorthand": "o",
"value_type": "string"
},
{
"description": "package API level",
"option": "api-level",
N/A
N/A
N/A
{
"command": "ffx package build",
"options": [
{
"description": "directory to save package artifacts",
"option": "out",
"shorthand": "o",
"value_type": "string"
},
{
"description": "package API level",
"option": "api-level",
N/A
N/A
N/A
{
"command": "ffx package build",
"options": [
{
"description": "directory to save package artifacts",
"option": "out",
"shorthand": "o",
"value_type": "string"
},
{
"description": "package API level",
"option": "api-level",
N/A
N/A
N/A
{
"command": "ffx package build",
"options": [
{
"description": "directory to save package artifacts",
"option": "out",
"shorthand": "o",
"value_type": "string"
},
{
"description": "package API level",
"option": "api-level",
N/A
N/A
N/A
{
"command": "ffx package build",
"options": [
{
"description": "directory to save package artifacts",
"option": "out",
"shorthand": "o",
"value_type": "string"
},
{
"description": "package API level",
"option": "api-level",
N/A
N/A
N/A
{
"command": "ffx package far",
"options": [],
"short": "Work with Fuchsia Archive Format (FAR) files"
}
N/A
N/A
N/A
{
"command": "ffx package far cat",
"options": [],
"short": "Dump the contents of the <far_file> entry associated with <path> to stdout"
}
N/A
N/A
N/A
{
"command": "ffx package far create",
"options": [],
"short": "Create a FAR file from a directory. WARNING: this will overwrite <output_file> if it exists."
}
N/A
N/A
N/A
{
"command": "ffx package far extract",
"options": [
{
"description": "verbose output: print file names that were extracted",
"option": "verbose",
"shorthand": "v",
"value_type": "bool"
},
{
"description": "output directory (defaults to current directory, creates the directory if it doesn't exist)",
"option": "output-dir",
N/A
N/A
N/A
{
"command": "ffx package far extract",
"options": [
{
"description": "verbose output: print file names that were extracted",
"option": "verbose",
"shorthand": "v",
"value_type": "bool"
},
{
"description": "output directory (defaults to current directory, creates the directory if it doesn't exist)",
"option": "output-dir",
N/A
N/A
N/A
{
"command": "ffx package far extract",
"options": [
{
"description": "verbose output: print file names that were extracted",
"option": "verbose",
"shorthand": "v",
"value_type": "bool"
},
{
"description": "output directory (defaults to current directory, creates the directory if it doesn't exist)",
"option": "output-dir",
N/A
N/A
N/A
{
"command": "ffx package far list",
"options": [
{
"description": "show detailed information for each entry (does nothing if --machine json is specified, which shows everything)",
"option": "long-format",
"shorthand": "l",
"value_type": "bool"
}
],
"short": "List the entry paths contained in a FAR file"
}
#[fuchsia::test]
async fn normal_output() -> Result<()> {
let tmp_dir = TempDir::new().unwrap();
let far_path = create_test_far(&tmp_dir, &["foo", "bar", "baz"]).unwrap();
let cmd = ListCommand { far_file: far_path, long_format: false };
let buffers = TestBuffers::default();
let writer = <FarListTool as FfxMain>::Writer::new_test(None, &buffers);
cmd_list(cmd, writer).await?;
let (stdout, stderr) = buffers.into_strings();
let expected = r#"
bar
baz
foo
"#[1..]
.to_string();
assert_eq!(stdout, expected);
assert_eq!(stderr, "");
Ok(())
}
#[fuchsia::test]
async fn long_output() -> Result<()> {
let tmp_dir = TempDir::new().unwrap();
let far_path = create_test_far(&tmp_dir, &["alpha", "beta", "gamma"]).unwrap();
let cmd = ListCommand { far_file: far_path, long_format: true };
let buffers = TestBuffers::default();
let writer = <FarListTool as FfxMain>::Writer::new_test(None, &buffers);
cmd_list(cmd, writer).await?;
let (stdout, stderr) = buffers.into_strings();
let expected = concat!(
"PATH OFFSET LENGTH \n",
"alpha 4096 5 B \n",
"beta 8192 4 B \n",
"gamma 12288 5 B \n"
)
.to_owned();
assert_eq!(stdout, expected);
assert_eq!(stderr, "");
Ok(())
}
#[fuchsia::test]
async fn machine_output() -> Result<()> {
let tmp_dir = TempDir::new().unwrap();
let far_path = create_test_far(&tmp_dir, &["one", "two", "three"]).unwrap();
let cmd = ListCommand { far_file: far_path, long_format: false };
let buffers = TestBuffers::default();
let writer = <FarListTool as FfxMain>::Writer::new_test(Some(Format::Json), &buffers);
cmd_list(cmd, writer).await?;
let (stdout, stderr) = buffers.into_strings();
assert_eq!(
stdout,
"[{\"path\":\"one\",\"offset\":4096,\"length\":3},{\"path\":\"three\",\"offset\":8192,\"length\":5},{\"path\":\"two\",\"offset\":12288,\"length\":3}]\n"
);
assert_eq!(stderr, "");
Ok(())
}
N/A
N/A
{
"command": "ffx package far list",
"options": [
{
"description": "show detailed information for each entry (does nothing if --machine json is specified, which shows everything)",
"option": "long-format",
"shorthand": "l",
"value_type": "bool"
}
],
"short": "List the entry paths contained in a FAR file"
}
N/A
N/A
N/A
{
"command": "ffx package file-hash",
"options": [],
"short": "Compute the merkle tree root hash of one or more files."
}
#[fuchsia::test]
async fn validate_output() -> Result<()> {
let test_data = [
("first_file", ""),
("second_file", "Hello world!"),
("third_file", &"0123456789".repeat(1024)),
];
let dir = create_test_files(&test_data)?;
let paths = test_data.iter().map(|(name, _)| dir.path().join(name)).collect();
let cmd = FileHashCommand { paths };
let tool = FileHashTool { cmd };
let buffers = TestBuffers::default();
let writer = <FileHashTool as FfxMain>::Writer::new_test(None, &buffers);
tool.main(writer).await.expect("success");
let (out, err) = &buffers.into_strings();
let expected_output = format!(
"\
15ec7bf0b50732b49f8228e07d24365338f9e3ab994b00af08e5a3bffe55fd8b {0}/first_file
e6a73dbd2d88e51ccdaa648cbf49b3939daac8a3e370169bc85e0324a41adbc2 {0}/second_file
f5a0dff4578d0150d3dace71b08733d5cd8cbe63a322633445c9ff0d9041b9c4 {0}/third_file
",
dir.path().display(),
);
assert_eq!(out, &expected_output);
assert_eq!(err, "");
#[fuchsia::test]
async fn validate_output_machine_mode() -> Result<()> {
let test_data = [
("first_file", ""),
("second_file", "Hello world!"),
("third_file", &"0123456789".repeat(1024)),
];
let dir = create_test_files(&test_data)?;
let paths = test_data.iter().map(|(name, _)| dir.path().join(name)).collect();
let cmd = FileHashCommand { paths };
let tool = FileHashTool { cmd };
let buffers = TestBuffers::default();
let writer = <FileHashTool as FfxMain>::Writer::new_test(Some(Format::Json), &buffers);
tool.main(writer).await.expect("success");
let (out, err) = buffers.into_strings();
let expected_output = format!(
concat!(
r#"{{"ok":{{"data":["#,
r#"{{"path":"{0}/first_file","hash":"15ec7bf0b50732b49f8228e07d24365338f9e3ab994b00af08e5a3bffe55fd8b"}},"#,
r#"{{"path":"{0}/second_file","hash":"e6a73dbd2d88e51ccdaa648cbf49b3939daac8a3e370169bc85e0324a41adbc2"}},"#,
r#"{{"path":"{0}/third_file","hash":"f5a0dff4578d0150d3dace71b08733d5cd8cbe63a322633445c9ff0d9041b9c4"}}"#,
r#"]}}}}"#,
"\n"
),
dir.path().display(),
);
#[fuchsia::test]
async fn file_not_found() -> Result<()> {
const NAME: &str = "filename_that_does_not_exist";
let cmd = FileHashCommand { paths: vec![NAME.into()] };
let tool = FileHashTool { cmd };
let buffers = TestBuffers::default();
let writer = <FileHashTool as FfxMain>::Writer::new_test(None, &buffers);
tool.main(writer).await.expect("success");
let (out, err) = buffers.into_strings();
assert_eq!(
err,
format!("failed to open file {NAME}: No such file or directory (os error 2)\n")
);
assert_eq!(out, "");
Ok(())
}
N/A
N/A
{
"command": "ffx package ota-manifest",
"options": [],
"short": "Inspect or modify OTA Manifests"
}
N/A
N/A
N/A
{
"command": "ffx package ota-manifest show",
"options": [
{
"description": "optional public key file for verifying the manifest signature",
"option": "public-key",
"shorthand": "",
"value_type": "string"
},
{
"description": "whether to print the full list of blobs (default is false outside of machine mode)",
"option": "print-blobs",
#[fuchsia::test]
async fn test_show_json() {
use serde_json::json;
let keypair = make_keypair();
let manifest = make_ota_manifest();
let bytes = update_package::signed_manifest::generate(manifest, &keypair).unwrap();
let raw_manifest = update_package::signed_manifest::parse_raw(&bytes).unwrap();
let expected_sig = hex::encode(&raw_manifest.signatures[0]);
let mut file = NamedTempFile::new().unwrap();
file.write_all(&bytes).unwrap();
let manifest_path = camino::Utf8PathBuf::try_from(file.path().to_path_buf()).unwrap();
let cmd = ShowCommand { manifest: manifest_path, public_key: None, print_blobs: false };
let tool = ShowTool { cmd };
let buffers = TestBuffers::default();
let writer = <ShowTool as FfxMain>::Writer::new_test(Some(Format::Json), &buffers);
tool.main(writer).await.unwrap();
let (out, err) = buffers.into_strings();
assert_eq!(err, "");
let out_json: serde_json::Value = serde_json::from_str(&out).expect("valid JSON output");
let expected_json = json!({
"manifest_version": 1,
"signatures": [expected_sig],
#[fuchsia::test]
async fn test_show_table() {
let keypair = make_keypair();
let manifest = make_ota_manifest();
let bytes = update_package::signed_manifest::generate(manifest, &keypair).unwrap();
let raw_manifest = update_package::signed_manifest::parse_raw(&bytes).unwrap();
let expected_sig = hex::encode(&raw_manifest.signatures[0]);
let mut file = NamedTempFile::new().unwrap();
file.write_all(&bytes).unwrap();
let manifest_path = camino::Utf8PathBuf::try_from(file.path().to_path_buf()).unwrap();
let cmd = ShowCommand { manifest: manifest_path, public_key: None, print_blobs: true };
let tool = ShowTool { cmd };
let buffers = TestBuffers::default();
let writer = <ShowTool as FfxMain>::Writer::new_test(None, &buffers);
tool.main(writer).await.unwrap();
let (out, err) = buffers.into_strings();
assert_eq!(err, "");
let expected_table = format!(
r#"Manifest Version: 1
Signature 0: {expected_sig}
Build Info Version: 1.2.3.4
Board: test-board
Epoch: 1
N/A
N/A
{
"command": "ffx package ota-manifest show",
"options": [
{
"description": "optional public key file for verifying the manifest signature",
"option": "public-key",
"shorthand": "",
"value_type": "string"
},
{
"description": "whether to print the full list of blobs (default is false outside of machine mode)",
"option": "print-blobs",
N/A
N/A
N/A
{
"command": "ffx package ota-manifest show",
"options": [
{
"description": "optional public key file for verifying the manifest signature",
"option": "public-key",
"shorthand": "",
"value_type": "string"
},
{
"description": "whether to print the full list of blobs (default is false outside of machine mode)",
"option": "print-blobs",
N/A
N/A
N/A
{
"command": "ffx platform",
"options": [],
"short": "Manage platform build prerequisites"
}
N/A
N/A
N/A
{
"command": "ffx platform preflight",
"options": [
{
"description": "outputs json instead of human-readable text.",
"option": "json",
"shorthand": "",
"value_type": "bool"
}
],
"short": "Evaluate suitability for building and running Fuchsia"
}
#[fuchsia::test]
async fn test_parse_macos_version() -> Result<()> {
let mut run_command: command_runner::CommandRunner = |args| {
assert_eq!(
args.to_vec(),
vec!["defaults", "read", "loginwindow", "SystemVersionStampAsString"]
);
Ok((ExitStatus(0), "10.15.17\n\n".to_string(), "".to_string()))
};
assert_eq!(OperatingSystem::MacOS(10, 15), get_operating_system_macos(&run_command)?);
run_command = |args| {
assert_eq!(
args.to_vec(),
vec!["defaults", "read", "loginwindow", "SystemVersionStampAsString"]
);
Ok((ExitStatus(0), "11.1\n\n".to_string(), "".to_string()))
};
assert_eq!(OperatingSystem::MacOS(11, 1), get_operating_system_macos(&run_command)?);
Ok(())
}
#[fuchsia::test]
async fn run_checks_success() -> Result<()> {
let config = PreflightConfig { system: OperatingSystem::Linux };
let checks: Vec<Box<dyn PreflightCheck>> = vec![Box::new(SuccessCheck {})];
let mut buf = Vec::new();
let results = run_preflight_checks(&checks, &config).await?;
let result = write_preflight_results(&mut buf, &results);
let output = String::from_utf8(buf)?;
// Check for the various output strings.
assert!(output.starts_with(RUNNING_CHECKS_PREAMBLE));
assert!(output.contains("This check passed!"));
assert!(output.contains(EVERYTING_CHECKS_OUT));
result
}
#[fuchsia::test]
async fn run_checks_fail_nonrecoverable() -> Result<()> {
let config = PreflightConfig { system: OperatingSystem::Linux };
let checks: Vec<Box<dyn PreflightCheck>> = vec![
Box::new(SuccessCheck {}),
Box::new(FailPermanentCheck {}),
Box::new(FailRecoverableCheck {}),
];
let mut buf = Vec::new();
let results = run_preflight_checks(&checks, &config).await?;
let result = write_preflight_results(&mut buf, &results);
let output = String::from_utf8(buf)?;
// Check for the various output strings.
assert!(output.starts_with(RUNNING_CHECKS_PREAMBLE), "{:?}", output);
assert!(output.contains("This check passed!"), "{:?}", output);
assert!(output.contains("Oh no..."), "{:?}", output);
match result {
Err(error) => {
assert!(
error.to_string().contains(SOME_CHECKS_FAILED_FATAL),
"{}",
error.to_string()
);
assert!(
!error.to_string().contains(SOME_CHECKS_FAILED_RECOVERABLE),
"{}",
error.to_string()
);
Ok(())
N/A
N/A
{
"command": "ffx platform preflight",
"options": [
{
"description": "outputs json instead of human-readable text.",
"option": "json",
"shorthand": "",
"value_type": "bool"
}
],
"short": "Evaluate suitability for building and running Fuchsia"
}
N/A
N/A
N/A
{
"command": "ffx playground",
"options": [
{
"description": "A command to run. If passed, the playground will run that one command, display the output, and return immediately.",
"option": "command",
"shorthand": "c",
"value_type": "string"
}
],
"short": "Directly invoke FIDL services"
}
* **`ffx_playground_cmd`**: Emitted when executing commands inside the experimental `ffx playground` shell. Records the underlying command in the `type` dimension and logs whether its execution succeeded or failed.
N/A
N/A
N/A
{
"command": "ffx playground",
"options": [
{
"description": "A command to run. If passed, the playground will run that one command, display the output, and return immediately.",
"option": "command",
"shorthand": "c",
"value_type": "string"
}
],
"short": "Directly invoke FIDL services"
}
N/A
N/A
N/A
{
"command": "ffx power",
"options": [],
"short": "Control system power features"
}
// Copyright 2024 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use diagnostics_data::InspectData;
use ffx_e2e_emu::IsolatedEmulator;
#[fuchsia::test(logging = true)]
async fn taking_lease_adds_lease_to_broker_inspect() {
let emu = IsolatedEmulator::start("application-activity-test").await.unwrap();
emu.ffx(&["power", "system-activity", "application-activity", "start"]).await.unwrap();
// Wait until application_activity level changing to active.
loop {
if get_application_activity_level(&emu).await == 1 {
break;
}
std::thread::sleep(std::time::Duration::from_secs(1));
}
}
#[fuchsia::test(logging = true)]
async fn taking_lease_adds_lease_to_broker_inspect() {
let emu = IsolatedEmulator::start("application-activity-test").await.unwrap();
emu.ffx(&["power", "system-activity", "application-activity", "start"]).await.unwrap();
// Wait until application_activity level changing to active.
loop {
if get_application_activity_level(&emu).await == 1 {
break;
}
std::thread::sleep(std::time::Duration::from_secs(1));
}
}
self.dut.ffx.run(cmd)
async def test_wait_for_rcs_connection(self) -> None:
"""Test case for FFX.wait_for_rcs_connection()."""
self.dut.ffx.wait_for_rcs_connection()
async def test_ffx_run_test_component(self) -> None:
"""Test case for FFX.run_test_component()."""
# Skip test if run on non-eng images.
asserts.skip_if(
"core/test_manager" not in self.dut.ffx.run(["component", "list"]),
"Test manager component is not present",
)
output: str = self.dut.ffx.run_test_component(
"fuchsia-pkg://fuchsia.com/hello-world-rust-tests#meta/hello-world-rust-tests.cm",
)
asserts.assert_in("PASSED", output)
async def test_ffx_run_ssh_cmd(self) -> None:
"""Test case for FFX.run_ssh_cmd()."""
cmd: str = "ls"
self.dut.ffx.run_ssh_cmd(cmd)
async def test_get_ffx_target_status(self) -> None:
"""Test case for FFX.get_ffx_target_status()."""
output: str = self.dut.ffx.get_ffx_target_status()
asserts.assert_is_instance(output, str)
if __name__ == "__main__":
N/A
N/A
{
"command": "ffx process",
"options": [],
"short": "Processes related commands"
}
#[fuchsia::test]
async fn get_raw_data_test() {
let client = fdomain_local::local_client_empty();
let query_proxy = setup_fake_query_svc(client);
let raw_data = get_raw_data(query_proxy).await.expect("failed to get raw data");
assert_eq!(raw_data, *DATA_WRITTEN_BY_PROCESS_EXPLORER);
}
#[fuchsia::test]
async fn get_processes_data_test() {
let client = fdomain_local::local_client_empty();
let query_proxy = setup_fake_query_svc(client);
let processes_data =
get_processes_data(query_proxy).await.expect("failed to get processes_data");
assert_eq!(processes_data, *EXPECTED_PROCESSES_DATA);
}
#[fuchsia::test]
async fn test_verify_missing() {
let mut counter =
CategoryCounter::new(vec!["some".into(), "other".into(), "categories".into()]);
counter.increment_category("some");
counter.increment_category("other");
let missing = counter.get_invalid_category_list();
assert_eq!(missing.len(), 1);
assert_eq!(missing[0], "categories");
}
N/A
N/A
{
"command": "ffx process filter",
"options": [],
"short": "outputs information about the processes that correspond to the koids input"
}
N/A
N/A
N/A
{
"command": "ffx process generate-fuchsia-map",
"options": [],
"short": "outputs the json required to generate a map of all processes and channels"
}
N/A
N/A
N/A
{
"command": "ffx process kill",
"options": [],
"short": "Attempts to kill a process by it's KOID or process name."
}
N/A
N/A
N/A
{
"command": "ffx process list",
"options": [
{
"description": "outputs all processes and the kernel objects owned by each of them",
"option": "verbose",
"shorthand": "",
"value_type": "bool"
}
],
"short": "outputs a list containing the name and koid of all processes"
}
N/A
N/A
N/A
{
"command": "ffx process list",
"options": [
{
"description": "outputs all processes and the kernel objects owned by each of them",
"option": "verbose",
"shorthand": "",
"value_type": "bool"
}
],
"short": "outputs a list containing the name and koid of all processes"
}
N/A
N/A
N/A
{
"command": "ffx process stack_trace",
"options": [],
"short": "Attempts to get a strack trace a process by it's KOID or process name."
}
N/A
N/A
N/A
N/A
{
"command": "ffx process tree",
"options": [
{
"description": "include threads",
"option": "threads",
"shorthand": "",
"value_type": "bool"
}
],
"short": "outputs the tree of all tasks in the system"
}
N/A
N/A
N/A
{
"command": "ffx process tree",
"options": [
{
"description": "include threads",
"option": "threads",
"shorthand": "",
"value_type": "bool"
}
],
"short": "outputs the tree of all tasks in the system"
}
N/A
N/A
N/A
{
"command": "ffx product",
"options": [],
"short": "Discover and access product bundle metadata and image data."
}
#[test]
fn extract_blob_contents_test() -> Result<()> {
let blobfs_contents = BlobfsContents {
packages: PackagesMetadata {
base: PackageSetMetadata {
metadata: vec![PackageMetadata {
name: "hello".to_string(),
manifest: "path".into(),
blobs: Default::default(),
abi_revision: Some(version_history::AbiRevision::from_u64(1234)),
}],
},
cache: PackageSetMetadata { metadata: vec![] },
},
maximum_contents_size: Some(1234),
};
let mut assembled_system = AssembledSystem {
images: vec![Image::VBMeta("a/b/c".into()), Image::FVM("x/y/z".into())],
board_name: "my_board".into(),
partitions_config: None,
system_release_info: SystemReleaseInfo::new_for_testing(),
platform_tools: vec![],
};
assert_eq!(extract_blob_contents(&assembled_system), None);
assembled_system
.images
.push(Image::BlobFS { path: "path/to/blob.blk".into(), contents: blobfs_contents });
let blobfs_contents =
extract_blob_contents(&assembled_system).expect("blobfs contents is found");
#[test]
fn gerrit_report_test() {
let gerrit_report = create_gerrit_report(
&SizeResult { consumed_bytes: 151, consumed_bytes_resources: 30 },
200,
20,
50,
);
assert_eq!(
gerrit_report,
json!({
TOTAL_BLOBFS_GERRIT_COMPONENT_NAME: 121,
format!("{TOTAL_BLOBFS_GERRIT_COMPONENT_NAME}.budget"): 150,
format!("{TOTAL_BLOBFS_GERRIT_COMPONENT_NAME}.creepBudget"): 20,
TOTAL_RESOURCES_GERRIT_COMPONENT_NAME: 30,
format!("{TOTAL_RESOURCES_GERRIT_COMPONENT_NAME}.budget"): 50,
format!("{TOTAL_RESOURCES_GERRIT_COMPONENT_NAME}.creepBudget"): 2097152,
})
)
}
N/A
{
"command": "ffx product create-old",
"options": [
{
"description": "product.board label. e.g. \"workstation_eng.x64\".",
"option": "product-name",
"shorthand": "",
"value_type": "string"
},
{
"description": "unique version of this product.board.",
"option": "product-version",
#[fuchsia::test]
async fn test_pb_create_minimal() {
let temp = TempDir::new().unwrap();
let tempdir = Utf8Path::from_path(temp.path()).unwrap();
let pb_dir = tempdir.join("pb");
let partitions_dir = tempdir.join("partitions");
fs::create_dir(&partitions_dir).unwrap();
let partitions_path = partitions_dir.join("partitions_config.json");
let partitions_file = File::create(&partitions_path).unwrap();
serde_json::to_writer(&partitions_file, &PartitionsConfig::default()).unwrap();
let system_dir = tempdir.join("system");
AssembledSystem {
images: vec![],
board_name: "board_name".into(),
partitions_config: Some(DirectoryPathBuf::new(partitions_dir)),
system_release_info: SystemReleaseInfo::new_for_testing(),
platform_tools: vec![],
}
.write_to_dir(&system_dir, None::<Utf8PathBuf>)
.unwrap();
let tool_provider = Box::new(FakeToolProvider::new_with_side_effect(blobfs_side_effect));
pb_create_with_sdk_version(
CreateCommand {
product_name: String::default(),
product_version: Some(String::default()),
#[fuchsia::test]
async fn test_pb_create_a_and_r() {
let temp = TempDir::new().unwrap();
let tempdir = Utf8Path::from_path(temp.path()).unwrap();
let pb_dir = tempdir.join("pb");
let partitions_dir = tempdir.join("partitions");
fs::create_dir(&partitions_dir).unwrap();
let partitions_path = partitions_dir.join("partitions_config.json");
let partitions_file = File::create(&partitions_path).unwrap();
serde_json::to_writer(&partitions_file, &PartitionsConfig::default()).unwrap();
let system_dir = tempdir.join("system");
fs::create_dir(&system_dir).unwrap();
AssembledSystem {
images: Default::default(),
board_name: "my_board".into(),
partitions_config: Some(DirectoryPathBuf::new(partitions_dir)),
system_release_info: SystemReleaseInfo::new_for_testing(),
platform_tools: vec![],
}
.write_to_dir(&system_dir, None::<Utf8PathBuf>)
.unwrap();
let tool_provider = Box::new(FakeToolProvider::new_with_side_effect(blobfs_side_effect));
pb_create_with_sdk_version(
CreateCommand {
product_name: String::default(),
#[fuchsia::test]
async fn test_pb_create_a_and_r_with_multiple_zbi() {
let temp = TempDir::new().unwrap();
let tempdir = Utf8Path::from_path(temp.path()).unwrap();
let pb_dir = tempdir.join("pb");
let partitions_dir = tempdir.join("partitions");
fs::create_dir(&partitions_dir).unwrap();
let partitions_path = partitions_dir.join("partitions_config.json");
let partitions_file = File::create(&partitions_path).unwrap();
serde_json::to_writer(&partitions_file, &PartitionsConfig::default()).unwrap();
let system_dir = tempdir.join("system");
fs::create_dir(&system_dir).unwrap();
let mut manifest = AssembledSystem {
images: Default::default(),
board_name: "my_board".into(),
partitions_config: None,
system_release_info: SystemReleaseInfo::new_for_testing(),
platform_tools: vec![],
};
manifest.images = vec![
Image::ZBI { path: tempdir.join("path1"), signed: false },
Image::ZBI { path: tempdir.join("path2"), signed: true },
];
std::fs::write(&tempdir.join("path1"), "").unwrap();
std::fs::write(&tempdir.join("path2"), "").unwrap();
manifest.write_to_dir(&system_dir, None::<Utf8PathBuf>).unwrap();
N/A
N/A
{
"command": "ffx product create-old",
"options": [
{
"description": "product.board label. e.g. \"workstation_eng.x64\".",
"option": "product-name",
"shorthand": "",
"value_type": "string"
},
{
"description": "unique version of this product.board.",
"option": "product-version",
N/A
N/A
N/A
{
"command": "ffx product create-old",
"options": [
{
"description": "product.board label. e.g. \"workstation_eng.x64\".",
"option": "product-name",
"shorthand": "",
"value_type": "string"
},
{
"description": "unique version of this product.board.",
"option": "product-version",
N/A
N/A
N/A
{
"command": "ffx product create-old",
"options": [
{
"description": "product.board label. e.g. \"workstation_eng.x64\".",
"option": "product-name",
"shorthand": "",
"value_type": "string"
},
{
"description": "unique version of this product.board.",
"option": "product-version",
N/A
N/A
N/A
{
"command": "ffx product create-old",
"options": [
{
"description": "product.board label. e.g. \"workstation_eng.x64\".",
"option": "product-name",
"shorthand": "",
"value_type": "string"
},
{
"description": "unique version of this product.board.",
"option": "product-version",
N/A
N/A
N/A
{
"command": "ffx product create-old",
"options": [
{
"description": "product.board label. e.g. \"workstation_eng.x64\".",
"option": "product-name",
"shorthand": "",
"value_type": "string"
},
{
"description": "unique version of this product.board.",
"option": "product-version",
N/A
N/A
N/A
{
"command": "ffx product create-old",
"options": [
{
"description": "product.board label. e.g. \"workstation_eng.x64\".",
"option": "product-name",
"shorthand": "",
"value_type": "string"
},
{
"description": "unique version of this product.board.",
"option": "product-version",
N/A
N/A
N/A
{
"command": "ffx product create-old",
"options": [
{
"description": "product.board label. e.g. \"workstation_eng.x64\".",
"option": "product-name",
"shorthand": "",
"value_type": "string"
},
{
"description": "unique version of this product.board.",
"option": "product-version",
N/A
N/A
N/A
{
"command": "ffx product create-old",
"options": [
{
"description": "product.board label. e.g. \"workstation_eng.x64\".",
"option": "product-name",
"shorthand": "",
"value_type": "string"
},
{
"description": "unique version of this product.board.",
"option": "product-version",
N/A
N/A
N/A
{
"command": "ffx product create-old",
"options": [
{
"description": "product.board label. e.g. \"workstation_eng.x64\".",
"option": "product-name",
"shorthand": "",
"value_type": "string"
},
{
"description": "unique version of this product.board.",
"option": "product-version",
N/A
N/A
N/A
{
"command": "ffx product create-old",
"options": [
{
"description": "product.board label. e.g. \"workstation_eng.x64\".",
"option": "product-name",
"shorthand": "",
"value_type": "string"
},
{
"description": "unique version of this product.board.",
"option": "product-version",
N/A
N/A
N/A
{
"command": "ffx product create-old",
"options": [
{
"description": "product.board label. e.g. \"workstation_eng.x64\".",
"option": "product-name",
"shorthand": "",
"value_type": "string"
},
{
"description": "unique version of this product.board.",
"option": "product-version",
N/A
N/A
N/A
{
"command": "ffx product create-old",
"options": [
{
"description": "product.board label. e.g. \"workstation_eng.x64\".",
"option": "product-name",
"shorthand": "",
"value_type": "string"
},
{
"description": "unique version of this product.board.",
"option": "product-version",
N/A
N/A
N/A
{
"command": "ffx product create-old",
"options": [
{
"description": "product.board label. e.g. \"workstation_eng.x64\".",
"option": "product-name",
"shorthand": "",
"value_type": "string"
},
{
"description": "unique version of this product.board.",
"option": "product-version",
N/A
N/A
N/A
{
"command": "ffx product create-old",
"options": [
{
"description": "product.board label. e.g. \"workstation_eng.x64\".",
"option": "product-name",
"shorthand": "",
"value_type": "string"
},
{
"description": "unique version of this product.board.",
"option": "product-version",
N/A
N/A
N/A
{
"command": "ffx product create-old",
"options": [
{
"description": "product.board label. e.g. \"workstation_eng.x64\".",
"option": "product-name",
"shorthand": "",
"value_type": "string"
},
{
"description": "unique version of this product.board.",
"option": "product-version",
N/A
N/A
N/A
{
"command": "ffx product create-old",
"options": [
{
"description": "product.board label. e.g. \"workstation_eng.x64\".",
"option": "product-name",
"shorthand": "",
"value_type": "string"
},
{
"description": "unique version of this product.board.",
"option": "product-version",
N/A
N/A
N/A
{
"command": "ffx product download",
"options": [
{
"description": "get the data again, even if it's already present locally.",
"option": "force",
"shorthand": "",
"value_type": "bool"
},
{
"description": "use specific auth flow for oauth2 (see examples; default: pkce).",
"option": "auth",
#[fuchsia::test]
async fn test_gcs_pb_download_impl() {
let test_dir = tempfile::TempDir::new().expect("temp dir");
let server = TestServer::builder()
.handler(ForPath::new(
"/example/fake/transfer.json",
StaticResponse::ok_body(
r#"
{
"version": "1",
"entries": [{
"type": "files",
"local": "foo",
"remote": "data",
"entries": [{ "name": "payload.txt"}]
}]
}"#,
),
))
.handler(ForPath::new("/api/b/example/o", StaticResponse::ok_body(r#"{}"#)))
.start()
.await;
let auth = pbms::AuthFlowChoice::Default;
let force = false;
let manifest_url = "gs://example/fake/transfer.json".to_string();
let product_dir = test_dir.path().join("download");
let client = Client::initial_with_urls(
&server.local_url_for_path("api"),
&server.local_url_for_path("storage"),
#[fuchsia::test]
async fn test_http_download() {
let server = TestServer::builder()
.handler(ForPath::new(
"/example/fake/transfer.json",
StaticResponse::ok_body(
r#"
{
"version": "1",
"entries": [{
"type": "files",
"local": "foo",
"remote": "data",
"entries": [{ "name": "payload.txt"}]
}]
}"#,
),
))
.handler(ForPath::new(
"/data/payload.txt",
StaticResponse::ok_body(r#"Some fake payload to download."#),
))
.start()
.await;
let test_dir = tempfile::TempDir::new().expect("temp dir");
let download_dir = test_dir.path().join("download");
let auth = pbms::AuthFlowChoice::NoAuth;
let force = false;
let manifest_url = server.local_url_for_path("example/fake/transfer.json");
#[fuchsia::test]
async fn test_preprocess_cmd() {
let tmp = tempfile::tempdir().unwrap();
let path = tmp.path().join(PB_MANIFEST_NAME);
let env = setup_test_env(&path).await;
let mut f = File::create(&path).expect("file create");
f.write_all(
r#"[{
"name": "fake_name",
"product_version": "fake_version",
"transfer_manifest_url": "fake_url"
}]"#
.as_bytes(),
)
.expect("write_all");
let ui = structured_ui::MockUi::new();
let force = false;
let manifest_url = String::from("fake_name");
let auth = pbms::AuthFlowChoice::NoAuth;
let product_dir = tmp.path().join("download");
let base_url = Some(format!("file:{}", tmp.path().display()));
let cmd = DownloadCommand {
force,
auth,
manifest_url,
product_dir,
base_url,
version: None,
```posix-terminal
```posix-terminal
N/A
{
"command": "ffx product download",
"options": [
{
"description": "get the data again, even if it's already present locally.",
"option": "force",
"shorthand": "",
"value_type": "bool"
},
{
"description": "use specific auth flow for oauth2 (see examples; default: pkce).",
"option": "auth",
N/A
N/A
N/A
{
"command": "ffx product download",
"options": [
{
"description": "get the data again, even if it's already present locally.",
"option": "force",
"shorthand": "",
"value_type": "bool"
},
{
"description": "use specific auth flow for oauth2 (see examples; default: pkce).",
"option": "auth",
N/A
N/A
N/A
{
"command": "ffx product download",
"options": [
{
"description": "get the data again, even if it's already present locally.",
"option": "force",
"shorthand": "",
"value_type": "bool"
},
{
"description": "use specific auth flow for oauth2 (see examples; default: pkce).",
"option": "auth",
N/A
```posix-terminal
```posix-terminal
N/A
{
"command": "ffx product download",
"options": [
{
"description": "get the data again, even if it's already present locally.",
"option": "force",
"shorthand": "",
"value_type": "bool"
},
{
"description": "use specific auth flow for oauth2 (see examples; default: pkce).",
"option": "auth",
N/A
```posix-terminal
```posix-terminal
N/A
{
"command": "ffx product download",
"options": [
{
"description": "get the data again, even if it's already present locally.",
"option": "force",
"shorthand": "",
"value_type": "bool"
},
{
"description": "use specific auth flow for oauth2 (see examples; default: pkce).",
"option": "auth",
N/A
```posix-terminal
```posix-terminal
N/A
{
"command": "ffx product get",
"options": [
{
"description": "get the data again, even if it's already present locally.",
"option": "force",
"shorthand": "",
"value_type": "bool"
},
{
"description": "use specific auth flow for oauth2 (see examples; default: pkce).",
"option": "auth",
N/A
```posix-terminal
N/A
{
"command": "ffx product get",
"options": [
{
"description": "get the data again, even if it's already present locally.",
"option": "force",
"shorthand": "",
"value_type": "bool"
},
{
"description": "use specific auth flow for oauth2 (see examples; default: pkce).",
"option": "auth",
N/A
N/A
N/A
{
"command": "ffx product get",
"options": [
{
"description": "get the data again, even if it's already present locally.",
"option": "force",
"shorthand": "",
"value_type": "bool"
},
{
"description": "use specific auth flow for oauth2 (see examples; default: pkce).",
"option": "auth",
N/A
N/A
N/A
{
"command": "ffx product get",
"options": [
{
"description": "get the data again, even if it's already present locally.",
"option": "force",
"shorthand": "",
"value_type": "bool"
},
{
"description": "use specific auth flow for oauth2 (see examples; default: pkce).",
"option": "auth",
N/A
N/A
N/A
{
"command": "ffx product get",
"options": [
{
"description": "get the data again, even if it's already present locally.",
"option": "force",
"shorthand": "",
"value_type": "bool"
},
{
"description": "use specific auth flow for oauth2 (see examples; default: pkce).",
"option": "auth",
N/A
N/A
N/A
{
"command": "ffx product get",
"options": [
{
"description": "get the data again, even if it's already present locally.",
"option": "force",
"shorthand": "",
"value_type": "bool"
},
{
"description": "use specific auth flow for oauth2 (see examples; default: pkce).",
"option": "auth",
N/A
N/A
N/A
{
"command": "ffx product get",
"options": [
{
"description": "get the data again, even if it's already present locally.",
"option": "force",
"shorthand": "",
"value_type": "bool"
},
{
"description": "use specific auth flow for oauth2 (see examples; default: pkce).",
"option": "auth",
N/A
N/A
N/A
{
"command": "ffx product get-artifacts",
"options": [
{
"description": "select what group of artifacts to list. One of flash, emu, update, bootloader, all",
"option": "artifacts-group",
"shorthand": "g",
"value_type": "string"
},
{
"description": "return relative path or not",
"option": "relative-path",
#[fuchsia::test]
async fn test_get_flashing_artifacts() {
let env = ffx_config::test_init().expect("test env");
let tmp = tempdir().unwrap();
let tempdir = Utf8Path::from_path(tmp.path()).unwrap().canonicalize_utf8().unwrap();
let json = r#"
{
bootloader_partitions: [
{
type: "tpl",
name: "firmware_tpl",
image: "bootloader_path",
}
],
partitions: [
{
type: "ZBI",
name: "zircon_a",
slot: "A",
},
{
type: "VBMeta",
name: "vbmeta_b",
slot: "B",
},
{
type: "FVM",
name: "fvm",
#[fuchsia::test]
async fn test_get_emu_artifacts() {
let env = ffx_config::test_init().expect("test env");
let tmp = tempdir().unwrap();
let tempdir = Utf8Path::from_path(tmp.path()).unwrap().canonicalize_utf8().unwrap();
let json = r#"
{
bootloader_partitions: [
{
type: "tpl",
name: "firmware_tpl",
image: "bootloader_path",
}
],
partitions: [
{
type: "ZBI",
name: "zircon_a",
slot: "A",
},
{
type: "VBMeta",
name: "vbmeta_b",
slot: "B",
},
{
type: "FVM",
name: "fvm",
#[fuchsia::test]
async fn test_get_bootloaders() {
let env = ffx_config::test_init().expect("test env");
let tmp = tempdir().unwrap();
let tempdir = Utf8Path::from_path(tmp.path()).unwrap().canonicalize_utf8().unwrap();
let json = r#"
{
bootloader_partitions: [
{
type: "",
name: "firmware_tpl",
image: "bootloader_path",
},
{
type: "bl2",
name: "firmware_tpl",
image: "bootloader_path2",
}
],
partitions: [],
hardware_revision: "hw",
unlock_credentials: [
"credential.zip",
],
}
"#;
let partitions_config_path = tempdir.join("partitions_config.json");
File::create(partitions_config_path.as_path()).unwrap().write_all(json.as_bytes()).unwrap();
N/A
N/A
{
"command": "ffx product get-artifacts",
"options": [
{
"description": "select what group of artifacts to list. One of flash, emu, update, bootloader, all",
"option": "artifacts-group",
"shorthand": "g",
"value_type": "string"
},
{
"description": "return relative path or not",
"option": "relative-path",
N/A
N/A
N/A
{
"command": "ffx product get-artifacts",
"options": [
{
"description": "select what group of artifacts to list. One of flash, emu, update, bootloader, all",
"option": "artifacts-group",
"shorthand": "g",
"value_type": "string"
},
{
"description": "return relative path or not",
"option": "relative-path",
N/A
N/A
N/A
{
"command": "ffx product get-image-path",
"options": [
{
"description": "the slot where image will be located in. Valid slots are A,B,R.",
"option": "slot",
"shorthand": "",
"value_type": "string"
},
{
"description": "the type of image. Supported types are zbi, vbmeta, fvm, fxfs.fastboot, qemu-kernel, or dtbo.",
"option": "image-type",
#[fuchsia::test]
async fn test_get_image_path() {
let env = ffx_config::test_init().expect("test env");
let tmp = tempdir().unwrap();
let tempdir = Utf8Path::from_path(tmp.path()).unwrap().canonicalize_utf8().unwrap();
let json = r#"
{
bootloader_partitions: [
{
type: "bl2",
name: "bl2",
image: "bootloader_bl2",
},
{
type: "",
name: "bootloader",
image: "bootloader",
}
],
partitions: [
{
type: "ZBI",
name: "zircon_a",
slot: "A",
},
{
type: "VBMeta",
name: "vbmeta_b",
#[fuchsia::test]
async fn test_get_image_path_not_found() {
let env = ffx_config::test_init().expect("test env");
let pb = ProductBundle::V2(ProductBundleV2 {
product_name: "".to_string(),
product_version: "".to_string(),
partitions: PartitionsConfig::default(),
sdk_version: "".to_string(),
system_a: Some(vec![
Image::ZBI { path: Utf8PathBuf::from("zbi/path"), signed: false },
Image::FVM(Utf8PathBuf::from("fvm/path")),
Image::QemuKernel(Utf8PathBuf::from("qemu/path")),
]),
system_b: None,
system_r: None,
platform_tools_a: vec![],
platform_tools_b: vec![],
platform_tools_r: vec![],
repositories: vec![],
update_package_hash: None,
virtual_devices_path: None,
release_info: None,
});
let tool = PbGetImagePathTool {
cmd: GetImagePathCommand {
product_bundle: None,
slot: Some(Slot::A),
image_type: Some(ImageType::VBMeta),
relative_path: false,
#[fuchsia::test]
async fn test_get_image_path_not_found_machine() {
let env = ffx_config::test_init().expect("test env");
let pb_path = env.isolate_root.path().join("test_bundle");
fs::create_dir_all(&pb_path).expect("create test bundle dir");
let pb = ProductBundle::V2(ProductBundleV2 {
product_name: "".to_string(),
product_version: "".to_string(),
partitions: PartitionsConfig::default(),
sdk_version: "".to_string(),
system_a: Some(vec![
Image::ZBI {
path: Utf8PathBuf::from_path_buf(pb_path.join("zbi/path")).expect("utf8 path"),
signed: false,
},
Image::FVM(
Utf8PathBuf::from_path_buf(pb_path.join("fvm/path")).expect("utf8 path"),
),
Image::QemuKernel(
Utf8PathBuf::from_path_buf(pb_path.join("qemu/path")).expect("utf8 path"),
),
]),
system_b: None,
system_r: None,
platform_tools_a: vec![],
platform_tools_b: vec![],
platform_tools_r: vec![],
repositories: vec![],
N/A
N/A
{
"command": "ffx product get-image-path",
"options": [
{
"description": "the slot where image will be located in. Valid slots are A,B,R.",
"option": "slot",
"shorthand": "",
"value_type": "string"
},
{
"description": "the type of image. Supported types are zbi, vbmeta, fvm, fxfs.fastboot, qemu-kernel, or dtbo.",
"option": "image-type",
N/A
N/A
N/A
{
"command": "ffx product get-image-path",
"options": [
{
"description": "the slot where image will be located in. Valid slots are A,B,R.",
"option": "slot",
"shorthand": "",
"value_type": "string"
},
{
"description": "the type of image. Supported types are zbi, vbmeta, fvm, fxfs.fastboot, qemu-kernel, or dtbo.",
"option": "image-type",
N/A
N/A
N/A
{
"command": "ffx product get-image-path",
"options": [
{
"description": "the slot where image will be located in. Valid slots are A,B,R.",
"option": "slot",
"shorthand": "",
"value_type": "string"
},
{
"description": "the type of image. Supported types are zbi, vbmeta, fvm, fxfs.fastboot, qemu-kernel, or dtbo.",
"option": "image-type",
N/A
N/A
N/A
{
"command": "ffx product get-image-path",
"options": [
{
"description": "the slot where image will be located in. Valid slots are A,B,R.",
"option": "slot",
"shorthand": "",
"value_type": "string"
},
{
"description": "the type of image. Supported types are zbi, vbmeta, fvm, fxfs.fastboot, qemu-kernel, or dtbo.",
"option": "image-type",
N/A
N/A
N/A
{
"command": "ffx product get-repository",
"options": [],
"short": "Get the info of repository inside a Product Bundle."
}
#[test]
fn test_get_repository() {
let tmp = tempfile::tempdir().unwrap();
let dir = Utf8Path::from_path(tmp.path()).unwrap();
let product_bundle_dir = dir.join("product_bundle");
let blobs_dir = product_bundle_dir.join("blobs");
let fuchsia_metadata_dir = product_bundle_dir.join("repository");
let pb = ProductBundle::V2(ProductBundleV2 {
product_name: "test".into(),
product_version: "test-product-version".into(),
partitions: PartitionsConfig::default(),
sdk_version: "test-sdk-version".into(),
system_a: None,
system_b: None,
system_r: None,
platform_tools_a: vec![],
platform_tools_b: vec![],
platform_tools_r: vec![],
repositories: vec![Repository {
name: "fuchsia.com".into(),
metadata_path: fuchsia_metadata_dir.clone(),
blobs_path: blobs_dir.clone(),
delivery_blob_type: 1,
root_private_key_path: None,
targets_private_key_path: None,
snapshot_private_key_path: None,
timestamp_private_key_path: None,
N/A
N/A
{
"command": "ffx product get-version",
"options": [
{
"description": "when true, return version info for all included assembly artifacts.",
"option": "include-dependencies",
"shorthand": "",
"value_type": "bool"
}
],
"short": "Get the product version of a Product Bundle."
}
#[test]
fn test_version_string_writer() {
let pb = generate_test_product_bundle();
let version_info = load_product_bundle_v2(&pb);
assert_eq!("fake_version", version_info.version.human);
let test_buffers = TestBuffers::default();
let mut writer: MachineWriter<VersionInfo> = MachineWriter::new_test(None, &test_buffers);
// Write the version string.
let res = writer.line(version_info.version);
assert!(res.is_ok());
// Write the json structure. This should be suppressed.
let res = writer.machine(&version_info.version_with_deps);
assert!(res.is_ok());
let (stdout, stderr) = test_buffers.into_strings();
assert_eq!("fake_version\n", stdout);
assert_eq!("", stderr);
}
#[test]
fn test_machine_json_writer() {
let mut expected = generate_test_pb_flat_unique_release_info_vector();
let pb = generate_test_product_bundle();
let version_info = load_product_bundle_v2(&pb);
expected.sort();
let mut release_info = version_info.version_with_deps;
release_info.machine.sort();
assert_eq!(expected, release_info.machine);
let test_buffers = TestBuffers::default();
let mut writer: MachineWriter<VersionInfo> =
MachineWriter::new_test(Some(Format::Json), &test_buffers);
// Write the version string. This should be suppressed.
let res = writer.line(version_info.version);
assert!(res.is_ok());
// Write the json structure.
let res = writer.machine(&release_info);
assert!(res.is_ok());
let (stdout, stderr) = test_buffers.into_strings();
// The stdout string needs to be un-escaped, which can be done using serde.
let mut actual: VersionInfo = serde_json::from_str(&stdout).unwrap();
actual.machine.sort();
#[test]
fn test_load_platform() {
let tmp = tempfile::tempdir().unwrap();
let path = Utf8Path::from_path(tmp.path()).unwrap();
let platform_artifacts_path = path.join("platform_artifacts.json");
let mut file = std::fs::File::create(platform_artifacts_path).unwrap();
serde_json::to_writer(
&mut file,
&serde_json::json!(
{
// This verifies it can handle config changes.
"new_field": "some_value",
"release_info": {
"name": "fake_platform",
"repository": "fake_repository_for_platform",
"version": "fake_version_for_platform"
}
}
),
)
.unwrap();
let info = load_platform(&path).unwrap();
assert_eq!(info.human, "fake_version_for_platform");
assert_eq!(
info.machine[0],
UniqueReleaseInfo::new(
"fake_platform".to_string(),
"fake_version_for_platform".to_string(),
N/A
N/A
{
"command": "ffx product get-version",
"options": [
{
"description": "when true, return version info for all included assembly artifacts.",
"option": "include-dependencies",
"shorthand": "",
"value_type": "bool"
}
],
"short": "Get the product version of a Product Bundle."
}
N/A
N/A
N/A
{
"command": "ffx product list",
"options": [
{
"description": "use specific auth flow for oauth2 (see examples; default: pkce).",
"option": "auth",
"shorthand": "",
"value_type": "string"
},
{
"description": "location to look for product bundles manifest inside GCS.",
"option": "base-url",
#[fuchsia::test]
async fn test_pb_list_impl() {
let tmp = tempfile::tempdir().unwrap();
let path = tmp.path().join(PB_MANIFEST_NAME);
let env = setup_test_env().await;
let mut f = File::create(&path).expect("file create");
f.write_all(
r#"[{
"name": "fake_name",
"product_version": "fake_version",
"transfer_manifest_url": "fake_url"
}]"#
.as_bytes(),
)
.expect("write_all");
let ui = structured_ui::MockUi::new();
let pbs = pb_list_impl(
&AuthFlowChoice::Default,
Some(format!("file:{}", tmp.path().display())),
None,
None,
&ui,
&env.context,
)
.await
.expect("testing list");
assert_eq!(
vec![ProductBundle {
#[fuchsia::test]
async fn test_pb_list_impl_filter_based_on_version() {
let tmp = tempfile::tempdir().unwrap();
let path = tmp.path().join(PB_MANIFEST_NAME);
let env = setup_test_env().await;
let mut f = File::create(&path).expect("file create");
f.write_all(
r#"[{
"name": "fake_name",
"product_version": "fake_version",
"transfer_manifest_url": "fake_url"
}]"#
.as_bytes(),
)
.expect("write_all");
let ui = structured_ui::MockUi::new();
let pbs = pb_list_impl(
&AuthFlowChoice::Default,
None,
Some("24.20240910.2.1".into()),
None,
&ui,
&env.context,
)
.await
.expect("testing list");
assert!(pbs.is_empty());
}
#[fuchsia::test]
async fn test_pb_list_impl_machine_code() {
let tmp = tempfile::tempdir().unwrap();
let path = tmp.path().join(PB_MANIFEST_NAME);
let env = setup_test_env().await;
let mut f = File::create(&path).expect("file create");
f.write_all(
r#"[{
"name": "fake_name",
"product_version": "fake_version",
"transfer_manifest_url": "fake_url"
}]"#
.as_bytes(),
)
.expect("write_all");
let buffers = TestBuffers::default();
let writer = MachineWriter::new_test(Some(Format::Json), &buffers);
let tool = ProductListTool {
cmd: ListCommand {
auth: AuthFlowChoice::Default,
base_url: Some(format!("file:{}", tmp.path().display())),
version: None,
branch: None,
},
context: env.context.clone(),
};
tool.main(writer).await.expect("testing list");
```posix-terminal
N/A
{
"command": "ffx product list",
"options": [
{
"description": "use specific auth flow for oauth2 (see examples; default: pkce).",
"option": "auth",
"shorthand": "",
"value_type": "string"
},
{
"description": "location to look for product bundles manifest inside GCS.",
"option": "base-url",
N/A
N/A
N/A
{
"command": "ffx product list",
"options": [
{
"description": "use specific auth flow for oauth2 (see examples; default: pkce).",
"option": "auth",
"shorthand": "",
"value_type": "string"
},
{
"description": "location to look for product bundles manifest inside GCS.",
"option": "base-url",
N/A
N/A
N/A
{
"command": "ffx product list",
"options": [
{
"description": "use specific auth flow for oauth2 (see examples; default: pkce).",
"option": "auth",
"shorthand": "",
"value_type": "string"
},
{
"description": "location to look for product bundles manifest inside GCS.",
"option": "base-url",
N/A
```posix-terminal
N/A
{
"command": "ffx product list",
"options": [
{
"description": "use specific auth flow for oauth2 (see examples; default: pkce).",
"option": "auth",
"shorthand": "",
"value_type": "string"
},
{
"description": "location to look for product bundles manifest inside GCS.",
"option": "base-url",
N/A
```posix-terminal
N/A
{
"command": "ffx product lookup",
"options": [
{
"description": "use specific auth flow for oauth2 (see examples; default: pkce).",
"option": "auth",
"shorthand": "",
"value_type": "string"
},
{
"description": "where to look for product bundles manifest.",
"option": "base-url",
#[fuchsia::test]
async fn test_pb_lookup_impl() {
let tmp = tempfile::tempdir().unwrap();
let path = tmp.path().join(PB_MANIFEST_NAME);
let env = setup_test_env(&path).await;
let mut f = File::create(&path).expect("file create");
f.write_all(
r#"[{
"name": "fake_name",
"product_version": "fake_version",
"transfer_manifest_url": "fake_url"
}]"#
.as_bytes(),
)
.expect("write_all");
let ui = structured_ui::MockUi::new();
let product = pb_lookup_impl(
&AuthFlowChoice::Default,
&Some(format!("file:{}", tmp.path().display())),
"fake_name",
"fake_version",
&ui,
&env.context,
)
.await
.expect("testing lookup");
assert_eq!(
#[fuchsia::test]
async fn test_bp_lookup_machine_mode() {
let tmp = tempfile::tempdir().unwrap();
let path = tmp.path().join(PB_MANIFEST_NAME);
let env = setup_test_env(&path).await;
let mut f = File::create(&path).expect("file create");
f.write_all(
r#"[{
"name": "fake_name",
"product_version": "fake_version",
"transfer_manifest_url": "fake_url"
}]"#
.as_bytes(),
)
.expect("write_all");
let buffers = TestBuffers::default();
let writer = VerifiedMachineWriter::new_test(Some(Format::Json), &buffers);
let tool = PbLookupTool {
cmd: LookupCommand {
auth: AuthFlowChoice::Default,
base_url: Some(format!("file:{}", tmp.path().display())),
name: "fake_name".into(),
version: "fake_version".into(),
},
context: env.context.clone(),
};
tool.main(writer).await.expect("testing lookup");
N/A
N/A
{
"command": "ffx product lookup",
"options": [
{
"description": "use specific auth flow for oauth2 (see examples; default: pkce).",
"option": "auth",
"shorthand": "",
"value_type": "string"
},
{
"description": "where to look for product bundles manifest.",
"option": "base-url",
N/A
N/A
N/A
{
"command": "ffx product lookup",
"options": [
{
"description": "use specific auth flow for oauth2 (see examples; default: pkce).",
"option": "auth",
"shorthand": "",
"value_type": "string"
},
{
"description": "where to look for product bundles manifest.",
"option": "base-url",
N/A
N/A
N/A
{
"command": "ffx product show",
"options": [
{
"description": "list the virtual devices linked to this product bundle.",
"option": "devices",
"shorthand": "",
"value_type": "bool"
},
{
"description": "print the details of a virtual device linked to this product bundle.",
"option": "device",
N/A
N/A
N/A
{
"command": "ffx product show",
"options": [
{
"description": "list the virtual devices linked to this product bundle.",
"option": "devices",
"shorthand": "",
"value_type": "bool"
},
{
"description": "print the details of a virtual device linked to this product bundle.",
"option": "device",
N/A
N/A
N/A
{
"command": "ffx product show",
"options": [
{
"description": "list the virtual devices linked to this product bundle.",
"option": "devices",
"shorthand": "",
"value_type": "bool"
},
{
"description": "print the details of a virtual device linked to this product bundle.",
"option": "device",
N/A
N/A
N/A
{
"command": "ffx product-bundle",
"options": [],
"short": "Manage product bundles. NOTE: 'list' and 'get' have been moved to 'ffx product'"
}
N/A
N/A
{
"command": "ffx product-bundle bisect",
"options": [
{
"description": "known-good version of the product bundle. The bisection search window begins here.",
"option": "from-success",
"shorthand": "",
"value_type": "string"
},
{
"description": "known-bad version of the product bundle. The bisection search window ends here.",
"option": "to-failure",
with the `ffx product-bundle bisect` command to automate the bisection process.
The `ffx product-bundle bisect` tool supports an `--script` argument that takes an executable file path. During the execution phase of a bisection step, instead of waiting for the user to manually verify a flashed device, the bisection CLI tool will invoke this script.
N/A
```posix-terminal
N/A
{
"command": "ffx product-bundle bisect",
"options": [
{
"description": "known-good version of the product bundle. The bisection search window begins here.",
"option": "from-success",
"shorthand": "",
"value_type": "string"
},
{
"description": "known-bad version of the product bundle. The bisection search window ends here.",
"option": "to-failure",
N/A
N/A
N/A
{
"command": "ffx product-bundle bisect",
"options": [
{
"description": "known-good version of the product bundle. The bisection search window begins here.",
"option": "from-success",
"shorthand": "",
"value_type": "string"
},
{
"description": "known-bad version of the product bundle. The bisection search window ends here.",
"option": "to-failure",
N/A
N/A
N/A
{
"command": "ffx product-bundle bisect",
"options": [
{
"description": "known-good version of the product bundle. The bisection search window begins here.",
"option": "from-success",
"shorthand": "",
"value_type": "string"
},
{
"description": "known-bad version of the product bundle. The bisection search window ends here.",
"option": "to-failure",
N/A
N/A
N/A
{
"command": "ffx product-bundle bisect",
"options": [
{
"description": "known-good version of the product bundle. The bisection search window begins here.",
"option": "from-success",
"shorthand": "",
"value_type": "string"
},
{
"description": "known-bad version of the product bundle. The bisection search window ends here.",
"option": "to-failure",
N/A
N/A
N/A
{
"command": "ffx product-bundle bisect",
"options": [
{
"description": "known-good version of the product bundle. The bisection search window begins here.",
"option": "from-success",
"shorthand": "",
"value_type": "string"
},
{
"description": "known-bad version of the product bundle. The bisection search window ends here.",
"option": "to-failure",
N/A
N/A
N/A
{
"command": "ffx product-bundle bisect",
"options": [
{
"description": "known-good version of the product bundle. The bisection search window begins here.",
"option": "from-success",
"shorthand": "",
"value_type": "string"
},
{
"description": "known-bad version of the product bundle. The bisection search window ends here.",
"option": "to-failure",
N/A
N/A
N/A
{
"command": "ffx product-bundle bisect",
"options": [
{
"description": "known-good version of the product bundle. The bisection search window begins here.",
"option": "from-success",
"shorthand": "",
"value_type": "string"
},
{
"description": "known-bad version of the product bundle. The bisection search window ends here.",
"option": "to-failure",
N/A
N/A
N/A
{
"command": "ffx product-bundle create",
"options": [
{
"description": "the platform artifacts to use. See PLATFORM_ARTIFACT below.",
"option": "platform",
"shorthand": "",
"value_type": "string"
},
{
"description": "the product config to use. See ARTIFACT below.",
"option": "product-config",
#[test]
fn test_recovery_board_config_requires_recovery_product_config() {
let cmd = CreateCommand {
product_config_board_config_combo: None,
platform: None,
product_config: Some("product".to_string()),
recovery_product_config: None,
board_config: Some("board".to_string()),
recovery_board_config: Some("recovery_board".to_string()),
output_name: None,
output_version: None,
output_version_file: None,
tuf_keys: None,
ota_manifest_key: None,
developer_overrides: None,
stage: false,
out: None,
auth: AuthFlowChoice::Default,
zbi_only: false,
bib_set: vec![],
pib: vec![],
};
let result = SanitizedCreateCommand::try_from(cmd);
assert!(result.is_err());
assert_eq!(
result.unwrap_err().to_string(),
"--recovery-product-config is required if --recovery-board-config is specified."
);
#[test]
fn test_recovery_board_config_success() {
let cmd = CreateCommand {
product_config_board_config_combo: None,
platform: None,
product_config: Some("product".to_string()),
recovery_product_config: Some("recovery_product".to_string()),
board_config: Some("board".to_string()),
recovery_board_config: Some("recovery_board".to_string()),
output_name: None,
output_version: None,
output_version_file: None,
tuf_keys: None,
ota_manifest_key: None,
developer_overrides: None,
stage: false,
out: None,
auth: AuthFlowChoice::Default,
zbi_only: false,
bib_set: vec![],
pib: vec![],
};
let result = SanitizedCreateCommand::try_from(cmd);
assert!(result.is_ok());
let sanitized = result.unwrap();
assert_eq!(sanitized.recovery_board_config, Some("recovery_board".to_string()));
}
```posix-terminal
```posix-terminal
```posix-terminal
N/A
{
"command": "ffx product-bundle create",
"options": [
{
"description": "the platform artifacts to use. See PLATFORM_ARTIFACT below.",
"option": "platform",
"shorthand": "",
"value_type": "string"
},
{
"description": "the product config to use. See ARTIFACT below.",
"option": "product-config",
N/A
N/A
N/A
{
"command": "ffx product-bundle create",
"options": [
{
"description": "the platform artifacts to use. See PLATFORM_ARTIFACT below.",
"option": "platform",
"shorthand": "",
"value_type": "string"
},
{
"description": "the product config to use. See ARTIFACT below.",
"option": "product-config",
N/A
N/A
N/A
{
"command": "ffx product-bundle create",
"options": [
{
"description": "the platform artifacts to use. See PLATFORM_ARTIFACT below.",
"option": "platform",
"shorthand": "",
"value_type": "string"
},
{
"description": "the product config to use. See ARTIFACT below.",
"option": "product-config",
N/A
```posix-terminal
N/A
{
"command": "ffx product-bundle create",
"options": [
{
"description": "the platform artifacts to use. See PLATFORM_ARTIFACT below.",
"option": "platform",
"shorthand": "",
"value_type": "string"
},
{
"description": "the product config to use. See ARTIFACT below.",
"option": "product-config",
N/A
N/A
N/A
{
"command": "ffx product-bundle create",
"options": [
{
"description": "the platform artifacts to use. See PLATFORM_ARTIFACT below.",
"option": "platform",
"shorthand": "",
"value_type": "string"
},
{
"description": "the product config to use. See ARTIFACT below.",
"option": "product-config",
N/A
N/A
N/A
{
"command": "ffx product-bundle create",
"options": [
{
"description": "the platform artifacts to use. See PLATFORM_ARTIFACT below.",
"option": "platform",
"shorthand": "",
"value_type": "string"
},
{
"description": "the product config to use. See ARTIFACT below.",
"option": "product-config",
N/A
N/A
N/A
{
"command": "ffx product-bundle create",
"options": [
{
"description": "the platform artifacts to use. See PLATFORM_ARTIFACT below.",
"option": "platform",
"shorthand": "",
"value_type": "string"
},
{
"description": "the product config to use. See ARTIFACT below.",
"option": "product-config",
N/A
N/A
N/A
{
"command": "ffx product-bundle create",
"options": [
{
"description": "the platform artifacts to use. See PLATFORM_ARTIFACT below.",
"option": "platform",
"shorthand": "",
"value_type": "string"
},
{
"description": "the product config to use. See ARTIFACT below.",
"option": "product-config",
N/A
N/A
N/A
{
"command": "ffx product-bundle create",
"options": [
{
"description": "the platform artifacts to use. See PLATFORM_ARTIFACT below.",
"option": "platform",
"shorthand": "",
"value_type": "string"
},
{
"description": "the product config to use. See ARTIFACT below.",
"option": "product-config",
N/A
N/A
N/A
{
"command": "ffx product-bundle create",
"options": [
{
"description": "the platform artifacts to use. See PLATFORM_ARTIFACT below.",
"option": "platform",
"shorthand": "",
"value_type": "string"
},
{
"description": "the product config to use. See ARTIFACT below.",
"option": "product-config",
N/A
N/A
N/A
{
"command": "ffx product-bundle create",
"options": [
{
"description": "the platform artifacts to use. See PLATFORM_ARTIFACT below.",
"option": "platform",
"shorthand": "",
"value_type": "string"
},
{
"description": "the product config to use. See ARTIFACT below.",
"option": "product-config",
N/A
N/A
N/A
{
"command": "ffx product-bundle create",
"options": [
{
"description": "the platform artifacts to use. See PLATFORM_ARTIFACT below.",
"option": "platform",
"shorthand": "",
"value_type": "string"
},
{
"description": "the product config to use. See ARTIFACT below.",
"option": "product-config",
N/A
```posix-terminal
N/A
{
"command": "ffx product-bundle create",
"options": [
{
"description": "the platform artifacts to use. See PLATFORM_ARTIFACT below.",
"option": "platform",
"shorthand": "",
"value_type": "string"
},
{
"description": "the product config to use. See ARTIFACT below.",
"option": "product-config",
N/A
N/A
N/A
{
"command": "ffx product-bundle create",
"options": [
{
"description": "the platform artifacts to use. See PLATFORM_ARTIFACT below.",
"option": "platform",
"shorthand": "",
"value_type": "string"
},
{
"description": "the product config to use. See ARTIFACT below.",
"option": "product-config",
N/A
N/A
N/A
{
"command": "ffx product-bundle create",
"options": [
{
"description": "the platform artifacts to use. See PLATFORM_ARTIFACT below.",
"option": "platform",
"shorthand": "",
"value_type": "string"
},
{
"description": "the product config to use. See ARTIFACT below.",
"option": "product-config",
N/A
N/A
N/A
{
"command": "ffx product-bundle create",
"options": [
{
"description": "the platform artifacts to use. See PLATFORM_ARTIFACT below.",
"option": "platform",
"shorthand": "",
"value_type": "string"
},
{
"description": "the product config to use. See ARTIFACT below.",
"option": "product-config",
N/A
N/A
N/A
{
"command": "ffx product-bundle create",
"options": [
{
"description": "the platform artifacts to use. See PLATFORM_ARTIFACT below.",
"option": "platform",
"shorthand": "",
"value_type": "string"
},
{
"description": "the product config to use. See ARTIFACT below.",
"option": "product-config",
N/A
N/A
N/A
{
"command": "ffx product-bundle create-old",
"options": [
{
"description": "product.board label. e.g. \"workstation_eng.x64\".",
"option": "product-name",
"shorthand": "",
"value_type": "string"
},
{
"description": "unique version of this product.board.",
"option": "product-version",
N/A
N/A
N/A
{
"command": "ffx product-bundle create-old",
"options": [
{
"description": "product.board label. e.g. \"workstation_eng.x64\".",
"option": "product-name",
"shorthand": "",
"value_type": "string"
},
{
"description": "unique version of this product.board.",
"option": "product-version",
N/A
N/A
N/A
{
"command": "ffx product-bundle create-old",
"options": [
{
"description": "product.board label. e.g. \"workstation_eng.x64\".",
"option": "product-name",
"shorthand": "",
"value_type": "string"
},
{
"description": "unique version of this product.board.",
"option": "product-version",
N/A
N/A
N/A
{
"command": "ffx product-bundle create-old",
"options": [
{
"description": "product.board label. e.g. \"workstation_eng.x64\".",
"option": "product-name",
"shorthand": "",
"value_type": "string"
},
{
"description": "unique version of this product.board.",
"option": "product-version",
N/A
N/A
N/A
{
"command": "ffx product-bundle create-old",
"options": [
{
"description": "product.board label. e.g. \"workstation_eng.x64\".",
"option": "product-name",
"shorthand": "",
"value_type": "string"
},
{
"description": "unique version of this product.board.",
"option": "product-version",
N/A
N/A
N/A
{
"command": "ffx product-bundle create-old",
"options": [
{
"description": "product.board label. e.g. \"workstation_eng.x64\".",
"option": "product-name",
"shorthand": "",
"value_type": "string"
},
{
"description": "unique version of this product.board.",
"option": "product-version",
N/A
N/A
N/A
{
"command": "ffx product-bundle create-old",
"options": [
{
"description": "product.board label. e.g. \"workstation_eng.x64\".",
"option": "product-name",
"shorthand": "",
"value_type": "string"
},
{
"description": "unique version of this product.board.",
"option": "product-version",
N/A
N/A
N/A
{
"command": "ffx product-bundle create-old",
"options": [
{
"description": "product.board label. e.g. \"workstation_eng.x64\".",
"option": "product-name",
"shorthand": "",
"value_type": "string"
},
{
"description": "unique version of this product.board.",
"option": "product-version",
N/A
N/A
N/A
{
"command": "ffx product-bundle create-old",
"options": [
{
"description": "product.board label. e.g. \"workstation_eng.x64\".",
"option": "product-name",
"shorthand": "",
"value_type": "string"
},
{
"description": "unique version of this product.board.",
"option": "product-version",
N/A
N/A
N/A
{
"command": "ffx product-bundle create-old",
"options": [
{
"description": "product.board label. e.g. \"workstation_eng.x64\".",
"option": "product-name",
"shorthand": "",
"value_type": "string"
},
{
"description": "unique version of this product.board.",
"option": "product-version",
N/A
N/A
N/A
{
"command": "ffx product-bundle create-old",
"options": [
{
"description": "product.board label. e.g. \"workstation_eng.x64\".",
"option": "product-name",
"shorthand": "",
"value_type": "string"
},
{
"description": "unique version of this product.board.",
"option": "product-version",
N/A
N/A
N/A
{
"command": "ffx product-bundle create-old",
"options": [
{
"description": "product.board label. e.g. \"workstation_eng.x64\".",
"option": "product-name",
"shorthand": "",
"value_type": "string"
},
{
"description": "unique version of this product.board.",
"option": "product-version",
N/A
N/A
N/A
{
"command": "ffx product-bundle create-old",
"options": [
{
"description": "product.board label. e.g. \"workstation_eng.x64\".",
"option": "product-name",
"shorthand": "",
"value_type": "string"
},
{
"description": "unique version of this product.board.",
"option": "product-version",
N/A
N/A
N/A
{
"command": "ffx product-bundle create-old",
"options": [
{
"description": "product.board label. e.g. \"workstation_eng.x64\".",
"option": "product-name",
"shorthand": "",
"value_type": "string"
},
{
"description": "unique version of this product.board.",
"option": "product-version",
N/A
N/A
N/A
{
"command": "ffx product-bundle create-old",
"options": [
{
"description": "product.board label. e.g. \"workstation_eng.x64\".",
"option": "product-name",
"shorthand": "",
"value_type": "string"
},
{
"description": "unique version of this product.board.",
"option": "product-version",
N/A
N/A
N/A
{
"command": "ffx product-bundle create-old",
"options": [
{
"description": "product.board label. e.g. \"workstation_eng.x64\".",
"option": "product-name",
"shorthand": "",
"value_type": "string"
},
{
"description": "unique version of this product.board.",
"option": "product-version",
N/A
N/A
N/A
{
"command": "ffx product-bundle download",
"options": [
{
"description": "get the data again, even if it's already present locally.",
"option": "force",
"shorthand": "",
"value_type": "bool"
},
{
"description": "use specific auth flow for oauth2 (see examples; default: pkce).",
"option": "auth",
N/A
N/A
N/A
{
"command": "ffx product-bundle download",
"options": [
{
"description": "get the data again, even if it's already present locally.",
"option": "force",
"shorthand": "",
"value_type": "bool"
},
{
"description": "use specific auth flow for oauth2 (see examples; default: pkce).",
"option": "auth",
N/A
N/A
N/A
{
"command": "ffx product-bundle download",
"options": [
{
"description": "get the data again, even if it's already present locally.",
"option": "force",
"shorthand": "",
"value_type": "bool"
},
{
"description": "use specific auth flow for oauth2 (see examples; default: pkce).",
"option": "auth",
N/A
N/A
N/A
{
"command": "ffx product-bundle download",
"options": [
{
"description": "get the data again, even if it's already present locally.",
"option": "force",
"shorthand": "",
"value_type": "bool"
},
{
"description": "use specific auth flow for oauth2 (see examples; default: pkce).",
"option": "auth",
N/A
N/A
N/A
{
"command": "ffx product-bundle download",
"options": [
{
"description": "get the data again, even if it's already present locally.",
"option": "force",
"shorthand": "",
"value_type": "bool"
},
{
"description": "use specific auth flow for oauth2 (see examples; default: pkce).",
"option": "auth",
N/A
N/A
N/A
{
"command": "ffx product-bundle download",
"options": [
{
"description": "get the data again, even if it's already present locally.",
"option": "force",
"shorthand": "",
"value_type": "bool"
},
{
"description": "use specific auth flow for oauth2 (see examples; default: pkce).",
"option": "auth",
N/A
N/A
N/A
{
"command": "ffx product-bundle get-artifacts",
"options": [
{
"description": "select what group of artifacts to list. One of flash, emu, update, bootloader",
"option": "artifacts-group",
"shorthand": "g",
"value_type": "string"
},
{
"description": "return relative path or not",
"option": "relative-path",
N/A
N/A
N/A
{
"command": "ffx product-bundle get-artifacts",
"options": [
{
"description": "select what group of artifacts to list. One of flash, emu, update, bootloader",
"option": "artifacts-group",
"shorthand": "g",
"value_type": "string"
},
{
"description": "return relative path or not",
"option": "relative-path",
N/A
N/A
N/A
{
"command": "ffx product-bundle get-artifacts",
"options": [
{
"description": "select what group of artifacts to list. One of flash, emu, update, bootloader",
"option": "artifacts-group",
"shorthand": "g",
"value_type": "string"
},
{
"description": "return relative path or not",
"option": "relative-path",
N/A
N/A
N/A
{
"command": "ffx product-bundle get-image-path",
"options": [
{
"description": "the slot where image will be located in. Valid slots are A,B,R.",
"option": "slot",
"shorthand": "",
"value_type": "string"
},
{
"description": "the type of image. Supported types are zbi, vbmeta, fvm, fxfs.fastboot, qemu-kernel, or dtbo.",
"option": "image-type",
N/A
N/A
N/A
{
"command": "ffx product-bundle get-image-path",
"options": [
{
"description": "the slot where image will be located in. Valid slots are A,B,R.",
"option": "slot",
"shorthand": "",
"value_type": "string"
},
{
"description": "the type of image. Supported types are zbi, vbmeta, fvm, fxfs.fastboot, qemu-kernel, or dtbo.",
"option": "image-type",
N/A
N/A
N/A
{
"command": "ffx product-bundle get-image-path",
"options": [
{
"description": "the slot where image will be located in. Valid slots are A,B,R.",
"option": "slot",
"shorthand": "",
"value_type": "string"
},
{
"description": "the type of image. Supported types are zbi, vbmeta, fvm, fxfs.fastboot, qemu-kernel, or dtbo.",
"option": "image-type",
N/A
N/A
N/A
{
"command": "ffx product-bundle get-image-path",
"options": [
{
"description": "the slot where image will be located in. Valid slots are A,B,R.",
"option": "slot",
"shorthand": "",
"value_type": "string"
},
{
"description": "the type of image. Supported types are zbi, vbmeta, fvm, fxfs.fastboot, qemu-kernel, or dtbo.",
"option": "image-type",
N/A
N/A
N/A
{
"command": "ffx product-bundle get-image-path",
"options": [
{
"description": "the slot where image will be located in. Valid slots are A,B,R.",
"option": "slot",
"shorthand": "",
"value_type": "string"
},
{
"description": "the type of image. Supported types are zbi, vbmeta, fvm, fxfs.fastboot, qemu-kernel, or dtbo.",
"option": "image-type",
N/A
N/A
N/A
{
"command": "ffx product-bundle get-repository",
"options": [],
"short": "Get the info of repository inside a Product Bundle."
}
N/A
N/A
N/A
{
"command": "ffx product-bundle get-version",
"options": [
{
"description": "when true, return version info for all included assembly artifacts.",
"option": "include-dependencies",
"shorthand": "",
"value_type": "bool"
}
],
"short": "Get the product version of a Product Bundle."
}
N/A
N/A
N/A
{
"command": "ffx product-bundle get-version",
"options": [
{
"description": "when true, return version info for all included assembly artifacts.",
"option": "include-dependencies",
"shorthand": "",
"value_type": "bool"
}
],
"short": "Get the product version of a Product Bundle."
}
N/A
N/A
N/A
{
"command": "ffx product-bundle lookup",
"options": [
{
"description": "use specific auth flow for oauth2 (see examples; default: pkce).",
"option": "auth",
"shorthand": "",
"value_type": "string"
},
{
"description": "where to look for product bundles manifest.",
"option": "base-url",
N/A
N/A
N/A
{
"command": "ffx product-bundle lookup",
"options": [
{
"description": "use specific auth flow for oauth2 (see examples; default: pkce).",
"option": "auth",
"shorthand": "",
"value_type": "string"
},
{
"description": "where to look for product bundles manifest.",
"option": "base-url",
N/A
N/A
N/A
{
"command": "ffx product-bundle lookup",
"options": [
{
"description": "use specific auth flow for oauth2 (see examples; default: pkce).",
"option": "auth",
"shorthand": "",
"value_type": "string"
},
{
"description": "where to look for product bundles manifest.",
"option": "base-url",
N/A
N/A
N/A
{
"command": "ffx product-bundle show",
"options": [
{
"description": "list the virtual devices linked to this product bundle.",
"option": "devices",
"shorthand": "",
"value_type": "bool"
},
{
"description": "print the details of a virtual device linked to this product bundle.",
"option": "device",
N/A
N/A
N/A
{
"command": "ffx product-bundle show",
"options": [
{
"description": "list the virtual devices linked to this product bundle.",
"option": "devices",
"shorthand": "",
"value_type": "bool"
},
{
"description": "print the details of a virtual device linked to this product bundle.",
"option": "device",
N/A
N/A
N/A
{
"command": "ffx product-bundle show",
"options": [
{
"description": "list the virtual devices linked to this product bundle.",
"option": "devices",
"shorthand": "",
"value_type": "bool"
},
{
"description": "print the details of a virtual device linked to this product bundle.",
"option": "device",
N/A
N/A
N/A
{
"command": "ffx profile",
"options": [],
"short": "Profile run-time information from various subsystems"
}
// Copyright 2023 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use anyhow::{Context, Result, bail};
#[fuchsia::test(logging = true)]
async fn test_ffx_profile_heapdump() {
let scratch_dir = tempdir().expect("Failed to create a temporary directory");
let emu = IsolatedEmulator::start("test-ffx-profile-heapdump").await.unwrap();
// Enable heapdump's experimental plugin.
emu.ffx(&["config", "set", "ffx_profile_heapdump", "true"]).await.unwrap();
info!("Starting heapdump's example component...");
let moniker = "/core/ffx-laboratory:heapdump-example";
let url = "fuchsia-pkg://fuchsia.com/heapdump-example#meta/heapdump-example.cm";
emu.ffx(&["component", "run", moniker, url]).await.unwrap();
// Wait for the example component to have completed its execution *and* the collector to have
// received all the eight stored snapshots it produces. Note that, after generating the eight
// stored snapshots, the test program enters pause() so that it stays alive until killed.
const NUM_EXPECTED_SNAPSHOTS: usize = 8;
let stored_snapshots =
wait_at_least_n_stored_snapshots(&emu, NUM_EXPECTED_SNAPSHOTS).await.unwrap();
// Verify that the snapshot names match those produced by the example program.
info!("Validating list of stored snapshots...");
for (i, snapshot) in stored_snapshots.iter().enumerate() {
assert_eq!(snapshot.snapshot_name, format!("fib-{}", i));
assert_eq!(snapshot.process_name, "heapdump-example.cm");
}
// Verify that a stored snapshot can be downloaded and parsed successfully.
info!("Validating the last stored snapshot...");
{
N/A
{
"command": "ffx profile cpu",
"options": [],
"short": "Query CPU-related information"
}
N/A
```posix-terminal
N/A
{
"command": "ffx profile cpu load",
"options": [
{
"description": "duration over which to measure and print the CPU load",
"option": "duration",
"shorthand": "d",
"value_type": "string"
}
],
"short": "Collect and print CPU usage data for the specified time frame, or instruct the metrics-logger component to record the CPU usage data to Inspect, Trace, and/or syslog."
}
#[fuchsia::test]
async fn test_invalid_args() {
let client = fdomain_local::local_client_empty();
let (proxy, _) = client.create_proxy_and_stream::<fstats::StatsMarker>();
assert!(measure(proxy, Duration::from_secs(0), &mut std::io::stdout()).await.is_err());
}
#[fuchsia::test]
async fn test_cpu_load_duration() {
let (duration_request_sender, mut duration_request_receiver) = mpsc::channel(1);
let client = fdomain_local::local_client_empty();
let proxy = fake_async_proxy(client, move |req| {
let mut duration_request_sender = duration_request_sender.clone();
async move {
match req {
fstats::StatsRequest::GetCpuLoad { duration, responder } => {
duration_request_sender.try_send(duration).unwrap();
let _ = responder.send(&[]); // returned values don't matter for this test
}
request => panic!("Unexpected request: {:?}", request),
}
}
});
let _ = measure(proxy, Duration::from_secs(1), &mut std::io::stdout()).await.unwrap();
match duration_request_receiver.next().await {
Some(duration_request) => {
assert_eq!(duration_request as u128, Duration::from_secs(1).as_nanos())
}
e => panic!("Failed to get duration_request: {:?}", e),
}
}
#[fuchsia::test]
async fn test_cpu_load_output() {
let client = fdomain_local::local_client_empty();
let proxy = fake_async_proxy(client, move |req| async move {
let data = vec![0.66f32, 1.56, 0.83, 0.71];
match req {
fstats::StatsRequest::GetCpuLoad { responder, .. } => {
let _ = responder.send(&data.clone());
}
request => panic!("Unexpected request: {:?}", request),
}
});
let mut writer = Vec::new();
let _ = measure(proxy, Duration::from_secs(1), &mut writer).await.unwrap();
let output = String::from_utf8(writer).expect("valid utf8 output");
assert_eq!(
output,
"\
CPU 0: 0.66%
CPU 1: 1.56%
CPU 2: 0.83%
CPU 3: 0.71%
Total: 3.76%
",
);
}
```posix-terminal
N/A
{
"command": "ffx profile cpu load",
"options": [
{
"description": "duration over which to measure and print the CPU load",
"option": "duration",
"shorthand": "d",
"value_type": "string"
}
],
"short": "Collect and print CPU usage data for the specified time frame, or instruct the metrics-logger component to record the CPU usage data to Inspect, Trace, and/or syslog."
}
N/A
```posix-terminal
N/A
{
"command": "ffx profile cpu load start",
"options": [
{
"description": "interval for logging the CPU load",
"option": "interval",
"shorthand": "s",
"value_type": "string"
},
{
"description": "toggle for logging CPU loads to syslog",
"option": "output-to-syslog",
N/A
N/A
N/A
{
"command": "ffx profile cpu load start",
"options": [
{
"description": "interval for logging the CPU load",
"option": "interval",
"shorthand": "s",
"value_type": "string"
},
{
"description": "toggle for logging CPU loads to syslog",
"option": "output-to-syslog",
N/A
N/A
N/A
{
"command": "ffx profile cpu load start",
"options": [
{
"description": "interval for logging the CPU load",
"option": "interval",
"shorthand": "s",
"value_type": "string"
},
{
"description": "toggle for logging CPU loads to syslog",
"option": "output-to-syslog",
N/A
N/A
N/A
{
"command": "ffx profile cpu load start",
"options": [
{
"description": "interval for logging the CPU load",
"option": "interval",
"shorthand": "s",
"value_type": "string"
},
{
"description": "toggle for logging CPU loads to syslog",
"option": "output-to-syslog",
N/A
N/A
N/A
{
"command": "ffx profile cpu load stop",
"options": [],
"short": "Stop logging on the target"
}
N/A
N/A
N/A
{
"command": "ffx profile gpu",
"options": [],
"short": "Access GPU usage information"
}
N/A
```posix-terminal
N/A
{
"command": "ffx profile gpu usage",
"options": [],
"short": "Controls the metrics-logger component to log gpu usage. Logged samples will be available in syslog, via iquery under core/metrics-logger and via tracing in the `metrics_logger` category."
}
#[test]
fn test_parse_duration() {
assert_eq!(parse_duration("1h"), Ok(Duration::from_secs(3600)));
assert_eq!(parse_duration("3m"), Ok(Duration::from_secs(180)));
assert_eq!(parse_duration("10s"), Ok(Duration::from_secs(10)));
assert_eq!(parse_duration("100ms"), Ok(Duration::from_millis(100)));
}
#[test]
fn test_parse_duration_err() {
assert!(parse_duration("100").is_err());
assert!(parse_duration("10 0").is_err());
assert!(parse_duration("foobar").is_err());
}
#[fuchsia::test]
async fn test_request_dispatch_start_logging() {
// Start logging: interval=1s, duration=4s
let args = args_mod::StartCommand {
interval: ONE_SEC,
duration: Some(4 * ONE_SEC),
output_to_syslog: false,
};
let (mut sender, mut receiver) = mpsc::channel(1);
let client = fdomain_local::local_client_empty();
let proxy = fake_proxy(client, move |req| match req {
fmetrics::RecorderRequest::StartLogging {
client_id,
metrics,
duration_ms,
output_samples_to_syslog,
output_stats_to_syslog,
responder,
} => {
assert_eq!(String::from("ffx_gpu"), client_id);
assert_eq!(metrics.len(), 1);
assert_eq!(metrics[0], Metric::GpuUsage(GpuUsage { interval_ms: 1000 }),);
assert_eq!(output_samples_to_syslog, false);
assert_eq!(output_stats_to_syslog, false);
assert_eq!(duration_ms, 4000);
responder.send(Ok(())).unwrap();
sender.try_send(()).unwrap();
}
_ => panic!("Expected RecorderRequest::StartLogging; got {:?}", req),
});
```posix-terminal
N/A
{
"command": "ffx profile gpu usage start",
"options": [
{
"description": "interval for polling the GPU driver",
"option": "interval",
"shorthand": "s",
"value_type": "string"
},
{
"description": "toggle for logging samples to syslog",
"option": "output-to-syslog",
N/A
N/A
N/A
{
"command": "ffx profile gpu usage start",
"options": [
{
"description": "interval for polling the GPU driver",
"option": "interval",
"shorthand": "s",
"value_type": "string"
},
{
"description": "toggle for logging samples to syslog",
"option": "output-to-syslog",
N/A
N/A
N/A
{
"command": "ffx profile gpu usage start",
"options": [
{
"description": "interval for polling the GPU driver",
"option": "interval",
"shorthand": "s",
"value_type": "string"
},
{
"description": "toggle for logging samples to syslog",
"option": "output-to-syslog",
N/A
N/A
N/A
{
"command": "ffx profile gpu usage start",
"options": [
{
"description": "interval for polling the GPU driver",
"option": "interval",
"shorthand": "s",
"value_type": "string"
},
{
"description": "toggle for logging samples to syslog",
"option": "output-to-syslog",
N/A
N/A
N/A
{
"command": "ffx profile gpu usage stop",
"options": [],
"short": "Stop logging on the target"
}
N/A
N/A
N/A
{
"command": "ffx profile heapdump",
"options": [],
"short": "Profile and dump heap memory usage"
}
// Copyright 2023 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use anyhow::{Context, Result, bail};
#[fuchsia::test(logging = true)]
async fn test_ffx_profile_heapdump() {
let scratch_dir = tempdir().expect("Failed to create a temporary directory");
let emu = IsolatedEmulator::start("test-ffx-profile-heapdump").await.unwrap();
// Enable heapdump's experimental plugin.
emu.ffx(&["config", "set", "ffx_profile_heapdump", "true"]).await.unwrap();
info!("Starting heapdump's example component...");
let moniker = "/core/ffx-laboratory:heapdump-example";
let url = "fuchsia-pkg://fuchsia.com/heapdump-example#meta/heapdump-example.cm";
emu.ffx(&["component", "run", moniker, url]).await.unwrap();
// Wait for the example component to have completed its execution *and* the collector to have
// received all the eight stored snapshots it produces. Note that, after generating the eight
// stored snapshots, the test program enters pause() so that it stays alive until killed.
const NUM_EXPECTED_SNAPSHOTS: usize = 8;
let stored_snapshots =
wait_at_least_n_stored_snapshots(&emu, NUM_EXPECTED_SNAPSHOTS).await.unwrap();
// Verify that the snapshot names match those produced by the example program.
info!("Validating list of stored snapshots...");
for (i, snapshot) in stored_snapshots.iter().enumerate() {
assert_eq!(snapshot.snapshot_name, format!("fib-{}", i));
assert_eq!(snapshot.process_name, "heapdump-example.cm");
}
// Verify that a stored snapshot can be downloaded and parsed successfully.
info!("Validating the last stored snapshot...");
{
N/A
N/A
{
"command": "ffx profile heapdump download",
"options": [
{
"description": "moniker of the collector to be queried (default: autodetect)",
"option": "collector",
"shorthand": "",
"value_type": "string"
},
{
"description": "snapshot ID to be downloaded",
"option": "snapshot-id",
// Copyright 2023 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use anyhow::{Context, Result, bail};
#[fuchsia::test(logging = true)]
async fn test_ffx_profile_heapdump() {
let scratch_dir = tempdir().expect("Failed to create a temporary directory");
let emu = IsolatedEmulator::start("test-ffx-profile-heapdump").await.unwrap();
// Enable heapdump's experimental plugin.
emu.ffx(&["config", "set", "ffx_profile_heapdump", "true"]).await.unwrap();
info!("Starting heapdump's example component...");
let moniker = "/core/ffx-laboratory:heapdump-example";
let url = "fuchsia-pkg://fuchsia.com/heapdump-example#meta/heapdump-example.cm";
emu.ffx(&["component", "run", moniker, url]).await.unwrap();
// Wait for the example component to have completed its execution *and* the collector to have
// received all the eight stored snapshots it produces. Note that, after generating the eight
// stored snapshots, the test program enters pause() so that it stays alive until killed.
const NUM_EXPECTED_SNAPSHOTS: usize = 8;
let stored_snapshots =
wait_at_least_n_stored_snapshots(&emu, NUM_EXPECTED_SNAPSHOTS).await.unwrap();
// Verify that the snapshot names match those produced by the example program.
info!("Validating list of stored snapshots...");
for (i, snapshot) in stored_snapshots.iter().enumerate() {
assert_eq!(snapshot.snapshot_name, format!("fib-{}", i));
assert_eq!(snapshot.process_name, "heapdump-example.cm");
}
// Verify that a stored snapshot can be downloaded and parsed successfully.
info!("Validating the last stored snapshot...");
{
N/A
N/A
{
"command": "ffx profile heapdump download",
"options": [
{
"description": "moniker of the collector to be queried (default: autodetect)",
"option": "collector",
"shorthand": "",
"value_type": "string"
},
{
"description": "snapshot ID to be downloaded",
"option": "snapshot-id",
N/A
N/A
N/A
{
"command": "ffx profile heapdump download",
"options": [
{
"description": "moniker of the collector to be queried (default: autodetect)",
"option": "collector",
"shorthand": "",
"value_type": "string"
},
{
"description": "snapshot ID to be downloaded",
"option": "snapshot-id",
// Copyright 2023 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use anyhow::{Context, Result, bail};
#[fuchsia::test(logging = true)]
async fn test_ffx_profile_heapdump() {
let scratch_dir = tempdir().expect("Failed to create a temporary directory");
let emu = IsolatedEmulator::start("test-ffx-profile-heapdump").await.unwrap();
// Enable heapdump's experimental plugin.
emu.ffx(&["config", "set", "ffx_profile_heapdump", "true"]).await.unwrap();
info!("Starting heapdump's example component...");
let moniker = "/core/ffx-laboratory:heapdump-example";
let url = "fuchsia-pkg://fuchsia.com/heapdump-example#meta/heapdump-example.cm";
emu.ffx(&["component", "run", moniker, url]).await.unwrap();
// Wait for the example component to have completed its execution *and* the collector to have
// received all the eight stored snapshots it produces. Note that, after generating the eight
// stored snapshots, the test program enters pause() so that it stays alive until killed.
const NUM_EXPECTED_SNAPSHOTS: usize = 8;
let stored_snapshots =
wait_at_least_n_stored_snapshots(&emu, NUM_EXPECTED_SNAPSHOTS).await.unwrap();
// Verify that the snapshot names match those produced by the example program.
info!("Validating list of stored snapshots...");
for (i, snapshot) in stored_snapshots.iter().enumerate() {
assert_eq!(snapshot.snapshot_name, format!("fib-{}", i));
assert_eq!(snapshot.process_name, "heapdump-example.cm");
}
// Verify that a stored snapshot can be downloaded and parsed successfully.
info!("Validating the last stored snapshot...");
{
N/A
N/A
{
"command": "ffx profile heapdump download",
"options": [
{
"description": "moniker of the collector to be queried (default: autodetect)",
"option": "collector",
"shorthand": "",
"value_type": "string"
},
{
"description": "snapshot ID to be downloaded",
"option": "snapshot-id",
// Copyright 2023 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use anyhow::{Context, Result, bail};
#[fuchsia::test(logging = true)]
async fn test_ffx_profile_heapdump() {
let scratch_dir = tempdir().expect("Failed to create a temporary directory");
let emu = IsolatedEmulator::start("test-ffx-profile-heapdump").await.unwrap();
// Enable heapdump's experimental plugin.
emu.ffx(&["config", "set", "ffx_profile_heapdump", "true"]).await.unwrap();
info!("Starting heapdump's example component...");
let moniker = "/core/ffx-laboratory:heapdump-example";
let url = "fuchsia-pkg://fuchsia.com/heapdump-example#meta/heapdump-example.cm";
emu.ffx(&["component", "run", moniker, url]).await.unwrap();
// Wait for the example component to have completed its execution *and* the collector to have
// received all the eight stored snapshots it produces. Note that, after generating the eight
// stored snapshots, the test program enters pause() so that it stays alive until killed.
const NUM_EXPECTED_SNAPSHOTS: usize = 8;
let stored_snapshots =
wait_at_least_n_stored_snapshots(&emu, NUM_EXPECTED_SNAPSHOTS).await.unwrap();
// Verify that the snapshot names match those produced by the example program.
info!("Validating list of stored snapshots...");
for (i, snapshot) in stored_snapshots.iter().enumerate() {
assert_eq!(snapshot.snapshot_name, format!("fib-{}", i));
assert_eq!(snapshot.process_name, "heapdump-example.cm");
}
// Verify that a stored snapshot can be downloaded and parsed successfully.
info!("Validating the last stored snapshot...");
{
N/A
N/A
{
"command": "ffx profile heapdump download",
"options": [
{
"description": "moniker of the collector to be queried (default: autodetect)",
"option": "collector",
"shorthand": "",
"value_type": "string"
},
{
"description": "snapshot ID to be downloaded",
"option": "snapshot-id",
N/A
N/A
N/A
{
"command": "ffx profile heapdump download",
"options": [
{
"description": "moniker of the collector to be queried (default: autodetect)",
"option": "collector",
"shorthand": "",
"value_type": "string"
},
{
"description": "snapshot ID to be downloaded",
"option": "snapshot-id",
N/A
N/A
N/A
{
"command": "ffx profile heapdump list",
"options": [
{
"description": "moniker of the collector to be queried (default: autodetect)",
"option": "collector",
"shorthand": "",
"value_type": "string"
},
{
"description": "select process by name",
"option": "by-name",
N/A
N/A
N/A
{
"command": "ffx profile heapdump list",
"options": [
{
"description": "moniker of the collector to be queried (default: autodetect)",
"option": "collector",
"shorthand": "",
"value_type": "string"
},
{
"description": "select process by name",
"option": "by-name",
N/A
N/A
N/A
{
"command": "ffx profile heapdump list",
"options": [
{
"description": "moniker of the collector to be queried (default: autodetect)",
"option": "collector",
"shorthand": "",
"value_type": "string"
},
{
"description": "select process by name",
"option": "by-name",
N/A
N/A
N/A
{
"command": "ffx profile heapdump list",
"options": [
{
"description": "moniker of the collector to be queried (default: autodetect)",
"option": "collector",
"shorthand": "",
"value_type": "string"
},
{
"description": "select process by name",
"option": "by-name",
N/A
N/A
N/A
{
"command": "ffx profile heapdump snapshot",
"options": [
{
"description": "moniker of the collector to be queried (default: autodetect)",
"option": "collector",
"shorthand": "",
"value_type": "string"
},
{
"description": "select process by name",
"option": "by-name",
// Copyright 2023 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use anyhow::{Context, Result, bail};
#[fuchsia::test(logging = true)]
async fn test_ffx_profile_heapdump() {
let scratch_dir = tempdir().expect("Failed to create a temporary directory");
let emu = IsolatedEmulator::start("test-ffx-profile-heapdump").await.unwrap();
// Enable heapdump's experimental plugin.
emu.ffx(&["config", "set", "ffx_profile_heapdump", "true"]).await.unwrap();
info!("Starting heapdump's example component...");
let moniker = "/core/ffx-laboratory:heapdump-example";
let url = "fuchsia-pkg://fuchsia.com/heapdump-example#meta/heapdump-example.cm";
emu.ffx(&["component", "run", moniker, url]).await.unwrap();
// Wait for the example component to have completed its execution *and* the collector to have
// received all the eight stored snapshots it produces. Note that, after generating the eight
// stored snapshots, the test program enters pause() so that it stays alive until killed.
const NUM_EXPECTED_SNAPSHOTS: usize = 8;
let stored_snapshots =
wait_at_least_n_stored_snapshots(&emu, NUM_EXPECTED_SNAPSHOTS).await.unwrap();
// Verify that the snapshot names match those produced by the example program.
info!("Validating list of stored snapshots...");
for (i, snapshot) in stored_snapshots.iter().enumerate() {
assert_eq!(snapshot.snapshot_name, format!("fib-{}", i));
assert_eq!(snapshot.process_name, "heapdump-example.cm");
}
// Verify that a stored snapshot can be downloaded and parsed successfully.
info!("Validating the last stored snapshot...");
{
N/A
N/A
{
"command": "ffx profile heapdump snapshot",
"options": [
{
"description": "moniker of the collector to be queried (default: autodetect)",
"option": "collector",
"shorthand": "",
"value_type": "string"
},
{
"description": "select process by name",
"option": "by-name",
N/A
N/A
N/A
{
"command": "ffx profile heapdump snapshot",
"options": [
{
"description": "moniker of the collector to be queried (default: autodetect)",
"option": "collector",
"shorthand": "",
"value_type": "string"
},
{
"description": "select process by name",
"option": "by-name",
// Copyright 2023 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use anyhow::{Context, Result, bail};
#[fuchsia::test(logging = true)]
async fn test_ffx_profile_heapdump() {
let scratch_dir = tempdir().expect("Failed to create a temporary directory");
let emu = IsolatedEmulator::start("test-ffx-profile-heapdump").await.unwrap();
// Enable heapdump's experimental plugin.
emu.ffx(&["config", "set", "ffx_profile_heapdump", "true"]).await.unwrap();
info!("Starting heapdump's example component...");
let moniker = "/core/ffx-laboratory:heapdump-example";
let url = "fuchsia-pkg://fuchsia.com/heapdump-example#meta/heapdump-example.cm";
emu.ffx(&["component", "run", moniker, url]).await.unwrap();
// Wait for the example component to have completed its execution *and* the collector to have
// received all the eight stored snapshots it produces. Note that, after generating the eight
// stored snapshots, the test program enters pause() so that it stays alive until killed.
const NUM_EXPECTED_SNAPSHOTS: usize = 8;
let stored_snapshots =
wait_at_least_n_stored_snapshots(&emu, NUM_EXPECTED_SNAPSHOTS).await.unwrap();
// Verify that the snapshot names match those produced by the example program.
info!("Validating list of stored snapshots...");
for (i, snapshot) in stored_snapshots.iter().enumerate() {
assert_eq!(snapshot.snapshot_name, format!("fib-{}", i));
assert_eq!(snapshot.process_name, "heapdump-example.cm");
}
// Verify that a stored snapshot can be downloaded and parsed successfully.
info!("Validating the last stored snapshot...");
{
N/A
N/A
{
"command": "ffx profile heapdump snapshot",
"options": [
{
"description": "moniker of the collector to be queried (default: autodetect)",
"option": "collector",
"shorthand": "",
"value_type": "string"
},
{
"description": "select process by name",
"option": "by-name",
N/A
N/A
N/A
{
"command": "ffx profile heapdump snapshot",
"options": [
{
"description": "moniker of the collector to be queried (default: autodetect)",
"option": "collector",
"shorthand": "",
"value_type": "string"
},
{
"description": "select process by name",
"option": "by-name",
N/A
N/A
N/A
{
"command": "ffx profile heapdump snapshot",
"options": [
{
"description": "moniker of the collector to be queried (default: autodetect)",
"option": "collector",
"shorthand": "",
"value_type": "string"
},
{
"description": "select process by name",
"option": "by-name",
// Copyright 2023 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use anyhow::{Context, Result, bail};
#[fuchsia::test(logging = true)]
async fn test_ffx_profile_heapdump() {
let scratch_dir = tempdir().expect("Failed to create a temporary directory");
let emu = IsolatedEmulator::start("test-ffx-profile-heapdump").await.unwrap();
// Enable heapdump's experimental plugin.
emu.ffx(&["config", "set", "ffx_profile_heapdump", "true"]).await.unwrap();
info!("Starting heapdump's example component...");
let moniker = "/core/ffx-laboratory:heapdump-example";
let url = "fuchsia-pkg://fuchsia.com/heapdump-example#meta/heapdump-example.cm";
emu.ffx(&["component", "run", moniker, url]).await.unwrap();
// Wait for the example component to have completed its execution *and* the collector to have
// received all the eight stored snapshots it produces. Note that, after generating the eight
// stored snapshots, the test program enters pause() so that it stays alive until killed.
const NUM_EXPECTED_SNAPSHOTS: usize = 8;
let stored_snapshots =
wait_at_least_n_stored_snapshots(&emu, NUM_EXPECTED_SNAPSHOTS).await.unwrap();
// Verify that the snapshot names match those produced by the example program.
info!("Validating list of stored snapshots...");
for (i, snapshot) in stored_snapshots.iter().enumerate() {
assert_eq!(snapshot.snapshot_name, format!("fib-{}", i));
assert_eq!(snapshot.process_name, "heapdump-example.cm");
}
// Verify that a stored snapshot can be downloaded and parsed successfully.
info!("Validating the last stored snapshot...");
{
N/A
N/A
{
"command": "ffx profile heapdump snapshot",
"options": [
{
"description": "moniker of the collector to be queried (default: autodetect)",
"option": "collector",
"shorthand": "",
"value_type": "string"
},
{
"description": "select process by name",
"option": "by-name",
// Copyright 2023 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use anyhow::{Context, Result, bail};
#[fuchsia::test(logging = true)]
async fn test_ffx_profile_heapdump() {
let scratch_dir = tempdir().expect("Failed to create a temporary directory");
let emu = IsolatedEmulator::start("test-ffx-profile-heapdump").await.unwrap();
// Enable heapdump's experimental plugin.
emu.ffx(&["config", "set", "ffx_profile_heapdump", "true"]).await.unwrap();
info!("Starting heapdump's example component...");
let moniker = "/core/ffx-laboratory:heapdump-example";
let url = "fuchsia-pkg://fuchsia.com/heapdump-example#meta/heapdump-example.cm";
emu.ffx(&["component", "run", moniker, url]).await.unwrap();
// Wait for the example component to have completed its execution *and* the collector to have
// received all the eight stored snapshots it produces. Note that, after generating the eight
// stored snapshots, the test program enters pause() so that it stays alive until killed.
const NUM_EXPECTED_SNAPSHOTS: usize = 8;
let stored_snapshots =
wait_at_least_n_stored_snapshots(&emu, NUM_EXPECTED_SNAPSHOTS).await.unwrap();
// Verify that the snapshot names match those produced by the example program.
info!("Validating list of stored snapshots...");
for (i, snapshot) in stored_snapshots.iter().enumerate() {
assert_eq!(snapshot.snapshot_name, format!("fib-{}", i));
assert_eq!(snapshot.process_name, "heapdump-example.cm");
}
// Verify that a stored snapshot can be downloaded and parsed successfully.
info!("Validating the last stored snapshot...");
{
N/A
N/A
{
"command": "ffx profile heapdump snapshot",
"options": [
{
"description": "moniker of the collector to be queried (default: autodetect)",
"option": "collector",
"shorthand": "",
"value_type": "string"
},
{
"description": "select process by name",
"option": "by-name",
// Copyright 2023 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use anyhow::{Context, Result, bail};
#[fuchsia::test(logging = true)]
async fn test_ffx_profile_heapdump() {
let scratch_dir = tempdir().expect("Failed to create a temporary directory");
let emu = IsolatedEmulator::start("test-ffx-profile-heapdump").await.unwrap();
// Enable heapdump's experimental plugin.
emu.ffx(&["config", "set", "ffx_profile_heapdump", "true"]).await.unwrap();
info!("Starting heapdump's example component...");
let moniker = "/core/ffx-laboratory:heapdump-example";
let url = "fuchsia-pkg://fuchsia.com/heapdump-example#meta/heapdump-example.cm";
emu.ffx(&["component", "run", moniker, url]).await.unwrap();
// Wait for the example component to have completed its execution *and* the collector to have
// received all the eight stored snapshots it produces. Note that, after generating the eight
// stored snapshots, the test program enters pause() so that it stays alive until killed.
const NUM_EXPECTED_SNAPSHOTS: usize = 8;
let stored_snapshots =
wait_at_least_n_stored_snapshots(&emu, NUM_EXPECTED_SNAPSHOTS).await.unwrap();
// Verify that the snapshot names match those produced by the example program.
info!("Validating list of stored snapshots...");
for (i, snapshot) in stored_snapshots.iter().enumerate() {
assert_eq!(snapshot.snapshot_name, format!("fib-{}", i));
assert_eq!(snapshot.process_name, "heapdump-example.cm");
}
// Verify that a stored snapshot can be downloaded and parsed successfully.
info!("Validating the last stored snapshot...");
{
N/A
N/A
{
"command": "ffx profile heapdump snapshot",
"options": [
{
"description": "moniker of the collector to be queried (default: autodetect)",
"option": "collector",
"shorthand": "",
"value_type": "string"
},
{
"description": "select process by name",
"option": "by-name",
N/A
N/A
N/A
{
"command": "ffx profile memory",
"options": [
{
"description": "outputs the json returned by memory_monitor. For debug purposes only, no guarantee is made on the stability of the output of this command.",
"option": "debug-json",
"shorthand": "",
"value_type": "bool"
},
{
"description": "filters by process koids. Repeatable flag.",
"option": "process-koids",
#[fuchsia::test]
async fn get_raw_data_test() {
let client = fdomain_local::local_client_empty();
let collector = create_fake_collector_proxy(client);
let raw_data = get_raw_data(&collector).await.expect("failed to get raw data");
assert_eq!(raw_data, *DATA_WRITTEN_BY_MEMORY_MONITOR);
}
#[fuchsia::test]
async fn get_output_test() {
let client = fdomain_local::local_client_empty();
let collector = create_fake_collector_proxy(client);
let output = get_output(&collector).await.expect("failed to get output");
assert_eq!(output, *EXPECTED_OUTPUT);
}
N/A
N/A
{
"command": "ffx profile memory",
"options": [
{
"description": "outputs the json returned by memory_monitor. For debug purposes only, no guarantee is made on the stability of the output of this command.",
"option": "debug-json",
"shorthand": "",
"value_type": "bool"
},
{
"description": "filters by process koids. Repeatable flag.",
"option": "process-koids",
N/A
N/A
N/A
{
"command": "ffx profile memory",
"options": [
{
"description": "outputs the json returned by memory_monitor. For debug purposes only, no guarantee is made on the stability of the output of this command.",
"option": "debug-json",
"shorthand": "",
"value_type": "bool"
},
{
"description": "filters by process koids. Repeatable flag.",
"option": "process-koids",
N/A
N/A
N/A
{
"command": "ffx profile memory",
"options": [
{
"description": "outputs the json returned by memory_monitor. For debug purposes only, no guarantee is made on the stability of the output of this command.",
"option": "debug-json",
"shorthand": "",
"value_type": "bool"
},
{
"description": "filters by process koids. Repeatable flag.",
"option": "process-koids",
N/A
N/A
N/A
{
"command": "ffx profile memory",
"options": [
{
"description": "outputs the json returned by memory_monitor. For debug purposes only, no guarantee is made on the stability of the output of this command.",
"option": "debug-json",
"shorthand": "",
"value_type": "bool"
},
{
"description": "filters by process koids. Repeatable flag.",
"option": "process-koids",
N/A
N/A
N/A
{
"command": "ffx profile memory",
"options": [
{
"description": "outputs the json returned by memory_monitor. For debug purposes only, no guarantee is made on the stability of the output of this command.",
"option": "debug-json",
"shorthand": "",
"value_type": "bool"
},
{
"description": "filters by process koids. Repeatable flag.",
"option": "process-koids",
N/A
N/A
N/A
{
"command": "ffx profile memory",
"options": [
{
"description": "outputs the json returned by memory_monitor. For debug purposes only, no guarantee is made on the stability of the output of this command.",
"option": "debug-json",
"shorthand": "",
"value_type": "bool"
},
{
"description": "filters by process koids. Repeatable flag.",
"option": "process-koids",
N/A
N/A
N/A
{
"command": "ffx profile memory",
"options": [
{
"description": "outputs the json returned by memory_monitor. For debug purposes only, no guarantee is made on the stability of the output of this command.",
"option": "debug-json",
"shorthand": "",
"value_type": "bool"
},
{
"description": "filters by process koids. Repeatable flag.",
"option": "process-koids",
N/A
N/A
N/A
{
"command": "ffx profile memory",
"options": [
{
"description": "outputs the json returned by memory_monitor. For debug purposes only, no guarantee is made on the stability of the output of this command.",
"option": "debug-json",
"shorthand": "",
"value_type": "bool"
},
{
"description": "filters by process koids. Repeatable flag.",
"option": "process-koids",
N/A
N/A
N/A
{
"command": "ffx profile memory",
"options": [
{
"description": "outputs the json returned by memory_monitor. For debug purposes only, no guarantee is made on the stability of the output of this command.",
"option": "debug-json",
"shorthand": "",
"value_type": "bool"
},
{
"description": "filters by process koids. Repeatable flag.",
"option": "process-koids",
N/A
N/A
N/A
{
"command": "ffx profile memory",
"options": [
{
"description": "outputs the json returned by memory_monitor. For debug purposes only, no guarantee is made on the stability of the output of this command.",
"option": "debug-json",
"shorthand": "",
"value_type": "bool"
},
{
"description": "filters by process koids. Repeatable flag.",
"option": "process-koids",
N/A
N/A
N/A
{
"command": "ffx profile memory components",
"options": [
{
"description": "loads the unprocessed memory information as json from stdin.",
"option": "stdin-input",
"shorthand": "",
"value_type": "bool"
},
{
"description": "outputs the unprocessed memory information from the device as json.",
"option": "debug-json",
#[test]
fn test_gather_resources() {
// Create a fake snapshot with 4 principals:
// root (1)
// - runner (2)
// - component 4 (4)
// - component 4 (3)
//
// and the following job/process/vmo hierarchy:
// root_job (1000)
// * root_process (1001)
// . root_vmo (1002)
// . shared_vmo (1003)
// - runner_job (1004)
// * runner_process (1005)
// . runner_vmo (1006)
// . component_vmo (1007)
// . component_vmo2 (1012)
// . component_vmo3 (1013)
// - component_2_job (1008)
// * 2_process (1009)
// . 2_vmo (1010)
// . shared_vmo (1003)
// And an additional parent VMO for 2_vmo, 2_vmo_parent (1011).
let snapshot = fplugin::Snapshot {
attributions: Some(vec![
fplugin::Attribution {
source: Some(fplugin::PrincipalIdentifier { id: 1 }),
#[test]
fn test_reshare_resources() {
// Create a fake snapshot with 3 principals:
// root (0)
// - component 1 (1)
// - component 3 (2)
//
// and the following job/process/vmo hierarchy:
// root_job (1000)
// - component_job (1001)
// * component_process (1002)
// . component_vmo (1003)
//
// In this scenario, component 1 reattributes component_job to component 3 entirely.
let snapshot = fplugin::Snapshot {
attributions: Some(vec![
fplugin::Attribution {
source: Some(fplugin::PrincipalIdentifier { id: 1 }),
subject: Some(fplugin::PrincipalIdentifier { id: 1 }),
resources: Some(vec![fplugin::ResourceReference::KernelObject(1000)]),
..Default::default()
},
fplugin::Attribution {
source: Some(fplugin::PrincipalIdentifier { id: 1 }),
subject: Some(fplugin::PrincipalIdentifier { id: 2 }),
resources: Some(vec![fplugin::ResourceReference::KernelObject(1001)]),
..Default::default()
},
N/A
N/A
{
"command": "ffx profile memory components",
"options": [
{
"description": "loads the unprocessed memory information as json from stdin.",
"option": "stdin-input",
"shorthand": "",
"value_type": "bool"
},
{
"description": "outputs the unprocessed memory information from the device as json.",
"option": "debug-json",
N/A
N/A
N/A
{
"command": "ffx profile memory components",
"options": [
{
"description": "loads the unprocessed memory information as json from stdin.",
"option": "stdin-input",
"shorthand": "",
"value_type": "bool"
},
{
"description": "outputs the unprocessed memory information from the device as json.",
"option": "debug-json",
N/A
N/A
N/A
{
"command": "ffx profile memory components",
"options": [
{
"description": "loads the unprocessed memory information as json from stdin.",
"option": "stdin-input",
"shorthand": "",
"value_type": "bool"
},
{
"description": "outputs the unprocessed memory information from the device as json.",
"option": "debug-json",
N/A
N/A
N/A
{
"command": "ffx profile memory components",
"options": [
{
"description": "loads the unprocessed memory information as json from stdin.",
"option": "stdin-input",
"shorthand": "",
"value_type": "bool"
},
{
"description": "outputs the unprocessed memory information from the device as json.",
"option": "debug-json",
N/A
N/A
N/A
{
"command": "ffx profile memory components",
"options": [
{
"description": "loads the unprocessed memory information as json from stdin.",
"option": "stdin-input",
"shorthand": "",
"value_type": "bool"
},
{
"description": "outputs the unprocessed memory information from the device as json.",
"option": "debug-json",
N/A
N/A
N/A
{
"command": "ffx profile memory components",
"options": [
{
"description": "loads the unprocessed memory information as json from stdin.",
"option": "stdin-input",
"shorthand": "",
"value_type": "bool"
},
{
"description": "outputs the unprocessed memory information from the device as json.",
"option": "debug-json",
N/A
N/A
N/A
{
"command": "ffx profile memory components",
"options": [
{
"description": "loads the unprocessed memory information as json from stdin.",
"option": "stdin-input",
"shorthand": "",
"value_type": "bool"
},
{
"description": "outputs the unprocessed memory information from the device as json.",
"option": "debug-json",
N/A
N/A
N/A
{
"command": "ffx profile memory components",
"options": [
{
"description": "loads the unprocessed memory information as json from stdin.",
"option": "stdin-input",
"shorthand": "",
"value_type": "bool"
},
{
"description": "outputs the unprocessed memory information from the device as json.",
"option": "debug-json",
N/A
N/A
N/A
{
"command": "ffx profile memory components",
"options": [
{
"description": "loads the unprocessed memory information as json from stdin.",
"option": "stdin-input",
"shorthand": "",
"value_type": "bool"
},
{
"description": "outputs the unprocessed memory information from the device as json.",
"option": "debug-json",
N/A
N/A
N/A
{
"command": "ffx profile memory signal",
"options": [],
"short": "Signals userspace clients with specified memory pressure level. Clients can use this command to test their response to memory pressure. Does not affect the real memory pressure level on the system, or trigger any kernel reclamation tasks."
}
#[test]
fn can_parse_canonical_levels() {
assert_eq!(parse_memory_pressure_level("NORMAL"), Ok(Level::Normal));
assert_eq!(parse_memory_pressure_level("WARNING"), Ok(Level::Warning));
assert_eq!(parse_memory_pressure_level("CRITICAL"), Ok(Level::Critical));
}
#[test]
fn cannot_parse_lowercase_levels() {
assert_matches!(parse_memory_pressure_level("normal"), Err(_));
assert_matches!(parse_memory_pressure_level("warning"), Err(_));
assert_matches!(parse_memory_pressure_level("critical"), Err(_));
}
#[test]
fn cannot_parse_capitalized_levels() {
assert_matches!(parse_memory_pressure_level("Normal"), Err(_));
assert_matches!(parse_memory_pressure_level("Warning"), Err(_));
assert_matches!(parse_memory_pressure_level("Critical"), Err(_));
}
N/A
N/A
{
"command": "ffx profile network",
"options": [],
"short": "Access network activity information"
}
N/A
```posix-terminal
N/A
{
"command": "ffx profile network activity",
"options": [],
"short": "Controls the metrics-logger component to log network activity. Logged samples will be available in syslog, via iquery under core/metrics-logger and via tracing in the `metrics_logger` category."
}
#[test]
fn test_parse_duration() {
assert_eq!(parse_duration("1h"), Ok(Duration::from_secs(3600)));
assert_eq!(parse_duration("3m"), Ok(Duration::from_secs(180)));
assert_eq!(parse_duration("10s"), Ok(Duration::from_secs(10)));
assert_eq!(parse_duration("100ms"), Ok(Duration::from_millis(100)));
}
#[test]
fn test_parse_duration_err() {
assert!(parse_duration("100").is_err());
assert!(parse_duration("10 0").is_err());
assert!(parse_duration("foobar").is_err());
}
#[fuchsia::test]
async fn test_request_dispatch_start_logging() {
// Start logging: interval=1s, duration=4s
let args = args_mod::StartCommand {
interval: ONE_SEC,
duration: Some(4 * ONE_SEC),
output_to_syslog: false,
};
let (mut sender, mut receiver) = mpsc::channel(1);
let client = fdomain_local::local_client_empty();
let proxy = fake_proxy(client, move |req| match req {
fmetrics::RecorderRequest::StartLogging {
client_id,
metrics,
duration_ms,
output_samples_to_syslog,
output_stats_to_syslog,
responder,
} => {
assert_eq!(String::from("ffx_network"), client_id);
assert_eq!(metrics.len(), 1);
assert_eq!(
metrics[0],
Metric::NetworkActivity(NetworkActivity { interval_ms: 1000 }),
);
assert_eq!(output_samples_to_syslog, false);
assert_eq!(output_stats_to_syslog, false);
assert_eq!(duration_ms, 4000);
responder.send(Ok(())).unwrap();
sender.try_send(()).unwrap();
```posix-terminal
N/A
{
"command": "ffx profile network activity start",
"options": [
{
"description": "interval for polling the network activity",
"option": "interval",
"shorthand": "s",
"value_type": "string"
},
{
"description": "toggle for logging samples to syslog",
"option": "output-to-syslog",
N/A
N/A
N/A
{
"command": "ffx profile network activity start",
"options": [
{
"description": "interval for polling the network activity",
"option": "interval",
"shorthand": "s",
"value_type": "string"
},
{
"description": "toggle for logging samples to syslog",
"option": "output-to-syslog",
N/A
N/A
N/A
{
"command": "ffx profile network activity start",
"options": [
{
"description": "interval for polling the network activity",
"option": "interval",
"shorthand": "s",
"value_type": "string"
},
{
"description": "toggle for logging samples to syslog",
"option": "output-to-syslog",
N/A
N/A
N/A
{
"command": "ffx profile network activity start",
"options": [
{
"description": "interval for polling the network activity",
"option": "interval",
"shorthand": "s",
"value_type": "string"
},
{
"description": "toggle for logging samples to syslog",
"option": "output-to-syslog",
N/A
N/A
N/A
{
"command": "ffx profile network activity stop",
"options": [],
"short": "Stop logging on the target"
}
N/A
N/A
N/A
{
"command": "ffx profile power",
"options": [],
"short": "Access power-related information"
}
N/A
```posix-terminal
N/A
{
"command": "ffx profile power logger",
"options": [],
"short": "Controls the metrics-logger component to log power. Logged power samples will be available in syslog, via iquery under core/metrics-logger and via tracing in the `metrics_logger` category."
}
#[fuchsia::test]
async fn test_request_dispatch() {
// Start logging: sampling_interval=1s, statistics_interval=2s, duration=4s
let args = args_mod::StartCommand {
sampling_interval: ONE_SEC,
statistics_interval: Some(2 * ONE_SEC),
duration: Some(4 * ONE_SEC),
output_samples_to_syslog: false,
output_stats_to_syslog: false,
};
let (mut sender, mut receiver) = mpsc::channel(1);
let client = fdomain_local::local_client_empty();
let logger = fake_proxy(client, move |req| match req {
fmetrics::RecorderRequest::StartLogging {
client_id,
metrics,
duration_ms,
output_samples_to_syslog,
output_stats_to_syslog,
responder,
} => {
assert_eq!(String::from("ffx_power"), client_id);
assert_eq!(metrics.len(), 1);
assert_eq!(
metrics[0],
Metric::Power(Power {
sampling_interval_ms: 1000,
statistics_args: Some(Box::new(StatisticsArgs {
statistics_interval_ms: 2000
})),
#[fuchsia::test]
async fn test_request_dispatch_start_logging() {
// Start logging: sampling_interval=1s, statistics_interval=2s, duration=4s
let args = args_mod::StartCommand {
sampling_interval: ONE_SEC,
statistics_interval: Some(2 * ONE_SEC),
duration: Some(4 * ONE_SEC),
output_samples_to_syslog: false,
output_stats_to_syslog: false,
};
let (mut sender, mut receiver) = mpsc::channel(1);
let client = fdomain_local::local_client_empty();
let logger = fake_proxy(client, move |req| match req {
fmetrics::RecorderRequest::StartLogging {
client_id,
metrics,
duration_ms,
output_samples_to_syslog,
output_stats_to_syslog,
responder,
} => {
assert_eq!(String::from("ffx_power"), client_id);
assert_eq!(metrics.len(), 1);
assert_eq!(
metrics[0],
Metric::Power(Power {
sampling_interval_ms: 1000,
statistics_args: Some(Box::new(StatisticsArgs {
statistics_interval_ms: 2000
})),
#[fuchsia::test]
async fn test_request_dispatch_start_logging_forever() {
// Start logging: sampling_interval=1s, statistics_interval=2s, duration=forever
let args = args_mod::StartCommand {
sampling_interval: ONE_SEC,
statistics_interval: Some(2 * ONE_SEC),
duration: None,
output_samples_to_syslog: false,
output_stats_to_syslog: false,
};
let (mut sender, mut receiver) = mpsc::channel(1);
let client = fdomain_local::local_client_empty();
let logger = fake_proxy(client, move |req| match req {
fmetrics::RecorderRequest::StartLoggingForever {
client_id,
metrics,
output_samples_to_syslog,
output_stats_to_syslog,
responder,
..
} => {
assert_eq!(String::from("ffx_power"), client_id);
assert_eq!(metrics.len(), 1);
assert_eq!(
metrics[0],
Metric::Power(Power {
sampling_interval_ms: 1000,
statistics_args: Some(Box::new(StatisticsArgs {
statistics_interval_ms: 2000
})),
```posix-terminal
N/A
{
"command": "ffx profile power logger start",
"options": [
{
"description": "interval for summarizing statistics; if omitted, statistics is disabled",
"option": "statistics-interval",
"shorthand": "l",
"value_type": "string"
},
{
"description": "interval for polling the sensor",
"option": "sampling-interval",
N/A
N/A
N/A
{
"command": "ffx profile power logger start",
"options": [
{
"description": "interval for summarizing statistics; if omitted, statistics is disabled",
"option": "statistics-interval",
"shorthand": "l",
"value_type": "string"
},
{
"description": "interval for polling the sensor",
"option": "sampling-interval",
N/A
N/A
N/A
{
"command": "ffx profile power logger start",
"options": [
{
"description": "interval for summarizing statistics; if omitted, statistics is disabled",
"option": "statistics-interval",
"shorthand": "l",
"value_type": "string"
},
{
"description": "interval for polling the sensor",
"option": "sampling-interval",
N/A
N/A
N/A
{
"command": "ffx profile power logger start",
"options": [
{
"description": "interval for summarizing statistics; if omitted, statistics is disabled",
"option": "statistics-interval",
"shorthand": "l",
"value_type": "string"
},
{
"description": "interval for polling the sensor",
"option": "sampling-interval",
N/A
N/A
N/A
{
"command": "ffx profile power logger start",
"options": [
{
"description": "interval for summarizing statistics; if omitted, statistics is disabled",
"option": "statistics-interval",
"shorthand": "l",
"value_type": "string"
},
{
"description": "interval for polling the sensor",
"option": "sampling-interval",
N/A
N/A
N/A
{
"command": "ffx profile power logger start",
"options": [
{
"description": "interval for summarizing statistics; if omitted, statistics is disabled",
"option": "statistics-interval",
"shorthand": "l",
"value_type": "string"
},
{
"description": "interval for polling the sensor",
"option": "sampling-interval",
N/A
N/A
N/A
{
"command": "ffx profile power logger stop",
"options": [],
"short": "Stop logging on the target"
}
N/A
N/A
N/A
{
"command": "ffx profile temperature",
"options": [],
"short": "Access temperature-related information"
}
N/A
```posix-terminal
N/A
{
"command": "ffx profile temperature logger",
"options": [],
"short": "Controls the metrics-logger component to log temperature. Logged temperature samples will be available in syslog, via iquery under core/metrics-logger and via tracing in the `metrics_logger` category."
}
#[test]
fn test_parse_duration() {
assert_eq!(parse_duration("1h"), Ok(Duration::from_secs(3600)));
assert_eq!(parse_duration("3m"), Ok(Duration::from_secs(180)));
assert_eq!(parse_duration("10s"), Ok(Duration::from_secs(10)));
assert_eq!(parse_duration("100ms"), Ok(Duration::from_millis(100)));
}
#[test]
fn test_parse_duration_err() {
assert!(parse_duration("100").is_err());
assert!(parse_duration("10 0").is_err());
assert!(parse_duration("foobar").is_err());
}
#[fuchsia::test]
async fn test_request_dispatch_start_logging() {
// Start logging: sampling_interval=1s, statistics_interval=2s, duration=4s
let args = args_mod::StartCommand {
sampling_interval: ONE_SEC,
statistics_interval: Some(2 * ONE_SEC),
duration: Some(4 * ONE_SEC),
output_samples_to_syslog: false,
output_stats_to_syslog: false,
};
let (mut sender, mut receiver) = mpsc::channel(1);
let client = fdomain_local::local_client_empty();
let logger = fake_proxy(client, move |req| match req {
fmetrics::RecorderRequest::StartLogging {
client_id,
metrics,
duration_ms,
output_samples_to_syslog,
output_stats_to_syslog,
responder,
} => {
assert_eq!(String::from("ffx_temperature"), client_id);
assert_eq!(metrics.len(), 1);
assert_eq!(
metrics[0],
Metric::Temperature(Temperature {
sampling_interval_ms: 1000,
statistics_args: Some(Box::new(StatisticsArgs {
statistics_interval_ms: 2000
})),
```posix-terminal
N/A
{
"command": "ffx profile temperature logger start",
"options": [
{
"description": "interval for summarizing statistics; if omitted, statistics is disabled",
"option": "statistics-interval",
"shorthand": "l",
"value_type": "string"
},
{
"description": "interval for polling the sensor",
"option": "sampling-interval",
N/A
N/A
N/A
{
"command": "ffx profile temperature logger start",
"options": [
{
"description": "interval for summarizing statistics; if omitted, statistics is disabled",
"option": "statistics-interval",
"shorthand": "l",
"value_type": "string"
},
{
"description": "interval for polling the sensor",
"option": "sampling-interval",
N/A
N/A
N/A
{
"command": "ffx profile temperature logger start",
"options": [
{
"description": "interval for summarizing statistics; if omitted, statistics is disabled",
"option": "statistics-interval",
"shorthand": "l",
"value_type": "string"
},
{
"description": "interval for polling the sensor",
"option": "sampling-interval",
N/A
N/A
N/A
{
"command": "ffx profile temperature logger start",
"options": [
{
"description": "interval for summarizing statistics; if omitted, statistics is disabled",
"option": "statistics-interval",
"shorthand": "l",
"value_type": "string"
},
{
"description": "interval for polling the sensor",
"option": "sampling-interval",
N/A
N/A
N/A
{
"command": "ffx profile temperature logger start",
"options": [
{
"description": "interval for summarizing statistics; if omitted, statistics is disabled",
"option": "statistics-interval",
"shorthand": "l",
"value_type": "string"
},
{
"description": "interval for polling the sensor",
"option": "sampling-interval",
N/A
N/A
N/A
{
"command": "ffx profile temperature logger start",
"options": [
{
"description": "interval for summarizing statistics; if omitted, statistics is disabled",
"option": "statistics-interval",
"shorthand": "l",
"value_type": "string"
},
{
"description": "interval for polling the sensor",
"option": "sampling-interval",
N/A
N/A
N/A
{
"command": "ffx profile temperature logger stop",
"options": [],
"short": "Stop logging on the target"
}
N/A
N/A
N/A
{
"command": "ffx repository",
"options": [],
"short": "Inspect and manage package repositories"
}
// Copyright 2023 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use anyhow::{Context as _, ensure};
// Copyright 2026 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use async_trait::async_trait;
use fdomain_client::fidl::{DiscoverableProtocolMarker, Proxy};
```posix-terminal
```posix-terminal
```posix-terminal
N/A
{
"command": "ffx repository add",
"options": [
{
"description": "repositories will have the prefix `NAME`. Defaults to `devhost`.",
"option": "prefix",
"shorthand": "p",
"value_type": "string"
}
],
"short": "Make the daemon aware of specific product bundle repositories"
}
N/A
N/A
N/A
{
"command": "ffx repository add",
"options": [
{
"description": "repositories will have the prefix `NAME`. Defaults to `devhost`.",
"option": "prefix",
"shorthand": "p",
"value_type": "string"
}
],
"short": "Make the daemon aware of specific product bundle repositories"
}
N/A
N/A
N/A
{
"command": "ffx repository create",
"options": [
{
"description": "set repository version based on the current time rather than monotonically increasing version",
"option": "time-versioning",
"shorthand": "",
"value_type": "bool"
},
{
"description": "path to the repository keys directory. Default to generate keys at 'repo_path'/keys.",
"option": "keys",
#[fuchsia::test]
async fn test_machine_ok() {
let tool = CreateTool::<OkFakeTools> {
cmd: RepoCreateCommand {
time_versioning: false,
keys: None,
repo_path: "/somewhere".into(),
},
_phantom: PhantomData,
};
let buffers = TestBuffers::default();
let writer =
<CreateTool<OkFakeTools> as FfxMain>::Writer::new_test(Some(Format::Json), &buffers);
let res = tool.main(writer).await;
let (stdout, stderr) = buffers.into_strings();
assert!(res.is_ok(), "expected ok: {stdout} {stderr}");
let err = format!("schema not valid {stdout}");
let json = serde_json::from_str(&stdout).expect(&err);
let err = format!("json must adhere to schema: {json}");
<CreateTool<OkFakeTools> as FfxMain>::Writer::verify_schema(&json).expect(&err);
assert_eq!(json, serde_json::json!({"ok":{}}));
}
#[fuchsia::test]
async fn test_machine_error() {
let tool = CreateTool::<ErrFakeTools> {
cmd: RepoCreateCommand {
time_versioning: false,
keys: None,
repo_path: "/somewhere".into(),
},
_phantom: PhantomData,
};
let buffers = TestBuffers::default();
let writer =
<CreateTool<ErrFakeTools> as FfxMain>::Writer::new_test(Some(Format::Json), &buffers);
let res = tool.main(writer).await;
let (stdout, stderr) = buffers.into_strings();
assert!(res.is_err(), "expected err: {stdout} {stderr}");
let err = format!("schema not valid {stdout}");
let json = serde_json::from_str(&stdout).expect(&err);
let err = format!("json must adhere to schema: {json}");
<CreateTool<ErrFakeTools> as FfxMain>::Writer::verify_schema(&json).expect(&err);
assert_eq!(
json,
serde_json::json!({"unexpected_error" :{"message": "BUG: An internal command error occurred.\nError: general error"}})
);
}
N/A
N/A
{
"command": "ffx repository create",
"options": [
{
"description": "set repository version based on the current time rather than monotonically increasing version",
"option": "time-versioning",
"shorthand": "",
"value_type": "bool"
},
{
"description": "path to the repository keys directory. Default to generate keys at 'repo_path'/keys.",
"option": "keys",
N/A
N/A
N/A
{
"command": "ffx repository create",
"options": [
{
"description": "set repository version based on the current time rather than monotonically increasing version",
"option": "time-versioning",
"shorthand": "",
"value_type": "bool"
},
{
"description": "path to the repository keys directory. Default to generate keys at 'repo_path'/keys.",
"option": "keys",
N/A
N/A
N/A
{
"command": "ffx repository default",
"options": [],
"short": "Manage the default repository"
}
N/A
```posix-terminal
```posix-terminal
N/A
{
"command": "ffx repository default get",
"options": [],
"short": "Get the default configured repository"
}
N/A
N/A
N/A
{
"command": "ffx repository default set",
"options": [
{
"description": "config level, such as 'user', 'build', or 'global'",
"option": "level",
"shorthand": "l",
"value_type": "string"
},
{
"description": "optional directory to associate the provided build config",
"option": "build-dir",
N/A
```posix-terminal
N/A
{
"command": "ffx repository default set",
"options": [
{
"description": "config level, such as 'user', 'build', or 'global'",
"option": "level",
"shorthand": "l",
"value_type": "string"
},
{
"description": "optional directory to associate the provided build config",
"option": "build-dir",
N/A
N/A
N/A
{
"command": "ffx repository default set",
"options": [
{
"description": "config level, such as 'user', 'build', or 'global'",
"option": "level",
"shorthand": "l",
"value_type": "string"
},
{
"description": "optional directory to associate the provided build config",
"option": "build-dir",
N/A
N/A
N/A
{
"command": "ffx repository default unset",
"options": [
{
"description": "config level, such as 'user', 'build', or 'global'",
"option": "level",
"shorthand": "l",
"value_type": "string"
},
{
"description": "optional directory to associate the provided build config",
"option": "build-dir",
N/A
```posix-terminal
N/A
{
"command": "ffx repository default unset",
"options": [
{
"description": "config level, such as 'user', 'build', or 'global'",
"option": "level",
"shorthand": "l",
"value_type": "string"
},
{
"description": "optional directory to associate the provided build config",
"option": "build-dir",
N/A
N/A
N/A
{
"command": "ffx repository default unset",
"options": [
{
"description": "config level, such as 'user', 'build', or 'global'",
"option": "level",
"shorthand": "l",
"value_type": "string"
},
{
"description": "optional directory to associate the provided build config",
"option": "build-dir",
N/A
N/A
N/A
{
"command": "ffx repository package",
"options": [],
"short": "List the packages inside a repository"
}
N/A
N/A
N/A
{
"command": "ffx repository package extract-archive",
"options": [
{
"description": "output path for the extracted archive.",
"option": "out",
"shorthand": "o",
"value_type": "string"
},
{
"description": "extract package from this repository.",
"option": "repository",
N/A
N/A
N/A
{
"command": "ffx repository package extract-archive",
"options": [
{
"description": "output path for the extracted archive.",
"option": "out",
"shorthand": "o",
"value_type": "string"
},
{
"description": "extract package from this repository.",
"option": "repository",
N/A
N/A
N/A
{
"command": "ffx repository package extract-archive",
"options": [
{
"description": "output path for the extracted archive.",
"option": "out",
"shorthand": "o",
"value_type": "string"
},
{
"description": "extract package from this repository.",
"option": "repository",
N/A
N/A
N/A
{
"command": "ffx repository package extract-archive",
"options": [
{
"description": "output path for the extracted archive.",
"option": "out",
"shorthand": "o",
"value_type": "string"
},
{
"description": "extract package from this repository.",
"option": "repository",
N/A
N/A
N/A
{
"command": "ffx repository package extract-archive",
"options": [
{
"description": "output path for the extracted archive.",
"option": "out",
"shorthand": "o",
"value_type": "string"
},
{
"description": "extract package from this repository.",
"option": "repository",
N/A
N/A
N/A
{
"command": "ffx repository package list",
"options": [
{
"description": "list packages from a running repository with this name.",
"option": "repository",
"shorthand": "r",
"value_type": "string"
},
{
"description": "repository server port number. Required needed to disambiguate multiple repositories with the same name.",
"option": "port",
N/A
N/A
N/A
{
"command": "ffx repository package list",
"options": [
{
"description": "list packages from a running repository with this name.",
"option": "repository",
"shorthand": "r",
"value_type": "string"
},
{
"description": "repository server port number. Required needed to disambiguate multiple repositories with the same name.",
"option": "port",
N/A
N/A
N/A
{
"command": "ffx repository package list",
"options": [
{
"description": "list packages from a running repository with this name.",
"option": "repository",
"shorthand": "r",
"value_type": "string"
},
{
"description": "repository server port number. Required needed to disambiguate multiple repositories with the same name.",
"option": "port",
N/A
N/A
N/A
{
"command": "ffx repository package list",
"options": [
{
"description": "list packages from a running repository with this name.",
"option": "repository",
"shorthand": "r",
"value_type": "string"
},
{
"description": "repository server port number. Required needed to disambiguate multiple repositories with the same name.",
"option": "port",
N/A
N/A
N/A
{
"command": "ffx repository package list",
"options": [
{
"description": "list packages from a running repository with this name.",
"option": "repository",
"shorthand": "r",
"value_type": "string"
},
{
"description": "repository server port number. Required needed to disambiguate multiple repositories with the same name.",
"option": "port",
N/A
N/A
N/A
{
"command": "ffx repository package list",
"options": [
{
"description": "list packages from a running repository with this name.",
"option": "repository",
"shorthand": "r",
"value_type": "string"
},
{
"description": "repository server port number. Required needed to disambiguate multiple repositories with the same name.",
"option": "port",
N/A
N/A
N/A
{
"command": "ffx repository package list",
"options": [
{
"description": "list packages from a running repository with this name.",
"option": "repository",
"shorthand": "r",
"value_type": "string"
},
{
"description": "repository server port number. Required needed to disambiguate multiple repositories with the same name.",
"option": "port",
N/A
N/A
N/A
{
"command": "ffx repository package show",
"options": [
{
"description": "list package contents from this repository.",
"option": "repository",
"shorthand": "r",
"value_type": "string"
},
{
"description": "repository server port number. Required to disambiguate multiple repositories with the same name.",
"option": "port",
N/A
N/A
N/A
{
"command": "ffx repository package show",
"options": [
{
"description": "list package contents from this repository.",
"option": "repository",
"shorthand": "r",
"value_type": "string"
},
{
"description": "repository server port number. Required to disambiguate multiple repositories with the same name.",
"option": "port",
N/A
N/A
N/A
{
"command": "ffx repository package show",
"options": [
{
"description": "list package contents from this repository.",
"option": "repository",
"shorthand": "r",
"value_type": "string"
},
{
"description": "repository server port number. Required to disambiguate multiple repositories with the same name.",
"option": "port",
N/A
N/A
N/A
{
"command": "ffx repository package show",
"options": [
{
"description": "list package contents from this repository.",
"option": "repository",
"shorthand": "r",
"value_type": "string"
},
{
"description": "repository server port number. Required to disambiguate multiple repositories with the same name.",
"option": "port",
N/A
N/A
N/A
{
"command": "ffx repository package show",
"options": [
{
"description": "list package contents from this repository.",
"option": "repository",
"shorthand": "r",
"value_type": "string"
},
{
"description": "repository server port number. Required to disambiguate multiple repositories with the same name.",
"option": "port",
N/A
N/A
N/A
{
"command": "ffx repository package show",
"options": [
{
"description": "list package contents from this repository.",
"option": "repository",
"shorthand": "r",
"value_type": "string"
},
{
"description": "repository server port number. Required to disambiguate multiple repositories with the same name.",
"option": "port",
N/A
N/A
N/A
{
"command": "ffx repository publish",
"options": [
{
"description": "path to the keys used to sign metadata, but not trust for key rotation",
"option": "signing-keys",
"shorthand": "",
"value_type": "string"
},
{
"description": "path to the keys used to sign and trust metadata (default repository `keys/` directory)",
"option": "trusted-keys",
#[fuchsia::test]
async fn test_machine_ok() {
let tool = PublishTool::<OkFakeTools> {
cmd: RepoPublishCommand {
signing_keys: None,
trusted_keys: None,
trusted_root: None,
package_manifests: vec![],
package_list_manifests: vec![],
package_archives: vec![],
product_bundle: vec![],
time_versioning: false,
metadata_current_time: chrono::Utc::now(),
refresh_root: false,
clean: false,
depfile: None,
copy_mode: fuchsia_repo::repository::CopyMode::Copy,
delivery_blob_type: 1,
watch: false,
ignore_missing_packages: false,
blob_manifest: None,
blob_repo_dir: None,
repo_path: "/somewhere".into(),
},
_phantom: PhantomData,
};
let buffers = TestBuffers::default();
let writer =
<PublishTool<OkFakeTools> as FfxMain>::Writer::new_test(Some(Format::Json), &buffers);
#[fuchsia::test]
async fn test_machine_error() {
let tool = PublishTool::<ErrFakeTools> {
cmd: RepoPublishCommand {
signing_keys: None,
trusted_keys: None,
trusted_root: None,
package_manifests: vec![],
package_list_manifests: vec![],
package_archives: vec![],
product_bundle: vec![],
time_versioning: false,
metadata_current_time: chrono::Utc::now(),
refresh_root: false,
clean: false,
depfile: None,
copy_mode: fuchsia_repo::repository::CopyMode::Copy,
delivery_blob_type: 1,
watch: false,
ignore_missing_packages: false,
blob_manifest: None,
blob_repo_dir: None,
repo_path: "/somewhere".into(),
},
_phantom: PhantomData,
};
let buffers = TestBuffers::default();
let writer =
<PublishTool<ErrFakeTools> as FfxMain>::Writer::new_test(Some(Format::Json), &buffers);
N/A
N/A
{
"command": "ffx repository publish",
"options": [
{
"description": "path to the keys used to sign metadata, but not trust for key rotation",
"option": "signing-keys",
"shorthand": "",
"value_type": "string"
},
{
"description": "path to the keys used to sign and trust metadata (default repository `keys/` directory)",
"option": "trusted-keys",
N/A
N/A
N/A
{
"command": "ffx repository publish",
"options": [
{
"description": "path to the keys used to sign metadata, but not trust for key rotation",
"option": "signing-keys",
"shorthand": "",
"value_type": "string"
},
{
"description": "path to the keys used to sign and trust metadata (default repository `keys/` directory)",
"option": "trusted-keys",
N/A
N/A
N/A
{
"command": "ffx repository publish",
"options": [
{
"description": "path to the keys used to sign metadata, but not trust for key rotation",
"option": "signing-keys",
"shorthand": "",
"value_type": "string"
},
{
"description": "path to the keys used to sign and trust metadata (default repository `keys/` directory)",
"option": "trusted-keys",
N/A
N/A
N/A
{
"command": "ffx repository publish",
"options": [
{
"description": "path to the keys used to sign metadata, but not trust for key rotation",
"option": "signing-keys",
"shorthand": "",
"value_type": "string"
},
{
"description": "path to the keys used to sign and trust metadata (default repository `keys/` directory)",
"option": "trusted-keys",
N/A
N/A
N/A
{
"command": "ffx repository publish",
"options": [
{
"description": "path to the keys used to sign metadata, but not trust for key rotation",
"option": "signing-keys",
"shorthand": "",
"value_type": "string"
},
{
"description": "path to the keys used to sign and trust metadata (default repository `keys/` directory)",
"option": "trusted-keys",
N/A
N/A
N/A
{
"command": "ffx repository publish",
"options": [
{
"description": "path to the keys used to sign metadata, but not trust for key rotation",
"option": "signing-keys",
"shorthand": "",
"value_type": "string"
},
{
"description": "path to the keys used to sign and trust metadata (default repository `keys/` directory)",
"option": "trusted-keys",
N/A
N/A
N/A
{
"command": "ffx repository publish",
"options": [
{
"description": "path to the keys used to sign metadata, but not trust for key rotation",
"option": "signing-keys",
"shorthand": "",
"value_type": "string"
},
{
"description": "path to the keys used to sign and trust metadata (default repository `keys/` directory)",
"option": "trusted-keys",
N/A
N/A
N/A
{
"command": "ffx repository publish",
"options": [
{
"description": "path to the keys used to sign metadata, but not trust for key rotation",
"option": "signing-keys",
"shorthand": "",
"value_type": "string"
},
{
"description": "path to the keys used to sign and trust metadata (default repository `keys/` directory)",
"option": "trusted-keys",
N/A
N/A
N/A
{
"command": "ffx repository publish",
"options": [
{
"description": "path to the keys used to sign metadata, but not trust for key rotation",
"option": "signing-keys",
"shorthand": "",
"value_type": "string"
},
{
"description": "path to the keys used to sign and trust metadata (default repository `keys/` directory)",
"option": "trusted-keys",
N/A
N/A
N/A
{
"command": "ffx repository publish",
"options": [
{
"description": "path to the keys used to sign metadata, but not trust for key rotation",
"option": "signing-keys",
"shorthand": "",
"value_type": "string"
},
{
"description": "path to the keys used to sign and trust metadata (default repository `keys/` directory)",
"option": "trusted-keys",
N/A
N/A
N/A
{
"command": "ffx repository publish",
"options": [
{
"description": "path to the keys used to sign metadata, but not trust for key rotation",
"option": "signing-keys",
"shorthand": "",
"value_type": "string"
},
{
"description": "path to the keys used to sign and trust metadata (default repository `keys/` directory)",
"option": "trusted-keys",
N/A
N/A
N/A
{
"command": "ffx repository publish",
"options": [
{
"description": "path to the keys used to sign metadata, but not trust for key rotation",
"option": "signing-keys",
"shorthand": "",
"value_type": "string"
},
{
"description": "path to the keys used to sign and trust metadata (default repository `keys/` directory)",
"option": "trusted-keys",
N/A
N/A
N/A
{
"command": "ffx repository publish",
"options": [
{
"description": "path to the keys used to sign metadata, but not trust for key rotation",
"option": "signing-keys",
"shorthand": "",
"value_type": "string"
},
{
"description": "path to the keys used to sign and trust metadata (default repository `keys/` directory)",
"option": "trusted-keys",
N/A
N/A
N/A
{
"command": "ffx repository publish",
"options": [
{
"description": "path to the keys used to sign metadata, but not trust for key rotation",
"option": "signing-keys",
"shorthand": "",
"value_type": "string"
},
{
"description": "path to the keys used to sign and trust metadata (default repository `keys/` directory)",
"option": "trusted-keys",
N/A
N/A
N/A
{
"command": "ffx repository publish",
"options": [
{
"description": "path to the keys used to sign metadata, but not trust for key rotation",
"option": "signing-keys",
"shorthand": "",
"value_type": "string"
},
{
"description": "path to the keys used to sign and trust metadata (default repository `keys/` directory)",
"option": "trusted-keys",
N/A
N/A
N/A
{
"command": "ffx repository publish",
"options": [
{
"description": "path to the keys used to sign metadata, but not trust for key rotation",
"option": "signing-keys",
"shorthand": "",
"value_type": "string"
},
{
"description": "path to the keys used to sign and trust metadata (default repository `keys/` directory)",
"option": "trusted-keys",
N/A
N/A
N/A
{
"command": "ffx repository publish",
"options": [
{
"description": "path to the keys used to sign metadata, but not trust for key rotation",
"option": "signing-keys",
"shorthand": "",
"value_type": "string"
},
{
"description": "path to the keys used to sign and trust metadata (default repository `keys/` directory)",
"option": "trusted-keys",
N/A
N/A
N/A
{
"command": "ffx repository publish",
"options": [
{
"description": "path to the keys used to sign metadata, but not trust for key rotation",
"option": "signing-keys",
"shorthand": "",
"value_type": "string"
},
{
"description": "path to the keys used to sign and trust metadata (default repository `keys/` directory)",
"option": "trusted-keys",
N/A
N/A
N/A
{
"command": "ffx repository serve",
"options": [
{
"description": "register this repository. Default is `devhost`.",
"option": "repository",
"shorthand": "r",
"value_type": "string"
},
{
"description": "path to the root metadata that was used to sign the repository TUF metadata. This establishes the root of trust for this repository. If the TUF metadata was not signed by this root metadata, running this command will result in an error. Default is to use 1.root.json from the repository.",
"option": "trusted-root",
N/A
N/A
N/A
{
"command": "ffx repository serve",
"options": [
{
"description": "register this repository. Default is `devhost`.",
"option": "repository",
"shorthand": "r",
"value_type": "string"
},
{
"description": "path to the root metadata that was used to sign the repository TUF metadata. This establishes the root of trust for this repository. If the TUF metadata was not signed by this root metadata, running this command will result in an error. Default is to use 1.root.json from the repository.",
"option": "trusted-root",
N/A
N/A
N/A
{
"command": "ffx repository serve",
"options": [
{
"description": "register this repository. Default is `devhost`.",
"option": "repository",
"shorthand": "r",
"value_type": "string"
},
{
"description": "path to the root metadata that was used to sign the repository TUF metadata. This establishes the root of trust for this repository. If the TUF metadata was not signed by this root metadata, running this command will result in an error. Default is to use 1.root.json from the repository.",
"option": "trusted-root",
N/A
N/A
N/A
{
"command": "ffx repository serve",
"options": [
{
"description": "register this repository. Default is `devhost`.",
"option": "repository",
"shorthand": "r",
"value_type": "string"
},
{
"description": "path to the root metadata that was used to sign the repository TUF metadata. This establishes the root of trust for this repository. If the TUF metadata was not signed by this root metadata, running this command will result in an error. Default is to use 1.root.json from the repository.",
"option": "trusted-root",
N/A
N/A
N/A
{
"command": "ffx repository serve",
"options": [
{
"description": "register this repository. Default is `devhost`.",
"option": "repository",
"shorthand": "r",
"value_type": "string"
},
{
"description": "path to the root metadata that was used to sign the repository TUF metadata. This establishes the root of trust for this repository. If the TUF metadata was not signed by this root metadata, running this command will result in an error. Default is to use 1.root.json from the repository.",
"option": "trusted-root",
N/A
N/A
N/A
{
"command": "ffx repository serve",
"options": [
{
"description": "register this repository. Default is `devhost`.",
"option": "repository",
"shorthand": "r",
"value_type": "string"
},
{
"description": "path to the root metadata that was used to sign the repository TUF metadata. This establishes the root of trust for this repository. If the TUF metadata was not signed by this root metadata, running this command will result in an error. Default is to use 1.root.json from the repository.",
"option": "trusted-root",
N/A
N/A
N/A
{
"command": "ffx repository serve",
"options": [
{
"description": "register this repository. Default is `devhost`.",
"option": "repository",
"shorthand": "r",
"value_type": "string"
},
{
"description": "path to the root metadata that was used to sign the repository TUF metadata. This establishes the root of trust for this repository. If the TUF metadata was not signed by this root metadata, running this command will result in an error. Default is to use 1.root.json from the repository.",
"option": "trusted-root",
N/A
N/A
N/A
{
"command": "ffx repository serve",
"options": [
{
"description": "register this repository. Default is `devhost`.",
"option": "repository",
"shorthand": "r",
"value_type": "string"
},
{
"description": "path to the root metadata that was used to sign the repository TUF metadata. This establishes the root of trust for this repository. If the TUF metadata was not signed by this root metadata, running this command will result in an error. Default is to use 1.root.json from the repository.",
"option": "trusted-root",
N/A
N/A
N/A
{
"command": "ffx repository serve",
"options": [
{
"description": "register this repository. Default is `devhost`.",
"option": "repository",
"shorthand": "r",
"value_type": "string"
},
{
"description": "path to the root metadata that was used to sign the repository TUF metadata. This establishes the root of trust for this repository. If the TUF metadata was not signed by this root metadata, running this command will result in an error. Default is to use 1.root.json from the repository.",
"option": "trusted-root",
N/A
N/A
N/A
{
"command": "ffx repository serve",
"options": [
{
"description": "register this repository. Default is `devhost`.",
"option": "repository",
"shorthand": "r",
"value_type": "string"
},
{
"description": "path to the root metadata that was used to sign the repository TUF metadata. This establishes the root of trust for this repository. If the TUF metadata was not signed by this root metadata, running this command will result in an error. Default is to use 1.root.json from the repository.",
"option": "trusted-root",
N/A
N/A
N/A
{
"command": "ffx repository serve",
"options": [
{
"description": "register this repository. Default is `devhost`.",
"option": "repository",
"shorthand": "r",
"value_type": "string"
},
{
"description": "path to the root metadata that was used to sign the repository TUF metadata. This establishes the root of trust for this repository. If the TUF metadata was not signed by this root metadata, running this command will result in an error. Default is to use 1.root.json from the repository.",
"option": "trusted-root",
N/A
N/A
N/A
{
"command": "ffx repository serve",
"options": [
{
"description": "register this repository. Default is `devhost`.",
"option": "repository",
"shorthand": "r",
"value_type": "string"
},
{
"description": "path to the root metadata that was used to sign the repository TUF metadata. This establishes the root of trust for this repository. If the TUF metadata was not signed by this root metadata, running this command will result in an error. Default is to use 1.root.json from the repository.",
"option": "trusted-root",
N/A
N/A
N/A
{
"command": "ffx repository serve",
"options": [
{
"description": "register this repository. Default is `devhost`.",
"option": "repository",
"shorthand": "r",
"value_type": "string"
},
{
"description": "path to the root metadata that was used to sign the repository TUF metadata. This establishes the root of trust for this repository. If the TUF metadata was not signed by this root metadata, running this command will result in an error. Default is to use 1.root.json from the repository.",
"option": "trusted-root",
N/A
N/A
N/A
{
"command": "ffx repository serve-archive",
"options": [
{
"description": "repository name. Default is `devhost`.",
"option": "repository",
"shorthand": "r",
"value_type": "string"
},
{
"description": "address on which to serve the repository. Default is `[::]:8083`.",
"option": "address",
#[fuchsia::test]
fn test_parse_args() {
let cmd =
ServeArchiveCommand::from_args(&["serve-archive"], &["/path/to/archive.far"]).unwrap();
assert_eq!(cmd.archive, Utf8PathBuf::from("/path/to/archive.far"));
assert_eq!(cmd.repository, "devhost");
assert_eq!(cmd.address, default_address());
assert_eq!(cmd.tunnel_addr, None);
assert_eq!(cmd.alias, Vec::<String>::new());
assert_eq!(cmd.no_device, false);
}
N/A
N/A
{
"command": "ffx repository serve-archive",
"options": [
{
"description": "repository name. Default is `devhost`.",
"option": "repository",
"shorthand": "r",
"value_type": "string"
},
{
"description": "address on which to serve the repository. Default is `[::]:8083`.",
"option": "address",
N/A
N/A
N/A
{
"command": "ffx repository serve-archive",
"options": [
{
"description": "repository name. Default is `devhost`.",
"option": "repository",
"shorthand": "r",
"value_type": "string"
},
{
"description": "address on which to serve the repository. Default is `[::]:8083`.",
"option": "address",
N/A
N/A
N/A
{
"command": "ffx repository serve-archive",
"options": [
{
"description": "repository name. Default is `devhost`.",
"option": "repository",
"shorthand": "r",
"value_type": "string"
},
{
"description": "address on which to serve the repository. Default is `[::]:8083`.",
"option": "address",
N/A
N/A
N/A
{
"command": "ffx repository serve-archive",
"options": [
{
"description": "repository name. Default is `devhost`.",
"option": "repository",
"shorthand": "r",
"value_type": "string"
},
{
"description": "address on which to serve the repository. Default is `[::]:8083`.",
"option": "address",
N/A
N/A
N/A
{
"command": "ffx repository serve-archive",
"options": [
{
"description": "repository name. Default is `devhost`.",
"option": "repository",
"shorthand": "r",
"value_type": "string"
},
{
"description": "address on which to serve the repository. Default is `[::]:8083`.",
"option": "address",
N/A
N/A
N/A
{
"command": "ffx repository server",
"options": [],
"short": "Inspect and manage the repository server"
}
// Copyright 2023 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use anyhow::{Context as _, ensure};
// Copyright 2026 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use async_trait::async_trait;
use fdomain_client::fidl::{DiscoverableProtocolMarker, Proxy};
#[fuchsia::test]
fn test_to_argv() {
let start_cmd = StartCommand {
address: Some(([127, 0, 0, 1], 8787).into()),
background: true,
foreground: false,
disconnected: false,
repository: Some("repo-name".into()),
trusted_root: Some(Utf8PathBuf::from_str("/trusted/root").expect("UTF8 path")),
repo_path: Some(Utf8PathBuf::from_str("/repo/path/root").expect("UTF8 path")),
product_bundle: Some(Utf8PathBuf::from_str("/product/bundle/path").expect("UTF8 path")),
alias: vec!["alias1".into(), "alias2".into()],
storage_type: Some(RepositoryStorageType::Ephemeral),
alias_conflict_mode: RepositoryRegistrationAliasConflictMode::Replace,
port_path: Some("/path/port/file".into()),
tunnel_addr: Some(([127, 0, 0, 1], 1313).into()),
no_device: false,
refresh_metadata: true,
auto_publish: Some(Utf8PathBuf::from_str("/auto/publish/list").expect("UTF8 path")),
};
let actual = to_argv(&start_cmd);
let expected: Vec<String> = [
"--address",
"127.0.0.1:8787",
"--alias",
"alias1",
"--alias",
"alias2",
"--alias-conflict-mode",
N/A
N/A
{
"command": "ffx repository server list",
"options": [
{
"description": "long version of output.",
"option": "full",
"shorthand": "",
"value_type": "bool"
},
{
"description": "limit output to provided name. This option can appear multiple times",
"option": "name",
// Copyright 2026 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use async_trait::async_trait;
use fdomain_client::fidl::{DiscoverableProtocolMarker, Proxy};
#[fuchsia::test]
async fn test_empty() {
let test_env = ffx_config::test_init().expect("test env");
test_env
.context
.query("repository.process_dir")
.level(Some(ConfigLevel::User))
.build()
.set(&test_env.context, test_env.isolate_root.path().to_string_lossy().into())
.expect("Setting process dir");
let tool = RepoListTool {
cmd: ListCommand { full: false, names: vec![] },
context: test_env.context.clone(),
};
let buffers = TestBuffers::default();
let writer = <RepoListTool as FfxMain>::Writer::new_test(None, &buffers);
tool.main(writer).await.expect("ok");
let (stdout, stderr) = buffers.into_strings();
assert_eq!("\n", stdout);
assert_eq!("", stderr);
}
#[fuchsia::test]
async fn test_text() {
let test_env = ffx_config::test_init().expect("test env");
test_env
.context
.query("repository.process_dir")
.level(Some(ConfigLevel::User))
.build()
.set(&test_env.context, test_env.isolate_root.path().to_string_lossy().into())
.expect("Setting process dir");
let dir = test_env.context.get("repository.process_dir").expect("process_dir");
let mgr = PkgServerInstances::new(dir);
let addr = SocketAddr::new(std::net::IpAddr::V6(std::net::Ipv6Addr::UNSPECIFIED), 8000);
let instance_name = "s1";
let repo_config =
RepositoryConfigBuilder::new(format!("fuchsia-pkg://{instance_name}").parse().unwrap())
.build();
let s1 = PkgServerInfo {
name: instance_name.into(),
address: addr,
repo_spec: fuchsia_repo::repository::RepositorySpec::Pm {
path: Utf8PathBuf::from("/some/repo"),
aliases: BTreeSet::new(),
},
registration_storage_type: RepositoryStorageType::Ephemeral,
registration_alias_conflict_mode: RepositoryRegistrationAliasConflictMode::ErrorOut,
N/A
N/A
{
"command": "ffx repository server list",
"options": [
{
"description": "long version of output.",
"option": "full",
"shorthand": "",
"value_type": "bool"
},
{
"description": "limit output to provided name. This option can appear multiple times",
"option": "name",
N/A
N/A
N/A
{
"command": "ffx repository server list",
"options": [
{
"description": "long version of output.",
"option": "full",
"shorthand": "",
"value_type": "bool"
},
{
"description": "limit output to provided name. This option can appear multiple times",
"option": "name",
N/A
N/A
N/A
{
"command": "ffx repository server start",
"options": [
{
"description": "address on which to serve the repository. Note that this can be either IPV4 or IPV6. For example, [::]:8083 or 127.0.0.1:8083 Default is `[::]:8083`.",
"option": "address",
"shorthand": "",
"value_type": "string"
},
{
"description": "run server as a background process. This is mutually exclusive with --foreground.",
"option": "background",
// Copyright 2023 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use anyhow::{Context as _, ensure};
N/A
N/A
{
"command": "ffx repository server start",
"options": [
{
"description": "address on which to serve the repository. Note that this can be either IPV4 or IPV6. For example, [::]:8083 or 127.0.0.1:8083 Default is `[::]:8083`.",
"option": "address",
"shorthand": "",
"value_type": "string"
},
{
"description": "run server as a background process. This is mutually exclusive with --foreground.",
"option": "background",
// Copyright 2023 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use anyhow::{Context as _, ensure};
N/A
N/A
{
"command": "ffx repository server start",
"options": [
{
"description": "address on which to serve the repository. Note that this can be either IPV4 or IPV6. For example, [::]:8083 or 127.0.0.1:8083 Default is `[::]:8083`.",
"option": "address",
"shorthand": "",
"value_type": "string"
},
{
"description": "run server as a background process. This is mutually exclusive with --foreground.",
"option": "background",
N/A
N/A
N/A
{
"command": "ffx repository server start",
"options": [
{
"description": "address on which to serve the repository. Note that this can be either IPV4 or IPV6. For example, [::]:8083 or 127.0.0.1:8083 Default is `[::]:8083`.",
"option": "address",
"shorthand": "",
"value_type": "string"
},
{
"description": "run server as a background process. This is mutually exclusive with --foreground.",
"option": "background",
N/A
N/A
N/A
{
"command": "ffx repository server start",
"options": [
{
"description": "address on which to serve the repository. Note that this can be either IPV4 or IPV6. For example, [::]:8083 or 127.0.0.1:8083 Default is `[::]:8083`.",
"option": "address",
"shorthand": "",
"value_type": "string"
},
{
"description": "run server as a background process. This is mutually exclusive with --foreground.",
"option": "background",
N/A
N/A
N/A
{
"command": "ffx repository server start",
"options": [
{
"description": "address on which to serve the repository. Note that this can be either IPV4 or IPV6. For example, [::]:8083 or 127.0.0.1:8083 Default is `[::]:8083`.",
"option": "address",
"shorthand": "",
"value_type": "string"
},
{
"description": "run server as a background process. This is mutually exclusive with --foreground.",
"option": "background",
// Copyright 2023 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use anyhow::{Context as _, ensure};
N/A
N/A
{
"command": "ffx repository server start",
"options": [
{
"description": "address on which to serve the repository. Note that this can be either IPV4 or IPV6. For example, [::]:8083 or 127.0.0.1:8083 Default is `[::]:8083`.",
"option": "address",
"shorthand": "",
"value_type": "string"
},
{
"description": "run server as a background process. This is mutually exclusive with --foreground.",
"option": "background",
N/A
N/A
N/A
{
"command": "ffx repository server start",
"options": [
{
"description": "address on which to serve the repository. Note that this can be either IPV4 or IPV6. For example, [::]:8083 or 127.0.0.1:8083 Default is `[::]:8083`.",
"option": "address",
"shorthand": "",
"value_type": "string"
},
{
"description": "run server as a background process. This is mutually exclusive with --foreground.",
"option": "background",
// Copyright 2023 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use anyhow::{Context as _, ensure};
N/A
N/A
{
"command": "ffx repository server start",
"options": [
{
"description": "address on which to serve the repository. Note that this can be either IPV4 or IPV6. For example, [::]:8083 or 127.0.0.1:8083 Default is `[::]:8083`.",
"option": "address",
"shorthand": "",
"value_type": "string"
},
{
"description": "run server as a background process. This is mutually exclusive with --foreground.",
"option": "background",
N/A
N/A
N/A
{
"command": "ffx repository server start",
"options": [
{
"description": "address on which to serve the repository. Note that this can be either IPV4 or IPV6. For example, [::]:8083 or 127.0.0.1:8083 Default is `[::]:8083`.",
"option": "address",
"shorthand": "",
"value_type": "string"
},
{
"description": "run server as a background process. This is mutually exclusive with --foreground.",
"option": "background",
N/A
N/A
N/A
{
"command": "ffx repository server start",
"options": [
{
"description": "address on which to serve the repository. Note that this can be either IPV4 or IPV6. For example, [::]:8083 or 127.0.0.1:8083 Default is `[::]:8083`.",
"option": "address",
"shorthand": "",
"value_type": "string"
},
{
"description": "run server as a background process. This is mutually exclusive with --foreground.",
"option": "background",
N/A
N/A
N/A
{
"command": "ffx repository server start",
"options": [
{
"description": "address on which to serve the repository. Note that this can be either IPV4 or IPV6. For example, [::]:8083 or 127.0.0.1:8083 Default is `[::]:8083`.",
"option": "address",
"shorthand": "",
"value_type": "string"
},
{
"description": "run server as a background process. This is mutually exclusive with --foreground.",
"option": "background",
// Copyright 2023 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use anyhow::{Context as _, ensure};
N/A
N/A
{
"command": "ffx repository server start",
"options": [
{
"description": "address on which to serve the repository. Note that this can be either IPV4 or IPV6. For example, [::]:8083 or 127.0.0.1:8083 Default is `[::]:8083`.",
"option": "address",
"shorthand": "",
"value_type": "string"
},
{
"description": "run server as a background process. This is mutually exclusive with --foreground.",
"option": "background",
// Copyright 2023 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use anyhow::{Context as _, ensure};
N/A
N/A
{
"command": "ffx repository server start",
"options": [
{
"description": "address on which to serve the repository. Note that this can be either IPV4 or IPV6. For example, [::]:8083 or 127.0.0.1:8083 Default is `[::]:8083`.",
"option": "address",
"shorthand": "",
"value_type": "string"
},
{
"description": "run server as a background process. This is mutually exclusive with --foreground.",
"option": "background",
N/A
N/A
N/A
{
"command": "ffx repository server start",
"options": [
{
"description": "address on which to serve the repository. Note that this can be either IPV4 or IPV6. For example, [::]:8083 or 127.0.0.1:8083 Default is `[::]:8083`.",
"option": "address",
"shorthand": "",
"value_type": "string"
},
{
"description": "run server as a background process. This is mutually exclusive with --foreground.",
"option": "background",
N/A
N/A
N/A
{
"command": "ffx repository server start",
"options": [
{
"description": "address on which to serve the repository. Note that this can be either IPV4 or IPV6. For example, [::]:8083 or 127.0.0.1:8083 Default is `[::]:8083`.",
"option": "address",
"shorthand": "",
"value_type": "string"
},
{
"description": "run server as a background process. This is mutually exclusive with --foreground.",
"option": "background",
N/A
N/A
N/A
{
"command": "ffx repository server stop",
"options": [
{
"description": "stop all repository servers.",
"option": "all",
"shorthand": "",
"value_type": "bool"
},
{
"description": "stop servers serving the product bundle location.",
"option": "product-bundle",
#[fuchsia::test]
async fn test_standalone_stop() {
let env = ffx_config::test_init().unwrap();
env.context
.query("repository.process_dir")
.level(Some(ConfigLevel::User))
.build()
.set(
&env.context,
env.isolate_root.path().join("repo_servers").to_string_lossy().into(),
)
.expect("setting isolated process dir");
let (_mgr, _server_proc) =
make_standalone_instance("default".into(), None, &env.context, &env)
.expect("test daemon instance");
let tool = RepoStopTool {
context: env.context.clone(),
cmd: StopCommand { all: true, name: None, port: None, product_bundle: None },
};
let buffers = ffx_writer::TestBuffers::default();
let writer = <RepoStopTool as FfxMain>::Writer::new_test(None, &buffers);
let res = tool.main(writer).await;
let (stdout, stderr) = buffers.into_strings();
assert_eq!(stdout, "Stopped the repository server\n");
assert_eq!(stderr, "");
assert!(res.is_ok());
#[fuchsia::test]
async fn test_product_bundle_stop() {
let env = ffx_config::test_init().unwrap();
env.context
.query("repository.process_dir")
.level(Some(ConfigLevel::User))
.build()
.set(
&env.context,
env.isolate_root.path().join("repo_servers").to_string_lossy().into(),
)
.expect("setting isolated process dir");
let product_bundle_path =
Utf8PathBuf::from_path_buf(env.isolate_root.path().join("pb")).expect("utf8 path");
let (_mgr, mut server_proc) = make_standalone_instance(
"some-pb.com".into(),
Some(product_bundle_path.clone()),
&env.context,
&env,
)
.expect("test daemon instance");
let tool = RepoStopTool {
context: env.context.clone(),
cmd: StopCommand {
all: false,
name: None,
N/A
N/A
{
"command": "ffx repository server stop",
"options": [
{
"description": "stop all repository servers.",
"option": "all",
"shorthand": "",
"value_type": "bool"
},
{
"description": "stop servers serving the product bundle location.",
"option": "product-bundle",
N/A
N/A
N/A
{
"command": "ffx repository server stop",
"options": [
{
"description": "stop all repository servers.",
"option": "all",
"shorthand": "",
"value_type": "bool"
},
{
"description": "stop servers serving the product bundle location.",
"option": "product-bundle",
N/A
N/A
N/A
{
"command": "ffx repository server stop",
"options": [
{
"description": "stop all repository servers.",
"option": "all",
"shorthand": "",
"value_type": "bool"
},
{
"description": "stop servers serving the product bundle location.",
"option": "product-bundle",
N/A
N/A
N/A
{
"command": "ffx scrutiny",
"options": [],
"short": "Audit the security of Fuchsia"
}
// Copyright 2022 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use std::process::Command;
use tempfile::TempDir;
const FFX_TOOL_PATH: &str = env!("FFX_TOOL_PATH");
const BLOBFS_PATH: &str = env!("BLOBFS_PATH");
const ZBI_PATH: &str = env!("ZBI_PATH");
const RECOVERY_ZBI_PATH: &str = env!("RECOVERY_ZBI_PATH");
#[test]
fn extract_blobfs() {
let tmp_dir = TempDir::new().unwrap();
let tmp_path = tmp_dir.path().to_str().unwrap();
assert!(Command::new(FFX_TOOL_PATH)
.args(vec![
"scrutiny",
"shell",
&format!("tool.blobfs.extract --input {} --output {}/blobfs", BLOBFS_PATH, tmp_path),
])
.status()
.unwrap()
.success());
}
#[test]
fn extract_blobfs() {
let tmp_dir = TempDir::new().unwrap();
let tmp_path = tmp_dir.path().to_str().unwrap();
assert!(Command::new(FFX_TOOL_PATH)
.args(vec![
"scrutiny",
"shell",
&format!("tool.blobfs.extract --input {} --output {}/blobfs", BLOBFS_PATH, tmp_path),
])
.status()
.unwrap()
.success());
}
#[test]
fn extract_zbi() {
let tmp_dir = TempDir::new().unwrap();
let tmp_path = tmp_dir.path().to_str().unwrap();
assert!(Command::new(FFX_TOOL_PATH)
.args(vec![
"scrutiny",
"shell",
&format!("tool.zbi.extract --input {} --output {}/zbi", ZBI_PATH, tmp_path),
])
.status()
.unwrap()
.success());
}
N/A
{
"command": "ffx scrutiny extract",
"options": [],
"short": "Extracts common Fuchsia file types"
}
N/A
N/A
{
"command": "ffx scrutiny extract blobfs",
"options": [],
"short": "Extracts a Blobfs block file"
}
N/A
```posix-terminal
N/A
{
"command": "ffx scrutiny extract fvm",
"options": [],
"short": "Extracts a FVM file"
}
N/A
```posix-terminal
N/A
{
"command": "ffx scrutiny extract package",
"options": [
{
"description": "a path to a product bundle that contains the package.",
"option": "product-bundle",
"shorthand": "",
"value_type": "string"
},
{
"description": "the package url.",
"option": "url",
N/A
```posix-terminal
N/A
{
"command": "ffx scrutiny extract package",
"options": [
{
"description": "a path to a product bundle that contains the package.",
"option": "product-bundle",
"shorthand": "",
"value_type": "string"
},
{
"description": "the package url.",
"option": "url",
N/A
```posix-terminal
N/A
{
"command": "ffx scrutiny extract package",
"options": [
{
"description": "a path to a product bundle that contains the package.",
"option": "product-bundle",
"shorthand": "",
"value_type": "string"
},
{
"description": "the package url.",
"option": "url",
N/A
```posix-terminal
N/A
{
"command": "ffx scrutiny extract package",
"options": [
{
"description": "a path to a product bundle that contains the package.",
"option": "product-bundle",
"shorthand": "",
"value_type": "string"
},
{
"description": "the package url.",
"option": "url",
N/A
N/A
N/A
{
"command": "ffx scrutiny extract package",
"options": [
{
"description": "a path to a product bundle that contains the package.",
"option": "product-bundle",
"shorthand": "",
"value_type": "string"
},
{
"description": "the package url.",
"option": "url",
N/A
```posix-terminal
N/A
{
"command": "ffx scrutiny extract structured-config",
"options": [
{
"description": "path to a product bundle.",
"option": "product-bundle",
"shorthand": "",
"value_type": "string"
},
{
"description": "path to the build directory which is used to rebase the paths in the depfile.",
"option": "build-path",
N/A
N/A
N/A
{
"command": "ffx scrutiny extract structured-config",
"options": [
{
"description": "path to a product bundle.",
"option": "product-bundle",
"shorthand": "",
"value_type": "string"
},
{
"description": "path to the build directory which is used to rebase the paths in the depfile.",
"option": "build-path",
N/A
N/A
N/A
{
"command": "ffx scrutiny extract structured-config",
"options": [
{
"description": "path to a product bundle.",
"option": "product-bundle",
"shorthand": "",
"value_type": "string"
},
{
"description": "path to the build directory which is used to rebase the paths in the depfile.",
"option": "build-path",
N/A
N/A
N/A
{
"command": "ffx scrutiny extract structured-config",
"options": [
{
"description": "path to a product bundle.",
"option": "product-bundle",
"shorthand": "",
"value_type": "string"
},
{
"description": "path to the build directory which is used to rebase the paths in the depfile.",
"option": "build-path",
N/A
N/A
N/A
{
"command": "ffx scrutiny extract structured-config",
"options": [
{
"description": "path to a product bundle.",
"option": "product-bundle",
"shorthand": "",
"value_type": "string"
},
{
"description": "path to the build directory which is used to rebase the paths in the depfile.",
"option": "build-path",
N/A
N/A
N/A
{
"command": "ffx scrutiny extract structured-config",
"options": [
{
"description": "path to a product bundle.",
"option": "product-bundle",
"shorthand": "",
"value_type": "string"
},
{
"description": "path to the build directory which is used to rebase the paths in the depfile.",
"option": "build-path",
N/A
N/A
N/A
{
"command": "ffx scrutiny extract structured-config",
"options": [
{
"description": "path to a product bundle.",
"option": "product-bundle",
"shorthand": "",
"value_type": "string"
},
{
"description": "path to the build directory which is used to rebase the paths in the depfile.",
"option": "build-path",
N/A
N/A
N/A
{
"command": "ffx scrutiny extract zbi",
"options": [],
"short": "Extracts the Zircon Boot Image"
}
N/A
```posix-terminal
N/A
{
"command": "ffx scrutiny list",
"options": [],
"short": "Lists properties about build artifacts"
}
N/A
```posix-terminal
```posix-terminal
```posix-terminal
N/A
{
"command": "ffx scrutiny list components",
"options": [
{
"description": "path to a product bundle.",
"option": "product-bundle",
"shorthand": "",
"value_type": "string"
},
{
"description": "build scrutiny model based on recovery-mode build artifacts.",
"option": "recovery",
N/A
```posix-terminal
N/A
{
"command": "ffx scrutiny list components",
"options": [
{
"description": "path to a product bundle.",
"option": "product-bundle",
"shorthand": "",
"value_type": "string"
},
{
"description": "build scrutiny model based on recovery-mode build artifacts.",
"option": "recovery",
N/A
```posix-terminal
N/A
{
"command": "ffx scrutiny list components",
"options": [
{
"description": "path to a product bundle.",
"option": "product-bundle",
"shorthand": "",
"value_type": "string"
},
{
"description": "build scrutiny model based on recovery-mode build artifacts.",
"option": "recovery",
N/A
N/A
N/A
{
"command": "ffx scrutiny list package",
"options": [
{
"description": "path to a product bundle.",
"option": "product-bundle",
"shorthand": "",
"value_type": "string"
},
{
"description": "fuchsia url to the package.",
"option": "url",
N/A
```posix-terminal
N/A
{
"command": "ffx scrutiny list package",
"options": [
{
"description": "path to a product bundle.",
"option": "product-bundle",
"shorthand": "",
"value_type": "string"
},
{
"description": "fuchsia url to the package.",
"option": "url",
N/A
```posix-terminal
N/A
{
"command": "ffx scrutiny list package",
"options": [
{
"description": "path to a product bundle.",
"option": "product-bundle",
"shorthand": "",
"value_type": "string"
},
{
"description": "fuchsia url to the package.",
"option": "url",
N/A
N/A
N/A
{
"command": "ffx scrutiny list package",
"options": [
{
"description": "path to a product bundle.",
"option": "product-bundle",
"shorthand": "",
"value_type": "string"
},
{
"description": "fuchsia url to the package.",
"option": "url",
N/A
```posix-terminal
N/A
{
"command": "ffx scrutiny list packages",
"options": [
{
"description": "path to a product bundle.",
"option": "product-bundle",
"shorthand": "",
"value_type": "string"
},
{
"description": "build scrutiny model based on recovery-mode build artifacts.",
"option": "recovery",
N/A
```posix-terminal
N/A
{
"command": "ffx scrutiny list packages",
"options": [
{
"description": "path to a product bundle.",
"option": "product-bundle",
"shorthand": "",
"value_type": "string"
},
{
"description": "build scrutiny model based on recovery-mode build artifacts.",
"option": "recovery",
N/A
```posix-terminal
N/A
{
"command": "ffx scrutiny list packages",
"options": [
{
"description": "path to a product bundle.",
"option": "product-bundle",
"shorthand": "",
"value_type": "string"
},
{
"description": "build scrutiny model based on recovery-mode build artifacts.",
"option": "recovery",
N/A
N/A
N/A
{
"command": "ffx scrutiny shell",
"options": [],
"short": "Launch the scrutiny shell"
}
#[test]
fn test_parse_command() {
assert_eq!(parse_command("foo".into()).is_ok(), false);
assert_eq!(
parse_command("foo --input in".into()).unwrap(),
("foo".into(), ToolArgs { input: "in".into(), output: None })
);
assert_eq!(
parse_command("foo --input in --output out".into()).unwrap(),
("foo".into(), ToolArgs { input: "in".into(), output: Some("out".into()) })
);
assert_eq!(parse_command("foo --output out".into()).is_ok(), false);
}
// Copyright 2022 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use std::process::Command;
use tempfile::TempDir;
const FFX_TOOL_PATH: &str = env!("FFX_TOOL_PATH");
const BLOBFS_PATH: &str = env!("BLOBFS_PATH");
const ZBI_PATH: &str = env!("ZBI_PATH");
const RECOVERY_ZBI_PATH: &str = env!("RECOVERY_ZBI_PATH");
#[test]
fn extract_blobfs() {
let tmp_dir = TempDir::new().unwrap();
let tmp_path = tmp_dir.path().to_str().unwrap();
assert!(Command::new(FFX_TOOL_PATH)
.args(vec![
"scrutiny",
"shell",
&format!("tool.blobfs.extract --input {} --output {}/blobfs", BLOBFS_PATH, tmp_path),
])
.status()
.unwrap()
.success());
}
#[test]
fn extract_blobfs() {
let tmp_dir = TempDir::new().unwrap();
let tmp_path = tmp_dir.path().to_str().unwrap();
assert!(Command::new(FFX_TOOL_PATH)
.args(vec![
"scrutiny",
"shell",
&format!("tool.blobfs.extract --input {} --output {}/blobfs", BLOBFS_PATH, tmp_path),
])
.status()
.unwrap()
.success());
}
```posix-terminal
N/A
{
"command": "ffx scrutiny verify",
"options": [
{
"description": "path to depfile that gathers dependencies during execution.",
"option": "depfile",
"shorthand": "",
"value_type": "string"
},
{
"description": "path to stamp file to write to if and only if verification succeeds.",
"option": "stamp",
The `ffx scrutiny verify` command has a number of subcommands that perform different verification procedures against build artifacts. The command performs some common logic before and after delegating execution to subcommands. This pattern requires that there be a single ffx plugin that encapsulates all arguments and subcommands.
N/A
N/A
{
"command": "ffx scrutiny verify",
"options": [
{
"description": "path to depfile that gathers dependencies during execution.",
"option": "depfile",
"shorthand": "",
"value_type": "string"
},
{
"description": "path to stamp file to write to if and only if verification succeeds.",
"option": "stamp",
N/A
N/A
N/A
{
"command": "ffx scrutiny verify",
"options": [
{
"description": "path to depfile that gathers dependencies during execution.",
"option": "depfile",
"shorthand": "",
"value_type": "string"
},
{
"description": "path to stamp file to write to if and only if verification succeeds.",
"option": "stamp",
N/A
N/A
N/A
{
"command": "ffx scrutiny verify",
"options": [
{
"description": "path to depfile that gathers dependencies during execution.",
"option": "depfile",
"shorthand": "",
"value_type": "string"
},
{
"description": "path to stamp file to write to if and only if verification succeeds.",
"option": "stamp",
N/A
N/A
N/A
{
"command": "ffx scrutiny verify",
"options": [
{
"description": "path to depfile that gathers dependencies during execution.",
"option": "depfile",
"shorthand": "",
"value_type": "string"
},
{
"description": "path to stamp file to write to if and only if verification succeeds.",
"option": "stamp",
N/A
N/A
N/A
{
"command": "ffx scrutiny verify bootfs",
"options": [
{
"description": "absolute or working directory-relative path to a product bundle.",
"option": "product-bundle",
"shorthand": "",
"value_type": "string"
},
{
"description": "absolute or working directory-relative path(s) to golden file(s) for verifying bootfs paths.",
"option": "golden",
N/A
```posix-terminal
N/A
{
"command": "ffx scrutiny verify bootfs",
"options": [
{
"description": "absolute or working directory-relative path to a product bundle.",
"option": "product-bundle",
"shorthand": "",
"value_type": "string"
},
{
"description": "absolute or working directory-relative path(s) to golden file(s) for verifying bootfs paths.",
"option": "golden",
N/A
N/A
N/A
{
"command": "ffx scrutiny verify bootfs",
"options": [
{
"description": "absolute or working directory-relative path to a product bundle.",
"option": "product-bundle",
"shorthand": "",
"value_type": "string"
},
{
"description": "absolute or working directory-relative path(s) to golden file(s) for verifying bootfs paths.",
"option": "golden",
N/A
N/A
N/A
{
"command": "ffx scrutiny verify bootfs",
"options": [
{
"description": "absolute or working directory-relative path to a product bundle.",
"option": "product-bundle",
"shorthand": "",
"value_type": "string"
},
{
"description": "absolute or working directory-relative path(s) to golden file(s) for verifying bootfs paths.",
"option": "golden",
N/A
N/A
N/A
{
"command": "ffx scrutiny verify component-resolvers",
"options": [
{
"description": "absolute or working directory-relative path to a product bundle.",
"option": "product-bundle",
"shorthand": "",
"value_type": "string"
},
{
"description": "absolute or working directory-relative path to allowlist file that specifies which components may use particular custom component resolvers.",
"option": "allowlist",
#[test]
fn fails_on_invalid_response() {
let allowlist = parse_allowlist(
r#"[
{
scheme: "fuchsia-pkg",
moniker: "/core/full-resolver",
protocol: "fuchsia.pkg.PackageResolver",
components: [
],
},
]"#,
);
let scrutiny = MockQueryComponentResolvers::new().with_raw_response(
(
"fuchsia-pkg".to_owned(),
"/core/full-resolver".to_owned(),
"fuchsia.pkg.PackageResolver".to_owned(),
),
"invalid".to_owned(),
);
assert_matches!(verify_component_resolvers(scrutiny, allowlist), Err(_));
}
#[test]
fn reports_unexpected_entry() {
let allowlist = parse_allowlist(
r#"[
{
scheme: "fuchsia-pkg",
moniker: "/core/full-resolver",
protocol: "fuchsia.pkg.PackageResolver",
components: [
"/core/allowed",
],
},
]"#,
);
let violations = parse_allowlist(
r#"[
{
scheme: "fuchsia-pkg",
moniker: "/core/full-resolver",
protocol: "fuchsia.pkg.PackageResolver",
components: [
"/core/stopme",
],
},
]"#,
);
let scrutiny = MockQueryComponentResolvers::new().with_response(
#[test]
fn ignores_unused_allow() {
let allowlist = parse_allowlist(
r#"[
{
scheme: "fuchsia-pkg",
moniker: "/core/full-resolver",
protocol: "fuchsia.pkg.PackageResolver",
components: [
"/core/allowed",
"/core/also-allowed",
],
},
]"#,
);
let scrutiny = MockQueryComponentResolvers::new().with_response(
(
"fuchsia-pkg".to_owned(),
"/core/full-resolver".to_owned(),
"fuchsia.pkg.PackageResolver".to_owned(),
),
vec!["/core/allowed".to_owned(), "/core/also-allowed".to_owned()],
vec!["path/to/dep.zbi".to_owned()],
);
let expected_deps = vec!["path/to/dep.zbi".to_string().into()].into_iter().collect();
assert_eq!(verify_component_resolvers(scrutiny, allowlist).unwrap(), Ok(expected_deps));
}
```posix-terminal
N/A
{
"command": "ffx scrutiny verify component-resolvers",
"options": [
{
"description": "absolute or working directory-relative path to a product bundle.",
"option": "product-bundle",
"shorthand": "",
"value_type": "string"
},
{
"description": "absolute or working directory-relative path to allowlist file that specifies which components may use particular custom component resolvers.",
"option": "allowlist",
N/A
```posix-terminal
N/A
{
"command": "ffx scrutiny verify component-resolvers",
"options": [
{
"description": "absolute or working directory-relative path to a product bundle.",
"option": "product-bundle",
"shorthand": "",
"value_type": "string"
},
{
"description": "absolute or working directory-relative path to allowlist file that specifies which components may use particular custom component resolvers.",
"option": "allowlist",
N/A
```posix-terminal
N/A
{
"command": "ffx scrutiny verify kernel-cmdline",
"options": [
{
"description": "absolute or working directory-relative path to a product bundle.",
"option": "product-bundle",
"shorthand": "",
"value_type": "string"
},
{
"description": "absolute or working directory-relative path(s) to golden files to compare against during verification.",
"option": "golden",
N/A
```posix-terminal
N/A
{
"command": "ffx scrutiny verify kernel-cmdline",
"options": [
{
"description": "absolute or working directory-relative path to a product bundle.",
"option": "product-bundle",
"shorthand": "",
"value_type": "string"
},
{
"description": "absolute or working directory-relative path(s) to golden files to compare against during verification.",
"option": "golden",
N/A
N/A
N/A
{
"command": "ffx scrutiny verify kernel-cmdline",
"options": [
{
"description": "absolute or working directory-relative path to a product bundle.",
"option": "product-bundle",
"shorthand": "",
"value_type": "string"
},
{
"description": "absolute or working directory-relative path(s) to golden files to compare against during verification.",
"option": "golden",
N/A
N/A
N/A
{
"command": "ffx scrutiny verify pre-signing",
"options": [
{
"description": "path to a signing validation policy file",
"option": "policy",
"shorthand": "",
"value_type": "string"
},
{
"description": "path to the product bundle for the build to validate",
"option": "product-bundle",
N/A
```posix-terminal
N/A
{
"command": "ffx scrutiny verify pre-signing",
"options": [
{
"description": "path to a signing validation policy file",
"option": "policy",
"shorthand": "",
"value_type": "string"
},
{
"description": "path to the product bundle for the build to validate",
"option": "product-bundle",
N/A
N/A
N/A
{
"command": "ffx scrutiny verify pre-signing",
"options": [
{
"description": "path to a signing validation policy file",
"option": "policy",
"shorthand": "",
"value_type": "string"
},
{
"description": "path to the product bundle for the build to validate",
"option": "product-bundle",
N/A
N/A
N/A
{
"command": "ffx scrutiny verify pre-signing",
"options": [
{
"description": "path to a signing validation policy file",
"option": "policy",
"shorthand": "",
"value_type": "string"
},
{
"description": "path to the product bundle for the build to validate",
"option": "product-bundle",
N/A
N/A
N/A
{
"command": "ffx scrutiny verify route-sources",
"options": [
{
"description": "absolute or working directory-relative path to a product bundle.",
"option": "product-bundle",
"shorthand": "",
"value_type": "string"
},
{
"description": "absolute or working directory-relative path to configuration file that specifies components and their expected route sources.",
"option": "config",
N/A
```posix-terminal
N/A
{
"command": "ffx scrutiny verify route-sources",
"options": [
{
"description": "absolute or working directory-relative path to a product bundle.",
"option": "product-bundle",
"shorthand": "",
"value_type": "string"
},
{
"description": "absolute or working directory-relative path to configuration file that specifies components and their expected route sources.",
"option": "config",
N/A
N/A
N/A
{
"command": "ffx scrutiny verify route-sources",
"options": [
{
"description": "absolute or working directory-relative path to a product bundle.",
"option": "product-bundle",
"shorthand": "",
"value_type": "string"
},
{
"description": "absolute or working directory-relative path to configuration file that specifies components and their expected route sources.",
"option": "config",
N/A
N/A
N/A
{
"command": "ffx scrutiny verify routes",
"options": [
{
"description": "capability types to verify.",
"option": "capability-type",
"shorthand": "",
"value_type": "string"
},
{
"description": "response level to report from routes scrutiny plugin.",
"option": "response-level",
N/A
```posix-terminal
N/A
{
"command": "ffx scrutiny verify routes",
"options": [
{
"description": "capability types to verify.",
"option": "capability-type",
"shorthand": "",
"value_type": "string"
},
{
"description": "response level to report from routes scrutiny plugin.",
"option": "response-level",
N/A
N/A
N/A
{
"command": "ffx scrutiny verify routes",
"options": [
{
"description": "capability types to verify.",
"option": "capability-type",
"shorthand": "",
"value_type": "string"
},
{
"description": "response level to report from routes scrutiny plugin.",
"option": "response-level",
N/A
N/A
N/A
{
"command": "ffx scrutiny verify routes",
"options": [
{
"description": "capability types to verify.",
"option": "capability-type",
"shorthand": "",
"value_type": "string"
},
{
"description": "response level to report from routes scrutiny plugin.",
"option": "response-level",
N/A
N/A
N/A
{
"command": "ffx scrutiny verify routes",
"options": [
{
"description": "capability types to verify.",
"option": "capability-type",
"shorthand": "",
"value_type": "string"
},
{
"description": "response level to report from routes scrutiny plugin.",
"option": "response-level",
N/A
N/A
N/A
{
"command": "ffx scrutiny verify static-pkgs",
"options": [
{
"description": "path to a product bundle.",
"option": "product-bundle",
"shorthand": "",
"value_type": "string"
},
{
"description": "path(s) to golden file(s) used to verify routes.",
"option": "golden",
N/A
```posix-terminal
N/A
{
"command": "ffx scrutiny verify static-pkgs",
"options": [
{
"description": "path to a product bundle.",
"option": "product-bundle",
"shorthand": "",
"value_type": "string"
},
{
"description": "path(s) to golden file(s) used to verify routes.",
"option": "golden",
N/A
```posix-terminal
N/A
{
"command": "ffx scrutiny verify static-pkgs",
"options": [
{
"description": "path to a product bundle.",
"option": "product-bundle",
"shorthand": "",
"value_type": "string"
},
{
"description": "path(s) to golden file(s) used to verify routes.",
"option": "golden",
N/A
```posix-terminal
N/A
{
"command": "ffx scrutiny verify structured-config",
"options": [
{
"description": "absolute or working directory-relative path to a policy file for structured configuration",
"option": "policy",
"shorthand": "",
"value_type": "string"
},
{
"description": "path to a product bundle.",
"option": "product-bundle",
N/A
```posix-terminal
N/A
{
"command": "ffx scrutiny verify structured-config",
"options": [
{
"description": "absolute or working directory-relative path to a policy file for structured configuration",
"option": "policy",
"shorthand": "",
"value_type": "string"
},
{
"description": "path to a product bundle.",
"option": "product-bundle",
N/A
N/A
N/A
{
"command": "ffx scrutiny verify structured-config",
"options": [
{
"description": "absolute or working directory-relative path to a policy file for structured configuration",
"option": "policy",
"shorthand": "",
"value_type": "string"
},
{
"description": "path to a product bundle.",
"option": "product-bundle",
N/A
N/A
N/A
{
"command": "ffx scrutiny verify structured-config",
"options": [
{
"description": "absolute or working directory-relative path to a policy file for structured configuration",
"option": "policy",
"shorthand": "",
"value_type": "string"
},
{
"description": "path to a product bundle.",
"option": "product-bundle",
N/A
N/A
N/A
{
"command": "ffx sdk",
"options": [],
"short": "Modify or query the installed SDKs"
}
#[test]
fn test_manifest_exists() {
let release_root = sdk_test_data_root();
assert!(
SdkRoot::Full {
root: release_root.path().to_owned(),
manifest: Some(SDK_MANIFEST_PATH.into())
}
.manifest_path()
.is_some()
);
}
#[fuchsia::test]
fn test_sdk_manifest() {
let root = sdk_test_data_root();
let sdk_root = root.path();
let manifest: Manifest = serde_json::from_reader(BufReader::new(
fs::File::open(sdk_root.join(SDK_MANIFEST_PATH)).unwrap(),
))
.unwrap();
assert_eq!("0.20201005.4.1", manifest.id);
let mut parts = manifest.parts.iter();
assert!(matches!(parts.next().unwrap(), Part { kind: ElementType::FidlLibrary, .. }));
assert!(matches!(parts.next().unwrap(), Part { kind: ElementType::HostTool, .. }));
assert!(matches!(parts.next().unwrap(), Part { kind: ElementType::FfxTool, .. }));
assert!(parts.next().is_none());
}
#[fuchsia::test]
fn test_sdk_manifest_host_tool() {
let root = sdk_test_data_root();
let sdk_root = root.path();
let manifest: Manifest = serde_json::from_reader(BufReader::new(
fs::File::open(sdk_root.join(SDK_MANIFEST_PATH)).unwrap(),
))
.unwrap();
let expected = sdk_root.join("tools/zxdb");
fs::write(&expected, "#!/bin/bash\n echo hello").expect("fake host tool");
let sdk = Sdk {
path_prefix: sdk_root.to_owned(),
module: None,
parts: manifest.parts,
real_paths: None,
version: SdkVersion::Version(manifest.id.to_owned()),
};
let zxdb = sdk.get_host_tool("zxdb").unwrap();
assert_eq!(expected, zxdb);
let zxdb_cmd = sdk.get_host_tool_command("zxdb").unwrap();
assert_eq!(zxdb_cmd.get_program(), sdk_root.join("tools/zxdb"));
}
N/A
N/A
{
"command": "ffx sdk populate-path",
"options": [],
"short": "Populates the given path with symlinks to the `fuchsha-sdk-run` tool to run project-specific sdk tools"
}
N/A
N/A
N/A
{
"command": "ffx sdk run",
"options": [],
"short": "Run a host tool from the active sdk"
}
N/A
N/A
N/A
{
"command": "ffx sdk set",
"options": [],
"short": "Set sdk-related configuration options"
}
N/A
N/A
N/A
{
"command": "ffx sdk set root",
"options": [],
"short": "Sets the path to the root of the preferred SDK"
}
N/A
N/A
N/A
{
"command": "ffx sdk version",
"options": [],
"short": "Retrieve the version of the current SDK"
}
N/A
N/A
N/A
{
"command": "ffx session",
"options": [],
"short": "Control the session component."
}
self._ffx.run(
["session", "start"], machine=ffx_types.MachineFormat.RAW
)
except ffx_errors.FfxCommandError as err:
raise session_errors.SessionError(err)
_LOGGER.info("wait for session started on device %s", self._name)
# wait for session started.
while not self.is_started():
time.sleep(1) # second.
_LOGGER.info("session started on device %s", self._name)
def is_started(self) -> bool:
"""Check if session is started.
Returns:
True if session is started.
Raises:
SessionError: failed to check the session state.
"""
try:
res = self._ffx.run(
["session", "show"], machine=ffx_types.MachineFormat.RAW
)
lines = res.splitlines()
for line in lines:
if "Execution State: Running" in line:
res = self._ffx.run(
["session", "show"], machine=ffx_types.MachineFormat.RAW
)
lines = res.splitlines()
for line in lines:
if "Execution State: Running" in line:
return True
except ffx_errors.FfxCommandError as err:
if (
'No matching component instance found for query "core/session-manager/session:session"'
in str(err)
):
# session is not running.
return False
raise session_errors.SessionError(err)
return False
def ensure_started(self) -> None:
"""Ensure session started, if not start a session. Wait indefinitely until session
started.
Raises:
honeydew.errors.SessionError: session failed to check or start.
"""
if not self.is_started():
_LOGGER.info("session not started on device %s", self._name)
self.start()
self._ffx.run(
["session", "add", url], machine=ffx_types.MachineFormat.RAW
)
except ffx_errors.FfxCommandError as err:
raise session_errors.SessionError(err)
def restart(self) -> None:
"""Restart session.
`ffx session restart` is only allow to call when session is started.
Raises:
honeydew.errors.SessionError: session failed to restart.
"""
if not self.is_started():
raise session_errors.SessionError("session is not started.")
_LOGGER.info("restart session on device %s", self._name)
try:
self._ffx.run(
["session", "restart"], machine=ffx_types.MachineFormat.RAW
)
except ffx_errors.FfxCommandError as err:
raise session_errors.SessionError(err)
_LOGGER.info("wait for session started on device %s", self._name)
# wait for session started.
while not self.is_started():
```posix-terminal
```posix-terminal
N/A
{
"command": "ffx session add",
"options": [
{
"description": "pass to keep element alive until command exits",
"option": "interactive",
"shorthand": "",
"value_type": "bool"
},
{
"description": "pass to have the element persist over reboots",
"option": "persist",
#[fuchsia::test]
async fn test_add_element() {
const TEST_ELEMENT_URL: &str = "Test Element Url";
let client = fdomain_local::local_client_empty();
let proxy = fake_proxy(client, |req| match req {
ManagerRequest::ProposeElement { spec, responder, .. } => {
assert_eq!(spec.component_url.unwrap(), TEST_ELEMENT_URL.to_string());
let _ = responder.send(Ok(()));
}
ManagerRequest::RemoveElement { .. } => unreachable!(),
});
let add_cmd = SessionAddCommand {
url: TEST_ELEMENT_URL.to_string(),
interactive: false,
persist: false,
name: None,
};
let response = add_impl(proxy, add_cmd, async {}.boxed(), &mut std::io::stdout()).await;
assert!(response.is_ok());
}
#[fuchsia::test]
async fn test_add_element_args() {
const TEST_ELEMENT_URL: &str = "Test Element Url";
let client = fdomain_local::local_client_empty();
let proxy = fake_proxy(client, |req| match req {
ManagerRequest::ProposeElement { responder, .. } => {
let _ = responder.send(Ok(()));
}
ManagerRequest::RemoveElement { .. } => unreachable!(),
});
let add_cmd = SessionAddCommand {
url: TEST_ELEMENT_URL.to_string(),
interactive: false,
persist: false,
name: None,
};
let response = add_impl(proxy, add_cmd, async {}.boxed(), &mut std::io::stdout()).await;
assert!(response.is_ok());
}
#[fuchsia::test]
async fn test_add_interactive_element_stop_with_ctrl_c() {
const TEST_ELEMENT_URL: &str = "Test Element Url";
let client = fdomain_local::local_client_empty();
let proxy = fake_proxy(client, move |req| match req {
ManagerRequest::ProposeElement { responder, .. } => {
responder.send(Ok(())).unwrap();
}
ManagerRequest::RemoveElement { .. } => unreachable!(),
});
let add_cmd = SessionAddCommand {
url: TEST_ELEMENT_URL.to_string(),
interactive: true,
persist: false,
name: None,
};
let (ctrl_c_sender, ctrl_c_receiver) = oneshot::channel();
let mut stdout = std::io::stdout();
let mut add_fut =
Box::pin(add_impl(proxy, add_cmd, ctrl_c_receiver.map(|_| ()), &mut stdout));
assert!(poll!(&mut add_fut).is_pending(), "add should yield until ctrl+c");
// Send ctrl+c so add will exit.
ctrl_c_sender.send(()).unwrap();
let result = add_fut.await;
assert!(result.is_ok());
```posix-terminal
N/A
{
"command": "ffx session add",
"options": [
{
"description": "pass to keep element alive until command exits",
"option": "interactive",
"shorthand": "",
"value_type": "bool"
},
{
"description": "pass to have the element persist over reboots",
"option": "persist",
N/A
N/A
N/A
{
"command": "ffx session add",
"options": [
{
"description": "pass to keep element alive until command exits",
"option": "interactive",
"shorthand": "",
"value_type": "bool"
},
{
"description": "pass to have the element persist over reboots",
"option": "persist",
N/A
N/A
N/A
{
"command": "ffx session add",
"options": [
{
"description": "pass to keep element alive until command exits",
"option": "interactive",
"shorthand": "",
"value_type": "bool"
},
{
"description": "pass to have the element persist over reboots",
"option": "persist",
N/A
N/A
N/A
{
"command": "ffx session drop-power-lease",
"options": [
{
"description": "if true, the tool will not return an error if the lease has already been dropped",
"option": "allow-missing",
"shorthand": "",
"value_type": "bool"
}
],
"short": "Drop the power lease reserved for the current session component."
}
#[fuchsia::test]
async fn test_drop_power_lease() {
let client = fdomain_local::local_client_empty();
let client_clone = std::sync::Arc::clone(&client);
let proxy = fake_proxy(client, move |req| match req {
HandoffRequest::Take { responder } => {
let _ = responder.send(Ok(client_clone.create_event().into()));
}
x @ _ => unimplemented!("{x:?}"),
});
let drop_power_lease_cmd = SessionDropPowerLeaseCommand { allow_missing: false };
let mut writer = Vec::new();
let result = drop_power_lease_impl(proxy, drop_power_lease_cmd, &mut writer).await;
assert!(result.is_ok());
let output = String::from_utf8(writer).unwrap();
assert_eq!(output, "Requesting to dropping power lease on execution state\nSuccess!\n");
}
#[fuchsia::test]
async fn test_drop_power_lease_already_taken_error() {
let client = fdomain_local::local_client_empty();
let proxy = fake_proxy(std::sync::Arc::clone(&client), |req| match req {
HandoffRequest::Take { responder } => {
let _ =
responder.send(Err(fdomain_fuchsia_session_power::HandoffError::AlreadyTaken));
}
x @ _ => unimplemented!("{x:?}"),
});
let drop_power_lease_cmd = SessionDropPowerLeaseCommand { allow_missing: false };
let mut writer = Vec::new();
let result = drop_power_lease_impl(proxy, drop_power_lease_cmd, &mut writer).await;
assert!(result.is_err());
}
#[fuchsia::test]
async fn test_drop_power_lease_already_taken_allow_missing() {
let client = fdomain_local::local_client_empty();
let proxy = fake_proxy(std::sync::Arc::clone(&client), |req| match req {
HandoffRequest::Take { responder } => {
let _ =
responder.send(Err(fdomain_fuchsia_session_power::HandoffError::AlreadyTaken));
}
x @ _ => unimplemented!("{x:?}"),
});
let drop_power_lease_cmd = SessionDropPowerLeaseCommand { allow_missing: true };
let mut writer = Vec::new();
let result = drop_power_lease_impl(proxy, drop_power_lease_cmd, &mut writer).await;
assert!(result.is_ok());
let output = String::from_utf8(writer).unwrap();
assert_eq!(
output,
"Requesting to dropping power lease on execution state\nLease already dropped, ignoring error.\nSuccess!\n"
);
}
N/A
N/A
{
"command": "ffx session drop-power-lease",
"options": [
{
"description": "if true, the tool will not return an error if the lease has already been dropped",
"option": "allow-missing",
"shorthand": "",
"value_type": "bool"
}
],
"short": "Drop the power lease reserved for the current session component."
}
device.ffx.run(
["session", "drop-power-lease", "--allow-missing"],
machine=ffx_types.MachineFormat.RAW,
)
attempt = -1
while True:
attempt += 1
if deadline.is_due():
raise DeviceDidNotSuspendError("SAG did not suspend during idle.")
_LOGGER.info("Suspension attempt %s...", attempt + 1)
before_off_charger_stats = await get_sag_suspend_stats(device)
sleep_deadline = deadline.subdeadline_with_timeout(
SUSPEND_RESUME_BASE_IDLE_DURATION * (2**attempt)
)
try:
await device.suspend()
await control_flows.sleep_until_deadline(sleep_deadline)
finally:
await device.resume()
while_off_charger_stats = (
await get_sag_suspend_stats(device) - before_off_charger_stats
)
_LOGGER.info(
"Suspend stats during off-charger idle: \n%s",
while_off_charger_stats,
N/A
N/A
{
"command": "ffx session launch",
"options": [
{
"description": "provide additional configuration capabilities to the component being run. Specified in the format `fully.qualified.Name=VALUE` where `fully.qualified.Name` is the name of the configuration capability, and `VALUE` is a JSON string which can be resolved as the correct type of configuration value.",
"option": "config",
"shorthand": "",
"value_type": "string"
}
],
"short": "Launch a session component."
}
#[fuchsia::test]
async fn test_launch_session() {
const SESSION_URL: &str = "Session URL";
let client = fdomain_local::local_client_empty();
let proxy = fake_proxy(client.clone(), |req| match req {
LauncherRequest::Launch { configuration, responder } => {
assert!(configuration.session_url.is_some());
let session_url = configuration.session_url.unwrap();
assert!(session_url == SESSION_URL.to_string());
let _ = responder.send(Ok(()));
}
});
let (rcs_proxy, _) = client.create_proxy_and_stream::<rc::RemoteControlMarker>();
let rcs = rcs_proxy.into();
let launch_cmd = SessionLaunchCommand { url: SESSION_URL.to_string(), config: vec![] };
let test_buffers = ffx_writer::TestBuffers::default();
let mut writer = MachineWriter::new_test(None, &test_buffers);
let result = launch_impl(proxy, rcs, launch_cmd, &mut writer).await;
assert!(result.is_ok());
}
#[fuchsia::test]
async fn test_machine_output_is_valid_json() {
const SESSION_URL: &str = "Session URL";
let client = fdomain_local::local_client_empty();
let proxy = target_holders::fdomain::fake_proxy(client.clone(), |req| match req {
LauncherRequest::Launch { configuration: _, responder } => {
let _ = responder.send(Ok(()));
}
});
let (rcs_proxy, _) = client.create_proxy_and_stream::<rc::RemoteControlMarker>();
let rcs = rcs_proxy.into();
let launch_cmd = SessionLaunchCommand { url: SESSION_URL.to_string(), config: vec![] };
let test_buffers = ffx_writer::TestBuffers::default();
let writer = MachineWriter::new_test(Some(ffx_writer::Format::Json), &test_buffers);
let tool = LaunchTool { cmd: launch_cmd, rcs, launcher_proxy: proxy };
let result = tool.main(writer).await;
assert!(result.is_ok());
let output = test_buffers.into_stdout_str();
assert_eq!(output, "null\n");
}
```posix-terminal
N/A
{
"command": "ffx session launch",
"options": [
{
"description": "provide additional configuration capabilities to the component being run. Specified in the format `fully.qualified.Name=VALUE` where `fully.qualified.Name` is the name of the configuration capability, and `VALUE` is a JSON string which can be resolved as the correct type of configuration value.",
"option": "config",
"shorthand": "",
"value_type": "string"
}
],
"short": "Launch a session component."
}
N/A
N/A
N/A
{
"command": "ffx session remove",
"options": [],
"short": "Remove an element from the current session.\n\nPersistent elements will be removed permanently. Any persistent storage used by\nelements will *not* be removed."
}
#[fuchsia::test]
async fn test_remove_element() {
let client = fdomain_local::local_client_empty();
let proxy = fake_proxy(client, |req| match req {
ManagerRequest::ProposeElement { .. } => unreachable!(),
ManagerRequest::RemoveElement { name, responder } => {
assert_eq!(name, "foo");
let _ = responder.send(Ok(()));
}
});
let remove_cmd = SessionRemoveCommand { name: "foo".to_string() };
let mut writer = Vec::new();
let response = remove_impl(proxy, remove_cmd, &mut writer).await;
assert!(response.is_ok());
}
res = self._ffx.run(
["component", "list"], machine=ffx_types.MachineFormat.RAW
)
components = res.splitlines()
for component in components:
if component.startswith(ELEMENT_PREFIX):
name = component[len(ELEMENT_PREFIX) :]
# Starnix's element naming starts with main. Not sure how to remove them yet,
# `ffx session remove` seems not work.
if not name.startswith("main"):
_LOGGER.info(
"remove component on device %s: %s",
self._name,
name,
)
self._ffx.run(
["session", "remove", name],
machine=ffx_types.MachineFormat.RAW,
)
except ffx_errors.FfxCommandError as err:
# TODO(b/406501041): Handle potential "NotFound" error. If multiple components share the
# same URL, removing one will implicitly remove all others with that URL. Subsequent
# attempts to remove components with the same URL will result in a "NotFound" error.
if "Error: NotFound" not in str(err):
raise session_errors.SessionError(err)
N/A
N/A
{
"command": "ffx session restart",
"options": [],
"short": "Restart the current session component."
}
#[fuchsia::test]
async fn test_restart_session() {
let client = fdomain_local::local_client_empty();
let proxy = fake_proxy(client, |req| match req {
RestarterRequest::Restart { responder } => {
let _ = responder.send(Ok(()));
}
});
let restart_cmd = SessionRestartCommand {};
let test_buffers = ffx_writer::TestBuffers::default();
let mut writer = MachineWriter::new_test(None, &test_buffers);
let result = restart_impl(proxy, restart_cmd, &mut writer).await;
assert!(result.is_ok());
let output = test_buffers.into_stdout_str();
assert_eq!(output, "Restarting the current session\n");
}
#[fuchsia::test]
async fn test_machine_output_is_valid_json() {
let client = fdomain_local::local_client_empty();
let proxy = fake_proxy(client.clone(), |req| match req {
RestarterRequest::Restart { responder } => {
let _ = responder.send(Ok(()));
}
});
let restart_cmd = SessionRestartCommand {};
let test_buffers = ffx_writer::TestBuffers::default();
let writer = MachineWriter::new_test(Some(ffx_writer::Format::Json), &test_buffers);
let tool = RestartTool { cmd: restart_cmd, restarter_proxy: proxy };
let result = tool.main(writer).await;
assert!(result.is_ok());
let output = test_buffers.into_stdout_str();
assert_eq!(output, "null\n");
}
self._ffx.run(
["session", "restart"], machine=ffx_types.MachineFormat.RAW
)
except ffx_errors.FfxCommandError as err:
raise session_errors.SessionError(err)
_LOGGER.info("wait for session started on device %s", self._name)
# wait for session started.
while not self.is_started():
time.sleep(1) # second.
_LOGGER.info("session started on device %s", self._name)
def stop(self) -> None:
"""Stop the session.
It is ok to call `ffx session stop` regardless of whether a session
has started or not.
Raises:
SessionError: Session failed stop to the session.
"""
_LOGGER.info("stop session on device %s", self._name)
try:
self._ffx.run(
["session", "stop"], machine=ffx_types.MachineFormat.RAW
)
except ffx_errors.FfxCommandError as err:
N/A
N/A
{
"command": "ffx session show",
"options": [],
"short": "Show information about the current session"
}
res = self._ffx.run(
["session", "show"], machine=ffx_types.MachineFormat.RAW
)
lines = res.splitlines()
for line in lines:
if "Execution State: Running" in line:
return True
except ffx_errors.FfxCommandError as err:
if (
'No matching component instance found for query "core/session-manager/session:session"'
in str(err)
):
# session is not running.
return False
raise session_errors.SessionError(err)
return False
def ensure_started(self) -> None:
"""Ensure session started, if not start a session. Wait indefinitely until session
started.
Raises:
honeydew.errors.SessionError: session failed to check or start.
"""
if not self.is_started():
_LOGGER.info("session not started on device %s", self._name)
self.start()
N/A
N/A
{
"command": "ffx session start",
"options": [],
"short": "Start the default session component."
}
#[fuchsia::test]
async fn test_start_session() -> Result<()> {
let client = fdomain_local::local_client_empty();
let proxy = fake_proxy(client, |req| match req {
LifecycleRequest::Start { payload, responder, .. } => {
assert_eq!(payload.session_url, None);
let _ = responder.send(Ok(()));
}
_ => panic!("Unxpected Lifecycle request"),
});
let start_cmd = SessionStartCommand {};
let mut writer = Vec::new();
start_impl(proxy, start_cmd, &mut writer).await?;
let output = String::from_utf8(writer).unwrap();
assert_eq!(output, STARTING_SESSION);
Ok(())
}
self._ffx.run(
["session", "start"], machine=ffx_types.MachineFormat.RAW
)
except ffx_errors.FfxCommandError as err:
raise session_errors.SessionError(err)
_LOGGER.info("wait for session started on device %s", self._name)
# wait for session started.
while not self.is_started():
time.sleep(1) # second.
_LOGGER.info("session started on device %s", self._name)
def is_started(self) -> bool:
"""Check if session is started.
Returns:
True if session is started.
Raises:
SessionError: failed to check the session state.
"""
try:
res = self._ffx.run(
["session", "show"], machine=ffx_types.MachineFormat.RAW
)
lines = res.splitlines()
for line in lines:
if "Execution State: Running" in line:
N/A
N/A
{
"command": "ffx session stop",
"options": [],
"short": "Stop the session component."
}
#[fuchsia::test]
async fn test_stop_session() -> Result<()> {
let client = fdomain_local::local_client_empty();
let proxy = fake_proxy(client, |req| match req {
LifecycleRequest::Stop { responder } => {
let _ = responder.send(Ok(()));
}
_ => panic!("Unxpected Lifecycle request"),
});
let stop_cmd = SessionStopCommand {};
let mut writer = Vec::new();
stop_impl(proxy, stop_cmd, &mut writer).await?;
let output = String::from_utf8(writer).unwrap();
assert_eq!(output, STOPPING_SESSION);
Ok(())
}
self._ffx.run(
["session", "stop"], machine=ffx_types.MachineFormat.RAW
)
except ffx_errors.FfxCommandError as err:
raise session_errors.SessionError(err)
_LOGGER.info("wait for session stopped on device %s", self._name)
# wait for session stopped.
while self.is_started():
time.sleep(1) # second.
_LOGGER.info("session stopped on device %s", self._name)
def cleanup(self) -> None:
"""Cleanup the session using `ffx component list` and `ffx session remove`.
Raises:
SessionError: Session failed to list running components or remove components.
"""
# when session is stopped, no cleanup.
if not self.is_started():
_LOGGER.info(
"no cleanup needed on device %s, session is stopped.",
self._name,
)
return
_LOGGER.info("cleanup session on device %s", self._name)
N/A
N/A
{
"command": "ffx setui",
"options": [],
"short": "Modify and query settings."
}
N/A
N/A
N/A
{
"command": "ffx setui accessibility",
"options": [],
"short": "watch or set accessibility settings"
}
#[test]
fn test_accessibility_add_caption_cmd() {
// Test input arguments are generated to according struct.
let window_color = "red";
let font_family = "casual";
let char_edge_style = "drop_shadow";
let args = &["add-caption", "-w", window_color, "-f", font_family, "-e", char_edge_style];
assert_eq!(
Accessibility::from_args(CMD_NAME, args),
Ok(Accessibility {
subcommand: SubCommandEnum::AddCaption(CaptionArgs {
for_media: None,
for_tts: None,
window_color: Some(str_to_color(window_color).unwrap()),
background_color: None,
font_family: Some(str_to_font_family(font_family).unwrap()),
font_color: None,
relative_size: None,
char_edge_style: Some(str_to_edge_style(char_edge_style).unwrap()),
})
})
)
}
#[test]
fn test_accessibility_set_cmd() {
// Test input arguments are generated to according struct.
let color_correction = "protanomaly";
let args = &["set", "-c", color_correction];
assert_eq!(
Accessibility::from_args(CMD_NAME, args),
Ok(Accessibility {
subcommand: SubCommandEnum::Set(SetArgs {
audio_description: None,
screen_reader: None,
color_inversion: None,
enable_magnification: None,
color_correction: Some(str_to_color_blindness_type(color_correction).unwrap())
})
})
)
}
#[test]
fn test_accessibility_watch_cmd() {
// Test input arguments are generated to according struct.
let args = &["watch"];
assert_eq!(
Accessibility::from_args(CMD_NAME, args),
Ok(Accessibility { subcommand: SubCommandEnum::Watch(WatchArgs {}) })
)
}
N/A
N/A
{
"command": "ffx setui accessibility add-caption",
"options": [
{
"description": "enable closed captions for media sources of audio",
"option": "for-media",
"shorthand": "m",
"value_type": "string"
},
{
"description": "enable closed captions for Text-To-Speech sources of audio",
"option": "for-tts",
#[fuchsia::test]
async fn test_add_caption() {
const TRUE: bool = true;
let client = fdomain_local::local_client_empty();
let proxy = fake_proxy(client, move |req| match req {
AccessibilityRequest::Set { responder, .. } => {
let _ = responder.send(Ok(()));
}
AccessibilityRequest::Watch { .. } => {
panic!("Unexpected call to watch");
}
});
let args = CaptionArgs {
for_media: Some(TRUE),
for_tts: None,
window_color: None,
background_color: None,
font_family: None,
font_color: None,
relative_size: None,
char_edge_style: None,
};
let response = add_caption(proxy, args, &mut vec![]).await;
assert!(response.is_ok());
}
#[fuchsia::test]
async fn validate_accessibility_add_caption(expected_add: CaptionArgs) -> Result<()> {
let add_clone = expected_add.clone();
let client = fdomain_local::local_client_empty();
let proxy = fake_proxy(client, move |req| match req {
AccessibilityRequest::Set { responder, .. } => {
let _ = responder.send(Ok(()));
}
AccessibilityRequest::Watch { .. } => {
panic!("Unexpected call to watch");
}
});
let output = utils::assert_set!(command(proxy, add_clone));
assert_eq!(output, format!("Successfully set AccessibilitySettings"));
Ok(())
}
N/A
N/A
{
"command": "ffx setui accessibility add-caption",
"options": [
{
"description": "enable closed captions for media sources of audio",
"option": "for-media",
"shorthand": "m",
"value_type": "string"
},
{
"description": "enable closed captions for Text-To-Speech sources of audio",
"option": "for-tts",
N/A
N/A
N/A
{
"command": "ffx setui accessibility add-caption",
"options": [
{
"description": "enable closed captions for media sources of audio",
"option": "for-media",
"shorthand": "m",
"value_type": "string"
},
{
"description": "enable closed captions for Text-To-Speech sources of audio",
"option": "for-tts",
N/A
N/A
N/A
{
"command": "ffx setui accessibility add-caption",
"options": [
{
"description": "enable closed captions for media sources of audio",
"option": "for-media",
"shorthand": "m",
"value_type": "string"
},
{
"description": "enable closed captions for Text-To-Speech sources of audio",
"option": "for-tts",
N/A
N/A
N/A
{
"command": "ffx setui accessibility add-caption",
"options": [
{
"description": "enable closed captions for media sources of audio",
"option": "for-media",
"shorthand": "m",
"value_type": "string"
},
{
"description": "enable closed captions for Text-To-Speech sources of audio",
"option": "for-tts",
N/A
N/A
N/A
{
"command": "ffx setui accessibility add-caption",
"options": [
{
"description": "enable closed captions for media sources of audio",
"option": "for-media",
"shorthand": "m",
"value_type": "string"
},
{
"description": "enable closed captions for Text-To-Speech sources of audio",
"option": "for-tts",
N/A
N/A
N/A
{
"command": "ffx setui accessibility add-caption",
"options": [
{
"description": "enable closed captions for media sources of audio",
"option": "for-media",
"shorthand": "m",
"value_type": "string"
},
{
"description": "enable closed captions for Text-To-Speech sources of audio",
"option": "for-tts",
N/A
N/A
N/A
{
"command": "ffx setui accessibility add-caption",
"options": [
{
"description": "enable closed captions for media sources of audio",
"option": "for-media",
"shorthand": "m",
"value_type": "string"
},
{
"description": "enable closed captions for Text-To-Speech sources of audio",
"option": "for-tts",
N/A
N/A
N/A
{
"command": "ffx setui accessibility add-caption",
"options": [
{
"description": "enable closed captions for media sources of audio",
"option": "for-media",
"shorthand": "m",
"value_type": "string"
},
{
"description": "enable closed captions for Text-To-Speech sources of audio",
"option": "for-tts",
N/A
N/A
N/A
{
"command": "ffx setui accessibility set",
"options": [
{
"description": "when set to 'true', will turn on an audio track for videos that includes a description of what is occurring in the video",
"option": "audio-description",
"shorthand": "a",
"value_type": "string"
},
{
"description": "when set to 'true', will read aloud elements of the screen selected by the user",
"option": "screen-reader",
#[fuchsia::test]
async fn test_set() {
const TRUE: bool = true;
let client = fdomain_local::local_client_empty();
let proxy = fake_proxy(client, move |req| match req {
AccessibilityRequest::Set { responder, .. } => {
let _ = responder.send(Ok(()));
}
AccessibilityRequest::Watch { .. } => {
panic!("Unexpected call to watch");
}
});
let args = SetArgs {
audio_description: Some(TRUE),
screen_reader: None,
color_inversion: None,
enable_magnification: None,
color_correction: None,
};
let response = set(proxy, args, &mut vec![]).await;
assert!(response.is_ok());
}
#[fuchsia::test]
async fn validate_accessibility_set(expected_set: SetArgs) -> Result<()> {
let set_clone = expected_set.clone();
let client = fdomain_local::local_client_empty();
let proxy = fake_proxy(client, move |req| match req {
AccessibilityRequest::Set { responder, .. } => {
let _ = responder.send(Ok(()));
}
AccessibilityRequest::Watch { .. } => {
panic!("Unexpected call to watch");
}
});
let output = utils::assert_set!(command(proxy, set_clone));
assert_eq!(output, format!("Successfully set AccessibilitySettings"));
Ok(())
}
N/A
N/A
{
"command": "ffx setui accessibility set",
"options": [
{
"description": "when set to 'true', will turn on an audio track for videos that includes a description of what is occurring in the video",
"option": "audio-description",
"shorthand": "a",
"value_type": "string"
},
{
"description": "when set to 'true', will read aloud elements of the screen selected by the user",
"option": "screen-reader",
N/A
N/A
N/A
{
"command": "ffx setui accessibility set",
"options": [
{
"description": "when set to 'true', will turn on an audio track for videos that includes a description of what is occurring in the video",
"option": "audio-description",
"shorthand": "a",
"value_type": "string"
},
{
"description": "when set to 'true', will read aloud elements of the screen selected by the user",
"option": "screen-reader",
N/A
N/A
N/A
{
"command": "ffx setui accessibility set",
"options": [
{
"description": "when set to 'true', will turn on an audio track for videos that includes a description of what is occurring in the video",
"option": "audio-description",
"shorthand": "a",
"value_type": "string"
},
{
"description": "when set to 'true', will read aloud elements of the screen selected by the user",
"option": "screen-reader",
N/A
N/A
N/A
{
"command": "ffx setui accessibility set",
"options": [
{
"description": "when set to 'true', will turn on an audio track for videos that includes a description of what is occurring in the video",
"option": "audio-description",
"shorthand": "a",
"value_type": "string"
},
{
"description": "when set to 'true', will read aloud elements of the screen selected by the user",
"option": "screen-reader",
N/A
N/A
N/A
{
"command": "ffx setui accessibility set",
"options": [
{
"description": "when set to 'true', will turn on an audio track for videos that includes a description of what is occurring in the video",
"option": "audio-description",
"shorthand": "a",
"value_type": "string"
},
{
"description": "when set to 'true', will read aloud elements of the screen selected by the user",
"option": "screen-reader",
N/A
N/A
N/A
{
"command": "ffx setui accessibility watch",
"options": [],
"short": "watch current accessibility settings"
}
#[fuchsia::test]
async fn validate_accessibility_watch() -> Result<()> {
let client = fdomain_local::local_client_empty();
let proxy = fake_proxy(client, move |req| match req {
AccessibilityRequest::Set { .. } => {
panic!("Unexpected call to set");
}
AccessibilityRequest::Watch { responder } => {
let _ = responder.send(&AccessibilitySettings::default());
}
});
let output = utils::assert_watch!(command(proxy));
assert_eq!(output, format!("{:#?}", AccessibilitySettings::default()));
Ok(())
}
N/A
N/A
{
"command": "ffx setui audio",
"options": [
{
"description": "which stream should be modified. Valid options are background, media, interruption, system_agent, communication and accessibility.",
"option": "stream",
"shorthand": "t",
"value_type": "string"
},
{
"description": "which source is changing the stream. Valid options are user, system, and system_with_feedback",
"option": "source",
#[test]
fn test_audio_cmd() {
// Test input arguments are generated to according struct.
let render = "background";
let source = "system";
let level = "0.6";
let not_muted = "false";
let args = &["-t", render, "-s", source, "-l", level, "-v", not_muted];
assert_eq!(
Audio::from_args(CMD_NAME, args),
Ok(Audio {
stream: Some(str_to_audio_stream(render).unwrap()),
source: Some(str_to_audio_source(source).unwrap()),
level: Some(0.6),
volume_muted: Some(false),
})
)
}
#[fuchsia::test]
async fn test_run_command() {
let client = fdomain_local::local_client_empty();
let proxy = fake_proxy(client, move |req| match req {
AudioRequest::Set { .. } => {
panic!("Unexpected call to set");
}
AudioRequest::Watch { .. } => {
panic!("Unexpected call to watch");
}
AudioRequest::Set2 { responder, .. } => {
let _ = responder.send(Ok(()));
}
AudioRequest::Watch2 { .. } => {
panic!("Unexpected call to watch2");
}
AudioRequest::_UnknownMethod { .. } => {
panic!("Unexpected call to unknown method");
}
});
let audio = Audio {
stream: Some(AudioRenderUsage2::Background),
source: Some(fdomain_fuchsia_settings::AudioStreamSettingSource::User),
level: Some(0.5),
volume_muted: Some(false),
};
let response = run_command(proxy, audio, &mut vec![]).await;
assert!(response.is_ok());
#[fuchsia::test]
async fn validate_audio_set_output(expected_audio: Audio) -> Result<()> {
let client = fdomain_local::local_client_empty();
let proxy = fake_proxy(client, move |req| match req {
AudioRequest::Set { .. } => {
panic!("Unexpected call to set");
}
AudioRequest::Watch { .. } => {
panic!("Unexpected call to watch");
}
AudioRequest::Set2 { responder, .. } => {
let _ = responder.send(Ok(()));
}
AudioRequest::Watch2 { .. } => {
panic!("Unexpected call to watch2");
}
AudioRequest::_UnknownMethod { .. } => {
panic!("Unexpected call to unknown method");
}
});
let output = utils::assert_set!(command(proxy, expected_audio));
assert_eq!(output, format!("Successfully set Audio to {:?}", expected_audio));
Ok(())
}
N/A
N/A
{
"command": "ffx setui audio",
"options": [
{
"description": "which stream should be modified. Valid options are background, media, interruption, system_agent, communication and accessibility.",
"option": "stream",
"shorthand": "t",
"value_type": "string"
},
{
"description": "which source is changing the stream. Valid options are user, system, and system_with_feedback",
"option": "source",
N/A
N/A
N/A
{
"command": "ffx setui audio",
"options": [
{
"description": "which stream should be modified. Valid options are background, media, interruption, system_agent, communication and accessibility.",
"option": "stream",
"shorthand": "t",
"value_type": "string"
},
{
"description": "which source is changing the stream. Valid options are user, system, and system_with_feedback",
"option": "source",
N/A
N/A
N/A
{
"command": "ffx setui audio",
"options": [
{
"description": "which stream should be modified. Valid options are background, media, interruption, system_agent, communication and accessibility.",
"option": "stream",
"shorthand": "t",
"value_type": "string"
},
{
"description": "which source is changing the stream. Valid options are user, system, and system_with_feedback",
"option": "source",
N/A
N/A
N/A
{
"command": "ffx setui audio",
"options": [
{
"description": "which stream should be modified. Valid options are background, media, interruption, system_agent, communication and accessibility.",
"option": "stream",
"shorthand": "t",
"value_type": "string"
},
{
"description": "which source is changing the stream. Valid options are user, system, and system_with_feedback",
"option": "source",
N/A
N/A
N/A
{
"command": "ffx setui display",
"options": [],
"short": "get or set display settings"
}
#[test]
fn test_display_set_cmd() {
// Test input arguments are generated to according struct.
let turned_on_auto = "true";
let low_light_mode = "disable";
let theme = "darkauto";
let args = &["set", "-a", turned_on_auto, "-m", low_light_mode, "-t", theme];
assert_eq!(
Display::from_args(CMD_NAME, args),
Ok(Display {
subcommand: SubCommandEnum::Set(SetArgs {
brightness: None,
auto_brightness_level: None,
auto_brightness: Some(true),
low_light_mode: Some(str_to_low_light_mode(low_light_mode).unwrap()),
theme: Some(str_to_theme(theme).unwrap()),
screen_enabled: None,
})
})
)
}
#[test]
fn test_display_get_cmd() {
// Test input arguments are generated to according struct.
let args = &["get"];
assert_eq!(
Display::from_args(CMD_NAME, args),
Ok(Display { subcommand: SubCommandEnum::Get(GetArgs { field: None }) })
)
}
#[test]
fn test_display_watch_cmd() {
// Test input arguments are generated to according struct.
let args = &["watch"];
assert_eq!(
Display::from_args(CMD_NAME, args),
Ok(Display { subcommand: SubCommandEnum::Watch(WatchArgs {}) })
)
}
N/A
N/A
{
"command": "ffx setui display get",
"options": [
{
"description": "choose which display settings field value to return, valid options are auto and brightness",
"option": "field",
"shorthand": "f",
"value_type": "string"
}
],
"short": "Get the current display settings."
}
#[fuchsia::test]
async fn test_get() {
let expected_display = SetArgs {
brightness: None,
auto_brightness_level: None,
auto_brightness: Some(false),
low_light_mode: None,
theme: None,
screen_enabled: None,
};
let client = fdomain_local::local_client_empty();
let proxy = fake_proxy(client, move |req| match req {
DisplayRequest::Set { .. } => {
panic!("Unexpected call to set");
}
DisplayRequest::Watch { responder } => {
let _ = responder.send(&DisplaySettings::from(expected_display.clone()));
}
});
let get_args = GetArgs { field: Some(Field::Auto) };
let response = get(proxy, get_args, &mut vec![]).await;
assert!(response.is_ok());
}
#[fuchsia::test]
async fn test_get_failure() {
let expected_display = SetArgs {
brightness: None,
auto_brightness_level: None,
auto_brightness: None,
low_light_mode: None,
theme: None,
screen_enabled: None,
};
let client = fdomain_local::local_client_empty();
let proxy = fake_proxy(client, move |req| match req {
DisplayRequest::Set { .. } => {
panic!("Unexpected call to set");
}
DisplayRequest::Watch { responder } => {
let _ = responder.send(&DisplaySettings::from(expected_display.clone()));
}
});
let get_args = GetArgs { field: Some(Field::Auto) };
let _ = get(proxy, get_args, &mut vec![]).await;
}
N/A
N/A
{
"command": "ffx setui display get",
"options": [
{
"description": "choose which display settings field value to return, valid options are auto and brightness",
"option": "field",
"shorthand": "f",
"value_type": "string"
}
],
"short": "Get the current display settings."
}
N/A
N/A
N/A
{
"command": "ffx setui display set",
"options": [
{
"description": "the brightness value specified as a float in the range [0, 1]",
"option": "brightness",
"shorthand": "b",
"value_type": "string"
},
{
"description": "the brightness values used to control auto brightness as a float in the range [0, 1]",
"option": "auto-brightness-level",
#[fuchsia::test]
async fn test_set() {
let client = fdomain_local::local_client_empty();
let proxy = fake_proxy(client, move |req| match req {
DisplayRequest::Set { responder, .. } => {
let _ = responder.send(Ok(()));
}
DisplayRequest::Watch { .. } => {
panic!("Unexpected call to watch");
}
});
let display = SetArgs {
brightness: None,
auto_brightness_level: None,
auto_brightness: Some(true),
low_light_mode: None,
theme: None,
screen_enabled: None,
};
let response = set(proxy, display, &mut vec![]).await;
assert!(response.is_ok());
}
#[fuchsia::test]
async fn validate_display_set_output(expected_display: SetArgs) -> Result<()> {
let client = fdomain_local::local_client_empty();
let proxy = fake_proxy(client, move |req| match req {
DisplayRequest::Set { responder, .. } => {
let _ = responder.send(Ok(()));
}
DisplayRequest::Watch { .. } => {
panic!("Unexpected call to watch");
}
});
let output =
utils::assert_set!(command(proxy, DisplaySettings::from(expected_display.clone())));
assert_eq!(output, format!("Successfully set Display to {:?}", expected_display));
Ok(())
}
N/A
N/A
{
"command": "ffx setui display set",
"options": [
{
"description": "the brightness value specified as a float in the range [0, 1]",
"option": "brightness",
"shorthand": "b",
"value_type": "string"
},
{
"description": "the brightness values used to control auto brightness as a float in the range [0, 1]",
"option": "auto-brightness-level",
N/A
N/A
N/A
{
"command": "ffx setui display set",
"options": [
{
"description": "the brightness value specified as a float in the range [0, 1]",
"option": "brightness",
"shorthand": "b",
"value_type": "string"
},
{
"description": "the brightness values used to control auto brightness as a float in the range [0, 1]",
"option": "auto-brightness-level",
N/A
N/A
N/A
{
"command": "ffx setui display set",
"options": [
{
"description": "the brightness value specified as a float in the range [0, 1]",
"option": "brightness",
"shorthand": "b",
"value_type": "string"
},
{
"description": "the brightness values used to control auto brightness as a float in the range [0, 1]",
"option": "auto-brightness-level",
N/A
N/A
N/A
{
"command": "ffx setui display set",
"options": [
{
"description": "the brightness value specified as a float in the range [0, 1]",
"option": "brightness",
"shorthand": "b",
"value_type": "string"
},
{
"description": "the brightness values used to control auto brightness as a float in the range [0, 1]",
"option": "auto-brightness-level",
N/A
N/A
N/A
{
"command": "ffx setui display set",
"options": [
{
"description": "the brightness value specified as a float in the range [0, 1]",
"option": "brightness",
"shorthand": "b",
"value_type": "string"
},
{
"description": "the brightness values used to control auto brightness as a float in the range [0, 1]",
"option": "auto-brightness-level",
N/A
N/A
N/A
{
"command": "ffx setui display set",
"options": [
{
"description": "the brightness value specified as a float in the range [0, 1]",
"option": "brightness",
"shorthand": "b",
"value_type": "string"
},
{
"description": "the brightness values used to control auto brightness as a float in the range [0, 1]",
"option": "auto-brightness-level",
N/A
N/A
N/A
{
"command": "ffx setui display watch",
"options": [],
"short": "Get the current display settings and watch for changes."
}
#[fuchsia::test]
async fn validate_display_watch_output(expected_display: SetArgs) -> Result<()> {
let expected_display_clone = expected_display.clone();
let client = fdomain_local::local_client_empty();
let proxy = fake_proxy(client, move |req| match req {
DisplayRequest::Set { .. } => {
panic!("Unexpected call to set");
}
DisplayRequest::Watch { responder } => {
let _ = responder.send(&DisplaySettings::from(expected_display.clone()));
}
});
let output = utils::assert_watch!(command(proxy));
assert_eq!(output, format!("{:#?}", DisplaySettings::from(expected_display_clone)));
Ok(())
}
N/A
N/A
{
"command": "ffx setui do_not_disturb",
"options": [
{
"description": "when set to 'true', allows the device to enter do not disturb mode",
"option": "user-dnd",
"shorthand": "u",
"value_type": "string"
},
{
"description": "when set to 'true', forces the device into do not disturb mode",
"option": "night-mode-dnd",
N/A
#[test]
fn test_dnd_cmd() {
// Test input arguments are generated to according struct.
let user = "true";
let args = &["-u", user];
assert_eq!(
DoNotDisturb::from_args(CMD_NAME, args),
Ok(DoNotDisturb { user_dnd: Some(true), night_mode_dnd: None })
)
}
#[fuchsia::test]
async fn test_run_command() {
const USER: bool = true;
const NIGHT_MODE: bool = false;
let client = fdomain_local::local_client_empty();
let proxy = fake_proxy(client, move |req| match req {
DoNotDisturbRequest::Set { responder, .. } => {
let _ = responder.send(Ok(()));
}
DoNotDisturbRequest::Watch { .. } => {
panic!("Unexpected call to watch");
}
});
let dnd = DoNotDisturb { user_dnd: Some(USER), night_mode_dnd: Some(NIGHT_MODE) };
let response = run_command(proxy, dnd, &mut vec![]).await;
assert!(response.is_ok());
}
#[fuchsia::test]
async fn validate_do_not_disturb_set_output(
expected_do_not_disturb: DoNotDisturb,
) -> Result<()> {
let client = fdomain_local::local_client_empty();
let proxy = fake_proxy(client, move |req| match req {
DoNotDisturbRequest::Set { responder, .. } => {
let _ = responder.send(Ok(()));
}
DoNotDisturbRequest::Watch { .. } => {
panic!("Unexpected call to watch");
}
});
let output = utils::assert_set!(command(proxy, expected_do_not_disturb));
assert_eq!(
output,
format!("Successfully set DoNotDisturb to {:?}", expected_do_not_disturb)
);
Ok(())
}
N/A
N/A
{
"command": "ffx setui do_not_disturb",
"options": [
{
"description": "when set to 'true', allows the device to enter do not disturb mode",
"option": "user-dnd",
"shorthand": "u",
"value_type": "string"
},
{
"description": "when set to 'true', forces the device into do not disturb mode",
"option": "night-mode-dnd",
N/A
N/A
N/A
N/A
{
"command": "ffx setui do_not_disturb",
"options": [
{
"description": "when set to 'true', allows the device to enter do not disturb mode",
"option": "user-dnd",
"shorthand": "u",
"value_type": "string"
},
{
"description": "when set to 'true', forces the device into do not disturb mode",
"option": "night-mode-dnd",
N/A
N/A
N/A
N/A
{
"command": "ffx setui factory_reset",
"options": [
{
"description": "when set to 'true', factory reset can be performed on the device",
"option": "is-local-reset-allowed",
"shorthand": "l",
"value_type": "string"
}
],
"short": "get or set factory reset settings"
}
N/A
#[test]
fn test_factory_reset_cmd() {
// Test input arguments are generated to according struct.
let allowed = "true";
let args = &["-l", allowed];
assert_eq!(
FactoryReset::from_args(CMD_NAME, args),
Ok(FactoryReset { is_local_reset_allowed: Some(true) })
)
}
#[fuchsia::test]
async fn test_run_command() {
const ALLOWED: bool = true;
let client = fdomain_local::local_client_empty();
let proxy = fake_proxy(client, move |req| match req {
FactoryResetRequest::Set { responder, .. } => {
let _ = responder.send(Ok(()));
}
FactoryResetRequest::Watch { .. } => {
panic!("Unexpected call to watch");
}
});
let factory_reset = FactoryReset { is_local_reset_allowed: Some(ALLOWED) };
let response = run_command(proxy, factory_reset, &mut vec![]).await;
assert!(response.is_ok());
}
#[fuchsia::test]
async fn validate_factory_reset_set_output(
expected_is_local_reset_allowed: bool,
) -> Result<()> {
let client = fdomain_local::local_client_empty();
let proxy = fake_proxy(client, move |req| match req {
FactoryResetRequest::Set { responder, .. } => {
let _ = responder.send(Ok(()));
}
FactoryResetRequest::Watch { .. } => {
panic!("Unexpected call to watch");
}
});
let output = utils::assert_set!(command(proxy, Some(expected_is_local_reset_allowed)));
assert_eq!(
output,
format!(
"Successfully set factory_reset to {:?}",
FactoryResetSettings {
is_local_reset_allowed: Some(expected_is_local_reset_allowed),
..Default::default()
}
)
);
Ok(())
}
N/A
N/A
{
"command": "ffx setui factory_reset",
"options": [
{
"description": "when set to 'true', factory reset can be performed on the device",
"option": "is-local-reset-allowed",
"shorthand": "l",
"value_type": "string"
}
],
"short": "get or set factory reset settings"
}
N/A
N/A
N/A
N/A
{
"command": "ffx setui input",
"options": [
{
"description": "the type of input device. Valid options are camera and microphone",
"option": "device-type",
"shorthand": "t",
"value_type": "string"
},
{
"description": "the name of the device. Must be unique within a device type",
"option": "name",
#[test]
fn test_display_cmd() {
// Test input arguments are generated to according struct.
let device_type = "microphone";
let state = "muted";
let args = &["-t", device_type, "-s", state];
assert_eq!(
Input::from_args(CMD_NAME, args),
Ok(Input {
device_type: Some(str_to_device_type(device_type).unwrap()),
device_name: None,
device_state: Some(str_to_device_state(state).unwrap()),
})
)
}
#[fuchsia::test]
async fn test_run_command() {
let client = fdomain_local::local_client_empty();
let proxy = fake_proxy(client, move |req| match req {
InputRequest::Set { responder, .. } => {
let _ = responder.send(Ok(()));
}
InputRequest::Watch { .. } => {
panic!("Unexpected call to watch");
}
});
let input = Input {
device_name: None,
device_type: Some(DeviceType::Camera),
device_state: Some(DeviceState {
toggle_flags: Some(ToggleStateFlags::AVAILABLE),
..Default::default()
}),
};
let response = run_command(proxy, input, &mut vec![]).await;
assert!(response.is_ok());
}
#[fuchsia::test]
async fn validate_input_set_output(mut expected_input: Input) -> Result<()> {
let client = fdomain_local::local_client_empty();
let proxy = fake_proxy(client, move |req| match req {
InputRequest::Set { responder, .. } => {
let _ = responder.send(Ok(()));
}
InputRequest::Watch { .. } => {
panic!("Unexpected call to watch");
}
});
let output = utils::assert_set!(command(proxy, InputState::from(expected_input.clone())));
// Make sure the `name` is auto-filled.
if expected_input.device_name.is_none() {
// Default device names.
expected_input.device_name = match expected_input.device_type.unwrap() {
DeviceType::Camera => Some("camera".to_string()),
DeviceType::Microphone => Some("microphone".to_string()),
};
}
assert_eq!(
output,
format!(
"Successfully set input states to {:#?}\n",
vec!(InputState::from(expected_input))
)
);
Ok(())
}
N/A
N/A
{
"command": "ffx setui input",
"options": [
{
"description": "the type of input device. Valid options are camera and microphone",
"option": "device-type",
"shorthand": "t",
"value_type": "string"
},
{
"description": "the name of the device. Must be unique within a device type",
"option": "name",
N/A
N/A
N/A
{
"command": "ffx setui input",
"options": [
{
"description": "the type of input device. Valid options are camera and microphone",
"option": "device-type",
"shorthand": "t",
"value_type": "string"
},
{
"description": "the name of the device. Must be unique within a device type",
"option": "name",
N/A
N/A
N/A
{
"command": "ffx setui input",
"options": [
{
"description": "the type of input device. Valid options are camera and microphone",
"option": "device-type",
"shorthand": "t",
"value_type": "string"
},
{
"description": "the name of the device. Must be unique within a device type",
"option": "name",
N/A
N/A
N/A
{
"command": "ffx setui intl",
"options": [
{
"description": "a valid timezone matching the data available at https://www.iana.org/time-zones",
"option": "time-zone",
"shorthand": "z",
"value_type": "string"
},
{
"description": "the unit to use for temperature. Valid options are celsius and fahrenheit",
"option": "temperature-unit",
#[test]
fn test_intl_cmd() {
// Test input arguments are generated to according struct.
let time_zone = "GTM";
let unit = "celsius";
let locales = "fr-u-hc-h12";
let hour_cycle = "h12";
let args = &["-z", time_zone, "-u", unit, "-l", locales, "-h", hour_cycle];
assert_eq!(
Intl::from_args(CMD_NAME, args),
Ok(Intl {
time_zone: Some(str_to_time_zone(time_zone).unwrap()),
temperature_unit: Some(str_to_temperature_unit(unit).unwrap()),
locales: vec![str_to_locale(locales).unwrap()],
hour_cycle: Some(str_to_hour_cycle(hour_cycle).unwrap()),
clear_locales: false,
})
)
}
#[fuchsia::test]
async fn test_run_command() {
let client = fdomain_local::local_client_empty();
let proxy = fake_proxy(client, move |req| match req {
IntlRequest::Set { responder, .. } => {
let _ = responder.send(Ok(()));
}
IntlRequest::Watch { .. } => {
panic!("Unexpected call to watch");
}
});
let intl = Intl {
time_zone: None,
temperature_unit: Some(TemperatureUnit::Celsius),
locales: vec![],
hour_cycle: None,
clear_locales: false,
};
let response = run_command(proxy, intl, &mut vec![]).await;
assert!(response.is_ok());
}
#[fuchsia::test]
async fn validate_intl_set_output(expected_intl: Intl) -> Result<()> {
let client = fdomain_local::local_client_empty();
let proxy = fake_proxy(client, move |req| match req {
IntlRequest::Set { responder, .. } => {
let _ = responder.send(Ok(()));
}
IntlRequest::Watch { .. } => {
panic!("Unexpected call to watch");
}
});
let output = utils::assert_set!(command(proxy, IntlSettings::from(expected_intl.clone())));
assert_eq!(output, format!("Successfully set Intl to {:?}", expected_intl));
Ok(())
}
N/A
N/A
{
"command": "ffx setui intl",
"options": [
{
"description": "a valid timezone matching the data available at https://www.iana.org/time-zones",
"option": "time-zone",
"shorthand": "z",
"value_type": "string"
},
{
"description": "the unit to use for temperature. Valid options are celsius and fahrenheit",
"option": "temperature-unit",
N/A
N/A
N/A
{
"command": "ffx setui intl",
"options": [
{
"description": "a valid timezone matching the data available at https://www.iana.org/time-zones",
"option": "time-zone",
"shorthand": "z",
"value_type": "string"
},
{
"description": "the unit to use for temperature. Valid options are celsius and fahrenheit",
"option": "temperature-unit",
N/A
N/A
N/A
{
"command": "ffx setui intl",
"options": [
{
"description": "a valid timezone matching the data available at https://www.iana.org/time-zones",
"option": "time-zone",
"shorthand": "z",
"value_type": "string"
},
{
"description": "the unit to use for temperature. Valid options are celsius and fahrenheit",
"option": "temperature-unit",
N/A
N/A
N/A
{
"command": "ffx setui intl",
"options": [
{
"description": "a valid timezone matching the data available at https://www.iana.org/time-zones",
"option": "time-zone",
"shorthand": "z",
"value_type": "string"
},
{
"description": "the unit to use for temperature. Valid options are celsius and fahrenheit",
"option": "temperature-unit",
N/A
N/A
N/A
{
"command": "ffx setui intl",
"options": [
{
"description": "a valid timezone matching the data available at https://www.iana.org/time-zones",
"option": "time-zone",
"shorthand": "z",
"value_type": "string"
},
{
"description": "the unit to use for temperature. Valid options are celsius and fahrenheit",
"option": "temperature-unit",
N/A
N/A
N/A
{
"command": "ffx setui keyboard",
"options": [
{
"description": "keymap selection for the keyboard. Valid options are - UsQwerty - FrAzerty - UsDvorak - UsColemak",
"option": "keymap",
"shorthand": "k",
"value_type": "string"
},
{
"description": "delay value of autorepeat values for the keyboard. Values should be a positive integer plus an SI time unit. Valid units are s, ms. If this value and autorepeat_period are zero, the autorepeat field of KeyboardSettings will be cleaned as None.",
"option": "autorepeat-delay",
#[test]
fn test_keyboard_cmd() {
// Test input arguments are generated to according struct.
let keymap = "usqwerty";
let num = "123s";
let args = &["-k", keymap, "-d", num];
assert_eq!(
Keyboard::from_args(CMD_NAME, args),
Ok(Keyboard {
keymap: Some(str_to_keymap(keymap).unwrap()),
autorepeat_delay: Some(str_to_duration(num).unwrap()),
autorepeat_period: None
})
)
}
#[fuchsia::test]
async fn test_run_command() {
const NUM: i64 = 7;
let client = fdomain_local::local_client_empty();
let proxy = fake_proxy(client, move |req| match req {
KeyboardRequest::Set { responder, .. } => {
let _ = responder.send(Ok(()));
}
KeyboardRequest::Watch { .. } => {
panic!("Unexpected call to watch");
}
});
let keyboard =
Keyboard { keymap: None, autorepeat_delay: Some(NUM), autorepeat_period: Some(NUM) };
let response = run_command(proxy, keyboard, &mut vec![]).await;
assert!(response.is_ok());
}
#[fuchsia::test]
async fn validate_keyboard_failure(expected_keyboard: Keyboard) -> Result<()> {
let client = fdomain_local::local_client_empty();
let proxy = fake_proxy(client, move |req| match req {
KeyboardRequest::Set { responder, .. } => {
let _ = responder.send(Ok(()));
}
KeyboardRequest::Watch { responder } => {
let _ = responder.send(&KeyboardSettings::from(expected_keyboard));
}
});
let result = command(proxy, expected_keyboard).await;
match result {
Err(e) => {
assert!(
format!("{:?}", e)
.contains("Negative values are invalid for autorepeat values.")
)
}
_ => panic!("Should return errors."),
}
Ok(())
}
N/A
N/A
{
"command": "ffx setui keyboard",
"options": [
{
"description": "keymap selection for the keyboard. Valid options are - UsQwerty - FrAzerty - UsDvorak - UsColemak",
"option": "keymap",
"shorthand": "k",
"value_type": "string"
},
{
"description": "delay value of autorepeat values for the keyboard. Values should be a positive integer plus an SI time unit. Valid units are s, ms. If this value and autorepeat_period are zero, the autorepeat field of KeyboardSettings will be cleaned as None.",
"option": "autorepeat-delay",
N/A
N/A
N/A
{
"command": "ffx setui keyboard",
"options": [
{
"description": "keymap selection for the keyboard. Valid options are - UsQwerty - FrAzerty - UsDvorak - UsColemak",
"option": "keymap",
"shorthand": "k",
"value_type": "string"
},
{
"description": "delay value of autorepeat values for the keyboard. Values should be a positive integer plus an SI time unit. Valid units are s, ms. If this value and autorepeat_period are zero, the autorepeat field of KeyboardSettings will be cleaned as None.",
"option": "autorepeat-delay",
N/A
N/A
N/A
{
"command": "ffx setui keyboard",
"options": [
{
"description": "keymap selection for the keyboard. Valid options are - UsQwerty - FrAzerty - UsDvorak - UsColemak",
"option": "keymap",
"shorthand": "k",
"value_type": "string"
},
{
"description": "delay value of autorepeat values for the keyboard. Values should be a positive integer plus an SI time unit. Valid units are s, ms. If this value and autorepeat_period are zero, the autorepeat field of KeyboardSettings will be cleaned as None.",
"option": "autorepeat-delay",
N/A
N/A
N/A
{
"command": "ffx setui light",
"options": [
{
"description": "name of a light group to set values for. Required if setting the value of a light group",
"option": "name",
"shorthand": "n",
"value_type": "string"
},
{
"description": "repeated parameter for a list of simple on/off values to set for a light group.",
"option": "simple",
#[test]
fn test_light_cmd() {
// Test input arguments are generated to according struct.
let name = "test";
let simple = "false";
let brightness = "0.5";
let rgb = "0.1,0.4,0.23";
let args = &["-n", name, "-s", simple, "-b", brightness, "-r", rgb];
assert_eq!(
LightGroup::from_args(CMD_NAME, args),
Ok(LightGroup {
name: Some(name.to_string()),
simple: vec![false],
brightness: vec![0.5],
rgb: vec![str_to_rgb(rgb).unwrap()],
})
)
}
#[fuchsia::test]
async fn test_run_command() {
let client = fdomain_local::local_client_empty();
let proxy = fake_proxy(client, move |req| match req {
LightRequest::SetLightGroupValues { responder, .. } => {
let _ = responder.send(Ok(()));
}
LightRequest::WatchLightGroups { .. } => {
panic!("Unexpected call to watch light groups");
}
LightRequest::WatchLightGroup { .. } => {
panic!("Unexpected call to watch a light group");
}
});
let light = LightGroup {
name: Some(TEST_NAME.to_string()),
simple: vec![],
brightness: vec![LIGHT_VAL_1, LIGHT_VAL_2],
rgb: vec![],
};
let response = run_command(proxy, light, &mut vec![]).await;
assert!(response.is_ok());
}
#[fuchsia::test]
async fn validate_light_set_output(expected_light: LightGroup) -> Result<()> {
let client = fdomain_local::local_client_empty();
let proxy = fake_proxy(client, move |req| match req {
LightRequest::SetLightGroupValues { responder, .. } => {
let _ = responder.send(Ok(()));
}
LightRequest::WatchLightGroups { .. } => {
panic!("Unexpected call to watch light groups");
}
LightRequest::WatchLightGroup { .. } => {
panic!("Unexpected call to watch a light group");
}
});
let light_states: Vec<LightState> = expected_light.clone().into();
let output = utils::assert_set!(command(proxy, expected_light.clone()));
assert_eq!(
output,
format!(
"Successfully set light group {} with values {:?}",
expected_light.name.unwrap(),
light_states
)
);
Ok(())
}
N/A
N/A
{
"command": "ffx setui light",
"options": [
{
"description": "name of a light group to set values for. Required if setting the value of a light group",
"option": "name",
"shorthand": "n",
"value_type": "string"
},
{
"description": "repeated parameter for a list of simple on/off values to set for a light group.",
"option": "simple",
N/A
N/A
N/A
{
"command": "ffx setui light",
"options": [
{
"description": "name of a light group to set values for. Required if setting the value of a light group",
"option": "name",
"shorthand": "n",
"value_type": "string"
},
{
"description": "repeated parameter for a list of simple on/off values to set for a light group.",
"option": "simple",
N/A
N/A
N/A
{
"command": "ffx setui light",
"options": [
{
"description": "name of a light group to set values for. Required if setting the value of a light group",
"option": "name",
"shorthand": "n",
"value_type": "string"
},
{
"description": "repeated parameter for a list of simple on/off values to set for a light group.",
"option": "simple",
N/A
N/A
N/A
{
"command": "ffx setui light",
"options": [
{
"description": "name of a light group to set values for. Required if setting the value of a light group",
"option": "name",
"shorthand": "n",
"value_type": "string"
},
{
"description": "repeated parameter for a list of simple on/off values to set for a light group.",
"option": "simple",
N/A
N/A
N/A
{
"command": "ffx setui night_mode",
"options": [
{
"description": "when 'true', enables night mode",
"option": "night-mode-enabled",
"shorthand": "n",
"value_type": "string"
}
],
"short": "get or set night mode settings"
}
N/A
#[test]
fn test_night_mode_cmd() {
// Test input arguments are generated to according struct.
let enabled = "true";
let args = &["-n", enabled];
assert_eq!(
NightMode::from_args(CMD_NAME, args),
Ok(NightMode { night_mode_enabled: Some(true) })
)
}
#[fuchsia::test]
async fn test_run_command() {
const ENABLED: bool = true;
let client = fdomain_local::local_client_empty();
let proxy = fake_proxy(client, move |req| match req {
NightModeRequest::Set { responder, .. } => {
let _ = responder.send(Ok(()));
}
NightModeRequest::Watch { .. } => {
panic!("Unexpected call to watch");
}
});
let night_mode = NightMode { night_mode_enabled: Some(ENABLED) };
let response = run_command(proxy, night_mode, &mut vec![]).await;
assert!(response.is_ok());
}
#[fuchsia::test]
async fn validate_night_mode_set_output(expected_night_mode_enabled: bool) -> Result<()> {
let client = fdomain_local::local_client_empty();
let proxy = fake_proxy(client, move |req| match req {
NightModeRequest::Set { responder, .. } => {
let _ = responder.send(Ok(()));
}
NightModeRequest::Watch { .. } => {
panic!("Unexpected call to watch");
}
});
let output = utils::assert_set!(command(proxy, Some(expected_night_mode_enabled)));
assert_eq!(
output,
format!(
"Successfully set night_mode_enabled to {:?}",
Some(expected_night_mode_enabled)
)
);
Ok(())
}
N/A
N/A
{
"command": "ffx setui night_mode",
"options": [
{
"description": "when 'true', enables night mode",
"option": "night-mode-enabled",
"shorthand": "n",
"value_type": "string"
}
],
"short": "get or set night mode settings"
}
N/A
N/A
N/A
N/A
{
"command": "ffx setui privacy",
"options": [
{
"description": "when 'true', is considered to be user giving consent to have their data shared with product owner, e.g. for metrics collection and crash reporting",
"option": "user-data-sharing-consent",
"shorthand": "u",
"value_type": "string"
}
],
"short": "get or set privacy settings"
}
#[test]
fn test_privacy_cmd() {
// Test input arguments are generated to according struct.
let consent = "true";
let args = &["-u", consent];
assert_eq!(
Privacy::from_args(CMD_NAME, args),
Ok(Privacy { user_data_sharing_consent: Some(true) })
)
}
#[fuchsia::test]
async fn test_run_command() {
const CONSENT: bool = true;
let client = fdomain_local::local_client_empty();
let proxy = fake_proxy(client, move |req| match req {
PrivacyRequest::Set { responder, .. } => {
let _ = responder.send(Ok(()));
}
PrivacyRequest::Watch { .. } => {
panic!("Unexpected call to watch");
}
});
let privacy = Privacy { user_data_sharing_consent: Some(CONSENT) };
let response = run_command(proxy, privacy, &mut vec![]).await;
assert!(response.is_ok());
}
#[fuchsia::test]
async fn validate_privacy_set_output(expected_user_data_sharing_consent: bool) -> Result<()> {
let client = fdomain_local::local_client_empty();
let proxy = fake_proxy(client, move |req| match req {
PrivacyRequest::Set { responder, .. } => {
let _ = responder.send(Ok(()));
}
PrivacyRequest::Watch { .. } => {
panic!("Unexpected call to watch");
}
});
let output = utils::assert_set!(command(proxy, Some(expected_user_data_sharing_consent)));
assert_eq!(
output,
format!(
"Successfully set user_data_sharing_consent to {:?}",
Some(expected_user_data_sharing_consent)
)
);
Ok(())
}
N/A
N/A
{
"command": "ffx setui privacy",
"options": [
{
"description": "when 'true', is considered to be user giving consent to have their data shared with product owner, e.g. for metrics collection and crash reporting",
"option": "user-data-sharing-consent",
"shorthand": "u",
"value_type": "string"
}
],
"short": "get or set privacy settings"
}
N/A
N/A
N/A
{
"command": "ffx setui setup",
"options": [
{
"description": "a supported group of interfaces, specified as a comma-delimited string of the valid values eth and wifi, e.g. \"-i eth,wifi\" or \"-i wifi\"",
"option": "interfaces",
"shorthand": "i",
"value_type": "string"
}
],
"short": "get or set setup settings"
}
#[test]
fn test_setup_cmd() {
// Test input arguments are generated to according struct.
let interfaces = "eth";
let args = &["-i", interfaces];
assert_eq!(
Setup::from_args(CMD_NAME, args),
Ok(Setup { configuration_interfaces: Some(str_to_interfaces(interfaces).unwrap()) })
)
}
#[fuchsia::test]
async fn test_run_command() {
const INTERFACE: ConfigurationInterfaces = ConfigurationInterfaces::ETHERNET;
let client = fdomain_local::local_client_empty();
let proxy = fake_proxy(client, move |req| match req {
SetupRequest::Set { settings, responder, .. } => {
if let Some(val) = settings.enabled_configuration_interfaces {
assert_eq!(val, INTERFACE);
let _ = responder.send(Ok(()));
} else {
panic!("Unexpected call to set");
}
}
SetupRequest::Watch { .. } => {
panic!("Unexpected call to watch");
}
});
let setup = Setup { configuration_interfaces: Some(INTERFACE) };
let response = run_command(proxy, setup, &mut vec![]).await;
assert!(response.is_ok());
}
#[fuchsia::test]
async fn validate_setup_output(expected_interface: ConfigurationInterfaces) -> Result<()> {
let client = fdomain_local::local_client_empty();
let proxy = fake_proxy(client, move |req| match req {
SetupRequest::Set { settings, responder, .. } => {
if let Some(val) = settings.enabled_configuration_interfaces {
assert_eq!(val, expected_interface);
let _ = responder.send(Ok(()));
} else {
panic!("Unexpected call to set");
}
}
SetupRequest::Watch { .. } => {
panic!("Unexpected call to watch");
}
});
let output = utils::assert_set!(command(proxy, Some(expected_interface)));
assert_eq!(
output,
format!("Successfully set configuration interfaces to {:?}", Some(expected_interface))
);
Ok(())
}
N/A
N/A
{
"command": "ffx setui setup",
"options": [
{
"description": "a supported group of interfaces, specified as a comma-delimited string of the valid values eth and wifi, e.g. \"-i eth,wifi\" or \"-i wifi\"",
"option": "interfaces",
"shorthand": "i",
"value_type": "string"
}
],
"short": "get or set setup settings"
}
N/A
N/A
N/A
{
"command": "ffx starnix",
"options": [],
"short": "Control starnix containers"
}
N/A
N/A
{
"command": "ffx starnix adb",
"options": [
{
"description": "path to the adb client command",
"option": "adb",
"shorthand": "",
"value_type": "string"
}
],
"short": "Bridge from host adb to adbd running inside starnix"
}
#[fuchsia::test]
async fn test_adb_relay() {
let any_local_address = "127.0.0.1:0";
let listener = TcpListener::bind(any_local_address).await.unwrap();
let local_address = listener.local_addr().unwrap();
let port = local_address.port();
let client = fdomain_local::local_client_empty();
let (sbridge, cbridge) = client.create_stream_socket();
fasync::Task::spawn(async move {
run_connection(listener, sbridge).await;
})
.detach();
let connect_address = format!("127.0.0.1:{}", port);
let mut stream = TcpStream::connect(connect_address).await.unwrap().into_futures_stream();
let test_data_1: Vec<u8> = vec![1, 2, 3, 4, 5];
stream.write_all(&test_data_1).await.unwrap();
let mut buf = [0u8; 64];
let mut async_socket = cbridge;
let bytes_read = async_socket.read(&mut buf).await.unwrap();
assert_eq!(test_data_1.len(), bytes_read);
for (a, b) in test_data_1.iter().zip(buf[..bytes_read].iter()) {
assert_eq!(a, b);
}
```posix-terminal
N/A
{
"command": "ffx starnix adb",
"options": [
{
"description": "path to the adb client command",
"option": "adb",
"shorthand": "",
"value_type": "string"
}
],
"short": "Bridge from host adb to adbd running inside starnix"
}
N/A
N/A
N/A
{
"command": "ffx starnix adb connect",
"options": [],
"short": "directly connect the local adb server to an adbd instance running on the target."
}
N/A
N/A
N/A
{
"command": "ffx starnix adb proxy",
"options": [
{
"description": "the moniker of the container running adbd (defaults to looking for a container in the current session)",
"option": "moniker",
"shorthand": "m",
"value_type": "string"
},
{
"description": "which port to serve the adb server on",
"option": "port",
N/A
```posix-terminal
N/A
{
"command": "ffx starnix adb proxy",
"options": [
{
"description": "the moniker of the container running adbd (defaults to looking for a container in the current session)",
"option": "moniker",
"shorthand": "m",
"value_type": "string"
},
{
"description": "which port to serve the adb server on",
"option": "port",
N/A
N/A
N/A
{
"command": "ffx starnix adb proxy",
"options": [
{
"description": "the moniker of the container running adbd (defaults to looking for a container in the current session)",
"option": "moniker",
"shorthand": "m",
"value_type": "string"
},
{
"description": "which port to serve the adb server on",
"option": "port",
N/A
N/A
N/A
{
"command": "ffx starnix adb proxy",
"options": [
{
"description": "the moniker of the container running adbd (defaults to looking for a container in the current session)",
"option": "moniker",
"shorthand": "m",
"value_type": "string"
},
{
"description": "which port to serve the adb server on",
"option": "port",
N/A
N/A
N/A
{
"command": "ffx starnix console",
"options": [
{
"description": "the moniker of the container in which to create the console (defaults to looking for a container in the current session)",
"option": "moniker",
"shorthand": "m",
"value_type": "string"
},
{
"description": "environment variables to pass to the program.",
"option": "env",
N/A
```posix-terminal
N/A
{
"command": "ffx starnix console",
"options": [
{
"description": "the moniker of the container in which to create the console (defaults to looking for a container in the current session)",
"option": "moniker",
"shorthand": "m",
"value_type": "string"
},
{
"description": "environment variables to pass to the program.",
"option": "env",
N/A
N/A
N/A
{
"command": "ffx starnix console",
"options": [
{
"description": "the moniker of the container in which to create the console (defaults to looking for a container in the current session)",
"option": "moniker",
"shorthand": "m",
"value_type": "string"
},
{
"description": "environment variables to pass to the program.",
"option": "env",
N/A
N/A
N/A
{
"command": "ffx starnix kill",
"options": [
{
"description": "the linux pid to send the signal to",
"option": "pid",
"shorthand": "p",
"value_type": "string"
},
{
"description": "the signal to send",
"option": "signal",
N/A
```posix-terminal
N/A
{
"command": "ffx starnix kill",
"options": [
{
"description": "the linux pid to send the signal to",
"option": "pid",
"shorthand": "p",
"value_type": "string"
},
{
"description": "the signal to send",
"option": "signal",
N/A
N/A
N/A
{
"command": "ffx starnix kill",
"options": [
{
"description": "the linux pid to send the signal to",
"option": "pid",
"shorthand": "p",
"value_type": "string"
},
{
"description": "the signal to send",
"option": "signal",
N/A
N/A
N/A
{
"command": "ffx starnix resume",
"options": [],
"short": "Resume a Starnix kernel and all the processes running in it"
}
N/A
```posix-terminal
N/A
{
"command": "ffx starnix suspend",
"options": [],
"short": "Suspend a Starnix kernel and all the processes running in it"
}
N/A
```posix-terminal
N/A
{
"command": "ffx starnix vmo",
"options": [
{
"description": "koid of the vmo to search for references to.",
"option": "koid",
"shorthand": "k",
"value_type": "string"
}
],
"short": "Return all processes that have references to a file backed by a vmo with koid"
}
N/A
```posix-terminal
N/A
{
"command": "ffx starnix vmo",
"options": [
{
"description": "koid of the vmo to search for references to.",
"option": "koid",
"shorthand": "k",
"value_type": "string"
}
],
"short": "Return all processes that have references to a file backed by a vmo with koid"
}
N/A
N/A
N/A
{
"command": "ffx storage",
"options": [],
"short": "Manage Fuchsia Filesystems"
}
#[test]
fn test_persistent_build() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let persistent_config = Config::new(
Some(ConfigFile::from_buf(None, BufReader::new(GLOBAL), true)),
Some(ConfigFile::from_buf(None, BufReader::new(BUILD), true)),
Some(ConfigFile::from_buf(None, BufReader::new(USER), true)),
Map::default(),
Map::default(),
);
let value = persistent_config.get("name", SelectMode::First);
assert!(value.is_some());
assert_eq!(value.unwrap(), Value::String(String::from("User")));
let mut user_file_out = String::new();
let mut build_file_out = String::new();
let mut global_file_out = String::new();
unsafe {
persistent_config.write(
Some(BufWriter::new(global_file_out.as_mut_vec())),
Some(BufWriter::new(build_file_out.as_mut_vec())),
Some(BufWriter::new(user_file_out.as_mut_vec())),
)?;
}
// Remove whitespace
let mut user_file = String::from_utf8_lossy(USER).to_string();
let mut build_file = String::from_utf8_lossy(BUILD).to_string();
#[test]
fn test_priority_iterator() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let test = Config {
user: Some(ConfigFile::from_buf(None, BufReader::new(USER), true)),
build: Some(ConfigFile::from_buf(None, BufReader::new(BUILD), true)),
global: Some(ConfigFile::from_buf(None, BufReader::new(GLOBAL), true)),
default: serde_json::from_slice(DEFAULT)?,
runtime: serde_json::from_slice(RUNTIME)?,
};
let mut test_iter = test.iter();
assert_eq!(test_iter.next(), Some(Some(&test.runtime)));
assert_eq!(test_iter.next(), Some(test.user.as_ref().map(|file| &file.contents)));
assert_eq!(test_iter.next(), Some(test.build.as_ref().map(|file| &file.contents)));
assert_eq!(test_iter.next(), Some(test.global.as_ref().map(|file| &file.contents)));
assert_eq!(test_iter.next(), Some(Some(&test.default)));
assert_eq!(test_iter.next(), None);
Ok(())
}
#[test]
fn test_priority_iterator_with_nones() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let test = Config {
user: Some(ConfigFile::from_buf(None, BufReader::new(USER), true)),
build: None,
global: None,
default: serde_json::from_slice(DEFAULT)?,
runtime: ConfigMap::default(),
};
let mut test_iter = test.iter();
assert_eq!(test_iter.next(), Some(Some(&test.runtime)));
assert_eq!(test_iter.next(), Some(test.user.as_ref().map(|file| &file.contents)));
assert_eq!(test_iter.next(), Some(test.build.as_ref().map(|file| &file.contents)));
assert_eq!(test_iter.next(), Some(test.global.as_ref().map(|file| &file.contents)));
assert_eq!(test_iter.next(), Some(Some(&test.default)));
assert_eq!(test_iter.next(), None);
Ok(())
}
N/A
N/A
{
"command": "ffx target",
"options": [],
"short": "Interact with a target device or emulator"
}
// Copyright 2023 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use anyhow::{Context as _, ensure};
// Copyright 2021 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use crate::test::*;
use anyhow::*;
use ffx_config::EnvironmentContext;
use std::time::Duration;
pub(crate) async fn test_manual_add_target_list(context: EnvironmentContext) -> Result<()> {
let isolate = new_isolate(&context, "target-manual-add-target-list").await?;
isolate.start_daemon().await?;
let _ = isolate.ffx(&["target", "add", "--nowait", "[::1]:8022"]).await?;
let out = isolate
.ffx(&["--target", "[::1]:8022", "target", "list", "--format", "a", "--no-probe"])
.await?;
ensure!(out.stdout.contains("[::1]:8022"), "stdout is unexpected: {:?}", out);
ensure!(out.stderr.lines().count() == 0, "stderr is unexpected: {:?}", out);
// TODO: establish a good way to assert against the whole target address.
Ok(())
}
// Copyright 2022 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use anyhow::{Result, anyhow};
N/A
{
"command": "ffx target add",
"options": [
{
"description": "do not wait for a connection to be verified on the Fuchsia device.",
"option": "nowait",
"shorthand": "n",
"value_type": "bool"
}
],
"short": "Make the daemon aware of a specific target"
}
Manual targets are configured via `ffx target add` or `ffx config`. This is currently done by address only.
* manual targets, added via `ffx target add`
// Copyright 2021 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use crate::test::*;
use anyhow::*;
use ffx_config::EnvironmentContext;
use std::time::Duration;
pub(crate) async fn test_manual_add_target_list(context: EnvironmentContext) -> Result<()> {
let isolate = new_isolate(&context, "target-manual-add-target-list").await?;
isolate.start_daemon().await?;
let _ = isolate.ffx(&["target", "add", "--nowait", "[::1]:8022"]).await?;
let out = isolate
.ffx(&["--target", "[::1]:8022", "target", "list", "--format", "a", "--no-probe"])
.await?;
ensure!(out.stdout.contains("[::1]:8022"), "stdout is unexpected: {:?}", out);
ensure!(out.stderr.lines().count() == 0, "stderr is unexpected: {:?}", out);
// TODO: establish a good way to assert against the whole target address.
Ok(())
}
// Copyright 2022 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use anyhow::{Result, anyhow};
N/A
{
"command": "ffx target add",
"options": [
{
"description": "do not wait for a connection to be verified on the Fuchsia device.",
"option": "nowait",
"shorthand": "n",
"value_type": "bool"
}
],
"short": "Make the daemon aware of a specific target"
}
// Copyright 2021 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use crate::test::*;
use anyhow::*;
use ffx_config::EnvironmentContext;
use std::time::Duration;
pub(crate) async fn test_manual_add_target_list(context: EnvironmentContext) -> Result<()> {
let isolate = new_isolate(&context, "target-manual-add-target-list").await?;
isolate.start_daemon().await?;
let _ = isolate.ffx(&["target", "add", "--nowait", "[::1]:8022"]).await?;
let out = isolate
.ffx(&["--target", "[::1]:8022", "target", "list", "--format", "a", "--no-probe"])
.await?;
ensure!(out.stdout.contains("[::1]:8022"), "stdout is unexpected: {:?}", out);
ensure!(out.stderr.lines().count() == 0, "stderr is unexpected: {:?}", out);
// TODO: establish a good way to assert against the whole target address.
Ok(())
}
N/A
N/A
{
"command": "ffx target bootloader",
"options": [
{
"description": "path to flashing manifest or zip file containing images and manifest",
"option": "manifest",
"shorthand": "m",
"value_type": "string"
},
{
"description": "product entry in manifest - defaults to `fuchsia`",
"option": "product",
N/A
N/A
N/A
{
"command": "ffx target bootloader",
"options": [
{
"description": "path to flashing manifest or zip file containing images and manifest",
"option": "manifest",
"shorthand": "m",
"value_type": "string"
},
{
"description": "product entry in manifest - defaults to `fuchsia`",
"option": "product",
N/A
N/A
N/A
{
"command": "ffx target bootloader",
"options": [
{
"description": "path to flashing manifest or zip file containing images and manifest",
"option": "manifest",
"shorthand": "m",
"value_type": "string"
},
{
"description": "product entry in manifest - defaults to `fuchsia`",
"option": "product",
N/A
N/A
N/A
{
"command": "ffx target bootloader",
"options": [
{
"description": "path to flashing manifest or zip file containing images and manifest",
"option": "manifest",
"shorthand": "m",
"value_type": "string"
},
{
"description": "product entry in manifest - defaults to `fuchsia`",
"option": "product",
N/A
N/A
N/A
{
"command": "ffx target bootloader",
"options": [
{
"description": "path to flashing manifest or zip file containing images and manifest",
"option": "manifest",
"shorthand": "m",
"value_type": "string"
},
{
"description": "product entry in manifest - defaults to `fuchsia`",
"option": "product",
N/A
N/A
N/A
{
"command": "ffx target bootloader boot",
"options": [
{
"description": "optional zbi image file path to use",
"option": "zbi",
"shorthand": "z",
"value_type": "string"
},
{
"description": "optional vbmeta image file path to use",
"option": "vbmeta",
N/A
N/A
N/A
{
"command": "ffx target bootloader boot",
"options": [
{
"description": "optional zbi image file path to use",
"option": "zbi",
"shorthand": "z",
"value_type": "string"
},
{
"description": "optional vbmeta image file path to use",
"option": "vbmeta",
N/A
N/A
N/A
{
"command": "ffx target bootloader boot",
"options": [
{
"description": "optional zbi image file path to use",
"option": "zbi",
"shorthand": "z",
"value_type": "string"
},
{
"description": "optional vbmeta image file path to use",
"option": "vbmeta",
N/A
N/A
N/A
{
"command": "ffx target bootloader boot",
"options": [
{
"description": "optional zbi image file path to use",
"option": "zbi",
"shorthand": "z",
"value_type": "string"
},
{
"description": "optional vbmeta image file path to use",
"option": "vbmeta",
N/A
N/A
N/A
{
"command": "ffx target bootloader info",
"options": [],
"short": "Prints fastboot variables for target."
}
N/A
N/A
N/A
{
"command": "ffx target bootloader lock",
"options": [],
"short": "Locks a fastboot target."
}
N/A
N/A
N/A
{
"command": "ffx target bootloader unlock",
"options": [
{
"description": "optional path to credential file to use to unlock the device",
"option": "cred",
"shorthand": "c",
"value_type": "string"
},
{
"description": "skips the warning message that this command is dangerous",
"option": "force",
N/A
N/A
N/A
{
"command": "ffx target bootloader unlock",
"options": [
{
"description": "optional path to credential file to use to unlock the device",
"option": "cred",
"shorthand": "c",
"value_type": "string"
},
{
"description": "skips the warning message that this command is dangerous",
"option": "force",
N/A
N/A
N/A
{
"command": "ffx target bootloader unlock",
"options": [
{
"description": "optional path to credential file to use to unlock the device",
"option": "cred",
"shorthand": "c",
"value_type": "string"
},
{
"description": "skips the warning message that this command is dangerous",
"option": "force",
N/A
N/A
N/A
{
"command": "ffx target clear-preferred-ssh-address",
"options": [],
"short": "Clears a previously configured SSH address"
}
N/A
N/A
N/A
{
"command": "ffx target default",
"options": [],
"short": "View the default target"
}
N/A
N/A
{
"command": "ffx target default get",
"options": [],
"short": "Get the default configured target"
}
N/A
```posix-terminal
```posix-terminal
N/A
{
"command": "ffx target default set",
"options": [],
"short": "Set the default target"
}
N/A
```posix-terminal
N/A
{
"command": "ffx target default unset",
"options": [],
"short": "Clears the configured default target"
}
N/A
```posix-terminal
N/A
{
"command": "ffx target discover",
"options": [
{
"description": "run in a loop, in the specified mode (fg or bg)",
"option": "loop",
"shorthand": "l",
"value_type": "string"
},
{
"description": "do not write to stdout",
"option": "quiet",
To eliminate this delay, you can run `ffx target discover`, which will start a background process to discover the available targets and make them available when connecting to the target. This discovery cache is refreshed by default every 6o seconds, but if you want to refresh it more quickly (e.g. because you have just disconnected a target), you can simply run `ffx target discover` again to update the cache immediately.
have just disconnected a target), you can simply run `ffx target discover` again to update the cache immediately.
N/A
N/A
N/A
{
"command": "ffx target discover",
"options": [
{
"description": "run in a loop, in the specified mode (fg or bg)",
"option": "loop",
"shorthand": "l",
"value_type": "string"
},
{
"description": "do not write to stdout",
"option": "quiet",
N/A
N/A
N/A
{
"command": "ffx target discover",
"options": [
{
"description": "run in a loop, in the specified mode (fg or bg)",
"option": "loop",
"shorthand": "l",
"value_type": "string"
},
{
"description": "do not write to stdout",
"option": "quiet",
N/A
N/A
N/A
{
"command": "ffx target discover",
"options": [
{
"description": "run in a loop, in the specified mode (fg or bg)",
"option": "loop",
"shorthand": "l",
"value_type": "string"
},
{
"description": "do not write to stdout",
"option": "quiet",
N/A
N/A
N/A
{
"command": "ffx target discover",
"options": [
{
"description": "run in a loop, in the specified mode (fg or bg)",
"option": "loop",
"shorthand": "l",
"value_type": "string"
},
{
"description": "do not write to stdout",
"option": "quiet",
N/A
N/A
N/A
{
"command": "ffx target discover clear",
"options": [],
"short": "clear the discovery cache"
}
N/A
N/A
N/A
{
"command": "ffx target echo",
"options": [
{
"description": "run the echo test repeatedly until the command is killed",
"option": "repeat",
"shorthand": "",
"value_type": "bool"
}
],
"short": "run echo test against the target"
}
N/A
```posix-terminal
N/A
{
"command": "ffx target echo",
"options": [
{
"description": "run the echo test repeatedly until the command is killed",
"option": "repeat",
"shorthand": "",
"value_type": "bool"
}
],
"short": "run echo test against the target"
}
N/A
N/A
N/A
{
"command": "ffx target fastboot",
"options": [],
"short": "Perform fastboot operations on a target device"
}
N/A
```posix-terminal
N/A
{
"command": "ffx target fastboot authorize",
"options": [],
"short": "Authorize subcommand."
}
N/A
N/A
N/A
{
"command": "ffx target fastboot continue",
"options": [],
"short": "Continue subcommand"
}
N/A
N/A
N/A
{
"command": "ffx target fastboot flash",
"options": [],
"short": "Flash subcommand"
}
N/A
```posix-terminal
N/A
{
"command": "ffx target fastboot getvar",
"options": [],
"short": "Get Variable subcommand"
}
N/A
N/A
N/A
{
"command": "ffx target fastboot oem",
"options": [],
"short": "Oem subcommand"
}
N/A
N/A
N/A
{
"command": "ffx target fastboot reboot",
"options": [],
"short": "Reboot subcommand"
}
#[fuchsia::test]
async fn test_fastboot_reboot_product() -> Result<()> {
let env = ffx_config::test_init().unwrap();
let (target, proxy) = setup_usb(&env.context).await;
target.set_state(TargetConnectionState::Fastboot(Instant::now()));
proxy
.reboot(TargetRebootState::Product)
.await?
.map_err(|e| anyhow!("error rebooting: {:?}", e))
}
#[fuchsia::test]
async fn test_fastboot_reboot_recovery() -> Result<()> {
let env = ffx_config::test_init().unwrap();
let (target, proxy) = setup_usb(&env.context).await;
target.set_state(TargetConnectionState::Fastboot(Instant::now()));
assert!(proxy.reboot(TargetRebootState::Recovery).await?.is_err());
Ok(())
}
#[fuchsia::test]
async fn test_fastboot_reboot_bootloader() -> Result<()> {
let env = ffx_config::test_init().unwrap();
let (target, proxy) = setup_usb(&env.context).await;
target.set_state(TargetConnectionState::Fastboot(Instant::now()));
proxy
.reboot(TargetRebootState::Bootloader)
.await?
.map_err(|e| anyhow!("error rebooting: {:?}", e))
}
N/A
N/A
{
"command": "ffx target fastboot sparse",
"options": [
{
"description": "size to split the image into. If unset defaults to target's max download size",
"option": "size",
"shorthand": "",
"value_type": "string"
}
],
"short": "Sparse subcommand."
}
N/A
N/A
N/A
{
"command": "ffx target fastboot sparse",
"options": [
{
"description": "size to split the image into. If unset defaults to target's max download size",
"option": "size",
"shorthand": "",
"value_type": "string"
}
],
"short": "Sparse subcommand."
}
N/A
N/A
N/A
{
"command": "ffx target fastboot stage",
"options": [],
"short": "Stage subcommand"
}
N/A
N/A
N/A
{
"command": "ffx target flash",
"options": [
{
"description": "product entry in manifest - defaults to `fuchsia`",
"option": "product",
"shorthand": "p",
"value_type": "string"
},
{
"description": "optional product bundle name",
"option": "product-bundle",
to get the device into a flashable state before `ffx target flash` can be executed. For internal products, see the README in the v/g repository for more information.
2. **Flash the device:** Use `ffx target flash` to push the downloaded image onto the hardware. 3. **Wait for boot:** Ensure the device successfully boots and reconnects to `ffx`. 4. **Execute the test:** Run the specific test you are trying to bisect (e.g., an `fx test` command, a custom Python script, or pinging an endpoint). 5. **Return the outcome:** Exit with `0` on success, or non-zero on failure.
N/A
```posix-terminal
```posix-terminal
N/A
{
"command": "ffx target flash",
"options": [
{
"description": "product entry in manifest - defaults to `fuchsia`",
"option": "product",
"shorthand": "p",
"value_type": "string"
},
{
"description": "optional product bundle name",
"option": "product-bundle",
N/A
N/A
N/A
{
"command": "ffx target flash",
"options": [
{
"description": "product entry in manifest - defaults to `fuchsia`",
"option": "product",
"shorthand": "p",
"value_type": "string"
},
{
"description": "optional product bundle name",
"option": "product-bundle",
N/A
```posix-terminal
N/A
{
"command": "ffx target flash",
"options": [
{
"description": "product entry in manifest - defaults to `fuchsia`",
"option": "product",
"shorthand": "p",
"value_type": "string"
},
{
"description": "optional product bundle name",
"option": "product-bundle",
N/A
N/A
N/A
{
"command": "ffx target flash",
"options": [
{
"description": "product entry in manifest - defaults to `fuchsia`",
"option": "product",
"shorthand": "p",
"value_type": "string"
},
{
"description": "optional product bundle name",
"option": "product-bundle",
N/A
N/A
N/A
{
"command": "ffx target flash",
"options": [
{
"description": "product entry in manifest - defaults to `fuchsia`",
"option": "product",
"shorthand": "p",
"value_type": "string"
},
{
"description": "optional product bundle name",
"option": "product-bundle",
N/A
N/A
N/A
{
"command": "ffx target flash",
"options": [
{
"description": "product entry in manifest - defaults to `fuchsia`",
"option": "product",
"shorthand": "p",
"value_type": "string"
},
{
"description": "optional product bundle name",
"option": "product-bundle",
N/A
```posix-terminal
N/A
{
"command": "ffx target flash",
"options": [
{
"description": "product entry in manifest - defaults to `fuchsia`",
"option": "product",
"shorthand": "p",
"value_type": "string"
},
{
"description": "optional product bundle name",
"option": "product-bundle",
N/A
N/A
N/A
{
"command": "ffx target flash",
"options": [
{
"description": "product entry in manifest - defaults to `fuchsia`",
"option": "product",
"shorthand": "p",
"value_type": "string"
},
{
"description": "optional product bundle name",
"option": "product-bundle",
N/A
N/A
N/A
{
"command": "ffx target flash",
"options": [
{
"description": "product entry in manifest - defaults to `fuchsia`",
"option": "product",
"shorthand": "p",
"value_type": "string"
},
{
"description": "optional product bundle name",
"option": "product-bundle",
N/A
N/A
N/A
{
"command": "ffx target forward",
"options": [],
"short": "Forward ports from a target"
}
N/A
N/A
N/A
{
"command": "ffx target forward tcp",
"options": [],
"short": "Forward a TCP port from the target to the host"
}
N/A
N/A
N/A
{
"command": "ffx target get-time",
"options": [
{
"description": "if true, return boot time",
"option": "boot",
"shorthand": "b",
"value_type": "bool"
}
],
"short": "Returns the current time in the system monotonic clock. This is the number of nanoseconds since the system was powered on. It does not always reset on reboot and does not adjust during sleep, and thus should not be used as a reliable source of uptime. See https://fuchsia.dev/reference/syscalls/clock_get_monotonic"
}
N/A
```posix-terminal
N/A
{
"command": "ffx target get-time",
"options": [
{
"description": "if true, return boot time",
"option": "boot",
"shorthand": "b",
"value_type": "bool"
}
],
"short": "Returns the current time in the system monotonic clock. This is the number of nanoseconds since the system was powered on. It does not always reset on reboot and does not adjust during sleep, and thus should not be used as a reliable source of uptime. See https://fuchsia.dev/reference/syscalls/clock_get_monotonic"
}
N/A
N/A
N/A
{
"command": "ffx target list",
"options": [
{
"description": "determines the output format for the list operation",
"option": "format",
"shorthand": "f",
"value_type": "string"
},
{
"description": "do not return IPv4 addresses (deprecated, use --allow-addrs/--deny-addrs)",
"option": "no-ipv4",
When multiple targets are visible in `ffx target list`, you must specify which target to use. Most `ffx` commands will fail if it is ambiguous which device they should operate on.
- The target's IP address (any address mentioned in `ffx target list`). - The target's serial number.
// Copyright 2021 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use crate::test::*;
use anyhow::*;
use ffx_config::EnvironmentContext;
use std::time::Duration;
pub(crate) async fn test_manual_add_target_list(context: EnvironmentContext) -> Result<()> {
let isolate = new_isolate(&context, "target-manual-add-target-list").await?;
isolate.start_daemon().await?;
let _ = isolate.ffx(&["target", "add", "--nowait", "[::1]:8022"]).await?;
let out = isolate
.ffx(&["--target", "[::1]:8022", "target", "list", "--format", "a", "--no-probe"])
.await?;
ensure!(out.stdout.contains("[::1]:8022"), "stdout is unexpected: {:?}", out);
ensure!(out.stderr.lines().count() == 0, "stderr is unexpected: {:?}", out);
// TODO: establish a good way to assert against the whole target address.
Ok(())
}
output: str = self.ffx.run(
cmd=cmd,
include_target=False,
)
targets = json.loads(output)
if not targets:
raise ffx_errors.FfxCommandError(
f"Target '{self.device_name}' not found in 'ffx target list'"
output: str = self.run(
cmd=cmd,
include_target=False,
)
target_info_from_target_list: list[dict[str, Any]] = json.loads(output)
_LOGGER.debug(
"`%s` returned: %s", " ".join(cmd), target_info_from_target_list
)
if len(target_info_from_target_list) == 1:
return target_info_from_target_list[0]
else:
raise ffx_errors.FfxCommandError(
f"'{target}' is not connected to host"
N/A
{
"command": "ffx target list",
"options": [
{
"description": "determines the output format for the list operation",
"option": "format",
"shorthand": "f",
"value_type": "string"
},
{
"description": "do not return IPv4 addresses (deprecated, use --allow-addrs/--deny-addrs)",
"option": "no-ipv4",
N/A
N/A
N/A
{
"command": "ffx target list",
"options": [
{
"description": "determines the output format for the list operation",
"option": "format",
"shorthand": "f",
"value_type": "string"
},
{
"description": "do not return IPv4 addresses (deprecated, use --allow-addrs/--deny-addrs)",
"option": "no-ipv4",
N/A
N/A
N/A
{
"command": "ffx target list",
"options": [
{
"description": "determines the output format for the list operation",
"option": "format",
"shorthand": "f",
"value_type": "string"
},
{
"description": "do not return IPv4 addresses (deprecated, use --allow-addrs/--deny-addrs)",
"option": "no-ipv4",
// Copyright 2021 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use crate::test::*;
use anyhow::*;
use ffx_config::EnvironmentContext;
use std::time::Duration;
pub(crate) async fn test_manual_add_target_list(context: EnvironmentContext) -> Result<()> {
let isolate = new_isolate(&context, "target-manual-add-target-list").await?;
isolate.start_daemon().await?;
let _ = isolate.ffx(&["target", "add", "--nowait", "[::1]:8022"]).await?;
let out = isolate
.ffx(&["--target", "[::1]:8022", "target", "list", "--format", "a", "--no-probe"])
.await?;
ensure!(out.stdout.contains("[::1]:8022"), "stdout is unexpected: {:?}", out);
ensure!(out.stderr.lines().count() == 0, "stderr is unexpected: {:?}", out);
// TODO: establish a good way to assert against the whole target address.
Ok(())
}
```posix-terminal
N/A
{
"command": "ffx target list",
"options": [
{
"description": "determines the output format for the list operation",
"option": "format",
"shorthand": "f",
"value_type": "string"
},
{
"description": "do not return IPv4 addresses (deprecated, use --allow-addrs/--deny-addrs)",
"option": "no-ipv4",
N/A
N/A
N/A
{
"command": "ffx target list",
"options": [
{
"description": "determines the output format for the list operation",
"option": "format",
"shorthand": "f",
"value_type": "string"
},
{
"description": "do not return IPv4 addresses (deprecated, use --allow-addrs/--deny-addrs)",
"option": "no-ipv4",
N/A
N/A
N/A
{
"command": "ffx target list",
"options": [
{
"description": "determines the output format for the list operation",
"option": "format",
"shorthand": "f",
"value_type": "string"
},
{
"description": "do not return IPv4 addresses (deprecated, use --allow-addrs/--deny-addrs)",
"option": "no-ipv4",
N/A
N/A
N/A
{
"command": "ffx target list",
"options": [
{
"description": "determines the output format for the list operation",
"option": "format",
"shorthand": "f",
"value_type": "string"
},
{
"description": "do not return IPv4 addresses (deprecated, use --allow-addrs/--deny-addrs)",
"option": "no-ipv4",
// Copyright 2021 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use crate::test::*;
use anyhow::*;
use ffx_config::EnvironmentContext;
use std::time::Duration;
pub(crate) async fn test_manual_add_target_list(context: EnvironmentContext) -> Result<()> {
let isolate = new_isolate(&context, "target-manual-add-target-list").await?;
isolate.start_daemon().await?;
let _ = isolate.ffx(&["target", "add", "--nowait", "[::1]:8022"]).await?;
let out = isolate
.ffx(&["--target", "[::1]:8022", "target", "list", "--format", "a", "--no-probe"])
.await?;
ensure!(out.stdout.contains("[::1]:8022"), "stdout is unexpected: {:?}", out);
ensure!(out.stderr.lines().count() == 0, "stderr is unexpected: {:?}", out);
// TODO: establish a good way to assert against the whole target address.
Ok(())
}
output: str = self.ffx.run(
cmd=cmd,
include_target=False,
)
targets = json.loads(output)
if not targets:
raise ffx_errors.FfxCommandError(
f"Target '{self.device_name}' not found in 'ffx target list'"
output: str = self.run(cmd=cmd, include_target=False)
targets = json.loads(output)
if not targets:
raise ffx_errors.FfxCommandError(
f"Target '{self._query}' not found in 'ffx target list'"
N/A
N/A
{
"command": "ffx target list",
"options": [
{
"description": "determines the output format for the list operation",
"option": "format",
"shorthand": "f",
"value_type": "string"
},
{
"description": "do not return IPv4 addresses (deprecated, use --allow-addrs/--deny-addrs)",
"option": "no-ipv4",
output: str = self.ffx.run(
cmd=cmd,
include_target=False,
)
targets = json.loads(output)
if not targets:
raise ffx_errors.FfxCommandError(
f"Target '{self.device_name}' not found in 'ffx target list'"
output: str = self.run(cmd=cmd, include_target=False)
targets = json.loads(output)
if not targets:
raise ffx_errors.FfxCommandError(
f"Target '{self._query}' not found in 'ffx target list'"
N/A
N/A
{
"command": "ffx target log-message",
"options": [
{
"description": "the log tag to use",
"option": "tag",
"shorthand": "t",
"value_type": "string"
},
{
"description": "trace, debug, info, warn, error, fatal",
"option": "severity",
N/A
```posix-terminal
N/A
{
"command": "ffx target log-message",
"options": [
{
"description": "the log tag to use",
"option": "tag",
"shorthand": "t",
"value_type": "string"
},
{
"description": "trace, debug, info, warn, error, fatal",
"option": "severity",
N/A
N/A
N/A
{
"command": "ffx target log-message",
"options": [
{
"description": "the log tag to use",
"option": "tag",
"shorthand": "t",
"value_type": "string"
},
{
"description": "trace, debug, info, warn, error, fatal",
"option": "severity",
N/A
N/A
N/A
{
"command": "ffx target off",
"options": [],
"short": "Powers off a target"
}
N/A
N/A
N/A
{
"command": "ffx target package",
"options": [],
"short": "Interact with target package management"
}
N/A
```posix-terminal
N/A
{
"command": "ffx target package explore",
"options": [
{
"description": "the chain of subpackages, if any, of `url` to resolve, in resolution order. If `subpackages` is not empty, the package directory of the final subpackage will be loaded into the shell's namespace at `/pkg`.",
"option": "subpackage",
"shorthand": "",
"value_type": "string"
},
{
"description": "list of URLs of tools packages to include in the shell environment. the PATH variable will be updated to include binaries from these tools packages. repeat `--tools url` for each package to be included. The path preference is given by command line order.",
"option": "tools",
N/A
```posix-terminal
N/A
{
"command": "ffx target package explore",
"options": [
{
"description": "the chain of subpackages, if any, of `url` to resolve, in resolution order. If `subpackages` is not empty, the package directory of the final subpackage will be loaded into the shell's namespace at `/pkg`.",
"option": "subpackage",
"shorthand": "",
"value_type": "string"
},
{
"description": "list of URLs of tools packages to include in the shell environment. the PATH variable will be updated to include binaries from these tools packages. repeat `--tools url` for each package to be included. The path preference is given by command line order.",
"option": "tools",
N/A
N/A
N/A
{
"command": "ffx target package explore",
"options": [
{
"description": "the chain of subpackages, if any, of `url` to resolve, in resolution order. If `subpackages` is not empty, the package directory of the final subpackage will be loaded into the shell's namespace at `/pkg`.",
"option": "subpackage",
"shorthand": "",
"value_type": "string"
},
{
"description": "list of URLs of tools packages to include in the shell environment. the PATH variable will be updated to include binaries from these tools packages. repeat `--tools url` for each package to be included. The path preference is given by command line order.",
"option": "tools",
N/A
N/A
N/A
{
"command": "ffx target package explore",
"options": [
{
"description": "the chain of subpackages, if any, of `url` to resolve, in resolution order. If `subpackages` is not empty, the package directory of the final subpackage will be loaded into the shell's namespace at `/pkg`.",
"option": "subpackage",
"shorthand": "",
"value_type": "string"
},
{
"description": "list of URLs of tools packages to include in the shell environment. the PATH variable will be updated to include binaries from these tools packages. repeat `--tools url` for each package to be included. The path preference is given by command line order.",
"option": "tools",
N/A
N/A
N/A
{
"command": "ffx target package explore",
"options": [
{
"description": "the chain of subpackages, if any, of `url` to resolve, in resolution order. If `subpackages` is not empty, the package directory of the final subpackage will be loaded into the shell's namespace at `/pkg`.",
"option": "subpackage",
"shorthand": "",
"value_type": "string"
},
{
"description": "list of URLs of tools packages to include in the shell environment. the PATH variable will be updated to include binaries from these tools packages. repeat `--tools url` for each package to be included. The path preference is given by command line order.",
"option": "tools",
N/A
N/A
N/A
{
"command": "ffx target package gc",
"options": [],
"short": "Trigger garbage collection on a target"
}
N/A
N/A
N/A
{
"command": "ffx target package resolve",
"options": [],
"short": "Resolve packages from configured repositories on a target"
}
N/A
N/A
N/A
{
"command": "ffx target reboot",
"options": [
{
"description": "reboot to bootloader",
"option": "bootloader",
"shorthand": "b",
"value_type": "bool"
},
{
"description": "reboot to recovery",
"option": "recovery",
#[fuchsia::test]
async fn test_reboot_product() -> Result<()> {
let env = ffx_config::test_init().unwrap();
let (_, proxy) = setup(&env.context).await;
proxy
.reboot(TargetRebootState::Product)
.await?
.map_err(|e| anyhow!("error rebooting: {:?}", e))
}
#[fuchsia::test]
async fn test_reboot_recovery() -> Result<()> {
let env = ffx_config::test_init().unwrap();
let (_, proxy) = setup(&env.context).await;
proxy
.reboot(TargetRebootState::Recovery)
.await?
.map_err(|e| anyhow!("error rebooting: {:?}", e))
}
#[fuchsia::test]
async fn test_reboot_bootloader() -> Result<()> {
let env = ffx_config::test_init().unwrap();
let (_, proxy) = setup(&env.context).await;
proxy
.reboot(TargetRebootState::Bootloader)
.await?
.map_err(|e| anyhow!("error rebooting: {:?}", e))
}
N/A
{
"command": "ffx target reboot",
"options": [
{
"description": "reboot to bootloader",
"option": "bootloader",
"shorthand": "b",
"value_type": "bool"
},
{
"description": "reboot to recovery",
"option": "recovery",
self.ffx.run(cmd=_FFX_CMDS["BOOT_TO_FASTBOOT_MODE"])
except ffx_errors.FfxCommandError:
# Command is expected to fail as device reboots immediately
pass
# TODO(b/359261703): Once issue is resolved, remove `| None` from type hint for `serial_transport` and `power_switch`
async def _boot_to_fastboot_mode_using_serial(
self,
serial_transport: serial_interface.Serial | None,
power_switch: power_switch_interface.PowerSwitch | None,
outlet: int | None = None,
) -> None:
"""Boot the device to fastboot mode using serial.
Args:
serial_transport: Implementation of Serial interface.
power_switch: Implementation of PowerSwitch interface.
outlet (int): If required by power switch hardware, outlet on
power switch hardware where this fuchsia device is connected.
Raises:
ValueError: Invalid args sent.
"""
if power_switch is None or serial_transport is None:
raise ValueError(
f"'power_switch' and 'serial_transport' args need to be provided to reboot "
f"'{self._device_name}' into Fastboot using Serial"
N/A
{
"command": "ffx target reboot",
"options": [
{
"description": "reboot to bootloader",
"option": "bootloader",
"shorthand": "b",
"value_type": "bool"
},
{
"description": "reboot to recovery",
"option": "recovery",
N/A
N/A
N/A
{
"command": "ffx target remove",
"options": [
{
"description": "remove all manually added targets",
"option": "all",
"shorthand": "",
"value_type": "bool"
}
],
"short": "Make the daemon forget a specific target"
}
N/A
```posix-terminal
N/A
{
"command": "ffx target remove",
"options": [
{
"description": "remove all manually added targets",
"option": "all",
"shorthand": "",
"value_type": "bool"
}
],
"short": "Make the daemon forget a specific target"
}
N/A
N/A
N/A
{
"command": "ffx target repository",
"options": [],
"short": "Interact with target repository registration"
}
// Copyright 2023 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use anyhow::{Context as _, ensure};
N/A
N/A
{
"command": "ffx target repository deregister",
"options": [
{
"description": "remove the repository named `name` from the target, rather than the default.",
"option": "repository",
"shorthand": "r",
"value_type": "string"
},
{
"description": "repository server port number. Required to disambiguate multiple repositories with the same name.",
"option": "port",
N/A
N/A
N/A
{
"command": "ffx target repository deregister",
"options": [
{
"description": "remove the repository named `name` from the target, rather than the default.",
"option": "repository",
"shorthand": "r",
"value_type": "string"
},
{
"description": "repository server port number. Required to disambiguate multiple repositories with the same name.",
"option": "port",
N/A
N/A
N/A
{
"command": "ffx target repository deregister",
"options": [
{
"description": "remove the repository named `name` from the target, rather than the default.",
"option": "repository",
"shorthand": "r",
"value_type": "string"
},
{
"description": "repository server port number. Required to disambiguate multiple repositories with the same name.",
"option": "port",
N/A
N/A
N/A
{
"command": "ffx target repository list",
"options": [],
"short": "List all the repositories on a target"
}
N/A
N/A
N/A
{
"command": "ffx target repository register",
"options": [
{
"description": "register this repository, rather than the default.",
"option": "repository",
"shorthand": "r",
"value_type": "string"
},
{
"description": "repository server port number. Required to disambiguate multiple repositories with the same name.",
"option": "port",
// Copyright 2023 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use anyhow::{Context as _, ensure};
N/A
N/A
{
"command": "ffx target repository register",
"options": [
{
"description": "register this repository, rather than the default.",
"option": "repository",
"shorthand": "r",
"value_type": "string"
},
{
"description": "repository server port number. Required to disambiguate multiple repositories with the same name.",
"option": "port",
N/A
N/A
N/A
{
"command": "ffx target repository register",
"options": [
{
"description": "register this repository, rather than the default.",
"option": "repository",
"shorthand": "r",
"value_type": "string"
},
{
"description": "repository server port number. Required to disambiguate multiple repositories with the same name.",
"option": "port",
// Copyright 2023 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use anyhow::{Context as _, ensure};
N/A
N/A
{
"command": "ffx target repository register",
"options": [
{
"description": "register this repository, rather than the default.",
"option": "repository",
"shorthand": "r",
"value_type": "string"
},
{
"description": "repository server port number. Required to disambiguate multiple repositories with the same name.",
"option": "port",
N/A
N/A
N/A
{
"command": "ffx target repository register",
"options": [
{
"description": "register this repository, rather than the default.",
"option": "repository",
"shorthand": "r",
"value_type": "string"
},
{
"description": "repository server port number. Required to disambiguate multiple repositories with the same name.",
"option": "port",
N/A
N/A
N/A
{
"command": "ffx target repository register",
"options": [
{
"description": "register this repository, rather than the default.",
"option": "repository",
"shorthand": "r",
"value_type": "string"
},
{
"description": "repository server port number. Required to disambiguate multiple repositories with the same name.",
"option": "port",
N/A
N/A
N/A
{
"command": "ffx target repository register",
"options": [
{
"description": "register this repository, rather than the default.",
"option": "repository",
"shorthand": "r",
"value_type": "string"
},
{
"description": "repository server port number. Required to disambiguate multiple repositories with the same name.",
"option": "port",
// Copyright 2023 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use anyhow::{Context as _, ensure};
N/A
N/A
{
"command": "ffx target repository register",
"options": [
{
"description": "register this repository, rather than the default.",
"option": "repository",
"shorthand": "r",
"value_type": "string"
},
{
"description": "repository server port number. Required to disambiguate multiple repositories with the same name.",
"option": "port",
N/A
N/A
N/A
{
"command": "ffx target repository resolve",
"options": [],
"short": "Resolve packages from configured repositories on a target"
}
N/A
N/A
N/A
{
"command": "ffx target repository rule",
"options": [],
"short": "Configure rewriting rules on a target"
}
N/A
N/A
N/A
{
"command": "ffx target repository rule replace",
"options": [
{
"description": "read the rules from a configuration in a json file. Must be either a path or an URL. This is mutually exclusive with the `rule` option.",
"option": "json-uri",
"shorthand": "u",
"value_type": "string"
},
{
"description": "read the rules from a string provided in the argument. Must be valid JSON. This is mutually exclusive with the `json_uri` option.",
"option": "rule",
N/A
N/A
N/A
{
"command": "ffx target repository rule replace",
"options": [
{
"description": "read the rules from a configuration in a json file. Must be either a path or an URL. This is mutually exclusive with the `rule` option.",
"option": "json-uri",
"shorthand": "u",
"value_type": "string"
},
{
"description": "read the rules from a string provided in the argument. Must be valid JSON. This is mutually exclusive with the `json_uri` option.",
"option": "rule",
N/A
N/A
N/A
{
"command": "ffx target repository rule replace",
"options": [
{
"description": "read the rules from a configuration in a json file. Must be either a path or an URL. This is mutually exclusive with the `rule` option.",
"option": "json-uri",
"shorthand": "u",
"value_type": "string"
},
{
"description": "read the rules from a string provided in the argument. Must be valid JSON. This is mutually exclusive with the `json_uri` option.",
"option": "rule",
N/A
N/A
N/A
{
"command": "ffx target screenshot",
"options": [
{
"description": "override the default directory where the screenshot will be saved",
"option": "dir",
"shorthand": "d",
"value_type": "string"
},
{
"description": "screenshot format. If no value is provided bgra will be used.\n Accepted values: bgra, rgba, png",
"option": "format",
self._ffx.run(cmd=_FFX_SCREENSHOT_CMD + [temp_dir])
image = types.ScreenshotImage.load_from_path(path)
_LOGGER.debug("Screenshot taken")
return image
```posix-terminal
N/A
{
"command": "ffx target screenshot",
"options": [
{
"description": "override the default directory where the screenshot will be saved",
"option": "dir",
"shorthand": "d",
"value_type": "string"
},
{
"description": "screenshot format. If no value is provided bgra will be used.\n Accepted values: bgra, rgba, png",
"option": "format",
N/A
N/A
N/A
{
"command": "ffx target screenshot",
"options": [
{
"description": "override the default directory where the screenshot will be saved",
"option": "dir",
"shorthand": "d",
"value_type": "string"
},
{
"description": "screenshot format. If no value is provided bgra will be used.\n Accepted values: bgra, rgba, png",
"option": "format",
self._ffx.run(cmd=_FFX_SCREENSHOT_CMD + [temp_dir])
image = types.ScreenshotImage.load_from_path(path)
_LOGGER.debug("Screenshot taken")
return image
N/A
N/A
{
"command": "ffx target set-preferred-ssh-address",
"options": [],
"short": "Sets the preferred SSH address"
}
N/A
```posix-terminal
N/A
{
"command": "ffx target shell",
"options": [],
"short": "open a developer shell to a target device"
}
N/A
N/A
N/A
{
"command": "ffx target show",
"options": [
{
"description": "display descriptions of entries",
"option": "desc",
"shorthand": "",
"value_type": "bool"
},
{
"description": "display label of entries",
"option": "label",
[i] Running `ffx target show` against device
output: str = self.run(cmd=cmd)
target_info = TargetInfoData(**json.loads(output))
_LOGGER.debug("`%s` returned: %s", " ".join(cmd), target_info)
return target_info
# TODO(b/455928356) This method would be removed in favor of `get_target_status`.
def get_target_info_from_target_list(self) -> dict[str, Any]:
"""Executed and returns the output of
`ffx --machine json target list <target>`.
For monitor, the "targets" field of `ffx monitor status`
response is identical with `ffx target list`, so they can share
the same parsing logic.
Returns:
Output of `ffx --machine json target list <target>`.
Raises:
FfxCommandError: In case of FFX command failure.
"""
if self._use_monitor:
return asdict(self._get_target_status())
if self._target_addr is not None:
target = str(self._target_addr)
else:
target = self._query
N/A
N/A
{
"command": "ffx target show",
"options": [
{
"description": "display descriptions of entries",
"option": "desc",
"shorthand": "",
"value_type": "bool"
},
{
"description": "display label of entries",
"option": "label",
N/A
N/A
N/A
{
"command": "ffx target show",
"options": [
{
"description": "display descriptions of entries",
"option": "desc",
"shorthand": "",
"value_type": "bool"
},
{
"description": "display label of entries",
"option": "label",
N/A
N/A
N/A
{
"command": "ffx target snapshot",
"options": [
{
"description": "valid directory where the snapshot will be stored",
"option": "dir",
"shorthand": "d",
"value_type": "string"
},
{
"description": "print annotations without capturing the snapshot, ignores `dir` and `upload` flags",
"option": "dump-annotations",
N/A
```posix-terminal
N/A
{
"command": "ffx target snapshot",
"options": [
{
"description": "valid directory where the snapshot will be stored",
"option": "dir",
"shorthand": "d",
"value_type": "string"
},
{
"description": "print annotations without capturing the snapshot, ignores `dir` and `upload` flags",
"option": "dump-annotations",
N/A
N/A
N/A
{
"command": "ffx target snapshot",
"options": [
{
"description": "valid directory where the snapshot will be stored",
"option": "dir",
"shorthand": "d",
"value_type": "string"
},
{
"description": "print annotations without capturing the snapshot, ignores `dir` and `upload` flags",
"option": "dump-annotations",
N/A
N/A
N/A
{
"command": "ffx target snapshot",
"options": [
{
"description": "valid directory where the snapshot will be stored",
"option": "dir",
"shorthand": "d",
"value_type": "string"
},
{
"description": "print annotations without capturing the snapshot, ignores `dir` and `upload` flags",
"option": "dump-annotations",
N/A
N/A
N/A
{
"command": "ffx target ssh",
"options": [
{
"description": "path to the custom ssh config file to use.",
"option": "sshconfig",
"shorthand": "",
"value_type": "string"
}
],
"short": "SSH to a target device"
}
return self.run(
ffx_cmd, capture_output=capture_output, machine=MachineFormat.RAW
)
def wait_for_rcs_connection(
self, include_target_name: bool = False
) -> None:
"""Wait until FFX is able to establish a RCS connection to the target.
Args:
include_target_name: If set to True, target will be specified by query.
Otherwise, target will be specified by address.
Raises:
DeviceNotConnectedError: If FFX fails to reach target.
FfxCommandError: In case of other FFX command failure.
"""
_LOGGER.info("Waiting for %s to connect to host...", self._log_name)
if self._use_monitor:
while True:
target = self._get_target_status()
if target.target_state == "Product" and target.rcs_state == "Y":
_LOGGER.info("%s is connected to host", self._log_name)
return
self.run(
cmd=_FFX_CMDS["TARGET_WAIT"],
include_target_name=include_target_name,
disable_controlmaster=True,
)
self.dut.ffx.run(cmd, machine=ffx_types.MachineFormat.RAW)
async def test_ffx_run_subtool(self) -> None:
"""Test case for FFX.run() with a subtool.
This test requires the test to have `test_data_deps=["//src/developer/ffx/tools/power:ffx_power_test_data"]`
to ensure the subtool exists.
"""
cmd: list[str] = ["power", "help"]
self.dut.ffx.run(cmd)
async def test_wait_for_rcs_connection(self) -> None:
"""Test case for FFX.wait_for_rcs_connection()."""
self.dut.ffx.wait_for_rcs_connection()
async def test_ffx_run_test_component(self) -> None:
"""Test case for FFX.run_test_component()."""
# Skip test if run on non-eng images.
asserts.skip_if(
"core/test_manager" not in self.dut.ffx.run(["component", "list"]),
"Test manager component is not present",
)
output: str = self.dut.ffx.run_test_component(
"fuchsia-pkg://fuchsia.com/hello-world-rust-tests#meta/hello-world-rust-tests.cm",
)
asserts.assert_in("PASSED", output)
async def test_ffx_run_ssh_cmd(self) -> None:
"""Test case for FFX.run_ssh_cmd()."""
cmd: str = "ls"
```posix-terminal
N/A
{
"command": "ffx target ssh",
"options": [
{
"description": "path to the custom ssh config file to use.",
"option": "sshconfig",
"shorthand": "",
"value_type": "string"
}
],
"short": "SSH to a target device"
}
N/A
N/A
N/A
{
"command": "ffx target status",
"options": [],
"short": "Run status checks step by step to determine a device's state"
}
N/A
N/A
N/A
{
"command": "ffx target update",
"options": [],
"short": "Update base system software on target"
}
from the history of [`ffx target update`](https://cs.opensource.google/fuchsia/fuchsia/+/main:src/developer/ffx/plugins/target/update/src/lib.rs;l=19) for an example). If users want to use a subcommand, they will need to set the associated config option in order to invoke that subcommand.
N/A
```posix-terminal
```posix-terminal
```posix-terminal
N/A
{
"command": "ffx target update channel",
"options": [],
"short": "View and manage update channels"
}
N/A
```posix-terminal
N/A
{
"command": "ffx target update channel get-current",
"options": [],
"short": "Return the currently configured update channel"
}
N/A
N/A
N/A
{
"command": "ffx target update channel get-next",
"options": [],
"short": "Return the next or target update channel"
}
N/A
N/A
N/A
{
"command": "ffx target update channel list",
"options": [],
"short": "List the known update channels"
}
N/A
N/A
N/A
{
"command": "ffx target update channel set",
"options": [],
"short": "Sets the update channel"
}
N/A
N/A
N/A
{
"command": "ffx target update check-now",
"options": [
{
"description": "the update check was initiated by a service, in the background.",
"option": "service-initiated",
"shorthand": "",
"value_type": "bool"
},
{
"description": "monitor for state update.",
"option": "monitor",
N/A
```posix-terminal
N/A
{
"command": "ffx target update check-now",
"options": [
{
"description": "the update check was initiated by a service, in the background.",
"option": "service-initiated",
"shorthand": "",
"value_type": "bool"
},
{
"description": "monitor for state update.",
"option": "monitor",
N/A
```posix-terminal
N/A
{
"command": "ffx target update check-now",
"options": [
{
"description": "the update check was initiated by a service, in the background.",
"option": "service-initiated",
"shorthand": "",
"value_type": "bool"
},
{
"description": "monitor for state update.",
"option": "monitor",
N/A
N/A
N/A
{
"command": "ffx target update check-now",
"options": [
{
"description": "the update check was initiated by a service, in the background.",
"option": "service-initiated",
"shorthand": "",
"value_type": "bool"
},
{
"description": "monitor for state update.",
"option": "monitor",
N/A
N/A
N/A
{
"command": "ffx target update check-now",
"options": [
{
"description": "the update check was initiated by a service, in the background.",
"option": "service-initiated",
"shorthand": "",
"value_type": "bool"
},
{
"description": "monitor for state update.",
"option": "monitor",
N/A
N/A
N/A
{
"command": "ffx target update force-install",
"options": [
{
"description": "automatically trigger a reboot into the new system",
"option": "reboot",
"shorthand": "",
"value_type": "string"
},
{
"description": "use the product bundle to use as the source of the update.",
"option": "product-bundle",
N/A
```posix-terminal
N/A
{
"command": "ffx target update force-install",
"options": [
{
"description": "automatically trigger a reboot into the new system",
"option": "reboot",
"shorthand": "",
"value_type": "string"
},
{
"description": "use the product bundle to use as the source of the update.",
"option": "product-bundle",
N/A
N/A
N/A
{
"command": "ffx target update force-install",
"options": [
{
"description": "automatically trigger a reboot into the new system",
"option": "reboot",
"shorthand": "",
"value_type": "string"
},
{
"description": "use the product bundle to use as the source of the update.",
"option": "product-bundle",
N/A
N/A
N/A
{
"command": "ffx target update force-install",
"options": [
{
"description": "automatically trigger a reboot into the new system",
"option": "reboot",
"shorthand": "",
"value_type": "string"
},
{
"description": "use the product bundle to use as the source of the update.",
"option": "product-bundle",
N/A
N/A
N/A
{
"command": "ffx target update force-install",
"options": [
{
"description": "automatically trigger a reboot into the new system",
"option": "reboot",
"shorthand": "",
"value_type": "string"
},
{
"description": "use the product bundle to use as the source of the update.",
"option": "product-bundle",
N/A
N/A
N/A
{
"command": "ffx target update force-install",
"options": [
{
"description": "automatically trigger a reboot into the new system",
"option": "reboot",
"shorthand": "",
"value_type": "string"
},
{
"description": "use the product bundle to use as the source of the update.",
"option": "product-bundle",
N/A
N/A
N/A
{
"command": "ffx target update wait-for-commit",
"options": [],
"short": "Wait for the update to be committed."
}
N/A
N/A
N/A
{
"command": "ffx target wait",
"options": [
{
"description": "the timeout in seconds [default = 120]. A value of 0 implies no timeout.",
"option": "timeout",
"shorthand": "t",
"value_type": "string"
},
{
"description": "wait for target to go down",
"option": "down",
self.run(
cmd=_FFX_CMDS["TARGET_WAIT"],
include_target_name=include_target_name,
disable_controlmaster=True,
)
_LOGGER.info("%s is connected to host", self._log_name)
return
def wait_for_rcs_disconnection(self) -> None:
"""Wait until FFX is able to disconnect RCS connection to the target.
Raises:
DeviceNotConnectedError: If FFX fails to reach target.
FfxCommandError: In case of other FFX command failure.
"""
_LOGGER.info(
"Waiting for %s to disconnect from host...", self._log_name
)
self.run(cmd=_FFX_CMDS["TARGET_WAIT_DOWN"], disable_controlmaster=True)
_LOGGER.info("%s is not connected to host", self._log_name)
return
def _get_target_status(self) -> MonitorTargetInfo:
"""Gets the status information of the target node from 'ffx monitor status'.
This method is valid only when 'ffx monitor start` session was running
for this target. It parses the output of `ffx --machine json monitor status`
to find the dictionary corresponding to the current target node.
self.run(cmd=_FFX_CMDS["TARGET_WAIT_DOWN"], disable_controlmaster=True)
_LOGGER.info("%s is not connected to host", self._log_name)
return
def _get_target_status(self) -> MonitorTargetInfo:
"""Gets the status information of the target node from 'ffx monitor status'.
This method is valid only when 'ffx monitor start` session was running
for this target. It parses the output of `ffx --machine json monitor status`
to find the dictionary corresponding to the current target node.
This method will only provide status information when the Ffx object
node name is provided.
Args:
None
Returns:
A MonitorTargetInfo containing the status information of the target
node, an empty MonitorTargetInfo if the target is not found in the
monitor output.
Raises:
ffx_errors.FfxMonitorNotSupportedError: If this method is called when monitor is not in use.
"""
if not self._use_monitor:
raise ffx_errors.FfxMonitorNotSupportedError(
"_get_target_status can only be called when ffx monitor is in"
" use."
)
N/A
{
"command": "ffx target wait",
"options": [
{
"description": "the timeout in seconds [default = 120]. A value of 0 implies no timeout.",
"option": "timeout",
"shorthand": "t",
"value_type": "string"
},
{
"description": "wait for target to go down",
"option": "down",
self.run(cmd=_FFX_CMDS["TARGET_WAIT_DOWN"], disable_controlmaster=True)
_LOGGER.info("%s is not connected to host", self._log_name)
return
def _get_target_status(self) -> MonitorTargetInfo:
"""Gets the status information of the target node from 'ffx monitor status'.
This method is valid only when 'ffx monitor start` session was running
for this target. It parses the output of `ffx --machine json monitor status`
to find the dictionary corresponding to the current target node.
This method will only provide status information when the Ffx object
node name is provided.
Args:
None
Returns:
A MonitorTargetInfo containing the status information of the target
node, an empty MonitorTargetInfo if the target is not found in the
monitor output.
Raises:
ffx_errors.FfxMonitorNotSupportedError: If this method is called when monitor is not in use.
"""
if not self._use_monitor:
raise ffx_errors.FfxMonitorNotSupportedError(
"_get_target_status can only be called when ffx monitor is in"
" use."
)
N/A
N/A
{
"command": "ffx target wait",
"options": [
{
"description": "the timeout in seconds [default = 120]. A value of 0 implies no timeout.",
"option": "timeout",
"shorthand": "t",
"value_type": "string"
},
{
"description": "wait for target to go down",
"option": "down",
self.run(
cmd=_FFX_CMDS["TARGET_WAIT"],
include_target_name=include_target_name,
disable_controlmaster=True,
)
_LOGGER.info("%s is connected to host", self._log_name)
return
def wait_for_rcs_disconnection(self) -> None:
"""Wait until FFX is able to disconnect RCS connection to the target.
Raises:
DeviceNotConnectedError: If FFX fails to reach target.
FfxCommandError: In case of other FFX command failure.
"""
_LOGGER.info(
"Waiting for %s to disconnect from host...", self._log_name
)
self.run(cmd=_FFX_CMDS["TARGET_WAIT_DOWN"], disable_controlmaster=True)
_LOGGER.info("%s is not connected to host", self._log_name)
return
def _get_target_status(self) -> MonitorTargetInfo:
"""Gets the status information of the target node from 'ffx monitor status'.
This method is valid only when 'ffx monitor start` session was running
for this target. It parses the output of `ffx --machine json monitor status`
to find the dictionary corresponding to the current target node.
self.run(cmd=_FFX_CMDS["TARGET_WAIT_DOWN"], disable_controlmaster=True)
_LOGGER.info("%s is not connected to host", self._log_name)
return
def _get_target_status(self) -> MonitorTargetInfo:
"""Gets the status information of the target node from 'ffx monitor status'.
This method is valid only when 'ffx monitor start` session was running
for this target. It parses the output of `ffx --machine json monitor status`
to find the dictionary corresponding to the current target node.
This method will only provide status information when the Ffx object
node name is provided.
Args:
None
Returns:
A MonitorTargetInfo containing the status information of the target
node, an empty MonitorTargetInfo if the target is not found in the
monitor output.
Raises:
ffx_errors.FfxMonitorNotSupportedError: If this method is called when monitor is not in use.
"""
if not self._use_monitor:
raise ffx_errors.FfxMonitorNotSupportedError(
"_get_target_status can only be called when ffx monitor is in"
" use."
)
N/A
N/A
{
"command": "ffx target wipe",
"options": [
{
"description": "reset without prompting for confirmation",
"option": "force",
"shorthand": "",
"value_type": "bool"
}
],
"short": "Performs a factory data reset"
}
N/A
N/A
N/A
{
"command": "ffx target wipe",
"options": [
{
"description": "reset without prompting for confirmation",
"option": "force",
"shorthand": "",
"value_type": "bool"
}
],
"short": "Performs a factory data reset"
}
N/A
N/A
N/A
{
"command": "ffx test",
"options": [],
"short": "Run test suite"
}
#[fuchsia::test]
async fn add() {
Test::test("2 + 2")
.check(|value| {
assert_eq!(4, value.try_usize().unwrap());
})
.await;
}
#[fuchsia::test]
async fn assignment() {
Test::test("let a = 0; $a = 4; $a")
.check(|value| {
assert_eq!(4, value.try_usize().unwrap());
})
.await;
}
#[fuchsia::test]
async fn bare_string() {
Test::test("def f (x) $x; f abc123")
.check(|value| {
let Value::String(value) = value else {
panic!();
};
assert_eq!("abc123", &value);
})
.await;
}
```posix-terminal
```posix-terminal
N/A
{
"command": "ffx test early-boot-profile",
"options": [
{
"description": "output early boot profile to the specified directory. The produced output is in the format described in https://fuchsia.dev/fuchsia-src/reference/platform-spec/testing/test-output-format",
"option": "output-directory",
"shorthand": "",
"value_type": "string"
}
],
"short": "Manage early boot profiles"
}
N/A
N/A
N/A
{
"command": "ffx test early-boot-profile",
"options": [
{
"description": "output early boot profile to the specified directory. The produced output is in the format described in https://fuchsia.dev/fuchsia-src/reference/platform-spec/testing/test-output-format",
"option": "output-directory",
"shorthand": "",
"value_type": "string"
}
],
"short": "Manage early boot profiles"
}
N/A
N/A
N/A
{
"command": "ffx test list-cases",
"options": [
{
"description": "the realm to enumerate the test in. This field is optional and takes the form: /path/to/realm:test_collection.",
"option": "realm",
"shorthand": "",
"value_type": "string"
}
],
"short": "List test suite cases"
}
N/A
N/A
N/A
{
"command": "ffx test list-cases",
"options": [
{
"description": "the realm to enumerate the test in. This field is optional and takes the form: /path/to/realm:test_collection.",
"option": "realm",
"shorthand": "",
"value_type": "string"
}
],
"short": "List test suite cases"
}
N/A
N/A
N/A
{
"command": "ffx test run",
"options": [
{
"description": "read test parameters from the specified file instead of from the command line. This is intended to be used by test_pilot.",
"option": "pilot",
"shorthand": "",
"value_type": "string"
},
{
"description": "read test url and options from the specified file instead of from the command line. May not be used in conjunction with `test_args`, `--count`, `--test-filter`, `--run-disabled`, `--parallel`, `--max-severity-logs` This option is currently unstable and the format of the file is subject to change. Using this option requires setting the 'test.experimental_json_input' configuration to true. For current details, see test-list.json format at https://fuchsia.googlesource.com/fuchsia/+/refs/heads/main/src/lib/testing/test_list/",
"option": "test-file",
return self.run(cmd, capture_output=capture_output)
def run_ssh_cmd(
self,
cmd: str,
capture_output: bool = True,
) -> str:
"""Executes and returns the output of `ffx -t target ssh <cmd>`.
Args:
cmd: SSH command to run.
capture_output: When True, the stdout/err from the command will be
captured and returned. When False, the output of the command
will be streamed to stdout/err accordingly and it won't be
returned. Defaults to True.
Returns:
Output of `ffx -t target ssh <cmd>` when capture_output is set to
True, otherwise an empty string.
Raises:
DeviceNotConnectedError: If FFX fails to reach target.
FfxCommandError: In case of other FFX command failure.
"""
ffx_cmd: list[str] = _FFX_CMDS["TARGET_SSH"][:]
ffx_cmd.append(cmd)
return self.run(
ffx_cmd, capture_output=capture_output, machine=MachineFormat.RAW
)
"core/test_manager" not in self.dut.ffx.run(["component", "list"]),
"Test manager component is not present",
)
output: str = self.dut.ffx.run_test_component(
"fuchsia-pkg://fuchsia.com/hello-world-rust-tests#meta/hello-world-rust-tests.cm",
)
asserts.assert_in("PASSED", output)
async def test_ffx_run_ssh_cmd(self) -> None:
"""Test case for FFX.run_ssh_cmd()."""
cmd: str = "ls"
self.dut.ffx.run_ssh_cmd(cmd)
async def test_get_ffx_target_status(self) -> None:
"""Test case for FFX.get_ffx_target_status()."""
output: str = self.dut.ffx.get_ffx_target_status()
asserts.assert_is_instance(output, str)
if __name__ == "__main__":
test_runner.main()
```posix-terminal
```posix-terminal
N/A
{
"command": "ffx test run",
"options": [
{
"description": "read test parameters from the specified file instead of from the command line. This is intended to be used by test_pilot.",
"option": "pilot",
"shorthand": "",
"value_type": "string"
},
{
"description": "read test url and options from the specified file instead of from the command line. May not be used in conjunction with `test_args`, `--count`, `--test-filter`, `--run-disabled`, `--parallel`, `--max-severity-logs` This option is currently unstable and the format of the file is subject to change. Using this option requires setting the 'test.experimental_json_input' configuration to true. For current details, see test-list.json format at https://fuchsia.googlesource.com/fuchsia/+/refs/heads/main/src/lib/testing/test_list/",
"option": "test-file",
N/A
N/A
N/A
{
"command": "ffx test run",
"options": [
{
"description": "read test parameters from the specified file instead of from the command line. This is intended to be used by test_pilot.",
"option": "pilot",
"shorthand": "",
"value_type": "string"
},
{
"description": "read test url and options from the specified file instead of from the command line. May not be used in conjunction with `test_args`, `--count`, `--test-filter`, `--run-disabled`, `--parallel`, `--max-severity-logs` This option is currently unstable and the format of the file is subject to change. Using this option requires setting the 'test.experimental_json_input' configuration to true. For current details, see test-list.json format at https://fuchsia.googlesource.com/fuchsia/+/refs/heads/main/src/lib/testing/test_list/",
"option": "test-file",
N/A
N/A
N/A
{
"command": "ffx test run",
"options": [
{
"description": "read test parameters from the specified file instead of from the command line. This is intended to be used by test_pilot.",
"option": "pilot",
"shorthand": "",
"value_type": "string"
},
{
"description": "read test url and options from the specified file instead of from the command line. May not be used in conjunction with `test_args`, `--count`, `--test-filter`, `--run-disabled`, `--parallel`, `--max-severity-logs` This option is currently unstable and the format of the file is subject to change. Using this option requires setting the 'test.experimental_json_input' configuration to true. For current details, see test-list.json format at https://fuchsia.googlesource.com/fuchsia/+/refs/heads/main/src/lib/testing/test_list/",
"option": "test-file",
N/A
N/A
N/A
{
"command": "ffx test run",
"options": [
{
"description": "read test parameters from the specified file instead of from the command line. This is intended to be used by test_pilot.",
"option": "pilot",
"shorthand": "",
"value_type": "string"
},
{
"description": "read test url and options from the specified file instead of from the command line. May not be used in conjunction with `test_args`, `--count`, `--test-filter`, `--run-disabled`, `--parallel`, `--max-severity-logs` This option is currently unstable and the format of the file is subject to change. Using this option requires setting the 'test.experimental_json_input' configuration to true. For current details, see test-list.json format at https://fuchsia.googlesource.com/fuchsia/+/refs/heads/main/src/lib/testing/test_list/",
"option": "test-file",
N/A
N/A
N/A
{
"command": "ffx test run",
"options": [
{
"description": "read test parameters from the specified file instead of from the command line. This is intended to be used by test_pilot.",
"option": "pilot",
"shorthand": "",
"value_type": "string"
},
{
"description": "read test url and options from the specified file instead of from the command line. May not be used in conjunction with `test_args`, `--count`, `--test-filter`, `--run-disabled`, `--parallel`, `--max-severity-logs` This option is currently unstable and the format of the file is subject to change. Using this option requires setting the 'test.experimental_json_input' configuration to true. For current details, see test-list.json format at https://fuchsia.googlesource.com/fuchsia/+/refs/heads/main/src/lib/testing/test_list/",
"option": "test-file",
N/A
N/A
N/A
{
"command": "ffx test run",
"options": [
{
"description": "read test parameters from the specified file instead of from the command line. This is intended to be used by test_pilot.",
"option": "pilot",
"shorthand": "",
"value_type": "string"
},
{
"description": "read test url and options from the specified file instead of from the command line. May not be used in conjunction with `test_args`, `--count`, `--test-filter`, `--run-disabled`, `--parallel`, `--max-severity-logs` This option is currently unstable and the format of the file is subject to change. Using this option requires setting the 'test.experimental_json_input' configuration to true. For current details, see test-list.json format at https://fuchsia.googlesource.com/fuchsia/+/refs/heads/main/src/lib/testing/test_list/",
"option": "test-file",
N/A
N/A
N/A
{
"command": "ffx test run",
"options": [
{
"description": "read test parameters from the specified file instead of from the command line. This is intended to be used by test_pilot.",
"option": "pilot",
"shorthand": "",
"value_type": "string"
},
{
"description": "read test url and options from the specified file instead of from the command line. May not be used in conjunction with `test_args`, `--count`, `--test-filter`, `--run-disabled`, `--parallel`, `--max-severity-logs` This option is currently unstable and the format of the file is subject to change. Using this option requires setting the 'test.experimental_json_input' configuration to true. For current details, see test-list.json format at https://fuchsia.googlesource.com/fuchsia/+/refs/heads/main/src/lib/testing/test_list/",
"option": "test-file",
N/A
N/A
N/A
{
"command": "ffx test run",
"options": [
{
"description": "read test parameters from the specified file instead of from the command line. This is intended to be used by test_pilot.",
"option": "pilot",
"shorthand": "",
"value_type": "string"
},
{
"description": "read test url and options from the specified file instead of from the command line. May not be used in conjunction with `test_args`, `--count`, `--test-filter`, `--run-disabled`, `--parallel`, `--max-severity-logs` This option is currently unstable and the format of the file is subject to change. Using this option requires setting the 'test.experimental_json_input' configuration to true. For current details, see test-list.json format at https://fuchsia.googlesource.com/fuchsia/+/refs/heads/main/src/lib/testing/test_list/",
"option": "test-file",
N/A
N/A
N/A
{
"command": "ffx test run",
"options": [
{
"description": "read test parameters from the specified file instead of from the command line. This is intended to be used by test_pilot.",
"option": "pilot",
"shorthand": "",
"value_type": "string"
},
{
"description": "read test url and options from the specified file instead of from the command line. May not be used in conjunction with `test_args`, `--count`, `--test-filter`, `--run-disabled`, `--parallel`, `--max-severity-logs` This option is currently unstable and the format of the file is subject to change. Using this option requires setting the 'test.experimental_json_input' configuration to true. For current details, see test-list.json format at https://fuchsia.googlesource.com/fuchsia/+/refs/heads/main/src/lib/testing/test_list/",
"option": "test-file",
N/A
N/A
N/A
{
"command": "ffx test run",
"options": [
{
"description": "read test parameters from the specified file instead of from the command line. This is intended to be used by test_pilot.",
"option": "pilot",
"shorthand": "",
"value_type": "string"
},
{
"description": "read test url and options from the specified file instead of from the command line. May not be used in conjunction with `test_args`, `--count`, `--test-filter`, `--run-disabled`, `--parallel`, `--max-severity-logs` This option is currently unstable and the format of the file is subject to change. Using this option requires setting the 'test.experimental_json_input' configuration to true. For current details, see test-list.json format at https://fuchsia.googlesource.com/fuchsia/+/refs/heads/main/src/lib/testing/test_list/",
"option": "test-file",
N/A
N/A
N/A
{
"command": "ffx test run",
"options": [
{
"description": "read test parameters from the specified file instead of from the command line. This is intended to be used by test_pilot.",
"option": "pilot",
"shorthand": "",
"value_type": "string"
},
{
"description": "read test url and options from the specified file instead of from the command line. May not be used in conjunction with `test_args`, `--count`, `--test-filter`, `--run-disabled`, `--parallel`, `--max-severity-logs` This option is currently unstable and the format of the file is subject to change. Using this option requires setting the 'test.experimental_json_input' configuration to true. For current details, see test-list.json format at https://fuchsia.googlesource.com/fuchsia/+/refs/heads/main/src/lib/testing/test_list/",
"option": "test-file",
N/A
N/A
N/A
{
"command": "ffx test run",
"options": [
{
"description": "read test parameters from the specified file instead of from the command line. This is intended to be used by test_pilot.",
"option": "pilot",
"shorthand": "",
"value_type": "string"
},
{
"description": "read test url and options from the specified file instead of from the command line. May not be used in conjunction with `test_args`, `--count`, `--test-filter`, `--run-disabled`, `--parallel`, `--max-severity-logs` This option is currently unstable and the format of the file is subject to change. Using this option requires setting the 'test.experimental_json_input' configuration to true. For current details, see test-list.json format at https://fuchsia.googlesource.com/fuchsia/+/refs/heads/main/src/lib/testing/test_list/",
"option": "test-file",
N/A
N/A
N/A
{
"command": "ffx test run",
"options": [
{
"description": "read test parameters from the specified file instead of from the command line. This is intended to be used by test_pilot.",
"option": "pilot",
"shorthand": "",
"value_type": "string"
},
{
"description": "read test url and options from the specified file instead of from the command line. May not be used in conjunction with `test_args`, `--count`, `--test-filter`, `--run-disabled`, `--parallel`, `--max-severity-logs` This option is currently unstable and the format of the file is subject to change. Using this option requires setting the 'test.experimental_json_input' configuration to true. For current details, see test-list.json format at https://fuchsia.googlesource.com/fuchsia/+/refs/heads/main/src/lib/testing/test_list/",
"option": "test-file",
N/A
N/A
N/A
{
"command": "ffx test run",
"options": [
{
"description": "read test parameters from the specified file instead of from the command line. This is intended to be used by test_pilot.",
"option": "pilot",
"shorthand": "",
"value_type": "string"
},
{
"description": "read test url and options from the specified file instead of from the command line. May not be used in conjunction with `test_args`, `--count`, `--test-filter`, `--run-disabled`, `--parallel`, `--max-severity-logs` This option is currently unstable and the format of the file is subject to change. Using this option requires setting the 'test.experimental_json_input' configuration to true. For current details, see test-list.json format at https://fuchsia.googlesource.com/fuchsia/+/refs/heads/main/src/lib/testing/test_list/",
"option": "test-file",
N/A
N/A
N/A
{
"command": "ffx test run",
"options": [
{
"description": "read test parameters from the specified file instead of from the command line. This is intended to be used by test_pilot.",
"option": "pilot",
"shorthand": "",
"value_type": "string"
},
{
"description": "read test url and options from the specified file instead of from the command line. May not be used in conjunction with `test_args`, `--count`, `--test-filter`, `--run-disabled`, `--parallel`, `--max-severity-logs` This option is currently unstable and the format of the file is subject to change. Using this option requires setting the 'test.experimental_json_input' configuration to true. For current details, see test-list.json format at https://fuchsia.googlesource.com/fuchsia/+/refs/heads/main/src/lib/testing/test_list/",
"option": "test-file",
N/A
```posix-terminal
N/A
{
"command": "ffx test run",
"options": [
{
"description": "read test parameters from the specified file instead of from the command line. This is intended to be used by test_pilot.",
"option": "pilot",
"shorthand": "",
"value_type": "string"
},
{
"description": "read test url and options from the specified file instead of from the command line. May not be used in conjunction with `test_args`, `--count`, `--test-filter`, `--run-disabled`, `--parallel`, `--max-severity-logs` This option is currently unstable and the format of the file is subject to change. Using this option requires setting the 'test.experimental_json_input' configuration to true. For current details, see test-list.json format at https://fuchsia.googlesource.com/fuchsia/+/refs/heads/main/src/lib/testing/test_list/",
"option": "test-file",
N/A
N/A
N/A
{
"command": "ffx test run",
"options": [
{
"description": "read test parameters from the specified file instead of from the command line. This is intended to be used by test_pilot.",
"option": "pilot",
"shorthand": "",
"value_type": "string"
},
{
"description": "read test url and options from the specified file instead of from the command line. May not be used in conjunction with `test_args`, `--count`, `--test-filter`, `--run-disabled`, `--parallel`, `--max-severity-logs` This option is currently unstable and the format of the file is subject to change. Using this option requires setting the 'test.experimental_json_input' configuration to true. For current details, see test-list.json format at https://fuchsia.googlesource.com/fuchsia/+/refs/heads/main/src/lib/testing/test_list/",
"option": "test-file",
N/A
N/A
N/A
{
"command": "ffx test run",
"options": [
{
"description": "read test parameters from the specified file instead of from the command line. This is intended to be used by test_pilot.",
"option": "pilot",
"shorthand": "",
"value_type": "string"
},
{
"description": "read test url and options from the specified file instead of from the command line. May not be used in conjunction with `test_args`, `--count`, `--test-filter`, `--run-disabled`, `--parallel`, `--max-severity-logs` This option is currently unstable and the format of the file is subject to change. Using this option requires setting the 'test.experimental_json_input' configuration to true. For current details, see test-list.json format at https://fuchsia.googlesource.com/fuchsia/+/refs/heads/main/src/lib/testing/test_list/",
"option": "test-file",
N/A
N/A
N/A
{
"command": "ffx test run",
"options": [
{
"description": "read test parameters from the specified file instead of from the command line. This is intended to be used by test_pilot.",
"option": "pilot",
"shorthand": "",
"value_type": "string"
},
{
"description": "read test url and options from the specified file instead of from the command line. May not be used in conjunction with `test_args`, `--count`, `--test-filter`, `--run-disabled`, `--parallel`, `--max-severity-logs` This option is currently unstable and the format of the file is subject to change. Using this option requires setting the 'test.experimental_json_input' configuration to true. For current details, see test-list.json format at https://fuchsia.googlesource.com/fuchsia/+/refs/heads/main/src/lib/testing/test_list/",
"option": "test-file",
N/A
```posix-terminal
N/A
{
"command": "ffx test run",
"options": [
{
"description": "read test parameters from the specified file instead of from the command line. This is intended to be used by test_pilot.",
"option": "pilot",
"shorthand": "",
"value_type": "string"
},
{
"description": "read test url and options from the specified file instead of from the command line. May not be used in conjunction with `test_args`, `--count`, `--test-filter`, `--run-disabled`, `--parallel`, `--max-severity-logs` This option is currently unstable and the format of the file is subject to change. Using this option requires setting the 'test.experimental_json_input' configuration to true. For current details, see test-list.json format at https://fuchsia.googlesource.com/fuchsia/+/refs/heads/main/src/lib/testing/test_list/",
"option": "test-file",
N/A
```posix-terminal
N/A
{
"command": "ffx test run",
"options": [
{
"description": "read test parameters from the specified file instead of from the command line. This is intended to be used by test_pilot.",
"option": "pilot",
"shorthand": "",
"value_type": "string"
},
{
"description": "read test url and options from the specified file instead of from the command line. May not be used in conjunction with `test_args`, `--count`, `--test-filter`, `--run-disabled`, `--parallel`, `--max-severity-logs` This option is currently unstable and the format of the file is subject to change. Using this option requires setting the 'test.experimental_json_input' configuration to true. For current details, see test-list.json format at https://fuchsia.googlesource.com/fuchsia/+/refs/heads/main/src/lib/testing/test_list/",
"option": "test-file",
N/A
N/A
N/A
{
"command": "ffx trace",
"options": [],
"short": "Collect, aggregate, and visualize traces"
}
#[fuchsia::test]
fn test_get_category_group() {
let env = ffx_config::test_init().unwrap();
let birds = vec!["chickens", "bald_eagle", "blue-jay", "hawk*", "goose:gosling"];
env.context
.query("trace.category_groups.birds")
.level(Some(ffx_config::ConfigLevel::User))
.build()
.set(&env.context, json!(birds))
.unwrap();
assert_eq!(birds, get_category_group(&env.context, "birds").unwrap());
}
#[fuchsia::test]
fn test_get_category_group_names() {
let env = ffx_config::test_init().unwrap();
let birds = vec!["chickens", "ducks"];
let bees = vec!["honey", "bumble"];
env.context
.query("trace.category_groups.birds")
.level(Some(ffx_config::ConfigLevel::User))
.build()
.set(&env.context, json!(birds))
.unwrap();
env.context
.query("trace.category_groups.bees")
.level(Some(ffx_config::ConfigLevel::User))
.build()
.set(&env.context, json!(bees))
.unwrap();
env.context
.query("trace.category_groups.*invalid")
.level(Some(ffx_config::ConfigLevel::User))
.build()
.set(&env.context, json!(bees))
.unwrap();
assert!(get_category_group_names(&env.context).unwrap().contains(&"birds".to_owned()));
assert!(get_category_group_names(&env.context).unwrap().contains(&"bees".to_owned()));
assert!(get_category_group_names(&env.context).unwrap().contains(&"*invalid".to_owned()));
}
#[fuchsia::test]
fn test_get_category_group_not_found() {
let env = ffx_config::test_init().unwrap();
let err = get_category_group(&env.context, "not_found").unwrap_err();
assert!(
err.to_string().contains("Error: no category group found for not_found"),
"the actual value was \"{}\"",
err.to_string()
);
}
```posix-terminal
```posix-terminal
N/A
{
"command": "ffx trace list-categories",
"options": [],
"short": "List the target's known trace categories."
}
N/A
N/A
N/A
{
"command": "ffx trace list-category-groups",
"options": [],
"short": "List the builtin and custom category groups."
}
N/A
N/A
N/A
{
"command": "ffx trace list-providers",
"options": [],
"short": "List the target's trace providers."
}
N/A
N/A
N/A
{
"command": "ffx trace start",
"options": [
{
"description": "the buffering scheme to trace with. Defaults to \"oneshot\" oneshot: Writes to the tracing buffer until it is full, then ignores all additional trace events. circular: Writes to the tracing buffer until its is full, then new events will replace old events. streaming: Forwards tracing events to the trace manager as they arrive. Provides additional buffer space with the trade off of some overhead due to occasional ipcs to send the events to the trace manager during the trace.",
"option": "buffering-mode",
"shorthand": "",
"value_type": "string"
},
{
"description": "size of per-provider trace buffer in MB. Defaults to 4.",
"option": "buffer-size",
self._ffx.run(cmd)
except FfxCommandError as err:
raise TracingError(
f"Failed to start FFX trace on {self._name}: {err}"
```posix-terminal
```posix-terminal
N/A
{
"command": "ffx trace start",
"options": [
{
"description": "the buffering scheme to trace with. Defaults to \"oneshot\" oneshot: Writes to the tracing buffer until it is full, then ignores all additional trace events. circular: Writes to the tracing buffer until its is full, then new events will replace old events. streaming: Forwards tracing events to the trace manager as they arrive. Provides additional buffer space with the trade off of some overhead due to occasional ipcs to send the events to the trace manager during the trace.",
"option": "buffering-mode",
"shorthand": "",
"value_type": "string"
},
{
"description": "size of per-provider trace buffer in MB. Defaults to 4.",
"option": "buffer-size",
self._ffx.run(cmd)
except FfxCommandError as err:
raise TracingError(
f"Failed to start FFX trace on {self._name}: {err}"
N/A
N/A
{
"command": "ffx trace start",
"options": [
{
"description": "the buffering scheme to trace with. Defaults to \"oneshot\" oneshot: Writes to the tracing buffer until it is full, then ignores all additional trace events. circular: Writes to the tracing buffer until its is full, then new events will replace old events. streaming: Forwards tracing events to the trace manager as they arrive. Provides additional buffer space with the trade off of some overhead due to occasional ipcs to send the events to the trace manager during the trace.",
"option": "buffering-mode",
"shorthand": "",
"value_type": "string"
},
{
"description": "size of per-provider trace buffer in MB. Defaults to 4.",
"option": "buffer-size",
self._ffx.run(cmd)
except FfxCommandError as err:
raise TracingError(
f"Failed to start FFX trace on {self._name}: {err}"
```posix-terminal
N/A
{
"command": "ffx trace start",
"options": [
{
"description": "the buffering scheme to trace with. Defaults to \"oneshot\" oneshot: Writes to the tracing buffer until it is full, then ignores all additional trace events. circular: Writes to the tracing buffer until its is full, then new events will replace old events. streaming: Forwards tracing events to the trace manager as they arrive. Provides additional buffer space with the trade off of some overhead due to occasional ipcs to send the events to the trace manager during the trace.",
"option": "buffering-mode",
"shorthand": "",
"value_type": "string"
},
{
"description": "size of per-provider trace buffer in MB. Defaults to 4.",
"option": "buffer-size",
self._ffx.run(cmd)
except FfxCommandError as err:
raise TracingError(
f"Failed to start FFX trace on {self._name}: {err}"
```posix-terminal
N/A
{
"command": "ffx trace start",
"options": [
{
"description": "the buffering scheme to trace with. Defaults to \"oneshot\" oneshot: Writes to the tracing buffer until it is full, then ignores all additional trace events. circular: Writes to the tracing buffer until its is full, then new events will replace old events. streaming: Forwards tracing events to the trace manager as they arrive. Provides additional buffer space with the trade off of some overhead due to occasional ipcs to send the events to the trace manager during the trace.",
"option": "buffering-mode",
"shorthand": "",
"value_type": "string"
},
{
"description": "size of per-provider trace buffer in MB. Defaults to 4.",
"option": "buffer-size",
self._ffx.run(cmd)
except FfxCommandError as err:
raise TracingError(
f"Failed to start FFX trace on {self._name}: {err}"
```posix-terminal
N/A
{
"command": "ffx trace start",
"options": [
{
"description": "the buffering scheme to trace with. Defaults to \"oneshot\" oneshot: Writes to the tracing buffer until it is full, then ignores all additional trace events. circular: Writes to the tracing buffer until its is full, then new events will replace old events. streaming: Forwards tracing events to the trace manager as they arrive. Provides additional buffer space with the trade off of some overhead due to occasional ipcs to send the events to the trace manager during the trace.",
"option": "buffering-mode",
"shorthand": "",
"value_type": "string"
},
{
"description": "size of per-provider trace buffer in MB. Defaults to 4.",
"option": "buffer-size",
N/A
N/A
N/A
{
"command": "ffx trace start",
"options": [
{
"description": "the buffering scheme to trace with. Defaults to \"oneshot\" oneshot: Writes to the tracing buffer until it is full, then ignores all additional trace events. circular: Writes to the tracing buffer until its is full, then new events will replace old events. streaming: Forwards tracing events to the trace manager as they arrive. Provides additional buffer space with the trade off of some overhead due to occasional ipcs to send the events to the trace manager during the trace.",
"option": "buffering-mode",
"shorthand": "",
"value_type": "string"
},
{
"description": "size of per-provider trace buffer in MB. Defaults to 4.",
"option": "buffer-size",
N/A
N/A
N/A
{
"command": "ffx trace start",
"options": [
{
"description": "the buffering scheme to trace with. Defaults to \"oneshot\" oneshot: Writes to the tracing buffer until it is full, then ignores all additional trace events. circular: Writes to the tracing buffer until its is full, then new events will replace old events. streaming: Forwards tracing events to the trace manager as they arrive. Provides additional buffer space with the trade off of some overhead due to occasional ipcs to send the events to the trace manager during the trace.",
"option": "buffering-mode",
"shorthand": "",
"value_type": "string"
},
{
"description": "size of per-provider trace buffer in MB. Defaults to 4.",
"option": "buffer-size",
N/A
N/A
N/A
{
"command": "ffx trace start",
"options": [
{
"description": "the buffering scheme to trace with. Defaults to \"oneshot\" oneshot: Writes to the tracing buffer until it is full, then ignores all additional trace events. circular: Writes to the tracing buffer until its is full, then new events will replace old events. streaming: Forwards tracing events to the trace manager as they arrive. Provides additional buffer space with the trade off of some overhead due to occasional ipcs to send the events to the trace manager during the trace.",
"option": "buffering-mode",
"shorthand": "",
"value_type": "string"
},
{
"description": "size of per-provider trace buffer in MB. Defaults to 4.",
"option": "buffer-size",
self._ffx.run(cmd)
except FfxCommandError as err:
raise TracingError(
f"Failed to start FFX trace on {self._name}: {err}"
N/A
N/A
{
"command": "ffx trace start",
"options": [
{
"description": "the buffering scheme to trace with. Defaults to \"oneshot\" oneshot: Writes to the tracing buffer until it is full, then ignores all additional trace events. circular: Writes to the tracing buffer until its is full, then new events will replace old events. streaming: Forwards tracing events to the trace manager as they arrive. Provides additional buffer space with the trade off of some overhead due to occasional ipcs to send the events to the trace manager during the trace.",
"option": "buffering-mode",
"shorthand": "",
"value_type": "string"
},
{
"description": "size of per-provider trace buffer in MB. Defaults to 4.",
"option": "buffer-size",
N/A
N/A
N/A
{
"command": "ffx trace start",
"options": [
{
"description": "the buffering scheme to trace with. Defaults to \"oneshot\" oneshot: Writes to the tracing buffer until it is full, then ignores all additional trace events. circular: Writes to the tracing buffer until its is full, then new events will replace old events. streaming: Forwards tracing events to the trace manager as they arrive. Provides additional buffer space with the trade off of some overhead due to occasional ipcs to send the events to the trace manager during the trace.",
"option": "buffering-mode",
"shorthand": "",
"value_type": "string"
},
{
"description": "size of per-provider trace buffer in MB. Defaults to 4.",
"option": "buffer-size",
N/A
N/A
N/A
{
"command": "ffx trace start",
"options": [
{
"description": "the buffering scheme to trace with. Defaults to \"oneshot\" oneshot: Writes to the tracing buffer until it is full, then ignores all additional trace events. circular: Writes to the tracing buffer until its is full, then new events will replace old events. streaming: Forwards tracing events to the trace manager as they arrive. Provides additional buffer space with the trade off of some overhead due to occasional ipcs to send the events to the trace manager during the trace.",
"option": "buffering-mode",
"shorthand": "",
"value_type": "string"
},
{
"description": "size of per-provider trace buffer in MB. Defaults to 4.",
"option": "buffer-size",
N/A
N/A
N/A
{
"command": "ffx trace start",
"options": [
{
"description": "the buffering scheme to trace with. Defaults to \"oneshot\" oneshot: Writes to the tracing buffer until it is full, then ignores all additional trace events. circular: Writes to the tracing buffer until its is full, then new events will replace old events. streaming: Forwards tracing events to the trace manager as they arrive. Provides additional buffer space with the trade off of some overhead due to occasional ipcs to send the events to the trace manager during the trace.",
"option": "buffering-mode",
"shorthand": "",
"value_type": "string"
},
{
"description": "size of per-provider trace buffer in MB. Defaults to 4.",
"option": "buffer-size",
N/A
```posix-terminal
N/A
{
"command": "ffx trace start",
"options": [
{
"description": "the buffering scheme to trace with. Defaults to \"oneshot\" oneshot: Writes to the tracing buffer until it is full, then ignores all additional trace events. circular: Writes to the tracing buffer until its is full, then new events will replace old events. streaming: Forwards tracing events to the trace manager as they arrive. Provides additional buffer space with the trade off of some overhead due to occasional ipcs to send the events to the trace manager during the trace.",
"option": "buffering-mode",
"shorthand": "",
"value_type": "string"
},
{
"description": "size of per-provider trace buffer in MB. Defaults to 4.",
"option": "buffer-size",
N/A
N/A
N/A
{
"command": "ffx trace status",
"options": [],
"short": "Gets status of all running traces."
}
N/A
N/A
N/A
{
"command": "ffx trace stop",
"options": [
{
"description": "name of output trace file. Relative or absolute paths are both supported. If this is not supplied (the default), then the default target will be used as the method to stop the trace.",
"option": "output",
"shorthand": "",
"value_type": "string"
},
{
"description": "increase verbosity of command output. Defaults to false. Enabling this prints stats from trace providers including the number of records dropped, wrapped buffers count, % of durable buffer used and non durable bytes written.",
"option": "verbose",
self._ffx.run(["trace", "stop", "--output", temp_file_path])
except FfxCommandError as err:
raise TracingError(
f"Failed to stop FFX trace on {self._name}: {err}"
self._ffx.run(["trace", "stop", "--abort"])
except FfxCommandError as err:
raise TracingError(
f"Failed to abort FFX trace on {self._name}: {err}"
N/A
N/A
{
"command": "ffx trace stop",
"options": [
{
"description": "name of output trace file. Relative or absolute paths are both supported. If this is not supplied (the default), then the default target will be used as the method to stop the trace.",
"option": "output",
"shorthand": "",
"value_type": "string"
},
{
"description": "increase verbosity of command output. Defaults to false. Enabling this prints stats from trace providers including the number of records dropped, wrapped buffers count, % of durable buffer used and non durable bytes written.",
"option": "verbose",
self._ffx.run(["trace", "stop", "--abort"])
except FfxCommandError as err:
raise TracingError(
f"Failed to abort FFX trace on {self._name}: {err}"
N/A
N/A
{
"command": "ffx trace stop",
"options": [
{
"description": "name of output trace file. Relative or absolute paths are both supported. If this is not supplied (the default), then the default target will be used as the method to stop the trace.",
"option": "output",
"shorthand": "",
"value_type": "string"
},
{
"description": "increase verbosity of command output. Defaults to false. Enabling this prints stats from trace providers including the number of records dropped, wrapped buffers count, % of durable buffer used and non durable bytes written.",
"option": "verbose",
N/A
N/A
N/A
{
"command": "ffx trace stop",
"options": [
{
"description": "name of output trace file. Relative or absolute paths are both supported. If this is not supplied (the default), then the default target will be used as the method to stop the trace.",
"option": "output",
"shorthand": "",
"value_type": "string"
},
{
"description": "increase verbosity of command output. Defaults to false. Enabling this prints stats from trace providers including the number of records dropped, wrapped buffers count, % of durable buffer used and non durable bytes written.",
"option": "verbose",
N/A
N/A
N/A
{
"command": "ffx trace stop",
"options": [
{
"description": "name of output trace file. Relative or absolute paths are both supported. If this is not supplied (the default), then the default target will be used as the method to stop the trace.",
"option": "output",
"shorthand": "",
"value_type": "string"
},
{
"description": "increase verbosity of command output. Defaults to false. Enabling this prints stats from trace providers including the number of records dropped, wrapped buffers count, % of durable buffer used and non durable bytes written.",
"option": "verbose",
self._ffx.run(["trace", "stop", "--output", temp_file_path])
except FfxCommandError as err:
raise TracingError(
f"Failed to stop FFX trace on {self._name}: {err}"
N/A
N/A
{
"command": "ffx trace stop",
"options": [
{
"description": "name of output trace file. Relative or absolute paths are both supported. If this is not supplied (the default), then the default target will be used as the method to stop the trace.",
"option": "output",
"shorthand": "",
"value_type": "string"
},
{
"description": "increase verbosity of command output. Defaults to false. Enabling this prints stats from trace providers including the number of records dropped, wrapped buffers count, % of durable buffer used and non durable bytes written.",
"option": "verbose",
N/A
N/A
N/A
{
"command": "ffx trace stop",
"options": [
{
"description": "name of output trace file. Relative or absolute paths are both supported. If this is not supplied (the default), then the default target will be used as the method to stop the trace.",
"option": "output",
"shorthand": "",
"value_type": "string"
},
{
"description": "increase verbosity of command output. Defaults to false. Enabling this prints stats from trace providers including the number of records dropped, wrapped buffers count, % of durable buffer used and non durable bytes written.",
"option": "verbose",
N/A
N/A
N/A
{
"command": "ffx trace symbolize",
"options": [
{
"description": "FIDL ordinal to be symbolized.",
"option": "ordinal",
"shorthand": "",
"value_type": "string"
},
{
"description": "trace file to be symbolized.",
"option": "fxt",
N/A
N/A
N/A
{
"command": "ffx trace symbolize",
"options": [
{
"description": "FIDL ordinal to be symbolized.",
"option": "ordinal",
"shorthand": "",
"value_type": "string"
},
{
"description": "trace file to be symbolized.",
"option": "fxt",
N/A
N/A
N/A
{
"command": "ffx trace symbolize",
"options": [
{
"description": "FIDL ordinal to be symbolized.",
"option": "ordinal",
"shorthand": "",
"value_type": "string"
},
{
"description": "trace file to be symbolized.",
"option": "fxt",
N/A
N/A
N/A
{
"command": "ffx trace symbolize",
"options": [
{
"description": "FIDL ordinal to be symbolized.",
"option": "ordinal",
"shorthand": "",
"value_type": "string"
},
{
"description": "trace file to be symbolized.",
"option": "fxt",
N/A
N/A
N/A
{
"command": "ffx trace symbolize",
"options": [
{
"description": "FIDL ordinal to be symbolized.",
"option": "ordinal",
"shorthand": "",
"value_type": "string"
},
{
"description": "trace file to be symbolized.",
"option": "fxt",
N/A
N/A
N/A
{
"command": "ffx trace symbolize",
"options": [
{
"description": "FIDL ordinal to be symbolized.",
"option": "ordinal",
"shorthand": "",
"value_type": "string"
},
{
"description": "trace file to be symbolized.",
"option": "fxt",
N/A
N/A
N/A
{
"command": "ffx triage",
"options": [
{
"description": "path to config file or dir",
"option": "config",
"shorthand": "",
"value_type": "string"
},
{
"description": "path to snapshot.zip or uncompressed dir",
"option": "data",
N/A
N/A
N/A
{
"command": "ffx triage",
"options": [
{
"description": "path to config file or dir",
"option": "config",
"shorthand": "",
"value_type": "string"
},
{
"description": "path to snapshot.zip or uncompressed dir",
"option": "data",
N/A
N/A
N/A
{
"command": "ffx triage",
"options": [
{
"description": "path to config file or dir",
"option": "config",
"shorthand": "",
"value_type": "string"
},
{
"description": "path to snapshot.zip or uncompressed dir",
"option": "data",
N/A
N/A
N/A
{
"command": "ffx triage",
"options": [
{
"description": "path to config file or dir",
"option": "config",
"shorthand": "",
"value_type": "string"
},
{
"description": "path to snapshot.zip or uncompressed dir",
"option": "data",
N/A
N/A
N/A
{
"command": "ffx triage",
"options": [
{
"description": "path to config file or dir",
"option": "config",
"shorthand": "",
"value_type": "string"
},
{
"description": "path to snapshot.zip or uncompressed dir",
"option": "data",
N/A
N/A
N/A
{
"command": "ffx version",
"options": [
{
"description": "if true, includes details about both ffx and the daemon",
"option": "verbose",
"shorthand": "v",
"value_type": "bool"
}
],
"short": "Print out ffx tool and daemon versions"
}
#[test]
fn test_valid_string_dirty() {
let s = format!("{}-{}", HASH, TIMESTAMP);
let result = build_info_impl(s, FAKE_BUILD_VERSION.to_string());
let version = version_history_data::HISTORY.get_misleading_version_for_ffx();
assert_eq!(
result,
VersionInfo {
commit_hash: Some(HASH.to_string()),
commit_timestamp: Some(TIMESTAMP),
build_version: Some(FAKE_BUILD_VERSION.to_string()),
abi_revision: Some(version.abi_revision.as_u64()),
api_level: Some(
#[allow(deprecated)]
version.api_level.as_u64()
),
exec_path: std::env::current_exe().map(|x| x.to_string_lossy().to_string()).ok(),
..Default::default()
}
);
}
#[test]
fn test_valid_string_clean() {
let s = format!("{}-{}", HASH, TIMESTAMP);
let result = build_info_impl(s, FAKE_BUILD_VERSION.to_string());
let version = version_history_data::HISTORY.get_misleading_version_for_ffx();
assert_eq!(
result,
VersionInfo {
commit_hash: Some(HASH.to_string()),
commit_timestamp: Some(TIMESTAMP),
build_version: Some(FAKE_BUILD_VERSION.to_string()),
abi_revision: Some(version.abi_revision.as_u64()),
api_level: Some(
#[allow(deprecated)]
version.api_level.as_u64()
),
exec_path: std::env::current_exe().map(|x| x.to_string_lossy().to_string()).ok(),
..Default::default()
}
);
}
#[test]
fn test_invalid_string_empty() {
let result = build_info_impl(String::default(), FAKE_BUILD_VERSION.to_string());
assert_eq!(
result,
VersionInfo {
commit_hash: None,
commit_timestamp: None,
build_version: Some(FAKE_BUILD_VERSION.to_string()),
abi_revision: None,
api_level: None,
..Default::default()
}
);
}
N/A
N/A
{
"command": "ffx version",
"options": [
{
"description": "if true, includes details about both ffx and the daemon",
"option": "verbose",
"shorthand": "v",
"value_type": "bool"
}
],
"short": "Print out ffx tool and daemon versions"
}
N/A
N/A
N/A
{
"command": "ffx wlan",
"options": [],
"short": "Developer tool for manipulating WLAN state."
}
N/A
N/A
{
"command": "ffx wlan ap",
"options": [],
"short": "Controls WLAN AP policy API."
}
N/A
N/A
{
"command": "ffx wlan ap listen",
"options": [],
"short": "Listens for policy AP updates"
}
N/A
```posix-terminal
N/A
{
"command": "ffx wlan ap start",
"options": [
{
"description": "WLAN network name",
"option": "ssid",
"shorthand": "",
"value_type": "string"
},
{
"description": "one of None, WEP, WPA, WPA2, WPA3",
"option": "security-type",
N/A
```posix-terminal
N/A
{
"command": "ffx wlan ap start",
"options": [
{
"description": "WLAN network name",
"option": "ssid",
"shorthand": "",
"value_type": "string"
},
{
"description": "one of None, WEP, WPA, WPA2, WPA3",
"option": "security-type",
N/A
N/A
N/A
{
"command": "ffx wlan ap start",
"options": [
{
"description": "WLAN network name",
"option": "ssid",
"shorthand": "",
"value_type": "string"
},
{
"description": "one of None, WEP, WPA, WPA2, WPA3",
"option": "security-type",
N/A
N/A
N/A
{
"command": "ffx wlan ap start",
"options": [
{
"description": "WLAN network name",
"option": "ssid",
"shorthand": "",
"value_type": "string"
},
{
"description": "one of None, WEP, WPA, WPA2, WPA3",
"option": "security-type",
N/A
N/A
N/A
{
"command": "ffx wlan ap start",
"options": [
{
"description": "WLAN network name",
"option": "ssid",
"shorthand": "",
"value_type": "string"
},
{
"description": "one of None, WEP, WPA, WPA2, WPA3",
"option": "security-type",
N/A
N/A
N/A
{
"command": "ffx wlan ap status",
"options": [],
"short": "Provides the first available AP status update"
}
N/A
```posix-terminal
N/A
{
"command": "ffx wlan ap stop",
"options": [
{
"description": "WLAN network name",
"option": "ssid",
"shorthand": "",
"value_type": "string"
},
{
"description": "one of None, WEP, WPA, WPA2, WPA3",
"option": "security-type",
N/A
```posix-terminal
N/A
{
"command": "ffx wlan ap stop",
"options": [
{
"description": "WLAN network name",
"option": "ssid",
"shorthand": "",
"value_type": "string"
},
{
"description": "one of None, WEP, WPA, WPA2, WPA3",
"option": "security-type",
N/A
N/A
N/A
{
"command": "ffx wlan ap stop",
"options": [
{
"description": "WLAN network name",
"option": "ssid",
"shorthand": "",
"value_type": "string"
},
{
"description": "one of None, WEP, WPA, WPA2, WPA3",
"option": "security-type",
N/A
N/A
N/A
{
"command": "ffx wlan ap stop",
"options": [
{
"description": "WLAN network name",
"option": "ssid",
"shorthand": "",
"value_type": "string"
},
{
"description": "one of None, WEP, WPA, WPA2, WPA3",
"option": "security-type",
N/A
N/A
N/A
{
"command": "ffx wlan ap stop",
"options": [
{
"description": "WLAN network name",
"option": "ssid",
"shorthand": "",
"value_type": "string"
},
{
"description": "one of None, WEP, WPA, WPA2, WPA3",
"option": "security-type",
N/A
N/A
N/A
{
"command": "ffx wlan ap stop-all",
"options": [],
"short": "Stops all active APs"
}
N/A
```posix-terminal
N/A
{
"command": "ffx wlan client",
"options": [],
"short": "Controls WLAN client policy API."
}
N/A
N/A
{
"command": "ffx wlan client batch-config",
"options": [],
"short": "Allows WLAN credentials to be extracted and restored."
}
N/A
```posix-terminal
```posix-terminal
N/A
{
"command": "ffx wlan client batch-config dump",
"options": [],
"short": "Extracts a structured representation of the device's saved WLAN credentials."
}
N/A
N/A
N/A
{
"command": "ffx wlan client batch-config restore",
"options": [],
"short": "Injects a structure representation of WLAN credentials into a device."
}
N/A
N/A
N/A
{
"command": "ffx wlan client connect",
"options": [
{
"description": "WLAN network name",
"option": "ssid",
"shorthand": "",
"value_type": "string"
},
{
"description": "one of None, WEP, WPA, WPA2, WPA3",
"option": "security-type",
N/A
```posix-terminal
N/A
{
"command": "ffx wlan client connect",
"options": [
{
"description": "WLAN network name",
"option": "ssid",
"shorthand": "",
"value_type": "string"
},
{
"description": "one of None, WEP, WPA, WPA2, WPA3",
"option": "security-type",
N/A
N/A
N/A
{
"command": "ffx wlan client connect",
"options": [
{
"description": "WLAN network name",
"option": "ssid",
"shorthand": "",
"value_type": "string"
},
{
"description": "one of None, WEP, WPA, WPA2, WPA3",
"option": "security-type",
N/A
N/A
N/A
{
"command": "ffx wlan client list-saved-networks",
"options": [],
"short": "Lists all networks saved by the WLAN policy layer."
}
N/A
```posix-terminal
N/A
{
"command": "ffx wlan client listen",
"options": [],
"short": "Listens for policy client connections updates"
}
N/A
```posix-terminal
N/A
{
"command": "ffx wlan client remove-network",
"options": [
{
"description": "WLAN network name",
"option": "ssid",
"shorthand": "",
"value_type": "string"
},
{
"description": "one of None, WEP, WPA, WPA2, WPA3",
"option": "security-type",
N/A
```posix-terminal
N/A
{
"command": "ffx wlan client remove-network",
"options": [
{
"description": "WLAN network name",
"option": "ssid",
"shorthand": "",
"value_type": "string"
},
{
"description": "one of None, WEP, WPA, WPA2, WPA3",
"option": "security-type",
N/A
N/A
N/A
{
"command": "ffx wlan client remove-network",
"options": [
{
"description": "WLAN network name",
"option": "ssid",
"shorthand": "",
"value_type": "string"
},
{
"description": "one of None, WEP, WPA, WPA2, WPA3",
"option": "security-type",
N/A
N/A
N/A
{
"command": "ffx wlan client remove-network",
"options": [
{
"description": "WLAN network name",
"option": "ssid",
"shorthand": "",
"value_type": "string"
},
{
"description": "one of None, WEP, WPA, WPA2, WPA3",
"option": "security-type",
N/A
N/A
N/A
{
"command": "ffx wlan client remove-network",
"options": [
{
"description": "WLAN network name",
"option": "ssid",
"shorthand": "",
"value_type": "string"
},
{
"description": "one of None, WEP, WPA, WPA2, WPA3",
"option": "security-type",
N/A
N/A
N/A
{
"command": "ffx wlan client save-network",
"options": [
{
"description": "WLAN network name",
"option": "ssid",
"shorthand": "",
"value_type": "string"
},
{
"description": "one of None, WEP, WPA, WPA2, WPA3",
"option": "security-type",
N/A
```posix-terminal
N/A
{
"command": "ffx wlan client save-network",
"options": [
{
"description": "WLAN network name",
"option": "ssid",
"shorthand": "",
"value_type": "string"
},
{
"description": "one of None, WEP, WPA, WPA2, WPA3",
"option": "security-type",
N/A
N/A
N/A
{
"command": "ffx wlan client save-network",
"options": [
{
"description": "WLAN network name",
"option": "ssid",
"shorthand": "",
"value_type": "string"
},
{
"description": "one of None, WEP, WPA, WPA2, WPA3",
"option": "security-type",
N/A
N/A
N/A
{
"command": "ffx wlan client save-network",
"options": [
{
"description": "WLAN network name",
"option": "ssid",
"shorthand": "",
"value_type": "string"
},
{
"description": "one of None, WEP, WPA, WPA2, WPA3",
"option": "security-type",
N/A
N/A
N/A
{
"command": "ffx wlan client save-network",
"options": [
{
"description": "WLAN network name",
"option": "ssid",
"shorthand": "",
"value_type": "string"
},
{
"description": "one of None, WEP, WPA, WPA2, WPA3",
"option": "security-type",
N/A
N/A
N/A
{
"command": "ffx wlan client scan",
"options": [],
"short": "Scan for nearby WLAN networks."
}
N/A
```posix-terminal
N/A
{
"command": "ffx wlan client start",
"options": [],
"short": "Allows wlancfg to automate WLAN client operation"
}
N/A
```posix-terminal
N/A
{
"command": "ffx wlan client status",
"options": [],
"short": "Provides the first available client status update"
}
N/A
```posix-terminal
N/A
{
"command": "ffx wlan client stop",
"options": [],
"short": "Stops automated WLAN policy control of client interfaces and\ndestroys all client interfaces."
}
N/A
```posix-terminal
N/A
{
"command": "ffx wlan deprecated",
"options": [],
"short": "Controls to-be-deleted WLAN functionality."
}
N/A
```posix-terminal
N/A
{
"command": "ffx wlan deprecated suggest-mac",
"options": [],
"short": "Notifies WLAN policy of a MAC address that ought to be used when creating new AP interfaces"
}
N/A
```posix-terminal
N/A
Four percent of flags appear in any documented sequence — recipes name the command, not the flag. An agent that knows a flag exists in isolation hasn't been shown when to use it.