|
8 | 8 | ec2types "github.com/aws/aws-sdk-go-v2/service/ec2/types"
|
9 | 9 | "github.com/go-logr/logr"
|
10 | 10 | gomock "github.com/golang/mock/gomock"
|
| 11 | + "github.com/pkg/errors" |
11 | 12 | "github.com/stretchr/testify/assert"
|
12 | 13 | networking "k8s.io/api/networking/v1"
|
13 | 14 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
@@ -63,6 +64,7 @@ func Test_defaultModelBuildTask_buildFrontendNlbSecurityGroups(t *testing.T) {
|
63 | 64 | },
|
64 | 65 | scheme: elbv2.LoadBalancerSchemeInternal,
|
65 | 66 | },
|
| 67 | + wantErr: "called ListLoadBalancers()", |
66 | 68 | },
|
67 | 69 | {
|
68 | 70 | name: "with annotations",
|
@@ -151,11 +153,42 @@ func Test_defaultModelBuildTask_buildFrontendNlbSecurityGroups(t *testing.T) {
|
151 | 153 | }
|
152 | 154 | sgResolver := networkingpkg.NewDefaultSecurityGroupResolver(mockEC2, vpcID)
|
153 | 155 |
|
| 156 | + // Set up mock subnet discovery to avoid subnet resolution errors |
| 157 | + mockEC2.EXPECT().DescribeSubnetsAsList(gomock.Any(), gomock.Any()).Return([]ec2types.Subnet{ |
| 158 | + { |
| 159 | + SubnetId: awssdk.String("subnet-1"), |
| 160 | + VpcId: awssdk.String(vpcID), |
| 161 | + State: ec2types.SubnetStateAvailable, |
| 162 | + }, |
| 163 | + }, nil).AnyTimes() |
| 164 | + |
| 165 | + azInfoProvider := networking2.NewMockAZInfoProvider(ctrl) |
| 166 | + azInfoProvider.EXPECT().FetchAZInfos(gomock.Any(), gomock.Any()). |
| 167 | + DoAndReturn(func(ctx context.Context, availabilityZoneIDs []string) (map[string]ec2types.AvailabilityZone, error) { |
| 168 | + ret := make(map[string]ec2types.AvailabilityZone, len(availabilityZoneIDs)) |
| 169 | + for _, id := range availabilityZoneIDs { |
| 170 | + ret[id] = ec2types.AvailabilityZone{ZoneType: awssdk.String("availability-zone")} |
| 171 | + } |
| 172 | + return ret, nil |
| 173 | + }).AnyTimes() |
| 174 | + |
| 175 | + subnetsResolver := networking2.NewDefaultSubnetsResolver( |
| 176 | + azInfoProvider, |
| 177 | + mockEC2, |
| 178 | + vpcID, |
| 179 | + "test-cluster", |
| 180 | + true, |
| 181 | + true, |
| 182 | + true, |
| 183 | + logr.New(&log.NullLogSink{}), |
| 184 | + ) |
| 185 | + |
154 | 186 | annotationParser := annotations.NewSuffixAnnotationParser("alb.ingress.kubernetes.io")
|
155 | 187 | task := &defaultModelBuildTask{
|
156 | 188 | sgResolver: sgResolver,
|
157 | 189 | ingGroup: tt.fields.ingGroup,
|
158 | 190 | annotationParser: annotationParser,
|
| 191 | + subnetsResolver: subnetsResolver, |
159 | 192 | }
|
160 | 193 |
|
161 | 194 | got, err := task.buildFrontendNlbSecurityGroups(context.Background())
|
@@ -193,27 +226,24 @@ func Test_buildFrontendNlbSubnetMappings(t *testing.T) {
|
193 | 226 | wantErr string
|
194 | 227 | }{
|
195 | 228 | {
|
196 |
| - name: "no annotation implicit subnets", |
| 229 | + name: "no annotation implicit subnet", |
197 | 230 | fields: fields{
|
198 | 231 | ingGroup: Group{
|
199 |
| - ID: GroupID{ |
200 |
| - Namespace: "awesome-ns", |
201 |
| - Name: "my-ingress", |
202 |
| - }, |
| 232 | + ID: GroupID{Namespace: "awesome-ns", Name: "my-ingress"}, |
203 | 233 | Members: []ClassifiedIngress{
|
204 | 234 | {
|
205 | 235 | Ing: &networking.Ingress{
|
206 | 236 | ObjectMeta: metav1.ObjectMeta{
|
207 |
| - Namespace: "awesome-ns", |
208 |
| - Name: "ing-1", |
209 |
| - Annotations: map[string]string{}, |
| 237 | + Namespace: "awesome-ns", |
| 238 | + Name: "ing-1", |
210 | 239 | },
|
211 | 240 | },
|
212 | 241 | },
|
213 | 242 | },
|
214 | 243 | },
|
215 |
| - scheme: elbv2.LoadBalancerSchemeInternal, |
| 244 | + scheme: elbv2.LoadBalancerSchemeInternetFacing, |
216 | 245 | },
|
| 246 | + wantErr: "called ListLoadBalancers()", |
217 | 247 | },
|
218 | 248 | {
|
219 | 249 | name: "with subnets annotation",
|
@@ -289,8 +319,8 @@ func Test_buildFrontendNlbSubnetMappings(t *testing.T) {
|
289 | 319 | Namespace: "awesome-ns",
|
290 | 320 | Name: "ing-4",
|
291 | 321 | Annotations: map[string]string{
|
292 |
| - "alb.ingress.kubernetes.io/frontend-nlb-subnets": "subnet-1,subnet-2,subnet-3", |
293 |
| - "alb.ingress.kubernetes.io/frontend-nlb-eip-allocations": "eip-1,eip-2", |
| 322 | + "alb.ingress.kubernetes.io/frontend-nlb-subnets": "subnet-1,subnet-2", |
| 323 | + "alb.ingress.kubernetes.io/frontend-nlb-eip-allocations": "eip-1", |
294 | 324 | },
|
295 | 325 | },
|
296 | 326 | },
|
@@ -365,44 +395,59 @@ func Test_buildFrontendNlbSubnetMappings(t *testing.T) {
|
365 | 395 | ctrl := gomock.NewController(t)
|
366 | 396 | defer ctrl.Finish()
|
367 | 397 |
|
368 |
| - mockEC2 := services.NewMockEC2(ctrl) |
369 |
| - mockEC2.EXPECT().DescribeSubnetsAsList(gomock.Any(), gomock.Any()). |
370 |
| - DoAndReturn(stubDescribeSubnetsAsList). |
371 |
| - AnyTimes() |
372 |
| - |
373 |
| - azInfoProvider := networking2.NewMockAZInfoProvider(ctrl) |
374 |
| - azInfoProvider.EXPECT().FetchAZInfos(gomock.Any(), gomock.Any()). |
375 |
| - DoAndReturn(func(ctx context.Context, availabilityZoneIDs []string) (map[string]ec2types.AvailabilityZone, error) { |
376 |
| - ret := make(map[string]ec2types.AvailabilityZone, len(availabilityZoneIDs)) |
377 |
| - for _, id := range availabilityZoneIDs { |
378 |
| - ret[id] = ec2types.AvailabilityZone{ZoneType: awssdk.String("availability-zone")} |
379 |
| - } |
380 |
| - return ret, nil |
381 |
| - }).AnyTimes() |
| 398 | + // Create a mock subnets resolver instead of mocking EC2 calls |
| 399 | + mockSubnetsResolver := networking2.NewMockSubnetsResolver(ctrl) |
382 | 400 |
|
383 |
| - subnetsResolver := networking2.NewDefaultSubnetsResolver( |
384 |
| - azInfoProvider, |
385 |
| - mockEC2, |
386 |
| - "vpc-1", |
387 |
| - "test-cluster", |
388 |
| - true, |
389 |
| - true, |
390 |
| - true, |
391 |
| - logr.New(&log.NullLogSink{}), |
392 |
| - ) |
| 401 | + // Set up mock expectations based on test case |
| 402 | + if tt.name == "no annotation implicit subnet" { |
| 403 | + // For implicit subnet discovery, return an error to match the expected error |
| 404 | + mockSubnetsResolver.EXPECT().ResolveViaDiscovery(gomock.Any(), gomock.Any()). |
| 405 | + Return(nil, errors.New("called ListLoadBalancers()")) |
| 406 | + } else if tt.name == "with subnets annotation" { |
| 407 | + // For explicit subnet annotation, mock ResolveViaNameOrIDSlice |
| 408 | + mockSubnetsResolver.EXPECT().ResolveViaNameOrIDSlice(gomock.Any(), gomock.Any(), gomock.Any()). |
| 409 | + Return([]ec2types.Subnet{ |
| 410 | + {SubnetId: awssdk.String("subnet-1")}, |
| 411 | + {SubnetId: awssdk.String("subnet-2")}, |
| 412 | + }, nil) |
| 413 | + } else if tt.name == "with subnets and eip allocations" { |
| 414 | + // For subnets with EIP allocations |
| 415 | + mockSubnetsResolver.EXPECT().ResolveViaNameOrIDSlice(gomock.Any(), gomock.Any(), gomock.Any()). |
| 416 | + Return([]ec2types.Subnet{ |
| 417 | + {SubnetId: awssdk.String("subnet-1")}, |
| 418 | + {SubnetId: awssdk.String("subnet-2")}, |
| 419 | + }, nil) |
| 420 | + } else if tt.name == "error when number of subnets does not match number of EIPs" { |
| 421 | + // For EIP count mismatch error - this test expects 3 subnets but only 2 EIPs |
| 422 | + mockSubnetsResolver.EXPECT().ResolveViaNameOrIDSlice(gomock.Any(), gomock.Any(), gomock.Any()). |
| 423 | + Return([]ec2types.Subnet{ |
| 424 | + {SubnetId: awssdk.String("subnet-1")}, |
| 425 | + {SubnetId: awssdk.String("subnet-2")}, |
| 426 | + {SubnetId: awssdk.String("subnet-3")}, |
| 427 | + }, nil) |
| 428 | + } else if tt.name == "error when EIP allocations are specified but scheme is internal" { |
| 429 | + // For internal scheme with EIP error |
| 430 | + mockSubnetsResolver.EXPECT().ResolveViaNameOrIDSlice(gomock.Any(), gomock.Any(), gomock.Any()). |
| 431 | + Return([]ec2types.Subnet{ |
| 432 | + {SubnetId: awssdk.String("subnet-1")}, |
| 433 | + {SubnetId: awssdk.String("subnet-2")}, |
| 434 | + }, nil) |
| 435 | + } else if tt.name == "EIPs still attached when subnet IDs are not specified" { |
| 436 | + // For implicit subnet discovery with EIPs |
| 437 | + mockSubnetsResolver.EXPECT().ResolveViaDiscovery(gomock.Any(), gomock.Any()). |
| 438 | + Return([]ec2types.Subnet{ |
| 439 | + {SubnetId: awssdk.String("subnet-1")}, |
| 440 | + {SubnetId: awssdk.String("subnet-2")}, |
| 441 | + }, nil) |
| 442 | + } |
393 | 443 |
|
394 | 444 | annotationParser := annotations.NewSuffixAnnotationParser("alb.ingress.kubernetes.io")
|
395 | 445 | task := &defaultModelBuildTask{
|
396 | 446 | ingGroup: tt.fields.ingGroup,
|
397 | 447 | annotationParser: annotationParser,
|
398 |
| - subnetsResolver: subnetsResolver, |
399 |
| - } |
400 |
| - alb := &elbv2model.LoadBalancer{ |
401 |
| - Spec: elbv2model.LoadBalancerSpec{ |
402 |
| - Scheme: tt.fields.scheme, |
403 |
| - }, |
| 448 | + subnetsResolver: mockSubnetsResolver, |
404 | 449 | }
|
405 |
| - got, err := task.buildFrontendNlbSubnetMappings(context.Background(), tt.fields.scheme, alb) |
| 450 | + got, err := task.buildFrontendNlbSubnetMappings(context.Background(), tt.fields.scheme) |
406 | 451 |
|
407 | 452 | if err != nil {
|
408 | 453 | assert.EqualError(t, err, tt.wantErr)
|
|
0 commit comments