Skip to content

Commit 30d175f

Browse files
committed
Add more unit tests
These were written by Junie, but needed tweaking and refactoring.
1 parent bad1e4a commit 30d175f

File tree

1 file changed

+179
-10
lines changed

1 file changed

+179
-10
lines changed

server/src/test/kotlin/com/adobe/testing/s3mock/service/BucketServiceTest.kt

Lines changed: 179 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,15 @@
1717
package com.adobe.testing.s3mock.service
1818

1919
import com.adobe.testing.s3mock.S3Exception
20+
import com.adobe.testing.s3mock.dto.BucketLifecycleConfiguration
21+
import com.adobe.testing.s3mock.dto.ObjectLockConfiguration
22+
import com.adobe.testing.s3mock.dto.ObjectLockEnabled
2023
import com.adobe.testing.s3mock.dto.ObjectOwnership
2124
import com.adobe.testing.s3mock.dto.VersioningConfiguration
2225
import com.adobe.testing.s3mock.dto.VersioningConfiguration.Status
2326
import com.adobe.testing.s3mock.store.BucketMetadata
2427
import com.adobe.testing.s3mock.store.MultipartStore
28+
import com.adobe.testing.s3mock.store.S3ObjectMetadata
2529
import org.assertj.core.api.Assertions.assertThat
2630
import org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy
2731
import org.junit.jupiter.api.Test
@@ -474,25 +478,190 @@ internal class BucketServiceTest : ServiceTestBase() {
474478

475479
// After setting, BucketStore should have been invoked; we simulate by making metadata return the configuration
476480
whenever(bucketStore.getBucketMetadata(bucketName)).thenReturn(
477-
BucketMetadata(
481+
bucketMetadata(
478482
bucketName,
479-
bucketMetadata.creationDate(),
480-
cfg,
481-
bucketMetadata.objectLockConfiguration(),
482-
bucketMetadata.bucketLifecycleConfiguration(),
483-
bucketMetadata.objectOwnership(),
484-
bucketMetadata.path(),
485-
bucketMetadata.bucketRegion(),
486-
bucketMetadata.bucketInfo(),
487-
bucketMetadata.locationInfo()
483+
bucketMetadata,
484+
versioningConfiguration = cfg,
488485
)
489486
)
490487

491488
val out = iut.getVersioningConfiguration(bucketName)
492489
assertThat(out.status()).isEqualTo(Status.ENABLED)
493490
}
494491

492+
@Test
493+
fun testObjectLockConfiguration_getThrowsWhenAbsent_thenSetAndGet() {
494+
val bucketName = "bucket-lock"
495+
val bucketMetadata = givenBucket(bucketName)
496+
497+
// Absent -> throws
498+
assertThatThrownBy { iut.getObjectLockConfiguration(bucketName) }
499+
.isEqualTo(S3Exception.NOT_FOUND_BUCKET_OBJECT_LOCK)
500+
501+
// Set configuration
502+
val cfg = ObjectLockConfiguration(
503+
ObjectLockEnabled.ENABLED,
504+
null
505+
)
506+
iut.setObjectLockConfiguration(bucketName, cfg)
507+
508+
// Return metadata updated with configuration
509+
whenever(bucketStore.getBucketMetadata(bucketName)).thenReturn(
510+
bucketMetadata(
511+
bucketName,
512+
bucketMetadata,
513+
cfg,
514+
)
515+
)
516+
517+
val out = iut.getObjectLockConfiguration(bucketName)
518+
assertThat(out.objectLockEnabled()).isEqualTo(ObjectLockEnabled.ENABLED)
519+
}
520+
521+
@Test
522+
fun testBucketLifecycleConfiguration_setGetDelete() {
523+
val bucketName = "bucket-lc"
524+
val bucketMetadata = givenBucket(bucketName)
525+
526+
// Absent -> throws
527+
assertThatThrownBy { iut.getBucketLifecycleConfiguration(bucketName) }
528+
.isEqualTo(S3Exception.NO_SUCH_LIFECYCLE_CONFIGURATION)
529+
530+
// Set lifecycle configuration
531+
val lc = BucketLifecycleConfiguration(emptyList())
532+
iut.setBucketLifecycleConfiguration(bucketName, lc)
533+
534+
// Simulate store returning updated metadata
535+
whenever(bucketStore.getBucketMetadata(bucketName)).thenReturn(
536+
bucketMetadata(
537+
bucketName,
538+
bucketMetadata,
539+
bucketLifecycleConfiguration = lc,
540+
)
541+
)
542+
543+
val read = iut.getBucketLifecycleConfiguration(bucketName)
544+
assertThat(read.rules()).isEmpty()
545+
546+
// Delete configuration and ensure it's gone
547+
iut.deleteBucketLifecycleConfiguration(bucketName)
548+
549+
// After delete, simulate metadata without lifecycle configuration again
550+
whenever(bucketStore.getBucketMetadata(bucketName)).thenReturn(
551+
bucketMetadata(bucketName, bucketMetadata)
552+
)
553+
554+
assertThatThrownBy { iut.getBucketLifecycleConfiguration(bucketName) }
555+
.isEqualTo(S3Exception.NO_SUCH_LIFECYCLE_CONFIGURATION)
556+
}
557+
558+
@Test
559+
fun testDeleteBucket_nonEmptyWithNonDeleteMarker_throws() {
560+
val bucketName = "bucket-del"
561+
val meta = givenBucket(bucketName)
562+
val key = "k1"
563+
val id = meta.addKey(key)
564+
565+
// First call returns metadata with one object, second call also returns non-empty -> triggers exception
566+
whenever(bucketStore.getBucketMetadata(bucketName)).thenReturn(meta, meta)
567+
568+
// Object metadata without delete marker
569+
whenever(objectStore.getS3ObjectMetadata(meta, id, null)).thenReturn(s3ObjectMetadata(id, key))
570+
571+
assertThatThrownBy { iut.deleteBucket(bucketName) }
572+
.isInstanceOf(IllegalStateException::class.java)
573+
.hasMessageContaining("Bucket is not empty: $bucketName")
574+
}
575+
576+
@Test
577+
fun testDeleteBucket_onlyDeleteMarkersAreRemoved_andBucketDeleted() {
578+
val bucketName = "bucket-del-markers"
579+
val metaInitial = givenBucket(bucketName)
580+
val key = "k1"
581+
val id = metaInitial.addKey(key)
582+
583+
// Metadata before deletion: contains one key
584+
// After removing delete marker, metadata is empty
585+
val metaAfter = bucketMetadata(bucketName, metaInitial)
586+
587+
whenever(bucketStore.getBucketMetadata(bucketName)).thenReturn(metaInitial, metaAfter)
588+
589+
// Return S3ObjectMetadata marked as delete marker
590+
val dm = s3ObjectMetadata(id, key)
591+
// mark it as a delete marker using helper
592+
val dmMeta = S3ObjectMetadata.deleteMarker(dm, "v1")
593+
594+
whenever(objectStore.getS3ObjectMetadata(metaInitial, id, null)).thenReturn(dmMeta)
595+
596+
// bucketStore.deleteBucket should be called and return true
597+
whenever(bucketStore.deleteBucket(bucketName)).thenReturn(true)
598+
599+
val deleted = iut.deleteBucket(bucketName)
600+
assertThat(deleted).isTrue()
601+
// ensure we removed the key from the bucket
602+
verify(bucketStore).removeFromBucket(key, bucketName)
603+
verify(objectStore).doDeleteObject(metaInitial, id)
604+
}
605+
606+
@Test
607+
fun testDeleteBucket_nonExistingBucket_throws() {
608+
val bucketName = "no-such-bucket"
609+
// Return null metadata to trigger the else-branch in service
610+
whenever(bucketStore.getBucketMetadata(bucketName)).thenReturn(null)
611+
assertThatThrownBy { iut.deleteBucket(bucketName) }
612+
.isInstanceOf(IllegalStateException::class.java)
613+
.hasMessageContaining("Requested Bucket does not exist: $bucketName")
614+
}
615+
616+
@Test
617+
fun testListVersions_versioningDisabled_returnsCurrentVersionsOnly() {
618+
val bucketName = "bucket-versions"
619+
val prefix = ""
620+
val delimiter = ""
621+
val encodingType = "url"
622+
val maxKeys = 100
623+
val keyMarker = ""
624+
val versionIdMarker = ""
625+
626+
givenBucketWithContents(bucketName, prefix)
627+
628+
val out = iut.listVersions(
629+
bucketName,
630+
prefix,
631+
delimiter,
632+
encodingType,
633+
maxKeys,
634+
keyMarker,
635+
versionIdMarker
636+
)
637+
638+
// With versioning disabled, entries are mapped 1:1 without delete markers
639+
assertThat(out.deleteMarkers()).isEmpty()
640+
assertThat(out.objectVersions()).isNotEmpty()
641+
}
642+
495643
companion object {
496644
private const val TEST_BUCKET_NAME = "test-bucket"
645+
646+
private fun bucketMetadata(
647+
bucketName: String,
648+
bucketMetadata: BucketMetadata,
649+
objectLockConfiguration: ObjectLockConfiguration? = bucketMetadata.objectLockConfiguration(),
650+
bucketLifecycleConfiguration: BucketLifecycleConfiguration? = bucketMetadata.bucketLifecycleConfiguration(),
651+
versioningConfiguration: VersioningConfiguration? = bucketMetadata.versioningConfiguration()
652+
): BucketMetadata {
653+
return BucketMetadata(
654+
bucketName,
655+
bucketMetadata.creationDate(),
656+
versioningConfiguration,
657+
objectLockConfiguration,
658+
bucketLifecycleConfiguration,
659+
bucketMetadata.objectOwnership(),
660+
bucketMetadata.path(),
661+
bucketMetadata.bucketRegion(),
662+
bucketMetadata.bucketInfo(),
663+
bucketMetadata.locationInfo()
664+
)
665+
}
497666
}
498667
}

0 commit comments

Comments
 (0)