public async Task CompleteWithCrashingPeers() { ImmutableArray <Block <DumbAction> > fixture = GenerateBlocks <DumbAction>(15).ToImmutableArray(); var bc = new BlockCompletion <char, DumbAction>(_ => false, 5); bc.Demand(fixture.Select(b => b.Hash)); BlockCompletion <char, DumbAction> .BlockFetcher blockFetcher = (peer, blockHashes, token) => new AsyncEnumerable <Block <DumbAction> >(async yield => { // Peer A does crash and Peer B does respond. if (peer == 'A') { throw new Exception("Peer A can't respond."); } foreach (Block <DumbAction> b in fixture) { if (blockHashes.Contains(b.Hash)) { await yield.ReturnAsync(b); } } }); Tuple <Block <DumbAction>, char>[] result = await AsyncEnumerable.ToArrayAsync(bc.Complete(new[] { 'A', 'B' }, blockFetcher)); Assert.Equal( fixture.Select(b => Tuple.Create(b, 'B')).ToHashSet(), result.ToHashSet() ); }
public async Task CompleteWithBlockFetcherGivingWrongBlocks() { Block <DumbAction> genesis = TestUtils.MineGenesis <DumbAction>(), demand = TestUtils.MineNext(genesis), wrong = TestUtils.MineNext(genesis); _logger.Debug("Genesis: #{Index} {Hash}", genesis.Index, genesis.Hash); _logger.Debug("Demand: #{Index} {Hash}", demand.Index, demand.Hash); _logger.Debug("Wrong: #{Index} {Hash}", wrong.Index, wrong.Hash); var bc = new BlockCompletion <char, DumbAction>( ((IEquatable <HashDigest <SHA256> >)genesis.Hash).Equals, 5 ); bc.Demand(demand.Hash); long counter = 0; BlockCompletion <char, DumbAction> .BlockFetcher wrongBlockFetcher = (peer, blockHashes, token) => new AsyncEnumerable <Block <DumbAction> >(async yield => { // Provides a wrong block (i.e., not corresponding to the demand) at first call, // and then provide a proper block later calls. await yield.ReturnAsync(Interlocked.Read(ref counter) < 1 ? wrong : demand); Interlocked.Increment(ref counter); }); Tuple <Block <DumbAction>, char>[] result = await AsyncEnumerable.ToArrayAsync(bc.Complete(new[] { 'A' }, wrongBlockFetcher)); Assert.Equal(new[] { Tuple.Create(demand, 'A') }, result); }
public async Task CompleteWithNonRespondingPeers() { ImmutableArray <Block <DumbAction> > fixture = GenerateBlocks <DumbAction>(15).ToImmutableArray(); var bc = new BlockCompletion <char, DumbAction>(_ => false, 5); bc.Demand(fixture.Select(b => b.Hash)); BlockCompletion <char, DumbAction> .BlockFetcher blockFetcher = (peer, blockHashes, token) => new AsyncEnumerable <Block <DumbAction> >(async yield => { // Peer A does not respond and Peer B does respond. if (peer == 'A') { while (true) { await Task.Delay(5000, yield.CancellationToken); } } foreach (Block <DumbAction> b in fixture) { if (blockHashes.Contains(b.Hash)) { await yield.ReturnAsync(b); } } }); Tuple <Block <DumbAction>, char>[] result = await AsyncEnumerable.ToArrayAsync( bc.Complete( new[] { 'A', 'B' }, blockFetcher, millisecondsSingleSessionTimeout: 3000 ) ); Assert.Equal( fixture.Select(b => Tuple.Create(b, 'B')).ToHashSet(), result.ToHashSet() ); }
public static ValueTask <TSource[]> ToArrayAsync <TSource>(this IAsyncEnumerable <TSource> source) => LinqEnumerable.ToArrayAsync(source);