Skip to content

Commit

Permalink
Add modifycontroller test setupFakeK8sEnvironment helper
Browse files Browse the repository at this point in the history
  • Loading branch information
AndrewSirenko committed Oct 23, 2024
1 parent 26d5a05 commit babf8dc
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 118 deletions.
4 changes: 2 additions & 2 deletions pkg/modifycontroller/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ func (ctrl *modifyController) sync() {
}
}

// syncPVC checks if a pvc requests resizing, and execute the resize operation if requested.
// syncPVC checks if a pvc requests modification, and execute the ModifyVolume operation if requested.
func (ctrl *modifyController) syncPVC(key string) error {
klog.V(4).InfoS("Started PVC processing for modify controller", "key", key)

Expand All @@ -277,7 +277,7 @@ func (ctrl *modifyController) syncPVC(key string) error {
}

// Only trigger modify volume if the following conditions are met
// 1. Non empty vac name
// 1. Non-empty vac name
// 2. PVC is in Bound state
// 3. PV CSI driver name matches local driver
vacName := pvc.Spec.VolumeAttributesClassName
Expand Down
170 changes: 62 additions & 108 deletions pkg/modifycontroller/controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ func TestController(t *testing.T) {
}{
{
name: "Modify called",
pvc: createTestPVC(pvcName, "target-vac" /*vacName*/, testVac /*curVacName*/, testVac /*targetVacName*/),
pvc: createTestPVC(pvcName, targetVac /*vacName*/, testVac /*curVacName*/, testVac /*targetVacName*/),
pv: basePV,
vacExists: true,
callCSIModify: true,
Expand All @@ -61,57 +61,12 @@ func TestController(t *testing.T) {
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
// Setup
client := csi.NewMockClient("foo", true, true, true, true, true, false)
driverName, _ := client.GetDriverName(context.TODO())

var initialObjects []runtime.Object
initialObjects = append(initialObjects, test.pvc)
initialObjects = append(initialObjects, test.pv)
// existing vac set in the pvc and pv
initialObjects = append(initialObjects, testVacObject)
if test.vacExists {
initialObjects = append(initialObjects, targetVacObject)
}
client := csi.NewMockClient(testDriverName, true, true, true, true, true, false)

kubeClient, informerFactory := fakeK8s(initialObjects)
pvInformer := informerFactory.Core().V1().PersistentVolumes()
pvcInformer := informerFactory.Core().V1().PersistentVolumeClaims()
vacInformer := informerFactory.Storage().V1beta1().VolumeAttributesClasses()
initialObjects := []runtime.Object{test.pvc, test.pv, testVacObject, targetVacObject}
ctrlInstance := setupFakeK8sEnvironment(t, client, initialObjects)

csiModifier, err := modifier.NewModifierFromClient(client, 15*time.Second, kubeClient, informerFactory, false, driverName)
if err != nil {
t.Fatalf("Test %s: Unable to create modifier: %v", test.name, err)
}

featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.VolumeAttributesClass, true)
controller := NewModifyController(driverName,
csiModifier, kubeClient,
time.Second, false, informerFactory,
workqueue.DefaultControllerRateLimiter())

ctrlInstance, _ := controller.(*modifyController)

stopCh := make(chan struct{})
informerFactory.Start(stopCh)

ctx := context.TODO()
defer ctx.Done()
go controller.Run(1, ctx)

for _, obj := range initialObjects {
switch obj.(type) {
case *v1.PersistentVolume:
pvInformer.Informer().GetStore().Add(obj)
case *v1.PersistentVolumeClaim:
pvcInformer.Informer().GetStore().Add(obj)
case *storagev1beta1.VolumeAttributesClass:
vacInformer.Informer().GetStore().Add(obj)
default:
t.Fatalf("Test %s: Unknown initalObject type: %+v", test.name, obj)
}
}
time.Sleep(time.Second * 2)
err = ctrlInstance.modifyPVC(test.pvc, test.pv)
_ = ctrlInstance.modifyPVC(test.pvc, test.pv)

modifyCallCount := client.GetModifyCount()
if test.callCSIModify && modifyCallCount == 0 {
Expand All @@ -138,14 +93,14 @@ func TestModifyPVC(t *testing.T) {
}{
{
name: "Modify succeeded",
pvc: createTestPVC(pvcName, "target-vac" /*vacName*/, testVac /*curVacName*/, testVac /*targetVacName*/),
pvc: createTestPVC(pvcName, targetVac /*vacName*/, testVac /*curVacName*/, testVac /*targetVacName*/),
pv: basePV,
modifyFailure: false,
expectFailure: false,
},
{
name: "Modify failed",
pvc: createTestPVC(pvcName, "target-vac" /*vacName*/, testVac /*curVacName*/, testVac /*targetVacName*/),
pvc: createTestPVC(pvcName, targetVac /*vacName*/, testVac /*curVacName*/, testVac /*targetVacName*/),
pv: basePV,
modifyFailure: true,
expectFailure: true,
Expand All @@ -154,67 +109,15 @@ func TestModifyPVC(t *testing.T) {

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
client := csi.NewMockClient("mock", true, true, true, true, true, false)
client := csi.NewMockClient(testDriverName, true, true, true, true, true, false)
if test.modifyFailure {
client.SetModifyFailed()
}
driverName, _ := client.GetDriverName(context.TODO())

initialObjects := []runtime.Object{}
if test.pvc != nil {
initialObjects = append(initialObjects, test.pvc)
}
if test.pv != nil {
test.pv.Spec.PersistentVolumeSource.CSI.Driver = driverName
initialObjects = append(initialObjects, test.pv)
}

// existing vac set in the pvc and pv
initialObjects = append(initialObjects, testVacObject)
// new vac used in modify volume
initialObjects = append(initialObjects, targetVacObject)

kubeClient, informerFactory := fakeK8s(initialObjects)
pvInformer := informerFactory.Core().V1().PersistentVolumes()
pvcInformer := informerFactory.Core().V1().PersistentVolumeClaims()
vacInformer := informerFactory.Storage().V1beta1().VolumeAttributesClasses()

csiModifier, err := modifier.NewModifierFromClient(client, 15*time.Second, kubeClient, informerFactory, false, driverName)
if err != nil {
t.Fatalf("Test %s: Unable to create modifier: %v", test.name, err)
}

featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.VolumeAttributesClass, true)
controller := NewModifyController(driverName,
csiModifier, kubeClient,
time.Second, false, informerFactory,
workqueue.DefaultControllerRateLimiter())

ctrlInstance, _ := controller.(*modifyController)

stopCh := make(chan struct{})
informerFactory.Start(stopCh)

ctx := context.TODO()
defer ctx.Done()
go controller.Run(1, ctx)

for _, obj := range initialObjects {
switch obj.(type) {
case *v1.PersistentVolume:
pvInformer.Informer().GetStore().Add(obj)
case *v1.PersistentVolumeClaim:
pvcInformer.Informer().GetStore().Add(obj)
case *storagev1beta1.VolumeAttributesClass:
vacInformer.Informer().GetStore().Add(obj)
default:
t.Fatalf("Test %s: Unknown initalObject type: %+v", test.name, obj)
}
}

time.Sleep(time.Second * 2)
initialObjects := []runtime.Object{test.pvc, test.pv, testVacObject, targetVacObject}
ctrlInstance := setupFakeK8sEnvironment(t, client, initialObjects)

_, _, err, _ = ctrlInstance.modify(test.pvc, test.pv)
_, _, err, _ := ctrlInstance.modify(test.pvc, test.pv)

if test.expectFailure && err == nil {
t.Errorf("for %s expected error got nothing", test.name)
Expand All @@ -228,3 +131,54 @@ func TestModifyPVC(t *testing.T) {
})
}
}

// setupFakeK8sEnvironment
func setupFakeK8sEnvironment(t *testing.T, client *csi.MockClient, initialObjects []runtime.Object) *modifyController {
t.Helper()

featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.VolumeAttributesClass, true)

/* Create fake kubeClient, Informers, and ModifyController */
kubeClient, informerFactory := fakeK8s(initialObjects)
pvInformer := informerFactory.Core().V1().PersistentVolumes()
pvcInformer := informerFactory.Core().V1().PersistentVolumeClaims()
vacInformer := informerFactory.Storage().V1beta1().VolumeAttributesClasses()

driverName, _ := client.GetDriverName(context.TODO())

csiModifier, err := modifier.NewModifierFromClient(client, 15*time.Second, kubeClient, informerFactory, false, driverName)
if err != nil {
t.Fatalf("Test %s: Unable to create modifier: %v", t.Name(), err)
}

controller := NewModifyController(driverName,
csiModifier, kubeClient,
0, false, informerFactory,
workqueue.DefaultControllerRateLimiter())

/* Start informers and ModifyController*/
stopCh := make(chan struct{})
informerFactory.Start(stopCh)

ctx := context.TODO()
defer ctx.Done()
go controller.Run(1, ctx)

/* Add initial objects to informer caches (TODO Q confirm this is true/needed?) */
for _, obj := range initialObjects {
switch obj.(type) {
case *v1.PersistentVolume:
pvInformer.Informer().GetStore().Add(obj)
case *v1.PersistentVolumeClaim:
pvcInformer.Informer().GetStore().Add(obj)
case *storagev1beta1.VolumeAttributesClass:
vacInformer.Informer().GetStore().Add(obj)
default:
t.Fatalf("Test %s: Unknown initalObject type: %+v", t.Name(), obj)
}
}

ctrlInstance, _ := controller.(*modifyController)

return ctrlInstance
}
4 changes: 3 additions & 1 deletion pkg/modifycontroller/modify_status_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,14 @@ import (
const (
pvcName = "foo"
pvcNamespace = "modify"
pvName = "testPV"
)

var (
fsVolumeMode = v1.PersistentVolumeFilesystem
testVac = "test-vac"
targetVac = "target-vac"
testDriverName = "mock"
infeasibleErr = status.Errorf(codes.InvalidArgument, "Parameters in VolumeAttributesClass is invalid")
finalErr = status.Errorf(codes.Internal, "Final error")
pvcConditionInProgress = v1.PersistentVolumeClaimCondition{
Expand Down Expand Up @@ -390,7 +392,7 @@ func createTestPV(capacityGB int, pvcName, pvcNamespace string, pvcUID types.UID
},
PersistentVolumeSource: v1.PersistentVolumeSource{
CSI: &v1.CSIPersistentVolumeSource{
Driver: "foo",
Driver: testDriverName,
VolumeHandle: "foo",
},
},
Expand Down
15 changes: 8 additions & 7 deletions pkg/modifycontroller/modify_volume_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,18 +25,18 @@ import (
var (
testVacObject = &storagev1beta1.VolumeAttributesClass{
ObjectMeta: metav1.ObjectMeta{Name: testVac},
DriverName: "test-driver",
DriverName: testDriverName,
Parameters: map[string]string{"iops": "3000"},
}

targetVacObject = &storagev1beta1.VolumeAttributesClass{
ObjectMeta: metav1.ObjectMeta{Name: targetVac},
DriverName: "test-driver",
DriverName: testDriverName,
Parameters: map[string]string{
"iops": "4567",
"csi.storage.k8s.io/pvc/name": "foo",
"csi.storage.k8s.io/pvc/namespace": "modify",
"csi.storage.k8s.io/pv/name": "testPV",
"csi.storage.k8s.io/pvc/name": pvcName,
"csi.storage.k8s.io/pvc/namespace": pvcNamespace,
"csi.storage.k8s.io/pv/name": pvName,
},
}
)
Expand Down Expand Up @@ -112,7 +112,7 @@ func TestModify(t *testing.T) {
t.Run(test.name, func(t *testing.T) {
// Setup
featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.VolumeAttributesClass, true)
client := csi.NewMockClient("foo", true, true, true, true, true, test.withExtraMetadata)
client := csi.NewMockClient(testDriverName, true, true, true, true, true, test.withExtraMetadata)
driverName, _ := client.GetDriverName(context.TODO())

var initialObjects []runtime.Object
Expand Down Expand Up @@ -199,7 +199,7 @@ func TestModify(t *testing.T) {

func createTestPVC(pvcName string, vacName string, curVacName string, targetVacName string) *v1.PersistentVolumeClaim {
pvc := &v1.PersistentVolumeClaim{
ObjectMeta: metav1.ObjectMeta{Name: pvcName, Namespace: "modify"},
ObjectMeta: metav1.ObjectMeta{Name: pvcName, Namespace: pvcNamespace},
Spec: v1.PersistentVolumeClaimSpec{
AccessModes: []v1.PersistentVolumeAccessMode{
v1.ReadWriteOnce,
Expand All @@ -211,6 +211,7 @@ func createTestPVC(pvcName string, vacName string, curVacName string, targetVacN
},
},
VolumeAttributesClassName: &vacName,
VolumeName: pvName,
},
Status: v1.PersistentVolumeClaimStatus{
Phase: v1.ClaimBound,
Expand Down

0 comments on commit babf8dc

Please sign in to comment.