Skip to content

Commit 6ebd53b

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

File tree

2 files changed

+268
-1
lines changed

2 files changed

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

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

0 commit comments

Comments
 (0)