Skip to content

Commit

Permalink
CON-2182 Refactor content service to use decorator pattern
Browse files Browse the repository at this point in the history
  • Loading branch information
ben1stone-leftdfe committed Aug 17, 2020
1 parent d322ae5 commit 9438c68
Show file tree
Hide file tree
Showing 13 changed files with 314 additions and 111 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -70,37 +70,6 @@ public override async Task ThenIfTheMessageIsValidTheValueIsReturnedInTheRespons
Assert.AreEqual(ContentBanner, response.Content);
}

[Test, RecursiveMoqAutoData]
public async Task Check_Cache_ReturnIfExists(GetClientContentRequest query1, string contentBanner1,
Mock<ICacheStorageService> cacheStorageService1,
GetClientContentRequestHandler requestHandler1,
Mock<IValidator<GetClientContentRequest>> requestValidator1,
Mock<ILog> logger,
Mock<IClientContentService> clientMockontentService)
{
query1.ContentType = "Banner";
query1.UseLegacyStyles = false;

var key = EmployerAccountsConfiguration.ApplicationId;

requestValidator1.Setup(r => r.Validate(query1)).Returns(new ValidationResult());

clientMockontentService.Setup(c => c.Get("banner", key));

requestHandler1 = new GetClientContentRequestHandler(requestValidator1.Object, logger.Object, clientMockontentService.Object,
cacheStorageService1.Object, EmployerAccountsConfiguration);

var cacheKey = key + "_banner";
cacheStorageService1.Setup(c => c.TryGet(cacheKey, out contentBanner1))
.Returns(true);
//Act
var result = await requestHandler1.Handle(query1);

//assert
Assert.AreEqual(result.Content, contentBanner1);
cacheStorageService1.Verify(x => x.TryGet(cacheKey, out contentBanner1), Times.Once);
}

[Test, RecursiveMoqAutoData]
public async Task Check_Cache_ReturnNull_CallFromClient(GetClientContentRequest query1, string contentBanner1,
Mock<ICacheStorageService> cacheStorageService1,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@


using Moq;
using NUnit.Framework;
using SFA.DAS.EmployerAccounts.Configuration;
using SFA.DAS.EmployerAccounts.Interfaces;
using SFA.DAS.EmployerAccounts.Services;
using System.Threading.Tasks;

namespace SFA.DAS.EmployerAccounts.UnitTests.Services.ContentBanner
{
public class WhenIGetContentWithCaching
{
private string _contentType;
private string _clientId;

private Mock<IClientContentService> MockClientContentService;
private Mock<ICacheStorageService> MockCacheStorageService;

private string CacheKey;
private string ContentFromCache;
private string ContentFromApi;
private EmployerAccountsConfiguration EmployerAccountsConfig;

private IClientContentService ClientContentServiceWithCaching;

[SetUp]
public void Arrange()
{
_clientId = "eas-fin";
_contentType = "banner";

EmployerAccountsConfig = new EmployerAccountsConfiguration()
{
ApplicationId = "eas-fin",
DefaultCacheExpirationInMinutes = 1
};
ContentFromCache = "<p> Example content from cache </p>";
ContentFromApi = "<p> Example content from api </p>";
CacheKey = EmployerAccountsConfig.ApplicationId + "_banner";

MockClientContentService = new Mock<IClientContentService>();
MockCacheStorageService = new Mock<ICacheStorageService>();

ClientContentServiceWithCaching = new ClientContentServiceWithCaching(MockClientContentService.Object, MockCacheStorageService.Object, EmployerAccountsConfig);
}

[Test]
public async Task AND_ItIsStoredInTheCache_THEN_ReturnContent()
{
StoredInCacheSetup();

var result = await ClientContentServiceWithCaching.Get(_contentType, EmployerAccountsConfig.ApplicationId);

Assert.AreEqual(ContentFromCache, result);
MockCacheStorageService.Verify(c => c.TryGet(CacheKey, out ContentFromCache), Times.Once);
}

[Test]
public async Task AND_ItIsStoredInTheCache_THEN_ContentApiIsNotCalled()
{
StoredInCacheSetup();

var result = await ClientContentServiceWithCaching.Get(_contentType, EmployerAccountsConfig.ApplicationId);

MockClientContentService.Verify(c => c.Get(_contentType, _clientId), Times.Never);
}

[Test]
public async Task AND_ItIsNotStoredInTheCache_THEN_CallFromClient()
{
NotStoredInCacheSetup();

var result = await ClientContentServiceWithCaching.Get(_contentType, EmployerAccountsConfig.ApplicationId);

MockClientContentService.Verify(c => c.Get(_contentType, _clientId), Times.Once);
Assert.AreEqual(ContentFromApi, result);
}
private void StoredInCacheSetup()
{
MockCacheStorageService.Setup(c => c.TryGet(CacheKey, out ContentFromCache)).Returns(true);
MockClientContentService.Setup(c => c.Get("banner", CacheKey));
}

private void NotStoredInCacheSetup()
{

MockCacheStorageService.Setup(c => c.TryGet(CacheKey, out ContentFromCache)).Returns(false);
MockClientContentService.Setup(c => c.Get("banner", EmployerAccountsConfig.ApplicationId))
.ReturnsAsync(ContentFromApi);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ public ServicesRegistry()
For<IReservationsService>().DecorateAllWith<ReservationsServiceWithTimeout>();
For<ICommitmentV2Service>().Use<CommitmentsV2Service>();
For<ICommitmentV2Service>().DecorateAllWith<CommitmentsV2ServiceWithTimeout>();
For<IClientContentService>().Use<ClientContentService>();
For<IClientContentService>().DecorateAllWith<ClientContentServiceWithCaching>();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,33 +37,21 @@ public async Task<GetClientContentResponse> Handle(GetClientContentRequest messa
throw new InvalidRequestException(validationResult.ValidationDictionary);
}

var applicationId = message.UseLegacyStyles? _employerAccountsConfiguration.ApplicationId + "-legacy" : _employerAccountsConfiguration.ApplicationId;
var cacheKey = $"{applicationId}_{message.ContentType}".ToLowerInvariant();
var applicationId = message.UseLegacyStyles? _employerAccountsConfiguration.ApplicationId + "-legacy" : _employerAccountsConfiguration.ApplicationId;

try
{
if (_cacheStorageService.TryGet(cacheKey, out string cachedContentBanner))
{
return new GetClientContentResponse
{
Content = cachedContentBanner
};
}

{
var contentBanner = await _service.Get(message.ContentType, applicationId);

if (contentBanner != null)
{
await _cacheStorageService.Save(cacheKey, contentBanner, 1);
}

return new GetClientContentResponse
{
Content = contentBanner
};
}
catch (Exception ex)
{
_logger.Error(ex, $"Failed to get Content for {cacheKey}");
_logger.Error(ex, $"Failed to get Content {message.ContentType} for {applicationId}");

return new GetClientContentResponse
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
using SFA.DAS.EmployerAccounts.Configuration;
using SFA.DAS.EmployerAccounts.Interfaces;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SFA.DAS.EmployerAccounts.Services
{
public class ClientContentServiceWithCaching : IClientContentService
{
private readonly IClientContentService _contentService;
private readonly ICacheStorageService _cacheStorageService;
private readonly EmployerAccountsConfiguration _employerAccountsConfiguration;

public ClientContentServiceWithCaching(IClientContentService contentService, ICacheStorageService cacheStorageService, EmployerAccountsConfiguration employerAccountsConfiguration)
{
_contentService = contentService;
_cacheStorageService = cacheStorageService;
_employerAccountsConfiguration = employerAccountsConfiguration;
}
public async Task<string> Get(string type, string applicationId)
{
var cacheKey = $"{applicationId}_{type}".ToLowerInvariant();

try
{
if (_cacheStorageService.TryGet(cacheKey, out string cachedContentBanner))
{
return cachedContentBanner;
}

var content = await _contentService.Get(type, applicationId);

if (content != null)
{
await _cacheStorageService.Save(cacheKey, content, _employerAccountsConfiguration.DefaultCacheExpirationInMinutes);
}

return content;
}
catch
{
throw new ArgumentException($"Failed to get content for {cacheKey}");
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -83,47 +83,8 @@ public override async Task ThenIfTheMessageIsValidTheValueIsReturnedInTheRespons
MockClientContentService.Verify(x => x.Get(_contentType, _clientId), Times.Once);
}

[Test]
public async Task AND_ItIsStoredInTheCache_THEN_ReturnContent()
{
StoredInCacheSetup();

var result = await RequestHandler.Handle(Query);

Assert.AreEqual(Content, result.Content);
MockCacheStorageService.Verify(c => c.TryGet(CacheKey, out Content), Times.Once);
}

[Test]
public async Task AND_ItIsStoredInTheCache_THEN_ContentApiIsNotCalled()
{
StoredInCacheSetup();

var result = await RequestHandler.Handle(Query);

MockClientContentService.Verify(c => c.Get(_contentType, _clientId), Times.Never);
}

[Test]
public async Task AND_ItIsNotStoredInTheCache_THEN_CallFromClient()
{
NotStoredInCacheSetup();

var result = await RequestHandler.Handle(Query);

Assert.AreEqual(Content, result.Content);
}

private void StoredInCacheSetup()
{
// RequestValidator.Setup(r => r.Validate(Query)).Returns(new ValidationResult());
MockCacheStorageService.Setup(c => c.TryGet(CacheKey, out Content)).Returns(true);
MockClientContentService.Setup(c => c.Get("banner", CacheKey));
}

private void NotStoredInCacheSetup()
{
//RequestValidator.Setup(r => r.Validate(Query)).Returns(new ValidationResult());
MockCacheStorageService.Setup(c => c.TryGet(CacheKey, out Content)).Returns(false);
MockClientContentService.Setup(c => c.Get("banner", CacheKey))
.ReturnsAsync(Content);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
using Moq;
using NUnit.Framework;
using SFA.DAS.EmployerFinance.Configuration;
using SFA.DAS.EmployerFinance.Interfaces;
using SFA.DAS.EmployerFinance.Services;
using System.Threading.Tasks;

namespace SFA.DAS.EmployerFinance.UnitTests.Services.ClientContentServiceTests.ClientContentServiceWithCachingTests
{
class WhenIGetContentDataWithCaching
{
private string _contentType;
private string _clientId;

private Mock<IClientContentService> MockClientContentService;
private Mock<ICacheStorageService> MockCacheStorageService;

private string CacheKey;
private string ContentFromCache;
private string ContentFromApi;
private EmployerFinanceConfiguration EmployerFinanceConfig;

private IClientContentService ClientContentServiceWithCaching;

[SetUp]
public void Arrange()
{
_clientId = "eas-fin";
_contentType = "banner";

EmployerFinanceConfig = new EmployerFinanceConfiguration()
{
ApplicationId = "eas-fin",
DefaultCacheExpirationInMinutes = 1
};
ContentFromCache = "<p> Example content from cache </p>";
ContentFromApi = "<p> Example content from api </p>";
CacheKey = EmployerFinanceConfig.ApplicationId + "_banner";

MockClientContentService = new Mock<IClientContentService>();
MockCacheStorageService = new Mock<ICacheStorageService>();

ClientContentServiceWithCaching = new ClientContentServiceWithCaching(MockClientContentService.Object, MockCacheStorageService.Object, EmployerFinanceConfig);
}
[Test]
public async Task AND_ItIsStoredInTheCache_THEN_ReturnContent()
{
StoredInCacheSetup();

var result = await ClientContentServiceWithCaching.Get(_contentType, EmployerFinanceConfig.ApplicationId);

Assert.AreEqual(ContentFromCache, result);
MockCacheStorageService.Verify(c => c.TryGet(CacheKey, out ContentFromCache), Times.Once);
}

[Test]
public async Task AND_ItIsStoredInTheCache_THEN_ContentApiIsNotCalled()
{
StoredInCacheSetup();

var result = await ClientContentServiceWithCaching.Get(_contentType, EmployerFinanceConfig.ApplicationId);

MockClientContentService.Verify(c => c.Get(_contentType, _clientId), Times.Never);
}

[Test]
public async Task AND_ItIsNotStoredInTheCache_THEN_CallFromClient()
{
NotStoredInCacheSetup();

var result = await ClientContentServiceWithCaching.Get(_contentType, EmployerFinanceConfig.ApplicationId);

MockClientContentService.Verify(c => c.Get(_contentType, _clientId), Times.Once);
Assert.AreEqual(ContentFromApi, result);
}
private void StoredInCacheSetup()
{
MockCacheStorageService.Setup(c => c.TryGet(CacheKey, out ContentFromCache)).Returns(true);
MockClientContentService.Setup(c => c.Get("banner", CacheKey));
}

private void NotStoredInCacheSetup()
{

MockCacheStorageService.Setup(c => c.TryGet(CacheKey, out ContentFromCache)).Returns(false);
MockClientContentService.Setup(c => c.Get("banner", EmployerFinanceConfig.ApplicationId))
.ReturnsAsync(ContentFromApi);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ public static IContainer Initialize()
c.AddRegistry<EmployerFeaturesAuthorizationRegistry>();
c.AddRegistry<EmployerUserRolesAuthorizationRegistry>();
c.AddRegistry<ContentApiClientRegistry>();
c.AddRegistry<ServicesRegistry>();
});
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,7 @@
using SFA.DAS.Http.TokenGenerators;
using SFA.DAS.NLog.Logger.Web.MessageHandlers;
using StructureMap;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;

namespace SFA.DAS.EmployerFinance.DependencyResolution
{
Expand All @@ -35,6 +30,5 @@ private HttpClient CreateClient(IContext context)

return httpClient;
}

}
}
Loading

0 comments on commit 9438c68

Please sign in to comment.