Fix retry crash for unregistered remotes in the Sessions popup
Opening a window whose target was removed from the registry (its tab stays open by design) and failing landed in the action menu with a "重试连接" row that indexed self.entries directly and raised KeyError, killing the popup with a traceback. Only offer the retry action for registered targets, degrade a stale retry row to a message, and keep the popup alive when a handler raises anything unexpected instead of dying with a traceback. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
@@ -1000,5 +1000,50 @@ class SelectorActionTests(unittest.TestCase):
|
||||
os.waitpid(pid, 0)
|
||||
|
||||
|
||||
class SelectorRobustnessTests(unittest.TestCase):
|
||||
def test_retry_is_not_offered_for_unregistered_remote_and_never_crashes(self) -> None:
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
|
||||
def activate(result: SelectorResult) -> None:
|
||||
raise RuntimeError("ssh: connect to host orangepi port 22: No route to host")
|
||||
|
||||
# The registry is empty: this window's target was removed via
|
||||
# "移除远端记录" while its tab stayed open.
|
||||
window = CatalogWindow(
|
||||
"@7",
|
||||
"remote:orangepi:default",
|
||||
"R orangepi/default",
|
||||
True,
|
||||
False,
|
||||
kind="remote",
|
||||
target="orangepi",
|
||||
session="default",
|
||||
default_label="R orangepi/default",
|
||||
)
|
||||
selector = SessionSelector(
|
||||
[window],
|
||||
RemoteRegistry(Path(directory) / "remotes.json"),
|
||||
"/missing/ssh",
|
||||
activate_handler=activate,
|
||||
)
|
||||
self.addCleanup(selector.pool.close)
|
||||
row = next(
|
||||
item
|
||||
for item in selector._rows() # type: ignore[attr-defined]
|
||||
if item.key == "window:@7"
|
||||
)
|
||||
self.assertIsNone(selector._activate(row)) # type: ignore[attr-defined]
|
||||
self.assertEqual(selector.view, "actions")
|
||||
kinds = [item.kind for item in selector._rows()] # type: ignore[attr-defined]
|
||||
self.assertIn("action-window", kinds)
|
||||
self.assertNotIn("action-retry", kinds)
|
||||
|
||||
# A stale retry row must degrade to a message instead of a KeyError.
|
||||
stale = PickerRow("retry:orangepi", "retry", "! orangepi", target="orangepi")
|
||||
self.assertIsNone(selector._activate(stale)) # type: ignore[attr-defined]
|
||||
self.assertEqual(selector.view, "main")
|
||||
self.assertIn("未登记", selector.message)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
Reference in New Issue
Block a user