Repository: grpc/grpc-go
File: internal/resolver/dns/dns_resolver_test.go (Go)

Code before:

// expectedUpdate contains the expected results to be verified in a state update
// from the DNS resolver.
type expectedUpdate struct {
	addrs         []resolver.Address
	endpoints     []resolver.Endpoint
	balancerAddrs []resolver.Address
	sc            string
}

// Waits for a state update from the DNS resolver and verifies the following:
// - want.addrs matches the list of addresses in the update
// - want.balancerAddrs matches the list of grpclb addresses in the update
// - want.sc matches the service config in the update
func verifyUpdateFromResolver(ctx context.Context, t *testing.T, stateCh chan resolver.State, want expectedUpdate) {
	t.Helper()

	var state resolver.State
	select {
	case <-ctx.Done():
		t.Fatal("Timeout when waiting for a state update from the resolver")
	case state = <-stateCh:
	}

	if !cmp.Equal(state.Addresses, want.addrs, cmpopts.EquateEmpty()) {
		t.Fatalf("Got addresses: %+v, want: %+v", state.Addresses, want.addrs)
	}
	if !cmp.Equal(state.Endpoints, want.endpoints, cmpopts.EquateEmpty()) {
		t.Fatalf("Got endpoints: %+v, want: %+v", state.Endpoints, want.endpoints)
	}
	if gs := grpclbstate.Get(state); gs == nil {
		if len(want.balancerAddrs) > 0 {
			t.Fatalf("Got no grpclb addresses. Want %d", len(want.balancerAddrs))
		}
	} else {
		if !cmp.Equal(gs.BalancerAddresses, want.balancerAddrs) {
			t.Fatalf("Got grpclb addresses %+v, want %+v", gs.BalancerAddresses, want.balancerAddrs)
		}
	}
	if want.sc == "{}" {
		if state.ServiceConfig != nil && state.ServiceConfig.Config != nil {
			t.Fatalf("Got service config:\n%s \nWant service config: {}", cmp.Diff(nil, state.ServiceConfig.Config))
		}

	} else if want.sc != "" {
		wantSCParsed := internal.ParseServiceConfig.(func(string) *serviceconfig.ParseResult)(want.sc)
		if !internal.EqualServiceConfigForTesting(state.ServiceConfig.Config, wantSCParsed.Config) {
			t.Fatalf("Got service config:\n%s \nWant service config:\n%s", cmp.Diff(nil, state.ServiceConfig.Config), cmp.Diff(nil, wantSCParsed.Config))
		}
	}
}

Review comment (bug):
Can we show `cmp.Diff` in the error message? I have seen that it is more helpful while debugging than showing two different structs that need to be compared manually.

Code after:
}

// resolverUpdate holds required components of a resolver state for validation.
type resolverUpdate struct {
	addrs         []resolver.Address
	endpoints     []resolver.Endpoint
	balancerAddrs []resolver.Address // list of grpclb addresses
	serviceConfig serviceconfig.Config
}

// Waits for a state update from the DNS resolver.
func verifyUpdateFromResolver(ctx context.Context, t *testing.T, stateCh chan resolver.State, want resolverUpdate) {
	t.Helper()

	var state resolver.State
	select {
	case <-ctx.Done():
		t.Fatal("Timeout when waiting for a state update from the resolver")
	case state = <-stateCh:
	}

	wantResolverState := resolver.State{
		Addresses: want.addrs,
		Endpoints: want.endpoints,
		ServiceConfig: &serviceconfig.ParseResult{
			Config: want.serviceConfig,
		},
	}
	if len(want.balancerAddrs) > 0 {
		wantResolverState = grpclbstate.Set(wantResolverState, &grpclbstate.State{
			BalancerAddresses: want.balancerAddrs,
		})
	}

	scComparer := cmp.Comparer(func(a, b *serviceconfig.ParseResult) bool {
		var scA serviceconfig.Config
		var scB serviceconfig.Config
		if a != nil {
			scA = a.Config
		}
		if b != nil {
			scB = b.Config
		}
		return internal.EqualServiceConfigForTesting(scA, scB)
	})
	attrComparer := cmp.Comparer(func(a, b *attributes.Attributes) bool {
		if a == nil && b == nil {
			return true
		}
		if a == nil || b == nil {
			return false