use aws_sdk_keyspaces::config::BehaviorVersion;
use winterbaume_core::MockAws;
use winterbaume_keyspaces::KeyspacesService;
async fn make_client() -> aws_sdk_keyspaces::Client {
let mock = MockAws::builder()
.with_service(KeyspacesService::new())
.build();
let config = aws_config::defaults(BehaviorVersion::latest())
.http_client(mock.http_client())
.credentials_provider(mock.credentials_provider())
.region(aws_sdk_keyspaces::config::Region::new("us-east-1"))
.load()
.await;
aws_sdk_keyspaces::Client::new(&config)
}
#[tokio::test]
async fn test_table_lifecycle() {
let client = make_client().await;
client
.create_keyspace()
.keyspace_name("scenario_ks")
.send()
.await
.expect("create keyspace should succeed");
let schema = aws_sdk_keyspaces::types::SchemaDefinition::builder()
.all_columns(
aws_sdk_keyspaces::types::ColumnDefinition::builder()
.name("user_id")
.r#type("uuid")
.build()
.unwrap(),
)
.all_columns(
aws_sdk_keyspaces::types::ColumnDefinition::builder()
.name("created_at")
.r#type("timestamp")
.build()
.unwrap(),
)
.partition_keys(
aws_sdk_keyspaces::types::PartitionKey::builder()
.name("user_id")
.build()
.unwrap(),
)
.build()
.unwrap();
let create_resp = client
.create_table()
.keyspace_name("scenario_ks")
.table_name("users")
.schema_definition(schema)
.capacity_specification(
aws_sdk_keyspaces::types::CapacitySpecification::builder()
.throughput_mode(aws_sdk_keyspaces::types::ThroughputMode::PayPerRequest)
.build()
.unwrap(),
)
.send()
.await
.expect("create table should succeed");
assert!(create_resp.resource_arn().contains("users"));
let update_resp = client
.update_table()
.keyspace_name("scenario_ks")
.table_name("users")
.capacity_specification(
aws_sdk_keyspaces::types::CapacitySpecification::builder()
.throughput_mode(aws_sdk_keyspaces::types::ThroughputMode::Provisioned)
.read_capacity_units(10)
.write_capacity_units(5)
.build()
.unwrap(),
)
.add_columns(
aws_sdk_keyspaces::types::ColumnDefinition::builder()
.name("email")
.r#type("text")
.build()
.unwrap(),
)
.send()
.await
.expect("update table should succeed");
assert!(update_resp.resource_arn().contains("users"));
let get_resp = client
.get_table()
.keyspace_name("scenario_ks")
.table_name("users")
.send()
.await
.expect("get table should succeed");
let cap = get_resp
.capacity_specification()
.expect("capacity_specification should be set");
assert_eq!(
cap.throughput_mode().as_str(),
"PROVISIONED",
"throughput mode should be PROVISIONED after update"
);
assert_eq!(
cap.read_capacity_units(),
Some(10),
"read capacity should be 10"
);
let restore_resp = client
.restore_table()
.source_keyspace_name("scenario_ks")
.source_table_name("users")
.target_keyspace_name("scenario_ks")
.target_table_name("users_backup")
.send()
.await
.expect("restore table should succeed");
assert!(restore_resp.restored_table_arn().contains("users_backup"));
let list_resp = client
.list_tables()
.keyspace_name("scenario_ks")
.send()
.await
.expect("list tables should succeed");
let table_names: Vec<_> = list_resp
.tables()
.iter()
.map(|t| t.table_name().to_string())
.collect();
assert!(
table_names.contains(&"users".to_string()),
"original table should be listed"
);
assert!(
table_names.contains(&"users_backup".to_string()),
"backup table should be listed"
);
client
.delete_table()
.keyspace_name("scenario_ks")
.table_name("users_backup")
.send()
.await
.expect("delete backup table should succeed");
client
.delete_table()
.keyspace_name("scenario_ks")
.table_name("users")
.send()
.await
.expect("delete original table should succeed");
client
.delete_keyspace()
.keyspace_name("scenario_ks")
.send()
.await
.expect("delete keyspace should succeed");
}
#[tokio::test]
async fn test_tag_management_lifecycle() {
let client = make_client().await;
let create_resp = client
.create_keyspace()
.keyspace_name("tagged_ks")
.tags(
aws_sdk_keyspaces::types::Tag::builder()
.key("env")
.value("staging")
.build()
.unwrap(),
)
.send()
.await
.expect("create keyspace with tags should succeed");
let arn = create_resp.resource_arn().to_string();
let tags_resp = client
.list_tags_for_resource()
.resource_arn(&arn)
.send()
.await
.expect("list initial tags should succeed");
assert_eq!(tags_resp.tags().len(), 1);
assert_eq!(tags_resp.tags()[0].key(), "env");
client
.tag_resource()
.resource_arn(&arn)
.tags(
aws_sdk_keyspaces::types::Tag::builder()
.key("team")
.value("platform")
.build()
.unwrap(),
)
.tags(
aws_sdk_keyspaces::types::Tag::builder()
.key("cost-centre")
.value("infra")
.build()
.unwrap(),
)
.send()
.await
.expect("tag_resource should succeed");
let tags_resp = client
.list_tags_for_resource()
.resource_arn(&arn)
.send()
.await
.expect("list tags after adding should succeed");
assert_eq!(tags_resp.tags().len(), 3, "should have 3 tags now");
client
.untag_resource()
.resource_arn(&arn)
.tags(
aws_sdk_keyspaces::types::Tag::builder()
.key("env")
.value("staging")
.build()
.unwrap(),
)
.send()
.await
.expect("untag_resource should succeed");
let tags_resp = client
.list_tags_for_resource()
.resource_arn(&arn)
.send()
.await
.expect("list tags after removal should succeed");
assert_eq!(
tags_resp.tags().len(),
2,
"should have 2 tags after removal"
);
let keys: Vec<_> = tags_resp
.tags()
.iter()
.map(|t| t.key().to_string())
.collect();
assert!(
!keys.contains(&"env".to_string()),
"removed tag should not be present"
);
client
.delete_keyspace()
.keyspace_name("tagged_ks")
.send()
.await
.expect("delete keyspace should succeed");
}
#[tokio::test]
async fn test_user_defined_type_lifecycle() {
let client = make_client().await;
client
.create_keyspace()
.keyspace_name("udt_ks")
.send()
.await
.expect("create keyspace should succeed");
let create_resp = client
.create_type()
.keyspace_name("udt_ks")
.type_name("address")
.field_definitions(
aws_sdk_keyspaces::types::FieldDefinition::builder()
.name("street")
.r#type("text")
.build()
.unwrap(),
)
.field_definitions(
aws_sdk_keyspaces::types::FieldDefinition::builder()
.name("city")
.r#type("text")
.build()
.unwrap(),
)
.send()
.await
.expect("create_type should succeed");
assert_eq!(create_resp.type_name(), "address");
let get_resp = client
.get_type()
.keyspace_name("udt_ks")
.type_name("address")
.send()
.await
.expect("get_type should succeed");
assert_eq!(get_resp.keyspace_name(), "udt_ks");
let fields = get_resp.field_definitions();
assert_eq!(fields.len(), 2, "should have 2 field definitions");
let list_resp = client
.list_types()
.keyspace_name("udt_ks")
.send()
.await
.expect("list_types should succeed");
assert!(
list_resp.types().contains(&"address".to_string()),
"address type should appear in list"
);
let delete_resp = client
.delete_type()
.keyspace_name("udt_ks")
.type_name("address")
.send()
.await
.expect("delete_type should succeed");
assert_eq!(delete_resp.type_name(), "address");
let err = client
.get_type()
.keyspace_name("udt_ks")
.type_name("address")
.send()
.await
.expect_err("get_type after delete should fail");
assert!(
format!("{err:?}").contains("ResourceNotFound"),
"should get ResourceNotFoundException"
);
client
.delete_keyspace()
.keyspace_name("udt_ks")
.send()
.await
.expect("delete keyspace should succeed");
}