mirror of
https://github.com/openglow-org/forgefirm.git
synced 2026-10-15 17:19:55 -07:00
forgetest: the coolant flow calibration is a required step; the gate's missing list
forgectrl requires cooling.flow after preferences, machine, and cloud, and GET /wiz lists the required steps the gate waits for as missing. - REQUIRED_STEPS is the form steps plus cooling.flow, in the gate's order; REQUIRED_FORM_STEPS are the form steps. cooling.flow leaves RECOMMENDED_STEPS. - setup.gate-blocks-controllers expects "setup required: preferences, machine, cloud, cooling.flow" on a record with no step done, with all four named in missing, and an empty missing list once they are done and the gate is open. - setup.first-run-flow walks the form steps alone: its seed keeps the checks done, the calibration among them, so the gate's reason narrows from the three form steps to open. Proof: the setup host tests (74) and the manifest tests pass; the host test of record_with_required_steps keeps the four. Acceptance: these are the tests.
This commit is contained in:
@@ -47,15 +47,18 @@ TLS_BASE = "https://127.0.0.1" # FORGECTRL_TLS_URL overrides (host test
|
|||||||
# The first run's form wizards, all at version 1 (wiz.c).
|
# The first run's form wizards, all at version 1 (wiz.c).
|
||||||
FORM_WIZARDS = ("advisories", "account", "preferences", "machine", "cloud")
|
FORM_WIZARDS = ("advisories", "account", "preferences", "machine", "cloud")
|
||||||
# The steps the gate requires after the account, all at version 1, in
|
# The steps the gate requires after the account, all at version 1, in
|
||||||
# the order the gate's reason names them (setup.c).
|
# the order the gate's reason names them (setup.c): the form steps, then
|
||||||
REQUIRED_STEPS = ("preferences", "machine", "cloud")
|
# the coolant flow calibration. The first-run tests seed the checks done,
|
||||||
|
# the calibration among them, so the form steps are what they walk.
|
||||||
|
REQUIRED_FORM_STEPS = ("preferences", "machine", "cloud")
|
||||||
|
REQUIRED_STEPS = REQUIRED_FORM_STEPS + ("cooling.flow",)
|
||||||
# What the image's step table recommends on a record with the required
|
# What the image's step table recommends on a record with the required
|
||||||
# steps done and nothing else (setup.c): every step after them. The
|
# steps done and nothing else (setup.c): every step after them. The
|
||||||
# cloud header joins on a machine with cloud mode on. The gate's own
|
# cloud header joins on a machine with cloud mode on. The gate's own
|
||||||
# parts (the advisories, the account, the required steps, the intake fan
|
# parts (the advisories, the account, the required steps, the intake fan
|
||||||
# count) are never recommended as not run yet, and the laser floor and
|
# count) are never recommended as not run yet, and the laser floor and
|
||||||
# the bed size are offered, never recommended.
|
# the bed size are offered, never recommended.
|
||||||
RECOMMENDED_STEPS = ("switches", "sensors", "airflow", "cooling.aa-offset", "cooling.flow", "motion",
|
RECOMMENDED_STEPS = ("switches", "sensors", "airflow", "cooling.aa-offset", "motion",
|
||||||
"cameras", "lens.travel", "laser.focus")
|
"cameras", "lens.travel", "laser.focus")
|
||||||
NEVER_RECOMMENDED = ("advisories", "account", "airflow.intakes", "laser.floor", "motion.envelope")
|
NEVER_RECOMMENDED = ("advisories", "account", "airflow.intakes", "laser.floor", "motion.envelope")
|
||||||
# The setting that counts the intake fans: the gate holds without it.
|
# The setting that counts the intake fans: the gate holds without it.
|
||||||
@@ -388,10 +391,11 @@ _GATE_COVERS = [("forgectrl", "src/setup.*"), ("forgectrl", "src/super.c"),
|
|||||||
"process runs and the Grbl port is closed; with the consent and without the "
|
"process runs and the Grbl port is closed; with the consent and without the "
|
||||||
"account, the same with the reason naming the account; with the consent and "
|
"account, the same with the reason naming the account; with the consent and "
|
||||||
"the account and no step done, the same with the reason 'setup required: "
|
"the account and no step done, the same with the reason 'setup required: "
|
||||||
"preferences, machine, cloud'. With those three done as well and no flag, the "
|
"preferences, machine, cloud, cooling.flow'. With those four done as well and "
|
||||||
|
"no flag, the "
|
||||||
"gate is open with no reason: the supervisor spawns the controller, the Grbl "
|
"gate is open with no reason: the supervisor spawns the controller, the Grbl "
|
||||||
"port accepts, and GET /wiz recommends every other step as not run yet (never "
|
"port accepts, and GET /wiz recommends every other step as not run yet (never "
|
||||||
"the advisories, the account, the three required steps, or the intake fan "
|
"the advisories, the account, the four required steps, or the intake fan "
|
||||||
"count; not the optional laser floor or bed size). On that record the intake "
|
"count; not the optional laser floor or bed size). On that record the intake "
|
||||||
"fan count is cleared: the gate closes live with the reason naming the intake "
|
"fan count is cleared: the gate closes live with the reason naming the intake "
|
||||||
"fans, GET /wiz reports them not counted, and the supervisor stops the "
|
"fans, GET /wiz reports them not counted, and the supervisor stops the "
|
||||||
@@ -459,6 +463,11 @@ def gate_blocks_controllers(ctx):
|
|||||||
with ctx.takeover():
|
with ctx.takeover():
|
||||||
write_file(record_path(), encoded(record_without_wizards(record)))
|
write_file(record_path(), encoded(record_without_wizards(record)))
|
||||||
gated("required steps", "setup required: " + ", ".join(REQUIRED_STEPS))
|
gated("required steps", "setup required: " + ", ".join(REQUIRED_STEPS))
|
||||||
|
# The page opens the steps the gate waits for from this list.
|
||||||
|
w = wiz(fc)
|
||||||
|
ev["missing_none_done"] = w.get("missing")
|
||||||
|
ctx.check(w.get("missing") == list(REQUIRED_STEPS),
|
||||||
|
"GET /wiz does not name the required steps as missing: %s", w.get("missing"))
|
||||||
with ctx.takeover():
|
with ctx.takeover():
|
||||||
write_file(record_path(), encoded(record_with_required_steps(record)))
|
write_file(record_path(), encoded(record_with_required_steps(record)))
|
||||||
|
|
||||||
@@ -468,6 +477,8 @@ def gate_blocks_controllers(ctx):
|
|||||||
ev["open_wiz"] = wiz_summary(w)
|
ev["open_wiz"] = wiz_summary(w)
|
||||||
ctx.check(w.get("gate") == "open" and not w.get("why") and w.get("fans_counted") is True,
|
ctx.check(w.get("gate") == "open" and not w.get("why") and w.get("fans_counted") is True,
|
||||||
"the consent, the account, and the required steps do not open the gate: %s", wiz_summary(w))
|
"the consent, the account, and the required steps do not open the gate: %s", wiz_summary(w))
|
||||||
|
ctx.check(w.get("missing") == [], "GET /wiz names steps as missing with the required ones done: %s",
|
||||||
|
w.get("missing"))
|
||||||
running("with the required steps done")
|
running("with the required steps done")
|
||||||
recm = recommended(w)
|
recm = recommended(w)
|
||||||
missing = [s for s in RECOMMENDED_STEPS if s not in recm]
|
missing = [s for s in RECOMMENDED_STEPS if s not in recm]
|
||||||
@@ -1500,7 +1511,8 @@ _FIRST_RUN_REQUIRES = ["setup.gate-blocks-controllers", "setup.advisories-rehash
|
|||||||
"acceptance_done; POST /wiz/account with a temporary name and password, the "
|
"acceptance_done; POST /wiz/account with a temporary name and password, the "
|
||||||
"account exists and the response sets the session cookie, and the gate holds "
|
"account exists and the response sets the session cookie, and the gate holds "
|
||||||
"with the reason 'setup required: preferences, machine, cloud' and no "
|
"with the reason 'setup required: preferences, machine, cloud' and no "
|
||||||
"controller. Then the required steps, the gate's reason naming what is left "
|
"controller (the seed keeps the coolant flow calibration done). Then the "
|
||||||
|
"required form steps, the gate's reason naming what is left "
|
||||||
"after each: POST /wiz/preferences with the units as found; POST /wiz/machine "
|
"after each: POST /wiz/preferences with the units as found; POST /wiz/machine "
|
||||||
"with the model as found (basic when unknown) and no TEC; POST /wiz/cloud as "
|
"with the model as found (basic when unknown) and no TEC; POST /wiz/cloud as "
|
||||||
"found (enabled with the phrase and the homing as found, or off). With the "
|
"found (enabled with the phrase and the homing as found, or off). With the "
|
||||||
@@ -1570,12 +1582,12 @@ def first_run_flow(ctx):
|
|||||||
ctx.check(m.get("controller") == "gated", "the controller is %s with %s left", m.get("controller"),
|
ctx.check(m.get("controller") == "gated", "the controller is %s with %s left", m.get("controller"),
|
||||||
", ".join(left))
|
", ".join(left))
|
||||||
|
|
||||||
still_gated(REQUIRED_STEPS)
|
still_gated(REQUIRED_FORM_STEPS)
|
||||||
ctx.log("the gate holds after the account: %s", wiz(fc).get("why"))
|
ctx.log("the gate holds after the account: %s", wiz(fc).get("why"))
|
||||||
|
|
||||||
st, body = fc.post("/wiz/preferences", data={"ui_units": settings.get("ui_units") or "metric"})
|
st, body = fc.post("/wiz/preferences", data={"ui_units": settings.get("ui_units") or "metric"})
|
||||||
ctx.check(st == 200, "POST /wiz/preferences -> %s %s", st, body if isinstance(body, dict) else "")
|
ctx.check(st == 200, "POST /wiz/preferences -> %s %s", st, body if isinstance(body, dict) else "")
|
||||||
still_gated(REQUIRED_STEPS[1:])
|
still_gated(REQUIRED_FORM_STEPS[1:])
|
||||||
machine = (w.get("machine") or {})
|
machine = (w.get("machine") or {})
|
||||||
model = machine.get("model") if machine.get("model") in ("basic", "plus", "pro") else "basic"
|
model = machine.get("model") if machine.get("model") in ("basic", "plus", "pro") else "basic"
|
||||||
st, body = fc.post("/wiz/machine", data={"model": model, "tec": "0"})
|
st, body = fc.post("/wiz/machine", data={"model": model, "tec": "0"})
|
||||||
@@ -1586,7 +1598,7 @@ def first_run_flow(ctx):
|
|||||||
ev["head"] = head
|
ev["head"] = head
|
||||||
ctx.check(head.get("present") is True and bool(head.get("hw_id")),
|
ctx.check(head.get("present") is True and bool(head.get("hw_id")),
|
||||||
"the machine facts do not see the head: %s", head)
|
"the machine facts do not see the head: %s", head)
|
||||||
still_gated(REQUIRED_STEPS[2:])
|
still_gated(REQUIRED_FORM_STEPS[2:])
|
||||||
if settings.get("cloud_enabled") == "1":
|
if settings.get("cloud_enabled") == "1":
|
||||||
data = {"enabled": "1", "phrase": SAFETY_PHRASE,
|
data = {"enabled": "1", "phrase": SAFETY_PHRASE,
|
||||||
"homing_mode": settings.get("homing_mode") or "gfcloud"}
|
"homing_mode": settings.get("homing_mode") or "gfcloud"}
|
||||||
|
|||||||
@@ -85,7 +85,9 @@ class RegistrationTests(unittest.TestCase):
|
|||||||
self.assertIn(wid, setup.RECOMMENDED_STEPS)
|
self.assertIn(wid, setup.RECOMMENDED_STEPS)
|
||||||
self.assertEqual(setup.FORM_WIZARDS, ("advisories", "account", "preferences", "machine", "cloud"))
|
self.assertEqual(setup.FORM_WIZARDS, ("advisories", "account", "preferences", "machine", "cloud"))
|
||||||
# in the order the gate's reason names them
|
# in the order the gate's reason names them
|
||||||
self.assertEqual(setup.REQUIRED_STEPS, ("preferences", "machine", "cloud"))
|
self.assertEqual(setup.REQUIRED_FORM_STEPS, ("preferences", "machine", "cloud"))
|
||||||
|
self.assertEqual(setup.REQUIRED_STEPS, ("preferences", "machine", "cloud", "cooling.flow"))
|
||||||
|
self.assertIn("cooling.flow", setup.REQUIRED_STEPS)
|
||||||
|
|
||||||
def test_the_gate_test_starts_from_an_open_gate_and_the_intake_tests_from_a_count(self):
|
def test_the_gate_test_starts_from_an_open_gate_and_the_intake_tests_from_a_count(self):
|
||||||
reg = self.reg
|
reg = self.reg
|
||||||
@@ -191,9 +193,10 @@ class RecordTests(unittest.TestCase):
|
|||||||
rec["wizards"]["switches"] = {"version": 1}
|
rec["wizards"]["switches"] = {"version": 1}
|
||||||
rec["flags"] = {"machine": {"reason": "the head was replaced"}}
|
rec["flags"] = {"machine": {"reason": "the head was replaced"}}
|
||||||
out = setup.record_with_required_steps(rec)
|
out = setup.record_with_required_steps(rec)
|
||||||
self.assertEqual(sorted(out["wizards"]), ["cloud", "machine", "preferences"])
|
self.assertEqual(sorted(out["wizards"]), ["cloud", "cooling.flow", "machine", "preferences"])
|
||||||
self.assertEqual(out["wizards"]["machine"]["result"], {"model": "basic"}) # kept from the record
|
self.assertEqual(out["wizards"]["machine"]["result"], {"model": "basic"}) # kept from the record
|
||||||
self.assertEqual(out["wizards"]["preferences"]["version"], 1) # written at version 1
|
self.assertEqual(out["wizards"]["preferences"]["version"], 1) # written at version 1
|
||||||
|
self.assertEqual(out["wizards"]["cooling.flow"]["version"], 1)
|
||||||
self.assertEqual(out["flags"], {})
|
self.assertEqual(out["flags"], {})
|
||||||
self.assertEqual(out["account"], rec["account"])
|
self.assertEqual(out["account"], rec["account"])
|
||||||
self.assertIn("switches", rec["wizards"]) # a copy
|
self.assertIn("switches", rec["wizards"]) # a copy
|
||||||
|
|||||||
Reference in New Issue
Block a user