can generate transcript for two-client test
This commit is contained in:
parent
410d62849a
commit
ecada92dc5
|
@ -1,4 +1,5 @@
|
|||
using Core;
|
||||
using CodexPlugin.OverwatchSupport.LineConverters;
|
||||
using Core;
|
||||
using OverwatchTranscript;
|
||||
using Utils;
|
||||
|
||||
|
@ -18,8 +19,8 @@ namespace CodexPlugin.OverwatchSupport
|
|||
public void ProcessLog(IDownloadedLog log)
|
||||
{
|
||||
var peerId = DeterminPeerId(log);
|
||||
|
||||
|
||||
var runner = new ConversionRunner(writer, peerId);
|
||||
runner.Run(log);
|
||||
}
|
||||
|
||||
private string DeterminPeerId(IDownloadedLog log)
|
||||
|
@ -30,8 +31,8 @@ namespace CodexPlugin.OverwatchSupport
|
|||
|
||||
// Expected string:
|
||||
// Downloading container log for '<Downloader1>'
|
||||
var nameLine = log.FindLinesThatContain("Downloading container log for").Single();
|
||||
var name = Str.Between(nameLine, "'<", ">'");
|
||||
var nameLine = log.FindLinesThatContain("Downloading container log for").First();
|
||||
var name = Str.Between(nameLine, "'", "'");
|
||||
|
||||
var peerId = nameIdMap.GetPeerId(name);
|
||||
var shortPeerId = CodexUtils.ToShortId(peerId);
|
||||
|
@ -46,4 +47,60 @@ namespace CodexPlugin.OverwatchSupport
|
|||
return peerId;
|
||||
}
|
||||
}
|
||||
|
||||
public class ConversionRunner
|
||||
{
|
||||
private readonly ITranscriptWriter writer;
|
||||
private readonly string peerId;
|
||||
private readonly ILineConverter[] converters = new ILineConverter[]
|
||||
{
|
||||
new BlockReceivedLineConverter()
|
||||
};
|
||||
|
||||
public ConversionRunner(ITranscriptWriter writer, string peerId)
|
||||
{
|
||||
this.writer = writer;
|
||||
this.peerId = peerId;
|
||||
}
|
||||
|
||||
public void Run(IDownloadedLog log)
|
||||
{
|
||||
log.IterateLines(line =>
|
||||
{
|
||||
foreach (var converter in converters)
|
||||
{
|
||||
ProcessLine(line, converter);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void AddEvent(DateTime utc, Action<OverwatchCodexEvent> action)
|
||||
{
|
||||
var e = new OverwatchCodexEvent
|
||||
{
|
||||
PeerId = peerId,
|
||||
};
|
||||
action(e);
|
||||
writer.Add(utc, e);
|
||||
}
|
||||
|
||||
private void ProcessLine(string line, ILineConverter converter)
|
||||
{
|
||||
if (!line.Contains(converter.Interest)) return;
|
||||
|
||||
var codexLine = CodexLogLine.Parse(line);
|
||||
if (codexLine == null) throw new Exception("Unable to parse required line");
|
||||
|
||||
converter.Process(codexLine, (action) =>
|
||||
{
|
||||
AddEvent(codexLine.TimestampUtc, action);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public interface ILineConverter
|
||||
{
|
||||
string Interest { get; }
|
||||
void Process(CodexLogLine line, Action<Action<OverwatchCodexEvent>> addEvent);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using CodexPlugin.Hooks;
|
||||
using Core;
|
||||
using OverwatchTranscript;
|
||||
using Utils;
|
||||
|
||||
namespace CodexPlugin.OverwatchSupport
|
||||
{
|
||||
|
@ -23,6 +24,7 @@ namespace CodexPlugin.OverwatchSupport
|
|||
|
||||
public ICodexNodeHooks CreateHooks(string nodeName)
|
||||
{
|
||||
nodeName = Str.Between(nodeName, "'", "'");
|
||||
return new CodexNodeTranscriptWriter(writer, nameIdMap, nodeName);
|
||||
}
|
||||
|
||||
|
@ -39,6 +41,19 @@ namespace CodexPlugin.OverwatchSupport
|
|||
converter.ProcessLog(log);
|
||||
}
|
||||
}
|
||||
|
||||
public void AddResult(bool success, string result)
|
||||
{
|
||||
writer.Add(DateTime.UtcNow, new OverwatchCodexEvent
|
||||
{
|
||||
PeerId = string.Empty,
|
||||
ScenarioFinished = new ScenarioFinishedEvent
|
||||
{
|
||||
Success = success,
|
||||
Result = result
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public class CodexNodeTranscriptWriter : ICodexNodeHooks
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
namespace CodexPlugin.OverwatchSupport.LineConverters
|
||||
{
|
||||
public class BlockReceivedLineConverter : ILineConverter
|
||||
{
|
||||
public string Interest => "Received blocks from peer";
|
||||
|
||||
public void Process(CodexLogLine line, Action<Action<OverwatchCodexEvent>> addEvent)
|
||||
{
|
||||
var peer = line.Attributes["peer"];
|
||||
var blockAddresses = line.Attributes["blocks"];
|
||||
|
||||
SplitBlockAddresses(blockAddresses, address =>
|
||||
{
|
||||
addEvent(e =>
|
||||
{
|
||||
e.BlockReceived = new BlockReceivedEvent
|
||||
{
|
||||
SenderPeerId = peer,
|
||||
BlockAddress = address
|
||||
};
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private void SplitBlockAddresses(string blockAddresses, Action<string> onBlockAddress)
|
||||
{
|
||||
// Single line can contain multiple block addresses.
|
||||
var tokens = blockAddresses.Split(",", StringSplitOptions.RemoveEmptyEntries).ToList();
|
||||
while (tokens.Count > 0)
|
||||
{
|
||||
if (tokens.Count == 1)
|
||||
{
|
||||
onBlockAddress(tokens[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
var blockAddress = $"{tokens[0]}, {tokens[1]}";
|
||||
tokens.RemoveRange(0, 2);
|
||||
|
||||
onBlockAddress(blockAddress);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
namespace OverwatchTranscript
|
||||
namespace CodexPlugin.OverwatchSupport
|
||||
{
|
||||
[Serializable]
|
||||
public class OverwatchCodexHeader
|
||||
|
@ -62,7 +62,7 @@
|
|||
public class BlockReceivedEvent
|
||||
{
|
||||
public string BlockAddress { get; set; } = string.Empty;
|
||||
public string PeerId { get; set; } = string.Empty;
|
||||
public string SenderPeerId { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
|
|
@ -10,6 +10,7 @@ using DistTestCore.Logs;
|
|||
using Logging;
|
||||
using MetricsPlugin;
|
||||
using Newtonsoft.Json;
|
||||
using NUnit.Framework;
|
||||
using NUnit.Framework.Constraints;
|
||||
using OverwatchTranscript;
|
||||
|
||||
|
@ -38,29 +39,13 @@ namespace CodexTests
|
|||
protected override void LifecycleStart(TestLifecycle lifecycle)
|
||||
{
|
||||
base.LifecycleStart(lifecycle);
|
||||
if (!enableOverwatchTranscript) return;
|
||||
|
||||
var writer = new CodexTranscriptWriter(Transcript.NewWriter());
|
||||
Ci.SetCodexHooksProvider(writer);
|
||||
writers.Add(lifecycle, writer);
|
||||
SetupTranscript(lifecycle);
|
||||
}
|
||||
|
||||
protected override void LifecycleStop(TestLifecycle lifecycle)
|
||||
protected override void LifecycleStop(TestLifecycle lifecycle, DistTestResult result)
|
||||
{
|
||||
base.LifecycleStop(lifecycle);
|
||||
if (!enableOverwatchTranscript) return;
|
||||
|
||||
var writer = writers[lifecycle];
|
||||
writers.Remove(lifecycle);
|
||||
|
||||
writer.ProcessLogs(lifecycle.DownloadAllLogs());
|
||||
|
||||
var file = lifecycle.Log.CreateSubfile("owts");
|
||||
Stopwatch.Measure(lifecycle.Log, $"Transcript.Finalize: {file.FullFilename}", () =>
|
||||
{
|
||||
writer.IncludeFile(lifecycle.Log.LogFile.FullFilename);
|
||||
writer.Finalize(file.FullFilename);
|
||||
});
|
||||
base.LifecycleStop(lifecycle, result);
|
||||
TeardownTranscript(lifecycle, result);
|
||||
}
|
||||
|
||||
public ICodexNode StartCodex()
|
||||
|
@ -142,5 +127,43 @@ namespace CodexTests
|
|||
protected virtual void OnCodexSetup(ICodexSetup setup)
|
||||
{
|
||||
}
|
||||
|
||||
private void SetupTranscript(TestLifecycle lifecycle)
|
||||
{
|
||||
if (!enableOverwatchTranscript) return;
|
||||
|
||||
var writer = new CodexTranscriptWriter(Transcript.NewWriter());
|
||||
Ci.SetCodexHooksProvider(writer);
|
||||
writers.Add(lifecycle, writer);
|
||||
}
|
||||
|
||||
private void TeardownTranscript(TestLifecycle lifecycle, DistTestResult result)
|
||||
{
|
||||
if (!enableOverwatchTranscript) return;
|
||||
|
||||
var writer = writers[lifecycle];
|
||||
writers.Remove(lifecycle);
|
||||
|
||||
writer.AddResult(result.Success, result.Result);
|
||||
|
||||
try
|
||||
{
|
||||
Stopwatch.Measure(lifecycle.Log, "Transcript.ProcessLogs", () =>
|
||||
{
|
||||
writer.ProcessLogs(lifecycle.DownloadAllLogs());
|
||||
});
|
||||
|
||||
var file = lifecycle.Log.CreateSubfile("owts");
|
||||
Stopwatch.Measure(lifecycle.Log, $"Transcript.Finalize: {file.FullFilename}", () =>
|
||||
{
|
||||
writer.IncludeFile(lifecycle.Log.LogFile.FullFilename);
|
||||
writer.Finalize(file.FullFilename);
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
lifecycle.Log.Error("Failure during transcript teardown: " + ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -166,7 +166,7 @@ namespace DistTestCore
|
|||
{
|
||||
}
|
||||
|
||||
protected virtual void LifecycleStop(TestLifecycle lifecycle)
|
||||
protected virtual void LifecycleStop(TestLifecycle lifecycle, DistTestResult testResult)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -218,7 +218,7 @@ namespace DistTestCore
|
|||
WriteEndTestLog(lifecycle.Log);
|
||||
|
||||
IncludeLogsOnTestFailure(lifecycle);
|
||||
LifecycleStop(lifecycle);
|
||||
LifecycleStop(lifecycle, testResult);
|
||||
lifecycle.DeleteAllResources();
|
||||
lifecycles.Remove(GetCurrentTestName());
|
||||
});
|
||||
|
@ -309,9 +309,12 @@ namespace DistTestCore
|
|||
return $"[{TestContext.CurrentContext.Test.Name}]";
|
||||
}
|
||||
|
||||
private string GetTestResult()
|
||||
private DistTestResult GetTestResult()
|
||||
{
|
||||
return TestContext.CurrentContext.Result.Outcome.Status.ToString();
|
||||
var success = TestContext.CurrentContext.Result.Outcome.Status == TestStatus.Passed;
|
||||
var status = TestContext.CurrentContext.Result.Outcome.Status.ToString();
|
||||
var result = TestContext.CurrentContext.Result.Message;
|
||||
return new DistTestResult(success, status, result ?? string.Empty);
|
||||
}
|
||||
|
||||
private bool IsDownloadingLogsEnabled()
|
||||
|
@ -320,6 +323,20 @@ namespace DistTestCore
|
|||
}
|
||||
}
|
||||
|
||||
public class DistTestResult
|
||||
{
|
||||
public DistTestResult(bool success, string status, string result)
|
||||
{
|
||||
Success = success;
|
||||
Status = status;
|
||||
Result = result;
|
||||
}
|
||||
|
||||
public bool Success { get; }
|
||||
public string Status { get; }
|
||||
public string Result { get; }
|
||||
}
|
||||
|
||||
public static class GlobalTestFailure
|
||||
{
|
||||
public static bool HasFailed { get; set; } = false;
|
||||
|
|
|
@ -20,9 +20,9 @@ namespace DistTestCore.Logs
|
|||
this.deployId = deployId;
|
||||
}
|
||||
|
||||
public void ConcludeTest(string resultStatus, TimeSpan testDuration, Dictionary<string, string> data)
|
||||
public void ConcludeTest(DistTestResult resultStatus, TimeSpan testDuration, Dictionary<string, string> data)
|
||||
{
|
||||
ConcludeTest(resultStatus, testDuration.TotalSeconds.ToString(CultureInfo.InvariantCulture), data);
|
||||
ConcludeTest(resultStatus.Status, testDuration.TotalSeconds.ToString(CultureInfo.InvariantCulture), data);
|
||||
}
|
||||
|
||||
public void ConcludeTest(string resultStatus, string testDuration, Dictionary<string, string> data)
|
||||
|
|
Loading…
Reference in New Issue