seaworthy.definitions

Wrappers over Docker resource types to aid in setup/teardown of and interaction with Docker resources.

class ContainerDefinition(name, image, wait_patterns=None, wait_timeout=None, create_kwargs=None, helper=None)[source]

This is the base class for container definitions. Instances (and instances of subclasses) are intended to be used both as test fixtures and as convenient objects for operating on containers being tested.

Todo

Document this properly.

A container object may be used as a context manager to ensure proper setup and teardown of the container around the code that uses it:

with ContainerDefinition('my_container', IMAGE, helper=ch) as c:
    assert c.status() == 'running'

(Note that this only works if the container has a helper set and does not have a container created.)

as_fixture(name=None)

A decorator to inject this container into a function as a test fixture.

base_kwargs()

Override this method to provide dynamically generated base kwargs for the resource.

clean()[source]

This method should “clean” the container so that it is in the same state as it was when it was started. It is up to the implementer of this method to decide how the container should be cleaned. See clean_container_fixtures() for how this can be used with pytest fixtures.

create(**kwargs)

Create an instance of this resource definition.

Only one instance may exist at any given time.

get_first_host_port()[source]

Get the first mapping of the first (lowest) container port that has a mapping. Useful when a container publishes only one port.

Note that unlike the Docker API, which sorts ports lexicographically (e.g. 90/tcp > 8000/tcp), we sort ports numerically so that the lowest port is always chosen.

get_host_port(container_port, proto='tcp', index=0)[source]
Parameters:
  • container_port – The container port.
  • proto – The protocol (‘tcp’ or ‘udp’).
  • index – The index of the mapping entry to return.
Returns:

A tuple of the interface IP and port on the host.

get_logs(stdout=True, stderr=True, timestamps=False, tail='all', since=None)[source]

Get container logs.

This method does not support streaming, use stream_logs() for that.

halt(stop_timeout=5)[source]

Stop the container and remove it. The opposite of run().

http_client(port=None)[source]

Construct an HTTP client for this container.

inner()
Returns:the underlying Docker model object
merge_kwargs(default_kwargs, kwargs)

Override this method to merge kwargs differently.

ports

The ports (exposed and published) of the container.

pytest_clean_fixtures(name, scope='function', dependencies=())

Creates a pytest fixture for a container that can be “cleaned”. See clean_container_fixtures().

Note

This method returns two fixture functions. It is important to keep references to the returned functions within the scope of the tests that use the fixtures.

Note

This method is only available if pytest is used.

Parameters:
  • name – The fixture name.
  • scope – The scope of the fixture.
  • dependencies – A sequence of names of other pytest fixtures that this fixture depends on. These fixtures will be requested from pytest and so will be setup, but nothing is done with the actual fixture values.
pytest_fixture(name, scope='function', dependencies=())

Create a pytest fixture for the resource. See resource_fixture().

Note

This method returns a fixture function. It is important to keep a reference to the returned function within the scope of the tests that use the fixture.

Note

This method is only available if pytest is used.

Parameters:
  • name – The fixture name.
  • scope – The scope of the fixture.
  • dependencies – A sequence of names of other pytest fixtures that this fixture depends on. These fixtures will be requested from pytest and so will be setup, but nothing is done with the actual fixture values.
remove(**kwargs)

Remove an instance of this resource definition.

run(fetch_image=True, **kwargs)[source]

Create the container and start it. Similar to docker run.

Parameters:
  • fetch_image – Whether to try pull the image if it’s not found. The behaviour here is similar to docker run and this parameter defaults to True.
  • **kwargs

    Keyword arguments passed to create().

set_helper(helper)

Todo

Document this.

setup(helper=None, **run_kwargs)[source]

Creates the container, starts it, and waits for it to completely start.

Parameters:
  • helper – The resource helper to use, if one was not provided when this container definition was created.
  • **run_kwargs

    Keyword arguments passed to run().

Returns:

This container definition instance. Useful for creating and setting up a container in a single step:

con = ContainerDefinition('conny', 'nginx').setup(helper=dh)

start()[source]

Start the container. The container must have been created.

status()[source]

Get the container’s current status from Docker.

If the container does not exist (before creation and after removal), the status is None.

stop(timeout=5)[source]

Stop the container. The container must have been created.

Parameters:timeout – Timeout in seconds to wait for the container to stop before sending a SIGKILL. Default: 5 (half the Docker default)
stream_logs(stdout=True, stderr=True, tail='all', timeout=10.0)[source]

Stream container output.

teardown()[source]

Stop and remove the container if it exists.

wait_for_logs_matching(matcher, timeout=10, encoding='utf-8', **logs_kwargs)[source]

Wait for logs matching the given matcher.

wait_for_start()[source]

Wait for the container to start.

By default this will wait for the log lines matching the patterns passed in the wait_patterns parameter of the constructor using an UnorderedMatcher. For more advanced checks for container startup, this method should be overridden.

class NetworkDefinition(name, create_kwargs=None, helper=None)[source]

This is the base class for network definitions.

Todo

Document this properly.

as_fixture(name=None)

A decorator to inject this container into a function as a test fixture.

base_kwargs()

Override this method to provide dynamically generated base kwargs for the resource.

create(**kwargs)

Create an instance of this resource definition.

Only one instance may exist at any given time.

inner()
Returns:the underlying Docker model object
merge_kwargs(default_kwargs, kwargs)

Override this method to merge kwargs differently.

pytest_fixture(name, scope='function', dependencies=())

Create a pytest fixture for the resource. See resource_fixture().

Note

This method returns a fixture function. It is important to keep a reference to the returned function within the scope of the tests that use the fixture.

Note

This method is only available if pytest is used.

Parameters:
  • name – The fixture name.
  • scope – The scope of the fixture.
  • dependencies – A sequence of names of other pytest fixtures that this fixture depends on. These fixtures will be requested from pytest and so will be setup, but nothing is done with the actual fixture values.
remove(**kwargs)

Remove an instance of this resource definition.

set_helper(helper)

Todo

Document this.

setup(helper=None, **create_kwargs)

Setup this resource so that is ready to be used in a test. If the resource has already been created, this call does nothing.

For most resources, this just involves creating the resource in Docker.

Parameters:
  • helper – The resource helper to use, if one was not provided when this resource definition was created.
  • **create_kwargs

    Keyword arguments passed to create().

Returns:

This definition instance. Useful for creating and setting up a resource in a single step:

volume = VolumeDefinition('volly').setup(helper=docker_helper)

teardown()

Teardown this resource so that it no longer exists in Docker. If the resource has already been removed, this call does nothing.

For most resources, this just involves removing the resource in Docker.

class VolumeDefinition(name, create_kwargs=None, helper=None)[source]

This is the base class for volume definitions.

The following is an example of how VolumeDefinition can be used to attach volumes to a container:

from seaworthy.definitions import ContainerDefinition

class DjangoContainer(ContainerDefinition):
    IMAGE = "seaworthy-demo:django"
    WAIT_PATTERNS = (r"Booting worker",)

    def __init__(self, name, socket_volume, static_volume, db_url):
        super().__init__(name, self.IMAGE, self.WAIT_PATTERNS)
        self.socket_volume = socket_volume
        self.static_volume = static_volume
        self.db_url = db_url

    def base_kwargs(self):
        return {
            "volumes": {
                self.socket_volume.inner(): "/var/run/gunicorn",
                self.static_volume.inner(): "/app/static:ro",
            },
            "environment": {"DATABASE_URL": self.db_url}
        }

# Create definition instances
socket_volume = VolumeDefinition("socket")
static_volume = VolumeDefinition("static")
django_container = DjangoContainer(
    "django", socket_volume, static_volume,
    postgresql_container.database_url())

# Create pytest fixtures
socket_volume_fixture = socket_volume.pytest_fixture("socket_volume")
static_volume_fixture = static_volume.pytest_fixture("static_volume")
django_fixture = django_container.pytest_fixture(
    "django_container",
    dependencies=[
        "socket_volume", "static_volume", "postgresql_container"])

This example is explained in the introductory blog post and demo repository.

Todo

Document this properly.

as_fixture(name=None)

A decorator to inject this container into a function as a test fixture.

base_kwargs()

Override this method to provide dynamically generated base kwargs for the resource.

create(**kwargs)

Create an instance of this resource definition.

Only one instance may exist at any given time.

inner()
Returns:the underlying Docker model object
merge_kwargs(default_kwargs, kwargs)

Override this method to merge kwargs differently.

pytest_fixture(name, scope='function', dependencies=())

Create a pytest fixture for the resource. See resource_fixture().

Note

This method returns a fixture function. It is important to keep a reference to the returned function within the scope of the tests that use the fixture.

Note

This method is only available if pytest is used.

Parameters:
  • name – The fixture name.
  • scope – The scope of the fixture.
  • dependencies – A sequence of names of other pytest fixtures that this fixture depends on. These fixtures will be requested from pytest and so will be setup, but nothing is done with the actual fixture values.
remove(**kwargs)

Remove an instance of this resource definition.

set_helper(helper)

Todo

Document this.

setup(helper=None, **create_kwargs)

Setup this resource so that is ready to be used in a test. If the resource has already been created, this call does nothing.

For most resources, this just involves creating the resource in Docker.

Parameters:
  • helper – The resource helper to use, if one was not provided when this resource definition was created.
  • **create_kwargs

    Keyword arguments passed to create().

Returns:

This definition instance. Useful for creating and setting up a resource in a single step:

volume = VolumeDefinition('volly').setup(helper=docker_helper)

teardown()

Teardown this resource so that it no longer exists in Docker. If the resource has already been removed, this call does nothing.

For most resources, this just involves removing the resource in Docker.

deep_merge(*dicts)[source]

Recursively merge all input dicts into a single dict.