diff --git a/src/app/tests/TestReadInteraction.cpp b/src/app/tests/TestReadInteraction.cpp index d9e42b9b72228b..637c0df0a02682 100644 --- a/src/app/tests/TestReadInteraction.cpp +++ b/src/app/tests/TestReadInteraction.cpp @@ -319,6 +319,7 @@ class TestReadInteraction static void TestSubscribeRoundtripStatusReportTimeout(nlTestSuite * apSuite, void * apContext); static void TestPostSubscribeRoundtripStatusReportTimeout(nlTestSuite * apSuite, void * apContext); static void TestReadChunkingStatusReportTimeout(nlTestSuite * apSuite, void * apContext); + static void TestReadReportFailure(nlTestSuite * apSuite, void * apContext); static void TestSubscribeRoundtripChunkStatusReportTimeout(nlTestSuite * apSuite, void * apContext); static void TestPostSubscribeRoundtripChunkStatusReportTimeout(nlTestSuite * apSuite, void * apContext); static void TestPostSubscribeRoundtripChunkReportTimeout(nlTestSuite * apSuite, void * apContext); @@ -2531,6 +2532,59 @@ void TestReadInteraction::TestReadChunkingStatusReportTimeout(nlTestSuite * apSu ctx.CreateSessionBobToAlice(); } +// ReadClient sends the read request, but handler fails to send the report with the error, current state +// has not yet moved AwaitingReportResponse, defunct would not call OnReportConfirm, but mNumReportsInFlight has increased by 1, +// then we detect error when failing to send the error and decrease mNumReportsInFlight by 1. +void TestReadInteraction::TestReadReportFailure(nlTestSuite * apSuite, void * apContext) +{ + TestContext & ctx = *static_cast(apContext); + CHIP_ERROR err = CHIP_NO_ERROR; + + Messaging::ReliableMessageMgr * rm = ctx.GetExchangeManager().GetReliableMessageMgr(); + // Shouldn't have anything in the retransmit table when starting the test. + NL_TEST_ASSERT(apSuite, rm->TestGetCountRetransTable() == 0); + + GenerateEvents(apSuite, apContext); + + MockInteractionModelApp delegate; + auto * engine = chip::app::InteractionModelEngine::GetInstance(); + err = engine->Init(&ctx.GetExchangeManager(), &ctx.GetFabricTable()); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); + NL_TEST_ASSERT(apSuite, !delegate.mGotEventResponse); + + chip::app::AttributePathParams attributePathParams[1]; + attributePathParams[0].mEndpointId = Test::kMockEndpoint2; + attributePathParams[0].mClusterId = Test::MockClusterId(3); + attributePathParams[0].mAttributeId = Test::MockAttributeId(1); + + ReadPrepareParams readPrepareParams(ctx.GetSessionBobToAlice()); + readPrepareParams.mpEventPathParamsList = nullptr; + readPrepareParams.mEventPathParamsListSize = 0; + readPrepareParams.mpAttributePathParamsList = attributePathParams; + readPrepareParams.mAttributePathParamsListSize = 1; + + { + app::ReadClient readClient(chip::app::InteractionModelEngine::GetInstance(), &ctx.GetExchangeManager(), delegate, + chip::app::ReadClient::InteractionType::Read); + + ctx.GetLoopback().mNumMessagesToAllowBeforeError = 1; + ctx.GetLoopback().mMessageSendError = CHIP_ERROR_INCORRECT_STATE; + err = readClient.SendRequest(readPrepareParams); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); + + ctx.DrainAndServiceIO(); + NL_TEST_ASSERT(apSuite, engine->GetReportingEngine().GetNumReportsInFlight() == 0); + NL_TEST_ASSERT(apSuite, engine->GetNumActiveReadHandlers() == 0); + + ctx.GetLoopback().mNumMessagesToAllowBeforeError = 0; + ctx.GetLoopback().mMessageSendError = CHIP_NO_ERROR; + } + + NL_TEST_ASSERT(apSuite, engine->GetNumActiveReadClients() == 0); + engine->Shutdown(); + NL_TEST_ASSERT(apSuite, ctx.GetExchangeManager().GetNumActiveExchanges() == 0); +} + void TestReadInteraction::TestSubscribeRoundtripChunkStatusReportTimeout(nlTestSuite * apSuite, void * apContext) { TestContext & ctx = *static_cast(apContext); @@ -4155,6 +4209,7 @@ const nlTest sTests[] = NL_TEST_DEF("TestSubscribeRoundtripStatusReportTimeout", chip::app::TestReadInteraction::TestSubscribeRoundtripStatusReportTimeout), NL_TEST_DEF("TestPostSubscribeRoundtripStatusReportTimeout", chip::app::TestReadInteraction::TestPostSubscribeRoundtripStatusReportTimeout), NL_TEST_DEF("TestReadChunkingStatusReportTimeout", chip::app::TestReadInteraction::TestReadChunkingStatusReportTimeout), + NL_TEST_DEF("TestReadReportFailure", chip::app::TestReadInteraction::TestReadReportFailure), NL_TEST_DEF("TestSubscribeRoundtripChunkStatusReportTimeout", chip::app::TestReadInteraction::TestSubscribeRoundtripChunkStatusReportTimeout), NL_TEST_DEF("TestPostSubscribeRoundtripChunkStatusReportTimeout", chip::app::TestReadInteraction::TestPostSubscribeRoundtripChunkStatusReportTimeout), NL_TEST_DEF("TestPostSubscribeRoundtripChunkReportTimeout", chip::app::TestReadInteraction::TestPostSubscribeRoundtripChunkReportTimeout), diff --git a/src/transport/raw/tests/NetworkTestHelpers.h b/src/transport/raw/tests/NetworkTestHelpers.h index 6de687e7eb6d33..2ee7b9f98061c7 100644 --- a/src/transport/raw/tests/NetworkTestHelpers.h +++ b/src/transport/raw/tests/NetworkTestHelpers.h @@ -103,9 +103,16 @@ class LoopbackTransport : public Transport::Base CHIP_ERROR SendMessage(const Transport::PeerAddress & address, System::PacketBufferHandle && msgBuf) override { - ReturnErrorOnFailure(mMessageSendError); + if (mNumMessagesToAllowBeforeError == 0) + { + ReturnErrorOnFailure(mMessageSendError); + } mSentMessageCount++; bool dropMessage = false; + if (mNumMessagesToAllowBeforeError > 0) + { + --mNumMessagesToAllowBeforeError; + } if (mNumMessagesToAllowBeforeDropping > 0) { --mNumMessagesToAllowBeforeDropping; @@ -141,6 +148,7 @@ class LoopbackTransport : public Transport::Base mDroppedMessageCount = 0; mSentMessageCount = 0; mNumMessagesToAllowBeforeDropping = 0; + mNumMessagesToAllowBeforeError = 0; mMessageSendError = CHIP_NO_ERROR; } @@ -160,6 +168,7 @@ class LoopbackTransport : public Transport::Base uint32_t mDroppedMessageCount = 0; uint32_t mSentMessageCount = 0; uint32_t mNumMessagesToAllowBeforeDropping = 0; + uint32_t mNumMessagesToAllowBeforeError = 0; CHIP_ERROR mMessageSendError = CHIP_NO_ERROR; LoopbackTransportDelegate * mDelegate = nullptr; };