istio.io/istio@v0.0.0-20240520182934-d79c90f27776/operator/pkg/translate/strategic_port_merge_test.go (about)

     1  // Copyright Istio Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package translate
    16  
    17  import (
    18  	"testing"
    19  
    20  	"github.com/google/go-cmp/cmp"
    21  	v1 "k8s.io/api/core/v1"
    22  	"k8s.io/apimachinery/pkg/util/intstr"
    23  )
    24  
    25  var (
    26  	httpsPort = &v1.ServicePort{
    27  		Name:       "https",
    28  		Protocol:   v1.ProtocolTCP,
    29  		Port:       443,
    30  		TargetPort: intstr.IntOrString{IntVal: 8443},
    31  	}
    32  	quicPort = &v1.ServicePort{
    33  		Name:       "http3-quic",
    34  		Protocol:   v1.ProtocolUDP,
    35  		Port:       443,
    36  		TargetPort: intstr.IntOrString{IntVal: 8443},
    37  	}
    38  	httpPort = &v1.ServicePort{
    39  		Name:       "http-port",
    40  		Protocol:   v1.ProtocolTCP,
    41  		Port:       80,
    42  		TargetPort: intstr.IntOrString{IntVal: 8080},
    43  	}
    44  	httpNoProtoPort = &v1.ServicePort{
    45  		Name:       "http-port",
    46  		Port:       80,
    47  		TargetPort: intstr.IntOrString{IntVal: 8080},
    48  	}
    49  	mysqlPort = &v1.ServicePort{
    50  		Name:     "mysql-port",
    51  		Protocol: v1.ProtocolTCP,
    52  		Port:     3306,
    53  	}
    54  	istioHealthcheckPort = &v1.ServicePort{
    55  		Name:     "status-port",
    56  		Protocol: v1.ProtocolTCP,
    57  		Port:     15021,
    58  	}
    59  	istioMetricsPort = &v1.ServicePort{
    60  		Name:     "metrics-port",
    61  		Protocol: v1.ProtocolTCP,
    62  		Port:     15020,
    63  	}
    64  	httpBaseBarPort = &v1.ServicePort{
    65  		Name:     "http-bar-base",
    66  		Protocol: v1.ProtocolTCP,
    67  		Port:     9000,
    68  	}
    69  	httpOverlayBarPort = &v1.ServicePort{
    70  		Name:     "http-bar-overlay",
    71  		Protocol: v1.ProtocolTCP,
    72  		Port:     9000,
    73  	}
    74  	httpOverlayDiffProtocolBarPort = &v1.ServicePort{
    75  		Name:     "http3-bar-overlay",
    76  		Protocol: v1.ProtocolUDP,
    77  		Port:     9000,
    78  	}
    79  	httpFooPort = &v1.ServicePort{
    80  		Name:     "http-foo",
    81  		Protocol: v1.ProtocolTCP,
    82  		Port:     8080,
    83  	}
    84  	httpFooProtocolOmittedPort = &v1.ServicePort{
    85  		Name: "http-foo",
    86  		Port: 8080,
    87  	}
    88  )
    89  
    90  func TestStrategicPortMergeByPortAndProtocol(t *testing.T) {
    91  	for _, tt := range []struct {
    92  		name                string
    93  		basePorts           []*v1.ServicePort
    94  		overlayPorts        []*v1.ServicePort
    95  		expectedMergedPorts []*v1.ServicePort
    96  	}{
    97  		{
    98  			name:                "both base and overlay are nil",
    99  			basePorts:           nil,
   100  			overlayPorts:        nil,
   101  			expectedMergedPorts: nil,
   102  		},
   103  		{
   104  			name:                "overlay is nil",
   105  			basePorts:           []*v1.ServicePort{httpPort, httpsPort, quicPort},
   106  			overlayPorts:        nil,
   107  			expectedMergedPorts: []*v1.ServicePort{httpPort, httpsPort, quicPort},
   108  		},
   109  		{
   110  			name:                "base is nil",
   111  			basePorts:           nil,
   112  			overlayPorts:        []*v1.ServicePort{httpPort, httpsPort, quicPort},
   113  			expectedMergedPorts: []*v1.ServicePort{httpPort, httpsPort, quicPort},
   114  		},
   115  		{
   116  			name:                "same base and overlay",
   117  			basePorts:           []*v1.ServicePort{httpPort, httpsPort},
   118  			overlayPorts:        []*v1.ServicePort{httpsPort, httpPort},
   119  			expectedMergedPorts: []*v1.ServicePort{httpPort, httpsPort},
   120  		},
   121  		{
   122  			name:                "base and overlay for the same port, different protocol",
   123  			basePorts:           []*v1.ServicePort{httpPort, httpsPort, mysqlPort},
   124  			overlayPorts:        []*v1.ServicePort{quicPort},
   125  			expectedMergedPorts: []*v1.ServicePort{httpPort, httpsPort, mysqlPort, quicPort},
   126  		},
   127  		{
   128  			name:                "base and overlay with different ports",
   129  			basePorts:           []*v1.ServicePort{httpPort},
   130  			overlayPorts:        []*v1.ServicePort{httpsPort},
   131  			expectedMergedPorts: []*v1.ServicePort{httpPort, httpsPort},
   132  		},
   133  		{
   134  			name:                "implicit ports",
   135  			basePorts:           []*v1.ServicePort{httpPort},
   136  			overlayPorts:        []*v1.ServicePort{httpNoProtoPort},
   137  			expectedMergedPorts: []*v1.ServicePort{httpPort},
   138  		},
   139  		{
   140  			name:                "status and metrics port are present",
   141  			basePorts:           []*v1.ServicePort{istioHealthcheckPort, istioMetricsPort, httpsPort},
   142  			overlayPorts:        []*v1.ServicePort{httpsPort, httpPort},
   143  			expectedMergedPorts: []*v1.ServicePort{istioHealthcheckPort, istioMetricsPort, httpsPort, httpPort},
   144  		},
   145  		{
   146  			name:                "status port is present",
   147  			basePorts:           []*v1.ServicePort{istioHealthcheckPort, httpsPort, httpPort},
   148  			overlayPorts:        []*v1.ServicePort{httpsPort, httpPort},
   149  			expectedMergedPorts: []*v1.ServicePort{istioHealthcheckPort, httpsPort, httpPort},
   150  		},
   151  		{
   152  			name:                "metrics port is present",
   153  			basePorts:           []*v1.ServicePort{istioMetricsPort, httpsPort, httpPort},
   154  			overlayPorts:        []*v1.ServicePort{httpsPort, httpPort},
   155  			expectedMergedPorts: []*v1.ServicePort{istioMetricsPort, httpsPort, httpPort},
   156  		},
   157  		{
   158  			name:                "overlay with port name changed",
   159  			basePorts:           []*v1.ServicePort{httpBaseBarPort},
   160  			overlayPorts:        []*v1.ServicePort{httpOverlayBarPort},
   161  			expectedMergedPorts: []*v1.ServicePort{httpOverlayBarPort},
   162  		},
   163  		{
   164  			name:                "overlay with different protocol",
   165  			basePorts:           []*v1.ServicePort{httpBaseBarPort},
   166  			overlayPorts:        []*v1.ServicePort{httpOverlayDiffProtocolBarPort},
   167  			expectedMergedPorts: []*v1.ServicePort{httpBaseBarPort, httpOverlayDiffProtocolBarPort},
   168  		},
   169  		{
   170  			name:                "same base and overlay with protocol omitted for overlay",
   171  			basePorts:           []*v1.ServicePort{httpFooPort},
   172  			overlayPorts:        []*v1.ServicePort{httpFooProtocolOmittedPort},
   173  			expectedMergedPorts: []*v1.ServicePort{httpFooPort},
   174  		},
   175  		{
   176  			name:                "same base and overlay with protocol omitted for base",
   177  			basePorts:           []*v1.ServicePort{httpFooProtocolOmittedPort},
   178  			overlayPorts:        []*v1.ServicePort{httpFooPort},
   179  			expectedMergedPorts: []*v1.ServicePort{httpFooPort},
   180  		},
   181  	} {
   182  		t.Run(tt.name, func(t *testing.T) {
   183  			actualMergedPorts := strategicMergePorts(tt.basePorts, tt.overlayPorts)
   184  			if diff := cmp.Diff(actualMergedPorts, tt.expectedMergedPorts); diff != "" {
   185  				t.Fatalf("expected differs from actual. Diff:\n%s", diff)
   186  			}
   187  		})
   188  	}
   189  }