github.com/treeverse/lakefs@v1.24.1-0.20240520134607-95648127bfb0/pkg/testutil/cosmosdb.go (about)

     1  package testutil
     2  
     3  import (
     4  	"crypto/tls"
     5  	"fmt"
     6  	"net/http"
     7  	"net/url"
     8  
     9  	"github.com/ory/dockertest/v3"
    10  	"github.com/ory/dockertest/v3/docker"
    11  )
    12  
    13  const (
    14  	CosmosDBLocalPort = "8081"
    15  )
    16  
    17  var cosmosdbLocalURI string
    18  
    19  func GetCosmosDBInstance() (string, func(), error) {
    20  	dockerPool, err := dockertest.NewPool("")
    21  	if err != nil {
    22  		return "", nil, fmt.Errorf("could not connect to Docker: %w", err)
    23  	}
    24  
    25  	cosmosdbDockerRunOptions := &dockertest.RunOptions{
    26  		Repository: "mcr.microsoft.com/cosmosdb/linux/azure-cosmos-emulator",
    27  		Tag:        "latest",
    28  		Env: []string{"AZURE_COSMOS_EMULATOR_PARTITION_COUNT=5",
    29  			"AZURE_COSMOS_EMULATOR_ENABLE_DATA_PERSISTENCE=true",
    30  			"AZURE_COSMOS_EMULATOR_IP_ADDRESS_OVERRIDE=127.0.0.1"},
    31  		PortBindings: map[docker.Port][]docker.PortBinding{
    32  			"8081/tcp":  {{HostPort: CosmosDBLocalPort}},
    33  			"10251/tcp": {{HostPort: "10251"}},
    34  			"10252/tcp": {{HostPort: "10252"}},
    35  			"10253/tcp": {{HostPort: "10253"}},
    36  			"10254/tcp": {{HostPort: "10254"}},
    37  			"10255/tcp": {{HostPort: "10255"}},
    38  		},
    39  		ExposedPorts: []string{CosmosDBLocalPort, "10251", "10252", "10253", "10254", "10255"},
    40  	}
    41  
    42  	resource, err := dockerPool.RunWithOptions(cosmosdbDockerRunOptions)
    43  	if err != nil {
    44  		return "", nil, fmt.Errorf("could not start cosmosdb emulator: %w", err)
    45  	}
    46  
    47  	cosmosdbLocalURI = "https://localhost:" + resource.GetPort("8081/tcp")
    48  	// set cleanup
    49  	closer := func() {
    50  		err = dockerPool.Purge(resource)
    51  		if err != nil {
    52  			panic("could not kill cosmosdb local container")
    53  		}
    54  	}
    55  
    56  	// expire, just to make sure
    57  	err = resource.Expire(dbContainerTimeoutSeconds)
    58  	if err != nil {
    59  		return "", nil, fmt.Errorf("could not expire cosmosdb local emulator: %w", err)
    60  	}
    61  	p, err := url.JoinPath(cosmosdbLocalURI, "/_explorer/emulator.pem")
    62  	if err != nil {
    63  		return "", nil, fmt.Errorf("joining urls: %w", err)
    64  	}
    65  
    66  	err = dockerPool.Retry(func() error {
    67  		// waiting for cosmosdb container to be ready by issuing an HTTP get request with
    68  		// exponential backoff retry. The response is not really meaningful for that case
    69  		// and so is ignored
    70  		client := http.Client{Transport: &http.Transport{
    71  			TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, //nolint:gosec // ignore self-signed cert for local testing using the emulator
    72  		}}
    73  		resp, err := client.Get(p)
    74  		if err != nil {
    75  			return err
    76  		}
    77  		_ = resp.Body.Close()
    78  		return nil
    79  	})
    80  	if err != nil {
    81  		return "", nil, fmt.Errorf("could not connect to cosmosdb emulator at %s: %w", cosmosdbLocalURI, err)
    82  	}
    83  
    84  	// return DB URI
    85  	return cosmosdbLocalURI, closer, nil
    86  }