Skip to content

Commit

Permalink
feat: add azurite module (testcontainers#2569)
Browse files Browse the repository at this point in the history
* chore: rename variable name

* feat: add azurite module

* chore: use constants

* chore: fix lint warnings

* chore: mod tidy
  • Loading branch information
mdelapenya authored Jun 25, 2024
1 parent 2c07694 commit e22f2fa
Show file tree
Hide file tree
Showing 14 changed files with 892 additions and 5 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ jobs:
matrix:
go-version: [1.21.x, 1.x]
platform: [ubuntu-latest]
module: [artemis, cassandra, chroma, clickhouse, cockroachdb, compose, consul, couchbase, dolt, elasticsearch, gcloud, inbucket, influxdb, k3s, k6, kafka, localstack, mariadb, milvus, minio, mockserver, mongodb, mssql, mysql, nats, neo4j, ollama, openfga, openldap, opensearch, postgres, pulsar, qdrant, rabbitmq, redis, redpanda, registry, surrealdb, vault, vearch, weaviate]
module: [artemis, azurite, cassandra, chroma, clickhouse, cockroachdb, compose, consul, couchbase, dolt, elasticsearch, gcloud, inbucket, influxdb, k3s, k6, kafka, localstack, mariadb, milvus, minio, mockserver, mongodb, mssql, mysql, nats, neo4j, ollama, openfga, openldap, opensearch, postgres, pulsar, qdrant, rabbitmq, redis, redpanda, registry, surrealdb, vault, vearch, weaviate]
uses: ./.github/workflows/ci-test-go.yml
with:
go-version: ${{ matrix.go-version }}
Expand Down
4 changes: 4 additions & 0 deletions .vscode/.testcontainers-go.code-workspace
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@
"name": "module / artemis",
"path": "../modules/artemis"
},
{
"name": "module / azurite",
"path": "../modules/azurite"
},
{
"name": "module / cassandra",
"path": "../modules/cassandra"
Expand Down
107 changes: 107 additions & 0 deletions docs/modules/azurite.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
# Azurite

Not available until the next release of testcontainers-go <a href="https://github.com/testcontainers/testcontainers-go"><span class="tc-version">:material-tag: main</span></a>

## Introduction

The Testcontainers module for Azurite.

## Adding this module to your project dependencies

Please run the following command to add the Azurite module to your Go dependencies:

```
go get github.com/testcontainers/testcontainers-go/modules/azurite
```

## Usage example

<!--codeinclude-->
[Creating a Azurite container](../../modules/azurite/examples_test.go) inside_block:runAzuriteContainer
<!--/codeinclude-->

## Module reference

The Azurite module exposes one entrypoint function to create the Azurite container, and this function receives two parameters:

```golang
func RunContainer(ctx context.Context, opts ...testcontainers.ContainerCustomizer) (*AzuriteContainer, error)
```

- `context.Context`, the Go context.
- `testcontainers.ContainerCustomizer`, a variadic argument for passing options.

### Default Credentials

The Azurite container uses the following default credentials:

<!--codeinclude-->
[Default Credencials](../../modules/azurite/azurite.go) inside_block:defaultCredentials
<!--/codeinclude-->

### Container Options

When starting the Azurite container, you can pass options in a variadic way to configure it.

#### Image

If you need to set a different Azurite Docker image, you can use `testcontainers.WithImage` with a valid Docker image
for Azurite. E.g. `testcontainers.WithImage("mcr.microsoft.com/azure-storage/azurite:3.28.0")`.

{% include "../features/common_functional_options.md" %}

#### WithInMemoryPersistence

- Not available until the next release of testcontainers-go <a href="https://github.com/testcontainers/testcontainers-go"><span class="tc-version">:material-tag: main</span></a>

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](https://github.com/Azure/Azurite?tab=readme-ov-file#use-in-memory-storage) for more information.

!!! warning
This option is only available in Azurite versions 3.28.0 and later.

### Container Methods

The Azurite container exposes the following methods:

#### ServiceURL

- Not available until the next release of testcontainers-go <a href="https://github.com/testcontainers/testcontainers-go"><span class="tc-version">:material-tag: main</span></a>

Returns the service URL to connect to the Azurite container and an error, passing the Go context and the service name as parameters.

#### MustServiceURL

- Not available until the next release of testcontainers-go <a href="https://github.com/testcontainers/testcontainers-go"><span class="tc-version">:material-tag: main</span></a>

Returns the service URL to connect to the Azurite container, passing the Go context and the service name as parameters. If an error occurs, it will panic.

### 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.

<!--codeinclude-->
[Performing blob operations](../../modules/azurite/examples_test.go) inside_block:blobOperations
<!--/codeinclude-->

#### 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.

<!--codeinclude-->
[Performing queue operations](../../modules/azurite/examples_test.go) inside_block:queueOperations
<!--/codeinclude-->

#### 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.

<!--codeinclude-->
[Performing table operations](../../modules/azurite/examples_test.go) inside_block:tableOperations
<!--/codeinclude-->
1 change: 1 addition & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ nav:
- Modules:
- modules/index.md
- modules/artemis.md
- modules/azurite.md
- modules/cassandra.md
- modules/chroma.md
- modules/clickhouse.md
Expand Down
5 changes: 5 additions & 0 deletions modules/azurite/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
include ../../commons-test.mk

.PHONY: test
test:
$(MAKE) test-azurite
123 changes: 123 additions & 0 deletions modules/azurite/azurite.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
package azurite

import (
"context"
"fmt"

"github.com/docker/go-connections/nat"

"github.com/testcontainers/testcontainers-go"
"github.com/testcontainers/testcontainers-go/wait"
)

const (
// BlobPort is the default port used by Azurite
BlobPort = "10000/tcp"
// QueuePort is the default port used by Azurite
QueuePort = "10001/tcp"
// TablePort is the default port used by Azurite
TablePort = "10002/tcp"

// defaultCredentials {
// 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=="
// }
)

// AzuriteContainer represents the Azurite container type used in the module
type AzuriteContainer struct {
testcontainers.Container
Settings options
}

func (c *AzuriteContainer) ServiceURL(ctx context.Context, srv Service) (string, error) {
hostname, err := c.Host(ctx)
if err != nil {
return "", err
}

var port nat.Port
switch srv {
case BlobService:
port = BlobPort
case QueueService:
port = QueuePort
case TableService:
port = TablePort
default:
return "", fmt.Errorf("unknown service: %s", srv)
}

mappedPort, err := c.MappedPort(ctx, port)
if err != nil {
return "", err
}

return fmt.Sprintf("http://%s:%d", hostname, mappedPort.Int()), nil
}

func (c *AzuriteContainer) MustServiceURL(ctx context.Context, srv Service) string {
url, err := c.ServiceURL(ctx, srv)
if err != nil {
panic(err)
}

return url
}

// RunContainer creates an instance of the Azurite container type
func RunContainer(ctx context.Context, opts ...testcontainers.ContainerCustomizer) (*AzuriteContainer, error) {
req := testcontainers.ContainerRequest{
Image: "mcr.microsoft.com/azure-storage/azurite:3.28.0",
ExposedPorts: []string{BlobPort, QueuePort, TablePort},
Env: map[string]string{},
Entrypoint: []string{"azurite"},
Cmd: []string{},
}

genericContainerReq := testcontainers.GenericContainerRequest{
ContainerRequest: req,
Started: true,
}

// 1. Gather all config options (defaults and then apply provided options)
settings := defaultOptions()
for _, opt := range opts {
if err := opt.Customize(&genericContainerReq); err != nil {
return nil, err
}
}

// 2. evaluate the enabled services to apply the right wait strategy and Cmd options
enabledServices := settings.EnabledServices
if len(enabledServices) > 0 {
waitingFor := make([]wait.Strategy, 0)
for _, srv := range enabledServices {
switch srv {
case BlobService:
genericContainerReq.Cmd = append(genericContainerReq.Cmd, "--blobHost", "0.0.0.0")
waitingFor = append(waitingFor, wait.ForLog("Blob service is successfully listening"))
case QueueService:
genericContainerReq.Cmd = append(genericContainerReq.Cmd, "--queueHost", "0.0.0.0")
waitingFor = append(waitingFor, wait.ForLog("Queue service is successfully listening"))
case TableService:
genericContainerReq.Cmd = append(genericContainerReq.Cmd, "--tableHost", "0.0.0.0")
waitingFor = append(waitingFor, wait.ForLog("Table service is successfully listening"))
}
}

if len(waitingFor) > 0 {
genericContainerReq.WaitingFor = wait.ForAll(waitingFor...)
}
}

container, err := testcontainers.GenericContainer(ctx, genericContainerReq)
if err != nil {
return nil, err
}

return &AzuriteContainer{Container: container, Settings: settings}, nil
}
27 changes: 27 additions & 0 deletions modules/azurite/azurite_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package azurite_test

import (
"context"
"testing"

"github.com/testcontainers/testcontainers-go"
"github.com/testcontainers/testcontainers-go/modules/azurite"
)

func TestAzurite(t *testing.T) {
ctx := context.Background()

container, err := azurite.RunContainer(ctx, testcontainers.WithImage("mcr.microsoft.com/azure-storage/azurite:3.23.0"))
if err != nil {
t.Fatal(err)
}

// Clean up the container after the test is complete
t.Cleanup(func() {
if err := container.Terminate(ctx); err != nil {
t.Fatalf("failed to terminate container: %s", err)
}
})

// perform assertions
}
Loading

0 comments on commit e22f2fa

Please sign in to comment.