Skip to content

Commit

Permalink
Merge branch 'release/2020.1.6.1'
Browse files Browse the repository at this point in the history
  • Loading branch information
Ian Robertson committed Jan 6, 2020
2 parents 011ad04 + d32bdcb commit 7d5b27b
Show file tree
Hide file tree
Showing 11 changed files with 124 additions and 49 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -159,3 +159,4 @@ $RECYCLE.BIN/
/Outputs/4.5.1/EFCache.Redis.dll
/EFCache.Redis.Tests/lib/dump.rdb
.vs/
*.nupkg
22 changes: 19 additions & 3 deletions EFCache.Redis.Tests/RedisCacheLazyTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,29 @@ public class RedisCacheLazyTests
{

private static readonly Lazy<ConnectionMultiplexer> LazyConnection = new Lazy<ConnectionMultiplexer>(() =>
ConnectionMultiplexer.Connect("localhost:6379"));
ConnectionMultiplexer.Connect(RegularConnectionString));

private static string RegularConnectionString;
public RedisCacheLazyTests()
{
RedisStorageEmulatorManager.Instance.StartProcess(false);
}
try
{
// See if we have a running copy of redis in a K8s Cluster
// helm install --name redis-dev --set password=secretpassword --set master.disableCommands= stable/redis
// kubectl get secret --namespace default redis-dev -o jsonpath="{.data.redis-password}" | base64 --decode
// kubectl port-forward --namespace default svc/redis-dev-master 6379:6379
var connString = "localhost:6379,password=secretpassword";

var cache = new RedisCache(connString);
RegularConnectionString = connString;
}
catch (Exception)
{
// Could not connect to redis above, so start a local copy
RedisStorageEmulatorManager.Instance.StartProcess(false);
}

}

[TestMethod]
public void Item_cached_with_lazy()
Expand Down
81 changes: 63 additions & 18 deletions EFCache.Redis.Tests/RedisCacheTests.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using EFCache.Redis.Tests.Annotations;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using StackExchange.Redis;
Expand All @@ -12,19 +13,40 @@ public class TestObject
public string Message { get; set; }
}


[TestClass]
[UsedImplicitly]
public class RedisCacheTests
{
private readonly string RegularConnectionString = "localhost:6379";
private readonly string AdminConnectionString = "localhost:6379,allowAdmin=true";
public RedisCacheTests()
{
RedisStorageEmulatorManager.Instance.StartProcess(false);
try
{
// See if we have a running copy of redis in a K8s Cluster
// helm install --name redis-dev --set password=secretpassword --set master.disableCommands= stable/redis
// kubectl get secret --namespace default redis-dev -o jsonpath="{.data.redis-password}" | base64 --decode
// kubectl port-forward --namespace default svc/redis-dev-master 6379:6379
var connString = "localhost:6379,password=secretpassword";

var cache = new RedisCache(connString);
RegularConnectionString = connString;
AdminConnectionString = string.Join(",", connString, "allowAdmin=true");

}
catch (Exception)
{
// Could not connect to redis above, so start a local copy
RedisStorageEmulatorManager.Instance.StartProcess(false);
}

}

[TestMethod]
public void Item_cached()
{
var cache = new RedisCache("localhost:6379");
var cache = new RedisCache(RegularConnectionString);
var item = new TestObject { Message = "OK" };

cache.PutItem("key", item, new string[0], TimeSpan.MaxValue, DateTimeOffset.MaxValue);
Expand All @@ -39,19 +61,21 @@ public void Item_cached()
[TestMethod]
public void Item_not_returned_after_absolute_expiration_expired()
{
var cache = new RedisCache("localhost:6379");
var cache = new RedisCache(RegularConnectionString);
var item = new TestObject { Message = "OK" };

cache.PutItem("key", item, new string[0], TimeSpan.MaxValue, DateTimeOffset.Now.AddMinutes(-10));
cache.PutItem("key", item, new string[0], TimeSpan.MaxValue, DateTimeOffset.Now.AddSeconds(1));

Thread.Sleep(1000);

Assert.IsFalse(cache.GetItem("key", out var fromCache));
Assert.IsNull(fromCache);
}

[TestMethod]
public void Item_not_returned_after_sliding_expiration_expired()
public void Item_not_returned_when_slidingexpiration_has_passed()
{
var cache = new RedisCache("localhost:6379");
var cache = new RedisCache(RegularConnectionString);
var item = new TestObject { Message = "OK" };

cache.PutItem("key", item, new string[0], TimeSpan.Zero.Subtract(new TimeSpan(10000)), DateTimeOffset.MaxValue);
Expand All @@ -63,7 +87,7 @@ public void Item_not_returned_after_sliding_expiration_expired()
[TestMethod]
public void Item_still_returned_after_sliding_expiration_period()
{
var cache = new RedisCache("localhost:6379");
var cache = new RedisCache(RegularConnectionString);
var item = new TestObject { Message = "OK" };

// Cache the item with a sliding expiration of 10 seconds
Expand All @@ -75,7 +99,7 @@ public void Item_still_returned_after_sliding_expiration_period()
{
Thread.Sleep(5000); // Wait 5 seconds
// Retrieve item again. This should update LastAccess and as such keep the item 'alive'
// Break when item cannot be retrieved
// Throw if item cannot be retrieved
Assert.IsTrue(cache.GetItem("key", out fromCache));
}
Assert.IsNotNull(fromCache);
Expand All @@ -84,7 +108,7 @@ public void Item_still_returned_after_sliding_expiration_period()
[TestMethod]
public void InvalidateSets_invalidate_items_with_given_sets()
{
var cache = new RedisCache("localhost:6379");
var cache = new RedisCache(RegularConnectionString);

cache.PutItem("1", new object(), new[] { "ES1", "ES2" }, TimeSpan.MaxValue, DateTimeOffset.MaxValue);
cache.PutItem("2", new object(), new[] { "ES2", "ES3" }, TimeSpan.MaxValue, DateTimeOffset.MaxValue);
Expand All @@ -102,7 +126,7 @@ public void InvalidateSets_invalidate_items_with_given_sets()
[TestMethod]
public void InvalidateItem_invalidates_item()
{
var cache = new RedisCache("localhost:6379");
var cache = new RedisCache(RegularConnectionString);

cache.PutItem("1", new object(), new[] { "ES1", "ES2" }, TimeSpan.MaxValue, DateTimeOffset.MaxValue);
cache.InvalidateItem("1");
Expand All @@ -113,7 +137,7 @@ public void InvalidateItem_invalidates_item()
[TestMethod]
public void Count_returns_numers_of_cached_entries()
{
var cache = new RedisCache("localhost:6379,allowAdmin=true");
var cache = new RedisCache(AdminConnectionString);

cache.Purge();

Expand All @@ -128,18 +152,39 @@ public void Count_returns_numers_of_cached_entries()
Assert.AreEqual(0, cache.Count);
}


[TestMethod]
public void Count_does_not_return_expired_entries()
{
var cache = new RedisCache(AdminConnectionString);

cache.Purge();

Assert.AreEqual(0, cache.Count);

cache.PutItem("1", new object(), new string[0], TimeSpan.MaxValue, DateTimeOffset.Now.AddSeconds(1));

Assert.AreEqual(1, cache.Count);

Thread.Sleep(1000);

Assert.AreEqual(0, cache.Count);
}

[TestMethod]
public void Purge_removes_stale_items_from_cache()
{
var cache = new RedisCache("localhost:6379,allowAdmin=true");
var cache = new RedisCache(AdminConnectionString);

cache.Purge();

cache.PutItem("1", new object(), new[] { "ES1", "ES2" }, TimeSpan.MaxValue, DateTimeOffset.Now.AddMinutes(-1));
cache.PutItem("1", new object(), new[] { "ES1", "ES2" }, TimeSpan.MaxValue, DateTimeOffset.Now.AddSeconds(1));
cache.PutItem("2", new object(), new[] { "ES1", "ES2" }, TimeSpan.MaxValue, DateTimeOffset.MaxValue);

Assert.AreEqual(4, cache.Count); // "1", "2", "ES1", "ES2"

Thread.Sleep(1000);

cache.Purge();

Assert.AreEqual(0, cache.Count);
Expand All @@ -152,35 +197,35 @@ public void Purge_removes_stale_items_from_cache()
[ExpectedException(typeof(ArgumentOutOfRangeException))]
public void GetItem_validates_parameters()
{
var unused = new RedisCache("localhost:6379").GetItem(null, out _);
var unused = new RedisCache(RegularConnectionString).GetItem(null, out _);
}

[TestMethod]
[ExpectedException(typeof(ArgumentOutOfRangeException))]
public void PutItem_validates_key_parameter()
{
new RedisCache("localhost:6379").PutItem(null, 42, new string[0], TimeSpan.Zero, DateTimeOffset.Now);
new RedisCache(RegularConnectionString).PutItem(null, 42, new string[0], TimeSpan.Zero, DateTimeOffset.Now);
}

[TestMethod]
[ExpectedException(typeof(ArgumentNullException))]
public void PutItem_validates_dependentEntitySets_parameter()
{
new RedisCache("localhost:6379").PutItem("1", 42, null, TimeSpan.Zero, DateTimeOffset.Now);
new RedisCache(RegularConnectionString).PutItem("1", 42, null, TimeSpan.Zero, DateTimeOffset.Now);
}

[TestMethod]
[ExpectedException(typeof(ArgumentNullException))]
public void InvalidateSets_validates_parameters()
{
new RedisCache("localhost:6379").InvalidateSets(null);
new RedisCache(RegularConnectionString).InvalidateSets(null);
}

[TestMethod]
[ExpectedException(typeof(ArgumentOutOfRangeException))]
public void InvalidateItem_validates_parameters()
{
new RedisCache("localhost:6379").InvalidateItem(null);
new RedisCache(RegularConnectionString).InvalidateItem(null);
}

[TestMethod]
Expand Down
5 changes: 3 additions & 2 deletions EFCache.Redis.Tests/StackExchangeExtensionsTests.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using StackExchange.Redis;

Expand All @@ -11,7 +12,7 @@ public class StackExchangeExtensionsTests
public void Set_should_not_throw_when_caching_null_object()
{
var cache = Mock.Of<IDatabase>();
cache.Set("key", (object)null);
cache.Set("key", (object)null, TimeSpan.FromMinutes(1));
}
}
}
2 changes: 1 addition & 1 deletion EFCache.Redis/App.config
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
<provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
</providers>
</entityFramework>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" /></startup>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8" /></startup>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
Expand Down
5 changes: 4 additions & 1 deletion EFCache.Redis/EFCache.Redis.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>EFCache.Redis</RootNamespace>
<AssemblyName>EFCache.Redis</AssemblyName>
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
<RestorePackages>true</RestorePackages>
Expand All @@ -32,6 +32,9 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
</PropertyGroup>
<ItemGroup>
<Reference Include="EFCache, Version=1.1.3.0, Culture=neutral, PublicKeyToken=46c4868af4307d2c, processorArchitecture=MSIL">
<HintPath>..\packages\EntityFramework.Cache.1.1.3\lib\net45\EFCache.dll</HintPath>
Expand Down
3 changes: 3 additions & 0 deletions EFCache.Redis/EFCache.Redis.nuspec
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
<dependency id="Pipelines.Sockets.Unofficial" version="1.1.23" />
<dependency id="System.Buffers" version="4.5.0" />
<dependency id="System.Diagnostics.PerformanceCounter" version="4.5.0" />
<dependency id="System.IO.Compression" version="4.3.0" />
<dependency id="System.IO.Pipelines" version="4.5.3" />
<dependency id="System.Memory" version="4.5.2" />
<dependency id="System.Numerics.Vectors" version="4.5.0" />
Expand All @@ -32,5 +33,7 @@
<file src="bin\4.7.1\EFCache.Redis.dll.config" target="lib\net471\EFCache.Redis.dll.config" />
<file src="bin\4.7.2\EFCache.Redis.dll" target="lib\net472\EFCache.Redis.dll" />
<file src="bin\4.7.2\EFCache.Redis.dll.config" target="lib\net472\EFCache.Redis.dll.config" />
<file src="bin\4.8\EFCache.Redis.dll" target="lib\net48\EFCache.Redis.dll" />
<file src="bin\4.8\EFCache.Redis.dll.config" target="lib\net48\EFCache.Redis.dll.config" />
</files>
</package>
6 changes: 3 additions & 3 deletions EFCache.Redis/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("EFCache.Redis")]
[assembly: AssemblyCopyright("Copyright © 2019")]
[assembly: AssemblyCopyright("Copyright © 2020")]
[assembly: AssemblyTrademark("Ian Robertson")]
[assembly: AssemblyCulture("")]
//[assembly: log4net.Config.XmlConfigurator(Watch = true)]
Expand All @@ -31,6 +31,6 @@
// Build Number
// Revision
//
[assembly: AssemblyVersion("2019.3.11.1")]
[assembly: AssemblyFileVersion("2019.3.11.1")]
[assembly: AssemblyVersion("2020.1.6.1")]
[assembly: AssemblyFileVersion("2020.1.6.1")]

15 changes: 10 additions & 5 deletions EFCache.Redis/RedisCache.cs
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ public bool GetItem(string key, out object value)
{
try
{
_database.Set(key, entry);
_database.Set(key, entry, GetTimeSpanExpiration(entry.AbsoluteExpiration));
}
catch (Exception e)
{
Expand Down Expand Up @@ -144,22 +144,27 @@ public void PutItem(string key, object value, IEnumerable<string> dependentEntit

lock (_lock)
{
try
try
{
foreach (var entitySet in entitySets)
{
_database.SetAdd(AddCacheQualifier(entitySet), key, CommandFlags.FireAndForget);
}

_database.Set(key, new CacheEntry(value, entitySets, slidingExpiration, absoluteExpiration));
}
catch (Exception e)
_database.Set(key, new CacheEntry(value, entitySets, slidingExpiration, absoluteExpiration), GetTimeSpanExpiration(absoluteExpiration));
}
catch (Exception e)
{
OnCachingFailed(e);
}
}
}

private TimeSpan GetTimeSpanExpiration(DateTimeOffset expiration)
{
return TimeSpan.FromTicks(expiration.UtcTicks - DateTime.UtcNow.Ticks);
}

private RedisKey AddCacheQualifier(string entitySet) => string.Concat(_cacheIdentifier, ".", entitySet);

private static string HashKey(string key)
Expand Down
7 changes: 4 additions & 3 deletions EFCache.Redis/StackExchangeRedisExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using StackExchange.Redis;
using System;
using StackExchange.Redis;
using System.IO;
using System.Linq;
using System.Runtime.Serialization.Formatters.Binary;
Expand All @@ -13,9 +14,9 @@ public static T Get<T>(this IDatabase cache, string key)
return Deserialize<T>(item);
}

public static void Set<T>(this IDatabase cache, string key, T value) where T : class
public static void Set<T>(this IDatabase cache, string key, T value, TimeSpan expiry) where T : class
{
cache.StringSet(key, Serialize<T>(value));
cache.StringSet(key, Serialize<T>(value), expiry);
}

static byte[] Serialize<T>(T o) where T : class
Expand Down
Loading

0 comments on commit 7d5b27b

Please sign in to comment.