Skip to content

Commit fc3417e

Browse files
Add some unit tests for ExchangeContext and ExchangeMessageDispatch.
1 parent 3c5b92c commit fc3417e

File tree

2 files changed

+267
-1
lines changed

2 files changed

+267
-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

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

0 commit comments

Comments
 (0)