aboutsummaryrefslogtreecommitdiff
path: root/tests/cli_wrapper.rs
diff options
context:
space:
mode:
authorEric Yue <yue1995pro@gmail.com>2026-06-15 21:50:24 +0800
committerGitHub <noreply@github.com>2026-06-15 16:50:24 +0300
commit07261e09be60ac0c145685fd11f94351cc0e5ba6 (patch)
tree771b0180c7a1560189547e6d23ef004ec1cf6d5c /tests/cli_wrapper.rs
parent08bb0768ae224c8db04bbe016b050353ce13eee7 (diff)
feat: add devin cli detection and restore support (#622)
* feat: add devin cli detection and restore support refs #606 * fix: keep devin integration session-only --------- Co-authored-by: Ogulcan Celik <ogulcancelik@gmail.com>
Diffstat (limited to 'tests/cli_wrapper.rs')
-rw-r--r--tests/cli_wrapper.rs140
1 files changed, 136 insertions, 4 deletions
diff --git a/tests/cli_wrapper.rs b/tests/cli_wrapper.rs
index 33cea043..53d91c43 100644
--- a/tests/cli_wrapper.rs
+++ b/tests/cli_wrapper.rs
@@ -544,7 +544,29 @@ fn run_copilot_hook(hook_input: &str) -> Option<serde_json::Value> {
)
}
+fn run_devin_hook(
+ action: &str,
+ hook_input: &str,
+ envs: &[(&str, &str)],
+) -> Option<serde_json::Value> {
+ run_shell_hook_with_env(
+ "src/integration/assets/devin/herdr-agent-state.sh",
+ &[action],
+ hook_input,
+ envs,
+ )
+}
+
fn run_shell_hook(asset_path: &str, args: &[&str], hook_input: &str) -> Option<serde_json::Value> {
+ run_shell_hook_with_env(asset_path, args, hook_input, &[])
+}
+
+fn run_shell_hook_with_env(
+ asset_path: &str,
+ args: &[&str],
+ hook_input: &str,
+ envs: &[(&str, &str)],
+) -> Option<serde_json::Value> {
let base = unique_test_dir();
fs::create_dir_all(&base).unwrap();
let socket_path = base.join("herdr.sock");
@@ -574,7 +596,8 @@ fn run_shell_hook(asset_path: &str, args: &[&str], hook_input: &str) -> Option<s
});
let hook_path = Path::new(env!("CARGO_MANIFEST_DIR")).join(asset_path);
- let mut child = Command::new("bash")
+ let mut command = Command::new("bash");
+ command
.arg(hook_path)
.args(args)
.env("HERDR_ENV", "1")
@@ -582,9 +605,11 @@ fn run_shell_hook(asset_path: &str, args: &[&str], hook_input: &str) -> Option<s
.env("HERDR_PANE_ID", "p_test")
.stdin(Stdio::piped())
.stdout(Stdio::piped())
- .stderr(Stdio::piped())
- .spawn()
- .unwrap();
+ .stderr(Stdio::piped());
+ for (key, value) in envs {
+ command.env(key, value);
+ }
+ let mut child = command.spawn().unwrap();
let mut stdin = child.stdin.take().unwrap();
stdin.write_all(hook_input.as_bytes()).unwrap();
drop(stdin);
@@ -696,6 +721,113 @@ fn copilot_hook_does_not_report_lifecycle_state() {
}
#[test]
+fn devin_hook_ignores_prompt_session_list_fallback() {
+ let request = run_devin_hook(
+ "session",
+ r#"{"hook_event_name":"UserPromptSubmit","prompt":"run tests"}"#,
+ &[
+ ("DEVIN_PROJECT_DIR", "/tmp/project"),
+ (
+ "HERDR_DEVIN_LIST_JSON",
+ r#"[{"id":"older-session","working_directory":"/tmp/other"},{"id":"devin-session","working_directory":"/tmp/project"}]"#,
+ ),
+ ],
+ );
+
+ assert!(request.is_none());
+}
+
+#[test]
+fn devin_hook_reports_session_id_from_stdin_without_state() {
+ let request = run_devin_hook(
+ "session",
+ r#"{"hook_event_name":"SessionStart","session_id":"devin-session","source":"startup"}"#,
+ &[("HERDR_DEVIN_LIST_JSON", r#"[{"id":"older-session"}]"#)],
+ )
+ .expect("devin session start should report session identity");
+
+ assert_eq!(request["method"], "pane.report_agent_session");
+ assert_eq!(request["params"]["agent"], "devin");
+ assert_eq!(request["params"]["agent_session_id"], "devin-session");
+ assert!(request["params"].get("state").is_none());
+}
+
+#[test]
+fn devin_hook_prefers_hook_session_id_over_list() {
+ let request = run_devin_hook(
+ "session",
+ r#"{"hook_event_name":"PreToolUse","sessionId":"fresh-session","tool_name":"exec"}"#,
+ &[
+ ("DEVIN_PROJECT_DIR", "/tmp/project"),
+ (
+ "HERDR_DEVIN_LIST_JSON",
+ r#"[{"id":"older-session","working_directory":"/tmp/project"}]"#,
+ ),
+ ],
+ )
+ .expect("devin tool hook should report session identity");
+
+ assert_eq!(request["method"], "pane.report_agent_session");
+ assert_eq!(request["params"]["agent_session_id"], "fresh-session");
+ assert!(request["params"].get("state").is_none());
+}
+
+#[test]
+fn devin_hook_reports_tool_session_from_list_without_state() {
+ let request = run_devin_hook(
+ "session",
+ r#"{"hook_event_name":"PreToolUse","tool_name":"exec"}"#,
+ &[
+ ("DEVIN_PROJECT_DIR", "/tmp/project"),
+ (
+ "HERDR_DEVIN_LIST_JSON",
+ r#"[{"id":"older-session","working_directory":"/tmp/other"},{"id":"devin-session","working_directory":"/tmp/project"}]"#,
+ ),
+ ],
+ )
+ .expect("devin tool hook should report session identity");
+
+ assert_eq!(request["method"], "pane.report_agent_session");
+ assert_eq!(request["params"]["agent"], "devin");
+ assert_eq!(request["params"]["agent_session_id"], "devin-session");
+ assert!(request["params"].get("state").is_none());
+}
+
+#[test]
+fn devin_hook_ignores_startup_session_list_fallback() {
+ let request = run_devin_hook(
+ "session",
+ r#"{"hook_event_name":"SessionStart","source":"startup"}"#,
+ &[
+ ("DEVIN_PROJECT_DIR", "/tmp/project"),
+ (
+ "HERDR_DEVIN_LIST_JSON",
+ r#"[{"id":"stale-session","working_directory":"/tmp/project"}]"#,
+ ),
+ ],
+ );
+
+ assert!(request.is_none());
+}
+
+#[test]
+fn devin_hook_ignores_non_matching_session_list_entries() {
+ let request = run_devin_hook(
+ "session",
+ r#"{"hook_event_name":"PreToolUse","tool_name":"exec"}"#,
+ &[
+ ("DEVIN_PROJECT_DIR", "/tmp/project"),
+ (
+ "HERDR_DEVIN_LIST_JSON",
+ r#"[{"id":"other-session","working_directory":"/tmp/other"}]"#,
+ ),
+ ],
+ );
+
+ assert!(request.is_none());
+}
+
+#[test]
fn pane_run_sends_one_send_input_request_with_enter_key() {
let base = unique_test_dir();
fs::create_dir_all(&base).unwrap();