@@ -3690,6 +3690,93 @@ func testPutObjectStreaming() {
36903690 logSuccess (testName , function , args , startTime )
36913691}
36923692
3693+ // Test PutObject with preconditions on non-existent objects
3694+ func testPutObjectPreconditionOnNonExistent () {
3695+ startTime := time .Now ()
3696+ testName := getFuncName ()
3697+ function := "PutObject(bucketName, objectName, reader, size, opts) with preconditions"
3698+ args := map [string ]interface {}{
3699+ "bucketName" : "" ,
3700+ "objectName" : "" ,
3701+ "opts" : "minio.PutObjectOptions{SetMatchETag/SetMatchETagExcept}" ,
3702+ }
3703+
3704+ c , err := NewClient (ClientConfig {})
3705+ if err != nil {
3706+ logError (testName , function , args , startTime , "" , "MinIO client object creation failed" , err )
3707+ return
3708+ }
3709+
3710+ bucketName := randString (60 , rand .NewSource (time .Now ().UnixNano ()), "minio-go-test-" )
3711+ args ["bucketName" ] = bucketName
3712+
3713+ err = c .MakeBucket (context .Background (), bucketName , minio.MakeBucketOptions {Region : "us-east-1" })
3714+ if err != nil {
3715+ logError (testName , function , args , startTime , "" , "MakeBucket failed" , err )
3716+ return
3717+ }
3718+
3719+ defer cleanupBucket (bucketName , c )
3720+
3721+ // Test 1: PutObject with SetMatchETag on non-existent object should fail
3722+ objectName := randString (60 , rand .NewSource (time .Now ().UnixNano ()), "test-object-" )
3723+ args ["objectName" ] = objectName
3724+
3725+ data := bytes .NewReader ([]byte ("test data" ))
3726+
3727+ opts := minio.PutObjectOptions {}
3728+ opts .SetMatchETag ("some-etag" )
3729+
3730+ _ , err = c .PutObject (context .Background (), bucketName , objectName , data , int64 (data .Len ()), opts )
3731+ if err == nil {
3732+ logError (testName , function , args , startTime , "" , "PutObject with SetMatchETag on non-existent object should have failed" , nil )
3733+ return
3734+ }
3735+
3736+ errResp := minio .ToErrorResponse (err )
3737+ if errResp .Code != "NoSuchKey" {
3738+ logError (testName , function , args , startTime , "" , fmt .Sprintf ("Expected NoSuchKey error (AWS standard for non-existent objects), got %s" , errResp .Code ), err )
3739+ return
3740+ }
3741+
3742+ // Test 2: PutObject with SetMatchETagExcept (If-None-Match) on non-existent object should succeed
3743+ objectName2 := randString (60 , rand .NewSource (time .Now ().UnixNano ()), "test-object2-" )
3744+ args ["objectName" ] = objectName2
3745+
3746+ data2 := bytes .NewReader ([]byte ("test data 2" ))
3747+ opts2 := minio.PutObjectOptions {}
3748+ opts2 .SetMatchETagExcept ("some-etag" )
3749+
3750+ _ , err = c .PutObject (context .Background (), bucketName , objectName2 , data2 , int64 (data2 .Len ()), opts2 )
3751+ if err != nil {
3752+ logError (testName , function , args , startTime , "" , "PutObject with SetMatchETagExcept (If-None-Match) on non-existent object should have succeeded" , err )
3753+ return
3754+ }
3755+ // Test 3: CompleteMultipartUpload with preconditions on non-existent object should fail
3756+ objectName3 := randString (60 , rand .NewSource (time .Now ().UnixNano ()), "test-multipart-" )
3757+ args ["objectName" ] = objectName3
3758+
3759+ data3 := bytes .Repeat ([]byte ("a" ), 5 * 1024 * 1024 + 1 )
3760+ reader3 := bytes .NewReader (data3 )
3761+
3762+ opts3 := minio.PutObjectOptions {}
3763+ opts3 .SetMatchETag ("non-existent-etag" )
3764+
3765+ _ , err = c .PutObject (context .Background (), bucketName , objectName3 , reader3 , int64 (len (data3 )), opts3 )
3766+ if err == nil {
3767+ logError (testName , function , args , startTime , "" , "CompleteMultipartUpload with SetMatchETag on non-existent object should have failed" , nil )
3768+ return
3769+ }
3770+
3771+ errResp = minio .ToErrorResponse (err )
3772+ if errResp .Code != "NoSuchKey" {
3773+ logError (testName , function , args , startTime , "" , fmt .Sprintf ("Expected NoSuchKey error (AWS standard for non-existent objects) for multipart, got %s" , errResp .Code ), err )
3774+ return
3775+ }
3776+
3777+ logSuccess (testName , function , args , startTime )
3778+ }
3779+
36933780// Test get object seeker from the end, using whence set to '2'.
36943781func testGetObjectSeekEnd () {
36953782 // initialize logging params
@@ -14609,6 +14696,7 @@ func main() {
1460914696 testPutObjectWithMetadata ()
1461014697 testPutObjectReadAt ()
1461114698 testPutObjectStreaming ()
14699+ testPutObjectPreconditionOnNonExistent ()
1461214700 testGetObjectSeekEnd ()
1461314701 testGetObjectClosedTwice ()
1461414702 testGetObjectS3Zip ()
0 commit comments