Skip to content

Commit 45b184c

Browse files
Merge pull request #376 from joshrotenberg/feat/api-coverage-high-priority-375
feat: High Priority API Coverage Improvements (Issue #375)
2 parents 1cde8c0 + 7ff400f commit 45b184c

File tree

6 files changed

+132
-47
lines changed

6 files changed

+132
-47
lines changed

CLAUDE.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -428,13 +428,42 @@ Examples:
428428
- BDB creation: Use `/v2/bdbs` for async operations
429429
- Actions: Use `/v2/actions` for listing and status
430430
431+
### Active-Active (CRDB) Pattern
432+
433+
Redis Cloud has separate functions for Active-Active (CRDB) operations to ensure type safety:
434+
435+
#### When to Use Active-Active Functions
436+
Active-Active databases (Conflict-free Replicated Databases) require special handling for multi-region deployments. The `_active_active` suffix indicates functions designed specifically for these databases.
437+
438+
**Key Active-Active Operations:**
439+
- VPC Peering: `create_active_active()`, `get_active_active()`, `update_active_active()`, `delete_active_active()`
440+
- PSC: `create_service_active_active()`, `create_endpoint_active_active()`, etc.
441+
- Transit Gateway: `create_attachment_active_active()`, `get_attachments_active_active()`, etc.
442+
443+
**Why Separate Functions?**
444+
1. **Different request structures** - AA operations often require region-specific parameters
445+
2. **Type safety** - Prevents accidentally calling regular endpoints with AA-specific data
446+
3. **Clear API surface** - Explicit function names make intent clear
447+
448+
**Example:**
449+
```rust
450+
// Regular database VPC peering
451+
let vpc = handler.create(subscription_id, &request).await?;
452+
453+
// Active-Active database VPC peering (requires region specification)
454+
let vpc = handler.create_active_active(subscription_id, region_id, &request).await?;
455+
```
456+
457+
**Note:** Despite having separate functions, these map to the same API endpoints. The separation is for developer ergonomics and type safety.
458+
431459
### Common Code Patterns
432460
- **Client creation**: Use `create_cloud_client()` or `create_enterprise_client()` helpers
433461
- **Error context**: Always add `.context()` to errors for debugging
434462
- **Output handling**: Use `print_output()` helper for consistent formatting
435463
- **Async operations**: Use `handle_async_response()` for task-based operations
436464
- **Parameter grouping**: Create params struct when >7 parameters needed
437465
- **Testing**: Mock all HTTP calls with `wiremock`, never make real API calls in tests
466+
- **Active-Active**: Use `_active_active` suffixed functions for CRDB operations
438467
439468
## Testing Approach
440469

crates/redis-cloud/src/cloud_accounts.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,14 @@ pub struct CloudAccount {
121121
#[serde(skip_serializing_if = "Option::is_none")]
122122
pub access_secret_key: Option<String>,
123123

124+
/// AWS Console Role ARN (AWS-specific)
125+
#[serde(skip_serializing_if = "Option::is_none")]
126+
pub aws_console_role_arn: Option<String>,
127+
128+
/// AWS User ARN (AWS-specific)
129+
#[serde(skip_serializing_if = "Option::is_none")]
130+
pub aws_user_arn: Option<String>,
131+
124132
/// Cloud provider management console username
125133
#[serde(skip_serializing_if = "Option::is_none")]
126134
pub console_username: Option<String>,

crates/redis-cloud/src/fixed/databases.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1044,8 +1044,13 @@ impl FixedDatabaseHandler {
10441044
// ========================================================================
10451045
// Backward compatibility wrapper methods
10461046
// ========================================================================
1047+
// NOTE: These methods are deprecated in favor of the shorter, more idiomatic names.
1048+
// They will be removed in a future version.
10471049

10481050
/// Create fixed database (backward compatibility)
1051+
///
1052+
/// **Deprecated**: Use [`create`](Self::create) instead
1053+
#[deprecated(since = "0.8.0", note = "Use `create` instead")]
10491054
pub async fn create_fixed_database(
10501055
&self,
10511056
subscription_id: i32,
@@ -1055,6 +1060,9 @@ impl FixedDatabaseHandler {
10551060
}
10561061

10571062
/// Get fixed database (backward compatibility)
1063+
///
1064+
/// **Deprecated**: Use [`get_by_id`](Self::get_by_id) instead
1065+
#[deprecated(since = "0.8.0", note = "Use `get_by_id` instead")]
10581066
pub async fn get_fixed_database(
10591067
&self,
10601068
subscription_id: i32,
@@ -1066,6 +1074,9 @@ impl FixedDatabaseHandler {
10661074
}
10671075

10681076
/// Update fixed database (backward compatibility)
1077+
///
1078+
/// **Deprecated**: Use [`update`](Self::update) instead
1079+
#[deprecated(since = "0.8.0", note = "Use `update` instead")]
10691080
pub async fn update_fixed_database(
10701081
&self,
10711082
subscription_id: i32,
@@ -1076,6 +1087,9 @@ impl FixedDatabaseHandler {
10761087
}
10771088

10781089
/// Delete fixed database (backward compatibility)
1090+
///
1091+
/// **Deprecated**: Use [`delete_by_id`](Self::delete_by_id) instead
1092+
#[deprecated(since = "0.8.0", note = "Use `delete_by_id` instead")]
10791093
pub async fn delete_fixed_database(
10801094
&self,
10811095
subscription_id: i32,
@@ -1085,6 +1099,9 @@ impl FixedDatabaseHandler {
10851099
}
10861100

10871101
/// Backup fixed database (backward compatibility)
1102+
///
1103+
/// **Deprecated**: Use [`backup`](Self::backup) instead
1104+
#[deprecated(since = "0.8.0", note = "Use `backup` instead")]
10881105
pub async fn backup_fixed_database(
10891106
&self,
10901107
subscription_id: i32,
@@ -1095,6 +1112,9 @@ impl FixedDatabaseHandler {
10951112
}
10961113

10971114
/// Get fixed subscription databases (backward compatibility)
1115+
///
1116+
/// **Deprecated**: Use [`list`](Self::list) instead
1117+
#[deprecated(since = "0.8.0", note = "Use `list` instead")]
10981118
pub async fn get_fixed_subscription_databases(
10991119
&self,
11001120
subscription_id: i32,
@@ -1105,6 +1125,9 @@ impl FixedDatabaseHandler {
11051125
}
11061126

11071127
/// Get fixed database by id (backward compatibility)
1128+
///
1129+
/// **Deprecated**: Use [`get_by_id`](Self::get_by_id) instead
1130+
#[deprecated(since = "0.8.0", note = "Use `get_by_id` instead")]
11081131
pub async fn fixed_database_by_id(
11091132
&self,
11101133
subscription_id: i32,
@@ -1114,6 +1137,9 @@ impl FixedDatabaseHandler {
11141137
}
11151138

11161139
/// Get fixed subscription database by id (backward compatibility)
1140+
///
1141+
/// **Deprecated**: Use [`get_by_id`](Self::get_by_id) instead
1142+
#[deprecated(since = "0.8.0", note = "Use `get_by_id` instead")]
11171143
pub async fn get_fixed_subscription_database_by_id(
11181144
&self,
11191145
subscription_id: i32,
@@ -1123,6 +1149,9 @@ impl FixedDatabaseHandler {
11231149
}
11241150

11251151
/// Delete fixed database by id (backward compatibility)
1152+
///
1153+
/// **Deprecated**: Use [`delete_by_id`](Self::delete_by_id) instead
1154+
#[deprecated(since = "0.8.0", note = "Use `delete_by_id` instead")]
11261155
pub async fn delete_fixed_database_by_id(
11271156
&self,
11281157
subscription_id: i32,
@@ -1132,6 +1161,9 @@ impl FixedDatabaseHandler {
11321161
}
11331162

11341163
/// Import fixed database (backward compatibility)
1164+
///
1165+
/// **Deprecated**: Use [`import`](Self::import) instead
1166+
#[deprecated(since = "0.8.0", note = "Use `import` instead")]
11351167
pub async fn import_fixed_database(
11361168
&self,
11371169
subscription_id: i32,
@@ -1142,6 +1174,9 @@ impl FixedDatabaseHandler {
11421174
}
11431175

11441176
/// Create fixed database tag (backward compatibility)
1177+
///
1178+
/// **Deprecated**: Use [`create_tag`](Self::create_tag) instead
1179+
#[deprecated(since = "0.8.0", note = "Use `create_tag` instead")]
11451180
pub async fn create_fixed_database_tag(
11461181
&self,
11471182
subscription_id: i32,
@@ -1152,6 +1187,9 @@ impl FixedDatabaseHandler {
11521187
}
11531188

11541189
/// Get fixed database tags (backward compatibility)
1190+
///
1191+
/// **Deprecated**: Use [`get_tags`](Self::get_tags) instead
1192+
#[deprecated(since = "0.8.0", note = "Use `get_tags` instead")]
11551193
pub async fn get_fixed_database_tags(
11561194
&self,
11571195
subscription_id: i32,

crates/redis-cloud/src/fixed/subscriptions.rs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -550,8 +550,13 @@ impl FixedSubscriptionHandler {
550550
// ========================================================================
551551
// Backward compatibility wrapper methods
552552
// ========================================================================
553+
// NOTE: These methods are deprecated in favor of the shorter, more idiomatic names.
554+
// They will be removed in a future version.
553555

554556
/// Create fixed subscription (backward compatibility)
557+
///
558+
/// **Deprecated**: Use [`create`](Self::create) instead
559+
#[deprecated(since = "0.8.0", note = "Use `create` instead")]
555560
pub async fn create_fixed_subscription(
556561
&self,
557562
request: &FixedSubscriptionCreateRequest,
@@ -560,13 +565,19 @@ impl FixedSubscriptionHandler {
560565
}
561566

562567
/// Get fixed subscription (backward compatibility)
568+
///
569+
/// **Deprecated**: Use [`get_by_id`](Self::get_by_id) instead
570+
#[deprecated(since = "0.8.0", note = "Use `get_by_id` instead")]
563571
pub async fn get_fixed_subscription(&self, subscription_id: i32) -> Result<TaskStateUpdate> {
564572
self.get_by_id(subscription_id)
565573
.await
566574
.map(|sub| serde_json::from_value(serde_json::json!(sub)).unwrap())
567575
}
568576

569577
/// Update fixed subscription (backward compatibility)
578+
///
579+
/// **Deprecated**: Use [`update`](Self::update) instead
580+
#[deprecated(since = "0.8.0", note = "Use `update` instead")]
570581
pub async fn update_fixed_subscription(
571582
&self,
572583
subscription_id: i32,
@@ -576,16 +587,25 @@ impl FixedSubscriptionHandler {
576587
}
577588

578589
/// Delete fixed subscription (backward compatibility)
590+
///
591+
/// **Deprecated**: Use [`delete_by_id`](Self::delete_by_id) instead
592+
#[deprecated(since = "0.8.0", note = "Use `delete_by_id` instead")]
579593
pub async fn delete_fixed_subscription(&self, subscription_id: i32) -> Result<TaskStateUpdate> {
580594
self.delete_by_id(subscription_id).await
581595
}
582596

583597
/// Get all fixed subscriptions plans (backward compatibility)
598+
///
599+
/// **Deprecated**: Use [`list_plans`](Self::list_plans) instead
600+
#[deprecated(since = "0.8.0", note = "Use `list_plans` instead")]
584601
pub async fn get_all_fixed_subscriptions_plans(&self) -> Result<FixedSubscriptionsPlans> {
585602
self.list_plans(None, None).await
586603
}
587604

588605
/// Get fixed subscriptions plans by subscription id (backward compatibility)
606+
///
607+
/// **Deprecated**: Use [`get_plans_by_subscription_id`](Self::get_plans_by_subscription_id) instead
608+
#[deprecated(since = "0.8.0", note = "Use `get_plans_by_subscription_id` instead")]
589609
pub async fn get_fixed_subscriptions_plans_by_subscription_id(
590610
&self,
591611
subscription_id: i32,
@@ -594,6 +614,9 @@ impl FixedSubscriptionHandler {
594614
}
595615

596616
/// Get fixed subscriptions plan by id (backward compatibility)
617+
///
618+
/// **Deprecated**: Use [`get_plan_by_id`](Self::get_plan_by_id) instead
619+
#[deprecated(since = "0.8.0", note = "Use `get_plan_by_id` instead")]
597620
pub async fn get_fixed_subscriptions_plan_by_id(
598621
&self,
599622
plan_id: i32,
@@ -602,16 +625,25 @@ impl FixedSubscriptionHandler {
602625
}
603626

604627
/// Get fixed redis versions (backward compatibility)
628+
///
629+
/// **Deprecated**: Use [`get_redis_versions`](Self::get_redis_versions) instead
630+
#[deprecated(since = "0.8.0", note = "Use `get_redis_versions` instead")]
605631
pub async fn get_fixed_redis_versions(&self, subscription_id: i32) -> Result<RedisVersions> {
606632
self.get_redis_versions(subscription_id).await
607633
}
608634

609635
/// Get all fixed subscriptions (backward compatibility)
636+
///
637+
/// **Deprecated**: Use [`list`](Self::list) instead
638+
#[deprecated(since = "0.8.0", note = "Use `list` instead")]
610639
pub async fn get_all_fixed_subscriptions(&self) -> Result<FixedSubscriptions> {
611640
self.list().await
612641
}
613642

614643
/// Delete fixed subscription by id (backward compatibility)
644+
///
645+
/// **Deprecated**: Use [`delete_by_id`](Self::delete_by_id) instead
646+
#[deprecated(since = "0.8.0", note = "Use `delete_by_id` instead")]
615647
pub async fn delete_fixed_subscription_by_id(
616648
&self,
617649
subscription_id: i32,
@@ -620,6 +652,9 @@ impl FixedSubscriptionHandler {
620652
}
621653

622654
/// Get fixed subscription by id (backward compatibility)
655+
///
656+
/// **Deprecated**: Use [`get_by_id`](Self::get_by_id) instead
657+
#[deprecated(since = "0.8.0", note = "Use `get_by_id` instead")]
623658
pub async fn get_fixed_subscription_by_id(
624659
&self,
625660
subscription_id: i32,

crates/redis-cloud/tests/fixed_databases_tests.rs

Lines changed: 10 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,7 @@ async fn test_get_fixed_subscription_databases() {
3737
.unwrap();
3838

3939
let handler = FixedDatabaseHandler::new(client);
40-
let result = handler
41-
.get_fixed_subscription_databases(123, None, None)
42-
.await
43-
.unwrap();
40+
let result = handler.list(123, None, None).await.unwrap();
4441

4542
assert_eq!(result.account_id, Some(456));
4643
assert!(result.links.is_some());
@@ -105,7 +102,7 @@ async fn test_create_fixed_database() {
105102
extra: serde_json::Value::Null,
106103
};
107104

108-
let result = handler.create_fixed_database(123, &request).await.unwrap();
105+
let result = handler.create(123, &request).await.unwrap();
109106
assert_eq!(result.task_id, Some("task-create-fixed-db".to_string()));
110107
assert_eq!(
111108
result.command_type,
@@ -196,7 +193,7 @@ async fn test_delete_fixed_database() {
196193
.unwrap();
197194

198195
let handler = FixedDatabaseHandler::new(client);
199-
let result = handler.delete_fixed_database_by_id(123, 456).await.unwrap();
196+
let result = handler.delete_by_id(123, 456).await.unwrap();
200197

201198
assert_eq!(result.task_id, Some("task-delete-fixed-db".to_string()));
202199
assert_eq!(
@@ -236,10 +233,7 @@ async fn test_backup_fixed_database() {
236233
command_type: None,
237234
extra: serde_json::Value::Null,
238235
};
239-
let result = handler
240-
.backup_fixed_database(123, 456, &request)
241-
.await
242-
.unwrap();
236+
let result = handler.backup(123, 456, &request).await.unwrap();
243237

244238
assert_eq!(result.task_id, Some("task-backup-fixed-db".to_string()));
245239
}
@@ -278,10 +272,7 @@ async fn test_import_fixed_database() {
278272
extra: serde_json::Value::Null,
279273
};
280274

281-
let result = handler
282-
.import_fixed_database(123, 456, &request)
283-
.await
284-
.unwrap();
275+
let result = handler.import(123, 456, &request).await.unwrap();
285276
assert_eq!(result.task_id, Some("task-import-fixed-db".to_string()));
286277
}
287278

@@ -318,10 +309,7 @@ async fn test_tag_operations() {
318309
extra: serde_json::Value::Null,
319310
};
320311

321-
let result = handler
322-
.create_fixed_database_tag(123, 456, &request)
323-
.await
324-
.unwrap();
312+
let result = handler.create_tag(123, 456, &request).await.unwrap();
325313
assert!(result.key.is_some());
326314
}
327315

@@ -345,9 +333,7 @@ async fn test_error_handling_401() {
345333
.unwrap();
346334

347335
let handler = FixedDatabaseHandler::new(client);
348-
let result = handler
349-
.get_fixed_subscription_databases(123, None, None)
350-
.await;
336+
let result = handler.list(123, None, None).await;
351337

352338
assert!(result.is_err());
353339
match result {
@@ -378,7 +364,7 @@ async fn test_error_handling_403() {
378364
.unwrap();
379365

380366
let handler = FixedDatabaseHandler::new(client);
381-
let result = handler.delete_fixed_database_by_id(123, 456).await;
367+
let result = handler.delete_by_id(123, 456).await;
382368

383369
assert!(result.is_err());
384370
match result {
@@ -409,9 +395,7 @@ async fn test_error_handling_404() {
409395
.unwrap();
410396

411397
let handler = FixedDatabaseHandler::new(client);
412-
let result = handler
413-
.get_fixed_subscription_database_by_id(999, 999)
414-
.await;
398+
let result = handler.get_by_id(999, 999).await;
415399

416400
assert!(result.is_err());
417401
if let Err(redis_cloud::CloudError::NotFound { message }) = result {
@@ -472,7 +456,7 @@ async fn test_error_handling_500() {
472456
command_type: None,
473457
extra: serde_json::Value::Null,
474458
};
475-
let result = handler.create_fixed_database(123, &request).await;
459+
let result = handler.create(123, &request).await;
476460

477461
assert!(result.is_err());
478462
match result {

0 commit comments

Comments
 (0)