Skip to content

Commit 9d52130

Browse files
authored
fix: skip nil strategies in wait.ForAll (#3032)
* fix: skip nil strategies in wait.ForAll * fix: handle nil strategies correctly * fix: lint
1 parent 5ce9faf commit 9d52130

File tree

2 files changed

+62
-0
lines changed

2 files changed

+62
-0
lines changed

wait/all.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package wait
33
import (
44
"context"
55
"errors"
6+
"reflect"
67
"time"
78
)
89

@@ -62,6 +63,13 @@ func (ms *MultiStrategy) WaitUntilReady(ctx context.Context, target StrategyTarg
6263
}
6364

6465
for _, strategy := range ms.Strategies {
66+
if strategy == nil || reflect.ValueOf(strategy).IsNil() {
67+
// A module could be appending strategies after part of the container initialization,
68+
// and use wait.ForAll on a not initialized strategy.
69+
// In this case, we just skip the nil strategy.
70+
continue
71+
}
72+
6573
strategyCtx := ctx
6674

6775
// Set default Timeout when strategy implements StrategyTimeout

wait/all_test.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,3 +124,57 @@ func TestMultiStrategy_WaitUntilReady(t *testing.T) {
124124
})
125125
}
126126
}
127+
128+
func TestMultiStrategy_handleNils(t *testing.T) {
129+
t.Run("nil-strategy", func(t *testing.T) {
130+
strategy := ForAll(nil)
131+
err := strategy.WaitUntilReady(context.Background(), NopStrategyTarget{})
132+
require.NoError(t, err)
133+
})
134+
135+
t.Run("nil-strategy-in-the-middle", func(t *testing.T) {
136+
strategy := ForAll(nil, ForLog("docker"))
137+
err := strategy.WaitUntilReady(context.Background(), NopStrategyTarget{
138+
ReaderCloser: io.NopCloser(bytes.NewReader([]byte("docker"))),
139+
})
140+
require.NoError(t, err)
141+
})
142+
143+
t.Run("nil-strategy-last", func(t *testing.T) {
144+
strategy := ForAll(ForLog("docker"), nil)
145+
err := strategy.WaitUntilReady(context.Background(), NopStrategyTarget{
146+
ReaderCloser: io.NopCloser(bytes.NewReader([]byte("docker"))),
147+
})
148+
require.NoError(t, err)
149+
})
150+
151+
t.Run("nil-type-implements-strategy", func(t *testing.T) {
152+
var nilStrategy Strategy
153+
154+
strategy := ForAll(ForLog("docker"), nilStrategy)
155+
err := strategy.WaitUntilReady(context.Background(), NopStrategyTarget{
156+
ReaderCloser: io.NopCloser(bytes.NewReader([]byte("docker"))),
157+
})
158+
require.NoError(t, err)
159+
})
160+
161+
t.Run("nil-concrete-value-implements-strategy", func(t *testing.T) {
162+
// Create a nil pointer to a type that implements Strategy
163+
var nilPointerStrategy *nilWaitStrategy
164+
// When we assign it to the interface, the type information is preserved
165+
// but the concrete value is nil
166+
var strategyInterface Strategy = nilPointerStrategy
167+
168+
strategy := ForAll(ForLog("docker"), strategyInterface)
169+
err := strategy.WaitUntilReady(context.Background(), NopStrategyTarget{
170+
ReaderCloser: io.NopCloser(bytes.NewReader([]byte("docker"))),
171+
})
172+
require.NoError(t, err)
173+
})
174+
}
175+
176+
type nilWaitStrategy struct{}
177+
178+
func (s *nilWaitStrategy) WaitUntilReady(_ context.Context, _ StrategyTarget) error {
179+
return nil
180+
}

0 commit comments

Comments
 (0)