Skip to content

Commit a712f77

Browse files
[ICD] Add subscriber request max interval getter (#36021)
* Add subscriber request max interval getter * Add unit-test for the SetMaxReportingInterval * Restyled by clang-format * fix conversation error * Restyled by clang-format --------- Co-authored-by: Restyled.io <commits@restyled.io>
1 parent 8c0f11a commit a712f77

File tree

3 files changed

+145
-5
lines changed

3 files changed

+145
-5
lines changed

src/app/ReadHandler.cpp

+3-1
Original file line numberDiff line numberDiff line change
@@ -741,7 +741,9 @@ CHIP_ERROR ReadHandler::ProcessSubscribeRequest(System::PacketBufferHandle && aP
741741
ReturnErrorOnFailure(err);
742742

743743
ReturnErrorOnFailure(subscribeRequestParser.GetMinIntervalFloorSeconds(&mMinIntervalFloorSeconds));
744-
ReturnErrorOnFailure(subscribeRequestParser.GetMaxIntervalCeilingSeconds(&mMaxInterval));
744+
ReturnErrorOnFailure(subscribeRequestParser.GetMaxIntervalCeilingSeconds(&mSubscriberRequestedMaxInterval));
745+
mMaxInterval = mSubscriberRequestedMaxInterval;
746+
745747
VerifyOrReturnError(mMinIntervalFloorSeconds <= mMaxInterval, CHIP_ERROR_INVALID_ARGUMENT);
746748

747749
#if CHIP_CONFIG_ENABLE_ICD_SERVER

src/app/ReadHandler.h

+24-4
Original file line numberDiff line numberDiff line change
@@ -229,12 +229,31 @@ class ReadHandler : public Messaging::ExchangeDelegate
229229
const SingleLinkedListNode<EventPathParams> * GetEventPathList() const { return mpEventPathList; }
230230
const SingleLinkedListNode<DataVersionFilter> * GetDataVersionFilterList() const { return mpDataVersionFilterList; }
231231

232+
/**
233+
* @brief Returns the reporting intervals that will used by the ReadHandler for the subscription being requested.
234+
* After the subscription is established, these will be the set reporting intervals and cannot be changed.
235+
*
236+
* @param[out] aMinInterval minimum time delta between two reports for the subscription
237+
* @param[in] aMaxInterval maximum time delta between two reports for the subscription
238+
*/
232239
void GetReportingIntervals(uint16_t & aMinInterval, uint16_t & aMaxInterval) const
233240
{
234241
aMinInterval = mMinIntervalFloorSeconds;
235242
aMaxInterval = mMaxInterval;
236243
}
237244

245+
/**
246+
* @brief Returns the maximum reporting interval that was initially requested by the subscriber
247+
* This is the same value as the mMaxInterval member if the max interval is not changed by the publisher.
248+
*
249+
* @note If the device is an ICD, the MaxInterval of a subscription is automatically set to a multiple of the IdleModeDuration.
250+
* This function is the only way to get the requested max interval once the OnSubscriptionRequested application callback
251+
* is called.
252+
*
253+
* @return uint16_t subscriber requested maximum reporting interval
254+
*/
255+
inline uint16_t GetSubscriberRequestedMaxInterval() const { return mSubscriberRequestedMaxInterval; }
256+
238257
CHIP_ERROR SetMinReportingIntervalForTests(uint16_t aMinInterval)
239258
{
240259
VerifyOrReturnError(IsIdle(), CHIP_ERROR_INCORRECT_STATE);
@@ -254,7 +273,7 @@ class ReadHandler : public Messaging::ExchangeDelegate
254273
{
255274
VerifyOrReturnError(IsIdle(), CHIP_ERROR_INCORRECT_STATE);
256275
VerifyOrReturnError(mMinIntervalFloorSeconds <= aMaxInterval, CHIP_ERROR_INVALID_ARGUMENT);
257-
VerifyOrReturnError(aMaxInterval <= std::max(GetPublisherSelectedIntervalLimit(), mMaxInterval),
276+
VerifyOrReturnError(aMaxInterval <= std::max(GetPublisherSelectedIntervalLimit(), mSubscriberRequestedMaxInterval),
258277
CHIP_ERROR_INVALID_ARGUMENT);
259278
mMaxInterval = aMaxInterval;
260279
return CHIP_NO_ERROR;
@@ -542,9 +561,10 @@ class ReadHandler : public Messaging::ExchangeDelegate
542561
// engine, the "oldest" subscription is the subscription with the smallest generation.
543562
uint64_t mTransactionStartGeneration = 0;
544563

545-
SubscriptionId mSubscriptionId = 0;
546-
uint16_t mMinIntervalFloorSeconds = 0;
547-
uint16_t mMaxInterval = 0;
564+
SubscriptionId mSubscriptionId = 0;
565+
uint16_t mMinIntervalFloorSeconds = 0;
566+
uint16_t mMaxInterval = 0;
567+
uint16_t mSubscriberRequestedMaxInterval = 0;
548568

549569
EventNumber mEventMin = 0;
550570

src/app/tests/TestReadInteraction.cpp

+118
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,7 @@ class TestReadInteraction : public chip::Test::AppContext
343343
void TestReadClient();
344344
void TestReadUnexpectedSubscriptionId();
345345
void TestReadHandler();
346+
void TestReadHandlerSetMaxReportingInterval();
346347
void TestReadClientGenerateAttributePathList();
347348
void TestReadClientGenerateInvalidAttributePathList();
348349
void TestReadClientInvalidReport();
@@ -568,6 +569,115 @@ TEST_F_FROM_FIXTURE(TestReadInteraction, TestReadHandler)
568569
EXPECT_EQ(GetExchangeManager().GetNumActiveExchanges(), 0u);
569570
}
570571

572+
TEST_F_FROM_FIXTURE(TestReadInteraction, TestReadHandlerSetMaxReportingInterval)
573+
{
574+
System::PacketBufferTLVWriter writer;
575+
System::PacketBufferHandle subscribeRequestbuf = System::PacketBufferHandle::New(System::PacketBuffer::kMaxSize);
576+
SubscribeRequestMessage::Builder subscribeRequestBuilder;
577+
578+
auto * engine = chip::app::InteractionModelEngine::GetInstance();
579+
EXPECT_EQ(engine->Init(&GetExchangeManager(), &GetFabricTable(), gReportScheduler), CHIP_NO_ERROR);
580+
581+
uint16_t kIntervalInfMinInterval = 119;
582+
uint16_t kMinInterval = 120;
583+
uint16_t kMaxIntervalCeiling = 500;
584+
585+
Messaging::ExchangeContext * exchangeCtx = NewExchangeToAlice(nullptr, false);
586+
587+
{
588+
589+
uint16_t minInterval;
590+
uint16_t maxInterval;
591+
592+
// Configure ReadHandler
593+
ReadHandler readHandler(*engine, exchangeCtx, chip::app::ReadHandler::InteractionType::Read, gReportScheduler,
594+
CodegenDataModelProviderInstance());
595+
596+
writer.Init(std::move(subscribeRequestbuf));
597+
EXPECT_EQ(subscribeRequestBuilder.Init(&writer), CHIP_NO_ERROR);
598+
599+
subscribeRequestBuilder.KeepSubscriptions(true);
600+
EXPECT_EQ(subscribeRequestBuilder.GetError(), CHIP_NO_ERROR);
601+
602+
subscribeRequestBuilder.MinIntervalFloorSeconds(kMinInterval);
603+
EXPECT_EQ(subscribeRequestBuilder.GetError(), CHIP_NO_ERROR);
604+
605+
subscribeRequestBuilder.MaxIntervalCeilingSeconds(kMaxIntervalCeiling);
606+
EXPECT_EQ(subscribeRequestBuilder.GetError(), CHIP_NO_ERROR);
607+
608+
AttributePathIBs::Builder & attributePathListBuilder = subscribeRequestBuilder.CreateAttributeRequests();
609+
EXPECT_EQ(attributePathListBuilder.GetError(), CHIP_NO_ERROR);
610+
611+
AttributePathIB::Builder & attributePathBuilder = attributePathListBuilder.CreatePath();
612+
EXPECT_EQ(attributePathListBuilder.GetError(), CHIP_NO_ERROR);
613+
614+
attributePathBuilder.Node(1).Endpoint(2).Cluster(3).Attribute(4).ListIndex(5).EndOfAttributePathIB();
615+
EXPECT_EQ(attributePathBuilder.GetError(), CHIP_NO_ERROR);
616+
617+
attributePathListBuilder.EndOfAttributePathIBs();
618+
EXPECT_EQ(attributePathListBuilder.GetError(), CHIP_NO_ERROR);
619+
620+
subscribeRequestBuilder.IsFabricFiltered(false).EndOfSubscribeRequestMessage();
621+
EXPECT_EQ(subscribeRequestBuilder.GetError(), CHIP_NO_ERROR);
622+
623+
EXPECT_EQ(subscribeRequestBuilder.GetError(), CHIP_NO_ERROR);
624+
EXPECT_EQ(writer.Finalize(&subscribeRequestbuf), CHIP_NO_ERROR);
625+
626+
EXPECT_EQ(readHandler.ProcessSubscribeRequest(std::move(subscribeRequestbuf)), CHIP_NO_ERROR);
627+
628+
#if CHIP_CONFIG_ENABLE_ICD_SERVER
629+
// When an ICD build, the default behavior is to select the IdleModeDuration as MaxInterval
630+
kMaxIntervalCeiling = readHandler.GetPublisherSelectedIntervalLimit();
631+
#endif
632+
// Try to change the MaxInterval while ReadHandler is active
633+
EXPECT_EQ(readHandler.SetMaxReportingInterval(340), CHIP_ERROR_INCORRECT_STATE);
634+
635+
readHandler.GetReportingIntervals(minInterval, maxInterval);
636+
EXPECT_EQ(kMaxIntervalCeiling, maxInterval);
637+
// Set ReadHandler to Idle to allow MaxInterval changes
638+
readHandler.MoveToState(ReadHandler::HandlerState::Idle);
639+
640+
// TC1: MaxInterval < MinIntervalFloor
641+
EXPECT_EQ(readHandler.SetMaxReportingInterval(kIntervalInfMinInterval), CHIP_ERROR_INVALID_ARGUMENT);
642+
643+
readHandler.GetReportingIntervals(minInterval, maxInterval);
644+
EXPECT_EQ(kMaxIntervalCeiling, maxInterval);
645+
646+
// TC2: MaxInterval == MinIntervalFloor
647+
EXPECT_EQ(readHandler.SetMaxReportingInterval(kMinInterval), CHIP_NO_ERROR);
648+
649+
readHandler.GetReportingIntervals(minInterval, maxInterval);
650+
EXPECT_EQ(kMinInterval, maxInterval);
651+
652+
// TC3: Minterval < MaxInterval < max(GetPublisherSelectedIntervalLimit(), mSubscriberRequestedMaxInterval)
653+
EXPECT_EQ(readHandler.SetMaxReportingInterval(kMaxIntervalCeiling), CHIP_NO_ERROR);
654+
655+
readHandler.GetReportingIntervals(minInterval, maxInterval);
656+
EXPECT_EQ(kMaxIntervalCeiling, maxInterval);
657+
658+
// TC4: MaxInterval == Subscriber Requested Max Interval
659+
EXPECT_EQ(readHandler.SetMaxReportingInterval(readHandler.GetSubscriberRequestedMaxInterval()), CHIP_NO_ERROR);
660+
661+
readHandler.GetReportingIntervals(minInterval, maxInterval);
662+
EXPECT_EQ(readHandler.GetSubscriberRequestedMaxInterval(), maxInterval);
663+
664+
// TC4: MaxInterval == GetPublisherSelectedIntervalLimit()
665+
EXPECT_EQ(readHandler.SetMaxReportingInterval(readHandler.GetPublisherSelectedIntervalLimit()), CHIP_NO_ERROR);
666+
667+
readHandler.GetReportingIntervals(minInterval, maxInterval);
668+
EXPECT_EQ(readHandler.GetPublisherSelectedIntervalLimit(), maxInterval);
669+
670+
// TC5: MaxInterval > max(GetPublisherSelectedIntervalLimit(), mSubscriberRequestedMaxInterval)
671+
EXPECT_EQ(readHandler.SetMaxReportingInterval(std::numeric_limits<uint16_t>::max()), CHIP_ERROR_INVALID_ARGUMENT);
672+
673+
readHandler.GetReportingIntervals(minInterval, maxInterval);
674+
EXPECT_EQ(readHandler.GetPublisherSelectedIntervalLimit(), maxInterval);
675+
}
676+
677+
engine->Shutdown();
678+
EXPECT_EQ(GetExchangeManager().GetNumActiveExchanges(), 0u);
679+
}
680+
571681
TEST_F_FROM_FIXTURE(TestReadInteraction, TestReadClientGenerateAttributePathList)
572682
{
573683
MockInteractionModelApp delegate;
@@ -1517,6 +1627,7 @@ TEST_F_FROM_FIXTURE(TestReadInteraction, TestICDProcessSubscribeRequestSupMaxInt
15171627

15181628
EXPECT_EQ(minInterval, kMinInterval);
15191629
EXPECT_EQ(maxInterval, idleModeDuration);
1630+
EXPECT_EQ(kMaxIntervalCeiling, readHandler.GetSubscriberRequestedMaxInterval());
15201631
}
15211632
engine->Shutdown();
15221633

@@ -1584,6 +1695,7 @@ TEST_F_FROM_FIXTURE(TestReadInteraction, TestICDProcessSubscribeRequestInfMaxInt
15841695

15851696
EXPECT_EQ(minInterval, kMinInterval);
15861697
EXPECT_EQ(maxInterval, idleModeDuration);
1698+
EXPECT_EQ(kMaxIntervalCeiling, readHandler.GetSubscriberRequestedMaxInterval());
15871699
}
15881700
engine->Shutdown();
15891701

@@ -1651,6 +1763,7 @@ TEST_F_FROM_FIXTURE(TestReadInteraction, TestICDProcessSubscribeRequestSupMinInt
16511763

16521764
EXPECT_EQ(minInterval, kMinInterval);
16531765
EXPECT_EQ(maxInterval, (2 * idleModeDuration));
1766+
EXPECT_EQ(kMaxIntervalCeiling, readHandler.GetSubscriberRequestedMaxInterval());
16541767
}
16551768
engine->Shutdown();
16561769

@@ -1716,6 +1829,7 @@ TEST_F_FROM_FIXTURE(TestReadInteraction, TestICDProcessSubscribeRequestMaxMinInt
17161829

17171830
EXPECT_EQ(minInterval, kMinInterval);
17181831
EXPECT_EQ(maxInterval, kMaxIntervalCeiling);
1832+
EXPECT_EQ(kMaxIntervalCeiling, readHandler.GetSubscriberRequestedMaxInterval());
17191833
}
17201834
engine->Shutdown();
17211835

@@ -1781,6 +1895,7 @@ TEST_F_FROM_FIXTURE(TestReadInteraction, TestICDProcessSubscribeRequestInvalidId
17811895

17821896
EXPECT_EQ(minInterval, kMinInterval);
17831897
EXPECT_EQ(maxInterval, kMaxIntervalCeiling);
1898+
EXPECT_EQ(kMaxIntervalCeiling, readHandler.GetSubscriberRequestedMaxInterval());
17841899
}
17851900
engine->Shutdown();
17861901

@@ -1959,6 +2074,7 @@ TEST_F_FROM_FIXTURE(TestReadInteraction, TestSubscribeRoundtrip)
19592074
uint16_t minInterval;
19602075
uint16_t maxInterval;
19612076
delegate.mpReadHandler->GetReportingIntervals(minInterval, maxInterval);
2077+
EXPECT_EQ(readPrepareParams.mMaxIntervalCeilingSeconds, delegate.mpReadHandler->GetSubscriberRequestedMaxInterval());
19622078

19632079
// Test empty report
19642080
// Advance monotonic timestamp for min interval to elapse
@@ -2028,6 +2144,7 @@ TEST_F_FROM_FIXTURE(TestReadInteraction, TestSubscribeEarlyReport)
20282144
uint16_t minInterval;
20292145
uint16_t maxInterval;
20302146
delegate.mpReadHandler->GetReportingIntervals(minInterval, maxInterval);
2147+
EXPECT_EQ(readPrepareParams.mMaxIntervalCeilingSeconds, delegate.mpReadHandler->GetSubscriberRequestedMaxInterval());
20312148

20322149
EXPECT_EQ(engine->GetNumActiveReadHandlers(ReadHandler::InteractionType::Subscribe), 1u);
20332150

@@ -2760,6 +2877,7 @@ TEST_F_FROM_FIXTURE(TestReadInteraction, TestSubscribeInvalidAttributePathRoundt
27602877
uint16_t minInterval;
27612878
uint16_t maxInterval;
27622879
delegate.mpReadHandler->GetReportingIntervals(minInterval, maxInterval);
2880+
EXPECT_EQ(readPrepareParams.mMaxIntervalCeilingSeconds, delegate.mpReadHandler->GetSubscriberRequestedMaxInterval());
27632881

27642882
// Advance monotonic timestamp for min interval to elapse
27652883
gMockClock.AdvanceMonotonic(System::Clock::Seconds16(maxInterval));

0 commit comments

Comments
 (0)