mirror of
https://github.com/openglow-org/forgefirm.git
synced 2026-09-27 08:41:13 -07:00
Check a print's warm-up and rest where a print already runs
cloud.pause-resume runs a print end to end, which is exactly what the job lifecycle needs to be seen: a non-zero hold before the first fire, a non-zero rest after the park, and neither on the connect-time hunt in the same session. Folding the checks in there costs the operator nothing, where a test of its own would cost another print. The forgetest replay noticed first: it plays a real captured log from a build that predates those lines. Rather than editing what the machine said that day, the replay carries the two lines where the current build emits them. BRINGUP's cloud item now names what is actually open on the header keys, the park and the two periods, and records that the pause constants were looked for in the wrong place.
This commit is contained in:
+7
-2
@@ -984,8 +984,13 @@ Open items only. Anything closed is in `CAMPAIGN-LOG.md`.
|
||||
live job longer than the ring (built and covered, never yet run from the
|
||||
service), the memory guards against a real ceiling rather than a reasoned
|
||||
one, packaged-path boot with `controller_mode = cloud`, the three unobserved
|
||||
actions, the lid-flash LED, and taking the pause constants from the pulse
|
||||
header (`CCbp`/`CCbt`) once a capture confirms them. Not inducible from the bench: the
|
||||
actions, the lid-flash LED, and driving the park and the two lifecycle
|
||||
periods off the header (`CFrh`, `CCwp`, `CCrp`) once a capture confirms
|
||||
what they mean; the machine warms up and rests on the factory's measured
|
||||
timings meanwhile, and logs those keys on every job. (`CCbp`/`CCbt`, read
|
||||
earlier as the pause constants, are refuted: the factory's tag table marks
|
||||
them report-only, so they cannot appear in a pulse header at all.) Not
|
||||
inducible from the bench: the
|
||||
cancel-with-a-rejected-`settings`-action case, a malformed frame (needs a
|
||||
MITM), a body past the memory guard (the service has no such job to send),
|
||||
and a wedged feed (a healthy machine will not stall on request). The pulse header's unenforced safety envelope is item 19: it is
|
||||
|
||||
@@ -728,7 +728,10 @@ def hunt_lid_open(ctx):
|
||||
description="Pressing the button during a cloud print pauses it the factory way - controlled "
|
||||
"stop, backtrack with the laser off, print:paused - and the next press resumes "
|
||||
"with the laser-off lead, print:resumed; the job then completes and parks. The "
|
||||
"latch stays unlocked and the armed window open through the pause.")
|
||||
"latch stays unlocked and the armed window open through the pause. The same "
|
||||
"print is where the job's lifecycle shows: a print warms up before its first "
|
||||
"fire and rests after its park, both non-zero, while the connect-time hunt in "
|
||||
"the same session does neither.")
|
||||
def pause_resume(ctx):
|
||||
ev = ctx.evidence
|
||||
offset = enter_cloud(ctx)
|
||||
@@ -759,8 +762,38 @@ def pause_resume(ctx):
|
||||
ctx.check(not relocked, "the pause relocked or cancelled the job (%s)", relocked[:2])
|
||||
ctx.confirm("Did the head stop and back up a few millimeters (laser off) on the first press, "
|
||||
"resume on the second, and did the job finish and the app show it complete?")
|
||||
|
||||
# The job's lifecycle, from the same print: a warm-up before the first
|
||||
# fire and a rest after the park are equipment protection the service
|
||||
# assumes has happened, and a machine configured to skip them says so in
|
||||
# the log rather than quietly not doing them.
|
||||
lines = log_lines_since(GFCLOUD_LOG, offset)
|
||||
holds = {"warm up": None, "cool down": None}
|
||||
for ln in lines:
|
||||
for phase in holds:
|
||||
if holds[phase] is None and ("%s: holding" % phase) in ln:
|
||||
holds[phase] = ln.strip()[:160]
|
||||
if holds[phase] is None and ("%s: skipped" % phase) in ln:
|
||||
holds[phase] = ln.strip()[:160]
|
||||
ev["lifecycle"] = holds
|
||||
ctx.log("warm-up: %s", holds["warm up"])
|
||||
ctx.log("rest: %s", holds["cool down"])
|
||||
for phase in ("warm up", "cool down"):
|
||||
ctx.check(holds[phase] is not None, "the print logged no %s at all", phase)
|
||||
ctx.check(holds[phase] and "holding" in holds[phase],
|
||||
"the print skipped its %s (%s): the config still carries a zero",
|
||||
phase, holds[phase])
|
||||
# A hunt is not a print: the connect-time hunt ran in this same session
|
||||
# and must not have held for either period.
|
||||
hunt_end = next((i for i, ln in enumerate(lines) if "waiting for button" in ln), len(lines))
|
||||
early_holds = [ln.strip()[:120] for ln in lines[:hunt_end]
|
||||
if "warm up: holding" in ln or "cool down: holding" in ln]
|
||||
ev["holds_before_the_print"] = early_holds
|
||||
ctx.check(not early_holds, "a hunt or motion held for a print's periods: %s", early_holds[:2])
|
||||
|
||||
settle_cloud(ctx, offset)
|
||||
ctx.log("PASS: button pause/resume mid-print, job completed and parked")
|
||||
ctx.log("PASS: button pause/resume mid-print, warm-up and rest observed, job completed "
|
||||
"and parked")
|
||||
|
||||
|
||||
@test("cloud.oversize-stream", title="A print longer than the ring is fed while it plays",
|
||||
|
||||
@@ -32,6 +32,13 @@ def fixture(name):
|
||||
return f.read().decode().splitlines()
|
||||
|
||||
|
||||
# What the build under test logs around a print, in the machine's own format.
|
||||
WARM_UP_LINE = ("2026-08-17T09:44:02.100000+00:00 gfcloud[1522] INFO "
|
||||
"machine:_dwell warm up: holding 3.0 s")
|
||||
COOL_DOWN_LINE = ("2026-08-17T09:45:31.700000+00:00 gfcloud[1522] INFO "
|
||||
"machine:_dwell cool down: holding 10.0 s")
|
||||
|
||||
|
||||
def cut(lines, marker, count=1):
|
||||
"""(before, after) at the count-th line containing marker (the line
|
||||
itself opens `after`)."""
|
||||
@@ -281,8 +288,13 @@ class CloudSuiteTests(unittest.TestCase):
|
||||
lines = fixture(name)
|
||||
pre, rest = cut(lines, "waiting for button")
|
||||
run_pre, rest = cut(rest, "current state: MachineState.RUNNING") # the PRINT's run
|
||||
# The excerpt was captured before the machine held for a warm-up and
|
||||
# a rest; the replay carries those two lines where it emits them now,
|
||||
# rather than editing what the machine actually said that day.
|
||||
run_pre = run_pre + [WARM_UP_LINE]
|
||||
pre, rest = pre + run_pre + [rest[0]], rest[1:]
|
||||
mid, tail = cut(rest, at_end)
|
||||
tail = tail + [COOL_DOWN_LINE]
|
||||
return {"Click Done here": lambda: self.append(pre, delay=0.1),
|
||||
at_run: lambda: (self.append(mid, delay=0.05), self.append(tail, delay=tail_delay))}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user