Skip to content

Commit

Permalink
feat: allow explicitly specifying provider type
Browse files Browse the repository at this point in the history
  • Loading branch information
austince committed Dec 12, 2023
1 parent e983907 commit 6fb035c
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 9 deletions.
9 changes: 9 additions & 0 deletions docs/system_requirements/using_podman.md
Expand Up @@ -35,6 +35,15 @@ func TestSomething(t *testing.T) {
}
```

If using the [Podman Desktop Docker compatibility mode](https://podman-desktop.io/docs/migrating-from-docker/using-podman-mac-helper),
where the `DOCKER_HOST` still points to the Docker socket,
you can also configure the provider explicitly in a `.testcontainers.properties` file
or the `TESTCONTAINERS_PROVIDER_TYPE` env variable.
```properties
tc.provider=podman
```


The `ProviderPodman` configures the `DockerProvider` with the correct default network for Podman to ensure complex network scenarios are working as with Docker.

## Podman socket activation
Expand Down
3 changes: 3 additions & 0 deletions internal/config/config.go
Expand Up @@ -29,6 +29,7 @@ type Config struct {
RyukPrivileged bool `properties:"ryuk.container.privileged,default=false"`
RyukReconnectionTimeout time.Duration `properties:"ryuk.reconnection.timeout,default=10s"`
RyukConnectionTimeout time.Duration `properties:"ryuk.connection.timeout,default=1m"`
ProviderType string `properties:"provider.type,default="`
TestcontainersHost string `properties:"tc.host,default="`
}

Expand Down Expand Up @@ -80,6 +81,8 @@ func read() Config {
config.RyukPrivileged = ryukPrivilegedEnv == "true"
}

config.ProviderType = os.Getenv("TESTCONTAINERS_PROVIDER_TYPE")

return config
}

Expand Down
31 changes: 27 additions & 4 deletions provider.go
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"errors"
"fmt"
"github.com/testcontainers/testcontainers-go/internal/config"
"os"
"strings"

Expand Down Expand Up @@ -102,12 +103,21 @@ func (t ProviderType) GetProvider(opts ...GenericProviderOption) (GenericProvide
o.ApplyGenericTo(opt)
}

pt := t
if pt == ProviderDefault && strings.Contains(os.Getenv("DOCKER_HOST"), "podman.sock") {
pt = ProviderPodman
providerType := t
if providerType == ProviderDefault {
cfg := config.Read()
var err error
providerType, err = getProviderType(cfg.ProviderType)
if err != nil {
return nil, err
}
}

if providerType == ProviderDefault && strings.Contains(os.Getenv("DOCKER_HOST"), "podman.sock") {
providerType = ProviderPodman
}

switch pt {
switch providerType {
case ProviderDefault, ProviderDocker:
providerOptions := append(Generic2DockerOptions(opts...), WithDefaultBridgeNetwork(Bridge))
provider, err := NewDockerProvider(providerOptions...)
Expand Down Expand Up @@ -157,3 +167,16 @@ func NewDockerProvider(provOpts ...DockerProviderOption) (*DockerProvider, error

return p, nil
}

// getProviderType maps a human-readable string to a corresponding ProviderType.
func getProviderType(providerType string) (ProviderType, error) {
switch providerType {
case "":
return ProviderDefault, nil
case "docker":
return ProviderDocker, nil
case "podman":
return ProviderPodman, nil
}
return 0, errors.New(fmt.Sprintf("unknown provider: %s", providerType))
}
63 changes: 58 additions & 5 deletions provider_test.go
Expand Up @@ -2,6 +2,9 @@ package testcontainers

import (
"context"
"github.com/testcontainers/testcontainers-go/internal/config"
"os"
"path/filepath"
"testing"

"github.com/testcontainers/testcontainers-go/internal/testcontainersdocker"
Expand All @@ -12,11 +15,12 @@ func TestProviderTypeGetProviderAutodetect(t *testing.T) {
const podmanSocket = "unix://$XDG_RUNTIME_DIR/podman/podman.sock"

tests := []struct {
name string
tr ProviderType
DockerHost string
want string
wantErr bool
name string
tr ProviderType
PropertiesProvider string
DockerHost string
want string
wantErr bool
}{
{
name: "default provider without podman.socket",
Expand Down Expand Up @@ -55,6 +59,21 @@ func TestProviderTypeGetProviderAutodetect(t *testing.T) {
DockerHost: podmanSocket,
want: Podman,
},
{
name: "default provider with podman configured in properties",
tr: ProviderDefault,
PropertiesProvider: "podman",
DockerHost: dockerHost,
want: Podman,
},
{
// Explicitly setting Docker provider should not be overridden by properties
name: "docker provider with podman configured in properties",
tr: ProviderDocker,
PropertiesProvider: "podman",
DockerHost: dockerHost,
want: Bridge,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
Expand All @@ -64,6 +83,8 @@ func TestProviderTypeGetProviderAutodetect(t *testing.T) {

t.Setenv("DOCKER_HOST", tt.DockerHost)

setupTestcontainersProperties(t, "provider.type="+tt.PropertiesProvider)

got, err := tt.tr.GetProvider()
if (err != nil) != tt.wantErr {
t.Errorf("ProviderType.GetProvider() error = %v, wantErr %v", err, tt.wantErr)
Expand All @@ -79,3 +100,35 @@ func TestProviderTypeGetProviderAutodetect(t *testing.T) {
})
}
}

func setupTestcontainersProperties(t *testing.T, content string) {
t.Cleanup(func() {
// reset the properties file after the test
config.Reset()
})

config.Reset()

tmpDir := t.TempDir()
homeDir := filepath.Join(tmpDir, "home")
err := createTmpDir(homeDir)
if err != nil {
t.Fatalf("failed to create tmp home dir: %v", err)
}
t.Setenv("HOME", homeDir)
t.Setenv("USERPROFILE", homeDir) // Windows support

if err := os.WriteFile(filepath.Join(homeDir, ".testcontainers.properties"), []byte(content), 0o600); err != nil {
t.Errorf("Failed to create the file: %v", err)
return
}
}

func createTmpDir(dir string) error {
err := os.MkdirAll(dir, 0o755)
if err != nil {
return err
}

return nil
}

0 comments on commit 6fb035c

Please sign in to comment.