public async Task TestNearCacheGetAsync() // EntryIsHit
        {
            var dictionary = await _client.GetDictionaryAsync <object, object>("nc-" + TestUtils.RandomString());

            await using var _ = new AsyncDisposable(dictionary.DestroyAsync);
            var cache = GetNearCache(dictionary);

            // add a value to the dictionary
            await dictionary.SetAsync("key", "value");

            // get the value
            var result = await dictionary.GetAsync("key");

            Assert.AreEqual("value", result);

            // validate that the cache contains a value
            Assert.AreEqual(1, cache.Count);

            // and that the corresponding entry has zero hits
            var cacheEntries = await cache.SnapshotEntriesAsync();

            Assert.That(cacheEntries.Count, Is.EqualTo(1));
            Assert.That(cacheEntries.First().Hits, Is.EqualTo(0));

            // get the value again
            result = await dictionary.GetAsync("key");

            Assert.AreEqual("value", result);

            // validate that the entry now has one hit
            cacheEntries = await cache.SnapshotEntriesAsync();

            Assert.That(cacheEntries.Count, Is.EqualTo(1));
            Assert.That(cacheEntries.First().Hits, Is.EqualTo(1));
        }
示例#2
0
        public static IAsyncObservable <TSource> Finally <TSource>(this IAsyncObservable <TSource> source, Func <Task> finallyAction)
        {
            if (source == null)
            {
                throw new ArgumentNullException(nameof(source));
            }
            if (finallyAction == null)
            {
                throw new ArgumentNullException(nameof(finallyAction));
            }

            return(Create <TSource>(async observer =>
            {
                var subscription = await source.SubscribeSafeAsync(observer).ConfigureAwait(false);

                return AsyncDisposable.Create(async() =>
                {
                    try
                    {
                        await subscription.DisposeAsync().ConfigureAwait(false);
                    }
                    finally
                    {
                        await finallyAction().ConfigureAwait(false);
                    }
                });
            }));
        }
        public async Task Add_AfterDisposeStarts_ExecutingInSerial_InvokesActionAfterDisposeCompletes()
        {
            bool action1Invoked = false;
            bool action2Invoked = false;
            var  ready          = new TaskCompletionSource <object>();
            var  signal         = new TaskCompletionSource <object>();
            var  disposable     = AsyncDisposable.Create(async() =>
            {
                action1Invoked = true;
                ready.TrySetResult(null);
                await signal.Task;
            });
            var disposeTask = Task.Run(async() => await disposable.DisposeAsync());
            await ready.Task;
            var addTask = Task.Run(async() => await disposable.AddAsync(async() => { action2Invoked = true; }));

            Assert.NotEqual(addTask, await Task.WhenAny(addTask, Task.Delay(100)));
            Assert.True(action1Invoked);
            Assert.False(action2Invoked);
            signal.TrySetResult(null);
            await disposeTask;
            await addTask;

            Assert.True(action2Invoked);
        }
        public async Task TestNearCacheInvalidationOnRemoveAllPredicate()
        {
            var dictionary = await _client.GetDictionaryAsync <string, string>("nc-invalidate-" + TestUtils.RandomString());

            await using var _ = new AsyncDisposable(dictionary.DestroyAsync);
            var cache = GetNearCache(dictionary);

            for (var i = 0; i < 100; i++)
            {
                await dictionary.SetAsync("key" + i, "value" + i);
            }

            for (var i = 0; i < 100; i++)
            {
                await dictionary.GetAsync("key" + i);
            }

            Assert.AreEqual(100, cache.Count);
            Assert.AreEqual(cache.Count, cache.Statistics.EntryCount);

            await dictionary.RemoveAsync(new SqlPredicate("this == 'value2'"));

            await AssertEx.SucceedsEventually(() =>
            {
                Assert.AreEqual(0, cache.Count);
                Assert.AreEqual(cache.Count, cache.Statistics.EntryCount);
            }, 8000, 500);
        }
示例#5
0
    public ValueTask <IAsyncDisposable> Subscribe(Func <IEnumerable <FileEvent>, ValueTask> cb)
    {
#pragma warning disable CA2000
        return(ValueTask.FromResult(AsyncDisposable.Create(() => ValueTask.CompletedTask) as IAsyncDisposable));

#pragma warning restore CA2000
    }
示例#6
0
        private static IAsyncObservable <TEventArgs> FromEventCore <TDelegate, TEventArgs>(Func <Action <TEventArgs>, TDelegate> conversion, Action <TDelegate> addHandler, Action <TDelegate> removeHandler, IAsyncScheduler scheduler)
        {
            return
                (SynchronizeEvents(
                     Create <TEventArgs>(observer =>
            {
                var handler = new Action <TEventArgs>(async e =>
                {
                    await observer.OnNextAsync(e).ConfigureAwait(false);
                });

                var converted = conversion(handler);

                addHandler(converted);

                return Task.FromResult(AsyncDisposable.Create(() =>
                {
                    removeHandler(converted);

                    return Task.CompletedTask;
                }));
            }),
                     scheduler
                     ));
        }
        public void GetAsyncService_DisposeAsyncOnSameThread_ThrowsAndDoesNotHangAndDisposeAsyncGetsCalled()
        {
            // Arrange
            var services = new ServiceCollection();
            var asyncDisposableResource = new AsyncDisposable();

            services.AddSingleton <DisposeServiceProviderInCtorAsyncDisposable>(sp =>
                                                                                new DisposeServiceProviderInCtorAsyncDisposable(asyncDisposableResource, sp));

            var  sp          = services.BuildServiceProvider();
            bool doesNotHang = Task.Run(() =>
            {
                SingleThreadedSynchronizationContext.Run(() =>
                {
                    // Act
                    Assert.Throws <ObjectDisposedException>(() =>
                    {
                        // ctor disposes ServiceProvider
                        var service = sp.GetRequiredService <DisposeServiceProviderInCtorAsyncDisposable>();
                    });
                });
            }).Wait(TimeSpan.FromSeconds(10));

            Assert.True(doesNotHang);
            Assert.True(asyncDisposableResource.DisposeAsyncCalled);
        }
        public async Task TestNearCacheTtlEviction()
        {
            var dictionary = await _client.GetDictionaryAsync <int, int>("nc-ttl-" + TestUtils.RandomString());

            await using var _ = new AsyncDisposable(dictionary.DestroyAsync);
            var cache = GetNearCache(dictionary);

            var keys = Enumerable.Range(0, 10).ToList();

            foreach (var k in keys)
            {
                await dictionary.SetAsync(k, k);
            }

            await dictionary.GetAsync(keys);

            Assert.AreEqual(keys.Count, cache.Count);

            await AssertEx.SucceedsEventually(async() =>
            {
                await dictionary.GetAsync(100); // force ttl check
                foreach (var k in keys)
                {
                    var keyData = ToData(k);
                    Assert.That(await cache.ContainsKeyAsync(keyData), Is.False, $"Key {k} should have expired.");
                }
            }, 8000, 1000);
        }
        /// <summary>
        /// Initializes given editor
        /// </summary>
        /// <returns>the cleanup routine</returns>
        public async ValueTask <IAsyncDisposable> InitializeEditor(RichTextEdit richTextEdit)
        {
            await InitializeJsInterop();

            var dotNetRef = DotNetObjectReference
                            .Create(richTextEdit);

            await jsRuntime.InvokeVoidAsync("blazoriseRichTextEdit.initialize",
                                            dotNetRef,
                                            richTextEdit.ElementRef,
                                            richTextEdit.ReadOnly,
                                            richTextEdit.PlaceHolder,
                                            richTextEdit.Theme == RichTextEditTheme.Snow? "snow" : "bubble",
                                            richTextEdit.SubmitOnEnter,
                                            richTextEdit.ConfigureQuillJsMethod);

            return(AsyncDisposable.Create(async() =>
            {
                var task = DestroyEditor(richTextEdit.EditorRef);

                try
                {
                    await task;
                }
                catch
                {
                    if (!task.IsCanceled)
                    {
                        throw;
                    }
                }

                dotNetRef.Dispose();
            }));
        }
        private async Task TestInvalidateAsync(Func <IHDictionary <string, string>, string, Task> invalidatingAction)
        {
            var dictionary = await _client.GetDictionaryAsync <string, string>("nc-invalidate-" + TestUtils.RandomString());

            await using var _ = new AsyncDisposable(dictionary.DestroyAsync);
            var cache = GetNearCache(dictionary);

            await dictionary.SetAsync("key", "value");

            var value = await dictionary.GetAsync("key");

            Assert.AreEqual("value", value);

            Assert.AreEqual(1, cache.Count);
            Assert.AreEqual(cache.Count, cache.Statistics.EntryCount);

            await using (var client = await CreateAndStartClientAsync())
            {
                await invalidatingAction(await client.GetDictionaryAsync <string, string>(dictionary.Name), "key");
            }

            var keyData = ToData("key");

            await AssertEx.SucceedsEventually(async() =>
            {
                Assert.IsFalse(await cache.ContainsKeyAsync(keyData), "Key should have been invalidated");
            }, 8000, 1000);
        }
示例#11
0
        public async Task <IAsyncDisposable> SubscribeAsync(IAsyncObserver <T> observer)
        {
            if (observer == null)
            {
                throw new ArgumentNullException(nameof(observer));
            }

            bool      hasValue;
            T         value;
            bool      done;
            Exception error;

            lock (_gate)
            {
                done  = _done;
                error = _error;

                hasValue = _hasValue;
                value    = _value;

                if (!done && error == null)
                {
                    _observers.Add(observer);
                }
            }

            if (error != null)
            {
                await observer.OnErrorAsync(error).ConfigureAwait(false);

                return(AsyncDisposable.Nop);
            }
            else if (done)
            {
                if (hasValue)
                {
                    await observer.OnNextAsync(value).ConfigureAwait(false);
                }

                await observer.OnCompletedAsync().ConfigureAwait(false);

                return(AsyncDisposable.Nop);
            }

            return(AsyncDisposable.Create(() =>
            {
                lock (_gate)
                {
                    var i = _observers.LastIndexOf(observer);

                    if (i >= 0)
                    {
                        _observers.RemoveAt(i);
                    }
                }

                return Task.CompletedTask;
            }));
        }
        public async Task Dispose_InvokesAction()
        {
            bool actionInvoked = false;
            var  disposable    = AsyncDisposable.Create(async() => { actionInvoked = true; });
            await disposable.DisposeAsync();

            Assert.True(actionInvoked);
        }
    public static void Explain(this AsyncDisposable runnable, TextWriter writer)
    {
        writer.WriteLine(@"
- `Stream`, `Utf8JsonWriter`, `System.Threading.Timer`, `CancellationTokenRegistration`, `BinaryWriter`, `TextWriter` and `IAsyncEnumerator<T>` implement `IAsyncDisposable`
- `Stream`, `BinaryWriter`, `TextWriter`  calls `.Dispose` synchronously
- `Stream` `FlushAsync` calls `Flush` on another thread which is bad behavior that should be overwritten
");
    }
示例#14
0
        public static IAsyncObservable <TResult> UsingAwaitAsync <TResult, TResource>(Func <Task <TResource> > resourceFactory, Func <TResource, Task <IAsyncObservable <TResult> > > observableFactory)
            where TResource : IAsyncDisposable
        {
            if (resourceFactory == null)
            {
                throw new ArgumentNullException(nameof(resourceFactory));
            }
            if (observableFactory == null)
            {
                throw new ArgumentNullException(nameof(observableFactory));
            }

            return(Create <TResult>(async observer =>
            {
                TResource resource;
                try
                {
                    resource = await resourceFactory().ConfigureAwait(false);
                }
                catch (Exception ex)
                {
                    await observer.OnErrorAsync(ex).ConfigureAwait(false);
                    return AsyncDisposable.Nop;
                }

                IAsyncObservable <TResult> observable;
                try
                {
                    observable = await observableFactory(resource).ConfigureAwait(false);
                }
                catch (Exception ex)
                {
                    try
                    {
                        await observer.OnErrorAsync(ex).ConfigureAwait(false);
                        return AsyncDisposable.Nop;
                    }
                    finally
                    {
                        await resource.DisposeAsync().ConfigureAwait(false);
                    }
                }

                var subscription = await observable.SubscribeSafeAsync(observer).ConfigureAwait(false);

                return AsyncDisposable.Create(async() =>
                {
                    try
                    {
                        await subscription.DisposeAsync().ConfigureAwait(false);
                    }
                    finally
                    {
                        await resource.DisposeAsync().ConfigureAwait(false);
                    }
                });
            }));
        }
        /// <summary>
        /// Temporary enables a static result for an action with the given <paramref name="actionName"/> on the logic app,
        /// and disables the static result when the returned instance gets disposed.
        /// </summary>
        /// <param name="actionName">The name of the action to enable the static result.</param>
        /// <param name="definition">The definition that describes the static result for the action.</param>
        /// <returns>
        ///     An instance to control when the static result for the action on the logic app should be disabled.
        /// </returns>
        public async Task<IAsyncDisposable> TemporaryEnableStaticResultAsync(string actionName, StaticResultDefinition definition)
        {
            Guard.NotNullOrEmpty(actionName, nameof(actionName));
            Guard.NotNull(definition, nameof(definition));

            return await AsyncDisposable.CreateAsync(
                async () => await EnableStaticResultForActionsAsync(new Dictionary<string, StaticResultDefinition> { [actionName] = definition }),
                async () => await DisableStaticResultForActionAsync(actionName));
        }
示例#16
0
        public async Task AsyncDisposableDisposesAsync()
        {
            var disposable = new AsyncDisposable();

            Assert.IsFalse(disposable.IsDisposed);
            await disposable.UsingAsync(() => { });

            Assert.IsTrue(disposable.IsDisposed);
        }
示例#17
0
        /// <summary>
        /// Enables static results for a given set of actions on the logic app.
        /// </summary>
        /// <param name="actions">The set of action names and the corresponding static result.</param>
        /// <returns>
        ///     An instance to control when the static result for the actions on the logic app should be disabled.
        /// </returns>
        public async Task <IAsyncDisposable> TemporaryEnableStaticResultsAsync(IDictionary <string, StaticResultDefinition> actions)
        {
            Guard.NotNull(actions, nameof(actions));
            Guard.NotAny(actions, nameof(actions));

            return(await AsyncDisposable.CreateAsync(
                       async() => await EnableStaticResultForActionsAsync(actions),
                       async() => await DisableStaticResultsForActionsAsync(actions.Keys)));
        }
        public async Task MultipleDispose_OnlyInvokesActionOnce()
        {
            var counter    = 0;
            var disposable = AsyncDisposable.Create(async() => { ++counter; });
            await disposable.DisposeAsync();

            await disposable.DisposeAsync();

            Assert.Equal(1, counter);
        }
        public async Task Dispose_AfterAddingNull_DoesNotThrow()
        {
            bool action1Invoked = false;
            var  disposable     = AsyncDisposable.Create(async() => { action1Invoked = true; });
            await disposable.AddAsync(null);

            await disposable.DisposeAsync();

            Assert.True(action1Invoked);
        }
        public async Task TestNearCacheLfuEviction()
        {
            var dictionary = await _client.GetDictionaryAsync <object, object>("nc-lfu-" + TestUtils.RandomString());

            await using var _ = new AsyncDisposable(dictionary.DestroyAsync);
            var cache = GetNearCache(dictionary);

            var keys = new List <object>();

            for (var i = 0; i < MaxSize; i++)
            {
                await dictionary.SetAsync(i, i);

                keys.Add(i);
            }

            // make sure all keys are cached
            await dictionary.GetAsync(keys);

            // make keys in sublist accessed again
            var subList = keys.Take(MaxSize / 2).ToList();
            await dictionary.GetAsync(subList);

            // Add another item, triggering eviction
            await dictionary.SetAsync(MaxSize, MaxSize);

            await dictionary.GetAsync(MaxSize);

            // var sl = new SortedList<int, int>();
            //
            // foreach (var cacheRecord in cache.Records.Keys)
            // {
            //     sl.Add(ClientInternal.SerializationService.ToObject<int>(cacheRecord), 0);
            // }

            // foreach (var lazy in cache.Records.Values)
            // {
            //     if (lazy.Value.Hit.Get() > 0)
            //     {
            //         Console.WriteLine($"non zero hit {ClientInternal.SerializationService.ToObject<int>(lazy.Value.Key)}");
            //     }
            // }

            await AssertEx.SucceedsEventually(async() =>
            {
                Assert.IsTrue(cache.Count <= MaxSize, cache.Count + " should be less than " + MaxSize);
                Assert.AreEqual(cache.Count, cache.Statistics.EntryCount);

                foreach (var key in subList)
                {
                    var keyData = ToData(key);
                    Assert.IsTrue(await cache.ContainsKeyAsync(keyData), "key " + key + " not found in cache");
                }
            }, 8000, 1000);
        }
示例#21
0
        private static async Task Main()
        {
            var asyncDisposable = new AsyncDisposable();
            await asyncDisposable.DisposeAsync();

            _ = new ExampleClass("test").WriteSpans().DoSerialize();

            await ExampleClass.DoAsyncNumbersAsync();

            Console.WriteLine($"The character 7 {('7'.IsLetter() ? "is" : "is not")} a letter");
        }
        public async Task Dispose_AfterAdd_InvokesBothActions()
        {
            bool action1Invoked = false;
            bool action2Invoked = false;
            var  disposable     = AsyncDisposable.Create(async() => { action1Invoked = true; });
            await disposable.AddAsync(async() => { action2Invoked = true; });

            await disposable.DisposeAsync();

            Assert.True(action1Invoked);
            Assert.True(action2Invoked);
        }
        public async Task TestNearCacheIdleEviction()
        {
            var dictionary = await _client.GetDictionaryAsync <int, int>("nc-idle-" + TestUtils.RandomString());

            await using var _ = new AsyncDisposable(dictionary.DestroyAsync);
            var cache = GetNearCache(dictionary);

            var keys = Enumerable.Range(0, 10).ToList();

            foreach (var k in keys)
            {
                await dictionary.SetAsync(k, k);
            }
            Assert.AreEqual(0, cache.Count); // cache is still empty
            Assert.AreEqual(cache.Count, cache.Statistics.EntryCount);

            const int nonIdleKey = 100;
            await dictionary.SetAsync(nonIdleKey, nonIdleKey);

            Assert.AreEqual(0, cache.Count); // cache is still empty
            Assert.AreEqual(cache.Count, cache.Statistics.EntryCount);

            await dictionary.GetAsync(keys);          // populates the cache

            Assert.AreEqual(keys.Count, cache.Count); // which only contains the 10 keys
            Assert.AreEqual(cache.Count, cache.Statistics.EntryCount);

            await dictionary.GetAsync(nonIdleKey);        // also the non-idle key

            Assert.AreEqual(keys.Count + 1, cache.Count); // now also contains the idle key
            Assert.AreEqual(cache.Count, cache.Statistics.EntryCount);

            var nonIdleKeyData = ToData(nonIdleKey);

            await AssertEx.SucceedsEventually(async() =>
            {
                var val = await dictionary.GetAsync(nonIdleKey); // force ttl check
                Assert.That(val, Is.EqualTo(100));

                // note: ContainsKeyAsync(, false) to make sure we don't hit the entries,
                // else they would never ever become idle of course...

                // idle keys are going away
                foreach (var k in keys)
                {
                    var keyData = ToData(k);
                    Assert.IsFalse(await cache.ContainsKeyAsync(keyData, false), "Key " + k + " should have expired.");
                }

                // non-idle key is never going away
                Assert.IsTrue(await cache.ContainsKeyAsync(nonIdleKeyData, false), "Key 100 should not have expired.");
            }, 8000, 200);
        }
示例#24
0
        public async Task <IAsyncDisposable> ServeAsync()
        {
            var host = Host;
            await host.StartAsync().ConfigureAwait(false);

            // ReSharper disable once HeapView.BoxingAllocation
            return(AsyncDisposable.New(async self => {
                var host1 = self.Host;
                await host1.StopAsync().SuppressExceptions().ConfigureAwait(false);
                Task.Run(() => host1.Dispose()).Ignore();
                self.HostLazy = new Lazy <IHost>(CreateHost);
            }, this));
        }
示例#25
0
 /// <summary>
 /// Temporary disables the current logic app resource on Azure, and enables the logic app after the returned instance gets disposed.
 /// </summary>
 /// <returns>
 ///     An instance to control the removal of the updates.
 /// </returns>
 public async Task <IAsyncDisposable> TemporaryDisableAsync()
 {
     return(await AsyncDisposable.CreateAsync(
                async() =>
     {
         _logger.LogTrace("Disables (-) the workflow on logic app '{LogicAppName}' in resource group '{ResourceGroup}'", _logicAppName, _resourceGroup);
         await _logicManagementClient.Workflows.DisableAsync(_resourceGroup, _logicAppName);
     },
                async() =>
     {
         _logger.LogTrace("Enables (+) the workflow on logic app '{LogicAppName}' in resource group '{ResourceGroup}'", _logicAppName, _resourceGroup);
         await _logicManagementClient.Workflows.EnableAsync(_resourceGroup, _logicAppName);
     }));
 }
        /// <summary>
        /// Updates the current JSON logic app definition with the given <paramref name="logicAppDefinition"/>,
        /// and removes this update after the returned instance gets disposed.
        /// </summary>
        /// <param name="logicAppDefinition">Then JSON representation of the new definition.</param>
        /// <returns>
        ///     An instance to control the removal of the updates.
        /// </returns>
        public async Task<IAsyncDisposable> TemporaryUpdateAsync(string logicAppDefinition)
        {
            Guard.NotNull(logicAppDefinition, nameof(logicAppDefinition));

            Workflow workflow = await _logicManagementClient.Workflows.GetAsync(_resourceGroup, _logicAppName);
            object originalAppDefinition = workflow.Definition;

            _logger.LogTrace("Updates (+) the logic app '{LogicAppName}' workflow definition in resource group '{ResourceGroup}'", _logicAppName, _resourceGroup);
            await UpdateAsync(workflow, JObject.Parse(logicAppDefinition));
            return AsyncDisposable.Create(async () =>
            {
                _logger.LogTrace("Reverts (-) the update of the logic app '{LogicAppName}' workflow definition in resource group '{ResourceGroup}'", _logicAppName, _resourceGroup);
                await UpdateAsync(workflow, originalAppDefinition);
            });
        }
示例#27
0
        public async Task AsyncDisposableThrowsOnceDisposedAsync()
        {
            var disposable = new AsyncDisposable();
            await disposable.UsingAsync(() => { });

            var threwObjectDisposed = false;

            try
            {
                disposable.RequiresNotDisposed();
            }
            catch (ObjectDisposedException)
            {
                threwObjectDisposed = true;
            }
            Assert.IsTrue(threwObjectDisposed);
        }
示例#28
0
        public static IAsyncObservable <TSource> SubscribeOn <TSource>(this IAsyncObservable <TSource> source, IAsyncScheduler subscribeScheduler, IAsyncScheduler disposeScheduler)
        {
            if (source == null)
            {
                throw new ArgumentNullException(nameof(source));
            }
            if (subscribeScheduler == null)
            {
                throw new ArgumentNullException(nameof(subscribeScheduler));
            }
            if (disposeScheduler == null)
            {
                throw new ArgumentNullException(nameof(disposeScheduler));
            }

            return(CreateAsyncObservable <TSource> .From(
                       source,
                       (subscribeScheduler, disposeScheduler),
                       static async (source, state, observer) =>
            {
                var m = new SingleAssignmentAsyncDisposable();
                var d = new SerialAsyncDisposable();

                await d.AssignAsync(m).ConfigureAwait(false);

                var scheduled = await state.subscribeScheduler.ScheduleAsync(async ct =>
                {
                    var subscription = await source.SubscribeSafeAsync(observer).RendezVous(state.subscribeScheduler, ct);

                    var scheduledDispose = AsyncDisposable.Create(async() =>
                    {
                        await state.disposeScheduler.ScheduleAsync(async _ =>
                        {
                            await subscription.DisposeAsync().RendezVous(state.disposeScheduler, ct);
                        }).ConfigureAwait(false);
                    });

                    await d.AssignAsync(scheduledDispose).RendezVous(state.subscribeScheduler, ct);
                }).ConfigureAwait(false);

                await m.AssignAsync(scheduled).ConfigureAwait(false);

                return d;
            }));
        }
        public async Task Actions_ExecutingInSerial_ExecuteInSerial()
        {
            bool running    = false;
            var  disposable = new AsyncDisposable(null);

            for (int i = 0; i != 10; ++i)
            {
                await disposable.AddAsync(async() =>
                {
                    Assert.False(running);
                    running = true;
                    await Task.Delay(10);
                    running = false;
                });
            }

            await disposable.DisposeAsync();
        }
        public async Task TestNearCacheGet() // CacheIsPopulatedByRead
        {
            var dictionary = await _client.GetDictionaryAsync <object, object>("nc-" + TestUtils.RandomString());

            await using var _ = new AsyncDisposable(dictionary.DestroyAsync);
            var cache = GetNearCache(dictionary);

            // add a vale to the dictionary
            await dictionary.SetAsync("key", "value");

            // get the value = populates the cache
            await dictionary.GetAsync("key");

            // validate that the value is in the cache
            var getAttempt = await cache.TryGetAsync(ToData("key"));

            Assert.That(getAttempt.Success, Is.True);
            Assert.That(getAttempt.Value, Is.EqualTo("value"));
        }
        public void TestUsing1_CanceledResource_CanceledBody_AsyncDisposable()
        {
            bool executed = false;
            AsyncDisposable resourceObject = null;

            // declaring these makes it clear we are testing the correct overload
            Func<Task<IDisposable>> resource = () =>
                {
                    resourceObject = new AsyncDisposable();
                    return CompletedTask.Canceled<IDisposable>();
                };

            CancellationTokenSource cts = new CancellationTokenSource();
            Func<Task<IDisposable>, Task> body = task =>
                Task.Factory.StartNew(
                    () =>
                    {
                        executed = true;
                        cts.Cancel();
                        cts.Token.ThrowIfCancellationRequested();
                    }, cts.Token);

            Task combinedTask = null;

            try
            {
                combinedTask = TaskBlocks.Using(resource, body);
                combinedTask.Wait();
                Assert.Fail("Expected a TaskCanceledException wrapped in an AggregateException");
            }
            catch (AggregateException ex)
            {
                Assert.IsNotNull(combinedTask, "Failed to create the combined task.");
                Assert.AreEqual(TaskStatus.Canceled, combinedTask.Status);
                Assert.AreEqual(1, ex.InnerExceptions.Count);
                Assert.IsInstanceOfType(ex.InnerExceptions[0], typeof(TaskCanceledException));
                Assert.IsNotNull(resourceObject);
                Assert.IsFalse(resourceObject.Disposed);
                Assert.IsFalse(resourceObject.AsyncDisposed);
                Assert.IsFalse(executed);
            }
        }
        public void TestUsing1_CompletedResource_NullBody_AsyncDisposable()
        {
            bool executed = false;
            AsyncDisposable resourceObject = null;

            // declaring these makes it clear we are testing the correct overload
            Func<Task<IDisposable>> resource = () =>
                {
                    resourceObject = new AsyncDisposable();
                    return CompletedTask.FromResult<IDisposable>(resourceObject);
                };

            Func<Task<IDisposable>, Task> body = task =>
                {
                    executed = true;
                    return null;
                };

            Task combinedTask = null;

            try
            {
                combinedTask = TaskBlocks.Using(resource, body);
                combinedTask.Wait();
                Assert.Fail("Expected an TaskCanceledException wrapped in an AggregateException");
            }
            catch (AggregateException ex)
            {
                Assert.IsNotNull(combinedTask, "Failed to create the combined task.");
                Assert.AreEqual(TaskStatus.Canceled, combinedTask.Status);
                Assert.AreEqual(1, ex.InnerExceptions.Count);
                Assert.IsInstanceOfType(ex.InnerExceptions[0], typeof(TaskCanceledException));
                Assert.IsNotNull(resourceObject);
                Assert.IsTrue(resourceObject.Disposed);
                Assert.IsTrue(resourceObject.AsyncDisposed);
                Assert.IsTrue(executed);
            }
        }
        public void TestUsing1_CompletedResource_FaultedBody_AsyncDisposable()
        {
            bool executed = false;
            AsyncDisposable resourceObject = null;

            // declaring these makes it clear we are testing the correct overload
            Func<Task<IDisposable>> resource = () =>
                {
                    resourceObject = new AsyncDisposable();
                    return CompletedTask.FromResult<IDisposable>(resourceObject);
                };

            Exception bodyException = new InvalidOperationException();
            Func<Task<IDisposable>, Task> body = task =>
                Task.Factory.StartNew(() =>
                {
                    executed = true;
                    throw bodyException;
                });

            Task combinedTask = null;

            try
            {
                combinedTask = TaskBlocks.Using(resource, body);
                combinedTask.Wait();
                Assert.Fail("Expected an InvalidOperationException wrapped in an AggregateException");
            }
            catch (AggregateException ex)
            {
                Assert.IsNotNull(combinedTask, "Failed to create the combined task.");
                Assert.AreEqual(TaskStatus.Faulted, combinedTask.Status);
                Assert.AreEqual(1, ex.InnerExceptions.Count);
                Assert.AreSame(bodyException, ex.InnerExceptions[0]);
                Assert.IsNotNull(resourceObject);
                Assert.IsTrue(resourceObject.Disposed);
                Assert.IsTrue(resourceObject.AsyncDisposed);
                Assert.IsTrue(executed);
            }
        }
        public void TestUsing1_CompletedResource_CompletedBody_AsyncDisposable()
        {
            bool executed = false;
            AsyncDisposable resourceObject = null;

            // declaring these makes it clear we are testing the correct overload
            Func<Task<IDisposable>> resource = () =>
                {
                    resourceObject = new AsyncDisposable();
                    return CompletedTask.FromResult<IDisposable>(resourceObject);
                };
            Func<Task<IDisposable>, Task> body = task => Task.Factory.StartNew(() => executed = true);

            Task combinedTask = TaskBlocks.Using(resource, body);
            combinedTask.Wait();
            Assert.AreEqual(TaskStatus.RanToCompletion, combinedTask.Status);
            Assert.IsNotNull(resourceObject);
            Assert.IsTrue(resourceObject.Disposed);
            Assert.IsTrue(resourceObject.AsyncDisposed);
            Assert.IsTrue(executed);
        }