mirror of
https://github.com/NVIDIA/OpenShell.git
synced 2026-10-19 05:50:41 +08:00
* feat(api)!: use sandbox names as canonical references Signed-off-by: Drew Newberry <anewberry@nvidia.com> * test(cli): update forward color fixture for workspace scope Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(supervisor): use sandbox names for settings lookup Signed-off-by: Drew Newberry <anewberry@nvidia.com> * test(e2e): use canonical sandbox request fields Signed-off-by: Drew Newberry <anewberry@nvidia.com> * test(e2e): use canonical sandbox receipt field Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(server): harden sandbox mutation handling Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(ci): update rebased sandbox references Signed-off-by: Drew Newberry <anewberry@nvidia.com> * feat(api)!: standardize canonical entity references Signed-off-by: Drew Newberry <anewberry@nvidia.com> * docs(api): codify protobuf API conventions Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(api): preserve workspace selector semantics Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(api): restore workspace selector parity Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(api): preserve descriptive name fields Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(api): update e2e request fixtures Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(core): omit workspace selector during bootstrap Signed-off-by: Drew Newberry <anewberry@nvidia.com> * chore(api): remove proto convention checker Signed-off-by: Drew Newberry <anewberry@nvidia.com> * chore(api): refresh schema fingerprints after rebase Signed-off-by: Drew Newberry <anewberry@nvidia.com> * fix(cli): use canonical provider receipt field Signed-off-by: Drew Newberry <anewberry@nvidia.com> --------- Signed-off-by: Drew Newberry <anewberry@nvidia.com>
162 lines
5.0 KiB
Rust
162 lines
5.0 KiB
Rust
// SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
use std::fs;
|
|
use std::path::Path;
|
|
use std::process::{Command, Output};
|
|
|
|
const DEAD_PID: u32 = u32::MAX;
|
|
|
|
fn run_forward_list(config_dir: &Path, args: &[&str]) -> Output {
|
|
let mut command = Command::new(env!("CARGO_BIN_EXE_openshell"));
|
|
for (key, _) in std::env::vars().filter(|(key, _)| key.starts_with("OPENSHELL_")) {
|
|
command.env_remove(key);
|
|
}
|
|
command
|
|
.args(["forward", "list"])
|
|
.args(args)
|
|
.env("XDG_CONFIG_HOME", config_dir)
|
|
.env("HOME", config_dir)
|
|
.output()
|
|
.expect("run openshell forward list")
|
|
}
|
|
|
|
fn write_dead_forward(config_dir: &Path) {
|
|
let forward_dir = config_dir.join("openshell/forwards/default");
|
|
fs::create_dir_all(&forward_dir).expect("create forward directory");
|
|
fs::write(
|
|
forward_dir.join("my-sandbox-8443.pid"),
|
|
format!("{DEAD_PID}\tsandbox-id\t0.0.0.0"),
|
|
)
|
|
.expect("write forward PID record");
|
|
}
|
|
|
|
fn assert_success(output: &Output) {
|
|
assert!(
|
|
output.status.success(),
|
|
"forward list failed:\n{}",
|
|
String::from_utf8_lossy(&output.stderr)
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn forward_list_json_emits_machine_readable_records() {
|
|
let config_dir = tempfile::tempdir().expect("create config directory");
|
|
write_dead_forward(config_dir.path());
|
|
|
|
let output = run_forward_list(config_dir.path(), &["--output", "json"]);
|
|
assert_success(&output);
|
|
assert!(
|
|
output.stderr.is_empty(),
|
|
"structured output wrote to stderr"
|
|
);
|
|
assert!(
|
|
!output.stdout.contains(&0x1b),
|
|
"JSON contained ANSI escapes"
|
|
);
|
|
|
|
let value: serde_json::Value =
|
|
serde_json::from_slice(&output.stdout).expect("stdout should contain only JSON");
|
|
assert_eq!(
|
|
value,
|
|
serde_json::json!([{
|
|
"workspace": "default",
|
|
"sandbox": "my-sandbox",
|
|
"bind_address": "0.0.0.0",
|
|
"port": 8443,
|
|
"pid": DEAD_PID,
|
|
"alive": false,
|
|
}])
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn forward_list_yaml_emits_equivalent_records() {
|
|
let config_dir = tempfile::tempdir().expect("create config directory");
|
|
write_dead_forward(config_dir.path());
|
|
|
|
let output = run_forward_list(config_dir.path(), &["-o", "yaml"]);
|
|
assert_success(&output);
|
|
assert!(
|
|
output.stderr.is_empty(),
|
|
"structured output wrote to stderr"
|
|
);
|
|
assert!(
|
|
!output.stdout.contains(&0x1b),
|
|
"YAML contained ANSI escapes"
|
|
);
|
|
|
|
let value: serde_json::Value =
|
|
serde_yml::from_slice(&output.stdout).expect("stdout should contain only YAML");
|
|
assert_eq!(
|
|
value,
|
|
serde_json::json!([{
|
|
"workspace": "default",
|
|
"sandbox": "my-sandbox",
|
|
"bind_address": "0.0.0.0",
|
|
"port": 8443,
|
|
"pid": DEAD_PID,
|
|
"alive": false,
|
|
}])
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn forward_list_structured_output_emits_empty_collections() {
|
|
let config_dir = tempfile::tempdir().expect("create config directory");
|
|
|
|
for format in ["json", "yaml"] {
|
|
let output = run_forward_list(config_dir.path(), &["--output", format]);
|
|
assert_success(&output);
|
|
assert!(output.stderr.is_empty(), "{format} output wrote to stderr");
|
|
|
|
let value: serde_json::Value = match format {
|
|
"json" => serde_json::from_slice(&output.stdout).expect("parse empty JSON collection"),
|
|
"yaml" => serde_yml::from_slice(&output.stdout).expect("parse empty YAML collection"),
|
|
_ => unreachable!(),
|
|
};
|
|
assert_eq!(value, serde_json::json!([]));
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn forward_list_table_output_includes_workspace_scope() {
|
|
let config_dir = tempfile::tempdir().expect("create config directory");
|
|
write_dead_forward(config_dir.path());
|
|
|
|
let output = run_forward_list(config_dir.path(), &[]);
|
|
assert_success(&output);
|
|
assert!(output.stderr.is_empty(), "table output wrote to stderr");
|
|
|
|
let stdout = String::from_utf8_lossy(&output.stdout);
|
|
let rows: Vec<Vec<&str>> = stdout
|
|
.lines()
|
|
.map(|line| line.split_whitespace().collect())
|
|
.collect();
|
|
assert_eq!(rows.len(), 2);
|
|
assert_eq!(
|
|
rows[0],
|
|
vec!["WORKSPACE", "SANDBOX", "BIND", "PORT", "PID", "STATUS"]
|
|
);
|
|
assert_eq!(
|
|
&rows[1][..5],
|
|
["default", "my-sandbox", "0.0.0.0", "8443", "4294967295"]
|
|
);
|
|
assert!(rows[1][5].contains("dead"));
|
|
}
|
|
|
|
#[test]
|
|
fn forward_list_help_documents_output_flag() {
|
|
let config_dir = tempfile::tempdir().expect("create config directory");
|
|
let output = run_forward_list(config_dir.path(), &["--help"]);
|
|
assert_success(&output);
|
|
|
|
let stdout = String::from_utf8(output.stdout).expect("help should be UTF-8");
|
|
assert!(stdout.contains("-o, --output <OUTPUT>"), "{stdout}");
|
|
assert!(stdout.contains("[default: table]"), "{stdout}");
|
|
assert!(
|
|
stdout.contains("possible values: table, yaml, json"),
|
|
"{stdout}"
|
|
);
|
|
}
|