use crate::{
AzureHttpClient, Result,
ops::redis::RedisOps,
types::redis::{
ExportRDBParameters, ImportRDBParameters, RedisAccessKeys, RedisCreateRequest,
RedisForceRebootResponse, RedisListResult, RedisRebootParameters,
RedisRegenerateKeyParameters, RedisResource,
},
};
pub struct RedisClient<'a> {
ops: RedisOps<'a>,
client: &'a AzureHttpClient,
}
impl<'a> RedisClient<'a> {
pub(crate) fn new(client: &'a AzureHttpClient) -> Self {
Self {
ops: RedisOps::new(client),
client,
}
}
pub async fn list_caches(&self) -> Result<RedisListResult> {
self.ops.list_caches(self.client.subscription_id()).await
}
pub async fn list_caches_by_resource_group(
&self,
resource_group_name: &str,
) -> Result<RedisListResult> {
self.ops
.list_caches_by_resource_group(self.client.subscription_id(), resource_group_name)
.await
}
pub async fn get_cache(&self, resource_group_name: &str, name: &str) -> Result<RedisResource> {
self.ops
.get_cache(self.client.subscription_id(), resource_group_name, name)
.await
}
pub async fn create_cache(
&self,
resource_group_name: &str,
name: &str,
body: &RedisCreateRequest,
) -> Result<RedisResource> {
self.ops
.create_cache(
self.client.subscription_id(),
resource_group_name,
name,
body,
)
.await
}
pub async fn delete_cache(&self, resource_group_name: &str, name: &str) -> Result<()> {
self.ops
.delete_cache(self.client.subscription_id(), resource_group_name, name)
.await
}
pub async fn list_keys(
&self,
resource_group_name: &str,
name: &str,
) -> Result<RedisAccessKeys> {
self.ops
.list_keys(self.client.subscription_id(), resource_group_name, name)
.await
}
pub async fn regenerate_key(
&self,
resource_group_name: &str,
name: &str,
body: &RedisRegenerateKeyParameters,
) -> Result<RedisAccessKeys> {
self.ops
.regenerate_key(
self.client.subscription_id(),
resource_group_name,
name,
body,
)
.await
}
pub async fn force_reboot(
&self,
resource_group_name: &str,
name: &str,
body: &RedisRebootParameters,
) -> Result<RedisForceRebootResponse> {
self.ops
.force_reboot(
self.client.subscription_id(),
resource_group_name,
name,
body,
)
.await
}
pub async fn import_data(
&self,
resource_group_name: &str,
name: &str,
body: &ImportRDBParameters,
) -> Result<()> {
self.ops
.import_data(
self.client.subscription_id(),
resource_group_name,
name,
body,
)
.await
}
pub async fn export_data(
&self,
resource_group_name: &str,
name: &str,
body: &ExportRDBParameters,
) -> Result<()> {
self.ops
.export_data(
self.client.subscription_id(),
resource_group_name,
name,
body,
)
.await
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{
MockClient,
types::redis::{RedisCreateProperties, RedisSku},
};
const SUB_ID: &str = "test-subscription-id";
const RG: &str = "test-rg";
const CACHE: &str = "cloud-lite-test-redis";
fn make_client(mock: MockClient) -> AzureHttpClient {
AzureHttpClient::from_mock(mock)
}
fn cache_json() -> serde_json::Value {
serde_json::json!({
"id": format!("/subscriptions/{SUB_ID}/resourceGroups/{RG}/providers/Microsoft.Cache/Redis/{CACHE}"),
"name": CACHE,
"type": "Microsoft.Cache/Redis",
"location": "eastus",
"properties": {
"hostName": format!("{CACHE}.redis.cache.windows.net"),
"port": 6379,
"sslPort": 6380,
"provisioningState": "Succeeded",
"enableNonSslPort": false,
"redisVersion": "6.0",
"sku": { "name": "Basic", "family": "C", "capacity": 0 }
}
})
}
fn keys_json() -> serde_json::Value {
serde_json::json!({
"primaryKey": "primary-key-value",
"secondaryKey": "secondary-key-value"
})
}
#[tokio::test]
async fn list_caches_returns_list() {
let mut mock = MockClient::new();
mock.expect_get(&format!(
"/subscriptions/{SUB_ID}/providers/Microsoft.Cache/redis"
))
.returning_json(serde_json::json!({ "value": [cache_json()] }));
let client = make_client(mock);
let result = client
.redis()
.list_caches()
.await
.expect("list_caches failed");
assert_eq!(result.value.len(), 1);
assert_eq!(result.value[0].name.as_deref(), Some(CACHE));
}
#[tokio::test]
async fn list_caches_by_resource_group_returns_list() {
let mut mock = MockClient::new();
mock.expect_get(&format!(
"/subscriptions/{SUB_ID}/resourceGroups/{RG}/providers/Microsoft.Cache/redis"
))
.returning_json(serde_json::json!({ "value": [cache_json()] }));
let client = make_client(mock);
let result = client
.redis()
.list_caches_by_resource_group(RG)
.await
.expect("list_caches_by_resource_group failed");
assert_eq!(result.value.len(), 1);
}
#[tokio::test]
async fn get_cache_deserializes_properties() {
let mut mock = MockClient::new();
mock.expect_get(&format!(
"/subscriptions/{SUB_ID}/resourceGroups/{RG}/providers/Microsoft.Cache/redis/{CACHE}"
))
.returning_json(cache_json());
let client = make_client(mock);
let c = client
.redis()
.get_cache(RG, CACHE)
.await
.expect("get_cache failed");
assert_eq!(c.name.as_deref(), Some(CACHE));
let props = c.properties.as_ref().unwrap();
assert_eq!(props.provisioning_state.as_deref(), Some("Succeeded"));
assert_eq!(props.ssl_port, Some(6380));
assert_eq!(props.redis_version.as_deref(), Some("6.0"));
let sku = props.sku.as_ref().unwrap();
assert_eq!(sku.name, "Basic");
assert_eq!(sku.family, "C");
assert_eq!(sku.capacity, 0);
}
#[tokio::test]
async fn create_cache_sends_body() {
let mut mock = MockClient::new();
mock.expect_put(&format!(
"/subscriptions/{SUB_ID}/resourceGroups/{RG}/providers/Microsoft.Cache/redis/{CACHE}"
))
.returning_json(cache_json());
let client = make_client(mock);
let body = RedisCreateRequest {
location: "eastus".into(),
properties: RedisCreateProperties {
sku: RedisSku {
name: "Basic".into(),
family: "C".into(),
capacity: 0,
},
..Default::default()
},
..Default::default()
};
let c = client
.redis()
.create_cache(RG, CACHE, &body)
.await
.expect("create_cache failed");
assert_eq!(c.name.as_deref(), Some(CACHE));
}
#[tokio::test]
async fn delete_cache_succeeds() {
let mut mock = MockClient::new();
mock.expect_delete(&format!(
"/subscriptions/{SUB_ID}/resourceGroups/{RG}/providers/Microsoft.Cache/redis/{CACHE}"
))
.returning_json(serde_json::json!({}));
let client = make_client(mock);
client
.redis()
.delete_cache(RG, CACHE)
.await
.expect("delete_cache failed");
}
#[tokio::test]
async fn list_keys_returns_both_keys() {
let mut mock = MockClient::new();
mock.expect_post(
&format!("/subscriptions/{SUB_ID}/resourceGroups/{RG}/providers/Microsoft.Cache/redis/{CACHE}/listKeys"),
)
.returning_json(keys_json());
let client = make_client(mock);
let keys = client
.redis()
.list_keys(RG, CACHE)
.await
.expect("list_keys failed");
assert_eq!(keys.primary_key.as_deref(), Some("primary-key-value"));
assert_eq!(keys.secondary_key.as_deref(), Some("secondary-key-value"));
}
#[tokio::test]
async fn regenerate_key_returns_new_keys() {
let mut mock = MockClient::new();
mock.expect_post(
&format!("/subscriptions/{SUB_ID}/resourceGroups/{RG}/providers/Microsoft.Cache/redis/{CACHE}/regenerateKey"),
)
.returning_json(keys_json());
let client = make_client(mock);
let keys = client
.redis()
.regenerate_key(
RG,
CACHE,
&RedisRegenerateKeyParameters {
key_type: "Secondary".into(),
},
)
.await
.expect("regenerate_key failed");
assert_eq!(keys.secondary_key.as_deref(), Some("secondary-key-value"));
}
#[tokio::test]
async fn force_reboot_returns_message() {
let mut mock = MockClient::new();
mock.expect_post(
&format!("/subscriptions/{SUB_ID}/resourceGroups/{RG}/providers/Microsoft.Cache/redis/{CACHE}/forceReboot"),
)
.returning_json(serde_json::json!({
"message": "The requested reboot operation has been successfully scheduled."
}));
let client = make_client(mock);
let result = client
.redis()
.force_reboot(
RG,
CACHE,
&RedisRebootParameters {
reboot_type: "AllNodes".into(),
shard_id: None,
},
)
.await
.expect("force_reboot failed");
assert!(
result
.message
.as_deref()
.unwrap_or("")
.contains("scheduled")
);
}
}