-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add Azure Service Bus Emulator container to Azure module #9795
base: main
Are you sure you want to change the base?
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
package org.testcontainers.azure; | ||
|
||
import org.testcontainers.containers.GenericContainer; | ||
import org.testcontainers.containers.MSSQLServerContainer; | ||
import org.testcontainers.containers.wait.strategy.Wait; | ||
import org.testcontainers.images.builder.Transferable; | ||
import org.testcontainers.utility.DockerImageName; | ||
import org.testcontainers.utility.LicenseAcceptance; | ||
|
||
/** | ||
* Testcontainers implementation for Azure Service Bus Emulator. | ||
* <p> | ||
* Supported image: {@code mcr.microsoft.com/azure-messaging/servicebus-emulator} | ||
* <p> | ||
* Exposed port: 5672 | ||
*/ | ||
public class AzureServiceBusEmulatorContainer extends GenericContainer<AzureServiceBusEmulatorContainer> { | ||
|
||
private static final String CONNECTION_STRING_FORMAT = | ||
"Endpoint=sb://%s:%d;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=SAS_KEY_VALUE;UseDevelopmentEmulator=true;"; | ||
|
||
private static final int DEFAULT_PORT = 5672; | ||
|
||
private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse( | ||
"mcr.microsoft.com/azure-messaging/servicebus-emulator" | ||
); | ||
|
||
private final MSSQLServerContainer<?> mssqlServerContainer; | ||
|
||
/** | ||
* @param dockerImageName The specified docker image name to run | ||
* @param mssqlServerContainer The MS SQL Server container used by Service Bus as a dependency | ||
*/ | ||
public AzureServiceBusEmulatorContainer( | ||
final DockerImageName dockerImageName, | ||
final MSSQLServerContainer<?> mssqlServerContainer | ||
) { | ||
super(dockerImageName); | ||
dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME); | ||
this.mssqlServerContainer = mssqlServerContainer; | ||
dependsOn(mssqlServerContainer); | ||
withExposedPorts(DEFAULT_PORT); | ||
waitingFor(Wait.forLogMessage(".*Emulator Service is Successfully Up!.*", 1)); | ||
} | ||
|
||
/** | ||
* Provide the Service Bus configuration JSON. | ||
* | ||
* @param config The configuration | ||
* @return this | ||
*/ | ||
public AzureServiceBusEmulatorContainer withConfig(final Transferable config) { | ||
withCopyToContainer(config, "/ServiceBus_Emulator/ConfigFiles/Config.json"); | ||
return this; | ||
} | ||
|
||
/** | ||
* Accepts the EULA of the container. | ||
* | ||
* @return this | ||
*/ | ||
public AzureServiceBusEmulatorContainer acceptLicense() { | ||
return withEnv("ACCEPT_EULA", "Y"); | ||
} | ||
|
||
@Override | ||
protected void configure() { | ||
withEnv("SQL_SERVER", mssqlServerContainer.getNetworkAliases().get(0)); | ||
withEnv("MSSQL_SA_PASSWORD", mssqlServerContainer.getPassword()); | ||
// If license was not accepted programmatically, check if it was accepted via resource file | ||
if (!getEnvMap().containsKey("ACCEPT_EULA")) { | ||
LicenseAcceptance.assertLicenseAccepted(this.getDockerImageName()); | ||
acceptLicense(); | ||
} | ||
} | ||
|
||
/** | ||
* Returns the connection string. | ||
* | ||
* @return connection string | ||
*/ | ||
public String getConnectionString() { | ||
return String.format(CONNECTION_STRING_FORMAT, getHost(), getMappedPort(DEFAULT_PORT)); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,102 @@ | ||||||||||||||||||||||||||||||
package org.testcontainers.azure; | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
import com.azure.messaging.servicebus.ServiceBusClientBuilder; | ||||||||||||||||||||||||||||||
import com.azure.messaging.servicebus.ServiceBusErrorContext; | ||||||||||||||||||||||||||||||
import com.azure.messaging.servicebus.ServiceBusMessage; | ||||||||||||||||||||||||||||||
import com.azure.messaging.servicebus.ServiceBusProcessorClient; | ||||||||||||||||||||||||||||||
import com.azure.messaging.servicebus.ServiceBusReceivedMessage; | ||||||||||||||||||||||||||||||
import com.azure.messaging.servicebus.ServiceBusReceivedMessageContext; | ||||||||||||||||||||||||||||||
import com.azure.messaging.servicebus.ServiceBusSenderClient; | ||||||||||||||||||||||||||||||
import com.azure.messaging.servicebus.ServiceBusTransactionContext; | ||||||||||||||||||||||||||||||
import com.github.dockerjava.api.model.Capability; | ||||||||||||||||||||||||||||||
import org.assertj.core.api.Assertions; | ||||||||||||||||||||||||||||||
import org.junit.Rule; | ||||||||||||||||||||||||||||||
import org.junit.Test; | ||||||||||||||||||||||||||||||
import org.testcontainers.containers.MSSQLServerContainer; | ||||||||||||||||||||||||||||||
import org.testcontainers.containers.Network; | ||||||||||||||||||||||||||||||
import org.testcontainers.utility.DockerImageName; | ||||||||||||||||||||||||||||||
import org.testcontainers.utility.MountableFile; | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
import java.util.ArrayList; | ||||||||||||||||||||||||||||||
import java.util.List; | ||||||||||||||||||||||||||||||
import java.util.concurrent.TimeUnit; | ||||||||||||||||||||||||||||||
import java.util.function.Consumer; | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
import static org.assertj.core.api.Assertions.assertThat; | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
public class AzureServiceBusEmulatorContainerTest { | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
@Rule | ||||||||||||||||||||||||||||||
// network { | ||||||||||||||||||||||||||||||
public Network network = Network.newNetwork(); | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
nagyesta marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||
// } | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
@Rule | ||||||||||||||||||||||||||||||
// sqlContainer { | ||||||||||||||||||||||||||||||
public MSSQLServerContainer<?> mssqlServerContainer = new MSSQLServerContainer<>( | ||||||||||||||||||||||||||||||
"mcr.microsoft.com/mssql/server:2022-CU14-ubuntu-22.04" | ||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||
eddumelendez marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||
.acceptLicense() | ||||||||||||||||||||||||||||||
.withPassword("yourStrong(!)Password") | ||||||||||||||||||||||||||||||
.withCreateContainerCmdModifier(cmd -> { | ||||||||||||||||||||||||||||||
cmd.getHostConfig().withCapAdd(Capability.SYS_PTRACE); | ||||||||||||||||||||||||||||||
}) | ||||||||||||||||||||||||||||||
.withNetwork(network); | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
nagyesta marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||
// } | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
@Rule | ||||||||||||||||||||||||||||||
// emulatorContainer { | ||||||||||||||||||||||||||||||
public AzureServiceBusEmulatorContainer emulator = new AzureServiceBusEmulatorContainer( | ||||||||||||||||||||||||||||||
DockerImageName.parse("mcr.microsoft.com/azure-messaging/servicebus-emulator:1.0.1"), | ||||||||||||||||||||||||||||||
mssqlServerContainer | ||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||
.acceptLicense() | ||||||||||||||||||||||||||||||
.withConfig(MountableFile.forClasspathResource("/service-bus-config.json")) | ||||||||||||||||||||||||||||||
.withNetwork(network); | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's keep the constructor only accepting the image as a String or DockerImageName. Rather we can declare dependsOn via de API.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have created a new |
||||||||||||||||||||||||||||||
// } | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
@Test | ||||||||||||||||||||||||||||||
public void testWithClient() throws InterruptedException { | ||||||||||||||||||||||||||||||
assertThat(emulator.getConnectionString()).startsWith("Endpoint=sb://"); | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
// senderClient { | ||||||||||||||||||||||||||||||
ServiceBusSenderClient senderClient = new ServiceBusClientBuilder() | ||||||||||||||||||||||||||||||
.connectionString(emulator.getConnectionString()) | ||||||||||||||||||||||||||||||
.sender() | ||||||||||||||||||||||||||||||
.queueName("queue.1") | ||||||||||||||||||||||||||||||
.buildClient(); | ||||||||||||||||||||||||||||||
// } | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
TimeUnit.SECONDS.sleep(5); | ||||||||||||||||||||||||||||||
nagyesta marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||
ServiceBusTransactionContext transaction = senderClient.createTransaction(); | ||||||||||||||||||||||||||||||
senderClient.sendMessage(new ServiceBusMessage("Hello, Testcontainers!"), transaction); | ||||||||||||||||||||||||||||||
senderClient.commitTransaction(transaction); | ||||||||||||||||||||||||||||||
senderClient.close(); | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
TimeUnit.SECONDS.sleep(5); | ||||||||||||||||||||||||||||||
final List<ServiceBusReceivedMessage> received = new ArrayList<>(); | ||||||||||||||||||||||||||||||
Consumer<ServiceBusReceivedMessageContext> messageConsumer = m -> { | ||||||||||||||||||||||||||||||
received.add(m.getMessage()); | ||||||||||||||||||||||||||||||
m.complete(); | ||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||
Consumer<ServiceBusErrorContext> errorConsumer = e -> Assertions.fail("Unexpected error: " + e); | ||||||||||||||||||||||||||||||
// processorClient { | ||||||||||||||||||||||||||||||
ServiceBusProcessorClient processorClient = new ServiceBusClientBuilder() | ||||||||||||||||||||||||||||||
.connectionString(emulator.getConnectionString()) | ||||||||||||||||||||||||||||||
.processor() | ||||||||||||||||||||||||||||||
.queueName("queue.1") | ||||||||||||||||||||||||||||||
.processMessage(messageConsumer) | ||||||||||||||||||||||||||||||
.processError(errorConsumer) | ||||||||||||||||||||||||||||||
.buildProcessorClient(); | ||||||||||||||||||||||||||||||
// } | ||||||||||||||||||||||||||||||
processorClient.start(); | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
TimeUnit.SECONDS.sleep(10); | ||||||||||||||||||||||||||||||
processorClient.close(); | ||||||||||||||||||||||||||||||
assertThat(received).hasSize(1); | ||||||||||||||||||||||||||||||
assertThat(received.get(0).getBody().toString()).isEqualTo("Hello, Testcontainers!"); | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
{ | ||
"UserConfig": { | ||
"Namespaces": [ | ||
{ | ||
"Name": "sbemulatorns", | ||
"Queues": [ | ||
{ | ||
"Name": "queue.1", | ||
"Properties": { | ||
"DeadLetteringOnMessageExpiration": false, | ||
"DefaultMessageTimeToLive": "PT1H", | ||
"DuplicateDetectionHistoryTimeWindow": "PT20S", | ||
"ForwardDeadLetteredMessagesTo": "", | ||
"ForwardTo": "", | ||
"LockDuration": "PT1M", | ||
"MaxDeliveryCount": 3, | ||
"RequiresDuplicateDetection": false, | ||
"RequiresSession": false | ||
} | ||
} | ||
], | ||
"Topics": [] | ||
} | ||
], | ||
"Logging": { | ||
"Type": "File" | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
documentation must mention dependency on this module
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Left as-is due to: #9795 (comment)