Exemple #1
0
        public async Task GetFundingStreams_GivenNullOrEmptyFundingStreamsReturned_LogsAndReturnsOKWithEmptyList()
        {
            // Arrange
            ILogger logger = CreateLogger();

            IEnumerable <FundingStream> fundingStreams = null;

            ISpecificationsRepository specificationsRepository = CreateSpecificationsRepository();

            specificationsRepository
            .GetFundingStreams()
            .Returns(fundingStreams);

            IFundingService fundingService = CreateService(logger: logger, specificationsRepository: specificationsRepository);

            // Act
            IActionResult result = await fundingService.GetFundingStreams();

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

            OkObjectResult objectResult = result as OkObjectResult;

            IEnumerable <FundingStream> values = objectResult.Value as IEnumerable <FundingStream>;

            values
            .Should()
            .NotBeNull();

            logger
            .Received(1)
            .Error(Arg.Is("No funding streams were returned"));
        }
        private async Task <IEnumerable <FundingStream> > GetAllFundingStreams()
        {
            IEnumerable <FundingStream> allFundingStreams = await _specificationsRepository.GetFundingStreams();

            if (allFundingStreams.IsNullOrEmpty())
            {
                throw new NonRetriableException("Failed to get all funding streams");
            }

            return(allFundingStreams);
        }
        public void ValidateWithSpecificationAndFundingStreams_ValidatesAsExpected(CalculationCreateModel model,
                                                                                   Specification specification,
                                                                                   IEnumerable <FundingStream> fundingStreams,
                                                                                   bool expectedResult,
                                                                                   IEnumerable <string> expectedErrors)
        {
            //Arrange
            ISpecificationsRepository specsRepo = CreateSpecificationsRepository(false);

            specsRepo
            .GetSpecificationById(specificationId)
            .Returns(specification);

            specsRepo
            .GetFundingStreams()
            .Returns(fundingStreams);

            CalculationCreateModelValidator validator = CreateValidator(specsRepo);

            //Act
            ValidationResult result = validator.Validate(model);

            //Assert
            result
            .IsValid
            .Should()
            .Be(expectedResult);

            foreach (var error in expectedErrors)
            {
                result
                .Errors
                .Select(e => e.ErrorMessage)
                .Distinct()
                .Count(e => e == error)
                .Should()
                .Be(1, $"Expected to find error message '{error}'");
            }

            result
            .Errors
            .Count
            .Should()
            .Be(expectedErrors.Count());
        }
Exemple #4
0
        public void ValidateWithSpecificationAndFundingStream_ValidatesAsExpected(CalculationEditModel calculationEditModel,
                                                                                  Specification specification,
                                                                                  IEnumerable <FundingStream> fundingStreams,
                                                                                  bool expectedResult,
                                                                                  IEnumerable <string> expectedErrors)
        {
            //Arrange
            ISpecificationsRepository specsRepo = CreateSpecificationsRepository(false);

            specsRepo
            .GetSpecificationById(specificationId)
            .Returns(specification);

            specsRepo
            .GetFundingStreams()
            .Returns(fundingStreams);

            CalculationEditModelValidator validator = CreateValidator(specsRepo);

            // Act
            ValidationResult result = validator.Validate(calculationEditModel);

            // Assert
            result
            .IsValid
            .Should()
            .Be(expectedResult);

            result
            .Errors
            .Count
            .Should()
            .Be(expectedErrors.Count());

            foreach (string error in expectedErrors)
            {
                result
                .Errors
                .Count(e => e.ErrorMessage == error)
                .Should()
                .Be(1, $"Error message collection should have included '{error}'");
            }
        }
        public async Task <IActionResult> GetFundingStreams()
        {
            IEnumerable <FundingStream> fundingStreams = await _cacheProvider.GetAsync <FundingStream[]>(CacheKeys.AllFundingStreams);

            if (fundingStreams.IsNullOrEmpty())
            {
                fundingStreams = await _specificationsRepository.GetFundingStreams();

                if (fundingStreams.IsNullOrEmpty())
                {
                    _logger.Error("No funding streams were returned");

                    fundingStreams = new FundingStream[0];
                }

                await _cacheProvider.SetAsync <FundingStream[]>(CacheKeys.AllFundingStreams, fundingStreams.ToArray());
            }

            return(new OkObjectResult(fundingStreams));
        }
Exemple #6
0
        public async Task GetFundingStreams_GivenFundingStreamsReturned_ReturnsOKWithResults()
        {
            // Arrange
            ILogger logger = CreateLogger();

            IEnumerable <FundingStream> fundingStreams = new[]
            {
                new FundingStream(),
                new FundingStream()
            };

            ISpecificationsRepository specificationsRepository = CreateSpecificationsRepository();

            specificationsRepository
            .GetFundingStreams()
            .Returns(fundingStreams);

            IFundingService fundingService = CreateService(logger: logger, specificationsRepository: specificationsRepository);

            // Act
            IActionResult result = await fundingService.GetFundingStreams();

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

            OkObjectResult objectResult = result as OkObjectResult;

            IEnumerable <FundingStream> values = objectResult.Value as IEnumerable <FundingStream>;

            values
            .Count()
            .Should()
            .Be(2);
        }
Exemple #7
0
        public CalculationCreateModelValidator(ISpecificationsRepository specificationsRepository, ICalculationsRepository calculationsRepository)
        {
            Guard.ArgumentNotNull(specificationsRepository, nameof(specificationsRepository));
            Guard.ArgumentNotNull(calculationsRepository, nameof(calculationsRepository));

            _specificationsRepository = specificationsRepository;
            _calculationsRepository   = calculationsRepository;

            RuleFor(model => model.Description)
            .NotEmpty()
            .WithMessage("You must give a description for the calculation");

            RuleFor(model => model.SpecificationId)
            .NotEmpty()
            .WithMessage("Null or empty specification Id provided")
            .CustomAsync(async(name, context, cancellationToken) =>
            {
                CalculationCreateModel model = context.ParentContext.InstanceToValidate as CalculationCreateModel;
                if (!string.IsNullOrWhiteSpace(model.SpecificationId))
                {
                    Specification specification = await _specificationsRepository.GetSpecificationById(model.SpecificationId);
                    if (specification == null)
                    {
                        context.AddFailure("Specification not found");
                        return;
                    }
                }
            });

            RuleFor(model => model.PolicyId)
            .NotEmpty()
            .WithMessage("You must select a policy or a sub policy");

            RuleFor(model => model.CalculationType)
            .IsInEnum()
            .WithMessage("You must specify a valid calculation type");

            RuleFor(model => model.Name)
            .NotEmpty()
            .WithMessage("You must give a unique calculation name")
            .Custom((name, context) =>
            {
                CalculationCreateModel model = context.ParentContext.InstanceToValidate as CalculationCreateModel;

                if (!_calculationsRepository.IsCalculationNameValid(model.SpecificationId, model.Name).Result)
                {
                    context.AddFailure("Calculation with the same generated source code name already exists in this specification");
                }
            });

            RuleFor(model => model.AllocationLineId)
            .CustomAsync(async(name, context, cancellationToken) =>
            {
                CalculationCreateModel model        = context.ParentContext.InstanceToValidate as CalculationCreateModel;
                bool checkForDuplicateBaselineCalcs = false;
                bool requireAllocationLine          = false;

                if (model.CalculationType == CalculationType.Baseline)
                {
                    checkForDuplicateBaselineCalcs = true;
                    requireAllocationLine          = true;
                }

                if (model.CalculationType == CalculationType.Baseline || model.CalculationType == CalculationType.Number)
                {
                    if (requireAllocationLine && string.IsNullOrWhiteSpace(model.AllocationLineId))
                    {
                        context.AddFailure("Select an allocation line to create this calculation specification");
                        return;
                    }

                    if (!string.IsNullOrWhiteSpace(model.SpecificationId) && !string.IsNullOrWhiteSpace(model.AllocationLineId))
                    {
                        IEnumerable <FundingStream> fundingStreams = await _specificationsRepository.GetFundingStreams();
                        if (fundingStreams == null)
                        {
                            context.AddFailure("Unable to query funding streams, result returned null");
                            return;
                        }

                        bool foundFundingStream = false;

                        foreach (FundingStream fundingStream in fundingStreams)
                        {
                            foreach (AllocationLine allocationLine in fundingStream.AllocationLines)
                            {
                                if (allocationLine.Id == model.AllocationLineId)
                                {
                                    foundFundingStream = true;
                                    break;
                                }
                            }

                            if (foundFundingStream)
                            {
                                break;
                            }
                        }

                        if (!foundFundingStream)
                        {
                            context.AddFailure("Unable to find Allocation Line with provided ID");
                            return;
                        }

                        if (checkForDuplicateBaselineCalcs)
                        {
                            Specification specification = await _specificationsRepository.GetSpecificationById(model.SpecificationId);
                            if (specification == null)
                            {
                                context.AddFailure("Specification not found");
                                return;
                            }

                            bool existingBaselineSpecification = specification.Current.GetAllCalculations().Any(c => c.CalculationType == CalculationType.Baseline && string.Equals(c.AllocationLine?.Id, model.AllocationLineId, StringComparison.InvariantCultureIgnoreCase));
                            if (existingBaselineSpecification)
                            {
                                context.AddFailure("This specification already has an existing Baseline calculation associated with it. Please choose a different allocation line ID to create a Baseline calculation for.");
                                return;
                            }
                        }
                    }
                }
            });
        }
Exemple #8
0
        public async Task EditSpecification_GivenChangesButFundingPeriodUnchanged_EnsuresCacheCorrectlyInvalidates()
        {
            //Arrange
            SpecificationEditModel specificationEditModel = new SpecificationEditModel
            {
                FundingPeriodId  = "FP1",
                Name             = "new spec name",
                FundingStreamIds = new[] { "fs11" }
            };

            Period fundingPeriod = new Period
            {
                Id   = "FP1",
                Name = "fp 1"
            };

            IEnumerable <FundingStream> fundingStreams = new[]
            {
                new FundingStream()
            };

            string json = JsonConvert.SerializeObject(specificationEditModel);

            byte[]       byteArray = Encoding.UTF8.GetBytes(json);
            MemoryStream stream    = new MemoryStream(byteArray);

            HttpContext context = Substitute.For <HttpContext>();

            HttpRequest request = Substitute.For <HttpRequest>();

            IQueryCollection queryStringValues = new QueryCollection(new Dictionary <string, StringValues>
            {
                { "specificationId", new StringValues(SpecificationId) },
            });

            request
            .Query
            .Returns(queryStringValues);
            request
            .Body
            .Returns(stream);

            request
            .HttpContext
            .Returns(context);

            ILogger logger = CreateLogger();

            Specification specification = CreateSpecification();

            ISpecificationsRepository specificationsRepository = CreateSpecificationsRepository();

            specificationsRepository
            .GetSpecificationById(Arg.Is(SpecificationId))
            .Returns(specification);

            specificationsRepository
            .GetPeriodById(Arg.Is(fundingPeriod.Id))
            .Returns(fundingPeriod);

            specificationsRepository
            .GetFundingStreams(Arg.Any <Expression <Func <FundingStream, bool> > >())
            .Returns(fundingStreams);

            specificationsRepository
            .UpdateSpecification(Arg.Any <Specification>())
            .Returns(HttpStatusCode.OK);

            ICacheProvider cacheProvider = CreateCacheProvider();

            SpecificationVersion newSpecVersion = specification.Current.Clone() as SpecificationVersion;

            IVersionRepository <SpecificationVersion> versionRepository = CreateVersionRepository();

            versionRepository
            .CreateVersion(Arg.Any <SpecificationVersion>(), Arg.Any <SpecificationVersion>())
            .Returns(newSpecVersion);

            SpecificationsService service = CreateService(
                logs: logger, specificationsRepository: specificationsRepository, cacheProvider: cacheProvider, specificationVersionRepository: versionRepository);

            //Act
            IActionResult result = await service.EditSpecification(request);

            //Arrange
            await
            cacheProvider
            .Received(1)
            .RemoveAsync <SpecificationSummary>(Arg.Is($"{CacheKeys.SpecificationSummaryById}{specification.Id}"));

            await
            cacheProvider
            .DidNotReceive()
            .RemoveAsync <List <SpecificationSummary> >(Arg.Is($"{CacheKeys.SpecificationSummariesByFundingPeriodId}fp1"));

            await
            versionRepository
            .Received(1)
            .SaveVersion(Arg.Is(newSpecVersion));
        }
Exemple #9
0
        public async Task EditSpecification_GivenChangesAndSpecContainsPoliciesAndCalculations_UpdatesSearchAndSendsMessage()
        {
            //Arrange
            SpecificationEditModel specificationEditModel = new SpecificationEditModel
            {
                FundingPeriodId  = "fp10",
                Name             = "new spec name",
                FundingStreamIds = new[] { "fs11" }
            };

            Period fundingPeriod = new Period
            {
                Id   = "fp10",
                Name = "fp 10"
            };

            IEnumerable <FundingStream> fundingStreams = new[]
            {
                new FundingStream {
                    AllocationLines = new List <AllocationLine>
                    {
                        new AllocationLine {
                            Id = "al1", Name = "al2"
                        }
                    }
                }
            };

            string json = JsonConvert.SerializeObject(specificationEditModel);

            byte[]       byteArray = Encoding.UTF8.GetBytes(json);
            MemoryStream stream    = new MemoryStream(byteArray);

            HttpContext context = Substitute.For <HttpContext>();

            HttpRequest request = Substitute.For <HttpRequest>();

            IQueryCollection queryStringValues = new QueryCollection(new Dictionary <string, StringValues>
            {
                { "specificationId", new StringValues(SpecificationId) },
            });

            request
            .Query
            .Returns(queryStringValues);
            request
            .Body
            .Returns(stream);

            request
            .HttpContext
            .Returns(context);

            ILogger logger = CreateLogger();

            Specification specification = CreateSpecification();

            specification
            .Current
            .Policies = new[]
            {
                new Policy
                {
                    Calculations = new[]
                    {
                        new Calculation {
                            AllocationLine = new AllocationLine {
                                Id = "oldallocationlineid"
                            }
                        }
                    }
                }
            };

            ISpecificationsRepository specificationsRepository = CreateSpecificationsRepository();

            specificationsRepository
            .GetSpecificationById(Arg.Is(SpecificationId))
            .Returns(specification);

            specificationsRepository
            .GetPeriodById(Arg.Is(fundingPeriod.Id))
            .Returns(fundingPeriod);

            specificationsRepository
            .GetFundingStreams(Arg.Any <Expression <Func <FundingStream, bool> > >())
            .Returns(fundingStreams);

            specificationsRepository
            .UpdateSpecification(Arg.Any <Specification>())
            .Returns(HttpStatusCode.OK);

            ISearchRepository <SpecificationIndex> searchRepository = CreateSearchRepository();

            ICacheProvider cacheProvider = CreateCacheProvider();

            IMessengerService messengerService = CreateMessengerService();

            SpecificationVersion newSpecVersion = specification.Current.Clone() as SpecificationVersion;

            newSpecVersion.Name             = specificationEditModel.Name;
            newSpecVersion.FundingPeriod.Id = specificationEditModel.FundingPeriodId;
            newSpecVersion.FundingStreams   = new[] { new FundingStream {
                                                          Id = "fs11"
                                                      } };

            IVersionRepository <SpecificationVersion> versionRepository = CreateVersionRepository();

            versionRepository
            .CreateVersion(Arg.Any <SpecificationVersion>(), Arg.Any <SpecificationVersion>())
            .Returns(newSpecVersion);

            SpecificationsService service = CreateService(
                logs: logger, specificationsRepository: specificationsRepository, searchRepository: searchRepository,
                cacheProvider: cacheProvider, messengerService: messengerService, specificationVersionRepository: versionRepository);

            //Act
            IActionResult result = await service.EditSpecification(request);

            //Arrange
            await
            searchRepository
            .Received(1)
            .Index(Arg.Is <IEnumerable <SpecificationIndex> >(
                       m => m.First().Id == SpecificationId &&
                       m.First().Name == "new spec name" &&
                       m.First().FundingPeriodId == "fp10" &&
                       m.First().FundingStreamIds.Count() == 1
                       ));

            await
            cacheProvider
            .Received(1)
            .RemoveAsync <SpecificationSummary>(Arg.Is($"{CacheKeys.SpecificationSummaryById}{specification.Id}"));

            await
            messengerService
            .Received(1)
            .SendToTopic(Arg.Is(ServiceBusConstants.TopicNames.EditSpecification),
                         Arg.Is <SpecificationVersionComparisonModel>(
                             m => m.Id == SpecificationId &&
                             m.Current.Name == "new spec name" &&
                             m.Previous.Name == "Spec name"
                             ), Arg.Any <IDictionary <string, string> >(), Arg.Is(true));

            await
            versionRepository
            .Received(1)
            .SaveVersion(Arg.Is(newSpecVersion));
        }
Exemple #10
0
        public async Task EditSpecification_GivenFailsToUpdateCosomosWithBadRequest_ReturnsBadRequest()
        {
            //Arrange
            SpecificationEditModel specificationEditModel = new SpecificationEditModel
            {
                FundingPeriodId = "fp10"
            };

            Period fundingPeriod = new Period
            {
                Id   = "fp10",
                Name = "fp 10"
            };

            IEnumerable <FundingStream> fundingStreams = new[]
            {
                new FundingStream()
            };

            string json = JsonConvert.SerializeObject(specificationEditModel);

            byte[]       byteArray = Encoding.UTF8.GetBytes(json);
            MemoryStream stream    = new MemoryStream(byteArray);

            HttpContext context = Substitute.For <HttpContext>();

            HttpRequest request = Substitute.For <HttpRequest>();

            IQueryCollection queryStringValues = new QueryCollection(new Dictionary <string, StringValues>
            {
                { "specificationId", new StringValues(SpecificationId) },
            });

            request
            .Query
            .Returns(queryStringValues);
            request
            .Body
            .Returns(stream);

            request
            .HttpContext
            .Returns(context);

            ILogger logger = CreateLogger();

            Specification specification = CreateSpecification();

            ISpecificationsRepository specificationsRepository = CreateSpecificationsRepository();

            specificationsRepository
            .GetSpecificationById(Arg.Is(SpecificationId))
            .Returns(specification);

            specificationsRepository
            .GetPeriodById(Arg.Is(fundingPeriod.Id))
            .Returns(fundingPeriod);

            specificationsRepository
            .GetFundingStreams(Arg.Any <Expression <Func <FundingStream, bool> > >())
            .Returns(fundingStreams);

            specificationsRepository
            .UpdateSpecification(Arg.Any <Specification>())
            .Returns(HttpStatusCode.BadRequest);

            SpecificationsService service = CreateService(logs: logger, specificationsRepository: specificationsRepository);

            //Act
            IActionResult result = await service.EditSpecification(request);

            //Arrange
            result
            .Should()
            .BeOfType <StatusCodeResult>()
            .Which
            .StatusCode
            .Should()
            .Be(400);
        }
Exemple #11
0
        public async Task EditSpecification_WhenIndexingReturnsErrors_ShouldThrowException()
        {
            //Arrange
            const string errorMessage = "Encountered error 802 code";

            SpecificationEditModel specificationEditModel = new SpecificationEditModel
            {
                FundingPeriodId  = "fp10",
                Name             = "new spec name",
                FundingStreamIds = new[] { "fs11" }
            };

            Period fundingPeriod = new Period
            {
                Id   = "fp10",
                Name = "fp 10"
            };

            IEnumerable <FundingStream> fundingStreams = new[]
            {
                new FundingStream {
                    AllocationLines = new List <AllocationLine>
                    {
                        new AllocationLine {
                            Id = "al1", Name = "al2"
                        }
                    }
                }
            };

            string json = JsonConvert.SerializeObject(specificationEditModel);

            byte[]       byteArray = Encoding.UTF8.GetBytes(json);
            MemoryStream stream    = new MemoryStream(byteArray);

            HttpContext context = Substitute.For <HttpContext>();

            HttpRequest request = Substitute.For <HttpRequest>();

            IQueryCollection queryStringValues = new QueryCollection(new Dictionary <string, StringValues>
            {
                { "specificationId", new StringValues(SpecificationId) },
            });

            request
            .Query
            .Returns(queryStringValues);
            request
            .Body
            .Returns(stream);

            request
            .HttpContext
            .Returns(context);

            ILogger logger = CreateLogger();

            Specification specification = CreateSpecification();

            ISpecificationsRepository specificationsRepository = CreateSpecificationsRepository();

            specificationsRepository
            .GetSpecificationById(Arg.Is(SpecificationId))
            .Returns(specification);

            specificationsRepository
            .GetPeriodById(Arg.Is(fundingPeriod.Id))
            .Returns(fundingPeriod);

            specificationsRepository
            .GetFundingStreams(Arg.Any <Expression <Func <FundingStream, bool> > >())
            .Returns(fundingStreams);

            specificationsRepository
            .UpdateSpecification(Arg.Any <Specification>())
            .Returns(HttpStatusCode.OK);

            ISearchRepository <SpecificationIndex> searchRepository = CreateSearchRepository();

            searchRepository
            .Index(Arg.Any <IEnumerable <SpecificationIndex> >())
            .Returns(new[] { new IndexError()
                             {
                                 ErrorMessage = errorMessage
                             } });

            ICacheProvider cacheProvider = CreateCacheProvider();

            IMessengerService messengerService = CreateMessengerService();

            SpecificationVersion newSpecVersion = specification.Current.Clone() as SpecificationVersion;

            newSpecVersion.Name             = specificationEditModel.Name;
            newSpecVersion.FundingPeriod.Id = specificationEditModel.FundingPeriodId;
            newSpecVersion.FundingStreams   = new[] { new FundingStream {
                                                          Id = "fs11"
                                                      } };

            IVersionRepository <SpecificationVersion> versionRepository = CreateVersionRepository();

            versionRepository
            .CreateVersion(Arg.Any <SpecificationVersion>(), Arg.Any <SpecificationVersion>())
            .Returns(newSpecVersion);

            SpecificationsService service = CreateService(
                logs: logger, specificationsRepository: specificationsRepository, searchRepository: searchRepository,
                cacheProvider: cacheProvider, messengerService: messengerService, specificationVersionRepository: versionRepository);

            //Act
            Func <Task <IActionResult> > editSpecification = async() => await service.EditSpecification(request);

            //Assert
            editSpecification
            .Should()
            .Throw <ApplicationException>()
            .Which
            .Message
            .Should()
            .Be($"Could not index specification {specification.Current.Id} because: {errorMessage}");
        }
Exemple #12
0
        public async Task SpecificationsService_GetFundingStreamsForSpecificationById_WhenSpecificationContainsNoFundingStreams_ThenErrorReturned()
        {
            // Arrange
            const string specificationId = "spec1";

            ISpecificationsRepository specificationsRepository = CreateSpecificationsRepository();
            SpecificationsService     specificationsService    = CreateService(specificationsRepository: specificationsRepository);

            IQueryCollection queryStringValues = new QueryCollection(new Dictionary <string, StringValues>
            {
                { "specificationId", new StringValues(specificationId) }
            });

            HttpRequest request = Substitute.For <HttpRequest>();

            request
            .Query
            .Returns(queryStringValues);

            Specification specification = new Specification()
            {
                Id      = specificationId,
                Name    = "Test Specification",
                Current = new SpecificationVersion()
                {
                    FundingStreams = new List <Reference>()
                    {
                    },
                },
            };

            specificationsRepository
            .GetSpecificationById(Arg.Is(specificationId))
            .Returns(specification);

            List <FundingStream> fundingStreams = new List <FundingStream>();

            specificationsRepository
            .GetFundingStreams(Arg.Any <Expression <Func <FundingStream, bool> > >())
            .Returns(fundingStreams);

            // Act
            IActionResult actionResult = await specificationsService.GetFundingStreamsForSpecificationById(request);

            // Assert
            actionResult
            .Should()
            .BeOfType <InternalServerErrorResult>()
            .Which
            .Value
            .Should()
            .Be("Specification contains no funding streams");

            await specificationsRepository
            .Received(1)
            .GetSpecificationById(Arg.Is(specificationId));

            await specificationsRepository
            .Received(0)
            .GetFundingStreams(Arg.Any <Expression <Func <FundingStream, bool> > >());
        }
Exemple #13
0
        public async Task SpecificationsService_GetFundingStreamsForSpecificationById_WhenRequestingASpecificationWhenExists_ThenFundingStreamsReturned()
        {
            // Arrange
            const string specificationId = "spec1";

            ISpecificationsRepository specificationsRepository = CreateSpecificationsRepository();
            SpecificationsService     specificationsService    = CreateService(specificationsRepository: specificationsRepository);

            IQueryCollection queryStringValues = new QueryCollection(new Dictionary <string, StringValues>
            {
                { "specificationId", new StringValues(specificationId) }
            });

            HttpRequest request = Substitute.For <HttpRequest>();

            request
            .Query
            .Returns(queryStringValues);

            Specification specification = new Specification()
            {
                Id      = specificationId,
                Name    = "Test Specification",
                Current = new SpecificationVersion()
                {
                    FundingStreams = new List <Reference>()
                    {
                        new Reference("fs1", "Funding Stream 1"),
                        new Reference("fs2", "Funding Stream Two"),
                    },
                },
            };

            specificationsRepository
            .GetSpecificationById(Arg.Is(specificationId))
            .Returns(specification);

            List <FundingStream> fundingStreams = new List <FundingStream>()
            {
                new FundingStream()
                {
                    Id              = "fs1",
                    Name            = "Funding Stream 1",
                    AllocationLines = new List <AllocationLine>(),
                },
                new FundingStream()
                {
                    Id              = "fs2",
                    Name            = "Funding Stream Two",
                    AllocationLines = new List <AllocationLine>(),
                }
            };

            specificationsRepository
            .GetFundingStreams(Arg.Any <Expression <Func <FundingStream, bool> > >())
            .Returns(fundingStreams);

            // Act
            IActionResult actionResult = await specificationsService.GetFundingStreamsForSpecificationById(request);

            // Assert

            List <FundingStream> expectedFundingStreams = new List <FundingStream>()
            {
                new FundingStream()
                {
                    Id              = "fs1",
                    Name            = "Funding Stream 1",
                    AllocationLines = new List <AllocationLine>(),
                },
                new FundingStream()
                {
                    Id              = "fs2",
                    Name            = "Funding Stream Two",
                    AllocationLines = new List <AllocationLine>(),
                }
            };

            actionResult
            .Should()
            .BeOfType <OkObjectResult>()
            .Which
            .Value
            .Should().BeEquivalentTo(expectedFundingStreams.AsEnumerable());

            await specificationsRepository
            .Received(1)
            .GetSpecificationById(Arg.Is(specificationId));

            await specificationsRepository
            .Received(1)
            .GetFundingStreams(Arg.Any <Expression <Func <FundingStream, bool> > >());
        }
        public void CreateCalculation_WhenSomethingGoesWrongDuringIndexing_ShouldThrowException()
        {
            //Arrange
            const string errorMessage = "Encountered 802 error code";

            AllocationLine allocationLine = new AllocationLine
            {
                Id   = "02a6eeaf-e1a0-476e-9cf9-8aa5d9129345",
                Name = "test alloctaion"
            };

            List <FundingStream> fundingStreams = new List <FundingStream>();

            FundingStream fundingStream = new FundingStream
            {
                AllocationLines = new List <AllocationLine>
                {
                    allocationLine
                },
                Id = FundingStreamId
            };

            fundingStreams.Add(fundingStream);

            Policy policy = new Policy
            {
                Id   = PolicyId,
                Name = PolicyName,
            };

            Specification specification = CreateSpecification();

            specification.Current.Policies       = new[] { policy };
            specification.Current.FundingStreams = new List <Reference>()
            {
                new Reference {
                    Id = FundingStreamId
                }
            };

            CalculationCreateModel model = new CalculationCreateModel
            {
                SpecificationId  = SpecificationId,
                PolicyId         = PolicyId,
                AllocationLineId = AllocationLineId
            };

            string json = JsonConvert.SerializeObject(model);

            byte[]       byteArray = Encoding.UTF8.GetBytes(json);
            MemoryStream stream    = new MemoryStream(byteArray);

            ClaimsPrincipal principle = new ClaimsPrincipal(new[]
            {
                new ClaimsIdentity(new [] { new Claim(ClaimTypes.Sid, UserId), new Claim(ClaimTypes.Name, Username) })
            });

            HttpContext context = Substitute.For <HttpContext>();

            context
            .User
            .Returns(principle);

            HttpRequest request = Substitute.For <HttpRequest>();

            request
            .Body
            .Returns(stream);

            request
            .HttpContext
            .Returns(context);

            IHeaderDictionary headerDictionary = new HeaderDictionary();

            headerDictionary
            .Add("sfa-correlationId", new StringValues(SfaCorrelationId));

            request
            .Headers
            .Returns(headerDictionary);

            ILogger logger = CreateLogger();

            ISpecificationsRepository specificationsRepository = CreateSpecificationsRepository();

            specificationsRepository
            .GetSpecificationById(Arg.Is(SpecificationId))
            .Returns(specification);

            specificationsRepository
            .GetFundingStreams(Arg.Any <Expression <Func <FundingStream, bool> > >())
            .Returns(fundingStreams);

            specificationsRepository
            .UpdateSpecification(Arg.Is(specification))
            .Returns(HttpStatusCode.OK);

            Calculation calculation = new Calculation
            {
                AllocationLine = new Reference()
            };

            IMapper mapper = CreateMapper();

            mapper
            .Map <Calculation>(Arg.Any <CalculationCreateModel>())
            .Returns(calculation);

            IMessengerService messengerService = CreateMessengerService();

            ISearchRepository <SpecificationIndex> mockSearchRepository = CreateSearchRepository();

            mockSearchRepository
            .Index(Arg.Any <IEnumerable <SpecificationIndex> >())
            .Returns(new List <IndexError>()
            {
                new IndexError()
                {
                    ErrorMessage = errorMessage
                }
            });

            SpecificationVersion newSpecVersion = specification.Current.Clone() as SpecificationVersion;

            newSpecVersion.PublishStatus = PublishStatus.Updated;
            newSpecVersion.Version       = 2;
            IVersionRepository <SpecificationVersion> mockVersionRepository = CreateVersionRepository();

            mockVersionRepository
            .CreateVersion(Arg.Any <SpecificationVersion>(), Arg.Any <SpecificationVersion>())
            .Returns(newSpecVersion);

            SpecificationsService service = CreateService(logs: logger, specificationsRepository: specificationsRepository,
                                                          mapper: mapper, messengerService: messengerService, specificationVersionRepository: mockVersionRepository, searchRepository: mockSearchRepository);


            //Act
            Func <Task <IActionResult> > createCalculation = async() => await service.CreateCalculation(request);

            //Assert
            createCalculation
            .Should()
            .Throw <ApplicationException>()
            .Which
            .Message
            .Should()
            .Be($"Could not index specification {specification.Current.Id} because: {errorMessage}");
        }
        public async Task CreateCalculation_GivenValidModelForSubPolicyAndSubPolicyFoundAndUpdated_ReturnsOK()
        {
            //Arrange
            AllocationLine allocationLine = new AllocationLine
            {
                Id   = "02a6eeaf-e1a0-476e-9cf9-8aa5d9129345",
                Name = "test alloctaion"
            };

            List <FundingStream> fundingStreams = new List <FundingStream>();

            FundingStream fundingStream = new FundingStream
            {
                AllocationLines = new List <AllocationLine>
                {
                    allocationLine
                },
                Id = FundingStreamId
            };

            fundingStreams.Add(fundingStream);

            Policy policy = new Policy
            {
                Id   = PolicyId,
                Name = PolicyName,
            };

            Specification specification = CreateSpecification();

            specification.Current.Policies       = new[] { policy };
            specification.Current.FundingStreams = new List <Reference>()
            {
                new Reference {
                    Id = FundingStreamId
                }
            };

            CalculationCreateModel model = new CalculationCreateModel
            {
                SpecificationId  = SpecificationId,
                PolicyId         = PolicyId,
                AllocationLineId = AllocationLineId
            };

            string json = JsonConvert.SerializeObject(model);

            byte[]       byteArray = Encoding.UTF8.GetBytes(json);
            MemoryStream stream    = new MemoryStream(byteArray);

            ClaimsPrincipal principle = new ClaimsPrincipal(new[]
            {
                new ClaimsIdentity(new [] { new Claim(ClaimTypes.Sid, UserId), new Claim(ClaimTypes.Name, Username) })
            });

            HttpContext context = Substitute.For <HttpContext>();

            context
            .User
            .Returns(principle);

            HttpRequest request = Substitute.For <HttpRequest>();

            request
            .Body
            .Returns(stream);

            request
            .HttpContext
            .Returns(context);

            IHeaderDictionary headerDictionary = new HeaderDictionary();

            headerDictionary
            .Add("sfa-correlationId", new StringValues(SfaCorrelationId));

            request
            .Headers
            .Returns(headerDictionary);

            ILogger logger = CreateLogger();

            ISpecificationsRepository specificationsRepository = CreateSpecificationsRepository();

            specificationsRepository
            .GetSpecificationById(Arg.Is(SpecificationId))
            .Returns(specification);

            specificationsRepository
            .GetFundingStreams(Arg.Any <Expression <Func <FundingStream, bool> > >())
            .Returns(fundingStreams);

            specificationsRepository
            .UpdateSpecification(Arg.Is(specification))
            .Returns(HttpStatusCode.OK);

            Calculation calculation = new Calculation
            {
                AllocationLine = new Reference()
            };

            IMapper mapper = CreateMapper();

            mapper
            .Map <Calculation>(Arg.Any <CalculationCreateModel>())
            .Returns(calculation);

            IMessengerService messengerService = CreateMessengerService();

            SpecificationVersion newSpecVersion = specification.Current.Clone() as SpecificationVersion;

            newSpecVersion.PublishStatus = PublishStatus.Updated;
            newSpecVersion.Version       = 2;

            IVersionRepository <SpecificationVersion> mockVersionRepository = CreateVersionRepository();

            mockVersionRepository
            .CreateVersion(Arg.Any <SpecificationVersion>(), Arg.Any <SpecificationVersion>())
            .Returns(newSpecVersion);

            SpecificationsService service = CreateService(logs: logger, specificationsRepository: specificationsRepository,
                                                          mapper: mapper, messengerService: messengerService, specificationVersionRepository: mockVersionRepository);

            //Act
            IActionResult result = await service.CreateCalculation(request);

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

            await
            messengerService
            .Received(1)
            .SendToQueue(Arg.Is("calc-events-create-draft"),
                         Arg.Is <Models.Calcs.Calculation>(m =>
                                                           m.CalculationSpecification.Id == calculation.Id &&
                                                           m.CalculationSpecification.Name == calculation.Name &&
                                                           m.Name == calculation.Name &&
                                                           !string.IsNullOrEmpty(m.Id) &&
                                                           m.AllocationLine.Id == allocationLine.Id &&
                                                           m.AllocationLine.Name == allocationLine.Name),
                         Arg.Is <IDictionary <string, string> >(m =>
                                                                m["user-id"] == UserId &&
                                                                m["user-name"] == Username &&
                                                                m["sfa-correlationId"] == SfaCorrelationId));
        }
        public async Task CreateCalculation_GivenValidModelAndPolicyFoundButAddingCalcCausesBadRequest_ReturnsBadRequest()
        {
            //Arrange
            AllocationLine allocationLine = new AllocationLine
            {
                Id   = "02a6eeaf-e1a0-476e-9cf9-8aa5d9129345",
                Name = "test alloctaion"
            };

            List <FundingStream> fundingStreams = new List <FundingStream>();

            FundingStream fundingStream = new FundingStream
            {
                AllocationLines = new List <AllocationLine>
                {
                    allocationLine
                },
                Id = FundingStreamId
            };

            fundingStreams.Add(fundingStream);

            Policy policy = new Policy
            {
                Id   = PolicyId,
                Name = PolicyName,
            };

            Specification specification = new Specification
            {
                Current = new SpecificationVersion()
                {
                    Policies = new[]
                    {
                        policy,
                    },
                    FundingStreams = new List <Reference>()
                    {
                        new Reference {
                            Id = FundingStreamId
                        }
                    },
                },
            };

            CalculationCreateModel model = new CalculationCreateModel
            {
                SpecificationId  = SpecificationId,
                PolicyId         = PolicyId,
                AllocationLineId = AllocationLineId
            };

            string json = JsonConvert.SerializeObject(model);

            byte[]       byteArray = Encoding.UTF8.GetBytes(json);
            MemoryStream stream    = new MemoryStream(byteArray);

            HttpRequest request = Substitute.For <HttpRequest>();

            request
            .Body
            .Returns(stream);

            ILogger logger = CreateLogger();

            ISpecificationsRepository specificationsRepository = CreateSpecificationsRepository();

            specificationsRepository
            .GetSpecificationById(Arg.Is(SpecificationId))
            .Returns(specification);

            specificationsRepository
            .GetFundingStreams(Arg.Any <Expression <Func <FundingStream, bool> > >())
            .Returns(fundingStreams);

            specificationsRepository
            .UpdateSpecification(Arg.Is(specification))
            .Returns(HttpStatusCode.BadRequest);

            Calculation calculation = new Calculation
            {
                AllocationLine = new Reference()
            };

            IMapper mapper = CreateMapper();

            mapper
            .Map <Calculation>(Arg.Any <CalculationCreateModel>())
            .Returns(calculation);

            SpecificationsService service = CreateService(logs: logger, specificationsRepository: specificationsRepository, mapper: mapper);

            //Act
            IActionResult result = await service.CreateCalculation(request);

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

            StatusCodeResult statusCodeResult = (StatusCodeResult)result;

            statusCodeResult
            .StatusCode
            .Should()
            .Be(400);

            logger
            .Received(1)
            .Error($"Failed to update specification when creating a calc with status BadRequest");
        }