Remove a few more calls of IME to ember-compatibility. (#35749)
* Remove a few more calls of IME to ember-compatibility.
This works to move more logic into DataModel::Provider calls
to decouple interactionmodel engine from ember calls.
* Remove auto-include logic
* Some work to make tests actually pass. Starts adding CHI-based enumeration of commands
* Restyle
* Add unit tests and fixes for codgen data provider actually honoring the generated/accepted command callbacks
* Add support for using CommandHandlerInterface for accepted/generated commands.
Note that iteration is still O(N^2) which is not ideal, however at least
the use of this is infrequent and list of commands is somewhat short.
* Fix includes
* Comment update
* Comment update
* Make TestServerCommandDispatch pass
* Unit tests pass
* Remove unused include
* Remove unused include
* Restyled by clang-format
* Remove debug code
* Update src/app/InteractionModelEngine.cpp
Co-authored-by: Boris Zbarsky <bzbarsky@apple.com>
* Make TestRead actually pass
* Restyle
* Make TestAclAttribute pass
* make test reporting engine pass
* Undo hardcoding of attribute info and make test read interaction use a custom mock model
* Remove do not submit code
* Test passes now
* Restyle
* Config reset not used
* Better fix for TestCommandInteraction
* Restyle
* Fix up data model for test commands as well
* Self review: fix up includes
* Self review: fix up includes
* Self review: fix up includes
* Restyle
* DELETE IntnteractionModelTest.py and chip im-responder/im-initiator
* Method rename
* Revert "DELETE IntnteractionModelTest.py and chip im-responder/im-initiator"
This reverts commit 4a6dd205f27b9dd64ec77201084c8cf0a81b3fbd.
* Disable InteractionModelTest without deletion
---------
Co-authored-by: Andrei Litvin <andreilitvin@google.com>
Co-authored-by: Restyled.io <commits@restyled.io>
Co-authored-by: Boris Zbarsky <bzbarsky@apple.com>
diff --git a/scripts/tests/cirque_tests.sh b/scripts/tests/cirque_tests.sh
index a8be290..b7dcdbc 100755
--- a/scripts/tests/cirque_tests.sh
+++ b/scripts/tests/cirque_tests.sh
@@ -37,13 +37,17 @@
OT_SIMULATION_CACHE_STAMP_FILE="$CIRQUE_CACHE_PATH/ot-simulation.commit"
# Append test name here to add more tests for run_all_tests
+#
+# NOTE:
+# "InteractionModelTest" is currently disabled due to it overriding
+# internal data model methods (for example it says "CommandExists" for
+# paths where endpoint/cluster do not)
CIRQUE_TESTS=(
"EchoTest"
"EchoOverTcpTest"
"FailsafeTest"
"MobileDeviceTest"
"CommissioningTest"
- "InteractionModelTest"
"IcdWaitForActiveTest"
"SplitCommissioningTest"
"CommissioningFailureTest"
diff --git a/src/app/InteractionModelEngine.cpp b/src/app/InteractionModelEngine.cpp
index 6e4c041..e4c90b4 100644
--- a/src/app/InteractionModelEngine.cpp
+++ b/src/app/InteractionModelEngine.cpp
@@ -36,6 +36,7 @@
#include <app/util/af-types.h>
#include <app/util/ember-compatibility-functions.h>
#include <app/util/endpoint-config-api.h>
+#include <lib/core/DataModelTypes.h>
#include <lib/core/Global.h>
#include <lib/core/TLVUtilities.h>
#include <lib/support/CHIPFaultInjection.h>
@@ -515,7 +516,8 @@
{
ConcreteAttributePath concretePath(paramsList.mValue.mEndpointId, paramsList.mValue.mClusterId,
paramsList.mValue.mAttributeId);
- if (ConcreteAttributePathExists(concretePath))
+
+ if (IsExistentAttributePath(concretePath))
{
Access::RequestPath requestPath{ .cluster = concretePath.mClusterId,
.endpoint = concretePath.mEndpointId,
@@ -1584,16 +1586,19 @@
return err;
}
-bool InteractionModelEngine::IsExistingAttributePath(const ConcreteAttributePath & path)
+bool InteractionModelEngine::IsExistentAttributePath(const ConcreteAttributePath & path)
{
#if CHIP_CONFIG_USE_DATA_MODEL_INTERFACE
#if CHIP_CONFIG_USE_EMBER_DATA_MODEL
- // Ensure that Provider interface and ember are IDENTICAL in attribute location (i.e. "check" mode)
- VerifyOrDie(GetDataModelProvider()
- ->GetAttributeInfo(ConcreteAttributePath(path.mEndpointId, path.mClusterId, path.mAttributeId))
- .has_value() == emberAfContainsAttribute(path.mEndpointId, path.mClusterId, path.mAttributeId)
- );
+ bool providerResult = GetDataModelProvider()
+ ->GetAttributeInfo(ConcreteAttributePath(path.mEndpointId, path.mClusterId, path.mAttributeId))
+ .has_value();
+
+ bool emberResult = emberAfContainsAttribute(path.mEndpointId, path.mClusterId, path.mAttributeId);
+
+ // Ensure that Provider interface and ember are IDENTICAL in attribute location (i.e. "check" mode)
+ VerifyOrDie(providerResult == emberResult);
#endif
return GetDataModelProvider()
@@ -1615,7 +1620,7 @@
// skip all wildcard paths and invalid concrete attribute
if (path1->mValue.IsWildcardPath() ||
- !IsExistingAttributePath(
+ !IsExistentAttributePath(
ConcreteAttributePath(path1->mValue.mEndpointId, path1->mValue.mClusterId, path1->mValue.mAttributeId)))
{
prev = path1;
@@ -1766,7 +1771,49 @@
Protocols::InteractionModel::Status InteractionModelEngine::CommandExists(const ConcreteCommandPath & aCommandPath)
{
+#if CHIP_CONFIG_USE_DATA_MODEL_INTERFACE
+ auto provider = GetDataModelProvider();
+ if (provider->GetAcceptedCommandInfo(aCommandPath).has_value())
+ {
+#if CHIP_CONFIG_USE_EMBER_DATA_MODEL
+ VerifyOrDie(ServerClusterCommandExists(aCommandPath) == Protocols::InteractionModel::Status::Success);
+#endif
+ return Protocols::InteractionModel::Status::Success;
+ }
+
+ // We failed, figure out why ...
+ //
+ if (provider->GetClusterInfo(aCommandPath).has_value())
+ {
+#if CHIP_CONFIG_USE_EMBER_DATA_MODEL
+ VerifyOrDie(ServerClusterCommandExists(aCommandPath) == Protocols::InteractionModel::Status::UnsupportedCommand);
+#endif
+ return Protocols::InteractionModel::Status::UnsupportedCommand; // cluster exists, so command is invalid
+ }
+
+ // At this point either cluster or endpoint does not exist. If we find the endpoint, then the cluster
+ // is invalid
+ for (EndpointId endpoint = provider->FirstEndpoint(); endpoint != kInvalidEndpointId;
+ endpoint = provider->NextEndpoint(endpoint))
+ {
+ if (endpoint == aCommandPath.mEndpointId)
+ {
+#if CHIP_CONFIG_USE_EMBER_DATA_MODEL
+ VerifyOrDie(ServerClusterCommandExists(aCommandPath) == Protocols::InteractionModel::Status::UnsupportedCluster);
+#endif
+ // endpoint exists, so cluster is invalid
+ return Protocols::InteractionModel::Status::UnsupportedCluster;
+ }
+ }
+
+ // endpoint not found
+#if CHIP_CONFIG_USE_EMBER_DATA_MODEL
+ VerifyOrDie(ServerClusterCommandExists(aCommandPath) == Protocols::InteractionModel::Status::UnsupportedEndpoint);
+#endif
+ return Protocols::InteractionModel::Status::UnsupportedEndpoint;
+#else
return ServerClusterCommandExists(aCommandPath);
+#endif
}
DataModel::Provider * InteractionModelEngine::SetDataModelProvider(DataModel::Provider * model)
diff --git a/src/app/InteractionModelEngine.h b/src/app/InteractionModelEngine.h
index a51e781..82af788 100644
--- a/src/app/InteractionModelEngine.h
+++ b/src/app/InteractionModelEngine.h
@@ -508,6 +508,7 @@
void DispatchCommand(CommandHandlerImpl & apCommandObj, const ConcreteCommandPath & aCommandPath,
TLV::TLVReader & apPayload) override;
+
Protocols::InteractionModel::Status CommandExists(const ConcreteCommandPath & aCommandPath) override;
bool HasActiveRead();
@@ -615,7 +616,7 @@
/**
* Check if the given attribute path is a valid path in the data model provider.
*/
- bool IsExistingAttributePath(const ConcreteAttributePath & path);
+ bool IsExistentAttributePath(const ConcreteAttributePath & path);
static void ResumeSubscriptionsTimerCallback(System::Layer * apSystemLayer, void * apAppState);
diff --git a/src/app/tests/TestAclAttribute.cpp b/src/app/tests/TestAclAttribute.cpp
index 264137d..0325760 100644
--- a/src/app/tests/TestAclAttribute.cpp
+++ b/src/app/tests/TestAclAttribute.cpp
@@ -41,11 +41,27 @@
#include <messaging/Flags.h>
#include <protocols/interaction_model/Constants.h>
-#include <type_traits>
-
namespace {
using namespace chip;
using namespace chip::Access;
+using namespace chip::Test;
+
+const MockNodeConfig & TestMockNodeConfig()
+{
+ using namespace chip::app;
+ using namespace chip::app::Clusters::Globals::Attributes;
+
+ // clang-format off
+ static const MockNodeConfig config({
+ MockEndpointConfig(kTestEndpointId, {
+ MockClusterConfig(kTestClusterId, {
+ ClusterRevision::Id, FeatureMap::Id, 1, 2
+ }),
+ }),
+ });
+ // clang-format on
+ return config;
+}
class TestAccessControlDelegate : public AccessControl::Delegate
{
@@ -119,10 +135,12 @@
Access::GetAccessControl().Finish();
Access::GetAccessControl().Init(GetTestAccessControlDelegate(), gDeviceTypeResolver);
mOldProvider = InteractionModelEngine::GetInstance()->SetDataModelProvider(&TestImCustomDataModel::Instance());
+ chip::Test::SetMockNodeConfig(TestMockNodeConfig());
}
void TearDown() override
{
+ chip::Test::ResetMockNodeConfig();
AppContext::TearDown();
InteractionModelEngine::GetInstance()->SetDataModelProvider(mOldProvider);
}
diff --git a/src/app/tests/TestCommandInteraction.cpp b/src/app/tests/TestCommandInteraction.cpp
index 34f59ed..e4465c1 100644
--- a/src/app/tests/TestCommandInteraction.cpp
+++ b/src/app/tests/TestCommandInteraction.cpp
@@ -31,6 +31,7 @@
#include <app/AppConfig.h>
#include <app/CommandHandlerImpl.h>
#include <app/InteractionModelEngine.h>
+#include <app/data-model-provider/ActionReturnStatus.h>
#include <app/data-model/Encode.h>
#include <app/tests/AppTestContext.h>
#include <app/tests/test-interaction-model-api.h>
@@ -96,6 +97,33 @@
}
};
+const chip::Test::MockNodeConfig & TestMockNodeConfig()
+{
+ using namespace chip::app;
+ using namespace chip::Test;
+ using namespace chip::app::Clusters::Globals::Attributes;
+
+ // clang-format off
+ static const MockNodeConfig config({
+ MockEndpointConfig(chip::kTestEndpointId, {
+ MockClusterConfig(Clusters::Identify::Id, {
+ ClusterRevision::Id, FeatureMap::Id,
+ },
+ {}, // events
+ {
+ kTestCommandIdWithData,
+ kTestCommandIdNoData,
+ kTestCommandIdCommandSpecificResponse,
+ kTestCommandIdFillResponseMessage,
+ }, // accepted commands
+ {} // generated commands
+ ),
+ }),
+ });
+ // clang-format on
+ return config;
+}
+
} // namespace
namespace app {
@@ -354,9 +382,42 @@
int onFinalCalledTimes = 0;
} mockCommandHandlerDelegate;
+class TestCommandInteractionModel : public TestImCustomDataModel
+{
+public:
+ static TestCommandInteractionModel * Instance()
+ {
+ static TestCommandInteractionModel instance;
+ return &instance;
+ }
+
+ TestCommandInteractionModel() {}
+
+ std::optional<DataModel::ActionReturnStatus> Invoke(const DataModel::InvokeRequest & request,
+ chip::TLV::TLVReader & input_arguments, CommandHandler * handler)
+ {
+ DispatchSingleClusterCommand(request.path, input_arguments, handler);
+ return std::nullopt; // handler status is set by the dispatch
+ }
+};
+
class TestCommandInteraction : public chip::Test::AppContext
{
public:
+ void SetUp() override
+ {
+ AppContext::SetUp();
+ mOldProvider = InteractionModelEngine::GetInstance()->SetDataModelProvider(TestCommandInteractionModel::Instance());
+ chip::Test::SetMockNodeConfig(TestMockNodeConfig());
+ }
+
+ void TearDown() override
+ {
+ chip::Test::ResetMockNodeConfig();
+ InteractionModelEngine::GetInstance()->SetDataModelProvider(mOldProvider);
+ AppContext::TearDown();
+ }
+
static size_t GetNumActiveCommandResponderObjects()
{
return chip::app::InteractionModelEngine::GetInstance()->mCommandResponderObjs.Allocated();
@@ -423,6 +484,9 @@
static void FillCurrentInvokeResponseBuffer(CommandHandlerImpl * apCommandHandler,
const ConcreteCommandPath & aRequestCommandPath, uint32_t aSizeToLeaveInBuffer);
static void ValidateCommandHandlerEncodeInvokeResponseMessage(bool aNeedStatusCode);
+
+protected:
+ chip::app::DataModel::Provider * mOldProvider = nullptr;
};
class TestExchangeDelegate : public Messaging::ExchangeDelegate
diff --git a/src/app/tests/TestReadInteraction.cpp b/src/app/tests/TestReadInteraction.cpp
index e984b3e..aec74af 100644
--- a/src/app/tests/TestReadInteraction.cpp
+++ b/src/app/tests/TestReadInteraction.cpp
@@ -15,9 +15,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
-#include <type_traits>
-
#include <access/examples/PermissiveAccessControlDelegate.h>
#include <app/AttributeValueEncoder.h>
#include <app/InteractionModelEngine.h>
@@ -51,7 +48,7 @@
uint8_t gInfoEventBuffer[128];
uint8_t gCritEventBuffer[128];
chip::app::CircularEventBuffer gCircularEventBuffer[3];
-chip::ClusterId kTestClusterId = 6;
+chip::ClusterId kTestClusterId = 6; // OnOff, but not used as OnOff directly
chip::ClusterId kTestEventClusterId = chip::Test::MockClusterId(1);
chip::ClusterId kInvalidTestClusterId = 7;
chip::EndpointId kTestEndpointId = 1;
@@ -71,6 +68,65 @@
static chip::app::reporting::ReportSchedulerImpl * gReportScheduler;
static bool sUsingSubSync = false;
+const chip::Test::MockNodeConfig & TestMockNodeConfig()
+{
+ using namespace chip::app;
+ using namespace chip::app::Clusters::Globals::Attributes;
+ using namespace chip::Test;
+
+ // clang-format off
+ static const chip::Test::MockNodeConfig config({
+ MockEndpointConfig(kTestEndpointId, {
+ MockClusterConfig(kTestClusterId, {
+ ClusterRevision::Id, FeatureMap::Id,
+ 1,
+ 2, // treated as a list
+ }),
+ MockClusterConfig(kInvalidTestClusterId, {
+ ClusterRevision::Id, FeatureMap::Id,
+ 1,
+ }),
+ }),
+ MockEndpointConfig(kMockEndpoint1, {
+ MockClusterConfig(MockClusterId(1), {
+ ClusterRevision::Id, FeatureMap::Id,
+ }, {
+ MockEventId(1), MockEventId(2),
+ }),
+ MockClusterConfig(MockClusterId(2), {
+ ClusterRevision::Id, FeatureMap::Id, MockAttributeId(1),
+ }),
+ }),
+ MockEndpointConfig(kMockEndpoint2, {
+ MockClusterConfig(MockClusterId(1), {
+ ClusterRevision::Id, FeatureMap::Id,
+ }),
+ MockClusterConfig(MockClusterId(2), {
+ ClusterRevision::Id, FeatureMap::Id, MockAttributeId(1), MockAttributeId(2),
+ }),
+ MockClusterConfig(MockClusterId(3), {
+ ClusterRevision::Id, FeatureMap::Id, MockAttributeId(1), MockAttributeId(2), MockAttributeId(3),
+ }),
+ }),
+ MockEndpointConfig(chip::Test::kMockEndpoint3, {
+ MockClusterConfig(MockClusterId(1), {
+ ClusterRevision::Id, FeatureMap::Id, MockAttributeId(1),
+ }),
+ MockClusterConfig(MockClusterId(2), {
+ ClusterRevision::Id, FeatureMap::Id, MockAttributeId(1), MockAttributeId(2), MockAttributeId(3), MockAttributeId(4),
+ }),
+ MockClusterConfig(MockClusterId(3), {
+ ClusterRevision::Id, FeatureMap::Id,
+ }),
+ MockClusterConfig(MockClusterId(4), {
+ ClusterRevision::Id, FeatureMap::Id,
+ }),
+ }),
+ });
+ // clang-format on
+ return config;
+}
+
class TestEventGenerator : public chip::app::EventLoggingDelegate
{
public:
@@ -259,7 +315,7 @@
AppContext::TearDownTestSuite();
}
- void SetUp()
+ void SetUp() override
{
const chip::app::LogStorageResources logStorageResources[] = {
{ &gDebugEventBuffer[0], sizeof(gDebugEventBuffer), chip::app::PriorityLevel::Debug },
@@ -273,9 +329,11 @@
chip::app::EventManagement::CreateEventManagement(&GetExchangeManager(), ArraySize(logStorageResources),
gCircularEventBuffer, logStorageResources, &mEventCounter);
mOldProvider = InteractionModelEngine::GetInstance()->SetDataModelProvider(&TestImCustomDataModel::Instance());
+ chip::Test::SetMockNodeConfig(TestMockNodeConfig());
}
- void TearDown()
+ void TearDown() override
{
+ chip::Test::ResetMockNodeConfig();
InteractionModelEngine::GetInstance()->SetDataModelProvider(mOldProvider);
chip::app::EventManagement::DestroyEventManagement();
AppContext::TearDown();
@@ -2330,6 +2388,10 @@
TEST_F(TestReadInteraction, TestSubscribeWildcard)
{
+ // This test in particular is completely tied to the DefaultMockConfig in the mock
+ // attribute storage, so reset to that (figuring out chunking location is extra hard to
+ // maintain)
+ chip::Test::ResetMockNodeConfig();
Messaging::ReliableMessageMgr * rm = GetExchangeManager().GetReliableMessageMgr();
// Shouldn't have anything in the retransmit table when starting the test.
@@ -2368,8 +2430,8 @@
EXPECT_TRUE(delegate.mGotReport);
#if CHIP_CONFIG_ENABLE_EVENTLIST_ATTRIBUTE
- // Mock attribute storage in src/app/util/mock/attribute-storage.cpp
- // has the following items
+ // Mock attribute storage that is reset and resides in src/app/util/mock/attribute-storage.cpp
+ // has the following items:
// - Endpoint 0xFFFE
// - cluster 0xFFF1'FC01 (2 attributes)
// - cluster 0xFFF1'FC02 (3 attributes)
diff --git a/src/app/tests/TestReportingEngine.cpp b/src/app/tests/TestReportingEngine.cpp
index f4f52b8..3a16e43 100644
--- a/src/app/tests/TestReportingEngine.cpp
+++ b/src/app/tests/TestReportingEngine.cpp
@@ -50,6 +50,27 @@
constexpr chip::AttributeId kTestFieldId1 = 1;
constexpr chip::AttributeId kTestFieldId2 = 2;
+using namespace chip;
+using namespace chip::Access;
+
+const Test::MockNodeConfig & TestMockNodeConfig()
+{
+ using namespace chip::app;
+ using namespace chip::app::Clusters::Globals::Attributes;
+
+ // clang-format off
+ static const Test::MockNodeConfig config({
+ Test::MockEndpointConfig(kTestEndpointId, {
+ Test::MockClusterConfig(kTestClusterId, {
+ ClusterRevision::Id, FeatureMap::Id,
+ kTestFieldId1, kTestFieldId2,
+ }),
+ }),
+ });
+ // clang-format on
+ return config;
+}
+
namespace app {
namespace reporting {
@@ -60,10 +81,12 @@
{
chip::Test::AppContext::SetUp();
mOldProvider = InteractionModelEngine::GetInstance()->SetDataModelProvider(&TestImCustomDataModel::Instance());
+ chip::Test::SetMockNodeConfig(TestMockNodeConfig());
}
void TearDown() override
{
+ chip::Test::ResetMockNodeConfig();
InteractionModelEngine::GetInstance()->SetDataModelProvider(mOldProvider);
chip::Test::AppContext::TearDown();
}
diff --git a/src/app/tests/integration/chip_im_responder.cpp b/src/app/tests/integration/chip_im_responder.cpp
index 86d654b..b65710d 100644
--- a/src/app/tests/integration/chip_im_responder.cpp
+++ b/src/app/tests/integration/chip_im_responder.cpp
@@ -69,6 +69,21 @@
} // namespace
+// TODO:
+// The overrides here do NOT provide a consistent data model view:
+// This should be overriden with a Mock data model if using direct ember and
+// CodegenDataModel OR a custom DataModel::Provider should be written
+//
+// We cannot just say "every attribut exist, every device on every endpoint exists,
+// every data version compare is the same etc.".
+//
+// The following override implementation need changing:
+// - ServerClusterCommandExists - should have a proper data mmodel
+// - ConcreteAttributePathExists - cannot say "Yes" on all paths when query for EP/Cluster would fail
+// - CheckEventSupportStatus - cannot say yes for invalid endpoints/clusters
+// - IsClusterDataVersionEqual returning true on everything is odd
+// - IsDeviceTypeOnEndpoint returning true on every value seems odd
+
Protocols::InteractionModel::Status ServerClusterCommandExists(const ConcreteCommandPath & aCommandPath)
{
// The Mock cluster catalog -- only have one command on one cluster on one endpoint.
diff --git a/src/app/tests/test-interaction-model-api.cpp b/src/app/tests/test-interaction-model-api.cpp
index d24c586..5750e09 100644
--- a/src/app/tests/test-interaction-model-api.cpp
+++ b/src/app/tests/test-interaction-model-api.cpp
@@ -13,16 +13,17 @@
* 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/data-model-provider/ActionReturnStatus.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 <lib/core/DataModelTypes.h>
#include <messaging/ReliableMessageContext.h>
using namespace chip::app::DataModel;
diff --git a/src/app/tests/test-interaction-model-api.h b/src/app/tests/test-interaction-model-api.h
index 7b1b1ad..3f4bd27 100644
--- a/src/app/tests/test-interaction-model-api.h
+++ b/src/app/tests/test-interaction-model-api.h
@@ -91,7 +91,6 @@
TLV::TLVReader & aReader, WriteHandler * aWriteHandler);
const EmberAfAttributeMetadata * GetAttributeMetadata(const ConcreteAttributePath & aConcreteClusterPath);
-bool ConcreteAttributePathExists(const ConcreteAttributePath & aPath);
Protocols::InteractionModel::Status CheckEventSupportStatus(const ConcreteEventPath & aPath);
Protocols::InteractionModel::Status ServerClusterCommandExists(const ConcreteCommandPath & aRequestCommandPath);
diff --git a/src/controller/tests/TestServerCommandDispatch.cpp b/src/controller/tests/TestServerCommandDispatch.cpp
index 6e2c2c5..a09d253 100644
--- a/src/controller/tests/TestServerCommandDispatch.cpp
+++ b/src/controller/tests/TestServerCommandDispatch.cpp
@@ -15,13 +15,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
-/**
- * @file
- * This file implements unit tests for CHIP Interaction Model Command Interaction
- *
- */
-
#include <pw_unit_test/framework.h>
#include <app-common/zap-generated/cluster-objects.h>
@@ -30,10 +23,14 @@
#include <app/CommandHandlerInterface.h>
#include <app/CommandHandlerInterfaceRegistry.h>
#include <app/InteractionModelEngine.h>
+#include <app/codegen-data-model-provider/CodegenDataModelProvider.h>
+#include <app/codegen-data-model-provider/Instance.h>
#include <app/tests/AppTestContext.h>
#include <app/util/attribute-storage.h>
#include <controller/InvokeInteraction.h>
#include <controller/ReadInteraction.h>
+#include <lib/core/CHIPError.h>
+#include <lib/core/DataModelTypes.h>
#include <lib/core/ErrorStr.h>
#include <lib/core/StringBuilderAdapters.h>
#include <lib/support/logging/CHIPLogging.h>
@@ -129,9 +126,33 @@
namespace {
+class DispatchTestDataModel : public CodegenDataModelProvider
+{
+public:
+ static DispatchTestDataModel & Instance()
+ {
+ static DispatchTestDataModel instance;
+ return instance;
+ }
+};
+
class TestServerCommandDispatch : public chip::Test::AppContext
{
+public:
+ void SetUp()
+ {
+ AppContext::SetUp();
+ mOldProvider = InteractionModelEngine::GetInstance()->SetDataModelProvider(&DispatchTestDataModel::Instance());
+ }
+ void TearDown()
+ {
+ InteractionModelEngine::GetInstance()->SetDataModelProvider(mOldProvider);
+ AppContext::TearDown();
+ }
+
protected:
+ chip::app::DataModel::Provider * mOldProvider = nullptr;
+
void TestDataResponseHelper(const EmberAfEndpointType * aEndpoint, bool aExpectSuccess);
};
diff --git a/src/controller/tests/data_model/DataModelFixtures.cpp b/src/controller/tests/data_model/DataModelFixtures.cpp
index 1850bc0..e30641f 100644
--- a/src/controller/tests/data_model/DataModelFixtures.cpp
+++ b/src/controller/tests/data_model/DataModelFixtures.cpp
@@ -17,14 +17,19 @@
*/
#include "DataModelFixtures.h"
-#include "app/data-model-provider/ActionReturnStatus.h"
#include <app-common/zap-generated/cluster-objects.h>
#include <app-common/zap-generated/ids/Clusters.h>
#include <app/AttributeValueDecoder.h>
#include <app/AttributeValueEncoder.h>
+#include <app/ConcreteAttributePath.h>
+#include <app/ConcreteClusterPath.h>
#include <app/InteractionModelEngine.h>
#include <app/codegen-data-model-provider/Instance.h>
+#include <app/data-model-provider/ActionReturnStatus.h>
+#include <lib/core/DataModelTypes.h>
+#include <lib/support/logging/TextOnlyLogging.h>
+#include <optional>
using namespace chip;
using namespace chip::app;
@@ -237,11 +242,6 @@
return false;
}
-bool ConcreteAttributePathExists(const ConcreteAttributePath & aPath)
-{
- return true;
-}
-
Protocols::InteractionModel::Status CheckEventSupportStatus(const ConcreteEventPath & aPath)
{
return Protocols::InteractionModel::Status::Success;
@@ -485,7 +485,7 @@
// Mock cluster catalog, only support commands on one cluster on one endpoint.
using Protocols::InteractionModel::Status;
- if (aCommandPath.mEndpointId != kTestEndpointId)
+ if (aCommandPath.mEndpointId != DataModelTests::kTestEndpointId)
{
return Status::UnsupportedEndpoint;
}
@@ -665,7 +665,8 @@
std::optional<ActionReturnStatus> CustomDataModel::Invoke(const InvokeRequest & request, chip::TLV::TLVReader & input_arguments,
CommandHandler * handler)
{
- return std::make_optional<ActionReturnStatus>(CHIP_ERROR_NOT_IMPLEMENTED);
+ DispatchSingleClusterCommand(request.path, input_arguments, handler);
+ return std::nullopt; // handler status is set by the dispatch
}
EndpointId CustomDataModel::FirstEndpoint()
diff --git a/src/controller/tests/data_model/TestCommands.cpp b/src/controller/tests/data_model/TestCommands.cpp
index 4e8b3dd..c54e458 100644
--- a/src/controller/tests/data_model/TestCommands.cpp
+++ b/src/controller/tests/data_model/TestCommands.cpp
@@ -50,7 +50,50 @@
namespace {
-using TestCommands = chip::Test::AppContext;
+const chip::Test::MockNodeConfig & TestMockNodeConfig()
+{
+ using namespace chip::app;
+ using namespace chip::Test;
+ using namespace chip::app::Clusters::Globals::Attributes;
+
+ // clang-format off
+ static const MockNodeConfig config({
+ MockEndpointConfig(kTestEndpointId, {
+ MockClusterConfig(Clusters::UnitTesting::Id, {
+ ClusterRevision::Id, FeatureMap::Id,
+ },
+ {}, // events
+ {
+ Clusters::UnitTesting::Commands::TestSimpleArgumentRequest::Id,
+ }, // accepted commands
+ {} // generated commands
+ ),
+ }),
+ });
+ // clang-format on
+ return config;
+}
+
+class TestCommands : public chip::Test::AppContext
+{
+public:
+ void SetUp() override
+ {
+ AppContext::SetUp();
+ mOldProvider = InteractionModelEngine::GetInstance()->SetDataModelProvider(&CustomDataModel::Instance());
+ chip::Test::SetMockNodeConfig(TestMockNodeConfig());
+ }
+
+ void TearDown() override
+ {
+ chip::Test::ResetMockNodeConfig();
+ InteractionModelEngine::GetInstance()->SetDataModelProvider(mOldProvider);
+ AppContext::TearDown();
+ }
+
+protected:
+ chip::app::DataModel::Provider * mOldProvider = nullptr;
+};
TEST_F(TestCommands, TestDataResponse)
{
@@ -104,7 +147,8 @@
DrainAndServiceIO();
- EXPECT_TRUE(onSuccessWasCalled && !onFailureWasCalled);
+ EXPECT_TRUE(onSuccessWasCalled);
+ EXPECT_FALSE(onFailureWasCalled);
EXPECT_EQ(GetExchangeManager().GetNumActiveExchanges(), 0u);
}
@@ -367,7 +411,7 @@
{
app::StatusIB status(aError);
statusCheck = (status.mStatus == Protocols::InteractionModel::Status::Failure &&
- status.mClusterStatus.Value() == kTestFailureClusterStatus);
+ status.mClusterStatus == MakeOptional(kTestFailureClusterStatus));
}
onFailureWasCalled = true;
};
diff --git a/src/controller/tests/data_model/TestRead.cpp b/src/controller/tests/data_model/TestRead.cpp
index c2c2e63..6724e0d 100644
--- a/src/controller/tests/data_model/TestRead.cpp
+++ b/src/controller/tests/data_model/TestRead.cpp
@@ -31,6 +31,7 @@
#include <app/util/mock/Constants.h>
#include <app/util/mock/Functions.h>
#include <controller/ReadInteraction.h>
+#include <lib/core/DataModelTypes.h>
#include <lib/core/ErrorStr.h>
#include <lib/support/logging/CHIPLogging.h>
#include <messaging/tests/MessagingContext.h>
@@ -47,6 +48,67 @@
namespace {
+const MockNodeConfig & TestMockNodeConfig()
+{
+ using namespace Clusters::Globals::Attributes;
+
+ // clang-format off
+ static const MockNodeConfig config({
+ MockEndpointConfig(kRootEndpointId, {
+ MockClusterConfig(Clusters::IcdManagement::Id, {
+ ClusterRevision::Id, FeatureMap::Id,
+ Clusters::IcdManagement::Attributes::OperatingMode::Id,
+ }),
+ }),
+ MockEndpointConfig(kTestEndpointId, {
+ MockClusterConfig(Clusters::UnitTesting::Id, {
+ ClusterRevision::Id, FeatureMap::Id,
+ Clusters::UnitTesting::Attributes::Boolean::Id,
+ Clusters::UnitTesting::Attributes::Int16u::Id,
+ Clusters::UnitTesting::Attributes::ListFabricScoped::Id,
+ Clusters::UnitTesting::Attributes::ListStructOctetString::Id,
+ }),
+ }),
+ MockEndpointConfig(kMockEndpoint1, {
+ MockClusterConfig(MockClusterId(1), {
+ ClusterRevision::Id, FeatureMap::Id,
+ }, {
+ MockEventId(1), MockEventId(2),
+ }),
+ MockClusterConfig(MockClusterId(2), {
+ ClusterRevision::Id, FeatureMap::Id, MockAttributeId(1),
+ }),
+ }),
+ MockEndpointConfig(kMockEndpoint2, {
+ MockClusterConfig(MockClusterId(1), {
+ ClusterRevision::Id, FeatureMap::Id,
+ }),
+ MockClusterConfig(MockClusterId(2), {
+ ClusterRevision::Id, FeatureMap::Id, MockAttributeId(1), MockAttributeId(2),
+ }),
+ MockClusterConfig(MockClusterId(3), {
+ ClusterRevision::Id, FeatureMap::Id, MockAttributeId(1), MockAttributeId(2), MockAttributeId(3),
+ }),
+ }),
+ MockEndpointConfig(kMockEndpoint3, {
+ MockClusterConfig(MockClusterId(1), {
+ ClusterRevision::Id, FeatureMap::Id, MockAttributeId(1),
+ }),
+ MockClusterConfig(MockClusterId(2), {
+ ClusterRevision::Id, FeatureMap::Id, MockAttributeId(1), MockAttributeId(2), MockAttributeId(3), MockAttributeId(4),
+ }),
+ MockClusterConfig(MockClusterId(3), {
+ ClusterRevision::Id, FeatureMap::Id,
+ }),
+ MockClusterConfig(MockClusterId(4), {
+ ClusterRevision::Id, FeatureMap::Id,
+ }),
+ }),
+ });
+ // clang-format on
+ return config;
+}
+
class TestRead : public chip::Test::AppContext, public app::ReadHandler::ApplicationCallback
{
protected:
@@ -57,11 +119,13 @@
{
chip::Test::AppContext::SetUp();
mOldProvider = InteractionModelEngine::GetInstance()->SetDataModelProvider(&CustomDataModel::Instance());
+ chip::Test::SetMockNodeConfig(TestMockNodeConfig());
}
// Performs teardown for each individual test in the test suite
void TearDown() override
{
+ chip::Test::ResetMockNodeConfig();
InteractionModelEngine::GetInstance()->SetDataModelProvider(mOldProvider);
chip::Test::AppContext::TearDown();
}
@@ -3192,6 +3256,7 @@
app::AttributePathParams attributePathParams[1];
readPrepareParams.mpAttributePathParamsList = attributePathParams;
readPrepareParams.mAttributePathParamsListSize = ArraySize(attributePathParams);
+ attributePathParams[0].mEndpointId = kRootEndpointId; // this cluster does NOT exist on the root endpoint
attributePathParams[0].mClusterId = app::Clusters::UnitTesting::Id;
attributePathParams[0].mAttributeId = app::Clusters::UnitTesting::Attributes::ListStructOctetString::Id;