mirror of
https://github.com/rustfs/rustfs.git
synced 2026-07-26 16:28:15 +00:00
test(e2e): add SHA256 write and HEAD checksum regressions (#4354)
test(e2e): add SHA256 verify-on-write & HEAD-checksum regression for #4341 Issue #4341 reported (on beta.8) that RustFS accepted mismatched S3 SHA256 checksums on PutObject (HTTP 200 instead of 400 BadDigest) and did not return ChecksumSHA256 on HeadObject with ChecksumMode=ENABLED. Both behaviors are already correct on current main, but the existing e2e coverage only asserted the happy path (upload succeeds + GetObject content matches). It did not encode the issue's two acceptance criteria, so a future regression would go undetected. Add two focused e2e tests that assert exactly the issue's contract: - test_put_object_rejects_mismatched_sha256: a body that does not match the declared x-amz-checksum-sha256 must be rejected with BadDigest and must not be stored. - test_head_object_returns_stored_sha256: after a correct upload, HeadObject with ChecksumMode=ENABLED must return the stored base64 SHA256 digest. Both tests pass against a real rustfs server (mismatch -> HTTP 400 BadDigest verified). Co-authored-by: heihutu <heihutu@gmail.com>
This commit is contained in:
@@ -136,6 +136,101 @@ mod tests {
|
||||
info!("PASSED: PutObject with checksum_sha256 and GetObject content match");
|
||||
}
|
||||
|
||||
/// Regression test for issue #4341 (part 1: verify-on-write):
|
||||
/// PutObject with a SHA256 checksum that does NOT match the body must be
|
||||
/// rejected (BadDigest / checksum mismatch), NOT accepted with HTTP 200.
|
||||
#[tokio::test]
|
||||
#[serial]
|
||||
async fn test_put_object_rejects_mismatched_sha256() {
|
||||
init_logging();
|
||||
info!("TEST: PutObject rejects mismatched x-amz-checksum-sha256 (issue #4341)");
|
||||
|
||||
let mut env = RustFSTestEnvironment::new().await.expect("Failed to create test environment");
|
||||
env.start_rustfs_server(vec![]).await.expect("Failed to start RustFS");
|
||||
|
||||
let client = create_s3_client(&env);
|
||||
let bucket = "test-checksum-sha256-mismatch";
|
||||
create_bucket(&client, bucket).await.expect("Failed to create bucket");
|
||||
|
||||
let key = "obj-bad-sha256.txt";
|
||||
let content = b"Body bytes that do NOT match the declared checksum";
|
||||
// Checksum of a DIFFERENT payload -> deliberate mismatch.
|
||||
let wrong_checksum = checksum_sha256_base64(b"some other payload entirely");
|
||||
|
||||
let result = client
|
||||
.put_object()
|
||||
.bucket(bucket)
|
||||
.key(key)
|
||||
.body(ByteStream::from_static(content))
|
||||
.checksum_sha256(&wrong_checksum)
|
||||
.send()
|
||||
.await;
|
||||
|
||||
assert!(
|
||||
result.is_err(),
|
||||
"PutObject with a mismatched SHA256 must be rejected, but it succeeded (issue #4341)"
|
||||
);
|
||||
let err = result.err().unwrap();
|
||||
let msg = format!("{err:?}");
|
||||
info!("PutObject correctly rejected mismatched checksum: {msg}");
|
||||
assert!(
|
||||
msg.contains("BadDigest") || msg.to_lowercase().contains("digest") || msg.to_lowercase().contains("checksum"),
|
||||
"Expected a BadDigest/checksum error, got: {msg}"
|
||||
);
|
||||
|
||||
// And the object must not have been stored.
|
||||
let head = client.head_object().bucket(bucket).key(key).send().await;
|
||||
assert!(head.is_err(), "Object must not exist after a rejected mismatched-checksum PutObject");
|
||||
info!("PASSED: PutObject rejects mismatched SHA256 and stores nothing");
|
||||
}
|
||||
|
||||
/// Regression test for issue #4341 (part 2: retrieve-on-HEAD):
|
||||
/// After PutObject with a correct SHA256 checksum, HeadObject with
|
||||
/// ChecksumMode=ENABLED must return that stored base64 SHA256 digest.
|
||||
#[tokio::test]
|
||||
#[serial]
|
||||
async fn test_head_object_returns_stored_sha256() {
|
||||
init_logging();
|
||||
info!("TEST: HeadObject returns stored SHA256 with ChecksumMode=ENABLED (issue #4341)");
|
||||
|
||||
let mut env = RustFSTestEnvironment::new().await.expect("Failed to create test environment");
|
||||
env.start_rustfs_server(vec![]).await.expect("Failed to start RustFS");
|
||||
|
||||
let client = create_s3_client(&env);
|
||||
let bucket = "test-checksum-sha256-head";
|
||||
create_bucket(&client, bucket).await.expect("Failed to create bucket");
|
||||
|
||||
let key = "obj-head-sha256.txt";
|
||||
let content = b"Retrieve my SHA256 checksum on HEAD";
|
||||
let checksum = checksum_sha256_base64(content);
|
||||
|
||||
client
|
||||
.put_object()
|
||||
.bucket(bucket)
|
||||
.key(key)
|
||||
.body(ByteStream::from_static(content))
|
||||
.checksum_sha256(&checksum)
|
||||
.send()
|
||||
.await
|
||||
.expect("PutObject with correct SHA256 failed");
|
||||
|
||||
let head = client
|
||||
.head_object()
|
||||
.bucket(bucket)
|
||||
.key(key)
|
||||
.checksum_mode(ChecksumMode::Enabled)
|
||||
.send()
|
||||
.await
|
||||
.expect("HeadObject failed");
|
||||
|
||||
assert_eq!(
|
||||
head.checksum_sha256(),
|
||||
Some(checksum.as_str()),
|
||||
"HeadObject with ChecksumMode=ENABLED must return the stored base64 SHA256 (issue #4341)"
|
||||
);
|
||||
info!("PASSED: HeadObject returns stored SHA256 digest");
|
||||
}
|
||||
|
||||
/// Multipart upload with checksum: CreateMultipartUpload, UploadPart(s) with checksum_sha256, CompleteMultipartUpload; then GetObject verifies content.
|
||||
/// Uses part size >= 5MB (server minimum) for two parts.
|
||||
#[tokio::test]
|
||||
|
||||
Reference in New Issue
Block a user