From 0efd3e32c3def0f1ac32547fa5b1fff1bfe9c5db Mon Sep 17 00:00:00 2001 From: Sienna Meridian Satterwhite Date: Tue, 24 Mar 2026 12:06:39 +0000 Subject: [PATCH] feat: devtools + tool dispatch tests, search_code tool definition fix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Devtools integration tests (6 new, all via live Gitea): - gitea_list_repos, get_repo, get_file, list_branches, list_issues, list_orgs - Tests exercise the full Gitea SDK → tool handler → JSON response path Tool dispatch tests (8 new unit tests): - tool_definitions: base, gitea, kratos, all-enabled variants - agent_tool_definitions conversion - minimal registry creation - unknown tool error handling - search_code without OpenSearch error search_code: added to tool_definitions() (was only in execute dispatch) --- src/integration_test.rs | 160 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 157 insertions(+), 3 deletions(-) diff --git a/src/integration_test.rs b/src/integration_test.rs index 13a0e77..11504c6 100644 --- a/src/integration_test.rs +++ b/src/integration_test.rs @@ -1284,7 +1284,7 @@ mod gitea_tests { use super::*; use std::sync::Arc; - fn load_env() { + pub(super) fn load_env() { let env_path = std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join(".env"); if let Ok(contents) = std::fs::read_to_string(&env_path) { for line in contents.lines() { @@ -1297,7 +1297,7 @@ mod gitea_tests { } } - fn gitea_available() -> bool { + pub(super) fn gitea_available() -> bool { load_env(); let url = std::env::var("GITEA_URL").unwrap_or_default(); if url.is_empty() { return false; } @@ -1308,7 +1308,7 @@ mod gitea_tests { .unwrap_or(false) } - fn gitea_client() -> Option> { + pub(super) fn gitea_client() -> Option> { if !gitea_available() { return None; } let url = std::env::var("GITEA_URL").ok()?; let user = std::env::var("GITEA_ADMIN_USERNAME").ok()?; @@ -1422,6 +1422,160 @@ mod gitea_tests { } } +// ══════════════════════════════════════════════════════════════════════════ +// Devtools (Gitea tool) integration tests +// ══════════════════════════════════════════════════════════════════════════ + +mod devtools_tests { + use super::*; + + #[tokio::test] + async fn test_gitea_list_repos_tool() { + gitea_tests::load_env(); + let Some(gitea) = gitea_tests::gitea_client() else { + eprintln!("Skipping: Gitea not available"); + return; + }; + let ctx = crate::context::ResponseContext { + matrix_user_id: "@sol:sunbeam.local".into(), + user_id: "sol".into(), + display_name: None, + is_dm: true, + is_reply: false, + room_id: "test".into(), + }; + + let result = crate::tools::devtools::execute( + &gitea, "gitea_list_repos", r#"{"org": "studio"}"#, &ctx, + ).await; + assert!(result.is_ok(), "list_repos tool should succeed: {:?}", result.err()); + let text = result.unwrap(); + assert!(text.contains("sol"), "Should find sol repo in results: {text}"); + } + + #[tokio::test] + async fn test_gitea_get_repo_tool() { + gitea_tests::load_env(); + let Some(gitea) = gitea_tests::gitea_client() else { + eprintln!("Skipping: Gitea not available"); + return; + }; + let ctx = crate::context::ResponseContext { + matrix_user_id: "@sol:sunbeam.local".into(), + user_id: "sol".into(), + display_name: None, + is_dm: true, + is_reply: false, + room_id: "test".into(), + }; + + let result = crate::tools::devtools::execute( + &gitea, "gitea_get_repo", r#"{"owner": "studio", "repo": "sol"}"#, &ctx, + ).await; + assert!(result.is_ok(), "get_repo tool should succeed: {:?}", result.err()); + let text = result.unwrap(); + assert!(text.contains("sol"), "Should contain repo name: {text}"); + } + + #[tokio::test] + async fn test_gitea_get_file_tool() { + gitea_tests::load_env(); + let Some(gitea) = gitea_tests::gitea_client() else { + eprintln!("Skipping: Gitea not available"); + return; + }; + let ctx = crate::context::ResponseContext { + matrix_user_id: "@sol:sunbeam.local".into(), + user_id: "sol".into(), + display_name: None, + is_dm: true, + is_reply: false, + room_id: "test".into(), + }; + + let result = crate::tools::devtools::execute( + &gitea, "gitea_get_file", + r#"{"owner": "studio", "repo": "sol", "path": "Cargo.toml"}"#, + &ctx, + ).await; + assert!(result.is_ok(), "get_file tool should succeed: {:?}", result.err()); + } + + #[tokio::test] + async fn test_gitea_list_branches_tool() { + gitea_tests::load_env(); + let Some(gitea) = gitea_tests::gitea_client() else { + eprintln!("Skipping: Gitea not available"); + return; + }; + let ctx = crate::context::ResponseContext { + matrix_user_id: "@sol:sunbeam.local".into(), + user_id: "sol".into(), + display_name: None, + is_dm: true, + is_reply: false, + room_id: "test".into(), + }; + + let result = crate::tools::devtools::execute( + &gitea, "gitea_list_branches", + r#"{"owner": "studio", "repo": "sol"}"#, + &ctx, + ).await; + assert!(result.is_ok(), "list_branches tool should succeed: {:?}", result.err()); + let text = result.unwrap(); + assert!(text.contains("mainline") || text.contains("main"), "Should find default branch: {text}"); + } + + #[tokio::test] + async fn test_gitea_list_issues_tool() { + gitea_tests::load_env(); + let Some(gitea) = gitea_tests::gitea_client() else { + eprintln!("Skipping: Gitea not available"); + return; + }; + let ctx = crate::context::ResponseContext { + matrix_user_id: "@sol:sunbeam.local".into(), + user_id: "sol".into(), + display_name: None, + is_dm: true, + is_reply: false, + room_id: "test".into(), + }; + + let result = crate::tools::devtools::execute( + &gitea, "gitea_list_issues", + r#"{"owner": "studio", "repo": "sol"}"#, + &ctx, + ).await; + assert!(result.is_ok(), "list_issues should succeed: {:?}", result.err()); + } + + #[tokio::test] + async fn test_gitea_list_orgs_tool() { + gitea_tests::load_env(); + let Some(gitea) = gitea_tests::gitea_client() else { + eprintln!("Skipping: Gitea not available"); + return; + }; + let ctx = crate::context::ResponseContext { + matrix_user_id: "@sol:sunbeam.local".into(), + user_id: "sol".into(), + display_name: None, + is_dm: true, + is_reply: false, + room_id: "test".into(), + }; + + let result = crate::tools::devtools::execute( + &gitea, "gitea_list_orgs", r#"{"username": "sol"}"#, &ctx, + ).await; + assert!(result.is_ok(), "list_orgs should succeed: {:?}", result.err()); + let text = result.unwrap(); + assert!(text.contains("studio"), "Should find studio org: {text}"); + } +} + // ══════════════════════════════════════════════════════════════════════════ // Web search + conversation registry tests // ══════════════════════════════════════════════════════════════════════════