From 1024945dad14ef16c1eddbe804911948ae161cb7 Mon Sep 17 00:00:00 2001 From: lpbeliveau-silabs <112982107+lpbeliveau-silabs@users.noreply.github.com> Date: Wed, 15 Nov 2023 09:06:44 -0500 Subject: [PATCH] [Scenes] Scenes-Server on Fabric Removal (#30419) Added Fabric Removal callback to the scenes-server --- src/app/clusters/scenes-server/SceneTable.h | 8 + .../clusters/scenes-server/scenes-server.cpp | 14 + .../tests/suites/TestScenesFabricRemoval.yaml | 394 ++++++ src/app/tests/suites/ciTests.json | 1 + .../zap-generated/test/Commands.h | 1066 +++++++++++++++++ 5 files changed, 1483 insertions(+) create mode 100644 src/app/tests/suites/TestScenesFabricRemoval.yaml diff --git a/src/app/clusters/scenes-server/SceneTable.h b/src/app/clusters/scenes-server/SceneTable.h index 33a495f671bec8..5ee97bf1da3fe3 100644 --- a/src/app/clusters/scenes-server/SceneTable.h +++ b/src/app/clusters/scenes-server/SceneTable.h @@ -284,6 +284,14 @@ class SceneTable virtual CHIP_ERROR SceneApplyEFS(const SceneTableEntry & scene) = 0; // Fabrics + + /** + * @brief Removes all scenes associated with a fabric index and the stored FabricSceneData that maps them + * @param fabric_index Fabric index to remove + * @return CHIP_ERROR, CHIP_NO_ERROR if successful or if the Fabric was not found, specific CHIP_ERROR otherwise + * @note This function is meant to be used after a fabric is removed from the device, the implementation MUST ensure that it + * won't interact with the actual fabric table as it will be removed beforehand. + */ virtual CHIP_ERROR RemoveFabric(FabricIndex fabric_index) = 0; virtual CHIP_ERROR RemoveEndpoint() = 0; diff --git a/src/app/clusters/scenes-server/scenes-server.cpp b/src/app/clusters/scenes-server/scenes-server.cpp index 7a0807b5c7c816..ba171b8dc36c45 100644 --- a/src/app/clusters/scenes-server/scenes-server.cpp +++ b/src/app/clusters/scenes-server/scenes-server.cpp @@ -104,6 +104,19 @@ ScenesServer & ScenesServer::Instance() } void ReportAttributeOnAllEndpoints(AttributeId attribute) {} +class ScenesClusterFabricDelegate : public chip::FabricTable::Delegate +{ + void OnFabricRemoved(const FabricTable & fabricTable, FabricIndex fabricIndex) override + { + SceneTable * sceneTable = scenes::GetSceneTableImpl(); + VerifyOrReturn(nullptr != sceneTable); + // The implementation of SceneTable::RemoveFabric() must not call back into the FabricTable + sceneTable->RemoveFabric(fabricIndex); + } +}; + +static ScenesClusterFabricDelegate gFabricDelegate; + CHIP_ERROR ScenesServer::Init() { // Prevents re-initializing @@ -115,6 +128,7 @@ CHIP_ERROR ScenesServer::Init() SceneTable * sceneTable = scenes::GetSceneTableImpl(); ReturnErrorOnFailure(sceneTable->Init(&chip::Server::GetInstance().GetPersistentStorage())); + ReturnErrorOnFailure(chip::Server::GetInstance().GetFabricTable().AddFabricDelegate(&gFabricDelegate)); mIsInitialized = true; return CHIP_NO_ERROR; diff --git a/src/app/tests/suites/TestScenesFabricRemoval.yaml b/src/app/tests/suites/TestScenesFabricRemoval.yaml new file mode 100644 index 00000000000000..3acb0ebf3ae9df --- /dev/null +++ b/src/app/tests/suites/TestScenesFabricRemoval.yaml @@ -0,0 +1,394 @@ +# Copyright (c) 2023 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. + +# !!!!!!!!!! TEST INFORMATION !!!!!!!!!!!!!!!!!! +# This test covers removal of fabric in the SceneTable + +name: Scenes Fabric Removal + +config: + nodeId: 0x12344321 + cluster: "Scenes" + endpoint: 1 + payload: + type: char_string + defaultValue: "MT:-24J0AFN00KA0648G00" + discriminator: + type: int16u + defaultValue: 3840 + waitAfterCommissioning: + type: int16u + defaultValue: 5000 + PakeVerifier: + type: octet_string + defaultValue: "hex:b96170aae803346884724fe9a3b287c30330c2a660375d17bb205a8cf1aecb350457f8ab79ee253ab6a8e46bb09e543ae422736de501e3db37d441fe344920d09548e4c18240630c4ff4913c53513839b7c07fcc0627a1b8573a149fcd1fa466cf" + G1: + type: group_id + defaultValue: 0x0001 + +tests: + - label: "Commission DUT to TH1" + cluster: "DelayCommands" + command: "WaitForCommissionee" + arguments: + values: + - name: "nodeId" + value: nodeId + + - label: "TH1 reads the fabric index" + cluster: "Operational Credentials" + endpoint: 0 + command: "readAttribute" + attribute: "CurrentFabricIndex" + response: + saveAs: th1FabricIndex + + - label: "Open Commissioning Window from alpha" + endpoint: 0 + cluster: "Administrator Commissioning" + command: "OpenCommissioningWindow" + timedInteractionTimeoutMs: 10000 + arguments: + values: + - name: "CommissioningTimeout" + value: 180 + - name: "PAKEPasscodeVerifier" + value: PakeVerifier + - name: "Discriminator" + value: discriminator + - name: "Iterations" + value: 1000 + - name: "Salt" + value: "SPAKE2P Key Salt" + + - label: "Waiting after opening commissioning window" + cluster: "DelayCommands" + command: "WaitForMs" + arguments: + values: + - name: "ms" + value: waitAfterCommissioning + + - label: "Commission from TH2" + identity: "beta" + endpoint: 0 + cluster: "CommissionerCommands" + command: "PairWithCode" + arguments: + values: + - name: "nodeId" + value: nodeId + - name: "payload" + value: payload + + - label: "Wait for the commissioned device to be retrieved for TH2" + endpoint: 0 + identity: beta + cluster: "DelayCommands" + command: "WaitForCommissionee" + arguments: + values: + - name: "nodeId" + value: nodeId + + - label: "TH2 reads the fabric index" + identity: "beta" + endpoint: 0 + cluster: "Operational Credentials" + command: "readAttribute" + attribute: "CurrentFabricIndex" + response: + saveAs: th2FabricIndex + + - label: "TH1 sends a RemoveAllGroups command to DUT." + cluster: "Groups" + command: "RemoveAllGroups" + + - label: "TH 1 Add Group KeySet." + cluster: "Group Key Management" + endpoint: 0 + command: "KeySetWrite" + arguments: + values: + - name: "GroupKeySet" + value: + { + GroupKeySetID: 0x01a1, + GroupKeySecurityPolicy: 0, + EpochKey0: "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf", + EpochStartTime0: 1110000, + EpochKey1: "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf", + EpochStartTime1: 1110001, + EpochKey2: "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf", + EpochStartTime2: 1110002, + } + + - label: "TH1 Map KeySets to GroupId." + cluster: "Group Key Management" + endpoint: 0 + command: "writeAttribute" + attribute: "GroupKeyMap" + arguments: + value: [{ FabricIndex: 0, GroupId: G1, GroupKeySetID: 0x01a1 }] + + - label: "TH1 sends a AddGroup command to DUT for G1." + cluster: "Groups" + command: "AddGroup" + arguments: + values: + - name: "GroupID" + value: G1 + - name: "GroupName" + value: "Group1" + response: + values: + - name: "Status" + value: 0 + - name: "GroupID" + value: G1 + + - label: "Preparation step : TH2 Add Group KeySet." + identity: "beta" + cluster: "Group Key Management" + endpoint: 0 + command: "KeySetWrite" + arguments: + values: + - name: "GroupKeySet" + value: + { + GroupKeySetID: 0x01a2, + GroupKeySecurityPolicy: 0, + EpochKey0: "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf", + EpochStartTime0: 1120000, + EpochKey1: "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf", + EpochStartTime1: 1120001, + EpochKey2: "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf", + EpochStartTime2: 1120002, + } + + - label: "Preparation step TH2 Map KeySets to GroupId." + identity: "beta" + cluster: "Group Key Management" + endpoint: 0 + command: "writeAttribute" + attribute: "GroupKeyMap" + arguments: + value: [{ FabricIndex: 0, GroupId: G1, GroupKeySetID: 0x01a2 }] + + - label: "TH2 sends a AddGroup command to DUT for G1." + identity: "beta" + cluster: "Groups" + command: "AddGroup" + arguments: + values: + - name: "GroupID" + value: G1 + - name: "GroupName" + value: "Group1" + response: + values: + - name: "Status" + value: 0 + - name: "GroupID" + value: G1 + + - label: "TH1 confirms its Scene table is empty and gets its capacity" + command: "GetSceneMembership" + arguments: + values: + - name: "GroupID" + value: G1 + response: + values: + - name: "Status" + value: 0x00 + - name: "Capacity" + saveAs: fabricCapacity + - name: "GroupID" + value: G1 + + - label: + "TH2 confirms its Scene table is empty and has the same capacity as + TH1" + identity: "beta" + command: "GetSceneMembership" + arguments: + values: + - name: "GroupID" + value: G1 + response: + values: + - name: "Status" + value: 0x00 + - name: "Capacity" + value: fabricCapacity + - name: "GroupID" + value: G1 + + - label: "TH1 sends an AddScene command to DUT for Scene 1 G1" + command: "AddScene" + arguments: + values: + - name: "GroupID" + value: G1 + - name: "SceneID" + value: 0x01 + - name: "TransitionTime" + value: 0x0001 + - name: "SceneName" + value: "Scene1" + - name: "ExtensionFieldSets" + value: [] + response: + values: + - name: "Status" + value: 0x00 + - name: "GroupID" + value: G1 + - name: "SceneID" + value: 0x01 + + - label: "TH1 sends an AddScene command to DUT for Scene 2 G1" + command: "AddScene" + arguments: + values: + - name: "GroupID" + value: G1 + - name: "SceneID" + value: 0x02 + - name: "TransitionTime" + value: 0x0000 + - name: "SceneName" + value: "Scene2" + - name: "ExtensionFieldSets" + value: [] + response: + values: + - name: "Status" + value: 0x00 + - name: "GroupID" + value: G1 + - name: "SceneID" + value: 0x02 + + - label: "TH2 sends an AddScene command to DUT for Scene 1 G1" + identity: "beta" + command: "AddScene" + arguments: + values: + - name: "GroupID" + value: G1 + - name: "SceneID" + value: 0x01 + - name: "TransitionTime" + value: 0x0001 + - name: "SceneName" + value: "Scene1" + - name: "ExtensionFieldSets" + value: [] + response: + values: + - name: "Status" + value: 0x00 + - name: "GroupID" + value: G1 + - name: "SceneID" + value: 0x01 + + - label: "TH2 sends an AddScene command to DUT for Scene 2 G1" + identity: "beta" + command: "AddScene" + arguments: + values: + - name: "GroupID" + value: G1 + - name: "SceneID" + value: 0x02 + - name: "TransitionTime" + value: 0x0000 + - name: "SceneName" + value: "Scene2" + - name: "ExtensionFieldSets" + value: [] + response: + values: + - name: "Status" + value: 0x00 + - name: "GroupID" + value: G1 + - name: "SceneID" + value: 0x02 + + - label: "TH1 confirms its G1 holds 2 scenes" + command: "GetSceneMembership" + arguments: + values: + - name: "GroupID" + value: G1 + response: + values: + - name: "Status" + value: 0x00 + - name: "Capacity" + value: fabricCapacity - 2 + - name: "GroupID" + value: G1 + - name: "SceneList" + value: [0x01, 0x02] + + - label: "TH2 confirms its G1 holds 2 scenes" + command: "GetSceneMembership" + identity: "beta" + arguments: + values: + - name: "GroupID" + value: G1 + response: + values: + - name: "Status" + value: 0x00 + - name: "Capacity" + value: fabricCapacity - 2 + - name: "GroupID" + value: G1 + - name: "SceneList" + value: [0x01, 0x02] + + - label: "TH1 sends RemoveFabric command for TH2" + cluster: "Operational Credentials" + endpoint: 0 + command: "RemoveFabric" + arguments: + values: + - name: "FabricIndex" + value: th2FabricIndex + + - label: "TH1 confirms its G1 still holds 2 scenes" + command: "GetSceneMembership" + arguments: + values: + - name: "GroupID" + value: G1 + response: + values: + - name: "Status" + value: 0x00 + - name: "Capacity" + value: fabricCapacity - 2 + - name: "GroupID" + value: G1 + - name: "SceneList" + value: [0x01, 0x02] +# TODO Figure out a way to recommission with Fabric Index 2 and confirm the scene table is empty for that fabric index diff --git a/src/app/tests/suites/ciTests.json b/src/app/tests/suites/ciTests.json index 5202ed65195e02..ae696e96735391 100644 --- a/src/app/tests/suites/ciTests.json +++ b/src/app/tests/suites/ciTests.json @@ -321,6 +321,7 @@ "Test_TC_G_2_1" ], "Scenes": [ + "TestScenesFabricRemoval", "Test_TC_S_1_1", "Test_TC_S_2_1", "Test_TC_S_2_2", diff --git a/zzz_generated/darwin-framework-tool/zap-generated/test/Commands.h b/zzz_generated/darwin-framework-tool/zap-generated/test/Commands.h index 3db46600ff03ff..ec5f99335eec51 100644 --- a/zzz_generated/darwin-framework-tool/zap-generated/test/Commands.h +++ b/zzz_generated/darwin-framework-tool/zap-generated/test/Commands.h @@ -296,6 +296,7 @@ class TestList : public Command { printf("Test_TC_DRLK_2_11\n"); printf("TestGroupsCluster\n"); printf("Test_TC_G_1_1\n"); + printf("TestScenesFabricRemoval\n"); printf("Test_TC_S_1_1\n"); printf("Test_TC_S_2_1\n"); printf("Test_TC_S_2_4\n"); @@ -187768,6 +187769,1070 @@ class Test_TC_G_1_1 : public TestCommandBridge { } }; +class TestScenesFabricRemoval : public TestCommandBridge { +public: + // NOLINTBEGIN(clang-analyzer-nullability.NullPassedToNonnull): Test constructor nullability not enforced + TestScenesFabricRemoval() + : TestCommandBridge("TestScenesFabricRemoval") + , mTestIndex(0) + { + AddArgument("nodeId", 0, UINT64_MAX, &mNodeId); + AddArgument("cluster", &mCluster); + AddArgument("endpoint", 0, UINT16_MAX, &mEndpoint); + AddArgument("payload", &mPayload); + AddArgument("discriminator", 0, UINT16_MAX, &mDiscriminator); + AddArgument("waitAfterCommissioning", 0, UINT16_MAX, &mWaitAfterCommissioning); + AddArgument("PakeVerifier", &mPakeVerifier); + AddArgument("G1", 0, UINT16_MAX, &mG1); + AddArgument("timeout", 0, UINT16_MAX, &mTimeout); + } + // NOLINTEND(clang-analyzer-nullability.NullPassedToNonnull) + + ~TestScenesFabricRemoval() + { + } + + /////////// TestCommand Interface ///////// + void NextTest() override + { + CHIP_ERROR err = CHIP_NO_ERROR; + + if (0 == mTestIndex) { + ChipLogProgress(chipTool, " **** Test Start: TestScenesFabricRemoval\n"); + } + + if (mTestCount == mTestIndex) { + ChipLogProgress(chipTool, " **** Test Complete: TestScenesFabricRemoval\n"); + SetCommandExitStatus(CHIP_NO_ERROR); + return; + } + + Wait(); + + // Ensure we increment mTestIndex before we start running the relevant + // command. That way if we lose the timeslice after we send the message + // but before our function call returns, we won't end up with an + // incorrect mTestIndex value observed when we get the response. + switch (mTestIndex++) { + case 0: + ChipLogProgress(chipTool, " ***** Test Step 0 : Commission DUT to TH1\n"); + err = TestCommissionDutToTh1_0(); + break; + case 1: + ChipLogProgress(chipTool, " ***** Test Step 1 : TH1 reads the fabric index\n"); + err = TestTh1ReadsTheFabricIndex_1(); + break; + case 2: + ChipLogProgress(chipTool, " ***** Test Step 2 : Open Commissioning Window from alpha\n"); + err = TestOpenCommissioningWindowFromAlpha_2(); + break; + case 3: + ChipLogProgress(chipTool, " ***** Test Step 3 : Waiting after opening commissioning window\n"); + err = TestWaitingAfterOpeningCommissioningWindow_3(); + break; + case 4: + ChipLogProgress(chipTool, " ***** Test Step 4 : Commission from TH2\n"); + err = TestCommissionFromTh2_4(); + break; + case 5: + ChipLogProgress(chipTool, " ***** Test Step 5 : Wait for the commissioned device to be retrieved for TH2\n"); + err = TestWaitForTheCommissionedDeviceToBeRetrievedForTh2_5(); + break; + case 6: + ChipLogProgress(chipTool, " ***** Test Step 6 : TH2 reads the fabric index\n"); + err = TestTh2ReadsTheFabricIndex_6(); + break; + case 7: + ChipLogProgress(chipTool, " ***** Test Step 7 : TH1 sends a RemoveAllGroups command to DUT.\n"); + err = TestTh1SendsARemoveAllGroupsCommandToDut_7(); + break; + case 8: + ChipLogProgress(chipTool, " ***** Test Step 8 : TH 1 Add Group KeySet.\n"); + err = TestTh1AddGroupKeySet_8(); + break; + case 9: + ChipLogProgress(chipTool, " ***** Test Step 9 : TH1 Map KeySets to GroupId.\n"); + err = TestTh1MapKeySetsToGroupId_9(); + break; + case 10: + ChipLogProgress(chipTool, " ***** Test Step 10 : TH1 sends a AddGroup command to DUT for G1.\n"); + err = TestTh1SendsAAddGroupCommandToDutForG1_10(); + break; + case 11: + ChipLogProgress(chipTool, " ***** Test Step 11 : Preparation step : TH2 Add Group KeySet.\n"); + err = TestPreparationStepTh2AddGroupKeySet_11(); + break; + case 12: + ChipLogProgress(chipTool, " ***** Test Step 12 : Preparation step TH2 Map KeySets to GroupId.\n"); + err = TestPreparationStepTh2MapKeySetsToGroupId_12(); + break; + case 13: + ChipLogProgress(chipTool, " ***** Test Step 13 : TH2 sends a AddGroup command to DUT for G1.\n"); + err = TestTh2SendsAAddGroupCommandToDutForG1_13(); + break; + case 14: + ChipLogProgress(chipTool, " ***** Test Step 14 : TH1 confirms its Scene table is empty and gets its capacity\n"); + err = TestTh1ConfirmsItsSceneTableIsEmptyAndGetsItsCapacity_14(); + break; + case 15: + ChipLogProgress(chipTool, " ***** Test Step 15 : TH2 confirms its Scene table is empty and has the same capacity as TH1\n"); + err = TestTh2ConfirmsItsSceneTableIsEmptyAndHasTheSameCapacityAsTh1_15(); + break; + case 16: + ChipLogProgress(chipTool, " ***** Test Step 16 : TH1 sends an AddScene command to DUT for Scene 1 G1\n"); + err = TestTh1SendsAnAddSceneCommandToDutForScene1G1_16(); + break; + case 17: + ChipLogProgress(chipTool, " ***** Test Step 17 : TH1 sends an AddScene command to DUT for Scene 2 G1\n"); + err = TestTh1SendsAnAddSceneCommandToDutForScene2G1_17(); + break; + case 18: + ChipLogProgress(chipTool, " ***** Test Step 18 : TH2 sends an AddScene command to DUT for Scene 1 G1\n"); + err = TestTh2SendsAnAddSceneCommandToDutForScene1G1_18(); + break; + case 19: + ChipLogProgress(chipTool, " ***** Test Step 19 : TH2 sends an AddScene command to DUT for Scene 2 G1\n"); + err = TestTh2SendsAnAddSceneCommandToDutForScene2G1_19(); + break; + case 20: + ChipLogProgress(chipTool, " ***** Test Step 20 : TH1 confirms its G1 holds 2 scenes\n"); + err = TestTh1ConfirmsItsG1Holds2Scenes_20(); + break; + case 21: + ChipLogProgress(chipTool, " ***** Test Step 21 : TH2 confirms its G1 holds 2 scenes\n"); + err = TestTh2ConfirmsItsG1Holds2Scenes_21(); + break; + case 22: + ChipLogProgress(chipTool, " ***** Test Step 22 : TH1 sends RemoveFabric command for TH2\n"); + err = TestTh1SendsRemoveFabricCommandForTh2_22(); + break; + case 23: + ChipLogProgress(chipTool, " ***** Test Step 23 : TH1 confirms its G1 still holds 2 scenes\n"); + err = TestTh1ConfirmsItsG1StillHolds2Scenes_23(); + break; + } + + if (CHIP_NO_ERROR != err) { + ChipLogError(chipTool, " ***** Test Failure: %s\n", chip::ErrorStr(err)); + SetCommandExitStatus(err); + } + } + + void OnStatusUpdate(const chip::app::StatusIB & status) override + { + switch (mTestIndex - 1) { + case 0: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + break; + case 1: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + break; + case 2: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + break; + case 3: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + break; + case 4: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + break; + case 5: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + break; + case 6: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + break; + case 7: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + break; + case 8: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + break; + case 9: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + break; + case 10: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + break; + case 11: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + break; + case 12: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + break; + case 13: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + break; + case 14: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + break; + case 15: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + break; + case 16: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + break; + case 17: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + break; + case 18: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + break; + case 19: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + break; + case 20: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + break; + case 21: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + break; + case 22: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + break; + case 23: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + break; + } + + // Go on to the next test. + ContinueOnChipMainThread(CHIP_NO_ERROR); + } + + chip::System::Clock::Timeout GetWaitDuration() const override { return chip::System::Clock::Seconds16(mTimeout.ValueOr(kTimeoutInSeconds)); } + +private: + std::atomic_uint16_t mTestIndex; + const uint16_t mTestCount = 24; + + chip::Optional mNodeId; + chip::Optional mCluster; + chip::Optional mEndpoint; + chip::Optional mPayload; + chip::Optional mDiscriminator; + chip::Optional mWaitAfterCommissioning; + chip::Optional mPakeVerifier; + chip::Optional mG1; + chip::Optional mTimeout; + + CHIP_ERROR TestCommissionDutToTh1_0() + { + + chip::app::Clusters::DelayCommands::Commands::WaitForCommissionee::Type value; + value.nodeId = mNodeId.HasValue() ? mNodeId.Value() : 305414945ULL; + return WaitForCommissionee("alpha", value); + } + NSNumber * _Nonnull th1FabricIndex; + + CHIP_ERROR TestTh1ReadsTheFabricIndex_1() + { + + MTRBaseDevice * device = GetDevice("alpha"); + __auto_type * cluster = [[MTRBaseClusterOperationalCredentials alloc] initWithDevice:device endpointID:@(0) queue:mCallbackQueue]; + VerifyOrReturnError(cluster != nil, CHIP_ERROR_INCORRECT_STATE); + + [cluster readAttributeCurrentFabricIndexWithCompletion:^(NSNumber * _Nullable value, NSError * _Nullable err) { + if (err != nil) { + NSLog(@"TH1 reads the fabric index: Error: %@", err); + } else { + NSLog(@"TH1 reads the fabric index: Success"); + } + + VerifyOrReturn(CheckValue("status", err ? err.code : 0, 0)); + + { + th1FabricIndex = value; + } + + NextTest(); + }]; + + return CHIP_NO_ERROR; + } + + CHIP_ERROR TestOpenCommissioningWindowFromAlpha_2() + { + + MTRBaseDevice * device = GetDevice("alpha"); + __auto_type * cluster = [[MTRBaseClusterAdministratorCommissioning alloc] initWithDevice:device endpointID:@(0) queue:mCallbackQueue]; + VerifyOrReturnError(cluster != nil, CHIP_ERROR_INCORRECT_STATE); + + __auto_type * params = [[MTRAdministratorCommissioningClusterOpenCommissioningWindowParams alloc] init]; + params.commissioningTimeout = + [NSNumber numberWithUnsignedShort:180U]; + params.pakePasscodeVerifier = mPakeVerifier.HasValue() ? [NSData dataWithBytes:mPakeVerifier.Value().data() length:mPakeVerifier.Value().size()] : [[NSData alloc] initWithBytes:"\xb9\x61\x70\xaa\xe8\x03\x34\x68\x84\x72\x4f\xe9\xa3\xb2\x87\xc3\x03\x30\xc2\xa6\x60\x37\x5d\x17\xbb\x20\x5a\x8c\xf1\xae\xcb\x35\x04\x57\xf8\xab\x79\xee\x25\x3a\xb6\xa8\xe4\x6b\xb0\x9e\x54\x3a\xe4\x22\x73\x6d\xe5\x01\xe3\xdb\x37\xd4\x41\xfe\x34\x49\x20\xd0\x95\x48\xe4\xc1\x82\x40\x63\x0c\x4f\xf4\x91\x3c\x53\x51\x38\x39\xb7\xc0\x7f\xcc\x06\x27\xa1\xb8\x57\x3a\x14\x9f\xcd\x1f\xa4\x66\xcf" length:97]; + params.discriminator = mDiscriminator.HasValue() ? [NSNumber numberWithUnsignedShort:mDiscriminator.Value()] : [NSNumber numberWithUnsignedShort:3840U]; + params.iterations = + [NSNumber numberWithUnsignedInt:1000UL]; + params.salt = + [[NSData alloc] initWithBytes:"SPAKE2P Key Salt" length:16]; + [cluster openCommissioningWindowWithParams:params completion: + ^(NSError * _Nullable err) { + if (err != nil) { + NSLog(@"Open Commissioning Window from alpha: Error: %@", err); + } else { + NSLog(@"Open Commissioning Window from alpha: Success"); + } + + VerifyOrReturn(CheckValue("status", err ? err.code : 0, 0)); + + NextTest(); + }]; + + return CHIP_NO_ERROR; + } + + CHIP_ERROR TestWaitingAfterOpeningCommissioningWindow_3() + { + + chip::app::Clusters::DelayCommands::Commands::WaitForMs::Type value; + value.ms = mWaitAfterCommissioning.HasValue() ? mWaitAfterCommissioning.Value() : 5000UL; + return WaitForMs("alpha", value); + } + + CHIP_ERROR TestCommissionFromTh2_4() + { + + chip::app::Clusters::CommissionerCommands::Commands::PairWithCode::Type value; + value.nodeId = mNodeId.HasValue() ? mNodeId.Value() : 305414945ULL; + value.payload = mPayload.HasValue() ? mPayload.Value() : chip::Span("MT:-24J0AFN00KA0648G00", 22); + return PairWithCode("beta", value); + } + + CHIP_ERROR TestWaitForTheCommissionedDeviceToBeRetrievedForTh2_5() + { + + chip::app::Clusters::DelayCommands::Commands::WaitForCommissionee::Type value; + value.nodeId = mNodeId.HasValue() ? mNodeId.Value() : 305414945ULL; + return WaitForCommissionee("beta", value); + } + NSNumber * _Nonnull th2FabricIndex; + + CHIP_ERROR TestTh2ReadsTheFabricIndex_6() + { + + MTRBaseDevice * device = GetDevice("beta"); + __auto_type * cluster = [[MTRBaseClusterOperationalCredentials alloc] initWithDevice:device endpointID:@(0) queue:mCallbackQueue]; + VerifyOrReturnError(cluster != nil, CHIP_ERROR_INCORRECT_STATE); + + [cluster readAttributeCurrentFabricIndexWithCompletion:^(NSNumber * _Nullable value, NSError * _Nullable err) { + if (err != nil) { + NSLog(@"TH2 reads the fabric index: Error: %@", err); + } else { + NSLog(@"TH2 reads the fabric index: Success"); + } + + VerifyOrReturn(CheckValue("status", err ? err.code : 0, 0)); + + { + th2FabricIndex = value; + } + + NextTest(); + }]; + + return CHIP_NO_ERROR; + } + + CHIP_ERROR TestTh1SendsARemoveAllGroupsCommandToDut_7() + { + + MTRBaseDevice * device = GetDevice("alpha"); + __auto_type * cluster = [[MTRBaseClusterGroups alloc] initWithDevice:device endpointID:@(1) queue:mCallbackQueue]; + VerifyOrReturnError(cluster != nil, CHIP_ERROR_INCORRECT_STATE); + + [cluster removeAllGroupsWithCompletion: + ^(NSError * _Nullable err) { + if (err != nil) { + NSLog(@"TH1 sends a RemoveAllGroups command to DUT.: Error: %@", err); + } else { + NSLog(@"TH1 sends a RemoveAllGroups command to DUT.: Success"); + } + + VerifyOrReturn(CheckValue("status", err ? err.code : 0, 0)); + + NextTest(); + }]; + + return CHIP_NO_ERROR; + } + + CHIP_ERROR TestTh1AddGroupKeySet_8() + { + + MTRBaseDevice * device = GetDevice("alpha"); + __auto_type * cluster = [[MTRBaseClusterGroupKeyManagement alloc] initWithDevice:device endpointID:@(0) queue:mCallbackQueue]; + VerifyOrReturnError(cluster != nil, CHIP_ERROR_INCORRECT_STATE); + + __auto_type * params = [[MTRGroupKeyManagementClusterKeySetWriteParams alloc] init]; + params.groupKeySet = [[MTRGroupKeyManagementClusterGroupKeySetStruct alloc] init]; + ((MTRGroupKeyManagementClusterGroupKeySetStruct *) params.groupKeySet).groupKeySetID = + [NSNumber numberWithUnsignedShort:417U]; + ((MTRGroupKeyManagementClusterGroupKeySetStruct *) params.groupKeySet).groupKeySecurityPolicy = + [NSNumber numberWithUnsignedChar:0U]; + ((MTRGroupKeyManagementClusterGroupKeySetStruct *) params.groupKeySet).epochKey0 = + [[NSData alloc] initWithBytes:"\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257" length:16]; + ((MTRGroupKeyManagementClusterGroupKeySetStruct *) params.groupKeySet).epochStartTime0 = + [NSNumber numberWithUnsignedLongLong:1110000ULL]; + ((MTRGroupKeyManagementClusterGroupKeySetStruct *) params.groupKeySet).epochKey1 = + [[NSData alloc] initWithBytes:"\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277" length:16]; + ((MTRGroupKeyManagementClusterGroupKeySetStruct *) params.groupKeySet).epochStartTime1 = + [NSNumber numberWithUnsignedLongLong:1110001ULL]; + ((MTRGroupKeyManagementClusterGroupKeySetStruct *) params.groupKeySet).epochKey2 = + [[NSData alloc] initWithBytes:"\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317" length:16]; + ((MTRGroupKeyManagementClusterGroupKeySetStruct *) params.groupKeySet).epochStartTime2 = + [NSNumber numberWithUnsignedLongLong:1110002ULL]; + + [cluster keySetWriteWithParams:params completion: + ^(NSError * _Nullable err) { + if (err != nil) { + NSLog(@"TH 1 Add Group KeySet.: Error: %@", err); + } else { + NSLog(@"TH 1 Add Group KeySet.: Success"); + } + + VerifyOrReturn(CheckValue("status", err ? err.code : 0, 0)); + + NextTest(); + }]; + + return CHIP_NO_ERROR; + } + + CHIP_ERROR TestTh1MapKeySetsToGroupId_9() + { + + MTRBaseDevice * device = GetDevice("alpha"); + __auto_type * cluster = [[MTRBaseClusterGroupKeyManagement alloc] initWithDevice:device endpointID:@(0) queue:mCallbackQueue]; + VerifyOrReturnError(cluster != nil, CHIP_ERROR_INCORRECT_STATE); + + id groupKeyMapArgument; + { + NSMutableArray * temp_0 = [[NSMutableArray alloc] init]; + temp_0[0] = [[MTRGroupKeyManagementClusterGroupKeyMapStruct alloc] init]; + ((MTRGroupKeyManagementClusterGroupKeyMapStruct *) temp_0[0]).groupId = mG1.HasValue() ? [NSNumber numberWithUnsignedShort:mG1.Value()] : [NSNumber numberWithUnsignedShort:1U]; + ((MTRGroupKeyManagementClusterGroupKeyMapStruct *) temp_0[0]).groupKeySetID = + [NSNumber numberWithUnsignedShort:417U]; + ((MTRGroupKeyManagementClusterGroupKeyMapStruct *) temp_0[0]).fabricIndex = + [NSNumber numberWithUnsignedChar:0U]; + + groupKeyMapArgument = temp_0; + } + [cluster writeAttributeGroupKeyMapWithValue:groupKeyMapArgument completion:^(NSError * _Nullable err) { + if (err != nil) { + NSLog(@"TH1 Map KeySets to GroupId.: Error: %@", err); + } else { + NSLog(@"TH1 Map KeySets to GroupId.: Success"); + } + + VerifyOrReturn(CheckValue("status", err ? err.code : 0, 0)); + + NextTest(); + }]; + + return CHIP_NO_ERROR; + } + + CHIP_ERROR TestTh1SendsAAddGroupCommandToDutForG1_10() + { + + MTRBaseDevice * device = GetDevice("alpha"); + __auto_type * cluster = [[MTRBaseClusterGroups alloc] initWithDevice:device endpointID:@(1) queue:mCallbackQueue]; + VerifyOrReturnError(cluster != nil, CHIP_ERROR_INCORRECT_STATE); + + __auto_type * params = [[MTRGroupsClusterAddGroupParams alloc] init]; + params.groupID = mG1.HasValue() ? [NSNumber numberWithUnsignedShort:mG1.Value()] : [NSNumber numberWithUnsignedShort:1U]; + params.groupName = @"Group1"; + [cluster addGroupWithParams:params completion: + ^(MTRGroupsClusterAddGroupResponseParams * _Nullable values, NSError * _Nullable err) { + if (err != nil) { + NSLog(@"TH1 sends a AddGroup command to DUT for G1.: Error: %@", err); + } else { + NSLog(@"TH1 sends a AddGroup command to DUT for G1.: Success"); + } + + VerifyOrReturn(CheckValue("status", err ? err.code : 0, 0)); + + { + id actualValue = values.status; + VerifyOrReturn(CheckValue("Status", actualValue, 0U)); + } + + { + id actualValue = values.groupID; + VerifyOrReturn(CheckValue("GroupID", actualValue, mG1.HasValue() ? mG1.Value() : 1U)); + } + + NextTest(); + }]; + + return CHIP_NO_ERROR; + } + + CHIP_ERROR TestPreparationStepTh2AddGroupKeySet_11() + { + + MTRBaseDevice * device = GetDevice("beta"); + __auto_type * cluster = [[MTRBaseClusterGroupKeyManagement alloc] initWithDevice:device endpointID:@(0) queue:mCallbackQueue]; + VerifyOrReturnError(cluster != nil, CHIP_ERROR_INCORRECT_STATE); + + __auto_type * params = [[MTRGroupKeyManagementClusterKeySetWriteParams alloc] init]; + params.groupKeySet = [[MTRGroupKeyManagementClusterGroupKeySetStruct alloc] init]; + ((MTRGroupKeyManagementClusterGroupKeySetStruct *) params.groupKeySet).groupKeySetID = + [NSNumber numberWithUnsignedShort:418U]; + ((MTRGroupKeyManagementClusterGroupKeySetStruct *) params.groupKeySet).groupKeySecurityPolicy = + [NSNumber numberWithUnsignedChar:0U]; + ((MTRGroupKeyManagementClusterGroupKeySetStruct *) params.groupKeySet).epochKey0 = + [[NSData alloc] initWithBytes:"\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257" length:16]; + ((MTRGroupKeyManagementClusterGroupKeySetStruct *) params.groupKeySet).epochStartTime0 = + [NSNumber numberWithUnsignedLongLong:1120000ULL]; + ((MTRGroupKeyManagementClusterGroupKeySetStruct *) params.groupKeySet).epochKey1 = + [[NSData alloc] initWithBytes:"\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277" length:16]; + ((MTRGroupKeyManagementClusterGroupKeySetStruct *) params.groupKeySet).epochStartTime1 = + [NSNumber numberWithUnsignedLongLong:1120001ULL]; + ((MTRGroupKeyManagementClusterGroupKeySetStruct *) params.groupKeySet).epochKey2 = + [[NSData alloc] initWithBytes:"\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317" length:16]; + ((MTRGroupKeyManagementClusterGroupKeySetStruct *) params.groupKeySet).epochStartTime2 = + [NSNumber numberWithUnsignedLongLong:1120002ULL]; + + [cluster keySetWriteWithParams:params completion: + ^(NSError * _Nullable err) { + if (err != nil) { + NSLog(@"Preparation step : TH2 Add Group KeySet.: Error: %@", err); + } else { + NSLog(@"Preparation step : TH2 Add Group KeySet.: Success"); + } + + VerifyOrReturn(CheckValue("status", err ? err.code : 0, 0)); + + NextTest(); + }]; + + return CHIP_NO_ERROR; + } + + CHIP_ERROR TestPreparationStepTh2MapKeySetsToGroupId_12() + { + + MTRBaseDevice * device = GetDevice("beta"); + __auto_type * cluster = [[MTRBaseClusterGroupKeyManagement alloc] initWithDevice:device endpointID:@(0) queue:mCallbackQueue]; + VerifyOrReturnError(cluster != nil, CHIP_ERROR_INCORRECT_STATE); + + id groupKeyMapArgument; + { + NSMutableArray * temp_0 = [[NSMutableArray alloc] init]; + temp_0[0] = [[MTRGroupKeyManagementClusterGroupKeyMapStruct alloc] init]; + ((MTRGroupKeyManagementClusterGroupKeyMapStruct *) temp_0[0]).groupId = mG1.HasValue() ? [NSNumber numberWithUnsignedShort:mG1.Value()] : [NSNumber numberWithUnsignedShort:1U]; + ((MTRGroupKeyManagementClusterGroupKeyMapStruct *) temp_0[0]).groupKeySetID = + [NSNumber numberWithUnsignedShort:418U]; + ((MTRGroupKeyManagementClusterGroupKeyMapStruct *) temp_0[0]).fabricIndex = + [NSNumber numberWithUnsignedChar:0U]; + + groupKeyMapArgument = temp_0; + } + [cluster writeAttributeGroupKeyMapWithValue:groupKeyMapArgument completion:^(NSError * _Nullable err) { + if (err != nil) { + NSLog(@"Preparation step TH2 Map KeySets to GroupId.: Error: %@", err); + } else { + NSLog(@"Preparation step TH2 Map KeySets to GroupId.: Success"); + } + + VerifyOrReturn(CheckValue("status", err ? err.code : 0, 0)); + + NextTest(); + }]; + + return CHIP_NO_ERROR; + } + + CHIP_ERROR TestTh2SendsAAddGroupCommandToDutForG1_13() + { + + MTRBaseDevice * device = GetDevice("beta"); + __auto_type * cluster = [[MTRBaseClusterGroups alloc] initWithDevice:device endpointID:@(1) queue:mCallbackQueue]; + VerifyOrReturnError(cluster != nil, CHIP_ERROR_INCORRECT_STATE); + + __auto_type * params = [[MTRGroupsClusterAddGroupParams alloc] init]; + params.groupID = mG1.HasValue() ? [NSNumber numberWithUnsignedShort:mG1.Value()] : [NSNumber numberWithUnsignedShort:1U]; + params.groupName = @"Group1"; + [cluster addGroupWithParams:params completion: + ^(MTRGroupsClusterAddGroupResponseParams * _Nullable values, NSError * _Nullable err) { + if (err != nil) { + NSLog(@"TH2 sends a AddGroup command to DUT for G1.: Error: %@", err); + } else { + NSLog(@"TH2 sends a AddGroup command to DUT for G1.: Success"); + } + + VerifyOrReturn(CheckValue("status", err ? err.code : 0, 0)); + + { + id actualValue = values.status; + VerifyOrReturn(CheckValue("Status", actualValue, 0U)); + } + + { + id actualValue = values.groupID; + VerifyOrReturn(CheckValue("GroupID", actualValue, mG1.HasValue() ? mG1.Value() : 1U)); + } + + NextTest(); + }]; + + return CHIP_NO_ERROR; + } + NSNumber * _Nullable fabricCapacity; + + CHIP_ERROR TestTh1ConfirmsItsSceneTableIsEmptyAndGetsItsCapacity_14() + { + + MTRBaseDevice * device = GetDevice("alpha"); + __auto_type * cluster = [[MTRBaseClusterScenes alloc] initWithDevice:device endpointID:@(1) queue:mCallbackQueue]; + VerifyOrReturnError(cluster != nil, CHIP_ERROR_INCORRECT_STATE); + + __auto_type * params = [[MTRScenesClusterGetSceneMembershipParams alloc] init]; + params.groupID = mG1.HasValue() ? [NSNumber numberWithUnsignedShort:mG1.Value()] : [NSNumber numberWithUnsignedShort:1U]; + [cluster getSceneMembershipWithParams:params completion: + ^(MTRScenesClusterGetSceneMembershipResponseParams * _Nullable values, NSError * _Nullable err) { + if (err != nil) { + NSLog(@"TH1 confirms its Scene table is empty and gets its capacity: Error: %@", err); + } else { + NSLog(@"TH1 confirms its Scene table is empty and gets its capacity: Success"); + } + + VerifyOrReturn(CheckValue("status", err ? err.code : 0, 0)); + + { + id actualValue = values.status; + VerifyOrReturn(CheckValue("Status", actualValue, 0U)); + } + + { + fabricCapacity = values.capacity; + } + + { + id actualValue = values.groupID; + VerifyOrReturn(CheckValue("GroupID", actualValue, mG1.HasValue() ? mG1.Value() : 1U)); + } + + NextTest(); + }]; + + return CHIP_NO_ERROR; + } + + CHIP_ERROR TestTh2ConfirmsItsSceneTableIsEmptyAndHasTheSameCapacityAsTh1_15() + { + + MTRBaseDevice * device = GetDevice("beta"); + __auto_type * cluster = [[MTRBaseClusterScenes alloc] initWithDevice:device endpointID:@(1) queue:mCallbackQueue]; + VerifyOrReturnError(cluster != nil, CHIP_ERROR_INCORRECT_STATE); + + __auto_type * params = [[MTRScenesClusterGetSceneMembershipParams alloc] init]; + params.groupID = mG1.HasValue() ? [NSNumber numberWithUnsignedShort:mG1.Value()] : [NSNumber numberWithUnsignedShort:1U]; + [cluster getSceneMembershipWithParams:params completion: + ^(MTRScenesClusterGetSceneMembershipResponseParams * _Nullable values, NSError * _Nullable err) { + if (err != nil) { + NSLog(@"TH2 confirms its Scene table is empty and has the same capacity as TH1: Error: %@", err); + } else { + NSLog(@"TH2 confirms its Scene table is empty and has the same capacity as TH1: Success"); + } + + VerifyOrReturn(CheckValue("status", err ? err.code : 0, 0)); + + { + id actualValue = values.status; + VerifyOrReturn(CheckValue("Status", actualValue, 0U)); + } + + { + id actualValue = values.capacity; + if (fabricCapacity == nil) { + VerifyOrReturn(CheckValueNull("Capacity", actualValue)); + } else { + VerifyOrReturn(CheckValueNonNull("Capacity", actualValue)); + VerifyOrReturn(CheckValue("Capacity", actualValue, fabricCapacity)); + } + } + + { + id actualValue = values.groupID; + VerifyOrReturn(CheckValue("GroupID", actualValue, mG1.HasValue() ? mG1.Value() : 1U)); + } + + NextTest(); + }]; + + return CHIP_NO_ERROR; + } + + CHIP_ERROR TestTh1SendsAnAddSceneCommandToDutForScene1G1_16() + { + + MTRBaseDevice * device = GetDevice("alpha"); + __auto_type * cluster = [[MTRBaseClusterScenes alloc] initWithDevice:device endpointID:@(1) queue:mCallbackQueue]; + VerifyOrReturnError(cluster != nil, CHIP_ERROR_INCORRECT_STATE); + + __auto_type * params = [[MTRScenesClusterAddSceneParams alloc] init]; + params.groupID = mG1.HasValue() ? [NSNumber numberWithUnsignedShort:mG1.Value()] : [NSNumber numberWithUnsignedShort:1U]; + params.sceneID = + [NSNumber numberWithUnsignedChar:1U]; + params.transitionTime = + [NSNumber numberWithUnsignedShort:1U]; + params.sceneName = @"Scene1"; + { + NSMutableArray * temp_0 = [[NSMutableArray alloc] init]; + params.extensionFieldSets = temp_0; + } + [cluster addSceneWithParams:params completion: + ^(MTRScenesClusterAddSceneResponseParams * _Nullable values, NSError * _Nullable err) { + if (err != nil) { + NSLog(@"TH1 sends an AddScene command to DUT for Scene 1 G1: Error: %@", err); + } else { + NSLog(@"TH1 sends an AddScene command to DUT for Scene 1 G1: Success"); + } + + VerifyOrReturn(CheckValue("status", err ? err.code : 0, 0)); + + { + id actualValue = values.status; + VerifyOrReturn(CheckValue("Status", actualValue, 0U)); + } + + { + id actualValue = values.groupID; + VerifyOrReturn(CheckValue("GroupID", actualValue, mG1.HasValue() ? mG1.Value() : 1U)); + } + + { + id actualValue = values.sceneID; + VerifyOrReturn(CheckValue("SceneID", actualValue, 1U)); + } + + NextTest(); + }]; + + return CHIP_NO_ERROR; + } + + CHIP_ERROR TestTh1SendsAnAddSceneCommandToDutForScene2G1_17() + { + + MTRBaseDevice * device = GetDevice("alpha"); + __auto_type * cluster = [[MTRBaseClusterScenes alloc] initWithDevice:device endpointID:@(1) queue:mCallbackQueue]; + VerifyOrReturnError(cluster != nil, CHIP_ERROR_INCORRECT_STATE); + + __auto_type * params = [[MTRScenesClusterAddSceneParams alloc] init]; + params.groupID = mG1.HasValue() ? [NSNumber numberWithUnsignedShort:mG1.Value()] : [NSNumber numberWithUnsignedShort:1U]; + params.sceneID = + [NSNumber numberWithUnsignedChar:2U]; + params.transitionTime = + [NSNumber numberWithUnsignedShort:0U]; + params.sceneName = @"Scene2"; + { + NSMutableArray * temp_0 = [[NSMutableArray alloc] init]; + params.extensionFieldSets = temp_0; + } + [cluster addSceneWithParams:params completion: + ^(MTRScenesClusterAddSceneResponseParams * _Nullable values, NSError * _Nullable err) { + if (err != nil) { + NSLog(@"TH1 sends an AddScene command to DUT for Scene 2 G1: Error: %@", err); + } else { + NSLog(@"TH1 sends an AddScene command to DUT for Scene 2 G1: Success"); + } + + VerifyOrReturn(CheckValue("status", err ? err.code : 0, 0)); + + { + id actualValue = values.status; + VerifyOrReturn(CheckValue("Status", actualValue, 0U)); + } + + { + id actualValue = values.groupID; + VerifyOrReturn(CheckValue("GroupID", actualValue, mG1.HasValue() ? mG1.Value() : 1U)); + } + + { + id actualValue = values.sceneID; + VerifyOrReturn(CheckValue("SceneID", actualValue, 2U)); + } + + NextTest(); + }]; + + return CHIP_NO_ERROR; + } + + CHIP_ERROR TestTh2SendsAnAddSceneCommandToDutForScene1G1_18() + { + + MTRBaseDevice * device = GetDevice("beta"); + __auto_type * cluster = [[MTRBaseClusterScenes alloc] initWithDevice:device endpointID:@(1) queue:mCallbackQueue]; + VerifyOrReturnError(cluster != nil, CHIP_ERROR_INCORRECT_STATE); + + __auto_type * params = [[MTRScenesClusterAddSceneParams alloc] init]; + params.groupID = mG1.HasValue() ? [NSNumber numberWithUnsignedShort:mG1.Value()] : [NSNumber numberWithUnsignedShort:1U]; + params.sceneID = + [NSNumber numberWithUnsignedChar:1U]; + params.transitionTime = + [NSNumber numberWithUnsignedShort:1U]; + params.sceneName = @"Scene1"; + { + NSMutableArray * temp_0 = [[NSMutableArray alloc] init]; + params.extensionFieldSets = temp_0; + } + [cluster addSceneWithParams:params completion: + ^(MTRScenesClusterAddSceneResponseParams * _Nullable values, NSError * _Nullable err) { + if (err != nil) { + NSLog(@"TH2 sends an AddScene command to DUT for Scene 1 G1: Error: %@", err); + } else { + NSLog(@"TH2 sends an AddScene command to DUT for Scene 1 G1: Success"); + } + + VerifyOrReturn(CheckValue("status", err ? err.code : 0, 0)); + + { + id actualValue = values.status; + VerifyOrReturn(CheckValue("Status", actualValue, 0U)); + } + + { + id actualValue = values.groupID; + VerifyOrReturn(CheckValue("GroupID", actualValue, mG1.HasValue() ? mG1.Value() : 1U)); + } + + { + id actualValue = values.sceneID; + VerifyOrReturn(CheckValue("SceneID", actualValue, 1U)); + } + + NextTest(); + }]; + + return CHIP_NO_ERROR; + } + + CHIP_ERROR TestTh2SendsAnAddSceneCommandToDutForScene2G1_19() + { + + MTRBaseDevice * device = GetDevice("beta"); + __auto_type * cluster = [[MTRBaseClusterScenes alloc] initWithDevice:device endpointID:@(1) queue:mCallbackQueue]; + VerifyOrReturnError(cluster != nil, CHIP_ERROR_INCORRECT_STATE); + + __auto_type * params = [[MTRScenesClusterAddSceneParams alloc] init]; + params.groupID = mG1.HasValue() ? [NSNumber numberWithUnsignedShort:mG1.Value()] : [NSNumber numberWithUnsignedShort:1U]; + params.sceneID = + [NSNumber numberWithUnsignedChar:2U]; + params.transitionTime = + [NSNumber numberWithUnsignedShort:0U]; + params.sceneName = @"Scene2"; + { + NSMutableArray * temp_0 = [[NSMutableArray alloc] init]; + params.extensionFieldSets = temp_0; + } + [cluster addSceneWithParams:params completion: + ^(MTRScenesClusterAddSceneResponseParams * _Nullable values, NSError * _Nullable err) { + if (err != nil) { + NSLog(@"TH2 sends an AddScene command to DUT for Scene 2 G1: Error: %@", err); + } else { + NSLog(@"TH2 sends an AddScene command to DUT for Scene 2 G1: Success"); + } + + VerifyOrReturn(CheckValue("status", err ? err.code : 0, 0)); + + { + id actualValue = values.status; + VerifyOrReturn(CheckValue("Status", actualValue, 0U)); + } + + { + id actualValue = values.groupID; + VerifyOrReturn(CheckValue("GroupID", actualValue, mG1.HasValue() ? mG1.Value() : 1U)); + } + + { + id actualValue = values.sceneID; + VerifyOrReturn(CheckValue("SceneID", actualValue, 2U)); + } + + NextTest(); + }]; + + return CHIP_NO_ERROR; + } + + CHIP_ERROR TestTh1ConfirmsItsG1Holds2Scenes_20() + { + + MTRBaseDevice * device = GetDevice("alpha"); + __auto_type * cluster = [[MTRBaseClusterScenes alloc] initWithDevice:device endpointID:@(1) queue:mCallbackQueue]; + VerifyOrReturnError(cluster != nil, CHIP_ERROR_INCORRECT_STATE); + + __auto_type * params = [[MTRScenesClusterGetSceneMembershipParams alloc] init]; + params.groupID = mG1.HasValue() ? [NSNumber numberWithUnsignedShort:mG1.Value()] : [NSNumber numberWithUnsignedShort:1U]; + [cluster getSceneMembershipWithParams:params completion: + ^(MTRScenesClusterGetSceneMembershipResponseParams * _Nullable values, NSError * _Nullable err) { + if (err != nil) { + NSLog(@"TH1 confirms its G1 holds 2 scenes: Error: %@", err); + } else { + NSLog(@"TH1 confirms its G1 holds 2 scenes: Success"); + } + + VerifyOrReturn(CheckValue("status", err ? err.code : 0, 0)); + + { + id actualValue = values.status; + VerifyOrReturn(CheckValue("Status", actualValue, 0U)); + } + + { + id actualValue = values.capacity; + VerifyOrReturn(CheckValueNonNull("Capacity", actualValue)); + VerifyOrReturn(CheckValue("Capacity", actualValue, [fabricCapacity unsignedCharValue] - 2U)); + } + + { + id actualValue = values.groupID; + VerifyOrReturn(CheckValue("GroupID", actualValue, mG1.HasValue() ? mG1.Value() : 1U)); + } + + { + id actualValue = values.sceneList; + VerifyOrReturn(CheckValue("SceneList", [actualValue count], static_cast(2))); + VerifyOrReturn(CheckValue("", actualValue[0], 1U)); + VerifyOrReturn(CheckValue("", actualValue[1], 2U)); + } + + NextTest(); + }]; + + return CHIP_NO_ERROR; + } + + CHIP_ERROR TestTh2ConfirmsItsG1Holds2Scenes_21() + { + + MTRBaseDevice * device = GetDevice("beta"); + __auto_type * cluster = [[MTRBaseClusterScenes alloc] initWithDevice:device endpointID:@(1) queue:mCallbackQueue]; + VerifyOrReturnError(cluster != nil, CHIP_ERROR_INCORRECT_STATE); + + __auto_type * params = [[MTRScenesClusterGetSceneMembershipParams alloc] init]; + params.groupID = mG1.HasValue() ? [NSNumber numberWithUnsignedShort:mG1.Value()] : [NSNumber numberWithUnsignedShort:1U]; + [cluster getSceneMembershipWithParams:params completion: + ^(MTRScenesClusterGetSceneMembershipResponseParams * _Nullable values, NSError * _Nullable err) { + if (err != nil) { + NSLog(@"TH2 confirms its G1 holds 2 scenes: Error: %@", err); + } else { + NSLog(@"TH2 confirms its G1 holds 2 scenes: Success"); + } + + VerifyOrReturn(CheckValue("status", err ? err.code : 0, 0)); + + { + id actualValue = values.status; + VerifyOrReturn(CheckValue("Status", actualValue, 0U)); + } + + { + id actualValue = values.capacity; + VerifyOrReturn(CheckValueNonNull("Capacity", actualValue)); + VerifyOrReturn(CheckValue("Capacity", actualValue, [fabricCapacity unsignedCharValue] - 2U)); + } + + { + id actualValue = values.groupID; + VerifyOrReturn(CheckValue("GroupID", actualValue, mG1.HasValue() ? mG1.Value() : 1U)); + } + + { + id actualValue = values.sceneList; + VerifyOrReturn(CheckValue("SceneList", [actualValue count], static_cast(2))); + VerifyOrReturn(CheckValue("", actualValue[0], 1U)); + VerifyOrReturn(CheckValue("", actualValue[1], 2U)); + } + + NextTest(); + }]; + + return CHIP_NO_ERROR; + } + + CHIP_ERROR TestTh1SendsRemoveFabricCommandForTh2_22() + { + + MTRBaseDevice * device = GetDevice("alpha"); + __auto_type * cluster = [[MTRBaseClusterOperationalCredentials alloc] initWithDevice:device endpointID:@(0) queue:mCallbackQueue]; + VerifyOrReturnError(cluster != nil, CHIP_ERROR_INCORRECT_STATE); + + __auto_type * params = [[MTROperationalCredentialsClusterRemoveFabricParams alloc] init]; + params.fabricIndex = + [th2FabricIndex copy]; + [cluster removeFabricWithParams:params completion: + ^(MTROperationalCredentialsClusterNOCResponseParams * _Nullable values, NSError * _Nullable err) { + if (err != nil) { + NSLog(@"TH1 sends RemoveFabric command for TH2: Error: %@", err); + } else { + NSLog(@"TH1 sends RemoveFabric command for TH2: Success"); + } + + VerifyOrReturn(CheckValue("status", err ? err.code : 0, 0)); + + NextTest(); + }]; + + return CHIP_NO_ERROR; + } + + CHIP_ERROR TestTh1ConfirmsItsG1StillHolds2Scenes_23() + { + + MTRBaseDevice * device = GetDevice("alpha"); + __auto_type * cluster = [[MTRBaseClusterScenes alloc] initWithDevice:device endpointID:@(1) queue:mCallbackQueue]; + VerifyOrReturnError(cluster != nil, CHIP_ERROR_INCORRECT_STATE); + + __auto_type * params = [[MTRScenesClusterGetSceneMembershipParams alloc] init]; + params.groupID = mG1.HasValue() ? [NSNumber numberWithUnsignedShort:mG1.Value()] : [NSNumber numberWithUnsignedShort:1U]; + [cluster getSceneMembershipWithParams:params completion: + ^(MTRScenesClusterGetSceneMembershipResponseParams * _Nullable values, NSError * _Nullable err) { + if (err != nil) { + NSLog(@"TH1 confirms its G1 still holds 2 scenes: Error: %@", err); + } else { + NSLog(@"TH1 confirms its G1 still holds 2 scenes: Success"); + } + + VerifyOrReturn(CheckValue("status", err ? err.code : 0, 0)); + + { + id actualValue = values.status; + VerifyOrReturn(CheckValue("Status", actualValue, 0U)); + } + + { + id actualValue = values.capacity; + VerifyOrReturn(CheckValueNonNull("Capacity", actualValue)); + VerifyOrReturn(CheckValue("Capacity", actualValue, [fabricCapacity unsignedCharValue] - 2U)); + } + + { + id actualValue = values.groupID; + VerifyOrReturn(CheckValue("GroupID", actualValue, mG1.HasValue() ? mG1.Value() : 1U)); + } + + { + id actualValue = values.sceneList; + VerifyOrReturn(CheckValue("SceneList", [actualValue count], static_cast(2))); + VerifyOrReturn(CheckValue("", actualValue[0], 1U)); + VerifyOrReturn(CheckValue("", actualValue[1], 2U)); + } + + NextTest(); + }]; + + return CHIP_NO_ERROR; + } +}; + class Test_TC_S_1_1 : public TestCommandBridge { public: // NOLINTBEGIN(clang-analyzer-nullability.NullPassedToNonnull): Test constructor nullability not enforced @@ -192351,6 +193416,7 @@ void registerCommandsTests(Commands & commands) make_unique(), make_unique(), make_unique(), + make_unique(), make_unique(), make_unique(), make_unique(),