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

TC-IDM-1.2 #27024

Merged
merged 11 commits into from
Jul 12, 2023
1 change: 1 addition & 0 deletions .github/workflows/tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -447,6 +447,7 @@ jobs:
scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --app out/linux-x64-all-clusters-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-all-clusters-app --factoryreset --app-args "--discriminator 1234 --KVS kvs1 --trace_decode 1" --script "src/python_testing/TC_CGEN_2_4.py" --script-args "--storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021"'
scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --app out/linux-x64-all-clusters-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-all-clusters-app --factoryreset --app-args "--discriminator 1234 --KVS kvs1 --trace_decode 1" --script "src/python_testing/TC_DA_1_2.py" --script-args "--storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --PICS src/app/tests/suites/certification/ci-pics-values"'
scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --app out/linux-x64-all-clusters-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-all-clusters-app --factoryreset --app-args "--discriminator 1234 --KVS kvs1 --trace_decode 1" --script "src/python_testing/TC_DA_1_5.py" --script-args "--storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --PICS src/app/tests/suites/certification/ci-pics-values"'
scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --app out/linux-x64-all-clusters-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-all-clusters-app --factoryreset --app-args "--discriminator 1234 --KVS kvs1 --trace_decode 1" --script "src/python_testing/TC_IDM_1_2.py" --script-args "--storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021"'
scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --script "src/python_testing/TestMatterTestingSupport.py"'
- name: Uploading core files
uses: actions/upload-artifact@v3
Expand Down
2 changes: 2 additions & 0 deletions config/python/CHIPProjectConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,4 +59,6 @@
#define CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY 1
#define CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE 1

#define CONFIG_BUILD_FOR_HOST_UNIT_TEST 1

#endif /* CHIPPROJECTCONFIG_H */
41 changes: 28 additions & 13 deletions src/app/CommandSender.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,10 @@
namespace chip {
namespace app {

CommandSender::CommandSender(Callback * apCallback, Messaging::ExchangeManager * apExchangeMgr, bool aIsTimedRequest) :
mExchangeCtx(*this), mpCallback(apCallback), mpExchangeMgr(apExchangeMgr), mSuppressResponse(false),
mTimedRequest(aIsTimedRequest)
CommandSender::CommandSender(Callback * apCallback, Messaging::ExchangeManager * apExchangeMgr, bool aIsTimedRequest,
bool aSuppressResponse) :
mExchangeCtx(*this),
mpCallback(apCallback), mpExchangeMgr(apExchangeMgr), mSuppressResponse(aSuppressResponse), mTimedRequest(aIsTimedRequest)
{}

CHIP_ERROR CommandSender::AllocateBuffer()
Expand All @@ -61,7 +62,7 @@ CHIP_ERROR CommandSender::AllocateBuffer()
return CHIP_NO_ERROR;
}

CHIP_ERROR CommandSender::SendCommandRequest(const SessionHandle & session, Optional<System::Clock::Timeout> timeout)
CHIP_ERROR CommandSender::SendCommandRequestInternal(const SessionHandle & session, Optional<System::Clock::Timeout> timeout)
{
VerifyOrReturnError(mState == State::AddedCommand, CHIP_ERROR_INCORRECT_STATE);
cecille marked this conversation as resolved.
Show resolved Hide resolved

Expand All @@ -76,15 +77,6 @@ CHIP_ERROR CommandSender::SendCommandRequest(const SessionHandle & session, Opti

mExchangeCtx->SetResponseTimeout(timeout.ValueOr(session->ComputeRoundTripTimeout(app::kExpectedIMProcessingTime)));

if (mTimedRequest != mTimedInvokeTimeoutMs.HasValue())
{
ChipLogError(
DataManagement,
"Inconsistent timed request state in CommandSender: mTimedRequest (%d) != mTimedInvokeTimeoutMs.HasValue() (%d)",
mTimedRequest, mTimedInvokeTimeoutMs.HasValue());
return CHIP_ERROR_INCORRECT_STATE;
}

if (mTimedInvokeTimeoutMs.HasValue())
{
ReturnErrorOnFailure(TimedRequest::Send(mExchangeCtx.Get(), mTimedInvokeTimeoutMs.Value()));
Expand All @@ -95,6 +87,29 @@ CHIP_ERROR CommandSender::SendCommandRequest(const SessionHandle & session, Opti
return SendInvokeRequest();
}

#if CONFIG_BUILD_FOR_HOST_UNIT_TEST
CHIP_ERROR CommandSender::TestOnlyCommandSenderTimedRequestFlagWithNoTimedInvoke(const SessionHandle & session,
Optional<System::Clock::Timeout> timeout)
{
VerifyOrReturnError(mTimedRequest, CHIP_ERROR_INCORRECT_STATE);
return SendCommandRequestInternal(session, timeout);
}
#endif

CHIP_ERROR CommandSender::SendCommandRequest(const SessionHandle & session, Optional<System::Clock::Timeout> timeout)
{

if (mTimedRequest != mTimedInvokeTimeoutMs.HasValue())
{
ChipLogError(
DataManagement,
"Inconsistent timed request state in CommandSender: mTimedRequest (%d) != mTimedInvokeTimeoutMs.HasValue() (%d)",
mTimedRequest, mTimedInvokeTimeoutMs.HasValue());
return CHIP_ERROR_INCORRECT_STATE;
}
return SendCommandRequestInternal(session, timeout);
}

CHIP_ERROR CommandSender::SendGroupCommandRequest(const SessionHandle & session)
{
VerifyOrReturnError(mState == State::AddedCommand, CHIP_ERROR_INCORRECT_STATE);
Expand Down
16 changes: 13 additions & 3 deletions src/app/CommandSender.h
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,8 @@ class CommandSender final : public Messaging::ExchangeDelegate
* If used in a groups setting, callbacks do not need to be passed.
* If callbacks are passed the only one that will be called in a group sesttings is the onDone
*/
CommandSender(Callback * apCallback, Messaging::ExchangeManager * apExchangeMgr, bool aIsTimedRequest = false);
CommandSender(Callback * apCallback, Messaging::ExchangeManager * apExchangeMgr, bool aIsTimedRequest = false,
bool aSuppressResponse = false);
CHIP_ERROR PrepareCommand(const CommandPathParams & aCommandPathParams, bool aStartDataStruct = true);
CHIP_ERROR FinishCommand(bool aEndDataStruct = true);
TLV::TLVWriter * GetCommandDataIBTLVWriter();
Expand Down Expand Up @@ -164,11 +165,18 @@ class CommandSender final : public Messaging::ExchangeDelegate
*/
template <typename CommandDataT>
CHIP_ERROR AddRequestDataNoTimedCheck(const CommandPathParams & aCommandPath, const CommandDataT & aData,
const Optional<uint16_t> & aTimedInvokeTimeoutMs, bool aSuppressResponse = false)
const Optional<uint16_t> & aTimedInvokeTimeoutMs)
{
mSuppressResponse = aSuppressResponse;
return AddRequestDataInternal(aCommandPath, aData, aTimedInvokeTimeoutMs);
}

/**
* Version of SendCommandRequest that sets the TimedRequest flag but does not send the TimedInvoke
* action. For use in tests only.
*/
CHIP_ERROR TestOnlyCommandSenderTimedRequestFlagWithNoTimedInvoke(const SessionHandle & session,
Optional<System::Clock::Timeout> timeout = NullOptional);

#endif // CONFIG_BUILD_FOR_HOST_UNIT_TEST

private:
Expand Down Expand Up @@ -265,6 +273,8 @@ class CommandSender final : public Messaging::ExchangeDelegate

CHIP_ERROR Finalize(System::PacketBufferHandle & commandPacket);

CHIP_ERROR SendCommandRequestInternal(const SessionHandle & session, Optional<System::Clock::Timeout> timeout);

Messaging::ExchangeHolder mExchangeCtx;
Callback * mpCallback = nullptr;
Messaging::ExchangeManager * mpExchangeMgr = nullptr;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -234,12 +234,11 @@ class InteractionModelCommands

chip::app::CommandPathParams commandPath = { endpointId, clusterId, commandId,
(chip::app::CommandPathFlags::kEndpointIdValid) };
auto commandSender = std::make_unique<chip::app::CommandSender>(mCallback, device->GetExchangeManager(),
mTimedInteractionTimeoutMs.HasValue());
auto commandSender = std::make_unique<chip::app::CommandSender>(
mCallback, device->GetExchangeManager(), mTimedInteractionTimeoutMs.HasValue(), mSuppressResponse.ValueOr(false));
VerifyOrReturnError(commandSender != nullptr, CHIP_ERROR_NO_MEMORY);

ReturnErrorOnFailure(commandSender->AddRequestDataNoTimedCheck(commandPath, value, mTimedInteractionTimeoutMs,
mSuppressResponse.ValueOr(false)));
ReturnErrorOnFailure(commandSender->AddRequestDataNoTimedCheck(commandPath, value, mTimedInteractionTimeoutMs));
ReturnErrorOnFailure(commandSender->SendCommandRequest(device->GetSecureSession().Value()));
mCommandSender.push_back(std::move(commandSender));

Expand Down
8 changes: 6 additions & 2 deletions src/controller/python/ChipDeviceController-ScriptBinding.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ PyChipError pychip_DeviceController_SetThreadOperationalDataset(const char * thr
PyChipError pychip_DeviceController_SetWiFiCredentials(const char * ssid, const char * credentials);
PyChipError pychip_DeviceController_CloseSession(chip::Controller::DeviceCommissioner * devCtrl, chip::NodeId nodeid);
PyChipError pychip_DeviceController_EstablishPASESessionIP(chip::Controller::DeviceCommissioner * devCtrl, const char * peerAddrStr,
uint32_t setupPINCode, chip::NodeId nodeid);
uint32_t setupPINCode, chip::NodeId nodeid, uint16_t port);
PyChipError pychip_DeviceController_EstablishPASESessionBLE(chip::Controller::DeviceCommissioner * devCtrl, uint32_t setupPINCode,
uint16_t discriminator, chip::NodeId nodeid);
PyChipError pychip_DeviceController_Commission(chip::Controller::DeviceCommissioner * devCtrl, chip::NodeId nodeid);
Expand Down Expand Up @@ -512,13 +512,17 @@ PyChipError pychip_DeviceController_CloseSession(chip::Controller::DeviceCommiss
}

PyChipError pychip_DeviceController_EstablishPASESessionIP(chip::Controller::DeviceCommissioner * devCtrl, const char * peerAddrStr,
uint32_t setupPINCode, chip::NodeId nodeid)
uint32_t setupPINCode, chip::NodeId nodeid, uint16_t port)
{
chip::Inet::IPAddress peerAddr;
chip::Transport::PeerAddress addr;
RendezvousParameters params = chip::RendezvousParameters().SetSetupPINCode(setupPINCode);
VerifyOrReturnError(chip::Inet::IPAddress::FromString(peerAddrStr, peerAddr), ToPyChipError(CHIP_ERROR_INVALID_ARGUMENT));
addr.SetTransportType(chip::Transport::Type::kUdp).SetIPAddress(peerAddr);
if (port != 0)
{
addr.SetPort(port);
}
params.SetPeerAddress(addr).SetDiscriminator(0);
sPairingDelegate.SetExpectingPairingComplete(true);
return ToPyChipError(devCtrl->EstablishPASEConnection(nodeid, params));
Expand Down
31 changes: 26 additions & 5 deletions src/controller/python/chip/ChipDeviceCtrl.py
Original file line number Diff line number Diff line change
Expand Up @@ -473,13 +473,13 @@ def EstablishPASESessionBLE(self, setupPinCode: int, discriminator: int, nodeid:
self.devCtrl, setupPinCode, discriminator, nodeid)
)

def EstablishPASESessionIP(self, ipaddr: str, setupPinCode: int, nodeid: int):
def EstablishPASESessionIP(self, ipaddr: str, setupPinCode: int, nodeid: int, port: int = 0):
self.CheckIsActive()

self.state = DCState.RENDEZVOUS_ONGOING
return self._ChipStack.CallAsync(
lambda: self._dmLib.pychip_DeviceController_EstablishPASESessionIP(
self.devCtrl, ipaddr.encode("utf-8"), setupPinCode, nodeid)
self.devCtrl, ipaddr.encode("utf-8"), setupPinCode, nodeid, port)
)

def GetTestCommissionerUsed(self):
Expand Down Expand Up @@ -779,9 +779,30 @@ def ComputeRoundTripTimeout(self, nodeid, upperLayerProcessingTimeoutMs: int = 0
device.deviceProxy, upperLayerProcessingTimeoutMs))
return res

async def TestOnlySendCommandTimedRequestFlagWithNoTimedInvoke(self, nodeid: int, endpoint: int,
payload: ClusterObjects.ClusterCommand, responseType=None):
'''

Please see SendCommand for description.
'''
self.CheckIsActive()

eventLoop = asyncio.get_running_loop()
future = eventLoop.create_future()

device = self.GetConnectedDeviceSync(nodeid, timeoutMs=None)
ClusterCommand.TestOnlySendCommandTimedRequestFlagWithNoTimedInvoke(
future, eventLoop, responseType, device.deviceProxy, ClusterCommand.CommandPath(
EndpointId=endpoint,
ClusterId=payload.cluster_id,
CommandId=payload.command_id,
), payload).raise_on_error()
return await future

async def SendCommand(self, nodeid: int, endpoint: int, payload: ClusterObjects.ClusterCommand, responseType=None,
timedRequestTimeoutMs: typing.Union[None, int] = None,
interactionTimeoutMs: typing.Union[None, int] = None, busyWaitMs: typing.Union[None, int] = None):
interactionTimeoutMs: typing.Union[None, int] = None, busyWaitMs: typing.Union[None, int] = None,
suppressResponse: typing.Union[None, bool] = 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,
Expand All @@ -803,7 +824,7 @@ async def SendCommand(self, nodeid: int, endpoint: int, payload: ClusterObjects.
ClusterId=payload.cluster_id,
CommandId=payload.command_id,
), payload, timedRequestTimeoutMs=timedRequestTimeoutMs,
interactionTimeoutMs=interactionTimeoutMs, busyWaitMs=busyWaitMs).raise_on_error()
interactionTimeoutMs=interactionTimeoutMs, busyWaitMs=busyWaitMs, suppressResponse=suppressResponse).raise_on_error()
return await future

def SendGroupCommand(self, groupid: int, payload: ClusterObjects.ClusterCommand, busyWaitMs: typing.Union[None, int] = None):
Expand Down Expand Up @@ -1335,7 +1356,7 @@ def _InitLib(self):
self._dmLib.pychip_DeviceController_DiscoverCommissionableNodesCommissioningEnabled.restype = PyChipError

self._dmLib.pychip_DeviceController_EstablishPASESessionIP.argtypes = [
c_void_p, c_char_p, c_uint32, c_uint64]
c_void_p, c_char_p, c_uint32, c_uint64, c_uint16]
self._dmLib.pychip_DeviceController_EstablishPASESessionIP.restype = PyChipError

self._dmLib.pychip_DeviceController_EstablishPASESessionBLE.argtypes = [
Expand Down
31 changes: 28 additions & 3 deletions src/controller/python/chip/clusters/Command.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
import logging
import sys
from asyncio.futures import Future
from ctypes import CFUNCTYPE, c_char_p, c_size_t, c_uint8, c_uint16, c_uint32, c_void_p, py_object
from ctypes import CFUNCTYPE, c_bool, c_char_p, c_size_t, c_uint8, c_uint16, c_uint32, c_void_p, py_object
from dataclasses import dataclass
from typing import Type, Union

Expand Down Expand Up @@ -144,8 +144,30 @@ def _OnCommandSenderDoneCallback(closure):
ctypes.pythonapi.Py_DecRef(ctypes.py_object(closure))


def TestOnlySendCommandTimedRequestFlagWithNoTimedInvoke(future: Future, eventLoop, responseType, device, commandPath, payload):
''' ONLY TO BE USED FOR TEST: Sends the payload with a TimedRequest flag but no TimedInvoke transaction
'''
if (responseType is not None) and (not issubclass(responseType, ClusterCommand)):
raise ValueError("responseType must be a ClusterCommand or None")

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_TestOnlySendCommandTimedRequestNoTimedInvoke(
ctypes.py_object(transaction), device,
commandPath.EndpointId, commandPath.ClusterId, commandPath.CommandId, payloadTLV, len(payloadTLV),
ctypes.c_uint16(0), # interactionTimeoutMs
ctypes.c_uint16(0), # busyWaitMs
ctypes.c_bool(False) # suppressResponse
))


def SendCommand(future: Future, eventLoop, responseType: Type, device, commandPath: CommandPath, payload: ClusterCommand,
timedRequestTimeoutMs: Union[None, int] = None, interactionTimeoutMs: Union[None, int] = None, busyWaitMs: Union[None, int] = None) -> PyChipError:
timedRequestTimeoutMs: Union[None, int] = None, interactionTimeoutMs: Union[None, int] = None, busyWaitMs: Union[None, int] = None,
suppressResponse: Union[None, bool] = 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 Down Expand Up @@ -175,6 +197,7 @@ def SendCommand(future: Future, eventLoop, responseType: Type, device, commandPa
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),
ctypes.c_bool(False if suppressResponse is None else suppressResponse)
))


Expand Down Expand Up @@ -203,7 +226,9 @@ def Init():
setter = chip.native.NativeLibraryHandleMethodArguments(handle)

setter.Set('pychip_CommandSender_SendCommand',
PyChipError, [py_object, c_void_p, c_uint16, c_uint32, c_uint32, c_char_p, c_size_t, c_uint16])
PyChipError, [py_object, c_void_p, c_uint16, c_uint32, c_uint32, c_char_p, c_size_t, c_uint16, c_bool])
setter.Set('pychip_CommandSender_TestOnlySendCommandTimedRequestNoTimedInvoke',
PyChipError, [py_object, c_void_p, c_uint32, c_uint32, c_char_p, c_size_t, c_uint16, c_bool])
setter.Set('pychip_CommandSender_SendGroupCommand',
PyChipError, [c_uint16, c_void_p, c_uint32, c_uint32, c_char_p, c_size_t, c_uint16])
setter.Set('pychip_CommandSender_InitCallbacks', None, [
Expand Down
Loading