Skip to content

Commit b22a27f

Browse files
xds/clusterimpl: Convert existing unit tests to e2e style (3/N) (#8616)
1 parent ece7397 commit b22a27f

File tree

2 files changed

+190
-105
lines changed

2 files changed

+190
-105
lines changed

internal/xds/balancer/clusterimpl/balancer_test.go

Lines changed: 0 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,7 @@ package clusterimpl
2020

2121
import (
2222
"context"
23-
"encoding/json"
2423
"errors"
25-
"strings"
2624
"testing"
2725
"time"
2826

@@ -38,7 +36,6 @@ import (
3836
"google.golang.org/grpc/internal/xds/testutils/fakeclient"
3937
"google.golang.org/grpc/internal/xds/xdsclient"
4038
"google.golang.org/grpc/resolver"
41-
"google.golang.org/grpc/serviceconfig"
4239
)
4340

4441
const (
@@ -212,108 +209,6 @@ func (s) TestClusterNameInAddressAttributes(t *testing.T) {
212209
}
213210
}
214211

215-
// Test verifies that child policies was updated on receipt of
216-
// configuration update.
217-
func (s) TestChildPolicyUpdatedOnConfigUpdate(t *testing.T) {
218-
xdsC := fakeclient.NewClient()
219-
220-
builder := balancer.Get(Name)
221-
cc := testutils.NewBalancerClientConn(t)
222-
b := builder.Build(cc, balancer.BuildOptions{})
223-
defer b.Close()
224-
225-
// Keep track of which child policy was updated
226-
updatedChildPolicy := ""
227-
228-
// Create stub balancers to track config updates
229-
const (
230-
childPolicyName1 = "stubBalancer1"
231-
childPolicyName2 = "stubBalancer2"
232-
)
233-
234-
stub.Register(childPolicyName1, stub.BalancerFuncs{
235-
UpdateClientConnState: func(_ *stub.BalancerData, _ balancer.ClientConnState) error {
236-
updatedChildPolicy = childPolicyName1
237-
return nil
238-
},
239-
})
240-
241-
stub.Register(childPolicyName2, stub.BalancerFuncs{
242-
UpdateClientConnState: func(_ *stub.BalancerData, _ balancer.ClientConnState) error {
243-
updatedChildPolicy = childPolicyName2
244-
return nil
245-
},
246-
})
247-
248-
// Initial config update with childPolicyName1
249-
if err := b.UpdateClientConnState(balancer.ClientConnState{
250-
ResolverState: xdsclient.SetClient(resolver.State{Endpoints: testBackendEndpoints}, xdsC),
251-
BalancerConfig: &LBConfig{
252-
Cluster: testClusterName,
253-
ChildPolicy: &internalserviceconfig.BalancerConfig{
254-
Name: childPolicyName1,
255-
},
256-
},
257-
}); err != nil {
258-
t.Fatalf("Error updating the config: %v", err)
259-
}
260-
261-
if updatedChildPolicy != childPolicyName1 {
262-
t.Fatal("Child policy 1 was not updated on initial configuration update.")
263-
}
264-
265-
// Second config update with childPolicyName2
266-
if err := b.UpdateClientConnState(balancer.ClientConnState{
267-
ResolverState: xdsclient.SetClient(resolver.State{Endpoints: testBackendEndpoints}, xdsC),
268-
BalancerConfig: &LBConfig{
269-
Cluster: testClusterName,
270-
ChildPolicy: &internalserviceconfig.BalancerConfig{
271-
Name: childPolicyName2,
272-
},
273-
},
274-
}); err != nil {
275-
t.Fatalf("Error updating the config: %v", err)
276-
}
277-
278-
if updatedChildPolicy != childPolicyName2 {
279-
t.Fatal("Child policy 2 was not updated after child policy name change.")
280-
}
281-
}
282-
283-
// Test verifies that config update fails if child policy config
284-
// failed to parse.
285-
func (s) TestFailedToParseChildPolicyConfig(t *testing.T) {
286-
xdsC := fakeclient.NewClient()
287-
288-
builder := balancer.Get(Name)
289-
cc := testutils.NewBalancerClientConn(t)
290-
b := builder.Build(cc, balancer.BuildOptions{})
291-
defer b.Close()
292-
293-
// Create a stub balancer which fails to ParseConfig.
294-
const parseConfigError = "failed to parse config"
295-
const childPolicyName = "stubBalancer-FailedToParseChildPolicyConfig"
296-
stub.Register(childPolicyName, stub.BalancerFuncs{
297-
ParseConfig: func(_ json.RawMessage) (serviceconfig.LoadBalancingConfig, error) {
298-
return nil, errors.New(parseConfigError)
299-
},
300-
})
301-
302-
err := b.UpdateClientConnState(balancer.ClientConnState{
303-
ResolverState: xdsclient.SetClient(resolver.State{Endpoints: testBackendEndpoints}, xdsC),
304-
BalancerConfig: &LBConfig{
305-
Cluster: testClusterName,
306-
ChildPolicy: &internalserviceconfig.BalancerConfig{
307-
Name: childPolicyName,
308-
},
309-
},
310-
})
311-
312-
if err == nil || !strings.Contains(err.Error(), parseConfigError) {
313-
t.Fatalf("Got error: %v, want error: %s", err, parseConfigError)
314-
}
315-
}
316-
317212
// Test verify that the case picker is updated synchronously on receipt of
318213
// configuration update.
319214
func (s) TestPickerUpdatedSynchronouslyOnConfigUpdate(t *testing.T) {

internal/xds/balancer/clusterimpl/tests/balancer_test.go

Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,21 +20,27 @@ package clusterimpl_test
2020

2121
import (
2222
"context"
23+
"encoding/json"
24+
"errors"
2325
"fmt"
2426
"math"
2527
"net"
2628
"strconv"
2729
"strings"
30+
"sync/atomic"
2831
"testing"
2932
"time"
3033

3134
"github.com/google/go-cmp/cmp"
3235
"github.com/google/uuid"
3336
"google.golang.org/grpc"
37+
"google.golang.org/grpc/balancer"
38+
"google.golang.org/grpc/balancer/pickfirst"
3439
"google.golang.org/grpc/codes"
3540
"google.golang.org/grpc/connectivity"
3641
"google.golang.org/grpc/credentials/insecure"
3742
"google.golang.org/grpc/internal"
43+
"google.golang.org/grpc/internal/balancer/stub"
3844
"google.golang.org/grpc/internal/grpctest"
3945
"google.golang.org/grpc/internal/stubserver"
4046
"google.golang.org/grpc/internal/testutils"
@@ -43,6 +49,7 @@ import (
4349
"google.golang.org/grpc/peer"
4450
"google.golang.org/grpc/resolver"
4551
"google.golang.org/grpc/resolver/manual"
52+
"google.golang.org/grpc/serviceconfig"
4653
"google.golang.org/grpc/status"
4754
"google.golang.org/protobuf/testing/protocmp"
4855
"google.golang.org/protobuf/types/known/durationpb"
@@ -1113,3 +1120,186 @@ func (s) TestUpdateLRSServerToNil(t *testing.T) {
11131120
t.Fatalf("Expected no LRS reports after disable, got %v want %v", err, context.DeadlineExceeded)
11141121
}
11151122
}
1123+
1124+
// Test verifies that child policy was updated on receipt of
1125+
// configuration update.
1126+
func (s) TestChildPolicyChangeOnConfigUpdate(t *testing.T) {
1127+
// Create an xDS management server.
1128+
mgmtServer := e2e.StartManagementServer(t, e2e.ManagementServerOptions{AllowResourceSubset: true})
1129+
defer mgmtServer.Stop()
1130+
1131+
// Create bootstrap configuration pointing to the above management server.
1132+
nodeID := uuid.New().String()
1133+
bc := e2e.DefaultBootstrapContents(t, nodeID, mgmtServer.Address)
1134+
testutils.CreateBootstrapFileForTesting(t, bc)
1135+
1136+
// Create an xDS resolver with the above bootstrap configuration.
1137+
if internal.NewXDSResolverWithConfigForTesting == nil {
1138+
t.Fatalf("internal.NewXDSResolverWithConfigForTesting is nil")
1139+
}
1140+
resolverBuilder, err := internal.NewXDSResolverWithConfigForTesting.(func([]byte) (resolver.Builder, error))(bc)
1141+
if err != nil {
1142+
t.Fatalf("Failed to create xDS resolver for testing: %v", err)
1143+
}
1144+
1145+
// Start a server backend exposing the test service.
1146+
server := stubserver.StartTestService(t, nil)
1147+
defer server.Stop()
1148+
1149+
const serviceName = "test-child-policy"
1150+
1151+
// Configure the xDS management server with default resources. Cluster
1152+
// corresponding to this resource will be configured with "round_robin"
1153+
// as the endpoint picking policy
1154+
resources := e2e.DefaultClientResources(e2e.ResourceParams{
1155+
DialTarget: serviceName,
1156+
NodeID: nodeID,
1157+
Host: "localhost",
1158+
Port: testutils.ParsePort(t, server.Address),
1159+
})
1160+
1161+
ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
1162+
defer cancel()
1163+
if err := mgmtServer.Update(ctx, resources); err != nil {
1164+
t.Fatalf("Failed to update xDS resources: %v", err)
1165+
}
1166+
1167+
cc, err := grpc.NewClient(fmt.Sprintf("xds:///%s", serviceName), grpc.WithResolvers(resolverBuilder), grpc.WithTransportCredentials(insecure.NewCredentials()))
1168+
if err != nil {
1169+
t.Fatalf("Failed to create client: %v", err)
1170+
}
1171+
defer cc.Close()
1172+
1173+
client := testgrpc.NewTestServiceClient(cc)
1174+
if _, err := client.EmptyCall(ctx, &testpb.Empty{}); err != nil {
1175+
t.Fatalf("client.EmptyCall() failed: %v", err)
1176+
}
1177+
1178+
// Register stub pickfirst LB policy so that we can catch config changes.
1179+
pfBuilder := balancer.Get(pickfirst.Name)
1180+
internal.BalancerUnregister(pfBuilder.Name())
1181+
lbCfgCh := make(chan serviceconfig.LoadBalancingConfig, 1)
1182+
var updatedChildPolicy atomic.Pointer[string]
1183+
stub.Register(pfBuilder.Name(), stub.BalancerFuncs{
1184+
ParseConfig: func(lbCfg json.RawMessage) (serviceconfig.LoadBalancingConfig, error) {
1185+
return pfBuilder.(balancer.ConfigParser).ParseConfig(lbCfg)
1186+
},
1187+
Init: func(bd *stub.BalancerData) {
1188+
bd.ChildBalancer = pfBuilder.Build(bd.ClientConn, bd.BuildOptions)
1189+
},
1190+
UpdateClientConnState: func(bd *stub.BalancerData, ccs balancer.ClientConnState) error {
1191+
name := pfBuilder.Name()
1192+
updatedChildPolicy.Store(&name)
1193+
select {
1194+
case lbCfgCh <- ccs.BalancerConfig:
1195+
case <-ctx.Done():
1196+
t.Error("Timed out while waiting for BalancerConfig, context deadline exceeded")
1197+
}
1198+
return bd.ChildBalancer.UpdateClientConnState(ccs)
1199+
},
1200+
Close: func(bd *stub.BalancerData) {
1201+
bd.ChildBalancer.Close()
1202+
},
1203+
})
1204+
defer balancer.Register(pfBuilder)
1205+
1206+
// Now update the cluster to use "pick_first" as the endpoint picking policy.
1207+
resources.Clusters[0].LoadBalancingPolicy = &v3clusterpb.LoadBalancingPolicy{
1208+
Policies: []*v3clusterpb.LoadBalancingPolicy_Policy{{
1209+
TypedExtensionConfig: &v3corepb.TypedExtensionConfig{
1210+
TypedConfig: testutils.MarshalAny(t, &v3pickfirstpb.PickFirst{}),
1211+
},
1212+
}},
1213+
}
1214+
if err := mgmtServer.Update(ctx, resources); err != nil {
1215+
t.Fatal(err)
1216+
}
1217+
1218+
select {
1219+
case <-ctx.Done():
1220+
t.Fatalf("Timeout waiting for pickfirst child policy config")
1221+
case <-lbCfgCh:
1222+
}
1223+
1224+
if p := updatedChildPolicy.Load(); p == nil || *p != pfBuilder.Name() {
1225+
var got string
1226+
if p != nil {
1227+
got = *p
1228+
}
1229+
t.Fatalf("Unexpected child policy after config update, got %q, want %q", got, pfBuilder.Name())
1230+
}
1231+
1232+
// New RPC should still be routed successfully
1233+
if _, err := client.EmptyCall(ctx, &testpb.Empty{}); err != nil {
1234+
t.Errorf("EmptyCall() failed after policy update: %v", err)
1235+
}
1236+
}
1237+
1238+
// Test verifies that config update fails if child policy config
1239+
// failed to parse.
1240+
func (s) TestFailedToParseChildPolicyConfig(t *testing.T) {
1241+
// Create an xDS management server.
1242+
mgmtServer := e2e.StartManagementServer(t, e2e.ManagementServerOptions{AllowResourceSubset: true})
1243+
defer mgmtServer.Stop()
1244+
1245+
// Create bootstrap configuration pointing to the above management server.
1246+
nodeID := uuid.New().String()
1247+
bc := e2e.DefaultBootstrapContents(t, nodeID, mgmtServer.Address)
1248+
testutils.CreateBootstrapFileForTesting(t, bc)
1249+
1250+
// Create an xDS resolver with the above bootstrap configuration.
1251+
if internal.NewXDSResolverWithConfigForTesting == nil {
1252+
t.Fatalf("internal.NewXDSResolverWithConfigForTesting is nil")
1253+
}
1254+
resolverBuilder, err := internal.NewXDSResolverWithConfigForTesting.(func([]byte) (resolver.Builder, error))(bc)
1255+
if err != nil {
1256+
t.Fatalf("Failed to create xDS resolver for testing: %v", err)
1257+
}
1258+
1259+
// Start a server backend exposing the test service.
1260+
server := stubserver.StartTestService(t, nil)
1261+
defer server.Stop()
1262+
1263+
const serviceName = "test-child-policy"
1264+
resources := e2e.DefaultClientResources(e2e.ResourceParams{
1265+
DialTarget: serviceName,
1266+
NodeID: nodeID,
1267+
Host: "localhost",
1268+
Port: testutils.ParsePort(t, server.Address),
1269+
})
1270+
resources.Clusters[0].LoadBalancingPolicy = &v3clusterpb.LoadBalancingPolicy{
1271+
Policies: []*v3clusterpb.LoadBalancingPolicy_Policy{{
1272+
TypedExtensionConfig: &v3corepb.TypedExtensionConfig{
1273+
TypedConfig: testutils.MarshalAny(t, &v3pickfirstpb.PickFirst{}),
1274+
},
1275+
}},
1276+
}
1277+
1278+
ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
1279+
defer cancel()
1280+
if err := mgmtServer.Update(ctx, resources); err != nil {
1281+
t.Fatalf("Failed to update xDS resources: %v", err)
1282+
}
1283+
1284+
// Register stub pickfirst LB policy so that we can catch parsing errors.
1285+
pfBuilder := balancer.Get(pickfirst.Name)
1286+
internal.BalancerUnregister(pfBuilder.Name())
1287+
const parseConfigError = "failed to parse config"
1288+
stub.Register(pfBuilder.Name(), stub.BalancerFuncs{
1289+
ParseConfig: func(_ json.RawMessage) (serviceconfig.LoadBalancingConfig, error) {
1290+
return nil, errors.New(parseConfigError)
1291+
},
1292+
})
1293+
defer balancer.Register(pfBuilder)
1294+
1295+
cc, err := grpc.NewClient(fmt.Sprintf("xds:///%s", serviceName), grpc.WithResolvers(resolverBuilder), grpc.WithTransportCredentials(insecure.NewCredentials()))
1296+
if err != nil {
1297+
t.Fatalf("Failed to create client: %v", err)
1298+
}
1299+
defer cc.Close()
1300+
1301+
client := testgrpc.NewTestServiceClient(cc)
1302+
if _, err := client.EmptyCall(ctx, &testpb.Empty{}); err == nil || !strings.Contains(err.Error(), parseConfigError) {
1303+
t.Fatal("EmptyCall RPC succeeded when expected to fail")
1304+
}
1305+
}

0 commit comments

Comments
 (0)