Better logging for json errors and node actions.

This commit is contained in:
benbierens 2023-04-19 10:42:08 +02:00
parent e4e7afd580
commit e9d84a5cf7
No known key found for this signature in database
GPG Key ID: FE44815D96D0A1AA
15 changed files with 105 additions and 43 deletions

View File

@ -9,6 +9,16 @@
public long SizeInBytes { get; }
public override bool Equals(object? obj)
{
return obj is ByteSize size && SizeInBytes == size.SizeInBytes;
}
public override int GetHashCode()
{
return HashCode.Combine(SizeInBytes);
}
public override string ToString()
{
return $"{SizeInBytes} bytes";

View File

@ -1,5 +1,4 @@
using KubernetesWorkflow;
using Newtonsoft.Json;
namespace DistTestCore.Codex
{

View File

@ -40,9 +40,9 @@ namespace DistTestCore
}
fixtureLog.Log("Global setup cleanup successful");
fixtureLog.Log($"Codex image: {CodexContainerRecipe.DockerImage}");
fixtureLog.Log($"Prometheus image: {PrometheusContainerRecipe.DockerImage}");
fixtureLog.Log($"Geth image: {GethContainerRecipe.DockerImage}");
fixtureLog.Log($"Codex image: '{CodexContainerRecipe.DockerImage}'");
fixtureLog.Log($"Prometheus image: '{PrometheusContainerRecipe.DockerImage}'");
fixtureLog.Log($"Geth image: '{GethContainerRecipe.DockerImage}'");
}
[SetUp]

View File

@ -35,20 +35,22 @@ namespace DistTestCore
public T HttpGetJson<T>(string route)
{
return JsonConvert.DeserializeObject<T>(HttpGetString(route))!;
var json = HttpGetString(route);
return TryJsonDeserialize<T>(json);
}
public TResponse HttpPostJson<TRequest, TResponse>(string route, TRequest body)
{
return Retry(() =>
var json = Retry(() =>
{
using var client = GetClient();
var url = GetUrl() + route;
using var content = JsonContent.Create(body);
var result = Time.Wait(client.PostAsync(url, content));
var json = Time.Wait(result.Content.ReadAsStringAsync());
return JsonConvert.DeserializeObject<TResponse>(json)!;
return Time.Wait(result.Content.ReadAsStringAsync());
});
return TryJsonDeserialize<TResponse>(json);
}
public string HttpPostStream(string route, Stream stream)
@ -98,13 +100,27 @@ namespace DistTestCore
retryCounter++;
if (retryCounter > Timing.HttpCallRetryCount())
{
Assert.Fail(exception.Message);
Assert.Fail(exception.ToString());
throw;
}
}
}
}
private static T TryJsonDeserialize<T>(string json)
{
try
{
return JsonConvert.DeserializeObject<T>(json)!;
}
catch (Exception exception)
{
var msg = $"Failed to deserialize JSON: '{json}' with exception: {exception}";
Assert.Fail(msg);
throw new InvalidOperationException(msg, exception);
}
}
private static HttpClient GetClient()
{
var client = new HttpClient();

View File

@ -11,10 +11,12 @@ namespace DistTestCore.Logs
public class CodexNodeLog : ICodexNodeLog
{
private readonly LogFile logFile;
private readonly OnlineCodexNode owner;
public CodexNodeLog(LogFile logFile)
public CodexNodeLog(LogFile logFile, OnlineCodexNode owner)
{
this.logFile = logFile;
this.owner = owner;
}
public void AssertLogContains(string expectedString)
@ -29,7 +31,7 @@ namespace DistTestCore.Logs
line = streamReader.ReadLine();
}
Assert.Fail($"Unable to find string '{expectedString}' in CodexNode log file {logFile.FullFilename}");
Assert.Fail($"{owner.GetName()} Unable to find string '{expectedString}' in CodexNode log file {logFile.FullFilename}");
}
}
}

View File

@ -5,10 +5,12 @@ namespace DistTestCore.Logs
{
public class LogDownloadHandler : LogHandler, ILogHandler
{
private readonly OnlineCodexNode node;
private readonly LogFile log;
public LogDownloadHandler(string description, LogFile log)
public LogDownloadHandler(OnlineCodexNode node, string description, LogFile log)
{
this.node = node;
this.log = log;
log.Write($"{description} -->> {log.FullFilename}");
@ -17,7 +19,7 @@ namespace DistTestCore.Logs
public CodexNodeLog CreateCodexNodeLog()
{
return new CodexNodeLog(log);
return new CodexNodeLog(log, node);
}
protected override void ProcessLine(string line)

View File

@ -44,10 +44,10 @@ namespace DistTestCore.Marketplace
};
Log($"Requesting storage for: {contentId.Id}... (" +
$"pricePerBytePerSecond: {pricePerBytePerSecond}," +
$"requiredCollateral: {requiredCollateral}," +
$"minRequiredNumberOfNodes: {minRequiredNumberOfNodes}," +
$"proofProbability: {proofProbability}," +
$"pricePerBytePerSecond: {pricePerBytePerSecond}, " +
$"requiredCollateral: {requiredCollateral}, " +
$"minRequiredNumberOfNodes: {minRequiredNumberOfNodes}, " +
$"proofProbability: {proofProbability}, " +
$"duration: {Time.FormatDuration(duration)})");
var response = codexAccess.RequestStorage(request, contentId.Id);
@ -68,10 +68,10 @@ namespace DistTestCore.Marketplace
};
Log($"Making storage available... (" +
$"size: {size}," +
$"minPricePerBytePerSecond: {minPricePerBytePerSecond}," +
$"maxCollateral: {maxCollateral}," +
$"maxDuration: {Time.FormatDuration(maxDuration)}");
$"size: {size}, " +
$"minPricePerBytePerSecond: {minPricePerBytePerSecond}, " +
$"maxCollateral: {maxCollateral}, " +
$"maxDuration: {Time.FormatDuration(maxDuration)})");
var response = codexAccess.SalesAvailability(request);
@ -103,14 +103,14 @@ namespace DistTestCore.Marketplace
var amount = interaction.GetBalance(marketplaceNetwork.Marketplace.TokenAddress, account);
var balance = new TestToken(amount);
Log($"Balance of {codexAccess.Container.GetName()}({account}) is {balance}.");
Log($"Balance of {account} is {balance}.");
return balance;
}
private void Log(string msg)
{
log.Log(msg);
log.Log($"{codexAccess.Container.GetName()} {msg}");
}
}

View File

@ -1,4 +1,5 @@
using KubernetesWorkflow;
using Logging;
using NUnit.Framework;
using NUnit.Framework.Constraints;
using Utils;
@ -10,22 +11,15 @@ namespace DistTestCore.Metrics
void AssertThat(string metricName, IResolveConstraint constraint, string message = "");
}
public class MetricsUnavailable : IMetricsAccess
{
public void AssertThat(string metricName, IResolveConstraint constraint, string message = "")
{
Assert.Fail("Incorrect test setup: Metrics were not enabled for this group of Codex nodes. Add 'EnableMetrics()' after 'SetupCodexNodes()' to enable it.");
throw new InvalidOperationException();
}
}
public class MetricsAccess : IMetricsAccess
{
private readonly TestLog log;
private readonly MetricsQuery query;
private readonly RunningContainer node;
public MetricsAccess(MetricsQuery query, RunningContainer node)
public MetricsAccess(TestLog log, MetricsQuery query, RunningContainer node)
{
this.log = log;
this.query = query;
this.node = node;
}
@ -34,6 +28,9 @@ namespace DistTestCore.Metrics
{
var metricSet = GetMetricWithTimeout(metricName);
var metricValue = metricSet.Values[0].Value;
log.Log($"{node.GetName()} metric '{metricName}' = {metricValue}");
Assert.That(metricValue, constraint, message);
}
@ -67,4 +64,13 @@ namespace DistTestCore.Metrics
return result.Sets.LastOrDefault();
}
}
public class MetricsUnavailable : IMetricsAccess
{
public void AssertThat(string metricName, IResolveConstraint constraint, string message = "")
{
Assert.Fail("Incorrect test setup: Metrics were not enabled for this group of Codex nodes. Add 'EnableMetrics()' after 'SetupCodexNodes()' to enable it.");
throw new InvalidOperationException();
}
}
}

View File

@ -17,17 +17,19 @@ namespace DistTestCore.Metrics
public class CodexNodeMetricsAccessFactory : IMetricsAccessFactory
{
private readonly TestLifecycle lifecycle;
private readonly RunningContainers prometheusContainer;
public CodexNodeMetricsAccessFactory(RunningContainers prometheusContainer)
public CodexNodeMetricsAccessFactory(TestLifecycle lifecycle, RunningContainers prometheusContainer)
{
this.lifecycle = lifecycle;
this.prometheusContainer = prometheusContainer;
}
public IMetricsAccess CreateMetricsAccess(RunningContainer codexContainer)
{
var query = new MetricsQuery(prometheusContainer);
return new MetricsAccess(query, codexContainer);
return new MetricsAccess(lifecycle.Log, query, codexContainer);
}
}
}

View File

@ -91,7 +91,7 @@ namespace DistTestCore
public string Describe()
{
return $"({Group.Describe()} contains {GetName()})";
return $"({GetName()} in {Group.Describe()})";
}
private string GetPeerMultiAddress(OnlineCodexNode peer, CodexDebugResponse peerInfo)

View File

@ -26,7 +26,7 @@ namespace DistTestCore
LogEnd("Metrics server started.");
return new CodexNodeMetricsAccessFactory(runningContainers);
return new CodexNodeMetricsAccessFactory(lifecycle, runningContainers);
}
private string GeneratePrometheusConfig(RunningContainer[] nodes)

View File

@ -35,12 +35,12 @@ namespace DistTestCore
{
var subFile = Log.CreateSubfile();
var description = node.Describe();
var handler = new LogDownloadHandler(description, subFile);
var handler = new LogDownloadHandler(node, description, subFile);
Log.Log($"Downloading logs for {description} to file '{subFile.FullFilename}'");
CodexStarter.DownloadLog(node.CodexAccess.Container, handler);
return new CodexNodeLog(subFile);
return new CodexNodeLog(subFile, node);
}
}
}

View File

@ -8,6 +8,21 @@
}
public decimal Wei { get; }
public override bool Equals(object? obj)
{
return obj is Ether ether && Wei == ether.Wei;
}
public override int GetHashCode()
{
return HashCode.Combine(Wei);
}
public override string ToString()
{
return $"{Wei} Wei";
}
}
public class TestToken
@ -19,6 +34,16 @@
public decimal Amount { get; }
public override bool Equals(object? obj)
{
return obj is TestToken token && Amount == token.Amount;
}
public override int GetHashCode()
{
return HashCode.Combine(Amount);
}
public override string ToString()
{
return $"{Amount} TestTokens";

View File

@ -14,7 +14,7 @@ namespace Logging
methodName = GetMethodName();
fullName = Path.Combine(folder, methodName);
Log($"Begin: {methodName}");
Log($"*** Begin: {methodName}");
}
public LogFile CreateSubfile(string ext = "log")
@ -26,7 +26,7 @@ namespace Logging
{
var result = TestContext.CurrentContext.Result;
Log($"Finished: {methodName} = {result.Outcome.Status}");
Log($"*** Finished: {methodName} = {result.Outcome.Status}");
if (!string.IsNullOrEmpty(result.Message))
{
Log(result.Message);

View File

@ -41,7 +41,7 @@ namespace Tests.BasicTests
primary.ConnectToPeer(secondary);
primary2.ConnectToPeer(secondary2);
Thread.Sleep(TimeSpan.FromMinutes(5));
Thread.Sleep(TimeSpan.FromMinutes(2));
primary.Metrics.AssertThat("libp2p_peers", Is.EqualTo(1));
primary2.Metrics.AssertThat("libp2p_peers", Is.EqualTo(1));
@ -55,7 +55,7 @@ namespace Tests.BasicTests
.EnableMarketplace(initialBalance: 234.TestTokens())
.BringOnline()[0];
Assert.That(primary.Marketplace.GetBalance(), Is.EqualTo(234));
primary.Marketplace.AssertThatBalance(Is.EqualTo(234.TestTokens()));
var secondary = SetupCodexNodes(1)
.EnableMarketplace(initialBalance: 1000.TestTokens())