Skip to content

Commit

Permalink
Cache service bugfix and tests (pfh59#272)
Browse files Browse the repository at this point in the history
* Rename current test file to reflect what it's actually doing

* Fix a small bug with the cache removal method and write unit tests for the cache service
  • Loading branch information
pkoelemij authored Jun 3, 2024
1 parent bdc7b1e commit 22fd256
Show file tree
Hide file tree
Showing 5 changed files with 418 additions and 108 deletions.
Original file line number Diff line number Diff line change
@@ -1,107 +1,106 @@
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using WHMapper.Services.Cache;

namespace WHMapper.Tests.Services;

[Collection("C1-Services")]
public class CacheTest
{
private readonly ICacheService? _services;
private readonly ICacheService? _badServices;
public CacheTest()
{
var services = new ServiceCollection();


var configuration = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.AddEnvironmentVariables()
.Build();

services.AddStackExchangeRedisCache(option =>
{
option.Configuration = configuration.GetConnectionString("RedisConnection");
option.InstanceName = "WHMapper";
});


var provider = services.BuildServiceProvider();
if(provider != null)
{
IDistributedCache? _distriCache = provider.GetService<IDistributedCache>();
ILogger<CacheService> loggerCache = new NullLogger<CacheService>();

if(_distriCache != null && loggerCache != null)
{
_services = new CacheService(loggerCache,_distriCache);
Assert.NotNull(_services);

_badServices = new CacheService(loggerCache,null!);
Assert.NotNull(_badServices);
}
}
}

[Fact]
public async Task Set_Get_Remove()
{
var key = "test";
var value = "test";

var key2 = "test2";
var value2 = "test2";

Assert.NotNull(_services);

bool successSet = await _services.Set(key,value);
Assert.True(successSet);

var result = await _services.Get<string>(key);
Assert.NotNull(result);
Assert.Equal(value,result);

bool successSetTimed = await _services.Set(key2,value2,TimeSpan.FromSeconds(5));
Assert.True(successSetTimed);

await Task.Delay(TimeSpan.FromSeconds(7));

var result2 = await _services.Get<string>(key2);
Assert.Null(result2);

bool successDel = await _services.Remove(key);
Assert.True(successDel);
}

[Fact]
public async Task Set_Get_Remove_With_Bad_Config()
{


var key = "test";
var value = "test";

var key2 = "test2";
var value2 = "test2";

Assert.NotNull(_badServices);
bool badSet = await _badServices.Set(key,value);
Assert.False(badSet);

var result = await _badServices.Get<string>(key);
Assert.Null(result);

bool badSetTimed = await _badServices.Set(key2,value2,TimeSpan.FromSeconds(5));
Assert.False(badSetTimed);

var result2 = await _badServices.Get<string>(key2);
Assert.Null(result2);

bool badDel = await _badServices.Remove(key);
Assert.False(badDel);
}

using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using WHMapper.Services.Cache;

namespace WHMapper.Tests.Services.Cache;

[Collection("C1-Services")]
public class CacheIntegrationTests
{
private readonly ICacheService? _services;
private readonly ICacheService? _badServices;

public CacheIntegrationTests()
{
var services = new ServiceCollection();

var configuration = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.AddEnvironmentVariables()
.Build();

services.AddStackExchangeRedisCache(option =>
{
option.Configuration = configuration.GetConnectionString("RedisConnection");
option.InstanceName = "WHMapper";
});


var provider = services.BuildServiceProvider();
if (provider != null)
{
IDistributedCache? _distriCache = provider.GetService<IDistributedCache>();
ILogger<CacheService> loggerCache = new NullLogger<CacheService>();

if (_distriCache != null && loggerCache != null)
{
_services = new CacheService(loggerCache, _distriCache);
Assert.NotNull(_services);

_badServices = new CacheService(loggerCache, null!);
Assert.NotNull(_badServices);
}
}
}

[Fact]
public async Task Set_Get_Remove()
{
var key = "test";
var value = "test";

var key2 = "test2";
var value2 = "test2";

Assert.NotNull(_services);

bool successSet = await _services.Set(key, value);
Assert.True(successSet);

var result = await _services.Get<string>(key);
Assert.NotNull(result);
Assert.Equal(value, result);

bool successSetTimed = await _services.Set(key2, value2, TimeSpan.FromSeconds(5));
Assert.True(successSetTimed);

await Task.Delay(TimeSpan.FromSeconds(7));

var result2 = await _services.Get<string>(key2);
Assert.Null(result2);

bool successDel = await _services.Remove(key);
Assert.True(successDel);
}

[Fact]
public async Task Set_Get_Remove_With_Bad_Config()
{


var key = "test";
var value = "test";

var key2 = "test2";
var value2 = "test2";

Assert.NotNull(_badServices);
bool badSet = await _badServices.Set(key, value);
Assert.False(badSet);

var result = await _badServices.Get<string>(key);
Assert.Null(result);

bool badSetTimed = await _badServices.Set(key2, value2, TimeSpan.FromSeconds(5));
Assert.False(badSetTimed);

var result2 = await _badServices.Get<string>(key2);
Assert.Null(result2);

bool badDel = await _badServices.Remove(key);
Assert.False(badDel);
}
}
143 changes: 143 additions & 0 deletions src/WHMapper.Tests/Services/Cache/CacheServiceObjectTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
using AutoFixture.Xunit2;
using Microsoft.Extensions.Caching.Distributed;
using Moq;
using System.Text;
using System.Text.Json;
using WHMapper.Services.Cache;

namespace WHMapper.Tests.Services.Cache
{
public class CacheServiceObjectTests
{
[Theory, AutoDomainData]
public async Task WhenCacheContainsSerializedByteArray_GettingKey_ReturnsValue(
string key,
FakeCacheObject value,
[Frozen] Mock<IDistributedCache> cacheMock,
CacheService sut)
{
var serializedCachedValue = JsonSerializer.Serialize(value);
byte[] cachedValueBytes = Encoding.ASCII.GetBytes(serializedCachedValue);
cacheMock.Setup(cache => cache.GetAsync(key, It.IsAny<CancellationToken>()))
.ReturnsAsync(cachedValueBytes);

var result = await sut.Get<FakeCacheObject>(key);

Assert.Equal(value, result);
}

[Theory, AutoDomainData]
public async Task WhenCacheContainsDeformedString_GettingKey_ReturnsNull(
string key,
string value,
[Frozen] Mock<IDistributedCache> cacheMock,
CacheService sut)
{
byte[] valueBytes = Encoding.ASCII.GetBytes(value);
cacheMock.Setup(cache => cache.GetAsync(key, It.IsAny<CancellationToken>()))
.ReturnsAsync(valueBytes);

var result = await sut.Get<FakeCacheObject>(key);

Assert.Null(result);
}

[Theory, AutoDomainData]
public async Task WhenCacheDoesntContainKey_GettingKey_ReturnsNull(
string key,
[Frozen] Mock<IDistributedCache> cacheMock,
CacheService sut)
{
cacheMock.Setup(cache => cache.GetAsync(key, It.IsAny<CancellationToken>()))
.ReturnsAsync((byte[]?)null);

var result = await sut.Get<FakeCacheObject>(key);

Assert.Null(result);
}

[Theory, AutoMoqData]
public async Task WhenSettingValue_WithExpiry_SetsValue(
string key,
FakeCacheObject value,
[Frozen] Mock<IDistributedCache> cacheMock,
CacheService sut)
{
var serializedValue = JsonSerializer.Serialize(value);
byte[] serializedValueBytes = Encoding.ASCII.GetBytes(serializedValue);

var result = await sut.Set(key, value, new TimeSpan(0,5,0));

Assert.True(result);
cacheMock.Verify(cache => cache.SetAsync(key, serializedValueBytes, It.Is<DistributedCacheEntryOptions>(x => x.AbsoluteExpirationRelativeToNow != null), It.IsAny<CancellationToken>()), Times.Once);
}

[Theory, AutoMoqData]
public async Task WhenSettingValue_WithoutExpiry_SetsValue(
string key,
FakeCacheObject value,
[Frozen] Mock<IDistributedCache> cacheMock,
CacheService sut)
{
var serializedValue = JsonSerializer.Serialize(value);
byte[] serializedValueBytes = Encoding.ASCII.GetBytes(serializedValue);

var result = await sut.Set(key, value);

Assert.True(result);
cacheMock.Verify(cache => cache.SetAsync(key, serializedValueBytes, It.Is<DistributedCacheEntryOptions>(x => x.AbsoluteExpirationRelativeToNow == null), It.IsAny<CancellationToken>()), Times.Once);
}

[Theory, AutoMoqData]
public async Task WhenSettingValue_WhenKeyIsNull_ReturnsFalse(
FakeCacheObject value,
CacheService sut)
{
var result = await sut.Set(null!, value);
Assert.False(result);
}

[Theory, AutoMoqData]
public async Task WhenSettingValue_ThatExists_OverWritesValue(
string key,
FakeCacheObject value,
[Frozen] Mock<IDistributedCache> cacheMock,
CacheService sut)
{
var serializedValue = JsonSerializer.Serialize(value);
byte[] serializedValueBytes = Encoding.ASCII.GetBytes(serializedValue);

//Ensuring that the IDistributedCache always returns something, this is to
//ensure that this behaviour doesn't change in the future.
cacheMock.Setup(cache => cache.GetAsync(key, It.IsAny<CancellationToken>()))
.ReturnsAsync(serializedValueBytes);
cacheMock.Setup(cache => cache.Get(key))
.Returns(serializedValueBytes);

var result = await sut.Set(key, value);

Assert.True(result);
cacheMock.Verify(cache => cache.SetAsync(key, serializedValueBytes, It.Is<DistributedCacheEntryOptions>(x => x.AbsoluteExpirationRelativeToNow == null), It.IsAny<CancellationToken>()), Times.Once);
}

[Theory, AutoMoqData]
public async Task WhenRemovingValue_RemovesValue(
string key,
[Frozen] Mock<IDistributedCache> cacheMock,
CacheService sut)
{
var result = await sut.Remove(key);

Assert.True(result);
cacheMock.Verify(cache => cache.RemoveAsync(key, default), Times.Once);
}

[Theory, AutoMoqData]
public async Task WhenRemovingValue_KeyIsNull_ReturnsFalse(
CacheService sut)
{
var result = await sut.Remove(null!);
Assert.False(result);
}
}
}
Loading

0 comments on commit 22fd256

Please sign in to comment.