diff --git a/proxy/healthy_endpoints_test.go b/proxy/healthy_endpoints_test.go index b07e7bbc8b..89ae09ae00 100644 --- a/proxy/healthy_endpoints_test.go +++ b/proxy/healthy_endpoints_test.go @@ -29,38 +29,42 @@ func defaultEndpointRegistry() *routing.EndpointRegistry { } func TestPHCWithoutRequests(t *testing.T) { - services := []*httptest.Server{} - for i := 0; i < 3; i++ { - service := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(http.StatusOK) - })) - services = append(services, service) - defer service.Close() + for _, algorithm := range []string{"random", "consistentHash", "roundRobin", "powerOfRandomNChoices"} { + t.Run(algorithm, func(t *testing.T) { + services := []*httptest.Server{} + for i := 0; i < 3; i++ { + service := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + })) + services = append(services, service) + defer service.Close() + } + endpointRegistry := defaultEndpointRegistry() + + doc := fmt.Sprintf(`* -> consistentHashKey("${request.header.ConsistentHashKey}") -> <%s, "%s", "%s", "%s">`, algorithm, services[0].URL, services[1].URL, services[2].URL) + tp, err := newTestProxyWithParams(doc, Params{ + EnablePassiveHealthCheck: true, + EndpointRegistry: endpointRegistry, + }) + if err != nil { + t.Fatal(err) + } + defer tp.close() + + ps := httptest.NewServer(tp.proxy) + defer ps.Close() + + rsp, err := ps.Client().Get(ps.URL) + if err != nil { + t.Fatal(err) + } + assert.Equal(t, http.StatusOK, rsp.StatusCode) + rsp.Body.Close() + + time.Sleep(10 * period) + /* this test is needed to check PHC will not crash without requests sent during period at all */ + }) } - endpointRegistry := defaultEndpointRegistry() - - doc := fmt.Sprintf(`* -> `, services[0].URL, services[1].URL, services[2].URL) - tp, err := newTestProxyWithParams(doc, Params{ - EnablePassiveHealthCheck: true, - EndpointRegistry: endpointRegistry, - }) - if err != nil { - t.Fatal(err) - } - defer tp.close() - - ps := httptest.NewServer(tp.proxy) - defer ps.Close() - - rsp, err := ps.Client().Get(ps.URL) - if err != nil { - t.Fatal(err) - } - assert.Equal(t, http.StatusOK, rsp.StatusCode) - rsp.Body.Close() - - time.Sleep(10 * period) - /* this test is needed to check PHC will not crash without requests sent during period at all */ } func TestPHCForSingleHealthyEndpoint(t *testing.T) { @@ -99,42 +103,46 @@ func TestPHCForSingleHealthyEndpoint(t *testing.T) { } func TestPHCForMultipleHealthyEndpoints(t *testing.T) { - services := []*httptest.Server{} - for i := 0; i < 3; i++ { - service := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(http.StatusOK) - })) - services = append(services, service) - defer service.Close() + for _, algorithm := range []string{"random", "consistentHash", "roundRobin", "powerOfRandomNChoices"} { + t.Run(algorithm, func(t *testing.T) { + services := []*httptest.Server{} + for i := 0; i < 3; i++ { + service := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + })) + services = append(services, service) + defer service.Close() + } + endpointRegistry := defaultEndpointRegistry() + + doc := fmt.Sprintf(`* -> consistentHashKey("${request.header.ConsistentHashKey}") -> <%s, "%s", "%s", "%s">`, algorithm, services[0].URL, services[1].URL, services[2].URL) + tp, err := newTestProxyWithParams(doc, Params{ + EnablePassiveHealthCheck: true, + EndpointRegistry: endpointRegistry, + }) + if err != nil { + t.Fatal(err) + } + defer tp.close() + + ps := httptest.NewServer(tp.proxy) + defer ps.Close() + + failedReqs := 0 + for i := 0; i < nRequests; i++ { + rsp, err := ps.Client().Get(ps.URL) + if err != nil { + t.Fatal(err) + } + + if rsp.StatusCode != http.StatusOK { + failedReqs++ + } + rsp.Body.Close() + } + assert.Equal(t, 0, failedReqs) + }) } - endpointRegistry := defaultEndpointRegistry() - - doc := fmt.Sprintf(`* -> `, services[0].URL, services[1].URL, services[2].URL) - tp, err := newTestProxyWithParams(doc, Params{ - EnablePassiveHealthCheck: true, - EndpointRegistry: endpointRegistry, - }) - if err != nil { - t.Fatal(err) - } - defer tp.close() - - ps := httptest.NewServer(tp.proxy) - defer ps.Close() - - failedReqs := 0 - for i := 0; i < nRequests; i++ { - rsp, err := ps.Client().Get(ps.URL) - if err != nil { - t.Fatal(err) - } - - if rsp.StatusCode != http.StatusOK { - failedReqs++ - } - rsp.Body.Close() - } - assert.Equal(t, 0, failedReqs) } type roundTripperUnhealthyHost struct { @@ -165,41 +173,51 @@ func newRoundTripperUnhealthyHost(o *RoundTripperUnhealthyHostOptions) func(r ht } func TestPHCForMultipleHealthyAndOneUnhealthyEndpoints(t *testing.T) { - services := []*httptest.Server{} - for i := 0; i < 3; i++ { - service := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(http.StatusOK) - })) - services = append(services, service) - defer service.Close() - } - endpointRegistry := defaultEndpointRegistry() - - doc := fmt.Sprintf(`* -> `, services[0].URL, services[1].URL, services[2].URL) - tp, err := newTestProxyWithParams(doc, Params{ - EnablePassiveHealthCheck: true, - EndpointRegistry: endpointRegistry, - CustomHttpRoundTripperWrap: newRoundTripperUnhealthyHost(&RoundTripperUnhealthyHostOptions{Host: services[0].URL[7:], Probability: rtFailureProbability}), - }) - if err != nil { - t.Fatal(err) - } - defer tp.close() - - ps := httptest.NewServer(tp.proxy) - defer ps.Close() - - failedReqs := 0 - for i := 0; i < nRequests; i++ { - rsp, err := ps.Client().Get(ps.URL) - if err != nil { - t.Fatal(err) - } - - if rsp.StatusCode != http.StatusOK { - failedReqs++ - } - rsp.Body.Close() + for _, algorithm := range []string{"random", "consistentHash", "roundRobin", "powerOfRandomNChoices"} { + t.Run(algorithm, func(t *testing.T) { + services := []*httptest.Server{} + for i := 0; i < 3; i++ { + service := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + })) + services = append(services, service) + defer service.Close() + } + endpointRegistry := defaultEndpointRegistry() + + doc := fmt.Sprintf(`* -> consistentHashKey("${request.header.ConsistentHashKey}") -> <%s, "%s", "%s", "%s">`, algorithm, services[0].URL, services[1].URL, services[2].URL) + tp, err := newTestProxyWithParams(doc, Params{ + EnablePassiveHealthCheck: true, + EndpointRegistry: endpointRegistry, + CustomHttpRoundTripperWrap: newRoundTripperUnhealthyHost(&RoundTripperUnhealthyHostOptions{Host: services[0].URL[7:], Probability: rtFailureProbability}), + }) + if err != nil { + t.Fatal(err) + } + defer tp.close() + + ps := httptest.NewServer(tp.proxy) + defer ps.Close() + + failedReqs := 0 + for i := 0; i < nRequests; i++ { + req, err := http.NewRequest("GET", ps.URL, nil) + if err != nil { + t.Fatal(err) + } + req.Header.Add("ConsistentHashKey", fmt.Sprintf("%+v", i)) + + rsp, err := ps.Client().Do(req) + if err != nil { + t.Fatal(err) + } + + if rsp.StatusCode != http.StatusOK { + failedReqs++ + } + rsp.Body.Close() + } + assert.InDelta(t, 0.33*rtFailureProbability*(1.0-rtFailureProbability)*float64(nRequests), failedReqs, 0.1*float64(nRequests)) + }) } - assert.InDelta(t, 0.33*rtFailureProbability*(1.0-rtFailureProbability)*float64(nRequests), failedReqs, 0.1*float64(nRequests)) }