From 20dafe678bd8ffa475102035e24ec79b9564791c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9B=BE=E6=98=AF=E7=84=B6?= Date: Fri, 10 Oct 2025 02:22:03 +0000 Subject: [PATCH] test: Add failing tests for IP allocator CIDR filtering and overflow protection --- .../service/ipallocator/ipallocator_test.go | 216 ++++++++++++++++++ 1 file changed, 216 insertions(+) diff --git a/pkg/registry/core/service/ipallocator/ipallocator_test.go b/pkg/registry/core/service/ipallocator/ipallocator_test.go index 9a3d5bfd7bf..4f030bcd737 100644 --- a/pkg/registry/core/service/ipallocator/ipallocator_test.go +++ b/pkg/registry/core/service/ipallocator/ipallocator_test.go @@ -26,6 +26,7 @@ import ( "time" networkingv1 "k8s.io/api/networking/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/sets" "k8s.io/client-go/informers" @@ -1012,3 +1013,218 @@ func BenchmarkIPAllocatorAllocateNextIPv6Size65535(b *testing.B) { r.AllocateNext() } } + +// TestUsedWithCIDRFiltering tests that Used() method only counts IPs within the allocator's CIDR +func TestUsedWithCIDRFiltering(t *testing.T) { + // Create an allocator for 192.168.1.0/24 + _, cidr, err := netutils.ParseCIDRSloppy("192.168.1.0/24") + if err != nil { + t.Fatal(err) + } + + // Create test components + client := fake.NewClientset() + informerFactory := informers.NewSharedInformerFactory(client, 0*time.Second) + ipInformer := informerFactory.Networking().V1().IPAddresses() + ipStore := ipInformer.Informer().GetIndexer() + + r, err := NewIPAllocator(cidr, client.NetworkingV1(), ipInformer) + if err != nil { + t.Fatal(err) + } + r.ipAddressSynced = func() bool { return true } + defer r.Destroy() + + // Add valid IPs (within CIDR) with correct labels + validIPAddr1 := &networkingv1.IPAddress{ + ObjectMeta: metav1.ObjectMeta{ + Name: "192.168.1.10", + Labels: map[string]string{ + networkingv1.LabelIPAddressFamily: string(r.IPFamily()), + networkingv1.LabelManagedBy: ControllerName, + }, + }, + } + validIPAddr2 := &networkingv1.IPAddress{ + ObjectMeta: metav1.ObjectMeta{ + Name: "192.168.1.20", + Labels: map[string]string{ + networkingv1.LabelIPAddressFamily: string(r.IPFamily()), + networkingv1.LabelManagedBy: ControllerName, + }, + }, + } + if err := ipStore.Add(validIPAddr1); err != nil { + t.Fatal(err) + } + if err := ipStore.Add(validIPAddr2); err != nil { + t.Fatal(err) + } + + // Add invalid IPs (outside CIDR) with correct labels - these should not be counted + invalidIP1 := &networkingv1.IPAddress{ + ObjectMeta: metav1.ObjectMeta{ + Name: "192.168.2.10", // different subnet + Labels: map[string]string{ + networkingv1.LabelIPAddressFamily: string(r.IPFamily()), + networkingv1.LabelManagedBy: ControllerName, + }, + }, + } + invalidIP2 := &networkingv1.IPAddress{ + ObjectMeta: metav1.ObjectMeta{ + Name: "10.0.0.1", // completely different network + Labels: map[string]string{ + networkingv1.LabelIPAddressFamily: string(r.IPFamily()), + networkingv1.LabelManagedBy: ControllerName, + }, + }, + } + if err := ipStore.Add(invalidIP1); err != nil { + t.Fatal(err) + } + if err := ipStore.Add(invalidIP2); err != nil { + t.Fatal(err) + } + + // Used() should only count valid IPs (2), not all IPs (4) + used := r.Used() + if used != 2 { + t.Errorf("Expected Used() to return 2 (only IPs in CIDR), got %d", used) + } +} + +// TestFreeWithOverflowProtection tests the overflow protection in Free() method +func TestFreeWithOverflowProtection(t *testing.T) { + testCases := []struct { + name string + cidr string + simulateSize uint64 + simulateUsed int + expectedFree int + }{ + { + name: "normal case", + cidr: "192.168.1.0/30", // size = 2 (4 total - 2 reserved) + simulateSize: 2, + simulateUsed: 1, + expectedFree: 1, + }, + { + name: "size exceeds MaxInt", + cidr: "192.168.1.0/24", + simulateSize: uint64(math.MaxInt) + 1, + simulateUsed: 100, + expectedFree: math.MaxInt - 100, + }, + { + name: "used exceeds size (data inconsistency)", + cidr: "192.168.1.0/30", + simulateSize: 2, + simulateUsed: 5, // More than size + expectedFree: 0, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + _, cidr, err := netutils.ParseCIDRSloppy(tc.cidr) + if err != nil { + t.Fatal(err) + } + + // Create test components + client := fake.NewClientset() + informerFactory := informers.NewSharedInformerFactory(client, 0*time.Second) + ipInformer := informerFactory.Networking().V1().IPAddresses() + ipStore := ipInformer.Informer().GetIndexer() + + r, err := NewIPAllocator(cidr, client.NetworkingV1(), ipInformer) + if err != nil { + t.Fatal(err) + } + r.ipAddressSynced = func() bool { return true } + defer r.Destroy() + + // Override the size for testing overflow scenarios + r.size = tc.simulateSize + + // Mock the Used() method by adding IP addresses to simulate usage + for i := 0; i < tc.simulateUsed; i++ { + // Add valid IPs within the CIDR with correct labels + ip := &networkingv1.IPAddress{ + ObjectMeta: metav1.ObjectMeta{ + Name: fmt.Sprintf("192.168.1.%d", i+1), + Labels: map[string]string{ + networkingv1.LabelIPAddressFamily: string(r.IPFamily()), + networkingv1.LabelManagedBy: ControllerName, + }, + }, + } + if err := ipStore.Add(ip); err != nil { + t.Fatal(err) + } + } + + free := r.Free() + if free != tc.expectedFree { + t.Errorf("Expected Free() to return %d, got %d", tc.expectedFree, free) + } + }) + } +} + +// TestUsedWithInvalidIPs tests that Used() handles invalid IP addresses gracefully +func TestUsedWithInvalidIPs(t *testing.T) { + _, cidr, err := netutils.ParseCIDRSloppy("192.168.1.0/24") + if err != nil { + t.Fatal(err) + } + + // Create test components + client := fake.NewClientset() + informerFactory := informers.NewSharedInformerFactory(client, 0*time.Second) + ipInformer := informerFactory.Networking().V1().IPAddresses() + ipStore := ipInformer.Informer().GetIndexer() + + r, err := NewIPAllocator(cidr, client.NetworkingV1(), ipInformer) + if err != nil { + t.Fatal(err) + } + r.ipAddressSynced = func() bool { return true } + defer r.Destroy() + + // Add valid IP with correct labels + validIP := &networkingv1.IPAddress{ + ObjectMeta: metav1.ObjectMeta{ + Name: "192.168.1.10", + Labels: map[string]string{ + networkingv1.LabelIPAddressFamily: string(r.IPFamily()), + networkingv1.LabelManagedBy: ControllerName, + }, + }, + } + if err := ipStore.Add(validIP); err != nil { + t.Fatal(err) + } + + // Add invalid IP address (malformed) with correct labels + invalidIP := &networkingv1.IPAddress{ + ObjectMeta: metav1.ObjectMeta{ + Name: "invalid-ip-address", + Labels: map[string]string{ + networkingv1.LabelIPAddressFamily: string(r.IPFamily()), + networkingv1.LabelManagedBy: ControllerName, + }, + }, + } + if err := ipStore.Add(invalidIP); err != nil { + t.Fatal(err) + } + + // Used() should only count the valid IP + used := r.Used() + if used != 1 { + t.Errorf("Expected Used() to return 1 (only valid IPs), got %d", used) + } +}