Skip to content

Commit 7585d71

Browse files
Add some unit tests for ExchangeContext and ExchangeMessageDispatch. (#33340)
* Add some unit tests for ExchangeContext and ExchangeMessageDispatch. * Address review comment.
1 parent 6090618 commit 7585d71

File tree

2 files changed

+262
-1
lines changed

2 files changed

+262
-1
lines changed

src/messaging/tests/BUILD.gn

+1-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ static_library("helpers") {
4949
chip_test_suite_using_nltest("tests") {
5050
output_name = "libMessagingLayerTests"
5151

52-
test_sources = []
52+
test_sources = [ "TestExchange.cpp" ]
5353

5454
if (chip_device_platform != "efr32") {
5555
# TODO(#10447): ReliableMessage Test has HF, and ExchangeMgr hangs on EFR32.

src/messaging/tests/TestExchange.cpp

+261
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,261 @@
1+
/*
2+
* Copyright (c) 2024 Project CHIP Authors
3+
* All rights reserved.
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
#include <lib/core/CHIPCore.h>
19+
#include <lib/support/CHIPMem.h>
20+
#include <lib/support/CodeUtils.h>
21+
#include <lib/support/UnitTestContext.h>
22+
#include <lib/support/UnitTestRegistration.h>
23+
#include <messaging/ExchangeContext.h>
24+
#include <messaging/ExchangeMgr.h>
25+
#include <messaging/Flags.h>
26+
#include <messaging/tests/MessagingContext.h>
27+
#include <protocols/Protocols.h>
28+
#include <transport/SessionManager.h>
29+
#include <transport/TransportMgr.h>
30+
31+
#include <nlbyteorder.h>
32+
#include <nlunit-test.h>
33+
34+
#include <errno.h>
35+
#include <utility>
36+
37+
#if CHIP_CRYPTO_PSA
38+
#include "psa/crypto.h"
39+
#endif
40+
41+
namespace {
42+
43+
using namespace chip;
44+
using namespace chip::Inet;
45+
using namespace chip::Transport;
46+
using namespace chip::Messaging;
47+
48+
struct TestContext : Test::LoopbackMessagingContext
49+
{
50+
// TODO Add TearDown function when changing test framework to Pigweed to make it more clear how it works.
51+
// Currently, the TearDown function is from LoopbackMessagingContext
52+
void SetUp() override
53+
{
54+
#if CHIP_CRYPTO_PSA
55+
// TODO: use ASSERT_EQ, once transition to pw_unit_test is complete
56+
VerifyOrDie(psa_crypto_init() == PSA_SUCCESS);
57+
#endif
58+
chip::Test::LoopbackMessagingContext::SetUp();
59+
}
60+
};
61+
62+
enum : uint8_t
63+
{
64+
kMsgType_TEST1 = 0xf0,
65+
kMsgType_TEST2 = 0xf1,
66+
};
67+
68+
class MockExchangeDelegate : public UnsolicitedMessageHandler, public ExchangeDelegate
69+
{
70+
public:
71+
CHIP_ERROR OnUnsolicitedMessageReceived(const PayloadHeader & payloadHeader, ExchangeDelegate *& newDelegate) override
72+
{
73+
newDelegate = this;
74+
return CHIP_NO_ERROR;
75+
}
76+
77+
CHIP_ERROR OnMessageReceived(ExchangeContext * ec, const PayloadHeader & payloadHeader,
78+
System::PacketBufferHandle && buffer) override
79+
{
80+
++mReceivedMessageCount;
81+
if (mKeepExchangeAliveOnMessageReceipt)
82+
{
83+
ec->WillSendMessage();
84+
mExchange = ec;
85+
}
86+
else
87+
{
88+
// Exchange will be closing, so don't hold on to a reference to it.
89+
mExchange = nullptr;
90+
}
91+
return CHIP_NO_ERROR;
92+
}
93+
94+
void OnResponseTimeout(ExchangeContext * ec) override {}
95+
96+
ExchangeMessageDispatch & GetMessageDispatch() override
97+
{
98+
if (mMessageDispatch != nullptr)
99+
{
100+
return *mMessageDispatch;
101+
}
102+
103+
return ExchangeDelegate::GetMessageDispatch();
104+
}
105+
106+
uint32_t mReceivedMessageCount = 0;
107+
bool mKeepExchangeAliveOnMessageReceipt = true;
108+
ExchangeContext * mExchange = nullptr;
109+
ExchangeMessageDispatch * mMessageDispatch = nullptr;
110+
};
111+
112+
// Helper used by several tests. Registers delegate2 as an unsolicited message
113+
// handler, sends a message of type requestMessageType via an exchange that has
114+
// delegate1 as delegate, responds with responseMessageType.
115+
template <typename AfterRequestChecker, typename AfterResponseChecker>
116+
void DoRoundTripTest(nlTestSuite * inSuite, void * inContext, MockExchangeDelegate & delegate1, MockExchangeDelegate & delegate2,
117+
uint8_t requestMessageType, uint8_t responseMessageType, AfterRequestChecker && afterRequestChecker,
118+
AfterResponseChecker && afterResponseChecker)
119+
{
120+
TestContext & ctx = *reinterpret_cast<TestContext *>(inContext);
121+
122+
ExchangeContext * ec1 = ctx.NewExchangeToBob(&delegate1);
123+
NL_TEST_ASSERT(inSuite, ec1 != nullptr);
124+
125+
CHIP_ERROR err = ctx.GetExchangeManager().RegisterUnsolicitedMessageHandlerForType(Protocols::SecureChannel::Id,
126+
requestMessageType, &delegate2);
127+
NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
128+
129+
// To simplify things, skip MRP for all our messages, and make sure we are
130+
// always expecting responses.
131+
constexpr auto sendFlags =
132+
SendFlags(Messaging::SendMessageFlags::kNoAutoRequestAck, Messaging::SendMessageFlags::kExpectResponse);
133+
134+
err = ec1->SendMessage(Protocols::SecureChannel::Id, requestMessageType,
135+
System::PacketBufferHandle::New(System::PacketBuffer::kMaxSize), sendFlags);
136+
NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
137+
138+
ctx.DrainAndServiceIO();
139+
140+
afterRequestChecker();
141+
142+
ExchangeContext * ec2 = delegate2.mExchange;
143+
err = ec2->SendMessage(Protocols::SecureChannel::Id, responseMessageType,
144+
System::PacketBufferHandle::New(System::PacketBuffer::kMaxSize), sendFlags);
145+
NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
146+
147+
ctx.DrainAndServiceIO();
148+
149+
afterResponseChecker();
150+
151+
ec1->Close();
152+
ec2->Close();
153+
154+
err = ctx.GetExchangeManager().UnregisterUnsolicitedMessageHandlerForType(Protocols::SecureChannel::Id, kMsgType_TEST1);
155+
NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
156+
}
157+
158+
void CheckBasicMessageRoundTrip(nlTestSuite * inSuite, void * inContext)
159+
{
160+
MockExchangeDelegate delegate1;
161+
MockExchangeDelegate delegate2;
162+
DoRoundTripTest(
163+
inSuite, inContext, delegate1, delegate2, kMsgType_TEST1, kMsgType_TEST2,
164+
[&] {
165+
NL_TEST_ASSERT(inSuite, delegate1.mReceivedMessageCount == 0);
166+
NL_TEST_ASSERT(inSuite, delegate2.mReceivedMessageCount == 1);
167+
},
168+
[&] {
169+
NL_TEST_ASSERT(inSuite, delegate1.mReceivedMessageCount == 1);
170+
NL_TEST_ASSERT(inSuite, delegate2.mReceivedMessageCount == 1);
171+
});
172+
}
173+
174+
void CheckBasicExchangeMessageDispatch(nlTestSuite * inSuite, void * inContext)
175+
{
176+
class MockMessageDispatch : public ExchangeMessageDispatch
177+
{
178+
bool MessagePermitted(Protocols::Id protocol, uint8_t type) override
179+
{
180+
// Only allow TEST1 messages.
181+
return protocol == Protocols::SecureChannel::Id && type == kMsgType_TEST1;
182+
}
183+
};
184+
185+
MockMessageDispatch dispatch;
186+
187+
{
188+
// Allowed response.
189+
MockExchangeDelegate delegate1;
190+
delegate1.mMessageDispatch = &dispatch;
191+
MockExchangeDelegate delegate2;
192+
193+
DoRoundTripTest(
194+
inSuite, inContext, delegate1, delegate2, kMsgType_TEST1, kMsgType_TEST1,
195+
[&] {
196+
NL_TEST_ASSERT(inSuite, delegate1.mReceivedMessageCount == 0);
197+
NL_TEST_ASSERT(inSuite, delegate2.mReceivedMessageCount == 1);
198+
},
199+
[&] {
200+
NL_TEST_ASSERT(inSuite, delegate1.mReceivedMessageCount == 1);
201+
NL_TEST_ASSERT(inSuite, delegate2.mReceivedMessageCount == 1);
202+
});
203+
}
204+
205+
{
206+
// Disallowed response.
207+
MockExchangeDelegate delegate1;
208+
delegate1.mMessageDispatch = &dispatch;
209+
MockExchangeDelegate delegate2;
210+
211+
DoRoundTripTest(
212+
inSuite, inContext, delegate1, delegate2, kMsgType_TEST1, kMsgType_TEST2,
213+
[&] {
214+
NL_TEST_ASSERT(inSuite, delegate1.mReceivedMessageCount == 0);
215+
NL_TEST_ASSERT(inSuite, delegate2.mReceivedMessageCount == 1);
216+
},
217+
[&] {
218+
NL_TEST_ASSERT(inSuite, delegate1.mReceivedMessageCount == 0);
219+
NL_TEST_ASSERT(inSuite, delegate2.mReceivedMessageCount == 1);
220+
});
221+
}
222+
}
223+
224+
// Test Suite
225+
226+
/**
227+
* Test Suite that lists all the test functions.
228+
*/
229+
// clang-format off
230+
const nlTest sTests[] =
231+
{
232+
NL_TEST_DEF("Test ExchangeContext::SendMessage", CheckBasicMessageRoundTrip),
233+
NL_TEST_DEF("Test ExchangeMessageDispatch", CheckBasicExchangeMessageDispatch),
234+
235+
NL_TEST_SENTINEL()
236+
};
237+
// clang-format on
238+
239+
// clang-format off
240+
nlTestSuite sSuite =
241+
{
242+
"Test-Exchange",
243+
&sTests[0],
244+
TestContext::nlTestSetUpTestSuite,
245+
TestContext::nlTestTearDownTestSuite,
246+
TestContext::nlTestSetUp,
247+
TestContext::nlTestTearDown,
248+
};
249+
// clang-format on
250+
251+
} // namespace
252+
253+
/**
254+
* Main
255+
*/
256+
int TestExchange()
257+
{
258+
return chip::ExecuteTestsWithContext<TestContext>(&sSuite);
259+
}
260+
261+
CHIP_REGISTER_TEST_SUITE(TestExchange);

0 commit comments

Comments
 (0)