public void CachedAllUsesFreshValuesIfThereHasBeenAnUpdate()
        {
            var wrapper = MakeWrapper(true);
            var key1    = "flag1";
            var item1   = new MockItem(key1, 1, false);
            var item1v2 = new MockItem(key1, 2, false);
            var key2    = "flag2";
            var item2   = new MockItem(key2, 1, false);
            var item2v2 = new MockItem(key2, 2, false);

            var allData = MakeData(item1, item2);

            wrapper.Init(allData);

            // make a change to item1 via the wrapper - this should flush the cache
            wrapper.Upsert(MockItem.Kind, item1v2);

            // make a change to item2 that bypasses the cache
            _core.ForceSet(MockItem.Kind, item2v2);

            // we should now see both changes since the cache was flushed
            var items    = wrapper.All(MockItem.Kind);
            var expected = new Dictionary <string, MockItem>()
            {
                { key1, item1v2 },
                { key2, item2v2 }
            };

            Assert.Equal(expected, items);
        }
        public void UpsertSuccessful(bool cached)
        {
            var wrapper = MakeWrapper(cached);
            var key     = "flag";
            var itemv1  = new MockItem(key, 1, false);
            var itemv2  = new MockItem(key, 2, false);

            wrapper.Upsert(MockItem.Kind, itemv1);
            var internalItem1 = (MockItem)_core.Data[MockItem.Kind][key];

            Assert.Equal(itemv1, internalItem1);

            wrapper.Upsert(MockItem.Kind, itemv2);
            var internalItem2 = (MockItem)_core.Data[MockItem.Kind][key];

            Assert.Equal(itemv2, internalItem2);

            // if we have a cache, verify that the new item is now cached by writing a different value
            // to the underlying data - Get should still return the cached item
            if (cached)
            {
                MockItem item1v3 = new MockItem(key, 3, false);
                _core.ForceSet(MockItem.Kind, item1v3);
            }

            Assert.Equal(itemv2, wrapper.Get(MockItem.Kind, key));
        }
        public void GetAll(bool cached)
        {
            var wrapper = MakeWrapper(cached);
            var item1   = new MockItem("flag1", 1, false);
            var item2   = new MockItem("flag2", 1, false);

            _core.ForceSet(MockItem.Kind, item1);
            _core.ForceSet(MockItem.Kind, item2);

            var items    = wrapper.All(MockItem.Kind);
            var expected = new Dictionary <String, MockItem>()
            {
                { item1.Key, item1 },
                { item2.Key, item2 }
            };

            Assert.Equal(expected, items);

            _core.ForceRemove(MockItem.Kind, item2.Key);
            items = wrapper.All(MockItem.Kind);
            if (cached)
            {
                Assert.Equal(expected, items);
            }
            else
            {
                var expected1 = new Dictionary <string, MockItem>()
                {
                    { item1.Key, item1 }
                };
                Assert.Equal(expected1, items);
            }
        }
        public void CachedStoreWithFiniteTtlDoesNotUpdateCacheIfCoreInitFails()
        {
            var wrapper = MakeWrapper(Cached);
            var key     = "flag";
            var item    = new MockItem(key, 1, false);

            _core.Error = FakeError;
            Assert.Throws(FakeError.GetType(), () => wrapper.Init(MakeData(item)));

            _core.Error = null;
            Assert.Empty(wrapper.All(MockItem.Kind));
        }
        public void CachedGetUsesValuesFromInit()
        {
            var wrapper = MakeWrapper(true);
            var item1   = new MockItem("flag1", 1, false);
            var item2   = new MockItem("flag2", 1, false);

            var allData = MakeData(item1, item2);

            wrapper.Init(allData);

            _core.ForceRemove(MockItem.Kind, item1.Key);

            Assert.Equal(item1, wrapper.Get(MockItem.Kind, item1.Key));
        }
        public void GetItem(bool cached)
        {
            var wrapper = MakeWrapper(cached);
            var itemv1  = new MockItem("flag", 1, false);
            var itemv2  = new MockItem("flag", 2, false);

            _core.ForceSet(MockItem.Kind, itemv1);
            Assert.Equal(wrapper.Get(MockItem.Kind, itemv1.Key), itemv1);

            _core.ForceSet(MockItem.Kind, itemv2);
            var result = wrapper.Get(MockItem.Kind, itemv1.Key);

            Assert.Equal(cached ? itemv1 : itemv2, result); // if cached, we will not see the new underlying value yet
        }
        public void CachedStoreWithInfiniteTtlUpdatesCacheEvenIfCoreUpdateFails()
        {
            var wrapper = MakeWrapper(CachedIndefinitely);
            var key     = "flag";
            var itemv1  = new MockItem(key, 1, false);
            var itemv2  = new MockItem(key, 2, false);

            wrapper.Init(MakeData(itemv1));

            _core.Error = FakeError;
            Assert.Throws(FakeError.GetType(), () => wrapper.Upsert(MockItem.Kind, itemv2));

            _core.Error = null;
            Assert.Equal(itemv2, wrapper.Get(MockItem.Kind, key)); // underlying store has old item but cache has new item
        }
        public void CachedStoreWithFiniteTtlDoesNotUpdateCacheIfCoreUpdateFails()
        {
            var wrapper = MakeWrapper(Cached);
            var key     = "flag";
            var itemv1  = new MockItem(key, 1, false);
            var itemv2  = new MockItem(key, 2, false);

            wrapper.Init(MakeData(itemv1));

            _core.Error = FakeError;
            Assert.Throws(FakeError.GetType(), () => wrapper.Upsert(MockItem.Kind, itemv2));

            _core.Error = null;
            Assert.Equal(itemv1, wrapper.Get(MockItem.Kind, key)); // cache still has old item, same as underlying store
        }
        public void CachedStoreWithInfiniteTtlUpdatesCacheIfCoreInitFails()
        {
            var wrapper = MakeWrapper(CachedIndefinitely);
            var key     = "flag";
            var item    = new MockItem(key, 1, false);

            _core.Error = FakeError;
            Assert.Throws(FakeError.GetType(), () => wrapper.Init(MakeData(item)));

            _core.Error = null;
            var expected = new Dictionary <string, MockItem> {
                { key, item }
            };

            Assert.Equal(expected, wrapper.All(MockItem.Kind));
        }
        public void GetAllRemovesDeletedItems(bool cached)
        {
            var wrapper = MakeWrapper(cached);
            var item1   = new MockItem("flag1", 1, false);
            var item2   = new MockItem("flag2", 1, true);

            _core.ForceSet(MockItem.Kind, item1);
            _core.ForceSet(MockItem.Kind, item2);

            var items    = wrapper.All(MockItem.Kind);
            var expected = new Dictionary <String, MockItem>()
            {
                { item1.Key, item1 }
            };

            Assert.Equal(expected, items);
        }
        public void GetMissingItem(bool cached)
        {
            var wrapper = MakeWrapper(cached);
            var item    = new MockItem("flag", 1, false);

            Assert.Null(wrapper.Get(MockItem.Kind, item.Key));

            _core.ForceSet(MockItem.Kind, item);
            var result = wrapper.Get(MockItem.Kind, item.Key);

            if (cached)
            {
                Assert.Null(result); // the cache can retain a null result
            }
            else
            {
                Assert.Equal(item, result);
            }
        }
        public void CachedAllUsesValuesFromInit()
        {
            var wrapper = MakeWrapper(true);
            var item1   = new MockItem("flag1", 1, false);
            var item2   = new MockItem("flag2", 1, false);

            var allData = MakeData(item1, item2);

            wrapper.Init(allData);
            var expected = new Dictionary <string, MockItem>()
            {
                { item1.Key, item1 },
                { item2.Key, item2 }
            };

            _core.ForceRemove(MockItem.Kind, item1.Key);

            Assert.Equal(expected, wrapper.All(MockItem.Kind));
        }
        public void GetDeletedItem(bool cached)
        {
            var wrapper = MakeWrapper(cached);
            var itemv1  = new MockItem("flag", 1, true);
            var itemv2  = new MockItem("flag", 2, false);

            _core.ForceSet(MockItem.Kind, itemv1);
            Assert.Null(wrapper.Get(MockItem.Kind, itemv1.Key)); // item is filtered out because deleted is true

            _core.ForceSet(MockItem.Kind, itemv2);
            var result = wrapper.Get(MockItem.Kind, itemv1.Key);

            if (cached)
            {
                Assert.Null(result); // if cached, we will not see the new underlying value yet
            }
            else
            {
                Assert.Equal(itemv2, result);
            }
        }
        public void CachedUpsertUnsuccessful()
        {
            var wrapper = MakeWrapper(true);
            var key     = "flag";
            var itemv1  = new MockItem(key, 1, false);
            var itemv2  = new MockItem(key, 2, false);

            wrapper.Upsert(MockItem.Kind, itemv2);
            var internalItem2 = (MockItem)_core.Data[MockItem.Kind][key];

            Assert.Equal(itemv2, internalItem2);

            wrapper.Upsert(MockItem.Kind, itemv1);
            var internalItem1 = (MockItem)_core.Data[MockItem.Kind][key];

            Assert.Equal(itemv2, internalItem1); // value in store remains the same

            var itemv3 = new MockItem(key, 3, false);

            _core.ForceSet(MockItem.Kind, itemv3); // bypasses cache so we can verify that itemv2 is in the cache

            Assert.Equal(itemv2, wrapper.Get(MockItem.Kind, key));
        }
        public void CachedStoreWithFiniteTtlUpdatesCachedAllDataIfOneItemIsUpdated()
        {
            var wrapper = MakeWrapper(CachedIndefinitely);
            var item1v1 = new MockItem("item1", 1, false);
            var item1v2 = new MockItem("item1", 2, false);
            var item2v1 = new MockItem("item2", 1, false);
            var item2v2 = new MockItem("item2", 2, false);

            wrapper.Init(MakeData(item1v1, item2v1));
            wrapper.All(MockItem.Kind); // now the All data is cached

            // do an Upsert for item1 - this should update the underlying data *and* the cached All data
            wrapper.Upsert(MockItem.Kind, item1v2);

            // modify item2 directly in the underlying data
            _core.ForceSet(MockItem.Kind, item2v2);

            // now, All should *not* reread the underlying data - we should only see the change to item1
            var expected = new Dictionary <string, MockItem> {
                { item1v1.Key, item1v2 }, { item2v1.Key, item2v1 }
            };

            Assert.Equal(expected, wrapper.All(MockItem.Kind));
        }
        public void CachedStoreWithFiniteTtlRemovesCachedAllDataIfOneItemIsUpdated()
        {
            var wrapper = MakeWrapper(Cached);
            var item1v1 = new MockItem("item1", 1, false);
            var item1v2 = new MockItem("item1", 2, false);
            var item2v1 = new MockItem("item2", 1, false);
            var item2v2 = new MockItem("item2", 2, false);

            wrapper.Init(MakeData(item1v1, item2v1));
            wrapper.All(MockItem.Kind); // now the All data is cached

            // do an Upsert for item1 - this should drop the previous All data from the cache
            wrapper.Upsert(MockItem.Kind, item1v2);

            // modify item2 directly in the underlying data
            _core.ForceSet(MockItem.Kind, item2v2);

            // now, All should reread the underlying data so we see both changes
            var expected = new Dictionary <string, MockItem> {
                { item1v1.Key, item1v2 }, { item2v1.Key, item2v2 }
            };

            Assert.Equal(expected, wrapper.All(MockItem.Kind));
        }