From 830d74a5ae02fab6f8060eeee1fcf845dd392237 Mon Sep 17 00:00:00 2001 From: benbierens Date: Fri, 12 May 2023 10:48:12 +0200 Subject: [PATCH] Faster peer-pair checking --- Tests/PeerDiscoveryTests/PeerTestHelpers.cs | 174 +++++++++++++------- 1 file changed, 113 insertions(+), 61 deletions(-) diff --git a/Tests/PeerDiscoveryTests/PeerTestHelpers.cs b/Tests/PeerDiscoveryTests/PeerTestHelpers.cs index 99a6cbbd..c404fe3d 100644 --- a/Tests/PeerDiscoveryTests/PeerTestHelpers.cs +++ b/Tests/PeerDiscoveryTests/PeerTestHelpers.cs @@ -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(); + RetryWhilePairs(pairs, () => + { + CheckAndRemoveSuccessful(pairs, log); + }); + + if (pairs.Any()) + { + Assert.Fail(string.Join(Environment.NewLine, pairs.Select(p => p.GetMessage()))); + } + } + + private static void RetryWhilePairs(List 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 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 CreatePairs(Entry[] entries) + { + return CreatePairsIterator(entries).ToList(); + } + + private static IEnumerable 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 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; + } + } } }