Container images generally consist of distribution packages and some scripts that help start the container properly. For example, a container with a MariaDB database typically consists of a set of RPMs, such as mariadb-server, that provides the main functionality, and scripts that handle initialization, setup, etc. A simplified example of MariaDB Dockerfile may look like this:
FROM fedora:24
RUN true \
&& dnf install -y mariadb-server \
&& dnf clean all \
&& /usr/libexec/container-setup \
&& true
COPY run-mysqld /usr/bin/
COPY container-setup /usr/libexec/
VOLUME ["/var/lib/mysql/data"]
USER 27
CMD ["run-mysqld"]
If we want to test the basic functionality of the container, we do not have to test the RPM functionality. The benefit of using the distribution packaging is that we know testing has already been done during the RPM develpment process. Instead, we need to focus on testing of the added scripts instead and the API of the container. The goal is to determine if it works as described. For example, for the MariaDB database container, we do not run the MariaDB unit tests in the container. Instead we focus on whether the database is initialized, configured, and responds to commands properly.
It is good practice to keep the basic sanity tests for the image together with the image sources. For example test/run might be a script, that tests the image specified by the IMAGE_NAME environment variable, so users may specify an image which should be tested.
These examples of test scripts can be found in the container images for Software Collections:
A minimal script that verifies a container image by running it as a daemon and then running a script that checks the proper functionality, is shown below. It stores the IDs of the containers created during the test in a temporary directory. This makes it easy to clean up those containers after the test finishes.
#!/bin/bash
#
# General test of the image.
#
# IMAGE_NAME specifies the name of the candidate image used for testing.
# The image has to be available before this script is executed.
#
set -exo nounset
shopt -s nullglob
IMAGE_NAME=${IMAGE_NAME-default-image-name}
CIDFILE_DIR=$(mktemp --suffix=test_cidfiles -d)
# clears containers run during the test
function cleanup() {
for cidfile in $CIDFILE_DIR/* ; do
CONTAINER=$(cat $cidfile)
echo "Stopping and removing container $CONTAINER..."
docker stop $CONTAINER
exit_status=$(docker inspect -f '{{.State.ExitCode}}' $CONTAINER)
if [ "$exit_status" != "0" ]; then
echo "Dumping logs for $CONTAINER"
docker logs $CONTAINER
fi
docker rm $CONTAINER
rm $cidfile
echo "Done."
done
rmdir $CIDFILE_DIR
}
trap cleanup EXIT
# returns ID of specified named container
function get_cid() {
local id="$1" ; shift || return 1
echo $(cat "$CIDFILE_DIR/$id")
}
# returns IP of specified named container
function get_container_ip() {
local id="$1" ; shift
docker inspect --format='{{.NetworkSettings.IPAddress}}' $(get_cid "$id")
}
# runs command to test running container
function test_image() {
local name=$1 ; shift
echo " Testing Image"
docker run --rm $IMAGE_NAME get_status `get_container_ip $name`
echo " Success!"
}
# start a new container
function create_container() {
local name=$1 ; shift
cidfile="$CIDFILE_DIR/$name"
# create container with a cidfile in a directory for cleanup
docker run --cidfile $cidfile -d $IMAGE_NAME
echo "Created container $(cat $cidfile)"
}
# Tests.
create_container test1
test_image test1