|
23 | 23 |
|
24 | 24 | #include "NetworkTestHelpers.h"
|
25 | 25 |
|
| 26 | +#include <gtest/gtest.h> |
26 | 27 | #include <lib/core/CHIPCore.h>
|
27 | 28 | #include <lib/core/CHIPEncoding.h>
|
28 | 29 | #include <lib/support/CHIPMem.h>
|
|
32 | 33 | #include <transport/TransportMgr.h>
|
33 | 34 | #include <transport/raw/TCP.h>
|
34 | 35 |
|
35 |
| -#include <gtest/gtest.h> |
36 |
| - |
37 | 36 | #include <errno.h>
|
38 | 37 | #include <stdlib.h>
|
39 | 38 | #include <string.h>
|
40 | 39 | #include <utility>
|
41 | 40 |
|
42 | 41 | using namespace chip;
|
| 42 | +using namespace chip::Test; |
43 | 43 | using namespace chip::Inet;
|
44 | 44 |
|
45 |
| -namespace { |
46 |
| - |
47 | 45 | constexpr size_t kMaxTcpActiveConnectionCount = 4;
|
48 | 46 | constexpr size_t kMaxTcpPendingPackets = 4;
|
49 | 47 | constexpr uint16_t kPacketSizeBytes = static_cast<uint16_t>(sizeof(uint16_t));
|
50 | 48 |
|
51 | 49 | using TCPImpl = Transport::TCP<kMaxTcpActiveConnectionCount, kMaxTcpPendingPackets>;
|
52 | 50 |
|
| 51 | +namespace chip { |
| 52 | +namespace Transport { |
| 53 | +class TCPTestAccess |
| 54 | +{ |
| 55 | +public: |
| 56 | + static void * FindActiveConnection(TCPImpl & tcp, Transport::PeerAddress & lPeerAddress) |
| 57 | + { |
| 58 | + return tcp.FindActiveConnection(lPeerAddress); |
| 59 | + } |
| 60 | + static TCPEndPoint * GetEndpoint(void * state) { return static_cast<TCPBase::ActiveConnectionState *>(state)->mEndPoint; } |
| 61 | + |
| 62 | + static CHIP_ERROR ProcessReceivedBuffer(TCPImpl & tcp, TCPEndPoint * endPoint, const PeerAddress & peerAddress, |
| 63 | + System::PacketBufferHandle && buffer) |
| 64 | + { |
| 65 | + return tcp.ProcessReceivedBuffer(endPoint, peerAddress, std::move(buffer)); |
| 66 | + } |
| 67 | +}; |
| 68 | +} // namespace Transport |
| 69 | +} // namespace chip |
| 70 | + |
| 71 | +namespace { |
| 72 | + |
53 | 73 | constexpr NodeId kSourceNodeId = 123654;
|
54 | 74 | constexpr NodeId kDestinationNodeId = 111222333;
|
55 | 75 | constexpr uint32_t kMessageCounter = 18;
|
56 | 76 |
|
57 |
| -using TestContext = chip::Test::IOContext; |
58 |
| - |
59 | 77 | const char PAYLOAD[] = "Hello!";
|
60 | 78 |
|
61 | 79 | class MockTransportMgrDelegate : public chip::TransportMgrDelegate
|
62 | 80 | {
|
63 | 81 | public:
|
64 | 82 | typedef int (*MessageReceivedCallback)(const uint8_t * message, size_t length, int count, void * data);
|
65 | 83 |
|
66 |
| - MockTransportMgrDelegate(TestContext * inContext) : mContext(inContext), mCallback(nullptr), mCallbackData(nullptr) {} |
| 84 | + MockTransportMgrDelegate(IOContext * inContext) : mContext(inContext), mCallback(nullptr), mCallbackData(nullptr) {} |
67 | 85 | ~MockTransportMgrDelegate() override {}
|
68 | 86 |
|
69 | 87 | void SetCallback(MessageReceivedCallback callback = nullptr, void * callback_data = nullptr)
|
@@ -151,66 +169,12 @@ class MockTransportMgrDelegate : public chip::TransportMgrDelegate
|
151 | 169 | int mReceiveHandlerCallCount = 0;
|
152 | 170 |
|
153 | 171 | private:
|
154 |
| - TestContext * mContext; |
| 172 | + IOContext * mContext; |
155 | 173 | MessageReceivedCallback mCallback;
|
156 | 174 | void * mCallbackData;
|
157 | 175 | TransportMgrBase mTransportMgrBase;
|
158 | 176 | };
|
159 | 177 |
|
160 |
| -/////////////////////////// Init test |
161 |
| - |
162 |
| -class TestTCP : public ::testing::Test, public chip::Test::IOContext |
163 |
| -{ |
164 |
| -protected: |
165 |
| - void SetUp() { ASSERT_EQ(Init(), CHIP_NO_ERROR); } |
166 |
| - void TearDown() { Shutdown(); } |
167 |
| - |
168 |
| - void CheckSimpleInitTest(Inet::IPAddressType type) |
169 |
| - { |
170 |
| - TCPImpl tcp; |
171 |
| - |
172 |
| - CHIP_ERROR err = tcp.Init(Transport::TcpListenParameters(GetTCPEndPointManager()).SetAddressType(type)); |
173 |
| - |
174 |
| - EXPECT_EQ(err, CHIP_NO_ERROR); |
175 |
| - } |
176 |
| - |
177 |
| - void CheckMessageTest(const IPAddress & addr) |
178 |
| - { |
179 |
| - TCPImpl tcp; |
180 |
| - |
181 |
| - MockTransportMgrDelegate gMockTransportMgrDelegate(this); |
182 |
| - gMockTransportMgrDelegate.InitializeMessageTest(tcp, addr); |
183 |
| - gMockTransportMgrDelegate.SingleMessageTest(tcp, addr); |
184 |
| - gMockTransportMgrDelegate.FinalizeMessageTest(tcp, addr); |
185 |
| - } |
186 |
| -}; |
187 |
| - |
188 |
| -#if INET_CONFIG_ENABLE_IPV4 |
189 |
| -TEST_F(TestTCP, CheckSimpleInitTest4) |
190 |
| -{ |
191 |
| - CheckSimpleInitTest(IPAddressType::kIPv4); |
192 |
| -} |
193 |
| - |
194 |
| -TEST_F(TestTCP, CheckMessageTest4) |
195 |
| -{ |
196 |
| - IPAddress addr; |
197 |
| - IPAddress::FromString("127.0.0.1", addr); |
198 |
| - CheckMessageTest(addr); |
199 |
| -} |
200 |
| -#endif |
201 |
| - |
202 |
| -TEST_F(TestTCP, CheckSimpleInitTest6) |
203 |
| -{ |
204 |
| - CheckSimpleInitTest(IPAddressType::kIPv6); |
205 |
| -} |
206 |
| - |
207 |
| -TEST_F(TestTCP, CheckMessageTest6) |
208 |
| -{ |
209 |
| - IPAddress addr; |
210 |
| - IPAddress::FromString("::1", addr); |
211 |
| - CheckMessageTest(addr); |
212 |
| -} |
213 |
| - |
214 | 178 | // Generates a packet buffer or a chain of packet buffers for a single message.
|
215 | 179 | struct TestData
|
216 | 180 | {
|
@@ -338,108 +302,177 @@ void TestData::Free()
|
338 | 302 | mMessageOffset = 0;
|
339 | 303 | }
|
340 | 304 |
|
341 |
| -int TestDataCallbackCheck(const uint8_t * message, size_t length, int count, void * data) |
| 305 | +// Test Context |
| 306 | + |
| 307 | +class TestTCP : public ::testing::Test |
342 | 308 | {
|
343 |
| - if (data == nullptr) |
344 |
| - { |
345 |
| - return -1; |
346 |
| - } |
347 |
| - TestData * currentData = static_cast<TestData *>(data) + count; |
348 |
| - if (currentData->mPayload == nullptr) |
349 |
| - { |
350 |
| - return -2; |
351 |
| - } |
352 |
| - if (currentData->mMessageLength != length) |
| 309 | +public: |
| 310 | + // Performs shared setup for all tests in the test suite |
| 311 | + static void SetUpTestSuite() |
353 | 312 | {
|
354 |
| - return -3; |
| 313 | + if (mIOContext == nullptr) |
| 314 | + { |
| 315 | + mIOContext = new IOContext(); |
| 316 | + ASSERT_NE(mIOContext, nullptr); |
| 317 | + } |
| 318 | + ASSERT_EQ(mIOContext->Init(), CHIP_NO_ERROR); |
355 | 319 | }
|
356 |
| - if (memcmp(currentData->mPayload + currentData->mMessageOffset, message, length) != 0) |
| 320 | + |
| 321 | + // Performs shared teardown for all tests in the test suite |
| 322 | + static void TearDownTestSuite() |
357 | 323 | {
|
358 |
| - return -4; |
| 324 | + if (mIOContext != nullptr) |
| 325 | + { |
| 326 | + mIOContext->Shutdown(); |
| 327 | + delete mIOContext; |
| 328 | + mIOContext = nullptr; |
| 329 | + } |
359 | 330 | }
|
360 |
| - return 0; |
361 |
| -} |
362 | 331 |
|
363 |
| -} // namespace |
| 332 | +protected: |
| 333 | + static IOContext * mIOContext; |
364 | 334 |
|
365 |
| -namespace chip { |
366 |
| -namespace Transport { |
367 |
| -class TCPTest |
368 |
| -{ |
369 |
| -public: |
370 |
| - static void CheckProcessReceivedBuffer(TestContext * ctx) |
| 335 | + void CheckSimpleInitTest(IPAddressType type) |
371 | 336 | {
|
372 | 337 | TCPImpl tcp;
|
373 | 338 |
|
374 |
| - IPAddress addr; |
375 |
| - IPAddress::FromString("::1", addr); |
| 339 | + CHIP_ERROR err = tcp.Init(Transport::TcpListenParameters(mIOContext->GetTCPEndPointManager()).SetAddressType(type)); |
376 | 340 |
|
377 |
| - MockTransportMgrDelegate gMockTransportMgrDelegate(ctx); |
378 |
| - gMockTransportMgrDelegate.InitializeMessageTest(tcp, addr); |
| 341 | + EXPECT_EQ(err, CHIP_NO_ERROR); |
| 342 | + } |
| 343 | + |
| 344 | + void CheckMessageTest(const IPAddress & addr) |
| 345 | + { |
| 346 | + TCPImpl tcp; |
379 | 347 |
|
380 |
| - // Send a packet to get TCP going, so that we can find a TCPEndPoint to pass to ProcessReceivedBuffer. |
381 |
| - // (The current TCPEndPoint implementation is not effectively mockable.) |
| 348 | + MockTransportMgrDelegate gMockTransportMgrDelegate(mIOContext); |
| 349 | + gMockTransportMgrDelegate.InitializeMessageTest(tcp, addr); |
382 | 350 | gMockTransportMgrDelegate.SingleMessageTest(tcp, addr);
|
| 351 | + gMockTransportMgrDelegate.FinalizeMessageTest(tcp, addr); |
| 352 | + } |
383 | 353 |
|
384 |
| - Transport::PeerAddress lPeerAddress = Transport::PeerAddress::TCP(addr); |
385 |
| - TCPBase::ActiveConnectionState * state = tcp.FindActiveConnection(lPeerAddress); |
386 |
| - ASSERT_NE(state, nullptr); |
387 |
| - Inet::TCPEndPoint * lEndPoint = state->mEndPoint; |
388 |
| - ASSERT_NE(lEndPoint, nullptr); |
| 354 | + static int TestDataCallbackCheck(const uint8_t * message, size_t length, int count, void * data) |
| 355 | + { |
| 356 | + if (data == nullptr) |
| 357 | + { |
| 358 | + return -1; |
| 359 | + } |
| 360 | + TestData * currentData = static_cast<TestData *>(data) + count; |
| 361 | + if (currentData->mPayload == nullptr) |
| 362 | + { |
| 363 | + return -2; |
| 364 | + } |
| 365 | + if (currentData->mMessageLength != length) |
| 366 | + { |
| 367 | + return -3; |
| 368 | + } |
| 369 | + if (memcmp(currentData->mPayload + currentData->mMessageOffset, message, length) != 0) |
| 370 | + { |
| 371 | + return -4; |
| 372 | + } |
| 373 | + return 0; |
| 374 | + } |
| 375 | +}; |
389 | 376 |
|
390 |
| - CHIP_ERROR err = CHIP_NO_ERROR; |
391 |
| - TestData testData[2]; |
392 |
| - gMockTransportMgrDelegate.SetCallback(TestDataCallbackCheck, testData); |
| 377 | +IOContext * TestTCP::mIOContext = nullptr; |
393 | 378 |
|
394 |
| - // Test a single packet buffer. |
395 |
| - gMockTransportMgrDelegate.mReceiveHandlerCallCount = 0; |
396 |
| - EXPECT_TRUE(testData[0].Init((const uint16_t[]){ 111, 0 })); |
397 |
| - err = tcp.ProcessReceivedBuffer(lEndPoint, lPeerAddress, std::move(testData[0].mHandle)); |
398 |
| - EXPECT_EQ(err, CHIP_NO_ERROR); |
399 |
| - EXPECT_EQ(gMockTransportMgrDelegate.mReceiveHandlerCallCount, 1); |
| 379 | +// IPv4 Tests |
400 | 380 |
|
401 |
| - // Test a message in a chain of three packet buffers. The message length is split across buffers. |
402 |
| - gMockTransportMgrDelegate.mReceiveHandlerCallCount = 0; |
403 |
| - EXPECT_TRUE(testData[0].Init((const uint16_t[]){ 1, 122, 123, 0 })); |
404 |
| - err = tcp.ProcessReceivedBuffer(lEndPoint, lPeerAddress, std::move(testData[0].mHandle)); |
405 |
| - EXPECT_EQ(err, CHIP_NO_ERROR); |
406 |
| - EXPECT_EQ(gMockTransportMgrDelegate.mReceiveHandlerCallCount, 1); |
407 |
| - |
408 |
| - // Test two messages in a chain. |
409 |
| - gMockTransportMgrDelegate.mReceiveHandlerCallCount = 0; |
410 |
| - EXPECT_TRUE(testData[0].Init((const uint16_t[]){ 131, 0 })); |
411 |
| - EXPECT_TRUE(testData[1].Init((const uint16_t[]){ 132, 0 })); |
412 |
| - testData[0].mHandle->AddToEnd(std::move(testData[1].mHandle)); |
413 |
| - err = tcp.ProcessReceivedBuffer(lEndPoint, lPeerAddress, std::move(testData[0].mHandle)); |
414 |
| - EXPECT_EQ(err, CHIP_NO_ERROR); |
415 |
| - EXPECT_EQ(gMockTransportMgrDelegate.mReceiveHandlerCallCount, 2); |
416 |
| - |
417 |
| - // Test a chain of two messages, each a chain. |
418 |
| - gMockTransportMgrDelegate.mReceiveHandlerCallCount = 0; |
419 |
| - EXPECT_TRUE(testData[0].Init((const uint16_t[]){ 141, 142, 0 })); |
420 |
| - EXPECT_TRUE(testData[1].Init((const uint16_t[]){ 143, 144, 0 })); |
421 |
| - testData[0].mHandle->AddToEnd(std::move(testData[1].mHandle)); |
422 |
| - err = tcp.ProcessReceivedBuffer(lEndPoint, lPeerAddress, std::move(testData[0].mHandle)); |
423 |
| - EXPECT_EQ(err, CHIP_NO_ERROR); |
424 |
| - EXPECT_EQ(gMockTransportMgrDelegate.mReceiveHandlerCallCount, 2); |
425 |
| - |
426 |
| - // Test a message that is too large to coalesce into a single packet buffer. |
427 |
| - gMockTransportMgrDelegate.mReceiveHandlerCallCount = 0; |
428 |
| - gMockTransportMgrDelegate.SetCallback(TestDataCallbackCheck, &testData[1]); |
429 |
| - EXPECT_TRUE(testData[0].Init((const uint16_t[]){ 51, System::PacketBuffer::kMaxSizeWithoutReserve, 0 })); |
430 |
| - // Sending only the first buffer of the long chain. This should be enough to trigger the error. |
431 |
| - System::PacketBufferHandle head = testData[0].mHandle.PopHead(); |
432 |
| - err = tcp.ProcessReceivedBuffer(lEndPoint, lPeerAddress, std::move(head)); |
433 |
| - EXPECT_EQ(err, CHIP_ERROR_MESSAGE_TOO_LONG); |
434 |
| - EXPECT_EQ(gMockTransportMgrDelegate.mReceiveHandlerCallCount, 0); |
| 381 | +#if INET_CONFIG_ENABLE_IPV4 |
| 382 | +TEST_F(TestTCP, CheckSimpleInitTest4) |
| 383 | +{ |
| 384 | + CheckSimpleInitTest(IPAddressType::kIPv4); |
| 385 | +} |
435 | 386 |
|
436 |
| - gMockTransportMgrDelegate.FinalizeMessageTest(tcp, addr); |
437 |
| - } |
438 |
| -}; |
439 |
| -} // namespace Transport |
440 |
| -} // namespace chip |
| 387 | +TEST_F(TestTCP, CheckMessageTest4) |
| 388 | +{ |
| 389 | + IPAddress addr; |
| 390 | + IPAddress::FromString("127.0.0.1", addr); |
| 391 | + CheckMessageTest(addr); |
| 392 | +} |
| 393 | +#endif |
| 394 | + |
| 395 | +// IPv6 Tests |
| 396 | + |
| 397 | +TEST_F(TestTCP, CheckSimpleInitTest6) |
| 398 | +{ |
| 399 | + CheckSimpleInitTest(IPAddressType::kIPv6); |
| 400 | +} |
| 401 | + |
| 402 | +TEST_F(TestTCP, CheckMessageTest6) |
| 403 | +{ |
| 404 | + IPAddress addr; |
| 405 | + IPAddress::FromString("::1", addr); |
| 406 | + CheckMessageTest(addr); |
| 407 | +} |
441 | 408 |
|
442 | 409 | TEST_F(TestTCP, CheckProcessReceivedBuffer)
|
443 | 410 | {
|
444 |
| - chip::Transport::TCPTest::CheckProcessReceivedBuffer(this); |
| 411 | + TCPImpl tcp; |
| 412 | + |
| 413 | + IPAddress addr; |
| 414 | + IPAddress::FromString("::1", addr); |
| 415 | + |
| 416 | + MockTransportMgrDelegate gMockTransportMgrDelegate(mIOContext); |
| 417 | + gMockTransportMgrDelegate.InitializeMessageTest(tcp, addr); |
| 418 | + |
| 419 | + // Send a packet to get TCP going, so that we can find a TCPEndPoint to pass to ProcessReceivedBuffer. |
| 420 | + // (The current TCPEndPoint implementation is not effectively mockable.) |
| 421 | + gMockTransportMgrDelegate.SingleMessageTest(tcp, addr); |
| 422 | + |
| 423 | + Transport::PeerAddress lPeerAddress = Transport::PeerAddress::TCP(addr); |
| 424 | + void * state = Transport::TCPTestAccess::FindActiveConnection(tcp, lPeerAddress); |
| 425 | + ASSERT_NE(state, nullptr); |
| 426 | + TCPEndPoint * lEndPoint = Transport::TCPTestAccess::GetEndpoint(state); |
| 427 | + ASSERT_NE(lEndPoint, nullptr); |
| 428 | + |
| 429 | + CHIP_ERROR err = CHIP_NO_ERROR; |
| 430 | + TestData testData[2]; |
| 431 | + gMockTransportMgrDelegate.SetCallback(TestDataCallbackCheck, testData); |
| 432 | + |
| 433 | + // Test a single packet buffer. |
| 434 | + gMockTransportMgrDelegate.mReceiveHandlerCallCount = 0; |
| 435 | + EXPECT_TRUE(testData[0].Init((const uint16_t[]){ 111, 0 })); |
| 436 | + err = Transport::TCPTestAccess::ProcessReceivedBuffer(tcp, lEndPoint, lPeerAddress, std::move(testData[0].mHandle)); |
| 437 | + EXPECT_EQ(err, CHIP_NO_ERROR); |
| 438 | + EXPECT_EQ(gMockTransportMgrDelegate.mReceiveHandlerCallCount, 1); |
| 439 | + |
| 440 | + // Test a message in a chain of three packet buffers. The message length is split across buffers. |
| 441 | + gMockTransportMgrDelegate.mReceiveHandlerCallCount = 0; |
| 442 | + EXPECT_TRUE(testData[0].Init((const uint16_t[]){ 1, 122, 123, 0 })); |
| 443 | + err = Transport::TCPTestAccess::ProcessReceivedBuffer(tcp, lEndPoint, lPeerAddress, std::move(testData[0].mHandle)); |
| 444 | + EXPECT_EQ(err, CHIP_NO_ERROR); |
| 445 | + EXPECT_EQ(gMockTransportMgrDelegate.mReceiveHandlerCallCount, 1); |
| 446 | + |
| 447 | + // Test two messages in a chain. |
| 448 | + gMockTransportMgrDelegate.mReceiveHandlerCallCount = 0; |
| 449 | + EXPECT_TRUE(testData[0].Init((const uint16_t[]){ 131, 0 })); |
| 450 | + EXPECT_TRUE(testData[1].Init((const uint16_t[]){ 132, 0 })); |
| 451 | + testData[0].mHandle->AddToEnd(std::move(testData[1].mHandle)); |
| 452 | + err = Transport::TCPTestAccess::ProcessReceivedBuffer(tcp, lEndPoint, lPeerAddress, std::move(testData[0].mHandle)); |
| 453 | + EXPECT_EQ(err, CHIP_NO_ERROR); |
| 454 | + EXPECT_EQ(gMockTransportMgrDelegate.mReceiveHandlerCallCount, 2); |
| 455 | + |
| 456 | + // Test a chain of two messages, each a chain. |
| 457 | + gMockTransportMgrDelegate.mReceiveHandlerCallCount = 0; |
| 458 | + EXPECT_TRUE(testData[0].Init((const uint16_t[]){ 141, 142, 0 })); |
| 459 | + EXPECT_TRUE(testData[1].Init((const uint16_t[]){ 143, 144, 0 })); |
| 460 | + testData[0].mHandle->AddToEnd(std::move(testData[1].mHandle)); |
| 461 | + err = Transport::TCPTestAccess::ProcessReceivedBuffer(tcp, lEndPoint, lPeerAddress, std::move(testData[0].mHandle)); |
| 462 | + EXPECT_EQ(err, CHIP_NO_ERROR); |
| 463 | + EXPECT_EQ(gMockTransportMgrDelegate.mReceiveHandlerCallCount, 2); |
| 464 | + |
| 465 | + // Test a message that is too large to coalesce into a single packet buffer. |
| 466 | + gMockTransportMgrDelegate.mReceiveHandlerCallCount = 0; |
| 467 | + gMockTransportMgrDelegate.SetCallback(TestDataCallbackCheck, &testData[1]); |
| 468 | + EXPECT_TRUE(testData[0].Init((const uint16_t[]){ 51, System::PacketBuffer::kMaxSizeWithoutReserve, 0 })); |
| 469 | + // Sending only the first buffer of the long chain. This should be enough to trigger the error. |
| 470 | + System::PacketBufferHandle head = testData[0].mHandle.PopHead(); |
| 471 | + err = Transport::TCPTestAccess::ProcessReceivedBuffer(tcp, lEndPoint, lPeerAddress, std::move(head)); |
| 472 | + EXPECT_EQ(err, CHIP_ERROR_MESSAGE_TOO_LONG); |
| 473 | + EXPECT_EQ(gMockTransportMgrDelegate.mReceiveHandlerCallCount, 0); |
| 474 | + |
| 475 | + gMockTransportMgrDelegate.FinalizeMessageTest(tcp, addr); |
445 | 476 | }
|
| 477 | + |
| 478 | +} // namespace |
0 commit comments