CLI: document and return correct errors
Also clean up test_scripts.PregeneratedCode: * fetch results from both sides at the same time * only check rc when using a subprocess, since the direct call doesn't use rc=0 anymore * no need to cancel the other side's Deferred when one errors * provide more information if stderr was non-empty
This commit is contained in:
parent
e4a19748db
commit
34116c7b1f
|
@ -14,6 +14,13 @@ class RespondError(Exception):
|
||||||
self.response = response
|
self.response = response
|
||||||
|
|
||||||
def receive(args, reactor=reactor):
|
def receive(args, reactor=reactor):
|
||||||
|
"""I implement 'wormhole receive'. I return a Deferred that fires with
|
||||||
|
None (for success), or signals one of the following errors:
|
||||||
|
* WrongPasswordError: the two sides didn't use matching passwords
|
||||||
|
* Timeout: something didn't happen fast enough for our tastes
|
||||||
|
* TransferError: the sender rejected the transfer: verifier mismatch
|
||||||
|
* any other error: something unexpected happened
|
||||||
|
"""
|
||||||
return TwistedReceiver(args, reactor).go()
|
return TwistedReceiver(args, reactor).go()
|
||||||
|
|
||||||
|
|
||||||
|
@ -72,7 +79,7 @@ class TwistedReceiver:
|
||||||
try:
|
try:
|
||||||
if "message" in them_d:
|
if "message" in them_d:
|
||||||
yield self.handle_text(them_d, w)
|
yield self.handle_text(them_d, w)
|
||||||
returnValue(0)
|
returnValue(None)
|
||||||
if "file" in them_d:
|
if "file" in them_d:
|
||||||
f = self.handle_file(them_d)
|
f = self.handle_file(them_d)
|
||||||
rp = yield self.establish_transit(w, them_d, tor_manager)
|
rp = yield self.establish_transit(w, them_d, tor_manager)
|
||||||
|
@ -92,8 +99,8 @@ class TwistedReceiver:
|
||||||
except RespondError as r:
|
except RespondError as r:
|
||||||
data = json.dumps(r.response).encode("utf-8")
|
data = json.dumps(r.response).encode("utf-8")
|
||||||
yield w.send_data(data)
|
yield w.send_data(data)
|
||||||
raise SystemExit(1)
|
raise TransferError(r["error"])
|
||||||
returnValue(0)
|
returnValue(None)
|
||||||
|
|
||||||
@inlineCallbacks
|
@inlineCallbacks
|
||||||
def handle_code(self, w):
|
def handle_code(self, w):
|
||||||
|
@ -227,7 +234,7 @@ class TwistedReceiver:
|
||||||
self.msg()
|
self.msg()
|
||||||
self.msg(u"Connection dropped before full file received")
|
self.msg(u"Connection dropped before full file received")
|
||||||
self.msg(u"got %d bytes, wanted %d" % (received, self.xfersize))
|
self.msg(u"got %d bytes, wanted %d" % (received, self.xfersize))
|
||||||
returnValue(1) # TODO: exit properly
|
raise TransferError("Connection dropped before full file received")
|
||||||
assert received == self.xfersize
|
assert received == self.xfersize
|
||||||
|
|
||||||
def write_file(self, f):
|
def write_file(self, f):
|
||||||
|
|
|
@ -12,6 +12,14 @@ APPID = u"lothar.com/wormhole/text-or-file-xfer"
|
||||||
|
|
||||||
@inlineCallbacks
|
@inlineCallbacks
|
||||||
def send(args, reactor=reactor):
|
def send(args, reactor=reactor):
|
||||||
|
"""I implement 'wormhole send'. I return a Deferred that fires with None
|
||||||
|
(for success), or signals one of the following errors:
|
||||||
|
* WrongPasswordError: the two sides didn't use matching passwords
|
||||||
|
* Timeout: something didn't happen fast enough for our tastes
|
||||||
|
* TransferError: the receiver rejected the transfer: verifier mismatch,
|
||||||
|
permission not granted, ack not successful.
|
||||||
|
* any other error: something unexpected happened
|
||||||
|
"""
|
||||||
assert isinstance(args.relay_url, type(u""))
|
assert isinstance(args.relay_url, type(u""))
|
||||||
if args.zeromode:
|
if args.zeromode:
|
||||||
assert not args.code
|
assert not args.code
|
||||||
|
@ -96,7 +104,7 @@ def send(args, reactor=reactor):
|
||||||
if them_phase1["message_ack"] == "ok":
|
if them_phase1["message_ack"] == "ok":
|
||||||
print(u"text message sent", file=args.stdout)
|
print(u"text message sent", file=args.stdout)
|
||||||
yield w.close()
|
yield w.close()
|
||||||
returnValue(0) # terminates this function
|
returnValue(None) # terminates this function
|
||||||
raise TransferError("error sending text: %r" % (them_phase1,))
|
raise TransferError("error sending text: %r" % (them_phase1,))
|
||||||
|
|
||||||
if "error" in them_phase1:
|
if "error" in them_phase1:
|
||||||
|
@ -109,7 +117,7 @@ def send(args, reactor=reactor):
|
||||||
yield w.close()
|
yield w.close()
|
||||||
yield _send_file_twisted(tdata, transit_sender, fd_to_send,
|
yield _send_file_twisted(tdata, transit_sender, fd_to_send,
|
||||||
args.stdout, args.hide_progress, args.timing)
|
args.stdout, args.hide_progress, args.timing)
|
||||||
returnValue(0)
|
returnValue(None)
|
||||||
|
|
||||||
def build_phase1_data(args):
|
def build_phase1_data(args):
|
||||||
phase1 = {}
|
phase1 = {}
|
||||||
|
|
|
@ -3,7 +3,7 @@ import os, sys, re, io, zipfile, six
|
||||||
from twisted.trial import unittest
|
from twisted.trial import unittest
|
||||||
from twisted.python import procutils, log
|
from twisted.python import procutils, log
|
||||||
from twisted.internet.utils import getProcessOutputAndValue
|
from twisted.internet.utils import getProcessOutputAndValue
|
||||||
from twisted.internet.defer import inlineCallbacks
|
from twisted.internet.defer import gatherResults, inlineCallbacks
|
||||||
from .. import __version__
|
from .. import __version__
|
||||||
from .common import ServerBase
|
from .common import ServerBase
|
||||||
from ..cli import runner, cmd_send, cmd_receive
|
from ..cli import runner, cmd_send, cmd_receive
|
||||||
|
@ -306,15 +306,17 @@ class PregeneratedCode(ServerBase, ScriptsBase, unittest.TestCase):
|
||||||
path=send_dir)
|
path=send_dir)
|
||||||
receive_d = getProcessOutputAndValue(wormhole_bin, receive_args,
|
receive_d = getProcessOutputAndValue(wormhole_bin, receive_args,
|
||||||
path=receive_dir)
|
path=receive_dir)
|
||||||
send_res = yield send_d
|
(send_res, receive_res) = yield gatherResults([send_d, receive_d],
|
||||||
|
True)
|
||||||
send_stdout = send_res[0].decode("utf-8")
|
send_stdout = send_res[0].decode("utf-8")
|
||||||
send_stderr = send_res[1].decode("utf-8")
|
send_stderr = send_res[1].decode("utf-8")
|
||||||
send_rc = send_res[2]
|
send_rc = send_res[2]
|
||||||
receive_res = yield receive_d
|
|
||||||
receive_stdout = receive_res[0].decode("utf-8")
|
receive_stdout = receive_res[0].decode("utf-8")
|
||||||
receive_stderr = receive_res[1].decode("utf-8")
|
receive_stderr = receive_res[1].decode("utf-8")
|
||||||
receive_rc = receive_res[2]
|
receive_rc = receive_res[2]
|
||||||
NL = os.linesep
|
NL = os.linesep
|
||||||
|
self.assertEqual((send_rc, receive_rc), (0, 0),
|
||||||
|
(send_res, receive_res))
|
||||||
else:
|
else:
|
||||||
sargs = runner.parser.parse_args(send_args)
|
sargs = runner.parser.parse_args(send_args)
|
||||||
sargs.cwd = send_dir
|
sargs.cwd = send_dir
|
||||||
|
@ -330,22 +332,11 @@ class PregeneratedCode(ServerBase, ScriptsBase, unittest.TestCase):
|
||||||
receive_d = cmd_receive.receive(rargs)
|
receive_d = cmd_receive.receive(rargs)
|
||||||
|
|
||||||
# The sender might fail, leaving the receiver hanging, or vice
|
# The sender might fail, leaving the receiver hanging, or vice
|
||||||
# versa. If either side fails, cancel the other, so it won't
|
# versa. Make sure we don't wait on one side exclusively
|
||||||
# matter which Deferred we wait upon first.
|
|
||||||
|
|
||||||
def _oops(f, which):
|
yield gatherResults([send_d, receive_d], True)
|
||||||
log.msg("test_scripts: %s failed, cancelling both" % which)
|
|
||||||
send_d.cancel()
|
|
||||||
receive_d.cancel()
|
|
||||||
return f
|
|
||||||
send_d.addErrback(_oops, "send_d")
|
|
||||||
receive_d.addErrback(_oops, "receive_d")
|
|
||||||
|
|
||||||
send_rc = yield send_d
|
|
||||||
send_stdout = sargs.stdout.getvalue()
|
send_stdout = sargs.stdout.getvalue()
|
||||||
send_stderr = sargs.stderr.getvalue()
|
send_stderr = sargs.stderr.getvalue()
|
||||||
|
|
||||||
receive_rc = yield receive_d
|
|
||||||
receive_stdout = rargs.stdout.getvalue()
|
receive_stdout = rargs.stdout.getvalue()
|
||||||
receive_stderr = rargs.stderr.getvalue()
|
receive_stderr = rargs.stderr.getvalue()
|
||||||
|
|
||||||
|
@ -355,8 +346,10 @@ class PregeneratedCode(ServerBase, ScriptsBase, unittest.TestCase):
|
||||||
|
|
||||||
self.maxDiff = None # show full output for assertion failures
|
self.maxDiff = None # show full output for assertion failures
|
||||||
|
|
||||||
self.failUnlessEqual(send_stderr, "")
|
self.failUnlessEqual(send_stderr, "",
|
||||||
self.failUnlessEqual(receive_stderr, "")
|
(send_stdout, send_stderr))
|
||||||
|
self.failUnlessEqual(receive_stderr, "",
|
||||||
|
(receive_stdout, receive_stderr))
|
||||||
|
|
||||||
# check sender
|
# check sender
|
||||||
if mode == "text":
|
if mode == "text":
|
||||||
|
@ -417,9 +410,6 @@ class PregeneratedCode(ServerBase, ScriptsBase, unittest.TestCase):
|
||||||
with open(fn, "r") as f:
|
with open(fn, "r") as f:
|
||||||
self.failUnlessEqual(f.read(), message(i))
|
self.failUnlessEqual(f.read(), message(i))
|
||||||
|
|
||||||
self.failUnlessEqual(send_rc, 0)
|
|
||||||
self.failUnlessEqual(receive_rc, 0)
|
|
||||||
|
|
||||||
def test_text(self):
|
def test_text(self):
|
||||||
return self._do_test()
|
return self._do_test()
|
||||||
def test_text_subprocess(self):
|
def test_text_subprocess(self):
|
||||||
|
|
Loading…
Reference in New Issue
Block a user