diff options
Diffstat (limited to 'test')
-rw-r--r-- | test/mitmproxy/data/addonscripts/shutdown.py | 2 | ||||
-rw-r--r-- | test/mitmproxy/proxy/protocol/test_http2.py | 6 | ||||
-rw-r--r-- | test/mitmproxy/proxy/protocol/test_websocket.py | 21 | ||||
-rw-r--r-- | test/mitmproxy/proxy/test_server.py | 42 | ||||
-rw-r--r-- | test/mitmproxy/test_controller.py | 79 | ||||
-rw-r--r-- | test/mitmproxy/test_flow.py | 9 | ||||
-rw-r--r-- | test/mitmproxy/test_fuzzing.py | 12 | ||||
-rw-r--r-- | test/mitmproxy/tools/test_main.py | 10 | ||||
-rw-r--r-- | test/mitmproxy/tservers.py | 60 |
9 files changed, 94 insertions, 147 deletions
diff --git a/test/mitmproxy/data/addonscripts/shutdown.py b/test/mitmproxy/data/addonscripts/shutdown.py index 51a99b5c..3da4d03e 100644 --- a/test/mitmproxy/data/addonscripts/shutdown.py +++ b/test/mitmproxy/data/addonscripts/shutdown.py @@ -1,5 +1,5 @@ from mitmproxy import ctx -def running(): +def tick(): ctx.master.shutdown() diff --git a/test/mitmproxy/proxy/protocol/test_http2.py b/test/mitmproxy/proxy/protocol/test_http2.py index d9aa03b4..13f28728 100644 --- a/test/mitmproxy/proxy/protocol/test_http2.py +++ b/test/mitmproxy/proxy/protocol/test_http2.py @@ -10,7 +10,6 @@ import h2 from mitmproxy import options import mitmproxy.net -from mitmproxy.addons import core from ...net import tservers as net_tservers from mitmproxy import exceptions from mitmproxy.net.http import http1, http2 @@ -90,9 +89,7 @@ class _Http2TestBase: @classmethod def setup_class(cls): cls.options = cls.get_options() - tmaster = tservers.TestMaster(cls.options) - tmaster.addons.add(core.Core()) - cls.proxy = tservers.ProxyThread(tmaster) + cls.proxy = tservers.ProxyThread(tservers.TestMaster, cls.options) cls.proxy.start() @classmethod @@ -120,6 +117,7 @@ class _Http2TestBase: def teardown(self): if self.client: self.client.close() + self.server.server.wait_for_silence() def setup_connection(self): self.client = mitmproxy.net.tcp.TCPClient(("127.0.0.1", self.proxy.port)) diff --git a/test/mitmproxy/proxy/protocol/test_websocket.py b/test/mitmproxy/proxy/protocol/test_websocket.py index 661605b7..e5ed8e9d 100644 --- a/test/mitmproxy/proxy/protocol/test_websocket.py +++ b/test/mitmproxy/proxy/protocol/test_websocket.py @@ -3,10 +3,10 @@ import os import struct import tempfile import traceback +import time from mitmproxy import options from mitmproxy import exceptions -from mitmproxy.addons import core from mitmproxy.http import HTTPFlow from mitmproxy.websocket import WebSocketFlow @@ -52,9 +52,7 @@ class _WebSocketTestBase: @classmethod def setup_class(cls): cls.options = cls.get_options() - tmaster = tservers.TestMaster(cls.options) - tmaster.addons.add(core.Core()) - cls.proxy = tservers.ProxyThread(tmaster) + cls.proxy = tservers.ProxyThread(tservers.TestMaster, cls.options) cls.proxy.start() @classmethod @@ -163,7 +161,7 @@ class TestSimple(_WebSocketTest): def websocket_start(self, f): f.stream = streaming - self.master.addons.add(Stream()) + self.proxy.set_addons(Stream()) self.setup_connection() frame = websockets.Frame.from_file(self.client.rfile) @@ -204,7 +202,7 @@ class TestSimple(_WebSocketTest): def websocket_message(self, f): f.messages[-1].content = "foo" - self.master.addons.add(Addon()) + self.proxy.set_addons(Addon()) self.setup_connection() frame = websockets.Frame.from_file(self.client.rfile) @@ -235,7 +233,7 @@ class TestKillFlow(_WebSocketTest): def websocket_message(self, f): f.kill() - self.master.addons.add(KillFlow()) + self.proxy.set_addons(KillFlow()) self.setup_connection() with pytest.raises(exceptions.TcpDisconnect): @@ -329,7 +327,12 @@ class TestPong(_WebSocketTest): assert frame.header.opcode == websockets.OPCODE.PONG assert frame.payload == b'foobar' - assert self.master.has_log("Pong Received from server", "info") + for i in range(20): + if self.master.has_log("Pong Received from server", "info"): + break + time.sleep(0.01) + else: + raise AssertionError("No pong seen") class TestClose(_WebSocketTest): @@ -405,7 +408,7 @@ class TestStreaming(_WebSocketTest): def websocket_start(self, f): f.stream = streaming - self.master.addons.add(Stream()) + self.proxy.set_addons(Stream()) self.setup_connection() frame = None diff --git a/test/mitmproxy/proxy/test_server.py b/test/mitmproxy/proxy/test_server.py index 986dfb39..aed4a774 100644 --- a/test/mitmproxy/proxy/test_server.py +++ b/test/mitmproxy/proxy/test_server.py @@ -21,14 +21,6 @@ from pathod import pathod from .. import tservers from ...conftest import skip_appveyor -""" - Note that the choice of response code in these tests matters more than you - might think. libcurl treats a 304 response code differently from, say, a - 200 response code - it will correctly terminate a 304 response with no - content-length header, whereas it will block forever waiting for content - for a 200 response. -""" - class CommonMixin: @@ -284,10 +276,9 @@ class TestHTTP(tservers.HTTPProxyTest, CommonMixin): s = script.Script( tutils.test_data.path("mitmproxy/data/addonscripts/stream_modify.py") ) - self.master.addons.add(s) + self.set_addons(s) d = self.pathod('200:b"foo"') assert d.content == b"bar" - self.master.addons.remove(s) def test_first_line_rewrite(self): """ @@ -591,12 +582,11 @@ class TestTransparent(tservers.TransparentProxyTest, CommonMixin, TcpMixin): s = script.Script( tutils.test_data.path("mitmproxy/data/addonscripts/tcp_stream_modify.py") ) - self.master.addons.add(s) + self.set_addons(s) self._tcpproxy_on() d = self.pathod('200:b"foo"') self._tcpproxy_off() assert d.content == b"bar" - self.master.addons.remove(s) class TestTransparentSSL(tservers.TransparentProxyTest, CommonMixin, TcpMixin): @@ -739,7 +729,7 @@ class TestRedirectRequest(tservers.HTTPProxyTest): This test verifies that the original destination is restored for the third request. """ - self.proxy.tmaster.addons.add(ARedirectRequest(self.server2.port)) + self.set_addons(ARedirectRequest(self.server2.port)) p = self.pathoc() with p.connect(): @@ -778,7 +768,7 @@ class AStreamRequest: class TestStreamRequest(tservers.HTTPProxyTest): def test_stream_simple(self): - self.proxy.tmaster.addons.add(AStreamRequest()) + self.set_addons(AStreamRequest()) p = self.pathoc() with p.connect(): # a request with 100k of data but without content-length @@ -787,7 +777,7 @@ class TestStreamRequest(tservers.HTTPProxyTest): assert len(r1.content) > 100000 def test_stream_multiple(self): - self.proxy.tmaster.addons.add(AStreamRequest()) + self.set_addons(AStreamRequest()) p = self.pathoc() with p.connect(): # simple request with streaming turned on @@ -799,7 +789,7 @@ class TestStreamRequest(tservers.HTTPProxyTest): assert r1.status_code == 201 def test_stream_chunked(self): - self.proxy.tmaster.addons.add(AStreamRequest()) + self.set_addons(AStreamRequest()) connection = socket.socket(socket.AF_INET, socket.SOCK_STREAM) connection.connect(("127.0.0.1", self.proxy.port)) fconn = connection.makefile("rb") @@ -828,7 +818,7 @@ class AFakeResponse: class TestFakeResponse(tservers.HTTPProxyTest): def test_fake(self): - self.proxy.tmaster.addons.add(AFakeResponse()) + self.set_addons(AFakeResponse()) f = self.pathod("200") assert "header-response" in f.headers @@ -844,7 +834,7 @@ class TestServerConnect(tservers.HTTPProxyTest): def test_unnecessary_serverconnect(self): """A replayed/fake response with no upstream_cert should not connect to an upstream server""" - self.proxy.tmaster.addons.add(AFakeResponse()) + self.set_addons(AFakeResponse()) assert self.pathod("200").status_code == 200 assert not self.proxy.tmaster.has_log("serverconnect") @@ -857,7 +847,7 @@ class AKillRequest: class TestKillRequest(tservers.HTTPProxyTest): def test_kill(self): - self.proxy.tmaster.addons.add(AKillRequest()) + self.set_addons(AKillRequest()) with pytest.raises(exceptions.HttpReadDisconnect): self.pathod("200") # Nothing should have hit the server @@ -871,7 +861,7 @@ class AKillResponse: class TestKillResponse(tservers.HTTPProxyTest): def test_kill(self): - self.proxy.tmaster.addons.add(AKillResponse()) + self.set_addons(AKillResponse()) with pytest.raises(exceptions.HttpReadDisconnect): self.pathod("200") # The server should have seen a request @@ -894,7 +884,7 @@ class AIncomplete: class TestIncompleteResponse(tservers.HTTPProxyTest): def test_incomplete(self): - self.proxy.tmaster.addons.add(AIncomplete()) + self.set_addons(AIncomplete()) assert self.pathod("200").status_code == 502 @@ -977,7 +967,7 @@ class TestUpstreamProxySSL( def test_change_upstream_proxy_connect(self): # skip chain[0]. - self.proxy.tmaster.addons.add( + self.set_addons( UpstreamProxyChanger( ("127.0.0.1", self.chain[1].port) ) @@ -996,8 +986,8 @@ class TestUpstreamProxySSL( Client <- HTTPS -> Proxy <- HTTP -> Proxy <- HTTPS -> Server """ - self.proxy.tmaster.addons.add(RewriteToHttp()) - self.chain[1].tmaster.addons.add(RewriteToHttps()) + self.set_addons(RewriteToHttp()) + self.chain[1].set_addons(RewriteToHttps()) p = self.pathoc() with p.connect(): resp = p.request("get:'/p/418'") @@ -1071,8 +1061,8 @@ class TestProxyChainingSSLReconnect(tservers.HTTPUpstreamProxyTest): http1obj.server_conn.wfile.write(headers) http1obj.server_conn.wfile.flush() - self.chain[0].tmaster.addons.add(RequestKiller([1, 2])) - self.chain[1].tmaster.addons.add(RequestKiller([1])) + self.chain[0].set_addons(RequestKiller([1, 2])) + self.chain[1].set_addons(RequestKiller([1])) p = self.pathoc() with p.connect(): diff --git a/test/mitmproxy/test_controller.py b/test/mitmproxy/test_controller.py index e840380a..f7c64ed9 100644 --- a/test/mitmproxy/test_controller.py +++ b/test/mitmproxy/test_controller.py @@ -1,82 +1,31 @@ -from threading import Thread, Event -from unittest.mock import Mock +import asyncio import queue import pytest from mitmproxy.exceptions import Kill, ControlException from mitmproxy import controller -from mitmproxy import master -from mitmproxy import proxy from mitmproxy.test import taddons -class TMsg: - pass +@pytest.mark.asyncio +async def test_master(): + class TMsg: + pass + class tAddon: + def log(self, _): + ctx.master.should_exit.set() -class TestMaster: - def test_simple(self): - class tAddon: - def log(self, _): - ctx.master.should_exit.set() + with taddons.context(tAddon()) as ctx: + assert not ctx.master.should_exit.is_set() - with taddons.context() as ctx: - ctx.master.addons.add(tAddon()) - assert not ctx.master.should_exit.is_set() + async def test(): msg = TMsg() msg.reply = controller.DummyReply() - ctx.master.event_queue.put(("log", msg)) - ctx.master.run() - assert ctx.master.should_exit.is_set() - - def test_server_simple(self): - m = master.Master(None) - m.server = proxy.DummyServer() - m.start() - m.shutdown() - m.start() - m.shutdown() + await ctx.master.channel.tell("log", msg) - -class TestServerThread: - def test_simple(self): - m = Mock() - t = master.ServerThread(m) - t.run() - assert m.serve_forever.called - - -class TestChannel: - def test_tell(self): - q = queue.Queue() - channel = controller.Channel(q, Event()) - m = Mock(name="test_tell") - channel.tell("test", m) - assert q.get() == ("test", m) - assert m.reply - - def test_ask_simple(self): - q = queue.Queue() - - def reply(): - m, obj = q.get() - assert m == "test" - obj.reply.send(42) - obj.reply.take() - obj.reply.commit() - - Thread(target=reply).start() - - channel = controller.Channel(q, Event()) - assert channel.ask("test", Mock(name="test_ask_simple")) == 42 - - def test_ask_shutdown(self): - q = queue.Queue() - done = Event() - done.set() - channel = controller.Channel(q, done) - with pytest.raises(Kill): - channel.ask("test", Mock(name="test_ask_shutdown")) + asyncio.ensure_future(test()) + assert not ctx.master.should_exit.is_set() class TestReply: diff --git a/test/mitmproxy/test_flow.py b/test/mitmproxy/test_flow.py index 8cc11a16..4042de5b 100644 --- a/test/mitmproxy/test_flow.py +++ b/test/mitmproxy/test_flow.py @@ -7,7 +7,7 @@ import mitmproxy.io from mitmproxy import flowfilter from mitmproxy import options from mitmproxy.io import tnetstring -from mitmproxy.exceptions import FlowReadException, ReplayException, ControlException +from mitmproxy.exceptions import FlowReadException, ReplayException from mitmproxy import flow from mitmproxy import http from mitmproxy.net import http as net_http @@ -169,9 +169,10 @@ class TestFlowMaster: f.error = flow.Error("msg") fm.addons.handle_lifecycle("error", f) - fm.tell("foo", f) - with pytest.raises(ControlException): - fm.tick(timeout=1) + # FIXME: This no longer works, because we consume on the main loop. + # fm.tell("foo", f) + # with pytest.raises(ControlException): + # fm.addons.trigger("unknown") fm.shutdown() diff --git a/test/mitmproxy/test_fuzzing.py b/test/mitmproxy/test_fuzzing.py index 905ba1cd..57d0ca55 100644 --- a/test/mitmproxy/test_fuzzing.py +++ b/test/mitmproxy/test_fuzzing.py @@ -25,14 +25,4 @@ class TestFuzzy(tservers.HTTPProxyTest): p = self.pathoc() with p.connect(): resp = p.request(req % self.server.port) - assert resp.status_code == 400 - - # def test_invalid_upstream(self): - # req = r"get:'http://localhost:%s/p/200:i10,\x27+\x27'" - # p = self.pathoc() - # assert p.request(req % self.server.port).status_code == 502 - - # def test_upstream_disconnect(self): - # req = r'200:d0' - # p = self.pathod(req) - # assert p.status_code == 502 + assert resp.status_code == 400
\ No newline at end of file diff --git a/test/mitmproxy/tools/test_main.py b/test/mitmproxy/tools/test_main.py index 88e2fe86..a514df74 100644 --- a/test/mitmproxy/tools/test_main.py +++ b/test/mitmproxy/tools/test_main.py @@ -1,19 +1,25 @@ +import pytest + from mitmproxy.test import tutils from mitmproxy.tools import main shutdown_script = tutils.test_data.path("mitmproxy/data/addonscripts/shutdown.py") -def test_mitmweb(): +@pytest.mark.asyncio +async def test_mitmweb(): main.mitmweb([ "--no-web-open-browser", "-q", + "-p", "0", "-s", shutdown_script ]) -def test_mitmdump(): +@pytest.mark.asyncio +async def test_mitmdump(): main.mitmdump([ "-q", + "-p", "0", "-s", shutdown_script ]) diff --git a/test/mitmproxy/tservers.py b/test/mitmproxy/tservers.py index 0040b023..2d102a5d 100644 --- a/test/mitmproxy/tservers.py +++ b/test/mitmproxy/tservers.py @@ -2,7 +2,9 @@ import os.path import threading import tempfile import sys +import time from unittest import mock +import asyncio import mitmproxy.platform from mitmproxy.addons import core @@ -12,6 +14,7 @@ from mitmproxy import controller from mitmproxy import options from mitmproxy import exceptions from mitmproxy import io +from mitmproxy.utils import human import pathod.test import pathod.pathoc @@ -62,11 +65,6 @@ class TestState: if f not in self.flows: self.flows.append(f) - # TODO: add TCP support? - # def tcp_start(self, f): - # if f not in self.flows: - # self.flows.append(f) - class TestMaster(taddons.RecordingMaster): @@ -90,13 +88,12 @@ class TestMaster(taddons.RecordingMaster): class ProxyThread(threading.Thread): - def __init__(self, tmaster): + def __init__(self, masterclass, options): threading.Thread.__init__(self) - self.tmaster = tmaster - self.name = "ProxyThread (%s:%s)" % ( - tmaster.server.address[0], - tmaster.server.address[1], - ) + self.masterclass = masterclass + self.options = options + self.tmaster = None + self.event_loop = None controller.should_exit = False @property @@ -107,11 +104,27 @@ class ProxyThread(threading.Thread): def tlog(self): return self.tmaster.logs + def shutdown(self): + self.tmaster.shutdown() + def run(self): + self.event_loop = asyncio.new_event_loop() + asyncio.set_event_loop(self.event_loop) + self.tmaster = self.masterclass(self.options) + self.tmaster.addons.add(core.Core()) + self.name = "ProxyThread (%s)" % human.format_address(self.tmaster.server.address) self.tmaster.run() - def shutdown(self): - self.tmaster.shutdown() + def set_addons(self, *addons): + self.tmaster.reset(addons) + self.tmaster.addons.trigger("tick") + + def start(self): + super().start() + while True: + if self.tmaster: + break + time.sleep(0.01) class ProxyTestBase: @@ -132,9 +145,7 @@ class ProxyTestBase: ssloptions=cls.ssloptions) cls.options = cls.get_options() - tmaster = cls.masterclass(cls.options) - tmaster.addons.add(core.Core()) - cls.proxy = ProxyThread(tmaster) + cls.proxy = ProxyThread(cls.masterclass, cls.options) cls.proxy.start() @classmethod @@ -173,6 +184,9 @@ class ProxyTestBase: ssl_insecure=True, ) + def set_addons(self, *addons): + self.proxy.set_addons(*addons) + def addons(self): """ Can be over-ridden to add a standard set of addons to tests. @@ -327,8 +341,7 @@ class SocksModeTest(HTTPProxyTest): return opts -class ChainProxyTest(ProxyTestBase): - +class HTTPUpstreamProxyTest(HTTPProxyTest): """ Chain three instances of mitmproxy in a row to test upstream mode. Proxy order is cls.proxy -> cls.chain[0] -> cls.chain[1] @@ -344,11 +357,12 @@ class ChainProxyTest(ProxyTestBase): cls.chain = [] for _ in range(cls.n): opts = cls.get_options() - tmaster = cls.masterclass(opts) - tmaster.addons.add(core.Core()) - proxy = ProxyThread(tmaster) + proxy = ProxyThread(cls.masterclass, opts) proxy.start() cls.chain.insert(0, proxy) + while True: + if proxy.event_loop and proxy.event_loop.is_running(): + break super().setup_class() @@ -372,7 +386,3 @@ class ChainProxyTest(ProxyTestBase): mode="upstream:" + s, ) return opts - - -class HTTPUpstreamProxyTest(ChainProxyTest, HTTPProxyTest): - pass |