fix(tests): cover hook event dispatch paths
This commit is contained in:
committed by
Hunter Bown
parent
0428f08625
commit
fd5a0aaec5
@@ -168,3 +168,129 @@ impl HookDispatcher {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use std::sync::Mutex;
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
|
||||
#[test]
|
||||
fn hook_event_serializes_with_snake_case_type_and_payload() {
|
||||
let event = HookEvent::ToolLifecycle {
|
||||
response_id: "resp-1".to_string(),
|
||||
tool_name: "shell".to_string(),
|
||||
phase: "end".to_string(),
|
||||
payload: json!({ "exit_code": 0 }),
|
||||
};
|
||||
|
||||
let encoded = event.to_json();
|
||||
|
||||
assert_eq!(encoded["type"], "tool_lifecycle");
|
||||
assert_eq!(encoded["response_id"], "resp-1");
|
||||
assert_eq!(encoded["tool_name"], "shell");
|
||||
assert_eq!(encoded["phase"], "end");
|
||||
assert_eq!(encoded["payload"]["exit_code"], 0);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn jsonl_sink_creates_parent_dir_and_appends_events() {
|
||||
let root = unique_temp_dir("jsonl_sink");
|
||||
let path = root.join("nested").join("hooks.jsonl");
|
||||
let sink = JsonlHookSink::new(path.clone());
|
||||
|
||||
sink.emit(&HookEvent::ResponseStart {
|
||||
response_id: "resp-1".to_string(),
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
sink.emit(&HookEvent::ResponseEnd {
|
||||
response_id: "resp-1".to_string(),
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let raw = std::fs::read_to_string(&path).unwrap();
|
||||
let lines = raw.lines().collect::<Vec<_>>();
|
||||
assert_eq!(lines.len(), 2);
|
||||
|
||||
let first: Value = serde_json::from_str(lines[0]).unwrap();
|
||||
let second: Value = serde_json::from_str(lines[1]).unwrap();
|
||||
assert!(first["at"].as_str().is_some());
|
||||
assert_eq!(first["event"]["type"], "response_start");
|
||||
assert_eq!(first["event"]["response_id"], "resp-1");
|
||||
assert_eq!(second["event"]["type"], "response_end");
|
||||
assert_eq!(second["event"]["response_id"], "resp-1");
|
||||
|
||||
let _ = std::fs::remove_dir_all(root);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn dispatcher_continues_after_sink_error() {
|
||||
let mut dispatcher = HookDispatcher::default();
|
||||
let first = Arc::new(RecordingSink::default());
|
||||
let second = Arc::new(RecordingSink::default());
|
||||
|
||||
dispatcher.add_sink(first.clone());
|
||||
dispatcher.add_sink(Arc::new(FailingSink));
|
||||
dispatcher.add_sink(second.clone());
|
||||
|
||||
dispatcher
|
||||
.emit(HookEvent::ApprovalLifecycle {
|
||||
approval_id: "approval-1".to_string(),
|
||||
phase: "requested".to_string(),
|
||||
reason: Some("needs review".to_string()),
|
||||
})
|
||||
.await;
|
||||
|
||||
assert_eq!(
|
||||
first.events(),
|
||||
vec![json!({
|
||||
"type": "approval_lifecycle",
|
||||
"approval_id": "approval-1",
|
||||
"phase": "requested",
|
||||
"reason": "needs review",
|
||||
})]
|
||||
);
|
||||
assert_eq!(second.events(), first.events());
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct RecordingSink {
|
||||
events: Mutex<Vec<Value>>,
|
||||
}
|
||||
|
||||
impl RecordingSink {
|
||||
fn events(&self) -> Vec<Value> {
|
||||
self.events.lock().unwrap().clone()
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl HookSink for RecordingSink {
|
||||
async fn emit(&self, event: &HookEvent) -> Result<()> {
|
||||
self.events.lock().unwrap().push(event.to_json());
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
struct FailingSink;
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl HookSink for FailingSink {
|
||||
async fn emit(&self, _event: &HookEvent) -> Result<()> {
|
||||
anyhow::bail!("sink failed")
|
||||
}
|
||||
}
|
||||
|
||||
fn unique_temp_dir(label: &str) -> PathBuf {
|
||||
let nanos = SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.unwrap()
|
||||
.as_nanos();
|
||||
std::env::temp_dir().join(format!(
|
||||
"deepseek-hooks-{label}-{}-{nanos}",
|
||||
std::process::id()
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user