mod common;
use axum::http::StatusCode;
use common::TestApp;
use skill_http::types::*;
use serde_json::json;
#[tokio::test]
async fn test_execute_tool_with_valid_request() {
let app = TestApp::new().await;
let body = json!({
"skill": "test-skill",
"tool": "echo",
"args": {
"message": "Hello, World!"
}
}).to_string();
let req = TestApp::post_request("/api/execute", &body);
let (status, resp_body) = app.request(req).await;
assert!(
status == StatusCode::OK
|| status == StatusCode::INTERNAL_SERVER_ERROR
|| status == StatusCode::NOT_FOUND
);
if status == StatusCode::OK {
let response: ExecutionResponse = TestApp::parse_json(&resp_body);
assert!(!response.id.is_empty());
assert!(!response.output.is_empty() || response.error.is_some());
}
}
#[tokio::test]
async fn test_execute_tool_missing_skill() {
let app = TestApp::new().await;
let body = json!({
"skill": "nonexistent-skill",
"tool": "some-tool",
"args": {}
}).to_string();
let req = TestApp::post_request("/api/execute", &body);
let (status, _) = app.request(req).await;
assert_eq!(status, StatusCode::NOT_FOUND);
}
#[tokio::test]
async fn test_execute_tool_missing_tool() {
let app = TestApp::new().await;
let body = json!({
"skill": "test-skill",
"tool": "nonexistent-tool",
"args": {}
}).to_string();
let req = TestApp::post_request("/api/execute", &body);
let (status, _) = app.request(req).await;
assert!(status == StatusCode::NOT_FOUND || status == StatusCode::BAD_REQUEST);
}
#[tokio::test]
async fn test_execute_tool_with_string_parameter() {
let app = TestApp::new().await;
let body = json!({
"skill": "test-skill",
"tool": "echo",
"args": {
"message": "test message"
}
}).to_string();
let req = TestApp::post_request("/api/execute", &body);
let (status, _) = app.request(req).await;
assert!(
status == StatusCode::OK
|| status == StatusCode::INTERNAL_SERVER_ERROR
|| status == StatusCode::NOT_FOUND
);
}
#[tokio::test]
async fn test_execute_tool_with_number_parameters() {
let app = TestApp::new().await;
let body = json!({
"skill": "test-skill",
"tool": "add",
"args": {
"a": 5,
"b": 10
}
}).to_string();
let req = TestApp::post_request("/api/execute", &body);
let (status, _) = app.request(req).await;
assert!(
status == StatusCode::OK
|| status == StatusCode::INTERNAL_SERVER_ERROR
|| status == StatusCode::NOT_FOUND
);
}
#[tokio::test]
async fn test_execute_tool_with_boolean_parameter() {
let app = TestApp::new().await;
let body = json!({
"skill": "test-skill",
"tool": "list",
"args": {
"enabled": true
}
}).to_string();
let req = TestApp::post_request("/api/execute", &body);
let (status, _) = app.request(req).await;
assert!(
status == StatusCode::OK
|| status == StatusCode::INTERNAL_SERVER_ERROR
|| status == StatusCode::NOT_FOUND
|| status == StatusCode::BAD_REQUEST
);
}
#[tokio::test]
async fn test_execute_tool_with_json_object_parameter() {
let app = TestApp::new().await;
let body = json!({
"skill": "test-skill",
"tool": "configure",
"args": {
"config": {
"timeout": 30,
"retries": 3,
"verbose": true
}
}
}).to_string();
let req = TestApp::post_request("/api/execute", &body);
let (status, _) = app.request(req).await;
assert!(
status == StatusCode::OK
|| status == StatusCode::INTERNAL_SERVER_ERROR
|| status == StatusCode::NOT_FOUND
|| status == StatusCode::BAD_REQUEST
);
}
#[tokio::test]
async fn test_execute_tool_with_json_array_parameter() {
let app = TestApp::new().await;
let body = json!({
"skill": "test-skill",
"tool": "batch",
"args": {
"items": ["item1", "item2", "item3"]
}
}).to_string();
let req = TestApp::post_request("/api/execute", &body);
let (status, _) = app.request(req).await;
assert!(
status == StatusCode::OK
|| status == StatusCode::INTERNAL_SERVER_ERROR
|| status == StatusCode::NOT_FOUND
|| status == StatusCode::BAD_REQUEST
);
}
#[tokio::test]
async fn test_execute_tool_invalid_json() {
let app = TestApp::new().await;
let body = r#"{ invalid json }"#;
let req = TestApp::post_request("/api/execute", body);
let (status, _) = app.request(req).await;
assert_eq!(status, StatusCode::BAD_REQUEST);
}
#[tokio::test]
async fn test_execute_tool_missing_required_field() {
let app = TestApp::new().await;
let body = json!({
"skill": "test-skill"
}).to_string();
let req = TestApp::post_request("/api/execute", &body);
let (status, _) = app.request(req).await;
assert!(status == StatusCode::BAD_REQUEST || status == StatusCode::UNPROCESSABLE_ENTITY);
}
#[tokio::test]
async fn test_execute_tool_with_instance() {
let app = TestApp::new().await;
let body = json!({
"skill": "test-skill",
"tool": "echo",
"instance": "default",
"args": {
"message": "test"
}
}).to_string();
let req = TestApp::post_request("/api/execute", &body);
let (status, _) = app.request(req).await;
assert!(
status == StatusCode::OK
|| status == StatusCode::INTERNAL_SERVER_ERROR
|| status == StatusCode::NOT_FOUND
);
}
#[tokio::test]
async fn test_list_execution_history_empty() {
let app = TestApp::new().await;
let req = TestApp::get_request("/api/executions");
let (status, body) = app.request(req).await;
assert_eq!(status, StatusCode::OK);
let response: PaginatedResponse<ExecutionHistoryEntry> = TestApp::parse_json(&body);
assert!(response.items.len() >= 0);
}
#[tokio::test]
async fn test_list_execution_history_pagination() {
let app = TestApp::new().await;
let req = TestApp::get_request("/api/executions?page=1&per_page=10");
let (status, body) = app.request(req).await;
assert_eq!(status, StatusCode::OK);
let response: PaginatedResponse<ExecutionHistoryEntry> = TestApp::parse_json(&body);
assert_eq!(response.page, 1);
assert_eq!(response.per_page, 10);
}
#[tokio::test]
async fn test_get_execution_by_id_nonexistent() {
let app = TestApp::new().await;
let req = TestApp::get_request("/api/executions/nonexistent-id");
let (status, _) = app.request(req).await;
assert_eq!(status, StatusCode::NOT_FOUND);
}
#[tokio::test]
async fn test_execution_response_has_required_fields() {
let app = TestApp::new().await;
let body = json!({
"skill": "test-skill",
"tool": "echo",
"args": {
"message": "test"
}
}).to_string();
let req = TestApp::post_request("/api/execute", &body);
let (status, resp_body) = app.request(req).await;
if status == StatusCode::OK {
let response: ExecutionResponse = TestApp::parse_json(&resp_body);
assert!(!response.id.is_empty());
assert!(response.duration_ms >= 0);
assert!(matches!(
response.status,
ExecutionStatus::Success
| ExecutionStatus::Failed
| ExecutionStatus::Running
| ExecutionStatus::Pending
| ExecutionStatus::Timeout
| ExecutionStatus::Cancelled
));
}
}
#[tokio::test]
async fn test_concurrent_executions() {
let app = TestApp::new().await;
let mut handles = vec![];
for i in 0..5 {
let app_clone = TestApp::new().await;
let handle = tokio::spawn(async move {
let body = json!({
"skill": "test-skill",
"tool": "echo",
"args": {
"message": format!("concurrent test {}", i)
}
}).to_string();
let req = TestApp::post_request("/api/execute", &body);
app_clone.request(req).await
});
handles.push(handle);
}
let results: Vec<_> = futures::future::join_all(handles).await;
for result in results {
assert!(result.is_ok());
let (status, _) = result.unwrap();
assert!(
status == StatusCode::OK
|| status == StatusCode::INTERNAL_SERVER_ERROR
|| status == StatusCode::NOT_FOUND
);
}
}
#[tokio::test]
async fn test_execute_with_invalid_parameter_type() {
let app = TestApp::new().await;
let body = json!({
"skill": "test-skill",
"tool": "add",
"args": {
"a": "not_a_number", "b": 10
}
}).to_string();
let req = TestApp::post_request("/api/execute", &body);
let (status, _) = app.request(req).await;
assert!(
status == StatusCode::OK
|| status == StatusCode::BAD_REQUEST
|| status == StatusCode::INTERNAL_SERVER_ERROR
|| status == StatusCode::NOT_FOUND
);
}
#[tokio::test]
async fn test_execute_empty_args() {
let app = TestApp::new().await;
let body = json!({
"skill": "test-skill",
"tool": "list",
"args": {}
}).to_string();
let req = TestApp::post_request("/api/execute", &body);
let (status, _) = app.request(req).await;
assert!(
status == StatusCode::OK
|| status == StatusCode::BAD_REQUEST
|| status == StatusCode::INTERNAL_SERVER_ERROR
|| status == StatusCode::NOT_FOUND
);
}
#[tokio::test]
async fn test_execute_null_args() {
let app = TestApp::new().await;
let body = json!({
"skill": "test-skill",
"tool": "list"
}).to_string();
let req = TestApp::post_request("/api/execute", &body);
let (status, _) = app.request(req).await;
assert!(
status == StatusCode::OK
|| status == StatusCode::INTERNAL_SERVER_ERROR
|| status == StatusCode::NOT_FOUND
);
}