soteria/internal/k8s/volumes_test.go

137 lines
5.4 KiB
Go
Raw Permalink Normal View History

package k8s
import (
"context"
"testing"
corev1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
k8sfake "k8s.io/client-go/kubernetes/fake"
k8stesting "k8s.io/client-go/testing"
)
func TestResolvePVCVolumeCoversSuccessAndFailures(t *testing.T) {
pvcBound := &corev1.PersistentVolumeClaim{
ObjectMeta: metav1.ObjectMeta{Name: "data", Namespace: "apps"},
Spec: corev1.PersistentVolumeClaimSpec{VolumeName: "pv-data"},
}
pvBound := &corev1.PersistentVolume{
ObjectMeta: metav1.ObjectMeta{Name: "pv-data"},
}
pvcNoVolume := &corev1.PersistentVolumeClaim{
ObjectMeta: metav1.ObjectMeta{Name: "pending", Namespace: "apps"},
}
client := &Client{Clientset: k8sfake.NewSimpleClientset(pvcBound, pvcNoVolume, pvBound)}
volumeName, pvc, pv, err := client.ResolvePVCVolume(context.Background(), "apps", "data")
if err != nil || volumeName != "pv-data" || pvc.Name != "data" || pv.Name != "pv-data" {
t.Fatalf("expected resolved pvc volume, got volume=%q pvc=%v pv=%v err=%v", volumeName, pvc, pv, err)
}
if _, _, _, err := client.ResolvePVCVolume(context.Background(), "apps", "pending"); err == nil {
t.Fatalf("expected unbound pvc error")
}
if _, _, _, err := client.ResolvePVCVolume(context.Background(), "apps", "missing"); err == nil {
t.Fatalf("expected missing pvc error")
}
clientset := k8sfake.NewSimpleClientset(pvcBound)
clientset.PrependReactor("get", "persistentvolumes", func(action k8stesting.Action) (bool, runtime.Object, error) {
return true, nil, apierrors.NewNotFound(schema.GroupResource{Resource: "persistentvolumes"}, "pv-data")
})
client = &Client{Clientset: clientset}
if _, _, _, err := client.ResolvePVCVolume(context.Background(), "apps", "data"); err == nil {
t.Fatalf("expected missing pv error")
}
}
func TestListBoundPVCsAndExistsCoversFilteringSortingAndCapacityFallback(t *testing.T) {
storageClass := "fast"
client := &Client{Clientset: k8sfake.NewSimpleClientset(
&corev1.PersistentVolumeClaim{
ObjectMeta: metav1.ObjectMeta{Name: "zeta", Namespace: "ops"},
Spec: corev1.PersistentVolumeClaimSpec{
VolumeName: "pv-zeta",
StorageClassName: &storageClass,
AccessModes: []corev1.PersistentVolumeAccessMode{corev1.ReadWriteMany},
Resources: corev1.VolumeResourceRequirements{
Requests: corev1.ResourceList{corev1.ResourceStorage: resource.MustParse("2Gi")},
},
},
Status: corev1.PersistentVolumeClaimStatus{Phase: corev1.ClaimBound},
},
&corev1.PersistentVolumeClaim{
ObjectMeta: metav1.ObjectMeta{Name: "alpha", Namespace: "apps"},
Spec: corev1.PersistentVolumeClaimSpec{
VolumeName: "pv-alpha",
AccessModes: []corev1.PersistentVolumeAccessMode{corev1.ReadWriteOnce},
},
Status: corev1.PersistentVolumeClaimStatus{
Phase: corev1.ClaimBound,
Capacity: corev1.ResourceList{corev1.ResourceStorage: resource.MustParse("5Gi")},
},
},
&corev1.PersistentVolumeClaim{
ObjectMeta: metav1.ObjectMeta{Name: "skip-unbound", Namespace: "apps"},
Status: corev1.PersistentVolumeClaimStatus{Phase: corev1.ClaimPending},
},
&corev1.PersistentVolumeClaim{
ObjectMeta: metav1.ObjectMeta{Name: "skip-novol", Namespace: "apps"},
Status: corev1.PersistentVolumeClaimStatus{Phase: corev1.ClaimBound},
},
)}
items, err := client.ListBoundPVCs(context.Background())
if err != nil {
t.Fatalf("list bound pvcs: %v", err)
}
if len(items) != 2 {
t.Fatalf("expected two bound pvc summaries, got %#v", items)
}
if items[0].Namespace != "apps" || items[0].Name != "alpha" || items[1].Namespace != "ops" || items[1].Name != "zeta" {
t.Fatalf("expected sorted pvc summaries, got %#v", items)
}
if items[0].Capacity != "5Gi" || items[1].Capacity != "2Gi" {
t.Fatalf("expected status/spec capacity fallback, got %#v", items)
}
if len(items[0].AccessModes) != 1 || items[0].AccessModes[0] != string(corev1.ReadWriteOnce) {
t.Fatalf("expected access modes to be captured, got %#v", items[0])
}
exists, err := client.PersistentVolumeClaimExists(context.Background(), "apps", "alpha")
if err != nil || !exists {
t.Fatalf("expected pvc to exist, got %v %v", exists, err)
}
exists, err = client.PersistentVolumeClaimExists(context.Background(), "apps", "missing")
if err != nil || exists {
t.Fatalf("expected pvc to be missing, got %v %v", exists, err)
}
clientset := k8sfake.NewSimpleClientset()
clientset.PrependReactor("list", "persistentvolumeclaims", func(action k8stesting.Action) (bool, runtime.Object, error) {
return true, nil, apierrors.NewForbidden(schema.GroupResource{Resource: "persistentvolumeclaims"}, "", nil)
})
client = &Client{Clientset: clientset}
if _, err := client.ListBoundPVCs(context.Background()); err == nil {
t.Fatalf("expected wrapped pvc list error")
}
}
func TestPersistentVolumeClaimExistsWrapsUnexpectedErrors(t *testing.T) {
clientset := k8sfake.NewSimpleClientset()
clientset.PrependReactor("get", "persistentvolumeclaims", func(action k8stesting.Action) (bool, runtime.Object, error) {
return true, nil, apierrors.NewForbidden(schema.GroupResource{Resource: "persistentvolumeclaims"}, "data", nil)
})
client := &Client{Clientset: clientset}
if _, err := client.PersistentVolumeClaimExists(context.Background(), "apps", "data"); err == nil {
t.Fatalf("expected wrapped pvc get error")
}
}