Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 1 addition & 10 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# tool variables
GO=go
GO=GO111MODULE=on go
DEP=dep
GOMETALINTER=gometalinter

Expand All @@ -9,23 +9,14 @@ Q=@

## make rules

all: get build install

get:
$(Q)$(DEP) ensure

build:
$(Q)$(GO) build $(GO_BUILD_FLAGS)

install:
$(Q)$(GO) install

test:
$(Q)$(GO) test

lint:
$(Q)$(GOMETALINTER) $(GOMETALINTER_FLAGS) .


.PHONY: all build get install test lint

60 changes: 52 additions & 8 deletions container.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,7 @@ func ResetCustom(fn func() error) ResetFunc {
// ContainerOpts is an option struct for creating a docker container
// configuration.
type ContainerOpts struct {
ForcePull bool
// AutoRemove is always set to true
ForcePull bool
Config *container.Config
HostConfig *container.HostConfig
Name string
Expand Down Expand Up @@ -116,6 +115,7 @@ type Container struct { // nolint: maligned
cancel func()
resetF ResetFunc
closed bool
removed bool
}

// Creates a new container configuration with the given options.
Expand All @@ -125,11 +125,9 @@ func newContainer(t testing.TB, c *client.Client, opts ContainerOpts) *Container
opts.HealthCheckTimeout = 30 * time.Second
}

// always autoremove
if opts.HostConfig == nil {
opts.HostConfig = &container.HostConfig{}
}
opts.HostConfig.AutoRemove = true

// set testingdock label
opts.Config.Labels = createTestingLabel()
Expand Down Expand Up @@ -175,7 +173,7 @@ func (c *Container) start(ctx context.Context) { // nolint: gocyclo
}

if len(images) == 0 || c.forcePull {
printf("(setup) %-25s - pulling image", c.ccfg.Image)
printf("(setup ) %-25s - pulling image", c.ccfg.Image)
img, err := c.imagePull(ctx)
if err != nil {
c.t.Fatalf("image downloading failure of '%s': %s", c.ccfg.Image, err.Error())
Expand Down Expand Up @@ -209,17 +207,21 @@ func (c *Container) start(ctx context.Context) { // nolint: gocyclo
c.t.Fatalf("container disconnect failure: %s", err.Error())
}
printf("(cancel) %-25s (%s) - container disconnected from: %s", c.Name, c.ID, c.network.name)
if err := c.cli.ContainerRemove(ctx, c.ID, types.ContainerRemoveOptions{Force: true}); err != nil {
c.t.Fatalf("container removal failure: %s", err.Error())
timeout := time.Second * 5
if err := c.cli.ContainerStop(ctx, c.ID, &timeout); err != nil {
c.t.Fatalf("container stop failure: %s", err.Error())
}
printf("(cancel) %-25s (%s) - container removed", c.Name, c.ID)
printf("(cancel) %-25s (%s) - container stopped", c.Name, c.ID)
}

// start the container finally
if err = c.cli.ContainerStart(ctx, c.ID, types.ContainerStartOptions{}); err != nil {
c.t.Fatalf("container start failure: %s", err.Error())
}

c.closed = false
c.removed = false

printf("(setup ) %-25s (%s) - container started", c.Name, c.ID)

// start container logging
Expand Down Expand Up @@ -303,6 +305,7 @@ func (c *Container) initialCleanup(ctx context.Context) {
if err = c.cli.ContainerRemove(ctx, cont.ID, types.ContainerRemoveOptions{
Force: true,
RemoveVolumes: true,
RemoveLinks: true,
}); err != nil {
c.t.Fatalf("container removal failure: %s", err.Error())
}
Expand Down Expand Up @@ -343,6 +346,43 @@ func (c *Container) close() error {
return nil
}

// remove removes/cleans up the container
func (c *Container) remove() {
if !c.closed {
c.t.Fatalf("container removal failed, please close containers first")
}

if SpawnSequential {
for _, cont := range c.children {
cont.remove() // nolint: errcheck
}
} else {
var wg sync.WaitGroup

wg.Add(len(c.children))
for _, cont := range c.children {
go func(cont *Container) {
defer wg.Done()
cont.remove() // nolint: errcheck
}(cont)
}
wg.Wait()
}

if c.removed {
return
}

if err := c.cli.ContainerRemove(context.TODO(), c.ID, types.ContainerRemoveOptions{
Force: true,
RemoveVolumes: true,
}); err != nil {
c.t.Fatalf("container removal failure: %s", err.Error())
}
c.removed = true
printf("(remove ) %-25s (%s) - container removed/cleaned up", c.Name, c.ID)
}

// After adds a child container (dependency, sort of)
// to the current container configuration in the same network.
func (c *Container) After(cc *Container) {
Expand All @@ -357,6 +397,10 @@ func (c *Container) reset(ctx context.Context) {
if err := c.resetF(ctx, c); err != nil {
c.t.Fatalf("container reset failure: %s", err.Error())
}

c.closed = false
c.removed = false

c.executeHealthCheck(ctx)

for _, cc := range c.children {
Expand Down
47 changes: 44 additions & 3 deletions container_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,30 @@ import (
"database/sql"
"testing"

"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/client"
"github.com/docker/go-connections/nat"
_ "github.com/lib/pq"

"github.com/m4ksio/testingdock"
"github.com/dapperlabs/testingdock"
)

func TestContainer_Start(t *testing.T) {
// set up docker client
cli, err := client.NewClientWithOpts(
client.FromEnv,
client.WithAPIVersionNegotiation(),
)
if err != nil {
t.Fatalf("error creating docker client: %s", err.Error())
}

// create suite
name := "TestContainer_Start"
s, ok := testingdock.GetOrCreateSuite(t, name, testingdock.SuiteOpts{})
s, ok := testingdock.GetOrCreateSuite(t, name, testingdock.SuiteOpts{
Client: cli,
})
if ok {
t.Fatal("this suite should not exists yet")
}
Expand All @@ -39,6 +52,7 @@ func TestContainer_Start(t *testing.T) {
ForcePull: false,
Config: &container.Config{
Image: "postgres:9.6",
Env: []string{"POSTGRES_HOST_AUTH_METHOD=trust"},
},
HostConfig: &container.HostConfig{
PortBindings: nat.PortMap{
Expand Down Expand Up @@ -79,6 +93,7 @@ func TestContainer_Start(t *testing.T) {
ForcePull: true,
Config: &container.Config{
Image: "postgres:9.6",
Env: []string{"POSTGRES_HOST_AUTH_METHOD=trust"},
},
})

Expand All @@ -91,14 +106,40 @@ func TestContainer_Start(t *testing.T) {

// start the network, this also starts the containers
s.Start(context.TODO())
defer s.Close()
defer func() {
s.Close()
s.Remove()
}()

// test stuff within the database
testQueries(t, db)

s.Reset(context.TODO())

testQueries(t, db)

if err = s.Close(); err != nil {
t.Fatalf("could not close containers: %s", err.Error())
}

list0, err := cli.ContainerList(context.TODO(), types.ContainerListOptions{All: true})
if err != nil {
t.Fatalf("could not retreive container list: %s", err.Error())
}

if err = s.Remove(); err != nil {
t.Fatalf("could not remove containers: %s", err.Error())
}

list1, err := cli.ContainerList(context.TODO(), types.ContainerListOptions{All: true})
if err != nil {
t.Fatalf("could not retreive container list: %s", err.Error())
}

if len(list0) != len(list1)+3 {
t.Fatalf("expected Remove to remove 3 containers from container list (len before %v, len after %v)", len(list0),
len(list1))
}
}

func testQueries(t *testing.T, db *sql.DB) {
Expand Down
3 changes: 2 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
module github.com/m4ksio/testingdock
module github.com/dapperlabs/testingdock

go 1.13

Expand All @@ -21,6 +21,7 @@ require (
github.com/opencontainers/image-spec v1.0.1 // indirect
github.com/opencontainers/runc v0.1.1 // indirect
github.com/sirupsen/logrus v1.4.2 // indirect
github.com/stretchr/testify v1.4.0
golang.org/x/time v0.0.0-20191024005414-555d28b269f0 // indirect
google.golang.org/grpc v1.26.0 // indirect
gopkg.in/yaml.v2 v2.2.4 // indirect
Expand Down
20 changes: 20 additions & 0 deletions network.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,22 @@ func (n *Network) close() error {
return nil
}

// remove removes all the containers in the network.
func (n *Network) remove() error {
var wg sync.WaitGroup

wg.Add(len(n.children))
for _, cont := range n.children {
go func(cont *Container) {
defer wg.Done()
cont.remove() // nolint: errcheck
}(cont)
}
wg.Wait()

return nil
}

// After adds a child container to the current network configuration.
// These containers then kind of "depend" on the network and will
// be closed when the network closes.
Expand All @@ -184,3 +200,7 @@ func (n *Network) reset(ctx context.Context) {
}
printf("(reset ) %-25s (%s) - network reseted in %s", n.name, n.id, time.Since(now))
}

func (n *Network) ID() string {
return n.id
}
6 changes: 5 additions & 1 deletion network_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import (
"context"
"testing"

"github.com/m4ksio/testingdock"
"github.com/dapperlabs/testingdock"
)

func TestNetwork_Start(t *testing.T) {
Expand All @@ -20,4 +20,8 @@ func TestNetwork_Start(t *testing.T) {
if err := s.Close(); err != nil {
t.Fatalf("Failed to close a network: %s", err.Error())
}

if err := s.Remove(); err != nil {
t.Fatalf("Failed to remove a network: %s", err.Error())
}
}
9 changes: 9 additions & 0 deletions suite.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,3 +161,12 @@ func (s *Suite) Close() error {

return nil
}

// Remove removes all the containers in the network.
func (s *Suite) Remove() error {
if s.network != nil {
return s.network.remove()
}

return nil
}
2 changes: 1 addition & 1 deletion suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (
"os"
"testing"

"github.com/m4ksio/testingdock"
"github.com/dapperlabs/testingdock"
)

func TestMain(m *testing.M) {
Expand Down