Faster peer-pair checking

This commit is contained in:
benbierens 2023-05-12 10:48:12 +02:00
parent 90a5aafa1c
commit 830d74a5ae
No known key found for this signature in database
GPG Key ID: FE44815D96D0A1AA
1 changed files with 113 additions and 61 deletions

View File

@ -1,8 +1,8 @@
using DistTestCore.Codex;
using DistTestCore;
using NUnit.Framework;
using Utils;
using Logging;
using Utils;
namespace Tests.PeerDiscoveryTests
{
@ -15,73 +15,65 @@ namespace Tests.PeerDiscoveryTests
public static void AssertFullyConnected(BaseLog? log = null, params IOnlineCodexNode[] nodes)
{
var entries = nodes.Select(n => new Entry(n)).ToArray();
var entries = CreateEntries(nodes);
var pairs = CreatePairs(entries);
var failureMessags = new List<string>();
RetryWhilePairs(pairs, () =>
{
CheckAndRemoveSuccessful(pairs, log);
});
if (pairs.Any())
{
Assert.Fail(string.Join(Environment.NewLine, pairs.Select(p => p.GetMessage())));
}
}
private static void RetryWhilePairs(List<Pair> pairs, Action action)
{
var timeout = DateTime.UtcNow + TimeSpan.FromMinutes(2);
while (pairs.Any() && (timeout > DateTime.UtcNow))
{
action();
if (pairs.Any()) Time.Sleep(TimeSpan.FromSeconds(5));
}
}
private static void CheckAndRemoveSuccessful(List<Pair> pairs, BaseLog? log)
{
var checkTasks = pairs.Select(p => Task.Run(p.Check)).ToArray();
Task.WaitAll(checkTasks);
foreach (var pair in pairs.ToArray())
{
if (pair.Success)
{
pairs.Remove(pair);
if (log != null) log.Log(pair.GetMessage());
}
}
}
private static Entry[] CreateEntries(IOnlineCodexNode[] nodes)
{
return nodes.Select(n => new Entry(n)).ToArray();
}
private static List<Pair> CreatePairs(Entry[] entries)
{
return CreatePairsIterator(entries).ToList();
}
private static IEnumerable<Pair> CreatePairsIterator(Entry[] entries)
{
for (var x = 0; x < entries.Length; x++)
{
for (var y = x + 1; y < entries.Length; y++)
{
AssertKnowEachother(failureMessags, entries[x], entries[y], log);
yield return new Pair(entries[x], entries[y]);
}
}
CollectionAssert.IsEmpty(failureMessags);
}
private static void AssertKnowEachother(List<string> failureMessags, Entry a, Entry b, BaseLog? log)
{
var aKnowsB = Knows(a, b);
var bKnowsA = Knows(b, a);
var message = GetMessage(a, b, aKnowsB, bKnowsA);
if (log != null) log.Log(message);
if (!aKnowsB || !bKnowsA) failureMessags.Add(message);
}
private static string GetMessage(Entry a, Entry b, bool aKnowsB, bool bKnowsA)
{
var aName = a.Response.id;
var bName = b.Response.id;
if (aKnowsB && bKnowsA)
{
return $"{aName} and {bName} know each other.";
}
if (aKnowsB)
{
return $"{aName} knows {bName}, but {bName} does not know {aName}";
}
if (bKnowsA)
{
return $"{bName} knows {aName}, but {aName} does not know {bName}";
}
return $"{aName} and {bName} don't know each other.";
}
private static bool Knows(Entry a, Entry b)
{
var peerId = b.Response.id;
try
{
var response = GetDebugPeer(a.Node, peerId);
if (!string.IsNullOrEmpty(response.peerId) && response.addresses.Any())
{
return true;
}
}
catch
{
}
return false;
}
private static CodexDebugPeerResponse GetDebugPeer(IOnlineCodexNode node, string peerId)
{
return Time.Retry(() => node.GetDebugPeer(peerId), TimeSpan.FromMinutes(2), TimeSpan.FromSeconds(0.1));
}
public class Entry
@ -95,5 +87,65 @@ namespace Tests.PeerDiscoveryTests
public IOnlineCodexNode Node { get ; }
public CodexDebugResponse Response { get; }
}
public class Pair
{
public Pair(Entry a, Entry b)
{
A = a;
B = b;
}
public Entry A { get; }
public Entry B { get; }
public bool AKnowsB { get; private set; }
public bool BKnowsA { get; private set; }
public bool Success { get { return AKnowsB && BKnowsA; } }
public void Check()
{
AKnowsB = Knows(A, B);
BKnowsA = Knows(B, A);
}
public string GetMessage()
{
var aName = A.Response.id;
var bName = B.Response.id;
if (AKnowsB && BKnowsA)
{
return $"{aName} and {bName} know each other.";
}
if (AKnowsB)
{
return $"{aName} knows {bName}, but {bName} does not know {aName}";
}
if (BKnowsA)
{
return $"{bName} knows {aName}, but {aName} does not know {bName}";
}
return $"{aName} and {bName} don't know each other.";
}
private static bool Knows(Entry a, Entry b)
{
var peerId = b.Response.id;
try
{
var response = a.Node.GetDebugPeer(peerId);
if (!string.IsNullOrEmpty(response.peerId) && response.addresses.Any())
{
return true;
}
}
catch
{
}
return false;
}
}
}
}