diff --git a/Makefile b/Makefile index d365cde699..d50ffda1af 100644 --- a/Makefile +++ b/Makefile @@ -129,8 +129,8 @@ lint-fix: bin/golangci-lint .PHONY: unit unit: - cd $(VALIDATION_TEST_PATH) && go test ./... - go test $$(go list -e ./... | grep -v cmd | grep -v tools | grep -v tests/e2e | grep -v third_party) \ + cd $(VALIDATION_TEST_PATH) && go test -race ./... + go test -race $$(go list -e ./... | grep -v cmd | grep -v tools | grep -v tests/e2e | grep -v third_party) \ -cover -coverprofile=coverage.txt -covermode=atomic sed -i.bak '/generated/d;/fake.go/d' coverage.txt && rm coverage.txt.bak diff --git a/pkg/timanager/manager_test.go b/pkg/timanager/manager_test.go index 1997d1c4fa..7bd2a444af 100644 --- a/pkg/timanager/manager_test.go +++ b/pkg/timanager/manager_test.go @@ -325,7 +325,7 @@ func TestClientManagerSource(t *testing.T) { }) assert.True(tt, synced) - lister.L.Items = c.updated + lister.UpdateItems(c.updated) select { case <-ctx.Done(): diff --git a/pkg/timanager/poller_test.go b/pkg/timanager/poller_test.go index 6a899e6148..d7cf6f6e7d 100644 --- a/pkg/timanager/poller_test.go +++ b/pkg/timanager/poller_test.go @@ -18,6 +18,7 @@ import ( "cmp" "context" "slices" + "sync" "testing" "time" @@ -33,17 +34,23 @@ import ( ) type FakeLister[T any, PT Object[T]] struct { - L List[T, PT] + lock sync.Mutex + L List[T, PT] } func (l *FakeLister[T, PT]) List(_ context.Context) (*List[T, PT], error) { + l.lock.Lock() + defer l.lock.Unlock() return &l.L, nil } -func (l *FakeLister[T, PT]) GetItems(_ *List[T, PT]) []PT { - objs := make([]PT, 0, len(l.L.Items)) - for i := range l.L.Items { - objs = append(objs, &l.L.Items[i]) +func (l *FakeLister[T, PT]) GetItems(list *List[T, PT]) []PT { + l.lock.Lock() + defer l.lock.Unlock() + + objs := make([]PT, 0, len(list.Items)) + for i := range list.Items { + objs = append(objs, &list.Items[i]) } return objs } @@ -52,6 +59,13 @@ func (*FakeLister[T, PT]) MarkAsInvalid(PT) bool { return false } +func (l *FakeLister[T, PT]) UpdateItems(items []T) { + l.lock.Lock() + defer l.lock.Unlock() + + l.L.Items = items +} + func TestPoller(t *testing.T) { cases := []struct { desc string diff --git a/pkg/timanager/util.go b/pkg/timanager/util.go index 574d8137a2..6630800125 100644 --- a/pkg/timanager/util.go +++ b/pkg/timanager/util.go @@ -131,9 +131,11 @@ type cached[Client, UnderlayClient any] struct { c Client f SharedInformerFactory[UnderlayClient] - cancel context.CancelFunc - cacheKeys []string + + started bool + cancel context.CancelFunc + lock sync.Mutex } func NewCache[Client, UnderlayClient any](keys []string, c Client, f SharedInformerFactory[UnderlayClient]) Cache[Client, UnderlayClient] { @@ -157,14 +159,28 @@ func (c *cached[Client, UnderlayClient]) Keys() []string { } func (c *cached[Client, UnderlayClient]) Start(ctx context.Context) { + c.lock.Lock() + defer c.lock.Unlock() + + if c.started { + return + } + nctx, cancel := context.WithCancel(ctx) c.cancel = cancel + c.started = true + c.f.Start(nctx.Done()) } func (c *cached[Client, UnderlayClient]) Stop() { - if c.cancel != nil { - c.cancel() + c.lock.Lock() + defer c.lock.Unlock() + + if !c.started { + return } + + c.cancel() c.f.Shutdown() }