add a --debug-state command-line option
This exposes set_trace functionality for debugging state-machine transitions in the various state machines.
This commit is contained in:
parent
679434a9e1
commit
98d769c983
|
@ -38,6 +38,30 @@ class Config(object):
|
|||
self.stdout = stdout
|
||||
self.stderr = stderr
|
||||
self.tor = False # XXX?
|
||||
self._debug_state = None
|
||||
|
||||
@property
|
||||
def debug_state(self):
|
||||
return self._debug_state
|
||||
|
||||
@debug_state.setter
|
||||
def debug_state(self, debug_state):
|
||||
if not debug_state:
|
||||
return
|
||||
valid_machines = [
|
||||
'B', 'N', 'M', 'S', 'O', 'K', 'SK', 'R', 'RC', 'L', 'C', 'T'
|
||||
]
|
||||
debug_state = debug_state.split(",")
|
||||
invalid_machines = [
|
||||
machine
|
||||
for machine in debug_state
|
||||
if machine not in valid_machines
|
||||
]
|
||||
if invalid_machines:
|
||||
raise click.UsageError(
|
||||
"Cannot debug unknown machines: {}".format(" ".join(invalid_machines))
|
||||
)
|
||||
self._debug_state = debug_state
|
||||
|
||||
|
||||
def _compose(*decorators):
|
||||
|
@ -236,6 +260,19 @@ def help(context, **kwargs):
|
|||
default=False,
|
||||
is_flag=True,
|
||||
help="Don't raise an error if a file can't be read.")
|
||||
@click.option(
|
||||
"--debug-state",
|
||||
is_flag=False,
|
||||
flag_value="B,N,M,S,O,K,SK,R,RC,L,C,T",
|
||||
default=None,
|
||||
metavar="MACHINES",
|
||||
help=(
|
||||
"Debug state-machine transitions. "
|
||||
"Possible machines to debug are accepted as a comma-separated list "
|
||||
"and the default is all of them. Valid machines are "
|
||||
"any of: B,N,M,S,O,K,SK,R,RC,L,C,T"
|
||||
)
|
||||
)
|
||||
@click.argument("what", required=False, type=click.Path(path_type=type(u"")))
|
||||
@click.pass_obj
|
||||
def send(cfg, **kwargs):
|
||||
|
@ -277,6 +314,21 @@ def go(f, cfg):
|
|||
help=("The file or directory to create, overriding the name suggested"
|
||||
" by the sender."),
|
||||
)
|
||||
# --debug-state might be better at the top-level but Click can't parse
|
||||
# an option like "--debug-state <optional-value>" if there's a subcommand name next
|
||||
@click.option(
|
||||
"--debug-state",
|
||||
is_flag=False,
|
||||
flag_value="B,N,M,S,O,K,SK,R,RC,L,C,T",
|
||||
default=None,
|
||||
metavar="MACHINES",
|
||||
help=(
|
||||
"Debug state-machine transitions. "
|
||||
"Possible machines to debug are accepted as a comma-separated list "
|
||||
"and the default is all of them. Valid machines are "
|
||||
"any of: B,N,M,S,O,K,SK,R,RC,L,C,T"
|
||||
)
|
||||
)
|
||||
@click.argument(
|
||||
"code",
|
||||
nargs=-1,
|
||||
|
|
|
@ -84,6 +84,8 @@ class Receiver:
|
|||
self._reactor,
|
||||
tor=self._tor,
|
||||
timing=self.args.timing)
|
||||
if self.args.debug_state:
|
||||
w.debug_set_trace("recv", which=" ".join(self.args.debug_state), file=self.args.stdout)
|
||||
self._w = w # so tests can wait on events too
|
||||
|
||||
# I wanted to do this instead:
|
||||
|
|
|
@ -69,6 +69,8 @@ class Sender:
|
|||
self._reactor,
|
||||
tor=self._tor,
|
||||
timing=self._timing)
|
||||
if self._args.debug_state:
|
||||
w.debug_set_trace("send", which=" ".join(self._args.debug_state), file=self._args.stdout)
|
||||
d = self._go(w)
|
||||
|
||||
# if we succeed, we should close and return the w.close results
|
||||
|
|
|
@ -9,10 +9,11 @@ import zipfile
|
|||
from textwrap import dedent, fill
|
||||
|
||||
import six
|
||||
from click import UsageError
|
||||
from click.testing import CliRunner
|
||||
from humanize import naturalsize
|
||||
from twisted.internet import endpoints, reactor
|
||||
from twisted.internet.defer import gatherResults, inlineCallbacks, returnValue
|
||||
from twisted.internet.defer import gatherResults, inlineCallbacks, returnValue, CancelledError
|
||||
from twisted.internet.error import ConnectionRefusedError
|
||||
from twisted.internet.utils import getProcessOutputAndValue
|
||||
from twisted.python import log, procutils
|
||||
|
@ -1278,6 +1279,49 @@ class Dispatch(unittest.TestCase):
|
|||
self.assertEqual(cfg.timing.mock_calls[-1],
|
||||
mock.call.write("filename", cfg.stderr))
|
||||
|
||||
def test_debug_state_invalid_machine(self):
|
||||
cfg = cli.Config()
|
||||
with self.assertRaises(UsageError):
|
||||
cfg.debug_state = "ZZZ"
|
||||
|
||||
@inlineCallbacks
|
||||
def test_debug_state_send(self):
|
||||
args = config("send")
|
||||
args.debug_state = "B,N,M,S,O,K,SK,R,RC,L,C,T"
|
||||
args.stdout = io.StringIO()
|
||||
s = cmd_send.Sender(args, reactor)
|
||||
d = s.go()
|
||||
d.cancel()
|
||||
try:
|
||||
yield d
|
||||
except CancelledError:
|
||||
pass
|
||||
# just check for at least one state-transition we expected to
|
||||
# get logged due to the --debug-state option
|
||||
self.assertIn(
|
||||
"send.B[S0_empty].close",
|
||||
args.stdout.getvalue(),
|
||||
)
|
||||
|
||||
@inlineCallbacks
|
||||
def test_debug_state_receive(self):
|
||||
args = config("receive")
|
||||
args.debug_state = "B,N,M,S,O,K,SK,R,RC,L,C,T"
|
||||
args.stdout = io.StringIO()
|
||||
s = cmd_receive.Receiver(args, reactor)
|
||||
d = s.go()
|
||||
d.cancel()
|
||||
try:
|
||||
yield d
|
||||
except CancelledError:
|
||||
pass
|
||||
# just check for at least one state-transition we expected to
|
||||
# get logged due to the --debug-state option
|
||||
self.assertIn(
|
||||
"recv.B[S0_empty].close",
|
||||
args.stdout.getvalue(),
|
||||
)
|
||||
|
||||
@inlineCallbacks
|
||||
def test_wrong_password_error(self):
|
||||
cfg = config("send")
|
||||
|
|
Loading…
Reference in New Issue
Block a user