Documentation
¶
Overview ¶
Package foundationdb provides a testcontainers module for FoundationDB.
This module creates a single FoundationDB container (no socat proxy) and provides two coordinator bootstrap addresses:
- External: via Docker port mapping (usually localhost:mappedPort).
- Internal (cross-container): via Docker bridge IP (containerIP:4500). Used by sidecar containers on the same Docker network.
Both modes require routing to advertised bridge-IP transaction endpoints; publishing the coordinator alone is insufficient on Docker Desktop or remote daemons.
The container is auto-initialized by default (configured for single-node operation with tenant support). Use WithoutInit to skip.
Basic usage:
container, err := foundationdb.Run(ctx, "") clusterFile, _ := container.ClusterFile(ctx) db, _ := fdb.OpenDatabase(writeToFile(clusterFile))
Multi-container usage (e.g., binding tester):
nw, _ := foundationdb.CreateNetwork(ctx)
fdb, _ := foundationdb.Run(ctx, "", foundationdb.WithNetwork(nw))
// Attach another container to the same network:
otherReq.Networks = []string{fdb.NetworkName()}
// Use InternalClusterFile() for the other container's cluster file.
Index ¶
- func CreateNetwork(ctx context.Context) (*testcontainers.DockerNetwork, error)
- func DatabaseAvailable(statusMinimal string) bool
- func SkipWithoutDocker(err error) bool
- func Terminate(ctx context.Context, c Terminator) error
- func TerminateT(t interface{ ... }, ctx context.Context, c Terminator)
- type Cluster
- type Container
- func (c *Container) APIVersion() int
- func (c *Container) ClusterFile(_ context.Context) (string, error)
- func (c *Container) ClusterFilePath(_ context.Context) (string, error)
- func (c *Container) ConnectionString(ctx context.Context) (string, error)
- func (c *Container) Database() string
- func (c *Container) FDBCLIExec(ctx context.Context, command string) (string, error)
- func (c *Container) FDBPort() int
- func (c *Container) InitializeDatabase(ctx context.Context) error
- func (c *Container) InternalAddress() string
- func (c *Container) InternalClusterFile() string
- func (c *Container) MappedPort() int
- func (c *Container) MustClusterFile(ctx context.Context) string
- func (c *Container) NetworkName() string
- func (c *Container) Pause(ctx context.Context) error
- func (c *Container) Status(ctx context.Context) (string, error)
- func (c *Container) Terminate(ctx context.Context) error
- func (c *Container) Unpause(ctx context.Context) error
- func (c *Container) Version() string
- func (c *Container) WaitAvailable(ctx context.Context) error
- type DockerUnavailableError
- type Option
- func WithAPIVersion(version int) Option
- func WithDataOnDisk() Option
- func WithDatabase(name string) Option
- func WithDirectIP() Option
- func WithFDBPort(port int) Option
- func WithKnob(name, value string) Option
- func WithNetwork(nw *testcontainers.DockerNetwork, aliases ...string) Option
- func WithNetworkAliases(aliases ...string) Option
- func WithProcessCount(n int) Option
- func WithRedundancyMode(mode string) Option
- func WithStartupTimeout(timeout time.Duration) Option
- func WithStorageEngine(engine string) Option
- func WithTenantMode(mode string) Option
- func WithVersion(version string) Option
- func WithoutInit() Option
- type TerminationError
- type Terminator
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func CreateNetwork ¶
func CreateNetwork(ctx context.Context) (*testcontainers.DockerNetwork, error)
CreateNetwork creates a new Docker network. This is a convenience for tests that need to share a network between multiple containers without letting each Run call create its own.
The caller is responsible for removing the network.
func DatabaseAvailable ¶
DatabaseAvailable reports whether fdbcli `status minimal` output says the database is available. The phrase is matched whole: "unavailable" contains "available", and FDB 7.3 never prints "Healthy" there.
func SkipWithoutDocker ¶
SkipWithoutDocker reports whether a suite may skip its FDB tests after Run returned err: only when no Docker daemon is reachable, and never with CI set (.bazelrc forwards CI to tests under --config=ci).
func Terminate ¶
func Terminate(ctx context.Context, c Terminator) error
Terminate stops c with the caller's cleanup context and includes its ID on failure.
func TerminateT ¶
func TerminateT(t interface {
Helper()
Errorf(string, ...any)
}, ctx context.Context, c Terminator,
)
TerminateT stops c and fails the test or benchmark if cleanup fails. Call it from a defer or Cleanup callback with the existing cleanup context.
Types ¶
type Cluster ¶
type Cluster struct {
Coordinator *Container
Replicas []*Container // all containers including coordinator
// contains filtered or unexported fields
}
Cluster represents a multi-container FDB cluster. Each container runs one fdbserver process. The first is the coordinator.
Example:
cluster, err := foundationdb.RunCluster(ctx, 3,
foundationdb.WithStorageEngine("ssd"),
foundationdb.WithRedundancyMode("double"),
)
defer func() {
if err := cluster.Terminate(ctx); err != nil {
log.Printf("terminate cluster: %v", err)
}
}()
cf, _ := cluster.ClusterFile(ctx)
func RunCluster ¶
func RunCluster(ctx context.Context, size int, opts ...testcontainers.ContainerCustomizer) (*Cluster, error)
RunCluster creates an N-container FDB cluster on a shared Docker network. The first container is the coordinator; additional containers join as storage.
All options from Run() are supported. WithNetwork is set automatically. Like Run, it returns a *DockerUnavailableError when no Docker daemon is reachable.
func (*Cluster) ClusterFile ¶
ClusterFile returns the cluster file for external clients (via coordinator).
func (*Cluster) GetContainerID ¶
GetContainerID returns the comma-separated IDs of all cluster containers.
func (*Cluster) InternalClusterFile ¶
InternalClusterFile returns the cluster file for containers on the same network.
type Container ¶
type Container struct {
testcontainers.Container
// contains filtered or unexported fields
}
Container represents a running FoundationDB container.
External clients bootstrap via the mapped port; internal clients use containerIP:4500. Both need routing to the server-advertised bridge-IP transaction endpoints.
func Run ¶
func Run(ctx context.Context, img string, opts ...testcontainers.ContainerCustomizer) (*Container, error)
Run creates, starts, and (by default) initializes a FoundationDB container.
The mapped coordinator port also needs advertised bridge-IP routing for transactions. Cross-container clients use [InternalClusterFile] with a shared WithNetwork.
By default, the database is auto-initialized for single-node operation with tenant_mode=optional_experimental. Use WithoutInit to skip initialization.
The image parameter can be empty ("") to use the default image with the version from FDB_VERSION env var or the built-in default.
With no reachable Docker daemon, Run returns a *DockerUnavailableError; SkipWithoutDocker decides whether a suite may skip.
Example ¶
ctx := context.Background()
// Start a FoundationDB container — auto-initialized, ready to use.
container, err := Run(ctx, "")
if err != nil {
log.Panic(err)
}
defer func() {
if err := Terminate(ctx, container); err != nil {
log.Panic(err)
}
}()
clusterFile, err := container.ClusterFile(ctx)
if err != nil {
log.Panic(err)
}
fmt.Printf("Cluster file: %s\n", clusterFile)
Example (WithCustomConfiguration) ¶
ctx := context.Background()
container, err := Run(ctx, "",
WithDatabase("my_test_db"),
WithAPIVersion(720),
WithVersion("7.1.61"),
)
if err != nil {
log.Panic(err)
}
defer func() {
if err := Terminate(ctx, container); err != nil {
log.Panic(err)
}
}()
fmt.Printf("Database: %s\n", container.Database())
fmt.Printf("API Version: %d\n", container.APIVersion())
fmt.Printf("Version: %s\n", container.Version())
func (*Container) APIVersion ¶
APIVersion returns the configured FDB API version.
func (*Container) ClusterFile ¶
ClusterFile returns the mapped-port bootstrap address, or bridge IP with WithDirectIP. Both modes require routing to the advertised bridge-IP transaction endpoints.
func (*Container) ClusterFilePath ¶
ClusterFilePath writes the cluster file to a temp file and returns the path. The file persists until the caller removes it.
func (*Container) ConnectionString ¶
ConnectionString returns "host:port" for the FDB server (external, port-mapped).
func (*Container) FDBCLIExec ¶
FDBCLIExec runs an fdbcli command inside the container and returns the output.
Example:
output, err := container.FDBCLIExec(ctx, "status details")
Example ¶
ctx := context.Background()
container, err := Run(ctx, "")
if err != nil {
log.Panic(err)
}
defer func() {
if err := Terminate(ctx, container); err != nil {
log.Panic(err)
}
}()
output, err := container.FDBCLIExec(ctx, "status minimal")
if err != nil {
log.Panic(err)
}
fmt.Printf("FDB status: %s\n", output)
func (*Container) InitializeDatabase ¶
InitializeDatabase configures the database for single-node operation. This is called automatically by Run unless WithoutInit is used.
The configure command uses the storage engine and redundancy mode from options. Default: "memory" engine, "single" redundancy, tenant_mode=optional_experimental.
This method is idempotent — calling it on an already-configured database is safe.
func (*Container) InternalAddress ¶
InternalAddress returns the FDB address reachable from within Docker networks. Uses the container's bridge IP: "containerIP:4500".
func (*Container) InternalClusterFile ¶
InternalClusterFile returns a cluster file string usable from containers on the same Docker network. Uses the container's bridge IP (no port mapping needed).
func (*Container) MappedPort ¶
MappedPort returns the host port mapped to FDB's container port.
func (*Container) MustClusterFile ¶
MustClusterFile returns the cluster file content, panicking on error.
func (*Container) NetworkName ¶
NetworkName returns the Docker network name. Returns empty string if the container is on the default bridge (no custom network). Use this to attach other containers to the same network for inter-container communication.
func (*Container) Pause ¶
Pause freezes all processes in the container using Docker pause. The container remains running but FDB becomes unreachable. TCP connections stay open but will time out. Use this to simulate network partitions or FDB hangs.
Call [Unpause] to resume.
func (*Container) Terminate ¶
Terminate terminates the container. The network, if user-provided via WithNetwork, is NOT removed — the caller owns it.
type DockerUnavailableError ¶
type DockerUnavailableError struct {
}
DockerUnavailableError reports that no Docker daemon is reachable, the one startup failure a suite may skip on (see SkipWithoutDocker).
func (*DockerUnavailableError) Error ¶
func (e *DockerUnavailableError) Error() string
func (*DockerUnavailableError) Unwrap ¶
func (e *DockerUnavailableError) Unwrap() error
type Option ¶
type Option struct {
// contains filtered or unexported fields
}
Option configures the FoundationDB container. Options implement testcontainers.ContainerCustomizer so they can be mixed with standard testcontainers options in the Run call.
func WithAPIVersion ¶
WithAPIVersion sets the FDB API version. This is metadata for callers to know which version to pass to fdb.MustAPIVersion(). It doesn't configure the container.
func WithDataOnDisk ¶
func WithDataOnDisk() Option
WithDataOnDisk stores /var/fdb/data on disk (the container's writable layer) instead of the default tmpfs. The default tmpfs keeps tests fast and avoids a leaked anonymous volume, but caps a dataset at host RAM; use this (with an SSD storage engine, e.g. WithStorageEngine("ssd-redwood-1")) for datasets larger than memory. The container's anonymous data volume is on disk and is cleaned up with the container.
func WithDatabase ¶
WithDatabase sets the database name. This is metadata for callers — FDB itself doesn't have named databases (it has one keyspace per cluster).
func WithDirectIP ¶
func WithDirectIP() Option
WithDirectIP makes Container.ClusterFile return the container's bridge IP instead of localhost:mappedPort. This avoids Docker DNAT which causes FDB canonicalRemotePort assertion spam under high connection churn.
This changes coordinator bootstrap only: both modes require routing to advertised bridge-IP transaction endpoints, even when the coordinator port is published.
func WithFDBPort ¶
WithFDBPort overrides the default FDB port (4500). This sets the FDB_PORT environment variable in the container.
func WithKnob ¶
WithKnob sets a server-side FDB knob. Knobs are passed as --knob_NAME=VALUE to the fdbserver process. This is useful for forcing shard splits (e.g., WithKnob("min_shard_bytes", "40000")) or other server behavior changes.
The knob is injected by modifying the entrypoint script inside the container. Multiple WithKnob calls accumulate.
func WithNetwork ¶
func WithNetwork(nw *testcontainers.DockerNetwork, aliases ...string) Option
WithNetwork attaches the container to an existing Docker network instead of creating a new one. The network will NOT be removed on Container.Terminate. Additional aliases can be specified for DNS resolution within the network.
Example ¶
ctx := context.Background()
// Create a shared network for multi-container setups.
nw, err := CreateNetwork(ctx)
if err != nil {
log.Panic(err)
}
defer func() {
if err := nw.Remove(ctx); err != nil {
log.Panicf("remove network %s: %v", nw.ID, err)
}
}()
container, err := Run(ctx, "",
WithNetwork(nw, "fdb-primary"),
)
if err != nil {
log.Panic(err)
}
defer func() {
if err := Terminate(ctx, container); err != nil {
log.Panic(err)
}
}()
fmt.Printf("Network: %s\n", container.NetworkName())
fmt.Printf("Internal address: %s\n", container.InternalAddress())
func WithNetworkAliases ¶
WithNetworkAliases adds network aliases for the container. These are DNS names resolvable by other containers on the same Docker network.
func WithProcessCount ¶
WithProcessCount sets the number of fdbserver processes to run inside the container. Default is 1. When n > 1, additional processes are started on ports 4501..4500+n-1 after the primary process joins the cluster.
Use with WithRedundancyMode("double") or ("triple") to enable data replication across processes. Multiple storage servers enable shard splits, which is required for testing cross-shard GetRange behavior.
Example:
Run(ctx, "",
WithProcessCount(3),
WithRedundancyMode("double"),
WithKnob("min_shard_bytes", "40000"),
)
func WithRedundancyMode ¶
WithRedundancyMode configures FDB replication for the configure command. Valid values: "single" (default), "double", "triple".
func WithStartupTimeout ¶
WithStartupTimeout sets the timeout for waiting for the FDB container to start. Default: 60 seconds.
func WithStorageEngine ¶
WithStorageEngine configures the FDB storage engine for the configure command. Valid values: "memory" (default, fast for tests), "ssd" (persistent).
func WithTenantMode ¶
WithTenantMode configures FDB tenant mode for the configure command. Valid values: "disabled", "optional_experimental", "required". Default: "optional_experimental".
func WithVersion ¶
WithVersion sets the FoundationDB Docker image tag.
func WithoutInit ¶
func WithoutInit() Option
WithoutInit skips automatic database initialization in Run. Use Container.InitializeDatabase for manual initialization.
func (Option) Customize ¶
func (o Option) Customize(_ *testcontainers.GenericContainerRequest) error
Customize implements testcontainers.ContainerCustomizer. Module options don't modify the container request directly — they configure our options struct.
type TerminationError ¶
TerminationError identifies a failed cleanup, including during container startup.
func (*TerminationError) Error ¶
func (e *TerminationError) Error() string
func (*TerminationError) Unwrap ¶
func (e *TerminationError) Unwrap() error