aboutsummaryrefslogtreecommitdiff
path: root/src/integration/tests.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/integration/tests.rs')
-rw-r--r--src/integration/tests.rs184
1 files changed, 184 insertions, 0 deletions
diff --git a/src/integration/tests.rs b/src/integration/tests.rs
index ff616264..7abf7be2 100644
--- a/src/integration/tests.rs
+++ b/src/integration/tests.rs
@@ -102,6 +102,7 @@ fn clear_integration_path_env() {
std::env::remove_var("XDG_CONFIG_HOME");
std::env::remove_var(QODERCLI_CONFIG_DIR_ENV_VAR);
std::env::remove_var(CURSOR_CONFIG_DIR_ENV_VAR);
+ std::env::remove_var(ANTIGRAVITY_CLI_CONFIG_DIR_ENV_VAR);
std::env::remove_var(GROK_CONFIG_DIR_ENV_VAR);
std::env::remove_var(GROK_HOME_ENV_VAR);
}
@@ -3645,6 +3646,154 @@ fn uninstall_mastracode_errors_when_event_value_not_array() {
}
#[test]
+fn install_antigravity_cli_writes_hook_and_updates_hooks_json() {
+ let _lock = integration_env_lock();
+ let base = unique_base();
+ let agy_dir = base.join(".gemini").join("config");
+ fs::create_dir_all(&agy_dir).unwrap();
+ fs::write(
+ agy_dir.join("hooks.json"),
+ r#"{"lint-checker":{"PreInvocation":[{"type":"command","command":"echo keep-me"}]}}"#,
+ )
+ .unwrap();
+ std::env::set_var(ANTIGRAVITY_CLI_CONFIG_DIR_ENV_VAR, &agy_dir);
+
+ let installed = install_antigravity_cli().unwrap();
+
+ assert_eq!(
+ installed.hook_path,
+ agy_dir
+ .join("hooks")
+ .join(ANTIGRAVITY_CLI_HOOK_INSTALL_NAME)
+ );
+ assert_eq!(installed.hooks_path, agy_dir.join("hooks.json"));
+ assert_eq!(
+ fs::read_to_string(&installed.hook_path).unwrap(),
+ ANTIGRAVITY_CLI_HOOK_ASSET
+ );
+
+ let hooks_file: Value =
+ serde_json::from_str(&fs::read_to_string(agy_dir.join("hooks.json")).unwrap()).unwrap();
+ let hooks = hooks_file.as_object().unwrap();
+
+ // Herdr entries live under a named hook block; Antigravity CLI rejects a
+ // file whose top level maps event names straight to arrays.
+ let block = hooks
+ .get(ANTIGRAVITY_CLI_HOOK_BLOCK_NAME)
+ .and_then(Value::as_object)
+ .unwrap();
+
+ for (event, action) in ANTIGRAVITY_CLI_HOOK_EVENTS {
+ let entries = block.get(event).and_then(Value::as_array).unwrap();
+ assert_eq!(entries.len(), 1, "{event} should hold one Herdr entry");
+ let handler = &entries[0];
+
+ // Handlers must be a flat list; the matcher/hooks wrapper is only
+ // valid for tool events and invalidates the whole file here.
+ assert!(
+ handler.get("matcher").is_none() && handler.get("hooks").is_none(),
+ "{event} must be a flat handler, got {handler}"
+ );
+
+ assert_eq!(handler.get("type").and_then(Value::as_str), Some("command"));
+ assert_eq!(
+ handler.get("timeout").and_then(Value::as_u64),
+ Some(ANTIGRAVITY_CLI_HOOK_TIMEOUT_SEC)
+ );
+ let command = handler.get("command").and_then(Value::as_str).unwrap();
+ assert!(command.contains("herdr-agent-state"));
+ assert!(command.ends_with(action));
+ }
+
+ // The integration is session-only. Antigravity CLI cannot express blocked
+ // state, skips PostInvocation on interruption, and fires Stop at end of
+ // turn rather than process exit, so Herdr never claims lifecycle authority
+ // here and screen detection owns agent state.
+ for event in ["PreToolUse", "PostToolUse", "PostInvocation", "Stop"] {
+ assert!(
+ block.get(event).is_none(),
+ "{event} must not be registered; lifecycle stays with screen detection"
+ );
+ }
+
+ // Other named hooks are left untouched.
+ assert_eq!(
+ hooks
+ .get("lint-checker")
+ .and_then(|block| block.get("PreInvocation"))
+ .and_then(Value::as_array)
+ .and_then(|entries| entries.first())
+ .and_then(|entry| entry.get("command"))
+ .and_then(Value::as_str),
+ Some("echo keep-me")
+ );
+
+ std::env::remove_var(ANTIGRAVITY_CLI_CONFIG_DIR_ENV_VAR);
+ let _ = fs::remove_dir_all(base);
+}
+
+#[test]
+fn install_antigravity_cli_rewrites_stale_herdr_block() {
+ let _lock = integration_env_lock();
+ let base = unique_base();
+ let agy_dir = base.join(".gemini").join("config");
+ fs::create_dir_all(&agy_dir).unwrap();
+ // An older Herdr install claimed lifecycle authority, wrapped events in
+ // matcher/hooks, and left entries Antigravity CLI now rejects.
+ fs::write(
+ agy_dir.join("hooks.json"),
+ r#"{"herdr":{"Stop":[{"matcher":"*","hooks":[{"type":"command","command":"stale"}]}],"PostInvocation":[{"type":"command","command":"stale idle"}],"Legacy":[]}}"#,
+ )
+ .unwrap();
+ std::env::set_var(ANTIGRAVITY_CLI_CONFIG_DIR_ENV_VAR, &agy_dir);
+
+ install_antigravity_cli().unwrap();
+
+ let hooks_file: Value =
+ serde_json::from_str(&fs::read_to_string(agy_dir.join("hooks.json")).unwrap()).unwrap();
+ let block = hooks_file
+ .get(ANTIGRAVITY_CLI_HOOK_BLOCK_NAME)
+ .and_then(Value::as_object)
+ .unwrap();
+
+ // The block is Herdr-owned and rewritten wholesale, so a stale lifecycle
+ // install is migrated to session-only rather than merged with.
+ assert_eq!(
+ block.keys().map(String::as_str).collect::<Vec<_>>(),
+ vec!["PreInvocation"],
+ "stale lifecycle events should be gone"
+ );
+ let entries = block
+ .get("PreInvocation")
+ .and_then(Value::as_array)
+ .unwrap();
+ assert_eq!(entries.len(), 1);
+ assert!(entries[0].get("hooks").is_none());
+ assert!(entries[0]
+ .get("command")
+ .and_then(Value::as_str)
+ .is_some_and(|command| command.contains("herdr-agent-state")));
+
+ std::env::remove_var(ANTIGRAVITY_CLI_CONFIG_DIR_ENV_VAR);
+ let _ = fs::remove_dir_all(base);
+}
+
+#[test]
+fn install_antigravity_cli_errors_when_config_dir_missing() {
+ let _lock = integration_env_lock();
+ let base = unique_base();
+ let agy_dir = base.join(".gemini").join("config");
+ std::env::set_var(ANTIGRAVITY_CLI_CONFIG_DIR_ENV_VAR, &agy_dir);
+
+ let err = install_antigravity_cli().unwrap_err();
+ assert!(err.to_string().contains("install antigravity cli first"));
+ assert!(!agy_dir.exists(), "install must not create the config dir");
+
+ std::env::remove_var(ANTIGRAVITY_CLI_CONFIG_DIR_ENV_VAR);
+ let _ = fs::remove_dir_all(base);
+}
+
+#[test]
fn grok_v1_integration_status_is_current() {
let _lock = integration_env_lock();
let base = unique_base();
@@ -3756,6 +3905,41 @@ fn grok_status_reports_outdated_when_hook_config_missing_or_broken() {
}
#[test]
+fn uninstall_antigravity_cli_removes_hooks_json_entries_and_hook_file() {
+ let _lock = integration_env_lock();
+ let base = unique_base();
+ let agy_dir = base.join(".gemini").join("config");
+ fs::create_dir_all(&agy_dir).unwrap();
+ fs::write(
+ agy_dir.join("hooks.json"),
+ r#"{"lint-checker":{"PreInvocation":[{"type":"command","command":"echo keep-me"}]}}"#,
+ )
+ .unwrap();
+ std::env::set_var(ANTIGRAVITY_CLI_CONFIG_DIR_ENV_VAR, &agy_dir);
+
+ // Install first
+ let installed = install_antigravity_cli().unwrap();
+ assert!(installed.hook_path.is_file());
+
+ // Uninstall
+ let result = uninstall_antigravity_cli().unwrap();
+ assert!(result.removed_hook_file);
+ assert!(!installed.hook_path.is_file());
+ assert!(result.updated_hooks);
+
+ let hooks_file: Value =
+ serde_json::from_str(&fs::read_to_string(agy_dir.join("hooks.json")).unwrap()).unwrap();
+ let hooks = hooks_file.as_object().unwrap();
+
+ // The Herdr block is gone and unrelated named hooks survive.
+ assert!(hooks.get(ANTIGRAVITY_CLI_HOOK_BLOCK_NAME).is_none());
+ assert!(hooks.contains_key("lint-checker"));
+
+ std::env::remove_var(ANTIGRAVITY_CLI_CONFIG_DIR_ENV_VAR);
+ let _ = fs::remove_dir_all(base);
+}
+
+#[test]
fn grok_dir_honors_grok_home_after_config_dir_seam() {
let _lock = integration_env_lock();
let base = unique_base();