Skip to content

Commit 3161b52

Browse files
authored
Optionally cancel context in TestWaitForWatcher to test timeouts (#4425)
1 parent 7f02231 commit 3161b52

File tree

1 file changed

+30
-29
lines changed

1 file changed

+30
-29
lines changed

internal/pkg/agent/application/upgrade/upgrade_test.go

+30-29
Original file line numberDiff line numberDiff line change
@@ -748,27 +748,25 @@ func TestWaitForWatcher(t *testing.T) {
748748
wantErrWatcherNotStarted := func(t assert.TestingT, err error, i ...interface{}) bool {
749749
return assert.ErrorIs(t, err, ErrWatcherNotStarted, i)
750750
}
751+
751752
tests := []struct {
752-
name string
753-
states []details.State
754-
stateChangeInterval time.Duration
755-
timeout time.Duration
756-
expirationAfterLastState time.Duration
757-
wantErr assert.ErrorAssertionFunc
753+
name string
754+
states []details.State
755+
stateChangeInterval time.Duration
756+
cancelWaitContext bool
757+
wantErr assert.ErrorAssertionFunc
758758
}{
759759
{
760-
name: "Happy path: watcher is watching already",
761-
states: []details.State{details.StateWatching},
762-
stateChangeInterval: 1 * time.Millisecond,
763-
timeout: 500 * time.Millisecond,
764-
expirationAfterLastState: 100 * time.Millisecond,
765-
wantErr: assert.NoError,
760+
name: "Happy path: watcher is watching already",
761+
states: []details.State{details.StateWatching},
762+
stateChangeInterval: 1 * time.Millisecond,
763+
wantErr: assert.NoError,
766764
},
767765
{
768766
name: "Sad path: watcher is never starting",
769767
states: []details.State{details.StateReplacing},
770768
stateChangeInterval: 1 * time.Millisecond,
771-
timeout: 50 * time.Millisecond,
769+
cancelWaitContext: true,
772770
wantErr: wantErrWatcherNotStarted,
773771
},
774772
{
@@ -782,16 +780,14 @@ func TestWaitForWatcher(t *testing.T) {
782780
details.StateRestarting,
783781
details.StateWatching,
784782
},
785-
stateChangeInterval: 1 * time.Millisecond,
786-
timeout: 500 * time.Millisecond,
787-
expirationAfterLastState: 10 * time.Millisecond,
788-
wantErr: assert.NoError,
783+
stateChangeInterval: 1 * time.Millisecond,
784+
wantErr: assert.NoError,
789785
},
790786
{
791787
name: "Timeout: marker is never created",
792788
states: nil,
793789
stateChangeInterval: 1 * time.Millisecond,
794-
timeout: 50 * time.Millisecond,
790+
cancelWaitContext: true,
795791
wantErr: wantErrWatcherNotStarted,
796792
},
797793
{
@@ -805,8 +801,8 @@ func TestWaitForWatcher(t *testing.T) {
805801
details.StateRestarting,
806802
},
807803

808-
stateChangeInterval: 5 * time.Millisecond,
809-
timeout: 20 * time.Millisecond,
804+
stateChangeInterval: 1 * time.Millisecond,
805+
cancelWaitContext: true,
810806
wantErr: wantErrWatcherNotStarted,
811807
},
812808
}
@@ -817,18 +813,22 @@ func TestWaitForWatcher(t *testing.T) {
817813
if !ok {
818814
deadline = time.Now().Add(5 * time.Second)
819815
}
820-
testCtx, cancel := context.WithDeadline(context.TODO(), deadline)
821-
defer cancel()
816+
testCtx, testCancel := context.WithDeadline(context.Background(), deadline)
817+
defer testCancel()
822818

823819
tmpDir := t.TempDir()
824820
updMarkerFilePath := filepath.Join(tmpDir, markerFilename)
825821

826822
waitContext, waitCancel := context.WithCancel(testCtx)
823+
defer waitCancel()
824+
825+
fakeTimeout := 30 * time.Second
826+
827827
// in order to take timing out of the equation provide a context that we can cancel manually
828828
// still assert that the parent context and timeout passed are correct
829829
var createContextFunc createContextWithTimeout = func(ctx context.Context, timeout time.Duration) (context.Context, context.CancelFunc) {
830830
assert.Same(t, testCtx, ctx, "parent context should be the same as the waitForWatcherCall")
831-
assert.Equal(t, tt.timeout, timeout, "timeout used in new context should be the same as testcase")
831+
assert.Equal(t, fakeTimeout, timeout, "timeout used in new context should be the same as testcase")
832832

833833
return waitContext, waitCancel
834834
}
@@ -848,6 +848,8 @@ func TestWaitForWatcher(t *testing.T) {
848848

849849
wg.Add(1)
850850

851+
// worker goroutine: writes out additional states while the test is blocked on waitOnWatcher() call and expires
852+
// the wait context if cancelWaitContext is set to true. Timing of the goroutine is driven by stateChangeInterval.
851853
go func() {
852854
defer wg.Done()
853855
tick := time.NewTicker(tt.stateChangeInterval)
@@ -860,16 +862,15 @@ func TestWaitForWatcher(t *testing.T) {
860862
writeState(t, updMarkerFilePath, state)
861863
}
862864
}
863-
<-time.After(tt.expirationAfterLastState)
864-
waitCancel()
865+
if tt.cancelWaitContext {
866+
<-tick.C
867+
waitCancel()
868+
}
865869
}()
866870

867871
log, _ := logger.NewTesting(tt.name)
868872

869-
tt.wantErr(t, waitForWatcherWithTimeoutCreationFunc(testCtx, log, updMarkerFilePath, tt.timeout, createContextFunc), fmt.Sprintf("waitForWatcher %s, %v, %s, %s)", updMarkerFilePath, tt.states, tt.stateChangeInterval, tt.timeout))
870-
871-
// cancel context
872-
cancel()
873+
tt.wantErr(t, waitForWatcherWithTimeoutCreationFunc(testCtx, log, updMarkerFilePath, fakeTimeout, createContextFunc), fmt.Sprintf("waitForWatcher %s, %v, %s, %s)", updMarkerFilePath, tt.states, tt.stateChangeInterval, fakeTimeout))
873874

874875
// wait for goroutines to finish
875876
wg.Wait()

0 commit comments

Comments
 (0)