Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix issue with chip-repl yamltest running TestClusterComplexTypes.yaml #24502

Merged
merged 6 commits into from
Jan 20, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion scripts/tests/chiptest/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,10 @@ def tests_with_command(chip_tool: str, is_manual: bool):
# TODO We will move away from hardcoded list of yamltests to run all file when yamltests
# parser/runner reaches parity with the code gen version.
def _hardcoded_python_yaml_tests():
currently_supported_yaml_tests = ["TestConstraints.yaml"]
currently_supported_yaml_tests = [
"TestClusterComplexTypes.yaml",
"TestConstraints.yaml",
]

for name in currently_supported_yaml_tests:
yaml_test_path = _FindYamlTestPath(name)
Expand Down
8 changes: 4 additions & 4 deletions src/controller/python/chip/ChipDeviceCtrl.py
Original file line number Diff line number Diff line change
Expand Up @@ -846,7 +846,7 @@ def ComputeRoundTripTimeout(self, nodeid, upperLayerProcessingTimeoutMs: int = 0
device.deviceProxy, upperLayerProcessingTimeoutMs))
return res

async def SendCommand(self, nodeid: int, endpoint: int, payload: ClusterObjects.ClusterCommand, responseType=None, timedRequestTimeoutMs: int = None, interactionTimeoutMs: int = None):
async def SendCommand(self, nodeid: int, endpoint: int, payload: ClusterObjects.ClusterCommand, responseType=None, timedRequestTimeoutMs: int = None, interactionTimeoutMs: int = None, busyWaitMs: int = None):
'''
Send a cluster-object encapsulated command to a node and get returned a future that can be awaited upon to receive the response.
If a valid responseType is passed in, that will be used to deserialize the object. If not, the type will be automatically deduced
Expand All @@ -867,10 +867,10 @@ async def SendCommand(self, nodeid: int, endpoint: int, payload: ClusterObjects.
EndpointId=endpoint,
ClusterId=payload.cluster_id,
CommandId=payload.command_id,
), payload, timedRequestTimeoutMs=timedRequestTimeoutMs, interactionTimeoutMs=interactionTimeoutMs).raise_on_error()
), payload, timedRequestTimeoutMs=timedRequestTimeoutMs, interactionTimeoutMs=interactionTimeoutMs, busyWaitMs=busyWaitMs).raise_on_error()
return await future

async def WriteAttribute(self, nodeid: int, attributes: typing.List[typing.Tuple[int, ClusterObjects.ClusterAttributeDescriptor, int]], timedRequestTimeoutMs: int = None, interactionTimeoutMs: int = None):
async def WriteAttribute(self, nodeid: int, attributes: typing.List[typing.Tuple[int, ClusterObjects.ClusterAttributeDescriptor, int]], timedRequestTimeoutMs: int = None, interactionTimeoutMs: int = None, busyWaitMs: int = None):
tehampson marked this conversation as resolved.
Show resolved Hide resolved
'''
Write a list of attributes on a target node.

Expand Down Expand Up @@ -900,7 +900,7 @@ async def WriteAttribute(self, nodeid: int, attributes: typing.List[typing.Tuple
v[0], v[1], v[2], 1, v[1].value))

ClusterAttribute.WriteAttributes(
future, eventLoop, device.deviceProxy, attrs, timedRequestTimeoutMs=timedRequestTimeoutMs, interactionTimeoutMs=interactionTimeoutMs).raise_on_error()
future, eventLoop, device.deviceProxy, attrs, timedRequestTimeoutMs=timedRequestTimeoutMs, interactionTimeoutMs=interactionTimeoutMs, busyWaitMs=busyWaitMs).raise_on_error()
return await future

def _parseAttributePathTuple(self, pathTuple: typing.Union[
Expand Down
20 changes: 14 additions & 6 deletions src/controller/python/chip/clusters/Attribute.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
import chip.interaction_model
import chip.tlv
import construct
from chip.native import PyChipError
from chip.native import ErrorSDKPart, PyChipError
from rich.pretty import pprint

from .ClusterObjects import Cluster, ClusterAttributeDescriptor, ClusterEvent
Expand Down Expand Up @@ -810,7 +810,11 @@ def _handleDone(self):
# move on, possibly invalidating the provided _event_loop.
#
if self._resultError is not None:
self._future.set_exception(self._resultError.to_exception())
if self._resultError.sdk_part is ErrorSDKPart.IM_GLOBAL_STATUS:
im_status = chip.interaction_model.Status(self._resultError.sdk_code)
self._future.set_exception(chip.interaction_model.InteractionModelError(im_status))
else:
self._future.set_exception(self._resultError.to_exception())
else:
self._future.set_result(self._resultData)

Expand Down Expand Up @@ -910,14 +914,13 @@ def _OnWriteDoneCallback(closure):
closure.handleDone()


def WriteAttributes(future: Future, eventLoop, device, attributes: List[AttributeWriteRequest], timedRequestTimeoutMs: int = None, interactionTimeoutMs: int = None) -> PyChipError:
def WriteAttributes(future: Future, eventLoop, device, attributes: List[AttributeWriteRequest], timedRequestTimeoutMs: int = None, interactionTimeoutMs: int = None, busyWaitMs: int = None) -> PyChipError:
handle = chip.native.GetLibraryHandle()

writeargs = []
for attr in attributes:
if attr.Attribute.must_use_timed_write and timedRequestTimeoutMs is None or timedRequestTimeoutMs == 0:
raise ValueError(
f"Attribute {attr.__class__} must use timed write, please specify a valid timedRequestTimeoutMs value.")
raise chip.interaction_model.InteractionModelError(chip.interaction_model.Status.NeedsTimedInteraction)
path = chip.interaction_model.AttributePathIBstruct.parse(
b'\x00' * chip.interaction_model.AttributePathIBstruct.sizeof())
path.EndpointId = attr.EndpointId
Expand All @@ -935,7 +938,12 @@ def WriteAttributes(future: Future, eventLoop, device, attributes: List[Attribut
ctypes.pythonapi.Py_IncRef(ctypes.py_object(transaction))
res = builtins.chipStack.Call(
lambda: handle.pychip_WriteClient_WriteAttributes(
ctypes.py_object(transaction), device, ctypes.c_uint16(0 if timedRequestTimeoutMs is None else timedRequestTimeoutMs), ctypes.c_uint16(0 if interactionTimeoutMs is None else interactionTimeoutMs), ctypes.c_size_t(len(attributes)), *writeargs))
ctypes.py_object(transaction), device,
ctypes.c_uint16(0 if timedRequestTimeoutMs is None else timedRequestTimeoutMs),
ctypes.c_uint16(0 if interactionTimeoutMs is None else interactionTimeoutMs),
ctypes.c_uint16(0 if busyWaitMs is None else busyWaitMs),
ctypes.c_size_t(len(attributes)), *writeargs)
)
if not res.is_success:
ctypes.pythonapi.Py_DecRef(ctypes.py_object(transaction))
return res
Expand Down
14 changes: 9 additions & 5 deletions src/controller/python/chip/clusters/Command.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ def _OnCommandSenderDoneCallback(closure):
ctypes.pythonapi.Py_DecRef(ctypes.py_object(closure))


def SendCommand(future: Future, eventLoop, responseType: Type, device, commandPath: CommandPath, payload: ClusterCommand, timedRequestTimeoutMs: int = None, interactionTimeoutMs: int = None) -> PyChipError:
def SendCommand(future: Future, eventLoop, responseType: Type, device, commandPath: CommandPath, payload: ClusterCommand, timedRequestTimeoutMs: int = None, interactionTimeoutMs: int = None, busyWaitMs: int = None) -> PyChipError:
''' Send a cluster-object encapsulated command to a device and does the following:
- On receipt of a successful data response, returns the cluster-object equivalent through the provided future.
- None (on a successful response containing no data)
Expand All @@ -158,17 +158,21 @@ def SendCommand(future: Future, eventLoop, responseType: Type, device, commandPa
if (responseType is not None) and (not issubclass(responseType, ClusterCommand)):
raise ValueError("responseType must be a ClusterCommand or None")
if payload.must_use_timed_invoke and timedRequestTimeoutMs is None or timedRequestTimeoutMs == 0:
raise ValueError(
f"Command {payload.__class__} must use timed invoke, please specify a valid timedRequestTimeoutMs value")
raise chip.interaction_model.InteractionModelError(chip.interaction_model.Status.NeedsTimedInteraction)

handle = chip.native.GetLibraryHandle()
transaction = AsyncCommandTransaction(future, eventLoop, responseType)

payloadTLV = payload.ToTLV()
ctypes.pythonapi.Py_IncRef(ctypes.py_object(transaction))
return builtins.chipStack.Call(
lambda: handle.pychip_CommandSender_SendCommand(ctypes.py_object(
transaction), device, c_uint16(0 if timedRequestTimeoutMs is None else timedRequestTimeoutMs), commandPath.EndpointId, commandPath.ClusterId, commandPath.CommandId, payloadTLV, len(payloadTLV), ctypes.c_uint16(0 if interactionTimeoutMs is None else interactionTimeoutMs)))
lambda: handle.pychip_CommandSender_SendCommand(
ctypes.py_object(transaction), device,
c_uint16(0 if timedRequestTimeoutMs is None else timedRequestTimeoutMs), commandPath.EndpointId,
commandPath.ClusterId, commandPath.CommandId, payloadTLV, len(payloadTLV),
ctypes.c_uint16(0 if interactionTimeoutMs is None else interactionTimeoutMs),
ctypes.c_uint16(0 if busyWaitMs is None else busyWaitMs),
))


def Init():
Expand Down
14 changes: 12 additions & 2 deletions src/controller/python/chip/clusters/attribute.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ struct __attribute__((packed)) PyReadAttributeParams

// Encodes n attribute write requests, follows 3 * n arguments, in the (AttributeWritePath*=void *, uint8_t*, size_t) order.
PyChipError pychip_WriteClient_WriteAttributes(void * appContext, DeviceProxy * device, uint16_t timedWriteTimeoutMs,
uint16_t interactionTimeoutMs, size_t n, ...);
uint16_t interactionTimeoutMs, uint16_t busyWaitMs, size_t n, ...);
PyChipError pychip_ReadClient_ReadAttributes(void * appContext, ReadClient ** pReadClient, ReadClientCallback ** pCallback,
DeviceProxy * device, uint8_t * readParamsBuf, size_t n, size_t total, ...);
}
Expand Down Expand Up @@ -323,7 +323,7 @@ void pychip_ReadClient_InitCallbacks(OnReadAttributeDataCallback onReadAttribute
}

PyChipError pychip_WriteClient_WriteAttributes(void * appContext, DeviceProxy * device, uint16_t timedWriteTimeoutMs,
uint16_t interactionTimeoutMs, size_t n, ...)
uint16_t interactionTimeoutMs, uint16_t busyWaitMs, size_t n, ...)
{
CHIP_ERROR err = CHIP_NO_ERROR;

Expand Down Expand Up @@ -370,6 +370,16 @@ PyChipError pychip_WriteClient_WriteAttributes(void * appContext, DeviceProxy *
client.release();
callback.release();

if (busyWaitMs) {
auto durationInMs = chip::System::Clock::Milliseconds32(busyWaitMs);
auto & clock = chip::System::SystemClock();
auto start = clock.GetMonotonicTimestamp();
while (clock.GetMonotonicTimestamp() - start < durationInMs)
{
// nothing to do.
tehampson marked this conversation as resolved.
Show resolved Hide resolved
};
}

exit:
va_end(args);
return ToPyChipError(err);
Expand Down
16 changes: 14 additions & 2 deletions src/controller/python/chip/clusters/command.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ using PyObject = void *;
extern "C" {
PyChipError pychip_CommandSender_SendCommand(void * appContext, DeviceProxy * device, uint16_t timedRequestTimeoutMs,
chip::EndpointId endpointId, chip::ClusterId clusterId, chip::CommandId commandId,
const uint8_t * payload, size_t length, uint16_t interactionTimeoutMs);
const uint8_t * payload, size_t length, uint16_t interactionTimeoutMs,
uint16_t busyWaitMs);
}

namespace chip {
Expand Down Expand Up @@ -126,7 +127,8 @@ void pychip_CommandSender_InitCallbacks(OnCommandSenderResponseCallback onComman

PyChipError pychip_CommandSender_SendCommand(void * appContext, DeviceProxy * device, uint16_t timedRequestTimeoutMs,
chip::EndpointId endpointId, chip::ClusterId clusterId, chip::CommandId commandId,
const uint8_t * payload, size_t length, uint16_t interactionTimeoutMs)
const uint8_t * payload, size_t length, uint16_t interactionTimeoutMs,
uint16_t busyWaitMs)
{
CHIP_ERROR err = CHIP_NO_ERROR;

Expand Down Expand Up @@ -161,6 +163,16 @@ PyChipError pychip_CommandSender_SendCommand(void * appContext, DeviceProxy * de
sender.release();
callback.release();

if (busyWaitMs) {
auto durationInMs = chip::System::Clock::Milliseconds32(busyWaitMs);
auto & clock = chip::System::SystemClock();
auto start = clock.GetMonotonicTimestamp();
while (clock.GetMonotonicTimestamp() - start < durationInMs)
tehampson marked this conversation as resolved.
Show resolved Hide resolved
{
// nothing to do.
};
}

exit:
return ToPyChipError(err);
}
Expand Down
15 changes: 10 additions & 5 deletions src/controller/python/chip/yaml/runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ def __init__(self, test_step, cluster: str, context: _ExecutionContext):
UnexpectedParsingError: Raised if there is an unexpected parsing error.
'''
super().__init__(test_step.label, test_step.identity)
self._busy_wait_ms = test_step.busy_wait_ms
self._command_name = stringcase.pascalcase(test_step.command)
self._cluster = cluster
self._interation_timeout_ms = test_step.timed_interaction_timeout_ms
Expand Down Expand Up @@ -142,7 +143,8 @@ def run_action(self, dev_ctrl: ChipDeviceCtrl) -> _ActionResult:
try:
resp = asyncio.run(dev_ctrl.SendCommand(
self._node_id, self._endpoint, self._request_object,
timedRequestTimeoutMs=self._interation_timeout_ms))
timedRequestTimeoutMs=self._interation_timeout_ms,
busyWaitMs=self._busy_wait_ms))
except chip.interaction_model.InteractionModelError as error:
return _ActionResult(status=_ActionStatus.ERROR, response=error)

Expand Down Expand Up @@ -357,8 +359,10 @@ def __init__(self, test_step, cluster: str, context: _ExecutionContext):
'''
super().__init__(test_step.label, test_step.identity)
self._attribute_name = stringcase.pascalcase(test_step.attribute)
self._busy_wait_ms = test_step.busy_wait_ms
self._cluster = cluster
self._endpoint = test_step.endpoint
self._interation_timeout_ms = test_step.timed_interaction_timeout_ms
self._node_id = test_step.node_id
self._request_object = None

Expand Down Expand Up @@ -389,10 +393,11 @@ def __init__(self, test_step, cluster: str, context: _ExecutionContext):
def run_action(self, dev_ctrl: ChipDeviceCtrl) -> _ActionResult:
try:
resp = asyncio.run(
dev_ctrl.WriteAttribute(self._node_id, [(self._endpoint, self._request_object)]))
except chip.interaction_model.InteractionModelError:
# TODO Should we be doing the same thing as InvokeAction on InteractionModelError?
raise
dev_ctrl.WriteAttribute(self._node_id, [(self._endpoint, self._request_object)],
timedRequestTimeoutMs=self._interation_timeout_ms,
busyWaitMs=self._busy_wait_ms))
except chip.interaction_model.InteractionModelError as error:
return _ActionResult(status=_ActionStatus.ERROR, response=error)
if len(resp) == 1 and isinstance(resp[0], AttributeStatus):
if resp[0].Status == chip.interaction_model.Status.Success:
return _ActionResult(status=_ActionStatus.SUCCESS, response=None)
Expand Down