From 1621140793188f2958923af6d0ad9d32b0f34dc0 Mon Sep 17 00:00:00 2001 From: Karsten Sperling <113487422+ksperling-apple@users.noreply.github.com> Date: Wed, 3 Jul 2024 10:52:11 +1200 Subject: [PATCH] Disentangle data model tests by moving fixtures into their own file (#34154) * Disentangle data model tests by moving fixtures into their own file The data model tests all had linker dependencies on each other, which meant that running any of Test{Read,Write,Commands} would run the tests from all of them, because the global fixture function from that test was required. This change moves all those fixture functions into DataModelFixtures.cpp. Also disambiguate the enum types and control variable names involved. * Address review comments - Add more comments to DataModelFixtures.h - Use ScopedChangeOnly for the fixture control variables - Extend ScopedChange to allow assignments within the scope --- src/app/util/mock/Constants.h | 19 + src/app/util/mock/attribute-storage.cpp | 20 +- src/controller/tests/data_model/BUILD.gn | 14 +- .../tests/data_model/DataModelFixtures.cpp | 468 ++++++++++++++++++ .../tests/data_model/DataModelFixtures.h | 102 ++++ .../tests/data_model/TestCommands.cpp | 159 +----- src/controller/tests/data_model/TestRead.cpp | 377 +++----------- src/controller/tests/data_model/TestWrite.cpp | 192 +------ src/lib/support/Scoped.h | 30 +- 9 files changed, 744 insertions(+), 637 deletions(-) create mode 100644 src/controller/tests/data_model/DataModelFixtures.cpp create mode 100644 src/controller/tests/data_model/DataModelFixtures.h diff --git a/src/app/util/mock/Constants.h b/src/app/util/mock/Constants.h index 803dff5b7f8f12..e60154a5d0e773 100644 --- a/src/app/util/mock/Constants.h +++ b/src/app/util/mock/Constants.h @@ -50,5 +50,24 @@ constexpr EventId MockEventId(const uint16_t & id) { return (0xFFF1'0000 | id); } + +// Cluster Revision value returned by mock clusters +extern const uint16_t mockClusterRevision; + +// Feature Map value returned by mock clusters +extern const uint32_t mockFeatureMap; + +// Scalar value returned by mock clusters for MockAttributeId(1) +extern const bool mockAttribute1; + +// Scalar value returned by mock clusters for MockAttributeId(2) +extern const int16_t mockAttribute2; + +// Scalar value returned by mock clusters for MockAttributeId(3) +extern const uint64_t mockAttribute3; + +// MockAttributeId(4) returns a list of octstr with this value +extern const uint8_t mockAttribute4[256]; + } // namespace Test } // namespace chip diff --git a/src/app/util/mock/attribute-storage.cpp b/src/app/util/mock/attribute-storage.cpp index 97b21967be0313..93d3219fc04a41 100644 --- a/src/app/util/mock/attribute-storage.cpp +++ b/src/app/util/mock/attribute-storage.cpp @@ -113,12 +113,17 @@ const MockNodeConfig & GetMockNodeConfig() return (mockConfig != nullptr) ? *mockConfig : DefaultMockNodeConfig(); } -uint16_t mockClusterRevision = 1; -uint32_t mockFeatureMap = 0x1234; -bool mockAttribute1 = true; -int16_t mockAttribute2 = 42; -uint64_t mockAttribute3 = 0xdeadbeef0000cafe; -uint8_t mockAttribute4[256] = { +} // namespace + +namespace chip { +namespace Test { + +const uint16_t mockClusterRevision = 1; +const uint32_t mockFeatureMap = 0x1234; +const bool mockAttribute1 = true; +const int16_t mockAttribute2 = 42; +const uint64_t mockAttribute3 = 0xdeadbeef0000cafe; +const uint8_t mockAttribute4[256] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, @@ -129,7 +134,8 @@ uint8_t mockAttribute4[256] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, }; -} // namespace +} // namespace Test +} // namespace chip uint16_t emberAfEndpointCount() { diff --git a/src/controller/tests/data_model/BUILD.gn b/src/controller/tests/data_model/BUILD.gn index d8ce821ed837af..c67922717645dd 100644 --- a/src/controller/tests/data_model/BUILD.gn +++ b/src/controller/tests/data_model/BUILD.gn @@ -22,11 +22,19 @@ import("${chip_root}/src/platform/device.gni") chip_test_suite("data_model") { output_name = "libDataModelTests" + sources = [ + "DataModelFixtures.cpp", + "DataModelFixtures.h", + ] + + test_sources = [] if (chip_device_platform != "mbed" && chip_device_platform != "efr32" && chip_device_platform != "esp32" && chip_device_platform != "fake") { - test_sources = [ "TestCommands.cpp" ] - test_sources += [ "TestWrite.cpp" ] - test_sources += [ "TestRead.cpp" ] + test_sources += [ + "TestCommands.cpp", + "TestRead.cpp", + "TestWrite.cpp", + ] } public_deps = [ diff --git a/src/controller/tests/data_model/DataModelFixtures.cpp b/src/controller/tests/data_model/DataModelFixtures.cpp new file mode 100644 index 00000000000000..11dbd1059f7415 --- /dev/null +++ b/src/controller/tests/data_model/DataModelFixtures.cpp @@ -0,0 +1,468 @@ +/* + * + * Copyright (c) 2024 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "DataModelFixtures.h" + +#include +#include +#include +#include + +using namespace chip; +using namespace chip::app; +using namespace chip::app::DataModelTests; +using namespace chip::app::Clusters; +using namespace chip::app::Clusters::UnitTesting; +using namespace chip::Protocols; + +namespace chip { +namespace app { + +namespace DataModelTests { + +ScopedChangeOnly gReadResponseDirective(ReadResponseDirective::kSendDataResponse); +ScopedChangeOnly gWriteResponseDirective(WriteResponseDirective::kSendAttributeSuccess); +ScopedChangeOnly gCommandResponseDirective(CommandResponseDirective::kSendSuccessStatusCode); + +ScopedChangeOnly gIsLitIcd(false); + +uint16_t gInt16uTotalReadCount = 0; +CommandHandler::Handle gAsyncCommandHandle; + +} // namespace DataModelTests + +CHIP_ERROR ReadSingleClusterData(const Access::SubjectDescriptor & aSubjectDescriptor, bool aIsFabricFiltered, + const ConcreteReadAttributePath & aPath, AttributeReportIBs::Builder & aAttributeReports, + AttributeEncodeState * apEncoderState) +{ + if (aPath.mEndpointId >= chip::Test::kMockEndpointMin) + { + return chip::Test::ReadSingleMockClusterData(aSubjectDescriptor.fabricIndex, aPath, aAttributeReports, apEncoderState); + } + + if (gReadResponseDirective == ReadResponseDirective::kSendManyDataResponses || + gReadResponseDirective == ReadResponseDirective::kSendManyDataResponsesWrongPath) + { + if (aPath.mClusterId != Clusters::UnitTesting::Id || aPath.mAttributeId != Clusters::UnitTesting::Attributes::Boolean::Id) + { + return CHIP_ERROR_INCORRECT_STATE; + } + + for (size_t i = 0; i < 4; ++i) + { + ConcreteAttributePath path(aPath); + // Use an incorrect attribute id for some of the responses. + path.mAttributeId = static_cast( + path.mAttributeId + (i / 2) + (gReadResponseDirective == ReadResponseDirective::kSendManyDataResponsesWrongPath)); + AttributeEncodeState state(apEncoderState); + AttributeValueEncoder valueEncoder(aAttributeReports, aSubjectDescriptor, path, kDataVersion, aIsFabricFiltered, state); + ReturnErrorOnFailure(valueEncoder.Encode(true)); + } + + return CHIP_NO_ERROR; + } + + if (gReadResponseDirective == ReadResponseDirective::kSendDataResponse) + { + if (aPath.mClusterId == app::Clusters::UnitTesting::Id && + aPath.mAttributeId == app::Clusters::UnitTesting::Attributes::ListFabricScoped::Id) + { + AttributeEncodeState state(apEncoderState); + AttributeValueEncoder valueEncoder(aAttributeReports, aSubjectDescriptor, aPath, kDataVersion, aIsFabricFiltered, + state); + + return valueEncoder.EncodeList([aSubjectDescriptor](const auto & encoder) -> CHIP_ERROR { + app::Clusters::UnitTesting::Structs::TestFabricScoped::Type val; + val.fabricIndex = aSubjectDescriptor.fabricIndex; + ReturnErrorOnFailure(encoder.Encode(val)); + val.fabricIndex = (val.fabricIndex == 1) ? 2 : 1; + ReturnErrorOnFailure(encoder.Encode(val)); + return CHIP_NO_ERROR; + }); + } + if (aPath.mClusterId == app::Clusters::UnitTesting::Id && + aPath.mAttributeId == app::Clusters::UnitTesting::Attributes::Int16u::Id) + { + AttributeEncodeState state(apEncoderState); + AttributeValueEncoder valueEncoder(aAttributeReports, aSubjectDescriptor, aPath, kDataVersion, aIsFabricFiltered, + state); + + return valueEncoder.Encode(++gInt16uTotalReadCount); + } + if (aPath.mClusterId == kPerpetualClusterId || + (aPath.mClusterId == app::Clusters::UnitTesting::Id && aPath.mAttributeId == kPerpetualAttributeid)) + { + AttributeEncodeState state; + AttributeValueEncoder valueEncoder(aAttributeReports, aSubjectDescriptor, aPath, kDataVersion, aIsFabricFiltered, + state); + + CHIP_ERROR err = valueEncoder.EncodeList([](const auto & encoder) -> CHIP_ERROR { + encoder.Encode(static_cast(1)); + return CHIP_ERROR_NO_MEMORY; + }); + + if (err != CHIP_NO_ERROR) + { + // If the err is not CHIP_NO_ERROR, means the encoding was aborted, then the valueEncoder may save its state. + // The state is used by list chunking feature for now. + if (apEncoderState != nullptr) + { + *apEncoderState = valueEncoder.GetState(); + } + return err; + } + } + if (aPath.mClusterId == app::Clusters::IcdManagement::Id && + aPath.mAttributeId == app::Clusters::IcdManagement::Attributes::OperatingMode::Id) + { + AttributeEncodeState state(apEncoderState); + AttributeValueEncoder valueEncoder(aAttributeReports, aSubjectDescriptor, aPath, kDataVersion, aIsFabricFiltered, + state); + + return valueEncoder.Encode(gIsLitIcd ? Clusters::IcdManagement::OperatingModeEnum::kLit + : Clusters::IcdManagement::OperatingModeEnum::kSit); + } + + AttributeReportIB::Builder & attributeReport = aAttributeReports.CreateAttributeReport(); + ReturnErrorOnFailure(aAttributeReports.GetError()); + AttributeDataIB::Builder & attributeData = attributeReport.CreateAttributeData(); + ReturnErrorOnFailure(attributeReport.GetError()); + Clusters::UnitTesting::Attributes::ListStructOctetString::TypeInfo::Type value; + Clusters::UnitTesting::Structs::TestListStructOctet::Type valueBuf[4]; + + value = valueBuf; + + uint8_t i = 0; + for (auto & item : valueBuf) + { + item.member1 = i; + i++; + } + + attributeData.DataVersion(kDataVersion); + ReturnErrorOnFailure(attributeData.GetError()); + AttributePathIB::Builder & attributePath = attributeData.CreatePath(); + attributePath.Endpoint(aPath.mEndpointId).Cluster(aPath.mClusterId).Attribute(aPath.mAttributeId).EndOfAttributePathIB(); + ReturnErrorOnFailure(attributePath.GetError()); + + ReturnErrorOnFailure(DataModel::Encode(*(attributeData.GetWriter()), TLV::ContextTag(AttributeDataIB::Tag::kData), value)); + ReturnErrorOnFailure(attributeData.EndOfAttributeDataIB()); + return attributeReport.EndOfAttributeReportIB(); + } + + for (size_t i = 0; i < (gReadResponseDirective == ReadResponseDirective::kSendTwoDataErrors ? 2 : 1); ++i) + { + AttributeReportIB::Builder & attributeReport = aAttributeReports.CreateAttributeReport(); + ReturnErrorOnFailure(aAttributeReports.GetError()); + AttributeStatusIB::Builder & attributeStatus = attributeReport.CreateAttributeStatus(); + AttributePathIB::Builder & attributePath = attributeStatus.CreatePath(); + attributePath.Endpoint(aPath.mEndpointId).Cluster(aPath.mClusterId).Attribute(aPath.mAttributeId).EndOfAttributePathIB(); + ReturnErrorOnFailure(attributePath.GetError()); + + StatusIB::Builder & errorStatus = attributeStatus.CreateErrorStatus(); + ReturnErrorOnFailure(attributeStatus.GetError()); + errorStatus.EncodeStatusIB(StatusIB(Protocols::InteractionModel::Status::Busy)); + attributeStatus.EndOfAttributeStatusIB(); + ReturnErrorOnFailure(attributeStatus.GetError()); + ReturnErrorOnFailure(attributeReport.EndOfAttributeReportIB()); + } + + return CHIP_NO_ERROR; +} + +bool IsClusterDataVersionEqual(const app::ConcreteClusterPath & aConcreteClusterPath, DataVersion aRequiredVersion) +{ + if (aRequiredVersion == kDataVersion) + { + return true; + } + if (Test::GetVersion() == aRequiredVersion) + { + return true; + } + + return false; +} + +bool IsDeviceTypeOnEndpoint(DeviceTypeId deviceType, EndpointId endpoint) +{ + return false; +} + +bool ConcreteAttributePathExists(const ConcreteAttributePath & aPath) +{ + return true; +} + +Protocols::InteractionModel::Status CheckEventSupportStatus(const ConcreteEventPath & aPath) +{ + return Protocols::InteractionModel::Status::Success; +} + +const EmberAfAttributeMetadata * GetAttributeMetadata(const ConcreteAttributePath & aConcreteClusterPath) +{ + // Note: This test does not make use of the real attribute metadata. + static EmberAfAttributeMetadata stub = { .defaultValue = EmberAfDefaultOrMinMaxAttributeValue(uint32_t(0)) }; + return &stub; +} + +CHIP_ERROR WriteSingleClusterData(const Access::SubjectDescriptor & aSubjectDescriptor, const ConcreteDataAttributePath & aPath, + TLV::TLVReader & aReader, WriteHandler * aWriteHandler) +{ + static ListIndex listStructOctetStringElementCount = 0; + + if (aPath.mDataVersion.HasValue() && aPath.mDataVersion.Value() == kRejectedDataVersion) + { + return aWriteHandler->AddStatus(aPath, Protocols::InteractionModel::Status::DataVersionMismatch); + } + + if (aPath.mClusterId == Clusters::UnitTesting::Id && + aPath.mAttributeId == Attributes::ListStructOctetString::TypeInfo::GetAttributeId()) + { + if (gWriteResponseDirective == WriteResponseDirective::kSendAttributeSuccess) + { + if (!aPath.IsListOperation() || aPath.mListOp == ConcreteDataAttributePath::ListOperation::ReplaceAll) + { + + Attributes::ListStructOctetString::TypeInfo::DecodableType value; + + ReturnErrorOnFailure(DataModel::Decode(aReader, value)); + + auto iter = value.begin(); + listStructOctetStringElementCount = 0; + while (iter.Next()) + { + auto & item = iter.GetValue(); + + VerifyOrReturnError(item.member1 == listStructOctetStringElementCount, CHIP_ERROR_INVALID_ARGUMENT); + listStructOctetStringElementCount++; + } + + aWriteHandler->AddStatus(aPath, Protocols::InteractionModel::Status::Success); + } + else if (aPath.mListOp == ConcreteDataAttributePath::ListOperation::AppendItem) + { + Structs::TestListStructOctet::DecodableType item; + ReturnErrorOnFailure(DataModel::Decode(aReader, item)); + VerifyOrReturnError(item.member1 == listStructOctetStringElementCount, CHIP_ERROR_INVALID_ARGUMENT); + listStructOctetStringElementCount++; + + aWriteHandler->AddStatus(aPath, Protocols::InteractionModel::Status::Success); + } + else + { + return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; + } + } + else + { + aWriteHandler->AddStatus(aPath, Protocols::InteractionModel::Status::Failure); + } + + return CHIP_NO_ERROR; + } + if (aPath.mClusterId == Clusters::UnitTesting::Id && aPath.mAttributeId == Attributes::ListFabricScoped::Id) + { + // Mock a invalid SubjectDescriptor + AttributeValueDecoder decoder(aReader, Access::SubjectDescriptor()); + if (!aPath.IsListOperation() || aPath.mListOp == ConcreteDataAttributePath::ListOperation::ReplaceAll) + { + Attributes::ListFabricScoped::TypeInfo::DecodableType value; + + ReturnErrorOnFailure(decoder.Decode(value)); + + auto iter = value.begin(); + while (iter.Next()) + { + auto & item = iter.GetValue(); + (void) item; + } + + aWriteHandler->AddStatus(aPath, Protocols::InteractionModel::Status::Success); + } + else if (aPath.mListOp == ConcreteDataAttributePath::ListOperation::AppendItem) + { + Structs::TestFabricScoped::DecodableType item; + ReturnErrorOnFailure(decoder.Decode(item)); + + aWriteHandler->AddStatus(aPath, Protocols::InteractionModel::Status::Success); + } + else + { + return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; + } + return CHIP_NO_ERROR; + } + + // Boolean attribute of unit testing cluster triggers "multiple errors" case. + if (aPath.mClusterId == Clusters::UnitTesting::Id && aPath.mAttributeId == Attributes::Boolean::TypeInfo::GetAttributeId()) + { + InteractionModel::ClusterStatusCode status{ Protocols::InteractionModel::Status::InvalidValue }; + + if (gWriteResponseDirective == WriteResponseDirective::kSendMultipleSuccess) + { + status = InteractionModel::Status::Success; + } + else if (gWriteResponseDirective == WriteResponseDirective::kSendMultipleErrors) + { + status = InteractionModel::Status::Failure; + } + else + { + VerifyOrDie(false); + } + + for (size_t i = 0; i < 4; ++i) + { + aWriteHandler->AddStatus(aPath, status); + } + + return CHIP_NO_ERROR; + } + + if (aPath.mClusterId == Clusters::UnitTesting::Id && aPath.mAttributeId == Attributes::Int8u::TypeInfo::GetAttributeId()) + { + InteractionModel::ClusterStatusCode status{ Protocols::InteractionModel::Status::InvalidValue }; + if (gWriteResponseDirective == WriteResponseDirective::kSendClusterSpecificSuccess) + { + status = InteractionModel::ClusterStatusCode::ClusterSpecificSuccess(kExampleClusterSpecificSuccess); + } + else if (gWriteResponseDirective == WriteResponseDirective::kSendClusterSpecificFailure) + { + status = InteractionModel::ClusterStatusCode::ClusterSpecificFailure(kExampleClusterSpecificFailure); + } + else + { + VerifyOrDie(false); + } + + aWriteHandler->AddStatus(aPath, status); + return CHIP_NO_ERROR; + } + + return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; +} + +void DispatchSingleClusterCommand(const ConcreteCommandPath & aCommandPath, chip::TLV::TLVReader & aReader, + CommandHandler * apCommandObj) +{ + ChipLogDetail(Controller, "Received Cluster Command: Endpoint=%x Cluster=" ChipLogFormatMEI " Command=" ChipLogFormatMEI, + aCommandPath.mEndpointId, ChipLogValueMEI(aCommandPath.mClusterId), ChipLogValueMEI(aCommandPath.mCommandId)); + + if (aCommandPath.mClusterId == Clusters::UnitTesting::Id && + aCommandPath.mCommandId == Clusters::UnitTesting::Commands::TestSimpleArgumentRequest::Type::GetCommandId()) + { + Clusters::UnitTesting::Commands::TestSimpleArgumentRequest::DecodableType dataRequest; + + if (DataModel::Decode(aReader, dataRequest) != CHIP_NO_ERROR) + { + apCommandObj->AddStatus(aCommandPath, Protocols::InteractionModel::Status::Failure, "Unable to decode the request"); + return; + } + + if (gCommandResponseDirective == CommandResponseDirective::kSendDataResponse) + { + Clusters::UnitTesting::Commands::TestStructArrayArgumentResponse::Type dataResponse; + Clusters::UnitTesting::Structs::NestedStructList::Type nestedStructList[4]; + + uint8_t i = 0; + for (auto & item : nestedStructList) + { + item.a = i; + item.b = false; + item.c.a = i; + item.c.b = true; + i++; + } + + dataResponse.arg1 = nestedStructList; + dataResponse.arg6 = true; + + apCommandObj->AddResponse(aCommandPath, dataResponse); + } + else if (gCommandResponseDirective == CommandResponseDirective::kSendSuccessStatusCode) + { + apCommandObj->AddStatus(aCommandPath, Protocols::InteractionModel::Status::Success); + } + else if (gCommandResponseDirective == CommandResponseDirective::kSendMultipleSuccessStatusCodes) + { + apCommandObj->AddStatus(aCommandPath, Protocols::InteractionModel::Status::Success, + "No error but testing status success case"); + + // TODO: Right now all but the first AddStatus call fail, so this + // test is not really testing what it should. + for (size_t i = 0; i < 3; ++i) + { + (void) apCommandObj->FallibleAddStatus(aCommandPath, Protocols::InteractionModel::Status::Success, + "No error but testing status success case"); + } + // And one failure on the end. + (void) apCommandObj->FallibleAddStatus(aCommandPath, Protocols::InteractionModel::Status::Failure); + } + else if (gCommandResponseDirective == CommandResponseDirective::kSendError) + { + apCommandObj->AddStatus(aCommandPath, Protocols::InteractionModel::Status::Failure); + } + else if (gCommandResponseDirective == CommandResponseDirective::kSendMultipleErrors) + { + apCommandObj->AddStatus(aCommandPath, Protocols::InteractionModel::Status::Failure); + + // TODO: Right now all but the first AddStatus call fail, so this + // test is not really testing what it should. + for (size_t i = 0; i < 3; ++i) + { + (void) apCommandObj->FallibleAddStatus(aCommandPath, Protocols::InteractionModel::Status::Failure); + } + } + else if (gCommandResponseDirective == CommandResponseDirective::kSendSuccessStatusCodeWithClusterStatus) + { + apCommandObj->AddStatus( + aCommandPath, Protocols::InteractionModel::ClusterStatusCode::ClusterSpecificSuccess(kTestSuccessClusterStatus)); + } + else if (gCommandResponseDirective == CommandResponseDirective::kSendErrorWithClusterStatus) + { + apCommandObj->AddStatus( + aCommandPath, Protocols::InteractionModel::ClusterStatusCode::ClusterSpecificFailure(kTestFailureClusterStatus)); + } + else if (gCommandResponseDirective == CommandResponseDirective::kAsync) + { + gAsyncCommandHandle = apCommandObj; + } + } +} + +InteractionModel::Status ServerClusterCommandExists(const ConcreteCommandPath & aCommandPath) +{ + // Mock cluster catalog, only support commands on one cluster on one endpoint. + using InteractionModel::Status; + + if (aCommandPath.mEndpointId != kTestEndpointId) + { + return Status::UnsupportedEndpoint; + } + + if (aCommandPath.mClusterId != Clusters::UnitTesting::Id) + { + return Status::UnsupportedCluster; + } + + return Status::Success; +} + +} // namespace app +} // namespace chip diff --git a/src/controller/tests/data_model/DataModelFixtures.h b/src/controller/tests/data_model/DataModelFixtures.h new file mode 100644 index 00000000000000..dfdc60e5b59b06 --- /dev/null +++ b/src/controller/tests/data_model/DataModelFixtures.h @@ -0,0 +1,102 @@ +/* + * + * Copyright (c) 2024 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// This module provides shared fixture implementations of global functions +// for data model tests as well as global variables to control them. + +#pragma once + +#include +#include +#include +#include +#include + +namespace chip { +namespace app { +namespace DataModelTests { + +constexpr EndpointId kTestEndpointId = 1; + +constexpr ClusterId kPerpetualClusterId = Test::MockClusterId(2); +constexpr AttributeId kPerpetualAttributeid = Test::MockAttributeId(1); + +constexpr DataVersion kRejectedDataVersion = 1; +constexpr DataVersion kAcceptedDataVersion = 5; +constexpr DataVersion kDataVersion = kAcceptedDataVersion; + +constexpr uint8_t kExampleClusterSpecificSuccess = 11u; +constexpr uint8_t kExampleClusterSpecificFailure = 12u; + +constexpr ClusterStatus kTestSuccessClusterStatus = 1; +constexpr ClusterStatus kTestFailureClusterStatus = 2; + +// Controls how the fixture responds to attribute reads +enum class ReadResponseDirective +{ + kSendDataResponse, + kSendManyDataResponses, // Many data blocks, for a single concrete path + // read, simulating a malicious server. + kSendManyDataResponsesWrongPath, // Many data blocks, all using the wrong + // path, for a single concrete path + // read, simulating a malicious server. + kSendDataError, + kSendTwoDataErrors, // Multiple errors, for a single concrete path, + // simulating a malicious server. +}; +extern ScopedChangeOnly gReadResponseDirective; + +// Number of reads of Clusters::UnitTesting::Attributes::Int16u that we have observed. +// Every read will increment this count by 1 and return the new value. +extern uint16_t gInt16uTotalReadCount; + +// Controls the ICD operating mode for the fixture +extern ScopedChangeOnly gIsLitIcd; + +// Controls how the fixture responds to attribute writes +enum class WriteResponseDirective +{ + kSendAttributeSuccess, + kSendAttributeError, + kSendMultipleSuccess, + kSendMultipleErrors, + kSendClusterSpecificSuccess, + kSendClusterSpecificFailure, +}; +extern ScopedChangeOnly gWriteResponseDirective; + +// Controls how the fixture responds to commands +enum class CommandResponseDirective +{ + kSendDataResponse, + kSendSuccessStatusCode, + kSendMultipleSuccessStatusCodes, + kSendError, + kSendMultipleErrors, + kSendSuccessStatusCodeWithClusterStatus, + kSendErrorWithClusterStatus, + kAsync, +}; +extern ScopedChangeOnly gCommandResponseDirective; + +// Populated with the command handle when gCommandResponseDirective == kAsync +extern CommandHandler::Handle gAsyncCommandHandle; + +} // namespace DataModelTests +} // namespace app +} // namespace chip diff --git a/src/controller/tests/data_model/TestCommands.cpp b/src/controller/tests/data_model/TestCommands.cpp index 11b71415ad6ec5..2ccb98d5cf7e00 100644 --- a/src/controller/tests/data_model/TestCommands.cpp +++ b/src/controller/tests/data_model/TestCommands.cpp @@ -25,10 +25,12 @@ #include #include -#include "app/data-model/NullObject.h" +#include "DataModelFixtures.h" + #include #include #include +#include #include #include #include @@ -45,142 +47,9 @@ using TestContext = chip::Test::AppContext; using namespace chip; using namespace chip::app; using namespace chip::app::Clusters; +using namespace chip::app::DataModelTests; using namespace chip::Protocols; -namespace { -chip::ClusterStatus kTestSuccessClusterStatus = 1; -chip::ClusterStatus kTestFailureClusterStatus = 2; - -constexpr EndpointId kTestEndpointId = 1; - -enum ResponseDirective -{ - kSendDataResponse, - kSendSuccessStatusCode, - kSendMultipleSuccessStatusCodes, - kSendError, - kSendMultipleErrors, - kSendSuccessStatusCodeWithClusterStatus, - kSendErrorWithClusterStatus, - kAsync, -}; - -ResponseDirective responseDirective; -CommandHandler::Handle asyncHandle; - -} // namespace - -namespace chip { -namespace app { - -void DispatchSingleClusterCommand(const ConcreteCommandPath & aCommandPath, chip::TLV::TLVReader & aReader, - CommandHandler * apCommandObj) -{ - ChipLogDetail(Controller, "Received Cluster Command: Endpoint=%x Cluster=" ChipLogFormatMEI " Command=" ChipLogFormatMEI, - aCommandPath.mEndpointId, ChipLogValueMEI(aCommandPath.mClusterId), ChipLogValueMEI(aCommandPath.mCommandId)); - - if (aCommandPath.mClusterId == Clusters::UnitTesting::Id && - aCommandPath.mCommandId == Clusters::UnitTesting::Commands::TestSimpleArgumentRequest::Type::GetCommandId()) - { - Clusters::UnitTesting::Commands::TestSimpleArgumentRequest::DecodableType dataRequest; - - if (DataModel::Decode(aReader, dataRequest) != CHIP_NO_ERROR) - { - apCommandObj->AddStatus(aCommandPath, Protocols::InteractionModel::Status::Failure, "Unable to decode the request"); - return; - } - - if (responseDirective == kSendDataResponse) - { - Clusters::UnitTesting::Commands::TestStructArrayArgumentResponse::Type dataResponse; - Clusters::UnitTesting::Structs::NestedStructList::Type nestedStructList[4]; - - uint8_t i = 0; - for (auto & item : nestedStructList) - { - item.a = i; - item.b = false; - item.c.a = i; - item.c.b = true; - i++; - } - - dataResponse.arg1 = nestedStructList; - dataResponse.arg6 = true; - - apCommandObj->AddResponse(aCommandPath, dataResponse); - } - else if (responseDirective == kSendSuccessStatusCode) - { - apCommandObj->AddStatus(aCommandPath, Protocols::InteractionModel::Status::Success); - } - else if (responseDirective == kSendMultipleSuccessStatusCodes) - { - apCommandObj->AddStatus(aCommandPath, Protocols::InteractionModel::Status::Success, - "No error but testing status success case"); - - // TODO: Right now all but the first AddStatus call fail, so this - // test is not really testing what it should. - for (size_t i = 0; i < 3; ++i) - { - (void) apCommandObj->FallibleAddStatus(aCommandPath, Protocols::InteractionModel::Status::Success, - "No error but testing status success case"); - } - // And one failure on the end. - (void) apCommandObj->FallibleAddStatus(aCommandPath, Protocols::InteractionModel::Status::Failure); - } - else if (responseDirective == kSendError) - { - apCommandObj->AddStatus(aCommandPath, Protocols::InteractionModel::Status::Failure); - } - else if (responseDirective == kSendMultipleErrors) - { - apCommandObj->AddStatus(aCommandPath, Protocols::InteractionModel::Status::Failure); - - // TODO: Right now all but the first AddStatus call fail, so this - // test is not really testing what it should. - for (size_t i = 0; i < 3; ++i) - { - (void) apCommandObj->FallibleAddStatus(aCommandPath, Protocols::InteractionModel::Status::Failure); - } - } - else if (responseDirective == kSendSuccessStatusCodeWithClusterStatus) - { - apCommandObj->AddStatus( - aCommandPath, Protocols::InteractionModel::ClusterStatusCode::ClusterSpecificSuccess(kTestSuccessClusterStatus)); - } - else if (responseDirective == kSendErrorWithClusterStatus) - { - apCommandObj->AddStatus( - aCommandPath, Protocols::InteractionModel::ClusterStatusCode::ClusterSpecificFailure(kTestFailureClusterStatus)); - } - else if (responseDirective == kAsync) - { - asyncHandle = apCommandObj; - } - } -} - -InteractionModel::Status ServerClusterCommandExists(const ConcreteCommandPath & aCommandPath) -{ - // Mock cluster catalog, only support commands on one cluster on one endpoint. - using InteractionModel::Status; - - if (aCommandPath.mEndpointId != kTestEndpointId) - { - return Status::UnsupportedEndpoint; - } - - if (aCommandPath.mClusterId != Clusters::UnitTesting::Id) - { - return Status::UnsupportedCluster; - } - - return Status::Success; -} -} // namespace app -} // namespace chip - namespace { class TestCommands : public ::testing::Test @@ -257,7 +126,7 @@ TEST_F(TestCommands, TestDataResponse) // not safe to do so. auto onFailureCb = [&onFailureWasCalled](CHIP_ERROR aError) { onFailureWasCalled = true; }; - responseDirective = kSendDataResponse; + ScopedChange directive(gCommandResponseDirective, CommandResponseDirective::kSendDataResponse); chip::Controller::InvokeCommandRequest(&mpContext->GetExchangeManager(), sessionHandle, kTestEndpointId, request, onSuccessCb, onFailureCb); @@ -295,7 +164,7 @@ TEST_F(TestCommands, TestSuccessNoDataResponse) // not safe to do so. auto onFailureCb = [&onFailureWasCalled](CHIP_ERROR aError) { onFailureWasCalled = true; }; - responseDirective = kSendSuccessStatusCode; + ScopedChange directive(gCommandResponseDirective, CommandResponseDirective::kSendSuccessStatusCode); chip::Controller::InvokeCommandRequest(&mpContext->GetExchangeManager(), sessionHandle, kTestEndpointId, request, onSuccessCb, onFailureCb); @@ -333,7 +202,7 @@ TEST_F(TestCommands, TestMultipleSuccessNoDataResponses) // not safe to do so. auto onFailureCb = [&failureCalls](CHIP_ERROR aError) { ++failureCalls; }; - responseDirective = kSendMultipleSuccessStatusCodes; + ScopedChange directive(gCommandResponseDirective, CommandResponseDirective::kSendMultipleSuccessStatusCodes); Controller::InvokeCommandRequest(&mpContext->GetExchangeManager(), sessionHandle, kTestEndpointId, request, onSuccessCb, onFailureCb); @@ -372,7 +241,7 @@ TEST_F(TestCommands, TestAsyncResponse) // not safe to do so. auto onFailureCb = [&onFailureWasCalled](CHIP_ERROR aError) { onFailureWasCalled = true; }; - responseDirective = kAsync; + ScopedChange directive(gCommandResponseDirective, CommandResponseDirective::kAsync); chip::Controller::InvokeCommandRequest(&mpContext->GetExchangeManager(), sessionHandle, kTestEndpointId, request, onSuccessCb, onFailureCb); @@ -382,12 +251,12 @@ TEST_F(TestCommands, TestAsyncResponse) EXPECT_TRUE(!onSuccessWasCalled && !onFailureWasCalled && !statusCheck); EXPECT_EQ(mpContext->GetExchangeManager().GetNumActiveExchanges(), 2u); - CommandHandler * commandHandle = asyncHandle.Get(); + CommandHandler * commandHandle = gAsyncCommandHandle.Get(); ASSERT_NE(commandHandle, nullptr); commandHandle->AddStatus(ConcreteCommandPath(kTestEndpointId, request.GetClusterId(), request.GetCommandId()), Protocols::InteractionModel::Status::Success); - asyncHandle.Release(); + gAsyncCommandHandle.Release(); mpContext->DrainAndServiceIO(); @@ -417,7 +286,7 @@ TEST_F(TestCommands, TestFailure) onFailureWasCalled = true; }; - responseDirective = kSendError; + ScopedChange directive(gCommandResponseDirective, CommandResponseDirective::kSendError); chip::Controller::InvokeCommandRequest(&mpContext->GetExchangeManager(), sessionHandle, kTestEndpointId, request, onSuccessCb, onFailureCb); @@ -455,7 +324,7 @@ TEST_F(TestCommands, TestMultipleFailures) ++failureCalls; }; - responseDirective = kSendMultipleErrors; + ScopedChange directive(gCommandResponseDirective, CommandResponseDirective::kSendMultipleErrors); Controller::InvokeCommandRequest(&mpContext->GetExchangeManager(), sessionHandle, kTestEndpointId, request, onSuccessCb, onFailureCb); @@ -495,7 +364,7 @@ TEST_F(TestCommands, TestSuccessNoDataResponseWithClusterStatus) // not safe to do so. auto onFailureCb = [&onFailureWasCalled](CHIP_ERROR aError) { onFailureWasCalled = true; }; - responseDirective = kSendSuccessStatusCodeWithClusterStatus; + ScopedChange directive(gCommandResponseDirective, CommandResponseDirective::kSendSuccessStatusCodeWithClusterStatus); chip::Controller::InvokeCommandRequest(&mpContext->GetExchangeManager(), sessionHandle, kTestEndpointId, request, onSuccessCb, onFailureCb); @@ -534,7 +403,7 @@ TEST_F(TestCommands, TestFailureWithClusterStatus) onFailureWasCalled = true; }; - responseDirective = kSendErrorWithClusterStatus; + ScopedChange directive(gCommandResponseDirective, CommandResponseDirective::kSendErrorWithClusterStatus); chip::Controller::InvokeCommandRequest(&mpContext->GetExchangeManager(), sessionHandle, kTestEndpointId, request, onSuccessCb, onFailureCb); diff --git a/src/controller/tests/data_model/TestRead.cpp b/src/controller/tests/data_model/TestRead.cpp index 906ba82a213042..954ff5044418d4 100644 --- a/src/controller/tests/data_model/TestRead.cpp +++ b/src/controller/tests/data_model/TestRead.cpp @@ -19,8 +19,8 @@ #include #include -#include "system/SystemClock.h" -#include "transport/SecureSession.h" +#include "DataModelFixtures.h" + #include #include #include @@ -35,228 +35,17 @@ #include #include #include +#include +#include using TestContext = chip::Test::AppContext; using namespace chip; using namespace chip::app; using namespace chip::app::Clusters; +using namespace chip::app::DataModelTests; using namespace chip::Protocols; - -namespace { - -constexpr EndpointId kTestEndpointId = 1; -constexpr DataVersion kDataVersion = 5; -constexpr AttributeId kPerpetualAttributeid = chip::Test::MockAttributeId(1); -constexpr ClusterId kPerpetualClusterId = chip::Test::MockClusterId(2); -bool expectedAttribute1 = true; -int16_t expectedAttribute2 = 42; -uint64_t expectedAttribute3 = 0xdeadbeef0000cafe; -uint8_t expectedAttribute4[256] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, -}; - -enum ResponseDirective -{ - kSendDataResponse, - kSendManyDataResponses, // Many data blocks, for a single concrete path - // read, simulating a malicious server. - kSendManyDataResponsesWrongPath, // Many data blocks, all using the wrong - // path, for a single concrete path - // read, simulating a malicious server. - kSendDataError, - kSendTwoDataErrors, // Multiple errors, for a single concrete path, - // simulating a malicious server. -}; - -ResponseDirective responseDirective; - -// Number of reads of Clusters::UnitTesting::Attributes::Int16u that we have observed. -// Every read will increment this count by 1 and return the new value. -uint16_t totalReadCount = 0; - -bool isLitIcd = false; - -} // namespace - -namespace chip { -namespace app { -CHIP_ERROR ReadSingleClusterData(const Access::SubjectDescriptor & aSubjectDescriptor, bool aIsFabricFiltered, - const ConcreteReadAttributePath & aPath, AttributeReportIBs::Builder & aAttributeReports, - AttributeEncodeState * apEncoderState) -{ - if (aPath.mEndpointId >= chip::Test::kMockEndpointMin) - { - return chip::Test::ReadSingleMockClusterData(aSubjectDescriptor.fabricIndex, aPath, aAttributeReports, apEncoderState); - } - - if (responseDirective == kSendManyDataResponses || responseDirective == kSendManyDataResponsesWrongPath) - { - if (aPath.mClusterId != Clusters::UnitTesting::Id || aPath.mAttributeId != Clusters::UnitTesting::Attributes::Boolean::Id) - { - return CHIP_ERROR_INCORRECT_STATE; - } - - for (size_t i = 0; i < 4; ++i) - { - ConcreteAttributePath path(aPath); - // Use an incorrect attribute id for some of the responses. - path.mAttributeId = - static_cast(path.mAttributeId + (i / 2) + (responseDirective == kSendManyDataResponsesWrongPath)); - AttributeEncodeState state(apEncoderState); - AttributeValueEncoder valueEncoder(aAttributeReports, aSubjectDescriptor, path, kDataVersion, aIsFabricFiltered, state); - ReturnErrorOnFailure(valueEncoder.Encode(true)); - } - - return CHIP_NO_ERROR; - } - - if (responseDirective == kSendDataResponse) - { - if (aPath.mClusterId == app::Clusters::UnitTesting::Id && - aPath.mAttributeId == app::Clusters::UnitTesting::Attributes::ListFabricScoped::Id) - { - AttributeEncodeState state(apEncoderState); - AttributeValueEncoder valueEncoder(aAttributeReports, aSubjectDescriptor, aPath, kDataVersion, aIsFabricFiltered, - state); - - return valueEncoder.EncodeList([aSubjectDescriptor](const auto & encoder) -> CHIP_ERROR { - app::Clusters::UnitTesting::Structs::TestFabricScoped::Type val; - val.fabricIndex = aSubjectDescriptor.fabricIndex; - ReturnErrorOnFailure(encoder.Encode(val)); - val.fabricIndex = (val.fabricIndex == 1) ? 2 : 1; - ReturnErrorOnFailure(encoder.Encode(val)); - return CHIP_NO_ERROR; - }); - } - if (aPath.mClusterId == app::Clusters::UnitTesting::Id && - aPath.mAttributeId == app::Clusters::UnitTesting::Attributes::Int16u::Id) - { - AttributeEncodeState state(apEncoderState); - AttributeValueEncoder valueEncoder(aAttributeReports, aSubjectDescriptor, aPath, kDataVersion, aIsFabricFiltered, - state); - - return valueEncoder.Encode(++totalReadCount); - } - if (aPath.mClusterId == kPerpetualClusterId || - (aPath.mClusterId == app::Clusters::UnitTesting::Id && aPath.mAttributeId == kPerpetualAttributeid)) - { - AttributeEncodeState state; - AttributeValueEncoder valueEncoder(aAttributeReports, aSubjectDescriptor, aPath, kDataVersion, aIsFabricFiltered, - state); - - CHIP_ERROR err = valueEncoder.EncodeList([](const auto & encoder) -> CHIP_ERROR { - encoder.Encode(static_cast(1)); - return CHIP_ERROR_NO_MEMORY; - }); - - if (err != CHIP_NO_ERROR) - { - // If the err is not CHIP_NO_ERROR, means the encoding was aborted, then the valueEncoder may save its state. - // The state is used by list chunking feature for now. - if (apEncoderState != nullptr) - { - *apEncoderState = valueEncoder.GetState(); - } - return err; - } - } - if (aPath.mClusterId == app::Clusters::IcdManagement::Id && - aPath.mAttributeId == app::Clusters::IcdManagement::Attributes::OperatingMode::Id) - { - AttributeEncodeState state(apEncoderState); - AttributeValueEncoder valueEncoder(aAttributeReports, aSubjectDescriptor, aPath, kDataVersion, aIsFabricFiltered, - state); - - return valueEncoder.Encode(isLitIcd ? Clusters::IcdManagement::OperatingModeEnum::kLit - : Clusters::IcdManagement::OperatingModeEnum::kSit); - } - - AttributeReportIB::Builder & attributeReport = aAttributeReports.CreateAttributeReport(); - ReturnErrorOnFailure(aAttributeReports.GetError()); - AttributeDataIB::Builder & attributeData = attributeReport.CreateAttributeData(); - ReturnErrorOnFailure(attributeReport.GetError()); - Clusters::UnitTesting::Attributes::ListStructOctetString::TypeInfo::Type value; - Clusters::UnitTesting::Structs::TestListStructOctet::Type valueBuf[4]; - - value = valueBuf; - - uint8_t i = 0; - for (auto & item : valueBuf) - { - item.member1 = i; - i++; - } - - attributeData.DataVersion(kDataVersion); - ReturnErrorOnFailure(attributeData.GetError()); - AttributePathIB::Builder & attributePath = attributeData.CreatePath(); - attributePath.Endpoint(aPath.mEndpointId).Cluster(aPath.mClusterId).Attribute(aPath.mAttributeId).EndOfAttributePathIB(); - ReturnErrorOnFailure(attributePath.GetError()); - - ReturnErrorOnFailure(DataModel::Encode(*(attributeData.GetWriter()), TLV::ContextTag(AttributeDataIB::Tag::kData), value)); - ReturnErrorOnFailure(attributeData.EndOfAttributeDataIB()); - return attributeReport.EndOfAttributeReportIB(); - } - - for (size_t i = 0; i < (responseDirective == kSendTwoDataErrors ? 2 : 1); ++i) - { - AttributeReportIB::Builder & attributeReport = aAttributeReports.CreateAttributeReport(); - ReturnErrorOnFailure(aAttributeReports.GetError()); - AttributeStatusIB::Builder & attributeStatus = attributeReport.CreateAttributeStatus(); - AttributePathIB::Builder & attributePath = attributeStatus.CreatePath(); - attributePath.Endpoint(aPath.mEndpointId).Cluster(aPath.mClusterId).Attribute(aPath.mAttributeId).EndOfAttributePathIB(); - ReturnErrorOnFailure(attributePath.GetError()); - - StatusIB::Builder & errorStatus = attributeStatus.CreateErrorStatus(); - ReturnErrorOnFailure(attributeStatus.GetError()); - errorStatus.EncodeStatusIB(StatusIB(Protocols::InteractionModel::Status::Busy)); - attributeStatus.EndOfAttributeStatusIB(); - ReturnErrorOnFailure(attributeStatus.GetError()); - ReturnErrorOnFailure(attributeReport.EndOfAttributeReportIB()); - } - - return CHIP_NO_ERROR; -} - -bool IsClusterDataVersionEqual(const app::ConcreteClusterPath & aConcreteClusterPath, DataVersion aRequiredVersion) -{ - if (aRequiredVersion == kDataVersion) - { - return true; - } - if (Test::GetVersion() == aRequiredVersion) - { - return true; - } - - return false; -} - -bool IsDeviceTypeOnEndpoint(DeviceTypeId deviceType, EndpointId endpoint) -{ - return false; -} - -bool ConcreteAttributePathExists(const ConcreteAttributePath & aPath) -{ - return true; -} - -Protocols::InteractionModel::Status CheckEventSupportStatus(const ConcreteEventPath & aPath) -{ - return Protocols::InteractionModel::Status::Success; -} - -} // namespace app -} // namespace chip +using namespace chip::Test; namespace { @@ -390,7 +179,7 @@ TEST_F(TestRead, TestReadAttributeResponse) auto sessionHandle = mpContext->GetSessionBobToAlice(); bool onSuccessCbInvoked = false, onFailureCbInvoked = false; - responseDirective = kSendDataResponse; + ScopedChange directive(gReadResponseDirective, ReadResponseDirective::kSendDataResponse); // Passing of stack variables by reference is only safe because of synchronous completion of the interaction. Otherwise, it's // not safe to do so. @@ -430,8 +219,8 @@ TEST_F(TestRead, TestReadAttributeResponse) // `EXPECT_TRUE(version1.HasValue() && (version1.Value() == 0))`. TEST_F(TestRead, TestReadSubscribeAttributeResponseWithVersionOnlyCache) { - CHIP_ERROR err = CHIP_NO_ERROR; - responseDirective = kSendDataResponse; + CHIP_ERROR err = CHIP_NO_ERROR; + ScopedChange directive(gReadResponseDirective, ReadResponseDirective::kSendDataResponse); MockInteractionModelApp delegate; chip::app::ClusterStateCache cache(delegate, Optional::Missing(), false /*cachedData*/); @@ -502,8 +291,8 @@ TEST_F(TestRead, TestReadSubscribeAttributeResponseWithVersionOnlyCache) TEST_F(TestRead, TestReadSubscribeAttributeResponseWithCache) { - CHIP_ERROR err = CHIP_NO_ERROR; - responseDirective = kSendDataResponse; + CHIP_ERROR err = CHIP_NO_ERROR; + ScopedChange directive(gReadResponseDirective, ReadResponseDirective::kSendDataResponse); MockInteractionModelApp delegate; chip::app::ClusterStateCache cache(delegate); @@ -606,7 +395,7 @@ TEST_F(TestRead, TestReadSubscribeAttributeResponseWithCache) EXPECT_EQ(cache.Get(attributePath, reader), CHIP_NO_ERROR); bool receivedAttribute1; reader.Get(receivedAttribute1); - EXPECT_EQ(receivedAttribute1, expectedAttribute1); + EXPECT_EQ(receivedAttribute1, mockAttribute1); } { @@ -616,7 +405,7 @@ TEST_F(TestRead, TestReadSubscribeAttributeResponseWithCache) EXPECT_EQ(cache.Get(attributePath, reader), CHIP_NO_ERROR); int16_t receivedAttribute2; reader.Get(receivedAttribute2); - EXPECT_EQ(receivedAttribute2, expectedAttribute2); + EXPECT_EQ(receivedAttribute2, mockAttribute2); } { @@ -626,7 +415,7 @@ TEST_F(TestRead, TestReadSubscribeAttributeResponseWithCache) EXPECT_EQ(cache.Get(attributePath, reader), CHIP_NO_ERROR); int16_t receivedAttribute2; reader.Get(receivedAttribute2); - EXPECT_EQ(receivedAttribute2, expectedAttribute2); + EXPECT_EQ(receivedAttribute2, mockAttribute2); } delegate.mNumAttributeResponse = 0; @@ -684,7 +473,7 @@ TEST_F(TestRead, TestReadSubscribeAttributeResponseWithCache) EXPECT_EQ(cache.Get(attributePath, reader), CHIP_NO_ERROR); int16_t receivedAttribute2; reader.Get(receivedAttribute2); - EXPECT_EQ(receivedAttribute2, expectedAttribute2); + EXPECT_EQ(receivedAttribute2, mockAttribute2); } { @@ -694,7 +483,7 @@ TEST_F(TestRead, TestReadSubscribeAttributeResponseWithCache) EXPECT_EQ(cache.Get(attributePath, reader), CHIP_NO_ERROR); int16_t receivedAttribute2; reader.Get(receivedAttribute2); - EXPECT_EQ(receivedAttribute2, expectedAttribute2); + EXPECT_EQ(receivedAttribute2, mockAttribute2); } delegate.mNumAttributeResponse = 0; } @@ -739,7 +528,7 @@ TEST_F(TestRead, TestReadSubscribeAttributeResponseWithCache) EXPECT_EQ(cache.Get(attributePath, reader), CHIP_NO_ERROR); bool receivedAttribute1; reader.Get(receivedAttribute1); - EXPECT_EQ(receivedAttribute1, expectedAttribute1); + EXPECT_EQ(receivedAttribute1, mockAttribute1); } { @@ -749,7 +538,7 @@ TEST_F(TestRead, TestReadSubscribeAttributeResponseWithCache) EXPECT_EQ(cache.Get(attributePath, reader), CHIP_NO_ERROR); int16_t receivedAttribute2; reader.Get(receivedAttribute2); - EXPECT_EQ(receivedAttribute2, expectedAttribute2); + EXPECT_EQ(receivedAttribute2, mockAttribute2); } { @@ -759,7 +548,7 @@ TEST_F(TestRead, TestReadSubscribeAttributeResponseWithCache) EXPECT_EQ(cache.Get(attributePath, reader), CHIP_NO_ERROR); uint64_t receivedAttribute3; reader.Get(receivedAttribute3); - EXPECT_EQ(receivedAttribute3, expectedAttribute3); + EXPECT_EQ(receivedAttribute3, mockAttribute3); } { @@ -769,7 +558,7 @@ TEST_F(TestRead, TestReadSubscribeAttributeResponseWithCache) EXPECT_EQ(cache.Get(attributePath, reader), CHIP_NO_ERROR); int16_t receivedAttribute2; reader.Get(receivedAttribute2); - EXPECT_EQ(receivedAttribute2, expectedAttribute2); + EXPECT_EQ(receivedAttribute2, mockAttribute2); } delegate.mNumAttributeResponse = 0; } @@ -818,7 +607,7 @@ TEST_F(TestRead, TestReadSubscribeAttributeResponseWithCache) EXPECT_EQ(cache.Get(attributePath, reader), CHIP_NO_ERROR); bool receivedAttribute1; reader.Get(receivedAttribute1); - EXPECT_EQ(receivedAttribute1, expectedAttribute1); + EXPECT_EQ(receivedAttribute1, mockAttribute1); } { @@ -828,7 +617,7 @@ TEST_F(TestRead, TestReadSubscribeAttributeResponseWithCache) EXPECT_EQ(cache.Get(attributePath, reader), CHIP_NO_ERROR); int16_t receivedAttribute2; reader.Get(receivedAttribute2); - EXPECT_EQ(receivedAttribute2, expectedAttribute2); + EXPECT_EQ(receivedAttribute2, mockAttribute2); } { @@ -838,7 +627,7 @@ TEST_F(TestRead, TestReadSubscribeAttributeResponseWithCache) EXPECT_EQ(cache.Get(attributePath, reader), CHIP_NO_ERROR); int16_t receivedAttribute2; reader.Get(receivedAttribute2); - EXPECT_EQ(receivedAttribute2, expectedAttribute2); + EXPECT_EQ(receivedAttribute2, mockAttribute2); } delegate.mNumAttributeResponse = 0; } @@ -882,7 +671,7 @@ TEST_F(TestRead, TestReadSubscribeAttributeResponseWithCache) EXPECT_EQ(cache.Get(attributePath, reader), CHIP_NO_ERROR); bool receivedAttribute1; reader.Get(receivedAttribute1); - EXPECT_EQ(receivedAttribute1, expectedAttribute1); + EXPECT_EQ(receivedAttribute1, mockAttribute1); } { @@ -892,7 +681,7 @@ TEST_F(TestRead, TestReadSubscribeAttributeResponseWithCache) EXPECT_EQ(cache.Get(attributePath, reader), CHIP_NO_ERROR); int16_t receivedAttribute2; reader.Get(receivedAttribute2); - EXPECT_EQ(receivedAttribute2, expectedAttribute2); + EXPECT_EQ(receivedAttribute2, mockAttribute2); } { @@ -902,7 +691,7 @@ TEST_F(TestRead, TestReadSubscribeAttributeResponseWithCache) EXPECT_EQ(cache.Get(attributePath, reader), CHIP_NO_ERROR); uint64_t receivedAttribute3; reader.Get(receivedAttribute3); - EXPECT_EQ(receivedAttribute3, expectedAttribute3); + EXPECT_EQ(receivedAttribute3, mockAttribute3); } { @@ -912,7 +701,7 @@ TEST_F(TestRead, TestReadSubscribeAttributeResponseWithCache) EXPECT_EQ(cache.Get(attributePath, reader), CHIP_NO_ERROR); int16_t receivedAttribute2; reader.Get(receivedAttribute2); - EXPECT_EQ(receivedAttribute2, expectedAttribute2); + EXPECT_EQ(receivedAttribute2, mockAttribute2); } delegate.mNumAttributeResponse = 0; } @@ -964,7 +753,7 @@ TEST_F(TestRead, TestReadSubscribeAttributeResponseWithCache) EXPECT_EQ(cache.Get(attributePath, reader), CHIP_NO_ERROR); bool receivedAttribute1; reader.Get(receivedAttribute1); - EXPECT_EQ(receivedAttribute1, expectedAttribute1); + EXPECT_EQ(receivedAttribute1, mockAttribute1); } { @@ -974,7 +763,7 @@ TEST_F(TestRead, TestReadSubscribeAttributeResponseWithCache) EXPECT_EQ(cache.Get(attributePath, reader), CHIP_NO_ERROR); int16_t receivedAttribute2; reader.Get(receivedAttribute2); - EXPECT_EQ(receivedAttribute2, expectedAttribute2); + EXPECT_EQ(receivedAttribute2, mockAttribute2); } { @@ -984,7 +773,7 @@ TEST_F(TestRead, TestReadSubscribeAttributeResponseWithCache) EXPECT_EQ(cache.Get(attributePath, reader), CHIP_NO_ERROR); int16_t receivedAttribute2; reader.Get(receivedAttribute2); - EXPECT_EQ(receivedAttribute2, expectedAttribute2); + EXPECT_EQ(receivedAttribute2, mockAttribute2); } delegate.mNumAttributeResponse = 0; } @@ -1033,7 +822,7 @@ TEST_F(TestRead, TestReadSubscribeAttributeResponseWithCache) EXPECT_EQ(cache.Get(attributePath, reader), CHIP_NO_ERROR); bool receivedAttribute1; reader.Get(receivedAttribute1); - EXPECT_EQ(receivedAttribute1, expectedAttribute1); + EXPECT_EQ(receivedAttribute1, mockAttribute1); } { @@ -1043,7 +832,7 @@ TEST_F(TestRead, TestReadSubscribeAttributeResponseWithCache) EXPECT_EQ(cache.Get(attributePath, reader), CHIP_NO_ERROR); int16_t receivedAttribute2; reader.Get(receivedAttribute2); - EXPECT_EQ(receivedAttribute2, expectedAttribute2); + EXPECT_EQ(receivedAttribute2, mockAttribute2); } { @@ -1053,7 +842,7 @@ TEST_F(TestRead, TestReadSubscribeAttributeResponseWithCache) EXPECT_EQ(cache.Get(attributePath, reader), CHIP_NO_ERROR); int16_t receivedAttribute2; reader.Get(receivedAttribute2); - EXPECT_EQ(receivedAttribute2, expectedAttribute2); + EXPECT_EQ(receivedAttribute2, mockAttribute2); } delegate.mNumAttributeResponse = 0; } @@ -1097,7 +886,7 @@ TEST_F(TestRead, TestReadSubscribeAttributeResponseWithCache) EXPECT_EQ(cache.Get(attributePath, reader), CHIP_NO_ERROR); bool receivedAttribute1; reader.Get(receivedAttribute1); - EXPECT_EQ(receivedAttribute1, expectedAttribute1); + EXPECT_EQ(receivedAttribute1, mockAttribute1); } { @@ -1107,7 +896,7 @@ TEST_F(TestRead, TestReadSubscribeAttributeResponseWithCache) EXPECT_EQ(cache.Get(attributePath, reader), CHIP_NO_ERROR); int16_t receivedAttribute2; reader.Get(receivedAttribute2); - EXPECT_EQ(receivedAttribute2, expectedAttribute2); + EXPECT_EQ(receivedAttribute2, mockAttribute2); } { @@ -1117,7 +906,7 @@ TEST_F(TestRead, TestReadSubscribeAttributeResponseWithCache) EXPECT_EQ(cache.Get(attributePath, reader), CHIP_NO_ERROR); uint64_t receivedAttribute3; reader.Get(receivedAttribute3); - EXPECT_EQ(receivedAttribute3, expectedAttribute3); + EXPECT_EQ(receivedAttribute3, mockAttribute3); } { @@ -1127,7 +916,7 @@ TEST_F(TestRead, TestReadSubscribeAttributeResponseWithCache) EXPECT_EQ(cache.Get(attributePath, reader), CHIP_NO_ERROR); int16_t receivedAttribute2; reader.Get(receivedAttribute2); - EXPECT_EQ(receivedAttribute2, expectedAttribute2); + EXPECT_EQ(receivedAttribute2, mockAttribute2); } delegate.mNumAttributeResponse = 0; } @@ -1180,7 +969,7 @@ TEST_F(TestRead, TestReadSubscribeAttributeResponseWithCache) EXPECT_EQ(cache.Get(attributePath, reader), CHIP_NO_ERROR); bool receivedAttribute1; reader.Get(receivedAttribute1); - EXPECT_EQ(receivedAttribute1, expectedAttribute1); + EXPECT_EQ(receivedAttribute1, mockAttribute1); } { @@ -1190,7 +979,7 @@ TEST_F(TestRead, TestReadSubscribeAttributeResponseWithCache) EXPECT_EQ(cache.Get(attributePath, reader), CHIP_NO_ERROR); int16_t receivedAttribute2; reader.Get(receivedAttribute2); - EXPECT_EQ(receivedAttribute2, expectedAttribute2); + EXPECT_EQ(receivedAttribute2, mockAttribute2); } { @@ -1200,7 +989,7 @@ TEST_F(TestRead, TestReadSubscribeAttributeResponseWithCache) EXPECT_EQ(cache.Get(attributePath, reader), CHIP_NO_ERROR); uint64_t receivedAttribute3; reader.Get(receivedAttribute3); - EXPECT_EQ(receivedAttribute3, expectedAttribute3); + EXPECT_EQ(receivedAttribute3, mockAttribute3); } { @@ -1210,7 +999,7 @@ TEST_F(TestRead, TestReadSubscribeAttributeResponseWithCache) EXPECT_EQ(cache.Get(attributePath, reader), CHIP_NO_ERROR); int16_t receivedAttribute2; reader.Get(receivedAttribute2); - EXPECT_EQ(receivedAttribute2, expectedAttribute2); + EXPECT_EQ(receivedAttribute2, mockAttribute2); } delegate.mNumAttributeResponse = 0; readPrepareParams.mpEventPathParamsList = nullptr; @@ -1269,7 +1058,7 @@ TEST_F(TestRead, TestReadSubscribeAttributeResponseWithCache) EXPECT_EQ(cache.Get(attributePath, reader), CHIP_NO_ERROR); bool receivedAttribute1; reader.Get(receivedAttribute1); - EXPECT_EQ(receivedAttribute1, expectedAttribute1); + EXPECT_EQ(receivedAttribute1, mockAttribute1); } { @@ -1279,7 +1068,7 @@ TEST_F(TestRead, TestReadSubscribeAttributeResponseWithCache) EXPECT_EQ(cache.Get(attributePath, reader), CHIP_NO_ERROR); bool receivedAttribute1; reader.Get(receivedAttribute1); - EXPECT_EQ(receivedAttribute1, expectedAttribute1); + EXPECT_EQ(receivedAttribute1, mockAttribute1); } { @@ -1289,7 +1078,7 @@ TEST_F(TestRead, TestReadSubscribeAttributeResponseWithCache) EXPECT_EQ(cache.Get(attributePath, reader), CHIP_NO_ERROR); int16_t receivedAttribute2; reader.Get(receivedAttribute2); - EXPECT_EQ(receivedAttribute2, expectedAttribute2); + EXPECT_EQ(receivedAttribute2, mockAttribute2); } { @@ -1299,7 +1088,7 @@ TEST_F(TestRead, TestReadSubscribeAttributeResponseWithCache) EXPECT_EQ(cache.Get(attributePath, reader), CHIP_NO_ERROR); uint64_t receivedAttribute3; reader.Get(receivedAttribute3); - EXPECT_EQ(receivedAttribute3, expectedAttribute3); + EXPECT_EQ(receivedAttribute3, mockAttribute3); } { @@ -1309,7 +1098,7 @@ TEST_F(TestRead, TestReadSubscribeAttributeResponseWithCache) EXPECT_EQ(cache.Get(attributePath, reader), CHIP_NO_ERROR); bool receivedAttribute1; reader.Get(receivedAttribute1); - EXPECT_EQ(receivedAttribute1, expectedAttribute1); + EXPECT_EQ(receivedAttribute1, mockAttribute1); } { app::ConcreteAttributePath attributePath(chip::Test::kMockEndpoint2, chip::Test::MockClusterId(2), @@ -1318,7 +1107,7 @@ TEST_F(TestRead, TestReadSubscribeAttributeResponseWithCache) EXPECT_EQ(cache.Get(attributePath, reader), CHIP_NO_ERROR); int16_t receivedAttribute2; reader.Get(receivedAttribute2); - EXPECT_EQ(receivedAttribute2, expectedAttribute2); + EXPECT_EQ(receivedAttribute2, mockAttribute2); } delegate.mNumAttributeResponse = 0; @@ -1380,7 +1169,7 @@ TEST_F(TestRead, TestReadSubscribeAttributeResponseWithCache) EXPECT_EQ(cache.Get(attributePath, reader), CHIP_NO_ERROR); bool receivedAttribute1; reader.Get(receivedAttribute1); - EXPECT_EQ(receivedAttribute1, expectedAttribute1); + EXPECT_EQ(receivedAttribute1, mockAttribute1); } { @@ -1390,7 +1179,7 @@ TEST_F(TestRead, TestReadSubscribeAttributeResponseWithCache) EXPECT_EQ(cache.Get(attributePath, reader), CHIP_NO_ERROR); bool receivedAttribute1; reader.Get(receivedAttribute1); - EXPECT_EQ(receivedAttribute1, expectedAttribute1); + EXPECT_EQ(receivedAttribute1, mockAttribute1); } { @@ -1400,7 +1189,7 @@ TEST_F(TestRead, TestReadSubscribeAttributeResponseWithCache) EXPECT_EQ(cache.Get(attributePath, reader), CHIP_NO_ERROR); int16_t receivedAttribute2; reader.Get(receivedAttribute2); - EXPECT_EQ(receivedAttribute2, expectedAttribute2); + EXPECT_EQ(receivedAttribute2, mockAttribute2); } { @@ -1410,7 +1199,7 @@ TEST_F(TestRead, TestReadSubscribeAttributeResponseWithCache) EXPECT_EQ(cache.Get(attributePath, reader), CHIP_NO_ERROR); uint64_t receivedAttribute3; reader.Get(receivedAttribute3); - EXPECT_EQ(receivedAttribute3, expectedAttribute3); + EXPECT_EQ(receivedAttribute3, mockAttribute3); } { @@ -1420,7 +1209,7 @@ TEST_F(TestRead, TestReadSubscribeAttributeResponseWithCache) EXPECT_EQ(cache.Get(attributePath, reader), CHIP_NO_ERROR); bool receivedAttribute1; reader.Get(receivedAttribute1); - EXPECT_EQ(receivedAttribute1, expectedAttribute1); + EXPECT_EQ(receivedAttribute1, mockAttribute1); } { @@ -1430,7 +1219,7 @@ TEST_F(TestRead, TestReadSubscribeAttributeResponseWithCache) EXPECT_EQ(cache.Get(attributePath, reader), CHIP_NO_ERROR); int16_t receivedAttribute2; reader.Get(receivedAttribute2); - EXPECT_EQ(receivedAttribute2, expectedAttribute2); + EXPECT_EQ(receivedAttribute2, mockAttribute2); } delegate.mNumAttributeResponse = 0; readPrepareParams.mpEventPathParamsList = nullptr; @@ -1469,7 +1258,7 @@ TEST_F(TestRead, TestReadSubscribeAttributeResponseWithCache) EXPECT_EQ(cache.Get(attributePath, reader), CHIP_NO_ERROR); bool receivedAttribute1; reader.Get(receivedAttribute1); - EXPECT_EQ(receivedAttribute1, expectedAttribute1); + EXPECT_EQ(receivedAttribute1, mockAttribute1); } { @@ -1479,7 +1268,7 @@ TEST_F(TestRead, TestReadSubscribeAttributeResponseWithCache) EXPECT_EQ(cache.Get(attributePath, reader), CHIP_NO_ERROR); int16_t receivedAttribute2; reader.Get(receivedAttribute2); - EXPECT_EQ(receivedAttribute2, expectedAttribute2); + EXPECT_EQ(receivedAttribute2, mockAttribute2); } { @@ -1489,7 +1278,7 @@ TEST_F(TestRead, TestReadSubscribeAttributeResponseWithCache) EXPECT_EQ(cache.Get(attributePath, reader), CHIP_NO_ERROR); uint64_t receivedAttribute3; reader.Get(receivedAttribute3); - EXPECT_EQ(receivedAttribute3, expectedAttribute3); + EXPECT_EQ(receivedAttribute3, mockAttribute3); } { @@ -1499,7 +1288,7 @@ TEST_F(TestRead, TestReadSubscribeAttributeResponseWithCache) EXPECT_EQ(cache.Get(attributePath, reader), CHIP_NO_ERROR); uint8_t receivedAttribute4[256]; reader.GetBytes(receivedAttribute4, 256); - EXPECT_TRUE(memcmp(receivedAttribute4, expectedAttribute4, 256)); + EXPECT_TRUE(memcmp(receivedAttribute4, mockAttribute4, 256)); } delegate.mNumAttributeResponse = 0; } @@ -1546,7 +1335,7 @@ TEST_F(TestRead, TestReadAttributeError) auto sessionHandle = mpContext->GetSessionBobToAlice(); bool onSuccessCbInvoked = false, onFailureCbInvoked = false; - responseDirective = kSendDataError; + ScopedChange directive(gReadResponseDirective, ReadResponseDirective::kSendDataError); // Passing of stack variables by reference is only safe because of synchronous completion of the interaction. Otherwise, it's // not safe to do so. @@ -1577,7 +1366,7 @@ TEST_F(TestRead, TestReadAttributeTimeout) auto sessionHandle = mpContext->GetSessionBobToAlice(); bool onSuccessCbInvoked = false, onFailureCbInvoked = false; - responseDirective = kSendDataError; + ScopedChange directive(gReadResponseDirective, ReadResponseDirective::kSendDataError); // Passing of stack variables by reference is only safe because of synchronous completion of the interaction. Otherwise, it's // not safe to do so. @@ -1836,7 +1625,7 @@ TEST_F(TestRead, TestReadHandler_MultipleSubscriptions) uint32_t numSuccessCalls = 0; uint32_t numSubscriptionEstablishedCalls = 0; - responseDirective = kSendDataResponse; + ScopedChange directive(gReadResponseDirective, ReadResponseDirective::kSendDataResponse); // Passing of stack variables by reference is only safe because of synchronous completion of the interaction. Otherwise, it's // not safe to do so. @@ -1904,7 +1693,7 @@ TEST_F(TestRead, TestReadHandler_SubscriptionAppRejection) uint32_t numFailureCalls = 0; uint32_t numSubscriptionEstablishedCalls = 0; - responseDirective = kSendDataResponse; + ScopedChange directive(gReadResponseDirective, ReadResponseDirective::kSendDataResponse); // Passing of stack variables by reference is only safe because of synchronous completion of the interaction. Otherwise, it's // not safe to do so. @@ -1970,7 +1759,7 @@ TEST_F(TestRead, TestReadHandler_SubscriptionReportingIntervalsTest1) uint32_t numFailureCalls = 0; uint32_t numSubscriptionEstablishedCalls = 0; - responseDirective = kSendDataResponse; + ScopedChange directive(gReadResponseDirective, ReadResponseDirective::kSendDataResponse); // Passing of stack variables by reference is only safe because of synchronous completion of the interaction. Otherwise, it's // not safe to do so. @@ -2045,7 +1834,7 @@ TEST_F(TestRead, TestReadHandler_SubscriptionReportingIntervalsTest2) uint32_t numFailureCalls = 0; uint32_t numSubscriptionEstablishedCalls = 0; - responseDirective = kSendDataResponse; + ScopedChange directive(gReadResponseDirective, ReadResponseDirective::kSendDataResponse); // Passing of stack variables by reference is only safe because of synchronous completion of the interaction. Otherwise, it's // not safe to do so. @@ -2120,7 +1909,7 @@ TEST_F(TestRead, TestReadHandler_SubscriptionReportingIntervalsTest3) uint32_t numFailureCalls = 0; uint32_t numSubscriptionEstablishedCalls = 0; - responseDirective = kSendDataResponse; + ScopedChange directive(gReadResponseDirective, ReadResponseDirective::kSendDataResponse); // Passing of stack variables by reference is only safe because of synchronous completion of the interaction. Otherwise, it's // not safe to do so. @@ -2197,7 +1986,7 @@ TEST_F(TestRead, TestReadHandler_SubscriptionReportingIntervalsTest4) uint32_t numFailureCalls = 0; uint32_t numSubscriptionEstablishedCalls = 0; - responseDirective = kSendDataResponse; + ScopedChange directive(gReadResponseDirective, ReadResponseDirective::kSendDataResponse); // Passing of stack variables by reference is only safe because of synchronous completion of the interaction. Otherwise, it's // not safe to do so. @@ -2264,7 +2053,7 @@ TEST_F(TestRead, TestReadHandler_SubscriptionReportingIntervalsTest5) uint32_t numFailureCalls = 0; uint32_t numSubscriptionEstablishedCalls = 0; - responseDirective = kSendDataResponse; + ScopedChange directive(gReadResponseDirective, ReadResponseDirective::kSendDataResponse); // Passing of stack variables by reference is only safe because of synchronous completion of the interaction. Otherwise, it's // not safe to do so. @@ -2339,7 +2128,7 @@ TEST_F(TestRead, TestReadHandler_SubscriptionReportingIntervalsTest6) uint32_t numFailureCalls = 0; uint32_t numSubscriptionEstablishedCalls = 0; - responseDirective = kSendDataResponse; + ScopedChange directive(gReadResponseDirective, ReadResponseDirective::kSendDataResponse); // Passing of stack variables by reference is only safe because of synchronous completion of the interaction. Otherwise, it's // not safe to do so. @@ -2414,7 +2203,7 @@ TEST_F(TestRead, TestReadHandler_SubscriptionReportingIntervalsTest7) uint32_t numFailureCalls = 0; uint32_t numSubscriptionEstablishedCalls = 0; - responseDirective = kSendDataResponse; + ScopedChange directive(gReadResponseDirective, ReadResponseDirective::kSendDataResponse); // Passing of stack variables by reference is only safe because of synchronous completion of the interaction. Otherwise, it's // not safe to do so. @@ -2490,7 +2279,7 @@ TEST_F(TestRead, TestReadHandler_SubscriptionReportingIntervalsTest8) uint32_t numFailureCalls = 0; uint32_t numSubscriptionEstablishedCalls = 0; - responseDirective = kSendDataResponse; + ScopedChange directive(gReadResponseDirective, ReadResponseDirective::kSendDataResponse); // Passing of stack variables by reference is only safe because of synchronous completion of the interaction. Otherwise, it's // not safe to do so. @@ -2553,7 +2342,7 @@ TEST_F(TestRead, TestReadHandler_SubscriptionReportingIntervalsTest9) uint32_t numFailureCalls = 0; uint32_t numSubscriptionEstablishedCalls = 0; - responseDirective = kSendDataResponse; + ScopedChange directive(gReadResponseDirective, ReadResponseDirective::kSendDataResponse); // Passing of stack variables by reference is only safe because of synchronous completion of the interaction. Otherwise, it's // not safe to do so. @@ -2704,16 +2493,16 @@ TEST_F(TestRead, TestSubscribe_DynamicLITSubscription) auto sessionHandle = mpContext->GetSessionBobToAlice(); mpContext->SetMRPMode(chip::Test::MessagingContext::MRPMode::kResponsive); + ScopedChange directive(gReadResponseDirective, ReadResponseDirective::kSendDataResponse); + ScopedChange isLitIcd(gIsLitIcd, false); { TestResubscriptionCallback callback; app::ReadClient readClient(app::InteractionModelEngine::GetInstance(), &mpContext->GetExchangeManager(), callback, app::ReadClient::InteractionType::Subscribe); - responseDirective = kSendDataResponse; callback.mScheduleLITResubscribeImmediately = false; callback.SetReadClient(&readClient); - isLitIcd = false; app::ReadPrepareParams readPrepareParams(mpContext->GetSessionBobToAlice()); @@ -2808,8 +2597,6 @@ TEST_F(TestRead, TestSubscribe_DynamicLITSubscription) app::InteractionModelEngine::GetInstance()->ShutdownActiveReads(); EXPECT_EQ(mpContext->GetExchangeManager().GetNumActiveExchanges(), 0u); - - isLitIcd = false; } /** @@ -2944,7 +2731,7 @@ void TestRead::SubscribeThenReadHelper(TestContext * apCtx, size_t aSubscribeCou uint32_t numReadSuccessCalls = 0; uint32_t numReadFailureCalls = 0; - responseDirective = kSendDataResponse; + ScopedChange directive(gReadResponseDirective, ReadResponseDirective::kSendDataResponse); // Passing of stack variables by reference is only safe because of synchronous completion of the interaction. Otherwise, it's // not safe to do so. @@ -2997,9 +2784,9 @@ void TestRead::MultipleReadHelperInternal(TestContext * apCtx, size_t aReadCount auto sessionHandle = apCtx->GetSessionBobToAlice(); - responseDirective = kSendDataResponse; + ScopedChange directive(gReadResponseDirective, ReadResponseDirective::kSendDataResponse); - uint16_t firstExpectedResponse = totalReadCount + 1; + uint16_t firstExpectedResponse = gInt16uTotalReadCount + 1; auto onFailureCb = [&aNumFailureCalls](const app::ConcreteDataAttributePath * attributePath, CHIP_ERROR aError) { aNumFailureCalls++; @@ -3040,7 +2827,7 @@ TEST_F(TestRead, TestReadHandler_MultipleSubscriptionsWithDataVersionFilter) uint32_t numSuccessCalls = 0; uint32_t numSubscriptionEstablishedCalls = 0; - responseDirective = kSendDataResponse; + ScopedChange directive(gReadResponseDirective, ReadResponseDirective::kSendDataResponse); // Passing of stack variables by reference is only safe because of synchronous completion of the interaction. Otherwise, it's // not safe to do so. @@ -3181,7 +2968,7 @@ TEST_F(TestRead, TestReadHandlerResourceExhaustion_MultipleReads) uint32_t numSuccessCalls = 0; uint32_t numFailureCalls = 0; - responseDirective = kSendDataResponse; + ScopedChange directive(gReadResponseDirective, ReadResponseDirective::kSendDataResponse); // Passing of stack variables by reference is only safe because of synchronous completion of the interaction. Otherwise, it's // not safe to do so. @@ -3232,7 +3019,7 @@ TEST_F(TestRead, TestReadFabricScopedWithoutFabricFilter) auto sessionHandle = mpContext->GetSessionBobToAlice(); bool onSuccessCbInvoked = false, onFailureCbInvoked = false; - responseDirective = kSendDataResponse; + ScopedChange directive(gReadResponseDirective, ReadResponseDirective::kSendDataResponse); // Passing of stack variables by reference is only safe because of synchronous completion of the interaction. Otherwise, it's // not safe to do so. @@ -3277,7 +3064,7 @@ TEST_F(TestRead, TestReadFabricScopedWithFabricFilter) auto sessionHandle = mpContext->GetSessionBobToAlice(); bool onSuccessCbInvoked = false, onFailureCbInvoked = false; - responseDirective = kSendDataResponse; + ScopedChange directive(gReadResponseDirective, ReadResponseDirective::kSendDataResponse); // Passing of stack variables by reference is only safe because of synchronous completion of the interaction. Otherwise, it's // not safe to do so. @@ -4835,7 +4622,7 @@ TEST_F(TestRead, TestReadAttribute_ManyDataValues) size_t successCalls = 0; size_t failureCalls = 0; - responseDirective = kSendManyDataResponses; + ScopedChange directive(gReadResponseDirective, ReadResponseDirective::kSendManyDataResponses); // Passing of stack variables by reference is only safe because of synchronous completion of the interaction. Otherwise, it's // not safe to do so. @@ -4868,7 +4655,7 @@ TEST_F(TestRead, TestReadAttribute_ManyDataValuesWrongPath) size_t successCalls = 0; size_t failureCalls = 0; - responseDirective = kSendManyDataResponsesWrongPath; + ScopedChange directive(gReadResponseDirective, ReadResponseDirective::kSendManyDataResponsesWrongPath); // Passing of stack variables by reference is only safe because of synchronous completion of the interaction. Otherwise, it's // not safe to do so. @@ -4901,7 +4688,7 @@ TEST_F(TestRead, TestReadAttribute_ManyErrors) size_t successCalls = 0; size_t failureCalls = 0; - responseDirective = kSendTwoDataErrors; + ScopedChange directive(gReadResponseDirective, ReadResponseDirective::kSendTwoDataErrors); // Passing of stack variables by reference is only safe because of synchronous completion of the interaction. Otherwise, it's // not safe to do so. diff --git a/src/controller/tests/data_model/TestWrite.cpp b/src/controller/tests/data_model/TestWrite.cpp index da5505ccd613a1..8f0d96f7667507 100644 --- a/src/controller/tests/data_model/TestWrite.cpp +++ b/src/controller/tests/data_model/TestWrite.cpp @@ -19,6 +19,8 @@ #include #include +#include "DataModelFixtures.h" + #include "app-common/zap-generated/ids/Clusters.h" #include #include @@ -37,178 +39,11 @@ using namespace chip; using namespace chip::app; using namespace chip::app::Clusters; using namespace chip::app::Clusters::UnitTesting; +using namespace chip::app::DataModelTests; using namespace chip::Protocols; namespace { -constexpr EndpointId kTestEndpointId = 1; -constexpr DataVersion kRejectedDataVersion = 1; -constexpr DataVersion kAcceptedDataVersion = 5; - -constexpr uint8_t kExampleClusterSpecificSuccess = 11u; -constexpr uint8_t kExampleClusterSpecificFailure = 12u; - -enum ResponseDirective -{ - kSendAttributeSuccess, - kSendAttributeError, - kSendMultipleSuccess, - kSendMultipleErrors, - kSendClusterSpecificSuccess, - kSendClusterSpecificFailure, -}; - -ResponseDirective gResponseDirective = kSendAttributeSuccess; - -} // namespace - -namespace chip { -namespace app { - -const EmberAfAttributeMetadata * GetAttributeMetadata(const ConcreteAttributePath & aConcreteClusterPath) -{ - // Note: This test does not make use of the real attribute metadata. - static EmberAfAttributeMetadata stub = { .defaultValue = EmberAfDefaultOrMinMaxAttributeValue(uint32_t(0)) }; - return &stub; -} - -CHIP_ERROR WriteSingleClusterData(const Access::SubjectDescriptor & aSubjectDescriptor, const ConcreteDataAttributePath & aPath, - TLV::TLVReader & aReader, WriteHandler * aWriteHandler) -{ - static ListIndex listStructOctetStringElementCount = 0; - - if (aPath.mDataVersion.HasValue() && aPath.mDataVersion.Value() == kRejectedDataVersion) - { - return aWriteHandler->AddStatus(aPath, Protocols::InteractionModel::Status::DataVersionMismatch); - } - - if (aPath.mClusterId == Clusters::UnitTesting::Id && - aPath.mAttributeId == Attributes::ListStructOctetString::TypeInfo::GetAttributeId()) - { - if (gResponseDirective == kSendAttributeSuccess) - { - if (!aPath.IsListOperation() || aPath.mListOp == ConcreteDataAttributePath::ListOperation::ReplaceAll) - { - - Attributes::ListStructOctetString::TypeInfo::DecodableType value; - - ReturnErrorOnFailure(DataModel::Decode(aReader, value)); - - auto iter = value.begin(); - listStructOctetStringElementCount = 0; - while (iter.Next()) - { - auto & item = iter.GetValue(); - - VerifyOrReturnError(item.member1 == listStructOctetStringElementCount, CHIP_ERROR_INVALID_ARGUMENT); - listStructOctetStringElementCount++; - } - - aWriteHandler->AddStatus(aPath, Protocols::InteractionModel::Status::Success); - } - else if (aPath.mListOp == ConcreteDataAttributePath::ListOperation::AppendItem) - { - Structs::TestListStructOctet::DecodableType item; - ReturnErrorOnFailure(DataModel::Decode(aReader, item)); - VerifyOrReturnError(item.member1 == listStructOctetStringElementCount, CHIP_ERROR_INVALID_ARGUMENT); - listStructOctetStringElementCount++; - - aWriteHandler->AddStatus(aPath, Protocols::InteractionModel::Status::Success); - } - else - { - return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; - } - } - else - { - aWriteHandler->AddStatus(aPath, Protocols::InteractionModel::Status::Failure); - } - - return CHIP_NO_ERROR; - } - if (aPath.mClusterId == Clusters::UnitTesting::Id && aPath.mAttributeId == Attributes::ListFabricScoped::Id) - { - // Mock a invalid SubjectDescriptor - AttributeValueDecoder decoder(aReader, Access::SubjectDescriptor()); - if (!aPath.IsListOperation() || aPath.mListOp == ConcreteDataAttributePath::ListOperation::ReplaceAll) - { - Attributes::ListFabricScoped::TypeInfo::DecodableType value; - - ReturnErrorOnFailure(decoder.Decode(value)); - - auto iter = value.begin(); - while (iter.Next()) - { - auto & item = iter.GetValue(); - (void) item; - } - - aWriteHandler->AddStatus(aPath, Protocols::InteractionModel::Status::Success); - } - else if (aPath.mListOp == ConcreteDataAttributePath::ListOperation::AppendItem) - { - Structs::TestFabricScoped::DecodableType item; - ReturnErrorOnFailure(decoder.Decode(item)); - - aWriteHandler->AddStatus(aPath, Protocols::InteractionModel::Status::Success); - } - else - { - return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; - } - return CHIP_NO_ERROR; - } - - // Boolean attribute of unit testing cluster triggers "multiple errors" case. - if (aPath.mClusterId == Clusters::UnitTesting::Id && aPath.mAttributeId == Attributes::Boolean::TypeInfo::GetAttributeId()) - { - InteractionModel::ClusterStatusCode status{ Protocols::InteractionModel::Status::InvalidValue }; - - if (gResponseDirective == kSendMultipleSuccess) - { - status = InteractionModel::Status::Success; - } - else if (gResponseDirective == kSendMultipleErrors) - { - status = InteractionModel::Status::Failure; - } - else - { - VerifyOrDie(false); - } - - for (size_t i = 0; i < 4; ++i) - { - aWriteHandler->AddStatus(aPath, status); - } - - return CHIP_NO_ERROR; - } - - if (aPath.mClusterId == Clusters::UnitTesting::Id && aPath.mAttributeId == Attributes::Int8u::TypeInfo::GetAttributeId()) - { - InteractionModel::ClusterStatusCode status{ Protocols::InteractionModel::Status::InvalidValue }; - if (gResponseDirective == kSendClusterSpecificSuccess) - { - status = InteractionModel::ClusterStatusCode::ClusterSpecificSuccess(kExampleClusterSpecificSuccess); - } - else if (gResponseDirective == kSendClusterSpecificFailure) - { - status = InteractionModel::ClusterStatusCode::ClusterSpecificFailure(kExampleClusterSpecificFailure); - } - else - { - VerifyOrDie(false); - } - - aWriteHandler->AddStatus(aPath, status); - return CHIP_NO_ERROR; - } - - return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; -} - class SingleWriteCallback : public WriteClient::Callback { public: @@ -249,11 +84,6 @@ class SingleWriteCallback : public WriteClient::Callback StatusIB mPathStatus; }; -} // namespace app -} // namespace chip - -namespace { - class TestWrite : public ::testing::Test { public: @@ -315,7 +145,7 @@ TEST_F(TestWrite, TestDataResponse) i++; } - gResponseDirective = kSendAttributeSuccess; + ScopedChange directive(gWriteResponseDirective, WriteResponseDirective::kSendAttributeSuccess); // Passing of stack variables by reference is only safe because of synchronous completion of the interaction. Otherwise, it's // not safe to do so. @@ -353,7 +183,7 @@ TEST_F(TestWrite, TestDataResponseWithAcceptedDataVersion) i++; } - gResponseDirective = kSendAttributeSuccess; + ScopedChange directive(gWriteResponseDirective, WriteResponseDirective::kSendAttributeSuccess); // Passing of stack variables by reference is only safe because of synchronous completion of the interaction. Otherwise, it's // not safe to do so. @@ -393,7 +223,7 @@ TEST_F(TestWrite, TestDataResponseWithRejectedDataVersion) i++; } - gResponseDirective = kSendAttributeSuccess; + ScopedChange directive(gWriteResponseDirective, WriteResponseDirective::kSendAttributeSuccess); // Passing of stack variables by reference is only safe because of synchronous completion of the interaction. Otherwise, it's // not safe to do so. @@ -432,7 +262,7 @@ TEST_F(TestWrite, TestAttributeError) i++; } - gResponseDirective = kSendAttributeError; + ScopedChange directive(gWriteResponseDirective, WriteResponseDirective::kSendAttributeError); // Passing of stack variables by reference is only safe because of synchronous completion of the interaction. Otherwise, it's // not safe to do so. @@ -498,7 +328,7 @@ TEST_F(TestWrite, TestMultipleSuccessResponses) size_t successCalls = 0; size_t failureCalls = 0; - gResponseDirective = kSendMultipleSuccess; + ScopedChange directive(gWriteResponseDirective, WriteResponseDirective::kSendMultipleSuccess); // Passing of stack variables by reference is only safe because of synchronous completion of the interaction. Otherwise, it's // not safe to do so. @@ -525,7 +355,7 @@ TEST_F(TestWrite, TestMultipleFailureResponses) size_t successCalls = 0; size_t failureCalls = 0; - gResponseDirective = kSendMultipleErrors; + ScopedChange directive(gWriteResponseDirective, WriteResponseDirective::kSendMultipleErrors); // Passing of stack variables by reference is only safe because of synchronous completion of the interaction. Otherwise, it's // not safe to do so. @@ -552,7 +382,7 @@ TEST_F(TestWrite, TestWriteClusterSpecificStatuses) // Cluster-specific success code case { - gResponseDirective = kSendClusterSpecificSuccess; + ScopedChange directive(gWriteResponseDirective, WriteResponseDirective::kSendClusterSpecificSuccess); this->ResetCallback(); this->PrepareWriteCallback( @@ -584,7 +414,7 @@ TEST_F(TestWrite, TestWriteClusterSpecificStatuses) // Cluster-specific failure code case { - gResponseDirective = kSendClusterSpecificFailure; + ScopedChange directive(gWriteResponseDirective, WriteResponseDirective::kSendClusterSpecificFailure); this->ResetCallback(); this->PrepareWriteCallback( diff --git a/src/lib/support/Scoped.h b/src/lib/support/Scoped.h index 67cc2ea9e96271..a96021c097ee0a 100644 --- a/src/lib/support/Scoped.h +++ b/src/lib/support/Scoped.h @@ -46,12 +46,16 @@ class ScopedChangeOnly /// Allows a scoped mutation to occur on a variable. /// /// When an instance of this class goes out of scope, the variable -/// will be reset to the default. +/// will be reset to the value id had before the scoped change came +/// into effect. /// -/// Example usage +/// While the ScopedChange is in scope it can be used to make changes +/// to the underlying value using the assignment operator. /// -/// int a = 123; -/// ScopedChangeOnly b(234); +/// Example usage: +/// +/// int a = 123; +/// ScopedChangeOnly b(234); /// /// /* a == 123, b == 234 */ /// { @@ -62,6 +66,8 @@ class ScopedChangeOnly /// /* a == 321, b == 10 */ /// } /// /* a == 321, b == 234 */ +/// changeA = 333; // assignments within the ScopedChange are allowed +/// /* a == 333, b == 234 */ /// } /// /* a == 123, b == 234 */ /// @@ -69,10 +75,22 @@ template class ScopedChange { public: - ScopedChange(ScopedChangeOnly & what, T value) : mValue(what.InternalMutableValue()), mOriginal(what) { mValue = value; } - ScopedChange(T & what, T value) : mValue(what), mOriginal(what) { mValue = value; } + ScopedChange(ScopedChangeOnly & what) : mValue(what.InternalMutableValue()), mOriginal(what) {} + ScopedChange(ScopedChangeOnly & what, T value) : ScopedChange(what) { mValue = value; } + + ScopedChange(T & what) : mValue(what), mOriginal(what) {} + ScopedChange(T & what, T value) : ScopedChange(what) { mValue = value; } + ~ScopedChange() { mValue = mOriginal; } + ScopedChange & operator=(T const & value) + { + mValue = value; + return *this; + } + + operator T() const { return mValue; } + private: T & mValue; T mOriginal;