mirror of
https://github.com/openglow-org/forgefirm.git
synced 2026-09-27 08:41:13 -07:00
forgetest: the supervisor's levers get a timeout above the daemon's own waits
POST /mode, /controller/start and /controller/stop answer only when the switch is done: the old controller gone, the new one started after any pending liveness probe, and its first job-state report in (15 s without one). The client's 10 s timeout read a slow but honest switch as a dead daemon and errored cloud.service-protocol on the bench; those three paths now get 120 s. No catalog consequence: the tests and their covers are unchanged, the client only waits longer.
This commit is contained in:
@@ -26,14 +26,29 @@ class HwError(Exception):
|
||||
|
||||
# ------------------------------------------------------------ forgectrl
|
||||
|
||||
# The supervisor's levers answer only when the switch is done: a mode
|
||||
# switch waits for the old controller to exit, the new one to start (a
|
||||
# pending liveness probe first) and its first job-state report (up to
|
||||
# 15 s; the emulator's comes with its start, a real client's with its
|
||||
# machine); a stop waits for the child to go. They get their own timeout,
|
||||
# above the daemon's own deadlines, so a slow but honest switch is never
|
||||
# read as a dead daemon.
|
||||
SLOW_PATHS = ("/mode", "/controller/start", "/controller/stop")
|
||||
SLOW_TIMEOUT_S = 120.0
|
||||
|
||||
|
||||
class Forgectrl:
|
||||
"""Thin client for the machine-services daemon."""
|
||||
|
||||
def __init__(self, base=None, token=None, timeout=10.0):
|
||||
def __init__(self, base=None, token=None, timeout=10.0, slow_timeout=SLOW_TIMEOUT_S):
|
||||
self.base = (base or os.environ.get("FORGECTRL_URL") or "http://127.0.0.1:8080").rstrip("/")
|
||||
self.timeout = timeout
|
||||
self.slow_timeout = slow_timeout
|
||||
self._token = token
|
||||
|
||||
def timeout_for(self, method, path):
|
||||
return self.slow_timeout if method == "POST" and path in SLOW_PATHS else self.timeout
|
||||
|
||||
@property
|
||||
def token(self):
|
||||
if self._token is None:
|
||||
@@ -71,7 +86,7 @@ class Forgectrl:
|
||||
hdrs.setdefault("X-ForgeFIRM-Token", self.token)
|
||||
req = urllib.request.Request(url, data=body, method=method, headers=hdrs)
|
||||
try:
|
||||
with urllib.request.urlopen(req, timeout=self.timeout) as resp:
|
||||
with urllib.request.urlopen(req, timeout=self.timeout_for(method, path)) as resp:
|
||||
status = resp.status
|
||||
content = resp.read()
|
||||
ctype = resp.headers.get("Content-Type", "")
|
||||
|
||||
@@ -78,6 +78,27 @@ class SwitchModeTests(unittest.TestCase):
|
||||
self.assertTrue(ok, detail)
|
||||
self.assertEqual(self.fc.posts, [])
|
||||
|
||||
def test_the_supervisors_levers_get_the_slow_timeout(self):
|
||||
from forgetest import hw
|
||||
fc = hw.Forgectrl(timeout=1.0, slow_timeout=2.0)
|
||||
self.assertEqual(fc.timeout_for("POST", "/mode"), 2.0)
|
||||
self.assertEqual(fc.timeout_for("POST", "/controller/start"), 2.0)
|
||||
self.assertEqual(fc.timeout_for("POST", "/controller/stop"), 2.0)
|
||||
self.assertEqual(fc.timeout_for("GET", "/mode"), 1.0)
|
||||
self.assertEqual(fc.timeout_for("POST", "/settings"), 1.0)
|
||||
self.assertGreater(hw.SLOW_TIMEOUT_S, 15.0) # forgectrl's first-report wait
|
||||
# a switch that answers after the ordinary timeout still lands
|
||||
import time
|
||||
|
||||
def on_post(path, form):
|
||||
time.sleep(1.5)
|
||||
self.fc.state["mode"] = dict(self.fc.state["mode"], mode="cloud")
|
||||
return None
|
||||
self.fc.on_post = on_post
|
||||
st, body = fc.post("/mode", data={"controller": "cloud"})
|
||||
self.assertEqual(st, 200) # 1.5 s > timeout, < slow_timeout
|
||||
self.assertEqual(self.fc.state["mode"]["mode"], "cloud")
|
||||
|
||||
def test_cloud_to_grbl_switches_and_waits_for_the_port(self):
|
||||
cloud(self.fc)
|
||||
b = self.bl()
|
||||
|
||||
Reference in New Issue
Block a user