Skip to content

Commit 2abcd8e

Browse files
authored
Create test_boot_no_loop.py
1 parent 2e59371 commit 2abcd8e

1 file changed

Lines changed: 62 additions & 0 deletions

File tree

tests/hil/test_boot_no_loop.py

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
# deps: pytest, pytest-embedded, pytest-embedded-serial, pytest-embedded-idf
2+
# Detects reboot loops using only standard boot/panic text patterns.
3+
4+
import re
5+
import time
6+
7+
# Common boot banners from ROM/bootloader
8+
BOOT_MARKERS = [
9+
re.compile(r"\bESP-ROM:", re.I),
10+
re.compile(r"\brst:0x[0-9a-f]+\b", re.I), # e.g. rst:0xc (SW_CPU_RESET)
11+
re.compile(r"\bboot:0x[0-9a-f]+\b", re.I), # e.g. boot:0x20c
12+
re.compile(r"\bboot:\s+ESP-IDF\b", re.I), # "I (...) boot: ESP-IDF v..."
13+
re.compile(r"\bentry 0x[0-9a-f]+\b", re.I),
14+
]
15+
16+
# Common fatal/panic signatures
17+
PANIC_MARKERS = [
18+
re.compile(r"\bBacktrace:\b", re.I),
19+
re.compile(r"\babort\(\)\s+was\s+called\b", re.I),
20+
re.compile(r"\bGuru Meditation Error\b", re.I),
21+
re.compile(r"\bWDT\b", re.I), # watchdog resets
22+
]
23+
24+
def _has_any(line: str, pats) -> bool:
25+
return any(p.search(line) for p in pats)
26+
27+
def test_boots_once_and_does_not_loop(dut):
28+
"""
29+
Procedure:
30+
1) Let pytest-embedded flash and start the DUT.
31+
2) Consume serial until we see the first complete boot sequence.
32+
3) Then watch for 30s; if any boot markers or panic markers reappear, fail.
33+
"""
34+
# Phase 1: consume initial boot (first marker set must appear)
35+
saw_first_boot = False
36+
t0 = time.time()
37+
while time.time() - t0 < 15.0: # up to 15s to get through bootloader->app
38+
buf = dut.read(timeout=1.0) or b""
39+
line = buf.decode(errors="ignore")
40+
if _has_any(line, BOOT_MARKERS):
41+
saw_first_boot = True
42+
# keep consuming until boot banners quiet down for a moment
43+
# (heuristic) break once we hit a lull
44+
if saw_first_boot and not line.strip():
45+
break
46+
assert saw_first_boot, "Never observed initial ESP-IDF/ROM boot markers on UART"
47+
48+
# Phase 2: verify no reboots/panics for 30s
49+
reboots = 0
50+
panics = 0
51+
t1 = time.time()
52+
while time.time() - t1 < 30.0:
53+
buf = dut.read(timeout=1.0) or b""
54+
line = buf.decode(errors="ignore")
55+
if _has_any(line, PANIC_MARKERS):
56+
panics += 1
57+
raise AssertionError(f"Panic detected: {line.strip()[:200]}")
58+
if _has_any(line, BOOT_MARKERS):
59+
reboots += 1
60+
raise AssertionError(f"Reboot/boot-loop detected (marker seen again): {line.strip()[:200]}")
61+
62+
# If we reach here, the app stayed up without printing boot/panic markers again.

0 commit comments

Comments
 (0)