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

[YAML] Update the tests to use ReadClient/WriteClient/CommandSender directly instead of Invoke #17628

Merged
merged 5 commits into from
Apr 26, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
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
4 changes: 2 additions & 2 deletions examples/chip-tool-darwin/commands/tests/TestCommandBridge.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,10 @@ class TestCommandBridge : public CHIPCommandBridge, public ValueChecker, public

virtual void NextTest() = 0;

void Exit(std::string message) override
void Exit(std::string message, CHIP_ERROR err = CHIP_ERROR_INTERNAL) override
{
ChipLogError(chipTool, " ***** Test Failure: %s\n", message.c_str());
SetCommandExitStatus(CHIP_ERROR_INTERNAL);
SetCommandExitStatus(err);
}

/////////// GlobalCommands Interface /////////
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{{#chip_tests tests}}
{{#chip_tests tests useSynthesizeWaitForReport=true}}
class {{filename}}: public TestCommandBridge
{
public:
Expand Down
1 change: 1 addition & 0 deletions examples/chip-tool/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ static_library("chip-tool-utils") {
"${chip_root}/src/app/tests/suites/commands/commissioner",
"${chip_root}/src/app/tests/suites/commands/delay",
"${chip_root}/src/app/tests/suites/commands/discovery",
"${chip_root}/src/app/tests/suites/commands/interaction_model",
"${chip_root}/src/app/tests/suites/commands/log",
"${chip_root}/src/app/tests/suites/commands/system",
"${chip_root}/src/app/tests/suites/pics",
Expand Down
38 changes: 31 additions & 7 deletions examples/chip-tool/commands/tests/TestCommand.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,18 +66,42 @@ void TestCommand::OnDeviceConnectionFailureFn(void * context, PeerId peerId, CHI
LogErrorOnFailure(command->ContinueOnChipMainThread(error));
}

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

void TestCommand::ThrowFailureResponse(CHIP_ERROR error)
void TestCommand::Exit(std::string message, CHIP_ERROR err)
{
Exit(std::string("Expecting success response but got a failure response: ") + chip::ErrorStr(error));
mContinueProcessing = false;

LogEnd(err);

if (CHIP_NO_ERROR == err)
{
InteractionModel::Shutdown();
SetCommandExitStatus(err);
}
else
{
chip::DeviceLayer::PlatformMgr().ScheduleWork(ExitAsync, reinterpret_cast<intptr_t>(this));
}
}

void TestCommand::ThrowSuccessResponse()
CHIP_ERROR TestCommand::ContinueOnChipMainThread(CHIP_ERROR err)
{
Exit("Expecting failure response but got a success response");
if (mContinueProcessing == false)
{
return CHIP_NO_ERROR;
}

if (CHIP_NO_ERROR == err)
{
return WaitForMs(0);
}

Exit(chip::ErrorStr(err), err);
return CHIP_NO_ERROR;
}
51 changes: 23 additions & 28 deletions examples/chip-tool/commands/tests/TestCommand.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,30 +22,33 @@
#include <app/tests/suites/commands/commissioner/CommissionerCommands.h>
#include <app/tests/suites/commands/delay/DelayCommands.h>
#include <app/tests/suites/commands/discovery/DiscoveryCommands.h>
#include <app/tests/suites/commands/interaction_model/InteractionModel.h>
#include <app/tests/suites/commands/log/LogCommands.h>
#include <app/tests/suites/commands/system/SystemCommands.h>
#include <app/tests/suites/include/ConstraintsChecker.h>
#include <app/tests/suites/include/PICSChecker.h>
#include <app/tests/suites/include/TestRunner.h>
#include <app/tests/suites/include/ValueChecker.h>
#include <lib/support/UnitTestUtils.h>
#include <zap-generated/tests/CHIPClustersTest.h>

constexpr uint16_t kTimeoutInSeconds = 90;

class TestCommand : public CHIPCommand,
class TestCommand : public TestRunner,
public CHIPCommand,
public ValueChecker,
public ConstraintsChecker,
public PICSChecker,
public LogCommands,
public CommissionerCommands,
public DiscoveryCommands,
public SystemCommands,
public DelayCommands
public DelayCommands,
public InteractionModel
{
public:
TestCommand(const char * commandName, CredentialIssuerCommands * credsIssuerConfig) :
CHIPCommand(commandName, credsIssuerConfig), mOnDeviceConnectedCallback(OnDeviceConnectedFn, this),
mOnDeviceConnectionFailureCallback(OnDeviceConnectionFailureFn, this)
TestCommand(const char * commandName, uint16_t testsCount, CredentialIssuerCommands * credsIssuerConfig) :
TestRunner(commandName, testsCount), CHIPCommand(commandName, credsIssuerConfig),
mOnDeviceConnectedCallback(OnDeviceConnectedFn, this), mOnDeviceConnectionFailureCallback(OnDeviceConnectionFailureFn, this)
{
AddArgument("delayInMs", 0, UINT64_MAX, &mDelayInMs);
AddArgument("PICS", &mPICSFilePath);
Expand All @@ -55,33 +58,25 @@ class TestCommand : public CHIPCommand,

/////////// CHIPCommand Interface /////////
CHIP_ERROR RunCommand() override;
virtual void NextTest() = 0;

protected:
/////////// DelayCommands Interface /////////
CHIP_ERROR WaitForCommissionee(chip::NodeId nodeId) override;
void OnWaitForMs() override { NextTest(); };

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

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

CHIP_ERROR ContinueOnChipMainThread(CHIP_ERROR err) override
{
if (CHIP_NO_ERROR == err)
{
return WaitForMs(0);
}
Exit(chip::ErrorStr(err));
return CHIP_NO_ERROR;
}
CHIP_ERROR ContinueOnChipMainThread(CHIP_ERROR err) override;

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

void Exit(std::string message) override;
void ThrowFailureResponse(CHIP_ERROR error);
void ThrowSuccessResponse();
static void ExitAsync(intptr_t context);
void Exit(std::string message, CHIP_ERROR err = CHIP_ERROR_INTERNAL) override;

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

void Wait()
{
if (mDelayInMs.HasValue())
{
chip::test_utils::SleepMillis(mDelayInMs.Value());
}
};
chip::Optional<uint64_t> mDelayInMs;
chip::Optional<char *> mPICSFilePath;
chip::Optional<uint16_t> mTimeout;
std::map<std::string, ChipDevice *> mDevices;

// When set to false, prevents interaction model events from affecting the current test status.
// This flag exists because if an error happens while processing a response the allocated
// command client/sender (ReadClient/WriteClient/CommandSender) can not be deallocated
// as it still used by the stack afterward. So a task is scheduled to run to close the
// test suite as soon as possible, and pending events are ignored in between.
bool mContinueProcessing = true;
vivien-apple marked this conversation as resolved.
Show resolved Hide resolved
};
44 changes: 34 additions & 10 deletions examples/chip-tool/templates/tests/helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
* limitations under the License.
*/

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

Expand All @@ -31,21 +31,44 @@ function utf8StringLength(str)
*/
function asPropertyValue(options)
{
let name = '';
let rootObject = 'value';

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

name += asLowerCamelCase(this.name);

if (this.isOptional && !options.hash.dontUnwrapValue) {
name += '.Value()';
rootObject += '.Value()';
}

return rootObject;
}

async function asEncodableType()
{
// Copy some properties needed by zapTypeToEncodableClusterObjectType
let target = { global : this.global, entryType : this.entryType };

let type;
if ('commandObject' in this) {
type = this.commandObject.name;
} else if ('attributeObject' in this) {
type = this.attributeObject.type;
target.isArray = this.attributeObject.isArray;
target.isOptional = this.attributeObject.isOptional;
target.isNullable = this.attributeObject.isNullable;
} else {
throw new Error("Unsupported encodable type");
}

return name;
if (isTestOnlyCluster(this.cluster) || 'commandObject' in this) {
return `chip::app::Clusters::${asUpperCamelCase(this.cluster)}::Commands::${asUpperCamelCase(type)}::Type`;
}

const options = { 'hash' : { ns : this.cluster } };
return await zapTypeToEncodableClusterObjectType.call(target, type, options);
}

async function asDecodableType()
Expand All @@ -62,7 +85,7 @@ async function asDecodableType()
target.isOptional = this.attributeObject.isOptional;
target.isNullable = this.attributeObject.isNullable;
} else if ('eventObject' in this) {
type = this.eventObject.type;
type = this.event;
} else {
throw new Error("Unsupported decodable type");
}
Expand All @@ -81,3 +104,4 @@ async function asDecodableType()
exports.utf8StringLength = utf8StringLength;
exports.asPropertyValue = asPropertyValue;
exports.asDecodableType = asDecodableType;
exports.asEncodableType = asEncodableType;
Loading