fix(grid-agent): move setup into YAML preferences (#135)
This commit is contained in:
110
crates/metacrate-grid-agent/tests/preferences_config.rs
Normal file
110
crates/metacrate-grid-agent/tests/preferences_config.rs
Normal file
@@ -0,0 +1,110 @@
|
||||
use metacrate_grid_agent::{
|
||||
AgentPreferences, ConfigLoader, MapEnvironment, OperatingMode, OperatorScreen, OperatorTui,
|
||||
PreferencesPanel, TuiInput, TuiRenderOptions,
|
||||
};
|
||||
use std::fs;
|
||||
use std::path::PathBuf;
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
|
||||
fn temporary(name: &str) -> PathBuf {
|
||||
let directory = std::env::temp_dir().join(format!(
|
||||
"metacrate-preferences-{}-{name}",
|
||||
SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.unwrap()
|
||||
.as_nanos()
|
||||
));
|
||||
fs::create_dir_all(&directory).unwrap();
|
||||
directory
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn yaml_is_primary_and_preferences_preserve_unknown_settings() {
|
||||
let directory = temporary("yaml");
|
||||
let path = directory.join("config.yml");
|
||||
fs::write(
|
||||
&path,
|
||||
r"schema_version: 1
|
||||
integrated: true
|
||||
llm:
|
||||
endpoint_url: https://ai.invalid/v1/chat/completions
|
||||
api_key: private-key
|
||||
model: local-model
|
||||
grid:
|
||||
login_url: https://grid.invalid/login
|
||||
avatar_name: Service Avatar
|
||||
password: private-password
|
||||
authorized_avatar_uuids:
|
||||
- 00000000-0000-4000-8000-000000000001
|
||||
behavior:
|
||||
idle_interval_seconds: 321
|
||||
",
|
||||
)
|
||||
.unwrap();
|
||||
let config = ConfigLoader::new()
|
||||
.with_file(&path)
|
||||
.with_environment(MapEnvironment::default())
|
||||
.load()
|
||||
.unwrap();
|
||||
assert_eq!(config.mode, OperatingMode::Integrated);
|
||||
assert_eq!(config.llm.model.as_deref(), Some("local-model"));
|
||||
assert_eq!(config.behavior.idle_interval.as_secs(), 321);
|
||||
|
||||
let mut preferences = AgentPreferences::load(&path).unwrap();
|
||||
preferences.set_llm_model("replacement-model".into());
|
||||
preferences.save(&path).unwrap();
|
||||
let saved = fs::read_to_string(&path).unwrap();
|
||||
assert!(saved.contains("idle_interval_seconds: 321"));
|
||||
assert!(saved.contains("model: replacement-model"));
|
||||
assert!(!format!("{preferences:?}").contains("private-key"));
|
||||
#[cfg(unix)]
|
||||
{
|
||||
use std::os::unix::fs::PermissionsExt as _;
|
||||
assert_eq!(
|
||||
fs::metadata(&path).unwrap().permissions().mode() & 0o777,
|
||||
0o600
|
||||
);
|
||||
}
|
||||
fs::remove_dir_all(directory).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dotenv_import_is_explicit_and_preferences_panel_never_renders_secrets() {
|
||||
let directory = temporary("import");
|
||||
let dotenv = directory.join("legacy.env");
|
||||
let config = directory.join("config.yml");
|
||||
fs::write(
|
||||
&dotenv,
|
||||
"OPENAPI_URL=https://ai.invalid/v1/chat/completions\nOPENAPI_KEY=very-secret-key\nOPENAPI_MODEL=test-model\nGRID_LOGIN_URL=https://grid.invalid/login\nGRID_USER=Test Avatar\nGRID_PASSWORD=very-secret-password\n",
|
||||
)
|
||||
.unwrap();
|
||||
let mut preferences = AgentPreferences::load(&config).unwrap();
|
||||
preferences.import_dotenv(&dotenv).unwrap();
|
||||
preferences.set_privileged_users(vec!["00000000-0000-4000-8000-000000000001".into()]);
|
||||
preferences.save(&config).unwrap();
|
||||
|
||||
let panel = PreferencesPanel::open(config.clone()).unwrap();
|
||||
let summary = panel.summary();
|
||||
assert_eq!(summary.llm_model.as_deref(), Some("test-model"));
|
||||
assert!(summary.llm_api_key_configured && summary.grid_password_configured);
|
||||
assert_eq!(summary.privileged_users.len(), 1);
|
||||
|
||||
let mut tui = OperatorTui::with_preferences(config).unwrap();
|
||||
tui.screen = OperatorScreen::Preferences;
|
||||
let rendered = tui.render(TuiRenderOptions {
|
||||
width: 120,
|
||||
height: 30,
|
||||
color: false,
|
||||
});
|
||||
assert!(rendered.contains("LLM API key: [configured]"));
|
||||
assert!(rendered.contains("grid password: [configured]"));
|
||||
assert!(!rendered.contains("very-secret"));
|
||||
let _ = tui.reduce(TuiInput::PreferenceNext);
|
||||
let _ = tui.reduce(TuiInput::PreferenceEditOrCommit);
|
||||
for value in "https://replacement.invalid/v1/chat".chars() {
|
||||
let _ = tui.reduce(TuiInput::PreferenceCharacter(value));
|
||||
}
|
||||
let _ = tui.reduce(TuiInput::PreferenceEditOrCommit);
|
||||
let _ = tui.reduce(TuiInput::PreferenceSave);
|
||||
fs::remove_dir_all(directory).unwrap();
|
||||
}
|
||||
Reference in New Issue
Block a user