istio.io/istio@v0.0.0-20240520182934-d79c90f27776/pilot/pkg/status/distribution/reporter_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 distribution 16 17 import ( 18 "testing" 19 "time" 20 21 . "github.com/onsi/gomega" 22 "k8s.io/utils/clock" 23 24 "istio.io/istio/pilot/pkg/status" 25 "istio.io/istio/pilot/pkg/xds" 26 "istio.io/istio/pkg/config" 27 "istio.io/istio/pkg/config/schema/collections" 28 "istio.io/istio/pkg/ledger" 29 "istio.io/istio/pkg/util/sets" 30 ) 31 32 func TestStatusMaps(t *testing.T) { 33 r := initReporterWithoutStarting() 34 typ := "" 35 r.processEvent("conA", typ, "a") 36 r.processEvent("conB", typ, "a") 37 r.processEvent("conC", typ, "c") 38 r.processEvent("conD", typ, "d") 39 RegisterTestingT(t) 40 x := struct{}{} 41 Expect(r.status).To(Equal(map[string]string{"conA~": "a", "conB~": "a", "conC~": "c", "conD~": "d"})) 42 Expect(r.reverseStatus).To(Equal(map[string]sets.String{"a": {"conA~": x, "conB~": x}, "c": {"conC~": x}, "d": {"conD~": x}})) 43 r.processEvent("conA", typ, "d") 44 Expect(r.status).To(Equal(map[string]string{"conA~": "d", "conB~": "a", "conC~": "c", "conD~": "d"})) 45 Expect(r.reverseStatus).To(Equal(map[string]sets.String{"a": {"conB~": x}, "c": {"conC~": x}, "d": {"conD~": x, "conA~": x}})) 46 r.RegisterDisconnect("conA", sets.New[xds.EventType](typ)) 47 Expect(r.status).To(Equal(map[string]string{"conB~": "a", "conC~": "c", "conD~": "d"})) 48 Expect(r.reverseStatus).To(Equal(map[string]sets.String{"a": {"conB~": x}, "c": {"conC~": x}, "d": {"conD~": x}})) 49 } 50 51 func initReporterWithoutStarting() (out Reporter) { 52 out.PodName = "tespod" 53 out.inProgressResources = map[string]*inProgressEntry{} 54 out.client = nil // TODO 55 out.clock = clock.RealClock{} // TODO 56 out.UpdateInterval = 300 * time.Millisecond 57 out.cm = nil // TODO 58 out.reverseStatus = make(map[string]sets.String) 59 out.status = make(map[string]string) 60 return 61 } 62 63 func TestBuildReport(t *testing.T) { 64 RegisterTestingT(t) 65 r := initReporterWithoutStarting() 66 r.ledger = ledger.Make(time.Minute) 67 resources := []*config.Config{ 68 { 69 Meta: config.Meta{ 70 Namespace: "default", 71 Name: "foo", 72 ResourceVersion: "1", 73 }, 74 }, 75 { 76 Meta: config.Meta{ 77 Namespace: "default", 78 Name: "bar", 79 ResourceVersion: "1", 80 }, 81 }, 82 { 83 Meta: config.Meta{ 84 Namespace: "alternate", 85 Name: "boo", 86 ResourceVersion: "1", 87 }, 88 }, 89 } 90 // cast our model.Configs to Resource because these types aren't compatible 91 var myResources []status.Resource 92 col := collections.VirtualService 93 for _, res := range resources { 94 // Set Group Version and GroupVersionKind to real world values from VS 95 res.GroupVersionKind = col.GroupVersionKind() 96 myResources = append(myResources, status.ResourceFromModelConfig(*res)) 97 // Add each resource to our ledger for tracking history 98 // mark each of our resources as in flight so they are included in the report. 99 r.AddInProgressResource(*res) 100 } 101 firstNoncePrefix := r.ledger.RootHash() 102 connections := []string{ 103 "conA", "conB", "conC", 104 } 105 // mark each fake connection as having acked version 1 of all resources 106 for _, con := range connections { 107 r.processEvent(con, "", firstNoncePrefix) 108 } 109 // modify one resource to version 2 110 resources[1].Generation = int64(2) 111 myResources[1].Generation = "2" 112 // notify the ledger of the new version 113 r.AddInProgressResource(*resources[1]) 114 // mark only one connection as having acked version 2 115 r.processEvent(connections[1], "", r.ledger.RootHash()) 116 // mark one connection as having disconnected. 117 r.RegisterDisconnect(connections[2], sets.New[xds.EventType]("")) 118 // build a report, which should have only two dataplanes, with 50% acking v2 of config 119 rpt, prunes := r.buildReport() 120 r.removeCompletedResource(prunes) 121 Expect(rpt.DataPlaneCount).To(Equal(2)) 122 Expect(rpt.InProgressResources).To(Equal(map[string]int{ 123 myResources[0].String(): 2, 124 myResources[1].String(): 1, 125 myResources[2].String(): 2, 126 })) 127 Expect(r.inProgressResources).NotTo(ContainElement(resources[0])) 128 }