Skip to content

Commit

Permalink
Merge branch 'master' into 128-bash-host-port
Browse files Browse the repository at this point in the history
  • Loading branch information
mdelapenya committed Feb 5, 2020
2 parents 1a20327 + c0c9a5c commit b04cfb9
Show file tree
Hide file tree
Showing 8 changed files with 221 additions and 5 deletions.
4 changes: 4 additions & 0 deletions container.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package testcontainers

import (
"context"
"github.com/docker/docker/api/types/container"
"io"

"github.com/docker/docker/pkg/archive"
Expand Down Expand Up @@ -68,6 +69,7 @@ type ContainerRequest struct {
Labels map[string]string
BindMounts map[string]string
VolumeMounts map[string]string
Tmpfs map[string]string
RegistryCred string
WaitingFor wait.Strategy
Name string // for specifying container name
Expand All @@ -76,6 +78,8 @@ type ContainerRequest struct {
NetworkAliases map[string][]string // for specifying network aliases
SkipReaper bool // indicates whether we skip setting up a reaper for this
ReaperImage string // alternative reaper image
AutoRemove bool // if set to true, the container will be removed from the host when stopped
NetworkMode container.NetworkMode
}

// ProviderType is an enum for the possible providers
Expand Down
38 changes: 38 additions & 0 deletions container_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import (
"bytes"
"context"
"io"
"io/ioutil"
"strings"
"testing"
"time"

Expand Down Expand Up @@ -265,3 +267,39 @@ func Test_BuildImageWithContexts(t *testing.T) {

}
}

func Test_GetLogsFromFailedContainer(t *testing.T) {
ctx := context.Background()
req := ContainerRequest{
Image: "alpine",
Cmd: []string{"echo", "-n", "I was not expecting this"},
WaitingFor: wait.ForLog("I was expecting this").WithStartupTimeout(5 * time.Second),
}

c, err := GenericContainer(ctx, GenericContainerRequest{
ContainerRequest: req,
Started: true,
})

if err != nil && err.Error() != "failed to start container: context deadline exceeded" {
t.Fatal(err)
} else if err == nil {
c.Terminate(ctx)
t.Fatal("was expecting error starting container")
}

logs, logErr := c.Logs(ctx)
if logErr != nil {
t.Fatal(logErr)
}

b, err := ioutil.ReadAll(logs)
if err != nil {
t.Fatal(err)
}

log := string(b)
if strings.Contains(log, "I was not expecting this") == false {
t.Fatalf("could not find expected log in %s", log)
}
}
4 changes: 3 additions & 1 deletion docker.go
Original file line number Diff line number Diff line change
Expand Up @@ -443,8 +443,10 @@ func (p *DockerProvider) CreateContainer(ctx context.Context, req ContainerReque
hostConfig := &container.HostConfig{
PortBindings: exposedPortMap,
Mounts: mounts,
AutoRemove: true,
Tmpfs: req.Tmpfs,
AutoRemove: req.AutoRemove,
Privileged: req.Privileged,
NetworkMode: req.NetworkMode,
}

endpointConfigs := map[string]*network.EndpointSettings{}
Expand Down
99 changes: 98 additions & 1 deletion docker_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@ package testcontainers
import (
"context"
"fmt"
"github.com/docker/docker/api/types/volume"
"net/http"
"path/filepath"
"testing"
"time"

"github.com/docker/docker/api/types/volume"

"database/sql"
// Import mysql into the scope of this package (required)
_ "github.com/go-sql-driver/mysql"
Expand Down Expand Up @@ -89,6 +90,52 @@ func TestContainerAttachedToNewNetwork(t *testing.T) {
}
}

func TestContainerWithHostNetworkOptions(t *testing.T) {
ctx := context.Background()
gcr := GenericContainerRequest{ContainerRequest: ContainerRequest{
Image: "nginx",
SkipReaper: true,
NetworkMode: "host",
},
Started: true,
}

nginxC, err := GenericContainer(ctx, gcr)
if err != nil {
t.Fatal(err)
}

defer nginxC.Terminate(ctx)

host, err := nginxC.Host(ctx)
if err != nil {
t.Errorf("Expected host %s. Got '%d'.", host, err)
}

_, err = http.Get("http://" + host + ":80")
if err != nil {
t.Errorf("Expected OK response. Got '%d'.", err)
}
}

func TestContainerWithNetworkModeAndNetworkTogether(t *testing.T) {
ctx := context.Background()
gcr := GenericContainerRequest{ContainerRequest: ContainerRequest{
Image: "nginx",
SkipReaper: true,
NetworkMode: "host",
Networks: []string{"new-network"},
},
Started: true,
}

_, err := GenericContainer(ctx, gcr)
if err != nil {
// Error when NetworkMode = host and Network = []string{"bridge"}
t.Logf("Can't use Network and NetworkMode together, %s", err)
}
}

func TestContainerReturnItsContainerID(t *testing.T) {
ctx := context.Background()
nginxA, err := GenericContainer(ctx, GenericContainerRequest{
Expand Down Expand Up @@ -987,3 +1034,53 @@ func TestContainerCreationWithBindAndVolume(t *testing.T) {
}
}()
}

func TestContainerWithTmpFs(t *testing.T) {
ctx := context.Background()
req := ContainerRequest{
Image: "busybox",
Cmd: []string{"sleep", "10"},
Tmpfs: map[string]string{"/testtmpfs": "rw"},
}

container, err := GenericContainer(ctx, GenericContainerRequest{
ContainerRequest: req,
Started: true,
})
if err != nil {
t.Fatal(err)
}
defer func() {
t.Log("terminating container")
err := container.Terminate(ctx)
if err != nil {
t.Fatal(err)
}
}()

var path = "/testtmpfs/test.file"

c, err := container.Exec(ctx, []string{"ls", path})
if err != nil {
t.Fatal(err)
}
if c != 1 {
t.Fatalf("File %s should not have existed, expected return code 1, got %v", path, c)
}

c, err = container.Exec(ctx, []string{"touch", path})
if err != nil {
t.Fatal(err)
}
if c != 0 {
t.Fatalf("File %s should have been created successfully, expected return code 0, got %v", path, c)
}

c, err = container.Exec(ctx, []string{"ls", path})
if err != nil {
t.Fatal(err)
}
if c != 0 {
t.Fatalf("File %s should exist, expected return code 0, got %v", path, c)
}
}
6 changes: 3 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ require (
github.com/docker/docker v0.7.3-0.20190506211059-b20a14b54661
github.com/docker/go-connections v0.4.0
github.com/docker/go-units v0.3.3 // indirect
github.com/go-redis/redis v6.15.6+incompatible
github.com/go-sql-driver/mysql v1.4.1
github.com/go-redis/redis v6.15.7+incompatible
github.com/go-sql-driver/mysql v1.5.0
github.com/gogo/protobuf v1.2.0 // indirect
github.com/gorilla/context v1.1.1 // indirect
github.com/gorilla/mux v1.6.2 // indirect
Expand All @@ -24,7 +24,7 @@ require (
github.com/opencontainers/go-digest v1.0.0-rc1 // indirect
github.com/opencontainers/image-spec v1.0.1 // indirect
github.com/opencontainers/runc v0.1.1 // indirect
github.com/pkg/errors v0.8.1
github.com/pkg/errors v0.9.1
github.com/satori/go.uuid v1.2.0
github.com/sirupsen/logrus v1.2.0 // indirect
golang.org/x/sys v0.0.0-20181228144115-9a3f9b0469bb // indirect
Expand Down
8 changes: 8 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,12 @@ github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/go-redis/redis v6.15.6+incompatible h1:H9evprGPLI8+ci7fxQx6WNZHJSb7be8FqJQRhdQZ5Sg=
github.com/go-redis/redis v6.15.6+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
github.com/go-redis/redis v6.15.7+incompatible h1:3skhDh95XQMpnqeqNftPkQD9jL9e5e36z/1SUm6dy1U=
github.com/go-redis/redis v6.15.7+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA=
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/gogo/protobuf v1.2.0 h1:xU6/SpYbvkNYiptHJYEDRseDLvYE7wSqhYYNy0QSUzI=
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
Expand Down Expand Up @@ -65,6 +69,10 @@ github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.0 h1:J8lpUdobwIeCI7OiSxHqEwJUKvJwicL5+3v1oe2Yb4k=
github.com/pkg/errors v0.9.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
Expand Down
1 change: 1 addition & 0 deletions reaper.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ func NewReaper(ctx context.Context, sessionID string, provider ReaperProvider, r
BindMounts: map[string]string{
"/var/run/docker.sock": "/var/run/docker.sock",
},
AutoRemove: true,
}

c, err := provider.RunContainer(ctx, req)
Expand Down
66 changes: 66 additions & 0 deletions wait/sql.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package wait

import (
"context"
"database/sql"
"fmt"
"github.com/docker/go-connections/nat"
"time"
)

//ForSQL constructs a new waitForSql strategy for the given driver
func ForSQL(port nat.Port, driver string, url func(nat.Port) string) *waitForSql {
return &waitForSql{
Port: port,
URL: url,
Driver: driver,
}
}

type waitForSql struct {
URL func(port nat.Port) string
Driver string
Port nat.Port
startupTimeout time.Duration
}

//Timeout sets the maximum waiting time for the strategy after which it'll give up and return an error
func (w *waitForSql) Timeout(duration time.Duration) *waitForSql {
w.startupTimeout = duration
return w
}

//WaitUntilReady repeatedly tries to run "SELECT 1" query on the given port using sql and driver.
// If the it doesn't succeed until the timeout value which defaults to 10 seconds, it will return an error
func (w *waitForSql) WaitUntilReady(ctx context.Context, target StrategyTarget) (err error) {
if w.startupTimeout == 0 {
w.startupTimeout = time.Second * 10
}
ctx, cancel := context.WithTimeout(ctx, w.startupTimeout)
defer cancel()

ticker := time.NewTicker(time.Millisecond * 100)
defer ticker.Stop()

port, err := target.MappedPort(ctx, w.Port)
if err != nil {
return fmt.Errorf("target.MappedPort: %v", err)
}

db, err := sql.Open(w.Driver, w.URL(port))
if err != nil {
return fmt.Errorf("sql.Open: %v", err)
}
for {
select {
case <-ctx.Done():
return ctx.Err()
case <-ticker.C:

if _, err := db.ExecContext(ctx, "SELECT 1"); err != nil {
continue
}
return nil
}
}
}

0 comments on commit b04cfb9

Please sign in to comment.