HyperDeck hold switches its Companion connection off and on
After a deck restarts, Companion's HyperDeck connection does not come back by itself and a plain restart of the connection does not help; switching it off and on does. Each HD key's hold now does exactly that (even when it looks green), waits 15 s and checks: DONE, STILL OFFLINE (deck pings) or NO NETWORK. Decks are no longer rebooted by the panel; a recording deck is left alone. Tested live on HD2 (off/on, reconnected in 17 s). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+44
-17
@@ -893,6 +893,21 @@ class TestFixes(unittest.TestCase):
|
||||
self.assertEqual(decks[0], ("HyperDeck_2", "10.1.10.12"))
|
||||
self.assertEqual(self.plan("hd3"), [])
|
||||
|
||||
def test_hd_hold_works_even_when_it_looks_green(self):
|
||||
ran = []
|
||||
self.engine.executor = lambda cfg, fix_id, chk: ran.append((fix_id, chk.get("conn"), chk.get("ip"))) or True
|
||||
run_steps(self.engine, self.snap, SUNDAY, 4) # every deck fine
|
||||
self.engine.run_fixes("hd4", self.snap, None, SUNDAY + 5)
|
||||
self.snap.vars[("HyperDeck_3", "status")] = "Record"
|
||||
self.engine.run_fixes("hd3", self.snap, None, SUNDAY + 5) # recording: left alone
|
||||
time.sleep(0.2)
|
||||
self.assertEqual(ran, [("hyperdeck", "HyperDeck_4", "10.1.10.14")])
|
||||
self.assertEqual(self.engine.notes["hd3"]["text"], "RECORDING\nLEFT ALONE")
|
||||
self.engine.run_fixes("hd5", self.snap, None, SUNDAY + 6) # another deck: its own guard
|
||||
self.engine.run_fixes("hd4", self.snap, None, SUNDAY + 20) # same deck within a minute
|
||||
time.sleep(0.2)
|
||||
self.assertEqual([r[1] for r in ran], ["HyperDeck_4", "HyperDeck_5"])
|
||||
|
||||
def test_disabled_connection_is_switched_on_never_rebooted(self):
|
||||
# 2026-10-08: HyperDeck_1 disabled in Companion, a hold sent the deck a reboot.
|
||||
self.snap.conns["HyperDeck_1"]["enabled"] = False
|
||||
@@ -1082,28 +1097,40 @@ class TestHyperDeckProbe(unittest.TestCase):
|
||||
deck.close()
|
||||
self.assertEqual(sp.hyperdeck_probe("127.0.0.1", timeout=1, port=port), "unreachable")
|
||||
|
||||
def test_only_a_silent_deck_is_rebooted(self):
|
||||
deck = FakeDeck("silent")
|
||||
def test_the_hold_switches_the_connection_off_and_on_and_never_reboots(self):
|
||||
from unittest import mock
|
||||
deck = FakeDeck("silent") # even a deck that would once have been rebooted
|
||||
try:
|
||||
comp = mock.Mock()
|
||||
comp.connections.side_effect = [
|
||||
[{"label": "HyperDeck_1", "id": "h1", "enabled": True, "status": {"category": "error"}}],
|
||||
[{"label": "HyperDeck_1", "id": "h1", "enabled": True, "status": {"category": "good"}}]]
|
||||
comp.disable_connection.return_value = comp.enable_connection.return_value = True
|
||||
chk = {"conn": "HyperDeck_1", "ip": "127.0.0.1", "port": deck.port}
|
||||
self.assertTrue(sp.execute_fix(CONFIG, "hyperdeck", chk))
|
||||
time.sleep(0.3)
|
||||
self.assertIn(b"reboot", deck.received)
|
||||
finally:
|
||||
deck.close()
|
||||
|
||||
def test_a_recording_deck_is_never_rebooted(self):
|
||||
deck = FakeDeck("record")
|
||||
try:
|
||||
cfg = json.loads(json.dumps(CONFIG))
|
||||
cfg["companion"]["port"] = 1 # no Companion here: the reconnect just fails
|
||||
chk = {"conn": "HyperDeck_1", "ip": "127.0.0.1", "port": deck.port}
|
||||
sp.execute_fix(cfg, "hyperdeck", chk)
|
||||
with mock.patch.object(sp, "Companion", return_value=comp), mock.patch.object(sp.time, "sleep"):
|
||||
self.assertTrue(sp.execute_fix(CONFIG, "hyperdeck", chk))
|
||||
self.assertEqual([c[0] for c in comp.method_calls if c[0].endswith("_connection")],
|
||||
["disable_connection", "enable_connection"])
|
||||
comp.restart_connection.assert_not_called()
|
||||
time.sleep(0.3)
|
||||
self.assertNotIn(b"reboot", deck.received)
|
||||
finally:
|
||||
deck.close()
|
||||
|
||||
def test_a_deck_that_stays_offline_says_so(self):
|
||||
from unittest import mock
|
||||
fix = CONFIG["fixes"]["hyperdeck"]
|
||||
for pings, expect in ((True, "STILL OFFLINE\nHOLD AGAIN"), (False, "NO NETWORK\nCHECK POWER")):
|
||||
comp = mock.Mock()
|
||||
comp.connections.side_effect = [
|
||||
[{"label": "HyperDeck_2", "id": "h2", "enabled": True, "status": {"category": "error"}}],
|
||||
[{"label": "HyperDeck_2", "id": "h2", "enabled": True, "status": {"category": "error"}}]]
|
||||
with mock.patch.object(sp, "Companion", return_value=comp), \
|
||||
mock.patch.object(sp, "ping_once", return_value=pings) as ping:
|
||||
self.assertEqual(sp.reconnect_and_verify(CONFIG, fix, "x", sleep=lambda s: None,
|
||||
conn="HyperDeck_2", host="10.1.10.12", toggle=True), expect)
|
||||
ping.assert_called_once_with("10.1.10.12") # the deck's own address, from Companion
|
||||
|
||||
|
||||
class TestNetgearParsing(unittest.TestCase):
|
||||
BIG = """ VLAN ID MAC Address Interface IfIndex Status
|
||||
@@ -1233,8 +1260,8 @@ class TestAgainstFakeCompanion(unittest.TestCase):
|
||||
sp.poll_connections(comp, snap)
|
||||
run_steps(engine, snap, now, 4)
|
||||
before = len(store["restarts"])
|
||||
# hd3 is green, so its hold does nothing; LED is failing on VX1000, so that restarts.
|
||||
sp.handle_commands(";restart hd3;restart led;service off;bogus", engine, comp, snap, now + 5)
|
||||
# x32 is green, so its hold does nothing; LED is failing on VX1000, so that restarts.
|
||||
sp.handle_commands(";restart x32;restart led;service off;bogus", engine, comp, snap, now + 5)
|
||||
self.assertEqual(store["restarts"][before:], ["id-VX1000"])
|
||||
finally:
|
||||
store["conns"]["VX1000"]["category"] = "good"
|
||||
|
||||
Reference in New Issue
Block a user