From 138472256bcef174f1e7274e7eec6af200b15e38 Mon Sep 17 00:00:00 2001 From: lpbeliveau-silabs <112982107+lpbeliveau-silabs@users.noreply.github.com> Date: Thu, 3 Aug 2023 10:26:21 -0400 Subject: [PATCH] [ReadHandler] Removal of test flags (#28421) * Removed reportScheduler test flags and made TestReadInteractin.cpp wait for min/max instead of setting flags. Modified subscription times in the test to minimise the impact of waiting. * Restyled by clang-format * Added a driveAndServiceIO after waiting for max in test where we should wait for max to expire to ensure the run gets scheduled reliably * Moved ctx.GetIOContext().DriveIO(); after each tests to garantee this will run after maxInterval is expired * Implemented a mock clock in TestReadInteraction to reduce wait loops * Removed more loops and added comment on loop left in the code --------- Co-authored-by: Restyled.io --- src/app/reporting/ReportScheduler.h | 49 +------ src/app/tests/TestReadInteraction.cpp | 203 +++++++++++--------------- 2 files changed, 89 insertions(+), 163 deletions(-) diff --git a/src/app/reporting/ReportScheduler.h b/src/app/reporting/ReportScheduler.h index fc1858862bc4bd..068237780b86a0 100644 --- a/src/app/reporting/ReportScheduler.h +++ b/src/app/reporting/ReportScheduler.h @@ -63,17 +63,6 @@ class ReportScheduler : public ReadHandler::Observer, public ICDStateObserver class ReadHandlerNode : public TimerContext { public: -#ifdef CONFIG_BUILD_FOR_HOST_UNIT_TEST - /// Test flags to allow TestReadInteraction to simulate expiration of the minimal and maximal intervals without - /// waiting - enum class TestFlags : uint8_t{ - MinIntervalElapsed = (1 << 0), - MaxIntervalElapsed = (1 << 1), - }; - void SetTestFlags(TestFlags aFlag, bool aValue) { mFlags.Set(aFlag, aValue); } - bool GetTestFlags(TestFlags aFlag) const { return mFlags.Has(aFlag); } -#endif // CONFIG_BUILD_FOR_HOST_UNIT_TEST - ReadHandlerNode(ReadHandler * aReadHandler, TimerDelegate * aTimerDelegate, ReportScheduler * aScheduler) : mTimerDelegate(aTimerDelegate), mScheduler(aScheduler) { @@ -93,29 +82,12 @@ class ReportScheduler : public ReadHandler::Observer, public ICDStateObserver { Timestamp now = mTimerDelegate->GetCurrentMonotonicTimestamp(); -#ifdef CONFIG_BUILD_FOR_HOST_UNIT_TEST - return (mReadHandler->IsGeneratingReports() && (now >= mMinTimestamp || mFlags.Has(TestFlags::MinIntervalElapsed)) && - (mReadHandler->IsDirty() || (now >= mMaxTimestamp || mFlags.Has(TestFlags::MaxIntervalElapsed)) || - now >= mSyncTimestamp)); -#else return (mReadHandler->IsGeneratingReports() && (now >= mMinTimestamp && (mReadHandler->IsDirty() || now >= mMaxTimestamp || now >= mSyncTimestamp))); -#endif // CONFIG_BUILD_FOR_HOST_UNIT_TEST } bool IsEngineRunScheduled() const { return mEngineRunScheduled; } - void SetEngineRunScheduled(bool aEngineRunScheduled) - { - mEngineRunScheduled = aEngineRunScheduled; -#ifdef CONFIG_BUILD_FOR_HOST_UNIT_TEST - // If the engine becomes unscheduled, this means a run just took place so we reset the test flags - if (!mEngineRunScheduled) - { - mFlags.Set(TestFlags::MinIntervalElapsed, false); - mFlags.Set(TestFlags::MaxIntervalElapsed, false); - } -#endif // CONFIG_BUILD_FOR_HOST_UNIT_TEST - } + void SetEngineRunScheduled(bool aEngineRunScheduled) { mEngineRunScheduled = aEngineRunScheduled; } void SetIntervalTimeStamps(ReadHandler * aReadHandler) { @@ -146,9 +118,6 @@ class ReportScheduler : public ReadHandler::Observer, public ICDStateObserver System::Clock::Timestamp GetSyncTimestamp() const { return mSyncTimestamp; } private: -#ifdef CONFIG_BUILD_FOR_HOST_UNIT_TEST - BitFlags mFlags; -#endif // CONFIG_BUILD_FOR_HOST_UNIT_TEST TimerDelegate * mTimerDelegate; ReadHandler * mReadHandler; ReportScheduler * mScheduler; @@ -180,22 +149,6 @@ class ReportScheduler : public ReadHandler::Observer, public ICDStateObserver size_t GetNumReadHandlers() const { return mNodesPool.Allocated(); } #ifdef CONFIG_BUILD_FOR_HOST_UNIT_TEST - void RunNodeCallbackForHandler(const ReadHandler * aReadHandler) - { - ReadHandlerNode * node = FindReadHandlerNode(aReadHandler); - node->TimerFired(); - } - void SetFlagsForHandler(const ReadHandler * aReadHandler, ReadHandlerNode::TestFlags aFlag, bool aValue) - { - ReadHandlerNode * node = FindReadHandlerNode(aReadHandler); - node->SetTestFlags(aFlag, aValue); - } - - bool CheckFlagsForHandler(const ReadHandler * aReadHandler, ReadHandlerNode::TestFlags aFlag) - { - ReadHandlerNode * node = FindReadHandlerNode(aReadHandler); - return node->GetTestFlags(aFlag); - } Timestamp GetMinTimestampForHandler(const ReadHandler * aReadHandler) { ReadHandlerNode * node = FindReadHandlerNode(aReadHandler); diff --git a/src/app/tests/TestReadInteraction.cpp b/src/app/tests/TestReadInteraction.cpp index 88571b040e866d..0c490f86002f73 100644 --- a/src/app/tests/TestReadInteraction.cpp +++ b/src/app/tests/TestReadInteraction.cpp @@ -67,11 +67,17 @@ chip::EndpointId kInvalidTestEndpointId = 3; chip::DataVersion kTestDataVersion1 = 3; chip::DataVersion kTestDataVersion2 = 5; +static chip::System::Clock::Internal::MockClock gMockClock; +static chip::System::Clock::ClockBase * gRealClock; + class TestContext : public chip::Test::AppContext { public: static int Initialize(void * context) { + gRealClock = &chip::System::SystemClock(); + chip::System::Clock::Internal::SetSystemClockForTesting(&gMockClock); + if (AppContext::Initialize(context) != SUCCESS) return FAILURE; @@ -97,6 +103,7 @@ class TestContext : public chip::Test::AppContext static int Finalize(void * context) { chip::app::EventManagement::DestroyEventManagement(); + chip::System::Clock::Internal::SetSystemClockForTesting(gRealClock); if (AppContext::Finalize(context) != SUCCESS) return FAILURE; @@ -1918,8 +1925,8 @@ void TestReadInteraction::TestSubscribeRoundtrip(nlTestSuite * apSuite, void * a readPrepareParams.mAttributePathParamsListSize = 2; - readPrepareParams.mMinIntervalFloorSeconds = 2; - readPrepareParams.mMaxIntervalCeilingSeconds = 5; + readPrepareParams.mMinIntervalFloorSeconds = 1; + readPrepareParams.mMaxIntervalCeilingSeconds = 2; printf("\nSend first subscribe request message to Node: %" PRIu64 "\n", chip::kTestDeviceNodeId); { @@ -1983,7 +1990,11 @@ void TestReadInteraction::TestSubscribeRoundtrip(nlTestSuite * apSuite, void * a dirtyPath5.mAttributeId = 4; // Test report with 2 different path - reportScheduler->SetFlagsForHandler(delegate.mpReadHandler, ReadHandlerNode::TestFlags::MinIntervalElapsed, true); + + // Advance monotonic timestamp for min interval to elapse + gMockClock.AdvanceMonotonic(System::Clock::Seconds16(readPrepareParams.mMinIntervalFloorSeconds)); + ctx.GetIOContext().DriveIO(); + delegate.mGotReport = false; delegate.mGotEventResponse = false; delegate.mNumAttributeResponse = 0; @@ -1995,15 +2006,15 @@ void TestReadInteraction::TestSubscribeRoundtrip(nlTestSuite * apSuite, void * a ctx.DrainAndServiceIO(); - NL_TEST_ASSERT( - apSuite, - !reportScheduler->CheckFlagsForHandler(delegate.mpReadHandler, ReadHandlerNode::TestFlags::MinIntervalElapsed)); NL_TEST_ASSERT(apSuite, delegate.mGotReport); NL_TEST_ASSERT(apSuite, delegate.mGotEventResponse == true); NL_TEST_ASSERT(apSuite, delegate.mNumAttributeResponse == 2); // Test report with 2 different path, and 1 same path - reportScheduler->SetFlagsForHandler(delegate.mpReadHandler, ReadHandlerNode::TestFlags::MinIntervalElapsed, true); + // Advance monotonic timestamp for min interval to elapse + gMockClock.AdvanceMonotonic(System::Clock::Seconds16(readPrepareParams.mMinIntervalFloorSeconds)); + ctx.GetIOContext().DriveIO(); + delegate.mGotReport = false; delegate.mNumAttributeResponse = 0; err = engine->GetReportingEngine().SetDirty(dirtyPath1); @@ -2015,14 +2026,14 @@ void TestReadInteraction::TestSubscribeRoundtrip(nlTestSuite * apSuite, void * a ctx.DrainAndServiceIO(); - NL_TEST_ASSERT( - apSuite, - !reportScheduler->CheckFlagsForHandler(delegate.mpReadHandler, ReadHandlerNode::TestFlags::MinIntervalElapsed)); NL_TEST_ASSERT(apSuite, delegate.mGotReport); NL_TEST_ASSERT(apSuite, delegate.mNumAttributeResponse == 2); // Test report with 3 different path, and one path is overlapped with another - reportScheduler->SetFlagsForHandler(delegate.mpReadHandler, ReadHandlerNode::TestFlags::MinIntervalElapsed, true); + // Advance monotonic timestamp for min interval to elapse + gMockClock.AdvanceMonotonic(System::Clock::Seconds16(readPrepareParams.mMinIntervalFloorSeconds)); + ctx.GetIOContext().DriveIO(); + delegate.mGotReport = false; delegate.mNumAttributeResponse = 0; err = engine->GetReportingEngine().SetDirty(dirtyPath1); @@ -2034,14 +2045,14 @@ void TestReadInteraction::TestSubscribeRoundtrip(nlTestSuite * apSuite, void * a ctx.DrainAndServiceIO(); - NL_TEST_ASSERT( - apSuite, - !reportScheduler->CheckFlagsForHandler(delegate.mpReadHandler, ReadHandlerNode::TestFlags::MinIntervalElapsed)); NL_TEST_ASSERT(apSuite, delegate.mGotReport); NL_TEST_ASSERT(apSuite, delegate.mNumAttributeResponse == 2); // Test report with 3 different path, all are not overlapped, one path is not interested for current subscription - reportScheduler->SetFlagsForHandler(delegate.mpReadHandler, ReadHandlerNode::TestFlags::MinIntervalElapsed, true); + // Advance monotonic timestamp for min interval to elapse + gMockClock.AdvanceMonotonic(System::Clock::Seconds16(readPrepareParams.mMinIntervalFloorSeconds)); + ctx.GetIOContext().DriveIO(); + delegate.mGotReport = false; delegate.mNumAttributeResponse = 0; err = engine->GetReportingEngine().SetDirty(dirtyPath1); @@ -2053,18 +2064,13 @@ void TestReadInteraction::TestSubscribeRoundtrip(nlTestSuite * apSuite, void * a ctx.DrainAndServiceIO(); - NL_TEST_ASSERT( - apSuite, - !reportScheduler->CheckFlagsForHandler(delegate.mpReadHandler, ReadHandlerNode::TestFlags::MinIntervalElapsed)); NL_TEST_ASSERT(apSuite, delegate.mGotReport); NL_TEST_ASSERT(apSuite, delegate.mNumAttributeResponse == 2); // Test empty report - reportScheduler->SetFlagsForHandler(delegate.mpReadHandler, ReadHandlerNode::TestFlags::MinIntervalElapsed, true); - reportScheduler->SetFlagsForHandler(delegate.mpReadHandler, ReadHandlerNode::TestFlags::MaxIntervalElapsed, true); - // Manually trigger the callback that would schedule the next report as it would normally have been called if the time had - // elapsed as simulated above - reportScheduler->RunNodeCallbackForHandler(delegate.mpReadHandler); + // Advance monotonic timestamp for min interval to elapse + gMockClock.AdvanceMonotonic(System::Clock::Seconds16(readPrepareParams.mMaxIntervalCeilingSeconds)); + ctx.GetIOContext().DriveIO(); NL_TEST_ASSERT(apSuite, engine->GetReportingEngine().IsRunScheduled()); delegate.mGotReport = false; @@ -2117,7 +2123,7 @@ void TestReadInteraction::TestSubscribeUrgentWildcardEvent(nlTestSuite * apSuite readPrepareParams.mpAttributePathParamsList = nullptr; readPrepareParams.mAttributePathParamsListSize = 0; - readPrepareParams.mMinIntervalFloorSeconds = 2; + readPrepareParams.mMinIntervalFloorSeconds = 1; readPrepareParams.mMaxIntervalCeilingSeconds = 3600; printf("\nSend first subscribe request message with wildcard urgent event to Node: %" PRIu64 "\n", chip::kTestDeviceNodeId); @@ -2138,8 +2144,7 @@ void TestReadInteraction::TestSubscribeUrgentWildcardEvent(nlTestSuite * apSuite NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); ctx.DrainAndServiceIO(); - - System::Clock::Timestamp startTime = System::SystemClock().GetMonotonicTimestamp(); + System::Clock::Timestamp startTime = gMockClock.GetMonotonicTimestamp(); NL_TEST_ASSERT(apSuite, engine->GetNumActiveReadHandlers() == 2); NL_TEST_ASSERT(apSuite, engine->ActiveHandlerAt(0) != nullptr); @@ -2163,40 +2168,39 @@ void TestReadInteraction::TestSubscribeUrgentWildcardEvent(nlTestSuite * apSuite nonUrgentDelegate.mGotEventResponse = false; nonUrgentDelegate.mGotReport = false; - // wait for min interval 2 seconds (in test, we use 1.6 seconds considering the time variation), expect no event is + // wait for min interval 1 seconds (in test, we use 0.6 seconds considering the time variation), expect no event is // received, then wait for 0.8 seconds, then the urgent event would be sent out // currently DriveIOUntil will call `DriveIO` at least once, which means that if there is any CPU scheduling issues, // there's a chance 1.9s will already have elapsed by the time we get there, which will result in DriveIO being called when // it shouldn't. Better fix could happen inside DriveIOUntil, not sure the sideeffect there. - while (true) - { - if ((System::SystemClock().GetMonotonicTimestamp() - startTime) >= System::Clock::Milliseconds32(1600)) - { - break; - } - ctx.GetIOContext().DriveIO(); // at least one IO loop is guaranteed - } + + // Advance monotonic looping to allow events to trigger + gMockClock.AdvanceMonotonic(System::Clock::Milliseconds32(600)); + ctx.GetIOContext().DriveIO(); NL_TEST_ASSERT(apSuite, !delegate.mGotEventResponse); NL_TEST_ASSERT(apSuite, !nonUrgentDelegate.mGotEventResponse); - startTime = System::SystemClock().GetMonotonicTimestamp(); - while (true) - { - if ((System::SystemClock().GetMonotonicTimestamp() - startTime) >= System::Clock::Milliseconds32(800)) - { - break; - } - ctx.GetIOContext().DriveIO(); // at least one IO loop is guaranteed - } + // Advance monotonic timestamp for min interval to elapse + startTime = gMockClock.GetMonotonicTimestamp(); + gMockClock.AdvanceMonotonic(System::Clock::Milliseconds32(800)); + + // Service Timer expired event + ctx.GetIOContext().DriveIO(); + + // Service Engine Run + ctx.GetIOContext().DriveIO(); + + // Service EventManagement event + ctx.GetIOContext().DriveIO(); + NL_TEST_ASSERT(apSuite, delegate.mGotEventResponse); NL_TEST_ASSERT(apSuite, !nonUrgentDelegate.mGotEventResponse); // Since we just sent a report for our urgent subscription, the min interval of the urgent subcription should have been // updated NL_TEST_ASSERT(apSuite, - reportScheduler->GetMinTimestampForHandler(delegate.mpReadHandler) > - System::SystemClock().GetMonotonicTimestamp()); + reportScheduler->GetMinTimestampForHandler(delegate.mpReadHandler) > gMockClock.GetMonotonicTimestamp()); NL_TEST_ASSERT(apSuite, !delegate.mpReadHandler->IsDirty()); delegate.mGotEventResponse = false; @@ -2204,19 +2208,12 @@ void TestReadInteraction::TestSubscribeUrgentWildcardEvent(nlTestSuite * apSuite // should be in the past NL_TEST_ASSERT(apSuite, reportScheduler->GetMinTimestampForHandler(nonUrgentDelegate.mpReadHandler) < - System::SystemClock().GetMonotonicTimestamp()); + gMockClock.GetMonotonicTimestamp()); NL_TEST_ASSERT(apSuite, !nonUrgentDelegate.mpReadHandler->IsDirty()); - // Wait for the min interval timer to fire. - startTime = System::SystemClock().GetMonotonicTimestamp(); - while (true) - { - if ((System::SystemClock().GetMonotonicTimestamp() - startTime) >= System::Clock::Milliseconds32(2100)) - { - break; - } - ctx.GetIOContext().DriveIO(); // at least one IO loop is guaranteed - } + // Advance monotonic timestamp for min interval to elapse + gMockClock.AdvanceMonotonic(System::Clock::Milliseconds32(2100)); + ctx.GetIOContext().DriveIO(); // No reporting should have happened. NL_TEST_ASSERT(apSuite, !delegate.mGotEventResponse); @@ -2377,7 +2374,6 @@ void TestReadInteraction::TestSubscribeWildcard(nlTestSuite * apSuite, void * ap // Set a concrete path dirty { - reportScheduler->SetFlagsForHandler(delegate.mpReadHandler, ReadHandlerNode::TestFlags::MinIntervalElapsed, true); delegate.mGotReport = false; delegate.mNumAttributeResponse = 0; @@ -2391,9 +2387,6 @@ void TestReadInteraction::TestSubscribeWildcard(nlTestSuite * apSuite, void * ap ctx.DrainAndServiceIO(); - NL_TEST_ASSERT( - apSuite, - !reportScheduler->CheckFlagsForHandler(delegate.mpReadHandler, ReadHandlerNode::TestFlags::MinIntervalElapsed)); NL_TEST_ASSERT(apSuite, delegate.mGotReport); // We subscribed wildcard path twice, so we will receive two reports here. NL_TEST_ASSERT(apSuite, delegate.mNumAttributeResponse == 2); @@ -2401,7 +2394,6 @@ void TestReadInteraction::TestSubscribeWildcard(nlTestSuite * apSuite, void * ap // Set a endpoint dirty { - reportScheduler->SetFlagsForHandler(delegate.mpReadHandler, ReadHandlerNode::TestFlags::MinIntervalElapsed, true); delegate.mGotReport = false; delegate.mNumAttributeResponse = 0; delegate.mNumArrayItems = 0; @@ -2423,10 +2415,6 @@ void TestReadInteraction::TestSubscribeWildcard(nlTestSuite * apSuite, void * ap ctx.DrainAndServiceIO(); } while (last != delegate.mNumAttributeResponse); - NL_TEST_ASSERT( - apSuite, - !reportScheduler->CheckFlagsForHandler(delegate.mpReadHandler, ReadHandlerNode::TestFlags::MinIntervalElapsed)); - NL_TEST_ASSERT(apSuite, delegate.mGotReport); // Mock endpoint3 has 13 attributes in total, and we subscribed twice. // And attribute 3/2/4 is a list with 6 elements and list chunking // is applied to it, but the way the packet boundaries fall we get two of @@ -2497,7 +2485,6 @@ void TestReadInteraction::TestSubscribePartialOverlap(nlTestSuite * apSuite, voi // Set a partial overlapped path dirty { - reportScheduler->SetFlagsForHandler(delegate.mpReadHandler, ReadHandlerNode::TestFlags::MinIntervalElapsed, true); delegate.mGotReport = false; delegate.mNumAttributeResponse = 0; @@ -2510,9 +2497,6 @@ void TestReadInteraction::TestSubscribePartialOverlap(nlTestSuite * apSuite, voi ctx.DrainAndServiceIO(); - NL_TEST_ASSERT( - apSuite, - !reportScheduler->CheckFlagsForHandler(delegate.mpReadHandler, ReadHandlerNode::TestFlags::MinIntervalElapsed)); NL_TEST_ASSERT(apSuite, delegate.mGotReport); NL_TEST_ASSERT(apSuite, delegate.mNumAttributeResponse == 1); NL_TEST_ASSERT(apSuite, delegate.mReceivedAttributePaths[0].mEndpointId == Test::kMockEndpoint2); @@ -2578,7 +2562,6 @@ void TestReadInteraction::TestSubscribeSetDirtyFullyOverlap(nlTestSuite * apSuit // Set a full overlapped path dirty and expect to receive one E2C3A1 { - reportScheduler->SetFlagsForHandler(delegate.mpReadHandler, ReadHandlerNode::TestFlags::MinIntervalElapsed, true); delegate.mGotReport = false; delegate.mNumAttributeResponse = 0; @@ -2588,9 +2571,6 @@ void TestReadInteraction::TestSubscribeSetDirtyFullyOverlap(nlTestSuite * apSuit ctx.DrainAndServiceIO(); - NL_TEST_ASSERT( - apSuite, - !reportScheduler->CheckFlagsForHandler(delegate.mpReadHandler, ReadHandlerNode::TestFlags::MinIntervalElapsed)); NL_TEST_ASSERT(apSuite, delegate.mGotReport); NL_TEST_ASSERT(apSuite, delegate.mNumAttributeResponse == 1); NL_TEST_ASSERT(apSuite, delegate.mReceivedAttributePaths[0].mEndpointId == Test::kMockEndpoint2); @@ -2705,11 +2685,11 @@ void TestReadInteraction::TestSubscribeInvalidAttributePathRoundtrip(nlTestSuite NL_TEST_ASSERT(apSuite, engine->ActiveHandlerAt(0) != nullptr); delegate.mpReadHandler = engine->ActiveHandlerAt(0); - reportScheduler->SetFlagsForHandler(delegate.mpReadHandler, ReadHandlerNode::TestFlags::MinIntervalElapsed, true); - reportScheduler->SetFlagsForHandler(delegate.mpReadHandler, ReadHandlerNode::TestFlags::MaxIntervalElapsed, true); - // Manually trigger the callback that would schedule the next report as it would normally have been called if the time had - // elapsed as simulated above - reportScheduler->RunNodeCallbackForHandler(delegate.mpReadHandler); + // Advance monotonic timestamp for min interval to elapse + gMockClock.AdvanceMonotonic(System::Clock::Seconds16(readPrepareParams.mMaxIntervalCeilingSeconds)); + ctx.GetIOContext().DriveIO(); + + NL_TEST_ASSERT(apSuite, engine->GetReportingEngine().IsRunScheduled()); NL_TEST_ASSERT(apSuite, engine->GetReportingEngine().IsRunScheduled()); ctx.DrainAndServiceIO(); @@ -2848,8 +2828,8 @@ void TestReadInteraction::TestPostSubscribeRoundtripStatusReportTimeout(nlTestSu readPrepareParams.mAttributePathParamsListSize = 2; - readPrepareParams.mMinIntervalFloorSeconds = 2; - readPrepareParams.mMaxIntervalCeilingSeconds = 5; + readPrepareParams.mMinIntervalFloorSeconds = 0; + readPrepareParams.mMaxIntervalCeilingSeconds = 1; delegate.mNumAttributeResponse = 0; readPrepareParams.mKeepSubscriptions = false; @@ -2885,7 +2865,6 @@ void TestReadInteraction::TestPostSubscribeRoundtripStatusReportTimeout(nlTestSu dirtyPath2.mAttributeId = 2; // Test report with 2 different path - reportScheduler->SetFlagsForHandler(delegate.mpReadHandler, ReadHandlerNode::TestFlags::MinIntervalElapsed, true); delegate.mGotReport = false; delegate.mNumAttributeResponse = 0; @@ -2896,14 +2875,13 @@ void TestReadInteraction::TestPostSubscribeRoundtripStatusReportTimeout(nlTestSu ctx.DrainAndServiceIO(); - NL_TEST_ASSERT( - apSuite, - !reportScheduler->CheckFlagsForHandler(delegate.mpReadHandler, ReadHandlerNode::TestFlags::MinIntervalElapsed)); NL_TEST_ASSERT(apSuite, delegate.mGotReport); NL_TEST_ASSERT(apSuite, delegate.mNumAttributeResponse == 2); - reportScheduler->SetFlagsForHandler(delegate.mpReadHandler, ReadHandlerNode::TestFlags::MinIntervalElapsed, true); - reportScheduler->SetFlagsForHandler(delegate.mpReadHandler, ReadHandlerNode::TestFlags::MaxIntervalElapsed, true); + // Wait for max interval to elapse + gMockClock.AdvanceMonotonic(System::Clock::Seconds16(readPrepareParams.mMaxIntervalCeilingSeconds)); + ctx.GetIOContext().DriveIO(); + delegate.mGotReport = false; delegate.mNumAttributeResponse = 0; ctx.ExpireSessionBobToAlice(); @@ -3221,8 +3199,8 @@ void TestReadInteraction::TestPostSubscribeRoundtripChunkStatusReportTimeout(nlT readPrepareParams.mpAttributePathParamsList = attributePathParams; readPrepareParams.mAttributePathParamsListSize = 1; - readPrepareParams.mMinIntervalFloorSeconds = 2; - readPrepareParams.mMaxIntervalCeilingSeconds = 5; + readPrepareParams.mMinIntervalFloorSeconds = 0; + readPrepareParams.mMaxIntervalCeilingSeconds = 1; delegate.mNumAttributeResponse = 0; readPrepareParams.mKeepSubscriptions = false; @@ -3251,8 +3229,9 @@ void TestReadInteraction::TestPostSubscribeRoundtripChunkStatusReportTimeout(nlT dirtyPath1.mEndpointId = Test::kMockEndpoint3; dirtyPath1.mAttributeId = Test::MockAttributeId(4); - reportScheduler->SetFlagsForHandler(delegate.mpReadHandler, ReadHandlerNode::TestFlags::MinIntervalElapsed, true); - reportScheduler->SetFlagsForHandler(delegate.mpReadHandler, ReadHandlerNode::TestFlags::MaxIntervalElapsed, true); + gMockClock.AdvanceMonotonic(System::Clock::Seconds16(readPrepareParams.mMaxIntervalCeilingSeconds)); + ctx.GetIOContext().DriveIO(); + err = engine->GetReportingEngine().SetDirty(dirtyPath1); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); delegate.mGotReport = false; @@ -3324,8 +3303,8 @@ void TestReadInteraction::TestPostSubscribeRoundtripChunkReportTimeout(nlTestSui readPrepareParams.mpAttributePathParamsList = attributePathParams; readPrepareParams.mAttributePathParamsListSize = 1; - readPrepareParams.mMinIntervalFloorSeconds = 2; - readPrepareParams.mMaxIntervalCeilingSeconds = 5; + readPrepareParams.mMinIntervalFloorSeconds = 0; + readPrepareParams.mMaxIntervalCeilingSeconds = 1; delegate.mNumAttributeResponse = 0; readPrepareParams.mKeepSubscriptions = false; @@ -3354,8 +3333,9 @@ void TestReadInteraction::TestPostSubscribeRoundtripChunkReportTimeout(nlTestSui dirtyPath1.mEndpointId = Test::kMockEndpoint3; dirtyPath1.mAttributeId = Test::MockAttributeId(4); - reportScheduler->SetFlagsForHandler(delegate.mpReadHandler, ReadHandlerNode::TestFlags::MinIntervalElapsed, true); - reportScheduler->SetFlagsForHandler(delegate.mpReadHandler, ReadHandlerNode::TestFlags::MaxIntervalElapsed, true); + gMockClock.AdvanceMonotonic(System::Clock::Seconds16(readPrepareParams.mMaxIntervalCeilingSeconds)); + ctx.GetIOContext().DriveIO(); + err = engine->GetReportingEngine().SetDirty(dirtyPath1); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); delegate.mGotReport = false; @@ -3425,7 +3405,7 @@ void TestReadInteraction::TestPostSubscribeRoundtripChunkReport(nlTestSuite * ap readPrepareParams.mpAttributePathParamsList = attributePathParams; readPrepareParams.mAttributePathParamsListSize = 1; - readPrepareParams.mMinIntervalFloorSeconds = 2; + readPrepareParams.mMinIntervalFloorSeconds = 1; readPrepareParams.mMaxIntervalCeilingSeconds = 5; delegate.mNumAttributeResponse = 0; @@ -3460,28 +3440,25 @@ void TestReadInteraction::TestPostSubscribeRoundtripChunkReport(nlTestSuite * ap delegate.mNumAttributeResponse = 0; delegate.mNumArrayItems = 0; - // wait for min interval 2 seconds(in test, we use 1.9second considering the time variation), expect no event is received, + // wait for min interval 1 seconds(in test, we use 0.9second considering the time variation), expect no event is received, // then wait for 0.5 seconds, then all chunked dirty reports are sent out, which would not honor minInterval - System::Clock::Timestamp startTime = System::SystemClock().GetMonotonicTimestamp(); - while (true) - { - if ((System::SystemClock().GetMonotonicTimestamp() - startTime) >= System::Clock::Milliseconds32(1900)) - { - break; - } - ctx.GetIOContext().DriveIO(); - } + gMockClock.AdvanceMonotonic(System::Clock::Milliseconds32(900)); + ctx.GetIOContext().DriveIO(); + NL_TEST_ASSERT(apSuite, delegate.mNumAttributeResponse == 0); - startTime = System::SystemClock().GetMonotonicTimestamp(); + System::Clock::Timestamp startTime = gMockClock.GetMonotonicTimestamp(); + + // Increment in time is done by steps here to allow for multiple IO processing at the right time and allow the timer to be + // rescheduled accordingly while (true) { - if ((System::SystemClock().GetMonotonicTimestamp() - startTime) >= System::Clock::Milliseconds32(500)) + ctx.GetIOContext().DriveIO(); + if ((gMockClock.GetMonotonicTimestamp() - startTime) >= System::Clock::Milliseconds32(500)) { break; } - ctx.GetIOContext().DriveIO(); + gMockClock.AdvanceMonotonic(System::Clock::Milliseconds32(10)); } - ctx.DrainAndServiceIO(); } // Two chunked reports carry 4 attributeDataIB: 1 with a list of 3 items, // and then one per remaining item. @@ -4736,14 +4713,11 @@ void TestReadInteraction::TestSubscriptionReportWithDefunctSession(nlTestSuite * NL_TEST_ASSERT(apSuite, SessionHandle(*readHandler->GetSession()) == ctx.GetSessionAliceToBob()); // Test that we send reports as needed. - reportScheduler->SetFlagsForHandler(readHandler, ReadHandlerNode::TestFlags::MinIntervalElapsed, true); delegate.mGotReport = false; delegate.mNumAttributeResponse = 0; engine->GetReportingEngine().SetDirty(subscribePath); - ctx.DrainAndServiceIO(); - NL_TEST_ASSERT(apSuite, - !reportScheduler->CheckFlagsForHandler(readHandler, ReadHandlerNode::TestFlags::MinIntervalElapsed)); + NL_TEST_ASSERT(apSuite, delegate.mGotReport); NL_TEST_ASSERT(apSuite, delegate.mNumAttributeResponse == 1); NL_TEST_ASSERT(apSuite, engine->GetNumActiveReadHandlers(ReadHandler::InteractionType::Subscribe) == 1); @@ -4753,7 +4727,6 @@ void TestReadInteraction::TestSubscriptionReportWithDefunctSession(nlTestSuite * // Test that if the session is defunct we don't send reports and clean // up properly. readHandler->GetSession()->MarkAsDefunct(); - reportScheduler->SetFlagsForHandler(readHandler, ReadHandlerNode::TestFlags::MinIntervalElapsed, true); delegate.mGotReport = false; delegate.mNumAttributeResponse = 0; engine->GetReportingEngine().SetDirty(subscribePath);