| /* |
| Copyright 2019 The Kubernetes Authors. |
| |
| Licensed under the Apache License, Version 2.0 (the "License"); |
| you may not use this file except in compliance with the License. |
| You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| */ |
| |
| package validation |
| |
| import ( |
| "fmt" |
| "strings" |
| "testing" |
| |
| corev1 "k8s.io/api/core/v1" |
| metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" |
| api "k8s.io/kubernetes/pkg/apis/core" |
| "k8s.io/kubernetes/pkg/apis/discovery" |
| utilpointer "k8s.io/utils/pointer" |
| ) |
| |
| func TestValidateEndpointSlice(t *testing.T) { |
| standardMeta := metav1.ObjectMeta{ |
| Name: "hello", |
| Namespace: "world", |
| } |
| |
| testCases := map[string]struct { |
| expectedErrors int |
| endpointSlice *discovery.EndpointSlice |
| }{ |
| "good-slice": { |
| expectedErrors: 0, |
| endpointSlice: &discovery.EndpointSlice{ |
| ObjectMeta: standardMeta, |
| AddressType: discovery.AddressTypeIPv4, |
| Ports: []discovery.EndpointPort{{ |
| Name: utilpointer.String("http"), |
| Protocol: protocolPtr(api.ProtocolTCP), |
| }}, |
| Endpoints: []discovery.Endpoint{{ |
| Addresses: generateIPAddresses(1), |
| Hostname: utilpointer.String("valid-123"), |
| }}, |
| }, |
| }, |
| "good-ipv6": { |
| expectedErrors: 0, |
| endpointSlice: &discovery.EndpointSlice{ |
| ObjectMeta: standardMeta, |
| AddressType: discovery.AddressTypeIPv6, |
| Ports: []discovery.EndpointPort{{ |
| Name: utilpointer.String("http"), |
| Protocol: protocolPtr(api.ProtocolTCP), |
| }}, |
| Endpoints: []discovery.Endpoint{{ |
| Addresses: []string{"a00:100::4"}, |
| Hostname: utilpointer.String("valid-123"), |
| }}, |
| }, |
| }, |
| "good-fqdns": { |
| expectedErrors: 0, |
| endpointSlice: &discovery.EndpointSlice{ |
| ObjectMeta: standardMeta, |
| AddressType: discovery.AddressTypeFQDN, |
| Ports: []discovery.EndpointPort{{ |
| Name: utilpointer.String("http"), |
| Protocol: protocolPtr(api.ProtocolTCP), |
| }}, |
| Endpoints: []discovery.Endpoint{{ |
| Addresses: []string{"foo.example.com", "example.com", "example.com.", "hyphens-are-good.example.com"}, |
| Hostname: utilpointer.String("valid-123"), |
| }}, |
| }, |
| }, |
| "all-protocols": { |
| expectedErrors: 0, |
| endpointSlice: &discovery.EndpointSlice{ |
| ObjectMeta: standardMeta, |
| AddressType: discovery.AddressTypeIPv4, |
| Ports: []discovery.EndpointPort{{ |
| Name: utilpointer.String("tcp"), |
| Protocol: protocolPtr(api.ProtocolTCP), |
| }, { |
| Name: utilpointer.String("udp"), |
| Protocol: protocolPtr(api.ProtocolUDP), |
| }, { |
| Name: utilpointer.String("sctp"), |
| Protocol: protocolPtr(api.ProtocolSCTP), |
| }}, |
| Endpoints: []discovery.Endpoint{{ |
| Addresses: generateIPAddresses(1), |
| Hostname: utilpointer.String("valid-123"), |
| }}, |
| }, |
| }, |
| "app-protocols": { |
| expectedErrors: 0, |
| endpointSlice: &discovery.EndpointSlice{ |
| ObjectMeta: standardMeta, |
| AddressType: discovery.AddressTypeIPv4, |
| Ports: []discovery.EndpointPort{{ |
| Name: utilpointer.String("one"), |
| Protocol: protocolPtr(api.ProtocolTCP), |
| AppProtocol: utilpointer.String("HTTP"), |
| }, { |
| Name: utilpointer.String("two"), |
| Protocol: protocolPtr(api.ProtocolTCP), |
| AppProtocol: utilpointer.String("https"), |
| }, { |
| Name: utilpointer.String("three"), |
| Protocol: protocolPtr(api.ProtocolTCP), |
| AppProtocol: utilpointer.String("my-protocol"), |
| }, { |
| Name: utilpointer.String("four"), |
| Protocol: protocolPtr(api.ProtocolTCP), |
| AppProtocol: utilpointer.String("example.com/custom-protocol"), |
| }}, |
| Endpoints: []discovery.Endpoint{{ |
| Addresses: generateIPAddresses(1), |
| Hostname: utilpointer.String("valid-123"), |
| }}, |
| }, |
| }, |
| "empty-port-name": { |
| expectedErrors: 0, |
| endpointSlice: &discovery.EndpointSlice{ |
| ObjectMeta: standardMeta, |
| AddressType: discovery.AddressTypeIPv4, |
| Ports: []discovery.EndpointPort{{ |
| Name: utilpointer.String(""), |
| Protocol: protocolPtr(api.ProtocolTCP), |
| }, { |
| Name: utilpointer.String("http"), |
| Protocol: protocolPtr(api.ProtocolTCP), |
| }}, |
| Endpoints: []discovery.Endpoint{{ |
| Addresses: generateIPAddresses(1), |
| }}, |
| }, |
| }, |
| "long-port-name": { |
| expectedErrors: 0, |
| endpointSlice: &discovery.EndpointSlice{ |
| ObjectMeta: standardMeta, |
| AddressType: discovery.AddressTypeIPv4, |
| Ports: []discovery.EndpointPort{{ |
| Name: utilpointer.String(strings.Repeat("a", 63)), |
| Protocol: protocolPtr(api.ProtocolTCP), |
| }}, |
| Endpoints: []discovery.Endpoint{{ |
| Addresses: generateIPAddresses(1), |
| }}, |
| }, |
| }, |
| "empty-ports-and-endpoints": { |
| expectedErrors: 0, |
| endpointSlice: &discovery.EndpointSlice{ |
| ObjectMeta: standardMeta, |
| AddressType: discovery.AddressTypeIPv4, |
| Ports: []discovery.EndpointPort{}, |
| Endpoints: []discovery.Endpoint{}, |
| }, |
| }, |
| "max-endpoints": { |
| expectedErrors: 0, |
| endpointSlice: &discovery.EndpointSlice{ |
| ObjectMeta: standardMeta, |
| AddressType: discovery.AddressTypeIPv4, |
| Ports: generatePorts(1), |
| Endpoints: generateEndpoints(maxEndpoints), |
| }, |
| }, |
| "max-ports": { |
| expectedErrors: 0, |
| endpointSlice: &discovery.EndpointSlice{ |
| ObjectMeta: standardMeta, |
| AddressType: discovery.AddressTypeIPv4, |
| Ports: generatePorts(maxPorts), |
| }, |
| }, |
| "max-addresses": { |
| expectedErrors: 0, |
| endpointSlice: &discovery.EndpointSlice{ |
| ObjectMeta: standardMeta, |
| AddressType: discovery.AddressTypeIPv4, |
| Ports: []discovery.EndpointPort{{ |
| Name: utilpointer.String("http"), |
| Protocol: protocolPtr(api.ProtocolTCP), |
| }}, |
| Endpoints: []discovery.Endpoint{{ |
| Addresses: generateIPAddresses(maxAddresses), |
| }}, |
| }, |
| }, |
| "max-topology-keys": { |
| expectedErrors: 0, |
| endpointSlice: &discovery.EndpointSlice{ |
| ObjectMeta: standardMeta, |
| AddressType: discovery.AddressTypeIPv4, |
| Ports: []discovery.EndpointPort{{ |
| Name: utilpointer.String("http"), |
| Protocol: protocolPtr(api.ProtocolTCP), |
| }}, |
| Endpoints: []discovery.Endpoint{{ |
| Addresses: generateIPAddresses(1), |
| DeprecatedTopology: generateTopology(maxTopologyLabels), |
| }}, |
| }, |
| }, |
| "valid-hints": { |
| expectedErrors: 0, |
| endpointSlice: &discovery.EndpointSlice{ |
| ObjectMeta: standardMeta, |
| AddressType: discovery.AddressTypeIPv4, |
| Ports: []discovery.EndpointPort{{ |
| Name: utilpointer.String("http"), |
| Protocol: protocolPtr(api.ProtocolTCP), |
| }}, |
| Endpoints: []discovery.Endpoint{{ |
| Addresses: generateIPAddresses(1), |
| Hints: &discovery.EndpointHints{ |
| ForZones: []discovery.ForZone{{Name: "zone-a"}}, |
| }, |
| }}, |
| }, |
| }, |
| |
| // expected failures |
| "duplicate-port-name": { |
| expectedErrors: 1, |
| endpointSlice: &discovery.EndpointSlice{ |
| ObjectMeta: standardMeta, |
| AddressType: discovery.AddressTypeIPv4, |
| Ports: []discovery.EndpointPort{{ |
| Name: utilpointer.String(""), |
| Protocol: protocolPtr(api.ProtocolTCP), |
| }, { |
| Name: utilpointer.String(""), |
| Protocol: protocolPtr(api.ProtocolTCP), |
| }}, |
| Endpoints: []discovery.Endpoint{}, |
| }, |
| }, |
| "bad-port-name-caps": { |
| expectedErrors: 1, |
| endpointSlice: &discovery.EndpointSlice{ |
| ObjectMeta: standardMeta, |
| AddressType: discovery.AddressTypeIPv4, |
| Ports: []discovery.EndpointPort{{ |
| Name: utilpointer.String("aCapital"), |
| Protocol: protocolPtr(api.ProtocolTCP), |
| }}, |
| Endpoints: []discovery.Endpoint{}, |
| }, |
| }, |
| "bad-port-name-chars": { |
| expectedErrors: 1, |
| endpointSlice: &discovery.EndpointSlice{ |
| ObjectMeta: standardMeta, |
| AddressType: discovery.AddressTypeIPv4, |
| Ports: []discovery.EndpointPort{{ |
| Name: utilpointer.String("almost_valid"), |
| Protocol: protocolPtr(api.ProtocolTCP), |
| }}, |
| Endpoints: []discovery.Endpoint{}, |
| }, |
| }, |
| "bad-port-name-length": { |
| expectedErrors: 1, |
| endpointSlice: &discovery.EndpointSlice{ |
| ObjectMeta: standardMeta, |
| AddressType: discovery.AddressTypeIPv4, |
| Ports: []discovery.EndpointPort{{ |
| Name: utilpointer.String(strings.Repeat("a", 64)), |
| Protocol: protocolPtr(api.ProtocolTCP), |
| }}, |
| Endpoints: []discovery.Endpoint{}, |
| }, |
| }, |
| "invalid-port-protocol": { |
| expectedErrors: 1, |
| endpointSlice: &discovery.EndpointSlice{ |
| ObjectMeta: standardMeta, |
| AddressType: discovery.AddressTypeIPv4, |
| Ports: []discovery.EndpointPort{{ |
| Name: utilpointer.String("http"), |
| Protocol: protocolPtr(api.Protocol("foo")), |
| }}, |
| }, |
| }, |
| "too-many-ports": { |
| expectedErrors: 1, |
| endpointSlice: &discovery.EndpointSlice{ |
| ObjectMeta: standardMeta, |
| AddressType: discovery.AddressTypeIPv4, |
| Ports: generatePorts(maxPorts + 1), |
| }, |
| }, |
| "too-many-endpoints": { |
| expectedErrors: 1, |
| endpointSlice: &discovery.EndpointSlice{ |
| ObjectMeta: standardMeta, |
| AddressType: discovery.AddressTypeIPv4, |
| Ports: generatePorts(1), |
| Endpoints: generateEndpoints(maxEndpoints + 1), |
| }, |
| }, |
| "no-endpoint-addresses": { |
| expectedErrors: 1, |
| endpointSlice: &discovery.EndpointSlice{ |
| ObjectMeta: standardMeta, |
| AddressType: discovery.AddressTypeIPv4, |
| Ports: []discovery.EndpointPort{{ |
| Name: utilpointer.String("http"), |
| Protocol: protocolPtr(api.ProtocolTCP), |
| }}, |
| Endpoints: []discovery.Endpoint{{ |
| Addresses: generateIPAddresses(0), |
| }}, |
| }, |
| }, |
| "too-many-addresses": { |
| expectedErrors: 1, |
| endpointSlice: &discovery.EndpointSlice{ |
| ObjectMeta: standardMeta, |
| AddressType: discovery.AddressTypeIPv4, |
| Ports: []discovery.EndpointPort{{ |
| Name: utilpointer.String("http"), |
| Protocol: protocolPtr(api.ProtocolTCP), |
| }}, |
| Endpoints: []discovery.Endpoint{{ |
| Addresses: generateIPAddresses(maxAddresses + 1), |
| }}, |
| }, |
| }, |
| "bad-topology-key": { |
| expectedErrors: 1, |
| endpointSlice: &discovery.EndpointSlice{ |
| ObjectMeta: standardMeta, |
| AddressType: discovery.AddressTypeIPv4, |
| Ports: []discovery.EndpointPort{{ |
| Name: utilpointer.String("http"), |
| Protocol: protocolPtr(api.ProtocolTCP), |
| }}, |
| Endpoints: []discovery.Endpoint{{ |
| Addresses: generateIPAddresses(1), |
| DeprecatedTopology: map[string]string{"--INVALID": "example"}, |
| }}, |
| }, |
| }, |
| "too-many-topology-keys": { |
| expectedErrors: 1, |
| endpointSlice: &discovery.EndpointSlice{ |
| ObjectMeta: standardMeta, |
| AddressType: discovery.AddressTypeIPv4, |
| Ports: []discovery.EndpointPort{{ |
| Name: utilpointer.String("http"), |
| Protocol: protocolPtr(api.ProtocolTCP), |
| }}, |
| Endpoints: []discovery.Endpoint{{ |
| Addresses: generateIPAddresses(1), |
| DeprecatedTopology: generateTopology(maxTopologyLabels + 1), |
| }}, |
| }, |
| }, |
| "bad-hostname": { |
| expectedErrors: 1, |
| endpointSlice: &discovery.EndpointSlice{ |
| ObjectMeta: standardMeta, |
| AddressType: discovery.AddressTypeIPv4, |
| Ports: []discovery.EndpointPort{{ |
| Name: utilpointer.String("http"), |
| Protocol: protocolPtr(api.ProtocolTCP), |
| }}, |
| Endpoints: []discovery.Endpoint{{ |
| Addresses: generateIPAddresses(1), |
| Hostname: utilpointer.String("--INVALID"), |
| }}, |
| }, |
| }, |
| "bad-meta": { |
| expectedErrors: 1, |
| endpointSlice: &discovery.EndpointSlice{ |
| ObjectMeta: metav1.ObjectMeta{ |
| Name: "*&^", |
| Namespace: "foo", |
| }, |
| AddressType: discovery.AddressTypeIPv4, |
| Ports: []discovery.EndpointPort{{ |
| Name: utilpointer.String("http"), |
| Protocol: protocolPtr(api.ProtocolTCP), |
| }}, |
| Endpoints: []discovery.Endpoint{{ |
| Addresses: generateIPAddresses(1), |
| Hostname: utilpointer.String("valid-123"), |
| }}, |
| }, |
| }, |
| "bad-ip": { |
| expectedErrors: 2, |
| endpointSlice: &discovery.EndpointSlice{ |
| ObjectMeta: standardMeta, |
| AddressType: discovery.AddressTypeIPv4, |
| Ports: []discovery.EndpointPort{{ |
| Name: utilpointer.String("http"), |
| Protocol: protocolPtr(api.ProtocolTCP), |
| }}, |
| Endpoints: []discovery.Endpoint{{ |
| Addresses: []string{"123.456.789.012"}, |
| Hostname: utilpointer.String("valid-123"), |
| }}, |
| }, |
| }, |
| "bad-ipv4": { |
| expectedErrors: 3, |
| endpointSlice: &discovery.EndpointSlice{ |
| ObjectMeta: standardMeta, |
| AddressType: discovery.AddressTypeIPv4, |
| Ports: []discovery.EndpointPort{{ |
| Name: utilpointer.String("http"), |
| Protocol: protocolPtr(api.ProtocolTCP), |
| }}, |
| Endpoints: []discovery.Endpoint{{ |
| Addresses: []string{"123.456.789.012", "2001:4860:4860::8888"}, |
| Hostname: utilpointer.String("valid-123"), |
| }}, |
| }, |
| }, |
| "bad-ipv6": { |
| expectedErrors: 4, |
| endpointSlice: &discovery.EndpointSlice{ |
| ObjectMeta: standardMeta, |
| AddressType: discovery.AddressTypeIPv6, |
| Ports: []discovery.EndpointPort{{ |
| Name: utilpointer.String("http"), |
| Protocol: protocolPtr(api.ProtocolTCP), |
| }}, |
| Endpoints: []discovery.Endpoint{{ |
| Addresses: []string{"123.456.789.012", "2001:4860:4860:defg"}, |
| Hostname: utilpointer.String("valid-123"), |
| }}, |
| }, |
| }, |
| "bad-fqdns": { |
| expectedErrors: 4, |
| endpointSlice: &discovery.EndpointSlice{ |
| ObjectMeta: standardMeta, |
| AddressType: discovery.AddressTypeFQDN, |
| Ports: []discovery.EndpointPort{{ |
| Name: utilpointer.String("http"), |
| Protocol: protocolPtr(api.ProtocolTCP), |
| }}, |
| Endpoints: []discovery.Endpoint{{ |
| Addresses: []string{"foo.*", "FOO.example.com", "underscores_are_bad.example.com", "*.example.com"}, |
| Hostname: utilpointer.String("valid-123"), |
| }}, |
| }, |
| }, |
| "bad-app-protocol": { |
| expectedErrors: 1, |
| endpointSlice: &discovery.EndpointSlice{ |
| ObjectMeta: standardMeta, |
| AddressType: discovery.AddressTypeIPv4, |
| Ports: []discovery.EndpointPort{{ |
| Name: utilpointer.String("http"), |
| Protocol: protocolPtr(api.ProtocolTCP), |
| AppProtocol: utilpointer.String("--"), |
| }}, |
| Endpoints: []discovery.Endpoint{{ |
| Addresses: generateIPAddresses(1), |
| Hostname: utilpointer.String("valid-123"), |
| }}, |
| }, |
| }, |
| "invalid-hints": { |
| expectedErrors: 1, |
| endpointSlice: &discovery.EndpointSlice{ |
| ObjectMeta: standardMeta, |
| AddressType: discovery.AddressTypeIPv4, |
| Ports: []discovery.EndpointPort{{ |
| Name: utilpointer.String("http"), |
| Protocol: protocolPtr(api.ProtocolTCP), |
| }}, |
| Endpoints: []discovery.Endpoint{{ |
| Addresses: generateIPAddresses(1), |
| Hints: &discovery.EndpointHints{ |
| ForZones: []discovery.ForZone{{Name: "inv@lid"}}, |
| }, |
| }}, |
| }, |
| }, |
| "overlapping-hints": { |
| expectedErrors: 1, |
| endpointSlice: &discovery.EndpointSlice{ |
| ObjectMeta: standardMeta, |
| AddressType: discovery.AddressTypeIPv4, |
| Ports: []discovery.EndpointPort{{ |
| Name: utilpointer.String("http"), |
| Protocol: protocolPtr(api.ProtocolTCP), |
| }}, |
| Endpoints: []discovery.Endpoint{{ |
| Addresses: generateIPAddresses(1), |
| Hints: &discovery.EndpointHints{ |
| ForZones: []discovery.ForZone{ |
| {Name: "zone-a"}, |
| {Name: "zone-b"}, |
| {Name: "zone-a"}, |
| }, |
| }, |
| }}, |
| }, |
| }, |
| "too-many-hints": { |
| expectedErrors: 1, |
| endpointSlice: &discovery.EndpointSlice{ |
| ObjectMeta: standardMeta, |
| AddressType: discovery.AddressTypeIPv4, |
| Ports: []discovery.EndpointPort{{ |
| Name: utilpointer.String("http"), |
| Protocol: protocolPtr(api.ProtocolTCP), |
| }}, |
| Endpoints: []discovery.Endpoint{{ |
| Addresses: generateIPAddresses(1), |
| Hints: &discovery.EndpointHints{ |
| ForZones: []discovery.ForZone{ |
| {Name: "zone-a"}, |
| {Name: "zone-b"}, |
| {Name: "zone-c"}, |
| {Name: "zone-d"}, |
| {Name: "zone-e"}, |
| {Name: "zone-f"}, |
| {Name: "zone-g"}, |
| {Name: "zone-h"}, |
| {Name: "zone-i"}, |
| }, |
| }, |
| }}, |
| }, |
| }, |
| "empty-everything": { |
| expectedErrors: 3, |
| endpointSlice: &discovery.EndpointSlice{}, |
| }, |
| "zone-key-topology": { |
| expectedErrors: 1, |
| endpointSlice: &discovery.EndpointSlice{ |
| ObjectMeta: standardMeta, |
| AddressType: discovery.AddressTypeIPv4, |
| Ports: []discovery.EndpointPort{{ |
| Name: utilpointer.String("http"), |
| Protocol: protocolPtr(api.ProtocolTCP), |
| }}, |
| Endpoints: []discovery.Endpoint{{ |
| Addresses: generateIPAddresses(1), |
| DeprecatedTopology: map[string]string{corev1.LabelTopologyZone: "zone1"}, |
| }}, |
| }, |
| }, |
| "special-ipv4": { |
| expectedErrors: 1, |
| endpointSlice: &discovery.EndpointSlice{ |
| ObjectMeta: standardMeta, |
| AddressType: discovery.AddressTypeIPv4, |
| Ports: []discovery.EndpointPort{{ |
| Name: utilpointer.String("http"), |
| Protocol: protocolPtr(api.ProtocolTCP), |
| }}, |
| Endpoints: []discovery.Endpoint{{ |
| Addresses: []string{"127.0.0.1"}, |
| Hostname: utilpointer.String("valid-123"), |
| }}, |
| }, |
| }, |
| "special-ipv6": { |
| expectedErrors: 1, |
| endpointSlice: &discovery.EndpointSlice{ |
| ObjectMeta: standardMeta, |
| AddressType: discovery.AddressTypeIPv6, |
| Ports: []discovery.EndpointPort{{ |
| Name: utilpointer.String("http"), |
| Protocol: protocolPtr(api.ProtocolTCP), |
| }}, |
| Endpoints: []discovery.Endpoint{{ |
| Addresses: []string{"fe80::9656:d028:8652:66b6"}, |
| Hostname: utilpointer.String("valid-123"), |
| }}, |
| }, |
| }, |
| } |
| |
| for name, testCase := range testCases { |
| t.Run(name, func(t *testing.T) { |
| errs := ValidateEndpointSlice(testCase.endpointSlice) |
| if len(errs) != testCase.expectedErrors { |
| t.Errorf("Expected %d errors, got %d errors: %v", testCase.expectedErrors, len(errs), errs) |
| } |
| }) |
| } |
| } |
| |
| func TestValidateEndpointSliceCreate(t *testing.T) { |
| standardMeta := metav1.ObjectMeta{ |
| Name: "hello", |
| Namespace: "world", |
| } |
| |
| testCases := map[string]struct { |
| expectedErrors int |
| endpointSlice *discovery.EndpointSlice |
| nodeNameGateEnabled bool |
| }{ |
| "good-slice": { |
| expectedErrors: 0, |
| endpointSlice: &discovery.EndpointSlice{ |
| ObjectMeta: standardMeta, |
| AddressType: discovery.AddressTypeIPv4, |
| Ports: []discovery.EndpointPort{{ |
| Name: utilpointer.String("http"), |
| Protocol: protocolPtr(api.ProtocolTCP), |
| }}, |
| Endpoints: []discovery.Endpoint{{ |
| Addresses: generateIPAddresses(1), |
| Hostname: utilpointer.String("valid-123"), |
| }}, |
| }, |
| }, |
| "good-slice-node-name": { |
| expectedErrors: 0, |
| endpointSlice: &discovery.EndpointSlice{ |
| ObjectMeta: standardMeta, |
| AddressType: discovery.AddressTypeIPv4, |
| Ports: []discovery.EndpointPort{{ |
| Name: utilpointer.String("http"), |
| Protocol: protocolPtr(api.ProtocolTCP), |
| }}, |
| Endpoints: []discovery.Endpoint{{ |
| Addresses: generateIPAddresses(1), |
| Hostname: utilpointer.String("valid-123"), |
| NodeName: utilpointer.String("valid-node-name"), |
| }}, |
| }, |
| }, |
| |
| // expected failures |
| "bad-node-name": { |
| expectedErrors: 1, |
| endpointSlice: &discovery.EndpointSlice{ |
| ObjectMeta: standardMeta, |
| AddressType: discovery.AddressTypeIPv4, |
| Ports: []discovery.EndpointPort{{ |
| Name: utilpointer.String("http"), |
| Protocol: protocolPtr(api.ProtocolTCP), |
| }}, |
| Endpoints: []discovery.Endpoint{{ |
| Addresses: generateIPAddresses(1), |
| Hostname: utilpointer.String("valid-123"), |
| NodeName: utilpointer.String("INvalid-node-name"), |
| }}, |
| }, |
| }, |
| "deprecated-address-type": { |
| expectedErrors: 1, |
| endpointSlice: &discovery.EndpointSlice{ |
| ObjectMeta: standardMeta, |
| AddressType: discovery.AddressType("IP"), |
| Ports: []discovery.EndpointPort{{ |
| Name: utilpointer.String("http"), |
| Protocol: protocolPtr(api.ProtocolTCP), |
| }}, |
| Endpoints: []discovery.Endpoint{{ |
| Addresses: generateIPAddresses(1), |
| }}, |
| }, |
| }, |
| "bad-address-type": { |
| expectedErrors: 1, |
| endpointSlice: &discovery.EndpointSlice{ |
| ObjectMeta: standardMeta, |
| AddressType: discovery.AddressType("other"), |
| Ports: []discovery.EndpointPort{{ |
| Name: utilpointer.String("http"), |
| Protocol: protocolPtr(api.ProtocolTCP), |
| }}, |
| Endpoints: []discovery.Endpoint{{ |
| Addresses: generateIPAddresses(1), |
| }}, |
| }, |
| }, |
| } |
| |
| for name, testCase := range testCases { |
| t.Run(name, func(t *testing.T) { |
| errs := ValidateEndpointSliceCreate(testCase.endpointSlice) |
| if len(errs) != testCase.expectedErrors { |
| t.Errorf("Expected %d errors, got %d errors: %v", testCase.expectedErrors, len(errs), errs) |
| } |
| }) |
| } |
| } |
| |
| func TestValidateEndpointSliceUpdate(t *testing.T) { |
| standardMeta := metav1.ObjectMeta{Name: "es1", Namespace: "test"} |
| |
| testCases := map[string]struct { |
| expectedErrors int |
| nodeNameGateEnabled bool |
| oldEndpointSlice *discovery.EndpointSlice |
| newEndpointSlice *discovery.EndpointSlice |
| }{ |
| "valid and identical slices": { |
| oldEndpointSlice: &discovery.EndpointSlice{ |
| ObjectMeta: standardMeta, |
| AddressType: discovery.AddressTypeIPv6, |
| }, |
| newEndpointSlice: &discovery.EndpointSlice{ |
| ObjectMeta: standardMeta, |
| AddressType: discovery.AddressTypeIPv6, |
| }, |
| expectedErrors: 0, |
| }, |
| |
| // expected errors |
| "invalid node name set": { |
| oldEndpointSlice: &discovery.EndpointSlice{ |
| ObjectMeta: standardMeta, |
| AddressType: discovery.AddressTypeIPv4, |
| Endpoints: []discovery.Endpoint{{ |
| Addresses: []string{"10.1.2.3"}, |
| }}, |
| }, |
| newEndpointSlice: &discovery.EndpointSlice{ |
| ObjectMeta: standardMeta, |
| AddressType: discovery.AddressTypeIPv4, |
| Endpoints: []discovery.Endpoint{{ |
| Addresses: []string{"10.1.2.3"}, |
| NodeName: utilpointer.String("INVALID foo"), |
| }}, |
| }, |
| expectedErrors: 1, |
| }, |
| |
| "deprecated address type": { |
| expectedErrors: 1, |
| oldEndpointSlice: &discovery.EndpointSlice{ |
| ObjectMeta: standardMeta, |
| AddressType: discovery.AddressType("IP"), |
| }, |
| newEndpointSlice: &discovery.EndpointSlice{ |
| ObjectMeta: standardMeta, |
| AddressType: discovery.AddressType("IP"), |
| }, |
| }, |
| "valid and identical slices with different address types": { |
| oldEndpointSlice: &discovery.EndpointSlice{ |
| ObjectMeta: standardMeta, |
| AddressType: discovery.AddressType("other"), |
| }, |
| newEndpointSlice: &discovery.EndpointSlice{ |
| ObjectMeta: standardMeta, |
| AddressType: discovery.AddressTypeIPv4, |
| }, |
| expectedErrors: 1, |
| }, |
| "invalid slices with valid address types": { |
| oldEndpointSlice: &discovery.EndpointSlice{ |
| ObjectMeta: standardMeta, |
| AddressType: discovery.AddressTypeIPv4, |
| }, |
| newEndpointSlice: &discovery.EndpointSlice{ |
| ObjectMeta: standardMeta, |
| AddressType: discovery.AddressTypeIPv4, |
| Ports: []discovery.EndpointPort{{ |
| Name: utilpointer.String(""), |
| Protocol: protocolPtr(api.Protocol("invalid")), |
| }}, |
| }, |
| expectedErrors: 1, |
| }, |
| } |
| |
| for name, testCase := range testCases { |
| t.Run(name, func(t *testing.T) { |
| errs := ValidateEndpointSliceUpdate(testCase.newEndpointSlice, testCase.oldEndpointSlice) |
| if len(errs) != testCase.expectedErrors { |
| t.Errorf("Expected %d errors, got %d errors: %v", testCase.expectedErrors, len(errs), errs) |
| } |
| }) |
| } |
| } |
| |
| // Test helpers |
| |
| func protocolPtr(protocol api.Protocol) *api.Protocol { |
| return &protocol |
| } |
| |
| func generatePorts(n int) []discovery.EndpointPort { |
| ports := []discovery.EndpointPort{} |
| for i := 0; i < n; i++ { |
| ports = append(ports, discovery.EndpointPort{ |
| Name: utilpointer.String(fmt.Sprintf("http-%d", i)), |
| Protocol: protocolPtr(api.ProtocolTCP), |
| }) |
| } |
| return ports |
| } |
| |
| func generateEndpoints(n int) []discovery.Endpoint { |
| endpoints := []discovery.Endpoint{} |
| for i := 0; i < n; i++ { |
| endpoints = append(endpoints, discovery.Endpoint{ |
| Addresses: []string{fmt.Sprintf("10.1.2.%d", i%255)}, |
| }) |
| } |
| return endpoints |
| } |
| |
| func generateIPAddresses(n int) []string { |
| addresses := []string{} |
| for i := 0; i < n; i++ { |
| addresses = append(addresses, fmt.Sprintf("10.1.2.%d", i%255)) |
| } |
| return addresses |
| } |
| |
| func generateTopology(n int) map[string]string { |
| topology := map[string]string{} |
| for i := 0; i < n; i++ { |
| topology[fmt.Sprintf("topology-%d", i)] = "example" |
| } |
| return topology |
| } |