From 4a6e47bf55b3fb225a239b7f4954785ba567820f Mon Sep 17 00:00:00 2001 From: Jonas Reich Date: Sun, 3 Mar 2024 21:20:45 +0100 Subject: [PATCH] Multiplayer tests now fail on network errors during tests --- .../Tests/Multiplayer/FT_Multiplayer.uasset | Bin 49220 -> 44294 bytes .../OUUMultiplayerFunctionalTest.cpp | 24 ++- .../OUUMultiplayerTestClientSignal.cpp | 2 +- .../OUUMultiplayerTestController.cpp | 149 +++++++++--------- .../OUUMultiplayerFunctionalTest.h | 14 +- .../OUUMultiplayerTestController.h | 11 +- 6 files changed, 119 insertions(+), 81 deletions(-) diff --git a/Content/Tests/Multiplayer/FT_Multiplayer.uasset b/Content/Tests/Multiplayer/FT_Multiplayer.uasset index 2deff2f833d0e0f927027d927506985ab738f8bd..bf15942872768f430c9ed80109b6f9547fa485c0 100644 GIT binary patch literal 44294 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 YTEVhJ9@3IcrAPF8>ap>;@>1acKbXfQg#Z8m literal 49220 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 L7?!Qw3jF^EJ;LXi diff --git a/Source/OUUTestUtilities/Private/Multiplayer/OUUMultiplayerFunctionalTest.cpp b/Source/OUUTestUtilities/Private/Multiplayer/OUUMultiplayerFunctionalTest.cpp index 52430ef..65ca98d 100644 --- a/Source/OUUTestUtilities/Private/Multiplayer/OUUMultiplayerFunctionalTest.cpp +++ b/Source/OUUTestUtilities/Private/Multiplayer/OUUMultiplayerFunctionalTest.cpp @@ -88,17 +88,22 @@ void AOUUMultiplayerFunctionalTest::ServerNotifyClientSyncMarkerReached( bool AOUUMultiplayerFunctionalTest::RunTest(const TArray& Params) { UOUUMultiplayerTestController::Get().NotifyFunctionalTestStarted(); - return Super::RunTest(Params); + const bool bWasStarted = Super::RunTest(Params); + Multicast_OnTestStarted(); + return bWasStarted; } void AOUUMultiplayerFunctionalTest::FinishTest(EFunctionalTestResult TestResult, const FString& Message) { - ensureMsgf( + if (ensureMsgf( HasAuthority(), TEXT("The FinishTest function should only ever be called on Authority! Use snyc point nodes for all " - "intermediate steps you want to ensure synchronicity.")); - UOUUMultiplayerTestController::Get().NotifyFunctionalTestEnded(TestResult); + "intermediate steps you want to ensure synchronicity.")) == false) + { + return; + } Super::FinishTest(TestResult, Message); + Multicast_OnTestEnded(TestResult, TestIndex, TotalNumTests); } void AOUUMultiplayerFunctionalTest::GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const @@ -107,6 +112,17 @@ void AOUUMultiplayerFunctionalTest::GetLifetimeReplicatedProps(TArrayNetworkFailureEvent.AddLambda( - [this](UWorld*, UNetDriver*, ENetworkFailure::Type Failure, const FString& Reason) { - UE_LOG( - LogOpenUnrealUtilities, - Fatal, - TEXT("Network failure (%s): %s"), - ENetworkFailure::ToString(Failure), - *Reason); - }); - */ + Heartbeat(TEXT("Test started...")); + if (GEngine->NetworkFailureEvent.IsBoundToObject(this) == false) + { + GEngine->NetworkFailureEvent + .AddWeakLambda(this, [this](UWorld*, UNetDriver*, ENetworkFailure::Type Failure, const FString& Reason) { + UE_LOG( + LogOpenUnrealUtilities, + Fatal, + TEXT("Network failure (%s): %s"), + ENetworkFailure::ToString(Failure), + *Reason); + }); + } } -void UOUUMultiplayerTestController::NotifyFunctionalTestEnded(EFunctionalTestResult TestResult) +void UOUUMultiplayerTestController::NotifyFunctionalTestEnded(EFunctionalTestResult TestResult, int32 TestIndex, int32 TotalNumTests) { - MarkHeartbeatActive(TEXT("[SERVER] test ended...")); - // #TODO stop listening for disconnects? - ServerNumFinishedTests++; - if (TestResult != EFunctionalTestResult::Succeeded) + if (TestIndex == TotalNumTests - 1) { - ServerNumFailedTests++; + // stop listening for network failures / disconnects. + // even a successful client disconnect results in an error for me. + GEngine->NetworkFailureEvent.RemoveAll(this); } - ServerRunNextFunctionalTest(); + Heartbeat(TEXT("Test ended...")); + if (bIsServer) + { + ServerNumFinishedTests++; + if (TestResult != EFunctionalTestResult::Succeeded) + { + ServerNumFailedTests++; + } + + ServerRunNextFunctionalTest(); + } } void UOUUMultiplayerTestController::OnInit() @@ -75,7 +81,6 @@ void UOUUMultiplayerTestController::OnInit() Instance = this; Super::OnInit(); - FString TestRole; FParse::Value(FCommandLine::Get(), TEXT("OUUMPTestRole="), OUT TestRole); UE_LOG(LogOpenUnrealUtilities, Log, TEXT("OUUMPTestRole=%s"), *TestRole); bIsServer = TestRole == OUU::TestUtilities::GTestRole_Server; @@ -87,7 +92,7 @@ void UOUUMultiplayerTestController::OnInit() void UOUUMultiplayerTestController::OnPostMapChange(UWorld* World) { - if (bIsServer) + if (bIsServer && bUseSessionSearch) { if (bServerInitialized) { @@ -96,7 +101,7 @@ void UOUUMultiplayerTestController::OnPostMapChange(UWorld* World) } bServerInitialized = true; - MarkHeartbeatActive(TEXT("[SERVER] create session...")); + Heartbeat(TEXT("Create session...")); FOnlineSessionSettings Settings; Settings.NumPublicConnections = 2; Settings.bShouldAdvertise = true; @@ -121,7 +126,7 @@ void UOUUMultiplayerTestController::OnTick(float TimeDelta) { ServerCheckRunFirstTest(); } - else + else if (bUseSessionSearch) { // #TODO is there a better way to delay client session search? constexpr float WaitUntilSessionSearch = 5.f; @@ -147,38 +152,21 @@ FUniqueNetIdPtr UOUUMultiplayerTestController::GetLocalNetID() const return UniqueNetID; } +void UOUUMultiplayerTestController::Heartbeat(const FString& Message) +{ + MarkHeartbeatActive(FString::Printf(TEXT("[%s] %s"), *TestRole, *Message)); +} + void UOUUMultiplayerTestController::OnCreateSessionComplete(FName, bool Success) { if (Success == false) { - MarkHeartbeatActive(TEXT("[SERVER] failed to create session")); + Heartbeat(TEXT("Failed to create session")); EndTest(1); } - // CRASH??? - // as listen server? - MarkHeartbeatActive(TEXT("[SERVER] enable listen server...")); + Heartbeat(TEXT("Enable listen server...")); GetWorld()->GetGameInstance()->EnableListenServer(true); - - MarkHeartbeatActive(TEXT("[SERVER] Collecting tests...")); - for (auto* FTest : TActorRange(GetWorld())) - { - if (auto* MultiplayerFTest = Cast(FTest)) - { - ServerAllFunctionalTests.Add(MultiplayerFTest); - } - else - { - UE_LOG( - LogOpenUnrealUtilities, - Fatal, - TEXT("Invalid functional test %s on map %s is not a multiplayer test"), - *GetCurrentMap(), - *GetNameSafe(FTest)); - } - } - - ServerTotalNumTests = ServerAllFunctionalTests.Num(); } void UOUUMultiplayerTestController::ServerOnPostLogin(AGameModeBase* GameModeBase, APlayerController* PlayerController) @@ -186,14 +174,36 @@ void UOUUMultiplayerTestController::ServerOnPostLogin(AGameModeBase* GameModeBas auto* Signal = GetWorld()->SpawnActor(); check(Signal); Signal->SetOwner(PlayerController); - MarkHeartbeatActive(FString::Printf(TEXT("[SERVER] post login (%s)"), *GetNameSafe(PlayerController))); + Heartbeat(FString::Printf(TEXT("Post login (%s)"), *GetNameSafe(PlayerController))); + ServerCheckRunFirstTest(); } void UOUUMultiplayerTestController::ServerCheckRunFirstTest() { // #TODO replace with parameter - if (bServerStartedFirstTest == false && ServerNumSignalsReplicated == 2 && GetWorld()->GetGameState()->PlayerArray.Num() == 3) + if (bServerStartedFirstTest == false && ServerNumSignalsReplicated == 2 + && GetWorld()->GetGameState()->PlayerArray.Num() == 3) { + Heartbeat(TEXT("Start condition fulfilled. Collecting tests...")); + for (auto* FTest : TActorRange(GetWorld())) + { + if (auto* MultiplayerFTest = Cast(FTest)) + { + ServerAllFunctionalTests.Add(MultiplayerFTest); + } + else + { + UE_LOG( + LogOpenUnrealUtilities, + Fatal, + TEXT("Invalid functional test %s on map %s is not a multiplayer test"), + *GetCurrentMap(), + *GetNameSafe(FTest)); + } + } + + ServerTotalNumTests = ServerAllFunctionalTests.Num(); + ServerRunNextFunctionalTest(); } } @@ -204,30 +214,30 @@ void UOUUMultiplayerTestController::ServerRunNextFunctionalTest() if (ServerAllFunctionalTests.Num() == 0) { ensure(ServerNumFinishedTests == ServerTotalNumTests); - MarkHeartbeatActive(TEXT("[SERVER] all tests completed")); - EndTest(ServerNumFailedTests); + Heartbeat(TEXT("All tests completed")); + // Wait 3 more seconds for clients to disconnect. + constexpr float EndTestDelay = 3.f; + FTimerHandle TempHandle; + GetWorld()->GetTimerManager().SetTimer( + IN OUT TempHandle, + FTimerDelegate::CreateLambda([this]() { EndTest(ServerNumFailedTests); }), + EndTestDelay, + false); } else { const auto NextTest = ServerAllFunctionalTests.Pop(); check(NextTest.IsValid()); - MarkHeartbeatActive(TEXT("[SERVER] starting test...")); + Heartbeat(TEXT("Starting test...")); + NextTest->TestIndex = ServerNumFinishedTests; + NextTest->TotalNumTests = ServerTotalNumTests; IFunctionalTestingModule::Get().RunTestOnMap(NextTest->GetName(), false, false); } } -void UOUUMultiplayerTestController::OnFunctionalTestEnd(FAutomationTestBase* AutomationTest) -{ - MarkHeartbeatActive(FString(TEXT("test completed: ")) + AutomationTest->GetTestName()); - if (AutomationTest->GetLastExecutionSuccessState() == false) - { - ServerNumFailedTests++; - } -} - void UOUUMultiplayerTestController::ClientStartSessionSearch() { - MarkHeartbeatActive(TEXT("[CLIENT] find sessions...")); + Heartbeat(TEXT("Start session search...")); ClientSessionSearch = MakeShared(); ClientSessionSearch->MaxSearchResults = 1; @@ -260,11 +270,8 @@ void UOUUMultiplayerTestController::ClientJoinSessionComplete(FName, EOnJoinSess FString ConnectString; if (GetSessions()->GetResolvedConnectString(NAME_GameSession, ConnectString)) { - UE_LOG_ONLINE_SESSION(Log, TEXT("Join session: traveling to %s"), *ConnectString); - MarkHeartbeatActive(TEXT("[CLIENT] travel...")); + Heartbeat(TEXT("Client travel...")); GetWorld()->GetFirstPlayerController()->ClientTravel(ConnectString, TRAVEL_Absolute); } } } - -UE_ENABLE_OPTIMIZATION diff --git a/Source/OUUTestUtilities/Public/Multiplayer/OUUMultiplayerFunctionalTest.h b/Source/OUUTestUtilities/Public/Multiplayer/OUUMultiplayerFunctionalTest.h index abb5b30..e6e8e65 100644 --- a/Source/OUUTestUtilities/Public/Multiplayer/OUUMultiplayerFunctionalTest.h +++ b/Source/OUUTestUtilities/Public/Multiplayer/OUUMultiplayerFunctionalTest.h @@ -18,6 +18,10 @@ class OUUTESTUTILITIES_API AOUUMultiplayerFunctionalTest : public AFunctionalTes AOUUMultiplayerFunctionalTest(); + // For tracking how far we are along the test progression + int32 TestIndex = INDEX_NONE; + int32 TotalNumTests = INDEX_NONE; + // Called on server + all clients if we detected that a sync point was reached. DECLARE_EVENT_OneParam(AOUUMultiplayerFunctionalTest, FOnSyncMarkerReached, int32); FOnSyncMarkerReached OnSyncMarkerReached; @@ -32,7 +36,15 @@ class OUUTESTUTILITIES_API AOUUMultiplayerFunctionalTest : public AFunctionalTes // - UObject void GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const override; // -- - + +public: + UFUNCTION(NetMulticast, Reliable) + void Multicast_OnTestStarted(); + UFUNCTION(BlueprintImplementableEvent, DisplayName = "Multiplayer Test Started") + void K2_OnTestStarted(); + UFUNCTION(NetMulticast, Reliable) + void Multicast_OnTestEnded(EFunctionalTestResult TestResult, int32 InTestIndex, int32 InTotalNumTests); + private: UPROPERTY(Transient) TMap ClientSyncMarkerLocations; diff --git a/Source/OUUTestUtilities/Public/Multiplayer/OUUMultiplayerTestController.h b/Source/OUUTestUtilities/Public/Multiplayer/OUUMultiplayerTestController.h index a067a61..c242bf9 100644 --- a/Source/OUUTestUtilities/Public/Multiplayer/OUUMultiplayerTestController.h +++ b/Source/OUUTestUtilities/Public/Multiplayer/OUUMultiplayerTestController.h @@ -10,7 +10,7 @@ #include "OUUMultiplayerTestController.generated.h" enum class EFunctionalTestResult : uint8; -class AFunctionalTest; +class AOUUMultiplayerFunctionalTest; UCLASS() class OUUTESTUTILITIES_API UOUUMultiplayerTestController : public UGauntletTestController @@ -25,7 +25,7 @@ class OUUTESTUTILITIES_API UOUUMultiplayerTestController : public UGauntletTestC void NotifyServerPostSignalReplicated(); // Notify the controller that a functional test started. void NotifyFunctionalTestStarted(); - void NotifyFunctionalTestEnded(EFunctionalTestResult TestResult); + void NotifyFunctionalTestEnded(EFunctionalTestResult TestResult, int32 TestIndex, int32 TotalNumTests); // - UGauntletTestController void OnInit() override; @@ -37,12 +37,12 @@ class OUUTESTUTILITIES_API UOUUMultiplayerTestController : public UGauntletTestC // --- SHARED IOnlineSessionPtr GetSessions() const; FUniqueNetIdPtr GetLocalNetID() const; + void Heartbeat(const FString& Message); // ---- SERVER void OnCreateSessionComplete(FName, bool Success); void ServerOnPostLogin(AGameModeBase* GameModeBase, APlayerController* PlayerController); void ServerCheckRunFirstTest(); void ServerRunNextFunctionalTest(); - void OnFunctionalTestEnd(FAutomationTestBase* AutomationTest); // ---- CLIENT void ClientStartSessionSearch(); void ClientSessionSearchComplete(bool Success); @@ -51,8 +51,10 @@ class OUUTESTUTILITIES_API UOUUMultiplayerTestController : public UGauntletTestC private: // --- SHARED static UOUUMultiplayerTestController* Instance; + FString TestRole; bool bIsServer = false; float TotalTickTime = 0.f; + bool bUseSessionSearch = true; // --- SERVER bool bServerInitialized = false; bool bServerStartedFirstTest = false; @@ -60,8 +62,9 @@ class OUUTESTUTILITIES_API UOUUMultiplayerTestController : public UGauntletTestC int32 ServerTotalNumTests = 0; int32 ServerNumFinishedTests = 0; int32 ServerNumSignalsReplicated = 0; - TArray> ServerAllFunctionalTests; + TArray> ServerAllFunctionalTests; // --- CLIENT bool bClientSessionSearchStarted = false; TSharedPtr ClientSessionSearch; }; +