diff options
| author | Ward Peeters <ward@coding-tech.com> | 2026-07-04 00:29:42 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-07-04 01:29:42 +0300 |
| commit | d0e333451bd794a419e96f28db925772950ea156 (patch) | |
| tree | 1a6e5d3bd6ac40f8ef454058f069d30202327002 /src/integration/tests.rs | |
| parent | d5521e3d250498df4af552fff83fce3d5ef33810 (diff) | |
feat: add mastracode integration (#788)
* feat: add mastracode integration
refs #337
Co-authored-by: Mastra Code (openai/gpt-5.5) <noreply@mastra.ai>
Co-authored-by: Ogulcan Celik <ogulcancelik@gmail.com>
Diffstat (limited to 'src/integration/tests.rs')
| -rw-r--r-- | src/integration/tests.rs | 205 |
1 files changed, 205 insertions, 0 deletions
diff --git a/src/integration/tests.rs b/src/integration/tests.rs index 2a8a7be3..b09e3c23 100644 --- a/src/integration/tests.rs +++ b/src/integration/tests.rs @@ -175,6 +175,7 @@ fn windows_supports_only_cli_hook_integrations() { assert!(!integration_target_supported(IntegrationTarget::Hermes)); assert!(!integration_target_supported(IntegrationTarget::Cursor)); assert!(!integration_target_supported(IntegrationTarget::Devin)); + assert!(!integration_target_supported(IntegrationTarget::Mastracode)); assert!(integration_target_supported(IntegrationTarget::Claude)); assert!(integration_target_supported(IntegrationTarget::Codex)); @@ -203,6 +204,7 @@ fn windows_does_not_offer_unsupported_integrations_even_when_commands_exist() { fs::write(bin.join("hermes.exe"), "").unwrap(); fs::write(bin.join("cursor-agent.cmd"), "@echo off\r\n").unwrap(); fs::write(bin.join("devin.cmd"), "@echo off\r\n").unwrap(); + fs::write(bin.join("mastracode.cmd"), "@echo off\r\n").unwrap(); assert!(!integration_target_available(IntegrationTarget::Pi)); assert!(!integration_target_available(IntegrationTarget::Omp)); @@ -211,6 +213,7 @@ fn windows_does_not_offer_unsupported_integrations_even_when_commands_exist() { assert!(!integration_target_available(IntegrationTarget::Hermes)); assert!(!integration_target_available(IntegrationTarget::Cursor)); assert!(!integration_target_available(IntegrationTarget::Devin)); + assert!(!integration_target_available(IntegrationTarget::Mastracode)); if let Some(path) = original_path { std::env::set_var("PATH", path); @@ -2587,6 +2590,13 @@ fn bundled_integration_assets_report_session_refs() { assert!(CURSOR_HOOK_ASSET.contains("sessionStart")); assert!(!CURSOR_HOOK_ASSET.contains("\"state\":")); assert!(!CURSOR_HOOK_ASSET.contains("pane.release_agent")); + assert!(MASTRACODE_HOOK_ASSET.contains("HERDR_INTEGRATION_ID=mastracode")); + assert!(MASTRACODE_HOOK_ASSET.contains("HERDR_INTEGRATION_VERSION=1")); + assert!(MASTRACODE_HOOK_ASSET.contains("session_id")); + assert!(!MASTRACODE_HOOK_ASSET.contains("run_id")); + assert!(MASTRACODE_HOOK_ASSET.contains("agent_session_id")); + assert!(MASTRACODE_HOOK_ASSET.contains("pane.report_agent")); + assert!(MASTRACODE_HOOK_ASSET.contains("pane.release_agent")); } #[test] @@ -3102,3 +3112,198 @@ fn install_cursor_errors_when_config_dir_missing() { std::env::remove_var(CURSOR_CONFIG_DIR_ENV_VAR); let _ = fs::remove_dir_all(base); } + +#[test] +fn install_mastracode_writes_hook_and_updates_hooks_json() { + let _lock = integration_env_lock(); + let base = unique_base(); + let original_home = std::env::var_os("HOME"); + let mastracode_dir = base.join(".mastracode"); + fs::create_dir_all(&mastracode_dir).unwrap(); + fs::write( + mastracode_dir.join("hooks.json"), + r#"{"PostToolUse":[{"type":"command","command":"echo keep-me"}]}"#, + ) + .unwrap(); + std::env::set_var("HOME", &base); + + let installed = install_mastracode().unwrap(); + + assert_eq!( + installed.hook_path, + mastracode_dir + .join("hooks") + .join(MASTRACODE_HOOK_INSTALL_NAME) + ); + assert_eq!(installed.hooks_path, mastracode_dir.join("hooks.json")); + assert_eq!( + fs::read_to_string(&installed.hook_path).unwrap(), + MASTRACODE_HOOK_ASSET + ); + + let hooks_file: Value = + serde_json::from_str(&fs::read_to_string(mastracode_dir.join("hooks.json")).unwrap()) + .unwrap(); + let hooks = hooks_file.as_object().unwrap(); + for (event, action) in MASTRACODE_HOOK_EVENTS { + let entries = hooks.get(event).and_then(Value::as_array).unwrap(); + assert_eq!(entries.len(), 1, "{event} should have one Herdr hook"); + let command = entries[0].get("command").and_then(Value::as_str).unwrap(); + assert!(command.starts_with("bash ")); + assert!(command.contains(MASTRACODE_HOOK_INSTALL_NAME)); + assert!(command.ends_with(action)); + assert_eq!( + entries[0].get("type").and_then(Value::as_str), + Some("command") + ); + assert_eq!( + entries[0].get("timeout").and_then(Value::as_u64), + Some(MASTRACODE_HOOK_TIMEOUT_MS) + ); + } + assert_eq!( + hooks["PostToolUse"][0] + .get("command") + .and_then(Value::as_str), + Some("echo keep-me") + ); + + if let Some(home) = original_home { + std::env::set_var("HOME", home); + } else { + std::env::remove_var("HOME"); + } + let _ = fs::remove_dir_all(base); +} + +#[test] +fn install_mastracode_is_idempotent_for_hook_entries() { + let _lock = integration_env_lock(); + let base = unique_base(); + let original_home = std::env::var_os("HOME"); + std::env::set_var("HOME", &base); + + install_mastracode().unwrap(); + install_mastracode().unwrap(); + + let hooks_file: Value = serde_json::from_str( + &fs::read_to_string(base.join(".mastracode").join("hooks.json")).unwrap(), + ) + .unwrap(); + let hooks = hooks_file.as_object().unwrap(); + for (event, _) in MASTRACODE_HOOK_EVENTS { + assert_eq!(hooks.get(event).and_then(Value::as_array).unwrap().len(), 1); + } + + if let Some(home) = original_home { + std::env::set_var("HOME", home); + } else { + std::env::remove_var("HOME"); + } + let _ = fs::remove_dir_all(base); +} + +#[test] +fn uninstall_mastracode_removes_herdr_hooks_and_preserves_others() { + let _lock = integration_env_lock(); + let base = unique_base(); + let original_home = std::env::var_os("HOME"); + std::env::set_var("HOME", &base); + + install_mastracode().unwrap(); + let hooks_path = base.join(".mastracode").join("hooks.json"); + let mut hooks_file: Value = + serde_json::from_str(&fs::read_to_string(&hooks_path).unwrap()).unwrap(); + hooks_file["UserPromptSubmit"] + .as_array_mut() + .unwrap() + .push(json!({ "type": "command", "command": "echo user-defined" })); + fs::write( + &hooks_path, + serde_json::to_string_pretty(&hooks_file).unwrap(), + ) + .unwrap(); + + let result = uninstall_mastracode().unwrap(); + assert!(result.removed_hook_file); + assert!(result.updated_hooks); + assert!(!base + .join(".mastracode") + .join("hooks") + .join(MASTRACODE_HOOK_INSTALL_NAME) + .is_file()); + + let hooks_file: Value = + serde_json::from_str(&fs::read_to_string(&hooks_path).unwrap()).unwrap(); + let hooks = hooks_file.as_object().unwrap(); + for (event, _) in MASTRACODE_HOOK_EVENTS { + if event == "UserPromptSubmit" { + continue; + } + assert!(!hooks.contains_key(event), "{event} should be removed"); + } + let user_prompt_submit = hooks + .get("UserPromptSubmit") + .and_then(Value::as_array) + .unwrap(); + assert_eq!(user_prompt_submit.len(), 1); + assert_eq!( + user_prompt_submit[0].get("command").and_then(Value::as_str), + Some("echo user-defined") + ); + + if let Some(home) = original_home { + std::env::set_var("HOME", home); + } else { + std::env::remove_var("HOME"); + } + let _ = fs::remove_dir_all(base); +} + +#[test] +fn install_mastracode_errors_when_event_value_not_array() { + let _lock = integration_env_lock(); + let base = unique_base(); + let original_home = std::env::var_os("HOME"); + let mastracode_dir = base.join(".mastracode"); + fs::create_dir_all(&mastracode_dir).unwrap(); + fs::write(mastracode_dir.join("hooks.json"), r#"{"SessionStart":{}}"#).unwrap(); + std::env::set_var("HOME", &base); + + let err = install_mastracode().unwrap_err().to_string(); + assert!( + err.contains("hook entries for SessionStart must be an array"), + "unexpected error: {err}" + ); + + if let Some(home) = original_home { + std::env::set_var("HOME", home); + } else { + std::env::remove_var("HOME"); + } + let _ = fs::remove_dir_all(base); +} + +#[test] +fn uninstall_mastracode_errors_when_event_value_not_array() { + let _lock = integration_env_lock(); + let base = unique_base(); + let original_home = std::env::var_os("HOME"); + let mastracode_dir = base.join(".mastracode"); + fs::create_dir_all(&mastracode_dir).unwrap(); + fs::write(mastracode_dir.join("hooks.json"), r#"{"SessionStart":{}}"#).unwrap(); + std::env::set_var("HOME", &base); + + let err = uninstall_mastracode().unwrap_err().to_string(); + assert!( + err.contains("hook entries for SessionStart must be an array"), + "unexpected error: {err}" + ); + + if let Some(home) = original_home { + std::env::set_var("HOME", home); + } else { + std::env::remove_var("HOME"); + } + let _ = fs::remove_dir_all(base); +} |
