111 lines
3.9 KiB
Rust
111 lines
3.9 KiB
Rust
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();
|
|
}
|