Skip to content

Commit

Permalink
Make tests compatible with Podman
Browse files Browse the repository at this point in the history
  • Loading branch information
prskr committed Apr 11, 2022
1 parent 0bad08a commit 32897fb
Show file tree
Hide file tree
Showing 18 changed files with 448 additions and 490 deletions.
96 changes: 67 additions & 29 deletions compose_test.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
package testcontainers

import (
"context"
"fmt"
"os/exec"
"regexp"
"strings"
"testing"
"time"

"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters"
"github.com/google/uuid"
"github.com/stretchr/testify/assert"

Expand Down Expand Up @@ -347,13 +350,11 @@ func TestLocalDockerComposeWithEnvironment(t *testing.T) {
assert.Equal(t, 1, len(compose.Services))
assert.Contains(t, compose.Services, "nginx")

containerNameNginx := compose.Identifier + "_nginx_1"

present := map[string]string{
"bar": "BAR",
}
absent := map[string]string{}
assertContainerEnvironmentVariables(t, containerNameNginx, present, absent)
assertContainerEnvironmentVariables(t, compose.Identifier, "nginx", present, absent)
}

func TestLocalDockerComposeWithMultipleComposeFiles(t *testing.T) {
Expand Down Expand Up @@ -386,17 +387,18 @@ func TestLocalDockerComposeWithMultipleComposeFiles(t *testing.T) {
assert.Contains(t, compose.Services, "mysql")
assert.Contains(t, compose.Services, "postgres")

containerNameNginx := compose.Identifier + "_nginx_1"

present := map[string]string{
"bar": "BAR",
"foo": "FOO",
}
absent := map[string]string{}
assertContainerEnvironmentVariables(t, containerNameNginx, present, absent)
assertContainerEnvironmentVariables(t, compose.Identifier, "nginx", present, absent)
}

func TestLocalDockerComposeWithVolume(t *testing.T) {
if providerType == ProviderPodman {
t.Skip("fails for some reason with Podman")
}
path := "./testresources/docker-compose-volume.yml"

identifier := strings.ToLower(uuid.New().String())
Expand All @@ -405,7 +407,7 @@ func TestLocalDockerComposeWithVolume(t *testing.T) {
destroyFn := func() {
err := compose.Down()
checkIfError(t, err)
assertVolumeDoesNotExist(t, fmt.Sprintf("%s_mydata", identifier))
assertVolumeDoesNotExist(t, identifier, "mydata")
}
defer destroyFn()

Expand All @@ -415,33 +417,79 @@ func TestLocalDockerComposeWithVolume(t *testing.T) {
checkIfError(t, err)
}

func assertVolumeDoesNotExist(t *testing.T, volume string) {
args := []string{"volume", "inspect", volume}
func assertVolumeDoesNotExist(tb testing.TB, composeIdentifier, volume string) {
containerClient, _, err := NewDockerClient()
if err != nil {
tb.Fatalf("Failed to get provider: %v", err)
}

output, _ := executeAndGetOutput("docker", args)
if !strings.Contains(output, "No such volume") {
t.Fatalf("Expected volume %q to not exist", volume)
volumeList, err := containerClient.VolumeList(context.Background(), filters.NewArgs())
if err != nil {
tb.Fatalf("Failed to list volumes: %v", err)
}

if len(volumeList.Warnings) > 0 {
tb.Logf("Volume list warnings: %v", volumeList.Warnings)
}

volumeNameRegexp := regexp.MustCompile(fmt.Sprintf(`^\/?%s(_|-)%s$`, composeIdentifier, volume))

for i := range volumeList.Volumes {
if volumeNameRegexp.MatchString(volumeList.Volumes[i].Name) {
tb.Fatalf("Volume should not be present")
}
}
}

func assertContainerEnvironmentVariables(t *testing.T, containerName string, present map[string]string, absent map[string]string) {
args := []string{"exec", containerName, "env"}
func assertContainerEnvironmentVariables(
tb testing.TB,
composeIdentifier, serviceName string,
present map[string]string,
absent map[string]string,
) {
containerClient, _, err := NewDockerClient()
if err != nil {
tb.Fatalf("Failed to get provider: %v", err)
}

containers, err := containerClient.ContainerList(context.Background(), types.ContainerListOptions{})
if err != nil {
tb.Fatalf("Failed to list containers: %v", err)
} else if len(containers) == 0 {
tb.Fatalf("container list empty")
}

output, err := executeAndGetOutput("docker", args)
checkIfError(t, err)
containerNameRegexp := regexp.MustCompile(fmt.Sprintf(`^\/?%s(_|-)%s(_|-)\d$`, composeIdentifier, serviceName))
var containerID string
containerLoop:
for i := range containers {
c := containers[i]
for j := range c.Names {
if containerNameRegexp.MatchString(c.Names[j]) {
containerID = c.ID
break containerLoop
}
}
}

details, err := containerClient.ContainerInspect(context.Background(), containerID)
if err != nil {
tb.Fatalf("Failed to inspect container: %v", err)
}

for k, v := range present {
keyVal := k + "=" + v
assert.Contains(t, output, keyVal)
assert.Contains(tb, details.Config.Env, keyVal)
}

for k, v := range absent {
keyVal := k + "=" + v
assert.NotContains(t, output, keyVal)
assert.NotContains(tb, details.Config.Env, keyVal)
}
}

func checkIfError(t *testing.T, err ExecError) {
t.Helper()
if err.Error != nil {
t.Fatalf("Failed when running %v: %v", err.Command, err.Error)
}
Expand All @@ -454,13 +502,3 @@ func checkIfError(t *testing.T, err ExecError) {
t.Fatalf("An error in Stderr happened when running %v: %v", err.Command, err.Stderr)
}
}

func executeAndGetOutput(command string, args []string) (string, ExecError) {
cmd := exec.Command(command, args...)
out, err := cmd.CombinedOutput()
if err != nil {
return string(out), ExecError{Error: err}
}

return string(out), ExecError{Error: nil}
}
24 changes: 11 additions & 13 deletions container_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ func Test_ContainerValidation(t *testing.T) {
}

testTable := []ContainerValidationTestCase{
ContainerValidationTestCase{
{
Name: "cannot set both context and image",
ExpectedError: errors.New("you cannot specify both an Image and Context in a ContainerRequest"),
ContainerRequest: ContainerRequest{
Expand All @@ -36,14 +36,14 @@ func Test_ContainerValidation(t *testing.T) {
Image: "redis:latest",
},
},
ContainerValidationTestCase{
{
Name: "can set image without context",
ExpectedError: nil,
ContainerRequest: ContainerRequest{
Image: "redis:latest",
},
},
ContainerValidationTestCase{
{
Name: "can set context without image",
ExpectedError: nil,
ContainerRequest: ContainerRequest{
Expand All @@ -52,15 +52,15 @@ func Test_ContainerValidation(t *testing.T) {
},
},
},
ContainerValidationTestCase{
{
Name: "Can mount same source to multiple targets",
ExpectedError: nil,
ContainerRequest: ContainerRequest{
Image: "redis:latest",
Mounts: Mounts(BindMount("/data", "/srv"), BindMount("/data", "/data")),
},
},
ContainerValidationTestCase{
{
Name: "Cannot mount multiple sources to same target",
ExpectedError: errors.New("duplicate mount target detected: /data"),
ContainerRequest: ContainerRequest{
Expand Down Expand Up @@ -149,7 +149,7 @@ func Test_BuildImageWithContexts(t *testing.T) {
}{
{
Name: "Dockerfile",
Contents: `FROM alpine
Contents: `FROM docker.io/alpine
CMD ["echo", "this is from the archive"]`,
},
}
Expand Down Expand Up @@ -197,7 +197,7 @@ func Test_BuildImageWithContexts(t *testing.T) {
},
{
Name: "Dockerfile",
Contents: `FROM alpine
Contents: `FROM docker.io/alpine
WORKDIR /app
COPY . .
CMD ["sh", "./say_hi.sh"]`,
Expand Down Expand Up @@ -280,16 +280,14 @@ func Test_BuildImageWithContexts(t *testing.T) {
} else {
c.Terminate(ctx)
}

})

}
}

func Test_GetLogsFromFailedContainer(t *testing.T) {
ctx := context.Background()
req := ContainerRequest{
Image: "alpine",
Image: "docker.io/alpine",
Cmd: []string{"echo", "-n", "I was not expecting this"},
WaitingFor: wait.ForLog("I was expecting this").WithStartupTimeout(5 * time.Second),
}
Expand Down Expand Up @@ -336,8 +334,8 @@ func TestShouldStartContainersInParallel(t *testing.T) {

func createTestContainer(t *testing.T, ctx context.Context) int {
req := ContainerRequest{
Image: "nginx",
ExposedPorts: []string{"80/tcp"},
Image: nginxAlpineImage,
ExposedPorts: []string{nginxDefaultPort},
WaitingFor: wait.ForHTTP("/"),
}
container, err := GenericContainer(ctx, GenericContainerRequest{
Expand All @@ -347,7 +345,7 @@ func createTestContainer(t *testing.T, ctx context.Context) int {
if err != nil {
t.Fatalf("could not start container: %v", err)
}
port, err := container.MappedPort(ctx, "80")
port, err := container.MappedPort(ctx, nginxDefaultPort)
if err != nil {
t.Fatalf("could not get mapped port: %v", err)
}
Expand Down
40 changes: 26 additions & 14 deletions docker.go
Original file line number Diff line number Diff line change
Expand Up @@ -613,20 +613,9 @@ func WithDefaultBridgeNetwork(bridgeNetworkName string) DockerProviderOption {
})
}

// NewDockerProvider creates a Docker provider with the EnvClient
func NewDockerProvider(provOpts ...DockerProviderOption) (*DockerProvider, error) {
func NewDockerClient() (cli *client.Client, host string, err error) {
tcConfig := readTCPropsFile()
host := tcConfig.Host

o := &DockerProviderOptions{
GenericProviderOptions: &GenericProviderOptions{
Logger: Logger,
},
}

for idx := range provOpts {
provOpts[idx].ApplyDockerTo(o)
}
host = tcConfig.Host

opts := []client.Opt{client.FromEnv}
if host != "" {
Expand All @@ -646,7 +635,30 @@ func NewDockerProvider(provOpts ...DockerProviderOption) (*DockerProvider, error
host = "unix:///var/run/docker.sock"
}

c, err := client.NewClientWithOpts(opts...)
cli, err = client.NewClientWithOpts(opts...)

if err != nil {
return nil, "", err
}

cli.NegotiateAPIVersion(context.Background())

return cli, host, nil
}

// NewDockerProvider creates a Docker provider with the EnvClient
func NewDockerProvider(provOpts ...DockerProviderOption) (*DockerProvider, error) {
o := &DockerProviderOptions{
GenericProviderOptions: &GenericProviderOptions{
Logger: Logger,
},
}

for idx := range provOpts {
provOpts[idx].ApplyDockerTo(o)
}

c, host, err := NewDockerClient()
if err != nil {
return nil, err
}
Expand Down
Loading

0 comments on commit 32897fb

Please sign in to comment.