protocols: docs++, minor test improvements

This commit is contained in:
Maximilian Hils 2017-07-24 18:11:37 +02:00
parent 2679387849
commit 6d59d213e3
2 changed files with 34 additions and 38 deletions

View File

@ -88,36 +88,6 @@ def test_simple_explicit(tctx):
assert list(layer.handle_event(events.HookReply(tcp_end, None))) == [] assert list(layer.handle_event(events.HookReply(tcp_end, None))) == []
r'''
def test_simple_alternate_syntax(tctx):
"""
Some alternate syntax experimentations:
- no asserts, evaluate when we reach a command or the end.
- use <= for final statement
- If the final statement is a hook, its data is returned.
This replaces placeholders (we must do partial matching on the first <= hook though)
"""
playbook = tutils.playbook(tcp.TCPLayer(tctx))
flow = (playbook
<< commands.Hook("tcp_start", mock.Mock())
>> events.HookReply(-1, None)
<< commands.OpenConnection(tctx.server)
>> events.OpenConnectionReply(-1, None)
>> events.DataReceived(tctx.client, b"hello!")
<= commands.Hook("tcp_message", None))
assert flow.messages[0].content == b"hello!"
(playbook
>> events.HookReply(-1, None)
<< commands.SendData(tctx.server, b"hello!")
>> events.ConnectionClosed(tctx.server)
<< commands.CloseConnection(tctx.client)
<< commands.Hook("tcp_end", flow)
>> events.HookReply(-1, None)
<= None)
'''
def test_receive_data_before_server_connected(tctx): def test_receive_data_before_server_connected(tctx):
""" """
assert that data received before a server connection is established assert that data received before a server connection is established
@ -135,18 +105,26 @@ def test_receive_data_before_server_connected(tctx):
>> events.HookReply(-1, None) >> events.HookReply(-1, None)
<< commands.SendData(tctx.server, b"hello!") << commands.SendData(tctx.server, b"hello!")
) )
assert f().messages
def test_receive_data_after_server_disconnected(tctx): def test_receive_data_after_server_disconnected(tctx):
""" """
this should just be discarded. data received after a connection has been closed should just be discarded.
""" """
f = tutils.Placeholder()
assert ( assert (
tutils.playbook(tcp.TCPLayer(tctx, True)) tutils.playbook(tcp.TCPLayer(tctx))
<< commands.Hook("tcp_start", f)
>> events.HookReply(-1, None)
<< commands.OpenConnection(tctx.server) << commands.OpenConnection(tctx.server)
>> events.OpenConnectionReply(-1, None) >> events.OpenConnectionReply(-1, None)
>> events.ConnectionClosed(tctx.server) >> events.ConnectionClosed(tctx.server)
<< commands.CloseConnection(tctx.client) << commands.CloseConnection(tctx.client)
<< commands.Hook("tcp_end", f)
>> events.HookReply(-1, None)
>> events.DataReceived(tctx.client, b"i'm late") >> events.DataReceived(tctx.client, b"i'm late")
<< None << None
) )
# not included here as it has not been sent to the server.
assert not f().messages

View File

@ -3,8 +3,6 @@ import difflib
import itertools import itertools
import typing import typing
import re
from mitmproxy.proxy.protocol2 import commands from mitmproxy.proxy.protocol2 import commands
from mitmproxy.proxy.protocol2 import events from mitmproxy.proxy.protocol2 import events
from mitmproxy.proxy.protocol2 import layer from mitmproxy.proxy.protocol2 import layer
@ -124,8 +122,9 @@ class playbook:
self._errored = True self._errored = True
def _str(x): def _str(x):
x_str = re.sub(r'Placeholder\((.*?)\)', r'\1', str(x)) arrow = ">" if isinstance(x, events.Event) else "<"
return f"{'>' if isinstance(x, events.Event) else '<'} {x_str}" x = str(x).replace('Placeholder:', '')
return f"{arrow} {x}"
diff = "\n".join(difflib.ndiff( diff = "\n".join(difflib.ndiff(
[_str(x) for x in self.expected], [_str(x) for x in self.expected],
@ -136,15 +135,34 @@ class playbook:
return True return True
def __del__(self): def __del__(self):
# Playbooks are only executed on assert (which signals that the playbook is partially
# complete), so we need to signal if someone forgets to assert and playbooks aren't
# evaluated.
if not self._errored and len(self.actual) < len(self.expected): if not self._errored and len(self.actual) < len(self.expected):
raise RuntimeError("Unfinished playbook!") raise RuntimeError("Unfinished playbook!")
def fork(self): def fork(self):
"""
Fork the current playbook to assert a second execution stream from here on.
Returns a new playbook instance.
"""
return copy.deepcopy(self) return copy.deepcopy(self)
class Placeholder: class Placeholder:
"""Placeholder value in playbooks, so that flows can be referenced before they are initialized.""" """
Placeholder value in playbooks, so that objects (flows in particular) can be referenced before
they are known. Example:
f = Placeholder()
assert (
playbook(tcp.TCPLayer(tctx))
<< commands.Hook("tcp_start", f) # the flow object returned here is generated by the layer.
)
# We can obtain the flow object now using f():
assert f().messages == 0
"""
def __init__(self): def __init__(self):
self.obj = None self.obj = None
@ -154,4 +172,4 @@ class Placeholder:
return self.obj return self.obj
def __repr__(self): def __repr__(self):
return f"Placeholder({repr(self.obj)})" return f"Placeholder:{repr(self.obj)}"