Skip to content

Commit

Permalink
test: fix flaky controller-manager tests (#1445)
Browse files Browse the repository at this point in the history
Go Testing doesn't handle panics in goroutines well. So test fatals
need to happen from the main thread. But errors can still happen in
goroutines. So change the controller-manager stopping to assert
instead of require no errors.
  • Loading branch information
karlkfi authored Oct 7, 2024
1 parent bbae3d9 commit 2edae49
Show file tree
Hide file tree
Showing 2 changed files with 18 additions and 49 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -64,13 +64,7 @@ func TestRepoSyncReconcilerDeploymentLifecycle(t *testing.T) {
errCh := startControllerManager(ctx, t, fakeClient, testReconciler)

// Wait for manager to exit before returning
defer func() {
cancel()
t.Log("waiting for controller-manager to stop")
for err := range errCh {
require.NoError(t, err)
}
}()
defer stopControllerManager(t, cancel, errCh)

watchCtx, watchCancel := context.WithTimeout(ctx, 10*time.Second)
defer watchCancel()
Expand Down Expand Up @@ -187,13 +181,7 @@ func TestReconcileInvalidRepoSyncLifecycle(t *testing.T) {
errCh := startControllerManager(ctx, t, fakeClient, testReconciler)

// Wait for manager to exit before returning
defer func() {
cancel()
t.Log("waiting for controller-manager to stop")
for err := range errCh {
require.NoError(t, err)
}
}()
defer stopControllerManager(t, cancel, errCh)

t.Log("watching for RepoSync status update")
watchCtx, watchCancel := context.WithTimeout(ctx, 10*time.Second)
Expand Down Expand Up @@ -260,13 +248,7 @@ func TestReconcileRepoSyncLifecycleValidToInvalid(t *testing.T) {
errCh := startControllerManager(ctx, t, fakeClient, testReconciler)

// Wait for manager to exit before returning
defer func() {
cancel()
t.Log("waiting for controller-manager to stop")
for err := range errCh {
require.NoError(t, err)
}
}()
defer stopControllerManager(t, cancel, errCh)

reconcilerKey := core.NsReconcilerObjectKey(rs.Namespace, rs.Name)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"time"

"github.com/go-logr/logr/testr"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
Expand Down Expand Up @@ -78,13 +79,7 @@ func TestRootSyncReconcilerDeploymentLifecycle(t *testing.T) {
errCh := startControllerManager(ctx, t, fakeClient, testReconciler)

// Wait for manager to exit before returning
defer func() {
cancel()
t.Log("waiting for controller-manager to stop")
for err := range errCh {
require.NoError(t, err)
}
}()
defer stopControllerManager(t, cancel, errCh)

watchCtx, watchCancel := context.WithTimeout(ctx, 10*time.Second)
defer watchCancel()
Expand Down Expand Up @@ -201,13 +196,7 @@ func TestReconcileInvalidRootSyncLifecycle(t *testing.T) {
errCh := startControllerManager(ctx, t, fakeClient, testReconciler)

// Wait for manager to exit before returning
defer func() {
cancel()
t.Log("waiting for controller-manager to stop")
for err := range errCh {
require.NoError(t, err)
}
}()
defer stopControllerManager(t, cancel, errCh)

t.Log("watching for RootSync status update")
watchCtx, watchCancel := context.WithTimeout(ctx, 10*time.Second)
Expand Down Expand Up @@ -274,13 +263,7 @@ func TestReconcileRootSyncLifecycleValidToInvalid1(t *testing.T) {
errCh := startControllerManager(ctx, t, fakeClient, testReconciler)

// Wait for manager to exit before returning
defer func() {
cancel()
t.Log("waiting for controller-manager to stop")
for err := range errCh {
require.NoError(t, err)
}
}()
defer stopControllerManager(t, cancel, errCh)

reconcilerKey := core.RootReconcilerObjectKey(rs.Name)

Expand Down Expand Up @@ -517,13 +500,7 @@ func testDriftProtection(t *testing.T, fakeClient *syncerFake.Client, testReconc
errCh := startControllerManager(ctx, t, fakeClient, testReconciler)

// Wait for manager to exit before returning
defer func() {
cancel()
t.Log("waiting for controller-manager to stop")
for err := range errCh {
require.NoError(t, err)
}
}()
defer stopControllerManager(t, cancel, errCh)

key := objKeyFunc(client.ObjectKeyFromObject(syncObj))

Expand Down Expand Up @@ -650,6 +627,16 @@ func startControllerManager(ctx context.Context, t *testing.T, fakeClient *synce
return errCh
}

func stopControllerManager(t *testing.T, cancel context.CancelFunc, errCh <-chan error) {
cancel()
t.Log("waiting for controller-manager to stop")
for err := range errCh {
// Error/Assert instead of Fatal/Require, to avoid panic when called async.
// Go tests that panic in a defer can be flakey.
assert.NoError(t, err)
}
}

func logObjectYAMLIfFailed(t *testing.T, fakeClient *syncerFake.Client, obj client.Object) {
if t.Failed() {
err := fakeClient.Get(context.Background(), client.ObjectKeyFromObject(obj), obj)
Expand Down

0 comments on commit 2edae49

Please sign in to comment.