snapshot of https://github.com/grpc/grpc-go.git (master, 2026-09-15; blobs > 131072B omitted)
Some checks failed
codecov / upload (push) Failing after 13m59s
CodeQL / Analyze (push) Failing after 1s
govulncheck / govulncheck (.) (push) Failing after 1s
govulncheck / govulncheck (./cmd/protoc-gen-go-grpc) (push) Failing after 1s
govulncheck / govulncheck (./gcp/observability) (push) Failing after 1s
govulncheck / govulncheck (./security/advancedtls) (push) Failing after 1s
govulncheck / govulncheck (./stats/opencensus) (push) Failing after 1s
Testing / tests (arm, latest) (push) Waiting to run
Testing / vet-proto (push) Failing after 1s
Testing / extras (latest) (push) Failing after 1s
Testing / static checks (latest-1) (push) Failing after 1s
Testing / tests (-race, latest) (push) Failing after 1s
Testing / tests (i386, latest) (push) Failing after 1s
Testing / tests (latest) (push) Failing after 1s
Testing / tests (latest-1) (push) Failing after 1s
Lock Threads / lock (push) Failing after 1s
Stale bot / stale (push) Failing after 1s
Some checks failed
codecov / upload (push) Failing after 13m59s
CodeQL / Analyze (push) Failing after 1s
govulncheck / govulncheck (.) (push) Failing after 1s
govulncheck / govulncheck (./cmd/protoc-gen-go-grpc) (push) Failing after 1s
govulncheck / govulncheck (./gcp/observability) (push) Failing after 1s
govulncheck / govulncheck (./security/advancedtls) (push) Failing after 1s
govulncheck / govulncheck (./stats/opencensus) (push) Failing after 1s
Testing / tests (arm, latest) (push) Waiting to run
Testing / vet-proto (push) Failing after 1s
Testing / extras (latest) (push) Failing after 1s
Testing / static checks (latest-1) (push) Failing after 1s
Testing / tests (-race, latest) (push) Failing after 1s
Testing / tests (i386, latest) (push) Failing after 1s
Testing / tests (latest) (push) Failing after 1s
Testing / tests (latest-1) (push) Failing after 1s
Lock Threads / lock (push) Failing after 1s
Stale bot / stale (push) Failing after 1s
This commit is contained in:
324
internal/xds/xdsclient/tests/federation_watchers_test.go
Normal file
324
internal/xds/xdsclient/tests/federation_watchers_test.go
Normal file
@@ -0,0 +1,324 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2021 gRPC 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 xdsclient_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"google.golang.org/grpc/internal/testutils/xds/e2e"
|
||||
"google.golang.org/grpc/internal/xds/bootstrap"
|
||||
"google.golang.org/grpc/internal/xds/clients"
|
||||
"google.golang.org/grpc/internal/xds/xdsclient"
|
||||
"google.golang.org/grpc/internal/xds/xdsclient/xdsresource"
|
||||
"google.golang.org/grpc/resolver"
|
||||
|
||||
v3clusterpb "github.com/envoyproxy/go-control-plane/envoy/config/cluster/v3"
|
||||
v3endpointpb "github.com/envoyproxy/go-control-plane/envoy/config/endpoint/v3"
|
||||
v3listenerpb "github.com/envoyproxy/go-control-plane/envoy/config/listener/v3"
|
||||
v3routepb "github.com/envoyproxy/go-control-plane/envoy/config/route/v3"
|
||||
)
|
||||
|
||||
const testNonDefaultAuthority = "non-default-authority"
|
||||
|
||||
// setupForFederationWatchersTest spins up two management servers, one for the
|
||||
// default (empty) authority and another for a non-default authority.
|
||||
//
|
||||
// Returns the management server associated with the non-default authority, the
|
||||
// nodeID to use, and the xDS client.
|
||||
func setupForFederationWatchersTest(t *testing.T) (*e2e.ManagementServer, string, xdsclient.XDSClient) {
|
||||
// Start a management server as the default authority.
|
||||
serverDefaultAuthority := e2e.StartManagementServer(t, e2e.ManagementServerOptions{})
|
||||
|
||||
// Start another management server as the other authority.
|
||||
serverNonDefaultAuthority := e2e.StartManagementServer(t, e2e.ManagementServerOptions{})
|
||||
|
||||
nodeID := uuid.New().String()
|
||||
bootstrapContents, err := bootstrap.NewContentsForTesting(bootstrap.ConfigOptionsForTesting{
|
||||
Servers: []byte(fmt.Sprintf(`[{
|
||||
"server_uri": %q,
|
||||
"channel_creds": [{"type": "insecure"}]
|
||||
}]`, serverDefaultAuthority.Address)),
|
||||
Node: []byte(fmt.Sprintf(`{"id": "%s"}`, nodeID)),
|
||||
Authorities: map[string]json.RawMessage{
|
||||
testNonDefaultAuthority: []byte(fmt.Sprintf(`{
|
||||
"xds_servers": [{
|
||||
"server_uri": %q,
|
||||
"channel_creds": [{"type": "insecure"}]
|
||||
}]}`, serverNonDefaultAuthority.Address)),
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create bootstrap configuration: %v", err)
|
||||
}
|
||||
// Create an xDS client with the above bootstrap contents.
|
||||
config, err := bootstrap.NewConfigFromContents(bootstrapContents)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse bootstrap contents: %s, %v", string(bootstrapContents), err)
|
||||
}
|
||||
pool := xdsclient.NewPool(config)
|
||||
client, close, err := pool.NewClientForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create xDS client: %v", err)
|
||||
}
|
||||
t.Cleanup(close)
|
||||
return serverNonDefaultAuthority, nodeID, client
|
||||
}
|
||||
|
||||
// TestFederation_ListenerResourceContextParamOrder covers the case of watching
|
||||
// a Listener resource with the new style resource name and context parameters.
|
||||
// The test registers watches for two resources which differ only in the order
|
||||
// of context parameters in their URI. The server is configured to respond with
|
||||
// a single resource with canonicalized context parameters. The test verifies
|
||||
// that both watchers are notified.
|
||||
func (s) TestFederation_ListenerResourceContextParamOrder(t *testing.T) {
|
||||
serverNonDefaultAuthority, nodeID, client := setupForFederationWatchersTest(t)
|
||||
|
||||
var (
|
||||
// Two resource names only differ in context parameter order.
|
||||
resourceName1 = fmt.Sprintf("xdstp://%s/envoy.config.listener.v3.Listener/xdsclient-test-lds-resource?a=1&b=2", testNonDefaultAuthority)
|
||||
resourceName2 = fmt.Sprintf("xdstp://%s/envoy.config.listener.v3.Listener/xdsclient-test-lds-resource?b=2&a=1", testNonDefaultAuthority)
|
||||
)
|
||||
|
||||
// Register two watches for listener resources with the same query string,
|
||||
// but context parameters in different order.
|
||||
lw1 := newListenerWatcher()
|
||||
ldsCancel1 := xdsresource.WatchListener(client, resourceName1, lw1)
|
||||
defer ldsCancel1()
|
||||
lw2 := newListenerWatcher()
|
||||
ldsCancel2 := xdsresource.WatchListener(client, resourceName2, lw2)
|
||||
defer ldsCancel2()
|
||||
|
||||
// Configure the management server for the non-default authority to return a
|
||||
// single listener resource, corresponding to the watches registered above.
|
||||
resources := e2e.UpdateOptions{
|
||||
NodeID: nodeID,
|
||||
Listeners: []*v3listenerpb.Listener{e2e.DefaultClientListener(resourceName1, "rds-resource")},
|
||||
SkipValidation: true,
|
||||
}
|
||||
ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
|
||||
defer cancel()
|
||||
if err := serverNonDefaultAuthority.Update(ctx, resources); err != nil {
|
||||
t.Fatalf("Failed to update management server with resources: %v, err: %v", resources, err)
|
||||
}
|
||||
|
||||
wantUpdate := listenerUpdateErrTuple{
|
||||
update: &xdsresource.ListenerUpdate{
|
||||
APIListener: &xdsresource.HTTPConnectionManagerConfig{
|
||||
RouteConfigName: "rds-resource",
|
||||
HTTPFilters: []xdsresource.HTTPFilter{{Name: "router"}},
|
||||
},
|
||||
},
|
||||
}
|
||||
// Verify the contents of the received update.
|
||||
if err := verifyListenerUpdate(ctx, lw1.updateCh, wantUpdate); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := verifyListenerUpdate(ctx, lw2.updateCh, wantUpdate); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// TestFederation_RouteConfigResourceContextParamOrder covers the case of
|
||||
// watching a RouteConfiguration resource with the new style resource name and
|
||||
// context parameters. The test registers watches for two resources which
|
||||
// differ only in the order of context parameters in their URI. The server is
|
||||
// configured to respond with a single resource with canonicalized context
|
||||
// parameters. The test verifies that both watchers are notified.
|
||||
func (s) TestFederation_RouteConfigResourceContextParamOrder(t *testing.T) {
|
||||
serverNonDefaultAuthority, nodeID, client := setupForFederationWatchersTest(t)
|
||||
|
||||
var (
|
||||
// Two resource names only differ in context parameter order.
|
||||
resourceName1 = fmt.Sprintf("xdstp://%s/envoy.config.route.v3.RouteConfiguration/xdsclient-test-rds-resource?a=1&b=2", testNonDefaultAuthority)
|
||||
resourceName2 = fmt.Sprintf("xdstp://%s/envoy.config.route.v3.RouteConfiguration/xdsclient-test-rds-resource?b=2&a=1", testNonDefaultAuthority)
|
||||
)
|
||||
|
||||
// Register two watches for route configuration resources with the same
|
||||
// query string, but context parameters in different order.
|
||||
rw1 := newRouteConfigWatcher()
|
||||
rdsCancel1 := xdsresource.WatchRouteConfig(client, resourceName1, rw1)
|
||||
defer rdsCancel1()
|
||||
rw2 := newRouteConfigWatcher()
|
||||
rdsCancel2 := xdsresource.WatchRouteConfig(client, resourceName2, rw2)
|
||||
defer rdsCancel2()
|
||||
|
||||
// Configure the management server for the non-default authority to return a
|
||||
// single route config resource, corresponding to the watches registered.
|
||||
resources := e2e.UpdateOptions{
|
||||
NodeID: nodeID,
|
||||
Routes: []*v3routepb.RouteConfiguration{e2e.DefaultRouteConfig(resourceName1, "listener-resource", "cluster-resource")},
|
||||
SkipValidation: true,
|
||||
}
|
||||
ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
|
||||
defer cancel()
|
||||
if err := serverNonDefaultAuthority.Update(ctx, resources); err != nil {
|
||||
t.Fatalf("Failed to update management server with resources: %v, err: %v", resources, err)
|
||||
}
|
||||
|
||||
wantUpdate := routeConfigUpdateErrTuple{
|
||||
update: xdsresource.RouteConfigUpdate{
|
||||
VirtualHosts: []*xdsresource.VirtualHost{
|
||||
{
|
||||
Domains: []string{"listener-resource"},
|
||||
Routes: []*xdsresource.Route{
|
||||
{
|
||||
Prefix: newStringP("/"),
|
||||
ActionType: xdsresource.RouteActionRoute,
|
||||
WeightedClusters: []xdsresource.WeightedCluster{{Name: "cluster-resource", Weight: 100}},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
// Verify the contents of the received update.
|
||||
if err := verifyRouteConfigUpdate(ctx, rw1.updateCh, wantUpdate); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := verifyRouteConfigUpdate(ctx, rw2.updateCh, wantUpdate); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// TestFederation_ClusterResourceContextParamOrder covers the case of watching a
|
||||
// Cluster resource with the new style resource name and context parameters.
|
||||
// The test registers watches for two resources which differ only in the order
|
||||
// of context parameters in their URI. The server is configured to respond with
|
||||
// a single resource with canonicalized context parameters. The test verifies
|
||||
// that both watchers are notified.
|
||||
func (s) TestFederation_ClusterResourceContextParamOrder(t *testing.T) {
|
||||
serverNonDefaultAuthority, nodeID, client := setupForFederationWatchersTest(t)
|
||||
|
||||
var (
|
||||
// Two resource names only differ in context parameter order.
|
||||
resourceName1 = fmt.Sprintf("xdstp://%s/envoy.config.cluster.v3.Cluster/xdsclient-test-cds-resource?a=1&b=2", testNonDefaultAuthority)
|
||||
resourceName2 = fmt.Sprintf("xdstp://%s/envoy.config.cluster.v3.Cluster/xdsclient-test-cds-resource?b=2&a=1", testNonDefaultAuthority)
|
||||
)
|
||||
|
||||
// Register two watches for cluster resources with the same query string,
|
||||
// but context parameters in different order.
|
||||
cw1 := newClusterWatcher()
|
||||
cdsCancel1 := xdsresource.WatchCluster(client, resourceName1, cw1)
|
||||
defer cdsCancel1()
|
||||
cw2 := newClusterWatcher()
|
||||
cdsCancel2 := xdsresource.WatchCluster(client, resourceName2, cw2)
|
||||
defer cdsCancel2()
|
||||
|
||||
// Configure the management server for the non-default authority to return a
|
||||
// single cluster resource, corresponding to the watches registered.
|
||||
resources := e2e.UpdateOptions{
|
||||
NodeID: nodeID,
|
||||
Clusters: []*v3clusterpb.Cluster{e2e.DefaultCluster(resourceName1, "eds-service-name", e2e.SecurityLevelNone)},
|
||||
SkipValidation: true,
|
||||
}
|
||||
ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
|
||||
defer cancel()
|
||||
if err := serverNonDefaultAuthority.Update(ctx, resources); err != nil {
|
||||
t.Fatalf("Failed to update management server with resources: %v, err: %v", resources, err)
|
||||
}
|
||||
|
||||
wantUpdate := clusterUpdateErrTuple{
|
||||
update: xdsresource.ClusterUpdate{
|
||||
ClusterName: "xdstp://non-default-authority/envoy.config.cluster.v3.Cluster/xdsclient-test-cds-resource?a=1&b=2",
|
||||
EDSServiceName: "eds-service-name",
|
||||
},
|
||||
}
|
||||
// Verify the contents of the received update.
|
||||
if err := verifyClusterUpdate(ctx, cw1.updateCh, wantUpdate); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := verifyClusterUpdate(ctx, cw2.updateCh, wantUpdate); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// TestFederation_EndpointsResourceContextParamOrder covers the case of watching
|
||||
// an Endpoints resource with the new style resource name and context parameters.
|
||||
// The test registers watches for two resources which differ only in the order
|
||||
// of context parameters in their URI. The server is configured to respond with
|
||||
// a single resource with canonicalized context parameters. The test verifies
|
||||
// that both watchers are notified.
|
||||
func (s) TestFederation_EndpointsResourceContextParamOrder(t *testing.T) {
|
||||
serverNonDefaultAuthority, nodeID, client := setupForFederationWatchersTest(t)
|
||||
|
||||
var (
|
||||
// Two resource names only differ in context parameter order.
|
||||
resourceName1 = fmt.Sprintf("xdstp://%s/envoy.config.endpoint.v3.ClusterLoadAssignment/xdsclient-test-eds-resource?a=1&b=2", testNonDefaultAuthority)
|
||||
resourceName2 = fmt.Sprintf("xdstp://%s/envoy.config.endpoint.v3.ClusterLoadAssignment/xdsclient-test-eds-resource?b=2&a=1", testNonDefaultAuthority)
|
||||
)
|
||||
|
||||
// Register two watches for endpoint resources with the same query string,
|
||||
// but context parameters in different order.
|
||||
ew1 := newEndpointsWatcher()
|
||||
edsCancel1 := xdsresource.WatchEndpoints(client, resourceName1, ew1)
|
||||
defer edsCancel1()
|
||||
ew2 := newEndpointsWatcher()
|
||||
edsCancel2 := xdsresource.WatchEndpoints(client, resourceName2, ew2)
|
||||
defer edsCancel2()
|
||||
|
||||
// Configure the management server for the non-default authority to return a
|
||||
// single endpoints resource, corresponding to the watches registered.
|
||||
resources := e2e.UpdateOptions{
|
||||
NodeID: nodeID,
|
||||
Endpoints: []*v3endpointpb.ClusterLoadAssignment{e2e.DefaultEndpoint(resourceName1, "localhost", []uint32{666})},
|
||||
SkipValidation: true,
|
||||
}
|
||||
ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
|
||||
defer cancel()
|
||||
if err := serverNonDefaultAuthority.Update(ctx, resources); err != nil {
|
||||
t.Fatalf("Failed to update management server with resources: %v, err: %v", resources, err)
|
||||
}
|
||||
|
||||
wantUpdate := endpointsUpdateErrTuple{
|
||||
update: xdsresource.EndpointsUpdate{
|
||||
Localities: []xdsresource.Locality{
|
||||
{
|
||||
Endpoints: []xdsresource.Endpoint{{
|
||||
ResolverEndpoint: resolver.Endpoint{
|
||||
Addresses: []resolver.Address{{Addr: "localhost:666"}},
|
||||
},
|
||||
Weight: 1,
|
||||
}},
|
||||
Weight: 1,
|
||||
ID: clients.Locality{
|
||||
Region: "region-1",
|
||||
Zone: "zone-1",
|
||||
SubZone: "subzone-1",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
// Verify the contents of the received update.
|
||||
if err := verifyEndpointsUpdate(ctx, ew1.updateCh, wantUpdate); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := verifyEndpointsUpdate(ctx, ew2.updateCh, wantUpdate); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func newStringP(s string) *string {
|
||||
return &s
|
||||
}
|
||||
Reference in New Issue
Block a user