public async Task Add() {
            var identity1 = await _identityRepository.AddAsync(IdentityGenerator.Generate());
            Assert.NotNull(identity1?.Id);

            var disposables = new List<IDisposable>(2);
            var countdownEvent = new AsyncCountdownEvent(2);

            try {
                var identity2 = IdentityGenerator.Default;
                disposables.Add(_identityRepository.DocumentsAdding.AddSyncHandler((o, args) => {
                    Assert.Equal(identity2, args.Documents.First());
                    countdownEvent.Signal();
                }));

                disposables.Add(_identityRepository.DocumentsAdded.AddSyncHandler((o, args) => {
                    Assert.Equal(identity2, args.Documents.First());
                    countdownEvent.Signal();
                }));

                var result = await _identityRepository.AddAsync(identity2);
                Assert.Equal(IdentityGenerator.Default.Id, result.Id);

                await countdownEvent.WaitAsync(new CancellationTokenSource(TimeSpan.FromMilliseconds(250)).Token);
                Assert.Equal(0, countdownEvent.CurrentCount);
            } finally {
                foreach (var disposable in disposables)
                    disposable.Dispose();

                disposables.Clear();
            }
        }
 public void WaitAsync_AfterCountingDown_IsCompleted()
 {
     var ce = new AsyncCountdownEvent(2);
     Assert.AreEqual(2, ce.CurrentCount);
     ce.Signal();
     var task = ce.WaitAsync();
     Assert.AreEqual(1, ce.CurrentCount);
     Assert.IsFalse(task.IsCompleted);
     ce.Signal();
     Assert.AreEqual(0, ce.CurrentCount);
     Assert.IsTrue(task.IsCompleted);
 }
 public void AddCount_IncrementsCount()
 {
     var ce = new AsyncCountdownEvent(1);
     var task = ce.WaitAsync();
     Assert.AreEqual(1, ce.CurrentCount);
     Assert.IsFalse(task.IsCompleted);
     ce.AddCount();
     Assert.AreEqual(2, ce.CurrentCount);
     Assert.IsFalse(task.IsCompleted);
     ce.Signal();
     Assert.AreEqual(1, ce.CurrentCount);
     Assert.IsFalse(task.IsCompleted);
     ce.Signal();
     Assert.AreEqual(0, ce.CurrentCount);
     Assert.IsTrue(task.IsCompleted);
 }
        public async Task SearchByQuery() {
            var identity = IdentityGenerator.Default;
            var result = await _identityRepository.AddAsync(identity);
            Assert.Equal(identity, result);

            await _client.RefreshAsync();
            var results = await _identityRepository.SearchAsync(null, "id:test");
            Assert.Equal(0, results.Documents.Count);

            var disposables = new List<IDisposable>(1);
            var countdownEvent = new AsyncCountdownEvent(1);

            try
            {
                var filter = $"id:{identity.Id}";
                disposables.Add(_identityRepository.BeforeQuery.AddSyncHandler((o, args) => {
                    Assert.Equal(filter, ((ElasticQuery)args.Query).Filter);
                    countdownEvent.Signal();
                }));

                results = await _identityRepository.SearchAsync(null, filter);
                Assert.Equal(1, results.Documents.Count);
                await countdownEvent.WaitAsync(new CancellationTokenSource(TimeSpan.FromMilliseconds(250)).Token);
                Assert.Equal(0, countdownEvent.CurrentCount);
            }
            finally
            {
                foreach (var disposable in disposables)
                    disposable.Dispose();

                disposables.Clear();
            }
        }
        public virtual async Task CanSendDelayedMessage() {
            const int numConcurrentMessages = 10000;
            var messageBus = GetMessageBus();
            if (messageBus == null)
                return;

            using (messageBus) {
                var countdown = new AsyncCountdownEvent(numConcurrentMessages);

                messageBus.Subscribe<SimpleMessageA>(msg => {
                    Logger.Trace().Message("Got message").Write();
                    Assert.Equal("Hello", msg.Data);
                    countdown.Signal();
                    Logger.Trace().Message("Set event").Write();
                });

                var sw = Stopwatch.StartNew();

                await Run.InParallel(numConcurrentMessages, async i => {
                    await messageBus.PublishAsync(new SimpleMessageA {
                        Data = "Hello"
                    }, TimeSpan.FromMilliseconds(RandomData.GetInt(0, 300)));
                    Logger.Trace().Message("Published one...").Write();
                });

                await countdown.WaitAsync(TimeSpan.FromSeconds(2));
                sw.Stop();
                
                Assert.True(sw.Elapsed > TimeSpan.FromMilliseconds(80));
            }
        }
 public void TrySignal_AfterSet_ReturnsFalse()
 {
     var ce = new AsyncCountdownEvent(1);
     ce.Signal();
     var result = ce.TrySignal();
     Assert.IsFalse(result);
 }
        public async Task CanRun() {
            var countdown = new AsyncCountdownEvent(1);
            Func<Task<DateTime?>> callback = () => {
                countdown.Signal();
                return null;
            };

            using (var timer = new ScheduledTimer(callback, loggerFactory: Log)) {
                timer.ScheduleNext();
                await countdown.WaitAsync(TimeSpan.FromMilliseconds(100));
                Assert.Equal(0, countdown.CurrentCount);
            }
        }
        private BackgroundTaskManager()
        {
            // Start the count at 1 and decrement it when ASP.NET notifies us we're shutting down.
            shutdown = new CancellationTokenSource();
            count = new AsyncCountdownEvent(1);
            shutdown.Token.Register(() => count.Signal(), useSynchronizationContext: false);

            // Register the object and unregister it when the count reaches zero.
            HostingEnvironment.RegisterObject(this);
            done = count.WaitAsync()
                .ContinueWith(_ => HostingEnvironment.UnregisterObject(this),
                    TaskContinuationOptions.ExecuteSynchronously);
        }
        public async Task CanRunWithMinimumInterval() {
            var countdown = new AsyncCountdownEvent(2);

            Func<Task<DateTime?>> callback = async () => {
                _logger.Info("Starting work.");
                countdown.Signal();
                await SystemClock.SleepAsync(500);
                _logger.Info("Finished work.");
                return null;
            };

            using (var timer = new ScheduledTimer(callback, minimumIntervalTime: TimeSpan.FromMilliseconds(100), loggerFactory: Log)) {
                for (int i = 0; i < 4; i++) {
                    timer.ScheduleNext();
                    SystemClock.Sleep(1);
                }

                await countdown.WaitAsync(TimeSpan.FromMilliseconds(100));
                Assert.Equal(1, countdown.CurrentCount);

                await countdown.WaitAsync(TimeSpan.FromSeconds(1.5));
                Assert.Equal(0, countdown.CurrentCount);
            }
        }
        public virtual async Task CanReceiveFromMultipleSubscribers() {
            var messageBus1 = GetMessageBus();
            if (messageBus1 == null)
                return;

            using (messageBus1) {
                var countdown1 = new AsyncCountdownEvent(1);
                messageBus1.Subscribe<SimpleMessageA>(msg => {
                    Assert.Equal("Hello", msg.Data);
                    countdown1.Signal();
                });
                
                using (var messageBus2 = GetMessageBus()) {
                    var countdown2 = new AsyncCountdownEvent(1);
                    messageBus2.Subscribe<SimpleMessageA>(msg => {
                        Assert.Equal("Hello", msg.Data);
                        countdown2.Signal();
                    });
                    

                    await messageBus1.PublishAsync(new SimpleMessageA {
                        Data = "Hello"
                    });

                    await countdown1.WaitAsync(TimeSpan.FromSeconds(2));
                    Assert.Equal(0, countdown1.CurrentCount);
                    await countdown2.WaitAsync(TimeSpan.FromSeconds(2));
                    Assert.Equal(0, countdown2.CurrentCount);
                }
            }
        }
        public virtual async Task CanCancelSubscription() {
            var messageBus = GetMessageBus();
            if (messageBus == null)
                return;

            using (messageBus) {
                var countdown = new AsyncCountdownEvent(2);

                long messageCount = 0;
                var cancellationTokenSource = new CancellationTokenSource();
                messageBus.Subscribe<SimpleMessageA>(msg => {
                    _logger.Trace("SimpleAMessage received");
                    Interlocked.Increment(ref messageCount);
                    cancellationTokenSource.Cancel();
                    countdown.Signal();
                }, cancellationTokenSource.Token);
                
                messageBus.Subscribe<object>(msg => countdown.Signal());

                await messageBus.PublishAsync(new SimpleMessageA {
                    Data = "Hello"
                });
                
                await countdown.WaitAsync(TimeSpan.FromSeconds(2));
                Assert.Equal(0, countdown.CurrentCount);
                Assert.Equal(1, messageCount);

                countdown = new AsyncCountdownEvent(1);
                await messageBus.PublishAsync(new SimpleMessageA {
                    Data = "Hello"
                });

                await countdown.WaitAsync(TimeSpan.FromSeconds(2));
                Assert.Equal(0, countdown.CurrentCount);
                Assert.Equal(1, messageCount);
            }
        }
        public virtual async Task CanSubscribeToAllMessageTypes() {
            var messageBus = GetMessageBus();
            if (messageBus == null)
                return;

            using (messageBus) {
                var countdown = new AsyncCountdownEvent(3);
                messageBus.Subscribe<object>(msg => {
                    countdown.Signal();
                });
                await messageBus.PublishAsync(new SimpleMessageA {
                    Data = "Hello"
                });
                await messageBus.PublishAsync(new SimpleMessageB {
                    Data = "Hello"
                });
                await messageBus.PublishAsync(new SimpleMessageC {
                    Data = "Hello"
                });

                await countdown.WaitAsync(TimeSpan.FromSeconds(2));
                Assert.Equal(0, countdown.CurrentCount);
            }
        }
        public virtual async Task WillReceiveDerivedMessageTypes() {
            var messageBus = GetMessageBus();
            if (messageBus == null)
                return;

            using (messageBus) {
                var countdown = new AsyncCountdownEvent(2);
                messageBus.Subscribe<ISimpleMessage>(msg => {
                    Assert.Equal("Hello", msg.Data);
                    countdown.Signal();
                });
                await messageBus.PublishAsync(new SimpleMessageA {
                    Data = "Hello"
                });
                await messageBus.PublishAsync(new SimpleMessageB {
                    Data = "Hello"
                });
                await messageBus.PublishAsync(new SimpleMessageC {
                    Data = "Hello"
                });

                await countdown.WaitAsync(TimeSpan.FromSeconds(5));
                Assert.Equal(0, countdown.CurrentCount);
            }
        }
        public virtual async Task WillExpireRemoteItems() {
            Logger.Trace().Message("Warm the log...").Write();
            var firstCache = GetCacheClient() as HybridCacheClient;
            Assert.NotNull(firstCache);

            var secondCache = GetCacheClient() as HybridCacheClient;
            Assert.NotNull(secondCache);

            var countdownEvent = new AsyncCountdownEvent(2);
            firstCache.LocalCache.ItemExpired.AddSyncHandler((sender, args) => {
                _writer.WriteLine("First expired: " + args.Key);
                countdownEvent.Signal();
            });
            secondCache.LocalCache.ItemExpired.AddSyncHandler((sender, args) => {
                _writer.WriteLine("Second expired: " + args.Key);
                countdownEvent.Signal();
            });

            var cacheKey = "willexpireremote";
            _writer.WriteLine("First Set");
            await firstCache.SetAsync(cacheKey, new SimpleModel { Data1 = "test" }, TimeSpan.FromMilliseconds(150));
            _writer.WriteLine("Done First Set");
            Assert.Equal(1, firstCache.LocalCache.Count);
            Assert.Equal(0, secondCache.LocalCache.Count);
            Assert.Equal(0, firstCache.LocalCacheHits);

            _writer.WriteLine("First Get");
            Assert.True((await firstCache.GetAsync<SimpleModel>(cacheKey)).HasValue);
            Assert.Equal(1, firstCache.LocalCacheHits);

            _writer.WriteLine("Second Get");
            Assert.True((await secondCache.GetAsync<SimpleModel>(cacheKey)).HasValue);
            Assert.Equal(0, secondCache.LocalCacheHits);
            Assert.Equal(1, secondCache.LocalCache.Count);

            _writer.WriteLine("Second Get from local cache");
            Assert.True((await secondCache.GetAsync<SimpleModel>(cacheKey)).HasValue);
            Assert.Equal(1, secondCache.LocalCacheHits);

            var sw = Stopwatch.StartNew();
            await countdownEvent.WaitAsync(new CancellationTokenSource(500).Token);
            sw.Stop();
            Trace.WriteLine(sw.Elapsed);
            Assert.Equal(0, firstCache.LocalCache.Count);
            Assert.Equal(0, secondCache.LocalCache.Count);
            //Assert.InRange(sw.Elapsed.TotalMilliseconds, 0, 200);
        }
        public async Task CanPostManyEvents() {
            await ResetAsync();

            const int batchSize = 250;
            const int batchCount = 10;

            try {
                var countdown = new AsyncCountdownEvent(batchCount);
                var messageSubscriber = IoC.GetInstance<IMessageSubscriber>();
                messageSubscriber.Subscribe<EntityChanged>(ch => {
                    if (ch.ChangeType != ChangeType.Added || ch.Type != typeof(PersistentEvent).Name)
                        return;

                    if (countdown.CurrentCount >= batchCount)
                        throw new ApplicationException("Too many change notifications.");

                    countdown.Signal();
                });

                await Run.InParallel(batchCount, async i => {
                    _eventController.Request = CreateRequestMessage(new ClaimsPrincipal(new User { EmailAddress = TestConstants.UserEmail, Id = TestConstants.UserId, OrganizationIds = new[] { TestConstants.OrganizationId }, Roles = new[] { AuthorizationRoles.Client } }.ToIdentity(TestConstants.ProjectId)), true, false);
                    var events = new RandomEventGenerator().Generate(batchSize);
                    var compressedEvents = await Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(events)).CompressAsync();
                    var actionResult = await _eventController.PostAsync(compressedEvents, version: 2, userAgent: "exceptionless/2.0.0.0");
                    Assert.IsType<StatusCodeResult>(actionResult);
                });

                Assert.Equal(batchCount, (await _eventQueue.GetQueueStatsAsync()).Enqueued);
                Assert.Equal(0, (await _eventQueue.GetQueueStatsAsync()).Completed);

                var processEventsJob = IoC.GetInstance<EventPostsJob>();
                var sw = Stopwatch.StartNew();
                await processEventsJob.RunUntilEmptyAsync();
                sw.Stop();
                Trace.WriteLine(sw.Elapsed);

                Assert.Equal(batchCount, (await _eventQueue.GetQueueStatsAsync()).Completed);
                Assert.Equal(batchSize * batchCount, await EventCountAsync());
                //await countdown.WaitAsync();
            } finally {
                await _eventQueue.DeleteQueueAsync();
            }
        }
        public async Task AddAndSave() {
            var log = await _dailyRepository.AddAsync(LogEventGenerator.Default, sendNotification: false);
            Assert.NotNull(log?.Id);
            
            var disposables = new List<IDisposable>(4);
            var countdownEvent = new AsyncCountdownEvent(5);
            // Save requires an id to be set.
            var addedLog = LogEventGenerator.Generate(id: ObjectId.GenerateNewId().ToString());
            try {
                disposables.Add(_dailyRepository.DocumentsAdding.AddSyncHandler((o, args) => {
                    Assert.Equal(addedLog, args.Documents.First());
                    countdownEvent.Signal();
                }));
                disposables.Add(_dailyRepository.DocumentsAdded.AddSyncHandler((o, args) => {
                    Assert.Equal(addedLog, args.Documents.First());
                    countdownEvent.Signal();
                }));
                disposables.Add(_dailyRepository.DocumentsSaving.AddSyncHandler((o, args) => {
                    Assert.Equal(log, args.Documents.First().Value);
                    countdownEvent.Signal();
                }));
                disposables.Add(_dailyRepository.DocumentsSaved.AddSyncHandler((o, args) => {
                    Assert.Equal(log, args.Documents.First().Value);
                    countdownEvent.Signal();
                }));
                _messgeBus.Subscribe<EntityChanged>((msg, ct) => {
                    Assert.Equal(nameof(LogEvent), msg.Type);
                    Assert.Equal(log.Id, msg.Id);
                    Assert.Equal(ChangeType.Saved, msg.ChangeType);
                    countdownEvent.Signal();
                    return Task.CompletedTask;
                });

                log.CompanyId = ObjectId.GenerateNewId().ToString();
                await _dailyRepository.SaveAsync(new List<LogEvent> { log, addedLog });

                await countdownEvent.WaitAsync(new CancellationTokenSource(TimeSpan.FromSeconds(2)).Token);
                Assert.Equal(0, countdownEvent.CurrentCount);
            } finally {
                foreach (var disposable in disposables)
                    disposable.Dispose();

                disposables.Clear();
            }
        }
Exemple #17
0
        protected async Task DoWorkAsync(QueueEntry<SimpleWorkItem> w, AsyncCountdownEvent countdown, WorkInfo info) {
            Trace.WriteLine($"Starting: {w.Value.Id}");
            Assert.Equal("Hello", w.Value.Data);

            try {
                // randomly complete, abandon or blowup.
                if (RandomData.GetBool()) {
                    Trace.WriteLine($"Completing: {w.Value.Id}");
                    await w.CompleteAsync();
                    info.IncrementCompletedCount();
                } else if (RandomData.GetBool()) {
                    Trace.WriteLine($"Abandoning: {w.Value.Id}");
                    await w.AbandonAsync();
                    info.IncrementAbandonCount();
                } else {
                    Trace.WriteLine($"Erroring: {w.Value.Id}");
                    info.IncrementErrorCount();
                    throw new ApplicationException();
                }
            } finally {
                Trace.WriteLine($"Signal {countdown.CurrentCount}");
                countdown.Signal();
            }
        }
        public virtual async Task CanSendMessageToMultipleSubscribers() {
            var messageBus = GetMessageBus();
            if (messageBus == null)
                return;

            using (messageBus) {
                var countdown = new AsyncCountdownEvent(3);
                messageBus.Subscribe<SimpleMessageA>(msg => {
                    Assert.Equal("Hello", msg.Data);
                    countdown.Signal();
                });
                messageBus.Subscribe<SimpleMessageA>(msg => {
                    Assert.Equal("Hello", msg.Data);
                    countdown.Signal();
                });
                messageBus.Subscribe<SimpleMessageA>(msg => {
                    Assert.Equal("Hello", msg.Data);
                    countdown.Signal();
                });
                await messageBus.PublishAsync(new SimpleMessageA {
                    Data = "Hello"
                });

                await countdown.WaitAsync(TimeSpan.FromSeconds(2));
            }
        }
        public async Task CanReindexVersionedIndexWithDeletedDocs() {
            var version1Index = new VersionedEmployeeIndex(_configuration, 1);
            await version1Index.DeleteAsync();

            var version2Index = new VersionedEmployeeIndex(_configuration, 2);
            await version2Index.DeleteAsync();

            using (new DisposableAction(() => version1Index.DeleteAsync().GetAwaiter().GetResult())) {
                await version1Index.ConfigureAsync();
                Assert.True(_client.IndexExists(version1Index.VersionedName).Exists);

                var repository = new EmployeeRepository(version1Index.Employee);
                var employee = await repository.AddAsync(EmployeeGenerator.Default);
                Assert.NotNull(employee?.Id);
                await _client.RefreshAsync();

                using (new DisposableAction(() => version2Index.DeleteAsync().GetAwaiter().GetResult())) {
                    await version2Index.ConfigureAsync();
                    Assert.True(_client.IndexExists(version2Index.VersionedName).Exists);
                    Assert.Equal(1, await version2Index.GetCurrentVersionAsync());

                    // alias should still point to the old version until reindex
                    var aliasResponse = await _client.GetAliasAsync(descriptor => descriptor.Alias(version2Index.Name));
                    Assert.True(aliasResponse.IsValid);
                    Assert.Equal(1, aliasResponse.Indices.Count);
                    Assert.Equal(version1Index.VersionedName, aliasResponse.Indices.First().Key);

                    var countdown = new AsyncCountdownEvent(1);
                    var reindexTask = version2Index.ReindexAsync((progress, message) => {
                        _logger.Info($"Reindex Progress {progress}%: {message}");
                        if (progress == 95) {
                            countdown.Signal();
                            SystemClock.Sleep(1000);
                        }

                        return Task.CompletedTask;
                    });

                    // Wait until the first reindex pass is done.
                    await countdown.WaitAsync();
                    Assert.Equal(1, await version1Index.GetCurrentVersionAsync());
                    await repository.RemoveAllAsync();
                    await _client.RefreshAsync();

                    // Resume after everythings been indexed.
                    await reindexTask;
                    aliasResponse = await _client.GetAliasAsync(descriptor => descriptor.Alias(version2Index.Name));
                    Assert.True(aliasResponse.IsValid, aliasResponse.GetErrorMessage());
                    Assert.Equal(1, aliasResponse.Indices.Count);
                    Assert.Equal(version2Index.VersionedName, aliasResponse.Indices.First().Key);

                    Assert.Equal(2, await version1Index.GetCurrentVersionAsync());
                    Assert.Equal(2, await version2Index.GetCurrentVersionAsync());

                    var countResponse = await _client.CountAsync(d => d.Index(version1Index.VersionedName));
                    _logger.Trace(() => countResponse.GetRequest());
                    Assert.True(countResponse.ConnectionStatus.HttpStatusCode == 404, countResponse.GetErrorMessage());
                    Assert.Equal(0, countResponse.Count);

                    countResponse = await _client.CountAsync(d => d.Index(version2Index.VersionedName));
                    _logger.Trace(() => countResponse.GetRequest());
                    Assert.True(countResponse.IsValid, countResponse.GetErrorMessage());
                    Assert.Equal(1, countResponse.Count);

                    Assert.Equal(employee, await repository.GetByIdAsync(employee.Id));
                    Assert.False(_client.IndexExists(d => d.Index(version1Index.VersionedName)).Exists);
                }
            }
        }
        public async Task MeasureWorkerThroughput() {
            var queue = GetQueue(retries: 3, workItemTimeout: TimeSpan.FromSeconds(2), retryDelay: TimeSpan.FromSeconds(1));
            if (queue == null)
                return;
            
            using (queue) {
                await queue.DeleteQueueAsync();

                const int workItemCount = 1;
                for (int i = 0; i < workItemCount; i++) {
                    await queue.EnqueueAsync(new SimpleWorkItem {
                        Data = "Hello"
                    });
                }
                Assert.Equal(workItemCount, (await queue.GetQueueStatsAsync()).Queued);

                var countdown = new AsyncCountdownEvent(workItemCount);
                var metrics = new InMemoryMetricsClient();
                await queue.StartWorkingAsync(async workItem => {
                    Assert.Equal("Hello", workItem.Value.Data);
                    await workItem.CompleteAsync();
                    await metrics.CounterAsync("work");
                    countdown.Signal();
                });

                await countdown.WaitAsync(TimeSpan.FromMinutes(1));
                Assert.Equal(0, countdown.CurrentCount);
                _logger.Trace((await metrics.GetCounterStatsAsync("work")).ToString());

                var stats = await queue.GetQueueStatsAsync();
                Assert.Equal(workItemCount, stats.Dequeued);
                Assert.Equal(workItemCount, stats.Completed);
                Assert.Equal(0, stats.Queued);

                _logger.Trace("# Keys: {0}", CountAllKeysAsync());
            }
        }
        public async Task Remove() {
            var log = await _dailyRepository.AddAsync(LogEventGenerator.Default);
            Assert.NotNull(log?.Id);

            var disposables = new List<IDisposable>(2);
            var countdownEvent = new AsyncCountdownEvent(2);

            try {
                disposables.Add(_dailyRepository.DocumentsRemoving.AddSyncHandler((o, args) => {
                    Assert.Equal(log, args.Documents.First());
                    countdownEvent.Signal();
                }));
                disposables.Add(_dailyRepository.DocumentsRemoved.AddSyncHandler((o, args) => {
                    Assert.Equal(log, args.Documents.First());
                    countdownEvent.Signal();
                }));

                await _dailyRepository.RemoveAsync(log);

                await countdownEvent.WaitAsync(new CancellationTokenSource(TimeSpan.FromMilliseconds(250)).Token);
                Assert.Equal(0, countdownEvent.CurrentCount);

            } finally {
                foreach (var disposable in disposables)
                    disposable.Dispose();

                disposables.Clear();
            }
        }
        public async Task RemoveAll() {
            await _identityRepository.RemoveAllAsync();

            var identities = new List<Identity> { IdentityGenerator.Default };
            await _identityRepository.AddAsync(identities);
            await _client.RefreshAsync();
            
            var disposables = new List<IDisposable>(2);
            var countdownEvent = new AsyncCountdownEvent(2);

            try {
                disposables.Add(_identityRepository.DocumentsRemoving.AddSyncHandler((o, args) => {
                    countdownEvent.Signal();
                }));
                disposables.Add(_identityRepository.DocumentsRemoved.AddSyncHandler((o, args) => {
                    countdownEvent.Signal();
                }));

                await _identityRepository.RemoveAllAsync();
                await countdownEvent.WaitAsync(new CancellationTokenSource(TimeSpan.FromMilliseconds(250)).Token);
                Assert.Equal(0, countdownEvent.CurrentCount);

            } finally {
                foreach (var disposable in disposables)
                    disposable.Dispose();

                disposables.Clear();
            }

            await _client.RefreshAsync();
            Assert.Equal(0, await _identityRepository.CountAsync());
        }
        public virtual async Task CanTolerateSubscriberFailure() {
            var messageBus = GetMessageBus();
            if (messageBus == null)
                return;

            using (messageBus) {
                var countdown = new AsyncCountdownEvent(2);
                messageBus.Subscribe<SimpleMessageA>(msg => {
                    throw new Exception();
                });
                messageBus.Subscribe<SimpleMessageA>(msg => {
                    Assert.Equal("Hello", msg.Data);
                    countdown.Signal();
                });
                messageBus.Subscribe<SimpleMessageA>(msg => {
                    Assert.Equal("Hello", msg.Data);
                    countdown.Signal();
                });
                await messageBus.PublishAsync(new SimpleMessageA {
                    Data = "Hello"
                });

                await countdown.WaitAsync(TimeSpan.FromSeconds(2));
                Assert.Equal(0, countdown.CurrentCount);
            }
        }
 public void AddCount_AfterSet_ThrowsException()
 {
     var ce = new AsyncCountdownEvent(1);
     ce.Signal();
     AssertEx.ThrowsException<InvalidOperationException>(() => ce.AddCount());
 }
        public virtual async Task WillExpireRemoteItems() {
            var countdownEvent = new AsyncCountdownEvent(2);

            using (var firstCache = GetCacheClient() as HybridCacheClient) {
                Assert.NotNull(firstCache);
                Action<object, ItemExpiredEventArgs> expiredHandler = (sender, args) => {
                    _logger.Trace("First expired: {0}", args.Key);
                    countdownEvent.Signal();
                };

                using (firstCache.LocalCache.ItemExpired.AddSyncHandler(expiredHandler)) {
                    using (var secondCache = GetCacheClient() as HybridCacheClient) {
                        Assert.NotNull(secondCache);
                        Action<object, ItemExpiredEventArgs> expiredHandler2 = (sender, args) => {
                            _logger.Trace("Second expired: {0}", args.Key);
                            countdownEvent.Signal();
                        };

                        using (secondCache.LocalCache.ItemExpired.AddSyncHandler(expiredHandler2)) {
                            string cacheKey = "willexpireremote";
                            _logger.Trace("First Set");
                            Assert.True(await firstCache.AddAsync(cacheKey, new SimpleModel { Data1 = "test" }, TimeSpan.FromMilliseconds(150)));
                            _logger.Trace("Done First Set");
                            Assert.Equal(1, firstCache.LocalCache.Count);

                            _logger.Trace("Second Get");
                            Assert.True((await secondCache.GetAsync<SimpleModel>(cacheKey)).HasValue);
                            _logger.Trace("Done Second Get");
                            Assert.Equal(1, secondCache.LocalCache.Count);

                            var sw = Stopwatch.StartNew();
                            await countdownEvent.WaitAsync(TimeSpan.FromMilliseconds(250));
                            sw.Stop();

                            _logger.Trace("Time {0}", sw.Elapsed);
                            Assert.Equal(0, countdownEvent.CurrentCount);
                            Assert.Equal(0, firstCache.LocalCache.Count);
                            Assert.Equal(0, secondCache.LocalCache.Count);
                        }
                    }
                }
            }
        }