use crate::EnterpriseClient;
use serde_json::Value;
use wiremock::matchers::{method, path, path_regex};
use wiremock::{Mock, MockServer, ResponseTemplate};
pub struct MockEnterpriseServer {
server: MockServer,
}
impl MockEnterpriseServer {
pub async fn start() -> Self {
Self {
server: MockServer::start().await,
}
}
pub fn uri(&self) -> String {
self.server.uri()
}
pub fn client(&self) -> EnterpriseClient {
self.client_builder()
.build()
.expect("Failed to build test client")
}
pub fn client_builder(&self) -> crate::EnterpriseClientBuilder {
EnterpriseClient::builder()
.base_url(self.uri())
.username("test@example.com")
.password("password")
.insecure(true)
}
pub fn inner(&self) -> &MockServer {
&self.server
}
pub async fn mock_databases_list(&self, databases: Vec<Value>) {
Mock::given(method("GET"))
.and(path("/v1/bdbs"))
.respond_with(ResponseTemplate::new(200).set_body_json(databases))
.mount(&self.server)
.await;
}
pub async fn mock_database_get(&self, uid: u32, database: Value) {
Mock::given(method("GET"))
.and(path(format!("/v1/bdbs/{}", uid)))
.respond_with(ResponseTemplate::new(200).set_body_json(database))
.mount(&self.server)
.await;
}
pub async fn mock_database_create(&self, response: Value) {
Mock::given(method("POST"))
.and(path("/v1/bdbs"))
.respond_with(ResponseTemplate::new(201).set_body_json(response))
.mount(&self.server)
.await;
}
pub async fn mock_database_delete(&self, uid: u32) {
Mock::given(method("DELETE"))
.and(path(format!("/v1/bdbs/{}", uid)))
.respond_with(ResponseTemplate::new(204))
.mount(&self.server)
.await;
}
pub async fn mock_nodes_list(&self, nodes: Vec<Value>) {
Mock::given(method("GET"))
.and(path("/v1/nodes"))
.respond_with(ResponseTemplate::new(200).set_body_json(nodes))
.mount(&self.server)
.await;
}
pub async fn mock_node_get(&self, uid: u32, node: Value) {
Mock::given(method("GET"))
.and(path(format!("/v1/nodes/{}", uid)))
.respond_with(ResponseTemplate::new(200).set_body_json(node))
.mount(&self.server)
.await;
}
pub async fn mock_cluster_info(&self, cluster: Value) {
Mock::given(method("GET"))
.and(path("/v1/cluster"))
.respond_with(ResponseTemplate::new(200).set_body_json(cluster))
.mount(&self.server)
.await;
}
pub async fn mock_cluster_stats(&self, stats: Value) {
Mock::given(method("GET"))
.and(path("/v1/cluster/stats/last"))
.respond_with(ResponseTemplate::new(200).set_body_json(stats))
.mount(&self.server)
.await;
}
pub async fn mock_license(&self, license: Value) {
Mock::given(method("GET"))
.and(path("/v1/license"))
.respond_with(ResponseTemplate::new(200).set_body_json(license))
.mount(&self.server)
.await;
}
pub async fn mock_users_list(&self, users: Vec<Value>) {
Mock::given(method("GET"))
.and(path("/v1/users"))
.respond_with(ResponseTemplate::new(200).set_body_json(users))
.mount(&self.server)
.await;
}
pub async fn mock_user_get(&self, uid: u32, user: Value) {
Mock::given(method("GET"))
.and(path(format!("/v1/users/{}", uid)))
.respond_with(ResponseTemplate::new(200).set_body_json(user))
.mount(&self.server)
.await;
}
pub async fn mock_alerts_list(&self, alerts: Vec<Value>) {
Mock::given(method("GET"))
.and(path("/v1/alerts"))
.respond_with(ResponseTemplate::new(200).set_body_json(alerts))
.mount(&self.server)
.await;
}
pub async fn mock_alert_get(&self, uid: &str, alert: Value) {
Mock::given(method("GET"))
.and(path(format!("/v1/alerts/{}", uid)))
.respond_with(ResponseTemplate::new(200).set_body_json(alert))
.mount(&self.server)
.await;
}
pub async fn mock_database_alerts(&self, bdb_uid: u32, alerts: Vec<Value>) {
Mock::given(method("GET"))
.and(path(format!("/v1/bdbs/{}/alerts", bdb_uid)))
.respond_with(ResponseTemplate::new(200).set_body_json(alerts))
.mount(&self.server)
.await;
}
pub async fn mock_node_alerts(&self, node_uid: u32, alerts: Vec<Value>) {
Mock::given(method("GET"))
.and(path(format!("/v1/nodes/{}/alerts", node_uid)))
.respond_with(ResponseTemplate::new(200).set_body_json(alerts))
.mount(&self.server)
.await;
}
pub async fn mock_cluster_alerts(&self, alerts: Vec<Value>) {
Mock::given(method("GET"))
.and(path("/v1/cluster/alerts"))
.respond_with(ResponseTemplate::new(200).set_body_json(alerts))
.mount(&self.server)
.await;
}
pub async fn mock_not_found(&self, path_pattern: &str) {
Mock::given(method("GET"))
.and(path_regex(path_pattern))
.respond_with(super::responses::not_found("Resource not found"))
.mount(&self.server)
.await;
}
pub async fn mock_unauthorized(&self) {
Mock::given(method("GET"))
.respond_with(super::responses::unauthorized())
.mount(&self.server)
.await;
}
pub async fn mock_server_error(&self, path_str: &str, message: &str) {
Mock::given(method("GET"))
.and(path(path_str))
.respond_with(super::responses::server_error(message))
.mount(&self.server)
.await;
}
pub async fn mount(&self, mock: Mock) {
mock.mount(&self.server).await;
}
pub async fn mock_path(&self, http_method: &str, path_str: &str, response: ResponseTemplate) {
Mock::given(method(http_method))
.and(path(path_str))
.respond_with(response)
.mount(&self.server)
.await;
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::testing::fixtures::{AlertFixture, ClusterFixture, DatabaseFixture, NodeFixture};
#[tokio::test]
async fn test_mock_server_starts() {
let server = MockEnterpriseServer::start().await;
assert!(server.uri().starts_with("http://"));
}
#[tokio::test]
async fn test_mock_databases_list() {
let server = MockEnterpriseServer::start().await;
server
.mock_databases_list(vec![
DatabaseFixture::new(1, "test-db").build(),
DatabaseFixture::new(2, "other-db").build(),
])
.await;
let client = server.client();
let dbs = client.databases().list().await.unwrap();
assert_eq!(dbs.len(), 2);
assert_eq!(dbs[0].name, "test-db");
assert_eq!(dbs[1].name, "other-db");
}
#[tokio::test]
async fn test_mock_database_get() {
let server = MockEnterpriseServer::start().await;
server
.mock_database_get(
1,
DatabaseFixture::new(1, "my-cache")
.memory_size(2 * 1024 * 1024 * 1024)
.build(),
)
.await;
let client = server.client();
let db = client.databases().get(1).await.unwrap();
assert_eq!(db.name, "my-cache");
assert_eq!(db.memory_size, Some(2 * 1024 * 1024 * 1024));
}
#[tokio::test]
async fn test_mock_nodes_list() {
let server = MockEnterpriseServer::start().await;
server
.mock_nodes_list(vec![
NodeFixture::new(1, "10.0.0.1").build(),
NodeFixture::new(2, "10.0.0.2").cores(8).build(),
])
.await;
let client = server.client();
let nodes = client.nodes().list().await.unwrap();
assert_eq!(nodes.len(), 2);
}
#[tokio::test]
async fn test_mock_cluster_info() {
let server = MockEnterpriseServer::start().await;
server
.mock_cluster_info(
ClusterFixture::new("test-cluster")
.nodes(vec![1, 2, 3])
.build(),
)
.await;
let client = server.client();
let info = client.cluster().info().await.unwrap();
assert_eq!(info.name, "test-cluster");
}
#[tokio::test]
async fn test_custom_mock() {
use wiremock::ResponseTemplate;
use wiremock::matchers::{method, path};
let server = MockEnterpriseServer::start().await;
Mock::given(method("GET"))
.and(path("/v1/custom"))
.respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
"custom": "response"
})))
.mount(server.inner())
.await;
}
#[tokio::test]
async fn test_mock_alerts_list_with_handler() {
let server = MockEnterpriseServer::start().await;
server
.mock_alerts_list(vec![
AlertFixture::new("alert-1", "bdb_size")
.severity("WARNING")
.entity_type("bdb")
.entity_uid("1")
.build(),
AlertFixture::new("alert-2", "node_memory")
.severity("CRITICAL")
.entity_type("node")
.entity_uid("2")
.build(),
])
.await;
let client = server.client();
let alerts = client.alerts().list().await.unwrap();
assert_eq!(alerts.len(), 2);
assert_eq!(alerts[0].uid, "alert-1");
assert_eq!(alerts[0].name, "bdb_size");
assert_eq!(alerts[0].severity, "WARNING");
assert_eq!(alerts[1].uid, "alert-2");
assert_eq!(alerts[1].name, "node_memory");
assert_eq!(alerts[1].severity, "CRITICAL");
}
#[tokio::test]
async fn test_mock_database_alerts_with_handler() {
let server = MockEnterpriseServer::start().await;
server
.mock_database_alerts(
1,
vec![
AlertFixture::new("alert-db-1", "bdb_high_latency")
.severity("WARNING")
.description("Latency above threshold")
.build(),
],
)
.await;
let client = server.client();
let alerts = client.alerts().list_by_database(1).await.unwrap();
assert_eq!(alerts.len(), 1);
assert_eq!(alerts[0].name, "bdb_high_latency");
}
}