Example #1
0
        /// <summary>
        /// Returns a hash that represents the results of a role. Should be 0 if no fatal errors or ensures
        /// </summary>
        /// <param name="InArtifacts"></param>
        /// <returns></returns>
        protected virtual string GetRoleResultHash(UnrealRoleArtifacts InArtifacts)
        {
            const int MaxCallstackLines = 10;

            UnrealLogParser.LogSummary LogSummary = InArtifacts.LogSummary;

            string TotalString = "";

            //Func<int, string> ComputeHash = (string Str) => { return Hasher.ComputeHash(Encoding.UTF8.GetBytes(Str)); };

            if (LogSummary.FatalError != null)
            {
                TotalString += string.Join("\n", InArtifacts.LogSummary.FatalError.Callstack.Take(MaxCallstackLines));
                TotalString += "\n";
            }

            foreach (var Ensure in LogSummary.Ensures)
            {
                TotalString += string.Join("\n", Ensure.Callstack.Take(MaxCallstackLines));
                TotalString += "\n";
            }

            string Hash = Hasher.ComputeHash(TotalString);

            return(Hash);
        }
Example #2
0
        /// <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);
        }
Example #3
0
        /// <summary>
        /// Parses the output of an application to try and determine a failure cause (if one exists). Returns
        /// 0 for graceful shutdown
        /// </summary>
        /// <param name="Prefix"></param>
        /// <param name="App"></param>
        /// <returns></returns>
        protected virtual int GetRoleSummary(UnrealRoleArtifacts InArtifacts, out string Summary)
        {
            const int MaxLogLines       = 10;
            const int MaxCallstackLines = 20;

            UnrealLogParser.LogSummary LogSummary = InArtifacts.LogSummary;

            string ExitReason = "Unknown";
            int    ExitCode   = GetExitCodeAndReason(InArtifacts, out ExitReason);

            MarkdownBuilder MB = new MarkdownBuilder();

            MB.H3(string.Format("Role: {0} ({1} {2})", InArtifacts.SessionRole.RoleType, InArtifacts.SessionRole.Platform, InArtifacts.SessionRole.Configuration));

            if (ExitCode != 0)
            {
                MB.H4(string.Format("Result: Abnormal Exit: {0}", ExitReason));
            }
            else
            {
                MB.H4(string.Format("Result: {0}", ExitReason));
            }

            int FatalErrors = LogSummary.FatalError != null ? 1 : 0;

            if (LogSummary.FatalError != null)
            {
                MB.H4(string.Format("Fatal Error: {0}", LogSummary.FatalError.Message));
                MB.UnorderedList(InArtifacts.LogSummary.FatalError.Callstack.Take(MaxCallstackLines));

                if (InArtifacts.LogSummary.FatalError.Callstack.Count() > MaxCallstackLines)
                {
                    MB.Paragraph("See log for full callstack");
                }
            }

            if (LogSummary.Ensures.Count() > 0)
            {
                foreach (var Ensure in LogSummary.Ensures)
                {
                    MB.H4(string.Format("Ensure: {0}", Ensure.Message));
                    MB.UnorderedList(Ensure.Callstack.Take(MaxCallstackLines));

                    if (Ensure.Callstack.Count() > MaxCallstackLines)
                    {
                        MB.Paragraph("See log for full callstack");
                    }
                }
            }

            MB.Paragraph(string.Format("FatalErrors: {0}, Ensures: {1}, Errors: {2}, Warnings: {3}",
                                       FatalErrors, LogSummary.Ensures.Count(), LogSummary.Errors.Count(), LogSummary.Warnings.Count()));

            if (GetConfiguration().ShowErrorsInSummary&& InArtifacts.LogSummary.Errors.Count() > 0)
            {
                MB.H4("Errors");
                MB.UnorderedList(LogSummary.Errors.Take(MaxLogLines));

                if (LogSummary.Errors.Count() > MaxLogLines)
                {
                    MB.Paragraph(string.Format("(First {0} of {1} errors)", MaxLogLines, LogSummary.Errors.Count()));
                }
            }

            if (GetConfiguration().ShowWarningsInSummary&& InArtifacts.LogSummary.Warnings.Count() > 0)
            {
                MB.H4("Warnings");
                MB.UnorderedList(LogSummary.Warnings.Take(MaxLogLines));

                if (LogSummary.Warnings.Count() > MaxLogLines)
                {
                    MB.Paragraph(string.Format("(First {0} of {1} warnings)", MaxLogLines, LogSummary.Warnings.Count()));
                }
            }

            MB.H4("Artifacts");
            MB.Paragraph(string.Format("Log: {0}", InArtifacts.LogPath));
            MB.Paragraph(string.Format("Commandline: {0}", InArtifacts.AppInstance.CommandLine));
            MB.Paragraph(InArtifacts.ArtifactPath);

            Summary = MB.ToString();
            return(ExitCode);
        }
Example #4
0
        /// <summary>
        /// Parses the provided artifacts to determine the cause of an exit and whether it was abnormal
        /// </summary>
        /// <param name="InArtifacts"></param>
        /// <param name="Reason"></param>
        /// <param name="WasAbnormal"></param>
        /// <returns></returns>
        protected virtual int GetExitCodeAndReason(UnrealRoleArtifacts InArtifacts, out string ExitReason)
        {
            UnrealLogParser.LogSummary LogSummary = InArtifacts.LogSummary;

            // Assume failure!
            int ExitCode = -1;

            ExitReason = "Unknown";

            if (LogSummary.FatalError != null)
            {
                ExitReason = "Process encountered fatal error";
            }
            else if (LogSummary.Ensures.Count() > 0 && CachedConfig.FailOnEnsures)
            {
                ExitReason = string.Format("Process encountered {0} Ensures", LogSummary.Ensures.Count());
            }
            else if (InArtifacts.AppInstance.WasKilled)
            {
                ExitReason = "Process was killed";
            }
            else if (LogSummary.HasTestExitCode)
            {
                if (LogSummary.TestExitCode == 0)
                {
                    ExitReason = "Process exited with code 0";
                }
                else
                {
                    ExitReason = string.Format("Process exited with error code {0}", LogSummary.TestExitCode);
                }

                ExitCode = LogSummary.TestExitCode;
            }
            else if (LogSummary.RequestedExit)
            {
                ExitReason = string.Format("Process requested exit with no fatal errors");
                ExitCode   = 0;
            }
            else
            {
                // ok, process appears to have exited for no good reason so try to divine a result...
                if (LogSummary.HasTestExitCode == false &&
                    InArtifacts.SessionRole.CommandLine.ToLower().Contains("-gauntlet"))
                {
                    Log.Verbose("Role {0} had 0 exit code but used Gauntlet and no TestExitCode was found. Assuming failure", InArtifacts.SessionRole.RoleType);
                    ExitCode   = -1;
                    ExitReason = "No test result from Gauntlet controller";
                }
            }

            // Normal exits from server are not ok if we had clients running!
            if (ExitCode == 0 && InArtifacts.SessionRole.RoleType.IsServer())
            {
                bool ClientsKilled = SessionArtifacts.Any(A => A.AppInstance.WasKilled && A.SessionRole.RoleType.IsClient());

                if (ClientsKilled)
                {
                    ExitCode   = -1;
                    ExitReason = "Server exited while clients were running";
                }
            }

            if (ExitCode == -1 && string.IsNullOrEmpty(ExitReason))
            {
                ExitReason = "Process exited with no indication of success";
            }

            return(ExitCode);
        }