testcontainers-cpp 0.2.0
Native C++20 Testcontainers over the Docker Engine API
Loading...
Searching...
No Matches
testcontainers::Container Class Reference

A RAII handle to a running container, normally obtained from GenericImage::start(). More...

#include <testcontainers/Container.hpp>

Public Member Functions

 Container (const Container &)=delete
Containeroperator= (const Container &)=delete
 Container (Container &&other) noexcept
Containeroperator= (Container &&other) noexcept
 ~Container ()
 Force-removes the container unless it was already explicitly removed or moved-from.
const std::string & id () const noexcept
 The full container id.
bool is_persistent () const noexcept
 True when this is a persistent (reusable) handle that will NOT remove the container on destruction.
bool has_tty () const noexcept
 True when the container was created with a pseudo-TTY (Tty=true), in which case its log stream is raw/unframed (no separate stderr channel).
std::string host () const
 The address a client in THIS process should connect to for the container's published ports: TESTCONTAINERS_HOST_OVERRIDE (or the host.override property) when set; the daemon hostname for a tcp:// / https:// daemon; otherwise "localhost" — unless the test process itself runs inside a Linux container, where the docker bridge gateway is returned instead (localhost there would be the container, not the host the ports are published on).
std::uint16_t get_host_port (ContainerPort port) const
 The host port Docker published for the given container port.
std::uint16_t get_host_port_ipv4 (ContainerPort port) const
 The host port Docker published on an IPv4 address (host_ip "0.0.0.0" or empty) for port.
std::uint16_t get_host_port_ipv6 (ContainerPort port) const
 The host port Docker published on an IPv6 address (host_ip contains ':') for port.
std::uint16_t first_mapped_port () const
 The mapped host port of the container's FIRST exposed port (the order passed to GenericImage::with_exposed_port); convenience for the common single-port container.
ContainerInspect inspect () const
 A structured snapshot of the container (GET /containers/{id}/json).
std::string inspect_raw () const
 The RAW inspect JSON body (GET /containers/{id}/json), so callers can read any field ContainerInspect does not model.
ContainerLogs logs () const
 A snapshot of the container's stdout / stderr logs.
void follow_logs (const LogConsumer &consumer, const LogOptions &opts={}) const
 Stream this container's logs to consumer until the container stops or the consumer returns false.
ExecResult exec (const std::vector< std::string > &cmd) const
 Run a command inside the running container, capturing its stdout / stderr and exit code.
ExecResult exec (const std::vector< std::string > &cmd, const ExecOptions &opts) const
 Run a command inside the running container with opts (env / working dir / user / privileged / tty / stdin / detach), capturing its output and exit code.
ExecResult exec (const std::vector< std::string > &cmd, const ExecOptions &opts, const LogConsumer &consumer) const
 Streaming variant: run cmd with opts, delivering output to consumer incrementally and returning an ExecResult with the exit code set (the stdout/stderr fields are left empty — the output went to consumer).
ExecStreamResult exec (const std::vector< std::string > &cmd, const ExecOptions &opts, const LogConsumer &consumer, std::chrono::steady_clock::time_point deadline) const
 Deadline-bounded streaming variant: like the consumer overload, but feeding stdin and the wait for each next output chunk are bounded by the absolute deadline — when it passes, delivery stops with FollowEnd::DeadlineExpired instead of blocking until the command finishes.
void resize_tty (TtySize size) const
 Resize this container's pseudo-TTY to size (rows x columns) — for containers created with a TTY; the foreground process gets SIGWINCH and sees the new dimensions.
void copy_to (const CopyToContainer &source) const
 Copy a host file, in-memory bytes, or a host directory tree into this already-running container (PUT /containers/{id}/archive).
std::string read_file (const std::string &container_path) const
 Read a single regular file out of the container and return its bytes.
void copy_file_from (const std::string &container_path, const std::filesystem::path &host_dest) const
 Copy a single regular file out of the container to host_dest (a host filesystem path; its parent directory is created if missing).
void stop (std::optional< int > timeout_secs=std::nullopt)
 Stop the container (an auto-removing handle still removes it on destruction; a persistent handle — with_reuse / after keep() — does not).
void start ()
 Start the container again after a stop() (POST /containers/{id}/start; already-running is accepted).
bool is_running () const
 Whether the container is currently running (per a fresh inspect).
void keep (bool keep=true) noexcept
 Keep the container alive past this handle: from here on neither destruction nor remove() removes it, and the stopping hooks do not fire on drop — the handle becomes persistent, exactly as if the container had been started with_reuse (is_persistent() reports true afterwards).
void remove ()
 Explicitly stop owning / force-remove the container now.

Static Public Member Functions

static Container adopt (DockerClient client, std::string id, AdoptOwnership ownership, bool tty=false)
 Adopt an already-running container that this library did NOT start (the manual escape hatch; GenericImage::start() is the normal way to obtain a handle).
static ContainerInspect inspect (const std::string &id)
 A structured snapshot of an arbitrary container by id (or name), without a Container handle — a read-only lookup that, unlike adopt, takes no ownership.

Detailed Description

A RAII handle to a running container, normally obtained from GenericImage::start().

Move-only: it owns a real external resource and force-removes the container on destruction (best-effort, exceptions swallowed). Copying is deleted so the removal happens exactly once.

A persistent handle (remove_on_drop == false) does NOT remove the container on destruction; it is used for reusable containers (with_reuse), which must survive across test runs, and is what keep() turns a normal handle into. The caller is then responsible for removing the container.

Constructor & Destructor Documentation

◆ Container() [1/2]

testcontainers::Container::Container ( const Container & )
delete

◆ Container() [2/2]

testcontainers::Container::Container ( Container && other)
inlinenoexcept

◆ ~Container()

testcontainers::Container::~Container ( )
inline

Force-removes the container unless it was already explicitly removed or moved-from.

Never throws.

Member Function Documentation

◆ adopt()

Container testcontainers::Container::adopt ( DockerClient client,
std::string id,
AdoptOwnership ownership,
bool tty = false )
inlinestatic

Adopt an already-running container that this library did NOT start (the manual escape hatch; GenericImage::start() is the normal way to obtain a handle).

ownership decides whether the handle removes the container on destruction — there is deliberately no default, since destroying a container we did not create must be an explicit choice. tty records whether the container was created with Tty=true, so logs() / follow_logs() read its raw/unframed log stream instead of demuxing. An adopted handle does not know the exposed-port declaration order — first_mapped_port() falls back to the lowest-numbered published port.

◆ operator=() [1/2]

Container & testcontainers::Container::operator= ( const Container & )
delete

◆ operator=() [2/2]

Container & testcontainers::Container::operator= ( Container && other)
inlinenoexcept

◆ id()

const std::string & testcontainers::Container::id ( ) const
inlinenoexcept

The full container id.

◆ is_persistent()

bool testcontainers::Container::is_persistent ( ) const
inlinenoexcept

True when this is a persistent (reusable) handle that will NOT remove the container on destruction.

◆ has_tty()

bool testcontainers::Container::has_tty ( ) const
inlinenoexcept

True when the container was created with a pseudo-TTY (Tty=true), in which case its log stream is raw/unframed (no separate stderr channel).

◆ host()

std::string testcontainers::Container::host ( ) const

The address a client in THIS process should connect to for the container's published ports: TESTCONTAINERS_HOST_OVERRIDE (or the host.override property) when set; the daemon hostname for a tcp:// / https:// daemon; otherwise "localhost" — unless the test process itself runs inside a Linux container, where the docker bridge gateway is returned instead (localhost there would be the container, not the host the ports are published on).

◆ get_host_port()

std::uint16_t testcontainers::Container::get_host_port ( ContainerPort port) const

The host port Docker published for the given container port.

Prefers the IPv4 binding, falling back to the first (e.g. IPv6-only) binding. Throws DockerError if the port is not exposed/published.

◆ get_host_port_ipv4()

std::uint16_t testcontainers::Container::get_host_port_ipv4 ( ContainerPort port) const

The host port Docker published on an IPv4 address (host_ip "0.0.0.0" or empty) for port.

Throws DockerError if there is no IPv4 binding.

◆ get_host_port_ipv6()

std::uint16_t testcontainers::Container::get_host_port_ipv6 ( ContainerPort port) const

The host port Docker published on an IPv6 address (host_ip contains ':') for port.

Throws DockerError if there is no IPv6 binding.

◆ first_mapped_port()

std::uint16_t testcontainers::Container::first_mapped_port ( ) const

The mapped host port of the container's FIRST exposed port (the order passed to GenericImage::with_exposed_port); convenience for the common single-port container.

IPv4 binding preferred. When the exposed-port order is unknown (e.g. an adopted / manually-constructed handle) this falls back to the lowest-numbered published container port. Throws DockerError if the container publishes no ports.

◆ inspect() [1/2]

ContainerInspect testcontainers::Container::inspect ( ) const

A structured snapshot of the container (GET /containers/{id}/json).

◆ inspect_raw()

std::string testcontainers::Container::inspect_raw ( ) const

The RAW inspect JSON body (GET /containers/{id}/json), so callers can read any field ContainerInspect does not model.

Throws DockerError if the container is gone.

◆ inspect() [2/2]

ContainerInspect testcontainers::Container::inspect ( const std::string & id)
static

A structured snapshot of an arbitrary container by id (or name), without a Container handle — a read-only lookup that, unlike adopt, takes no ownership.

Connects via DockerClient::from_environment(). Throws DockerError if no such container exists (NotFoundError) or the daemon cannot be reached.

◆ logs()

ContainerLogs testcontainers::Container::logs ( ) const

A snapshot of the container's stdout / stderr logs.

◆ follow_logs()

void testcontainers::Container::follow_logs ( const LogConsumer & consumer,
const LogOptions & opts = {} ) const

Stream this container's logs to consumer until the container stops or the consumer returns false.

Blocking — run on your own std::thread for background consumption. See DockerClient::follow_logs.

◆ exec() [1/4]

ExecResult testcontainers::Container::exec ( const std::vector< std::string > & cmd) const

Run a command inside the running container, capturing its stdout / stderr and exit code.

◆ exec() [2/4]

ExecResult testcontainers::Container::exec ( const std::vector< std::string > & cmd,
const ExecOptions & opts ) const

Run a command inside the running container with opts (env / working dir / user / privileged / tty / stdin / detach), capturing its output and exit code.

See DockerClient::exec for the tty/stdin/detach semantics.

◆ exec() [3/4]

ExecResult testcontainers::Container::exec ( const std::vector< std::string > & cmd,
const ExecOptions & opts,
const LogConsumer & consumer ) const

Streaming variant: run cmd with opts, delivering output to consumer incrementally and returning an ExecResult with the exit code set (the stdout/stderr fields are left empty — the output went to consumer).

See DockerClient::exec.

◆ exec() [4/4]

ExecStreamResult testcontainers::Container::exec ( const std::vector< std::string > & cmd,
const ExecOptions & opts,
const LogConsumer & consumer,
std::chrono::steady_clock::time_point deadline ) const

Deadline-bounded streaming variant: like the consumer overload, but feeding stdin and the wait for each next output chunk are bounded by the absolute deadline — when it passes, delivery stops with FollowEnd::DeadlineExpired instead of blocking until the command finishes.

The command is NOT killed by that: it keeps running inside the container, and the result's exit_code is present only when it had actually finished. See DockerClient::exec.

◆ resize_tty()

void testcontainers::Container::resize_tty ( TtySize size) const

Resize this container's pseudo-TTY to size (rows x columns) — for containers created with a TTY; the foreground process gets SIGWINCH and sees the new dimensions.

Resizing a TTY-less or stopped container throws DockerError. (An exec's own TTY is sized independently: ExecOptions::console_size / DockerClient::resize_exec.)

◆ copy_to()

void testcontainers::Container::copy_to ( const CopyToContainer & source) const

Copy a host file, in-memory bytes, or a host directory tree into this already-running container (PUT /containers/{id}/archive).

For a single-file source the target's parent directory must already exist; a directory source creates the target directory chain itself. Throws DockerError on failure.

◆ read_file()

std::string testcontainers::Container::read_file ( const std::string & container_path) const

Read a single regular file out of the container and return its bytes.

Fetches GET .../archive for container_path and extracts the one regular file in the archive. Throws DockerError if the path is not a single regular file (e.g. a directory). The bytes may be binary.

◆ copy_file_from()

void testcontainers::Container::copy_file_from ( const std::string & container_path,
const std::filesystem::path & host_dest ) const

Copy a single regular file out of the container to host_dest (a host filesystem path; its parent directory is created if missing).

Throws DockerError on failure. For directory trees use copy_from_container + extract_tar directly.

◆ stop()

void testcontainers::Container::stop ( std::optional< int > timeout_secs = std::nullopt)

Stop the container (an auto-removing handle still removes it on destruction; a persistent handle — with_reuse / after keep() — does not).

timeout_secs is the grace period before the daemon kills the process: unset uses the container's create-time StopTimeout (default 10s), 0 kills immediately, negative waits indefinitely. Stopping hooks fire once, before the stop.

◆ start()

void testcontainers::Container::start ( )

Start the container again after a stop() (POST /containers/{id}/start; already-running is accepted).

A plain daemon-side start: the request's wait strategies and lifecycle hooks do NOT re-run, and the stopping hooks — fired once by the earlier stop() — stay fired. The daemon re-binds ephemeral published ports on start: re-resolve them through get_host_port() (a module's Started* getters keep their original values). Throws DockerError on failure.

◆ is_running()

bool testcontainers::Container::is_running ( ) const

Whether the container is currently running (per a fresh inspect).

◆ keep()

void testcontainers::Container::keep ( bool keep = true)
inlinenoexcept

Keep the container alive past this handle: from here on neither destruction nor remove() removes it, and the stopping hooks do not fire on drop — the handle becomes persistent, exactly as if the container had been started with_reuse (is_persistent() reports true afterwards).

Removing the container then becomes the caller's responsibility (e.g. DockerClient::remove_container or docker rm -f).

keep(false) re-arms removal — handy for forwarding a "keep my containers" debug flag in one call instead of an if. It also works on a with_reuse handle, but then THIS handle removes the shared container on drop, defeating reuse for later runs — rarely what you want.

Ryuk still applies on Linux engines: a normally-started container carries the session label, so the reaper removes it shortly after the test process exits. keep() only protects it from THIS process's teardown — for a container that must outlive the process, disable the reaper (TESTCONTAINERS_RYUK_DISABLED) or use with_reuse, whose containers are never session-labeled. (No reaper runs against a Windows-containers engine — a kept container there stays until you remove it.)

◆ remove()

void testcontainers::Container::remove ( )

Explicitly stop owning / force-remove the container now.

Idempotent; after this the destructor does nothing. On a persistent handle (with_reuse / after keep()) this releases ownership without removing the container.