testing/advanced_url_intercept.py (32 lines of code) (raw):
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
"""
Advanced URL Interceptor extension to intercept URL requests originating from
mercurial.urllibcompat and mock the response instead of sending any real
requests.
The interceptor can be configured using a JSON file consisting of URLs as keys,
and data and/or status code as values.
Here is an example configuration:
{
"https://example.org/": {"code": 200, "data": "Hello, world!"},
"https://example.com/": {"code": 404},
"https://example.ca/": {"code": null},
}
In the above configuration, the interceptor will return a 200 status code and
"Hello, world!" as the body if a request is made to https://example.org/. It
will raise an HTTPError with a status code of 404 if a request is made to
https://example.com/, and it will raise a URLError if a request is made to
https://example.ca/.
Possible values for "code" include an integer (this will be used directly when
creating the HTTPError exception), or None (null in JSON) which will cause a
URLError to be raised.
"""
import io
import json
from mercurial import (
error,
pycompat,
registrar,
url,
urllibcompat,
)
configtable = {}
configitem = registrar.configitem(configtable)
configitem(b"advancedurlintercept", b"path", default=None)
class AdvancedURLInterceptor(object):
def __init__(self, ui):
self.ui = ui
def open(self, req, data=None, *args, **kwargs):
"""
Args:
req (Request)
Returns:
io.BytesIO object with extra `getcode` attribute.
Raises:
HTTPError, URLError
"""
path = self.ui.config(b"advancedurlintercept", b"path")
if not path:
raise error.Abort(b"no urlintercept path defined!")
with open(path, "rb") as fh:
data = json.load(fh)
response = data[req.get_full_url()]
if response["code"] is None:
# No response, i.e. raise URLError
raise urllibcompat.urlerr.urlerror(b"fake error")
if response["code"] != 200:
raise urllibcompat.urlerr.httperror(url, response["code"], b"", None, None)
return_obj = io.BytesIO(pycompat.bytestr(json.dumps(response["data"])))
# Urllib "openers" expect a file-like object with some
# extra helper parameters. Add them here.
return_obj.getcode = lambda: 200
return return_obj
def extsetup(ui):
interceptor = AdvancedURLInterceptor(ui)
url.urlreq.installopener(interceptor)