use api_tests::*;
use reqwest::StatusCode;
use serde_json::json;
#[tokio::test]
async fn test_health_endpoint() -> TestResult {
let client = build_test_client();
let response = wiremock::MockServer::start().await;
let health_url = format!("{}/health", response.uri());
wiremock::Mock::given(wiremock::matchers::method("GET"))
.and(wiremock::matchers::path("/health"))
.respond_with(wiremock::ResponseTemplate::new(200).set_body_json(json!({
"status": "healthy",
"version": "0.1.0",
"uptime_seconds": 123
})))
.mount(&response)
.await;
let res = client.get(&health_url).send().await?;
assert_eq!(res.status(), StatusCode::OK);
let body: serde_json::Value = res.json().await?;
assert_eq!(body["status"], "healthy");
Ok(())
}
#[tokio::test]
async fn test_ready_endpoint() -> TestResult {
let client = build_test_client();
let mock_server = wiremock::MockServer::start().await;
wiremock::Mock::given(wiremock::matchers::method("GET"))
.and(wiremock::matchers::path("/ready"))
.respond_with(wiremock::ResponseTemplate::new(200).set_body_json(json!({
"ready": true,
"checks": [
{
"name": "database",
"ready": true,
"message": null
}
]
})))
.mount(&mock_server)
.await;
let ready_url = format!("{}/ready", mock_server.uri());
let res = client.get(&ready_url).send().await?;
assert_eq!(res.status(), StatusCode::OK);
let body: serde_json::Value = res.json().await?;
assert_eq!(body["ready"], true);
Ok(())
}
#[tokio::test]
async fn test_metrics_endpoint() -> TestResult {
let client = build_test_client();
let mock_server = wiremock::MockServer::start().await;
wiremock::Mock::given(wiremock::matchers::method("GET"))
.and(wiremock::matchers::path("/metrics"))
.respond_with(
wiremock::ResponseTemplate::new(200)
.insert_header("content-type", "text/plain; version=0.0.4")
.set_body_string("# HELP requests_total Total requests\n# TYPE requests_total counter\nrequests_total 100\n")
)
.mount(&mock_server)
.await;
let metrics_url = format!("{}/metrics", mock_server.uri());
let res = client.get(&metrics_url).send().await?;
assert_eq!(res.status(), StatusCode::OK);
let content_type = res.headers().get("content-type").unwrap().to_str()?;
assert!(content_type.contains("text/plain"));
let body = res.text().await?;
assert!(body.contains("requests_total"));
Ok(())
}
#[tokio::test]
async fn test_create_resource_endpoint() -> TestResult {
let client = build_test_client();
let mock_server = wiremock::MockServer::start().await;
let create_body = json!({
"name": "test_resource",
"config": {
"model": "claude-3-sonnet",
"temperature": 0.7
}
});
wiremock::Mock::given(wiremock::matchers::method("POST"))
.and(wiremock::matchers::path("/api/v1/resources"))
.and(wiremock::matchers::body_json(&create_body))
.respond_with(wiremock::ResponseTemplate::new(201).set_body_json(json!({
"id": "res_123",
"name": "test_resource",
"created_at": "2025-11-10T00:00:00Z"
})))
.mount(&mock_server)
.await;
let url = format!("{}/api/v1/resources", mock_server.uri());
let res = client.post(&url).json(&create_body).send().await?;
assert_eq!(res.status(), StatusCode::CREATED);
let body: serde_json::Value = res.json().await?;
assert_eq!(body["id"], "res_123");
assert_eq!(body["name"], "test_resource");
Ok(())
}
#[tokio::test]
async fn test_get_resource_endpoint() -> TestResult {
let client = build_test_client();
let mock_server = wiremock::MockServer::start().await;
wiremock::Mock::given(wiremock::matchers::method("GET"))
.and(wiremock::matchers::path("/api/v1/resources/res_123"))
.respond_with(wiremock::ResponseTemplate::new(200).set_body_json(json!({
"id": "res_123",
"name": "test_resource",
"status": "active"
})))
.mount(&mock_server)
.await;
let url = format!("{}/api/v1/resources/res_123", mock_server.uri());
let res = client.get(&url).send().await?;
assert_eq!(res.status(), StatusCode::OK);
let body: serde_json::Value = res.json().await?;
assert_eq!(body["id"], "res_123");
Ok(())
}
#[tokio::test]
async fn test_list_resources_with_pagination() -> TestResult {
let client = build_test_client();
let mock_server = wiremock::MockServer::start().await;
wiremock::Mock::given(wiremock::matchers::method("GET"))
.and(wiremock::matchers::path("/api/v1/resources"))
.and(wiremock::matchers::query_param("page", "1"))
.and(wiremock::matchers::query_param("per_page", "10"))
.respond_with(wiremock::ResponseTemplate::new(200).set_body_json(json!({
"data": [
{"id": "res_1", "name": "Resource 1"},
{"id": "res_2", "name": "Resource 2"}
],
"pagination": {
"page": 1,
"per_page": 10,
"total": 2,
"total_pages": 1
}
})))
.mount(&mock_server)
.await;
let url = format!("{}/api/v1/resources?page=1&per_page=10", mock_server.uri());
let res = client.get(&url).send().await?;
assert_eq!(res.status(), StatusCode::OK);
let body: serde_json::Value = res.json().await?;
assert_eq!(body["pagination"]["page"], 1);
assert_eq!(body["data"].as_array().unwrap().len(), 2);
Ok(())
}
#[tokio::test]
async fn test_update_resource_endpoint() -> TestResult {
let client = build_test_client();
let mock_server = wiremock::MockServer::start().await;
let update_body = json!({
"name": "updated_resource"
});
wiremock::Mock::given(wiremock::matchers::method("PUT"))
.and(wiremock::matchers::path("/api/v1/resources/res_123"))
.respond_with(wiremock::ResponseTemplate::new(200).set_body_json(json!({
"id": "res_123",
"name": "updated_resource",
"updated_at": "2025-11-10T00:00:00Z"
})))
.mount(&mock_server)
.await;
let url = format!("{}/api/v1/resources/res_123", mock_server.uri());
let res = client.put(&url).json(&update_body).send().await?;
assert_eq!(res.status(), StatusCode::OK);
Ok(())
}
#[tokio::test]
async fn test_delete_resource_endpoint() -> TestResult {
let client = build_test_client();
let mock_server = wiremock::MockServer::start().await;
wiremock::Mock::given(wiremock::matchers::method("DELETE"))
.and(wiremock::matchers::path("/api/v1/resources/res_123"))
.respond_with(wiremock::ResponseTemplate::new(204))
.mount(&mock_server)
.await;
let url = format!("{}/api/v1/resources/res_123", mock_server.uri());
let res = client.delete(&url).send().await?;
assert_eq!(res.status(), StatusCode::NO_CONTENT);
Ok(())
}
#[tokio::test]
async fn test_404_not_found() -> TestResult {
let client = build_test_client();
let mock_server = wiremock::MockServer::start().await;
wiremock::Mock::given(wiremock::matchers::method("GET"))
.and(wiremock::matchers::path("/api/v1/resources/nonexistent"))
.respond_with(wiremock::ResponseTemplate::new(404).set_body_json(json!({
"error": "Resource not found",
"code": "RESOURCE_NOT_FOUND"
})))
.mount(&mock_server)
.await;
let url = format!("{}/api/v1/resources/nonexistent", mock_server.uri());
let res = client.get(&url).send().await?;
assert_eq!(res.status(), StatusCode::NOT_FOUND);
let body: serde_json::Value = res.json().await?;
assert_eq!(body["code"], "RESOURCE_NOT_FOUND");
Ok(())
}
#[tokio::test]
async fn test_400_bad_request() -> TestResult {
let client = build_test_client();
let mock_server = wiremock::MockServer::start().await;
let invalid_body = json!({
"invalid_field": "value"
});
wiremock::Mock::given(wiremock::matchers::method("POST"))
.and(wiremock::matchers::path("/api/v1/resources"))
.respond_with(wiremock::ResponseTemplate::new(400).set_body_json(json!({
"error": "Validation failed",
"code": "VALIDATION_ERROR",
"details": ["name is required"]
})))
.mount(&mock_server)
.await;
let url = format!("{}/api/v1/resources", mock_server.uri());
let res = client.post(&url).json(&invalid_body).send().await?;
assert_eq!(res.status(), StatusCode::BAD_REQUEST);
Ok(())
}
#[tokio::test]
async fn test_500_internal_server_error() -> TestResult {
let client = build_test_client();
let mock_server = wiremock::MockServer::start().await;
wiremock::Mock::given(wiremock::matchers::method("GET"))
.and(wiremock::matchers::path("/api/v1/error"))
.respond_with(wiremock::ResponseTemplate::new(500).set_body_json(json!({
"error": "Internal server error",
"code": "INTERNAL_ERROR"
})))
.mount(&mock_server)
.await;
let url = format!("{}/api/v1/error", mock_server.uri());
let res = client.get(&url).send().await?;
assert_eq!(res.status(), StatusCode::INTERNAL_SERVER_ERROR);
Ok(())
}