/// <summary> /// Constructor, all values must be provided /// </summary> /// <param name="InSessionRole"></param> /// <param name="InAppInstance"></param> /// <param name="InArtifactPath"></param> /// <param name="InLogSummary"></param> public UnrealRoleArtifacts(UnrealSessionRole InSessionRole, IAppInstance InAppInstance, string InArtifactPath, string InLogPath, UnrealLogParser InLog) { SessionRole = InSessionRole; AppInstance = InAppInstance; ArtifactPath = InArtifactPath; LogPath = InLogPath; LogParser = InLog; }
/// <summary> /// Periodically called while the test is running. A chance for tests to examine their /// health, log updates etc. Base classes must call this or take all responsibility for /// setting Status as necessary /// </summary> /// <returns></returns> public override void TickTest() { IAppInstance App = null; if (TestInstance.ClientApps == null) { App = TestInstance.ServerApp; } else { if (TestInstance.ClientApps.Length > 0) { App = TestInstance.ClientApps.First(); } } if (App != null) { UnrealLogParser Parser = new UnrealLogParser(App.StdOut); // TODO - hardcoded for Orion List <string> TestLines = Parser.GetLogChannel("Gauntlet").ToList(); TestLines.AddRange(Parser.GetLogChannel("OrionTest")); for (int i = LastLogCount; i < TestLines.Count; i++) { Log.Info(TestLines[i]); if (Regex.IsMatch(TestLines[i], @".*GauntletHeartbeat\: Active.*")) { LastHeartbeatTime = DateTime.Now; LastActiveHeartbeatTime = DateTime.Now; } else if (Regex.IsMatch(TestLines[i], @".*GauntletHeartbeat\: Idle.*")) { LastHeartbeatTime = DateTime.Now; } } LastLogCount = TestLines.Count; // Detect missed heartbeats and fail the test CheckHeartbeat(); } // Check status and health after updating logs if (GetTestStatus() == TestStatus.InProgress && IsTestRunning() == false) { MarkTestComplete(); } }
/// <summary> /// Periodically called while the test is running. A chance for tests to examine their /// health, log updates etc. Base classes must call this or take all responsibility for /// setting Status as necessary /// </summary> /// <returns></returns> public override void TickTest() { IAppInstance App = null; if (TestInstance.ClientApps == null) { App = TestInstance.ServerApp; } else { if (TestInstance.ClientApps.Length > 0) { App = TestInstance.ClientApps.First(); } } if (App != null) { UnrealLogParser Parser = new UnrealLogParser(App.StdOut); // TODO - hardcoded for Orion List <string> TestLines = Parser.GetLogChannel("Gauntlet").ToList(); TestLines.AddRange(Parser.GetLogChannel("OrionTest")); for (int i = LastLogCount; i < TestLines.Count; i++) { Log.Info(TestLines[i]); } LastLogCount = TestLines.Count; } // Check status and health after updating logs if (GetTestStatus() == TestStatus.InProgress && IsTestRunning() == false) { MarkTestComplete(); } }
/// <summary> /// Retrieves and saves all artifacts from the provided session role. Artifacts are saved to the destination path /// </summary> /// <param name="InContext"></param> /// <param name="InRunningRole"></param> /// <param name="InDestArtifactPath"></param> /// <returns></returns> public UnrealRoleArtifacts SaveRoleArtifacts(UnrealTestContext InContext, UnrealSessionInstance.RoleInstance InRunningRole, string InDestArtifactPath) { bool IsServer = InRunningRole.Role.RoleType.IsServer(); string RoleName = (InRunningRole.Role.IsDummy() ? "Dummy" : "") + InRunningRole.Role.RoleType.ToString(); UnrealTargetPlatform?Platform = InRunningRole.Role.Platform; string RoleConfig = InRunningRole.Role.Configuration.ToString(); Directory.CreateDirectory(InDestArtifactPath); // Don't archive editor data, there can be a *lot* of stuff in that saved folder! bool IsEditor = InRunningRole.Role.RoleType.UsesEditor(); bool IsDevBuild = InContext.TestParams.ParseParam("dev"); string DestSavedDir = Path.Combine(InDestArtifactPath, "Saved"); string SourceSavedDir = ""; // save the contents of the saved directory SourceSavedDir = InRunningRole.AppInstance.ArtifactPath; // save the output from TTY string ArtifactLogPath = Path.Combine(InDestArtifactPath, RoleName + "Output.log"); // Write a brief Gauntlet header to aid debugging StringBuilder LogOut = new StringBuilder(); LogOut.AppendLine("------ Gauntlet Test ------"); LogOut.AppendFormat("Role: {0}\r\n", InRunningRole.Role); LogOut.AppendFormat("Automation Command: {0}\r\n", Environment.CommandLine); LogOut.AppendLine("---------------------------"); // Write instance stdout stream LogOut.Append(InRunningRole.AppInstance.StdOut); File.WriteAllText(ArtifactLogPath, LogOut.ToString()); Log.Info("Wrote Log to {0}", ArtifactLogPath); if (IsServer == false) { // gif-ify and jpeg-ify any screenshots try { string ScreenshotPath = Path.Combine(SourceSavedDir, "Screenshots", Platform.ToString()).ToLower(); if (Directory.Exists(ScreenshotPath) && Directory.GetFiles(ScreenshotPath).Length > 0) { Log.Info("Downsizing and gifying session images at {0}", ScreenshotPath); // downsize first so gif-step is quicker and takes less resoruces. Utils.Image.ConvertImages(ScreenshotPath, ScreenshotPath, "jpg", true); string GifPath = Path.Combine(InDestArtifactPath, RoleName + "Test.gif"); if (Utils.Image.SaveImagesAsGif(ScreenshotPath, GifPath)) { Log.Info("Saved gif to {0}", GifPath); } } } catch (Exception Ex) { Log.Info("Failed to downsize and gif-ify images! {0}", Ex); } } // don't archive data in dev mode, because peoples saved data could be huuuuuuuge! if (IsEditor == false) { LogLevel OldLevel = Log.Level; Log.Level = LogLevel.Normal; if (Directory.Exists(SourceSavedDir)) { Utils.SystemHelpers.CopyDirectory(SourceSavedDir, DestSavedDir); Log.Info("Archived artifacts to to {0}", DestSavedDir); } else { Log.Info("Archive path '{0}' was not found!", SourceSavedDir); } Log.Level = OldLevel; } else { if (IsEditor) { Log.Info("Skipping archival of assets for editor {0}", RoleName); } else if (IsDevBuild) { Log.Info("Skipping archival of assets for dev build"); } } foreach (EIntendedBaseCopyDirectory ArtifactDir in InRunningRole.Role.AdditionalArtifactDirectories) { if (InRunningRole.AppInstance.Device.GetPlatformDirectoryMappings().ContainsKey(ArtifactDir)) { string SourcePath = InRunningRole.AppInstance.Device.GetPlatformDirectoryMappings()[ArtifactDir]; var DirToCopy = new DirectoryInfo(SourcePath); if (DirToCopy.Exists) { // Grab the final dir name to copy everything into so everything's not just going into root artifact dir. string IntendedCopyLocation = Path.Combine(InDestArtifactPath, DirToCopy.Name); Utils.SystemHelpers.CopyDirectory(SourcePath, IntendedCopyLocation); } } } // TODO REMOVEME- this should go elsewhere, likely a util that can be called or inserted by relevant test nodes. if (IsServer == false) { // Copy over PSOs try { if (InContext.Options.LogPSO) { foreach (var ThisFile in CommandUtils.FindFiles_NoExceptions(true, "*.rec.upipelinecache", true, DestSavedDir)) { bool Copied = false; var JustFile = Path.GetFileName(ThisFile); if (JustFile.StartsWith("++")) { var Parts = JustFile.Split(new Char[] { '+', '-' }).Where(A => A != "").ToArray(); if (Parts.Count() >= 2) { string ProjectName = Parts[0].ToString(); string BuildRoot = CommandUtils.CombinePaths(CommandUtils.RootBuildStorageDirectory()); string SrcBuildPath = CommandUtils.CombinePaths(BuildRoot, ProjectName); string SrcBuildPath2 = CommandUtils.CombinePaths(BuildRoot, ProjectName.Replace("Game", "").Replace("game", "")); if (!CommandUtils.DirectoryExists(SrcBuildPath)) { SrcBuildPath = SrcBuildPath2; } if (CommandUtils.DirectoryExists(SrcBuildPath)) { var JustBuildFolder = JustFile.Replace("-" + Parts.Last(), ""); string PlatformStr = Platform.ToString(); string SrcCLMetaPath = CommandUtils.CombinePaths(SrcBuildPath, JustBuildFolder, PlatformStr, "MetaData"); if (CommandUtils.DirectoryExists(SrcCLMetaPath)) { string SrcCLMetaPathCollected = CommandUtils.CombinePaths(SrcCLMetaPath, "CollectedPSOs"); if (!CommandUtils.DirectoryExists(SrcCLMetaPathCollected)) { Log.Info("Creating Directory {0}", SrcCLMetaPathCollected); CommandUtils.CreateDirectory(SrcCLMetaPathCollected); } if (CommandUtils.DirectoryExists(SrcCLMetaPathCollected)) { string DestFile = CommandUtils.CombinePaths(SrcCLMetaPathCollected, JustFile); CommandUtils.CopyFile_NoExceptions(ThisFile, DestFile, true); if (CommandUtils.FileExists(true, DestFile)) { Log.Info("Deleting local file, copied to {0}", DestFile); CommandUtils.DeleteFile_NoExceptions(ThisFile, true); Copied = true; } } } } } } if (!Copied) { Log.Warning("Could not find anywhere to put this file {0}", JustFile); } } } } catch (Exception Ex) { Log.Info("Failed to copy upipelinecaches to the network {0}", Ex); } } // END REMOVEME UnrealLogParser LogParser = new UnrealLogParser(InRunningRole.AppInstance.StdOut); int ExitCode = InRunningRole.AppInstance.ExitCode; LogParser.GetTestExitCode(out ExitCode); UnrealRoleArtifacts Artifacts = new UnrealRoleArtifacts(InRunningRole.Role, InRunningRole.AppInstance, InDestArtifactPath, ArtifactLogPath, LogParser); return(Artifacts); }
/// <summary> /// Constructor that takes raw log contents /// </summary> /// <param name="InContents"></param> public AutomationLogParser(string InContents) { Parser = new UnrealLogParser(InContents); }
/// <summary> /// Constructor that uses an existing log parser /// </summary> /// <param name="InParser"></param> public AutomationLogParser(UnrealLogParser InParser) { Parser = InParser; }
protected virtual void CreateFromLog(string LogContents, string InTitle) { UnrealLogParser Parser = new UnrealLogParser(LogContents); if (string.IsNullOrEmpty(InTitle)) { InTitle = "=== Snapshot: "; } try { // Find all end of match reports string[] SessionSnapshots = Parser.GetGroupsOfLinesStartingWith(InTitle, 20); SampleCount = SessionSnapshots.Length; SessionTime = 0; // convert these blocks into snapshot info Snapshots = SessionSnapshots.Select(S => { var Snapshot = new TSnapshotClass(); Snapshot.CreateFromString(S); return(Snapshot); }).ToList(); // get average MVP, GT, RT, GPU times foreach (UnrealHealthSnapshot Snap in Snapshots) { SessionTime += Snap.ProfileLength; MVP.Add(Snap.MVP); if (Snap.AvgFps > 0) { AvgFps.Add(Snap.AvgFps); } Hitches.Add(Snap.Hitches); AvgHitches.Add(Snap.AvgHitches); if (Snap.DynamicRes > 0) { DynamicRes.Add(Snap.DynamicRes); } if (Snap.GTTime > 0) { GTTime.Add(Snap.GTTime); } if (Snap.RTTime > 0) { RTTime.Add(Snap.RTTime); } if (Snap.GPUTime > 0) { GPUTime.Add(Snap.GPUTime); } if (Snap.FTTime > 0) { FTTime.Add(Snap.FTTime); } if (Snap.RHIT > 0) { RHIT.Add(Snap.RHIT); } if (Snap.DrawCalls > 0) { DrawCalls.Add(Snap.DrawCalls); DrawnPrims.Add(Snap.DrawnPrims); } if (Snap.UnbuiltHLODs > 0) { UnbuiltHLODs.Add(Snap.UnbuiltHLODs); } } // Now get peak memory from the last health report if (Snapshots.Count() > 0) { var LastSnapshot = Snapshots.Last(); float SnapshotPeakMemory = LastSnapshot.PhysicalPeakMemory; //if PeakMemory is reporting as 0, use Memory if it's higher than our last if (SnapshotPeakMemory == 0) { Log.Info("PeakMemory reported as 0mb"); } else { PeakMemory = SnapshotPeakMemory; } } } catch (Exception Ex) { Log.Info("Failed parsing PerformanceSummary: " + Ex.ToString()); } }