Azure¶
Since v0.36.0
Introduction¶
The Testcontainers module for Azure.
Adding this module to your project dependencies¶
Please run the following command to add the Azure module to your Go dependencies:
go get github.com/testcontainers/testcontainers-go/modules/azure
Usage example¶
The Azure module exposes the following Go packages:
- Azurite:
github.com/testcontainers/testcontainers-go/modules/azure/azurite
. - EventHubs:
github.com/testcontainers/testcontainers-go/modules/azure/eventhubs
. - ServiceBus:
github.com/testcontainers/testcontainers-go/modules/azure/servicebus
.
EULA Acceptance
Due to licensing restrictions you are required to explicitly accept an End User License Agreement (EULA) for the EventHubs container image. This is facilitated through the WithAcceptEULA
function.
ctx := context.Background()
azuriteContainer, err := azurite.Run(
ctx,
"mcr.microsoft.com/azure-storage/azurite:3.28.0",
)
defer func() {
if err := testcontainers.TerminateContainer(azuriteContainer); err != nil {
log.Printf("failed to terminate container: %s", err)
}
}()
if err != nil {
log.Printf("failed to start container: %s", err)
return
}
Azurite¶
Run function¶
- Since v0.36.0
The Azurite module exposes one entrypoint function to create the Azurite container, and this function receives three parameters:
func Run(ctx context.Context, img string, opts ...testcontainers.ContainerCustomizer) (*Container, error)
context.Context
, the Go context.string
, the Docker image to use.testcontainers.ContainerCustomizer
, a variadic argument for passing options.
Default Credentials¶
The Azurite container uses the following default credentials:
// AccountName is the default testing account name used by Azurite
AccountName string = "devstoreaccount1"
// AccountKey is the default testing account key used by Azurite
AccountKey string = "Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw=="
Image¶
Use the second argument in the Run
function to set a valid Docker image.
In example: Run(context.Background(), "mcr.microsoft.com/azure-storage/azurite:3.28.0")
.
Container Options¶
When starting the Azurite container, you can pass options in a variadic way to configure it.
WithInMemoryPersistence¶
- Since v0.36.0
If you want to use in-memory persistence, you can use WithInMemoryPersistence(megabytes float64)
. E.g. azurite.WithInMemoryPersistence(64.0)
.
Please read the Azurite documentation for more information.
Warning
This option is only available in Azurite versions 3.28.0
and later.
The following options are exposed by the testcontainers
package.
Basic Options¶
WithExposedPorts
Since v0.37.0WithEnv
Since v0.29.0WithWaitStrategy
Since v0.20.0WithAdditionalWaitStrategy
Not available until the next release mainWithWaitStrategyAndDeadline
Since v0.20.0WithAdditionalWaitStrategyAndDeadline
Not available until the next release mainWithEntrypoint
Since v0.37.0WithEntrypointArgs
Since v0.37.0WithCmd
Since v0.37.0WithCmdArgs
Since v0.37.0WithLabels
Since v0.37.0
Lifecycle Options¶
WithLifecycleHooks
Not available until the next release mainWithAdditionalLifecycleHooks
Not available until the next release mainWithStartupCommand
Since v0.25.0WithAfterReadyCommand
Since v0.28.0
Files & Mounts Options¶
WithFiles
Since v0.37.0WithMounts
Since v0.37.0WithTmpfs
Since v0.37.0WithImageMount
Since v0.37.0
Build Options¶
WithDockerfile
Since v0.37.0
Logging Options¶
WithLogConsumers
Since v0.28.0WithLogConsumerConfig
Not available until the next release mainWithLogger
Since v0.29.0
Image Options¶
WithAlwaysPull
Not available until the next release mainWithImageSubstitutors
Since v0.26.0WithImagePlatform
Not available until the next release main
Networking Options¶
WithNetwork
Since v0.27.0WithNetworkByName
Not available until the next release mainWithBridgeNetwork
Not available until the next release mainWithNewNetwork
Since v0.27.0
Advanced Options¶
WithHostPortAccess
Since v0.31.0WithConfigModifier
Since v0.20.0WithHostConfigModifier
Since v0.20.0WithEndpointSettingsModifier
Since v0.20.0CustomizeRequest
Since v0.20.0WithName
Not available until the next release mainWithNoStart
Not available until the next release main
Experimental Options¶
WithReuseByName
Since v0.37.0
Container Methods¶
The Azurite container exposes the following methods:
BlobServiceURL¶
- Since v0.36.0
Returns the service URL to connect to the Blob service of the Azurite container and an error, passing the Go context as parameter.
QueueServiceURL¶
- Since v0.36.0
Returns the service URL to connect to the Queue service of the Azurite container and an error, passing the Go context as parameter.
TableServiceURL¶
- Since v0.36.0
Returns the service URL to connect to the Table service of the Azurite container and an error, passing the Go context as parameter.
Examples¶
Blob Operations¶
In the following example, we will create a container with Azurite and perform some blob operations. For that, using the default credentials, we will create an Azurite container, upload a blob to it, list the blobs, and download the blob. Finally, we will remove the created blob and container.
ctx := context.Background()
azuriteContainer, err := azurite.Run(
ctx,
"mcr.microsoft.com/azure-storage/azurite:3.33.0",
azurite.WithInMemoryPersistence(64),
)
defer func() {
if err := testcontainers.TerminateContainer(azuriteContainer); err != nil {
log.Printf("failed to terminate container: %s", err)
}
}()
if err != nil {
log.Printf("failed to start container: %s", err)
return
}
cred, err := azblob.NewSharedKeyCredential(azurite.AccountName, azurite.AccountKey)
if err != nil {
log.Printf("failed to create shared key credential: %s", err)
return
}
⋯
cred, err := azqueue.NewSharedKeyCredential(azurite.AccountName, azurite.AccountKey)
if err != nil {
log.Printf("failed to create shared key credential: %s", err)
return
}
⋯
cred, err := aztables.NewSharedKeyCredential(azurite.AccountName, azurite.AccountKey)
if err != nil {
log.Printf("failed to create shared key credential: %s", err)
return
}
serviceURL, err := azuriteContainer.BlobServiceURL(ctx)
if err != nil {
log.Printf("failed to get service URL: %s", err)
return
}
blobServiceURL := serviceURL + "/" + azurite.AccountName
client, err := azblob.NewClientWithSharedKeyCredential(blobServiceURL, cred, nil)
if err != nil {
log.Printf("failed to create client: %s", err)
return
}
⋯
serviceURL, err := azuriteContainer.QueueServiceURL(ctx)
if err != nil {
log.Printf("failed to get service URL: %s", err)
return
}
queueServiceURL := serviceURL + "/" + azurite.AccountName
client, err := azqueue.NewServiceClientWithSharedKeyCredential(queueServiceURL, cred, nil)
if err != nil {
log.Printf("failed to create client: %s", err)
return
}
⋯
serviceURL, err := azuriteContainer.TableServiceURL(ctx)
if err != nil {
log.Printf("failed to get service URL: %s", err)
return
}
tablesServiceURL := serviceURL + "/" + azurite.AccountName
client, err := aztables.NewServiceClientWithSharedKey(tablesServiceURL, cred, nil)
if err != nil {
log.Printf("failed to create client: %s", err)
return
}
containerName := "testcontainer"
_, err = client.CreateContainer(context.TODO(), containerName, nil)
if err != nil {
log.Printf("failed to create container: %s", err)
return
}
blobData := "Hello world!"
blobName := "HelloWorld.txt"
_, err = client.UploadStream(context.TODO(),
containerName,
blobName,
strings.NewReader(blobData),
&azblob.UploadStreamOptions{
Metadata: map[string]*string{"Foo": to.Ptr("Bar")},
Tags: map[string]string{"Year": "2022"},
})
if err != nil {
log.Printf("failed to upload blob: %s", err)
return
}
// Download the blob's contents and ensure that the download worked properly
blobDownloadResponse, err := client.DownloadStream(context.TODO(), containerName, blobName, nil)
if err != nil {
log.Printf("failed to download blob: %s", err)
return
}
// Use the bytes.Buffer object to read the downloaded data.
// RetryReaderOptions has a lot of in-depth tuning abilities, but for the sake of simplicity, we'll omit those here.
reader := blobDownloadResponse.Body
downloadData, err := io.ReadAll(reader)
if err != nil {
log.Printf("failed to read downloaded data: %s", err)
return
}
// List methods returns a pager object which can be used to iterate over the results of a paging operation.
// To iterate over a page use the NextPage(context.Context) to fetch the next page of results.
// PageResponse() can be used to iterate over the results of the specific page.
pager := client.NewListBlobsFlatPager(containerName, nil)
for pager.More() {
resp, err := pager.NextPage(context.TODO())
if err != nil {
log.Printf("failed to list blobs: %s", err)
return
}
fmt.Println(len(resp.Segment.BlobItems))
}
_, err = client.DeleteBlob(context.TODO(), containerName, blobName, nil)
if err != nil {
log.Printf("failed to delete blob: %s", err)
return
}
_, err = client.DeleteContainer(context.TODO(), containerName, nil)
if err != nil {
log.Printf("failed to delete container: %s", err)
return
}
Queue Operations¶
In the following example, we will create an Azurite container and perform some queue operations. For that, using the default credentials, we will create a queue, list the queues, and finally we will remove the created queue.
ctx := context.Background()
azuriteContainer, err := azurite.Run(
ctx,
"mcr.microsoft.com/azure-storage/azurite:3.28.0",
azurite.WithInMemoryPersistence(64),
)
defer func() {
if err := testcontainers.TerminateContainer(azuriteContainer); err != nil {
log.Printf("failed to terminate container: %s", err)
}
}()
if err != nil {
log.Printf("failed to start container: %s", err)
return
}
cred, err := azqueue.NewSharedKeyCredential(azurite.AccountName, azurite.AccountKey)
if err != nil {
log.Printf("failed to create shared key credential: %s", err)
return
}
serviceURL, err := azuriteContainer.QueueServiceURL(ctx)
if err != nil {
log.Printf("failed to get service URL: %s", err)
return
}
queueServiceURL := serviceURL + "/" + azurite.AccountName
client, err := azqueue.NewServiceClientWithSharedKeyCredential(queueServiceURL, cred, nil)
if err != nil {
log.Printf("failed to create client: %s", err)
return
}
queueName := "testqueue"
_, err = client.CreateQueue(context.TODO(), queueName, &azqueue.CreateOptions{
Metadata: map[string]*string{"hello": to.Ptr("world")},
})
if err != nil {
log.Printf("failed to create queue: %s", err)
return
}
pager := client.NewListQueuesPager(&azqueue.ListQueuesOptions{
Include: azqueue.ListQueuesInclude{Metadata: true},
})
// list pre-existing queues
for pager.More() {
resp, err := pager.NextPage(context.Background())
if err != nil {
log.Printf("failed to list queues: %s", err)
return
}
fmt.Println(len(resp.Queues))
fmt.Println(*resp.Queues[0].Name)
}
_, err = client.DeleteQueue(context.TODO(), queueName, &azqueue.DeleteOptions{})
if err != nil {
log.Printf("failed to delete queue: %s", err)
return
}
Table Operations¶
In the following example, we will create an Azurite container and perform some table operations. For that, using the default credentials, we will create a table, list the tables, and finally we will remove the created table.
ctx := context.Background()
azuriteContainer, err := azurite.Run(
ctx,
"mcr.microsoft.com/azure-storage/azurite:3.28.0",
azurite.WithInMemoryPersistence(64),
)
defer func() {
if err := testcontainers.TerminateContainer(azuriteContainer); err != nil {
log.Printf("failed to terminate container: %s", err)
}
}()
if err != nil {
log.Printf("failed to start container: %s", err)
return
}
cred, err := aztables.NewSharedKeyCredential(azurite.AccountName, azurite.AccountKey)
if err != nil {
log.Printf("failed to create shared key credential: %s", err)
return
}
serviceURL, err := azuriteContainer.TableServiceURL(ctx)
if err != nil {
log.Printf("failed to get service URL: %s", err)
return
}
tablesServiceURL := serviceURL + "/" + azurite.AccountName
client, err := aztables.NewServiceClientWithSharedKey(tablesServiceURL, cred, nil)
if err != nil {
log.Printf("failed to create client: %s", err)
return
}
tableName := "fromServiceClient"
_, err = client.CreateTable(context.TODO(), tableName, nil)
if err != nil {
log.Printf("failed to create table: %s", err)
return
}
pager := client.NewListTablesPager(nil)
for pager.More() {
resp, err := pager.NextPage(context.Background())
if err != nil {
log.Printf("failed to list tables: %s", err)
return
}
fmt.Println(len(resp.Tables))
fmt.Println(*resp.Tables[0].Name)
}
_, err = client.DeleteTable(context.TODO(), tableName, nil)
if err != nil {
fmt.Println(err)
return
}
EventHubs¶
Run function¶
- Since v0.36.0
The EventHubs module exposes one entrypoint function to create the EventHubs container, and this function receives three parameters:
func Run(ctx context.Context, img string, opts ...testcontainers.ContainerCustomizer) (*Container, error)
context.Context
, the Go context.string
, the Docker image to use.testcontainers.ContainerCustomizer
, a variadic argument for passing options.
The EventHubs container needs an Azurite container to be running, for that reason Testcontainers for Go automatically creates a Docker network and an Azurite container for EventHubs to work. When terminating the EventHubs container, the Azurite container and the Docker network are also terminated.
Image¶
Use the second argument in the Run
function to set a valid Docker image.
In example: Run(context.Background(), "mcr.microsoft.com/azure-messaging/eventhubs-emulator:2.0.1")
.
Container Options¶
When starting the EventHubs container, you can pass options in a variadic way to configure it.
WithAzurite¶
- Since v0.36.0
This option allows you to set a different Azurite Docker image, instead of the default one, and also pass options to the Azurite container, in the form of a variadic argument of testcontainers.ContainerCustomizer
.
WithAcceptEULA¶
- Since v0.36.0
This option allows you to accept the EULA for the EventHubs container.
WithConfig¶
- Since v0.36.0
This option allows you to set a custom EventHubs config file for the EventHubs container.
The config file must be a valid EventHubs config file, and it must be a valid JSON object.
{
"UserConfig": {
"NamespaceConfig": [
{
"Type": "EventHub",
"Name": "emulatorNs1",
"Entities": [
{
"Name": "eh1",
"PartitionCount": "1",
"ConsumerGroups": [
{
"Name": "cg1"
}
]
}
]
}
],
"LoggingConfig": {
"Type": "File"
}
}
}
The following options are exposed by the testcontainers
package.
Basic Options¶
WithExposedPorts
Since v0.37.0WithEnv
Since v0.29.0WithWaitStrategy
Since v0.20.0WithAdditionalWaitStrategy
Not available until the next release mainWithWaitStrategyAndDeadline
Since v0.20.0WithAdditionalWaitStrategyAndDeadline
Not available until the next release mainWithEntrypoint
Since v0.37.0WithEntrypointArgs
Since v0.37.0WithCmd
Since v0.37.0WithCmdArgs
Since v0.37.0WithLabels
Since v0.37.0
Lifecycle Options¶
WithLifecycleHooks
Not available until the next release mainWithAdditionalLifecycleHooks
Not available until the next release mainWithStartupCommand
Since v0.25.0WithAfterReadyCommand
Since v0.28.0
Files & Mounts Options¶
WithFiles
Since v0.37.0WithMounts
Since v0.37.0WithTmpfs
Since v0.37.0WithImageMount
Since v0.37.0
Build Options¶
WithDockerfile
Since v0.37.0
Logging Options¶
WithLogConsumers
Since v0.28.0WithLogConsumerConfig
Not available until the next release mainWithLogger
Since v0.29.0
Image Options¶
WithAlwaysPull
Not available until the next release mainWithImageSubstitutors
Since v0.26.0WithImagePlatform
Not available until the next release main
Networking Options¶
WithNetwork
Since v0.27.0WithNetworkByName
Not available until the next release mainWithBridgeNetwork
Not available until the next release mainWithNewNetwork
Since v0.27.0
Advanced Options¶
WithHostPortAccess
Since v0.31.0WithConfigModifier
Since v0.20.0WithHostConfigModifier
Since v0.20.0WithEndpointSettingsModifier
Since v0.20.0CustomizeRequest
Since v0.20.0WithName
Not available until the next release mainWithNoStart
Not available until the next release main
Experimental Options¶
WithReuseByName
Since v0.37.0
Container Methods¶
The EventHubs container exposes the following methods:
ConnectionString¶
- Since v0.36.0
Returns the connection string to connect to the EventHubs container and an error, passing the Go context as parameter.
Examples¶
Send events to EventHubs¶
In the following example, inspired by the Azure Event Hubs Go SDK, we are creating an EventHubs container and sending events to it.
cfg := `{
"UserConfig": {
"NamespaceConfig": [
{
"Type": "EventHub",
"Name": "emulatorNs1",
"Entities": [
{
"Name": "eh1",
"PartitionCount": "1",
"ConsumerGroups": [
{
"Name": "cg1"
}
]
}
]
}
],
"LoggingConfig": {
"Type": "File"
}
}
}
`
eventHubsCtr, err := eventhubs.Run(ctx, "mcr.microsoft.com/azure-messaging/eventhubs-emulator:2.1.0", eventhubs.WithAcceptEULA(), eventhubs.WithConfig(strings.NewReader(cfg)))
defer func() {
if err := testcontainers.TerminateContainer(eventHubsCtr); err != nil {
log.Printf("failed to terminate container: %s", err)
}
}()
if err != nil {
log.Printf("failed to start container: %s", err)
return
}
connectionString, err := eventHubsCtr.ConnectionString(ctx)
if err != nil {
log.Printf("failed to get connection string: %s", err)
return
}
producerClient, err := azeventhubs.NewProducerClientFromConnectionString(connectionString, "eh1", nil)
if err != nil {
log.Printf("failed to create producer client: %s", err)
return
}
defer producerClient.Close(context.TODO())
events := []*azeventhubs.EventData{
{
Body: []byte("hello"),
},
{
Body: []byte("world"),
},
}
newBatchOptions := &azeventhubs.EventDataBatchOptions{}
var batch *azeventhubs.EventDataBatch
maxRetries := 3
// Retry creating the event data batch 3 times, because the event hub is created from the configuration
// and Testcontainers cannot add a wait strategy for the event hub to be created.
for retries := 0; retries < maxRetries; retries++ {
batch, err = producerClient.NewEventDataBatch(context.TODO(), newBatchOptions)
if err == nil {
break
}
if retries == maxRetries-1 {
log.Printf("failed to create event data batch after %d attempts: %s", maxRetries, err)
return
}
}
for i := range events {
err = batch.AddEventData(events[i], nil)
if err != nil {
log.Printf("failed to add event data to batch: %s", err)
return
}
}
err = producerClient.SendEventDataBatch(context.TODO(), batch, nil)
if err != nil {
log.Printf("failed to send event data batch: %s", err)
return
}
ServiceBus¶
Run function¶
- Since v0.36.0
The ServiceBus module exposes one entrypoint function to create the ServiceBus container, and this function receives three parameters:
func Run(ctx context.Context, img string, opts ...testcontainers.ContainerCustomizer) (*Container, error)
context.Context
, the Go context.string
, the Docker image to use.testcontainers.ContainerCustomizer
, a variadic argument for passing options.
The ServiceBus container needs a MSSQL Server container to be running, for that reason Testcontainers for Go automatically creates a Docker network and an MSSQL Server container for ServiceBus to work. When terminating the ServiceBus container, the MSSQL Server container and the Docker network are also terminated.
Info
Since version 1.1.2
of the ServiceBus emulator, it's possible to set the SQL_WAIT_INTERVAL
environment variable to the given seconds.
This module sets it to 0
by default, because the MSSQL Server container is started first.
Image¶
Use the second argument in the Run
function to set a valid Docker image.
In example: Run(context.Background(), "mcr.microsoft.com/azure-messaging/servicebus-emulator:1.1.2")
.
Container Options¶
When starting the ServiceBus container, you can pass options in a variadic way to configure it.
WithMSSQL¶
- Since v0.36.0
This option allows you to set a different MSSQL Server Docker image, instead of the default one, and also pass options to the MSSQL container, in the form of a variadic argument of testcontainers.ContainerCustomizer
.
WithAcceptEULA¶
- Since v0.36.0
This option allows you to accept the EULA for the ServiceBus container.
WithConfig¶
- Since v0.36.0
This option allows you to set a custom ServiceBus config file for the ServiceBus container.
The config file must be a valid ServiceBus config file, and it must be a valid JSON object.
{
"UserConfig": {
"Namespaces": [
{
"Name": "sbemulatorns",
"Queues": [
{
"Name": "queue.1",
"Properties": {
"DeadLetteringOnMessageExpiration": false,
"DefaultMessageTimeToLive": "PT1H",
"DuplicateDetectionHistoryTimeWindow": "PT20S",
"ForwardDeadLetteredMessagesTo": "",
"ForwardTo": "",
"LockDuration": "PT1M",
"MaxDeliveryCount": 10,
"RequiresDuplicateDetection": false,
"RequiresSession": false
}
}
]
}
],
"Logging": {
"Type": "File"
}
}
}
The following options are exposed by the testcontainers
package.
Basic Options¶
WithExposedPorts
Since v0.37.0WithEnv
Since v0.29.0WithWaitStrategy
Since v0.20.0WithAdditionalWaitStrategy
Not available until the next release mainWithWaitStrategyAndDeadline
Since v0.20.0WithAdditionalWaitStrategyAndDeadline
Not available until the next release mainWithEntrypoint
Since v0.37.0WithEntrypointArgs
Since v0.37.0WithCmd
Since v0.37.0WithCmdArgs
Since v0.37.0WithLabels
Since v0.37.0
Lifecycle Options¶
WithLifecycleHooks
Not available until the next release mainWithAdditionalLifecycleHooks
Not available until the next release mainWithStartupCommand
Since v0.25.0WithAfterReadyCommand
Since v0.28.0
Files & Mounts Options¶
WithFiles
Since v0.37.0WithMounts
Since v0.37.0WithTmpfs
Since v0.37.0WithImageMount
Since v0.37.0
Build Options¶
WithDockerfile
Since v0.37.0
Logging Options¶
WithLogConsumers
Since v0.28.0WithLogConsumerConfig
Not available until the next release mainWithLogger
Since v0.29.0
Image Options¶
WithAlwaysPull
Not available until the next release mainWithImageSubstitutors
Since v0.26.0WithImagePlatform
Not available until the next release main
Networking Options¶
WithNetwork
Since v0.27.0WithNetworkByName
Not available until the next release mainWithBridgeNetwork
Not available until the next release mainWithNewNetwork
Since v0.27.0
Advanced Options¶
WithHostPortAccess
Since v0.31.0WithConfigModifier
Since v0.20.0WithHostConfigModifier
Since v0.20.0WithEndpointSettingsModifier
Since v0.20.0CustomizeRequest
Since v0.20.0WithName
Not available until the next release mainWithNoStart
Not available until the next release main
Experimental Options¶
WithReuseByName
Since v0.37.0
Container Methods¶
The ServiceBus container exposes the following methods:
ConnectionString¶
- Since v0.36.0
Returns the connection string to connect to the ServiceBus container and an error, passing the Go context as parameter.
Examples¶
Send events to ServiceBus¶
In the following example, inspired by the Azure Event Hubs Go SDK, we are creating an EventHubs container and sending events to it.
cfg := `{
"UserConfig": {
"Namespaces": [
{
"Name": "sbemulatorns",
"Queues": [
{
"Name": "queue.1",
"Properties": {
"DeadLetteringOnMessageExpiration": false,
"DefaultMessageTimeToLive": "PT1H",
"DuplicateDetectionHistoryTimeWindow": "PT20S",
"ForwardDeadLetteredMessagesTo": "",
"ForwardTo": "",
"LockDuration": "PT1M",
"MaxDeliveryCount": 10,
"RequiresDuplicateDetection": false,
"RequiresSession": false
}
}
]
}
],
"Logging": {
"Type": "File"
}
}
}`
ctx := context.Background()
serviceBusContainer, err := servicebus.Run(
ctx,
"mcr.microsoft.com/azure-messaging/servicebus-emulator:1.1.2",
servicebus.WithAcceptEULA(),
servicebus.WithConfig(strings.NewReader(cfg)),
)
defer func() {
if err := testcontainers.TerminateContainer(serviceBusContainer); err != nil {
log.Printf("failed to terminate container: %s", err)
}
}()
if err != nil {
log.Printf("failed to start container: %s", err)
return
}
connectionString, err := serviceBusContainer.ConnectionString(ctx)
if err != nil {
log.Printf("failed to get connection string: %s", err)
return
}
client, err := azservicebus.NewClientFromConnectionString(connectionString, nil)
if err != nil {
log.Printf("failed to create client: %s", err)
return
}
message := "Hello, Testcontainers!"
sender, err := client.NewSender("queue.1", nil)
if err != nil {
log.Printf("failed to create sender: %s", err)
return
}
defer sender.Close(context.TODO())
sbMessage := &azservicebus.Message{
Body: []byte(message),
}
maxRetries := 3
// Retry sending the message 3 times, because the queue is created from the configuration
// and Testcontainers cannot add a wait strategy for the queue to be created.
for retries := 0; retries < maxRetries; retries++ {
err = sender.SendMessage(context.TODO(), sbMessage, nil)
if err == nil {
break
}
if retries == maxRetries-1 {
fmt.Printf("failed to send message after %d attempts: %s", maxRetries, err)
return
}
}
receiver, err := client.NewReceiverForQueue("queue.1", nil)
if err != nil {
fmt.Printf("failed to create receiver: %s", err)
return
}
defer receiver.Close(context.TODO())
// Receive 1 message from the queue
messagesCount := 1
messages, err := receiver.ReceiveMessages(context.TODO(), messagesCount, nil)
if err != nil {
fmt.Printf("failed to receive messages: %s", err)
return
}
fmt.Printf("received %d messages\n", len(messages))
for _, message := range messages {
body := message.Body
fmt.Printf("%s\n", string(body))
err = receiver.CompleteMessage(context.TODO(), message, nil)
if err != nil {
fmt.Printf("failed to complete message: %s", err)
return
}
}