public async Task GetDistinctFundingTemplateMetadataFundingLinesContents_GivenContentsInCache_ReturnsOkObjecWithResultsFromCache()
        {
            //Arrange
            const string fundingStreamId = "PES";
            const string fundingPeriodId = "AY-2020";
            const string templateVersion = "1.0";
            string       cacheKey        = $"{CacheKeys.FundingTemplateContentMetadataDistinct}{fundingStreamId}:{fundingPeriodId}:{templateVersion}".ToLowerInvariant();

            string blobNamePrefix = $"{fundingStreamId}/{ fundingPeriodId}/{templateVersion}";

            IFundingTemplateRepository fundingTemplateRepository = CreateFundingTemplateRepository();

            fundingTemplateRepository
            .TemplateVersionExists(Arg.Is <string>(_ => _.Contains(blobNamePrefix)))
            .Returns(true);
            fundingTemplateRepository.GetFundingTemplateVersion(Arg.Is <string>(_ => _.Contains(blobNamePrefix)))
            .Returns(string.Empty);

            ILogger        logger        = CreateLogger();
            ICacheProvider cacheProvider = CreateCacheProvider();

            cacheProvider.GetAsync <TemplateMetadataDistinctContents>(cacheKey)
            .Returns(new TemplateMetadataDistinctContents()
            {
                FundingStreamId = fundingStreamId,
                FundingPeriodId = fundingPeriodId,
                TemplateVersion = templateVersion
            });

            FundingTemplateService fundingTemplateService = CreateFundingTemplateService(
                logger,
                fundingTemplateRepository: fundingTemplateRepository,
                cacheProvider: cacheProvider);

            //Act
            ActionResult <TemplateMetadataDistinctContents> result = await fundingTemplateService.GetDistinctFundingTemplateMetadataContents(fundingStreamId, fundingPeriodId, templateVersion);

            //Assert

            TemplateMetadataDistinctContents contents = result.Value;

            contents.Should().NotBeNull();
            contents.FundingStreamId.Should().Be(fundingStreamId);
            contents.FundingPeriodId.Should().Be(fundingPeriodId);
            contents.TemplateVersion.Should().Be(templateVersion);

            await cacheProvider
            .Received(1).GetAsync <TemplateMetadataDistinctContents>(cacheKey);

            await fundingTemplateRepository
            .Received(0).GetFundingTemplateVersion(Arg.Is <string>(_ => _.Contains(blobNamePrefix)));

            await cacheProvider
            .Received(0)
            .SetAsync(cacheKey,
                      Arg.Is <TemplateMetadataDistinctContents>(_ => _.FundingStreamId == fundingStreamId && _.FundingPeriodId == fundingPeriodId && _.TemplateVersion == templateVersion),
                      TimeSpan.FromDays(365),
                      true,
                      null);
        }
        public async Task GetFundingTemplate_GivenFetechingBlobFails_ReturnsInternalServerError()
        {
            //Arrange
            const string fundingStreamId = "PES";
            const string templateVersion = "1.2";
            const string fundingPeriodId = "AY-2020";

            string cacheKey = $"{CacheKeys.FundingTemplatePrefix}{fundingStreamId}-{fundingPeriodId}-{templateVersion}";

            string blobName = $"{fundingStreamId}/{fundingPeriodId}/{templateVersion}.json";

            string template = string.Empty;

            ICacheProvider cacheProvider = CreateCacheProvider();

            cacheProvider
            .GetAsync <string>(Arg.Is(cacheKey))
            .Returns((string)null);

            IFundingTemplateRepository fundingTemplateRepository = CreateFundingTemplateRepository();

            fundingTemplateRepository
            .TemplateVersionExists(Arg.Is(blobName))
            .Returns(true);

            fundingTemplateRepository
            .When(x => x.GetFundingTemplateVersion(Arg.Is(blobName)))
            .Do(x => { throw new Exception(); });

            ILogger logger = CreateLogger();

            FundingTemplateService fundingTemplateService = CreateFundingTemplateService(
                logger,
                cacheProvider: cacheProvider,
                fundingTemplateRepository: fundingTemplateRepository);

            //Act
            ActionResult <string> result = await fundingTemplateService.GetFundingTemplateSourceFile(fundingStreamId, fundingPeriodId, templateVersion);

            //Assert
            result
            .Result
            .Should()
            .BeAssignableTo <InternalServerErrorResult>()
            .Which
            .Value
            .Should()
            .Be($"Error occurred fetching funding template for funding stream id '{fundingStreamId}', funding period id '{fundingPeriodId}' and version '{templateVersion}'");

            logger
            .Received(1)
            .Error(Arg.Any <Exception>(), $"Failed to fetch funding template '{blobName}' from blob storage");
        }
        public async Task GetFundingTemplate_GivenTemplateDoesExistInBlobStorageButIsEmpty_ReturnsInternalServerError()
        {
            //Arrange
            const string fundingStreamId = "PES";
            const string templateVersion = "1.2";
            const string fundingPeriodId = "AY-2020";

            string cacheKey = $"{CacheKeys.FundingTemplatePrefix}{fundingStreamId}-{fundingPeriodId}-{templateVersion}";

            string blobName = $"{fundingStreamId}/{fundingPeriodId}/{templateVersion}.json";

            string template = string.Empty;

            ICacheProvider cacheProvider = CreateCacheProvider();

            cacheProvider
            .GetAsync <string>(Arg.Is(cacheKey))
            .Returns((string)null);

            IFundingTemplateRepository fundingTemplateRepository = CreateFundingTemplateRepository();

            fundingTemplateRepository
            .TemplateVersionExists(Arg.Is(blobName))
            .Returns(true);

            fundingTemplateRepository
            .GetFundingTemplateVersion(Arg.Is(blobName))
            .Returns(template);

            ILogger logger = CreateLogger();

            FundingTemplateService fundingTemplateService = CreateFundingTemplateService(
                logger,
                cacheProvider: cacheProvider,
                fundingTemplateRepository: fundingTemplateRepository);

            //Act
            ActionResult <string> result = await fundingTemplateService.GetFundingTemplateSourceFile(fundingStreamId, fundingPeriodId, templateVersion);

            //Assert
            result
            .Result
            .Should()
            .BeAssignableTo <InternalServerErrorResult>()
            .Which
            .Value
            .Should()
            .Be($"Failed to retreive blob contents for funding stream id '{fundingStreamId}', funding period id '{fundingPeriodId}' and funding template version '{templateVersion}'");

            logger
            .Received(1)
            .Error($"Empty template returned from blob storage for blob name '{blobName}'");
        }
        private async Task <bool> CheckIfFundingTemplateVersionExists(string blobName)
        {
            try
            {
                return(await _fundingTemplateRepositoryPolicy.ExecuteAsync(() => _fundingTemplateRepository.TemplateVersionExists(blobName)));
            }
            catch (Exception ex)
            {
                _logger.Error($"Failed to check if funding template version: '{blobName}' exists");

                throw new NonRetriableException($"Failed to check if funding template version: '{blobName}' exists", ex);
            }
        }
        public async Task GetFundingTemplate_GivenFetechingBlobSucceeds_SetsCacheAndReturnsOKObjectResult()
        {
            //Arrange
            const string fundingStreamId = "PES";
            const string templateVersion = "1.2";
            const string fundingPeriodId = "AY-2020";

            string cacheKey = $"{CacheKeys.FundingTemplatePrefix}{fundingStreamId}-{fundingPeriodId}-{templateVersion}";

            string blobName = $"{fundingStreamId}/{fundingPeriodId}/{templateVersion}.json";

            string template = "a template";

            ICacheProvider cacheProvider = CreateCacheProvider();

            cacheProvider
            .GetAsync <string>(Arg.Is(cacheKey))
            .Returns((string)null);

            IFundingTemplateRepository fundingTemplateRepository = CreateFundingTemplateRepository();

            fundingTemplateRepository
            .TemplateVersionExists(Arg.Is(blobName))
            .Returns(true);

            fundingTemplateRepository
            .GetFundingTemplateVersion(Arg.Is(blobName))
            .Returns(template);

            ILogger logger = CreateLogger();

            FundingTemplateService fundingTemplateService = CreateFundingTemplateService(
                logger,
                cacheProvider: cacheProvider,
                fundingTemplateRepository: fundingTemplateRepository);

            //Act
            ActionResult <string> result = await fundingTemplateService.GetFundingTemplateSourceFile(fundingStreamId, fundingPeriodId, templateVersion);

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

            await
            cacheProvider
            .Received(1)
            .SetAsync(Arg.Is(cacheKey), Arg.Is(template));
        }
        public async Task GetDistinctFundingTemplateMetadataFundingLinesContents_GivenTemplateIsInBlob_ReturnsOkObjecResultstWithDistinctFundingLinesAndCalculations()
        {
            //Arrange
            const string fundingStreamId = "PES";
            const string fundingPeriodId = "AY-2020";
            const string templateVersion = "1.0";

            string template = CreateJsonFile("CalculateFunding.Services.Policy.Resources.LogicalModelTemplateForDistinctMetadataContents.json");

            string blobNamePrefix = $"{fundingStreamId}/{ fundingPeriodId}/{templateVersion}";

            IFundingTemplateRepository fundingTemplateRepository = CreateFundingTemplateRepository();

            fundingTemplateRepository
            .TemplateVersionExists(Arg.Is <string>(_ => _.Contains(blobNamePrefix)))
            .Returns(true);
            fundingTemplateRepository.GetFundingTemplateVersion(Arg.Is <string>(_ => _.Contains(blobNamePrefix)))
            .Returns(template);

            ILogger        logger        = CreateLogger();
            ICacheProvider cacheProvider = CreateCacheProvider();

            FundingTemplateService fundingTemplateService = CreateFundingTemplateService(
                logger,
                fundingTemplateRepository: fundingTemplateRepository,
                cacheProvider: cacheProvider);

            //Act
            ActionResult <TemplateMetadataDistinctContents> result = await fundingTemplateService.GetDistinctFundingTemplateMetadataContents(fundingStreamId, fundingPeriodId, templateVersion);

            //Assert
            TemplateMetadataDistinctContents contents = result.Value;

            contents.Should().NotBeNull();
            contents.FundingLines.Count().Should().Be(2);
            contents.Calculations.Count().Should().Be(2);
            contents.FundingStreamId.Should().Be(fundingStreamId);
            contents.FundingPeriodId.Should().Be(fundingPeriodId);
            contents.TemplateVersion.Should().Be(templateVersion);

            string cacheKey = $"{CacheKeys.FundingTemplateContentMetadataDistinct}{fundingStreamId}:{fundingPeriodId}:{templateVersion}".ToLowerInvariant();
            await cacheProvider
            .Received(1)
            .SetAsync(cacheKey,
                      Arg.Is <TemplateMetadataDistinctContents>(_ => _.FundingStreamId == fundingStreamId && _.FundingPeriodId == fundingPeriodId && _.TemplateVersion == templateVersion),
                      TimeSpan.FromDays(365),
                      true,
                      null);
        }
        public async Task TemplateExists_ChecksBlobExistsForFundingStreamIdAndVersionSupplied(bool expectedExistsFlag)
        {
            string fundingStreamId = NewRandomString();
            string templateVersion = NewRandomString();
            string fundingPeriodId = NewRandomString();

            IFundingTemplateRepository fundingTemplateRepository = Substitute.For <IFundingTemplateRepository>();
            FundingTemplateService     service = CreateFundingTemplateService(fundingTemplateRepository: fundingTemplateRepository);

            fundingTemplateRepository.TemplateVersionExists($"{fundingStreamId}/{fundingPeriodId}/{templateVersion}.json")
            .Returns(expectedExistsFlag);

            bool templateExists = await service.TemplateExists(fundingStreamId, fundingPeriodId, templateVersion);

            templateExists
            .Should()
            .Be(expectedExistsFlag);
        }
        public async Task GetFundingTemplate_GivenTemplateDoesNotExistInBlobStorage_ReturnsNotFoundResult()
        {
            //Arrange
            const string fundingStreamId = "PES";
            const string templateVersion = "1.2";
            const string fundingPeriodId = "AY-2020";

            string cacheKey = $"{CacheKeys.FundingTemplatePrefix}{fundingStreamId}-{fundingPeriodId}-{templateVersion}";

            string blobName = $"{fundingStreamId}/{fundingPeriodId}/{templateVersion}.json";

            ICacheProvider cacheProvider = CreateCacheProvider();

            cacheProvider
            .GetAsync <string>(Arg.Is(cacheKey))
            .Returns((string)null);

            IFundingTemplateRepository fundingTemplateRepository = CreateFundingTemplateRepository();

            fundingTemplateRepository
            .TemplateVersionExists(Arg.Is(blobName))
            .Returns(false);

            FundingTemplateService fundingTemplateService = CreateFundingTemplateService(
                cacheProvider: cacheProvider,
                fundingTemplateRepository: fundingTemplateRepository);

            //Act
            ActionResult <string> result = await fundingTemplateService.GetFundingTemplateSourceFile(fundingStreamId, fundingPeriodId, templateVersion);

            //Assert
            result
            .Result
            .Should()
            .BeAssignableTo <NotFoundResult>();
        }