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 May 10, 2022
1 parent 56dc8cb commit 21d8636
Show file tree
Hide file tree
Showing 18 changed files with 474 additions and 505 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}
}
53 changes: 31 additions & 22 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 @@ -128,6 +128,7 @@ func Test_GetDockerfile(t *testing.T) {
}

func Test_BuildImageWithContexts(t *testing.T) {
t.Parallel()
type TestCase struct {
Name string
ContextPath string
Expand All @@ -138,7 +139,7 @@ func Test_BuildImageWithContexts(t *testing.T) {
}

testCases := []TestCase{
TestCase{
{
Name: "test build from context archive",
ContextArchive: func() (io.Reader, error) {
var buf bytes.Buffer
Expand All @@ -149,8 +150,8 @@ func Test_BuildImageWithContexts(t *testing.T) {
}{
{
Name: "Dockerfile",
Contents: `FROM alpine
CMD ["echo", "this is from the archive"]`,
Contents: `FROM docker.io/alpine
CMD ["echo", "this is from the archive"]`,
},
}

Expand Down Expand Up @@ -182,7 +183,7 @@ func Test_BuildImageWithContexts(t *testing.T) {
},
ExpectedEchoOutput: "this is from the archive",
},
TestCase{
{
Name: "test build from context archive and be able to use files in it",
ContextArchive: func() (io.Reader, error) {
var buf bytes.Buffer
Expand All @@ -197,17 +198,17 @@ func Test_BuildImageWithContexts(t *testing.T) {
},
{
Name: "Dockerfile",
Contents: `FROM alpine
WORKDIR /app
COPY . .
CMD ["sh", "./say_hi.sh"]`,
Contents: `FROM docker.io/alpine
WORKDIR /app
COPY . .
CMD ["sh", "./say_hi.sh"]`,
},
}

for _, f := range files {
header := tar.Header{
Name: f.Name,
Mode: 0777,
Mode: 0o0777,
Size: int64(len(f.Contents)),
Typeflag: tar.TypeReg,
Format: tar.FormatGNU,
Expand All @@ -232,7 +233,7 @@ func Test_BuildImageWithContexts(t *testing.T) {
},
ExpectedEchoOutput: "hi this is from the say_hi.sh file!",
},
TestCase{
{
Name: "test buildling from a context on the filesystem",
ContextPath: "./testresources",
Dockerfile: "echo.Dockerfile",
Expand All @@ -241,7 +242,7 @@ func Test_BuildImageWithContexts(t *testing.T) {
return nil, nil
},
},
TestCase{
{
Name: "it should error if neither a context nor a context archive are specified",
ContextPath: "",
ContextArchive: func() (io.Reader, error) {
Expand All @@ -252,7 +253,9 @@ func Test_BuildImageWithContexts(t *testing.T) {
}

for _, testCase := range testCases {
testCase := testCase
t.Run(testCase.Name, func(t *testing.T) {
t.Parallel()
ctx := context.Background()
a, err := testCase.ContextArchive()
if err != nil {
Expand Down Expand Up @@ -280,16 +283,15 @@ func Test_BuildImageWithContexts(t *testing.T) {
} else {
c.Terminate(ctx)
}

})

}
}

func Test_GetLogsFromFailedContainer(t *testing.T) {
t.Parallel()
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 @@ -323,6 +325,7 @@ func Test_GetLogsFromFailedContainer(t *testing.T) {
}

func TestShouldStartContainersInParallel(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Minute)
t.Cleanup(cancel)

Expand All @@ -336,8 +339,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 +350,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 All @@ -360,6 +363,7 @@ func createTestContainer(t *testing.T, ctx context.Context) int {
}

func TestBindMount(t *testing.T) {
t.Parallel()
type args struct {
hostPath string
mountTarget ContainerMountTarget
Expand All @@ -381,13 +385,16 @@ func TestBindMount(t *testing.T) {
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
assert.Equalf(t, tt.want, BindMount(tt.args.hostPath, tt.args.mountTarget), "BindMount(%v, %v)", tt.args.hostPath, tt.args.mountTarget)
})
}
}

func TestVolumeMount(t *testing.T) {
t.Parallel()
type args struct {
volumeName string
mountTarget ContainerMountTarget
Expand All @@ -409,7 +416,9 @@ func TestVolumeMount(t *testing.T) {
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
assert.Equalf(t, tt.want, VolumeMount(tt.args.volumeName, tt.args.mountTarget), "VolumeMount(%v, %v)", tt.args.volumeName, tt.args.mountTarget)
})
}
Expand Down
Loading

0 comments on commit 21d8636

Please sign in to comment.