aboutsummaryrefslogtreecommitdiff
path: root/src/integration/tests.rs
diff options
context:
space:
mode:
authorWard Peeters <ward@coding-tech.com>2026-07-04 00:29:42 +0200
committerGitHub <noreply@github.com>2026-07-04 01:29:42 +0300
commitd0e333451bd794a419e96f28db925772950ea156 (patch)
tree1a6e5d3bd6ac40f8ef454058f069d30202327002 /src/integration/tests.rs
parentd5521e3d250498df4af552fff83fce3d5ef33810 (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.rs205
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);
+}