Skip to content

Commit

Permalink
[clusters] Fix scheduled actions in clusters (project-chip#10001)
Browse files Browse the repository at this point in the history
PR project-chip#9469 changed the implementation of
EventControlHandler function from af-event.cpp, but only
updated Color Control Cluster code to use the new approach.
As a result, all other clusters using scheduled actions,
such as LevelControl.MoveToLevel, got broken.

Make sure both methods of initializing cluster events are
supported until all clusters are aligned one way or another.
Also, add a cirque test for LevelControl.MoveToLevel.
  • Loading branch information
Damian-Nordic authored and jimlyall-q committed Oct 11, 2021
1 parent 19398a2 commit cad4818
Show file tree
Hide file tree
Showing 6 changed files with 83 additions and 45 deletions.
10 changes: 10 additions & 0 deletions src/app/util/af-event.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,16 @@ void EventControlHandler(chip::System::Layer * systemLayer, void * appState)
if (control->callback != NULL)
{
(control->callback)(control->endpoint);
return;
}

for (const EmberEventData & event : emAfEvents)
{
if (event.control != control)
continue;
control->status = EMBER_EVENT_INACTIVE;
event.handler();
break;
}
}
}
Expand Down
88 changes: 63 additions & 25 deletions src/controller/python/test/test_scripts/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,29 @@ def run(self):
TestFail("Timeout")


class TestResult:
def __init__(self, operationName, result):
self.operationName = operationName
self.result = result

def assertStatusEqual(self, expected):
if self.result is None:
raise Exception(f"{self.operationName}: no result got")
if self.result.status != expected:
raise Exception(
f"{self.operationName}: expected status {expected}, got {self.result.status}")
return self

def assertValueEqual(self, expected):
self.assertStatusEqual(0)
if self.result is None:
raise Exception(f"{self.operationName}: no result got")
if self.result.value != expected:
raise Exception(
f"{self.operationName}: expected value {expected}, got {self.result.value}")
return self


class BaseTestHelper:
def __init__(self, nodeid: int):
self.devCtrl = ChipDeviceCtrl.ChipDeviceController(
Expand Down Expand Up @@ -163,6 +186,39 @@ def TestOnOffCluster(self, nodeid: int, endpoint: int, group: int):
return False
return True

def TestLevelControlCluster(self, nodeid: int, endpoint: int, group: int):
self.logger.info(
f"Sending MoveToLevel command to device {nodeid} endpoint {endpoint}")
try:
commonArgs = dict(transitionTime=0, optionMask=0, optionOverride=0)

# Move to 0
self.devCtrl.ZCLSend("LevelControl", "MoveToLevel", nodeid,
endpoint, group, dict(**commonArgs, level=0), blocking=True)
res = self.devCtrl.ZCLReadAttribute(cluster="LevelControl",
attribute="CurrentLevel",
nodeid=nodeid,
endpoint=endpoint,
groupid=group)
TestResult("Read attribute LevelControl.CurrentLevel",
res).assertValueEqual(0)

# Move to 255
self.devCtrl.ZCLSend("LevelControl", "MoveToLevel", nodeid,
endpoint, group, dict(**commonArgs, level=255), blocking=True)
res = self.devCtrl.ZCLReadAttribute(cluster="LevelControl",
attribute="CurrentLevel",
nodeid=nodeid,
endpoint=endpoint,
groupid=group)
TestResult("Read attribute LevelControl.CurrentLevel",
res).assertValueEqual(255)

return True
except Exception as ex:
self.logger.exception(f"Level cluster test failed: {ex}")
return False

def TestResolve(self, nodeid):
fabricid = self.devCtrl.GetCompressedFabricId()
self.logger.info(
Expand All @@ -178,7 +234,7 @@ def TestResolve(self, nodeid):
self.logger.exception("Failed to resolve. {}".format(ex))
return False

def TestReadBasicAttribiutes(self, nodeid: int, endpoint: int, group: int):
def TestReadBasicAttributes(self, nodeid: int, endpoint: int, group: int):
basic_cluster_attrs = {
"VendorName": "TEST_VENDOR",
"VendorID": 9050,
Expand All @@ -199,15 +255,8 @@ def TestReadBasicAttribiutes(self, nodeid: int, endpoint: int, group: int):
nodeid=nodeid,
endpoint=endpoint,
groupid=group)
if res is None:
raise Exception(
"Read {} attribute: no value get".format(basic_attr))
elif res.status != 0:
raise Exception(
"Read {} attribute: non-zero status code {}".format(basic_attr, res.status))
elif res.value != expected_value:
raise Exception("Read {} attribute: expect {} got {}".format(
basic_attr, repr(expected_value), repr(res.value)))
TestResult(f"Read attribute {basic_attr}", res).assertValueEqual(
expected_value)
except Exception as ex:
failed_zcl[basic_attr] = str(ex)
if failed_zcl:
Expand Down Expand Up @@ -237,26 +286,15 @@ class AttributeWriteRequest:
endpoint=endpoint,
groupid=group,
value=req.value)
if res is None:
raise Exception(
f"Write {req.cluster}.{req.attribute} attribute: no value get")
elif res.status != req.expected_status:
raise Exception(
f"Write {req.cluster}.{req.attribute} attribute: expected status is {req.expected_status} got {res.status}")
TestResult(f"Write attribute {req.cluster}.{req.attribute}", res).assertStatusEqual(
req.expected_status)
if req.expected_status != IM.ProtocolCode.Success:
# If the write interaction is expected to success, proceed to verify it.
continue
res = self.devCtrl.ZCLReadAttribute(
cluster=req.cluster, attribute=req.attribute, nodeid=nodeid, endpoint=endpoint, groupid=group)
if res is None:
raise Exception(
f"Read written {req.cluster}.{req.attribute} attribute: failed to read attribute")
elif res.status != 0:
raise Exception(
f"Read written {req.cluster}.{req.attribute} attribute: non-zero status code {res.status}")
elif res.value != req.value:
raise Exception(
f"Read written {req.cluster}.{req.attribute} attribute: expected {req.value} got {res.value}")
TestResult(f"Read attribute {req.cluster}.{req.attribute}", res).assertValueEqual(
req.value)
except Exception as ex:
failed_zcl.append(str(ex))
if failed_zcl:
Expand Down
12 changes: 9 additions & 3 deletions src/controller/python/test/test_scripts/mobile-device-test.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,15 +96,21 @@ def main():
endpoint=LIGHTING_ENDPOINT_ID,
group=GROUP_ID), "Failed to test on off cluster")

logger.info("Testing level control cluster")
FailIfNot(test.TestLevelControlCluster(nodeid=1,
endpoint=LIGHTING_ENDPOINT_ID,
group=GROUP_ID),
"Failed to test level control cluster")

logger.info("Testing sending commands to non exist endpoint")
FailIfNot(not test.TestOnOffCluster(nodeid=1,
endpoint=233,
group=GROUP_ID), "Failed to test on off cluster on non-exist endpoint")

logger.info("Testing attribute reading")
FailIfNot(test.TestReadBasicAttribiutes(nodeid=1,
endpoint=ENDPOINT_ID,
group=GROUP_ID),
FailIfNot(test.TestReadBasicAttributes(nodeid=1,
endpoint=ENDPOINT_ID,
group=GROUP_ID),
"Failed to test Read Basic Attributes")

logger.info("Testing attribute writing")
Expand Down
2 changes: 1 addition & 1 deletion src/test_driver/linux-cirque/MobileDeviceTest.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@

from helper.CHIPTestBase import CHIPVirtualHome

logger = logging.getLogger('CHIPInteractionModelTest')
logger = logging.getLogger('MobileDeviceTest')
logger.setLevel(logging.INFO)

sh = logging.StreamHandler()
Expand Down
8 changes: 0 additions & 8 deletions zzz_generated/thermostat/zap-generated/af-gen-event.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 0 additions & 8 deletions zzz_generated/tv-casting-app/zap-generated/af-gen-event.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit cad4818

Please sign in to comment.