diff --git a/src/app/ClusterStateCache.cpp b/src/app/ClusterStateCache.cpp index 48d27a7f76a9c8..c99daf57e0c999 100644 --- a/src/app/ClusterStateCache.cpp +++ b/src/app/ClusterStateCache.cpp @@ -24,12 +24,25 @@ namespace chip { namespace app { +CHIP_ERROR ClusterStateCache::GetElementTLVSize(TLV::TLVReader * apData, size_t & aSize) +{ + Platform::ScopedMemoryBufferWithSize backingBuffer; + TLV::TLVReader reader; + reader.Init(*apData); + size_t totalBufSize = reader.GetTotalLength(); + backingBuffer.Calloc(totalBufSize); + VerifyOrReturnError(backingBuffer.Get() != nullptr, CHIP_ERROR_NO_MEMORY); + TLV::ScopedBufferTLVWriter writer(std::move(backingBuffer), totalBufSize); + ReturnErrorOnFailure(writer.CopyElement(TLV::AnonymousTag(), reader)); + aSize = writer.GetLengthWritten(); + ReturnErrorOnFailure(writer.Finalize(backingBuffer)); + return CHIP_NO_ERROR; +} + CHIP_ERROR ClusterStateCache::UpdateCache(const ConcreteDataAttributePath & aPath, TLV::TLVReader * apData, const StatusIB & aStatus) { AttributeState state; - System::PacketBufferHandle handle; - System::PacketBufferTLVWriter writer; bool endpointIsNew = false; if (mCache.find(aPath.mEndpointId) == mCache.end()) @@ -44,21 +57,16 @@ CHIP_ERROR ClusterStateCache::UpdateCache(const ConcreteDataAttributePath & aPat if (apData) { - handle = System::PacketBufferHandle::New(chip::app::kMaxSecureSduLengthBytes); - - writer.Init(std::move(handle), false); - + size_t elementSize = 0; + ReturnErrorOnFailure(GetElementTLVSize(apData, elementSize)); + Platform::ScopedMemoryBufferWithSize backingBuffer; + backingBuffer.Calloc(elementSize); + VerifyOrReturnError(backingBuffer.Get() != nullptr, CHIP_ERROR_NO_MEMORY); + TLV::ScopedBufferTLVWriter writer(std::move(backingBuffer), elementSize); ReturnErrorOnFailure(writer.CopyElement(TLV::AnonymousTag(), *apData)); - ReturnErrorOnFailure(writer.Finalize(&handle)); - - // - // Compact the buffer down to a more reasonably sized packet buffer - // if we can. - // - handle.RightSize(); - - state.Set(std::move(handle)); + ReturnErrorOnFailure(writer.Finalize(backingBuffer)); + state.Set>(std::move(backingBuffer)); // // Clear out the committed data version and only set it again once we have received all data for this cluster. // Otherwise, we may have incomplete data that looks like it's complete since it has a valid data version. @@ -204,22 +212,16 @@ void ClusterStateCache::OnReportEnd() CHIP_ERROR ClusterStateCache::Get(const ConcreteAttributePath & path, TLV::TLVReader & reader) { CHIP_ERROR err; - auto attributeState = GetAttributeState(path.mEndpointId, path.mClusterId, path.mAttributeId, err); ReturnErrorOnFailure(err); - if (attributeState->Is()) { return CHIP_ERROR_IM_STATUS_CODE_RECEIVED; } - System::PacketBufferTLVReader bufReader; - - bufReader.Init(attributeState->Get().Retain()); - ReturnErrorOnFailure(bufReader.Next()); - - reader.Init(bufReader); - return CHIP_NO_ERROR; + reader.Init(attributeState->Get>().Get(), + attributeState->Get>().BufferByteSize()); + return reader.Next(); } CHIP_ERROR ClusterStateCache::Get(EventNumber eventNumber, TLV::TLVReader & reader) @@ -336,10 +338,11 @@ void ClusterStateCache::OnAttributeData(const ConcreteDataAttributePath & aPath, mCallback.OnAttributeData(aPath, apData ? &dataSnapshot : nullptr, aStatus); } -CHIP_ERROR ClusterStateCache::GetVersion(EndpointId mEndpointId, ClusterId mClusterId, Optional & aVersion) +CHIP_ERROR ClusterStateCache::GetVersion(const ConcreteClusterPath & aPath, Optional & aVersion) { + VerifyOrReturnError(aPath.IsValidConcreteClusterPath(), CHIP_ERROR_INVALID_ARGUMENT); CHIP_ERROR err; - auto clusterState = GetClusterState(mEndpointId, mClusterId, err); + auto clusterState = GetClusterState(aPath.mEndpointId, aPath.mClusterId, err); ReturnErrorOnFailure(err); aVersion = clusterState->mCommittedDataVersion; return CHIP_NO_ERROR; @@ -417,8 +420,9 @@ void ClusterStateCache::GetSortedFilters(std::vector().Retain()); + TLV::TLVReader bufReader; + bufReader.Init(attributeIter.second.Get>().Get(), + attributeIter.second.Get>().BufferByteSize()); ReturnOnFailure(bufReader.Next()); // Skip to the end of the element. ReturnOnFailure(bufReader.Skip()); diff --git a/src/app/ClusterStateCache.h b/src/app/ClusterStateCache.h index 6536976884f7e9..ee9f9c465130f5 100644 --- a/src/app/ClusterStateCache.h +++ b/src/app/ClusterStateCache.h @@ -236,7 +236,7 @@ class ClusterStateCache : protected ReadClient::Callback * current data version for the cluster (which may have no value if we don't have a known data version * for it, for example because none of our paths were wildcards that covered the whole cluster). */ - CHIP_ERROR GetVersion(EndpointId mEndpointId, ClusterId mClusterId, Optional & aVersion); + CHIP_ERROR GetVersion(const ConcreteClusterPath & path, Optional & aVersion); /* * Get highest received event number. @@ -483,7 +483,7 @@ class ClusterStateCache : protected ReadClient::Callback } private: - using AttributeState = Variant; + using AttributeState = Variant, StatusIB>; // mPendingDataVersion represents a tentative data version for a cluster that we have gotten some reports for. // // mCurrentDataVersion represents a known data version for a cluster. In order for this to have a @@ -591,6 +591,8 @@ class ClusterStateCache : protected ReadClient::Callback // on the wire if not all filters can be applied. void GetSortedFilters(std::vector> & aVector); + CHIP_ERROR GetElementTLVSize(TLV::TLVReader * apData, size_t & aSize); + Callback & mCallback; NodeState mCache; std::set mChangedAttributeSet; diff --git a/src/app/tests/TestClusterStateCache.cpp b/src/app/tests/TestClusterStateCache.cpp index a6da5662d3cf5c..2aa7d48b1034a7 100644 --- a/src/app/tests/TestClusterStateCache.cpp +++ b/src/app/tests/TestClusterStateCache.cpp @@ -176,9 +176,6 @@ class DataSeriesGenerator void DataSeriesGenerator::Generate(ForwardedDataCallbackValidator & dataCallbackValidator) { - System::PacketBufferHandle handle; - System::PacketBufferTLVWriter writer; - System::PacketBufferTLVReader reader; ReadClient::Callback * callback = mReadCallback; StatusIB status; callback->OnReportBegin(); @@ -187,8 +184,10 @@ void DataSeriesGenerator::Generate(ForwardedDataCallbackValidator & dataCallback for (auto & instruction : mInstructionList) { ConcreteDataAttributePath path(instruction.mEndpointId, Clusters::TestCluster::Id, 0); - handle = System::PacketBufferHandle::New(1000); - writer.Init(std::move(handle), true); + Platform::ScopedMemoryBufferWithSize handle; + handle.Calloc(3000); + TLV::ScopedBufferTLVWriter writer(std::move(handle), 3000); + status = StatusIB(); path.mAttributeId = instruction.GetAttributeId(); path.mDataVersion.SetValue(1); @@ -231,7 +230,8 @@ void DataSeriesGenerator::Generate(ForwardedDataCallbackValidator & dataCallback case AttributeInstruction::kAttributeD: { ChipLogProgress(DataManagement, "\t -- Generating D"); - Clusters::TestCluster::Structs::TestListStructOctet::Type buf[4]; + // buf[200] is 1.6k + Clusters::TestCluster::Structs::TestListStructOctet::Type buf[200]; for (auto & i : buf) { @@ -250,8 +250,10 @@ void DataSeriesGenerator::Generate(ForwardedDataCallbackValidator & dataCallback break; } - writer.Finalize(&handle); - reader.Init(std::move(handle)); + uint32_t writtenLength = writer.GetLengthWritten(); + writer.Finalize(handle); + TLV::ScopedBufferTLVReader reader; + reader.Init(std::move(handle), writtenLength); NL_TEST_ASSERT(gSuite, reader.Next() == CHIP_NO_ERROR); dataCallbackValidator.SetExpectation(reader, instruction.mEndpointId, instruction.mAttributeType); callback->OnAttributeData(path, &reader, status); diff --git a/src/controller/tests/data_model/TestRead.cpp b/src/controller/tests/data_model/TestRead.cpp index a680dd63f25cea..85216a0dfe7460 100644 --- a/src/controller/tests/data_model/TestRead.cpp +++ b/src/controller/tests/data_model/TestRead.cpp @@ -41,6 +41,19 @@ namespace { constexpr EndpointId kTestEndpointId = 1; constexpr DataVersion kDataVersion = 5; +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 { @@ -141,7 +154,7 @@ CHIP_ERROR ReadSingleClusterData(const Access::SubjectDescriptor & aSubjectDescr return attributeReport.EndOfAttributeReportIB().GetError(); } -bool IsClusterDataVersionEqual(const ConcreteClusterPath & aConcreteClusterPath, DataVersion aRequiredVersion) +bool IsClusterDataVersionEqual(const app::ConcreteClusterPath & aConcreteClusterPath, DataVersion aRequiredVersion) { if (aRequiredVersion == kDataVersion) { @@ -238,8 +251,10 @@ class MockInteractionModelApp : public chip::app::ClusterStateCache::Callback { if (status.mStatus == chip::Protocols::InteractionModel::Status::Success) { + ChipLogProgress(DataManagement, "\t\t -- attribute status sucess"); mNumAttributeResponse++; } + ChipLogProgress(DataManagement, "\t\t -- OnAttributeData is called"); } void OnError(CHIP_ERROR aError) override @@ -415,11 +430,41 @@ void TestReadInteraction::TestReadSubscribeAttributeResponseWithCache(nlTestSuit NL_TEST_ASSERT(apSuite, delegate.mNumAttributeResponse == 3); NL_TEST_ASSERT(apSuite, !delegate.mReadError); Optional version1; - NL_TEST_ASSERT(apSuite, cache.GetVersion(Test::kMockEndpoint2, Test::MockClusterId(3), version1) == CHIP_NO_ERROR); + app::ConcreteClusterPath clusterPath1(Test::kMockEndpoint2, Test::MockClusterId(3)); + NL_TEST_ASSERT(apSuite, cache.GetVersion(clusterPath1, version1) == CHIP_NO_ERROR); NL_TEST_ASSERT(apSuite, !version1.HasValue()); Optional version2; - NL_TEST_ASSERT(apSuite, cache.GetVersion(Test::kMockEndpoint3, Test::MockClusterId(2), version2) == CHIP_NO_ERROR); + app::ConcreteClusterPath clusterPath2(Test::kMockEndpoint3, Test::MockClusterId(2)); + NL_TEST_ASSERT(apSuite, cache.GetVersion(clusterPath2, version2) == CHIP_NO_ERROR); NL_TEST_ASSERT(apSuite, !version2.HasValue()); + + { + app::ConcreteAttributePath attributePath(Test::kMockEndpoint2, Test::MockClusterId(3), Test::MockAttributeId(1)); + TLV::TLVReader reader; + NL_TEST_ASSERT(apSuite, cache.Get(attributePath, reader) == CHIP_NO_ERROR); + bool receivedAttribute1; + reader.Get(receivedAttribute1); + NL_TEST_ASSERT(apSuite, receivedAttribute1 == expectedAttribute1); + } + + { + app::ConcreteAttributePath attributePath(Test::kMockEndpoint2, Test::MockClusterId(3), Test::MockAttributeId(2)); + TLV::TLVReader reader; + NL_TEST_ASSERT(apSuite, cache.Get(attributePath, reader) == CHIP_NO_ERROR); + int16_t receivedAttribute2; + reader.Get(receivedAttribute2); + NL_TEST_ASSERT(apSuite, receivedAttribute2 == expectedAttribute2); + } + + { + app::ConcreteAttributePath attributePath(Test::kMockEndpoint3, Test::MockClusterId(2), Test::MockAttributeId(2)); + TLV::TLVReader reader; + NL_TEST_ASSERT(apSuite, cache.Get(attributePath, reader) == CHIP_NO_ERROR); + int16_t receivedAttribute2; + reader.Get(receivedAttribute2); + NL_TEST_ASSERT(apSuite, receivedAttribute2 == expectedAttribute2); + } + delegate.mNumAttributeResponse = 0; } @@ -453,11 +498,37 @@ void TestReadInteraction::TestReadSubscribeAttributeResponseWithCache(nlTestSuit NL_TEST_ASSERT(apSuite, delegate.mNumAttributeResponse == 2); NL_TEST_ASSERT(apSuite, !delegate.mReadError); Optional version1; - NL_TEST_ASSERT(apSuite, cache.GetVersion(Test::kMockEndpoint2, Test::MockClusterId(3), version1) == CHIP_NO_ERROR); + app::ConcreteClusterPath clusterPath1(Test::kMockEndpoint2, Test::MockClusterId(3)); + NL_TEST_ASSERT(apSuite, cache.GetVersion(clusterPath1, version1) == CHIP_NO_ERROR); NL_TEST_ASSERT(apSuite, !version1.HasValue()); Optional version2; - NL_TEST_ASSERT(apSuite, cache.GetVersion(Test::kMockEndpoint3, Test::MockClusterId(2), version2) == CHIP_NO_ERROR); + app::ConcreteClusterPath clusterPath2(Test::kMockEndpoint3, Test::MockClusterId(2)); + NL_TEST_ASSERT(apSuite, cache.GetVersion(clusterPath2, version2) == CHIP_NO_ERROR); NL_TEST_ASSERT(apSuite, !version2.HasValue()); + + { + app::ConcreteAttributePath attributePath(Test::kMockEndpoint1, Test::MockClusterId(2), Test::MockAttributeId(2)); + TLV::TLVReader reader; + NL_TEST_ASSERT(apSuite, cache.Get(attributePath, reader) != CHIP_NO_ERROR); + } + + { + app::ConcreteAttributePath attributePath(Test::kMockEndpoint2, Test::MockClusterId(2), Test::MockAttributeId(2)); + TLV::TLVReader reader; + NL_TEST_ASSERT(apSuite, cache.Get(attributePath, reader) == CHIP_NO_ERROR); + int16_t receivedAttribute2; + reader.Get(receivedAttribute2); + NL_TEST_ASSERT(apSuite, receivedAttribute2 == expectedAttribute2); + } + + { + app::ConcreteAttributePath attributePath(Test::kMockEndpoint3, Test::MockClusterId(2), Test::MockAttributeId(2)); + TLV::TLVReader reader; + NL_TEST_ASSERT(apSuite, cache.Get(attributePath, reader) == CHIP_NO_ERROR); + int16_t receivedAttribute2; + reader.Get(receivedAttribute2); + NL_TEST_ASSERT(apSuite, receivedAttribute2 == expectedAttribute2); + } delegate.mNumAttributeResponse = 0; } @@ -486,11 +557,49 @@ void TestReadInteraction::TestReadSubscribeAttributeResponseWithCache(nlTestSuit NL_TEST_ASSERT(apSuite, delegate.mNumAttributeResponse == 6); NL_TEST_ASSERT(apSuite, !delegate.mReadError); Optional version1; - NL_TEST_ASSERT(apSuite, cache.GetVersion(Test::kMockEndpoint2, Test::MockClusterId(3), version1) == CHIP_NO_ERROR); + app::ConcreteClusterPath clusterPath1(Test::kMockEndpoint2, Test::MockClusterId(3)); + NL_TEST_ASSERT(apSuite, cache.GetVersion(clusterPath1, version1) == CHIP_NO_ERROR); NL_TEST_ASSERT(apSuite, version1.HasValue() && (version1.Value() == 0)); Optional version2; - NL_TEST_ASSERT(apSuite, cache.GetVersion(Test::kMockEndpoint3, Test::MockClusterId(2), version2) == CHIP_NO_ERROR); + app::ConcreteClusterPath clusterPath2(Test::kMockEndpoint3, Test::MockClusterId(2)); + NL_TEST_ASSERT(apSuite, cache.GetVersion(clusterPath2, version2) == CHIP_NO_ERROR); NL_TEST_ASSERT(apSuite, !version2.HasValue()); + + { + app::ConcreteAttributePath attributePath(Test::kMockEndpoint2, Test::MockClusterId(3), Test::MockAttributeId(1)); + TLV::TLVReader reader; + NL_TEST_ASSERT(apSuite, cache.Get(attributePath, reader) == CHIP_NO_ERROR); + bool receivedAttribute1; + reader.Get(receivedAttribute1); + NL_TEST_ASSERT(apSuite, receivedAttribute1 == expectedAttribute1); + } + + { + app::ConcreteAttributePath attributePath(Test::kMockEndpoint2, Test::MockClusterId(3), Test::MockAttributeId(2)); + TLV::TLVReader reader; + NL_TEST_ASSERT(apSuite, cache.Get(attributePath, reader) == CHIP_NO_ERROR); + int16_t receivedAttribute2; + reader.Get(receivedAttribute2); + NL_TEST_ASSERT(apSuite, receivedAttribute2 == expectedAttribute2); + } + + { + app::ConcreteAttributePath attributePath(Test::kMockEndpoint2, Test::MockClusterId(3), Test::MockAttributeId(3)); + TLV::TLVReader reader; + NL_TEST_ASSERT(apSuite, cache.Get(attributePath, reader) == CHIP_NO_ERROR); + uint64_t receivedAttribute3; + reader.Get(receivedAttribute3); + NL_TEST_ASSERT(apSuite, receivedAttribute3 == expectedAttribute3); + } + + { + app::ConcreteAttributePath attributePath(Test::kMockEndpoint3, Test::MockClusterId(2), Test::MockAttributeId(2)); + TLV::TLVReader reader; + NL_TEST_ASSERT(apSuite, cache.Get(attributePath, reader) == CHIP_NO_ERROR); + int16_t receivedAttribute2; + reader.Get(receivedAttribute2); + NL_TEST_ASSERT(apSuite, receivedAttribute2 == expectedAttribute2); + } delegate.mNumAttributeResponse = 0; } @@ -523,11 +632,40 @@ void TestReadInteraction::TestReadSubscribeAttributeResponseWithCache(nlTestSuit NL_TEST_ASSERT(apSuite, delegate.mNumAttributeResponse == 1); NL_TEST_ASSERT(apSuite, !delegate.mReadError); Optional version1; - NL_TEST_ASSERT(apSuite, cache.GetVersion(Test::kMockEndpoint2, Test::MockClusterId(3), version1) == CHIP_NO_ERROR); + app::ConcreteClusterPath clusterPath1(Test::kMockEndpoint2, Test::MockClusterId(3)); + NL_TEST_ASSERT(apSuite, cache.GetVersion(clusterPath1, version1) == CHIP_NO_ERROR); NL_TEST_ASSERT(apSuite, version1.HasValue() && (version1.Value() == 0)); Optional version2; - NL_TEST_ASSERT(apSuite, cache.GetVersion(Test::kMockEndpoint3, Test::MockClusterId(2), version2) == CHIP_NO_ERROR); + app::ConcreteClusterPath clusterPath2(Test::kMockEndpoint3, Test::MockClusterId(2)); + NL_TEST_ASSERT(apSuite, cache.GetVersion(clusterPath2, version2) == CHIP_NO_ERROR); NL_TEST_ASSERT(apSuite, !version2.HasValue()); + + { + app::ConcreteAttributePath attributePath(Test::kMockEndpoint2, Test::MockClusterId(3), Test::MockAttributeId(1)); + TLV::TLVReader reader; + NL_TEST_ASSERT(apSuite, cache.Get(attributePath, reader) == CHIP_NO_ERROR); + bool receivedAttribute1; + reader.Get(receivedAttribute1); + NL_TEST_ASSERT(apSuite, receivedAttribute1 == expectedAttribute1); + } + + { + app::ConcreteAttributePath attributePath(Test::kMockEndpoint2, Test::MockClusterId(3), Test::MockAttributeId(2)); + TLV::TLVReader reader; + NL_TEST_ASSERT(apSuite, cache.Get(attributePath, reader) == CHIP_NO_ERROR); + int16_t receivedAttribute2; + reader.Get(receivedAttribute2); + NL_TEST_ASSERT(apSuite, receivedAttribute2 == expectedAttribute2); + } + + { + app::ConcreteAttributePath attributePath(Test::kMockEndpoint3, Test::MockClusterId(2), Test::MockAttributeId(2)); + TLV::TLVReader reader; + NL_TEST_ASSERT(apSuite, cache.Get(attributePath, reader) == CHIP_NO_ERROR); + int16_t receivedAttribute2; + reader.Get(receivedAttribute2); + NL_TEST_ASSERT(apSuite, receivedAttribute2 == expectedAttribute2); + } delegate.mNumAttributeResponse = 0; } @@ -555,11 +693,49 @@ void TestReadInteraction::TestReadSubscribeAttributeResponseWithCache(nlTestSuit NL_TEST_ASSERT(apSuite, delegate.mNumAttributeResponse == 1); NL_TEST_ASSERT(apSuite, !delegate.mReadError); Optional version1; - NL_TEST_ASSERT(apSuite, cache.GetVersion(Test::kMockEndpoint2, Test::MockClusterId(3), version1) == CHIP_NO_ERROR); + app::ConcreteClusterPath clusterPath1(Test::kMockEndpoint2, Test::MockClusterId(3)); + NL_TEST_ASSERT(apSuite, cache.GetVersion(clusterPath1, version1) == CHIP_NO_ERROR); NL_TEST_ASSERT(apSuite, version1.HasValue() && (version1.Value() == 0)); Optional version2; - NL_TEST_ASSERT(apSuite, cache.GetVersion(Test::kMockEndpoint3, Test::MockClusterId(2), version2) == CHIP_NO_ERROR); + app::ConcreteClusterPath clusterPath2(Test::kMockEndpoint3, Test::MockClusterId(2)); + NL_TEST_ASSERT(apSuite, cache.GetVersion(clusterPath2, version2) == CHIP_NO_ERROR); NL_TEST_ASSERT(apSuite, !version2.HasValue()); + + { + app::ConcreteAttributePath attributePath(Test::kMockEndpoint2, Test::MockClusterId(3), Test::MockAttributeId(1)); + TLV::TLVReader reader; + NL_TEST_ASSERT(apSuite, cache.Get(attributePath, reader) == CHIP_NO_ERROR); + bool receivedAttribute1; + reader.Get(receivedAttribute1); + NL_TEST_ASSERT(apSuite, receivedAttribute1 == expectedAttribute1); + } + + { + app::ConcreteAttributePath attributePath(Test::kMockEndpoint2, Test::MockClusterId(3), Test::MockAttributeId(2)); + TLV::TLVReader reader; + NL_TEST_ASSERT(apSuite, cache.Get(attributePath, reader) == CHIP_NO_ERROR); + int16_t receivedAttribute2; + reader.Get(receivedAttribute2); + NL_TEST_ASSERT(apSuite, receivedAttribute2 == expectedAttribute2); + } + + { + app::ConcreteAttributePath attributePath(Test::kMockEndpoint2, Test::MockClusterId(3), Test::MockAttributeId(3)); + TLV::TLVReader reader; + NL_TEST_ASSERT(apSuite, cache.Get(attributePath, reader) == CHIP_NO_ERROR); + uint64_t receivedAttribute3; + reader.Get(receivedAttribute3); + NL_TEST_ASSERT(apSuite, receivedAttribute3 == expectedAttribute3); + } + + { + app::ConcreteAttributePath attributePath(Test::kMockEndpoint3, Test::MockClusterId(2), Test::MockAttributeId(2)); + TLV::TLVReader reader; + NL_TEST_ASSERT(apSuite, cache.Get(attributePath, reader) == CHIP_NO_ERROR); + int16_t receivedAttribute2; + reader.Get(receivedAttribute2); + NL_TEST_ASSERT(apSuite, receivedAttribute2 == expectedAttribute2); + } delegate.mNumAttributeResponse = 0; } @@ -595,11 +771,40 @@ void TestReadInteraction::TestReadSubscribeAttributeResponseWithCache(nlTestSuit NL_TEST_ASSERT(apSuite, delegate.mNumAttributeResponse == 3); NL_TEST_ASSERT(apSuite, !delegate.mReadError); Optional version1; - NL_TEST_ASSERT(apSuite, cache.GetVersion(Test::kMockEndpoint2, Test::MockClusterId(3), version1) == CHIP_NO_ERROR); + app::ConcreteClusterPath clusterPath1(Test::kMockEndpoint2, Test::MockClusterId(3)); + NL_TEST_ASSERT(apSuite, cache.GetVersion(clusterPath1, version1) == CHIP_NO_ERROR); NL_TEST_ASSERT(apSuite, !version1.HasValue()); Optional version2; - NL_TEST_ASSERT(apSuite, cache.GetVersion(Test::kMockEndpoint3, Test::MockClusterId(2), version2) == CHIP_NO_ERROR); + app::ConcreteClusterPath clusterPath2(Test::kMockEndpoint3, Test::MockClusterId(2)); + NL_TEST_ASSERT(apSuite, cache.GetVersion(clusterPath2, version2) == CHIP_NO_ERROR); NL_TEST_ASSERT(apSuite, !version2.HasValue()); + + { + app::ConcreteAttributePath attributePath(Test::kMockEndpoint2, Test::MockClusterId(3), Test::MockAttributeId(1)); + TLV::TLVReader reader; + NL_TEST_ASSERT(apSuite, cache.Get(attributePath, reader) == CHIP_NO_ERROR); + bool receivedAttribute1; + reader.Get(receivedAttribute1); + NL_TEST_ASSERT(apSuite, receivedAttribute1 == expectedAttribute1); + } + + { + app::ConcreteAttributePath attributePath(Test::kMockEndpoint2, Test::MockClusterId(3), Test::MockAttributeId(2)); + TLV::TLVReader reader; + NL_TEST_ASSERT(apSuite, cache.Get(attributePath, reader) == CHIP_NO_ERROR); + int16_t receivedAttribute2; + reader.Get(receivedAttribute2); + NL_TEST_ASSERT(apSuite, receivedAttribute2 == expectedAttribute2); + } + + { + app::ConcreteAttributePath attributePath(Test::kMockEndpoint3, Test::MockClusterId(2), Test::MockAttributeId(2)); + TLV::TLVReader reader; + NL_TEST_ASSERT(apSuite, cache.Get(attributePath, reader) == CHIP_NO_ERROR); + int16_t receivedAttribute2; + reader.Get(receivedAttribute2); + NL_TEST_ASSERT(apSuite, receivedAttribute2 == expectedAttribute2); + } delegate.mNumAttributeResponse = 0; } @@ -632,11 +837,40 @@ void TestReadInteraction::TestReadSubscribeAttributeResponseWithCache(nlTestSuit NL_TEST_ASSERT(apSuite, delegate.mNumAttributeResponse == 3); NL_TEST_ASSERT(apSuite, !delegate.mReadError); Optional version1; - NL_TEST_ASSERT(apSuite, cache.GetVersion(Test::kMockEndpoint2, Test::MockClusterId(3), version1) == CHIP_NO_ERROR); + app::ConcreteClusterPath clusterPath1(Test::kMockEndpoint2, Test::MockClusterId(3)); + NL_TEST_ASSERT(apSuite, cache.GetVersion(clusterPath1, version1) == CHIP_NO_ERROR); NL_TEST_ASSERT(apSuite, !version1.HasValue()); Optional version2; - NL_TEST_ASSERT(apSuite, cache.GetVersion(Test::kMockEndpoint3, Test::MockClusterId(2), version2) == CHIP_NO_ERROR); + app::ConcreteClusterPath clusterPath2(Test::kMockEndpoint3, Test::MockClusterId(2)); + NL_TEST_ASSERT(apSuite, cache.GetVersion(clusterPath2, version2) == CHIP_NO_ERROR); NL_TEST_ASSERT(apSuite, !version2.HasValue()); + + { + app::ConcreteAttributePath attributePath(Test::kMockEndpoint2, Test::MockClusterId(3), Test::MockAttributeId(1)); + TLV::TLVReader reader; + NL_TEST_ASSERT(apSuite, cache.Get(attributePath, reader) == CHIP_NO_ERROR); + bool receivedAttribute1; + reader.Get(receivedAttribute1); + NL_TEST_ASSERT(apSuite, receivedAttribute1 == expectedAttribute1); + } + + { + app::ConcreteAttributePath attributePath(Test::kMockEndpoint2, Test::MockClusterId(3), Test::MockAttributeId(2)); + TLV::TLVReader reader; + NL_TEST_ASSERT(apSuite, cache.Get(attributePath, reader) == CHIP_NO_ERROR); + int16_t receivedAttribute2; + reader.Get(receivedAttribute2); + NL_TEST_ASSERT(apSuite, receivedAttribute2 == expectedAttribute2); + } + + { + app::ConcreteAttributePath attributePath(Test::kMockEndpoint3, Test::MockClusterId(2), Test::MockAttributeId(2)); + TLV::TLVReader reader; + NL_TEST_ASSERT(apSuite, cache.Get(attributePath, reader) == CHIP_NO_ERROR); + int16_t receivedAttribute2; + reader.Get(receivedAttribute2); + NL_TEST_ASSERT(apSuite, receivedAttribute2 == expectedAttribute2); + } delegate.mNumAttributeResponse = 0; } @@ -664,11 +898,49 @@ void TestReadInteraction::TestReadSubscribeAttributeResponseWithCache(nlTestSuit NL_TEST_ASSERT(apSuite, delegate.mNumAttributeResponse == 6); NL_TEST_ASSERT(apSuite, !delegate.mReadError); Optional version1; - NL_TEST_ASSERT(apSuite, cache.GetVersion(Test::kMockEndpoint2, Test::MockClusterId(3), version1) == CHIP_NO_ERROR); + app::ConcreteClusterPath clusterPath1(Test::kMockEndpoint2, Test::MockClusterId(3)); + NL_TEST_ASSERT(apSuite, cache.GetVersion(clusterPath1, version1) == CHIP_NO_ERROR); NL_TEST_ASSERT(apSuite, version1.HasValue() && (version1.Value() == 1)); Optional version2; - NL_TEST_ASSERT(apSuite, cache.GetVersion(Test::kMockEndpoint3, Test::MockClusterId(2), version2) == CHIP_NO_ERROR); + app::ConcreteClusterPath clusterPath2(Test::kMockEndpoint3, Test::MockClusterId(2)); + NL_TEST_ASSERT(apSuite, cache.GetVersion(clusterPath2, version2) == CHIP_NO_ERROR); NL_TEST_ASSERT(apSuite, !version2.HasValue()); + + { + app::ConcreteAttributePath attributePath(Test::kMockEndpoint2, Test::MockClusterId(3), Test::MockAttributeId(1)); + TLV::TLVReader reader; + NL_TEST_ASSERT(apSuite, cache.Get(attributePath, reader) == CHIP_NO_ERROR); + bool receivedAttribute1; + reader.Get(receivedAttribute1); + NL_TEST_ASSERT(apSuite, receivedAttribute1 == expectedAttribute1); + } + + { + app::ConcreteAttributePath attributePath(Test::kMockEndpoint2, Test::MockClusterId(3), Test::MockAttributeId(2)); + TLV::TLVReader reader; + NL_TEST_ASSERT(apSuite, cache.Get(attributePath, reader) == CHIP_NO_ERROR); + int16_t receivedAttribute2; + reader.Get(receivedAttribute2); + NL_TEST_ASSERT(apSuite, receivedAttribute2 == expectedAttribute2); + } + + { + app::ConcreteAttributePath attributePath(Test::kMockEndpoint2, Test::MockClusterId(3), Test::MockAttributeId(3)); + TLV::TLVReader reader; + NL_TEST_ASSERT(apSuite, cache.Get(attributePath, reader) == CHIP_NO_ERROR); + uint64_t receivedAttribute3; + reader.Get(receivedAttribute3); + NL_TEST_ASSERT(apSuite, receivedAttribute3 == expectedAttribute3); + } + + { + app::ConcreteAttributePath attributePath(Test::kMockEndpoint3, Test::MockClusterId(2), Test::MockAttributeId(2)); + TLV::TLVReader reader; + NL_TEST_ASSERT(apSuite, cache.Get(attributePath, reader) == CHIP_NO_ERROR); + int16_t receivedAttribute2; + reader.Get(receivedAttribute2); + NL_TEST_ASSERT(apSuite, receivedAttribute2 == expectedAttribute2); + } delegate.mNumAttributeResponse = 0; } @@ -701,11 +973,49 @@ void TestReadInteraction::TestReadSubscribeAttributeResponseWithCache(nlTestSuit NL_TEST_ASSERT(apSuite, delegate.mNumAttributeResponse == 6); NL_TEST_ASSERT(apSuite, !delegate.mReadError); Optional version1; - NL_TEST_ASSERT(apSuite, cache.GetVersion(Test::kMockEndpoint2, Test::MockClusterId(3), version1) == CHIP_NO_ERROR); + app::ConcreteClusterPath clusterPath1(Test::kMockEndpoint2, Test::MockClusterId(3)); + NL_TEST_ASSERT(apSuite, cache.GetVersion(clusterPath1, version1) == CHIP_NO_ERROR); NL_TEST_ASSERT(apSuite, version1.HasValue() && (version1.Value() == 1)); Optional version2; - NL_TEST_ASSERT(apSuite, cache.GetVersion(Test::kMockEndpoint3, Test::MockClusterId(2), version2) == CHIP_NO_ERROR); + app::ConcreteClusterPath clusterPath2(Test::kMockEndpoint3, Test::MockClusterId(2)); + NL_TEST_ASSERT(apSuite, cache.GetVersion(clusterPath2, version2) == CHIP_NO_ERROR); NL_TEST_ASSERT(apSuite, !version2.HasValue()); + + { + app::ConcreteAttributePath attributePath(Test::kMockEndpoint2, Test::MockClusterId(3), Test::MockAttributeId(1)); + TLV::TLVReader reader; + NL_TEST_ASSERT(apSuite, cache.Get(attributePath, reader) == CHIP_NO_ERROR); + bool receivedAttribute1; + reader.Get(receivedAttribute1); + NL_TEST_ASSERT(apSuite, receivedAttribute1 == expectedAttribute1); + } + + { + app::ConcreteAttributePath attributePath(Test::kMockEndpoint2, Test::MockClusterId(3), Test::MockAttributeId(2)); + TLV::TLVReader reader; + NL_TEST_ASSERT(apSuite, cache.Get(attributePath, reader) == CHIP_NO_ERROR); + int16_t receivedAttribute2; + reader.Get(receivedAttribute2); + NL_TEST_ASSERT(apSuite, receivedAttribute2 == expectedAttribute2); + } + + { + app::ConcreteAttributePath attributePath(Test::kMockEndpoint2, Test::MockClusterId(3), Test::MockAttributeId(3)); + TLV::TLVReader reader; + NL_TEST_ASSERT(apSuite, cache.Get(attributePath, reader) == CHIP_NO_ERROR); + uint64_t receivedAttribute3; + reader.Get(receivedAttribute3); + NL_TEST_ASSERT(apSuite, receivedAttribute3 == expectedAttribute3); + } + + { + app::ConcreteAttributePath attributePath(Test::kMockEndpoint3, Test::MockClusterId(2), Test::MockAttributeId(2)); + TLV::TLVReader reader; + NL_TEST_ASSERT(apSuite, cache.Get(attributePath, reader) == CHIP_NO_ERROR); + int16_t receivedAttribute2; + reader.Get(receivedAttribute2); + NL_TEST_ASSERT(apSuite, receivedAttribute2 == expectedAttribute2); + } delegate.mNumAttributeResponse = 0; readPrepareParams.mpEventPathParamsList = nullptr; readPrepareParams.mEventPathParamsListSize = 0; @@ -744,14 +1054,71 @@ void TestReadInteraction::TestReadSubscribeAttributeResponseWithCache(nlTestSuit NL_TEST_ASSERT(apSuite, delegate.mNumAttributeResponse == 12); NL_TEST_ASSERT(apSuite, !delegate.mReadError); Optional version1; - NL_TEST_ASSERT(apSuite, cache.GetVersion(Test::kMockEndpoint2, Test::MockClusterId(3), version1) == CHIP_NO_ERROR); + app::ConcreteClusterPath clusterPath1(Test::kMockEndpoint2, Test::MockClusterId(3)); + NL_TEST_ASSERT(apSuite, cache.GetVersion(clusterPath1, version1) == CHIP_NO_ERROR); NL_TEST_ASSERT(apSuite, version1.HasValue() && (version1.Value() == 2)); Optional version2; - NL_TEST_ASSERT(apSuite, cache.GetVersion(Test::kMockEndpoint2, Test::MockClusterId(2), version2) == CHIP_NO_ERROR); + app::ConcreteClusterPath clusterPath2(Test::kMockEndpoint2, Test::MockClusterId(2)); + NL_TEST_ASSERT(apSuite, cache.GetVersion(clusterPath2, version2) == CHIP_NO_ERROR); NL_TEST_ASSERT(apSuite, version2.HasValue() && (version2.Value() == 2)); Optional version3; - NL_TEST_ASSERT(apSuite, cache.GetVersion(Test::kMockEndpoint1, Test::MockClusterId(2), version3) == CHIP_NO_ERROR); + app::ConcreteClusterPath clusterPath3(Test::kMockEndpoint1, Test::MockClusterId(2)); + NL_TEST_ASSERT(apSuite, cache.GetVersion(clusterPath3, version3) == CHIP_NO_ERROR); NL_TEST_ASSERT(apSuite, version3.HasValue() && (version3.Value() == 2)); + + { + app::ConcreteAttributePath attributePath(Test::kMockEndpoint1, Test::MockClusterId(2), Test::MockAttributeId(1)); + TLV::TLVReader reader; + NL_TEST_ASSERT(apSuite, cache.Get(attributePath, reader) == CHIP_NO_ERROR); + bool receivedAttribute1; + reader.Get(receivedAttribute1); + NL_TEST_ASSERT(apSuite, receivedAttribute1 == expectedAttribute1); + } + + { + app::ConcreteAttributePath attributePath(Test::kMockEndpoint2, Test::MockClusterId(3), Test::MockAttributeId(1)); + TLV::TLVReader reader; + NL_TEST_ASSERT(apSuite, cache.Get(attributePath, reader) == CHIP_NO_ERROR); + bool receivedAttribute1; + reader.Get(receivedAttribute1); + NL_TEST_ASSERT(apSuite, receivedAttribute1 == expectedAttribute1); + } + + { + app::ConcreteAttributePath attributePath(Test::kMockEndpoint2, Test::MockClusterId(3), Test::MockAttributeId(2)); + TLV::TLVReader reader; + NL_TEST_ASSERT(apSuite, cache.Get(attributePath, reader) == CHIP_NO_ERROR); + int16_t receivedAttribute2; + reader.Get(receivedAttribute2); + NL_TEST_ASSERT(apSuite, receivedAttribute2 == expectedAttribute2); + } + + { + app::ConcreteAttributePath attributePath(Test::kMockEndpoint2, Test::MockClusterId(3), Test::MockAttributeId(3)); + TLV::TLVReader reader; + NL_TEST_ASSERT(apSuite, cache.Get(attributePath, reader) == CHIP_NO_ERROR); + uint64_t receivedAttribute3; + reader.Get(receivedAttribute3); + NL_TEST_ASSERT(apSuite, receivedAttribute3 == expectedAttribute3); + } + + { + app::ConcreteAttributePath attributePath(Test::kMockEndpoint2, Test::MockClusterId(2), Test::MockAttributeId(1)); + TLV::TLVReader reader; + NL_TEST_ASSERT(apSuite, cache.Get(attributePath, reader) == CHIP_NO_ERROR); + bool receivedAttribute1; + reader.Get(receivedAttribute1); + NL_TEST_ASSERT(apSuite, receivedAttribute1 == expectedAttribute1); + } + { + app::ConcreteAttributePath attributePath(Test::kMockEndpoint2, Test::MockClusterId(2), Test::MockAttributeId(2)); + TLV::TLVReader reader; + NL_TEST_ASSERT(apSuite, cache.Get(attributePath, reader) == CHIP_NO_ERROR); + int16_t receivedAttribute2; + reader.Get(receivedAttribute2); + NL_TEST_ASSERT(apSuite, receivedAttribute2 == expectedAttribute2); + } + delegate.mNumAttributeResponse = 0; } @@ -788,19 +1155,139 @@ void TestReadInteraction::TestReadSubscribeAttributeResponseWithCache(nlTestSuit NL_TEST_ASSERT(apSuite, delegate.mNumAttributeResponse == 7); NL_TEST_ASSERT(apSuite, !delegate.mReadError); Optional version1; - NL_TEST_ASSERT(apSuite, cache.GetVersion(Test::kMockEndpoint2, Test::MockClusterId(3), version1) == CHIP_NO_ERROR); + app::ConcreteClusterPath clusterPath1(Test::kMockEndpoint2, Test::MockClusterId(3)); + NL_TEST_ASSERT(apSuite, cache.GetVersion(clusterPath1, version1) == CHIP_NO_ERROR); NL_TEST_ASSERT(apSuite, version1.HasValue() && (version1.Value() == 2)); Optional version2; - NL_TEST_ASSERT(apSuite, cache.GetVersion(Test::kMockEndpoint2, Test::MockClusterId(2), version2) == CHIP_NO_ERROR); + app::ConcreteClusterPath clusterPath2(Test::kMockEndpoint2, Test::MockClusterId(2)); + NL_TEST_ASSERT(apSuite, cache.GetVersion(clusterPath2, version2) == CHIP_NO_ERROR); NL_TEST_ASSERT(apSuite, version2.HasValue() && (version2.Value() == 2)); Optional version3; - NL_TEST_ASSERT(apSuite, cache.GetVersion(Test::kMockEndpoint1, Test::MockClusterId(2), version3) == CHIP_NO_ERROR); + app::ConcreteClusterPath clusterPath3(Test::kMockEndpoint1, Test::MockClusterId(2)); + NL_TEST_ASSERT(apSuite, cache.GetVersion(clusterPath3, version3) == CHIP_NO_ERROR); NL_TEST_ASSERT(apSuite, version3.HasValue() && (version3.Value() == 2)); + + { + app::ConcreteAttributePath attributePath(Test::kMockEndpoint1, Test::MockClusterId(2), Test::MockAttributeId(1)); + TLV::TLVReader reader; + NL_TEST_ASSERT(apSuite, cache.Get(attributePath, reader) == CHIP_NO_ERROR); + bool receivedAttribute1; + reader.Get(receivedAttribute1); + NL_TEST_ASSERT(apSuite, receivedAttribute1 == expectedAttribute1); + } + + { + app::ConcreteAttributePath attributePath(Test::kMockEndpoint2, Test::MockClusterId(3), Test::MockAttributeId(1)); + TLV::TLVReader reader; + NL_TEST_ASSERT(apSuite, cache.Get(attributePath, reader) == CHIP_NO_ERROR); + bool receivedAttribute1; + reader.Get(receivedAttribute1); + NL_TEST_ASSERT(apSuite, receivedAttribute1 == expectedAttribute1); + } + + { + app::ConcreteAttributePath attributePath(Test::kMockEndpoint2, Test::MockClusterId(3), Test::MockAttributeId(2)); + TLV::TLVReader reader; + NL_TEST_ASSERT(apSuite, cache.Get(attributePath, reader) == CHIP_NO_ERROR); + int16_t receivedAttribute2; + reader.Get(receivedAttribute2); + NL_TEST_ASSERT(apSuite, receivedAttribute2 == expectedAttribute2); + } + + { + app::ConcreteAttributePath attributePath(Test::kMockEndpoint2, Test::MockClusterId(3), Test::MockAttributeId(3)); + TLV::TLVReader reader; + NL_TEST_ASSERT(apSuite, cache.Get(attributePath, reader) == CHIP_NO_ERROR); + uint64_t receivedAttribute3; + reader.Get(receivedAttribute3); + NL_TEST_ASSERT(apSuite, receivedAttribute3 == expectedAttribute3); + } + + { + app::ConcreteAttributePath attributePath(Test::kMockEndpoint2, Test::MockClusterId(2), Test::MockAttributeId(1)); + TLV::TLVReader reader; + NL_TEST_ASSERT(apSuite, cache.Get(attributePath, reader) == CHIP_NO_ERROR); + bool receivedAttribute1; + reader.Get(receivedAttribute1); + NL_TEST_ASSERT(apSuite, receivedAttribute1 == expectedAttribute1); + } + + { + app::ConcreteAttributePath attributePath(Test::kMockEndpoint2, Test::MockClusterId(2), Test::MockAttributeId(2)); + TLV::TLVReader reader; + NL_TEST_ASSERT(apSuite, cache.Get(attributePath, reader) == CHIP_NO_ERROR); + int16_t receivedAttribute2; + reader.Get(receivedAttribute2); + NL_TEST_ASSERT(apSuite, receivedAttribute2 == expectedAttribute2); + } delegate.mNumAttributeResponse = 0; readPrepareParams.mpEventPathParamsList = nullptr; readPrepareParams.mEventPathParamsListSize = 0; } + // Read of E3C2 which has a oversized list attribute, MockAttributeId (4). It would use none stored data versions in the cache + // since previous read does not cache any committed data version for E3C2, and expect to cache E3C2's version + { + testId++; + ChipLogProgress(DataManagement, "\t -- Running Read with ClusterStateCache Test ID %d", testId); + app::ReadClient readClient(chip::app::InteractionModelEngine::GetInstance(), &ctx.GetExchangeManager(), + cache.GetBufferedCallback(), chip::app::ReadClient::InteractionType::Read); + chip::app::AttributePathParams attributePathParams1[1]; + attributePathParams1[0].mEndpointId = Test::kMockEndpoint3; + attributePathParams1[0].mClusterId = Test::MockClusterId(2); + + readPrepareParams.mpAttributePathParamsList = attributePathParams1; + readPrepareParams.mAttributePathParamsListSize = 1; + err = readClient.SendRequest(readPrepareParams); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); + + ctx.DrainAndServiceIO(); + NL_TEST_ASSERT(apSuite, delegate.mNumAttributeResponse == 6); + NL_TEST_ASSERT(apSuite, !delegate.mReadError); + Optional version1; + app::ConcreteClusterPath clusterPath(Test::kMockEndpoint3, Test::MockClusterId(2)); + + NL_TEST_ASSERT(apSuite, cache.GetVersion(clusterPath, version1) == CHIP_NO_ERROR); + NL_TEST_ASSERT(apSuite, version1.HasValue()); + + { + app::ConcreteAttributePath attributePath(Test::kMockEndpoint3, Test::MockClusterId(2), Test::MockAttributeId(1)); + TLV::TLVReader reader; + NL_TEST_ASSERT(apSuite, cache.Get(attributePath, reader) == CHIP_NO_ERROR); + bool receivedAttribute1; + reader.Get(receivedAttribute1); + NL_TEST_ASSERT(apSuite, receivedAttribute1 == expectedAttribute1); + } + + { + app::ConcreteAttributePath attributePath(Test::kMockEndpoint3, Test::MockClusterId(2), Test::MockAttributeId(2)); + TLV::TLVReader reader; + NL_TEST_ASSERT(apSuite, cache.Get(attributePath, reader) == CHIP_NO_ERROR); + int16_t receivedAttribute2; + reader.Get(receivedAttribute2); + NL_TEST_ASSERT(apSuite, receivedAttribute2 == expectedAttribute2); + } + + { + app::ConcreteAttributePath attributePath(Test::kMockEndpoint3, Test::MockClusterId(2), Test::MockAttributeId(3)); + TLV::TLVReader reader; + NL_TEST_ASSERT(apSuite, cache.Get(attributePath, reader) == CHIP_NO_ERROR); + uint64_t receivedAttribute3; + reader.Get(receivedAttribute3); + NL_TEST_ASSERT(apSuite, receivedAttribute3 == expectedAttribute3); + } + + { + app::ConcreteAttributePath attributePath(Test::kMockEndpoint3, Test::MockClusterId(2), Test::MockAttributeId(4)); + TLV::TLVReader reader; + NL_TEST_ASSERT(apSuite, cache.Get(attributePath, reader) == CHIP_NO_ERROR); + uint8_t receivedAttribute4[256]; + reader.GetBytes(receivedAttribute4, 256); + NL_TEST_ASSERT(apSuite, memcmp(receivedAttribute4, expectedAttribute4, 256)); + } + delegate.mNumAttributeResponse = 0; + } + NL_TEST_ASSERT(apSuite, app::InteractionModelEngine::GetInstance()->GetNumActiveReadClients() == 0); NL_TEST_ASSERT(apSuite, ctx.GetExchangeManager().GetNumActiveExchanges() == 0); } diff --git a/src/lib/core/CHIPTLV.h b/src/lib/core/CHIPTLV.h index eaff1c29b9fee7..f507294435d4a8 100644 --- a/src/lib/core/CHIPTLV.h +++ b/src/lib/core/CHIPTLV.h @@ -839,12 +839,19 @@ class DLL_EXPORT TLVReader */ uint32_t GetRemainingLength() const { return mMaxLen - mLenRead; } + /** + * Return the total number of bytes for the TLV data + * @return the total number of bytes for the TLV data + */ + uint32_t GetTotalLength() const { return mMaxLen; } + /** * Returns the stored backing store. * * @return the stored backing store. */ TLVBackingStore * GetBackingStore() { return mBackingStore; } + /** * Gets the point in the underlying input buffer that corresponds to the reader's current position. * diff --git a/src/lib/support/ScopedBuffer.h b/src/lib/support/ScopedBuffer.h index ead4c563946e1d..5e1d10ec0d7037 100644 --- a/src/lib/support/ScopedBuffer.h +++ b/src/lib/support/ScopedBuffer.h @@ -160,5 +160,65 @@ class ScopedMemoryBuffer : public Impl::ScopedMemoryBufferBase } }; +/** + * Represents a memory buffer with buffer size allocated using chip::Platform::Memory*Alloc + * methods. + * + * Use for RAII to auto-free after use. + */ +template +class ScopedMemoryBufferWithSize : public ScopedMemoryBuffer +{ +public: + ScopedMemoryBufferWithSize() {} + ScopedMemoryBufferWithSize(ScopedMemoryBufferWithSize && other) { *this = std::move(other); } + + ScopedMemoryBufferWithSize & operator=(ScopedMemoryBufferWithSize && other) + { + if (this != &other) + { + mSize = other.mSize; + other.mSize = 0; + } + ScopedMemoryBuffer::operator=(std::move(other)); + return *this; + } + + ~ScopedMemoryBufferWithSize() { mSize = 0; } + + // return the size in bytes + inline size_t BufferByteSize() const { return mSize; } + + T * Release() + { + T * buffer = ScopedMemoryBuffer::Release(); + mSize = 0; + return buffer; + } + + ScopedMemoryBufferWithSize & Calloc(size_t elementCount) + { + ScopedMemoryBuffer::Calloc(elementCount); + if (this->Get() != nullptr) + { + mSize = elementCount * sizeof(T); + } + return *this; + } + + ScopedMemoryBufferWithSize & Alloc(size_t size) + { + ScopedMemoryBuffer::Alloc(size); + if (this->Get() != nullptr) + { + mSize = size * sizeof(T); + } + return *this; + } + +private: + size_t mSize = 0; +}; + } // namespace Platform } // namespace chip