dockertest

package module
v0.0.14 Latest Latest
Warning

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

Go to latest
Published: Oct 30, 2023 License: MIT Imports: 22 Imported by: 0

README

dockertest

GoDoc Go Report Card Build Status

DOCKERTEST

This project is an experimental library that wraps the docker client to ease testing services in docker containers.

I split it out from my docker-dns project where I found the need for functional testing a dns-container behaving well after build.

The rough concept is as follows:

  • create a ContainerBuilder (which takes basic parameters)
  • if necessay modify the docker-client data structures which are exposed by the builder
  • use the builder to create a Container
  • use Container to start

Additional to the creation and starting of containers there are convenicence methods like WaitForContainerToExit which waits for the container executing tests,

For debugging those tests it is useful to use method DumpContainerLogs to take a look inside the components under test.

Finally Cleanup() the whole setup, jenkins will love you for that.

Example

Here's one example simulating how to test an api with two containers.

More information here: examples/api/README.md

package main

import (
	"fmt"
	"os"
	"os/signal"
	"syscall"
	"time"

	"github.com/Oppodelldog/dockertest"
)

const waitingTimeout = time.Minute

// functional tests for name api.
// nolint:funlen
func main() {
	// the local test dir will help mounting the project into the containers
	projectDir, err := os.Getwd()
	panicOnErr(err)

	// start a new test
	test, err := dockertest.NewSession()
	panicOnErr(err)

	go cancelSessionOnSigTerm(test)

	// cleanup resources from a previous test
	test.CleanupRemains()

	// initialize testResult which is passed into deferred cleanup method
	var testResult = TestResult{ExitCode: -1}
	defer cleanup(test, &testResult)

	// let put test log output into a separate directory
	test.SetLogDir("examples/api/test-logs")

	// since it's a micro-service api test, we need networking facility
	net, err := test.CreateBasicNetwork("test-network").Create()
	panicOnErr(err)

	basicConfiguration := test.NewContainerBuilder().
		Image("golang:1.19.0").
		Connect(net).
		WorkingDir("/app/examples/api").
		Mount(projectDir, "/app")

	// create the API container, the system under test
	api, err := basicConfiguration.NewContainerBuilder().
		Name("api").
		Cmd("go run nameapi/main.go").
		Env("API_BASE_URL", "http://localhost:8080").
		HealthShellCmd("go run healthcheck/main.go").
		Build()
	panicOnErr(err)

	// create the testing container
	tests, err := basicConfiguration.NewContainerBuilder().
		Name("tests").
		Cmd("go test -v tests/api_test.go").
		Link(api, "api", net).
		Env("API_BASE_URL", "http://api:8080").
		Build()
	panicOnErr(err)

	// start api containers
	err = api.Start()
	panicOnErr(err)

	// wait until API is available
	err = <-test.NotifyContainerHealthy(api, waitingTimeout)
	panicOnErr(err)

	// now start the tests
	err = tests.Start()
	panicOnErr(err)

	// wait for tests to finish
	<-test.NotifyContainerExit(tests, waitingTimeout)

	// grab the exit code from the exited container
	testResult.ExitCode, err = tests.ExitCode()
	panicOnErr(err)

	// dump the test output to the log directory
	test.DumpContainerLogs(tests)
}

func cancelSessionOnSigTerm(session *dockertest.Session) {
	sigCh := make(chan os.Signal, 1)
	signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM)
	<-sigCh
	session.Cancel()
}

// it is always a good practise to clean up.
func cleanup(test *dockertest.Session, testResult *TestResult) {
	fmt.Println("CLEANUP-START")
	test.Cleanup()
	fmt.Println("CLEANUP-DONE")

	if r := recover(); r != nil {
		fmt.Printf("ERROR: %v\n", r)
	}

	os.Exit(testResult.ExitCode)
}

// TestResult helps to share the exit code through a defer to the cleanup function.
type TestResult struct {
	ExitCode int
}

func panicOnErr(err error) {
	if err != nil {
		fmt.Println(err)
		panic(err)
	}
}

Documentation

Overview

Package dockertest is intended to help in executing tests in containers.

This might be simple as executing unit tests in isolation on a docker host. You might also want to execute more complex setups like functionally testing a microservice with it's dependencies. This is where dockertest supports you.

Basically this package consists of Builders to create a Network or Containers. But it also helps in orchestrating the tests and finally in cleaning up.

To get started take a look in the main.go file in the examples folder, it's self explanatory.

Index

Constants

This section is empty.

Variables

View Source
var ErrClosedWithoutFinding = errors.New("log stream closed without finding")
View Source
var ErrContainerStartTimeout = errors.New("timeout - container is not healthy")

ErrContainerStartTimeout is returned from NotifyContainerHealthy when a container was detected to be not healthy due to timeout.

View Source
var ErrContainerStillRunning = errors.New("container is running, it has no exit code yet")

ErrContainerStillRunning is returned from a call to ExitCode() if the container is still running.

View Source
var ErrInspectingContainer = errors.New("error inspecting container")

ErrInspectingContainer is returned from a call to ExitCode() if the docker client returned an error on inspect.

View Source
var ErrReadingContainerLog = errors.New("error reading container log")
View Source
var ErrStateHealthNotSet = errors.New("inspectJSON.State.Health is nil")
View Source
var ErrStateNotSet = errors.New("inspectJSON.State is nil")

Functions

This section is empty.

Types

type Container

type Container struct {
	Name string
	// contains filtered or unexported fields
}

Container is a access wrapper for a docker container.

func (Container) Cancel added in v0.0.4

func (c Container) Cancel()

func (Container) ExitCode added in v0.0.3

func (c Container) ExitCode() (int, error)

ExitCode returns the exit code of the container. The container must be exited and exist, otherwise an error is returned.

func (Container) Start added in v0.0.3

func (c Container) Start() error

Start starts the container.

type ContainerBuilder

type ContainerBuilder struct {
	ContainerConfig  *container.Config
	HostConfig       *container.HostConfig
	NetworkingConfig *dockerNetwork.NetworkingConfig
	ContainerName    string
	// contains filtered or unexported fields
}

ContainerBuilder helps to create customized containers. Note that calling functions have not affect to running or already created container. only when calling the "Build" method all configuration is applied to a new container.

func (*ContainerBuilder) AutoRemove added in v0.0.3

func (b *ContainerBuilder) AutoRemove(v bool) *ContainerBuilder

AutoRemove tells the docker daemon to remove the container after it exits.

func (*ContainerBuilder) BindPort added in v0.0.12

func (b *ContainerBuilder) BindPort(containerPort, hostPort string) *ContainerBuilder

BindPort bind a Host port to a container port.

func (*ContainerBuilder) Build added in v0.0.3

func (b *ContainerBuilder) Build() (*Container, error)

Build creates a container from the current builders state.

func (ContainerBuilder) Cancel added in v0.0.4

func (c ContainerBuilder) Cancel()

func (*ContainerBuilder) Cmd added in v0.0.3

Cmd sets the command that is executed when the container starts.

func (*ContainerBuilder) CmdArgs added in v0.0.8

func (b *ContainerBuilder) CmdArgs(args ...string) *ContainerBuilder

CmdArgs sets the command that is executed when the container starts.

func (*ContainerBuilder) Connect added in v0.0.3

func (b *ContainerBuilder) Connect(n *Network) *ContainerBuilder

Connect connects the container to the given Network.

func (*ContainerBuilder) Dns added in v0.0.3

func (b *ContainerBuilder) Dns(dnsServerIP string) *ContainerBuilder

Dns adds a dns server to the container. nolint: golint, revive, stylecheck

func (*ContainerBuilder) Env added in v0.0.3

func (b *ContainerBuilder) Env(name string, value string) *ContainerBuilder

Env defines an environment variable that will be set in the container.

func (*ContainerBuilder) ExposePort added in v0.0.12

func (b *ContainerBuilder) ExposePort(port string) *ContainerBuilder

ExposePort exposes a containers port inside the docker network - for example "80/tcp".

func (*ContainerBuilder) HealthCmd added in v0.0.3

func (b *ContainerBuilder) HealthCmd(cmd string) *ContainerBuilder

HealthCmd sets a command that is executed directly.

func (*ContainerBuilder) HealthDisable added in v0.0.3

func (b *ContainerBuilder) HealthDisable() *ContainerBuilder

HealthDisable disabled the health check.

func (*ContainerBuilder) HealthInterval added in v0.0.3

func (b *ContainerBuilder) HealthInterval(d time.Duration) *ContainerBuilder

HealthInterval sets the time to wait between checks.

func (*ContainerBuilder) HealthRetries added in v0.0.3

func (b *ContainerBuilder) HealthRetries(r int) *ContainerBuilder

HealthRetries sets the number of consecutive failures needed to consider a container as unhealthy.

func (*ContainerBuilder) HealthShellCmd added in v0.0.3

func (b *ContainerBuilder) HealthShellCmd(cmd string) *ContainerBuilder

HealthShellCmd sets a command that is executed in the containers default shell to determine if the container is healthy.

func (*ContainerBuilder) HealthTimeout added in v0.0.3

func (b *ContainerBuilder) HealthTimeout(t time.Duration) *ContainerBuilder

HealthTimeout sets the timeout to wait before considering the check to have hung.

func (*ContainerBuilder) IPAddress added in v0.0.3

func (b *ContainerBuilder) IPAddress(ipAddress string, n *Network) *ContainerBuilder

IPAddress defines the IP address used by the container.

func (*ContainerBuilder) Image added in v0.0.3

func (b *ContainerBuilder) Image(image string) *ContainerBuilder

Image sets the docker image to start a container from.

func (b *ContainerBuilder) Link(container *Container, alias string, n *Network) *ContainerBuilder

Link links a foreign container.

func (*ContainerBuilder) Mount added in v0.0.2

func (b *ContainerBuilder) Mount(localPath string, containerPath string) *ContainerBuilder

Mount creates a volume binding to mount a local directory into the container.

func (*ContainerBuilder) Name added in v0.0.3

Name defines the container name.

func (*ContainerBuilder) NewContainerBuilder added in v0.0.3

func (b *ContainerBuilder) NewContainerBuilder() *ContainerBuilder

NewContainerBuilder returns a new *ContainerBuilder.

func (*ContainerBuilder) Port added in v0.0.7

func (b *ContainerBuilder) Port(containerPort, hostPort string) *ContainerBuilder

Port bind a Host port to a container port. Deprecated: use BindPort instead.

func (*ContainerBuilder) UseOriginalName added in v0.0.2

func (b *ContainerBuilder) UseOriginalName() *ContainerBuilder

UseOriginalName removes the unique session-identifier from the container name.

func (*ContainerBuilder) WorkingDir added in v0.0.3

func (b *ContainerBuilder) WorkingDir(wd string) *ContainerBuilder

WorkingDir defines the working directory for the container.

type Network added in v0.0.3

type Network struct {
	NetworkID   string
	NetworkName string
}

Network represents a docker network.

type NetworkBuilder added in v0.0.2

type NetworkBuilder struct {
	Name    string
	Options types.NetworkCreate
	// contains filtered or unexported fields
}

NetworkBuilder helps with the creation of a docker network.

func (NetworkBuilder) Cancel added in v0.0.4

func (c NetworkBuilder) Cancel()

func (NetworkBuilder) Create added in v0.0.2

func (n NetworkBuilder) Create() (*Network, error)

Create creates a new docker network.

type Session added in v0.0.3

type Session struct {
	ID string
	// contains filtered or unexported fields
}

Session is the main object when starting a docker driven container test.

func NewSession added in v0.0.3

func NewSession() (*Session, error)

NewSession creates a new Test and returns a Session instance to work with.

func (Session) Cancel added in v0.0.4

func (c Session) Cancel()

func (*Session) Cleanup added in v0.0.3

func (dt *Session) Cleanup()

Cleanup removes all resources (like containers/networks) used for this session.

func (*Session) CleanupRemains added in v0.0.6

func (dt *Session) CleanupRemains()

CleanupRemains removes all resources (like containers/networks) this kind of test - identified by the Session Label.

func (*Session) CreateBasicNetwork added in v0.0.3

func (dt *Session) CreateBasicNetwork(networkName string) NetworkBuilder

CreateBasicNetwork creates a bridged Network with the given name, subnet mask and ip range.

func (*Session) CreateSimpleNetwork added in v0.0.3

func (dt *Session) CreateSimpleNetwork(networkName, subNet, ipRange string) NetworkBuilder

CreateSimpleNetwork creates a bridged Network with the given name, subnet mask and ip range.

func (*Session) DumpContainerHealthCheckLogsToDir added in v0.0.8

func (dt *Session) DumpContainerHealthCheckLogsToDir(container ...*Container)

DumpContainerHealthCheckLogsToDir dumps the healthCheck logs of one or multiple containers to the log directory.

func (*Session) DumpContainerLogsToDir added in v0.0.7

func (dt *Session) DumpContainerLogsToDir(container ...*Container)

DumpContainerLogsToDir dumps the log of one or multiple containers to the log directory.

func (*Session) DumpInspect added in v0.0.3

func (dt *Session) DumpInspect(container ...*Container)

DumpInspect dumps an json file with the content of "docker inspect" into the log directory.

func (*Session) NewContainerBuilder added in v0.0.3

func (dt *Session) NewContainerBuilder() *ContainerBuilder

NewContainerBuilder returns a new *ContainerBuilder.

func (*Session) NotifyContainerExit added in v0.0.6

func (dt *Session) NotifyContainerExit(container *Container, timeout time.Duration) chan bool

NotifyContainerExit returns a channel that blocks until the container has exited. If the operation times out, it will try to kill the container.

func (*Session) NotifyContainerHealthy added in v0.0.6

func (dt *Session) NotifyContainerHealthy(container *Container, timeout time.Duration) chan error

NotifyContainerHealthy returns a channel that blocks until the given container reaches healthy state or timeout occurrs.

func (*Session) NotifyContainerLogContains added in v0.0.9

func (dt *Session) NotifyContainerLogContains(container *Container, timeout time.Duration, search string) chan error

NotifyContainerLogContains returns a channel that blocks until the given search string was found in the containers log output.

func (*Session) SetLabel added in v0.0.6

func (dt *Session) SetLabel(label string)

SetLabel sets the label all components of this session are assigned to. it must be set before any further creation calls to take effect.

func (*Session) SetLogDir added in v0.0.3

func (dt *Session) SetLogDir(logDir string)

SetLogDir sets the directory for log files creating during test execution. When calling it will directly ensure the path.

func (*Session) StartContainer added in v0.0.3

func (dt *Session) StartContainer(container ...*Container) error

StartContainer starts one or multiple given containers. If some containers return error while starting the last error will be returned.

func (*Session) WriteContainerLogs added in v0.0.7

func (dt *Session) WriteContainerLogs(w io.Writer, container ...*Container)

WriteContainerLogs writes the log of the given containers.

Directories

Path Synopsis
examples
api

Jump to

Keyboard shortcuts

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