From 95d337c8f69360b1f20da100bb15bd0ef5195842 Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Fri, 18 Nov 2022 01:30:16 -0500 Subject: [PATCH] Fix reporting for Administrator Commissioning attributes. (#23589) * Fix reporting for Administrator Commissioning attributes. Nothing was marking the attributes dirty when the data backing them changed. * Remove the dependency of af-types.h from reporting.h, so reporting.h can be part of the SDK library, not the app. * Move reporting.h to the same library as the other reporting files. * Fix the one example app that was using the EmberAfAttributeType bits in reporting.h. * Fix color control server depending on reporting.h to get af-types.h. * Add convenience MakeNullable methods, like we have for Optional. * Make sure we call MatterReportingAttributeChangeCallback as needed in CommissioningWindowManager. * Add a unit test that fails without these changes. * Fix the existing TestCommissioningWindow unit test to not hardcode fabric indices, since that's not needed anymore. * Address review comment. --- examples/bridge-app/linux/main.cpp | 4 +- src/app/BUILD.gn | 1 + src/app/chip_data_model.gni | 1 - .../color-control-server.h | 2 +- src/app/data-model/Nullable.h | 12 + src/app/reporting/Engine.cpp | 7 + src/app/reporting/reporting.h | 11 +- src/app/server/CommissioningWindowManager.cpp | 76 +- src/app/server/CommissioningWindowManager.h | 8 + src/app/tests/TestCommissionManager.cpp | 121 ++- .../tests/suites/TestCommissioningWindow.yaml | 16 +- ...tSubscribe_AdministratorCommissioning.yaml | 135 ++++ src/app/tests/suites/ciTests.json | 5 +- src/app/util/attribute-table.cpp | 2 +- .../util/ember-compatibility-functions.cpp | 9 - .../chip-tool/zap-generated/test/Commands.h | 309 +++++++- .../zap-generated/test/Commands.h | 722 +++++++++++++++++- 17 files changed, 1362 insertions(+), 79 deletions(-) create mode 100644 src/app/tests/suites/TestSubscribe_AdministratorCommissioning.yaml diff --git a/examples/bridge-app/linux/main.cpp b/examples/bridge-app/linux/main.cpp index 5007ceed7402cc..a1b54c5101f73f 100644 --- a/examples/bridge-app/linux/main.cpp +++ b/examples/bridge-app/linux/main.cpp @@ -420,9 +420,7 @@ void HandleDevicePowerSourceStatusChanged(DevicePowerSource * dev, DevicePowerSo if (itemChangedMask & DevicePowerSource::kChanged_BatLevel) { - uint8_t batChargeLevel = dev->GetBatChargeLevel(); - MatterReportingAttributeChangeCallback(dev->GetEndpointId(), PowerSource::Id, PowerSource::Attributes::BatChargeLevel::Id, - ZCL_INT8U_ATTRIBUTE_TYPE, &batChargeLevel); + MatterReportingAttributeChangeCallback(dev->GetEndpointId(), PowerSource::Id, PowerSource::Attributes::BatChargeLevel::Id); } if (itemChangedMask & DevicePowerSource::kChanged_Description) diff --git a/src/app/BUILD.gn b/src/app/BUILD.gn index 734baf6aaacbb3..83d6c7d354a713 100644 --- a/src/app/BUILD.gn +++ b/src/app/BUILD.gn @@ -183,6 +183,7 @@ static_library("app") { "WriteHandler.cpp", "reporting/Engine.cpp", "reporting/Engine.h", + "reporting/reporting.h", ] public_deps = [ diff --git a/src/app/chip_data_model.gni b/src/app/chip_data_model.gni index da193e79dbad04..8eaecc3859b7b0 100644 --- a/src/app/chip_data_model.gni +++ b/src/app/chip_data_model.gni @@ -94,7 +94,6 @@ template("chip_data_model") { "${_app_root}/clusters/on-off-server/on-off-server.h", "${_app_root}/clusters/scenes/scenes-tokens.h", "${_app_root}/clusters/scenes/scenes.h", - "${_app_root}/reporting/reporting.h", "${_app_root}/util/DataModelHandler.cpp", "${_app_root}/util/af-event.cpp", "${_app_root}/util/attribute-size-util.cpp", diff --git a/src/app/clusters/color-control-server/color-control-server.h b/src/app/clusters/color-control-server/color-control-server.h index 32ac77715eed1f..22cb14e28f10c0 100644 --- a/src/app/clusters/color-control-server/color-control-server.h +++ b/src/app/clusters/color-control-server/color-control-server.h @@ -19,7 +19,7 @@ #include #include -#include +#include #include /********************************************************** diff --git a/src/app/data-model/Nullable.h b/src/app/data-model/Nullable.h index c0e2a7ea8c9e58..46586e0742f328 100644 --- a/src/app/data-model/Nullable.h +++ b/src/app/data-model/Nullable.h @@ -86,6 +86,18 @@ struct Nullable : protected Optional bool operator!=(const Nullable & other) const { return !(*this == other); } }; +template +constexpr Nullable> MakeNullable(T && value) +{ + return Nullable>(InPlace, std::forward(value)); +} + +template +constexpr Nullable MakeNullable(Args &&... args) +{ + return Nullable(InPlace, std::forward(args)...); +} + } // namespace DataModel } // namespace app } // namespace chip diff --git a/src/app/reporting/Engine.cpp b/src/app/reporting/Engine.cpp index e4dcdfc99b012e..6e25f59a44f307 100644 --- a/src/app/reporting/Engine.cpp +++ b/src/app/reporting/Engine.cpp @@ -964,3 +964,10 @@ void Engine::ScheduleUrgentEventDeliverySync(Optional fabricIndex) void __attribute__((weak)) MatterPreAttributeReadCallback(const chip::app::ConcreteAttributePath & attributePath) {} void __attribute__((weak)) MatterPostAttributeReadCallback(const chip::app::ConcreteAttributePath & attributePath) {} + +// TODO: MatterReportingAttributeChangeCallback should just live in libCHIP, +// instead of being in ember-compatibility-functions. It does not depend on any +// app-specific generated bits. +void __attribute__((weak)) +MatterReportingAttributeChangeCallback(chip::EndpointId endpoint, chip::ClusterId clusterId, chip::AttributeId attributeId) +{} diff --git a/src/app/reporting/reporting.h b/src/app/reporting/reporting.h index eaed8e86644ece..02a8aeca02e059 100644 --- a/src/app/reporting/reporting.h +++ b/src/app/reporting/reporting.h @@ -18,20 +18,13 @@ #pragma once #include -#include /** @brief Reporting Attribute Change * * This function is called by the framework when an attribute managed by the * framework changes. The application should call this function when an - * externally-managed attribute changes. The application should use the change - * notification to inform its reporting decisions. - */ -void MatterReportingAttributeChangeCallback(chip::EndpointId endpoint, chip::ClusterId clusterId, chip::AttributeId attributeId, - EmberAfAttributeType type, uint8_t * data); - -/* - * Same but with just an attribute path and no data available. + * externally-managed attribute changes. This function triggers attribute + * reports for subscriptions as needed. */ void MatterReportingAttributeChangeCallback(chip::EndpointId endpoint, chip::ClusterId clusterId, chip::AttributeId attributeId); diff --git a/src/app/server/CommissioningWindowManager.cpp b/src/app/server/CommissioningWindowManager.cpp index 4256f9b6c82580..949b46020373b2 100644 --- a/src/app/server/CommissioningWindowManager.cpp +++ b/src/app/server/CommissioningWindowManager.cpp @@ -15,6 +15,7 @@ * limitations under the License. */ +#include #include #include #include @@ -28,6 +29,9 @@ using namespace chip::app::Clusters; using namespace chip::System::Clock; using AdministratorCommissioning::CommissioningWindowStatus; +using chip::app::DataModel::MakeNullable; +using chip::app::DataModel::Nullable; +using chip::app::DataModel::NullNullable; namespace { @@ -93,10 +97,11 @@ void CommissioningWindowManager::ResetState() mECMDiscriminator = 0; mECMIterations = 0; mECMSaltLength = 0; - mWindowStatus = CommissioningWindowStatus::kWindowNotOpen; - mOpenerFabricIndex.SetNull(); - mOpenerVendorId.SetNull(); + UpdateWindowStatus(CommissioningWindowStatus::kWindowNotOpen); + + UpdateOpenerFabricIndex(NullNullable); + UpdateOpenerVendorId(NullNullable); memset(&mECMPASEVerifier, 0, sizeof(mECMPASEVerifier)); memset(mECMSalt, 0, sizeof(mECMSalt)); @@ -294,8 +299,8 @@ CommissioningWindowManager::OpenBasicCommissioningWindowForAdministratorCommissi { ReturnErrorOnFailure(OpenBasicCommissioningWindow(commissioningTimeout, CommissioningWindowAdvertisement::kDnssdOnly)); - mOpenerFabricIndex.SetNonNull(fabricIndex); - mOpenerVendorId.SetNonNull(vendorId); + UpdateOpenerFabricIndex(MakeNullable(fabricIndex)); + UpdateOpenerVendorId(MakeNullable(vendorId)); return CHIP_NO_ERROR; } @@ -329,8 +334,8 @@ CHIP_ERROR CommissioningWindowManager::OpenEnhancedCommissioningWindow(Seconds16 } else { - mOpenerFabricIndex.SetNonNull(fabricIndex); - mOpenerVendorId.SetNonNull(vendorId); + UpdateOpenerFabricIndex(MakeNullable(fabricIndex)); + UpdateOpenerVendorId(MakeNullable(vendorId)); } return err; @@ -356,6 +361,10 @@ void CommissioningWindowManager::CloseCommissioningWindow() CommissioningWindowStatus CommissioningWindowManager::CommissioningWindowStatusForCluster() const { + // If the condition we use to determine whether we were opened via the + // cluster ever changes, make sure whatever code affects that condition + // marks calls MatterReportingAttributeChangeCallback for WindowStatus as + // needed. if (mOpenerVendorId.IsNull()) { // Not opened via the cluster. @@ -375,7 +384,7 @@ void CommissioningWindowManager::OnFabricRemoved(FabricIndex removedIndex) if (!mOpenerFabricIndex.IsNull() && mOpenerFabricIndex.Value() == removedIndex) { // Per spec, we should clear out the stale fabric index. - mOpenerFabricIndex.SetNull(); + UpdateOpenerFabricIndex(NullNullable); } } @@ -424,11 +433,11 @@ CHIP_ERROR CommissioningWindowManager::StartAdvertisement() if (mUseECM) { - mWindowStatus = CommissioningWindowStatus::kEnhancedWindowOpen; + UpdateWindowStatus(CommissioningWindowStatus::kEnhancedWindowOpen); } else { - mWindowStatus = CommissioningWindowStatus::kBasicWindowOpen; + UpdateWindowStatus(CommissioningWindowStatus::kBasicWindowOpen); } if (mAppDelegate != nullptr) @@ -526,4 +535,51 @@ void CommissioningWindowManager::ExpireFailSafeIfArmed() } } +void CommissioningWindowManager::UpdateWindowStatus(CommissioningWindowStatus aNewStatus) +{ + CommissioningWindowStatus oldClusterStatus = CommissioningWindowStatusForCluster(); + mWindowStatus = aNewStatus; + if (CommissioningWindowStatusForCluster() != oldClusterStatus) + { + // The Administrator Commissioning cluster is always on the root endpoint. + MatterReportingAttributeChangeCallback(kRootEndpointId, AdministratorCommissioning::Id, + AdministratorCommissioning::Attributes::WindowStatus::Id); + } +} + +void CommissioningWindowManager::UpdateOpenerVendorId(Nullable aNewOpenerVendorId) +{ + // Changing the opener vendor id affects what + // CommissioningWindowStatusForCluster() returns. + CommissioningWindowStatus oldClusterStatus = CommissioningWindowStatusForCluster(); + + if (mOpenerVendorId != aNewOpenerVendorId) + { + // The Administrator Commissioning cluster is always on the root endpoint. + MatterReportingAttributeChangeCallback(kRootEndpointId, AdministratorCommissioning::Id, + AdministratorCommissioning::Attributes::AdminVendorId::Id); + } + + mOpenerVendorId = aNewOpenerVendorId; + + if (CommissioningWindowStatusForCluster() != oldClusterStatus) + { + // The Administrator Commissioning cluster is always on the root endpoint. + MatterReportingAttributeChangeCallback(kRootEndpointId, AdministratorCommissioning::Id, + AdministratorCommissioning::Attributes::WindowStatus::Id); + } +} + +void CommissioningWindowManager::UpdateOpenerFabricIndex(Nullable aNewOpenerFabricIndex) +{ + if (mOpenerFabricIndex != aNewOpenerFabricIndex) + { + // The Administrator Commissioning cluster is always on the root endpoint. + MatterReportingAttributeChangeCallback(kRootEndpointId, AdministratorCommissioning::Id, + AdministratorCommissioning::Attributes::AdminFabricIndex::Id); + } + + mOpenerFabricIndex = aNewOpenerFabricIndex; +} + } // namespace chip diff --git a/src/app/server/CommissioningWindowManager.h b/src/app/server/CommissioningWindowManager.h index 9381a2c3c653c8..bb2cf00c8d8c3c 100644 --- a/src/app/server/CommissioningWindowManager.h +++ b/src/app/server/CommissioningWindowManager.h @@ -171,6 +171,14 @@ class CommissioningWindowManager : public SessionEstablishmentDelegate, */ void ExpireFailSafeIfArmed(); + /** + * Helpers to ensure the right attribute reporting happens when our state is + * updated. + */ + void UpdateWindowStatus(app::Clusters::AdministratorCommissioning::CommissioningWindowStatus aNewStatus); + void UpdateOpenerVendorId(app::DataModel::Nullable aNewOpenerVendorId); + void UpdateOpenerFabricIndex(app::DataModel::Nullable aNewOpenerFabricIndex); + AppDelegate * mAppDelegate = nullptr; Server * mServer = nullptr; diff --git a/src/app/tests/TestCommissionManager.cpp b/src/app/tests/TestCommissionManager.cpp index 580b62ef099c35..7a05cbdeea7d4b 100644 --- a/src/app/tests/TestCommissionManager.cpp +++ b/src/app/tests/TestCommissionManager.cpp @@ -37,6 +37,45 @@ using chip::Server; // Mock function for linking void InitDataModelHandler(chip::Messaging::ExchangeManager * exchangeMgr) {} +namespace { +bool sAdminFabricIndexDirty = false; +bool sAdminVendorIdDirty = false; +bool sWindowStatusDirty = false; + +void ResetDirtyFlags() +{ + sAdminFabricIndexDirty = false; + sAdminVendorIdDirty = false; + sWindowStatusDirty = false; +} + +} // namespace + +void MatterReportingAttributeChangeCallback(chip::EndpointId endpoint, chip::ClusterId clusterId, chip::AttributeId attributeId) +{ + using namespace chip::app::Clusters; + using namespace chip::app::Clusters::AdministratorCommissioning::Attributes; + if (endpoint != chip::kRootEndpointId || clusterId != AdministratorCommissioning::Id) + { + return; + } + + switch (attributeId) + { + case WindowStatus::Id: + sWindowStatusDirty = true; + break; + case AdminVendorId::Id: + sAdminVendorIdDirty = true; + break; + case AdminFabricIndex::Id: + sAdminFabricIndexDirty = true; + break; + default: + break; + } +} + namespace { static constexpr int kTestTaskWaitSeconds = 2; @@ -85,7 +124,11 @@ void ShutdownChipTest() void CheckCommissioningWindowManagerBasicWindowOpenCloseTask(intptr_t context) { - nlTestSuite * suite = reinterpret_cast(context); + nlTestSuite * suite = reinterpret_cast(context); + NL_TEST_ASSERT(suite, !sWindowStatusDirty); + NL_TEST_ASSERT(suite, !sAdminFabricIndexDirty); + NL_TEST_ASSERT(suite, !sAdminVendorIdDirty); + CommissioningWindowManager & commissionMgr = Server::GetInstance().GetCommissioningWindowManager(); CHIP_ERROR err = commissionMgr.OpenBasicCommissioningWindow(commissionMgr.MaxCommissioningTimeout(), CommissioningWindowAdvertisement::kDnssdOnly); @@ -97,8 +140,15 @@ void CheckCommissioningWindowManagerBasicWindowOpenCloseTask(intptr_t context) NL_TEST_ASSERT(suite, commissionMgr.GetOpenerFabricIndex().IsNull()); NL_TEST_ASSERT(suite, commissionMgr.GetOpenerVendorId().IsNull()); NL_TEST_ASSERT(suite, !chip::DeviceLayer::ConnectivityMgr().IsBLEAdvertisingEnabled()); + NL_TEST_ASSERT(suite, !sWindowStatusDirty); + NL_TEST_ASSERT(suite, !sAdminFabricIndexDirty); + NL_TEST_ASSERT(suite, !sAdminVendorIdDirty); + commissionMgr.CloseCommissioningWindow(); NL_TEST_ASSERT(suite, !commissionMgr.IsCommissioningWindowOpen()); + NL_TEST_ASSERT(suite, !sWindowStatusDirty); + NL_TEST_ASSERT(suite, !sAdminFabricIndexDirty); + NL_TEST_ASSERT(suite, !sAdminVendorIdDirty); } void CheckCommissioningWindowManagerBasicWindowOpenClose(nlTestSuite * suite, void *) @@ -110,7 +160,11 @@ void CheckCommissioningWindowManagerBasicWindowOpenClose(nlTestSuite * suite, vo void CheckCommissioningWindowManagerBasicWindowOpenCloseFromClusterTask(intptr_t context) { - nlTestSuite * suite = reinterpret_cast(context); + nlTestSuite * suite = reinterpret_cast(context); + NL_TEST_ASSERT(suite, !sWindowStatusDirty); + NL_TEST_ASSERT(suite, !sAdminFabricIndexDirty); + NL_TEST_ASSERT(suite, !sAdminVendorIdDirty); + CommissioningWindowManager & commissionMgr = Server::GetInstance().GetCommissioningWindowManager(); constexpr auto fabricIndex = static_cast(1); constexpr auto vendorId = static_cast(0xFFF3); @@ -126,10 +180,24 @@ void CheckCommissioningWindowManagerBasicWindowOpenCloseFromClusterTask(intptr_t NL_TEST_ASSERT(suite, !commissionMgr.GetOpenerVendorId().IsNull()); NL_TEST_ASSERT(suite, commissionMgr.GetOpenerVendorId().Value() == vendorId); NL_TEST_ASSERT(suite, !chip::DeviceLayer::ConnectivityMgr().IsBLEAdvertisingEnabled()); + NL_TEST_ASSERT(suite, sWindowStatusDirty); + NL_TEST_ASSERT(suite, sAdminFabricIndexDirty); + NL_TEST_ASSERT(suite, sAdminVendorIdDirty); + + ResetDirtyFlags(); + NL_TEST_ASSERT(suite, !sWindowStatusDirty); + NL_TEST_ASSERT(suite, !sAdminFabricIndexDirty); + NL_TEST_ASSERT(suite, !sAdminVendorIdDirty); + commissionMgr.CloseCommissioningWindow(); NL_TEST_ASSERT(suite, !commissionMgr.IsCommissioningWindowOpen()); NL_TEST_ASSERT(suite, commissionMgr.GetOpenerFabricIndex().IsNull()); NL_TEST_ASSERT(suite, commissionMgr.GetOpenerVendorId().IsNull()); + NL_TEST_ASSERT(suite, sWindowStatusDirty); + NL_TEST_ASSERT(suite, sAdminFabricIndexDirty); + NL_TEST_ASSERT(suite, sAdminVendorIdDirty); + + ResetDirtyFlags(); } void CheckCommissioningWindowManagerBasicWindowOpenCloseFromCluster(nlTestSuite * suite, void *) @@ -147,11 +215,18 @@ void CheckCommissioningWindowManagerWindowClosedTask(chip::System::Layer *, void NL_TEST_ASSERT(suite, commissionMgr.CommissioningWindowStatusForCluster() == chip::app::Clusters::AdministratorCommissioning::CommissioningWindowStatus::kWindowNotOpen); + NL_TEST_ASSERT(suite, !sWindowStatusDirty); + NL_TEST_ASSERT(suite, !sAdminFabricIndexDirty); + NL_TEST_ASSERT(suite, !sAdminVendorIdDirty); } void CheckCommissioningWindowManagerWindowTimeoutTask(intptr_t context) { - nlTestSuite * suite = reinterpret_cast(context); + nlTestSuite * suite = reinterpret_cast(context); + NL_TEST_ASSERT(suite, !sWindowStatusDirty); + NL_TEST_ASSERT(suite, !sAdminFabricIndexDirty); + NL_TEST_ASSERT(suite, !sAdminVendorIdDirty); + CommissioningWindowManager & commissionMgr = Server::GetInstance().GetCommissioningWindowManager(); constexpr auto kTimeoutSeconds = chip::System::Clock::Seconds16(1); constexpr uint16_t kTimeoutMs = 1000; @@ -164,6 +239,10 @@ void CheckCommissioningWindowManagerWindowTimeoutTask(intptr_t context) commissionMgr.CommissioningWindowStatusForCluster() == chip::app::Clusters::AdministratorCommissioning::CommissioningWindowStatus::kWindowNotOpen); NL_TEST_ASSERT(suite, !chip::DeviceLayer::ConnectivityMgr().IsBLEAdvertisingEnabled()); + NL_TEST_ASSERT(suite, !sWindowStatusDirty); + NL_TEST_ASSERT(suite, !sAdminFabricIndexDirty); + NL_TEST_ASSERT(suite, !sAdminVendorIdDirty); + chip::DeviceLayer::SystemLayer().StartTimer(chip::System::Clock::Milliseconds32(kTimeoutMs + kSleepPadding), CheckCommissioningWindowManagerWindowClosedTask, suite); } @@ -183,17 +262,28 @@ void SimulateFailedSessionEstablishmentTask(chip::System::Layer *, void * contex NL_TEST_ASSERT(suite, commissionMgr.CommissioningWindowStatusForCluster() == chip::app::Clusters::AdministratorCommissioning::CommissioningWindowStatus::kWindowNotOpen); + NL_TEST_ASSERT(suite, !sWindowStatusDirty); + NL_TEST_ASSERT(suite, !sAdminFabricIndexDirty); + NL_TEST_ASSERT(suite, !sAdminVendorIdDirty); + commissionMgr.OnSessionEstablishmentStarted(); commissionMgr.OnSessionEstablishmentError(CHIP_ERROR_INTERNAL); NL_TEST_ASSERT(suite, commissionMgr.IsCommissioningWindowOpen()); NL_TEST_ASSERT(suite, commissionMgr.CommissioningWindowStatusForCluster() == chip::app::Clusters::AdministratorCommissioning::CommissioningWindowStatus::kWindowNotOpen); + NL_TEST_ASSERT(suite, !sWindowStatusDirty); + NL_TEST_ASSERT(suite, !sAdminFabricIndexDirty); + NL_TEST_ASSERT(suite, !sAdminVendorIdDirty); } void CheckCommissioningWindowManagerWindowTimeoutWithSessionEstablishmentErrorsTask(intptr_t context) { - nlTestSuite * suite = reinterpret_cast(context); + nlTestSuite * suite = reinterpret_cast(context); + NL_TEST_ASSERT(suite, !sWindowStatusDirty); + NL_TEST_ASSERT(suite, !sAdminFabricIndexDirty); + NL_TEST_ASSERT(suite, !sAdminVendorIdDirty); + CommissioningWindowManager & commissionMgr = Server::GetInstance().GetCommissioningWindowManager(); constexpr auto kTimeoutSeconds = chip::System::Clock::Seconds16(1); constexpr uint16_t kTimeoutMs = 1000; @@ -205,10 +295,14 @@ void CheckCommissioningWindowManagerWindowTimeoutWithSessionEstablishmentErrorsT commissionMgr.CommissioningWindowStatusForCluster() == chip::app::Clusters::AdministratorCommissioning::CommissioningWindowStatus::kWindowNotOpen); NL_TEST_ASSERT(suite, !chip::DeviceLayer::ConnectivityMgr().IsBLEAdvertisingEnabled()); + NL_TEST_ASSERT(suite, !sWindowStatusDirty); + NL_TEST_ASSERT(suite, !sAdminFabricIndexDirty); + NL_TEST_ASSERT(suite, !sAdminVendorIdDirty); + chip::DeviceLayer::SystemLayer().StartTimer(chip::System::Clock::Milliseconds32(kTimeoutMs + kSleepPadding), CheckCommissioningWindowManagerWindowClosedTask, suite); // Simulate a session establishment error during that window, such that the - // delay for the error plust hte window size exceeds our "timeout + padding" above. + // delay for the error plus the window size exceeds our "timeout + padding" above. chip::DeviceLayer::SystemLayer().StartTimer(chip::System::Clock::Milliseconds32(kTimeoutMs / 4 * 3), SimulateFailedSessionEstablishmentTask, suite); } @@ -233,6 +327,10 @@ void CheckCommissioningWindowManagerEnhancedWindowTask(intptr_t context) uint8_t salt[chip::kSpake2p_Min_PBKDF_Salt_Length]; chip::ByteSpan saltData(salt); + NL_TEST_ASSERT(suite, !sWindowStatusDirty); + NL_TEST_ASSERT(suite, !sAdminFabricIndexDirty); + NL_TEST_ASSERT(suite, !sAdminVendorIdDirty); + constexpr auto fabricIndex = static_cast(1); constexpr auto vendorId = static_cast(0xFFF3); err = commissionMgr.OpenEnhancedCommissioningWindow(commissionMgr.MaxCommissioningTimeout(), newDiscriminator, verifier, @@ -247,6 +345,14 @@ void CheckCommissioningWindowManagerEnhancedWindowTask(intptr_t context) NL_TEST_ASSERT(suite, commissionMgr.GetOpenerFabricIndex().Value() == fabricIndex); NL_TEST_ASSERT(suite, !commissionMgr.GetOpenerVendorId().IsNull()); NL_TEST_ASSERT(suite, commissionMgr.GetOpenerVendorId().Value() == vendorId); + NL_TEST_ASSERT(suite, sWindowStatusDirty); + NL_TEST_ASSERT(suite, sAdminFabricIndexDirty); + NL_TEST_ASSERT(suite, sAdminVendorIdDirty); + + ResetDirtyFlags(); + NL_TEST_ASSERT(suite, !sWindowStatusDirty); + NL_TEST_ASSERT(suite, !sAdminFabricIndexDirty); + NL_TEST_ASSERT(suite, !sAdminVendorIdDirty); commissionMgr.CloseCommissioningWindow(); NL_TEST_ASSERT(suite, !commissionMgr.IsCommissioningWindowOpen()); @@ -255,6 +361,11 @@ void CheckCommissioningWindowManagerEnhancedWindowTask(intptr_t context) chip::app::Clusters::AdministratorCommissioning::CommissioningWindowStatus::kWindowNotOpen); NL_TEST_ASSERT(suite, commissionMgr.GetOpenerFabricIndex().IsNull()); NL_TEST_ASSERT(suite, commissionMgr.GetOpenerVendorId().IsNull()); + NL_TEST_ASSERT(suite, sWindowStatusDirty); + NL_TEST_ASSERT(suite, sAdminFabricIndexDirty); + NL_TEST_ASSERT(suite, sAdminVendorIdDirty); + + ResetDirtyFlags(); } void CheckCommissioningWindowManagerEnhancedWindow(nlTestSuite * suite, void *) diff --git a/src/app/tests/suites/TestCommissioningWindow.yaml b/src/app/tests/suites/TestCommissioningWindow.yaml index bade4a257f8dfb..5ec5bc46f422e5 100644 --- a/src/app/tests/suites/TestCommissioningWindow.yaml +++ b/src/app/tests/suites/TestCommissioningWindow.yaml @@ -27,12 +27,6 @@ config: payload: type: char_string defaultValue: "MT:-24J0AFN00KA0648G00" # This value needs to be generated automatically - alphaIndex: - type: int8u - defaultValue: 1 - betaIndex: - type: int8u - defaultValue: 2 tests: - label: "Wait for the commissioned device to be retrieved for alpha" @@ -48,10 +42,7 @@ tests: command: "readAttribute" attribute: "CurrentFabricIndex" response: - # We could saveAs here, but then when we try to compare to it later - # the nullable-vs-non-nullable compare fails to work right. For now - # just use a config variable. - value: alphaIndex + saveAs: alphaIndex - label: "Check that commissioning window is not open" command: "readAttribute" @@ -172,10 +163,7 @@ tests: command: "readAttribute" attribute: "CurrentFabricIndex" response: - # We could saveAs here, but then when we try to compare to it later - # the nullable-vs-non-nullable compare fails to work right. For now - # just use a config variable. - value: betaIndex + saveAs: betaIndex - label: "Open Commissioning Window from beta" identity: "beta" diff --git a/src/app/tests/suites/TestSubscribe_AdministratorCommissioning.yaml b/src/app/tests/suites/TestSubscribe_AdministratorCommissioning.yaml new file mode 100644 index 00000000000000..ecda538f57fd55 --- /dev/null +++ b/src/app/tests/suites/TestSubscribe_AdministratorCommissioning.yaml @@ -0,0 +1,135 @@ +# Copyright (c) 2021 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: Subscribe Tests - Administrator Commissioning Cluster + +config: + nodeId: 0x12344321 + cluster: "AdministratorCommissioning" + endpoint: 0 + ourVendorId: + type: int16u + defaultValue: 0xFFF1 + +tests: + - label: "Wait for the commissioned device to be retrieved" + cluster: "DelayCommands" + command: "WaitForCommissionee" + arguments: + values: + - name: "nodeId" + value: nodeId + + - label: "Get ourfabric index" + cluster: "Operational Credentials" + command: "readAttribute" + attribute: "CurrentFabricIndex" + response: + saveAs: ourFabricIndex + + - label: "Subscribe WindowStatus Attribute" + command: "subscribeAttribute" + attribute: "WindowStatus" + minInterval: 2 + maxInterval: 50 + response: + value: 0 + + - label: "Open the commissioning window 1" + command: "OpenBasicCommissioningWindow" + timedInteractionTimeoutMs: 10000 + arguments: + values: + - name: "CommissioningTimeout" + value: 180 + + - label: "Check for first attribute report for WindowStatus" + command: "waitForReport" + attribute: "WindowStatus" + response: + value: 2 + + - label: "Close the commissioning window 1" + command: "RevokeCommissioning" + timedInteractionTimeoutMs: 10000 + + - label: "Check for second attribute report for WindowStatus" + command: "waitForReport" + attribute: "WindowStatus" + response: + value: 0 + + - label: "Subscribe AdminVendorId Attribute" + command: "subscribeAttribute" + attribute: "AdminVendorId" + minInterval: 2 + maxInterval: 50 + response: + value: null + + - label: "Open the commissioning window 2" + command: "OpenBasicCommissioningWindow" + timedInteractionTimeoutMs: 10000 + arguments: + values: + - name: "CommissioningTimeout" + value: 180 + + - label: "Check for first attribute report for AdminVendorId" + command: "waitForReport" + attribute: "AdminVendorId" + response: + value: ourVendorId + + - label: "Close the commissioning window 2" + command: "RevokeCommissioning" + timedInteractionTimeoutMs: 10000 + + - label: "Check for second attribute report for AdminVendorId" + command: "waitForReport" + attribute: "AdminVendorId" + response: + value: null + + - label: "Subscribe AdminFabricIndex Attribute" + command: "subscribeAttribute" + attribute: "AdminFabricIndex" + minInterval: 2 + maxInterval: 50 + response: + value: null + + - label: "Open the commissioning window 3" + command: "OpenBasicCommissioningWindow" + timedInteractionTimeoutMs: 10000 + arguments: + values: + - name: "CommissioningTimeout" + value: 180 + + - label: "Check for first attribute report for AdminFabricIndex" + command: "waitForReport" + attribute: "AdminFabricIndex" + response: + value: ourFabricIndex + + - label: "Close the commissioning window 2" + command: "RevokeCommissioning" + timedInteractionTimeoutMs: 10000 + + - label: "Check for second attribute report for AdminFabricIndex" + command: "waitForReport" + attribute: "AdminFabricIndex" + response: + value: null diff --git a/src/app/tests/suites/ciTests.json b/src/app/tests/suites/ciTests.json index 17bfa98ec4d45d..58a3bd5145cb3c 100644 --- a/src/app/tests/suites/ciTests.json +++ b/src/app/tests/suites/ciTests.json @@ -227,7 +227,10 @@ ], "MultiAdmin": ["TestMultiAdmin"], "SoftwareDiagnostics": ["Test_TC_DGSW_1_1"], - "Subscriptions": ["TestSubscribe_OnOff"], + "Subscriptions": [ + "TestSubscribe_OnOff", + "TestSubscribe_AdministratorCommissioning" + ], "DoorLock": [ "DL_UsersAndCredentials", "DL_LockUnlock", diff --git a/src/app/util/attribute-table.cpp b/src/app/util/attribute-table.cpp index 2a86c16fec77fe..3c05b688aad6cf 100644 --- a/src/app/util/attribute-table.cpp +++ b/src/app/util/attribute-table.cpp @@ -359,7 +359,7 @@ EmberAfStatus emAfWriteAttribute(EndpointId endpoint, ClusterId cluster, Attribu // The callee will weed out attributes that do not need to be stored. emAfSaveAttributeToStorageIfNeeded(data, endpoint, cluster, metadata); - MatterReportingAttributeChangeCallback(endpoint, cluster, attributeID, dataType, data); + MatterReportingAttributeChangeCallback(endpoint, cluster, attributeID); // Post write attribute callback for all attributes changes, regardless // of cluster. diff --git a/src/app/util/ember-compatibility-functions.cpp b/src/app/util/ember-compatibility-functions.cpp index 648e296048dafd..683da9cd45e455 100644 --- a/src/app/util/ember-compatibility-functions.cpp +++ b/src/app/util/ember-compatibility-functions.cpp @@ -1107,15 +1107,6 @@ bool IsDeviceTypeOnEndpoint(DeviceTypeId deviceType, EndpointId endpoint) } // namespace app } // namespace chip -void MatterReportingAttributeChangeCallback(EndpointId endpoint, ClusterId clusterId, AttributeId attributeId, - EmberAfAttributeType type, uint8_t * data) -{ - IgnoreUnusedVariable(type); - IgnoreUnusedVariable(data); - - MatterReportingAttributeChangeCallback(endpoint, clusterId, attributeId); -} - void MatterReportingAttributeChangeCallback(EndpointId endpoint, ClusterId clusterId, AttributeId attributeId) { // Attribute writes have asserted this already, but this assert should catch diff --git a/zzz_generated/chip-tool/zap-generated/test/Commands.h b/zzz_generated/chip-tool/zap-generated/test/Commands.h index 1c8402f90d6507..d387909abeb645 100644 --- a/zzz_generated/chip-tool/zap-generated/test/Commands.h +++ b/zzz_generated/chip-tool/zap-generated/test/Commands.h @@ -235,6 +235,7 @@ class TestList : public Command printf("TestMultiAdmin\n"); printf("Test_TC_DGSW_1_1\n"); printf("TestSubscribe_OnOff\n"); + printf("TestSubscribe_AdministratorCommissioning\n"); printf("DL_UsersAndCredentials\n"); printf("DL_LockUnlock\n"); printf("DL_Schedules\n"); @@ -63169,8 +63170,6 @@ class TestCommissioningWindowSuite : public TestCommand AddArgument("cluster", &mCluster); AddArgument("discriminator", 0, UINT16_MAX, &mDiscriminator); AddArgument("payload", &mPayload); - AddArgument("alphaIndex", 0, UINT8_MAX, &mAlphaIndex); - AddArgument("betaIndex", 0, UINT8_MAX, &mBetaIndex); AddArgument("timeout", 0, UINT16_MAX, &mTimeout); } @@ -63188,10 +63187,10 @@ class TestCommissioningWindowSuite : public TestCommand chip::Optional mCluster; chip::Optional mDiscriminator; chip::Optional mPayload; - chip::Optional mAlphaIndex; - chip::Optional mBetaIndex; chip::Optional mTimeout; + uint8_t alphaIndex; + uint8_t betaIndex; chip::app::DataModel::Nullable adminVendorId; chip::EndpointId GetEndpoint(chip::EndpointId endpoint) { return mEndpoint.HasValue() ? mEndpoint.Value() : endpoint; } @@ -63215,7 +63214,7 @@ class TestCommissioningWindowSuite : public TestCommand { uint8_t value; VerifyOrReturn(CheckDecodeValue(chip::app::DataModel::Decode(*data, value))); - VerifyOrReturn(CheckValue("currentFabricIndex", value, mAlphaIndex.HasValue() ? mAlphaIndex.Value() : 1U)); + alphaIndex = value; } break; case 2: @@ -63259,8 +63258,7 @@ class TestCommissioningWindowSuite : public TestCommand chip::app::DataModel::Nullable value; VerifyOrReturn(CheckDecodeValue(chip::app::DataModel::Decode(*data, value))); VerifyOrReturn(CheckValueNonNull("adminFabricIndex", value)); - VerifyOrReturn( - CheckValue("adminFabricIndex.Value()", value.Value(), mAlphaIndex.HasValue() ? mAlphaIndex.Value() : 1U)); + VerifyOrReturn(CheckValue("adminFabricIndex.Value()", value.Value(), alphaIndex)); } break; case 8: @@ -63338,7 +63336,7 @@ class TestCommissioningWindowSuite : public TestCommand { uint8_t value; VerifyOrReturn(CheckDecodeValue(chip::app::DataModel::Decode(*data, value))); - VerifyOrReturn(CheckValue("currentFabricIndex", value, mBetaIndex.HasValue() ? mBetaIndex.Value() : 2U)); + betaIndex = value; } break; case 20: @@ -63358,8 +63356,7 @@ class TestCommissioningWindowSuite : public TestCommand chip::app::DataModel::Nullable value; VerifyOrReturn(CheckDecodeValue(chip::app::DataModel::Decode(*data, value))); VerifyOrReturn(CheckValueNonNull("adminFabricIndex", value)); - VerifyOrReturn( - CheckValue("adminFabricIndex.Value()", value.Value(), mBetaIndex.HasValue() ? mBetaIndex.Value() : 2U)); + VerifyOrReturn(CheckValue("adminFabricIndex.Value()", value.Value(), betaIndex)); } break; case 23: @@ -63579,7 +63576,7 @@ class TestCommissioningWindowSuite : public TestCommand LogStep(24, "Remove beta fabric"); ListFreer listFreer; chip::app::Clusters::OperationalCredentials::Commands::RemoveFabric::Type value; - value.fabricIndex = mBetaIndex.HasValue() ? mBetaIndex.Value() : 2U; + value.fabricIndex = betaIndex; return SendCommand(kIdentityAlpha, GetEndpoint(0), OperationalCredentials::Id, OperationalCredentials::Commands::RemoveFabric::Id, value, chip::NullOptional @@ -64290,6 +64287,295 @@ class TestSubscribe_OnOffSuite : public TestCommand } }; +class TestSubscribe_AdministratorCommissioningSuite : public TestCommand +{ +public: + TestSubscribe_AdministratorCommissioningSuite(CredentialIssuerCommands * credsIssuerConfig) : + TestCommand("TestSubscribe_AdministratorCommissioning", 17, credsIssuerConfig) + { + AddArgument("nodeId", 0, UINT64_MAX, &mNodeId); + AddArgument("cluster", &mCluster); + AddArgument("endpoint", 0, UINT16_MAX, &mEndpoint); + AddArgument("ourVendorId", 0, UINT16_MAX, &mOurVendorId); + AddArgument("timeout", 0, UINT16_MAX, &mTimeout); + } + + ~TestSubscribe_AdministratorCommissioningSuite() {} + + 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 mOurVendorId; + chip::Optional mTimeout; + + uint8_t 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))); + ourFabricIndex = value; + } + break; + case 2: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + { + chip::app::Clusters::AdministratorCommissioning::CommissioningWindowStatus value; + VerifyOrReturn(CheckDecodeValue(chip::app::DataModel::Decode(*data, value))); + VerifyOrReturn(CheckValue("windowStatus", value, 0U)); + } + break; + case 3: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + break; + case 4: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + { + chip::app::Clusters::AdministratorCommissioning::CommissioningWindowStatus value; + VerifyOrReturn(CheckDecodeValue(chip::app::DataModel::Decode(*data, value))); + VerifyOrReturn(CheckValue("windowStatus", value, 2U)); + } + shouldContinue = true; + break; + case 5: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + break; + case 6: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + { + chip::app::Clusters::AdministratorCommissioning::CommissioningWindowStatus value; + VerifyOrReturn(CheckDecodeValue(chip::app::DataModel::Decode(*data, value))); + VerifyOrReturn(CheckValue("windowStatus", value, 0U)); + } + shouldContinue = true; + break; + case 7: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + { + chip::app::DataModel::Nullable value; + VerifyOrReturn(CheckDecodeValue(chip::app::DataModel::Decode(*data, value))); + VerifyOrReturn(CheckValueNull("adminVendorId", value)); + } + break; + case 8: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + break; + case 9: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + { + chip::app::DataModel::Nullable value; + VerifyOrReturn(CheckDecodeValue(chip::app::DataModel::Decode(*data, value))); + VerifyOrReturn(CheckValueNonNull("adminVendorId", value)); + VerifyOrReturn( + CheckValue("adminVendorId.Value()", value.Value(), mOurVendorId.HasValue() ? mOurVendorId.Value() : 65521U)); + } + shouldContinue = true; + break; + case 10: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + break; + case 11: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + { + chip::app::DataModel::Nullable value; + VerifyOrReturn(CheckDecodeValue(chip::app::DataModel::Decode(*data, value))); + VerifyOrReturn(CheckValueNull("adminVendorId", value)); + } + shouldContinue = true; + break; + case 12: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + { + chip::app::DataModel::Nullable value; + VerifyOrReturn(CheckDecodeValue(chip::app::DataModel::Decode(*data, value))); + VerifyOrReturn(CheckValueNull("adminFabricIndex", value)); + } + break; + case 13: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + break; + case 14: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + { + chip::app::DataModel::Nullable value; + VerifyOrReturn(CheckDecodeValue(chip::app::DataModel::Decode(*data, value))); + VerifyOrReturn(CheckValueNonNull("adminFabricIndex", value)); + VerifyOrReturn(CheckValue("adminFabricIndex.Value()", value.Value(), ourFabricIndex)); + } + shouldContinue = true; + break; + case 15: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + break; + case 16: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + { + chip::app::DataModel::Nullable value; + VerifyOrReturn(CheckDecodeValue(chip::app::DataModel::Decode(*data, value))); + VerifyOrReturn(CheckValueNull("adminFabricIndex", value)); + } + shouldContinue = true; + 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, "Get ourfabric index"); + return ReadAttribute(kIdentityAlpha, GetEndpoint(0), OperationalCredentials::Id, + OperationalCredentials::Attributes::CurrentFabricIndex::Id, true, chip::NullOptional); + } + case 2: { + LogStep(2, "Subscribe WindowStatus Attribute"); + return SubscribeAttribute(kIdentityAlpha, GetEndpoint(0), AdministratorCommissioning::Id, + AdministratorCommissioning::Attributes::WindowStatus::Id, 2, 50, true, chip::NullOptional, + chip::NullOptional, /* autoResubscribe = */ chip::NullOptional); + } + case 3: { + LogStep(3, "Open the commissioning window 1"); + 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, "Check for first attribute report for WindowStatus"); + return WaitForReport(); + } + case 5: { + LogStep(5, "Close the commissioning window 1"); + ListFreer listFreer; + chip::app::Clusters::AdministratorCommissioning::Commands::RevokeCommissioning::Type value; + return SendCommand(kIdentityAlpha, GetEndpoint(0), AdministratorCommissioning::Id, + AdministratorCommissioning::Commands::RevokeCommissioning::Id, value, + chip::Optional(10000), chip::NullOptional + + ); + } + case 6: { + LogStep(6, "Check for second attribute report for WindowStatus"); + return WaitForReport(); + } + case 7: { + LogStep(7, "Subscribe AdminVendorId Attribute"); + return SubscribeAttribute(kIdentityAlpha, GetEndpoint(0), AdministratorCommissioning::Id, + AdministratorCommissioning::Attributes::AdminVendorId::Id, 2, 50, true, chip::NullOptional, + chip::NullOptional, /* autoResubscribe = */ chip::NullOptional); + } + case 8: { + LogStep(8, "Open the commissioning window 2"); + 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 9: { + LogStep(9, "Check for first attribute report for AdminVendorId"); + return WaitForReport(); + } + case 10: { + LogStep(10, "Close the commissioning window 2"); + ListFreer listFreer; + chip::app::Clusters::AdministratorCommissioning::Commands::RevokeCommissioning::Type value; + return SendCommand(kIdentityAlpha, GetEndpoint(0), AdministratorCommissioning::Id, + AdministratorCommissioning::Commands::RevokeCommissioning::Id, value, + chip::Optional(10000), chip::NullOptional + + ); + } + case 11: { + LogStep(11, "Check for second attribute report for AdminVendorId"); + return WaitForReport(); + } + case 12: { + LogStep(12, "Subscribe AdminFabricIndex Attribute"); + return SubscribeAttribute(kIdentityAlpha, GetEndpoint(0), AdministratorCommissioning::Id, + AdministratorCommissioning::Attributes::AdminFabricIndex::Id, 2, 50, true, chip::NullOptional, + chip::NullOptional, /* autoResubscribe = */ chip::NullOptional); + } + case 13: { + LogStep(13, "Open the commissioning window 3"); + 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 14: { + LogStep(14, "Check for first attribute report for AdminFabricIndex"); + return WaitForReport(); + } + case 15: { + LogStep(15, "Close the commissioning window 2"); + ListFreer listFreer; + chip::app::Clusters::AdministratorCommissioning::Commands::RevokeCommissioning::Type value; + return SendCommand(kIdentityAlpha, GetEndpoint(0), AdministratorCommissioning::Id, + AdministratorCommissioning::Commands::RevokeCommissioning::Id, value, + chip::Optional(10000), chip::NullOptional + + ); + } + case 16: { + LogStep(16, "Check for second attribute report for AdminFabricIndex"); + return WaitForReport(); + } + } + return CHIP_NO_ERROR; + } +}; + class DL_UsersAndCredentialsSuite : public TestCommand { public: @@ -104645,6 +104931,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 0c4c3e8c97c424..3fb1a5cc8884a1 100644 --- a/zzz_generated/darwin-framework-tool/zap-generated/test/Commands.h +++ b/zzz_generated/darwin-framework-tool/zap-generated/test/Commands.h @@ -216,6 +216,7 @@ class TestList : public Command { printf("TestMultiAdmin\n"); printf("Test_TC_DGSW_1_1\n"); printf("TestSubscribe_OnOff\n"); + printf("TestSubscribe_AdministratorCommissioning\n"); printf("DL_UsersAndCredentials\n"); printf("DL_LockUnlock\n"); printf("DL_Schedules\n"); @@ -100150,8 +100151,6 @@ class TestCommissioningWindow : public TestCommandBridge { AddArgument("cluster", &mCluster); AddArgument("discriminator", 0, UINT16_MAX, &mDiscriminator); AddArgument("payload", &mPayload); - AddArgument("alphaIndex", 0, UINT8_MAX, &mAlphaIndex); - AddArgument("betaIndex", 0, UINT8_MAX, &mBetaIndex); AddArgument("timeout", 0, UINT16_MAX, &mTimeout); } // NOLINTEND(clang-analyzer-nullability.NullPassedToNonnull) @@ -100408,8 +100407,6 @@ class TestCommissioningWindow : public TestCommandBridge { chip::Optional mCluster; chip::Optional mDiscriminator; chip::Optional mPayload; - chip::Optional mAlphaIndex; - chip::Optional mBetaIndex; chip::Optional mTimeout; CHIP_ERROR TestWaitForTheCommissionedDeviceToBeRetrievedForAlpha_0() @@ -100418,6 +100415,7 @@ class TestCommissioningWindow : public TestCommandBridge { value.nodeId = mNodeId.HasValue() ? mNodeId.Value() : 305414945ULL; return WaitForCommissionee("alpha", value); } + NSNumber * _Nonnull alphaIndex; CHIP_ERROR TestGetAlphasFabricIndex_1() { @@ -100432,8 +100430,7 @@ class TestCommissioningWindow : public TestCommandBridge { VerifyOrReturn(CheckValue("status", err ? err.code : 0, 0)); { - id actualValue = value; - VerifyOrReturn(CheckValue("CurrentFabricIndex", actualValue, mAlphaIndex.HasValue() ? mAlphaIndex.Value() : 1U)); + alphaIndex = value; } NextTest(); @@ -100569,8 +100566,12 @@ class TestCommissioningWindow : public TestCommandBridge { { id actualValue = value; - VerifyOrReturn(CheckValueNonNull("AdminFabricIndex", actualValue)); - VerifyOrReturn(CheckValue("AdminFabricIndex", actualValue, mAlphaIndex.HasValue() ? mAlphaIndex.Value() : 1U)); + if (alphaIndex == nil) { + VerifyOrReturn(CheckValueNull("AdminFabricIndex", actualValue)); + } else { + VerifyOrReturn(CheckValueNonNull("AdminFabricIndex", actualValue)); + VerifyOrReturn(CheckValue("AdminFabricIndex", actualValue, alphaIndex)); + } } NextTest(); @@ -100792,6 +100793,7 @@ class TestCommissioningWindow : public TestCommandBridge { return CHIP_NO_ERROR; } + NSNumber * _Nonnull betaIndex; CHIP_ERROR TestGetBetasFabricIndex_19() { @@ -100806,8 +100808,7 @@ class TestCommissioningWindow : public TestCommandBridge { VerifyOrReturn(CheckValue("status", err ? err.code : 0, 0)); { - id actualValue = value; - VerifyOrReturn(CheckValue("CurrentFabricIndex", actualValue, mBetaIndex.HasValue() ? mBetaIndex.Value() : 2U)); + betaIndex = value; } NextTest(); @@ -100874,8 +100875,12 @@ class TestCommissioningWindow : public TestCommandBridge { { id actualValue = value; - VerifyOrReturn(CheckValueNonNull("AdminFabricIndex", actualValue)); - VerifyOrReturn(CheckValue("AdminFabricIndex", actualValue, mBetaIndex.HasValue() ? mBetaIndex.Value() : 2U)); + if (betaIndex == nil) { + VerifyOrReturn(CheckValueNull("AdminFabricIndex", actualValue)); + } else { + VerifyOrReturn(CheckValueNonNull("AdminFabricIndex", actualValue)); + VerifyOrReturn(CheckValue("AdminFabricIndex", actualValue, betaIndex)); + } } NextTest(); @@ -100918,8 +100923,7 @@ class TestCommissioningWindow : public TestCommandBridge { VerifyOrReturnError(cluster != nil, CHIP_ERROR_INCORRECT_STATE); __auto_type * params = [[MTROperationalCredentialsClusterRemoveFabricParams alloc] init]; - params.fabricIndex - = mBetaIndex.HasValue() ? [NSNumber numberWithUnsignedChar:mBetaIndex.Value()] : [NSNumber numberWithUnsignedChar:2U]; + params.fabricIndex = [betaIndex copy]; [cluster removeFabricWithParams:params completion:^( MTROperationalCredentialsClusterNOCResponseParams * _Nullable values, NSError * _Nullable err) { @@ -102208,6 +102212,695 @@ class TestSubscribe_OnOff : public TestCommandBridge { } }; +class TestSubscribe_AdministratorCommissioning : public TestCommandBridge { +public: + // NOLINTBEGIN(clang-analyzer-nullability.NullPassedToNonnull): Test constructor nullability not enforced + TestSubscribe_AdministratorCommissioning() + : TestCommandBridge("TestSubscribe_AdministratorCommissioning") + , mTestIndex(0) + { + AddArgument("nodeId", 0, UINT64_MAX, &mNodeId); + AddArgument("cluster", &mCluster); + AddArgument("endpoint", 0, UINT16_MAX, &mEndpoint); + AddArgument("ourVendorId", 0, UINT16_MAX, &mOurVendorId); + AddArgument("timeout", 0, UINT16_MAX, &mTimeout); + } + // NOLINTEND(clang-analyzer-nullability.NullPassedToNonnull) + + ~TestSubscribe_AdministratorCommissioning() {} + + /////////// TestCommand Interface ///////// + void NextTest() override + { + CHIP_ERROR err = CHIP_NO_ERROR; + + if (0 == mTestIndex) { + ChipLogProgress(chipTool, " **** Test Start: TestSubscribe_AdministratorCommissioning\n"); + } + + if (mTestCount == mTestIndex) { + ChipLogProgress(chipTool, " **** Test Complete: TestSubscribe_AdministratorCommissioning\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 : Get ourfabric index\n"); + err = TestGetOurfabricIndex_1(); + break; + case 2: + ChipLogProgress(chipTool, " ***** Test Step 2 : Report: Subscribe WindowStatus Attribute\n"); + err = TestReportSubscribeWindowStatusAttribute_2(); + break; + case 3: + ChipLogProgress(chipTool, " ***** Test Step 3 : Subscribe WindowStatus Attribute\n"); + err = TestSubscribeWindowStatusAttribute_3(); + break; + case 4: + ChipLogProgress(chipTool, " ***** Test Step 4 : Open the commissioning window 1\n"); + err = TestOpenTheCommissioningWindow1_4(); + break; + case 5: + ChipLogProgress(chipTool, " ***** Test Step 5 : Check for first attribute report for WindowStatus\n"); + err = TestCheckForFirstAttributeReportForWindowStatus_5(); + break; + case 6: + ChipLogProgress(chipTool, " ***** Test Step 6 : Close the commissioning window 1\n"); + err = TestCloseTheCommissioningWindow1_6(); + break; + case 7: + ChipLogProgress(chipTool, " ***** Test Step 7 : Check for second attribute report for WindowStatus\n"); + err = TestCheckForSecondAttributeReportForWindowStatus_7(); + break; + case 8: + ChipLogProgress(chipTool, " ***** Test Step 8 : Report: Subscribe AdminVendorId Attribute\n"); + err = TestReportSubscribeAdminVendorIdAttribute_8(); + break; + case 9: + ChipLogProgress(chipTool, " ***** Test Step 9 : Subscribe AdminVendorId Attribute\n"); + err = TestSubscribeAdminVendorIdAttribute_9(); + break; + case 10: + ChipLogProgress(chipTool, " ***** Test Step 10 : Open the commissioning window 2\n"); + err = TestOpenTheCommissioningWindow2_10(); + break; + case 11: + ChipLogProgress(chipTool, " ***** Test Step 11 : Check for first attribute report for AdminVendorId\n"); + err = TestCheckForFirstAttributeReportForAdminVendorId_11(); + break; + case 12: + ChipLogProgress(chipTool, " ***** Test Step 12 : Close the commissioning window 2\n"); + err = TestCloseTheCommissioningWindow2_12(); + break; + case 13: + ChipLogProgress(chipTool, " ***** Test Step 13 : Check for second attribute report for AdminVendorId\n"); + err = TestCheckForSecondAttributeReportForAdminVendorId_13(); + break; + case 14: + ChipLogProgress(chipTool, " ***** Test Step 14 : Report: Subscribe AdminFabricIndex Attribute\n"); + err = TestReportSubscribeAdminFabricIndexAttribute_14(); + break; + case 15: + ChipLogProgress(chipTool, " ***** Test Step 15 : Subscribe AdminFabricIndex Attribute\n"); + err = TestSubscribeAdminFabricIndexAttribute_15(); + break; + case 16: + ChipLogProgress(chipTool, " ***** Test Step 16 : Open the commissioning window 3\n"); + err = TestOpenTheCommissioningWindow3_16(); + break; + case 17: + ChipLogProgress(chipTool, " ***** Test Step 17 : Check for first attribute report for AdminFabricIndex\n"); + err = TestCheckForFirstAttributeReportForAdminFabricIndex_17(); + break; + case 18: + ChipLogProgress(chipTool, " ***** Test Step 18 : Close the commissioning window 2\n"); + err = TestCloseTheCommissioningWindow2_18(); + break; + case 19: + ChipLogProgress(chipTool, " ***** Test Step 19 : Check for second attribute report for AdminFabricIndex\n"); + err = TestCheckForSecondAttributeReportForAdminFabricIndex_19(); + 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; + } + + // 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 = 20; + + chip::Optional mNodeId; + chip::Optional mCluster; + chip::Optional mEndpoint; + chip::Optional mOurVendorId; + 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); + } + NSNumber * _Nonnull ourFabricIndex; + + CHIP_ERROR TestGetOurfabricIndex_1() + { + MTRBaseDevice * device = GetDevice("alpha"); + MTRBaseClusterOperationalCredentials * cluster = + [[MTRBaseClusterOperationalCredentials alloc] initWithDevice:device endpointID:@(0) queue:mCallbackQueue]; + VerifyOrReturnError(cluster != nil, CHIP_ERROR_INCORRECT_STATE); + + [cluster readAttributeCurrentFabricIndexWithCompletion:^(NSNumber * _Nullable value, NSError * _Nullable err) { + NSLog(@"Get ourfabric index Error: %@", err); + + VerifyOrReturn(CheckValue("status", err ? err.code : 0, 0)); + + { + ourFabricIndex = value; + } + + NextTest(); + }]; + + return CHIP_NO_ERROR; + } + bool testSendClusterTestSubscribe_AdministratorCommissioning_2_WaitForReport_Fulfilled = false; + ResponseHandler _Nullable test_TestSubscribe_AdministratorCommissioning_WindowStatus_Reported = nil; + + CHIP_ERROR TestReportSubscribeWindowStatusAttribute_2() + { + MTRBaseDevice * device = GetDevice("alpha"); + MTRBaseClusterAdministratorCommissioning * cluster = + [[MTRBaseClusterAdministratorCommissioning alloc] initWithDevice:device endpointID:@(0) queue:mCallbackQueue]; + VerifyOrReturnError(cluster != nil, CHIP_ERROR_INCORRECT_STATE); + + test_TestSubscribe_AdministratorCommissioning_WindowStatus_Reported + = ^(NSNumber * _Nullable value, NSError * _Nullable err) { + NSLog(@"Report: Subscribe WindowStatus Attribute Error: %@", err); + + VerifyOrReturn(CheckValue("status", err ? err.code : 0, 0)); + + { + id actualValue = value; + VerifyOrReturn(CheckValue("WindowStatus", actualValue, 0U)); + } + + testSendClusterTestSubscribe_AdministratorCommissioning_2_WaitForReport_Fulfilled = true; + }; + + NextTest(); + return CHIP_NO_ERROR; + } + + CHIP_ERROR TestSubscribeWindowStatusAttribute_3() + { + MTRBaseDevice * device = GetDevice("alpha"); + MTRBaseClusterAdministratorCommissioning * cluster = + [[MTRBaseClusterAdministratorCommissioning alloc] initWithDevice:device endpointID:@(0) queue:mCallbackQueue]; + VerifyOrReturnError(cluster != nil, CHIP_ERROR_INCORRECT_STATE); + + uint16_t minIntervalArgument = 2U; + uint16_t maxIntervalArgument = 50U; + MTRSubscribeParams * params = [[MTRSubscribeParams alloc] initWithMinInterval:@(minIntervalArgument) + maxInterval:@(maxIntervalArgument)]; + params.filterByFabric = true; + params.replaceExistingSubscriptions = true; + [cluster subscribeAttributeWindowStatusWithParams:params + subscriptionEstablished:^{ + VerifyOrReturn(testSendClusterTestSubscribe_AdministratorCommissioning_2_WaitForReport_Fulfilled, + SetCommandExitStatus(CHIP_ERROR_INCORRECT_STATE)); + NextTest(); + } + reportHandler:^(NSNumber * _Nullable value, NSError * _Nullable err) { + NSLog(@"Subscribe WindowStatus Attribute Error: %@", err); + + VerifyOrReturn(CheckValue("status", err ? err.code : 0, 0)); + if (test_TestSubscribe_AdministratorCommissioning_WindowStatus_Reported != nil) { + ResponseHandler callback = test_TestSubscribe_AdministratorCommissioning_WindowStatus_Reported; + test_TestSubscribe_AdministratorCommissioning_WindowStatus_Reported = nil; + callback(value, err); + } + }]; + + return CHIP_NO_ERROR; + } + + CHIP_ERROR TestOpenTheCommissioningWindow1_4() + { + MTRBaseDevice * device = GetDevice("alpha"); + MTRBaseClusterAdministratorCommissioning * cluster = + [[MTRBaseClusterAdministratorCommissioning alloc] initWithDevice:device endpointID:@(0) queue:mCallbackQueue]; + VerifyOrReturnError(cluster != nil, CHIP_ERROR_INCORRECT_STATE); + + __auto_type * params = [[MTRAdministratorCommissioningClusterOpenBasicCommissioningWindowParams alloc] init]; + params.commissioningTimeout = [NSNumber numberWithUnsignedShort:180U]; + [cluster openBasicCommissioningWindowWithParams:params + completion:^(NSError * _Nullable err) { + NSLog(@"Open the commissioning window 1 Error: %@", err); + + VerifyOrReturn(CheckValue("status", err ? err.code : 0, 0)); + + NextTest(); + }]; + + return CHIP_NO_ERROR; + } + + CHIP_ERROR TestCheckForFirstAttributeReportForWindowStatus_5() + { + MTRBaseDevice * device = GetDevice("alpha"); + MTRBaseClusterAdministratorCommissioning * cluster = + [[MTRBaseClusterAdministratorCommissioning alloc] initWithDevice:device endpointID:@(0) queue:mCallbackQueue]; + VerifyOrReturnError(cluster != nil, CHIP_ERROR_INCORRECT_STATE); + + test_TestSubscribe_AdministratorCommissioning_WindowStatus_Reported + = ^(NSNumber * _Nullable value, NSError * _Nullable err) { + NSLog(@"Check for first attribute report for WindowStatus Error: %@", err); + + VerifyOrReturn(CheckValue("status", err ? err.code : 0, 0)); + + { + id actualValue = value; + VerifyOrReturn(CheckValue("WindowStatus", actualValue, 2U)); + } + + NextTest(); + }; + + return CHIP_NO_ERROR; + } + + CHIP_ERROR TestCloseTheCommissioningWindow1_6() + { + MTRBaseDevice * device = GetDevice("alpha"); + MTRBaseClusterAdministratorCommissioning * cluster = + [[MTRBaseClusterAdministratorCommissioning alloc] initWithDevice:device endpointID:@(0) queue:mCallbackQueue]; + VerifyOrReturnError(cluster != nil, CHIP_ERROR_INCORRECT_STATE); + + [cluster revokeCommissioningWithCompletion:^(NSError * _Nullable err) { + NSLog(@"Close the commissioning window 1 Error: %@", err); + + VerifyOrReturn(CheckValue("status", err ? err.code : 0, 0)); + + NextTest(); + }]; + + return CHIP_NO_ERROR; + } + + CHIP_ERROR TestCheckForSecondAttributeReportForWindowStatus_7() + { + MTRBaseDevice * device = GetDevice("alpha"); + MTRBaseClusterAdministratorCommissioning * cluster = + [[MTRBaseClusterAdministratorCommissioning alloc] initWithDevice:device endpointID:@(0) queue:mCallbackQueue]; + VerifyOrReturnError(cluster != nil, CHIP_ERROR_INCORRECT_STATE); + + test_TestSubscribe_AdministratorCommissioning_WindowStatus_Reported + = ^(NSNumber * _Nullable value, NSError * _Nullable err) { + NSLog(@"Check for second attribute report for WindowStatus Error: %@", err); + + VerifyOrReturn(CheckValue("status", err ? err.code : 0, 0)); + + { + id actualValue = value; + VerifyOrReturn(CheckValue("WindowStatus", actualValue, 0U)); + } + + NextTest(); + }; + + return CHIP_NO_ERROR; + } + bool testSendClusterTestSubscribe_AdministratorCommissioning_8_WaitForReport_Fulfilled = false; + ResponseHandler _Nullable test_TestSubscribe_AdministratorCommissioning_AdminVendorId_Reported = nil; + + CHIP_ERROR TestReportSubscribeAdminVendorIdAttribute_8() + { + MTRBaseDevice * device = GetDevice("alpha"); + MTRBaseClusterAdministratorCommissioning * cluster = + [[MTRBaseClusterAdministratorCommissioning alloc] initWithDevice:device endpointID:@(0) queue:mCallbackQueue]; + VerifyOrReturnError(cluster != nil, CHIP_ERROR_INCORRECT_STATE); + + test_TestSubscribe_AdministratorCommissioning_AdminVendorId_Reported + = ^(NSNumber * _Nullable value, NSError * _Nullable err) { + NSLog(@"Report: Subscribe AdminVendorId Attribute Error: %@", err); + + VerifyOrReturn(CheckValue("status", err ? err.code : 0, 0)); + + { + id actualValue = value; + VerifyOrReturn(CheckValueNull("AdminVendorId", actualValue)); + } + + testSendClusterTestSubscribe_AdministratorCommissioning_8_WaitForReport_Fulfilled = true; + }; + + NextTest(); + return CHIP_NO_ERROR; + } + + CHIP_ERROR TestSubscribeAdminVendorIdAttribute_9() + { + MTRBaseDevice * device = GetDevice("alpha"); + MTRBaseClusterAdministratorCommissioning * cluster = + [[MTRBaseClusterAdministratorCommissioning alloc] initWithDevice:device endpointID:@(0) queue:mCallbackQueue]; + VerifyOrReturnError(cluster != nil, CHIP_ERROR_INCORRECT_STATE); + + uint16_t minIntervalArgument = 2U; + uint16_t maxIntervalArgument = 50U; + MTRSubscribeParams * params = [[MTRSubscribeParams alloc] initWithMinInterval:@(minIntervalArgument) + maxInterval:@(maxIntervalArgument)]; + params.filterByFabric = true; + params.replaceExistingSubscriptions = true; + [cluster subscribeAttributeAdminVendorIdWithParams:params + subscriptionEstablished:^{ + VerifyOrReturn(testSendClusterTestSubscribe_AdministratorCommissioning_8_WaitForReport_Fulfilled, + SetCommandExitStatus(CHIP_ERROR_INCORRECT_STATE)); + NextTest(); + } + reportHandler:^(NSNumber * _Nullable value, NSError * _Nullable err) { + NSLog(@"Subscribe AdminVendorId Attribute Error: %@", err); + + VerifyOrReturn(CheckValue("status", err ? err.code : 0, 0)); + if (test_TestSubscribe_AdministratorCommissioning_AdminVendorId_Reported != nil) { + ResponseHandler callback = test_TestSubscribe_AdministratorCommissioning_AdminVendorId_Reported; + test_TestSubscribe_AdministratorCommissioning_AdminVendorId_Reported = nil; + callback(value, err); + } + }]; + + return CHIP_NO_ERROR; + } + + CHIP_ERROR TestOpenTheCommissioningWindow2_10() + { + MTRBaseDevice * device = GetDevice("alpha"); + MTRBaseClusterAdministratorCommissioning * cluster = + [[MTRBaseClusterAdministratorCommissioning alloc] initWithDevice:device endpointID:@(0) queue:mCallbackQueue]; + VerifyOrReturnError(cluster != nil, CHIP_ERROR_INCORRECT_STATE); + + __auto_type * params = [[MTRAdministratorCommissioningClusterOpenBasicCommissioningWindowParams alloc] init]; + params.commissioningTimeout = [NSNumber numberWithUnsignedShort:180U]; + [cluster openBasicCommissioningWindowWithParams:params + completion:^(NSError * _Nullable err) { + NSLog(@"Open the commissioning window 2 Error: %@", err); + + VerifyOrReturn(CheckValue("status", err ? err.code : 0, 0)); + + NextTest(); + }]; + + return CHIP_NO_ERROR; + } + + CHIP_ERROR TestCheckForFirstAttributeReportForAdminVendorId_11() + { + MTRBaseDevice * device = GetDevice("alpha"); + MTRBaseClusterAdministratorCommissioning * cluster = + [[MTRBaseClusterAdministratorCommissioning alloc] initWithDevice:device endpointID:@(0) queue:mCallbackQueue]; + VerifyOrReturnError(cluster != nil, CHIP_ERROR_INCORRECT_STATE); + + test_TestSubscribe_AdministratorCommissioning_AdminVendorId_Reported = ^( + NSNumber * _Nullable value, NSError * _Nullable err) { + NSLog(@"Check for first attribute report for AdminVendorId Error: %@", err); + + VerifyOrReturn(CheckValue("status", err ? err.code : 0, 0)); + + { + id actualValue = value; + VerifyOrReturn(CheckValueNonNull("AdminVendorId", actualValue)); + VerifyOrReturn(CheckValue("AdminVendorId", actualValue, mOurVendorId.HasValue() ? mOurVendorId.Value() : 65521U)); + } + + NextTest(); + }; + + return CHIP_NO_ERROR; + } + + CHIP_ERROR TestCloseTheCommissioningWindow2_12() + { + MTRBaseDevice * device = GetDevice("alpha"); + MTRBaseClusterAdministratorCommissioning * cluster = + [[MTRBaseClusterAdministratorCommissioning alloc] initWithDevice:device endpointID:@(0) queue:mCallbackQueue]; + VerifyOrReturnError(cluster != nil, CHIP_ERROR_INCORRECT_STATE); + + [cluster revokeCommissioningWithCompletion:^(NSError * _Nullable err) { + NSLog(@"Close the commissioning window 2 Error: %@", err); + + VerifyOrReturn(CheckValue("status", err ? err.code : 0, 0)); + + NextTest(); + }]; + + return CHIP_NO_ERROR; + } + + CHIP_ERROR TestCheckForSecondAttributeReportForAdminVendorId_13() + { + MTRBaseDevice * device = GetDevice("alpha"); + MTRBaseClusterAdministratorCommissioning * cluster = + [[MTRBaseClusterAdministratorCommissioning alloc] initWithDevice:device endpointID:@(0) queue:mCallbackQueue]; + VerifyOrReturnError(cluster != nil, CHIP_ERROR_INCORRECT_STATE); + + test_TestSubscribe_AdministratorCommissioning_AdminVendorId_Reported + = ^(NSNumber * _Nullable value, NSError * _Nullable err) { + NSLog(@"Check for second attribute report for AdminVendorId Error: %@", err); + + VerifyOrReturn(CheckValue("status", err ? err.code : 0, 0)); + + { + id actualValue = value; + VerifyOrReturn(CheckValueNull("AdminVendorId", actualValue)); + } + + NextTest(); + }; + + return CHIP_NO_ERROR; + } + bool testSendClusterTestSubscribe_AdministratorCommissioning_14_WaitForReport_Fulfilled = false; + ResponseHandler _Nullable test_TestSubscribe_AdministratorCommissioning_AdminFabricIndex_Reported = nil; + + CHIP_ERROR TestReportSubscribeAdminFabricIndexAttribute_14() + { + MTRBaseDevice * device = GetDevice("alpha"); + MTRBaseClusterAdministratorCommissioning * cluster = + [[MTRBaseClusterAdministratorCommissioning alloc] initWithDevice:device endpointID:@(0) queue:mCallbackQueue]; + VerifyOrReturnError(cluster != nil, CHIP_ERROR_INCORRECT_STATE); + + test_TestSubscribe_AdministratorCommissioning_AdminFabricIndex_Reported + = ^(NSNumber * _Nullable value, NSError * _Nullable err) { + NSLog(@"Report: Subscribe AdminFabricIndex Attribute Error: %@", err); + + VerifyOrReturn(CheckValue("status", err ? err.code : 0, 0)); + + { + id actualValue = value; + VerifyOrReturn(CheckValueNull("AdminFabricIndex", actualValue)); + } + + testSendClusterTestSubscribe_AdministratorCommissioning_14_WaitForReport_Fulfilled = true; + }; + + NextTest(); + return CHIP_NO_ERROR; + } + + CHIP_ERROR TestSubscribeAdminFabricIndexAttribute_15() + { + MTRBaseDevice * device = GetDevice("alpha"); + MTRBaseClusterAdministratorCommissioning * cluster = + [[MTRBaseClusterAdministratorCommissioning alloc] initWithDevice:device endpointID:@(0) queue:mCallbackQueue]; + VerifyOrReturnError(cluster != nil, CHIP_ERROR_INCORRECT_STATE); + + uint16_t minIntervalArgument = 2U; + uint16_t maxIntervalArgument = 50U; + MTRSubscribeParams * params = [[MTRSubscribeParams alloc] initWithMinInterval:@(minIntervalArgument) + maxInterval:@(maxIntervalArgument)]; + params.filterByFabric = true; + params.replaceExistingSubscriptions = true; + [cluster subscribeAttributeAdminFabricIndexWithParams:params + subscriptionEstablished:^{ + VerifyOrReturn(testSendClusterTestSubscribe_AdministratorCommissioning_14_WaitForReport_Fulfilled, + SetCommandExitStatus(CHIP_ERROR_INCORRECT_STATE)); + NextTest(); + } + reportHandler:^(NSNumber * _Nullable value, NSError * _Nullable err) { + NSLog(@"Subscribe AdminFabricIndex Attribute Error: %@", err); + + VerifyOrReturn(CheckValue("status", err ? err.code : 0, 0)); + if (test_TestSubscribe_AdministratorCommissioning_AdminFabricIndex_Reported != nil) { + ResponseHandler callback = test_TestSubscribe_AdministratorCommissioning_AdminFabricIndex_Reported; + test_TestSubscribe_AdministratorCommissioning_AdminFabricIndex_Reported = nil; + callback(value, err); + } + }]; + + return CHIP_NO_ERROR; + } + + CHIP_ERROR TestOpenTheCommissioningWindow3_16() + { + MTRBaseDevice * device = GetDevice("alpha"); + MTRBaseClusterAdministratorCommissioning * cluster = + [[MTRBaseClusterAdministratorCommissioning alloc] initWithDevice:device endpointID:@(0) queue:mCallbackQueue]; + VerifyOrReturnError(cluster != nil, CHIP_ERROR_INCORRECT_STATE); + + __auto_type * params = [[MTRAdministratorCommissioningClusterOpenBasicCommissioningWindowParams alloc] init]; + params.commissioningTimeout = [NSNumber numberWithUnsignedShort:180U]; + [cluster openBasicCommissioningWindowWithParams:params + completion:^(NSError * _Nullable err) { + NSLog(@"Open the commissioning window 3 Error: %@", err); + + VerifyOrReturn(CheckValue("status", err ? err.code : 0, 0)); + + NextTest(); + }]; + + return CHIP_NO_ERROR; + } + + CHIP_ERROR TestCheckForFirstAttributeReportForAdminFabricIndex_17() + { + MTRBaseDevice * device = GetDevice("alpha"); + MTRBaseClusterAdministratorCommissioning * cluster = + [[MTRBaseClusterAdministratorCommissioning alloc] initWithDevice:device endpointID:@(0) queue:mCallbackQueue]; + VerifyOrReturnError(cluster != nil, CHIP_ERROR_INCORRECT_STATE); + + test_TestSubscribe_AdministratorCommissioning_AdminFabricIndex_Reported + = ^(NSNumber * _Nullable value, NSError * _Nullable err) { + NSLog(@"Check for first attribute report for AdminFabricIndex Error: %@", err); + + VerifyOrReturn(CheckValue("status", err ? err.code : 0, 0)); + + { + id actualValue = value; + if (ourFabricIndex == nil) { + VerifyOrReturn(CheckValueNull("AdminFabricIndex", actualValue)); + } else { + VerifyOrReturn(CheckValueNonNull("AdminFabricIndex", actualValue)); + VerifyOrReturn(CheckValue("AdminFabricIndex", actualValue, ourFabricIndex)); + } + } + + NextTest(); + }; + + return CHIP_NO_ERROR; + } + + CHIP_ERROR TestCloseTheCommissioningWindow2_18() + { + MTRBaseDevice * device = GetDevice("alpha"); + MTRBaseClusterAdministratorCommissioning * cluster = + [[MTRBaseClusterAdministratorCommissioning alloc] initWithDevice:device endpointID:@(0) queue:mCallbackQueue]; + VerifyOrReturnError(cluster != nil, CHIP_ERROR_INCORRECT_STATE); + + [cluster revokeCommissioningWithCompletion:^(NSError * _Nullable err) { + NSLog(@"Close the commissioning window 2 Error: %@", err); + + VerifyOrReturn(CheckValue("status", err ? err.code : 0, 0)); + + NextTest(); + }]; + + return CHIP_NO_ERROR; + } + + CHIP_ERROR TestCheckForSecondAttributeReportForAdminFabricIndex_19() + { + MTRBaseDevice * device = GetDevice("alpha"); + MTRBaseClusterAdministratorCommissioning * cluster = + [[MTRBaseClusterAdministratorCommissioning alloc] initWithDevice:device endpointID:@(0) queue:mCallbackQueue]; + VerifyOrReturnError(cluster != nil, CHIP_ERROR_INCORRECT_STATE); + + test_TestSubscribe_AdministratorCommissioning_AdminFabricIndex_Reported + = ^(NSNumber * _Nullable value, NSError * _Nullable err) { + NSLog(@"Check for second attribute report for AdminFabricIndex Error: %@", err); + + VerifyOrReturn(CheckValue("status", err ? err.code : 0, 0)); + + { + id actualValue = value; + VerifyOrReturn(CheckValueNull("AdminFabricIndex", actualValue)); + } + + NextTest(); + }; + + return CHIP_NO_ERROR; + } +}; + class DL_UsersAndCredentials : public TestCommandBridge { public: // NOLINTBEGIN(clang-analyzer-nullability.NullPassedToNonnull): Test constructor nullability not enforced @@ -125555,6 +126248,7 @@ void registerCommandsTests(Commands & commands) make_unique(), make_unique(), make_unique(), + make_unique(), make_unique(), make_unique(), make_unique(),