Skip to content

Commit

Permalink
Merge pull request #176 from ikolomiyets/issue-173
Browse files Browse the repository at this point in the history
#173: Reaper reuse
  • Loading branch information
gianarb authored Apr 14, 2020
2 parents cabddc2 + 8d295a6 commit a18968f
Show file tree
Hide file tree
Showing 5 changed files with 138 additions and 26 deletions.
9 changes: 4 additions & 5 deletions docker.go
Original file line number Diff line number Diff line change
Expand Up @@ -394,11 +394,9 @@ type DockerNetwork struct {
}

// Remove is used to remove the network. It is usually triggered by as defer function.
func (n *DockerNetwork) Remove(_ context.Context) error {
if n.terminationSignal != nil {
n.terminationSignal <- true
}
return nil
func (n *DockerNetwork) Remove(ctx context.Context) error {

return n.provider.client.NetworkRemove(ctx, n.ID)
}

// DockerProvider implements the ContainerProvider interface
Expand Down Expand Up @@ -724,6 +722,7 @@ func (p *DockerProvider) CreateNetwork(ctx context.Context, req NetworkRequest)
Driver: req.Driver,
Name: req.Name,
terminationSignal: termSignal,
provider: p,
}

return n, nil
Expand Down
26 changes: 18 additions & 8 deletions docker_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,13 @@ func TestContainerAttachedToNewNetwork(t *testing.T) {
},
}

provider, err := gcr.ProviderType.GetProvider()

newNetwork, err := provider.CreateNetwork(ctx, NetworkRequest{
Name: networkName,
CheckDuplicate: true,
newNetwork, err := GenericNetwork(ctx, GenericNetworkRequest{
NetworkRequest: NetworkRequest{
Name: networkName,
CheckDuplicate: true,
},
})

if err != nil {
t.Fatal(err)
}
Expand Down Expand Up @@ -98,8 +99,12 @@ func TestContainerWithHostNetworkOptions(t *testing.T) {
gcr := GenericContainerRequest{
ContainerRequest: ContainerRequest{
Image: "nginx",
Privileged: true,
SkipReaper: true,
NetworkMode: "host",
ExposedPorts: []string{
"80/tcp",
},
},
Started: true,
}
Expand All @@ -111,12 +116,17 @@ func TestContainerWithHostNetworkOptions(t *testing.T) {

defer nginxC.Terminate(ctx)

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

_, err = http.Get("http://" + host + ":80")
_, err = http.Get(endpoint)
if err != nil {
t.Errorf("Expected OK response. Got '%d'.", err)
}
Expand Down
20 changes: 20 additions & 0 deletions generic.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,26 @@ type GenericContainerRequest struct {
ProviderType ProviderType // which provider to use, Docker if empty
}

// GenericNetworkRequest represents parameters to a generic network
type GenericNetworkRequest struct {
NetworkRequest // embedded request for provider
ProviderType ProviderType // which provider to use, Docker if empty
}

// GenericNetwork creates a generic network with parameters
func GenericNetwork(ctx context.Context, req GenericNetworkRequest) (Network, error) {
provider, err := req.ProviderType.GetProvider()
if err != nil {
return nil, err
}
network, err := provider.CreateNetwork(ctx, req.NetworkRequest)
if err != nil {
return nil, errors.Wrap(err, "failed to create network")
}

return network, nil
}

// GenericContainer creates a generic container with parameters
func GenericContainer(ctx context.Context, req GenericContainerRequest) (Container, error) {
provider, err := req.ProviderType.GetProvider()
Expand Down
94 changes: 85 additions & 9 deletions network_test.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,26 @@
package testcontainers

import "context"
import (
"context"
"fmt"
"github.com/testcontainers/testcontainers-go/wait"
"testing"
"time"
)

// Create a network using a provider. By default it is Docker.
func ExampleNetworkProvider_CreateNetwork() {
ctx := context.Background()
networkName := "new-network"
gcr := GenericContainerRequest{
net, _ := GenericNetwork(ctx, GenericNetworkRequest{
NetworkRequest: NetworkRequest{
Name: networkName,
CheckDuplicate: true,
},
})
defer net.Remove(ctx)

nginxC, _ := GenericContainer(ctx, GenericContainerRequest{
ContainerRequest: ContainerRequest{
Image: "nginx",
ExposedPorts: []string{
Expand All @@ -16,15 +30,77 @@ func ExampleNetworkProvider_CreateNetwork() {
networkName,
},
},
})
defer nginxC.Terminate(ctx)
nginxC.GetContainerID()
}

func Test_MultipleContainersInTheNewNetwork(t *testing.T) {
ctx := context.Background()

networkName := "test-network"

networkRequest := NetworkRequest{
Driver: "bridge",
Name: networkName,
Attachable: true,
}

env := make(map[string]string)
env["POSTGRES_PASSWORD"] = "Password1"
dbContainerRequest := ContainerRequest{
Image: "postgres:12.2",
ExposedPorts: []string{"5432/tcp"},
AutoRemove: true,
Env: env,
WaitingFor: wait.ForListeningPort("5432/tcp"),
Networks: []string{networkName},
}
provider, _ := gcr.ProviderType.GetProvider()
net, _ := provider.CreateNetwork(ctx, NetworkRequest{
Name: networkName,
CheckDuplicate: true,

net, err := GenericNetwork(ctx, GenericNetworkRequest{
NetworkRequest: networkRequest,
})

if err != nil {
t.Fatal("cannot create network")
}

defer net.Remove(ctx)

nginxC, _ := GenericContainer(ctx, gcr)
defer nginxC.Terminate(ctx)
nginxC.GetContainerID()
postgres, err := GenericContainer(ctx, GenericContainerRequest{
ContainerRequest: dbContainerRequest,
Started: true,
})
if err != nil {
t.Fatal(err)
}

defer postgres.Terminate(ctx)

env = make(map[string]string)
env["RABBITMQ_ERLANG_COOKIE"] = "f2a2d3d27c75"
env["RABBITMQ_DEFAULT_USER"] = "admin"
env["RABBITMQ_DEFAULT_PASS"] = "Password1"
hp := wait.ForListeningPort("5672/tcp")
hp.WithStartupTimeout(3 * time.Minute)
amqpRequest := ContainerRequest{
Image: "rabbitmq:management-alpine",
ExposedPorts: []string{"15672/tcp", "5672/tcp"},
Env: env,
AutoRemove: true,
WaitingFor: hp,
Networks: []string{networkName},
}
rabbitmq, err := GenericContainer(ctx, GenericContainerRequest{
ContainerRequest: amqpRequest,
Started: true,
})
if err != nil {
t.Fatal(err)
return
}

defer rabbitmq.Terminate(ctx)
fmt.Println(postgres.GetContainerID())
fmt.Println(rabbitmq.GetContainerID())
}
15 changes: 11 additions & 4 deletions reaper.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ const (
ReaperDefaultImage = "quay.io/testcontainers/ryuk:0.2.3"
)

var reaper *Reaper // We would like to create reaper only once

// ReaperProvider represents a provider for the reaper to run itself with
// The ContainerProvider interface should usually satisfy this as well, so it is pluggable
type ReaperProvider interface {
Expand All @@ -36,14 +38,19 @@ type Reaper struct {

// NewReaper creates a Reaper with a sessionID to identify containers and a provider to use
func NewReaper(ctx context.Context, sessionID string, provider ReaperProvider, reaperImageName string) (*Reaper, error) {
r := &Reaper{
// If reaper already exists re-use it
if reaper != nil {
return reaper, nil
}

// Otherwise create a new one
reaper = &Reaper{
Provider: provider,
SessionID: sessionID,
}

listeningPort := nat.Port("8080/tcp")

// TODO: reuse reaper if there already is one
req := ContainerRequest{
Image: reaperImage(reaperImageName),
ExposedPorts: []string{string(listeningPort)},
Expand All @@ -68,9 +75,9 @@ func NewReaper(ctx context.Context, sessionID string, provider ReaperProvider, r
if err != nil {
return nil, err
}
r.Endpoint = endpoint
reaper.Endpoint = endpoint

return r, nil
return reaper, nil
}

func reaperImage(reaperImageName string) string {
Expand Down

0 comments on commit a18968f

Please sign in to comment.