From f87c4203e55622882535f636d99f8f671e689be9 Mon Sep 17 00:00:00 2001 From: Mathieu Kardous Date: Fri, 19 Apr 2024 14:03:50 -0500 Subject: [PATCH] Update and Document ICDManager interface --- .../lit-icd-app/nrfconnect/main/AppTask.cpp | 3 +- examples/platform/silabs/BaseApplication.cpp | 4 +- src/app/icd/server/ICDManager.cpp | 23 +- src/app/icd/server/ICDManager.h | 144 +++++-- src/app/icd/server/ICDStateObserver.h | 34 +- src/app/reporting/ReportSchedulerImpl.h | 6 + src/app/server/Dnssd.h | 20 +- src/app/tests/TestICDManager.cpp | 393 +++++++++++++++++- src/messaging/ExchangeContext.cpp | 2 + 9 files changed, 558 insertions(+), 71 deletions(-) diff --git a/examples/lit-icd-app/nrfconnect/main/AppTask.cpp b/examples/lit-icd-app/nrfconnect/main/AppTask.cpp index d7d35bb53fcc04..336024fe289ea3 100644 --- a/examples/lit-icd-app/nrfconnect/main/AppTask.cpp +++ b/examples/lit-icd-app/nrfconnect/main/AppTask.cpp @@ -296,7 +296,8 @@ void AppTask::ButtonEventHandler(uint32_t buttonState, uint32_t hasChanged) void AppTask::IcdUatEventHandler(const AppEvent &) { - Server::GetInstance().GetICDManager().UpdateOperationState(ICDManager::OperationalState::ActiveMode); + // Temporarily claim network activity, until we implement a "user trigger" reason for ICD wakeups. + PlatformMgr().ScheduleWork([](intptr_t) { ICDNotifier::GetInstance().NotifyNetworkActivityNotification(); }); } void AppTask::FunctionTimerTimeoutCallback(k_timer * timer) diff --git a/examples/platform/silabs/BaseApplication.cpp b/examples/platform/silabs/BaseApplication.cpp index a6986db57d2b3e..f02826f1308c32 100644 --- a/examples/platform/silabs/BaseApplication.cpp +++ b/examples/platform/silabs/BaseApplication.cpp @@ -515,9 +515,7 @@ void BaseApplication::ButtonHandler(AppEvent * aEvent) SILABS_LOG("Network is already provisioned, Ble advertisement not enabled"); #if CHIP_CONFIG_ENABLE_ICD_SERVER // Temporarily claim network activity, until we implement a "user trigger" reason for ICD wakeups. - PlatformMgr().LockChipStack(); - ICDNotifier::GetInstance().NotifyNetworkActivityNotification(); - PlatformMgr().UnlockChipStack(); + PlatformMgr().ScheduleWork([](intptr_t) { ICDNotifier::GetInstance().NotifyNetworkActivityNotification(); }); #endif // CHIP_CONFIG_ENABLE_ICD_SERVER } } diff --git a/src/app/icd/server/ICDManager.cpp b/src/app/icd/server/ICDManager.cpp index 5f93946fa8eebf..e16acce86e850b 100644 --- a/src/app/icd/server/ICDManager.cpp +++ b/src/app/icd/server/ICDManager.cpp @@ -378,12 +378,13 @@ void ICDManager::UpdateICDMode() if (ICDConfigurationData::GetInstance().GetICDMode() != tempMode) { ICDConfigurationData::GetInstance().SetICDMode(tempMode); - postObserverEvent(ObserverEventType::ICDModeChange); // Can't use attribute accessors/Attributes::OperatingMode::Set in unit tests #if !CONFIG_BUILD_FOR_HOST_UNIT_TEST Attributes::OperatingMode::Set(kRootEndpointId, static_cast(tempMode)); #endif + + postObserverEvent(ObserverEventType::ICDModeChange); } // When in SIT mode, the slow poll interval SHOULDN'T be greater than the SIT mode polling threshold, per spec. @@ -433,6 +434,8 @@ void ICDManager::UpdateOperationState(OperationalState state) { ChipLogError(AppServer, "Failed to set Slow Polling Interval: err %" CHIP_ERROR_FORMAT, err.Format()); } + + postObserverEvent(ObserverEventType::EnterIdleMode); } else if (state == OperationalState::ActiveMode) { @@ -447,7 +450,7 @@ void ICDManager::UpdateOperationState(OperationalState state) if (activeModeDuration == kZero && !mKeepActiveFlags.HasAny()) { - // A Network Activity triggered the active mode and activeModeDuration is 0. + // Network Activity triggered the active mode and activeModeDuration is 0. // Stay active for at least Active Mode Threshold. activeModeDuration = ICDConfigurationData::GetInstance().GetActiveModeThreshold(); } @@ -455,9 +458,14 @@ void ICDManager::UpdateOperationState(OperationalState state) DeviceLayer::SystemLayer().StartTimer(activeModeDuration, OnActiveModeDone, this); Milliseconds32 activeModeJitterInterval = Milliseconds32(ICD_ACTIVE_TIME_JITTER_MS); + // TODO(#33074): Edge case when we transition to IdleMode with this conditio being true + // (activeModeDuration == kZero && !mKeepActiveFlags.HasAny()) activeModeJitterInterval = (activeModeDuration >= activeModeJitterInterval) ? activeModeDuration - activeModeJitterInterval : kZero; + // Reset this flag when we enter ActiveMode to avoid having a feedback loop that keeps us indefinitly in + // ActiveMode. + mTransitionToIdleCalled = false; DeviceLayer::SystemLayer().StartTimer(activeModeJitterInterval, OnTransitionToIdle, this); CHIP_ERROR err = @@ -504,10 +512,6 @@ void ICDManager::OnIdleModeDone(System::Layer * aLayer, void * appState) { ICDManager * pICDManager = reinterpret_cast(appState); pICDManager->UpdateOperationState(OperationalState::ActiveMode); - - // We only reset this flag when idle mode is complete to avoid re-triggering the check when an event brings us back to active, - // which could cause a loop. - pICDManager->mTransitionToIdleCalled = false; } void ICDManager::OnActiveModeDone(System::Layer * aLayer, void * appState) @@ -532,10 +536,10 @@ void ICDManager::OnTransitionToIdle(System::Layer * aLayer, void * appState) } /* ICDListener functions. */ + void ICDManager::OnKeepActiveRequest(KeepActiveFlags request) { assertChipStackLockedByCurrentThread(); - VerifyOrReturn(request < KeepActiveFlagsValues::kInvalidFlag); if (request.Has(KeepActiveFlag::kExchangeContextOpen)) @@ -560,7 +564,6 @@ void ICDManager::OnKeepActiveRequest(KeepActiveFlags request) void ICDManager::OnActiveRequestWithdrawal(KeepActiveFlags request) { assertChipStackLockedByCurrentThread(); - VerifyOrReturn(request < KeepActiveFlagsValues::kInvalidFlag); if (request.Has(KeepActiveFlag::kExchangeContextOpen)) @@ -697,6 +700,10 @@ void ICDManager::postObserverEvent(ObserverEventType event) obs->mObserver->OnEnterActiveMode(); return Loop::Continue; } + case ObserverEventType::EnterIdleMode: { + obs->mObserver->OnEnterIdleMode(); + return Loop::Continue; + } case ObserverEventType::TransitionToIdle: { obs->mObserver->OnTransitionToIdle(); return Loop::Continue; diff --git a/src/app/icd/server/ICDManager.h b/src/app/icd/server/ICDManager.h index 69dfdbf6a88863..391f3dce6499c4 100644 --- a/src/app/icd/server/ICDManager.h +++ b/src/app/icd/server/ICDManager.h @@ -57,7 +57,9 @@ class TestICDManager; class ICDManager : public ICDListener, public TestEventTriggerHandler { public: - // This structure is used for the creation an ObjectPool of ICDStateObserver pointers + /** + * @brief This structure is used for the creation an ObjectPool of ICDStateObserver pointers + */ struct ObserverPointer { ObserverPointer(ICDStateObserver * obs) : mObserver(obs) {} @@ -71,11 +73,14 @@ class ICDManager : public ICDListener, public TestEventTriggerHandler ActiveMode, }; - // This enum class represents to all ICDStateObserver callbacks available from the - // mStateObserverPool for the ICDManager. + /** + * @brief This enum class represents to all ICDStateObserver callbacks available from the + * mStateObserverPool for the ICDManager. + */ enum class ObserverEventType : uint8_t { EnterActiveMode, + EnterIdleMode, TransitionToIdle, ICDModeChange, }; @@ -85,22 +90,31 @@ class ICDManager : public ICDListener, public TestEventTriggerHandler * This type can be used to implement specific verifiers that can be used in the CheckInMessagesWouldBeSent function. * The goal is to avoid having multiple functions that implement the iterator loop with only the check changing. * - * @return true if at least one Check-In message would be sent - * false No Check-In messages would be sent + * @return true: if at least one Check-In message would be sent + * false: No Check-In messages would be sent */ - using ShouldCheckInMsgsBeSentFunction = bool(FabricIndex aFabricIndex, NodeId subjectID); - ICDManager() {} + ICDManager() = default; + ~ICDManager() = default; + void Init(PersistentStorageDelegate * storage, FabricTable * fabricTable, Crypto::SymmetricKeystore * symmetricKeyStore, - Messaging::ExchangeManager * exchangeManager, SubscriptionsInfoProvider * manager); + Messaging::ExchangeManager * exchangeManager, SubscriptionsInfoProvider * subInfoProvider); void Shutdown(); - void UpdateICDMode(); - void UpdateOperationState(OperationalState state); - void SetKeepActiveModeRequirements(KeepActiveFlags flag, bool state); - bool IsKeepActive() { return mKeepActiveFlags.HasAny(); } + + /** + * @brief SupportsFeature verifies if a given FeatureMap bit is enabled + * + * @param[in] feature FeatureMap bit to verify + * + * @return true: if the FeatureMap bit is enabled in the ICDM cluster attribute. + * false: ff the FeatureMap bit is not enabled in the ICDM cluster attribute. + * if we failed to read the FeatureMap attribute. + */ bool SupportsFeature(Clusters::IcdManagement::Feature feature); + ICDConfigurationData::ICDMode GetICDMode() { return ICDConfigurationData::GetInstance().GetICDMode(); }; + /** * @brief Adds the referenced observer in parameters to the mStateObserverPool * A maximum of CHIP_CONFIG_ICD_OBSERVERS_POOL_SIZE observers can be concurrently registered @@ -111,20 +125,14 @@ class ICDManager : public ICDListener, public TestEventTriggerHandler /** * @brief Remove the referenced observer in parameters from the mStateObserverPool + * If the observer is not present in the object pool, we do nothing */ void ReleaseObserver(ICDStateObserver * observer); - /** - * @brief Associates the ObserverEventType parameters to the correct - * ICDStateObservers function and calls it for all observers in the mStateObserverPool - */ - void postObserverEvent(ObserverEventType event); - OperationalState GetOperationalState() { return mOperationalState; } - /** * @brief Ensures that the remaining Active Mode duration is at least the smaller of 30000 milliseconds and stayActiveDuration. * - * @param stayActiveDuration The duration (in milliseconds) requested by the client to stay in Active Mode + * @param[in] stayActiveDuration The duration (in milliseconds) requested by the client to stay in Active Mode * @return The duration (in milliseconds) the device will stay in Active Mode */ uint32_t StayActiveRequest(uint32_t stayActiveDuration); @@ -132,15 +140,14 @@ class ICDManager : public ICDListener, public TestEventTriggerHandler /** * @brief TestEventTriggerHandler for the ICD feature set * - * @param eventTrigger Event trigger to handle. + * @param[in] eventTrigger Event trigger to handle. + * * @return CHIP_ERROR CHIP_NO_ERROR - No erros during the processing * CHIP_ERROR_INVALID_ARGUMENT - eventTrigger isn't a valid value */ CHIP_ERROR HandleEventTrigger(uint64_t eventTrigger) override; #if CHIP_CONFIG_ENABLE_ICD_CIP - void SendCheckInMsgs(); - /** * @brief Trigger the ICDManager to send Check-In message if necessary * @@ -160,47 +167,106 @@ class ICDManager : public ICDListener, public TestEventTriggerHandler #if CONFIG_BUILD_FOR_HOST_UNIT_TEST void SetTestFeatureMapValue(uint32_t featureMap) { mFeatureMap = featureMap; }; -#if !CHIP_CONFIG_SUBSCRIPTION_TIMEOUT_RESUMPTION && CHIP_CONFIG_PERSIST_SUBSCRIPTIONS +#if CHIP_CONFIG_PERSIST_SUBSCRIPTIONS && !CHIP_CONFIG_SUBSCRIPTION_TIMEOUT_RESUMPTION bool GetIsBootUpResumeSubscriptionExecuted() { return mIsBootUpResumeSubscriptionExecuted; }; #endif // !CHIP_CONFIG_SUBSCRIPTION_TIMEOUT_RESUMPTION && CHIP_CONFIG_PERSIST_SUBSCRIPTIONS #endif // Implementation of ICDListener functions. // Callers must origin from the chip task context or hold the ChipStack lock. + void OnNetworkActivity() override; void OnKeepActiveRequest(KeepActiveFlags request) override; void OnActiveRequestWithdrawal(KeepActiveFlags request) override; void OnICDManagementServerEvent(ICDManagementEvents event) override; void OnSubscriptionReport() override; -protected: +private: friend class TestICDManager; + /** + * @brief UpdateICDMode checks in which ICDMode (SIT or LIT) the ICD can go to and updates the mode if necessary. + * For a SIT ICD, the function does nothing. + * For a LIT ICD, the function checks if the ICD has a registration in the ICDMonitoringTable to determine in which + * ICDMode the ICD must be in. + */ + void UpdateICDMode(); + + /** + * @brief UpdateOperationState updates the OperationState of the ICD to the requested one. + * IdleMode -> IdleMode : No actions are necessary, do nothing. + * IdleMode -> ActiveMode : Transition the device to ActiveMode, start the ActiveMode timer and triggers all necessary + * operations. These operations could be : Send Check-In messages + * Send subscription reports + * Process user actions + * ActiveMode -> ActiveMode : Increase remaining ActiveMode timer to one ActiveModeThreshold. + * If ActiveModeThreshold is 0, do nothing. + * ActiveMode -> IdleMode : Transition ICD to IdleMode and starts the IdleMode timer. + * + * @param state requested OperationalState for the ICD to transition to + */ + void UpdateOperationState(OperationalState state); + + /** + * @brief Set or Remove a keep ActiveMode requirement for the given flag + * If state is true and the ICD is in IdleMode, transition the ICD to ActiveMode + * If state is false and the ICD is in ActiveMode, verifies if we can transition the ICD to IdleMode. + * If we can, transition the ICD to IdleMode. + * + * @param flag KeepActiveFlag to remove or add + * @param state true: adding a flag requirement + * false: removing a flag requirement + */ + void SetKeepActiveModeRequirements(KeepActiveFlags flag, bool state); + + /** + * @brief Associates the ObserverEventType parameters to the correct + * ICDStateObservers function and calls it for all observers in the mStateObserverPool + */ + void postObserverEvent(ObserverEventType event); /** - * @brief Hepler function that extends the Active Mode duration as well as the Active Mode Jitter timer for the transition to - * iddle mode. + * @brief Hepler function that extends the ActiveMode timer as well as the Active Mode Jitter timer for the transition to + * idle mode event. */ void ExtendActiveMode(System::Clock::Milliseconds16 extendDuration); + /** + * @brief Timer callback function for when the IdleMode timer expires + * + * @param appState pointer to the ICDManager + */ static void OnIdleModeDone(System::Layer * aLayer, void * appState); + + /** + * @brief Timer callback function for when the ActiveMode timer expires + * + * @param appState pointer to the ICDManager + */ static void OnActiveModeDone(System::Layer * aLayer, void * appState); /** - * @brief Callback function called shortly before the device enters idle mode to allow checks to be made. This is currently only - * called once to prevent entering in a loop if some events re-trigger this check (for instance if a check for subscription - * before entering idle mode leads to emiting a report, we will re-enter UpdateOperationState and check again for subscription, - * etc.) + * @brief Timer Callback function called shortly before the device enters idle mode to allow checks to be made. + * This is currently only called once to prevent entering in a loop if some events re-trigger this check (for instance if + * a check for subscriptions before entering idle mode leads to emiting a report, we will re-enter UpdateOperationState + * and check again for subscription, etc.) + * + * @param appState pointer to the ICDManager */ static void OnTransitionToIdle(System::Layer * aLayer, void * appState); #if CHIP_CONFIG_ENABLE_ICD_CIP - uint8_t mCheckInRequestCount = 0; -#endif // CHIP_CONFIG_ENABLE_ICD_CIP - - uint8_t mOpenExchangeContextCount = 0; + /** + * @brief Function triggers all necessary Check-In messages to be sent. + * + * @note For each ICDMonitoring entry, we check if should send a Check-In message with + * ShouldCheckInMsgsBeSentAtActiveModeFunction. If we should, we allocate an ICDCheckInSender which tries to send a + * Check-In message to the registered client. + */ + void SendCheckInMsgs(); -private: -#if CHIP_CONFIG_ENABLE_ICD_CIP + /** + * @brief See function implementation in .cpp for details on this function. + */ bool ShouldCheckInMsgsBeSentAtActiveModeFunction(FabricIndex aFabricIndex, NodeId subjectID); /** @@ -221,11 +287,15 @@ class ICDManager : public ICDListener, public TestEventTriggerHandler OperationalState mOperationalState = OperationalState::ActiveMode; bool mTransitionToIdleCalled = false; ObjectPool mStateObserverPool; + uint8_t mOpenExchangeContextCount = 0; #if CHIP_CONFIG_ENABLE_ICD_CIP + uint8_t mCheckInRequestCount = 0; + #if !CHIP_CONFIG_SUBSCRIPTION_TIMEOUT_RESUMPTION && CHIP_CONFIG_PERSIST_SUBSCRIPTIONS bool mIsBootUpResumeSubscriptionExecuted = false; #endif // !CHIP_CONFIG_SUBSCRIPTION_TIMEOUT_RESUMPTION && CHIP_CONFIG_PERSIST_SUBSCRIPTIONS + PersistentStorageDelegate * mStorage = nullptr; FabricTable * mFabricTable = nullptr; Messaging::ExchangeManager * mExchangeManager = nullptr; diff --git a/src/app/icd/server/ICDStateObserver.h b/src/app/icd/server/ICDStateObserver.h index 996dad0ec6608b..1e7474032f55bc 100644 --- a/src/app/icd/server/ICDStateObserver.h +++ b/src/app/icd/server/ICDStateObserver.h @@ -27,13 +27,43 @@ namespace chip { namespace app { +/** + * @brief Public API used my the ICDManager to expose when different events occurs. + * ICDManager::RegisterObserver can be used to register as an Observer to be notified when these events occurs. + * These functions are called synchronously. + */ class ICDStateObserver { public: virtual ~ICDStateObserver() {} - virtual void OnEnterActiveMode() = 0; + + /** + * @brief API called when the ICD enters ActiveMode. API isn't called if we need to extend the remaining active mode timer + * duration. API is called after the ICDManager has finished executing its internal actions. + */ + virtual void OnEnterActiveMode() = 0; + + /** + * @brief API called when the ICD enters IdleMode. + * API is called after the ICDManager has finished executing its internal actions. + */ + virtual void OnEnterIdleMode() = 0; + + /** + * @brief API is called when the ICD is about to enter IdleMode. API is called when there is `ICD_ACTIVE_TIME_JITTER_MS` of time + * remaining to the active mode timer. + * This API is only called once per transition from ActiveMode to IdleMode. + * If OnTransitionToIdle triggers the active mode timer to increase, the next time we are about to enter IdleMode, + * this API will not be called. + */ virtual void OnTransitionToIdle() = 0; - virtual void OnICDModeChange() = 0; + + /** + * @brief API is called when the ICD changes operating mode. This API is only called if the ICD changes state, not when it + * remains in the same state. + * API is called after the ICDManager has finished executing its internal actions. + */ + virtual void OnICDModeChange() = 0; }; } // namespace app diff --git a/src/app/reporting/ReportSchedulerImpl.h b/src/app/reporting/ReportSchedulerImpl.h index 38fcc2ae1bf941..f7889a5ac3e6c7 100644 --- a/src/app/reporting/ReportSchedulerImpl.h +++ b/src/app/reporting/ReportSchedulerImpl.h @@ -89,6 +89,12 @@ class ReportSchedulerImpl : public ReportScheduler */ void OnICDModeChange() override{}; + /** + * @brief This implementation does not attempt any synchronization on this ICD event, therefore no action is needed on + * ICDEnterIdleMode() + */ + void OnEnterIdleMode() override{}; + // ReadHandlerObserver /** diff --git a/src/app/server/Dnssd.h b/src/app/server/Dnssd.h index e669f4d0860a50..105318ca5a08be 100644 --- a/src/app/server/Dnssd.h +++ b/src/app/server/Dnssd.h @@ -126,11 +126,25 @@ class DLL_EXPORT DnssdServer : public ICDStateObserver */ CHIP_ERROR SetEphemeralDiscriminator(Optional discriminator); - // ICDStateObserver - // No action is needed by the DnssdServer on active or idle state entries + /** + * @brief When the ICD changes operating mode, the dnssd server needs to restart its DNS-SD advertising to update the TXT keys. + */ + void OnICDModeChange() override; + + /** + * @brief dnssd server has no action to do on this ICD event. Do nothing. + */ void OnEnterActiveMode() override{}; + + /** + * @brief dnssd server has no action to do on this ICD event. Do nothing. + */ void OnTransitionToIdle() override{}; - void OnICDModeChange() override; + + /** + * @brief dnssd server has no action to do on this ICD event. Do nothing. + */ + void OnEnterIdleMode() override{}; private: /// Overloaded utility method for commissioner and commissionable advertisement diff --git a/src/app/tests/TestICDManager.cpp b/src/app/tests/TestICDManager.cpp index fd93a146cf2755..6e814ebb01f579 100644 --- a/src/app/tests/TestICDManager.cpp +++ b/src/app/tests/TestICDManager.cpp @@ -77,9 +77,27 @@ enum class ICDTestEventTriggerEvent : uint64_t class TestICDStateObserver : public app::ICDStateObserver { public: - void OnEnterActiveMode() {} - void OnTransitionToIdle() {} - void OnICDModeChange() {} + void OnEnterActiveMode() { mOnEnterActiveModeCalled = true; } + void OnEnterIdleMode() { mOnEnterIdleModeCalled = true; } + void OnTransitionToIdle() { mOnTransitionToIdleCalled = true; } + void OnICDModeChange() { mOnICDModeChangeCalled = true; } + + void ResetOnEnterActiveMode() { mOnEnterActiveModeCalled = false; } + void ResetOnEnterIdleMode() { mOnEnterIdleModeCalled = false; } + void ResetOnTransitionToIdle() { mOnTransitionToIdleCalled = false; } + void ResetOnICDModeChange() { mOnICDModeChangeCalled = false; } + void ResetAll() + { + ResetOnEnterActiveMode(); + ResetOnEnterIdleMode(); + ResetOnTransitionToIdle(); + ResetOnICDModeChange(); + } + + bool mOnEnterActiveModeCalled = false; + bool mOnEnterIdleModeCalled = false; + bool mOnICDModeChangeCalled = false; + bool mOnTransitionToIdleCalled = false; }; class TestSubscriptionsInfoProvider : public SubscriptionsInfoProvider @@ -123,10 +141,10 @@ class TestContext : public chip::Test::AppContext // Performs setup for each individual test in the test suite CHIP_ERROR SetUp() override { - ReturnErrorOnFailure(chip::Test::AppContext::SetUp()); - mICDManager.Init(&testStorage, &GetFabricTable(), &mKeystore, &GetExchangeManager(), &mSubInfoProvider); + mICDStateObserver.ResetAll(); mICDManager.RegisterObserver(&mICDStateObserver); + mICDManager.Init(&testStorage, &GetFabricTable(), &mKeystore, &GetExchangeManager(), &mSubInfoProvider); return CHIP_NO_ERROR; } @@ -196,7 +214,7 @@ class TestICDManager /** * @brief Test verifies that the ICDManager starts its timers correctly based on if it will have any messages to send - * when the IdleModeDuration expires + * when the IdleMode timer expires */ static void TestICDModeDurationsWith0ActiveModeDurationWithoutActiveSub(nlTestSuite * aSuite, void * aContext) { @@ -254,7 +272,7 @@ class TestICDManager AdvanceClockAndRunEventLoop(ctx, icdConfigData.GetActiveModeThreshold() + 1_ms16); NL_TEST_ASSERT(aSuite, ctx->mICDManager.mOperationalState == ICDManager::OperationalState::IdleMode); - // Expire IdleModeDuration - Device should be in ActiveMode since it has an ICDM registration + // Expire IdleMode timer - Device should be in ActiveMode since it has an ICDM registration AdvanceClockAndRunEventLoop(ctx, icdConfigData.GetIdleModeDuration() + 1_s); NL_TEST_ASSERT(aSuite, ctx->mICDManager.mOperationalState == ICDManager::OperationalState::ActiveMode); @@ -276,7 +294,7 @@ class TestICDManager /** * @brief Test verifies that the ICDManager remains in IdleMode since it will not have any messages to send - * when the IdleModeDuration expires + * when the IdleMode timer expires */ static void TestICDModeDurationsWith0ActiveModeDurationWithActiveSub(nlTestSuite * aSuite, void * aContext) { @@ -334,7 +352,7 @@ class TestICDManager AdvanceClockAndRunEventLoop(ctx, icdConfigData.GetActiveModeThreshold() + 1_ms16); NL_TEST_ASSERT(aSuite, ctx->mICDManager.mOperationalState == ICDManager::OperationalState::IdleMode); - // Expire IdleModeDuration - Device stay in IdleMode since it has an active subscription for the ICDM entry + // Expire IdleMode timer - Device stay in IdleMode since it has an active subscription for the ICDM entry AdvanceClockAndRunEventLoop(ctx, icdConfigData.GetIdleModeDuration() + 1_s); NL_TEST_ASSERT(aSuite, ctx->mICDManager.mOperationalState == ICDManager::OperationalState::IdleMode); @@ -414,9 +432,9 @@ class TestICDManager NL_TEST_ASSERT(aSuite, ctx->mICDManager.mOperationalState == ICDManager::OperationalState::IdleMode); } - /* - * Test that verifies that the ICDManager is the correct operating mode based on entries - * in the ICDMonitoringTable + /** + * @brief Test that verifies that the ICDManager is in the correct operating mode based on entries + * in the ICDMonitoringTable */ static void TestICDMRegisterUnregisterEvents(nlTestSuite * aSuite, void * aContext) { @@ -554,7 +572,9 @@ class TestICDManager NL_TEST_ASSERT(aSuite, ctx->mICDManager.mOperationalState == ICDManager::OperationalState::IdleMode); } - /* Test that verifies the logic of the ICDManager when it receives a StayActiveRequest*/ + /** + * @brief Test verifies the logic of the ICDManager when it receives a StayActiveRequest + */ static void TestICDMStayActive(nlTestSuite * aSuite, void * aContext) { TestContext * ctx = static_cast(aContext); @@ -568,7 +588,7 @@ class TestICDManager notifier.NotifySubscriptionReport(); NL_TEST_ASSERT(aSuite, ctx->mICDManager.mOperationalState == ICDManager::OperationalState::ActiveMode); - // Advance time by the ActiveModeDuration - 1 + // Advance time just before ActiveMode timer expires AdvanceClockAndRunEventLoop(ctx, icdConfigData.GetActiveModeDuration() - 1_ms32); // Confirm ICD manager is in active mode NL_TEST_ASSERT(aSuite, ctx->mICDManager.mOperationalState == ICDManager::OperationalState::ActiveMode); @@ -580,7 +600,7 @@ class TestICDManager NL_TEST_ASSERT(aSuite, stayActivePromisedMs == stayActiveRequestedMs); // Advance time by the duration of the stay stayActiveRequestedMs - 1 ms - AdvanceClockAndRunEventLoop(ctx, System::Clock::Milliseconds32(stayActiveRequestedMs) - 1_ms32); + AdvanceClockAndRunEventLoop(ctx, Milliseconds32(stayActiveRequestedMs) - 1_ms32); // Confirm ICD manager is in active mode NL_TEST_ASSERT(aSuite, ctx->mICDManager.mOperationalState == ICDManager::OperationalState::ActiveMode); @@ -601,7 +621,7 @@ class TestICDManager NL_TEST_ASSERT(aSuite, stayActivePromisedMs == 30000); // Advance time by the duration of the max stay active duration - 1 ms - AdvanceClockAndRunEventLoop(ctx, System::Clock::Milliseconds32(30000) - 1_ms32); + AdvanceClockAndRunEventLoop(ctx, Milliseconds32(30000) - 1_ms32); NL_TEST_ASSERT(aSuite, ctx->mICDManager.mOperationalState == ICDManager::OperationalState::ActiveMode); // Advance time by 1ms and Confirm ICD manager is in idle mode @@ -621,7 +641,7 @@ class TestICDManager NL_TEST_ASSERT(aSuite, stayActivePromisedMs == 30000); // Advance time by the duration of the stay active request - 20000 ms - AdvanceClockAndRunEventLoop(ctx, System::Clock::Milliseconds32(stayActiveRequestedMs) - 20000_ms32); + AdvanceClockAndRunEventLoop(ctx, Milliseconds32(stayActiveRequestedMs) - 20000_ms32); // Confirm ICD manager is in active mode, we should have 20000 seconds left at that point NL_TEST_ASSERT(aSuite, ctx->mICDManager.mOperationalState == ICDManager::OperationalState::ActiveMode); @@ -721,6 +741,329 @@ class TestICDManager ctx->mICDManager.HandleEventTrigger(static_cast(ICDTestEventTriggerEvent::kRemoveActiveModeReq)); NL_TEST_ASSERT(aSuite, ctx->mICDManager.mOperationalState == ICDManager::OperationalState::IdleMode); } + + /** + * @brief Test verifies when OnEnterIdleMode is called during normal operations. + * Without the ActiveMode timer being extended + */ + static void TestICDStateObserverOnEnterIdleModeActiveModeDuration(nlTestSuite * aSuite, void * aContext) + { + TestContext * ctx = static_cast(aContext); + + // Verify that ICDManager starts in IdleMode and calls OnEnterIdleMode + NL_TEST_ASSERT(aSuite, ctx->mICDStateObserver.mOnEnterIdleModeCalled); + ctx->mICDStateObserver.ResetOnEnterIdleMode(); + + // Advance clock just before IdleMode timer expires + AdvanceClockAndRunEventLoop(ctx, ICDConfigurationData::GetInstance().GetIdleModeDuration() - 1_s); + NL_TEST_ASSERT(aSuite, !ctx->mICDStateObserver.mOnEnterIdleModeCalled); + + // Expire IdleModeInterval + AdvanceClockAndRunEventLoop(ctx, 1_s); + NL_TEST_ASSERT(aSuite, !ctx->mICDStateObserver.mOnEnterIdleModeCalled); + + // Advance clock Just before ActiveMode timer expires + AdvanceClockAndRunEventLoop(ctx, ICDConfigurationData::GetInstance().GetActiveModeDuration() - 1_ms32); + NL_TEST_ASSERT(aSuite, !ctx->mICDStateObserver.mOnEnterIdleModeCalled); + + // Expire ActiveMode timer + AdvanceClockAndRunEventLoop(ctx, 1_ms32); + NL_TEST_ASSERT(aSuite, ctx->mICDStateObserver.mOnEnterIdleModeCalled); + } + + /** + * @brief Test verifies when OnEnterIdleMode is called with the ActiveMode timer gets extended + */ + static void TestICDStateObserverOnEnterIdleModeActiveModeThreshold(nlTestSuite * aSuite, void * aContext) + { + TestContext * ctx = static_cast(aContext); + + // Verify that ICDManager starts in IdleMode and calls OnEnterIdleMode + NL_TEST_ASSERT(aSuite, ctx->mICDStateObserver.mOnEnterIdleModeCalled); + ctx->mICDStateObserver.ResetOnEnterIdleMode(); + + // Advance clock just before the IdleMode timer expires + AdvanceClockAndRunEventLoop(ctx, ICDConfigurationData::GetInstance().GetIdleModeDuration() - 1_s); + NL_TEST_ASSERT(aSuite, !ctx->mICDStateObserver.mOnEnterIdleModeCalled); + + // Expire IdleMode timer + AdvanceClockAndRunEventLoop(ctx, 1_s); + NL_TEST_ASSERT(aSuite, !ctx->mICDStateObserver.mOnEnterIdleModeCalled); + + // Advance clock Just before ActiveMode timer expires + AdvanceClockAndRunEventLoop(ctx, ICDConfigurationData::GetInstance().GetActiveModeDuration() - 1_ms32); + NL_TEST_ASSERT(aSuite, !ctx->mICDStateObserver.mOnEnterIdleModeCalled); + + // Increase ActiveMode timer by one ActiveModeThreshold + ICDNotifier::GetInstance().NotifyNetworkActivityNotification(); + NL_TEST_ASSERT(aSuite, !ctx->mICDStateObserver.mOnEnterIdleModeCalled); + + // Advance clock Just before ActiveMode timer expires + AdvanceClockAndRunEventLoop(ctx, ICDConfigurationData::GetInstance().GetActiveModeThreshold() - 1_ms32); + NL_TEST_ASSERT(aSuite, !ctx->mICDStateObserver.mOnEnterIdleModeCalled); + + // Expire ActiveMode timer + AdvanceClockAndRunEventLoop(ctx, 1_ms32); + NL_TEST_ASSERT(aSuite, ctx->mICDStateObserver.mOnEnterIdleModeCalled); + } + + static void TestICDStateObserverOnEnterActiveMode(nlTestSuite * aSuite, void * aContext) + { + TestContext * ctx = static_cast(aContext); + + // Verify OnEnterActiveMode wasn't called at Init + NL_TEST_ASSERT(aSuite, !(ctx->mICDStateObserver.mOnEnterActiveModeCalled)); + + // Advance clock just before IdleMode timer expires + AdvanceClockAndRunEventLoop(ctx, ICDConfigurationData::GetInstance().GetIdleModeDuration() - 1_s); + NL_TEST_ASSERT(aSuite, !(ctx->mICDStateObserver.mOnEnterActiveModeCalled)); + + // Expire IdleMode timer and check wether OnEnterActiveMode was called + AdvanceClockAndRunEventLoop(ctx, 1_s); + NL_TEST_ASSERT(aSuite, ctx->mICDStateObserver.mOnEnterActiveModeCalled); + ctx->mICDStateObserver.ResetOnEnterActiveMode(); + + // Advance clock just before the ActiveMode timer expires + AdvanceClockAndRunEventLoop(ctx, ICDConfigurationData::GetInstance().GetActiveModeDuration() - 1_ms32); + + // Verify OnEnterActiveMde wasn't called + NL_TEST_ASSERT(aSuite, !(ctx->mICDStateObserver.mOnEnterActiveModeCalled)); + + // Increase ActiveMode timer by one ActiveModeThreshold + ICDNotifier::GetInstance().NotifyNetworkActivityNotification(); + + // Verify OnEnterActiveMde wasn't called + NL_TEST_ASSERT(aSuite, !(ctx->mICDStateObserver.mOnEnterActiveModeCalled)); + + // Advance clock just before ActiveMode timer expires + AdvanceClockAndRunEventLoop(ctx, ICDConfigurationData::GetInstance().GetActiveModeThreshold() - 1_ms32); + + // Verify OnEnterActiveMde wasn't called + NL_TEST_ASSERT(aSuite, !(ctx->mICDStateObserver.mOnEnterActiveModeCalled)); + + // Expire ActiveMode timer + AdvanceClockAndRunEventLoop(ctx, 1_ms32); + + // Verify OnEnterActiveMde wasn't called + NL_TEST_ASSERT(aSuite, !(ctx->mICDStateObserver.mOnEnterActiveModeCalled)); + + // Advance clock just before IdleMode timer expires + AdvanceClockAndRunEventLoop(ctx, ICDConfigurationData::GetInstance().GetIdleModeDuration() - 1_s); + NL_TEST_ASSERT(aSuite, !(ctx->mICDStateObserver.mOnEnterActiveModeCalled)); + + // Expire IdleMode timer and check OnEnterActiveMode was called + AdvanceClockAndRunEventLoop(ctx, 1_s); + NL_TEST_ASSERT(aSuite, ctx->mICDStateObserver.mOnEnterActiveModeCalled); + } + + static void TestICDStateObserverOnICDModeChange(nlTestSuite * aSuite, void * aContext) + { + TestContext * ctx = static_cast(aContext); + typedef ICDListener::ICDManagementEvents ICDMEvent; + + // Since we don't have a registration, we stay in SIT mode. No changes + NL_TEST_ASSERT(aSuite, !(ctx->mICDStateObserver.mOnICDModeChangeCalled)); + + // Trigger register event to force ICDManager to re-evaluate OperatingMode + ICDNotifier::GetInstance().NotifyICDManagementEvent(ICDMEvent::kTableUpdated); + + // Since we don't have a registration, we stay in SIT mode. No changes + NL_TEST_ASSERT(aSuite, !(ctx->mICDStateObserver.mOnICDModeChangeCalled)); + + // Add an entry to the ICDMonitoringTable + ICDMonitoringTable table(ctx->testStorage, kTestFabricIndex1, kMaxTestClients, &(ctx->mKeystore)); + + ICDMonitoringEntry entry(&(ctx->mKeystore)); + entry.checkInNodeID = kClientNodeId11; + entry.monitoredSubject = kClientNodeId11; + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == entry.SetKey(ByteSpan(kKeyBuffer1a))); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == table.Set(0, entry)); + + // Trigger register event after first entry was added + ICDNotifier::GetInstance().NotifyICDManagementEvent(ICDMEvent::kTableUpdated); + + // We have a registration. Transition to LIT mode + NL_TEST_ASSERT(aSuite, ctx->mICDStateObserver.mOnICDModeChangeCalled); + ctx->mICDStateObserver.ResetOnICDModeChange(); + + // Trigger register event to force ICDManager to re-evaluate OperatingMode + ICDNotifier::GetInstance().NotifyICDManagementEvent(ICDMEvent::kTableUpdated); + + // We have a registration. We stay in LIT mode. No changes. + NL_TEST_ASSERT(aSuite, !(ctx->mICDStateObserver.mOnICDModeChangeCalled)); + + // Remove entry from the ICDMonitoringTable + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == table.Remove(0)); + ICDNotifier::GetInstance().NotifyICDManagementEvent(ICDMEvent::kTableUpdated); + + // Since we don't have a registration anymore. Transition to SIT mode. + NL_TEST_ASSERT(aSuite, ctx->mICDStateObserver.mOnICDModeChangeCalled); + ctx->mICDStateObserver.ResetOnICDModeChange(); + } + + static void TestICDStateObserverOnICDModeChangeOnInit(nlTestSuite * aSuite, void * aContext) + { + TestContext * ctx = static_cast(aContext); + + ICDMonitoringTable table(ctx->testStorage, kTestFabricIndex1, kMaxTestClients, &(ctx->mKeystore)); + + // Since we don't have a registration, we stay in SIT mode. No changes + NL_TEST_ASSERT(aSuite, !(ctx->mICDStateObserver.mOnICDModeChangeCalled)); + + // Add an entry to the ICDMonitoringTable + ICDMonitoringEntry entry(&(ctx->mKeystore)); + entry.checkInNodeID = kClientNodeId11; + entry.monitoredSubject = kClientNodeId11; + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == entry.SetKey(ByteSpan(kKeyBuffer1a))); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == table.Set(0, entry)); + + // Shut down and reinit ICDManager - We should go to LIT mode since we have a registration + ctx->mICDManager.Shutdown(); + ctx->mICDManager.RegisterObserver(&(ctx->mICDStateObserver)); + ctx->mICDManager.Init(&(ctx->testStorage), &(ctx->GetFabricTable()), &(ctx->mKeystore), &(ctx->GetExchangeManager()), + &(ctx->mSubInfoProvider)); + + // We have a registration, transition to LIT mode + NL_TEST_ASSERT(aSuite, ctx->mICDStateObserver.mOnICDModeChangeCalled); + ctx->mICDStateObserver.ResetOnICDModeChange(); + + // Remove entry from the ICDMonitoringTable + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == table.Remove(0)); + } + + /** + * @brief Test verifies the OnTransitionToIdleMode event when the ActiveModeDuration is greater than the + * ICD_ACTIVE_TIME_JITTER_MS + */ + static void TestICDStateObserverOnTransitionToIdleModeGreaterActiveModeDuration(nlTestSuite * aSuite, void * aContext) + { + TestContext * ctx = static_cast(aContext); + + // Set New durations for test case - ActiveModeDuration must be longuer than ICD_ACTIVE_TIME_JITTER_MS + Milliseconds32 oldActiveModeDuration = ICDConfigurationData::GetInstance().GetActiveModeDuration(); + ICDConfigurationData::GetInstance().SetModeDurations( + MakeOptional(Milliseconds32(200) + Milliseconds32(ICD_ACTIVE_TIME_JITTER_MS)), NullOptional); + + // Advance clock just before IdleMode timer expires + AdvanceClockAndRunEventLoop(ctx, ICDConfigurationData::GetInstance().GetIdleModeDuration() - 1_s); + NL_TEST_ASSERT(aSuite, !(ctx->mICDStateObserver.mOnTransitionToIdleCalled)); + + // Expire IdleMode timer + AdvanceClockAndRunEventLoop(ctx, 1_s); + NL_TEST_ASSERT(aSuite, !(ctx->mICDStateObserver.mOnTransitionToIdleCalled)); + + // Advance time just before OnTransitionToIdleMode is called + AdvanceClockAndRunEventLoop( + ctx, ICDConfigurationData::GetInstance().GetActiveModeDuration() - Milliseconds32(ICD_ACTIVE_TIME_JITTER_MS) - 1_ms32); + + // Check mOnTransitionToIdleCalled has not been called + NL_TEST_ASSERT(aSuite, !(ctx->mICDStateObserver.mOnTransitionToIdleCalled)); + + // Increase ActiveMode timer by one ActiveModeThreshold + ICDNotifier::GetInstance().NotifyNetworkActivityNotification(); + NL_TEST_ASSERT(aSuite, !(ctx->mICDStateObserver.mOnTransitionToIdleCalled)); + + // Advance time just before OnTransitionToIdleMode is called + AdvanceClockAndRunEventLoop( + ctx, ICDConfigurationData::GetInstance().GetActiveModeThreshold() - Milliseconds32(ICD_ACTIVE_TIME_JITTER_MS) - 1_ms32); + NL_TEST_ASSERT(aSuite, !(ctx->mICDStateObserver.mOnTransitionToIdleCalled)); + + // Expire OnTransitionToIdleMode + AdvanceClockAndRunEventLoop(ctx, 1_ms32); + // Check mOnTransitionToIdleCalled has been called + NL_TEST_ASSERT(aSuite, ctx->mICDStateObserver.mOnTransitionToIdleCalled); + ctx->mICDStateObserver.ResetOnTransitionToIdle(); + + // Expire ActiveMode timer + AdvanceClockAndRunEventLoop(ctx, Milliseconds32(ICD_ACTIVE_TIME_JITTER_MS)); + NL_TEST_ASSERT(aSuite, !(ctx->mICDStateObserver.mOnTransitionToIdleCalled)); + + // Reset Old durations + ICDConfigurationData::GetInstance().SetModeDurations(MakeOptional(oldActiveModeDuration), NullOptional); + } + + /** + * @brief Test verifies the OnTransitionToIdleMode event when the ActiveModeDuration is equal to the + * ICD_ACTIVE_TIME_JITTER_MS. + */ + static void TestICDStateObserverOnTransitionToIdleModeEqualActiveModeDuration(nlTestSuite * aSuite, void * aContext) + { + TestContext * ctx = static_cast(aContext); + + // Set New durations for test case - ActiveModeDuration must be equal to ICD_ACTIVE_TIME_JITTER_MS + Milliseconds32 oldActiveModeDuration = ICDConfigurationData::GetInstance().GetActiveModeDuration(); + ICDConfigurationData::GetInstance().SetModeDurations( + MakeOptional(Milliseconds32(ICD_ACTIVE_TIME_JITTER_MS)), NullOptional); + + // Advance clock just before IdleMode timer expires + AdvanceClockAndRunEventLoop(ctx, ICDConfigurationData::GetInstance().GetIdleModeDuration() - 1_s); + NL_TEST_ASSERT(aSuite, !(ctx->mICDStateObserver.mOnTransitionToIdleCalled)); + + // Expire IdleMode timer + AdvanceClockAndRunEventLoop(ctx, 1_s); + NL_TEST_ASSERT(aSuite, !(ctx->mICDStateObserver.mOnTransitionToIdleCalled)); + + // Expire OnTransitionToIdleMode + AdvanceClockAndRunEventLoop(ctx, 1_ms32); + NL_TEST_ASSERT(aSuite, ctx->mICDStateObserver.mOnTransitionToIdleCalled); + + // Reset Old durations + ICDConfigurationData::GetInstance().SetModeDurations(MakeOptional(oldActiveModeDuration), NullOptional); + } + + /** + * @brief Test verifies the OnTransitionToIdleMode event when the ActiveModeDuration is 0 and without an ActiveMode req + */ + static void TestICDStateObserverOnTransitionToIdleMode0ActiveModeDurationWithoutReq(nlTestSuite * aSuite, void * aContext) + { + TestContext * ctx = static_cast(aContext); + + // Set New durations for test case - ActiveModeDuration equal 0 + Milliseconds32 oldActiveModeDuration = ICDConfigurationData::GetInstance().GetActiveModeDuration(); + ICDConfigurationData::GetInstance().SetModeDurations(MakeOptional(0), NullOptional); + + // Advance clock just before IdleMode timer expires + AdvanceClockAndRunEventLoop(ctx, ICDConfigurationData::GetInstance().GetIdleModeDuration() - 1_s); + NL_TEST_ASSERT(aSuite, !(ctx->mICDStateObserver.mOnTransitionToIdleCalled)); + + // Expire IdleMode timer + AdvanceClockAndRunEventLoop(ctx, 1_s); + NL_TEST_ASSERT(aSuite, !(ctx->mICDStateObserver.mOnTransitionToIdleCalled)); + + // Increase time by 1 - Should not trigger OnTransitionToIdle. + // Timer length is one ActiveModeThreshold + AdvanceClockAndRunEventLoop(ctx, 1_ms32); + NL_TEST_ASSERT(aSuite, !(ctx->mICDStateObserver.mOnTransitionToIdleCalled)); + + // Expire ActiveModeThreshold + AdvanceClockAndRunEventLoop(ctx, ICDConfigurationData::GetInstance().GetActiveModeThreshold()); + NL_TEST_ASSERT(aSuite, ctx->mICDStateObserver.mOnTransitionToIdleCalled); + + // Reset Old durations + ICDConfigurationData::GetInstance().SetModeDurations(MakeOptional(oldActiveModeDuration), NullOptional); + } + + /** + * @brief Test verifies the OnTransitionToIdleMode event when the ActiveModeDuration is 0 with an ActiveMode req + */ + static void TestICDStateObserverOnTransitionToIdleMode0ActiveModeDurationWittReq(nlTestSuite * aSuite, void * aContext) + { + TestContext * ctx = static_cast(aContext); + + // Set New durations for test case - ActiveModeDuration equal 0 + Milliseconds32 oldActiveModeDuration = ICDConfigurationData::GetInstance().GetActiveModeDuration(); + ICDConfigurationData::GetInstance().SetModeDurations(MakeOptional(0), NullOptional); + + // Add ActiveMode req for the Test event trigger event + ctx->mICDManager.HandleEventTrigger(static_cast(ICDTestEventTriggerEvent::kAddActiveModeReq)); + + // Expire IdleMode timer + AdvanceClockAndRunEventLoop(ctx, ICDConfigurationData::GetInstance().GetIdleModeDuration()); + NL_TEST_ASSERT(aSuite, !(ctx->mICDStateObserver.mOnTransitionToIdleCalled)); + + // Reset Old durations + ICDConfigurationData::GetInstance().SetModeDurations(MakeOptional(oldActiveModeDuration), NullOptional); + } }; } // namespace app @@ -740,6 +1083,22 @@ static const nlTest sTests[] = { NL_TEST_DEF("TestICDStayActive", TestICDManager::TestICDMStayActive), NL_TEST_DEF("TestShouldCheckInMsgsBeSentAtActiveModeFunction", TestICDManager::TestShouldCheckInMsgsBeSentAtActiveModeFunction), NL_TEST_DEF("TestHandleTestEventTriggerActiveModeReq", TestICDManager::TestHandleTestEventTriggerActiveModeReq), + NL_TEST_DEF("TestICDStateObserverOnEnterIdleModeActiveModeDuration", + TestICDManager::TestICDStateObserverOnEnterIdleModeActiveModeDuration), + NL_TEST_DEF("TestICDStateObserverOnEnterIdleModeActiveModeThreshold", + TestICDManager::TestICDStateObserverOnEnterIdleModeActiveModeThreshold), + NL_TEST_DEF("TestICDStateObserverOnEnterActiveMode", TestICDManager::TestICDStateObserverOnEnterActiveMode), + NL_TEST_DEF("TestICDStateObserverOnICDModeChange", TestICDManager::TestICDStateObserverOnICDModeChange), + NL_TEST_DEF("TestICDStateObserverOnICDModeChangeOnInit", TestICDManager::TestICDStateObserverOnICDModeChangeOnInit), + NL_TEST_DEF("TestICDStateObserverOnTransitionToIdleModeGreaterActiveModeDuration", + TestICDManager::TestICDStateObserverOnTransitionToIdleModeGreaterActiveModeDuration), + NL_TEST_DEF("TestICDStateObserverOnTransitionToIdleModeEqualActiveModeDuration", + TestICDManager::TestICDStateObserverOnTransitionToIdleModeEqualActiveModeDuration), + NL_TEST_DEF("TestICDStateObserverOnTransitionToIdleMode0ActiveModeDurationWithoutReq", + TestICDManager::TestICDStateObserverOnTransitionToIdleMode0ActiveModeDurationWithoutReq), + // TODO(#33074): When the OnTransitionToIdle edge is fixed, we can enable this test + // NL_TEST_DEF("TestICDStateObserverOnTransitionToIdleMode0ActiveModeDurationWittReq", + // TestICDManager::TestICDStateObserverOnTransitionToIdleMode0ActiveModeDurationWittReq), NL_TEST_SENTINEL(), }; diff --git a/src/messaging/ExchangeContext.cpp b/src/messaging/ExchangeContext.cpp index 74a861c1170b7f..3869ab4c48c921 100644 --- a/src/messaging/ExchangeContext.cpp +++ b/src/messaging/ExchangeContext.cpp @@ -322,6 +322,7 @@ ExchangeContext::ExchangeContext(ExchangeManager * em, uint16_t ExchangeId, cons SetAutoRequestAck(session->AllowsMRP()); #if CHIP_CONFIG_ENABLE_ICD_SERVER + // TODO(#33075) : Add check for group context to not a req since it serves no purpose app::ICDNotifier::GetInstance().NotifyActiveRequestNotification(app::ICDListener::KeepActiveFlag::kExchangeContextOpen); #endif @@ -341,6 +342,7 @@ ExchangeContext::~ExchangeContext() VerifyOrDie(mFlags.Has(Flags::kFlagClosed)); #if CHIP_CONFIG_ENABLE_ICD_SERVER + // TODO(#33075) : Add check for group context to not a req since it serves no purpose app::ICDNotifier::GetInstance().NotifyActiveRequestWithdrawal(app::ICDListener::KeepActiveFlag::kExchangeContextOpen); #endif // CHIP_CONFIG_ENABLE_ICD_SERVER