Gracefully handle HTTP errors from pastebin
We find that the --pastebin option to pytest sometimes fails with "HTTP Error 400: Bad Request". We're still investigating the exact cause of these errors, but in the meantime, a failure to upload to the pastebin service should probably not crash pytest and cause a test failure in the continuous-integration. This patch catches exceptions like HTTPError that may be thrown while trying to communicate with the pastebin service, and reports them as a "bad response", without crashing with a backtrace or failing the entire test suite.
This commit is contained in:
parent
5bf9f9a711
commit
d47b9d04d4
1
AUTHORS
1
AUTHORS
|
@ -173,6 +173,7 @@ mbyt
|
|||
Michael Aquilina
|
||||
Michael Birtwell
|
||||
Michael Droettboom
|
||||
Michael Goerz
|
||||
Michael Seifert
|
||||
Michal Wajszczuk
|
||||
Mihai Capotă
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
New behavior of the ``--pastebin`` option: failures to connect to the pastebin server are reported, without failing the pytest run
|
|
@ -59,7 +59,7 @@ def create_new_paste(contents):
|
|||
Creates a new paste using bpaste.net service.
|
||||
|
||||
:contents: paste contents as utf-8 encoded bytes
|
||||
:returns: url to the pasted contents
|
||||
:returns: url to the pasted contents or error message
|
||||
"""
|
||||
import re
|
||||
from urllib.request import urlopen
|
||||
|
@ -67,12 +67,17 @@ def create_new_paste(contents):
|
|||
|
||||
params = {"code": contents, "lexer": "python3", "expiry": "1week"}
|
||||
url = "https://bpaste.net"
|
||||
response = urlopen(url, data=urlencode(params).encode("ascii")).read()
|
||||
m = re.search(r'href="/raw/(\w+)"', response.decode("utf-8"))
|
||||
try:
|
||||
response = (
|
||||
urlopen(url, data=urlencode(params).encode("ascii")).read().decode("utf-8")
|
||||
)
|
||||
except OSError as exc_info: # urllib errors
|
||||
return "bad response: %s" % exc_info
|
||||
m = re.search(r'href="/raw/(\w+)"', response)
|
||||
if m:
|
||||
return "{}/show/{}".format(url, m.group(1))
|
||||
else:
|
||||
return "bad response: " + response.decode("utf-8")
|
||||
return "bad response: invalid format ('" + response + "')"
|
||||
|
||||
|
||||
def pytest_terminal_summary(terminalreporter):
|
||||
|
|
|
@ -82,6 +82,47 @@ class TestPaste:
|
|||
def pastebin(self, request):
|
||||
return request.config.pluginmanager.getplugin("pastebin")
|
||||
|
||||
@pytest.fixture
|
||||
def mocked_urlopen_fail(self, monkeypatch):
|
||||
"""
|
||||
monkeypatch the actual urlopen call to emulate a HTTP Error 400
|
||||
"""
|
||||
calls = []
|
||||
|
||||
import urllib.error
|
||||
import urllib.request
|
||||
|
||||
def mocked(url, data):
|
||||
calls.append((url, data))
|
||||
raise urllib.error.HTTPError(url, 400, "Bad request", None, None)
|
||||
|
||||
monkeypatch.setattr(urllib.request, "urlopen", mocked)
|
||||
return calls
|
||||
|
||||
@pytest.fixture
|
||||
def mocked_urlopen_invalid(self, monkeypatch):
|
||||
"""
|
||||
monkeypatch the actual urlopen calls done by the internal plugin
|
||||
function that connects to bpaste service, but return a url in an
|
||||
unexpected format
|
||||
"""
|
||||
calls = []
|
||||
|
||||
def mocked(url, data):
|
||||
calls.append((url, data))
|
||||
|
||||
class DummyFile:
|
||||
def read(self):
|
||||
# part of html of a normal response
|
||||
return b'View <a href="/invalid/3c0c6750bd">raw</a>.'
|
||||
|
||||
return DummyFile()
|
||||
|
||||
import urllib.request
|
||||
|
||||
monkeypatch.setattr(urllib.request, "urlopen", mocked)
|
||||
return calls
|
||||
|
||||
@pytest.fixture
|
||||
def mocked_urlopen(self, monkeypatch):
|
||||
"""
|
||||
|
@ -105,6 +146,19 @@ class TestPaste:
|
|||
monkeypatch.setattr(urllib.request, "urlopen", mocked)
|
||||
return calls
|
||||
|
||||
def test_pastebin_invalid_url(self, pastebin, mocked_urlopen_invalid):
|
||||
result = pastebin.create_new_paste(b"full-paste-contents")
|
||||
assert (
|
||||
result
|
||||
== "bad response: invalid format ('View <a href=\"/invalid/3c0c6750bd\">raw</a>.')"
|
||||
)
|
||||
assert len(mocked_urlopen_invalid) == 1
|
||||
|
||||
def test_pastebin_http_error(self, pastebin, mocked_urlopen_fail):
|
||||
result = pastebin.create_new_paste(b"full-paste-contents")
|
||||
assert result == "bad response: HTTP Error 400: Bad request"
|
||||
assert len(mocked_urlopen_fail) == 1
|
||||
|
||||
def test_create_new_paste(self, pastebin, mocked_urlopen):
|
||||
result = pastebin.create_new_paste(b"full-paste-contents")
|
||||
assert result == "https://bpaste.net/show/3c0c6750bd"
|
||||
|
@ -127,4 +181,4 @@ class TestPaste:
|
|||
|
||||
monkeypatch.setattr(urllib.request, "urlopen", response)
|
||||
result = pastebin.create_new_paste(b"full-paste-contents")
|
||||
assert result == "bad response: something bad occurred"
|
||||
assert result == "bad response: invalid format ('something bad occurred')"
|
||||
|
|
Loading…
Reference in New Issue