Skip to content

Commit

Permalink
docs(docker-compose): add docs about new ComposeStack API
Browse files Browse the repository at this point in the history
  • Loading branch information
prskr committed Aug 11, 2022
1 parent f880dcb commit a2ec5a6
Show file tree
Hide file tree
Showing 5 changed files with 221 additions and 86 deletions.
40 changes: 37 additions & 3 deletions compose.go
Expand Up @@ -2,6 +2,7 @@ package testcontainers

import (
"context"
"errors"
"path/filepath"
"runtime"
"strings"
Expand All @@ -10,6 +11,7 @@ import (
"github.com/docker/cli/cli/flags"
"github.com/docker/compose/v2/pkg/api"
"github.com/docker/compose/v2/pkg/compose"
"github.com/google/uuid"

"github.com/testcontainers/testcontainers-go/wait"
)
Expand All @@ -19,6 +21,17 @@ const (
envComposeFile = "COMPOSE_FILE"
)

var ErrNoStackConfigured = errors.New("no stack files configured")

type composeStackOptions struct {
Identifier string
Paths []string
}

type ComposeStackOption interface {
applyToComposeStack(o *composeStackOptions)
}

type stackUpOptions struct {
api.CreateOptions
api.StartOptions
Expand All @@ -43,6 +56,7 @@ type ComposeStack interface {
Services() []string
WaitForService(s string, strategy wait.Strategy) ComposeStack
WithEnv(m map[string]string) ComposeStack
WithOsEnv() ComposeStack
ServiceContainer(ctx context.Context, svcName string) (*DockerContainer, error)
}

Expand All @@ -63,7 +77,27 @@ type waitService struct {
publishedPort int
}

func NewDockerComposeAPI(filePaths []string, identifier string) (*dockerComposeAPI, error) {
func WithStackFiles(filePaths ...string) ComposeStackOption {
return ComposeStackFiles(filePaths)
}

func NewDockerComposeAPI(filePaths ...string) (*dockerComposeAPI, error) {
return NewDockerComposeAPIWith(WithStackFiles(filePaths...))
}

func NewDockerComposeAPIWith(opts ...ComposeStackOption) (*dockerComposeAPI, error) {
composeOptions := composeStackOptions{
Identifier: uuid.New().String(),
}

for i := range opts {
opts[i].applyToComposeStack(&composeOptions)
}

if len(composeOptions.Paths) < 1 {
return nil, ErrNoStackConfigured
}

dockerCli, err := command.NewDockerCli()
if err != nil {
return nil, err
Expand All @@ -76,8 +110,8 @@ func NewDockerComposeAPI(filePaths []string, identifier string) (*dockerComposeA
}

composeAPI := &dockerComposeAPI{
name: identifier,
configs: filePaths,
name: composeOptions.Identifier,
configs: composeOptions.Paths,
composeService: compose.NewComposeService(dockerCli),
dockerClient: dockerCli.Client(),
waitStrategies: make(map[string]wait.Strategy),
Expand Down
21 changes: 21 additions & 0 deletions compose_api.go
Expand Up @@ -75,6 +75,22 @@ func (ri RemoveImages) applyToStackDown(o *stackDownOptions) {
}
}

type ComposeStackFiles []string

func (f ComposeStackFiles) applyToComposeStack(o *composeStackOptions) {
o.Paths = f
}

type StackIdentifier string

func (f StackIdentifier) applyToComposeStack(o *composeStackOptions) {
o.Identifier = string(f)
}

func (f StackIdentifier) String() string {
return string(f)
}

const (
// RemoveImagesAll - remove all images used by the stack
RemoveImagesAll RemoveImages = iota
Expand Down Expand Up @@ -184,6 +200,11 @@ func (d *dockerComposeAPI) WithEnv(m map[string]string) ComposeStack {
return d
}

func (d *dockerComposeAPI) WithOsEnv() ComposeStack {
d.projectOptions = append(d.projectOptions, cli.WithOsEnv)
return d
}

func (d *dockerComposeAPI) ServiceContainer(ctx context.Context, svcName string) (*DockerContainer, error) {
d.lock.Lock()
defer d.lock.Unlock()
Expand Down
94 changes: 20 additions & 74 deletions compose_api_test.go
Expand Up @@ -13,11 +13,7 @@ import (
)

func TestDockerComposeAPI(t *testing.T) {
path := "./testresources/docker-compose-simple.yml"

identifier := testNameHash(t.Name())

compose, err := NewDockerComposeAPI([]string{path}, identifier)
compose, err := NewDockerComposeAPI("./testresources/docker-compose-simple.yml")
assert.NoError(t, err, "NewDockerComposeAPI()")

t.Cleanup(func() {
Expand All @@ -31,11 +27,7 @@ func TestDockerComposeAPI(t *testing.T) {
}

func TestDockerComposeAPIStrategyForInvalidService(t *testing.T) {
path := "./testresources/docker-compose-simple.yml"

identifier := testNameHash(t.Name())

compose, err := NewDockerComposeAPI([]string{path}, identifier)
compose, err := NewDockerComposeAPI("./testresources/docker-compose-simple.yml")
assert.NoError(t, err, "NewDockerComposeAPI()")

t.Cleanup(func() {
Expand All @@ -59,11 +51,7 @@ func TestDockerComposeAPIStrategyForInvalidService(t *testing.T) {
}

func TestDockerComposeAPIWithWaitLogStrategy(t *testing.T) {
path := "./testresources/docker-compose-complex.yml"

identifier := testNameHash(t.Name())

compose, err := NewDockerComposeAPI([]string{path}, identifier)
compose, err := NewDockerComposeAPI("./testresources/docker-compose-complex.yml")
assert.NoError(t, err, "NewDockerComposeAPI()")

t.Cleanup(func() {
Expand All @@ -87,11 +75,7 @@ func TestDockerComposeAPIWithWaitLogStrategy(t *testing.T) {
}

func TestDockerComposeAPIWithRunServices(t *testing.T) {
path := "./testresources/docker-compose-complex.yml"

identifier := testNameHash(t.Name())

compose, err := NewDockerComposeAPI([]string{path}, identifier)
compose, err := NewDockerComposeAPI("./testresources/docker-compose-complex.yml")
assert.NoError(t, err, "NewDockerComposeAPI()")

t.Cleanup(func() {
Expand All @@ -117,11 +101,7 @@ func TestDockerComposeAPIWithRunServices(t *testing.T) {
}

func TestDockerComposeAPIWithWaitForService(t *testing.T) {
path := "./testresources/docker-compose-simple.yml"

identifier := testNameHash(t.Name())

compose, err := NewDockerComposeAPI([]string{path}, identifier)
compose, err := NewDockerComposeAPI("./testresources/docker-compose-simple.yml")
assert.NoError(t, err, "NewDockerComposeAPI()")

t.Cleanup(func() {
Expand All @@ -147,11 +127,7 @@ func TestDockerComposeAPIWithWaitForService(t *testing.T) {
}

func TestDockerComposeAPIWithWaitHTTPStrategy(t *testing.T) {
path := "./testresources/docker-compose-simple.yml"

identifier := testNameHash(t.Name())

compose, err := NewDockerComposeAPI([]string{path}, identifier)
compose, err := NewDockerComposeAPI("./testresources/docker-compose-simple.yml")
assert.NoError(t, err, "NewDockerComposeAPI()")

t.Cleanup(func() {
Expand All @@ -177,11 +153,7 @@ func TestDockerComposeAPIWithWaitHTTPStrategy(t *testing.T) {
}

func TestDockerComposeAPIWithContainerName(t *testing.T) {
path := "./testresources/docker-compose-container-name.yml"

identifier := testNameHash(t.Name())

compose, err := NewDockerComposeAPI([]string{path}, identifier)
compose, err := NewDockerComposeAPI("./testresources/docker-compose-container-name.yml")
assert.NoError(t, err, "NewDockerComposeAPI()")

t.Cleanup(func() {
Expand All @@ -207,11 +179,7 @@ func TestDockerComposeAPIWithContainerName(t *testing.T) {
}

func TestDockerComposeAPIWithWaitStrategy_NoExposedPorts(t *testing.T) {
path := "./testresources/docker-compose-no-exposed-ports.yml"

identifier := testNameHash(t.Name())

compose, err := NewDockerComposeAPI([]string{path}, identifier)
compose, err := NewDockerComposeAPI("./testresources/docker-compose-no-exposed-ports.yml")
assert.NoError(t, err, "NewDockerComposeAPI()")

t.Cleanup(func() {
Expand All @@ -234,11 +202,7 @@ func TestDockerComposeAPIWithWaitStrategy_NoExposedPorts(t *testing.T) {
}

func TestDockerComposeAPIWithMultipleWaitStrategies(t *testing.T) {
path := "./testresources/docker-compose-complex.yml"

identifier := testNameHash(t.Name())

compose, err := NewDockerComposeAPI([]string{path}, identifier)
compose, err := NewDockerComposeAPI("./testresources/docker-compose-complex.yml")
assert.NoError(t, err, "NewDockerComposeAPI()")

t.Cleanup(func() {
Expand All @@ -263,11 +227,7 @@ func TestDockerComposeAPIWithMultipleWaitStrategies(t *testing.T) {
}

func TestDockerComposeAPIWithFailedStrategy(t *testing.T) {
path := "./testresources/docker-compose-simple.yml"

identifier := testNameHash(t.Name())

compose, err := NewDockerComposeAPI([]string{path}, identifier)
compose, err := NewDockerComposeAPI("./testresources/docker-compose-simple.yml")
assert.NoError(t, err, "NewDockerComposeAPI()")

t.Cleanup(func() {
Expand Down Expand Up @@ -295,11 +255,7 @@ func TestDockerComposeAPIWithFailedStrategy(t *testing.T) {
}

func TestDockerComposeAPIComplex(t *testing.T) {
path := "./testresources/docker-compose-complex.yml"

identifier := testNameHash(t.Name())

compose, err := NewDockerComposeAPI([]string{path}, identifier)
compose, err := NewDockerComposeAPI("./testresources/docker-compose-complex.yml")
assert.NoError(t, err, "NewDockerComposeAPI()")

t.Cleanup(func() {
Expand All @@ -319,11 +275,9 @@ func TestDockerComposeAPIComplex(t *testing.T) {
}

func TestDockerComposeAPIWithEnvironment(t *testing.T) {
path := "./testresources/docker-compose-simple.yml"

identifier := testNameHash(t.Name())

compose, err := NewDockerComposeAPI([]string{path}, identifier)
compose, err := NewDockerComposeAPIWith(WithStackFiles("./testresources/docker-compose-simple.yml"), identifier)
assert.NoError(t, err, "NewDockerComposeAPI()")

t.Cleanup(func() {
Expand All @@ -350,19 +304,19 @@ func TestDockerComposeAPIWithEnvironment(t *testing.T) {
"bar": "BAR",
}
absent := map[string]string{}
assertContainerEnvironmentVariables(t, identifier, "nginx", present, absent)
assertContainerEnvironmentVariables(t, identifier.String(), "nginx", present, absent)
}

func TestDockerComposeAPIWithMultipleComposeFiles(t *testing.T) {
composeFiles := []string{
composeFiles := ComposeStackFiles{
"testresources/docker-compose-simple.yml",
"testresources/docker-compose-postgres.yml",
"testresources/docker-compose-override.yml",
}

identifier := testNameHash(t.Name())

compose, err := NewDockerComposeAPI(composeFiles, identifier)
compose, err := NewDockerComposeAPIWith(composeFiles, identifier)
assert.NoError(t, err, "NewDockerComposeAPI()")

t.Cleanup(func() {
Expand Down Expand Up @@ -392,15 +346,11 @@ func TestDockerComposeAPIWithMultipleComposeFiles(t *testing.T) {
"foo": "FOO",
}
absent := map[string]string{}
assertContainerEnvironmentVariables(t, identifier, "nginx", present, absent)
assertContainerEnvironmentVariables(t, identifier.String(), "nginx", present, absent)
}

func TestDockerComposeAPIWithVolume(t *testing.T) {
path := "./testresources/docker-compose-volume.yml"

identifier := testNameHash(t.Name())

compose, err := NewDockerComposeAPI([]string{path}, identifier)
compose, err := NewDockerComposeAPI("./testresources/docker-compose-volume.yml")
assert.NoError(t, err, "NewDockerComposeAPI()")

t.Cleanup(func() {
Expand All @@ -415,11 +365,7 @@ func TestDockerComposeAPIWithVolume(t *testing.T) {
}

func TestDockerComposeAPIWithBuild(t *testing.T) {
path := "./testresources/docker-compose-build.yml"

identifier := testNameHash(t.Name())

compose, err := NewDockerComposeAPI([]string{path}, identifier)
compose, err := NewDockerComposeAPI("./testresources/docker-compose-build.yml")
assert.NoError(t, err, "NewDockerComposeAPI()")

t.Cleanup(func() {
Expand All @@ -436,6 +382,6 @@ func TestDockerComposeAPIWithBuild(t *testing.T) {
assert.NoError(t, err, "compose.Up()")
}

func testNameHash(name string) string {
return fmt.Sprintf("%x", fnv.New32a().Sum([]byte(name)))
func testNameHash(name string) StackIdentifier {
return StackIdentifier(fmt.Sprintf("%x", fnv.New32a().Sum([]byte(name))))
}

0 comments on commit a2ec5a6

Please sign in to comment.