diff --git a/.editorconfig b/.editorconfig index 20fe9082..86bad1fa 100644 --- a/.editorconfig +++ b/.editorconfig @@ -13,7 +13,7 @@ tab_width = 4 # New line preferences end_of_line = crlf -insert_final_newline = false +insert_final_newline = true #### .NET Coding Conventions #### diff --git a/OptimizelySDK.Tests/OdpTests/LruCacheTest.cs b/OptimizelySDK.Tests/OdpTests/LruCacheTest.cs new file mode 100644 index 00000000..a1443956 --- /dev/null +++ b/OptimizelySDK.Tests/OdpTests/LruCacheTest.cs @@ -0,0 +1,213 @@ +/* + * Copyright 2022, Optimizely + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using NUnit.Framework; +using OptimizelySDK.Odp; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; + +namespace OptimizelySDK.Tests.OdpTests +{ + public class LruCacheTest + { + private List _segments1And2; + private List _segments3And4; + private List _segments5And6; + + [SetUp] + public void SetUp() + { + _segments1And2 = new List + { + "segment1", + "segment2", + }; + _segments3And4 = new List + { + "segment3", + "segment4", + }; + _segments5And6 = new List + { + "segment5", + "segment6", + }; + } + + [Test] + public void ShouldCreateSaveAndLookupOneItem() + { + var cache = new LruCache(); + Assert.IsNull(cache.Lookup("key1")); + + cache.Save("key1", "value1"); + Assert.AreEqual("value1", cache.Lookup("key1")); + } + + [Test] + public void ShouldSaveAndLookupMultipleItems() + { + var cache = new LruCache>(); + + cache.Save("user1", _segments1And2); + cache.Save("user2", _segments3And4); + cache.Save("user3", _segments5And6); + + var cacheKeys = cache._readCurrentCacheKeys(); + + Assert.AreEqual("user3", cacheKeys[0]); + Assert.AreEqual("user2", cacheKeys[1]); + Assert.AreEqual("user1", cacheKeys[2]); + + // Lookup should move user1 to top of the list and push down others. + Assert.AreEqual(_segments1And2, cache.Lookup("user1")); + + cacheKeys = cache._readCurrentCacheKeys(); + Assert.AreEqual("user1", cacheKeys[0]); + Assert.AreEqual("user3", cacheKeys[1]); + Assert.AreEqual("user2", cacheKeys[2]); + + // Lookup should move user2 to the beginning of the list and push others. + Assert.AreEqual(_segments3And4, cache.Lookup("user2")); + + cacheKeys = cache._readCurrentCacheKeys(); + Assert.AreEqual("user2", cacheKeys[0]); + Assert.AreEqual("user1", cacheKeys[1]); + Assert.AreEqual("user3", cacheKeys[2]); + + // Lookup moves user3 to top and pushes others down. + Assert.AreEqual(_segments5And6, cache.Lookup("user3")); + + cacheKeys = cache._readCurrentCacheKeys(); + Assert.AreEqual("user3", cacheKeys[0]); + Assert.AreEqual("user2", cacheKeys[1]); + Assert.AreEqual("user1", cacheKeys[2]); + } + + [Test] + public void ShouldReorderListOnSave() + { + var cache = new LruCache>(); + + cache.Save("user1", _segments1And2); + cache.Save("user2", _segments3And4); + cache.Save("user3", _segments5And6); + + var cacheKeys = cache._readCurrentCacheKeys(); + + // last added should be at the top of the list + Assert.AreEqual("user3",cacheKeys[0]); + Assert.AreEqual("user2",cacheKeys[1]); + Assert.AreEqual("user1" ,cacheKeys[2]); + + // save should move user1 to the top of the list and push down others. + cache.Save("user1", _segments1And2); + + cacheKeys = cache._readCurrentCacheKeys(); + Assert.AreEqual("user1",cacheKeys[0]); + Assert.AreEqual("user3",cacheKeys[1]); + Assert.AreEqual("user2",cacheKeys[2]); + + // save user2 should bring it to the top and push down others. + cache.Save("user2", _segments3And4); + + cacheKeys = cache._readCurrentCacheKeys(); + Assert.AreEqual("user2",cacheKeys[0]); + Assert.AreEqual("user1",cacheKeys[1]); + Assert.AreEqual("user3",cacheKeys[2]); + + // saving user3 again should return to the original insertion order. + cache.Save("user3", _segments5And6); + + cacheKeys = cache._readCurrentCacheKeys(); + Assert.AreEqual("user3",cacheKeys[0]); + Assert.AreEqual("user2",cacheKeys[1]); + Assert.AreEqual("user1" ,cacheKeys[2]); + } + + [Test] + public void ShouldHandleWhenCacheIsDisabled() + { + var cache = new LruCache>(maxSize: 0); + + cache.Save("user1", _segments1And2); + cache.Save("user2", _segments3And4); + cache.Save("user3", _segments5And6); + + Assert.IsNull(cache.Lookup("user1")); + Assert.IsNull(cache.Lookup("user2")); + Assert.IsNull(cache.Lookup("user3")); + } + + [Test] + public void ShouldHandleWhenItemsExpire() + { + var cache = new LruCache>(itemTimeout: TimeSpan.FromSeconds(1)); + + cache.Save("user1", _segments1And2); + + Assert.AreEqual(_segments1And2, cache.Lookup("user1")); + Assert.AreEqual(1, cache._readCurrentCacheKeys().Length); + + Thread.Sleep(1200); + + Assert.IsNull(cache.Lookup("user1")); + Assert.AreEqual(0, cache._readCurrentCacheKeys().Length); + } + + [Test] + public void ShouldHandleWhenCacheReachesMaxSize() + { + var cache = new LruCache>(maxSize: 2); + + cache.Save("user1", _segments1And2); + cache.Save("user2", _segments3And4); + cache.Save("user3", _segments5And6); + + Assert.AreEqual(2, cache._readCurrentCacheKeys().Length); + + Assert.AreEqual(_segments5And6, cache.Lookup("user3")); + Assert.AreEqual(_segments3And4, cache.Lookup("user2")); + Assert.IsNull(cache.Lookup("user1")); + } + + [Test] + public void ShouldHandleWhenCacheIsReset() + { + var cache = new LruCache>(); + + cache.Save("user1", _segments1And2); + cache.Save("user2", _segments3And4); + cache.Save("user3", _segments5And6); + + Assert.AreEqual(_segments1And2, cache.Lookup("user1")); + Assert.AreEqual(_segments3And4, cache.Lookup("user2")); + Assert.AreEqual(_segments5And6, cache.Lookup("user3")); + + Assert.AreEqual(3, cache._readCurrentCacheKeys().Length); + + cache.Reset(); + + Assert.IsNull(cache.Lookup("user1")); + Assert.IsNull(cache.Lookup("user2")); + Assert.IsNull(cache.Lookup("user3")); + + Assert.AreEqual(0, cache._readCurrentCacheKeys().Length); + } + } +} diff --git a/OptimizelySDK.Tests/OptimizelySDK.Tests.csproj b/OptimizelySDK.Tests/OptimizelySDK.Tests.csproj index d0a2d2ae..c563d781 100644 --- a/OptimizelySDK.Tests/OptimizelySDK.Tests.csproj +++ b/OptimizelySDK.Tests/OptimizelySDK.Tests.csproj @@ -80,6 +80,7 @@ + @@ -150,7 +151,6 @@ -