123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103 |
- package gock
- import (
- "bytes"
- "io"
- "net/http"
- "strconv"
- "time"
- )
- // Responder builds a mock http.Response based on the given Response mock.
- func Responder(req *http.Request, mock *Response, res *http.Response) (*http.Response, error) {
- // If error present, reply it
- err := mock.Error
- if err != nil {
- return nil, err
- }
- if res == nil {
- res = createResponse(req)
- }
- // Apply response filter
- for _, filter := range mock.Filters {
- if !filter(res) {
- return res, nil
- }
- }
- // Define mock status code
- if mock.StatusCode != 0 {
- res.Status = strconv.Itoa(mock.StatusCode) + " " + http.StatusText(mock.StatusCode)
- res.StatusCode = mock.StatusCode
- }
- // Define headers by merging fields
- res.Header = mergeHeaders(res, mock)
- // Define mock body, if present
- if len(mock.BodyBuffer) > 0 {
- res.ContentLength = int64(len(mock.BodyBuffer))
- res.Body = createReadCloser(mock.BodyBuffer)
- }
- // Apply response mappers
- for _, mapper := range mock.Mappers {
- if tres := mapper(res); tres != nil {
- res = tres
- }
- }
- // Sleep to simulate delay, if necessary
- if mock.ResponseDelay > 0 {
- time.Sleep(mock.ResponseDelay)
- }
- return res, err
- }
- // createResponse creates a new http.Response with default fields.
- func createResponse(req *http.Request) *http.Response {
- return &http.Response{
- ProtoMajor: 1,
- ProtoMinor: 1,
- Proto: "HTTP/1.1",
- Request: req,
- Header: make(http.Header),
- Body: createReadCloser([]byte{}),
- }
- }
- // mergeHeaders copies the mock headers.
- func mergeHeaders(res *http.Response, mres *Response) http.Header {
- for key := range mres.Header {
- res.Header.Set(key, mres.Header.Get(key))
- }
- return res.Header
- }
- // createReadCloser creates an io.ReadCloser from a byte slice that is suitable for use as an
- // http response body.
- func createReadCloser(body []byte) io.ReadCloser {
- return &dummyReadCloser{body: bytes.NewReader(body)}
- }
- // dummyReadCloser is used internally as io.ReadCloser capable interface for bodies.
- type dummyReadCloser struct {
- body io.ReadSeeker
- }
- // Read implements the required method by io.ReadClose interface.
- func (d *dummyReadCloser) Read(p []byte) (n int, err error) {
- n, err = d.body.Read(p)
- if err == io.EOF {
- d.body.Seek(0, 0)
- }
- return n, err
- }
- // Close implements a no-op required method by io.ReadClose interface.
- func (d *dummyReadCloser) Close() error {
- return nil
- }
|