From 76f67622f9716632db86c27b1eebfa7279372a23 Mon Sep 17 00:00:00 2001 From: lpbeliveau-silabs Date: Fri, 10 Mar 2023 18:04:18 -0500 Subject: [PATCH] Added testing to validate interaction with group table, removed useless casts, addressed problem on change on maximum scene changes --- src/app/clusters/scenes/SceneTableImpl.cpp | 139 +++++++++-------- src/app/clusters/scenes/SceneTableImpl.h | 2 +- src/app/tests/TestSceneTable.cpp | 172 ++++++++++++++++++++- 3 files changed, 247 insertions(+), 66 deletions(-) diff --git a/src/app/clusters/scenes/SceneTableImpl.cpp b/src/app/clusters/scenes/SceneTableImpl.cpp index cf1ddc9280a199..af67496def2686 100644 --- a/src/app/clusters/scenes/SceneTableImpl.cpp +++ b/src/app/clusters/scenes/SceneTableImpl.cpp @@ -22,10 +22,13 @@ namespace chip { namespace scenes { -enum SceneImplTLVTag +/// @brief Tags Used to serialize Scene specific Fabric data +/// kSceneCount: Tag for the number of scenes in Fabric +/// kGroupID: Tag for the next Fabric +enum class TagSceneImpl : uint8_t { - kTagSceneCount = 1, - kTagNext, + kSceneCount = 1, + kNextFabric, }; using SceneTableEntry = DefaultSceneTableImpl::SceneTableEntry; @@ -79,9 +82,9 @@ struct SceneTableData : public SceneTableEntry, PersistentData(mStorageId.mEndpointId))); - ReturnErrorOnFailure(writer.Put(TLV::ContextTag(TagScene::kGroupID), static_cast(mStorageId.mGroupId))); - ReturnErrorOnFailure(writer.Put(TLV::ContextTag(TagScene::kID), static_cast(mStorageId.mSceneId))); + ReturnErrorOnFailure(writer.Put(TLV::ContextTag(TagScene::kEndpointID), mStorageId.mEndpointId)); + ReturnErrorOnFailure(writer.Put(TLV::ContextTag(TagScene::kGroupID), mStorageId.mGroupId)); + ReturnErrorOnFailure(writer.Put(TLV::ContextTag(TagScene::kID), mStorageId.mSceneId)); // Scene Data // A length of 0 means the name wasn't used so it won't get stored @@ -90,10 +93,8 @@ struct SceneTableData : public SceneTableEntry, PersistentData(mStorageData.mSceneTransitionTimeSeconds))); - ReturnErrorOnFailure( - writer.Put(TLV::ContextTag(TagScene::kTransitionTime100), static_cast(mStorageData.mTransitionTime100ms))); + ReturnErrorOnFailure(writer.Put(TLV::ContextTag(TagScene::kTransitionTime), mStorageData.mSceneTransitionTimeSeconds)); + ReturnErrorOnFailure(writer.Put(TLV::ContextTag(TagScene::kTransitionTime100), mStorageData.mTransitionTime100ms)); ReturnErrorOnFailure(mStorageData.mExtensionFieldSets.Serialize(writer)); return writer.EndContainer(container); @@ -101,7 +102,8 @@ struct SceneTableData : public SceneTableEntry, PersistentData TLV::TLVType container; ReturnErrorOnFailure(writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, container)); - ReturnErrorOnFailure(writer.Put(TLV::ContextTag(kTagSceneCount), static_cast(scene_count))); - + ReturnErrorOnFailure(writer.Put(TLV::ContextTag(TagSceneImpl::kSceneCount), (scene_count))); + ReturnErrorOnFailure(writer.Put(TLV::ContextTag(TagSceneImpl::kNextFabric), (next))); // Storing the scene map for (uint8_t i = 0; i < kMaxScenePerFabric; i++) { - ReturnErrorOnFailure( - writer.Put(TLV::ContextTag(TagScene::kEndpointID), static_cast(scene_map[i].mEndpointId))); - ReturnErrorOnFailure(writer.Put(TLV::ContextTag(TagScene::kGroupID), static_cast(scene_map[i].mGroupId))); - ReturnErrorOnFailure(writer.Put(TLV::ContextTag(TagScene::kID), static_cast(scene_map[i].mSceneId))); + ReturnErrorOnFailure(writer.Put(TLV::ContextTag(TagScene::kEndpointID), (scene_map[i].mEndpointId))); + ReturnErrorOnFailure(writer.Put(TLV::ContextTag(TagScene::kGroupID), (scene_map[i].mGroupId))); + ReturnErrorOnFailure(writer.Put(TLV::ContextTag(TagScene::kID), (scene_map[i].mSceneId))); } - ReturnErrorOnFailure(writer.Put(TLV::ContextTag(kTagNext), static_cast(next))); return writer.EndContainer(container); } CHIP_ERROR Deserialize(TLV::TLVReader & reader) override { - ReturnErrorOnFailure(reader.Next(TLV::AnonymousTag())); - VerifyOrReturnError(TLV::kTLVType_Structure == reader.GetType(), CHIP_ERROR_INTERNAL); + ReturnErrorOnFailure(reader.Next(TLV::kTLVType_Structure, TLV::AnonymousTag())); TLV::TLVType container; ReturnErrorOnFailure(reader.EnterContainer(container)); - ReturnErrorOnFailure(reader.Next(TLV::ContextTag(kTagSceneCount))); + ReturnErrorOnFailure(reader.Next(TLV::ContextTag(TagSceneImpl::kSceneCount))); ReturnErrorOnFailure(reader.Get(scene_count)); - for (uint8_t i = 0; i < kMaxScenePerFabric; i++) + ReturnErrorOnFailure(reader.Next(TLV::ContextTag(TagSceneImpl::kNextFabric))); + ReturnErrorOnFailure(reader.Get(next)); + + uint8_t i = 0; + while (reader.Next(TLV::ContextTag(TagScene::kEndpointID)) != CHIP_END_OF_TLV) { - ReturnErrorOnFailure(reader.Next(TLV::ContextTag(TagScene::kEndpointID))); ReturnErrorOnFailure(reader.Get(scene_map[i].mEndpointId)); ReturnErrorOnFailure(reader.Next(TLV::ContextTag(TagScene::kGroupID))); ReturnErrorOnFailure(reader.Get(scene_map[i].mGroupId)); ReturnErrorOnFailure(reader.Next(TLV::ContextTag(TagScene::kID))); ReturnErrorOnFailure(reader.Get(scene_map[i].mSceneId)); + + i++; } - ReturnErrorOnFailure(reader.Next(TLV::ContextTag(kTagNext))); - ReturnErrorOnFailure(reader.Get(next)); return reader.ExitContainer(container); } @@ -263,7 +265,8 @@ struct FabricSceneData : public PersistentData { FabricHavingSceneList fabric_list; CHIP_ERROR err = fabric_list.Load(storage); - VerifyOrReturnError(CHIP_NO_ERROR == err || CHIP_ERROR_NOT_FOUND == err, err); + VerifyOrReturnValue(CHIP_ERROR_NOT_FOUND != err, CHIP_NO_ERROR); + ReturnErrorOnFailure(err); // Existing fabric list, search for existing entry FabricSceneData fabric(fabric_list.first_entry); @@ -347,7 +350,7 @@ struct FabricSceneData : public PersistentData CHIP_ERROR SaveScene(PersistentStorageDelegate * storage, const SceneTableEntry & entry) { - CHIP_ERROR err; + CHIP_ERROR err = CHIP_NO_ERROR; SceneTableData scene(fabric_index, entry.mStorageId, entry.mStorageData); // Look for empty storage space @@ -355,7 +358,6 @@ struct FabricSceneData : public PersistentData if (CHIP_NO_ERROR == err) { - return scene.Save(storage); } @@ -365,7 +367,17 @@ struct FabricSceneData : public PersistentData scene_map[scene.index] = scene.mStorageId; ReturnErrorOnFailure(this->Save(storage)); - return scene.Save(storage); + err = scene.Save(storage); + + // on failure to save the scene, undoes the changes to Fabric Scene Data + if (err != CHIP_NO_ERROR) + { + scene_count--; + scene_map[scene.index].Clear(); + ReturnErrorOnFailure(this->Save(storage)); + } + + return err; } return CHIP_ERROR_INVALID_LIST_LENGTH; @@ -373,20 +385,30 @@ struct FabricSceneData : public PersistentData CHIP_ERROR RemoveScene(PersistentStorageDelegate * storage, const SceneStorageId & scene_id) { + CHIP_ERROR err = CHIP_NO_ERROR; SceneTableData scene(fabric_index, scene_id); - // Look for empty storage space - - VerifyOrReturnError(this->Find(scene_id, scene.index) == CHIP_NO_ERROR, CHIP_ERROR_NOT_FOUND); - ReturnErrorOnFailure(scene.Delete(storage)); + // Empty Scene Fabric Data returns CHIP_NO_ERROR on remove if (scene_count > 0) { + // If Find doesn't return CHIP_NO_ERROR, the scene wasn't found, which doesn't return an error + VerifyOrReturnValue(this->Find(scene_id, scene.index) == CHIP_NO_ERROR, CHIP_NO_ERROR); + scene_count--; scene_map[scene.index].Clear(); ReturnErrorOnFailure(this->Save(storage)); - } - return CHIP_NO_ERROR; + err = scene.Delete(storage); + + // On failure to delete scene, undoes the change to the Fabric Scene Data + if (err != CHIP_NO_ERROR) + { + scene_count++; + scene_map[scene.index] = scene.mStorageId; + ReturnErrorOnFailure(this->Save(storage)); + } + } + return err; } }; @@ -448,18 +470,16 @@ CHIP_ERROR DefaultSceneTableImpl::RemoveSceneTableEntry(FabricIndex fabric_index /// @return CHIP_NO_ERROR if removal was successful, errors if failed to remove the scene or to update the fabric after removing it CHIP_ERROR DefaultSceneTableImpl::RemoveSceneTableEntryAtPosition(FabricIndex fabric_index, SceneIndex scene_idx) { + CHIP_ERROR err = CHIP_NO_ERROR; FabricSceneData fabric(fabric_index); SceneTableData scene(fabric_index, scene_idx); - ReturnErrorOnFailure(scene.Delete(mStorage)); - - if (fabric.scene_count > 0) - { - fabric.scene_count--; - ReturnErrorOnFailure(fabric.Save(mStorage)); - } + ReturnErrorOnFailure(fabric.Load(mStorage)); + err = scene.Load(mStorage); + VerifyOrReturnValue(CHIP_ERROR_NOT_FOUND != err, CHIP_NO_ERROR); + ReturnErrorOnFailure(err); - return CHIP_NO_ERROR; + return fabric.RemoveScene(mStorage, scene.mStorageId); } /// @brief Register a handler in the handler list @@ -467,37 +487,30 @@ CHIP_ERROR DefaultSceneTableImpl::RemoveSceneTableEntryAtPosition(FabricIndex fa /// @return CHIP_NO_ERROR if handler was registered, CHIP_ERROR_NO_MEMORY if the handler list is full CHIP_ERROR DefaultSceneTableImpl::RegisterHandler(SceneHandler * handler) { - CHIP_ERROR err = CHIP_ERROR_NO_MEMORY; - uint8_t idPosition = kInvalidPosition; uint8_t firstEmptyPosition = kInvalidPosition; for (uint8_t i = 0; i < kMaxSceneHandlers; i++) { if (this->mHandlers[i] == handler) { - idPosition = i; - break; + this->mHandlers[i] = handler; + return CHIP_NO_ERROR; } - if (this->mHandlers[i] == nullptr && fisrtEmptyPosition == kInvalidPosition) + if (this->mHandlers[i] == nullptr && firstEmptyPosition == kInvalidPosition) { - fisrtEmptyPosition = i; + firstEmptyPosition = i; } } // if found, insert at found position, otherwise at first free possition, otherwise return error - if (idPosition < kMaxSceneHandlers) - { - this->mHandlers[idPosition] = handler; - err = CHIP_NO_ERROR; - } - else if (fisrtEmptyPosition < kMaxSceneHandlers) + if (firstEmptyPosition < kMaxSceneHandlers) { - this->mHandlers[fisrtEmptyPosition] = handler; + this->mHandlers[firstEmptyPosition] = handler; this->mNumHandlers++; - err = CHIP_NO_ERROR; + return CHIP_NO_ERROR; } - return err; + return CHIP_ERROR_NO_MEMORY; } CHIP_ERROR DefaultSceneTableImpl::UnregisterHandler(SceneHandler * handler) @@ -555,14 +568,14 @@ CHIP_ERROR DefaultSceneTableImpl::SceneSaveEFS(SceneTableEntry & scene) if (this->mHandlers[i] != nullptr) { this->mHandlers[i]->GetSupportedClusters(scene.mStorageId.mEndpointId, cSpan); - for (uint8_t j = 0; j < cSpan.size(); j++) + for (clusterId cluster : cSpan) { ExtensionFieldSet EFS; MutableByteSpan EFSSpan = MutableByteSpan(EFS.mBytesBuffer, kMaxFieldBytesPerCluster); - EFS.mID = cArray[j]; + EFS.mID = cluster; ReturnErrorOnFailure(this->mHandlers[i]->SerializeSave(scene.mStorageId.mEndpointId, EFS.mID, EFSSpan)); - EFS.mUsedBytes = (uint8_t) EFSSpan.size(); + EFS.mUsedBytes = static_cast(EFSSpan.size()); ReturnErrorOnFailure(scene.mStorageData.mExtensionFieldSets.InsertFieldSet(EFS)); } } @@ -636,8 +649,8 @@ DefaultSceneTableImpl::SceneEntryIteratorImpl::SceneEntryIteratorImpl(DefaultSce { FabricSceneData fabric(fabric_index); ReturnOnFailure(fabric.Load(provider.mStorage)); - mTotalScene = fabric.scene_count; - mSceneIndex = 0; + mTotalScenes = fabric.scene_count; + mSceneIndex = 0; } size_t DefaultSceneTableImpl::SceneEntryIteratorImpl::Count() diff --git a/src/app/clusters/scenes/SceneTableImpl.h b/src/app/clusters/scenes/SceneTableImpl.h index 419cab78e9a601..56724b33cb9ccd 100644 --- a/src/app/clusters/scenes/SceneTableImpl.h +++ b/src/app/clusters/scenes/SceneTableImpl.h @@ -230,7 +230,7 @@ class DefaultSceneTableImpl : public SceneTable FabricIndex mFabric = kUndefinedFabricIndex; SceneIndex mNextSceneIdx; SceneIndex mSceneIndex = 0; - uint8_t mTotalScene = 0; + uint8_t mTotalScenes = 0; }; bool IsInitialized() { return (mStorage != nullptr); } diff --git a/src/app/tests/TestSceneTable.cpp b/src/app/tests/TestSceneTable.cpp index 7f776e6f3639ec..2dbba1b92468f1 100644 --- a/src/app/tests/TestSceneTable.cpp +++ b/src/app/tests/TestSceneTable.cpp @@ -17,6 +17,8 @@ */ #include +#include +#include #include #include #include @@ -34,6 +36,11 @@ using ExtensionFieldSet = scenes::ExtensionFieldSet; using TransitionTimeMs = scenes::TransitionTimeMs; namespace { + +// Group constants +constexpr uint16_t kMaxGroupsPerFabric = 5; +constexpr uint16_t kMaxGroupKeysPerFabric = 4; + // Test Cluster ID constexpr chip::ClusterId kOnOffClusterId = 0x0006; constexpr chip::ClusterId kLevelControlClusterId = 0x0008; @@ -119,6 +126,15 @@ static uint32_t OO_buffer_serialized_length = 0; static uint32_t LC_buffer_serialized_length = 0; static uint32_t CC_buffer_serialized_length = 0; +// Group related data +constexpr chip::GroupId kGroup1 = kMinFabricGroupId; +constexpr chip::GroupId kGroup2 = 0x2222; +constexpr chip::GroupId kGroup3 = 0x1111; + +static const chip::Credentials::GroupDataProvider::GroupInfo kGroupInfo1_1(kGroup1, "Group-1.1"); +static const chip::Credentials::GroupDataProvider::GroupInfo kGroupInfo1_2(kGroup2, "Group-1.2"); +static const chip::Credentials::GroupDataProvider::GroupInfo kGroupInfo1_3(kGroup3, "Group-1.3"); + /// @brief Simulates a Handler where Endpoint 1 supports onoff and level control and Endpoint 2 supports onoff and color control class TestSceneHandler : public scenes::DefaultSceneHandlerImpl { @@ -362,7 +378,13 @@ class TestSceneHandler : public scenes::DefaultSceneHandlerImpl } }; +// Storage static chip::TestPersistentStorageDelegate testStorage; + +// Groups +static chip::Crypto::DefaultSessionKeystore sSessionKeystore; +static chip::Credentials::GroupDataProviderImpl sProvider(kMaxGroupsPerFabric, kMaxGroupKeysPerFabric); +// Scene static SceneTableImpl sSceneTable; static TestSceneHandler sHandler; @@ -372,6 +394,12 @@ void ResetSceneTable(SceneTable * sceneTable) sceneTable->RemoveFabric(kFabric2); } +void ResetProvider(chip::Credentials::GroupDataProvider * provider) +{ + provider->RemoveFabric(kFabric1); + provider->RemoveFabric(kFabric2); +} + void TestHandlerRegistration(nlTestSuite * aSuite, void * aContext) { SceneTable * sceneTable = &sSceneTable; @@ -762,6 +790,9 @@ void TestRemoveScenes(nlTestSuite * aSuite, void * aContext) SceneTableEntry scene; + // Removing non-existing entry should not return errors + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RemoveSceneTableEntry(kFabric1, scene9.mStorageId)); + // Remove middle NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RemoveSceneTableEntry(kFabric1, scene5.mStorageId)); auto * iterator = sceneTable->IterateSceneEntries(kFabric1); @@ -787,7 +818,7 @@ void TestRemoveScenes(nlTestSuite * aSuite, void * aContext) iterator->Release(); // Remove first - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RemoveSceneTableEntry(kFabric1, scene1.mStorageId)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RemoveSceneTableEntryAtPosition(kFabric1, 0)); iterator = sceneTable->IterateSceneEntries(kFabric1); NL_TEST_ASSERT(aSuite, iterator->Count() == 6); NL_TEST_ASSERT(aSuite, iterator->Next(scene)); @@ -839,7 +870,9 @@ void TestRemoveScenes(nlTestSuite * aSuite, void * aContext) NL_TEST_ASSERT(aSuite, iterator->Next(scene) == false); iterator->Release(); - NL_TEST_ASSERT(aSuite, CHIP_ERROR_NOT_FOUND == sceneTable->RemoveSceneTableEntry(kFabric1, scene8.mStorageId)); + // Remove at empty position, shouldn't trigger error + NL_TEST_ASSERT(aSuite, + CHIP_NO_ERROR == sceneTable->RemoveSceneTableEntryAtPosition(kFabric1, chip::scenes::kMaxScenePerFabric - 1)); iterator = sceneTable->IterateSceneEntries(kFabric1); NL_TEST_ASSERT(aSuite, iterator->Count() == 0); @@ -904,6 +937,125 @@ void TestFabricScenes(nlTestSuite * aSuite, void * aContext) NL_TEST_ASSERT(aSuite, CHIP_ERROR_NOT_FOUND == sceneTable->GetSceneTableEntry(kFabric2, sceneId3, scene)); } +void TestGroupScenesInteraction(nlTestSuite * aSuite, void * aContext) +{ + chip::Credentials::GroupDataProvider * provider = chip::Credentials::GetGroupDataProvider(); + NL_TEST_ASSERT(aSuite, provider); + SceneTable * sceneTable = &sSceneTable; + NL_TEST_ASSERT(aSuite, sceneTable); + + // Scene Entry + SceneTableEntry scene; + + // Reset test + ResetSceneTable(sceneTable); + ResetProvider(provider); + + // Group Info + chip::Credentials::GroupDataProvider::GroupInfo group; + + // Setup Group Data in Fabric 1 + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == provider->SetGroupInfoAt(kFabric1, 0, kGroupInfo1_1)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == provider->SetGroupInfoAt(kFabric1, 1, kGroupInfo1_2)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == provider->SetGroupInfoAt(kFabric1, 2, kGroupInfo1_3)); + + // Validate data written properly + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == provider->GetGroupInfoAt(kFabric1, 0, group)); + NL_TEST_ASSERT(aSuite, group == kGroupInfo1_1); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == provider->GetGroupInfoAt(kFabric1, 1, group)); + NL_TEST_ASSERT(aSuite, group == kGroupInfo1_2); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == provider->GetGroupInfoAt(kFabric1, 2, group)); + NL_TEST_ASSERT(aSuite, group == kGroupInfo1_3); + + // Setup Scene Data in Fabric 1 + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SetSceneTableEntry(kFabric1, scene1)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SetSceneTableEntry(kFabric1, scene2)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SetSceneTableEntry(kFabric1, scene3)); + + // Validate data written properly + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric1, sceneId1, scene)); + NL_TEST_ASSERT(aSuite, scene == scene1); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric1, sceneId2, scene)); + NL_TEST_ASSERT(aSuite, scene == scene2); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric1, sceneId3, scene)); + NL_TEST_ASSERT(aSuite, scene == scene3); + + // Setup Group Data in Fabric 2 + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == provider->SetGroupInfoAt(kFabric2, 0, kGroupInfo1_3)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == provider->SetGroupInfoAt(kFabric2, 1, kGroupInfo1_1)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == provider->SetGroupInfoAt(kFabric2, 2, kGroupInfo1_2)); + + // Validate data written properly + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == provider->GetGroupInfoAt(kFabric2, 0, group)); + NL_TEST_ASSERT(aSuite, group == kGroupInfo1_3); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == provider->GetGroupInfoAt(kFabric2, 1, group)); + NL_TEST_ASSERT(aSuite, group == kGroupInfo1_1); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == provider->GetGroupInfoAt(kFabric2, 2, group)); + NL_TEST_ASSERT(aSuite, group == kGroupInfo1_2); + + // Setup Scene Data in Fabric 1 + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SetSceneTableEntry(kFabric2, scene1)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SetSceneTableEntry(kFabric2, scene2)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SetSceneTableEntry(kFabric2, scene3)); + + // Validate data written properly + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric2, sceneId1, scene)); + NL_TEST_ASSERT(aSuite, scene == scene1); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric2, sceneId2, scene)); + NL_TEST_ASSERT(aSuite, scene == scene2); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric2, sceneId3, scene)); + NL_TEST_ASSERT(aSuite, scene == scene3); + + // Verify removing a Fabric Scene Data doesn't impact Fabric Group Data + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RemoveFabric(kFabric1)); + + // Scene Entry + NL_TEST_ASSERT(aSuite, CHIP_ERROR_NOT_FOUND == sceneTable->GetSceneTableEntry(kFabric1, sceneId1, scene)); + NL_TEST_ASSERT(aSuite, CHIP_ERROR_NOT_FOUND == sceneTable->GetSceneTableEntry(kFabric1, sceneId2, scene)); + NL_TEST_ASSERT(aSuite, CHIP_ERROR_NOT_FOUND == sceneTable->GetSceneTableEntry(kFabric1, sceneId3, scene)); + + // Group Info + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == provider->GetGroupInfoAt(kFabric2, 0, group)); + NL_TEST_ASSERT(aSuite, group == kGroupInfo1_3); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == provider->GetGroupInfoAt(kFabric2, 1, group)); + NL_TEST_ASSERT(aSuite, group == kGroupInfo1_1); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == provider->GetGroupInfoAt(kFabric2, 2, group)); + NL_TEST_ASSERT(aSuite, group == kGroupInfo1_2); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == provider->GetGroupInfoAt(kFabric1, 0, group)); + NL_TEST_ASSERT(aSuite, group == kGroupInfo1_1); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == provider->GetGroupInfoAt(kFabric1, 1, group)); + NL_TEST_ASSERT(aSuite, group == kGroupInfo1_2); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == provider->GetGroupInfoAt(kFabric1, 2, group)); + NL_TEST_ASSERT(aSuite, group == kGroupInfo1_3); + + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == provider->RemoveFabric(kFabric1)); + + // Group Info + NL_TEST_ASSERT(aSuite, CHIP_ERROR_NOT_FOUND == provider->GetGroupInfoAt(kFabric1, 0, group)); + NL_TEST_ASSERT(aSuite, CHIP_ERROR_NOT_FOUND == provider->GetGroupInfoAt(kFabric1, 1, group)); + NL_TEST_ASSERT(aSuite, CHIP_ERROR_NOT_FOUND == provider->GetGroupInfoAt(kFabric1, 2, group)); + + // Verify removing a Fabric Group Data doesn't impact Fabric Scene Data + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == provider->RemoveFabric(kFabric2)); + + // Group Info + NL_TEST_ASSERT(aSuite, CHIP_ERROR_NOT_FOUND == provider->GetGroupInfoAt(kFabric2, 0, group)); + NL_TEST_ASSERT(aSuite, CHIP_ERROR_NOT_FOUND == provider->GetGroupInfoAt(kFabric2, 1, group)); + NL_TEST_ASSERT(aSuite, CHIP_ERROR_NOT_FOUND == provider->GetGroupInfoAt(kFabric2, 2, group)); + + // Scene Entry + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric2, sceneId1, scene)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric2, sceneId2, scene)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric2, sceneId3, scene)); + + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RemoveFabric(kFabric2)); + + // Scene Entry + NL_TEST_ASSERT(aSuite, CHIP_ERROR_NOT_FOUND == sceneTable->GetSceneTableEntry(kFabric2, sceneId1, scene)); + NL_TEST_ASSERT(aSuite, CHIP_ERROR_NOT_FOUND == sceneTable->GetSceneTableEntry(kFabric2, sceneId2, scene)); + NL_TEST_ASSERT(aSuite, CHIP_ERROR_NOT_FOUND == sceneTable->GetSceneTableEntry(kFabric2, sceneId3, scene)); +} + } // namespace /** @@ -912,7 +1064,17 @@ void TestFabricScenes(nlTestSuite * aSuite, void * aContext) int TestSetup(void * inContext) { VerifyOrReturnError(CHIP_NO_ERROR == chip::Platform::MemoryInit(), FAILURE); + printf("1\n"); + // Initialize Group Data Provider + sProvider.SetStorageDelegate(&testStorage); + sProvider.SetSessionKeystore(&sSessionKeystore); + VerifyOrReturnError(CHIP_NO_ERROR == sProvider.Init(), FAILURE); + SetGroupDataProvider(&sProvider); + printf("2\n"); + + // Initialize Scene Table VerifyOrReturnError(CHIP_NO_ERROR == sSceneTable.Init(&testStorage), FAILURE); + printf("3\n"); return SUCCESS; } @@ -923,6 +1085,11 @@ int TestSetup(void * inContext) int TestTeardown(void * inContext) { sSceneTable.Finish(); + chip::Credentials::GroupDataProvider * provider = chip::Credentials::GetGroupDataProvider(); + if (nullptr != provider) + { + provider->Finish(); + } chip::Platform::MemoryShutdown(); return SUCCESS; @@ -937,6 +1104,7 @@ int TestSceneTable() NL_TEST_DEF("TestIterateScenes", TestIterateScenes), NL_TEST_DEF("TestRemoveScenes", TestRemoveScenes), NL_TEST_DEF("TestFabricScenes", TestFabricScenes), + NL_TEST_DEF("TestGroupScenesInteraction", TestGroupScenesInteraction), NL_TEST_SENTINEL() };