Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,7 @@ public async Task should_trigger_block_production_when_queue_empties()
context.BlockProcessingQueue.IsEmpty.Returns(false);
Task<Block?> 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;
Expand All @@ -52,8 +51,7 @@ public async Task should_cancel_triggering_block_production()
using CancellationTokenSource cancellationTokenSource = new();
Task<Block?> 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();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand All @@ -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<ICall> 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]
Expand All @@ -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]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
76 changes: 56 additions & 20 deletions src/Nethermind/Nethermind.Core.Test/NSubstituteExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,71 @@
// SPDX-License-Identifier: LGPL-3.0-only

using System;
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;

public static class NSubstituteExtensions
{
public static bool ReceivedBool<T>(this T substitute, Action<T> action, int requiredNumberOfCalls = 1) where T : class
/// <summary>
/// Checks if a substitute received matching calls without throwing exceptions.
/// Suitable for polling scenarios with Is.True.After().
/// </summary>
public static bool ReceivedCallsMatching<T>(
this T substitute,
Action<T> action,
int requiredNumberOfCalls = 1,
int? maxNumberOfCalls = null,
[CallerArgumentExpression(nameof(action))] string? expression = null) where T : class
{
try
{
action(substitute.Received(requiredNumberOfCalls));
return true;
}
catch
{
return false;
}
}
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);

public static bool DidNotReceiveBool<T>(this T substitute, Action<T> action) where T : class
{
try
{
action(substitute.DidNotReceive());
return true;
}
catch
// 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();
int? matchCount = callSpecInfo?.Handle(
// Lambda 1: Handle call specification with Arg matchers
callSpec => callRouter.ReceivedCalls().Where(callSpec.IsSatisfiedBy).Count(),
// Lambda 2: Handle matching with concrete argument values
GetMatchCount);

return matchCount.HasValue && CheckMatchCount(matchCount.Value);

bool CheckMatchCount(int count) => count >= requiredNumberOfCalls && count <= maxNumberOfCalls;

int GetMatchCount(ICall expectedCall)
{
return false;
IEnumerable<ICall> 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;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,14 @@ 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);
CancellationToken cancellationToken = cancellationTokenSource.Token;
CancellationTxTracer tracer = new(Substitute.For<ITxTracer>(), cancellationToken) { IsTracingActions = true };

// ReSharper disable once MethodSupportsCancellation
await Task.Delay(100);

Assert.Throws<OperationCanceledException>(() => tracer.ReportActionError(EvmExceptionType.None));
Assert.That(() => tracer.ReportActionError(EvmExceptionType.None), Throws.TypeOf<OperationCanceledException>().After(100, 10));
}

[Test]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -458,9 +458,9 @@ await rpc.engine_forkchoiceUpdatedV2(new ForkchoiceStateV1(executionPayload1.Blo
IEnumerable<ExecutionPayloadBodyV1Result?> payloadBodies =
rpc.engine_getPayloadBodiesByRangeV1(1, 3).Result.Data;
ExecutionPayloadBodyV1Result[] expected =
{
[
new(Array.Empty<Transaction>(), withdrawals), new(txsA, withdrawals)
};
];

payloadBodies.Should().BeEquivalentTo(expected, static o => o.WithStrictOrdering());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -85,10 +86,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<PongMsg>(static m => m.FarAddress!.Address.ToString() == Host && m.FarAddress.Port == Port));
Assert.That(() => _msgSender.ReceivedCallsMatching(s => s.SendMsg(Arg.Is<PongMsg>(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<PingMsg>(static m => m.FarAddress!.Address.ToString() == Host && m.FarAddress.Port == Port));
Expand Down Expand Up @@ -179,8 +179,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<PingMsg>(m => m.FarAddress!.Address.ToString() == _nodes[0].Host && m.FarAddress.Port == _nodes[0].Port));
Assert.That(() => _msgSender.ReceivedCallsMatching(s => s.SendMsg(Arg.Is<PingMsg>(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<PingMsg>(m => m.FarAddress!.Address.ToString() == _nodes[1].Host && m.FarAddress.Port == _nodes[1].Port));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<TransactionsMessage>(m => m.Transactions.Count == numberOfTxsInOneMsg || m.Transactions.Count == nonFullMsgTxsCount));
Assert.That(() => _session.ReceivedCallsMatching(s => s.DeliverMessage(Arg.Is<TransactionsMessage>(m => m.Transactions.Count == numberOfTxsInOneMsg || m.Transactions.Count == nonFullMsgTxsCount)), messagesCount), Is.True.After(500, 50));

}

private void HandleZeroMessage<T>(T msg, int messageCode) where T : MessageBase
Expand Down
21 changes: 7 additions & 14 deletions src/Nethermind/Nethermind.Network.Test/PeerManagerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down Expand Up @@ -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)]
Expand Down Expand Up @@ -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));
}
}

Expand Down Expand Up @@ -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;
Expand All @@ -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));
}
}

Expand Down Expand Up @@ -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)]
Expand Down Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<StateTree, ITrieStore, IDb> SetupTree) testCase)
{
DbContext dbContext = new(_logger, _logManager)
Expand Down
Loading