Fix SmartBlockProvider test
MODIFY
WalletWasabi.Tests/UnitTests/SmartBlockProviderTests.cs
WalletWasabi.Tests/UnitTests/SmartBlockProviderTests.cs
using Microsoft.Extensions.Caching.Memory;
+using Moq;
using NBitcoin;
using System.Collections.Generic;
using System.Threading;
@@ -10,38 +11,55 @@ namespace WalletWasabi.Tests.UnitTests;
public class SmartBlockProviderTests
{
- /*
/// <summary>
/// Tests <see cref="SmartBlockProvider.GetBlockAsync(uint256, CancellationToken)"/> behavior.
/// </summary>
[Fact]
- public async void TestAsync()
+ public async void GettingBlocksFromP2pTestAsync()
{
- var blocks = new Dictionary<uint256, Block>
+ using CancellationTokenSource testDeadlineCts = new(TimeSpan.FromMinutes(1));
+
+ // Dummy block repository that does not gets (or stores) anything from the file-storage.
+ Mock<IRepository<uint256, Block>> mockBlockRepository = new(MockBehavior.Strict);
+ _ = mockBlockRepository.Setup(c => c.TryGetAsync(It.IsAny<uint256>(), It.IsAny<CancellationToken>()))
+ .ReturnsAsync((Block?)null);
+ _ = mockBlockRepository.Setup(c => c.SaveAsync(It.IsAny<Block>(), It.IsAny<CancellationToken>()))
+ .Returns(Task.CompletedTask);
+
+ // Local block provider returns nothing. Simulate that it's not enabled.
+ Mock<IBlockProvider> mockLocalBlockProvider = new(MockBehavior.Strict);
+ _ = mockLocalBlockProvider.Setup(c => c.TryGetBlockAsync(It.IsAny<uint256>(), It.IsAny<CancellationToken>()))
+ .ReturnsAsync((Block?)null);
+
+ // P2P block provider with predefined blocks.
+ Dictionary<uint256, Block> blocks = new()
{
[uint256.Zero] = Network.Main.Consensus.ConsensusFactory.CreateBlock(),
[uint256.One] = Network.Main.Consensus.ConsensusFactory.CreateBlock(),
};
- var blockProvider = new TestBlockProvider(blocks);
- using var cache = new MemoryCache(new MemoryCacheOptions());
- var smartBlockProvider = new SmartBlockProvider(blockProvider, cache);
+ TestBlockProvider p2PBlockProvider = new(blocks);
+
+ using MemoryCache cache = new(new MemoryCacheOptions());
+ IBlockProvider smartBlockProvider = new SmartBlockProvider(
+ mockBlockRepository.Object,
+ localBlockProvider: mockLocalBlockProvider.Object,
+ p2PBlockProvider: p2PBlockProvider,
+ cache);
- Task<Block> b0 = smartBlockProvider.GetBlockAsync(uint256.Zero, CancellationToken.None);
- Task<Block> b1 = smartBlockProvider.GetBlockAsync(uint256.One, CancellationToken.None);
- Task<Block> b2 = smartBlockProvider.GetBlockAsync(uint256.Zero, CancellationToken.None);
+ Task<Block> b0 = smartBlockProvider.GetBlockAsync(uint256.Zero, testDeadlineCts.Token);
+ Task<Block> b1 = smartBlockProvider.GetBlockAsync(uint256.One, testDeadlineCts.Token);
+ Task<Block> b2 = smartBlockProvider.GetBlockAsync(uint256.Zero, testDeadlineCts.Token);
// Wait for all blocks to be fetched.
- Block[] result = await Task.WhenAll(b0, b1, b2);
+ Block[] result = await Task.WhenAll(b0, b1, b2).WaitAsync(testDeadlineCts.Token);
- // We assert here that SmartBlockProvider used internal BlockProvider to get blocks
- // and that those blocks correspond to expected blocks.
- Assert.Equal(blocks[0], result[0]);
- Assert.Equal(blocks[0], result[2]);
+ // Assert that SmartBlockProvider uses an internal block provider to get blocks and that those blocks correspond to expected blocks.
+ Assert.Same(blocks[0], result[0]);
+ Assert.Same(blocks[0], result[2]);
- Assert.NotEqual(blocks[0], result[1]);
+ Assert.NotSame(blocks[0], result[1]);
}
- */
}
file class TestBlockProvider : IBlockProvider

MODIFY
WalletWasabi/Wallets/SmartBlockProvider.cs
WalletWasabi/Wallets/SmartBlockProvider.cs
using Microsoft.Extensions.Caching.Memory;
using NBitcoin;
+using System.Diagnostics.CodeAnalysis;
using System.Threading;
using System.Threading.Tasks;
using WalletWasabi.Cache;
@@ -17,16 +18,28 @@ public class SmartBlockProvider : IBlockProvider
SlidingExpiration = TimeSpan.FromSeconds(5)
};
+ [SuppressMessage("Style", "IDE0004:Remove Unnecessary Cast", Justification = "The cast is necessary to call the other constructor.")]
public SmartBlockProvider(IRepository<uint256, Block> blockRepository, LocalBlockProvider localBlockProvider, P2pBlockProvider p2PBlockProvider, IMemoryCache cache)
+ : this(blockRepository, (IBlockProvider)localBlockProvider, (IBlockProvider)p2PBlockProvider, cache)
+ {
+ }
+
+ /// <summary>
+ /// For testing.
+ /// </summary>
+ internal SmartBlockProvider(IRepository<uint256, Block> blockRepository, IBlockProvider localBlockProvider, IBlockProvider p2PBlockProvider, IMemoryCache cache)
{
BlockRepository = blockRepository;
- P2PBlockProvider = p2PBlockProvider;
- LocalBlockProvider = localBlockProvider;
+ P2PProvider = p2PBlockProvider;
+ LocalProvider = localBlockProvider;
Cache = new(cache);
}
- private LocalBlockProvider LocalBlockProvider { get; }
- private P2pBlockProvider P2PBlockProvider { get; }
+ /// <seealso cref="LocalBlockProvider"/>
+ private IBlockProvider LocalProvider { get; }
+
+ /// <seealso cref="P2pBlockProvider"/>
+ private IBlockProvider P2PProvider { get; }
private IdempotencyRequestCache Cache { get; }
private IRepository<uint256, Block> BlockRepository { get; }
@@ -68,8 +81,8 @@ public class SmartBlockProvider : IBlockProvider
/// <remarks>First ask the local block provider (which may or may not be set up) and use the P2P block provider as a fallback.</remarks>
private async Task<Block?> GetBlockNoCacheAsync(uint256 blockHash, CancellationToken cancellationToken)
{
- return await LocalBlockProvider.TryGetBlockAsync(blockHash, cancellationToken).ConfigureAwait(false)
- ?? await P2PBlockProvider.TryGetBlockAsync(blockHash, cancellationToken).ConfigureAwait(false);
+ return await LocalProvider.TryGetBlockAsync(blockHash, cancellationToken).ConfigureAwait(false)
+ ?? await P2PProvider.TryGetBlockAsync(blockHash, cancellationToken).ConfigureAwait(false);
}
/// <summary>

Fix SmartBlockProvider test