コード例 #1
0
 public void BasicFunctionality()
 {
     using (var scheduler = new TestScheduler(threadCount: 4))
     {
         TaskHelper taskHelper = scheduler.TaskHelper;
         var        number     = scheduler.Run(async() =>
         {
             Assert.Equal(Dt(0), scheduler.Clock.GetCurrentDateTimeUtc());
             await taskHelper.ConfigureAwait(scheduler.Delay(TimeSpan.FromSeconds(10), CancellationToken.None));
             Assert.Equal(Dt(10), scheduler.Clock.GetCurrentDateTimeUtc());
             await taskHelper.ConfigureAwait(scheduler.Delay(TimeSpan.FromSeconds(10), CancellationToken.None));
             Assert.Equal(Dt(20), scheduler.Clock.GetCurrentDateTimeUtc());
             int n1 = await taskHelper.ConfigureAwait(GetANumber1());
             Assert.Equal(111, n1);
             int n2 = await taskHelper.ConfigureAwait(GetANumber2());
             Assert.Equal(222, n2);
             Task <int>[] tasks = new Task <int> [1000];
             for (int i = 0; i < tasks.Length; i++)
             {
                 tasks[i] = WaitTest(scheduler, i);
             }
             await taskHelper.ConfigureAwait(taskHelper.WhenAll(tasks));
             return(tasks.Sum(x => x.Result));
         });
         Assert.Equal(1000 * 999 / 2, number);
     }
 }
コード例 #2
0
 public override async Task AcknowledgeAsync(SubscriptionName subscription, IEnumerable <string> ackIds, CancellationToken cancellationToken)
 {
     if (_writeAsyncPreDelay != TimeSpan.Zero)
     {
         await _taskHelper.ConfigureAwait(_scheduler.Delay(_writeAsyncPreDelay, CancellationToken.None));
     }
     lock (_lock)
     {
         _acks.AddRange(ackIds.Select(id => new TimedId(_clock.GetCurrentDateTimeUtc(), id)));
     }
 }
コード例 #3
0
        public void OrderingKeyManyMessages(
            [CombinatorialValues(1, 2, 5, 7)] int clientCount,
            [CombinatorialValues(1, 2, 6, 13)] int threadCount,
            [CombinatorialValues(101, 2000, 9999)] int messageCount,
            [CombinatorialValues(1, 2, 9, 51)] int orderingKeysCount,
            [CombinatorialValues(1, 5, 50)] int batchElementCountThreshold,
            [CombinatorialValues(0, 1, 59, 123, 1001)] int delayMs1,
            [CombinatorialValues(0, 2, 500)] int delayMs2)
        {
            var        topicName  = new TopicName("FakeProject", "FakeTopic");
            var        scheduler  = new TestScheduler(threadCount);
            TaskHelper taskHelper = scheduler.TaskHelper;
            var        clients    = Enumerable.Range(0, clientCount)
                                    .Select(_ => new FakePublisherServiceApiClient(scheduler, taskHelper,
                                                                                   new[] { TimeSpan.FromMilliseconds(delayMs1), TimeSpan.FromMilliseconds(delayMs2) })).ToArray();
            var settings = MakeSettings(scheduler,
                                        batchElementCountThreshold: batchElementCountThreshold, batchRequestByteThreshold: 10000, enableMessageOrdering: true);
            int shutdownCount = 0;
            var pub           = new PublisherClientImpl(topicName, clients, settings, () =>
            {
                Interlocked.Increment(ref shutdownCount);
                return(Task.FromResult(0));
            }, taskHelper);

            scheduler.Run(async() =>
            {
                var tasks = Enumerable.Range(0, messageCount)
                            .Select(i => pub.PublishAsync((i % orderingKeysCount).ToString(), $"{i % orderingKeysCount}:{i}")).ToArray();
                var ids = new HashSet <string>(await taskHelper.ConfigureAwait(taskHelper.WhenAll(tasks)));
                await taskHelper.ConfigureAwait(pub.ShutdownAsync(new CancellationToken()));
                Assert.Equal(messageCount, ids.Count);
                // This doesn't check the global ordering between clients, but that's OK here.
                // The emulator-based integration test checks are more thorough.
                foreach (var client in clients)
                {
                    var kv = client.HandledMessages.Select(x => x.Split(':')).Select(x => (key: x[0], value: x[1]));
                    foreach (var values in kv.GroupBy(x => x.key, x => x.value))
                    {
                        var errorMsg = $"Ordering-key '{values.Key}' out of order";
                        foreach (var pair in values.Zip(values.Skip(1), (a, b) => (a, b)))
                        {
                            Assert.True(int.Parse(pair.a) < int.Parse(pair.b), errorMsg);
                        }
                    }
                }
                Assert.Equal(ids, new HashSet <string>(clients.SelectMany(x => x.HandledMessages)));
                Assert.Equal(1, shutdownCount);
            });
        }
コード例 #4
0
        public void OneMessage(
            [CombinatorialValues(false, true)] bool hardStop)
        {
            var        topicName     = new TopicName("FakeProject", "FakeTopic");
            var        scheduler     = new TestScheduler();
            TaskHelper taskHelper    = scheduler.TaskHelper;
            var        client        = new FakePublisherServiceApiClient(scheduler, taskHelper);
            var        settings      = MakeSettings(scheduler);
            int        shutdownCount = 0;
            var        pub           = new PublisherClientImpl(topicName, new[] { client }, settings, () =>
            {
                Interlocked.Increment(ref shutdownCount);
                return(Task.FromResult(0));
            }, taskHelper);

            scheduler.Run(async() =>
            {
                var id           = await taskHelper.ConfigureAwait(pub.PublishAsync("1"));
                bool isCancelled = await taskHelper.ConfigureAwaitHideCancellation(
                    () => pub.ShutdownAsync(new CancellationToken(hardStop)));
                Assert.Equal(hardStop, isCancelled);
                Assert.Equal("1", id);
                Assert.Equal(1, shutdownCount);
            });
        }
コード例 #5
0
        public void ManyMessages(
            [CombinatorialValues(false, true)] bool hardStop,
            [CombinatorialValues(1, 2, 5, 7)] int clientCount,
            [CombinatorialValues(1, 2, 6, 13)] int threadCount,
            [CombinatorialValues(101, 2000, 9999)] int messageCount,
            [CombinatorialValues(1, 5, 50)] int batchElementCountThreshold)
        {
            var        topicName     = new TopicName("FakeProject", "FakeTopic");
            var        scheduler     = new TestScheduler(threadCount);
            TaskHelper taskHelper    = scheduler.TaskHelper;
            var        clients       = Enumerable.Range(0, clientCount).Select(_ => new FakePublisherServiceApiClient(scheduler, taskHelper)).ToArray();
            var        settings      = MakeSettings(scheduler, batchElementCountThreshold: batchElementCountThreshold, batchRequestByteThreshold: 10000);
            int        shutdownCount = 0;
            var        pub           = new PublisherClientImpl(topicName, clients, settings, () =>
            {
                Interlocked.Increment(ref shutdownCount);
                return(Task.FromResult(0));
            }, taskHelper);

            scheduler.Run(async() =>
            {
                var tasks       = Enumerable.Range(0, messageCount).Select(i => pub.PublishAsync(i.ToString())).ToArray();
                var ids         = new HashSet <string>(await taskHelper.ConfigureAwait(taskHelper.WhenAll(tasks)));
                var isCancelled = await taskHelper.ConfigureAwaitHideCancellation(
                    () => pub.ShutdownAsync(new CancellationToken(hardStop)));
                Assert.Equal(hardStop, isCancelled);
                var expected = new HashSet <string>(Enumerable.Range(0, messageCount).Select(x => x.ToString()));
                Assert.Equal(expected, ids);
                Assert.Equal(1, shutdownCount);
            });
        }
コード例 #6
0
            public override async Task <PublishResponse> PublishAsync(PublishRequest request, CallSettings callSettings = null)
            {
                _delays.MoveNext();
                await _taskHelper.ConfigureAwait(_schduler.Delay(_delays.Current, callSettings?.CancellationToken ?? CancellationToken.None));

                var byOrderingKey = request.Messages.GroupBy(x => x.OrderingKey).ToList();

                if (byOrderingKey.Count > 1)
                {
                    throw new InvalidOperationException("Multiple ordering-keys should not be present within a single batch.");
                }
                var msgIds = request.Messages.Select(x => x.Data.ToStringUtf8());

                lock (_lock)
                {
                    if (byOrderingKey.Count > 0 && byOrderingKey[0].Key == _orderingKeyErrorUnrecoverable)
                    {
                        // Cause a one-off unrecoverable error.
                        _orderingKeyErrorUnrecoverable = null;
                        throw new RpcException(new Status(StatusCode.DataLoss, "Data loss"));
                    }
                    if (byOrderingKey.Count > 0 && byOrderingKey[0].Key == _orderingKeyErrorRecoverable)
                    {
                        // Cause a one-off recoverable error.
                        _orderingKeyErrorRecoverable = null;
                        throw new RpcException(new Status(StatusCode.Unavailable, "Unavailable"));
                    }
                    _handledIds.AddRange(msgIds);
                }
                return(new PublishResponse {
                    MessageIds = { msgIds }
                });
            }
コード例 #7
0
 public override async Task<PublishResponse> PublishAsync(PublishRequest request, CallSettings callSettings = null)
 {
     _delays.MoveNext();
     await _taskHelper.ConfigureAwait(_schduler.Delay(_delays.Current, callSettings?.CancellationToken ?? CancellationToken.None));
     var msgIds = request.Messages.Select(x => x.Data.ToStringUtf8());
     lock (_lock)
     {
         _handledIds.AddRange(msgIds);
     }
     return new PublishResponse { MessageIds = { msgIds } };
 }
コード例 #8
0
                public override async Task WriteAsync(StreamingPullRequest message)
                {
                    await _taskHelper.ConfigureAwait(_scheduler.Delay(_writeAsyncPreDelay, CancellationToken.None));

                    var now = _clock.GetCurrentDateTimeUtc();

                    lock (_lock)
                    {
                        _extends.AddRange(message.ModifyDeadlineAckIds.Select(id => new TimedId(now, id)).ToList());
                        _acks.AddRange(message.AckIds.Select(id => new TimedId(now, id)).ToList());
                    }
                }
コード例 #9
0
 public void WhenAll([CombinatorialValues(1, 2, 3)] int threadCount)
 {
     using (var scheduler = new TestScheduler(threadCount: threadCount))
     {
         TaskHelper th = scheduler.TaskHelper;
         scheduler.Run(async() =>
         {
             var tcs1 = new TaskCompletionSource <int>();
             var tcs2 = new TaskCompletionSource <int>();
             tcs1.SetResult(0);
             Task delayTask = th.Run(async() =>
             {
                 await th.ConfigureAwait(scheduler.Delay(TimeSpan.FromSeconds(1), CancellationToken.None));
                 tcs2.SetResult(0);
             });
             await th.ConfigureAwait(th.WhenAll(tcs1.Task, tcs2.Task));
             await th.ConfigureAwait(delayTask);
             // Test passes if no exception is thrown.
         });
     }
 }
コード例 #10
0
 public void FlowState()
 {
     var topicName = new TopicName("FakeProject", "FakeTopic");
     var scheduler = new TestScheduler();
     TaskHelper taskHelper = scheduler.TaskHelper;
     var client = new FakePublisher(scheduler, taskHelper, TimeSpan.FromSeconds(1));
     var settings = MakeSettings(scheduler);
     var pub = new SimplePublisherImpl(topicName, new[] { client }, settings, null, taskHelper);
     var msgSize = new PubsubMessage { Data = ByteString.CopyFromUtf8("1") }.CalculateSize();
     scheduler.Run(async () =>
     {
         // Publish 2 msgs; 1st will be immediately sent, 2nd will stay in queue for 1 second.
         var pubTask = Task.WhenAll(pub.PublishAsync("1"), pub.PublishAsync("2"));
         Assert.Equal(1, pub.GetCurrentFlowState().ElementCount);
         Assert.Equal(msgSize, pub.GetCurrentFlowState().ByteCount);
         await taskHelper.ConfigureAwait(pubTask);
         Assert.Equal(0, pub.GetCurrentFlowState().ElementCount);
         Assert.Equal(0, pub.GetCurrentFlowState().ByteCount);
     });
 }
コード例 #11
0
        public void PublishingMessageWithOrderingKeyRequiresOrderingEnabled()
        {
            var        topicName     = new TopicName("FakeProject", "FakeTopic");
            var        scheduler     = new TestScheduler();
            TaskHelper taskHelper    = scheduler.TaskHelper;
            var        client        = new FakePublisherServiceApiClient(scheduler, taskHelper);
            var        settings      = MakeSettings(scheduler);
            int        shutdownCount = 0;
            var        pub           = new PublisherClientImpl(topicName, new[] { client }, settings, () =>
            {
                Interlocked.Increment(ref shutdownCount);
                return(Task.FromResult(0));
            }, taskHelper);

            scheduler.Run(async() =>
            {
                await taskHelper.ConfigureAwait(
                    Assert.ThrowsAsync <InvalidOperationException>(() => pub.PublishAsync("an ordering key", "1")));
            });
        }
コード例 #12
0
        public void OrderingKeyResumePublish()
        {
            const string unrecoverableKey = "error-unrecoverable";
            const string recoverableKey   = "error-recoverable";
            var          topicName        = new TopicName("FakeProject", "FakeTopic");
            var          scheduler        = new TestScheduler();
            TaskHelper   taskHelper       = scheduler.TaskHelper;
            var          client           = new FakePublisherServiceApiClient(scheduler, taskHelper,
                                                                              orderingKeyErrorUnrecoverable: unrecoverableKey, orderingKeyErrorRecoverable: recoverableKey);
            var settings      = MakeSettings(scheduler, enableMessageOrdering: true);
            int shutdownCount = 0;
            var pub           = new PublisherClientImpl(topicName, new[] { client }, settings, () =>
            {
                Interlocked.Increment(ref shutdownCount);
                return(Task.FromResult(0));
            }, taskHelper);

            scheduler.Run(async() =>
            {
                // First call will trigger an unrecoverable error.
                var ex = await taskHelper.ConfigureAwait(
                    Assert.ThrowsAsync <RpcException>(() => pub.PublishAsync(unrecoverableKey, "unrecoverable error")));
                Assert.Equal(StatusCode.DataLoss, ex.StatusCode);
                // Sending again will reject the message.
                await taskHelper.ConfigureAwait(
                    Assert.ThrowsAsync <OrderingKeyInErrorStateException>(() => pub.PublishAsync(unrecoverableKey, "key in error state")));
                // Other ordering-keys publish OK.
                await taskHelper.ConfigureAwait(pub.PublishAsync("ok-key", "ok"));
                // Including a recoverable error.
                await taskHelper.ConfigureAwait(pub.PublishAsync(recoverableKey, "recoverable error"));
                // Including a message without an ordering key.
                await taskHelper.ConfigureAwait(pub.PublishAsync("key not ordered"));
                // Resume publishing on the ordering key.
                pub.ResumePublish(unrecoverableKey);
                await taskHelper.ConfigureAwait(pub.PublishAsync(unrecoverableKey, "unrecoverable key resumed"));
                var expected = new HashSet <string>(new[] { "ok", "key not ordered", "recoverable error", "unrecoverable key resumed" });
                Assert.Equal(expected, new HashSet <string>(client.HandledMessages));
            });
        }
コード例 #13
0
 public void Run(Func <Task> taskProvider) => Run(async() =>
 {
     await TaskHelper.ConfigureAwait(taskProvider());
     return(0);
 });