summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Bruhin <git@the-compiler.org>2017-09-19 10:35:54 +0200
committerFlorian Bruhin <git@the-compiler.org>2017-09-19 10:35:54 +0200
commit55a4eb18f2a619562b29b17a13538192edad53c5 (patch)
tree0ac78f3994fa15eab6f0b26270540ede8c952a19
parent40b26d749276f9f48aa790a97e51a47618397cc1 (diff)
downloadqutebrowser-55a4eb18f2a619562b29b17a13538192edad53c5.tar.gz
qutebrowser-55a4eb18f2a619562b29b17a13538192edad53c5.zip
Get rid of httpbin
Fixes #2949
-rw-r--r--misc/requirements/requirements-tests-git.txt1
-rw-r--r--misc/requirements/requirements-tests.txt-raw1
-rw-r--r--tests/end2end/conftest.py2
-rw-r--r--tests/end2end/data/downloads/issue889.html2
-rw-r--r--tests/end2end/features/conftest.py68
-rw-r--r--tests/end2end/features/downloads.feature32
-rw-r--r--tests/end2end/features/history.feature6
-rw-r--r--tests/end2end/features/misc.feature8
-rw-r--r--tests/end2end/features/test_adblock_bdd.py4
-rw-r--r--tests/end2end/features/test_editor_bdd.py6
-rw-r--r--tests/end2end/features/test_history_bdd.py8
-rw-r--r--tests/end2end/features/test_private_bdd.py2
-rw-r--r--tests/end2end/features/test_sessions_bdd.py4
-rw-r--r--tests/end2end/fixtures/quteprocess.py10
-rw-r--r--tests/end2end/fixtures/test_quteprocess.py12
-rw-r--r--tests/end2end/fixtures/test_webserver.py20
-rw-r--r--tests/end2end/fixtures/testprocess.py8
-rw-r--r--tests/end2end/fixtures/webserver.py44
-rw-r--r--tests/end2end/fixtures/webserver_sub.py158
-rw-r--r--tests/end2end/test_invocations.py8
-rw-r--r--tests/end2end/test_mhtml_e2e.py16
21 files changed, 266 insertions, 154 deletions
diff --git a/misc/requirements/requirements-tests-git.txt b/misc/requirements/requirements-tests-git.txt
index 5a4450293..771cf58c8 100644
--- a/misc/requirements/requirements-tests-git.txt
+++ b/misc/requirements/requirements-tests-git.txt
@@ -4,7 +4,6 @@ hg+https://bitbucket.org/ned/coveragepy
git+https://github.com/micheles/decorator.git
git+https://github.com/pallets/flask.git
git+https://github.com/miracle2k/python-glob2.git
-git+https://github.com/Runscope/httpbin.git
git+https://github.com/HypothesisWorks/hypothesis-python.git
git+https://github.com/pallets/itsdangerous.git
git+https://bitbucket.org/zzzeek/mako.git
diff --git a/misc/requirements/requirements-tests.txt-raw b/misc/requirements/requirements-tests.txt-raw
index 3ca6de6bd..bc44bc8e1 100644
--- a/misc/requirements/requirements-tests.txt-raw
+++ b/misc/requirements/requirements-tests.txt-raw
@@ -3,7 +3,6 @@ cheroot
coverage
Flask
hunter
-httpbin
hypothesis
pytest
pytest-bdd
diff --git a/tests/end2end/conftest.py b/tests/end2end/conftest.py
index e9d2a8e95..1fd6eb874 100644
--- a/tests/end2end/conftest.py
+++ b/tests/end2end/conftest.py
@@ -34,7 +34,7 @@ from PyQt5.QtCore import PYQT_VERSION
pytest.register_assert_rewrite('end2end.fixtures')
-from end2end.fixtures.webserver import httpbin, httpbin_after_test, ssl_server
+from end2end.fixtures.webserver import server, server_after_test, ssl_server
from end2end.fixtures.quteprocess import (quteproc_process, quteproc,
quteproc_new)
from end2end.fixtures.testprocess import pytest_runtest_makereport
diff --git a/tests/end2end/data/downloads/issue889.html b/tests/end2end/data/downloads/issue889.html
index f6dbcfcbd..eccbefb33 100644
--- a/tests/end2end/data/downloads/issue889.html
+++ b/tests/end2end/data/downloads/issue889.html
@@ -5,7 +5,7 @@
<title>Failing download when redirecting/aborting</title>
</head>
<body>
- <a href="/custom/redirect-later?delay=1">redirect after 1s</a>
+ <a href="/redirect-later?delay=1">redirect after 1s</a>
<a href="/does-not-exist">404</a>
</body>
</html>
diff --git a/tests/end2end/features/conftest.py b/tests/end2end/features/conftest.py
index 602657541..52dfe616c 100644
--- a/tests/end2end/features/conftest.py
+++ b/tests/end2end/features/conftest.py
@@ -116,14 +116,14 @@ def pytest_runtest_makereport(item, call):
@bdd.given(bdd.parsers.parse("I set {opt} to {value}"))
-def set_setting_given(quteproc, httpbin, opt, value):
+def set_setting_given(quteproc, server, opt, value):
"""Set a qutebrowser setting.
This is available as "Given:" step so it can be used as "Background:".
"""
if value == '<empty>':
value = ''
- value = value.replace('(port)', str(httpbin.port))
+ value = value.replace('(port)', str(server.port))
quteproc.set_setting(opt, value)
@@ -174,7 +174,7 @@ def pdfjs_available():
@bdd.when(bdd.parsers.parse("I open {path}"))
-def open_path(quteproc, httpbin, path):
+def open_path(quteproc, server, path):
"""Open a URL.
- If used like "When I open ... in a new tab", the URL is opened in a new
@@ -183,7 +183,7 @@ def open_path(quteproc, httpbin, path):
- With "... in a private window" it's opened in a new private window.
- With "... as a URL", it's opened according to new_instance_open_target.
"""
- path = path.replace('(port)', str(httpbin.port))
+ path = path.replace('(port)', str(server.port))
new_tab = False
new_bg_tab = False
@@ -227,16 +227,16 @@ def open_path(quteproc, httpbin, path):
@bdd.when(bdd.parsers.parse("I set {opt} to {value}"))
-def set_setting(quteproc, httpbin, opt, value):
+def set_setting(quteproc, server, opt, value):
"""Set a qutebrowser setting."""
if value == '<empty>':
value = ''
- value = value.replace('(port)', str(httpbin.port))
+ value = value.replace('(port)', str(server.port))
quteproc.set_setting(opt, value)
@bdd.when(bdd.parsers.parse("I run {command}"))
-def run_command(quteproc, httpbin, tmpdir, command):
+def run_command(quteproc, server, tmpdir, command):
"""Run a qutebrowser command.
The suffix "with count ..." can be used to pass a count to the command.
@@ -254,7 +254,7 @@ def run_command(quteproc, httpbin, tmpdir, command):
else:
invalid = False
- command = command.replace('(port)', str(httpbin.port))
+ command = command.replace('(port)', str(server.port))
command = command.replace('(testdata)', utils.abs_datapath())
command = command.replace('(tmpdir)', str(tmpdir))
command = command.replace('(dirsep)', os.sep)
@@ -264,9 +264,9 @@ def run_command(quteproc, httpbin, tmpdir, command):
@bdd.when(bdd.parsers.parse("I reload"))
-def reload(qtbot, httpbin, quteproc, command):
+def reload(qtbot, server, quteproc, command):
"""Reload and wait until a new request is received."""
- with qtbot.waitSignal(httpbin.new_request):
+ with qtbot.waitSignal(server.new_request):
quteproc.send_cmd(':reload')
@@ -294,10 +294,10 @@ def wait_in_log(quteproc, is_regex, pattern, do_skip):
@bdd.when(bdd.parsers.re(r'I wait for the (?P<category>error|message|warning) '
r'"(?P<message>.*)"'))
-def wait_for_message(quteproc, httpbin, category, message):
+def wait_for_message(quteproc, server, category, message):
"""Wait for a given statusbar message/error/warning."""
quteproc.log_summary('Waiting for {} "{}"'.format(category, message))
- expect_message(quteproc, httpbin, category, message)
+ expect_message(quteproc, server, category, message)
@bdd.when(bdd.parsers.parse("I wait {delay}s"))
@@ -328,8 +328,8 @@ def selection_not_supported(qapp):
@bdd.when(bdd.parsers.re(r'I put "(?P<content>.*)" into the '
r'(?P<what>primary selection|clipboard)'))
-def fill_clipboard(quteproc, httpbin, what, content):
- content = content.replace('(port)', str(httpbin.port))
+def fill_clipboard(quteproc, server, what, content):
+ content = content.replace('(port)', str(server.port))
content = content.replace(r'\n', '\n')
quteproc.send_cmd(':debug-set-fake-clipboard "{}"'.format(content))
@@ -337,8 +337,8 @@ def fill_clipboard(quteproc, httpbin, what, content):
@bdd.when(bdd.parsers.re(r'I put the following lines into the '
r'(?P<what>primary selection|clipboard):\n'
r'(?P<content>.+)$', flags=re.DOTALL))
-def fill_clipboard_multiline(quteproc, httpbin, what, content):
- fill_clipboard(quteproc, httpbin, what, textwrap.dedent(content))
+def fill_clipboard_multiline(quteproc, server, what, content):
+ fill_clipboard(quteproc, server, what, textwrap.dedent(content))
@bdd.when(bdd.parsers.parse('I hint with args "{args}"'))
@@ -395,28 +395,28 @@ def path_should_be_loaded(quteproc, path):
@bdd.then(bdd.parsers.parse("{path} should be requested"))
-def path_should_be_requested(httpbin, path):
+def path_should_be_requested(server, path):
"""Make sure the given path was loaded from the webserver."""
- httpbin.wait_for(verb='GET', path='/' + path)
+ server.wait_for(verb='GET', path='/' + path)
@bdd.then(bdd.parsers.parse("The requests should be:\n{pages}"))
-def list_of_requests(httpbin, pages):
+def list_of_requests(server, pages):
"""Make sure the given requests were done from the webserver."""
- expected_requests = [httpbin.ExpectedRequest('GET', '/' + path.strip())
+ expected_requests = [server.ExpectedRequest('GET', '/' + path.strip())
for path in pages.split('\n')]
- actual_requests = httpbin.get_requests()
+ actual_requests = server.get_requests()
assert actual_requests == expected_requests
@bdd.then(bdd.parsers.parse("The unordered requests should be:\n{pages}"))
-def list_of_requests_unordered(httpbin, pages):
+def list_of_requests_unordered(server, pages):
"""Make sure the given requests were done (in no particular order)."""
- expected_requests = [httpbin.ExpectedRequest('GET', '/' + path.strip())
+ expected_requests = [server.ExpectedRequest('GET', '/' + path.strip())
for path in pages.split('\n')]
- actual_requests = httpbin.get_requests()
+ actual_requests = server.get_requests()
# Requests are not hashable, we need to convert to ExpectedRequests
- actual_requests = [httpbin.ExpectedRequest.from_request(req)
+ actual_requests = [server.ExpectedRequest.from_request(req)
for req in actual_requests]
assert (collections.Counter(actual_requests) ==
collections.Counter(expected_requests))
@@ -424,14 +424,14 @@ def list_of_requests_unordered(httpbin, pages):
@bdd.then(bdd.parsers.re(r'the (?P<category>error|message|warning) '
r'"(?P<message>.*)" should be shown'))
-def expect_message(quteproc, httpbin, category, message):
+def expect_message(quteproc, server, category, message):
"""Expect the given message in the qutebrowser log."""
category_to_loglevel = {
'message': logging.INFO,
'error': logging.ERROR,
'warning': logging.WARNING,
}
- message = message.replace('(port)', str(httpbin.port))
+ message = message.replace('(port)', str(server.port))
quteproc.mark_expected(category='message',
loglevel=category_to_loglevel[category],
message=message)
@@ -439,12 +439,12 @@ def expect_message(quteproc, httpbin, category, message):
@bdd.then(bdd.parsers.re(r'(?P<is_regex>regex )?"(?P<pattern>[^"]+)" should '
r'be logged'))
-def should_be_logged(quteproc, httpbin, is_regex, pattern):
+def should_be_logged(quteproc, server, is_regex, pattern):
"""Expect the given pattern on regex in the log."""
if is_regex:
pattern = re.compile(pattern)
else:
- pattern = pattern.replace('(port)', str(httpbin.port))
+ pattern = pattern.replace('(port)', str(server.port))
line = quteproc.wait_for(message=pattern)
line.expected = True
@@ -493,7 +493,7 @@ def no_crash():
def check_header(quteproc, header, value):
"""Check if a given header is set correctly.
- This assumes we're on the httpbin header page.
+ This assumes we're on the server header page.
"""
content = quteproc.get_content()
data = json.loads(content)
@@ -589,16 +589,16 @@ def check_open_tabs(quteproc, request, tabs):
@bdd.then(bdd.parsers.re(r'the (?P<what>primary selection|clipboard) should '
r'contain "(?P<content>.*)"'))
-def clipboard_contains(quteproc, httpbin, what, content):
- expected = content.replace('(port)', str(httpbin.port))
+def clipboard_contains(quteproc, server, what, content):
+ expected = content.replace('(port)', str(server.port))
expected = expected.replace('\\n', '\n')
quteproc.wait_for(message='Setting fake {}: {}'.format(
what, json.dumps(expected)))
@bdd.then(bdd.parsers.parse('the clipboard should contain:\n{content}'))
-def clipboard_contains_multiline(quteproc, httpbin, content):
- expected = textwrap.dedent(content).replace('(port)', str(httpbin.port))
+def clipboard_contains_multiline(quteproc, server, content):
+ expected = textwrap.dedent(content).replace('(port)', str(server.port))
quteproc.wait_for(message='Setting fake clipboard: {}'.format(
json.dumps(expected)))
diff --git a/tests/end2end/features/downloads.feature b/tests/end2end/features/downloads.feature
index 29d9fc7e3..103ad0123 100644
--- a/tests/end2end/features/downloads.feature
+++ b/tests/end2end/features/downloads.feature
@@ -292,7 +292,7 @@ Feature: Downloading things from a website.
Scenario: Opening a mhtml download directly
When I set downloads.location.prompt to true
- And I open html
+ And I open /
And I run :download --mhtml
And I wait for the download prompt for "*"
And I directly open the download
@@ -572,27 +572,27 @@ Feature: Downloading things from a website.
Scenario: Downloading with redirect to itself
When I set downloads.location.prompt to false
- And I run :download http://localhost:(port)/custom/redirect-self
+ And I run :download http://localhost:(port)/redirect-self
And I wait until the download is finished
Then the downloaded file redirect-self should exist
Scenario: Downloading with absolute redirect
When I set downloads.location.prompt to false
- And I run :download http://localhost:(port)/absolute-redirect/1
+ And I run :download http://localhost:(port)/absolute-redirect
And I wait until the download is finished
- Then the downloaded file 1 should exist
+ Then the downloaded file absolute-redirect should exist
Scenario: Downloading with relative redirect
When I set downloads.location.prompt to false
- And I run :download http://localhost:(port)/relative-redirect/1
+ And I run :download http://localhost:(port)/relative-redirect
And I wait until the download is finished
- Then the downloaded file 1 should exist
+ Then the downloaded file relative-redirect should exist
## Other
Scenario: Download without a content-size
When I set downloads.location.prompt to false
- When I run :download http://localhost:(port)/custom/content-size
+ When I run :download http://localhost:(port)/content-size
And I wait until the download is finished
Then the downloaded file content-size should exist
@@ -604,13 +604,13 @@ Feature: Downloading things from a website.
Scenario: Downloading 20MB file
When I set downloads.location.prompt to false
- And I run :download http://localhost:(port)/custom/twenty-mb
+ And I run :download http://localhost:(port)/twenty-mb
And I wait until the download is finished
Then the downloaded file twenty-mb should be 20971520 bytes big
Scenario: Downloading 20MB file with late prompt confirmation
When I set downloads.location.prompt to true
- And I run :download http://localhost:(port)/custom/twenty-mb
+ And I run :download http://localhost:(port)/twenty-mb
And I wait 1s
And I run :prompt-accept
And I wait until the download is finished
@@ -645,12 +645,6 @@ Feature: Downloading things from a website.
Then the downloaded file download.bin should exist
And the downloaded file download2.bin should not exist
- Scenario: Downloading a file with unknown size
- When I set downloads.location.prompt to false
- And I open stream-bytes/1024 without waiting
- And I wait until the download is finished
- Then the downloaded file 1024 should exist
-
@qtwebengine_skip: We can't get the UA from the page there
Scenario: user-agent when using :download
When I open user-agent
@@ -660,16 +654,14 @@ Feature: Downloading things from a website.
@qtwebengine_skip: We can't get the UA from the page there
Scenario: user-agent when using hints
- When I set hints.mode to number
- And I open /
+ When I open /
And I run :hint links download
- And I press the keys "us" # user-agent
- And I run :follow-hint 0
+ And I run :follow-hint a
And I wait until the download is finished
Then the downloaded file user-agent should contain Safari/
@qtwebengine_skip: Handled by QtWebEngine, not by us
Scenario: Downloading a "Internal server error" with disposition: inline (#2304)
When I set downloads.location.prompt to false
- And I open custom/500-inline
+ And I open 500-inline
Then the error "Download error: *INTERNAL SERVER ERROR" should be shown
diff --git a/tests/end2end/features/history.feature b/tests/end2end/features/history.feature
index be4035f37..b86e5743b 100644
--- a/tests/end2end/features/history.feature
+++ b/tests/end2end/features/history.feature
@@ -46,10 +46,10 @@ Feature: Page history
@qtwebengine_todo: Error page message is not implemented
Scenario: History with a 404
- When I open status/404 without waiting
- And I wait for "Error while loading http://localhost:*/status/404: NOT FOUND" in the log
+ When I open 404 without waiting
+ And I wait for "Error while loading http://localhost:*/404: NOT FOUND" in the log
Then the history should contain:
- http://localhost:(port)/status/404 Error loading page: http://localhost:(port)/status/404
+ http://localhost:(port)/404 Error loading page: http://localhost:(port)/404
Scenario: History with invalid URL
When I run :tab-only
diff --git a/tests/end2end/features/misc.feature b/tests/end2end/features/misc.feature
index e44e84571..3d23033f5 100644
--- a/tests/end2end/features/misc.feature
+++ b/tests/end2end/features/misc.feature
@@ -186,15 +186,15 @@ Feature: Various utility commands.
Given I have a fresh instance
# We can't use "When I open" because we don't want to wait for load
# finished
- When I run :open http://localhost:(port)/custom/redirect-later?delay=-1
+ When I run :open http://localhost:(port)/redirect-later?delay=-1
And I wait for "emitting: cur_load_status_changed('loading') (tab *)" in the log
And I wait 1s
And I run :stop
- And I open custom/redirect-later-continue in a new tab
+ And I open redirect-later-continue in a new tab
And I wait 1s
Then the unordered requests should be:
- custom/redirect-later-continue
- custom/redirect-later?delay=-1
+ redirect-later-continue
+ redirect-later?delay=-1
# no request on / because we stopped the redirect
Scenario: :stop with wrong count
diff --git a/tests/end2end/features/test_adblock_bdd.py b/tests/end2end/features/test_adblock_bdd.py
index 4f9d72f9c..780e55a59 100644
--- a/tests/end2end/features/test_adblock_bdd.py
+++ b/tests/end2end/features/test_adblock_bdd.py
@@ -25,7 +25,7 @@ bdd.scenarios('adblock.feature')
@bdd.when(bdd.parsers.parse('I set up "{lists}" as block lists'))
-def set_up_blocking(quteproc, lists, httpbin):
- url = 'http://localhost:{}/data/adblock/'.format(httpbin.port)
+def set_up_blocking(quteproc, lists, server):
+ url = 'http://localhost:{}/data/adblock/'.format(server.port)
urls = [url + item.strip() for item in lists.split(',')]
quteproc.set_setting('content.host_blocking.lists', json.dumps(urls))
diff --git a/tests/end2end/features/test_editor_bdd.py b/tests/end2end/features/test_editor_bdd.py
index 8e0537e69..eb937e0f2 100644
--- a/tests/end2end/features/test_editor_bdd.py
+++ b/tests/end2end/features/test_editor_bdd.py
@@ -27,9 +27,9 @@ bdd.scenarios('editor.feature')
@bdd.when(bdd.parsers.parse('I set up a fake editor replacing "{text}" by '
'"{replacement}"'))
-def set_up_editor_replacement(quteproc, httpbin, tmpdir, text, replacement):
+def set_up_editor_replacement(quteproc, server, tmpdir, text, replacement):
"""Set up editor.command to a small python script doing a replacement."""
- text = text.replace('(port)', str(httpbin.port))
+ text = text.replace('(port)', str(server.port))
script = tmpdir / 'script.py'
script.write(textwrap.dedent("""
import sys
@@ -47,7 +47,7 @@ def set_up_editor_replacement(quteproc, httpbin, tmpdir, text, replacement):
@bdd.when(bdd.parsers.parse('I set up a fake editor returning "{text}"'))
-def set_up_editor(quteproc, httpbin, tmpdir, text):
+def set_up_editor(quteproc, server, tmpdir, text):
"""Set up editor.command to a small python script inserting a text."""
script = tmpdir / 'script.py'
script.write(textwrap.dedent("""
diff --git a/tests/end2end/features/test_history_bdd.py b/tests/end2end/features/test_history_bdd.py
index debf72d09..8bdd8c396 100644
--- a/tests/end2end/features/test_history_bdd.py
+++ b/tests/end2end/features/test_history_bdd.py
@@ -35,7 +35,7 @@ def turn_on_sql_history(quteproc):
@bdd.then(bdd.parsers.parse("the history should contain:\n{expected}"))
-def check_history(quteproc, httpbin, tmpdir, expected):
+def check_history(quteproc, server, tmpdir, expected):
path = tmpdir / 'history'
quteproc.send_cmd(':debug-dump-history "{}"'.format(path))
quteproc.wait_for(category='message', loglevel=logging.INFO,
@@ -45,10 +45,10 @@ def check_history(quteproc, httpbin, tmpdir, expected):
# ignore access times, they will differ in each run
actual = '\n'.join(re.sub('^\\d+-?', '', line).strip() for line in f)
- expected = expected.replace('(port)', str(httpbin.port))
+ expected = expected.replace('(port)', str(server.port))
assert actual == expected
@bdd.then("the history should be empty")
-def check_history_empty(quteproc, httpbin, tmpdir):
- check_history(quteproc, httpbin, tmpdir, '')
+def check_history_empty(quteproc, server, tmpdir):
+ check_history(quteproc, server, tmpdir, '')
diff --git a/tests/end2end/features/test_private_bdd.py b/tests/end2end/features/test_private_bdd.py
index a9ed92e6e..6e591a2e0 100644
--- a/tests/end2end/features/test_private_bdd.py
+++ b/tests/end2end/features/test_private_bdd.py
@@ -27,7 +27,7 @@ bdd.scenarios('private.feature')
def check_cookie(quteproc, name, value):
"""Check if a given cookie is set correctly.
- This assumes we're on the httpbin cookies page.
+ This assumes we're on the server cookies page.
"""
content = quteproc.get_content()
data = json.loads(content)
diff --git a/tests/end2end/features/test_sessions_bdd.py b/tests/end2end/features/test_sessions_bdd.py
index 052748f90..b4f5dcf2c 100644
--- a/tests/end2end/features/test_sessions_bdd.py
+++ b/tests/end2end/features/test_sessions_bdd.py
@@ -34,13 +34,13 @@ def create_session_file(quteproc, name, contents):
@bdd.when(bdd.parsers.parse('I replace "{pattern}" by "{replacement}" in the '
'"{name}" session file'))
-def session_replace(quteproc, httpbin, pattern, replacement, name):
+def session_replace(quteproc, server, pattern, replacement, name):
# First wait until the session was actually saved
quteproc.wait_for(category='message', loglevel=logging.INFO,
message='Saved session {}.'.format(name))
filename = os.path.join(quteproc.basedir, 'data', 'sessions',
name + '.yml')
- replacement = replacement.replace('(port)', str(httpbin.port)) # yo dawg
+ replacement = replacement.replace('(port)', str(server.port)) # yo dawg
with open(filename, 'r', encoding='utf-8') as f:
data = f.read()
with open(filename, 'w', encoding='utf-8') as f:
diff --git a/tests/end2end/fixtures/quteprocess.py b/tests/end2end/fixtures/quteprocess.py
index eb166f5b6..73f885cfe 100644
--- a/tests/end2end/fixtures/quteprocess.py
+++ b/tests/end2end/fixtures/quteprocess.py
@@ -415,10 +415,10 @@ class QuteProc(testprocess.Process):
if any(path.startswith(scheme) for scheme in special_schemes):
return path
else:
- httpbin = self.request.getfixturevalue('httpbin')
+ server = self.request.getfixturevalue('server')
return '{}://localhost:{}/{}'.format(
'https' if https else 'http',
- httpbin.port if port is None else port,
+ server.port if port is None else port,
path if path != '/' else '')
def wait_for_js(self, message):
@@ -778,7 +778,7 @@ def _xpath_escape(text):
@pytest.fixture(scope='module')
-def quteproc_process(qapp, httpbin, request):
+def quteproc_process(qapp, server, request):
"""Fixture for qutebrowser process which is started once per file."""
# Passing request so it has an initial config
proc = QuteProc(request)
@@ -788,7 +788,7 @@ def quteproc_process(qapp, httpbin, request):
@pytest.fixture
-def quteproc(quteproc_process, httpbin, request):
+def quteproc(quteproc_process, server, request):
"""Per-test qutebrowser fixture which uses the per-file process."""
request.node._quteproc_log = quteproc_process.captured_log
quteproc_process.before_test()
@@ -798,7 +798,7 @@ def quteproc(quteproc_process, httpbin, request):
@pytest.fixture
-def quteproc_new(qapp, httpbin, request):
+def quteproc_new(qapp, server, request):
"""Per-test qutebrowser process to test invocations."""
proc = QuteProc(request)
request.node._quteproc_log = proc.captured_log
diff --git a/tests/end2end/fixtures/test_quteprocess.py b/tests/end2end/fixtures/test_quteprocess.py
index 0b9680ff4..39cbe598c 100644
--- a/tests/end2end/fixtures/test_quteprocess.py
+++ b/tests/end2end/fixtures/test_quteprocess.py
@@ -66,23 +66,23 @@ class FakeRequest:
"""Fake for request."""
- def __init__(self, node, config, httpbin):
+ def __init__(self, node, config, server):
self.node = node
self.config = config
- self._httpbin = httpbin
+ self._server = server
def getfixturevalue(self, name):
- assert name == 'httpbin'
- return self._httpbin
+ assert name == 'server'
+ return self._server
@pytest.fixture
-def request_mock(quteproc, monkeypatch, httpbin):
+def request_mock(quteproc, monkeypatch, server):
"""Patch out a pytest request."""
fake_call = FakeRepCall()
fake_config = FakeConfig()
fake_node = FakeNode(fake_call)
- fake_request = FakeRequest(fake_node, fake_config, httpbin)
+ fake_request = FakeRequest(fake_node, fake_config, server)
assert not hasattr(fake_request.node.rep_call, 'wasxfail')
monkeypatch.setattr(quteproc, 'request', fake_request)
return fake_request
diff --git a/tests/end2end/fixtures/test_webserver.py b/tests/end2end/fixtures/test_webserver.py
index c885ea5b6..331c0906d 100644
--- a/tests/end2end/fixtures/test_webserver.py
+++ b/tests/end2end/fixtures/test_webserver.py
@@ -17,7 +17,7 @@
# You should have received a copy of the GNU General Public License
# along with qutebrowser. If not, see <http://www.gnu.org/licenses/>.
-"""Test the httpbin webserver used for tests."""
+"""Test the server webserver used for tests."""
import json
import urllib.request
@@ -27,14 +27,14 @@ import pytest
@pytest.mark.parametrize('path, content, expected', [
- ('/', '<title>httpbin(1): HTTP Client Testing Service</title>', True),
- # https://github.com/Runscope/httpbin/issues/245
+ ('/', 'qutebrowser test webserver', True),
+ # https://github.com/Runscope/server/issues/245
('/', 'www.google-analytics.com', False),
('/data/hello.txt', 'Hello World!', True),
])
-def test_httpbin(httpbin, qtbot, path, content, expected):
- with qtbot.waitSignal(httpbin.new_request, timeout=100):
- url = 'http://localhost:{}{}'.format(httpbin.port, path)
+def test_server(server, qtbot, path, content, expected):
+ with qtbot.waitSignal(server.new_request, timeout=100):
+ url = 'http://localhost:{}{}'.format(server.port, path)
try:
response = urllib.request.urlopen(url)
except urllib.error.HTTPError as e:
@@ -47,7 +47,7 @@ def test_httpbin(httpbin, qtbot, path, content, expected):
data = response.read().decode('utf-8')
- assert httpbin.get_requests() == [httpbin.ExpectedRequest('GET', path)]
+ assert server.get_requests() == [server.ExpectedRequest('GET', path)]
assert (content in data) == expected
@@ -58,7 +58,7 @@ def test_httpbin(httpbin, qtbot, path, content, expected):
({'verb': 'GET', 'path': '/', 'status': 200}, 'GET', '/foo', False),
({'verb': 'POST', 'path': '/', 'status': 200}, 'GET', '/', False),
])
-def test_expected_request(httpbin, line, verb, path, equal):
- expected = httpbin.ExpectedRequest(verb, path)
- request = httpbin.Request(json.dumps(line))
+def test_expected_request(server, line, verb, path, equal):
+ expected = server.ExpectedRequest(verb, path)
+ request = server.Request(json.dumps(line))
assert (expected == request) == equal
diff --git a/tests/end2end/fixtures/testprocess.py b/tests/end2end/fixtures/testprocess.py
index 1a2c51baf..68b30a105 100644
--- a/tests/end2end/fixtures/testprocess.py
+++ b/tests/end2end/fixtures/testprocess.py
@@ -90,7 +90,7 @@ def _render_log(data, threshold=100):
@pytest.hookimpl(hookwrapper=True)
def pytest_runtest_makereport(item, call):
- """Add qutebrowser/httpbin sections to captured output if a test failed."""
+ """Add qutebrowser/server sections to captured output if a test failed."""
outcome = yield
if call.when not in ['call', 'teardown']:
return
@@ -100,7 +100,7 @@ def pytest_runtest_makereport(item, call):
return
quteproc_log = getattr(item, '_quteproc_log', None)
- httpbin_log = getattr(item, '_httpbin_log', None)
+ server_log = getattr(item, '_server_log', None)
if not hasattr(report.longrepr, 'addsection'):
# In some conditions (on macOS and Windows it seems), report.longrepr
@@ -114,8 +114,8 @@ def pytest_runtest_makereport(item, call):
if quteproc_log is not None:
report.longrepr.addsection("qutebrowser output",
_render_log(quteproc_log))
- if httpbin_log is not None:
- report.longrepr.addsection("httpbin output", _render_log(httpbin_log))
+ if server_log is not None:
+ report.longrepr.addsection("server output", _render_log(server_log))
class Process(QObject):
diff --git a/tests/end2end/fixtures/webserver.py b/tests/end2end/fixtures/webserver.py
index acb99acfe..01887d9b9 100644
--- a/tests/end2end/fixtures/webserver.py
+++ b/tests/end2end/fixtures/webserver.py
@@ -17,7 +17,7 @@
# You should have received a copy of the GNU General Public License
# along with qutebrowser. If not, see <http://www.gnu.org/licenses/>.
-"""Fixtures for the httpbin webserver."""
+"""Fixtures for the server webserver."""
import re
import sys
@@ -35,7 +35,7 @@ from qutebrowser.utils import utils
class Request(testprocess.Line):
- """A parsed line from the httpbin/flask log output.
+ """A parsed line from the flask log output.
Attributes:
verb/path/status: Parsed from the log output.
@@ -67,22 +67,20 @@ class Request(testprocess.Line):
'/favicon.ico': [http.client.NOT_FOUND],
'/does-not-exist': [http.client.NOT_FOUND],
'/does-not-exist-2': [http.client.NOT_FOUND],
- '/status/404': [http.client.NOT_FOUND],
+ '/404': [http.client.NOT_FOUND],
- '/custom/redirect-later': [http.client.FOUND],
- '/custom/redirect-self': [http.client.FOUND],
+ '/redirect-later': [http.client.FOUND],
+ '/redirect-self': [http.client.FOUND],
'/redirect-to': [http.client.FOUND],
+ '/relative-redirect': [http.client.FOUND],
+ '/absolute-redirect': [http.client.FOUND],
'/cookies/set': [http.client.FOUND],
- '/custom/500-inline': [http.client.INTERNAL_SERVER_ERROR],
+ '/500-inline': [http.client.INTERNAL_SERVER_ERROR],
}
for i in range(15):
path_to_statuses['/redirect/{}'.format(i)] = [http.client.FOUND]
- path_to_statuses['/relative-redirect/{}'.format(i)] = [
- http.client.FOUND]
- path_to_statuses['/absolute-redirect/{}'.format(i)] = [
- http.client.FOUND]
for suffix in ['', '1', '2', '3', '4', '5', '6']:
key = '/basic-auth/user{}/password{}'.format(suffix, suffix)
path_to_statuses[key] = [http.client.UNAUTHORIZED, http.client.OK]
@@ -130,7 +128,7 @@ class ExpectedRequest:
class WebserverProcess(testprocess.Process):
- """Abstraction over a running HTTPbin server process.
+ """Abstraction over a running Flask server process.
Reads the log from its stdout and parses it.
@@ -186,31 +184,31 @@ class WebserverProcess(testprocess.Process):
@pytest.fixture(scope='session', autouse=True)
-def httpbin(qapp):
- """Fixture for an httpbin object which ensures clean setup/teardown."""
- httpbin = WebserverProcess('webserver_sub')
- httpbin.start()
- yield httpbin
- httpbin.cleanup()
+def server(qapp):
+ """Fixture for an server object which ensures clean setup/teardown."""
+ server = WebserverProcess('webserver_sub')
+ server.start()
+ yield server
+ server.cleanup()
@pytest.fixture(autouse=True)
-def httpbin_after_test(httpbin, request):
- """Fixture to clean httpbin request list after each test."""
- request.node._httpbin_log = httpbin.captured_log
+def server_after_test(server, request):
+ """Fixture to clean server request list after each test."""
+ request.node._server_log = server.captured_log
yield
- httpbin.after_test()
+ server.after_test()
@pytest.fixture
def ssl_server(request, qapp):
"""Fixture for a webserver with a self-signed SSL certificate.
- This needs to be explicitly used in a test, and overwrites the httpbin log
+ This needs to be explicitly used in a test, and overwrites the server log
used in that test.
"""
server = WebserverProcess('webserver_sub_ssl')
- request.node._httpbin_log = server.captured_log
+ request.node._server_log = server.captured_log
server.start()
yield server
server.after_test()
diff --git a/tests/end2end/fixtures/webserver_sub.py b/tests/end2end/fixtures/webserver_sub.py
index 53c033f5b..1059ca520 100644
--- a/tests/end2end/fixtures/webserver_sub.py
+++ b/tests/end2end/fixtures/webserver_sub.py
@@ -17,9 +17,13 @@
# You should have received a copy of the GNU General Public License
# along with qutebrowser. If not, see <http://www.gnu.org/licenses/>.
-"""httpbin web server for end2end tests.
+"""Web server for end2end tests.
This script gets called as a QProcess from end2end/conftest.py.
+
+Some of the handlers here are inspired by the server project, but simplified
+for qutebrowser's needs. Note that it probably doesn't handle e.g. multiple
+parameters or headers with the same name properly.
"""
import sys
@@ -29,15 +33,20 @@ import signal
import os
import threading
-from httpbin.core import app
-from httpbin.structures import CaseInsensitiveDict
import cheroot.wsgi
import flask
-
+app = flask.Flask(__name__)
_redirect_later_event = None
+@app.route('/')
+def root():
+ """Show simple text."""
+ return flask.Response(b'qutebrowser test webserver, '
+ b'<a href="/user-agent">user agent</a>')
+
+
@app.route('/data/<path:path>')
def send_data(path):
"""Send a given data file to qutebrowser.
@@ -57,15 +66,14 @@ def send_data(path):
return flask.send_from_directory(data_dir, path)
-@app.route('/custom/redirect-later')
+@app.route('/redirect-later')
def redirect_later():
"""302 redirect to / after the given delay.
If delay is -1, wait until a request on redirect-later-continue is done.
"""
global _redirect_later_event
- args = CaseInsensitiveDict(flask.request.args.items())
- delay = int(args.get('delay', '1'))
+ delay = int(flask.request.args.get('delay', '1'))
if delay == -1:
_redirect_later_event = threading.Event()
ok = _redirect_later_event.wait(timeout=30 * 1000)
@@ -77,7 +85,7 @@ def redirect_later():
return x
-@app.route('/custom/redirect-later-continue')
+@app.route('/redirect-later-continue')
def redirect_later_continue():
"""Continue a redirect-later request."""
if _redirect_later_event is None:
@@ -87,7 +95,50 @@ def redirect_later_continue():
return flask.Response(b'Continued redirect.')
-@app.route('/custom/content-size')
+@app.route('/redirect-self')
+def redirect_self():
+ """302 Redirects to itself."""
+ return app.make_response(flask.redirect(flask.url_for('redirect_self')))
+
+
+@app.route('/redirect/<int:n>')
+def redirect_n_times(n):
+ """302 Redirects n times."""
+ assert n > 0
+ return flask.redirect(flask.url_for('redirect_n_times', n=n-1))
+
+
+@app.route('/relative-redirect')
+def relative_redirect():
+ """302 Redirect once."""
+ response = app.make_response('')
+ response.status_code = 302
+ response.headers['Location'] = flask.url_for('root')
+ return response
+
+
+@app.route('/absolute-redirect')
+def absolute_redirect():
+ """302 Redirect once."""
+ response = app.make_response('')
+ response.status_code = 302
+ response.headers['Location'] = flask.url_for('root', _external=True)
+ return response
+
+
+@app.route('/redirect-to')
+def redirect_to():
+ """302/3XX Redirects to the given URL."""
+ # We need to build the response manually and convert to UTF-8 to prevent
+ # werkzeug from "fixing" the URL. This endpoint should set the Location
+ # header to the exact string supplied.
+ response = app.make_response('')
+ response.status_code = 302
+ response.headers['Location'] = flask.request.args['url'].encode('utf-8')
+ return response
+
+
+@app.route('/content-size')
def content_size():
"""Send two bytes of data without a content-size."""
def generate_bytes():
@@ -102,7 +153,7 @@ def content_size():
return response
-@app.route('/custom/twenty-mb')
+@app.route('/twenty-mb')
def twenty_mb():
"""Send 20MB of data."""
def generate_bytes():
@@ -116,13 +167,7 @@ def twenty_mb():
return response
-@app.route('/custom/redirect-self')
-def redirect_self():
- """302 Redirects to itself."""
- return app.make_response(flask.redirect(flask.url_for('redirect_self')))
-
-
-@app.route('/custom/500-inline')
+@app.route('/500-inline')
def internal_error_attachment():
"""A 500 error with Content-Disposition: inline."""
response = flask.Response(b"", headers={
@@ -133,6 +178,85 @@ def internal_error_attachment():
return response
+@app.route('/cookies')
+def view_cookies():
+ """Show cookies."""
+ return flask.jsonify(cookies=flask.request.cookies)
+
+
+@app.route('/cookies/set')
+def set_cookies():
+ """Set cookie(s) as provided by the query string."""
+ r = app.make_response(flask.redirect(flask.url_for('view_cookies')))
+ for key, value in flask.request.args.items():
+ r.set_cookie(key=key, value=value)
+ return r
+
+
+@app.route('/basic-auth/<user>/<passwd>')
+def basic_auth(user='user', passwd='passwd'):
+ """Prompt the user for authorization using HTTP Basic Auth."""
+ auth = flask.request.authorization
+ if not auth or auth.username != user or auth.password != passwd:
+ r = flask.make_response()
+ r.status_code = 401
+ r.headers = {'WWW-Authenticate': 'Basic realm="Fake Realm"'}
+ return r
+
+ return flask.jsonify(authenticated=True, user=user)
+
+
+@app.route('/drip')
+def drip():
+ """Drip data over a duration."""
+ duration = float(flask.request.args.get('duration'))
+ numbytes = int(flask.request.args.get('numbytes'))
+ pause = duration / numbytes
+
+ def generate_bytes():
+ for _ in range(numbytes):
+ yield u"*".encode('utf-8')
+ time.sleep(pause)
+
+ response = flask.Response(generate_bytes(), headers={
+ "Content-Type": "application/octet-stream",
+ "Content-Length": str(numbytes),
+ })
+ response.status_code = 200
+ return response
+
+
+@app.route('/404')
+def status_404():
+ r = flask.make_response()
+ r.status_code = 404
+ return r
+
+
+@app.route('/headers')
+def view_headers():
+ """Return HTTP headers."""
+ return flask.jsonify(headers=dict(flask.request.headers))
+
+
+@app.route('/response-headers')
+def response_headers():
+ """Return a set of response headers from the query string."""
+ headers = flask.request.args
+ response = flask.jsonify(headers)
+ response.headers.extend(headers)
+
+ response = flask.jsonify(dict(response.headers))
+ response.headers.extend(headers)
+ return response
+
+
+@app.route('/user-agent')
+def view_user_agent():
+ """Return User-Agent."""
+ return flask.jsonify({'user-agent': flask.request.headers['user-agent']})
+
+
@app.after_request
def log_request(response):
"""Log a webserver request."""
diff --git a/tests/end2end/test_invocations.py b/tests/end2end/test_invocations.py
index a59ea5db7..03626dc14 100644
--- a/tests/end2end/test_invocations.py
+++ b/tests/end2end/test_invocations.py
@@ -70,7 +70,7 @@ def temp_basedir_env(tmpdir, short_tmpdir):
@pytest.mark.linux
-def test_ascii_locale(request, httpbin, tmpdir, quteproc_new):
+def test_ascii_locale(request, server, tmpdir, quteproc_new):
"""Test downloads with LC_ALL=C set.
https://github.com/qutebrowser/qutebrowser/issues/908
@@ -83,7 +83,7 @@ def test_ascii_locale(request, httpbin, tmpdir, quteproc_new):
# Test a normal download
quteproc_new.set_setting('downloads.location.prompt', 'false')
url = 'http://localhost:{port}/data/downloads/รค-issue908.bin'.format(
- port=httpbin.port)
+ port=server.port)
quteproc_new.send_cmd(':download {}'.format(url))
quteproc_new.wait_for(category='downloads',
message='Download ?-issue908.bin finished')
@@ -103,7 +103,7 @@ def test_ascii_locale(request, httpbin, tmpdir, quteproc_new):
@pytest.mark.linux
-def test_misconfigured_user_dirs(request, httpbin, temp_basedir_env,
+def test_misconfigured_user_dirs(request, server, temp_basedir_env,
tmpdir, quteproc_new):
"""Test downloads with a misconfigured XDG_DOWNLOAD_DIR.
@@ -122,7 +122,7 @@ def test_misconfigured_user_dirs(request, httpbin, temp_basedir_env,
quteproc_new.set_setting('downloads.location.prompt', 'false')
url = 'http://localhost:{port}/data/downloads/download.bin'.format(
- port=httpbin.port)
+ port=server.port)
quteproc_new.send_cmd(':download {}'.format(url))
line = quteproc_new.wait_for(
loglevel=logging.ERROR, category='message',
diff --git a/tests/end2end/test_mhtml_e2e.py b/tests/end2end/test_mhtml_e2e.py
index a623dd391..4317271f5 100644
--- a/tests/end2end/test_mhtml_e2e.py
+++ b/tests/end2end/test_mhtml_e2e.py
@@ -85,25 +85,25 @@ def download_dir(tmpdir):
return DownloadDir(tmpdir)
-def _test_mhtml_requests(test_dir, test_path, httpbin):
+def _test_mhtml_requests(test_dir, test_path, server):
with open(os.path.join(test_dir, 'requests'), encoding='utf-8') as f:
expected_requests = []
for line in f:
if line.startswith('#'):
continue
path = '/{}/{}'.format(test_path, line.strip())
- expected_requests.append(httpbin.ExpectedRequest('GET', path))
+ expected_requests.append(server.ExpectedRequest('GET', path))
- actual_requests = httpbin.get_requests()
+ actual_requests = server.get_requests()
# Requests are not hashable, we need to convert to ExpectedRequests
- actual_requests = [httpbin.ExpectedRequest.from_request(req)
+ actual_requests = [server.ExpectedRequest.from_request(req)
for req in actual_requests]
assert (collections.Counter(actual_requests) ==
collections.Counter(expected_requests))
@pytest.mark.parametrize('test_name', collect_tests())
-def test_mhtml(request, test_name, download_dir, quteproc, httpbin):
+def test_mhtml(request, test_name, download_dir, quteproc, server):
quteproc.set_setting('downloads.location.directory', download_dir.location)
quteproc.set_setting('downloads.location.prompt', 'false')
@@ -119,10 +119,10 @@ def test_mhtml(request, test_name, download_dir, quteproc, httpbin):
# Wait for favicon.ico to be loaded if there is one
if os.path.exists(os.path.join(test_dir, 'favicon.png')):
- httpbin.wait_for(path='/{}/favicon.png'.format(test_path))
+ server.wait_for(path='/{}/favicon.png'.format(test_path))
# Discard all requests that were necessary to display the page
- httpbin.clear_data()
+ server.clear_data()
quteproc.send_cmd(':download --mhtml --dest "{}"'.format(download_dest))
quteproc.wait_for(category='downloads',
message='File successfully written.')
@@ -136,4 +136,4 @@ def test_mhtml(request, test_name, download_dir, quteproc, httpbin):
download_dir.sanity_check_mhtml()
if not request.config.webengine:
- _test_mhtml_requests(test_dir, test_path, httpbin)
+ _test_mhtml_requests(test_dir, test_path, server)