ESPSomfy-RTS/test/e2e/test_update.py
cjkas 92cd54f097 fix: review fixes for the shades.cfg records
- A group in a backup from before version 23 has no rolling code, and a
  restore wrote 0 to NVS for it.  It keeps the code NVS has.
- A restore reads each record into one that starts as the shade, group
  or settings it replaces, so what an older version lacks stays as it
  was (the update check below version 20 among them), as before.
- restoreFile and loadFile read the rooms, shades and groups through one
  readModel(); the settings, network and radio are applied by helpers.
- The shade's tilt is forgotten where the shades are written, not in the
  conversion to a record.
- rollingCodeAfterLoad moves to RollingCode.h and its tests to
  test_rollingcode.
- The topics a deleted shade or group clears are one list each
  (MqttTopics.h), tested against what is published.
- e2e: a restore of the shades brings back every shade and group, and
  the README has the rollback check by hand.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 17:25:07 +01:00

52 lines
1.8 KiB
Python

"""A firmware update through /updateFirmware, as the web UI sends it.
Pass --firmware with a firmware.bin built for the device's chip, e.g.
.pio/build/esp32s3/firmware.bin. The device must have an OTA slot: the
release builds do, the C5, C6 and debug builds don't.
It can't tell the new firmware from the old when both have the same
version, and it doesn't make the update fail. test/e2e/README.md has the
rollback check by hand.
"""
import time
import pytest
from proto_client import run_sync
from test_routes import auth, upload
from test_settings import boot_time, wait_for_restart
# The new firmware is marked good once it has run this long with the network
# up; a reset before then boots the old one (docs/adr/0003-pioarduino-idf55.md).
PROVEN_AFTER_S = 60
@pytest.fixture
def firmware(request):
path = request.config.getoption("--firmware")
if not path:
pytest.skip("updates the device's firmware: pass --firmware <firmware.bin>")
with open(path, "rb") as f:
return f.read()
def test_an_update_restarts_on_the_new_firmware_and_stays(host, token, connect, schema, firmware):
c = connect(schema=schema.hash)
_, frames, _ = run_sync(c)
booted = boot_time(schema, frames)
c.close()
status, _, body = upload(host, "/updateFirmware", auth(token), file=firmware)
assert status == 200, body
wait_for_restart(host, token, schema, booted)
# Past the point where it is marked good it is still running, and hasn't
# restarted on the old firmware.
c = connect(schema=schema.hash)
_, frames, _ = run_sync(c)
restarted = boot_time(schema, frames)
c.close()
time.sleep(PROVEN_AFTER_S + 10)
c = connect(schema=schema.hash)
_, frames, _ = run_sync(c)
assert abs(boot_time(schema, frames) - restarted) < 5, "the device restarted again"