// If configMapper returns empty rates, then the default rate is applied. func (s *LimiterSuite) TestExtractorEmpty(c *C) { // Given extractor := func(*http.Request) (*RateSet, error) { return NewRateSet(), nil } rates := NewRateSet() rates.Add(time.Second, 1, 1) handler := http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { w.Write([]byte("hello")) }) l, err := New(handler, headerLimit, rates, Clock(s.clock), ExtractRates(RateExtractorFunc(extractor))) c.Assert(err, IsNil) srv := httptest.NewServer(l) defer srv.Close() // When/Then: The default rate is applied, which 1 req/second re, _, err := testutils.Get(srv.URL, testutils.Header("Source", "a")) c.Assert(err, IsNil) c.Assert(re.StatusCode, Equals, http.StatusOK) re, _, err = testutils.Get(srv.URL, testutils.Header("Source", "a")) c.Assert(err, IsNil) c.Assert(re.StatusCode, Equals, 429) s.clock.Sleep(time.Second) re, _, err = testutils.Get(srv.URL, testutils.Header("Source", "a")) c.Assert(err, IsNil) c.Assert(re.StatusCode, Equals, http.StatusOK) }
// We've hit the limit and were able to proceed on the next time run func (s *LimiterSuite) TestHitLimit(c *C) { handler := http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { w.Write([]byte("hello")) }) rates := NewRateSet() rates.Add(time.Second, 1, 1) l, err := New(handler, headerLimit, rates, Clock(s.clock)) c.Assert(err, IsNil) srv := httptest.NewServer(l) defer srv.Close() re, _, err := testutils.Get(srv.URL, testutils.Header("Source", "a")) c.Assert(err, IsNil) c.Assert(re.StatusCode, Equals, http.StatusOK) // Next request from the same source hits rate limit re, _, err = testutils.Get(srv.URL, testutils.Header("Source", "a")) c.Assert(err, IsNil) c.Assert(re.StatusCode, Equals, 429) // Second later, the request from this ip will succeed s.clock.Sleep(time.Second) re, _, err = testutils.Get(srv.URL, testutils.Header("Source", "a")) c.Assert(err, IsNil) c.Assert(re.StatusCode, Equals, http.StatusOK) }
// We've hit the limit and were able to proceed on the next time run func (s *LimiterSuite) TestOptions(c *C) { handler := http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { w.Write([]byte("hello")) }) rates := NewRateSet() rates.Add(time.Second, 1, 1) errHandler := utils.ErrorHandlerFunc(func(w http.ResponseWriter, req *http.Request, err error) { w.WriteHeader(http.StatusTeapot) w.Write([]byte(http.StatusText(http.StatusTeapot))) }) buf := &bytes.Buffer{} log := utils.NewFileLogger(buf, utils.INFO) l, err := New(handler, headerLimit, rates, ErrorHandler(errHandler), Logger(log), Clock(s.clock)) c.Assert(err, IsNil) srv := httptest.NewServer(l) defer srv.Close() re, _, err := testutils.Get(srv.URL, testutils.Header("Source", "a")) c.Assert(err, IsNil) c.Assert(re.StatusCode, Equals, http.StatusOK) re, _, err = testutils.Get(srv.URL, testutils.Header("Source", "a")) c.Assert(err, IsNil) c.Assert(re.StatusCode, Equals, http.StatusTeapot) c.Assert(len(buf.String()), Not(Equals), 0) }
func (s *STSuite) TestFileStreamingResponse(c *C) { srv := testutils.NewHandler(func(w http.ResponseWriter, req *http.Request) { w.Write([]byte("hello, this response is too large to fit in memory")) }) defer srv.Close() // forwarder will proxy the request to whatever destination fwd, err := forward.New() c.Assert(err, IsNil) // this is our redirect to server rdr := http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { req.URL = testutils.ParseURI(srv.URL) fwd.ServeHTTP(w, req) }) // stream handler will forward requests to redirect st, err := New(rdr, Logger(utils.NewFileLogger(os.Stdout, utils.INFO)), MemResponseBodyBytes(4)) c.Assert(err, IsNil) proxy := httptest.NewServer(st) defer proxy.Close() re, body, err := testutils.Get(proxy.URL) c.Assert(err, IsNil) c.Assert(re.StatusCode, Equals, http.StatusOK) c.Assert(string(body), Equals, "hello, this response is too large to fit in memory") }
// Makes sure hop-by-hop headers are removed func (s *FwdSuite) TestForwardedHeaders(c *C) { var outHeaders http.Header srv := testutils.NewHandler(func(w http.ResponseWriter, req *http.Request) { outHeaders = req.Header w.Write([]byte("hello")) }) defer srv.Close() f, err := New(Rewriter(&HeaderRewriter{TrustForwardHeader: true, Hostname: "hello"})) c.Assert(err, IsNil) proxy := testutils.NewHandler(func(w http.ResponseWriter, req *http.Request) { req.URL = testutils.ParseURI(srv.URL) f.ServeHTTP(w, req) }) defer proxy.Close() headers := http.Header{ XForwardedProto: []string{"httpx"}, XForwardedFor: []string{"192.168.1.1"}, XForwardedServer: []string{"foobar"}, } re, _, err := testutils.Get(proxy.URL, testutils.Headers(headers)) c.Assert(err, IsNil) c.Assert(re.StatusCode, Equals, http.StatusOK) c.Assert(outHeaders.Get(XForwardedProto), Equals, "httpx") c.Assert(strings.Contains(outHeaders.Get(XForwardedFor), "192.168.1.1"), Equals, true) c.Assert(outHeaders.Get(XForwardedServer), Equals, "hello") }
func (s *TraceSuite) TestTraceCaptureHeaders(c *C) { respHeaders := http.Header{ "X-Re-1": []string{"6", "7"}, "X-Re-2": []string{"2", "3"}, } handler := http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { utils.CopyHeaders(w.Header(), respHeaders) w.Write([]byte("hello")) }) buf := &bytes.Buffer{} l := utils.NewFileLogger(buf, utils.INFO) trace := &bytes.Buffer{} t, err := New(handler, trace, Logger(l), RequestHeaders("X-Req-B", "X-Req-A"), ResponseHeaders("X-Re-1", "X-Re-2")) c.Assert(err, IsNil) srv := httptest.NewServer(t) defer srv.Close() reqHeaders := http.Header{"X-Req-A": []string{"1", "2"}, "X-Req-B": []string{"3", "4"}} re, _, err := testutils.Get(srv.URL+"/hello", testutils.Headers(reqHeaders)) c.Assert(err, IsNil) c.Assert(re.StatusCode, Equals, http.StatusOK) var r *Record c.Assert(json.Unmarshal(trace.Bytes(), &r), IsNil) c.Assert(r.Request.Headers, DeepEquals, reqHeaders) c.Assert(r.Response.Headers, DeepEquals, respHeaders) }
func (s *CBSuite) TestRedirect(c *C) { handler := http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { w.Write([]byte("hello")) }) cb, err := New(handler, triggerNetRatio, Clock(s.clock), Fallback(fallbackRedirect)) c.Assert(err, IsNil) srv := httptest.NewServer(cb) defer srv.Close() cb.metrics = statsNetErrors(0.6) re, _, err := testutils.Get(srv.URL) c.Assert(err, IsNil) client := &http.Client{ CheckRedirect: func(req *http.Request, via []*http.Request) error { return fmt.Errorf("no redirects") }, } re, err = client.Get(srv.URL) c.Assert(err, NotNil) c.Assert(re.StatusCode, Equals, http.StatusFound) c.Assert(re.Header.Get("Location"), Equals, "http://localhost:5000") }
// Make sure that stream handler preserves TLS settings func (s *STSuite) TestPreservesTLS(c *C) { srv := testutils.NewHandler(func(w http.ResponseWriter, req *http.Request) { w.WriteHeader(http.StatusOK) w.Write([]byte("ok")) }) defer srv.Close() // forwarder will proxy the request to whatever destination fwd, err := forward.New() c.Assert(err, IsNil) var t *tls.ConnectionState // this is our redirect to server rdr := http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { t = req.TLS req.URL = testutils.ParseURI(srv.URL) fwd.ServeHTTP(w, req) }) // stream handler will forward requests to redirect st, err := New(rdr, Logger(utils.NewFileLogger(os.Stdout, utils.INFO))) c.Assert(err, IsNil) proxy := httptest.NewUnstartedServer(st) proxy.StartTLS() defer proxy.Close() re, _, err := testutils.Get(proxy.URL) c.Assert(err, IsNil) c.Assert(re.StatusCode, Equals, http.StatusOK) c.Assert(t, NotNil) }
func (s *STSuite) TestNoBody(c *C) { srv := testutils.NewHandler(func(w http.ResponseWriter, req *http.Request) { w.WriteHeader(http.StatusOK) }) defer srv.Close() // forwarder will proxy the request to whatever destination fwd, err := forward.New() c.Assert(err, IsNil) // this is our redirect to server rdr := http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { req.URL = testutils.ParseURI(srv.URL) fwd.ServeHTTP(w, req) }) // stream handler will forward requests to redirect st, err := New(rdr, Logger(utils.NewFileLogger(os.Stdout, utils.INFO))) c.Assert(err, IsNil) proxy := httptest.NewServer(st) defer proxy.Close() re, _, err := testutils.Get(proxy.URL) c.Assert(err, IsNil) c.Assert(re.StatusCode, Equals, http.StatusOK) }
func (s *STSuite) TestCustomErrorHandler(c *C) { srv := testutils.NewHandler(func(w http.ResponseWriter, req *http.Request) { w.Write([]byte("hello, this response is too large")) }) defer srv.Close() // forwarder will proxy the request to whatever destination fwd, err := forward.New() c.Assert(err, IsNil) // this is our redirect to server rdr := http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { req.URL = testutils.ParseURI(srv.URL) fwd.ServeHTTP(w, req) }) // stream handler will forward requests to redirect errHandler := utils.ErrorHandlerFunc(func(w http.ResponseWriter, req *http.Request, err error) { w.WriteHeader(http.StatusTeapot) w.Write([]byte(http.StatusText(http.StatusTeapot))) }) st, err := New(rdr, Logger(utils.NewFileLogger(os.Stdout, utils.INFO)), MaxResponseBodyBytes(4), ErrorHandler(errHandler)) c.Assert(err, IsNil) proxy := httptest.NewServer(st) defer proxy.Close() re, _, err := testutils.Get(proxy.URL) c.Assert(err, IsNil) c.Assert(re.StatusCode, Equals, http.StatusTeapot) }
func (s *FwdSuite) TestForwardedProto(c *C) { var proto string srv := testutils.NewHandler(func(w http.ResponseWriter, req *http.Request) { proto = req.Header.Get(XForwardedProto) w.Write([]byte("hello")) }) defer srv.Close() buf := &bytes.Buffer{} l := utils.NewFileLogger(buf, utils.INFO) f, err := New(Logger(l)) c.Assert(err, IsNil) proxy := http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { req.URL = testutils.ParseURI(srv.URL) f.ServeHTTP(w, req) }) tproxy := httptest.NewUnstartedServer(proxy) tproxy.StartTLS() defer tproxy.Close() re, _, err := testutils.Get(tproxy.URL) c.Assert(err, IsNil) c.Assert(re.StatusCode, Equals, http.StatusOK) c.Assert(proto, Equals, "https") c.Assert(strings.Contains(buf.String(), "tls"), Equals, true) }
func (s *STSuite) TestRequestLimitReached(c *C) { srv := testutils.NewHandler(func(w http.ResponseWriter, req *http.Request) { w.Write([]byte("hello")) }) defer srv.Close() // forwarder will proxy the request to whatever destination fwd, err := forward.New() c.Assert(err, IsNil) // this is our redirect to server rdr := http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { req.URL = testutils.ParseURI(srv.URL) fwd.ServeHTTP(w, req) }) // stream handler will forward requests to redirect st, err := New(rdr, Logger(utils.NewFileLogger(os.Stdout, utils.INFO)), MaxRequestBodyBytes(4)) c.Assert(err, IsNil) proxy := httptest.NewServer(st) defer proxy.Close() re, _, err := testutils.Get(proxy.URL, testutils.Body("this request is too long")) c.Assert(err, IsNil) c.Assert(re.StatusCode, Equals, http.StatusRequestEntityTooLarge) }
func seq(c *C, url string, repeat int) []string { out := []string{} for i := 0; i < repeat; i++ { _, body, err := testutils.Get(url) c.Assert(err, IsNil) out = append(out, string(body)) } return out }
func (s *RRSuite) TestNoServers(c *C) { fwd, err := forward.New() c.Assert(err, IsNil) lb, err := New(fwd) c.Assert(err, IsNil) proxy := httptest.NewServer(lb) defer proxy.Close() re, _, err := testutils.Get(proxy.URL) c.Assert(err, IsNil) c.Assert(re.StatusCode, Equals, http.StatusInternalServerError) }
func (s *FwdSuite) TestDefaultErrHandler(c *C) { f, err := New() c.Assert(err, IsNil) proxy := testutils.NewHandler(func(w http.ResponseWriter, req *http.Request) { req.URL = testutils.ParseURI("http://localhost:63450") f.ServeHTTP(w, req) }) defer proxy.Close() re, _, err := testutils.Get(proxy.URL) c.Assert(err, IsNil) c.Assert(re.StatusCode, Equals, http.StatusBadGateway) }
func (s *CBSuite) TestTriggerDuringRecovery(c *C) { handler := http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { w.Write([]byte("hello")) }) cb, err := New(handler, triggerNetRatio, Clock(s.clock), CheckPeriod(time.Microsecond)) c.Assert(err, IsNil) srv := httptest.NewServer(cb) defer srv.Close() cb.metrics = statsNetErrors(0.6) re, _, err := testutils.Get(srv.URL) c.Assert(err, IsNil) c.Assert(cb.state, Equals, cbState(stateTripped)) // We should be in recovering state by now s.advanceTime(10*time.Second + time.Millisecond) re, _, err = testutils.Get(srv.URL) c.Assert(err, IsNil) c.Assert(re.StatusCode, Equals, http.StatusServiceUnavailable) c.Assert(cb.state, Equals, cbState(stateRecovering)) // We have matched error condition during recovery state and are going back to tripped state s.advanceTime(5 * time.Second) cb.metrics = statsNetErrors(0.6) allowed := 0 for i := 0; i < 100; i++ { re, _, err = testutils.Get(srv.URL) if re.StatusCode == http.StatusOK && err == nil { allowed++ } } c.Assert(allowed, Not(Equals), 0) c.Assert(cb.state, Equals, cbState(stateTripped)) }
func (s *CBSuite) TestStandbyCycle(c *C) { handler := http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { w.Write([]byte("hello")) }) cb, err := New(handler, triggerNetRatio) c.Assert(err, IsNil) srv := httptest.NewServer(cb) defer srv.Close() re, body, err := testutils.Get(srv.URL) c.Assert(err, IsNil) c.Assert(re.StatusCode, Equals, http.StatusOK) c.Assert(string(body), Equals, "hello") }
func (s *CBSuite) TestFullCycle(c *C) { handler := http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { w.Write([]byte("hello")) }) cb, err := New(handler, triggerNetRatio, Clock(s.clock)) c.Assert(err, IsNil) srv := httptest.NewServer(cb) defer srv.Close() re, _, err := testutils.Get(srv.URL) c.Assert(err, IsNil) c.Assert(re.StatusCode, Equals, http.StatusOK) cb.metrics = statsNetErrors(0.6) s.advanceTime(defaultCheckPeriod + time.Millisecond) re, _, err = testutils.Get(srv.URL) c.Assert(err, IsNil) c.Assert(cb.state, Equals, cbState(stateTripped)) // Some time has passed, but we are still in trpped state. s.advanceTime(9 * time.Second) re, _, err = testutils.Get(srv.URL) c.Assert(err, IsNil) c.Assert(re.StatusCode, Equals, http.StatusServiceUnavailable) c.Assert(cb.state, Equals, cbState(stateTripped)) // We should be in recovering state by now s.advanceTime(time.Second*1 + time.Millisecond) re, _, err = testutils.Get(srv.URL) c.Assert(err, IsNil) c.Assert(re.StatusCode, Equals, http.StatusServiceUnavailable) c.Assert(cb.state, Equals, cbState(stateRecovering)) // 5 seconds after we should be allowing some requests to pass s.advanceTime(5 * time.Second) allowed := 0 for i := 0; i < 100; i++ { re, _, err = testutils.Get(srv.URL) if re.StatusCode == http.StatusOK && err == nil { allowed++ } } c.Assert(allowed, Not(Equals), 0) // After some time, all is good and we should be in stand by mode again s.advanceTime(5*time.Second + time.Millisecond) re, _, err = testutils.Get(srv.URL) c.Assert(cb.state, Equals, cbState(stateStandby)) c.Assert(err, IsNil) c.Assert(re.StatusCode, Equals, http.StatusOK) }
func (s *FwdSuite) TestCustomErrHandler(c *C) { f, err := New(ErrorHandler(utils.ErrorHandlerFunc(func(w http.ResponseWriter, req *http.Request, err error) { w.WriteHeader(http.StatusTeapot) w.Write([]byte(http.StatusText(http.StatusTeapot))) }))) c.Assert(err, IsNil) proxy := testutils.NewHandler(func(w http.ResponseWriter, req *http.Request) { req.URL = testutils.ParseURI("http://localhost:63450") f.ServeHTTP(w, req) }) defer proxy.Close() re, body, err := testutils.Get(proxy.URL) c.Assert(err, IsNil) c.Assert(re.StatusCode, Equals, http.StatusTeapot) c.Assert(string(body), Equals, http.StatusText(http.StatusTeapot)) }
func (s *RTSuite) TestSuccess(c *C) { srv := testutils.NewHandler(func(w http.ResponseWriter, req *http.Request) { w.Write([]byte("hello")) }) defer srv.Close() lb, rt := new(c, `IsNetworkError() && Attempts() <= 2`) proxy := httptest.NewServer(rt) defer proxy.Close() lb.UpsertServer(testutils.ParseURI(srv.URL)) re, body, err := testutils.Get(proxy.URL) c.Assert(err, IsNil) c.Assert(re.StatusCode, Equals, http.StatusOK) c.Assert(string(body), Equals, "hello") }
// We've failed to extract client ip func (s *LimiterSuite) TestFailure(c *C) { handler := http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { w.Write([]byte("hello")) }) rates := NewRateSet() rates.Add(time.Second, 1, 1) l, err := New(handler, faultyExtract, rates, Clock(s.clock)) c.Assert(err, IsNil) srv := httptest.NewServer(l) defer srv.Close() re, _, err := testutils.Get(srv.URL, testutils.Header("Source", "a")) c.Assert(err, IsNil) c.Assert(re.StatusCode, Equals, http.StatusInternalServerError) }
func (s *RRSuite) TestCustomErrHandler(c *C) { errHandler := utils.ErrorHandlerFunc(func(w http.ResponseWriter, req *http.Request, err error) { w.WriteHeader(http.StatusTeapot) w.Write([]byte(http.StatusText(http.StatusTeapot))) }) fwd, err := forward.New() c.Assert(err, IsNil) lb, err := New(fwd, ErrorHandler(errHandler)) c.Assert(err, IsNil) proxy := httptest.NewServer(lb) defer proxy.Close() re, _, err := testutils.Get(proxy.URL) c.Assert(err, IsNil) c.Assert(re.StatusCode, Equals, http.StatusTeapot) }
func (s *RTSuite) TestRetryExceedAttempts(c *C) { srv := testutils.NewHandler(func(w http.ResponseWriter, req *http.Request) { w.Write([]byte("hello")) }) defer srv.Close() lb, rt := new(c, `IsNetworkError() && Attempts() <= 2`) proxy := httptest.NewServer(rt) defer proxy.Close() lb.UpsertServer(testutils.ParseURI("http://localhost:64321")) lb.UpsertServer(testutils.ParseURI("http://localhost:64322")) lb.UpsertServer(testutils.ParseURI("http://localhost:64323")) lb.UpsertServer(testutils.ParseURI(srv.URL)) re, _, err := testutils.Get(proxy.URL) c.Assert(err, IsNil) c.Assert(re.StatusCode, Equals, http.StatusBadGateway) }
func (s *FwdSuite) TestCustomLogger(c *C) { srv := testutils.NewHandler(func(w http.ResponseWriter, req *http.Request) { w.Write([]byte("hello")) }) defer srv.Close() buf := &bytes.Buffer{} l := utils.NewFileLogger(buf, utils.INFO) f, err := New(Logger(l)) c.Assert(err, IsNil) proxy := testutils.NewHandler(func(w http.ResponseWriter, req *http.Request) { req.URL = testutils.ParseURI(srv.URL) f.ServeHTTP(w, req) }) defer proxy.Close() re, _, err := testutils.Get(proxy.URL) c.Assert(err, IsNil) c.Assert(re.StatusCode, Equals, http.StatusOK) c.Assert(strings.Contains(buf.String(), srv.URL), Equals, true) }
func (s *FwdSuite) TestCustomTransportTimeout(c *C) { srv := testutils.NewHandler(func(w http.ResponseWriter, req *http.Request) { time.Sleep(20 * time.Millisecond) w.Write([]byte("hello")) }) defer srv.Close() f, err := New(RoundTripper( &http.Transport{ ResponseHeaderTimeout: 5 * time.Millisecond, })) c.Assert(err, IsNil) proxy := testutils.NewHandler(func(w http.ResponseWriter, req *http.Request) { req.URL = testutils.ParseURI(srv.URL) f.ServeHTTP(w, req) }) defer proxy.Close() re, _, err := testutils.Get(proxy.URL) c.Assert(err, IsNil) c.Assert(re.StatusCode, Equals, http.StatusGatewayTimeout) }
// Makes sure hop-by-hop headers are removed func (s *FwdSuite) TestForwardHopHeaders(c *C) { called := false var outHeaders http.Header var outHost, expectedHost string srv := testutils.NewHandler(func(w http.ResponseWriter, req *http.Request) { called = true outHeaders = req.Header outHost = req.Host w.Write([]byte("hello")) }) defer srv.Close() f, err := New() c.Assert(err, IsNil) proxy := testutils.NewHandler(func(w http.ResponseWriter, req *http.Request) { req.URL = testutils.ParseURI(srv.URL) expectedHost = req.URL.Host f.ServeHTTP(w, req) }) defer proxy.Close() headers := http.Header{ Connection: []string{"close"}, KeepAlive: []string{"timeout=600"}, } re, body, err := testutils.Get(proxy.URL, testutils.Headers(headers)) c.Assert(err, IsNil) c.Assert(string(body), Equals, "hello") c.Assert(re.StatusCode, Equals, http.StatusOK) c.Assert(called, Equals, true) c.Assert(outHeaders.Get(Connection), Equals, "") c.Assert(outHeaders.Get(KeepAlive), Equals, "") c.Assert(outHost, Equals, expectedHost) }
func (s *FwdSuite) TestChunkedResponseConversion(c *C) { srv := testutils.NewHandler(func(w http.ResponseWriter, req *http.Request) { h := w.(http.Hijacker) conn, _, _ := h.Hijack() fmt.Fprintf(conn, "HTTP/1.0 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n4\r\ntest\r\n5\r\ntest1\r\n5\r\ntest2\r\n0\r\n\r\n") conn.Close() }) defer srv.Close() f, err := New() c.Assert(err, IsNil) proxy := testutils.NewHandler(func(w http.ResponseWriter, req *http.Request) { req.URL = testutils.ParseURI(srv.URL) f.ServeHTTP(w, req) }) defer proxy.Close() re, body, err := testutils.Get(proxy.URL) c.Assert(err, IsNil) c.Assert(string(body), Equals, "testtest1test2") c.Assert(re.StatusCode, Equals, http.StatusOK) c.Assert(re.Header.Get("Content-Length"), Equals, fmt.Sprintf("%d", len("testtest1test2"))) }
func (s *CBSuite) TestSideEffects(c *C) { srv1Chan := make(chan *http.Request, 1) var srv1Body []byte srv1 := testutils.NewHandler(func(w http.ResponseWriter, r *http.Request) { b, err := ioutil.ReadAll(r.Body) c.Assert(err, IsNil) srv1Body = b w.Write([]byte("srv1")) srv1Chan <- r }) defer srv1.Close() srv2Chan := make(chan *http.Request, 1) srv2 := testutils.NewHandler(func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("srv2")) r.ParseForm() srv2Chan <- r }) defer srv2.Close() onTripped, err := NewWebhookSideEffect( Webhook{ URL: fmt.Sprintf("%s/post.json", srv1.URL), Method: "POST", Headers: map[string][]string{"Content-Type": []string{"application/json"}}, Body: []byte(`{"Key": ["val1", "val2"]}`), }) c.Assert(err, IsNil) onStandby, err := NewWebhookSideEffect( Webhook{ URL: fmt.Sprintf("%s/post", srv2.URL), Method: "POST", Form: map[string][]string{"key": []string{"val1", "val2"}}, }) c.Assert(err, IsNil) handler := http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { w.Write([]byte("hello")) }) cb, err := New(handler, triggerNetRatio, Clock(s.clock), CheckPeriod(time.Microsecond), OnTripped(onTripped), OnStandby(onStandby)) c.Assert(err, IsNil) srv := httptest.NewServer(cb) defer srv.Close() cb.metrics = statsNetErrors(0.6) _, _, err = testutils.Get(srv.URL) c.Assert(err, IsNil) c.Assert(cb.state, Equals, cbState(stateTripped)) select { case req := <-srv1Chan: c.Assert(req.Method, Equals, "POST") c.Assert(req.URL.Path, Equals, "/post.json") c.Assert(string(srv1Body), Equals, `{"Key": ["val1", "val2"]}`) c.Assert(req.Header.Get("Content-Type"), Equals, "application/json") case <-time.After(time.Second): c.Error("timeout waiting for side effect to kick off") } // Transition to recovering state s.advanceTime(10*time.Second + time.Millisecond) cb.metrics = statsOK() testutils.Get(srv.URL) c.Assert(cb.state, Equals, cbState(stateRecovering)) // Going back to standby s.advanceTime(10*time.Second + time.Millisecond) testutils.Get(srv.URL) c.Assert(cb.state, Equals, cbState(stateStandby)) select { case req := <-srv2Chan: c.Assert(req.Method, Equals, "POST") c.Assert(req.URL.Path, Equals, "/post") c.Assert(req.Form, DeepEquals, url.Values{"key": []string{"val1", "val2"}}) case <-time.After(time.Second): c.Error("timeout waiting for side effect to kick off") } }