use hooks::{HookEvent, HookManager, HookResult}; use std::fs; use tempfile::tempdir; #[tokio::test] async fn pretooluse_can_deny_call() { let dir = tempdir().unwrap(); let hooks_dir = dir.path().join(".owlen/hooks"); fs::create_dir_all(&hooks_dir).unwrap(); // Create a PreToolUse hook that denies Write operations let hook_script = r#"#!/bin/bash INPUT=$(cat) TOOL=$(echo "$INPUT" | grep -o '"tool":"[^"]*"' | cut -d'"' -f4) if [ "$TOOL" = "Write" ]; then exit 2 # Deny fi exit 0 # Allow "#; let hook_path = hooks_dir.join("PreToolUse"); fs::write(&hook_path, hook_script).unwrap(); fs::set_permissions(&hook_path, std::os::unix::fs::PermissionsExt::from_mode(0o755)).unwrap(); let manager = HookManager::new(dir.path().to_str().unwrap()); // Test Write tool (should be denied) let write_event = HookEvent::PreToolUse { tool: "Write".to_string(), args: serde_json::json!({"path": "/tmp/test.txt", "content": "hello"}), }; let result = manager.execute(&write_event, Some(5000)).await.unwrap(); assert_eq!(result, HookResult::Deny); // Test Read tool (should be allowed) let read_event = HookEvent::PreToolUse { tool: "Read".to_string(), args: serde_json::json!({"path": "/tmp/test.txt"}), }; let result = manager.execute(&read_event, Some(5000)).await.unwrap(); assert_eq!(result, HookResult::Allow); } #[tokio::test] async fn posttooluse_runs_parallel() { let dir = tempdir().unwrap(); let hooks_dir = dir.path().join(".owlen/hooks"); fs::create_dir_all(&hooks_dir).unwrap(); let output_file = dir.path().join("hook_output.txt"); // Create a PostToolUse hook that writes to a file let hook_script = format!( r#"#!/bin/bash INPUT=$(cat) echo "Hook executed: $INPUT" >> {} exit 0 "#, output_file.display() ); let hook_path = hooks_dir.join("PostToolUse"); fs::write(&hook_path, hook_script).unwrap(); fs::set_permissions(&hook_path, std::os::unix::fs::PermissionsExt::from_mode(0o755)).unwrap(); let manager = HookManager::new(dir.path().to_str().unwrap()); // Execute hook let event = HookEvent::PostToolUse { tool: "Read".to_string(), result: serde_json::json!({"success": true}), }; let result = manager.execute(&event, Some(5000)).await.unwrap(); assert_eq!(result, HookResult::Allow); // Verify hook ran let output = fs::read_to_string(&output_file).unwrap(); assert!(output.contains("Hook executed")); } #[tokio::test] async fn sessionstart_persists_env() { let dir = tempdir().unwrap(); let hooks_dir = dir.path().join(".owlen/hooks"); fs::create_dir_all(&hooks_dir).unwrap(); let env_file = dir.path().join(".owlen/session.env"); // Create a SessionStart hook that writes env vars to a file let hook_script = format!( r#"#!/bin/bash cat > {} <