Skip to content

Commit

Permalink
Add AzuriteContainer to Azure module (#9661)
Browse files Browse the repository at this point in the history
Signed-off-by: Esta Nagy <[email protected]>
Co-authored-by: Eddú Meléndez <[email protected]>
  • Loading branch information
nagyesta and eddumelendez authored Jan 9, 2025
1 parent f7973aa commit 2707f31
Show file tree
Hide file tree
Showing 7 changed files with 551 additions and 1 deletion.
61 changes: 60 additions & 1 deletion docs/modules/azure.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,73 @@ This module is INCUBATING. While it is ready for use and operational in the curr

Testcontainers module for the Microsoft Azure's [SDK](https://github.com/Azure/azure-sdk-for-java).

Currently, the module supports `CosmosDB` emulator. In order to use it, you should use the following class:
Currently, the module supports `Azurite` and `CosmosDB` emulators. In order to use them, you should use the following classes:

Class | Container Image
-|-
AzuriteContainer | [mcr.microsoft.com/azure-storage/azurite](https://github.com/microsoft/containerregistry)
CosmosDBEmulatorContainer | [mcr.microsoft.com/cosmosdb/linux/azure-cosmos-emulator](https://github.com/microsoft/containerregistry)

## Usage example

### Azurite Storage Emulator

Start Azurite Emulator during a test:

<!--codeinclude-->
[Starting a Azurite container](../../modules/azure/src/test/java/org/testcontainers/azure/AzuriteContainerTest.java) inside_block:emulatorContainer
<!--/codeinclude-->

!!! note
SSL configuration is possible using the `withSsl(MountableFile, String)` and `withSsl(MountableFile, MountableFile)` methods.

If the tested application needs to use more than one set of credentials, the container can be configured to use custom credentials.
Please see some examples below.

<!--codeinclude-->
[Starting a Azurite Blob container with one account and two keys](../../modules/azure/src/test/java/org/testcontainers/azure/AzuriteContainerTest.java) inside_block:withTwoAccountKeys
<!--/codeinclude-->

<!--codeinclude-->
[Starting a Azurite Blob container with more accounts and keys](../../modules/azure/src/test/java/org/testcontainers/azure/AzuriteContainerTest.java) inside_block:withMoreAccounts
<!--/codeinclude-->

#### Using with Blob

Build Azure Blob client:

<!--codeinclude-->
[Build Azure Blob Service client](../../modules/azure/src/test/java/org/testcontainers/azure/AzuriteContainerTest.java) inside_block:createBlobClient
<!--/codeinclude-->

In case the application needs to use custom credentials, we can obtain them with a different method:

<!--codeinclude-->
[Obtain connection string with non-default credentials](../../modules/azure/src/test/java/org/testcontainers/azure/AzuriteContainerTest.java) inside_block:useNonDefaultCredentials
<!--/codeinclude-->

#### Using with Queue

Build Azure Queue client:

<!--codeinclude-->
[Build Azure Queue Service client](../../modules/azure/src/test/java/org/testcontainers/azure/AzuriteContainerTest.java) inside_block:createQueueClient
<!--/codeinclude-->

!!! note
We can use custom credentials the same way as defined in the Blob section.

#### Using with Table

Build Azure Table client:

<!--codeinclude-->
[Build Azure Table Service client](../../modules/azure/src/test/java/org/testcontainers/azure/AzuriteContainerTest.java) inside_block:createTableClient
<!--/codeinclude-->

!!! note
We can use custom credentials the same way as defined in the Blob section.

### CosmosDB

Start Azure CosmosDB Emulator during a test:
Expand Down
3 changes: 3 additions & 0 deletions modules/azure/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,7 @@ dependencies {

testImplementation 'org.assertj:assertj-core:3.26.3'
testImplementation 'com.azure:azure-cosmos:4.63.3'
testImplementation 'com.azure:azure-storage-blob:12.29.0'
testImplementation 'com.azure:azure-storage-queue:12.24.0'
testImplementation 'com.azure:azure-data-tables:12.5.0'
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
package org.testcontainers.azure;

import org.testcontainers.containers.GenericContainer;
import org.testcontainers.utility.DockerImageName;
import org.testcontainers.utility.MountableFile;

/**
* Testcontainers implementation for Azurite Emulator.
* <p>
* Supported image: {@code mcr.microsoft.com/azure-storage/azurite}
* <p>
* Exposed ports:
* <ul>
* <li>Blob: 10000</li>
* <li>Queue: 10001</li>
* <li>Table: 10002</li>
* </ul>
*/
public class AzuriteContainer extends GenericContainer<AzuriteContainer> {

private static final String ALLOW_ALL_CONNECTIONS = "0.0.0.0";

private static final int DEFAULT_BLOB_PORT = 10000;

private static final int DEFAULT_QUEUE_PORT = 10001;

private static final int DEFAULT_TABLE_PORT = 10002;

private static final String CONNECTION_STRING_FORMAT =
"DefaultEndpointsProtocol=%s;AccountName=%s;AccountKey=%s;BlobEndpoint=%s://%s:%d/%s;QueueEndpoint=%s://%s:%d/%s;TableEndpoint=%s://%s:%d/%s;";

/**
* The account name of the default credentials.
*/
private static final String WELL_KNOWN_ACCOUNT_NAME = "devstoreaccount1";

/**
* The account key of the default credentials.
*/
private static final String WELL_KNOWN_ACCOUNT_KEY =
"Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==";

private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse(
"mcr.microsoft.com/azure-storage/azurite"
);

private MountableFile cert = null;

private String certExtension = null;

private MountableFile key = null;

private String pwd = null;

/**
* @param dockerImageName specified docker image name to run
*/
public AzuriteContainer(String dockerImageName) {
this(DockerImageName.parse(dockerImageName));
}

/**
* @param dockerImageName specified docker image name to run
*/
public AzuriteContainer(DockerImageName dockerImageName) {
super(dockerImageName);
dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME);
withExposedPorts(DEFAULT_BLOB_PORT, DEFAULT_QUEUE_PORT, DEFAULT_TABLE_PORT);
}

/**
* Configure SSL with a custom certificate and password.
*
* @param pfxCert The PFX certificate file
* @param password The password securing the certificate
* @return this
*/
public AzuriteContainer withSsl(final MountableFile pfxCert, final String password) {
this.cert = pfxCert;
this.pwd = password;
this.certExtension = ".pfx";
return this;
}

/**
* Configure SSL with a custom certificate and private key.
*
* @param pemCert The PEM certificate file
* @param pemKey The PEM key file
* @return this
*/
public AzuriteContainer withSsl(final MountableFile pemCert, final MountableFile pemKey) {
this.cert = pemCert;
this.key = pemKey;
this.certExtension = ".pem";
return this;
}

@Override
protected void configure() {
withCommand(getCommandLine());
if (this.cert != null) {
logger().info("Using path for cert file: '{}'", this.cert);
withCopyFileToContainer(this.cert, "/cert" + this.certExtension);
if (this.key != null) {
logger().info("Using path for key file: '{}'", this.key);
withCopyFileToContainer(this.key, "/key.pem");
}
}
}

/**
* Returns the connection string for the default credentials.
*
* @return connection string
*/
public String getConnectionString() {
return getConnectionString(WELL_KNOWN_ACCOUNT_NAME, WELL_KNOWN_ACCOUNT_KEY);
}

/**
* Returns the connection string for the account name and key specified.
*
* @param accountName The name of the account
* @param accountKey The account key
* @return connection string
*/
public String getConnectionString(final String accountName, final String accountKey) {
final String protocol = cert != null ? "https" : "http";
return String.format(
CONNECTION_STRING_FORMAT,
protocol,
accountName,
accountKey,
protocol,
getHost(),
getMappedPort(DEFAULT_BLOB_PORT),
accountName,
protocol,
getHost(),
getMappedPort(DEFAULT_QUEUE_PORT),
accountName,
protocol,
getHost(),
getMappedPort(DEFAULT_TABLE_PORT),
accountName
);
}

String getCommandLine() {
final StringBuilder args = new StringBuilder("azurite");
args.append(" --blobHost ").append(ALLOW_ALL_CONNECTIONS);
args.append(" --queueHost ").append(ALLOW_ALL_CONNECTIONS);
args.append(" --tableHost ").append(ALLOW_ALL_CONNECTIONS);
if (this.cert != null) {
args.append(" --cert ").append("/cert").append(this.certExtension);
if (this.pwd != null) {
args.append(" --pwd ").append(this.pwd);
} else {
args.append(" --key ").append("/key.pem");
}
}
final String cmd = args.toString();
logger().debug("Using command line: '{}'", cmd);
return cmd;
}
}
Loading

0 comments on commit 2707f31

Please sign in to comment.