diff --git a/src/app/tests/suites/TestFabricRemovalWhileSubscribed.yaml b/src/app/tests/suites/TestFabricRemovalWhileSubscribed.yaml new file mode 100644 index 00000000000000..5271f380749cf1 --- /dev/null +++ b/src/app/tests/suites/TestFabricRemovalWhileSubscribed.yaml @@ -0,0 +1,102 @@ +# Copyright (c) 2022 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. + +name: + Validate removal of a fabric while another fabric is subscribed to the + fabrics list does not crash + +config: + nodeId: 0x12344321 + cluster: "Operational Credentials" + endpoint: 0 + discriminator: + type: INT16U + defaultValue: 3840 + payload: + type: CHAR_STRING + defaultValue: "MT:-24J0AFN00KA0648G00" # This value needs to be generated automatically + +tests: + - label: "Wait for the commissioned device to be retrieved" + cluster: "DelayCommands" + command: "WaitForCommissionee" + arguments: + values: + - name: "nodeId" + value: nodeId + + - label: "Read number of commissioned fabrics" + command: "readAttribute" + attribute: "CommissionedFabrics" + response: + value: 1 + constraints: + type: uint8 + + - label: "Read current fabric index" + command: "readAttribute" + attribute: "CurrentFabricIndex" + response: + saveAs: ourFabricIndex + constraints: + type: uint8 + # 0 is not a valid value, but past that we have no idea what the + # other side will claim here. + minValue: 1 + + - label: "Open commissioning window from alpha" + cluster: "AdministratorCommissioning" + command: "OpenBasicCommissioningWindow" + timedInteractionTimeoutMs: 10000 + arguments: + values: + - name: "CommissioningTimeout" + value: 180 + + - label: "Commission from beta" + identity: "beta" + cluster: "CommissionerCommands" + command: "PairWithCode" + arguments: + values: + - name: "nodeId" + value: 0x12345 + - name: "payload" + value: payload + + - label: "Wait for the commissioned device to be retrieved for beta" + identity: "beta" + cluster: "DelayCommands" + command: "WaitForCommissionee" + arguments: + values: + - name: "nodeId" + value: 0x12345 + + - label: "Subscribe Fabrics Attribute from beta" + identity: "beta" + command: "subscribeAttribute" + attribute: "Fabrics" + minInterval: 2 + maxInterval: 5 + response: + constraints: + type: list + + - label: "Remove single own fabric" + command: "RemoveFabric" + arguments: + values: + - name: "FabricIndex" + value: ourFabricIndex diff --git a/src/app/tests/suites/tests.js b/src/app/tests/suites/tests.js index b354d8be397579..d9f3c3fa83cb30 100644 --- a/src/app/tests/suites/tests.js +++ b/src/app/tests/suites/tests.js @@ -808,6 +808,7 @@ function getTests() { "TestConfigVariables", "TestDescriptorCluster", "TestBasicInformation", + "TestFabricRemovalWhileSubscribed", "TestGeneralCommissioning", "TestIdentifyCluster", "TestOperationalCredentialsCluster", diff --git a/zzz_generated/chip-tool/zap-generated/test/Commands.h b/zzz_generated/chip-tool/zap-generated/test/Commands.h index c52a297ef267d6..c705d0cca3d5b1 100644 --- a/zzz_generated/chip-tool/zap-generated/test/Commands.h +++ b/zzz_generated/chip-tool/zap-generated/test/Commands.h @@ -199,6 +199,7 @@ class TestList : public Command printf("TestConfigVariables\n"); printf("TestDescriptorCluster\n"); printf("TestBasicInformation\n"); + printf("TestFabricRemovalWhileSubscribed\n"); printf("TestGeneralCommissioning\n"); printf("TestIdentifyCluster\n"); printf("TestOperationalCredentialsCluster\n"); @@ -50269,6 +50270,179 @@ class TestBasicInformationSuite : public TestCommand } }; +class TestFabricRemovalWhileSubscribedSuite : public TestCommand +{ +public: + TestFabricRemovalWhileSubscribedSuite(CredentialIssuerCommands * credsIssuerConfig) : + TestCommand("TestFabricRemovalWhileSubscribed", 8, credsIssuerConfig) + { + AddArgument("nodeId", 0, UINT64_MAX, &mNodeId); + AddArgument("cluster", &mCluster); + AddArgument("endpoint", 0, UINT16_MAX, &mEndpoint); + AddArgument("discriminator", 0, UINT16_MAX, &mDiscriminator); + AddArgument("payload", &mPayload); + AddArgument("timeout", 0, UINT16_MAX, &mTimeout); + } + + ~TestFabricRemovalWhileSubscribedSuite() {} + + chip::System::Clock::Timeout GetWaitDuration() const override + { + return chip::System::Clock::Seconds16(mTimeout.ValueOr(kTimeoutInSeconds)); + } + +private: + chip::Optional mNodeId; + chip::Optional mCluster; + chip::Optional mEndpoint; + chip::Optional mDiscriminator; + chip::Optional mPayload; + chip::Optional mTimeout; + + chip::FabricIndex ourFabricIndex; + + chip::EndpointId GetEndpoint(chip::EndpointId endpoint) { return mEndpoint.HasValue() ? mEndpoint.Value() : endpoint; } + + // + // Tests methods + // + + void OnResponse(const chip::app::StatusIB & status, chip::TLV::TLVReader * data) override + { + bool shouldContinue = false; + + switch (mTestIndex - 1) + { + case 0: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + shouldContinue = true; + break; + case 1: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + { + uint8_t value; + VerifyOrReturn(CheckDecodeValue(chip::app::DataModel::Decode(*data, value))); + VerifyOrReturn(CheckValue("commissionedFabrics", value, 1U)); + VerifyOrReturn(CheckConstraintType("value", "", "uint8")); + } + break; + case 2: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + { + chip::FabricIndex value; + VerifyOrReturn(CheckDecodeValue(chip::app::DataModel::Decode(*data, value))); + VerifyOrReturn(CheckConstraintType("value", "", "uint8")); + VerifyOrReturn(CheckConstraintMinValue("value", value, 1U)); + ourFabricIndex = value; + } + break; + case 3: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + break; + case 4: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + shouldContinue = true; + break; + case 5: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + shouldContinue = true; + break; + case 6: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + { + chip::app::DataModel::DecodableList< + chip::app::Clusters::OperationalCredentials::Structs::FabricDescriptor::DecodableType> + value; + VerifyOrReturn(CheckDecodeValue(chip::app::DataModel::Decode(*data, value))); + VerifyOrReturn(CheckConstraintType("value", "", "list")); + } + break; + case 7: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + { + chip::app::Clusters::OperationalCredentials::Commands::NOCResponse::DecodableType value; + VerifyOrReturn(CheckDecodeValue(chip::app::DataModel::Decode(*data, value))); + } + break; + default: + LogErrorOnFailure(ContinueOnChipMainThread(CHIP_ERROR_INVALID_ARGUMENT)); + } + + if (shouldContinue) + { + ContinueOnChipMainThread(CHIP_NO_ERROR); + } + } + + CHIP_ERROR DoTestStep(uint16_t testIndex) override + { + using namespace chip::app::Clusters; + switch (testIndex) + { + case 0: { + LogStep(0, "Wait for the commissioned device to be retrieved"); + ListFreer listFreer; + chip::app::Clusters::DelayCommands::Commands::WaitForCommissionee::Type value; + value.nodeId = mNodeId.HasValue() ? mNodeId.Value() : 305414945ULL; + return WaitForCommissionee(kIdentityAlpha, value); + } + case 1: { + LogStep(1, "Read number of commissioned fabrics"); + return ReadAttribute(kIdentityAlpha, GetEndpoint(0), OperationalCredentials::Id, + OperationalCredentials::Attributes::CommissionedFabrics::Id, true, chip::NullOptional); + } + case 2: { + LogStep(2, "Read current fabric index"); + return ReadAttribute(kIdentityAlpha, GetEndpoint(0), OperationalCredentials::Id, + OperationalCredentials::Attributes::CurrentFabricIndex::Id, true, chip::NullOptional); + } + case 3: { + LogStep(3, "Open commissioning window from alpha"); + ListFreer listFreer; + chip::app::Clusters::AdministratorCommissioning::Commands::OpenBasicCommissioningWindow::Type value; + value.commissioningTimeout = 180U; + return SendCommand(kIdentityAlpha, GetEndpoint(0), AdministratorCommissioning::Id, + AdministratorCommissioning::Commands::OpenBasicCommissioningWindow::Id, value, + chip::Optional(10000), chip::NullOptional + + ); + } + case 4: { + LogStep(4, "Commission from beta"); + ListFreer listFreer; + chip::app::Clusters::CommissionerCommands::Commands::PairWithCode::Type value; + value.nodeId = 74565ULL; + value.payload = mPayload.HasValue() ? mPayload.Value() : chip::Span("MT:-24J0AFN00KA0648G00", 22); + return PairWithCode(kIdentityBeta, value); + } + case 5: { + LogStep(5, "Wait for the commissioned device to be retrieved for beta"); + ListFreer listFreer; + chip::app::Clusters::DelayCommands::Commands::WaitForCommissionee::Type value; + value.nodeId = 74565ULL; + return WaitForCommissionee(kIdentityBeta, value); + } + case 6: { + LogStep(6, "Subscribe Fabrics Attribute from beta"); + return SubscribeAttribute(kIdentityBeta, GetEndpoint(0), OperationalCredentials::Id, + OperationalCredentials::Attributes::Fabrics::Id, 2, 5, true, chip::NullOptional, + chip::NullOptional); + } + case 7: { + LogStep(7, "Remove single own fabric"); + ListFreer listFreer; + chip::app::Clusters::OperationalCredentials::Commands::RemoveFabric::Type value; + value.fabricIndex = ourFabricIndex; + return SendCommand(kIdentityAlpha, GetEndpoint(0), OperationalCredentials::Id, + OperationalCredentials::Commands::RemoveFabric::Id, value, chip::NullOptional + + ); + } + } + return CHIP_NO_ERROR; + } +}; + class TestGeneralCommissioningSuite : public TestCommand { public: @@ -87631,6 +87805,7 @@ void registerCommandsTests(Commands & commands, CredentialIssuerCommands * creds make_unique(credsIssuerConfig), make_unique(credsIssuerConfig), make_unique(credsIssuerConfig), + make_unique(credsIssuerConfig), make_unique(credsIssuerConfig), make_unique(credsIssuerConfig), make_unique(credsIssuerConfig), 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 2489e4e4229c8d..e422930fa5683c 100644 --- a/zzz_generated/darwin-framework-tool/zap-generated/test/Commands.h +++ b/zzz_generated/darwin-framework-tool/zap-generated/test/Commands.h @@ -186,6 +186,7 @@ class TestList : public Command { printf("TestConfigVariables\n"); printf("TestDescriptorCluster\n"); printf("TestBasicInformation\n"); + printf("TestFabricRemovalWhileSubscribed\n"); printf("TestGeneralCommissioning\n"); printf("TestIdentifyCluster\n"); printf("TestOperationalCredentialsCluster\n"); @@ -85078,6 +85079,311 @@ class TestBasicInformation : public TestCommandBridge { } }; +class TestFabricRemovalWhileSubscribed : public TestCommandBridge { +public: + // NOLINTBEGIN(clang-analyzer-nullability.NullPassedToNonnull): Test constructor nullability not enforced + TestFabricRemovalWhileSubscribed() + : TestCommandBridge("TestFabricRemovalWhileSubscribed") + , mTestIndex(0) + { + AddArgument("nodeId", 0, UINT64_MAX, &mNodeId); + AddArgument("cluster", &mCluster); + AddArgument("endpoint", 0, UINT16_MAX, &mEndpoint); + AddArgument("discriminator", 0, UINT16_MAX, &mDiscriminator); + AddArgument("payload", &mPayload); + AddArgument("timeout", 0, UINT16_MAX, &mTimeout); + } + // NOLINTEND(clang-analyzer-nullability.NullPassedToNonnull) + + ~TestFabricRemovalWhileSubscribed() {} + + /////////// TestCommand Interface ///////// + void NextTest() override + { + CHIP_ERROR err = CHIP_NO_ERROR; + + if (0 == mTestIndex) { + ChipLogProgress(chipTool, " **** Test Start: TestFabricRemovalWhileSubscribed\n"); + } + + if (mTestCount == mTestIndex) { + ChipLogProgress(chipTool, " **** Test Complete: TestFabricRemovalWhileSubscribed\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 : Wait for the commissioned device to be retrieved\n"); + err = TestWaitForTheCommissionedDeviceToBeRetrieved_0(); + break; + case 1: + ChipLogProgress(chipTool, " ***** Test Step 1 : Read number of commissioned fabrics\n"); + err = TestReadNumberOfCommissionedFabrics_1(); + break; + case 2: + ChipLogProgress(chipTool, " ***** Test Step 2 : Read current fabric index\n"); + err = TestReadCurrentFabricIndex_2(); + break; + case 3: + ChipLogProgress(chipTool, " ***** Test Step 3 : Open commissioning window from alpha\n"); + err = TestOpenCommissioningWindowFromAlpha_3(); + break; + case 4: + ChipLogProgress(chipTool, " ***** Test Step 4 : Commission from beta\n"); + err = TestCommissionFromBeta_4(); + break; + case 5: + ChipLogProgress(chipTool, " ***** Test Step 5 : Wait for the commissioned device to be retrieved for beta\n"); + err = TestWaitForTheCommissionedDeviceToBeRetrievedForBeta_5(); + break; + case 6: + ChipLogProgress(chipTool, " ***** Test Step 6 : Report: Subscribe Fabrics Attribute from beta\n"); + err = TestReportSubscribeFabricsAttributeFromBeta_6(); + break; + case 7: + ChipLogProgress(chipTool, " ***** Test Step 7 : Subscribe Fabrics Attribute from beta\n"); + err = TestSubscribeFabricsAttributeFromBeta_7(); + break; + case 8: + ChipLogProgress(chipTool, " ***** Test Step 8 : Remove single own fabric\n"); + err = TestRemoveSingleOwnFabric_8(); + 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; + } + + // 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 = 9; + + chip::Optional mNodeId; + chip::Optional mCluster; + chip::Optional mEndpoint; + chip::Optional mDiscriminator; + chip::Optional mPayload; + chip::Optional mTimeout; + + CHIP_ERROR TestWaitForTheCommissionedDeviceToBeRetrieved_0() + { + chip::app::Clusters::DelayCommands::Commands::WaitForCommissionee::Type value; + value.nodeId = mNodeId.HasValue() ? mNodeId.Value() : 305414945ULL; + return WaitForCommissionee("alpha", value); + } + + CHIP_ERROR TestReadNumberOfCommissionedFabrics_1() + { + MTRBaseDevice * device = GetDevice("alpha"); + MTRBaseClusterOperationalCredentials * cluster = + [[MTRBaseClusterOperationalCredentials alloc] initWithDevice:device endpoint:0 queue:mCallbackQueue]; + VerifyOrReturnError(cluster != nil, CHIP_ERROR_INCORRECT_STATE); + + [cluster readAttributeCommissionedFabricsWithCompletionHandler:^(NSNumber * _Nullable value, NSError * _Nullable err) { + NSLog(@"Read number of commissioned fabrics Error: %@", err); + + VerifyOrReturn(CheckValue("status", err ? err.code : 0, 0)); + + { + id actualValue = value; + VerifyOrReturn(CheckValue("CommissionedFabrics", actualValue, 1U)); + } + + VerifyOrReturn(CheckConstraintType("commissionedFabrics", "", "uint8")); + NextTest(); + }]; + + return CHIP_NO_ERROR; + } + NSNumber * _Nonnull ourFabricIndex; + + CHIP_ERROR TestReadCurrentFabricIndex_2() + { + MTRBaseDevice * device = GetDevice("alpha"); + MTRBaseClusterOperationalCredentials * cluster = + [[MTRBaseClusterOperationalCredentials alloc] initWithDevice:device endpoint:0 queue:mCallbackQueue]; + VerifyOrReturnError(cluster != nil, CHIP_ERROR_INCORRECT_STATE); + + [cluster readAttributeCurrentFabricIndexWithCompletionHandler:^(NSNumber * _Nullable value, NSError * _Nullable err) { + NSLog(@"Read current fabric index Error: %@", err); + + VerifyOrReturn(CheckValue("status", err ? err.code : 0, 0)); + + VerifyOrReturn(CheckConstraintType("currentFabricIndex", "", "uint8")); + VerifyOrReturn(CheckConstraintMinValue("currentFabricIndex", [value unsignedCharValue], 1U)); + { + ourFabricIndex = value; + } + + NextTest(); + }]; + + return CHIP_NO_ERROR; + } + + CHIP_ERROR TestOpenCommissioningWindowFromAlpha_3() + { + MTRBaseDevice * device = GetDevice("alpha"); + MTRBaseClusterAdministratorCommissioning * cluster = + [[MTRBaseClusterAdministratorCommissioning alloc] initWithDevice:device endpoint:0 queue:mCallbackQueue]; + VerifyOrReturnError(cluster != nil, CHIP_ERROR_INCORRECT_STATE); + + __auto_type * params = [[MTRAdministratorCommissioningClusterOpenBasicCommissioningWindowParams alloc] init]; + params.commissioningTimeout = [NSNumber numberWithUnsignedShort:180U]; + [cluster openBasicCommissioningWindowWithParams:params + completionHandler:^(NSError * _Nullable err) { + NSLog(@"Open commissioning window from alpha Error: %@", err); + + VerifyOrReturn(CheckValue("status", err ? err.code : 0, 0)); + + NextTest(); + }]; + + return CHIP_NO_ERROR; + } + + CHIP_ERROR TestCommissionFromBeta_4() + { + chip::app::Clusters::CommissionerCommands::Commands::PairWithCode::Type value; + value.nodeId = 74565ULL; + value.payload = mPayload.HasValue() ? mPayload.Value() : chip::Span("MT:-24J0AFN00KA0648G00", 22); + return PairWithCode("beta", value); + } + + CHIP_ERROR TestWaitForTheCommissionedDeviceToBeRetrievedForBeta_5() + { + chip::app::Clusters::DelayCommands::Commands::WaitForCommissionee::Type value; + value.nodeId = 74565ULL; + return WaitForCommissionee("beta", value); + } + bool testSendClusterTestFabricRemovalWhileSubscribed_6_WaitForReport_Fulfilled = false; + ResponseHandler _Nullable test_TestFabricRemovalWhileSubscribed_Fabrics_Reported = nil; + + CHIP_ERROR TestReportSubscribeFabricsAttributeFromBeta_6() + { + MTRBaseDevice * device = GetDevice("alpha"); + MTRBaseClusterOperationalCredentials * cluster = + [[MTRBaseClusterOperationalCredentials alloc] initWithDevice:device endpoint:0 queue:mCallbackQueue]; + VerifyOrReturnError(cluster != nil, CHIP_ERROR_INCORRECT_STATE); + + test_TestFabricRemovalWhileSubscribed_Fabrics_Reported = ^(NSArray * _Nullable value, NSError * _Nullable err) { + NSLog(@"Report: Subscribe Fabrics Attribute from beta Error: %@", err); + + VerifyOrReturn(CheckValue("status", err ? err.code : 0, 0)); + + VerifyOrReturn(CheckConstraintType("fabrics", "", "list")); + testSendClusterTestFabricRemovalWhileSubscribed_6_WaitForReport_Fulfilled = true; + }; + + NextTest(); + return CHIP_NO_ERROR; + } + + CHIP_ERROR TestSubscribeFabricsAttributeFromBeta_7() + { + MTRBaseDevice * device = GetDevice("beta"); + MTRBaseClusterOperationalCredentials * cluster = + [[MTRBaseClusterOperationalCredentials alloc] initWithDevice:device endpoint:0 queue:mCallbackQueue]; + VerifyOrReturnError(cluster != nil, CHIP_ERROR_INCORRECT_STATE); + + uint16_t minIntervalArgument = 2U; + uint16_t maxIntervalArgument = 5U; + MTRSubscribeParams * params = [[MTRSubscribeParams alloc] init]; + [cluster subscribeAttributeFabricsWithMinInterval:[NSNumber numberWithUnsignedInt:minIntervalArgument] + maxInterval:[NSNumber numberWithUnsignedInt:maxIntervalArgument] + params:params + subscriptionEstablished:^{ + VerifyOrReturn(testSendClusterTestFabricRemovalWhileSubscribed_6_WaitForReport_Fulfilled, + SetCommandExitStatus(CHIP_ERROR_INCORRECT_STATE)); + NextTest(); + } + reportHandler:^(NSArray * _Nullable value, NSError * _Nullable err) { + NSLog(@"Subscribe Fabrics Attribute from beta Error: %@", err); + + VerifyOrReturn(CheckValue("status", err ? err.code : 0, 0)); + if (test_TestFabricRemovalWhileSubscribed_Fabrics_Reported != nil) { + ResponseHandler callback = test_TestFabricRemovalWhileSubscribed_Fabrics_Reported; + test_TestFabricRemovalWhileSubscribed_Fabrics_Reported = nil; + callback(value, err); + } + }]; + + return CHIP_NO_ERROR; + } + + CHIP_ERROR TestRemoveSingleOwnFabric_8() + { + MTRBaseDevice * device = GetDevice("alpha"); + MTRBaseClusterOperationalCredentials * cluster = + [[MTRBaseClusterOperationalCredentials alloc] initWithDevice:device endpoint:0 queue:mCallbackQueue]; + VerifyOrReturnError(cluster != nil, CHIP_ERROR_INCORRECT_STATE); + + __auto_type * params = [[MTROperationalCredentialsClusterRemoveFabricParams alloc] init]; + params.fabricIndex = [ourFabricIndex copy]; + [cluster removeFabricWithParams:params + completionHandler:^( + MTROperationalCredentialsClusterNOCResponseParams * _Nullable values, NSError * _Nullable err) { + NSLog(@"Remove single own fabric Error: %@", err); + + VerifyOrReturn(CheckValue("status", err ? err.code : 0, 0)); + + NextTest(); + }]; + + return CHIP_NO_ERROR; + } +}; + class TestGeneralCommissioning : public TestCommandBridge { public: // NOLINTBEGIN(clang-analyzer-nullability.NullPassedToNonnull): Test constructor nullability not enforced @@ -108922,6 +109228,7 @@ void registerCommandsTests(Commands & commands) make_unique(), make_unique(), make_unique(), + make_unique(), make_unique(), make_unique(), make_unique(),