func createDecorator(name string, order *callOrder) kapusta.DecoratorFunc { return func(c kapusta.IClient) kapusta.IClient { return kapusta.ClientFunc(func(r *http.Request) (*http.Response, error) { *order = append(*order, name) return c.Do(r) }) } }
// HeadersDecorator returns a DecoratorFunc that adds the given HTTP headers to every request done by a Client. func HeadersDecorator(values map[string]string) kapusta.DecoratorFunc { return func(c kapusta.IClient) kapusta.IClient { return kapusta.ClientFunc(func(r *http.Request) (*http.Response, error) { for key, value := range values { r.Header.Add(key, value) } return c.Do(r) }) } }
// RecoverDecorator returns a DecoratorFunc that recovers panic and convert it to error func RecoverDecorator() kapusta.DecoratorFunc { return func(c kapusta.IClient) kapusta.IClient { return kapusta.ClientFunc(func(r *http.Request) (res *http.Response, err error) { defer func() { if r := recover(); r != nil { err = fmt.Errorf("recovered panic: %v", r) } }() return c.Do(r) }) } }
func (s *TestSuite) TestPanicDecorator(c *C) { panicTriggerDecorator := func(c kapusta.IClient) kapusta.IClient { return kapusta.ClientFunc(func(r *http.Request) (res *http.Response, err error) { panic("oops") }) } r, _ := http.NewRequest("GET", "/", nil) client := kapusta.Decorate(s.dummyClient, panicTriggerDecorator, RecoverDecorator()) res, err := client.Do(r) c.Assert(res, IsNil) c.Assert(err, ErrorMatches, "*oops") }
// LoggerDecorator returns DecoratorFunc that logs before and after request func LoggerDecorator(logger logger.ILogger, dumpRequests bool) kapusta.DecoratorFunc { return func(c kapusta.IClient) kapusta.IClient { return kapusta.ClientFunc(func(r *http.Request) (*http.Response, error) { logger.Debugf("start request: %v", r.URL) var bodyBytes []byte if dumpRequests { // We should preserve Body before Do and restore it after Do, because Body is io.ReadCloser and // it will have already been read after Do. DumpRequestOut is going to read Body again. if r.Body != nil { bodyBytes, _ = ioutil.ReadAll(r.Body) } // Restore the io.ReadCloser to its original state r.Body = ioutil.NopCloser(bytes.NewBuffer(bodyBytes)) } response, err := c.Do(r) if dumpRequests { // Restore the io.ReadCloser to its original state again, because it has been already read by Do r.Body = ioutil.NopCloser(bytes.NewBuffer(bodyBytes)) if requestDump, requestReadErr := httputil.DumpRequestOut(r, true); requestReadErr == nil { logger.Debugf("dump request to %v:\n%s", r.URL, string(requestDump)) } else { logger.Debugf("can't dump request to %v\nError: %v", r.URL, requestReadErr) } } if err != nil { logger.Errorf("done request: %v, error: %v", r.URL, err) return nil, err } logger.Debugf("done request: %v, HTTP status: %s", r.URL, response.Status) if dumpRequests { if responseDump, responseReadErr := httputil.DumpResponse(response, true); responseReadErr == nil { logger.Debugf("dump response from %v:\n%s", r.URL, string(responseDump)) } else { logger.Debugf("can't dump response from %v\nError: %v", r.URL, responseReadErr) } } return response, err }) } }
// BaseURLDecorator returns a DecoratorFunc that replaces scheme and host in request from specified baseURL func BaseURLDecorator(baseURL string) kapusta.DecoratorFunc { parsed, err := url.Parse(baseURL) if err != nil { panic(err) } return func(c kapusta.IClient) kapusta.IClient { return kapusta.ClientFunc(func(r *http.Request) (*http.Response, error) { r.URL.Scheme = parsed.Scheme r.URL.Host = parsed.Host return c.Do(r) }) } }