From a3d768a7decdee6b2f7714bff19323f1b9ed4de9 Mon Sep 17 00:00:00 2001 From: Brad Davidson Date: Tue, 17 Dec 2024 23:23:54 +0000 Subject: [PATCH] Replace *core.Factory with CoreFactory interface Make this field an interface instead of pointer to allow mocking. Not sure why wrangler has a type that returns an interface instead of just making it an interface itself. Wrangler in general is hard to mock for testing. Signed-off-by: Brad Davidson (cherry picked from commit e6327652f02be92ae086a751e016c639011c6848) Signed-off-by: Brad Davidson --- pkg/cluster/https.go | 10 +++++++--- pkg/daemons/config/types.go | 9 ++++++++- tests/mock/core.go | 28 ++++++++++++++++++++++++++++ 3 files changed, 43 insertions(+), 4 deletions(-) diff --git a/pkg/cluster/https.go b/pkg/cluster/https.go index 1b25d321bc..5705384440 100644 --- a/pkg/cluster/https.go +++ b/pkg/cluster/https.go @@ -141,9 +141,13 @@ func (c *Cluster) initClusterAndHTTPS(ctx context.Context) error { func tlsStorage(ctx context.Context, dataDir string, runtime *config.ControlRuntime) dynamiclistener.TLSStorage { fileStorage := file.New(filepath.Join(dataDir, "tls/dynamic-cert.json")) cache := memory.NewBacked(fileStorage) - return kubernetes.New(ctx, func() *core.Factory { - return runtime.Core - }, metav1.NamespaceSystem, version.Program+"-serving", cache) + coreGetter := func() *core.Factory { + if coreFactory, ok := runtime.Core.(*core.Factory); ok { + return coreFactory + } + return nil + } + return kubernetes.New(ctx, coreGetter, metav1.NamespaceSystem, version.Program+"-serving", cache) } // wrapHandler wraps the dynamiclistener request handler, adding a User-Agent value to diff --git a/pkg/daemons/config/types.go b/pkg/daemons/config/types.go index fce31f1c3b..23a2f21a12 100644 --- a/pkg/daemons/config/types.go +++ b/pkg/daemons/config/types.go @@ -1,6 +1,7 @@ package config import ( + "context" "fmt" "net" "net/http" @@ -372,11 +373,17 @@ type ControlRuntime struct { K8s kubernetes.Interface K3s *k3s.Factory - Core *core.Factory + Core CoreFactory Event record.EventRecorder EtcdConfig endpoint.ETCDConfig } +type CoreFactory interface { + Core() core.Interface + Sync(ctx context.Context) error + Start(ctx context.Context, defaultThreadiness int) error +} + func NewRuntime(containerRuntimeReady <-chan struct{}) *ControlRuntime { return &ControlRuntime{ ContainerRuntimeReady: containerRuntimeReady, diff --git a/tests/mock/core.go b/tests/mock/core.go index 7664b657f6..71014dc94d 100644 --- a/tests/mock/core.go +++ b/tests/mock/core.go @@ -1,7 +1,10 @@ package mock import ( + "context" + "github.com/golang/mock/gomock" + "github.com/k3s-io/k3s/pkg/daemons/config" "github.com/rancher/wrangler/v3/pkg/generated/controllers/core" corev1 "github.com/rancher/wrangler/v3/pkg/generated/controllers/core/v1" "github.com/rancher/wrangler/v3/pkg/generic/fake" @@ -16,6 +19,31 @@ import ( // Mocks so that we can call Runtime.Core.Core().V1() without a functioning apiserver // +// explicit interface check for core factory mock +var _ config.CoreFactory = &CoreFactoryMock{} + +type CoreFactoryMock struct { + CoreMock *CoreMock +} + +func NewCoreFactory(c *gomock.Controller) *CoreFactoryMock { + return &CoreFactoryMock{ + CoreMock: NewCore(c), + } +} + +func (m *CoreFactoryMock) Core() core.Interface { + return m.CoreMock +} + +func (m *CoreFactoryMock) Sync(ctx context.Context) error { + return nil +} + +func (m *CoreFactoryMock) Start(ctx context.Context, defaultThreadiness int) error { + return nil +} + // explicit interface check for core mock var _ core.Interface = &CoreMock{}