Skip to content

Commit

Permalink
Add new mock client to match responses by endpoint (#485)
Browse files Browse the repository at this point in the history
* Add new MatchingByEndpointClient

* Add unit tests
  • Loading branch information
claudia-correia authored Sep 18, 2024
1 parent e3672b5 commit d8b9435
Show file tree
Hide file tree
Showing 3 changed files with 419 additions and 0 deletions.
16 changes: 16 additions & 0 deletions pkg/api/mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,3 +85,19 @@ func NewDebugMock(o io.Writer, res ...mock.Response) *API {

return api
}

// NewMockMatchingByEndpoint creates a new api.API from a list of Responses, matching by endpoint.
// Defaults to a dummy APIKey for authentication, which is not checked
func NewMockMatchingByEndpoint(res map[string][]mock.Response) *API {
api, err := NewAPI(Config{
Client: mock.NewMatchingByEndpointClient(res),
Host: mockSchemaHost,
AuthWriter: auth.APIKey("dummy"),
})

if err != nil {
panic(err)
}

return api
}
48 changes: 48 additions & 0 deletions pkg/api/mock/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,58 @@ package mock
import (
"fmt"
"net/http"
"regexp"
"sync"
"sync/atomic"
)

// NewMatchingByEndpointClient returns a pointer to http.Client with the mocked Transport.
func NewMatchingByEndpointClient(r map[string][]Response) *http.Client {
return &http.Client{
Transport: NewMatchingByEndpointRoundTripper(r),
}
}

// NewRoundTripper initializes a new roundtripper and accepts multiple Response
// structures as variadric arguments.
func NewMatchingByEndpointRoundTripper(r map[string][]Response) *MatchingByEndpointRoundTripper {
responsesByEndpoint := make(map[string]*RoundTripper)

for endpoint, responses := range r {
responsesByEndpoint[endpoint] = &RoundTripper{
Responses: responses,
}
}

return &MatchingByEndpointRoundTripper{
ResponsesByEndpoint: responsesByEndpoint,
}
}

// MatchingByEndpointRoundTripper is aimed to be used as the Transport property in an http.Client
// in order to mock the responses that it would return in the normal execution, matching by endpoint.
// If the number of responses that are mocked for a specific endpoint are not enough, an error with the
// request iteration ID, method and full URL is returned.
type MatchingByEndpointRoundTripper struct {
ResponsesByEndpoint map[string]*RoundTripper
}

// RoundTrip executes a single HTTP transaction, returning
// a Response for the provided Request, based on the Request's URL.
func (rt *MatchingByEndpointRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
for endpoint, rt := range rt.ResponsesByEndpoint {
endpointRegex := regexp.MustCompile(endpoint)

if endpointRegex.MatchString(req.URL.Path) {
return rt.RoundTrip(req)
}
}

return nil, fmt.Errorf(
"failed to obtain response for request: %s %s", req.Method, req.URL,
)
}

// NewClient returns a pointer to http.Client with the mocked Transport.
func NewClient(r ...Response) *http.Client {
return &http.Client{
Expand Down
Loading

0 comments on commit d8b9435

Please sign in to comment.