add IM status report support for IM read (#9195)

Summry of Changes:
-- When Read Clent receives report data from Read handler, it needs to
send status report to handler per IM spec
-- Add status report generation and process.
-- Add corresponding unit test and integration test.
diff --git a/src/app/BUILD.gn b/src/app/BUILD.gn
index de3f97c..8740c3a 100644
--- a/src/app/BUILD.gn
+++ b/src/app/BUILD.gn
@@ -115,6 +115,7 @@
     ":app_buildconfig",
     "${chip_root}/src/lib/support",
     "${chip_root}/src/messaging",
+    "${chip_root}/src/protocols/secure_channel",
     "${chip_root}/src/system",
     "${nlio_root}:nlio",
   ]
diff --git a/src/app/InteractionModelDelegate.h b/src/app/InteractionModelDelegate.h
index 91e619a..0f6726c 100644
--- a/src/app/InteractionModelDelegate.h
+++ b/src/app/InteractionModelDelegate.h
@@ -195,6 +195,15 @@
         return CHIP_ERROR_NOT_IMPLEMENTED;
     }
 
+    /**
+     * Notification that a read client has completed the read interaction.
+     * @param[in]  apReadClient  A current read client which can identify the read client to the consumer, particularly
+     * during multiple read interactions
+     * @param[in]  aError  notify final error regarding the current read interaction
+     * @retval # CHIP_ERROR_NOT_IMPLEMENTED if not implemented
+     */
+    virtual CHIP_ERROR ReadDone(const ReadClient * apReadClient, CHIP_ERROR aError) { return CHIP_ERROR_NOT_IMPLEMENTED; }
+
     virtual ~InteractionModelDelegate() = default;
 };
 
diff --git a/src/app/InteractionModelEngine.cpp b/src/app/InteractionModelEngine.cpp
index aac9dd5..7d2aa40 100644
--- a/src/app/InteractionModelEngine.cpp
+++ b/src/app/InteractionModelEngine.cpp
@@ -240,9 +240,9 @@
     {
         if (readHandler.IsFree())
         {
-            err = readHandler.Init(mpDelegate);
+            err = readHandler.Init(mpDelegate, apExchangeContext);
             SuccessOrExit(err);
-            err               = readHandler.OnReadRequest(apExchangeContext, std::move(aPayload));
+            err               = readHandler.OnReadRequest(std::move(aPayload));
             apExchangeContext = nullptr;
             break;
         }
diff --git a/src/app/ReadClient.cpp b/src/app/ReadClient.cpp
index 47e2ff5..0c8aa2e 100644
--- a/src/app/ReadClient.cpp
+++ b/src/app/ReadClient.cpp
@@ -25,6 +25,7 @@
 #include <app/AppBuildConfig.h>
 #include <app/InteractionModelEngine.h>
 #include <app/ReadClient.h>
+#include <protocols/secure_channel/StatusReport.h>
 
 namespace chip {
 namespace app {
@@ -52,14 +53,18 @@
 void ReadClient::Shutdown()
 {
     AbortExistingExchangeContext();
-    ShutdownInternal();
+    ShutdownInternal(CHIP_NO_ERROR);
 }
 
-void ReadClient::ShutdownInternal()
+void ReadClient::ShutdownInternal(CHIP_ERROR aError)
 {
     mpExchangeMgr = nullptr;
     mpExchangeCtx = nullptr;
-    mpDelegate    = nullptr;
+    if (mpDelegate != nullptr)
+    {
+        mpDelegate->ReadDone(this, aError);
+        mpDelegate = nullptr;
+    }
     MoveToState(ClientState::Uninitialized);
 }
 
@@ -161,6 +166,40 @@
     return err;
 }
 
+CHIP_ERROR ReadClient::SendStatusReport(CHIP_ERROR aError, bool aExpectResponse)
+{
+    Protocols::SecureChannel::GeneralStatusCode generalCode = Protocols::SecureChannel::GeneralStatusCode::kSuccess;
+    uint32_t protocolId                                     = Protocols::InteractionModel::Id.ToFullyQualifiedSpecForm();
+    uint16_t protocolCode                                   = to_underlying(Protocols::InteractionModel::ProtocolCode::Success);
+    VerifyOrReturnLogError(mpExchangeCtx != nullptr, CHIP_ERROR_INCORRECT_STATE);
+
+    if (aError != CHIP_NO_ERROR)
+    {
+        generalCode  = Protocols::SecureChannel::GeneralStatusCode::kFailure;
+        protocolCode = to_underlying(Protocols::InteractionModel::ProtocolCode::InvalidSubscription);
+    }
+
+    ChipLogProgress(DataManagement, "SendStatusReport with error %s", ErrorStr(aError));
+    Protocols::SecureChannel::StatusReport report(generalCode, protocolId, protocolCode);
+
+    Encoding::LittleEndian::PacketBufferWriter buf(System::PacketBufferHandle::New(kMaxSecureSduLengthBytes));
+    report.WriteToBuffer(buf);
+    System::PacketBufferHandle msgBuf = buf.Finalize();
+    VerifyOrReturnLogError(!msgBuf.IsNull(), CHIP_ERROR_NO_MEMORY);
+
+    if (aExpectResponse)
+    {
+        ReturnLogErrorOnFailure(mpExchangeCtx->SendMessage(Protocols::SecureChannel::MsgType::StatusReport, std::move(msgBuf),
+                                                           Messaging::SendFlags(Messaging::SendMessageFlags::kExpectResponse)));
+    }
+    else
+    {
+        ReturnLogErrorOnFailure(mpExchangeCtx->SendMessage(Protocols::SecureChannel::MsgType::StatusReport, std::move(msgBuf)));
+    }
+
+    return CHIP_NO_ERROR;
+}
+
 CHIP_ERROR ReadClient::GenerateEventPathList(ReadRequest::Builder & aRequest, EventPathParams * apEventPathParamsList,
                                              size_t aEventPathParamsListSize, EventNumber & aEventNumber)
 {
@@ -226,31 +265,25 @@
                                          const PayloadHeader & aPayloadHeader, System::PacketBufferHandle && aPayload)
 {
     CHIP_ERROR err = CHIP_NO_ERROR;
-
-    VerifyOrExit(apExchangeContext == mpExchangeCtx, err = CHIP_ERROR_INCORRECT_STATE);
+    VerifyOrExit(!IsFree(), err = CHIP_ERROR_INCORRECT_STATE);
+    VerifyOrExit(mpDelegate != nullptr, err = CHIP_ERROR_INCORRECT_STATE);
     VerifyOrExit(aPayloadHeader.HasMessageType(Protocols::InteractionModel::MsgType::ReportData),
                  err = CHIP_ERROR_INVALID_MESSAGE_TYPE);
     err = ProcessReportData(std::move(aPayload));
+    SuccessOrExit(err);
+    err = SendStatusReport(err, false);
 
 exit:
-    ChipLogFunctError(err);
-
-    MoveToState(ClientState::Initialized);
-
-    if (mpDelegate != nullptr)
+    if (err != CHIP_NO_ERROR)
     {
-        if (err != CHIP_NO_ERROR)
-        {
-            mpDelegate->ReportError(this, err);
-        }
-        else
-        {
-            mpDelegate->ReportProcessed(this);
-        }
+        mpDelegate->ReportError(this, err);
     }
-
-    // TODO(#7521): Should close it after checking moreChunkedMessages flag is not set.
-    ShutdownInternal();
+    else
+    {
+        mpDelegate->ReportProcessed(this);
+    }
+    ChipLogFunctError(err);
+    ShutdownInternal(err);
 
     return err;
 }
@@ -352,9 +385,12 @@
                     apExchangeContext->GetExchangeId());
     if (nullptr != mpDelegate)
     {
-        mpDelegate->ReportError(this, CHIP_ERROR_TIMEOUT);
+        if (ClientState::AwaitingResponse == mState)
+        {
+            mpDelegate->ReportError(this, CHIP_ERROR_TIMEOUT);
+        }
     }
-    ShutdownInternal();
+    ShutdownInternal(CHIP_ERROR_TIMEOUT);
 }
 
 CHIP_ERROR ReadClient::ProcessAttributeDataList(TLV::TLVReader & aAttributeDataListReader)
diff --git a/src/app/ReadClient.h b/src/app/ReadClient.h
index c77fa9d..dd706f4 100644
--- a/src/app/ReadClient.h
+++ b/src/app/ReadClient.h
@@ -82,6 +82,7 @@
 
     uint64_t GetAppIdentifier() const { return mAppIdentifier; }
     Messaging::ExchangeContext * GetExchangeContext() const { return mpExchangeCtx; }
+    CHIP_ERROR SendStatusReport(CHIP_ERROR aError, bool aExpectResponse);
 
 private:
     friend class TestReadInteraction;
@@ -136,7 +137,7 @@
      * Internal shutdown method that we use when we know what's going on with
      * our exchange and don't need to manually close it.
      */
-    void ShutdownInternal();
+    void ShutdownInternal(CHIP_ERROR aError);
 
     Messaging::ExchangeManager * mpExchangeMgr = nullptr;
     Messaging::ExchangeContext * mpExchangeCtx = nullptr;
diff --git a/src/app/ReadHandler.cpp b/src/app/ReadHandler.cpp
index a624668..5be8d78 100644
--- a/src/app/ReadHandler.cpp
+++ b/src/app/ReadHandler.cpp
@@ -27,23 +27,27 @@
 #include <app/MessageDef/EventPath.h>
 #include <app/ReadHandler.h>
 #include <app/reporting/Engine.h>
+#include <protocols/secure_channel/StatusReport.h>
 
 namespace chip {
 namespace app {
-CHIP_ERROR ReadHandler::Init(InteractionModelDelegate * apDelegate)
+CHIP_ERROR ReadHandler::Init(InteractionModelDelegate * apDelegate, Messaging::ExchangeContext * apExchangeContext)
 {
     CHIP_ERROR err = CHIP_NO_ERROR;
     // Error if already initialized.
-    VerifyOrExit(mpExchangeCtx == nullptr, err = CHIP_ERROR_INCORRECT_STATE);
-    mpExchangeCtx              = nullptr;
+    VerifyOrReturnError(mpExchangeCtx == nullptr, err = CHIP_ERROR_INCORRECT_STATE);
+    mpExchangeCtx              = apExchangeContext;
     mSuppressResponse          = true;
     mpAttributeClusterInfoList = nullptr;
     mpEventClusterInfoList     = nullptr;
     mCurrentPriority           = PriorityLevel::Invalid;
     MoveToState(HandlerState::Initialized);
+    mpDelegate = apDelegate;
+    if (apExchangeContext != nullptr)
+    {
+        apExchangeContext->SetDelegate(this);
+    }
 
-exit:
-    ChipLogFunctError(err);
     return err;
 }
 
@@ -56,16 +60,15 @@
     mpAttributeClusterInfoList = nullptr;
     mpEventClusterInfoList     = nullptr;
     mCurrentPriority           = PriorityLevel::Invalid;
+    mpDelegate                 = nullptr;
 }
 
-CHIP_ERROR ReadHandler::OnReadRequest(Messaging::ExchangeContext * apExchangeContext, System::PacketBufferHandle && aPayload)
+CHIP_ERROR ReadHandler::OnReadRequest(System::PacketBufferHandle && aPayload)
 {
     CHIP_ERROR err = CHIP_NO_ERROR;
     System::PacketBufferHandle response;
 
-    mpExchangeCtx = apExchangeContext;
-    err           = ProcessReadRequest(std::move(aPayload));
-
+    err = ProcessReadRequest(std::move(aPayload));
     if (err != CHIP_NO_ERROR)
     {
         ChipLogFunctError(err);
@@ -75,24 +78,101 @@
     return err;
 }
 
+CHIP_ERROR ReadHandler::OnStatusReport(Messaging::ExchangeContext * apExchangeContext, System::PacketBufferHandle && aPayload)
+{
+    CHIP_ERROR err = CHIP_NO_ERROR;
+    Protocols::SecureChannel::StatusReport statusReport;
+    err = statusReport.Parse(std::move(aPayload));
+    SuccessOrExit(err);
+    ChipLogProgress(DataManagement, "Receive Status Report, protocol id is %" PRIu32 ", protocol code is %" PRIu16,
+                    statusReport.GetProtocolId(), statusReport.GetProtocolCode());
+    if ((statusReport.GetProtocolId() == Protocols::InteractionModel::Id.ToFullyQualifiedSpecForm()) &&
+        (statusReport.GetProtocolCode() == to_underlying(Protocols::InteractionModel::ProtocolCode::Success)))
+    {
+        switch (mState)
+        {
+        case HandlerState::Reporting:
+            InteractionModelEngine::GetInstance()->GetReportingEngine().OnReportConfirm();
+            break;
+        case HandlerState::Reportable:
+        case HandlerState::Initialized:
+        case HandlerState::Uninitialized:
+        default:
+            err = CHIP_ERROR_INCORRECT_STATE;
+            break;
+        }
+    }
+    else
+    {
+        err = CHIP_ERROR_INVALID_ARGUMENT;
+    }
+
+exit:
+    Shutdown();
+    return err;
+}
+
 CHIP_ERROR ReadHandler::SendReportData(System::PacketBufferHandle && aPayload)
 {
     CHIP_ERROR err = CHIP_NO_ERROR;
+    VerifyOrExit(IsReportable(), err = CHIP_ERROR_INCORRECT_STATE);
     VerifyOrExit(mpExchangeCtx != nullptr, err = CHIP_ERROR_INCORRECT_STATE);
 
-    err = mpExchangeCtx->SendMessage(Protocols::InteractionModel::MsgType::ReportData, std::move(aPayload));
-
-    if (err != CHIP_NO_ERROR)
+    err = mpExchangeCtx->SendMessage(Protocols::InteractionModel::MsgType::ReportData, std::move(aPayload),
+                                     Messaging::SendFlags(Messaging::SendMessageFlags::kExpectResponse));
+    if (err == CHIP_NO_ERROR)
     {
-        mpExchangeCtx->Close();
+        MoveToState(HandlerState::Reporting);
     }
 
 exit:
     ChipLogFunctError(err);
-    Shutdown();
+    if (err != CHIP_NO_ERROR)
+    {
+        Shutdown();
+    }
     return err;
 }
 
+CHIP_ERROR ReadHandler::OnMessageReceived(Messaging::ExchangeContext * apExchangeContext, const PacketHeader & aPacketHeader,
+                                          const PayloadHeader & aPayloadHeader, System::PacketBufferHandle && aPayload)
+{
+    CHIP_ERROR err = CHIP_NO_ERROR;
+
+    if (aPayloadHeader.HasMessageType(Protocols::SecureChannel::MsgType::StatusReport))
+    {
+        err = OnStatusReport(apExchangeContext, std::move(aPayload));
+    }
+    else
+    {
+        err = OnUnknownMsgType(apExchangeContext, aPacketHeader, aPayloadHeader, std::move(aPayload));
+    }
+    return err;
+}
+
+CHIP_ERROR ReadHandler::OnUnknownMsgType(Messaging::ExchangeContext * apExchangeContext, const PacketHeader & aPacketHeader,
+                                         const PayloadHeader & aPayloadHeader, System::PacketBufferHandle && aPayload)
+{
+    ChipLogDetail(DataManagement, "Msg type %d not supported", aPayloadHeader.GetMessageType());
+    if (IsReporting())
+    {
+        InteractionModelEngine::GetInstance()->GetReportingEngine().OnReportConfirm();
+    }
+    Shutdown();
+    return CHIP_ERROR_INVALID_MESSAGE_TYPE;
+}
+
+void ReadHandler::OnResponseTimeout(Messaging::ExchangeContext * apExchangeContext)
+{
+    ChipLogProgress(DataManagement, "Time out! failed to receive status response from Exchange: %d",
+                    apExchangeContext->GetExchangeId());
+    if (IsReporting())
+    {
+        InteractionModelEngine::GetInstance()->GetReportingEngine().OnReportConfirm();
+    }
+    Shutdown();
+}
+
 CHIP_ERROR ReadHandler::ProcessReadRequest(System::PacketBufferHandle && aPayload)
 {
     CHIP_ERROR err = CHIP_NO_ERROR;
@@ -279,6 +359,9 @@
 
     case HandlerState::Reportable:
         return "Reportable";
+
+    case HandlerState::Reporting:
+        return "Reporting";
     }
 #endif // CHIP_DETAIL_LOGGING
     return "N/A";
diff --git a/src/app/ReadHandler.h b/src/app/ReadHandler.h
index b677e63..cbaf423 100644
--- a/src/app/ReadHandler.h
+++ b/src/app/ReadHandler.h
@@ -47,7 +47,7 @@
  *         for the relevant data, and sending a reply.
  *
  */
-class ReadHandler
+class ReadHandler : public Messaging::ExchangeDelegate
 {
 public:
     /**
@@ -56,14 +56,12 @@
      *  construction until a call to Shutdown is made to terminate the
      *  instance.
      *
-     *  @param[in]    apDelegate       InteractionModelDelegate set by application.
-     *
      *  @retval #CHIP_ERROR_INCORRECT_STATE If the state is not equal to
      *          kState_NotInitialized.
      *  @retval #CHIP_NO_ERROR On success.
      *
      */
-    CHIP_ERROR Init(InteractionModelDelegate * apDelegate);
+    CHIP_ERROR Init(InteractionModelDelegate * apDelegate, Messaging::ExchangeContext * apExchangeContext);
 
     /**
      *  Shut down the ReadHandler. This terminates this instance
@@ -76,14 +74,11 @@
      *  guarantees that it will call Shutdown on itself when processing is done (including if OnReadRequest
      *  returns an error).
      *
-     *  @param[in]    apExchangeContext    A pointer to the ExchangeContext.
-     *  @param[in]    aPayload             A payload that has read request data
-     *
      *  @retval #Others If fails to process read request
      *  @retval #CHIP_NO_ERROR On success.
      *
      */
-    CHIP_ERROR OnReadRequest(Messaging::ExchangeContext * apExchangeContext, System::PacketBufferHandle && aPayload);
+    CHIP_ERROR OnReadRequest(System::PacketBufferHandle && aPayload);
 
     /**
      *  Send ReportData to initiator
@@ -98,7 +93,7 @@
 
     bool IsFree() const { return mState == HandlerState::Uninitialized; }
     bool IsReportable() const { return mState == HandlerState::Reportable; }
-
+    bool IsReporting() const { return mState == HandlerState::Reporting; }
     virtual ~ReadHandler() = default;
 
     ClusterInfo * GetAttributeClusterInfolist() { return mpAttributeClusterInfoList; }
@@ -121,11 +116,18 @@
         Uninitialized = 0, ///< The handler has not been initialized
         Initialized,       ///< The handler has been initialized and is ready
         Reportable,        ///< The handler has received read request and is waiting for the data to send to be available
+        Reporting,         ///< The handler is reporting
     };
 
     CHIP_ERROR ProcessReadRequest(System::PacketBufferHandle && aPayload);
     CHIP_ERROR ProcessAttributePathList(AttributePathList::Parser & aAttributePathListParser);
     CHIP_ERROR ProcessEventPathList(EventPathList::Parser & aEventPathListParser);
+    CHIP_ERROR OnStatusReport(Messaging::ExchangeContext * apExchangeContext, System::PacketBufferHandle && aPayload);
+    CHIP_ERROR OnMessageReceived(Messaging::ExchangeContext * apExchangeContext, const PacketHeader & aPacketHeader,
+                                 const PayloadHeader & aPayloadHeader, System::PacketBufferHandle && aPayload) override;
+    void OnResponseTimeout(Messaging::ExchangeContext * apExchangeContext) override;
+    CHIP_ERROR OnUnknownMsgType(Messaging::ExchangeContext * apExchangeContext, const PacketHeader & aPacketHeader,
+                                const PayloadHeader & aPayloadHeader, System::PacketBufferHandle && aPayload);
     void MoveToState(const HandlerState aTargetState);
 
     const char * GetStateStr() const;
@@ -147,6 +149,7 @@
 
     // The last schedule event number snapshoted in the beginning when preparing to fill new events to reports
     EventNumber mLastScheduledEventNumber[kNumPriorityLevel];
+    InteractionModelDelegate * mpDelegate = nullptr;
 };
 } // namespace app
 } // namespace chip
diff --git a/src/app/reporting/Engine.cpp b/src/app/reporting/Engine.cpp
index 13b7972..84b9c76 100644
--- a/src/app/reporting/Engine.cpp
+++ b/src/app/reporting/Engine.cpp
@@ -284,14 +284,9 @@
     ChipLogDetail(DataManagement, "<RE> ReportsInFlight = %" PRIu32 " with readHandler %" PRIu32 ", RE has %s", mNumReportsInFlight,
                   mCurReadHandlerIdx, mMoreChunkedMessages ? "more messages" : "no more messages");
 
-    if (!mMoreChunkedMessages)
-    {
-        OnReportConfirm();
-    }
-
 exit:
     ChipLogFunctError(err);
-    if (!mMoreChunkedMessages || err != CHIP_NO_ERROR)
+    if (err != CHIP_NO_ERROR)
     {
         apReadHandler->Shutdown();
     }
diff --git a/src/app/reporting/Engine.h b/src/app/reporting/Engine.h
index f31e0a1..101c05c 100644
--- a/src/app/reporting/Engine.h
+++ b/src/app/reporting/Engine.h
@@ -66,6 +66,13 @@
     void Run();
 
     /**
+     * Should be invoked when the device receives a Status report, or when the Report data request times out.
+     * This allows the engine to do some clean-up.
+     *
+     */
+    void OnReportConfirm();
+
+    /**
      * Main work-horse function that executes the run-loop asynchronously on the CHIP thread
      */
     CHIP_ERROR ScheduleRun();
@@ -90,13 +97,6 @@
     CHIP_ERROR SendReport(ReadHandler * apReadHandler, System::PacketBufferHandle && aPayload);
 
     /**
-     * Should be invoked when the device receives a Status report, or when the Report data request times out.
-     * This allows the engine to do some clean-up.
-     *
-     */
-    void OnReportConfirm();
-
-    /**
      * Generate and send the report data request when there exists subscription or read request
      *
      */
diff --git a/src/app/tests/TestReadInteraction.cpp b/src/app/tests/TestReadInteraction.cpp
index 9851c35..4c9a27a 100644
--- a/src/app/tests/TestReadInteraction.cpp
+++ b/src/app/tests/TestReadInteraction.cpp
@@ -151,7 +151,17 @@
         return err;
     }
 
-    bool mGotEventResponse = false;
+    CHIP_ERROR ReadDone(const chip::app::ReadClient * apReadClient, CHIP_ERROR aError) override
+    {
+        if (aError == CHIP_NO_ERROR)
+        {
+            mGotReadStatusResponse = true;
+        }
+        return aError;
+    }
+
+    bool mGotEventResponse      = false;
+    bool mGotReadStatusResponse = false;
 };
 } // namespace
 
@@ -288,8 +298,9 @@
     auto * engine = chip::app::InteractionModelEngine::GetInstance();
     err           = engine->Init(&ctx.GetExchangeManager(), &delegate);
     NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR);
-
-    readHandler.Init(nullptr);
+    Messaging::ExchangeManager exchangeManager;
+    Messaging::ExchangeContext * exchangeCtx = exchangeManager.NewContext(SessionHandle(), nullptr);
+    readHandler.Init(nullptr, exchangeCtx);
 
     GenerateReportData(apSuite, apContext, reportDatabuf);
     err = readHandler.SendReportData(std::move(reportDatabuf));
@@ -319,7 +330,7 @@
     err = writer.Finalize(&readRequestbuf);
     NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR);
 
-    err = readHandler.OnReadRequest(nullptr, std::move(readRequestbuf));
+    err = readHandler.OnReadRequest(std::move(readRequestbuf));
     NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR);
 
     engine->Shutdown();
@@ -416,7 +427,9 @@
     auto * engine = chip::app::InteractionModelEngine::GetInstance();
     err           = engine->Init(&ctx.GetExchangeManager(), &delegate);
     NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR);
-    readHandler.Init(nullptr);
+    Messaging::ExchangeManager exchangeManager;
+    Messaging::ExchangeContext * exchangeCtx = exchangeManager.NewContext(SessionHandle(), nullptr);
+    readHandler.Init(nullptr, exchangeCtx);
 
     GenerateReportData(apSuite, apContext, reportDatabuf);
     err = readHandler.SendReportData(std::move(reportDatabuf));
@@ -442,7 +455,7 @@
     err = writer.Finalize(&readRequestbuf);
     NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR);
 
-    err = readHandler.OnReadRequest(nullptr, std::move(readRequestbuf));
+    err = readHandler.OnReadRequest(std::move(readRequestbuf));
     NL_TEST_ASSERT(apSuite, err == CHIP_ERROR_IM_MALFORMED_ATTRIBUTE_PATH);
     engine->Shutdown();
 }
@@ -565,6 +578,7 @@
     err           = engine->Init(&ctx.GetExchangeManager(), &delegate);
     NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR);
     NL_TEST_ASSERT(apSuite, !delegate.mGotEventResponse);
+    NL_TEST_ASSERT(apSuite, !delegate.mGotReadStatusResponse);
 
     chip::app::EventPathParams eventPathParams[2];
     eventPathParams[0].mNodeId     = kTestNodeId;
@@ -584,6 +598,7 @@
 
     InteractionModelEngine::GetInstance()->GetReportingEngine().Run();
     NL_TEST_ASSERT(apSuite, delegate.mGotEventResponse);
+    NL_TEST_ASSERT(apSuite, delegate.mGotReadStatusResponse);
 
     // By now we should have closed all exchanges and sent all pending acks, so
     // there should be no queued-up things in the retransmit table.
diff --git a/src/app/tests/TestReportingEngine.cpp b/src/app/tests/TestReportingEngine.cpp
index 909d766..b0be734 100644
--- a/src/app/tests/TestReportingEngine.cpp
+++ b/src/app/tests/TestReportingEngine.cpp
@@ -133,10 +133,10 @@
     err = writer.Finalize(&readRequestbuf);
     NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR);
 
-    readHandler.OnReadRequest(exchangeCtx, std::move(readRequestbuf));
+    readHandler.OnReadRequest(std::move(readRequestbuf));
     reportingEngine.Init();
     err = reportingEngine.BuildAndSendSingleReportData(&readHandler);
-    NL_TEST_ASSERT(apSuite, err == CHIP_ERROR_NOT_CONNECTED);
+    NL_TEST_ASSERT(apSuite, err == CHIP_ERROR_INCORRECT_STATE);
 }
 } // namespace reporting
 } // namespace app
diff --git a/src/app/tests/integration/chip_im_initiator.cpp b/src/app/tests/integration/chip_im_initiator.cpp
index cb5a9dc..40d7cfd 100644
--- a/src/app/tests/integration/chip_im_initiator.cpp
+++ b/src/app/tests/integration/chip_im_initiator.cpp
@@ -437,16 +437,20 @@
     {
         return CHIP_NO_ERROR;
     }
-    CHIP_ERROR ReportProcessed(const chip::app::ReadClient * apReadClient) override
-    {
-        HandleReadComplete();
-        return CHIP_NO_ERROR;
-    }
+    CHIP_ERROR ReportProcessed(const chip::app::ReadClient * apReadClient) override { return CHIP_NO_ERROR; }
     CHIP_ERROR ReportError(const chip::app::ReadClient * apReadClient, CHIP_ERROR aError) override
     {
         printf("ReportError with err %" CHIP_ERROR_FORMAT, aError.Format());
         return CHIP_NO_ERROR;
     }
+    CHIP_ERROR ReadDone(const chip::app::ReadClient * apReadClient, CHIP_ERROR aError) override
+    {
+        if (aError == CHIP_NO_ERROR)
+        {
+            HandleReadComplete();
+        }
+        return aError;
+    }
     CHIP_ERROR CommandResponseStatus(const chip::app::CommandSender * apCommandSender,
                                      const chip::Protocols::SecureChannel::GeneralStatusCode aGeneralCode,
                                      const uint32_t aProtocolId, const uint16_t aProtocolCode, const chip::EndpointId aEndpointId,