Repository: grpc/grpc-go
File: balancer/randomsubsetting/randomsubsetting_test.go (Go)

Code before:
	minClientsPerBackend := math.MaxInt
	maxClientsPerBackend := 0
	for _, v := range clientsPerBackend {
		if len(v) < minClientsPerBackend {
			minClientsPerBackend = len(v)
		}
		if len(v) > maxClientsPerBackend {
			maxClientsPerBackend = len(v)
		}
	}

	if maxClientsPerBackend > minClientsPerBackend+maxDiff {
		t.Fatalf("the difference between min and max clients per backend should be <= %d, clientsPerBackend: %v", maxDiff, clientsPerBackend)
	}
}

func (s) TestSubsettingE2E(t *testing.T) {
	tests := []struct {
		name       string
		subsetSize int
		clients    int
		backends   int
		maxDiff    int
	}{
		{
			name:       "backends could be evenly distributed between small number of clients",
			backends:   3,
			clients:    2,
			subsetSize: 2,
			maxDiff:    1,
		},
		{
			name:       "backends could be evenly distributed between clients",
			backends:   12,
			clients:    8,
			subsetSize: 3,
			maxDiff:    3,
		},
		{
			name:       "backends could NOT be evenly distributed between clients",
			backends:   37,
			clients:    22,
			subsetSize: 5,
			maxDiff:    15,
		},
		{
			name:       "Nbackends %% subsetSize == 0, but there are not enough clients to fill the last round",
			backends:   20,
			clients:    7,
			subsetSize: 5,
			maxDiff:    20,

Review comment (security):
Please see here for guidelines on how best to name subtests: https://google.github.io/styleguide/go/decisions#subtest-names

TL;dr
Think of subtest names more like a function identifier than a prose description.

The test runner replaces spaces with underscores, and escapes non-printing characters. To ensure accurate correlation between test logs and source code, it is recommended to avoid using these characters in subtest names.



Code after:
		BalancerConfig: &lbConfig{
			SubsetSize:  5,
			ChildPolicy: &iserviceconfig.BalancerConfig{Name: "stub-child-balancer"},
		},
	}

	// Send the resolver state to the random_subsetting balancer and verify that
	// the child policy receives the expected number of endpoints.
	if err := rsb.UpdateClientConnState(state); err != nil {
		t.Fatalf("UpdateClientConnState failed: %v", err)
	}

	var wantEndpoints []resolver.Endpoint
	select {
	case s := <-updateCh:
		if len(s.ResolverState.Endpoints) != 5 {
			t.Fatalf("Child policy received %d endpoints, want 5", len(s.ResolverState.Endpoints))
		}
		// Store the subset for the next comparison.
		wantEndpoints = s.ResolverState.Endpoints
	case <-ctx.Done():
		t.Fatal("Timed out waiting for child policy to receive an update")
	}

	// Call UpdateClientConnState again with the same configuration.
	if err := rsb.UpdateClientConnState(state); err != nil {
		t.Fatalf("Second UpdateClientConnState failed: %v", err)
	}

	// Verify that the child policy receives the same subset of endpoints.
	select {
	case s := <-updateCh:
		if diff := cmp.Diff(wantEndpoints, s.ResolverState.Endpoints); diff != "" {
			t.Fatalf("Child policy received a different subset of endpoints on second update, diff (-want +got):\n%s", diff)
		}
	case <-ctx.Done():
		t.Fatal("Timed out waiting for second child policy update")
	}
}