1
0
Fork 0
mirror of https://github.com/kastenhq/kubestr.git synced 2024-12-15 17:50:57 +00:00
kastenhq-kubestr/pkg/csi/snapshot_restore_steps_test.go
Eugene Sumin 3843452900
Pass context to kube.Exec and similar functions. #25703 (#249)
* Bump go version
* Adjust code to follow Kanister changes
* Set appropriate Kanister revision
2024-06-04 14:44:33 -07:00

957 lines
26 KiB
Go

package csi
import (
"context"
"fmt"
"github.com/golang/mock/gomock"
"github.com/kastenhq/kubestr/pkg/common"
"github.com/kastenhq/kubestr/pkg/csi/mocks"
"github.com/kastenhq/kubestr/pkg/csi/types"
snapv1 "github.com/kubernetes-csi/external-snapshotter/client/v4/apis/volumesnapshot/v1"
. "gopkg.in/check.v1"
v1 "k8s.io/api/core/v1"
sv1 "k8s.io/api/storage/v1"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)
func (s *CSITestSuite) TestValidateArgs(c *C) {
ctx := context.Background()
type fields struct {
validateOps *mocks.MockArgumentValidator
versionOps *mocks.MockApiVersionFetcher
}
for _, tc := range []struct {
args *types.CSISnapshotRestoreArgs
prepare func(f *fields)
errChecker Checker
}{
{ // valid args
args: &types.CSISnapshotRestoreArgs{
StorageClass: "sc",
VolumeSnapshotClass: "vsc",
Namespace: "ns",
},
prepare: func(f *fields) {
gomock.InOrder(
f.validateOps.EXPECT().ValidateNamespace(gomock.Any(), "ns").Return(nil),
f.validateOps.EXPECT().ValidateStorageClass(gomock.Any(), "sc").Return(
&sv1.StorageClass{
Provisioner: "p1",
}, nil),
f.versionOps.EXPECT().GetCSISnapshotGroupVersion().Return(
&metav1.GroupVersionForDiscovery{
GroupVersion: common.SnapshotAlphaVersion,
}, nil),
f.validateOps.EXPECT().ValidateVolumeSnapshotClass(gomock.Any(), "vsc", &metav1.GroupVersionForDiscovery{
GroupVersion: common.SnapshotAlphaVersion,
}).Return(&unstructured.Unstructured{
Object: map[string]interface{}{
common.VolSnapClassAlphaDriverKey: "p1",
},
}, nil),
)
},
errChecker: IsNil,
},
{ // driver mismatch
args: &types.CSISnapshotRestoreArgs{
StorageClass: "sc",
VolumeSnapshotClass: "vsc",
Namespace: "ns",
},
prepare: func(f *fields) {
gomock.InOrder(
f.validateOps.EXPECT().ValidateNamespace(gomock.Any(), "ns").Return(nil),
f.validateOps.EXPECT().ValidateStorageClass(gomock.Any(), "sc").Return(
&sv1.StorageClass{
Provisioner: "p1",
}, nil),
f.versionOps.EXPECT().GetCSISnapshotGroupVersion().Return(
&metav1.GroupVersionForDiscovery{
GroupVersion: common.SnapshotAlphaVersion,
}, nil),
f.validateOps.EXPECT().ValidateVolumeSnapshotClass(gomock.Any(), "vsc", &metav1.GroupVersionForDiscovery{
GroupVersion: common.SnapshotAlphaVersion,
}).Return(&unstructured.Unstructured{
Object: map[string]interface{}{
common.VolSnapClassAlphaDriverKey: "p2",
},
}, nil),
)
},
errChecker: NotNil,
},
{ // vsc error
args: &types.CSISnapshotRestoreArgs{
StorageClass: "sc",
VolumeSnapshotClass: "vsc",
Namespace: "ns",
},
prepare: func(f *fields) {
gomock.InOrder(
f.validateOps.EXPECT().ValidateNamespace(gomock.Any(), "ns").Return(nil),
f.validateOps.EXPECT().ValidateStorageClass(gomock.Any(), "sc").Return(
&sv1.StorageClass{
Provisioner: "p1",
}, nil),
f.versionOps.EXPECT().GetCSISnapshotGroupVersion().Return(
&metav1.GroupVersionForDiscovery{
GroupVersion: common.SnapshotAlphaVersion,
}, nil),
f.validateOps.EXPECT().ValidateVolumeSnapshotClass(gomock.Any(), "vsc", &metav1.GroupVersionForDiscovery{
GroupVersion: common.SnapshotAlphaVersion,
}).Return(nil, fmt.Errorf("vsc error")),
)
},
errChecker: NotNil,
},
{ // groupversion error
args: &types.CSISnapshotRestoreArgs{
StorageClass: "sc",
VolumeSnapshotClass: "vsc",
Namespace: "ns",
},
prepare: func(f *fields) {
gomock.InOrder(
f.validateOps.EXPECT().ValidateNamespace(gomock.Any(), "ns").Return(nil),
f.validateOps.EXPECT().ValidateStorageClass(gomock.Any(), "sc").Return(
&sv1.StorageClass{
Provisioner: "p1",
}, nil),
f.versionOps.EXPECT().GetCSISnapshotGroupVersion().Return(
nil, fmt.Errorf("groupversion error")),
)
},
errChecker: NotNil,
},
{
args: &types.CSISnapshotRestoreArgs{
StorageClass: "sc",
VolumeSnapshotClass: "vsc",
Namespace: "ns",
},
prepare: func(f *fields) {
gomock.InOrder(
f.validateOps.EXPECT().ValidateNamespace(gomock.Any(), "ns").Return(nil),
f.validateOps.EXPECT().ValidateStorageClass(gomock.Any(), "sc").Return(
nil, fmt.Errorf("sc error")),
)
},
errChecker: NotNil,
},
{
args: &types.CSISnapshotRestoreArgs{
StorageClass: "sc",
VolumeSnapshotClass: "vsc",
Namespace: "ns",
},
prepare: func(f *fields) {
gomock.InOrder(
f.validateOps.EXPECT().ValidateNamespace(gomock.Any(), "ns").Return(fmt.Errorf("ns error")),
)
},
errChecker: NotNil,
},
{
args: &types.CSISnapshotRestoreArgs{
StorageClass: "",
VolumeSnapshotClass: "vsc",
Namespace: "ns",
},
errChecker: NotNil,
}, {
args: &types.CSISnapshotRestoreArgs{
StorageClass: "sc",
VolumeSnapshotClass: "",
Namespace: "ns",
},
errChecker: NotNil,
}, {
args: &types.CSISnapshotRestoreArgs{
StorageClass: "sc",
VolumeSnapshotClass: "vsc",
Namespace: "",
},
errChecker: NotNil,
},
} {
ctrl := gomock.NewController(c)
defer ctrl.Finish()
f := fields{
validateOps: mocks.NewMockArgumentValidator(ctrl),
versionOps: mocks.NewMockApiVersionFetcher(ctrl),
}
if tc.prepare != nil {
tc.prepare(&f)
}
stepper := &snapshotRestoreSteps{
validateOps: f.validateOps,
versionFetchOps: f.versionOps,
}
err := stepper.ValidateArgs(ctx, tc.args)
c.Check(err, tc.errChecker)
}
}
func (s *CSITestSuite) TestCreateApplication(c *C) {
ctx := context.Background()
type fields struct {
createAppOps *mocks.MockApplicationCreator
}
for _, tc := range []struct {
args *types.CSISnapshotRestoreArgs
genString string
prepare func(f *fields)
errChecker Checker
podChecker Checker
pvcChecker Checker
}{
{
args: &types.CSISnapshotRestoreArgs{
StorageClass: "sc",
Namespace: "ns",
RunAsUser: 100,
ContainerImage: "image",
},
genString: "some string",
prepare: func(f *fields) {
gomock.InOrder(
f.createAppOps.EXPECT().CreatePVC(gomock.Any(), &types.CreatePVCArgs{
GenerateName: originalPVCGenerateName,
StorageClass: "sc",
Namespace: "ns",
}).Return(&v1.PersistentVolumeClaim{
ObjectMeta: metav1.ObjectMeta{
Name: "pvc1",
},
}, nil),
f.createAppOps.EXPECT().CreatePod(gomock.Any(), &types.CreatePodArgs{
GenerateName: originalPodGenerateName,
PVCName: "pvc1",
Namespace: "ns",
Command: []string{"/bin/sh"},
ContainerArgs: []string{"-c", "echo 'some string' >> /data/out.txt; sync; tail -f /dev/null"},
RunAsUser: 100,
ContainerImage: "image",
MountPath: "/data",
}).Return(&v1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "pod1",
},
}, nil),
f.createAppOps.EXPECT().WaitForPVCReady(gomock.Any(), "ns", "pvc1").Return(nil),
f.createAppOps.EXPECT().WaitForPodReady(gomock.Any(), "ns", "pod1").Return(nil),
)
},
errChecker: IsNil,
podChecker: NotNil,
pvcChecker: NotNil,
},
{
args: &types.CSISnapshotRestoreArgs{
StorageClass: "sc",
Namespace: "ns",
RunAsUser: 100,
ContainerImage: "image",
},
genString: "some string",
prepare: func(f *fields) {
gomock.InOrder(
f.createAppOps.EXPECT().CreatePVC(gomock.Any(), &types.CreatePVCArgs{
GenerateName: originalPVCGenerateName,
StorageClass: "sc",
Namespace: "ns",
}).Return(&v1.PersistentVolumeClaim{
ObjectMeta: metav1.ObjectMeta{
Name: "pvc1",
},
}, nil),
f.createAppOps.EXPECT().CreatePod(gomock.Any(), &types.CreatePodArgs{
GenerateName: originalPodGenerateName,
PVCName: "pvc1",
Namespace: "ns",
Command: []string{"/bin/sh"},
ContainerArgs: []string{"-c", "echo 'some string' >> /data/out.txt; sync; tail -f /dev/null"},
RunAsUser: 100,
ContainerImage: "image",
MountPath: "/data",
}).Return(&v1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "pod1",
},
}, nil),
f.createAppOps.EXPECT().WaitForPVCReady(gomock.Any(), "ns", "pvc1").Return(nil),
f.createAppOps.EXPECT().WaitForPodReady(gomock.Any(), "ns", "pod1").Return(fmt.Errorf("pod ready error")),
)
},
errChecker: NotNil,
podChecker: NotNil,
pvcChecker: NotNil,
},
{
args: &types.CSISnapshotRestoreArgs{
StorageClass: "sc",
Namespace: "ns",
RunAsUser: 100,
ContainerImage: "image",
},
genString: "some string",
prepare: func(f *fields) {
gomock.InOrder(
f.createAppOps.EXPECT().CreatePVC(gomock.Any(), gomock.Any()).Return(&v1.PersistentVolumeClaim{
ObjectMeta: metav1.ObjectMeta{
Name: "pvc1",
},
}, nil),
f.createAppOps.EXPECT().CreatePod(gomock.Any(), gomock.Any()).Return(nil, fmt.Errorf("create pod error")),
)
},
errChecker: NotNil,
podChecker: IsNil,
pvcChecker: NotNil,
},
{
args: &types.CSISnapshotRestoreArgs{
StorageClass: "sc",
Namespace: "ns",
RunAsUser: 100,
ContainerImage: "image",
},
genString: "some string",
prepare: func(f *fields) {
gomock.InOrder(
f.createAppOps.EXPECT().CreatePVC(gomock.Any(), gomock.Any()).Return(nil, fmt.Errorf("create pvc error")),
)
},
errChecker: NotNil,
podChecker: IsNil,
pvcChecker: IsNil,
},
{ // PVC times out provisioning
args: &types.CSISnapshotRestoreArgs{
StorageClass: "sc",
Namespace: "ns",
RunAsUser: 100,
ContainerImage: "image",
},
genString: "some string",
prepare: func(f *fields) {
gomock.InOrder(
f.createAppOps.EXPECT().CreatePVC(gomock.Any(), &types.CreatePVCArgs{
GenerateName: originalPVCGenerateName,
StorageClass: "sc",
Namespace: "ns",
}).Return(&v1.PersistentVolumeClaim{
ObjectMeta: metav1.ObjectMeta{
Name: "pvc1",
},
}, nil),
f.createAppOps.EXPECT().CreatePod(gomock.Any(), &types.CreatePodArgs{
GenerateName: originalPodGenerateName,
PVCName: "pvc1",
Namespace: "ns",
Command: []string{"/bin/sh"},
ContainerArgs: []string{"-c", "echo 'some string' >> /data/out.txt; sync; tail -f /dev/null"},
RunAsUser: 100,
ContainerImage: "image",
MountPath: "/data",
}).Return(&v1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "pod1",
},
}, nil),
f.createAppOps.EXPECT().WaitForPVCReady(gomock.Any(), "ns", "pvc1").Return(fmt.Errorf("rate: Wait(n=1) would exceed context deadline")),
f.createAppOps.EXPECT().WaitForPodReady(gomock.Any(), "ns", "pvc1").Times(0),
)
},
errChecker: NotNil,
podChecker: NotNil,
pvcChecker: NotNil,
},
} {
ctrl := gomock.NewController(c)
defer ctrl.Finish()
f := fields{
createAppOps: mocks.NewMockApplicationCreator(ctrl),
}
if tc.prepare != nil {
tc.prepare(&f)
}
stepper := &snapshotRestoreSteps{
createAppOps: f.createAppOps,
}
pod, pvc, err := stepper.CreateApplication(ctx, tc.args, tc.genString)
c.Check(err, tc.errChecker)
c.Check(pod, tc.podChecker)
c.Check(pvc, tc.pvcChecker)
}
}
func (s *CSITestSuite) TestSnapshotApplication(c *C) {
ctx := context.Background()
snapshotter := &fakeSnapshotter{name: "snapshotter"}
groupversion := &metav1.GroupVersionForDiscovery{
GroupVersion: "gv",
Version: "v",
}
type fields struct {
snapshotOps *mocks.MockSnapshotCreator
}
for _, tc := range []struct {
args *types.CSISnapshotRestoreArgs
pvc *v1.PersistentVolumeClaim
snapshotName string
prepare func(f *fields)
errChecker Checker
snapChecker Checker
}{
{
args: &types.CSISnapshotRestoreArgs{
Namespace: "ns",
VolumeSnapshotClass: "vsc",
},
pvc: &v1.PersistentVolumeClaim{
ObjectMeta: metav1.ObjectMeta{
Name: "pvc1",
},
},
snapshotName: "snap1",
prepare: func(f *fields) {
gomock.InOrder(
f.snapshotOps.EXPECT().NewSnapshotter().Return(snapshotter, nil),
f.snapshotOps.EXPECT().CreateSnapshot(gomock.Any(), snapshotter, &types.CreateSnapshotArgs{
Namespace: "ns",
PVCName: "pvc1",
VolumeSnapshotClass: "vsc",
SnapshotName: "snap1",
}).Return(&snapv1.VolumeSnapshot{
ObjectMeta: metav1.ObjectMeta{
Name: "createdName",
},
}, nil),
f.snapshotOps.EXPECT().CreateFromSourceCheck(gomock.Any(), snapshotter, &types.CreateFromSourceCheckArgs{
VolumeSnapshotClass: "vsc",
SnapshotName: "createdName",
Namespace: "ns",
}, groupversion).Return(nil),
)
},
errChecker: IsNil,
snapChecker: NotNil,
},
{
args: &types.CSISnapshotRestoreArgs{
Namespace: "ns",
VolumeSnapshotClass: "vsc",
SkipCFSCheck: true,
},
pvc: &v1.PersistentVolumeClaim{
ObjectMeta: metav1.ObjectMeta{
Name: "pvc1",
},
},
snapshotName: "snap1",
prepare: func(f *fields) {
gomock.InOrder(
f.snapshotOps.EXPECT().NewSnapshotter().Return(snapshotter, nil),
f.snapshotOps.EXPECT().CreateSnapshot(gomock.Any(), snapshotter, &types.CreateSnapshotArgs{
Namespace: "ns",
PVCName: "pvc1",
VolumeSnapshotClass: "vsc",
SnapshotName: "snap1",
}).Return(&snapv1.VolumeSnapshot{
ObjectMeta: metav1.ObjectMeta{
Name: "createdName",
},
}, nil),
)
},
errChecker: IsNil,
snapChecker: NotNil,
},
{
args: &types.CSISnapshotRestoreArgs{
Namespace: "ns",
VolumeSnapshotClass: "vsc",
},
pvc: &v1.PersistentVolumeClaim{
ObjectMeta: metav1.ObjectMeta{
Name: "pvc1",
},
},
snapshotName: "snap1",
prepare: func(f *fields) {
gomock.InOrder(
f.snapshotOps.EXPECT().NewSnapshotter().Return(snapshotter, nil),
f.snapshotOps.EXPECT().CreateSnapshot(gomock.Any(), snapshotter, &types.CreateSnapshotArgs{
Namespace: "ns",
PVCName: "pvc1",
VolumeSnapshotClass: "vsc",
SnapshotName: "snap1",
}).Return(&snapv1.VolumeSnapshot{
ObjectMeta: metav1.ObjectMeta{
Name: "createdName",
},
}, nil),
f.snapshotOps.EXPECT().CreateFromSourceCheck(gomock.Any(), snapshotter, &types.CreateFromSourceCheckArgs{
VolumeSnapshotClass: "vsc",
SnapshotName: "createdName",
Namespace: "ns",
}, groupversion).Return(fmt.Errorf("cfs error")),
)
},
errChecker: NotNil,
snapChecker: NotNil,
},
{
args: &types.CSISnapshotRestoreArgs{
Namespace: "ns",
VolumeSnapshotClass: "vsc",
},
pvc: &v1.PersistentVolumeClaim{
ObjectMeta: metav1.ObjectMeta{
Name: "pvc1",
},
},
snapshotName: "snap1",
prepare: func(f *fields) {
gomock.InOrder(
f.snapshotOps.EXPECT().NewSnapshotter().Return(snapshotter, nil),
f.snapshotOps.EXPECT().CreateSnapshot(gomock.Any(), snapshotter, &types.CreateSnapshotArgs{
Namespace: "ns",
PVCName: "pvc1",
VolumeSnapshotClass: "vsc",
SnapshotName: "snap1",
}).Return(nil, fmt.Errorf("create snapshot error")),
)
},
errChecker: NotNil,
snapChecker: IsNil,
},
{
args: &types.CSISnapshotRestoreArgs{
Namespace: "ns",
VolumeSnapshotClass: "vsc",
},
pvc: &v1.PersistentVolumeClaim{
ObjectMeta: metav1.ObjectMeta{
Name: "pvc1",
},
},
snapshotName: "snap1",
prepare: func(f *fields) {
gomock.InOrder(
f.snapshotOps.EXPECT().NewSnapshotter().Return(nil, fmt.Errorf("snapshotter error")),
)
},
errChecker: NotNil,
snapChecker: IsNil,
},
} {
ctrl := gomock.NewController(c)
defer ctrl.Finish()
f := fields{
snapshotOps: mocks.NewMockSnapshotCreator(ctrl),
}
if tc.prepare != nil {
tc.prepare(&f)
}
stepper := &snapshotRestoreSteps{
snapshotCreateOps: f.snapshotOps,
SnapshotGroupVersion: groupversion,
}
snapshot, err := stepper.SnapshotApplication(ctx, tc.args, tc.pvc, tc.snapshotName)
c.Check(err, tc.errChecker)
c.Check(snapshot, tc.snapChecker)
}
}
func (s *CSITestSuite) TestRestoreApplication(c *C) {
ctx := context.Background()
resourceQuantity := resource.MustParse("1Gi")
snapshotAPIGroup := "snapshot.storage.k8s.io"
type fields struct {
createAppOps *mocks.MockApplicationCreator
}
for _, tc := range []struct {
args *types.CSISnapshotRestoreArgs
snapshot *snapv1.VolumeSnapshot
prepare func(f *fields)
errChecker Checker
podChecker Checker
pvcChecker Checker
}{
{
args: &types.CSISnapshotRestoreArgs{
StorageClass: "sc",
Namespace: "ns",
RunAsUser: 100,
ContainerImage: "image",
},
snapshot: &snapv1.VolumeSnapshot{
ObjectMeta: metav1.ObjectMeta{
Name: "snap1",
},
Status: &snapv1.VolumeSnapshotStatus{
RestoreSize: &resourceQuantity,
},
},
prepare: func(f *fields) {
gomock.InOrder(
f.createAppOps.EXPECT().CreatePVC(gomock.Any(), &types.CreatePVCArgs{
GenerateName: clonedPVCGenerateName,
StorageClass: "sc",
Namespace: "ns",
DataSource: &v1.TypedLocalObjectReference{
APIGroup: &snapshotAPIGroup,
Kind: "VolumeSnapshot",
Name: "snap1",
},
RestoreSize: &resourceQuantity,
}).Return(&v1.PersistentVolumeClaim{
ObjectMeta: metav1.ObjectMeta{
Name: "pvc1",
},
}, nil),
f.createAppOps.EXPECT().CreatePod(gomock.Any(), &types.CreatePodArgs{
GenerateName: clonedPodGenerateName,
PVCName: "pvc1",
Namespace: "ns",
Command: []string{"/bin/sh"},
ContainerArgs: []string{"-c", "tail -f /dev/null"},
MountPath: "/data",
RunAsUser: 100,
ContainerImage: "image",
}).Return(&v1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "pod1",
},
}, nil),
f.createAppOps.EXPECT().WaitForPVCReady(gomock.Any(), "ns", "pvc1").Return(nil),
f.createAppOps.EXPECT().WaitForPodReady(gomock.Any(), "ns", "pod1").Return(nil),
)
},
errChecker: IsNil,
podChecker: NotNil,
pvcChecker: NotNil,
},
{
args: &types.CSISnapshotRestoreArgs{
StorageClass: "sc",
Namespace: "ns",
RunAsUser: 100,
ContainerImage: "image",
},
snapshot: &snapv1.VolumeSnapshot{
ObjectMeta: metav1.ObjectMeta{
Name: "snap1",
},
Status: &snapv1.VolumeSnapshotStatus{
RestoreSize: &resourceQuantity,
},
},
prepare: func(f *fields) {
gomock.InOrder(
f.createAppOps.EXPECT().CreatePVC(gomock.Any(), &types.CreatePVCArgs{
GenerateName: clonedPVCGenerateName,
StorageClass: "sc",
Namespace: "ns",
DataSource: &v1.TypedLocalObjectReference{
APIGroup: &snapshotAPIGroup,
Kind: "VolumeSnapshot",
Name: "snap1",
},
RestoreSize: &resourceQuantity,
}).Return(&v1.PersistentVolumeClaim{
ObjectMeta: metav1.ObjectMeta{
Name: "pvc1",
},
}, nil),
f.createAppOps.EXPECT().CreatePod(gomock.Any(), &types.CreatePodArgs{
GenerateName: clonedPodGenerateName,
PVCName: "pvc1",
Namespace: "ns",
Command: []string{"/bin/sh"},
ContainerArgs: []string{"-c", "tail -f /dev/null"},
MountPath: "/data",
RunAsUser: 100,
ContainerImage: "image",
}).Return(&v1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "pod1",
},
}, nil),
f.createAppOps.EXPECT().WaitForPVCReady(gomock.Any(), "ns", "pvc1").Return(nil),
f.createAppOps.EXPECT().WaitForPodReady(gomock.Any(), "ns", "pod1").Return(fmt.Errorf("pod ready error")),
)
},
errChecker: NotNil,
podChecker: NotNil,
pvcChecker: NotNil,
},
{
args: &types.CSISnapshotRestoreArgs{
StorageClass: "sc",
Namespace: "ns",
RunAsUser: 100,
ContainerImage: "image",
},
snapshot: &snapv1.VolumeSnapshot{
ObjectMeta: metav1.ObjectMeta{
Name: "snap1",
},
Status: &snapv1.VolumeSnapshotStatus{
RestoreSize: &resourceQuantity,
},
},
prepare: func(f *fields) {
gomock.InOrder(
f.createAppOps.EXPECT().CreatePVC(gomock.Any(), gomock.Any()).Return(&v1.PersistentVolumeClaim{
ObjectMeta: metav1.ObjectMeta{
Name: "pvc1",
},
}, nil),
f.createAppOps.EXPECT().CreatePod(gomock.Any(), gomock.Any()).Return(nil, fmt.Errorf("create pod error")),
)
},
errChecker: NotNil,
podChecker: IsNil,
pvcChecker: NotNil,
},
{
args: &types.CSISnapshotRestoreArgs{
StorageClass: "sc",
Namespace: "ns",
RunAsUser: 100,
ContainerImage: "image",
},
snapshot: &snapv1.VolumeSnapshot{
ObjectMeta: metav1.ObjectMeta{
Name: "snap1",
},
Status: &snapv1.VolumeSnapshotStatus{
RestoreSize: &resourceQuantity,
},
},
prepare: func(f *fields) {
gomock.InOrder(
f.createAppOps.EXPECT().CreatePVC(gomock.Any(), gomock.Any()).Return(nil, fmt.Errorf("create pvc error")),
)
},
errChecker: NotNil,
podChecker: IsNil,
pvcChecker: IsNil,
},
} {
ctrl := gomock.NewController(c)
defer ctrl.Finish()
f := fields{
createAppOps: mocks.NewMockApplicationCreator(ctrl),
}
if tc.prepare != nil {
tc.prepare(&f)
}
stepper := &snapshotRestoreSteps{
createAppOps: f.createAppOps,
}
pod, pvc, err := stepper.RestoreApplication(ctx, tc.args, tc.snapshot)
c.Check(err, tc.errChecker)
c.Check(pod, tc.podChecker)
c.Check(pvc, tc.pvcChecker)
}
}
func (s *CSITestSuite) TestCleanup(c *C) {
ctx := context.Background()
groupversion := &metav1.GroupVersionForDiscovery{
GroupVersion: "gv",
Version: "v",
}
type fields struct {
cleanerOps *mocks.MockCleaner
}
for _, tc := range []struct {
results *types.CSISnapshotRestoreResults
prepare func(f *fields)
}{
{
results: nil,
},
{
results: &types.CSISnapshotRestoreResults{
OriginalPVC: &v1.PersistentVolumeClaim{
ObjectMeta: metav1.ObjectMeta{
Name: "pvc1",
Namespace: "ns",
},
},
OriginalPod: &v1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "pod1",
Namespace: "ns",
},
},
ClonedPVC: &v1.PersistentVolumeClaim{
ObjectMeta: metav1.ObjectMeta{
Name: "pvc2",
Namespace: "ns",
},
},
ClonedPod: &v1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "pod2",
Namespace: "ns",
},
},
Snapshot: &snapv1.VolumeSnapshot{
ObjectMeta: metav1.ObjectMeta{
Name: "snapshot",
Namespace: "ns",
},
},
},
prepare: func(f *fields) {
gomock.InOrder(
f.cleanerOps.EXPECT().DeletePVC(ctx, "pvc1", "ns").Return(nil),
f.cleanerOps.EXPECT().DeletePod(ctx, "pod1", "ns").Return(nil),
f.cleanerOps.EXPECT().DeletePVC(ctx, "pvc2", "ns").Return(nil),
f.cleanerOps.EXPECT().DeletePod(ctx, "pod2", "ns").Return(nil),
f.cleanerOps.EXPECT().DeleteSnapshot(ctx, "snapshot", "ns", groupversion).Return(nil),
)
},
},
{
results: &types.CSISnapshotRestoreResults{
OriginalPVC: &v1.PersistentVolumeClaim{
ObjectMeta: metav1.ObjectMeta{
Name: "pvc1",
Namespace: "ns",
},
},
OriginalPod: &v1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "pod1",
Namespace: "ns",
},
},
ClonedPVC: &v1.PersistentVolumeClaim{
ObjectMeta: metav1.ObjectMeta{
Name: "pvc2",
Namespace: "ns",
},
},
ClonedPod: &v1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "pod2",
Namespace: "ns",
},
},
Snapshot: &snapv1.VolumeSnapshot{
ObjectMeta: metav1.ObjectMeta{
Name: "snapshot",
Namespace: "ns",
},
},
},
prepare: func(f *fields) {
gomock.InOrder(
f.cleanerOps.EXPECT().DeletePVC(ctx, "pvc1", "ns").Return(fmt.Errorf("err")),
f.cleanerOps.EXPECT().DeletePod(ctx, "pod1", "ns").Return(fmt.Errorf("err")),
f.cleanerOps.EXPECT().DeletePVC(ctx, "pvc2", "ns").Return(fmt.Errorf("err")),
f.cleanerOps.EXPECT().DeletePod(ctx, "pod2", "ns").Return(fmt.Errorf("err")),
f.cleanerOps.EXPECT().DeleteSnapshot(ctx, "snapshot", "ns", groupversion).Return(fmt.Errorf("err")),
)
},
},
} {
ctrl := gomock.NewController(c)
defer ctrl.Finish()
f := fields{
cleanerOps: mocks.NewMockCleaner(ctrl),
}
if tc.prepare != nil {
tc.prepare(&f)
}
stepper := &snapshotRestoreSteps{
cleanerOps: f.cleanerOps,
SnapshotGroupVersion: groupversion,
}
stepper.Cleanup(ctx, tc.results)
}
}
func (s *CSITestSuite) TestValidateData(c *C) {
ctx := context.Background()
type fields struct {
validatorOps *mocks.MockDataValidator
}
for _, tc := range []struct {
prepare func(f *fields)
pod *v1.Pod
data string
errChecker Checker
}{
{
pod: &v1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "pod",
Namespace: "ns",
},
},
data: "somedata",
prepare: func(f *fields) {
gomock.InOrder(
f.validatorOps.EXPECT().FetchPodData(context.Background(), "pod", "ns").Return("somedata", nil),
)
},
errChecker: IsNil,
},
{
pod: &v1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "pod",
Namespace: "ns",
},
},
data: "somedata",
prepare: func(f *fields) {
gomock.InOrder(
f.validatorOps.EXPECT().FetchPodData(context.Background(), "pod", "ns").Return("someotherdata", nil),
)
},
errChecker: NotNil,
},
{
pod: &v1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "pod",
Namespace: "ns",
},
},
data: "somedata",
prepare: func(f *fields) {
gomock.InOrder(
f.validatorOps.EXPECT().FetchPodData(context.Background(), "pod", "ns").Return("", fmt.Errorf("error")),
)
},
errChecker: NotNil,
},
} {
ctrl := gomock.NewController(c)
defer ctrl.Finish()
f := fields{
validatorOps: mocks.NewMockDataValidator(ctrl),
}
if tc.prepare != nil {
tc.prepare(&f)
}
stepper := &snapshotRestoreSteps{
dataValidatorOps: f.validatorOps,
}
err := stepper.ValidateData(ctx, tc.pod, tc.data)
c.Check(err, tc.errChecker)
}
}