diff --git a/pkg/registry/apis/dashboard/legacy/legacy_migrator_mock.go b/pkg/registry/apis/dashboard/legacy/legacy_migrator_mock.go new file mode 100644 index 00000000000..d576d333d43 --- /dev/null +++ b/pkg/registry/apis/dashboard/legacy/legacy_migrator_mock.go @@ -0,0 +1,96 @@ +// Code generated by mockery v2.52.4. DO NOT EDIT. + +package legacy + +import ( + context "context" + + resource "github.com/grafana/grafana/pkg/storage/unified/resource" + mock "github.com/stretchr/testify/mock" +) + +// MockLegacyMigrator is an autogenerated mock type for the LegacyMigrator type +type MockLegacyMigrator struct { + mock.Mock +} + +type MockLegacyMigrator_Expecter struct { + mock *mock.Mock +} + +func (_m *MockLegacyMigrator) EXPECT() *MockLegacyMigrator_Expecter { + return &MockLegacyMigrator_Expecter{mock: &_m.Mock} +} + +// Migrate provides a mock function with given fields: ctx, opts +func (_m *MockLegacyMigrator) Migrate(ctx context.Context, opts MigrateOptions) (*resource.BulkResponse, error) { + ret := _m.Called(ctx, opts) + + if len(ret) == 0 { + panic("no return value specified for Migrate") + } + + var r0 *resource.BulkResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, MigrateOptions) (*resource.BulkResponse, error)); ok { + return rf(ctx, opts) + } + if rf, ok := ret.Get(0).(func(context.Context, MigrateOptions) *resource.BulkResponse); ok { + r0 = rf(ctx, opts) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*resource.BulkResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, MigrateOptions) error); ok { + r1 = rf(ctx, opts) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockLegacyMigrator_Migrate_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Migrate' +type MockLegacyMigrator_Migrate_Call struct { + *mock.Call +} + +// Migrate is a helper method to define mock.On call +// - ctx context.Context +// - opts MigrateOptions +func (_e *MockLegacyMigrator_Expecter) Migrate(ctx interface{}, opts interface{}) *MockLegacyMigrator_Migrate_Call { + return &MockLegacyMigrator_Migrate_Call{Call: _e.mock.On("Migrate", ctx, opts)} +} + +func (_c *MockLegacyMigrator_Migrate_Call) Run(run func(ctx context.Context, opts MigrateOptions)) *MockLegacyMigrator_Migrate_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(MigrateOptions)) + }) + return _c +} + +func (_c *MockLegacyMigrator_Migrate_Call) Return(_a0 *resource.BulkResponse, _a1 error) *MockLegacyMigrator_Migrate_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockLegacyMigrator_Migrate_Call) RunAndReturn(run func(context.Context, MigrateOptions) (*resource.BulkResponse, error)) *MockLegacyMigrator_Migrate_Call { + _c.Call.Return(run) + return _c +} + +// NewMockLegacyMigrator creates a new instance of MockLegacyMigrator. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockLegacyMigrator(t interface { + mock.TestingT + Cleanup(func()) +}) *MockLegacyMigrator { + mock := &MockLegacyMigrator{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/registry/apis/dashboard/legacy/migrate.go b/pkg/registry/apis/dashboard/legacy/migrate.go index b393fe63e6f..26da721dada 100644 --- a/pkg/registry/apis/dashboard/legacy/migrate.go +++ b/pkg/registry/apis/dashboard/legacy/migrate.go @@ -35,6 +35,8 @@ type MigrateOptions struct { } // Read from legacy and write into unified storage +// +//go:generate mockery --name LegacyMigrator --structname MockLegacyMigrator --inpackage --filename legacy_migrator_mock.go --with-expecter type LegacyMigrator interface { Migrate(ctx context.Context, opts MigrateOptions) (*resource.BulkResponse, error) } diff --git a/pkg/registry/apis/provisioning/controller/finalizers.go b/pkg/registry/apis/provisioning/controller/finalizers.go index 1c0437d3fca..137bd9e7055 100644 --- a/pkg/registry/apis/provisioning/controller/finalizers.go +++ b/pkg/registry/apis/provisioning/controller/finalizers.go @@ -29,7 +29,7 @@ const CleanFinalizer = "cleanup" type finalizer struct { lister resources.ResourceLister - clientFactory *resources.ClientFactory + clientFactory resources.ClientFactory } func (f *finalizer) process(ctx context.Context, diff --git a/pkg/registry/apis/provisioning/controller/repository.go b/pkg/registry/apis/provisioning/controller/repository.go index 266d2ea278a..3274ed0928b 100644 --- a/pkg/registry/apis/provisioning/controller/repository.go +++ b/pkg/registry/apis/provisioning/controller/repository.go @@ -58,7 +58,7 @@ type RepositoryController struct { resourceLister resources.ResourceLister repoLister listers.RepositoryLister repoSynced cache.InformerSynced - parsers *resources.ParserFactory + parsers resources.ParserFactory logger logging.Logger secrets secrets.Service dualwrite dualwrite.Service @@ -83,7 +83,8 @@ func NewRepositoryController( repoInformer informer.RepositoryInformer, repoGetter RepoGetter, resourceLister resources.ResourceLister, - parsers *resources.ParserFactory, + parsers resources.ParserFactory, + clients resources.ClientFactory, tester RepositoryTester, jobs jobs.Queue, secrets secrets.Service, @@ -104,7 +105,7 @@ func NewRepositoryController( parsers: parsers, finalizer: &finalizer{ lister: resourceLister, - clientFactory: parsers.ClientFactory, + clientFactory: clients, }, tester: tester, jobs: jobs, diff --git a/pkg/registry/apis/provisioning/files.go b/pkg/registry/apis/provisioning/files.go index 89a00bd2781..e28c36547c1 100644 --- a/pkg/registry/apis/provisioning/files.go +++ b/pkg/registry/apis/provisioning/files.go @@ -24,7 +24,12 @@ const ( type filesConnector struct { getter RepoGetter - parsers *resources.ParserFactory + parsers resources.ParserFactory + clients resources.ClientFactory +} + +func NewFilesConnector(getter RepoGetter, parsers resources.ParserFactory, clients resources.ClientFactory) *filesConnector { + return &filesConnector{getter: getter, parsers: parsers, clients: clients} } func (*filesConnector) New() runtime.Object { @@ -70,7 +75,12 @@ func (s *filesConnector) Connect(ctx context.Context, name string, opts runtime. return nil, fmt.Errorf("failed to get parser: %w", err) } - folderClient, err := parser.Clients().Folder() + clients, err := s.clients.Clients(ctx, repo.Config().Namespace) + if err != nil { + return nil, fmt.Errorf("failed to get clients: %w", err) + } + + folderClient, err := clients.Folder() if err != nil { return nil, fmt.Errorf("failed to get folder client: %w", err) } diff --git a/pkg/registry/apis/provisioning/jobs/driver.go b/pkg/registry/apis/provisioning/jobs/driver.go index 885175b66f1..407b95bdce3 100644 --- a/pkg/registry/apis/provisioning/jobs/driver.go +++ b/pkg/registry/apis/provisioning/jobs/driver.go @@ -15,6 +15,8 @@ import ( // Store is an abstraction for the storage API. // This exists to allow for unit testing. +// +//go:generate mockery --name Store --structname MockStore --inpackage --filename store_mock.go --with-expecter type Store interface { // Claim takes a job from storage, marks it as ours, and returns it. // diff --git a/pkg/registry/apis/provisioning/jobs/export/worker.go b/pkg/registry/apis/provisioning/jobs/export/worker.go index 42049e4cb32..a6085a627f4 100644 --- a/pkg/registry/apis/provisioning/jobs/export/worker.go +++ b/pkg/registry/apis/provisioning/jobs/export/worker.go @@ -19,17 +19,18 @@ import ( type ExportWorker struct { // required to create clients - clientFactory *resources.ClientFactory + clientFactory resources.ClientFactory // Check where values are currently saved storageStatus dualwrite.Service - parsers *resources.ParserFactory + parsers resources.ParserFactory } -func NewExportWorker(clientFactory *resources.ClientFactory, +func NewExportWorker( + clientFactory resources.ClientFactory, storageStatus dualwrite.Service, - parsers *resources.ParserFactory, + parsers resources.ParserFactory, ) *ExportWorker { return &ExportWorker{ clientFactory, diff --git a/pkg/registry/apis/provisioning/jobs/history.go b/pkg/registry/apis/provisioning/jobs/history.go index b4ba6275901..e791143c533 100644 --- a/pkg/registry/apis/provisioning/jobs/history.go +++ b/pkg/registry/apis/provisioning/jobs/history.go @@ -15,6 +15,8 @@ import ( ) // History keeps track of completed jobs +// +//go:generate mockery --name History --structname MockHistory --inpackage --filename history_mock.go --with-expecter type History interface { // Adds a job to the history WriteJob(ctx context.Context, job *provisioning.Job) error diff --git a/pkg/registry/apis/provisioning/jobs/history_mock.go b/pkg/registry/apis/provisioning/jobs/history_mock.go new file mode 100644 index 00000000000..fd762e9f485 --- /dev/null +++ b/pkg/registry/apis/provisioning/jobs/history_mock.go @@ -0,0 +1,205 @@ +// Code generated by mockery v2.52.4. DO NOT EDIT. + +package jobs + +import ( + context "context" + + v0alpha1 "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1" + mock "github.com/stretchr/testify/mock" +) + +// MockHistory is an autogenerated mock type for the History type +type MockHistory struct { + mock.Mock +} + +type MockHistory_Expecter struct { + mock *mock.Mock +} + +func (_m *MockHistory) EXPECT() *MockHistory_Expecter { + return &MockHistory_Expecter{mock: &_m.Mock} +} + +// GetJob provides a mock function with given fields: ctx, namespace, repo, uid +func (_m *MockHistory) GetJob(ctx context.Context, namespace string, repo string, uid string) (*v0alpha1.Job, error) { + ret := _m.Called(ctx, namespace, repo, uid) + + if len(ret) == 0 { + panic("no return value specified for GetJob") + } + + var r0 *v0alpha1.Job + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string, string, string) (*v0alpha1.Job, error)); ok { + return rf(ctx, namespace, repo, uid) + } + if rf, ok := ret.Get(0).(func(context.Context, string, string, string) *v0alpha1.Job); ok { + r0 = rf(ctx, namespace, repo, uid) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*v0alpha1.Job) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, string, string, string) error); ok { + r1 = rf(ctx, namespace, repo, uid) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockHistory_GetJob_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetJob' +type MockHistory_GetJob_Call struct { + *mock.Call +} + +// GetJob is a helper method to define mock.On call +// - ctx context.Context +// - namespace string +// - repo string +// - uid string +func (_e *MockHistory_Expecter) GetJob(ctx interface{}, namespace interface{}, repo interface{}, uid interface{}) *MockHistory_GetJob_Call { + return &MockHistory_GetJob_Call{Call: _e.mock.On("GetJob", ctx, namespace, repo, uid)} +} + +func (_c *MockHistory_GetJob_Call) Run(run func(ctx context.Context, namespace string, repo string, uid string)) *MockHistory_GetJob_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(string), args[2].(string), args[3].(string)) + }) + return _c +} + +func (_c *MockHistory_GetJob_Call) Return(_a0 *v0alpha1.Job, _a1 error) *MockHistory_GetJob_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockHistory_GetJob_Call) RunAndReturn(run func(context.Context, string, string, string) (*v0alpha1.Job, error)) *MockHistory_GetJob_Call { + _c.Call.Return(run) + return _c +} + +// RecentJobs provides a mock function with given fields: ctx, namespace, repo +func (_m *MockHistory) RecentJobs(ctx context.Context, namespace string, repo string) (*v0alpha1.JobList, error) { + ret := _m.Called(ctx, namespace, repo) + + if len(ret) == 0 { + panic("no return value specified for RecentJobs") + } + + var r0 *v0alpha1.JobList + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string, string) (*v0alpha1.JobList, error)); ok { + return rf(ctx, namespace, repo) + } + if rf, ok := ret.Get(0).(func(context.Context, string, string) *v0alpha1.JobList); ok { + r0 = rf(ctx, namespace, repo) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*v0alpha1.JobList) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, string, string) error); ok { + r1 = rf(ctx, namespace, repo) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockHistory_RecentJobs_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RecentJobs' +type MockHistory_RecentJobs_Call struct { + *mock.Call +} + +// RecentJobs is a helper method to define mock.On call +// - ctx context.Context +// - namespace string +// - repo string +func (_e *MockHistory_Expecter) RecentJobs(ctx interface{}, namespace interface{}, repo interface{}) *MockHistory_RecentJobs_Call { + return &MockHistory_RecentJobs_Call{Call: _e.mock.On("RecentJobs", ctx, namespace, repo)} +} + +func (_c *MockHistory_RecentJobs_Call) Run(run func(ctx context.Context, namespace string, repo string)) *MockHistory_RecentJobs_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(string), args[2].(string)) + }) + return _c +} + +func (_c *MockHistory_RecentJobs_Call) Return(_a0 *v0alpha1.JobList, _a1 error) *MockHistory_RecentJobs_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockHistory_RecentJobs_Call) RunAndReturn(run func(context.Context, string, string) (*v0alpha1.JobList, error)) *MockHistory_RecentJobs_Call { + _c.Call.Return(run) + return _c +} + +// WriteJob provides a mock function with given fields: ctx, job +func (_m *MockHistory) WriteJob(ctx context.Context, job *v0alpha1.Job) error { + ret := _m.Called(ctx, job) + + if len(ret) == 0 { + panic("no return value specified for WriteJob") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, *v0alpha1.Job) error); ok { + r0 = rf(ctx, job) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockHistory_WriteJob_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WriteJob' +type MockHistory_WriteJob_Call struct { + *mock.Call +} + +// WriteJob is a helper method to define mock.On call +// - ctx context.Context +// - job *v0alpha1.Job +func (_e *MockHistory_Expecter) WriteJob(ctx interface{}, job interface{}) *MockHistory_WriteJob_Call { + return &MockHistory_WriteJob_Call{Call: _e.mock.On("WriteJob", ctx, job)} +} + +func (_c *MockHistory_WriteJob_Call) Run(run func(ctx context.Context, job *v0alpha1.Job)) *MockHistory_WriteJob_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*v0alpha1.Job)) + }) + return _c +} + +func (_c *MockHistory_WriteJob_Call) Return(_a0 error) *MockHistory_WriteJob_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockHistory_WriteJob_Call) RunAndReturn(run func(context.Context, *v0alpha1.Job) error) *MockHistory_WriteJob_Call { + _c.Call.Return(run) + return _c +} + +// NewMockHistory creates a new instance of MockHistory. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockHistory(t interface { + mock.TestingT + Cleanup(func()) +}) *MockHistory { + mock := &MockHistory{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/registry/apis/provisioning/jobs/job_progress_recorder_mock.go b/pkg/registry/apis/provisioning/jobs/job_progress_recorder_mock.go new file mode 100644 index 00000000000..9f69727655e --- /dev/null +++ b/pkg/registry/apis/provisioning/jobs/job_progress_recorder_mock.go @@ -0,0 +1,375 @@ +// Code generated by mockery v2.52.4. DO NOT EDIT. + +package jobs + +import ( + context "context" + + v0alpha1 "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1" + mock "github.com/stretchr/testify/mock" +) + +// MockJobProgressRecorder is an autogenerated mock type for the JobProgressRecorder type +type MockJobProgressRecorder struct { + mock.Mock +} + +type MockJobProgressRecorder_Expecter struct { + mock *mock.Mock +} + +func (_m *MockJobProgressRecorder) EXPECT() *MockJobProgressRecorder_Expecter { + return &MockJobProgressRecorder_Expecter{mock: &_m.Mock} +} + +// Complete provides a mock function with given fields: ctx, err +func (_m *MockJobProgressRecorder) Complete(ctx context.Context, err error) v0alpha1.JobStatus { + ret := _m.Called(ctx, err) + + if len(ret) == 0 { + panic("no return value specified for Complete") + } + + var r0 v0alpha1.JobStatus + if rf, ok := ret.Get(0).(func(context.Context, error) v0alpha1.JobStatus); ok { + r0 = rf(ctx, err) + } else { + r0 = ret.Get(0).(v0alpha1.JobStatus) + } + + return r0 +} + +// MockJobProgressRecorder_Complete_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Complete' +type MockJobProgressRecorder_Complete_Call struct { + *mock.Call +} + +// Complete is a helper method to define mock.On call +// - ctx context.Context +// - err error +func (_e *MockJobProgressRecorder_Expecter) Complete(ctx interface{}, err interface{}) *MockJobProgressRecorder_Complete_Call { + return &MockJobProgressRecorder_Complete_Call{Call: _e.mock.On("Complete", ctx, err)} +} + +func (_c *MockJobProgressRecorder_Complete_Call) Run(run func(ctx context.Context, err error)) *MockJobProgressRecorder_Complete_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(error)) + }) + return _c +} + +func (_c *MockJobProgressRecorder_Complete_Call) Return(_a0 v0alpha1.JobStatus) *MockJobProgressRecorder_Complete_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockJobProgressRecorder_Complete_Call) RunAndReturn(run func(context.Context, error) v0alpha1.JobStatus) *MockJobProgressRecorder_Complete_Call { + _c.Call.Return(run) + return _c +} + +// GetRef provides a mock function with no fields +func (_m *MockJobProgressRecorder) GetRef() string { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for GetRef") + } + + var r0 string + if rf, ok := ret.Get(0).(func() string); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(string) + } + + return r0 +} + +// MockJobProgressRecorder_GetRef_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetRef' +type MockJobProgressRecorder_GetRef_Call struct { + *mock.Call +} + +// GetRef is a helper method to define mock.On call +func (_e *MockJobProgressRecorder_Expecter) GetRef() *MockJobProgressRecorder_GetRef_Call { + return &MockJobProgressRecorder_GetRef_Call{Call: _e.mock.On("GetRef")} +} + +func (_c *MockJobProgressRecorder_GetRef_Call) Run(run func()) *MockJobProgressRecorder_GetRef_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockJobProgressRecorder_GetRef_Call) Return(_a0 string) *MockJobProgressRecorder_GetRef_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockJobProgressRecorder_GetRef_Call) RunAndReturn(run func() string) *MockJobProgressRecorder_GetRef_Call { + _c.Call.Return(run) + return _c +} + +// Record provides a mock function with given fields: ctx, result +func (_m *MockJobProgressRecorder) Record(ctx context.Context, result JobResourceResult) { + _m.Called(ctx, result) +} + +// MockJobProgressRecorder_Record_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Record' +type MockJobProgressRecorder_Record_Call struct { + *mock.Call +} + +// Record is a helper method to define mock.On call +// - ctx context.Context +// - result JobResourceResult +func (_e *MockJobProgressRecorder_Expecter) Record(ctx interface{}, result interface{}) *MockJobProgressRecorder_Record_Call { + return &MockJobProgressRecorder_Record_Call{Call: _e.mock.On("Record", ctx, result)} +} + +func (_c *MockJobProgressRecorder_Record_Call) Run(run func(ctx context.Context, result JobResourceResult)) *MockJobProgressRecorder_Record_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(JobResourceResult)) + }) + return _c +} + +func (_c *MockJobProgressRecorder_Record_Call) Return() *MockJobProgressRecorder_Record_Call { + _c.Call.Return() + return _c +} + +func (_c *MockJobProgressRecorder_Record_Call) RunAndReturn(run func(context.Context, JobResourceResult)) *MockJobProgressRecorder_Record_Call { + _c.Run(run) + return _c +} + +// ResetResults provides a mock function with no fields +func (_m *MockJobProgressRecorder) ResetResults() { + _m.Called() +} + +// MockJobProgressRecorder_ResetResults_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ResetResults' +type MockJobProgressRecorder_ResetResults_Call struct { + *mock.Call +} + +// ResetResults is a helper method to define mock.On call +func (_e *MockJobProgressRecorder_Expecter) ResetResults() *MockJobProgressRecorder_ResetResults_Call { + return &MockJobProgressRecorder_ResetResults_Call{Call: _e.mock.On("ResetResults")} +} + +func (_c *MockJobProgressRecorder_ResetResults_Call) Run(run func()) *MockJobProgressRecorder_ResetResults_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockJobProgressRecorder_ResetResults_Call) Return() *MockJobProgressRecorder_ResetResults_Call { + _c.Call.Return() + return _c +} + +func (_c *MockJobProgressRecorder_ResetResults_Call) RunAndReturn(run func()) *MockJobProgressRecorder_ResetResults_Call { + _c.Run(run) + return _c +} + +// SetFinalMessage provides a mock function with given fields: ctx, msg +func (_m *MockJobProgressRecorder) SetFinalMessage(ctx context.Context, msg string) { + _m.Called(ctx, msg) +} + +// MockJobProgressRecorder_SetFinalMessage_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetFinalMessage' +type MockJobProgressRecorder_SetFinalMessage_Call struct { + *mock.Call +} + +// SetFinalMessage is a helper method to define mock.On call +// - ctx context.Context +// - msg string +func (_e *MockJobProgressRecorder_Expecter) SetFinalMessage(ctx interface{}, msg interface{}) *MockJobProgressRecorder_SetFinalMessage_Call { + return &MockJobProgressRecorder_SetFinalMessage_Call{Call: _e.mock.On("SetFinalMessage", ctx, msg)} +} + +func (_c *MockJobProgressRecorder_SetFinalMessage_Call) Run(run func(ctx context.Context, msg string)) *MockJobProgressRecorder_SetFinalMessage_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(string)) + }) + return _c +} + +func (_c *MockJobProgressRecorder_SetFinalMessage_Call) Return() *MockJobProgressRecorder_SetFinalMessage_Call { + _c.Call.Return() + return _c +} + +func (_c *MockJobProgressRecorder_SetFinalMessage_Call) RunAndReturn(run func(context.Context, string)) *MockJobProgressRecorder_SetFinalMessage_Call { + _c.Run(run) + return _c +} + +// SetMessage provides a mock function with given fields: ctx, msg +func (_m *MockJobProgressRecorder) SetMessage(ctx context.Context, msg string) { + _m.Called(ctx, msg) +} + +// MockJobProgressRecorder_SetMessage_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetMessage' +type MockJobProgressRecorder_SetMessage_Call struct { + *mock.Call +} + +// SetMessage is a helper method to define mock.On call +// - ctx context.Context +// - msg string +func (_e *MockJobProgressRecorder_Expecter) SetMessage(ctx interface{}, msg interface{}) *MockJobProgressRecorder_SetMessage_Call { + return &MockJobProgressRecorder_SetMessage_Call{Call: _e.mock.On("SetMessage", ctx, msg)} +} + +func (_c *MockJobProgressRecorder_SetMessage_Call) Run(run func(ctx context.Context, msg string)) *MockJobProgressRecorder_SetMessage_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(string)) + }) + return _c +} + +func (_c *MockJobProgressRecorder_SetMessage_Call) Return() *MockJobProgressRecorder_SetMessage_Call { + _c.Call.Return() + return _c +} + +func (_c *MockJobProgressRecorder_SetMessage_Call) RunAndReturn(run func(context.Context, string)) *MockJobProgressRecorder_SetMessage_Call { + _c.Run(run) + return _c +} + +// SetRef provides a mock function with given fields: ref +func (_m *MockJobProgressRecorder) SetRef(ref string) { + _m.Called(ref) +} + +// MockJobProgressRecorder_SetRef_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetRef' +type MockJobProgressRecorder_SetRef_Call struct { + *mock.Call +} + +// SetRef is a helper method to define mock.On call +// - ref string +func (_e *MockJobProgressRecorder_Expecter) SetRef(ref interface{}) *MockJobProgressRecorder_SetRef_Call { + return &MockJobProgressRecorder_SetRef_Call{Call: _e.mock.On("SetRef", ref)} +} + +func (_c *MockJobProgressRecorder_SetRef_Call) Run(run func(ref string)) *MockJobProgressRecorder_SetRef_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string)) + }) + return _c +} + +func (_c *MockJobProgressRecorder_SetRef_Call) Return() *MockJobProgressRecorder_SetRef_Call { + _c.Call.Return() + return _c +} + +func (_c *MockJobProgressRecorder_SetRef_Call) RunAndReturn(run func(string)) *MockJobProgressRecorder_SetRef_Call { + _c.Run(run) + return _c +} + +// SetTotal provides a mock function with given fields: ctx, total +func (_m *MockJobProgressRecorder) SetTotal(ctx context.Context, total int) { + _m.Called(ctx, total) +} + +// MockJobProgressRecorder_SetTotal_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetTotal' +type MockJobProgressRecorder_SetTotal_Call struct { + *mock.Call +} + +// SetTotal is a helper method to define mock.On call +// - ctx context.Context +// - total int +func (_e *MockJobProgressRecorder_Expecter) SetTotal(ctx interface{}, total interface{}) *MockJobProgressRecorder_SetTotal_Call { + return &MockJobProgressRecorder_SetTotal_Call{Call: _e.mock.On("SetTotal", ctx, total)} +} + +func (_c *MockJobProgressRecorder_SetTotal_Call) Run(run func(ctx context.Context, total int)) *MockJobProgressRecorder_SetTotal_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(int)) + }) + return _c +} + +func (_c *MockJobProgressRecorder_SetTotal_Call) Return() *MockJobProgressRecorder_SetTotal_Call { + _c.Call.Return() + return _c +} + +func (_c *MockJobProgressRecorder_SetTotal_Call) RunAndReturn(run func(context.Context, int)) *MockJobProgressRecorder_SetTotal_Call { + _c.Run(run) + return _c +} + +// TooManyErrors provides a mock function with no fields +func (_m *MockJobProgressRecorder) TooManyErrors() error { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for TooManyErrors") + } + + var r0 error + if rf, ok := ret.Get(0).(func() error); ok { + r0 = rf() + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockJobProgressRecorder_TooManyErrors_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'TooManyErrors' +type MockJobProgressRecorder_TooManyErrors_Call struct { + *mock.Call +} + +// TooManyErrors is a helper method to define mock.On call +func (_e *MockJobProgressRecorder_Expecter) TooManyErrors() *MockJobProgressRecorder_TooManyErrors_Call { + return &MockJobProgressRecorder_TooManyErrors_Call{Call: _e.mock.On("TooManyErrors")} +} + +func (_c *MockJobProgressRecorder_TooManyErrors_Call) Run(run func()) *MockJobProgressRecorder_TooManyErrors_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockJobProgressRecorder_TooManyErrors_Call) Return(_a0 error) *MockJobProgressRecorder_TooManyErrors_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockJobProgressRecorder_TooManyErrors_Call) RunAndReturn(run func() error) *MockJobProgressRecorder_TooManyErrors_Call { + _c.Call.Return(run) + return _c +} + +// NewMockJobProgressRecorder creates a new instance of MockJobProgressRecorder. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockJobProgressRecorder(t interface { + mock.TestingT + Cleanup(func()) +}) *MockJobProgressRecorder { + mock := &MockJobProgressRecorder{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/registry/apis/provisioning/jobs/migrate/folders.go b/pkg/registry/apis/provisioning/jobs/migrate/folders.go index 96a2dfc32ac..1ca69cddaa5 100644 --- a/pkg/registry/apis/provisioning/jobs/migrate/folders.go +++ b/pkg/registry/apis/provisioning/jobs/migrate/folders.go @@ -19,7 +19,7 @@ const maxFolders = 10000 var _ resource.BulkResourceWriter = (*legacyFolderReader)(nil) type legacyFolderReader struct { - tree *resources.FolderTree + tree resources.FolderTree repoName string legacyMigrator legacy.LegacyMigrator namespace string @@ -68,6 +68,6 @@ func (f *legacyFolderReader) Read(ctx context.Context, legacyMigrator legacy.Leg return err } -func (f *legacyFolderReader) Tree() *resources.FolderTree { +func (f *legacyFolderReader) Tree() resources.FolderTree { return f.tree } diff --git a/pkg/registry/apis/provisioning/jobs/migrate/resources.go b/pkg/registry/apis/provisioning/jobs/migrate/resources.go index e752d785279..136342e48fd 100644 --- a/pkg/registry/apis/provisioning/jobs/migrate/resources.go +++ b/pkg/registry/apis/provisioning/jobs/migrate/resources.go @@ -21,7 +21,7 @@ var _ resource.BulkResourceWriter = (*legacyResourceResourceMigrator)(nil) // TODO: can we use the same migrator for folders? type legacyResourceResourceMigrator struct { legacy legacy.LegacyMigrator - parser *resources.Parser + parser resources.Parser progress jobs.JobProgressRecorder namespace string kind schema.GroupResource @@ -29,7 +29,7 @@ type legacyResourceResourceMigrator struct { resources *resources.ResourcesManager } -func NewLegacyResourceMigrator(legacy legacy.LegacyMigrator, parser *resources.Parser, resources *resources.ResourcesManager, progress jobs.JobProgressRecorder, options provisioning.MigrateJobOptions, namespace string, kind schema.GroupResource) *legacyResourceResourceMigrator { +func NewLegacyResourceMigrator(legacy legacy.LegacyMigrator, parser resources.Parser, resources *resources.ResourcesManager, progress jobs.JobProgressRecorder, options provisioning.MigrateJobOptions, namespace string, kind schema.GroupResource) *legacyResourceResourceMigrator { return &legacyResourceResourceMigrator{ legacy: legacy, parser: parser, diff --git a/pkg/registry/apis/provisioning/jobs/migrate/users.go b/pkg/registry/apis/provisioning/jobs/migrate/users.go index cb023255a2b..223b0e98bb8 100644 --- a/pkg/registry/apis/provisioning/jobs/migrate/users.go +++ b/pkg/registry/apis/provisioning/jobs/migrate/users.go @@ -13,8 +13,8 @@ import ( const maxUsers = 10000 -func loadUsers(ctx context.Context, parser *resources.Parser) (map[string]repository.CommitSignature, error) { - client, err := parser.Clients().User() +func loadUsers(ctx context.Context, clients resources.ResourceClients) (map[string]repository.CommitSignature, error) { + client, err := clients.User() if err != nil { return nil, err } diff --git a/pkg/registry/apis/provisioning/jobs/migrate/worker.go b/pkg/registry/apis/provisioning/jobs/migrate/worker.go index 07deef86114..7bb01e67ddc 100644 --- a/pkg/registry/apis/provisioning/jobs/migrate/worker.go +++ b/pkg/registry/apis/provisioning/jobs/migrate/worker.go @@ -15,8 +15,6 @@ import ( provisioning "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1" "github.com/grafana/grafana/pkg/registry/apis/dashboard/legacy" "github.com/grafana/grafana/pkg/registry/apis/provisioning/jobs" - "github.com/grafana/grafana/pkg/registry/apis/provisioning/jobs/export" - "github.com/grafana/grafana/pkg/registry/apis/provisioning/jobs/sync" "github.com/grafana/grafana/pkg/registry/apis/provisioning/repository" "github.com/grafana/grafana/pkg/registry/apis/provisioning/resources" "github.com/grafana/grafana/pkg/storage/legacysql/dualwrite" @@ -25,7 +23,9 @@ import ( type MigrationWorker struct { // temporary... while we still do an import - parsers *resources.ParserFactory + parsers resources.ParserFactory + + clients resources.ClientFactory // Check where values are currently saved storageStatus dualwrite.Service @@ -37,22 +37,24 @@ type MigrationWorker struct { bulk resource.BulkStoreClient // Delegate the export to the export worker - exportWorker *export.ExportWorker + exportWorker jobs.Worker // Delegate the import to sync worker - syncWorker *sync.SyncWorker + syncWorker jobs.Worker } func NewMigrationWorker( legacyMigrator legacy.LegacyMigrator, - parsers *resources.ParserFactory, // should not be necessary! + parsers resources.ParserFactory, // should not be necessary! + clients resources.ClientFactory, storageStatus dualwrite.Service, batch resource.BulkStoreClient, - exportWorker *export.ExportWorker, - syncWorker *sync.SyncWorker, + exportWorker jobs.Worker, + syncWorker jobs.Worker, ) *MigrationWorker { return &MigrationWorker{ parsers, + clients, storageStatus, legacyMigrator, batch, @@ -82,15 +84,20 @@ func (w *MigrationWorker) Process(ctx context.Context, repo repository.Repositor return fmt.Errorf("error getting parser: %w", err) } - if dualwrite.IsReadingLegacyDashboardsAndFolders(ctx, w.storageStatus) { - return w.migrateFromLegacy(ctx, rw, parser, *options, progress) + clients, err := w.clients.Clients(ctx, rw.Config().Namespace) + if err != nil { + return fmt.Errorf("error getting clients: %w", err) } - return w.migrateFromAPIServer(ctx, rw, parser, *options, progress) + if dualwrite.IsReadingLegacyDashboardsAndFolders(ctx, w.storageStatus) { + return w.migrateFromLegacy(ctx, rw, parser, clients, *options, progress) + } + + return w.migrateFromAPIServer(ctx, rw, clients, *options, progress) } // migrateFromLegacy will export the resources from legacy storage and import them into the target repository -func (w *MigrationWorker) migrateFromLegacy(ctx context.Context, rw repository.ReaderWriter, parser *resources.Parser, options provisioning.MigrateJobOptions, progress jobs.JobProgressRecorder) error { +func (w *MigrationWorker) migrateFromLegacy(ctx context.Context, rw repository.ReaderWriter, parser resources.Parser, clients resources.ResourceClients, options provisioning.MigrateJobOptions, progress jobs.JobProgressRecorder) error { var ( err error clone repository.ClonedRepository @@ -128,7 +135,7 @@ func (w *MigrationWorker) migrateFromLegacy(ctx context.Context, rw repository.R var userInfo map[string]repository.CommitSignature if options.History { progress.SetMessage(ctx, "loading users") - userInfo, err = loadUsers(ctx, parser) + userInfo, err = loadUsers(ctx, clients) if err != nil { return fmt.Errorf("error loading users: %w", err) } @@ -141,7 +148,7 @@ func (w *MigrationWorker) migrateFromLegacy(ctx context.Context, rw repository.R return fmt.Errorf("error loading folder tree: %w", err) } - folderClient, err := parser.Clients().Folder() + folderClient, err := clients.Folder() if err != nil { return fmt.Errorf("error getting folder client: %w", err) } @@ -170,7 +177,7 @@ func (w *MigrationWorker) migrateFromLegacy(ctx context.Context, rw repository.R } progress.SetMessage(ctx, "exporting legacy resources") - resourceManager := resources.NewResourcesManager(rw, folders, parser, parser.Clients(), userInfo) + resourceManager := resources.NewResourcesManager(rw, folders, parser, clients, userInfo) for _, kind := range resources.SupportedProvisioningResources { if kind == resources.FolderResource { continue @@ -230,7 +237,7 @@ func (w *MigrationWorker) migrateFromLegacy(ctx context.Context, rw repository.R } // migrateFromAPIServer will export the resources from unified storage and import them into the target repository -func (w *MigrationWorker) migrateFromAPIServer(ctx context.Context, repo repository.ReaderWriter, parser *resources.Parser, options provisioning.MigrateJobOptions, progress jobs.JobProgressRecorder) error { +func (w *MigrationWorker) migrateFromAPIServer(ctx context.Context, repo repository.ReaderWriter, clients resources.ResourceClients, options provisioning.MigrateJobOptions, progress jobs.JobProgressRecorder) error { progress.SetMessage(ctx, "exporting unified storage resources") exportJob := provisioning.Job{ Spec: provisioning.JobSpec{ @@ -259,7 +266,7 @@ func (w *MigrationWorker) migrateFromAPIServer(ctx context.Context, repo reposit for _, kind := range resources.SupportedProvisioningResources { progress.SetMessage(ctx, fmt.Sprintf("removing unprovisioned %s", kind.Resource)) - client, _, err := parser.Clients().ForResource(kind) + client, _, err := clients.ForResource(kind) if err != nil { return err } diff --git a/pkg/registry/apis/provisioning/jobs/persistentstore.go b/pkg/registry/apis/provisioning/jobs/persistentstore.go index 964625e9bf0..66b76a078d8 100644 --- a/pkg/registry/apis/provisioning/jobs/persistentstore.go +++ b/pkg/registry/apis/provisioning/jobs/persistentstore.go @@ -55,6 +55,9 @@ var ( } ) +// Queue is a job queue abstraction. +// +//go:generate mockery --name Queue --structname MockQueue --inpackage --filename queue_mock.go --with-expecter type Queue interface { // Insert adds a new job to the queue. // diff --git a/pkg/registry/apis/provisioning/jobs/progress_fn_mock.go b/pkg/registry/apis/provisioning/jobs/progress_fn_mock.go new file mode 100644 index 00000000000..fd634d60844 --- /dev/null +++ b/pkg/registry/apis/provisioning/jobs/progress_fn_mock.go @@ -0,0 +1,84 @@ +// Code generated by mockery v2.52.4. DO NOT EDIT. + +package jobs + +import ( + context "context" + + v0alpha1 "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1" + mock "github.com/stretchr/testify/mock" +) + +// MockProgressFn is an autogenerated mock type for the ProgressFn type +type MockProgressFn struct { + mock.Mock +} + +type MockProgressFn_Expecter struct { + mock *mock.Mock +} + +func (_m *MockProgressFn) EXPECT() *MockProgressFn_Expecter { + return &MockProgressFn_Expecter{mock: &_m.Mock} +} + +// Execute provides a mock function with given fields: ctx, status +func (_m *MockProgressFn) Execute(ctx context.Context, status v0alpha1.JobStatus) error { + ret := _m.Called(ctx, status) + + if len(ret) == 0 { + panic("no return value specified for Execute") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, v0alpha1.JobStatus) error); ok { + r0 = rf(ctx, status) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockProgressFn_Execute_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Execute' +type MockProgressFn_Execute_Call struct { + *mock.Call +} + +// Execute is a helper method to define mock.On call +// - ctx context.Context +// - status v0alpha1.JobStatus +func (_e *MockProgressFn_Expecter) Execute(ctx interface{}, status interface{}) *MockProgressFn_Execute_Call { + return &MockProgressFn_Execute_Call{Call: _e.mock.On("Execute", ctx, status)} +} + +func (_c *MockProgressFn_Execute_Call) Run(run func(ctx context.Context, status v0alpha1.JobStatus)) *MockProgressFn_Execute_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(v0alpha1.JobStatus)) + }) + return _c +} + +func (_c *MockProgressFn_Execute_Call) Return(_a0 error) *MockProgressFn_Execute_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockProgressFn_Execute_Call) RunAndReturn(run func(context.Context, v0alpha1.JobStatus) error) *MockProgressFn_Execute_Call { + _c.Call.Return(run) + return _c +} + +// NewMockProgressFn creates a new instance of MockProgressFn. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockProgressFn(t interface { + mock.TestingT + Cleanup(func()) +}) *MockProgressFn { + mock := &MockProgressFn{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/registry/apis/provisioning/jobs/pullrequest/preview.go b/pkg/registry/apis/provisioning/jobs/pullrequest/preview.go index 4711a52963f..7a124f384cc 100644 --- a/pkg/registry/apis/provisioning/jobs/pullrequest/preview.go +++ b/pkg/registry/apis/provisioning/jobs/pullrequest/preview.go @@ -50,19 +50,29 @@ See the [preview]({{.PreviewURL}}) of {{.Filename}}. {{- end}}` // PreviewRenderer is an interface for rendering a preview of a file +// +//go:generate mockery --name PreviewRenderer --structname MockPreviewRenderer --inpackage --filename preview_renderer_mock.go --with-expecter type PreviewRenderer interface { IsAvailable(ctx context.Context) bool RenderDashboardPreview(ctx context.Context, namespace, repoName, path, ref string) (string, error) } -type Previewer struct { +// Previewer is a service for previewing dashboard changes in a pull request +// +//go:generate mockery --name Previewer --structname MockPreviewer --inpackage --filename previewer_mock.go --with-expecter +type Previewer interface { + Preview(ctx context.Context, f repository.VersionedFileChange, namespace, repoName, base, ref, pullRequestURL string, generatePreview bool) (resourcePreview, error) + GenerateComment(preview resourcePreview) (string, error) +} + +type previewer struct { template *template.Template urlProvider func(namespace string) string renderer PreviewRenderer } -func NewPreviewer(renderer PreviewRenderer, urlProvider func(namespace string) string) *Previewer { - return &Previewer{ +func NewPreviewer(renderer PreviewRenderer, urlProvider func(namespace string) string) *previewer { + return &previewer{ template: template.Must(template.New("comment").Parse(previewsCommentTemplate)), urlProvider: urlProvider, renderer: renderer, @@ -70,7 +80,7 @@ func NewPreviewer(renderer PreviewRenderer, urlProvider func(namespace string) s } // GenerateComment creates a formatted comment for dashboard previews -func (p *Previewer) GenerateComment(preview resourcePreview) (string, error) { +func (p *previewer) GenerateComment(preview resourcePreview) (string, error) { var buf bytes.Buffer if err := p.template.Execute(&buf, preview); err != nil { return "", fmt.Errorf("execute previews comment template: %w", err) @@ -79,7 +89,7 @@ func (p *Previewer) GenerateComment(preview resourcePreview) (string, error) { } // getOriginalURL returns the URL for the original version of the file based on the action -func (p *Previewer) getOriginalURL(ctx context.Context, f repository.VersionedFileChange, baseURL *url.URL, repoName, base, pullRequestURL string) string { +func (p *previewer) getOriginalURL(ctx context.Context, f repository.VersionedFileChange, baseURL *url.URL, repoName, base, pullRequestURL string) string { switch f.Action { case repository.FileActionCreated: return "" // No original URL for new files @@ -96,7 +106,7 @@ func (p *Previewer) getOriginalURL(ctx context.Context, f repository.VersionedFi } // getPreviewURL returns the URL for the preview version of the file based on the action -func (p *Previewer) getPreviewURL(ctx context.Context, f repository.VersionedFileChange, baseURL *url.URL, repoName, ref, pullRequestURL string) string { +func (p *previewer) getPreviewURL(ctx context.Context, f repository.VersionedFileChange, baseURL *url.URL, repoName, ref, pullRequestURL string) string { switch f.Action { case repository.FileActionCreated, repository.FileActionUpdated, repository.FileActionRenamed: return p.previewURL(baseURL, repoName, ref, f.Path, pullRequestURL) @@ -109,7 +119,7 @@ func (p *Previewer) getPreviewURL(ctx context.Context, f repository.VersionedFil } // previewURL returns the URL to preview the file in Grafana -func (p *Previewer) previewURL(u *url.URL, repoName, ref, filePath, pullRequestURL string) string { +func (p *previewer) previewURL(u *url.URL, repoName, ref, filePath, pullRequestURL string) string { baseURL := *u baseURL = *baseURL.JoinPath("/admin/provisioning", repoName, "dashboard/preview", filePath) @@ -126,7 +136,7 @@ func (p *Previewer) previewURL(u *url.URL, repoName, ref, filePath, pullRequestU } // Preview creates a preview for a single file change -func (p *Previewer) Preview( +func (p *previewer) Preview( ctx context.Context, f repository.VersionedFileChange, namespace string, diff --git a/pkg/registry/apis/provisioning/jobs/pullrequest/preview_renderer_mock.go b/pkg/registry/apis/provisioning/jobs/pullrequest/preview_renderer_mock.go new file mode 100644 index 00000000000..529430cc72c --- /dev/null +++ b/pkg/registry/apis/provisioning/jobs/pullrequest/preview_renderer_mock.go @@ -0,0 +1,142 @@ +// Code generated by mockery v2.52.4. DO NOT EDIT. + +package pullrequest + +import ( + context "context" + + mock "github.com/stretchr/testify/mock" +) + +// MockPreviewRenderer is an autogenerated mock type for the PreviewRenderer type +type MockPreviewRenderer struct { + mock.Mock +} + +type MockPreviewRenderer_Expecter struct { + mock *mock.Mock +} + +func (_m *MockPreviewRenderer) EXPECT() *MockPreviewRenderer_Expecter { + return &MockPreviewRenderer_Expecter{mock: &_m.Mock} +} + +// IsAvailable provides a mock function with given fields: ctx +func (_m *MockPreviewRenderer) IsAvailable(ctx context.Context) bool { + ret := _m.Called(ctx) + + if len(ret) == 0 { + panic("no return value specified for IsAvailable") + } + + var r0 bool + if rf, ok := ret.Get(0).(func(context.Context) bool); ok { + r0 = rf(ctx) + } else { + r0 = ret.Get(0).(bool) + } + + return r0 +} + +// MockPreviewRenderer_IsAvailable_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'IsAvailable' +type MockPreviewRenderer_IsAvailable_Call struct { + *mock.Call +} + +// IsAvailable is a helper method to define mock.On call +// - ctx context.Context +func (_e *MockPreviewRenderer_Expecter) IsAvailable(ctx interface{}) *MockPreviewRenderer_IsAvailable_Call { + return &MockPreviewRenderer_IsAvailable_Call{Call: _e.mock.On("IsAvailable", ctx)} +} + +func (_c *MockPreviewRenderer_IsAvailable_Call) Run(run func(ctx context.Context)) *MockPreviewRenderer_IsAvailable_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context)) + }) + return _c +} + +func (_c *MockPreviewRenderer_IsAvailable_Call) Return(_a0 bool) *MockPreviewRenderer_IsAvailable_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockPreviewRenderer_IsAvailable_Call) RunAndReturn(run func(context.Context) bool) *MockPreviewRenderer_IsAvailable_Call { + _c.Call.Return(run) + return _c +} + +// RenderDashboardPreview provides a mock function with given fields: ctx, namespace, repoName, path, ref +func (_m *MockPreviewRenderer) RenderDashboardPreview(ctx context.Context, namespace string, repoName string, path string, ref string) (string, error) { + ret := _m.Called(ctx, namespace, repoName, path, ref) + + if len(ret) == 0 { + panic("no return value specified for RenderDashboardPreview") + } + + var r0 string + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string, string, string, string) (string, error)); ok { + return rf(ctx, namespace, repoName, path, ref) + } + if rf, ok := ret.Get(0).(func(context.Context, string, string, string, string) string); ok { + r0 = rf(ctx, namespace, repoName, path, ref) + } else { + r0 = ret.Get(0).(string) + } + + if rf, ok := ret.Get(1).(func(context.Context, string, string, string, string) error); ok { + r1 = rf(ctx, namespace, repoName, path, ref) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockPreviewRenderer_RenderDashboardPreview_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RenderDashboardPreview' +type MockPreviewRenderer_RenderDashboardPreview_Call struct { + *mock.Call +} + +// RenderDashboardPreview is a helper method to define mock.On call +// - ctx context.Context +// - namespace string +// - repoName string +// - path string +// - ref string +func (_e *MockPreviewRenderer_Expecter) RenderDashboardPreview(ctx interface{}, namespace interface{}, repoName interface{}, path interface{}, ref interface{}) *MockPreviewRenderer_RenderDashboardPreview_Call { + return &MockPreviewRenderer_RenderDashboardPreview_Call{Call: _e.mock.On("RenderDashboardPreview", ctx, namespace, repoName, path, ref)} +} + +func (_c *MockPreviewRenderer_RenderDashboardPreview_Call) Run(run func(ctx context.Context, namespace string, repoName string, path string, ref string)) *MockPreviewRenderer_RenderDashboardPreview_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(string), args[2].(string), args[3].(string), args[4].(string)) + }) + return _c +} + +func (_c *MockPreviewRenderer_RenderDashboardPreview_Call) Return(_a0 string, _a1 error) *MockPreviewRenderer_RenderDashboardPreview_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockPreviewRenderer_RenderDashboardPreview_Call) RunAndReturn(run func(context.Context, string, string, string, string) (string, error)) *MockPreviewRenderer_RenderDashboardPreview_Call { + _c.Call.Return(run) + return _c +} + +// NewMockPreviewRenderer creates a new instance of MockPreviewRenderer. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockPreviewRenderer(t interface { + mock.TestingT + Cleanup(func()) +}) *MockPreviewRenderer { + mock := &MockPreviewRenderer{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/registry/apis/provisioning/jobs/pullrequest/previewer_mock.go b/pkg/registry/apis/provisioning/jobs/pullrequest/previewer_mock.go new file mode 100644 index 00000000000..e8e8aedcdab --- /dev/null +++ b/pkg/registry/apis/provisioning/jobs/pullrequest/previewer_mock.go @@ -0,0 +1,156 @@ +// Code generated by mockery v2.52.4. DO NOT EDIT. + +package pullrequest + +import ( + context "context" + + repository "github.com/grafana/grafana/pkg/registry/apis/provisioning/repository" + mock "github.com/stretchr/testify/mock" +) + +// MockPreviewer is an autogenerated mock type for the Previewer type +type MockPreviewer struct { + mock.Mock +} + +type MockPreviewer_Expecter struct { + mock *mock.Mock +} + +func (_m *MockPreviewer) EXPECT() *MockPreviewer_Expecter { + return &MockPreviewer_Expecter{mock: &_m.Mock} +} + +// GenerateComment provides a mock function with given fields: preview +func (_m *MockPreviewer) GenerateComment(preview resourcePreview) (string, error) { + ret := _m.Called(preview) + + if len(ret) == 0 { + panic("no return value specified for GenerateComment") + } + + var r0 string + var r1 error + if rf, ok := ret.Get(0).(func(resourcePreview) (string, error)); ok { + return rf(preview) + } + if rf, ok := ret.Get(0).(func(resourcePreview) string); ok { + r0 = rf(preview) + } else { + r0 = ret.Get(0).(string) + } + + if rf, ok := ret.Get(1).(func(resourcePreview) error); ok { + r1 = rf(preview) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockPreviewer_GenerateComment_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GenerateComment' +type MockPreviewer_GenerateComment_Call struct { + *mock.Call +} + +// GenerateComment is a helper method to define mock.On call +// - preview resourcePreview +func (_e *MockPreviewer_Expecter) GenerateComment(preview interface{}) *MockPreviewer_GenerateComment_Call { + return &MockPreviewer_GenerateComment_Call{Call: _e.mock.On("GenerateComment", preview)} +} + +func (_c *MockPreviewer_GenerateComment_Call) Run(run func(preview resourcePreview)) *MockPreviewer_GenerateComment_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(resourcePreview)) + }) + return _c +} + +func (_c *MockPreviewer_GenerateComment_Call) Return(_a0 string, _a1 error) *MockPreviewer_GenerateComment_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockPreviewer_GenerateComment_Call) RunAndReturn(run func(resourcePreview) (string, error)) *MockPreviewer_GenerateComment_Call { + _c.Call.Return(run) + return _c +} + +// Preview provides a mock function with given fields: ctx, f, namespace, repoName, base, ref, pullRequestURL, generatePreview +func (_m *MockPreviewer) Preview(ctx context.Context, f repository.VersionedFileChange, namespace string, repoName string, base string, ref string, pullRequestURL string, generatePreview bool) (resourcePreview, error) { + ret := _m.Called(ctx, f, namespace, repoName, base, ref, pullRequestURL, generatePreview) + + if len(ret) == 0 { + panic("no return value specified for Preview") + } + + var r0 resourcePreview + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, repository.VersionedFileChange, string, string, string, string, string, bool) (resourcePreview, error)); ok { + return rf(ctx, f, namespace, repoName, base, ref, pullRequestURL, generatePreview) + } + if rf, ok := ret.Get(0).(func(context.Context, repository.VersionedFileChange, string, string, string, string, string, bool) resourcePreview); ok { + r0 = rf(ctx, f, namespace, repoName, base, ref, pullRequestURL, generatePreview) + } else { + r0 = ret.Get(0).(resourcePreview) + } + + if rf, ok := ret.Get(1).(func(context.Context, repository.VersionedFileChange, string, string, string, string, string, bool) error); ok { + r1 = rf(ctx, f, namespace, repoName, base, ref, pullRequestURL, generatePreview) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockPreviewer_Preview_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Preview' +type MockPreviewer_Preview_Call struct { + *mock.Call +} + +// Preview is a helper method to define mock.On call +// - ctx context.Context +// - f repository.VersionedFileChange +// - namespace string +// - repoName string +// - base string +// - ref string +// - pullRequestURL string +// - generatePreview bool +func (_e *MockPreviewer_Expecter) Preview(ctx interface{}, f interface{}, namespace interface{}, repoName interface{}, base interface{}, ref interface{}, pullRequestURL interface{}, generatePreview interface{}) *MockPreviewer_Preview_Call { + return &MockPreviewer_Preview_Call{Call: _e.mock.On("Preview", ctx, f, namespace, repoName, base, ref, pullRequestURL, generatePreview)} +} + +func (_c *MockPreviewer_Preview_Call) Run(run func(ctx context.Context, f repository.VersionedFileChange, namespace string, repoName string, base string, ref string, pullRequestURL string, generatePreview bool)) *MockPreviewer_Preview_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(repository.VersionedFileChange), args[2].(string), args[3].(string), args[4].(string), args[5].(string), args[6].(string), args[7].(bool)) + }) + return _c +} + +func (_c *MockPreviewer_Preview_Call) Return(_a0 resourcePreview, _a1 error) *MockPreviewer_Preview_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockPreviewer_Preview_Call) RunAndReturn(run func(context.Context, repository.VersionedFileChange, string, string, string, string, string, bool) (resourcePreview, error)) *MockPreviewer_Preview_Call { + _c.Call.Return(run) + return _c +} + +// NewMockPreviewer creates a new instance of MockPreviewer. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockPreviewer(t interface { + mock.TestingT + Cleanup(func()) +}) *MockPreviewer { + mock := &MockPreviewer{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/registry/apis/provisioning/jobs/pullrequest/worker.go b/pkg/registry/apis/provisioning/jobs/pullrequest/worker.go index 25a42cb8dc9..485234e2598 100644 --- a/pkg/registry/apis/provisioning/jobs/pullrequest/worker.go +++ b/pkg/registry/apis/provisioning/jobs/pullrequest/worker.go @@ -24,18 +24,18 @@ type PullRequestRepo interface { } type PullRequestWorker struct { - parsers *resources.ParserFactory - previewer *Previewer + parsers resources.ParserFactory + previewer Previewer } func NewPullRequestWorker( - parsers *resources.ParserFactory, - previewer *Previewer, -) (*PullRequestWorker, error) { + parsers resources.ParserFactory, + previewer Previewer, +) *PullRequestWorker { return &PullRequestWorker{ parsers: parsers, previewer: previewer, - }, nil + } } func (c *PullRequestWorker) IsSupported(ctx context.Context, job provisioning.Job) bool { diff --git a/pkg/registry/apis/provisioning/jobs/queue.go b/pkg/registry/apis/provisioning/jobs/queue.go index 4a0ab7e7e3e..6782a003343 100644 --- a/pkg/registry/apis/provisioning/jobs/queue.go +++ b/pkg/registry/apis/provisioning/jobs/queue.go @@ -7,10 +7,16 @@ import ( "github.com/grafana/grafana/pkg/registry/apis/provisioning/repository" ) +// RepoGetter is a function that can be called to get a repository by name +// +//go:generate mockery --name RepoGetter --structname MockRepoGetter --inpackage --filename repo_getter_mock.go --with-expecter type RepoGetter interface { GetRepository(ctx context.Context, name string) (repository.Repository, error) } +// JobProgressRecorder is a function that can be called to record the progress of a job +// +//go:generate mockery --name JobProgressRecorder --structname MockJobProgressRecorder --inpackage --filename job_progress_recorder_mock.go --with-expecter type JobProgressRecorder interface { Record(ctx context.Context, result JobResourceResult) ResetResults() @@ -23,6 +29,9 @@ type JobProgressRecorder interface { Complete(ctx context.Context, err error) provisioning.JobStatus } +// Worker is a worker that can process a job +// +//go:generate mockery --name Worker --structname MockWorker --inpackage --filename worker_mock.go --with-expecter type Worker interface { IsSupported(ctx context.Context, job provisioning.Job) bool // Process the job. The job status should be updated as the job progresses. @@ -32,4 +41,6 @@ type Worker interface { } // ProgressFn is a function that can be called to update the progress of a job +// +//go:generate mockery --name ProgressFn --structname MockProgressFn --inpackage --filename progress_fn_mock.go --with-expecter type ProgressFn func(ctx context.Context, status provisioning.JobStatus) error diff --git a/pkg/registry/apis/provisioning/jobs/queue_mock.go b/pkg/registry/apis/provisioning/jobs/queue_mock.go new file mode 100644 index 00000000000..f20a8be6221 --- /dev/null +++ b/pkg/registry/apis/provisioning/jobs/queue_mock.go @@ -0,0 +1,97 @@ +// Code generated by mockery v2.52.4. DO NOT EDIT. + +package jobs + +import ( + context "context" + + v0alpha1 "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1" + mock "github.com/stretchr/testify/mock" +) + +// MockQueue is an autogenerated mock type for the Queue type +type MockQueue struct { + mock.Mock +} + +type MockQueue_Expecter struct { + mock *mock.Mock +} + +func (_m *MockQueue) EXPECT() *MockQueue_Expecter { + return &MockQueue_Expecter{mock: &_m.Mock} +} + +// Insert provides a mock function with given fields: ctx, namespace, spec +func (_m *MockQueue) Insert(ctx context.Context, namespace string, spec v0alpha1.JobSpec) (*v0alpha1.Job, error) { + ret := _m.Called(ctx, namespace, spec) + + if len(ret) == 0 { + panic("no return value specified for Insert") + } + + var r0 *v0alpha1.Job + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string, v0alpha1.JobSpec) (*v0alpha1.Job, error)); ok { + return rf(ctx, namespace, spec) + } + if rf, ok := ret.Get(0).(func(context.Context, string, v0alpha1.JobSpec) *v0alpha1.Job); ok { + r0 = rf(ctx, namespace, spec) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*v0alpha1.Job) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, string, v0alpha1.JobSpec) error); ok { + r1 = rf(ctx, namespace, spec) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockQueue_Insert_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Insert' +type MockQueue_Insert_Call struct { + *mock.Call +} + +// Insert is a helper method to define mock.On call +// - ctx context.Context +// - namespace string +// - spec v0alpha1.JobSpec +func (_e *MockQueue_Expecter) Insert(ctx interface{}, namespace interface{}, spec interface{}) *MockQueue_Insert_Call { + return &MockQueue_Insert_Call{Call: _e.mock.On("Insert", ctx, namespace, spec)} +} + +func (_c *MockQueue_Insert_Call) Run(run func(ctx context.Context, namespace string, spec v0alpha1.JobSpec)) *MockQueue_Insert_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(string), args[2].(v0alpha1.JobSpec)) + }) + return _c +} + +func (_c *MockQueue_Insert_Call) Return(_a0 *v0alpha1.Job, _a1 error) *MockQueue_Insert_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockQueue_Insert_Call) RunAndReturn(run func(context.Context, string, v0alpha1.JobSpec) (*v0alpha1.Job, error)) *MockQueue_Insert_Call { + _c.Call.Return(run) + return _c +} + +// NewMockQueue creates a new instance of MockQueue. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockQueue(t interface { + mock.TestingT + Cleanup(func()) +}) *MockQueue { + mock := &MockQueue{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/registry/apis/provisioning/jobs/repo_getter_mock.go b/pkg/registry/apis/provisioning/jobs/repo_getter_mock.go new file mode 100644 index 00000000000..d0152e725bc --- /dev/null +++ b/pkg/registry/apis/provisioning/jobs/repo_getter_mock.go @@ -0,0 +1,96 @@ +// Code generated by mockery v2.52.4. DO NOT EDIT. + +package jobs + +import ( + context "context" + + repository "github.com/grafana/grafana/pkg/registry/apis/provisioning/repository" + mock "github.com/stretchr/testify/mock" +) + +// MockRepoGetter is an autogenerated mock type for the RepoGetter type +type MockRepoGetter struct { + mock.Mock +} + +type MockRepoGetter_Expecter struct { + mock *mock.Mock +} + +func (_m *MockRepoGetter) EXPECT() *MockRepoGetter_Expecter { + return &MockRepoGetter_Expecter{mock: &_m.Mock} +} + +// GetRepository provides a mock function with given fields: ctx, name +func (_m *MockRepoGetter) GetRepository(ctx context.Context, name string) (repository.Repository, error) { + ret := _m.Called(ctx, name) + + if len(ret) == 0 { + panic("no return value specified for GetRepository") + } + + var r0 repository.Repository + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string) (repository.Repository, error)); ok { + return rf(ctx, name) + } + if rf, ok := ret.Get(0).(func(context.Context, string) repository.Repository); ok { + r0 = rf(ctx, name) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(repository.Repository) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { + r1 = rf(ctx, name) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockRepoGetter_GetRepository_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetRepository' +type MockRepoGetter_GetRepository_Call struct { + *mock.Call +} + +// GetRepository is a helper method to define mock.On call +// - ctx context.Context +// - name string +func (_e *MockRepoGetter_Expecter) GetRepository(ctx interface{}, name interface{}) *MockRepoGetter_GetRepository_Call { + return &MockRepoGetter_GetRepository_Call{Call: _e.mock.On("GetRepository", ctx, name)} +} + +func (_c *MockRepoGetter_GetRepository_Call) Run(run func(ctx context.Context, name string)) *MockRepoGetter_GetRepository_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(string)) + }) + return _c +} + +func (_c *MockRepoGetter_GetRepository_Call) Return(_a0 repository.Repository, _a1 error) *MockRepoGetter_GetRepository_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockRepoGetter_GetRepository_Call) RunAndReturn(run func(context.Context, string) (repository.Repository, error)) *MockRepoGetter_GetRepository_Call { + _c.Call.Return(run) + return _c +} + +// NewMockRepoGetter creates a new instance of MockRepoGetter. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockRepoGetter(t interface { + mock.TestingT + Cleanup(func()) +}) *MockRepoGetter { + mock := &MockRepoGetter{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/registry/apis/provisioning/jobs/store_mock.go b/pkg/registry/apis/provisioning/jobs/store_mock.go new file mode 100644 index 00000000000..300bf5fb271 --- /dev/null +++ b/pkg/registry/apis/provisioning/jobs/store_mock.go @@ -0,0 +1,303 @@ +// Code generated by mockery v2.52.4. DO NOT EDIT. + +package jobs + +import ( + context "context" + + v0alpha1 "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1" + mock "github.com/stretchr/testify/mock" +) + +// MockStore is an autogenerated mock type for the Store type +type MockStore struct { + mock.Mock +} + +type MockStore_Expecter struct { + mock *mock.Mock +} + +func (_m *MockStore) EXPECT() *MockStore_Expecter { + return &MockStore_Expecter{mock: &_m.Mock} +} + +// Claim provides a mock function with given fields: ctx +func (_m *MockStore) Claim(ctx context.Context) (*v0alpha1.Job, func(), error) { + ret := _m.Called(ctx) + + if len(ret) == 0 { + panic("no return value specified for Claim") + } + + var r0 *v0alpha1.Job + var r1 func() + var r2 error + if rf, ok := ret.Get(0).(func(context.Context) (*v0alpha1.Job, func(), error)); ok { + return rf(ctx) + } + if rf, ok := ret.Get(0).(func(context.Context) *v0alpha1.Job); ok { + r0 = rf(ctx) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*v0alpha1.Job) + } + } + + if rf, ok := ret.Get(1).(func(context.Context) func()); ok { + r1 = rf(ctx) + } else { + if ret.Get(1) != nil { + r1 = ret.Get(1).(func()) + } + } + + if rf, ok := ret.Get(2).(func(context.Context) error); ok { + r2 = rf(ctx) + } else { + r2 = ret.Error(2) + } + + return r0, r1, r2 +} + +// MockStore_Claim_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Claim' +type MockStore_Claim_Call struct { + *mock.Call +} + +// Claim is a helper method to define mock.On call +// - ctx context.Context +func (_e *MockStore_Expecter) Claim(ctx interface{}) *MockStore_Claim_Call { + return &MockStore_Claim_Call{Call: _e.mock.On("Claim", ctx)} +} + +func (_c *MockStore_Claim_Call) Run(run func(ctx context.Context)) *MockStore_Claim_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context)) + }) + return _c +} + +func (_c *MockStore_Claim_Call) Return(job *v0alpha1.Job, rollback func(), err error) *MockStore_Claim_Call { + _c.Call.Return(job, rollback, err) + return _c +} + +func (_c *MockStore_Claim_Call) RunAndReturn(run func(context.Context) (*v0alpha1.Job, func(), error)) *MockStore_Claim_Call { + _c.Call.Return(run) + return _c +} + +// Cleanup provides a mock function with given fields: ctx +func (_m *MockStore) Cleanup(ctx context.Context) error { + ret := _m.Called(ctx) + + if len(ret) == 0 { + panic("no return value specified for Cleanup") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context) error); ok { + r0 = rf(ctx) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockStore_Cleanup_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Cleanup' +type MockStore_Cleanup_Call struct { + *mock.Call +} + +// Cleanup is a helper method to define mock.On call +// - ctx context.Context +func (_e *MockStore_Expecter) Cleanup(ctx interface{}) *MockStore_Cleanup_Call { + return &MockStore_Cleanup_Call{Call: _e.mock.On("Cleanup", ctx)} +} + +func (_c *MockStore_Cleanup_Call) Run(run func(ctx context.Context)) *MockStore_Cleanup_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context)) + }) + return _c +} + +func (_c *MockStore_Cleanup_Call) Return(_a0 error) *MockStore_Cleanup_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockStore_Cleanup_Call) RunAndReturn(run func(context.Context) error) *MockStore_Cleanup_Call { + _c.Call.Return(run) + return _c +} + +// Complete provides a mock function with given fields: ctx, job +func (_m *MockStore) Complete(ctx context.Context, job *v0alpha1.Job) error { + ret := _m.Called(ctx, job) + + if len(ret) == 0 { + panic("no return value specified for Complete") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, *v0alpha1.Job) error); ok { + r0 = rf(ctx, job) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockStore_Complete_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Complete' +type MockStore_Complete_Call struct { + *mock.Call +} + +// Complete is a helper method to define mock.On call +// - ctx context.Context +// - job *v0alpha1.Job +func (_e *MockStore_Expecter) Complete(ctx interface{}, job interface{}) *MockStore_Complete_Call { + return &MockStore_Complete_Call{Call: _e.mock.On("Complete", ctx, job)} +} + +func (_c *MockStore_Complete_Call) Run(run func(ctx context.Context, job *v0alpha1.Job)) *MockStore_Complete_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*v0alpha1.Job)) + }) + return _c +} + +func (_c *MockStore_Complete_Call) Return(_a0 error) *MockStore_Complete_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockStore_Complete_Call) RunAndReturn(run func(context.Context, *v0alpha1.Job) error) *MockStore_Complete_Call { + _c.Call.Return(run) + return _c +} + +// InsertNotifications provides a mock function with no fields +func (_m *MockStore) InsertNotifications() chan struct{} { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for InsertNotifications") + } + + var r0 chan struct{} + if rf, ok := ret.Get(0).(func() chan struct{}); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(chan struct{}) + } + } + + return r0 +} + +// MockStore_InsertNotifications_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'InsertNotifications' +type MockStore_InsertNotifications_Call struct { + *mock.Call +} + +// InsertNotifications is a helper method to define mock.On call +func (_e *MockStore_Expecter) InsertNotifications() *MockStore_InsertNotifications_Call { + return &MockStore_InsertNotifications_Call{Call: _e.mock.On("InsertNotifications")} +} + +func (_c *MockStore_InsertNotifications_Call) Run(run func()) *MockStore_InsertNotifications_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockStore_InsertNotifications_Call) Return(_a0 chan struct{}) *MockStore_InsertNotifications_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockStore_InsertNotifications_Call) RunAndReturn(run func() chan struct{}) *MockStore_InsertNotifications_Call { + _c.Call.Return(run) + return _c +} + +// Update provides a mock function with given fields: ctx, job +func (_m *MockStore) Update(ctx context.Context, job *v0alpha1.Job) (*v0alpha1.Job, error) { + ret := _m.Called(ctx, job) + + if len(ret) == 0 { + panic("no return value specified for Update") + } + + var r0 *v0alpha1.Job + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *v0alpha1.Job) (*v0alpha1.Job, error)); ok { + return rf(ctx, job) + } + if rf, ok := ret.Get(0).(func(context.Context, *v0alpha1.Job) *v0alpha1.Job); ok { + r0 = rf(ctx, job) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*v0alpha1.Job) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *v0alpha1.Job) error); ok { + r1 = rf(ctx, job) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockStore_Update_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Update' +type MockStore_Update_Call struct { + *mock.Call +} + +// Update is a helper method to define mock.On call +// - ctx context.Context +// - job *v0alpha1.Job +func (_e *MockStore_Expecter) Update(ctx interface{}, job interface{}) *MockStore_Update_Call { + return &MockStore_Update_Call{Call: _e.mock.On("Update", ctx, job)} +} + +func (_c *MockStore_Update_Call) Run(run func(ctx context.Context, job *v0alpha1.Job)) *MockStore_Update_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*v0alpha1.Job)) + }) + return _c +} + +func (_c *MockStore_Update_Call) Return(_a0 *v0alpha1.Job, _a1 error) *MockStore_Update_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockStore_Update_Call) RunAndReturn(run func(context.Context, *v0alpha1.Job) (*v0alpha1.Job, error)) *MockStore_Update_Call { + _c.Call.Return(run) + return _c +} + +// NewMockStore creates a new instance of MockStore. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockStore(t interface { + mock.TestingT + Cleanup(func()) +}) *MockStore { + mock := &MockStore{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/registry/apis/provisioning/jobs/sync/worker.go b/pkg/registry/apis/provisioning/jobs/sync/worker.go index 60c345a8a89..07915493859 100644 --- a/pkg/registry/apis/provisioning/jobs/sync/worker.go +++ b/pkg/registry/apis/provisioning/jobs/sync/worker.go @@ -30,7 +30,10 @@ type SyncWorker struct { lister resources.ResourceLister // Parses fields saved in remore repository - parsers *resources.ParserFactory + parsers resources.ParserFactory + + // Clients for the repository + clients resources.ClientFactory // Check if the system is using unified storage storageStatus dualwrite.Service @@ -38,13 +41,15 @@ type SyncWorker struct { func NewSyncWorker( client client.ProvisioningV0alpha1Interface, - parsers *resources.ParserFactory, + parsers resources.ParserFactory, + clients resources.ClientFactory, lister resources.ResourceLister, storageStatus dualwrite.Service, ) *SyncWorker { return &SyncWorker{ client: client, parsers: parsers, + clients: clients, lister: lister, storageStatus: storageStatus, } @@ -137,7 +142,12 @@ func (r *SyncWorker) createJob(ctx context.Context, repo repository.ReaderWriter return nil, fmt.Errorf("failed to get parser for %s: %w", cfg.Name, err) } - folderClient, err := parser.Clients().Folder() + clients, err := r.clients.Clients(ctx, cfg.Namespace) + if err != nil { + return nil, fmt.Errorf("failed to get clients for %s: %w", cfg.Name, err) + } + + folderClient, err := clients.Folder() if err != nil { return nil, fmt.Errorf("unable to get folder client: %w", err) } @@ -148,8 +158,8 @@ func (r *SyncWorker) createJob(ctx context.Context, repo repository.ReaderWriter progress: progress, lister: r.lister, folders: folders, - clients: parser.Clients(), - resourceManager: resources.NewResourcesManager(repo, folders, parser, parser.Clients(), nil), + clients: clients, + resourceManager: resources.NewResourcesManager(repo, folders, parser, clients, nil), } return job, nil diff --git a/pkg/registry/apis/provisioning/jobs/worker_mock.go b/pkg/registry/apis/provisioning/jobs/worker_mock.go new file mode 100644 index 00000000000..b264b258d1c --- /dev/null +++ b/pkg/registry/apis/provisioning/jobs/worker_mock.go @@ -0,0 +1,135 @@ +// Code generated by mockery v2.52.4. DO NOT EDIT. + +package jobs + +import ( + context "context" + + repository "github.com/grafana/grafana/pkg/registry/apis/provisioning/repository" + mock "github.com/stretchr/testify/mock" + + v0alpha1 "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1" +) + +// MockWorker is an autogenerated mock type for the Worker type +type MockWorker struct { + mock.Mock +} + +type MockWorker_Expecter struct { + mock *mock.Mock +} + +func (_m *MockWorker) EXPECT() *MockWorker_Expecter { + return &MockWorker_Expecter{mock: &_m.Mock} +} + +// IsSupported provides a mock function with given fields: ctx, job +func (_m *MockWorker) IsSupported(ctx context.Context, job v0alpha1.Job) bool { + ret := _m.Called(ctx, job) + + if len(ret) == 0 { + panic("no return value specified for IsSupported") + } + + var r0 bool + if rf, ok := ret.Get(0).(func(context.Context, v0alpha1.Job) bool); ok { + r0 = rf(ctx, job) + } else { + r0 = ret.Get(0).(bool) + } + + return r0 +} + +// MockWorker_IsSupported_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'IsSupported' +type MockWorker_IsSupported_Call struct { + *mock.Call +} + +// IsSupported is a helper method to define mock.On call +// - ctx context.Context +// - job v0alpha1.Job +func (_e *MockWorker_Expecter) IsSupported(ctx interface{}, job interface{}) *MockWorker_IsSupported_Call { + return &MockWorker_IsSupported_Call{Call: _e.mock.On("IsSupported", ctx, job)} +} + +func (_c *MockWorker_IsSupported_Call) Run(run func(ctx context.Context, job v0alpha1.Job)) *MockWorker_IsSupported_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(v0alpha1.Job)) + }) + return _c +} + +func (_c *MockWorker_IsSupported_Call) Return(_a0 bool) *MockWorker_IsSupported_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockWorker_IsSupported_Call) RunAndReturn(run func(context.Context, v0alpha1.Job) bool) *MockWorker_IsSupported_Call { + _c.Call.Return(run) + return _c +} + +// Process provides a mock function with given fields: ctx, repo, job, progress +func (_m *MockWorker) Process(ctx context.Context, repo repository.Repository, job v0alpha1.Job, progress JobProgressRecorder) error { + ret := _m.Called(ctx, repo, job, progress) + + if len(ret) == 0 { + panic("no return value specified for Process") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, repository.Repository, v0alpha1.Job, JobProgressRecorder) error); ok { + r0 = rf(ctx, repo, job, progress) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockWorker_Process_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Process' +type MockWorker_Process_Call struct { + *mock.Call +} + +// Process is a helper method to define mock.On call +// - ctx context.Context +// - repo repository.Repository +// - job v0alpha1.Job +// - progress JobProgressRecorder +func (_e *MockWorker_Expecter) Process(ctx interface{}, repo interface{}, job interface{}, progress interface{}) *MockWorker_Process_Call { + return &MockWorker_Process_Call{Call: _e.mock.On("Process", ctx, repo, job, progress)} +} + +func (_c *MockWorker_Process_Call) Run(run func(ctx context.Context, repo repository.Repository, job v0alpha1.Job, progress JobProgressRecorder)) *MockWorker_Process_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(repository.Repository), args[2].(v0alpha1.Job), args[3].(JobProgressRecorder)) + }) + return _c +} + +func (_c *MockWorker_Process_Call) Return(_a0 error) *MockWorker_Process_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockWorker_Process_Call) RunAndReturn(run func(context.Context, repository.Repository, v0alpha1.Job, JobProgressRecorder) error) *MockWorker_Process_Call { + _c.Call.Return(run) + return _c +} + +// NewMockWorker creates a new instance of MockWorker. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockWorker(t interface { + mock.TestingT + Cleanup(func()) +}) *MockWorker { + mock := &MockWorker{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/registry/apis/provisioning/register.go b/pkg/registry/apis/provisioning/register.go index 096768ca037..8a55fb7ec9c 100644 --- a/pkg/registry/apis/provisioning/register.go +++ b/pkg/registry/apis/provisioning/register.go @@ -80,7 +80,8 @@ type APIBuilder struct { getter rest.Getter localFileResolver *repository.LocalFolderResolver render rendering.Service - parsers *resources.ParserFactory + parsers resources.ParserFactory + clients resources.ClientFactory ghFactory *github.Factory clonedir string // where repo clones are managed jobs interface { @@ -117,6 +118,7 @@ func NewAPIBuilder( ) *APIBuilder { // HACK: Assume is only public if it is HTTPS isPublic := strings.HasPrefix(urlProvider(""), "https://") + clients := resources.NewClientFactory(configProvider) return &APIBuilder{ urlProvider: urlProvider, @@ -125,16 +127,15 @@ func NewAPIBuilder( isPublic: isPublic, features: features, ghFactory: ghFactory, - parsers: &resources.ParserFactory{ - ClientFactory: resources.NewClientFactory(configProvider), - }, - render: render, - clonedir: clonedir, - resourceLister: resources.NewResourceLister(unified, unified, legacyMigrator, storageStatus), - legacyMigrator: legacyMigrator, - storageStatus: storageStatus, - unified: unified, - secrets: secrets, + clients: clients, + parsers: resources.NewParserFactory(clients), + render: render, + clonedir: clonedir, + resourceLister: resources.NewResourceLister(unified, unified, legacyMigrator, storageStatus), + legacyMigrator: legacyMigrator, + storageStatus: storageStatus, + unified: unified, + secrets: secrets, } } @@ -367,10 +368,7 @@ func (b *APIBuilder) UpdateAPIGroupInfo(apiGroupInfo *genericapiserver.APIGroupI storage[provisioning.RepositoryResourceInfo.StoragePath("test")] = &testConnector{ getter: b, } - storage[provisioning.RepositoryResourceInfo.StoragePath("files")] = &filesConnector{ - getter: b, - parsers: b.parsers, - } + storage[provisioning.RepositoryResourceInfo.StoragePath("files")] = NewFilesConnector(b, b.parsers, b.clients) storage[provisioning.RepositoryResourceInfo.StoragePath("resources")] = &listConnector{ getter: b, lister: b.resourceLister, @@ -562,19 +560,21 @@ func (b *APIBuilder) GetPostStartHooks() (map[string]genericapiserver.PostStartH b.repositoryLister = repoInformer.Lister() exportWorker := export.NewExportWorker( - b.parsers.ClientFactory, + b.clients, b.storageStatus, b.parsers, ) syncWorker := sync.NewSyncWorker( b.GetClient(), b.parsers, + b.clients, b.resourceLister, b.storageStatus, ) migrationWorker := migrate.NewMigrationWorker( b.legacyMigrator, b.parsers, + b.clients, b.storageStatus, b.unified, exportWorker, @@ -584,10 +584,7 @@ func (b *APIBuilder) GetPostStartHooks() (map[string]genericapiserver.PostStartH // Pull request worker renderer := pullrequest.NewScreenshotRenderer(b.render, b.unified, b.isPublic, b.urlProvider) previewer := pullrequest.NewPreviewer(renderer, b.urlProvider) - pullRequestWorker, err := pullrequest.NewPullRequestWorker(b.parsers, previewer) - if err != nil { - return fmt.Errorf("create pull request worker: %w", err) - } + pullRequestWorker := pullrequest.NewPullRequestWorker(b.parsers, previewer) driver := jobs.NewJobDriver(time.Second*28, time.Second*30, time.Second*30, b.jobs, b, b.jobHistory, exportWorker, syncWorker, migrationWorker, pullRequestWorker) @@ -599,6 +596,7 @@ func (b *APIBuilder) GetPostStartHooks() (map[string]genericapiserver.PostStartH b, // repoGetter b.resourceLister, b.parsers, + b.clients, &repository.Tester{}, b.jobs, b.secrets, diff --git a/pkg/registry/apis/provisioning/resources/client.go b/pkg/registry/apis/provisioning/resources/client.go index 9b35b86b0ee..4898a195199 100644 --- a/pkg/registry/apis/provisioning/resources/client.go +++ b/pkg/registry/apis/provisioning/resources/client.go @@ -26,7 +26,14 @@ var ( SupportedProvisioningResources = []schema.GroupVersionResource{FolderResource, DashboardResource} ) -type ClientFactory struct { +// ClientFactory is a factory for creating clients for a given namespace +// +//go:generate mockery --name ClientFactory --structname MockClientFactory --inpackage --filename client_factory_mock.go --with-expecter +type ClientFactory interface { + Clients(ctx context.Context, namespace string) (ResourceClients, error) +} + +type clientFactory struct { configProvider apiserver.RestConfigProvider } @@ -41,11 +48,11 @@ type ResourceClients interface { User() (dynamic.ResourceInterface, error) } -func NewClientFactory(configProvider apiserver.RestConfigProvider) *ClientFactory { - return &ClientFactory{configProvider} +func NewClientFactory(configProvider apiserver.RestConfigProvider) ClientFactory { + return &clientFactory{configProvider} } -func (f *ClientFactory) Clients(ctx context.Context, namespace string) (ResourceClients, error) { +func (f *clientFactory) Clients(ctx context.Context, namespace string) (ResourceClients, error) { restConfig, err := f.configProvider.GetRestConfig(ctx) if err != nil { return nil, err diff --git a/pkg/registry/apis/provisioning/resources/client_factory_mock.go b/pkg/registry/apis/provisioning/resources/client_factory_mock.go new file mode 100644 index 00000000000..b8aa174e04f --- /dev/null +++ b/pkg/registry/apis/provisioning/resources/client_factory_mock.go @@ -0,0 +1,95 @@ +// Code generated by mockery v2.52.4. DO NOT EDIT. + +package resources + +import ( + context "context" + + mock "github.com/stretchr/testify/mock" +) + +// MockClientFactory is an autogenerated mock type for the ClientFactory type +type MockClientFactory struct { + mock.Mock +} + +type MockClientFactory_Expecter struct { + mock *mock.Mock +} + +func (_m *MockClientFactory) EXPECT() *MockClientFactory_Expecter { + return &MockClientFactory_Expecter{mock: &_m.Mock} +} + +// Clients provides a mock function with given fields: ctx, namespace +func (_m *MockClientFactory) Clients(ctx context.Context, namespace string) (ResourceClients, error) { + ret := _m.Called(ctx, namespace) + + if len(ret) == 0 { + panic("no return value specified for Clients") + } + + var r0 ResourceClients + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string) (ResourceClients, error)); ok { + return rf(ctx, namespace) + } + if rf, ok := ret.Get(0).(func(context.Context, string) ResourceClients); ok { + r0 = rf(ctx, namespace) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(ResourceClients) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { + r1 = rf(ctx, namespace) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockClientFactory_Clients_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Clients' +type MockClientFactory_Clients_Call struct { + *mock.Call +} + +// Clients is a helper method to define mock.On call +// - ctx context.Context +// - namespace string +func (_e *MockClientFactory_Expecter) Clients(ctx interface{}, namespace interface{}) *MockClientFactory_Clients_Call { + return &MockClientFactory_Clients_Call{Call: _e.mock.On("Clients", ctx, namespace)} +} + +func (_c *MockClientFactory_Clients_Call) Run(run func(ctx context.Context, namespace string)) *MockClientFactory_Clients_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(string)) + }) + return _c +} + +func (_c *MockClientFactory_Clients_Call) Return(_a0 ResourceClients, _a1 error) *MockClientFactory_Clients_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockClientFactory_Clients_Call) RunAndReturn(run func(context.Context, string) (ResourceClients, error)) *MockClientFactory_Clients_Call { + _c.Call.Return(run) + return _c +} + +// NewMockClientFactory creates a new instance of MockClientFactory. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockClientFactory(t interface { + mock.TestingT + Cleanup(func()) +}) *MockClientFactory { + mock := &MockClientFactory{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/registry/apis/provisioning/resources/clients_mock.go b/pkg/registry/apis/provisioning/resources/clients_mock.go index dbbd1347edd..d78496c2183 100644 --- a/pkg/registry/apis/provisioning/resources/clients_mock.go +++ b/pkg/registry/apis/provisioning/resources/clients_mock.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.53.3. DO NOT EDIT. +// Code generated by mockery v2.52.4. DO NOT EDIT. package resources diff --git a/pkg/registry/apis/provisioning/resources/dualwriter.go b/pkg/registry/apis/provisioning/resources/dualwriter.go index 5c25094c1cc..094e5c2fb2d 100644 --- a/pkg/registry/apis/provisioning/resources/dualwriter.go +++ b/pkg/registry/apis/provisioning/resources/dualwriter.go @@ -18,11 +18,11 @@ import ( // TODO: it does not support folders yet type DualReadWriter struct { repo repository.ReaderWriter - parser *Parser + parser Parser folders *FolderManager } -func NewDualReadWriter(repo repository.ReaderWriter, parser *Parser, folders *FolderManager) *DualReadWriter { +func NewDualReadWriter(repo repository.ReaderWriter, parser Parser, folders *FolderManager) *DualReadWriter { return &DualReadWriter{repo: repo, parser: parser, folders: folders} } diff --git a/pkg/registry/apis/provisioning/resources/fileformat_test.go b/pkg/registry/apis/provisioning/resources/fileformat_test.go index 7bb0de5295d..611578abb45 100644 --- a/pkg/registry/apis/provisioning/resources/fileformat_test.go +++ b/pkg/registry/apis/provisioning/resources/fileformat_test.go @@ -95,7 +95,7 @@ spec: info.Data, err = os.ReadFile(path.Join("../../../../..", info.Path)) require.NoError(t, err) - parser := &Parser{ + parser := &parser{ repo: provisioning.ResourceRepositoryInfo{ Name: "test", }, diff --git a/pkg/registry/apis/provisioning/resources/folders.go b/pkg/registry/apis/provisioning/resources/folders.go index ad27a1abe5f..58570c819fe 100644 --- a/pkg/registry/apis/provisioning/resources/folders.go +++ b/pkg/registry/apis/provisioning/resources/folders.go @@ -20,11 +20,11 @@ const maxFolders = 10000 type FolderManager struct { repo repository.ReaderWriter - tree *FolderTree + tree FolderTree client dynamic.ResourceInterface } -func NewFolderManager(repo repository.ReaderWriter, client dynamic.ResourceInterface, lookup *FolderTree) *FolderManager { +func NewFolderManager(repo repository.ReaderWriter, client dynamic.ResourceInterface, lookup FolderTree) *FolderManager { return &FolderManager{ repo: repo, tree: lookup, @@ -36,11 +36,11 @@ func (fm *FolderManager) Client() dynamic.ResourceInterface { return fm.client } -func (fm *FolderManager) Tree() *FolderTree { +func (fm *FolderManager) Tree() FolderTree { return fm.tree } -func (fm *FolderManager) SetTree(tree *FolderTree) { +func (fm *FolderManager) SetTree(tree FolderTree) { fm.tree = tree } diff --git a/pkg/registry/apis/provisioning/resources/object.go b/pkg/registry/apis/provisioning/resources/object.go index c5702dfe22e..27df4be5cb6 100644 --- a/pkg/registry/apis/provisioning/resources/object.go +++ b/pkg/registry/apis/provisioning/resources/object.go @@ -16,6 +16,8 @@ import ( ) // Get repository stats +// +//go:generate mockery --name ResourceLister --structname MockResourceLister --inpackage --filename resource_lister_mock.go --with-expecter type ResourceLister interface { List(ctx context.Context, namespace, repository string) (*provisioning.ResourceList, error) Stats(ctx context.Context, namespace, repository string) (*provisioning.ResourceStats, error) diff --git a/pkg/registry/apis/provisioning/resources/parser.go b/pkg/registry/apis/provisioning/resources/parser.go index 1e39694fc03..61eaa004cf6 100644 --- a/pkg/registry/apis/provisioning/resources/parser.go +++ b/pkg/registry/apis/provisioning/resources/parser.go @@ -23,11 +23,29 @@ import ( "github.com/grafana/grafana/pkg/registry/apis/provisioning/safepath" ) -type ParserFactory struct { - ClientFactory *ClientFactory +// ParserFactory is a factory for creating parsers for a given repository +// +//go:generate mockery --name ParserFactory --structname MockParserFactory --inpackage --filename parser_factory_mock.go --with-expecter +type ParserFactory interface { + GetParser(ctx context.Context, repo repository.Reader) (Parser, error) } -func (f *ParserFactory) GetParser(ctx context.Context, repo repository.Reader) (*Parser, error) { +// Parser is a parser for a given repository +// +//go:generate mockery --name Parser --structname MockParser --inpackage --filename parser_mock.go --with-expecter +type Parser interface { + Parse(ctx context.Context, info *repository.FileInfo) (parsed *ParsedResource, err error) +} + +type parserFactory struct { + ClientFactory ClientFactory +} + +func NewParserFactory(clientFactory ClientFactory) ParserFactory { + return &parserFactory{clientFactory} +} + +func (f *parserFactory) GetParser(ctx context.Context, repo repository.Reader) (Parser, error) { config := repo.Config() clients, err := f.ClientFactory.Clients(ctx, config.GetNamespace()) @@ -36,7 +54,7 @@ func (f *ParserFactory) GetParser(ctx context.Context, repo repository.Reader) ( } urls, _ := repo.(repository.RepositoryWithURLs) - return &Parser{ + return &parser{ repo: provisioning.ResourceRepositoryInfo{ Type: config.Spec.Type, Title: config.Spec.Title, @@ -48,7 +66,7 @@ func (f *ParserFactory) GetParser(ctx context.Context, repo repository.Reader) ( }, nil } -type Parser struct { +type parser struct { // The target repository repo provisioning.ResourceRepositoryInfo @@ -101,12 +119,7 @@ type ParsedResource struct { Errors []string } -// FIXME: eliminate clients from parser (but be careful that we can use the same cache/resolved GVK+GVR) -func (r *Parser) Clients() ResourceClients { - return r.clients -} - -func (r *Parser) Parse(ctx context.Context, info *repository.FileInfo) (parsed *ParsedResource, err error) { +func (r *parser) Parse(ctx context.Context, info *repository.FileInfo) (parsed *ParsedResource, err error) { logger := logging.FromContext(ctx).With("path", info.Path) parsed = &ParsedResource{ Info: info, diff --git a/pkg/registry/apis/provisioning/resources/parser_factory_mock.go b/pkg/registry/apis/provisioning/resources/parser_factory_mock.go new file mode 100644 index 00000000000..434863be21c --- /dev/null +++ b/pkg/registry/apis/provisioning/resources/parser_factory_mock.go @@ -0,0 +1,96 @@ +// Code generated by mockery v2.52.4. DO NOT EDIT. + +package resources + +import ( + context "context" + + repository "github.com/grafana/grafana/pkg/registry/apis/provisioning/repository" + mock "github.com/stretchr/testify/mock" +) + +// MockParserFactory is an autogenerated mock type for the ParserFactory type +type MockParserFactory struct { + mock.Mock +} + +type MockParserFactory_Expecter struct { + mock *mock.Mock +} + +func (_m *MockParserFactory) EXPECT() *MockParserFactory_Expecter { + return &MockParserFactory_Expecter{mock: &_m.Mock} +} + +// GetParser provides a mock function with given fields: ctx, repo +func (_m *MockParserFactory) GetParser(ctx context.Context, repo repository.Reader) (Parser, error) { + ret := _m.Called(ctx, repo) + + if len(ret) == 0 { + panic("no return value specified for GetParser") + } + + var r0 Parser + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, repository.Reader) (Parser, error)); ok { + return rf(ctx, repo) + } + if rf, ok := ret.Get(0).(func(context.Context, repository.Reader) Parser); ok { + r0 = rf(ctx, repo) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(Parser) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, repository.Reader) error); ok { + r1 = rf(ctx, repo) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockParserFactory_GetParser_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetParser' +type MockParserFactory_GetParser_Call struct { + *mock.Call +} + +// GetParser is a helper method to define mock.On call +// - ctx context.Context +// - repo repository.Reader +func (_e *MockParserFactory_Expecter) GetParser(ctx interface{}, repo interface{}) *MockParserFactory_GetParser_Call { + return &MockParserFactory_GetParser_Call{Call: _e.mock.On("GetParser", ctx, repo)} +} + +func (_c *MockParserFactory_GetParser_Call) Run(run func(ctx context.Context, repo repository.Reader)) *MockParserFactory_GetParser_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(repository.Reader)) + }) + return _c +} + +func (_c *MockParserFactory_GetParser_Call) Return(_a0 Parser, _a1 error) *MockParserFactory_GetParser_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockParserFactory_GetParser_Call) RunAndReturn(run func(context.Context, repository.Reader) (Parser, error)) *MockParserFactory_GetParser_Call { + _c.Call.Return(run) + return _c +} + +// NewMockParserFactory creates a new instance of MockParserFactory. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockParserFactory(t interface { + mock.TestingT + Cleanup(func()) +}) *MockParserFactory { + mock := &MockParserFactory{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/registry/apis/provisioning/resources/parser_mock.go b/pkg/registry/apis/provisioning/resources/parser_mock.go new file mode 100644 index 00000000000..c207d0e9095 --- /dev/null +++ b/pkg/registry/apis/provisioning/resources/parser_mock.go @@ -0,0 +1,96 @@ +// Code generated by mockery v2.52.4. DO NOT EDIT. + +package resources + +import ( + context "context" + + repository "github.com/grafana/grafana/pkg/registry/apis/provisioning/repository" + mock "github.com/stretchr/testify/mock" +) + +// MockParser is an autogenerated mock type for the Parser type +type MockParser struct { + mock.Mock +} + +type MockParser_Expecter struct { + mock *mock.Mock +} + +func (_m *MockParser) EXPECT() *MockParser_Expecter { + return &MockParser_Expecter{mock: &_m.Mock} +} + +// Parse provides a mock function with given fields: ctx, info +func (_m *MockParser) Parse(ctx context.Context, info *repository.FileInfo) (*ParsedResource, error) { + ret := _m.Called(ctx, info) + + if len(ret) == 0 { + panic("no return value specified for Parse") + } + + var r0 *ParsedResource + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *repository.FileInfo) (*ParsedResource, error)); ok { + return rf(ctx, info) + } + if rf, ok := ret.Get(0).(func(context.Context, *repository.FileInfo) *ParsedResource); ok { + r0 = rf(ctx, info) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*ParsedResource) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *repository.FileInfo) error); ok { + r1 = rf(ctx, info) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockParser_Parse_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Parse' +type MockParser_Parse_Call struct { + *mock.Call +} + +// Parse is a helper method to define mock.On call +// - ctx context.Context +// - info *repository.FileInfo +func (_e *MockParser_Expecter) Parse(ctx interface{}, info interface{}) *MockParser_Parse_Call { + return &MockParser_Parse_Call{Call: _e.mock.On("Parse", ctx, info)} +} + +func (_c *MockParser_Parse_Call) Run(run func(ctx context.Context, info *repository.FileInfo)) *MockParser_Parse_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*repository.FileInfo)) + }) + return _c +} + +func (_c *MockParser_Parse_Call) Return(parsed *ParsedResource, err error) *MockParser_Parse_Call { + _c.Call.Return(parsed, err) + return _c +} + +func (_c *MockParser_Parse_Call) RunAndReturn(run func(context.Context, *repository.FileInfo) (*ParsedResource, error)) *MockParser_Parse_Call { + _c.Call.Return(run) + return _c +} + +// NewMockParser creates a new instance of MockParser. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockParser(t interface { + mock.TestingT + Cleanup(func()) +}) *MockParser { + mock := &MockParser{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/registry/apis/provisioning/resources/parser_test.go b/pkg/registry/apis/provisioning/resources/parser_test.go index 391e8abbd4a..f26432ecc20 100644 --- a/pkg/registry/apis/provisioning/resources/parser_test.go +++ b/pkg/registry/apis/provisioning/resources/parser_test.go @@ -20,7 +20,7 @@ func TestParser(t *testing.T) { clients.On("ForKind", dashboardV1.DashboardResourceInfo.GroupVersionKind()). Return(nil, dashboardV1.DashboardResourceInfo.GroupVersionResource(), nil).Maybe() - parser := &Parser{ + parser := &parser{ repo: v0alpha1.ResourceRepositoryInfo{ Type: v0alpha1.LocalRepositoryType, Namespace: "xxx", diff --git a/pkg/registry/apis/provisioning/resources/resource_lister_mock.go b/pkg/registry/apis/provisioning/resources/resource_lister_mock.go new file mode 100644 index 00000000000..fae2e39b221 --- /dev/null +++ b/pkg/registry/apis/provisioning/resources/resource_lister_mock.go @@ -0,0 +1,157 @@ +// Code generated by mockery v2.52.4. DO NOT EDIT. + +package resources + +import ( + context "context" + + v0alpha1 "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1" + mock "github.com/stretchr/testify/mock" +) + +// MockResourceLister is an autogenerated mock type for the ResourceLister type +type MockResourceLister struct { + mock.Mock +} + +type MockResourceLister_Expecter struct { + mock *mock.Mock +} + +func (_m *MockResourceLister) EXPECT() *MockResourceLister_Expecter { + return &MockResourceLister_Expecter{mock: &_m.Mock} +} + +// List provides a mock function with given fields: ctx, namespace, repository +func (_m *MockResourceLister) List(ctx context.Context, namespace string, repository string) (*v0alpha1.ResourceList, error) { + ret := _m.Called(ctx, namespace, repository) + + if len(ret) == 0 { + panic("no return value specified for List") + } + + var r0 *v0alpha1.ResourceList + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string, string) (*v0alpha1.ResourceList, error)); ok { + return rf(ctx, namespace, repository) + } + if rf, ok := ret.Get(0).(func(context.Context, string, string) *v0alpha1.ResourceList); ok { + r0 = rf(ctx, namespace, repository) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*v0alpha1.ResourceList) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, string, string) error); ok { + r1 = rf(ctx, namespace, repository) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockResourceLister_List_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'List' +type MockResourceLister_List_Call struct { + *mock.Call +} + +// List is a helper method to define mock.On call +// - ctx context.Context +// - namespace string +// - repository string +func (_e *MockResourceLister_Expecter) List(ctx interface{}, namespace interface{}, repository interface{}) *MockResourceLister_List_Call { + return &MockResourceLister_List_Call{Call: _e.mock.On("List", ctx, namespace, repository)} +} + +func (_c *MockResourceLister_List_Call) Run(run func(ctx context.Context, namespace string, repository string)) *MockResourceLister_List_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(string), args[2].(string)) + }) + return _c +} + +func (_c *MockResourceLister_List_Call) Return(_a0 *v0alpha1.ResourceList, _a1 error) *MockResourceLister_List_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockResourceLister_List_Call) RunAndReturn(run func(context.Context, string, string) (*v0alpha1.ResourceList, error)) *MockResourceLister_List_Call { + _c.Call.Return(run) + return _c +} + +// Stats provides a mock function with given fields: ctx, namespace, repository +func (_m *MockResourceLister) Stats(ctx context.Context, namespace string, repository string) (*v0alpha1.ResourceStats, error) { + ret := _m.Called(ctx, namespace, repository) + + if len(ret) == 0 { + panic("no return value specified for Stats") + } + + var r0 *v0alpha1.ResourceStats + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string, string) (*v0alpha1.ResourceStats, error)); ok { + return rf(ctx, namespace, repository) + } + if rf, ok := ret.Get(0).(func(context.Context, string, string) *v0alpha1.ResourceStats); ok { + r0 = rf(ctx, namespace, repository) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*v0alpha1.ResourceStats) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, string, string) error); ok { + r1 = rf(ctx, namespace, repository) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockResourceLister_Stats_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Stats' +type MockResourceLister_Stats_Call struct { + *mock.Call +} + +// Stats is a helper method to define mock.On call +// - ctx context.Context +// - namespace string +// - repository string +func (_e *MockResourceLister_Expecter) Stats(ctx interface{}, namespace interface{}, repository interface{}) *MockResourceLister_Stats_Call { + return &MockResourceLister_Stats_Call{Call: _e.mock.On("Stats", ctx, namespace, repository)} +} + +func (_c *MockResourceLister_Stats_Call) Run(run func(ctx context.Context, namespace string, repository string)) *MockResourceLister_Stats_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(string), args[2].(string)) + }) + return _c +} + +func (_c *MockResourceLister_Stats_Call) Return(_a0 *v0alpha1.ResourceStats, _a1 error) *MockResourceLister_Stats_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockResourceLister_Stats_Call) RunAndReturn(run func(context.Context, string, string) (*v0alpha1.ResourceStats, error)) *MockResourceLister_Stats_Call { + _c.Call.Return(run) + return _c +} + +// NewMockResourceLister creates a new instance of MockResourceLister. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockResourceLister(t interface { + mock.TestingT + Cleanup(func()) +}) *MockResourceLister { + mock := &MockResourceLister{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/registry/apis/provisioning/resources/resources.go b/pkg/registry/apis/provisioning/resources/resources.go index 22731d63594..a5f622f1f03 100644 --- a/pkg/registry/apis/provisioning/resources/resources.go +++ b/pkg/registry/apis/provisioning/resources/resources.go @@ -37,13 +37,13 @@ type resourceID struct { type ResourcesManager struct { repo repository.ReaderWriter folders *FolderManager - parser *Parser + parser Parser clients ResourceClients userInfo map[string]repository.CommitSignature resourcesLookup map[resourceID]string // the path with this k8s name } -func NewResourcesManager(repo repository.ReaderWriter, folders *FolderManager, parser *Parser, clients ResourceClients, userInfo map[string]repository.CommitSignature) *ResourcesManager { +func NewResourcesManager(repo repository.ReaderWriter, folders *FolderManager, parser Parser, clients ResourceClients, userInfo map[string]repository.CommitSignature) *ResourcesManager { return &ResourcesManager{ repo: repo, folders: folders, diff --git a/pkg/registry/apis/provisioning/resources/tree.go b/pkg/registry/apis/provisioning/resources/tree.go index 3f570f37e23..3afbfcef437 100644 --- a/pkg/registry/apis/provisioning/resources/tree.go +++ b/pkg/registry/apis/provisioning/resources/tree.go @@ -16,7 +16,18 @@ import ( // FolderTree contains the entire set of folders (at a given snapshot in time) of the Grafana instance. // The folders are portrayed as a tree, where a folder has a parent, up until the root folder. // The root folder is special-cased as a folder that exists, but is not itself stored. It has no ID, no title, and no data, but will return `true` for OK bools. -type FolderTree struct { +// +//go:generate mockery --name FolderTree --structname MockFolderTree --inpackage --filename tree_mock.go --with-expecter +type FolderTree interface { + In(folder string) bool + DirPath(folder, baseFolder string) (Folder, bool) + Add(folder Folder, parent string) + AddUnstructured(item *unstructured.Unstructured, skipRepo string) error + Count() int + Walk(ctx context.Context, fn WalkFunc) error +} + +type folderTree struct { tree map[string]string folders map[string]Folder count int @@ -24,7 +35,7 @@ type FolderTree struct { // In determines if the given folder is in the tree at all. That is, it answers "does the folder even exist in the Grafana instance?" // An empty folder string means the root folder, and is special-cased to always return true. -func (t *FolderTree) In(folder string) bool { +func (t *folderTree) In(folder string) bool { _, ok := t.tree[folder] return ok || folder == "" } @@ -36,7 +47,7 @@ func (t *FolderTree) In(folder string) bool { // // If In(folder) or In(baseFolder) is false, this will return ok=false, because it would be undefined behaviour. // If baseFolder is not a parent of folder, ok=false is returned. -func (t *FolderTree) DirPath(folder, baseFolder string) (fid Folder, ok bool) { +func (t *folderTree) DirPath(folder, baseFolder string) (fid Folder, ok bool) { if !t.In(folder) || !t.In(baseFolder) { return Folder{}, false } @@ -64,19 +75,19 @@ func (t *FolderTree) DirPath(folder, baseFolder string) (fid Folder, ok bool) { return fid, ok } -func (t *FolderTree) Add(folder Folder, parent string) { +func (t *folderTree) Add(folder Folder, parent string) { t.tree[folder.ID] = parent t.folders[folder.ID] = folder t.count++ } -func (t *FolderTree) Count() int { +func (t *folderTree) Count() int { return t.count } type WalkFunc func(ctx context.Context, folder Folder) error -func (t *FolderTree) Walk(ctx context.Context, fn WalkFunc) error { +func (t *folderTree) Walk(ctx context.Context, fn WalkFunc) error { toWalk := make([]Folder, 0, len(t.folders)) for _, folder := range t.folders { folder, _ := t.DirPath(folder.ID, "") @@ -97,14 +108,14 @@ func (t *FolderTree) Walk(ctx context.Context, fn WalkFunc) error { return nil } -func NewEmptyFolderTree() *FolderTree { - return &FolderTree{ +func NewEmptyFolderTree() FolderTree { + return &folderTree{ tree: make(map[string]string, 0), folders: make(map[string]Folder, 0), } } -func (t *FolderTree) AddUnstructured(item *unstructured.Unstructured, skipRepo string) error { +func (t *folderTree) AddUnstructured(item *unstructured.Unstructured, skipRepo string) error { meta, err := utils.MetaAccessor(item) if err != nil { return fmt.Errorf("extract meta accessor: %w", err) @@ -123,7 +134,7 @@ func (t *FolderTree) AddUnstructured(item *unstructured.Unstructured, skipRepo s return nil } -func NewFolderTreeFromResourceList(resources *provisioning.ResourceList) *FolderTree { +func NewFolderTreeFromResourceList(resources *provisioning.ResourceList) FolderTree { tree := make(map[string]string, len(resources.Items)) folderIDs := make(map[string]Folder, len(resources.Items)) for _, rf := range resources.Items { @@ -139,7 +150,7 @@ func NewFolderTreeFromResourceList(resources *provisioning.ResourceList) *Folder } } - return &FolderTree{ + return &folderTree{ tree: tree, folders: folderIDs, count: len(resources.Items), diff --git a/pkg/registry/apis/provisioning/resources/tree_mock.go b/pkg/registry/apis/provisioning/resources/tree_mock.go new file mode 100644 index 00000000000..4edbd4b7054 --- /dev/null +++ b/pkg/registry/apis/provisioning/resources/tree_mock.go @@ -0,0 +1,313 @@ +// Code generated by mockery v2.52.4. DO NOT EDIT. + +package resources + +import ( + context "context" + + mock "github.com/stretchr/testify/mock" + unstructured "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" +) + +// MockFolderTree is an autogenerated mock type for the FolderTree type +type MockFolderTree struct { + mock.Mock +} + +type MockFolderTree_Expecter struct { + mock *mock.Mock +} + +func (_m *MockFolderTree) EXPECT() *MockFolderTree_Expecter { + return &MockFolderTree_Expecter{mock: &_m.Mock} +} + +// Add provides a mock function with given fields: folder, parent +func (_m *MockFolderTree) Add(folder Folder, parent string) { + _m.Called(folder, parent) +} + +// MockFolderTree_Add_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Add' +type MockFolderTree_Add_Call struct { + *mock.Call +} + +// Add is a helper method to define mock.On call +// - folder Folder +// - parent string +func (_e *MockFolderTree_Expecter) Add(folder interface{}, parent interface{}) *MockFolderTree_Add_Call { + return &MockFolderTree_Add_Call{Call: _e.mock.On("Add", folder, parent)} +} + +func (_c *MockFolderTree_Add_Call) Run(run func(folder Folder, parent string)) *MockFolderTree_Add_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(Folder), args[1].(string)) + }) + return _c +} + +func (_c *MockFolderTree_Add_Call) Return() *MockFolderTree_Add_Call { + _c.Call.Return() + return _c +} + +func (_c *MockFolderTree_Add_Call) RunAndReturn(run func(Folder, string)) *MockFolderTree_Add_Call { + _c.Run(run) + return _c +} + +// AddUnstructured provides a mock function with given fields: item, skipRepo +func (_m *MockFolderTree) AddUnstructured(item *unstructured.Unstructured, skipRepo string) error { + ret := _m.Called(item, skipRepo) + + if len(ret) == 0 { + panic("no return value specified for AddUnstructured") + } + + var r0 error + if rf, ok := ret.Get(0).(func(*unstructured.Unstructured, string) error); ok { + r0 = rf(item, skipRepo) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockFolderTree_AddUnstructured_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AddUnstructured' +type MockFolderTree_AddUnstructured_Call struct { + *mock.Call +} + +// AddUnstructured is a helper method to define mock.On call +// - item *unstructured.Unstructured +// - skipRepo string +func (_e *MockFolderTree_Expecter) AddUnstructured(item interface{}, skipRepo interface{}) *MockFolderTree_AddUnstructured_Call { + return &MockFolderTree_AddUnstructured_Call{Call: _e.mock.On("AddUnstructured", item, skipRepo)} +} + +func (_c *MockFolderTree_AddUnstructured_Call) Run(run func(item *unstructured.Unstructured, skipRepo string)) *MockFolderTree_AddUnstructured_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(*unstructured.Unstructured), args[1].(string)) + }) + return _c +} + +func (_c *MockFolderTree_AddUnstructured_Call) Return(_a0 error) *MockFolderTree_AddUnstructured_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockFolderTree_AddUnstructured_Call) RunAndReturn(run func(*unstructured.Unstructured, string) error) *MockFolderTree_AddUnstructured_Call { + _c.Call.Return(run) + return _c +} + +// Count provides a mock function with no fields +func (_m *MockFolderTree) Count() int { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for Count") + } + + var r0 int + if rf, ok := ret.Get(0).(func() int); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(int) + } + + return r0 +} + +// MockFolderTree_Count_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Count' +type MockFolderTree_Count_Call struct { + *mock.Call +} + +// Count is a helper method to define mock.On call +func (_e *MockFolderTree_Expecter) Count() *MockFolderTree_Count_Call { + return &MockFolderTree_Count_Call{Call: _e.mock.On("Count")} +} + +func (_c *MockFolderTree_Count_Call) Run(run func()) *MockFolderTree_Count_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockFolderTree_Count_Call) Return(_a0 int) *MockFolderTree_Count_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockFolderTree_Count_Call) RunAndReturn(run func() int) *MockFolderTree_Count_Call { + _c.Call.Return(run) + return _c +} + +// DirPath provides a mock function with given fields: folder, baseFolder +func (_m *MockFolderTree) DirPath(folder string, baseFolder string) (Folder, bool) { + ret := _m.Called(folder, baseFolder) + + if len(ret) == 0 { + panic("no return value specified for DirPath") + } + + var r0 Folder + var r1 bool + if rf, ok := ret.Get(0).(func(string, string) (Folder, bool)); ok { + return rf(folder, baseFolder) + } + if rf, ok := ret.Get(0).(func(string, string) Folder); ok { + r0 = rf(folder, baseFolder) + } else { + r0 = ret.Get(0).(Folder) + } + + if rf, ok := ret.Get(1).(func(string, string) bool); ok { + r1 = rf(folder, baseFolder) + } else { + r1 = ret.Get(1).(bool) + } + + return r0, r1 +} + +// MockFolderTree_DirPath_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DirPath' +type MockFolderTree_DirPath_Call struct { + *mock.Call +} + +// DirPath is a helper method to define mock.On call +// - folder string +// - baseFolder string +func (_e *MockFolderTree_Expecter) DirPath(folder interface{}, baseFolder interface{}) *MockFolderTree_DirPath_Call { + return &MockFolderTree_DirPath_Call{Call: _e.mock.On("DirPath", folder, baseFolder)} +} + +func (_c *MockFolderTree_DirPath_Call) Run(run func(folder string, baseFolder string)) *MockFolderTree_DirPath_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string), args[1].(string)) + }) + return _c +} + +func (_c *MockFolderTree_DirPath_Call) Return(_a0 Folder, _a1 bool) *MockFolderTree_DirPath_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockFolderTree_DirPath_Call) RunAndReturn(run func(string, string) (Folder, bool)) *MockFolderTree_DirPath_Call { + _c.Call.Return(run) + return _c +} + +// In provides a mock function with given fields: folder +func (_m *MockFolderTree) In(folder string) bool { + ret := _m.Called(folder) + + if len(ret) == 0 { + panic("no return value specified for In") + } + + var r0 bool + if rf, ok := ret.Get(0).(func(string) bool); ok { + r0 = rf(folder) + } else { + r0 = ret.Get(0).(bool) + } + + return r0 +} + +// MockFolderTree_In_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'In' +type MockFolderTree_In_Call struct { + *mock.Call +} + +// In is a helper method to define mock.On call +// - folder string +func (_e *MockFolderTree_Expecter) In(folder interface{}) *MockFolderTree_In_Call { + return &MockFolderTree_In_Call{Call: _e.mock.On("In", folder)} +} + +func (_c *MockFolderTree_In_Call) Run(run func(folder string)) *MockFolderTree_In_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string)) + }) + return _c +} + +func (_c *MockFolderTree_In_Call) Return(_a0 bool) *MockFolderTree_In_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockFolderTree_In_Call) RunAndReturn(run func(string) bool) *MockFolderTree_In_Call { + _c.Call.Return(run) + return _c +} + +// Walk provides a mock function with given fields: ctx, fn +func (_m *MockFolderTree) Walk(ctx context.Context, fn WalkFunc) error { + ret := _m.Called(ctx, fn) + + if len(ret) == 0 { + panic("no return value specified for Walk") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, WalkFunc) error); ok { + r0 = rf(ctx, fn) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockFolderTree_Walk_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Walk' +type MockFolderTree_Walk_Call struct { + *mock.Call +} + +// Walk is a helper method to define mock.On call +// - ctx context.Context +// - fn WalkFunc +func (_e *MockFolderTree_Expecter) Walk(ctx interface{}, fn interface{}) *MockFolderTree_Walk_Call { + return &MockFolderTree_Walk_Call{Call: _e.mock.On("Walk", ctx, fn)} +} + +func (_c *MockFolderTree_Walk_Call) Run(run func(ctx context.Context, fn WalkFunc)) *MockFolderTree_Walk_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(WalkFunc)) + }) + return _c +} + +func (_c *MockFolderTree_Walk_Call) Return(_a0 error) *MockFolderTree_Walk_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockFolderTree_Walk_Call) RunAndReturn(run func(context.Context, WalkFunc) error) *MockFolderTree_Walk_Call { + _c.Call.Return(run) + return _c +} + +// NewMockFolderTree creates a new instance of MockFolderTree. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockFolderTree(t interface { + mock.TestingT + Cleanup(func()) +}) *MockFolderTree { + mock := &MockFolderTree{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/registry/apis/provisioning/resources/tree_test.go b/pkg/registry/apis/provisioning/resources/tree_test.go index e19a0980b3e..a98afbbbf3b 100644 --- a/pkg/registry/apis/provisioning/resources/tree_test.go +++ b/pkg/registry/apis/provisioning/resources/tree_test.go @@ -12,7 +12,7 @@ func TestFolderTree(t *testing.T) { } t.Run("empty tree", func(t *testing.T) { - tree := &FolderTree{ + tree := &folderTree{ tree: make(map[string]string), folders: make(map[string]Folder), } @@ -24,7 +24,7 @@ func TestFolderTree(t *testing.T) { }) t.Run("single directory in tree", func(t *testing.T) { - tree := &FolderTree{ + tree := &folderTree{ tree: map[string]string{"x": ""}, folders: map[string]Folder{"x": newFid("x", "X!")}, } @@ -45,7 +45,7 @@ func TestFolderTree(t *testing.T) { }) t.Run("simple nesting tree", func(t *testing.T) { - tree := &FolderTree{ + tree := &folderTree{ tree: map[string]string{"a": "b", "b": "c", "c": "x", "x": ""}, folders: map[string]Folder{ "x": newFid("x", "X!"), diff --git a/pkg/storage/legacysql/dualwrite/service_mock.go b/pkg/storage/legacysql/dualwrite/service_mock.go new file mode 100644 index 00000000000..264c19d7047 --- /dev/null +++ b/pkg/storage/legacysql/dualwrite/service_mock.go @@ -0,0 +1,374 @@ +// Code generated by mockery v2.52.4. DO NOT EDIT. + +package dualwrite + +import ( + context "context" + + rest "github.com/grafana/grafana/pkg/apiserver/rest" + mock "github.com/stretchr/testify/mock" + + schema "k8s.io/apimachinery/pkg/runtime/schema" +) + +// MockService is an autogenerated mock type for the Service type +type MockService struct { + mock.Mock +} + +type MockService_Expecter struct { + mock *mock.Mock +} + +func (_m *MockService) EXPECT() *MockService_Expecter { + return &MockService_Expecter{mock: &_m.Mock} +} + +// NewStorage provides a mock function with given fields: gr, legacy, storage +func (_m *MockService) NewStorage(gr schema.GroupResource, legacy rest.Storage, storage rest.Storage) (rest.Storage, error) { + ret := _m.Called(gr, legacy, storage) + + if len(ret) == 0 { + panic("no return value specified for NewStorage") + } + + var r0 rest.Storage + var r1 error + if rf, ok := ret.Get(0).(func(schema.GroupResource, rest.Storage, rest.Storage) (rest.Storage, error)); ok { + return rf(gr, legacy, storage) + } + if rf, ok := ret.Get(0).(func(schema.GroupResource, rest.Storage, rest.Storage) rest.Storage); ok { + r0 = rf(gr, legacy, storage) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(rest.Storage) + } + } + + if rf, ok := ret.Get(1).(func(schema.GroupResource, rest.Storage, rest.Storage) error); ok { + r1 = rf(gr, legacy, storage) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockService_NewStorage_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'NewStorage' +type MockService_NewStorage_Call struct { + *mock.Call +} + +// NewStorage is a helper method to define mock.On call +// - gr schema.GroupResource +// - legacy rest.Storage +// - storage rest.Storage +func (_e *MockService_Expecter) NewStorage(gr interface{}, legacy interface{}, storage interface{}) *MockService_NewStorage_Call { + return &MockService_NewStorage_Call{Call: _e.mock.On("NewStorage", gr, legacy, storage)} +} + +func (_c *MockService_NewStorage_Call) Run(run func(gr schema.GroupResource, legacy rest.Storage, storage rest.Storage)) *MockService_NewStorage_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(schema.GroupResource), args[1].(rest.Storage), args[2].(rest.Storage)) + }) + return _c +} + +func (_c *MockService_NewStorage_Call) Return(_a0 rest.Storage, _a1 error) *MockService_NewStorage_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockService_NewStorage_Call) RunAndReturn(run func(schema.GroupResource, rest.Storage, rest.Storage) (rest.Storage, error)) *MockService_NewStorage_Call { + _c.Call.Return(run) + return _c +} + +// ReadFromUnified provides a mock function with given fields: ctx, gr +func (_m *MockService) ReadFromUnified(ctx context.Context, gr schema.GroupResource) (bool, error) { + ret := _m.Called(ctx, gr) + + if len(ret) == 0 { + panic("no return value specified for ReadFromUnified") + } + + var r0 bool + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, schema.GroupResource) (bool, error)); ok { + return rf(ctx, gr) + } + if rf, ok := ret.Get(0).(func(context.Context, schema.GroupResource) bool); ok { + r0 = rf(ctx, gr) + } else { + r0 = ret.Get(0).(bool) + } + + if rf, ok := ret.Get(1).(func(context.Context, schema.GroupResource) error); ok { + r1 = rf(ctx, gr) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockService_ReadFromUnified_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ReadFromUnified' +type MockService_ReadFromUnified_Call struct { + *mock.Call +} + +// ReadFromUnified is a helper method to define mock.On call +// - ctx context.Context +// - gr schema.GroupResource +func (_e *MockService_Expecter) ReadFromUnified(ctx interface{}, gr interface{}) *MockService_ReadFromUnified_Call { + return &MockService_ReadFromUnified_Call{Call: _e.mock.On("ReadFromUnified", ctx, gr)} +} + +func (_c *MockService_ReadFromUnified_Call) Run(run func(ctx context.Context, gr schema.GroupResource)) *MockService_ReadFromUnified_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(schema.GroupResource)) + }) + return _c +} + +func (_c *MockService_ReadFromUnified_Call) Return(_a0 bool, _a1 error) *MockService_ReadFromUnified_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockService_ReadFromUnified_Call) RunAndReturn(run func(context.Context, schema.GroupResource) (bool, error)) *MockService_ReadFromUnified_Call { + _c.Call.Return(run) + return _c +} + +// ShouldManage provides a mock function with given fields: gr +func (_m *MockService) ShouldManage(gr schema.GroupResource) bool { + ret := _m.Called(gr) + + if len(ret) == 0 { + panic("no return value specified for ShouldManage") + } + + var r0 bool + if rf, ok := ret.Get(0).(func(schema.GroupResource) bool); ok { + r0 = rf(gr) + } else { + r0 = ret.Get(0).(bool) + } + + return r0 +} + +// MockService_ShouldManage_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ShouldManage' +type MockService_ShouldManage_Call struct { + *mock.Call +} + +// ShouldManage is a helper method to define mock.On call +// - gr schema.GroupResource +func (_e *MockService_Expecter) ShouldManage(gr interface{}) *MockService_ShouldManage_Call { + return &MockService_ShouldManage_Call{Call: _e.mock.On("ShouldManage", gr)} +} + +func (_c *MockService_ShouldManage_Call) Run(run func(gr schema.GroupResource)) *MockService_ShouldManage_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(schema.GroupResource)) + }) + return _c +} + +func (_c *MockService_ShouldManage_Call) Return(_a0 bool) *MockService_ShouldManage_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockService_ShouldManage_Call) RunAndReturn(run func(schema.GroupResource) bool) *MockService_ShouldManage_Call { + _c.Call.Return(run) + return _c +} + +// StartMigration provides a mock function with given fields: ctx, gr, key +func (_m *MockService) StartMigration(ctx context.Context, gr schema.GroupResource, key int64) (StorageStatus, error) { + ret := _m.Called(ctx, gr, key) + + if len(ret) == 0 { + panic("no return value specified for StartMigration") + } + + var r0 StorageStatus + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, schema.GroupResource, int64) (StorageStatus, error)); ok { + return rf(ctx, gr, key) + } + if rf, ok := ret.Get(0).(func(context.Context, schema.GroupResource, int64) StorageStatus); ok { + r0 = rf(ctx, gr, key) + } else { + r0 = ret.Get(0).(StorageStatus) + } + + if rf, ok := ret.Get(1).(func(context.Context, schema.GroupResource, int64) error); ok { + r1 = rf(ctx, gr, key) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockService_StartMigration_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'StartMigration' +type MockService_StartMigration_Call struct { + *mock.Call +} + +// StartMigration is a helper method to define mock.On call +// - ctx context.Context +// - gr schema.GroupResource +// - key int64 +func (_e *MockService_Expecter) StartMigration(ctx interface{}, gr interface{}, key interface{}) *MockService_StartMigration_Call { + return &MockService_StartMigration_Call{Call: _e.mock.On("StartMigration", ctx, gr, key)} +} + +func (_c *MockService_StartMigration_Call) Run(run func(ctx context.Context, gr schema.GroupResource, key int64)) *MockService_StartMigration_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(schema.GroupResource), args[2].(int64)) + }) + return _c +} + +func (_c *MockService_StartMigration_Call) Return(_a0 StorageStatus, _a1 error) *MockService_StartMigration_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockService_StartMigration_Call) RunAndReturn(run func(context.Context, schema.GroupResource, int64) (StorageStatus, error)) *MockService_StartMigration_Call { + _c.Call.Return(run) + return _c +} + +// Status provides a mock function with given fields: ctx, gr +func (_m *MockService) Status(ctx context.Context, gr schema.GroupResource) (StorageStatus, error) { + ret := _m.Called(ctx, gr) + + if len(ret) == 0 { + panic("no return value specified for Status") + } + + var r0 StorageStatus + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, schema.GroupResource) (StorageStatus, error)); ok { + return rf(ctx, gr) + } + if rf, ok := ret.Get(0).(func(context.Context, schema.GroupResource) StorageStatus); ok { + r0 = rf(ctx, gr) + } else { + r0 = ret.Get(0).(StorageStatus) + } + + if rf, ok := ret.Get(1).(func(context.Context, schema.GroupResource) error); ok { + r1 = rf(ctx, gr) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockService_Status_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Status' +type MockService_Status_Call struct { + *mock.Call +} + +// Status is a helper method to define mock.On call +// - ctx context.Context +// - gr schema.GroupResource +func (_e *MockService_Expecter) Status(ctx interface{}, gr interface{}) *MockService_Status_Call { + return &MockService_Status_Call{Call: _e.mock.On("Status", ctx, gr)} +} + +func (_c *MockService_Status_Call) Run(run func(ctx context.Context, gr schema.GroupResource)) *MockService_Status_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(schema.GroupResource)) + }) + return _c +} + +func (_c *MockService_Status_Call) Return(_a0 StorageStatus, _a1 error) *MockService_Status_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockService_Status_Call) RunAndReturn(run func(context.Context, schema.GroupResource) (StorageStatus, error)) *MockService_Status_Call { + _c.Call.Return(run) + return _c +} + +// Update provides a mock function with given fields: ctx, status +func (_m *MockService) Update(ctx context.Context, status StorageStatus) (StorageStatus, error) { + ret := _m.Called(ctx, status) + + if len(ret) == 0 { + panic("no return value specified for Update") + } + + var r0 StorageStatus + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, StorageStatus) (StorageStatus, error)); ok { + return rf(ctx, status) + } + if rf, ok := ret.Get(0).(func(context.Context, StorageStatus) StorageStatus); ok { + r0 = rf(ctx, status) + } else { + r0 = ret.Get(0).(StorageStatus) + } + + if rf, ok := ret.Get(1).(func(context.Context, StorageStatus) error); ok { + r1 = rf(ctx, status) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockService_Update_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Update' +type MockService_Update_Call struct { + *mock.Call +} + +// Update is a helper method to define mock.On call +// - ctx context.Context +// - status StorageStatus +func (_e *MockService_Expecter) Update(ctx interface{}, status interface{}) *MockService_Update_Call { + return &MockService_Update_Call{Call: _e.mock.On("Update", ctx, status)} +} + +func (_c *MockService_Update_Call) Run(run func(ctx context.Context, status StorageStatus)) *MockService_Update_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(StorageStatus)) + }) + return _c +} + +func (_c *MockService_Update_Call) Return(_a0 StorageStatus, _a1 error) *MockService_Update_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockService_Update_Call) RunAndReturn(run func(context.Context, StorageStatus) (StorageStatus, error)) *MockService_Update_Call { + _c.Call.Return(run) + return _c +} + +// NewMockService creates a new instance of MockService. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockService(t interface { + mock.TestingT + Cleanup(func()) +}) *MockService { + mock := &MockService{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/storage/legacysql/dualwrite/types.go b/pkg/storage/legacysql/dualwrite/types.go index a983432659c..0e103ce89c9 100644 --- a/pkg/storage/legacysql/dualwrite/types.go +++ b/pkg/storage/legacysql/dualwrite/types.go @@ -32,6 +32,9 @@ type StorageStatus struct { UpdateKey int64 `json:"update_key" xorm:"update_key"` } +// Service is a service for managing the dual write storage +// +//go:generate mockery --name Service --structname MockService --inpackage --filename service_mock.go --with-expecter type Service interface { ShouldManage(gr schema.GroupResource) bool