Skip to content

Commit 2707f31

Browse files
Add AzuriteContainer to Azure module (#9661)
Signed-off-by: Esta Nagy <[email protected]> Co-authored-by: Eddú Meléndez <[email protected]>
1 parent f7973aa commit 2707f31

File tree

7 files changed

+551
-1
lines changed

7 files changed

+551
-1
lines changed

docs/modules/azure.md

+60-1
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,73 @@ This module is INCUBATING. While it is ready for use and operational in the curr
55

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

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

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

1415
## Usage example
1516

17+
### Azurite Storage Emulator
18+
19+
Start Azurite Emulator during a test:
20+
21+
<!--codeinclude-->
22+
[Starting a Azurite container](../../modules/azure/src/test/java/org/testcontainers/azure/AzuriteContainerTest.java) inside_block:emulatorContainer
23+
<!--/codeinclude-->
24+
25+
!!! note
26+
SSL configuration is possible using the `withSsl(MountableFile, String)` and `withSsl(MountableFile, MountableFile)` methods.
27+
28+
If the tested application needs to use more than one set of credentials, the container can be configured to use custom credentials.
29+
Please see some examples below.
30+
31+
<!--codeinclude-->
32+
[Starting a Azurite Blob container with one account and two keys](../../modules/azure/src/test/java/org/testcontainers/azure/AzuriteContainerTest.java) inside_block:withTwoAccountKeys
33+
<!--/codeinclude-->
34+
35+
<!--codeinclude-->
36+
[Starting a Azurite Blob container with more accounts and keys](../../modules/azure/src/test/java/org/testcontainers/azure/AzuriteContainerTest.java) inside_block:withMoreAccounts
37+
<!--/codeinclude-->
38+
39+
#### Using with Blob
40+
41+
Build Azure Blob client:
42+
43+
<!--codeinclude-->
44+
[Build Azure Blob Service client](../../modules/azure/src/test/java/org/testcontainers/azure/AzuriteContainerTest.java) inside_block:createBlobClient
45+
<!--/codeinclude-->
46+
47+
In case the application needs to use custom credentials, we can obtain them with a different method:
48+
49+
<!--codeinclude-->
50+
[Obtain connection string with non-default credentials](../../modules/azure/src/test/java/org/testcontainers/azure/AzuriteContainerTest.java) inside_block:useNonDefaultCredentials
51+
<!--/codeinclude-->
52+
53+
#### Using with Queue
54+
55+
Build Azure Queue client:
56+
57+
<!--codeinclude-->
58+
[Build Azure Queue Service client](../../modules/azure/src/test/java/org/testcontainers/azure/AzuriteContainerTest.java) inside_block:createQueueClient
59+
<!--/codeinclude-->
60+
61+
!!! note
62+
We can use custom credentials the same way as defined in the Blob section.
63+
64+
#### Using with Table
65+
66+
Build Azure Table client:
67+
68+
<!--codeinclude-->
69+
[Build Azure Table Service client](../../modules/azure/src/test/java/org/testcontainers/azure/AzuriteContainerTest.java) inside_block:createTableClient
70+
<!--/codeinclude-->
71+
72+
!!! note
73+
We can use custom credentials the same way as defined in the Blob section.
74+
1675
### CosmosDB
1776

1877
Start Azure CosmosDB Emulator during a test:

modules/azure/build.gradle

+3
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,7 @@ dependencies {
77

88
testImplementation 'org.assertj:assertj-core:3.26.3'
99
testImplementation 'com.azure:azure-cosmos:4.63.3'
10+
testImplementation 'com.azure:azure-storage-blob:12.29.0'
11+
testImplementation 'com.azure:azure-storage-queue:12.24.0'
12+
testImplementation 'com.azure:azure-data-tables:12.5.0'
1013
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
package org.testcontainers.azure;
2+
3+
import org.testcontainers.containers.GenericContainer;
4+
import org.testcontainers.utility.DockerImageName;
5+
import org.testcontainers.utility.MountableFile;
6+
7+
/**
8+
* Testcontainers implementation for Azurite Emulator.
9+
* <p>
10+
* Supported image: {@code mcr.microsoft.com/azure-storage/azurite}
11+
* <p>
12+
* Exposed ports:
13+
* <ul>
14+
* <li>Blob: 10000</li>
15+
* <li>Queue: 10001</li>
16+
* <li>Table: 10002</li>
17+
* </ul>
18+
*/
19+
public class AzuriteContainer extends GenericContainer<AzuriteContainer> {
20+
21+
private static final String ALLOW_ALL_CONNECTIONS = "0.0.0.0";
22+
23+
private static final int DEFAULT_BLOB_PORT = 10000;
24+
25+
private static final int DEFAULT_QUEUE_PORT = 10001;
26+
27+
private static final int DEFAULT_TABLE_PORT = 10002;
28+
29+
private static final String CONNECTION_STRING_FORMAT =
30+
"DefaultEndpointsProtocol=%s;AccountName=%s;AccountKey=%s;BlobEndpoint=%s://%s:%d/%s;QueueEndpoint=%s://%s:%d/%s;TableEndpoint=%s://%s:%d/%s;";
31+
32+
/**
33+
* The account name of the default credentials.
34+
*/
35+
private static final String WELL_KNOWN_ACCOUNT_NAME = "devstoreaccount1";
36+
37+
/**
38+
* The account key of the default credentials.
39+
*/
40+
private static final String WELL_KNOWN_ACCOUNT_KEY =
41+
"Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==";
42+
43+
private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse(
44+
"mcr.microsoft.com/azure-storage/azurite"
45+
);
46+
47+
private MountableFile cert = null;
48+
49+
private String certExtension = null;
50+
51+
private MountableFile key = null;
52+
53+
private String pwd = null;
54+
55+
/**
56+
* @param dockerImageName specified docker image name to run
57+
*/
58+
public AzuriteContainer(String dockerImageName) {
59+
this(DockerImageName.parse(dockerImageName));
60+
}
61+
62+
/**
63+
* @param dockerImageName specified docker image name to run
64+
*/
65+
public AzuriteContainer(DockerImageName dockerImageName) {
66+
super(dockerImageName);
67+
dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME);
68+
withExposedPorts(DEFAULT_BLOB_PORT, DEFAULT_QUEUE_PORT, DEFAULT_TABLE_PORT);
69+
}
70+
71+
/**
72+
* Configure SSL with a custom certificate and password.
73+
*
74+
* @param pfxCert The PFX certificate file
75+
* @param password The password securing the certificate
76+
* @return this
77+
*/
78+
public AzuriteContainer withSsl(final MountableFile pfxCert, final String password) {
79+
this.cert = pfxCert;
80+
this.pwd = password;
81+
this.certExtension = ".pfx";
82+
return this;
83+
}
84+
85+
/**
86+
* Configure SSL with a custom certificate and private key.
87+
*
88+
* @param pemCert The PEM certificate file
89+
* @param pemKey The PEM key file
90+
* @return this
91+
*/
92+
public AzuriteContainer withSsl(final MountableFile pemCert, final MountableFile pemKey) {
93+
this.cert = pemCert;
94+
this.key = pemKey;
95+
this.certExtension = ".pem";
96+
return this;
97+
}
98+
99+
@Override
100+
protected void configure() {
101+
withCommand(getCommandLine());
102+
if (this.cert != null) {
103+
logger().info("Using path for cert file: '{}'", this.cert);
104+
withCopyFileToContainer(this.cert, "/cert" + this.certExtension);
105+
if (this.key != null) {
106+
logger().info("Using path for key file: '{}'", this.key);
107+
withCopyFileToContainer(this.key, "/key.pem");
108+
}
109+
}
110+
}
111+
112+
/**
113+
* Returns the connection string for the default credentials.
114+
*
115+
* @return connection string
116+
*/
117+
public String getConnectionString() {
118+
return getConnectionString(WELL_KNOWN_ACCOUNT_NAME, WELL_KNOWN_ACCOUNT_KEY);
119+
}
120+
121+
/**
122+
* Returns the connection string for the account name and key specified.
123+
*
124+
* @param accountName The name of the account
125+
* @param accountKey The account key
126+
* @return connection string
127+
*/
128+
public String getConnectionString(final String accountName, final String accountKey) {
129+
final String protocol = cert != null ? "https" : "http";
130+
return String.format(
131+
CONNECTION_STRING_FORMAT,
132+
protocol,
133+
accountName,
134+
accountKey,
135+
protocol,
136+
getHost(),
137+
getMappedPort(DEFAULT_BLOB_PORT),
138+
accountName,
139+
protocol,
140+
getHost(),
141+
getMappedPort(DEFAULT_QUEUE_PORT),
142+
accountName,
143+
protocol,
144+
getHost(),
145+
getMappedPort(DEFAULT_TABLE_PORT),
146+
accountName
147+
);
148+
}
149+
150+
String getCommandLine() {
151+
final StringBuilder args = new StringBuilder("azurite");
152+
args.append(" --blobHost ").append(ALLOW_ALL_CONNECTIONS);
153+
args.append(" --queueHost ").append(ALLOW_ALL_CONNECTIONS);
154+
args.append(" --tableHost ").append(ALLOW_ALL_CONNECTIONS);
155+
if (this.cert != null) {
156+
args.append(" --cert ").append("/cert").append(this.certExtension);
157+
if (this.pwd != null) {
158+
args.append(" --pwd ").append(this.pwd);
159+
} else {
160+
args.append(" --key ").append("/key.pem");
161+
}
162+
}
163+
final String cmd = args.toString();
164+
logger().debug("Using command line: '{}'", cmd);
165+
return cmd;
166+
}
167+
}

0 commit comments

Comments
 (0)