summaryrefslogtreecommitdiff
path: root/vendor/github.com/testcontainers/testcontainers-go/wait
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/testcontainers/testcontainers-go/wait')
-rw-r--r--vendor/github.com/testcontainers/testcontainers-go/wait/file.go2
-rw-r--r--vendor/github.com/testcontainers/testcontainers-go/wait/host_port.go94
-rw-r--r--vendor/github.com/testcontainers/testcontainers-go/wait/walk.go3
3 files changed, 73 insertions, 26 deletions
diff --git a/vendor/github.com/testcontainers/testcontainers-go/wait/file.go b/vendor/github.com/testcontainers/testcontainers-go/wait/file.go
index d9cab7a..4f6d38c 100644
--- a/vendor/github.com/testcontainers/testcontainers-go/wait/file.go
+++ b/vendor/github.com/testcontainers/testcontainers-go/wait/file.go
@@ -6,7 +6,7 @@ import (
"io"
"time"
- "github.com/docker/docker/errdefs"
+ "github.com/containerd/errdefs"
)
var (
diff --git a/vendor/github.com/testcontainers/testcontainers-go/wait/host_port.go b/vendor/github.com/testcontainers/testcontainers-go/wait/host_port.go
index 2070bf1..8d97ccb 100644
--- a/vendor/github.com/testcontainers/testcontainers-go/wait/host_port.go
+++ b/vendor/github.com/testcontainers/testcontainers-go/wait/host_port.go
@@ -6,7 +6,6 @@ import (
"fmt"
"net"
"os"
- "strconv"
"time"
"github.com/docker/go-connections/nat"
@@ -42,6 +41,11 @@ type HostPortStrategy struct {
// a shell is not available in the container or when the container doesn't bind
// the port internally until additional conditions are met.
skipInternalCheck bool
+
+ // skipExternalCheck is a flag to skip the external check, which, if used with
+ // skipInternalCheck, makes strategy waiting only for port mapping completion
+ // without accessing port.
+ skipExternalCheck bool
}
// NewHostPortStrategy constructs a default host port strategy that waits for the given
@@ -70,6 +74,12 @@ func ForExposedPort() *HostPortStrategy {
return NewHostPortStrategy("")
}
+// ForMappedPort returns a host port strategy that waits for the given port
+// to be mapped without accessing the port itself.
+func ForMappedPort(port nat.Port) *HostPortStrategy {
+ return NewHostPortStrategy(port).SkipInternalCheck().SkipExternalCheck()
+}
+
// SkipInternalCheck changes the host port strategy to skip the internal check,
// which is useful when a shell is not available in the container or when the
// container doesn't bind the port internally until additional conditions are met.
@@ -79,6 +89,15 @@ func (hp *HostPortStrategy) SkipInternalCheck() *HostPortStrategy {
return hp
}
+// SkipExternalCheck changes the host port strategy to skip the external check,
+// which, if used with SkipInternalCheck, makes strategy waiting only for port
+// mapping completion without accessing port.
+func (hp *HostPortStrategy) SkipExternalCheck() *HostPortStrategy {
+ hp.skipExternalCheck = true
+
+ return hp
+}
+
// WithStartupTimeout can be used to change the default startup timeout
func (hp *HostPortStrategy) WithStartupTimeout(startupTimeout time.Duration) *HostPortStrategy {
hp.timeout = &startupTimeout
@@ -95,6 +114,25 @@ func (hp *HostPortStrategy) Timeout() *time.Duration {
return hp.timeout
}
+// detectInternalPort returns the lowest internal port that is currently bound.
+// If no internal port is found, it returns the zero nat.Port value which
+// can be checked against an empty string.
+func (hp *HostPortStrategy) detectInternalPort(ctx context.Context, target StrategyTarget) (nat.Port, error) {
+ var internalPort nat.Port
+ inspect, err := target.Inspect(ctx)
+ if err != nil {
+ return internalPort, fmt.Errorf("inspect: %w", err)
+ }
+
+ for port := range inspect.NetworkSettings.Ports {
+ if internalPort == "" || port.Int() < internalPort.Int() {
+ internalPort = port
+ }
+ }
+
+ return internalPort, nil
+}
+
// WaitUntilReady implements Strategy.WaitUntilReady
func (hp *HostPortStrategy) WaitUntilReady(ctx context.Context, target StrategyTarget) error {
timeout := defaultStartupTimeout()
@@ -105,34 +143,37 @@ func (hp *HostPortStrategy) WaitUntilReady(ctx context.Context, target StrategyT
ctx, cancel := context.WithTimeout(ctx, timeout)
defer cancel()
- ipAddress, err := target.Host(ctx)
- if err != nil {
- return err
- }
-
waitInterval := hp.PollInterval
internalPort := hp.Port
+ i := 0
if internalPort == "" {
- inspect, err := target.Inspect(ctx)
+ var err error
+ // Port is not specified, so we need to detect it.
+ internalPort, err = hp.detectInternalPort(ctx, target)
if err != nil {
- return err
+ return fmt.Errorf("detect internal port: %w", err)
}
- for port := range inspect.NetworkSettings.Ports {
- if internalPort == "" || port.Int() < internalPort.Int() {
- internalPort = port
+ for internalPort == "" {
+ select {
+ case <-ctx.Done():
+ return fmt.Errorf("detect internal port: retries: %d, last err: %w, ctx err: %w", i, err, ctx.Err())
+ case <-time.After(waitInterval):
+ if err := checkTarget(ctx, target); err != nil {
+ return fmt.Errorf("detect internal port: check target: retries: %d, last err: %w", i, err)
+ }
+
+ internalPort, err = hp.detectInternalPort(ctx, target)
+ if err != nil {
+ return fmt.Errorf("detect internal port: %w", err)
+ }
}
}
}
- if internalPort == "" {
- return errors.New("no port to wait for")
- }
-
- var port nat.Port
- port, err = target.MappedPort(ctx, internalPort)
- i := 0
+ port, err := target.MappedPort(ctx, internalPort)
+ i = 0
for port == "" {
i++
@@ -142,7 +183,7 @@ func (hp *HostPortStrategy) WaitUntilReady(ctx context.Context, target StrategyT
return fmt.Errorf("mapped port: retries: %d, port: %q, last err: %w, ctx err: %w", i, port, err, ctx.Err())
case <-time.After(waitInterval):
if err := checkTarget(ctx, target); err != nil {
- return fmt.Errorf("check target: retries: %d, port: %q, last err: %w", i, port, err)
+ return fmt.Errorf("mapped port: check target: retries: %d, port: %q, last err: %w", i, port, err)
}
port, err = target.MappedPort(ctx, internalPort)
if err != nil {
@@ -151,8 +192,15 @@ func (hp *HostPortStrategy) WaitUntilReady(ctx context.Context, target StrategyT
}
}
- if err := externalCheck(ctx, ipAddress, port, target, waitInterval); err != nil {
- return fmt.Errorf("external check: %w", err)
+ if !hp.skipExternalCheck {
+ ipAddress, err := target.Host(ctx)
+ if err != nil {
+ return fmt.Errorf("host: %w", err)
+ }
+
+ if err := externalCheck(ctx, ipAddress, port, target, waitInterval); err != nil {
+ return fmt.Errorf("external check: %w", err)
+ }
}
if hp.skipInternalCheck {
@@ -177,11 +225,9 @@ func (hp *HostPortStrategy) WaitUntilReady(ctx context.Context, target StrategyT
func externalCheck(ctx context.Context, ipAddress string, port nat.Port, target StrategyTarget, waitInterval time.Duration) error {
proto := port.Proto()
- portNumber := port.Int()
- portString := strconv.Itoa(portNumber)
dialer := net.Dialer{}
- address := net.JoinHostPort(ipAddress, portString)
+ address := net.JoinHostPort(ipAddress, port.Port())
for i := 0; ; i++ {
if err := checkTarget(ctx, target); err != nil {
return fmt.Errorf("check target: retries: %d address: %s: %w", i, address, err)
diff --git a/vendor/github.com/testcontainers/testcontainers-go/wait/walk.go b/vendor/github.com/testcontainers/testcontainers-go/wait/walk.go
index 009e563..98f5755 100644
--- a/vendor/github.com/testcontainers/testcontainers-go/wait/walk.go
+++ b/vendor/github.com/testcontainers/testcontainers-go/wait/walk.go
@@ -2,6 +2,7 @@ package wait
import (
"errors"
+ "slices"
)
var (
@@ -63,7 +64,7 @@ func walk(root *Strategy, visit VisitFunc) error {
for range s.Strategies {
if err := walk(&s.Strategies[i], visit); err != nil {
if errors.Is(err, ErrVisitRemove) {
- s.Strategies = append(s.Strategies[:i], s.Strategies[i+1:]...)
+ s.Strategies = slices.Delete(s.Strategies, i, i+1)
if errors.Is(err, VisitStop) {
return VisitStop
}