summaryrefslogtreecommitdiff
path: root/vendor/github.com/testcontainers/testcontainers-go/options.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/testcontainers/testcontainers-go/options.go')
-rw-r--r--vendor/github.com/testcontainers/testcontainers-go/options.go336
1 files changed, 336 insertions, 0 deletions
diff --git a/vendor/github.com/testcontainers/testcontainers-go/options.go b/vendor/github.com/testcontainers/testcontainers-go/options.go
new file mode 100644
index 0000000..f17de88
--- /dev/null
+++ b/vendor/github.com/testcontainers/testcontainers-go/options.go
@@ -0,0 +1,336 @@
+package testcontainers
+
+import (
+ "context"
+ "fmt"
+ "net/url"
+ "time"
+
+ "dario.cat/mergo"
+ "github.com/docker/docker/api/types/container"
+ "github.com/docker/docker/api/types/network"
+
+ tcexec "github.com/testcontainers/testcontainers-go/exec"
+ "github.com/testcontainers/testcontainers-go/internal/core"
+ "github.com/testcontainers/testcontainers-go/wait"
+)
+
+// ContainerCustomizer is an interface that can be used to configure the Testcontainers container
+// request. The passed request will be merged with the default one.
+type ContainerCustomizer interface {
+ Customize(req *GenericContainerRequest) error
+}
+
+// CustomizeRequestOption is a type that can be used to configure the Testcontainers container request.
+// The passed request will be merged with the default one.
+type CustomizeRequestOption func(req *GenericContainerRequest) error
+
+func (opt CustomizeRequestOption) Customize(req *GenericContainerRequest) error {
+ return opt(req)
+}
+
+// CustomizeRequest returns a function that can be used to merge the passed container request with the one that is used by the container.
+// Slices and Maps will be appended.
+func CustomizeRequest(src GenericContainerRequest) CustomizeRequestOption {
+ return func(req *GenericContainerRequest) error {
+ if err := mergo.Merge(req, &src, mergo.WithOverride, mergo.WithAppendSlice); err != nil {
+ return fmt.Errorf("error merging container request, keeping the original one: %w", err)
+ }
+
+ return nil
+ }
+}
+
+// WithConfigModifier allows to override the default container config
+func WithConfigModifier(modifier func(config *container.Config)) CustomizeRequestOption {
+ return func(req *GenericContainerRequest) error {
+ req.ConfigModifier = modifier
+
+ return nil
+ }
+}
+
+// WithEndpointSettingsModifier allows to override the default endpoint settings
+func WithEndpointSettingsModifier(modifier func(settings map[string]*network.EndpointSettings)) CustomizeRequestOption {
+ return func(req *GenericContainerRequest) error {
+ req.EndpointSettingsModifier = modifier
+
+ return nil
+ }
+}
+
+// WithEnv sets the environment variables for a container.
+// If the environment variable already exists, it will be overridden.
+func WithEnv(envs map[string]string) CustomizeRequestOption {
+ return func(req *GenericContainerRequest) error {
+ if req.Env == nil {
+ req.Env = map[string]string{}
+ }
+
+ for key, val := range envs {
+ req.Env[key] = val
+ }
+
+ return nil
+ }
+}
+
+// WithHostConfigModifier allows to override the default host config
+func WithHostConfigModifier(modifier func(hostConfig *container.HostConfig)) CustomizeRequestOption {
+ return func(req *GenericContainerRequest) error {
+ req.HostConfigModifier = modifier
+
+ return nil
+ }
+}
+
+// WithHostPortAccess allows to expose the host ports to the container
+func WithHostPortAccess(ports ...int) CustomizeRequestOption {
+ return func(req *GenericContainerRequest) error {
+ if req.HostAccessPorts == nil {
+ req.HostAccessPorts = []int{}
+ }
+
+ req.HostAccessPorts = append(req.HostAccessPorts, ports...)
+ return nil
+ }
+}
+
+// Deprecated: the modules API forces passing the image as part of the signature of the Run function.
+// WithImage sets the image for a container
+func WithImage(image string) CustomizeRequestOption {
+ return func(req *GenericContainerRequest) error {
+ req.Image = image
+
+ return nil
+ }
+}
+
+// imageSubstitutor {
+
+// ImageSubstitutor represents a way to substitute container image names
+type ImageSubstitutor interface {
+ // Description returns the name of the type and a short description of how it modifies the image.
+ // Useful to be printed in logs
+ Description() string
+ Substitute(image string) (string, error)
+}
+
+// }
+
+// CustomHubSubstitutor represents a way to substitute the hub of an image with a custom one,
+// using provided value with respect to the HubImageNamePrefix configuration value.
+type CustomHubSubstitutor struct {
+ hub string
+}
+
+// NewCustomHubSubstitutor creates a new CustomHubSubstitutor
+func NewCustomHubSubstitutor(hub string) CustomHubSubstitutor {
+ return CustomHubSubstitutor{
+ hub: hub,
+ }
+}
+
+// Description returns the name of the type and a short description of how it modifies the image.
+func (c CustomHubSubstitutor) Description() string {
+ return fmt.Sprintf("CustomHubSubstitutor (replaces hub with %s)", c.hub)
+}
+
+// Substitute replaces the hub of the image with the provided one, with certain conditions:
+// - if the hub is empty, the image is returned as is.
+// - if the image already contains a registry, the image is returned as is.
+// - if the HubImageNamePrefix configuration value is set, the image is returned as is.
+func (c CustomHubSubstitutor) Substitute(image string) (string, error) {
+ registry := core.ExtractRegistry(image, "")
+ cfg := ReadConfig()
+
+ exclusions := []func() bool{
+ func() bool { return c.hub == "" },
+ func() bool { return registry != "" },
+ func() bool { return cfg.Config.HubImageNamePrefix != "" },
+ }
+
+ for _, exclusion := range exclusions {
+ if exclusion() {
+ return image, nil
+ }
+ }
+
+ result, err := url.JoinPath(c.hub, image)
+ if err != nil {
+ return "", err
+ }
+
+ return result, nil
+}
+
+// prependHubRegistry represents a way to prepend a custom Hub registry to the image name,
+// using the HubImageNamePrefix configuration value
+type prependHubRegistry struct {
+ prefix string
+}
+
+// newPrependHubRegistry creates a new prependHubRegistry
+func newPrependHubRegistry(hubPrefix string) prependHubRegistry {
+ return prependHubRegistry{
+ prefix: hubPrefix,
+ }
+}
+
+// Description returns the name of the type and a short description of how it modifies the image.
+func (p prependHubRegistry) Description() string {
+ return fmt.Sprintf("HubImageSubstitutor (prepends %s)", p.prefix)
+}
+
+// Substitute prepends the Hub prefix to the image name, with certain conditions:
+// - if the prefix is empty, the image is returned as is.
+// - if the image is a non-hub image (e.g. where another registry is set), the image is returned as is.
+// - if the image is a Docker Hub image where the hub registry is explicitly part of the name
+// (i.e. anything with a registry.hub.docker.com host part), the image is returned as is.
+func (p prependHubRegistry) Substitute(image string) (string, error) {
+ registry := core.ExtractRegistry(image, "")
+
+ // add the exclusions in the right order
+ exclusions := []func() bool{
+ func() bool { return p.prefix == "" }, // no prefix set at the configuration level
+ func() bool { return registry != "" }, // non-hub image
+ func() bool { return registry == "docker.io" }, // explicitly including docker.io
+ func() bool { return registry == "registry.hub.docker.com" }, // explicitly including registry.hub.docker.com
+ }
+
+ for _, exclusion := range exclusions {
+ if exclusion() {
+ return image, nil
+ }
+ }
+
+ result, err := url.JoinPath(p.prefix, image)
+ if err != nil {
+ return "", err
+ }
+
+ return result, nil
+}
+
+// WithImageSubstitutors sets the image substitutors for a container
+func WithImageSubstitutors(fn ...ImageSubstitutor) CustomizeRequestOption {
+ return func(req *GenericContainerRequest) error {
+ req.ImageSubstitutors = fn
+
+ return nil
+ }
+}
+
+// WithLogConsumers sets the log consumers for a container
+func WithLogConsumers(consumer ...LogConsumer) CustomizeRequestOption {
+ return func(req *GenericContainerRequest) error {
+ if req.LogConsumerCfg == nil {
+ req.LogConsumerCfg = &LogConsumerConfig{}
+ }
+
+ req.LogConsumerCfg.Consumers = consumer
+ return nil
+ }
+}
+
+// Executable represents an executable command to be sent to a container, including options,
+// as part of the different lifecycle hooks.
+type Executable interface {
+ AsCommand() []string
+ // Options can container two different types of options:
+ // - Docker's ExecConfigs (WithUser, WithWorkingDir, WithEnv, etc.)
+ // - testcontainers' ProcessOptions (i.e. Multiplexed response)
+ Options() []tcexec.ProcessOption
+}
+
+// ExecOptions is a struct that provides a default implementation for the Options method
+// of the Executable interface.
+type ExecOptions struct {
+ opts []tcexec.ProcessOption
+}
+
+func (ce ExecOptions) Options() []tcexec.ProcessOption {
+ return ce.opts
+}
+
+// RawCommand is a type that implements Executable and represents a command to be sent to a container
+type RawCommand struct {
+ ExecOptions
+ cmds []string
+}
+
+func NewRawCommand(cmds []string) RawCommand {
+ return RawCommand{
+ cmds: cmds,
+ ExecOptions: ExecOptions{
+ opts: []tcexec.ProcessOption{},
+ },
+ }
+}
+
+// AsCommand returns the command as a slice of strings
+func (r RawCommand) AsCommand() []string {
+ return r.cmds
+}
+
+// WithStartupCommand will execute the command representation of each Executable into the container.
+// It will leverage the container lifecycle hooks to call the command right after the container
+// is started.
+func WithStartupCommand(execs ...Executable) CustomizeRequestOption {
+ return func(req *GenericContainerRequest) error {
+ startupCommandsHook := ContainerLifecycleHooks{
+ PostStarts: []ContainerHook{},
+ }
+
+ for _, exec := range execs {
+ execFn := func(ctx context.Context, c Container) error {
+ _, _, err := c.Exec(ctx, exec.AsCommand(), exec.Options()...)
+ return err
+ }
+
+ startupCommandsHook.PostStarts = append(startupCommandsHook.PostStarts, execFn)
+ }
+
+ req.LifecycleHooks = append(req.LifecycleHooks, startupCommandsHook)
+
+ return nil
+ }
+}
+
+// WithAfterReadyCommand will execute the command representation of each Executable into the container.
+// It will leverage the container lifecycle hooks to call the command right after the container
+// is ready.
+func WithAfterReadyCommand(execs ...Executable) CustomizeRequestOption {
+ return func(req *GenericContainerRequest) error {
+ postReadiesHook := []ContainerHook{}
+
+ for _, exec := range execs {
+ execFn := func(ctx context.Context, c Container) error {
+ _, _, err := c.Exec(ctx, exec.AsCommand(), exec.Options()...)
+ return err
+ }
+
+ postReadiesHook = append(postReadiesHook, execFn)
+ }
+
+ req.LifecycleHooks = append(req.LifecycleHooks, ContainerLifecycleHooks{
+ PostReadies: postReadiesHook,
+ })
+
+ return nil
+ }
+}
+
+// WithWaitStrategy sets the wait strategy for a container, using 60 seconds as deadline
+func WithWaitStrategy(strategies ...wait.Strategy) CustomizeRequestOption {
+ return WithWaitStrategyAndDeadline(60*time.Second, strategies...)
+}
+
+// WithWaitStrategyAndDeadline sets the wait strategy for a container, including deadline
+func WithWaitStrategyAndDeadline(deadline time.Duration, strategies ...wait.Strategy) CustomizeRequestOption {
+ return func(req *GenericContainerRequest) error {
+ req.WaitingFor = wait.ForAll(strategies...).WithDeadline(deadline)
+
+ return nil
+ }
+}