testcontainers

package module
v0.0.4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 7, 2019 License: MIT Imports: 19 Imported by: 592

README

Build Status

When I was working on a Zipkin PR I discovered a nice Java library called testcontainers.

It provides an easy and clean API over the go docker sdk to run, terminate and connect to containers in your tests.

I found myself comfortable programmatically writing the containers I need to run an integration/smoke tests. So I started porting this library in Go.

This is the API I have defined:

package main

import (
	"context"
	"fmt"
	"net/http"
	"testing"

	testcontainers "github.com/testcontainers/testcontainers-go"
)

func TestNginxLatestReturn(t *testing.T) {
	ctx := context.Background()
	req := testcontainers.ContainerRequest{
		Image:        "nginx",
		ExposedPorts: []string{"80/tcp"},
	}
	nginxC, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{
		ContainerRequest: req,
		Started:          true,
	})
	if err != nil {
		t.Error(err)
	}
	defer nginxC.Terminate(ctx)
	ip, err := nginxC.Host(ctx)
	if err != nil {
		t.Error(err)
	}
	port, err := nginxC.MappedPort(ctx, "80")
	if err != nil {
		t.Error(err)
	}
	resp, err := http.Get(fmt.Sprintf("http://%s:%s", ip, port.Port()))
	if resp.StatusCode != http.StatusOK {
		t.Errorf("Expected status code %d. Got %d.", http.StatusOK, resp.StatusCode)
	}
}

This is a simple example, you can create one container in my case using the nginx image. You can get its IP ip, err := nginxC.GetContainerIpAddress(ctx) and you can use it to make a GET: resp, err := http.Get(fmt.Sprintf("http://%s", ip))

To clean your environment you can defer the container termination defer nginxC.Terminate(ctx, t). t is *testing.T and it is used to notify is the defer failed marking the test as failed.

You can build more complex flow using envvar to configure the containers. Let's suppose you are testing an application that requites redis:

func TestRedisPing(t *testing.T) {
	ctx := context.Background()
	req := testcontainers.ContainerRequest{
		Image:        "redis",
		ExposedPorts: []string{"6379/tcp"},
	}
	redisC, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{
		ContainerRequest: req,
		Started:          true,
	})
	if err != nil {
		t.Error(err)
	}
	defer redisC.Terminate(ctx)
	ip, err := redisC.Host(ctx)
	if err != nil {
		t.Error(err)
	}
	redisPort, err := redisC.MappedPort(ctx, "6479/tcp")
	if err != nil {
		t.Error(err)
	}

	appReq := testcontainers.ContainerRequest{
		ExposedPorts: []string{"8081/tcp"},
		Env: map[string]string{
			"REDIS_HOST": fmt.Sprintf("http://%s:%s", ip, redisPort.Port()),
		},
	}
	appC, err := testcontainers.RunContainer(ctx, "your/app", testcontainers.GenericContainerRequest{
		ContainerRequest: appReq,
		Started:          true,
	})
	if err != nil {
		t.Error(err)
	}
	defer appC.Terminate(ctx)

	// your assertions
}

Documentation

Index

Constants

View Source
const (
	TestcontainerLabel          = "org.testcontainers.golang"
	TestcontainerLabelSessionID = TestcontainerLabel + ".sessionId"
	ReaperDefaultImage          = "quay.io/testcontainers/ryuk:0.2.2"
)

TestcontainerLabel is used as a base for docker labels

Variables

This section is empty.

Functions

This section is empty.

Types

type Container

type Container interface {
	GetContainerID() string                                         // get the container id from the provider
	Endpoint(context.Context, string) (string, error)               // get proto://ip:port string for the first exposed port
	PortEndpoint(context.Context, nat.Port, string) (string, error) // get proto://ip:port string for the given exposed port
	Host(context.Context) (string, error)                           // get host where the container port is exposed
	MappedPort(context.Context, nat.Port) (nat.Port, error)         // get externally mapped port for a container port
	Ports(context.Context) (nat.PortMap, error)                     // get all exposed ports
	SessionID() string                                              // get session id
	Start(context.Context) error                                    // start the container
	Terminate(context.Context) error                                // terminate the container
	Logs(context.Context) (io.ReadCloser, error)                    // Get logs of the container
}

Container allows getting info about and controlling a single container instance

func GenericContainer

func GenericContainer(ctx context.Context, req GenericContainerRequest) (Container, error)

GenericContainer creates a generic container with parameters

type ContainerProvider

type ContainerProvider interface {
	CreateContainer(context.Context, ContainerRequest) (Container, error) // create a container without starting it
	RunContainer(context.Context, ContainerRequest) (Container, error)    // create a container and start it
}

ContainerProvider allows the creation of containers on an arbitrary system

type ContainerRequest

type ContainerRequest struct {
	Image        string
	Env          map[string]string
	ExposedPorts []string // allow specifying protocol info
	Cmd          string
	Labels       map[string]string
	BindMounts   map[string]string
	RegistryCred string
	WaitingFor   wait.Strategy
	// contains filtered or unexported fields
}

ContainerRequest represents the parameters used to get a running container

type DeprecatedContainer

type DeprecatedContainer interface {
	GetHostEndpoint(ctx context.Context, port string) (string, string, error)
	GetIPAddress(ctx context.Context) (string, error)
	LivenessCheckPorts(ctx context.Context) (nat.PortSet, error)
	Terminate(ctx context.Context) error
}

DeprecatedContainer shows methods that were supported before, but are now deprecated Deprecated: Use Container

func RunContainer

func RunContainer(ctx context.Context, containerImage string, input RequestContainer) (DeprecatedContainer, error)

RunContainer takes a RequestContainer as input and it runs a container via the docker sdk Deprecated: Use GenericContainer()

type DockerContainer

type DockerContainer struct {
	// Container ID from Docker
	ID         string
	WaitingFor wait.Strategy
	// contains filtered or unexported fields
}

DockerContainer represents a container started using Docker

func (*DockerContainer) Endpoint

func (c *DockerContainer) Endpoint(ctx context.Context, proto string) (string, error)

Endpoint gets proto://host:port string for the first exposed port Will returns just host:port if proto is ""

func (*DockerContainer) GetContainerID

func (c *DockerContainer) GetContainerID() string

func (*DockerContainer) GetHostEndpoint

func (c *DockerContainer) GetHostEndpoint(ctx context.Context, port string) (string, string, error)

GetHostEndpoint is deprecated and kept for backwards compat Deprecated: Use Endpoint()

func (*DockerContainer) GetIPAddress

func (c *DockerContainer) GetIPAddress(ctx context.Context) (string, error)

GetIPAddress is deprecated and kept for backwards compat Deprecated: Use IPAddress()

func (*DockerContainer) Host

func (c *DockerContainer) Host(ctx context.Context) (string, error)

Host gets host (ip or name) of the docker daemon where the container port is exposed Warning: this is based on your Docker host setting. Will fail if using an SSH tunnel You can use the "TC_HOST" env variable to set this yourself

func (*DockerContainer) LivenessCheckPorts

func (c *DockerContainer) LivenessCheckPorts(ctx context.Context) (nat.PortSet, error)

LivenessCheckPorts is deprecated and kept for backwards compat Deprecated: Use Ports()

func (*DockerContainer) Logs

Logs will fetch both STDOUT and STDERR from the current container. Returns a ReadCloser and leaves it up to the caller to extract what it wants.

func (*DockerContainer) MappedPort

func (c *DockerContainer) MappedPort(ctx context.Context, port nat.Port) (nat.Port, error)

MappedPort gets externally mapped port for a container port

func (*DockerContainer) PortEndpoint

func (c *DockerContainer) PortEndpoint(ctx context.Context, port nat.Port, proto string) (string, error)

PortEndpoint gets proto://host:port string for the given exposed port Will returns just host:port if proto is ""

func (*DockerContainer) Ports

func (c *DockerContainer) Ports(ctx context.Context) (nat.PortMap, error)

Ports gets the exposed ports for the container.

func (*DockerContainer) SessionID

func (c *DockerContainer) SessionID() string

SessionID gets the current session id

func (*DockerContainer) Start

func (c *DockerContainer) Start(ctx context.Context) error

Start will start an already created container

func (*DockerContainer) Terminate

func (c *DockerContainer) Terminate(_ context.Context) error

Terminate is used to kill the container. It is usally triggered by as defer function.

type DockerProvider

type DockerProvider struct {
	// contains filtered or unexported fields
}

DockerProvider implements the ContainerProvider interface

func NewDockerProvider

func NewDockerProvider() (*DockerProvider, error)

NewDockerProvider creates a Docker provider with the EnvClient

func (*DockerProvider) CreateContainer

func (p *DockerProvider) CreateContainer(ctx context.Context, req ContainerRequest) (Container, error)

CreateContainer fulfills a request for a container without starting it

func (*DockerProvider) RunContainer

func (p *DockerProvider) RunContainer(ctx context.Context, req ContainerRequest) (Container, error)

RunContainer takes a RequestContainer as input and it runs a container via the docker sdk

type GenericContainerRequest

type GenericContainerRequest struct {
	ContainerRequest              // embedded request for provider
	Started          bool         // whether to auto-start the container
	ProviderType     ProviderType // which provider to use, Docker if empty
}

GenericContainerRequest represents parameters to a generic container

type ProviderType

type ProviderType int

ProviderType is an enum for the possible providers

const (
	ProviderDocker ProviderType = iota // Docker is default = 0
)

possible provider types

func (ProviderType) GetProvider

func (t ProviderType) GetProvider() (ContainerProvider, error)

GetProvider provides the provider implementation for a certain type

type Reaper

type Reaper struct {
	Provider  ReaperProvider
	SessionID string
	Endpoint  string
}

Reaper is used to start a sidecar container that cleans up resources

func NewReaper

func NewReaper(ctx context.Context, sessionID string, provider ReaperProvider) (*Reaper, error)

NewReaper creates a Reaper with a sessionID to identify containers and a provider to use

func (*Reaper) Connect

func (r *Reaper) Connect() (chan bool, error)

Connect runs a goroutine which can be terminated by sending true into the returned channel

func (*Reaper) Labels

func (r *Reaper) Labels() map[string]string

Labels returns the container labels to use so that this Reaper cleans them up

type ReaperProvider

type ReaperProvider interface {
	RunContainer(ctx context.Context, req ContainerRequest) (Container, error)
}

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 RequestContainer

type RequestContainer struct {
	Env          map[string]string
	ExportedPort []string
	Cmd          string
	RegistryCred string
	WaitingFor   wait.Strategy
}

RequestContainer supplies input parameters for a container Deprecated: Use ContainerRequest with provider pattern

Directories

Path Synopsis
examples
bigtable Module
cockroachdb Module
consul Module
datastore Module
firestore Module
mongodb Module
mysql Module
nats Module
nginx Module
postgres Module
pubsub Module
pulsar Module
redis Module
spanner Module
toxiproxy Module
modulegen module
modules
artemis Module
cassandra Module
chroma Module
clickhouse Module
cockroachdb Module
compose Module
consul Module
couchbase Module
elasticsearch Module
gcloud Module
inbucket Module
influxdb Module
k3s Module
k6 Module
kafka Module
localstack Module
mariadb Module
milvus Module
minio Module
mockserver Module
mongodb Module
mssql Module
mysql Module
nats Module
neo4j Module
ollama Module
openfga Module
openldap Module
opensearch Module
postgres Module
pulsar Module
qdrant Module
rabbitmq Module
redis Module
redpanda Module
registry Module
surrealdb Module
vault Module
weaviate Module

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL