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:
187
internal/xds/resolver/watch_service_test.go
Normal file
187
internal/xds/resolver/watch_service_test.go
Normal file
@@ -0,0 +1,187 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2020 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 resolver_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/envoyproxy/go-control-plane/pkg/wellknown"
|
||||
"github.com/google/uuid"
|
||||
"google.golang.org/grpc/internal/testutils"
|
||||
"google.golang.org/grpc/internal/testutils/xds/e2e"
|
||||
"google.golang.org/grpc/resolver"
|
||||
"google.golang.org/protobuf/types/known/wrapperspb"
|
||||
|
||||
v3listenerpb "github.com/envoyproxy/go-control-plane/envoy/config/listener/v3"
|
||||
v3routepb "github.com/envoyproxy/go-control-plane/envoy/config/route/v3"
|
||||
v3routerpb "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/http/router/v3"
|
||||
v3httppb "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/network/http_connection_manager/v3"
|
||||
)
|
||||
|
||||
// Tests the case where the listener resource starts pointing to a new route
|
||||
// configuration resource after the xDS resolver has successfully resolved the
|
||||
// service name and pushed an update on the channel. The test verifies that the
|
||||
// resolver stops requesting the old route configuration resource and requests
|
||||
// the new resource, and once successfully resolved, verifies that the update
|
||||
// from the resolver matches expected service config.
|
||||
func (s) TestServiceWatch_ListenerPointsToNewRouteConfiguration(t *testing.T) {
|
||||
// Spin up an xDS management server for the test.
|
||||
ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
|
||||
defer cancel()
|
||||
nodeID := uuid.New().String()
|
||||
mgmtServer, lisCh, routeCfgCh, bc := setupManagementServerForTest(t, nodeID)
|
||||
|
||||
// Configure resources on the management server.
|
||||
resources := e2e.DefaultClientResources(e2e.ResourceParams{
|
||||
DialTarget: defaultTestServiceName,
|
||||
NodeID: nodeID,
|
||||
Host: defaultTestHostname,
|
||||
Port: defaultTestPort[0],
|
||||
SecLevel: e2e.SecurityLevelNone,
|
||||
})
|
||||
if err := mgmtServer.Update(ctx, resources); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
stateCh, _, _ := buildResolverForTarget(t, resolver.Target{URL: *testutils.MustParseURL("xds:///" + defaultTestServiceName)}, bc)
|
||||
|
||||
// Verify initial update from the resolver.
|
||||
waitForResourceNames(ctx, t, lisCh, []string{defaultTestServiceName})
|
||||
waitForResourceNames(ctx, t, routeCfgCh, []string{resources.Routes[0].Name})
|
||||
verifyUpdateFromResolver(ctx, t, stateCh, wantServiceConfig(resources.Clusters[0].Name))
|
||||
|
||||
// Update the listener resource to point to a new route configuration name.
|
||||
// The old route configuration resource is left unchanged to prevent a race:
|
||||
// if it were removed immediately, the resolver might encounter a
|
||||
// "resource-not-found" error for the old route before the listener update
|
||||
// successfully transitions the client to the new route.
|
||||
newTestRouteConfigName := defaultTestRouteConfigName + "-new"
|
||||
resources.Listeners = []*v3listenerpb.Listener{e2e.DefaultClientListener(defaultTestServiceName, newTestRouteConfigName)}
|
||||
resources.SkipValidation = true
|
||||
mgmtServer.Update(ctx, resources)
|
||||
|
||||
// Verify that the new route configuration resource is requested.
|
||||
waitForResourceNames(ctx, t, routeCfgCh, []string{newTestRouteConfigName})
|
||||
|
||||
// Update the old route configuration resource by adding a new route.
|
||||
resources.Routes[0].VirtualHosts[0].Routes = append(resources.Routes[0].VirtualHosts[0].Routes, &v3routepb.Route{
|
||||
Match: &v3routepb.RouteMatch{
|
||||
PathSpecifier: &v3routepb.RouteMatch_Prefix{Prefix: "/foo/bar"},
|
||||
CaseSensitive: &wrapperspb.BoolValue{Value: false},
|
||||
},
|
||||
Action: &v3routepb.Route_Route{
|
||||
Route: &v3routepb.RouteAction{
|
||||
ClusterSpecifier: &v3routepb.RouteAction_Cluster{Cluster: "some-random-cluster"},
|
||||
},
|
||||
},
|
||||
})
|
||||
mgmtServer.Update(ctx, resources)
|
||||
|
||||
// Wait for no update from the resolver since the listener resource no
|
||||
// longer points to the old route resource and new route resource hasn't
|
||||
// been sent yet.
|
||||
verifyNoUpdateFromResolver(ctx, t, stateCh)
|
||||
|
||||
// Update the management server with the new route configuration resource.
|
||||
resources.Routes = append(resources.Routes, e2e.DefaultRouteConfig(newTestRouteConfigName, defaultTestServiceName, resources.Clusters[0].Name))
|
||||
configureResources(ctx, t, mgmtServer, nodeID, resources.Listeners, resources.Routes, nil, nil)
|
||||
|
||||
// Ensure update from the resolver.
|
||||
verifyUpdateFromResolver(ctx, t, stateCh, wantServiceConfig(resources.Clusters[0].Name))
|
||||
}
|
||||
|
||||
// Tests the case where the listener resource changes to contain an inline route
|
||||
// configuration and changes back to having a route configuration resource name.
|
||||
// Verifies that the expected xDS resource names are requested by the resolver
|
||||
// and that the update from the resolver matches expected service config.
|
||||
func (s) TestServiceWatch_ListenerPointsToInlineRouteConfiguration(t *testing.T) {
|
||||
// Spin up an xDS management server for the test.
|
||||
ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
|
||||
defer cancel()
|
||||
nodeID := uuid.New().String()
|
||||
mgmtServer, lisCh, routeCfgCh, bc := setupManagementServerForTest(t, nodeID)
|
||||
|
||||
// Configure resources on the management server.
|
||||
resources := e2e.DefaultClientResources(e2e.ResourceParams{
|
||||
DialTarget: defaultTestServiceName,
|
||||
NodeID: nodeID,
|
||||
Host: defaultTestHostname,
|
||||
Port: defaultTestPort[0],
|
||||
SecLevel: e2e.SecurityLevelNone,
|
||||
})
|
||||
if err := mgmtServer.Update(ctx, resources); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
stateCh, _, _ := buildResolverForTarget(t, resolver.Target{URL: *testutils.MustParseURL("xds:///" + defaultTestServiceName)}, bc)
|
||||
|
||||
// Verify initial update from the resolver.
|
||||
waitForResourceNames(ctx, t, lisCh, []string{defaultTestServiceName})
|
||||
waitForResourceNames(ctx, t, routeCfgCh, []string{resources.Routes[0].Name})
|
||||
verifyUpdateFromResolver(ctx, t, stateCh, wantServiceConfig(resources.Clusters[0].Name))
|
||||
|
||||
// Update listener to contain an inline route configuration.
|
||||
hcm := testutils.MarshalAny(t, &v3httppb.HttpConnectionManager{
|
||||
RouteSpecifier: &v3httppb.HttpConnectionManager_RouteConfig{
|
||||
RouteConfig: &v3routepb.RouteConfiguration{
|
||||
Name: resources.Routes[0].Name,
|
||||
VirtualHosts: []*v3routepb.VirtualHost{{
|
||||
Domains: []string{defaultTestServiceName},
|
||||
Routes: []*v3routepb.Route{{
|
||||
Match: &v3routepb.RouteMatch{
|
||||
PathSpecifier: &v3routepb.RouteMatch_Prefix{Prefix: "/"},
|
||||
},
|
||||
Action: &v3routepb.Route_Route{
|
||||
Route: &v3routepb.RouteAction{
|
||||
ClusterSpecifier: &v3routepb.RouteAction_Cluster{Cluster: resources.Clusters[0].Name},
|
||||
},
|
||||
},
|
||||
}},
|
||||
}},
|
||||
},
|
||||
},
|
||||
HttpFilters: []*v3httppb.HttpFilter{e2e.HTTPFilter("router", &v3routerpb.Router{})},
|
||||
})
|
||||
resources.Listeners = []*v3listenerpb.Listener{{
|
||||
Name: defaultTestServiceName,
|
||||
ApiListener: &v3listenerpb.ApiListener{ApiListener: hcm},
|
||||
FilterChains: []*v3listenerpb.FilterChain{{
|
||||
Name: "filter-chain-name",
|
||||
Filters: []*v3listenerpb.Filter{{
|
||||
Name: wellknown.HTTPConnectionManager,
|
||||
ConfigType: &v3listenerpb.Filter_TypedConfig{TypedConfig: hcm},
|
||||
}},
|
||||
}},
|
||||
}}
|
||||
configureResources(ctx, t, mgmtServer, nodeID, resources.Listeners, nil, nil, nil)
|
||||
|
||||
// Verify that the old route configuration is not requested anymore.
|
||||
waitForResourceNames(ctx, t, routeCfgCh, []string{})
|
||||
verifyUpdateFromResolver(ctx, t, stateCh, wantServiceConfig(resources.Clusters[0].Name))
|
||||
|
||||
// Update listener back to contain a route configuration name.
|
||||
resources.Listeners = []*v3listenerpb.Listener{e2e.DefaultClientListener(defaultTestServiceName, resources.Routes[0].Name)}
|
||||
configureResources(ctx, t, mgmtServer, nodeID, resources.Listeners, resources.Routes, nil, nil)
|
||||
|
||||
// Verify that that route configuration resource is requested.
|
||||
waitForResourceNames(ctx, t, routeCfgCh, []string{resources.Routes[0].Name})
|
||||
|
||||
// Verify that appropriate SC is pushed on the channel.
|
||||
verifyUpdateFromResolver(ctx, t, stateCh, wantServiceConfig(resources.Clusters[0].Name))
|
||||
}
|
||||
Reference in New Issue
Block a user