Ejemplo n.º 1
0
        [Timeout(900)]         // Must be less than 2x the delay of the server.
        public static void TestChattelReader_GetAssetAsync2_UncachedAsset_SingleSlowServer_ParallelReads_SingleServerCall()
        {
            var server = Substitute.For <IAssetServer>();
            var config = new ChattelConfiguration(server);
            var asset  = new StratusAsset {
                Id   = Guid.NewGuid(),
                Name = "Avengers",
            };

            server
            .RequestAssetSync(asset.Id)
            .Returns(x => {
                Thread.Sleep(500);                         // Slow server call.
                return(asset);
            })
            ;

            var reader = new ChattelReader(config);

            Parallel.Invoke(
                () => {
                reader.GetAssetAsync(asset.Id, resultAsset => { });
            },
                () => {
                reader.GetAssetAsync(asset.Id, resultAsset => { });
            },
                () => {
                reader.GetAssetAsync(asset.Id, resultAsset => { });
            }
                );

            // The server should only be hit once for multiple parallel calls for the same asset ID.
            server.Received(1).RequestAssetSync(asset.Id);
        }
Ejemplo n.º 2
0
        public static void TestChattelReader_GetAssetAsync2_UncachedAsset_SerialServer_ReturnsEqualAsset()
        {
            var server1 = Substitute.For <IAssetServer>();
            var server2 = Substitute.For <IAssetServer>();
            var config  = new ChattelConfiguration(new List <List <IAssetServer> > {
                new List <IAssetServer> {
                    server1
                },
                new List <IAssetServer> {
                    server2
                }
            });
            var asset = new StratusAsset {
                Id   = Guid.NewGuid(),
                Name = "Avengers",
            };

            server1.WhenForAnyArgs(x => x.StoreAssetSync(asset)).Do(x => throw new AssetWriteException(asset.Id));

            server2.RequestAssetSync(asset.Id).Returns(asset);

            var reader = new ChattelReader(config);

            var wait = new AutoResetEvent(false);

            reader.GetAssetAsync(asset.Id, resultAsset => {
                Assert.AreEqual(asset, resultAsset);
                wait.Set();
            });

            wait.WaitOne();
        }
Ejemplo n.º 3
0
        public static void TestChattelReader_GetAssetAsync2_CachedAsset_ReturnsEqualAsset()
        {
            var config       = new ChattelConfiguration(LOCAL_STORAGE_DIR_INFO.FullName);
            var localStorage = Substitute.For <IChattelLocalStorage>();
            var asset        = new StratusAsset {
                Id   = Guid.NewGuid(),
                Name = "Avengers",
            };

            localStorage
            .TryGetAsset(asset.Id, out var junk)
            .Returns(x => {
                x[1] = asset;
                return(true);
            })
            ;

            var reader = new ChattelReader(config, localStorage);

            var wait = new AutoResetEvent(false);

            reader.GetAssetAsync(asset.Id, resultAsset => {
                Assert.AreEqual(asset, resultAsset);
                wait.Set();
            });

            wait.WaitOne();
        }
Ejemplo n.º 4
0
        protected void TestAssetKnownExists()
        {
            StratusAsset asset     = null;
            var          stopWatch = new Stopwatch();

            stopWatch.Reset();
            using (var wait = new AutoResetEvent(false)) {
                _reader.GetAssetAsync(_knownAssetId, (a) => {
                    asset = a;
                    wait.Set();
                });

                wait.WaitOne(TIMEOUT_MS);
            }
            stopWatch.Stop();

            if (asset == null)
            {
                if (stopWatch.ElapsedMilliseconds >= 100)
                {
                    throw new TestFailedException("Asset fetch timeout.");
                }

                throw new TestFailedException("Asset not found.");
            }
        }
Ejemplo n.º 5
0
        [Timeout(900)]         // Must be less than 2x the delay of the server.
        public static void TestChattelReader_GetAssetAsync2_UncachedAsset_SingleSlowServer_ParallelReads_TakeExpectedTime()
        {
            var server = Substitute.For <IAssetServer>();
            var config = new ChattelConfiguration(server);
            var asset  = new StratusAsset {
                Id   = Guid.NewGuid(),
                Name = "Avengers",
            };

            server
            .RequestAssetSync(asset.Id)
            .Returns(x => {
                Thread.Sleep(500);                         // Slow server call.
                return(asset);
            })
            ;

            var reader = new ChattelReader(config);

            var time1ms = 0L;
            var time2ms = 0L;

            Parallel.Invoke(
                () => {
                var timer = new Stopwatch();
                timer.Restart();
                reader.GetAssetAsync(asset.Id, resultAsset => {
                    timer.Stop();
                    time1ms = timer.ElapsedMilliseconds;
                });
            },
                () => {
                var timer = new Stopwatch();
                timer.Restart();
                reader.GetAssetAsync(asset.Id, resultAsset => {
                    timer.Stop();
                    time2ms = timer.ElapsedMilliseconds;
                });
            }
                );

            // Both calls are to take about the same time, as the server is going to take its jolly time getting back to us.
            Assert.Less(time1ms, 600);
            Assert.Greater(time1ms, 490);
            Assert.Less(time2ms, 600);
            Assert.Greater(time2ms, 490);
        }
        public static Texture GetByUUID(Guid id, Color?defaultColor)
        {
            if (_memoryCache.TryGetValue(id, out var cachedTexture))
            {
                return(cachedTexture);
            }

            if (_assetReader == null && defaultColor == null)
            {
                return(DEFAULT);
                // No cache needed for default.
            }
            Texture   texture = null;
            Exception ex      = null;

            var wait = new System.Threading.AutoResetEvent(false);

            _assetReader.GetAssetAsync(id, asset => {
                if (asset == null || !(asset?.IsTextureAsset() ?? false))
                {
                    texture = new Texture(color: defaultColor);
                    // No cache when the asset was not found: maybe next time it will be.
                }
                else
                {
                    try {
                        texture = new Texture(asset);

                        _memoryCache.TryAdd(id, texture);
                    }
                    catch (Exception e) {
                        ex = e;
                    }
                }
                wait.Set();
            });
            wait.WaitOne(60000);

            if (ex != null)
            {
                throw new Exception("See inner exception", ex);
            }

            if (texture == null && defaultColor == null)
            {
                return(DEFAULT);
                // No cache needed for default.
            }
            else if (texture == null)
            {
                return(new Texture(color: defaultColor));
            }

            return(texture);
        }
Ejemplo n.º 7
0
        /// <summary>
        /// Retrieves the asset. Tries local storage first, then moves on to the remote storage systems.
        /// If neither could find the data, or if there is no remote storage set up, the failure callback is called.
        /// </summary>
        /// <param name="assetId">Asset identifier.</param>
        /// <param name="successCallback">Callback called when the asset was successfully found.</param>
        /// <param name="failureCallback">Callback called when there was a failure attempting to get the asset.</param>
        /// <param name="storeResultLocally">Specifies to locally store the asset if it was fetched from a remote.</param>
        public void GetAsset(Guid assetId, SuccessCallback successCallback, FailureCallback failureCallback, bool storeResultLocally = true)
        {
            successCallback = successCallback ?? throw new ArgumentNullException(nameof(successCallback));
            failureCallback = failureCallback ?? throw new ArgumentNullException(nameof(failureCallback));
            if (assetId == Guid.Empty)
            {
                throw new ArgumentException("Asset ID cannot be zero.", nameof(assetId));
            }

            if (_negativeCache != null)
            {
                _negativeCacheLock.EnterReadLock();
                try {
                    if (_negativeCache.Contains(assetId.ToString("N")))
                    {
                        failureCallback();
                        return;
                    }
                }
                finally {
                    _negativeCacheLock.ExitReadLock();
                }
            }

            // Solves GET in middle of PUT situation.
            if (_localStorage.Contains(assetId) && !_localStorage.AssetWasWrittenToDisk(assetId))
            {
                // Asset exists, just might not be on disk yet. Wait here until the asset makes it to disk.
                SpinWait.SpinUntil(() => _localStorage.AssetWasWrittenToDisk(assetId));
            }

            _assetReader.GetAssetAsync(assetId, asset => {
                if (asset != null)
                {
                    successCallback(asset);
                    return;
                }

                failureCallback();

                if (_negativeCache != null)
                {
                    _negativeCacheLock.EnterWriteLock();
                    try {
                        _negativeCache.Set(new System.Runtime.Caching.CacheItem(assetId.ToString("N"), 0), _negativeCachePolicy);
                    }
                    finally {
                        _negativeCacheLock.ExitWriteLock();
                    }
                }
            }, storeResultLocally ? ChattelReader.CacheRule.Normal : ChattelReader.CacheRule.SkipWrite);
        }
Ejemplo n.º 8
0
        [Timeout(900)]         // Must be less than 2x the delay of the server.
        public static void TestChattelReader_GetAssetAsync2_UncachedAsset_SingleSlowServer_ParallelReads_ReturnsEqualAssetToBoth()
        {
            var server = Substitute.For <IAssetServer>();
            var config = new ChattelConfiguration(server);
            var asset  = new StratusAsset {
                Id   = Guid.NewGuid(),
                Name = "Avengers",
            };

            server
            .RequestAssetSync(asset.Id)
            .Returns(x => {
                Thread.Sleep(500);                         // Slow server call.
                return(asset);
            })
            ;

            var reader = new ChattelReader(config);

            StratusAsset asset1 = null;
            StratusAsset asset2 = null;

            Parallel.Invoke(
                () => {
                reader.GetAssetAsync(asset.Id, resultAsset => {
                    asset1 = resultAsset;
                });
            },
                () => {
                reader.GetAssetAsync(asset.Id, resultAsset => {
                    asset2 = resultAsset;
                });
            }
                );

            Assert.AreEqual(asset, asset1);
            Assert.AreEqual(asset, asset2);
        }
Ejemplo n.º 9
0
        public static void TestChattelReader_GetAssetAsync3_NoUpstream_CacheRuleSkipReadWrite_LocalCacheIsNotWritten()
        {
            var config       = new ChattelConfiguration(LOCAL_STORAGE_DIR_INFO.FullName);
            var localStorage = Substitute.For <IChattelLocalStorage>();
            var asset        = new StratusAsset {
                Id = Guid.NewGuid(),
            };

            var reader = new ChattelReader(config, localStorage);

            reader.GetAssetAsync(asset.Id, resultAsset => {}, ChattelReader.CacheRule.SkipRead | ChattelReader.CacheRule.SkipWrite);

            localStorage.Received(0).StoreAsset(asset);
        }
Ejemplo n.º 10
0
        public static void TestChattelReader_GetAssetAsync2_EmptyGuid_ReturnsNull()
        {
            var config = new ChattelConfiguration(LOCAL_STORAGE_DIR_INFO.FullName);
            var reader = new ChattelReader(config);

            var wait = new AutoResetEvent(false);

            reader.GetAssetAsync(Guid.Empty, resultAsset => {
                Assert.Null(resultAsset);
                wait.Set();
            });

            wait.WaitOne();
        }
Ejemplo n.º 11
0
        public static void TestChattelReader_GetAssetAsync3_WithUpstream_CacheRuleSkipRead_LocalCacheIsWritten()
        {
            var server       = Substitute.For <IAssetServer>();
            var config       = new ChattelConfiguration(LOCAL_STORAGE_DIR_INFO.FullName, server);
            var localStorage = Substitute.For <IChattelLocalStorage>();
            var asset        = new StratusAsset {
                Id = Guid.NewGuid(),
            };

            server.RequestAssetSync(asset.Id).Returns(asset);

            var reader = new ChattelReader(config, localStorage);

            reader.GetAssetAsync(asset.Id, resultAsset => {}, ChattelReader.CacheRule.SkipRead);

            localStorage.Received(1).StoreAsset(asset);
        }
Ejemplo n.º 12
0
        public static void TestChattelReader_GetAssetAsync2_EmptyGuid_CallbackCalled()
        {
            var config = new ChattelConfiguration(LOCAL_STORAGE_DIR_INFO.FullName);
            var reader = new ChattelReader(config);

            var wait = new AutoResetEvent(false);
            var callbackWasCalled = false;

            reader.GetAssetAsync(Guid.Empty, resultAsset => {
                callbackWasCalled = true;
                wait.Set();
            });

            wait.WaitOne();

            Assert.True(callbackWasCalled);
        }
Ejemplo n.º 13
0
        public static void TestChattelReader_GetAssetAsync2_LocalCacheIsWritten()
        {
            // Simply need to verify that CacheRule.Normal is in effect.

            var server       = Substitute.For <IAssetServer>();
            var config       = new ChattelConfiguration(LOCAL_STORAGE_DIR_INFO.FullName, server);
            var localStorage = Substitute.For <IChattelLocalStorage>();
            var asset        = new StratusAsset {
                Id = Guid.NewGuid(),
            };

            server.RequestAssetSync(asset.Id).Returns(asset);

            var reader = new ChattelReader(config, localStorage);

            reader.GetAssetAsync(asset.Id, resultAsset => {});

            localStorage.Received(1).StoreAsset(asset);
        }
Ejemplo n.º 14
0
        public static void TestChattelReader_GetAssetAsync3_NoUpstream_CacheRuleSkipReadWrite_LocalCacheIsReadAnyway()
        {
            var config       = new ChattelConfiguration(LOCAL_STORAGE_DIR_INFO.FullName);
            var localStorage = Substitute.For <IChattelLocalStorage>();
            var assetId      = Guid.NewGuid();

            localStorage
            .TryGetAsset(assetId, out var junk)
            .Returns(x => {
                x[1] = new StratusAsset();
                return(true);
            })
            ;

            var reader = new ChattelReader(config, localStorage);

            reader.GetAssetAsync(assetId, resultAsset => {}, ChattelReader.CacheRule.SkipRead | ChattelReader.CacheRule.SkipWrite);

            localStorage.Received(1).TryGetAsset(assetId, out junk);
        }
Ejemplo n.º 15
0
        public static void TestChattelReader_GetAssetAsync2_UncachedAsset_SingleServer_ReturnsEqualAsset()
        {
            var server = Substitute.For <IAssetServer>();
            var config = new ChattelConfiguration(server);
            var asset  = new StratusAsset {
                Id   = Guid.NewGuid(),
                Name = "Avengers",
            };

            server.RequestAssetSync(asset.Id).Returns(asset);

            var reader = new ChattelReader(config);

            var wait = new AutoResetEvent(false);

            reader.GetAssetAsync(asset.Id, resultAsset => {
                Assert.AreEqual(asset, resultAsset);
                wait.Set();
            });

            wait.WaitOne();
        }
Ejemplo n.º 16
0
        public static void TestChattelReader_GetAssetAsync2_LocalCacheIsRead()
        {
            // Simply need to verify that CacheRule.Normal is in effect.

            var config       = new ChattelConfiguration(LOCAL_STORAGE_DIR_INFO.FullName);
            var localStorage = Substitute.For <IChattelLocalStorage>();
            var assetId      = Guid.NewGuid();

            localStorage
            .TryGetAsset(assetId, out var junk)
            .Returns(x => {
                x[1] = new StratusAsset();
                return(true);
            })
            ;

            var reader = new ChattelReader(config, localStorage);

            reader.GetAssetAsync(assetId, resultAsset => {});

            localStorage.Received(1).TryGetAsset(assetId, out junk);
        }