mirror of
https://github.com/esphome/esphome.git
synced 2026-10-07 11:26:39 +00:00
Fold the duplicated noise gate and inflate bookkeeping
One predicate for the noise offer and one place that allocates the session; the window is already zero from value initialization, so drop the second clearing pass. The RP2 backend reads the framework version from the define ESPHome already emits rather than a vendor header, the inflate counter moves into the test device helper, and the corrupt stream sweep takes a coarser stride for the same coverage.
This commit is contained in:
@@ -306,7 +306,8 @@ TEST(OtaInflate, CorruptStreamsNeverEscapeTheWindow) {
|
||||
// Flipped bytes and garbage; the sanitizers check the decoder stays in bounds
|
||||
auto s = std::make_unique<Session>();
|
||||
std::vector<uint8_t> bad(DEFLATED, DEFLATED + sizeof(DEFLATED));
|
||||
for (size_t i = 0; i < bad.size(); i += 3) {
|
||||
// A coarse, non-aligned stride: neighbouring offsets hit the same paths
|
||||
for (size_t i = 0; i < bad.size(); i += 29) {
|
||||
bad[i] ^= 0x5a;
|
||||
inflate_all(*s, bad.data(), bad.size(), 1040);
|
||||
bad[i] ^= 0x5a;
|
||||
|
||||
@@ -122,6 +122,7 @@ class _Device:
|
||||
binary_path: Path
|
||||
proc: asyncio.subprocess.Process | None = None
|
||||
reboots: int = 0
|
||||
inflates: int = 0
|
||||
|
||||
def __post_init__(self) -> None:
|
||||
self._rebooted = asyncio.Event()
|
||||
@@ -130,6 +131,8 @@ class _Device:
|
||||
if "Rebooting safely" in line:
|
||||
self.reboots += 1
|
||||
self._rebooted.set()
|
||||
if "Inflated " in line and " bytes from " in line:
|
||||
self.inflates += 1
|
||||
|
||||
async def wait_reboot(self, count: int, timeout: float = 10.0) -> None:
|
||||
async with asyncio.timeout(timeout):
|
||||
@@ -180,14 +183,10 @@ async def test_host_ota_self_update(
|
||||
)
|
||||
)
|
||||
staged = asyncio.Event()
|
||||
inflated = asyncio.Event()
|
||||
|
||||
def on_log(line: str) -> None:
|
||||
if "OTA staged at" in line:
|
||||
staged.set()
|
||||
# The host backend cannot store gzip, so the upload negotiates deflate
|
||||
if "Inflated " in line and " bytes from " in line:
|
||||
inflated.set()
|
||||
dev.on_log(line)
|
||||
|
||||
async with run_binary(dev.binary_path, line_callback=on_log) as (proc, _lines):
|
||||
@@ -199,7 +198,6 @@ async def test_host_ota_self_update(
|
||||
|
||||
await dev.ota(None, None, "espota2 reported failure")
|
||||
assert staged.is_set()
|
||||
assert inflated.is_set(), "upload was not deflate compressed"
|
||||
|
||||
async with wait_and_connect_api_client(port=dev.api_port) as client:
|
||||
info_after = await client.device_info()
|
||||
@@ -224,13 +222,15 @@ async def test_host_ota_deflate(
|
||||
yaml_config, write_yaml_config, compile_esphome, reserved_tcp_port
|
||||
)
|
||||
)
|
||||
inflated: list[str] = []
|
||||
errors: list[str] = []
|
||||
|
||||
def on_log(line: str) -> None:
|
||||
if "Inflated " in line and " bytes from " in line:
|
||||
inflated.append(line)
|
||||
if "Inflate err" in line or "End update err" in line:
|
||||
# A corrupt stream is caught by the decoder, by the size check or by
|
||||
# the MD5 at the end, depending on where the damage lands
|
||||
if any(
|
||||
text in line
|
||||
for text in ("Inflate err", "Inflate overrun", "End update err")
|
||||
):
|
||||
errors.append(line)
|
||||
dev.on_log(line)
|
||||
|
||||
@@ -247,12 +247,12 @@ async def test_host_ota_deflate(
|
||||
|
||||
# Default: the host backend cannot store gzip, so the CLI sends deflate
|
||||
await dev.ota(None, None, "deflate upload failed")
|
||||
assert len(inflated) == 1, "device did not inflate the upload"
|
||||
assert dev.inflates == 1, "device did not inflate the upload"
|
||||
|
||||
# A client that does not offer deflate is served uncompressed
|
||||
monkeypatch.setattr(espota2, "CLIENT_FEATURE_SUPPORTS_DEFLATE", 0)
|
||||
await dev.ota(None, None, "uncompressed upload failed")
|
||||
assert len(inflated) == 1, "device inflated without a client offer"
|
||||
assert dev.inflates == 1, "device inflated without a client offer"
|
||||
monkeypatch.undo()
|
||||
|
||||
# A corrupt stream fails the upload and leaves the device running
|
||||
@@ -262,9 +262,8 @@ async def test_host_ota_deflate(
|
||||
assert errors, "device did not report the corrupt stream"
|
||||
|
||||
# and it still takes a good upload afterwards
|
||||
inflated_before = len(inflated)
|
||||
await dev.ota(None, None, "upload after a rejected stream failed")
|
||||
assert len(inflated) == inflated_before + 1
|
||||
assert dev.inflates == 2
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
||||
Reference in New Issue
Block a user