2026-04-20 18:38:12 -03:00
|
|
|
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)
|
|
|
|
|
}
|
2026-04-20 21:24:27 -03:00
|
|
|
|
|
|
|
|
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")
|
|
|
|
|
}
|
2026-04-20 18:38:12 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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")
|
|
|
|
|
}
|
|
|
|
|
}
|