istio.io/istio@v0.0.0-20240520182934-d79c90f27776/pilot/pkg/networking/core/route/route_cache_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 route 16 17 import ( 18 "reflect" 19 "testing" 20 "time" 21 22 discovery "github.com/envoyproxy/go-control-plane/envoy/service/discovery/v3" 23 24 networking "istio.io/api/networking/v1alpha3" 25 "istio.io/istio/pilot/pkg/model" 26 "istio.io/istio/pkg/config" 27 "istio.io/istio/pkg/config/constants" 28 "istio.io/istio/pkg/config/schema/kind" 29 "istio.io/istio/pkg/util/sets" 30 ) 31 32 func TestClearRDSCacheOnDelegateUpdate(t *testing.T) { 33 xdsCache := model.NewXdsCache() 34 // root virtual service 35 root := config.Config{ 36 Meta: config.Meta{Name: "root", Namespace: "default"}, 37 Spec: &networking.VirtualService{ 38 Http: []*networking.HTTPRoute{ 39 { 40 Name: "route", 41 Delegate: &networking.Delegate{ 42 Namespace: "default", 43 Name: "delegate", 44 }, 45 }, 46 }, 47 }, 48 } 49 // delegate virtual service 50 delegate := model.ConfigKey{Kind: kind.VirtualService, Name: "delegate", Namespace: "default"} 51 // rds cache entry 52 entry := Cache{ 53 VirtualServices: []config.Config{root}, 54 DelegateVirtualServices: []model.ConfigHash{delegate.HashCode()}, 55 ListenerPort: 8080, 56 } 57 resource := &discovery.Resource{Name: "bar"} 58 59 // add resource to cache 60 xdsCache.Add(&entry, &model.PushRequest{Start: time.Now()}, resource) 61 if got := xdsCache.Get(&entry); got == nil || !reflect.DeepEqual(got, resource) { 62 t.Fatalf("rds cache was not updated") 63 } 64 65 // clear cache when delegate virtual service is updated 66 // this func is called by `dropCacheForRequest` in `initPushContext` 67 xdsCache.Clear(sets.New(delegate)) 68 if got := xdsCache.Get(&entry); got != nil { 69 t.Fatalf("rds cache was not cleared") 70 } 71 72 // add resource to cache 73 xdsCache.Add(&entry, &model.PushRequest{Start: time.Now()}, resource) 74 irrelevantDelegate := model.ConfigKey{Kind: kind.VirtualService, Name: "foo", Namespace: "default"} 75 76 // don't clear cache when irrelevant delegate virtual service is updated 77 xdsCache.Clear(sets.New(irrelevantDelegate)) 78 if got := xdsCache.Get(&entry); got == nil || !reflect.DeepEqual(got, resource) { 79 t.Fatalf("rds cache was cleared by irrelevant delegate virtual service update") 80 } 81 } 82 83 func TestDependentConfigs(t *testing.T) { 84 tests := []struct { 85 name string 86 r Cache 87 want []model.ConfigHash 88 }{ 89 { 90 name: "no internal vs", 91 r: Cache{ 92 VirtualServices: []config.Config{ 93 { 94 Meta: config.Meta{ 95 Name: "foo", 96 Namespace: "default", 97 }, 98 }, 99 }, 100 }, 101 want: []model.ConfigHash{ 102 model.ConfigKey{ 103 Kind: kind.VirtualService, 104 Name: "foo", 105 Namespace: "default", 106 }.HashCode(), 107 }, 108 }, 109 { 110 name: "single parent", 111 r: Cache{ 112 VirtualServices: []config.Config{ 113 { 114 Meta: config.Meta{ 115 Name: "foo-0-istio-autogenerated-k8s-gateway", 116 Namespace: "default", 117 Annotations: map[string]string{ 118 constants.InternalRouteSemantics: constants.RouteSemanticsGateway, 119 constants.InternalParentNames: "HTTPRoute/foo.default", 120 }, 121 }, 122 }, 123 }, 124 }, 125 want: []model.ConfigHash{ 126 model.ConfigKey{ 127 Kind: kind.HTTPRoute, 128 Name: "foo", 129 Namespace: "default", 130 }.HashCode(), 131 }, 132 }, 133 { 134 name: "multiple parents", 135 r: Cache{ 136 VirtualServices: []config.Config{ 137 { 138 Meta: config.Meta{ 139 Name: "foo-1-istio-autogenerated-k8s-gateway", 140 Namespace: "default", 141 Annotations: map[string]string{ 142 constants.InternalRouteSemantics: constants.RouteSemanticsGateway, 143 constants.InternalParentNames: "HTTPRoute/foo.default,HTTPRoute/bar.default", 144 }, 145 }, 146 }, 147 }, 148 }, 149 want: []model.ConfigHash{ 150 model.ConfigKey{ 151 Kind: kind.HTTPRoute, 152 Name: "foo", 153 Namespace: "default", 154 }.HashCode(), 155 model.ConfigKey{ 156 Kind: kind.HTTPRoute, 157 Name: "bar", 158 Namespace: "default", 159 }.HashCode(), 160 }, 161 }, 162 { 163 name: "mixed", 164 r: Cache{ 165 VirtualServices: []config.Config{ 166 { 167 Meta: config.Meta{ 168 Name: "foo", 169 Namespace: "default", 170 }, 171 }, 172 { 173 Meta: config.Meta{ 174 Name: "bar-0-istio-autogenerated-k8s-gateway", 175 Namespace: "default", 176 Annotations: map[string]string{ 177 constants.InternalRouteSemantics: constants.RouteSemanticsGateway, 178 constants.InternalParentNames: "HTTPRoute/bar.default,HTTPRoute/baz.default", 179 }, 180 }, 181 }, 182 }, 183 }, 184 want: []model.ConfigHash{ 185 model.ConfigKey{ 186 Kind: kind.VirtualService, 187 Name: "foo", 188 Namespace: "default", 189 }.HashCode(), 190 model.ConfigKey{ 191 Kind: kind.HTTPRoute, 192 Name: "bar", 193 Namespace: "default", 194 }.HashCode(), 195 model.ConfigKey{ 196 Kind: kind.HTTPRoute, 197 Name: "baz", 198 Namespace: "default", 199 }.HashCode(), 200 }, 201 }, 202 } 203 for _, tt := range tests { 204 t.Run(tt.name, func(t *testing.T) { 205 if got := tt.r.DependentConfigs(); !reflect.DeepEqual(got, tt.want) { 206 t.Errorf("DependentConfigs got %v, want %v", got, tt.want) 207 } 208 }) 209 } 210 } 211 212 func TestExtractNamespaceForKubernetesService(t *testing.T) { 213 tests := []struct { 214 hostname string 215 want string 216 }{ 217 { 218 "foo.ns.svc.cluster.local", 219 "ns", 220 }, 221 { 222 "foo.svc.cluster.local", 223 "", 224 }, 225 { 226 "svc.ns.svc.svc.svc", 227 "ns", 228 }, 229 { 230 ".svc.", 231 "", 232 }, 233 { 234 "..svc.", 235 "", 236 }, 237 { 238 "x.svc.", 239 "", 240 }, 241 } 242 for _, tt := range tests { 243 t.Run(tt.hostname, func(t *testing.T) { 244 got, err := extractNamespaceForKubernetesService(tt.hostname) 245 if (err != nil) != (tt.want == "") { 246 t.Fatalf("unexpected error = %v", err) 247 } 248 if got != tt.want { 249 t.Fatalf("got = %v, want %v", got, tt.want) 250 } 251 }) 252 } 253 }