Skip to content

Commit

Permalink
Allow chip-repl to know how many InvokeResponseMessages were recieved
Browse files Browse the repository at this point in the history
  • Loading branch information
tehampson committed Jan 30, 2024
1 parent 30a7636 commit b020ad7
Show file tree
Hide file tree
Showing 10 changed files with 70 additions and 11 deletions.
3 changes: 3 additions & 0 deletions src/app/CommandSender.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,9 @@ CHIP_ERROR CommandSender::OnMessageReceived(Messaging::ExchangeContext * apExcha
{
err = ProcessInvokeResponse(std::move(aPayload), moreChunkedMessages);
SuccessOrExit(err);
#if CONFIG_BUILD_FOR_HOST_UNIT_TEST
mInvokeResponseMessageCount++;
#endif // CONFIG_BUILD_FOR_HOST_UNIT_TEST
if (moreChunkedMessages)
{
StatusResponse::Send(Status::Success, apExchangeContext, /*aExpectResponse = */ true);
Expand Down
5 changes: 5 additions & 0 deletions src/app/CommandSender.h
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,7 @@ class CommandSender final : public Messaging::ExchangeDelegate
CHIP_ERROR TestOnlyCommandSenderTimedRequestFlagWithNoTimedInvoke(const SessionHandle & session,
Optional<System::Clock::Timeout> timeout = NullOptional);

size_t GetInvokeResponseMessageCount() { return mInvokeResponseMessageCount; }
#endif // CONFIG_BUILD_FOR_HOST_UNIT_TEST

private:
Expand Down Expand Up @@ -510,6 +511,10 @@ class CommandSender final : public Messaging::ExchangeDelegate
uint16_t mFinishedCommandCount = 0;
uint16_t mRemoteMaxPathsPerInvoke = 1;

#if CONFIG_BUILD_FOR_HOST_UNIT_TEST
size_t mInvokeResponseMessageCount = 0;
#endif // CONFIG_BUILD_FOR_HOST_UNIT_TEST

State mState = State::Idle;
bool mSuppressResponse = false;
bool mTimedRequest = false;
Expand Down
3 changes: 3 additions & 0 deletions src/controller/python/chip/ChipDeviceCtrl.py
Original file line number Diff line number Diff line change
Expand Up @@ -864,6 +864,9 @@ async def TestOnlySendBatchCommands(self, nodeid: int, commands: typing.List[Clu
remoteMaxPathsPerInvoke: Overrides the number of batch commands we think can be sent to remote node.
suppressTimedRequestMessage: When set to true, we suppress sending Timed Request Message.
commandRefsOverride: List of commandRefs to use for each command with the same index in `commands`.
Returns:
- TestOnlyBatchCommandResponse
'''
self.CheckIsActive()

Expand Down
31 changes: 27 additions & 4 deletions src/controller/python/chip/clusters/Command.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@

import chip.exceptions
import chip.interaction_model
from chip.interaction_model import PyInvokeRequestData, TestOnlyPyBatchCommandsOverrides
from chip.interaction_model import PyInvokeRequestData, TestOnlyPyBatchCommandsOverrides, TestOnlyPyOnDoneInfo
from chip.native import PyChipError

from .ClusterObjects import ClusterCommand
Expand Down Expand Up @@ -55,6 +55,11 @@ class Status:
IMStatus: int
ClusterStatus: int

@dataclass
class TestOnlyBatchCommandResponse:
Responses: object
ResponseMessageCount: int


def FindCommandClusterObject(isClientSideCommand: bool, path: CommandPath):
''' Locates the right generated cluster object given a set of parameters.
Expand Down Expand Up @@ -215,12 +220,27 @@ def handleDone(self):
)


class TestOnlyAsyncBatchCommandsTransaction(AsyncBatchCommandsTransaction):
def __init__(self, future: Future, eventLoop, expectTypes: List[Type]):
self._responseMessageCount = 0
super().__init__(future, eventLoop, expectTypes)

def _handleDone(self):
# Future might already be set with exception from `handleError`
if not self._future.done():
self._future.set_result(TestOnlyBatchCommandResponse(self._responses, self._responseMessageCount))
ctypes.pythonapi.Py_DecRef(ctypes.py_object(self))

def testOnlyDoneInfo(self, testOnlyDoneInfo: TestOnlyPyOnDoneInfo):
self._responseMessageCount = testOnlyDoneInfo.responseMessageCount


_OnCommandSenderResponseCallbackFunct = CFUNCTYPE(
None, py_object, c_uint16, c_uint32, c_uint32, c_size_t, c_uint16, c_uint8, c_void_p, c_uint32)
_OnCommandSenderErrorCallbackFunct = CFUNCTYPE(
None, py_object, c_uint16, c_uint8, PyChipError)
_OnCommandSenderDoneCallbackFunct = CFUNCTYPE(
None, py_object)
None, py_object, TestOnlyPyOnDoneInfo)


@_OnCommandSenderResponseCallbackFunct
Expand All @@ -237,7 +257,10 @@ def _OnCommandSenderErrorCallback(closure, imStatus: int, clusterStatus: int, ch


@_OnCommandSenderDoneCallbackFunct
def _OnCommandSenderDoneCallback(closure):
def _OnCommandSenderDoneCallback(closure, testOnlyDoneInfo: TestOnlyPyOnDoneInfo):
testOnlyDoneInfoFunction = getattr(closure, "testOnlyDoneInfo", None)
if testOnlyDoneInfoFunction:
closure.testOnlyDoneInfo(testOnlyDoneInfo)
closure.handleDone()


Expand Down Expand Up @@ -392,7 +415,7 @@ def TestOnlySendBatchCommands(future: Future, eventLoop, device, commands: List[
pyBatchCommandsData = _BuildPyInvokeRequestData(commands, timedRequestTimeoutMs,
responseTypes, suppressTimedRequestMessage=suppressTimedRequestMessage)

transaction = AsyncBatchCommandsTransaction(future, eventLoop, responseTypes)
transaction = TestOnlyAsyncBatchCommandsTransaction(future, eventLoop, responseTypes)
ctypes.pythonapi.Py_IncRef(ctypes.py_object(transaction))

testOnlyOverrides = TestOnlyPyBatchCommandsOverrides()
Expand Down
7 changes: 5 additions & 2 deletions src/controller/python/chip/clusters/command.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ using OnCommandSenderResponseCallback = void (*)(PyObject appContext, chip::Endp
using OnCommandSenderErrorCallback = void (*)(PyObject appContext,
std::underlying_type_t<Protocols::InteractionModel::Status> status,
chip::ClusterStatus clusterStatus, PyChipError chiperror);
using OnCommandSenderDoneCallback = void (*)(PyObject appContext);
using OnCommandSenderDoneCallback = void (*)(PyObject appContext, python::TestOnlyPyOnDoneInfo testOnlyDoneInfo);

OnCommandSenderResponseCallback gOnCommandSenderResponseCallback = nullptr;
OnCommandSenderErrorCallback gOnCommandSenderErrorCallback = nullptr;
Expand Down Expand Up @@ -148,7 +148,10 @@ class CommandSenderCallback : public CommandSender::ExtendableCallback

void OnDone(CommandSender * apCommandSender) override
{
gOnCommandSenderDoneCallback(mAppContext);

python::TestOnlyPyOnDoneInfo testOnlyOnDoneInfo;
testOnlyOnDoneInfo.responseMessageCount = apCommandSender->GetInvokeResponseMessageCount();
gOnCommandSenderDoneCallback(mAppContext, testOnlyOnDoneInfo);
delete apCommandSender;
delete this;
};
Expand Down
5 changes: 5 additions & 0 deletions src/controller/python/chip/interaction_model/Delegate.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,11 @@ struct TestOnlyPyBatchCommandsOverrides
size_t overrideCommandRefsListLength;
};

struct TestOnlyPyOnDoneInfo
{
size_t responseMessageCount;
};

} // namespace python

namespace Controller {
Expand Down
4 changes: 2 additions & 2 deletions src/controller/python/chip/interaction_model/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,11 @@

from .delegate import (AttributePath, AttributePathIBstruct, DataVersionFilterIBstruct, EventPath, EventPathIBstruct,
PyInvokeRequestData, PyWriteAttributeData, SessionParameters, SessionParametersStruct,
TestOnlyPyBatchCommandsOverrides)
TestOnlyPyBatchCommandsOverrides, TestOnlyPyOnDoneInfo)

__all__ = ["AttributePath", "AttributePathIBstruct", "DataVersionFilterIBstruct",
"EventPath", "EventPathIBstruct", "InteractionModelError", "PyInvokeRequestData",
"PyWriteAttributeData", "SessionParameters", "SessionParametersStruct", "Status", "TestOnlyPyBatchCommandsOverrides"]
"PyWriteAttributeData", "SessionParameters", "SessionParametersStruct", "Status", "TestOnlyPyBatchCommandsOverrides", "TestOnlyPyOnDoneInfo"]


# defined src/controller/python/chip/interaction_model/Delegate.h
Expand Down
15 changes: 15 additions & 0 deletions src/controller/python/chip/interaction_model/delegate.py
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,21 @@ class TestOnlyPyBatchCommandsOverrides(ctypes.Structure):
('overrideCommandRefsList', POINTER(ctypes.c_uint16)), ('overrideCommandRefsListLength', ctypes.c_size_t)]


class TestOnlyPyOnDoneInfo(ctypes.Structure):
''' TestOnly struct for overriding aspects of batch command to send invalid commands.
We are using the following struct for passing the information of TestOnlyPyBatchCommandsOverrides between Python and C++:
```c
struct TestOnlyPyOnDoneInfo
{
size_t responseMessageCount;
};
```
'''
_fields_ = [('responseMessageCount', ctypes.c_size_t)]


# typedef void (*PythonInteractionModelDelegate_OnCommandResponseStatusCodeReceivedFunct)(uint64_t commandSenderPtr,
# void * commandStatusBuf);
# typedef void (*PythonInteractionModelDelegate_OnCommandResponseProtocolErrorFunct)(uint64_t commandSenderPtr,
Expand Down
4 changes: 2 additions & 2 deletions src/python_testing/TC_IDM_1_4.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ async def steps_3_to_9(self, dummy_value):
invoke_request_2 = Clusters.Command.InvokeRequestInfo(endpoint, command)
commandRefsOverride = [1, 1]
try:
result = await dev_ctrl.TestOnlySendBatchCommands(dut_node_id, [invoke_request_1, invoke_request_2], commandRefsOverride=commandRefsOverride)
await dev_ctrl.TestOnlySendBatchCommands(dut_node_id, [invoke_request_1, invoke_request_2], commandRefsOverride=commandRefsOverride)
asserts.fail("Unexpected success return after sending two unique commands with identical CommandRef in the InvokeRequest")
except InteractionModelError as e:
asserts.assert_equal(e.status, Status.InvalidAction,
Expand Down Expand Up @@ -216,7 +216,7 @@ async def steps_3_to_9(self, dummy_value):
# receiving a path-specific response to the same command, with the TimedRequestMessage sent before
# the InvokeRequestMessage.
try:
result = await dev_ctrl.TestOnlySendBatchCommands(dut_node_id, [invoke_request_1, invoke_request_2], suppressTimedRequestMessage=True)
await dev_ctrl.TestOnlySendBatchCommands(dut_node_id, [invoke_request_1, invoke_request_2], suppressTimedRequestMessage=True)
asserts.fail("Unexpected success call to sending Batch command when non-path specific error expected")
except InteractionModelError as e:
asserts.assert_equal(e.status, Status.TimedRequestMismatch,
Expand Down
4 changes: 3 additions & 1 deletion src/python_testing/TestBatchInvoke.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,10 +88,12 @@ async def test_batch_invoke(self):
sleepBeforeResponseTimeMs=0, sizeOfResponseBuffer=response_size, fillCharacter=ord(request_2_fill_character))
invoke_request_2 = Clusters.Command.InvokeRequestInfo(endpoint, command)
try:
result = await dev_ctrl.SendBatchCommands(dut_node_id, [invoke_request_1, invoke_request_2])
testOnlyResponse = await dev_ctrl.TestOnlySendBatchCommands(dut_node_id, [invoke_request_1, invoke_request_2])
except InteractionModelError:
asserts.fail("DUT failed to successfully responded to a InvokeRequest action with two valid commands")

asserts.assert_greater(testOnlyResponse.ResponseMessageCount, 1, "Unexpected, DUT sent response back in single InvokeResponseMessage")
result = testOnlyResponse.Responses
asserts.assert_true(type_matches(result, list), "Unexpected return from SendBatchCommands")
asserts.assert_equal(len(result), 2, "Unexpected number of InvokeResponses sent back from DUT")
asserts.assert_true(type_matches(
Expand Down

0 comments on commit b020ad7

Please sign in to comment.