Skip to content

Commit d8b369f

Browse files
committed
Add unit and validation tests for alias IP ranges
- Add unit tests for InstanceNetworkInterfaceAliasIPRangesSpec function - Add CRD validation tests using envtest to verify regex patterns - Tests cover valid formats (CIDR, IP only, netmask only) and invalid cases
1 parent 2cce5c8 commit d8b369f

File tree

2 files changed

+375
-0
lines changed

2 files changed

+375
-0
lines changed
Lines changed: 243 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,243 @@
1+
/*
2+
Copyright 2024 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package v1beta1
18+
19+
import (
20+
"context"
21+
"fmt"
22+
"path/filepath"
23+
"testing"
24+
25+
. "github.com/onsi/gomega"
26+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
27+
"k8s.io/client-go/kubernetes/scheme"
28+
"sigs.k8s.io/controller-runtime/pkg/client"
29+
"sigs.k8s.io/controller-runtime/pkg/envtest"
30+
)
31+
32+
func TestGCPMachine_AliasIPRanges_Validation(t *testing.T) {
33+
g := NewWithT(t)
34+
ctx := context.Background()
35+
36+
// Setup the test environment with CRDs
37+
testEnv := &envtest.Environment{
38+
CRDDirectoryPaths: []string{
39+
filepath.Join("..", "..", "config", "crd", "bases"),
40+
},
41+
ErrorIfCRDPathMissing: true,
42+
}
43+
44+
cfg, err := testEnv.Start()
45+
g.Expect(err).NotTo(HaveOccurred())
46+
g.Expect(cfg).NotTo(BeNil())
47+
48+
defer func() {
49+
err := testEnv.Stop()
50+
g.Expect(err).NotTo(HaveOccurred())
51+
}()
52+
53+
err = AddToScheme(scheme.Scheme)
54+
g.Expect(err).NotTo(HaveOccurred())
55+
56+
k8sClient, err := client.New(cfg, client.Options{Scheme: scheme.Scheme})
57+
g.Expect(err).NotTo(HaveOccurred())
58+
g.Expect(k8sClient).NotTo(BeNil())
59+
60+
namespace := "default"
61+
62+
tests := []struct {
63+
name string
64+
aliasIPRanges []AliasIPRange
65+
wantErr bool
66+
errorContains string
67+
}{
68+
// Valid cases - these should be accepted
69+
{
70+
name: "valid CIDR notation",
71+
aliasIPRanges: []AliasIPRange{
72+
{
73+
IPCidrRange: "127.0.0.1/24",
74+
SubnetworkRangeName: "subnet-name",
75+
},
76+
},
77+
wantErr: false,
78+
},
79+
{
80+
name: "valid IP address only",
81+
aliasIPRanges: []AliasIPRange{
82+
{
83+
IPCidrRange: "127.0.0.1",
84+
SubnetworkRangeName: "subnet-name",
85+
},
86+
},
87+
wantErr: false,
88+
},
89+
{
90+
name: "valid netmask only",
91+
aliasIPRanges: []AliasIPRange{
92+
{
93+
IPCidrRange: "/24",
94+
SubnetworkRangeName: "subnet-name",
95+
},
96+
},
97+
wantErr: false,
98+
},
99+
{
100+
name: "valid without subnetwork range name",
101+
aliasIPRanges: []AliasIPRange{
102+
{
103+
IPCidrRange: "/24",
104+
},
105+
},
106+
wantErr: false,
107+
},
108+
{
109+
name: "valid multiple ranges",
110+
aliasIPRanges: []AliasIPRange{
111+
{
112+
IPCidrRange: "10.0.0.0/24",
113+
SubnetworkRangeName: "pods",
114+
},
115+
{
116+
IPCidrRange: "10.1.0.0/24",
117+
SubnetworkRangeName: "services",
118+
},
119+
},
120+
wantErr: false,
121+
},
122+
{
123+
name: "valid empty alias IP ranges",
124+
aliasIPRanges: []AliasIPRange{},
125+
wantErr: false,
126+
},
127+
{
128+
name: "valid nil alias IP ranges",
129+
aliasIPRanges: nil,
130+
wantErr: false,
131+
},
132+
// Invalid cases - these should be rejected by CRD validation
133+
{
134+
name: "invalid netmask too large",
135+
aliasIPRanges: []AliasIPRange{
136+
{
137+
IPCidrRange: "/33",
138+
SubnetworkRangeName: "subnet-name",
139+
},
140+
},
141+
wantErr: true,
142+
errorContains: "should match",
143+
},
144+
{
145+
name: "invalid empty ipCidrRange",
146+
aliasIPRanges: []AliasIPRange{
147+
{
148+
IPCidrRange: "",
149+
SubnetworkRangeName: "subnet-name",
150+
},
151+
},
152+
wantErr: true,
153+
errorContains: "should match",
154+
},
155+
{
156+
name: "invalid IP address out of range",
157+
aliasIPRanges: []AliasIPRange{
158+
{
159+
IPCidrRange: "1270.0.0.1/24",
160+
SubnetworkRangeName: "subnet-name",
161+
},
162+
},
163+
wantErr: true,
164+
errorContains: "should match",
165+
},
166+
{
167+
name: "invalid IP address with letters",
168+
aliasIPRanges: []AliasIPRange{
169+
{
170+
IPCidrRange: "127.0.0.1a",
171+
SubnetworkRangeName: "subnet-name",
172+
},
173+
},
174+
wantErr: true,
175+
errorContains: "should match",
176+
},
177+
{
178+
name: "invalid CIDR with letters",
179+
aliasIPRanges: []AliasIPRange{
180+
{
181+
IPCidrRange: "127.0.0.1a/24",
182+
SubnetworkRangeName: "subnet-name",
183+
},
184+
},
185+
wantErr: true,
186+
errorContains: "should match",
187+
},
188+
{
189+
name: "invalid format with extra slash",
190+
aliasIPRanges: []AliasIPRange{
191+
{
192+
IPCidrRange: "10.0.0.0//24",
193+
SubnetworkRangeName: "subnet-name",
194+
},
195+
},
196+
wantErr: true,
197+
errorContains: "should match",
198+
},
199+
{
200+
name: "invalid format with space",
201+
aliasIPRanges: []AliasIPRange{
202+
{
203+
IPCidrRange: "10.0.0.0 /24",
204+
SubnetworkRangeName: "subnet-name",
205+
},
206+
},
207+
wantErr: true,
208+
errorContains: "should match",
209+
},
210+
}
211+
212+
for i, tt := range tests {
213+
t.Run(tt.name, func(t *testing.T) {
214+
g := NewWithT(t)
215+
216+
// Create a GCPMachine with the test aliasIPRanges
217+
machine := &GCPMachine{
218+
ObjectMeta: metav1.ObjectMeta{
219+
Name: fmt.Sprintf("test-machine-%d", i),
220+
Namespace: namespace,
221+
},
222+
Spec: GCPMachineSpec{
223+
InstanceType: "n1-standard-2",
224+
AliasIPRanges: tt.aliasIPRanges,
225+
},
226+
}
227+
228+
// Attempt to create the machine
229+
err := k8sClient.Create(ctx, machine)
230+
231+
if tt.wantErr {
232+
g.Expect(err).To(HaveOccurred())
233+
if tt.errorContains != "" {
234+
g.Expect(err.Error()).To(ContainSubstring(tt.errorContains))
235+
}
236+
} else {
237+
g.Expect(err).NotTo(HaveOccurred())
238+
// Clean up successfully created resources
239+
_ = k8sClient.Delete(ctx, machine)
240+
}
241+
})
242+
}
243+
}

cloud/scope/machine_test.go

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,3 +75,135 @@ func TestMachineLocalSSDDiskType(t *testing.T) {
7575
assert.Equal(t, "NVME", localSSDTest.Interface)
7676
assert.Equal(t, int64(375), localSSDTest.InitializeParams.DiskSizeGb)
7777
}
78+
79+
// TestInstanceNetworkInterfaceAliasIPRangesSpec tests the InstanceNetworkInterfaceAliasIPRangesSpec function
80+
func TestInstanceNetworkInterfaceAliasIPRangesSpec(t *testing.T) {
81+
// Register the GCPMachine and GCPMachineList in a schema.
82+
schema, err := infrav1.SchemeBuilder.Register(&infrav1.GCPMachine{}, &infrav1.GCPMachineList{}).Build()
83+
assert.Nil(t, err)
84+
85+
// Create a controller fake client.
86+
testClient := fake.NewClientBuilder().WithScheme(schema).Build()
87+
88+
// Test machine parameter
89+
failureDomain := "us-central1-a"
90+
testMachine := clusterv1.Machine{
91+
Spec: clusterv1.MachineSpec{
92+
FailureDomain: &failureDomain,
93+
},
94+
}
95+
96+
t.Run("should return nil for empty alias IP ranges", func(t *testing.T) {
97+
testGCPMachine := infrav1.GCPMachine{
98+
Spec: infrav1.GCPMachineSpec{
99+
AliasIPRanges: []infrav1.AliasIPRange{},
100+
},
101+
}
102+
103+
testScopeParams := MachineScopeParams{
104+
Client: testClient,
105+
Machine: &testMachine,
106+
GCPMachine: &testGCPMachine,
107+
}
108+
109+
testMachineScope, err := NewMachineScope(testScopeParams)
110+
assert.Nil(t, err)
111+
assert.NotNil(t, testMachineScope)
112+
113+
result := testMachineScope.InstanceNetworkInterfaceAliasIPRangesSpec()
114+
assert.Nil(t, result)
115+
})
116+
117+
t.Run("should convert single alias IP range", func(t *testing.T) {
118+
testGCPMachine := infrav1.GCPMachine{
119+
Spec: infrav1.GCPMachineSpec{
120+
AliasIPRanges: []infrav1.AliasIPRange{
121+
{
122+
IPCidrRange: "10.0.0.0/24",
123+
SubnetworkRangeName: "pods",
124+
},
125+
},
126+
},
127+
}
128+
129+
testScopeParams := MachineScopeParams{
130+
Client: testClient,
131+
Machine: &testMachine,
132+
GCPMachine: &testGCPMachine,
133+
}
134+
135+
testMachineScope, err := NewMachineScope(testScopeParams)
136+
assert.Nil(t, err)
137+
assert.NotNil(t, testMachineScope)
138+
139+
result := testMachineScope.InstanceNetworkInterfaceAliasIPRangesSpec()
140+
assert.NotNil(t, result)
141+
assert.Len(t, result, 1)
142+
assert.Equal(t, "10.0.0.0/24", result[0].IpCidrRange)
143+
assert.Equal(t, "pods", result[0].SubnetworkRangeName)
144+
})
145+
146+
t.Run("should convert multiple alias IP ranges", func(t *testing.T) {
147+
testGCPMachine := infrav1.GCPMachine{
148+
Spec: infrav1.GCPMachineSpec{
149+
AliasIPRanges: []infrav1.AliasIPRange{
150+
{
151+
IPCidrRange: "10.0.0.0/24",
152+
SubnetworkRangeName: "pods",
153+
},
154+
{
155+
IPCidrRange: "10.1.0.0/24",
156+
SubnetworkRangeName: "services",
157+
},
158+
},
159+
},
160+
}
161+
162+
testScopeParams := MachineScopeParams{
163+
Client: testClient,
164+
Machine: &testMachine,
165+
GCPMachine: &testGCPMachine,
166+
}
167+
168+
testMachineScope, err := NewMachineScope(testScopeParams)
169+
assert.Nil(t, err)
170+
assert.NotNil(t, testMachineScope)
171+
172+
result := testMachineScope.InstanceNetworkInterfaceAliasIPRangesSpec()
173+
assert.NotNil(t, result)
174+
assert.Len(t, result, 2)
175+
assert.Equal(t, "10.0.0.0/24", result[0].IpCidrRange)
176+
assert.Equal(t, "pods", result[0].SubnetworkRangeName)
177+
assert.Equal(t, "10.1.0.0/24", result[1].IpCidrRange)
178+
assert.Equal(t, "services", result[1].SubnetworkRangeName)
179+
})
180+
181+
t.Run("should handle alias IP range without SubnetworkRangeName", func(t *testing.T) {
182+
testGCPMachine := infrav1.GCPMachine{
183+
Spec: infrav1.GCPMachineSpec{
184+
AliasIPRanges: []infrav1.AliasIPRange{
185+
{
186+
IPCidrRange: "10.100.0.0/24",
187+
SubnetworkRangeName: "",
188+
},
189+
},
190+
},
191+
}
192+
193+
testScopeParams := MachineScopeParams{
194+
Client: testClient,
195+
Machine: &testMachine,
196+
GCPMachine: &testGCPMachine,
197+
}
198+
199+
testMachineScope, err := NewMachineScope(testScopeParams)
200+
assert.Nil(t, err)
201+
assert.NotNil(t, testMachineScope)
202+
203+
result := testMachineScope.InstanceNetworkInterfaceAliasIPRangesSpec()
204+
assert.NotNil(t, result)
205+
assert.Len(t, result, 1)
206+
assert.Equal(t, "10.100.0.0/24", result[0].IpCidrRange)
207+
assert.Equal(t, "", result[0].SubnetworkRangeName)
208+
})
209+
}

0 commit comments

Comments
 (0)