_rlcompleter: use blockingCallFromThread for all Helper APIs
We were missing two (the calls to choose_nameplate() and choose_words() that happen after the input() function has finished, but while we're still inside the thread that makes it safe for input() to block). This almost certainly caused the crash seen in issue #280. Update the tests to match: CodeInputter.finish must now be called with deferToThread from inside tests, or the internal blockingCallFromThread must be stubbed out.
This commit is contained in:
parent
3847339f43
commit
af406a600e
|
@ -134,11 +134,13 @@ class CodeInputter(object):
|
||||||
raise AlreadyInputNameplateError("nameplate (%s-) already entered, cannot go back" % self._committed_nameplate)
|
raise AlreadyInputNameplateError("nameplate (%s-) already entered, cannot go back" % self._committed_nameplate)
|
||||||
else:
|
else:
|
||||||
debug(" choose_nameplate(%s)" % nameplate)
|
debug(" choose_nameplate(%s)" % nameplate)
|
||||||
self._input_helper.choose_nameplate(nameplate)
|
self.bcft(self._input_helper.choose_nameplate, nameplate)
|
||||||
debug(" choose_words(%s)" % words)
|
debug(" choose_words(%s)" % words)
|
||||||
self._input_helper.choose_words(words)
|
self.bcft(self._input_helper.choose_words, words)
|
||||||
|
|
||||||
def _input_code_with_completion(prompt, input_helper, reactor):
|
def _input_code_with_completion(prompt, input_helper, reactor):
|
||||||
|
# reminder: this all occurs in a separate thread. All calls to input_helper
|
||||||
|
# must go through blockingCallFromThread()
|
||||||
c = CodeInputter(input_helper, reactor)
|
c = CodeInputter(input_helper, reactor)
|
||||||
if readline is not None:
|
if readline is not None:
|
||||||
if readline.__doc__ and "libedit" in readline.__doc__:
|
if readline.__doc__ and "libedit" in readline.__doc__:
|
||||||
|
|
|
@ -147,11 +147,15 @@ def get_completions(c, prefix):
|
||||||
return completions
|
return completions
|
||||||
completions.append(text)
|
completions.append(text)
|
||||||
|
|
||||||
|
def fake_blockingCallFromThread(f, *a, **kw):
|
||||||
|
return f(*a, **kw)
|
||||||
|
|
||||||
class Completion(unittest.TestCase):
|
class Completion(unittest.TestCase):
|
||||||
def test_simple(self):
|
def test_simple(self):
|
||||||
# no actual completion
|
# no actual completion
|
||||||
helper = mock.Mock()
|
helper = mock.Mock()
|
||||||
c = CodeInputter(helper, "reactor")
|
c = CodeInputter(helper, "reactor")
|
||||||
|
c.bcft = fake_blockingCallFromThread
|
||||||
c.finish("1-code-ghost")
|
c.finish("1-code-ghost")
|
||||||
self.assertFalse(c.used_completion)
|
self.assertFalse(c.used_completion)
|
||||||
self.assertEqual(helper.mock_calls,
|
self.assertEqual(helper.mock_calls,
|
||||||
|
@ -164,6 +168,7 @@ class Completion(unittest.TestCase):
|
||||||
# check that it calls _commit_and_build_completions correctly
|
# check that it calls _commit_and_build_completions correctly
|
||||||
helper = mock.Mock()
|
helper = mock.Mock()
|
||||||
c = CodeInputter(helper, "reactor")
|
c = CodeInputter(helper, "reactor")
|
||||||
|
c.bcft = fake_blockingCallFromThread
|
||||||
|
|
||||||
# pretend nameplates: 1, 12, 34
|
# pretend nameplates: 1, 12, 34
|
||||||
|
|
||||||
|
@ -304,12 +309,13 @@ class Completion(unittest.TestCase):
|
||||||
self.assertEqual(gwc.mock_calls, [mock.call("and-b")])
|
self.assertEqual(gwc.mock_calls, [mock.call("and-b")])
|
||||||
gwc.reset_mock()
|
gwc.reset_mock()
|
||||||
|
|
||||||
c.finish("12-and-bat")
|
yield deferToThread(c.finish, "12-and-bat")
|
||||||
self.assertEqual(cw.mock_calls, [mock.call("and-bat")])
|
self.assertEqual(cw.mock_calls, [mock.call("and-bat")])
|
||||||
|
|
||||||
def test_incomplete_code(self):
|
def test_incomplete_code(self):
|
||||||
helper = mock.Mock()
|
helper = mock.Mock()
|
||||||
c = CodeInputter(helper, "reactor")
|
c = CodeInputter(helper, "reactor")
|
||||||
|
c.bcft = fake_blockingCallFromThread
|
||||||
with self.assertRaises(KeyFormatError) as e:
|
with self.assertRaises(KeyFormatError) as e:
|
||||||
c.finish("1")
|
c.finish("1")
|
||||||
self.assertEqual(str(e.exception), "incomplete wormhole code")
|
self.assertEqual(str(e.exception), "incomplete wormhole code")
|
||||||
|
@ -349,7 +355,7 @@ class Completion(unittest.TestCase):
|
||||||
self.assertEqual(matches, ["1-code", "1-court"])
|
self.assertEqual(matches, ["1-code", "1-court"])
|
||||||
helper.reset_mock()
|
helper.reset_mock()
|
||||||
with self.assertRaises(AlreadyInputNameplateError) as e:
|
with self.assertRaises(AlreadyInputNameplateError) as e:
|
||||||
c.finish("2-code")
|
yield deferToThread(c.finish, "2-code")
|
||||||
self.assertEqual(str(e.exception),
|
self.assertEqual(str(e.exception),
|
||||||
"nameplate (1-) already entered, cannot go back")
|
"nameplate (1-) already entered, cannot go back")
|
||||||
self.assertEqual(helper.mock_calls, [])
|
self.assertEqual(helper.mock_calls, [])
|
||||||
|
|
Loading…
Reference in New Issue
Block a user