From 615bd88777c9776cc1dc2df1c3df34726fd5301f Mon Sep 17 00:00:00 2001 From: "emanuel.trandafir" Date: Wed, 20 Nov 2024 15:54:58 +0100 Subject: [PATCH 1/3] google cloud storage emulator --- docs/modules/gcloud.md | 12 ++- modules/gcloud/build.gradle | 1 + .../CloudStorageEmulatorContainer.java | 74 +++++++++++++++++++ .../CloudStorageEmulatorContainerTest.java | 44 +++++++++++ 4 files changed, 130 insertions(+), 1 deletion(-) create mode 100644 modules/gcloud/src/main/java/org/testcontainers/containers/CloudStorageEmulatorContainer.java create mode 100644 modules/gcloud/src/test/java/org/testcontainers/containers/CloudStorageEmulatorContainerTest.java diff --git a/docs/modules/gcloud.md b/docs/modules/gcloud.md index 049931b3be1..84fab5e0e3b 100644 --- a/docs/modules/gcloud.md +++ b/docs/modules/gcloud.md @@ -5,7 +5,7 @@ Testcontainers module for the Google Cloud Platform's [Cloud SDK](https://cloud.google.com/sdk/). -Currently, the module supports `BigQuery`, `Bigtable`, `Datastore`, `Firestore`, `Spanner`, and `Pub/Sub` emulators. In order to use it, you should use the following classes: +Currently, the module supports `BigQuery`, `Bigtable`, `Datastore`, `Firestore`, `Spanner`, `Pub/Sub`, and `CloudStorage` emulators. In order to use it, you should use the following classes: Class | Container Image -|- @@ -15,6 +15,7 @@ DatastoreEmulatorContainer | [gcr.io/google.com/cloudsdktool/google-cloud-cli:em FirestoreEmulatorContainer | [gcr.io/google.com/cloudsdktool/google-cloud-cli:emulators](https://gcr.io/google.com/cloudsdktool/google-cloud-cli) SpannerEmulatorContainer | [gcr.io/cloud-spanner-emulator/emulator](https://gcr.io/cloud-spanner-emulator/emulator) PubSubEmulatorContainer | [gcr.io/google.com/cloudsdktool/google-cloud-cli:emulators](https://gcr.io/google.com/cloudsdktool/google-cloud-cli) +CloudStorageEmulatorContainer | [hub.docker.com/r/fsouza/fake-gcs-server](https://hub.docker.com/r/fsouza/fake-gcs-server) ## Usage example @@ -150,6 +151,15 @@ See more examples: * [Full sample code](https://github.com/testcontainers/testcontainers-java/tree/main/modules/gcloud/src/test/java/org/testcontainers/containers/PubSubEmulatorContainerTest.java) * [With Spring Boot](https://github.com/saturnism/testcontainers-gcloud-examples/tree/main/springboot/pubsub-example/src/test/java/com/example/springboot/pubsub/PubSubIntegrationTests.java) +### CloudStorage + +Start the CloudStorage emulator and test against it: + + +[Testing with a CloudStorage Emulator container](../../modules/gcloud/src/test/java/org/testcontainers/containers/CloudStorageEmulatorContainerTest.java) inside_block:testWithCloudStorageEmulatorContainer + + + ## Adding this module to your project dependencies Add the following dependency to your `pom.xml`/`build.gradle` file: diff --git a/modules/gcloud/build.gradle b/modules/gcloud/build.gradle index cb55e466e22..a8c75d357bf 100644 --- a/modules/gcloud/build.gradle +++ b/modules/gcloud/build.gradle @@ -10,5 +10,6 @@ dependencies { testImplementation 'com.google.cloud:google-cloud-pubsub' testImplementation 'com.google.cloud:google-cloud-spanner' testImplementation 'com.google.cloud:google-cloud-bigtable' + testImplementation 'com.google.cloud:google-cloud-storage' testImplementation 'org.assertj:assertj-core:3.26.3' } diff --git a/modules/gcloud/src/main/java/org/testcontainers/containers/CloudStorageEmulatorContainer.java b/modules/gcloud/src/main/java/org/testcontainers/containers/CloudStorageEmulatorContainer.java new file mode 100644 index 00000000000..8a20e9d52e6 --- /dev/null +++ b/modules/gcloud/src/main/java/org/testcontainers/containers/CloudStorageEmulatorContainer.java @@ -0,0 +1,74 @@ +package org.testcontainers.containers; + +import org.testcontainers.containers.wait.strategy.WaitStrategy; +import org.testcontainers.containers.wait.strategy.WaitStrategyTarget; +import org.testcontainers.utility.DockerImageName; + +import java.io.IOException; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.time.Duration; + +/** + * Testcontainers implementation for Google Cloud Storage. + * Default port: 4443 + *

+ * Supported image: {@code fsouza/fake-gcs-server} + *

+ * @see fsouza/fake-gcs-server on GitHub + */ +public class CloudStorageEmulatorContainer extends GenericContainer { + + public static final DockerImageName DEFAULT_IMAGE = DockerImageName.parse("fsouza/fake-gcs-server"); + public static final int EMULATOR_PORT = 4443; + + public CloudStorageEmulatorContainer(String image) { + this(DockerImageName.parse(image)); + } + + public CloudStorageEmulatorContainer(DockerImageName dockerImageName) { + super(dockerImageName); + dockerImageName.assertCompatibleWith(DEFAULT_IMAGE); + addExposedPorts(EMULATOR_PORT); + withCreateContainerCmdModifier(cmd -> cmd.withEntrypoint("/bin/fake-gcs-server", "-scheme", "http")); + waitingFor(new WaitStrategy() { + @Override + public void waitUntilReady(WaitStrategyTarget target) { + updateFakeGcsExternalUrl(getEmulatorHttpEndpoint()); + } + + @Override + public WaitStrategy withStartupTimeout(Duration startupTimeout) { + return getWaitStrategy().withStartupTimeout(startupTimeout); + } + }); + } + + public String getEmulatorHttpEndpoint() { + return String.format("http://%s:%d", getHost(), getMappedPort(EMULATOR_PORT)); + } + + private static void updateFakeGcsExternalUrl(String gcsUrl) { + String json = String.format("{ \"externalUrl\": \"%s\" }", gcsUrl); + + HttpRequest req = HttpRequest.newBuilder() + .uri(URI.create(gcsUrl + "/_internal/config")) + .header("Content-Type", "application/json") + .PUT(HttpRequest.BodyPublishers.ofString(json)) + .build(); + + try { + HttpResponse response = HttpClient.newBuilder().build() + .send(req, HttpResponse.BodyHandlers.discarding()); + + if (response.statusCode() != 200) { + throw new RuntimeException( + "error updating fake-gcs-server with external url, response status code " + response.statusCode() + " != 200"); + } + } catch (IOException | InterruptedException e) { + throw new RuntimeException(e); + } + } +} diff --git a/modules/gcloud/src/test/java/org/testcontainers/containers/CloudStorageEmulatorContainerTest.java b/modules/gcloud/src/test/java/org/testcontainers/containers/CloudStorageEmulatorContainerTest.java new file mode 100644 index 00000000000..bc69d0102a3 --- /dev/null +++ b/modules/gcloud/src/test/java/org/testcontainers/containers/CloudStorageEmulatorContainerTest.java @@ -0,0 +1,44 @@ +package org.testcontainers.containers; + +import com.google.cloud.NoCredentials; +import com.google.cloud.storage.*; +import org.junit.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +public class CloudStorageEmulatorContainerTest { + + // testWithCloudStorageEmulatorContainer { + @Test + public void shouldWriteAndReadFile() { + final String BUCKET_NAME = "test-bucket"; + final String FILE_NAME = "test-file.txt"; + final String FILE_CONTENT = "test file content"; + + try ( + CloudStorageEmulatorContainer container = new CloudStorageEmulatorContainer("fsouza/fake-gcs-server:1.50.2") + ) { + container.start(); + + Storage storageClient = StorageOptions.newBuilder() + .setHost(container.getEmulatorHttpEndpoint()) + .setProjectId("test-project") + .setCredentials(NoCredentials.getInstance()) + .build() + .getService(); + storageClient.create(BucketInfo.of(BUCKET_NAME)); + + storageClient.create( + BlobInfo.newBuilder(BUCKET_NAME, FILE_NAME).build(), + FILE_CONTENT.getBytes() + ); + + Blob blob = storageClient.get(BUCKET_NAME, FILE_NAME); + assertThat(blob.getContent()) + .asString() + .isEqualTo(FILE_CONTENT); + } + } + // } + +} From 817c3e6ee1c0008beb46d8607db7510aaf1ec88e Mon Sep 17 00:00:00 2001 From: "emanuel.trandafir" Date: Wed, 20 Nov 2024 16:44:40 +0100 Subject: [PATCH 2/3] code formatting --- .../CloudStorageEmulatorContainer.java | 73 +++++++++++-------- .../CloudStorageEmulatorContainerTest.java | 66 ++++++++--------- 2 files changed, 74 insertions(+), 65 deletions(-) diff --git a/modules/gcloud/src/main/java/org/testcontainers/containers/CloudStorageEmulatorContainer.java b/modules/gcloud/src/main/java/org/testcontainers/containers/CloudStorageEmulatorContainer.java index 8a20e9d52e6..4dffbcf19b5 100644 --- a/modules/gcloud/src/main/java/org/testcontainers/containers/CloudStorageEmulatorContainer.java +++ b/modules/gcloud/src/main/java/org/testcontainers/containers/CloudStorageEmulatorContainer.java @@ -21,51 +21,60 @@ */ public class CloudStorageEmulatorContainer extends GenericContainer { - public static final DockerImageName DEFAULT_IMAGE = DockerImageName.parse("fsouza/fake-gcs-server"); - public static final int EMULATOR_PORT = 4443; + public static final DockerImageName DEFAULT_IMAGE = DockerImageName.parse("fsouza/fake-gcs-server"); - public CloudStorageEmulatorContainer(String image) { - this(DockerImageName.parse(image)); - } + public static final int EMULATOR_PORT = 4443; - public CloudStorageEmulatorContainer(DockerImageName dockerImageName) { - super(dockerImageName); - dockerImageName.assertCompatibleWith(DEFAULT_IMAGE); - addExposedPorts(EMULATOR_PORT); - withCreateContainerCmdModifier(cmd -> cmd.withEntrypoint("/bin/fake-gcs-server", "-scheme", "http")); - waitingFor(new WaitStrategy() { - @Override - public void waitUntilReady(WaitStrategyTarget target) { - updateFakeGcsExternalUrl(getEmulatorHttpEndpoint()); - } + public CloudStorageEmulatorContainer(String image) { + this(DockerImageName.parse(image)); + } - @Override - public WaitStrategy withStartupTimeout(Duration startupTimeout) { - return getWaitStrategy().withStartupTimeout(startupTimeout); - } - }); - } + public CloudStorageEmulatorContainer(DockerImageName dockerImageName) { + super(dockerImageName); + dockerImageName.assertCompatibleWith(DEFAULT_IMAGE); + addExposedPorts(EMULATOR_PORT); + withCreateContainerCmdModifier(cmd -> cmd.withEntrypoint("/bin/fake-gcs-server", "-scheme", "http")); + waitingFor( + new WaitStrategy() { + @Override + public void waitUntilReady(WaitStrategyTarget target) { + updateFakeGcsExternalUrl(getEmulatorHttpEndpoint()); + } - public String getEmulatorHttpEndpoint() { - return String.format("http://%s:%d", getHost(), getMappedPort(EMULATOR_PORT)); - } + @Override + public WaitStrategy withStartupTimeout(Duration startupTimeout) { + return getWaitStrategy().withStartupTimeout(startupTimeout); + } + } + ); + } + + public String getEmulatorHttpEndpoint() { + return String.format("http://%s:%d", getHost(), getMappedPort(EMULATOR_PORT)); + } private static void updateFakeGcsExternalUrl(String gcsUrl) { String json = String.format("{ \"externalUrl\": \"%s\" }", gcsUrl); - HttpRequest req = HttpRequest.newBuilder() - .uri(URI.create(gcsUrl + "/_internal/config")) - .header("Content-Type", "application/json") - .PUT(HttpRequest.BodyPublishers.ofString(json)) - .build(); + HttpRequest req = HttpRequest + .newBuilder() + .uri(URI.create(gcsUrl + "/_internal/config")) + .header("Content-Type", "application/json") + .PUT(HttpRequest.BodyPublishers.ofString(json)) + .build(); try { - HttpResponse response = HttpClient.newBuilder().build() - .send(req, HttpResponse.BodyHandlers.discarding()); + HttpResponse response = HttpClient + .newBuilder() + .build() + .send(req, HttpResponse.BodyHandlers.discarding()); if (response.statusCode() != 200) { throw new RuntimeException( - "error updating fake-gcs-server with external url, response status code " + response.statusCode() + " != 200"); + "error updating fake-gcs-server with external url, response status code " + + response.statusCode() + + " != 200" + ); } } catch (IOException | InterruptedException e) { throw new RuntimeException(e); diff --git a/modules/gcloud/src/test/java/org/testcontainers/containers/CloudStorageEmulatorContainerTest.java b/modules/gcloud/src/test/java/org/testcontainers/containers/CloudStorageEmulatorContainerTest.java index bc69d0102a3..e7e2baab0de 100644 --- a/modules/gcloud/src/test/java/org/testcontainers/containers/CloudStorageEmulatorContainerTest.java +++ b/modules/gcloud/src/test/java/org/testcontainers/containers/CloudStorageEmulatorContainerTest.java @@ -1,44 +1,44 @@ package org.testcontainers.containers; import com.google.cloud.NoCredentials; -import com.google.cloud.storage.*; +import com.google.cloud.storage.Blob; +import com.google.cloud.storage.BlobInfo; +import com.google.cloud.storage.BucketInfo; +import com.google.cloud.storage.Storage; +import com.google.cloud.storage.StorageOptions; import org.junit.Test; import static org.assertj.core.api.Assertions.assertThat; public class CloudStorageEmulatorContainerTest { - // testWithCloudStorageEmulatorContainer { - @Test - public void shouldWriteAndReadFile() { - final String BUCKET_NAME = "test-bucket"; - final String FILE_NAME = "test-file.txt"; - final String FILE_CONTENT = "test file content"; - - try ( - CloudStorageEmulatorContainer container = new CloudStorageEmulatorContainer("fsouza/fake-gcs-server:1.50.2") - ) { - container.start(); - - Storage storageClient = StorageOptions.newBuilder() - .setHost(container.getEmulatorHttpEndpoint()) - .setProjectId("test-project") - .setCredentials(NoCredentials.getInstance()) - .build() - .getService(); - storageClient.create(BucketInfo.of(BUCKET_NAME)); - - storageClient.create( - BlobInfo.newBuilder(BUCKET_NAME, FILE_NAME).build(), - FILE_CONTENT.getBytes() - ); - - Blob blob = storageClient.get(BUCKET_NAME, FILE_NAME); - assertThat(blob.getContent()) - .asString() - .isEqualTo(FILE_CONTENT); - } - } - // } + // testWithCloudStorageEmulatorContainer { + @Test + public void shouldWriteAndReadFile() { + final String BUCKET_NAME = "test-bucket"; + final String FILE_NAME = "test-file.txt"; + final String FILE_CONTENT = "test file content"; + + try ( + CloudStorageEmulatorContainer container = new CloudStorageEmulatorContainer("fsouza/fake-gcs-server:1.50.2") + ) { + container.start(); + + Storage storageClient = StorageOptions + .newBuilder() + .setHost(container.getEmulatorHttpEndpoint()) + .setProjectId("test-project") + .setCredentials(NoCredentials.getInstance()) + .build() + .getService(); + storageClient.create(BucketInfo.of(BUCKET_NAME)); + + storageClient.create(BlobInfo.newBuilder(BUCKET_NAME, FILE_NAME).build(), FILE_CONTENT.getBytes()); + + Blob blob = storageClient.get(BUCKET_NAME, FILE_NAME); + assertThat(blob.getContent()).asString().isEqualTo(FILE_CONTENT); + } + } + // } } From fc81661025f52761807b14f66a00bc00f3389f3f Mon Sep 17 00:00:00 2001 From: "emanuel.trandafir" Date: Wed, 20 Nov 2024 16:47:55 +0100 Subject: [PATCH 3/3] update javadoc --- .../containers/CloudStorageEmulatorContainer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/gcloud/src/main/java/org/testcontainers/containers/CloudStorageEmulatorContainer.java b/modules/gcloud/src/main/java/org/testcontainers/containers/CloudStorageEmulatorContainer.java index 4dffbcf19b5..48d68a81c18 100644 --- a/modules/gcloud/src/main/java/org/testcontainers/containers/CloudStorageEmulatorContainer.java +++ b/modules/gcloud/src/main/java/org/testcontainers/containers/CloudStorageEmulatorContainer.java @@ -15,7 +15,7 @@ * Testcontainers implementation for Google Cloud Storage. * Default port: 4443 *

- * Supported image: {@code fsouza/fake-gcs-server} + * Supported image: {@code hub.docker.com/r/fsouza/fake-gcs-server} *

* @see fsouza/fake-gcs-server on GitHub */