Skip to content

Commit

Permalink
Merge pull request #119 from jarcoal/unregister
Browse files Browse the repository at this point in the history
feat: registering a nil responder unregisters it
  • Loading branch information
maxatome authored Dec 22, 2021
2 parents 5115a49 + b1c767b commit a62b874
Show file tree
Hide file tree
Showing 2 changed files with 121 additions and 15 deletions.
90 changes: 76 additions & 14 deletions transport.go
Original file line number Diff line number Diff line change
Expand Up @@ -364,7 +364,14 @@ func (m *MockTransport) checkMethod(method string) {
// GetCallCountInfo(). As 2 regexps can match the same URL, the regexp
// responders are tested in the order they are registered. Registering
// an already existing regexp responder (same method & same regexp
// string) replaces its responder but does not change its position.
// string) replaces its responder, but does not change its position.
//
// Registering an already existing responder resets the corresponding
// statistics as returned by GetCallCountInfo().
//
// Registering a nil Responder removes the existing one and the
// corresponding statistics as returned by GetCallCountInfo(). It does
// nothing if it does not already exist.
//
// See RegisterRegexpResponder() to directly pass a *regexp.Regexp.
//
Expand Down Expand Up @@ -410,31 +417,49 @@ func (m *MockTransport) RegisterResponder(method, url string, responder Responde
}

m.mu.Lock()
m.responders[key] = responder
m.callCountInfo[key] = 0
if responder == nil {
delete(m.responders, key)
delete(m.callCountInfo, key)
} else {
m.responders[key] = responder
m.callCountInfo[key] = 0
}
m.mu.Unlock()
}

func (m *MockTransport) registerRegexpResponder(regexpResponder regexpResponder) {
func (m *MockTransport) registerRegexpResponder(rxResp regexpResponder) {
m.mu.Lock()
defer m.mu.Unlock()

found:
for {
for i, rr := range m.regexpResponders {
if rr.method == regexpResponder.method && rr.origRx == regexpResponder.origRx {
m.regexpResponders[i] = regexpResponder
if rr.method == rxResp.method && rr.origRx == rxResp.origRx {
if rxResp.responder == nil {
copy(m.regexpResponders[:i], m.regexpResponders[i+1:])
m.regexpResponders[len(m.regexpResponders)-1] = regexpResponder{}
m.regexpResponders = m.regexpResponders[:len(m.regexpResponders)-1]
} else {
m.regexpResponders[i] = rxResp
}
break found
}
}
m.regexpResponders = append(m.regexpResponders, regexpResponder)
if rxResp.responder != nil {
m.regexpResponders = append(m.regexpResponders, rxResp)
}
break // nolint: staticcheck
}

m.callCountInfo[internal.RouteKey{
Method: regexpResponder.method,
URL: regexpResponder.origRx,
}] = 0
key := internal.RouteKey{
Method: rxResp.method,
URL: rxResp.origRx,
}
if rxResp.responder == nil {
delete(m.callCountInfo, key)
} else {
m.callCountInfo[key] = 0
}
}

// RegisterRegexpResponder adds a new responder, associated with a given
Expand All @@ -446,7 +471,12 @@ found:
// As 2 regexps can match the same URL, the regexp responders are
// tested in the order they are registered. Registering an already
// existing regexp responder (same method & same regexp string)
// replaces its responder but does not change its position.
// replaces its responder, but does not change its position, and
// resets the corresponding statistics as returned by GetCallCountInfo().
//
// Registering a nil Responder removes the existing one and the
// corresponding statistics as returned by GetCallCountInfo(). It does
// nothing if it does not already exist.
//
// A "=~" prefix is added to the stringified regexp in the statistics
// returned by GetCallCountInfo().
Expand Down Expand Up @@ -483,6 +513,13 @@ func (m *MockTransport) RegisterRegexpResponder(method string, urlRegexp *regexp
// Unlike RegisterResponder, path cannot be prefixed by "=~" to say it
// is a regexp. If it is, a panic occurs.
//
// Registering an already existing responder resets the corresponding
// statistics as returned by GetCallCountInfo().
//
// Registering a nil Responder removes the existing one and the
// corresponding statistics as returned by GetCallCountInfo(). It does
// nothing if it does not already exist.
//
// If method is a lower-cased version of CONNECT, DELETE, GET, HEAD,
// OPTIONS, POST, PUT or TRACE, a panics occurs to notice the possible
// mistake. This panic can be disabled by setting m.DontCheckMethod to
Expand Down Expand Up @@ -581,6 +618,9 @@ func sortedQuery(m url.Values) string {
// at /go/src/testing/testing.go:865
// testing.tRunner()
// at /go/src/runtime/asm_amd64.s:1337
//
// If responder is passed as nil, the default behavior
// (httpmock.ConnectionFailure) is re-enabled.
func (m *MockTransport) RegisterNoResponder(responder Responder) {
m.mu.Lock()
m.noResponder = responder
Expand Down Expand Up @@ -812,7 +852,14 @@ func DeactivateAndReset() {
// GetCallCountInfo(). As 2 regexps can match the same URL, the regexp
// responders are tested in the order they are registered. Registering
// an already existing regexp responder (same method & same regexp
// string) replaces its responder but does not change its position.
// string) replaces its responder, but does not change its position.
//
// Registering an already existing responder resets the corresponding
// statistics as returned by GetCallCountInfo().
//
// Registering a nil Responder removes the existing one and the
// corresponding statistics as returned by GetCallCountInfo(). It does
// nothing if it does not already exist.
//
// See RegisterRegexpResponder() to directly pass a *regexp.Regexp.
//
Expand Down Expand Up @@ -852,7 +899,12 @@ func RegisterResponder(method, url string, responder Responder) {
// As 2 regexps can match the same URL, the regexp responders are
// tested in the order they are registered. Registering an already
// existing regexp responder (same method & same regexp string)
// replaces its responder but does not change its position.
// replaces its responder, but does not change its position, and
// resets the corresponding statistics as returned by GetCallCountInfo().
//
// Registering a nil Responder removes the existing one and the
// corresponding statistics as returned by GetCallCountInfo(). It does
// nothing if it does not already exist.
//
// A "=~" prefix is added to the stringified regexp in the statistics
// returned by GetCallCountInfo().
Expand All @@ -879,6 +931,16 @@ func RegisterRegexpResponder(method string, urlRegexp *regexp.Regexp, responder
// If the query type is not recognized or the string cannot be parsed
// using net/url.ParseQuery, a panic() occurs.
//
// Unlike RegisterResponder, path cannot be prefixed by "=~" to say it
// is a regexp. If it is, a panic occurs.
//
// Registering an already existing responder resets the corresponding
// statistics as returned by GetCallCountInfo().
//
// Registering a nil Responder removes the existing one and the
// corresponding statistics as returned by GetCallCountInfo(). It does
// nothing if it does not already exist.
//
// Example using a net/url.Values:
// func TestFetchArticles(t *testing.T) {
// httpmock.Activate()
Expand Down
46 changes: 45 additions & 1 deletion transport_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ func TestMockTransportReset(t *testing.T) {
t.Fatal("expected no responders at this point")
}

RegisterResponder("GET", testURL, nil)
RegisterResponder("GET", testURL, NewStringResponder(200, "hey"))

if DefaultTransport.NumResponders() != 1 {
t.Fatal("expected one responder")
Expand Down Expand Up @@ -687,9 +687,25 @@ func TestMockTransportCallCountZero(t *testing.T) {
if !reflect.DeepEqual(info, expectedInfo) {
t.Fatalf("did not correctly reset the call count info. expected it to be \n %+v\n but it was \n %+v", expectedInfo, info)
}

// Unregister each responder
RegisterResponder("GET", url, nil)
RegisterResponder("POST", "=~gitlab", nil)

info = GetCallCountInfo()
expectedInfo = map[string]int{
// this one remains as it is not directly related to a registered
// responder but a consequence of a regexp match
"POST " + url2: 0,
}
if !reflect.DeepEqual(info, expectedInfo) {
t.Fatalf("did not correctly reset the call count info. expected it to be \n %+v\n but it was \n %+v", expectedInfo, info)
}
}

func TestRegisterResponderWithQuery(t *testing.T) {
Reset()

// Just in case a panic occurs
defer DeactivateAndReset()

Expand Down Expand Up @@ -768,6 +784,34 @@ func TestRegisterResponderWithQuery(t *testing.T) {
assertBody(t, resp, body)
}

if info := GetCallCountInfo(); len(info) != 1 {
t.Fatalf("%s: len(GetCallCountInfo()) should be 1 but contains %+v", testURLPath, info)
}

// Remove...
RegisterResponderWithQuery("GET", testURLPath, query, nil)
if info := GetCallCountInfo(); len(info) != 0 {
t.Fatalf("did not correctly reset the call count info, it still contains %+v", info)
}

for _, url := range test.URLs {
t.Logf("query=%v URL=%s", query, url)

req, err := http.NewRequest("GET", url, nil)
if err != nil {
t.Fatal(err)
}

_, err = client.Do(req)
if err == nil {
t.Fatalf("No error occurred for %s", url)
}

if !strings.HasSuffix(err.Error(), "no responder found") {
t.Errorf("Not expected error suffix: %s", err)
}
}

DeactivateAndReset()
}
}
Expand Down

0 comments on commit a62b874

Please sign in to comment.