Merge pull request #411 from meejah/debug-state

add a --debug-state command-line option
This commit is contained in:
meejah 2021-07-23 09:23:50 -06:00 committed by GitHub
commit e522a39922
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 101 additions and 1 deletions

View File

@ -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,

View File

@ -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:

View File

@ -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

View File

@ -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")