aboutsummaryrefslogtreecommitdiffstats
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/conftest.py124
-rw-r--r--test/filename_matching.py57
-rw-r--r--test/full_coverage_plugin.py121
-rw-r--r--test/helper_tools/1024example (renamed from test/mitmproxy/tools/1024example)0
-rw-r--r--test/helper_tools/ab.exe (renamed from test/mitmproxy/tools/ab.exe)bin82944 -> 82944 bytes
-rw-r--r--test/helper_tools/bench.py (renamed from test/mitmproxy/tools/bench.py)0
-rw-r--r--test/helper_tools/benchtool.py (renamed from test/mitmproxy/tools/benchtool.py)0
-rwxr-xr-xtest/helper_tools/dumperview.py (renamed from test/mitmproxy/addons/dumperview.py)0
-rw-r--r--test/helper_tools/getcert (renamed from test/mitmproxy/tools/getcert)0
-rw-r--r--test/helper_tools/inspect_dumpfile.py (renamed from test/mitmproxy/tools/inspect_dumpfile.py)0
-rw-r--r--test/helper_tools/memoryleak.py (renamed from test/mitmproxy/tools/memoryleak.py)0
-rw-r--r--test/helper_tools/passive_close.py (renamed from test/mitmproxy/tools/passive_close.py)0
-rw-r--r--test/helper_tools/testpatt (renamed from test/mitmproxy/tools/testpatt)0
-rw-r--r--test/individual_coverage.py82
-rw-r--r--test/mitmproxy/__init__.py1
-rw-r--r--test/mitmproxy/addons/onboardingapp/test_app.py1
-rw-r--r--test/mitmproxy/addons/test_eventstore.py (renamed from test/mitmproxy/addons/test_evenstore.py)0
-rw-r--r--test/mitmproxy/addons/test_proxyauth.py50
-rw-r--r--test/mitmproxy/contentviews/image/__init__.py (renamed from test/mitmproxy/console/__init__.py)0
-rw-r--r--test/mitmproxy/contentviews/image/test_image_parser.py (renamed from test/mitmproxy/contentviews/test_image_parser.py)6
-rw-r--r--test/mitmproxy/contentviews/image/test_view.py (renamed from test/mitmproxy/contentviews/test_image.py)10
-rw-r--r--test/mitmproxy/contentviews/test_auto.py12
-rw-r--r--test/mitmproxy/contentviews/test_base.py1
-rw-r--r--test/mitmproxy/contentviews/test_protobuf.py52
-rw-r--r--test/mitmproxy/contentviews/test_wbxml.py1
-rw-r--r--test/mitmproxy/contrib/test_tnetstring.py (renamed from test/mitmproxy/test_contrib_tnetstring.py)0
-rw-r--r--test/mitmproxy/mock_urwid.py11
-rw-r--r--test/mitmproxy/net/http/test_request.py47
-rw-r--r--test/mitmproxy/net/http/test_url.py20
-rw-r--r--test/mitmproxy/platform/test_pf.py (renamed from test/mitmproxy/test_platform_pf.py)0
-rw-r--r--test/mitmproxy/proxy/__init__.py (renamed from test/mitmproxy/protocol/__init__.py)0
-rw-r--r--test/mitmproxy/proxy/modes/test_http_proxy.py1
-rw-r--r--test/mitmproxy/proxy/modes/test_reverse_proxy.py1
-rw-r--r--test/mitmproxy/proxy/modes/test_socks_proxy.py1
-rw-r--r--test/mitmproxy/proxy/modes/test_transparent_proxy.py1
-rw-r--r--test/mitmproxy/proxy/protocol/__init__.py0
-rw-r--r--test/mitmproxy/proxy/protocol/test_base.py1
-rw-r--r--test/mitmproxy/proxy/protocol/test_http.py1
-rw-r--r--test/mitmproxy/proxy/protocol/test_http1.py (renamed from test/mitmproxy/protocol/test_http1.py)2
-rw-r--r--test/mitmproxy/proxy/protocol/test_http2.py (renamed from test/mitmproxy/protocol/test_http2.py)150
-rw-r--r--test/mitmproxy/proxy/protocol/test_http_replay.py1
-rw-r--r--test/mitmproxy/proxy/protocol/test_rawtcp.py1
-rw-r--r--test/mitmproxy/proxy/protocol/test_tls.py (renamed from test/mitmproxy/protocol/test_tls.py)0
-rw-r--r--test/mitmproxy/proxy/protocol/test_websocket.py (renamed from test/mitmproxy/protocol/test_websocket.py)10
-rw-r--r--test/mitmproxy/proxy/test_config.py (renamed from test/mitmproxy/test_proxy_config.py)0
-rw-r--r--test/mitmproxy/proxy/test_root_context.py1
-rw-r--r--test/mitmproxy/proxy/test_server.py (renamed from test/mitmproxy/test_server.py)4
-rw-r--r--test/mitmproxy/test_connections.py1
-rw-r--r--test/mitmproxy/test_ctx.py1
-rw-r--r--test/mitmproxy/test_exceptions.py1
-rw-r--r--test/mitmproxy/test_export.py (renamed from test/mitmproxy/test_flow_export.py)0
-rw-r--r--test/mitmproxy/test_flow.py112
-rw-r--r--test/mitmproxy/test_http.py1
-rw-r--r--test/mitmproxy/test_io.py1
-rw-r--r--test/mitmproxy/test_io_compat.py (renamed from test/mitmproxy/test_flow_format_compat.py)0
-rw-r--r--test/mitmproxy/test_log.py1
-rw-r--r--test/mitmproxy/test_master.py1
-rw-r--r--test/mitmproxy/test_options.py1
-rw-r--r--test/mitmproxy/test_tcp.py59
-rw-r--r--test/mitmproxy/test_websocket.py62
-rw-r--r--test/mitmproxy/tools/__init__.py0
-rw-r--r--test/mitmproxy/tools/console/__init__.py0
-rw-r--r--test/mitmproxy/tools/console/test_common.py (renamed from test/mitmproxy/console/test_common.py)2
-rw-r--r--test/mitmproxy/tools/console/test_help.py (renamed from test/mitmproxy/console/test_help.py)2
-rw-r--r--test/mitmproxy/tools/console/test_master.py (renamed from test/mitmproxy/console/test_master.py)10
-rw-r--r--test/mitmproxy/tools/console/test_palettes.py (renamed from test/mitmproxy/console/test_palettes.py)2
-rw-r--r--test/mitmproxy/tools/console/test_pathedit.py (renamed from test/mitmproxy/console/test_pathedit.py)0
-rw-r--r--test/mitmproxy/tools/test_cmdline.py (renamed from test/mitmproxy/test_cmdline.py)0
-rw-r--r--test/mitmproxy/tools/test_dump.py (renamed from test/mitmproxy/test_tools_dump.py)2
-rw-r--r--test/mitmproxy/tools/web/__init__.py0
-rw-r--r--test/mitmproxy/tools/web/test_app.py (renamed from test/mitmproxy/test_web_app.py)0
-rw-r--r--test/mitmproxy/tools/web/test_master.py (renamed from test/mitmproxy/test_web_master.py)2
-rw-r--r--test/mitmproxy/utils/test_bits.py1
-rw-r--r--test/mitmproxy/utils/test_debug.py11
-rw-r--r--test/pathod/language/__init__.py0
-rw-r--r--test/pathod/language/test_actions.py (renamed from test/pathod/test_language_actions.py)0
-rw-r--r--test/pathod/language/test_base.py (renamed from test/pathod/test_language_base.py)0
-rw-r--r--test/pathod/language/test_exceptions.py1
-rw-r--r--test/pathod/language/test_generators.py (renamed from test/pathod/test_language_generators.py)0
-rw-r--r--test/pathod/language/test_http.py (renamed from test/pathod/test_language_http.py)2
-rw-r--r--test/pathod/language/test_http2.py (renamed from test/pathod/test_language_http2.py)0
-rw-r--r--test/pathod/language/test_message.py1
-rw-r--r--test/pathod/language/test_websockets.py (renamed from test/pathod/test_language_websocket.py)2
-rw-r--r--test/pathod/language/test_writer.py (renamed from test/pathod/test_language_writer.py)0
-rw-r--r--test/pathod/protocols/__init__.py0
-rw-r--r--test/pathod/protocols/test_http.py1
-rw-r--r--test/pathod/protocols/test_http2.py (renamed from test/pathod/test_protocols_http2.py)4
-rw-r--r--test/pathod/protocols/test_websockets.py1
88 files changed, 677 insertions, 379 deletions
diff --git a/test/conftest.py b/test/conftest.py
index 83823a19..b4e1da93 100644
--- a/test/conftest.py
+++ b/test/conftest.py
@@ -6,6 +6,7 @@ from contextlib import contextmanager
import mitmproxy.net.tcp
+pytest_plugins = ('test.full_coverage_plugin',)
requires_alpn = pytest.mark.skipif(
not mitmproxy.net.tcp.HAS_ALPN,
@@ -27,10 +28,17 @@ skip_appveyor = pytest.mark.skipif(
)
-original_pytest_raises = pytest.raises
+@pytest.fixture()
+def disable_alpn(monkeypatch):
+ monkeypatch.setattr(mitmproxy.net.tcp, 'HAS_ALPN', False)
+ monkeypatch.setattr(OpenSSL.SSL._lib, 'Cryptography_HAS_ALPN', False)
+################################################################################
# TODO: remove this wrapper when pytest 3.1.0 is released
+original_pytest_raises = pytest.raises
+
+
@contextmanager
@functools.wraps(original_pytest_raises)
def raises(exc, *args, **kwargs):
@@ -41,116 +49,4 @@ def raises(exc, *args, **kwargs):
pytest.raises = raises
-
-
-@pytest.fixture()
-def disable_alpn(monkeypatch):
- monkeypatch.setattr(mitmproxy.net.tcp, 'HAS_ALPN', False)
- monkeypatch.setattr(OpenSSL.SSL._lib, 'Cryptography_HAS_ALPN', False)
-
-
-enable_coverage = False
-coverage_values = []
-coverage_passed = False
-
-
-def pytest_addoption(parser):
- parser.addoption('--full-cov',
- action='append',
- dest='full_cov',
- default=[],
- help="Require full test coverage of 100%% for this module/path/filename (multi-allowed). Default: none")
-
- parser.addoption('--no-full-cov',
- action='append',
- dest='no_full_cov',
- default=[],
- help="Exclude file from a parent 100%% coverage requirement (multi-allowed). Default: none")
-
-
-def pytest_configure(config):
- global enable_coverage
- enable_coverage = (
- len(config.getoption('file_or_dir')) == 0 and
- len(config.getoption('full_cov')) > 0 and
- config.pluginmanager.getplugin("_cov") is not None and
- config.pluginmanager.getplugin("_cov").cov_controller is not None and
- config.pluginmanager.getplugin("_cov").cov_controller.cov is not None
- )
-
-
-@pytest.hookimpl(hookwrapper=True)
-def pytest_runtestloop(session):
- global enable_coverage
- global coverage_values
- global coverage_passed
-
- if not enable_coverage:
- yield
- return
-
- cov = pytest.config.pluginmanager.getplugin("_cov").cov_controller.cov
-
- if os.name == 'nt':
- cov.exclude('pragma: windows no cover')
-
- yield
-
- coverage_values = dict([(name, 0) for name in pytest.config.option.full_cov])
-
- prefix = os.getcwd()
- excluded_files = [os.path.normpath(f) for f in pytest.config.option.no_full_cov]
- measured_files = [os.path.normpath(os.path.relpath(f, prefix)) for f in cov.get_data().measured_files()]
- measured_files = [f for f in measured_files if not any(f.startswith(excluded_f) for excluded_f in excluded_files)]
-
- for name in coverage_values.keys():
- files = [f for f in measured_files if f.startswith(os.path.normpath(name))]
- try:
- with open(os.devnull, 'w') as null:
- overall = cov.report(files, ignore_errors=True, file=null)
- singles = [(s, cov.report(s, ignore_errors=True, file=null)) for s in files]
- coverage_values[name] = (overall, singles)
- except:
- pass
-
- if any(v < 100 for v, _ in coverage_values.values()):
- # make sure we get the EXIT_TESTSFAILED exit code
- session.testsfailed += 1
- else:
- coverage_passed = True
-
-
-def pytest_terminal_summary(terminalreporter, exitstatus):
- global enable_coverage
- global coverage_values
- global coverage_passed
-
- if not enable_coverage:
- return
-
- terminalreporter.write('\n')
- if not coverage_passed:
- markup = {'red': True, 'bold': True}
- msg = "FAIL: Full test coverage not reached!\n"
- terminalreporter.write(msg, **markup)
-
- for name in sorted(coverage_values.keys()):
- msg = 'Coverage for {}: {:.2f}%\n'.format(name, coverage_values[name][0])
- if coverage_values[name][0] < 100:
- markup = {'red': True, 'bold': True}
- for s, v in sorted(coverage_values[name][1]):
- if v < 100:
- msg += ' {}: {:.2f}%\n'.format(s, v)
- else:
- markup = {'green': True}
- terminalreporter.write(msg, **markup)
- else:
- markup = {'green': True}
- msg = 'SUCCESS: Full test coverage reached in modules and files:\n'
- msg += '{}\n\n'.format('\n'.join(pytest.config.option.full_cov))
- terminalreporter.write(msg, **markup)
-
- msg = '\nExcluded files:\n'
- for s in sorted(pytest.config.option.no_full_cov):
- msg += " {}\n".format(s)
- terminalreporter.write(msg)
+################################################################################
diff --git a/test/filename_matching.py b/test/filename_matching.py
new file mode 100644
index 00000000..51cedf03
--- /dev/null
+++ b/test/filename_matching.py
@@ -0,0 +1,57 @@
+import os
+import re
+import glob
+import sys
+
+
+def check_src_files_have_test():
+ missing_test_files = []
+
+ excluded = ['mitmproxy/contrib/', 'mitmproxy/test/', 'mitmproxy/tools/', 'mitmproxy/platform/']
+ src_files = glob.glob('mitmproxy/**/*.py', recursive=True) + glob.glob('pathod/**/*.py', recursive=True)
+ src_files = [f for f in src_files if os.path.basename(f) != '__init__.py']
+ src_files = [f for f in src_files if not any(os.path.normpath(p) in f for p in excluded)]
+ for f in src_files:
+ p = os.path.join("test", os.path.dirname(f), "test_" + os.path.basename(f))
+ if not os.path.isfile(p):
+ missing_test_files.append((f, p))
+
+ return missing_test_files
+
+
+def check_test_files_have_src():
+ unknown_test_files = []
+
+ excluded = ['test/mitmproxy/data/', 'test/mitmproxy/net/data/', '/tservers.py']
+ test_files = glob.glob('test/mitmproxy/**/*.py', recursive=True) + glob.glob('test/pathod/**/*.py', recursive=True)
+ test_files = [f for f in test_files if os.path.basename(f) != '__init__.py']
+ test_files = [f for f in test_files if not any(os.path.normpath(p) in f for p in excluded)]
+ for f in test_files:
+ p = os.path.join(re.sub('^test/', '', os.path.dirname(f)), re.sub('^test_', '', os.path.basename(f)))
+ if not os.path.isfile(p):
+ unknown_test_files.append((f, p))
+
+ return unknown_test_files
+
+
+def main():
+ exitcode = 0
+
+ missing_test_files = check_src_files_have_test()
+ if missing_test_files:
+ exitcode += 1
+ for f, p in sorted(missing_test_files):
+ print("{} MUST have a matching test file: {}".format(f, p))
+
+ unknown_test_files = check_test_files_have_src()
+ if unknown_test_files:
+ # TODO: enable this in the future
+ # exitcode += 1
+ for f, p in sorted(unknown_test_files):
+ print("{} DOES NOT MATCH a source file! Expected to find: {}".format(f, p))
+
+ sys.exit(exitcode)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/test/full_coverage_plugin.py b/test/full_coverage_plugin.py
new file mode 100644
index 00000000..d98c29d6
--- /dev/null
+++ b/test/full_coverage_plugin.py
@@ -0,0 +1,121 @@
+import os
+import configparser
+import pytest
+
+here = os.path.abspath(os.path.dirname(__file__))
+
+
+enable_coverage = False
+coverage_values = []
+coverage_passed = True
+no_full_cov = []
+
+
+def pytest_addoption(parser):
+ parser.addoption('--full-cov',
+ action='append',
+ dest='full_cov',
+ default=[],
+ help="Require full test coverage of 100%% for this module/path/filename (multi-allowed). Default: none")
+
+ parser.addoption('--no-full-cov',
+ action='append',
+ dest='no_full_cov',
+ default=[],
+ help="Exclude file from a parent 100%% coverage requirement (multi-allowed). Default: none")
+
+
+def pytest_configure(config):
+ global enable_coverage
+ global no_full_cov
+
+ enable_coverage = (
+ len(config.getoption('file_or_dir')) == 0 and
+ len(config.getoption('full_cov')) > 0 and
+ config.pluginmanager.getplugin("_cov") is not None and
+ config.pluginmanager.getplugin("_cov").cov_controller is not None and
+ config.pluginmanager.getplugin("_cov").cov_controller.cov is not None
+ )
+
+ c = configparser.ConfigParser()
+ c.read(os.path.join(here, "..", "setup.cfg"))
+ fs = c['tool:full_coverage']['exclude'].split('\n')
+ no_full_cov = config.option.no_full_cov + [f.strip() for f in fs]
+
+
+@pytest.hookimpl(hookwrapper=True)
+def pytest_runtestloop(session):
+ global enable_coverage
+ global coverage_values
+ global coverage_passed
+ global no_full_cov
+
+ if not enable_coverage:
+ yield
+ return
+
+ cov = pytest.config.pluginmanager.getplugin("_cov").cov_controller.cov
+
+ if os.name == 'nt':
+ cov.exclude('pragma: windows no cover')
+
+ yield
+
+ coverage_values = dict([(name, 0) for name in pytest.config.option.full_cov])
+
+ prefix = os.getcwd()
+
+ excluded_files = [os.path.normpath(f) for f in no_full_cov]
+ measured_files = [os.path.normpath(os.path.relpath(f, prefix)) for f in cov.get_data().measured_files()]
+ measured_files = [f for f in measured_files if not any(f.startswith(excluded_f) for excluded_f in excluded_files)]
+
+ for name in coverage_values.keys():
+ files = [f for f in measured_files if f.startswith(os.path.normpath(name))]
+ try:
+ with open(os.devnull, 'w') as null:
+ overall = cov.report(files, ignore_errors=True, file=null)
+ singles = [(s, cov.report(s, ignore_errors=True, file=null)) for s in files]
+ coverage_values[name] = (overall, singles)
+ except:
+ pass
+
+ if any(v < 100 for v, _ in coverage_values.values()):
+ # make sure we get the EXIT_TESTSFAILED exit code
+ session.testsfailed += 1
+ coverage_passed = False
+
+
+def pytest_terminal_summary(terminalreporter, exitstatus):
+ global enable_coverage
+ global coverage_values
+ global coverage_passed
+ global no_full_cov
+
+ if not enable_coverage:
+ return
+
+ terminalreporter.write('\n')
+ if not coverage_passed:
+ markup = {'red': True, 'bold': True}
+ msg = "FAIL: Full test coverage not reached!\n"
+ terminalreporter.write(msg, **markup)
+
+ for name in sorted(coverage_values.keys()):
+ msg = 'Coverage for {}: {:.2f}%\n'.format(name, coverage_values[name][0])
+ if coverage_values[name][0] < 100:
+ markup = {'red': True, 'bold': True}
+ for s, v in sorted(coverage_values[name][1]):
+ if v < 100:
+ msg += ' {}: {:.2f}%\n'.format(s, v)
+ else:
+ markup = {'green': True}
+ terminalreporter.write(msg, **markup)
+ else:
+ msg = 'SUCCESS: Full test coverage reached in modules and files:\n'
+ msg += '{}\n\n'.format('\n'.join(pytest.config.option.full_cov))
+ terminalreporter.write(msg, green=True)
+
+ msg = '\nExcluded files:\n'
+ for s in sorted(no_full_cov):
+ msg += " {}\n".format(s)
+ terminalreporter.write(msg)
diff --git a/test/mitmproxy/tools/1024example b/test/helper_tools/1024example
index 78af7ed0..78af7ed0 100644
--- a/test/mitmproxy/tools/1024example
+++ b/test/helper_tools/1024example
diff --git a/test/mitmproxy/tools/ab.exe b/test/helper_tools/ab.exe
index d68ed0f3..d68ed0f3 100644
--- a/test/mitmproxy/tools/ab.exe
+++ b/test/helper_tools/ab.exe
Binary files differ
diff --git a/test/mitmproxy/tools/bench.py b/test/helper_tools/bench.py
index fb75ef46..fb75ef46 100644
--- a/test/mitmproxy/tools/bench.py
+++ b/test/helper_tools/bench.py
diff --git a/test/mitmproxy/tools/benchtool.py b/test/helper_tools/benchtool.py
index b9078d0e..b9078d0e 100644
--- a/test/mitmproxy/tools/benchtool.py
+++ b/test/helper_tools/benchtool.py
diff --git a/test/mitmproxy/addons/dumperview.py b/test/helper_tools/dumperview.py
index be56fe14..be56fe14 100755
--- a/test/mitmproxy/addons/dumperview.py
+++ b/test/helper_tools/dumperview.py
diff --git a/test/mitmproxy/tools/getcert b/test/helper_tools/getcert
index 43ebf11d..43ebf11d 100644
--- a/test/mitmproxy/tools/getcert
+++ b/test/helper_tools/getcert
diff --git a/test/mitmproxy/tools/inspect_dumpfile.py b/test/helper_tools/inspect_dumpfile.py
index b2201f40..b2201f40 100644
--- a/test/mitmproxy/tools/inspect_dumpfile.py
+++ b/test/helper_tools/inspect_dumpfile.py
diff --git a/test/mitmproxy/tools/memoryleak.py b/test/helper_tools/memoryleak.py
index c03230da..c03230da 100644
--- a/test/mitmproxy/tools/memoryleak.py
+++ b/test/helper_tools/memoryleak.py
diff --git a/test/mitmproxy/tools/passive_close.py b/test/helper_tools/passive_close.py
index 6f97ea4f..6f97ea4f 100644
--- a/test/mitmproxy/tools/passive_close.py
+++ b/test/helper_tools/passive_close.py
diff --git a/test/mitmproxy/tools/testpatt b/test/helper_tools/testpatt
index b41011c0..b41011c0 100644
--- a/test/mitmproxy/tools/testpatt
+++ b/test/helper_tools/testpatt
diff --git a/test/individual_coverage.py b/test/individual_coverage.py
new file mode 100644
index 00000000..35bcd27f
--- /dev/null
+++ b/test/individual_coverage.py
@@ -0,0 +1,82 @@
+import io
+import contextlib
+import os
+import sys
+import glob
+import multiprocessing
+import configparser
+import itertools
+import pytest
+
+
+def run_tests(src, test, fail):
+ stderr = io.StringIO()
+ stdout = io.StringIO()
+ with contextlib.redirect_stderr(stderr):
+ with contextlib.redirect_stdout(stdout):
+ e = pytest.main([
+ '-qq',
+ '--disable-pytest-warnings',
+ '--no-faulthandler',
+ '--cov', src.replace('.py', '').replace('/', '.'),
+ '--cov-fail-under', '100',
+ '--cov-report', 'term-missing:skip-covered',
+ test
+ ])
+
+ if e == 0:
+ if fail:
+ print("SUCCESS but should have FAILED:", src, "Please remove this file from setup.cfg tool:individual_coverage/exclude.")
+ e = 42
+ else:
+ print("SUCCESS:", src)
+ else:
+ if fail:
+ print("Ignoring fail:", src)
+ e = 0
+ else:
+ cov = [l for l in stdout.getvalue().split("\n") if (src in l) or ("was never imported" in l)]
+ if len(cov) == 1:
+ print("FAIL:", cov[0])
+ else:
+ print("FAIL:", src, test, stdout.getvalue(), stdout.getvalue())
+ print(stderr.getvalue())
+ print(stdout.getvalue())
+
+ sys.exit(e)
+
+
+def start_pytest(src, test, fail):
+ # run pytest in a new process, otherwise imports and modules might conflict
+ proc = multiprocessing.Process(target=run_tests, args=(src, test, fail))
+ proc.start()
+ proc.join()
+ return (src, test, proc.exitcode)
+
+
+def main():
+ c = configparser.ConfigParser()
+ c.read('setup.cfg')
+ fs = c['tool:individual_coverage']['exclude'].strip().split('\n')
+ no_individual_cov = [f.strip() for f in fs]
+
+ excluded = ['mitmproxy/contrib/', 'mitmproxy/test/', 'mitmproxy/tools/', 'mitmproxy/platform/']
+ src_files = glob.glob('mitmproxy/**/*.py', recursive=True) + glob.glob('pathod/**/*.py', recursive=True)
+ src_files = [f for f in src_files if os.path.basename(f) != '__init__.py']
+ src_files = [f for f in src_files if not any(os.path.normpath(p) in f for p in excluded)]
+
+ ps = []
+ for src in sorted(src_files):
+ test = os.path.join("test", os.path.dirname(src), "test_" + os.path.basename(src))
+ if os.path.isfile(test):
+ ps.append((src, test, src in no_individual_cov))
+
+ result = list(itertools.starmap(start_pytest, ps))
+
+ if any(e != 0 for _, _, e in result):
+ sys.exit(1)
+ pass
+
+
+if __name__ == '__main__':
+ main()
diff --git a/test/mitmproxy/__init__.py b/test/mitmproxy/__init__.py
index 28dc133f..6f114e18 100644
--- a/test/mitmproxy/__init__.py
+++ b/test/mitmproxy/__init__.py
@@ -3,5 +3,4 @@ import logging
logging.getLogger("hyper").setLevel(logging.WARNING)
logging.getLogger("requests").setLevel(logging.WARNING)
logging.getLogger("passlib").setLevel(logging.WARNING)
-logging.getLogger("PIL").setLevel(logging.WARNING)
logging.getLogger("tornado").setLevel(logging.WARNING)
diff --git a/test/mitmproxy/addons/onboardingapp/test_app.py b/test/mitmproxy/addons/onboardingapp/test_app.py
new file mode 100644
index 00000000..777ab4dd
--- /dev/null
+++ b/test/mitmproxy/addons/onboardingapp/test_app.py
@@ -0,0 +1 @@
+# TODO: write tests
diff --git a/test/mitmproxy/addons/test_evenstore.py b/test/mitmproxy/addons/test_eventstore.py
index f54b9980..f54b9980 100644
--- a/test/mitmproxy/addons/test_evenstore.py
+++ b/test/mitmproxy/addons/test_eventstore.py
diff --git a/test/mitmproxy/addons/test_proxyauth.py b/test/mitmproxy/addons/test_proxyauth.py
index b59b87c1..dd5829ab 100644
--- a/test/mitmproxy/addons/test_proxyauth.py
+++ b/test/mitmproxy/addons/test_proxyauth.py
@@ -1,21 +1,27 @@
import binascii
+
import pytest
from mitmproxy import exceptions
+from mitmproxy.addons import proxyauth
from mitmproxy.test import taddons
from mitmproxy.test import tflow
from mitmproxy.test import tutils
-from mitmproxy.addons import proxyauth
def test_parse_http_basic_auth():
assert proxyauth.parse_http_basic_auth(
proxyauth.mkauth("test", "test")
) == ("basic", "test", "test")
- assert not proxyauth.parse_http_basic_auth("")
- assert not proxyauth.parse_http_basic_auth("foo bar")
- v = "basic " + binascii.b2a_base64(b"foo").decode("ascii")
- assert not proxyauth.parse_http_basic_auth(v)
+ with pytest.raises(ValueError):
+ proxyauth.parse_http_basic_auth("")
+ with pytest.raises(ValueError):
+ proxyauth.parse_http_basic_auth("foo bar")
+ with pytest.raises(ValueError):
+ proxyauth.parse_http_basic_auth("basic abc")
+ with pytest.raises(ValueError):
+ v = "basic " + binascii.b2a_base64(b"foo").decode("ascii")
+ proxyauth.parse_http_basic_auth(v)
def test_configure():
@@ -42,14 +48,14 @@ def test_configure():
ctx.configure(
up,
- auth_htpasswd = tutils.test_data.path(
+ auth_htpasswd=tutils.test_data.path(
"mitmproxy/net/data/htpasswd"
)
)
assert up.htpasswd
assert up.htpasswd.check_password("test", "test")
assert not up.htpasswd.check_password("test", "foo")
- ctx.configure(up, auth_htpasswd = None)
+ ctx.configure(up, auth_htpasswd=None)
assert not up.htpasswd
with pytest.raises(exceptions.OptionsError):
@@ -57,11 +63,14 @@ def test_configure():
with pytest.raises(exceptions.OptionsError):
ctx.configure(up, auth_nonanonymous=True, mode="socks5")
+ ctx.configure(up, mode="regular")
+ assert up.mode == "regular"
+
def test_check():
up = proxyauth.ProxyAuth()
with taddons.context() as ctx:
- ctx.configure(up, auth_nonanonymous=True)
+ ctx.configure(up, auth_nonanonymous=True, mode="regular")
f = tflow.tflow()
assert not up.check(f)
f.request.headers["Proxy-Authorization"] = proxyauth.mkauth(
@@ -73,7 +82,7 @@ def test_check():
assert not up.check(f)
f.request.headers["Proxy-Authorization"] = proxyauth.mkauth(
- "test", "test", scheme = "unknown"
+ "test", "test", scheme="unknown"
)
assert not up.check(f)
@@ -87,8 +96,8 @@ def test_check():
ctx.configure(
up,
- auth_singleuser = None,
- auth_htpasswd = tutils.test_data.path(
+ auth_singleuser=None,
+ auth_htpasswd=tutils.test_data.path(
"mitmproxy/net/data/htpasswd"
)
)
@@ -105,7 +114,7 @@ def test_check():
def test_authenticate():
up = proxyauth.ProxyAuth()
with taddons.context() as ctx:
- ctx.configure(up, auth_nonanonymous=True)
+ ctx.configure(up, auth_nonanonymous=True, mode="regular")
f = tflow.tflow()
assert not f.response
@@ -121,13 +130,12 @@ def test_authenticate():
assert not f.request.headers.get("Proxy-Authorization")
f = tflow.tflow()
- f.mode = "transparent"
+ ctx.configure(up, mode="reverse")
assert not f.response
up.authenticate(f)
assert f.response.status_code == 401
f = tflow.tflow()
- f.mode = "transparent"
f.request.headers["Authorization"] = proxyauth.mkauth(
"test", "test"
)
@@ -139,7 +147,7 @@ def test_authenticate():
def test_handlers():
up = proxyauth.ProxyAuth()
with taddons.context() as ctx:
- ctx.configure(up, auth_nonanonymous=True)
+ ctx.configure(up, auth_nonanonymous=True, mode="regular")
f = tflow.tflow()
assert not f.response
@@ -151,3 +159,15 @@ def test_handlers():
assert not f.response
up.http_connect(f)
assert f.response.status_code == 407
+
+ f = tflow.tflow()
+ f.request.method = "CONNECT"
+ f.request.headers["Proxy-Authorization"] = proxyauth.mkauth(
+ "test", "test"
+ )
+ up.http_connect(f)
+ assert not f.response
+
+ f2 = tflow.tflow(client_conn=f.client_conn)
+ up.requestheaders(f2)
+ assert not f2.response
diff --git a/test/mitmproxy/console/__init__.py b/test/mitmproxy/contentviews/image/__init__.py
index e69de29b..e69de29b 100644
--- a/test/mitmproxy/console/__init__.py
+++ b/test/mitmproxy/contentviews/image/__init__.py
diff --git a/test/mitmproxy/contentviews/test_image_parser.py b/test/mitmproxy/contentviews/image/test_image_parser.py
index 3c8bfdf7..3cb44ca6 100644
--- a/test/mitmproxy/contentviews/test_image_parser.py
+++ b/test/mitmproxy/contentviews/image/test_image_parser.py
@@ -80,7 +80,7 @@ def test_parse_png(filename, metadata):
# check comment
"mitmproxy/data/image_parser/hopper.gif": [
('Format', 'Compuserve GIF'),
- ('version', 'GIF89a'),
+ ('Version', 'GIF89a'),
('Size', '128 x 128 px'),
('background', '0'),
('comment', "b'File written by Adobe Photoshop\\xa8 4.0'")
@@ -88,7 +88,7 @@ def test_parse_png(filename, metadata):
# check background
"mitmproxy/data/image_parser/chi.gif": [
('Format', 'Compuserve GIF'),
- ('version', 'GIF89a'),
+ ('Version', 'GIF89a'),
('Size', '320 x 240 px'),
('background', '248'),
('comment', "b'Created with GIMP'")
@@ -96,7 +96,7 @@ def test_parse_png(filename, metadata):
# check working with color table
"mitmproxy/data/image_parser/iss634.gif": [
('Format', 'Compuserve GIF'),
- ('version', 'GIF89a'),
+ ('Version', 'GIF89a'),
('Size', '245 x 245 px'),
('background', '0')
],
diff --git a/test/mitmproxy/contentviews/test_image.py b/test/mitmproxy/contentviews/image/test_view.py
index e3dfb714..34f655a1 100644
--- a/test/mitmproxy/contentviews/test_image.py
+++ b/test/mitmproxy/contentviews/image/test_view.py
@@ -1,6 +1,6 @@
from mitmproxy.contentviews import image
from mitmproxy.test import tutils
-from . import full_eval
+from .. import full_eval
def test_view_image():
@@ -9,9 +9,11 @@ def test_view_image():
"mitmproxy/data/image.png",
"mitmproxy/data/image.gif",
"mitmproxy/data/all.jpeg",
- "mitmproxy/data/image.ico"
+ # https://bugs.python.org/issue21574
+ # "mitmproxy/data/image.ico",
]:
with open(tutils.test_data.path(img), "rb") as f:
- assert v(f.read())
+ viewname, lines = v(f.read())
+ assert img.split(".")[-1].upper() in viewname
- assert not v(b"flibble")
+ assert v(b"flibble") == ('Unknown Image', [[('header', 'Image Format: '), ('text', 'unknown')]])
diff --git a/test/mitmproxy/contentviews/test_auto.py b/test/mitmproxy/contentviews/test_auto.py
index a077affa..2ff43139 100644
--- a/test/mitmproxy/contentviews/test_auto.py
+++ b/test/mitmproxy/contentviews/test_auto.py
@@ -30,6 +30,18 @@ def test_view_auto():
)
assert f[0].startswith("XML")
+ f = v(
+ b"<svg></svg>",
+ headers=http.Headers(content_type="image/svg+xml")
+ )
+ assert f[0].startswith("XML")
+
+ f = v(
+ b"verybinary",
+ headers=http.Headers(content_type="image/new-magic-image-format")
+ )
+ assert f[0] == "Unknown Image"
+
f = v(b"\xFF" * 30)
assert f[0] == "Hex"
diff --git a/test/mitmproxy/contentviews/test_base.py b/test/mitmproxy/contentviews/test_base.py
new file mode 100644
index 00000000..777ab4dd
--- /dev/null
+++ b/test/mitmproxy/contentviews/test_base.py
@@ -0,0 +1 @@
+# TODO: write tests
diff --git a/test/mitmproxy/contentviews/test_protobuf.py b/test/mitmproxy/contentviews/test_protobuf.py
index 1224b8db..31e382ec 100644
--- a/test/mitmproxy/contentviews/test_protobuf.py
+++ b/test/mitmproxy/contentviews/test_protobuf.py
@@ -1,12 +1,50 @@
+from unittest import mock
+import pytest
+
from mitmproxy.contentviews import protobuf
from mitmproxy.test import tutils
from . import full_eval
-if protobuf.ViewProtobuf.is_available():
- def test_view_protobuf_request():
- v = full_eval(protobuf.ViewProtobuf())
- p = tutils.test_data.path("mitmproxy/data/protobuf01")
- content_type, output = v(open(p, "rb").read())
- assert content_type == "Protobuf"
- assert output.next()[0][1] == '1: "3bbc333c-e61c-433b-819a-0b9a8cc103b8"'
+def test_view_protobuf_request():
+ v = full_eval(protobuf.ViewProtobuf())
+ p = tutils.test_data.path("mitmproxy/data/protobuf01")
+
+ with mock.patch('mitmproxy.contentviews.protobuf.ViewProtobuf.is_available'):
+ with mock.patch('subprocess.Popen') as n:
+ m = mock.Mock()
+ attrs = {'communicate.return_value': (b'1: "3bbc333c-e61c-433b-819a-0b9a8cc103b8"', True)}
+ m.configure_mock(**attrs)
+ n.return_value = m
+
+ content_type, output = v(open(p, "rb").read())
+ assert content_type == "Protobuf"
+ assert output[0] == [('text', b'1: "3bbc333c-e61c-433b-819a-0b9a8cc103b8"')]
+
+ m.communicate = mock.MagicMock()
+ m.communicate.return_value = (None, None)
+ with pytest.raises(ValueError, matches="Failed to parse input."):
+ v(b'foobar')
+
+
+def test_view_protobuf_availability():
+ with mock.patch('subprocess.Popen') as n:
+ m = mock.Mock()
+ attrs = {'communicate.return_value': (b'libprotoc fake version', True)}
+ m.configure_mock(**attrs)
+ n.return_value = m
+ assert protobuf.ViewProtobuf().is_available()
+
+ m = mock.Mock()
+ attrs = {'communicate.return_value': (b'command not found', True)}
+ m.configure_mock(**attrs)
+ n.return_value = m
+ assert not protobuf.ViewProtobuf().is_available()
+
+
+def test_view_protobuf_fallback():
+ with mock.patch('subprocess.Popen.communicate') as m:
+ m.side_effect = OSError()
+ v = full_eval(protobuf.ViewProtobuf())
+ with pytest.raises(NotImplementedError, matches='protoc not found'):
+ v(b'foobar')
diff --git a/test/mitmproxy/contentviews/test_wbxml.py b/test/mitmproxy/contentviews/test_wbxml.py
new file mode 100644
index 00000000..777ab4dd
--- /dev/null
+++ b/test/mitmproxy/contentviews/test_wbxml.py
@@ -0,0 +1 @@
+# TODO: write tests
diff --git a/test/mitmproxy/test_contrib_tnetstring.py b/test/mitmproxy/contrib/test_tnetstring.py
index 05c4a7c9..05c4a7c9 100644
--- a/test/mitmproxy/test_contrib_tnetstring.py
+++ b/test/mitmproxy/contrib/test_tnetstring.py
diff --git a/test/mitmproxy/mock_urwid.py b/test/mitmproxy/mock_urwid.py
deleted file mode 100644
index 9cc41abc..00000000
--- a/test/mitmproxy/mock_urwid.py
+++ /dev/null
@@ -1,11 +0,0 @@
-import os
-import sys
-from unittest import mock
-
-if os.name == "nt":
- m = mock.Mock()
- m.__version__ = "1.1.1"
- m.Widget = mock.Mock
- m.WidgetWrap = mock.Mock
- sys.modules['urwid'] = m
- sys.modules['urwid.util'] = mock.Mock()
diff --git a/test/mitmproxy/net/http/test_request.py b/test/mitmproxy/net/http/test_request.py
index 6fe57010..90ec31fe 100644
--- a/test/mitmproxy/net/http/test_request.py
+++ b/test/mitmproxy/net/http/test_request.py
@@ -97,7 +97,7 @@ class TestRequestCore:
request.host = d
assert request.data.host == b"foo\xFF\x00bar"
- def test_host_header_update(self):
+ def test_host_update_also_updates_header(self):
request = treq()
assert "host" not in request.headers
request.host = "example.com"
@@ -107,6 +107,51 @@ class TestRequestCore:
request.host = "example.org"
assert request.headers["Host"] == "example.org"
+ def test_get_host_header(self):
+ no_hdr = treq()
+ assert no_hdr.host_header is None
+
+ h1 = treq(headers=(
+ (b"host", b"example.com"),
+ ))
+ assert h1.host_header == "example.com"
+
+ h2 = treq(headers=(
+ (b":authority", b"example.org"),
+ ))
+ assert h2.host_header == "example.org"
+
+ both_hdrs = treq(headers=(
+ (b"host", b"example.org"),
+ (b":authority", b"example.com"),
+ ))
+ assert both_hdrs.host_header == "example.com"
+
+ def test_modify_host_header(self):
+ h1 = treq()
+ assert "host" not in h1.headers
+ assert ":authority" not in h1.headers
+ h1.host_header = "example.com"
+ assert "host" in h1.headers
+ assert ":authority" not in h1.headers
+ h1.host_header = None
+ assert "host" not in h1.headers
+
+ h2 = treq(http_version=b"HTTP/2.0")
+ h2.host_header = "example.org"
+ assert "host" not in h2.headers
+ assert ":authority" in h2.headers
+ del h2.host_header
+ assert ":authority" not in h2.headers
+
+ both_hdrs = treq(headers=(
+ (b":authority", b"example.com"),
+ (b"host", b"example.org"),
+ ))
+ both_hdrs.host_header = "foo.example.com"
+ assert both_hdrs.headers["Host"] == "foo.example.com"
+ assert both_hdrs.headers[":authority"] == "foo.example.com"
+
class TestRequestUtils:
"""
diff --git a/test/mitmproxy/net/http/test_url.py b/test/mitmproxy/net/http/test_url.py
index 11ab1b81..2064aab8 100644
--- a/test/mitmproxy/net/http/test_url.py
+++ b/test/mitmproxy/net/http/test_url.py
@@ -85,6 +85,26 @@ surrogates_quoted = (
)
+def test_empty_key_trailing_equal_sign():
+ """
+ Some HTTP clients don't send trailing equal signs for parameters without assigned value, e.g. they send
+ foo=bar&baz&qux=quux
+ instead of
+ foo=bar&baz=&qux=quux
+ The respective behavior of encode() should be driven by a reference string given in similar_to parameter
+ """
+ reference_without_equal = "key1=val1&key2&key3=val3"
+ reference_with_equal = "key1=val1&key2=&key3=val3"
+
+ post_data_empty_key_middle = [('one', 'two'), ('emptykey', ''), ('three', 'four')]
+ post_data_empty_key_end = [('one', 'two'), ('three', 'four'), ('emptykey', '')]
+
+ assert url.encode(post_data_empty_key_middle, similar_to = reference_with_equal) == "one=two&emptykey=&three=four"
+ assert url.encode(post_data_empty_key_end, similar_to = reference_with_equal) == "one=two&three=four&emptykey="
+ assert url.encode(post_data_empty_key_middle, similar_to = reference_without_equal) == "one=two&emptykey&three=four"
+ assert url.encode(post_data_empty_key_end, similar_to = reference_without_equal) == "one=two&three=four&emptykey"
+
+
def test_encode():
assert url.encode([('foo', 'bar')])
assert url.encode([('foo', surrogates)])
diff --git a/test/mitmproxy/test_platform_pf.py b/test/mitmproxy/platform/test_pf.py
index f644bcc5..f644bcc5 100644
--- a/test/mitmproxy/test_platform_pf.py
+++ b/test/mitmproxy/platform/test_pf.py
diff --git a/test/mitmproxy/protocol/__init__.py b/test/mitmproxy/proxy/__init__.py
index e69de29b..e69de29b 100644
--- a/test/mitmproxy/protocol/__init__.py
+++ b/test/mitmproxy/proxy/__init__.py
diff --git a/test/mitmproxy/proxy/modes/test_http_proxy.py b/test/mitmproxy/proxy/modes/test_http_proxy.py
new file mode 100644
index 00000000..777ab4dd
--- /dev/null
+++ b/test/mitmproxy/proxy/modes/test_http_proxy.py
@@ -0,0 +1 @@
+# TODO: write tests
diff --git a/test/mitmproxy/proxy/modes/test_reverse_proxy.py b/test/mitmproxy/proxy/modes/test_reverse_proxy.py
new file mode 100644
index 00000000..777ab4dd
--- /dev/null
+++ b/test/mitmproxy/proxy/modes/test_reverse_proxy.py
@@ -0,0 +1 @@
+# TODO: write tests
diff --git a/test/mitmproxy/proxy/modes/test_socks_proxy.py b/test/mitmproxy/proxy/modes/test_socks_proxy.py
new file mode 100644
index 00000000..777ab4dd
--- /dev/null
+++ b/test/mitmproxy/proxy/modes/test_socks_proxy.py
@@ -0,0 +1 @@
+# TODO: write tests
diff --git a/test/mitmproxy/proxy/modes/test_transparent_proxy.py b/test/mitmproxy/proxy/modes/test_transparent_proxy.py
new file mode 100644
index 00000000..777ab4dd
--- /dev/null
+++ b/test/mitmproxy/proxy/modes/test_transparent_proxy.py
@@ -0,0 +1 @@
+# TODO: write tests
diff --git a/test/mitmproxy/proxy/protocol/__init__.py b/test/mitmproxy/proxy/protocol/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/mitmproxy/proxy/protocol/__init__.py
diff --git a/test/mitmproxy/proxy/protocol/test_base.py b/test/mitmproxy/proxy/protocol/test_base.py
new file mode 100644
index 00000000..777ab4dd
--- /dev/null
+++ b/test/mitmproxy/proxy/protocol/test_base.py
@@ -0,0 +1 @@
+# TODO: write tests
diff --git a/test/mitmproxy/proxy/protocol/test_http.py b/test/mitmproxy/proxy/protocol/test_http.py
new file mode 100644
index 00000000..777ab4dd
--- /dev/null
+++ b/test/mitmproxy/proxy/protocol/test_http.py
@@ -0,0 +1 @@
+# TODO: write tests
diff --git a/test/mitmproxy/protocol/test_http1.py b/test/mitmproxy/proxy/protocol/test_http1.py
index 44a9effa..07cd7dcc 100644
--- a/test/mitmproxy/protocol/test_http1.py
+++ b/test/mitmproxy/proxy/protocol/test_http1.py
@@ -2,7 +2,7 @@ from mitmproxy.test import tflow
from mitmproxy.net.http import http1
from mitmproxy.net.tcp import TCPClient
from mitmproxy.test.tutils import treq
-from .. import tservers
+from ... import tservers
class TestHTTPFlow:
diff --git a/test/mitmproxy/protocol/test_http2.py b/test/mitmproxy/proxy/protocol/test_http2.py
index 8e8ba644..cb9c0474 100644
--- a/test/mitmproxy/protocol/test_http2.py
+++ b/test/mitmproxy/proxy/protocol/test_http2.py
@@ -4,27 +4,25 @@
import os
import tempfile
import traceback
-
+import pytest
import h2
from mitmproxy import options
from mitmproxy.proxy.config import ProxyConfig
import mitmproxy.net
-from ...mitmproxy.net import tservers as net_tservers
+from ....mitmproxy.net import tservers as net_tservers
from mitmproxy import exceptions
from mitmproxy.net.http import http1, http2
-from .. import tservers
-from ...conftest import requires_alpn
+from ... import tservers
+from ....conftest import requires_alpn
import logging
logging.getLogger("hyper.packages.hpack.hpack").setLevel(logging.WARNING)
logging.getLogger("requests.packages.urllib3.connectionpool").setLevel(logging.WARNING)
logging.getLogger("passlib.utils.compat").setLevel(logging.WARNING)
logging.getLogger("passlib.registry").setLevel(logging.WARNING)
-logging.getLogger("PIL.Image").setLevel(logging.WARNING)
-logging.getLogger("PIL.PngImagePlugin").setLevel(logging.WARNING)
# inspect the log:
@@ -274,13 +272,13 @@ class TestSimple(_Http2Test):
@requires_alpn
-class TestRequestWithPriority(_Http2Test):
+class TestForbiddenHeaders(_Http2Test):
@classmethod
def handle_server_event(cls, event, h2_conn, rfile, wfile):
if isinstance(event, h2.events.ConnectionTerminated):
return False
- elif isinstance(event, h2.events.RequestReceived):
+ elif isinstance(event, h2.events.StreamEnded):
import warnings
with warnings.catch_warnings():
# Ignore UnicodeWarning:
@@ -291,60 +289,18 @@ class TestRequestWithPriority(_Http2Test):
warnings.simplefilter("ignore")
- headers = [(':status', '200')]
- if event.priority_updated:
- headers.append(('priority_exclusive', str(event.priority_updated.exclusive).encode()))
- headers.append(('priority_depends_on', str(event.priority_updated.depends_on).encode()))
- headers.append(('priority_weight', str(event.priority_updated.weight).encode()))
- h2_conn.send_headers(event.stream_id, headers)
+ h2_conn.config.validate_outbound_headers = False
+ h2_conn.send_headers(event.stream_id, [
+ (':status', '200'),
+ ('keep-alive', 'foobar'),
+ ])
+ h2_conn.send_data(event.stream_id, b'response body')
h2_conn.end_stream(event.stream_id)
wfile.write(h2_conn.data_to_send())
wfile.flush()
return True
- def test_request_with_priority(self):
- client, h2_conn = self._setup_connection()
-
- self._send_request(
- client.wfile,
- h2_conn,
- headers=[
- (':authority', "127.0.0.1:{}".format(self.server.server.address.port)),
- (':method', 'GET'),
- (':scheme', 'https'),
- (':path', '/'),
- ],
- priority_exclusive=True,
- priority_depends_on=42424242,
- priority_weight=42,
- )
-
- done = False
- while not done:
- try:
- raw = b''.join(http2.read_raw_frame(client.rfile))
- events = h2_conn.receive_data(raw)
- except exceptions.HttpException:
- print(traceback.format_exc())
- assert False
-
- client.wfile.write(h2_conn.data_to_send())
- client.wfile.flush()
-
- for event in events:
- if isinstance(event, h2.events.StreamEnded):
- done = True
-
- h2_conn.close_connection()
- client.wfile.write(h2_conn.data_to_send())
- client.wfile.flush()
-
- assert len(self.master.state.flows) == 1
- assert self.master.state.flows[0].response.headers['priority_exclusive'] == 'True'
- assert self.master.state.flows[0].response.headers['priority_depends_on'] == '42424242'
- assert self.master.state.flows[0].response.headers['priority_weight'] == '42'
-
- def test_request_without_priority(self):
+ def test_forbidden_headers(self):
client, h2_conn = self._setup_connection()
self._send_request(
@@ -355,8 +311,7 @@ class TestRequestWithPriority(_Http2Test):
(':method', 'GET'),
(':scheme', 'https'),
(':path', '/'),
- ],
- )
+ ])
done = False
while not done:
@@ -371,7 +326,9 @@ class TestRequestWithPriority(_Http2Test):
client.wfile.flush()
for event in events:
- if isinstance(event, h2.events.StreamEnded):
+ if isinstance(event, h2.events.ResponseReceived):
+ assert 'keep-alive' not in event.headers
+ elif isinstance(event, h2.events.StreamEnded):
done = True
h2_conn.close_connection()
@@ -379,21 +336,17 @@ class TestRequestWithPriority(_Http2Test):
client.wfile.flush()
assert len(self.master.state.flows) == 1
- assert 'priority_exclusive' not in self.master.state.flows[0].response.headers
- assert 'priority_depends_on' not in self.master.state.flows[0].response.headers
- assert 'priority_weight' not in self.master.state.flows[0].response.headers
+ assert self.master.state.flows[0].response.status_code == 200
+ assert self.master.state.flows[0].response.headers['keep-alive'] == 'foobar'
@requires_alpn
-class TestPriority(_Http2Test):
- priority_data = None
+class TestRequestWithPriority(_Http2Test):
@classmethod
def handle_server_event(cls, event, h2_conn, rfile, wfile):
if isinstance(event, h2.events.ConnectionTerminated):
return False
- elif isinstance(event, h2.events.PriorityUpdated):
- cls.priority_data = (event.exclusive, event.depends_on, event.weight)
elif isinstance(event, h2.events.RequestReceived):
import warnings
with warnings.catch_warnings():
@@ -406,18 +359,26 @@ class TestPriority(_Http2Test):
warnings.simplefilter("ignore")
headers = [(':status', '200')]
+ if event.priority_updated:
+ headers.append(('priority_exclusive', str(event.priority_updated.exclusive).encode()))
+ headers.append(('priority_depends_on', str(event.priority_updated.depends_on).encode()))
+ headers.append(('priority_weight', str(event.priority_updated.weight).encode()))
h2_conn.send_headers(event.stream_id, headers)
h2_conn.end_stream(event.stream_id)
wfile.write(h2_conn.data_to_send())
wfile.flush()
return True
- def test_priority(self):
- client, h2_conn = self._setup_connection()
+ @pytest.mark.parametrize("http2_priority_enabled, priority, expected_priority", [
+ (True, (True, 42424242, 42), ('True', '42424242', '42')),
+ (False, (True, 42424242, 42), (None, None, None)),
+ (True, (None, None, None), (None, None, None)),
+ (False, (None, None, None), (None, None, None)),
+ ])
+ def test_request_with_priority(self, http2_priority_enabled, priority, expected_priority):
+ self.config.options.http2_priority = http2_priority_enabled
- h2_conn.prioritize(1, exclusive=True, depends_on=0, weight=42)
- client.wfile.write(h2_conn.data_to_send())
- client.wfile.flush()
+ client, h2_conn = self._setup_connection()
self._send_request(
client.wfile,
@@ -428,6 +389,9 @@ class TestPriority(_Http2Test):
(':scheme', 'https'),
(':path', '/'),
],
+ priority_exclusive=priority[0],
+ priority_depends_on=priority[1],
+ priority_weight=priority[2],
)
done = False
@@ -451,12 +415,15 @@ class TestPriority(_Http2Test):
client.wfile.flush()
assert len(self.master.state.flows) == 1
- assert self.priority_data == (True, 0, 42)
+
+ resp = self.master.state.flows[0].response
+ assert resp.headers.get('priority_exclusive', None) == expected_priority[0]
+ assert resp.headers.get('priority_depends_on', None) == expected_priority[1]
+ assert resp.headers.get('priority_weight', None) == expected_priority[2]
@requires_alpn
-class TestPriorityWithExistingStream(_Http2Test):
- priority_data = []
+class TestPriority(_Http2Test):
@classmethod
def handle_server_event(cls, event, h2_conn, rfile, wfile):
@@ -465,8 +432,6 @@ class TestPriorityWithExistingStream(_Http2Test):
elif isinstance(event, h2.events.PriorityUpdated):
cls.priority_data.append((event.exclusive, event.depends_on, event.weight))
elif isinstance(event, h2.events.RequestReceived):
- assert not event.priority_updated
-
import warnings
with warnings.catch_warnings():
# Ignore UnicodeWarning:
@@ -479,17 +444,27 @@ class TestPriorityWithExistingStream(_Http2Test):
headers = [(':status', '200')]
h2_conn.send_headers(event.stream_id, headers)
- wfile.write(h2_conn.data_to_send())
- wfile.flush()
- elif isinstance(event, h2.events.StreamEnded):
h2_conn.end_stream(event.stream_id)
wfile.write(h2_conn.data_to_send())
wfile.flush()
return True
- def test_priority_with_existing_stream(self):
+ @pytest.mark.parametrize("prioritize_before", [True, False])
+ @pytest.mark.parametrize("http2_priority_enabled, priority, expected_priority", [
+ (True, (True, 42424242, 42), [(True, 42424242, 42)]),
+ (False, (True, 42424242, 42), []),
+ ])
+ def test_priority(self, prioritize_before, http2_priority_enabled, priority, expected_priority):
+ self.config.options.http2_priority = http2_priority_enabled
+ self.__class__.priority_data = []
+
client, h2_conn = self._setup_connection()
+ if prioritize_before:
+ h2_conn.prioritize(1, exclusive=priority[0], depends_on=priority[1], weight=priority[2])
+ client.wfile.write(h2_conn.data_to_send())
+ client.wfile.flush()
+
self._send_request(
client.wfile,
h2_conn,
@@ -499,13 +474,14 @@ class TestPriorityWithExistingStream(_Http2Test):
(':scheme', 'https'),
(':path', '/'),
],
- end_stream=False,
+ end_stream=prioritize_before,
)
- h2_conn.prioritize(1, exclusive=True, depends_on=0, weight=42)
- h2_conn.end_stream(1)
- client.wfile.write(h2_conn.data_to_send())
- client.wfile.flush()
+ if not prioritize_before:
+ h2_conn.prioritize(1, exclusive=priority[0], depends_on=priority[1], weight=priority[2])
+ h2_conn.end_stream(1)
+ client.wfile.write(h2_conn.data_to_send())
+ client.wfile.flush()
done = False
while not done:
@@ -528,7 +504,7 @@ class TestPriorityWithExistingStream(_Http2Test):
client.wfile.flush()
assert len(self.master.state.flows) == 1
- assert self.priority_data == [(True, 0, 42)]
+ assert self.priority_data == expected_priority
@requires_alpn
diff --git a/test/mitmproxy/proxy/protocol/test_http_replay.py b/test/mitmproxy/proxy/protocol/test_http_replay.py
new file mode 100644
index 00000000..777ab4dd
--- /dev/null
+++ b/test/mitmproxy/proxy/protocol/test_http_replay.py
@@ -0,0 +1 @@
+# TODO: write tests
diff --git a/test/mitmproxy/proxy/protocol/test_rawtcp.py b/test/mitmproxy/proxy/protocol/test_rawtcp.py
new file mode 100644
index 00000000..777ab4dd
--- /dev/null
+++ b/test/mitmproxy/proxy/protocol/test_rawtcp.py
@@ -0,0 +1 @@
+# TODO: write tests
diff --git a/test/mitmproxy/protocol/test_tls.py b/test/mitmproxy/proxy/protocol/test_tls.py
index e17ee46f..e17ee46f 100644
--- a/test/mitmproxy/protocol/test_tls.py
+++ b/test/mitmproxy/proxy/protocol/test_tls.py
diff --git a/test/mitmproxy/protocol/test_websocket.py b/test/mitmproxy/proxy/protocol/test_websocket.py
index 73ee8b35..4ea01d34 100644
--- a/test/mitmproxy/protocol/test_websocket.py
+++ b/test/mitmproxy/proxy/protocol/test_websocket.py
@@ -9,17 +9,17 @@ from mitmproxy.http import HTTPFlow
from mitmproxy.websocket import WebSocketFlow
from mitmproxy.proxy.config import ProxyConfig
-import mitmproxy.net
+from mitmproxy.net import tcp
from mitmproxy.net import http
-from ...mitmproxy.net import tservers as net_tservers
-from .. import tservers
+from ....mitmproxy.net import tservers as net_tservers
+from ... import tservers
from mitmproxy.net import websockets
class _WebSocketServerBase(net_tservers.ServerTestBase):
- class handler(mitmproxy.net.tcp.BaseHandler):
+ class handler(tcp.BaseHandler):
def handle(self):
try:
@@ -80,7 +80,7 @@ class _WebSocketTestBase:
self.server.server.handle_websockets = self.handle_websockets
def _setup_connection(self):
- client = mitmproxy.net.tcp.TCPClient(("127.0.0.1", self.proxy.port))
+ client = tcp.TCPClient(("127.0.0.1", self.proxy.port))
client.connect()
request = http.Request(
diff --git a/test/mitmproxy/test_proxy_config.py b/test/mitmproxy/proxy/test_config.py
index 4272d952..4272d952 100644
--- a/test/mitmproxy/test_proxy_config.py
+++ b/test/mitmproxy/proxy/test_config.py
diff --git a/test/mitmproxy/proxy/test_root_context.py b/test/mitmproxy/proxy/test_root_context.py
new file mode 100644
index 00000000..777ab4dd
--- /dev/null
+++ b/test/mitmproxy/proxy/test_root_context.py
@@ -0,0 +1 @@
+# TODO: write tests
diff --git a/test/mitmproxy/test_server.py b/test/mitmproxy/proxy/test_server.py
index 9cd47cea..0be772a4 100644
--- a/test/mitmproxy/test_server.py
+++ b/test/mitmproxy/proxy/test_server.py
@@ -21,8 +21,8 @@ from mitmproxy.net.tcp import Address
from pathod import pathoc
from pathod import pathod
-from . import tservers
-from ..conftest import skip_appveyor
+from .. import tservers
+from ...conftest import skip_appveyor
"""
diff --git a/test/mitmproxy/test_connections.py b/test/mitmproxy/test_connections.py
new file mode 100644
index 00000000..777ab4dd
--- /dev/null
+++ b/test/mitmproxy/test_connections.py
@@ -0,0 +1 @@
+# TODO: write tests
diff --git a/test/mitmproxy/test_ctx.py b/test/mitmproxy/test_ctx.py
new file mode 100644
index 00000000..777ab4dd
--- /dev/null
+++ b/test/mitmproxy/test_ctx.py
@@ -0,0 +1 @@
+# TODO: write tests
diff --git a/test/mitmproxy/test_exceptions.py b/test/mitmproxy/test_exceptions.py
new file mode 100644
index 00000000..777ab4dd
--- /dev/null
+++ b/test/mitmproxy/test_exceptions.py
@@ -0,0 +1 @@
+# TODO: write tests
diff --git a/test/mitmproxy/test_flow_export.py b/test/mitmproxy/test_export.py
index 457d8836..457d8836 100644
--- a/test/mitmproxy/test_flow_export.py
+++ b/test/mitmproxy/test_export.py
diff --git a/test/mitmproxy/test_flow.py b/test/mitmproxy/test_flow.py
index 65e6845f..a78e5f80 100644
--- a/test/mitmproxy/test_flow.py
+++ b/test/mitmproxy/test_flow.py
@@ -10,7 +10,6 @@ from mitmproxy.exceptions import FlowReadException, Kill
from mitmproxy import flow
from mitmproxy import http
from mitmproxy import connections
-from mitmproxy import tcp
from mitmproxy.proxy import ProxyConfig
from mitmproxy.proxy.server import DummyServer
from mitmproxy import master
@@ -157,117 +156,6 @@ class TestHTTPFlow:
assert f.response.raw_content == b"abarb"
-class TestWebSocketFlow:
-
- def test_copy(self):
- f = tflow.twebsocketflow()
- f.get_state()
- f2 = f.copy()
- a = f.get_state()
- b = f2.get_state()
- del a["id"]
- del b["id"]
- del a["handshake_flow"]["id"]
- del b["handshake_flow"]["id"]
- assert a == b
- assert not f == f2
- assert f is not f2
-
- assert f.client_key == f2.client_key
- assert f.client_protocol == f2.client_protocol
- assert f.client_extensions == f2.client_extensions
- assert f.server_accept == f2.server_accept
- assert f.server_protocol == f2.server_protocol
- assert f.server_extensions == f2.server_extensions
- assert f.messages is not f2.messages
- assert f.handshake_flow is not f2.handshake_flow
-
- for m in f.messages:
- m2 = m.copy()
- m2.set_state(m2.get_state())
- assert m is not m2
- assert m.get_state() == m2.get_state()
-
- f = tflow.twebsocketflow(err=True)
- f2 = f.copy()
- assert f is not f2
- assert f.handshake_flow is not f2.handshake_flow
- assert f.error.get_state() == f2.error.get_state()
- assert f.error is not f2.error
-
- def test_match(self):
- f = tflow.twebsocketflow()
- assert not flowfilter.match("~b nonexistent", f)
- assert flowfilter.match(None, f)
- assert not flowfilter.match("~b nonexistent", f)
-
- f = tflow.twebsocketflow(err=True)
- assert flowfilter.match("~e", f)
-
- with pytest.raises(ValueError):
- flowfilter.match("~", f)
-
- def test_repr(self):
- f = tflow.twebsocketflow()
- assert 'WebSocketFlow' in repr(f)
- assert 'binary message: ' in repr(f.messages[0])
- assert 'text message: ' in repr(f.messages[1])
-
-
-class TestTCPFlow:
-
- def test_copy(self):
- f = tflow.ttcpflow()
- f.get_state()
- f2 = f.copy()
- a = f.get_state()
- b = f2.get_state()
- del a["id"]
- del b["id"]
- assert a == b
- assert not f == f2
- assert f is not f2
-
- assert f.messages is not f2.messages
-
- for m in f.messages:
- assert m.get_state()
- m2 = m.copy()
- assert not m == m2
- assert m is not m2
-
- a = m.get_state()
- b = m2.get_state()
- assert a == b
-
- m = tcp.TCPMessage(False, 'foo')
- m.set_state(f.messages[0].get_state())
- assert m.timestamp == f.messages[0].timestamp
-
- f = tflow.ttcpflow(err=True)
- f2 = f.copy()
- assert f is not f2
- assert f.error.get_state() == f2.error.get_state()
- assert f.error is not f2.error
-
- def test_match(self):
- f = tflow.ttcpflow()
- assert not flowfilter.match("~b nonexistent", f)
- assert flowfilter.match(None, f)
- assert not flowfilter.match("~b nonexistent", f)
-
- f = tflow.ttcpflow(err=True)
- assert flowfilter.match("~e", f)
-
- with pytest.raises(ValueError):
- flowfilter.match("~", f)
-
- def test_repr(self):
- f = tflow.ttcpflow()
- assert 'TCPFlow' in repr(f)
- assert '-> ' in repr(f.messages[0])
-
-
class TestSerialize:
def _treader(self):
diff --git a/test/mitmproxy/test_http.py b/test/mitmproxy/test_http.py
new file mode 100644
index 00000000..777ab4dd
--- /dev/null
+++ b/test/mitmproxy/test_http.py
@@ -0,0 +1 @@
+# TODO: write tests
diff --git a/test/mitmproxy/test_io.py b/test/mitmproxy/test_io.py
new file mode 100644
index 00000000..777ab4dd
--- /dev/null
+++ b/test/mitmproxy/test_io.py
@@ -0,0 +1 @@
+# TODO: write tests
diff --git a/test/mitmproxy/test_flow_format_compat.py b/test/mitmproxy/test_io_compat.py
index 288de4fc..288de4fc 100644
--- a/test/mitmproxy/test_flow_format_compat.py
+++ b/test/mitmproxy/test_io_compat.py
diff --git a/test/mitmproxy/test_log.py b/test/mitmproxy/test_log.py
new file mode 100644
index 00000000..777ab4dd
--- /dev/null
+++ b/test/mitmproxy/test_log.py
@@ -0,0 +1 @@
+# TODO: write tests
diff --git a/test/mitmproxy/test_master.py b/test/mitmproxy/test_master.py
new file mode 100644
index 00000000..777ab4dd
--- /dev/null
+++ b/test/mitmproxy/test_master.py
@@ -0,0 +1 @@
+# TODO: write tests
diff --git a/test/mitmproxy/test_options.py b/test/mitmproxy/test_options.py
new file mode 100644
index 00000000..777ab4dd
--- /dev/null
+++ b/test/mitmproxy/test_options.py
@@ -0,0 +1 @@
+# TODO: write tests
diff --git a/test/mitmproxy/test_tcp.py b/test/mitmproxy/test_tcp.py
new file mode 100644
index 00000000..dce6493c
--- /dev/null
+++ b/test/mitmproxy/test_tcp.py
@@ -0,0 +1,59 @@
+import pytest
+
+from mitmproxy import tcp
+from mitmproxy import flowfilter
+from mitmproxy.test import tflow
+
+
+class TestTCPFlow:
+
+ def test_copy(self):
+ f = tflow.ttcpflow()
+ f.get_state()
+ f2 = f.copy()
+ a = f.get_state()
+ b = f2.get_state()
+ del a["id"]
+ del b["id"]
+ assert a == b
+ assert not f == f2
+ assert f is not f2
+
+ assert f.messages is not f2.messages
+
+ for m in f.messages:
+ assert m.get_state()
+ m2 = m.copy()
+ assert not m == m2
+ assert m is not m2
+
+ a = m.get_state()
+ b = m2.get_state()
+ assert a == b
+
+ m = tcp.TCPMessage(False, 'foo')
+ m.set_state(f.messages[0].get_state())
+ assert m.timestamp == f.messages[0].timestamp
+
+ f = tflow.ttcpflow(err=True)
+ f2 = f.copy()
+ assert f is not f2
+ assert f.error.get_state() == f2.error.get_state()
+ assert f.error is not f2.error
+
+ def test_match(self):
+ f = tflow.ttcpflow()
+ assert not flowfilter.match("~b nonexistent", f)
+ assert flowfilter.match(None, f)
+ assert not flowfilter.match("~b nonexistent", f)
+
+ f = tflow.ttcpflow(err=True)
+ assert flowfilter.match("~e", f)
+
+ with pytest.raises(ValueError):
+ flowfilter.match("~", f)
+
+ def test_repr(self):
+ f = tflow.ttcpflow()
+ assert 'TCPFlow' in repr(f)
+ assert '-> ' in repr(f.messages[0])
diff --git a/test/mitmproxy/test_websocket.py b/test/mitmproxy/test_websocket.py
new file mode 100644
index 00000000..f2963390
--- /dev/null
+++ b/test/mitmproxy/test_websocket.py
@@ -0,0 +1,62 @@
+import pytest
+
+from mitmproxy import flowfilter
+from mitmproxy.test import tflow
+
+
+class TestWebSocketFlow:
+
+ def test_copy(self):
+ f = tflow.twebsocketflow()
+ f.get_state()
+ f2 = f.copy()
+ a = f.get_state()
+ b = f2.get_state()
+ del a["id"]
+ del b["id"]
+ del a["handshake_flow"]["id"]
+ del b["handshake_flow"]["id"]
+ assert a == b
+ assert not f == f2
+ assert f is not f2
+
+ assert f.client_key == f2.client_key
+ assert f.client_protocol == f2.client_protocol
+ assert f.client_extensions == f2.client_extensions
+ assert f.server_accept == f2.server_accept
+ assert f.server_protocol == f2.server_protocol
+ assert f.server_extensions == f2.server_extensions
+ assert f.messages is not f2.messages
+ assert f.handshake_flow is not f2.handshake_flow
+
+ for m in f.messages:
+ m2 = m.copy()
+ m2.set_state(m2.get_state())
+ assert m is not m2
+ assert m.get_state() == m2.get_state()
+
+ f = tflow.twebsocketflow(err=True)
+ f2 = f.copy()
+ assert f is not f2
+ assert f.handshake_flow is not f2.handshake_flow
+ assert f.error.get_state() == f2.error.get_state()
+ assert f.error is not f2.error
+
+ def test_match(self):
+ f = tflow.twebsocketflow()
+ assert not flowfilter.match("~b nonexistent", f)
+ assert flowfilter.match(None, f)
+ assert not flowfilter.match("~b nonexistent", f)
+
+ f = tflow.twebsocketflow(err=True)
+ assert flowfilter.match("~e", f)
+
+ with pytest.raises(ValueError):
+ flowfilter.match("~", f)
+
+ def test_repr(self):
+ f = tflow.twebsocketflow()
+ assert f.message_info(f.messages[0])
+ assert 'WebSocketFlow' in repr(f)
+ assert 'binary message: ' in repr(f.messages[0])
+ assert 'text message: ' in repr(f.messages[1])
diff --git a/test/mitmproxy/tools/__init__.py b/test/mitmproxy/tools/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/mitmproxy/tools/__init__.py
diff --git a/test/mitmproxy/tools/console/__init__.py b/test/mitmproxy/tools/console/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/mitmproxy/tools/console/__init__.py
diff --git a/test/mitmproxy/console/test_common.py b/test/mitmproxy/tools/console/test_common.py
index 236ebb41..3ab4fd67 100644
--- a/test/mitmproxy/console/test_common.py
+++ b/test/mitmproxy/tools/console/test_common.py
@@ -1,7 +1,7 @@
from mitmproxy.test import tflow
from mitmproxy.tools.console import common
-from ...conftest import skip_appveyor
+from ....conftest import skip_appveyor
@skip_appveyor
diff --git a/test/mitmproxy/console/test_help.py b/test/mitmproxy/tools/console/test_help.py
index 86b842d8..ac3011e6 100644
--- a/test/mitmproxy/console/test_help.py
+++ b/test/mitmproxy/tools/console/test_help.py
@@ -1,6 +1,6 @@
import mitmproxy.tools.console.help as help
-from ...conftest import skip_appveyor
+from ....conftest import skip_appveyor
@skip_appveyor
diff --git a/test/mitmproxy/console/test_master.py b/test/mitmproxy/tools/console/test_master.py
index 1c89467c..0bf3734b 100644
--- a/test/mitmproxy/console/test_master.py
+++ b/test/mitmproxy/tools/console/test_master.py
@@ -1,10 +1,10 @@
from mitmproxy.test import tflow
-import mitmproxy.test.tutils
+from mitmproxy.test import tutils
from mitmproxy.tools import console
from mitmproxy import proxy
from mitmproxy import options
from mitmproxy.tools.console import common
-from .. import tservers
+from ... import tservers
def test_format_keyvals():
@@ -45,12 +45,12 @@ class TestMaster(tservers.MasterTest):
def test_intercept(self):
"""regression test for https://github.com/mitmproxy/mitmproxy/issues/1605"""
m = self.mkmaster(intercept="~b bar")
- f = tflow.tflow(req=mitmproxy.test.tutils.treq(content=b"foo"))
+ f = tflow.tflow(req=tutils.treq(content=b"foo"))
m.request(f)
assert not m.view[0].intercepted
- f = tflow.tflow(req=mitmproxy.test.tutils.treq(content=b"bar"))
+ f = tflow.tflow(req=tutils.treq(content=b"bar"))
m.request(f)
assert m.view[1].intercepted
- f = tflow.tflow(resp=mitmproxy.test.tutils.tresp(content=b"bar"))
+ f = tflow.tflow(resp=tutils.tresp(content=b"bar"))
m.request(f)
assert m.view[2].intercepted
diff --git a/test/mitmproxy/console/test_palettes.py b/test/mitmproxy/tools/console/test_palettes.py
index 3892797d..1c7e1df1 100644
--- a/test/mitmproxy/console/test_palettes.py
+++ b/test/mitmproxy/tools/console/test_palettes.py
@@ -1,6 +1,6 @@
import mitmproxy.tools.console.palettes as palettes
-from ...conftest import skip_appveyor
+from ....conftest import skip_appveyor
@skip_appveyor
diff --git a/test/mitmproxy/console/test_pathedit.py b/test/mitmproxy/tools/console/test_pathedit.py
index bd064e5f..bd064e5f 100644
--- a/test/mitmproxy/console/test_pathedit.py
+++ b/test/mitmproxy/tools/console/test_pathedit.py
diff --git a/test/mitmproxy/test_cmdline.py b/test/mitmproxy/tools/test_cmdline.py
index 96d5ae31..96d5ae31 100644
--- a/test/mitmproxy/test_cmdline.py
+++ b/test/mitmproxy/tools/test_cmdline.py
diff --git a/test/mitmproxy/test_tools_dump.py b/test/mitmproxy/tools/test_dump.py
index f8a88871..b4183725 100644
--- a/test/mitmproxy/test_tools_dump.py
+++ b/test/mitmproxy/tools/test_dump.py
@@ -8,7 +8,7 @@ from mitmproxy import controller
from mitmproxy.tools import dump
from mitmproxy.test import tutils
-from . import tservers
+from .. import tservers
class TestDumpMaster(tservers.MasterTest):
diff --git a/test/mitmproxy/tools/web/__init__.py b/test/mitmproxy/tools/web/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/mitmproxy/tools/web/__init__.py
diff --git a/test/mitmproxy/test_web_app.py b/test/mitmproxy/tools/web/test_app.py
index 00dc2c7c..00dc2c7c 100644
--- a/test/mitmproxy/test_web_app.py
+++ b/test/mitmproxy/tools/web/test_app.py
diff --git a/test/mitmproxy/test_web_master.py b/test/mitmproxy/tools/web/test_master.py
index d4190ffb..27f99a18 100644
--- a/test/mitmproxy/test_web_master.py
+++ b/test/mitmproxy/tools/web/test_master.py
@@ -3,7 +3,7 @@ from mitmproxy import proxy
from mitmproxy import options
from mitmproxy.proxy.config import ProxyConfig
-from . import tservers
+from ... import tservers
class TestWebMaster(tservers.MasterTest):
diff --git a/test/mitmproxy/utils/test_bits.py b/test/mitmproxy/utils/test_bits.py
new file mode 100644
index 00000000..777ab4dd
--- /dev/null
+++ b/test/mitmproxy/utils/test_bits.py
@@ -0,0 +1 @@
+# TODO: write tests
diff --git a/test/mitmproxy/utils/test_debug.py b/test/mitmproxy/utils/test_debug.py
index 22f8dc66..4371ef70 100644
--- a/test/mitmproxy/utils/test_debug.py
+++ b/test/mitmproxy/utils/test_debug.py
@@ -1,13 +1,20 @@
import io
import subprocess
+import sys
from unittest import mock
+import pytest
from mitmproxy.utils import debug
-def test_dump_system_info():
- assert debug.dump_system_info()
+@pytest.mark.parametrize("precompiled", [True, False])
+def test_dump_system_info_precompiled(precompiled):
+ sys.frozen = None
+ with mock.patch.object(sys, 'frozen', precompiled):
+ assert ("Precompiled Binary" in debug.dump_system_info()) == precompiled
+
+def test_dump_system_info_version():
with mock.patch('subprocess.check_output') as m:
m.side_effect = subprocess.CalledProcessError(-1, 'git describe --tags --long')
assert 'release version' in debug.dump_system_info()
diff --git a/test/pathod/language/__init__.py b/test/pathod/language/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/pathod/language/__init__.py
diff --git a/test/pathod/test_language_actions.py b/test/pathod/language/test_actions.py
index 9740e5c7..9740e5c7 100644
--- a/test/pathod/test_language_actions.py
+++ b/test/pathod/language/test_actions.py
diff --git a/test/pathod/test_language_base.py b/test/pathod/language/test_base.py
index 85e9e53b..85e9e53b 100644
--- a/test/pathod/test_language_base.py
+++ b/test/pathod/language/test_base.py
diff --git a/test/pathod/language/test_exceptions.py b/test/pathod/language/test_exceptions.py
new file mode 100644
index 00000000..777ab4dd
--- /dev/null
+++ b/test/pathod/language/test_exceptions.py
@@ -0,0 +1 @@
+# TODO: write tests
diff --git a/test/pathod/test_language_generators.py b/test/pathod/language/test_generators.py
index b3ce0335..b3ce0335 100644
--- a/test/pathod/test_language_generators.py
+++ b/test/pathod/language/test_generators.py
diff --git a/test/pathod/test_language_http.py b/test/pathod/language/test_http.py
index 6ab43fe0..a5b35c05 100644
--- a/test/pathod/test_language_http.py
+++ b/test/pathod/language/test_http.py
@@ -4,7 +4,7 @@ import pytest
from pathod import language
from pathod.language import http, base
-from . import tservers
+from .. import tservers
def parse_request(s):
diff --git a/test/pathod/test_language_http2.py b/test/pathod/language/test_http2.py
index 4f89adb8..4f89adb8 100644
--- a/test/pathod/test_language_http2.py
+++ b/test/pathod/language/test_http2.py
diff --git a/test/pathod/language/test_message.py b/test/pathod/language/test_message.py
new file mode 100644
index 00000000..777ab4dd
--- /dev/null
+++ b/test/pathod/language/test_message.py
@@ -0,0 +1 @@
+# TODO: write tests
diff --git a/test/pathod/test_language_websocket.py b/test/pathod/language/test_websockets.py
index e5046591..ed766bca 100644
--- a/test/pathod/test_language_websocket.py
+++ b/test/pathod/language/test_websockets.py
@@ -4,7 +4,7 @@ from pathod import language
from pathod.language import websockets
import mitmproxy.net.websockets
-from . import tservers
+from .. import tservers
def parse_request(s):
diff --git a/test/pathod/test_language_writer.py b/test/pathod/language/test_writer.py
index 7feb985d..7feb985d 100644
--- a/test/pathod/test_language_writer.py
+++ b/test/pathod/language/test_writer.py
diff --git a/test/pathod/protocols/__init__.py b/test/pathod/protocols/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/pathod/protocols/__init__.py
diff --git a/test/pathod/protocols/test_http.py b/test/pathod/protocols/test_http.py
new file mode 100644
index 00000000..777ab4dd
--- /dev/null
+++ b/test/pathod/protocols/test_http.py
@@ -0,0 +1 @@
+# TODO: write tests
diff --git a/test/pathod/test_protocols_http2.py b/test/pathod/protocols/test_http2.py
index 5bb31031..1c074197 100644
--- a/test/pathod/test_protocols_http2.py
+++ b/test/pathod/protocols/test_http2.py
@@ -7,11 +7,11 @@ from mitmproxy.net import tcp, http
from mitmproxy.net.http import http2
from mitmproxy import exceptions
-from ..mitmproxy.net import tservers as net_tservers
+from ...mitmproxy.net import tservers as net_tservers
from pathod.protocols.http2 import HTTP2StateProtocol, TCPHandler
-from ..conftest import requires_alpn
+from ...conftest import requires_alpn
class TestTCPHandlerWrapper:
diff --git a/test/pathod/protocols/test_websockets.py b/test/pathod/protocols/test_websockets.py
new file mode 100644
index 00000000..777ab4dd
--- /dev/null
+++ b/test/pathod/protocols/test_websockets.py
@@ -0,0 +1 @@
+# TODO: write tests