dockertest

package module
v0.3.11 Latest Latest
Warning

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

Go to latest
Published: Sep 30, 2020 License: MIT Imports: 17 Imported by: 2

README

Docker Test

Build Status codecov Go Report Card GoDoc

This project provides a small set of wrappers around docker. It is intended to be used to ease testing. Documentation is available via godoc: https://godoc.org/github.com/opalmer/dockertest

Examples

Create a container and retrieve an exposed port.

import (
	"context"
	"log"
	"github.com/opalmer/dockertest"
)

func main() {
	client, err := dockertest.NewClient()
	if err != nil {
		log.Fatal(err)
	}

	// Construct information about the container to start.
	input := dockertest.NewClientInput("nginx:mainline-alpine")
	input.Ports.Add(&dockertest.Port{
		Private:  80,
		Public:   dockertest.RandomPort,
		Protocol: dockertest.ProtocolTCP,
	})

	// Start the container
	container, err := client.RunContainer(context.Background(), input)
	if err != nil {
		log.Fatal(err)
	}

	// Extract information about the started container.
	port, err := container.Port(80)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println(port.Public, port.Address)

	if err := client.RemoveContainer(context.Background(), container.ID()); err != nil {
		log.Fatal(err)
	}
}

Create a container using the Service struct.

import (
	"context"
	"log"
	"github.com/opalmer/dockertest"
)

func main() {
	client, err := dockertest.NewClient()
	if err != nil {
		log.Fatal(err)
	}

	// Construct information about the container to start.
	input := dockertest.NewClientInput("nginx:mainline-alpine")
	input.Ports.Add(&dockertest.Port{
		Private:  80,
		Public:   dockertest.RandomPort,
		Protocol: dockertest.ProtocolTCP,
	})

	// Construct the service and tell it how to handle waiting
	// for the container to start.
	service := client.Service(input)
	service.Ping = func(input *dockertest.PingInput) error {
		port, err := input.Container.Port(80)
		if err != nil {
			return err // Will cause Run() to call Terminate()
		}

		for {
			_, err := net.Dial(string(port.Protocol), fmt.Sprintf("%s:%d", port.Address, port.Public))
			if err != nil {
				time.Sleep(time.Millisecond * 100)
				continue
			}
			break
		}

		return nil
	}

	// Starts the container, runs Ping() and waits for it to return. If Ping()
	// fails the container will be terminated and Run() will return an error.
	if err := service.Run(); err != nil {
		log.Fatal(err)
	}

	// Container has started, get information information
	// about the exposed port.
	port, err := service.Container.Port(80)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(port.Public, port.Address)

	if err := service.Terminate(); err != nil {
		log.Fatal(err)
	}
}

Documentation

Index

Examples

Constants

View Source
const (
	// RandomPort may be passed to a function to indicate
	// that a random port should be chosen.
	RandomPort uint16 = 0

	// ProtocolTCP represents a tcp Protocol.
	ProtocolTCP Protocol = "tcp"

	// ProtocolUDP represents a udp Protocol.
	ProtocolUDP Protocol = "udp"
)

Variables

View Source
var (
	// ErrPortNotFound is returned by ContainerInfo.Port if we're unable
	// to find a matching port on the c.
	ErrPortNotFound = errors.New("the requested port could not be found")

	// ErrContainerNotRunning is returned by Started() if the Container
	// was never started.
	ErrContainerNotRunning = errors.New("container not running")

	// ErrContainerStillRunning is returned by Finished() if the Container
	// is still running.
	ErrContainerStillRunning = errors.New("container still running")
)
View Source
var (
	// ErrInputNotProvided is returned by Service.Run if the Input field
	// is not provided.
	ErrInputNotProvided = errors.New("input field not provided")

	// ErrContainerNotStarted is returned by Terminate() if the container
	// was never started.
	ErrContainerNotStarted = errors.New("container not started")
)
View Source
var (
	// ErrContainerNotFound is returned by GetContainer if we were
	// unable to find the requested c.
	ErrContainerNotFound = errors.New("failed to locate the Container")
)

Functions

This section is empty.

Types

type ClientInput

type ClientInput struct {
	Image       string
	Ports       *Ports
	Labels      map[string]string
	Environment []string

	// Fields provided for the purposes of filtering containers.
	Since     string
	Before    string
	Status    string
	All       bool
	OlderThan time.Duration
}

ClientInput is used to provide inputs to the RunContainer function.

func NewClientInput

func NewClientInput(image string) *ClientInput

NewClientInput produces a *ClientInput struct.

func (*ClientInput) AddEnvironmentVar added in v0.3.6

func (i *ClientInput) AddEnvironmentVar(key string, value string)

AddEnvironmentVar adds an environment variable.

func (*ClientInput) ContainerConfig

func (i *ClientInput) ContainerConfig() *container.Config

ContainerConfig will return a *c.Config struct which may be passed to the ContainerCreate() API call.

func (*ClientInput) FilterArgs

func (i *ClientInput) FilterArgs() filters.Args

FilterArgs converts *ClientInput into a filters.Args struct which may be used with the docker client directly.

func (*ClientInput) RemoveLabel

func (i *ClientInput) RemoveLabel(key string)

RemoveLabel will remove the specified label.

func (*ClientInput) SetLabel

func (i *ClientInput) SetLabel(key string, value string)

SetLabel will add set the provided label key to the provided value.

type ContainerInfo

type ContainerInfo struct {
	JSON     types.ContainerJSON
	Data     types.Container
	State    *types.ContainerState
	Warnings []string
	// contains filtered or unexported fields
}

ContainerInfo provides a wrapper around information.

func (*ContainerInfo) Elapsed added in v0.2.0

func (c *ContainerInfo) Elapsed() (time.Duration, error)

Elapsed returns how long the Container has been running or had run if the Container has stopped.

func (*ContainerInfo) Finished added in v0.2.0

func (c *ContainerInfo) Finished() (time.Time, error)

Finished returns the time the Container finished running.

func (*ContainerInfo) GetLabel

func (c *ContainerInfo) GetLabel(name string) (string, bool)

GetLabel will return the value of the given label or "" if it does not exist. The boolean indicates if the label exists at all.

func (*ContainerInfo) HasLabel

func (c *ContainerInfo) HasLabel(name string, value string) bool

HasLabel returns true if the provided label exists and is equal to the provided value.

func (*ContainerInfo) ID added in v0.2.0

func (c *ContainerInfo) ID() string

ID is a shortcut function to return the Container's id.

func (*ContainerInfo) Port

func (c *ContainerInfo) Port(internal int) (*Port, error)

Port will return types.Port for the requested internal port. Note, attempts will be made to correct the address before returning. If $DOCKER_URL is not set however 127.0.0.1 will be returned if a specific IP was not provided by Docker.

func (*ContainerInfo) Refresh added in v0.2.0

func (c *ContainerInfo) Refresh() error

Refresh will refresh the data present on this struct.

func (*ContainerInfo) Started added in v0.2.0

func (c *ContainerInfo) Started() (time.Time, error)

Started returns the time the Container was started at.

func (*ContainerInfo) String

func (c *ContainerInfo) String() string

type DockerClient

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

DockerClient provides a wrapper for the standard dc client.

func NewClient

func NewClient() (*DockerClient, error)

NewClient produces a new *DockerClient that can be used to interact with Docker.

Example
client, err := dockertest.NewClient()
if err != nil {
	log.Fatal(err)
}

// Construct information about the container to start.
input := dockertest.NewClientInput("nginx:mainline-alpine")
input.Ports.Add(&dockertest.Port{
	Private:  80,
	Public:   dockertest.RandomPort,
	Protocol: dockertest.ProtocolTCP,
})

// Start the container
container, err := client.RunContainer(context.Background(), input)
if err != nil {
	log.Fatal(err)
}

// Extract information about the started container.
port, err := container.Port(80)
if err != nil {
	log.Fatal(err)
}

fmt.Println(port.Public, port.Address)

if err := client.RemoveContainer(context.Background(), container.ID()); err != nil {
	log.Fatal(err)
}
Output:

func (*DockerClient) ContainerInfo

func (d *DockerClient) ContainerInfo(ctx context.Context, id string) (*ContainerInfo, error)

ContainerInfo retrieves a single c by id and returns a *ContainerInfo struct.

func (*DockerClient) ListContainers

func (d *DockerClient) ListContainers(ctx context.Context, input *ClientInput) ([]*ContainerInfo, error)

ListContainers will return a list of *ContainerInfo structs based on the provided input.

func (*DockerClient) RemoveContainer

func (d *DockerClient) RemoveContainer(ctx context.Context, id string) error

RemoveContainer will delete the requested Container, force terminating it if necessary.

func (*DockerClient) RunContainer

func (d *DockerClient) RunContainer(ctx context.Context, input *ClientInput) (*ContainerInfo, error)

RunContainer will run a new c and return the results. By default all ports that are exposed by the c will be published to the host randomly. The published ports will be accessible using functions on the struct:

client, err := NewClient()
c := client.RunContainer("testimage", "testing", nil)
port, err := c.Port(80)
port.External

func (*DockerClient) Service added in v0.3.0

func (d *DockerClient) Service(input *ClientInput) *Service

Service will return a *Service struct that may be used to spin up a specific service. See the documentation present on the Service struct for more information.

Example
client, err := dockertest.NewClient()
if err != nil {
	log.Fatal(err)
}

// Construct information about the container to start.
input := dockertest.NewClientInput("nginx:mainline-alpine")
input.Ports.Add(&dockertest.Port{
	Private:  80,
	Public:   dockertest.RandomPort,
	Protocol: dockertest.ProtocolTCP,
})

// Construct the service and tell it how to handle waiting
// for the container to start.
service := client.Service(input)
service.Ping = func(input *dockertest.PingInput) error {
	port, err := input.Container.Port(80)
	if err != nil {
		return err // Will cause Run() to call Terminate()
	}

	for {
		_, err := net.Dial(string(port.Protocol), fmt.Sprintf("%s:%d", port.Address, port.Public))
		if err != nil {
			time.Sleep(time.Millisecond * 100)
			continue
		}
		break
	}

	return nil
}

// Starts the container, runs Ping() and waits for it to return. If Ping()
// fails the container will be terminated and Run() will return an error.
if err := service.Run(); err != nil {
	log.Fatal(err)
}

// Container has started, get information information
// about the exposed port.
port, err := service.Container.Port(80)
if err != nil {
	log.Fatal(err)
}
fmt.Println(port.Public, port.Address)

if err := service.Terminate(); err != nil {
	log.Fatal(err)
}
Output:

type Ping added in v0.3.0

type Ping func(*PingInput) error

Ping is a function that's used to ping a service before returning from Service.Run. Any errors produced by ping will cause the associated Container to be removed.

type PingInput added in v0.3.0

type PingInput struct {
	Service   *Service
	Container *ContainerInfo
}

PingInput is used to provide inputs to a Ping function.

type Port added in v0.3.0

type Port struct {
	// Private is the port exposed on the inside of the container
	// that you wish to map.
	Private uint16

	// Public is the publicly facing port that you wish to expose
	// the Private port on. Note, this may be `RandomPort` if you
	// wish to expose a random port instead of a specific port.
	Public uint16 `json:"port"`

	// Address is the IP address to expose the port mapping
	// on. By default, 0.0.0.0 will be used.
	Address string `json:"address"`

	// Protocol is the network protocol to expose.
	Protocol Protocol `json:"protocol"`
}

Port represents a port spec that may be used by the *Ports struct to expose a port on a container.

func (*Port) Binding added in v0.3.0

func (s *Port) Binding() nat.PortBinding

Binding converts the struct in a a nat.PortBinding. If no address has been given 0.0.0.0 will be used for the host ip.

func (*Port) Port added in v0.3.0

func (s *Port) Port() (nat.Port, error)

Port converts the struct into a nat.Port.

type Ports

type Ports struct {
	// Specs is a map of internal to external ports. The external
	// port may be the same as the internal port or it may be the
	// constant `RandomPort` if you wish for Docker to chose a port
	// for you.
	Specs []*Port
}

Ports is when to convey port exposures to RunContainer().

func NewPorts

func NewPorts() *Ports

NewPorts will produces a new *Ports struct that's ready to be modified.

func (*Ports) Add added in v0.3.0

func (p *Ports) Add(port *Port)

Add is a shortcut function to add a new port spec.

func (*Ports) Bindings added in v0.3.0

func (p *Ports) Bindings() (nat.PortMap, error)

Bindings will take the port specs and return port bindings that can be used in by the container.HostConfig.PortBindings field.

type Protocol added in v0.3.0

type Protocol string

Protocol is a string representing a protocol such as TCP or UDP.

type Service added in v0.3.0

type Service struct {
	// Name is an optional name that may be used for tracking a service. This
	// field is not used by dockertest.
	Name string

	// Ping is a function that may be used to wait for the service
	// to come up before returning. If this function is specified
	// and it return an error Terminate() will be automatically
	// called. This function is called by Run() before returning.
	Ping Ping

	// Input is used to control the inputs to Run()
	Input *ClientInput

	// Client is the docker client.
	Client *DockerClient

	// Container will container information about the running container
	// once Run() has finished.
	Container *ContainerInfo
}

Service is a struct used to run and manage a Container for a specific service.

func (*Service) Run added in v0.3.0

func (s *Service) Run() error

Run will run the Container.

func (*Service) Terminate added in v0.3.0

func (s *Service) Terminate() error

Terminate terminates the Container and returns.

Jump to

Keyboard shortcuts

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