mod common;
use bucketwarden_s3::S3HttpRequest;
use common::*;
#[test]
fn replication_preserves_legal_hold_and_retention_state() {
let mut runtime = runtime();
runtime
.handle_s3_http(S3HttpRequest::new("alice", "PUT", "/archive-001"))
.expect("source");
runtime
.handle_s3_http(S3HttpRequest::new("alice", "PUT", "/archive-002"))
.expect("destination");
for bucket in ["archive-001", "archive-002"] {
runtime
.handle_s3_http(
S3HttpRequest::new("alice", "PUT", format!("/{bucket}"))
.with_query("object-lock", "")
.with_body(
b"<ObjectLockConfiguration><ObjectLockEnabled>Enabled</ObjectLockEnabled></ObjectLockConfiguration>"
.to_vec(),
),
)
.expect("object lock");
}
runtime
.handle_s3_http(
S3HttpRequest::new("alice", "PUT", "/archive-001")
.with_query("replication", "")
.with_body(
br#"<ReplicationConfiguration>
<Role>arn:aws:iam::123456789012:role/bucketwarden-replication</Role>
<Rule>
<ID>records</ID>
<Status>Enabled</Status>
<Filter><Prefix>records/</Prefix></Filter>
<Destination><Bucket>arn:aws:s3:::archive-002</Bucket></Destination>
<DeleteMarkerReplication><Status>Enabled</Status></DeleteMarkerReplication>
<SourceSelectionCriteria><SseKmsEncryptedObjects><Status>Enabled</Status></SseKmsEncryptedObjects></SourceSelectionCriteria>
</Rule>
</ReplicationConfiguration>"#
.to_vec(),
),
)
.expect("replication config");
let put = runtime
.handle_s3_http(
S3HttpRequest::new("alice", "PUT", "/archive-001/records/a.json")
.with_header("x-amz-object-lock-legal-hold", "ON")
.with_header("x-amz-object-lock-mode", "COMPLIANCE")
.with_header(
"x-amz-object-lock-retain-until-date",
"1970-01-03T00:00:00Z",
)
.with_body(br#"{"locked":true}"#.to_vec()),
)
.expect("put locked object");
let version_id = put
.headers
.get("x-amz-version-id")
.expect("version")
.clone();
let run = runtime
.run_bucket_replication("alice", "archive-001")
.expect("replicate");
assert_eq!(run.replicated_object_versions, 1);
let source_retention = runtime
.get_object_retention("alice", "archive-001", "records/a.json", Some(&version_id))
.expect("source retention");
let destination_retention = runtime
.get_object_retention("alice", "archive-002", "records/a.json", Some(&version_id))
.expect("destination retention");
assert_eq!(destination_retention.mode, source_retention.mode);
assert_eq!(
destination_retention.retain_until_epoch_seconds,
source_retention.retain_until_epoch_seconds
);
let source_hold = runtime
.get_object_legal_hold("alice", "archive-001", "records/a.json", Some(&version_id))
.expect("source hold");
let destination_hold = runtime
.get_object_legal_hold("alice", "archive-002", "records/a.json", Some(&version_id))
.expect("destination hold");
assert!(source_hold.enabled);
assert!(destination_hold.enabled);
assert_eq!(
runtime
.get_object_version("alice", "archive-001", "records/a.json", &version_id)
.expect("source version")
.replication_status
.as_deref(),
Some("COMPLETED")
);
}