Exemple #1
0
        public ScopedProvidersService(ICacheProvider cacheProvider,
                                      IResultsApiClient resultsApiClient,
                                      ISpecificationsApiClient specificationsApiClient,
                                      IProviderVersionService providerVersionService,
                                      IScopedProvidersServiceSettings scopedProvidersServiceSettings,
                                      IFileSystemCache fileSystemCache,
                                      IJobManagement jobManagement,
                                      IProvidersResiliencePolicies providersResiliencePolicies,
                                      ILogger logger) : base(jobManagement, logger)
        {
            Guard.ArgumentNotNull(cacheProvider, nameof(cacheProvider));
            Guard.ArgumentNotNull(resultsApiClient, nameof(resultsApiClient));
            Guard.ArgumentNotNull(specificationsApiClient, nameof(specificationsApiClient));
            Guard.ArgumentNotNull(providerVersionService, nameof(providerVersionService));
            Guard.ArgumentNotNull(scopedProvidersServiceSettings, nameof(scopedProvidersServiceSettings));
            Guard.ArgumentNotNull(fileSystemCache, nameof(fileSystemCache));
            Guard.ArgumentNotNull(jobManagement, nameof(jobManagement));
            Guard.ArgumentNotNull(providersResiliencePolicies?.SpecificationsApiClient, nameof(providersResiliencePolicies.SpecificationsApiClient));
            Guard.ArgumentNotNull(providersResiliencePolicies?.ResultsApiClient, nameof(providersResiliencePolicies.ResultsApiClient));
            Guard.ArgumentNotNull(providersResiliencePolicies?.CacheProvider, nameof(providersResiliencePolicies.CacheProvider));
            Guard.ArgumentNotNull(logger, nameof(logger));

            _cachePolicy                    = providersResiliencePolicies.CacheProvider;
            _specificationsPolicy           = providersResiliencePolicies.SpecificationsApiClient;
            _resultsPolicy                  = providersResiliencePolicies.ResultsApiClient;
            _cacheProvider                  = cacheProvider;
            _resultsApiClient               = resultsApiClient;
            _specificationsApiClient        = specificationsApiClient;
            _providerVersionService         = providerVersionService;
            _fileSystemCache                = fileSystemCache;
            _scopedProvidersServiceSettings = scopedProvidersServiceSettings;
            _jobManagement                  = jobManagement;
            _logger = logger;
        }
        public void Initialize()
        {
            _mapper = new MapperConfiguration(_ =>
            {
                _.AddProfile <ExternalServiceMappingProfile>();
            }).CreateMapper();

            _publishedProviderVersion = NewRandomString();
            _providerId        = NewRandomString();
            _providerVersionId = NewRandomString();

            _publishedFundingRepository = Substitute.For <IPublishedFundingRepository>();
            _providersApiClient         = Substitute.For <IProvidersApiClient>();
            _logger          = Substitute.For <ILogger>();
            _cacheSettings   = Substitute.For <IExternalApiFileSystemCacheSettings>();
            _fileSystemCache = Substitute.For <IFileSystemCache>();

            _publishedProviderRetrievalService = new PublishedProviderRetrievalService(
                _publishedFundingRepository,
                PublishingResilienceTestHelper.GenerateTestPolicies(),
                _providersApiClient,
                _logger,
                _mapper,
                _cacheSettings,
                _fileSystemCache);
        }
Exemple #3
0
        public PublishedProviderRetrievalService(
            IPublishedFundingRepository publishedFundingRepository,
            IPublishingResiliencePolicies publishingResiliencePolicies,
            IProvidersApiClient providersApiClient,
            ILogger logger,
            IMapper mapper,
            IExternalApiFileSystemCacheSettings cacheSettings,
            IFileSystemCache fileSystemCache)
        {
            Guard.ArgumentNotNull(publishedFundingRepository, nameof(publishedFundingRepository));
            Guard.ArgumentNotNull(providersApiClient, nameof(providersApiClient));
            Guard.ArgumentNotNull(logger, nameof(logger));
            Guard.ArgumentNotNull(mapper, nameof(mapper));
            Guard.ArgumentNotNull(publishingResiliencePolicies, nameof(publishingResiliencePolicies));
            Guard.ArgumentNotNull(publishingResiliencePolicies.PublishedFundingRepository, nameof(publishingResiliencePolicies.PublishedFundingRepository));
            Guard.ArgumentNotNull(publishingResiliencePolicies.ProvidersApiClient, nameof(publishingResiliencePolicies.ProvidersApiClient));
            Guard.ArgumentNotNull(cacheSettings, nameof(cacheSettings));
            Guard.ArgumentNotNull(fileSystemCache, nameof(fileSystemCache));

            _publishedFundingRepository = publishedFundingRepository;
            _providersApiClient         = providersApiClient;
            _logger          = logger;
            _mapper          = mapper;
            _cacheSettings   = cacheSettings;
            _fileSystemCache = fileSystemCache;
            _publishedFundingRepositoryPolicy = publishingResiliencePolicies.PublishedFundingRepository;
            _providersApiClientPolicy         = publishingResiliencePolicies.ProvidersApiClient;
        }
Exemple #4
0
        public void SetUp()
        {
            _versionKeyProvider = Substitute.For <IProviderSourceDatasetVersionKeyProvider>();
            _fileSystemCache    = Substitute.For <IFileSystemCache>();
            _cosmosRepository   = Substitute.For <ICosmosRepository>();
            _resiliencePolicies = CalcEngineResilienceTestHelper.GenerateTestPolicies();

            _repository = new ProviderSourceDatasetsRepository(_cosmosRepository, _resiliencePolicies);

            _specificationId = "specId";
        }
Exemple #5
0
 private static PublishedFundingRetrievalService CreatePublishedFundingRetrievalService(
     IBlobClient blobClient           = null,
     ILogger logger                   = null,
     IFileSystemCache fileSystemCache = null,
     IExternalApiFileSystemCacheSettings cacheSettings = null)
 {
     return(new PublishedFundingRetrievalService(
                blobClient ?? CreateBlobClient(),
                ExternalApiResilienceTestHelper.GenerateTestPolicies(),
                fileSystemCache ?? CreateFileSystemCache(),
                logger ?? CreateLogger(),
                cacheSettings ?? CreateFileSystemCacheSettings()));
 }
Exemple #6
0
        public SpecificationAssemblyProvider(IFileSystemCache fileSystemCache,
                                             IBlobClient blobs,
                                             ICalculatorResiliencePolicies resiliencePolicies,
                                             ILogger logger)
        {
            Guard.ArgumentNotNull(fileSystemCache, nameof(fileSystemCache));
            Guard.ArgumentNotNull(blobs, nameof(blobs));
            Guard.ArgumentNotNull(logger, nameof(logger));
            Guard.ArgumentNotNull(resiliencePolicies?.BlobClient, nameof(resiliencePolicies.BlobClient));

            _fileSystemCache = fileSystemCache;
            _blobs           = blobs;
            _logger          = logger;
            _blobResilience  = resiliencePolicies.BlobClient;
        }
Exemple #7
0
        public FeedItemPreLoader(IFeedItemPreloaderSettings settings,
                                 IPublishedFundingRetrievalService retrievalService,
                                 IFundingFeedSearchService searchService,
                                 IFileSystemCache cache,
                                 IExternalApiFileSystemCacheSettings apiFileSystemCacheSettings)
        {
            Guard.ArgumentNotNull(settings, nameof(settings));
            Guard.ArgumentNotNull(retrievalService, nameof(retrievalService));
            Guard.ArgumentNotNull(searchService, nameof(searchService));
            Guard.ArgumentNotNull(cache, nameof(cache));

            _settings                   = settings;
            _retrievalService           = retrievalService;
            _searchService              = searchService;
            _cache                      = cache;
            _apiFileSystemCacheSettings = apiFileSystemCacheSettings;
        }
        public void SetUp()
        {
            _settings                   = new FeedItemPreLoaderSettings();
            _retrievalService           = Substitute.For <IPublishedFundingRetrievalService>();
            _searchService              = Substitute.For <IFundingFeedSearchService>();
            _cache                      = Substitute.For <IFileSystemCache>();
            _apiFileSystemCacheSettings = Substitute.For <IExternalApiFileSystemCacheSettings>();

            _preLoader = new FeedItemPreLoader(_settings,
                                               _retrievalService,
                                               _searchService,
                                               _cache,
                                               _apiFileSystemCacheSettings);

            _retrievalService
            .GetFundingFeedDocument(Arg.Any <string>(), Arg.Any <bool>())
            .Returns((string)null);
        }
Exemple #9
0
        public PublishedFundingRetrievalService(IBlobClient blobClient,
                                                IExternalApiResiliencePolicies resiliencePolicies,
                                                IFileSystemCache fileSystemCache,
                                                ILogger logger,
                                                IExternalApiFileSystemCacheSettings cacheSettings)
        {
            Guard.ArgumentNotNull(blobClient, nameof(blobClient));
            Guard.ArgumentNotNull(resiliencePolicies, nameof(resiliencePolicies));
            Guard.ArgumentNotNull(fileSystemCache, nameof(fileSystemCache));
            Guard.ArgumentNotNull(logger, nameof(logger));
            Guard.ArgumentNotNull(cacheSettings, nameof(cacheSettings));
            Guard.ArgumentNotNull(resiliencePolicies.PublishedFundingBlobRepositoryPolicy, nameof(resiliencePolicies.PublishedFundingBlobRepositoryPolicy));

            _blobClient = blobClient;
            _publishedFundingRepositoryPolicy = resiliencePolicies.PublishedFundingBlobRepositoryPolicy;
            _fileSystemCache = fileSystemCache;
            _logger          = logger;
            _cacheSettings   = cacheSettings;
        }
        public ProviderVersionService(ICacheProvider cacheProvider,
                                      IBlobClient blobClient,
                                      ILogger logger,
                                      IValidator <ProviderVersionViewModel> providerVersionModelValidator,
                                      IProviderVersionsMetadataRepository providerVersionMetadataRepository,
                                      IProvidersResiliencePolicies resiliencePolicies,
                                      IMapper mapper,
                                      IFileSystemCache fileSystemCache,
                                      IProviderVersionServiceSettings providerVersionServiceSettings,
                                      ISearchRepository <ProvidersIndex> searchRepository)
        {
            Guard.ArgumentNotNull(blobClient, nameof(blobClient));
            Guard.ArgumentNotNull(logger, nameof(logger));
            Guard.ArgumentNotNull(providerVersionModelValidator, nameof(providerVersionModelValidator));
            Guard.ArgumentNotNull(resiliencePolicies?.ProviderVersionMetadataRepository, nameof(resiliencePolicies.ProviderVersionMetadataRepository));
            Guard.ArgumentNotNull(resiliencePolicies?.BlobRepositoryPolicy, nameof(resiliencePolicies.BlobRepositoryPolicy));
            Guard.ArgumentNotNull(resiliencePolicies?.CacheProvider, nameof(resiliencePolicies.CacheProvider));
            Guard.ArgumentNotNull(resiliencePolicies?.ProviderVersionsSearchRepository, nameof(resiliencePolicies.ProviderVersionsSearchRepository));
            Guard.ArgumentNotNull(mapper, nameof(mapper));
            Guard.ArgumentNotNull(fileSystemCache, nameof(fileSystemCache));
            Guard.ArgumentNotNull(providerVersionServiceSettings, nameof(providerVersionServiceSettings));
            Guard.ArgumentNotNull(cacheProvider, nameof(cacheProvider));
            Guard.ArgumentNotNull(searchRepository, nameof(searchRepository));

            _cacheProvider = cacheProvider;
            _blobClient    = blobClient;
            _logger        = logger;
            _providerVersionModelValidator           = providerVersionModelValidator;
            _providerVersionMetadataRepository       = providerVersionMetadataRepository;
            _providerVersionMetadataRepositoryPolicy = resiliencePolicies.ProviderVersionMetadataRepository;
            _providersSearchPolicy = resiliencePolicies.ProviderVersionsSearchRepository;
            _cachePolicy           = resiliencePolicies.CacheProvider;
            _blobRepositoryPolicy  = resiliencePolicies.BlobRepositoryPolicy;
            _mapper          = mapper;
            _fileSystemCache = fileSystemCache;
            _providerVersionServiceSettings = providerVersionServiceSettings;
            _searchRepository = searchRepository;
        }
 private static ProviderFundingVersionService CreateProviderFundingVersionService(ILogger logger                   = null,
                                                                                  IBlobClient blobClient           = null,
                                                                                  IFileSystemCache fileSystemCache = null,
                                                                                  IExternalApiFileSystemCacheSettings cacheSettings = null,
                                                                                  PublishingInterfaces.IPublishedFundingRepository publishedFundingRepository = null)
 {
     return(new ProviderFundingVersionService(blobClient ?? CreateBlobClient(),
                                              publishedFundingRepository ?? CreatePublishedFundingRepository(),
                                              logger ?? CreateLogger(),
                                              ExternalApiResilienceTestHelper.GenerateTestPolicies(),
                                              fileSystemCache ?? CreateFileSystemCache(),
                                              cacheSettings ?? CreateFileSystemCacheSettings()));
 }
        public async Task GetProviderFundingVersionsBody_GivenReturnsFromBlobStorage_ReturnsOK(bool isFileSystemCacheEnabled,
                                                                                               int expectedCacheAddCount)
        {
            //Arrange
            string template = "just a string";

            byte[] bytes = Encoding.UTF8.GetBytes(template);

            Stream memoryStream = new MemoryStream(bytes);

            ILogger          logger          = CreateLogger();
            ICloudBlob       cloudBlob       = CreateBlob();
            IFileSystemCache fileSystemCache = CreateFileSystemCache();
            IExternalApiFileSystemCacheSettings cacheSettings = Substitute.For <IExternalApiFileSystemCacheSettings>();

            cacheSettings.IsEnabled.Returns(isFileSystemCacheEnabled);

            IBlobClient blobClient = CreateBlobClient();

            blobClient
            .BlobExistsAsync(blobName)
            .Returns(true);

            blobClient
            .GetBlobReferenceFromServerAsync(blobName)
            .Returns(cloudBlob);

            blobClient
            .DownloadToStreamAsync(cloudBlob)
            .Returns(memoryStream);

            ProviderFundingVersionService service = CreateProviderFundingVersionService(logger, blobClient, fileSystemCache, cacheSettings);

            //Act
            IActionResult result = await service.GetProviderFundingVersion(providerFundingVersion);

            //Assert
            result
            .Should()
            .BeOfType <ContentResult>();

            ContentResult contentResult = result as ContentResult;

            contentResult
            .ContentType
            .Should()
            .Be("application/json");

            contentResult
            .StatusCode
            .Should()
            .Be((int)HttpStatusCode.OK);

            contentResult
            .Content
            .Should()
            .Be(template);

            fileSystemCache
            .Received(expectedCacheAddCount)
            .Add(Arg.Is <ProviderFundingFileSystemCacheKey>(_ => _.Key == providerFundingVersion),
                 memoryStream,
                 CancellationToken.None);
        }
        public async Task GetProviderFundingVersionsBody_GivenReturnsFromFileSystemCacheAndSkipBlobClientFetch_ReturnsOK()
        {
            //Arrange
            string template = "just a string";

            byte[] bytes = Encoding.UTF8.GetBytes(template);

            Stream memoryStream = new MemoryStream(bytes);

            ILogger          logger          = CreateLogger();
            IFileSystemCache fileSystemCache = CreateFileSystemCache();
            IBlobClient      blobClient      = CreateBlobClient();

            fileSystemCache.Exists(Arg.Is <ProviderFundingFileSystemCacheKey>(
                                       _ => _.Key == providerFundingVersion))
            .Returns(true);

            fileSystemCache.Get(Arg.Is <ProviderFundingFileSystemCacheKey>(
                                    _ => _.Key == providerFundingVersion))
            .Returns(memoryStream);

            ProviderFundingVersionService service = CreateProviderFundingVersionService(logger, blobClient, fileSystemCache);

            //Act
            IActionResult result = await service.GetProviderFundingVersion(providerFundingVersion);

            //Assert
            result
            .Should()
            .BeOfType <ContentResult>();

            ContentResult contentResult = result as ContentResult;

            contentResult
            .ContentType
            .Should()
            .Be("application/json");

            contentResult
            .StatusCode
            .Should()
            .Be((int)HttpStatusCode.OK);

            contentResult
            .Content
            .Should()
            .Be(template);

            await blobClient
            .Received(0)
            .BlobExistsAsync(providerFundingVersion);

            await blobClient
            .Received(0)
            .GetAsync(Arg.Any <string>());

            fileSystemCache
            .Received(0)
            .Add(Arg.Is <ProviderFundingFileSystemCacheKey>(_ => _.Key == providerFundingVersion),
                 memoryStream,
                 CancellationToken.None);
        }
        public void RegisterComponents(IServiceCollection builder)
        {
            builder.AddSingleton <IUserProfileProvider, UserProfileProvider>();

            builder
            .AddSingleton <IPublishedFundingQueryBuilder, PublishedFundingQueryBuilder>();

            builder
            .AddSingleton <IHealthChecker, ControllerResolverHealthCheck>();

            builder.AddFeatureToggling(Configuration);

            // Register v3 services
            builder
            .AddSingleton <IFundingFeedService, FundingFeedService>();

            builder
            .AddSingleton <IFundingFeedItemByIdService, FundingFeedItemByIdService>();

            builder
            .AddSingleton <IFileSystemCache, FileSystemCache>()
            .AddSingleton <IFileSystemAccess, FileSystemAccess>()
            .AddSingleton <IFileSystemCacheSettings, FileSystemCacheSettings>();

            builder.AddSingleton <IFeedItemPreloader, FeedItemPreLoader>()
            .AddSingleton <IFeedItemPreloaderSettings>(ctx =>
            {
                FeedItemPreLoaderSettings settings = new FeedItemPreLoaderSettings();

                Configuration.Bind("feeditempreloadersettings", settings);

                return(settings);
            });

            builder.AddSingleton <IExternalApiFileSystemCacheSettings>(ctx =>
            {
                ExternalApiFileSystemCacheSettings settings = new ExternalApiFileSystemCacheSettings();

                Configuration.Bind("externalapifilesystemcachesettings", settings);

                return(settings);
            });

            builder.AddSingleton <IExternalEngineOptions>(ctx =>
            {
                ExternalEngineOptions settings = new ExternalEngineOptions();

                Configuration.Bind("externalengineoptions", settings);

                return(settings);
            });

            builder.AddSingleton <IPublishedFundingRetrievalService>((ctx) =>
            {
                BlobStorageOptions storageSettings = new BlobStorageOptions();

                Configuration.Bind("AzureStorageSettings", storageSettings);

                storageSettings.ContainerName = "publishedfunding";

                IBlobContainerRepository blobContainerRepository = new BlobContainerRepository(storageSettings);
                IBlobClient blobClient = new BlobClient(blobContainerRepository);

                IExternalApiResiliencePolicies resiliencePolicies = ctx.GetService <IExternalApiResiliencePolicies>();
                ILogger logger = ctx.GetService <ILogger>();
                IFileSystemCache fileSystemCache             = ctx.GetService <IFileSystemCache>();
                IExternalApiFileSystemCacheSettings settings = ctx.GetService <IExternalApiFileSystemCacheSettings>();

                return(new PublishedFundingRetrievalService(blobClient, resiliencePolicies, fileSystemCache, logger, settings));
            });

            builder.AddSingleton <IPublishedFundingRepository, PublishedFundingRepository>((ctx) =>
            {
                CosmosDbSettings calssDbSettings = new CosmosDbSettings();

                Configuration.Bind("CosmosDbSettings", calssDbSettings);

                calssDbSettings.ContainerName = "publishedfunding";

                CosmosRepository calcsCosmosRepostory = new CosmosRepository(calssDbSettings);
                IPublishedFundingQueryBuilder publishedFundingQueryBuilder = ctx.GetService <IPublishedFundingQueryBuilder>();

                return(new PublishedFundingRepository(calcsCosmosRepostory, publishedFundingQueryBuilder));
            });

            // Register dependencies
            builder
            .AddSingleton <IFundingFeedSearchService, FundingFeedSearchService>()
            .AddSingleton <IHealthChecker, FundingFeedSearchService>();

            builder
            .AddSingleton <IFundingStreamService, FundingStreamService>();
            builder
            .AddSingleton <IPublishedProviderRetrievalService, PublishedProviderRetrievalService>();

            builder.AddSearch(Configuration);
            builder
            .AddSingleton <ISearchRepository <PublishedFundingIndex>, SearchRepository <PublishedFundingIndex> >();

            builder.AddApplicationInsightsTelemetry();
            builder.AddApplicationInsightsTelemetryClient(Configuration, "CalculateFunding.Api.External");
            builder.AddApplicationInsightsServiceName(Configuration, "CalculateFunding.Api.External");
            builder.AddLogging("CalculateFunding.Api.External");
            builder.AddTelemetry();


            builder.AddHttpContextAccessor();
            builder.AddPolicySettings(Configuration);

            builder.AddSingleton <IPublishingResiliencePolicies>((ctx) =>
            {
                PolicySettings policySettings = ctx.GetService <PolicySettings>();

                AsyncBulkheadPolicy totalNetworkRequestsPolicy = ResiliencePolicyHelpers.GenerateTotalNetworkRequestsPolicy(policySettings);

                return(new ResiliencePolicies()
                {
                    FundingFeedSearchRepository = SearchResiliencePolicyHelper.GenerateSearchPolicy(totalNetworkRequestsPolicy),
                    PublishedFundingBlobRepository = ResiliencePolicyHelpers.GenerateRestRepositoryPolicy(totalNetworkRequestsPolicy),
                    PublishedFundingRepository = CosmosResiliencePolicyHelper.GenerateCosmosPolicy(totalNetworkRequestsPolicy),
                    ProvidersApiClient = ResiliencePolicyHelpers.GenerateRestRepositoryPolicy(totalNetworkRequestsPolicy),
                });
            });

            builder.AddSingleton <IExternalApiResiliencePolicies>((ctx) =>
            {
                PolicySettings policySettings = ctx.GetService <PolicySettings>();

                AsyncBulkheadPolicy totalNetworkRequestsPolicy = ResiliencePolicyHelpers.GenerateTotalNetworkRequestsPolicy(policySettings);

                return(new ExternalApiResiliencePolicies()
                {
                    PublishedProviderBlobRepositoryPolicy = ResiliencePolicyHelpers.GenerateRestRepositoryPolicy(totalNetworkRequestsPolicy),
                    PublishedFundingBlobRepositoryPolicy = ResiliencePolicyHelpers.GenerateRestRepositoryPolicy(totalNetworkRequestsPolicy),
                    PublishedFundingRepositoryPolicy = CosmosResiliencePolicyHelper.GenerateCosmosPolicy(totalNetworkRequestsPolicy),
                    PoliciesApiClientPolicy = ResiliencePolicyHelpers.GenerateRestRepositoryPolicy(totalNetworkRequestsPolicy),
                });
            });

            MapperConfiguration externalConfig = new MapperConfiguration(c =>
            {
                c.AddProfile <ExternalServiceMappingProfile>();
            });

            builder.AddSingleton(externalConfig.CreateMapper());

            builder.AddAuthenticatedHealthCheckMiddleware();
            builder.AddTransient <ContentTypeCheckMiddleware>();
            builder.AddPoliciesInterServiceClient(Configuration);
            builder.AddProvidersInterServiceClient(Configuration);

            builder.AddSingleton <IProviderFundingVersionService>((ctx) =>
            {
                BlobStorageOptions storageSettings = new BlobStorageOptions();

                Configuration.Bind("AzureStorageSettings", storageSettings);

                storageSettings.ContainerName = "publishedproviderversions";

                IBlobContainerRepository blobContainerRepository = new BlobContainerRepository(storageSettings);
                IBlobClient blobClient = new BlobClient(blobContainerRepository);

                IExternalApiResiliencePolicies publishingResiliencePolicies = ctx.GetService <IExternalApiResiliencePolicies>();
                ILogger logger = ctx.GetService <ILogger>();
                IFileSystemCache fileSystemCache                       = ctx.GetService <IFileSystemCache>();
                IExternalApiFileSystemCacheSettings settings           = ctx.GetService <IExternalApiFileSystemCacheSettings>();
                IPublishedFundingRepository publishedFundingRepository = ctx.GetService <IPublishedFundingRepository>();

                return(new ProviderFundingVersionService(blobClient, publishedFundingRepository, logger, publishingResiliencePolicies, fileSystemCache, settings));
            });
        }
Exemple #15
0
        public async Task GetFundingFeedDocument_WhenReturnsFromBlobStorage_ReturnsOK(bool fileSystemCacheEnabled,
                                                                                      int expectedCacheAccessCount)
        {
            //Arrange
            string template     = new RandomString();
            string documentPath = "cromulent.json";
            string uri          = $"https://cfs/test/{documentPath}";

            Stream memoryStream = new MemoryStream(Encoding.UTF8.GetBytes(template));

            ILogger          logger          = CreateLogger();
            ICloudBlob       cloudBlob       = CreateBlob();
            IFileSystemCache fileSystemCache = CreateFileSystemCache();
            IExternalApiFileSystemCacheSettings cacheSettings = Substitute.For <IExternalApiFileSystemCacheSettings>();

            cacheSettings.IsEnabled.Returns(fileSystemCacheEnabled);

            cloudBlob
            .Exists()
            .Returns(true);
            cloudBlob
            .Exists(Arg.Any <BlobRequestOptions>(), Arg.Any <OperationContext>())
            .Returns(true);

            IBlobClient blobClient = CreateBlobClient();

            blobClient
            .GetBlockBlobReference(Arg.Is(documentPath))
            .Returns(cloudBlob);

            blobClient
            .DownloadToStreamAsync(Arg.Is(cloudBlob))
            .Returns(memoryStream);

            PublishedFundingRetrievalService service = CreatePublishedFundingRetrievalService(
                blobClient: blobClient,
                logger: logger,
                fileSystemCache: fileSystemCache,
                cacheSettings: cacheSettings);

            //Act
            string result = await service.GetFundingFeedDocument(uri);

            //Assert
            result
            .Should()
            .Be(template);

            blobClient
            .Received(1)
            .GetBlockBlobReference(documentPath);

            cloudBlob
            .Received(1)
            .Exists();

            logger
            .Received(0)
            .Error(Arg.Any <string>());

            await blobClient
            .Received(1)
            .DownloadToStreamAsync(cloudBlob);

            fileSystemCache
            .Received(0)
            .Get(Arg.Any <FundingFileSystemCacheKey>());

            string documentName = Path.GetFileNameWithoutExtension(documentPath);

            fileSystemCache
            .Received(expectedCacheAccessCount)
            .Add(Arg.Is <FundingFileSystemCacheKey>(
                     _ => _.Key == documentName),
                 memoryStream);
        }