Rework mock executor using gomock for call validation

Generate the mock executor with mockgen and convert existing uses of the mock executor to set it up properly.

Signed-off-by: Brad Davidson <brad.davidson@rancher.com>
This commit is contained in:
Brad Davidson 2025-03-27 20:30:02 +00:00 committed by Brad Davidson
parent 441a42e8ce
commit 0eeac6a622
4 changed files with 275 additions and 54 deletions

View file

@ -19,6 +19,7 @@ import (
"github.com/k3s-io/k3s/pkg/daemons/config"
"github.com/k3s-io/k3s/pkg/etcd/s3"
testutil "github.com/k3s-io/k3s/tests"
"github.com/k3s-io/k3s/tests/mock"
"github.com/robfig/cron/v3"
"github.com/sirupsen/logrus"
"go.etcd.io/etcd/api/v3/etcdserverpb"
@ -137,7 +138,9 @@ func Test_UnitETCD_IsInitialized(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
mock.NewExecutorWithEmbeddedETCD(t)
e := NewETCD()
defer tt.teardown(tt.args.config)
if err := tt.setup(tt.args.config); err != nil {
t.Errorf("Prep for ETCD.IsInitialized() failed = %v", err)
@ -215,6 +218,7 @@ func Test_UnitETCD_Register(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
mock.NewExecutorWithEmbeddedETCD(t)
e := NewETCD()
defer tt.teardown(tt.args.config)
@ -389,6 +393,7 @@ func Test_UnitETCD_Start(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
mock.NewExecutorWithEmbeddedETCD(t)
e := &ETCD{
client: tt.fields.client,
config: tt.fields.config,
@ -628,6 +633,7 @@ func Test_UnitETCD_Test(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
mock.NewExecutorWithEmbeddedETCD(t)
e := &ETCD{
client: tt.fields.client,
config: tt.fields.config,

View file

@ -1,86 +1,273 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: pkg/daemons/executor/executor.go
//
// Generated by this command:
//
// mockgen --source pkg/daemons/executor/executor.go -self_package github.com/k3s-io/k3s/tests/mock -package mock -mock_names Executor=Executor
//
// Package mock is a generated GoMock package.
package mock
import (
"context"
"errors"
"net/http"
context "context"
http "net/http"
reflect "reflect"
"github.com/k3s-io/k3s/pkg/cli/cmds"
"github.com/k3s-io/k3s/pkg/daemons/config"
"github.com/k3s-io/k3s/pkg/daemons/executor"
"k8s.io/apiserver/pkg/authentication/authenticator"
cmds "github.com/k3s-io/k3s/pkg/cli/cmds"
config "github.com/k3s-io/k3s/pkg/daemons/config"
executor "github.com/k3s-io/k3s/pkg/daemons/executor"
gomock "go.uber.org/mock/gomock"
authenticator "k8s.io/apiserver/pkg/authentication/authenticator"
)
// mock executor that does not actually start anything
type Executor struct{}
func (e *Executor) Bootstrap(ctx context.Context, nodeConfig *config.Node, cfg cmds.Agent) error {
return errors.New("not implemented")
// Executor is a mock of Executor interface.
type Executor struct {
ctrl *gomock.Controller
recorder *ExecutorMockRecorder
isgomock struct{}
}
func (e *Executor) Kubelet(ctx context.Context, args []string) error {
return errors.New("not implemented")
// ExecutorMockRecorder is the mock recorder for Executor.
type ExecutorMockRecorder struct {
mock *Executor
}
func (e *Executor) KubeProxy(ctx context.Context, args []string) error {
return errors.New("not implemented")
// NewExecutor creates a new mock instance.
func NewExecutor(ctrl *gomock.Controller) *Executor {
mock := &Executor{ctrl: ctrl}
mock.recorder = &ExecutorMockRecorder{mock}
return mock
}
func (e *Executor) APIServerHandlers(ctx context.Context) (authenticator.Request, http.Handler, error) {
return nil, nil, errors.New("not implemented")
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *Executor) EXPECT() *ExecutorMockRecorder {
return m.recorder
}
func (e *Executor) APIServer(ctx context.Context, args []string) error {
return errors.New("not implemented")
// APIServer mocks base method.
func (m *Executor) APIServer(ctx context.Context, args []string) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "APIServer", ctx, args)
ret0, _ := ret[0].(error)
return ret0
}
func (e *Executor) Scheduler(ctx context.Context, nodeReady <-chan struct{}, args []string) error {
return errors.New("not implemented")
// APIServer indicates an expected call of APIServer.
func (mr *ExecutorMockRecorder) APIServer(ctx, args any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "APIServer", reflect.TypeOf((*Executor)(nil).APIServer), ctx, args)
}
func (e *Executor) ControllerManager(ctx context.Context, args []string) error {
return errors.New("not implemented")
// APIServerHandlers mocks base method.
func (m *Executor) APIServerHandlers(ctx context.Context) (authenticator.Request, http.Handler, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "APIServerHandlers", ctx)
ret0, _ := ret[0].(authenticator.Request)
ret1, _ := ret[1].(http.Handler)
ret2, _ := ret[2].(error)
return ret0, ret1, ret2
}
func (e *Executor) CurrentETCDOptions() (executor.InitialOptions, error) {
return executor.InitialOptions{}, nil
// APIServerHandlers indicates an expected call of APIServerHandlers.
func (mr *ExecutorMockRecorder) APIServerHandlers(ctx any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "APIServerHandlers", reflect.TypeOf((*Executor)(nil).APIServerHandlers), ctx)
}
func (e *Executor) ETCD(ctx context.Context, args *executor.ETCDConfig, extraArgs []string, test executor.TestFunc) error {
embed := &executor.Embedded{}
return embed.ETCD(ctx, args, extraArgs, test)
// APIServerReadyChan mocks base method.
func (m *Executor) APIServerReadyChan() <-chan struct{} {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "APIServerReadyChan")
ret0, _ := ret[0].(<-chan struct{})
return ret0
}
func (e *Executor) CloudControllerManager(ctx context.Context, ccmRBACReady <-chan struct{}, args []string) error {
return errors.New("not implemented")
// APIServerReadyChan indicates an expected call of APIServerReadyChan.
func (mr *ExecutorMockRecorder) APIServerReadyChan() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "APIServerReadyChan", reflect.TypeOf((*Executor)(nil).APIServerReadyChan))
}
func (e *Executor) Containerd(ctx context.Context, node *config.Node) error {
return errors.New("not implemented")
// Bootstrap mocks base method.
func (m *Executor) Bootstrap(ctx context.Context, nodeConfig *config.Node, cfg cmds.Agent) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Bootstrap", ctx, nodeConfig, cfg)
ret0, _ := ret[0].(error)
return ret0
}
func (e *Executor) Docker(ctx context.Context, node *config.Node) error {
return errors.New("not implemented")
// Bootstrap indicates an expected call of Bootstrap.
func (mr *ExecutorMockRecorder) Bootstrap(ctx, nodeConfig, cfg any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Bootstrap", reflect.TypeOf((*Executor)(nil).Bootstrap), ctx, nodeConfig, cfg)
}
func (e *Executor) CRI(ctx context.Context, node *config.Node) error {
return errors.New("not implemented")
// CRI mocks base method.
func (m *Executor) CRI(ctx context.Context, node *config.Node) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "CRI", ctx, node)
ret0, _ := ret[0].(error)
return ret0
}
func (e *Executor) APIServerReadyChan() <-chan struct{} {
c := make(chan struct{})
close(c)
return c
// CRI indicates an expected call of CRI.
func (mr *ExecutorMockRecorder) CRI(ctx, node any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CRI", reflect.TypeOf((*Executor)(nil).CRI), ctx, node)
}
func (e *Executor) ETCDReadyChan() <-chan struct{} {
c := make(chan struct{})
close(c)
return c
// CRIReadyChan mocks base method.
func (m *Executor) CRIReadyChan() <-chan struct{} {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "CRIReadyChan")
ret0, _ := ret[0].(<-chan struct{})
return ret0
}
func (e *Executor) CRIReadyChan() <-chan struct{} {
c := make(chan struct{})
close(c)
return c
// CRIReadyChan indicates an expected call of CRIReadyChan.
func (mr *ExecutorMockRecorder) CRIReadyChan() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CRIReadyChan", reflect.TypeOf((*Executor)(nil).CRIReadyChan))
}
// CloudControllerManager mocks base method.
func (m *Executor) CloudControllerManager(ctx context.Context, ccmRBACReady <-chan struct{}, args []string) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "CloudControllerManager", ctx, ccmRBACReady, args)
ret0, _ := ret[0].(error)
return ret0
}
// CloudControllerManager indicates an expected call of CloudControllerManager.
func (mr *ExecutorMockRecorder) CloudControllerManager(ctx, ccmRBACReady, args any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CloudControllerManager", reflect.TypeOf((*Executor)(nil).CloudControllerManager), ctx, ccmRBACReady, args)
}
// Containerd mocks base method.
func (m *Executor) Containerd(ctx context.Context, node *config.Node) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Containerd", ctx, node)
ret0, _ := ret[0].(error)
return ret0
}
// Containerd indicates an expected call of Containerd.
func (mr *ExecutorMockRecorder) Containerd(ctx, node any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Containerd", reflect.TypeOf((*Executor)(nil).Containerd), ctx, node)
}
// ControllerManager mocks base method.
func (m *Executor) ControllerManager(ctx context.Context, args []string) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "ControllerManager", ctx, args)
ret0, _ := ret[0].(error)
return ret0
}
// ControllerManager indicates an expected call of ControllerManager.
func (mr *ExecutorMockRecorder) ControllerManager(ctx, args any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ControllerManager", reflect.TypeOf((*Executor)(nil).ControllerManager), ctx, args)
}
// CurrentETCDOptions mocks base method.
func (m *Executor) CurrentETCDOptions() (executor.InitialOptions, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "CurrentETCDOptions")
ret0, _ := ret[0].(executor.InitialOptions)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// CurrentETCDOptions indicates an expected call of CurrentETCDOptions.
func (mr *ExecutorMockRecorder) CurrentETCDOptions() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CurrentETCDOptions", reflect.TypeOf((*Executor)(nil).CurrentETCDOptions))
}
// Docker mocks base method.
func (m *Executor) Docker(ctx context.Context, node *config.Node) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Docker", ctx, node)
ret0, _ := ret[0].(error)
return ret0
}
// Docker indicates an expected call of Docker.
func (mr *ExecutorMockRecorder) Docker(ctx, node any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Docker", reflect.TypeOf((*Executor)(nil).Docker), ctx, node)
}
// ETCD mocks base method.
func (m *Executor) ETCD(ctx context.Context, args *executor.ETCDConfig, extraArgs []string, test executor.TestFunc) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "ETCD", ctx, args, extraArgs, test)
ret0, _ := ret[0].(error)
return ret0
}
// ETCD indicates an expected call of ETCD.
func (mr *ExecutorMockRecorder) ETCD(ctx, args, extraArgs, test any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ETCD", reflect.TypeOf((*Executor)(nil).ETCD), ctx, args, extraArgs, test)
}
// ETCDReadyChan mocks base method.
func (m *Executor) ETCDReadyChan() <-chan struct{} {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "ETCDReadyChan")
ret0, _ := ret[0].(<-chan struct{})
return ret0
}
// ETCDReadyChan indicates an expected call of ETCDReadyChan.
func (mr *ExecutorMockRecorder) ETCDReadyChan() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ETCDReadyChan", reflect.TypeOf((*Executor)(nil).ETCDReadyChan))
}
// KubeProxy mocks base method.
func (m *Executor) KubeProxy(ctx context.Context, args []string) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "KubeProxy", ctx, args)
ret0, _ := ret[0].(error)
return ret0
}
// KubeProxy indicates an expected call of KubeProxy.
func (mr *ExecutorMockRecorder) KubeProxy(ctx, args any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "KubeProxy", reflect.TypeOf((*Executor)(nil).KubeProxy), ctx, args)
}
// Kubelet mocks base method.
func (m *Executor) Kubelet(ctx context.Context, args []string) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Kubelet", ctx, args)
ret0, _ := ret[0].(error)
return ret0
}
// Kubelet indicates an expected call of Kubelet.
func (mr *ExecutorMockRecorder) Kubelet(ctx, args any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Kubelet", reflect.TypeOf((*Executor)(nil).Kubelet), ctx, args)
}
// Scheduler mocks base method.
func (m *Executor) Scheduler(ctx context.Context, nodeReady <-chan struct{}, args []string) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Scheduler", ctx, nodeReady, args)
ret0, _ := ret[0].(error)
return ret0
}
// Scheduler indicates an expected call of Scheduler.
func (mr *ExecutorMockRecorder) Scheduler(ctx, nodeReady, args any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Scheduler", reflect.TypeOf((*Executor)(nil).Scheduler), ctx, nodeReady, args)
}

View file

@ -0,0 +1,33 @@
package mock
import (
"testing"
executor "github.com/k3s-io/k3s/pkg/daemons/executor"
"go.uber.org/mock/gomock"
)
// NewExecutorWithEmbeddedETCD creates a new mock executor, and sets it as the current executor.
// The executor exepects calls to ETCD(), and wraps the embedded executor method of the same name.
// The various ready channels are also mocked with immediate channel closure.
func NewExecutorWithEmbeddedETCD(t *testing.T) {
mockController := gomock.NewController(t)
mockExecutor := NewExecutor(mockController)
embed := &executor.Embedded{}
initialOptions := func() (executor.InitialOptions, error) {
return executor.InitialOptions{}, nil
}
closedChannel := func() <-chan struct{} {
c := make(chan struct{})
close(c)
return c
}
mockExecutor.EXPECT().ETCD(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes().DoAndReturn(embed.ETCD)
mockExecutor.EXPECT().CurrentETCDOptions().AnyTimes().DoAndReturn(initialOptions)
mockExecutor.EXPECT().CRIReadyChan().AnyTimes().DoAndReturn(closedChannel)
mockExecutor.EXPECT().ETCDReadyChan().AnyTimes().DoAndReturn(closedChannel)
executor.Set(mockExecutor)
}

View file

@ -7,8 +7,6 @@ import (
"github.com/k3s-io/k3s/pkg/daemons/config"
"github.com/k3s-io/k3s/pkg/daemons/control/deps"
"github.com/k3s-io/k3s/pkg/daemons/executor"
"github.com/k3s-io/k3s/tests/mock"
)
// GenerateDataDir creates a temporary directory at "/tmp/k3s/<RANDOM_STRING>/".
@ -45,9 +43,6 @@ func CleanupDataDir(cnf *config.Control) {
// GenerateRuntime creates a temporary data dir and configures
// config.ControlRuntime with all the appropriate certificate keys.
func GenerateRuntime(cnf *config.Control) error {
// use mock executor that does not actually start things
executor.Set(&mock.Executor{})
// reuse ready channel from existing runtime if set
cnf.Runtime = config.NewRuntime()
if err := GenerateDataDir(cnf); err != nil {