Revert "Add some unit test coverage"

This reverts commit 420c9674d2.
This commit is contained in:
Roberto Jimenez Sanchez 2025-02-14 13:04:57 +01:00
parent d8e0930069
commit f7eca41957
No known key found for this signature in database
6 changed files with 4 additions and 886 deletions

View File

@ -1,52 +0,0 @@
package repository
import (
"context"
"testing"
"time"
"github.com/stretchr/testify/require"
)
func TestAuthorSignature(t *testing.T) {
t.Run("should store and retrieve author signature", func(t *testing.T) {
expected := CommitSignature{
Name: "John Doe",
Email: "john@example.com",
When: time.Date(2024, 1, 1, 12, 0, 0, 0, time.UTC),
}
ctx := context.Background()
ctx = WithAuthorSignature(ctx, expected)
result := GetAuthorSignature(ctx)
require.NotNil(t, result)
require.Equal(t, expected.Name, result.Name)
require.Equal(t, expected.Email, result.Email)
require.Equal(t, expected.When, result.When)
})
t.Run("should return nil when no signature is set", func(t *testing.T) {
ctx := context.Background()
result := GetAuthorSignature(ctx)
require.Nil(t, result)
})
t.Run("should return copy of signature", func(t *testing.T) {
original := CommitSignature{
Name: "John Doe",
Email: "john@example.com",
When: time.Now(),
}
ctx := context.Background()
ctx = WithAuthorSignature(ctx, original)
result1 := GetAuthorSignature(ctx)
result2 := GetAuthorSignature(ctx)
require.NotNil(t, result1)
require.NotNil(t, result2)
require.NotSame(t, result1, result2)
})
}

View File

@ -1,4 +1,4 @@
// Code generated by mockery v2.50.0. DO NOT EDIT.
// Code generated by mockery v2.49.0. DO NOT EDIT.
package github
@ -202,17 +202,9 @@ func (_m *MockClient) CreateWebhook(ctx context.Context, owner string, repositor
var r0 WebhookConfig
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, string, string, WebhookConfig) (WebhookConfig, error)); ok {
return rf(ctx, owner, repository, cfg)
}
if rf, ok := ret.Get(0).(func(context.Context, string, string, WebhookConfig) WebhookConfig); ok {
r0 = rf(ctx, owner, repository, cfg)
r0, r1 = rf(ctx, owner, repository, cfg)
} else {
r0 = ret.Get(0).(WebhookConfig)
}
if rf, ok := ret.Get(1).(func(context.Context, string, string, WebhookConfig) error); ok {
r1 = rf(ctx, owner, repository, cfg)
} else {
r1 = ret.Error(1)
}
@ -534,7 +526,8 @@ func (_m *MockClient) UpdateFile(ctx context.Context, owner string, repository s
func NewMockClient(t interface {
mock.TestingT
Cleanup(func())
}) *MockClient {
},
) *MockClient {
mock := &MockClient{}
mock.Mock.Test(t)

View File

@ -1,193 +0,0 @@
package github
import (
"context"
"net/http"
"testing"
"github.com/google/go-github/v66/github"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
apierrors "k8s.io/apimachinery/pkg/api/errors"
)
func TestIsAuthenticated(t *testing.T) {
tests := []struct {
name string
statusCode int
wantErr error
}{
{
name: "success",
statusCode: http.StatusOK,
wantErr: nil,
},
{
name: "unauthorized",
statusCode: http.StatusUnauthorized,
wantErr: apierrors.NewUnauthorized("token is invalid or expired"),
},
{
name: "forbidden",
statusCode: http.StatusForbidden,
wantErr: apierrors.NewUnauthorized("token is revoked or has insufficient permissions"),
},
{
name: "service unavailable",
statusCode: http.StatusServiceUnavailable,
wantErr: ErrServiceUnavailable,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
client := newMockClient(t, mockClientOpts{
statusCode: tt.statusCode,
})
impl := NewRealClient(client)
err := impl.IsAuthenticated(context.Background())
if tt.wantErr != nil {
assert.Equal(t, tt.wantErr, err)
} else {
assert.NoError(t, err)
}
})
}
}
func TestRepoExists(t *testing.T) {
tests := []struct {
name string
statusCode int
want bool
wantErr bool
}{
{
name: "repo exists",
statusCode: http.StatusOK,
want: true,
wantErr: false,
},
{
name: "repo does not exist",
statusCode: http.StatusNotFound,
want: false,
wantErr: false,
},
{
name: "error response",
statusCode: http.StatusInternalServerError,
want: false,
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
client := newMockClient(t, mockClientOpts{
statusCode: tt.statusCode,
})
impl := NewRealClient(client)
got, err := impl.RepoExists(context.Background(), "owner", "repo")
if tt.wantErr {
assert.Error(t, err)
return
}
assert.NoError(t, err)
assert.Equal(t, tt.want, got)
})
}
}
func TestGetContents(t *testing.T) {
tests := []struct {
name string
path string
mockResponse interface{}
statusCode int
wantFile bool
wantDir bool
wantErr error
}{
{
name: "get file contents",
path: "path/to/file.txt",
mockResponse: &github.RepositoryContent{
Type: github.String("file"),
Content: github.String("content"),
},
statusCode: http.StatusOK,
wantFile: true,
wantDir: false,
},
{
name: "get directory contents",
path: "path/to/dir",
mockResponse: []*github.RepositoryContent{
{
Type: github.String("dir"),
Path: github.String("subdir"),
},
{
Type: github.String("file"),
Path: github.String("file.txt"),
},
},
statusCode: http.StatusOK,
wantFile: false,
wantDir: true,
},
{
name: "path traversal attempt",
path: "../secret",
wantErr: ErrPathTraversalDisallowed,
},
{
name: "not found",
path: "nonexistent",
statusCode: http.StatusNotFound,
wantErr: ErrResourceNotFound,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
client := newMockClient(t, mockClientOpts{
statusCode: tt.statusCode,
mockResponse: tt.mockResponse,
})
impl := NewRealClient(client)
file, dir, err := impl.GetContents(context.Background(), "owner", "repo", tt.path, "main")
if tt.wantErr != nil {
assert.Equal(t, tt.wantErr, err)
return
}
require.NoError(t, err)
if tt.wantFile {
assert.NotNil(t, file)
assert.Nil(t, dir)
}
if tt.wantDir {
assert.Nil(t, file)
assert.NotNil(t, dir)
}
})
}
}
// Mock client implementation
type mockClientOpts struct {
statusCode int
mockResponse interface{}
}
func newMockClient(_ *testing.T, _ mockClientOpts) *github.Client {
// Create a mock client that returns the specified status code and response
client := github.NewClient(nil)
// TODO: Configure mock client with opts.statusCode and opts.mockResponse
return client
}

View File

@ -47,7 +47,6 @@ type FileTreeEntry struct {
Blob bool
}
//go:generate mockery --name Repository --structname MockRepository --inpackage --filename repository_mock.go
type Repository interface {
// The saved Kubernetes object.
Config() *provisioning.Repository

View File

@ -1,295 +0,0 @@
// Code generated by mockery v2.50.0. DO NOT EDIT.
package repository
import (
context "context"
http "net/http"
field "k8s.io/apimachinery/pkg/util/validation/field"
mock "github.com/stretchr/testify/mock"
v0alpha1 "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1"
)
// MockRepository is an autogenerated mock type for the Repository type
type MockRepository struct {
mock.Mock
}
// Config provides a mock function with no fields
func (_m *MockRepository) Config() *v0alpha1.Repository {
ret := _m.Called()
if len(ret) == 0 {
panic("no return value specified for Config")
}
var r0 *v0alpha1.Repository
if rf, ok := ret.Get(0).(func() *v0alpha1.Repository); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*v0alpha1.Repository)
}
}
return r0
}
// Create provides a mock function with given fields: ctx, path, ref, data, message
func (_m *MockRepository) Create(ctx context.Context, path string, ref string, data []byte, message string) error {
ret := _m.Called(ctx, path, ref, data, message)
if len(ret) == 0 {
panic("no return value specified for Create")
}
var r0 error
if rf, ok := ret.Get(0).(func(context.Context, string, string, []byte, string) error); ok {
r0 = rf(ctx, path, ref, data, message)
} else {
r0 = ret.Error(0)
}
return r0
}
// Delete provides a mock function with given fields: ctx, path, ref, message
func (_m *MockRepository) Delete(ctx context.Context, path string, ref string, message string) error {
ret := _m.Called(ctx, path, ref, message)
if len(ret) == 0 {
panic("no return value specified for Delete")
}
var r0 error
if rf, ok := ret.Get(0).(func(context.Context, string, string, string) error); ok {
r0 = rf(ctx, path, ref, message)
} else {
r0 = ret.Error(0)
}
return r0
}
// History provides a mock function with given fields: ctx, path, ref
func (_m *MockRepository) History(ctx context.Context, path string, ref string) ([]v0alpha1.HistoryItem, error) {
ret := _m.Called(ctx, path, ref)
if len(ret) == 0 {
panic("no return value specified for History")
}
var r0 []v0alpha1.HistoryItem
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, string, string) ([]v0alpha1.HistoryItem, error)); ok {
return rf(ctx, path, ref)
}
if rf, ok := ret.Get(0).(func(context.Context, string, string) []v0alpha1.HistoryItem); ok {
r0 = rf(ctx, path, ref)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]v0alpha1.HistoryItem)
}
}
if rf, ok := ret.Get(1).(func(context.Context, string, string) error); ok {
r1 = rf(ctx, path, ref)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// Read provides a mock function with given fields: ctx, path, ref
func (_m *MockRepository) Read(ctx context.Context, path string, ref string) (*FileInfo, error) {
ret := _m.Called(ctx, path, ref)
if len(ret) == 0 {
panic("no return value specified for Read")
}
var r0 *FileInfo
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, string, string) (*FileInfo, error)); ok {
return rf(ctx, path, ref)
}
if rf, ok := ret.Get(0).(func(context.Context, string, string) *FileInfo); ok {
r0 = rf(ctx, path, ref)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*FileInfo)
}
}
if rf, ok := ret.Get(1).(func(context.Context, string, string) error); ok {
r1 = rf(ctx, path, ref)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// ReadTree provides a mock function with given fields: ctx, ref
func (_m *MockRepository) ReadTree(ctx context.Context, ref string) ([]FileTreeEntry, error) {
ret := _m.Called(ctx, ref)
if len(ret) == 0 {
panic("no return value specified for ReadTree")
}
var r0 []FileTreeEntry
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, string) ([]FileTreeEntry, error)); ok {
return rf(ctx, ref)
}
if rf, ok := ret.Get(0).(func(context.Context, string) []FileTreeEntry); ok {
r0 = rf(ctx, ref)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]FileTreeEntry)
}
}
if rf, ok := ret.Get(1).(func(context.Context, string) error); ok {
r1 = rf(ctx, ref)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// Test provides a mock function with given fields: ctx
func (_m *MockRepository) Test(ctx context.Context) (*v0alpha1.TestResults, error) {
ret := _m.Called(ctx)
if len(ret) == 0 {
panic("no return value specified for Test")
}
var r0 *v0alpha1.TestResults
var r1 error
if rf, ok := ret.Get(0).(func(context.Context) (*v0alpha1.TestResults, error)); ok {
return rf(ctx)
}
if rf, ok := ret.Get(0).(func(context.Context) *v0alpha1.TestResults); ok {
r0 = rf(ctx)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*v0alpha1.TestResults)
}
}
if rf, ok := ret.Get(1).(func(context.Context) error); ok {
r1 = rf(ctx)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// Update provides a mock function with given fields: ctx, path, ref, data, message
func (_m *MockRepository) Update(ctx context.Context, path string, ref string, data []byte, message string) error {
ret := _m.Called(ctx, path, ref, data, message)
if len(ret) == 0 {
panic("no return value specified for Update")
}
var r0 error
if rf, ok := ret.Get(0).(func(context.Context, string, string, []byte, string) error); ok {
r0 = rf(ctx, path, ref, data, message)
} else {
r0 = ret.Error(0)
}
return r0
}
// Validate provides a mock function with no fields
func (_m *MockRepository) Validate() field.ErrorList {
ret := _m.Called()
if len(ret) == 0 {
panic("no return value specified for Validate")
}
var r0 field.ErrorList
if rf, ok := ret.Get(0).(func() field.ErrorList); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(field.ErrorList)
}
}
return r0
}
// Webhook provides a mock function with given fields: ctx, req
func (_m *MockRepository) Webhook(ctx context.Context, req *http.Request) (*v0alpha1.WebhookResponse, error) {
ret := _m.Called(ctx, req)
if len(ret) == 0 {
panic("no return value specified for Webhook")
}
var r0 *v0alpha1.WebhookResponse
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, *http.Request) (*v0alpha1.WebhookResponse, error)); ok {
return rf(ctx, req)
}
if rf, ok := ret.Get(0).(func(context.Context, *http.Request) *v0alpha1.WebhookResponse); ok {
r0 = rf(ctx, req)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*v0alpha1.WebhookResponse)
}
}
if rf, ok := ret.Get(1).(func(context.Context, *http.Request) error); ok {
r1 = rf(ctx, req)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// Write provides a mock function with given fields: ctx, path, ref, data, message
func (_m *MockRepository) Write(ctx context.Context, path string, ref string, data []byte, message string) error {
ret := _m.Called(ctx, path, ref, data, message)
if len(ret) == 0 {
panic("no return value specified for Write")
}
var r0 error
if rf, ok := ret.Get(0).(func(context.Context, string, string, []byte, string) error); ok {
r0 = rf(ctx, path, ref, data, message)
} else {
r0 = ret.Error(0)
}
return r0
}
// NewMockRepository creates a new instance of MockRepository. 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 NewMockRepository(t interface {
mock.TestingT
Cleanup(func())
}) *MockRepository {
mock := &MockRepository{}
mock.Mock.Test(t)
t.Cleanup(func() { mock.AssertExpectations(t) })
return mock
}

View File

@ -1,334 +0,0 @@
package repository
import (
"context"
"fmt"
"net/http"
"testing"
provisioning "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/validation/field"
)
func TestValidateRepository(t *testing.T) {
tests := []struct {
name string
repository *MockRepository
expectedErrs int
validateError func(t *testing.T, errors field.ErrorList)
}{
{
name: "valid repository",
repository: func() *MockRepository {
m := NewMockRepository(t)
m.On("Config").Return(&provisioning.Repository{
Spec: provisioning.RepositorySpec{
Title: "Test Repo",
},
})
m.On("Validate").Return(field.ErrorList{})
return m
}(),
expectedErrs: 0,
},
{
name: "missing title",
repository: func() *MockRepository {
m := NewMockRepository(t)
m.On("Config").Return(&provisioning.Repository{
Spec: provisioning.RepositorySpec{},
})
m.On("Validate").Return(field.ErrorList{})
return m
}(),
expectedErrs: 1,
validateError: func(t *testing.T, errors field.ErrorList) {
require.Contains(t, errors.ToAggregate().Error(), "spec.title: Required value")
},
},
{
name: "sync enabled without target",
repository: func() *MockRepository {
m := NewMockRepository(t)
m.On("Config").Return(&provisioning.Repository{
Spec: provisioning.RepositorySpec{
Title: "Test Repo",
Sync: provisioning.SyncOptions{
Enabled: true,
IntervalSeconds: 10,
},
},
})
m.On("Validate").Return(field.ErrorList{})
return m
}(),
expectedErrs: 1,
validateError: func(t *testing.T, errors field.ErrorList) {
require.Contains(t, errors.ToAggregate().Error(), "spec.sync.target: Required value")
},
},
{
name: "sync interval too low",
repository: func() *MockRepository {
m := NewMockRepository(t)
m.On("Config").Return(&provisioning.Repository{
Spec: provisioning.RepositorySpec{
Title: "Test Repo",
Sync: provisioning.SyncOptions{
Enabled: true,
Target: "test",
IntervalSeconds: 5,
},
},
})
m.On("Validate").Return(field.ErrorList{})
return m
}(),
expectedErrs: 1,
validateError: func(t *testing.T, errors field.ErrorList) {
require.Contains(t, errors.ToAggregate().Error(), "spec.sync.intervalSeconds: Invalid value")
},
},
{
name: "reserved name",
repository: func() *MockRepository {
m := NewMockRepository(t)
m.On("Config").Return(&provisioning.Repository{
ObjectMeta: metav1.ObjectMeta{
Name: "sql",
},
Spec: provisioning.RepositorySpec{
Title: "Test Repo",
},
})
m.On("Validate").Return(field.ErrorList{})
return m
}(),
expectedErrs: 1,
validateError: func(t *testing.T, errors field.ErrorList) {
require.Contains(t, errors.ToAggregate().Error(), "metadata.name: Invalid value")
},
},
{
name: "mismatched local config",
repository: func() *MockRepository {
m := NewMockRepository(t)
m.On("Config").Return(&provisioning.Repository{
Spec: provisioning.RepositorySpec{
Title: "Test Repo",
Type: provisioning.GitHubRepositoryType,
Local: &provisioning.LocalRepositoryConfig{},
},
})
m.On("Validate").Return(field.ErrorList{})
return m
}(),
expectedErrs: 1,
validateError: func(t *testing.T, errors field.ErrorList) {
require.Contains(t, errors.ToAggregate().Error(), "spec.local: Invalid value")
},
},
{
name: "mismatched github config",
repository: func() *MockRepository {
m := NewMockRepository(t)
m.On("Config").Return(&provisioning.Repository{
Spec: provisioning.RepositorySpec{
Title: "Test Repo",
Type: provisioning.LocalRepositoryType,
GitHub: &provisioning.GitHubRepositoryConfig{},
},
})
m.On("Validate").Return(field.ErrorList{})
return m
}(),
expectedErrs: 1,
validateError: func(t *testing.T, errors field.ErrorList) {
require.Contains(t, errors.ToAggregate().Error(), "spec.github: Invalid value")
},
},
{
name: "mismatched s3 config",
repository: func() *MockRepository {
m := NewMockRepository(t)
m.On("Config").Return(&provisioning.Repository{
Spec: provisioning.RepositorySpec{
Title: "Test Repo",
Type: provisioning.LocalRepositoryType,
S3: &provisioning.S3RepositoryConfig{},
},
})
m.On("Validate").Return(field.ErrorList{})
return m
}(),
expectedErrs: 1,
validateError: func(t *testing.T, errors field.ErrorList) {
require.Contains(t, errors.ToAggregate().Error(), "spec.s3: Invalid value")
},
},
{
name: "multiple validation errors",
repository: func() *MockRepository {
m := NewMockRepository(t)
m.On("Config").Return(&provisioning.Repository{
ObjectMeta: metav1.ObjectMeta{
Name: "sql",
},
Spec: provisioning.RepositorySpec{
Sync: provisioning.SyncOptions{
Enabled: true,
IntervalSeconds: 5,
},
},
})
m.On("Validate").Return(field.ErrorList{})
return m
}(),
expectedErrs: 4, // Updated from 3 to 4 to match actual errors:
// 1. missing title
// 2. sync target missing
// 3. sync interval too low
// 4. reserved name
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
errors := ValidateRepository(tt.repository)
require.Len(t, errors, tt.expectedErrs)
if tt.validateError != nil {
tt.validateError(t, errors)
}
})
}
}
func TestTestRepository(t *testing.T) {
tests := []struct {
name string
repository *MockRepository
expectedCode int
expectedErrs []string
expectedError error
}{
{
name: "validation fails",
repository: func() *MockRepository {
m := NewMockRepository(t)
m.On("Config").Return(&provisioning.Repository{
Spec: provisioning.RepositorySpec{
// Missing required title
},
})
m.On("Validate").Return(field.ErrorList{})
return m
}(),
expectedCode: http.StatusUnprocessableEntity,
expectedErrs: []string{"spec.title: Required value: a repository title must be given"},
},
{
name: "test passes",
repository: func() *MockRepository {
m := NewMockRepository(t)
m.On("Config").Return(&provisioning.Repository{
Spec: provisioning.RepositorySpec{
Title: "Test Repo",
},
})
m.On("Validate").Return(field.ErrorList{})
m.On("Test", mock.Anything).Return(&provisioning.TestResults{
Code: http.StatusOK,
Success: true,
}, nil)
return m
}(),
expectedCode: http.StatusOK,
expectedErrs: nil,
},
{
name: "test fails with error",
repository: func() *MockRepository {
m := NewMockRepository(t)
m.On("Config").Return(&provisioning.Repository{
Spec: provisioning.RepositorySpec{
Title: "Test Repo",
},
})
m.On("Validate").Return(field.ErrorList{})
m.On("Test", mock.Anything).Return(nil, fmt.Errorf("test error"))
return m
}(),
expectedError: fmt.Errorf("test error"),
},
{
name: "test fails with results",
repository: func() *MockRepository {
m := NewMockRepository(t)
m.On("Config").Return(&provisioning.Repository{
Spec: provisioning.RepositorySpec{
Title: "Test Repo",
},
})
m.On("Validate").Return(field.ErrorList{})
m.On("Test", mock.Anything).Return(&provisioning.TestResults{
Code: http.StatusBadRequest,
Success: false,
Errors: []string{"test failed"},
}, nil)
return m
}(),
expectedCode: http.StatusBadRequest,
expectedErrs: []string{"test failed"},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
results, err := TestRepository(context.Background(), tt.repository)
if tt.expectedError != nil {
require.Error(t, err)
require.Equal(t, tt.expectedError.Error(), err.Error())
return
}
require.NoError(t, err)
require.NotNil(t, results)
require.Equal(t, tt.expectedCode, results.Code)
if tt.expectedErrs != nil {
require.Equal(t, tt.expectedErrs, results.Errors)
require.False(t, results.Success)
} else {
require.True(t, results.Success)
require.Empty(t, results.Errors)
}
})
}
}
func TestTester_TestRepository(t *testing.T) {
tester := &Tester{}
// Test that it properly delegates to TestRepository
repository := NewMockRepository(t)
repository.On("Config").Return(&provisioning.Repository{
Spec: provisioning.RepositorySpec{
Title: "Test Repo",
},
})
repository.On("Validate").Return(field.ErrorList{})
repository.On("Test", mock.Anything).Return(&provisioning.TestResults{
Code: http.StatusOK,
Success: true,
}, nil)
results, err := tester.TestRepository(context.Background(), repository)
require.NoError(t, err)
require.NotNil(t, results)
require.Equal(t, http.StatusOK, results.Code)
require.True(t, results.Success)
}