#![cfg(feature = "tower-integration")]
use redis_cloud::CloudClient;
use redis_cloud::tower_support::{ApiRequest, Method};
use serde_json::json;
use tower::{Service, ServiceExt};
use wiremock::matchers::{header, method, path};
use wiremock::{Mock, MockServer, ResponseTemplate};
#[tokio::test]
async fn test_tower_service_get_request() {
let mock_server = MockServer::start().await;
Mock::given(method("GET"))
.and(path("/subscriptions"))
.and(header("x-api-key", "test-key"))
.and(header("x-api-secret-key", "test-secret"))
.respond_with(ResponseTemplate::new(200).set_body_json(json!({
"subscriptions": []
})))
.mount(&mock_server)
.await;
let client = CloudClient::builder()
.api_key("test-key")
.api_secret("test-secret")
.base_url(mock_server.uri())
.build()
.expect("Failed to create client");
let mut service = client.into_service();
let request = ApiRequest::get("/subscriptions");
let response = service
.ready()
.await
.expect("Service not ready")
.call(request)
.await
.expect("Request failed");
assert_eq!(response.status, 200);
assert!(response.body["subscriptions"].is_array());
}
#[tokio::test]
async fn test_tower_service_post_request() {
let mock_server = MockServer::start().await;
let request_body = json!({
"name": "test-subscription",
"cloudProviderId": 1
});
Mock::given(method("POST"))
.and(path("/subscriptions"))
.and(header("x-api-key", "test-key"))
.and(header("x-api-secret-key", "test-secret"))
.respond_with(ResponseTemplate::new(200).set_body_json(json!({
"taskId": "12345",
"commandType": "subscriptionCreateRequest",
"status": "processing-in-progress"
})))
.mount(&mock_server)
.await;
let client = CloudClient::builder()
.api_key("test-key")
.api_secret("test-secret")
.base_url(mock_server.uri())
.build()
.expect("Failed to create client");
let mut service = client.into_service();
let request = ApiRequest::post("/subscriptions", request_body);
let response = service
.ready()
.await
.expect("Service not ready")
.call(request)
.await
.expect("Request failed");
assert_eq!(response.status, 200);
assert_eq!(response.body["taskId"], "12345");
assert_eq!(response.body["status"], "processing-in-progress");
}
#[tokio::test]
async fn test_tower_service_put_request() {
let mock_server = MockServer::start().await;
let request_body = json!({
"name": "updated-name"
});
Mock::given(method("PUT"))
.and(path("/subscriptions/123"))
.and(header("x-api-key", "test-key"))
.and(header("x-api-secret-key", "test-secret"))
.respond_with(ResponseTemplate::new(200).set_body_json(json!({
"taskId": "67890",
"status": "processing-in-progress"
})))
.mount(&mock_server)
.await;
let client = CloudClient::builder()
.api_key("test-key")
.api_secret("test-secret")
.base_url(mock_server.uri())
.build()
.expect("Failed to create client");
let mut service = client.into_service();
let request = ApiRequest::put("/subscriptions/123", request_body);
let response = service
.ready()
.await
.expect("Service not ready")
.call(request)
.await
.expect("Request failed");
assert_eq!(response.status, 200);
assert_eq!(response.body["taskId"], "67890");
}
#[tokio::test]
async fn test_tower_service_patch_request() {
let mock_server = MockServer::start().await;
let request_body = json!({
"memory_limit_in_gb": 10.0
});
Mock::given(method("PATCH"))
.and(path("/subscriptions/123/databases/456"))
.and(header("x-api-key", "test-key"))
.and(header("x-api-secret-key", "test-secret"))
.respond_with(ResponseTemplate::new(200).set_body_json(json!({
"taskId": "patch-123",
"status": "processing-in-progress"
})))
.mount(&mock_server)
.await;
let client = CloudClient::builder()
.api_key("test-key")
.api_secret("test-secret")
.base_url(mock_server.uri())
.build()
.expect("Failed to create client");
let mut service = client.into_service();
let request = ApiRequest::patch("/subscriptions/123/databases/456", request_body);
let response = service
.ready()
.await
.expect("Service not ready")
.call(request)
.await
.expect("Request failed");
assert_eq!(response.status, 200);
assert_eq!(response.body["taskId"], "patch-123");
}
#[tokio::test]
async fn test_tower_service_delete_request() {
let mock_server = MockServer::start().await;
Mock::given(method("DELETE"))
.and(path("/subscriptions/123"))
.and(header("x-api-key", "test-key"))
.and(header("x-api-secret-key", "test-secret"))
.respond_with(ResponseTemplate::new(200).set_body_json(json!({
"taskId": "delete-123",
"status": "processing-in-progress"
})))
.mount(&mock_server)
.await;
let client = CloudClient::builder()
.api_key("test-key")
.api_secret("test-secret")
.base_url(mock_server.uri())
.build()
.expect("Failed to create client");
let mut service = client.into_service();
let request = ApiRequest::delete("/subscriptions/123");
let response = service
.ready()
.await
.expect("Service not ready")
.call(request)
.await
.expect("Request failed");
assert_eq!(response.status, 200);
assert_eq!(response.body["taskId"], "delete-123");
}
#[tokio::test]
async fn test_tower_service_oneshot() {
let mock_server = MockServer::start().await;
Mock::given(method("GET"))
.and(path("/account"))
.and(header("x-api-key", "test-key"))
.and(header("x-api-secret-key", "test-secret"))
.respond_with(ResponseTemplate::new(200).set_body_json(json!({
"id": 12345,
"name": "Test Account"
})))
.mount(&mock_server)
.await;
let client = CloudClient::builder()
.api_key("test-key")
.api_secret("test-secret")
.base_url(mock_server.uri())
.build()
.expect("Failed to create client");
let service = client.into_service();
let request = ApiRequest::get("/account");
let response = service
.oneshot(request)
.await
.expect("Oneshot request failed");
assert_eq!(response.status, 200);
assert_eq!(response.body["id"], 12345);
assert_eq!(response.body["name"], "Test Account");
}
#[tokio::test]
async fn test_tower_service_multiple_requests() {
let mock_server = MockServer::start().await;
Mock::given(method("GET"))
.and(path("/subscriptions"))
.respond_with(ResponseTemplate::new(200).set_body_json(json!({
"subscriptions": []
})))
.mount(&mock_server)
.await;
Mock::given(method("GET"))
.and(path("/account"))
.respond_with(ResponseTemplate::new(200).set_body_json(json!({
"id": 1
})))
.mount(&mock_server)
.await;
let client = CloudClient::builder()
.api_key("test-key")
.api_secret("test-secret")
.base_url(mock_server.uri())
.build()
.expect("Failed to create client");
let mut service = client.into_service();
let response1 = service
.ready()
.await
.expect("Service not ready")
.call(ApiRequest::get("/subscriptions"))
.await
.expect("First request failed");
assert_eq!(response1.status, 200);
let response2 = service
.ready()
.await
.expect("Service not ready")
.call(ApiRequest::get("/account"))
.await
.expect("Second request failed");
assert_eq!(response2.status, 200);
}
#[tokio::test]
async fn test_tower_service_error_handling() {
let mock_server = MockServer::start().await;
Mock::given(method("GET"))
.and(path("/subscriptions/999"))
.respond_with(ResponseTemplate::new(404).set_body_json(json!({
"error": {
"type": "SUBSCRIPTION_NOT_FOUND",
"status": "404 NOT_FOUND",
"description": "Subscription not found"
}
})))
.mount(&mock_server)
.await;
let client = CloudClient::builder()
.api_key("test-key")
.api_secret("test-secret")
.base_url(mock_server.uri())
.build()
.expect("Failed to create client");
let mut service = client.into_service();
let request = ApiRequest::get("/subscriptions/999");
let result = service
.ready()
.await
.expect("Service not ready")
.call(request)
.await;
assert!(result.is_err());
}
#[tokio::test]
async fn test_api_request_method_constructors() {
let get_req = ApiRequest::get("/test");
assert_eq!(get_req.method, Method::Get);
assert_eq!(get_req.path, "/test");
assert!(get_req.body.is_none());
let post_req = ApiRequest::post("/test", json!({"key": "value"}));
assert_eq!(post_req.method, Method::Post);
assert_eq!(post_req.path, "/test");
assert!(post_req.body.is_some());
let put_req = ApiRequest::put("/test", json!({"key": "value"}));
assert_eq!(put_req.method, Method::Put);
assert!(put_req.body.is_some());
let patch_req = ApiRequest::patch("/test", json!({"key": "value"}));
assert_eq!(patch_req.method, Method::Patch);
assert!(patch_req.body.is_some());
let delete_req = ApiRequest::delete("/test");
assert_eq!(delete_req.method, Method::Delete);
assert!(delete_req.body.is_none());
}
#[tokio::test]
async fn test_tower_service_post_without_body_fails() {
let mock_server = MockServer::start().await;
let client = CloudClient::builder()
.api_key("test-key")
.api_secret("test-secret")
.base_url(mock_server.uri())
.build()
.expect("Failed to create client");
let mut service = client.into_service();
let request = ApiRequest {
method: Method::Post,
path: "/subscriptions".to_string(),
body: None,
};
let result = service
.ready()
.await
.expect("Service not ready")
.call(request)
.await;
assert!(result.is_err());
let error = result.unwrap_err();
assert!(error.to_string().contains("body"));
}