velero/internal/resourcepolicies/resource_policies_test.go

1076 lines
25 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 resourcepolicies
import (
"testing"
"github.com/stretchr/testify/assert"
corev1api "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
func TestLoadResourcePolicies(t *testing.T) {
testCases := []struct {
name string
yamlData string
wantErr bool
}{
{
name: "unknown key in yaml",
yamlData: `version: v1
volumePolicies:
- conditions:
capacity: "0,100Gi"
unknown: {}
storageClass:
- gp2
- ebs-sc
action:
type: skip`,
wantErr: true,
},
{
name: "reduplicated key in yaml",
yamlData: `version: v1
volumePolicies:
- conditions:
capacity: "0,100Gi"
capacity: "0,100Gi"
storageClass:
- gp2
- ebs-sc
action:
type: skip`,
wantErr: true,
},
{
name: "error format of storageClass",
yamlData: `version: v1
volumePolicies:
- conditions:
capacity: "0,100Gi"
storageClass: gp2
action:
type: skip`,
wantErr: true,
},
{
name: "error format of csi",
yamlData: `version: v1
volumePolicies:
- conditions:
capacity: "0,100Gi"
csi: gp2
action:
type: skip`,
wantErr: true,
},
{
name: "error format of nfs",
yamlData: `version: v1
volumePolicies:
- conditions:
capacity: "0,100Gi"
csi: {}
nfs: abc
action:
type: skip`,
wantErr: true,
},
{
name: "supported format volume policies",
yamlData: `version: v1
volumePolicies:
- conditions:
capacity: '0,100Gi'
csi:
driver: aws.efs.csi.driver
action:
type: skip
`,
wantErr: false,
},
{
name: "supported format csi driver with volumeAttributes for volume policies",
yamlData: `version: v1
volumePolicies:
- conditions:
capacity: '0,100Gi'
csi:
driver: aws.efs.csi.driver
volumeAttributes:
key1: value1
action:
type: skip
`,
wantErr: false,
},
{
name: "supported format pvcLabels",
yamlData: `version: v1
volumePolicies:
- conditions:
pvcLabels:
environment: production
app: database
action:
type: skip
`,
wantErr: false,
},
{
name: "error format of pvcLabels (not a map)",
yamlData: `version: v1
volumePolicies:
- conditions:
pvcLabels: "production"
action:
type: skip
`,
wantErr: true,
},
{
name: "supported format pvcLabels with extra keys",
yamlData: `version: v1
volumePolicies:
- conditions:
pvcLabels:
environment: production
region: us-west
action:
type: skip
`,
wantErr: false,
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
_, err := unmarshalResourcePolicies(&tc.yamlData)
if (err != nil) != tc.wantErr {
t.Fatalf("Expected error %v, but got error %v", tc.wantErr, err)
}
})
}
}
func TestGetResourceMatchedAction(t *testing.T) {
resPolicies := &ResourcePolicies{
Version: "v1",
VolumePolicies: []VolumePolicy{
{
Action: Action{Type: "skip"},
Conditions: map[string]any{
"capacity": "0,10Gi",
"storageClass": []string{"gp2", "ebs-sc"},
"csi": any(
map[string]any{
"driver": "aws.efs.csi.driver",
}),
},
},
{
Action: Action{Type: "skip"},
Conditions: map[string]any{
"csi": any(
map[string]any{
"driver": "files.csi.driver",
"volumeAttributes": map[string]string{"protocol": "nfs"},
}),
},
},
{
Action: Action{Type: "snapshot"},
Conditions: map[string]any{
"capacity": "10,100Gi",
"storageClass": []string{"gp2", "ebs-sc"},
"csi": any(
map[string]any{
"driver": "aws.efs.csi.driver",
}),
},
},
{
Action: Action{Type: "fs-backup"},
Conditions: map[string]any{
"storageClass": []string{"gp2", "ebs-sc"},
"csi": any(
map[string]any{
"driver": "aws.efs.csi.driver",
}),
},
},
{
Action: Action{Type: "snapshot"},
Conditions: map[string]any{
"pvcLabels": map[string]string{
"environment": "production",
},
},
},
},
}
testCases := []struct {
name string
volume *structuredVolume
expectedAction *Action
}{
{
name: "match policy",
volume: &structuredVolume{
capacity: *resource.NewQuantity(5<<30, resource.BinarySI),
storageClass: "ebs-sc",
csi: &csiVolumeSource{Driver: "aws.efs.csi.driver"},
},
expectedAction: &Action{Type: "skip"},
},
{
name: "match policy AFS NFS",
volume: &structuredVolume{
capacity: *resource.NewQuantity(5<<30, resource.BinarySI),
storageClass: "afs-nfs",
csi: &csiVolumeSource{Driver: "files.csi.driver", VolumeAttributes: map[string]string{"protocol": "nfs"}},
},
expectedAction: &Action{Type: "skip"},
},
{
name: "match policy AFS SMB",
volume: &structuredVolume{
capacity: *resource.NewQuantity(5<<30, resource.BinarySI),
storageClass: "afs-smb",
csi: &csiVolumeSource{Driver: "files.csi.driver"},
},
expectedAction: nil,
},
{
name: "both matches return the first policy",
volume: &structuredVolume{
capacity: *resource.NewQuantity(50<<30, resource.BinarySI),
storageClass: "ebs-sc",
csi: &csiVolumeSource{Driver: "aws.efs.csi.driver"},
},
expectedAction: &Action{Type: "snapshot"},
},
{
name: "mismatch all policies",
volume: &structuredVolume{
capacity: *resource.NewQuantity(50<<30, resource.BinarySI),
storageClass: "ebs-sc",
nfs: &nFSVolumeSource{},
},
expectedAction: nil,
},
{
name: "match pvcLabels condition",
volume: &structuredVolume{
capacity: *resource.NewQuantity(5<<30, resource.BinarySI),
storageClass: "some-class",
pvcLabels: map[string]string{
"environment": "production",
"team": "backend",
},
},
expectedAction: &Action{Type: "snapshot"},
},
{
name: "mismatch pvcLabels condition",
volume: &structuredVolume{
capacity: *resource.NewQuantity(5<<30, resource.BinarySI),
storageClass: "some-class",
pvcLabels: map[string]string{
"environment": "staging",
},
},
expectedAction: nil,
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
policies := &Policies{}
err := policies.BuildPolicy(resPolicies)
if err != nil {
t.Errorf("Failed to build policy with error %v", err)
}
action := policies.match(tc.volume)
if action == nil {
if tc.expectedAction != nil {
t.Errorf("Expected action %v, but got result nil", tc.expectedAction.Type)
}
} else {
if tc.expectedAction != nil {
if action.Type != tc.expectedAction.Type {
t.Errorf("Expected action %v, but got result %v", tc.expectedAction.Type, action.Type)
}
} else {
t.Errorf("Expected action nil, but got result %v", action.Type)
}
}
})
}
}
func TestGetResourcePoliciesFromConfig(t *testing.T) {
// Create a test ConfigMap
cm := &corev1api.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: "test-configmap",
Namespace: "test-namespace",
},
Data: map[string]string{
"test-data": `version: v1
volumePolicies:
- conditions:
capacity: '0,10Gi'
csi:
driver: disks.csi.driver
action:
type: skip
- conditions:
csi:
driver: files.csi.driver
volumeAttributes:
protocol: nfs
action:
type: skip
- conditions:
pvcLabels:
environment: production
action:
type: skip
`,
},
}
// Call the function and check for errors
resPolicies, err := getResourcePoliciesFromConfig(cm)
assert.NoError(t, err)
// Check that the returned resourcePolicies object contains the expected data
assert.Equal(t, "v1", resPolicies.version)
assert.Len(t, resPolicies.volumePolicies, 3)
policies := ResourcePolicies{
Version: "v1",
VolumePolicies: []VolumePolicy{
{
Conditions: map[string]any{
"capacity": "0,10Gi",
"csi": map[string]any{
"driver": "disks.csi.driver",
},
},
Action: Action{
Type: Skip,
},
},
{
Conditions: map[string]any{
"csi": map[string]any{
"driver": "files.csi.driver",
"volumeAttributes": map[string]string{"protocol": "nfs"},
},
},
Action: Action{
Type: Skip,
},
},
{
Conditions: map[string]any{
"pvcLabels": map[string]string{
"environment": "production",
},
},
Action: Action{
Type: Skip,
},
},
},
}
p := &Policies{}
err = p.BuildPolicy(&policies)
if err != nil {
t.Fatalf("failed to build policy: %v", err)
}
assert.Equal(t, p, resPolicies)
}
func TestGetMatchAction(t *testing.T) {
testCases := []struct {
name string
yamlData string
vol *corev1api.PersistentVolume
podVol *corev1api.Volume
pvc *corev1api.PersistentVolumeClaim
skip bool
}{
{
name: "empty csi",
yamlData: `version: v1
volumePolicies:
- conditions:
csi: {}
action:
type: skip`,
vol: &corev1api.PersistentVolume{
Spec: corev1api.PersistentVolumeSpec{
PersistentVolumeSource: corev1api.PersistentVolumeSource{
CSI: &corev1api.CSIPersistentVolumeSource{Driver: "ebs.csi.aws.com"},
}},
},
skip: true,
},
{
name: "empty csi with pv no csi driver",
yamlData: `version: v1
volumePolicies:
- conditions:
csi: {}
action:
type: skip`,
vol: &corev1api.PersistentVolume{
Spec: corev1api.PersistentVolumeSpec{
Capacity: corev1api.ResourceList{
corev1api.ResourceStorage: resource.MustParse("1Gi"),
}},
},
skip: false,
},
{
name: "Skip AFS CSI condition with Disk volumes",
yamlData: `version: v1
volumePolicies:
- conditions:
csi:
driver: files.csi.driver
action:
type: skip`,
vol: &corev1api.PersistentVolume{
Spec: corev1api.PersistentVolumeSpec{
PersistentVolumeSource: corev1api.PersistentVolumeSource{
CSI: &corev1api.CSIPersistentVolumeSource{Driver: "disks.csi.driver"},
}},
},
skip: false,
},
{
name: "Skip AFS CSI condition with AFS volumes",
yamlData: `version: v1
volumePolicies:
- conditions:
csi:
driver: files.csi.driver
action:
type: skip`,
vol: &corev1api.PersistentVolume{
Spec: corev1api.PersistentVolumeSpec{
PersistentVolumeSource: corev1api.PersistentVolumeSource{
CSI: &corev1api.CSIPersistentVolumeSource{Driver: "files.csi.driver"},
}},
},
skip: true,
},
{
name: "Skip AFS NFS CSI condition with Disk volumes",
yamlData: `version: v1
volumePolicies:
- conditions:
csi:
driver: files.csi.driver
volumeAttributes:
protocol: nfs
action:
type: skip
`,
vol: &corev1api.PersistentVolume{
Spec: corev1api.PersistentVolumeSpec{
PersistentVolumeSource: corev1api.PersistentVolumeSource{
CSI: &corev1api.CSIPersistentVolumeSource{Driver: "disks.csi.driver"},
}},
},
skip: false,
},
{
name: "Skip AFS NFS CSI condition with AFS SMB volumes",
yamlData: `version: v1
volumePolicies:
- conditions:
csi:
driver: files.csi.driver
volumeAttributes:
protocol: nfs
action:
type: skip
`,
vol: &corev1api.PersistentVolume{
Spec: corev1api.PersistentVolumeSpec{
PersistentVolumeSource: corev1api.PersistentVolumeSource{
CSI: &corev1api.CSIPersistentVolumeSource{Driver: "files.csi.driver", VolumeAttributes: map[string]string{"key1": "val1"}},
}},
},
skip: false,
},
{
name: "Skip AFS NFS CSI condition with AFS NFS volumes",
yamlData: `version: v1
volumePolicies:
- conditions:
csi:
driver: files.csi.driver
volumeAttributes:
protocol: nfs
action:
type: skip
`,
vol: &corev1api.PersistentVolume{
Spec: corev1api.PersistentVolumeSpec{
PersistentVolumeSource: corev1api.PersistentVolumeSource{
CSI: &corev1api.CSIPersistentVolumeSource{Driver: "files.csi.driver", VolumeAttributes: map[string]string{"protocol": "nfs"}},
}},
},
skip: true,
},
{
name: "Skip Disk and AFS NFS CSI condition with Disk volumes",
yamlData: `version: v1
volumePolicies:
- conditions:
csi:
driver: disks.csi.driver
action:
type: skip
- conditions:
csi:
driver: files.csi.driver
volumeAttributes:
protocol: nfs
action:
type: skip`,
vol: &corev1api.PersistentVolume{
Spec: corev1api.PersistentVolumeSpec{
PersistentVolumeSource: corev1api.PersistentVolumeSource{
CSI: &corev1api.CSIPersistentVolumeSource{Driver: "disks.csi.driver", VolumeAttributes: map[string]string{"key1": "val1"}},
}},
},
skip: true,
},
{
name: "Skip Disk and AFS NFS CSI condition with AFS SMB volumes",
yamlData: `version: v1
volumePolicies:
- conditions:
csi:
driver: disks.csi.driver
action:
type: skip
- conditions:
csi:
driver: files.csi.driver
volumeAttributes:
protocol: nfs
action:
type: skip`,
vol: &corev1api.PersistentVolume{
Spec: corev1api.PersistentVolumeSpec{
PersistentVolumeSource: corev1api.PersistentVolumeSource{
CSI: &corev1api.CSIPersistentVolumeSource{Driver: "files.csi.driver", VolumeAttributes: map[string]string{"key1": "val1"}},
}},
},
skip: false,
},
{
name: "Skip Disk and AFS NFS CSI condition with AFS NFS volumes",
yamlData: `version: v1
volumePolicies:
- conditions:
csi:
driver: disks.csi.driver
action:
type: skip
- conditions:
csi:
driver: files.csi.driver
volumeAttributes:
protocol: nfs
action:
type: skip`,
vol: &corev1api.PersistentVolume{
Spec: corev1api.PersistentVolumeSpec{
PersistentVolumeSource: corev1api.PersistentVolumeSource{
CSI: &corev1api.CSIPersistentVolumeSource{Driver: "files.csi.driver", VolumeAttributes: map[string]string{"key1": "val1", "protocol": "nfs"}},
}},
},
skip: true,
},
{
name: "csi not configured and testing capacity condition",
yamlData: `version: v1
volumePolicies:
- conditions:
capacity: "0,100Gi"
action:
type: skip`,
vol: &corev1api.PersistentVolume{
Spec: corev1api.PersistentVolumeSpec{
Capacity: corev1api.ResourceList{
corev1api.ResourceStorage: resource.MustParse("1Gi"),
},
PersistentVolumeSource: corev1api.PersistentVolumeSource{
CSI: &corev1api.CSIPersistentVolumeSource{Driver: "ebs.csi.aws.com"},
}},
},
skip: true,
},
{
name: "empty nfs",
yamlData: `version: v1
volumePolicies:
- conditions:
nfs: {}
action:
type: skip`,
vol: &corev1api.PersistentVolume{
Spec: corev1api.PersistentVolumeSpec{
PersistentVolumeSource: corev1api.PersistentVolumeSource{
NFS: &corev1api.NFSVolumeSource{Server: "192.168.1.20"},
}},
},
skip: true,
},
{
name: "nfs not configured",
yamlData: `version: v1
volumePolicies:
- conditions:
capacity: "0,100Gi"
action:
type: skip`,
vol: &corev1api.PersistentVolume{
Spec: corev1api.PersistentVolumeSpec{
Capacity: corev1api.ResourceList{
corev1api.ResourceStorage: resource.MustParse("1Gi"),
},
PersistentVolumeSource: corev1api.PersistentVolumeSource{
NFS: &corev1api.NFSVolumeSource{Server: "192.168.1.20"},
},
},
},
skip: true,
},
{
name: "empty nfs with pv no nfs volume source",
yamlData: `version: v1
volumePolicies:
- conditions:
capacity: "0,100Gi"
nfs: {}
action:
type: skip`,
vol: &corev1api.PersistentVolume{
Spec: corev1api.PersistentVolumeSpec{
Capacity: corev1api.ResourceList{
corev1api.ResourceStorage: resource.MustParse("1Gi"),
},
},
},
skip: false,
},
{
name: "match volume by types",
yamlData: `version: v1
volumePolicies:
- conditions:
capacity: "0,100Gi"
volumeTypes:
- local
- hostPath
action:
type: skip`,
vol: &corev1api.PersistentVolume{
Spec: corev1api.PersistentVolumeSpec{
Capacity: corev1api.ResourceList{
corev1api.ResourceStorage: resource.MustParse("1Gi"),
},
PersistentVolumeSource: corev1api.PersistentVolumeSource{
HostPath: &corev1api.HostPathVolumeSource{Path: "/mnt/data"},
},
},
},
skip: true,
},
{
name: "mismatch volume by types",
yamlData: `version: v1
volumePolicies:
- conditions:
capacity: "0,100Gi"
volumeTypes:
- local
action:
type: skip`,
vol: &corev1api.PersistentVolume{
Spec: corev1api.PersistentVolumeSpec{
Capacity: corev1api.ResourceList{
corev1api.ResourceStorage: resource.MustParse("1Gi"),
},
PersistentVolumeSource: corev1api.PersistentVolumeSource{
HostPath: &corev1api.HostPathVolumeSource{Path: "/mnt/data"},
},
},
},
skip: false,
},
{
name: "PVC labels match",
yamlData: `version: v1
volumePolicies:
- conditions:
capacity: "0,100Gi"
pvcLabels:
environment: production
action:
type: skip`,
vol: &corev1api.PersistentVolume{
ObjectMeta: metav1.ObjectMeta{
Name: "pv-1",
},
Spec: corev1api.PersistentVolumeSpec{
Capacity: corev1api.ResourceList{
corev1api.ResourceStorage: resource.MustParse("1Gi"),
},
PersistentVolumeSource: corev1api.PersistentVolumeSource{},
ClaimRef: &corev1api.ObjectReference{
Namespace: "default",
Name: "pvc-1",
},
},
},
pvc: &corev1api.PersistentVolumeClaim{
ObjectMeta: metav1.ObjectMeta{
Namespace: "default",
Name: "pvc-1",
Labels: map[string]string{"environment": "production"},
},
},
skip: true,
},
{
name: "PVC labels match, criteria label is a subset of the pvc labels",
yamlData: `version: v1
volumePolicies:
- conditions:
capacity: "0,100Gi"
pvcLabels:
environment: production
action:
type: skip`,
vol: &corev1api.PersistentVolume{
ObjectMeta: metav1.ObjectMeta{
Name: "pv-1",
},
Spec: corev1api.PersistentVolumeSpec{
Capacity: corev1api.ResourceList{
corev1api.ResourceStorage: resource.MustParse("1Gi"),
},
PersistentVolumeSource: corev1api.PersistentVolumeSource{},
ClaimRef: &corev1api.ObjectReference{
Namespace: "default",
Name: "pvc-1",
},
},
},
pvc: &corev1api.PersistentVolumeClaim{
ObjectMeta: metav1.ObjectMeta{
Namespace: "default",
Name: "pvc-1",
Labels: map[string]string{"environment": "production", "app": "backend"},
},
},
skip: true,
},
{
name: "PVC labels match don't match exactly",
yamlData: `version: v1
volumePolicies:
- conditions:
capacity: "0,100Gi"
pvcLabels:
environment: production
app: frontend
action:
type: skip`,
vol: &corev1api.PersistentVolume{
ObjectMeta: metav1.ObjectMeta{
Name: "pv-1",
},
Spec: corev1api.PersistentVolumeSpec{
Capacity: corev1api.ResourceList{
corev1api.ResourceStorage: resource.MustParse("1Gi"),
},
PersistentVolumeSource: corev1api.PersistentVolumeSource{},
ClaimRef: &corev1api.ObjectReference{
Namespace: "default",
Name: "pvc-1",
},
},
},
pvc: &corev1api.PersistentVolumeClaim{
ObjectMeta: metav1.ObjectMeta{
Namespace: "default",
Name: "pvc-1",
Labels: map[string]string{"environment": "production"},
},
},
skip: false,
},
{
name: "PVC labels mismatch",
yamlData: `version: v1
volumePolicies:
- conditions:
capacity: "0,100Gi"
pvcLabels:
environment: production
action:
type: skip`,
vol: &corev1api.PersistentVolume{
ObjectMeta: metav1.ObjectMeta{
Name: "pv-2",
},
Spec: corev1api.PersistentVolumeSpec{
Capacity: corev1api.ResourceList{
corev1api.ResourceStorage: resource.MustParse("1Gi"),
},
PersistentVolumeSource: corev1api.PersistentVolumeSource{},
ClaimRef: &corev1api.ObjectReference{
Namespace: "default",
Name: "pvc-2",
},
},
},
pvc: &corev1api.PersistentVolumeClaim{
ObjectMeta: metav1.ObjectMeta{
Namespace: "default",
Name: "pvc-1",
Labels: map[string]string{"environment": "staging"},
},
},
skip: false,
},
{
name: "PodVolume case with PVC labels match",
yamlData: `version: v1
volumePolicies:
- conditions:
pvcLabels:
environment: production
action:
type: skip`,
vol: nil,
podVol: &corev1api.Volume{Name: "pod-vol-1"},
pvc: &corev1api.PersistentVolumeClaim{
ObjectMeta: metav1.ObjectMeta{
Namespace: "default",
Name: "pvc-1",
Labels: map[string]string{"environment": "production"},
},
},
skip: true,
},
{
name: "PodVolume case with PVC labels mismatch",
yamlData: `version: v1
volumePolicies:
- conditions:
pvcLabels:
environment: production
action:
type: skip`,
vol: nil,
podVol: &corev1api.Volume{Name: "pod-vol-2"},
pvc: &corev1api.PersistentVolumeClaim{
ObjectMeta: metav1.ObjectMeta{
Namespace: "default",
Name: "pvc-2",
Labels: map[string]string{"environment": "staging"},
},
},
skip: false,
},
{
name: "PodVolume case with PVC labels match with extra keys on PVC",
yamlData: `version: v1
volumePolicies:
- conditions:
pvcLabels:
environment: production
action:
type: skip`,
vol: nil,
podVol: &corev1api.Volume{Name: "pod-vol-3"},
pvc: &corev1api.PersistentVolumeClaim{
ObjectMeta: metav1.ObjectMeta{
Namespace: "default",
Name: "pvc-3",
Labels: map[string]string{"environment": "production", "app": "backend"},
},
},
skip: true,
},
{
name: "PodVolume case with PVC labels don't match exactly",
yamlData: `version: v1
volumePolicies:
- conditions:
pvcLabels:
environment: production
app: frontend
action:
type: skip`,
vol: nil,
podVol: &corev1api.Volume{Name: "pod-vol-4"},
pvc: &corev1api.PersistentVolumeClaim{
ObjectMeta: metav1.ObjectMeta{
Namespace: "default",
Name: "pvc-4",
Labels: map[string]string{"environment": "production"},
},
},
skip: false,
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
resPolicies, err := unmarshalResourcePolicies(&tc.yamlData)
if err != nil {
t.Fatalf("got error when get match action %v", err)
}
assert.NoError(t, err)
policies := &Policies{}
err = policies.BuildPolicy(resPolicies)
assert.NoError(t, err)
vfd := VolumeFilterData{}
if tc.pvc != nil {
vfd.PVC = tc.pvc
}
if tc.vol != nil {
vfd.PersistentVolume = tc.vol
}
if tc.podVol != nil {
vfd.PodVolume = tc.podVol
}
action, err := policies.GetMatchAction(vfd)
assert.NoError(t, err)
if tc.skip {
if action.Type != Skip {
t.Fatalf("Expected action skip but is %v", action.Type)
}
} else if action != nil && action.Type == Skip {
t.Fatalf("Expected action not skip but is %v", action.Type)
}
})
}
}
func TestGetMatchAction_Errors(t *testing.T) {
p := &Policies{}
testCases := []struct {
name string
input any
expectedErr string
}{
{
name: "invalid input type",
input: "invalid input",
expectedErr: "failed to convert input to VolumeFilterData",
},
{
name: "no volume provided",
input: VolumeFilterData{
PersistentVolume: nil,
PodVolume: nil,
PVC: nil,
},
expectedErr: "failed to convert object",
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
action, err := p.GetMatchAction(tc.input)
assert.Error(t, err)
assert.Contains(t, err.Error(), tc.expectedErr)
assert.Nil(t, action)
})
}
}
func TestParsePVC(t *testing.T) {
tests := []struct {
name string
pvc *corev1api.PersistentVolumeClaim
expectedLabels map[string]string
expectErr bool
}{
{
name: "valid PVC with labels",
pvc: &corev1api.PersistentVolumeClaim{
ObjectMeta: metav1.ObjectMeta{
Labels: map[string]string{"env": "prod"},
},
},
expectedLabels: map[string]string{"env": "prod"},
expectErr: false,
},
{
name: "valid PVC with empty labels",
pvc: &corev1api.PersistentVolumeClaim{
ObjectMeta: metav1.ObjectMeta{
Labels: map[string]string{},
},
},
expectedLabels: nil,
expectErr: false,
},
{
name: "nil PVC pointer",
pvc: (*corev1api.PersistentVolumeClaim)(nil),
expectedLabels: nil,
expectErr: false,
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
s := &structuredVolume{}
s.parsePVC(tc.pvc)
assert.Equal(t, tc.expectedLabels, s.pvcLabels)
})
}
}