adaptive-lighting/tests/test_native_group_models.py

97 lines
2.7 KiB
Python

"""Native request snapshots and completed-invocation retention contracts."""
import gc
import weakref
from unittest.mock import Mock
import pytest
from homeassistant.components.adaptive_lighting.adaptation_utils import (
LightControlAttributes,
)
from homeassistant.components.adaptive_lighting.native_group_models import (
AttributePolicy,
BatchExecution,
NativeIntent,
NativePlan,
)
from homeassistant.core import Context
@pytest.mark.parametrize(
("attribute", "vector"),
[
("rgb_color", [255, 56, 0]),
("xy_color", [0.4, 0.3]),
("hs_color", [30, 75]),
("rgbw_color", [255, 56, 0, 80]),
("rgbww_color", [255, 56, 0, 80, 100]),
],
)
def test_colour_intent_detaches_mutable_colour_vectors(attribute, vector):
"""Queued colour is fixed even when the preparation payload changes later."""
expected = tuple(vector)
source = {attribute: vector, "transition": 1}
intent = NativeIntent(
colour=source,
explicit=LightControlAttributes.NONE,
version=0,
source="light.member",
policies={LightControlAttributes.COLOR: AttributePolicy(Mock(), 0)},
)
source["transition"] = 2
vector[0] = 0
dispatch = dict(intent.colour)
dispatch[attribute] = tuple(0 for _ in vector)
assert intent.colour[attribute] == expected
assert intent.colour["transition"] == 1
with pytest.raises(TypeError):
intent.colour[attribute][0] = 0
def test_complete_request_snapshot_detaches_scene_colour_vectors():
"""Later scene payload edits cannot change the request used for child matching."""
colour = [255, 56, 0]
request = {"state": "on", "rgb_color": colour}
requests = {"light.member": request}
plan = NativePlan(Context(), requests, {}, {})
colour[0] = 0
request["state"] = "off"
requests.clear()
assert plan.requests["light.member"] == {
"state": "on",
"rgb_color": (255, 56, 0),
}
def test_closed_execution_releases_error_traceback_payload():
"""A late-report claim retaining outcomes must not retain failed request frames."""
execution = BatchExecution()
class RequestPayload:
"""Stand in for request data reachable through a failed handler frame."""
def fail_request():
raise ValueError
def record_failure():
payload = RequestPayload()
reference = weakref.ref(payload)
try:
fail_request()
except ValueError as error:
execution.errors.append(error)
return reference
reference = record_failure()
gc.collect()
assert reference() is not None
execution.close()
gc.collect()
assert execution.closed
assert reference() is None