docs/INTEGRATION_TESTS.md
To run all named integration tests:
make test-integration
To run all tests, including unit and integration tests:
go test -count 1 -race ./...
To run integration tests against a service the project uses testcontainers. The makes it very easy to create and cleanup container-based tests.
The testutil/container.go has a Container type that wraps this project to
easily create containers for testing in Telegraf. A typical test looks like
the following:
servicePort := "5432"
container := testutil.Container{
Image: "postgres:alpine",
ExposedPorts: []string{servicePort},
Env: map[string]string{
"POSTGRES_HOST_AUTH_METHOD": "trust",
},
WaitingFor: wait.ForAll(
wait.ForLog("database system is ready to accept connections"),
wait.ForListeningPort(servicePort),
),
}
require.NoError(t, container.Start(), "failed to start container")
defer func() {
require.NoError(t, container.Terminate(), "terminating container failed")
}()
User's should start the container and then defer termination of the container.
The test.Container type requires at least an image, ports to expose, and a
wait stanza. See the following to learn more:
Images are pulled from DockerHub by default. When looking for and selecting an image from DockerHub, please use the following priority order:
When the port is specified as a single value (e.g. 11211) then testcontainers
will generate a random port for the service to start on. This way multiple
tests can be run and prevent ports from conflicting.
The test container will expect an array of ports to expose for testing. For most tests only a single port is used, but a user can specify more than one to allow for testing if another port is open for example.
On each container's DockerHub page, the README will usually specify what ports are used by the container by default. For many containers this port can be changed or specified with an environment variable.
If no ports are specified, a user can view the image tag and view the various
image layers. Find an image layer with the EXPOSE keyword to determine what
ports are used by the container.
The wait stanza lays out what test containers will wait for to determine that the container has started and is ready for use by the test. It is best to provide not only a port, but also a log message. Ports can come up very early in the container, and the service may not be ready.
To find a good log message, it is suggested to launch the container manually and see what the final message is printed. Usually this is something to the effect of "ready for connections" or "setup complete". Also ensure that this message only shows up once, or the use of the
There are other optional parameters that user can make use of for additional configuration of the test containers:
BindMounts: used to mount local test data into the container. The order is
location in the container as the key and the local file as the value.Entrypoint: if a user wishes to override the entrypoint with a custom
commandEnv: to pass environmental variables to the container similar to Docker
CLI's --env optionName: if a container needs a hostname set or expects a certain name use
this option to set the containers hostnameNetworks: if the user creates a custom networkBy default the containers will use the bridge network where other containers cannot talk to each other.
If a custom network is required for running tests, for example if containers do need to communicate, then users can set that up with the following code:
networkName := "test-network"
net, err := testcontainers.GenericNetwork(ctx, testcontainers.GenericNetworkRequest{
NetworkRequest: testcontainers.NetworkRequest{
Name: networkName,
Attachable: true,
CheckDuplicate: true,
},
})
require.NoError(t, err)
defer func() {
require.NoError(t, net.Remove(ctx), "terminating network failed")
}()
Then specify the network name in the container startup:
zookeeper := testutil.Container{
Image: "wurstmeister/zookeeper",
ExposedPorts: []string{"2181:2181"},
Networks: []string{networkName},
WaitingFor: wait.ForLog("binding to port"),
Name: "telegraf-test-zookeeper",
}
When adding integrations tests please do the following: