Merge pull request #6296 from Lyndon-Li/issue-fix-6258

Fix issue 6258
pull/6333/head
lyndon 2023-06-01 16:03:52 +08:00 committed by GitHub
commit 59965af775
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 551 additions and 0 deletions

View File

@ -0,0 +1 @@
Add UT cases for pkg/repository

View File

@ -132,3 +132,47 @@ func TestGetStorageDomainFromCloudName(t *testing.T) {
})
}
}
func TestGetRequiredValues(t *testing.T) {
testCases := []struct {
name string
mp map[string]string
keys []string
err string
}{
{
name: "with miss",
mp: map[string]string{
"key1": "value1",
},
keys: []string{"key1", "key2", "key3"},
err: "the following keys do not have values: key2, key3",
},
{
name: "without miss",
mp: map[string]string{
"key1": "value1",
"key2": "value2",
"key3": "value3",
},
keys: []string{"key1", "key2", "key3"},
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
err := getRequiredValues(func(key string) string {
if tc.mp == nil {
return ""
} else {
return tc.mp[key]
}
}, tc.keys...)
if err == nil {
assert.NoError(t, err)
} else {
assert.EqualError(t, err, tc.err)
}
})
}
}

View File

@ -0,0 +1,198 @@
/*
Copyright the Velero contributors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package repository
import (
"context"
"testing"
"time"
"github.com/stretchr/testify/assert"
"k8s.io/apimachinery/pkg/runtime"
"sigs.k8s.io/controller-runtime/pkg/client/fake"
velerov1 "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
velerotest "github.com/vmware-tanzu/velero/pkg/test"
)
func TestEnsureRepo(t *testing.T) {
bkRepoObj := newBackupRepository(velerov1.DefaultNamespace, BackupRepositoryKey{
VolumeNamespace: "fake-ns",
BackupLocation: "fake-bsl",
RepositoryType: "fake-repo-type",
})
bkRepoObj.Status.Phase = velerov1.BackupRepositoryPhaseReady
scheme := runtime.NewScheme()
velerov1.AddToScheme(scheme)
tests := []struct {
name string
namespace string
bsl string
repositoryType string
kubeClientObj []runtime.Object
runtimeScheme *runtime.Scheme
expectedRepo *velerov1.BackupRepository
err string
}{
{
name: "namespace is empty",
bsl: "fake-bsl",
repositoryType: "fake-repo-type",
err: "wrong parameters, namespace \"\", backup storage location \"fake-bsl\", repository type \"fake-repo-type\"",
},
{
name: "bsl is empty",
namespace: "fake-ns",
repositoryType: "fake-repo-type",
err: "wrong parameters, namespace \"fake-ns\", backup storage location \"\", repository type \"fake-repo-type\"",
},
{
name: "repositoryType is empty",
namespace: "fake-ns",
bsl: "fake-bsl",
err: "wrong parameters, namespace \"fake-ns\", backup storage location \"fake-bsl\", repository type \"\"",
},
{
name: "get repo fail",
namespace: "fake-ns",
bsl: "fake-bsl",
repositoryType: "fake-repo-type",
err: "error getting backup repository list: no kind is registered for the type v1.BackupRepositoryList in scheme \"pkg/runtime/scheme.go:100\"",
},
{
name: "success on existing repo",
namespace: "fake-ns",
bsl: "fake-bsl",
repositoryType: "fake-repo-type",
kubeClientObj: []runtime.Object{
bkRepoObj,
},
runtimeScheme: scheme,
expectedRepo: bkRepoObj,
},
{
name: "create fail",
namespace: "fake-ns",
bsl: "fake-bsl",
repositoryType: "fake-repo-type",
runtimeScheme: scheme,
err: "failed to wait BackupRepository: timed out waiting for the condition",
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
fakeClientBuilder := fake.NewClientBuilder()
if test.runtimeScheme != nil {
fakeClientBuilder = fakeClientBuilder.WithScheme(test.runtimeScheme)
}
fakeClient := fakeClientBuilder.WithRuntimeObjects(test.kubeClientObj...).Build()
ensurer := NewEnsurer(fakeClient, velerotest.NewLogger(), time.Millisecond)
repo, err := ensurer.EnsureRepo(context.Background(), velerov1.DefaultNamespace, test.namespace, test.bsl, test.repositoryType)
if err != nil {
assert.EqualError(t, err, test.err)
} else {
assert.NoError(t, err)
}
assert.Equal(t, test.expectedRepo, repo)
})
}
}
func TestCreateBackupRepositoryAndWait(t *testing.T) {
bkRepoObj := newBackupRepository(velerov1.DefaultNamespace, BackupRepositoryKey{
VolumeNamespace: "fake-ns",
BackupLocation: "fake-bsl",
RepositoryType: "fake-repo-type",
})
bkRepoObj.Status.Phase = velerov1.BackupRepositoryPhaseReady
scheme := runtime.NewScheme()
velerov1.AddToScheme(scheme)
tests := []struct {
name string
namespace string
bsl string
repositoryType string
kubeClientObj []runtime.Object
runtimeScheme *runtime.Scheme
expectedRepo *velerov1.BackupRepository
err string
}{
{
name: "create fail",
namespace: "fake-ns",
bsl: "fake-bsl",
repositoryType: "fake-repo-type",
err: "unable to create backup repository resource: no kind is registered for the type v1.BackupRepository in scheme \"pkg/runtime/scheme.go:100\"",
},
{
name: "get repo fail",
namespace: "fake-ns",
bsl: "fake-bsl",
repositoryType: "fake-repo-type",
kubeClientObj: []runtime.Object{
bkRepoObj,
},
runtimeScheme: scheme,
err: "failed to wait BackupRepository: more than one BackupRepository found for workload namespace \"fake-ns\", backup storage location \"fake-bsl\", repository type \"fake-repo-type\"",
},
{
name: "wait repo fail",
namespace: "fake-ns",
bsl: "fake-bsl",
repositoryType: "fake-repo-type",
runtimeScheme: scheme,
err: "failed to wait BackupRepository: timed out waiting for the condition",
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
fakeClientBuilder := fake.NewClientBuilder()
if test.runtimeScheme != nil {
fakeClientBuilder = fakeClientBuilder.WithScheme(test.runtimeScheme)
}
fakeClient := fakeClientBuilder.WithRuntimeObjects(test.kubeClientObj...).Build()
ensurer := NewEnsurer(fakeClient, velerotest.NewLogger(), time.Millisecond)
repo, err := ensurer.createBackupRepositoryAndWait(context.Background(), velerov1.DefaultNamespace, BackupRepositoryKey{
VolumeNamespace: test.namespace,
BackupLocation: test.bsl,
RepositoryType: test.repositoryType,
})
if err != nil {
assert.EqualError(t, err, test.err)
} else {
assert.NoError(t, err)
}
assert.Equal(t, test.expectedRepo, repo)
})
}
}

View File

@ -405,3 +405,311 @@ func TestShouldLog(t *testing.T) {
})
}
}
func TestOpenObject(t *testing.T) {
testCases := []struct {
name string
rawRepo *repomocks.DirectRepository
objectID string
retErr error
expectedErr string
}{
{
name: "raw repo is nil",
expectedErr: "repo is closed or not open",
},
{
name: "objectID is invalid",
rawRepo: repomocks.NewDirectRepository(t),
objectID: "fake-id",
expectedErr: "error to parse object ID from fake-id: malformed content ID: \"fake-id\": invalid content prefix",
},
{
name: "raw open fail",
rawRepo: repomocks.NewDirectRepository(t),
retErr: errors.New("fake-open-error"),
expectedErr: "error to open object: fake-open-error",
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
kr := &kopiaRepository{}
if tc.rawRepo != nil {
if tc.retErr != nil {
tc.rawRepo.On("OpenObject", mock.Anything, mock.Anything).Return(nil, tc.retErr)
}
kr.rawRepo = tc.rawRepo
}
_, err := kr.OpenObject(context.Background(), udmrepo.ID(tc.objectID))
if tc.expectedErr == "" {
assert.NoError(t, err)
} else {
assert.EqualError(t, err, tc.expectedErr)
}
})
}
}
func TestGetManifest(t *testing.T) {
testCases := []struct {
name string
rawRepo *repomocks.DirectRepository
retErr error
expectedErr string
}{
{
name: "raw repo is nil",
expectedErr: "repo is closed or not open",
},
{
name: "raw get fail",
rawRepo: repomocks.NewDirectRepository(t),
retErr: errors.New("fake-get-error"),
expectedErr: "error to get manifest: fake-get-error",
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
kr := &kopiaRepository{}
if tc.rawRepo != nil {
if tc.retErr != nil {
tc.rawRepo.On("GetManifest", mock.Anything, mock.Anything, mock.Anything).Return(nil, tc.retErr)
}
kr.rawRepo = tc.rawRepo
}
err := kr.GetManifest(context.Background(), udmrepo.ID(""), &udmrepo.RepoManifest{})
if tc.expectedErr == "" {
assert.NoError(t, err)
} else {
assert.EqualError(t, err, tc.expectedErr)
}
})
}
}
func TestFindManifests(t *testing.T) {
testCases := []struct {
name string
rawRepo *repomocks.DirectRepository
retErr error
expectedErr string
}{
{
name: "raw repo is nil",
expectedErr: "repo is closed or not open",
},
{
name: "raw find fail",
rawRepo: repomocks.NewDirectRepository(t),
retErr: errors.New("fake-find-error"),
expectedErr: "error to find manifests: fake-find-error",
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
kr := &kopiaRepository{}
if tc.rawRepo != nil {
tc.rawRepo.On("FindManifests", mock.Anything, mock.Anything).Return(nil, tc.retErr)
kr.rawRepo = tc.rawRepo
}
_, err := kr.FindManifests(context.Background(), udmrepo.ManifestFilter{})
if tc.expectedErr == "" {
assert.NoError(t, err)
} else {
assert.EqualError(t, err, tc.expectedErr)
}
})
}
}
func TestClose(t *testing.T) {
testCases := []struct {
name string
rawRepo *repomocks.DirectRepository
rawWriter *repomocks.DirectRepositoryWriter
rawRepoRetErr error
rawWriterRetErr error
expectedErr string
}{
{
name: "both nil",
},
{
name: "writer is not nil",
rawWriter: repomocks.NewDirectRepositoryWriter(t),
},
{
name: "repo is not nil",
rawRepo: repomocks.NewDirectRepository(t),
},
{
name: "writer close error",
rawWriter: repomocks.NewDirectRepositoryWriter(t),
rawWriterRetErr: errors.New("fake-writer-close-error"),
expectedErr: "error to close repo writer: fake-writer-close-error",
},
{
name: "repo is not nil",
rawRepo: repomocks.NewDirectRepository(t),
rawRepoRetErr: errors.New("fake-repo-close-error"),
expectedErr: "error to close repo: fake-repo-close-error",
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
kr := &kopiaRepository{}
if tc.rawRepo != nil {
tc.rawRepo.On("Close", mock.Anything).Return(tc.rawRepoRetErr)
kr.rawRepo = tc.rawRepo
}
if tc.rawWriter != nil {
tc.rawWriter.On("Close", mock.Anything).Return(tc.rawWriterRetErr)
kr.rawWriter = tc.rawWriter
}
err := kr.Close(context.Background())
if tc.expectedErr == "" {
assert.NoError(t, err)
} else {
assert.EqualError(t, err, tc.expectedErr)
}
})
}
}
func TestPutManifest(t *testing.T) {
testCases := []struct {
name string
rawWriter *repomocks.DirectRepositoryWriter
rawWriterRetErr error
expectedErr string
}{
{
name: "raw writer is nil",
expectedErr: "repo writer is closed or not open",
},
{
name: "raw put fail",
rawWriter: repomocks.NewDirectRepositoryWriter(t),
rawWriterRetErr: errors.New("fake-writer-put-error"),
expectedErr: "error to put manifest: fake-writer-put-error",
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
kr := &kopiaRepository{}
if tc.rawWriter != nil {
tc.rawWriter.On("PutManifest", mock.Anything, mock.Anything, mock.Anything).Return(manifest.ID(""), tc.rawWriterRetErr)
kr.rawWriter = tc.rawWriter
}
_, err := kr.PutManifest(context.Background(), udmrepo.RepoManifest{
Metadata: &udmrepo.ManifestEntryMetadata{},
})
if tc.expectedErr == "" {
assert.NoError(t, err)
} else {
assert.EqualError(t, err, tc.expectedErr)
}
})
}
}
func TestDeleteManifest(t *testing.T) {
testCases := []struct {
name string
rawWriter *repomocks.DirectRepositoryWriter
rawWriterRetErr error
expectedErr string
}{
{
name: "raw writer is nil",
expectedErr: "repo writer is closed or not open",
},
{
name: "raw delete fail",
rawWriter: repomocks.NewDirectRepositoryWriter(t),
rawWriterRetErr: errors.New("fake-writer-delete-error"),
expectedErr: "error to delete manifest: fake-writer-delete-error",
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
kr := &kopiaRepository{}
if tc.rawWriter != nil {
tc.rawWriter.On("DeleteManifest", mock.Anything, mock.Anything).Return(tc.rawWriterRetErr)
kr.rawWriter = tc.rawWriter
}
err := kr.DeleteManifest(context.Background(), udmrepo.ID(""))
if tc.expectedErr == "" {
assert.NoError(t, err)
} else {
assert.EqualError(t, err, tc.expectedErr)
}
})
}
}
func TestFlush(t *testing.T) {
testCases := []struct {
name string
rawWriter *repomocks.DirectRepositoryWriter
rawWriterRetErr error
expectedErr string
}{
{
name: "raw writer is nil",
expectedErr: "repo writer is closed or not open",
},
{
name: "raw flush fail",
rawWriter: repomocks.NewDirectRepositoryWriter(t),
rawWriterRetErr: errors.New("fake-writer-flush-error"),
expectedErr: "error to flush repo: fake-writer-flush-error",
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
kr := &kopiaRepository{}
if tc.rawWriter != nil {
tc.rawWriter.On("Flush", mock.Anything).Return(tc.rawWriterRetErr)
kr.rawWriter = tc.rawWriter
}
err := kr.Flush(context.Background())
if tc.expectedErr == "" {
assert.NoError(t, err)
} else {
assert.EqualError(t, err, tc.expectedErr)
}
})
}
}