添加qiming-rcoder模块

This commit is contained in:
Codex
2026-06-01 13:54:52 +08:00
parent 8092c4b1f8
commit 4b1a580132
539 changed files with 151650 additions and 0 deletions

View File

@@ -0,0 +1,126 @@
//! 测试用阻塞注入
//!
//! 用于模拟极端场景 (Agent 阻塞、超时等)
use std::sync::Arc;
use std::time::Duration;
/// 阻塞配置
#[derive(Debug, Clone)]
pub struct BlockingConfig {
/// 是否阻塞 new_session
pub block_new_session: bool,
/// 是否阻塞 prompt
pub block_prompt: bool,
/// 阻塞持续时间
pub block_duration: Duration,
}
impl Default for BlockingConfig {
fn default() -> Self {
Self {
block_new_session: false,
block_prompt: false,
block_duration: Duration::from_secs(30),
}
}
}
/// 全局阻塞配置 (线程安全)
pub static BLOCKING_CONFIG: std::sync::LazyLock<Arc<std::sync::RwLock<BlockingConfig>>> =
std::sync::LazyLock::new(|| Arc::new(std::sync::RwLock::new(BlockingConfig::default())));
/// 注入阻塞 (用于测试)
///
/// # Example
///
/// ```rust
/// use agent_runner::testing::blocking::{BlockingConfig, inject_blocking};
/// use std::time::Duration;
///
/// // 注入 30 秒阻塞
/// inject_blocking(BlockingConfig {
/// block_prompt: true,
/// block_duration: Duration::from_secs(30),
/// ..Default::default()
/// });
/// ```
pub fn inject_blocking(config: BlockingConfig) {
tracing::warn!("🧪 [TEST] Blocking config updated: {:?}", config);
let mut global = BLOCKING_CONFIG.write().unwrap();
*global = config;
}
/// 检查并执行阻塞 (在 agent_worker_with_heartbeat 中调用)
///
/// # Arguments
///
/// * `blocking_type` - 阻塞类型: "new_session" 或 "prompt"
///
/// # Example
///
/// ```rust
/// # use agent_runner::testing::blocking::maybe_block;
/// # async fn test() {
/// // 在 agent_worker_with_heartbeat 中调用
/// maybe_block("prompt").await;
/// # }
/// ```
pub async fn maybe_block(blocking_type: &str) {
let config = BLOCKING_CONFIG.read().unwrap();
let should_block = match blocking_type {
"new_session" => config.block_new_session,
"prompt" => config.block_prompt,
_ => false,
};
if should_block {
tracing::warn!(
"🧪 [TEST] Injected blocking: {}, duration: {:?}",
blocking_type,
config.block_duration
);
tokio::time::sleep(config.block_duration).await;
}
}
/// 重置阻塞配置 (用于测试清理)
pub fn reset_blocking() {
inject_blocking(BlockingConfig::default());
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_blocking_config_default() {
let config = BlockingConfig::default();
assert!(!config.block_new_session);
assert!(!config.block_prompt);
assert_eq!(config.block_duration, Duration::from_secs(30));
}
#[test]
fn test_inject_and_reset_blocking() {
// 注入配置
inject_blocking(BlockingConfig {
block_prompt: true,
block_duration: Duration::from_secs(10),
..Default::default()
});
let config = BLOCKING_CONFIG.read().unwrap();
assert!(config.block_prompt);
assert_eq!(config.block_duration, Duration::from_secs(10));
// 重置配置
drop(config);
reset_blocking();
let config = BLOCKING_CONFIG.read().unwrap();
assert!(!config.block_prompt);
assert_eq!(config.block_duration, Duration::from_secs(30));
}
}

View File

@@ -0,0 +1,226 @@
//! 测试 Fixtures
//!
//! 提供测试用的构造器和辅助工具
use crate::proxy_agent::AgentRequest;
use agent_abstraction::PromptMessage;
use shared_types::{Attachment, ServiceType};
use std::path::PathBuf;
/// 测试请求构造器
///
/// # Example
///
/// ```rust
/// use agent_runner::testing::fixtures::TestRequestBuilder;
///
/// // 创建基础测试请求
/// let (req, resp_rx) = TestRequestBuilder::new()
/// .project_id("test-project")
/// .content("Hello, Agent!")
/// .build();
/// ```
pub struct TestRequestBuilder {
project_id: String,
content: String,
request_id: String,
attachments: Vec<Attachment>,
session_id: Option<String>,
project_path: Option<PathBuf>,
}
impl Default for TestRequestBuilder {
fn default() -> Self {
Self::new()
}
}
impl TestRequestBuilder {
/// 创建新的测试请求构造器
pub fn new() -> Self {
Self {
project_id: "test-project".to_string(),
content: "Hello, Agent!".to_string(),
request_id: uuid::Uuid::new_v4().to_string().replace("-", ""),
attachments: vec![],
session_id: None,
project_path: None,
}
}
/// 设置 project_id
pub fn project_id(mut self, id: &str) -> Self {
self.project_id = id.to_string();
self
}
/// 设置请求内容
pub fn content(mut self, content: &str) -> Self {
self.content = content.to_string();
self
}
/// 设置 request_id
pub fn request_id(mut self, request_id: &str) -> Self {
self.request_id = request_id.to_string();
self
}
/// 设置 session_id
pub fn session_id(mut self, session_id: &str) -> Self {
self.session_id = Some(session_id.to_string());
self
}
/// 设置项目路径
pub fn project_path(mut self, path: &str) -> Self {
self.project_path = Some(PathBuf::from(path));
self
}
/// 添加附件
pub fn add_attachment(mut self, attachment: Attachment) -> Self {
self.attachments.push(attachment);
self
}
/// 构建 PromptMessage用于测试验证
///
/// 返回构建的 PromptMessage可以直接访问字段进行断言验证
pub fn build_prompt_message(&self) -> PromptMessage {
PromptMessage {
content: self.content.clone(),
project_id: self.project_id.clone(),
project_path: self
.project_path
.clone()
.unwrap_or_else(|| PathBuf::from("/tmp/test")),
session_id: self.session_id.clone(),
request_id: self.request_id.clone(),
attachments: self.attachments.clone(),
data_source_attachments: vec![],
service_type: ServiceType::RCoder,
system_prompt_override: None,
user_prompt_template_override: None,
agent_config_override: None,
}
}
/// 构建测试请求
pub fn build(
self,
) -> (
AgentRequest,
tokio::sync::oneshot::Receiver<crate::model::ChatPromptResponse>,
) {
let prompt_message = self.build_prompt_message();
AgentRequest::new(prompt_message, None)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_test_request_builder_default() {
let builder = TestRequestBuilder::new();
let prompt = builder.build_prompt_message();
// 验证默认值
assert_eq!(prompt.project_id, "test-project");
assert_eq!(prompt.content, "Hello, Agent!");
assert!(!prompt.request_id.is_empty(), "request_id 应该自动生成");
assert_eq!(prompt.project_path, PathBuf::from("/tmp/test"));
assert!(prompt.session_id.is_none());
assert!(prompt.attachments.is_empty());
assert_eq!(prompt.service_type, ServiceType::RCoder);
}
#[test]
fn test_test_request_builder_with_project_id() {
let prompt = TestRequestBuilder::new()
.project_id("custom-project")
.build_prompt_message();
assert_eq!(prompt.project_id, "custom-project");
}
#[test]
fn test_test_request_builder_with_content() {
let prompt = TestRequestBuilder::new()
.content("Custom content")
.build_prompt_message();
assert_eq!(prompt.content, "Custom content");
}
#[test]
fn test_test_request_builder_with_session_id() {
let prompt = TestRequestBuilder::new()
.session_id("test-session-123")
.build_prompt_message();
assert_eq!(prompt.session_id, Some("test-session-123".to_string()));
}
#[test]
fn test_test_request_builder_with_request_id() {
let prompt = TestRequestBuilder::new()
.request_id("custom-request-id")
.build_prompt_message();
assert_eq!(prompt.request_id, "custom-request-id");
}
#[test]
fn test_test_request_builder_with_project_path() {
let prompt = TestRequestBuilder::new()
.project_path("/home/user/project")
.build_prompt_message();
assert_eq!(prompt.project_path, PathBuf::from("/home/user/project"));
}
#[test]
fn test_test_request_builder_chain() {
// 验证链式调用和所有字段设置
let prompt = TestRequestBuilder::new()
.project_id("my-project")
.content("Test content")
.request_id("custom-request-id")
.session_id("session-456")
.project_path("/home/user/project")
.build_prompt_message();
assert_eq!(prompt.project_id, "my-project");
assert_eq!(prompt.content, "Test content");
assert_eq!(prompt.request_id, "custom-request-id");
assert_eq!(prompt.session_id, Some("session-456".to_string()));
assert_eq!(prompt.project_path, PathBuf::from("/home/user/project"));
}
#[test]
fn test_test_request_builder_build_returns_receiver() {
// 验证 build() 返回的接收器可用
let (_req, mut rx) = TestRequestBuilder::new().build();
// 验证接收器尚未收到消息
assert!(rx.try_recv().is_err(), "接收器应该为空");
}
#[test]
fn test_test_request_builder_request_id_auto_generated() {
// 验证每次构建生成不同的 request_id
let builder1 = TestRequestBuilder::new();
let builder2 = TestRequestBuilder::new();
let prompt1 = builder1.build_prompt_message();
let prompt2 = builder2.build_prompt_message();
assert_ne!(
prompt1.request_id, prompt2.request_id,
"每次构建应该生成不同的 request_id"
);
}
}

View File

@@ -0,0 +1,14 @@
//! 测试辅助模块
//!
//! 仅在 `testing` feature 启用时编译
// 阻塞注入模块 (用于极端场景测试)
#[cfg(feature = "test-blocking")]
pub mod blocking;
#[cfg(feature = "test-blocking")]
pub use blocking::{BlockingConfig, inject_blocking};
// 测试 Fixtures (通用测试辅助工具)
pub mod fixtures;
pub use fixtures::TestRequestBuilder;