mirror of
https://github.com/vmware-tanzu/velero.git
synced 2025-12-23 06:15:21 +00:00
351 lines
10 KiB
Go
351 lines
10 KiB
Go
/*
|
|
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 kopia
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/kopia/kopia/repo"
|
|
"github.com/kopia/kopia/repo/content"
|
|
"github.com/kopia/kopia/repo/manifest"
|
|
"github.com/kopia/kopia/repo/object"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/mock"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/vmware-tanzu/velero/pkg/repository/udmrepo"
|
|
"github.com/vmware-tanzu/velero/pkg/repository/udmrepo/mocks"
|
|
)
|
|
|
|
func TestShimRepo(t *testing.T) {
|
|
ctx := t.Context()
|
|
backupRepo := &mocks.BackupRepo{}
|
|
backupRepo.On("Time").Return(time.Time{})
|
|
shim := NewShimRepo(backupRepo)
|
|
// All below calls put together for the implementation are empty or just very simple, and just want to cover testing
|
|
// If wanting to write unit tests for some functions could remove it and with writing new function alone
|
|
shim.VerifyObject(ctx, object.ID{})
|
|
shim.Time()
|
|
shim.ClientOptions()
|
|
shim.Refresh(ctx)
|
|
shim.ContentInfo(ctx, content.ID{})
|
|
shim.PrefetchContents(ctx, []content.ID{}, "hint")
|
|
shim.PrefetchObjects(ctx, []object.ID{}, "hint")
|
|
shim.UpdateDescription("desc")
|
|
shim.NewWriter(ctx, repo.WriteSessionOptions{})
|
|
shim.OnSuccessfulFlush(func(ctx context.Context, w repo.RepositoryWriter) error { return nil })
|
|
|
|
backupRepo.On("Close", mock.Anything).Return(nil)
|
|
NewShimRepo(backupRepo).Close(ctx)
|
|
|
|
var id udmrepo.ID
|
|
backupRepo.On("PutManifest", mock.Anything, mock.Anything).Return(id, nil)
|
|
NewShimRepo(backupRepo).PutManifest(ctx, map[string]string{}, nil)
|
|
|
|
var mf manifest.ID
|
|
backupRepo.On("DeleteManifest", mock.Anything, mock.Anything).Return(nil)
|
|
NewShimRepo(backupRepo).DeleteManifest(ctx, mf)
|
|
|
|
backupRepo.On("Flush", mock.Anything).Return(nil)
|
|
NewShimRepo(backupRepo).Flush(ctx)
|
|
|
|
backupRepo.On("NewObjectWriter", mock.Anything, mock.Anything).Return(nil)
|
|
NewShimRepo(backupRepo).NewObjectWriter(ctx, object.WriterOptions{})
|
|
}
|
|
|
|
func TestOpenObject(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
backupRepo *mocks.BackupRepo
|
|
isOpenObjectError bool
|
|
isReaderNil bool
|
|
}{
|
|
{
|
|
name: "Success",
|
|
backupRepo: func() *mocks.BackupRepo {
|
|
backupRepo := &mocks.BackupRepo{}
|
|
backupRepo.On("OpenObject", mock.Anything, mock.Anything).Return(&shimObjectReader{}, nil)
|
|
return backupRepo
|
|
}(),
|
|
},
|
|
{
|
|
name: "Open object error",
|
|
backupRepo: func() *mocks.BackupRepo {
|
|
backupRepo := &mocks.BackupRepo{}
|
|
backupRepo.On("OpenObject", mock.Anything, mock.Anything).Return(&shimObjectReader{}, errors.New("Error open object"))
|
|
return backupRepo
|
|
}(),
|
|
isOpenObjectError: true,
|
|
},
|
|
{
|
|
name: "Get nil reader",
|
|
backupRepo: func() *mocks.BackupRepo {
|
|
backupRepo := &mocks.BackupRepo{}
|
|
backupRepo.On("OpenObject", mock.Anything, mock.Anything).Return(nil, nil)
|
|
return backupRepo
|
|
}(),
|
|
isReaderNil: true,
|
|
},
|
|
}
|
|
|
|
for _, tc := range tests {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
ctx := t.Context()
|
|
reader, err := NewShimRepo(tc.backupRepo).OpenObject(ctx, object.ID{})
|
|
if tc.isOpenObjectError {
|
|
require.ErrorContains(t, err, "failed to open object")
|
|
} else if tc.isReaderNil {
|
|
assert.Nil(t, reader)
|
|
} else {
|
|
assert.NotNil(t, reader)
|
|
assert.NoError(t, err)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestFindManifests(t *testing.T) {
|
|
meta := []*udmrepo.ManifestEntryMetadata{}
|
|
tests := []struct {
|
|
name string
|
|
backupRepo *mocks.BackupRepo
|
|
isGetManifestError bool
|
|
}{
|
|
{
|
|
name: "Success",
|
|
backupRepo: func() *mocks.BackupRepo {
|
|
backupRepo := &mocks.BackupRepo{}
|
|
backupRepo.On("FindManifests", mock.Anything, mock.Anything).Return(meta, nil)
|
|
return backupRepo
|
|
}(),
|
|
},
|
|
{
|
|
name: "Failed to find manifest",
|
|
isGetManifestError: true,
|
|
backupRepo: func() *mocks.BackupRepo {
|
|
backupRepo := &mocks.BackupRepo{}
|
|
backupRepo.On("FindManifests", mock.Anything, mock.Anything).Return(meta,
|
|
errors.New("failed to find manifest"))
|
|
return backupRepo
|
|
}(),
|
|
},
|
|
}
|
|
for _, tc := range tests {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
ctx := t.Context()
|
|
_, err := NewShimRepo(tc.backupRepo).FindManifests(ctx, map[string]string{})
|
|
if tc.isGetManifestError {
|
|
require.ErrorContains(t, err, "failed")
|
|
} else {
|
|
assert.NoError(t, err)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestShimObjReader(t *testing.T) {
|
|
reader := new(shimObjectReader)
|
|
objReader := &mocks.ObjectReader{}
|
|
reader.repoReader = objReader
|
|
// All below calls put together for the implementation are empty or just very simple, and just want to cover testing
|
|
// If wanting to write unit tests for some functions could remove it and with writing new function alone
|
|
objReader.On("Seek", mock.Anything, mock.Anything).Return(int64(0), nil)
|
|
reader.Seek(int64(0), 0)
|
|
|
|
objReader.On("Read", mock.Anything).Return(0, nil)
|
|
reader.Read(nil)
|
|
|
|
objReader.On("Close").Return(nil)
|
|
reader.Close()
|
|
|
|
objReader.On("Length").Return(int64(0))
|
|
reader.Length()
|
|
}
|
|
|
|
func TestShimObjWriter(t *testing.T) {
|
|
writer := new(shimObjectWriter)
|
|
objWriter := &mocks.ObjectWriter{}
|
|
writer.repoWriter = objWriter
|
|
// All below calls put together for the implementation are empty or just very simple, and just want to cover testing
|
|
// If wanting to write unit tests for some functions could remove it and with writing new function alone
|
|
var id udmrepo.ID
|
|
objWriter.On("Checkpoint").Return(id, nil)
|
|
writer.Checkpoint()
|
|
|
|
objWriter.On("Result").Return(id, nil)
|
|
writer.Result()
|
|
|
|
objWriter.On("Write", mock.Anything).Return(0, nil)
|
|
writer.Write(nil)
|
|
|
|
objWriter.On("Close").Return(nil)
|
|
writer.Close()
|
|
}
|
|
|
|
func TestReplaceManifests(t *testing.T) {
|
|
meta1 := udmrepo.ManifestEntryMetadata{
|
|
ID: "mani-1",
|
|
}
|
|
|
|
meta2 := udmrepo.ManifestEntryMetadata{
|
|
ID: "mani-2",
|
|
}
|
|
|
|
tests := []struct {
|
|
name string
|
|
backupRepo *mocks.BackupRepo
|
|
isGetManifestError bool
|
|
expectedError string
|
|
expectedID manifest.ID
|
|
}{
|
|
{
|
|
name: "Failed to find manifest",
|
|
isGetManifestError: true,
|
|
backupRepo: func() *mocks.BackupRepo {
|
|
backupRepo := &mocks.BackupRepo{}
|
|
backupRepo.On("FindManifests", mock.Anything, mock.Anything).Return([]*udmrepo.ManifestEntryMetadata{},
|
|
errors.New("fake-find-error"))
|
|
return backupRepo
|
|
}(),
|
|
expectedError: "unable to load manifests: failed to get manifests with labels map[]: fake-find-error",
|
|
},
|
|
{
|
|
name: "Failed to delete manifest",
|
|
isGetManifestError: true,
|
|
backupRepo: func() *mocks.BackupRepo {
|
|
backupRepo := &mocks.BackupRepo{}
|
|
backupRepo.On("FindManifests", mock.Anything, mock.Anything).Return([]*udmrepo.ManifestEntryMetadata{
|
|
&meta1,
|
|
&meta2,
|
|
}, nil)
|
|
backupRepo.On("Time").Return(time.Now())
|
|
backupRepo.On("DeleteManifest", mock.Anything, mock.Anything).Return(errors.New("fake-delete-error"))
|
|
return backupRepo
|
|
}(),
|
|
expectedError: "unable to delete previous manifest mani-1: fake-delete-error",
|
|
},
|
|
{
|
|
name: "Failed to put manifest",
|
|
backupRepo: func() *mocks.BackupRepo {
|
|
backupRepo := &mocks.BackupRepo{}
|
|
backupRepo.On("FindManifests", mock.Anything, mock.Anything).Return([]*udmrepo.ManifestEntryMetadata{
|
|
&meta1,
|
|
&meta2,
|
|
}, nil)
|
|
backupRepo.On("Time").Return(time.Now())
|
|
backupRepo.On("DeleteManifest", mock.Anything, mock.Anything).Return(nil)
|
|
backupRepo.On("PutManifest", mock.Anything, mock.Anything).Return(udmrepo.ID(""), errors.New("fake-put-error"))
|
|
return backupRepo
|
|
}(),
|
|
expectedError: "fake-put-error",
|
|
},
|
|
{
|
|
name: "Success",
|
|
backupRepo: func() *mocks.BackupRepo {
|
|
backupRepo := &mocks.BackupRepo{}
|
|
backupRepo.On("FindManifests", mock.Anything, mock.Anything).Return([]*udmrepo.ManifestEntryMetadata{
|
|
&meta1,
|
|
&meta2,
|
|
}, nil)
|
|
backupRepo.On("Time").Return(time.Now())
|
|
backupRepo.On("DeleteManifest", mock.Anything, mock.Anything).Return(nil)
|
|
backupRepo.On("PutManifest", mock.Anything, mock.Anything).Return(udmrepo.ID("fake-id"), nil)
|
|
return backupRepo
|
|
}(),
|
|
expectedID: manifest.ID("fake-id"),
|
|
},
|
|
}
|
|
for _, tc := range tests {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
ctx := t.Context()
|
|
id, err := NewShimRepo(tc.backupRepo).ReplaceManifests(ctx, map[string]string{}, nil)
|
|
|
|
if tc.expectedError != "" {
|
|
require.EqualError(t, err, tc.expectedError)
|
|
} else {
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
assert.Equal(t, tc.expectedID, id)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestConcatenateObjects(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
backupRepo *mocks.BackupRepo
|
|
objectIDs []object.ID
|
|
expectedError string
|
|
}{
|
|
{
|
|
name: "empty object list",
|
|
expectedError: "object list is empty",
|
|
},
|
|
{
|
|
name: "concatenate error",
|
|
backupRepo: func() *mocks.BackupRepo {
|
|
backupRepo := &mocks.BackupRepo{}
|
|
backupRepo.On("ConcatenateObjects", mock.Anything, mock.Anything).Return(udmrepo.ID(""), errors.New("fake-concatenate-error"))
|
|
return backupRepo
|
|
}(),
|
|
objectIDs: []object.ID{
|
|
{},
|
|
},
|
|
expectedError: "fake-concatenate-error",
|
|
},
|
|
{
|
|
name: "parse error",
|
|
backupRepo: func() *mocks.BackupRepo {
|
|
backupRepo := &mocks.BackupRepo{}
|
|
backupRepo.On("ConcatenateObjects", mock.Anything, mock.Anything).Return(udmrepo.ID("fake-id"), nil)
|
|
return backupRepo
|
|
}(),
|
|
objectIDs: []object.ID{
|
|
{},
|
|
},
|
|
expectedError: "malformed content ID: \"fake-id\": invalid content prefix",
|
|
},
|
|
{
|
|
name: "success",
|
|
backupRepo: func() *mocks.BackupRepo {
|
|
backupRepo := &mocks.BackupRepo{}
|
|
backupRepo.On("ConcatenateObjects", mock.Anything, mock.Anything).Return(udmrepo.ID("I123456"), nil)
|
|
return backupRepo
|
|
}(),
|
|
objectIDs: []object.ID{
|
|
{},
|
|
},
|
|
},
|
|
}
|
|
for _, tc := range tests {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
ctx := t.Context()
|
|
_, err := NewShimRepo(tc.backupRepo).ConcatenateObjects(ctx, tc.objectIDs, repo.ConcatenateOptions{})
|
|
|
|
if tc.expectedError != "" {
|
|
assert.EqualError(t, err, tc.expectedError)
|
|
} else {
|
|
assert.NoError(t, err)
|
|
}
|
|
})
|
|
}
|
|
}
|