From 6069d49d49f2f2477219c6028da5e5060d98458d Mon Sep 17 00:00:00 2001 From: Tim Hockin Date: Fri, 3 Feb 2017 16:05:09 -0800 Subject: [PATCH] Add tests for updateEndpoints --- pkg/proxy/iptables/proxier.go | 95 +++-- pkg/proxy/iptables/proxier_test.go | 623 +++++++++++++++++++++++++++++ 2 files changed, 679 insertions(+), 39 deletions(-) diff --git a/pkg/proxy/iptables/proxier.go b/pkg/proxy/iptables/proxier.go index e915c3c808e..284e5370d1a 100644 --- a/pkg/proxy/iptables/proxier.go +++ b/pkg/proxy/iptables/proxier.go @@ -588,42 +588,9 @@ func (proxier *Proxier) OnEndpointsUpdate(allEndpoints []api.Endpoints) { defer proxier.mu.Unlock() proxier.haveReceivedEndpointsUpdate = true - staleConnections := make(map[endpointServicePair]bool) - svcPortToInfoMap := make(map[proxy.ServicePortName][]hostPortInfo) - newEndpointsMap := make(map[proxy.ServicePortName][]*endpointsInfo) - - // Update endpoints for services. - for i := range allEndpoints { - accumulateEndpointsMap(&allEndpoints[i], proxier.hostname, proxier.endpointsMap, &newEndpointsMap, - &svcPortToInfoMap, &staleConnections) - } - // Check stale connections against endpoints missing from the update. - // TODO: we should really only mark a connection stale if the proto was UDP - // and the (ip, port, proto) was removed from the endpoints. - for svcPort := range proxier.endpointsMap { - if _, found := newEndpointsMap[svcPort]; !found { - glog.V(3).Infof("Removing endpoints for %q", svcPort) - // record endpoints of unactive service to stale connections - for _, ep := range proxier.endpointsMap[svcPort] { - staleConnections[endpointServicePair{endpoint: ep.endpoint, servicePortName: svcPort}] = true - } - } - } - - // Update service health check - allSvcPorts := make(map[proxy.ServicePortName]bool) - for svcPort := range proxier.endpointsMap { - allSvcPorts[svcPort] = true - } - for svcPort := range newEndpointsMap { - allSvcPorts[svcPort] = true - } - for svcPort := range allSvcPorts { - proxier.updateHealthCheckEntries(svcPort.NamespacedName, svcPortToInfoMap[svcPort]) - } - - if len(newEndpointsMap) != len(proxier.endpointsMap) || !reflect.DeepEqual(newEndpointsMap, proxier.endpointsMap) { - proxier.endpointsMap = newEndpointsMap + newMap, staleConnections := updateEndpoints(allEndpoints, proxier.endpointsMap, proxier.hostname, updateHealthCheckEntries) + if len(newMap) != len(proxier.endpointsMap) || !reflect.DeepEqual(newMap, proxier.endpointsMap) { + proxier.endpointsMap = newMap proxier.syncProxyRules() } else { glog.V(4).Infof("Skipping proxy iptables rule sync on endpoint update because nothing changed") @@ -632,9 +599,59 @@ func (proxier *Proxier) OnEndpointsUpdate(allEndpoints []api.Endpoints) { proxier.deleteEndpointConnections(staleConnections) } +// Convert a slice of api.Endpoints objects into a map of service-port -> endpoints. +// TODO: the hcUpdater should be a method on an interface, but it is a global pkg for now +func updateEndpoints(allEndpoints []api.Endpoints, curMap map[proxy.ServicePortName][]*endpointsInfo, hostname string, + hcUpdater func(types.NamespacedName, []hostPortInfo)) (newMap map[proxy.ServicePortName][]*endpointsInfo, stale map[endpointServicePair]bool) { + + // return values + newMap = make(map[proxy.ServicePortName][]*endpointsInfo) + stale = make(map[endpointServicePair]bool) + + // local + svcPortToInfoMap := make(map[proxy.ServicePortName][]hostPortInfo) + + // Update endpoints for services. + for i := range allEndpoints { + accumulateEndpointsMap(&allEndpoints[i], hostname, curMap, &newMap, &svcPortToInfoMap, &stale) + } + // Check stale connections against endpoints missing from the update. + // TODO: we should really only mark a connection stale if the proto was UDP + // and the (ip, port, proto) was removed from the endpoints. + for svcPort := range curMap { + if _, found := newMap[svcPort]; !found { + glog.V(3).Infof("Removing endpoints for %q", svcPort) + // record endpoints of unactive service to stale connections + for _, ep := range curMap[svcPort] { + stale[endpointServicePair{endpoint: ep.endpoint, servicePortName: svcPort}] = true + } + } + } + + // Update service health check + allSvcPorts := make(map[proxy.ServicePortName]bool) + for svcPort := range curMap { + allSvcPorts[svcPort] = true + } + for svcPort := range newMap { + allSvcPorts[svcPort] = true + } + for svcPort := range allSvcPorts { + hcUpdater(svcPort.NamespacedName, svcPortToInfoMap[svcPort]) + } + + return newMap, stale +} + // Gather information about all the endpoint state for a given api.Endpoints. -// This can not detect all stale connections, so the caller should also check -// for entries that were totally removed. +// This can not report complete info on stale connections because it has limited +// scope - it only knows one Endpoints, but sees the whole current map. That +// cleanup has to be done above. +// +// TODO: this could be simplified: +// - hostPortInfo and endpointsInfo overlap too much +// - the test for this is overlapped by the test for updateEndpoints +// - naming is poor and responsibilities are muddled func accumulateEndpointsMap(endpoints *api.Endpoints, hostname string, curEndpoints map[proxy.ServicePortName][]*endpointsInfo, newEndpoints *map[proxy.ServicePortName][]*endpointsInfo, @@ -682,7 +699,7 @@ func accumulateEndpointsMap(endpoints *api.Endpoints, hostname string, } // updateHealthCheckEntries - send the new set of local endpoints to the health checker -func (proxier *Proxier) updateHealthCheckEntries(name types.NamespacedName, hostPorts []hostPortInfo) { +func updateHealthCheckEntries(name types.NamespacedName, hostPorts []hostPortInfo) { if !utilfeature.DefaultFeatureGate.Enabled(features.ExternalTrafficLocalOnly) { return } diff --git a/pkg/proxy/iptables/proxier_test.go b/pkg/proxy/iptables/proxier_test.go index 194cae464fb..1ebd9af31eb 100644 --- a/pkg/proxy/iptables/proxier_test.go +++ b/pkg/proxy/iptables/proxier_test.go @@ -1453,4 +1453,627 @@ func makeServicePortName(ns, name, port string) proxy.ServicePortName { } } +func Test_updateEndpoints(t *testing.T) { + testCases := []struct { + newEndpoints []api.Endpoints + oldEndpoints map[proxy.ServicePortName][]*endpointsInfo + expectedResult map[proxy.ServicePortName][]*endpointsInfo + expectedStale []endpointServicePair + }{{ + // Case[0]: nothing + newEndpoints: []api.Endpoints{}, + oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{}, + expectedResult: map[proxy.ServicePortName][]*endpointsInfo{}, + expectedStale: []endpointServicePair{}, + }, { + // Case[1]: no change, unnamed port + newEndpoints: []api.Endpoints{ + makeTestEndpoints("ns1", "ep1", func(ept *api.Endpoints) { + ept.Subsets = []api.EndpointSubset{{ + Addresses: []api.EndpointAddress{{ + IP: "1.1.1.1", + }}, + Ports: []api.EndpointPort{{ + Port: 11, + }}, + }} + }), + }, + oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{ + makeServicePortName("ns1", "ep1", ""): { + {"1.1.1.1:11", false}, + }, + }, + expectedResult: map[proxy.ServicePortName][]*endpointsInfo{ + makeServicePortName("ns1", "ep1", ""): { + {"1.1.1.1:11", false}, + }, + }, + expectedStale: []endpointServicePair{}, + }, { + // Case[2]: no change, named port + newEndpoints: []api.Endpoints{ + makeTestEndpoints("ns1", "ep1", func(ept *api.Endpoints) { + ept.Subsets = []api.EndpointSubset{{ + Addresses: []api.EndpointAddress{{ + IP: "1.1.1.1", + }}, + Ports: []api.EndpointPort{{ + Name: "p11", + Port: 11, + }}, + }} + }), + }, + oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{ + makeServicePortName("ns1", "ep1", "p11"): { + {"1.1.1.1:11", false}, + }, + }, + expectedResult: map[proxy.ServicePortName][]*endpointsInfo{ + makeServicePortName("ns1", "ep1", "p11"): { + {"1.1.1.1:11", false}, + }, + }, + expectedStale: []endpointServicePair{}, + }, { + // Case[3]: no change, multiple subsets + newEndpoints: []api.Endpoints{ + makeTestEndpoints("ns1", "ep1", func(ept *api.Endpoints) { + ept.Subsets = []api.EndpointSubset{{ + Addresses: []api.EndpointAddress{{ + IP: "1.1.1.1", + }}, + Ports: []api.EndpointPort{{ + Name: "p11", + Port: 11, + }}, + }, { + Addresses: []api.EndpointAddress{{ + IP: "1.1.1.2", + }}, + Ports: []api.EndpointPort{{ + Name: "p12", + Port: 12, + }}, + }} + }), + }, + oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{ + makeServicePortName("ns1", "ep1", "p11"): { + {"1.1.1.1:11", false}, + }, + makeServicePortName("ns1", "ep1", "p12"): { + {"1.1.1.2:12", false}, + }, + }, + expectedResult: map[proxy.ServicePortName][]*endpointsInfo{ + makeServicePortName("ns1", "ep1", "p11"): { + {"1.1.1.1:11", false}, + }, + makeServicePortName("ns1", "ep1", "p12"): { + {"1.1.1.2:12", false}, + }, + }, + expectedStale: []endpointServicePair{}, + }, { + // Case[4]: no change, multiple subsets, multiple ports + newEndpoints: []api.Endpoints{ + makeTestEndpoints("ns1", "ep1", func(ept *api.Endpoints) { + ept.Subsets = []api.EndpointSubset{{ + Addresses: []api.EndpointAddress{{ + IP: "1.1.1.1", + }}, + Ports: []api.EndpointPort{{ + Name: "p11", + Port: 11, + }, { + Name: "p12", + Port: 12, + }}, + }, { + Addresses: []api.EndpointAddress{{ + IP: "1.1.1.3", + }}, + Ports: []api.EndpointPort{{ + Name: "p13", + Port: 13, + }}, + }} + }), + }, + oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{ + makeServicePortName("ns1", "ep1", "p11"): { + {"1.1.1.1:11", false}, + }, + makeServicePortName("ns1", "ep1", "p12"): { + {"1.1.1.1:12", false}, + }, + makeServicePortName("ns1", "ep1", "p13"): { + {"1.1.1.3:13", false}, + }, + }, + expectedResult: map[proxy.ServicePortName][]*endpointsInfo{ + makeServicePortName("ns1", "ep1", "p11"): { + {"1.1.1.1:11", false}, + }, + makeServicePortName("ns1", "ep1", "p12"): { + {"1.1.1.1:12", false}, + }, + makeServicePortName("ns1", "ep1", "p13"): { + {"1.1.1.3:13", false}, + }, + }, + expectedStale: []endpointServicePair{}, + }, { + // Case[5]: no change, multiple endpoints, subsets, IPs, and ports + newEndpoints: []api.Endpoints{ + makeTestEndpoints("ns1", "ep1", func(ept *api.Endpoints) { + ept.Subsets = []api.EndpointSubset{{ + Addresses: []api.EndpointAddress{{ + IP: "1.1.1.1", + }, { + IP: "1.1.1.2", + }}, + Ports: []api.EndpointPort{{ + Name: "p11", + Port: 11, + }, { + Name: "p12", + Port: 12, + }}, + }, { + Addresses: []api.EndpointAddress{{ + IP: "1.1.1.3", + }, { + IP: "1.1.1.4", + }}, + Ports: []api.EndpointPort{{ + Name: "p13", + Port: 13, + }, { + Name: "p14", + Port: 14, + }}, + }} + }), + makeTestEndpoints("ns2", "ep2", func(ept *api.Endpoints) { + ept.Subsets = []api.EndpointSubset{{ + Addresses: []api.EndpointAddress{{ + IP: "2.2.2.1", + }, { + IP: "2.2.2.2", + }}, + Ports: []api.EndpointPort{{ + Name: "p21", + Port: 21, + }, { + Name: "p22", + Port: 22, + }}, + }} + }), + }, + oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{ + makeServicePortName("ns1", "ep1", "p11"): { + {"1.1.1.1:11", false}, + {"1.1.1.2:11", false}, + }, + makeServicePortName("ns1", "ep1", "p12"): { + {"1.1.1.1:12", false}, + {"1.1.1.2:12", false}, + }, + makeServicePortName("ns1", "ep1", "p13"): { + {"1.1.1.3:13", false}, + {"1.1.1.4:13", false}, + }, + makeServicePortName("ns1", "ep1", "p14"): { + {"1.1.1.3:14", false}, + {"1.1.1.4:14", false}, + }, + makeServicePortName("ns2", "ep2", "p21"): { + {"2.2.2.1:21", false}, + {"2.2.2.2:21", false}, + }, + makeServicePortName("ns2", "ep2", "p22"): { + {"2.2.2.1:22", false}, + {"2.2.2.2:22", false}, + }, + }, + expectedResult: map[proxy.ServicePortName][]*endpointsInfo{ + makeServicePortName("ns1", "ep1", "p11"): { + {"1.1.1.1:11", false}, + {"1.1.1.2:11", false}, + }, + makeServicePortName("ns1", "ep1", "p12"): { + {"1.1.1.1:12", false}, + {"1.1.1.2:12", false}, + }, + makeServicePortName("ns1", "ep1", "p13"): { + {"1.1.1.3:13", false}, + {"1.1.1.4:13", false}, + }, + makeServicePortName("ns1", "ep1", "p14"): { + {"1.1.1.3:14", false}, + {"1.1.1.4:14", false}, + }, + makeServicePortName("ns2", "ep2", "p21"): { + {"2.2.2.1:21", false}, + {"2.2.2.2:21", false}, + }, + makeServicePortName("ns2", "ep2", "p22"): { + {"2.2.2.1:22", false}, + {"2.2.2.2:22", false}, + }, + }, + expectedStale: []endpointServicePair{}, + }, { + // Case[6]: add an Endpoints + newEndpoints: []api.Endpoints{ + makeTestEndpoints("ns1", "ep1", func(ept *api.Endpoints) { + ept.Subsets = []api.EndpointSubset{{ + Addresses: []api.EndpointAddress{{ + IP: "1.1.1.1", + }}, + Ports: []api.EndpointPort{{ + Port: 11, + }}, + }} + }), + }, + oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{ /* empty */ }, + expectedResult: map[proxy.ServicePortName][]*endpointsInfo{ + makeServicePortName("ns1", "ep1", ""): { + {"1.1.1.1:11", false}, + }, + }, + expectedStale: []endpointServicePair{}, + }, { + // Case[7]: remove an Endpoints + newEndpoints: []api.Endpoints{ /* empty */ }, + oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{ + makeServicePortName("ns1", "ep1", ""): { + {"1.1.1.1:11", false}, + }, + }, + expectedResult: map[proxy.ServicePortName][]*endpointsInfo{}, + expectedStale: []endpointServicePair{{ + endpoint: "1.1.1.1:11", + servicePortName: makeServicePortName("ns1", "ep1", ""), + }}, + }, { + // Case[8]: add an IP and port + newEndpoints: []api.Endpoints{ + makeTestEndpoints("ns1", "ep1", func(ept *api.Endpoints) { + ept.Subsets = []api.EndpointSubset{{ + Addresses: []api.EndpointAddress{{ + IP: "1.1.1.1", + }, { + IP: "1.1.1.2", + }}, + Ports: []api.EndpointPort{{ + Name: "p11", + Port: 11, + }, { + Name: "p12", + Port: 12, + }}, + }} + }), + }, + oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{ + makeServicePortName("ns1", "ep1", "p11"): { + {"1.1.1.1:11", false}, + }, + }, + expectedResult: map[proxy.ServicePortName][]*endpointsInfo{ + makeServicePortName("ns1", "ep1", "p11"): { + {"1.1.1.1:11", false}, + {"1.1.1.2:11", false}, + }, + makeServicePortName("ns1", "ep1", "p12"): { + {"1.1.1.1:12", false}, + {"1.1.1.2:12", false}, + }, + }, + expectedStale: []endpointServicePair{}, + }, { + // Case[9]: remove an IP and port + newEndpoints: []api.Endpoints{ + makeTestEndpoints("ns1", "ep1", func(ept *api.Endpoints) { + ept.Subsets = []api.EndpointSubset{{ + Addresses: []api.EndpointAddress{{ + IP: "1.1.1.1", + }}, + Ports: []api.EndpointPort{{ + Name: "p11", + Port: 11, + }}, + }} + }), + }, + oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{ + makeServicePortName("ns1", "ep1", "p11"): { + {"1.1.1.1:11", false}, + {"1.1.1.2:11", false}, + }, + makeServicePortName("ns1", "ep1", "p12"): { + {"1.1.1.1:12", false}, + {"1.1.1.2:12", false}, + }, + }, + expectedResult: map[proxy.ServicePortName][]*endpointsInfo{ + makeServicePortName("ns1", "ep1", "p11"): { + {"1.1.1.1:11", false}, + }, + }, + expectedStale: []endpointServicePair{{ + endpoint: "1.1.1.2:11", + servicePortName: makeServicePortName("ns1", "ep1", "p11"), + }, { + endpoint: "1.1.1.1:12", + servicePortName: makeServicePortName("ns1", "ep1", "p12"), + }, { + endpoint: "1.1.1.2:12", + servicePortName: makeServicePortName("ns1", "ep1", "p12"), + }}, + }, { + // Case[10]: add a subset + newEndpoints: []api.Endpoints{ + makeTestEndpoints("ns1", "ep1", func(ept *api.Endpoints) { + ept.Subsets = []api.EndpointSubset{{ + Addresses: []api.EndpointAddress{{ + IP: "1.1.1.1", + }}, + Ports: []api.EndpointPort{{ + Name: "p11", + Port: 11, + }}, + }, { + Addresses: []api.EndpointAddress{{ + IP: "2.2.2.2", + }}, + Ports: []api.EndpointPort{{ + Name: "p22", + Port: 22, + }}, + }} + }), + }, + oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{ + makeServicePortName("ns1", "ep1", "p11"): { + {"1.1.1.1:11", false}, + }, + }, + expectedResult: map[proxy.ServicePortName][]*endpointsInfo{ + makeServicePortName("ns1", "ep1", "p11"): { + {"1.1.1.1:11", false}, + }, + makeServicePortName("ns1", "ep1", "p22"): { + {"2.2.2.2:22", false}, + }, + }, + expectedStale: []endpointServicePair{}, + }, { + // Case[11]: remove a subset + newEndpoints: []api.Endpoints{ + makeTestEndpoints("ns1", "ep1", func(ept *api.Endpoints) { + ept.Subsets = []api.EndpointSubset{{ + Addresses: []api.EndpointAddress{{ + IP: "1.1.1.1", + }}, + Ports: []api.EndpointPort{{ + Name: "p11", + Port: 11, + }}, + }} + }), + }, + oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{ + makeServicePortName("ns1", "ep1", "p11"): { + {"1.1.1.1:11", false}, + }, + makeServicePortName("ns1", "ep1", "p22"): { + {"2.2.2.2:22", false}, + }, + }, + expectedResult: map[proxy.ServicePortName][]*endpointsInfo{ + makeServicePortName("ns1", "ep1", "p11"): { + {"1.1.1.1:11", false}, + }, + }, + expectedStale: []endpointServicePair{{ + endpoint: "2.2.2.2:22", + servicePortName: makeServicePortName("ns1", "ep1", "p22"), + }}, + }, { + // Case[12]: rename a port + newEndpoints: []api.Endpoints{ + makeTestEndpoints("ns1", "ep1", func(ept *api.Endpoints) { + ept.Subsets = []api.EndpointSubset{{ + Addresses: []api.EndpointAddress{{ + IP: "1.1.1.1", + }}, + Ports: []api.EndpointPort{{ + Name: "p11-2", + Port: 11, + }}, + }} + }), + }, + oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{ + makeServicePortName("ns1", "ep1", "p11"): { + {"1.1.1.1:11", false}, + }, + }, + expectedResult: map[proxy.ServicePortName][]*endpointsInfo{ + makeServicePortName("ns1", "ep1", "p11-2"): { + {"1.1.1.1:11", false}, + }, + }, + expectedStale: []endpointServicePair{{ + endpoint: "1.1.1.1:11", + servicePortName: makeServicePortName("ns1", "ep1", "p11"), + }}, + }, { + // Case[13]: renumber a port + newEndpoints: []api.Endpoints{ + makeTestEndpoints("ns1", "ep1", func(ept *api.Endpoints) { + ept.Subsets = []api.EndpointSubset{{ + Addresses: []api.EndpointAddress{{ + IP: "1.1.1.1", + }}, + Ports: []api.EndpointPort{{ + Name: "p11", + Port: 22, + }}, + }} + }), + }, + oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{ + makeServicePortName("ns1", "ep1", "p11"): { + {"1.1.1.1:11", false}, + }, + }, + expectedResult: map[proxy.ServicePortName][]*endpointsInfo{ + makeServicePortName("ns1", "ep1", "p11"): { + {"1.1.1.1:22", false}, + }, + }, + expectedStale: []endpointServicePair{{ + endpoint: "1.1.1.1:11", + servicePortName: makeServicePortName("ns1", "ep1", "p11"), + }}, + }, { + // Case[14]: complex add and remove + newEndpoints: []api.Endpoints{ + makeTestEndpoints("ns1", "ep1", func(ept *api.Endpoints) { + ept.Subsets = []api.EndpointSubset{{ + Addresses: []api.EndpointAddress{{ + IP: "1.1.1.1", + }, { + IP: "1.1.1.11", + }}, + Ports: []api.EndpointPort{{ + Name: "p11", + Port: 11, + }}, + }, { + Addresses: []api.EndpointAddress{{ + IP: "1.1.1.2", + }}, + Ports: []api.EndpointPort{{ + Name: "p12", + Port: 12, + }, { + Name: "p122", + Port: 122, + }}, + }} + }), + makeTestEndpoints("ns3", "ep3", func(ept *api.Endpoints) { + ept.Subsets = []api.EndpointSubset{{ + Addresses: []api.EndpointAddress{{ + IP: "3.3.3.3", + }}, + Ports: []api.EndpointPort{{ + Name: "p33", + Port: 33, + }}, + }} + }), + makeTestEndpoints("ns4", "ep4", func(ept *api.Endpoints) { + ept.Subsets = []api.EndpointSubset{{ + Addresses: []api.EndpointAddress{{ + IP: "4.4.4.4", + }}, + Ports: []api.EndpointPort{{ + Name: "p44", + Port: 44, + }}, + }} + }), + }, + oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{ + makeServicePortName("ns1", "ep1", "p11"): { + {"1.1.1.1:11", false}, + }, + makeServicePortName("ns2", "ep2", "p22"): { + {"2.2.2.2:22", false}, + {"2.2.2.22:22", false}, + }, + makeServicePortName("ns2", "ep2", "p23"): { + {"2.2.2.3:23", false}, + }, + makeServicePortName("ns4", "ep4", "p44"): { + {"4.4.4.4:44", false}, + {"4.4.4.5:44", false}, + }, + makeServicePortName("ns4", "ep4", "p45"): { + {"4.4.4.6:45", false}, + }, + }, + expectedResult: map[proxy.ServicePortName][]*endpointsInfo{ + makeServicePortName("ns1", "ep1", "p11"): { + {"1.1.1.1:11", false}, + {"1.1.1.11:11", false}, + }, + makeServicePortName("ns1", "ep1", "p12"): { + {"1.1.1.2:12", false}, + }, + makeServicePortName("ns1", "ep1", "p122"): { + {"1.1.1.2:122", false}, + }, + makeServicePortName("ns3", "ep3", "p33"): { + {"3.3.3.3:33", false}, + }, + makeServicePortName("ns4", "ep4", "p44"): { + {"4.4.4.4:44", false}, + }, + }, + expectedStale: []endpointServicePair{{ + endpoint: "2.2.2.2:22", + servicePortName: makeServicePortName("ns2", "ep2", "p22"), + }, { + endpoint: "2.2.2.22:22", + servicePortName: makeServicePortName("ns2", "ep2", "p22"), + }, { + endpoint: "2.2.2.3:23", + servicePortName: makeServicePortName("ns2", "ep2", "p23"), + }, { + endpoint: "4.4.4.5:44", + servicePortName: makeServicePortName("ns4", "ep4", "p44"), + }, { + endpoint: "4.4.4.6:45", + servicePortName: makeServicePortName("ns4", "ep4", "p45"), + }}, + }} + + for tci, tc := range testCases { + newMap, stale := updateEndpoints(tc.newEndpoints, tc.oldEndpoints, "host", func(types.NamespacedName, []hostPortInfo) {}) + if len(newMap) != len(tc.expectedResult) { + t.Errorf("[%d] expected %d results, got %d: %v", tci, len(tc.expectedResult), len(newMap), newMap) + } + for x := range tc.expectedResult { + if len(newMap[x]) != len(tc.expectedResult[x]) { + t.Errorf("[%d] expected %d endpoints for %v, got %d", tci, len(tc.expectedResult[x]), x, len(newMap[x])) + } else { + for i := range tc.expectedResult[x] { + if *(newMap[x][i]) != *(tc.expectedResult[x][i]) { + t.Errorf("[%d] expected new[%v][%d] to be %v, got %v", tci, x, i, tc.expectedResult[x][i], newMap[x][i]) + } + } + } + } + if len(stale) != len(tc.expectedStale) { + t.Errorf("[%d] expected %d stale, got %d: %v", tci, len(tc.expectedStale), len(stale), stale) + } + for _, x := range tc.expectedStale { + if stale[x] != true { + t.Errorf("[%d] expected stale[%v], but didn't find it: %v", tci, x, stale) + } + } + } +} + // TODO(thockin): add *more* tests for syncProxyRules() or break it down further and test the pieces.