Skip to content

Commit

Permalink
Switch a few more unit tests to async message delivery. (#12482)
Browse files Browse the repository at this point in the history
* Create a LoopbackMessagingContext that supports async operation.

Trying to push the setup that AppContext has to a wider range of tests

* Convert TestExchangeMgr to LoopbackMessagingContext.

* Switch TestExchangeMgr to async message delivery.

* Convert TestPASESession to LoopbackMessagingContext.

* Convert TestPASESession to async message delivery.
  • Loading branch information
bzbarsky-apple authored and pull[bot] committed Mar 28, 2022
1 parent f183af5 commit 1702372
Show file tree
Hide file tree
Showing 5 changed files with 147 additions and 149 deletions.
9 changes: 2 additions & 7 deletions src/app/tests/AppTestContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,7 @@ namespace Test {

CHIP_ERROR AppContext::Init()
{
ReturnErrorOnFailure(chip::Platform::MemoryInit());
ReturnErrorOnFailure(mIOContext.Init());
ReturnErrorOnFailure(mTransportManager.Init("LOOPBACK"));
ReturnErrorOnFailure(MessagingContext::Init(&mTransportManager, &mIOContext));
ReturnErrorOnFailure(Super::Init());
ReturnErrorOnFailure(chip::app::InteractionModelEngine::GetInstance()->Init(&GetExchangeManager(), nullptr));

return CHIP_NO_ERROR;
Expand All @@ -37,9 +34,7 @@ CHIP_ERROR AppContext::Init()
CHIP_ERROR AppContext::Shutdown()
{
chip::app::InteractionModelEngine::GetInstance()->Shutdown();
ReturnErrorOnFailure(MessagingContext::Shutdown());
ReturnErrorOnFailure(mIOContext.Shutdown());
chip::Platform::MemoryShutdown();
ReturnErrorOnFailure(Super::Shutdown());

return CHIP_NO_ERROR;
}
Expand Down
82 changes: 6 additions & 76 deletions src/app/tests/AppTestContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,96 +15,26 @@
*/
#pragma once

#include "system/SystemClock.h"
#include <messaging/tests/MessagingContext.h>
#include <transport/raw/tests/NetworkTestHelpers.h>

#include <nlunit-test.h>

namespace chip {
namespace Test {

/**
* @brief The context of test cases for messaging layer. It wil initialize network layer and system layer, and create
* two secure sessions, connected with each other. Exchanges can be created for each secure session.
*/
class AppContext : public MessagingContext
class AppContext : public LoopbackMessagingContext<LoopbackTransport>
{
typedef LoopbackMessagingContext<LoopbackTransport> Super;

public:
/// Initialize the underlying layers and test suite pointer
CHIP_ERROR Init();
/// Initialize the underlying layers.
CHIP_ERROR Init() override;

// Shutdown all layers, finalize operations
CHIP_ERROR Shutdown();

/*
* For unit-tests that simulate end-to-end transmission and reception of messages in loopback mode,
* this mode better replicates a real-functioning stack that correctly handles the processing
* of a transmitted message as an asynchronous, bottom half handler dispatched after the current execution context has
completed.
* This is achieved using SystemLayer::ScheduleWork.
* This should be used in conjunction with the DrainAndServiceIO function below to correctly service and drain the event queue.
*
*/
void EnableAsyncDispatch()
{
auto & impl = mTransportManager.GetTransport().GetImplAtIndex<0>();
impl.EnableAsyncDispatch(&mIOContext.GetSystemLayer());
}

/*
* This drives the servicing of events using the embedded IOContext while there are pending
* messages in the loopback transport's pending message queue. This should run to completion
* in well-behaved logic (i.e there isn't an indefinite ping-pong of messages transmitted back
* and forth).
*
* Consequently, this is guarded with a user-provided timeout to ensure we don't have unit-tests that stall
* in CI due to bugs in the code that is being tested.
*
* This DOES NOT ensure that all pending events are serviced to completion (i.e timers, any ScheduleWork calls).
*
*/
void DrainAndServiceIO(System::Clock::Timeout maxWait = chip::System::Clock::Seconds16(5))
{
auto & impl = mTransportManager.GetTransport().GetImplAtIndex<0>();
System::Clock::Timestamp startTime = System::SystemClock().GetMonotonicTimestamp();

while (impl.HasPendingMessages())
{
mIOContext.DriveIO();
if ((System::SystemClock().GetMonotonicTimestamp() - startTime) >= maxWait)
{
break;
}
}
}

static int Initialize(void * context)
{
auto * ctx = static_cast<AppContext *>(context);
return ctx->Init() == CHIP_NO_ERROR ? SUCCESS : FAILURE;
}

static int InitializeAsync(void * context)
{
auto * ctx = static_cast<AppContext *>(context);

VerifyOrReturnError(ctx->Init() == CHIP_NO_ERROR, FAILURE);
ctx->EnableAsyncDispatch();

return SUCCESS;
}

static int Finalize(void * context)
{
auto * ctx = static_cast<AppContext *>(context);
return ctx->Shutdown() == CHIP_NO_ERROR ? SUCCESS : FAILURE;
}

private:
chip::TransportMgr<chip::Test::LoopbackTransport> mTransportManager;
chip::Test::IOContext mIOContext;
CHIP_ERROR Shutdown() override;
};

} // namespace Test
Expand Down
102 changes: 102 additions & 0 deletions src/messaging/tests/MessagingContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,13 @@
#include <messaging/ExchangeMgr.h>
#include <protocols/secure_channel/MessageCounterManager.h>
#include <protocols/secure_channel/PASESession.h>
#include <system/SystemClock.h>
#include <transport/SessionManager.h>
#include <transport/TransportMgr.h>
#include <transport/raw/tests/NetworkTestHelpers.h>

#include <nlunit-test.h>

namespace chip {
namespace Test {

Expand Down Expand Up @@ -109,5 +112,104 @@ class MessagingContext
FabricIndex mDestFabricIndex = 0;
};

template <typename Transport>
class LoopbackMessagingContext : public MessagingContext
{
public:
virtual ~LoopbackMessagingContext() {}

/// Initialize the underlying layers.
virtual CHIP_ERROR Init()
{
ReturnErrorOnFailure(chip::Platform::MemoryInit());
ReturnErrorOnFailure(mIOContext.Init());
ReturnErrorOnFailure(mTransportManager.Init("LOOPBACK"));
ReturnErrorOnFailure(MessagingContext::Init(&mTransportManager, &mIOContext));
return CHIP_NO_ERROR;
}

// Shutdown all layers, finalize operations
virtual CHIP_ERROR Shutdown()
{
ReturnErrorOnFailure(MessagingContext::Shutdown());
ReturnErrorOnFailure(mIOContext.Shutdown());
chip::Platform::MemoryShutdown();
return CHIP_NO_ERROR;
}

// Init/Shutdown Helpers that can be used directly as the nlTestSuite
// initialize/finalize function.
static int Initialize(void * context)
{
auto * ctx = static_cast<LoopbackMessagingContext *>(context);
return ctx->Init() == CHIP_NO_ERROR ? SUCCESS : FAILURE;
}

static int InitializeAsync(void * context)
{
auto * ctx = static_cast<LoopbackMessagingContext *>(context);

VerifyOrReturnError(ctx->Init() == CHIP_NO_ERROR, FAILURE);
ctx->EnableAsyncDispatch();

return SUCCESS;
}

static int Finalize(void * context)
{
auto * ctx = static_cast<LoopbackMessagingContext *>(context);
return ctx->Shutdown() == CHIP_NO_ERROR ? SUCCESS : FAILURE;
}

Transport & GetLoopback() { return mTransportManager.GetTransport().template GetImplAtIndex<0>(); }

/*
* For unit-tests that simulate end-to-end transmission and reception of messages in loopback mode,
* this mode better replicates a real-functioning stack that correctly handles the processing
* of a transmitted message as an asynchronous, bottom half handler dispatched after the current execution context has
completed.
* This is achieved using SystemLayer::ScheduleWork.
* This should be used in conjunction with the DrainAndServiceIO function below to correctly service and drain the event queue.
*
*/
void EnableAsyncDispatch()
{
auto & impl = GetLoopback();
impl.EnableAsyncDispatch(&mIOContext.GetSystemLayer());
}

/*
* This drives the servicing of events using the embedded IOContext while there are pending
* messages in the loopback transport's pending message queue. This should run to completion
* in well-behaved logic (i.e there isn't an indefinite ping-pong of messages transmitted back
* and forth).
*
* Consequently, this is guarded with a user-provided timeout to ensure we don't have unit-tests that stall
* in CI due to bugs in the code that is being tested.
*
* This DOES NOT ensure that all pending events are serviced to completion (i.e timers, any ScheduleWork calls).
*
*/
void DrainAndServiceIO(System::Clock::Timeout maxWait = chip::System::Clock::Seconds16(5))
{
auto & impl = GetLoopback();
System::Clock::Timestamp startTime = System::SystemClock().GetMonotonicTimestamp();

while (impl.HasPendingMessages())
{
mIOContext.DriveIO();
if ((System::SystemClock().GetMonotonicTimestamp() - startTime) >= maxWait)
{
break;
}
}
}

private:
TransportMgr<Transport> mTransportManager;
Test::IOContext mIOContext;
};

} // namespace Test
} // namespace chip
47 changes: 11 additions & 36 deletions src/messaging/tests/TestExchangeMgr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ using namespace chip::Inet;
using namespace chip::Transport;
using namespace chip::Messaging;

using TestContext = chip::Test::MessagingContext;
using TestContext = chip::Test::LoopbackMessagingContext<Test::LoopbackTransport>;

enum : uint8_t
{
Expand All @@ -59,9 +59,6 @@ enum : uint8_t

TestContext sContext;

TransportMgr<Test::LoopbackTransport> gTransportMgr;
Test::IOContext gIOContext;

class MockAppDelegate : public ExchangeDelegate
{
public:
Expand Down Expand Up @@ -134,6 +131,8 @@ void CheckSessionExpirationBasics(nlTestSuite * inSuite, void * inContext)
err = ec1->SendMessage(Protocols::BDX::Id, kMsgType_TEST1, System::PacketBufferHandle::New(System::PacketBuffer::kMaxSize),
SendFlags(Messaging::SendMessageFlags::kNoAutoRequestAck));
NL_TEST_ASSERT(inSuite, err != CHIP_NO_ERROR);
ctx.DrainAndServiceIO();

NL_TEST_ASSERT(inSuite, !receiveDelegate.IsOnMessageReceivedCalled);
ec1->Close();

Expand All @@ -150,6 +149,8 @@ void CheckSessionExpirationTimeout(nlTestSuite * inSuite, void * inContext)

ec1->SendMessage(Protocols::BDX::Id, kMsgType_TEST1, System::PacketBufferHandle::New(System::PacketBuffer::kMaxSize),
SendFlags(Messaging::SendMessageFlags::kExpectResponse).Set(Messaging::SendMessageFlags::kNoAutoRequestAck));

ctx.DrainAndServiceIO();
NL_TEST_ASSERT(inSuite, !sendDelegate.IsOnResponseTimeoutCalled);

// Expire the session this exchange is supposedly on. This should close the
Expand Down Expand Up @@ -203,13 +204,17 @@ void CheckExchangeMessages(nlTestSuite * inSuite, void * inContext)
// send a malicious packet
ec1->SendMessage(Protocols::BDX::Id, kMsgType_TEST2, System::PacketBufferHandle::New(System::PacketBuffer::kMaxSize),
SendFlags(Messaging::SendMessageFlags::kNoAutoRequestAck));

ctx.DrainAndServiceIO();
NL_TEST_ASSERT(inSuite, !mockUnsolicitedAppDelegate.IsOnMessageReceivedCalled);

ec1 = ctx.NewExchangeToAlice(&mockSolicitedAppDelegate);

// send a good packet
ec1->SendMessage(Protocols::BDX::Id, kMsgType_TEST1, System::PacketBufferHandle::New(System::PacketBuffer::kMaxSize),
SendFlags(Messaging::SendMessageFlags::kNoAutoRequestAck));

ctx.DrainAndServiceIO();
NL_TEST_ASSERT(inSuite, mockUnsolicitedAppDelegate.IsOnMessageReceivedCalled);

err = ctx.GetExchangeManager().UnregisterUnsolicitedMessageHandlerForType(Protocols::BDX::Id, kMsgType_TEST1);
Expand All @@ -234,46 +239,16 @@ const nlTest sTests[] =
};
// clang-format on

int Initialize(void * aContext);
int Finalize(void * aContext);

// clang-format off
nlTestSuite sSuite =
{
"Test-CHIP-ExchangeManager",
&sTests[0],
Initialize,
Finalize
TestContext::InitializeAsync,
TestContext::Finalize
};
// clang-format on

/**
* Initialize the test suite.
*/
int Initialize(void * aContext)
{
// Initialize System memory and resources
VerifyOrReturnError(chip::Platform::MemoryInit() == CHIP_NO_ERROR, FAILURE);
VerifyOrReturnError(gIOContext.Init() == CHIP_NO_ERROR, FAILURE);
VerifyOrReturnError(gTransportMgr.Init("LOOPBACK") == CHIP_NO_ERROR, FAILURE);

auto * ctx = static_cast<TestContext *>(aContext);
VerifyOrReturnError(ctx->Init(&gTransportMgr, &gIOContext) == CHIP_NO_ERROR, FAILURE);

return SUCCESS;
}

/**
* Finalize the test suite.
*/
int Finalize(void * aContext)
{
CHIP_ERROR err = reinterpret_cast<TestContext *>(aContext)->Shutdown();
gIOContext.Shutdown();
chip::Platform::MemoryShutdown();
return (err == CHIP_NO_ERROR) ? SUCCESS : FAILURE;
}

} // namespace

/**
Expand Down
Loading

0 comments on commit 1702372

Please sign in to comment.