sigs.k8s.io/cluster-api-provider-azure@v1.14.3/azure/services/inboundnatrules/spec_test.go (about)

     1  /*
     2  Copyright 2021 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 inboundnatrules
    18  
    19  import (
    20  	"context"
    21  	"reflect"
    22  	"testing"
    23  
    24  	"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v4"
    25  	"github.com/google/go-cmp/cmp"
    26  	. "github.com/onsi/gomega"
    27  	"k8s.io/utils/ptr"
    28  )
    29  
    30  func TestParameters(t *testing.T) {
    31  	testcases := []struct {
    32  		name     string
    33  		spec     InboundNatSpec
    34  		existing interface{}
    35  		expected interface{}
    36  		errorMsg string
    37  	}{
    38  		{
    39  			name:     "no existing InboundNatRule",
    40  			spec:     fakeInboundNatSpec(true),
    41  			existing: nil,
    42  			expected: fakeNatRule(),
    43  		},
    44  		{
    45  			name:     "no existing InboundNatRule and FrontendIPConfigurationID not set",
    46  			spec:     fakeInboundNatSpec(false),
    47  			existing: nil,
    48  			errorMsg: "FrontendIPConfigurationID is not set",
    49  		},
    50  		{
    51  			name:     "existing is not an InboundNatRule",
    52  			spec:     fakeInboundNatSpec(true),
    53  			existing: "wrong type",
    54  			errorMsg: "string is not an armnetwork.InboundNatRule",
    55  		},
    56  		{
    57  			name:     "existing InboundNatRule",
    58  			spec:     fakeInboundNatSpec(false),
    59  			existing: fakeNatRule(),
    60  			expected: nil,
    61  		},
    62  	}
    63  	for _, tc := range testcases {
    64  		tc := tc
    65  		t.Run(tc.name, func(t *testing.T) {
    66  			g := NewWithT(t)
    67  			t.Parallel()
    68  
    69  			result, err := tc.spec.Parameters(context.Background(), tc.existing)
    70  			if tc.errorMsg != "" {
    71  				g.Expect(err).To(HaveOccurred())
    72  				g.Expect(err.Error()).To(ContainSubstring(tc.errorMsg))
    73  			} else {
    74  				g.Expect(err).NotTo(HaveOccurred())
    75  			}
    76  			if !reflect.DeepEqual(result, tc.expected) {
    77  				t.Errorf("Got difference between expected result and computed result:\n%s", cmp.Diff(tc.expected, result))
    78  			}
    79  		})
    80  	}
    81  }
    82  
    83  func fakeInboundNatSpec(frontendIPConfigID bool) InboundNatSpec {
    84  	spec := InboundNatSpec{
    85  		Name:             "my-machine-1",
    86  		LoadBalancerName: "my-lb-1",
    87  		ResourceGroup:    fakeGroupName,
    88  	}
    89  	if frontendIPConfigID {
    90  		spec.FrontendIPConfigurationID = ptr.To("frontend-ip-config-id-1")
    91  	}
    92  	return spec
    93  }
    94  
    95  // fakeNatRule returns a fake InboundNatRule, associated with `fakeInboundNatSpec()`.
    96  func fakeNatRule() armnetwork.InboundNatRule {
    97  	return armnetwork.InboundNatRule{
    98  		Name: ptr.To("my-machine-1"),
    99  		Properties: &armnetwork.InboundNatRulePropertiesFormat{
   100  			BackendPort:      ptr.To[int32](22),
   101  			EnableFloatingIP: ptr.To(false),
   102  			FrontendIPConfiguration: &armnetwork.SubResource{
   103  				ID: ptr.To("frontend-ip-config-id-1"),
   104  			},
   105  			IdleTimeoutInMinutes: ptr.To[int32](4),
   106  			Protocol:             ptr.To(armnetwork.TransportProtocolTCP),
   107  		},
   108  	}
   109  }
   110  
   111  func TestGetAvailablePort(t *testing.T) {
   112  	testcases := []struct {
   113  		name               string
   114  		portsInput         map[int32]struct{}
   115  		expectedError      string
   116  		expectedPortResult int32
   117  	}{
   118  		{
   119  			name:               "Empty ports",
   120  			portsInput:         map[int32]struct{}{},
   121  			expectedError:      "",
   122  			expectedPortResult: 22,
   123  		},
   124  		{
   125  			name: "22 taken",
   126  			portsInput: map[int32]struct{}{
   127  				22: {},
   128  			},
   129  			expectedError:      "",
   130  			expectedPortResult: 2201,
   131  		},
   132  		{
   133  			name: "Existing ports",
   134  			portsInput: map[int32]struct{}{
   135  				22:   {},
   136  				2201: {},
   137  				2202: {},
   138  				2204: {},
   139  			},
   140  			expectedError:      "",
   141  			expectedPortResult: 2203,
   142  		},
   143  		{
   144  			name:               "No ports available",
   145  			portsInput:         getFullPortsMap(),
   146  			expectedError:      "No available SSH Frontend ports",
   147  			expectedPortResult: 0,
   148  		},
   149  	}
   150  	for _, tc := range testcases {
   151  		tc := tc
   152  		t.Run(tc.name, func(t *testing.T) {
   153  			g := NewWithT(t)
   154  			t.Parallel()
   155  
   156  			res, err := getAvailableSSHFrontendPort(tc.portsInput)
   157  			if tc.expectedError != "" {
   158  				g.Expect(err).To(HaveOccurred())
   159  				g.Expect(err).To(MatchError(tc.expectedError))
   160  			} else {
   161  				g.Expect(err).NotTo(HaveOccurred())
   162  				g.Expect(res).To(Equal(tc.expectedPortResult))
   163  			}
   164  		})
   165  	}
   166  }
   167  
   168  func getFullPortsMap() map[int32]struct{} {
   169  	res := map[int32]struct{}{
   170  		22: {},
   171  	}
   172  	for i := 2201; i < 2220; i++ {
   173  		res[int32(i)] = struct{}{}
   174  	}
   175  	return res
   176  }