/* * Copyright (c) Contributors to the Open 3D Engine Project. * For complete copyright and license terms please see the LICENSE at the root of this distribution. * * SPDX-License-Identifier: Apache-2.0 OR MIT * */ #include #include #include #include #include #include #include #include namespace UnitTest { using namespace AzNetworking; class TestTcpConnectionListener : public IConnectionListener { public: ConnectResult ValidateConnect([[maybe_unused]] const IpAddress& remoteAddress, [[maybe_unused]] const IPacketHeader& packetHeader, [[maybe_unused]] ISerializer& serializer) override { return ConnectResult::Accepted; } void OnConnect([[maybe_unused]] IConnection* connection) override { ; } PacketDispatchResult OnPacketReceived([[maybe_unused]] IConnection* connection, const IPacketHeader& packetHeader, [[maybe_unused]] ISerializer& serializer) override { EXPECT_TRUE((packetHeader.GetPacketType() == static_cast(CorePackets::PacketType::InitiateConnectionPacket)) || (packetHeader.GetPacketType() == static_cast(CorePackets::PacketType::HeartbeatPacket))); return PacketDispatchResult::Failure; } void OnPacketLost([[maybe_unused]] IConnection* connection, [[maybe_unused]] PacketId packetId) override { } void OnDisconnect([[maybe_unused]] IConnection* connection, [[maybe_unused]] DisconnectReason reason, [[maybe_unused]] TerminationEndpoint endpoint) override { // This should fail given we should be in a disconnecting state EXPECT_FALSE(connection->Disconnect(reason, endpoint)); } }; class TestTcpClient { public: TestTcpClient() { AZStd::string name = AZStd::string::format("TcpClient%d", ++s_numClients); m_name = name; m_clientNetworkInterface = AZ::Interface::Get()->CreateNetworkInterface(m_name, ProtocolType::Tcp, TrustZone::ExternalClientToServer, m_connectionListener); m_clientNetworkInterface->Connect(IpAddress(127, 0, 0, 1, 12345)); } ~TestTcpClient() { AZ::Interface::Get()->DestroyNetworkInterface(m_name); } AZ::Name m_name; TestTcpConnectionListener m_connectionListener; INetworkInterface* m_clientNetworkInterface; static inline int32_t s_numClients = 0; }; class TestTcpServer { public: TestTcpServer() { m_serverNetworkInterface = AZ::Interface::Get()->CreateNetworkInterface(m_name, ProtocolType::Tcp, TrustZone::ExternalClientToServer, m_connectionListener); m_serverNetworkInterface->Listen(12345); } ~TestTcpServer() { AZ::Interface::Get()->DestroyNetworkInterface(m_name); } AZ::Name m_name = AZ::Name(AZStd::string_view("TcpServer")); TestTcpConnectionListener m_connectionListener; INetworkInterface* m_serverNetworkInterface; }; class TcpTransportTests : public LeakDetectionFixture { public: void SetUp() override { AZ::NameDictionary::Create(); m_loggerComponent = AZStd::make_unique(); m_timeSystem = AZStd::make_unique(); m_networkingSystemComponent = AZStd::make_unique(); } void TearDown() override { m_networkingSystemComponent.reset(); m_timeSystem.reset(); m_loggerComponent.reset(); AZ::NameDictionary::Destroy(); } AZStd::unique_ptr m_loggerComponent; AZStd::unique_ptr m_timeSystem; AZStd::unique_ptr m_networkingSystemComponent; }; #if AZ_TRAIT_DISABLE_FAILED_NETWORKING_TESTS TEST_F(TcpTransportTests, DISABLED_TestSingleClient) #else TEST_F(TcpTransportTests, SUITE_sandbox_TestSingleClient) #endif // AZ_TRAIT_DISABLE_FAILED_NETWORKING_TESTS { TestTcpServer testServer; TestTcpClient testClient; constexpr AZ::TimeMs TotalIterationTimeMs = AZ::TimeMs{ 5000 }; const AZ::TimeMs startTimeMs = AZ::GetElapsedTimeMs(); for (;;) { AZStd::this_thread::sleep_for(AZStd::chrono::milliseconds(25)); m_networkingSystemComponent->OnSystemTick(); bool timeExpired = (AZ::GetElapsedTimeMs() - startTimeMs > TotalIterationTimeMs); bool canTerminate = (testServer.m_serverNetworkInterface->GetConnectionSet().GetConnectionCount() == 1) && (testClient.m_clientNetworkInterface->GetConnectionSet().GetConnectionCount() == 1); if (canTerminate || timeExpired) { break; } } EXPECT_EQ(testServer.m_serverNetworkInterface->GetConnectionSet().GetConnectionCount(), 1); EXPECT_EQ(testClient.m_clientNetworkInterface->GetConnectionSet().GetConnectionCount(), 1); const AZ::TimeMs timeoutMs = AZ::TimeMs{ 100 }; testClient.m_clientNetworkInterface->SetTimeoutMs(timeoutMs); EXPECT_EQ(testClient.m_clientNetworkInterface->GetTimeoutMs(), timeoutMs); EXPECT_TRUE(testServer.m_serverNetworkInterface->StopListening()); } #if AZ_TRAIT_DISABLE_FAILED_NETWORKING_TESTS TEST_F(TcpTransportTests, DISABLED_TestMultipleClients) #else TEST_F(TcpTransportTests, SUITE_sandbox_TestMultipleClients) #endif // AZ_TRAIT_DISABLE_FAILED_NETWORKING_TESTS { constexpr uint32_t NumTestClients = 50; TestTcpServer testServer; TestTcpClient testClient[NumTestClients]; constexpr AZ::TimeMs TotalIterationTimeMs = AZ::TimeMs{ 5000 }; const AZ::TimeMs startTimeMs = AZ::GetElapsedTimeMs(); for (;;) { AZStd::this_thread::sleep_for(AZStd::chrono::milliseconds(25)); m_networkingSystemComponent->OnSystemTick(); bool timeExpired = (AZ::GetElapsedTimeMs() - startTimeMs > TotalIterationTimeMs); bool canTerminate = testServer.m_serverNetworkInterface->GetConnectionSet().GetConnectionCount() == NumTestClients; for (uint32_t i = 0; i < NumTestClients; ++i) { canTerminate &= testClient[i].m_clientNetworkInterface->GetConnectionSet().GetConnectionCount() == 1; } if (canTerminate || timeExpired) { break; } } EXPECT_EQ(testServer.m_serverNetworkInterface->GetConnectionSet().GetConnectionCount(), NumTestClients); for (uint32_t i = 0; i < NumTestClients; ++i) { EXPECT_EQ(testClient[i].m_clientNetworkInterface->GetConnectionSet().GetConnectionCount(), 1); } } }