1335 lines
71 KiB
C#
1335 lines
71 KiB
C#
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Runtime.InteropServices;
|
|
using System.Text;
|
|
using EpicGames.Core;
|
|
using EpicGames.Perforce;
|
|
using Microsoft.Extensions.Logging;
|
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
|
|
|
namespace AutomationTool.Tests
|
|
{
|
|
[TestClass]
|
|
public class LogParserTests
|
|
{
|
|
const string LogLine = "LogLine";
|
|
|
|
static readonly DirectoryReference s_rootDir = new DirectoryReference(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "C:\\Horde" : "/horde");
|
|
|
|
static string MakeAbsolutePath(string path) => FileReference.Combine(s_rootDir, path).FullName;
|
|
|
|
class LoggerCapture : ILogger
|
|
{
|
|
int _logLineIndex;
|
|
|
|
public List<LogEvent> _events = new List<LogEvent>();
|
|
|
|
public IDisposable? BeginScope<TState>(TState state) where TState : notnull => null!;
|
|
|
|
public bool IsEnabled(LogLevel logLevel) => true;
|
|
|
|
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func<TState, Exception?, string> formatter)
|
|
{
|
|
LogEvent logEvent = LogEvent.Read(JsonLogEvent.FromLoggerState(logLevel, eventId, state, exception, formatter).Data.Span);
|
|
if (logEvent.Level != LogLevel.Information || logEvent.Id != default || logEvent.Properties != null)
|
|
{
|
|
KeyValuePair<string, object?>[] items = new[] { new KeyValuePair<string, object?>(LogLine, _logLineIndex) };
|
|
logEvent.Properties = (logEvent.Properties == null) ? items : Enumerable.Concat(logEvent.Properties, items);
|
|
_events.Add(logEvent);
|
|
}
|
|
|
|
_logLineIndex++;
|
|
}
|
|
}
|
|
|
|
[TestMethod]
|
|
public void StructuredOutputMatcher()
|
|
{
|
|
string[] lines =
|
|
{
|
|
new LogEvent(DateTime.UtcNow, LogLevel.Information, new EventId(123), "Hello 123", null, null, null).ToJson(),
|
|
new LogEvent(DateTime.UtcNow, LogLevel.Information, default, "Building 43 projects (see Log \u0027Engine/Programs/AutomationTool/Saved/Logs/Log.txt\u0027 for more details)", null, null, null).ToJson(),
|
|
new LogEvent(DateTime.UtcNow, LogLevel.Warning, default, " Restore...", null, null, null).ToJson(),
|
|
new LogEvent(DateTime.UtcNow, LogLevel.Error, default, " Build...", null, null, null).ToJson(),
|
|
};
|
|
|
|
List<LogEvent> logEvents = Parse(lines);
|
|
Assert.AreEqual(3, logEvents.Count);
|
|
|
|
int idx = 0;
|
|
|
|
LogEvent logEvent = logEvents[idx++];
|
|
Assert.AreEqual(LogLevel.Information, logEvent.Level);
|
|
Assert.AreEqual(new EventId(123), logEvent.Id);
|
|
Assert.AreEqual("Hello 123", logEvent.Message);
|
|
|
|
logEvent = logEvents[idx++];
|
|
Assert.AreEqual(LogLevel.Warning, logEvent.Level);
|
|
Assert.AreEqual(new EventId(0), logEvent.Id);
|
|
Assert.AreEqual(" Restore...", logEvent.Message);
|
|
|
|
logEvent = logEvents[idx++];
|
|
Assert.AreEqual(LogLevel.Error, logEvent.Level);
|
|
Assert.AreEqual(new EventId(0), logEvent.Id);
|
|
Assert.AreEqual(" Build...", logEvent.Message);
|
|
}
|
|
|
|
[TestMethod]
|
|
public void ExitCodeEventMatcher()
|
|
{
|
|
string[] lines =
|
|
{
|
|
@"Took 620.820352s to run UE4Editor-Cmd.exe, ExitCode=777003",
|
|
@"Editor terminated with exit code 777003 while running GenerateSkinSwapDetections for D:\Build\++UE5\Sync\ShooterGame\ShooterGame.uproject; see log D:\Build\++UE5\Sync\Engine\Programs\AutomationTool\Saved\Logs\GenerateSkinSwapDetections-2020.08.18-21.47.07.txt",
|
|
@"Error executing D:\build\++ShooterGame\Sync\Engine\Build\Windows\link - filter\link - filter.exe(tool returned code: STATUS_ACCESS_VIOLATION)",
|
|
@"Error executing C:\Windows\system32\cmd.exe (tool returned code: 1)",
|
|
@"AutomationTool exiting with ExitCode=1 (Error_Unknown)",
|
|
@"BUILD FAILED"
|
|
};
|
|
|
|
List<LogEvent> logEvents = Parse(lines);
|
|
CheckEventGroup(logEvents, 1, 3, LogLevel.Error, KnownLogEvents.ExitCode);
|
|
}
|
|
|
|
[TestMethod]
|
|
public void ExitCodeEventMatcher2()
|
|
{
|
|
string[] lines =
|
|
{
|
|
@"1 error generated.",
|
|
@"",
|
|
@"Error executing d:\build\AutoSDK\Sync\HostWin64\Android\-24\ndk\21.4.7075529\toolchains\llvm\prebuilt\windows-x86_64\bin\clang++.exe (tool returned code: 1)",
|
|
};
|
|
|
|
List<LogEvent> logEvents = Parse(lines);
|
|
CheckEventGroup(logEvents, 2, 1, LogLevel.Error, KnownLogEvents.ExitCode);
|
|
}
|
|
|
|
[TestMethod]
|
|
public void ExitCodeEventMatcher3()
|
|
{
|
|
string[] lines =
|
|
{
|
|
@"Took 5406.5523184s to run UnrealEditor-Cmd.exe, ExitCode=-1073741819",
|
|
@"Editor terminated with exit code -1073741819 while running Cook for D:\build\++UE5\Sync\Samples\Games\AncientGame\AncientGame.uproject; see log d:\build\++UE5\Sync\Engine\Programs\AutomationTool\Saved\Logs\Cook-2022.11.11-08.02.19.txt",
|
|
@"AutomationTool executed for 1h 33m 5s",
|
|
@"AutomationTool exiting with ExitCode=1 (Error_Unknown)",
|
|
@"BUILD FAILED"
|
|
};
|
|
|
|
List<LogEvent> logEvents = Parse(lines);
|
|
CheckEventGroup(logEvents, 1, 1, LogLevel.Error, KnownLogEvents.ExitCode);
|
|
}
|
|
|
|
[TestMethod]
|
|
public void ExitCodeEventMatcher4()
|
|
{
|
|
string[] lines =
|
|
{
|
|
@"/app/Source/Programs/Horde/Plugins/Build/HordeServer.Build.Tests/Agents/AgentServiceTest.cs(221,126): error CS1503: Argument 4: cannot convert from 'EpicGames.Horde.Agents.AgentStatus?' to 'EpicGames.Horde.Agents.AgentStatus' [/app/Source/Programs/Horde/Plugins/Build/HordeServer.Build.Tests/HordeServer.Build.Tests.csproj]",
|
|
@"ERROR: process ""/bin/sh -c bash Source/Programs/Horde/Scripts/test.sh"" did not complete successfully: exit code: 1"
|
|
};
|
|
|
|
List<LogEvent> logEvents = Parse(lines);
|
|
CheckEventGroup(logEvents.Slice(0, 1), 0, 1, LogLevel.Error, KnownLogEvents.Compiler);
|
|
CheckEventGroup(logEvents.Slice(1, 1), 1, 1, LogLevel.Error, KnownLogEvents.ExitCode);
|
|
}
|
|
|
|
[TestMethod]
|
|
public void CrashEventMatcher()
|
|
{
|
|
string[] lines =
|
|
{
|
|
@" LogOutputDevice: Error: begin: stack for UAT",
|
|
@" LogOutputDevice: Error: === Handled ensure: ===",
|
|
@" LogOutputDevice: Error:",
|
|
@" LogOutputDevice: Error: Ensure condition failed: Foo [File:D:/build/++UE5/Sync/Foo.cpp] [Line: 233]",
|
|
@" LogOutputDevice: Error:",
|
|
@" LogOutputDevice: Error: Stack:",
|
|
@" LogOutputDevice: Error: [Callstack] 0x00007ff6b68a035d UnrealEditor-Cmd.exe!GuardedMain() [D:\build\++UE5\Sync\Engine\Source\Runtime\Launch\Private\Launch.cpp:129]",
|
|
@" LogOutputDevice: Error: [Callstack] 0x00007ff6b68a05fa UnrealEditor-Cmd.exe!GuardedMainWrapper() [D:\build\++UE5\Sync\Engine\Source\Runtime\Launch\Private\Windows\LaunchWindows.cpp:142]",
|
|
@" LogOutputDevice: Error: [Callstack] 0x00007ff6b68b522d UnrealEditor-Cmd.exe!WinMain() [D:\build\++UE5\Sync\Engine\Source\Runtime\Launch\Private\Windows\LaunchWindows.cpp:273]",
|
|
@" LogOutputDevice: Error: [Callstack] 0x00007ff6b68b7522 UnrealEditor-Cmd.exe!__scrt_common_main_seh() [D:\a01\_work\9\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:288]",
|
|
@" LogOutputDevice: Error: [Callstack] 0x00007ff96a517974 KERNEL32.DLL!UnknownFunction []",
|
|
@" LogOutputDevice: Error: [Callstack] 0x00007ff96d14a271 ntdll.dll!UnknownFunction []",
|
|
@" LogOutputDevice: Error:",
|
|
@" LogOutputDevice: Error: end: stack for UAT"
|
|
};
|
|
|
|
{
|
|
List<LogEvent> logEvents = Parse(String.Join("\n", lines));
|
|
CheckEventGroup(logEvents, 0, 14, LogLevel.Error, KnownLogEvents.Engine_Crash);
|
|
}
|
|
|
|
{
|
|
List<LogEvent> logEvents = Parse(String.Join("\n", lines).Replace("Error:", "Warning:", StringComparison.Ordinal));
|
|
CheckEventGroup(logEvents, 0, 14, LogLevel.Warning, KnownLogEvents.Engine_Crash);
|
|
}
|
|
}
|
|
|
|
[TestMethod]
|
|
public void CrashEventMatcher2()
|
|
{
|
|
string[] lines =
|
|
{
|
|
@"Took 620.820352s to run UE4Editor-Cmd.exe, ExitCode=3",
|
|
@"Took 620.820352s to run UE4Editor-Cmd.exe, ExitCode=30",
|
|
};
|
|
|
|
List<LogEvent> logEvents = Parse(lines);
|
|
CheckEventGroup(logEvents, 0, 1, LogLevel.Error, KnownLogEvents.AutomationTool_CrashExitCode);
|
|
}
|
|
|
|
[TestMethod]
|
|
public void AssertionFailedEventMatcher()
|
|
{
|
|
string[] lines =
|
|
{
|
|
@"Assertion failed: !NumUsed.GetValue() [File:Runtime/Core/Public/Containers/LockFreeFixedSizeAllocator.h] [Line: 201]"
|
|
};
|
|
|
|
List<LogEvent> logEvents = Parse(lines);
|
|
CheckEventGroup(logEvents, 0, 1, LogLevel.Error, KnownLogEvents.Engine_AssertionFailed);
|
|
}
|
|
|
|
[TestMethod]
|
|
public void SymbolStripSpuriousEventMatcher()
|
|
{
|
|
// Symbol stripping error
|
|
{
|
|
string[] lines =
|
|
{
|
|
@"Stripping symbols: d:\build\++UE5\Sync\Engine\Plugins\Runtime\GoogleVR\GoogleVRController\Binaries\Win64\UnrealEditor-GoogleVRController.pdb -> d:\build\++UE5\Sync\ArchiveForUGS\Staging\Engine\Plugins\Runtime\GoogleVR\GoogleVRController\Binaries\Win64\UnrealEditor-GoogleVRController.pdb",
|
|
@"ERROR: Error: EC_OK -- ??",
|
|
@"ERROR:",
|
|
@"Stripping symbols: d:\build\++UE5\Sync\Engine\Plugins\Runtime\GoogleVR\GoogleVRHMD\Binaries\Win64\UnrealEditor-GoogleVRHMD.pdb -> d:\build\++UE5\Sync\ArchiveForUGS\Staging\Engine\Plugins\Runtime\GoogleVR\GoogleVRHMD\Binaries\Win64\UnrealEditor-GoogleVRHMD.pdb",
|
|
};
|
|
|
|
List<LogEvent> logEvents = Parse(String.Join("\n", lines));
|
|
CheckEventGroup(logEvents, 1, 2, LogLevel.Information, KnownLogEvents.Systemic_PdbUtil);
|
|
}
|
|
}
|
|
|
|
[TestMethod]
|
|
public void CsCompileEventMatcher()
|
|
{
|
|
// C# compile error
|
|
{
|
|
string[] lines =
|
|
{
|
|
@" GenerateSigningRequestDialog.cs(22,7): error CS0246: The type or namespace name 'Org' could not be found (are you missing a using directive or an assembly reference?) [" + MakeAbsolutePath(@"Engine\Source\Programs\IOS\iPhonePackager\iPhonePackager.csproj") + @"]",
|
|
@" Utilities.cs(16,7): error CS0246: The type or namespace name 'Org' could not be found (are you missing a using directive or an assembly reference?) [" + MakeAbsolutePath(@"Engine\Source\Programs\IOS\iPhonePackager\iPhonePackager.csproj") + @"]"
|
|
};
|
|
|
|
List<LogEvent> logEvents = Parse(String.Join("\n", lines));
|
|
Assert.AreEqual(2, logEvents.Count);
|
|
|
|
CheckEventGroup(logEvents.Slice(0, 1), 0, 1, LogLevel.Error, KnownLogEvents.Compiler);
|
|
Assert.AreEqual("CS0246", logEvents[0].GetProperty("code").ToString());
|
|
Assert.AreEqual("22", logEvents[0].GetProperty("line").ToString());
|
|
|
|
LogValue fileProperty1 = (LogValue)logEvents[0].GetProperty("file");
|
|
Assert.AreEqual(@"GenerateSigningRequestDialog.cs", fileProperty1.Text);
|
|
Assert.AreEqual(@"SourceFile", fileProperty1.Type.ToString());
|
|
Assert.AreEqual(@"Engine/Source/Programs/IOS/iPhonePackager/GenerateSigningRequestDialog.cs", fileProperty1.Properties![LogEventPropertyName.RelativePath]?.ToString());
|
|
Assert.AreEqual(@"//UE4/Main/Engine/Source/Programs/IOS/iPhonePackager/GenerateSigningRequestDialog.cs@12345", fileProperty1.Properties[LogEventPropertyName.DepotPath]?.ToString());
|
|
|
|
CheckEventGroup(logEvents.Slice(1, 1), 1, 1, LogLevel.Error, KnownLogEvents.Compiler);
|
|
Assert.AreEqual("CS0246", logEvents[1].GetProperty("code").ToString());
|
|
Assert.AreEqual("16", logEvents[1].GetProperty("line").ToString());
|
|
|
|
LogValue fileProperty2 = (LogValue)logEvents[1].GetProperty("file");
|
|
Assert.AreEqual(@"Utilities.cs", fileProperty2.Text);
|
|
Assert.AreEqual(@"SourceFile", fileProperty2.Type.ToString());
|
|
Assert.AreEqual(@"Engine/Source/Programs/IOS/iPhonePackager/Utilities.cs", fileProperty2.Properties![LogEventPropertyName.RelativePath]?.ToString());
|
|
Assert.AreEqual(@"//UE4/Main/Engine/Source/Programs/IOS/iPhonePackager/Utilities.cs@12345", fileProperty2.Properties[LogEventPropertyName.DepotPath]?.ToString());
|
|
}
|
|
}
|
|
|
|
[TestMethod]
|
|
public void CsCompileEventMatcher2()
|
|
{
|
|
// C# compile error
|
|
{
|
|
string[] lines =
|
|
{
|
|
@" Configuration\TargetRules.cs(1497,58): warning CS8625: Cannot convert null literal to non-nullable reference type. [" + MakeAbsolutePath(@"Engine\Source\Programs\UnrealBuildTool\UnrealBuildTool.csproj") + @"]",
|
|
};
|
|
|
|
List<LogEvent> events = Parse(String.Join("\n", lines));
|
|
CheckEventGroup(events, 0, 1, LogLevel.Warning, KnownLogEvents.Compiler);
|
|
|
|
Assert.AreEqual("CS8625", events[0].GetProperty("code").ToString());
|
|
Assert.AreEqual("1497", events[0].GetProperty("line").ToString());
|
|
|
|
LogValue fileProperty = (LogValue)events[0].GetProperty("file");
|
|
Assert.AreEqual(@"Configuration\TargetRules.cs", fileProperty.Text);
|
|
Assert.AreEqual(@"SourceFile", fileProperty.Type.ToString());
|
|
Assert.AreEqual(@"Engine/Source/Programs/UnrealBuildTool/Configuration/TargetRules.cs", fileProperty.Properties![LogEventPropertyName.RelativePath]?.ToString());
|
|
Assert.AreEqual(@"//UE4/Main/Engine/Source/Programs/UnrealBuildTool/Configuration/TargetRules.cs@12345", fileProperty.Properties![LogEventPropertyName.DepotPath]?.ToString());
|
|
}
|
|
}
|
|
|
|
[TestMethod]
|
|
public void CsCompileEventMatcher3()
|
|
{
|
|
// C# compile error from UBT
|
|
{
|
|
string absPath = MakeAbsolutePath(@"Engine\Source\Runtime\CoreOnline\CoreOnline.Build.cs");
|
|
|
|
string[] lines =
|
|
{
|
|
@" ERROR: " + absPath + @"(4,7): error CS0246: The type or namespace name 'Tools' could not be found (are you missing a using directive or an assembly reference?)",
|
|
@" WARNING: " + absPath + @"(4,7): warning CS0246: The type or namespace name 'Tools' could not be found (are you missing a using directive or an assembly reference?)"
|
|
};
|
|
|
|
List<LogEvent> logEvents = Parse(String.Join("\n", lines));
|
|
Assert.AreEqual(2, logEvents.Count);
|
|
|
|
CheckEventGroup(logEvents.Slice(0, 1), 0, 1, LogLevel.Error, KnownLogEvents.Compiler);
|
|
Assert.AreEqual("CS0246", logEvents[0].GetProperty("code").ToString());
|
|
Assert.AreEqual("4", logEvents[0].GetProperty("line").ToString());
|
|
|
|
LogValue fileProperty = (LogValue)logEvents[0].GetProperty("file");
|
|
Assert.AreEqual(absPath, fileProperty.Text);
|
|
Assert.AreEqual(@"SourceFile", fileProperty.Type.ToString());
|
|
Assert.AreEqual(@"Engine/Source/Runtime/CoreOnline/CoreOnline.Build.cs", fileProperty.Properties![LogEventPropertyName.RelativePath]?.ToString());
|
|
Assert.AreEqual(@"//UE4/Main/Engine/Source/Runtime/CoreOnline/CoreOnline.Build.cs@12345", fileProperty.Properties![LogEventPropertyName.DepotPath]?.ToString());
|
|
|
|
CheckEventGroup(logEvents.Slice(1, 1), 1, 1, LogLevel.Warning, KnownLogEvents.Compiler);
|
|
Assert.AreEqual("CS0246", logEvents[1].GetProperty("code").ToString());
|
|
Assert.AreEqual("4", logEvents[1].GetProperty("line").ToString());
|
|
|
|
LogValue fileProperty1 = logEvents[1].GetProperty<LogValue>("file");
|
|
Assert.AreEqual(absPath, fileProperty1.Text);
|
|
Assert.AreEqual(@"SourceFile", fileProperty1.Type.ToString());
|
|
Assert.AreEqual(@"Engine/Source/Runtime/CoreOnline/CoreOnline.Build.cs", fileProperty1.Properties![LogEventPropertyName.RelativePath]?.ToString());
|
|
Assert.AreEqual(@"//UE4/Main/Engine/Source/Runtime/CoreOnline/CoreOnline.Build.cs@12345", fileProperty1.Properties![LogEventPropertyName.DepotPath]?.ToString());
|
|
}
|
|
}
|
|
|
|
[TestMethod]
|
|
public void CsCompileEventMatcher4()
|
|
{
|
|
// C# compile error from UBT startup
|
|
{
|
|
string[] lines =
|
|
{
|
|
@"Building AutomationTool...",
|
|
@"Microsoft (R) Build Engine version 17.2.0+41abc5629 for .NET",
|
|
@"Copyright (C) Microsoft Corporation. All rights reserved.",
|
|
@"Engine/Source/Programs/Shared/EpicGames.Horde/Storage/Workspace.cs(405,11): error CS1501: No overload for method 'ReadList' takes 2 arguments [Engine/Source/Programs/Shared/EpicGames.Horde/EpicGames.Horde.csproj]",
|
|
@"Engine/Source/Programs/Shared/EpicGames.Horde/Storage/Workspace.cs(423,12): error CS1501: No overload for method 'ReadList' takes 2 arguments [Engine/Source/Programs/Shared/EpicGames.Horde/EpicGames.Horde.csproj]",
|
|
@"Build FAILED.",
|
|
@"Engine/Source/Programs/Shared/EpicGames.Horde/Storage/Workspace.cs(405,11): error CS1501: No overload for method 'ReadList' takes 2 arguments [Engine/Source/Programs/Shared/EpicGames.Horde/EpicGames.Horde.csproj]",
|
|
@"Engine/Source/Programs/Shared/EpicGames.Horde/Storage/Workspace.cs(423,12): error CS1501: No overload for method 'ReadList' takes 2 arguments [Engine/Source/Programs/Shared/EpicGames.Horde/EpicGames.Horde.csproj]",
|
|
@" 0 Warning(s)",
|
|
@" 2 Error(s)",
|
|
@"Time Elapsed 00:00:06.84",
|
|
@"RunUBT ERROR: UnrealBuildTool failed to compile.",
|
|
@"RunUAT.bat ERROR: AutomationTool failed to compile.",
|
|
@"BUILD FAILED",
|
|
};
|
|
|
|
List<LogEvent> logEvents = Parse(String.Join("\n", lines));
|
|
Assert.AreEqual(6, logEvents.Count);
|
|
|
|
CheckEventGroup(logEvents.Slice(0, 1), 3, 1, LogLevel.Error, KnownLogEvents.Compiler);
|
|
CheckEventGroup(logEvents.Slice(1, 1), 4, 1, LogLevel.Error, KnownLogEvents.Compiler);
|
|
CheckEventGroup(logEvents.Slice(2, 1), 6, 1, LogLevel.Error, KnownLogEvents.Compiler);
|
|
CheckEventGroup(logEvents.Slice(3, 1), 7, 1, LogLevel.Error, KnownLogEvents.Compiler);
|
|
CheckEventGroup(logEvents.Slice(4, 1), 11, 1, LogLevel.Error, KnownLogEvents.Compiler_Summary);
|
|
CheckEventGroup(logEvents.Slice(5, 1), 12, 1, LogLevel.Error, KnownLogEvents.Compiler_Summary);
|
|
}
|
|
}
|
|
|
|
[TestMethod]
|
|
public void CsCompileEventMatcher5()
|
|
{
|
|
string[] lines =
|
|
{
|
|
@" EpicGames.BuildGraph.Tests -> /mnt/horde/DMH/Sync/Engine/Source/Programs/Shared/EpicGames.BuildGraph.Tests/bin/Analyze/net6.0/EpicGames.BuildGraph.Tests.dll",
|
|
@"Engine/Source/Programs/Shared/EpicGames.Horde/Storage/BlobData.cs(4,1): warning IDE0005: Using directive is unnecessary. [/mnt/horde/DMH/Sync/Engine/Source/Programs/Shared/EpicGames.Horde/EpicGames.Horde.csproj]",
|
|
@"Engine/Source/Programs/Shared/EpicGames.Horde/Storage/BlobData.cs(7,1): warning IDE0005: Using directive is unnecessary. [/mnt/horde/DMH/Sync/Engine/Source/Programs/Shared/EpicGames.Horde/EpicGames.Horde.csproj]",
|
|
@" EpicGames.Horde -> /mnt/horde/DMH/Sync/Engine/Source/Programs/Shared/EpicGames.Horde/bin/Analyze/net6.0/EpicGames.Horde.dll",
|
|
@" RemoteWorker -> /mnt/horde/DMH/Sync/Engine/Source/Programs/Horde/Samples/RemoteWorker/bin/Debug/net6.0/RemoteWorker.dll",
|
|
@" EpicGames.Serialization.Tests -> /mnt/horde/DMH/Sync/Engine/Source/Programs/Shared/EpicGames.Serialization.Tests/bin/Analyze/net6.0/EpicGames.Serialization.Tests.dll",
|
|
};
|
|
|
|
List<LogEvent> logEvents = Parse(String.Join("\n", lines));
|
|
Assert.AreEqual(2, logEvents.Count);
|
|
|
|
CheckEventGroup(logEvents.Slice(0, 1), 1, 1, LogLevel.Warning, KnownLogEvents.Compiler);
|
|
CheckEventGroup(logEvents.Slice(1, 1), 2, 1, LogLevel.Warning, KnownLogEvents.Compiler);
|
|
}
|
|
|
|
[TestMethod]
|
|
public void HttpEventMatcher()
|
|
{
|
|
string[] lines =
|
|
{
|
|
@"WARNING: Failed to resolve binaries for artifact fe1b277b-7751-4a52-8059-ec3f943811de:xsx with error: fe1b277b-7751-4a52-8059-ec3f943811de:xsx Failed.Unexpected error retrieving response.BaseUrl = https://content-service-latest-gamedev.cdae.dev.use1a.on.epicgames.com/api. Status = Timeout. McpConfig = ValkyrieDevLatest."
|
|
};
|
|
|
|
List<LogEvent> logEvents = Parse(String.Join("\n", lines));
|
|
CheckEventGroup(logEvents, 0, 1, LogLevel.Warning, KnownLogEvents.Generic);
|
|
}
|
|
|
|
[TestMethod]
|
|
public void MicrosoftEventMatcher()
|
|
{
|
|
// Generic Microsoft errors which can be parsed by visual studio
|
|
{
|
|
string[] lines =
|
|
{
|
|
@" " + MakeAbsolutePath(@"Foo\Bar.txt") + @"(20): warning TL2012: Some error message",
|
|
@" " + MakeAbsolutePath(@"Foo\Bar.txt") + @"(20, 30) : warning TL2034: Some error message",
|
|
@" CSC : error CS2012: Cannot open 'D:\Build\++UE4\Sync\Engine\Source\Programs\Enterprise\Datasmith\DatasmithRevitExporter\Resources\obj\Release\DatasmithRevitResources.dll' for writing -- 'The process cannot access the file 'D:\Build\++UE4\Sync\Engine\Source\Programs\Enterprise\Datasmith\DatasmithRevitExporter\Resources\obj\Release\DatasmithRevitResources.dll' because it is being used by another process.' [D:\Build\++UE4\Sync\Engine\Source\Programs\Enterprise\Datasmith\DatasmithRevitExporter\Resources\DatasmithRevitResources.csproj]"
|
|
};
|
|
|
|
List<LogEvent> logEvents = Parse(String.Join("\n", lines));
|
|
Assert.AreEqual(3, logEvents.Count);
|
|
|
|
// 0
|
|
CheckEventGroup(logEvents.Slice(0, 1), 0, 1, LogLevel.Warning, KnownLogEvents.Microsoft);
|
|
Assert.AreEqual("TL2012", logEvents[0].GetProperty("code").ToString());
|
|
Assert.AreEqual("20", logEvents[0].GetProperty("line").ToString());
|
|
|
|
LogValue fileProperty0 = (LogValue)logEvents[0].GetProperty("file");
|
|
Assert.AreEqual(@"SourceFile", fileProperty0.Type.ToString());
|
|
Assert.AreEqual(@"Foo/Bar.txt", fileProperty0.Properties![LogEventPropertyName.RelativePath]?.ToString());
|
|
|
|
// 1
|
|
CheckEventGroup(logEvents.Slice(1, 1), 1, 1, LogLevel.Warning, KnownLogEvents.Microsoft);
|
|
Assert.AreEqual("TL2034", logEvents[1].GetProperty("code").ToString());
|
|
Assert.AreEqual("20", logEvents[1].GetProperty("line").ToString());
|
|
Assert.AreEqual("30", logEvents[1].GetProperty("column").ToString());
|
|
|
|
LogValue fileProperty1 = logEvents[1].GetProperty<LogValue>("file");
|
|
Assert.AreEqual(@"SourceFile", fileProperty1.Type.ToString());
|
|
Assert.AreEqual(@"Foo/Bar.txt", fileProperty1.Properties![LogEventPropertyName.RelativePath]?.ToString());
|
|
|
|
// 2
|
|
CheckEventGroup(logEvents.Slice(2, 1), 2, 1, LogLevel.Error, KnownLogEvents.Microsoft);
|
|
Assert.AreEqual("CS2012", logEvents[2].GetProperty("code").ToString());
|
|
Assert.AreEqual("CSC", logEvents[2].GetProperty("tool").ToString());
|
|
}
|
|
}
|
|
|
|
[TestMethod]
|
|
public void CompileWarningErrorMacroMatcher()
|
|
{
|
|
// Visual C++ error & warning emitted via COMPILE_WARNING & COMPILE_ERROR
|
|
{
|
|
string[] lines =
|
|
{
|
|
MakeAbsolutePath(@"Engine\Plugins\Experimental\VirtualCamera\Source\VirtualCamera\Private\VCamBlueprintFunctionLibrary.cpp") + @"(249): warning: Some developer's custom warning message.",
|
|
MakeAbsolutePath(@"Engine\Plugins\Experimental\VirtualCamera\Source\VirtualCamera\Private\VCamBlueprintFunctionLibrary.cpp") + @"(250): error: Some developer's custom error message.",
|
|
};
|
|
|
|
List<LogEvent> logEvents = Parse(String.Join("\n", lines));
|
|
Assert.AreEqual(2, logEvents.Count);
|
|
|
|
Assert.AreEqual(LogLevel.Warning, logEvents[0].Level);
|
|
Assert.AreEqual(KnownLogEvents.Compiler, logEvents[0].Id);
|
|
Assert.AreEqual(LogLevel.Error, logEvents[1].Level);
|
|
Assert.AreEqual(KnownLogEvents.Compiler, logEvents[1].Id);
|
|
}
|
|
}
|
|
|
|
[TestMethod]
|
|
public void WarningsAsErrorsEventMatcher()
|
|
{
|
|
// Visual C++ error
|
|
{
|
|
string[] lines =
|
|
{
|
|
MakeAbsolutePath(@"Engine\Plugins\Experimental\VirtualCamera\Source\VirtualCamera\Private\VCamBlueprintFunctionLibrary.cpp") + @"(249): error C2220: the following warning is treated as an error",
|
|
MakeAbsolutePath(@"Engine\Plugins\Experimental\VirtualCamera\Source\VirtualCamera\Private\VCamBlueprintFunctionLibrary.cpp") + @"(249): warning C4996: 'UEditorLevelLibrary::PilotLevelActor': The Editor Scripting Utilities Plugin is deprecated - Use the function in Level Editor Subsystem Please update your code to the new API before upgrading to the next release, otherwise your project will no longer compile.",
|
|
@"..\Plugins\Editor\EditorScriptingUtilities\Source\EditorScriptingUtilities\Public\EditorLevelLibrary.h(122): note: see declaration of 'UEditorLevelLibrary::PilotLevelActor'",
|
|
MakeAbsolutePath(@"Engine\Plugins\Experimental\VirtualCamera\Source\VirtualCamera\Private\VCamBlueprintFunctionLibrary.cpp") + @"(314): warning C4996: 'UEditorLevelLibrary::EditorSetGameView': The Editor Scripting Utilities Plugin is deprecated - Use the function in Level Editor Subsystem Please update your code to the new API before upgrading to the next release, otherwise your project will no longer compile.",
|
|
@"..\Plugins\Editor\EditorScriptingUtilities\Source\EditorScriptingUtilities\Public\EditorLevelLibrary.h(190): note: see declaration of 'UEditorLevelLibrary::EditorSetGameView'"
|
|
};
|
|
|
|
List<LogEvent> logEvents = Parse(String.Join("\n", lines));
|
|
Assert.AreEqual(5, logEvents.Count);
|
|
CheckEventGroup(logEvents.Slice(0, 1), 0, 1, LogLevel.Error, KnownLogEvents.Compiler);
|
|
CheckEventGroup(logEvents.Slice(1, 2), 1, 2, LogLevel.Error, KnownLogEvents.Compiler);
|
|
CheckEventGroup(logEvents.Slice(3, 2), 3, 2, LogLevel.Error, KnownLogEvents.Compiler);
|
|
|
|
LogEvent logEvent = logEvents[1];
|
|
Assert.AreEqual("C4996", logEvent.GetProperty("code").ToString());
|
|
Assert.AreEqual(LogLevel.Error, logEvent.Level);
|
|
|
|
//LogValue FileProperty = (LogValue)Event.Properties["file"];
|
|
|
|
// FIXME: Fails on Linux. Properties dict is empty
|
|
//Assert.AreEqual(@"//UE4/Main/Engine/Plugins/Experimental/VirtualCamera/Source/VirtualCamera/Private/VCamBlueprintFunctionLibrary.cpp@12345", FileProperty.Properties["depotPath"].ToString());
|
|
|
|
LogValue noteProperty1 = logEvents[2].GetProperty<LogValue>("file");
|
|
Assert.AreEqual(@"SourceFile", noteProperty1.Type.ToString());
|
|
Assert.AreEqual(@"//UE4/Main/Engine/Plugins/Editor/EditorScriptingUtilities/Source/EditorScriptingUtilities/Public/EditorLevelLibrary.h@12345", noteProperty1.Properties![LogEventPropertyName.DepotPath]?.ToString());
|
|
}
|
|
}
|
|
|
|
[TestMethod]
|
|
public void AssetLogEventMatcher()
|
|
{
|
|
string[] lines =
|
|
{
|
|
@"LogBlueprint: Warning: [AssetLog] " + MakeAbsolutePath(@"QAGame\Plugins\NiagaraFluids\Content\Blueprints\Phsyarum_BP.uasset") + @": [Compiler] Fill Texture 2D : Usage of 'Fill Texture 2D' has been deprecated. This function has been replaced by object user variables on the emitter to specify render targets to fill with data.",
|
|
};
|
|
|
|
List<LogEvent> events = Parse(String.Join("\n", lines));
|
|
Assert.AreEqual(1, events.Count);
|
|
Assert.AreEqual(events[0].Id, KnownLogEvents.Engine_AssetLog);
|
|
|
|
LogValue assetProperty = events[0].GetProperty<LogValue>("asset");
|
|
Assert.AreEqual(new Utf8String("Asset"), assetProperty.Type);
|
|
Assert.AreEqual(@"//UE4/Main/QAGame/Plugins/NiagaraFluids/Content/Blueprints/Phsyarum_BP.uasset@12345", assetProperty.Properties![LogEventPropertyName.DepotPath]?.ToString());
|
|
Assert.AreEqual(@"QAGame/Plugins/NiagaraFluids/Content/Blueprints/Phsyarum_BP.uasset", assetProperty.Properties![LogEventPropertyName.RelativePath]?.ToString());
|
|
}
|
|
|
|
[TestMethod]
|
|
public void SourceFileLineEventMatcher()
|
|
{
|
|
List<LogEvent> logEvents = Parse("ERROR: C:\\Horde\\InstalledEngineBuild.xml(50): Some error");
|
|
CheckEventGroup(logEvents, 0, 1, LogLevel.Error, KnownLogEvents.AutomationTool_SourceFileLine);
|
|
|
|
Assert.AreEqual("ERROR", logEvents[0].GetProperty("severity").ToString());
|
|
Assert.AreEqual("C:\\Horde\\InstalledEngineBuild.xml", logEvents[0].GetProperty("file").ToString());
|
|
Assert.AreEqual("50", logEvents[0].GetProperty("line").ToString());
|
|
}
|
|
|
|
[TestMethod]
|
|
public void SourceFileEventMatcher()
|
|
{
|
|
List<LogEvent> logEvents = Parse(" WARNING: Engine\\Plugins\\Test\\Foo.cpp: Missing copyright boilerplate");
|
|
CheckEventGroup(logEvents, 0, 1, LogLevel.Warning, KnownLogEvents.AutomationTool_MissingCopyright);
|
|
|
|
Assert.AreEqual("WARNING", logEvents[0].GetProperty("severity").ToString());
|
|
Assert.AreEqual("Engine\\Plugins\\Test\\Foo.cpp", logEvents[0].GetProperty("file").ToString());
|
|
}
|
|
|
|
[TestMethod]
|
|
public void MSBuildEventMatcher()
|
|
{
|
|
List<LogEvent> logEvents = Parse(@" C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\MSBuild\Current\Bin\Microsoft.Common.CurrentVersion.targets(4207,5): warning MSB3026: Could not copy ""obj\Development\DotNETUtilities.dll"" to ""..\..\..\..\Binaries\DotNET\DotNETUtilities.dll"". Beginning retry 2 in 1000ms. The process cannot access the file '..\..\..\..\Binaries\DotNET\DotNETUtilities.dll' because it is being used by another process. The file is locked by: ""UnrealAutomationTool(13236)"" [" + MakeAbsolutePath(@"Engine\Source\Programs\DotNETCommon\DotNETUtilities\DotNETUtilities.csproj") + @"]");
|
|
CheckEventGroup(logEvents, 0, 1, LogLevel.Information, KnownLogEvents.Systemic_MSBuild);
|
|
|
|
Assert.AreEqual("warning", logEvents[0].GetProperty("severity").ToString());
|
|
}
|
|
|
|
[TestMethod]
|
|
public void MonoEventMatcher()
|
|
{
|
|
string[] lines =
|
|
{
|
|
@"Running: sh -c 'xbuild ""/Users/build/Build/++UE4/Sync/Engine/Source/Programs/AutomationTool/Gauntlet/Gauntlet.Automation.csproj"" /verbosity:quiet /nologo /target:Build /p:Platform=AnyCPU /p:Configuration=Development /p:EngineDir=/Users/build/Build/++UE4/Sync/Engine /p:TreatWarningsAsErrors=false /p:NoWarn=""612,618,672,1591"" /p:BuildProjectReferences=true /p:DefineConstants=MONO /p:DefineConstants=__MonoCS__ /verbosity:quiet /nologo |grep -i error; if [ $? -ne 1 ]; then exit 1; else exit 0; fi'",
|
|
@" /Users/build/Build/++UE4/Sync/Engine/Source/Programs/AutomationTool/Gauntlet/Gauntlet.Automation.csproj: error : /Users/build/Build/++UE4/Sync/Engine/Source/Programs/AutomationTool/Gauntlet/Gauntlet.Automation.csproj: /Users/build/Build/++UE4/Sync/Engine/Source/Programs/AutomationTool/Gauntlet/Gauntlet.Automation.csproj could not import ""../../../../Platforms/*/Source/Programs/AutomationTool/Gauntlet/*.Gauntlet.targets""",
|
|
};
|
|
|
|
List<LogEvent> logEvents = Parse(String.Join("\n", lines));
|
|
CheckEventGroup(logEvents, 1, 1, LogLevel.Error, KnownLogEvents.Generic);
|
|
}
|
|
|
|
[TestMethod]
|
|
public void AndroidGradleErrorMatcher()
|
|
{
|
|
string[] lines =
|
|
{
|
|
@" AAPT2 aapt2-4.0.0-6051327-windows Daemon #0: shutdown",
|
|
@" AAPT2 aapt2-4.0.0-6051327-windows Daemon #1: shutdown",
|
|
@" AAPT2 aapt2-4.0.0-6051327-windows Daemon #2: shutdown",
|
|
@" AAPT2 aapt2-4.0.0-6051327-windows Daemon #3: shutdown",
|
|
@" AAPT2 aapt2-4.0.0-6051327-windows Daemon #4: shutdown",
|
|
@" AAPT2 aapt2-4.0.0-6051327-windows Daemon #5: shutdown",
|
|
@" AAPT2 aapt2-4.0.0-6051327-windows Daemon #6: shutdown",
|
|
@" AAPT2 aapt2-4.0.0-6051327-windows Daemon #7: shutdown",
|
|
@"",
|
|
@" FAILURE: Build failed with an exception.",
|
|
@"",
|
|
@" * What went wrong:",
|
|
@" Execution failed for task ':app:buildUeDevelopmentDebugPreBundle'.",
|
|
@" > Required array size too large",
|
|
@"",
|
|
@" * Try:",
|
|
@" Run with --debug option to get more log output. Run with --scan to get full insights.",
|
|
@"",
|
|
@" * Exception is:",
|
|
@" org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':app:buildUeDevelopmentDebugPreBundle'.",
|
|
@" at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.lambda$executeIfValid$1(ExecuteActionsTaskExecuter.java:205)",
|
|
@" at org.gradle.internal.Try$Failure.ifSuccessfulOrElse(Try.java:263)",
|
|
@" at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeIfValid(ExecuteActionsTaskExecuter.java:203)",
|
|
@" at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:184)",
|
|
@" at org.gradle.api.internal.tasks.execution.CleanupStaleOutputsExecuter.execute(CleanupStaleOutputsExecuter.java:109)",
|
|
@" at org.gradle.api.internal.tasks.execution.FinalizePropertiesTaskExecuter.execute(FinalizePropertiesTaskExecuter.java:46)",
|
|
@" at org.gradle.api.internal.tasks.execution.ResolveTaskExecutionModeExecuter.execute(ResolveTaskExecutionModeExecuter.java:62)",
|
|
@" at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:57)",
|
|
@" at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:56)",
|
|
@" at org.gradle.api.internal.tasks.execution.CatchExceptionTaskExecuter.execute(CatchExceptionTaskExecuter.java:36)",
|
|
@" at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.executeTask(EventFiringTaskExecuter.java:77)",
|
|
@" at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.call(EventFiringTaskExecuter.java:55)",
|
|
@" at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.call(EventFiringTaskExecuter.java:52)",
|
|
@" at org.gradle.internal.operations.DefaultBuildOperationExecutor$CallableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:416)",
|
|
@" at org.gradle.internal.operations.DefaultBuildOperationExecutor$CallableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:406)",
|
|
@" at org.gradle.internal.operations.DefaultBuildOperationExecutor$1.execute(DefaultBuildOperationExecutor.java:165)",
|
|
@" at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:250)",
|
|
@" at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:158)",
|
|
@" at org.gradle.internal.operations.DefaultBuildOperationExecutor.call(DefaultBuildOperationExecutor.java:102)",
|
|
@" at org.gradle.internal.operations.DelegatingBuildOperationExecutor.call(DelegatingBuildOperationExecutor.java:36)",
|
|
@" at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter.execute(EventFiringTaskExecuter.java:52)",
|
|
@" at org.gradle.execution.plan.LocalTaskNodeExecutor.execute(LocalTaskNodeExecutor.java:41)",
|
|
@"",
|
|
@" Something else"
|
|
};
|
|
|
|
List<LogEvent> logEvents = Parse(lines);
|
|
Assert.AreEqual(33, logEvents.Count);
|
|
for (int idx = 0; idx < 33; idx++)
|
|
{
|
|
Assert.AreEqual(LogLevel.Error, logEvents[idx].Level);
|
|
}
|
|
Assert.AreEqual(9, logEvents[0].GetProperty(LogLine));
|
|
Assert.AreEqual(lines.Length, logEvents[0].GetProperty<int>(LogLine) + logEvents[0].LineCount + 2);
|
|
}
|
|
|
|
[TestMethod]
|
|
public void SuspendLogParsing()
|
|
{
|
|
string[] lines =
|
|
{
|
|
@" <-- Suspend Log Parsing -->",
|
|
@" Error: File Copy failed with Could not find a part of the path 'P:\Builds\Automation\ShooterGame\Logs\++ShooterGame+Release-14.60\CL-14584315\ShooterGame.QuickSmokeAthena_(Win64_Development_Client)\Client\Saved\Settings\ShooterGame\Saved\Config\CrashReportClient\UE4CC-Win64-C4477473430A2DD50ABDD297FF7811CD\CrashReportClient.ini'..",
|
|
@" <-- Resume Log Parsing -->"
|
|
};
|
|
|
|
List<LogEvent> logEvents = Parse(lines);
|
|
Assert.AreEqual(0, logEvents.Count);
|
|
}
|
|
|
|
[TestMethod]
|
|
public void DockerWarningMatcher()
|
|
{
|
|
string[] lines =
|
|
{
|
|
@"#14 8.477 cc -O2 -Wall -DLUA_ANSI -DENABLE_CJSON_GLOBAL -DREDIS_STATIC='' -c -o lauxlib.o lauxlib.c",
|
|
@"#14 8.499 lauxlib.c: In function 'luaL_loadfile':",
|
|
@"#14 8.499 lauxlib.c:577:4: warning: this 'while' clause does not guard... [-Wmisleading-indentation]",
|
|
@"#14 8.499 while ((c = getc(lf.f)) != EOF && c != LUA_SIGNATURE[0]) ;",
|
|
@"#14 8.499 ^~~~~",
|
|
@"#14 8.499 lauxlib.c:578:5: note: ...this statement, but the latter is misleadingly indented as if it were guarded by the 'while'",
|
|
@"#14 8.499 lf.extraline = 0;",
|
|
@"#14 8.499 ^~",
|
|
@"#14 8.643 cc -O2 -Wall -DLUA_ANSI -DENABLE_CJSON_GLOBAL -DREDIS_STATIC='' -c -o lbaselib.o lbaselib.c",
|
|
};
|
|
|
|
List<LogEvent> logEvents = Parse(lines);
|
|
CheckEventGroup(logEvents, 2, 1, LogLevel.Warning, KnownLogEvents.Compiler);
|
|
}
|
|
|
|
[TestMethod]
|
|
public void DockerErrorMatcher()
|
|
{
|
|
string[] lines =
|
|
{
|
|
@" #14 9.301 cc -O2 -Wall -DLUA_ANSI -DENABLE_CJSON_GLOBAL -DREDIS_STATIC='' -c -o lua.o lua.c",
|
|
@" #14 9.419 cc -o lua lua.o liblua.a -lm",
|
|
@" #14 9.447 /usr/bin/ld: liblua.a(loslib.o): in function `os_tmpname':",
|
|
@" #14 9.447 loslib.c:(.text+0x280): warning: the use of `tmpnam' is dangerous, better use `mkstemp'",
|
|
@" #14 9.448 cc -O2 -Wall -DLUA_ANSI -DENABLE_CJSON_GLOBAL -DREDIS_STATIC='' -c -o luac.o luac.c"
|
|
};
|
|
List<LogEvent> logEvents = Parse(lines);
|
|
CheckEventGroup(logEvents, 2, 2, LogLevel.Warning, KnownLogEvents.Linker);
|
|
}
|
|
|
|
[TestMethod]
|
|
public void DockerDiskSpaceMatcher()
|
|
{
|
|
string[] lines =
|
|
{
|
|
@" Horde.Server -> /app/out/",
|
|
@"Error processing tar file(exit status 1): write /app/Source/Programs/Horde/Horde.Server/obj/Release/net6.0/Horde.Server.dll: no space left on device",
|
|
@"Took 32.59s to run docker, ExitCode=1",
|
|
};
|
|
|
|
List<LogEvent> logEvents = Parse(lines);
|
|
CheckEventGroup(logEvents, 1, 1, LogLevel.Error, KnownLogEvents.Systemic_OutOfDiskSpace);
|
|
}
|
|
|
|
[TestMethod]
|
|
public void SystemicErrorMatcher()
|
|
{
|
|
string[] lines =
|
|
{
|
|
@" LogDerivedDataCache: Warning: Access to //epicgames.net/root/DDC-Global-UE4 appears to be slow. 'Touch' will be disabled and queries/writes will be limited."
|
|
};
|
|
|
|
List<LogEvent> logEvents = Parse(lines);
|
|
CheckEventGroup(logEvents, 0, 1, LogLevel.Information, KnownLogEvents.Systemic_SlowDDC);
|
|
}
|
|
|
|
[TestMethod]
|
|
public void SystemicErrorMatcher2()
|
|
{
|
|
string[] lines =
|
|
{
|
|
@"LogDerivedDataCache: Warning: //amznfsxahfo0vod.epicgames.net/share/DDC: Loading //amznfsxahfo0vod.epicgames.net/share/DDC/Buckets/Test/d2/31/fca1bb2ff10d802e76beb932c2d43a2d539e.udd from 'CacheRecord' is very slow (0.00 MiB/s); consider disabling this cache store."
|
|
};
|
|
|
|
List<LogEvent> logEvents = Parse(lines);
|
|
CheckEventGroup(logEvents, 0, 1, LogLevel.Information, KnownLogEvents.Systemic_SlowDDC);
|
|
}
|
|
|
|
[TestMethod]
|
|
public void LogChannelMatcher()
|
|
{
|
|
string[] lines =
|
|
{
|
|
@"Execution of commandlet took: 749.68 seconds",
|
|
@"LogShooterGAme: Error: Serialized Class /Script/Engine.AnimSequence for a property of Class /Script/Engine.BlendSpace. Reference will be nulled.",
|
|
@" Property = ObjectProperty /Game/Animation/Game/Enemies/HuskHusky/HuskyHusk_AnimBlueprint.HuskyHusk_AnimBlueprint_C:AnimBlueprintGeneratedConstantData:ObjectProperty_358",
|
|
@" Item = AnimSequence /Game/Animation/Game/Enemies/HuskyHusk_Riot/Locomotion/Idle/Idle_Shield.Idle_Shield",
|
|
@"LogDataAssetDirectoryExporter: Display: 'Platform' property is of type: string",
|
|
@"Took 0.17187880000000003s to run p4.exe, ExitCode=0"
|
|
};
|
|
|
|
{
|
|
List<LogEvent> logEvents = Parse(lines);
|
|
Assert.AreEqual(4, logEvents.Count);
|
|
CheckEventGroup(logEvents.Slice(0, 3), 1, 3, LogLevel.Error, KnownLogEvents.Engine_LogChannel);
|
|
CheckEventGroup(logEvents.Slice(3, 1), 4, 1, LogLevel.Information, KnownLogEvents.Engine_LogChannel);
|
|
}
|
|
|
|
{
|
|
List<LogEvent> logEvents = Parse(String.Join("\n", lines).Replace("Error:", "Warning:", StringComparison.Ordinal));
|
|
Assert.AreEqual(4, logEvents.Count);
|
|
CheckEventGroup(logEvents.Slice(0, 3), 1, 3, LogLevel.Warning, KnownLogEvents.Engine_LogChannel);
|
|
CheckEventGroup(logEvents.Slice(3, 1), 4, 1, LogLevel.Information, KnownLogEvents.Engine_LogChannel);
|
|
}
|
|
}
|
|
|
|
[TestMethod]
|
|
public void ShaderEventMatcher()
|
|
{
|
|
string[] lines =
|
|
{
|
|
@"LogCook: Display: Cook Diagnostics: OpenFileHandles=10353, VirtualMemory=20078MiB",
|
|
@"LogShaderCompilers: Warning: Failed to compile Material /Game/Crowd/Character/Shared/Materials/MetaHuman/M_Crowd_Head_v2.M_Crowd_Head_v2 for platform SF_XSX_SM6, Default Material will be used in game.",
|
|
@" error:validation errors",
|
|
@" error:Root Signature in DXIL container is not compatible with shader.",
|
|
@" error:Shader SRV descriptor range (RegisterSpace=0, NumDescriptors=1, BaseShaderRegister=64) is not fully bound in root signature.",
|
|
@"Validation failed.",
|
|
@" Shader compile failed",
|
|
@"LogCook: Display: Excluding /Interchange/gltf/MaterialInstances/MI_ClearCoat_Mask_DS"
|
|
};
|
|
|
|
{
|
|
List<LogEvent> logEvents = Parse(lines);
|
|
Assert.AreEqual(8, logEvents.Count);
|
|
CheckEventGroup(logEvents.Slice(1, 6), 1, 6, LogLevel.Warning, KnownLogEvents.Engine_ShaderCompiler);
|
|
}
|
|
}
|
|
|
|
[TestMethod]
|
|
public void ThreadSanitizerErrorMatcher_NoMatch()
|
|
{
|
|
string[] lines =
|
|
{
|
|
@"==================",
|
|
@"WARNING: ThreadSanitizer: data race (pid=21089)",
|
|
@" Write of size 1 at 0x00004060ea38 by thread T25:",
|
|
@" #0 FPaths::IsStaged() /mnt/horde/++UE5/Sync/Engine/Source/./Runtime/Core/Private/Misc/Paths.cpp:172:33 (CitySampleEditor+0x2c0f2f44) (BuildId: 6622c84dbb6a946e)",
|
|
@"",
|
|
@" Previous write of size 1 at 0x00004060ea38 by thread T20:",
|
|
@" #0 FPaths::IsStaged() /mnt/horde/++UE5/Sync/Engine/Source/./Runtime/Core/Private/Misc/Paths.cpp:172:33 (CitySampleEditor+0x2c0f2f44) (BuildId: 6622c84dbb6a946e)",
|
|
};
|
|
|
|
// We won't find a terminating string for the TSAN report so we only log a source file warning
|
|
List<LogEvent> logEvents = Parse(lines);
|
|
Assert.AreEqual(1, logEvents.Count);
|
|
Assert.AreEqual(LogLevel.Warning, logEvents[0].Level);
|
|
Assert.AreEqual(KnownLogEvents.AutomationTool_SourceFileLine, logEvents[0].Id);
|
|
}
|
|
|
|
[TestMethod]
|
|
public void ThreadSanitizerErrorMatcher()
|
|
{
|
|
string[] lines =
|
|
{
|
|
@"==================",
|
|
@"WARNING: ThreadSanitizer: data race (pid=21089)",
|
|
@" Write of size 1 at 0x00004060ea38 by thread T25:",
|
|
@" #0 FPaths::IsStaged() /mnt/horde/++UE5/Sync/Engine/Source/./Runtime/Core/Private/Misc/Paths.cpp:172:33 (CitySampleEditor+0x2c0f2f44) (BuildId: 6622c84dbb6a946e)",
|
|
@"",
|
|
@" Previous write of size 1 at 0x00004060ea38 by thread T20:",
|
|
@" #0 FPaths::IsStaged() /mnt/horde/++UE5/Sync/Engine/Source/./Runtime/Core/Private/Misc/Paths.cpp:172:33 (CitySampleEditor+0x2c0f2f44) (BuildId: 6622c84dbb6a946e)",
|
|
@"",
|
|
@" Location is global '??' at 0x000000000000 (CitySampleEditor+0x4060ea38)",
|
|
@"",
|
|
@" Thread T25 'Backgro-ker #19' (tid=21138, running) created by thread T7 at:",
|
|
@" #0 pthread_create /src/build/llvm-src/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp:1048 (CitySampleEditor+0x10351c92) (BuildId: 6622c84dbb6a946e)",
|
|
@" #1 FRunnableThreadPThread::CreateThreadWithName(unsigned long*, pthread_attr_t*, void* (*)(void*), void*, char const*) /mnt/horde/++UE5/Sync/Engine/Source/Runtime/Core/Private/HAL/PThreadRunnableThread.h:90:10 (CitySampleEditor+0x2bd32c50) (BuildId: 6622c84dbb6a946e)",
|
|
@"",
|
|
@" Thread T20 'Backgro-ker #14' (tid=21133, running) created by thread T5 at:",
|
|
@" #0 pthread_create /src/build/llvm-src/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp:1048 (CitySampleEditor+0x10351c92) (BuildId: 6622c84dbb6a946e)",
|
|
@" #1 FRunnableThreadPThread::CreateThreadWithName(unsigned long*, pthread_attr_t*, void* (*)(void*), void*, char const*) /mnt/horde/++UE5/Sync/Engine/Source/Runtime/Core/Private/HAL/PThreadRunnableThread.h:90:10 (CitySampleEditor+0x2bd32c50) (BuildId: 6622c84dbb6a946e)",
|
|
@"",
|
|
@"SUMMARY: ThreadSanitizer: data race /mnt/horde/++UE5/Sync/Engine/Source/./Runtime/Core/Private/Misc/Paths.cpp:172:33 in FPaths::IsStaged()",
|
|
@"=================="
|
|
};
|
|
|
|
List<LogEvent> logEvents = Parse(lines);
|
|
Assert.AreEqual(20, logEvents[0].LineCount);
|
|
CheckEventGroup(logEvents, 0, 20, LogLevel.Warning, KnownLogEvents.Sanitizer_Thread);
|
|
|
|
Assert.AreEqual("/mnt/horde/++UE5/Sync/Engine/Source/Runtime/Core/Private/HAL/PThreadRunnableThread.h", logEvents[12].GetProperty("SourceFile").ToString());
|
|
Assert.AreEqual("90", logEvents[12].GetProperty("Line").ToString());
|
|
Assert.AreEqual("10", logEvents[12].GetProperty("Column").ToString());
|
|
Assert.AreEqual("FRunnableThreadPThread::CreateThreadWithName(unsigned long*, pthread_attr_t*, void* (*)(void*), void*, char const*)", logEvents[12].GetProperty("Symbol").ToString());
|
|
|
|
// Summary
|
|
Assert.AreEqual("/mnt/horde/++UE5/Sync/Engine/Source/./Runtime/Core/Private/Misc/Paths.cpp", logEvents[18].GetProperty("SummarySourceFile").ToString());
|
|
Assert.AreEqual("172", logEvents[18].GetProperty("Line").ToString());
|
|
Assert.AreEqual("33", logEvents[18].GetProperty("Column").ToString());
|
|
Assert.AreEqual("FPaths::IsStaged()", logEvents[18].GetProperty("Symbol").ToString());
|
|
Assert.AreEqual("data race", logEvents[18].GetProperty("SummaryReason").ToString());
|
|
}
|
|
|
|
[TestMethod]
|
|
public void ThreadSanitizerErrorMatcher_SummaryWithSourceFileFromLibrary()
|
|
{
|
|
string[] lines =
|
|
{
|
|
@"==================",
|
|
@"WARNING: ThreadSanitizer: data race (pid=66092)",
|
|
@"SUMMARY: ThreadSanitizer: data race (/mnt/horde/++Fortnite/Sync/Samples/Showcases/CitySample/Binaries/Linux/../../../../../Engine/Binaries/ThirdParty/FreeImage/Linux/libfreeimage-3.18.0.so+0x3e5ad5) (BuildId: c695478f660e26fac50341783e39865323ee3eea) in std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>::find(char, unsigned long) const",
|
|
@"=================="
|
|
};
|
|
|
|
List<LogEvent> logEvents = Parse(lines);
|
|
Assert.AreEqual(4, logEvents[0].LineCount);
|
|
CheckEventGroup(logEvents, 0, 4, LogLevel.Warning, KnownLogEvents.Sanitizer_Thread);
|
|
|
|
// Summary
|
|
const int SummaryIndex = 2;
|
|
Assert.IsTrue(logEvents[SummaryIndex].Message.StartsWith("SUMMARY: ThreadSanitizer"));
|
|
Assert.AreEqual("/mnt/horde/++Fortnite/Sync/Samples/Showcases/CitySample/Binaries/Linux/../../../../../Engine/Binaries/ThirdParty/FreeImage/Linux/libfreeimage-3.18.0.so+0x3e5ad5", logEvents[SummaryIndex].GetProperty("SummarySourceFile").ToString());
|
|
Assert.AreEqual("std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>::find(char, unsigned long) const", logEvents[SummaryIndex].GetProperty("Symbol").ToString());
|
|
Assert.AreEqual("data race", logEvents[SummaryIndex].GetProperty("SummaryReason").ToString());
|
|
}
|
|
|
|
[TestMethod]
|
|
public void AddressSanitizerErrorMatcher()
|
|
{
|
|
string[] lines =
|
|
{
|
|
@"=================================================================",
|
|
@"==30562==ERROR: AddressSanitizer: heap-use-after-free on address 0x617002aa8418 at pc 0x7f98a08bd090 bp 0x7ffc30203af0 sp 0x7ffc30203ae8",
|
|
@"READ of size 8 at 0x617002aa8418 thread T0",
|
|
@" #0 0x7f98a08bd08f in UObjectBase::GetFName() const /mnt/horde/FNR+Main+Inc/Sync/Engine/Source/Runtime/CoreUObject/Public/UObject/UObjectBase.h:166:10",
|
|
@"",
|
|
@"0x617002aa8418 is located 24 bytes inside of 712-byte region [0x617002aa8400,0x617002aa86c8)",
|
|
@"freed by thread T0 here:",
|
|
@" #0 0x7f9a283e6b08 in __interceptor_free.part.5 /src/build/llvm-src/compiler-rt/lib/asan/asan_malloc_linux.cpp:52",
|
|
@"",
|
|
@"previously allocated by thread T0 here:",
|
|
@" #0 0x7f9a283e730d in posix_memalign /src/build/llvm-src/compiler-rt/lib/asan/asan_malloc_linux.cpp:145",
|
|
@"",
|
|
@"SUMMARY: AddressSanitizer: heap-use-after-free /mnt/horde/FNR+Main+Inc/Sync/Engine/Source/Runtime/CoreUObject/Public/UObject/UObjectBase.h:166:10 in UObjectBase::GetFName() const",
|
|
@"Shadow bytes around the buggy address:",
|
|
@" 0x617002aa8180: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
|
|
@" 0x617002aa8200: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
|
|
@" 0x617002aa8280: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
|
|
@" 0x617002aa8300: 00 00 00 00 00 00 00 00 fa fa fa fa fa fa fa fa",
|
|
@" 0x617002aa8380: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa",
|
|
@"=>0x617002aa8400: fd fd fd[fd]fd fd fd fd fd fd fd fd fd fd fd fd",
|
|
@" 0x617002aa8480: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd",
|
|
@" 0x617002aa8500: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd",
|
|
@" 0x617002aa8580: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd",
|
|
@" 0x617002aa8600: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd",
|
|
@" 0x617002aa8680: fd fd fd fd fd fd fd fd fd fa fa fa fa fa fa fa",
|
|
@"Shadow byte legend (one shadow byte represents 8 application bytes):",
|
|
@" Addressable: 00",
|
|
@" Partially addressable: 01 02 03 04 05 06 07 ",
|
|
@" Heap left redzone: fa",
|
|
@" Freed heap region: fd",
|
|
@" Stack left redzone: f1",
|
|
@" Stack mid redzone: f2",
|
|
@" Stack right redzone: f3",
|
|
@" Stack after return: f5",
|
|
@" Stack use after scope: f8",
|
|
@" Global redzone: f9",
|
|
@" Global init order: f6",
|
|
@" Poisoned by user: f7",
|
|
@" Container overflow: fc",
|
|
@" Array cookie: ac",
|
|
@" Intra object redzone: bb",
|
|
@" ASan internal: fe",
|
|
@" Left alloca redzone: ca",
|
|
@" Right alloca redzone: cb",
|
|
@"==30562==ABORTING",
|
|
};
|
|
|
|
List<LogEvent> logEvents = Parse(lines);
|
|
Assert.AreEqual(45, logEvents[0].LineCount);
|
|
CheckEventGroup(logEvents, 0, 45, LogLevel.Error, KnownLogEvents.Sanitizer_Address);
|
|
|
|
LogValue? column;
|
|
Assert.AreEqual("/src/build/llvm-src/compiler-rt/lib/asan/asan_malloc_linux.cpp", logEvents[7].GetProperty("SourceFile").ToString());
|
|
Assert.AreEqual("52", logEvents[7].GetProperty("Line").ToString());
|
|
Assert.IsFalse(logEvents[7].TryGetProperty("Column", out column));
|
|
Assert.AreEqual("__interceptor_free.part.5", logEvents[7].GetProperty("Symbol").ToString());
|
|
|
|
// Summary
|
|
Assert.AreEqual("/mnt/horde/FNR+Main+Inc/Sync/Engine/Source/Runtime/CoreUObject/Public/UObject/UObjectBase.h", logEvents[12].GetProperty("SummarySourceFile").ToString());
|
|
Assert.AreEqual("166", logEvents[12].GetProperty("Line").ToString());
|
|
Assert.IsTrue(logEvents[12].TryGetProperty("Column", out column));
|
|
Assert.AreEqual("10", column.ToString());
|
|
Assert.AreEqual("UObjectBase::GetFName() const", logEvents[12].GetProperty("Symbol").ToString());
|
|
Assert.AreEqual("heap-use-after-free", logEvents[12].GetProperty("SummaryReason").ToString());
|
|
}
|
|
|
|
[TestMethod]
|
|
public void AddressSanitizerErrorMatcher2()
|
|
{
|
|
string[] lines =
|
|
{
|
|
@"=================================================================",
|
|
@"==85[0x18ca8]==ERROR: AddressSanitizer: use-after-poison on address 0x00d0572d5090 at pc 0x0000268d15d3 bp 0x0007effc1b90 sp 0x0007effc1b88",
|
|
@"READ of size 2 at 0x00d0572d5090 thread T0",
|
|
@" #0 0x0000268d15d3 (eboot.bin+0x4c55d3)",
|
|
@" #1 0x0000268cb2ee (eboot.bin+0x4bf2ee)",
|
|
@" #2 0x0000268d06b9 (eboot.bin+0x4c46b9)",
|
|
@" #3 0x0000268d072a (eboot.bin+0x4c472a)",
|
|
@" #4 0x000026904cf7 (eboot.bin+0x4f8cf7)",
|
|
@" #5 0x0000268d2fd1 (eboot.bin+0x4c6fd1)",
|
|
@" #6 0x0000268d486c (eboot.bin+0x4c886c)",
|
|
@" #7 0x0000268caf3e (eboot.bin+0x4bef3e)",
|
|
@" #8 0x00002642a55f (eboot.bin+0x1e55f)",
|
|
@" #9 0x00002642a2cd (eboot.bin+0x1e2cd)",
|
|
@" #10 0x0000268ca9d9 (eboot.bin+0x4be9d9)",
|
|
@" #11 0x0000267c663d (eboot.bin+0x3ba63d)",
|
|
@" #12 0x0000267433e9 (eboot.bin+0x3373e9)",
|
|
@" #13 0x00004005f913 (eboot.bin+0x19c53913)",
|
|
@" #14 0x00004005f7a1 (eboot.bin+0x19c537a1)",
|
|
@" #15 0x000036b55372 (eboot.bin+0x10749372)",
|
|
@" #16 0x000036bbc84e (eboot.bin+0x107b084e)",
|
|
@" #17 0x00002a5e38ec (eboot.bin+0x41d78ec)",
|
|
@" #18 0x000036b2bd70 (eboot.bin+0x1071fd70)",
|
|
@" #19 0x000036b2b1d9 (eboot.bin+0x1071f1d9)",
|
|
@" #20 0x000036bcd8e6 (eboot.bin+0x107c18e6)",
|
|
@" #21 0x000036bcd55b (eboot.bin+0x107c155b)",
|
|
@" #22 0x000036b315a7 (eboot.bin+0x107255a7)",
|
|
@" #23 0x000036b32697 (eboot.bin+0x10726697)",
|
|
@" #24 0x000036b9dfde (eboot.bin+0x10791fde)",
|
|
@" #25 0x000036bd751c (eboot.bin+0x107cb51c)",
|
|
@" #26 0x000036bd72cb (eboot.bin+0x107cb2cb)",
|
|
@" #27 0x0000265cc963 (eboot.bin+0x1c0963)",
|
|
@" #28 0x000031b40ed6 (eboot.bin+0xb734ed6)",
|
|
@" #29 0x000031ac8d2e (eboot.bin+0xb6bcd2e)",
|
|
@" #30 0x000031b7c352 (eboot.bin+0xb770352)",
|
|
@" #31 0x000031b7bfa0 (eboot.bin+0xb76ffa0)",
|
|
@" #32 0x000029fdd12f (eboot.bin+0x3bd112f)",
|
|
@" #33 0x000031a5885e (eboot.bin+0xb64c85e)",
|
|
@" #34 0x00002a014420 (eboot.bin+0x3c08420)",
|
|
@" #35 0x00002a0140d5 (eboot.bin+0x3c080d5)",
|
|
@" #36 0x000029fdd12f (eboot.bin+0x3bd112f)",
|
|
@" #37 0x000029fed56c (eboot.bin+0x3be156c)",
|
|
@" #38 0x00002a014420 (eboot.bin+0x3c08420)",
|
|
@" #39 0x00002a0140d5 (eboot.bin+0x3c080d5)",
|
|
@" #40 0x000029fdd12f (eboot.bin+0x3bd112f)",
|
|
@" #41 0x000029fc93f0 (eboot.bin+0x3bbd3f0)",
|
|
@" #42 0x000029fc902c (eboot.bin+0x3bbd02c)",
|
|
@" #43 0x000029fe3f84 (eboot.bin+0x3bd7f84)",
|
|
@" #44 0x00002648e9c9 (eboot.bin+0x829c9)",
|
|
@" #45 0x000026541ad9 (eboot.bin+0x135ad9)",
|
|
@" #46 0x00002652a6bb (eboot.bin+0x11e6bb)",
|
|
@" #47 0x00002653ea89 (eboot.bin+0x132a89)",
|
|
@" #48 0x00002652a6bb (eboot.bin+0x11e6bb)",
|
|
@" #49 0x000030e67257 (eboot.bin+0xaa5b257)",
|
|
@" #50 0x000030e606e6 (eboot.bin+0xaa546e6)",
|
|
@" #51 0x000030e69fea (eboot.bin+0xaa5dfea)",
|
|
@" #52 0x00002640c0bf (eboot.bin+0xbf)",
|
|
@"",
|
|
@"Address 0x00d0572d5090 is a wild pointer inside of access range of size 0x000000000002.",
|
|
@"SUMMARY: AddressSanitizer: use-after-poison (eboot.bin+0x4c55d3) at (eboot.bin+0x4c55d3)",
|
|
@"Shadow bytes around the buggy address:",
|
|
@" 0x00d0572d4e00: f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7",
|
|
@" 0x00d0572d4e80: f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7",
|
|
@" 0x00d0572d4f00: f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7",
|
|
@" 0x00d0572d4f80: f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7",
|
|
@" 0x00d0572d5000: f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7",
|
|
@"=>0x00d0572d5080: f7 f7[f7]f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7",
|
|
@" 0x00d0572d5100: f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7",
|
|
@" 0x00d0572d5180: f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7",
|
|
@" 0x00d0572d5200: f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7",
|
|
@" 0x00d0572d5280: f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7",
|
|
@" 0x00d0572d5300: f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7",
|
|
@"Shadow byte legend (one shadow byte represents 8 application bytes):",
|
|
@" Addressable: 00",
|
|
@" Partially addressable: 01 02 03 04 05 06 07 ",
|
|
@" Heap left redzone: fa",
|
|
@" Freed heap region: fd",
|
|
@" Stack left redzone: f1",
|
|
@" Stack mid redzone: f2",
|
|
@" Stack right redzone: f3",
|
|
@" Stack after return: f5",
|
|
@" Stack use after scope: f8",
|
|
@" Global redzone: f9",
|
|
@" Global init order: f6",
|
|
@" Poisoned by user: f7",
|
|
@" Container overflow: fc",
|
|
@" Array cookie: ac",
|
|
@" Intra object redzone: bb",
|
|
@" ASan internal: fe",
|
|
@" Left alloca redzone: ca",
|
|
@" Right alloca redzone: cb",
|
|
@"Fatal error: [File:Z:/UEVFS/Root/Engine/Platforms/Source/Runtime/Core/Private/PlatformMemory.cpp] [Line: 520] ",
|
|
@"ASan Error: =================================================================",
|
|
@"==85[0x18ca8]==ERROR: AddressSanitizer: use-after-poison on address 0x00d0572d5090 at pc 0x0000268d15d3 bp 0x0007effc1b90 sp 0x0007effc1b88",
|
|
@"READ of size 2 at 0x00d0572d5090 thread T0",
|
|
@" #0 0x0000268d15d3 (eboot.bin+0x4c55d3)",
|
|
@" #1 0x0000268cb2ee (eboot.bin+0x4bf2ee)",
|
|
@" #2 0x0000268d06b9 (eboot.bin+0x4c46b9)",
|
|
@" #3 0x0000268d072a (eboot.bin+0x4c472a)",
|
|
@" #4 0x000026904cf7 (eboot.bin+0x4f8cf7)",
|
|
@" #5 0x0000268d2fd1 (eboot.bin+0x4c6fd1)",
|
|
@" #6 0x0000268d486c (eboot.bin+0x4c886c)",
|
|
@" #7 0x0000268caf3e (eboot.bin+0x4bef3e)",
|
|
@" #8 0x00002642a55f (eboot.bin+0x1e55f)",
|
|
@" #9 0x00002642a2cd (eboot.bin+0x1e2cd)",
|
|
@" #10 0x0000268ca9d9 (eboot.bin+0x4be9d9)",
|
|
@" #11 0x0000267c663d (eboot.bin+0x3ba63d)",
|
|
@" #12 0x0000267433e9 (eboot.bin+0x3373e9)",
|
|
@" #13 0x00004005f913 (eboot.bin+0x19c53913)",
|
|
@" #14 0x00004005f7a1 (eboot.bin+0x19c537a1)",
|
|
@" #15 0x000036b55372 (eboot.bin+0x10749372)",
|
|
@" #16 0x000036bbc84e (eboot.bin+0x107b084e)",
|
|
@" #17 0x00002a5e38ec (eboot.bin+0x41d78ec)",
|
|
@" #18 0x000036b2bd70 (eboot.bin+0x1071fd70)",
|
|
@" #19 0x000036b2b1d9 (eboot.bin+0x1071f1d9)",
|
|
@" #20 0x000036bcd8e6 (eboot.bin+0x107c18e6)",
|
|
@" #21 0x000036bcd55b (eboot.bin+0x107c155b)",
|
|
@" #22 0x000036b315a7 (eboot.bin+0x107255a7)",
|
|
@" #23 0x000036b32697 (eboot.bin+0x10726697)",
|
|
@" #24 0x000036b9dfde (eboot.bin+0x10791fde)",
|
|
@" #25 0x000036bd751c (eboot.bin+0x107cb51c)",
|
|
@" #26 0x000036bd72cb (eboot.bin+0x107cb2cb)",
|
|
@" #27 0x0000265cc963 (eboot.bin+0x1c0963)",
|
|
@" #28 0x000031b40ed6 (eboot.bin+0xb734ed6)",
|
|
@" #29 0x000031ac8d2e (eboot.bin+0xb6bcd2e)",
|
|
@" #30 0x000031b7c352 (eboot.bin+0xb770352)",
|
|
@" #31 0x000031b7bfa0 (eboot.bin+0xb76ffa0)",
|
|
@" #32 0x000029fdd12f (eboot.bin+0x3bd112f)",
|
|
@" #33 0x000031a5885e (eboot.bin+0xb64c85e)",
|
|
@" #34 0x00002a014420 (eboot.bin+0x3c08420)",
|
|
@" #35 0x00002a0140d5 (eboot.bin+0x3c080d5)",
|
|
@" #36 0x000029fdd12f (eboot.bin+0x3bd112f)",
|
|
@" #37 0x000029fed56c (eboot.bin+0x3be156c)",
|
|
@" #38 0x00002a014420 (eboot.bin+0x3c08420)",
|
|
@" #39 0x00002a0140d5 (eboot.bin+0x3c080d5)",
|
|
@" #40 0x000029fdd12f (eboot.bin+0x3bd112f)",
|
|
@" #41 0x000029fc93f0 (eboot.bin+0x3bbd3f0)",
|
|
@" #42 0x000029fc902c (eboot.bin+0x3bbd02c)",
|
|
@" #43 0x000029fe3f84 (eboot.bin+0x3bd7f84)",
|
|
@" #44 0x00002648e9c9 (eboot.bin+0x829c9)",
|
|
@" #45 0x000026541ad9 (eboot.bin+0x135ad9)",
|
|
@" #46 0x00002652a6bb (eboot.bin+0x11e6bb)",
|
|
@" #47 0x00002653ea89 (eboot.bin+0x132a89)",
|
|
@" #48 0x00002652a6bb (eboot.bin+0x11e6bb)",
|
|
@" #49 0x000030e67257 (eboot.bin+0xaa5b257)",
|
|
@" #50 0x000030e606e6 (eboot.bin+0xaa546e6)",
|
|
@" #51 0x000030e69fea (eboot.bin+0xaa5dfea)",
|
|
@" #52 0x00002640c0bf (eboot.bin+0xbf)",
|
|
@"",
|
|
@"Address 0x00d0572d5090 is a wild pointer inside of access range of size 0x000000000002.",
|
|
@"SUMMARY: AddressSanitizer: use-after-poison (eboot.bin+0x4c55d3) at (eboot.bin+0x4c55d3)",
|
|
@"Shadow bytes around the buggy address:",
|
|
@" 0x00d0572d4e00: f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7",
|
|
@" 0x00d0572d4e80: f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7",
|
|
@" 0x00d0572d4f00: f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7",
|
|
@" 0x00d0572d4f80: f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7",
|
|
@" 0x00d0572d5000: f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7",
|
|
@"=>0x00d0572d5080: f7 f7[f7]f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7",
|
|
@" 0x00d0572d5100: f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7",
|
|
@" 0x00d0572d5180: f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7",
|
|
@" 0x00d0572d5200: f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7",
|
|
@" 0x00d0572d5280: f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7",
|
|
@" 0x00d0572d5300: f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7",
|
|
@"Shadow byte legend (one shadow byte represents 8 application bytes):",
|
|
@" Addressable: 00",
|
|
@" Partially addressable: 01 02 03 04 05 06 07 ",
|
|
@" Heap left redzone: fa",
|
|
@" Freed heap region: fd",
|
|
@" Stack left redzone: f1",
|
|
@" Stack mid redzone: f2",
|
|
@" Stack right redzone: f3",
|
|
@" Stack after return: f5",
|
|
@" Stack use after scope: f8",
|
|
@" Global redzone: f9",
|
|
@" Global init order: f6",
|
|
@" Poisoned by user: f7",
|
|
@" Container overflow: fc",
|
|
@" Array cookie: ac",
|
|
@" Intra object redzone: bb",
|
|
@" ASan internal: fe",
|
|
@" Left alloca redzone: ca",
|
|
@" Right alloca redzone: cb",
|
|
@"",
|
|
@"End of Address Sanitizer report",
|
|
};
|
|
|
|
List<LogEvent> logEvents = Parse(lines);
|
|
Assert.AreEqual(183, logEvents[0].LineCount);
|
|
CheckEventGroup(logEvents, 0, 183, LogLevel.Error, KnownLogEvents.Sanitizer_Address);
|
|
|
|
// Summary
|
|
Assert.AreEqual("eboot.bin+0x4c55d3", logEvents[58].GetProperty("SummarySourceFile").ToString());
|
|
Assert.AreEqual("eboot.bin+0x4c55d3", logEvents[58].GetProperty("Symbol").ToString());
|
|
Assert.AreEqual("use-after-poison", logEvents[58].GetProperty("SummaryReason").ToString());
|
|
}
|
|
|
|
[TestMethod]
|
|
public void LocalizationChannelMatcher()
|
|
{
|
|
string[] lines =
|
|
{
|
|
@"[2022.05.31-04.25.40:235][ 0]LogGatherTextFromSourceCommandlet: Warning: Plugins/Enterprise/VariantManager/Source/VariantManager/Private/SVariantManager.cpp(3717): LOCTEXT macro has an empty identifier and cannot be gathered.",
|
|
@"[2022.06.01-04.29.09:630][ 0]LogLocTextHelper: Warning: Plugins/Experimental/UVEditor/Source/UVEditor/Private/UVEditorCommands.cpp(39): Text conflict from UI_COMMAND macro for namespace ""UICommands.FUVEditorCommands"" and key ""SplitAction_ToolTip"". The conflicting sources are ""Given an edge selection, split those edges. Given a vertex selection, split any selected bowtie vertices. Given a triangle selection, split along selection boundaries."" and ""Given an edge selection, split those edges. Given a vertex selection, split any selected bowtie vertices."".",
|
|
@"[2022.06.01-04.29.09:630][ 0]LogLocTextHelper: Warning: Content/Localization/Engine/Engine.manifest: See conflicting location.",
|
|
};
|
|
|
|
{
|
|
List<LogEvent> logEvents = Parse(lines);
|
|
Assert.AreEqual(3, logEvents.Count);
|
|
CheckEventGroup(logEvents.Slice(0, 1), 0, 1, LogLevel.Warning, KnownLogEvents.Engine_Localization);
|
|
CheckEventGroup(logEvents.Slice(1, 2), 1, 2, LogLevel.Warning, KnownLogEvents.Engine_Localization);
|
|
|
|
LogEvent logEvent = logEvents[0];
|
|
Assert.AreEqual("LogGatherTextFromSourceCommandlet", logEvent.GetProperty("channel").ToString());
|
|
Assert.AreEqual("Warning", logEvent.GetProperty("severity").ToString());
|
|
Assert.AreEqual("Engine/Plugins/Enterprise/VariantManager/Source/VariantManager/Private/SVariantManager.cpp", logEvent.GetProperty<LogValue>("file")!.Properties![LogEventPropertyName.RelativePath]?.ToString());
|
|
Assert.AreEqual("3717", logEvent.GetProperty("line").ToString());
|
|
Assert.AreEqual(0, logEvent.LineIndex);
|
|
Assert.AreEqual(1, logEvent.LineCount);
|
|
|
|
logEvent = logEvents[1];
|
|
Assert.AreEqual("LogLocTextHelper", logEvent.GetProperty("channel").ToString());
|
|
Assert.AreEqual("Warning", logEvent.GetProperty("severity").ToString());
|
|
Assert.AreEqual("Engine/Plugins/Experimental/UVEditor/Source/UVEditor/Private/UVEditorCommands.cpp", logEvent.GetProperty<LogValue>("file")!.Properties![LogEventPropertyName.RelativePath]?.ToString());
|
|
Assert.AreEqual("39", logEvent.GetProperty("line").ToString());
|
|
Assert.AreEqual(0, logEvent.LineIndex);
|
|
Assert.AreEqual(2, logEvent.LineCount);
|
|
|
|
logEvent = logEvents[2];
|
|
Assert.AreEqual("LogLocTextHelper", logEvent.GetProperty("channel").ToString());
|
|
Assert.AreEqual("Warning", logEvent.GetProperty("severity").ToString());
|
|
Assert.AreEqual("Engine/Content/Localization/Engine/Engine.manifest", logEvent.GetProperty<LogValue>("file")!.Properties![LogEventPropertyName.RelativePath]?.ToString());
|
|
Assert.AreEqual(1, logEvent.LineIndex);
|
|
Assert.AreEqual(2, logEvent.LineCount);
|
|
}
|
|
}
|
|
|
|
[TestMethod]
|
|
public void HangingIndentMatcher()
|
|
{
|
|
string[] lines =
|
|
{
|
|
@"first line",
|
|
@"first line in multi-line message",
|
|
@" this is a hanging indent",
|
|
@" this is also hanging",
|
|
@"this is a separate item",
|
|
};
|
|
|
|
LogBuffer buffer = new LogBuffer(10);
|
|
buffer.AddLines(lines);
|
|
|
|
Assert.IsTrue(buffer.IsAligned(0, buffer.CurrentLine));
|
|
Assert.IsTrue(buffer.IsAligned(1, buffer.CurrentLine));
|
|
Assert.IsTrue(buffer.IsAligned(2, buffer.CurrentLine));
|
|
Assert.IsTrue(buffer.IsAligned(3, buffer.CurrentLine));
|
|
Assert.IsTrue(buffer.IsAligned(4, buffer.CurrentLine));
|
|
Assert.IsFalse(buffer.IsAligned(5, buffer.CurrentLine));
|
|
|
|
string? firstIndentedLine = buffer[2];
|
|
Assert.IsTrue(buffer.IsAligned(2, firstIndentedLine));
|
|
Assert.IsTrue(buffer.IsAligned(3, firstIndentedLine));
|
|
Assert.IsFalse(buffer.IsAligned(4, firstIndentedLine));
|
|
|
|
Assert.IsFalse(buffer.IsHanging(1, buffer.CurrentLine));
|
|
Assert.IsTrue(buffer.IsHanging(2, buffer.CurrentLine));
|
|
Assert.IsTrue(buffer.IsHanging(3, buffer.CurrentLine));
|
|
Assert.IsFalse(buffer.IsHanging(4, buffer.CurrentLine));
|
|
|
|
Assert.IsFalse(buffer.IsHanging(2, firstIndentedLine));
|
|
Assert.IsTrue(buffer.IsHanging(3, firstIndentedLine));
|
|
Assert.IsFalse(buffer.IsHanging(4, firstIndentedLine));
|
|
}
|
|
|
|
[TestMethod]
|
|
public void MsTestEventMatcher()
|
|
{
|
|
string[] lines =
|
|
{
|
|
@"Microsoft (R) Test Execution Command Line Tool Version 17.2.0 (x64)",
|
|
@"Copyright (c) Microsoft Corporation. All rights reserved.",
|
|
@"Starting test execution, please wait...",
|
|
@"A total of 1 test files matched the specified pattern.",
|
|
@"",
|
|
@" Failed ExplicitGroupingTest [219 ms]",
|
|
@" Error Message:",
|
|
@" Assert.AreEqual failed. Expected:<2>. Actual:<1>.",
|
|
@" Stack Trace:",
|
|
@" at Horde.Build.Tests.IssueServiceTests.ExplicitGroupingTest() in /app/Source/Programs/Horde/Horde.Build.Tests/IssueServiceTests.cs:line 1382",
|
|
@" at Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.ThreadOperations.ExecuteWithAbortSafety(Action action)",
|
|
@"",
|
|
@" Standard Output Messages:",
|
|
@" info: Horde.Build.Issues.IssueService[0]",
|
|
@" Updating issues for 62a21de84f3b4344e94f3f10:0000:0004",
|
|
@" info: Horde.Build.Logs.LogEventCollection[0]",
|
|
@" Querying for log events for log 62a21de84f3b4344e94f3f15 creation time 06/09/2022 16:20:56",
|
|
@" info: Horde.Build.Auditing.AuditLog[0]",
|
|
@" Created issue 1",
|
|
@" info: Horde.Build.Auditing.AuditLog[0]",
|
|
@" Changed severity to Error",
|
|
};
|
|
|
|
List<LogEvent> logEvents = Parse(lines);
|
|
Assert.AreEqual(6, logEvents.Count);
|
|
CheckEventGroup(logEvents, 5, 6, LogLevel.Error, KnownLogEvents.MSTest);
|
|
}
|
|
|
|
[TestMethod]
|
|
public void MsTestEventMatcher2()
|
|
{
|
|
string[] lines =
|
|
{
|
|
@" Passed ConditionSimple [154 ms]",
|
|
@" Passed GetPoolQueueSizes [1 s]",
|
|
@" Failed DowntimeActive [6 s]",
|
|
@" Error Message:",
|
|
@" Assert.AreEqual failed. Expected:<1>. Actual:<0>.",
|
|
@" Stack Trace:",
|
|
@" at Horde.Server.Tests.Fleet.JobQueueStrategyTest.DowntimeActive() in /app/Source/Programs/Horde/Horde.Server.Tests/Fleet/JobQueueStrategyTest.cs:line 40",
|
|
};
|
|
|
|
List<LogEvent> logEvents = Parse(lines);
|
|
Assert.AreEqual(5, logEvents.Count);
|
|
CheckEventGroup(logEvents, 2, 5, LogLevel.Error, KnownLogEvents.MSTest);
|
|
}
|
|
|
|
[TestMethod]
|
|
public void MsTestEventMatcher3()
|
|
{
|
|
string[] lines =
|
|
{
|
|
@" info: Horde.Server.Auditing.AuditLog[0]",
|
|
@" Session 662a561ef41fb04ceda48319 started",
|
|
@"",
|
|
@" Failed AutoConformAgentsAsync (True,200,) [208 ms]",
|
|
@" Error Message:",
|
|
@" Assert.AreEqual failed. Expected:<True>. Actual:<False>.",
|
|
@" Stack Trace:",
|
|
@" at Horde.Server.Tests.Agents.Pools.PoolUpdateServiceTest.AutoConformAgentsAsync(Boolean conformRequested, Nullable`1[] autoConformThresholdsM) in /app/Source/Programs/Horde/Horde.Server.Tests/Agents/Pools/PoolUpdateServiceTest.cs:line 120",
|
|
};
|
|
|
|
List<LogEvent> logEvents = Parse(lines);
|
|
Assert.AreEqual(5, logEvents.Count);
|
|
CheckEventGroup(logEvents, 3, 5, LogLevel.Error, KnownLogEvents.MSTest);
|
|
}
|
|
|
|
|
|
[TestMethod]
|
|
public void ZenCliEventMatcher()
|
|
{
|
|
string[] lines =
|
|
{
|
|
@"[2025-03-14 09:17:37.209] [warning] HttpClient request failed (session: 07e58d18351114f0452d7a10): Url: http://use-corp.jupiter.devtools.epicgames.com:8080/api/v2/builds/fortnite.oplog/FortniteGame.staged-build.fortnite-main.Windows-Server/07e58d18f6299c5324851bb7/blobs/255310fd5b5048ba3e4a7a7e64d97b8756037419, Status: 504, Bytes: 1807567166/19 (Up/Down), Elapsed: 109.533087s, Reponse: '{""error_code"": 504}', Reason: 'Gateway Time-out'",
|
|
@"[2025-03-14 09:17:37.209] [info] Retry: HTTP error 504 Gateway Timeout ({""error_code"": 504}) Attempt 2/3",
|
|
@"Uploading blobs 47% (5m20s): Compressed 15/15 (45.4G/45.4G) chunks. Uploaded 250/254 (25.3G/52.9G) blobs (12.0G 0bits/s)",
|
|
@"Uploading blobs 47% (5m25s): Compressed 15/15 (45.4G/45.4G) chunks. Uploaded 250/254 (25.3G/52.9G) blobs (12.0G 0bits/s)",
|
|
@"[2025-03-14 09:18:42.123] [warning] HttpClient request failed (session: 07e58d18351114f0452d7a10): Url: http://use-corp.jupiter.devtools.epicgames.com:8080/api/v2/builds/fortnite.oplog/FortniteGame.staged-build.fortnite-main.Windows-Server/07e58d18f6299c5324851bb7/blobs/808890007cea205213cd3b41768601baa8e7b7ec, Status: 504, Bytes: 1522307998/19 (Up/Down), Elapsed: 88.734826s, Reponse: '{""error_code"": 504}', Reason: 'Gateway Time-out'",
|
|
@"Uploading blobs 47% (5m30s): Compressed 15/15 (45.4G/45.4G) chunks. Uploaded 250/254 (25.3G/52.9G) blobs (12.0G 0bits/s)",
|
|
@"Uploading blobs 47% (5m35s): Compressed 15/15 (45.4G/45.4G) chunks. Uploaded 250/254 (25.3G/52.9G) blobs (12.0G 0bits/s)",
|
|
@"Uploading blobs 47% (5m40s): Compressed 15/15 (45.4G/45.4G) chunks. Uploaded 250/254 (25.3G/52.9G) blobs (12.0G 0bits/s)",
|
|
@"[2025-03-14 09:18:58.492] [warning] HttpClient request failed (session: 07e58d18351114f0452d7a10): Url: http://use-corp.jupiter.devtools.epicgames.com:8080/api/v2/builds/fortnite.oplog/FortniteGame.staged-build.fortnite-main.Windows-Server/07e58d18f6299c5324851bb7/blobs/c4fd36d11b830735f28cbe23096eb7c79f030cad, Status: 504, Bytes: 1523839912/19 (Up/Down), Elapsed: 102.125895s, Reponse: '{""error_code"": 504}', Reason: 'Gateway Time-out'",
|
|
@"[2025-03-14 09:19:00.902] [warning] HttpClient request failed (session: 07e58d18351114f0452d7a10): Url: http://use-corp.jupiter.devtools.epicgames.com:8080/api/v2/builds/fortnite.oplog/FortniteGame.staged-build.fortnite-main.Windows-Server/07e58d18f6299c5324851bb7/blobs/6a12b6c4dfaf7eeafe0259fde410c4b25bb3be64, Status: 504, Bytes: 1522162526/19 (Up/Down), Elapsed: 104.317546s, Reponse: '{""error_code"": 504}', Reason: 'Gateway Time-out'",
|
|
@"Uploading blobs 47% (5m45s): Compressed 15/15 (45.4G/45.4G) chunks. Uploaded 250/254 (25.3G/52.9G) blobs (12.0G 0bits/s)",
|
|
@"Uploading blobs 47% (6m00s): Compressed 15/15 (45.4G/45.4G) chunks. Uploaded 250/254 (25.3G/52.9G) blobs (12.0G 0bits/s)",
|
|
@"[2025-03-14 09:19:20.663] [warning] HttpClient request failed (session: 07e58d18351114f0452d7a10): Url: http://use-corp.jupiter.devtools.epicgames.com:8080/api/v2/builds/fortnite.oplog/FortniteGame.staged-build.fortnite-main.Windows-Server/07e58d18f6299c5324851bb7/blobs/255310fd5b5048ba3e4a7a7e64d97b8756037419, Status: 504, Bytes: 1807567166/19 (Up/Down), Elapsed: 103.452505s, Reponse: '{""error_code"": 504}', Reason: 'Gateway Time-out'",
|
|
@"Generated 0 (0B 0B/s) and uploaded 239 (7.46G) blocks. Compressed 15 (10.5G 0B/s) and uploaded 11 (4.59G) chunks. Transferred 12.1G (0bits/s) in 6m05s",
|
|
@"[2025-03-14 09:19:23.225] [error] [builds_cmd.cpp:6643] Multiple errors:",
|
|
@" Failed putting build part: JupiterSession::PutBuildBlob: HTTP error 504 Gateway Timeout ({""error_code"": 504}) (504)",
|
|
@" Failed putting build part: JupiterSession::PutBuildBlob: HTTP error 504 Gateway Timeout ({""error_code"": 504}) (504)",
|
|
@" Failed putting build part: JupiterSession::PutBuildBlob: HTTP error 504 Gateway Timeout ({""error_code"": 504}) (504)",
|
|
@" Failed putting build part: JupiterSession::PutBuildBlob: HTTP error 504 Gateway Timeout ({""error_code"": 504}) (504)"
|
|
};
|
|
|
|
List<LogEvent> logEvents = Parse(lines);
|
|
Assert.AreEqual(7, logEvents.Count);
|
|
|
|
// the last event is an error on line 15
|
|
CheckEventGroup(logEvents.Slice(logEvents.Count - 1, 1), 14, 1, LogLevel.Error, KnownLogEvents.ZenCli_Event);
|
|
}
|
|
|
|
static List<LogEvent> Parse(IEnumerable<string> lines)
|
|
{
|
|
return Parse(String.Join("\n", lines));
|
|
}
|
|
|
|
static List<LogEvent> Parse(string text)
|
|
{
|
|
return Parse(text, s_rootDir);
|
|
}
|
|
|
|
static List<LogEvent> Parse(string text, DirectoryReference workspaceDir)
|
|
{
|
|
byte[] textBytes = Encoding.UTF8.GetBytes(text);
|
|
|
|
Random generator = new Random(0);
|
|
|
|
LoggerCapture logger = new LoggerCapture();
|
|
|
|
PerforceMetadataLogger perforceLogger = new PerforceMetadataLogger(logger);
|
|
perforceLogger.AddClientView(workspaceDir, "//UE4/Main/...", 12345);
|
|
|
|
using (LogEventParser parser = new LogEventParser(perforceLogger))
|
|
{
|
|
parser.AddMatchersFromAssembly(typeof(AutomationTool.Automation).Assembly);
|
|
parser.AddMatchersFromAssembly(typeof(UnrealBuildTool.TargetRules).Assembly);
|
|
|
|
int pos = 0;
|
|
while (pos < textBytes.Length)
|
|
{
|
|
int len = Math.Min((int)(generator.NextDouble() * 256), textBytes.Length - pos);
|
|
parser.WriteData(textBytes.AsMemory(pos, len));
|
|
pos += len;
|
|
}
|
|
}
|
|
return logger._events;
|
|
}
|
|
|
|
static void CheckEventGroup(IEnumerable<LogEvent> logEvents, int index, int count, LogLevel level, EventId eventId = default)
|
|
{
|
|
IEnumerator<LogEvent> enumerator = logEvents.GetEnumerator();
|
|
for (int idx = 0; idx < count; idx++)
|
|
{
|
|
Assert.IsTrue(enumerator.MoveNext());
|
|
|
|
LogEvent logEvent = enumerator.Current;
|
|
Assert.AreEqual(level, logEvent.Level, "Log level mismatch");
|
|
Assert.AreEqual(eventId, logEvent.Id, "Event ID mismatch");
|
|
Assert.AreEqual(idx, logEvent.LineIndex, "Line index mismatch");
|
|
Assert.AreEqual(count, logEvent.LineCount, "Line count mismatch");
|
|
Assert.AreEqual(index + idx, logEvent.GetProperty(LogLine));
|
|
}
|
|
Assert.IsFalse(enumerator.MoveNext());
|
|
}
|
|
}
|
|
}
|