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(); } }
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); } } } } }