Repository: grpc/grpc-go
File: xds/internal/xdsclient/tests/fallback_test.go (Go)

Code before:

	// Get the xDS resolver to use the above xDS client.
	resolverBuilder := internal.NewXDSResolverWithPoolForTesting.(func(*xdsclient.Pool) (resolver.Builder, error))
	resolver, err := resolverBuilder(pool)
	if err != nil {
		t.Fatalf("Failed to create xDS resolver for testing: %v", err)
	}

	// Start a gRPC client that uses the above xDS resolver.
	cc, err := grpc.NewClient(fmt.Sprintf("xds:///%s", serviceName), grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithResolvers(resolver))
	if err != nil {
		t.Fatalf("Failed to create gRPC client: %v", err)
	}
	defer cc.Close()
	cc.Connect()
	client := testgrpc.NewTestServiceClient(cc)

	// Secondary2 fallback, RPCs reach backend3.
	secondary2Lis.Restart()
	if err := waitForRPCsToReachBackend(ctx, client, backend3.Address); err != nil {
		t.Fatal(err)
	}

	// Verify that connection attempts were made to primaryWrappedLis and
	// secondary1WrappedLis, even though the fallback succeeded using
	// secondary2WrappedLis and RPCs reached backend3.
	if _, err := primaryWrappedLis.NewConnCh.Receive(ctx); err != nil {
		t.Fatalf("Expected connection attempt to primary but got error: %v", err)
	}
	if _, err := secondary1WrappedLis.NewConnCh.Receive(ctx); err != nil {
		t.Fatalf("Expected connection attempt to secondary1 but got error: %v", err)
	}

	// Secondary1 becomes available, RPCs go to backend2.
	secondary1Lis.Restart()
	secondary1ManagementServer.Update(ctx, e2e.UpdateOptions{
		NodeID:    nodeID,
		Listeners: []*v3listenerpb.Listener{e2e.DefaultClientListener(serviceName, "route-s1")},
		Routes:    []*v3routepb.RouteConfiguration{e2e.DefaultRouteConfig("route-s1", serviceName, "cluster-s1")},
		Clusters:  []*v3clusterpb.Cluster{e2e.DefaultCluster("cluster-s1", "endpoints-s1", e2e.SecurityLevelNone)},
		Endpoints: []*v3endpointpb.ClusterLoadAssignment{
			e2e.DefaultEndpoint("endpoints-s1", "localhost", []uint32{testutils.ParsePort(t, backend2.Address)}),
		},
	})

	// Wait for switch from secondary2 to secondary1.
	if conn, err := secondary2WrappedLis.NewConnCh.Receive(ctx); err == nil {
		cw := conn.(*testutils.ConnWrapper)
		if _, err := cw.CloseCh.Receive(ctx); err != nil {
			t.Fatalf("Expected secondary2 connection to close after promotion to secondary1, got error: %v", err)
		}

Review comment (suggestion):
```suggestion
	// Verify that connection attempts were made to primaryWrappedLis and
	// secondary1WrappedLis, before using secondary2WrappedLis to
	// make succesful RPCs to backend3.
```

Code after:
	resolverBuilder := internal.NewXDSResolverWithPoolForTesting.(func(*xdsclient.Pool) (resolver.Builder, error))
	resolver, err := resolverBuilder(pool)
	if err != nil {
		t.Fatalf("Failed to create xDS resolver for testing: %v", err)
	}

	// Start a gRPC client that uses the above xDS resolver.
	cc, err := grpc.NewClient(fmt.Sprintf("xds:///%s", serviceName), grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithResolvers(resolver))
	if err != nil {
		t.Fatalf("Failed to create gRPC client: %v", err)
	}
	defer cc.Close()
	cc.Connect()
	client := testgrpc.NewTestServiceClient(cc)

	// Verify that connection attempts were made to primaryWrappedLis and
	// secondaryWrappedLis, before using tertiaryWrappedLis to make
	// successful RPCs to backend3.
	if _, err := primaryWrappedLis.NewConnCh.Receive(ctx); err != nil {
		t.Fatalf("Timeout when waiting for connection to primary: %v", err)
	}

	// Stop primary, client should connect to secondary.
	primaryLis.Stop()
	if _, err := secondaryWrappedLis.NewConnCh.Receive(ctx); err != nil {
		t.Fatalf("Timeout when waiting for connection to secondary after primary stopped: %v", err)
	}

	// Stop secondary, client should connect to tertiary.
	secondaryLis.Stop()
	tertiaryConn, err := tertiaryWrappedLis.NewConnCh.Receive(ctx)
	if err != nil {
		t.Fatalf("Timeout when waiting for connection to tertiary after secondary stopped: %v", err)
	}

	// Tertiary has all resources, RPCs should succeed to backend3.
	if err := waitForRPCsToReachBackend(ctx, client, backend3.Address); err != nil {
		t.Fatal(err)
	}

	// Secondary1 becomes available, RPCs go to backend2.
	secondaryLis.Restart()
	secondaryManagementServer.Update(ctx, e2e.UpdateOptions{
		NodeID:    nodeID,
		Listeners: []*v3listenerpb.Listener{e2e.DefaultClientListener(serviceName, "route-s1")},
		Routes:    []*v3routepb.RouteConfiguration{e2e.DefaultRouteConfig("route-s1", serviceName, "cluster-s1")},
		Clusters:  []*v3clusterpb.Cluster{e2e.DefaultCluster("cluster-s1", "endpoints-s1", e2e.SecurityLevelNone)},
		Endpoints: []*v3endpointpb.ClusterLoadAssignment{
			e2e.DefaultEndpoint("endpoints-s1", "localhost", []uint32{testutils.ParsePort(t, backend2.Address)}),
		},
	})