diff --git a/README.md b/README.md index 7869986a0..de1e5fc06 100644 --- a/README.md +++ b/README.md @@ -108,6 +108,14 @@ |---------------------------------------------------------------------------------------------------------------------|--------------------------------|--------------------------------| | [spring-petclinic-microservices](spring-petclinic-microservices) | ✅ | ❌ | +### TestContainers Support + +| Sample Project | Support Spring Cloud Azure 4.x | Support Spring Cloud Azure 5.x | +|------------------------------------------------------------------|--------------------------------|--------------------------------| +| [testContainers for Cosmos](testcontainers/cosmos) | ❌ | ✅ | +| [testContainers for Storage Blob](testcontainers/storage-blob) | ❌ | ✅ | +| [testContainers for Storage Queue](testcontainers/storage-queue) | ❌ | ✅ | + ## Getting Help - If you have any question about using these samples, please [create an new issue](https://github.com/Azure-Samples/azure-spring-boot-samples/issues/new/choose). diff --git a/pom.xml b/pom.xml index 102b82392..180eb8e9f 100644 --- a/pom.xml +++ b/pom.xml @@ -195,6 +195,9 @@ storage/spring-cloud-azure-starter-integration-storage-queue/storage-queue-integration storage/spring-cloud-azure-starter-storage-queue/storage-queue-client storage/spring-messaging-azure-storage-queue/storage-queue-spring-messaging + testcontainers/cosmos + testcontainers/storage-blob + testcontainers/storage-queue true @@ -208,7 +211,7 @@ 5.15.0 3.1.1.RELEASE 3.1.0 - + 1.20.0 2.22.0 4.11.0 @@ -224,6 +227,11 @@ jakarta.persistence-api ${version.jakarta-persistence} + + org.testcontainers + azure + ${version.testcontainers.azure} + diff --git a/testcontainers/README.md b/testcontainers/README.md new file mode 100644 index 000000000..e756b544c --- /dev/null +++ b/testcontainers/README.md @@ -0,0 +1,43 @@ +--- +page_type: sample +languages: +- java +products: +- spring-cloud-azure-testcontainers +name: Spring Cloud Azure Testcontainers samples +description: These samples demonstrates how to use Spring Cloud Azure Testcontainers in test cases. +--- + +# Testcontainers Service Connection Samples for Spring Cloud Azure +Testcontainers is an open source framework for providing throwaway, lightweight instances of databases, message brokers, web browsers, or just about anything that can run in a Docker container. + +We provide `spring-cloud-azure-testcontainers` library to support Testcontainers in Spring Cloud Azure. It allows you to write a test class that can start up a container before any of the tests run. Testcontainers is especially useful for writing integration tests that talk to a real backend service. + +This sample project demonstrates how to use Testcontainers Service Connection with Azure Cosmos DB, Azure Storage Blob, and Azure Storage Queue in test cases. + +## What You Need + +- [Docker environment](https://java.testcontainers.org/supported_docker_environment/) +- [JDK8](https://www.oracle.com/java/technologies/downloads/) or later +- Maven +- You can also import the code straight into your IDE: + - [IntelliJ IDEA](https://www.jetbrains.com/idea/download) + +## Run Locally +With docker environment running, you can directly run the tests. + +### Run the sample with Maven + +In your terminal, run `mvn clean test`. + +```shell +mvn clean test +``` + +### Run the sample in IDEs + +You can debug your sample by IDEs. + +* If your tool is `IDEA`, please refer to [Debug your first Java application](https://www.jetbrains.com/help/idea/debugging-your-first-java-application.html) and [add environment variables](https://www.jetbrains.com/help/objc/add-environment-variables-and-program-arguments.html#add-environment-variables). + +* If your tool is `ECLIPSE`, please refer to [Debugging the Eclipse IDE for Java Developers](https://www.eclipse.org/community/eclipse_newsletter/2017/june/article1.php) and [Eclipse Environment Variable Setup](https://examples.javacodegeeks.com/desktop-java/ide/eclipse/eclipse-environment-variable-setup-example). diff --git a/testcontainers/cosmos/pom.xml b/testcontainers/cosmos/pom.xml new file mode 100644 index 000000000..de69c606e --- /dev/null +++ b/testcontainers/cosmos/pom.xml @@ -0,0 +1,68 @@ + + + 4.0.0 + + + com.azure.spring + azure-spring-boot-samples + 1.0.0 + ../../pom.xml + + + spring-cloud-azure-testcontainers-for-cosmos-sample + 1.0.0 + jar + + TestContainers for Azure Cosmos DB + + + + com.azure.spring + spring-cloud-azure-starter-cosmos + test + + + com.azure.spring + spring-cloud-azure-testcontainers + test + + + org.testcontainers + junit-jupiter + test + + + org.testcontainers + azure + test + + + org.springframework.boot + spring-boot-test + test + + + org.junit.jupiter + junit-jupiter-api + test + + + org.assertj + assertj-core + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + true + + + + + diff --git a/testcontainers/cosmos/src/test/java/CosmosTestcontainersTest.java b/testcontainers/cosmos/src/test/java/CosmosTestcontainersTest.java new file mode 100644 index 000000000..e36e96ead --- /dev/null +++ b/testcontainers/cosmos/src/test/java/CosmosTestcontainersTest.java @@ -0,0 +1,72 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +import com.azure.cosmos.CosmosClient; +import com.azure.cosmos.models.CosmosContainerResponse; +import com.azure.cosmos.models.CosmosDatabaseResponse; +import com.azure.spring.cloud.autoconfigure.implementation.context.AzureGlobalPropertiesAutoConfiguration; +import com.azure.spring.cloud.autoconfigure.implementation.cosmos.AzureCosmosAutoConfiguration; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.jupiter.api.io.TempDir; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.ImportAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.testcontainers.service.connection.ServiceConnection; +import org.springframework.test.context.junit4.SpringRunner; +import org.testcontainers.containers.CosmosDBEmulatorContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; +import org.testcontainers.utility.DockerImageName; + +import java.io.File; +import java.nio.file.Files; +import java.nio.file.Path; +import java.security.KeyStore; + +import static org.assertj.core.api.Assertions.assertThat; + +@SpringBootTest(classes = CosmosTestcontainersTest.class) +@Testcontainers +@RunWith(SpringRunner.class) +@ImportAutoConfiguration(classes = { AzureGlobalPropertiesAutoConfiguration.class, AzureCosmosAutoConfiguration.class}) +public class CosmosTestcontainersTest { + + @TempDir + private static File tempFolder; + + @Autowired + private CosmosClient client; + + @Container + @ServiceConnection + static CosmosDBEmulatorContainer cosmos = new CosmosDBEmulatorContainer( + DockerImageName.parse("mcr.microsoft.com/cosmosdb/linux/azure-cosmos-emulator:latest")); + + @BeforeClass + public static void setup() { + cosmos.start(); + Path keyStoreFile = new File(tempFolder, "azure-cosmos-emulator.keystore").toPath(); + KeyStore keyStore = cosmos.buildNewKeyStore(); + try { + keyStore.store(Files.newOutputStream(keyStoreFile.toFile().toPath()), cosmos.getEmulatorKey().toCharArray()); + } catch (Exception e) { + throw new RuntimeException(e); + } + + System.setProperty("javax.net.ssl.trustStore", keyStoreFile.toString()); + System.setProperty("javax.net.ssl.trustStorePassword", cosmos.getEmulatorKey()); + System.setProperty("javax.net.ssl.trustStoreType", "PKCS12"); + } + + @Test + public void test() { + CosmosDatabaseResponse databaseResponse = client.createDatabaseIfNotExists("Azure"); + assertThat(databaseResponse.getStatusCode()).isEqualTo(201); + CosmosContainerResponse containerResponse = client + .getDatabase("Azure") + .createContainerIfNotExists("ServiceContainer", "/name"); + assertThat(containerResponse.getStatusCode()).isEqualTo(201); + } + +} diff --git a/testcontainers/storage-blob/pom.xml b/testcontainers/storage-blob/pom.xml new file mode 100644 index 000000000..d3a9bf0f4 --- /dev/null +++ b/testcontainers/storage-blob/pom.xml @@ -0,0 +1,59 @@ + + + 4.0.0 + + + com.azure.spring + azure-spring-boot-samples + 1.0.0 + ../../pom.xml + + + spring-cloud-azure-testcontainers-for-storage-blob-sample + 1.0.0 + jar + + TestContainers for Azure Storage Blob + + + + com.azure.spring + spring-cloud-azure-starter-storage-blob + test + + + com.azure.spring + spring-cloud-azure-testcontainers + test + + + org.springframework.boot + spring-boot-test + test + + + org.assertj + assertj-core + test + + + org.testcontainers + junit-jupiter + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + true + + + + + diff --git a/testcontainers/storage-blob/src/test/java/StorageBlobTestcontainersTest.java b/testcontainers/storage-blob/src/test/java/StorageBlobTestcontainersTest.java new file mode 100644 index 000000000..7f2bd1ae8 --- /dev/null +++ b/testcontainers/storage-blob/src/test/java/StorageBlobTestcontainersTest.java @@ -0,0 +1,56 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +import com.azure.spring.cloud.autoconfigure.implementation.context.AzureGlobalPropertiesAutoConfiguration; +import com.azure.spring.cloud.autoconfigure.implementation.storage.blob.AzureStorageBlobAutoConfiguration; +import com.azure.spring.cloud.autoconfigure.implementation.storage.blob.AzureStorageBlobResourceAutoConfiguration; +import org.junit.BeforeClass; +import org.junit.Test; + +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.ImportAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.testcontainers.service.connection.ServiceConnection; +import org.springframework.core.io.Resource; +import org.springframework.core.io.WritableResource; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.util.StreamUtils; +import org.testcontainers.containers.GenericContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; + +import java.io.IOException; +import java.io.OutputStream; +import java.nio.charset.Charset; +import static org.assertj.core.api.Assertions.assertThat; + +@SpringBootTest(classes = StorageBlobTestcontainersTest.class) +@Testcontainers +@RunWith(SpringRunner.class) +@ImportAutoConfiguration(classes = { AzureGlobalPropertiesAutoConfiguration.class, AzureStorageBlobAutoConfiguration.class, AzureStorageBlobResourceAutoConfiguration.class}) +public class StorageBlobTestcontainersTest { + @Container + @ServiceConnection + private static final GenericContainer AZURITE_CONTAINER = new GenericContainer<>( + "mcr.microsoft.com/azure-storage/azurite:latest") + .withExposedPorts(10000); + + @Value("azure-blob://testcontainers/message.txt") + private Resource blobFile; + + @BeforeClass + public static void setup() { + AZURITE_CONTAINER.start(); + } + + @Test + public void test() throws IOException { + String originalContent = "Hello World!"; + try (OutputStream os = ((WritableResource) this.blobFile).getOutputStream()) { + os.write(originalContent.getBytes()); + } + String resultContent = StreamUtils.copyToString(this.blobFile.getInputStream(), Charset.defaultCharset()); + assertThat(resultContent).isEqualTo(originalContent); + } + +} diff --git a/testcontainers/storage-queue/pom.xml b/testcontainers/storage-queue/pom.xml new file mode 100644 index 000000000..b28988ade --- /dev/null +++ b/testcontainers/storage-queue/pom.xml @@ -0,0 +1,58 @@ + + + 4.0.0 + + + com.azure.spring + azure-spring-boot-samples + 1.0.0 + ../../pom.xml + + + spring-cloud-azure-testcontainers-for-storage-queue-sample + 1.0.0 + jar + TestContainers for Storage Queue + + + + com.azure.spring + spring-cloud-azure-starter-storage-queue + test + + + com.azure.spring + spring-cloud-azure-testcontainers + test + + + org.testcontainers + junit-jupiter + test + + + org.springframework.boot + spring-boot-test + test + + + org.assertj + assertj-core + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + true + + + + + diff --git a/testcontainers/storage-queue/src/test/java/StorageQueueTestcontainersTest.java b/testcontainers/storage-queue/src/test/java/StorageQueueTestcontainersTest.java new file mode 100644 index 000000000..48f8faab7 --- /dev/null +++ b/testcontainers/storage-queue/src/test/java/StorageQueueTestcontainersTest.java @@ -0,0 +1,52 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +import com.azure.spring.cloud.autoconfigure.implementation.context.AzureGlobalPropertiesAutoConfiguration; +import com.azure.spring.cloud.autoconfigure.implementation.storage.queue.AzureStorageQueueAutoConfiguration; +import com.azure.storage.queue.QueueClient; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.ImportAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.testcontainers.service.connection.ServiceConnection; + +import org.springframework.test.context.TestPropertySource; + +import org.springframework.test.context.junit4.SpringRunner; +import org.testcontainers.containers.GenericContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; + +import static org.assertj.core.api.Assertions.assertThat; + +@SpringBootTest(classes = StorageQueueTestcontainersTest.class) +@Testcontainers +@TestPropertySource(properties = "spring.cloud.azure.storage.queue.queue-name=devstoreaccount1/tc-queue") +@RunWith(SpringRunner.class) +@ImportAutoConfiguration(classes = { AzureGlobalPropertiesAutoConfiguration.class, AzureStorageQueueAutoConfiguration.class}) +public class StorageQueueTestcontainersTest { + + @Container + @ServiceConnection + private static final GenericContainer AZURITE_CONTAINER = new GenericContainer<>( + "mcr.microsoft.com/azure-storage/azurite:latest") + .withExposedPorts(10001); + + @Autowired + private QueueClient queueClient; + + @BeforeClass + public static void setup() { + AZURITE_CONTAINER.start(); + } + + @Test + public void test() { + String message = "Hello World!"; + this.queueClient.create(); + this.queueClient.sendMessage(message); + assertThat(this.queueClient.receiveMessage().getBody().toString()).isEqualTo(message); + } + +}