aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/python/requests-mock
diff options
context:
space:
mode:
authormaxim-yurchuk <maxim-yurchuk@yandex-team.com>2024-10-09 12:29:46 +0300
committermaxim-yurchuk <maxim-yurchuk@yandex-team.com>2024-10-09 13:14:22 +0300
commit9731d8a4bb7ee2cc8554eaf133bb85498a4c7d80 (patch)
treea8fb3181d5947c0d78cf402aa56e686130179049 /contrib/python/requests-mock
parenta44b779cd359f06c3ebbef4ec98c6b38609d9d85 (diff)
downloadydb-9731d8a4bb7ee2cc8554eaf133bb85498a4c7d80.tar.gz
publishFullContrib: true for ydb
<HIDDEN_URL> commit_hash:c82a80ac4594723cebf2c7387dec9c60217f603e
Diffstat (limited to 'contrib/python/requests-mock')
-rw-r--r--contrib/python/requests-mock/py2/.dist-info/METADATA144
-rw-r--r--contrib/python/requests-mock/py2/.dist-info/entry_points.txt2
-rw-r--r--contrib/python/requests-mock/py2/.dist-info/top_level.txt1
-rw-r--r--contrib/python/requests-mock/py2/patches/01-fix-tests.patch13
-rw-r--r--contrib/python/requests-mock/py2/requests_mock/__init__.py37
-rw-r--r--contrib/python/requests-mock/py2/requests_mock/__init__.pyi33
-rw-r--r--contrib/python/requests-mock/py2/requests_mock/adapter.py323
-rw-r--r--contrib/python/requests-mock/py2/requests_mock/adapter.pyi75
-rw-r--r--contrib/python/requests-mock/py2/requests_mock/compat.py30
-rw-r--r--contrib/python/requests-mock/py2/requests_mock/contrib/__init__.py0
-rw-r--r--contrib/python/requests-mock/py2/requests_mock/contrib/_pytest_plugin.py86
-rw-r--r--contrib/python/requests-mock/py2/requests_mock/contrib/_pytest_plugin.pyi6
-rw-r--r--contrib/python/requests-mock/py2/requests_mock/contrib/fixture.py27
-rw-r--r--contrib/python/requests-mock/py2/requests_mock/exceptions.py30
-rw-r--r--contrib/python/requests-mock/py2/requests_mock/exceptions.pyi13
-rw-r--r--contrib/python/requests-mock/py2/requests_mock/mocker.py342
-rw-r--r--contrib/python/requests-mock/py2/requests_mock/mocker.pyi263
-rw-r--r--contrib/python/requests-mock/py2/requests_mock/py.typed0
-rw-r--r--contrib/python/requests-mock/py2/requests_mock/request.py178
-rw-r--r--contrib/python/requests-mock/py2/requests_mock/request.pyi41
-rw-r--r--contrib/python/requests-mock/py2/requests_mock/response.py281
-rw-r--r--contrib/python/requests-mock/py2/requests_mock/response.pyi38
-rw-r--r--contrib/python/requests-mock/py2/tests/__init__.py0
-rw-r--r--contrib/python/requests-mock/py2/tests/base.py17
-rw-r--r--contrib/python/requests-mock/py2/tests/pytest/__init__.py0
-rw-r--r--contrib/python/requests-mock/py2/tests/pytest/pytest.ini2
-rw-r--r--contrib/python/requests-mock/py2/tests/pytest/test_with_pytest.py119
-rw-r--r--contrib/python/requests-mock/py2/tests/test_adapter.py707
-rw-r--r--contrib/python/requests-mock/py2/tests/test_custom_matchers.py75
-rw-r--r--contrib/python/requests-mock/py2/tests/test_fixture.py39
-rw-r--r--contrib/python/requests-mock/py2/tests/test_matcher.py324
-rw-r--r--contrib/python/requests-mock/py2/tests/test_mocker.py646
-rw-r--r--contrib/python/requests-mock/py2/tests/test_request.py139
-rw-r--r--contrib/python/requests-mock/py2/tests/test_response.py154
-rw-r--r--contrib/python/requests-mock/py2/tests/ya.make26
-rw-r--r--contrib/python/requests-mock/py2/ya.make56
-rw-r--r--contrib/python/requests-mock/py3/patches/01-fix-tests.patch13
-rw-r--r--contrib/python/requests-mock/py3/patches/02-support-python-3.12.patch5
-rw-r--r--contrib/python/requests-mock/py3/tests/__init__.py0
-rw-r--r--contrib/python/requests-mock/py3/tests/base.py17
-rw-r--r--contrib/python/requests-mock/py3/tests/pytest/__init__.py0
-rw-r--r--contrib/python/requests-mock/py3/tests/pytest/pytest.ini2
-rw-r--r--contrib/python/requests-mock/py3/tests/pytest/test_with_pytest.py119
-rw-r--r--contrib/python/requests-mock/py3/tests/test_adapter.py724
-rw-r--r--contrib/python/requests-mock/py3/tests/test_custom_matchers.py74
-rw-r--r--contrib/python/requests-mock/py3/tests/test_fixture.py39
-rw-r--r--contrib/python/requests-mock/py3/tests/test_matcher.py324
-rw-r--r--contrib/python/requests-mock/py3/tests/test_mocker.py646
-rw-r--r--contrib/python/requests-mock/py3/tests/test_request.py139
-rw-r--r--contrib/python/requests-mock/py3/tests/test_response.py151
-rw-r--r--contrib/python/requests-mock/py3/tests/ya.make26
51 files changed, 6546 insertions, 0 deletions
diff --git a/contrib/python/requests-mock/py2/.dist-info/METADATA b/contrib/python/requests-mock/py2/.dist-info/METADATA
new file mode 100644
index 0000000000..d8eadeaec2
--- /dev/null
+++ b/contrib/python/requests-mock/py2/.dist-info/METADATA
@@ -0,0 +1,144 @@
+Metadata-Version: 2.1
+Name: requests-mock
+Version: 1.11.0
+Summary: Mock out responses from the requests package
+Home-page: https://requests-mock.readthedocs.io/
+Author: Jamie Lennox
+Author-email: jamielennox@gmail.com
+License: Apache-2
+Project-URL: Source, https://github.com/jamielennox/requests-mock
+Classifier: Development Status :: 5 - Production/Stable
+Classifier: Intended Audience :: Developers
+Classifier: Intended Audience :: Information Technology
+Classifier: License :: OSI Approved :: Apache Software License
+Classifier: Operating System :: OS Independent
+Classifier: Programming Language :: Python
+Classifier: Programming Language :: Python :: 2
+Classifier: Programming Language :: Python :: 2.7
+Classifier: Programming Language :: Python :: 3
+Classifier: Programming Language :: Python :: 3.4
+Classifier: Programming Language :: Python :: 3.5
+Classifier: Programming Language :: Python :: 3.6
+Classifier: Programming Language :: Python :: 3.7
+Classifier: Programming Language :: Python :: 3.8
+Classifier: Programming Language :: Python :: 3.9
+Classifier: Programming Language :: Python :: 3.10
+Classifier: Programming Language :: Python :: Implementation :: CPython
+Classifier: Programming Language :: Python :: Implementation :: PyPy
+Classifier: Topic :: Software Development :: Testing
+License-File: LICENSE
+Requires-Dist: requests (<3,>=2.3)
+Requires-Dist: six
+Provides-Extra: fixture
+Requires-Dist: fixtures ; extra == 'fixture'
+Provides-Extra: test
+Requires-Dist: fixtures ; extra == 'test'
+Requires-Dist: purl ; extra == 'test'
+Requires-Dist: pytest ; extra == 'test'
+Requires-Dist: sphinx ; extra == 'test'
+Requires-Dist: testtools ; extra == 'test'
+Requires-Dist: requests-futures ; extra == 'test'
+Requires-Dist: mock ; (( python_version < '3.3')) and extra == 'test'
+
+===============================
+requests-mock
+===============================
+
+.. image:: https://badge.fury.io/py/requests-mock.png
+ :target: https://pypi.org/project/requests-mock/
+
+Intro
+=====
+
+`requests-mock` provides a building block to stub out the HTTP `requests`_ portions of your testing code.
+You should checkout the `docs`_ for more information.
+
+The Basics
+==========
+
+Everything in `requests`_ eventually goes through an adapter to do the transport work.
+`requests-mock` creates a custom `adapter` that allows you to predefine responses when certain URIs are called.
+
+There are then a number of methods provided to get the adapter used.
+
+A simple example:
+
+.. code:: python
+
+ >>> import requests
+ >>> import requests_mock
+
+ >>> session = requests.Session()
+ >>> adapter = requests_mock.Adapter()
+ >>> session.mount('mock://', adapter)
+
+ >>> adapter.register_uri('GET', 'mock://test.com', text='data')
+ >>> resp = session.get('mock://test.com')
+ >>> resp.status_code, resp.text
+ (200, 'data')
+
+Obviously having all URLs be `mock://` prefixed isn't going to be useful,
+so you can use `requests_mock.Mocker` to get the adapter into place.
+
+As a context manager:
+
+.. code:: python
+
+ >>> with requests_mock.Mocker() as m:
+ ... m.get('http://test.com', text='data')
+ ... requests.get('http://test.com').text
+ ...
+ 'data'
+
+Or as a decorator:
+
+.. code:: python
+
+ >>> @requests_mock.Mocker()
+ ... def test_func(m):
+ ... m.get('http://test.com', text='data')
+ ... return requests.get('http://test.com').text
+ ...
+ >>> test_func()
+ 'data'
+
+Or as a pytest fixture:
+
+.. code:: python
+
+ >>> def test_simple(requests_mock):
+ ... requests_mock.get('http://test.com', text='data')
+ ... assert 'data' == requests.get('http://test.com').text
+
+For more information checkout the `docs`_.
+
+Reporting Bugs
+==============
+
+Development and bug tracking is performed on `GitHub`_.
+
+Questions
+=========
+
+There is a tag dedicated to `requests-mock` on `StackOverflow`_ where you can ask usage questions.
+
+License
+=======
+
+Licensed under the Apache License, Version 2.0 (the "License"); you may
+not use this file except in compliance with the License. You may obtain
+a copy of the License at
+
+ https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+License for the specific language governing permissions and limitations
+under the License.
+
+.. _requests: https://requests.readthedocs.io
+.. _docs: https://requests-mock.readthedocs.io/
+.. _GitHub: https://github.com/jamielennox/requests-mock
+.. _StackOverflow: https://stackoverflow.com/questions/tagged/requests-mock
+
diff --git a/contrib/python/requests-mock/py2/.dist-info/entry_points.txt b/contrib/python/requests-mock/py2/.dist-info/entry_points.txt
new file mode 100644
index 0000000000..b157e5a5ec
--- /dev/null
+++ b/contrib/python/requests-mock/py2/.dist-info/entry_points.txt
@@ -0,0 +1,2 @@
+[pytest11]
+requests_mock = requests_mock.contrib._pytest_plugin
diff --git a/contrib/python/requests-mock/py2/.dist-info/top_level.txt b/contrib/python/requests-mock/py2/.dist-info/top_level.txt
new file mode 100644
index 0000000000..65a92dd61d
--- /dev/null
+++ b/contrib/python/requests-mock/py2/.dist-info/top_level.txt
@@ -0,0 +1 @@
+requests_mock
diff --git a/contrib/python/requests-mock/py2/patches/01-fix-tests.patch b/contrib/python/requests-mock/py2/patches/01-fix-tests.patch
new file mode 100644
index 0000000000..c738d3d08e
--- /dev/null
+++ b/contrib/python/requests-mock/py2/patches/01-fix-tests.patch
@@ -0,0 +1,13 @@
+--- contrib/python/requests-mock/py2/tests/base.py (index)
++++ contrib/python/requests-mock/py2/tests/base.py (working tree)
+@@ -10,8 +10,8 @@
+ # License for the specific language governing permissions and limitations
+ # under the License.
+
+-import testtools
++import unittest
+
+
+-class TestCase(testtools.TestCase):
++class TestCase(unittest.TestCase):
+ pass
diff --git a/contrib/python/requests-mock/py2/requests_mock/__init__.py b/contrib/python/requests-mock/py2/requests_mock/__init__.py
new file mode 100644
index 0000000000..799b752ee7
--- /dev/null
+++ b/contrib/python/requests-mock/py2/requests_mock/__init__.py
@@ -0,0 +1,37 @@
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from requests_mock.adapter import Adapter, ANY
+from requests_mock.exceptions import MockException, NoMockAddress
+from requests_mock.mocker import mock, Mocker, MockerCore
+from requests_mock.mocker import DELETE, GET, HEAD, OPTIONS, PATCH, POST, PUT
+from requests_mock.response import create_response, CookieJar
+
+
+__all__ = ['Adapter',
+ 'ANY',
+ 'create_response',
+ 'CookieJar',
+ 'mock',
+ 'Mocker',
+ 'MockerCore',
+ 'MockException',
+ 'NoMockAddress',
+
+ 'DELETE',
+ 'GET',
+ 'HEAD',
+ 'OPTIONS',
+ 'PATCH',
+ 'POST',
+ 'PUT',
+ ]
diff --git a/contrib/python/requests-mock/py2/requests_mock/__init__.pyi b/contrib/python/requests-mock/py2/requests_mock/__init__.pyi
new file mode 100644
index 0000000000..9d8dd002e9
--- /dev/null
+++ b/contrib/python/requests-mock/py2/requests_mock/__init__.pyi
@@ -0,0 +1,33 @@
+# Stubs for requests_mock
+
+from requests_mock.adapter import (
+ ANY as ANY,
+ Adapter as Adapter,
+ Callback as Callback,
+ AdditionalMatcher as AdditionalMatcher,
+)
+from requests_mock.exceptions import (
+ MockException as MockException,
+ NoMockAddress as NoMockAddress,
+)
+from requests_mock.mocker import (
+ DELETE as DELETE,
+ GET as GET,
+ HEAD as HEAD,
+ Mocker as Mocker,
+ MockerCore as MockerCore,
+ OPTIONS as OPTIONS,
+ PATCH as PATCH,
+ POST as POST,
+ PUT as PUT,
+ mock as mock,
+)
+from requests_mock.request import (
+ Request as Request,
+ _RequestObjectProxy as _RequestObjectProxy, # For backward compatibility
+)
+from requests_mock.response import (
+ CookieJar as CookieJar,
+ create_response as create_response,
+ Context as Context,
+)
diff --git a/contrib/python/requests-mock/py2/requests_mock/adapter.py b/contrib/python/requests-mock/py2/requests_mock/adapter.py
new file mode 100644
index 0000000000..e0560b2226
--- /dev/null
+++ b/contrib/python/requests-mock/py2/requests_mock/adapter.py
@@ -0,0 +1,323 @@
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import weakref
+
+from requests.adapters import BaseAdapter
+from requests.utils import requote_uri
+import six
+from six.moves.urllib import parse as urlparse
+
+from requests_mock import exceptions
+from requests_mock.request import _RequestObjectProxy
+from requests_mock.response import _MatcherResponse
+
+import logging
+
+logger = logging.getLogger(__name__)
+
+try:
+ import purl
+ purl_types = (purl.URL,)
+except ImportError:
+ purl = None
+ purl_types = ()
+
+ANY = object()
+
+
+class _RequestHistoryTracker(object):
+
+ def __init__(self):
+ self.request_history = []
+
+ def _add_to_history(self, request):
+ self.request_history.append(request)
+
+ @property
+ def last_request(self):
+ """Retrieve the latest request sent"""
+ try:
+ return self.request_history[-1]
+ except IndexError:
+ return None
+
+ @property
+ def called(self):
+ return self.call_count > 0
+
+ @property
+ def called_once(self):
+ return self.call_count == 1
+
+ @property
+ def call_count(self):
+ return len(self.request_history)
+
+ def reset(self):
+ self.request_history = []
+
+
+class _RunRealHTTP(Exception):
+ """A fake exception to jump out of mocking and allow a real request.
+
+ This exception is caught at the mocker level and allows it to execute this
+ request through the real requests mechanism rather than the mocker.
+
+ It should never be exposed to a user.
+ """
+
+
+class _Matcher(_RequestHistoryTracker):
+ """Contains all the information about a provided URL to match."""
+
+ def __init__(self, method, url, responses, complete_qs, request_headers,
+ additional_matcher, real_http, case_sensitive):
+ """
+ :param bool complete_qs: Match the entire query string. By default URLs
+ match if all the provided matcher query arguments are matched and
+ extra query arguments are ignored. Set complete_qs to true to
+ require that the entire query string needs to match.
+ """
+ super(_Matcher, self).__init__()
+
+ self._method = method
+ self._url = url
+ self._responses = responses
+ self._complete_qs = complete_qs
+ self._request_headers = request_headers
+ self._real_http = real_http
+ self._additional_matcher = additional_matcher
+
+ # url can be a regex object or ANY so don't always run urlparse
+ if isinstance(url, six.string_types):
+ url_parts = urlparse.urlparse(url)
+ self._scheme = url_parts.scheme.lower()
+ self._netloc = url_parts.netloc.lower()
+ self._path = requote_uri(url_parts.path or '/')
+ self._query = url_parts.query
+
+ if not case_sensitive:
+ self._path = self._path.lower()
+ self._query = self._query.lower()
+
+ elif isinstance(url, purl_types):
+ self._scheme = url.scheme()
+ self._netloc = url.netloc()
+ self._path = url.path()
+ self._query = url.query()
+
+ if not case_sensitive:
+ self._path = self._path.lower()
+ self._query = self._query.lower()
+
+ else:
+ self._scheme = None
+ self._netloc = None
+ self._path = None
+ self._query = None
+
+ def _match_method(self, request):
+ if self._method is ANY:
+ return True
+
+ if request.method.lower() == self._method.lower():
+ return True
+
+ return False
+
+ def _match_url(self, request):
+ if self._url is ANY:
+ return True
+
+ # regular expression matching
+ if hasattr(self._url, 'search'):
+ return self._url.search(request.url) is not None
+
+ # scheme is always matched case insensitive
+ if self._scheme and request.scheme.lower() != self._scheme:
+ return False
+
+ # netloc is always matched case insensitive
+ if self._netloc and request.netloc.lower() != self._netloc:
+ return False
+
+ if (request.path or '/') != self._path:
+ return False
+
+ # construct our own qs structure as we remove items from it below
+ request_qs = urlparse.parse_qs(request.query, keep_blank_values=True)
+ matcher_qs = urlparse.parse_qs(self._query, keep_blank_values=True)
+
+ for k, vals in six.iteritems(matcher_qs):
+ for v in vals:
+ try:
+ request_qs.get(k, []).remove(v)
+ except ValueError:
+ return False
+
+ if self._complete_qs:
+ for v in six.itervalues(request_qs):
+ if v:
+ return False
+
+ return True
+
+ def _match_headers(self, request):
+ for k, vals in six.iteritems(self._request_headers):
+
+ try:
+ header = request.headers[k]
+ except KeyError:
+ # NOTE(jamielennox): This seems to be a requests 1.2/2
+ # difference, in 2 they are just whatever the user inputted in
+ # 1 they are bytes. Let's optionally handle both and look at
+ # removing this when we depend on requests 2.
+ if not isinstance(k, six.text_type):
+ return False
+
+ try:
+ header = request.headers[k.encode('utf-8')]
+ except KeyError:
+ return False
+
+ if header != vals:
+ return False
+
+ return True
+
+ def _match_additional(self, request):
+ if callable(self._additional_matcher):
+ return self._additional_matcher(request)
+
+ if self._additional_matcher is not None:
+ raise TypeError("Unexpected format of additional matcher.")
+
+ return True
+
+ def _match(self, request):
+ return (self._match_method(request) and
+ self._match_url(request) and
+ self._match_headers(request) and
+ self._match_additional(request))
+
+ def __call__(self, request):
+ if not self._match(request):
+ return None
+
+ # doing this before _add_to_history means real requests are not stored
+ # in the request history. I'm not sure what is better here.
+ if self._real_http:
+ raise _RunRealHTTP()
+
+ if len(self._responses) > 1:
+ response_matcher = self._responses.pop(0)
+ else:
+ response_matcher = self._responses[0]
+
+ self._add_to_history(request)
+ return response_matcher.get_response(request)
+
+
+class Adapter(BaseAdapter, _RequestHistoryTracker):
+ """A fake adapter than can return predefined responses.
+
+ """
+ def __init__(self, case_sensitive=False):
+ super(Adapter, self).__init__()
+ self._case_sensitive = case_sensitive
+ self._matchers = []
+
+ def send(self, request, **kwargs):
+ request = _RequestObjectProxy(request,
+ case_sensitive=self._case_sensitive,
+ **kwargs)
+ self._add_to_history(request)
+
+ for matcher in reversed(self._matchers):
+ try:
+ resp = matcher(request)
+ except Exception:
+ request._matcher = weakref.ref(matcher)
+ raise
+
+ if resp is not None:
+ request._matcher = weakref.ref(matcher)
+ resp.connection = self
+ logger.debug('{} {} {}'.format(request._request.method,
+ request._request.url,
+ resp.status_code))
+ return resp
+
+ raise exceptions.NoMockAddress(request)
+
+ def close(self):
+ pass
+
+ def register_uri(self, method, url, response_list=None, **kwargs):
+ """Register a new URI match and fake response.
+
+ :param str method: The HTTP method to match.
+ :param str url: The URL to match.
+ """
+ complete_qs = kwargs.pop('complete_qs', False)
+ additional_matcher = kwargs.pop('additional_matcher', None)
+ request_headers = kwargs.pop('request_headers', {})
+ real_http = kwargs.pop('_real_http', False)
+ json_encoder = kwargs.pop('json_encoder', None)
+
+ if response_list and kwargs:
+ raise RuntimeError('You should specify either a list of '
+ 'responses OR response kwargs. Not both.')
+ elif real_http and (response_list or kwargs):
+ raise RuntimeError('You should specify either response data '
+ 'OR real_http. Not both.')
+ elif not response_list:
+ if json_encoder is not None:
+ kwargs['json_encoder'] = json_encoder
+ response_list = [] if real_http else [kwargs]
+
+ # NOTE(jamielennox): case_sensitive is not present as a kwarg because i
+ # think there would be an edge case where the adapter and register_uri
+ # had different values.
+ # Ideally case_sensitive would be a value passed to match() however
+ # this would change the contract of matchers so we pass ito to the
+ # proxy and the matcher separately.
+ responses = [_MatcherResponse(**k) for k in response_list]
+ matcher = _Matcher(method,
+ url,
+ responses,
+ case_sensitive=self._case_sensitive,
+ complete_qs=complete_qs,
+ additional_matcher=additional_matcher,
+ request_headers=request_headers,
+ real_http=real_http)
+ self.add_matcher(matcher)
+ return matcher
+
+ def add_matcher(self, matcher):
+ """Register a custom matcher.
+
+ A matcher is a callable that takes a `requests.Request` and returns a
+ `requests.Response` if it matches or None if not.
+
+ :param callable matcher: The matcher to execute.
+ """
+ self._matchers.append(matcher)
+
+ def reset(self):
+ super(Adapter, self).reset()
+ for matcher in self._matchers:
+ matcher.reset()
+
+
+__all__ = ['Adapter']
diff --git a/contrib/python/requests-mock/py2/requests_mock/adapter.pyi b/contrib/python/requests-mock/py2/requests_mock/adapter.pyi
new file mode 100644
index 0000000000..dbeba496ba
--- /dev/null
+++ b/contrib/python/requests-mock/py2/requests_mock/adapter.pyi
@@ -0,0 +1,75 @@
+# Stubs for requests_mock.adapter
+
+from http.cookiejar import CookieJar
+from io import IOBase
+from typing import Any, Callable, Dict, List, NewType, Optional, Pattern, Type, TypeVar, Union
+
+from requests import Response
+from requests.adapters import BaseAdapter
+from urllib3.response import HTTPResponse
+
+from requests_mock.request import Request
+from requests_mock.response import Context
+
+AnyMatcher = NewType("AnyMatcher", object)
+
+ANY: AnyMatcher = ...
+
+T = TypeVar('T')
+Callback = Callable[[Request, Context], T]
+Matcher = Callable[[Request], Optional[Response]]
+AdditionalMatcher = Callable[[Request], bool]
+
+class _RequestHistoryTracker:
+ request_history: List[Request] = ...
+ def __init__(self) -> None: ...
+ @property
+ def last_request(self) -> Optional[Request]: ...
+ @property
+ def called(self) -> bool: ...
+ @property
+ def called_once(self) -> bool: ...
+ @property
+ def call_count(self) -> int: ...
+
+class _RunRealHTTP(Exception): ...
+
+class _Matcher(_RequestHistoryTracker):
+ def __init__(
+ self,
+ method: Any,
+ url: Any,
+ responses: Any,
+ complete_qs: Any,
+ request_headers: Any,
+ additional_matcher: AdditionalMatcher,
+ real_http: Any,
+ case_sensitive: Any
+ ) -> None: ...
+ def __call__(self, request: Request) -> Optional[Response]: ...
+
+class Adapter(BaseAdapter, _RequestHistoryTracker):
+ def __init__(self, case_sensitive: bool = ...) -> None: ...
+ def register_uri(
+ self,
+ method: Union[str, AnyMatcher],
+ url: Union[str, Pattern[str], AnyMatcher],
+ response_list: Optional[List[Dict[str, Any]]] = ...,
+ *,
+ request_headers: Dict[str, str] = ...,
+ complete_qs: bool = ...,
+ status_code: int = ...,
+ reason: str = ...,
+ headers: Dict[str, str] = ...,
+ cookies: Union[CookieJar, Dict[str, str]] = ...,
+ json: Union[Any, Callback[Any]] = ...,
+ text: Union[str, Callback[str]] = ...,
+ content: Union[bytes, Callback[bytes]] = ...,
+ body: Union[IOBase, Callback[IOBase]] = ...,
+ raw: HTTPResponse = ...,
+ exc: Union[Exception, Type[Exception]] = ...,
+ additional_matcher: AdditionalMatcher = ...,
+ **kwargs: Any
+ ) -> _Matcher: ...
+ def add_matcher(self, matcher: Matcher) -> None: ...
+ def reset(self) -> None: ...
diff --git a/contrib/python/requests-mock/py2/requests_mock/compat.py b/contrib/python/requests-mock/py2/requests_mock/compat.py
new file mode 100644
index 0000000000..8b6293af15
--- /dev/null
+++ b/contrib/python/requests-mock/py2/requests_mock/compat.py
@@ -0,0 +1,30 @@
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+
+class _FakeHTTPMessage(object):
+
+ def __init__(self, headers):
+ self.headers = headers
+
+ def getheaders(self, name):
+ try:
+ return [self.headers[name]]
+ except KeyError:
+ return []
+
+ def get_all(self, name, failobj=None):
+ # python 3 only, overrides email.message.Message.get_all
+ try:
+ return [self.headers[name]]
+ except KeyError:
+ return failobj
diff --git a/contrib/python/requests-mock/py2/requests_mock/contrib/__init__.py b/contrib/python/requests-mock/py2/requests_mock/contrib/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/contrib/python/requests-mock/py2/requests_mock/contrib/__init__.py
diff --git a/contrib/python/requests-mock/py2/requests_mock/contrib/_pytest_plugin.py b/contrib/python/requests-mock/py2/requests_mock/contrib/_pytest_plugin.py
new file mode 100644
index 0000000000..bb6cd2b973
--- /dev/null
+++ b/contrib/python/requests-mock/py2/requests_mock/contrib/_pytest_plugin.py
@@ -0,0 +1,86 @@
+import pytest
+
+
+# RHEL 7 ships pytest 2.7 which doesn't have the 'bool' type to addini. This
+# broke pytest for EPEL: https://bugzilla.redhat.com/show_bug.cgi?id=1605138
+# If it's older than 2.9 we handle bool conversion ourselves. Remove this when
+# we can rely on a newer pytest.
+#
+# Version 3 is also where the @yield_fixture decorator was deprecated and you
+# can now just use @fixture, so we handle both of those cases as well.
+
+try:
+ _pytest_version = tuple([
+ int(x) for x in pytest.__version__.split('.')[:2]
+ ])
+ _pytest29 = _pytest_version >= (2, 9)
+ _pytest30 = _pytest_version >= (3, 0)
+except Exception:
+ _pytest29 = False
+ _pytest30 = False
+
+
+if not _pytest29:
+ _case_type = None
+ _case_default = 'false'
+
+ # Copied from pytest 2.9.0 where bool was introduced. It's what happens
+ # internally if we specify a bool type argument.
+ def _strtobool(val):
+ """Convert a string representation of truth to true (1) or false (0).
+
+ True values are 'y', 'yes', 't', 'true', 'on', and '1'; false values
+ are 'n', 'no', 'f', 'false', 'off', and '0'. Raises ValueError if
+ 'val' is anything else.
+
+ .. note:: copied from distutils.util
+ """
+ val = val.lower()
+ if val in ('y', 'yes', 't', 'true', 'on', '1'):
+ return 1
+ elif val in ('n', 'no', 'f', 'false', 'off', '0'):
+ return 0
+ else:
+ raise ValueError("invalid truth value %r" % (val,))
+
+ def _bool_value(value):
+ return bool(_strtobool(value.strip()))
+
+else:
+ _case_type = 'bool'
+ _case_default = False
+
+ def _bool_value(value):
+ return value
+
+
+if _pytest30:
+ _fixture_type = pytest.fixture
+else:
+ _fixture_type = pytest.yield_fixture
+
+
+def pytest_addoption(parser):
+ parser.addini('requests_mock_case_sensitive',
+ 'Use case sensitive matching in requests_mock',
+ type=_case_type,
+ default=_case_default)
+
+
+@_fixture_type(scope='function') # executed on every test
+def requests_mock(request):
+ """Mock out the requests component of your code with defined responses.
+
+ Mocks out any requests made through the python requests library with useful
+ responses for unit testing. See:
+ https://requests-mock.readthedocs.io/en/latest/
+ """
+ # pytest plugins get loaded immediately. If we import requests_mock it
+ # imports requests and then SSL which prevents gevent patching. Late load.
+ import requests_mock as rm_module
+
+ case_sensitive = request.config.getini('requests_mock_case_sensitive')
+ kw = {'case_sensitive': _bool_value(case_sensitive)}
+
+ with rm_module.Mocker(**kw) as m:
+ yield m
diff --git a/contrib/python/requests-mock/py2/requests_mock/contrib/_pytest_plugin.pyi b/contrib/python/requests-mock/py2/requests_mock/contrib/_pytest_plugin.pyi
new file mode 100644
index 0000000000..3ffb573881
--- /dev/null
+++ b/contrib/python/requests-mock/py2/requests_mock/contrib/_pytest_plugin.pyi
@@ -0,0 +1,6 @@
+
+from typing import Literal, Optional, Union
+
+
+_case_type = Optional[str]
+_case_default = Union[Literal['false'], Literal[False]]
diff --git a/contrib/python/requests-mock/py2/requests_mock/contrib/fixture.py b/contrib/python/requests-mock/py2/requests_mock/contrib/fixture.py
new file mode 100644
index 0000000000..0c23947566
--- /dev/null
+++ b/contrib/python/requests-mock/py2/requests_mock/contrib/fixture.py
@@ -0,0 +1,27 @@
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import fixtures
+
+from requests_mock import mocker
+
+
+class Fixture(fixtures.Fixture, mocker.MockerCore):
+
+ def __init__(self, **kwargs):
+ fixtures.Fixture.__init__(self)
+ mocker.MockerCore.__init__(self, **kwargs)
+
+ def setUp(self):
+ super(Fixture, self).setUp()
+ self.start()
+ self.addCleanup(self.stop)
diff --git a/contrib/python/requests-mock/py2/requests_mock/exceptions.py b/contrib/python/requests-mock/py2/requests_mock/exceptions.py
new file mode 100644
index 0000000000..feeb1aa312
--- /dev/null
+++ b/contrib/python/requests-mock/py2/requests_mock/exceptions.py
@@ -0,0 +1,30 @@
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+
+class MockException(Exception):
+ """Base Exception for library"""
+
+
+class NoMockAddress(MockException):
+ """The requested URL was not mocked"""
+
+ def __init__(self, request):
+ self.request = request
+
+ def __str__(self):
+ return "No mock address: %s %s" % (self.request.method,
+ self.request.url)
+
+
+class InvalidRequest(MockException):
+ """This call cannot be made under a mocked environment"""
diff --git a/contrib/python/requests-mock/py2/requests_mock/exceptions.pyi b/contrib/python/requests-mock/py2/requests_mock/exceptions.pyi
new file mode 100644
index 0000000000..eb35447228
--- /dev/null
+++ b/contrib/python/requests-mock/py2/requests_mock/exceptions.pyi
@@ -0,0 +1,13 @@
+# Stubs for requests_mock.exceptions
+
+from typing import Any
+
+from requests import Request
+
+class MockException(Exception): ...
+
+class NoMockAddress(MockException):
+ request: Any = ...
+ def __init__(self, request: Request) -> None: ...
+
+class InvalidRequest(MockException): ...
diff --git a/contrib/python/requests-mock/py2/requests_mock/mocker.py b/contrib/python/requests-mock/py2/requests_mock/mocker.py
new file mode 100644
index 0000000000..d3bc85538e
--- /dev/null
+++ b/contrib/python/requests-mock/py2/requests_mock/mocker.py
@@ -0,0 +1,342 @@
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import contextlib
+import functools
+import sys
+import threading
+import types
+
+import requests
+import six
+
+from requests_mock import adapter
+from requests_mock import exceptions
+
+DELETE = 'DELETE'
+GET = 'GET'
+HEAD = 'HEAD'
+OPTIONS = 'OPTIONS'
+PATCH = 'PATCH'
+POST = 'POST'
+PUT = 'PUT'
+
+_original_send = requests.Session.send
+
+# NOTE(phodge): we need to use an RLock (reentrant lock) here because
+# requests.Session.send() is reentrant. See further comments where we
+# monkeypatch get_adapter()
+_send_lock = threading.RLock()
+
+
+@contextlib.contextmanager
+def threading_rlock(timeout):
+ kwargs = {}
+ if sys.version_info.major >= 3:
+ # python2 doesn't support the timeout argument
+ kwargs['timeout'] = timeout
+
+ if not _send_lock.acquire(**kwargs):
+ m = "Could not acquire threading lock - possible deadlock scenario"
+ raise Exception(m)
+
+ try:
+ yield
+ finally:
+ _send_lock.release()
+
+
+def _is_bound_method(method):
+ """
+ bound_method 's self is a obj
+ unbound_method 's self is None
+ """
+ if isinstance(method, types.MethodType) and six.get_method_self(method):
+ return True
+ return False
+
+
+def _set_method(target, name, method):
+ """ Set a mocked method onto the target.
+
+ Target may be either an instance of a Session object of the
+ requests.Session class. First we Bind the method if it's an instance.
+
+ If method is a bound_method, can direct setattr
+ """
+ if not isinstance(target, type) and not _is_bound_method(method):
+ method = six.create_bound_method(method, target)
+
+ setattr(target, name, method)
+
+
+class MockerCore(object):
+ """A wrapper around common mocking functions.
+
+ Automate the process of mocking the requests library. This will keep the
+ same general options available and prevent repeating code.
+ """
+
+ _PROXY_FUNCS = {
+ 'last_request',
+ 'add_matcher',
+ 'request_history',
+ 'called',
+ 'called_once',
+ 'call_count',
+ 'reset',
+ }
+
+ case_sensitive = False
+ """case_sensitive handles a backwards incompatible bug. The URL used to
+ match against our matches and that is saved in request_history is always
+ lowercased. This is incorrect as it reports incorrect history to the user
+ and doesn't allow case sensitive path matching.
+
+ Unfortunately fixing this change is backwards incompatible in the 1.X
+ series as people may rely on this behaviour. To work around this you can
+ globally set:
+
+ requests_mock.mock.case_sensitive = True
+
+ or for pytest set in your configuration:
+
+ [pytest]
+ requests_mock_case_sensitive = True
+
+ which will prevent the lowercase being executed and return case sensitive
+ url and query information.
+
+ This will become the default in a 2.X release. See bug: #1584008.
+ """
+
+ def __init__(self, session=None, **kwargs):
+ if session and not isinstance(session, requests.Session):
+ raise TypeError("Only a requests.Session object can be mocked")
+
+ self._mock_target = session or requests.Session
+ self.case_sensitive = kwargs.pop('case_sensitive', self.case_sensitive)
+ self._adapter = (
+ kwargs.pop('adapter', None) or
+ adapter.Adapter(case_sensitive=self.case_sensitive)
+ )
+
+ self._json_encoder = kwargs.pop('json_encoder', None)
+ self.real_http = kwargs.pop('real_http', False)
+ self._last_send = None
+
+ if kwargs:
+ raise TypeError('Unexpected Arguments: %s' % ', '.join(kwargs))
+
+ def start(self):
+ """Start mocking requests.
+
+ Install the adapter and the wrappers required to intercept requests.
+ """
+ if self._last_send:
+ raise RuntimeError('Mocker has already been started')
+
+ # backup last `send` for restoration on `self.stop`
+ self._last_send = self._mock_target.send
+ self._last_get_adapter = self._mock_target.get_adapter
+
+ def _fake_get_adapter(session, url):
+ return self._adapter
+
+ def _fake_send(session, request, **kwargs):
+ # NOTE(phodge): we need to use a threading lock here in case there
+ # are multiple threads running - one thread could restore the
+ # original get_adapter() just as a second thread is about to
+ # execute _original_send() below
+ with threading_rlock(timeout=10):
+ # mock get_adapter
+ #
+ # NOTE(phodge): requests.Session.send() is actually
+ # reentrant due to how it resolves redirects with nested
+ # calls to send(), however the reentry occurs _after_ the
+ # call to self.get_adapter(), so it doesn't matter that we
+ # will restore _last_get_adapter before a nested send() has
+ # completed as long as we monkeypatch get_adapter() each
+ # time immediately before calling original send() like we
+ # are doing here.
+ _set_method(session, "get_adapter", _fake_get_adapter)
+
+ # NOTE(jamielennox): self._last_send vs _original_send. Whilst
+ # it seems like here we would use _last_send there is the
+ # possibility that the user has messed up and is somehow
+ # nesting their mockers. If we call last_send at this point
+ # then we end up calling this function again and the outer
+ # level adapter ends up winning. All we really care about here
+ # is that our adapter is in place before calling send so we
+ # always jump directly to the real function so that our most
+ # recently patched send call ends up putting in the most recent
+ # adapter. It feels funny, but it works.
+
+ try:
+ return _original_send(session, request, **kwargs)
+ except exceptions.NoMockAddress:
+ if not self.real_http:
+ raise
+ except adapter._RunRealHTTP:
+ # this mocker wants you to run the request through the real
+ # requests library rather than the mocking. Let it.
+ pass
+ finally:
+ # restore get_adapter
+ _set_method(session, "get_adapter", self._last_get_adapter)
+
+ # 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
+ if isinstance(self._mock_target, type):
+ return self._last_send(session, request, **kwargs)
+ else:
+ return self._last_send(request, **kwargs)
+
+ _set_method(self._mock_target, "send", _fake_send)
+
+ def stop(self):
+ """Stop mocking requests.
+
+ This should have no impact if mocking has not been started.
+ When nesting mockers, make sure to stop the innermost first.
+ """
+ if self._last_send:
+ self._mock_target.send = self._last_send
+ self._last_send = None
+
+ # for familiarity with MagicMock
+ def reset_mock(self):
+ self.reset()
+
+ def __getattr__(self, name):
+ if name in self._PROXY_FUNCS:
+ try:
+ return getattr(self._adapter, name)
+ except AttributeError:
+ pass
+
+ raise AttributeError(name)
+
+ def register_uri(self, *args, **kwargs):
+ # you can pass real_http here, but it's private to pass direct to the
+ # adapter, because if you pass direct to the adapter you'll see the exc
+ kwargs['_real_http'] = kwargs.pop('real_http', False)
+ kwargs.setdefault('json_encoder', self._json_encoder)
+ return self._adapter.register_uri(*args, **kwargs)
+
+ def request(self, *args, **kwargs):
+ return self.register_uri(*args, **kwargs)
+
+ def get(self, *args, **kwargs):
+ return self.request(GET, *args, **kwargs)
+
+ def options(self, *args, **kwargs):
+ return self.request(OPTIONS, *args, **kwargs)
+
+ def head(self, *args, **kwargs):
+ return self.request(HEAD, *args, **kwargs)
+
+ def post(self, *args, **kwargs):
+ return self.request(POST, *args, **kwargs)
+
+ def put(self, *args, **kwargs):
+ return self.request(PUT, *args, **kwargs)
+
+ def patch(self, *args, **kwargs):
+ return self.request(PATCH, *args, **kwargs)
+
+ def delete(self, *args, **kwargs):
+ return self.request(DELETE, *args, **kwargs)
+
+
+class Mocker(MockerCore):
+ """The standard entry point for mock Adapter loading.
+ """
+
+ #: Defines with what should method name begin to be patched
+ TEST_PREFIX = 'test'
+
+ def __init__(self, **kwargs):
+ """Create a new mocker adapter.
+
+ :param str kw: Pass the mock object through to the decorated function
+ as this named keyword argument, rather than a positional argument.
+ :param bool real_http: True to send the request to the real requested
+ uri if there is not a mock installed for it. Defaults to False.
+ """
+ self._kw = kwargs.pop('kw', None)
+ super(Mocker, self).__init__(**kwargs)
+
+ def __enter__(self):
+ self.start()
+ return self
+
+ def __exit__(self, type, value, traceback):
+ self.stop()
+
+ def __call__(self, obj):
+ if isinstance(obj, type):
+ return self.decorate_class(obj)
+
+ return self.decorate_callable(obj)
+
+ def copy(self):
+ """Returns an exact copy of current mock
+ """
+ m = type(self)(
+ kw=self._kw,
+ real_http=self.real_http,
+ case_sensitive=self.case_sensitive
+ )
+ return m
+
+ def decorate_callable(self, func):
+ """Decorates a callable
+
+ :param callable func: callable to decorate
+ """
+ @functools.wraps(func)
+ def inner(*args, **kwargs):
+ with self.copy() as m:
+ if self._kw:
+ kwargs[self._kw] = m
+ else:
+ args = list(args)
+ args.append(m)
+
+ return func(*args, **kwargs)
+
+ return inner
+
+ def decorate_class(self, klass):
+ """Decorates methods in a class with request_mock
+
+ Method will be decorated only if it name begins with `TEST_PREFIX`
+
+ :param object klass: class which methods will be decorated
+ """
+ for attr_name in dir(klass):
+ if not attr_name.startswith(self.TEST_PREFIX):
+ continue
+
+ attr = getattr(klass, attr_name)
+ if not hasattr(attr, '__call__'):
+ continue
+
+ m = self.copy()
+ setattr(klass, attr_name, m(attr))
+
+ return klass
+
+
+mock = Mocker
diff --git a/contrib/python/requests-mock/py2/requests_mock/mocker.pyi b/contrib/python/requests-mock/py2/requests_mock/mocker.pyi
new file mode 100644
index 0000000000..891e7d6c9a
--- /dev/null
+++ b/contrib/python/requests-mock/py2/requests_mock/mocker.pyi
@@ -0,0 +1,263 @@
+# Stubs for requests_mock.mocker
+
+from json import JSONEncoder
+from http.cookiejar import CookieJar
+from io import IOBase
+from typing import Any, Callable, Dict, List, Optional, Pattern, Type, TypeVar, Union
+
+from requests import Response, Session
+from urllib3.response import HTTPResponse
+
+from requests_mock.adapter import AnyMatcher, _Matcher, Callback, AdditionalMatcher
+from requests_mock.request import Request
+
+DELETE: str
+GET: str
+HEAD: str
+OPTIONS: str
+PATCH: str
+POST: str
+PUT: str
+
+class MockerCore:
+ case_sensitive: bool = ...
+ def __init__(self, **kwargs: Any) -> None: ...
+ def start(self) -> None: ...
+ def stop(self) -> None: ...
+ def add_matcher(self, matcher: Callable[[Request], Optional[Response]]) -> None: ...
+ @property
+ def request_history(self) -> List[Request]: ...
+ @property
+ def last_request(self) -> Optional[Request]: ...
+ @property
+ def called(self) -> bool: ...
+ @property
+ def called_once(self) -> bool: ...
+ @property
+ def call_count(self) -> int: ...
+ def reset(self) -> None: ...
+ def reset_mock(self) -> None: ...
+
+ def register_uri(
+ self,
+ method: Union[str, AnyMatcher],
+ url: Union[str, Pattern[str], AnyMatcher],
+ response_list: Optional[List[Dict[str, Any]]] = ...,
+ *,
+ request_headers: Dict[str, str] = ...,
+ complete_qs: bool = ...,
+ status_code: int = ...,
+ reason: str = ...,
+ headers: Dict[str, str] = ...,
+ cookies: Union[CookieJar, Dict[str, str]] = ...,
+ json: Union[Any, Callback[Any]] = ...,
+ text: Union[str, Callback[str]] = ...,
+ content: Union[bytes, Callback[bytes]] = ...,
+ body: Union[IOBase, Callback[IOBase]] = ...,
+ raw: HTTPResponse = ...,
+ exc: Union[Exception, Type[Exception]] = ...,
+ additional_matcher: AdditionalMatcher = ...,
+ json_encoder: Optional[Type[JSONEncoder]] = ...,
+ **kwargs: Any,
+ ) -> _Matcher: ...
+
+ def request(
+ self,
+ method: Union[str, AnyMatcher],
+ url: Union[str, Pattern[str], AnyMatcher],
+ response_list: Optional[List[Dict[str, Any]]] = ...,
+ *,
+ request_headers: Dict[str, str] = ...,
+ complete_qs: bool = ...,
+ status_code: int = ...,
+ reason: str = ...,
+ headers: Dict[str, str] = ...,
+ cookies: Union[CookieJar, Dict[str, str]] = ...,
+ json: Union[Any, Callback[Any]] = ...,
+ text: Union[str, Callback[str]] = ...,
+ content: Union[bytes, Callback[bytes]] = ...,
+ body: Union[IOBase, Callback[IOBase]] = ...,
+ raw: HTTPResponse = ...,
+ exc: Union[Exception, Type[Exception]] = ...,
+ additional_matcher: AdditionalMatcher = ...,
+ json_encoder: Optional[Type[JSONEncoder]] = ...,
+ **kwargs: Any,
+ ) -> _Matcher: ...
+
+ def get(
+ self,
+ url: Union[str, Pattern[str], AnyMatcher],
+ response_list: Optional[List[Dict[str, Any]]] = ...,
+ *,
+ request_headers: Dict[str, str] = ...,
+ complete_qs: bool = ...,
+ status_code: int = ...,
+ reason: str = ...,
+ headers: Dict[str, str] = ...,
+ cookies: Union[CookieJar, Dict[str, str]] = ...,
+ json: Union[Any, Callback[Any]] = ...,
+ text: Union[str, Callback[str]] = ...,
+ content: Union[bytes, Callback[bytes]] = ...,
+ body: Union[IOBase, Callback[IOBase]] = ...,
+ raw: HTTPResponse = ...,
+ exc: Union[Exception, Type[Exception]] = ...,
+ additional_matcher: AdditionalMatcher = ...,
+ json_encoder: Optional[Type[JSONEncoder]] = ...,
+ **kwargs: Any,
+ ) -> _Matcher: ...
+
+ def head(
+ self,
+ url: Union[str, Pattern[str], AnyMatcher],
+ response_list: Optional[List[Dict[str, Any]]] = ...,
+ *,
+ request_headers: Dict[str, str] = ...,
+ complete_qs: bool = ...,
+ status_code: int = ...,
+ reason: str = ...,
+ headers: Dict[str, str] = ...,
+ cookies: Union[CookieJar, Dict[str, str]] = ...,
+ json: Union[Any, Callback[Any]] = ...,
+ text: Union[str, Callback[str]] = ...,
+ content: Union[bytes, Callback[bytes]] = ...,
+ body: Union[IOBase, Callback[IOBase]] = ...,
+ raw: HTTPResponse = ...,
+ exc: Union[Exception, Type[Exception]] = ...,
+ additional_matcher: AdditionalMatcher = ...,
+ json_encoder: Optional[Type[JSONEncoder]] = ...,
+ **kwargs: Any,
+ ) -> _Matcher: ...
+
+ def options(
+ self,
+ url: Union[str, Pattern[str], AnyMatcher],
+ response_list: Optional[List[Dict[str, Any]]] = ...,
+ *,
+ request_headers: Dict[str, str] = ...,
+ complete_qs: bool = ...,
+ status_code: int = ...,
+ reason: str = ...,
+ headers: Dict[str, str] = ...,
+ cookies: Union[CookieJar, Dict[str, str]] = ...,
+ json: Union[Any, Callback[Any]] = ...,
+ text: Union[str, Callback[str]] = ...,
+ content: Union[bytes, Callback[bytes]] = ...,
+ body: Union[IOBase, Callback[IOBase]] = ...,
+ raw: HTTPResponse = ...,
+ exc: Union[Exception, Type[Exception]] = ...,
+ additional_matcher: AdditionalMatcher = ...,
+ json_encoder: Optional[Type[JSONEncoder]] = ...,
+ **kwargs: Any,
+ ) -> _Matcher: ...
+
+ def post(
+ self,
+ url: Union[str, Pattern[str], AnyMatcher],
+ response_list: Optional[List[Dict[str, Any]]] = ...,
+ *,
+ request_headers: Dict[str, str] = ...,
+ complete_qs: bool = ...,
+ status_code: int = ...,
+ reason: str = ...,
+ headers: Dict[str, str] = ...,
+ cookies: Union[CookieJar, Dict[str, str]] = ...,
+ json: Union[Any, Callback[Any]] = ...,
+ text: Union[str, Callback[str]] = ...,
+ content: Union[bytes, Callback[bytes]] = ...,
+ body: Union[IOBase, Callback[IOBase]] = ...,
+ raw: HTTPResponse = ...,
+ exc: Union[Exception, Type[Exception]] = ...,
+ additional_matcher: AdditionalMatcher = ...,
+ json_encoder: Optional[Type[JSONEncoder]] = ...,
+ **kwargs: Any,
+ ) -> _Matcher: ...
+
+ def put(
+ self,
+ url: Union[str, Pattern[str], AnyMatcher],
+ response_list: Optional[List[Dict[str, Any]]] = ...,
+ *,
+ request_headers: Dict[str, str] = ...,
+ complete_qs: bool = ...,
+ status_code: int = ...,
+ reason: str = ...,
+ headers: Dict[str, str] = ...,
+ cookies: Union[CookieJar, Dict[str, str]] = ...,
+ json: Union[Any, Callback[Any]] = ...,
+ text: Union[str, Callback[str]] = ...,
+ content: Union[bytes, Callback[bytes]] = ...,
+ body: Union[IOBase, Callback[IOBase]] = ...,
+ raw: HTTPResponse = ...,
+ exc: Union[Exception, Type[Exception]] = ...,
+ additional_matcher: AdditionalMatcher = ...,
+ json_encoder: Optional[Type[JSONEncoder]] = ...,
+ **kwargs: Any,
+ ) -> _Matcher: ...
+
+ def patch(
+ self,
+ url: Union[str, Pattern[str], AnyMatcher],
+ response_list: Optional[List[Dict[str, Any]]] = ...,
+ *,
+ request_headers: Dict[str, str] = ...,
+ complete_qs: bool = ...,
+ status_code: int = ...,
+ reason: str = ...,
+ headers: Dict[str, str] = ...,
+ cookies: Union[CookieJar, Dict[str, str]] = ...,
+ json: Union[Any, Callback[Any]] = ...,
+ text: Union[str, Callback[str]] = ...,
+ content: Union[bytes, Callback[bytes]] = ...,
+ body: Union[IOBase, Callback[IOBase]] = ...,
+ raw: HTTPResponse = ...,
+ exc: Union[Exception, Type[Exception]] = ...,
+ additional_matcher: AdditionalMatcher = ...,
+ json_encoder: Optional[Type[JSONEncoder]] = ...,
+ **kwargs: Any,
+ ) -> _Matcher: ...
+
+ def delete(
+ self,
+ url: Union[str, Pattern[str], AnyMatcher],
+ response_list: Optional[List[Dict[str, Any]]] = ...,
+ *,
+ request_headers: Dict[str, str] = ...,
+ complete_qs: bool = ...,
+ status_code: int = ...,
+ reason: str = ...,
+ headers: Dict[str, str] = ...,
+ cookies: Union[CookieJar, Dict[str, str]] = ...,
+ json: Union[Any, Callback[Any]] = ...,
+ text: Union[str, Callback[str]] = ...,
+ content: Union[bytes, Callback[bytes]] = ...,
+ body: Union[IOBase, Callback[IOBase]] = ...,
+ raw: HTTPResponse = ...,
+ exc: Union[Exception, Type[Exception]] = ...,
+ additional_matcher: AdditionalMatcher = ...,
+ json_encoder: Optional[Type[JSONEncoder]] = ...,
+ **kwargs: Any,
+ ) -> _Matcher: ...
+
+_T = TypeVar('_T')
+
+class Mocker(MockerCore):
+ TEST_PREFIX: str = ...
+ real_http: bool = ...
+
+ def __init__(
+ self,
+ kw: str = ...,
+ case_sensitive: bool = ...,
+ adapter: Any = ...,
+ session: Optional[Session] = ...,
+ real_http: bool = ...,
+ json_encoder: Optional[Type[JSONEncoder]] = ...,
+ ) -> None: ...
+ def __enter__(self) -> Any: ...
+ def __exit__(self, type: Any, value: Any, traceback: Any) -> None: ...
+ def __call__(self, obj: Any) -> Any: ...
+ def copy(self) -> Mocker: ...
+ def decorate_callable(self, func: Callable[..., _T]) -> Callable[..., _T]: ...
+ def decorate_class(self, klass: Type[_T]) -> Type[_T]: ...
+
+mock = Mocker
diff --git a/contrib/python/requests-mock/py2/requests_mock/py.typed b/contrib/python/requests-mock/py2/requests_mock/py.typed
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/contrib/python/requests-mock/py2/requests_mock/py.typed
diff --git a/contrib/python/requests-mock/py2/requests_mock/request.py b/contrib/python/requests-mock/py2/requests_mock/request.py
new file mode 100644
index 0000000000..05cbc3d4a3
--- /dev/null
+++ b/contrib/python/requests-mock/py2/requests_mock/request.py
@@ -0,0 +1,178 @@
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import copy
+import json
+
+import requests
+import six
+from six.moves.urllib import parse as urlparse
+
+
+class _RequestObjectProxy(object):
+ """A wrapper around a requests.Request that gives some extra information.
+
+ This will be important both for matching and so that when it's save into
+ the request_history users will be able to access these properties.
+ """
+
+ def __init__(self, request, **kwargs):
+ self._request = request
+ self._matcher = None
+ self._url_parts_ = None
+ self._qs = None
+
+ # All of these params should always exist but we use a default
+ # to make the test setup easier.
+ self._timeout = kwargs.pop('timeout', None)
+ self._allow_redirects = kwargs.pop('allow_redirects', None)
+ self._verify = kwargs.pop('verify', None)
+ self._stream = kwargs.pop('stream', None)
+ self._cert = kwargs.pop('cert', None)
+ self._proxies = copy.deepcopy(kwargs.pop('proxies', {}))
+
+ # FIXME(jamielennox): This is part of bug #1584008 and should default
+ # to True (or simply removed) in a major version bump.
+ self._case_sensitive = kwargs.pop('case_sensitive', False)
+
+ def __getattr__(self, name):
+ # there should be a better way to exclude this, but I don't want to
+ # implement __setstate__ just not forward it to the request. You can't
+ # actually define the method and raise AttributeError there either.
+ if name in ('__setstate__',):
+ raise AttributeError(name)
+
+ return getattr(self._request, name)
+
+ @property
+ def _url_parts(self):
+ if self._url_parts_ is None:
+ url = self._request.url
+
+ if not self._case_sensitive:
+ url = url.lower()
+
+ self._url_parts_ = urlparse.urlparse(url)
+
+ return self._url_parts_
+
+ @property
+ def scheme(self):
+ return self._url_parts.scheme
+
+ @property
+ def netloc(self):
+ return self._url_parts.netloc
+
+ @property
+ def hostname(self):
+ try:
+ return self.netloc.split(':')[0]
+ except IndexError:
+ return ''
+
+ @property
+ def port(self):
+ components = self.netloc.split(':')
+
+ try:
+ return int(components[1])
+ except (IndexError, ValueError):
+ pass
+
+ if self.scheme == 'https':
+ return 443
+ if self.scheme == 'http':
+ return 80
+
+ # The default return shouldn't matter too much because if you are
+ # wanting to test this value you really should be explicitly setting it
+ # somewhere. 0 at least is a boolean False and an int.
+ return 0
+
+ @property
+ def path(self):
+ return self._url_parts.path
+
+ @property
+ def query(self):
+ return self._url_parts.query
+
+ @property
+ def qs(self):
+ if self._qs is None:
+ self._qs = urlparse.parse_qs(self.query, keep_blank_values=True)
+
+ return self._qs
+
+ @property
+ def timeout(self):
+ return self._timeout
+
+ @property
+ def allow_redirects(self):
+ return self._allow_redirects
+
+ @property
+ def verify(self):
+ return self._verify
+
+ @property
+ def stream(self):
+ return self._stream
+
+ @property
+ def cert(self):
+ return self._cert
+
+ @property
+ def proxies(self):
+ return self._proxies
+
+ @classmethod
+ def _create(cls, *args, **kwargs):
+ return cls(requests.Request(*args, **kwargs).prepare())
+
+ @property
+ def text(self):
+ body = self.body
+
+ if isinstance(body, six.binary_type):
+ body = body.decode('utf-8')
+
+ return body
+
+ def json(self, **kwargs):
+ return json.loads(self.text, **kwargs)
+
+ def __getstate__(self):
+ # Can't pickle a weakref, but it's a weakref so ok to drop it.
+ d = self.__dict__.copy()
+ d['_matcher'] = None
+ return d
+
+ @property
+ def matcher(self):
+ """The matcher that this request was handled by.
+
+ The matcher object is handled by a weakref. It will return the matcher
+ object if it is still available - so if the mock is still in place. If
+ the matcher is not available it will return None.
+ """
+ # if unpickled or not from a response this will be None
+ if self._matcher is None:
+ return None
+
+ return self._matcher()
+
+ def __str__(self):
+ return "{0.method} {0.url}".format(self._request)
diff --git a/contrib/python/requests-mock/py2/requests_mock/request.pyi b/contrib/python/requests-mock/py2/requests_mock/request.pyi
new file mode 100644
index 0000000000..5e2fb30d20
--- /dev/null
+++ b/contrib/python/requests-mock/py2/requests_mock/request.pyi
@@ -0,0 +1,41 @@
+# Stubs for requests_mock.request
+
+from typing import Any, Dict, List
+
+class _RequestObjectProxy:
+ def __init__(self, request: Any, **kwargs: Any) -> None: ...
+ def __getattr__(self, name: str) -> Any: ...
+ @property
+ def scheme(self) -> str: ...
+ @property
+ def netloc(self) -> str: ...
+ @property
+ def hostname(self) -> str: ...
+ @property
+ def port(self) -> int: ...
+ @property
+ def path(self) -> str: ...
+ @property
+ def query(self) -> str: ...
+ @property
+ def qs(self) -> Dict[str, List[str]]: ...
+ @property
+ def timeout(self) -> int: ...
+ @property
+ def allow_redirects(self) -> bool: ...
+ @property
+ def verify(self) -> Any: ...
+ @property
+ def stream(self) -> Any: ...
+ @property
+ def cert(self) -> Any: ...
+ @property
+ def proxies(self) -> Any: ...
+ @property
+ def text(self) -> str: ...
+ def json(self, **kwargs: Any) -> Any: ...
+ @property
+ def matcher(self) -> Any: ...
+
+
+Request = _RequestObjectProxy
diff --git a/contrib/python/requests-mock/py2/requests_mock/response.py b/contrib/python/requests-mock/py2/requests_mock/response.py
new file mode 100644
index 0000000000..5855539273
--- /dev/null
+++ b/contrib/python/requests-mock/py2/requests_mock/response.py
@@ -0,0 +1,281 @@
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import json as jsonutils
+
+from requests.adapters import HTTPAdapter
+from requests.cookies import MockRequest, MockResponse
+from requests.cookies import RequestsCookieJar
+from requests.cookies import merge_cookies, cookiejar_from_dict
+from requests.packages.urllib3.response import HTTPResponse
+from requests.utils import get_encoding_from_headers
+import six
+
+from requests_mock import compat
+from requests_mock import exceptions
+
+_BODY_ARGS = frozenset(['raw', 'body', 'content', 'text', 'json'])
+_HTTP_ARGS = frozenset([
+ 'status_code',
+ 'reason',
+ 'headers',
+ 'cookies',
+ 'json_encoder',
+])
+
+_DEFAULT_STATUS = 200
+_http_adapter = HTTPAdapter()
+
+
+class CookieJar(RequestsCookieJar):
+
+ def set(self, name, value, **kwargs):
+ """Add a cookie to the Jar.
+
+ :param str name: cookie name/key.
+ :param str value: cookie value.
+ :param int version: Integer or None. Netscape cookies have version 0.
+ RFC 2965 and RFC 2109 cookies have a version cookie-attribute of 1.
+ However, note that cookielib may 'downgrade' RFC 2109 cookies to
+ Netscape cookies, in which case version is 0.
+ :param str port: String representing a port or a set of ports
+ (eg. '80', or '80,8080'),
+ :param str domain: The domain the cookie should apply to.
+ :param str path: Cookie path (a string, eg. '/acme/rocket_launchers').
+ :param bool secure: True if cookie should only be returned over a
+ secure connection.
+ :param int expires: Integer expiry date in seconds since epoch or None.
+ :param bool discard: True if this is a session cookie.
+ :param str comment: String comment from the server explaining the
+ function of this cookie.
+ :param str comment_url: URL linking to a comment from the server
+ explaining the function of this cookie.
+ """
+ # just here to provide the function documentation
+ return super(CookieJar, self).set(name, value, **kwargs)
+
+
+def _check_body_arguments(**kwargs):
+ # mutual exclusion, only 1 body method may be provided
+ provided = [x for x in _BODY_ARGS if kwargs.pop(x, None) is not None]
+
+ if len(provided) > 1:
+ raise RuntimeError('You may only supply one body element. You '
+ 'supplied %s' % ', '.join(provided))
+
+ extra = [x for x in kwargs if x not in _HTTP_ARGS]
+
+ if extra:
+ raise TypeError('Too many arguments provided. Unexpected '
+ 'arguments %s.' % ', '.join(extra))
+
+
+class _FakeConnection(object):
+ """An object that can mock the necessary parts of a socket interface."""
+
+ def send(self, request, **kwargs):
+ msg = 'This response was created without a connection. You are ' \
+ 'therefore unable to make a request directly on that connection.'
+ raise exceptions.InvalidRequest(msg)
+
+ def close(self):
+ pass
+
+
+def _extract_cookies(request, response, cookies):
+ """Add cookies to the response.
+
+ Cookies in requests are extracted from the headers in the original_response
+ httplib.HTTPMessage which we don't create so we have to do this step
+ manually.
+ """
+ # This will add cookies set manually via the Set-Cookie or Set-Cookie2
+ # header but this only allows 1 cookie to be set.
+ http_message = compat._FakeHTTPMessage(response.headers)
+ response.cookies.extract_cookies(MockResponse(http_message),
+ MockRequest(request))
+
+ # This allows you to pass either a CookieJar or a dictionary to request_uri
+ # or directly to create_response. To allow more than one cookie to be set.
+ if cookies:
+ merge_cookies(response.cookies, cookies)
+
+
+class _IOReader(six.BytesIO):
+ """A reader that makes a BytesIO look like a HTTPResponse.
+
+ A HTTPResponse will return an empty string when you read from it after
+ the socket has been closed. A BytesIO will raise a ValueError. For
+ compatibility we want to do the same thing a HTTPResponse does.
+ """
+
+ def read(self, *args, **kwargs):
+ if self.closed:
+ return six.b('')
+
+ # if the file is open, but you asked for zero bytes read you should get
+ # back zero without closing the stream.
+ if len(args) > 0 and args[0] == 0:
+ return six.b('')
+
+ # not a new style object in python 2
+ result = six.BytesIO.read(self, *args, **kwargs)
+
+ # when using resp.iter_content(None) it'll go through a different
+ # request path in urllib3. This path checks whether the object is
+ # marked closed instead of the return value. see gh124.
+ if result == six.b(''):
+ self.close()
+
+ return result
+
+
+def create_response(request, **kwargs):
+ """
+ :param int status_code: The status code to return upon a successful
+ match. Defaults to 200.
+ :param HTTPResponse raw: A HTTPResponse object to return upon a
+ successful match.
+ :param io.IOBase body: An IO object with a read() method that can
+ return a body on successful match.
+ :param bytes content: A byte string to return upon a successful match.
+ :param unicode text: A text string to return upon a successful match.
+ :param object json: A python object to be converted to a JSON string
+ and returned upon a successful match.
+ :param class json_encoder: Encoder object to use for JOSON.
+ :param dict headers: A dictionary object containing headers that are
+ returned upon a successful match.
+ :param CookieJar cookies: A cookie jar with cookies to set on the
+ response.
+
+ :returns requests.Response: A response object that can
+ be returned to requests.
+ """
+ connection = kwargs.pop('connection', _FakeConnection())
+
+ _check_body_arguments(**kwargs)
+
+ raw = kwargs.pop('raw', None)
+ body = kwargs.pop('body', None)
+ content = kwargs.pop('content', None)
+ text = kwargs.pop('text', None)
+ json = kwargs.pop('json', None)
+ headers = kwargs.pop('headers', {})
+ encoding = None
+
+ if content is not None and not isinstance(content, six.binary_type):
+ raise TypeError('Content should be binary data')
+ if text is not None and not isinstance(text, six.string_types):
+ raise TypeError('Text should be string data')
+
+ if json is not None:
+ encoder = kwargs.pop('json_encoder', None) or jsonutils.JSONEncoder
+ text = jsonutils.dumps(json, cls=encoder)
+ if text is not None:
+ encoding = get_encoding_from_headers(headers) or 'utf-8'
+ content = text.encode(encoding)
+ if content is not None:
+ body = _IOReader(content)
+ if not raw:
+ status = kwargs.get('status_code', _DEFAULT_STATUS)
+ reason = kwargs.get('reason',
+ six.moves.http_client.responses.get(status))
+
+ raw = HTTPResponse(status=status,
+ reason=reason,
+ headers=headers,
+ body=body or _IOReader(six.b('')),
+ decode_content=False,
+ enforce_content_length=False,
+ preload_content=False,
+ original_response=None)
+
+ response = _http_adapter.build_response(request, raw)
+ response.connection = connection
+
+ if encoding and not response.encoding:
+ response.encoding = encoding
+
+ _extract_cookies(request, response, kwargs.get('cookies'))
+
+ return response
+
+
+class _Context(object):
+ """Stores the data being used to process a current URL match."""
+
+ def __init__(self, headers, status_code, reason, cookies):
+ self.headers = headers
+ self.status_code = status_code
+ self.reason = reason
+ self.cookies = cookies
+
+
+class _MatcherResponse(object):
+
+ def __init__(self, **kwargs):
+ self._exc = kwargs.pop('exc', None)
+
+ # If the user is asking for an exception to be thrown then prevent them
+ # specifying any sort of body or status response as it won't be used.
+ # This may be protecting the user too much but can be removed later.
+ if self._exc and kwargs:
+ raise TypeError('Cannot provide other arguments with exc.')
+
+ _check_body_arguments(**kwargs)
+ self._params = kwargs
+
+ # whilst in general you shouldn't do type checking in python this
+ # makes sure we don't end up with differences between the way types
+ # are handled between python 2 and 3.
+ content = self._params.get('content')
+ text = self._params.get('text')
+
+ if content is not None and not (callable(content) or
+ isinstance(content, six.binary_type)):
+ raise TypeError('Content should be a callback or binary data')
+
+ if text is not None and not (callable(text) or
+ isinstance(text, six.string_types)):
+ raise TypeError('Text should be a callback or string data')
+
+ def get_response(self, request):
+ # if an error was requested then raise that instead of doing response
+ if self._exc:
+ raise self._exc
+
+ # If a cookie dict is passed convert it into a CookieJar so that the
+ # cookies object available in a callback context is always a jar.
+ cookies = self._params.get('cookies', CookieJar())
+ if isinstance(cookies, dict):
+ cookies = cookiejar_from_dict(cookies, CookieJar())
+
+ context = _Context(self._params.get('headers', {}).copy(),
+ self._params.get('status_code', _DEFAULT_STATUS),
+ self._params.get('reason'),
+ cookies)
+
+ # if a body element is a callback then execute it
+ def _call(f, *args, **kwargs):
+ return f(request, context, *args, **kwargs) if callable(f) else f
+
+ return create_response(request,
+ json=_call(self._params.get('json')),
+ text=_call(self._params.get('text')),
+ content=_call(self._params.get('content')),
+ body=_call(self._params.get('body')),
+ raw=self._params.get('raw'),
+ json_encoder=self._params.get('json_encoder'),
+ status_code=context.status_code,
+ reason=context.reason,
+ headers=context.headers,
+ cookies=context.cookies)
diff --git a/contrib/python/requests-mock/py2/requests_mock/response.pyi b/contrib/python/requests-mock/py2/requests_mock/response.pyi
new file mode 100644
index 0000000000..e7c8977883
--- /dev/null
+++ b/contrib/python/requests-mock/py2/requests_mock/response.pyi
@@ -0,0 +1,38 @@
+# Stubs for requests_mock.response
+
+from typing import Any, Dict
+
+import six
+
+from requests import Request, Response
+from requests.cookies import RequestsCookieJar
+
+class CookieJar(RequestsCookieJar):
+ def set(self, name: Any, value: Any, **kwargs: Any) -> Any: ...
+
+class _FakeConnection:
+ def send(self, request: Any, **kwargs: Any) -> None: ...
+ def close(self) -> None: ...
+
+class _IOReader(six.BytesIO):
+ def read(self, *args: Any, **kwargs: Any) -> Any: ...
+
+def create_response(request: Any, **kwargs: Any) -> Response: ...
+
+class _Context:
+ headers: Dict[str,str] = ...
+ status_code: int = ...
+ reason: str = ...
+ cookies: Any = ...
+
+ def __init__(self,
+ headers: Dict[str, str],
+ status_code: int,
+ reason: str,
+ cookies: Any) -> None: ...
+
+class _MatcherResponse:
+ def __init__(self, **kwargs: Any) -> None: ...
+ def get_response(self, request: Request) -> Response: ...
+
+Context = _Context
diff --git a/contrib/python/requests-mock/py2/tests/__init__.py b/contrib/python/requests-mock/py2/tests/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/contrib/python/requests-mock/py2/tests/__init__.py
diff --git a/contrib/python/requests-mock/py2/tests/base.py b/contrib/python/requests-mock/py2/tests/base.py
new file mode 100644
index 0000000000..ecc872ecb7
--- /dev/null
+++ b/contrib/python/requests-mock/py2/tests/base.py
@@ -0,0 +1,17 @@
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import unittest
+
+
+class TestCase(unittest.TestCase):
+ pass
diff --git a/contrib/python/requests-mock/py2/tests/pytest/__init__.py b/contrib/python/requests-mock/py2/tests/pytest/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/contrib/python/requests-mock/py2/tests/pytest/__init__.py
diff --git a/contrib/python/requests-mock/py2/tests/pytest/pytest.ini b/contrib/python/requests-mock/py2/tests/pytest/pytest.ini
new file mode 100644
index 0000000000..58c87f21b7
--- /dev/null
+++ b/contrib/python/requests-mock/py2/tests/pytest/pytest.ini
@@ -0,0 +1,2 @@
+[pytest]
+requests_mock_case_sensitive=false
diff --git a/contrib/python/requests-mock/py2/tests/pytest/test_with_pytest.py b/contrib/python/requests-mock/py2/tests/pytest/test_with_pytest.py
new file mode 100644
index 0000000000..d74908bc38
--- /dev/null
+++ b/contrib/python/requests-mock/py2/tests/pytest/test_with_pytest.py
@@ -0,0 +1,119 @@
+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):
+ requests_mock.get('https://httpbin.org/get', text='data')
+ 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_base = "https://www.example.com/"
+
+ text_middle = 'middle' + url_middle
+ text_outer = 'outer' + url_outer
+ text_base = 'outer' + url_base
+
+ with requests_mock.Mocker() as outer_mock:
+ outer_mock.get(url_base, text=text_base)
+ outer_mock.get(url_outer, text=text_outer)
+
+ with requests_mock.Mocker(real_http=True) as middle_mock:
+ middle_mock.get(url_middle, text=text_middle)
+
+ with requests_mock.Mocker() as inner_mock:
+ inner_mock.post(url_inner,
+ status_code=HTTP_STATUS_FOUND,
+ headers={'location': url_base})
+ inner_mock.get(url_base, real_http=True)
+
+ assert text_base == 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 text_middle == requests.get(url_middle).text # nosec
+ assert text_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 text_outer == requests.get(url_outer).text # nosec
+
+
+def test_mixed_mocks():
+ url = 'mock://example.test/'
+ with requests_mock.Mocker() as global_mock:
+ global_mock.get(url, text='global')
+ session = requests.Session()
+ text = session.get(url).text
+ assert text == 'global' # nosec
+ with requests_mock.Mocker(session=session) as session_mock:
+ session_mock.get(url, real_http=True)
+ text = session.get(url).text
+ assert text == 'global' # nosec
+
+
+def test_threaded_sessions():
+ """
+ When using requests_futures.FuturesSession() with a ThreadPoolExecutor
+ there is a race condition where one threaded request removes the
+ monkeypatched get_adapter() method from the Session before another threaded
+ request is finished using it.
+ """
+ from requests_futures.sessions import FuturesSession
+
+ url1 = 'http://www.example.com/requests-mock-fake-url1'
+ url2 = 'http://www.example.com/requests-mock-fake-url2'
+
+ with requests_mock.Mocker() as m:
+ # respond with 204 so we know its us
+ m.get(url1, status_code=204)
+ m.get(url2, status_code=204)
+
+ # NOTE(phodge): just firing off two .get() requests right after each
+ # other was a pretty reliable way to reproduce the race condition on my
+ # intel Macbook Pro but YMMV. Guaranteeing the race condition to
+ # reappear might require replacing the Session.send() with a wrapper
+ # that delays kicking off the request for url1 until the request for
+ # url2 has restored the original session.get_adapter(), but replacing
+ # Session.send() could be difficult because the requests_mock.Mocker()
+ # context manager has *already* monkeypatched this method.
+ session = FuturesSession()
+ future1 = session.get(url1)
+ future2 = session.get(url2)
+
+ # verify both requests were handled by the mock dispatcher
+ assert future1.result().status_code == 204
+ assert future2.result().status_code == 204
+
+
+class TestClass(object):
+
+ def configure(self, requests_mock):
+ requests_mock.get('https://httpbin.org/get', text='data')
+
+ def test_one(self, requests_mock):
+ self.configure(requests_mock)
+ assert 'data' == requests.get('https://httpbin.org/get').text
diff --git a/contrib/python/requests-mock/py2/tests/test_adapter.py b/contrib/python/requests-mock/py2/tests/test_adapter.py
new file mode 100644
index 0000000000..2913727072
--- /dev/null
+++ b/contrib/python/requests-mock/py2/tests/test_adapter.py
@@ -0,0 +1,707 @@
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import json
+import re
+
+import purl
+import requests
+import six
+from six.moves.urllib import parse as urlparse
+
+import requests_mock
+from . import base
+
+
+class MyExc(Exception):
+ pass
+
+
+class SessionAdapterTests(base.TestCase):
+
+ PREFIX = "mock"
+
+ def setUp(self):
+ super(SessionAdapterTests, self).setUp()
+
+ self.adapter = requests_mock.Adapter()
+ self.session = requests.Session()
+ self.session.mount(self.PREFIX, self.adapter)
+
+ self.url = '%s://example.com/test' % self.PREFIX
+ self.headers = {'header_a': 'A', 'header_b': 'B'}
+
+ def assertHeaders(self, resp):
+ for k, v in six.iteritems(self.headers):
+ self.assertEqual(v, resp.headers[k])
+
+ def assertLastRequest(self, method='GET', body=None):
+ self.assertEqual(self.url, self.adapter.last_request.url)
+ self.assertEqual(method, self.adapter.last_request.method)
+ self.assertEqual(body, self.adapter.last_request.body)
+
+ url_parts = urlparse.urlparse(self.url)
+ qs = urlparse.parse_qs(url_parts.query)
+ self.assertEqual(url_parts.scheme, self.adapter.last_request.scheme)
+ self.assertEqual(url_parts.netloc, self.adapter.last_request.netloc)
+ self.assertEqual(url_parts.path, self.adapter.last_request.path)
+ self.assertEqual(url_parts.query, self.adapter.last_request.query)
+ self.assertEqual(url_parts.query, self.adapter.last_request.query)
+ self.assertEqual(qs, self.adapter.last_request.qs)
+
+ def test_content(self):
+ data = six.b('testdata')
+
+ self.adapter.register_uri('GET',
+ self.url,
+ content=data,
+ headers=self.headers)
+ resp = self.session.get(self.url)
+ self.assertEqual(data, resp.content)
+ self.assertHeaders(resp)
+ self.assertLastRequest()
+
+ def test_content_callback(self):
+ status_code = 401
+ data = six.b('testdata')
+
+ def _content_cb(request, context):
+ context.status_code = status_code
+ context.headers.update(self.headers)
+ return data
+
+ self.adapter.register_uri('GET',
+ self.url,
+ content=_content_cb)
+ resp = self.session.get(self.url)
+ self.assertEqual(status_code, resp.status_code)
+ self.assertEqual(data, resp.content)
+ self.assertHeaders(resp)
+ self.assertLastRequest()
+
+ def test_text(self):
+ data = 'testdata'
+
+ self.adapter.register_uri('GET',
+ self.url,
+ text=data,
+ headers=self.headers)
+ resp = self.session.get(self.url)
+ self.assertEqual(six.b(data), resp.content)
+ self.assertEqual(six.u(data), resp.text)
+ self.assertEqual('utf-8', resp.encoding)
+ self.assertHeaders(resp)
+ self.assertLastRequest()
+
+ def test_text_callback(self):
+ status_code = 401
+ data = 'testdata'
+
+ def _text_cb(request, context):
+ context.status_code = status_code
+ context.headers.update(self.headers)
+ return six.u(data)
+
+ self.adapter.register_uri('GET', self.url, text=_text_cb)
+ resp = self.session.get(self.url)
+ self.assertEqual(status_code, resp.status_code)
+ self.assertEqual(six.u(data), resp.text)
+ self.assertEqual(six.b(data), resp.content)
+ self.assertEqual('utf-8', resp.encoding)
+ self.assertHeaders(resp)
+ self.assertLastRequest()
+
+ def test_json(self):
+ json_data = {'hello': 'world'}
+ self.adapter.register_uri('GET',
+ self.url,
+ json=json_data,
+ headers=self.headers)
+ resp = self.session.get(self.url)
+ self.assertEqual(six.b('{"hello": "world"}'), resp.content)
+ self.assertEqual(six.u('{"hello": "world"}'), resp.text)
+ self.assertEqual(json_data, resp.json())
+ self.assertEqual('utf-8', resp.encoding)
+ self.assertHeaders(resp)
+ self.assertLastRequest()
+
+ def test_json_callback(self):
+ status_code = 401
+ json_data = {'hello': 'world'}
+ data = '{"hello": "world"}'
+
+ def _json_cb(request, context):
+ context.status_code = status_code
+ context.headers.update(self.headers)
+ return json_data
+
+ self.adapter.register_uri('GET', self.url, json=_json_cb)
+ resp = self.session.get(self.url)
+ self.assertEqual(status_code, resp.status_code)
+ self.assertEqual(json_data, resp.json())
+ self.assertEqual(six.u(data), resp.text)
+ self.assertEqual(six.b(data), resp.content)
+ self.assertEqual('utf-8', resp.encoding)
+ self.assertHeaders(resp)
+ self.assertLastRequest()
+
+ def test_no_body(self):
+ self.adapter.register_uri('GET', self.url)
+ resp = self.session.get(self.url)
+ self.assertEqual(six.b(''), resp.content)
+ self.assertEqual(200, resp.status_code)
+
+ def test_multiple_body_elements(self):
+ self.assertRaises(RuntimeError,
+ self.adapter.register_uri,
+ self.url,
+ 'GET',
+ content=six.b('b'),
+ text=six.u('u'))
+
+ def test_multiple_responses(self):
+ inp = [{'status_code': 400, 'text': 'abcd'},
+ {'status_code': 300, 'text': 'defg'},
+ {'status_code': 200, 'text': 'hijk'}]
+
+ self.adapter.register_uri('GET', self.url, inp)
+ out = [self.session.get(self.url) for i in range(0, len(inp))]
+
+ for i, o in zip(inp, out):
+ for k, v in six.iteritems(i):
+ self.assertEqual(v, getattr(o, k))
+
+ last = self.session.get(self.url)
+ for k, v in six.iteritems(inp[-1]):
+ self.assertEqual(v, getattr(last, k))
+
+ def test_callback_optional_status(self):
+ headers = {'a': 'b'}
+
+ def _test_cb(request, context):
+ context.headers.update(headers)
+ return ''
+
+ self.adapter.register_uri('GET',
+ self.url,
+ text=_test_cb,
+ status_code=300)
+ resp = self.session.get(self.url)
+ self.assertEqual(300, resp.status_code)
+
+ for k, v in six.iteritems(headers):
+ self.assertEqual(v, resp.headers[k])
+
+ def test_callback_optional_headers(self):
+ headers = {'a': 'b'}
+
+ def _test_cb(request, context):
+ context.status_code = 300
+ return ''
+
+ self.adapter.register_uri('GET',
+ self.url,
+ text=_test_cb,
+ headers=headers)
+
+ resp = self.session.get(self.url)
+ self.assertEqual(300, resp.status_code)
+
+ for k, v in six.iteritems(headers):
+ self.assertEqual(v, resp.headers[k])
+
+ def test_latest_register_overrides(self):
+ self.adapter.register_uri('GET', self.url, text='abc')
+ self.adapter.register_uri('GET', self.url, text='def')
+
+ resp = self.session.get(self.url)
+ self.assertEqual('def', resp.text)
+
+ def test_no_last_request(self):
+ self.assertIsNone(self.adapter.last_request)
+ self.assertEqual(0, len(self.adapter.request_history))
+
+ def test_dont_pass_list_and_kwargs(self):
+ self.assertRaises(RuntimeError,
+ self.adapter.register_uri,
+ 'GET',
+ self.url,
+ [{'text': 'a'}],
+ headers={'a': 'b'})
+
+ def test_empty_string_return(self):
+ # '' evaluates as False, so make sure an empty string is not ignored.
+ self.adapter.register_uri('GET', self.url, text='')
+ resp = self.session.get(self.url)
+ self.assertEqual('', resp.text)
+
+ def test_dont_pass_multiple_bodies(self):
+ self.assertRaises(RuntimeError,
+ self.adapter.register_uri,
+ 'GET',
+ self.url,
+ json={'abc': 'def'},
+ text='ghi')
+
+ def test_dont_pass_unexpected_kwargs(self):
+ self.assertRaises(TypeError,
+ self.adapter.register_uri,
+ 'GET',
+ self.url,
+ unknown='argument')
+
+ def test_dont_pass_unicode_as_content(self):
+ self.assertRaises(TypeError,
+ self.adapter.register_uri,
+ 'GET',
+ self.url,
+ content=six.u('unicode'))
+
+ def test_dont_pass_empty_string_as_content(self):
+ self.assertRaises(TypeError,
+ self.adapter.register_uri,
+ 'GET',
+ self.url,
+ content=six.u(''))
+
+ def test_dont_pass_bytes_as_text(self):
+ if six.PY2:
+ self.skipTest('Cannot enforce byte behaviour in PY2')
+
+ self.assertRaises(TypeError,
+ self.adapter.register_uri,
+ 'GET',
+ self.url,
+ text=six.b('bytes'))
+
+ def test_dont_pass_empty_string_as_text(self):
+ if six.PY2:
+ self.skipTest('Cannot enforce byte behaviour in PY2')
+
+ self.assertRaises(TypeError,
+ self.adapter.register_uri,
+ 'GET',
+ self.url,
+ text=six.b(''))
+
+ def test_dont_pass_non_str_as_content(self):
+ self.assertRaises(TypeError,
+ self.adapter.register_uri,
+ 'GET',
+ self.url,
+ content=5)
+
+ def test_dont_pass_non_str_as_text(self):
+ self.assertRaises(TypeError,
+ self.adapter.register_uri,
+ 'GET',
+ self.url,
+ text=5)
+
+ def test_with_any_method(self):
+ self.adapter.register_uri(requests_mock.ANY, self.url, text='resp')
+
+ for m in ('GET', 'HEAD', 'POST', 'UNKNOWN'):
+ resp = self.session.request(m, self.url)
+ self.assertEqual('resp', resp.text)
+
+ def test_with_any_url(self):
+ self.adapter.register_uri('GET', requests_mock.ANY, text='resp')
+
+ for u in ('mock://a', 'mock://b', 'mock://c'):
+ resp = self.session.get(u)
+ self.assertEqual('resp', resp.text)
+
+ def test_with_regexp(self):
+ self.adapter.register_uri('GET', re.compile('tester.com'), text='resp')
+
+ for u in ('mock://www.tester.com/a', 'mock://abc.tester.com'):
+ resp = self.session.get(u)
+ self.assertEqual('resp', resp.text)
+
+ def test_with_purl(self):
+ self.adapter.register_uri('GET',
+ purl.URL('mock://www.tester.com/a'),
+ text='resp')
+
+ resp = self.session.get('mock://www.tester.com/a')
+ self.assertEqual('resp', resp.text)
+
+ def test_requests_in_history_on_no_match(self):
+ self.assertRaises(requests_mock.NoMockAddress,
+ self.session.get,
+ self.url)
+
+ self.assertEqual(self.url, self.adapter.last_request.url)
+
+ def test_requests_in_history_on_exception(self):
+
+ def _test_cb(request, ctx):
+ raise MyExc()
+
+ self.adapter.register_uri('GET', self.url, text=_test_cb)
+
+ self.assertRaises(MyExc,
+ self.session.get,
+ self.url)
+
+ self.assertEqual(self.url, self.adapter.last_request.url)
+
+ def test_not_called_and_called_count(self):
+ m = self.adapter.register_uri('GET', self.url, text='resp')
+ self.assertEqual(0, m.call_count)
+ self.assertFalse(m.called)
+ self.assertFalse(m.called_once)
+
+ self.assertEqual(0, self.adapter.call_count)
+ self.assertFalse(self.adapter.called)
+ self.assertFalse(m.called_once)
+
+ def test_called_and_called_count(self):
+ m = self.adapter.register_uri('GET', self.url, text='resp')
+
+ resps = [self.session.get(self.url) for i in range(0, 3)]
+
+ for r in resps:
+ self.assertEqual('resp', r.text)
+ self.assertEqual(200, r.status_code)
+
+ self.assertEqual(len(resps), m.call_count)
+ self.assertTrue(m.called)
+ self.assertFalse(m.called_once)
+
+ self.assertEqual(len(resps), self.adapter.call_count)
+ self.assertTrue(self.adapter.called)
+ self.assertFalse(m.called_once)
+
+ def test_reset_reverts_call_count(self):
+ # Create matchers and add calls to history
+ call_count = 3
+ matcher_count = 3
+ for i in range(matcher_count):
+ url = self.url + str(i)
+ self.adapter.register_uri('GET', url, text='resp')
+ for _ in range(call_count):
+ self.session.get(url)
+
+ # Verify call counts on adapter and matchers
+ self.assertEqual(self.adapter.call_count, matcher_count * call_count)
+ for matcher in self.adapter._matchers:
+ self.assertEqual(matcher.call_count, call_count)
+
+ self.adapter.reset()
+
+ # Verify call counts are 0 after reset
+ self.assertEqual(self.adapter.call_count, 0)
+ for matcher in self.adapter._matchers:
+ self.assertEqual(matcher.call_count, 0)
+
+ def test_adapter_picks_correct_adapter(self):
+ good = '%s://test3.url/' % self.PREFIX
+ self.adapter.register_uri('GET',
+ '%s://test1.url' % self.PREFIX,
+ text='bad')
+ self.adapter.register_uri('GET',
+ '%s://test2.url' % self.PREFIX,
+ text='bad')
+ self.adapter.register_uri('GET', good, text='good')
+ self.adapter.register_uri('GET',
+ '%s://test4.url' % self.PREFIX,
+ text='bad')
+
+ resp = self.session.get(good)
+
+ self.assertEqual('good', resp.text)
+
+ def test_adapter_is_connection(self):
+ url = '%s://test.url' % self.PREFIX
+ text = 'text'
+ self.adapter.register_uri('GET', url, text=text)
+ resp = self.session.get(url)
+
+ self.assertEqual(text, resp.text)
+ self.assertIs(self.adapter, resp.connection)
+
+ def test_send_to_connection(self):
+ url1 = '%s://test1.url/' % self.PREFIX
+ url2 = '%s://test2.url/' % self.PREFIX
+
+ text1 = 'text1'
+ text2 = 'text2'
+
+ self.adapter.register_uri('GET', url1, text=text1)
+ self.adapter.register_uri('GET', url2, text=text2)
+
+ req = requests.Request(method='GET', url=url2).prepare()
+
+ resp1 = self.session.get(url1)
+ self.assertEqual(text1, resp1.text)
+
+ resp2 = resp1.connection.send(req)
+ self.assertEqual(text2, resp2.text)
+
+ def test_request_json_with_str_data(self):
+ dict_req = {'hello': 'world'}
+ dict_resp = {'goodbye': 'world'}
+
+ m = self.adapter.register_uri('POST', self.url, json=dict_resp)
+
+ data = json.dumps(dict_req)
+ resp = self.session.post(self.url, data=data)
+
+ self.assertIs(data, m.last_request.body)
+ self.assertEqual(dict_resp, resp.json())
+ self.assertEqual(dict_req, m.last_request.json())
+
+ def test_request_json_with_bytes_data(self):
+ dict_req = {'hello': 'world'}
+ dict_resp = {'goodbye': 'world'}
+
+ m = self.adapter.register_uri('POST', self.url, json=dict_resp)
+
+ data = json.dumps(dict_req).encode('utf-8')
+ resp = self.session.post(self.url, data=data)
+
+ self.assertIs(data, m.last_request.body)
+ self.assertEqual(dict_resp, resp.json())
+ self.assertEqual(dict_req, m.last_request.json())
+
+ def test_request_json_with_cb(self):
+ dict_req = {'hello': 'world'}
+ dict_resp = {'goodbye': 'world'}
+ data = json.dumps(dict_req)
+
+ def _cb(req, context):
+ self.assertEqual(dict_req, req.json())
+ return dict_resp
+
+ m = self.adapter.register_uri('POST', self.url, json=_cb)
+ resp = self.session.post(self.url, data=data)
+
+ self.assertEqual(1, m.call_count)
+ self.assertTrue(m.called_once)
+ self.assertEqual(dict_resp, resp.json())
+
+ def test_raises_exception(self):
+ self.adapter.register_uri('GET', self.url, exc=MyExc)
+
+ self.assertRaises(MyExc,
+ self.session.get,
+ self.url)
+
+ self.assertTrue(self.adapter.called_once)
+ self.assertEqual(self.url, self.adapter.last_request.url)
+
+ def test_raises_exception_with_body_args_fails(self):
+ self.assertRaises(TypeError,
+ self.adapter.register_uri,
+ 'GET',
+ self.url,
+ exc=MyExc,
+ text='fail')
+
+ def test_sets_request_matcher_in_history(self):
+ url1 = '%s://test1.url/' % self.PREFIX
+ url2 = '%s://test2.url/' % self.PREFIX
+
+ text1 = 'text1'
+ text2 = 'text2'
+
+ m1 = self.adapter.register_uri('GET', url1, text=text1)
+ m2 = self.adapter.register_uri('GET', url2, text=text2)
+
+ resp1 = self.session.get(url1)
+ resp2 = self.session.get(url2)
+
+ self.assertEqual(text1, resp1.text)
+ self.assertEqual(text2, resp2.text)
+
+ self.assertEqual(2, self.adapter.call_count)
+ self.assertFalse(self.adapter.called_once)
+
+ self.assertEqual(url1, self.adapter.request_history[0].url)
+ self.assertEqual(url2, self.adapter.request_history[1].url)
+
+ self.assertIs(m1, self.adapter.request_history[0].matcher)
+ self.assertIs(m2, self.adapter.request_history[1].matcher)
+
+ def test_sets_request_matcher_on_exception(self):
+ m = self.adapter.register_uri('GET', self.url, exc=MyExc)
+
+ self.assertRaises(MyExc,
+ self.session.get,
+ self.url)
+
+ self.assertEqual(self.url, self.adapter.last_request.url)
+ self.assertIs(m, self.adapter.last_request.matcher)
+
+ def test_cookies_from_header(self):
+ headers = {'Set-Cookie': 'fig=newton; Path=/test; domain=.example.com'}
+ self.adapter.register_uri('GET',
+ self.url,
+ text='text',
+ headers=headers)
+
+ resp = self.session.get(self.url)
+
+ self.assertEqual('newton', resp.cookies['fig'])
+ self.assertEqual(['/test'], resp.cookies.list_paths())
+ self.assertEqual(['.example.com'], resp.cookies.list_domains())
+
+ def test_cookies_from_dict(self):
+ # This is a syntax we get from requests. I'm not sure i like it.
+ self.adapter.register_uri('GET',
+ self.url,
+ text='text',
+ cookies={'fig': 'newton', 'sugar': 'apple'})
+
+ resp = self.session.get(self.url)
+
+ self.assertEqual('newton', resp.cookies['fig'])
+ self.assertEqual('apple', resp.cookies['sugar'])
+
+ def test_cookies_with_jar(self):
+ jar = requests_mock.CookieJar()
+ jar.set('fig', 'newton', path='/foo', domain='.example.com')
+ jar.set('sugar', 'apple', path='/bar', domain='.example.com')
+
+ self.adapter.register_uri('GET', self.url, text='text', cookies=jar)
+ resp = self.session.get(self.url)
+
+ self.assertEqual('newton', resp.cookies['fig'])
+ self.assertEqual('apple', resp.cookies['sugar'])
+ self.assertEqual({'/foo', '/bar'}, set(resp.cookies.list_paths()))
+ self.assertEqual(['.example.com'], resp.cookies.list_domains())
+
+ def test_cookies_header_with_cb(self):
+
+ def _cb(request, context):
+ val = 'fig=newton; Path=/test; domain=.example.com'
+ context.headers['Set-Cookie'] = val
+ return 'text'
+
+ self.adapter.register_uri('GET', self.url, text=_cb)
+ resp = self.session.get(self.url)
+
+ self.assertEqual('newton', resp.cookies['fig'])
+ self.assertEqual(['/test'], resp.cookies.list_paths())
+ self.assertEqual(['.example.com'], resp.cookies.list_domains())
+
+ def test_cookies_from_dict_with_cb(self):
+ def _cb(request, context):
+ # converted into a jar by now
+ context.cookies.set('sugar', 'apple', path='/test')
+ return 'text'
+
+ self.adapter.register_uri('GET',
+ self.url,
+ text=_cb,
+ cookies={'fig': 'newton'})
+
+ resp = self.session.get(self.url)
+
+ self.assertEqual('newton', resp.cookies['fig'])
+ self.assertEqual('apple', resp.cookies['sugar'])
+ self.assertEqual(['/', '/test'], resp.cookies.list_paths())
+
+ def test_cookies_with_jar_cb(self):
+ def _cb(request, context):
+ context.cookies.set('sugar',
+ 'apple',
+ path='/bar',
+ domain='.example.com')
+ return 'text'
+
+ jar = requests_mock.CookieJar()
+ jar.set('fig', 'newton', path='/foo', domain='.example.com')
+
+ self.adapter.register_uri('GET', self.url, text=_cb, cookies=jar)
+ resp = self.session.get(self.url)
+
+ self.assertEqual('newton', resp.cookies['fig'])
+ self.assertEqual('apple', resp.cookies['sugar'])
+ self.assertEqual({'/foo', '/bar'}, set(resp.cookies.list_paths()))
+ self.assertEqual(['.example.com'], resp.cookies.list_domains())
+
+ def test_reading_closed_fp(self):
+ self.adapter.register_uri('GET', self.url, text='abc')
+ resp = self.session.get(self.url)
+
+ # raw will have been closed during the request reading
+ self.assertTrue(resp.raw.closed)
+
+ data = resp.raw.read()
+
+ self.assertIsInstance(data, six.binary_type)
+ self.assertEqual(0, len(data))
+
+ def test_case_sensitive_headers(self):
+ data = 'testdata'
+ headers = {'aBcDe': 'FgHiJ'}
+
+ self.adapter.register_uri('GET', self.url, text=data)
+ resp = self.session.get(self.url, headers=headers)
+
+ self.assertEqual('GET', self.adapter.last_request.method)
+ self.assertEqual(200, resp.status_code)
+ self.assertEqual(data, resp.text)
+
+ for k, v in headers.items():
+ self.assertEqual(v, self.adapter.last_request.headers[k])
+
+ def test_case_sensitive_history(self):
+ self.adapter._case_sensitive = True
+
+ data = 'testdata'
+ netloc = 'examPlE.CoM'
+ path = '/TesTER'
+ query = 'aBC=deF'
+
+ mock_url = '%s://%s%s' % (self.PREFIX, netloc.lower(), path)
+ request_url = '%s://%s%s?%s' % (self.PREFIX, netloc, path, query)
+
+ # test that the netloc is ignored when actually making the request
+ self.adapter.register_uri('GET', mock_url, text=data)
+ resp = self.session.get(request_url)
+
+ self.assertEqual('GET', self.adapter.last_request.method)
+ self.assertEqual(200, resp.status_code)
+ self.assertEqual(data, resp.text)
+
+ # but even still the mixed case parameters come out in history
+ self.assertEqual(netloc, self.adapter.last_request.netloc)
+ self.assertEqual(path, self.adapter.last_request.path)
+ self.assertEqual(query, self.adapter.last_request.query)
+
+ def test_stream_none(self):
+ text = 'hello world'
+
+ self.adapter.register_uri('GET',
+ self.url,
+ text=text,
+ headers=self.headers)
+
+ resp = self.session.get(self.url, stream=True)
+ resps = [c for c in resp.iter_content(None, decode_unicode=True)]
+ self.assertEqual([text], resps)
+
+ def test_stream_size(self):
+ text = 'hello world'
+
+ self.adapter.register_uri('GET',
+ self.url,
+ text=text,
+ headers=self.headers)
+
+ resp = self.session.get(self.url, stream=True)
+ resps = [c for c in resp.iter_content(3, decode_unicode=True)]
+ self.assertEqual(['hel', 'lo ', 'wor', 'ld'], resps)
diff --git a/contrib/python/requests-mock/py2/tests/test_custom_matchers.py b/contrib/python/requests-mock/py2/tests/test_custom_matchers.py
new file mode 100644
index 0000000000..546a63e2f1
--- /dev/null
+++ b/contrib/python/requests-mock/py2/tests/test_custom_matchers.py
@@ -0,0 +1,75 @@
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import requests
+import six
+
+import requests_mock
+from . import base
+
+
+class FailMatcher(object):
+
+ def __init___(self):
+ self.called = False
+
+ def __call__(self, request):
+ self.called = True
+ return None
+
+
+def match_all(request):
+ return requests_mock.create_response(request, content=six.b('data'))
+
+
+class CustomMatchersTests(base.TestCase):
+
+ def assertMatchAll(self, resp):
+ self.assertEqual(200, resp.status_code)
+ self.assertEqual(resp.text, six.u('data'))
+
+ @requests_mock.Mocker()
+ def test_custom_matcher(self, mocker):
+ mocker.add_matcher(match_all)
+
+ resp = requests.get('http://any/thing')
+ self.assertMatchAll(resp)
+
+ @requests_mock.Mocker()
+ def test_failing_matcher(self, mocker):
+ failer = FailMatcher()
+
+ mocker.add_matcher(match_all)
+ mocker.add_matcher(failer)
+
+ resp = requests.get('http://any/thing')
+
+ self.assertMatchAll(resp)
+ self.assertTrue(failer.called)
+
+ @requests_mock.Mocker()
+ def test_some_pass(self, mocker):
+
+ def matcher_a(request):
+ if 'a' in request.url:
+ return match_all(request)
+
+ return None
+
+ mocker.add_matcher(matcher_a)
+
+ resp = requests.get('http://any/thing')
+ self.assertMatchAll(resp)
+
+ self.assertRaises(requests_mock.NoMockAddress,
+ requests.get,
+ 'http://other/thing')
diff --git a/contrib/python/requests-mock/py2/tests/test_fixture.py b/contrib/python/requests-mock/py2/tests/test_fixture.py
new file mode 100644
index 0000000000..63cbb99141
--- /dev/null
+++ b/contrib/python/requests-mock/py2/tests/test_fixture.py
@@ -0,0 +1,39 @@
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import requests
+import requests_mock
+from requests_mock.contrib import fixture
+from . import base
+
+
+class MockingTests(base.TestCase):
+
+ def setUp(self):
+ super(MockingTests, self).setUp()
+ self.mocker = self.useFixture(fixture.Fixture())
+
+ def test_failure(self):
+ self.assertRaises(requests_mock.NoMockAddress,
+ requests.get,
+ 'http://www.google.com')
+
+ def test_basic(self):
+ test_url = 'http://www.google.com/'
+ self.mocker.register_uri('GET', test_url, text='response')
+
+ resp = requests.get(test_url)
+ self.assertEqual('response', resp.text)
+ self.assertEqual(test_url, self.mocker.last_request.url)
+
+ def test_fixture_has_normal_attr_error(self):
+ self.assertRaises(AttributeError, lambda: self.mocker.unknown)
diff --git a/contrib/python/requests-mock/py2/tests/test_matcher.py b/contrib/python/requests-mock/py2/tests/test_matcher.py
new file mode 100644
index 0000000000..a30e195966
--- /dev/null
+++ b/contrib/python/requests-mock/py2/tests/test_matcher.py
@@ -0,0 +1,324 @@
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import re
+
+from requests_mock import adapter
+from . import base
+from requests_mock.response import _MatcherResponse
+
+ANY = adapter.ANY
+
+
+class TestMatcher(base.TestCase):
+
+ def match(self,
+ target,
+ url,
+ matcher_method='GET',
+ request_method='GET',
+ complete_qs=False,
+ headers=None,
+ request_data=None,
+ request_headers={},
+ additional_matcher=None,
+ real_http=False,
+ case_sensitive=False):
+ matcher = adapter._Matcher(matcher_method,
+ target,
+ [],
+ complete_qs=complete_qs,
+ additional_matcher=additional_matcher,
+ request_headers=request_headers,
+ real_http=real_http,
+ case_sensitive=case_sensitive)
+ request = adapter._RequestObjectProxy._create(request_method,
+ url,
+ headers,
+ data=request_data)
+ return matcher._match(request)
+
+ def assertMatch(self,
+ target=ANY,
+ url='http://example.com/requests-mock',
+ matcher_method='GET',
+ request_method='GET',
+ **kwargs):
+ self.assertEqual(True,
+ self.match(target,
+ url,
+ matcher_method=matcher_method,
+ request_method=request_method,
+ **kwargs),
+ 'Matcher %s %s failed to match %s %s' %
+ (matcher_method, target, request_method, url))
+
+ def assertMatchBoth(self,
+ target=ANY,
+ url='http://example.com/requests-mock',
+ matcher_method='GET',
+ request_method='GET',
+ **kwargs):
+ self.assertMatch(target,
+ url,
+ matcher_method=matcher_method,
+ request_method=request_method,
+ **kwargs)
+ self.assertMatch(url,
+ target,
+ matcher_method=request_method,
+ request_method=matcher_method,
+ **kwargs)
+
+ def assertNoMatch(self,
+ target=ANY,
+ url='http://example.com/requests-mock',
+ matcher_method='GET',
+ request_method='GET',
+ **kwargs):
+ self.assertEqual(False,
+ self.match(target,
+ url,
+ matcher_method=matcher_method,
+ request_method=request_method,
+ **kwargs),
+ 'Matcher %s %s unexpectedly matched %s %s' %
+ (matcher_method, target, request_method, url))
+
+ def assertNoMatchBoth(self,
+ target=ANY,
+ url='http://example.com/requests-mock',
+ matcher_method='GET',
+ request_method='GET',
+ **kwargs):
+ self.assertNoMatch(target,
+ url,
+ matcher_method=matcher_method,
+ request_method=request_method,
+ **kwargs)
+ self.assertNoMatch(url,
+ target,
+ matcher_method=request_method,
+ request_method=matcher_method,
+ **kwargs)
+
+ def assertMatchMethodBoth(self, matcher_method, request_method, **kwargs):
+ url = 'http://www.test.com'
+
+ self.assertMatchBoth(url,
+ url,
+ request_method=request_method,
+ matcher_method=matcher_method,
+ **kwargs)
+
+ def assertNoMatchMethodBoth(self,
+ matcher_method,
+ request_method,
+ **kwargs):
+ url = 'http://www.test.com'
+
+ self.assertNoMatchBoth(url,
+ url,
+ request_method=request_method,
+ matcher_method=matcher_method,
+ **kwargs)
+
+ def test_url_matching(self):
+ self.assertMatchBoth('http://www.test.com',
+ 'http://www.test.com')
+ self.assertMatchBoth('http://www.test.com',
+ 'http://www.test.com/')
+ self.assertMatchBoth('http://www.test.com/abc',
+ 'http://www.test.com/abc')
+ self.assertMatchBoth('http://www.test.com:5000/abc',
+ 'http://www.test.com:5000/abc')
+ self.assertNoMatchBoth('https://www.test.com',
+ 'http://www.test.com')
+ self.assertNoMatchBoth('http://www.test.com/abc',
+ 'http://www.test.com')
+ self.assertNoMatchBoth('http://test.com',
+ 'http://www.test.com')
+ self.assertNoMatchBoth('http://test.com',
+ 'http://www.test.com')
+ self.assertNoMatchBoth('http://test.com/abc',
+ 'http://www.test.com/abc/')
+ self.assertNoMatchBoth('http://test.com/abc/',
+ 'http://www.test.com/abc')
+ self.assertNoMatchBoth('http://test.com:5000/abc/',
+ 'http://www.test.com/abc')
+ self.assertNoMatchBoth('http://test.com/abc/',
+ 'http://www.test.com:5000/abc')
+
+ def test_quotation(self):
+ self.assertMatchBoth('http://www.test.com/a string%url',
+ 'http://www.test.com/a string%url')
+ self.assertMatchBoth('http://www.test.com/ABC 123',
+ 'http://www.test.com/ABC%20123')
+ self.assertMatchBoth('http://www.test.com/user@example.com',
+ 'http://www.test.com/user@example.com')
+
+ def test_subset_match(self):
+ self.assertMatch('/path', 'http://www.test.com/path')
+ self.assertMatch('/path', 'http://www.test.com/path')
+ self.assertMatch('//www.test.com/path', 'http://www.test.com/path')
+ self.assertMatch('//www.test.com/path', 'https://www.test.com/path')
+
+ def test_query_string(self):
+ self.assertMatch('/path?a=1&b=2',
+ 'http://www.test.com/path?a=1&b=2')
+ self.assertMatch('/path?a=1',
+ 'http://www.test.com/path?a=1&b=2',
+ complete_qs=False)
+ self.assertNoMatch('/path?a=1',
+ 'http://www.test.com/path?a=1&b=2',
+ complete_qs=True)
+ self.assertNoMatch('/path?a=1&b=2',
+ 'http://www.test.com/path?a=1')
+
+ def test_query_empty_string(self):
+ self.assertMatch('/path?a',
+ 'http://www.test.com/path?a')
+ self.assertMatch('/path?bob&paul',
+ 'http://www.test.com/path?paul&bob')
+ self.assertNoMatch('/path?bob',
+ 'http://www.test.com/path?paul')
+ self.assertNoMatch('/path?pual&bob',
+ 'http://www.test.com/path?bob')
+
+ def test_method_match(self):
+ self.assertNoMatchMethodBoth('GET', 'POST')
+ self.assertMatchMethodBoth('GET', 'get')
+ self.assertMatchMethodBoth('GeT', 'geT')
+
+ def test_match_ANY_url(self):
+ self.assertMatch(ANY, 'http://anything')
+ self.assertMatch(ANY, 'http://somethingelse')
+ self.assertNoMatch(ANY, 'http://somethingelse', request_method='POST')
+
+ def test_match_ANY_method(self):
+ for m in ('GET', 'POST', 'HEAD', 'OPTION'):
+ self.assertMatch('http://www.test.com',
+ 'http://www.test.com',
+ matcher_method=ANY,
+ request_method=m)
+
+ self.assertNoMatch('http://www.test.com',
+ 'http://another',
+ matcher_method=ANY)
+
+ def test_match_with_regex(self):
+ r1 = re.compile('test.com/a')
+ r2 = re.compile('/b/c')
+
+ self.assertMatch(r1, 'http://mock.test.com/a/b')
+ self.assertMatch(r1, 'http://test.com/a/')
+ self.assertMatch(r1, 'mock://test.com/a/b')
+ self.assertNoMatch(r1, 'mock://test.com/')
+
+ self.assertMatch(r2, 'http://anything/a/b/c/d')
+ self.assertMatch(r2, 'mock://anything/a/b/c/d')
+
+ def test_match_with_headers(self):
+ self.assertMatch('/path',
+ 'http://www.test.com/path',
+ headers={'A': 'abc', 'b': 'def'},
+ request_headers={'a': 'abc'})
+
+ self.assertMatch('/path',
+ 'http://www.test.com/path',
+ headers={'A': 'abc', 'b': 'def'})
+
+ self.assertNoMatch('/path',
+ 'http://www.test.com/path',
+ headers={'A': 'abc', 'b': 'def'},
+ request_headers={'b': 'abc'})
+
+ self.assertNoMatch('/path',
+ 'http://www.test.com/path',
+ headers={'A': 'abc', 'b': 'def'},
+ request_headers={'c': 'ghi'})
+
+ # headers should be key insensitive and value sensitive, we have no
+ # choice here because they go into an insensitive dict.
+ self.assertMatch('/path',
+ 'http://www.test.com/path',
+ headers={'aBc': 'abc', 'DEF': 'def'},
+ request_headers={'abC': 'abc'})
+
+ self.assertNoMatch('/path',
+ 'http://www.test.com/path',
+ headers={'abc': 'aBC', 'DEF': 'def'},
+ request_headers={'abc': 'Abc'})
+
+ def test_case_sensitive_ignored_for_netloc_and_protocol(self):
+ for case_sensitive in (True, False):
+ self.assertMatch('http://AbC.CoM',
+ 'http://aBc.CoM',
+ case_sensitive=case_sensitive)
+
+ self.assertMatch('htTP://abc.com',
+ 'hTTp://abc.com',
+ case_sensitive=case_sensitive)
+
+ self.assertMatch('htTP://aBC.cOm',
+ 'hTTp://AbC.Com',
+ case_sensitive=case_sensitive)
+
+ def assertSensitiveMatch(self, target, url, **kwargs):
+ self.assertMatch(target, url, case_sensitive=False, **kwargs)
+ self.assertNoMatch(target, url, case_sensitive=True, **kwargs)
+
+ def test_case_sensitive_paths(self):
+ self.assertSensitiveMatch('http://abc.com/pAtH', 'http://abc.com/path')
+ self.assertSensitiveMatch('/pAtH', 'http://abc.com/path')
+
+ def test_case_sensitive_query(self):
+ self.assertSensitiveMatch('http://abc.com/path?abCD=efGH',
+ 'http://abc.com/path?abCd=eFGH')
+
+ self.assertSensitiveMatch('http://abc.com/path?abcd=efGH',
+ 'http://abc.com/path?abcd=eFGH')
+
+ def test_additional_matcher(self):
+
+ def test_match_body(request):
+ return 'hello' in request.text
+
+ self.assertMatch(request_method='POST',
+ matcher_method='POST',
+ request_data='hello world',
+ additional_matcher=test_match_body)
+
+ self.assertNoMatch(request_method='POST',
+ matcher_method='POST',
+ request_data='goodbye world',
+ additional_matcher=test_match_body)
+
+ def test_reset_reverts_count(self):
+ url = 'mock://test/site/'
+ matcher = adapter._Matcher('GET',
+ url,
+ [_MatcherResponse()],
+ complete_qs=False,
+ additional_matcher=None,
+ request_headers={},
+ real_http=False,
+ case_sensitive=False)
+ request = adapter._RequestObjectProxy._create('GET', url)
+
+ call_count = 3
+ for _ in range(call_count):
+ matcher(request)
+
+ self.assertEqual(matcher.call_count, call_count)
+ matcher.reset()
+ self.assertEqual(matcher.call_count, 0)
diff --git a/contrib/python/requests-mock/py2/tests/test_mocker.py b/contrib/python/requests-mock/py2/tests/test_mocker.py
new file mode 100644
index 0000000000..7a4061c6bd
--- /dev/null
+++ b/contrib/python/requests-mock/py2/tests/test_mocker.py
@@ -0,0 +1,646 @@
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import json
+import pickle
+
+try:
+ from unittest import mock
+except ImportError:
+ import mock
+import requests
+
+import requests_mock
+from requests_mock import adapter
+from requests_mock import exceptions
+from requests_mock import response
+from . import base
+
+original_send = requests.Session.send
+
+
+class MockerTests(base.TestCase):
+
+ def assertMockStarted(self):
+ self.assertNotEqual(original_send, requests.Session.send)
+
+ def assertMockStopped(self):
+ self.assertEqual(original_send, requests.Session.send)
+
+ def _do_test(self, m):
+ self.assertMockStarted()
+ matcher = m.register_uri('GET', 'http://www.test.com', text='resp')
+ resp = requests.get('http://www.test.com')
+ self.assertEqual('resp', resp.text)
+ return matcher
+
+ def test_multiple_starts(self):
+ mocker = requests_mock.Mocker()
+ self.assertMockStopped()
+ mocker.start()
+ self.assertMockStarted()
+ self.assertRaises(RuntimeError, mocker.start)
+ mocker.stop()
+ self.assertMockStopped()
+ mocker.stop()
+
+ def test_with_session(self):
+ url = 'http://test.url/path'
+ url_inner = 'http://test.url/inner'
+ url_outer = 'http://test.url/outer'
+ with requests_mock.Mocker() as global_mock:
+ global_mock.get(url_outer, text='global')
+
+ session_a = requests.Session()
+ session_b = requests.Session()
+
+ session_a_original_send = session_a.send
+ session_b_original_send = session_b.send
+ self.assertNotEqual(session_a_original_send,
+ session_b_original_send)
+
+ mocker_a = requests_mock.Mocker(session=session_a)
+ mocker_b = requests_mock.Mocker(session=session_b)
+
+ mocker_a.start()
+ mocker_b.start()
+
+ mocker_a.register_uri('GET', url, text='resp_a')
+ mocker_a.register_uri('GET', url_outer, real_http=True)
+ mocker_b.register_uri('GET', url, text='resp_b')
+
+ with requests_mock.Mocker(session=session_b) as mocker_b_inner:
+ mocker_b_inner.register_uri('GET', url, real_http=True)
+ mocker_b_inner.register_uri('GET',
+ url_inner,
+ text='resp_b_inner')
+
+ self.assertEqual('resp_a', session_a.get(url).text)
+ self.assertEqual('resp_b', session_b.get(url).text)
+ self.assertRaises(exceptions.NoMockAddress,
+ session_a.get,
+ url_inner)
+ self.assertEqual('resp_b_inner', session_b.get(url_inner).text)
+
+ self.assertEqual('resp_a', session_a.get(url).text)
+ self.assertEqual('resp_b', session_b.get(url).text)
+ self.assertRaises(exceptions.NoMockAddress,
+ session_a.get,
+ url_inner)
+ self.assertRaises(exceptions.NoMockAddress,
+ session_b.get,
+ url_inner)
+ self.assertEqual('global', session_a.get(url_outer).text)
+ self.assertRaises(exceptions.NoMockAddress,
+ session_b.get,
+ url_outer)
+
+ self.assertNotEqual(session_a.send, session_a_original_send)
+ self.assertNotEqual(session_b.send, session_b_original_send)
+ self.assertNotEqual(session_a.send, session_b.send)
+
+ mocker_a.stop()
+ mocker_b.stop()
+
+ self.assertEqual(session_a.send, session_a_original_send)
+ self.assertEqual(session_b.send, session_b_original_send)
+
+ self.assertEqual(requests.Session.send, original_send)
+
+ def test_with_context_manager(self):
+ self.assertMockStopped()
+ with requests_mock.Mocker() as m:
+ self._do_test(m)
+ self.assertMockStopped()
+
+ @mock.patch('requests.adapters.HTTPAdapter.send')
+ @requests_mock.mock(real_http=True)
+ def test_real_http(self, real_send, mocker):
+ url = 'http://www.google.com/'
+ test_text = 'real http data'
+ test_bytes = test_text.encode('utf-8')
+
+ # using create_response is a bit bootstrappy here but so long as it's
+ # coming from HTTPAdapter.send it's ok
+ req = requests.Request(method='GET', url=url)
+ real_send.return_value = response.create_response(req.prepare(),
+ status_code=200,
+ content=test_bytes)
+ resp = requests.get(url)
+
+ self.assertEqual(1, real_send.call_count)
+ self.assertEqual(url, real_send.call_args[0][0].url)
+
+ self.assertEqual(test_text, resp.text)
+ self.assertEqual(test_bytes, resp.content)
+
+ @mock.patch('requests.adapters.HTTPAdapter.send')
+ def test_real_http_changes(self, real_send):
+ url = 'http://www.google.com/'
+ test_text = 'real http data'
+ test_bytes = test_text.encode('utf-8')
+
+ req = requests.Request(method='GET', url=url)
+ real_send.return_value = response.create_response(req.prepare(),
+ status_code=200,
+ content=test_bytes)
+
+ with requests_mock.Mocker() as m:
+ # real_http defaults to false so should raise NoMockAddress
+
+ self.assertRaises(exceptions.NoMockAddress,
+ requests.get,
+ url)
+
+ self.assertEqual(1, m.call_count)
+ self.assertEqual(0, real_send.call_count)
+
+ # change the value of real_http mid test
+ m.real_http = True
+
+ # fetch the url again and it should go through to the real url that
+ # we've mocked out at a lower level.
+ resp = requests.get(url)
+
+ self.assertEqual(1, real_send.call_count)
+ self.assertEqual(url, real_send.call_args[0][0].url)
+
+ self.assertEqual(test_text, resp.text)
+ self.assertEqual(test_bytes, resp.content)
+
+ @mock.patch('requests.adapters.HTTPAdapter.send')
+ def test_real_http_and_session(self, real_send):
+ url = 'http://www.google.com/'
+ test_text = 'real http data'
+ test_bytes = test_text.encode('utf-8')
+
+ req = requests.Request(method='GET', url=url)
+ real_send.return_value = response.create_response(req.prepare(),
+ status_code=200,
+ content=test_bytes)
+
+ session = requests.Session()
+ with requests_mock.Mocker(session=session, real_http=True):
+ resp = session.get(url)
+
+ self.assertEqual(test_text, resp.text)
+ self.assertEqual(test_bytes, resp.content)
+
+ @requests_mock.mock()
+ def test_with_test_decorator(self, m):
+ self._do_test(m)
+
+ @requests_mock.mock(kw='mock')
+ def test_with_mocker_kwargs(self, **kwargs):
+ self._do_test(kwargs['mock'])
+
+ def test_with_decorator(self):
+
+ @requests_mock.mock()
+ def inner(m):
+ self.assertMockStarted()
+ self._do_test(m)
+
+ self.assertMockStopped()
+ inner()
+ self.assertMockStopped()
+
+ def test_with_decorator_called_multiple_times(self):
+
+ @requests_mock.Mocker()
+ def inner(arg1, m):
+ self._do_test(m)
+ self.assertEquals(
+ len(m.request_history), 1,
+ "Failed to provide clean mock on subsequent calls"
+ )
+
+ inner('a')
+ # if we call the same decorated method again should get
+ # a new request mock
+ inner('b')
+
+ def test_with_class_decorator(self):
+ outer = self
+
+ @requests_mock.mock()
+ class Decorated(object):
+
+ def test_will_be_decorated(self, m):
+ outer.assertMockStarted()
+ outer._do_test(m)
+
+ def will_not_be_decorated(self):
+ outer.assertMockStopped()
+
+ decorated_class = Decorated()
+
+ self.assertMockStopped()
+ decorated_class.test_will_be_decorated()
+ self.assertMockStopped()
+ decorated_class.will_not_be_decorated()
+ self.assertMockStopped()
+
+ def test_with_class_decorator_and_custom_kw(self):
+ outer = self
+
+ @requests_mock.mock(kw='custom_m')
+ class Decorated(object):
+
+ def test_will_be_decorated(self, **kwargs):
+ outer.assertMockStarted()
+ outer._do_test(kwargs['custom_m'])
+
+ def will_not_be_decorated(self):
+ outer.assertMockStopped()
+
+ decorated_class = Decorated()
+
+ self.assertMockStopped()
+ decorated_class.test_will_be_decorated()
+ self.assertMockStopped()
+ decorated_class.will_not_be_decorated()
+ self.assertMockStopped()
+
+ @mock.patch.object(requests_mock.mock, 'TEST_PREFIX', 'foo')
+ def test_with_class_decorator_and_custom_test_prefix(self):
+ outer = self
+
+ @requests_mock.mock()
+ class Decorated(object):
+
+ def foo_will_be_decorated(self, m):
+ outer.assertMockStarted()
+ outer._do_test(m)
+
+ def will_not_be_decorated(self):
+ outer.assertMockStopped()
+
+ decorated_class = Decorated()
+
+ self.assertMockStopped()
+ decorated_class.foo_will_be_decorated()
+ self.assertMockStopped()
+ decorated_class.will_not_be_decorated()
+ self.assertMockStopped()
+
+ @requests_mock.mock()
+ def test_query_string(self, m):
+ url = 'http://test.url/path'
+ qs = 'a=1&b=2'
+ m.register_uri('GET', url, text='resp')
+ resp = requests.get("%s?%s" % (url, qs))
+
+ self.assertEqual('resp', resp.text)
+
+ self.assertEqual(qs, m.last_request.query)
+ self.assertEqual(['1'], m.last_request.qs['a'])
+ self.assertEqual(['2'], m.last_request.qs['b'])
+
+ @requests_mock.mock()
+ def test_mock_matcher_attributes(self, m):
+ matcher = self._do_test(m)
+
+ self.assertEqual(1, matcher.call_count)
+ self.assertEqual(1, m.call_count)
+
+ self.assertTrue(matcher.called)
+ self.assertTrue(matcher.called_once)
+ self.assertTrue(m.called)
+ self.assertTrue(m.called_once)
+
+ self.assertEqual(m.request_history, matcher.request_history)
+ self.assertIs(m.last_request, matcher.last_request)
+
+ def test_copy(self):
+ mocker = requests_mock.mock(kw='foo', real_http=True)
+ copy_of_mocker = mocker.copy()
+ self.assertIsNot(copy_of_mocker, mocker)
+ self.assertEqual(copy_of_mocker._kw, mocker._kw)
+ self.assertEqual(copy_of_mocker.real_http, mocker.real_http)
+
+ @requests_mock.mock()
+ def test_reset_mock_reverts_call_count(self, request_mock):
+ url = 'http://test.url/path'
+ request_mock.get(url, text='resp')
+ requests.get(url)
+
+ self.assertEqual(request_mock.call_count, 1)
+
+ # reset count and verify it is 0
+ request_mock.reset_mock()
+ self.assertEqual(request_mock.call_count, 0)
+
+
+class MockerHttpMethodsTests(base.TestCase):
+
+ URL = 'http://test.com/path'
+ TEXT = 'resp'
+
+ def assertResponse(self, resp):
+ self.assertEqual(self.TEXT, resp.text)
+
+ @requests_mock.Mocker()
+ def test_mocker_request(self, m):
+ method = 'XXX'
+ mock_obj = m.request(method, self.URL, text=self.TEXT)
+ resp = requests.request(method, self.URL)
+ self.assertResponse(resp)
+ self.assertTrue(mock_obj.called)
+ self.assertTrue(mock_obj.called_once)
+ self.assertTrue(m.called)
+ self.assertTrue(m.called_once)
+
+ @requests_mock.Mocker()
+ def test_mocker_get(self, m):
+ mock_obj = m.get(self.URL, text=self.TEXT)
+ self.assertResponse(requests.get(self.URL))
+ self.assertTrue(mock_obj.called)
+ self.assertTrue(mock_obj.called_once)
+ self.assertTrue(m.called)
+ self.assertTrue(m.called_once)
+
+ @requests_mock.Mocker()
+ def test_mocker_options(self, m):
+ mock_obj = m.options(self.URL, text=self.TEXT)
+ self.assertResponse(requests.options(self.URL))
+ self.assertTrue(mock_obj.called)
+ self.assertTrue(mock_obj.called_once)
+ self.assertTrue(m.called)
+ self.assertTrue(m.called_once)
+
+ @requests_mock.Mocker()
+ def test_mocker_head(self, m):
+ mock_obj = m.head(self.URL, text=self.TEXT)
+ self.assertResponse(requests.head(self.URL))
+ self.assertTrue(mock_obj.called)
+ self.assertTrue(mock_obj.called_once)
+ self.assertTrue(m.called)
+ self.assertTrue(m.called_once)
+
+ @requests_mock.Mocker()
+ def test_mocker_post(self, m):
+ mock_obj = m.post(self.URL, text=self.TEXT)
+ self.assertResponse(requests.post(self.URL))
+ self.assertTrue(mock_obj.called)
+ self.assertTrue(mock_obj.called_once)
+ self.assertTrue(m.called)
+ self.assertTrue(m.called_once)
+
+ @requests_mock.Mocker()
+ def test_mocker_put(self, m):
+ mock_obj = m.put(self.URL, text=self.TEXT)
+ self.assertResponse(requests.put(self.URL))
+ self.assertTrue(mock_obj.called)
+ self.assertTrue(mock_obj.called_once)
+ self.assertTrue(m.called)
+ self.assertTrue(m.called_once)
+
+ @requests_mock.Mocker()
+ def test_mocker_patch(self, m):
+ mock_obj = m.patch(self.URL, text=self.TEXT)
+ self.assertResponse(requests.patch(self.URL))
+ self.assertTrue(mock_obj.called)
+ self.assertTrue(mock_obj.called_once)
+ self.assertTrue(m.called)
+ self.assertTrue(m.called_once)
+
+ @requests_mock.Mocker()
+ def test_mocker_delete(self, m):
+ mock_obj = m.delete(self.URL, text=self.TEXT)
+ self.assertResponse(requests.delete(self.URL))
+ self.assertTrue(mock_obj.called)
+ self.assertTrue(mock_obj.called_once)
+ self.assertTrue(m.called)
+ self.assertTrue(m.called_once)
+
+ @requests_mock.Mocker()
+ def test_mocker_real_http_and_responses(self, m):
+ self.assertRaises(RuntimeError,
+ m.get,
+ self.URL,
+ text='abcd',
+ real_http=True)
+
+ @requests_mock.Mocker()
+ def test_mocker_real_http(self, m):
+ data = 'testdata'
+
+ uri1 = 'fake://example.com/foo'
+ uri2 = 'fake://example.com/bar'
+ uri3 = 'fake://example.com/baz'
+
+ m.get(uri1, text=data)
+ m.get(uri2, real_http=True)
+
+ self.assertEqual(data, requests.get(uri1).text)
+
+ # This should fail because requests can't get an adapter for mock://
+ # but it shows that it has tried and would have made a request.
+ self.assertRaises(requests.exceptions.InvalidSchema,
+ requests.get,
+ uri2)
+
+ # This fails because real_http is not set on the mocker
+ self.assertRaises(exceptions.NoMockAddress,
+ requests.get,
+ uri3)
+
+ # do it again to make sure the mock is still in place
+ self.assertEqual(data, requests.get(uri1).text)
+
+ @requests_mock.Mocker(case_sensitive=True)
+ def test_case_sensitive_query(self, m):
+ data = 'testdata'
+ query = {'aBcDe': 'FgHiJ'}
+
+ m.get(self.URL, text=data)
+ resp = requests.get(self.URL, params=query)
+
+ self.assertEqual('GET', m.last_request.method)
+ self.assertEqual(200, resp.status_code)
+ self.assertEqual(data, resp.text)
+
+ for k, v in query.items():
+ self.assertEqual([v], m.last_request.qs[k])
+
+ @mock.patch.object(requests_mock.Mocker, 'case_sensitive', True)
+ def test_global_case_sensitive(self):
+ with requests_mock.mock() as m:
+ data = 'testdata'
+ query = {'aBcDe': 'FgHiJ'}
+
+ m.get(self.URL, text=data)
+ resp = requests.get(self.URL, params=query)
+
+ self.assertEqual('GET', m.last_request.method)
+ self.assertEqual(200, resp.status_code)
+ self.assertEqual(data, resp.text)
+
+ for k, v in query.items():
+ self.assertEqual([v], m.last_request.qs[k])
+
+ def test_nested_mocking(self):
+ url1 = 'http://url1.com/path1'
+ url2 = 'http://url2.com/path2'
+ url3 = 'http://url3.com/path3'
+
+ data1 = 'data1'
+ data2 = 'data2'
+ data3 = 'data3'
+
+ with requests_mock.mock() as m1:
+
+ r1 = m1.get(url1, text=data1)
+
+ resp1a = requests.get(url1)
+ self.assertRaises(exceptions.NoMockAddress, requests.get, url2)
+ self.assertRaises(exceptions.NoMockAddress, requests.get, url3)
+
+ self.assertEqual(data1, resp1a.text)
+
+ # call count = 3 because there are 3 calls above, url 1-3
+ self.assertEqual(3, m1.call_count)
+ self.assertEqual(1, r1.call_count)
+
+ with requests_mock.mock() as m2:
+
+ r2 = m2.get(url2, text=data2)
+
+ self.assertRaises(exceptions.NoMockAddress, requests.get, url1)
+ resp2a = requests.get(url2)
+ self.assertRaises(exceptions.NoMockAddress, requests.get, url3)
+
+ self.assertEqual(data2, resp2a.text)
+
+ with requests_mock.mock() as m3:
+
+ r3 = m3.get(url3, text=data3)
+
+ self.assertRaises(exceptions.NoMockAddress,
+ requests.get,
+ url1)
+ self.assertRaises(exceptions.NoMockAddress,
+ requests.get,
+ url2)
+ resp3 = requests.get(url3)
+
+ self.assertEqual(data3, resp3.text)
+
+ self.assertEqual(3, m3.call_count)
+ self.assertEqual(1, r3.call_count)
+
+ resp2b = requests.get(url2)
+ self.assertRaises(exceptions.NoMockAddress, requests.get, url1)
+ self.assertEqual(data2, resp2b.text)
+ self.assertRaises(exceptions.NoMockAddress, requests.get, url3)
+
+ self.assertEqual(3, m1.call_count)
+ self.assertEqual(1, r1.call_count)
+ self.assertEqual(6, m2.call_count)
+ self.assertEqual(2, r2.call_count)
+ self.assertEqual(3, m3.call_count)
+ self.assertEqual(1, r3.call_count)
+
+ resp1b = requests.get(url1)
+ self.assertEqual(data1, resp1b.text)
+ self.assertRaises(exceptions.NoMockAddress, requests.get, url2)
+ self.assertRaises(exceptions.NoMockAddress, requests.get, url3)
+
+ self.assertEqual(6, m1.call_count)
+ self.assertEqual(2, r1.call_count)
+
+ @requests_mock.mock()
+ def test_mocker_additional(self, m):
+ url = 'http://www.example.com'
+ good_text = 'success'
+
+ def additional_cb(req):
+ return 'hello' in req.text
+
+ m.post(url, additional_matcher=additional_cb, text=good_text)
+
+ self.assertEqual(good_text,
+ requests.post(url, data='hello world').text)
+ self.assertRaises(exceptions.NoMockAddress,
+ requests.post,
+ url,
+ data='goodbye world')
+
+ @requests_mock.mock()
+ def test_mocker_pickle(self, m):
+ url = 'http://www.example.com'
+ text = 'hello world'
+ m.get(url, text=text)
+
+ orig_resp = requests.get(url)
+ self.assertEqual(text, orig_resp.text)
+
+ d = pickle.dumps(orig_resp)
+ new_resp = pickle.loads(d)
+
+ self.assertEqual(text, new_resp.text)
+ self.assertIsInstance(orig_resp.request.matcher, adapter._Matcher)
+ self.assertIsNone(new_resp.request.matcher)
+
+ @requests_mock.mock()
+ def test_stream_zero_bytes(self, m):
+ content = b'blah'
+
+ m.get("http://test", content=content)
+ res = requests.get("http://test", stream=True)
+ zero_val = res.raw.read(0)
+ self.assertEqual(b'', zero_val)
+ self.assertFalse(res.raw.closed)
+
+ full_val = res.raw.read()
+ self.assertEqual(content, full_val)
+
+ def test_with_json_encoder_on_mocker(self):
+ test_val = 'hello world'
+
+ class MyJsonEncoder(json.JSONEncoder):
+ def encode(s, o):
+ return test_val
+
+ with requests_mock.Mocker(json_encoder=MyJsonEncoder) as m:
+ m.get("http://test", json={"a": "b"})
+ res = requests.get("http://test")
+ self.assertEqual(test_val, res.text)
+
+ @requests_mock.mock()
+ def test_with_json_encoder_on_endpoint(self, m):
+ test_val = 'hello world'
+
+ class MyJsonEncoder(json.JSONEncoder):
+ def encode(s, o):
+ return test_val
+
+ m.get("http://test", json={"a": "b"}, json_encoder=MyJsonEncoder)
+ res = requests.get("http://test")
+ self.assertEqual(test_val, res.text)
+
+ @requests_mock.mock()
+ def test_mismatch_content_length_streaming(self, m):
+ url = "https://test/package.tar.gz"
+
+ def f(request, context):
+ context.headers["Content-Length"] = "300810"
+ return None
+
+ m.head(
+ url=url,
+ status_code=200,
+ text=f,
+ )
+
+ requests.head(url)
diff --git a/contrib/python/requests-mock/py2/tests/test_request.py b/contrib/python/requests-mock/py2/tests/test_request.py
new file mode 100644
index 0000000000..69a71556e2
--- /dev/null
+++ b/contrib/python/requests-mock/py2/tests/test_request.py
@@ -0,0 +1,139 @@
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import uuid
+
+import requests
+import requests_mock
+from . import base
+
+
+class RequestTests(base.TestCase):
+
+ def setUp(self):
+ super(RequestTests, self).setUp()
+
+ self.mocker = requests_mock.Mocker()
+ self.addCleanup(self.mocker.stop)
+ self.mocker.start()
+
+ def do_request(self, **kwargs):
+ method = kwargs.pop('method', 'GET')
+ url = kwargs.pop('url', 'http://test.example.com/path')
+ status_code = kwargs.pop('status_code', 200)
+ data = uuid.uuid4().hex
+
+ m = self.mocker.register_uri(method,
+ url,
+ text=data,
+ status_code=status_code)
+
+ resp = requests.request(method, url, **kwargs)
+
+ self.assertEqual(status_code, resp.status_code)
+ self.assertEqual(data, resp.text)
+
+ self.assertTrue(m.called_once)
+ return m.last_request
+
+ def test_base_params(self):
+ req = self.do_request(method='GET', status_code=200)
+
+ self.assertIs(None, req.allow_redirects)
+ self.assertIs(None, req.timeout)
+ self.assertIs(True, req.verify)
+ self.assertIs(None, req.cert)
+ self.assertIs(False, req.stream)
+
+ # actually it's an OrderedDict, but equality works fine
+ # Skipping this check - it's problematic based on people's environments
+ # and in CI systems where there are proxies set up at the environment
+ # level. gh #127
+ # self.assertEqual({}, req.proxies)
+
+ def test_allow_redirects(self):
+ req = self.do_request(allow_redirects=False, status_code=300)
+ self.assertFalse(req.allow_redirects)
+
+ def test_timeout(self):
+ timeout = 300
+ req = self.do_request(timeout=timeout)
+ self.assertEqual(timeout, req.timeout)
+
+ def test_verify_false(self):
+ verify = False
+ req = self.do_request(verify=verify)
+ self.assertIs(verify, req.verify)
+
+ def test_verify_path(self):
+ verify = '/path/to/cacerts.pem'
+ req = self.do_request(verify=verify)
+ self.assertEqual(verify, req.verify)
+
+ def test_stream(self):
+ req = self.do_request()
+ self.assertIs(False, req.stream)
+ req = self.do_request(stream=False)
+ self.assertIs(False, req.stream)
+ req = self.do_request(stream=True)
+ self.assertIs(True, req.stream)
+
+ def test_certs(self):
+ cert = ('/path/to/cert.pem', 'path/to/key.pem')
+ req = self.do_request(cert=cert)
+ self.assertEqual(cert, req.cert)
+ self.assertTrue(req.verify)
+
+ def test_proxies(self):
+ proxies = {'http': 'foo.bar:3128',
+ 'http://host.name': 'foo.bar:4012'}
+
+ req = self.do_request(proxies=proxies)
+
+ self.assertEqual(proxies, req.proxies)
+ self.assertIsNot(proxies, req.proxies)
+
+ def test_hostname_port_http(self):
+ req = self.do_request(url='http://host.example.com:81/path')
+
+ self.assertEqual('host.example.com:81', req.netloc)
+ self.assertEqual('host.example.com', req.hostname)
+ self.assertEqual(81, req.port)
+
+ def test_hostname_port_https(self):
+ req = self.do_request(url='https://host.example.com:8080/path')
+
+ self.assertEqual('host.example.com:8080', req.netloc)
+ self.assertEqual('host.example.com', req.hostname)
+ self.assertEqual(8080, req.port)
+
+ def test_hostname_default_port_http(self):
+ req = self.do_request(url='http://host.example.com/path')
+
+ self.assertEqual('host.example.com', req.netloc)
+ self.assertEqual('host.example.com', req.hostname)
+ self.assertEqual(80, req.port)
+
+ def test_hostname_default_port_https(self):
+ req = self.do_request(url='https://host.example.com/path')
+
+ self.assertEqual('host.example.com', req.netloc)
+ self.assertEqual('host.example.com', req.hostname)
+ self.assertEqual(443, req.port)
+
+ def test_to_string(self):
+ req = self.do_request(url='https://host.example.com/path')
+ self.assertEqual('GET https://host.example.com/path', str(req))
+
+ def test_empty_query_string(self):
+ req = self.do_request(url='https://host.example.com/path?key')
+ self.assertEqual([''], req.qs['key'])
diff --git a/contrib/python/requests-mock/py2/tests/test_response.py b/contrib/python/requests-mock/py2/tests/test_response.py
new file mode 100644
index 0000000000..2dc11c8f7a
--- /dev/null
+++ b/contrib/python/requests-mock/py2/tests/test_response.py
@@ -0,0 +1,154 @@
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import pickle
+import six
+
+from requests_mock import exceptions
+from requests_mock import request
+from requests_mock import response
+from . import base
+
+
+class ResponseTests(base.TestCase):
+
+ def setUp(self):
+ super(ResponseTests, self).setUp()
+ self.method = 'GET'
+ self.url = 'http://test.url/path'
+ self.request = request._RequestObjectProxy._create(self.method,
+ self.url,
+ {})
+
+ def create_response(self, **kwargs):
+ return response.create_response(self.request, **kwargs)
+
+ def test_create_response_body_args(self):
+ self.assertRaises(RuntimeError,
+ self.create_response,
+ raw='abc',
+ body='abc')
+
+ self.assertRaises(RuntimeError,
+ self.create_response,
+ text='abc',
+ json={'a': 1})
+
+ def test_content_type(self):
+ self.assertRaises(TypeError, self.create_response, text=55)
+ self.assertRaises(TypeError, self.create_response, text={'a': 1})
+
+ # this only works on python 2 because bytes is a string
+ if six.PY3:
+ self.assertRaises(TypeError, self.create_response, text=six.b(''))
+
+ def test_text_type(self):
+ self.assertRaises(TypeError, self.create_response, content=six.u('t'))
+ self.assertRaises(TypeError, self.create_response, content={'a': 1})
+ self.assertRaises(TypeError, self.create_response, content=six.u(''))
+
+ def test_json_body(self):
+ data = {'a': 1}
+ resp = self.create_response(json=data)
+
+ self.assertEqual('{"a": 1}', resp.text)
+ self.assertIsInstance(resp.text, six.string_types)
+ self.assertIsInstance(resp.content, six.binary_type)
+ self.assertEqual(data, resp.json())
+
+ def test_body_body(self):
+ value = 'data'
+ body = six.BytesIO(six.b(value))
+ resp = self.create_response(body=body)
+
+ self.assertEqual(value, resp.text)
+ self.assertIsInstance(resp.text, six.string_types)
+ self.assertIsInstance(resp.content, six.binary_type)
+
+ def test_setting_connection(self):
+ conn = object()
+ resp = self.create_response(connection=conn)
+ self.assertIs(conn, resp.connection)
+
+ def test_send_from_no_connection(self):
+ resp = self.create_response()
+ self.assertRaises(exceptions.InvalidRequest,
+ resp.connection.send, self.request)
+
+ def test_cookies_from_header(self):
+ # domain must be same as request url to pass policy check
+ headers = {'Set-Cookie': 'fig=newton; Path=/test; domain=.test.url'}
+ resp = self.create_response(headers=headers)
+
+ self.assertEqual('newton', resp.cookies['fig'])
+ self.assertEqual(['/test'], resp.cookies.list_paths())
+ self.assertEqual(['.test.url'], resp.cookies.list_domains())
+
+ def test_cookies_from_dict(self):
+ # This is a syntax we get from requests. I'm not sure i like it.
+ resp = self.create_response(cookies={'fig': 'newton',
+ 'sugar': 'apple'})
+
+ self.assertEqual('newton', resp.cookies['fig'])
+ self.assertEqual('apple', resp.cookies['sugar'])
+
+ def test_cookies_with_jar(self):
+ jar = response.CookieJar()
+ jar.set('fig', 'newton', path='/foo', domain='.test.url')
+ jar.set('sugar', 'apple', path='/bar', domain='.test.url')
+ resp = self.create_response(cookies=jar)
+
+ self.assertEqual('newton', resp.cookies['fig'])
+ self.assertEqual('apple', resp.cookies['sugar'])
+ self.assertEqual({'/foo', '/bar'}, set(resp.cookies.list_paths()))
+ self.assertEqual(['.test.url'], resp.cookies.list_domains())
+
+ def test_response_pickle(self):
+ text = 'hello world'
+ jar = response.CookieJar()
+ jar.set('fig', 'newton', path='/foo', domain='.test.url')
+ orig_resp = self.create_response(cookies=jar, text=text)
+
+ d = pickle.dumps(orig_resp)
+ new_resp = pickle.loads(d)
+
+ self.assertEqual(text, new_resp.text)
+ self.assertEqual('newton', new_resp.cookies['fig'])
+ self.assertIsNone(new_resp.request.matcher)
+
+ def test_response_encoding(self):
+ headers = {"content-type": "text/html; charset=ISO-8859-1"}
+ resp = self.create_response(headers=headers,
+ text="<html><body></body></html")
+ self.assertEqual('ISO-8859-1', resp.encoding)
+
+ def test_default_reason(self):
+ resp = self.create_response()
+ self.assertEqual('OK', resp.reason)
+
+ def test_custom_reason(self):
+ reason = 'Live long and prosper'
+ resp = self.create_response(status_code=201, reason=reason)
+
+ self.assertEqual(201, resp.status_code)
+ self.assertEqual(reason, resp.reason)
+
+ def test_some_other_response_reasons(self):
+ reasons = {
+ 301: 'Moved Permanently',
+ 410: 'Gone',
+ 503: 'Service Unavailable',
+ }
+
+ for code, reason in six.iteritems(reasons):
+ self.assertEqual(reason,
+ self.create_response(status_code=code).reason)
diff --git a/contrib/python/requests-mock/py2/tests/ya.make b/contrib/python/requests-mock/py2/tests/ya.make
new file mode 100644
index 0000000000..574578a75c
--- /dev/null
+++ b/contrib/python/requests-mock/py2/tests/ya.make
@@ -0,0 +1,26 @@
+PY2TEST()
+
+SUBSCRIBER(g:python-contrib)
+
+PEERDIR(
+ contrib/python/mock
+ contrib/python/requests-futures
+ contrib/python/requests-mock
+)
+
+TEST_SRCS(
+ base.py
+ pytest/__init__.py
+ pytest/test_with_pytest.py
+ #test_adapter.py - need purl
+ test_custom_matchers.py
+ #test_fixture.py - need fixtures
+ test_matcher.py
+ test_mocker.py
+ test_request.py
+ test_response.py
+)
+
+NO_LINT()
+
+END()
diff --git a/contrib/python/requests-mock/py2/ya.make b/contrib/python/requests-mock/py2/ya.make
new file mode 100644
index 0000000000..d84a85f668
--- /dev/null
+++ b/contrib/python/requests-mock/py2/ya.make
@@ -0,0 +1,56 @@
+# Generated by devtools/yamaker (pypi).
+
+PY2_LIBRARY()
+
+SUBSCRIBER(g:python-contrib)
+
+VERSION(1.11.0)
+
+LICENSE(Apache-2.0)
+
+PEERDIR(
+ contrib/python/requests
+ contrib/python/six
+)
+
+NO_LINT()
+
+NO_CHECK_IMPORTS(
+ requests_mock.contrib._pytest_plugin
+ requests_mock.contrib.fixture
+)
+
+PY_SRCS(
+ TOP_LEVEL
+ requests_mock/__init__.py
+ requests_mock/__init__.pyi
+ requests_mock/adapter.py
+ requests_mock/adapter.pyi
+ requests_mock/compat.py
+ requests_mock/contrib/__init__.py
+ requests_mock/contrib/_pytest_plugin.py
+ requests_mock/contrib/_pytest_plugin.pyi
+ requests_mock/contrib/fixture.py
+ requests_mock/exceptions.py
+ requests_mock/exceptions.pyi
+ requests_mock/mocker.py
+ requests_mock/mocker.pyi
+ requests_mock/request.py
+ requests_mock/request.pyi
+ requests_mock/response.py
+ requests_mock/response.pyi
+)
+
+RESOURCE_FILES(
+ PREFIX contrib/python/requests-mock/py2/
+ .dist-info/METADATA
+ .dist-info/entry_points.txt
+ .dist-info/top_level.txt
+ requests_mock/py.typed
+)
+
+END()
+
+RECURSE_FOR_TESTS(
+ tests
+)
diff --git a/contrib/python/requests-mock/py3/patches/01-fix-tests.patch b/contrib/python/requests-mock/py3/patches/01-fix-tests.patch
new file mode 100644
index 0000000000..dc5164a523
--- /dev/null
+++ b/contrib/python/requests-mock/py3/patches/01-fix-tests.patch
@@ -0,0 +1,13 @@
+--- contrib/python/requests-mock/py3/tests/base.py (index)
++++ contrib/python/requests-mock/py3/tests/base.py (working tree)
+@@ -10,8 +10,8 @@
+ # License for the specific language governing permissions and limitations
+ # under the License.
+
+-import testtools
++import unittest
+
+
+-class TestCase(testtools.TestCase):
++class TestCase(unittest.TestCase):
+ pass
diff --git a/contrib/python/requests-mock/py3/patches/02-support-python-3.12.patch b/contrib/python/requests-mock/py3/patches/02-support-python-3.12.patch
new file mode 100644
index 0000000000..c876bc8243
--- /dev/null
+++ b/contrib/python/requests-mock/py3/patches/02-support-python-3.12.patch
@@ -0,0 +1,5 @@
+--- contrib/python/requests-mock/py3/tests/test_mocker.py (index)
++++ contrib/python/requests-mock/py3/tests/test_mocker.py (working tree)
+@@ -222 +222 @@ class MockerTests(base.TestCase):
+- self.assertEquals(
++ self.assertEqual(
diff --git a/contrib/python/requests-mock/py3/tests/__init__.py b/contrib/python/requests-mock/py3/tests/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/contrib/python/requests-mock/py3/tests/__init__.py
diff --git a/contrib/python/requests-mock/py3/tests/base.py b/contrib/python/requests-mock/py3/tests/base.py
new file mode 100644
index 0000000000..ecc872ecb7
--- /dev/null
+++ b/contrib/python/requests-mock/py3/tests/base.py
@@ -0,0 +1,17 @@
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import unittest
+
+
+class TestCase(unittest.TestCase):
+ pass
diff --git a/contrib/python/requests-mock/py3/tests/pytest/__init__.py b/contrib/python/requests-mock/py3/tests/pytest/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/contrib/python/requests-mock/py3/tests/pytest/__init__.py
diff --git a/contrib/python/requests-mock/py3/tests/pytest/pytest.ini b/contrib/python/requests-mock/py3/tests/pytest/pytest.ini
new file mode 100644
index 0000000000..58c87f21b7
--- /dev/null
+++ b/contrib/python/requests-mock/py3/tests/pytest/pytest.ini
@@ -0,0 +1,2 @@
+[pytest]
+requests_mock_case_sensitive=false
diff --git a/contrib/python/requests-mock/py3/tests/pytest/test_with_pytest.py b/contrib/python/requests-mock/py3/tests/pytest/test_with_pytest.py
new file mode 100644
index 0000000000..d74908bc38
--- /dev/null
+++ b/contrib/python/requests-mock/py3/tests/pytest/test_with_pytest.py
@@ -0,0 +1,119 @@
+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):
+ requests_mock.get('https://httpbin.org/get', text='data')
+ 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_base = "https://www.example.com/"
+
+ text_middle = 'middle' + url_middle
+ text_outer = 'outer' + url_outer
+ text_base = 'outer' + url_base
+
+ with requests_mock.Mocker() as outer_mock:
+ outer_mock.get(url_base, text=text_base)
+ outer_mock.get(url_outer, text=text_outer)
+
+ with requests_mock.Mocker(real_http=True) as middle_mock:
+ middle_mock.get(url_middle, text=text_middle)
+
+ with requests_mock.Mocker() as inner_mock:
+ inner_mock.post(url_inner,
+ status_code=HTTP_STATUS_FOUND,
+ headers={'location': url_base})
+ inner_mock.get(url_base, real_http=True)
+
+ assert text_base == 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 text_middle == requests.get(url_middle).text # nosec
+ assert text_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 text_outer == requests.get(url_outer).text # nosec
+
+
+def test_mixed_mocks():
+ url = 'mock://example.test/'
+ with requests_mock.Mocker() as global_mock:
+ global_mock.get(url, text='global')
+ session = requests.Session()
+ text = session.get(url).text
+ assert text == 'global' # nosec
+ with requests_mock.Mocker(session=session) as session_mock:
+ session_mock.get(url, real_http=True)
+ text = session.get(url).text
+ assert text == 'global' # nosec
+
+
+def test_threaded_sessions():
+ """
+ When using requests_futures.FuturesSession() with a ThreadPoolExecutor
+ there is a race condition where one threaded request removes the
+ monkeypatched get_adapter() method from the Session before another threaded
+ request is finished using it.
+ """
+ from requests_futures.sessions import FuturesSession
+
+ url1 = 'http://www.example.com/requests-mock-fake-url1'
+ url2 = 'http://www.example.com/requests-mock-fake-url2'
+
+ with requests_mock.Mocker() as m:
+ # respond with 204 so we know its us
+ m.get(url1, status_code=204)
+ m.get(url2, status_code=204)
+
+ # NOTE(phodge): just firing off two .get() requests right after each
+ # other was a pretty reliable way to reproduce the race condition on my
+ # intel Macbook Pro but YMMV. Guaranteeing the race condition to
+ # reappear might require replacing the Session.send() with a wrapper
+ # that delays kicking off the request for url1 until the request for
+ # url2 has restored the original session.get_adapter(), but replacing
+ # Session.send() could be difficult because the requests_mock.Mocker()
+ # context manager has *already* monkeypatched this method.
+ session = FuturesSession()
+ future1 = session.get(url1)
+ future2 = session.get(url2)
+
+ # verify both requests were handled by the mock dispatcher
+ assert future1.result().status_code == 204
+ assert future2.result().status_code == 204
+
+
+class TestClass(object):
+
+ def configure(self, requests_mock):
+ requests_mock.get('https://httpbin.org/get', text='data')
+
+ def test_one(self, requests_mock):
+ self.configure(requests_mock)
+ assert 'data' == requests.get('https://httpbin.org/get').text
diff --git a/contrib/python/requests-mock/py3/tests/test_adapter.py b/contrib/python/requests-mock/py3/tests/test_adapter.py
new file mode 100644
index 0000000000..4d6a0b4df2
--- /dev/null
+++ b/contrib/python/requests-mock/py3/tests/test_adapter.py
@@ -0,0 +1,724 @@
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import http.client
+import io
+import json
+import re
+import urllib.parse
+
+import purl
+import requests
+from urllib3 import HTTPResponse
+
+import requests_mock
+from . import base
+
+
+class MyExc(Exception):
+ pass
+
+
+class SessionAdapterTests(base.TestCase):
+
+ PREFIX = "mock"
+
+ def setUp(self):
+ super(SessionAdapterTests, self).setUp()
+
+ self.adapter = requests_mock.Adapter()
+ self.session = requests.Session()
+ self.session.mount(self.PREFIX, self.adapter)
+
+ self.url = '%s://example.com/test' % self.PREFIX
+ self.headers = {'header_a': 'A', 'header_b': 'B'}
+
+ def assertHeaders(self, resp):
+ for k, v in self.headers.items():
+ self.assertEqual(v, resp.headers[k])
+
+ def assertLastRequest(self, method='GET', body=None):
+ self.assertEqual(self.url, self.adapter.last_request.url)
+ self.assertEqual(method, self.adapter.last_request.method)
+ self.assertEqual(body, self.adapter.last_request.body)
+
+ url_parts = urllib.parse.urlparse(self.url)
+ qs = urllib.parse.parse_qs(url_parts.query)
+ self.assertEqual(url_parts.scheme, self.adapter.last_request.scheme)
+ self.assertEqual(url_parts.netloc, self.adapter.last_request.netloc)
+ self.assertEqual(url_parts.path, self.adapter.last_request.path)
+ self.assertEqual(url_parts.query, self.adapter.last_request.query)
+ self.assertEqual(url_parts.query, self.adapter.last_request.query)
+ self.assertEqual(qs, self.adapter.last_request.qs)
+
+ def test_content(self):
+ data = b'testdata'
+
+ self.adapter.register_uri('GET',
+ self.url,
+ content=data,
+ headers=self.headers)
+ resp = self.session.get(self.url)
+ self.assertEqual(data, resp.content)
+ self.assertHeaders(resp)
+ self.assertLastRequest()
+
+ def test_content_callback(self):
+ status_code = 401
+ data = b'testdata'
+
+ def _content_cb(request, context):
+ context.status_code = status_code
+ context.headers.update(self.headers)
+ return data
+
+ self.adapter.register_uri('GET',
+ self.url,
+ content=_content_cb)
+ resp = self.session.get(self.url)
+ self.assertEqual(status_code, resp.status_code)
+ self.assertEqual(data, resp.content)
+ self.assertHeaders(resp)
+ self.assertLastRequest()
+
+ def test_text(self):
+ data = u'testdata'
+
+ self.adapter.register_uri('GET',
+ self.url,
+ text=data,
+ headers=self.headers)
+ resp = self.session.get(self.url)
+ self.assertEqual(data.encode('utf-8'), resp.content)
+ self.assertEqual(data, resp.text)
+ self.assertEqual('utf-8', resp.encoding)
+ self.assertHeaders(resp)
+ self.assertLastRequest()
+
+ def test_text_callback(self):
+ status_code = 401
+ data = u'testdata'
+
+ def _text_cb(request, context):
+ context.status_code = status_code
+ context.headers.update(self.headers)
+ return data
+
+ self.adapter.register_uri('GET', self.url, text=_text_cb)
+ resp = self.session.get(self.url)
+ self.assertEqual(status_code, resp.status_code)
+ self.assertEqual(data, resp.text)
+ self.assertEqual(data.encode('utf-8'), resp.content)
+ self.assertEqual('utf-8', resp.encoding)
+ self.assertHeaders(resp)
+ self.assertLastRequest()
+
+ def test_raw_callback(self):
+ status_code = 401
+ data = 'testdata'
+
+ def _raw_cb(request, context):
+ return HTTPResponse(
+ status=status_code,
+ headers=self.headers,
+ body=io.BytesIO(data.encode('utf-8')),
+ preload_content=False,
+ reason=http.client.responses.get(status_code),
+ )
+
+ self.adapter.register_uri('GET', self.url, raw=_raw_cb)
+ resp = self.session.get(self.url)
+ self.assertEqual(status_code, resp.status_code)
+ self.assertEqual(data, resp.text)
+ self.assertEqual(data.encode('utf-8'), resp.content)
+ self.assertHeaders(resp)
+ self.assertLastRequest()
+
+ def test_json(self):
+ json_data = {'hello': 'world'}
+ self.adapter.register_uri('GET',
+ self.url,
+ json=json_data,
+ headers=self.headers)
+ resp = self.session.get(self.url)
+ self.assertEqual(b'{"hello": "world"}', resp.content)
+ self.assertEqual(u'{"hello": "world"}', resp.text)
+ self.assertEqual(json_data, resp.json())
+ self.assertEqual('utf-8', resp.encoding)
+ self.assertHeaders(resp)
+ self.assertLastRequest()
+
+ def test_json_callback(self):
+ status_code = 401
+ json_data = {'hello': 'world'}
+ data = u'{"hello": "world"}'
+
+ def _json_cb(request, context):
+ context.status_code = status_code
+ context.headers.update(self.headers)
+ return json_data
+
+ self.adapter.register_uri('GET', self.url, json=_json_cb)
+ resp = self.session.get(self.url)
+ self.assertEqual(status_code, resp.status_code)
+ self.assertEqual(json_data, resp.json())
+ self.assertEqual(data, resp.text)
+ self.assertEqual(data.encode('utf-8'), resp.content)
+ self.assertEqual('utf-8', resp.encoding)
+ self.assertHeaders(resp)
+ self.assertLastRequest()
+
+ def test_no_body(self):
+ self.adapter.register_uri('GET', self.url)
+ resp = self.session.get(self.url)
+ self.assertEqual(b'', resp.content)
+ self.assertEqual(200, resp.status_code)
+
+ def test_multiple_body_elements(self):
+ self.assertRaises(RuntimeError,
+ self.adapter.register_uri,
+ self.url,
+ 'GET',
+ content=b'b',
+ text=u'u')
+
+ def test_multiple_responses(self):
+ inp = [{'status_code': 400, 'text': 'abcd'},
+ {'status_code': 300, 'text': 'defg'},
+ {'status_code': 200, 'text': 'hijk'}]
+
+ self.adapter.register_uri('GET', self.url, inp)
+ out = [self.session.get(self.url) for i in range(0, len(inp))]
+
+ for i, o in zip(inp, out):
+ for k, v in i.items():
+ self.assertEqual(v, getattr(o, k))
+
+ last = self.session.get(self.url)
+ for k, v in inp[-1].items():
+ self.assertEqual(v, getattr(last, k))
+
+ def test_callback_optional_status(self):
+ headers = {'a': 'b'}
+
+ def _test_cb(request, context):
+ context.headers.update(headers)
+ return ''
+
+ self.adapter.register_uri('GET',
+ self.url,
+ text=_test_cb,
+ status_code=300)
+ resp = self.session.get(self.url)
+ self.assertEqual(300, resp.status_code)
+
+ for k, v in headers.items():
+ self.assertEqual(v, resp.headers[k])
+
+ def test_callback_optional_headers(self):
+ headers = {'a': 'b'}
+
+ def _test_cb(request, context):
+ context.status_code = 300
+ return ''
+
+ self.adapter.register_uri('GET',
+ self.url,
+ text=_test_cb,
+ headers=headers)
+
+ resp = self.session.get(self.url)
+ self.assertEqual(300, resp.status_code)
+
+ for k, v in headers.items():
+ self.assertEqual(v, resp.headers[k])
+
+ def test_latest_register_overrides(self):
+ self.adapter.register_uri('GET', self.url, text='abc')
+ self.adapter.register_uri('GET', self.url, text='def')
+
+ resp = self.session.get(self.url)
+ self.assertEqual('def', resp.text)
+
+ def test_no_last_request(self):
+ self.assertIsNone(self.adapter.last_request)
+ self.assertEqual(0, len(self.adapter.request_history))
+
+ def test_dont_pass_list_and_kwargs(self):
+ self.assertRaises(RuntimeError,
+ self.adapter.register_uri,
+ 'GET',
+ self.url,
+ [{'text': 'a'}],
+ headers={'a': 'b'})
+
+ def test_empty_string_return(self):
+ # '' evaluates as False, so make sure an empty string is not ignored.
+ self.adapter.register_uri('GET', self.url, text='')
+ resp = self.session.get(self.url)
+ self.assertEqual('', resp.text)
+
+ def test_dont_pass_multiple_bodies(self):
+ self.assertRaises(RuntimeError,
+ self.adapter.register_uri,
+ 'GET',
+ self.url,
+ json={'abc': 'def'},
+ text='ghi')
+
+ def test_dont_pass_unexpected_kwargs(self):
+ self.assertRaises(TypeError,
+ self.adapter.register_uri,
+ 'GET',
+ self.url,
+ unknown='argument')
+
+ def test_dont_pass_unicode_as_content(self):
+ self.assertRaises(TypeError,
+ self.adapter.register_uri,
+ 'GET',
+ self.url,
+ content=u'unicode')
+
+ def test_dont_pass_empty_string_as_content(self):
+ self.assertRaises(TypeError,
+ self.adapter.register_uri,
+ 'GET',
+ self.url,
+ content=u'')
+
+ def test_dont_pass_bytes_as_text(self):
+ self.assertRaises(TypeError,
+ self.adapter.register_uri,
+ 'GET',
+ self.url,
+ text=b'bytes')
+
+ def test_dont_pass_empty_string_as_text(self):
+ self.assertRaises(TypeError,
+ self.adapter.register_uri,
+ 'GET',
+ self.url,
+ text=b'')
+
+ def test_dont_pass_non_str_as_content(self):
+ self.assertRaises(TypeError,
+ self.adapter.register_uri,
+ 'GET',
+ self.url,
+ content=5)
+
+ def test_dont_pass_non_str_as_text(self):
+ self.assertRaises(TypeError,
+ self.adapter.register_uri,
+ 'GET',
+ self.url,
+ text=5)
+
+ def test_with_any_method(self):
+ self.adapter.register_uri(requests_mock.ANY, self.url, text='resp')
+
+ for m in ('GET', 'HEAD', 'POST', 'UNKNOWN'):
+ resp = self.session.request(m, self.url)
+ self.assertEqual('resp', resp.text)
+
+ def test_with_any_url(self):
+ self.adapter.register_uri('GET', requests_mock.ANY, text='resp')
+
+ for u in ('mock://a', 'mock://b', 'mock://c'):
+ resp = self.session.get(u)
+ self.assertEqual('resp', resp.text)
+
+ def test_with_regexp(self):
+ self.adapter.register_uri('GET', re.compile('tester.com'), text='resp')
+
+ for u in ('mock://www.tester.com/a', 'mock://abc.tester.com'):
+ resp = self.session.get(u)
+ self.assertEqual('resp', resp.text)
+
+ def test_with_purl(self):
+ self.adapter.register_uri('GET',
+ purl.URL('mock://www.tester.com/a'),
+ text='resp')
+
+ resp = self.session.get('mock://www.tester.com/a')
+ self.assertEqual('resp', resp.text)
+
+ def test_requests_in_history_on_no_match(self):
+ self.assertRaises(requests_mock.NoMockAddress,
+ self.session.get,
+ self.url)
+
+ self.assertEqual(self.url, self.adapter.last_request.url)
+
+ def test_requests_in_history_on_exception(self):
+
+ def _test_cb(request, ctx):
+ raise MyExc()
+
+ self.adapter.register_uri('GET', self.url, text=_test_cb)
+
+ self.assertRaises(MyExc,
+ self.session.get,
+ self.url)
+
+ self.assertEqual(self.url, self.adapter.last_request.url)
+
+ def test_not_called_and_called_count(self):
+ m = self.adapter.register_uri('GET', self.url, text='resp')
+ self.assertEqual(0, m.call_count)
+ self.assertFalse(m.called)
+ self.assertFalse(m.called_once)
+
+ self.assertEqual(0, self.adapter.call_count)
+ self.assertFalse(self.adapter.called)
+ self.assertFalse(m.called_once)
+
+ def test_called_and_called_count(self):
+ m = self.adapter.register_uri('GET', self.url, text='resp')
+
+ resps = [self.session.get(self.url) for i in range(0, 3)]
+
+ for r in resps:
+ self.assertEqual('resp', r.text)
+ self.assertEqual(200, r.status_code)
+
+ self.assertEqual(len(resps), m.call_count)
+ self.assertTrue(m.called)
+ self.assertFalse(m.called_once)
+
+ self.assertEqual(len(resps), self.adapter.call_count)
+ self.assertTrue(self.adapter.called)
+ self.assertFalse(m.called_once)
+
+ def test_reset_reverts_call_count(self):
+ # Create matchers and add calls to history
+ call_count = 3
+ matcher_count = 3
+ for i in range(matcher_count):
+ url = self.url + str(i)
+ self.adapter.register_uri('GET', url, text='resp')
+ for _ in range(call_count):
+ self.session.get(url)
+
+ # Verify call counts on adapter and matchers
+ self.assertEqual(self.adapter.call_count, matcher_count * call_count)
+ for matcher in self.adapter._matchers:
+ self.assertEqual(matcher.call_count, call_count)
+
+ self.adapter.reset()
+
+ # Verify call counts are 0 after reset
+ self.assertEqual(self.adapter.call_count, 0)
+ for matcher in self.adapter._matchers:
+ self.assertEqual(matcher.call_count, 0)
+
+ def test_adapter_picks_correct_adapter(self):
+ good = '%s://test3.url/' % self.PREFIX
+ self.adapter.register_uri('GET',
+ '%s://test1.url' % self.PREFIX,
+ text='bad')
+ self.adapter.register_uri('GET',
+ '%s://test2.url' % self.PREFIX,
+ text='bad')
+ self.adapter.register_uri('GET', good, text='good')
+ self.adapter.register_uri('GET',
+ '%s://test4.url' % self.PREFIX,
+ text='bad')
+
+ resp = self.session.get(good)
+
+ self.assertEqual('good', resp.text)
+
+ def test_adapter_is_connection(self):
+ url = '%s://test.url' % self.PREFIX
+ text = 'text'
+ self.adapter.register_uri('GET', url, text=text)
+ resp = self.session.get(url)
+
+ self.assertEqual(text, resp.text)
+ self.assertIs(self.adapter, resp.connection)
+
+ def test_send_to_connection(self):
+ url1 = '%s://test1.url/' % self.PREFIX
+ url2 = '%s://test2.url/' % self.PREFIX
+
+ text1 = 'text1'
+ text2 = 'text2'
+
+ self.adapter.register_uri('GET', url1, text=text1)
+ self.adapter.register_uri('GET', url2, text=text2)
+
+ req = requests.Request(method='GET', url=url2).prepare()
+
+ resp1 = self.session.get(url1)
+ self.assertEqual(text1, resp1.text)
+
+ resp2 = resp1.connection.send(req)
+ self.assertEqual(text2, resp2.text)
+
+ def test_request_json_with_str_data(self):
+ dict_req = {'hello': 'world'}
+ dict_resp = {'goodbye': 'world'}
+
+ m = self.adapter.register_uri('POST', self.url, json=dict_resp)
+
+ data = json.dumps(dict_req)
+ resp = self.session.post(self.url, data=data)
+
+ self.assertIs(data, m.last_request.body)
+ self.assertEqual(dict_resp, resp.json())
+ self.assertEqual(dict_req, m.last_request.json())
+
+ def test_request_json_with_bytes_data(self):
+ dict_req = {'hello': 'world'}
+ dict_resp = {'goodbye': 'world'}
+
+ m = self.adapter.register_uri('POST', self.url, json=dict_resp)
+
+ data = json.dumps(dict_req).encode('utf-8')
+ resp = self.session.post(self.url, data=data)
+
+ self.assertIs(data, m.last_request.body)
+ self.assertEqual(dict_resp, resp.json())
+ self.assertEqual(dict_req, m.last_request.json())
+
+ def test_request_json_with_cb(self):
+ dict_req = {'hello': 'world'}
+ dict_resp = {'goodbye': 'world'}
+ data = json.dumps(dict_req)
+
+ def _cb(req, context):
+ self.assertEqual(dict_req, req.json())
+ return dict_resp
+
+ m = self.adapter.register_uri('POST', self.url, json=_cb)
+ resp = self.session.post(self.url, data=data)
+
+ self.assertEqual(1, m.call_count)
+ self.assertTrue(m.called_once)
+ self.assertEqual(dict_resp, resp.json())
+
+ def test_raises_exception(self):
+ self.adapter.register_uri('GET', self.url, exc=MyExc)
+
+ self.assertRaises(MyExc,
+ self.session.get,
+ self.url)
+
+ self.assertTrue(self.adapter.called_once)
+ self.assertEqual(self.url, self.adapter.last_request.url)
+
+ def test_raises_exception_with_body_args_fails(self):
+ self.assertRaises(TypeError,
+ self.adapter.register_uri,
+ 'GET',
+ self.url,
+ exc=MyExc,
+ text='fail')
+
+ def test_sets_request_matcher_in_history(self):
+ url1 = '%s://test1.url/' % self.PREFIX
+ url2 = '%s://test2.url/' % self.PREFIX
+
+ text1 = 'text1'
+ text2 = 'text2'
+
+ m1 = self.adapter.register_uri('GET', url1, text=text1)
+ m2 = self.adapter.register_uri('GET', url2, text=text2)
+
+ resp1 = self.session.get(url1)
+ resp2 = self.session.get(url2)
+
+ self.assertEqual(text1, resp1.text)
+ self.assertEqual(text2, resp2.text)
+
+ self.assertEqual(2, self.adapter.call_count)
+ self.assertFalse(self.adapter.called_once)
+
+ self.assertEqual(url1, self.adapter.request_history[0].url)
+ self.assertEqual(url2, self.adapter.request_history[1].url)
+
+ self.assertIs(m1, self.adapter.request_history[0].matcher)
+ self.assertIs(m2, self.adapter.request_history[1].matcher)
+
+ def test_sets_request_matcher_on_exception(self):
+ m = self.adapter.register_uri('GET', self.url, exc=MyExc)
+
+ self.assertRaises(MyExc,
+ self.session.get,
+ self.url)
+
+ self.assertEqual(self.url, self.adapter.last_request.url)
+ self.assertIs(m, self.adapter.last_request.matcher)
+
+ def test_cookies_from_header(self):
+ headers = {'Set-Cookie': 'fig=newton; Path=/test; domain=.example.com'}
+ self.adapter.register_uri('GET',
+ self.url,
+ text='text',
+ headers=headers)
+
+ resp = self.session.get(self.url)
+
+ self.assertEqual('newton', resp.cookies['fig'])
+ self.assertEqual(['/test'], resp.cookies.list_paths())
+ self.assertEqual(['.example.com'], resp.cookies.list_domains())
+
+ def test_cookies_from_dict(self):
+ # This is a syntax we get from requests. I'm not sure i like it.
+ self.adapter.register_uri('GET',
+ self.url,
+ text='text',
+ cookies={'fig': 'newton', 'sugar': 'apple'})
+
+ resp = self.session.get(self.url)
+
+ self.assertEqual('newton', resp.cookies['fig'])
+ self.assertEqual('apple', resp.cookies['sugar'])
+
+ def test_cookies_with_jar(self):
+ jar = requests_mock.CookieJar()
+ jar.set('fig', 'newton', path='/foo', domain='.example.com')
+ jar.set('sugar', 'apple', path='/bar', domain='.example.com')
+
+ self.adapter.register_uri('GET', self.url, text='text', cookies=jar)
+ resp = self.session.get(self.url)
+
+ self.assertEqual('newton', resp.cookies['fig'])
+ self.assertEqual('apple', resp.cookies['sugar'])
+ self.assertEqual({'/foo', '/bar'}, set(resp.cookies.list_paths()))
+ self.assertEqual(['.example.com'], resp.cookies.list_domains())
+
+ def test_cookies_header_with_cb(self):
+
+ def _cb(request, context):
+ val = 'fig=newton; Path=/test; domain=.example.com'
+ context.headers['Set-Cookie'] = val
+ return 'text'
+
+ self.adapter.register_uri('GET', self.url, text=_cb)
+ resp = self.session.get(self.url)
+
+ self.assertEqual('newton', resp.cookies['fig'])
+ self.assertEqual(['/test'], resp.cookies.list_paths())
+ self.assertEqual(['.example.com'], resp.cookies.list_domains())
+
+ def test_cookies_from_dict_with_cb(self):
+ def _cb(request, context):
+ # converted into a jar by now
+ context.cookies.set('sugar', 'apple', path='/test')
+ return 'text'
+
+ self.adapter.register_uri('GET',
+ self.url,
+ text=_cb,
+ cookies={'fig': 'newton'})
+
+ resp = self.session.get(self.url)
+
+ self.assertEqual('newton', resp.cookies['fig'])
+ self.assertEqual('apple', resp.cookies['sugar'])
+ self.assertEqual(['/', '/test'], resp.cookies.list_paths())
+
+ def test_cookies_with_jar_cb(self):
+ def _cb(request, context):
+ context.cookies.set('sugar',
+ 'apple',
+ path='/bar',
+ domain='.example.com')
+ return 'text'
+
+ jar = requests_mock.CookieJar()
+ jar.set('fig', 'newton', path='/foo', domain='.example.com')
+
+ self.adapter.register_uri('GET', self.url, text=_cb, cookies=jar)
+ resp = self.session.get(self.url)
+
+ self.assertEqual('newton', resp.cookies['fig'])
+ self.assertEqual('apple', resp.cookies['sugar'])
+ self.assertEqual({'/foo', '/bar'}, set(resp.cookies.list_paths()))
+ self.assertEqual(['.example.com'], resp.cookies.list_domains())
+
+ def test_reading_closed_fp(self):
+ self.adapter.register_uri('GET', self.url, text='abc')
+ resp = self.session.get(self.url)
+
+ # raw will have been closed during the request reading
+ self.assertTrue(resp.raw.closed)
+
+ data = resp.raw.read()
+
+ self.assertIsInstance(data, bytes)
+ self.assertEqual(0, len(data))
+
+ def test_case_sensitive_headers(self):
+ data = 'testdata'
+ headers = {'aBcDe': 'FgHiJ'}
+
+ self.adapter.register_uri('GET', self.url, text=data)
+ resp = self.session.get(self.url, headers=headers)
+
+ self.assertEqual('GET', self.adapter.last_request.method)
+ self.assertEqual(200, resp.status_code)
+ self.assertEqual(data, resp.text)
+
+ for k, v in headers.items():
+ self.assertEqual(v, self.adapter.last_request.headers[k])
+
+ def test_case_sensitive_history(self):
+ self.adapter._case_sensitive = True
+
+ data = 'testdata'
+ netloc = 'examPlE.CoM'
+ path = '/TesTER'
+ query = 'aBC=deF'
+
+ mock_url = '%s://%s%s' % (self.PREFIX, netloc.lower(), path)
+ request_url = '%s://%s%s?%s' % (self.PREFIX, netloc, path, query)
+
+ # test that the netloc is ignored when actually making the request
+ self.adapter.register_uri('GET', mock_url, text=data)
+ resp = self.session.get(request_url)
+
+ self.assertEqual('GET', self.adapter.last_request.method)
+ self.assertEqual(200, resp.status_code)
+ self.assertEqual(data, resp.text)
+
+ # but even still the mixed case parameters come out in history
+ self.assertEqual(netloc, self.adapter.last_request.netloc)
+ self.assertEqual(path, self.adapter.last_request.path)
+ self.assertEqual(query, self.adapter.last_request.query)
+
+ def test_stream_none(self):
+ text = 'hello world'
+
+ self.adapter.register_uri('GET',
+ self.url,
+ text=text,
+ headers=self.headers)
+
+ resp = self.session.get(self.url, stream=True)
+ resps = [c for c in resp.iter_content(None, decode_unicode=True)]
+ self.assertEqual([text], resps)
+
+ def test_stream_size(self):
+ text = 'hello world'
+
+ self.adapter.register_uri('GET',
+ self.url,
+ text=text,
+ headers=self.headers)
+
+ resp = self.session.get(self.url, stream=True)
+ resps = [c for c in resp.iter_content(3, decode_unicode=True)]
+ self.assertEqual(['hel', 'lo ', 'wor', 'ld'], resps)
diff --git a/contrib/python/requests-mock/py3/tests/test_custom_matchers.py b/contrib/python/requests-mock/py3/tests/test_custom_matchers.py
new file mode 100644
index 0000000000..73e23822f5
--- /dev/null
+++ b/contrib/python/requests-mock/py3/tests/test_custom_matchers.py
@@ -0,0 +1,74 @@
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import requests
+
+import requests_mock
+from . import base
+
+
+class FailMatcher(object):
+
+ def __init___(self):
+ self.called = False
+
+ def __call__(self, request):
+ self.called = True
+ return None
+
+
+def match_all(request):
+ return requests_mock.create_response(request, content=b'data')
+
+
+class CustomMatchersTests(base.TestCase):
+
+ def assertMatchAll(self, resp):
+ self.assertEqual(200, resp.status_code)
+ self.assertEqual(resp.text, u'data')
+
+ @requests_mock.Mocker()
+ def test_custom_matcher(self, mocker):
+ mocker.add_matcher(match_all)
+
+ resp = requests.get('http://any/thing')
+ self.assertMatchAll(resp)
+
+ @requests_mock.Mocker()
+ def test_failing_matcher(self, mocker):
+ failer = FailMatcher()
+
+ mocker.add_matcher(match_all)
+ mocker.add_matcher(failer)
+
+ resp = requests.get('http://any/thing')
+
+ self.assertMatchAll(resp)
+ self.assertTrue(failer.called)
+
+ @requests_mock.Mocker()
+ def test_some_pass(self, mocker):
+
+ def matcher_a(request):
+ if 'a' in request.url:
+ return match_all(request)
+
+ return None
+
+ mocker.add_matcher(matcher_a)
+
+ resp = requests.get('http://any/thing')
+ self.assertMatchAll(resp)
+
+ self.assertRaises(requests_mock.NoMockAddress,
+ requests.get,
+ 'http://other/thing')
diff --git a/contrib/python/requests-mock/py3/tests/test_fixture.py b/contrib/python/requests-mock/py3/tests/test_fixture.py
new file mode 100644
index 0000000000..63cbb99141
--- /dev/null
+++ b/contrib/python/requests-mock/py3/tests/test_fixture.py
@@ -0,0 +1,39 @@
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import requests
+import requests_mock
+from requests_mock.contrib import fixture
+from . import base
+
+
+class MockingTests(base.TestCase):
+
+ def setUp(self):
+ super(MockingTests, self).setUp()
+ self.mocker = self.useFixture(fixture.Fixture())
+
+ def test_failure(self):
+ self.assertRaises(requests_mock.NoMockAddress,
+ requests.get,
+ 'http://www.google.com')
+
+ def test_basic(self):
+ test_url = 'http://www.google.com/'
+ self.mocker.register_uri('GET', test_url, text='response')
+
+ resp = requests.get(test_url)
+ self.assertEqual('response', resp.text)
+ self.assertEqual(test_url, self.mocker.last_request.url)
+
+ def test_fixture_has_normal_attr_error(self):
+ self.assertRaises(AttributeError, lambda: self.mocker.unknown)
diff --git a/contrib/python/requests-mock/py3/tests/test_matcher.py b/contrib/python/requests-mock/py3/tests/test_matcher.py
new file mode 100644
index 0000000000..a30e195966
--- /dev/null
+++ b/contrib/python/requests-mock/py3/tests/test_matcher.py
@@ -0,0 +1,324 @@
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import re
+
+from requests_mock import adapter
+from . import base
+from requests_mock.response import _MatcherResponse
+
+ANY = adapter.ANY
+
+
+class TestMatcher(base.TestCase):
+
+ def match(self,
+ target,
+ url,
+ matcher_method='GET',
+ request_method='GET',
+ complete_qs=False,
+ headers=None,
+ request_data=None,
+ request_headers={},
+ additional_matcher=None,
+ real_http=False,
+ case_sensitive=False):
+ matcher = adapter._Matcher(matcher_method,
+ target,
+ [],
+ complete_qs=complete_qs,
+ additional_matcher=additional_matcher,
+ request_headers=request_headers,
+ real_http=real_http,
+ case_sensitive=case_sensitive)
+ request = adapter._RequestObjectProxy._create(request_method,
+ url,
+ headers,
+ data=request_data)
+ return matcher._match(request)
+
+ def assertMatch(self,
+ target=ANY,
+ url='http://example.com/requests-mock',
+ matcher_method='GET',
+ request_method='GET',
+ **kwargs):
+ self.assertEqual(True,
+ self.match(target,
+ url,
+ matcher_method=matcher_method,
+ request_method=request_method,
+ **kwargs),
+ 'Matcher %s %s failed to match %s %s' %
+ (matcher_method, target, request_method, url))
+
+ def assertMatchBoth(self,
+ target=ANY,
+ url='http://example.com/requests-mock',
+ matcher_method='GET',
+ request_method='GET',
+ **kwargs):
+ self.assertMatch(target,
+ url,
+ matcher_method=matcher_method,
+ request_method=request_method,
+ **kwargs)
+ self.assertMatch(url,
+ target,
+ matcher_method=request_method,
+ request_method=matcher_method,
+ **kwargs)
+
+ def assertNoMatch(self,
+ target=ANY,
+ url='http://example.com/requests-mock',
+ matcher_method='GET',
+ request_method='GET',
+ **kwargs):
+ self.assertEqual(False,
+ self.match(target,
+ url,
+ matcher_method=matcher_method,
+ request_method=request_method,
+ **kwargs),
+ 'Matcher %s %s unexpectedly matched %s %s' %
+ (matcher_method, target, request_method, url))
+
+ def assertNoMatchBoth(self,
+ target=ANY,
+ url='http://example.com/requests-mock',
+ matcher_method='GET',
+ request_method='GET',
+ **kwargs):
+ self.assertNoMatch(target,
+ url,
+ matcher_method=matcher_method,
+ request_method=request_method,
+ **kwargs)
+ self.assertNoMatch(url,
+ target,
+ matcher_method=request_method,
+ request_method=matcher_method,
+ **kwargs)
+
+ def assertMatchMethodBoth(self, matcher_method, request_method, **kwargs):
+ url = 'http://www.test.com'
+
+ self.assertMatchBoth(url,
+ url,
+ request_method=request_method,
+ matcher_method=matcher_method,
+ **kwargs)
+
+ def assertNoMatchMethodBoth(self,
+ matcher_method,
+ request_method,
+ **kwargs):
+ url = 'http://www.test.com'
+
+ self.assertNoMatchBoth(url,
+ url,
+ request_method=request_method,
+ matcher_method=matcher_method,
+ **kwargs)
+
+ def test_url_matching(self):
+ self.assertMatchBoth('http://www.test.com',
+ 'http://www.test.com')
+ self.assertMatchBoth('http://www.test.com',
+ 'http://www.test.com/')
+ self.assertMatchBoth('http://www.test.com/abc',
+ 'http://www.test.com/abc')
+ self.assertMatchBoth('http://www.test.com:5000/abc',
+ 'http://www.test.com:5000/abc')
+ self.assertNoMatchBoth('https://www.test.com',
+ 'http://www.test.com')
+ self.assertNoMatchBoth('http://www.test.com/abc',
+ 'http://www.test.com')
+ self.assertNoMatchBoth('http://test.com',
+ 'http://www.test.com')
+ self.assertNoMatchBoth('http://test.com',
+ 'http://www.test.com')
+ self.assertNoMatchBoth('http://test.com/abc',
+ 'http://www.test.com/abc/')
+ self.assertNoMatchBoth('http://test.com/abc/',
+ 'http://www.test.com/abc')
+ self.assertNoMatchBoth('http://test.com:5000/abc/',
+ 'http://www.test.com/abc')
+ self.assertNoMatchBoth('http://test.com/abc/',
+ 'http://www.test.com:5000/abc')
+
+ def test_quotation(self):
+ self.assertMatchBoth('http://www.test.com/a string%url',
+ 'http://www.test.com/a string%url')
+ self.assertMatchBoth('http://www.test.com/ABC 123',
+ 'http://www.test.com/ABC%20123')
+ self.assertMatchBoth('http://www.test.com/user@example.com',
+ 'http://www.test.com/user@example.com')
+
+ def test_subset_match(self):
+ self.assertMatch('/path', 'http://www.test.com/path')
+ self.assertMatch('/path', 'http://www.test.com/path')
+ self.assertMatch('//www.test.com/path', 'http://www.test.com/path')
+ self.assertMatch('//www.test.com/path', 'https://www.test.com/path')
+
+ def test_query_string(self):
+ self.assertMatch('/path?a=1&b=2',
+ 'http://www.test.com/path?a=1&b=2')
+ self.assertMatch('/path?a=1',
+ 'http://www.test.com/path?a=1&b=2',
+ complete_qs=False)
+ self.assertNoMatch('/path?a=1',
+ 'http://www.test.com/path?a=1&b=2',
+ complete_qs=True)
+ self.assertNoMatch('/path?a=1&b=2',
+ 'http://www.test.com/path?a=1')
+
+ def test_query_empty_string(self):
+ self.assertMatch('/path?a',
+ 'http://www.test.com/path?a')
+ self.assertMatch('/path?bob&paul',
+ 'http://www.test.com/path?paul&bob')
+ self.assertNoMatch('/path?bob',
+ 'http://www.test.com/path?paul')
+ self.assertNoMatch('/path?pual&bob',
+ 'http://www.test.com/path?bob')
+
+ def test_method_match(self):
+ self.assertNoMatchMethodBoth('GET', 'POST')
+ self.assertMatchMethodBoth('GET', 'get')
+ self.assertMatchMethodBoth('GeT', 'geT')
+
+ def test_match_ANY_url(self):
+ self.assertMatch(ANY, 'http://anything')
+ self.assertMatch(ANY, 'http://somethingelse')
+ self.assertNoMatch(ANY, 'http://somethingelse', request_method='POST')
+
+ def test_match_ANY_method(self):
+ for m in ('GET', 'POST', 'HEAD', 'OPTION'):
+ self.assertMatch('http://www.test.com',
+ 'http://www.test.com',
+ matcher_method=ANY,
+ request_method=m)
+
+ self.assertNoMatch('http://www.test.com',
+ 'http://another',
+ matcher_method=ANY)
+
+ def test_match_with_regex(self):
+ r1 = re.compile('test.com/a')
+ r2 = re.compile('/b/c')
+
+ self.assertMatch(r1, 'http://mock.test.com/a/b')
+ self.assertMatch(r1, 'http://test.com/a/')
+ self.assertMatch(r1, 'mock://test.com/a/b')
+ self.assertNoMatch(r1, 'mock://test.com/')
+
+ self.assertMatch(r2, 'http://anything/a/b/c/d')
+ self.assertMatch(r2, 'mock://anything/a/b/c/d')
+
+ def test_match_with_headers(self):
+ self.assertMatch('/path',
+ 'http://www.test.com/path',
+ headers={'A': 'abc', 'b': 'def'},
+ request_headers={'a': 'abc'})
+
+ self.assertMatch('/path',
+ 'http://www.test.com/path',
+ headers={'A': 'abc', 'b': 'def'})
+
+ self.assertNoMatch('/path',
+ 'http://www.test.com/path',
+ headers={'A': 'abc', 'b': 'def'},
+ request_headers={'b': 'abc'})
+
+ self.assertNoMatch('/path',
+ 'http://www.test.com/path',
+ headers={'A': 'abc', 'b': 'def'},
+ request_headers={'c': 'ghi'})
+
+ # headers should be key insensitive and value sensitive, we have no
+ # choice here because they go into an insensitive dict.
+ self.assertMatch('/path',
+ 'http://www.test.com/path',
+ headers={'aBc': 'abc', 'DEF': 'def'},
+ request_headers={'abC': 'abc'})
+
+ self.assertNoMatch('/path',
+ 'http://www.test.com/path',
+ headers={'abc': 'aBC', 'DEF': 'def'},
+ request_headers={'abc': 'Abc'})
+
+ def test_case_sensitive_ignored_for_netloc_and_protocol(self):
+ for case_sensitive in (True, False):
+ self.assertMatch('http://AbC.CoM',
+ 'http://aBc.CoM',
+ case_sensitive=case_sensitive)
+
+ self.assertMatch('htTP://abc.com',
+ 'hTTp://abc.com',
+ case_sensitive=case_sensitive)
+
+ self.assertMatch('htTP://aBC.cOm',
+ 'hTTp://AbC.Com',
+ case_sensitive=case_sensitive)
+
+ def assertSensitiveMatch(self, target, url, **kwargs):
+ self.assertMatch(target, url, case_sensitive=False, **kwargs)
+ self.assertNoMatch(target, url, case_sensitive=True, **kwargs)
+
+ def test_case_sensitive_paths(self):
+ self.assertSensitiveMatch('http://abc.com/pAtH', 'http://abc.com/path')
+ self.assertSensitiveMatch('/pAtH', 'http://abc.com/path')
+
+ def test_case_sensitive_query(self):
+ self.assertSensitiveMatch('http://abc.com/path?abCD=efGH',
+ 'http://abc.com/path?abCd=eFGH')
+
+ self.assertSensitiveMatch('http://abc.com/path?abcd=efGH',
+ 'http://abc.com/path?abcd=eFGH')
+
+ def test_additional_matcher(self):
+
+ def test_match_body(request):
+ return 'hello' in request.text
+
+ self.assertMatch(request_method='POST',
+ matcher_method='POST',
+ request_data='hello world',
+ additional_matcher=test_match_body)
+
+ self.assertNoMatch(request_method='POST',
+ matcher_method='POST',
+ request_data='goodbye world',
+ additional_matcher=test_match_body)
+
+ def test_reset_reverts_count(self):
+ url = 'mock://test/site/'
+ matcher = adapter._Matcher('GET',
+ url,
+ [_MatcherResponse()],
+ complete_qs=False,
+ additional_matcher=None,
+ request_headers={},
+ real_http=False,
+ case_sensitive=False)
+ request = adapter._RequestObjectProxy._create('GET', url)
+
+ call_count = 3
+ for _ in range(call_count):
+ matcher(request)
+
+ self.assertEqual(matcher.call_count, call_count)
+ matcher.reset()
+ self.assertEqual(matcher.call_count, 0)
diff --git a/contrib/python/requests-mock/py3/tests/test_mocker.py b/contrib/python/requests-mock/py3/tests/test_mocker.py
new file mode 100644
index 0000000000..c2e88813ed
--- /dev/null
+++ b/contrib/python/requests-mock/py3/tests/test_mocker.py
@@ -0,0 +1,646 @@
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import json
+import pickle
+
+try:
+ from unittest import mock
+except ImportError:
+ import mock
+import requests
+
+import requests_mock
+from requests_mock import adapter
+from requests_mock import exceptions
+from requests_mock import response
+from . import base
+
+original_send = requests.Session.send
+
+
+class MockerTests(base.TestCase):
+
+ def assertMockStarted(self):
+ self.assertNotEqual(original_send, requests.Session.send)
+
+ def assertMockStopped(self):
+ self.assertEqual(original_send, requests.Session.send)
+
+ def _do_test(self, m):
+ self.assertMockStarted()
+ matcher = m.register_uri('GET', 'http://www.test.com', text='resp')
+ resp = requests.get('http://www.test.com')
+ self.assertEqual('resp', resp.text)
+ return matcher
+
+ def test_multiple_starts(self):
+ mocker = requests_mock.Mocker()
+ self.assertMockStopped()
+ mocker.start()
+ self.assertMockStarted()
+ self.assertRaises(RuntimeError, mocker.start)
+ mocker.stop()
+ self.assertMockStopped()
+ mocker.stop()
+
+ def test_with_session(self):
+ url = 'http://test.url/path'
+ url_inner = 'http://test.url/inner'
+ url_outer = 'http://test.url/outer'
+ with requests_mock.Mocker() as global_mock:
+ global_mock.get(url_outer, text='global')
+
+ session_a = requests.Session()
+ session_b = requests.Session()
+
+ session_a_original_send = session_a.send
+ session_b_original_send = session_b.send
+ self.assertNotEqual(session_a_original_send,
+ session_b_original_send)
+
+ mocker_a = requests_mock.Mocker(session=session_a)
+ mocker_b = requests_mock.Mocker(session=session_b)
+
+ mocker_a.start()
+ mocker_b.start()
+
+ mocker_a.register_uri('GET', url, text='resp_a')
+ mocker_a.register_uri('GET', url_outer, real_http=True)
+ mocker_b.register_uri('GET', url, text='resp_b')
+
+ with requests_mock.Mocker(session=session_b) as mocker_b_inner:
+ mocker_b_inner.register_uri('GET', url, real_http=True)
+ mocker_b_inner.register_uri('GET',
+ url_inner,
+ text='resp_b_inner')
+
+ self.assertEqual('resp_a', session_a.get(url).text)
+ self.assertEqual('resp_b', session_b.get(url).text)
+ self.assertRaises(exceptions.NoMockAddress,
+ session_a.get,
+ url_inner)
+ self.assertEqual('resp_b_inner', session_b.get(url_inner).text)
+
+ self.assertEqual('resp_a', session_a.get(url).text)
+ self.assertEqual('resp_b', session_b.get(url).text)
+ self.assertRaises(exceptions.NoMockAddress,
+ session_a.get,
+ url_inner)
+ self.assertRaises(exceptions.NoMockAddress,
+ session_b.get,
+ url_inner)
+ self.assertEqual('global', session_a.get(url_outer).text)
+ self.assertRaises(exceptions.NoMockAddress,
+ session_b.get,
+ url_outer)
+
+ self.assertNotEqual(session_a.send, session_a_original_send)
+ self.assertNotEqual(session_b.send, session_b_original_send)
+ self.assertNotEqual(session_a.send, session_b.send)
+
+ mocker_a.stop()
+ mocker_b.stop()
+
+ self.assertEqual(session_a.send, session_a_original_send)
+ self.assertEqual(session_b.send, session_b_original_send)
+
+ self.assertEqual(requests.Session.send, original_send)
+
+ def test_with_context_manager(self):
+ self.assertMockStopped()
+ with requests_mock.Mocker() as m:
+ self._do_test(m)
+ self.assertMockStopped()
+
+ @mock.patch('requests.adapters.HTTPAdapter.send')
+ @requests_mock.mock(real_http=True)
+ def test_real_http(self, real_send, mocker):
+ url = 'http://www.google.com/'
+ test_text = 'real http data'
+ test_bytes = test_text.encode('utf-8')
+
+ # using create_response is a bit bootstrappy here but so long as it's
+ # coming from HTTPAdapter.send it's ok
+ req = requests.Request(method='GET', url=url)
+ real_send.return_value = response.create_response(req.prepare(),
+ status_code=200,
+ content=test_bytes)
+ resp = requests.get(url)
+
+ self.assertEqual(1, real_send.call_count)
+ self.assertEqual(url, real_send.call_args[0][0].url)
+
+ self.assertEqual(test_text, resp.text)
+ self.assertEqual(test_bytes, resp.content)
+
+ @mock.patch('requests.adapters.HTTPAdapter.send')
+ def test_real_http_changes(self, real_send):
+ url = 'http://www.google.com/'
+ test_text = 'real http data'
+ test_bytes = test_text.encode('utf-8')
+
+ req = requests.Request(method='GET', url=url)
+ real_send.return_value = response.create_response(req.prepare(),
+ status_code=200,
+ content=test_bytes)
+
+ with requests_mock.Mocker() as m:
+ # real_http defaults to false so should raise NoMockAddress
+
+ self.assertRaises(exceptions.NoMockAddress,
+ requests.get,
+ url)
+
+ self.assertEqual(1, m.call_count)
+ self.assertEqual(0, real_send.call_count)
+
+ # change the value of real_http mid test
+ m.real_http = True
+
+ # fetch the url again and it should go through to the real url that
+ # we've mocked out at a lower level.
+ resp = requests.get(url)
+
+ self.assertEqual(1, real_send.call_count)
+ self.assertEqual(url, real_send.call_args[0][0].url)
+
+ self.assertEqual(test_text, resp.text)
+ self.assertEqual(test_bytes, resp.content)
+
+ @mock.patch('requests.adapters.HTTPAdapter.send')
+ def test_real_http_and_session(self, real_send):
+ url = 'http://www.google.com/'
+ test_text = 'real http data'
+ test_bytes = test_text.encode('utf-8')
+
+ req = requests.Request(method='GET', url=url)
+ real_send.return_value = response.create_response(req.prepare(),
+ status_code=200,
+ content=test_bytes)
+
+ session = requests.Session()
+ with requests_mock.Mocker(session=session, real_http=True):
+ resp = session.get(url)
+
+ self.assertEqual(test_text, resp.text)
+ self.assertEqual(test_bytes, resp.content)
+
+ @requests_mock.mock()
+ def test_with_test_decorator(self, m):
+ self._do_test(m)
+
+ @requests_mock.mock(kw='mock')
+ def test_with_mocker_kwargs(self, **kwargs):
+ self._do_test(kwargs['mock'])
+
+ def test_with_decorator(self):
+
+ @requests_mock.mock()
+ def inner(m):
+ self.assertMockStarted()
+ self._do_test(m)
+
+ self.assertMockStopped()
+ inner()
+ self.assertMockStopped()
+
+ def test_with_decorator_called_multiple_times(self):
+
+ @requests_mock.Mocker()
+ def inner(arg1, m):
+ self._do_test(m)
+ self.assertEqual(
+ len(m.request_history), 1,
+ "Failed to provide clean mock on subsequent calls"
+ )
+
+ inner('a')
+ # if we call the same decorated method again should get
+ # a new request mock
+ inner('b')
+
+ def test_with_class_decorator(self):
+ outer = self
+
+ @requests_mock.mock()
+ class Decorated(object):
+
+ def test_will_be_decorated(self, m):
+ outer.assertMockStarted()
+ outer._do_test(m)
+
+ def will_not_be_decorated(self):
+ outer.assertMockStopped()
+
+ decorated_class = Decorated()
+
+ self.assertMockStopped()
+ decorated_class.test_will_be_decorated()
+ self.assertMockStopped()
+ decorated_class.will_not_be_decorated()
+ self.assertMockStopped()
+
+ def test_with_class_decorator_and_custom_kw(self):
+ outer = self
+
+ @requests_mock.mock(kw='custom_m')
+ class Decorated(object):
+
+ def test_will_be_decorated(self, **kwargs):
+ outer.assertMockStarted()
+ outer._do_test(kwargs['custom_m'])
+
+ def will_not_be_decorated(self):
+ outer.assertMockStopped()
+
+ decorated_class = Decorated()
+
+ self.assertMockStopped()
+ decorated_class.test_will_be_decorated()
+ self.assertMockStopped()
+ decorated_class.will_not_be_decorated()
+ self.assertMockStopped()
+
+ @mock.patch.object(requests_mock.mock, 'TEST_PREFIX', 'foo')
+ def test_with_class_decorator_and_custom_test_prefix(self):
+ outer = self
+
+ @requests_mock.mock()
+ class Decorated(object):
+
+ def foo_will_be_decorated(self, m):
+ outer.assertMockStarted()
+ outer._do_test(m)
+
+ def will_not_be_decorated(self):
+ outer.assertMockStopped()
+
+ decorated_class = Decorated()
+
+ self.assertMockStopped()
+ decorated_class.foo_will_be_decorated()
+ self.assertMockStopped()
+ decorated_class.will_not_be_decorated()
+ self.assertMockStopped()
+
+ @requests_mock.mock()
+ def test_query_string(self, m):
+ url = 'http://test.url/path'
+ qs = 'a=1&b=2'
+ m.register_uri('GET', url, text='resp')
+ resp = requests.get("%s?%s" % (url, qs))
+
+ self.assertEqual('resp', resp.text)
+
+ self.assertEqual(qs, m.last_request.query)
+ self.assertEqual(['1'], m.last_request.qs['a'])
+ self.assertEqual(['2'], m.last_request.qs['b'])
+
+ @requests_mock.mock()
+ def test_mock_matcher_attributes(self, m):
+ matcher = self._do_test(m)
+
+ self.assertEqual(1, matcher.call_count)
+ self.assertEqual(1, m.call_count)
+
+ self.assertTrue(matcher.called)
+ self.assertTrue(matcher.called_once)
+ self.assertTrue(m.called)
+ self.assertTrue(m.called_once)
+
+ self.assertEqual(m.request_history, matcher.request_history)
+ self.assertIs(m.last_request, matcher.last_request)
+
+ def test_copy(self):
+ mocker = requests_mock.mock(kw='foo', real_http=True)
+ copy_of_mocker = mocker.copy()
+ self.assertIsNot(copy_of_mocker, mocker)
+ self.assertEqual(copy_of_mocker._kw, mocker._kw)
+ self.assertEqual(copy_of_mocker.real_http, mocker.real_http)
+
+ @requests_mock.mock()
+ def test_reset_mock_reverts_call_count(self, request_mock):
+ url = 'http://test.url/path'
+ request_mock.get(url, text='resp')
+ requests.get(url)
+
+ self.assertEqual(request_mock.call_count, 1)
+
+ # reset count and verify it is 0
+ request_mock.reset_mock()
+ self.assertEqual(request_mock.call_count, 0)
+
+
+class MockerHttpMethodsTests(base.TestCase):
+
+ URL = 'http://test.com/path'
+ TEXT = 'resp'
+
+ def assertResponse(self, resp):
+ self.assertEqual(self.TEXT, resp.text)
+
+ @requests_mock.Mocker()
+ def test_mocker_request(self, m):
+ method = 'XXX'
+ mock_obj = m.request(method, self.URL, text=self.TEXT)
+ resp = requests.request(method, self.URL)
+ self.assertResponse(resp)
+ self.assertTrue(mock_obj.called)
+ self.assertTrue(mock_obj.called_once)
+ self.assertTrue(m.called)
+ self.assertTrue(m.called_once)
+
+ @requests_mock.Mocker()
+ def test_mocker_get(self, m):
+ mock_obj = m.get(self.URL, text=self.TEXT)
+ self.assertResponse(requests.get(self.URL))
+ self.assertTrue(mock_obj.called)
+ self.assertTrue(mock_obj.called_once)
+ self.assertTrue(m.called)
+ self.assertTrue(m.called_once)
+
+ @requests_mock.Mocker()
+ def test_mocker_options(self, m):
+ mock_obj = m.options(self.URL, text=self.TEXT)
+ self.assertResponse(requests.options(self.URL))
+ self.assertTrue(mock_obj.called)
+ self.assertTrue(mock_obj.called_once)
+ self.assertTrue(m.called)
+ self.assertTrue(m.called_once)
+
+ @requests_mock.Mocker()
+ def test_mocker_head(self, m):
+ mock_obj = m.head(self.URL, text=self.TEXT)
+ self.assertResponse(requests.head(self.URL))
+ self.assertTrue(mock_obj.called)
+ self.assertTrue(mock_obj.called_once)
+ self.assertTrue(m.called)
+ self.assertTrue(m.called_once)
+
+ @requests_mock.Mocker()
+ def test_mocker_post(self, m):
+ mock_obj = m.post(self.URL, text=self.TEXT)
+ self.assertResponse(requests.post(self.URL))
+ self.assertTrue(mock_obj.called)
+ self.assertTrue(mock_obj.called_once)
+ self.assertTrue(m.called)
+ self.assertTrue(m.called_once)
+
+ @requests_mock.Mocker()
+ def test_mocker_put(self, m):
+ mock_obj = m.put(self.URL, text=self.TEXT)
+ self.assertResponse(requests.put(self.URL))
+ self.assertTrue(mock_obj.called)
+ self.assertTrue(mock_obj.called_once)
+ self.assertTrue(m.called)
+ self.assertTrue(m.called_once)
+
+ @requests_mock.Mocker()
+ def test_mocker_patch(self, m):
+ mock_obj = m.patch(self.URL, text=self.TEXT)
+ self.assertResponse(requests.patch(self.URL))
+ self.assertTrue(mock_obj.called)
+ self.assertTrue(mock_obj.called_once)
+ self.assertTrue(m.called)
+ self.assertTrue(m.called_once)
+
+ @requests_mock.Mocker()
+ def test_mocker_delete(self, m):
+ mock_obj = m.delete(self.URL, text=self.TEXT)
+ self.assertResponse(requests.delete(self.URL))
+ self.assertTrue(mock_obj.called)
+ self.assertTrue(mock_obj.called_once)
+ self.assertTrue(m.called)
+ self.assertTrue(m.called_once)
+
+ @requests_mock.Mocker()
+ def test_mocker_real_http_and_responses(self, m):
+ self.assertRaises(RuntimeError,
+ m.get,
+ self.URL,
+ text='abcd',
+ real_http=True)
+
+ @requests_mock.Mocker()
+ def test_mocker_real_http(self, m):
+ data = 'testdata'
+
+ uri1 = 'fake://example.com/foo'
+ uri2 = 'fake://example.com/bar'
+ uri3 = 'fake://example.com/baz'
+
+ m.get(uri1, text=data)
+ m.get(uri2, real_http=True)
+
+ self.assertEqual(data, requests.get(uri1).text)
+
+ # This should fail because requests can't get an adapter for mock://
+ # but it shows that it has tried and would have made a request.
+ self.assertRaises(requests.exceptions.InvalidSchema,
+ requests.get,
+ uri2)
+
+ # This fails because real_http is not set on the mocker
+ self.assertRaises(exceptions.NoMockAddress,
+ requests.get,
+ uri3)
+
+ # do it again to make sure the mock is still in place
+ self.assertEqual(data, requests.get(uri1).text)
+
+ @requests_mock.Mocker(case_sensitive=True)
+ def test_case_sensitive_query(self, m):
+ data = 'testdata'
+ query = {'aBcDe': 'FgHiJ'}
+
+ m.get(self.URL, text=data)
+ resp = requests.get(self.URL, params=query)
+
+ self.assertEqual('GET', m.last_request.method)
+ self.assertEqual(200, resp.status_code)
+ self.assertEqual(data, resp.text)
+
+ for k, v in query.items():
+ self.assertEqual([v], m.last_request.qs[k])
+
+ @mock.patch.object(requests_mock.Mocker, 'case_sensitive', True)
+ def test_global_case_sensitive(self):
+ with requests_mock.mock() as m:
+ data = 'testdata'
+ query = {'aBcDe': 'FgHiJ'}
+
+ m.get(self.URL, text=data)
+ resp = requests.get(self.URL, params=query)
+
+ self.assertEqual('GET', m.last_request.method)
+ self.assertEqual(200, resp.status_code)
+ self.assertEqual(data, resp.text)
+
+ for k, v in query.items():
+ self.assertEqual([v], m.last_request.qs[k])
+
+ def test_nested_mocking(self):
+ url1 = 'http://url1.com/path1'
+ url2 = 'http://url2.com/path2'
+ url3 = 'http://url3.com/path3'
+
+ data1 = 'data1'
+ data2 = 'data2'
+ data3 = 'data3'
+
+ with requests_mock.mock() as m1:
+
+ r1 = m1.get(url1, text=data1)
+
+ resp1a = requests.get(url1)
+ self.assertRaises(exceptions.NoMockAddress, requests.get, url2)
+ self.assertRaises(exceptions.NoMockAddress, requests.get, url3)
+
+ self.assertEqual(data1, resp1a.text)
+
+ # call count = 3 because there are 3 calls above, url 1-3
+ self.assertEqual(3, m1.call_count)
+ self.assertEqual(1, r1.call_count)
+
+ with requests_mock.mock() as m2:
+
+ r2 = m2.get(url2, text=data2)
+
+ self.assertRaises(exceptions.NoMockAddress, requests.get, url1)
+ resp2a = requests.get(url2)
+ self.assertRaises(exceptions.NoMockAddress, requests.get, url3)
+
+ self.assertEqual(data2, resp2a.text)
+
+ with requests_mock.mock() as m3:
+
+ r3 = m3.get(url3, text=data3)
+
+ self.assertRaises(exceptions.NoMockAddress,
+ requests.get,
+ url1)
+ self.assertRaises(exceptions.NoMockAddress,
+ requests.get,
+ url2)
+ resp3 = requests.get(url3)
+
+ self.assertEqual(data3, resp3.text)
+
+ self.assertEqual(3, m3.call_count)
+ self.assertEqual(1, r3.call_count)
+
+ resp2b = requests.get(url2)
+ self.assertRaises(exceptions.NoMockAddress, requests.get, url1)
+ self.assertEqual(data2, resp2b.text)
+ self.assertRaises(exceptions.NoMockAddress, requests.get, url3)
+
+ self.assertEqual(3, m1.call_count)
+ self.assertEqual(1, r1.call_count)
+ self.assertEqual(6, m2.call_count)
+ self.assertEqual(2, r2.call_count)
+ self.assertEqual(3, m3.call_count)
+ self.assertEqual(1, r3.call_count)
+
+ resp1b = requests.get(url1)
+ self.assertEqual(data1, resp1b.text)
+ self.assertRaises(exceptions.NoMockAddress, requests.get, url2)
+ self.assertRaises(exceptions.NoMockAddress, requests.get, url3)
+
+ self.assertEqual(6, m1.call_count)
+ self.assertEqual(2, r1.call_count)
+
+ @requests_mock.mock()
+ def test_mocker_additional(self, m):
+ url = 'http://www.example.com'
+ good_text = 'success'
+
+ def additional_cb(req):
+ return 'hello' in req.text
+
+ m.post(url, additional_matcher=additional_cb, text=good_text)
+
+ self.assertEqual(good_text,
+ requests.post(url, data='hello world').text)
+ self.assertRaises(exceptions.NoMockAddress,
+ requests.post,
+ url,
+ data='goodbye world')
+
+ @requests_mock.mock()
+ def test_mocker_pickle(self, m):
+ url = 'http://www.example.com'
+ text = 'hello world'
+ m.get(url, text=text)
+
+ orig_resp = requests.get(url)
+ self.assertEqual(text, orig_resp.text)
+
+ d = pickle.dumps(orig_resp)
+ new_resp = pickle.loads(d)
+
+ self.assertEqual(text, new_resp.text)
+ self.assertIsInstance(orig_resp.request.matcher, adapter._Matcher)
+ self.assertIsNone(new_resp.request.matcher)
+
+ @requests_mock.mock()
+ def test_stream_zero_bytes(self, m):
+ content = b'blah'
+
+ m.get("http://test", content=content)
+ res = requests.get("http://test", stream=True)
+ zero_val = res.raw.read(0)
+ self.assertEqual(b'', zero_val)
+ self.assertFalse(res.raw.closed)
+
+ full_val = res.raw.read()
+ self.assertEqual(content, full_val)
+
+ def test_with_json_encoder_on_mocker(self):
+ test_val = 'hello world'
+
+ class MyJsonEncoder(json.JSONEncoder):
+ def encode(s, o):
+ return test_val
+
+ with requests_mock.Mocker(json_encoder=MyJsonEncoder) as m:
+ m.get("http://test", json={"a": "b"})
+ res = requests.get("http://test")
+ self.assertEqual(test_val, res.text)
+
+ @requests_mock.mock()
+ def test_with_json_encoder_on_endpoint(self, m):
+ test_val = 'hello world'
+
+ class MyJsonEncoder(json.JSONEncoder):
+ def encode(s, o):
+ return test_val
+
+ m.get("http://test", json={"a": "b"}, json_encoder=MyJsonEncoder)
+ res = requests.get("http://test")
+ self.assertEqual(test_val, res.text)
+
+ @requests_mock.mock()
+ def test_mismatch_content_length_streaming(self, m):
+ url = "https://test/package.tar.gz"
+
+ def f(request, context):
+ context.headers["Content-Length"] = "300810"
+ return None
+
+ m.head(
+ url=url,
+ status_code=200,
+ text=f,
+ )
+
+ requests.head(url)
diff --git a/contrib/python/requests-mock/py3/tests/test_request.py b/contrib/python/requests-mock/py3/tests/test_request.py
new file mode 100644
index 0000000000..69a71556e2
--- /dev/null
+++ b/contrib/python/requests-mock/py3/tests/test_request.py
@@ -0,0 +1,139 @@
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import uuid
+
+import requests
+import requests_mock
+from . import base
+
+
+class RequestTests(base.TestCase):
+
+ def setUp(self):
+ super(RequestTests, self).setUp()
+
+ self.mocker = requests_mock.Mocker()
+ self.addCleanup(self.mocker.stop)
+ self.mocker.start()
+
+ def do_request(self, **kwargs):
+ method = kwargs.pop('method', 'GET')
+ url = kwargs.pop('url', 'http://test.example.com/path')
+ status_code = kwargs.pop('status_code', 200)
+ data = uuid.uuid4().hex
+
+ m = self.mocker.register_uri(method,
+ url,
+ text=data,
+ status_code=status_code)
+
+ resp = requests.request(method, url, **kwargs)
+
+ self.assertEqual(status_code, resp.status_code)
+ self.assertEqual(data, resp.text)
+
+ self.assertTrue(m.called_once)
+ return m.last_request
+
+ def test_base_params(self):
+ req = self.do_request(method='GET', status_code=200)
+
+ self.assertIs(None, req.allow_redirects)
+ self.assertIs(None, req.timeout)
+ self.assertIs(True, req.verify)
+ self.assertIs(None, req.cert)
+ self.assertIs(False, req.stream)
+
+ # actually it's an OrderedDict, but equality works fine
+ # Skipping this check - it's problematic based on people's environments
+ # and in CI systems where there are proxies set up at the environment
+ # level. gh #127
+ # self.assertEqual({}, req.proxies)
+
+ def test_allow_redirects(self):
+ req = self.do_request(allow_redirects=False, status_code=300)
+ self.assertFalse(req.allow_redirects)
+
+ def test_timeout(self):
+ timeout = 300
+ req = self.do_request(timeout=timeout)
+ self.assertEqual(timeout, req.timeout)
+
+ def test_verify_false(self):
+ verify = False
+ req = self.do_request(verify=verify)
+ self.assertIs(verify, req.verify)
+
+ def test_verify_path(self):
+ verify = '/path/to/cacerts.pem'
+ req = self.do_request(verify=verify)
+ self.assertEqual(verify, req.verify)
+
+ def test_stream(self):
+ req = self.do_request()
+ self.assertIs(False, req.stream)
+ req = self.do_request(stream=False)
+ self.assertIs(False, req.stream)
+ req = self.do_request(stream=True)
+ self.assertIs(True, req.stream)
+
+ def test_certs(self):
+ cert = ('/path/to/cert.pem', 'path/to/key.pem')
+ req = self.do_request(cert=cert)
+ self.assertEqual(cert, req.cert)
+ self.assertTrue(req.verify)
+
+ def test_proxies(self):
+ proxies = {'http': 'foo.bar:3128',
+ 'http://host.name': 'foo.bar:4012'}
+
+ req = self.do_request(proxies=proxies)
+
+ self.assertEqual(proxies, req.proxies)
+ self.assertIsNot(proxies, req.proxies)
+
+ def test_hostname_port_http(self):
+ req = self.do_request(url='http://host.example.com:81/path')
+
+ self.assertEqual('host.example.com:81', req.netloc)
+ self.assertEqual('host.example.com', req.hostname)
+ self.assertEqual(81, req.port)
+
+ def test_hostname_port_https(self):
+ req = self.do_request(url='https://host.example.com:8080/path')
+
+ self.assertEqual('host.example.com:8080', req.netloc)
+ self.assertEqual('host.example.com', req.hostname)
+ self.assertEqual(8080, req.port)
+
+ def test_hostname_default_port_http(self):
+ req = self.do_request(url='http://host.example.com/path')
+
+ self.assertEqual('host.example.com', req.netloc)
+ self.assertEqual('host.example.com', req.hostname)
+ self.assertEqual(80, req.port)
+
+ def test_hostname_default_port_https(self):
+ req = self.do_request(url='https://host.example.com/path')
+
+ self.assertEqual('host.example.com', req.netloc)
+ self.assertEqual('host.example.com', req.hostname)
+ self.assertEqual(443, req.port)
+
+ def test_to_string(self):
+ req = self.do_request(url='https://host.example.com/path')
+ self.assertEqual('GET https://host.example.com/path', str(req))
+
+ def test_empty_query_string(self):
+ req = self.do_request(url='https://host.example.com/path?key')
+ self.assertEqual([''], req.qs['key'])
diff --git a/contrib/python/requests-mock/py3/tests/test_response.py b/contrib/python/requests-mock/py3/tests/test_response.py
new file mode 100644
index 0000000000..b560eea8d7
--- /dev/null
+++ b/contrib/python/requests-mock/py3/tests/test_response.py
@@ -0,0 +1,151 @@
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import io
+import pickle
+
+from requests_mock import exceptions
+from requests_mock import request
+from requests_mock import response
+from . import base
+
+
+class ResponseTests(base.TestCase):
+
+ def setUp(self):
+ super(ResponseTests, self).setUp()
+ self.method = 'GET'
+ self.url = 'http://test.url/path'
+ self.request = request._RequestObjectProxy._create(self.method,
+ self.url,
+ {})
+
+ def create_response(self, **kwargs):
+ return response.create_response(self.request, **kwargs)
+
+ def test_create_response_body_args(self):
+ self.assertRaises(RuntimeError,
+ self.create_response,
+ raw='abc',
+ body='abc')
+
+ self.assertRaises(RuntimeError,
+ self.create_response,
+ text='abc',
+ json={'a': 1})
+
+ def test_content_type(self):
+ self.assertRaises(TypeError, self.create_response, text=55)
+ self.assertRaises(TypeError, self.create_response, text={'a': 1})
+ self.assertRaises(TypeError, self.create_response, text=b'')
+
+ def test_text_type(self):
+ self.assertRaises(TypeError, self.create_response, content=u't')
+ self.assertRaises(TypeError, self.create_response, content={'a': 1})
+ self.assertRaises(TypeError, self.create_response, content=u'')
+
+ def test_json_body(self):
+ data = {'a': 1}
+ resp = self.create_response(json=data)
+
+ self.assertEqual('{"a": 1}', resp.text)
+ self.assertIsInstance(resp.text, str)
+ self.assertIsInstance(resp.content, bytes)
+ self.assertEqual(data, resp.json())
+
+ def test_body_body(self):
+ value = b'data'
+ body = io.BytesIO(value)
+ resp = self.create_response(body=body)
+
+ self.assertEqual(value.decode(), resp.text)
+ self.assertIsInstance(resp.text, str)
+ self.assertIsInstance(resp.content, bytes)
+
+ def test_setting_connection(self):
+ conn = object()
+ resp = self.create_response(connection=conn)
+ self.assertIs(conn, resp.connection)
+
+ def test_send_from_no_connection(self):
+ resp = self.create_response()
+ self.assertRaises(exceptions.InvalidRequest,
+ resp.connection.send, self.request)
+
+ def test_cookies_from_header(self):
+ # domain must be same as request url to pass policy check
+ headers = {'Set-Cookie': 'fig=newton; Path=/test; domain=.test.url'}
+ resp = self.create_response(headers=headers)
+
+ self.assertEqual('newton', resp.cookies['fig'])
+ self.assertEqual(['/test'], resp.cookies.list_paths())
+ self.assertEqual(['.test.url'], resp.cookies.list_domains())
+
+ def test_cookies_from_dict(self):
+ # This is a syntax we get from requests. I'm not sure i like it.
+ resp = self.create_response(cookies={'fig': 'newton',
+ 'sugar': 'apple'})
+
+ self.assertEqual('newton', resp.cookies['fig'])
+ self.assertEqual('apple', resp.cookies['sugar'])
+
+ def test_cookies_with_jar(self):
+ jar = response.CookieJar()
+ jar.set('fig', 'newton', path='/foo', domain='.test.url')
+ jar.set('sugar', 'apple', path='/bar', domain='.test.url')
+ resp = self.create_response(cookies=jar)
+
+ self.assertEqual('newton', resp.cookies['fig'])
+ self.assertEqual('apple', resp.cookies['sugar'])
+ self.assertEqual({'/foo', '/bar'}, set(resp.cookies.list_paths()))
+ self.assertEqual(['.test.url'], resp.cookies.list_domains())
+
+ def test_response_pickle(self):
+ text = 'hello world'
+ jar = response.CookieJar()
+ jar.set('fig', 'newton', path='/foo', domain='.test.url')
+ orig_resp = self.create_response(cookies=jar, text=text)
+
+ d = pickle.dumps(orig_resp)
+ new_resp = pickle.loads(d)
+
+ self.assertEqual(text, new_resp.text)
+ self.assertEqual('newton', new_resp.cookies['fig'])
+ self.assertIsNone(new_resp.request.matcher)
+
+ def test_response_encoding(self):
+ headers = {"content-type": "text/html; charset=ISO-8859-1"}
+ resp = self.create_response(headers=headers,
+ text="<html><body></body></html")
+ self.assertEqual('ISO-8859-1', resp.encoding)
+
+ def test_default_reason(self):
+ resp = self.create_response()
+ self.assertEqual('OK', resp.reason)
+
+ def test_custom_reason(self):
+ reason = 'Live long and prosper'
+ resp = self.create_response(status_code=201, reason=reason)
+
+ self.assertEqual(201, resp.status_code)
+ self.assertEqual(reason, resp.reason)
+
+ def test_some_other_response_reasons(self):
+ reasons = {
+ 301: 'Moved Permanently',
+ 410: 'Gone',
+ 503: 'Service Unavailable',
+ }
+
+ for code, reason in reasons.items():
+ self.assertEqual(reason,
+ self.create_response(status_code=code).reason)
diff --git a/contrib/python/requests-mock/py3/tests/ya.make b/contrib/python/requests-mock/py3/tests/ya.make
new file mode 100644
index 0000000000..f52ec22dba
--- /dev/null
+++ b/contrib/python/requests-mock/py3/tests/ya.make
@@ -0,0 +1,26 @@
+PY3TEST()
+
+SUBSCRIBER(g:python-contrib)
+
+PEERDIR(
+ contrib/python/mock
+ contrib/python/requests-futures
+ contrib/python/requests-mock
+)
+
+TEST_SRCS(
+ base.py
+ pytest/__init__.py
+ pytest/test_with_pytest.py
+ #test_adapter.py - need purl
+ test_custom_matchers.py
+ #test_fixture.py - need fixtures
+ test_matcher.py
+ test_mocker.py
+ test_request.py
+ test_response.py
+)
+
+NO_LINT()
+
+END()