github.com/hxx258456/ccgo@v0.0.5-0.20230213014102-48b35f46f66f/grpc/xds/internal/xdsclient/dump_test.go (about) 1 /* 2 * 3 * Copyright 2021 gRPC authors. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 */ 18 19 package xdsclient 20 21 import ( 22 "fmt" 23 "testing" 24 "time" 25 26 "github.com/google/go-cmp/cmp" 27 "github.com/google/go-cmp/cmp/cmpopts" 28 v3clusterpb "github.com/hxx258456/ccgo/go-control-plane/envoy/config/cluster/v3" 29 v3corepb "github.com/hxx258456/ccgo/go-control-plane/envoy/config/core/v3" 30 v3listenerpb "github.com/hxx258456/ccgo/go-control-plane/envoy/config/listener/v3" 31 v3routepb "github.com/hxx258456/ccgo/go-control-plane/envoy/config/route/v3" 32 v3httppb "github.com/hxx258456/ccgo/go-control-plane/envoy/extensions/filters/network/http_connection_manager/v3" 33 grpc "github.com/hxx258456/ccgo/grpc" 34 "github.com/hxx258456/ccgo/grpc/xds/internal/xdsclient/xdsresource" 35 "google.golang.org/protobuf/testing/protocmp" 36 "google.golang.org/protobuf/types/known/anypb" 37 "google.golang.org/protobuf/types/known/durationpb" 38 39 "github.com/hxx258456/ccgo/grpc/credentials/insecure" 40 "github.com/hxx258456/ccgo/grpc/internal/testutils" 41 xdstestutils "github.com/hxx258456/ccgo/grpc/xds/internal/testutils" 42 "github.com/hxx258456/ccgo/grpc/xds/internal/xdsclient/bootstrap" 43 ) 44 45 func (s) TestLDSConfigDump(t *testing.T) { 46 const testVersion = "test-version-lds" 47 var ( 48 ldsTargets = []string{"lds.target.good:0000", "lds.target.good:1111"} 49 routeConfigNames = []string{"route-config-0", "route-config-1"} 50 listenerRaws = make(map[string]*anypb.Any, len(ldsTargets)) 51 ) 52 53 for i := range ldsTargets { 54 listenersT := &v3listenerpb.Listener{ 55 Name: ldsTargets[i], 56 ApiListener: &v3listenerpb.ApiListener{ 57 ApiListener: testutils.MarshalAny(&v3httppb.HttpConnectionManager{ 58 RouteSpecifier: &v3httppb.HttpConnectionManager_Rds{ 59 Rds: &v3httppb.Rds{ 60 ConfigSource: &v3corepb.ConfigSource{ 61 ConfigSourceSpecifier: &v3corepb.ConfigSource_Ads{Ads: &v3corepb.AggregatedConfigSource{}}, 62 }, 63 RouteConfigName: routeConfigNames[i], 64 }, 65 }, 66 CommonHttpProtocolOptions: &v3corepb.HttpProtocolOptions{ 67 MaxStreamDuration: durationpb.New(time.Second), 68 }, 69 }), 70 }, 71 } 72 listenerRaws[ldsTargets[i]] = testutils.MarshalAny(listenersT) 73 } 74 75 client, err := NewWithConfigForTesting(&bootstrap.Config{ 76 XDSServer: &bootstrap.ServerConfig{ 77 ServerURI: testXDSServer, 78 Creds: grpc.WithTransportCredentials(insecure.NewCredentials()), 79 NodeProto: xdstestutils.EmptyNodeProtoV2, 80 }, 81 }, defaultTestWatchExpiryTimeout) 82 if err != nil { 83 t.Fatalf("failed to create client: %v", err) 84 } 85 defer client.Close() 86 87 // Expected unknown. 88 if err := compareDump(client.DumpLDS, map[string]xdsresource.UpdateWithMD{}); err != nil { 89 t.Fatalf(err.Error()) 90 } 91 92 wantRequested := make(map[string]xdsresource.UpdateWithMD) 93 for _, n := range ldsTargets { 94 cancel := client.WatchListener(n, func(update xdsresource.ListenerUpdate, err error) {}) 95 defer cancel() 96 wantRequested[n] = xdsresource.UpdateWithMD{MD: xdsresource.UpdateMetadata{Status: xdsresource.ServiceStatusRequested}} 97 } 98 // Expected requested. 99 if err := compareDump(client.DumpLDS, wantRequested); err != nil { 100 t.Fatalf(err.Error()) 101 } 102 103 update0 := make(map[string]xdsresource.ListenerUpdateErrTuple) 104 want0 := make(map[string]xdsresource.UpdateWithMD) 105 for n, r := range listenerRaws { 106 update0[n] = xdsresource.ListenerUpdateErrTuple{Update: xdsresource.ListenerUpdate{Raw: r}} 107 want0[n] = xdsresource.UpdateWithMD{ 108 MD: xdsresource.UpdateMetadata{Status: xdsresource.ServiceStatusACKed, Version: testVersion}, 109 Raw: r, 110 } 111 } 112 updateHandler := findPubsubForTest(t, client.(*clientRefCounted).clientImpl, "") 113 updateHandler.NewListeners(update0, xdsresource.UpdateMetadata{Status: xdsresource.ServiceStatusACKed, Version: testVersion}) 114 115 // Expect ACK. 116 if err := compareDump(client.DumpLDS, want0); err != nil { 117 t.Fatalf(err.Error()) 118 } 119 120 const nackVersion = "lds-version-nack" 121 var nackErr = fmt.Errorf("lds nack error") 122 updateHandler.NewListeners( 123 map[string]xdsresource.ListenerUpdateErrTuple{ 124 ldsTargets[0]: {Err: nackErr}, 125 ldsTargets[1]: {Update: xdsresource.ListenerUpdate{Raw: listenerRaws[ldsTargets[1]]}}, 126 }, 127 xdsresource.UpdateMetadata{ 128 Status: xdsresource.ServiceStatusNACKed, 129 ErrState: &xdsresource.UpdateErrorMetadata{ 130 Version: nackVersion, 131 Err: nackErr, 132 }, 133 }, 134 ) 135 136 // Expect NACK for [0], but old ACK for [1]. 137 wantDump := make(map[string]xdsresource.UpdateWithMD) 138 // Though resource 0 was NACKed, the dump should show the previous ACKed raw 139 // message, as well as the NACK error. 140 wantDump[ldsTargets[0]] = xdsresource.UpdateWithMD{ 141 MD: xdsresource.UpdateMetadata{ 142 Status: xdsresource.ServiceStatusNACKed, 143 Version: testVersion, 144 ErrState: &xdsresource.UpdateErrorMetadata{ 145 Version: nackVersion, 146 Err: nackErr, 147 }, 148 }, 149 Raw: listenerRaws[ldsTargets[0]], 150 } 151 152 wantDump[ldsTargets[1]] = xdsresource.UpdateWithMD{ 153 MD: xdsresource.UpdateMetadata{Status: xdsresource.ServiceStatusACKed, Version: nackVersion}, 154 Raw: listenerRaws[ldsTargets[1]], 155 } 156 if err := compareDump(client.DumpLDS, wantDump); err != nil { 157 t.Fatalf(err.Error()) 158 } 159 } 160 161 func (s) TestRDSConfigDump(t *testing.T) { 162 const testVersion = "test-version-rds" 163 var ( 164 listenerNames = []string{"lds.target.good:0000", "lds.target.good:1111"} 165 rdsTargets = []string{"route-config-0", "route-config-1"} 166 clusterNames = []string{"cluster-0", "cluster-1"} 167 routeRaws = make(map[string]*anypb.Any, len(rdsTargets)) 168 ) 169 170 for i := range rdsTargets { 171 routeConfigT := &v3routepb.RouteConfiguration{ 172 Name: rdsTargets[i], 173 VirtualHosts: []*v3routepb.VirtualHost{ 174 { 175 Domains: []string{listenerNames[i]}, 176 Routes: []*v3routepb.Route{{ 177 Match: &v3routepb.RouteMatch{PathSpecifier: &v3routepb.RouteMatch_Prefix{Prefix: ""}}, 178 Action: &v3routepb.Route_Route{ 179 Route: &v3routepb.RouteAction{ 180 ClusterSpecifier: &v3routepb.RouteAction_Cluster{Cluster: clusterNames[i]}, 181 }, 182 }, 183 }}, 184 }, 185 }, 186 } 187 188 routeRaws[rdsTargets[i]] = testutils.MarshalAny(routeConfigT) 189 } 190 191 client, err := NewWithConfigForTesting(&bootstrap.Config{ 192 XDSServer: &bootstrap.ServerConfig{ 193 ServerURI: testXDSServer, 194 Creds: grpc.WithTransportCredentials(insecure.NewCredentials()), 195 NodeProto: xdstestutils.EmptyNodeProtoV2, 196 }, 197 }, defaultTestWatchExpiryTimeout) 198 if err != nil { 199 t.Fatalf("failed to create client: %v", err) 200 } 201 defer client.Close() 202 203 // Expected unknown. 204 if err := compareDump(client.DumpRDS, map[string]xdsresource.UpdateWithMD{}); err != nil { 205 t.Fatalf(err.Error()) 206 } 207 208 wantRequested := make(map[string]xdsresource.UpdateWithMD) 209 for _, n := range rdsTargets { 210 cancel := client.WatchRouteConfig(n, func(update xdsresource.RouteConfigUpdate, err error) {}) 211 defer cancel() 212 wantRequested[n] = xdsresource.UpdateWithMD{MD: xdsresource.UpdateMetadata{Status: xdsresource.ServiceStatusRequested}} 213 } 214 // Expected requested. 215 if err := compareDump(client.DumpRDS, wantRequested); err != nil { 216 t.Fatalf(err.Error()) 217 } 218 219 update0 := make(map[string]xdsresource.RouteConfigUpdateErrTuple) 220 want0 := make(map[string]xdsresource.UpdateWithMD) 221 for n, r := range routeRaws { 222 update0[n] = xdsresource.RouteConfigUpdateErrTuple{Update: xdsresource.RouteConfigUpdate{Raw: r}} 223 want0[n] = xdsresource.UpdateWithMD{ 224 MD: xdsresource.UpdateMetadata{Status: xdsresource.ServiceStatusACKed, Version: testVersion}, 225 Raw: r, 226 } 227 } 228 updateHandler := findPubsubForTest(t, client.(*clientRefCounted).clientImpl, "") 229 updateHandler.NewRouteConfigs(update0, xdsresource.UpdateMetadata{Status: xdsresource.ServiceStatusACKed, Version: testVersion}) 230 231 // Expect ACK. 232 if err := compareDump(client.DumpRDS, want0); err != nil { 233 t.Fatalf(err.Error()) 234 } 235 236 const nackVersion = "rds-version-nack" 237 var nackErr = fmt.Errorf("rds nack error") 238 updateHandler.NewRouteConfigs( 239 map[string]xdsresource.RouteConfigUpdateErrTuple{ 240 rdsTargets[0]: {Err: nackErr}, 241 rdsTargets[1]: {Update: xdsresource.RouteConfigUpdate{Raw: routeRaws[rdsTargets[1]]}}, 242 }, 243 xdsresource.UpdateMetadata{ 244 Status: xdsresource.ServiceStatusNACKed, 245 ErrState: &xdsresource.UpdateErrorMetadata{ 246 Version: nackVersion, 247 Err: nackErr, 248 }, 249 }, 250 ) 251 252 // Expect NACK for [0], but old ACK for [1]. 253 wantDump := make(map[string]xdsresource.UpdateWithMD) 254 // Though resource 0 was NACKed, the dump should show the previous ACKed raw 255 // message, as well as the NACK error. 256 wantDump[rdsTargets[0]] = xdsresource.UpdateWithMD{ 257 MD: xdsresource.UpdateMetadata{ 258 Status: xdsresource.ServiceStatusNACKed, 259 Version: testVersion, 260 ErrState: &xdsresource.UpdateErrorMetadata{ 261 Version: nackVersion, 262 Err: nackErr, 263 }, 264 }, 265 Raw: routeRaws[rdsTargets[0]], 266 } 267 wantDump[rdsTargets[1]] = xdsresource.UpdateWithMD{ 268 MD: xdsresource.UpdateMetadata{Status: xdsresource.ServiceStatusACKed, Version: nackVersion}, 269 Raw: routeRaws[rdsTargets[1]], 270 } 271 if err := compareDump(client.DumpRDS, wantDump); err != nil { 272 t.Fatalf(err.Error()) 273 } 274 } 275 276 func (s) TestCDSConfigDump(t *testing.T) { 277 const testVersion = "test-version-cds" 278 var ( 279 cdsTargets = []string{"cluster-0", "cluster-1"} 280 serviceNames = []string{"service-0", "service-1"} 281 clusterRaws = make(map[string]*anypb.Any, len(cdsTargets)) 282 ) 283 284 for i := range cdsTargets { 285 clusterT := &v3clusterpb.Cluster{ 286 Name: cdsTargets[i], 287 ClusterDiscoveryType: &v3clusterpb.Cluster_Type{Type: v3clusterpb.Cluster_EDS}, 288 EdsClusterConfig: &v3clusterpb.Cluster_EdsClusterConfig{ 289 EdsConfig: &v3corepb.ConfigSource{ 290 ConfigSourceSpecifier: &v3corepb.ConfigSource_Ads{ 291 Ads: &v3corepb.AggregatedConfigSource{}, 292 }, 293 }, 294 ServiceName: serviceNames[i], 295 }, 296 LbPolicy: v3clusterpb.Cluster_ROUND_ROBIN, 297 LrsServer: &v3corepb.ConfigSource{ 298 ConfigSourceSpecifier: &v3corepb.ConfigSource_Self{ 299 Self: &v3corepb.SelfConfigSource{}, 300 }, 301 }, 302 } 303 304 clusterRaws[cdsTargets[i]] = testutils.MarshalAny(clusterT) 305 } 306 307 client, err := NewWithConfigForTesting(&bootstrap.Config{ 308 XDSServer: &bootstrap.ServerConfig{ 309 ServerURI: testXDSServer, 310 Creds: grpc.WithTransportCredentials(insecure.NewCredentials()), 311 NodeProto: xdstestutils.EmptyNodeProtoV2, 312 }, 313 }, defaultTestWatchExpiryTimeout) 314 if err != nil { 315 t.Fatalf("failed to create client: %v", err) 316 } 317 defer client.Close() 318 319 // Expected unknown. 320 if err := compareDump(client.DumpCDS, map[string]xdsresource.UpdateWithMD{}); err != nil { 321 t.Fatalf(err.Error()) 322 } 323 324 wantRequested := make(map[string]xdsresource.UpdateWithMD) 325 for _, n := range cdsTargets { 326 cancel := client.WatchCluster(n, func(update xdsresource.ClusterUpdate, err error) {}) 327 defer cancel() 328 wantRequested[n] = xdsresource.UpdateWithMD{MD: xdsresource.UpdateMetadata{Status: xdsresource.ServiceStatusRequested}} 329 } 330 // Expected requested. 331 if err := compareDump(client.DumpCDS, wantRequested); err != nil { 332 t.Fatalf(err.Error()) 333 } 334 335 update0 := make(map[string]xdsresource.ClusterUpdateErrTuple) 336 want0 := make(map[string]xdsresource.UpdateWithMD) 337 for n, r := range clusterRaws { 338 update0[n] = xdsresource.ClusterUpdateErrTuple{Update: xdsresource.ClusterUpdate{Raw: r}} 339 want0[n] = xdsresource.UpdateWithMD{ 340 MD: xdsresource.UpdateMetadata{Status: xdsresource.ServiceStatusACKed, Version: testVersion}, 341 Raw: r, 342 } 343 } 344 updateHandler := findPubsubForTest(t, client.(*clientRefCounted).clientImpl, "") 345 updateHandler.NewClusters(update0, xdsresource.UpdateMetadata{Status: xdsresource.ServiceStatusACKed, Version: testVersion}) 346 347 // Expect ACK. 348 if err := compareDump(client.DumpCDS, want0); err != nil { 349 t.Fatalf(err.Error()) 350 } 351 352 const nackVersion = "cds-version-nack" 353 var nackErr = fmt.Errorf("cds nack error") 354 updateHandler.NewClusters( 355 map[string]xdsresource.ClusterUpdateErrTuple{ 356 cdsTargets[0]: {Err: nackErr}, 357 cdsTargets[1]: {Update: xdsresource.ClusterUpdate{Raw: clusterRaws[cdsTargets[1]]}}, 358 }, 359 xdsresource.UpdateMetadata{ 360 Status: xdsresource.ServiceStatusNACKed, 361 ErrState: &xdsresource.UpdateErrorMetadata{ 362 Version: nackVersion, 363 Err: nackErr, 364 }, 365 }, 366 ) 367 368 // Expect NACK for [0], but old ACK for [1]. 369 wantDump := make(map[string]xdsresource.UpdateWithMD) 370 // Though resource 0 was NACKed, the dump should show the previous ACKed raw 371 // message, as well as the NACK error. 372 wantDump[cdsTargets[0]] = xdsresource.UpdateWithMD{ 373 MD: xdsresource.UpdateMetadata{ 374 Status: xdsresource.ServiceStatusNACKed, 375 Version: testVersion, 376 ErrState: &xdsresource.UpdateErrorMetadata{ 377 Version: nackVersion, 378 Err: nackErr, 379 }, 380 }, 381 Raw: clusterRaws[cdsTargets[0]], 382 } 383 wantDump[cdsTargets[1]] = xdsresource.UpdateWithMD{ 384 MD: xdsresource.UpdateMetadata{Status: xdsresource.ServiceStatusACKed, Version: nackVersion}, 385 Raw: clusterRaws[cdsTargets[1]], 386 } 387 if err := compareDump(client.DumpCDS, wantDump); err != nil { 388 t.Fatalf(err.Error()) 389 } 390 } 391 392 func (s) TestEDSConfigDump(t *testing.T) { 393 const testVersion = "test-version-cds" 394 var ( 395 edsTargets = []string{"cluster-0", "cluster-1"} 396 localityNames = []string{"locality-0", "locality-1"} 397 addrs = []string{"addr0:123", "addr1:456"} 398 endpointRaws = make(map[string]*anypb.Any, len(edsTargets)) 399 ) 400 401 for i := range edsTargets { 402 clab0 := xdstestutils.NewClusterLoadAssignmentBuilder(edsTargets[i], nil) 403 clab0.AddLocality(localityNames[i], 1, 1, []string{addrs[i]}, nil) 404 claT := clab0.Build() 405 406 endpointRaws[edsTargets[i]] = testutils.MarshalAny(claT) 407 } 408 409 client, err := NewWithConfigForTesting(&bootstrap.Config{ 410 XDSServer: &bootstrap.ServerConfig{ 411 ServerURI: testXDSServer, 412 Creds: grpc.WithTransportCredentials(insecure.NewCredentials()), 413 NodeProto: xdstestutils.EmptyNodeProtoV2, 414 }, 415 }, defaultTestWatchExpiryTimeout) 416 if err != nil { 417 t.Fatalf("failed to create client: %v", err) 418 } 419 defer client.Close() 420 421 // Expected unknown. 422 if err := compareDump(client.DumpEDS, map[string]xdsresource.UpdateWithMD{}); err != nil { 423 t.Fatalf(err.Error()) 424 } 425 426 wantRequested := make(map[string]xdsresource.UpdateWithMD) 427 for _, n := range edsTargets { 428 cancel := client.WatchEndpoints(n, func(update xdsresource.EndpointsUpdate, err error) {}) 429 defer cancel() 430 wantRequested[n] = xdsresource.UpdateWithMD{MD: xdsresource.UpdateMetadata{Status: xdsresource.ServiceStatusRequested}} 431 } 432 // Expected requested. 433 if err := compareDump(client.DumpEDS, wantRequested); err != nil { 434 t.Fatalf(err.Error()) 435 } 436 437 update0 := make(map[string]xdsresource.EndpointsUpdateErrTuple) 438 want0 := make(map[string]xdsresource.UpdateWithMD) 439 for n, r := range endpointRaws { 440 update0[n] = xdsresource.EndpointsUpdateErrTuple{Update: xdsresource.EndpointsUpdate{Raw: r}} 441 want0[n] = xdsresource.UpdateWithMD{ 442 MD: xdsresource.UpdateMetadata{Status: xdsresource.ServiceStatusACKed, Version: testVersion}, 443 Raw: r, 444 } 445 } 446 updateHandler := findPubsubForTest(t, client.(*clientRefCounted).clientImpl, "") 447 updateHandler.NewEndpoints(update0, xdsresource.UpdateMetadata{Status: xdsresource.ServiceStatusACKed, Version: testVersion}) 448 449 // Expect ACK. 450 if err := compareDump(client.DumpEDS, want0); err != nil { 451 t.Fatalf(err.Error()) 452 } 453 454 const nackVersion = "eds-version-nack" 455 var nackErr = fmt.Errorf("eds nack error") 456 updateHandler.NewEndpoints( 457 map[string]xdsresource.EndpointsUpdateErrTuple{ 458 edsTargets[0]: {Err: nackErr}, 459 edsTargets[1]: {Update: xdsresource.EndpointsUpdate{Raw: endpointRaws[edsTargets[1]]}}, 460 }, 461 xdsresource.UpdateMetadata{ 462 Status: xdsresource.ServiceStatusNACKed, 463 ErrState: &xdsresource.UpdateErrorMetadata{ 464 Version: nackVersion, 465 Err: nackErr, 466 }, 467 }, 468 ) 469 470 // Expect NACK for [0], but old ACK for [1]. 471 wantDump := make(map[string]xdsresource.UpdateWithMD) 472 // Though resource 0 was NACKed, the dump should show the previous ACKed raw 473 // message, as well as the NACK error. 474 wantDump[edsTargets[0]] = xdsresource.UpdateWithMD{ 475 MD: xdsresource.UpdateMetadata{ 476 Status: xdsresource.ServiceStatusNACKed, 477 Version: testVersion, 478 ErrState: &xdsresource.UpdateErrorMetadata{ 479 Version: nackVersion, 480 Err: nackErr, 481 }, 482 }, 483 Raw: endpointRaws[edsTargets[0]], 484 } 485 wantDump[edsTargets[1]] = xdsresource.UpdateWithMD{ 486 MD: xdsresource.UpdateMetadata{Status: xdsresource.ServiceStatusACKed, Version: nackVersion}, 487 Raw: endpointRaws[edsTargets[1]], 488 } 489 if err := compareDump(client.DumpEDS, wantDump); err != nil { 490 t.Fatalf(err.Error()) 491 } 492 } 493 494 func compareDump(dumpFunc func() map[string]xdsresource.UpdateWithMD, wantDump interface{}) error { 495 dump := dumpFunc() 496 cmpOpts := cmp.Options{ 497 cmpopts.EquateEmpty(), 498 cmp.Comparer(func(a, b time.Time) bool { return true }), 499 cmp.Comparer(func(x, y error) bool { 500 if x == nil || y == nil { 501 return x == nil && y == nil 502 } 503 return x.Error() == y.Error() 504 }), 505 protocmp.Transform(), 506 } 507 if diff := cmp.Diff(dump, wantDump, cmpOpts); diff != "" { 508 return fmt.Errorf("Dump() returned unexpected dump, diff (-got +want): %s", diff) 509 } 510 return nil 511 }