diff --git a/docs/modules/azure.md b/docs/modules/azure.md
index 695e0efeb8..49e8bfe821 100644
--- a/docs/modules/azure.md
+++ b/docs/modules/azure.md
@@ -23,7 +23,7 @@ The Azure module exposes the following Go packages:
- [ServiceBus](#servicebus): `github.com/testcontainers/testcontainers-go/modules/azure/servicebus`.
!!! warning "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.
-
+- [CosmosDB](#cosmosdb): `github.com/testcontainers/testcontainers-go/modules/azure/cosmosdb`.
[Creating a Azurite container](../../modules/azure/azurite/examples_test.go) inside_block:runAzuriteContainer
@@ -307,4 +307,49 @@ In the following example, inspired by the [Azure Event Hubs Go SDK](https://lear
[Create Client](../../modules/azure/servicebus/examples_test.go) inside_block:createClient
[Send messages to a Queue](../../modules/azure/servicebus/examples_test.go) inside_block:sendMessages
[Receive messages from a Queue](../../modules/azure/servicebus/examples_test.go) inside_block:receiveMessages
-
\ No newline at end of file
+
+
+## CosmosDB
+
+### Run function
+
+- Not available until the next release :material-tag: main
+
+The CosmosDB module exposes one entrypoint function to create the CosmosDB container, and this function receives three parameters:
+
+```golang
+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.
+
+#### Image
+
+Use the second argument in the `Run` function to set a valid Docker image.
+In example: `Run(context.Background(), "mcr.microsoft.com/cosmosdb/linux/azure-cosmos-emulator:vnext-preview")`.
+
+### Container Options
+
+When starting the CosmosDB container, you can pass options in a variadic way to configure it.
+
+{% include "../features/common_functional_options_list.md" %}
+
+### Container Methods
+
+The CosmosDB container exposes the following methods:
+
+#### ConnectionString
+
+- Not available until the next release :material-tag: main
+
+Returns the connection string to connect to the CosmosDB container and an error, passing the Go context as parameter.
+
+### Examples
+
+#### Connect and Create database
+
+
+[Connect_CreateDatabase](../../modules/azure/cosmosdb/examples_test.go) inside_block:ExampleRun_connect
+
diff --git a/modules/azure/cosmosdb/cosmosdb.go b/modules/azure/cosmosdb/cosmosdb.go
new file mode 100644
index 0000000000..5c5457cd8c
--- /dev/null
+++ b/modules/azure/cosmosdb/cosmosdb.go
@@ -0,0 +1,69 @@
+package cosmosdb
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/docker/go-connections/nat"
+
+ "github.com/testcontainers/testcontainers-go"
+ "github.com/testcontainers/testcontainers-go/wait"
+)
+
+const (
+ defaultPort = "8081/tcp"
+ defaultProtocol = "http"
+
+ // Well-known, publicly documented account key for the Azure CosmosDB Emulator.
+ // See: https://learn.microsoft.com/en-us/azure/cosmos-db/how-to-develop-emulator
+ testAccKey = "C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw=="
+)
+
+// Container represents the CosmosDB container type used in the module
+type Container struct {
+ testcontainers.Container
+}
+
+// Run creates an instance of the CosmosDB container type
+func Run(ctx context.Context, img string, opts ...testcontainers.ContainerCustomizer) (*Container, error) {
+ // Initialize with module defaults
+ moduleOpts := []testcontainers.ContainerCustomizer{
+ testcontainers.WithExposedPorts(defaultPort),
+ testcontainers.WithCmdArgs("--enable-explorer", "false"),
+ testcontainers.WithWaitStrategy(
+ wait.ForAll(
+ wait.ForLog("Started"),
+ wait.ForListeningPort(nat.Port(defaultPort)),
+ ),
+ ),
+ }
+
+ // Add user-provided options
+ moduleOpts = append(moduleOpts, opts...)
+
+ ctr, err := testcontainers.Run(ctx, img, moduleOpts...)
+ var c *Container
+ if ctr != nil {
+ c = &Container{Container: ctr}
+ }
+
+ if err != nil {
+ return c, fmt.Errorf("run cosmosdb: %w", err)
+ }
+
+ return c, nil
+}
+
+// ConnectionString returns a connection string that can be used to connect to the CosmosDB emulator.
+// The connection string includes the account endpoint (host:port) and the default test account key.
+// It returns an error if the port endpoint cannot be determined.
+//
+// Format: "AccountEndpoint=:;AccountKey="
+func (c *Container) ConnectionString(ctx context.Context) (string, error) {
+ endpoint, err := c.PortEndpoint(ctx, defaultPort, defaultProtocol)
+ if err != nil {
+ return "", fmt.Errorf("port endpoint: %w", err)
+ }
+
+ return fmt.Sprintf("AccountEndpoint=%s;AccountKey=%s;", endpoint, testAccKey), nil
+}
diff --git a/modules/azure/cosmosdb/cosmosdb_test.go b/modules/azure/cosmosdb/cosmosdb_test.go
new file mode 100644
index 0000000000..9d2bcdc4a7
--- /dev/null
+++ b/modules/azure/cosmosdb/cosmosdb_test.go
@@ -0,0 +1,77 @@
+package cosmosdb_test
+
+import (
+ "context"
+ "encoding/json"
+ "testing"
+
+ "github.com/Azure/azure-sdk-for-go/sdk/data/azcosmos"
+ "github.com/stretchr/testify/require"
+
+ "github.com/testcontainers/testcontainers-go"
+ "github.com/testcontainers/testcontainers-go/modules/azure/cosmosdb"
+)
+
+func TestCosmosDB(t *testing.T) {
+ ctx := context.Background()
+
+ ctr, err := cosmosdb.Run(ctx, "mcr.microsoft.com/cosmosdb/linux/azure-cosmos-emulator:vnext-preview")
+ testcontainers.CleanupContainer(t, ctr)
+ require.NoError(t, err)
+
+ // Create Azure Cosmos client
+ connStr, err := ctr.ConnectionString(ctx)
+ require.NoError(t, err)
+ require.NotNil(t, connStr)
+
+ p, err := cosmosdb.NewContainerPolicy(ctx, ctr)
+ require.NoError(t, err)
+
+ client, err := azcosmos.NewClientFromConnectionString(connStr, p.ClientOptions())
+ require.NoError(t, err)
+ require.NotNil(t, client)
+
+ // Create database
+ createDatabaseResp, err := client.CreateDatabase(ctx, azcosmos.DatabaseProperties{ID: "myDatabase"}, nil)
+ require.NoError(t, err)
+ require.NotNil(t, createDatabaseResp)
+
+ dbClient, err := client.NewDatabase("myDatabase")
+ require.NoError(t, err)
+ require.NotNil(t, dbClient)
+
+ // Create container
+ containerProps := azcosmos.ContainerProperties{
+ ID: "myContainer",
+ PartitionKeyDefinition: azcosmos.PartitionKeyDefinition{Paths: []string{"/category"}},
+ }
+ createContainerResp, err := dbClient.CreateContainer(ctx, containerProps, nil)
+ require.NoError(t, err)
+ require.NotNil(t, createContainerResp)
+ containerClient, err := dbClient.NewContainer("myContainer")
+ require.NoError(t, err)
+ require.NotNil(t, containerClient)
+
+ // Create item
+ type Product struct {
+ ID string `json:"id"`
+ Category string `json:"category"`
+ Name string `json:"name"`
+ }
+
+ testItem := Product{ID: "item123", Category: "gear-surf-surfboards", Name: "Yamba Surfboard"}
+
+ pk := azcosmos.NewPartitionKeyString(testItem.Category)
+
+ jsonItem, err := json.Marshal(testItem)
+ require.NoError(t, err)
+
+ createItemResp, err := containerClient.CreateItem(ctx, pk, jsonItem, nil)
+ require.NoError(t, err)
+ require.NotNil(t, createItemResp)
+
+ // Read item
+ readItemResp, err := containerClient.ReadItem(ctx, pk, testItem.ID, nil)
+ require.NoError(t, err)
+ require.NotNil(t, readItemResp)
+}
diff --git a/modules/azure/cosmosdb/examples_test.go b/modules/azure/cosmosdb/examples_test.go
new file mode 100644
index 0000000000..3b4d9fccf1
--- /dev/null
+++ b/modules/azure/cosmosdb/examples_test.go
@@ -0,0 +1,85 @@
+package cosmosdb_test
+
+import (
+ "context"
+ "fmt"
+ "log"
+ "net/http"
+
+ "github.com/Azure/azure-sdk-for-go/sdk/data/azcosmos"
+
+ "github.com/testcontainers/testcontainers-go"
+ "github.com/testcontainers/testcontainers-go/modules/azure/cosmosdb"
+)
+
+func ExampleRun() {
+ ctx := context.Background()
+
+ cosmosdbContainer, err := cosmosdb.Run(ctx, "mcr.microsoft.com/cosmosdb/linux/azure-cosmos-emulator:vnext-preview")
+ defer func() {
+ if err := testcontainers.TerminateContainer(cosmosdbContainer); err != nil {
+ log.Printf("failed to terminate container: %s", err)
+ }
+ }()
+ if err != nil {
+ log.Printf("failed to start container: %s", err)
+ return
+ }
+ // }
+
+ state, err := cosmosdbContainer.State(ctx)
+ if err != nil {
+ log.Printf("failed to get container state: %s", err)
+ return
+ }
+
+ fmt.Println(state.Running)
+
+ // Output:
+ // true
+}
+
+func ExampleRun_connect() {
+ ctx := context.Background()
+
+ cosmosdbContainer, err := cosmosdb.Run(ctx, "mcr.microsoft.com/cosmosdb/linux/azure-cosmos-emulator:vnext-preview")
+ defer func() {
+ if err := testcontainers.TerminateContainer(cosmosdbContainer); err != nil {
+ log.Printf("failed to terminate container: %s", err)
+ }
+ }()
+ if err != nil {
+ log.Printf("failed to start container: %s", err)
+ return
+ }
+
+ connString, err := cosmosdbContainer.ConnectionString(ctx)
+ if err != nil {
+ log.Printf("failed to get connection string: %s", err)
+ return
+ }
+
+ p, err := cosmosdb.NewContainerPolicy(ctx, cosmosdbContainer)
+ if err != nil {
+ log.Printf("failed to create policy: %s", err)
+ return
+ }
+
+ client, err := azcosmos.NewClientFromConnectionString(connString, p.ClientOptions())
+ if err != nil {
+ log.Printf("failed to create cosmosdb client: %s", err)
+ return
+ }
+
+ createDatabaseResp, err := client.CreateDatabase(ctx, azcosmos.DatabaseProperties{ID: "myDatabase"}, nil)
+ if err != nil {
+ log.Printf("failed to create database: %s", err)
+ return
+ }
+ // }
+
+ fmt.Println(createDatabaseResp.RawResponse.StatusCode == http.StatusCreated)
+
+ // Output:
+ // true
+}
diff --git a/modules/azure/cosmosdb/policy.go b/modules/azure/cosmosdb/policy.go
new file mode 100644
index 0000000000..8dd5aa10b9
--- /dev/null
+++ b/modules/azure/cosmosdb/policy.go
@@ -0,0 +1,45 @@
+package cosmosdb
+
+import (
+ "context"
+ "fmt"
+ "net/http"
+
+ "github.com/Azure/azure-sdk-for-go/sdk/azcore"
+ "github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
+ "github.com/Azure/azure-sdk-for-go/sdk/data/azcosmos"
+)
+
+// ContainerPolicy ensures that requests always target the CosmosDB emulator container endpoint.
+// It overrides the CosmosDB client's globalEndpointManager, which would otherwise dynamically
+// update [http.Request.Host] based on global endpoint discovery, pinning all requests to the container.
+type ContainerPolicy struct {
+ endpoint string
+}
+
+func NewContainerPolicy(ctx context.Context, c *Container) (*ContainerPolicy, error) {
+ endpoint, err := c.PortEndpoint(ctx, defaultPort, "")
+ if err != nil {
+ return nil, fmt.Errorf("port endpoint: %w", err)
+ }
+
+ return &ContainerPolicy{
+ endpoint: endpoint,
+ }, nil
+}
+
+func (p *ContainerPolicy) Do(req *policy.Request) (*http.Response, error) {
+ req.Raw().Host = p.endpoint
+ req.Raw().URL.Host = p.endpoint
+
+ return req.Next()
+}
+
+// ClientOptions returns Azure CosmosDB client options that contain ContainerPolicy.
+func (p *ContainerPolicy) ClientOptions() *azcosmos.ClientOptions {
+ return &azcosmos.ClientOptions{
+ ClientOptions: azcore.ClientOptions{
+ PerRetryPolicies: []policy.Policy{p},
+ },
+ }
+}
diff --git a/modules/azure/go.mod b/modules/azure/go.mod
index f1b06b96d2..3e7aabe989 100644
--- a/modules/azure/go.mod
+++ b/modules/azure/go.mod
@@ -5,7 +5,8 @@ go 1.24.0
toolchain go1.24.7
require (
- github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.0
+ github.com/Azure/azure-sdk-for-go/sdk/azcore v1.19.1
+ github.com/Azure/azure-sdk-for-go/sdk/data/azcosmos v1.4.1
github.com/Azure/azure-sdk-for-go/sdk/data/aztables v1.3.0
github.com/Azure/azure-sdk-for-go/sdk/messaging/azeventhubs v1.3.0
github.com/Azure/azure-sdk-for-go/sdk/messaging/azservicebus v1.8.0
@@ -19,8 +20,8 @@ require (
require (
dario.cat/mergo v1.0.2 // indirect
- github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.2 // indirect
- github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 // indirect
+ github.com/Azure/azure-sdk-for-go v68.0.0+incompatible // indirect
+ github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2 // indirect
github.com/Azure/go-amqp v1.3.0 // indirect
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
github.com/Microsoft/go-winio v0.6.2 // indirect
diff --git a/modules/azure/go.sum b/modules/azure/go.sum
index 28a71e607e..1ad974a1a6 100644
--- a/modules/azure/go.sum
+++ b/modules/azure/go.sum
@@ -2,14 +2,18 @@ dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8=
dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA=
github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6 h1:He8afgbRMd7mFxO99hRNu+6tazq8nFF9lIwo9JFroBk=
github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8=
-github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.0 h1:g0EZJwz7xkXQiZAI5xi9f3WWFYBlX1CPTrR+NDToRkQ=
-github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.0/go.mod h1:XCW7KnZet0Opnr7HccfUw1PLc4CjHqpcaxW8DHklNkQ=
-github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.2 h1:F0gBpfdPLGsw+nsgk6aqqkZS1jiixa5WwFe3fk/T3Ys=
-github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.2/go.mod h1:SqINnQ9lVVdRlyC8cd1lCI0SdX4n2paeABd2K8ggfnE=
+github.com/Azure/azure-sdk-for-go v68.0.0+incompatible h1:fcYLmCpyNYRnvJbPerq7U0hS+6+I79yEDJBqVNcqUzU=
+github.com/Azure/azure-sdk-for-go v68.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
+github.com/Azure/azure-sdk-for-go/sdk/azcore v1.19.1 h1:5YTBM8QDVIBN3sxBil89WfdAAqDZbyJTgh688DSxX5w=
+github.com/Azure/azure-sdk-for-go/sdk/azcore v1.19.1/go.mod h1:YD5h/ldMsG0XiIw7PdyNhLxaM317eFh5yNLccNfGdyw=
+github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.10.1 h1:B+blDbyVIG3WaikNxPnhPiJ1MThR03b3vKGtER95TP4=
+github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.10.1/go.mod h1:JdM5psgjfBf5fo2uWOZhflPWyDBZ/O/CNAH9CtsuZE4=
+github.com/Azure/azure-sdk-for-go/sdk/data/azcosmos v1.4.1 h1:ToPLhnXvatKVN4ZkcxLOwcXOJhdu4iQl8w0efeuDz9Y=
+github.com/Azure/azure-sdk-for-go/sdk/data/azcosmos v1.4.1/go.mod h1:Krtog/7tz27z75TwM5cIS8bxEH4dcBUezcq+kGVeZEo=
github.com/Azure/azure-sdk-for-go/sdk/data/aztables v1.3.0 h1:NnE8y/opvxowwNcSNHubQUiSSEhfk3dmooLGAOmPuKs=
github.com/Azure/azure-sdk-for-go/sdk/data/aztables v1.3.0/go.mod h1:GhHzPHiiHxZloo6WvKu9X7krmSAKTyGoIwoKMbrKTTA=
-github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 h1:ywEEhmNahHBihViHepv3xPBn1663uRv2t2q/ESv9seY=
-github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0/go.mod h1:iZDifYGJTIgIIkYRNWPENUnqx6bJ2xnSDFI2tjwZNuY=
+github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2 h1:9iefClla7iYpfYWdzPCRDozdmndjTm8DXdpCzPajMgA=
+github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2/go.mod h1:XtLgD3ZD34DAaVIIAyG3objl5DynM3CQ/vMcbBNJZGI=
github.com/Azure/azure-sdk-for-go/sdk/messaging/azeventhubs v1.3.0 h1:skbmKp8umb8jMxl4A4CwvYyfCblujU00XUB/ytUjEac=
github.com/Azure/azure-sdk-for-go/sdk/messaging/azeventhubs v1.3.0/go.mod h1:nynTZqX7jGM6FQy6Y+7uFT7Y+LhaAeO3q3d48VZzH5E=
github.com/Azure/azure-sdk-for-go/sdk/messaging/azservicebus v1.8.0 h1:JNgM3Tz592fUHU2vgwgvOgKxo5s9Ki0y2wicBeckn70=
@@ -26,8 +30,8 @@ github.com/Azure/go-amqp v1.3.0 h1://1rikYhoIQNXJFXyoO/Rlb4+4EkHYfJceNtLlys2/4=
github.com/Azure/go-amqp v1.3.0/go.mod h1:vZAogwdrkbyK3Mla8m/CxSc/aKdnTZ4IbPxl51Y5WZE=
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8=
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
-github.com/AzureAD/microsoft-authentication-library-for-go v1.3.3 h1:H5xDQaE3XowWfhZRUpnfC+rGZMEVoSiji+b+/HFAPU4=
-github.com/AzureAD/microsoft-authentication-library-for-go v1.3.3/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI=
+github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2 h1:oygO0locgZJe7PpYPXT5A29ZkwJaPqcva7BVeemZOZs=
+github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI=
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
@@ -71,8 +75,8 @@ github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/golang-jwt/jwt v3.2.1+incompatible h1:73Z+4BJcrTC+KczS6WvTPvRGOp1WmfEP4Q1lOd9Z/+c=
-github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk=
-github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
+github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8=
+github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0ktxqI+Sida1w446QrXBRJ0nee3SNZlA=
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A=