1
// Copyright Istio Authors
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
7
// http://www.apache.org/licenses/LICENSE-2.0
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.
20
"github.com/google/go-cmp/cmp"
21
v1 "k8s.io/api/core/v1"
22
"k8s.io/apimachinery/pkg/util/intstr"
26
httpsPort = &v1.ServicePort{
28
Protocol: v1.ProtocolTCP,
30
TargetPort: intstr.IntOrString{IntVal: 8443},
32
quicPort = &v1.ServicePort{
34
Protocol: v1.ProtocolUDP,
36
TargetPort: intstr.IntOrString{IntVal: 8443},
38
httpPort = &v1.ServicePort{
40
Protocol: v1.ProtocolTCP,
42
TargetPort: intstr.IntOrString{IntVal: 8080},
44
httpNoProtoPort = &v1.ServicePort{
47
TargetPort: intstr.IntOrString{IntVal: 8080},
49
mysqlPort = &v1.ServicePort{
51
Protocol: v1.ProtocolTCP,
54
istioHealthcheckPort = &v1.ServicePort{
56
Protocol: v1.ProtocolTCP,
59
istioMetricsPort = &v1.ServicePort{
61
Protocol: v1.ProtocolTCP,
64
httpBaseBarPort = &v1.ServicePort{
65
Name: "http-bar-base",
66
Protocol: v1.ProtocolTCP,
69
httpOverlayBarPort = &v1.ServicePort{
70
Name: "http-bar-overlay",
71
Protocol: v1.ProtocolTCP,
74
httpOverlayDiffProtocolBarPort = &v1.ServicePort{
75
Name: "http3-bar-overlay",
76
Protocol: v1.ProtocolUDP,
79
httpFooPort = &v1.ServicePort{
81
Protocol: v1.ProtocolTCP,
84
httpFooProtocolOmittedPort = &v1.ServicePort{
90
func TestStrategicPortMergeByPortAndProtocol(t *testing.T) {
91
for _, tt := range []struct {
93
basePorts []*v1.ServicePort
94
overlayPorts []*v1.ServicePort
95
expectedMergedPorts []*v1.ServicePort
98
name: "both base and overlay are nil",
101
expectedMergedPorts: nil,
104
name: "overlay is nil",
105
basePorts: []*v1.ServicePort{httpPort, httpsPort, quicPort},
107
expectedMergedPorts: []*v1.ServicePort{httpPort, httpsPort, quicPort},
112
overlayPorts: []*v1.ServicePort{httpPort, httpsPort, quicPort},
113
expectedMergedPorts: []*v1.ServicePort{httpPort, httpsPort, quicPort},
116
name: "same base and overlay",
117
basePorts: []*v1.ServicePort{httpPort, httpsPort},
118
overlayPorts: []*v1.ServicePort{httpsPort, httpPort},
119
expectedMergedPorts: []*v1.ServicePort{httpPort, httpsPort},
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},
128
name: "base and overlay with different ports",
129
basePorts: []*v1.ServicePort{httpPort},
130
overlayPorts: []*v1.ServicePort{httpsPort},
131
expectedMergedPorts: []*v1.ServicePort{httpPort, httpsPort},
134
name: "implicit ports",
135
basePorts: []*v1.ServicePort{httpPort},
136
overlayPorts: []*v1.ServicePort{httpNoProtoPort},
137
expectedMergedPorts: []*v1.ServicePort{httpPort},
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},
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},
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},
158
name: "overlay with port name changed",
159
basePorts: []*v1.ServicePort{httpBaseBarPort},
160
overlayPorts: []*v1.ServicePort{httpOverlayBarPort},
161
expectedMergedPorts: []*v1.ServicePort{httpOverlayBarPort},
164
name: "overlay with different protocol",
165
basePorts: []*v1.ServicePort{httpBaseBarPort},
166
overlayPorts: []*v1.ServicePort{httpOverlayDiffProtocolBarPort},
167
expectedMergedPorts: []*v1.ServicePort{httpBaseBarPort, httpOverlayDiffProtocolBarPort},
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},
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},
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)