public void ExpiredLazyTriggerRemovesItemInBackground()
        {
            var clock = new TestClock();
            var cache = CreateCache(clock);
            string key = "myKey";
            var value = new object();
            var callbackInvoked = new ManualResetEvent(false);
            var trigger = new TestTrigger() { ActiveExpirationCallbacks = false };
            cache.Set(key, value, new MemoryCacheEntryOptions()
                .AddExpirationTrigger(trigger)
                .RegisterPostEvictionCallback((subkey, subValue, reason, state) =>
            {
                // TODO: Verify params
                var localCallbackInvoked = (ManualResetEvent)state;
                localCallbackInvoked.Set();
            }, state: callbackInvoked));
            var found = cache.TryGetValue(key, out value);
            Assert.True(found);

            clock.Add(TimeSpan.FromMinutes(2));
            trigger.IsExpired = true;
            var ignored = cache.Get("otherKey"); // Background expiration checks are triggered by misc cache activity.
            Assert.True(callbackInvoked.WaitOne(TimeSpan.FromSeconds(30)), "Callback");

            found = cache.TryGetValue(key, out value);
            Assert.False(found);
        }
        public void ExpiredLazyTriggerRemovesItemOnNextAccess()
        {
            var cache = CreateCache();
            string key = "myKey";
            var value = new object();
            var callbackInvoked = new ManualResetEvent(false);
            var trigger = new TestTrigger() { ActiveExpirationCallbacks = false };
            cache.Set(key, value, new MemoryCacheEntryOptions()
                .AddExpirationTrigger(trigger)
                .RegisterPostEvictionCallback((subkey, subValue, reason, state) =>
                {
                    // TODO: Verify params
                    var localCallbackInvoked = (ManualResetEvent)state;
                    localCallbackInvoked.Set();
                }, state: callbackInvoked));

            var found = cache.TryGetValue(key, out value);
            Assert.True(found);

            trigger.IsExpired = true;

            found = cache.TryGetValue(key, out value);
            Assert.False(found);

            Assert.True(callbackInvoked.WaitOne(TimeSpan.FromSeconds(30)), "Callback");
        }
        public void AbsoluteExpiration_WorksAcrossLink()
        {
            var clock = new TestClock();
            var cache = CreateCache(clock);
            var obj = new object();
            string key = "myKey";
            string key1 = "myKey1";
            var trigger = new TestTrigger() { ActiveExpirationCallbacks = true };

            using (var link = cache.CreateLinkingScope())
            {
                cache.Set(key, obj, new MemoryCacheEntryOptions().SetAbsoluteExpiration(TimeSpan.FromSeconds(5)));

                cache.Set(key1, obj, new MemoryCacheEntryOptions().AddEntryLink(link));
            }

            Assert.StrictEqual(obj, cache.Get(key));
            Assert.StrictEqual(obj, cache.Get(key1));

            clock.Add(TimeSpan.FromSeconds(10));

            object value;
            Assert.False(cache.TryGetValue(key1, out value));
            Assert.False(cache.TryGetValue(key, out value));
        }
        public void AddExpiredTriggerPreventsCaching()
        {
            var cache = CreateCache();
            string key = "myKey";
            var value = new object();
            var callbackInvoked = new ManualResetEvent(false);
            var trigger = new TestTrigger() { IsExpired = true };
            var result = cache.Set(key, value, new MemoryCacheEntryOptions()
                .AddExpirationTrigger(trigger)
                .RegisterPostEvictionCallback((subkey, subValue, reason, state) =>
            {
                // TODO: Verify params
                var localCallbackInvoked = (ManualResetEvent)state;
                localCallbackInvoked.Set();
            }, state: callbackInvoked));
            Assert.Same(value, result); // The created item should be returned, but not cached.

            Assert.True(trigger.IsExpiredWasCalled);
            Assert.False(trigger.ActiveExpirationCallbacksWasCalled);
            Assert.Null(trigger.Registration);
            Assert.True(callbackInvoked.WaitOne(TimeSpan.FromSeconds(30)), "Callback");

            result = cache.Get(key);
            Assert.Null(result); // It wasn't cached
        }
        public void GetWithImplicitLinkPopulatesTriggers()
        {
            var cache = CreateCache();
            var obj = new object();
            string key = "myKey";
            string key1 = "myKey1";

            Assert.Null(EntryLinkHelpers.ContextLink);

            IEntryLink link;
            using (link = cache.CreateLinkingScope())
            {
                Assert.StrictEqual(link, EntryLinkHelpers.ContextLink);
                var trigger = new TestTrigger() { ActiveExpirationCallbacks = true };
                cache.Set(key, obj, new MemoryCacheEntryOptions().AddExpirationTrigger(trigger));
            }

            Assert.Null(EntryLinkHelpers.ContextLink);

            Assert.Equal(1, link.Triggers.Count());
            Assert.Null(link.AbsoluteExpiration);

            cache.Set(key1, obj, new MemoryCacheEntryOptions().AddEntryLink(link));
        }
        public void SetWithTriggerRegistersForNotificaiton()
        {
            var cache = CreateCache();
            string key = "myKey";
            var value = new object();
            var trigger = new TestTrigger() { ActiveExpirationCallbacks = true };
            cache.Set(key, value, new MemoryCacheEntryOptions().AddExpirationTrigger(trigger));

            Assert.True(trigger.IsExpiredWasCalled);
            Assert.True(trigger.ActiveExpirationCallbacksWasCalled);
            Assert.NotNull(trigger.Registration);
            Assert.NotNull(trigger.Registration.RegisteredCallback);
            Assert.NotNull(trigger.Registration.RegisteredState);
            Assert.False(trigger.Registration.Disposed);
        }
        public void SetWithLazyTriggerDoesntRegisterForNotification()
        {
            var cache = CreateCache();
            string key = "myKey";
            var value = new object();
            var trigger = new TestTrigger() { ActiveExpirationCallbacks = false };
            cache.Set(key, value, new MemoryCacheEntryOptions().AddExpirationTrigger(trigger));

            Assert.True(trigger.IsExpiredWasCalled);
            Assert.True(trigger.ActiveExpirationCallbacksWasCalled);
            Assert.Null(trigger.Registration);
        }
        public void RemoveItemDisposesTriggerRegistration()
        {
            var cache = CreateCache();
            string key = "myKey";
            var value = new object();
            var callbackInvoked = new ManualResetEvent(false);
            var trigger = new TestTrigger() { ActiveExpirationCallbacks = true };
            cache.Set(key, value, new MemoryCacheEntryOptions()
                .AddExpirationTrigger(trigger)
                .RegisterPostEvictionCallback((subkey, subValue, reason, state) =>
            {
                // TODO: Verify params
                var localCallbackInvoked = (ManualResetEvent)state;
                localCallbackInvoked.Set();
            }, state: callbackInvoked));
            cache.Remove(key);

            Assert.NotNull(trigger.Registration);
            Assert.True(trigger.Registration.Disposed);
            Assert.True(callbackInvoked.WaitOne(TimeSpan.FromSeconds(30)), "Callback");
        }
        public void LinkContextsCanNest()
        {
            var cache = CreateCache();
            var obj = new object();
            string key = "myKey";
            string key1 = "myKey1";

            Assert.Null(EntryLinkHelpers.ContextLink);

            IEntryLink link1;
            IEntryLink link2;
            using (link1 = cache.CreateLinkingScope())
            {
                Assert.StrictEqual(link1, EntryLinkHelpers.ContextLink);

                using (link2 = cache.CreateLinkingScope())
                {
                    Assert.StrictEqual(link2, EntryLinkHelpers.ContextLink);

                    var trigger = new TestTrigger() { ActiveExpirationCallbacks = true };
                    cache.Set(key, obj, new MemoryCacheEntryOptions().AddExpirationTrigger(trigger));
                }

                Assert.StrictEqual(link1, EntryLinkHelpers.ContextLink);
            }

            Assert.Null(EntryLinkHelpers.ContextLink);

            Assert.Equal(0, link1.Triggers.Count());
            Assert.Null(link1.AbsoluteExpiration);
            Assert.Equal(1, link2.Triggers.Count());
            Assert.Null(link2.AbsoluteExpiration);

            cache.Set(key1, obj, new MemoryCacheEntryOptions().AddEntryLink(link2));
        }
        public void TriggerExpires_LinkedEntry()
        {
            var cache = CreateCache();
            var obj = new object();
            string key = "myKey";
            string key1 = "myKey1";
            var trigger = new TestTrigger() { ActiveExpirationCallbacks = true };

            using (var link = cache.CreateLinkingScope())
            {
                cache.Set(key, obj, new MemoryCacheEntryOptions().AddExpirationTrigger(trigger));

                cache.Set(key1, obj, new MemoryCacheEntryOptions().AddEntryLink(link));
            }

            Assert.StrictEqual(obj, cache.Get(key));
            Assert.StrictEqual(obj, cache.Get(key1));

            trigger.Fire();

            object value;
            Assert.False(cache.TryGetValue(key1, out value));
            Assert.False(cache.TryGetValue(key, out value));
        }
        public void SetPopulates_Triggers_IntoScopedLink()
        {
            var cache = CreateCache();
            var obj = new object();
            string key = "myKey";

            IEntryLink linkScope1;
            using (linkScope1 = cache.CreateLinkingScope())
            {
                Assert.Same(linkScope1, EntryLinkHelpers.ContextLink);

                var trigger = new TestTrigger() { ActiveExpirationCallbacks = true };
                cache.Set(key, obj, new MemoryCacheEntryOptions().AddExpirationTrigger(trigger));
            }

            Assert.Equal(1, linkScope1.Triggers.Count());
            Assert.Null(linkScope1.AbsoluteExpiration);
        }
        public void SetPopulates_AbsoluteExpiration_IntoScopeLink()
        {
            var cache = CreateCache();
            var obj = new object();
            string key = "myKey";
            var time = new DateTimeOffset(2051, 1, 1, 1, 1, 1, TimeSpan.Zero);

            IEntryLink linkScope1;
            using (linkScope1 = cache.CreateLinkingScope())
            {
                Assert.Same(linkScope1, EntryLinkHelpers.ContextLink);

                var trigger = new TestTrigger() { ActiveExpirationCallbacks = true };
                cache.Set(key, obj, new MemoryCacheEntryOptions().SetAbsoluteExpiration(time));
            }

            Assert.Equal(0, linkScope1.Triggers.Count());
            Assert.NotNull(linkScope1.AbsoluteExpiration);
            Assert.Equal(time, linkScope1.AbsoluteExpiration);
        }
        public void NestedLinkContextsCanAggregate()
        {
            var clock = new TestClock();
            var cache = CreateCache(clock);
            var obj = new object();
            string key2 = "myKey2";
            string key3 = "myKey3";

            var trigger2 = new TestTrigger() { ActiveExpirationCallbacks = true };
            var trigger3 = new TestTrigger() { ActiveExpirationCallbacks = true };

            IEntryLink link1 = null;
            IEntryLink link2 = null;

            using (link1 = cache.CreateLinkingScope())
            {
                cache.Set(key2, obj, new MemoryCacheEntryOptions()
                    .AddExpirationTrigger(trigger2)
                    .SetAbsoluteExpiration(TimeSpan.FromSeconds(10)));

                using (link2 = cache.CreateLinkingScope())
                {
                    cache.Set(key3, obj, new MemoryCacheEntryOptions()
                        .AddExpirationTrigger(trigger3)
                        .SetAbsoluteExpiration(TimeSpan.FromSeconds(15)));
                }
            }

            Assert.Equal(1, link1.Triggers.Count());
            Assert.NotNull(link1.AbsoluteExpiration);
            Assert.Equal(clock.UtcNow + TimeSpan.FromSeconds(10), link1.AbsoluteExpiration);

            Assert.Equal(1, link2.Triggers.Count());
            Assert.NotNull(link2.AbsoluteExpiration);
            Assert.Equal(clock.UtcNow + TimeSpan.FromSeconds(15), link2.AbsoluteExpiration);
        }