Skip to content

Commit 2057972

Browse files
authored
[YAML] Update the tests to use ReadClient/WriteClient/CommandSender directly instead of Invoke (project-chip#17628)
* [YAML] Add an interaction model module to src/app/tests/suites * [YAML] Get the interaction model module to be built along chip-tool * Update the commandName field in ClusterTestGeneration so that the actual command to be called can be generated directly * Update template to use the interaction model module instead of Invoke * Update generated code
1 parent 6160935 commit 2057972

File tree

23 files changed

+45692
-117358
lines changed

23 files changed

+45692
-117358
lines changed

examples/chip-tool-darwin/commands/tests/TestCommandBridge.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -57,10 +57,10 @@ class TestCommandBridge : public CHIPCommandBridge, public ValueChecker, public
5757

5858
virtual void NextTest() = 0;
5959

60-
void Exit(std::string message) override
60+
void Exit(std::string message, CHIP_ERROR err = CHIP_ERROR_INTERNAL) override
6161
{
6262
ChipLogError(chipTool, " ***** Test Failure: %s\n", message.c_str());
63-
SetCommandExitStatus(CHIP_ERROR_INTERNAL);
63+
SetCommandExitStatus(err);
6464
}
6565

6666
/////////// GlobalCommands Interface /////////

examples/chip-tool-darwin/templates/tests/partials/test_cluster.zapt

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
{{#chip_tests tests}}
1+
{{#chip_tests tests useSynthesizeWaitForReport=true}}
22
class {{filename}}: public TestCommandBridge
33
{
44
public:

examples/chip-tool/BUILD.gn

+1
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ static_library("chip-tool-utils") {
8484
"${chip_root}/src/app/tests/suites/commands/commissioner",
8585
"${chip_root}/src/app/tests/suites/commands/delay",
8686
"${chip_root}/src/app/tests/suites/commands/discovery",
87+
"${chip_root}/src/app/tests/suites/commands/interaction_model",
8788
"${chip_root}/src/app/tests/suites/commands/log",
8889
"${chip_root}/src/app/tests/suites/commands/system",
8990
"${chip_root}/src/app/tests/suites/pics",

examples/chip-tool/commands/tests/TestCommand.cpp

+31-7
Original file line numberDiff line numberDiff line change
@@ -66,18 +66,42 @@ void TestCommand::OnDeviceConnectionFailureFn(void * context, PeerId peerId, CHI
6666
LogErrorOnFailure(command->ContinueOnChipMainThread(error));
6767
}
6868

69-
void TestCommand::Exit(std::string message)
69+
void TestCommand::ExitAsync(intptr_t context)
7070
{
71-
ChipLogError(chipTool, " ***** Test Failure: %s\n", message.c_str());
72-
SetCommandExitStatus(CHIP_ERROR_INTERNAL);
71+
auto testCommand = reinterpret_cast<TestCommand *>(context);
72+
testCommand->InteractionModel::Shutdown();
73+
testCommand->SetCommandExitStatus(CHIP_ERROR_INTERNAL);
7374
}
7475

75-
void TestCommand::ThrowFailureResponse(CHIP_ERROR error)
76+
void TestCommand::Exit(std::string message, CHIP_ERROR err)
7677
{
77-
Exit(std::string("Expecting success response but got a failure response: ") + chip::ErrorStr(error));
78+
mContinueProcessing = false;
79+
80+
LogEnd(err);
81+
82+
if (CHIP_NO_ERROR == err)
83+
{
84+
InteractionModel::Shutdown();
85+
SetCommandExitStatus(err);
86+
}
87+
else
88+
{
89+
chip::DeviceLayer::PlatformMgr().ScheduleWork(ExitAsync, reinterpret_cast<intptr_t>(this));
90+
}
7891
}
7992

80-
void TestCommand::ThrowSuccessResponse()
93+
CHIP_ERROR TestCommand::ContinueOnChipMainThread(CHIP_ERROR err)
8194
{
82-
Exit("Expecting failure response but got a success response");
95+
if (mContinueProcessing == false)
96+
{
97+
return CHIP_NO_ERROR;
98+
}
99+
100+
if (CHIP_NO_ERROR == err)
101+
{
102+
return WaitForMs(0);
103+
}
104+
105+
Exit(chip::ErrorStr(err), err);
106+
return CHIP_NO_ERROR;
83107
}

examples/chip-tool/commands/tests/TestCommand.h

+23-28
Original file line numberDiff line numberDiff line change
@@ -22,30 +22,33 @@
2222
#include <app/tests/suites/commands/commissioner/CommissionerCommands.h>
2323
#include <app/tests/suites/commands/delay/DelayCommands.h>
2424
#include <app/tests/suites/commands/discovery/DiscoveryCommands.h>
25+
#include <app/tests/suites/commands/interaction_model/InteractionModel.h>
2526
#include <app/tests/suites/commands/log/LogCommands.h>
2627
#include <app/tests/suites/commands/system/SystemCommands.h>
2728
#include <app/tests/suites/include/ConstraintsChecker.h>
2829
#include <app/tests/suites/include/PICSChecker.h>
30+
#include <app/tests/suites/include/TestRunner.h>
2931
#include <app/tests/suites/include/ValueChecker.h>
30-
#include <lib/support/UnitTestUtils.h>
3132
#include <zap-generated/tests/CHIPClustersTest.h>
3233

3334
constexpr uint16_t kTimeoutInSeconds = 90;
3435

35-
class TestCommand : public CHIPCommand,
36+
class TestCommand : public TestRunner,
37+
public CHIPCommand,
3638
public ValueChecker,
3739
public ConstraintsChecker,
3840
public PICSChecker,
3941
public LogCommands,
4042
public CommissionerCommands,
4143
public DiscoveryCommands,
4244
public SystemCommands,
43-
public DelayCommands
45+
public DelayCommands,
46+
public InteractionModel
4447
{
4548
public:
46-
TestCommand(const char * commandName, CredentialIssuerCommands * credsIssuerConfig) :
47-
CHIPCommand(commandName, credsIssuerConfig), mOnDeviceConnectedCallback(OnDeviceConnectedFn, this),
48-
mOnDeviceConnectionFailureCallback(OnDeviceConnectionFailureFn, this)
49+
TestCommand(const char * commandName, uint16_t testsCount, CredentialIssuerCommands * credsIssuerConfig) :
50+
TestRunner(commandName, testsCount), CHIPCommand(commandName, credsIssuerConfig),
51+
mOnDeviceConnectedCallback(OnDeviceConnectedFn, this), mOnDeviceConnectionFailureCallback(OnDeviceConnectionFailureFn, this)
4952
{
5053
AddArgument("delayInMs", 0, UINT64_MAX, &mDelayInMs);
5154
AddArgument("PICS", &mPICSFilePath);
@@ -55,33 +58,25 @@ class TestCommand : public CHIPCommand,
5558

5659
/////////// CHIPCommand Interface /////////
5760
CHIP_ERROR RunCommand() override;
58-
virtual void NextTest() = 0;
5961

6062
protected:
6163
/////////// DelayCommands Interface /////////
6264
CHIP_ERROR WaitForCommissionee(chip::NodeId nodeId) override;
6365
void OnWaitForMs() override { NextTest(); };
6466

65-
std::map<std::string, ChipDevice *> mDevices;
67+
/////////// Interaction Model Interface /////////
68+
chip::DeviceProxy * GetDevice(const char * identity) override { return mDevices[identity]; }
69+
void OnResponse(const chip::app::StatusIB & status, chip::TLV::TLVReader * data) override{};
6670

6771
static void OnDeviceConnectedFn(void * context, chip::OperationalDeviceProxy * device);
6872
static void OnDeviceConnectionFailureFn(void * context, PeerId peerId, CHIP_ERROR error);
6973

70-
CHIP_ERROR ContinueOnChipMainThread(CHIP_ERROR err) override
71-
{
72-
if (CHIP_NO_ERROR == err)
73-
{
74-
return WaitForMs(0);
75-
}
76-
Exit(chip::ErrorStr(err));
77-
return CHIP_NO_ERROR;
78-
}
74+
CHIP_ERROR ContinueOnChipMainThread(CHIP_ERROR err) override;
7975

8076
chip::Controller::DeviceCommissioner & GetCurrentCommissioner() override { return CurrentCommissioner(); };
8177

82-
void Exit(std::string message) override;
83-
void ThrowFailureResponse(CHIP_ERROR error);
84-
void ThrowSuccessResponse();
78+
static void ExitAsync(intptr_t context);
79+
void Exit(std::string message, CHIP_ERROR err = CHIP_ERROR_INTERNAL) override;
8580

8681
chip::Callback::Callback<chip::OnDeviceConnected> mOnDeviceConnectedCallback;
8782
chip::Callback::Callback<chip::OnDeviceConnectionFailure> mOnDeviceConnectionFailureCallback;
@@ -92,14 +87,14 @@ class TestCommand : public CHIPCommand,
9287
status.mStatus == chip::Protocols::InteractionModel::Status::UnsupportedCommand;
9388
}
9489

95-
void Wait()
96-
{
97-
if (mDelayInMs.HasValue())
98-
{
99-
chip::test_utils::SleepMillis(mDelayInMs.Value());
100-
}
101-
};
102-
chip::Optional<uint64_t> mDelayInMs;
10390
chip::Optional<char *> mPICSFilePath;
10491
chip::Optional<uint16_t> mTimeout;
92+
std::map<std::string, ChipDevice *> mDevices;
93+
94+
// When set to false, prevents interaction model events from affecting the current test status.
95+
// This flag exists because if an error happens while processing a response the allocated
96+
// command client/sender (ReadClient/WriteClient/CommandSender) can not be deallocated
97+
// as it still used by the stack afterward. So a task is scheduled to run to close the
98+
// test suite as soon as possible, and pending events are ignored in between.
99+
bool mContinueProcessing = true;
105100
};

examples/chip-tool/templates/tests/helper.js

+34-10
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
* limitations under the License.
1616
*/
1717

18-
const { zapTypeToDecodableClusterObjectType, asUpperCamelCase, asLowerCamelCase }
18+
const { zapTypeToDecodableClusterObjectType, zapTypeToEncodableClusterObjectType, asUpperCamelCase, asLowerCamelCase }
1919
= require('../../../../src/app/zap-templates/templates/app/helper.js');
2020
const { isTestOnlyCluster } = require('../../../../src/app/zap-templates/common/simulated-clusters/SimulatedClusters.js');
2121

@@ -31,21 +31,44 @@ function utf8StringLength(str)
3131
*/
3232
function asPropertyValue(options)
3333
{
34-
let name = '';
34+
let rootObject = 'value';
3535

36-
// The decodable type for simulated cluster is a struct by default, even if the
36+
// The decodable type for commands is a struct by default, even if the
3737
// command just returns a single value.
38-
if (isTestOnlyCluster(this.parent.cluster)) {
39-
name = 'value.'
38+
if (this.parent.isCommand) {
39+
rootObject += '.' + asLowerCamelCase(this.name);
4040
}
4141

42-
name += asLowerCamelCase(this.name);
43-
4442
if (this.isOptional && !options.hash.dontUnwrapValue) {
45-
name += '.Value()';
43+
rootObject += '.Value()';
44+
}
45+
46+
return rootObject;
47+
}
48+
49+
async function asEncodableType()
50+
{
51+
// Copy some properties needed by zapTypeToEncodableClusterObjectType
52+
let target = { global : this.global, entryType : this.entryType };
53+
54+
let type;
55+
if ('commandObject' in this) {
56+
type = this.commandObject.name;
57+
} else if ('attributeObject' in this) {
58+
type = this.attributeObject.type;
59+
target.isArray = this.attributeObject.isArray;
60+
target.isOptional = this.attributeObject.isOptional;
61+
target.isNullable = this.attributeObject.isNullable;
62+
} else {
63+
throw new Error("Unsupported encodable type");
4664
}
4765

48-
return name;
66+
if (isTestOnlyCluster(this.cluster) || 'commandObject' in this) {
67+
return `chip::app::Clusters::${asUpperCamelCase(this.cluster)}::Commands::${asUpperCamelCase(type)}::Type`;
68+
}
69+
70+
const options = { 'hash' : { ns : this.cluster } };
71+
return await zapTypeToEncodableClusterObjectType.call(target, type, options);
4972
}
5073

5174
async function asDecodableType()
@@ -62,7 +85,7 @@ async function asDecodableType()
6285
target.isOptional = this.attributeObject.isOptional;
6386
target.isNullable = this.attributeObject.isNullable;
6487
} else if ('eventObject' in this) {
65-
type = this.eventObject.type;
88+
type = this.event;
6689
} else {
6790
throw new Error("Unsupported decodable type");
6891
}
@@ -81,3 +104,4 @@ async function asDecodableType()
81104
exports.utf8StringLength = utf8StringLength;
82105
exports.asPropertyValue = asPropertyValue;
83106
exports.asDecodableType = asDecodableType;
107+
exports.asEncodableType = asEncodableType;

0 commit comments

Comments
 (0)