/* * Copyright (c) 2024 Project CHIP Authors * * 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 #include #include #include #include #include #include #include #include #include #include using namespace chip::app::DataModel; namespace chip { uint8_t Test::attributeDataTLV[CHIP_CONFIG_DEFAULT_UDP_MTU_SIZE]; size_t Test::attributeDataTLVLen = 0; namespace app { class TestOnlyAttributeValueEncoderAccessor { public: TestOnlyAttributeValueEncoderAccessor(AttributeValueEncoder & encoder) : mEncoder(encoder) {} AttributeReportIBs::Builder & Builder() { return mEncoder.mAttributeReportIBsBuilder; } void SetState(const AttributeEncodeState & state) { mEncoder.mEncodeState = state; } private: AttributeValueEncoder & mEncoder; }; class TestOnlyAttributeValueDecoderAccessor { public: TestOnlyAttributeValueDecoderAccessor(AttributeValueDecoder & decoder) : mDecoder(decoder) {} TLV::TLVReader & GetTlvReader() { return mDecoder.mReader; } void SetTriedDecode(bool triedDecode) { mDecoder.mTriedDecode = triedDecode; } private: AttributeValueDecoder & mDecoder; }; // Used by the code in TestWriteInteraction.cpp (and generally tests that interact with the WriteHandler may need this). 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; } // Used by the code in TestWriteInteraction.cpp (and generally tests that interact with the WriteHandler may need this). CHIP_ERROR WriteSingleClusterData(const Access::SubjectDescriptor & aSubjectDescriptor, const ConcreteDataAttributePath & aPath, TLV::TLVReader & aReader, WriteHandler * aWriteHandler) { if (aPath.mDataVersion.HasValue() && aPath.mDataVersion.Value() == Test::kRejectedDataVersion) { return aWriteHandler->AddStatus(aPath, Protocols::InteractionModel::Status::DataVersionMismatch); } TLV::TLVWriter writer; writer.Init(chip::Test::attributeDataTLV); writer.CopyElement(TLV::AnonymousTag(), aReader); chip::Test::attributeDataTLVLen = writer.GetLengthWritten(); return aWriteHandler->AddStatus(aPath, Protocols::InteractionModel::Status::Success); } // Used by the code in TestAclAttribute.cpp (and generally tests that interact with the InteractionModelEngine may need this). bool ConcreteAttributePathExists(const ConcreteAttributePath & aPath) { return aPath.mClusterId != Test::kTestDeniedClusterId1; } // Used by the code in TestAclAttribute.cpp (and generally tests that interact with the InteractionModelEngine may need this). Protocols::InteractionModel::Status CheckEventSupportStatus(const ConcreteEventPath & aPath) { if (aPath.mClusterId == Test::kTestDeniedClusterId1) { return Protocols::InteractionModel::Status::UnsupportedCluster; } return Protocols::InteractionModel::Status::Success; } // strong defintion in TestCommandInteraction.cpp __attribute__((weak)) Protocols::InteractionModel::Status ServerClusterCommandExists(const ConcreteCommandPath & aRequestCommandPath) { // Mock cluster catalog, only support commands on one cluster on one endpoint. using Protocols::InteractionModel::Status; return Status::Success; } // strong defintion in TestCommandInteraction.cpp __attribute__((weak)) void DispatchSingleClusterCommand(const ConcreteCommandPath & aRequestCommandPath, chip::TLV::TLVReader & aReader, CommandHandler * apCommandObj) {} // Used by the code in TestReadInteraction.cpp (and generally tests that interact with the Reporting Engine may need this). bool IsClusterDataVersionEqual(const ConcreteClusterPath & aConcreteClusterPath, DataVersion aRequiredVersion) { return (Test::kTestDataVersion1 == aRequiredVersion); } // Used by the code in TestReadInteraction.cpp. bool IsDeviceTypeOnEndpoint(DeviceTypeId deviceType, EndpointId endpoint) { return false; } // Used by the code in TestReadInteraction.cpp (and generally tests that interact with the Reporting Engine may need this). CHIP_ERROR ReadSingleClusterData(const Access::SubjectDescriptor & aSubjectDescriptor, bool aIsFabricFiltered, const ConcreteReadAttributePath & aPath, AttributeReportIBs::Builder & aAttributeReports, AttributeEncodeState * apEncoderState) { if (aPath.mClusterId >= Test::kMockEndpointMin) { return Test::ReadSingleMockClusterData(aSubjectDescriptor.fabricIndex, aPath, aAttributeReports, apEncoderState); } if (!(aPath.mClusterId == Test::kTestClusterId && aPath.mEndpointId == Test::kTestEndpointId)) { AttributeReportIB::Builder & attributeReport = aAttributeReports.CreateAttributeReport(); ReturnErrorOnFailure(aAttributeReports.GetError()); ChipLogDetail(DataManagement, "TEST Cluster %" PRIx32 ", Field %" PRIx32 " is dirty", aPath.mClusterId, aPath.mAttributeId); AttributeStatusIB::Builder & attributeStatus = attributeReport.CreateAttributeStatus(); ReturnErrorOnFailure(attributeReport.GetError()); AttributePathIB::Builder & attributePath = attributeStatus.CreatePath(); ReturnErrorOnFailure(attributeStatus.GetError()); 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::UnsupportedAttribute)); ReturnErrorOnFailure(errorStatus.GetError()); ReturnErrorOnFailure(attributeStatus.EndOfAttributeStatusIB()); return attributeReport.EndOfAttributeReportIB(); } return AttributeValueEncoder(aAttributeReports, aSubjectDescriptor, aPath, 0 /* dataVersion */).Encode(Test::kTestFieldValue1); } TestImCustomDataModel & TestImCustomDataModel::Instance() { static TestImCustomDataModel model; return model; } ActionReturnStatus TestImCustomDataModel::ReadAttribute(const ReadAttributeRequest & request, AttributeValueEncoder & encoder) { AttributeEncodeState mutableState(&encoder.GetState()); // provide a state copy to start. CHIP_ERROR err = ReadSingleClusterData(request.subjectDescriptor.value_or(Access::SubjectDescriptor()), request.readFlags.Has(ReadFlags::kFabricFiltered), request.path, TestOnlyAttributeValueEncoderAccessor(encoder).Builder(), &mutableState); // state must survive CHIP_ERRORs as it is used for chunking TestOnlyAttributeValueEncoderAccessor(encoder).SetState(mutableState); return err; } ActionReturnStatus TestImCustomDataModel::WriteAttribute(const WriteAttributeRequest & request, AttributeValueDecoder & decoder) { if (request.path.mDataVersion.HasValue() && request.path.mDataVersion.Value() == Test::kRejectedDataVersion) { return CHIP_IM_GLOBAL_STATUS(DataVersionMismatch); } TestOnlyAttributeValueDecoderAccessor decodeAccess(decoder); decodeAccess.SetTriedDecode(true); TLV::TLVWriter writer; writer.Init(chip::Test::attributeDataTLV); writer.CopyElement(TLV::AnonymousTag(), decodeAccess.GetTlvReader()); chip::Test::attributeDataTLVLen = writer.GetLengthWritten(); return CHIP_NO_ERROR; } std::optional TestImCustomDataModel::Invoke(const InvokeRequest & request, chip::TLV::TLVReader & input_arguments, CommandHandler * handler) { return std::make_optional(CHIP_ERROR_NOT_IMPLEMENTED); } EndpointId TestImCustomDataModel::FirstEndpoint() { return CodegenDataModelProviderInstance()->FirstEndpoint(); } EndpointId TestImCustomDataModel::NextEndpoint(EndpointId before) { return CodegenDataModelProviderInstance()->NextEndpoint(before); } std::optional TestImCustomDataModel::FirstDeviceType(EndpointId endpoint) { return std::nullopt; } std::optional TestImCustomDataModel::NextDeviceType(EndpointId endpoint, const DataModel::DeviceTypeEntry & previous) { return std::nullopt; } ClusterEntry TestImCustomDataModel::FirstCluster(EndpointId endpoint) { return CodegenDataModelProviderInstance()->FirstCluster(endpoint); } ClusterEntry TestImCustomDataModel::NextCluster(const ConcreteClusterPath & before) { return CodegenDataModelProviderInstance()->NextCluster(before); } std::optional TestImCustomDataModel::GetClusterInfo(const ConcreteClusterPath & path) { return CodegenDataModelProviderInstance()->GetClusterInfo(path); } AttributeEntry TestImCustomDataModel::FirstAttribute(const ConcreteClusterPath & cluster) { return CodegenDataModelProviderInstance()->FirstAttribute(cluster); } AttributeEntry TestImCustomDataModel::NextAttribute(const ConcreteAttributePath & before) { return CodegenDataModelProviderInstance()->NextAttribute(before); } std::optional TestImCustomDataModel::GetAttributeInfo(const ConcreteAttributePath & path) { return CodegenDataModelProviderInstance()->GetAttributeInfo(path); } CommandEntry TestImCustomDataModel::FirstAcceptedCommand(const ConcreteClusterPath & cluster) { return CodegenDataModelProviderInstance()->FirstAcceptedCommand(cluster); } CommandEntry TestImCustomDataModel::NextAcceptedCommand(const ConcreteCommandPath & before) { return CodegenDataModelProviderInstance()->NextAcceptedCommand(before); } std::optional TestImCustomDataModel::GetAcceptedCommandInfo(const ConcreteCommandPath & path) { return CodegenDataModelProviderInstance()->GetAcceptedCommandInfo(path); } ConcreteCommandPath TestImCustomDataModel::FirstGeneratedCommand(const ConcreteClusterPath & cluster) { return CodegenDataModelProviderInstance()->FirstGeneratedCommand(cluster); } ConcreteCommandPath TestImCustomDataModel::NextGeneratedCommand(const ConcreteCommandPath & before) { return CodegenDataModelProviderInstance()->NextGeneratedCommand(before); } } // namespace app } // namespace chip