use redis_enterprise::{EnterpriseClient, StatsHandler, StatsQuery};
use serde_json::json;
use wiremock::matchers::{basic_auth, method, path, query_param};
use wiremock::{Mock, MockServer, ResponseTemplate};
fn success_response(body: serde_json::Value) -> ResponseTemplate {
ResponseTemplate::new(200).set_body_json(body)
}
fn error_response(code: u16, message: &str) -> ResponseTemplate {
ResponseTemplate::new(code).set_body_json(json!({
"error": message,
"code": code
}))
}
fn test_cluster_stats() -> serde_json::Value {
json!({
"intervals": [
{
"time": "2023-01-01T12:00:00Z",
"metrics": {
"cpu_usage": 25.5,
"memory_usage": 75.2,
"network_in": 1024000,
"network_out": 2048000,
"total_req": 150000,
"active_databases": 5
}
},
{
"time": "2023-01-01T12:01:00Z",
"metrics": {
"cpu_usage": 27.1,
"memory_usage": 76.8,
"network_in": 1100000,
"network_out": 2200000,
"total_req": 155000,
"active_databases": 5
}
}
]
})
}
fn test_node_stats() -> serde_json::Value {
json!({
"intervals": [
{
"time": "2023-01-01T12:00:00Z",
"metrics": {
"cpu_user": 15.5,
"cpu_system": 5.2,
"cpu_idle": 79.3,
"free_memory": 4294967296u64,
"network_bytes_in": 512000,
"network_bytes_out": 1024000
}
}
]
})
}
fn test_database_stats() -> serde_json::Value {
json!({
"intervals": [
{
"time": "2023-01-01T12:00:00Z",
"metrics": {
"used_memory": 1048576,
"total_req": 5000,
"ops_per_sec": 100.5,
"hits": 4500,
"misses": 500,
"evicted_objects": 0
}
}
]
})
}
fn test_shard_stats() -> serde_json::Value {
json!({
"intervals": [
{
"stime": "2023-01-01T12:00:00Z",
"etime": "2023-01-01T12:01:00Z",
"interval": "1min",
"used_memory": 524288,
"total_req": 2500,
"ops_per_sec": 50.0,
"keyspace_hits": 2250,
"keyspace_misses": 250
}
]
})
}
fn test_cluster_last_stats() -> serde_json::Value {
json!({
"stime": "2023-01-01T12:00:00Z",
"etime": "2023-01-01T12:02:00Z",
"interval": "2m",
"cpu_usage": 28.3,
"memory_usage": 77.5,
"network_in": 1150000,
"network_out": 2300000,
"total_req": 158000
})
}
fn test_node_last_stats() -> serde_json::Value {
json!({
"stime": "2023-01-01T12:00:00Z",
"etime": "2023-01-01T12:02:00Z",
"interval": "2m",
"cpu_user": 16.2,
"cpu_system": 5.8,
"cpu_idle": 78.0,
"free_memory": 4194304000u64,
"network_bytes_in": 520000,
"network_bytes_out": 1040000
})
}
fn test_database_last_stats() -> serde_json::Value {
json!({
"stime": "2023-01-01T12:00:00Z",
"etime": "2023-01-01T12:02:00Z",
"interval": "2m",
"used_memory": 1100000,
"total_req": 5200,
"ops_per_sec": 105.2,
"hits": 4680,
"misses": 520
})
}
fn test_shards_last_stats() -> serde_json::Value {
json!({
"1": {
"used_memory": 524288,
"ops_per_sec": 50.0
},
"2": {
"used_memory": 262144,
"ops_per_sec": 25.0
}
})
}
#[tokio::test]
async fn test_stats_cluster() {
let mock_server = MockServer::start().await;
Mock::given(method("GET"))
.and(path("/v1/cluster/stats"))
.and(basic_auth("admin", "password"))
.respond_with(success_response(test_cluster_stats()))
.mount(&mock_server)
.await;
let client = EnterpriseClient::builder()
.base_url(mock_server.uri())
.username("admin")
.password("password")
.build()
.unwrap();
let handler = StatsHandler::new(client);
let result = handler.cluster(None).await;
assert!(result.is_ok());
let stats = result.unwrap();
assert_eq!(stats.intervals.len(), 2);
assert_eq!(stats.intervals[0].time, "2023-01-01T12:00:00Z");
assert_eq!(stats.intervals[0].metrics["cpu_usage"], 25.5);
}
#[tokio::test]
async fn test_stats_cluster_with_query() {
let mock_server = MockServer::start().await;
Mock::given(method("GET"))
.and(path("/v1/cluster/stats"))
.and(query_param("interval", "5min"))
.and(query_param("metrics", "cpu_usage,memory_usage"))
.and(basic_auth("admin", "password"))
.respond_with(success_response(test_cluster_stats()))
.mount(&mock_server)
.await;
let client = EnterpriseClient::builder()
.base_url(mock_server.uri())
.username("admin")
.password("password")
.build()
.unwrap();
let handler = StatsHandler::new(client);
let query = StatsQuery {
interval: Some("5min".to_string()),
stime: None,
etime: None,
metrics: Some("cpu_usage,memory_usage".to_string()),
};
let result = handler.cluster(Some(query)).await;
assert!(result.is_ok());
let stats = result.unwrap();
assert_eq!(stats.intervals.len(), 2);
}
#[tokio::test]
async fn test_stats_cluster_last() {
let mock_server = MockServer::start().await;
Mock::given(method("GET"))
.and(path("/v1/cluster/stats/last"))
.and(basic_auth("admin", "password"))
.respond_with(success_response(test_cluster_last_stats()))
.mount(&mock_server)
.await;
let client = EnterpriseClient::builder()
.base_url(mock_server.uri())
.username("admin")
.password("password")
.build()
.unwrap();
let handler = StatsHandler::new(client);
let stats = handler.cluster_last().await.unwrap();
assert_eq!(stats.metrics["cpu_usage"], 28.3);
assert_eq!(stats.metrics["memory_usage"], 77.5);
}
#[tokio::test]
async fn test_stats_node() {
let mock_server = MockServer::start().await;
Mock::given(method("GET"))
.and(path("/v1/nodes/stats/1"))
.and(basic_auth("admin", "password"))
.respond_with(success_response(test_node_stats()))
.mount(&mock_server)
.await;
let client = EnterpriseClient::builder()
.base_url(mock_server.uri())
.username("admin")
.password("password")
.build()
.unwrap();
let handler = StatsHandler::new(client);
let result = handler.node(1, None).await;
assert!(result.is_ok());
let stats = result.unwrap();
assert_eq!(stats.intervals.len(), 1);
assert_eq!(stats.intervals[0].time, "2023-01-01T12:00:00Z");
assert_eq!(stats.intervals[0].metrics["cpu_user"], 15.5);
}
#[tokio::test]
async fn test_stats_node_with_query() {
let mock_server = MockServer::start().await;
Mock::given(method("GET"))
.and(path("/v1/nodes/stats/1"))
.and(query_param("interval", "1hour"))
.and(query_param("stime", "2023-01-01T10:00:00Z"))
.and(query_param("etime", "2023-01-01T14:00:00Z"))
.and(basic_auth("admin", "password"))
.respond_with(success_response(test_node_stats()))
.mount(&mock_server)
.await;
let client = EnterpriseClient::builder()
.base_url(mock_server.uri())
.username("admin")
.password("password")
.build()
.unwrap();
let handler = StatsHandler::new(client);
let query = StatsQuery {
interval: Some("1hour".to_string()),
stime: Some("2023-01-01T10:00:00Z".to_string()),
etime: Some("2023-01-01T14:00:00Z".to_string()),
metrics: None,
};
let result = handler.node(1, Some(query)).await;
assert!(result.is_ok());
let stats = result.unwrap();
assert_eq!(stats.intervals.len(), 1);
}
#[tokio::test]
async fn test_stats_node_nonexistent() {
let mock_server = MockServer::start().await;
Mock::given(method("GET"))
.and(path("/v1/nodes/stats/999"))
.and(basic_auth("admin", "password"))
.respond_with(error_response(404, "Node not found"))
.mount(&mock_server)
.await;
let client = EnterpriseClient::builder()
.base_url(mock_server.uri())
.username("admin")
.password("password")
.build()
.unwrap();
let handler = StatsHandler::new(client);
let result = handler.node(999, None).await;
assert!(result.is_err());
}
#[tokio::test]
async fn test_stats_node_last() {
let mock_server = MockServer::start().await;
Mock::given(method("GET"))
.and(path("/v1/nodes/stats/last/1"))
.and(basic_auth("admin", "password"))
.respond_with(success_response(test_node_last_stats()))
.mount(&mock_server)
.await;
let client = EnterpriseClient::builder()
.base_url(mock_server.uri())
.username("admin")
.password("password")
.build()
.unwrap();
let handler = StatsHandler::new(client);
let stats = handler.node_last(1).await.unwrap();
assert_eq!(stats.metrics["cpu_user"], 16.2);
assert_eq!(stats.metrics["free_memory"], 4194304000u64);
}
#[tokio::test]
async fn test_stats_node_last_nonexistent() {
let mock_server = MockServer::start().await;
Mock::given(method("GET"))
.and(path("/v1/nodes/stats/last/999"))
.and(basic_auth("admin", "password"))
.respond_with(error_response(404, "Node not found"))
.mount(&mock_server)
.await;
let client = EnterpriseClient::builder()
.base_url(mock_server.uri())
.username("admin")
.password("password")
.build()
.unwrap();
let handler = StatsHandler::new(client);
let result = handler.node_last(999).await;
assert!(result.is_err());
}
#[tokio::test]
async fn test_stats_nodes() {
let mock_server = MockServer::start().await;
Mock::given(method("GET"))
.and(path("/v1/nodes/stats"))
.and(basic_auth("admin", "password"))
.respond_with(success_response(json!({
"stats": [
{"uid": 1, "intervals": []},
{"uid": 2, "intervals": []}
]
})))
.mount(&mock_server)
.await;
let client = EnterpriseClient::builder()
.base_url(mock_server.uri())
.username("admin")
.password("password")
.build()
.unwrap();
let handler = StatsHandler::new(client);
let stats = handler.nodes(None).await.unwrap();
assert_eq!(stats.stats.len(), 2);
assert_eq!(stats.stats[0].uid, 1);
assert_eq!(stats.stats[1].uid, 2);
}
#[tokio::test]
async fn test_stats_nodes_with_query() {
let mock_server = MockServer::start().await;
Mock::given(method("GET"))
.and(path("/v1/nodes/stats"))
.and(query_param("interval", "1min"))
.and(basic_auth("admin", "password"))
.respond_with(success_response(json!({"stats": []})))
.mount(&mock_server)
.await;
let client = EnterpriseClient::builder()
.base_url(mock_server.uri())
.username("admin")
.password("password")
.build()
.unwrap();
let handler = StatsHandler::new(client);
let query = StatsQuery {
interval: Some("1min".to_string()),
stime: None,
etime: None,
metrics: None,
};
let stats = handler.nodes(Some(query)).await.unwrap();
assert!(stats.stats.is_empty());
}
#[tokio::test]
async fn test_stats_database() {
let mock_server = MockServer::start().await;
Mock::given(method("GET"))
.and(path("/v1/bdbs/stats/1"))
.and(basic_auth("admin", "password"))
.respond_with(success_response(test_database_stats()))
.mount(&mock_server)
.await;
let client = EnterpriseClient::builder()
.base_url(mock_server.uri())
.username("admin")
.password("password")
.build()
.unwrap();
let handler = StatsHandler::new(client);
let result = handler.database(1, None).await;
assert!(result.is_ok());
let stats = result.unwrap();
assert_eq!(stats.intervals.len(), 1);
assert_eq!(stats.intervals[0].metrics["used_memory"], 1048576);
assert_eq!(stats.intervals[0].metrics["ops_per_sec"], 100.5);
}
#[tokio::test]
async fn test_stats_database_nonexistent() {
let mock_server = MockServer::start().await;
Mock::given(method("GET"))
.and(path("/v1/bdbs/stats/999"))
.and(basic_auth("admin", "password"))
.respond_with(error_response(404, "Database not found"))
.mount(&mock_server)
.await;
let client = EnterpriseClient::builder()
.base_url(mock_server.uri())
.username("admin")
.password("password")
.build()
.unwrap();
let handler = StatsHandler::new(client);
let result = handler.database(999, None).await;
assert!(result.is_err());
}
#[tokio::test]
async fn test_stats_database_last() {
let mock_server = MockServer::start().await;
Mock::given(method("GET"))
.and(path("/v1/bdbs/stats/last/1"))
.and(basic_auth("admin", "password"))
.respond_with(success_response(test_database_last_stats()))
.mount(&mock_server)
.await;
let client = EnterpriseClient::builder()
.base_url(mock_server.uri())
.username("admin")
.password("password")
.build()
.unwrap();
let handler = StatsHandler::new(client);
let stats = handler.database_last(1).await.unwrap();
assert_eq!(stats.metrics["used_memory"], 1100000);
assert_eq!(stats.metrics["ops_per_sec"], 105.2);
}
#[tokio::test]
async fn test_stats_databases() {
let mock_server = MockServer::start().await;
Mock::given(method("GET"))
.and(path("/v1/bdbs/stats"))
.and(basic_auth("admin", "password"))
.respond_with(success_response(json!({
"stats": [
{"uid": 1, "intervals": []},
{"uid": 2, "intervals": []}
]
})))
.mount(&mock_server)
.await;
let client = EnterpriseClient::builder()
.base_url(mock_server.uri())
.username("admin")
.password("password")
.build()
.unwrap();
let handler = StatsHandler::new(client);
let stats = handler.databases(None).await.unwrap();
assert_eq!(stats.stats.len(), 2);
assert_eq!(stats.stats[0].uid, 1);
assert_eq!(stats.stats[1].uid, 2);
}
#[tokio::test]
async fn test_stats_shard() {
let mock_server = MockServer::start().await;
Mock::given(method("GET"))
.and(path("/v1/shards/stats/1"))
.and(basic_auth("admin", "password"))
.respond_with(success_response(test_shard_stats()))
.mount(&mock_server)
.await;
let client = EnterpriseClient::builder()
.base_url(mock_server.uri())
.username("admin")
.password("password")
.build()
.unwrap();
let handler = StatsHandler::new(client);
let result = handler.shard(1, None).await;
assert!(result.is_ok());
let stats = result.unwrap();
assert_eq!(stats.intervals.len(), 1);
assert_eq!(stats.intervals[0].metrics["used_memory"], 524288);
assert_eq!(stats.intervals[0].metrics["ops_per_sec"], 50.0);
}
#[tokio::test]
async fn test_stats_shard_nonexistent() {
let mock_server = MockServer::start().await;
Mock::given(method("GET"))
.and(path("/v1/shards/stats/999"))
.and(basic_auth("admin", "password"))
.respond_with(error_response(404, "Shard not found"))
.mount(&mock_server)
.await;
let client = EnterpriseClient::builder()
.base_url(mock_server.uri())
.username("admin")
.password("password")
.build()
.unwrap();
let handler = StatsHandler::new(client);
let result = handler.shard(999, None).await;
assert!(result.is_err());
}
#[tokio::test]
async fn test_stats_shards() {
let mock_server = MockServer::start().await;
Mock::given(method("GET"))
.and(path("/v1/shards/stats"))
.and(basic_auth("admin", "password"))
.respond_with(success_response(json!([
{"uid": 1, "intervals": []},
{"uid": 2, "intervals": []}
])))
.mount(&mock_server)
.await;
let client = EnterpriseClient::builder()
.base_url(mock_server.uri())
.username("admin")
.password("password")
.build()
.unwrap();
let handler = StatsHandler::new(client);
let result = handler.shards(None).await;
assert!(result.is_ok());
let stats = result.unwrap();
assert_eq!(stats.stats.len(), 2);
assert_eq!(stats.stats[0].uid, 1);
assert_eq!(stats.stats[1].uid, 2);
}
#[tokio::test]
async fn test_stats_shards_last() {
let mock_server = MockServer::start().await;
Mock::given(method("GET"))
.and(path("/v1/shards/stats/last"))
.and(basic_auth("admin", "password"))
.respond_with(success_response(test_shards_last_stats()))
.mount(&mock_server)
.await;
let client = EnterpriseClient::builder()
.base_url(mock_server.uri())
.username("admin")
.password("password")
.build()
.unwrap();
let handler = StatsHandler::new(client);
let stats = handler.shards_last().await.unwrap();
assert_eq!(stats["1"]["ops_per_sec"], 50.0);
assert_eq!(stats["2"]["used_memory"], 262144);
}
#[tokio::test]
async fn test_stats_shard_last() {
let mock_server = MockServer::start().await;
Mock::given(method("GET"))
.and(path("/v1/shards/stats/last/1"))
.and(basic_auth("admin", "password"))
.respond_with(success_response(json!({
"1": {
"used_memory": 524288,
"ops_per_sec": 50.0
}
})))
.mount(&mock_server)
.await;
let client = EnterpriseClient::builder()
.base_url(mock_server.uri())
.username("admin")
.password("password")
.build()
.unwrap();
let handler = StatsHandler::new(client);
let stats = handler.shard_last(1).await.unwrap();
assert_eq!(stats["1"]["used_memory"], 524288);
assert_eq!(stats["1"]["ops_per_sec"], 50.0);
}