Repository: getsentry/responses

Issue:
RequestsMock._on_request misses calls if callback raises BaseException
In case a `BaseException` (or a subclass) is raised in the `get_response()` method of a match object (e.g. in a callback) the call accounting isn't updated for that call.

This then leads to test failures due to `Not all requests have been executed`.

The reason is that only `Exception`s are expected:
https://github.com/getsentry/responses/blob/8b0b9c1883c1242246af3dd535df79bfb071732a/responses.py#L642-L648

I noticed this in the context of `gevent` and its `Timeout` feature which raises an exception inherited from `BaseException`.

Discussion:

Patch:
diff --git a/responses.py b/responses.py
index 3f32125..df42ef5 100644
--- a/responses.py
+++ b/responses.py
@@ -652,7 +652,7 @@ class RequestsMock(object):
 
         try:
             response = adapter.build_response(request, match.get_response(request))
-        except Exception as response:
+        except BaseException as response:
             match.call_count += 1
             self._calls.add(request, response)
             response = resp_callback(response) if resp_callback else response


Test patch:
diff --git a/test_responses.py b/test_responses.py
index 41400ee..af41f3a 100644
--- a/test_responses.py
+++ b/test_responses.py
@@ -749,6 +749,9 @@ def test_response_filebody():
 
 
 def test_assert_all_requests_are_fired():
+    def request_callback(request):
+        raise BaseException()
+
     def run():
         with pytest.raises(AssertionError) as excinfo:
             with responses.RequestsMock(assert_all_requests_are_fired=True) as m:
@@ -782,6 +785,13 @@ def test_assert_all_requests_are_fired():
                 requests.get("http://example.com")
             assert len(m._matches) == 1
 
+        with responses.RequestsMock(assert_all_requests_are_fired=True) as m:
+            m.add_callback(responses.GET, "http://example.com", request_callback)
+            assert len(m._matches) == 1
+            with pytest.raises(BaseException):
+                requests.get("http://example.com")
+            assert len(m._matches) == 1
+
     run()
     assert_reset()