mirror of
https://github.com/vmware-tanzu/velero.git
synced 2026-01-05 13:05:17 +00:00
RestoreItemAction v1 refactoring for plugin api versioning
Signed-off-by: Scott Seago <sseago@redhat.com>
This commit is contained in:
@@ -25,6 +25,7 @@ import (
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
|
||||
"github.com/vmware-tanzu/velero/internal/restartabletest"
|
||||
v1 "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
|
||||
"github.com/vmware-tanzu/velero/pkg/plugin/clientmgmt/process"
|
||||
"github.com/vmware-tanzu/velero/pkg/plugin/framework/common"
|
||||
@@ -57,7 +58,7 @@ func TestRestartableGetBackupItemAction(t *testing.T) {
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
p := new(mockRestartableProcess)
|
||||
p := new(restartabletest.MockRestartableProcess)
|
||||
defer p.AssertExpectations(t)
|
||||
|
||||
name := "pod"
|
||||
@@ -78,7 +79,7 @@ func TestRestartableGetBackupItemAction(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRestartableBackupItemActionGetDelegate(t *testing.T) {
|
||||
p := new(mockRestartableProcess)
|
||||
p := new(restartabletest.MockRestartableProcess)
|
||||
defer p.AssertExpectations(t)
|
||||
|
||||
// Reset error
|
||||
@@ -121,7 +122,7 @@ func TestRestartableBackupItemActionDelegatedFunctions(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
runRestartableDelegateTests(
|
||||
restartabletest.RunRestartableDelegateTests(
|
||||
t,
|
||||
common.PluginKindBackupItemAction,
|
||||
func(key process.KindAndName, p process.RestartableProcess) interface{} {
|
||||
@@ -130,20 +131,20 @@ func TestRestartableBackupItemActionDelegatedFunctions(t *testing.T) {
|
||||
SharedPluginProcess: p,
|
||||
}
|
||||
},
|
||||
func() mockable {
|
||||
func() restartabletest.Mockable {
|
||||
return new(mocks.BackupItemAction)
|
||||
},
|
||||
restartableDelegateTest{
|
||||
function: "AppliesTo",
|
||||
inputs: []interface{}{},
|
||||
expectedErrorOutputs: []interface{}{velero.ResourceSelector{}, errors.Errorf("reset error")},
|
||||
expectedDelegateOutputs: []interface{}{velero.ResourceSelector{IncludedNamespaces: []string{"a"}}, errors.Errorf("delegate error")},
|
||||
restartabletest.RestartableDelegateTest{
|
||||
Function: "AppliesTo",
|
||||
Inputs: []interface{}{},
|
||||
ExpectedErrorOutputs: []interface{}{velero.ResourceSelector{}, errors.Errorf("reset error")},
|
||||
ExpectedDelegateOutputs: []interface{}{velero.ResourceSelector{IncludedNamespaces: []string{"a"}}, errors.Errorf("delegate error")},
|
||||
},
|
||||
restartableDelegateTest{
|
||||
function: "Execute",
|
||||
inputs: []interface{}{pv, b},
|
||||
expectedErrorOutputs: []interface{}{nil, ([]velero.ResourceIdentifier)(nil), errors.Errorf("reset error")},
|
||||
expectedDelegateOutputs: []interface{}{pvToReturn, additionalItems, errors.Errorf("delegate error")},
|
||||
restartabletest.RestartableDelegateTest{
|
||||
Function: "Execute",
|
||||
Inputs: []interface{}{pv, b},
|
||||
ExpectedErrorOutputs: []interface{}{nil, ([]velero.ResourceIdentifier)(nil), errors.Errorf("reset error")},
|
||||
ExpectedDelegateOutputs: []interface{}{pvToReturn, additionalItems, errors.Errorf("delegate error")},
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,156 +0,0 @@
|
||||
/*
|
||||
Copyright 2018 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 v1
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/vmware-tanzu/velero/pkg/plugin/clientmgmt/process"
|
||||
"github.com/vmware-tanzu/velero/pkg/plugin/framework/common"
|
||||
)
|
||||
|
||||
type mockRestartableProcess struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
func (rp *mockRestartableProcess) AddReinitializer(key process.KindAndName, r process.Reinitializer) {
|
||||
rp.Called(key, r)
|
||||
}
|
||||
|
||||
func (rp *mockRestartableProcess) Reset() error {
|
||||
args := rp.Called()
|
||||
return args.Error(0)
|
||||
}
|
||||
|
||||
func (rp *mockRestartableProcess) ResetIfNeeded() error {
|
||||
args := rp.Called()
|
||||
return args.Error(0)
|
||||
}
|
||||
|
||||
func (rp *mockRestartableProcess) GetByKindAndName(key process.KindAndName) (interface{}, error) {
|
||||
args := rp.Called(key)
|
||||
return args.Get(0), args.Error(1)
|
||||
}
|
||||
|
||||
func (rp *mockRestartableProcess) Stop() {
|
||||
rp.Called()
|
||||
}
|
||||
|
||||
type restartableDelegateTest struct {
|
||||
function string
|
||||
inputs []interface{}
|
||||
expectedErrorOutputs []interface{}
|
||||
expectedDelegateOutputs []interface{}
|
||||
}
|
||||
|
||||
type mockable interface {
|
||||
Test(t mock.TestingT)
|
||||
On(method string, args ...interface{}) *mock.Call
|
||||
AssertExpectations(t mock.TestingT) bool
|
||||
}
|
||||
|
||||
func runRestartableDelegateTests(
|
||||
t *testing.T,
|
||||
kind common.PluginKind,
|
||||
newRestartable func(key process.KindAndName, p process.RestartableProcess) interface{},
|
||||
newMock func() mockable,
|
||||
tests ...restartableDelegateTest,
|
||||
) {
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.function, func(t *testing.T) {
|
||||
p := new(mockRestartableProcess)
|
||||
p.Test(t)
|
||||
defer p.AssertExpectations(t)
|
||||
|
||||
// getDelegate error
|
||||
p.On("ResetIfNeeded").Return(errors.Errorf("reset error")).Once()
|
||||
name := "delegateName"
|
||||
key := process.KindAndName{Kind: kind, Name: name}
|
||||
r := newRestartable(key, p)
|
||||
|
||||
// Get the method we're going to call using reflection
|
||||
method := reflect.ValueOf(r).MethodByName(tc.function)
|
||||
require.NotEmpty(t, method)
|
||||
|
||||
// Convert the test case inputs ([]interface{}) to []reflect.Value
|
||||
var inputValues []reflect.Value
|
||||
for i := range tc.inputs {
|
||||
inputValues = append(inputValues, reflect.ValueOf(tc.inputs[i]))
|
||||
}
|
||||
|
||||
// Invoke the method being tested
|
||||
actual := method.Call(inputValues)
|
||||
|
||||
// This function asserts that the actual outputs match the expected outputs
|
||||
checkOutputs := func(expected []interface{}, actual []reflect.Value) {
|
||||
require.Equal(t, len(expected), len(actual))
|
||||
|
||||
for i := range actual {
|
||||
// Get the underlying value from the reflect.Value
|
||||
a := actual[i].Interface()
|
||||
|
||||
// Check if it's an error
|
||||
actualErr, actualErrOk := a.(error)
|
||||
// Check if the expected output element is an error
|
||||
expectedErr, expectedErrOk := expected[i].(error)
|
||||
// If both are errors, use EqualError
|
||||
if actualErrOk && expectedErrOk {
|
||||
assert.EqualError(t, actualErr, expectedErr.Error())
|
||||
continue
|
||||
}
|
||||
|
||||
// If function returns nil as struct return type, we cannot just
|
||||
// compare the interface to nil as its type will not be nil,
|
||||
// only the value will be
|
||||
if expected[i] == nil && reflect.ValueOf(a).Kind() == reflect.Ptr {
|
||||
assert.True(t, reflect.ValueOf(a).IsNil())
|
||||
continue
|
||||
}
|
||||
|
||||
// Otherwise, use plain Equal
|
||||
assert.Equal(t, expected[i], a)
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure we get what we expected when getDelegate returned an error
|
||||
checkOutputs(tc.expectedErrorOutputs, actual)
|
||||
|
||||
// Invoke delegate, make sure all returned values are passed through
|
||||
p.On("ResetIfNeeded").Return(nil)
|
||||
|
||||
delegate := newMock()
|
||||
delegate.Test(t)
|
||||
defer delegate.AssertExpectations(t)
|
||||
|
||||
p.On("GetByKindAndName", key).Return(delegate, nil)
|
||||
|
||||
// Set up the mocked method in the delegate
|
||||
delegate.On(tc.function, tc.inputs...).Return(tc.expectedDelegateOutputs...)
|
||||
|
||||
// Invoke the method being tested
|
||||
actual = method.Call(inputValues)
|
||||
|
||||
// Make sure we get what we expected when invoking the delegate
|
||||
checkOutputs(tc.expectedDelegateOutputs, actual)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -26,10 +26,12 @@ import (
|
||||
|
||||
biav1cli "github.com/vmware-tanzu/velero/pkg/plugin/clientmgmt/backupitemaction/v1"
|
||||
"github.com/vmware-tanzu/velero/pkg/plugin/clientmgmt/process"
|
||||
riav1cli "github.com/vmware-tanzu/velero/pkg/plugin/clientmgmt/restoreitemaction/v1"
|
||||
"github.com/vmware-tanzu/velero/pkg/plugin/framework/common"
|
||||
"github.com/vmware-tanzu/velero/pkg/plugin/velero"
|
||||
biav1 "github.com/vmware-tanzu/velero/pkg/plugin/velero/backupitemaction/v1"
|
||||
isv1 "github.com/vmware-tanzu/velero/pkg/plugin/velero/item_snapshotter/v1"
|
||||
riav1 "github.com/vmware-tanzu/velero/pkg/plugin/velero/restoreitemaction/v1"
|
||||
)
|
||||
|
||||
// Manager manages the lifecycles of plugins.
|
||||
@@ -47,10 +49,10 @@ type Manager interface {
|
||||
GetBackupItemAction(name string) (biav1.BackupItemAction, error)
|
||||
|
||||
// GetRestoreItemActions returns all restore item action plugins.
|
||||
GetRestoreItemActions() ([]velero.RestoreItemAction, error)
|
||||
GetRestoreItemActions() ([]riav1.RestoreItemAction, error)
|
||||
|
||||
// GetRestoreItemAction returns the restore item action plugin for name.
|
||||
GetRestoreItemAction(name string) (velero.RestoreItemAction, error)
|
||||
GetRestoreItemAction(name string) (riav1.RestoreItemAction, error)
|
||||
|
||||
// GetDeleteItemActions returns all delete item action plugins.
|
||||
GetDeleteItemActions() ([]velero.DeleteItemAction, error)
|
||||
@@ -211,10 +213,10 @@ func (m *manager) GetBackupItemAction(name string) (biav1.BackupItemAction, erro
|
||||
}
|
||||
|
||||
// GetRestoreItemActions returns all restore item actions as restartableRestoreItemActions.
|
||||
func (m *manager) GetRestoreItemActions() ([]velero.RestoreItemAction, error) {
|
||||
func (m *manager) GetRestoreItemActions() ([]riav1.RestoreItemAction, error) {
|
||||
list := m.registry.List(common.PluginKindRestoreItemAction)
|
||||
|
||||
actions := make([]velero.RestoreItemAction, 0, len(list))
|
||||
actions := make([]riav1.RestoreItemAction, 0, len(list))
|
||||
|
||||
for i := range list {
|
||||
id := list[i]
|
||||
@@ -231,16 +233,21 @@ func (m *manager) GetRestoreItemActions() ([]velero.RestoreItemAction, error) {
|
||||
}
|
||||
|
||||
// GetRestoreItemAction returns a restartableRestoreItemAction for name.
|
||||
func (m *manager) GetRestoreItemAction(name string) (velero.RestoreItemAction, error) {
|
||||
func (m *manager) GetRestoreItemAction(name string) (riav1.RestoreItemAction, error) {
|
||||
name = sanitizeName(name)
|
||||
|
||||
restartableProcess, err := m.getRestartableProcess(common.PluginKindRestoreItemAction, name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
for _, adaptedRestoreItemAction := range riav1cli.AdaptedRestoreItemActions() {
|
||||
restartableProcess, err := m.getRestartableProcess(adaptedRestoreItemAction.Kind, name)
|
||||
// Check if plugin was not found
|
||||
if errors.As(err, &pluginNotFoundErrType) {
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return adaptedRestoreItemAction.GetRestartable(name, restartableProcess), nil
|
||||
}
|
||||
|
||||
r := NewRestartableRestoreItemAction(name, restartableProcess)
|
||||
return r, nil
|
||||
return nil, fmt.Errorf("unable to get valid RestoreItemAction for %q", name)
|
||||
}
|
||||
|
||||
// GetDeleteItemActions returns all delete item actions as restartableDeleteItemActions.
|
||||
|
||||
@@ -26,8 +26,10 @@ import (
|
||||
"github.com/stretchr/testify/mock"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/vmware-tanzu/velero/internal/restartabletest"
|
||||
biav1cli "github.com/vmware-tanzu/velero/pkg/plugin/clientmgmt/backupitemaction/v1"
|
||||
"github.com/vmware-tanzu/velero/pkg/plugin/clientmgmt/process"
|
||||
riav1cli "github.com/vmware-tanzu/velero/pkg/plugin/clientmgmt/restoreitemaction/v1"
|
||||
"github.com/vmware-tanzu/velero/pkg/plugin/framework"
|
||||
"github.com/vmware-tanzu/velero/pkg/plugin/framework/common"
|
||||
"github.com/vmware-tanzu/velero/pkg/test"
|
||||
@@ -84,33 +86,6 @@ func (f *mockRestartableProcessFactory) NewRestartableProcess(command string, lo
|
||||
return rp, args.Error(1)
|
||||
}
|
||||
|
||||
type mockRestartableProcess struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
func (rp *mockRestartableProcess) AddReinitializer(key process.KindAndName, r process.Reinitializer) {
|
||||
rp.Called(key, r)
|
||||
}
|
||||
|
||||
func (rp *mockRestartableProcess) Reset() error {
|
||||
args := rp.Called()
|
||||
return args.Error(0)
|
||||
}
|
||||
|
||||
func (rp *mockRestartableProcess) ResetIfNeeded() error {
|
||||
args := rp.Called()
|
||||
return args.Error(0)
|
||||
}
|
||||
|
||||
func (rp *mockRestartableProcess) GetByKindAndName(key process.KindAndName) (interface{}, error) {
|
||||
args := rp.Called(key)
|
||||
return args.Get(0), args.Error(1)
|
||||
}
|
||||
|
||||
func (rp *mockRestartableProcess) Stop() {
|
||||
rp.Called()
|
||||
}
|
||||
|
||||
func TestGetRestartableProcess(t *testing.T) {
|
||||
logger := test.NewLogger()
|
||||
logLevel := logrus.InfoLevel
|
||||
@@ -144,7 +119,7 @@ func TestGetRestartableProcess(t *testing.T) {
|
||||
assert.EqualError(t, err, "factory")
|
||||
|
||||
// Test 3: registry ok, factory ok
|
||||
restartableProcess := &mockRestartableProcess{}
|
||||
restartableProcess := &restartabletest.MockRestartableProcess{}
|
||||
defer restartableProcess.AssertExpectations(t)
|
||||
factory.On("NewRestartableProcess", podID.Command, logger, logLevel).Return(restartableProcess, nil).Once()
|
||||
rp, err = m.getRestartableProcess(pluginKind, pluginName)
|
||||
@@ -167,7 +142,7 @@ func TestCleanupClients(t *testing.T) {
|
||||
m := NewManager(logger, logLevel, registry).(*manager)
|
||||
|
||||
for i := 0; i < 5; i++ {
|
||||
rp := &mockRestartableProcess{}
|
||||
rp := &restartabletest.MockRestartableProcess{}
|
||||
defer rp.AssertExpectations(t)
|
||||
rp.On("Stop")
|
||||
m.restartableProcesses[fmt.Sprintf("rp%d", i)] = rp
|
||||
@@ -235,9 +210,9 @@ func TestGetRestoreItemAction(t *testing.T) {
|
||||
return m.GetRestoreItemAction(name)
|
||||
},
|
||||
func(name string, sharedPluginProcess process.RestartableProcess) interface{} {
|
||||
return &restartableRestoreItemAction{
|
||||
key: process.KindAndName{Kind: common.PluginKindRestoreItemAction, Name: name},
|
||||
sharedPluginProcess: sharedPluginProcess,
|
||||
return &riav1cli.RestartableRestoreItemAction{
|
||||
Key: process.KindAndName{Kind: common.PluginKindRestoreItemAction, Name: name},
|
||||
SharedPluginProcess: sharedPluginProcess,
|
||||
}
|
||||
},
|
||||
false,
|
||||
@@ -272,7 +247,7 @@ func getPluginTest(
|
||||
}
|
||||
registry.On("Get", pluginKind, pluginName).Return(pluginID, nil)
|
||||
|
||||
restartableProcess := &mockRestartableProcess{}
|
||||
restartableProcess := &restartabletest.MockRestartableProcess{}
|
||||
defer restartableProcess.AssertExpectations(t)
|
||||
|
||||
// Test 1: error getting restartable process
|
||||
@@ -349,7 +324,7 @@ func TestGetBackupItemActions(t *testing.T) {
|
||||
|
||||
registry.On("Get", pluginKind, pluginName).Return(pluginID, nil)
|
||||
|
||||
restartableProcess := &mockRestartableProcess{}
|
||||
restartableProcess := &restartabletest.MockRestartableProcess{}
|
||||
defer restartableProcess.AssertExpectations(t)
|
||||
|
||||
expected := &biav1cli.RestartableBackupItemAction{
|
||||
@@ -441,12 +416,12 @@ func TestGetRestoreItemActions(t *testing.T) {
|
||||
|
||||
registry.On("Get", pluginKind, pluginName).Return(pluginID, nil)
|
||||
|
||||
restartableProcess := &mockRestartableProcess{}
|
||||
restartableProcess := &restartabletest.MockRestartableProcess{}
|
||||
defer restartableProcess.AssertExpectations(t)
|
||||
|
||||
expected := &restartableRestoreItemAction{
|
||||
key: process.KindAndName{Kind: pluginKind, Name: pluginName},
|
||||
sharedPluginProcess: restartableProcess,
|
||||
expected := &riav1cli.RestartableRestoreItemAction{
|
||||
Key: process.KindAndName{Kind: pluginKind, Name: pluginName},
|
||||
SharedPluginProcess: restartableProcess,
|
||||
}
|
||||
|
||||
if tc.newRestartableProcessError != nil {
|
||||
@@ -540,12 +515,12 @@ func TestGetDeleteItemActions(t *testing.T) {
|
||||
|
||||
registry.On("Get", pluginKind, pluginName).Return(pluginID, nil)
|
||||
|
||||
restartableProcess := &mockRestartableProcess{}
|
||||
restartableProcess := &restartabletest.MockRestartableProcess{}
|
||||
defer restartableProcess.AssertExpectations(t)
|
||||
|
||||
expected := &restartableRestoreItemAction{
|
||||
key: process.KindAndName{Kind: pluginKind, Name: pluginName},
|
||||
sharedPluginProcess: restartableProcess,
|
||||
expected := &riav1cli.RestartableRestoreItemAction{
|
||||
Key: process.KindAndName{Kind: pluginKind, Name: pluginName},
|
||||
SharedPluginProcess: restartableProcess,
|
||||
}
|
||||
|
||||
if tc.newRestartableProcessError != nil {
|
||||
|
||||
@@ -1,129 +0,0 @@
|
||||
/*
|
||||
Copyright 2018 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 clientmgmt
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/vmware-tanzu/velero/pkg/plugin/clientmgmt/process"
|
||||
"github.com/vmware-tanzu/velero/pkg/plugin/framework/common"
|
||||
)
|
||||
|
||||
type restartableDelegateTest struct {
|
||||
function string
|
||||
inputs []interface{}
|
||||
expectedErrorOutputs []interface{}
|
||||
expectedDelegateOutputs []interface{}
|
||||
}
|
||||
|
||||
type mockable interface {
|
||||
Test(t mock.TestingT)
|
||||
On(method string, args ...interface{}) *mock.Call
|
||||
AssertExpectations(t mock.TestingT) bool
|
||||
}
|
||||
|
||||
func runRestartableDelegateTests(
|
||||
t *testing.T,
|
||||
kind common.PluginKind,
|
||||
newRestartable func(key process.KindAndName, p process.RestartableProcess) interface{},
|
||||
newMock func() mockable,
|
||||
tests ...restartableDelegateTest,
|
||||
) {
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.function, func(t *testing.T) {
|
||||
p := new(mockRestartableProcess)
|
||||
p.Test(t)
|
||||
defer p.AssertExpectations(t)
|
||||
|
||||
// getDelegate error
|
||||
p.On("ResetIfNeeded").Return(errors.Errorf("reset error")).Once()
|
||||
name := "delegateName"
|
||||
key := process.KindAndName{Kind: kind, Name: name}
|
||||
r := newRestartable(key, p)
|
||||
|
||||
// Get the method we're going to call using reflection
|
||||
method := reflect.ValueOf(r).MethodByName(tc.function)
|
||||
require.NotEmpty(t, method)
|
||||
|
||||
// Convert the test case inputs ([]interface{}) to []reflect.Value
|
||||
var inputValues []reflect.Value
|
||||
for i := range tc.inputs {
|
||||
inputValues = append(inputValues, reflect.ValueOf(tc.inputs[i]))
|
||||
}
|
||||
|
||||
// Invoke the method being tested
|
||||
actual := method.Call(inputValues)
|
||||
|
||||
// This function asserts that the actual outputs match the expected outputs
|
||||
checkOutputs := func(expected []interface{}, actual []reflect.Value) {
|
||||
require.Equal(t, len(expected), len(actual))
|
||||
|
||||
for i := range actual {
|
||||
// Get the underlying value from the reflect.Value
|
||||
a := actual[i].Interface()
|
||||
|
||||
// Check if it's an error
|
||||
actualErr, actualErrOk := a.(error)
|
||||
// Check if the expected output element is an error
|
||||
expectedErr, expectedErrOk := expected[i].(error)
|
||||
// If both are errors, use EqualError
|
||||
if actualErrOk && expectedErrOk {
|
||||
assert.EqualError(t, actualErr, expectedErr.Error())
|
||||
continue
|
||||
}
|
||||
|
||||
// If function returns nil as struct return type, we cannot just
|
||||
// compare the interface to nil as its type will not be nil,
|
||||
// only the value will be
|
||||
if expected[i] == nil && reflect.ValueOf(a).Kind() == reflect.Ptr {
|
||||
assert.True(t, reflect.ValueOf(a).IsNil())
|
||||
continue
|
||||
}
|
||||
|
||||
// Otherwise, use plain Equal
|
||||
assert.Equal(t, expected[i], a)
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure we get what we expected when getDelegate returned an error
|
||||
checkOutputs(tc.expectedErrorOutputs, actual)
|
||||
|
||||
// Invoke delegate, make sure all returned values are passed through
|
||||
p.On("ResetIfNeeded").Return(nil)
|
||||
|
||||
delegate := newMock()
|
||||
delegate.Test(t)
|
||||
defer delegate.AssertExpectations(t)
|
||||
|
||||
p.On("GetByKindAndName", key).Return(delegate, nil)
|
||||
|
||||
// Set up the mocked method in the delegate
|
||||
delegate.On(tc.function, tc.inputs...).Return(tc.expectedDelegateOutputs...)
|
||||
|
||||
// Invoke the method being tested
|
||||
actual = method.Call(inputValues)
|
||||
|
||||
// Make sure we get what we expected when invoking the delegate
|
||||
checkOutputs(tc.expectedDelegateOutputs, actual)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,7 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
|
||||
"github.com/vmware-tanzu/velero/internal/restartabletest"
|
||||
api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
|
||||
"github.com/vmware-tanzu/velero/pkg/plugin/clientmgmt/process"
|
||||
"github.com/vmware-tanzu/velero/pkg/plugin/framework/common"
|
||||
@@ -56,7 +57,7 @@ func TestRestartableGetDeleteItemAction(t *testing.T) {
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
p := new(mockRestartableProcess)
|
||||
p := new(restartabletest.MockRestartableProcess)
|
||||
defer p.AssertExpectations(t)
|
||||
|
||||
name := "pod"
|
||||
@@ -77,7 +78,7 @@ func TestRestartableGetDeleteItemAction(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRestartableDeleteItemActionGetDelegate(t *testing.T) {
|
||||
p := new(mockRestartableProcess)
|
||||
p := new(restartabletest.MockRestartableProcess)
|
||||
defer p.AssertExpectations(t)
|
||||
|
||||
// Reset error
|
||||
@@ -114,7 +115,7 @@ func TestRestartableDeleteItemActionDelegatedFunctions(t *testing.T) {
|
||||
Backup: backup,
|
||||
}
|
||||
|
||||
runRestartableDelegateTests(
|
||||
restartabletest.RunRestartableDelegateTests(
|
||||
t,
|
||||
common.PluginKindDeleteItemAction,
|
||||
func(key process.KindAndName, p process.RestartableProcess) interface{} {
|
||||
@@ -123,21 +124,21 @@ func TestRestartableDeleteItemActionDelegatedFunctions(t *testing.T) {
|
||||
sharedPluginProcess: p,
|
||||
}
|
||||
},
|
||||
func() mockable {
|
||||
func() restartabletest.Mockable {
|
||||
// Currently broken because this mocks the restore item action interface
|
||||
return new(mocks.DeleteItemAction)
|
||||
},
|
||||
restartableDelegateTest{
|
||||
function: "AppliesTo",
|
||||
inputs: []interface{}{},
|
||||
expectedErrorOutputs: []interface{}{velero.ResourceSelector{}, errors.Errorf("reset error")},
|
||||
expectedDelegateOutputs: []interface{}{velero.ResourceSelector{IncludedNamespaces: []string{"a"}}, errors.Errorf("delegate error")},
|
||||
restartabletest.RestartableDelegateTest{
|
||||
Function: "AppliesTo",
|
||||
Inputs: []interface{}{},
|
||||
ExpectedErrorOutputs: []interface{}{velero.ResourceSelector{}, errors.Errorf("reset error")},
|
||||
ExpectedDelegateOutputs: []interface{}{velero.ResourceSelector{IncludedNamespaces: []string{"a"}}, errors.Errorf("delegate error")},
|
||||
},
|
||||
restartableDelegateTest{
|
||||
function: "Execute",
|
||||
inputs: []interface{}{input},
|
||||
expectedErrorOutputs: []interface{}{errors.Errorf("reset error")},
|
||||
expectedDelegateOutputs: []interface{}{errors.Errorf("delegate error")},
|
||||
restartabletest.RestartableDelegateTest{
|
||||
Function: "Execute",
|
||||
Inputs: []interface{}{input},
|
||||
ExpectedErrorOutputs: []interface{}{errors.Errorf("reset error")},
|
||||
ExpectedDelegateOutputs: []interface{}{errors.Errorf("delegate error")},
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ import (
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
|
||||
"github.com/vmware-tanzu/velero/internal/restartabletest"
|
||||
v1 "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
|
||||
"github.com/vmware-tanzu/velero/pkg/plugin/velero/item_snapshotter/v1/mocks"
|
||||
|
||||
@@ -61,7 +62,7 @@ func TestRestartableGetItemSnapshotter(t *testing.T) {
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
p := new(mockRestartableProcess)
|
||||
p := new(restartabletest.MockRestartableProcess)
|
||||
defer p.AssertExpectations(t)
|
||||
|
||||
name := "pvc"
|
||||
@@ -82,7 +83,7 @@ func TestRestartableGetItemSnapshotter(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRestartableItemSnapshotterGetDelegate(t *testing.T) {
|
||||
p := new(mockRestartableProcess)
|
||||
p := new(restartabletest.MockRestartableProcess)
|
||||
defer p.AssertExpectations(t)
|
||||
|
||||
// Reset error
|
||||
@@ -175,7 +176,7 @@ func TestRestartableItemSnasphotterDelegatedFunctions(t *testing.T) {
|
||||
SnapshotMetadata: nil,
|
||||
Params: nil,
|
||||
}
|
||||
runRestartableDelegateTests(
|
||||
restartabletest.RunRestartableDelegateTests(
|
||||
t,
|
||||
common.PluginKindItemSnapshotter,
|
||||
func(key process.KindAndName, p process.RestartableProcess) interface{} {
|
||||
@@ -184,50 +185,50 @@ func TestRestartableItemSnasphotterDelegatedFunctions(t *testing.T) {
|
||||
sharedPluginProcess: p,
|
||||
}
|
||||
},
|
||||
func() mockable {
|
||||
func() restartabletest.Mockable {
|
||||
return new(mocks.ItemSnapshotter)
|
||||
},
|
||||
restartableDelegateTest{
|
||||
function: "Init",
|
||||
inputs: []interface{}{map[string]string{}},
|
||||
expectedErrorOutputs: []interface{}{errors.Errorf("reset error")},
|
||||
expectedDelegateOutputs: []interface{}{errors.Errorf("delegate error")},
|
||||
restartabletest.RestartableDelegateTest{
|
||||
Function: "Init",
|
||||
Inputs: []interface{}{map[string]string{}},
|
||||
ExpectedErrorOutputs: []interface{}{errors.Errorf("reset error")},
|
||||
ExpectedDelegateOutputs: []interface{}{errors.Errorf("delegate error")},
|
||||
},
|
||||
restartableDelegateTest{
|
||||
function: "AppliesTo",
|
||||
inputs: []interface{}{},
|
||||
expectedErrorOutputs: []interface{}{velero.ResourceSelector{}, errors.Errorf("reset error")},
|
||||
expectedDelegateOutputs: []interface{}{velero.ResourceSelector{IncludedNamespaces: []string{"a"}}, errors.Errorf("delegate error")},
|
||||
restartabletest.RestartableDelegateTest{
|
||||
Function: "AppliesTo",
|
||||
Inputs: []interface{}{},
|
||||
ExpectedErrorOutputs: []interface{}{velero.ResourceSelector{}, errors.Errorf("reset error")},
|
||||
ExpectedDelegateOutputs: []interface{}{velero.ResourceSelector{IncludedNamespaces: []string{"a"}}, errors.Errorf("delegate error")},
|
||||
},
|
||||
restartableDelegateTest{
|
||||
function: "AlsoHandles",
|
||||
inputs: []interface{}{&isv1.AlsoHandlesInput{}},
|
||||
expectedErrorOutputs: []interface{}{[]velero.ResourceIdentifier([]velero.ResourceIdentifier(nil)), errors.Errorf("reset error")},
|
||||
expectedDelegateOutputs: []interface{}{[]velero.ResourceIdentifier([]velero.ResourceIdentifier(nil)), errors.Errorf("delegate error")},
|
||||
restartabletest.RestartableDelegateTest{
|
||||
Function: "AlsoHandles",
|
||||
Inputs: []interface{}{&isv1.AlsoHandlesInput{}},
|
||||
ExpectedErrorOutputs: []interface{}{[]velero.ResourceIdentifier([]velero.ResourceIdentifier(nil)), errors.Errorf("reset error")},
|
||||
ExpectedDelegateOutputs: []interface{}{[]velero.ResourceIdentifier([]velero.ResourceIdentifier(nil)), errors.Errorf("delegate error")},
|
||||
},
|
||||
restartableDelegateTest{
|
||||
function: "SnapshotItem",
|
||||
inputs: []interface{}{ctx, sii},
|
||||
expectedErrorOutputs: []interface{}{nil, errors.Errorf("reset error")},
|
||||
expectedDelegateOutputs: []interface{}{sio, errors.Errorf("delegate error")},
|
||||
restartabletest.RestartableDelegateTest{
|
||||
Function: "SnapshotItem",
|
||||
Inputs: []interface{}{ctx, sii},
|
||||
ExpectedErrorOutputs: []interface{}{nil, errors.Errorf("reset error")},
|
||||
ExpectedDelegateOutputs: []interface{}{sio, errors.Errorf("delegate error")},
|
||||
},
|
||||
restartableDelegateTest{
|
||||
function: "CreateItemFromSnapshot",
|
||||
inputs: []interface{}{ctx, cii},
|
||||
expectedErrorOutputs: []interface{}{nil, errors.Errorf("reset error")},
|
||||
expectedDelegateOutputs: []interface{}{cio, errors.Errorf("delegate error")},
|
||||
restartabletest.RestartableDelegateTest{
|
||||
Function: "CreateItemFromSnapshot",
|
||||
Inputs: []interface{}{ctx, cii},
|
||||
ExpectedErrorOutputs: []interface{}{nil, errors.Errorf("reset error")},
|
||||
ExpectedDelegateOutputs: []interface{}{cio, errors.Errorf("delegate error")},
|
||||
},
|
||||
restartableDelegateTest{
|
||||
function: "Progress",
|
||||
inputs: []interface{}{pi},
|
||||
expectedErrorOutputs: []interface{}{nil, errors.Errorf("reset error")},
|
||||
expectedDelegateOutputs: []interface{}{po, errors.Errorf("delegate error")},
|
||||
restartabletest.RestartableDelegateTest{
|
||||
Function: "Progress",
|
||||
Inputs: []interface{}{pi},
|
||||
ExpectedErrorOutputs: []interface{}{nil, errors.Errorf("reset error")},
|
||||
ExpectedDelegateOutputs: []interface{}{po, errors.Errorf("delegate error")},
|
||||
},
|
||||
restartableDelegateTest{
|
||||
function: "DeleteSnapshot",
|
||||
inputs: []interface{}{ctx, dsi},
|
||||
expectedErrorOutputs: []interface{}{errors.Errorf("reset error")},
|
||||
expectedDelegateOutputs: []interface{}{errors.Errorf("delegate error")},
|
||||
restartabletest.RestartableDelegateTest{
|
||||
Function: "DeleteSnapshot",
|
||||
Inputs: []interface{}{ctx, dsi},
|
||||
ExpectedErrorOutputs: []interface{}{errors.Errorf("reset error")},
|
||||
ExpectedDelegateOutputs: []interface{}{errors.Errorf("delegate error")},
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/vmware-tanzu/velero/internal/restartabletest"
|
||||
"github.com/vmware-tanzu/velero/pkg/plugin/clientmgmt/process"
|
||||
"github.com/vmware-tanzu/velero/pkg/plugin/framework/common"
|
||||
providermocks "github.com/vmware-tanzu/velero/pkg/plugin/velero/mocks"
|
||||
@@ -56,7 +57,7 @@ func TestRestartableGetObjectStore(t *testing.T) {
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
p := new(mockRestartableProcess)
|
||||
p := new(restartabletest.MockRestartableProcess)
|
||||
p.Test(t)
|
||||
defer p.AssertExpectations(t)
|
||||
|
||||
@@ -81,7 +82,7 @@ func TestRestartableGetObjectStore(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRestartableObjectStoreReinitialize(t *testing.T) {
|
||||
p := new(mockRestartableProcess)
|
||||
p := new(restartabletest.MockRestartableProcess)
|
||||
p.Test(t)
|
||||
defer p.AssertExpectations(t)
|
||||
|
||||
@@ -112,7 +113,7 @@ func TestRestartableObjectStoreReinitialize(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRestartableObjectStoreGetDelegate(t *testing.T) {
|
||||
p := new(mockRestartableProcess)
|
||||
p := new(restartabletest.MockRestartableProcess)
|
||||
p.Test(t)
|
||||
defer p.AssertExpectations(t)
|
||||
|
||||
@@ -141,7 +142,7 @@ func TestRestartableObjectStoreGetDelegate(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRestartableObjectStoreInit(t *testing.T) {
|
||||
p := new(mockRestartableProcess)
|
||||
p := new(restartabletest.MockRestartableProcess)
|
||||
p.Test(t)
|
||||
defer p.AssertExpectations(t)
|
||||
|
||||
@@ -185,7 +186,7 @@ func TestRestartableObjectStoreInit(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRestartableObjectStoreDelegatedFunctions(t *testing.T) {
|
||||
runRestartableDelegateTests(
|
||||
restartabletest.RunRestartableDelegateTests(
|
||||
t,
|
||||
common.PluginKindObjectStore,
|
||||
func(key process.KindAndName, p process.RestartableProcess) interface{} {
|
||||
@@ -194,44 +195,44 @@ func TestRestartableObjectStoreDelegatedFunctions(t *testing.T) {
|
||||
sharedPluginProcess: p,
|
||||
}
|
||||
},
|
||||
func() mockable {
|
||||
func() restartabletest.Mockable {
|
||||
return new(providermocks.ObjectStore)
|
||||
},
|
||||
restartableDelegateTest{
|
||||
function: "PutObject",
|
||||
inputs: []interface{}{"bucket", "key", strings.NewReader("body")},
|
||||
expectedErrorOutputs: []interface{}{errors.Errorf("reset error")},
|
||||
expectedDelegateOutputs: []interface{}{errors.Errorf("delegate error")},
|
||||
restartabletest.RestartableDelegateTest{
|
||||
Function: "PutObject",
|
||||
Inputs: []interface{}{"bucket", "key", strings.NewReader("body")},
|
||||
ExpectedErrorOutputs: []interface{}{errors.Errorf("reset error")},
|
||||
ExpectedDelegateOutputs: []interface{}{errors.Errorf("delegate error")},
|
||||
},
|
||||
restartableDelegateTest{
|
||||
function: "GetObject",
|
||||
inputs: []interface{}{"bucket", "key"},
|
||||
expectedErrorOutputs: []interface{}{nil, errors.Errorf("reset error")},
|
||||
expectedDelegateOutputs: []interface{}{ioutil.NopCloser(strings.NewReader("object")), errors.Errorf("delegate error")},
|
||||
restartabletest.RestartableDelegateTest{
|
||||
Function: "GetObject",
|
||||
Inputs: []interface{}{"bucket", "key"},
|
||||
ExpectedErrorOutputs: []interface{}{nil, errors.Errorf("reset error")},
|
||||
ExpectedDelegateOutputs: []interface{}{ioutil.NopCloser(strings.NewReader("object")), errors.Errorf("delegate error")},
|
||||
},
|
||||
restartableDelegateTest{
|
||||
function: "ListCommonPrefixes",
|
||||
inputs: []interface{}{"bucket", "prefix", "delimiter"},
|
||||
expectedErrorOutputs: []interface{}{([]string)(nil), errors.Errorf("reset error")},
|
||||
expectedDelegateOutputs: []interface{}{[]string{"a", "b"}, errors.Errorf("delegate error")},
|
||||
restartabletest.RestartableDelegateTest{
|
||||
Function: "ListCommonPrefixes",
|
||||
Inputs: []interface{}{"bucket", "prefix", "delimiter"},
|
||||
ExpectedErrorOutputs: []interface{}{([]string)(nil), errors.Errorf("reset error")},
|
||||
ExpectedDelegateOutputs: []interface{}{[]string{"a", "b"}, errors.Errorf("delegate error")},
|
||||
},
|
||||
restartableDelegateTest{
|
||||
function: "ListObjects",
|
||||
inputs: []interface{}{"bucket", "prefix"},
|
||||
expectedErrorOutputs: []interface{}{([]string)(nil), errors.Errorf("reset error")},
|
||||
expectedDelegateOutputs: []interface{}{[]string{"a", "b"}, errors.Errorf("delegate error")},
|
||||
restartabletest.RestartableDelegateTest{
|
||||
Function: "ListObjects",
|
||||
Inputs: []interface{}{"bucket", "prefix"},
|
||||
ExpectedErrorOutputs: []interface{}{([]string)(nil), errors.Errorf("reset error")},
|
||||
ExpectedDelegateOutputs: []interface{}{[]string{"a", "b"}, errors.Errorf("delegate error")},
|
||||
},
|
||||
restartableDelegateTest{
|
||||
function: "DeleteObject",
|
||||
inputs: []interface{}{"bucket", "key"},
|
||||
expectedErrorOutputs: []interface{}{errors.Errorf("reset error")},
|
||||
expectedDelegateOutputs: []interface{}{errors.Errorf("delegate error")},
|
||||
restartabletest.RestartableDelegateTest{
|
||||
Function: "DeleteObject",
|
||||
Inputs: []interface{}{"bucket", "key"},
|
||||
ExpectedErrorOutputs: []interface{}{errors.Errorf("reset error")},
|
||||
ExpectedDelegateOutputs: []interface{}{errors.Errorf("delegate error")},
|
||||
},
|
||||
restartableDelegateTest{
|
||||
function: "CreateSignedURL",
|
||||
inputs: []interface{}{"bucket", "key", 30 * time.Minute},
|
||||
expectedErrorOutputs: []interface{}{"", errors.Errorf("reset error")},
|
||||
expectedDelegateOutputs: []interface{}{"signedURL", errors.Errorf("delegate error")},
|
||||
restartabletest.RestartableDelegateTest{
|
||||
Function: "CreateSignedURL",
|
||||
Inputs: []interface{}{"bucket", "key", 30 * time.Minute},
|
||||
ExpectedErrorOutputs: []interface{}{"", errors.Errorf("reset error")},
|
||||
ExpectedDelegateOutputs: []interface{}{"signedURL", errors.Errorf("delegate error")},
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
|
||||
"github.com/vmware-tanzu/velero/internal/restartabletest"
|
||||
"github.com/vmware-tanzu/velero/pkg/plugin/clientmgmt/process"
|
||||
"github.com/vmware-tanzu/velero/pkg/plugin/framework/common"
|
||||
providermocks "github.com/vmware-tanzu/velero/pkg/plugin/velero/mocks"
|
||||
@@ -55,7 +56,7 @@ func TestRestartableGetVolumeSnapshotter(t *testing.T) {
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
p := new(mockRestartableProcess)
|
||||
p := new(restartabletest.MockRestartableProcess)
|
||||
p.Test(t)
|
||||
defer p.AssertExpectations(t)
|
||||
|
||||
@@ -80,7 +81,7 @@ func TestRestartableGetVolumeSnapshotter(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRestartableVolumeSnapshotterReinitialize(t *testing.T) {
|
||||
p := new(mockRestartableProcess)
|
||||
p := new(restartabletest.MockRestartableProcess)
|
||||
p.Test(t)
|
||||
defer p.AssertExpectations(t)
|
||||
|
||||
@@ -111,7 +112,7 @@ func TestRestartableVolumeSnapshotterReinitialize(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRestartableVolumeSnapshotterGetDelegate(t *testing.T) {
|
||||
p := new(mockRestartableProcess)
|
||||
p := new(restartabletest.MockRestartableProcess)
|
||||
p.Test(t)
|
||||
defer p.AssertExpectations(t)
|
||||
|
||||
@@ -140,7 +141,7 @@ func TestRestartableVolumeSnapshotterGetDelegate(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRestartableVolumeSnapshotterInit(t *testing.T) {
|
||||
p := new(mockRestartableProcess)
|
||||
p := new(restartabletest.MockRestartableProcess)
|
||||
p.Test(t)
|
||||
defer p.AssertExpectations(t)
|
||||
|
||||
@@ -196,7 +197,7 @@ func TestRestartableVolumeSnapshotterDelegatedFunctions(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
runRestartableDelegateTests(
|
||||
restartabletest.RunRestartableDelegateTests(
|
||||
t,
|
||||
common.PluginKindVolumeSnapshotter,
|
||||
func(key process.KindAndName, p process.RestartableProcess) interface{} {
|
||||
@@ -205,44 +206,44 @@ func TestRestartableVolumeSnapshotterDelegatedFunctions(t *testing.T) {
|
||||
sharedPluginProcess: p,
|
||||
}
|
||||
},
|
||||
func() mockable {
|
||||
func() restartabletest.Mockable {
|
||||
return new(providermocks.VolumeSnapshotter)
|
||||
},
|
||||
restartableDelegateTest{
|
||||
function: "CreateVolumeFromSnapshot",
|
||||
inputs: []interface{}{"snapshotID", "volumeID", "volumeAZ", to.Int64Ptr(10000)},
|
||||
expectedErrorOutputs: []interface{}{"", errors.Errorf("reset error")},
|
||||
expectedDelegateOutputs: []interface{}{"volumeID", errors.Errorf("delegate error")},
|
||||
restartabletest.RestartableDelegateTest{
|
||||
Function: "CreateVolumeFromSnapshot",
|
||||
Inputs: []interface{}{"snapshotID", "volumeID", "volumeAZ", to.Int64Ptr(10000)},
|
||||
ExpectedErrorOutputs: []interface{}{"", errors.Errorf("reset error")},
|
||||
ExpectedDelegateOutputs: []interface{}{"volumeID", errors.Errorf("delegate error")},
|
||||
},
|
||||
restartableDelegateTest{
|
||||
function: "GetVolumeID",
|
||||
inputs: []interface{}{pv},
|
||||
expectedErrorOutputs: []interface{}{"", errors.Errorf("reset error")},
|
||||
expectedDelegateOutputs: []interface{}{"volumeID", errors.Errorf("delegate error")},
|
||||
restartabletest.RestartableDelegateTest{
|
||||
Function: "GetVolumeID",
|
||||
Inputs: []interface{}{pv},
|
||||
ExpectedErrorOutputs: []interface{}{"", errors.Errorf("reset error")},
|
||||
ExpectedDelegateOutputs: []interface{}{"volumeID", errors.Errorf("delegate error")},
|
||||
},
|
||||
restartableDelegateTest{
|
||||
function: "SetVolumeID",
|
||||
inputs: []interface{}{pv, "volumeID"},
|
||||
expectedErrorOutputs: []interface{}{nil, errors.Errorf("reset error")},
|
||||
expectedDelegateOutputs: []interface{}{pvToReturn, errors.Errorf("delegate error")},
|
||||
restartabletest.RestartableDelegateTest{
|
||||
Function: "SetVolumeID",
|
||||
Inputs: []interface{}{pv, "volumeID"},
|
||||
ExpectedErrorOutputs: []interface{}{nil, errors.Errorf("reset error")},
|
||||
ExpectedDelegateOutputs: []interface{}{pvToReturn, errors.Errorf("delegate error")},
|
||||
},
|
||||
restartableDelegateTest{
|
||||
function: "GetVolumeInfo",
|
||||
inputs: []interface{}{"volumeID", "volumeAZ"},
|
||||
expectedErrorOutputs: []interface{}{"", (*int64)(nil), errors.Errorf("reset error")},
|
||||
expectedDelegateOutputs: []interface{}{"volumeType", to.Int64Ptr(10000), errors.Errorf("delegate error")},
|
||||
restartabletest.RestartableDelegateTest{
|
||||
Function: "GetVolumeInfo",
|
||||
Inputs: []interface{}{"volumeID", "volumeAZ"},
|
||||
ExpectedErrorOutputs: []interface{}{"", (*int64)(nil), errors.Errorf("reset error")},
|
||||
ExpectedDelegateOutputs: []interface{}{"volumeType", to.Int64Ptr(10000), errors.Errorf("delegate error")},
|
||||
},
|
||||
restartableDelegateTest{
|
||||
function: "CreateSnapshot",
|
||||
inputs: []interface{}{"volumeID", "volumeAZ", map[string]string{"a": "b"}},
|
||||
expectedErrorOutputs: []interface{}{"", errors.Errorf("reset error")},
|
||||
expectedDelegateOutputs: []interface{}{"snapshotID", errors.Errorf("delegate error")},
|
||||
restartabletest.RestartableDelegateTest{
|
||||
Function: "CreateSnapshot",
|
||||
Inputs: []interface{}{"volumeID", "volumeAZ", map[string]string{"a": "b"}},
|
||||
ExpectedErrorOutputs: []interface{}{"", errors.Errorf("reset error")},
|
||||
ExpectedDelegateOutputs: []interface{}{"snapshotID", errors.Errorf("delegate error")},
|
||||
},
|
||||
restartableDelegateTest{
|
||||
function: "DeleteSnapshot",
|
||||
inputs: []interface{}{"snapshotID"},
|
||||
expectedErrorOutputs: []interface{}{errors.Errorf("reset error")},
|
||||
expectedDelegateOutputs: []interface{}{errors.Errorf("delegate error")},
|
||||
restartabletest.RestartableDelegateTest{
|
||||
Function: "DeleteSnapshot",
|
||||
Inputs: []interface{}{"snapshotID"},
|
||||
ExpectedErrorOutputs: []interface{}{errors.Errorf("reset error")},
|
||||
ExpectedDelegateOutputs: []interface{}{errors.Errorf("delegate error")},
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package clientmgmt
|
||||
package v1
|
||||
|
||||
import (
|
||||
"github.com/pkg/errors"
|
||||
@@ -22,36 +22,56 @@ import (
|
||||
"github.com/vmware-tanzu/velero/pkg/plugin/clientmgmt/process"
|
||||
"github.com/vmware-tanzu/velero/pkg/plugin/framework/common"
|
||||
"github.com/vmware-tanzu/velero/pkg/plugin/velero"
|
||||
riav1 "github.com/vmware-tanzu/velero/pkg/plugin/velero/restoreitemaction/v1"
|
||||
)
|
||||
|
||||
// AdaptedRestoreItemAction is a restore item action adapted to the v1 RestoreItemAction API
|
||||
type AdaptedRestoreItemAction struct {
|
||||
Kind common.PluginKind
|
||||
|
||||
// Get returns a restartable RestoreItemAction for the given name and process, wrapping if necessary
|
||||
GetRestartable func(name string, restartableProcess process.RestartableProcess) riav1.RestoreItemAction
|
||||
}
|
||||
|
||||
func AdaptedRestoreItemActions() []AdaptedRestoreItemAction {
|
||||
return []AdaptedRestoreItemAction{
|
||||
{
|
||||
Kind: common.PluginKindRestoreItemAction,
|
||||
GetRestartable: func(name string, restartableProcess process.RestartableProcess) riav1.RestoreItemAction {
|
||||
return NewRestartableRestoreItemAction(name, restartableProcess)
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// RestartableRestoreItemAction is a restore item action for a given implementation (such as "pod"). It is associated with
|
||||
// a restartableProcess, which may be shared and used to run multiple plugins. At the beginning of each method
|
||||
// call, the restartableRestoreItemAction asks its restartableProcess to restart itself if needed (e.g. if the
|
||||
// call, the RestartableRestoreItemAction asks its restartableProcess to restart itself if needed (e.g. if the
|
||||
// process terminated for any reason), then it proceeds with the actual call.
|
||||
type restartableRestoreItemAction struct {
|
||||
key process.KindAndName
|
||||
sharedPluginProcess process.RestartableProcess
|
||||
type RestartableRestoreItemAction struct {
|
||||
Key process.KindAndName
|
||||
SharedPluginProcess process.RestartableProcess
|
||||
config map[string]string
|
||||
}
|
||||
|
||||
// NewRestartableRestoreItemAction returns a new RestartableRestoreItemAction.
|
||||
func NewRestartableRestoreItemAction(name string, sharedPluginProcess process.RestartableProcess) *restartableRestoreItemAction {
|
||||
r := &restartableRestoreItemAction{
|
||||
key: process.KindAndName{Kind: common.PluginKindRestoreItemAction, Name: name},
|
||||
sharedPluginProcess: sharedPluginProcess,
|
||||
func NewRestartableRestoreItemAction(name string, sharedPluginProcess process.RestartableProcess) *RestartableRestoreItemAction {
|
||||
r := &RestartableRestoreItemAction{
|
||||
Key: process.KindAndName{Kind: common.PluginKindRestoreItemAction, Name: name},
|
||||
SharedPluginProcess: sharedPluginProcess,
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// getRestoreItemAction returns the restore item action for this restartableRestoreItemAction. It does *not* restart the
|
||||
// getRestoreItemAction returns the restore item action for this RestartableRestoreItemAction. It does *not* restart the
|
||||
// plugin process.
|
||||
func (r *restartableRestoreItemAction) getRestoreItemAction() (velero.RestoreItemAction, error) {
|
||||
plugin, err := r.sharedPluginProcess.GetByKindAndName(r.key)
|
||||
func (r *RestartableRestoreItemAction) getRestoreItemAction() (riav1.RestoreItemAction, error) {
|
||||
plugin, err := r.SharedPluginProcess.GetByKindAndName(r.Key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
restoreItemAction, ok := plugin.(velero.RestoreItemAction)
|
||||
restoreItemAction, ok := plugin.(riav1.RestoreItemAction)
|
||||
if !ok {
|
||||
return nil, errors.Errorf("%T is not a RestoreItemAction!", plugin)
|
||||
}
|
||||
@@ -59,9 +79,9 @@ func (r *restartableRestoreItemAction) getRestoreItemAction() (velero.RestoreIte
|
||||
return restoreItemAction, nil
|
||||
}
|
||||
|
||||
// getDelegate restarts the plugin process (if needed) and returns the restore item action for this restartableRestoreItemAction.
|
||||
func (r *restartableRestoreItemAction) getDelegate() (velero.RestoreItemAction, error) {
|
||||
if err := r.sharedPluginProcess.ResetIfNeeded(); err != nil {
|
||||
// getDelegate restarts the plugin process (if needed) and returns the restore item action for this RestartableRestoreItemAction.
|
||||
func (r *RestartableRestoreItemAction) getDelegate() (riav1.RestoreItemAction, error) {
|
||||
if err := r.SharedPluginProcess.ResetIfNeeded(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -69,7 +89,7 @@ func (r *restartableRestoreItemAction) getDelegate() (velero.RestoreItemAction,
|
||||
}
|
||||
|
||||
// AppliesTo restarts the plugin's process if needed, then delegates the call.
|
||||
func (r *restartableRestoreItemAction) AppliesTo() (velero.ResourceSelector, error) {
|
||||
func (r RestartableRestoreItemAction) AppliesTo() (velero.ResourceSelector, error) {
|
||||
delegate, err := r.getDelegate()
|
||||
if err != nil {
|
||||
return velero.ResourceSelector{}, err
|
||||
@@ -79,7 +99,7 @@ func (r *restartableRestoreItemAction) AppliesTo() (velero.ResourceSelector, err
|
||||
}
|
||||
|
||||
// Execute restarts the plugin's process if needed, then delegates the call.
|
||||
func (r *restartableRestoreItemAction) Execute(input *velero.RestoreItemActionExecuteInput) (*velero.RestoreItemActionExecuteOutput, error) {
|
||||
func (r *RestartableRestoreItemAction) Execute(input *riav1.RestoreItemActionExecuteInput) (*riav1.RestoreItemActionExecuteOutput, error) {
|
||||
delegate, err := r.getDelegate()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package clientmgmt
|
||||
package v1
|
||||
|
||||
import (
|
||||
"testing"
|
||||
@@ -24,11 +24,13 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
|
||||
"github.com/vmware-tanzu/velero/internal/restartabletest"
|
||||
v1 "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
|
||||
"github.com/vmware-tanzu/velero/pkg/plugin/clientmgmt/process"
|
||||
"github.com/vmware-tanzu/velero/pkg/plugin/framework/common"
|
||||
"github.com/vmware-tanzu/velero/pkg/plugin/velero"
|
||||
"github.com/vmware-tanzu/velero/pkg/restore/mocks"
|
||||
mocks "github.com/vmware-tanzu/velero/pkg/plugin/velero/mocks/restoreitemaction/v1"
|
||||
riav1 "github.com/vmware-tanzu/velero/pkg/plugin/velero/restoreitemaction/v1"
|
||||
)
|
||||
|
||||
func TestRestartableGetRestoreItemAction(t *testing.T) {
|
||||
@@ -50,13 +52,13 @@ func TestRestartableGetRestoreItemAction(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "happy path",
|
||||
plugin: new(mocks.ItemAction),
|
||||
plugin: new(mocks.RestoreItemAction),
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
p := new(mockRestartableProcess)
|
||||
p := new(restartabletest.MockRestartableProcess)
|
||||
defer p.AssertExpectations(t)
|
||||
|
||||
name := "pod"
|
||||
@@ -77,7 +79,7 @@ func TestRestartableGetRestoreItemAction(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRestartableRestoreItemActionGetDelegate(t *testing.T) {
|
||||
p := new(mockRestartableProcess)
|
||||
p := new(restartabletest.MockRestartableProcess)
|
||||
defer p.AssertExpectations(t)
|
||||
|
||||
// Reset error
|
||||
@@ -90,7 +92,7 @@ func TestRestartableRestoreItemActionGetDelegate(t *testing.T) {
|
||||
|
||||
// Happy path
|
||||
p.On("ResetIfNeeded").Return(nil)
|
||||
expected := new(mocks.ItemAction)
|
||||
expected := new(mocks.RestoreItemAction)
|
||||
key := process.KindAndName{Kind: common.PluginKindRestoreItemAction, Name: name}
|
||||
p.On("GetByKindAndName", key).Return(expected, nil)
|
||||
|
||||
@@ -106,13 +108,13 @@ func TestRestartableRestoreItemActionDelegatedFunctions(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
input := &velero.RestoreItemActionExecuteInput{
|
||||
input := &riav1.RestoreItemActionExecuteInput{
|
||||
Item: pv,
|
||||
ItemFromBackup: pv,
|
||||
Restore: new(v1.Restore),
|
||||
}
|
||||
|
||||
output := &velero.RestoreItemActionExecuteOutput{
|
||||
output := &riav1.RestoreItemActionExecuteOutput{
|
||||
UpdatedItem: &unstructured.Unstructured{
|
||||
Object: map[string]interface{}{
|
||||
"color": "green",
|
||||
@@ -120,29 +122,29 @@ func TestRestartableRestoreItemActionDelegatedFunctions(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
runRestartableDelegateTests(
|
||||
restartabletest.RunRestartableDelegateTests(
|
||||
t,
|
||||
common.PluginKindRestoreItemAction,
|
||||
func(key process.KindAndName, p process.RestartableProcess) interface{} {
|
||||
return &restartableRestoreItemAction{
|
||||
key: key,
|
||||
sharedPluginProcess: p,
|
||||
return &RestartableRestoreItemAction{
|
||||
Key: key,
|
||||
SharedPluginProcess: p,
|
||||
}
|
||||
},
|
||||
func() mockable {
|
||||
return new(mocks.ItemAction)
|
||||
func() restartabletest.Mockable {
|
||||
return new(mocks.RestoreItemAction)
|
||||
},
|
||||
restartableDelegateTest{
|
||||
function: "AppliesTo",
|
||||
inputs: []interface{}{},
|
||||
expectedErrorOutputs: []interface{}{velero.ResourceSelector{}, errors.Errorf("reset error")},
|
||||
expectedDelegateOutputs: []interface{}{velero.ResourceSelector{IncludedNamespaces: []string{"a"}}, errors.Errorf("delegate error")},
|
||||
restartabletest.RestartableDelegateTest{
|
||||
Function: "AppliesTo",
|
||||
Inputs: []interface{}{},
|
||||
ExpectedErrorOutputs: []interface{}{velero.ResourceSelector{}, errors.Errorf("reset error")},
|
||||
ExpectedDelegateOutputs: []interface{}{velero.ResourceSelector{IncludedNamespaces: []string{"a"}}, errors.Errorf("delegate error")},
|
||||
},
|
||||
restartableDelegateTest{
|
||||
function: "Execute",
|
||||
inputs: []interface{}{input},
|
||||
expectedErrorOutputs: []interface{}{nil, errors.Errorf("reset error")},
|
||||
expectedDelegateOutputs: []interface{}{output, errors.Errorf("delegate error")},
|
||||
restartabletest.RestartableDelegateTest{
|
||||
Function: "Execute",
|
||||
Inputs: []interface{}{input},
|
||||
ExpectedErrorOutputs: []interface{}{nil, errors.Errorf("reset error")},
|
||||
ExpectedDelegateOutputs: []interface{}{output, errors.Errorf("delegate error")},
|
||||
},
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user