|
testcontainers-cpp 0.2.0
Native C++20 Testcontainers over the Docker Engine API
|
A RAII handle to a running container, normally obtained from GenericImage::start(). More...
#include <testcontainers/Container.hpp>
Public Member Functions | |
| Container (const Container &)=delete | |
| Container & | operator= (const Container &)=delete |
| Container (Container &&other) noexcept | |
| Container & | operator= (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. | |
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.
|
delete |
|
inlinenoexcept |
|
inline |
Force-removes the container unless it was already explicitly removed or moved-from.
Never throws.
|
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.
|
inlinenoexcept |
The full container id.
|
inlinenoexcept |
True when this is a persistent (reusable) handle that will NOT remove the container on destruction.
|
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).
| 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).
| 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.
| 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.
| 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.
| 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.
| ContainerInspect testcontainers::Container::inspect | ( | ) | const |
A structured snapshot of the container (GET /containers/{id}/json).
| 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.
|
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.
| ContainerLogs testcontainers::Container::logs | ( | ) | const |
A snapshot of the container's stdout / stderr 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.
| 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.
| 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.
| 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.
| 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.
| 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.)
| 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.
| 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.
| 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.
| 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.
| 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.
| bool testcontainers::Container::is_running | ( | ) | const |
Whether the container is currently running (per a fresh inspect).
|
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.)
| 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.