Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 68 additions & 0 deletions docs/features/common_functional_options.md
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,12 @@ func (g *TestLogConsumer) Accept(l Log) {
}
```

#### WithLogConsumerConfig

- Not available until the next release of testcontainers-go <a href="https://github.com/testcontainers/testcontainers-go"><span class="tc-version">:material-tag: main</span></a>

If you need to set the log consumer config for the container, you can use `testcontainers.WithLogConsumerConfig`. This option completely replaces the existing log consumer config, including the log consumers and the log production options.

#### WithLogger

- Since testcontainers-go <a href="https://github.com/testcontainers/testcontainers-go/releases/tag/v0.29.0"><span class="tc-version">:material-tag: v0.29.0</span></a>
Expand All @@ -214,6 +220,26 @@ func TestHandler(t *testing.T) {

Please read the [Following Container Logs](/features/follow_logs) documentation for more information about creating log consumers.

#### WithAlwaysPull

- Not available until the next release of testcontainers-go <a href="https://github.com/testcontainers/testcontainers-go"><span class="tc-version">:material-tag: main</span></a>

If you need to pull the image before starting the container, you can use `testcontainers.WithAlwaysPull()`.

#### WithImagePlatform

- Not available until the next release of testcontainers-go <a href="https://github.com/testcontainers/testcontainers-go"><span class="tc-version">:material-tag: main</span></a>

If you need to set the platform for a container, you can use `testcontainers.WithImagePlatform(platform string)`.

#### LifecycleHooks

- Not available until the next release of testcontainers-go <a href="https://github.com/testcontainers/testcontainers-go"><span class="tc-version">:material-tag: main</span></a>

If you need to set the lifecycle hooks for the container, you can use `testcontainers.WithLifecycleHooks`, which replaces the existing lifecycle hooks with the new ones.

You can also use `testcontainers.WithAdditionalLifecycleHooks`, which appends the new lifecycle hooks to the existing ones.

#### Wait Strategies

If you need to set a different wait strategy for the container, you can use `testcontainers.WithWaitStrategy` with a valid wait strategy.
Expand Down Expand Up @@ -282,6 +308,24 @@ In the case you need to retrieve the network name, you can simply read it from t
!!!warning
This option is not checking whether the network exists or not. If you use a network that doesn't exist, the container will start in the default Docker network, as in the default behavior.

#### WithNetworkByName

- Not available until the next release of testcontainers-go <a href="https://github.com/testcontainers/testcontainers-go"><span class="tc-version">:material-tag: main</span></a>

If you want to attach your containers to an already existing Docker network by its name, you can use the `network.WithNetworkName(aliases []string, networkName string)` option, which receives an alias as parameter and the network name, attaching the container to it, and setting the network alias for that network.

!!!warning
In case the network name is `bridge`, no aliases are set. This is because network-scoped alias is supported only for containers in user defined networks.

#### WithBridgeNetwork

- Not available until the next release of testcontainers-go <a href="https://github.com/testcontainers/testcontainers-go"><span class="tc-version">:material-tag: main</span></a>

If you want to attach your containers to the `bridge` network, you can use the `network.WithBridgeNetwork()` option.

!!!warning
The `bridge` network is the default network for Docker. It's not a user defined network, so it doesn't support network-scoped aliases.

#### WithNewNetwork

- Since testcontainers-go <a href="https://github.com/testcontainers/testcontainers-go/releases/tag/v0.27.0"><span class="tc-version">:material-tag: v0.27.0</span></a>
Expand Down Expand Up @@ -335,3 +379,27 @@ ctr, err := mymodule.Run(ctx, "docker.io/myservice:1.2.3",

!!!warning
Reusing a container is experimental and the API is subject to change for a more robust implementation that is not based on container names.

#### WithName

- Not available until the next release of testcontainers-go <a href="https://github.com/testcontainers/testcontainers-go"><span class="tc-version">:material-tag: main</span></a>

If you need to set the name of the container, you can use the `testcontainers.WithName` option.

```golang
ctr, err := mymodule.Run(ctx, "docker.io/myservice:1.2.3",
testcontainers.WithName("my-container-name"),
)
```

!!!warning
This option is not checking whether the container name is already in use. If you use a name that is already in use, an error is returned.
At the same time, we discourage using this option as it might lead to unexpected behavior, but we understand that in some cases it might be useful.

#### WithNoStart

- Not available until the next release of testcontainers-go <a href="https://github.com/testcontainers/testcontainers-go"><span class="tc-version">:material-tag: main</span></a>

If you need to prevent the container from being started after creation, you can use the `testcontainers.WithNoStart` option.


11 changes: 11 additions & 0 deletions docs/modules/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,12 @@ In order to simplify the creation of the container for a given module, `Testcont
- `testcontainers.WithTmpfs`: a function that adds tmpfs mounts to the container.
- `testcontainers.WithHostPortAccess`: a function that enables the container to access a port that is already running in the host.
- `testcontainers.WithLogConsumers`: a function that sets the log consumers for the container request.
- `testcontainers.WithLogConsumerConfig`: a function that sets the log consumer config for the container request.
- `testcontainers.WithLogger`: a function that sets the logger for the container request.
- `testcontainers.WithLifecycleHooks`: a function that sets the lifecycle hooks for the container request.
- `testcontainers.WithAdditionalLifecycleHooks`: a function that appends lifecycle hooks to the existing ones for the container request.
- `testcontainers.WithAlwaysPull`: a function that pulls the image before starting the container.
- `testcontainers.WithImagePlatform`: a function that sets the image platform for the container request.
- `testcontainers.WithWaitStrategy`: a function that sets the wait strategy for the container request.
- `testcontainers.WithWaitStrategyAndDeadline`: a function that sets the wait strategy for the container request with a deadline.
- `testcontainers.WithStartupCommand`: a function that sets the execution of a command when the container starts.
Expand All @@ -217,6 +222,12 @@ In order to simplify the creation of the container for a given module, `Testcont
- `testcontainers.WithEndpointSettingsModifier`: a function that sets the endpoint settings Docker type for the container request. Please see [Advanced Settings](../features/creating_container.md#advanced-settings) for more information.
- `testcontainers.CustomizeRequest`: a function that merges the default options with the ones provided by the user. Recommended for completely customizing the container request.
- `testcontainers.WithReuseByName`: a function that marks a container to be reused if it exists or create a new one if it doesn't.
- `testcontainers.WithName`: a function that sets the name of the container.
- `testcontainers.WithNoStart`: a function that prevents the container from being started after creation, so it must be started manually.
- `network.WithNetwork`: a function that sets the network and the network aliases for the container request, reusing an already existing network.
- `network.WithNetworkName`: a function that sets the network aliases for an already existing network, by its name.
- `network.WithBridgeNetwork`: a function that sets the container to be attached to the `bridge` network.
- `network.WithNewNetwork`: a function that sets the network aliases for a throw-away network for the container request.

### Update Go dependencies in the modules

Expand Down
22 changes: 21 additions & 1 deletion network/network.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package network

import (
"context"
"errors"
"fmt"

"github.com/docker/docker/api/types/network"
Expand Down Expand Up @@ -137,8 +138,18 @@ func WithIPAM(ipam *network.IPAM) CustomizeNetworkOption {
// WithNetwork reuses an already existing network, attaching the container to it.
// Finally it sets the network alias on that network to the given alias.
func WithNetwork(aliases []string, nw *testcontainers.DockerNetwork) testcontainers.CustomizeRequestOption {
return WithNetworkName(aliases, nw.Name)
}

// WithNetworkName attachs a container to an already existing network, by its name.
// If the network is not "bridge", it sets the network alias on that network
// to the given alias, else, it returns an error. This is because network-scoped alias
// is supported only for containers in user defined networks.
func WithNetworkName(aliases []string, networkName string) testcontainers.CustomizeRequestOption {
return func(req *testcontainers.GenericContainerRequest) error {
networkName := nw.Name
if networkName == "bridge" {
return errors.New("network-scoped aliases are supported only for containers in user defined networks")
}

// attaching to the network because it was created with success or it already existed.
req.Networks = append(req.Networks, networkName)
Expand All @@ -152,6 +163,15 @@ func WithNetwork(aliases []string, nw *testcontainers.DockerNetwork) testcontain
}
}

// WithBridgeNetwork attachs a container to the "bridge" network.
// There is no need to set the network alias, as it is not supported for the "bridge" network.
func WithBridgeNetwork() testcontainers.CustomizeRequestOption {
return func(req *testcontainers.GenericContainerRequest) error {
req.Networks = append(req.Networks, "bridge")
return nil
}
}

// WithNewNetwork creates a new network with random name and customizers, and attaches the container to it.
// Finally it sets the network alias on that network to the given alias.
func WithNewNetwork(ctx context.Context, aliases []string, opts ...NetworkCustomizer) testcontainers.CustomizeRequestOption {
Expand Down
38 changes: 38 additions & 0 deletions network/network_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,44 @@ func TestWithNetwork(t *testing.T) {
require.Equal(t, expectedLabels, newNetwork.Labels)
}

func TestWithNetworkName(t *testing.T) {
t.Run("bridge/success", func(t *testing.T) {
req := testcontainers.GenericContainerRequest{
ContainerRequest: testcontainers.ContainerRequest{},
}

err := network.WithBridgeNetwork()(&req)
require.NoError(t, err)

require.Len(t, req.Networks, 1)
require.Equal(t, "bridge", req.Networks[0])
})

t.Run("bridge/error/network-scoped-alias", func(t *testing.T) {
req := testcontainers.GenericContainerRequest{
ContainerRequest: testcontainers.ContainerRequest{},
}

err := network.WithNetworkName([]string{"alias"}, "bridge")(&req)
require.Error(t, err)
})

t.Run("user-defined/success", func(t *testing.T) {
req := testcontainers.GenericContainerRequest{
ContainerRequest: testcontainers.ContainerRequest{},
}

err := network.WithNetworkName([]string{"alias"}, "user-defined")(&req)
require.NoError(t, err)

require.Len(t, req.Networks, 1)
require.Equal(t, "user-defined", req.Networks[0])

require.Len(t, req.NetworkAliases, 1)
require.Equal(t, map[string][]string{"user-defined": {"alias"}}, req.NetworkAliases)
})
}

func TestWithSyntheticNetwork(t *testing.T) {
nw := &testcontainers.DockerNetwork{
Name: "synthetic-network",
Expand Down
68 changes: 65 additions & 3 deletions options.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,14 +106,33 @@ func WithHostPortAccess(ports ...int) CustomizeRequestOption {
}
}

// WithName will set the name of the container.
func WithName(containerName string) CustomizeRequestOption {
return func(req *GenericContainerRequest) error {
if containerName == "" {
return errors.New("container name must be provided")
}
req.Name = containerName
return nil
}
}

// WithNoStart will prevent the container from being started after creation.
func WithNoStart() CustomizeRequestOption {
return func(req *GenericContainerRequest) error {
req.Started = false
return nil
}
}

// WithReuseByName will mark a container to be reused if it exists or create a new one if it doesn't.
// A container name must be provided to identify the container to be reused.
func WithReuseByName(containerName string) CustomizeRequestOption {
return func(req *GenericContainerRequest) error {
if containerName == "" {
return errors.New("container name must be provided for reuse")
if err := WithName(containerName)(req); err != nil {
return err
}
req.Name = containerName

req.Reuse = true
return nil
}
Expand Down Expand Up @@ -255,6 +274,17 @@ func WithLogConsumers(consumer ...LogConsumer) CustomizeRequestOption {
}
}

// WithLogConsumerConfig sets the log consumer config for a container.
// Beware that this option completely replaces the existing log consumer config,
// including the log consumers and the log production options,
// so it should be used with care.
func WithLogConsumerConfig(config *LogConsumerConfig) CustomizeRequestOption {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: didn't we deprecate logconsumers?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope, we added a log package for the logging of the library, but the logconsumers, and the config, it's still in the core.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something we should put on the list as the current way this is done is pretty limiting.

return func(req *GenericContainerRequest) error {
req.LogConsumerCfg = config
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 {
Expand Down Expand Up @@ -376,6 +406,22 @@ func WithImageMount(source string, subpath string, target ContainerMountTarget)
}
}

// WithAlwaysPull will pull the image before starting the container
func WithAlwaysPull() CustomizeRequestOption {
return func(req *GenericContainerRequest) error {
req.AlwaysPullImage = true
return nil
}
}

// WithImagePlatform sets the platform for a container
func WithImagePlatform(platform string) CustomizeRequestOption {
return func(req *GenericContainerRequest) error {
req.ImagePlatform = platform
return nil
}
}

// WithEntrypoint completely replaces the entrypoint of a container
func WithEntrypoint(entrypoint ...string) CustomizeRequestOption {
return func(req *GenericContainerRequest) error {
Expand Down Expand Up @@ -429,6 +475,22 @@ func WithLabels(labels map[string]string) CustomizeRequestOption {
}
}

// WithLifecycleHooks completely replaces the lifecycle hooks for a container
func WithLifecycleHooks(hooks ...ContainerLifecycleHooks) CustomizeRequestOption {
return func(req *GenericContainerRequest) error {
req.LifecycleHooks = hooks
return nil
}
}

// WithAdditionalLifecycleHooks appends lifecycle hooks to the existing ones for a container
func WithAdditionalLifecycleHooks(hooks ...ContainerLifecycleHooks) CustomizeRequestOption {
return func(req *GenericContainerRequest) error {
req.LifecycleHooks = append(req.LifecycleHooks, hooks...)
return nil
}
}

// WithMounts appends the mounts to the mounts for a container
func WithMounts(mounts ...ContainerMount) CustomizeRequestOption {
return func(req *GenericContainerRequest) error {
Expand Down
Loading
Loading