public async Task Cache_Dist_Test_InMemoryPerformance()
        {
            // Arrange
            var cacheAccessor1 = new CacheAccessor(new CacheConfig {
                IsAuditingEnabled = true
            });
            var cacheAccessor2 = new CacheAccessor(new CacheConfig {
                IsAuditingEnabled = true
            });
            await cacheAccessor1.InitialiseIfNecessaryAsync();

            await cacheAccessor2.InitialiseIfNecessaryAsync();

            var bigList = new List <int>(Enumerable.Range(0, 100000));
            await cacheAccessor1.SetAsync("biglist", bigList);

            var v1 = await cacheAccessor1.GetWithMetaDataAsync <List <int> >("biglist"); // should return instantly from the originating cache accessor (it's in-memory)

            var v2 = await cacheAccessor2.GetWithMetaDataAsync <List <int> >("biglist"); // should return with some delay from the new cache accessor (it's on the central cache)

            var v3 = await cacheAccessor2.GetWithMetaDataAsync <List <int> >("biglist"); // should return instantly, having put the object into in-memory cache the last time it was called

            Assert.IsNotNull(v1.Data);
            Assert.IsTrue(v1.IsFromInMemoryCache, "Shoulda oughta a bin from the in-memory cache");
            Assert.IsNotNull(v2.Data);
            Assert.IsTrue(v2.IsFromCentralCacheServer || v2.IsFromInMemoryCache, "Shoulda oughta a bin from the central / memory cache");
            Assert.IsNotNull(v3.Data);
            Assert.IsTrue(v3.IsFromInMemoryCache, "Shoulda oughta a bin from the in-memory cache");
        }
        public async Task Cache_NonDist_Test_That_Cache_Delete_Key_Works_OK()
        {
            // ARRANGE
            var ca1 = new CacheAccessor(new CacheConfig {
                IsAuditingEnabled = true, IsCentralCacheEnabled = false
            });

            await ca1.InitialiseIfNecessaryAsync();

            var KEY   = CreateGuid();
            var VALUE = CreateGuid();

            // ACT
            await ca1.SetAsync(KEY, VALUE); // set the value

            await ca1.DeleteAsync(KEY);

            var evt1 = ca1.LastCachingEvent;
            var v2   = await ca1.GetWithMetaDataAsync <string>(KEY);

            // ASSERT
            Assert.IsNull(v2.Data);
            Assert.IsTrue(evt1 == eCacheEvent.KeyDeletedInMemory);
            Assert.IsTrue(ca1.LastCachingEvent == eCacheEvent.KeyValueGotFromMemoryAttempt);
        }
        public async Task Cache_Dist_Test_That_Cache_Expiry_Works_OK()
        {
            // ARRANGE
            var ca1 = new CacheAccessor(new CacheConfig {
                IsAuditingEnabled = true
            });
            var ca2 = new CacheAccessor(new CacheConfig {
                IsAuditingEnabled = true
            });

            await ca1.InitialiseIfNecessaryAsync();

            await ca2.InitialiseIfNecessaryAsync();

            var KEY   = CreateGuid();
            var VALUE = CreateGuid();

            // ACT
            await ca1.SetAsync(KEY, VALUE, TimeSpan.FromSeconds(5));

            await ca2.WaitForEvent(eCacheEvent.KeySetInMemory);

            var v1 = await ca2.GetWithMetaDataAsync <string>(KEY);

            var v2 = await ca1.GetWithMetaDataAsync <string>(KEY);

            await Task.Delay(5000);

            var v3 = await ca2.GetWithMetaDataAsync <string>(KEY);

            var v4 = await ca1.GetWithMetaDataAsync <string>(KEY);

            Assert.IsNotNull(v1.Data);
            Assert.IsNotNull(v2.Data);
            Assert.IsTrue(v1.IsFromInMemoryCache);
            Assert.IsTrue(v2.IsFromInMemoryCache);

            Assert.IsNull(v3.Data);
            Assert.IsNull(v4.Data);
            Assert.IsTrue(v3.IsFromCentralCacheServer);
            Assert.IsTrue(v4.IsFromCentralCacheServer);
        }
        public async Task Cache_Dist_Test_That_Cache_Delete_Key_Works_OK()
        {
            // ARRANGE
            var ca1 = new CacheAccessor(new CacheConfig {
                IsAuditingEnabled = true
            });
            var ca2 = new CacheAccessor(new CacheConfig {
                IsAuditingEnabled = true
            });

            await ca1.InitialiseIfNecessaryAsync();

            await ca2.InitialiseIfNecessaryAsync();

            var KEY   = CreateGuid();
            var VALUE = CreateGuid();

            // ACT
            await ca1.SetAsync(KEY, VALUE); // set the value

            // Wait for propagation to ca2
            await ca2.WaitForEvent(eCacheEvent.KeySetInMemory);

            var v1 = await ca2.GetWithMetaDataAsync <string>(KEY);

            await ca2.DeleteAsync(KEY);

            var propagationTimeInMS = await ca1.WaitForEvent(eCacheEvent.KeyDeletedInMemory);

            var v2 = await ca1.GetWithMetaDataAsync <string>(KEY);

            var v3 = await ca2.GetWithMetaDataAsync <string>(KEY);

            // ASSERT
            Assert.IsNotNull(v1.Data);
            Assert.IsTrue(v1.IsFromInMemoryCache);
            Assert.IsNull(v2.Data);
            Assert.IsTrue(v2.IsFromCentralCacheServer);
            Assert.IsNull(v3.Data);
            Assert.IsTrue(v3.IsFromCentralCacheServer);
        }
        public async Task Cache_Dist_Test_Caching_Byte_Arrays()
        {
            // ARRANGE
            var ca1 = new CacheAccessor(new CacheConfig {
                IsAuditingEnabled = true
            });
            var ca2 = new CacheAccessor(new CacheConfig {
                IsAuditingEnabled = true
            });

            await ca1.InitialiseIfNecessaryAsync();

            await ca2.InitialiseIfNecessaryAsync();

            var KEY1   = CreateGuid();
            var VALUE1 = new byte[] { 32, 34, 55 };
            var KEY2   = CreateGuid();
            var VALUE2 = new byte[] { 1, 11, 33 };

            // ACT
            await ca1.SetAsync(KEY1, VALUE1); // set the value

            await ca2.WaitForEvent(eCacheEvent.KeySetInMemory);

            await ca2.SetAsync(KEY2, VALUE2); // set the value

            await ca1.WaitForEvent(eCacheEvent.KeySetInMemory);

            var data1 = await ca2.GetWithMetaDataAsync <byte[]>(KEY1);

            var data2 = await ca1.GetWithMetaDataAsync <byte[]>(KEY2);

            Assert.AreEqual(VALUE1.Length, data1.Data.Length);
            Assert.AreEqual(VALUE2.Length, data2.Data.Length);
            Assert.AreEqual(VALUE1[0], data1.Data[0]);
            Assert.AreEqual(VALUE1[1], data1.Data[1]);
            Assert.AreEqual(VALUE1[2], data1.Data[2]);

            Assert.AreEqual(VALUE2[0], data2.Data[0]);
            Assert.AreEqual(VALUE2[1], data2.Data[1]);
            Assert.AreEqual(VALUE2[2], data2.Data[2]);
        }
        public async Task Cache_Dist_TestKeyValuePairPropagation()
        {
            // Arrange
            var KEY            = Key();
            var VALUE          = CreateGuid();
            var cacheAccessor1 = new CacheAccessor(new CacheConfig {
                IsAuditingEnabled = true
            });
            var cacheAccessor2 = new CacheAccessor(new CacheConfig {
                IsAuditingEnabled = true
            });
            await cacheAccessor1.InitialiseIfNecessaryAsync();

            await cacheAccessor2.InitialiseIfNecessaryAsync();

            cacheAccessor1.AuditLog.Clear();
            cacheAccessor2.AuditLog.Clear();

            // Act
            var v1 = await cacheAccessor1.GetWithMetaDataAsync <string>(KEY);

            await cacheAccessor1.SetAsync(KEY, VALUE, TimeSpan.FromMinutes(2));

            await Task.Delay(300);

            var logOfCA2 = cacheAccessor2.AuditLog.ToArray();

            var v2 = await cacheAccessor2.GetWithMetaDataAsync <string>(KEY);

            var v3 = await cacheAccessor2.GetWithMetaDataAsync <string>(KEY);

            var cacheAccessor3 = new CacheAccessor(new CacheConfig());
            await cacheAccessor3.InitialiseIfNecessaryAsync();

            var v6 = await cacheAccessor3.GetWithMetaDataAsync <string>(KEY);

            var v7 = await cacheAccessor3.GetWithMetaDataAsync <string>(KEY);

            await cacheAccessor2.DeleteAsync(KEY);

            var v4_1 = await cacheAccessor1.GetWithMetaDataAsync <string>(KEY);

            var v5_1 = await cacheAccessor2.GetWithMetaDataAsync <string>(KEY);

            await Task.Delay(300);

            var v4 = await cacheAccessor1.GetWithMetaDataAsync <string>(KEY);

            var v5 = await cacheAccessor2.GetWithMetaDataAsync <string>(KEY);

            Assert.IsTrue(logOfCA2.First().CachingEvent == eCacheEvent.KeySetInMemory, "The next audit event should have been to receive the key update message");
            Assert.IsTrue(v1.IsFromCentralCacheServer, "Trying to get something that isn't set, should _AT_LEAST_ try the central cache");
            Assert.IsTrue(v2.IsFromInMemoryCache, "Getting an item after setting it should mean that the in-memory cache has had time to catch up");
            Assert.IsTrue(v3.IsFromInMemoryCache, "The value should have propagated to cache accessor");
            Assert.IsNull(v4.Data, "The value should be null");
            Assert.IsNull(v5.Data, "The value should be null");
            Assert.IsTrue(v4.IsFromCentralCacheServer, "If a value is null, it should have tried the central cache server");
            Assert.IsTrue(v5.IsFromCentralCacheServer, "If a value is null, it should have tried the central cache server");

            Assert.IsNotNull(v6.Data, "The data shouldn't be null");
            Assert.IsTrue(v6.IsFromCentralCacheServer, "The value should have been retrieved from the central server");

            Assert.IsNotNull(v7.Data, "The data shouldn't be null");
            Assert.AreEqual(VALUE, v7.Data);
            Assert.IsTrue(v7.IsFromInMemoryCache, "The value should have been retrieved from the memory cache");

            // This test is too subjective for the build server
            // Assert.IsTrue(v7.ElapsedMilliseconds < v6.ElapsedMilliseconds, "It should have been quicker to get the value the second time");
        }