private static void RunStandaloneClient(List <DeploymentContext> DeployContextList, string ClientLogFile, ERunOptions ClientRunFlags, string ClientApp, string ClientCmdLine, ProjectParams Params) { if (Params.Unattended) { string LookFor = "Bringing up level for play took"; bool bCommandlet = false; if (Params.RunAutomationTest != "") { LookFor = "Automation Test Succeeded"; } else if (Params.RunAutomationTests) { LookFor = "Automation Test Queue Empty"; } else if (Params.EditorTest) { LookFor = "Asset discovery search completed in"; } // If running a commandlet, just detect a normal exit else if (ClientCmdLine.IndexOf("-run=", StringComparison.InvariantCultureIgnoreCase) >= 0) { LookFor = "Game engine shut down"; bCommandlet = true; } { string AllClientOutput = ""; int LastAutoFailIndex = -1; IProcessResult ClientProcess = null; FileStream ClientProcessLog = null; StreamReader ClientLogReader = null; Log("Starting Client for unattended test...."); ClientProcess = Run(ClientApp, ClientCmdLine + " -testexit=\"" + LookFor + "\"", null, ClientRunFlags | ERunOptions.NoWaitForExit); while (!FileExists(ClientLogFile) && !ClientProcess.HasExited) { Log("Waiting for client logging process to start...{0}", ClientLogFile); Thread.Sleep(2000); } if (FileExists(ClientLogFile)) { Thread.Sleep(2000); Log("Client logging process started...{0}", ClientLogFile); ClientProcessLog = File.Open(ClientLogFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); ClientLogReader = new StreamReader(ClientProcessLog); } if (ClientLogReader == null) { throw new AutomationException("Client exited without creating a log file."); } bool bKeepReading = true; bool WelcomedCorrectly = false; bool bClientExited = false; DateTime ExitTime = DateTime.UtcNow; while (bKeepReading) { if (!bClientExited && ClientProcess.HasExited) { ExitTime = DateTime.UtcNow; bClientExited = true; } string ClientOutput = ClientLogReader.ReadToEnd(); if (!String.IsNullOrEmpty(ClientOutput)) { if (bClientExited) { ExitTime = DateTime.UtcNow; // as long as it is spewing, we reset the timer } AllClientOutput += ClientOutput; Console.Write(ClientOutput); if (AllClientOutput.LastIndexOf(LookFor) > AllClientOutput.IndexOf(LookFor)) { WelcomedCorrectly = true; Log("Test complete..."); bKeepReading = false; } else if (Params.RunAutomationTests) { int FailIndex = AllClientOutput.LastIndexOf("Automation Test Failed"); int ParenIndex = AllClientOutput.LastIndexOf(")"); if (FailIndex >= 0 && ParenIndex > FailIndex && FailIndex > LastAutoFailIndex) { string Tail = AllClientOutput.Substring(FailIndex); int CloseParenIndex = Tail.IndexOf(")"); int OpenParenIndex = Tail.IndexOf("("); string Test = ""; if (OpenParenIndex >= 0 && CloseParenIndex > OpenParenIndex) { Test = Tail.Substring(OpenParenIndex + 1, CloseParenIndex - OpenParenIndex - 1); LogError("Automated test failed ({0}).", Test); LastAutoFailIndex = FailIndex; } } } // Detect commandlet failure else if (bCommandlet) { const string ResultLog = "Commandlet->Main return this error code: "; int ResultStart = AllClientOutput.LastIndexOf(ResultLog); int ResultValIdx = ResultStart + ResultLog.Length; if (ResultStart >= 0 && ResultValIdx < AllClientOutput.Length && AllClientOutput.Substring(ResultValIdx, 1) == "1") { // Parse the full commandlet warning/error summary string FullSummary = ""; int SummaryStart = AllClientOutput.LastIndexOf("Warning/Error Summary"); if (SummaryStart >= 0 && SummaryStart < ResultStart) { FullSummary = AllClientOutput.Substring(SummaryStart, ResultStart - SummaryStart); } if (FullSummary.Length > 0) { LogError("Commandlet failed, summary:" + Environment.NewLine + FullSummary); } else { LogError("Commandlet failed."); } } } } else if (bClientExited && (DateTime.UtcNow - ExitTime).TotalSeconds > 30) { Log("Client exited and has been quiet for 30 seconds...exiting"); bKeepReading = false; } } if (ClientProcess != null && !ClientProcess.HasExited) { Log("Client is supposed to exit, lets wait a while for it to exit naturally..."); for (int i = 0; i < 120 && !ClientProcess.HasExited; i++) { Thread.Sleep(1000); } } if (ClientProcess != null && !ClientProcess.HasExited) { Log("Stopping client..."); ClientProcess.StopProcess(); Thread.Sleep(10000); } while (ClientLogReader != null && !ClientLogReader.EndOfStream) { string ClientOutput = ClientLogReader.ReadToEnd(); if (!String.IsNullOrEmpty(ClientOutput)) { Console.Write(ClientOutput); } } if (!WelcomedCorrectly) { throw new AutomationException("Client exited before we asked it to."); } } } else { var SC = DeployContextList[0]; IProcessResult ClientProcess = SC.StageTargetPlatform.RunClient(ClientRunFlags, ClientApp, ClientCmdLine, Params); if (ClientProcess != null) { // If the client runs without StdOut redirect we're going to read the log output directly from log file on // a separate thread. if ((ClientRunFlags & ERunOptions.NoStdOutRedirect) == ERunOptions.NoStdOutRedirect) { ClientLogReaderThread = new System.Threading.Thread(ClientLogReaderProc); ClientLogReaderThread.Start(new object[] { ClientLogFile, ClientProcess }); } do { Thread.Sleep(100); }while (ClientProcess.HasExited == false); SC.StageTargetPlatform.PostRunClient(ClientProcess, Params); // any non-zero exit code should propagate an exception. The Virtual function above may have // already thrown a more specific exception or given a more specific ErrorCode, but this catches the rest. if (ClientProcess.ExitCode != 0) { throw new AutomationException("Client exited with error code: " + ClientProcess.ExitCode); } } } }
private static void RunClientWithServer(List <DeploymentContext> DeployContextList, string ServerLogFile, IProcessResult ServerProcess, string ClientApp, string ClientCmdLine, ERunOptions ClientRunFlags, string ClientLogFile, ProjectParams Params) { IProcessResult ClientProcess = null; var OtherClients = new List <IProcessResult>(); bool WelcomedCorrectly = false; int NumClients = Params.NumClients; string AllClientOutput = ""; int LastAutoFailIndex = -1; if (Params.Unattended) { string LookFor = "Bringing up level for play took"; if (Params.DedicatedServer) { LookFor = "Welcomed by server"; } else if (Params.RunAutomationTest != "") { LookFor = "Automation Test Succeeded"; } else if (Params.RunAutomationTests) { LookFor = "Automation Test Queue Empty"; } { while (!FileExists(ServerLogFile) && !ServerProcess.HasExited) { Log("Waiting for logging process to start..."); Thread.Sleep(2000); } Thread.Sleep(1000); string AllServerOutput = ""; using (FileStream ProcessLog = File.Open(ServerLogFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) { StreamReader LogReader = new StreamReader(ProcessLog); bool bKeepReading = true; FileStream ClientProcessLog = null; StreamReader ClientLogReader = null; // Read until the process has exited. while (!ServerProcess.HasExited && bKeepReading) { while (!LogReader.EndOfStream && bKeepReading && ClientProcess == null) { string Output = LogReader.ReadToEnd(); if (!String.IsNullOrEmpty(Output)) { AllServerOutput += Output; if (ClientProcess == null && (AllServerOutput.Contains("Game Engine Initialized") || AllServerOutput.Contains("Unreal Network File Server is ready"))) { Log("Starting Client for unattended test...."); ClientProcess = Run(ClientApp, ClientCmdLine + " -testexit=\"" + LookFor + "\"", null, ClientRunFlags | ERunOptions.NoWaitForExit); //@todo no testing is done on these if (NumClients > 1 && NumClients < 9) { for (int i = 1; i < NumClients; i++) { Log("Starting Extra Client...."); OtherClients.Add(Run(ClientApp, ClientCmdLine, null, ClientRunFlags | ERunOptions.NoWaitForExit)); } } while (!FileExists(ClientLogFile) && !ClientProcess.HasExited) { Log("Waiting for client logging process to start...{0}", ClientLogFile); Thread.Sleep(2000); } if (!ClientProcess.HasExited) { Thread.Sleep(2000); Log("Client logging process started...{0}", ClientLogFile); ClientProcessLog = File.Open(ClientLogFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); ClientLogReader = new StreamReader(ClientProcessLog); } } else if (ClientProcess == null && !ServerProcess.HasExited) { Log("Waiting for server to start...."); Thread.Sleep(2000); } if (ClientProcess != null && ClientProcess.HasExited) { ServerProcess.StopProcess(); throw new AutomationException("Client exited before we asked it to."); } } } if (ClientLogReader != null) { if (ClientProcess.HasExited) { ServerProcess.StopProcess(); throw new AutomationException("Client exited or closed the log before we asked it to."); } while (!ClientProcess.HasExited && !ServerProcess.HasExited && bKeepReading) { while (!ClientLogReader.EndOfStream && bKeepReading && !ServerProcess.HasExited && !ClientProcess.HasExited) { string ClientOutput = ClientLogReader.ReadToEnd(); if (!String.IsNullOrEmpty(ClientOutput)) { AllClientOutput += ClientOutput; Console.Write(ClientOutput); if (AllClientOutput.LastIndexOf(LookFor) > AllClientOutput.IndexOf(LookFor)) { if (Params.FakeClient) { Log("Welcomed by server or client loaded, lets wait ten minutes..."); Thread.Sleep(60000 * 10); } else { Log("Welcomed by server or client loaded, lets wait 30 seconds..."); Thread.Sleep(30000); } WelcomedCorrectly = true; bKeepReading = false; } else if (Params.RunAutomationTests) { int FailIndex = AllClientOutput.LastIndexOf("Automation Test Failed"); int ParenIndex = AllClientOutput.LastIndexOf(")"); if (FailIndex >= 0 && ParenIndex > FailIndex && FailIndex > LastAutoFailIndex) { string Tail = AllClientOutput.Substring(FailIndex); int CloseParenIndex = Tail.IndexOf(")"); int OpenParenIndex = Tail.IndexOf("("); string Test = ""; if (OpenParenIndex >= 0 && CloseParenIndex > OpenParenIndex) { Test = Tail.Substring(OpenParenIndex + 1, CloseParenIndex - OpenParenIndex - 1); LogError("Automated test failed ({0}).", Test); LastAutoFailIndex = FailIndex; } } } } } } } } } } } else { LogFileReaderProcess(ServerLogFile, ServerProcess, (string Output) => { bool bKeepReading = true; if (ClientProcess == null && !String.IsNullOrEmpty(Output)) { AllClientOutput += Output; if (ClientProcess == null && (AllClientOutput.Contains("Game Engine Initialized") || AllClientOutput.Contains("Unreal Network File Server is ready"))) { Log("Starting Client...."); var SC = DeployContextList[0]; ClientProcess = SC.StageTargetPlatform.RunClient(ClientRunFlags | ERunOptions.NoWaitForExit, ClientApp, ClientCmdLine, Params); // ClientProcess = Run(ClientApp, ClientCmdLine, null, ClientRunFlags | ERunOptions.NoWaitForExit); if (NumClients > 1 && NumClients < 9) { for (int i = 1; i < NumClients; i++) { Log("Starting Extra Client...."); IProcessResult NewClient = SC.StageTargetPlatform.RunClient(ClientRunFlags | ERunOptions.NoWaitForExit, ClientApp, ClientCmdLine, Params); OtherClients.Add(NewClient); } } } } else if (ClientProcess == null && !ServerProcess.HasExited) { Log("Waiting for server to start...."); Thread.Sleep(2000); } if (String.IsNullOrEmpty(Output) == false) { Console.Write(Output); } if (ClientProcess != null && ClientProcess.HasExited) { Log("Client exited, stopping server...."); if (!GlobalCommandLine.NoKill) { ServerProcess.StopProcess(); } bKeepReading = false; } return(bKeepReading); // Keep reading }); } Log("Server exited...."); if (ClientProcess != null && !ClientProcess.HasExited) { ClientProcess.StopProcess(); } foreach (var OtherClient in OtherClients) { if (OtherClient != null && !OtherClient.HasExited) { OtherClient.StopProcess(); } } if (Params.Unattended) { if (!WelcomedCorrectly) { throw new AutomationException("Server or client exited before we asked it to."); } } }
private static void RunStandaloneClient(List <DeploymentContext> DeployContextList, string ClientLogFile, ERunOptions ClientRunFlags, string ClientApp, string ClientCmdLine, ProjectParams Params) { if (Params.Unattended) { string LookFor = "Bringing up level for play took"; if (Params.RunAutomationTest != "") { LookFor = "Automation Test Succeeded"; } else if (Params.RunAutomationTests) { LookFor = "Automation Test Queue Empty"; } else if (Params.EditorTest) { LookFor = "Asset discovery search completed in"; } { string AllClientOutput = ""; int LastAutoFailIndex = -1; ProcessResult ClientProcess = null; FileStream ClientProcessLog = null; StreamReader ClientLogReader = null; Log("Starting Client for unattended test...."); ClientProcess = Run(ClientApp, ClientCmdLine + " -FORCELOGFLUSH -testexit=\"" + LookFor + "\"", null, ClientRunFlags | ERunOptions.NoWaitForExit); while (!FileExists(ClientLogFile) && !ClientProcess.HasExited) { Log("Waiting for client logging process to start...{0}", ClientLogFile); Thread.Sleep(2000); } if (FileExists(ClientLogFile)) { Thread.Sleep(2000); Log("Client logging process started...{0}", ClientLogFile); ClientProcessLog = File.Open(ClientLogFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); ClientLogReader = new StreamReader(ClientProcessLog); } if (ClientLogReader == null) { throw new AutomationException("Client exited without creating a log file."); } bool bKeepReading = true; bool WelcomedCorrectly = false; bool bClientExited = false; DateTime ExitTime = DateTime.UtcNow; while (bKeepReading) { if (!bClientExited && ClientProcess.HasExited) { ExitTime = DateTime.UtcNow; bClientExited = true; } string ClientOutput = ClientLogReader.ReadToEnd(); if (!String.IsNullOrEmpty(ClientOutput)) { if (bClientExited) { ExitTime = DateTime.UtcNow; // as long as it is spewing, we reset the timer } AllClientOutput += ClientOutput; Console.Write(ClientOutput); if (AllClientOutput.LastIndexOf(LookFor) > AllClientOutput.IndexOf(LookFor)) { WelcomedCorrectly = true; Log("Test complete..."); bKeepReading = false; } else if (Params.RunAutomationTests) { int FailIndex = AllClientOutput.LastIndexOf("Automation Test Failed"); int ParenIndex = AllClientOutput.LastIndexOf(")"); if (FailIndex >= 0 && ParenIndex > FailIndex && FailIndex > LastAutoFailIndex) { string Tail = AllClientOutput.Substring(FailIndex); int CloseParenIndex = Tail.IndexOf(")"); int OpenParenIndex = Tail.IndexOf("("); string Test = ""; if (OpenParenIndex >= 0 && CloseParenIndex > OpenParenIndex) { Test = Tail.Substring(OpenParenIndex + 1, CloseParenIndex - OpenParenIndex - 1); Log(System.Diagnostics.TraceEventType.Error, "Automated test failed ({0}).", Test); LastAutoFailIndex = FailIndex; } } } } else if (bClientExited && (DateTime.UtcNow - ExitTime).TotalSeconds > 30) { Log("Client exited and has been quiet for 30 seconds...exiting"); bKeepReading = false; } } if (ClientProcess != null && !ClientProcess.HasExited) { Log("Client is supposed to exit, lets wait a while for it to exit naturally..."); for (int i = 0; i < 120 && !ClientProcess.HasExited; i++) { Thread.Sleep(1000); } } if (ClientProcess != null && !ClientProcess.HasExited) { Log("Stopping client..."); ClientProcess.StopProcess(); Thread.Sleep(10000); } while (ClientLogReader != null && !ClientLogReader.EndOfStream) { string ClientOutput = ClientLogReader.ReadToEnd(); if (!String.IsNullOrEmpty(ClientOutput)) { Console.Write(ClientOutput); } } if (!WelcomedCorrectly) { throw new AutomationException("Client exited before we asked it to."); } } } else { var SC = DeployContextList[0]; ProcessResult ClientProcess = SC.StageTargetPlatform.RunClient(ClientRunFlags, ClientApp, ClientCmdLine, Params); if (ClientProcess != null) { // If the client runs without StdOut redirect we're going to read the log output directly from log file on // a separate thread. if ((ClientRunFlags & ERunOptions.NoStdOutRedirect) == ERunOptions.NoStdOutRedirect) { ClientLogReaderThread = new System.Threading.Thread(ClientLogReaderProc); ClientLogReaderThread.Start(new object[] { ClientLogFile, ClientProcess }); } do { Thread.Sleep(100); }while (ClientProcess.HasExited == false); if (ClientProcess.ExitCode != 0) { throw new AutomationException("Client exited with error code: " + ClientProcess.ExitCode); } } } }