Tests that when a request hash key is set in the balancer configuration via service config, and the header is not set in the outgoing request, then it is sent to a random backend.
(t *testing.T)
| 2746 | // service config, and the header is not set in the outgoing request, then it |
| 2747 | // is sent to a random backend. |
| 2748 | func (s) TestRingHash_RequestHashKeyRandom(t *testing.T) { |
| 2749 | testutils.SetEnvConfig(t, &envconfig.RingHashSetRequestHashKey, true) |
| 2750 | |
| 2751 | backends := backendAddrs(startTestServiceBackends(t, 4)) |
| 2752 | |
| 2753 | // Create a clientConn with a manual resolver (which is used to push the |
| 2754 | // address of the test backend), and a default service config pointing to |
| 2755 | // the use of the ring_hash_experimental LB policy with an explicit hash |
| 2756 | // header. |
| 2757 | ringHashServiceConfig := highRingSizeServiceConfig(t) |
| 2758 | r := manual.NewBuilderWithScheme("whatever") |
| 2759 | dopts := []grpc.DialOption{ |
| 2760 | grpc.WithTransportCredentials(insecure.NewCredentials()), |
| 2761 | grpc.WithResolvers(r), |
| 2762 | grpc.WithDefaultServiceConfig(ringHashServiceConfig), |
| 2763 | grpc.WithConnectParams(fastConnectParams), |
| 2764 | } |
| 2765 | cc, err := grpc.NewClient(r.Scheme()+":///test.server", dopts...) |
| 2766 | if err != nil { |
| 2767 | t.Fatalf("Failed to dial local test server: %v", err) |
| 2768 | } |
| 2769 | defer cc.Close() |
| 2770 | var endpoints []resolver.Endpoint |
| 2771 | for _, backend := range backends { |
| 2772 | endpoints = append(endpoints, resolver.Endpoint{ |
| 2773 | Addresses: []resolver.Address{{Addr: backend}}, |
| 2774 | }) |
| 2775 | } |
| 2776 | r.UpdateState(resolver.State{ |
| 2777 | Endpoints: endpoints, |
| 2778 | }) |
| 2779 | client := testgrpc.NewTestServiceClient(cc) |
| 2780 | |
| 2781 | ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) |
| 2782 | defer cancel() |
| 2783 | |
| 2784 | // Due to the way that ring hash lazily establishes connections when using a |
| 2785 | // random hash, request distribution is skewed towards the order in which we |
| 2786 | // connected. The test send RPCs until we are connected to all backends, so |
| 2787 | // we can later assert that the distribution is uniform. |
| 2788 | seen := make(map[string]bool) |
| 2789 | for len(seen) != 4 { |
| 2790 | var remote peer.Peer |
| 2791 | if _, err := client.EmptyCall(ctx, &testpb.Empty{}, grpc.Peer(&remote)); err != nil { |
| 2792 | t.Fatalf("rpc EmptyCall() failed: %v", err) |
| 2793 | } |
| 2794 | seen[remote.String()] = true |
| 2795 | } |
| 2796 | |
| 2797 | // Make sure that requests with the old hash are sent to random backends. |
| 2798 | const want = 1.0 / 4 |
| 2799 | numRPCs := computeIdealNumberOfRPCs(t, want, errorTolerance) |
| 2800 | gotPerBackend := checkRPCSendOK(ctx, t, client, numRPCs) |
| 2801 | for _, backend := range backends { |
| 2802 | got := float64(gotPerBackend[backend]) / float64(numRPCs) |
| 2803 | if !cmp.Equal(got, want, cmpopts.EquateApprox(0, errorTolerance)) { |
| 2804 | t.Errorf("Fraction of RPCs to backend %s: got %v, want %v (margin: +-%v)", backend, got, want, errorTolerance) |
| 2805 | } |
nothing calls this directly
no test coverage detected