Repository: jamielennox/requests-mock

Issue:
redirects not working with second url real_http=True
```
with requests_mock.mock() as req_mock:
    req_mock.post(url1, status_code=HTTPStatus.FOUND, headers={'location': url2})
    req_mock.get(url2, real_http=True)

requests.post(url1)
```

this is resulting ConnectionError (since url1 is not reachable)

from what I can tell the redirection works ok, than mocker._fake_send calling _original_send and adapter._RunRealHTTP is being raised and caught (which is ok), it then tries to restore the original requests session adapter but unfortunately because the first redirection has yet to finish, the original adapter was not restored, so what the second requests consider the original requests session adapter is actually the fake adapter

Comments:

Patch:
diff --git a/requests_mock/mocker.py b/requests_mock/mocker.py
index 0b8565d..9450d12 100644
--- a/requests_mock/mocker.py
+++ b/requests_mock/mocker.py
@@ -89,12 +89,13 @@ class MockerCore(object):
             raise RuntimeError('Mocker has already been started')
 
         self._last_send = requests.Session.send
+        self._last_get_adapter = requests.Session.get_adapter
 
         def _fake_get_adapter(session, url):
             return self._adapter
 
         def _fake_send(session, request, **kwargs):
-            real_get_adapter = requests.Session.get_adapter
+            # mock get_adapter
             requests.Session.get_adapter = _fake_get_adapter
 
             # NOTE(jamielennox): self._last_send vs _original_send. Whilst it
@@ -117,9 +118,13 @@ class MockerCore(object):
                 # requests library rather than the mocking. Let it.
                 pass
             finally:
-                requests.Session.get_adapter = real_get_adapter
+                # restore get_adapter
+                requests.Session.get_adapter = self._last_get_adapter
 
-            return _original_send(session, request, **kwargs)
+            # if we are here it means we must run the real http request
+            # Or, with nested mocks, to the parent mock, that is why we use
+            # _last_send here instead of _original_send
+            return self._last_send(session, request, **kwargs)
 
         requests.Session.send = _fake_send
 


Test patch:
diff --git a/tests/pytest/test_with_pytest.py b/tests/pytest/test_with_pytest.py
index dafccf0..334d73a 100644
--- a/tests/pytest/test_with_pytest.py
+++ b/tests/pytest/test_with_pytest.py
@@ -1,4 +1,12 @@
+try:
+    from http import HTTPStatus
+    HTTP_STATUS_FOUND = HTTPStatus.FOUND
+except ImportError:
+    from httplib import FOUND as HTTP_STATUS_FOUND
+
+import pytest
 import requests
+import requests_mock
 
 
 def test_simple(requests_mock):
@@ -6,6 +14,42 @@ def test_simple(requests_mock):
     assert 'data' == requests.get('https://httpbin.org/get').text
 
 
+def test_redirect_and_nesting():
+    url_inner = "inner_mock://example.test/"
+    url_middle = "middle_mock://example.test/"
+    url_outer = "outer_mock://example.test/"
+    url = "https://www.example.com/"
+    with requests_mock.Mocker() as outer_mock:
+        outer_mock.get(url, text='outer' + url)
+        outer_mock.get(url_outer, text='outer' + url_outer)
+
+        with requests_mock.Mocker(real_http=True) as middle_mock:
+            middle_mock.get(url_middle, text='middle' + url_middle)
+
+            with requests_mock.Mocker() as inner_mock:
+                inner_mock.post(url_inner, status_code=HTTP_STATUS_FOUND, headers={'location': url})
+                inner_mock.get(url, real_http=True)
+
+                assert 'outer' + url == requests.post(url_inner).text  # nosec
+                with pytest.raises(requests_mock.NoMockAddress):
+                    requests.get(url_middle)
+                with pytest.raises(requests_mock.NoMockAddress):
+                    requests.get(url_outer)
+
+            # back to middle mock
+            with pytest.raises(requests_mock.NoMockAddress):
+                requests.post(url_inner)
+            assert 'middle' + url_middle == requests.get(url_middle).text  # nosec
+            assert 'outer' + url_outer == requests.get(url_outer).text  # nosec
+
+        # back to outter mock
+        with pytest.raises(requests_mock.NoMockAddress):
+            requests.post(url_inner)
+        with pytest.raises(requests_mock.NoMockAddress):
+            requests.get(url_middle)
+        assert 'outer' + url_outer == requests.get(url_outer).text  # nosec
+
+
 class TestClass(object):
 
     def configure(self, requests_mock):