From 0dd951b9598065f8a49433c8c512f26c382cabb3 Mon Sep 17 00:00:00 2001 From: Esko Suomi Date: Mon, 14 Oct 2024 11:28:24 +0300 Subject: [PATCH] update S3BlobStoreRepository to support metadata injection --- .../export/blob/S3BlobStoreRepository.java | 54 ++++++++++++------- .../blob/S3BlobStoreRepositoryTest.java | 37 ++++++++++++- 2 files changed, 71 insertions(+), 20 deletions(-) diff --git a/src/main/java/no/entur/uttu/export/blob/S3BlobStoreRepository.java b/src/main/java/no/entur/uttu/export/blob/S3BlobStoreRepository.java index f33bee92..1dc09db8 100644 --- a/src/main/java/no/entur/uttu/export/blob/S3BlobStoreRepository.java +++ b/src/main/java/no/entur/uttu/export/blob/S3BlobStoreRepository.java @@ -1,13 +1,8 @@ package no.entur.uttu.export.blob; -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; -import java.util.function.Function; import org.rutebanken.helper.storage.BlobAlreadyExistsException; import org.rutebanken.helper.storage.BlobStoreException; +import org.rutebanken.helper.storage.model.BlobDescriptor; import org.rutebanken.helper.storage.repository.BlobStoreRepository; import software.amazon.awssdk.core.sync.RequestBody; import software.amazon.awssdk.core.sync.ResponseTransformer; @@ -18,6 +13,14 @@ import software.amazon.awssdk.services.s3.model.S3Object; import software.amazon.awssdk.services.s3.paginators.ListObjectsV2Iterable; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.function.Function; + /** * AWS S3 backed implementation of {@link BlobStoreRepository}. */ @@ -49,31 +52,44 @@ public InputStream getBlob(String objectName) { } @Override - public long uploadBlob(String objectName, InputStream inputStream) { - return uploadBlob(objectName, inputStream, null); - } - - @Override - public long uploadBlob(String objectName, InputStream inputStream, String contentType) { + public long uploadBlob(BlobDescriptor blobDescriptor) { RequestBody body = null; try { - body = RequestBody.fromBytes(inputStream.readAllBytes()); + body = RequestBody.fromBytes(blobDescriptor.inputStream().readAllBytes()); } catch (IOException e) { throw new BlobStoreException("Failed to read all bytes from given InputStream", e); } s3Client.putObject( r -> { - r.bucket(containerName).key(objectName); - if (contentType != null) { - r.contentType(contentType); - } + r.bucket(containerName).key(blobDescriptor.name()); + blobDescriptor.contentType().ifPresent(r::contentType); + blobDescriptor.metadata().ifPresent(r::metadata); }, body ); return UNKNOWN_LATEST_VERSION; } + @Override + public long uploadBlob(String objectName, InputStream inputStream) { + return uploadBlob( + new BlobDescriptor(objectName, inputStream, Optional.empty(), Optional.empty()) + ); + } + + @Override + public long uploadBlob(String objectName, InputStream inputStream, String contentType) { + return uploadBlob( + new BlobDescriptor( + objectName, + inputStream, + Optional.of(contentType), + Optional.empty() + ) + ); + } + @Override public long uploadNewBlob(String objectName, InputStream inputStream) { if (objectExists(containerName, objectName)) { @@ -81,7 +97,9 @@ public long uploadNewBlob(String objectName, InputStream inputStream) { "Blob '" + objectName + "' already exists in bucket '" + containerName + "'" ); } else { - return uploadBlob(objectName, inputStream); + return uploadBlob( + new BlobDescriptor(objectName, inputStream, Optional.empty(), Optional.empty()) + ); } } diff --git a/src/test/java/no/entur/uttu/export/blob/S3BlobStoreRepositoryTest.java b/src/test/java/no/entur/uttu/export/blob/S3BlobStoreRepositoryTest.java index fab4e6ad..6ad38452 100644 --- a/src/test/java/no/entur/uttu/export/blob/S3BlobStoreRepositoryTest.java +++ b/src/test/java/no/entur/uttu/export/blob/S3BlobStoreRepositoryTest.java @@ -1,7 +1,5 @@ package no.entur.uttu.export.blob; -import java.io.ByteArrayInputStream; -import java.nio.charset.StandardCharsets; import no.entur.uttu.UttuIntegrationTest; import org.jetbrains.annotations.NotNull; import org.junit.Assert; @@ -9,6 +7,7 @@ import org.junit.BeforeClass; import org.junit.Test; import org.rutebanken.helper.storage.BlobAlreadyExistsException; +import org.rutebanken.helper.storage.model.BlobDescriptor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.DynamicPropertyRegistry; @@ -23,6 +22,11 @@ import software.amazon.awssdk.services.s3.model.NoSuchBucketException; import software.amazon.awssdk.services.s3.model.NoSuchKeyException; +import java.io.ByteArrayInputStream; +import java.nio.charset.StandardCharsets; +import java.util.Map; +import java.util.Optional; + @Testcontainers @ActiveProfiles({ "s3-blobstore" }) public class S3BlobStoreRepositoryTest extends UttuIntegrationTest { @@ -168,11 +172,37 @@ public void canCopyAllBlobsWithSharedPrefix() throws Exception { assertBlobExists(targetBucket, "stuff/d", false); } + @Test + public void attachesGivenMetadataToUploadWhenPresent() { + String customBucket = "metadata-bucket"; + createBucket(customBucket); + blobStore.setContainerName(customBucket); + Map metadata = Map.of("metadata.test", "testing"); + blobStore.uploadBlob( + new BlobDescriptor( + "things/a", + asStream("a"), + Optional.empty(), + Optional.of(metadata) + ) + ); + assertBlobExists(customBucket, "things/a", true, metadata); + } + private static @NotNull ByteArrayInputStream asStream(String source) { return new ByteArrayInputStream(source.getBytes(StandardCharsets.UTF_8)); } private void assertBlobExists(String bucket, String key, boolean exists) { + assertBlobExists(bucket, key, exists, null); + } + + private void assertBlobExists( + String bucket, + String key, + boolean exists, + Map expectedMetadata + ) { HeadObjectResponse response = null; try { response = s3Client.headObject(request -> request.bucket(bucket).key(key)); @@ -183,5 +213,8 @@ private void assertBlobExists(String bucket, String key, boolean exists) { if (exists && response == null) { Assert.fail(bucket + " / " + key + " does not exist"); } + if (expectedMetadata != null) { + Assert.assertEquals(response.metadata(), expectedMetadata); + } } }