Skip to content

Commit

Permalink
New unit testing cluster commands to support testing batch commands c…
Browse files Browse the repository at this point in the history
…orner cases (#31138)

* New unit testing cluster commands for batch testing

* Restyled by whitespace

* Restyled by clang-format

* Address PR comments

* Restyled by clang-format

* Fixes for CI

* Restyled by prettier-yaml

* Fix Darwin codegen for adding new commands to UnitTesting.

1) Add missing isSupported check that was causing us to generate an
   implementation that did not have a corresponding declaration (which had the
   check).

2) Add missing isForCommandPayload to existing isSupported check, so
   implementation and declaration are doing the same check.

3) Mark newly-added things as provisional.

* Rerun zap regen

---------

Co-authored-by: Restyled.io <commits@restyled.io>
Co-authored-by: Boris Zbarsky <bzbarsky@apple.com>
  • Loading branch information
3 people authored and pull[bot] committed Jan 13, 2024
1 parent a5cecf0 commit 1258899
Show file tree
Hide file tree
Showing 34 changed files with 1,705 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6198,6 +6198,10 @@ internal cluster UnitTesting = 4294048773 {
NestedStructList arg1[] = 0;
}

response struct TestBatchHelperResponse = 12 {
octet_string<800> buffer = 0;
}

request struct TestListInt8UReverseRequestRequest {
int8u arg1[] = 0;
}
Expand Down Expand Up @@ -6244,6 +6248,18 @@ internal cluster UnitTesting = 4294048773 {
int8u arg1 = 0;
}

request struct TestBatchHelperRequestRequest {
int16u sleepBeforeResponseTimeMs = 0;
int16u sizeOfResponseBuffer = 1;
int8u fillCharacter = 2;
}

request struct TestSecondBatchHelperRequestRequest {
int16u sleepBeforeResponseTimeMs = 0;
int16u sizeOfResponseBuffer = 1;
int8u fillCharacter = 2;
}

/** Simple command without any parameters and without a specific response */
command Test(): DefaultSuccess = 0;
/** Simple command without any parameters and without a specific response not handled by the server */
Expand Down Expand Up @@ -6309,6 +6325,10 @@ internal cluster UnitTesting = 4294048773 {
command TestEmitTestEventRequest(TestEmitTestEventRequestRequest): TestEmitTestEventResponse = 20;
/** Command that takes identical arguments to the fields of the TestFabricScopedEvent and logs the TestFabricScopedEvent to the buffer. Command returns an event ID as the response. */
command TestEmitTestFabricScopedEventRequest(TestEmitTestFabricScopedEventRequestRequest): TestEmitTestFabricScopedEventResponse = 21;
/** Command that responds after sleepBeforeResponseTimeMs with an octet_string the size requested with fillCharacter. */
command TestBatchHelperRequest(TestBatchHelperRequestRequest): TestBatchHelperResponse = 22;
/** Second command that responds after sleepBeforeResponseTimeMs with an octet_string the size requested with fillCharacter. */
command TestSecondBatchHelperRequest(TestSecondBatchHelperRequestRequest): TestBatchHelperResponse = 23;
}

/** The Fault Injection Cluster provide a means for a test harness to configure faults(for example triggering a fault in the system). */
Expand Down Expand Up @@ -8012,6 +8032,8 @@ endpoint 1 {
handle command TestSimpleOptionalArgumentRequest;
handle command TestEmitTestEventRequest;
handle command TestEmitTestFabricScopedEventRequest;
handle command TestBatchHelperRequest;
handle command TestSecondBatchHelperRequest;
}
}
endpoint 2 {
Expand Down
28 changes: 22 additions & 6 deletions examples/all-clusters-app/all-clusters-common/all-clusters-app.zap
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,19 @@
}
],
"package": [
{
"pathRelativity": "relativeToZap",
"path": "../../../src/app/zap-templates/app-templates.json",
"type": "gen-templates-json",
"version": "chip-v1"
},
{
"pathRelativity": "relativeToZap",
"path": "../../../src/app/zap-templates/zcl/zcl-with-test-extensions.json",
"type": "zcl-properties",
"category": "matter",
"version": 1,
"description": "Matter SDK ZCL data with some extensions"
},
{
"pathRelativity": "relativeToZap",
"path": "../../../src/app/zap-templates/app-templates.json",
"type": "gen-templates-json",
"version": "chip-v1"
}
],
"endpointTypes": [
Expand Down Expand Up @@ -19318,6 +19318,22 @@
"source": "client",
"isIncoming": 1,
"isEnabled": 1
},
{
"name": "TestBatchHelperRequest",
"code": 22,
"mfgCode": null,
"source": "client",
"isIncoming": 1,
"isEnabled": 1
},
{
"name": "TestSecondBatchHelperRequest",
"code": 23,
"mfgCode": null,
"source": "client",
"isIncoming": 1,
"isEnabled": 1
}
],
"attributes": [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5601,6 +5601,10 @@ internal cluster UnitTesting = 4294048773 {
NestedStructList arg1[] = 0;
}

response struct TestBatchHelperResponse = 12 {
octet_string<800> buffer = 0;
}

request struct TestListInt8UReverseRequestRequest {
int8u arg1[] = 0;
}
Expand Down Expand Up @@ -5647,6 +5651,18 @@ internal cluster UnitTesting = 4294048773 {
int8u arg1 = 0;
}

request struct TestBatchHelperRequestRequest {
int16u sleepBeforeResponseTimeMs = 0;
int16u sizeOfResponseBuffer = 1;
int8u fillCharacter = 2;
}

request struct TestSecondBatchHelperRequestRequest {
int16u sleepBeforeResponseTimeMs = 0;
int16u sizeOfResponseBuffer = 1;
int8u fillCharacter = 2;
}

/** Simple command without any parameters and without a specific response */
command Test(): DefaultSuccess = 0;
/** Simple command without any parameters and without a specific response not handled by the server */
Expand Down Expand Up @@ -5712,6 +5728,10 @@ internal cluster UnitTesting = 4294048773 {
command TestEmitTestEventRequest(TestEmitTestEventRequestRequest): TestEmitTestEventResponse = 20;
/** Command that takes identical arguments to the fields of the TestFabricScopedEvent and logs the TestFabricScopedEvent to the buffer. Command returns an event ID as the response. */
command TestEmitTestFabricScopedEventRequest(TestEmitTestFabricScopedEventRequestRequest): TestEmitTestFabricScopedEventResponse = 21;
/** Command that responds after sleepBeforeResponseTimeMs with an octet_string the size requested with fillCharacter. */
command TestBatchHelperRequest(TestBatchHelperRequestRequest): TestBatchHelperResponse = 22;
/** Second command that responds after sleepBeforeResponseTimeMs with an octet_string the size requested with fillCharacter. */
command TestSecondBatchHelperRequest(TestSecondBatchHelperRequestRequest): TestBatchHelperResponse = 23;
}

endpoint 0 {
Expand Down
87 changes: 87 additions & 0 deletions src/app/clusters/test-cluster-server/test-cluster-server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ constexpr uint8_t kFabricSensitiveCharLength = 128;
// The maximum length of the fabric sensitive integer list within the TestFabricScoped struct.
constexpr uint8_t kFabricSensitiveIntListLength = 8;

// The maximum buffer size allowed in TestBatchHelperResponse
constexpr uint16_t kTestBatchHelperResponseBufferMax = 800;

namespace {

class OctetStringData
Expand Down Expand Up @@ -103,6 +106,14 @@ class TestAttrAccess : public AttributeAccessInterface
CHIP_ERROR WriteListFabricScopedAttribute(const ConcreteDataAttributePath & aPath, AttributeValueDecoder & aDecoder);
};

struct AsyncBatchCommandsWorkData
{
CommandHandler::Handle asyncCommandHandle;
ConcreteCommandPath commandPath = ConcreteCommandPath(0, 0, 0);
uint16_t sizeOfResponseBuffer;
uint8_t fillCharacter;
};

TestAttrAccess gAttrAccess;
uint8_t gListUint8Data[kAttributeListLength];
size_t gListUint8DataLen = kAttributeListLength;
Expand Down Expand Up @@ -137,6 +148,36 @@ SimpleEnum gSimpleEnums[kAttributeListLength];
size_t gSimpleEnumCount = 0;
Structs::NullablesAndOptionalsStruct::Type gNullablesAndOptionalsStruct;

void AsyncBatchCommandWork(AsyncBatchCommandsWorkData * asyncWorkData)
{
auto commandHandleRef = std::move(asyncWorkData->asyncCommandHandle);
auto commandHandle = commandHandleRef.Get();
if (commandHandle == nullptr)
{
// Very weird that we are even in here, what set this to nullptr?
Platform::Delete(asyncWorkData);
return;
}

uint8_t buffer[kTestBatchHelperResponseBufferMax];
memset(buffer, asyncWorkData->fillCharacter, asyncWorkData->sizeOfResponseBuffer);
Commands::TestBatchHelperResponse::Type response;
response.buffer = ByteSpan(buffer, asyncWorkData->sizeOfResponseBuffer);
commandHandle->AddResponse(asyncWorkData->commandPath, response);
Platform::Delete(asyncWorkData);
}

static void timerCallback(System::Layer *, void * callbackContext)
{
AsyncBatchCommandWork(reinterpret_cast<AsyncBatchCommandsWorkData *>(callbackContext));
}

static void scheduleTimerCallbackMs(AsyncBatchCommandsWorkData * asyncWorkData, uint32_t delayMs)
{
DeviceLayer::SystemLayer().StartTimer(chip::System::Clock::Milliseconds32(delayMs), timerCallback,
reinterpret_cast<void *>(asyncWorkData));
}

CHIP_ERROR TestAttrAccess::Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder)
{
switch (aPath.mAttributeId)
Expand Down Expand Up @@ -994,6 +1035,52 @@ bool emberAfUnitTestingClusterTestSimpleOptionalArgumentRequestCallback(
return true;
}

// TestBatchHelperRequest and TestSecondBatchHelperRequest do the same thing.
// The reason there are two identical commands is because batch command requires
// command paths in the same batch to be unique. These command allow for
// client to control order of the response and control size of CommandDataIB
// being sent back to help test some corner cases.
bool TestBatchHelperCommon(CommandHandler * commandObj, const ConcreteCommandPath & commandPath, const uint16_t sleepTimeMs,
const uint16_t sizeOfResponseBuffer, const uint8_t fillCharacter)
{
if (sizeOfResponseBuffer > kTestBatchHelperResponseBufferMax)
{
commandObj->AddStatus(commandPath, Protocols::InteractionModel::Status::ConstraintError);
return true;
}

AsyncBatchCommandsWorkData * asyncWorkData = Platform::New<AsyncBatchCommandsWorkData>();
if (asyncWorkData == nullptr)
{
commandObj->AddStatus(commandPath, Protocols::InteractionModel::Status::Busy);
return true;
}

asyncWorkData->asyncCommandHandle = commandObj;
asyncWorkData->commandPath = commandPath;
asyncWorkData->sizeOfResponseBuffer = sizeOfResponseBuffer;
asyncWorkData->fillCharacter = fillCharacter;

scheduleTimerCallbackMs(asyncWorkData, sleepTimeMs);

return true;
}

bool emberAfUnitTestingClusterTestBatchHelperRequestCallback(CommandHandler * commandObj, const ConcreteCommandPath & commandPath,
const Commands::TestBatchHelperRequest::DecodableType & commandData)
{
return TestBatchHelperCommon(commandObj, commandPath, commandData.sleepBeforeResponseTimeMs, commandData.sizeOfResponseBuffer,
commandData.fillCharacter);
}

bool emberAfUnitTestingClusterTestSecondBatchHelperRequestCallback(
CommandHandler * commandObj, const ConcreteCommandPath & commandPath,
const Commands::TestSecondBatchHelperRequest::DecodableType & commandData)
{
return TestBatchHelperCommon(commandObj, commandPath, commandData.sleepBeforeResponseTimeMs, commandData.sizeOfResponseBuffer,
commandData.fillCharacter);
}

// -----------------------------------------------------------------------------
// Plugin initialization

Expand Down
25 changes: 23 additions & 2 deletions src/app/tests/suites/TestCluster.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3855,13 +3855,34 @@ tests:
attribute: "AcceptedCommandList"
response:
value:
[0, 1, 2, 4, 7, 8, 9, 10, 11, 12, 13, 14, 15, 17, 18, 19, 20, 21]
[
0,
1,
2,
4,
7,
8,
9,
10,
11,
12,
13,
14,
15,
17,
18,
19,
20,
21,
22,
23,
]

- label: "read GeneratedCommandList attribute"
command: "readAttribute"
attribute: "GeneratedCommandList"
response:
value: [0, 1, 4, 5, 6, 8, 9, 10, 11]
value: [0, 1, 4, 5, 6, 8, 9, 10, 11, 12]

# Struct-typed attribute
- label: "Write struct-typed attribute"
Expand Down
27 changes: 27 additions & 0 deletions src/app/zap-templates/zcl/data-model/chip/test-cluster.xml
Original file line number Diff line number Diff line change
Expand Up @@ -440,6 +440,26 @@ limitations under the License.
<arg name="arg1" type="int8u"/>
</command>

<command source="client" code="0x16" name="TestBatchHelperRequest"
optional="true" response="TestBatchHelperResponse" apiMaturity="provisional">
<description>
Command that responds after sleepBeforeResponseTimeMs with an octet_string the size requested with fillCharacter.
</description>
<arg name="sleepBeforeResponseTimeMs" type="int16u"/>
<arg name="sizeOfResponseBuffer" min="0" max="800" type="int16u"/>
<arg name="fillCharacter" type="int8u"/>
</command>

<command source="client" code="0x17" name="TestSecondBatchHelperRequest"
optional="true" response="TestBatchHelperResponse" apiMaturity="provisional">
<description>
Second command that responds after sleepBeforeResponseTimeMs with an octet_string the size requested with fillCharacter.
</description>
<arg name="sleepBeforeResponseTimeMs" type="int16u"/>
<arg name="sizeOfResponseBuffer" min="0" max="800" type="int16u"/>
<arg name="fillCharacter" type="int8u"/>
</command>

<command source="server" code="0x00" name="TestSpecificResponse" optional="true" disableDefaultResponse="true">
<description>
Simple response for TestWithResponse with a simple return value
Expand Down Expand Up @@ -566,6 +586,13 @@ limitations under the License.
<arg name="value" type="int64u"/>
</command>

<command source="server" code="0x0C" name="TestBatchHelperResponse" optional="true" disableDefaultResponse="true" apiMaturity="provisional">
<description>
Response to TestBatchHelperRequest or TestSecondBatchHelperRequest. Buffer in response is filled as directed in the Request.
</description>
<arg name="buffer" type="octet_string" length="800"/>
</command>

<event code="0x0001" name="TestEvent" priority="info" side="server">
<description>Example test event</description>
<field id="1" name="arg1" type="int8u"/>
Expand Down
20 changes: 20 additions & 0 deletions src/controller/data_model/controller-clusters.matter
Original file line number Diff line number Diff line change
Expand Up @@ -8693,6 +8693,10 @@ internal cluster UnitTesting = 4294048773 {
NestedStructList arg1[] = 0;
}

response struct TestBatchHelperResponse = 12 {
octet_string<800> buffer = 0;
}

request struct TestListInt8UReverseRequestRequest {
int8u arg1[] = 0;
}
Expand Down Expand Up @@ -8739,6 +8743,18 @@ internal cluster UnitTesting = 4294048773 {
int8u arg1 = 0;
}

request struct TestBatchHelperRequestRequest {
int16u sleepBeforeResponseTimeMs = 0;
int16u sizeOfResponseBuffer = 1;
int8u fillCharacter = 2;
}

request struct TestSecondBatchHelperRequestRequest {
int16u sleepBeforeResponseTimeMs = 0;
int16u sizeOfResponseBuffer = 1;
int8u fillCharacter = 2;
}

/** Simple command without any parameters and without a specific response */
command Test(): DefaultSuccess = 0;
/** Simple command without any parameters and without a specific response not handled by the server */
Expand Down Expand Up @@ -8804,6 +8820,10 @@ internal cluster UnitTesting = 4294048773 {
command TestEmitTestEventRequest(TestEmitTestEventRequestRequest): TestEmitTestEventResponse = 20;
/** Command that takes identical arguments to the fields of the TestFabricScopedEvent and logs the TestFabricScopedEvent to the buffer. Command returns an event ID as the response. */
command TestEmitTestFabricScopedEventRequest(TestEmitTestFabricScopedEventRequestRequest): TestEmitTestFabricScopedEventResponse = 21;
/** Command that responds after sleepBeforeResponseTimeMs with an octet_string the size requested with fillCharacter. */
command TestBatchHelperRequest(TestBatchHelperRequestRequest): TestBatchHelperResponse = 22;
/** Second command that responds after sleepBeforeResponseTimeMs with an octet_string the size requested with fillCharacter. */
command TestSecondBatchHelperRequest(TestSecondBatchHelperRequestRequest): TestBatchHelperResponse = 23;
}

/** The Fault Injection Cluster provide a means for a test harness to configure faults(for example triggering a fault in the system). */
Expand Down
Loading

0 comments on commit 1258899

Please sign in to comment.