blob: f483f4b3de88a42e7fb2dc191b478e5527137026 [file] [log] [blame]
/*
* 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 "app/data-model-provider/ActionReturnStatus.h"
#include <app/tests/test-interaction-model-api.h>
#include <app/InteractionModelEngine.h>
#include <app/MessageDef/AttributeReportIBs.h>
#include <app/codegen-data-model-provider/Instance.h>
#include <app/util/basic-types.h>
#include <app/util/mock/Constants.h>
#include <app/util/mock/Functions.h>
#include <lib/core/CHIPCore.h>
#include <messaging/ReliableMessageContext.h>
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;
};
// 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)
{
return CHIP_ERROR_NOT_IMPLEMENTED;
}
ActionReturnStatus TestImCustomDataModel::Invoke(const InvokeRequest & request, chip::TLV::TLVReader & input_arguments,
CommandHandler * handler)
{
return CHIP_ERROR_NOT_IMPLEMENTED;
}
EndpointId TestImCustomDataModel::FirstEndpoint()
{
return CodegenDataModelProviderInstance()->FirstEndpoint();
}
EndpointId TestImCustomDataModel::NextEndpoint(EndpointId before)
{
return CodegenDataModelProviderInstance()->NextEndpoint(before);
}
ClusterEntry TestImCustomDataModel::FirstCluster(EndpointId endpoint)
{
return CodegenDataModelProviderInstance()->FirstCluster(endpoint);
}
ClusterEntry TestImCustomDataModel::NextCluster(const ConcreteClusterPath & before)
{
return CodegenDataModelProviderInstance()->NextCluster(before);
}
std::optional<ClusterInfo> 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<AttributeInfo> 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<CommandInfo> 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