dev-pod-api-build/internal/k8s/cluster_test.go
2026-04-16 04:16:36 +00:00

224 lines
6.2 KiB
Go

package k8s
import (
"context"
"testing"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes/fake"
)
func TestGetClusterStatus_Nodes(t *testing.T) {
cs := fake.NewSimpleClientset(
&corev1.Node{
ObjectMeta: metav1.ObjectMeta{Name: "node-1"},
Status: corev1.NodeStatus{
Conditions: []corev1.NodeCondition{
{Type: corev1.NodeReady, Status: corev1.ConditionTrue},
},
Capacity: corev1.ResourceList{
corev1.ResourceCPU: resource.MustParse("8"),
corev1.ResourceMemory: resource.MustParse("32Gi"),
},
Allocatable: corev1.ResourceList{
corev1.ResourceCPU: resource.MustParse("7800m"),
corev1.ResourceMemory: resource.MustParse("30Gi"),
},
},
},
&corev1.Node{
ObjectMeta: metav1.ObjectMeta{Name: "node-2"},
Status: corev1.NodeStatus{
Conditions: []corev1.NodeCondition{
{Type: corev1.NodeReady, Status: corev1.ConditionFalse},
},
Capacity: corev1.ResourceList{
corev1.ResourceCPU: resource.MustParse("4"),
corev1.ResourceMemory: resource.MustParse("16Gi"),
},
Allocatable: corev1.ResourceList{
corev1.ResourceCPU: resource.MustParse("3800m"),
corev1.ResourceMemory: resource.MustParse("14Gi"),
},
},
},
)
client := NewClientWithClientset(cs, nil, Config{})
status, err := client.GetClusterStatus(context.Background())
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if len(status.Nodes) != 2 {
t.Fatalf("expected 2 nodes, got %d", len(status.Nodes))
}
n1 := status.Nodes[0]
if n1.Name != "node-1" {
t.Fatalf("expected node-1, got %s", n1.Name)
}
if n1.Status != "Ready" {
t.Fatalf("expected Ready, got %s", n1.Status)
}
if n1.CPUCapacity != "8" {
t.Fatalf("expected CPU capacity 8, got %s", n1.CPUCapacity)
}
n2 := status.Nodes[1]
if n2.Status != "NotReady" {
t.Fatalf("expected NotReady, got %s", n2.Status)
}
// Check totals: 8 + 4 = 12 CPU, 7800m + 3800m = 11600m allocatable
if status.Total.CPUCapacity != "12" {
t.Fatalf("expected total CPU capacity 12, got %s", status.Total.CPUCapacity)
}
}
func TestGetClusterStatus_EmptyCluster(t *testing.T) {
cs := fake.NewSimpleClientset()
client := NewClientWithClientset(cs, nil, Config{})
status, err := client.GetClusterStatus(context.Background())
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if len(status.Nodes) != 0 {
t.Fatalf("expected 0 nodes, got %d", len(status.Nodes))
}
}
func TestGetClusterStatus_NodeWithNoReadyCondition(t *testing.T) {
cs := fake.NewSimpleClientset(
&corev1.Node{
ObjectMeta: metav1.ObjectMeta{Name: "node-unknown"},
Status: corev1.NodeStatus{
Conditions: []corev1.NodeCondition{
{Type: corev1.NodeMemoryPressure, Status: corev1.ConditionFalse},
},
Capacity: corev1.ResourceList{
corev1.ResourceCPU: resource.MustParse("4"),
corev1.ResourceMemory: resource.MustParse("8Gi"),
},
Allocatable: corev1.ResourceList{
corev1.ResourceCPU: resource.MustParse("4"),
corev1.ResourceMemory: resource.MustParse("8Gi"),
},
},
},
)
client := NewClientWithClientset(cs, nil, Config{})
status, err := client.GetClusterStatus(context.Background())
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if status.Nodes[0].Status != "Unknown" {
t.Fatalf("expected Unknown, got %s", status.Nodes[0].Status)
}
}
func TestGetCacheStats_AllBound(t *testing.T) {
cs := fake.NewSimpleClientset(
&corev1.PersistentVolumeClaim{
ObjectMeta: metav1.ObjectMeta{Name: "verdaccio-storage", Namespace: "dev-infra"},
Status: corev1.PersistentVolumeClaimStatus{
Phase: corev1.ClaimBound,
Capacity: corev1.ResourceList{corev1.ResourceStorage: resource.MustParse("10Gi")},
},
},
&corev1.PersistentVolumeClaim{
ObjectMeta: metav1.ObjectMeta{Name: "athens-storage", Namespace: "dev-infra"},
Status: corev1.PersistentVolumeClaimStatus{
Phase: corev1.ClaimBound,
Capacity: corev1.ResourceList{corev1.ResourceStorage: resource.MustParse("10Gi")},
},
},
&corev1.PersistentVolumeClaim{
ObjectMeta: metav1.ObjectMeta{Name: "cargo-proxy-cache", Namespace: "dev-infra"},
Status: corev1.PersistentVolumeClaimStatus{
Phase: corev1.ClaimBound,
Capacity: corev1.ResourceList{corev1.ResourceStorage: resource.MustParse("10Gi")},
},
},
)
client := NewClientWithClientset(cs, nil, Config{})
stats, err := client.GetCacheStats(context.Background())
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if len(stats) != 3 {
t.Fatalf("expected 3 cache stats, got %d", len(stats))
}
for _, s := range stats {
if s.Status != "Bound" {
t.Fatalf("expected Bound for %s, got %s", s.Name, s.Status)
}
if s.Capacity != "10Gi" {
t.Fatalf("expected 10Gi capacity for %s, got %s", s.Name, s.Capacity)
}
}
}
func TestGetCacheStats_MissingPVC(t *testing.T) {
// Only verdaccio exists
cs := fake.NewSimpleClientset(
&corev1.PersistentVolumeClaim{
ObjectMeta: metav1.ObjectMeta{Name: "verdaccio-storage", Namespace: "dev-infra"},
Status: corev1.PersistentVolumeClaimStatus{
Phase: corev1.ClaimBound,
Capacity: corev1.ResourceList{corev1.ResourceStorage: resource.MustParse("10Gi")},
},
},
)
client := NewClientWithClientset(cs, nil, Config{})
stats, err := client.GetCacheStats(context.Background())
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if len(stats) != 3 {
t.Fatalf("expected 3 entries, got %d", len(stats))
}
for _, s := range stats {
switch s.Name {
case "verdaccio":
if s.Status != "Bound" {
t.Fatalf("expected Bound for verdaccio, got %s", s.Status)
}
case "athens", "cargo-proxy":
if s.Status != "NotFound" {
t.Fatalf("expected NotFound for %s, got %s", s.Name, s.Status)
}
}
}
}
func TestGetCacheStats_EmptyCluster(t *testing.T) {
cs := fake.NewSimpleClientset()
client := NewClientWithClientset(cs, nil, Config{})
stats, err := client.GetCacheStats(context.Background())
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if len(stats) != 3 {
t.Fatalf("expected 3 entries, got %d", len(stats))
}
for _, s := range stats {
if s.Status != "NotFound" {
t.Fatalf("expected NotFound for %s, got %s", s.Name, s.Status)
}
}
}