From ef1904bc5216e2d90f167250442df022adfd17d6 Mon Sep 17 00:00:00 2001 From: Brian Warner Date: Thu, 23 Feb 2017 17:29:56 -0800 Subject: [PATCH] get null test working (open and immediate close) --- docs/boss.dot | 2 ++ docs/mailbox.dot | 9 --------- src/wormhole/_boss.py | 26 ++++++++++++++++++------ src/wormhole/_interfaces.py | 2 ++ src/wormhole/_mailbox.py | 14 +++---------- src/wormhole/_rendezvous.py | 2 +- src/wormhole/test/test_wormhole_new.py | 28 ++++++++++++++++++++++++++ src/wormhole/timing.py | 3 +++ src/wormhole/wormhole.py | 19 +++++++++++------ 9 files changed, 72 insertions(+), 33 deletions(-) create mode 100644 src/wormhole/test/test_wormhole_new.py diff --git a/docs/boss.dot b/docs/boss.dot index 03062d3..8b34fc3 100644 --- a/docs/boss.dot +++ b/docs/boss.dot @@ -17,6 +17,8 @@ digraph { S0 [label="S0: empty"] S0 -> P0_build [label="set_code"] + S0 -> P_close_lonely [label="close"] + P0_build [shape="box" label="W.got_code\nM.set_nameplate\nK.got_code"] P0_build -> S1 S1 [label="S1: lonely" color="orange"] diff --git a/docs/mailbox.dot b/docs/mailbox.dot index 1353a14..881c617 100644 --- a/docs/mailbox.dot +++ b/docs/mailbox.dot @@ -1,17 +1,8 @@ digraph { /* new idea */ - {rank=same; title entry_whole_code entry_allocation entry_interactive} - entry_whole_code [label="whole\ncode"] - entry_whole_code -> S0A title [label="Message\nMachine" style="dotted"] - entry_allocation [label="allocation" color="orange"] - entry_allocation -> S0B [label="(already\nconnected)" - color="orange" fontcolor="orange"] - entry_interactive [label="interactive" color="orange"] - entry_interactive -> S0B [color="orange"] - {rank=same; S0A P0_connected S0B} S0A [label="S0A:\nknow nothing"] S0B [label="S0B:\nknow nothing\n(bound)" color="orange"] diff --git a/src/wormhole/_boss.py b/src/wormhole/_boss.py index 22f28eb..6065bfc 100644 --- a/src/wormhole/_boss.py +++ b/src/wormhole/_boss.py @@ -16,6 +16,7 @@ from .util import bytes_to_dict @attrs @implementer(_interfaces.IBoss) class Boss(object): + _W = attrib() _side = attrib(validator=instance_of(type(u""))) _url = attrib(validator=instance_of(type(u""))) _appid = attrib(validator=instance_of(type(u""))) @@ -24,14 +25,15 @@ class Boss(object): _timing = attrib(validator=provides(_interfaces.ITiming)) m = MethodicalMachine() - def __init__(self, wormhole): - self._W = wormhole + def __attrs_post_init__(self): self._M = Mailbox(self._side) self._S = Send(self._side, self._timing) self._O = Order(self._side, self._timing) self._K = Key(self._timing) self._R = Receive(self._side, self._timing) - self._RC = RendezvousConnector(self._side, self._timing, self._reactor) + self._RC = RendezvousConnector(self._url, self._appid, self._side, + self._reactor, self._journal, + self._timing) self._NL = NameplateListing() self._C = Code(self._timing) @@ -44,6 +46,10 @@ class Boss(object): self._NL.wire(self._RC, self._C) self._C.wire(self, self._RC, self._NL) + self._next_tx_phase = 0 + self._next_rx_phase = 0 + self._rx_phases = {} # phase -> plaintext + # these methods are called from outside def start(self): self._RC.start() @@ -82,7 +88,7 @@ class Boss(object): self._C.set_code(code) @m.input() - def send(self, phase, plaintext): pass + def send(self, plaintext): pass @m.input() def close(self): pass @@ -127,7 +133,9 @@ class Boss(object): # ignored for now @m.output() - def S_send(self, phase, plaintext): + def S_send(self, plaintext): + phase = self._next_tx_phase + self._next_tx_phase += 1 self._S.send(phase, plaintext) @m.output() @@ -145,13 +153,19 @@ class Boss(object): self._W.got_verifier(verifier) @m.output() def W_received(self, phase, plaintext): - self._W.received(phase, plaintext) + # we call Wormhole.received() in strict phase order, with no gaps + self._rx_phases[phase] = plaintext + while self._next_rx_phase in self._rx_phases: + self._W.received(self._next_rx_phase, + self._rx_phases.pop(self._next_rx_phase)) + self._next_rx_phase += 1 @m.output() def W_closed(self): result = "???" self._W.closed(result) + S0_empty.upon(close, enter=S3_closing, outputs=[close_lonely]) S0_empty.upon(send, enter=S0_empty, outputs=[S_send]) S0_empty.upon(got_code, enter=S1_lonely, outputs=[do_got_code]) S1_lonely.upon(happy, enter=S2_happy, outputs=[]) diff --git a/src/wormhole/_interfaces.py b/src/wormhole/_interfaces.py index b8abf49..ae8b459 100644 --- a/src/wormhole/_interfaces.py +++ b/src/wormhole/_interfaces.py @@ -1,5 +1,7 @@ from zope.interface import Interface +class IWormhole(Interface): + pass class IBoss(Interface): pass class IMailbox(Interface): diff --git a/src/wormhole/_mailbox.py b/src/wormhole/_mailbox.py index 5469806..1aec665 100644 --- a/src/wormhole/_mailbox.py +++ b/src/wormhole/_mailbox.py @@ -22,15 +22,12 @@ class Mailbox(object): self._RC = _interfaces.IRendezvousConnector(rendezvous_connector) self._O = _interfaces.IOrder(ordering) - @m.state(initial=True) - def initial(self): pass - # all -A states: not connected # all -B states: yes connected # B states serialize as A, so they deserialize as unconnected # S0: know nothing - @m.state() + @m.state(initial=True) def S0A(self): pass @m.state() def S0B(self): pass @@ -87,11 +84,6 @@ class Mailbox(object): def Ss(self): pass - @m.input() - def start_unconnected(self): pass - @m.input() - def start_connected(self): pass - # from Boss @m.input() def set_nameplate(self, nameplate): pass @@ -211,12 +203,12 @@ class Mailbox(object): @m.output() def RC_stop(self): self._RC_stop() + def _RC_stop(self): + self._RC.stop() @m.output() def W_closed(self): self._B.closed() - initial.upon(start_unconnected, enter=S0A, outputs=[]) - initial.upon(start_connected, enter=S0B, outputs=[]) S0A.upon(connected, enter=S0B, outputs=[]) S0A.upon(set_nameplate, enter=S1A, outputs=[record_nameplate]) S0A.upon(add_message, enter=S0A, outputs=[queue]) diff --git a/src/wormhole/_rendezvous.py b/src/wormhole/_rendezvous.py index 4a955b8..769cb25 100644 --- a/src/wormhole/_rendezvous.py +++ b/src/wormhole/_rendezvous.py @@ -61,7 +61,7 @@ class RendezvousConnector(object): _journal = attrib(validator=provides(_interfaces.IJournal)) _timing = attrib(validator=provides(_interfaces.ITiming)) - def __init__(self): + def __attrs_post_init__(self): self._ws = None f = WSFactory(self, self._url) f.setProtocolOptions(autoPingInterval=60, autoPingTimeout=600) diff --git a/src/wormhole/test/test_wormhole_new.py b/src/wormhole/test/test_wormhole_new.py new file mode 100644 index 0000000..821001b --- /dev/null +++ b/src/wormhole/test/test_wormhole_new.py @@ -0,0 +1,28 @@ +from __future__ import print_function, unicode_literals +from twisted.trial import unittest +from twisted.internet import reactor +from .common import ServerBase +from .. import wormhole + +APPID = "appid" + +class Delegate: + def __init__(self): + self.code = None + self.verifier = None + self.messages = [] + self.closed = None + def wormhole_got_code(self, code): + self.code = code + def wormhole_got_verifier(self, verifier): + self.verifier = verifier + def wormhole_receive(self, data): + self.messages.append(data) + def wormhole_closed(self, result): + self.closed = result + +class New(ServerBase, unittest.TestCase): + def test_basic(self): + dg = Delegate() + w = wormhole.delegated_wormhole(APPID, self.relayurl, reactor, dg) + w.close() diff --git a/src/wormhole/timing.py b/src/wormhole/timing.py index 0ecf1bc..8cb18e5 100644 --- a/src/wormhole/timing.py +++ b/src/wormhole/timing.py @@ -1,5 +1,7 @@ from __future__ import print_function, absolute_import, unicode_literals import json, time +from zope.interface import implementer +from ._interfaces import ITiming class Event: def __init__(self, name, when, **details): @@ -33,6 +35,7 @@ class Event: else: self.finish() +@implementer(ITiming) class DebugTiming: def __init__(self): self._events = [] diff --git a/src/wormhole/wormhole.py b/src/wormhole/wormhole.py index 5351bb0..c37bad8 100644 --- a/src/wormhole/wormhole.py +++ b/src/wormhole/wormhole.py @@ -1,6 +1,10 @@ from __future__ import print_function, absolute_import, unicode_literals -import sys +import os, sys from attr import attrs, attrib +from zope.interface import implementer +from twisted.internet import defer +from ._interfaces import IWormhole +from .util import bytes_to_hexstr from .timing import DebugTiming from .journal import ImmediateJournal from ._boss import Boss @@ -16,6 +20,7 @@ from ._boss import Boss # w = wormhole(delegate=app) # w.send(data) # app.wormhole_got_code(code) +# app.wormhole_got_verifier(verifier) # app.wormhole_receive(data) # w.close() # app.wormhole_closed() @@ -25,6 +30,7 @@ from ._boss import Boss # delegate_args=(args, kwargs)) @attrs +@implementer(IWormhole) class _DelegatedWormhole(object): _delegate = attrib() @@ -32,8 +38,8 @@ class _DelegatedWormhole(object): self._boss = boss # from above - def send(self, phase, plaintext): - self._boss.send(phase, plaintext) + def send(self, plaintext): + self._boss.send(plaintext) def close(self): self._boss.close() @@ -48,6 +54,7 @@ class _DelegatedWormhole(object): def closed(self, result): self._delegate.wormhole_closed(result) +@implementer(IWormhole) class _DeferredWormhole(object): def __init__(self): self._code = None @@ -73,8 +80,8 @@ class _DeferredWormhole(object): self._verifier_observers.append(d) return d - def send(self, phase, plaintext): - self._boss.send(phase, plaintext) + def send(self, plaintext): + self._boss.send(plaintext) def close(self): self._boss.close() @@ -130,5 +137,5 @@ def deferred_wormhole(appid, relay_url, reactor, journal=None, stderr=sys.stderr, ): - return _wormhole(appid, relay_url, reactor, delegate=None, + return _wormhole(appid, relay_url, reactor, None, tor_manager, timing, journal, stderr)