diff --git a/src/wormhole/test/test_wormhole.py b/src/wormhole/test/test_wormhole.py index 99dee58..fc329d6 100644 --- a/src/wormhole/test/test_wormhole.py +++ b/src/wormhole/test/test_wormhole.py @@ -1,20 +1,14 @@ from __future__ import print_function, unicode_literals -import os, json, re, gc, io -from binascii import hexlify, unhexlify +import json, io, re import mock from twisted.trial import unittest from twisted.internet import reactor -from twisted.internet.defer import Deferred, gatherResults, inlineCallbacks +from twisted.internet.defer import gatherResults, inlineCallbacks from .common import ServerBase from .. import wormhole, _rendezvous -from ..errors import (WrongPasswordError, WelcomeError, InternalError, +from ..errors import (WrongPasswordError, KeyFormatError, WormholeClosed, LonelyError, NoKeyError, OnlyOneCodeError) -from spake2 import SPAKE2_Symmetric -from ..timing import DebugTiming -from ..util import (bytes_to_dict, dict_to_bytes, - hexstr_to_bytes, bytes_to_hexstr) -from nacl.secret import SecretBox APPID = "appid" @@ -53,587 +47,6 @@ class Welcome(unittest.TestCase): ("Server (at relay_url) says:\n message of\n the day\n" "Server (at relay_url) says:\n second message\n")) -class Basic(unittest.TestCase): - def tearDown(self): - # flush out any errorful Deferreds left dangling in cycles - gc.collect() - - def check_out(self, out, **kwargs): - # Assert that each kwarg is present in the 'out' dict. Ignore other - # keys ('msgid' in particular) - for key, value in kwargs.items(): - self.assertIn(key, out) - self.assertEqual(out[key], value, (out, key, value)) - - def check_outbound(self, ws, types): - out = ws.outbound() - self.assertEqual(len(out), len(types), (out, types)) - for i,t in enumerate(types): - self.assertEqual(out[i]["type"], t, (i,t,out)) - return out - - def make_pake(self, code, side, msg1): - sp2 = SPAKE2_Symmetric(wormhole.to_bytes(code), - idSymmetric=wormhole.to_bytes(APPID)) - msg2 = sp2.start() - key = sp2.finish(msg1) - return key, msg2 - - def test_create(self): - wormhole._Wormhole(APPID, "relay_url", reactor, None, None, None) - - def test_basic(self): - # We don't call w._start(), so this doesn't create a WebSocket - # connection. We provide a mock connection instead. If we wanted to - # exercise _connect, we'd mock out WSFactory. - # w._connect = lambda self: None - # w._event_connected(mock_ws) - # w._event_ws_opened() - # w._ws_dispatch_response(payload) - - timing = DebugTiming() - with mock.patch("wormhole.wormhole._WelcomeHandler") as wh_c: - w = wormhole._Wormhole(APPID, "relay_url", reactor, None, timing, - None) - wh = wh_c.return_value - self.assertEqual(w._ws_url, "relay_url") - self.assertTrue(w._flag_need_nameplate) - self.assertTrue(w._flag_need_to_build_msg1) - self.assertTrue(w._flag_need_to_send_PAKE) - - v = w.verify() - - w._drop_connection = mock.Mock() - ws = MockWebSocket() - w._event_connected(ws) - out = ws.outbound() - self.assertEqual(len(out), 0) - - w._event_ws_opened(None) - out = ws.outbound() - self.assertEqual(len(out), 1) - self.check_out(out[0], type="bind", appid=APPID, side=w._side) - self.assertIn("id", out[0]) - - # WelcomeHandler should get called upon 'welcome' response. Its full - # behavior is exercised in 'Welcome' above. - WELCOME = {"foo": "bar"} - response(w, type="welcome", welcome=WELCOME) - self.assertEqual(wh.mock_calls, [mock.call.handle_welcome(WELCOME)]) - - # because we're connected, setting the code also claims the mailbox - CODE = "123-foo-bar" - w.set_code(CODE) - self.assertFalse(w._flag_need_to_build_msg1) - out = ws.outbound() - self.assertEqual(len(out), 1) - self.check_out(out[0], type="claim", nameplate="123") - - # the server reveals the linked mailbox - response(w, type="claimed", mailbox="mb456") - - # that triggers event_learned_mailbox, which should send open() and - # PAKE - self.assertEqual(w._mailbox_state, wormhole.OPEN) - out = ws.outbound() - self.assertEqual(len(out), 2) - self.check_out(out[0], type="open", mailbox="mb456") - self.check_out(out[1], type="add", phase="pake") - self.assertNoResult(v) - - # server echoes back all "add" messages - response(w, type="message", phase="pake", body=out[1]["body"], - side=w._side) - self.assertNoResult(v) - - # extract our outbound PAKE message - body = bytes_to_dict(hexstr_to_bytes(out[1]["body"])) - msg1 = hexstr_to_bytes(body["pake_v1"]) - - # next we build the simulated peer's PAKE operation - side2 = w._side + "other" - key, msg2 = self.make_pake(CODE, side2, msg1) - payload = {"pake_v1": bytes_to_hexstr(msg2)} - body_hex = bytes_to_hexstr(dict_to_bytes(payload)) - response(w, type="message", phase="pake", body=body_hex, side=side2) - - # hearing the peer's PAKE (msg2) makes us release the nameplate, send - # the confirmation message, and sends any queued phase messages. It - # doesn't deliver the verifier because we're still waiting on the - # confirmation message. - self.assertFalse(w._flag_need_to_see_mailbox_used) - self.assertEqual(w._key, key) - out = ws.outbound() - self.assertEqual(len(out), 2, out) - self.check_out(out[0], type="release") - self.check_out(out[1], type="add", phase="version") - self.assertNoResult(v) - - # hearing a valid confirmation message doesn't throw an error - plaintext = json.dumps({}).encode("utf-8") - data_key = w._derive_phase_key(side2, "version") - confmsg = w._encrypt_data(data_key, plaintext) - version2_hex = hexlify(confmsg).decode("ascii") - response(w, type="message", phase="version", body=version2_hex, - side=side2) - - # and it releases the verifier - verifier = self.successResultOf(v) - self.assertEqual(verifier, - w.derive_key("wormhole:verifier", SecretBox.KEY_SIZE)) - - # an outbound message can now be sent immediately - w.send(b"phase0-outbound") - out = ws.outbound() - self.assertEqual(len(out), 1) - self.check_out(out[0], type="add", phase="0") - # decrypt+check the outbound message - p0_outbound = unhexlify(out[0]["body"].encode("ascii")) - msgkey0 = w._derive_phase_key(w._side, "0") - p0_plaintext = w._decrypt_data(msgkey0, p0_outbound) - self.assertEqual(p0_plaintext, b"phase0-outbound") - - # get() waits for the inbound message to arrive - md = w.get() - self.assertNoResult(md) - self.assertIn("0", w._receive_waiters) - self.assertNotIn("0", w._received_messages) - msgkey1 = w._derive_phase_key(side2, "0") - p0_inbound = w._encrypt_data(msgkey1, b"phase0-inbound") - p0_inbound_hex = hexlify(p0_inbound).decode("ascii") - response(w, type="message", phase="0", body=p0_inbound_hex, - side=side2) - p0_in = self.successResultOf(md) - self.assertEqual(p0_in, b"phase0-inbound") - self.assertNotIn("0", w._receive_waiters) - self.assertIn("0", w._received_messages) - - # receiving an inbound message will queue it until get() is called - msgkey2 = w._derive_phase_key(side2, "1") - p1_inbound = w._encrypt_data(msgkey2, b"phase1-inbound") - p1_inbound_hex = hexlify(p1_inbound).decode("ascii") - response(w, type="message", phase="1", body=p1_inbound_hex, - side=side2) - self.assertIn("1", w._received_messages) - self.assertNotIn("1", w._receive_waiters) - p1_in = self.successResultOf(w.get()) - self.assertEqual(p1_in, b"phase1-inbound") - self.assertIn("1", w._received_messages) - self.assertNotIn("1", w._receive_waiters) - - d = w.close() - self.assertNoResult(d) - out = ws.outbound() - self.assertEqual(len(out), 1) - self.check_out(out[0], type="close", mood="happy") - self.assertEqual(w._drop_connection.mock_calls, []) - - response(w, type="released") - self.assertEqual(w._drop_connection.mock_calls, []) - response(w, type="closed") - self.assertEqual(w._drop_connection.mock_calls, [mock.call()]) - w._ws_closed(True, None, None) - self.assertEqual(self.successResultOf(d), None) - - def test_close_wait_0(self): - # Close before the connection is established. The connection still - # gets established, but it is then torn down before sending anything. - timing = DebugTiming() - w = wormhole._Wormhole(APPID, "relay_url", reactor, None, timing, None) - w._drop_connection = mock.Mock() - - d = w.close() - self.assertNoResult(d) - - ws = MockWebSocket() - w._event_connected(ws) - w._event_ws_opened(None) - self.assertEqual(w._drop_connection.mock_calls, [mock.call()]) - self.assertNoResult(d) - - w._ws_closed(True, None, None) - self.successResultOf(d) - - def test_close_wait_1(self): - # close before even claiming the nameplate - timing = DebugTiming() - w = wormhole._Wormhole(APPID, "relay_url", reactor, None, timing, None) - w._drop_connection = mock.Mock() - ws = MockWebSocket() - w._event_connected(ws) - w._event_ws_opened(None) - - d = w.close() - self.check_outbound(ws, ["bind"]) - self.assertNoResult(d) - self.assertEqual(w._drop_connection.mock_calls, [mock.call()]) - self.assertNoResult(d) - - w._ws_closed(True, None, None) - self.successResultOf(d) - - def test_close_wait_2(self): - # Close after claiming the nameplate, but before opening the mailbox. - # The 'claimed' response arrives before we close. - timing = DebugTiming() - w = wormhole._Wormhole(APPID, "relay_url", reactor, None, timing, None) - w._drop_connection = mock.Mock() - ws = MockWebSocket() - w._event_connected(ws) - w._event_ws_opened(None) - CODE = "123-foo-bar" - w.set_code(CODE) - self.check_outbound(ws, ["bind", "claim"]) - - response(w, type="claimed", mailbox="mb123") - - d = w.close() - self.check_outbound(ws, ["open", "add", "release", "close"]) - self.assertNoResult(d) - self.assertEqual(w._drop_connection.mock_calls, []) - - response(w, type="released") - self.assertNoResult(d) - self.assertEqual(w._drop_connection.mock_calls, []) - - response(w, type="closed") - self.assertEqual(w._drop_connection.mock_calls, [mock.call()]) - self.assertNoResult(d) - - w._ws_closed(True, None, None) - self.successResultOf(d) - - def test_close_wait_3(self): - # close after claiming the nameplate, but before opening the mailbox - # The 'claimed' response arrives after we start to close. - timing = DebugTiming() - w = wormhole._Wormhole(APPID, "relay_url", reactor, None, timing, None) - w._drop_connection = mock.Mock() - ws = MockWebSocket() - w._event_connected(ws) - w._event_ws_opened(None) - CODE = "123-foo-bar" - w.set_code(CODE) - self.check_outbound(ws, ["bind", "claim"]) - - d = w.close() - response(w, type="claimed", mailbox="mb123") - self.check_outbound(ws, ["release"]) - self.assertNoResult(d) - self.assertEqual(w._drop_connection.mock_calls, []) - - response(w, type="released") - self.assertEqual(w._drop_connection.mock_calls, [mock.call()]) - self.assertNoResult(d) - - w._ws_closed(True, None, None) - self.successResultOf(d) - - def test_close_wait_4(self): - # close after both claiming the nameplate and opening the mailbox - timing = DebugTiming() - w = wormhole._Wormhole(APPID, "relay_url", reactor, None, timing, None) - w._drop_connection = mock.Mock() - ws = MockWebSocket() - w._event_connected(ws) - w._event_ws_opened(None) - CODE = "123-foo-bar" - w.set_code(CODE) - response(w, type="claimed", mailbox="mb456") - self.check_outbound(ws, ["bind", "claim", "open", "add"]) - - d = w.close() - self.check_outbound(ws, ["release", "close"]) - self.assertNoResult(d) - self.assertEqual(w._drop_connection.mock_calls, []) - - response(w, type="released") - self.assertNoResult(d) - self.assertEqual(w._drop_connection.mock_calls, []) - - response(w, type="closed") - self.assertNoResult(d) - self.assertEqual(w._drop_connection.mock_calls, [mock.call()]) - - w._ws_closed(True, None, None) - self.successResultOf(d) - - def test_close_wait_5(self): - # close after claiming the nameplate, opening the mailbox, then - # releasing the nameplate - timing = DebugTiming() - w = wormhole._Wormhole(APPID, "relay_url", reactor, None, timing, None) - w._drop_connection = mock.Mock() - ws = MockWebSocket() - w._event_connected(ws) - w._event_ws_opened(None) - CODE = "123-foo-bar" - w.set_code(CODE) - response(w, type="claimed", mailbox="mb456") - - w._key = b"" - msgkey = w._derive_phase_key("side2", "misc") - p1_inbound = w._encrypt_data(msgkey, b"") - p1_inbound_hex = hexlify(p1_inbound).decode("ascii") - response(w, type="message", phase="misc", side="side2", - body=p1_inbound_hex) - self.check_outbound(ws, ["bind", "claim", "open", "add", - "release"]) - - d = w.close() - self.check_outbound(ws, ["close"]) - self.assertNoResult(d) - self.assertEqual(w._drop_connection.mock_calls, []) - - response(w, type="released") - self.assertNoResult(d) - self.assertEqual(w._drop_connection.mock_calls, []) - - response(w, type="closed") - self.assertNoResult(d) - self.assertEqual(w._drop_connection.mock_calls, [mock.call()]) - - w._ws_closed(True, None, None) - self.successResultOf(d) - - def test_close_errbacks(self): - # make sure the Deferreds returned by verify() and get() are properly - # errbacked upon close - pass - - def test_get_code_mock(self): - timing = DebugTiming() - w = wormhole._Wormhole(APPID, "relay_url", reactor, None, timing, None) - ws = MockWebSocket() # TODO: mock w._ws_send_command instead - w._event_connected(ws) - w._event_ws_opened(None) - self.check_outbound(ws, ["bind"]) - - gc_c = mock.Mock() - gc = gc_c.return_value = mock.Mock() - gc_d = gc.go.return_value = Deferred() - with mock.patch("wormhole.wormhole._GetCode", gc_c): - d = w.get_code() - self.assertNoResult(d) - - gc_d.callback("123-foo-bar") - code = self.successResultOf(d) - self.assertEqual(code, "123-foo-bar") - - def test_get_code_real(self): - timing = DebugTiming() - w = wormhole._Wormhole(APPID, "relay_url", reactor, None, timing, None) - ws = MockWebSocket() - w._event_connected(ws) - w._event_ws_opened(None) - self.check_outbound(ws, ["bind"]) - - d = w.get_code() - - out = ws.outbound() - self.assertEqual(len(out), 1) - self.check_out(out[0], type="allocate") - # TODO: nameplate attributes go here - self.assertNoResult(d) - - response(w, type="allocated", nameplate="123") - code = self.successResultOf(d) - self.assertIsInstance(code, type("")) - self.assert_(code.startswith("123-")) - pieces = code.split("-") - self.assertEqual(len(pieces), 3) # nameplate plus two words - self.assert_(re.search(r'^\d+-\w+-\w+$', code), code) - - def _test_establish_key_hook(self, established, before): - timing = DebugTiming() - w = wormhole._Wormhole(APPID, "relay_url", reactor, None, timing, None) - - if before: - d = w.establish_key() - - if established is True: - w._key = b"key" - elif established is False: - w._key = None - else: - w._key = b"key" - w._error = WelcomeError() - - if not before: - d = w.establish_key() - else: - w._maybe_notify_key() - - if w._key is not None and established is True: - self.successResultOf(d) - elif established is False: - self.assertNot(d.called) - else: - self.failureResultOf(d) - - def test_establish_key_hook(self): - for established in (True, False, "error"): - for before in (True, False): - self._test_establish_key_hook(established, before) - - def test_establish_key_twice(self): - timing = DebugTiming() - w = wormhole._Wormhole(APPID, "relay_url", reactor, None, timing, None) - d = w.establish_key() - self.assertRaises(InternalError, w.establish_key) - del d - - # make sure verify() can be called both before and after the verifier is - # computed - - def _test_verifier(self, when, order, success): - assert when in ("early", "middle", "late") - assert order in ("key-then-version", "version-then-key") - assert isinstance(success, bool) - #print(when, order, success) - - timing = DebugTiming() - w = wormhole._Wormhole(APPID, "relay_url", reactor, None, timing, None) - w._drop_connection = mock.Mock() - w._ws_send_command = mock.Mock() - w._mailbox_state = wormhole.OPEN - side2 = "side2" - d = None - - if success: - w._key = b"key" - else: - w._key = b"wrongkey" - plaintext = json.dumps({}).encode("utf-8") - data_key = w._derive_phase_key(side2, "version") - confmsg = w._encrypt_data(data_key, plaintext) - w._key = None - - if when == "early": - d = w.verify() - self.assertNoResult(d) - - if order == "key-then-version": - w._key = b"key" - w._event_established_key() - else: - w._event_received_version(side2, confmsg) - - if when == "middle": - d = w.verify() - if d: - self.assertNoResult(d) # still waiting for other msg - - if order == "version-then-key": - w._key = b"key" - w._event_established_key() - else: - w._event_received_version(side2, confmsg) - - if when == "late": - d = w.verify() - if success: - self.successResultOf(d) - else: - self.assertFailure(d, wormhole.WrongPasswordError) - self.flushLoggedErrors(WrongPasswordError) - - def test_verifier(self): - for when in ("early", "middle", "late"): - for order in ("key-then-version", "version-then-key"): - for success in (False, True): - self._test_verifier(when, order, success) - - - def test_api_errors(self): - # doing things you're not supposed to do - pass - - def test_welcome_error(self): - # A welcome message could arrive at any time, with an [error] key - # that should make us halt. In practice, though, this gets sent as - # soon as the connection is established, which limits the possible - # states in which we might see it. - - timing = DebugTiming() - w = wormhole._Wormhole(APPID, "relay_url", reactor, None, timing, None) - w._drop_connection = mock.Mock() - ws = MockWebSocket() - w._event_connected(ws) - w._event_ws_opened(None) - self.check_outbound(ws, ["bind"]) - - d1 = w.get() - d2 = w.verify() - d3 = w.get_code() - # TODO (tricky): test w.input_code - - self.assertNoResult(d1) - self.assertNoResult(d2) - self.assertNoResult(d3) - - w._signal_error(WelcomeError("you are not actually welcome"), "pouty") - self.failureResultOf(d1, WelcomeError) - self.failureResultOf(d2, WelcomeError) - self.failureResultOf(d3, WelcomeError) - - # once the error is signalled, all API calls should fail - self.assertRaises(WelcomeError, w.send, "foo") - self.assertRaises(WelcomeError, - w.derive_key, "foo", SecretBox.KEY_SIZE) - self.failureResultOf(w.get(), WelcomeError) - self.failureResultOf(w.verify(), WelcomeError) - - def test_version_error(self): - # we should only receive the "version" message after we receive the - # PAKE message, by which point we should know the key. If the - # confirmation message doesn't decrypt, we signal an error. - timing = DebugTiming() - w = wormhole._Wormhole(APPID, "relay_url", reactor, None, timing, None) - w._drop_connection = mock.Mock() - ws = MockWebSocket() - w._event_connected(ws) - w._event_ws_opened(None) - w.set_code("123-foo-bar") - response(w, type="claimed", mailbox="mb456") - - d1 = w.get() - d2 = w.verify() - self.assertNoResult(d1) - self.assertNoResult(d2) - - out = ws.outbound() - # ["bind", "claim", "open", "add"] - self.assertEqual(len(out), 4) - self.assertEqual(out[3]["type"], "add") - - sp2 = SPAKE2_Symmetric(b"", idSymmetric=wormhole.to_bytes(APPID)) - msg2 = sp2.start() - payload = {"pake_v1": bytes_to_hexstr(msg2)} - body_hex = bytes_to_hexstr(dict_to_bytes(payload)) - response(w, type="message", phase="pake", body=body_hex, side="s2") - self.assertNoResult(d1) - self.assertNoResult(d2) # verify() waits for confirmation - - # sending a random version message will cause a confirmation error - confkey = w.derive_key("WRONG", SecretBox.KEY_SIZE) - nonce = os.urandom(wormhole.CONFMSG_NONCE_LENGTH) - badversion = wormhole.make_confmsg(confkey, nonce) - badversion_hex = hexlify(badversion).decode("ascii") - response(w, type="message", phase="version", body=badversion_hex, - side="s2") - - self.failureResultOf(d1, WrongPasswordError) - self.failureResultOf(d2, WrongPasswordError) - - # once the error is signalled, all API calls should fail - self.assertRaises(WrongPasswordError, w.send, "foo") - self.assertRaises(WrongPasswordError, - w.derive_key, "foo", SecretBox.KEY_SIZE) - self.failureResultOf(w.get(), WrongPasswordError) - self.failureResultOf(w.verify(), WrongPasswordError) -Basic.skip = "being replaced by test_wormhole_new" - # event orderings to exercise: # # * normal sender: set_code, send_phase1, connected, claimed, learn_msg2, @@ -645,27 +58,105 @@ Basic.skip = "being replaced by test_wormhole_new" # * set_code, then connected # * connected, receive_pake, send_phase, set_code +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 Delegated(ServerBase, unittest.TestCase): + + def test_delegated(self): + dg = Delegate() + w = wormhole.create(APPID, self.relayurl, reactor, delegate=dg) + w.close() + class Wormholes(ServerBase, unittest.TestCase): # integration test, with a real server def doBoth(self, d1, d2): return gatherResults([d1, d2], True) + @inlineCallbacks + def test_allocate_default(self): + w1 = wormhole.create(APPID, self.relayurl, reactor) + w1.allocate_code() + code = yield w1.when_code() + mo = re.search(r"^\d+-\w+-\w+$", code) + self.assert_(mo, code) + # w.close() fails because we closed before connecting + yield self.assertFailure(w1.close(), LonelyError) + + @inlineCallbacks + def test_allocate_more_words(self): + w1 = wormhole.create(APPID, self.relayurl, reactor) + w1.allocate_code(3) + code = yield w1.when_code() + mo = re.search(r"^\d+-\w+-\w+-\w+$", code) + self.assert_(mo, code) + yield self.assertFailure(w1.close(), LonelyError) + @inlineCallbacks def test_basic(self): w1 = wormhole.create(APPID, self.relayurl, reactor) + #w1.debug_set_trace("W1") w2 = wormhole.create(APPID, self.relayurl, reactor) + #w2.debug_set_trace(" W2") w1.allocate_code() code = yield w1.when_code() w2.set_code(code) + + verifier1 = yield w1.when_verified() + verifier2 = yield w2.when_verified() + self.assertEqual(verifier1, verifier2) + + version1 = yield w1.when_version() + version2 = yield w2.when_version() + # TODO: add the ability to set app-versions + self.assertEqual(version1, {}) + self.assertEqual(version2, {}) + w1.send(b"data1") w2.send(b"data2") dataX = yield w1.when_received() dataY = yield w2.when_received() self.assertEqual(dataX, b"data2") self.assertEqual(dataY, b"data1") - yield w1.close() - yield w2.close() + + version1_again = yield w1.when_version() + self.assertEqual(version1, version1_again) + + c1 = yield w1.close() + self.assertEqual(c1, "happy") + c2 = yield w2.close() + self.assertEqual(c2, "happy") + + @inlineCallbacks + def test_when_code_early(self): + w1 = wormhole.create(APPID, self.relayurl, reactor) + d = w1.when_code() + w1.set_code("1-abc") + code = self.successResultOf(d) + self.assertEqual(code, "1-abc") + yield self.assertFailure(w1.close(), LonelyError) + + @inlineCallbacks + def test_when_code_late(self): + w1 = wormhole.create(APPID, self.relayurl, reactor) + w1.set_code("1-abc") + d = w1.when_code() + code = self.successResultOf(d) + self.assertEqual(code, "1-abc") + yield self.assertFailure(w1.close(), LonelyError) @inlineCallbacks def test_same_message(self): @@ -793,6 +284,8 @@ class Wormholes(ServerBase, unittest.TestCase): w1.allocate_code() code = yield w1.when_code() w2.set_code(code+"not") + code2 = yield w2.when_code() + self.assertNotEqual(code, code2) # That's enough to allow both sides to discover the mismatch, but # only after the confirmation message gets through. API calls that # don't wait will appear to work until the mismatched confirmation diff --git a/src/wormhole/test/test_wormhole_new.py b/src/wormhole/test/test_wormhole_new.py deleted file mode 100644 index 6e295ba..0000000 --- a/src/wormhole/test/test_wormhole_new.py +++ /dev/null @@ -1,108 +0,0 @@ -from __future__ import print_function, unicode_literals -import re -from twisted.trial import unittest -from twisted.internet import reactor -from twisted.internet.defer import inlineCallbacks -from .common import ServerBase -from .. import wormhole, errors - -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): - timeout = 2 - - @inlineCallbacks - def test_allocate(self): - w = wormhole.create(APPID, self.relayurl, reactor) - #w.debug_set_trace("W1") - w.allocate_code(2) - code = yield w.when_code() - self.assertEqual(type(code), type("")) - mo = re.search(r"^\d+-\w+-\w+$", code) - self.assert_(mo, code) - # w.close() fails because we closed before connecting - yield self.assertFailure(w.close(), errors.LonelyError) - - def test_delegated(self): - dg = Delegate() - w = wormhole.create(APPID, self.relayurl, reactor, delegate=dg) - w.close() - - @inlineCallbacks - def test_basic(self): - w1 = wormhole.create(APPID, self.relayurl, reactor) - #w1.debug_set_trace("W1") - w1.allocate_code(2) - code = yield w1.when_code() - mo = re.search(r"^\d+-\w+-\w+$", code) - self.assert_(mo, code) - w2 = wormhole.create(APPID, self.relayurl, reactor) - #w2.debug_set_trace(" W2") - w2.set_code(code) - code2 = yield w2.when_code() - self.assertEqual(code, code2) - - verifier1 = yield w1.when_verified() - verifier2 = yield w2.when_verified() - self.assertEqual(verifier1, verifier2) - - version1 = yield w1.when_version() - version2 = yield w2.when_version() - # TODO: add the ability to set app-versions - self.assertEqual(version1, {}) - self.assertEqual(version2, {}) - - w1.send(b"data") - - data = yield w2.when_received() - self.assertEqual(data, b"data") - - w2.send(b"data2") - data2 = yield w1.when_received() - self.assertEqual(data2, b"data2") - - version1_again = yield w1.when_version() - self.assertEqual(version1, version1_again) - - c1 = yield w1.close() - self.assertEqual(c1, "happy") - c2 = yield w2.close() - self.assertEqual(c2, "happy") - - @inlineCallbacks - def test_wrong_password(self): - w1 = wormhole.create(APPID, self.relayurl, reactor) - #w1.debug_set_trace("W1") - w1.allocate_code(2) - code = yield w1.when_code() - w2 = wormhole.create(APPID, self.relayurl, reactor) - w2.set_code(code+"NOT") - code2 = yield w2.when_code() - self.assertNotEqual(code, code2) - - w1.send(b"data") - - yield self.assertFailure(w2.when_received(), errors.WrongPasswordError) - # wait for w1.when_received, because if we close w1 before it has - # seen the VERSION message, we could legitimately get LonelyError - # instead of WrongPasswordError. w2 didn't send anything, so - # w1.when_received wouldn't ever callback, but it will errback when - # w1 gets the undecryptable VERSION. - yield self.assertFailure(w1.when_received(), errors.WrongPasswordError) - yield self.assertFailure(w1.close(), errors.WrongPasswordError) - yield self.assertFailure(w2.close(), errors.WrongPasswordError)