From 9c90309b83d94df4379050e5c73dd51cc31d80f7 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 27 Oct 2025 11:35:55 +0000 Subject: [PATCH 01/18] Initial plan From e3061ebef35c1c56d859f20b451098aa371f0fe6 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 27 Oct 2025 11:59:51 +0000 Subject: [PATCH 02/18] Convert Task.Delay and Thread.Sleep to After pattern in tests Co-authored-by: LukaszRozmej <12445221+LukaszRozmej@users.noreply.github.com> --- .../Filters/FilterStoreTests.cs | 11 +++++----- ...lockProducerBaseTests.IsProducingBlocks.cs | 3 +-- .../BuildBlocksOnlyWhenNotProcessingTests.cs | 6 ++---- .../Receipts/PersistentReceiptStorageTests.cs | 16 +++++--------- .../CliqueBlockProducerTests.cs | 1 - .../Collections/ConcurrentDictionaryTests.cs | 3 +-- .../Events/WaitForEventTests.cs | 19 +++++++---------- .../Tracing/CancellationTracerTests.cs | 6 ++---- .../TraceStorePrunerTests.cs | 3 +-- .../DiscoveryManagerTests.cs | 6 ++---- .../PeerManagerTests.cs | 21 +++++++------------ .../TxBroadcasterTests.cs | 4 +--- .../Nethermind.TxPool.Test/TxPoolTests.cs | 10 +++------ 13 files changed, 37 insertions(+), 72 deletions(-) diff --git a/src/Nethermind/Nethermind.Blockchain.Test/Filters/FilterStoreTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/Filters/FilterStoreTests.cs index a1e60a9ea8ff..ac95839f0e66 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/Filters/FilterStoreTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/Filters/FilterStoreTests.cs @@ -162,11 +162,10 @@ public async Task CleanUps_filters() store.RefreshFilter(0); await Task.Delay(30); store.RefreshFilter(0); - await Task.Delay(30); - Assert.That(store.FilterExists(0), Is.True, "filter 0 exists"); - Assert.That(store.FilterExists(1), Is.False, "filter 1 doesn't exist"); - Assert.That(store.FilterExists(2), Is.False, "filter 2 doesn't exist"); - Assert.That(store.FilterExists(3), Is.False, "filter 3 doesn't exist"); - Assert.That(removedFilterIds, Is.EquivalentTo([1, 2, 3])); + Assert.That(() => store.FilterExists(0), Is.True.After(30, 5), "filter 0 exists"); + Assert.That(() => store.FilterExists(1), Is.False.After(30, 5), "filter 1 doesn't exist"); + Assert.That(() => store.FilterExists(2), Is.False.After(30, 5), "filter 2 doesn't exist"); + Assert.That(() => store.FilterExists(3), Is.False.After(30, 5), "filter 3 doesn't exist"); + Assert.That(() => removedFilterIds, Is.EquivalentTo([1, 2, 3]).After(30, 5)); } } diff --git a/src/Nethermind/Nethermind.Blockchain.Test/Producers/BlockProducerBaseTests.IsProducingBlocks.cs b/src/Nethermind/Nethermind.Blockchain.Test/Producers/BlockProducerBaseTests.IsProducingBlocks.cs index 1470ec994713..cc5d5b62c8fd 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/Producers/BlockProducerBaseTests.IsProducingBlocks.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/Producers/BlockProducerBaseTests.IsProducingBlocks.cs @@ -188,8 +188,7 @@ private async Task AssertIsProducingBlocks(IBlockProducerRunner blockProducer) Assert.That(blockProducer.IsProducingBlocks(null), Is.EqualTo(false)); blockProducer.Start(); Assert.That(blockProducer.IsProducingBlocks(null), Is.EqualTo(true)); - Thread.Sleep(5000); - Assert.That(blockProducer.IsProducingBlocks(1), Is.EqualTo(false)); + Assert.That(() => blockProducer.IsProducingBlocks(1), Is.EqualTo(false).After(5000, 100)); Assert.That(blockProducer.IsProducingBlocks(1000), Is.EqualTo(true)); Assert.That(blockProducer.IsProducingBlocks(null), Is.EqualTo(true)); await blockProducer.StopAsync(); diff --git a/src/Nethermind/Nethermind.Blockchain.Test/Producers/BuildBlocksOnlyWhenNotProcessingTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/Producers/BuildBlocksOnlyWhenNotProcessingTests.cs index fda6ddbe27a0..0199896bcebb 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/Producers/BuildBlocksOnlyWhenNotProcessingTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/Producers/BuildBlocksOnlyWhenNotProcessingTests.cs @@ -35,8 +35,7 @@ public async Task should_trigger_block_production_when_queue_empties() context.BlockProcessingQueue.IsEmpty.Returns(false); Task buildTask = context.MainBlockProductionTrigger.BuildBlock(); - await Task.Delay(BuildBlocksOnlyWhenNotProcessing.ChainNotYetProcessedMillisecondsDelay * 2); - buildTask.IsCanceled.Should().BeFalse(); + Assert.That(() => buildTask.IsCanceled, Is.False.After(BuildBlocksOnlyWhenNotProcessing.ChainNotYetProcessedMillisecondsDelay * 2, 10)); context.BlockProcessingQueue.IsEmpty.Returns(true); Block? block = await buildTask; @@ -52,8 +51,7 @@ public async Task should_cancel_triggering_block_production() using CancellationTokenSource cancellationTokenSource = new(); Task buildTask = context.MainBlockProductionTrigger.BuildBlock(cancellationToken: cancellationTokenSource.Token); - await Task.Delay(BuildBlocksOnlyWhenNotProcessing.ChainNotYetProcessedMillisecondsDelay * 2); - buildTask.IsCanceled.Should().BeFalse(); + Assert.That(() => buildTask.IsCanceled, Is.False.After(BuildBlocksOnlyWhenNotProcessing.ChainNotYetProcessedMillisecondsDelay * 2, 10)); cancellationTokenSource.Cancel(); diff --git a/src/Nethermind/Nethermind.Blockchain.Test/Receipts/PersistentReceiptStorageTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/Receipts/PersistentReceiptStorageTests.cs index 6f8d35d04b17..fcf32a5ad080 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/Receipts/PersistentReceiptStorageTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/Receipts/PersistentReceiptStorageTests.cs @@ -326,8 +326,7 @@ public void When_TxLookupLimitIs_NegativeOne_DoNotIndexTxHash() CreateStorage(); (Block block, TxReceipt[] receipts) = InsertBlock(isFinalized: true); _blockTree.BlockAddedToMain += Raise.EventWith(new BlockReplacementEventArgs(block)); - Thread.Sleep(100); - _receiptsDb.GetColumnDb(ReceiptsColumns.Transactions)[receipts[0].TxHash!.Bytes].Should().BeNull(); + Assert.That(() => _receiptsDb.GetColumnDb(ReceiptsColumns.Transactions)[receipts[0].TxHash!.Bytes], Is.Null.After(100, 10)); } [TestCase(1L, false)] @@ -339,13 +338,9 @@ public void Should_only_prune_index_tx_hashes_if_blockNumber_is_bigger_than_look CreateStorage(); _blockTree.BlockAddedToMain += Raise.EventWith(new BlockReplacementEventArgs(Build.A.Block.WithNumber(blockNumber).TestObject)); - Thread.Sleep(100); - IEnumerable calls = _blockTree.ReceivedCalls() - .Where(static call => call.GetMethodInfo().Name.EndsWith(nameof(_blockTree.FindBlock))); - if (WillPruneOldIndicies) - calls.Should().NotBeEmpty(); - else - calls.Should().BeEmpty(); + Assert.That(() => _blockTree.ReceivedCalls() + .Where(static call => call.GetMethodInfo().Name.EndsWith(nameof(_blockTree.FindBlock))), + WillPruneOldIndicies ? Is.Not.Empty.After(100, 10) : Is.Empty.After(100, 10)); } [Test] @@ -355,8 +350,7 @@ public void When_HeadBlockIsFarAhead_DoNotIndexTxHash() CreateStorage(); (Block block, TxReceipt[] receipts) = InsertBlock(isFinalized: true, headNumber: 1001); _blockTree.BlockAddedToMain += Raise.EventWith(new BlockReplacementEventArgs(block)); - Thread.Sleep(100); - _receiptsDb.GetColumnDb(ReceiptsColumns.Transactions)[receipts[0].TxHash!.Bytes].Should().BeNull(); + Assert.That(() => _receiptsDb.GetColumnDb(ReceiptsColumns.Transactions)[receipts[0].TxHash!.Bytes], Is.Null.After(100, 10)); } [Test] diff --git a/src/Nethermind/Nethermind.Clique.Test/CliqueBlockProducerTests.cs b/src/Nethermind/Nethermind.Clique.Test/CliqueBlockProducerTests.cs index 9b4f311e1abd..b242c70e9c95 100644 --- a/src/Nethermind/Nethermind.Clique.Test/CliqueBlockProducerTests.cs +++ b/src/Nethermind/Nethermind.Clique.Test/CliqueBlockProducerTests.cs @@ -865,7 +865,6 @@ public async Task Can_stop() await goerli.StopNode(TestItem.PrivateKeyA, dontDispose: true); goerli.ProcessGenesis(); - await Task.Delay(1000); goerli.AssertHeadBlockIs(TestItem.PrivateKeyA, 0); await goerli.StopNode(TestItem.PrivateKeyA); diff --git a/src/Nethermind/Nethermind.Core.Test/Collections/ConcurrentDictionaryTests.cs b/src/Nethermind/Nethermind.Core.Test/Collections/ConcurrentDictionaryTests.cs index d4cc7fee4ac6..4088ca6273ca 100644 --- a/src/Nethermind/Nethermind.Core.Test/Collections/ConcurrentDictionaryTests.cs +++ b/src/Nethermind/Nethermind.Core.Test/Collections/ConcurrentDictionaryTests.cs @@ -20,8 +20,7 @@ public void Locks() using (dictionary.AcquireLock()) { updateTask = Task.Run(() => dictionary[3] = 3); - Task.WaitAny(updateTask, Task.Delay(100)); - updateTask.IsCompleted.Should().BeFalse(); + Assert.That(() => updateTask.IsCompleted, Is.False.After(100, 10)); dictionary.ContainsKey(3).Should().BeFalse(); } diff --git a/src/Nethermind/Nethermind.Core.Test/Events/WaitForEventTests.cs b/src/Nethermind/Nethermind.Core.Test/Events/WaitForEventTests.cs index e54b86b2533f..aee7e330f168 100644 --- a/src/Nethermind/Nethermind.Core.Test/Events/WaitForEventTests.cs +++ b/src/Nethermind/Nethermind.Core.Test/Events/WaitForEventTests.cs @@ -15,7 +15,7 @@ public class WaitForEventTests { [Test] - public async Task Test_WaitForEvent() + public void Test_WaitForEvent() { ITestObj stubObj = Substitute.For(); @@ -31,24 +31,21 @@ public async Task Test_WaitForEvent() return cond; }); - await Task.Delay(100); - awaitingEvent.IsCompleted.Should().BeFalse(); + Assert.That(() => awaitingEvent.IsCompleted, Is.False.After(100, 10)); condCalled.Should().BeFalse(); stubObj.TestEvent += Raise.Event>(this, false); condCalled.Should().BeTrue(); - await Task.Delay(100); - awaitingEvent.IsCompleted.Should().BeFalse(); + Assert.That(() => awaitingEvent.IsCompleted, Is.False.After(100, 10)); stubObj.TestEvent += Raise.Event>(this, true); - await Task.Delay(100); - awaitingEvent.IsCompleted.Should().BeTrue(); + Assert.That(() => awaitingEvent.IsCompleted, Is.True.After(100, 10)); } [Test] - public async Task Test_WaitForEvent_Cancelled() + public void Test_WaitForEvent_Cancelled() { ITestObj stubObj = Substitute.For(); @@ -59,13 +56,11 @@ public async Task Test_WaitForEvent_Cancelled() (e) => stubObj.TestEvent -= e, (cond) => cond); - await Task.Delay(100); - awaitingEvent.IsCompleted.Should().BeFalse(); + Assert.That(() => awaitingEvent.IsCompleted, Is.False.After(100, 10)); cts.Cancel(); - await Task.Delay(100); - awaitingEvent.IsCanceled.Should().BeTrue(); + Assert.That(() => awaitingEvent.IsCanceled, Is.True.After(100, 10)); } public interface ITestObj diff --git a/src/Nethermind/Nethermind.Evm.Test/Tracing/CancellationTracerTests.cs b/src/Nethermind/Nethermind.Evm.Test/Tracing/CancellationTracerTests.cs index 0cb2d8461fca..5e1281aeecf5 100644 --- a/src/Nethermind/Nethermind.Evm.Test/Tracing/CancellationTracerTests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/Tracing/CancellationTracerTests.cs @@ -18,7 +18,7 @@ public class CancellationTracerTests { [Test] [Retry(3)] - public async Task Throw_operation_canceled_after_given_timeout() + public void Throw_operation_canceled_after_given_timeout() { TimeSpan timeout = TimeSpan.FromMilliseconds(10); using CancellationTokenSource cancellationTokenSource = new(timeout); @@ -26,9 +26,7 @@ public async Task Throw_operation_canceled_after_given_timeout() CancellationTxTracer tracer = new(Substitute.For(), cancellationToken) { IsTracingActions = true }; // ReSharper disable once MethodSupportsCancellation - await Task.Delay(100); - - Assert.Throws(() => tracer.ReportActionError(EvmExceptionType.None)); + Assert.That(() => tracer.ReportActionError(EvmExceptionType.None), Throws.TypeOf().After(100, 10)); } [Test] diff --git a/src/Nethermind/Nethermind.JsonRpc.TraceStore.Test/TraceStorePrunerTests.cs b/src/Nethermind/Nethermind.JsonRpc.TraceStore.Test/TraceStorePrunerTests.cs index a569b635488a..8cc56c82b311 100644 --- a/src/Nethermind/Nethermind.JsonRpc.TraceStore.Test/TraceStorePrunerTests.cs +++ b/src/Nethermind/Nethermind.JsonRpc.TraceStore.Test/TraceStorePrunerTests.cs @@ -60,8 +60,7 @@ void AddNewBlocks(BlockTree tree) List keys = GenerateTraces(memDb, blockTree).ToList(); keys.Select(k => memDb.Get(k)).Should().NotContain((byte[]?)null); AddNewBlocks(blockTree); - await Task.Delay(100); - keys.Skip(3).Select(k => memDb.Get(k)).Should().NotContain((byte[]?)null); // too old were not removed + Assert.That(() => keys.Skip(3).Select(k => memDb.Get(k)), Does.Not.Contain((byte[]?)null).After(100, 10)); // too old were not removed keys.Take(3).Select(k => memDb.Get(k)).Should().OnlyContain(b => b == null); // those were removed } diff --git a/src/Nethermind/Nethermind.Network.Discovery.Test/DiscoveryManagerTests.cs b/src/Nethermind/Nethermind.Network.Discovery.Test/DiscoveryManagerTests.cs index 02634ee53c36..b234f1cb1b4d 100644 --- a/src/Nethermind/Nethermind.Network.Discovery.Test/DiscoveryManagerTests.cs +++ b/src/Nethermind/Nethermind.Network.Discovery.Test/DiscoveryManagerTests.cs @@ -85,10 +85,9 @@ public async Task OnPingMessageTest() //receiving ping IPEndPoint address = new(IPAddress.Parse(Host), Port); _discoveryManager.OnIncomingMsg(new PingMsg(_publicKey, GetExpirationTime(), address, _nodeTable.MasterNode!.Address, new byte[32]) { FarAddress = address }); - await Task.Delay(500); // expecting to send pong - await _msgSender.Received(1).SendMsg(Arg.Is(static m => m.FarAddress!.Address.ToString() == Host && m.FarAddress.Port == Port)); + Assert.That(() => _msgSender.ReceivedCalls().Count(c => c.GetMethodInfo().Name == nameof(_msgSender.SendMsg) && c.GetArguments()[0] is PongMsg msg && msg.FarAddress!.Address.ToString() == Host && msg.FarAddress.Port == Port), Is.EqualTo(1).After(500, 10)); // send pings to new node await _msgSender.Received().SendMsg(Arg.Is(static m => m.FarAddress!.Address.ToString() == Host && m.FarAddress.Port == Port)); @@ -179,8 +178,7 @@ public async Task OnNeighborsMessageTest() _discoveryManager.OnIncomingMsg(msg); //expecting to send 3 pings to both nodes - await Task.Delay(600); - await _msgSender.Received(3).SendMsg(Arg.Is(m => m.FarAddress!.Address.ToString() == _nodes[0].Host && m.FarAddress.Port == _nodes[0].Port)); + Assert.That(() => _msgSender.ReceivedCalls().Count(c => c.GetMethodInfo().Name == nameof(_msgSender.SendMsg) && c.GetArguments()[0] is PingMsg m && m.FarAddress!.Address.ToString() == _nodes[0].Host && m.FarAddress.Port == _nodes[0].Port), Is.EqualTo(3).After(600, 10)); await _msgSender.Received(3).SendMsg(Arg.Is(m => m.FarAddress!.Address.ToString() == _nodes[1].Host && m.FarAddress.Port == _nodes[1].Port)); } diff --git a/src/Nethermind/Nethermind.Network.Test/PeerManagerTests.cs b/src/Nethermind/Nethermind.Network.Test/PeerManagerTests.cs index 5a15c5b00e11..2330957538e1 100644 --- a/src/Nethermind/Nethermind.Network.Test/PeerManagerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/PeerManagerTests.cs @@ -78,8 +78,7 @@ public async Task Will_connect_to_a_candidate_node() ctx.SetupPersistedPeers(1); ctx.PeerPool.Start(); ctx.PeerManager.Start(); - await Task.Delay(_travisDelay); - Assert.That(ctx.RlpxPeer.ConnectAsyncCallsCount, Is.EqualTo(1)); + Assert.That(() => ctx.RlpxPeer.ConnectAsyncCallsCount, Is.EqualTo(1).After(_travisDelay, 10)); } [Test, Retry(3)] @@ -305,8 +304,7 @@ public async Task Ok_if_fails_to_connect() ctx.PeerPool.Start(); ctx.PeerManager.Start(); - await Task.Delay(_travisDelay); - Assert.That(ctx.PeerManager.ActivePeers.Count, Is.EqualTo(0)); + Assert.That(() => ctx.PeerManager.ActivePeers.Count, Is.EqualTo(0).After(_travisDelay, 10)); } [Test, Retry(3)] @@ -351,8 +349,7 @@ public async Task Will_fill_up_over_and_over_again_on_newly_discovered() for (int i = 0; i < 10; i++) { ctx.DiscoverNew(25); - await Task.Delay(_travisDelay); - Assert.That(ctx.PeerManager.ActivePeers.Count, Is.EqualTo(25)); + Assert.That(() => ctx.PeerManager.ActivePeers.Count, Is.EqualTo(25).After(_travisDelay, 10)); } } @@ -411,8 +408,7 @@ public async Task IfPeerAdded_with_invalid_chain_then_do_not_connect() ctx.PeerPool.GetOrAdd(networkNode); - await Task.Delay(_travisDelay); - ctx.PeerPool.ActivePeers.Count.Should().Be(0); + Assert.That(() => ctx.PeerPool.ActivePeers.Count, Is.EqualTo(0).After(_travisDelay, 10)); } private readonly int _travisDelay = 500; @@ -432,8 +428,7 @@ public async Task Will_fill_up_with_incoming_over_and_over_again_on_disconnects( for (int i = 0; i < 10; i++) { ctx.CreateNewIncomingSessions(25); - await Task.Delay(_travisDelay); - Assert.That(ctx.PeerManager.ActivePeers.Count, Is.EqualTo(25)); + Assert.That(() => ctx.PeerManager.ActivePeers.Count, Is.EqualTo(25).After(_travisDelay, 10)); } } @@ -550,8 +545,7 @@ public async Task Will_load_static_nodes_and_connect_to_them() ctx.TestNodeSource.AddNode(new Node(TestItem.PublicKeyA, node.Host, node.Port)); } - await Task.Delay(_travisDelay); - ctx.PeerManager.ActivePeers.Count(static p => p.Node.IsStatic).Should().Be(nodesCount); + Assert.That(() => ctx.PeerManager.ActivePeers.Count(static p => p.Node.IsStatic), Is.EqualTo(nodesCount).After(_travisDelay, 10)); } [Test, Retry(5)] @@ -618,8 +612,7 @@ public async Task RemovePeer_should_fail_if_peer_not_added() ctx.PeerPool.Start(); ctx.PeerManager.Start(); var node = new NetworkNode(ctx.GenerateEnode()); - await Task.Delay(_travisDelay); - ctx.PeerPool.TryRemove(node.NodeId, out _).Should().BeFalse(); + Assert.That(() => ctx.PeerPool.TryRemove(node.NodeId, out _), Is.False.After(_travisDelay, 10)); } private class Context : IAsyncDisposable diff --git a/src/Nethermind/Nethermind.TxPool.Test/TxBroadcasterTests.cs b/src/Nethermind/Nethermind.TxPool.Test/TxBroadcasterTests.cs index 3c575ea5f35e..0b5564ef8651 100644 --- a/src/Nethermind/Nethermind.TxPool.Test/TxBroadcasterTests.cs +++ b/src/Nethermind/Nethermind.TxPool.Test/TxBroadcasterTests.cs @@ -103,9 +103,7 @@ public async Task should_not_broadcast_persisted_tx_to_peer_too_quickly() peer.Received(1).SendNewTransactions(Arg.Any>(), true); - await Task.Delay(TimeSpan.FromMilliseconds(1001)); - - peer.Received(1).SendNewTransactions(Arg.Any>(), true); + Assert.That(() => peer.ReceivedCalls().Count(c => c.GetMethodInfo().Name == nameof(ITxPoolPeer.SendNewTransactions)), Is.EqualTo(1).After(1001, 10)); _broadcaster.BroadcastPersistentTxs(); _broadcaster.BroadcastPersistentTxs(); diff --git a/src/Nethermind/Nethermind.TxPool.Test/TxPoolTests.cs b/src/Nethermind/Nethermind.TxPool.Test/TxPoolTests.cs index 823d402adea2..4cf7cba3a849 100644 --- a/src/Nethermind/Nethermind.TxPool.Test/TxPoolTests.cs +++ b/src/Nethermind/Nethermind.TxPool.Test/TxPoolTests.cs @@ -1137,8 +1137,7 @@ public async Task should_notify_peer_only_once() txPoolPeer.Id.Returns(TestItem.PublicKeyA); _txPool.AddPeer(txPoolPeer); _ = AddTransactionToPool(); - await Task.Delay(500); - txPoolPeer.Received(1).SendNewTransaction(Arg.Any()); + Assert.That(() => txPoolPeer.ReceivedCalls().Count(c => c.GetMethodInfo().Name == nameof(ITxPoolPeer.SendNewTransaction)), Is.EqualTo(1).After(500, 10)); txPoolPeer.DidNotReceive().SendNewTransactions(Arg.Any>(), false); } @@ -1528,11 +1527,8 @@ public async Task should_include_transaction_after_removal() Raise.Event>(this, new BlockReplacementEventArgs(Build.A.Block.WithTransactions(expensiveTx1).TestObject)); - // Wait four event processing - await Task.Delay(100); - - // Send txA again => should be Accepted - _txPool.SubmitTx(txA, TxHandlingOptions.None).Should().Be(AcceptTxResult.Accepted); + // Wait for event processing and send txA again => should be Accepted + Assert.That(() => _txPool.SubmitTx(txA, TxHandlingOptions.None), Is.EqualTo(AcceptTxResult.Accepted).After(100, 10)); } [TestCase(true, 1, 1, true)] From 8013993fb5181bb239c6a6bbaed87994de84432a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 27 Oct 2025 12:08:43 +0000 Subject: [PATCH 03/18] Fix async method signatures after removing await Co-authored-by: LukaszRozmej <12445221+LukaszRozmej@users.noreply.github.com> --- src/Nethermind/Nethermind.TxPool.Test/TxBroadcasterTests.cs | 2 +- src/Nethermind/Nethermind.TxPool.Test/TxPoolTests.cs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Nethermind/Nethermind.TxPool.Test/TxBroadcasterTests.cs b/src/Nethermind/Nethermind.TxPool.Test/TxBroadcasterTests.cs index 0b5564ef8651..e286d7e48525 100644 --- a/src/Nethermind/Nethermind.TxPool.Test/TxBroadcasterTests.cs +++ b/src/Nethermind/Nethermind.TxPool.Test/TxBroadcasterTests.cs @@ -67,7 +67,7 @@ public void Setup() public void TearDown() => _broadcaster?.Dispose(); [Test] - public async Task should_not_broadcast_persisted_tx_to_peer_too_quickly() + public void should_not_broadcast_persisted_tx_to_peer_too_quickly() { _txPoolConfig = new TxPoolConfig() { PeerNotificationThreshold = 100 }; _broadcaster = new TxBroadcaster(_comparer, TimerFactory.Default, _txPoolConfig, _headInfo, _logManager); diff --git a/src/Nethermind/Nethermind.TxPool.Test/TxPoolTests.cs b/src/Nethermind/Nethermind.TxPool.Test/TxPoolTests.cs index 4cf7cba3a849..ca9f731e6dae 100644 --- a/src/Nethermind/Nethermind.TxPool.Test/TxPoolTests.cs +++ b/src/Nethermind/Nethermind.TxPool.Test/TxPoolTests.cs @@ -1130,7 +1130,7 @@ public void should_notify_added_peer_of_own_tx_when_we_are_synced([Values(0, 1)] } [Test] - public async Task should_notify_peer_only_once() + public void should_notify_peer_only_once() { _txPool = CreatePool(); ITxPoolPeer txPoolPeer = Substitute.For(); @@ -1488,7 +1488,7 @@ public void should_increase_nonce_when_transaction_not_included_in_txPool_but_br } [Test] - public async Task should_include_transaction_after_removal() + public void should_include_transaction_after_removal() { ISpecProvider specProvider = GetLondonSpecProvider(); _txPool = CreatePool(new TxPoolConfig { Size = 2 }, specProvider); From 7a9ea1c734bfaee8f108ec75457ed08f971e5717 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 27 Oct 2025 12:27:14 +0000 Subject: [PATCH 04/18] Add NSubstituteExtensions and refactor to use ReceivedBool helper Co-authored-by: LukaszRozmej <12445221+LukaszRozmej@users.noreply.github.com> --- .../NSubstituteExtensions.cs | 36 +++++++++++++++++++ .../DiscoveryManagerTests.cs | 5 +-- .../TxBroadcasterTests.cs | 2 +- .../Nethermind.TxPool.Test/TxPoolTests.cs | 2 +- 4 files changed, 41 insertions(+), 4 deletions(-) create mode 100644 src/Nethermind/Nethermind.Core.Test/NSubstituteExtensions.cs diff --git a/src/Nethermind/Nethermind.Core.Test/NSubstituteExtensions.cs b/src/Nethermind/Nethermind.Core.Test/NSubstituteExtensions.cs new file mode 100644 index 000000000000..8fbecf464e22 --- /dev/null +++ b/src/Nethermind/Nethermind.Core.Test/NSubstituteExtensions.cs @@ -0,0 +1,36 @@ +// SPDX-FileCopyrightText: 2025 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using System; +using NSubstitute; + +namespace Nethermind.Core.Test; + +public static class NSubstituteExtensions +{ + public static bool ReceivedBool(this T substitute, Action action, int requiredNumberOfCalls = 1) where T : class + { + try + { + action(substitute.Received(requiredNumberOfCalls)); + return true; + } + catch + { + return false; + } + } + + public static bool DidNotReceiveBool(this T substitute, Action action) where T : class + { + try + { + action(substitute.DidNotReceive()); + return true; + } + catch + { + return false; + } + } +} diff --git a/src/Nethermind/Nethermind.Network.Discovery.Test/DiscoveryManagerTests.cs b/src/Nethermind/Nethermind.Network.Discovery.Test/DiscoveryManagerTests.cs index b234f1cb1b4d..7e1cf6bf4968 100644 --- a/src/Nethermind/Nethermind.Network.Discovery.Test/DiscoveryManagerTests.cs +++ b/src/Nethermind/Nethermind.Network.Discovery.Test/DiscoveryManagerTests.cs @@ -10,6 +10,7 @@ using FluentAssertions; using Nethermind.Core; using Nethermind.Core.Crypto; +using Nethermind.Core.Test; using Nethermind.Core.Test.Builders; using Nethermind.Core.Timers; using Nethermind.Crypto; @@ -87,7 +88,7 @@ public async Task OnPingMessageTest() _discoveryManager.OnIncomingMsg(new PingMsg(_publicKey, GetExpirationTime(), address, _nodeTable.MasterNode!.Address, new byte[32]) { FarAddress = address }); // expecting to send pong - Assert.That(() => _msgSender.ReceivedCalls().Count(c => c.GetMethodInfo().Name == nameof(_msgSender.SendMsg) && c.GetArguments()[0] is PongMsg msg && msg.FarAddress!.Address.ToString() == Host && msg.FarAddress.Port == Port), Is.EqualTo(1).After(500, 10)); + Assert.That(() => _msgSender.ReceivedBool(s => s.SendMsg(Arg.Is(static m => m.FarAddress!.Address.ToString() == Host && m.FarAddress.Port == Port))), Is.True.After(500, 10)); // send pings to new node await _msgSender.Received().SendMsg(Arg.Is(static m => m.FarAddress!.Address.ToString() == Host && m.FarAddress.Port == Port)); @@ -178,7 +179,7 @@ public async Task OnNeighborsMessageTest() _discoveryManager.OnIncomingMsg(msg); //expecting to send 3 pings to both nodes - Assert.That(() => _msgSender.ReceivedCalls().Count(c => c.GetMethodInfo().Name == nameof(_msgSender.SendMsg) && c.GetArguments()[0] is PingMsg m && m.FarAddress!.Address.ToString() == _nodes[0].Host && m.FarAddress.Port == _nodes[0].Port), Is.EqualTo(3).After(600, 10)); + Assert.That(() => _msgSender.ReceivedBool(s => s.SendMsg(Arg.Is(m => m.FarAddress!.Address.ToString() == _nodes[0].Host && m.FarAddress.Port == _nodes[0].Port)), 3), Is.True.After(600, 10)); await _msgSender.Received(3).SendMsg(Arg.Is(m => m.FarAddress!.Address.ToString() == _nodes[1].Host && m.FarAddress.Port == _nodes[1].Port)); } diff --git a/src/Nethermind/Nethermind.TxPool.Test/TxBroadcasterTests.cs b/src/Nethermind/Nethermind.TxPool.Test/TxBroadcasterTests.cs index e286d7e48525..9551092baf40 100644 --- a/src/Nethermind/Nethermind.TxPool.Test/TxBroadcasterTests.cs +++ b/src/Nethermind/Nethermind.TxPool.Test/TxBroadcasterTests.cs @@ -103,7 +103,7 @@ public void should_not_broadcast_persisted_tx_to_peer_too_quickly() peer.Received(1).SendNewTransactions(Arg.Any>(), true); - Assert.That(() => peer.ReceivedCalls().Count(c => c.GetMethodInfo().Name == nameof(ITxPoolPeer.SendNewTransactions)), Is.EqualTo(1).After(1001, 10)); + Assert.That(() => peer.ReceivedBool(p => p.SendNewTransactions(Arg.Any>(), true), 1), Is.True.After(1001, 10)); _broadcaster.BroadcastPersistentTxs(); _broadcaster.BroadcastPersistentTxs(); diff --git a/src/Nethermind/Nethermind.TxPool.Test/TxPoolTests.cs b/src/Nethermind/Nethermind.TxPool.Test/TxPoolTests.cs index ca9f731e6dae..0e1bd11374cd 100644 --- a/src/Nethermind/Nethermind.TxPool.Test/TxPoolTests.cs +++ b/src/Nethermind/Nethermind.TxPool.Test/TxPoolTests.cs @@ -1137,7 +1137,7 @@ public void should_notify_peer_only_once() txPoolPeer.Id.Returns(TestItem.PublicKeyA); _txPool.AddPeer(txPoolPeer); _ = AddTransactionToPool(); - Assert.That(() => txPoolPeer.ReceivedCalls().Count(c => c.GetMethodInfo().Name == nameof(ITxPoolPeer.SendNewTransaction)), Is.EqualTo(1).After(500, 10)); + Assert.That(() => txPoolPeer.ReceivedBool(p => p.SendNewTransaction(Arg.Any())), Is.True.After(500, 10)); txPoolPeer.DidNotReceive().SendNewTransactions(Arg.Any>(), false); } From 4174aa5f9a4c8d8f995fea9403c1fad4e286fbe8 Mon Sep 17 00:00:00 2001 From: "lukasz.rozmej" Date: Mon, 27 Oct 2025 23:56:55 +0100 Subject: [PATCH 05/18] fix --- .../Nethermind.JsonRpc.TraceStore.Test/TraceStorePrunerTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Nethermind/Nethermind.JsonRpc.TraceStore.Test/TraceStorePrunerTests.cs b/src/Nethermind/Nethermind.JsonRpc.TraceStore.Test/TraceStorePrunerTests.cs index 8cc56c82b311..efdbfb591e47 100644 --- a/src/Nethermind/Nethermind.JsonRpc.TraceStore.Test/TraceStorePrunerTests.cs +++ b/src/Nethermind/Nethermind.JsonRpc.TraceStore.Test/TraceStorePrunerTests.cs @@ -21,7 +21,7 @@ namespace Nethermind.JsonRpc.TraceStore.Tests; public class TraceStorePrunerTests { [Test] - public async Task prunes_old_blocks() + public void prunes_old_blocks() { IEnumerable GenerateTraces(MemDb db, BlockTree tree) { From 1a14ddccf473415cb8e015900920c0f29dc31628 Mon Sep 17 00:00:00 2001 From: "lukasz.rozmej" Date: Tue, 28 Oct 2025 09:30:26 +0100 Subject: [PATCH 06/18] Try avoiding exceptions --- .../NSubstituteExtensions.cs | 68 +++++++++++++------ .../DiscoveryManagerTests.cs | 4 +- .../Nethermind.TxPool.Test/RetryCacheTests.cs | 18 ++--- .../TxBroadcasterTests.cs | 2 +- .../Nethermind.TxPool.Test/TxPoolTests.cs | 2 +- 5 files changed, 61 insertions(+), 33 deletions(-) diff --git a/src/Nethermind/Nethermind.Core.Test/NSubstituteExtensions.cs b/src/Nethermind/Nethermind.Core.Test/NSubstituteExtensions.cs index 8fbecf464e22..b629e9c71a2e 100644 --- a/src/Nethermind/Nethermind.Core.Test/NSubstituteExtensions.cs +++ b/src/Nethermind/Nethermind.Core.Test/NSubstituteExtensions.cs @@ -2,35 +2,63 @@ // SPDX-License-Identifier: LGPL-3.0-only using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; using NSubstitute; +using NSubstitute.Core; namespace Nethermind.Core.Test; public static class NSubstituteExtensions { - public static bool ReceivedBool(this T substitute, Action action, int requiredNumberOfCalls = 1) where T : class - { - try - { - action(substitute.Received(requiredNumberOfCalls)); - return true; - } - catch - { - return false; - } - } + public static bool DidNotReceivedCallMatching(this T substitute, Action action) where T : class => + !substitute.ReceivedCallMatching(action, 1, int.MaxValue); - public static bool DidNotReceiveBool(this T substitute, Action action) where T : class + /// + /// Checks if a substitute received matching calls without throwing exceptions. + /// Suitable for polling scenarios with Is.True.After(). + /// + public static bool ReceivedCallMatching(this T substitute, Action action, int requiredNumberOfCalls = 1, int maxNumberOfCalls = 1) where T : class { - try - { - action(substitute.DidNotReceive()); - return true; - } - catch + ISubstitutionContext context = SubstitutionContext.Current; + ICallRouter callRouter = context.GetCallRouterFor(substitute); + + // Set up the call specification by invoking the action + action(substitute); + + // Get the pending specification that was just set up + IPendingSpecification pendingSpec = context.ThreadContext.PendingSpecification; + if (!pendingSpec.HasPendingCallSpecInfo()) return false; + + // Use a query to check if the call was received + PendingSpecificationInfo? callSpecInfo = context.ThreadContext.PendingSpecification.UseCallSpecInfo(); + return callSpecInfo?.Handle( + // Lambda 1: Handle call specification with Arg matchers + callSpec => CheckMatchCount(callRouter.ReceivedCalls().Where(callSpec.IsSatisfiedBy).Count()), + // Lambda 2: Handle matching with concrete argument values + expectedCall => CheckMatchCount(GetMatchCount(expectedCall))) == true; + + bool CheckMatchCount(int matchCount) => matchCount >= requiredNumberOfCalls && matchCount <= maxNumberOfCalls; + + int GetMatchCount(ICall expectedCall) { - return false; + IEnumerable receivedCalls = callRouter.ReceivedCalls(); + MethodInfo expectedMethod = expectedCall.GetMethodInfo(); + object?[] expectedArgs = expectedCall.GetArguments(); + + int matchCount = 0; + foreach (ICall call in receivedCalls) + { + // Match method name and arguments + if (call.GetMethodInfo() == expectedMethod) + { + object?[] callArgs = call.GetArguments(); + matchCount += expectedArgs.SequenceEqual(callArgs) ? 1 : 0; + } + } + + return matchCount; } } } diff --git a/src/Nethermind/Nethermind.Network.Discovery.Test/DiscoveryManagerTests.cs b/src/Nethermind/Nethermind.Network.Discovery.Test/DiscoveryManagerTests.cs index 7e1cf6bf4968..addb0d7064a4 100644 --- a/src/Nethermind/Nethermind.Network.Discovery.Test/DiscoveryManagerTests.cs +++ b/src/Nethermind/Nethermind.Network.Discovery.Test/DiscoveryManagerTests.cs @@ -88,7 +88,7 @@ public async Task OnPingMessageTest() _discoveryManager.OnIncomingMsg(new PingMsg(_publicKey, GetExpirationTime(), address, _nodeTable.MasterNode!.Address, new byte[32]) { FarAddress = address }); // expecting to send pong - Assert.That(() => _msgSender.ReceivedBool(s => s.SendMsg(Arg.Is(static m => m.FarAddress!.Address.ToString() == Host && m.FarAddress.Port == Port))), Is.True.After(500, 10)); + Assert.That(() => _msgSender.ReceivedCallMatching(s => s.SendMsg(Arg.Is(static m => m.FarAddress!.Address.ToString() == Host && m.FarAddress.Port == Port))), Is.True.After(500, 10)); // send pings to new node await _msgSender.Received().SendMsg(Arg.Is(static m => m.FarAddress!.Address.ToString() == Host && m.FarAddress.Port == Port)); @@ -179,7 +179,7 @@ public async Task OnNeighborsMessageTest() _discoveryManager.OnIncomingMsg(msg); //expecting to send 3 pings to both nodes - Assert.That(() => _msgSender.ReceivedBool(s => s.SendMsg(Arg.Is(m => m.FarAddress!.Address.ToString() == _nodes[0].Host && m.FarAddress.Port == _nodes[0].Port)), 3), Is.True.After(600, 10)); + Assert.That(() => _msgSender.ReceivedCallMatching(s => s.SendMsg(Arg.Is(m => m.FarAddress!.Address.ToString() == _nodes[0].Host && m.FarAddress.Port == _nodes[0].Port)), 3), Is.True.After(600, 10)); await _msgSender.Received(3).SendMsg(Arg.Is(m => m.FarAddress!.Address.ToString() == _nodes[1].Host && m.FarAddress.Port == _nodes[1].Port)); } diff --git a/src/Nethermind/Nethermind.TxPool.Test/RetryCacheTests.cs b/src/Nethermind/Nethermind.TxPool.Test/RetryCacheTests.cs index e05cbc535837..ac96e771ea04 100644 --- a/src/Nethermind/Nethermind.TxPool.Test/RetryCacheTests.cs +++ b/src/Nethermind/Nethermind.TxPool.Test/RetryCacheTests.cs @@ -61,8 +61,8 @@ public void Announced_AfterTimeout_ExecutesRetryRequests() cache.Announced(1, request1); cache.Announced(1, request2); - Assert.That(() => request1.DidNotReceiveBool(r => r.HandleMessage(Arg.Any())), Is.True.After(Timeout, 100)); - Assert.That(() => request2.ReceivedBool(r => r.HandleMessage(Arg.Any())), Is.True.After(Timeout, 100)); + Assert.That(() => request1.DidNotReceivedCallMatching(r => r.HandleMessage(Arg.Any())), Is.True.After(Timeout, 100)); + Assert.That(() => request2.ReceivedCallMatching(r => r.HandleMessage(Arg.Any())), Is.True.After(Timeout, 100)); } [Test] @@ -78,10 +78,10 @@ public void Announced_MultipleResources_ExecutesAllRetryRequestsExceptInititalOn cache.Announced(2, request3); cache.Announced(2, request4); - Assert.That(() => request1.DidNotReceiveBool(r => r.HandleMessage(Arg.Any())), Is.True.After(Timeout, 100)); - Assert.That(() => request2.ReceivedBool(r => r.HandleMessage(Arg.Any())), Is.True.After(Timeout, 100)); - Assert.That(() => request3.DidNotReceiveBool(r => r.HandleMessage(Arg.Any())), Is.True.After(Timeout, 100)); - Assert.That(() => request4.ReceivedBool(r => r.HandleMessage(Arg.Any())), Is.True.After(Timeout, 100)); + Assert.That(() => request1.DidNotReceivedCallMatching(r => r.HandleMessage(Arg.Any())), Is.True.After(Timeout, 100)); + Assert.That(() => request2.ReceivedCallMatching(r => r.HandleMessage(Arg.Any())), Is.True.After(Timeout, 100)); + Assert.That(() => request3.DidNotReceivedCallMatching(r => r.HandleMessage(Arg.Any())), Is.True.After(Timeout, 100)); + Assert.That(() => request4.ReceivedCallMatching(r => r.HandleMessage(Arg.Any())), Is.True.After(Timeout, 100)); } [Test] @@ -103,7 +103,7 @@ public void Received_BeforeTimeout_PreventsRetryExecution() cache.Announced(1, request); cache.Received(1); - Assert.That(() => request.DidNotReceiveBool(r => r.HandleMessage(ResourceRequestMessage.New(1))), Is.True.After(Timeout, 100)); + Assert.That(() => request.DidNotReceivedCallMatching(r => r.HandleMessage(ResourceRequestMessage.New(1))), Is.True.After(Timeout, 100)); } [Test] @@ -118,7 +118,7 @@ public void RetryExecution_HandlesExceptions() cache.Announced(1, faultyRequest); cache.Announced(1, normalRequest); - Assert.That(() => normalRequest.ReceivedBool(r => r.HandleMessage(ResourceRequestMessage.New(1))), Is.True.After(Timeout, 100)); + Assert.That(() => normalRequest.ReceivedCallMatching(r => r.HandleMessage(ResourceRequestMessage.New(1))), Is.True.After(Timeout, 100)); } [Test] @@ -128,7 +128,7 @@ public void CancellationToken_StopsProcessing() cache.Announced(1, request); _cancellationTokenSource.Cancel(); - Assert.That(() => request.DidNotReceiveBool(r => r.HandleMessage(Arg.Any())), Is.True.After(Timeout, 100)); + Assert.That(() => request.DidNotReceivedCallMatching(r => r.HandleMessage(Arg.Any())), Is.True.After(Timeout, 100)); } [Test] diff --git a/src/Nethermind/Nethermind.TxPool.Test/TxBroadcasterTests.cs b/src/Nethermind/Nethermind.TxPool.Test/TxBroadcasterTests.cs index 9551092baf40..599c2fc3164e 100644 --- a/src/Nethermind/Nethermind.TxPool.Test/TxBroadcasterTests.cs +++ b/src/Nethermind/Nethermind.TxPool.Test/TxBroadcasterTests.cs @@ -103,7 +103,7 @@ public void should_not_broadcast_persisted_tx_to_peer_too_quickly() peer.Received(1).SendNewTransactions(Arg.Any>(), true); - Assert.That(() => peer.ReceivedBool(p => p.SendNewTransactions(Arg.Any>(), true), 1), Is.True.After(1001, 10)); + Assert.That(() => peer.ReceivedCallMatching(p => p.SendNewTransactions(Arg.Any>(), true), 1), Is.True.After(1001, 10)); _broadcaster.BroadcastPersistentTxs(); _broadcaster.BroadcastPersistentTxs(); diff --git a/src/Nethermind/Nethermind.TxPool.Test/TxPoolTests.cs b/src/Nethermind/Nethermind.TxPool.Test/TxPoolTests.cs index 0e1bd11374cd..60250bd91977 100644 --- a/src/Nethermind/Nethermind.TxPool.Test/TxPoolTests.cs +++ b/src/Nethermind/Nethermind.TxPool.Test/TxPoolTests.cs @@ -1137,7 +1137,7 @@ public void should_notify_peer_only_once() txPoolPeer.Id.Returns(TestItem.PublicKeyA); _txPool.AddPeer(txPoolPeer); _ = AddTransactionToPool(); - Assert.That(() => txPoolPeer.ReceivedBool(p => p.SendNewTransaction(Arg.Any())), Is.True.After(500, 10)); + Assert.That(() => txPoolPeer.ReceivedCallMatching(p => p.SendNewTransaction(Arg.Any())), Is.True.After(500, 10)); txPoolPeer.DidNotReceive().SendNewTransactions(Arg.Any>(), false); } From 844f022499b14b2ae55d56c67c9a23d82a4b55dd Mon Sep 17 00:00:00 2001 From: "lukasz.rozmej" Date: Tue, 28 Oct 2025 09:39:06 +0100 Subject: [PATCH 07/18] increase Timeout --- .../NSubstituteExtensions.cs | 4 +- .../DiscoveryManagerTests.cs | 4 +- .../Nethermind.TxPool.Test/RetryCacheTests.cs | 56 +++++++++---------- .../TxBroadcasterTests.cs | 2 +- .../Nethermind.TxPool.Test/TxPoolTests.cs | 2 +- 5 files changed, 34 insertions(+), 34 deletions(-) diff --git a/src/Nethermind/Nethermind.Core.Test/NSubstituteExtensions.cs b/src/Nethermind/Nethermind.Core.Test/NSubstituteExtensions.cs index b629e9c71a2e..8208c9c6255a 100644 --- a/src/Nethermind/Nethermind.Core.Test/NSubstituteExtensions.cs +++ b/src/Nethermind/Nethermind.Core.Test/NSubstituteExtensions.cs @@ -13,13 +13,13 @@ namespace Nethermind.Core.Test; public static class NSubstituteExtensions { public static bool DidNotReceivedCallMatching(this T substitute, Action action) where T : class => - !substitute.ReceivedCallMatching(action, 1, int.MaxValue); + !substitute.ReceivedCallsMatching(action, 1, int.MaxValue); /// /// Checks if a substitute received matching calls without throwing exceptions. /// Suitable for polling scenarios with Is.True.After(). /// - public static bool ReceivedCallMatching(this T substitute, Action action, int requiredNumberOfCalls = 1, int maxNumberOfCalls = 1) where T : class + public static bool ReceivedCallsMatching(this T substitute, Action action, int requiredNumberOfCalls = 1, int maxNumberOfCalls = 1) where T : class { ISubstitutionContext context = SubstitutionContext.Current; ICallRouter callRouter = context.GetCallRouterFor(substitute); diff --git a/src/Nethermind/Nethermind.Network.Discovery.Test/DiscoveryManagerTests.cs b/src/Nethermind/Nethermind.Network.Discovery.Test/DiscoveryManagerTests.cs index addb0d7064a4..d5df1bd8876a 100644 --- a/src/Nethermind/Nethermind.Network.Discovery.Test/DiscoveryManagerTests.cs +++ b/src/Nethermind/Nethermind.Network.Discovery.Test/DiscoveryManagerTests.cs @@ -88,7 +88,7 @@ public async Task OnPingMessageTest() _discoveryManager.OnIncomingMsg(new PingMsg(_publicKey, GetExpirationTime(), address, _nodeTable.MasterNode!.Address, new byte[32]) { FarAddress = address }); // expecting to send pong - Assert.That(() => _msgSender.ReceivedCallMatching(s => s.SendMsg(Arg.Is(static m => m.FarAddress!.Address.ToString() == Host && m.FarAddress.Port == Port))), Is.True.After(500, 10)); + Assert.That(() => _msgSender.ReceivedCallsMatching(s => s.SendMsg(Arg.Is(static m => m.FarAddress!.Address.ToString() == Host && m.FarAddress.Port == Port))), Is.True.After(500, 10)); // send pings to new node await _msgSender.Received().SendMsg(Arg.Is(static m => m.FarAddress!.Address.ToString() == Host && m.FarAddress.Port == Port)); @@ -179,7 +179,7 @@ public async Task OnNeighborsMessageTest() _discoveryManager.OnIncomingMsg(msg); //expecting to send 3 pings to both nodes - Assert.That(() => _msgSender.ReceivedCallMatching(s => s.SendMsg(Arg.Is(m => m.FarAddress!.Address.ToString() == _nodes[0].Host && m.FarAddress.Port == _nodes[0].Port)), 3), Is.True.After(600, 10)); + Assert.That(() => _msgSender.ReceivedCallsMatching(s => s.SendMsg(Arg.Is(m => m.FarAddress!.Address.ToString() == _nodes[0].Host && m.FarAddress.Port == _nodes[0].Port)), 3), Is.True.After(600, 10)); await _msgSender.Received(3).SendMsg(Arg.Is(m => m.FarAddress!.Address.ToString() == _nodes[1].Host && m.FarAddress.Port == _nodes[1].Port)); } diff --git a/src/Nethermind/Nethermind.TxPool.Test/RetryCacheTests.cs b/src/Nethermind/Nethermind.TxPool.Test/RetryCacheTests.cs index ac96e771ea04..226e32135305 100644 --- a/src/Nethermind/Nethermind.TxPool.Test/RetryCacheTests.cs +++ b/src/Nethermind/Nethermind.TxPool.Test/RetryCacheTests.cs @@ -24,15 +24,15 @@ public class RetryCacheTests public interface ITestHandler : IMessageHandler; private CancellationTokenSource _cancellationTokenSource; - private RetryCache cache; + private RetryCache _cache; - private readonly int Timeout = 1000; + private readonly int Timeout = 5000; [SetUp] public void Setup() { _cancellationTokenSource = new CancellationTokenSource(); - cache = new(TestLogManager.Instance, timeoutMs: Timeout / 2, token: _cancellationTokenSource.Token); + _cache = new(TestLogManager.Instance, timeoutMs: Timeout / 2, token: _cancellationTokenSource.Token); } [TearDown] @@ -45,8 +45,8 @@ public void TearDown() [Test] public void Announced_SameResourceDifferentNode_ReturnsEnqueued() { - AnnounceResult result1 = cache.Announced(1, Substitute.For()); - AnnounceResult result2 = cache.Announced(1, Substitute.For()); + AnnounceResult result1 = _cache.Announced(1, Substitute.For()); + AnnounceResult result2 = _cache.Announced(1, Substitute.For()); Assert.That(result1, Is.EqualTo(AnnounceResult.New)); Assert.That(result2, Is.EqualTo(AnnounceResult.Enqueued)); @@ -58,11 +58,11 @@ public void Announced_AfterTimeout_ExecutesRetryRequests() ITestHandler request1 = Substitute.For(); ITestHandler request2 = Substitute.For(); - cache.Announced(1, request1); - cache.Announced(1, request2); + _cache.Announced(1, request1); + _cache.Announced(1, request2); Assert.That(() => request1.DidNotReceivedCallMatching(r => r.HandleMessage(Arg.Any())), Is.True.After(Timeout, 100)); - Assert.That(() => request2.ReceivedCallMatching(r => r.HandleMessage(Arg.Any())), Is.True.After(Timeout, 100)); + Assert.That(() => request2.ReceivedCallsMatching(r => r.HandleMessage(Arg.Any())), Is.True.After(Timeout, 100)); } [Test] @@ -73,24 +73,24 @@ public void Announced_MultipleResources_ExecutesAllRetryRequestsExceptInititalOn ITestHandler request3 = Substitute.For(); ITestHandler request4 = Substitute.For(); - cache.Announced(1, request1); - cache.Announced(1, request2); - cache.Announced(2, request3); - cache.Announced(2, request4); + _cache.Announced(1, request1); + _cache.Announced(1, request2); + _cache.Announced(2, request3); + _cache.Announced(2, request4); Assert.That(() => request1.DidNotReceivedCallMatching(r => r.HandleMessage(Arg.Any())), Is.True.After(Timeout, 100)); - Assert.That(() => request2.ReceivedCallMatching(r => r.HandleMessage(Arg.Any())), Is.True.After(Timeout, 100)); + Assert.That(() => request2.ReceivedCallsMatching(r => r.HandleMessage(Arg.Any())), Is.True.After(Timeout, 100)); Assert.That(() => request3.DidNotReceivedCallMatching(r => r.HandleMessage(Arg.Any())), Is.True.After(Timeout, 100)); - Assert.That(() => request4.ReceivedCallMatching(r => r.HandleMessage(Arg.Any())), Is.True.After(Timeout, 100)); + Assert.That(() => request4.ReceivedCallsMatching(r => r.HandleMessage(Arg.Any())), Is.True.After(Timeout, 100)); } [Test] public void Received_RemovesResourceFromRetryQueue() { - cache.Announced(1, Substitute.For()); - cache.Received(1); + _cache.Announced(1, Substitute.For()); + _cache.Received(1); - AnnounceResult result = cache.Announced(1, Substitute.For()); + AnnounceResult result = _cache.Announced(1, Substitute.For()); Assert.That(result, Is.EqualTo(AnnounceResult.New)); } @@ -99,9 +99,9 @@ public void Received_BeforeTimeout_PreventsRetryExecution() { ITestHandler request = Substitute.For(); - cache.Announced(1, request); - cache.Announced(1, request); - cache.Received(1); + _cache.Announced(1, request); + _cache.Announced(1, request); + _cache.Received(1); Assert.That(() => request.DidNotReceivedCallMatching(r => r.HandleMessage(ResourceRequestMessage.New(1))), Is.True.After(Timeout, 100)); } @@ -114,11 +114,11 @@ public void RetryExecution_HandlesExceptions() faultyRequest.When(x => x.HandleMessage(Arg.Any())).Do(x => throw new InvalidOperationException("Test exception")); - cache.Announced(1, Substitute.For()); - cache.Announced(1, faultyRequest); - cache.Announced(1, normalRequest); + _cache.Announced(1, Substitute.For()); + _cache.Announced(1, faultyRequest); + _cache.Announced(1, normalRequest); - Assert.That(() => normalRequest.ReceivedCallMatching(r => r.HandleMessage(ResourceRequestMessage.New(1))), Is.True.After(Timeout, 100)); + Assert.That(() => normalRequest.ReceivedCallsMatching(r => r.HandleMessage(ResourceRequestMessage.New(1))), Is.True.After(Timeout, 100)); } [Test] @@ -126,7 +126,7 @@ public void CancellationToken_StopsProcessing() { ITestHandler request = Substitute.For(); - cache.Announced(1, request); + _cache.Announced(1, request); _cancellationTokenSource.Cancel(); Assert.That(() => request.DidNotReceivedCallMatching(r => r.HandleMessage(Arg.Any())), Is.True.After(Timeout, 100)); } @@ -134,16 +134,16 @@ public void CancellationToken_StopsProcessing() [Test] public async Task Announced_AfterRetryInProgress_ReturnsNew() { - cache.Announced(1, Substitute.For()); + _cache.Announced(1, Substitute.For()); await Task.Delay(Timeout, _cancellationTokenSource.Token); - Assert.That(() => cache.Announced(1, Substitute.For()), Is.EqualTo(AnnounceResult.New).After(Timeout, 100)); + Assert.That(() => _cache.Announced(1, Substitute.For()), Is.EqualTo(AnnounceResult.New).After(Timeout, 100)); } [Test] public void Received_NonExistentResource_DoesNotThrow() { - Assert.That(() => cache.Received(999), Throws.Nothing); + Assert.That(() => _cache.Received(999), Throws.Nothing); } } diff --git a/src/Nethermind/Nethermind.TxPool.Test/TxBroadcasterTests.cs b/src/Nethermind/Nethermind.TxPool.Test/TxBroadcasterTests.cs index 599c2fc3164e..3b0cc64d2e09 100644 --- a/src/Nethermind/Nethermind.TxPool.Test/TxBroadcasterTests.cs +++ b/src/Nethermind/Nethermind.TxPool.Test/TxBroadcasterTests.cs @@ -103,7 +103,7 @@ public void should_not_broadcast_persisted_tx_to_peer_too_quickly() peer.Received(1).SendNewTransactions(Arg.Any>(), true); - Assert.That(() => peer.ReceivedCallMatching(p => p.SendNewTransactions(Arg.Any>(), true), 1), Is.True.After(1001, 10)); + Assert.That(() => peer.ReceivedCallsMatching(p => p.SendNewTransactions(Arg.Any>(), true), 1), Is.True.After(1001, 10)); _broadcaster.BroadcastPersistentTxs(); _broadcaster.BroadcastPersistentTxs(); diff --git a/src/Nethermind/Nethermind.TxPool.Test/TxPoolTests.cs b/src/Nethermind/Nethermind.TxPool.Test/TxPoolTests.cs index 60250bd91977..c432bce991fa 100644 --- a/src/Nethermind/Nethermind.TxPool.Test/TxPoolTests.cs +++ b/src/Nethermind/Nethermind.TxPool.Test/TxPoolTests.cs @@ -1137,7 +1137,7 @@ public void should_notify_peer_only_once() txPoolPeer.Id.Returns(TestItem.PublicKeyA); _txPool.AddPeer(txPoolPeer); _ = AddTransactionToPool(); - Assert.That(() => txPoolPeer.ReceivedCallMatching(p => p.SendNewTransaction(Arg.Any())), Is.True.After(500, 10)); + Assert.That(() => txPoolPeer.ReceivedCallsMatching(p => p.SendNewTransaction(Arg.Any())), Is.True.After(500, 10)); txPoolPeer.DidNotReceive().SendNewTransactions(Arg.Any>(), false); } From 01aaf53b32ace7b5a589fd97c98f2a1c44ae3d7a Mon Sep 17 00:00:00 2001 From: "lukasz.rozmej" Date: Tue, 28 Oct 2025 10:04:10 +0100 Subject: [PATCH 08/18] change --- .../P2P/Subprotocols/Eth/V62/Eth62ProtocolHandlerTests.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V62/Eth62ProtocolHandlerTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V62/Eth62ProtocolHandlerTests.cs index 87bb693219ec..6a11ede1de06 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V62/Eth62ProtocolHandlerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V62/Eth62ProtocolHandlerTests.cs @@ -617,7 +617,8 @@ public void should_send_single_transaction_even_if_exceed_MaxPacketSize(int data _handler.SendNewTransactions(txs); - _session.Received(messagesCount).DeliverMessage(Arg.Is(m => m.Transactions.Count == numberOfTxsInOneMsg || m.Transactions.Count == nonFullMsgTxsCount)); + Assert.That(() => _session.ReceivedCallsMatching(s => s.DeliverMessage(Arg.Is(m => m.Transactions.Count == numberOfTxsInOneMsg || m.Transactions.Count == nonFullMsgTxsCount)), messagesCount), Is.True.After(500)); + } private void HandleZeroMessage(T msg, int messageCode) where T : MessageBase From fdd58ac5094e5d34c515ec7e8d0e61f62078edc0 Mon Sep 17 00:00:00 2001 From: "lukasz.rozmej" Date: Tue, 28 Oct 2025 10:14:46 +0100 Subject: [PATCH 09/18] fix --- .../Nethermind.Core.Test/NSubstituteExtensions.cs | 14 +++++++++----- .../EngineModuleTests.V2.cs | 4 ++-- .../Eth/V62/Eth62ProtocolHandlerTests.cs | 2 +- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/Nethermind/Nethermind.Core.Test/NSubstituteExtensions.cs b/src/Nethermind/Nethermind.Core.Test/NSubstituteExtensions.cs index 8208c9c6255a..253eff06dac7 100644 --- a/src/Nethermind/Nethermind.Core.Test/NSubstituteExtensions.cs +++ b/src/Nethermind/Nethermind.Core.Test/NSubstituteExtensions.cs @@ -19,8 +19,10 @@ public static bool DidNotReceivedCallMatching(this T substitute, Action ac /// Checks if a substitute received matching calls without throwing exceptions. /// Suitable for polling scenarios with Is.True.After(). /// - public static bool ReceivedCallsMatching(this T substitute, Action action, int requiredNumberOfCalls = 1, int maxNumberOfCalls = 1) where T : class + public static bool ReceivedCallsMatching(this T substitute, Action action, int requiredNumberOfCalls = 1, int? maxNumberOfCalls = null) where T : class { + if (maxNumberOfCalls < requiredNumberOfCalls) throw new ArgumentException($"{nameof(maxNumberOfCalls)} must be greater than or equal to {nameof(requiredNumberOfCalls)}", nameof(maxNumberOfCalls)); + maxNumberOfCalls ??= requiredNumberOfCalls; ISubstitutionContext context = SubstitutionContext.Current; ICallRouter callRouter = context.GetCallRouterFor(substitute); @@ -33,13 +35,15 @@ public static bool ReceivedCallsMatching(this T substitute, Action action, // Use a query to check if the call was received PendingSpecificationInfo? callSpecInfo = context.ThreadContext.PendingSpecification.UseCallSpecInfo(); - return callSpecInfo?.Handle( + int? matchCount = callSpecInfo?.Handle( // Lambda 1: Handle call specification with Arg matchers - callSpec => CheckMatchCount(callRouter.ReceivedCalls().Where(callSpec.IsSatisfiedBy).Count()), + callSpec => callRouter.ReceivedCalls().Where(callSpec.IsSatisfiedBy).Count(), // Lambda 2: Handle matching with concrete argument values - expectedCall => CheckMatchCount(GetMatchCount(expectedCall))) == true; + GetMatchCount); - bool CheckMatchCount(int matchCount) => matchCount >= requiredNumberOfCalls && matchCount <= maxNumberOfCalls; + return matchCount.HasValue && CheckMatchCount(matchCount.Value); + + bool CheckMatchCount(int count) => count >= requiredNumberOfCalls && count <= maxNumberOfCalls; int GetMatchCount(ICall expectedCall) { diff --git a/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.V2.cs b/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.V2.cs index 9c2d622c88c0..91bba6a5832a 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.V2.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.V2.cs @@ -458,9 +458,9 @@ await rpc.engine_forkchoiceUpdatedV2(new ForkchoiceStateV1(executionPayload1.Blo IEnumerable payloadBodies = rpc.engine_getPayloadBodiesByRangeV1(1, 3).Result.Data; ExecutionPayloadBodyV1Result[] expected = - { + [ new(Array.Empty(), withdrawals), new(txsA, withdrawals) - }; + ]; payloadBodies.Should().BeEquivalentTo(expected, static o => o.WithStrictOrdering()); } diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V62/Eth62ProtocolHandlerTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V62/Eth62ProtocolHandlerTests.cs index 6a11ede1de06..d409db422fd2 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V62/Eth62ProtocolHandlerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V62/Eth62ProtocolHandlerTests.cs @@ -617,7 +617,7 @@ public void should_send_single_transaction_even_if_exceed_MaxPacketSize(int data _handler.SendNewTransactions(txs); - Assert.That(() => _session.ReceivedCallsMatching(s => s.DeliverMessage(Arg.Is(m => m.Transactions.Count == numberOfTxsInOneMsg || m.Transactions.Count == nonFullMsgTxsCount)), messagesCount), Is.True.After(500)); + Assert.That(() => _session.ReceivedCallsMatching(s => s.DeliverMessage(Arg.Is(m => m.Transactions.Count == numberOfTxsInOneMsg || m.Transactions.Count == nonFullMsgTxsCount)), messagesCount), Is.True.After(500, 50)); } From 7c1d37d5bbc3e940d576e9e0a997a3c5347fc9a1 Mon Sep 17 00:00:00 2001 From: "lukasz.rozmej" Date: Tue, 28 Oct 2025 10:16:42 +0100 Subject: [PATCH 10/18] whitespace --- src/Nethermind/Nethermind.Core.Test/NSubstituteExtensions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Nethermind/Nethermind.Core.Test/NSubstituteExtensions.cs b/src/Nethermind/Nethermind.Core.Test/NSubstituteExtensions.cs index 253eff06dac7..660b0612cc32 100644 --- a/src/Nethermind/Nethermind.Core.Test/NSubstituteExtensions.cs +++ b/src/Nethermind/Nethermind.Core.Test/NSubstituteExtensions.cs @@ -21,7 +21,7 @@ public static bool DidNotReceivedCallMatching(this T substitute, Action ac /// public static bool ReceivedCallsMatching(this T substitute, Action action, int requiredNumberOfCalls = 1, int? maxNumberOfCalls = null) where T : class { - if (maxNumberOfCalls < requiredNumberOfCalls) throw new ArgumentException($"{nameof(maxNumberOfCalls)} must be greater than or equal to {nameof(requiredNumberOfCalls)}", nameof(maxNumberOfCalls)); + if (maxNumberOfCalls < requiredNumberOfCalls) throw new ArgumentException($"{nameof(maxNumberOfCalls)} must be greater than or equal to {nameof(requiredNumberOfCalls)}", nameof(maxNumberOfCalls)); maxNumberOfCalls ??= requiredNumberOfCalls; ISubstitutionContext context = SubstitutionContext.Current; ICallRouter callRouter = context.GetCallRouterFor(substitute); From 8d9607181dcedf514eee0a43fdf1beb4e744b6a7 Mon Sep 17 00:00:00 2001 From: "lukasz.rozmej" Date: Tue, 28 Oct 2025 10:22:32 +0100 Subject: [PATCH 11/18] make Big_test Explicit --- .../FastSync/StateSyncFeedTests.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Nethermind/Nethermind.Synchronization.Test/FastSync/StateSyncFeedTests.cs b/src/Nethermind/Nethermind.Synchronization.Test/FastSync/StateSyncFeedTests.cs index 8c2ce8306f21..362ecd23c3e8 100644 --- a/src/Nethermind/Nethermind.Synchronization.Test/FastSync/StateSyncFeedTests.cs +++ b/src/Nethermind/Nethermind.Synchronization.Test/FastSync/StateSyncFeedTests.cs @@ -39,6 +39,7 @@ public class StateSyncFeedTests(int peerCount, int maxNodeLatency) [Test] [TestCaseSource(nameof(Scenarios))] [Repeat(TestRepeatCount)] + [Explicit("This test is not stable, especially on slow Github Actions machines")] public async Task Big_test((string Name, Action SetupTree) testCase) { DbContext dbContext = new(_logger, _logManager) From 5839fc265681a994b91d9434a6da745ba85e838a Mon Sep 17 00:00:00 2001 From: "lukasz.rozmej" Date: Tue, 28 Oct 2025 10:32:34 +0100 Subject: [PATCH 12/18] fix negative paths --- .../NSubstituteExtensions.cs | 3 --- .../Nethermind.TxPool.Test/RetryCacheTests.cs | 21 ++++++++++++------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/Nethermind/Nethermind.Core.Test/NSubstituteExtensions.cs b/src/Nethermind/Nethermind.Core.Test/NSubstituteExtensions.cs index 660b0612cc32..43f3fe6d670b 100644 --- a/src/Nethermind/Nethermind.Core.Test/NSubstituteExtensions.cs +++ b/src/Nethermind/Nethermind.Core.Test/NSubstituteExtensions.cs @@ -12,9 +12,6 @@ namespace Nethermind.Core.Test; public static class NSubstituteExtensions { - public static bool DidNotReceivedCallMatching(this T substitute, Action action) where T : class => - !substitute.ReceivedCallsMatching(action, 1, int.MaxValue); - /// /// Checks if a substitute received matching calls without throwing exceptions. /// Suitable for polling scenarios with Is.True.After(). diff --git a/src/Nethermind/Nethermind.TxPool.Test/RetryCacheTests.cs b/src/Nethermind/Nethermind.TxPool.Test/RetryCacheTests.cs index 226e32135305..87990c5ac310 100644 --- a/src/Nethermind/Nethermind.TxPool.Test/RetryCacheTests.cs +++ b/src/Nethermind/Nethermind.TxPool.Test/RetryCacheTests.cs @@ -61,8 +61,8 @@ public void Announced_AfterTimeout_ExecutesRetryRequests() _cache.Announced(1, request1); _cache.Announced(1, request2); - Assert.That(() => request1.DidNotReceivedCallMatching(r => r.HandleMessage(Arg.Any())), Is.True.After(Timeout, 100)); Assert.That(() => request2.ReceivedCallsMatching(r => r.HandleMessage(Arg.Any())), Is.True.After(Timeout, 100)); + request1.DidNotReceive().HandleMessage(Arg.Any()); } [Test] @@ -78,10 +78,10 @@ public void Announced_MultipleResources_ExecutesAllRetryRequestsExceptInititalOn _cache.Announced(2, request3); _cache.Announced(2, request4); - Assert.That(() => request1.DidNotReceivedCallMatching(r => r.HandleMessage(Arg.Any())), Is.True.After(Timeout, 100)); Assert.That(() => request2.ReceivedCallsMatching(r => r.HandleMessage(Arg.Any())), Is.True.After(Timeout, 100)); - Assert.That(() => request3.DidNotReceivedCallMatching(r => r.HandleMessage(Arg.Any())), Is.True.After(Timeout, 100)); Assert.That(() => request4.ReceivedCallsMatching(r => r.HandleMessage(Arg.Any())), Is.True.After(Timeout, 100)); + request1.DidNotReceive().HandleMessage(Arg.Any()); + request3.DidNotReceive().HandleMessage(Arg.Any()); } [Test] @@ -95,7 +95,7 @@ public void Received_RemovesResourceFromRetryQueue() } [Test] - public void Received_BeforeTimeout_PreventsRetryExecution() + public async Task Received_BeforeTimeout_PreventsRetryExecution() { ITestHandler request = Substitute.For(); @@ -103,7 +103,10 @@ public void Received_BeforeTimeout_PreventsRetryExecution() _cache.Announced(1, request); _cache.Received(1); - Assert.That(() => request.DidNotReceivedCallMatching(r => r.HandleMessage(ResourceRequestMessage.New(1))), Is.True.After(Timeout, 100)); + + await Task.Delay(Timeout, _cancellationTokenSource.Token); + + request.DidNotReceive().HandleMessage(ResourceRequestMessage.New(1)); } [Test] @@ -122,13 +125,15 @@ public void RetryExecution_HandlesExceptions() } [Test] - public void CancellationToken_StopsProcessing() + public async Task CancellationToken_StopsProcessing() { ITestHandler request = Substitute.For(); _cache.Announced(1, request); - _cancellationTokenSource.Cancel(); - Assert.That(() => request.DidNotReceivedCallMatching(r => r.HandleMessage(Arg.Any())), Is.True.After(Timeout, 100)); + await _cancellationTokenSource.CancelAsync(); + await Task.Delay(Timeout); + + request.DidNotReceive().HandleMessage(Arg.Any()); } [Test] From b077f10027325dafd0a14dde66c96e77c50a0cd2 Mon Sep 17 00:00:00 2001 From: "lukasz.rozmej" Date: Tue, 28 Oct 2025 11:01:25 +0100 Subject: [PATCH 13/18] revert one test --- .../NSubstituteExtensions.cs | 18 ++++++++++++++++-- .../TxBroadcasterTests.cs | 6 ++++-- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/Nethermind/Nethermind.Core.Test/NSubstituteExtensions.cs b/src/Nethermind/Nethermind.Core.Test/NSubstituteExtensions.cs index 43f3fe6d670b..6ae1ea5cde00 100644 --- a/src/Nethermind/Nethermind.Core.Test/NSubstituteExtensions.cs +++ b/src/Nethermind/Nethermind.Core.Test/NSubstituteExtensions.cs @@ -5,8 +5,10 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; +using System.Runtime.CompilerServices; using NSubstitute; using NSubstitute.Core; +using NUnit.Framework; namespace Nethermind.Core.Test; @@ -16,7 +18,12 @@ public static class NSubstituteExtensions /// Checks if a substitute received matching calls without throwing exceptions. /// Suitable for polling scenarios with Is.True.After(). /// - public static bool ReceivedCallsMatching(this T substitute, Action action, int requiredNumberOfCalls = 1, int? maxNumberOfCalls = null) where T : class + public static bool ReceivedCallsMatching( + this T substitute, + Action action, + int requiredNumberOfCalls = 1, + int? maxNumberOfCalls = null, + [CallerArgumentExpression(nameof(action))] string? expression = null) where T : class { if (maxNumberOfCalls < requiredNumberOfCalls) throw new ArgumentException($"{nameof(maxNumberOfCalls)} must be greater than or equal to {nameof(requiredNumberOfCalls)}", nameof(maxNumberOfCalls)); maxNumberOfCalls ??= requiredNumberOfCalls; @@ -38,7 +45,14 @@ public static bool ReceivedCallsMatching(this T substitute, Action action, // Lambda 2: Handle matching with concrete argument values GetMatchCount); - return matchCount.HasValue && CheckMatchCount(matchCount.Value); + bool check = matchCount.HasValue && CheckMatchCount(matchCount.Value); + if (!check) + { + TestContext.Out.WriteLine(requiredNumberOfCalls == maxNumberOfCalls + ? $"Expected ({expression}) to receive calls matching {requiredNumberOfCalls} calls, but actually got {matchCount} calls." + : $"Expected ({expression}) to receive calls matching between {requiredNumberOfCalls} and {maxNumberOfCalls} calls, but actually got {matchCount} calls."); + } + return check; bool CheckMatchCount(int count) => count >= requiredNumberOfCalls && count <= maxNumberOfCalls; diff --git a/src/Nethermind/Nethermind.TxPool.Test/TxBroadcasterTests.cs b/src/Nethermind/Nethermind.TxPool.Test/TxBroadcasterTests.cs index 3b0cc64d2e09..3c575ea5f35e 100644 --- a/src/Nethermind/Nethermind.TxPool.Test/TxBroadcasterTests.cs +++ b/src/Nethermind/Nethermind.TxPool.Test/TxBroadcasterTests.cs @@ -67,7 +67,7 @@ public void Setup() public void TearDown() => _broadcaster?.Dispose(); [Test] - public void should_not_broadcast_persisted_tx_to_peer_too_quickly() + public async Task should_not_broadcast_persisted_tx_to_peer_too_quickly() { _txPoolConfig = new TxPoolConfig() { PeerNotificationThreshold = 100 }; _broadcaster = new TxBroadcaster(_comparer, TimerFactory.Default, _txPoolConfig, _headInfo, _logManager); @@ -103,7 +103,9 @@ public void should_not_broadcast_persisted_tx_to_peer_too_quickly() peer.Received(1).SendNewTransactions(Arg.Any>(), true); - Assert.That(() => peer.ReceivedCallsMatching(p => p.SendNewTransactions(Arg.Any>(), true), 1), Is.True.After(1001, 10)); + await Task.Delay(TimeSpan.FromMilliseconds(1001)); + + peer.Received(1).SendNewTransactions(Arg.Any>(), true); _broadcaster.BroadcastPersistentTxs(); _broadcaster.BroadcastPersistentTxs(); From 0d7c919f0234dfae243eb50b1bacedd62314a0cf Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 29 Oct 2025 08:21:38 +0000 Subject: [PATCH 14/18] Revert inappropriate After() conversions for blocking tests Co-authored-by: asdacap <1841324+asdacap@users.noreply.github.com> --- ...lockProducerBaseTests.IsProducingBlocks.cs | 3 ++- .../Collections/ConcurrentDictionaryTests.cs | 3 ++- .../Events/WaitForEventTests.cs | 19 ++++++++++++------- .../TraceStorePrunerTests.cs | 5 +++-- 4 files changed, 19 insertions(+), 11 deletions(-) diff --git a/src/Nethermind/Nethermind.Blockchain.Test/Producers/BlockProducerBaseTests.IsProducingBlocks.cs b/src/Nethermind/Nethermind.Blockchain.Test/Producers/BlockProducerBaseTests.IsProducingBlocks.cs index cc5d5b62c8fd..1470ec994713 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/Producers/BlockProducerBaseTests.IsProducingBlocks.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/Producers/BlockProducerBaseTests.IsProducingBlocks.cs @@ -188,7 +188,8 @@ private async Task AssertIsProducingBlocks(IBlockProducerRunner blockProducer) Assert.That(blockProducer.IsProducingBlocks(null), Is.EqualTo(false)); blockProducer.Start(); Assert.That(blockProducer.IsProducingBlocks(null), Is.EqualTo(true)); - Assert.That(() => blockProducer.IsProducingBlocks(1), Is.EqualTo(false).After(5000, 100)); + Thread.Sleep(5000); + Assert.That(blockProducer.IsProducingBlocks(1), Is.EqualTo(false)); Assert.That(blockProducer.IsProducingBlocks(1000), Is.EqualTo(true)); Assert.That(blockProducer.IsProducingBlocks(null), Is.EqualTo(true)); await blockProducer.StopAsync(); diff --git a/src/Nethermind/Nethermind.Core.Test/Collections/ConcurrentDictionaryTests.cs b/src/Nethermind/Nethermind.Core.Test/Collections/ConcurrentDictionaryTests.cs index 4088ca6273ca..d4cc7fee4ac6 100644 --- a/src/Nethermind/Nethermind.Core.Test/Collections/ConcurrentDictionaryTests.cs +++ b/src/Nethermind/Nethermind.Core.Test/Collections/ConcurrentDictionaryTests.cs @@ -20,7 +20,8 @@ public void Locks() using (dictionary.AcquireLock()) { updateTask = Task.Run(() => dictionary[3] = 3); - Assert.That(() => updateTask.IsCompleted, Is.False.After(100, 10)); + Task.WaitAny(updateTask, Task.Delay(100)); + updateTask.IsCompleted.Should().BeFalse(); dictionary.ContainsKey(3).Should().BeFalse(); } diff --git a/src/Nethermind/Nethermind.Core.Test/Events/WaitForEventTests.cs b/src/Nethermind/Nethermind.Core.Test/Events/WaitForEventTests.cs index aee7e330f168..e54b86b2533f 100644 --- a/src/Nethermind/Nethermind.Core.Test/Events/WaitForEventTests.cs +++ b/src/Nethermind/Nethermind.Core.Test/Events/WaitForEventTests.cs @@ -15,7 +15,7 @@ public class WaitForEventTests { [Test] - public void Test_WaitForEvent() + public async Task Test_WaitForEvent() { ITestObj stubObj = Substitute.For(); @@ -31,21 +31,24 @@ public void Test_WaitForEvent() return cond; }); - Assert.That(() => awaitingEvent.IsCompleted, Is.False.After(100, 10)); + await Task.Delay(100); + awaitingEvent.IsCompleted.Should().BeFalse(); condCalled.Should().BeFalse(); stubObj.TestEvent += Raise.Event>(this, false); condCalled.Should().BeTrue(); - Assert.That(() => awaitingEvent.IsCompleted, Is.False.After(100, 10)); + await Task.Delay(100); + awaitingEvent.IsCompleted.Should().BeFalse(); stubObj.TestEvent += Raise.Event>(this, true); - Assert.That(() => awaitingEvent.IsCompleted, Is.True.After(100, 10)); + await Task.Delay(100); + awaitingEvent.IsCompleted.Should().BeTrue(); } [Test] - public void Test_WaitForEvent_Cancelled() + public async Task Test_WaitForEvent_Cancelled() { ITestObj stubObj = Substitute.For(); @@ -56,11 +59,13 @@ public void Test_WaitForEvent_Cancelled() (e) => stubObj.TestEvent -= e, (cond) => cond); - Assert.That(() => awaitingEvent.IsCompleted, Is.False.After(100, 10)); + await Task.Delay(100); + awaitingEvent.IsCompleted.Should().BeFalse(); cts.Cancel(); - Assert.That(() => awaitingEvent.IsCanceled, Is.True.After(100, 10)); + await Task.Delay(100); + awaitingEvent.IsCanceled.Should().BeTrue(); } public interface ITestObj diff --git a/src/Nethermind/Nethermind.JsonRpc.TraceStore.Test/TraceStorePrunerTests.cs b/src/Nethermind/Nethermind.JsonRpc.TraceStore.Test/TraceStorePrunerTests.cs index efdbfb591e47..a569b635488a 100644 --- a/src/Nethermind/Nethermind.JsonRpc.TraceStore.Test/TraceStorePrunerTests.cs +++ b/src/Nethermind/Nethermind.JsonRpc.TraceStore.Test/TraceStorePrunerTests.cs @@ -21,7 +21,7 @@ namespace Nethermind.JsonRpc.TraceStore.Tests; public class TraceStorePrunerTests { [Test] - public void prunes_old_blocks() + public async Task prunes_old_blocks() { IEnumerable GenerateTraces(MemDb db, BlockTree tree) { @@ -60,7 +60,8 @@ void AddNewBlocks(BlockTree tree) List keys = GenerateTraces(memDb, blockTree).ToList(); keys.Select(k => memDb.Get(k)).Should().NotContain((byte[]?)null); AddNewBlocks(blockTree); - Assert.That(() => keys.Skip(3).Select(k => memDb.Get(k)), Does.Not.Contain((byte[]?)null).After(100, 10)); // too old were not removed + await Task.Delay(100); + keys.Skip(3).Select(k => memDb.Get(k)).Should().NotContain((byte[]?)null); // too old were not removed keys.Take(3).Select(k => memDb.Get(k)).Should().OnlyContain(b => b == null); // those were removed } From 127c3cd50551270cb979f409e91cc90327585ee6 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 29 Oct 2025 13:08:41 +0000 Subject: [PATCH 15/18] Remove redundant diagnostic messages from ReceivedCallsMatching Co-authored-by: flcl42 <630501+flcl42@users.noreply.github.com> --- .../Nethermind.Core.Test/NSubstituteExtensions.cs | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/Nethermind/Nethermind.Core.Test/NSubstituteExtensions.cs b/src/Nethermind/Nethermind.Core.Test/NSubstituteExtensions.cs index 6ae1ea5cde00..d9cb360ea08f 100644 --- a/src/Nethermind/Nethermind.Core.Test/NSubstituteExtensions.cs +++ b/src/Nethermind/Nethermind.Core.Test/NSubstituteExtensions.cs @@ -45,14 +45,7 @@ public static bool ReceivedCallsMatching( // Lambda 2: Handle matching with concrete argument values GetMatchCount); - bool check = matchCount.HasValue && CheckMatchCount(matchCount.Value); - if (!check) - { - TestContext.Out.WriteLine(requiredNumberOfCalls == maxNumberOfCalls - ? $"Expected ({expression}) to receive calls matching {requiredNumberOfCalls} calls, but actually got {matchCount} calls." - : $"Expected ({expression}) to receive calls matching between {requiredNumberOfCalls} and {maxNumberOfCalls} calls, but actually got {matchCount} calls."); - } - return check; + return matchCount.HasValue && CheckMatchCount(matchCount.Value); bool CheckMatchCount(int count) => count >= requiredNumberOfCalls && count <= maxNumberOfCalls; From d023a562e5dbf7f38a3992eec730451ca5c72595 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 29 Oct 2025 13:32:47 +0000 Subject: [PATCH 16/18] Display diagnostic message only once per test when ReceivedCallsMatching fails Co-authored-by: LukaszRozmej <12445221+LukaszRozmej@users.noreply.github.com> --- .../NSubstituteExtensions.cs | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/Nethermind/Nethermind.Core.Test/NSubstituteExtensions.cs b/src/Nethermind/Nethermind.Core.Test/NSubstituteExtensions.cs index d9cb360ea08f..cdfee24758a3 100644 --- a/src/Nethermind/Nethermind.Core.Test/NSubstituteExtensions.cs +++ b/src/Nethermind/Nethermind.Core.Test/NSubstituteExtensions.cs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LGPL-3.0-only using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Reflection; @@ -14,6 +15,8 @@ namespace Nethermind.Core.Test; public static class NSubstituteExtensions { + private static readonly ConcurrentDictionary _loggedMessages = new(); + /// /// Checks if a substitute received matching calls without throwing exceptions. /// Suitable for polling scenarios with Is.True.After(). @@ -45,7 +48,21 @@ public static bool ReceivedCallsMatching( // Lambda 2: Handle matching with concrete argument values GetMatchCount); - return matchCount.HasValue && CheckMatchCount(matchCount.Value); + bool check = matchCount.HasValue && CheckMatchCount(matchCount.Value); + + // Log diagnostic message only once per unique check when it fails + if (!check) + { + string logKey = $"{TestContext.CurrentContext.Test.ID}_{expression}_{requiredNumberOfCalls}_{maxNumberOfCalls}"; + if (_loggedMessages.TryAdd(logKey, true)) + { + TestContext.Out.WriteLine(requiredNumberOfCalls == maxNumberOfCalls + ? $"Expected ({expression}) to receive calls matching {requiredNumberOfCalls} calls, but actually got {matchCount} calls." + : $"Expected ({expression}) to receive calls matching between {requiredNumberOfCalls} and {maxNumberOfCalls} calls, but actually got {matchCount} calls."); + } + } + + return check; bool CheckMatchCount(int count) => count >= requiredNumberOfCalls && count <= maxNumberOfCalls; From 60bdf3b70ed7d4afe44b0f7f433c20e3ff814abf Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 29 Oct 2025 13:56:52 +0000 Subject: [PATCH 17/18] Remove diagnostic logging from ReceivedCallsMatching to avoid issues Co-authored-by: LukaszRozmej <12445221+LukaszRozmej@users.noreply.github.com> --- .../NSubstituteExtensions.cs | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/src/Nethermind/Nethermind.Core.Test/NSubstituteExtensions.cs b/src/Nethermind/Nethermind.Core.Test/NSubstituteExtensions.cs index cdfee24758a3..d9cb360ea08f 100644 --- a/src/Nethermind/Nethermind.Core.Test/NSubstituteExtensions.cs +++ b/src/Nethermind/Nethermind.Core.Test/NSubstituteExtensions.cs @@ -2,7 +2,6 @@ // SPDX-License-Identifier: LGPL-3.0-only using System; -using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Reflection; @@ -15,8 +14,6 @@ namespace Nethermind.Core.Test; public static class NSubstituteExtensions { - private static readonly ConcurrentDictionary _loggedMessages = new(); - /// /// Checks if a substitute received matching calls without throwing exceptions. /// Suitable for polling scenarios with Is.True.After(). @@ -48,21 +45,7 @@ public static bool ReceivedCallsMatching( // Lambda 2: Handle matching with concrete argument values GetMatchCount); - bool check = matchCount.HasValue && CheckMatchCount(matchCount.Value); - - // Log diagnostic message only once per unique check when it fails - if (!check) - { - string logKey = $"{TestContext.CurrentContext.Test.ID}_{expression}_{requiredNumberOfCalls}_{maxNumberOfCalls}"; - if (_loggedMessages.TryAdd(logKey, true)) - { - TestContext.Out.WriteLine(requiredNumberOfCalls == maxNumberOfCalls - ? $"Expected ({expression}) to receive calls matching {requiredNumberOfCalls} calls, but actually got {matchCount} calls." - : $"Expected ({expression}) to receive calls matching between {requiredNumberOfCalls} and {maxNumberOfCalls} calls, but actually got {matchCount} calls."); - } - } - - return check; + return matchCount.HasValue && CheckMatchCount(matchCount.Value); bool CheckMatchCount(int count) => count >= requiredNumberOfCalls && count <= maxNumberOfCalls; From 55c5a926323096c0da0dd242b60d4144e7f0489e Mon Sep 17 00:00:00 2001 From: "lukasz.rozmej" Date: Wed, 29 Oct 2025 20:44:25 +0100 Subject: [PATCH 18/18] remove stale annotation --- .../Nethermind.Evm.Test/Tracing/CancellationTracerTests.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Nethermind/Nethermind.Evm.Test/Tracing/CancellationTracerTests.cs b/src/Nethermind/Nethermind.Evm.Test/Tracing/CancellationTracerTests.cs index 5e1281aeecf5..03cc9cd3dc92 100644 --- a/src/Nethermind/Nethermind.Evm.Test/Tracing/CancellationTracerTests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/Tracing/CancellationTracerTests.cs @@ -25,7 +25,6 @@ public void Throw_operation_canceled_after_given_timeout() CancellationToken cancellationToken = cancellationTokenSource.Token; CancellationTxTracer tracer = new(Substitute.For(), cancellationToken) { IsTracingActions = true }; - // ReSharper disable once MethodSupportsCancellation Assert.That(() => tracer.ReportActionError(EvmExceptionType.None), Throws.TypeOf().After(100, 10)); }