1 package ipranger
2
3 import (
4 "fmt"
5 "testing"
6
7 "google.golang.org/api/compute/v1"
8 "gotest.tools/v3/assert"
9 )
10
11 var testProjectID = "mock-edge-test-foreman"
12
13 func TestFindOrCreateSubnet(t *testing.T) {
14 r := &IPRanger{subnetSvc: &mockComputeSubnetsSvc{}}
15
16 for i := 0; i < 512; i++ {
17 subnet, err := r.FindOrCreateSubnet(testProjectID, "region0")
18 assert.NilError(t, err)
19 assert.Assert(t, subnet != Subnet{})
20 assert.Assert(t, subnet.aliasRangeQuota >= rangePerRequest, "got subnet with insufficient range %s", subnet.Name)
21
22
23 r.subnetSvc.(*mockComputeSubnetsSvc).createAliasRangesForGKEinSubnet(subnet)
24 }
25
26
27 assert.NilError(t, r.InitState(testProjectID), "failed to re-initialize state after updating mock service")
28 assert.Assert(t, len(r.stores[testProjectID].subnets["region0"]) == 35)
29
30
31
32
33
34
35 }
36
37 func TestInitState(t *testing.T) {
38 r := &IPRanger{subnetSvc: &mockComputeSubnetsSvc{}}
39
40 assert.NilError(t, r.InitState(testProjectID), "failed to initialize state")
41
42
43 assert.Assert(t, len(r.stores[testProjectID].subnets) == 1)
44
45 assert.Assert(t, len(r.stores[testProjectID].subnets["region0"]) == 3)
46 }
47
48 func TestFindAvailableSubnet(t *testing.T) {
49 r := &IPRanger{subnetSvc: &mockComputeSubnetsSvc{}}
50 assert.NilError(t, r.InitState(testProjectID), "failed to initialize state")
51
52
53 ok, subnet := r.FindAvailableSubnet(testProjectID, "region0")
54 assert.Assert(t, ok, "expected to find subnet with available range space, but didnt")
55 assert.Assert(t, subnet != Subnet{})
56
57
58
59 r.stores[testProjectID].subnets = map[string]map[string]Subnet{
60 "region0": {
61 "subnet0": {
62 aliasRangeQuota: 1,
63 },
64 "subnet1": {
65 aliasRangeQuota: 0,
66 },
67 },
68 }
69 ok, subnet = r.FindAvailableSubnet(testProjectID, "region0")
70 assert.Assert(t, !ok, "expected to not find subnet with available range space, but did")
71 assert.Assert(t, subnet == Subnet{}, "expected subnet to be empty")
72
73
74 r.stores[testProjectID].subnets = map[string]map[string]Subnet{
75 "region0": {
76 "subnet0": {
77 aliasRangeQuota: 1,
78 },
79 },
80 "region1": {
81 "subnet0": {
82 Name: "subnet0",
83 aliasRangeQuota: 2,
84 },
85 },
86 }
87 ok, subnet = r.FindAvailableSubnet(testProjectID, "region0")
88 assert.Assert(t, !ok, "expected to not find subnet with available range space, but did")
89 assert.Assert(t, subnet == Subnet{}, "expected subnet to be empty")
90 ok, subnet = r.FindAvailableSubnet(testProjectID, "region1")
91 assert.Assert(t, ok, "expected to find subnet with available range space, but didnt")
92 assert.Assert(t, subnet != Subnet{})
93
94
95 r.stores[testProjectID].subnets = map[string]map[string]Subnet{}
96 ok, subnet = r.FindAvailableSubnet(testProjectID, "region0")
97 assert.Assert(t, !ok, "expected to not find subnet with available range space, but did")
98 assert.Assert(t, subnet == Subnet{}, "expected subnet to be empty")
99 }
100
101 func TestNextSubnetName(t *testing.T) {
102 r := &IPRanger{subnetSvc: &mockComputeSubnetsSvc{}}
103 assert.NilError(t, r.InitState(testProjectID), "failed to initialize state")
104
105 next := r.nextSubnetName(testProjectID)
106 assert.Assert(t, "subnet2" == next, "incorrect next subnet name, should be incrementally increasing")
107 }
108
109 func TestBuildRangeStore(t *testing.T) {
110 r := &IPRanger{subnetSvc: &mockComputeSubnetsSvc{}}
111
112 snlist, err := r.subnetSvc.List(testProjectID)
113 assert.NilError(t, err)
114 store, err := buildRangeStore(snlist)
115 assert.NilError(t, err)
116
117
118 assert.Assert(t, len(store.ipset.Ranges()) == 1, "incorrect amount of ip ranges in built set")
119 c := 0
120 for {
121 _, newSet, ok := store.ipset.RemoveFreePrefix(Netmask)
122 if !ok {
123 break
124 }
125 store.ipset = newSet
126 c++
127 }
128 assert.Assert(t, 4086 == c, "incorrect amount of allocatable /%d ranges", Netmask)
129 }
130
131
132 type mockComputeSubnetsSvc struct {
133 fakeState computeSubnetAggregatedList
134 }
135
136 func (g *mockComputeSubnetsSvc) List(project string) (computeSubnetAggregatedList, error) {
137 if g.fakeState == nil {
138 g.fakeState = computeSubnetAggregatedList{
139 "regions/region0": compute.SubnetworksScopedList{
140 Subnetworks: []*compute.Subnetwork{
141 {
142 Name: "subnet0",
143 Region: toRegionURI(project, "region0"),
144 IpCidrRange: "10.0.0.0/20",
145 SecondaryIpRanges: []*compute.SubnetworkSecondaryRange{
146 {
147 RangeName: "alias-range0",
148 IpCidrRange: "10.0.32.0/20",
149 },
150 {
151 RangeName: "alias-range1",
152 IpCidrRange: "10.0.48.0/20",
153 },
154 },
155 },
156 {
157 Name: "subnet1",
158 Region: toRegionURI(project, "region0"),
159 IpCidrRange: "10.0.16.0/20",
160 },
161 {
162 Name: "default",
163 Region: toRegionURI(project, "region0"),
164 IpCidrRange: "10.0.64.0/20",
165 },
166 },
167 },
168 }
169 }
170 return g.fakeState, nil
171 }
172
173 func (g *mockComputeSubnetsSvc) Create(project, ipRange, region, name string) (*compute.Subnetwork, error) {
174 toCreate := &compute.Subnetwork{
175 Name: name,
176 Region: toRegionURI(project, region),
177 IpCidrRange: ipRange,
178 SecondaryIpRanges: []*compute.SubnetworkSecondaryRange{},
179 }
180 rkey := fmt.Sprintf("regions/%s", region)
181 sns := g.fakeState[rkey].Subnetworks
182 g.fakeState[rkey] = compute.SubnetworksScopedList{
183 Subnetworks: append(sns, toCreate),
184 }
185 return toCreate, nil
186 }
187
188 func (g *mockComputeSubnetsSvc) createAliasRangesForGKEinSubnet(subnet Subnet) {
189 rkey := fmt.Sprintf("regions/%s", subnet.region)
190 for _, s := range g.fakeState[rkey].Subnetworks {
191 if s.Name == subnet.Name {
192 s.SecondaryIpRanges = append(s.SecondaryIpRanges, &compute.SubnetworkSecondaryRange{
193 RangeName: "fake-gkeABC-pods-range",
194 IpCidrRange: "10.0.0.0/21",
195 })
196 s.SecondaryIpRanges = append(s.SecondaryIpRanges, &compute.SubnetworkSecondaryRange{
197 RangeName: "fake-gkeABC-services-range",
198 IpCidrRange: "10.0.8.0/21",
199 })
200 }
201 }
202 }
203
View as plain text