public void Default_EnumeratorMembers_Throws()
 {
     ConfiguredCancelableAsyncEnumerable <int> .Enumerator e = default;
     Assert.Throws <NullReferenceException>(() => e.MoveNextAsync());
     Assert.Throws <NullReferenceException>(() => e.Current);
     Assert.Throws <NullReferenceException>(() => e.DisposeAsync());
 }
Exemple #2
0
        /// <summary>
        ///   Performs the tasks needed to initialize and set up the environment for an instance
        ///   of the test scenario.  When multiple instances are run in parallel, setup will be
        ///   run once for each prior to its execution.
        /// </summary>
        ///
        public async override Task SetupAsync()
        {
            await base.SetupAsync();

            // Attempt to take a consumer group from the available set; to ensure that the
            // test scenario can support the requested level of parallelism without violating
            // the concurrent reader limits of a consumer group, the default consumer group
            // should not be used.

            if (!ConsumerGroups.TryDequeue(out var consumerGroup))
            {
                throw new InvalidOperationException("Unable to reserve a consumer group to read from.");
            }

            _consumer = new EventHubConsumerClient(consumerGroup, TestEnvironment.EventHubsConnectionString, Scope.EventHubName);

            // In order to allow reading across multiple iterations, capture an enumerator.  Without using a consistent
            // enumerator, a new AMQP link would be created and the position reset each time RunAsync was invoked.

            _readEnumerator = _consumer
                              .ReadEventsFromPartitionAsync(PartitionId, EventPosition.Earliest)
                              .ConfigureAwait(false)
                              .GetAsyncEnumerator();

            // Force the connection and link creation by reading a single event.

            if (!(await _readEnumerator.MoveNextAsync()))
            {
                throw new InvalidOperationException("Unable to read from the partition.");
            }
        }
        public void Default_GetAsyncEnumerator_Throws()
        {
            ConfiguredCancelableAsyncEnumerable <int> e = default;

            Assert.Throws <NullReferenceException>(() => e.GetAsyncEnumerator());

            e = ((IAsyncEnumerable <int>)null).ConfigureAwait(false);
            Assert.Throws <NullReferenceException>(() => e.GetAsyncEnumerator());
        }
Exemple #4
0
 public AsyncEnumerableCollection(
     IAsyncEnumerable <T> valueEnumerable,
     CancellationToken cancellation = default)
 {
     _enumerator = valueEnumerable
                   .ConfigureAwait(true)
                   .WithCancellation(cancellation)
                   .GetAsyncEnumerator();
 }
Exemple #5
0
    public async IAsyncEnumerable <(string, object)> GetPendingNotifications([EnumeratorCancellation] CancellationToken ct)
    {
        ConfiguredCancelableAsyncEnumerable <NotificationBase> notifications = _service.GetPendingNotifications(uint.Parse(Context.UserIdentifier))
                                                                               .AsNoTracking()
                                                                               .AsAsyncEnumerable()
                                                                               .WithCancellation(ct);

        await foreach (NotificationBase item in notifications)
        {
            ct.ThrowIfCancellationRequested();
            object notificationDTO = item.ToDTO();

            yield return(notificationDTO.GetType().FullName, notificationDTO);
        }
    }
 public SubscriptionResultEnumerator(
     IAsyncEnumerable <object> sourceStream,
     Func <object, IExecutionContext> contextFactory,
     ExecuteSubscriptionQuery executeQuery,
     IRequestServiceScope serviceScope,
     CancellationToken cancellationToken)
 {
     _sourceStream = sourceStream
                     .WithCancellation(cancellationToken)
                     .GetAsyncEnumerator();
     _contextFactory    = contextFactory;
     _executeQuery      = executeQuery;
     _serviceScope      = serviceScope;
     _cancellationToken = cancellationToken;
     serviceScope.HandleLifetime();
 }
Exemple #7
0
        private async IAsyncEnumerable <Update> GetUpdates(
            string userId,
            [EnumeratorCancellation] CancellationToken cancellationToken)
        {
            IEnumerable <Update> updates = await _updatesProvider.GetUpdatesAsync(userId);

            List <Update> sortedUpdates = updates
                                          .Reverse()
                                          .OrderBy(update => update.CreationDate).ToList();

            UserLatestUpdateTime userLatestUpdateTime = await GetUserLatestUpdateTime(userId);

            ConfiguredCancelableAsyncEnumerable <Update> newUpdates = GetNewUpdates(sortedUpdates, userLatestUpdateTime)
                                                                      .WithCancellation(cancellationToken);

            await foreach (Update update in newUpdates)
            {
                yield return(update.Media?.Any() == true
                    ? await WithExtractedVideo(update, cancellationToken)
                    : update);
            }
        }
Exemple #8
0
        public async Task Handle_Subscription_DataReceived_And_Completed()
        {
            // arrange
            var errorHandler = new Mock <IErrorHandler>();

            IServiceProvider services = new ServiceCollection()
                                        .AddGraphQL()
                                        .AddStarWarsTypes()
                                        .AddStarWarsRepositories()
                                        .AddInMemorySubscriptions()
                                        .Services
                                        .BuildServiceProvider();

            IRequestExecutor executor = await services
                                        .GetRequiredService <IRequestExecutorResolver>()
                                        .GetRequestExecutorAsync();

            var interceptor = new SocketSessionInterceptorMock();
            var connection  = new SocketConnectionMock {
                RequestServices = services
            };
            DocumentNode query = Utf8GraphQLParser.Parse(
                "subscription { onReview(episode: NEW_HOPE) { stars } }");
            var handler = new DataStartMessageHandler(
                executor,
                interceptor,
                errorHandler.Object,
                new NoopExecutionDiagnosticEvents());
            var message = new DataStartMessage("123", new GraphQLRequest(query));

            // act
            await handler.HandleAsync(
                connection,
                message,
                CancellationToken.None);

            // assert
            Assert.Empty(connection.SentMessages);
            Assert.NotEmpty(connection.Subscriptions);

            var stream =
                (IResponseStream)await executor.ExecuteAsync(
                    "subscription { onReview(episode: NEW_HOPE) { stars } }");

            await executor.ExecuteAsync(@"
                mutation {
                    createReview(episode:NEW_HOPE review:
                        {
                            commentary: ""foo""
                            stars: 5
                        }) {
                        stars
                    }
                }");

            using var cts = new CancellationTokenSource(15000);
            ConfiguredCancelableAsyncEnumerable <IQueryResult> .Enumerator enumerator =
                stream.ReadResultsAsync().WithCancellation(cts.Token).GetAsyncEnumerator();
            Assert.True(await enumerator.MoveNextAsync());

            await Task.Delay(2000, cts.Token);

            Assert.Collection(connection.SentMessages,
                              t =>
            {
                Assert.True(t.SequenceEqual(
                                new DataResultMessage(message.Id, enumerator.Current).Serialize()));
            });
        }
Exemple #9
0
        /// <summary>
        /// Downloads blocks from <paramref name="peers"/> in parallel,
        /// using the given <paramref name="blockFetcher"/> function.
        /// </summary>
        /// <param name="peers">A list of peers to download blocks.</param>
        /// <param name="blockFetcher">A function to take demands and a peer, and then
        /// download corresponding blocks.</param>
        /// <param name="singleSessionTimeout">A maximum time to wait each single call of
        /// <paramref name="blockFetcher"/>.  If a call is timed out unsatisfied demands
        /// are automatically retried to fetch from other peers.</param>
        /// <param name="cancellationToken">A cancellation token to observe while waiting
        /// for the task to complete.</param>
        /// <returns>An async enumerable that yields pairs of a fetched block and its source
        /// peer.  It terminates when all demands are satisfied.</returns>
        public async IAsyncEnumerable <Tuple <Block <TAction>, TPeer> > Complete(
            IReadOnlyList <TPeer> peers,
            BlockFetcher blockFetcher,
            TimeSpan singleSessionTimeout,
            [EnumeratorCancellation] CancellationToken cancellationToken = default
            )
        {
            if (!peers.Any())
            {
                throw new ArgumentException("The list of peers must not be empty.", nameof(peers));
            }

            var pool       = new PeerPool(peers);
            var queue      = new AsyncProducerConsumerQueue <Tuple <Block <TAction>, TPeer> >();
            var completion =
                new ConcurrentDictionary <HashDigest <SHA256>, bool>(_satisfiedBlocks);

            await foreach (var hashes in EnumerateChunks(cancellationToken))
            {
                cancellationToken.ThrowIfCancellationRequested();
                IList <HashDigest <SHA256> > hashDigests =
                    hashes is IList <HashDigest <SHA256> > l ? l : hashes.ToList();

                foreach (HashDigest <SHA256> hash in hashDigests)
                {
                    completion.TryAdd(hash, false);
                }

                cancellationToken.ThrowIfCancellationRequested();
                await pool.SpawnAsync(
                    async (peer, ct) =>
                {
                    ct.ThrowIfCancellationRequested();
                    var demands = new HashSet <HashDigest <SHA256> >(hashDigests);
                    try
                    {
                        _logger.Debug(
                            "Request blocks {BlockHashes} to {Peer}...",
                            hashDigests,
                            peer
                            );
                        var timeout = new CancellationTokenSource(singleSessionTimeout);
                        CancellationToken timeoutToken = timeout.Token;
                        timeoutToken.Register(() =>
                                              _logger.Debug("Timed out to wait a response from {Peer}.", peer)
                                              );
                        ct.Register(() => timeout.Cancel());

                        try
                        {
                            ConfiguredCancelableAsyncEnumerable <Block <TAction> > blocks =
                                blockFetcher(peer, hashDigests, timeoutToken)
                                .WithCancellation(timeoutToken);
                            await foreach (Block <TAction> block in blocks)
                            {
                                _logger.Debug(
                                    "Downloaded a block #{BlockIndex} {BlockHash} " +
                                    "from {Peer}.",
                                    block.Index,
                                    block.Hash,
                                    peer
                                    );

                                if (Satisfy(block))
                                {
                                    await queue.EnqueueAsync(
                                        Tuple.Create(block, peer),
                                        cancellationToken
                                        );
                                }

                                demands.Remove(block.Hash);
                            }
                        }
                        catch (OperationCanceledException e)
                        {
                            if (ct.IsCancellationRequested)
                            {
                                _logger.Error(
                                    e,
                                    "A blockFetcher job (peer: {Peer}) is cancelled.",
                                    peer
                                    );
                                throw;
                            }

                            _logger.Debug(
                                e,
                                "Timed out to wait a response from {Peer}.",
                                peer
                                );
                        }
                    }
                    finally
                    {
                        if (demands.Any())
                        {
                            _logger.Verbose(
                                "Fetched blocks from {Peer}, but there are still " +
                                "unsatisfied demands ({UnsatisfiedDemandsNumber}) so " +
                                "enqueue them again: {UnsatisfiedDemands}.",
                                peer,
                                demands.Count,
                                demands
                                );
                            Demand(demands, retry: true);
                        }
                        else
                        {
                            _logger.Verbose("Fetched blocks from {Peer}.", peer);
                        }
                    }
                },
                    cancellationToken : cancellationToken
                    );
            }

            while (!completion.All(kv => kv.Value))
            {
                Tuple <Block <TAction>, TPeer> pair;
                try
                {
                    pair = await queue.DequeueAsync(cancellationToken);
                }
                catch (InvalidOperationException)
                {
                    break;
                }

                yield return(pair);

                _logger.Verbose(
                    "Completed a block {BlockIndex} {BlockHash} from {Peer}.",
                    pair.Item1.Index,
                    pair.Item1.Hash,
                    pair.Item2
                    );
                completion[pair.Item1.Hash] = true;
            }

            _logger.Verbose("Completed all blocks ({Number}).", completion.Count);
        }
 public void Default_WithCancellation_ConfigureAwait_NoThrow()
 {
     ConfiguredCancelableAsyncEnumerable <int> e = ((IAsyncEnumerable <int>)null).WithCancellation(default);
 public void Default_WithCancellation_ConfigureAwait_NoThrow()
 {
     ConfiguredCancelableAsyncEnumerable <int> e = TaskExtensions.WithCancellation((IAsyncEnumerable <int>)null, default);