diff --git a/RedisBackedHzCache/RedisBackedHzCache.cs b/RedisBackedHzCache/RedisBackedHzCache.cs index fa6c6f3..d4f216c 100644 --- a/RedisBackedHzCache/RedisBackedHzCache.cs +++ b/RedisBackedHzCache/RedisBackedHzCache.cs @@ -220,7 +220,7 @@ public void Set(string key, T value, TimeSpan ttl) public T GetOrSet(string key, Func valueFactory, TimeSpan ttl, long maxMsToWaitForFactory = 10000) { var value = hzCache.Get(key); - if (value != null) + if (!HzMemoryCache.IsNullOrDefault(value)) { return value; } diff --git a/RedisBackedHzCache/RedisBackedHzCacheAsync.cs b/RedisBackedHzCache/RedisBackedHzCacheAsync.cs index 84c26ce..243ab35 100644 --- a/RedisBackedHzCache/RedisBackedHzCacheAsync.cs +++ b/RedisBackedHzCache/RedisBackedHzCacheAsync.cs @@ -57,24 +57,24 @@ public Task SetAsync(string key, T value, TimeSpan ttl) public async Task GetOrSetAsync(string key, Func> valueFactory, TimeSpan ttl, long maxMsToWaitForFactory = 10000) { - var value = await hzCache.GetAsync(key); - if (value != null) + var value = await hzCache.GetAsync(key).ConfigureAwait(false); + if (!HzMemoryCache.IsNullOrDefault(value)) { return value; } if (options.useRedisAs2ndLevelCache) { - var redisValue = await GetRedisValueAsync(key); + var redisValue = await GetRedisValueAsync(key).ConfigureAwait(false); if (!redisValue.IsNull) { - var ttlValue = await TTLValue.FromRedisValueAsync(Encoding.ASCII.GetBytes(redisValue.ToString())); + var ttlValue = await TTLValue.FromRedisValueAsync(Encoding.ASCII.GetBytes(redisValue.ToString())).ConfigureAwait(false); hzCache.SetRaw(key, ttlValue); return (T)ttlValue.value; } } - return await hzCache.GetOrSetAsync(key, valueFactory, ttl, maxMsToWaitForFactory); + return await hzCache.GetOrSetAsync(key, valueFactory, ttl, maxMsToWaitForFactory).ConfigureAwait(false); } public Task> GetOrSetBatchAsync(IList keys, Func, Task>>> valueFactory) diff --git a/UnitTests/IntegrationTests.cs b/UnitTests/IntegrationTests.cs index c413eaf..660f953 100644 --- a/UnitTests/IntegrationTests.cs +++ b/UnitTests/IntegrationTests.cs @@ -306,6 +306,71 @@ public async Task TestRedisGetOrSet() } + [TestMethod] + [TestCategory("Integration")] + public async Task TestRedisGetOrSet_ValueType_CallsFactory() + { + // Arrange + var c1 = new RedisBackedHzCache( + new RedisBackedHzCacheOptions { redisConnectionString = ConnectionString, applicationCachePrefix = "test", instanceId = "c1", useRedisAs2ndLevelCache = false }); + var factoryCalled = false; + + // Act + var result = c1.GetOrSet("int-key", _ => + { + factoryCalled = true; + return 42; + }, TimeSpan.FromMinutes(1)); + + // Assert + Assert.IsTrue(factoryCalled, "Factory should be called on cache miss for value types"); + Assert.AreEqual(42, result); + await c1.RemoveAsync("int-key"); + } + + [TestMethod] + [TestCategory("Integration")] + public async Task TestRedisGetOrSetAsync_ValueType_CallsFactory() + { + // Arrange + var c1 = new RedisBackedHzCache( + new RedisBackedHzCacheOptions { redisConnectionString = ConnectionString, applicationCachePrefix = "test", instanceId = "c1", useRedisAs2ndLevelCache = false }); + var factoryCalled = false; + + // Act + var result = await c1.GetOrSetAsync("int-key-async", _ => + { + factoryCalled = true; + return Task.FromResult(42); + }, TimeSpan.FromMinutes(1)); + + // Assert + Assert.IsTrue(factoryCalled, "Factory should be called on cache miss for value types"); + Assert.AreEqual(42, result); + await c1.RemoveAsync("int-key-async"); + } + + [TestMethod] + [TestCategory("Integration")] + public async Task TestRedisGetOrSetAsync_ValueType_ReturnsCachedValue() + { + // Arrange + var c1 = new RedisBackedHzCache( + new RedisBackedHzCacheOptions { redisConnectionString = ConnectionString, applicationCachePrefix = "test", instanceId = "c1", useRedisAs2ndLevelCache = false }); + await c1.GetOrSetAsync("int-cached", _ => Task.FromResult(42), TimeSpan.FromMinutes(1)); + + // Act — second call should return cached value, not call factory + var result = await c1.GetOrSetAsync("int-cached", _ => + { + Assert.Fail("Factory should not be called when value is already cached"); + return Task.FromResult(0); + }, TimeSpan.FromMinutes(1)); + + // Assert + Assert.AreEqual(42, result); + await c1.RemoveAsync("int-cached"); + } + [TestMethod] [TestCategory("Integration")] public async Task TestRedisBackplaneDelete()