@@ -338,6 +338,7 @@ class TestReadInteraction
338
338
static void TestReadHandlerInvalidSubscribeRequest (nlTestSuite * apSuite, void * apContext);
339
339
static void TestSubscribeInvalidateFabric (nlTestSuite * apSuite, void * apContext);
340
340
static void TestShutdownSubscription (nlTestSuite * apSuite, void * apContext);
341
+ static void TestSubscriptionReportWithDefunctSession (nlTestSuite * apSuite, void * apContext);
341
342
static void TestReadHandlerMalformedSubscribeRequest (nlTestSuite * apSuite, void * apContext);
342
343
343
344
private:
@@ -4096,6 +4097,93 @@ void TestReadInteraction::TestShutdownSubscription(nlTestSuite * apSuite, void *
4096
4097
NL_TEST_ASSERT (apSuite, ctx.GetExchangeManager ().GetNumActiveExchanges () == 0 );
4097
4098
}
4098
4099
4100
+ /* *
4101
+ * Tests what happens when a subscription tries to deliver reports but the
4102
+ * session it has is defunct. Makes sure we correctly tear down the ReadHandler
4103
+ * and don't increment the "reports in flight" count.
4104
+ */
4105
+ void TestReadInteraction::TestSubscriptionReportWithDefunctSession (nlTestSuite * apSuite, void * apContext)
4106
+ {
4107
+ TestContext & ctx = *static_cast <TestContext *>(apContext);
4108
+ CHIP_ERROR err = CHIP_NO_ERROR;
4109
+
4110
+ Messaging::ReliableMessageMgr * rm = ctx.GetExchangeManager ().GetReliableMessageMgr ();
4111
+ // Shouldn't have anything in the retransmit table when starting the test.
4112
+ NL_TEST_ASSERT (apSuite, rm->TestGetCountRetransTable () == 0 );
4113
+
4114
+ MockInteractionModelApp delegate;
4115
+ auto * engine = chip::app::InteractionModelEngine::GetInstance ();
4116
+ err = engine->Init (&ctx.GetExchangeManager (), &ctx.GetFabricTable ());
4117
+ NL_TEST_ASSERT (apSuite, err == CHIP_NO_ERROR);
4118
+
4119
+ ReadPrepareParams readPrepareParams (ctx.GetSessionBobToAlice ());
4120
+ readPrepareParams.mpAttributePathParamsList = new chip::app::AttributePathParams[1 ];
4121
+ readPrepareParams.mAttributePathParamsListSize = 1 ;
4122
+
4123
+ AttributePathParams subscribePath (Test::kMockEndpoint3 , Test::MockClusterId (2 ), Test::MockAttributeId (4 ));
4124
+ readPrepareParams.mpAttributePathParamsList [0 ] = subscribePath;
4125
+
4126
+ readPrepareParams.mMinIntervalFloorSeconds = 0 ;
4127
+ readPrepareParams.mMaxIntervalCeilingSeconds = 0 ;
4128
+
4129
+ {
4130
+ app::ReadClient readClient (chip::app::InteractionModelEngine::GetInstance (), &ctx.GetExchangeManager (), delegate,
4131
+ chip::app::ReadClient::InteractionType::Subscribe);
4132
+
4133
+ delegate.mGotReport = false ;
4134
+
4135
+ err = readClient.SendSubscribeRequest (std::move (readPrepareParams));
4136
+ NL_TEST_ASSERT (apSuite, err == CHIP_NO_ERROR);
4137
+
4138
+ ctx.DrainAndServiceIO ();
4139
+
4140
+ NL_TEST_ASSERT (apSuite, delegate.mGotReport );
4141
+ NL_TEST_ASSERT (apSuite, engine->GetNumActiveReadHandlers (ReadHandler::InteractionType::Subscribe) == 1 );
4142
+ NL_TEST_ASSERT (apSuite, engine->GetNumActiveReadHandlers (ReadHandler::InteractionType::Read) == 0 );
4143
+ NL_TEST_ASSERT (apSuite, engine->GetReportingEngine ().GetNumReportsInFlight () == 0 );
4144
+
4145
+ NL_TEST_ASSERT (apSuite, engine->ActiveHandlerAt (0 ) != nullptr );
4146
+ auto * readHandler = engine->ActiveHandlerAt (0 );
4147
+
4148
+ // Verify that the session we will reset later is the one we will mess
4149
+ // with now.
4150
+ NL_TEST_ASSERT (apSuite, SessionHandle (*readHandler->GetSession ()) == ctx.GetSessionAliceToBob ());
4151
+
4152
+ // Test that we send reports as needed.
4153
+ readHandler->mFlags .Set (ReadHandler::ReadHandlerFlags::HoldReport, false );
4154
+ delegate.mGotReport = false ;
4155
+ engine->GetReportingEngine ().SetDirty (subscribePath);
4156
+
4157
+ ctx.DrainAndServiceIO ();
4158
+
4159
+ NL_TEST_ASSERT (apSuite, delegate.mGotReport );
4160
+ NL_TEST_ASSERT (apSuite, engine->GetNumActiveReadHandlers (ReadHandler::InteractionType::Subscribe) == 1 );
4161
+ NL_TEST_ASSERT (apSuite, engine->GetNumActiveReadHandlers (ReadHandler::InteractionType::Read) == 0 );
4162
+ NL_TEST_ASSERT (apSuite, engine->GetReportingEngine ().GetNumReportsInFlight () == 0 );
4163
+
4164
+ // Test that if the session is defunct we don't send reports and clean
4165
+ // up properly.
4166
+ readHandler->GetSession ()->MarkAsDefunct ();
4167
+ readHandler->mFlags .Set (ReadHandler::ReadHandlerFlags::HoldReport, false );
4168
+ delegate.mGotReport = false ;
4169
+ engine->GetReportingEngine ().SetDirty (subscribePath);
4170
+
4171
+ ctx.DrainAndServiceIO ();
4172
+
4173
+ NL_TEST_ASSERT (apSuite, !delegate.mGotReport );
4174
+ NL_TEST_ASSERT (apSuite, engine->GetNumActiveReadHandlers (ReadHandler::InteractionType::Subscribe) == 0 );
4175
+ NL_TEST_ASSERT (apSuite, engine->GetNumActiveReadHandlers (ReadHandler::InteractionType::Read) == 0 );
4176
+ NL_TEST_ASSERT (apSuite, engine->GetReportingEngine ().GetNumReportsInFlight () == 0 );
4177
+ }
4178
+ engine->Shutdown ();
4179
+ NL_TEST_ASSERT (apSuite, engine->GetNumActiveReadClients () == 0 );
4180
+ NL_TEST_ASSERT (apSuite, ctx.GetExchangeManager ().GetNumActiveExchanges () == 0 );
4181
+
4182
+ // Get rid of our defunct session.
4183
+ ctx.ExpireSessionAliceToBob ();
4184
+ ctx.CreateSessionAliceToBob ();
4185
+ }
4186
+
4099
4187
} // namespace app
4100
4188
} // namespace chip
4101
4189
@@ -4159,6 +4247,7 @@ const nlTest sTests[] =
4159
4247
NL_TEST_DEF (" TestPostSubscribeRoundtripChunkStatusReportTimeout" , chip::app::TestReadInteraction::TestPostSubscribeRoundtripChunkStatusReportTimeout),
4160
4248
NL_TEST_DEF (" TestPostSubscribeRoundtripChunkReportTimeout" , chip::app::TestReadInteraction::TestPostSubscribeRoundtripChunkReportTimeout),
4161
4249
NL_TEST_DEF (" TestReadShutdown" , chip::app::TestReadInteraction::TestReadShutdown),
4250
+ NL_TEST_DEF (" TestSubscriptionReportWithDefunctSession" , chip::app::TestReadInteraction::TestSubscriptionReportWithDefunctSession),
4162
4251
NL_TEST_SENTINEL ()
4163
4252
};
4164
4253
// clang-format on
0 commit comments