UX-15: mutations fail named checks, not crashes
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -28,7 +28,7 @@ HERE = os.path.dirname(os.path.abspath(__file__))
|
|||||||
sys.path.insert(0, os.path.join(HERE, "tools"))
|
sys.path.insert(0, os.path.join(HERE, "tools"))
|
||||||
logging.disable(logging.WARNING) # the validator's own log lines
|
logging.disable(logging.WARNING) # the validator's own log lines
|
||||||
|
|
||||||
from aiohttp import ClientSession, web as aioweb # noqa: E402
|
from aiohttp import ClientSession, ContentTypeError, web as aioweb # noqa: E402
|
||||||
|
|
||||||
import translations_lint as TL # noqa: E402
|
import translations_lint as TL # noqa: E402
|
||||||
import ux13_demo as D # noqa: E402
|
import ux13_demo as D # noqa: E402
|
||||||
@@ -264,7 +264,10 @@ async def _get(s, url):
|
|||||||
|
|
||||||
async def _post(s, url, body):
|
async def _post(s, url, body):
|
||||||
async with s.post(url, json=body) as r:
|
async with s.post(url, json=body) as r:
|
||||||
return r.status, await r.json()
|
try:
|
||||||
|
return r.status, await r.json()
|
||||||
|
except (ValueError, ContentTypeError): # e.g. a plain-text 500
|
||||||
|
return r.status, {}
|
||||||
|
|
||||||
|
|
||||||
STATES = [state("sensor.grid", "402"), state("number.inv1_power", "0"),
|
STATES = [state("sensor.grid", "402"), state("number.inv1_power", "0"),
|
||||||
@@ -790,18 +793,18 @@ async def _f1(s, root, sup):
|
|||||||
|
|
||||||
_r, _sup = asyncio.run(session(Controller(SITE, STATES, Store(), grid=402.0),
|
_r, _sup = asyncio.run(session(Controller(SITE, STATES, Store(), grid=402.0),
|
||||||
SITE, _f1))
|
SITE, _f1))
|
||||||
print(f" empty day price: steps {_r['price']['steps']}")
|
print(f" empty day price: steps {_r['price'].get('steps')}")
|
||||||
check("F1: a price the page cannot turn into options blocks step 4, beside "
|
check("F1: a price the page cannot turn into options blocks step 4, beside "
|
||||||
"its own field",
|
"its own field",
|
||||||
_r["price"]["steps"]["4"] >= 1
|
_r["price"].get("steps", {}).get("4", 0) >= 1
|
||||||
and {"field": "ui.day_price", "card": None, "tier": "bad",
|
and {"field": "ui.day_price", "card": None, "tier": "bad",
|
||||||
"text": WS_D["no_price"]["description"]} in _r["price"]["messages"])
|
"text": WS_D["no_price"]["description"]} in _r["price"].get("messages", []))
|
||||||
check("F1: ...and the last step's live checks still run on the rest",
|
check("F1: ...and the last step's live checks still run on the rest",
|
||||||
[x["tier"] for x in _r["price"].get("setup", [])
|
[x["tier"] for x in _r["price"].get("setup", [])
|
||||||
if "number.inv1_power" in x["text"]] == ["ok"]
|
if "number.inv1_power" in x["text"]] == ["ok"]
|
||||||
and any("402 W" in x["text"] for x in _r["price"]["setup"]))
|
and any("402 W" in x["text"] for x in _r["price"]["setup"]))
|
||||||
check("F1: no inverter card blocks step 2, not the last step alone",
|
check("F1: no inverter card blocks step 2, not the last step alone",
|
||||||
_r["none"]["steps"]["2"] >= 1)
|
_r["none"].get("steps", {}).get("2", 0) >= 1)
|
||||||
check("F1: the save refuses it (422) and says which step to go back to",
|
check("F1: the save refuses it (422) and says which step to go back to",
|
||||||
_r["save"][0] == 422 and _r["save"][1]["steps"]["4"] >= 1
|
_r["save"][0] == 422 and _r["save"][1]["steps"]["4"] >= 1
|
||||||
and _sup.writes == [])
|
and _sup.writes == [])
|
||||||
|
|||||||
@@ -339,10 +339,14 @@ class Session:
|
|||||||
|
|
||||||
|
|
||||||
def _refused(coro):
|
def _refused(coro):
|
||||||
|
"""True only for the read-only refusal; a request that reached the
|
||||||
|
session (AssertionError there) or no refusal at all is False."""
|
||||||
try:
|
try:
|
||||||
asyncio.run(coro)
|
asyncio.run(coro)
|
||||||
except H.ReadOnly:
|
except H.ReadOnly:
|
||||||
return True
|
return True
|
||||||
|
except Exception: # noqa: BLE001
|
||||||
|
return False
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
@@ -372,8 +376,10 @@ check("control: a normal HomeAssistant does send the write", _sent
|
|||||||
try:
|
try:
|
||||||
M.Controller(dict(_ok), _ro, None, None, stop=asyncio.Event())
|
M.Controller(dict(_ok), _ro, None, None, stop=asyncio.Event())
|
||||||
_built = True
|
_built = True
|
||||||
except ValueError:
|
except ValueError as err:
|
||||||
_built = False
|
_built = "read-only" not in str(err)
|
||||||
|
except Exception: # noqa: BLE001
|
||||||
|
_built = True # it got past the check and failed on something else
|
||||||
check("no controller can be built on a read-only HomeAssistant", not _built)
|
check("no controller can be built on a read-only HomeAssistant", not _built)
|
||||||
try:
|
try:
|
||||||
setuponly.SetupOnly(SHIPPED, _rw, None)
|
setuponly.SetupOnly(SHIPPED, _rw, None)
|
||||||
|
|||||||
Reference in New Issue
Block a user