public void CreateCalculation_CreatingCalculationButAssociatedCalculationSpecificationNotFound_ThrowsException()
        {
            //Arrange
            Calculation calculation = CreateCalculation();

            IEnumerable <Calculation> calculations = new[]
            {
                calculation
            };
            string json = JsonConvert.SerializeObject(calculation);

            IEnumerable <Models.Specs.Calculation> calculationSpecifications = new[]
            {
                new Models.Specs.Calculation
                {
                    Id = "any-id"
                }
            };

            Message message = new Message(Encoding.UTF8.GetBytes(json));

            message.UserProperties.Add("user-id", UserId);
            message.UserProperties.Add("user-name", Username);

            ILogger logger = CreateLogger();

            ISearchRepository <CalculationIndex> searchRepository = CreateSearchRepository();

            Models.Specs.SpecificationSummary specificationSummary = new Models.Specs.SpecificationSummary()
            {
                Id   = calculation.SpecificationId,
                Name = "Test Spec Name",
            };

            ISpecificationRepository specificationRepository = CreateSpecificationRepository();

            specificationRepository
            .GetSpecificationSummaryById(Arg.Is(calculation.SpecificationId))
            .Returns(specificationSummary);

            specificationRepository
            .GetCalculationSpecificationsForSpecification(Arg.Is(calculation.SpecificationId))
            .Returns(calculationSpecifications);

            CalculationService service = CreateCalculationService(logger: logger, searchRepository: searchRepository, specificationRepository: specificationRepository);

            //Act
            Func <Task> test = async() => await service.CreateCalculation(message);

            //Assert
            test
            .Should().ThrowExactly <RetriableException>()
            .WithMessage($"A calculation specification was not found for calculation specification id '{calculation.CalculationSpecification.Id}'");
        }
        public async Task ResetCalculationForFieldDefinitionChanges_GivenCalculationRequiresReset_UpdatesCalculationsAndDeletesAssembly()
        {
            //Arrange
            const string specificationId = "spec-id";

            IEnumerable <DatasetSpecificationRelationshipViewModel> relationships = new[]
            {
                new DatasetSpecificationRelationshipViewModel
                {
                    Name = "Test Name"
                }
            };

            IEnumerable <string> currentFieldDefinitionNames = new[]
            {
                "Test Field"
            };

            ILogger logger = CreateLogger();

            CalculationVersion calculationVersion = new CalculationVersion
            {
                SourceCode = "return Datasets.TestName.TestField",
                Date       = DateTimeOffset.Now
            };

            IEnumerable <Calculation> calculations = new[]
            {
                new Calculation
                {
                    Current                  = calculationVersion,
                    SpecificationId          = specificationId,
                    CalculationSpecification = new Reference("calc-spac-id", "calc spec name"),
                    FundingPeriod            = new Reference("fp1", "fp 1"),
                    FundingStream            = new Reference("fs1", "fs 1"),
                    Policies                 = new List <Reference> {
                        new Reference {
                            Id = "policy-1", Name = "policy 1"
                        }
                    }
                }
            };

            IEnumerable <Models.Specs.Calculation> calculationSpecifications = new[]
            {
                new Models.Specs.Calculation
                {
                    Id = "calc-spec-id"
                }
            };

            BuildProject buildProject = new BuildProject();

            Build build = new Build
            {
                SourceFiles = new List <SourceFile>()
            };

            Models.Specs.SpecificationSummary specificationSummary = new Models.Specs.SpecificationSummary();

            ICalculationsRepository calculationsRepository = CreateCalculationsRepository();

            calculationsRepository
            .GetCalculationsBySpecificationId(Arg.Is(specificationId))
            .Returns(calculations);
            calculationsRepository
            .UpdateCalculation(Arg.Any <Calculation>())
            .Returns(HttpStatusCode.OK);

            ISpecificationRepository specificationRepository = CreateSpecificationRepository();

            specificationRepository
            .GetCalculationSpecificationsForSpecification(Arg.Is(specificationId))
            .Returns(calculationSpecifications);

            specificationRepository
            .GetSpecificationSummaryById(Arg.Is(specificationId))
            .Returns(specificationSummary);

            IBuildProjectsService buildProjectsService = CreateBuildProjectsService();

            buildProjectsService
            .GetBuildProjectForSpecificationId(Arg.Is(specificationId))
            .Returns(buildProject);

            ISourceCodeService sourceCodeService = CreateSourceCodeService();

            sourceCodeService
            .Compile(Arg.Is(buildProject), Arg.Any <IEnumerable <Calculation> >(), Arg.Any <CompilerOptions>())
            .Returns(build);

            IVersionRepository <CalculationVersion> calculationVersionRepository = CreateCalculationVersionRepository();

            calculationVersionRepository
            .CreateVersion(Arg.Any <CalculationVersion>(), Arg.Any <CalculationVersion>())
            .Returns(calculationVersion);

            ICacheProvider cacheProvider = CreateCacheProvider();

            CalculationService calculationService = CreateCalculationService(
                logger: logger,
                calculationsRepository: calculationsRepository,
                specificationRepository: specificationRepository,
                buildProjectsService: buildProjectsService,
                sourceCodeService: sourceCodeService,
                calculationVersionRepository: calculationVersionRepository,
                cacheProvider: cacheProvider);

            //Act
            await calculationService.ResetCalculationForFieldDefinitionChanges(relationships, specificationId, currentFieldDefinitionNames);

            //Assert
            await
            sourceCodeService
            .Received(1)
            .DeleteAssembly(Arg.Is(specificationId));

            await
            cacheProvider
            .Received(1)
            .RemoveAsync <List <DatasetSchemaRelationshipModel> >(Arg.Is($"{CacheKeys.DatasetRelationshipFieldsForSpecification}{specificationId}"));
        }
        public async Task CreateCalculation_GivenValidCalculation_ButFailedToSave_DoesNotUpdateSearch()
        {
            //Arrange
            Calculation calculation = CreateCalculation();

            IEnumerable <Calculation> calculations = new[]
            {
                calculation
            };

            IEnumerable <Models.Specs.Calculation> calculationSpecifications = new[]
            {
                new Models.Specs.Calculation
                {
                    Id = calculation.CalculationSpecification.Id
                }
            };

            string json = JsonConvert.SerializeObject(calculation);

            Message message = new Message(Encoding.UTF8.GetBytes(json));

            message.UserProperties.Add("user-id", UserId);
            message.UserProperties.Add("user-name", Username);

            ICalculationsRepository repository = CreateCalculationsRepository();

            repository
            .CreateDraftCalculation(Arg.Any <Calculation>())
            .Returns(HttpStatusCode.BadRequest);

            repository
            .GetCalculationsBySpecificationId(Arg.Is("any-spec-id"))
            .Returns(calculations);

            ILogger logger = CreateLogger();

            ISearchRepository <CalculationIndex> searchRepository = CreateSearchRepository();

            Models.Specs.SpecificationSummary specificationSummary = new Models.Specs.SpecificationSummary()
            {
                Id   = calculation.SpecificationId,
                Name = "Test Spec Name",
            };

            ISpecificationRepository specificationRepository = CreateSpecificationRepository();

            specificationRepository
            .GetSpecificationSummaryById(Arg.Is(calculation.SpecificationId))
            .Returns(specificationSummary);

            specificationRepository
            .GetCalculationSpecificationsForSpecification(Arg.Is(calculation.SpecificationId))
            .Returns(calculationSpecifications);

            CalculationService service = CreateCalculationService(calculationsRepository: repository, logger: logger, searchRepository: searchRepository, specificationRepository: specificationRepository);

            //Act
            await service.CreateCalculation(message);

            //Assert
            logger
            .Received(1)
            .Error($"There was problem creating a new calculation with id {calculation.Id} in Cosmos Db with status code 400");

            await
            repository
            .Received(1)
            .CreateDraftCalculation(Arg.Is <Calculation>(m =>
                                                         m.Id == CalculationId &&
                                                         m.Current.PublishStatus == PublishStatus.Draft &&
                                                         m.Current.Author.Id == UserId &&
                                                         m.Current.Author.Name == Username &&
                                                         m.Current.Date.Date == DateTimeOffset.Now.Date &&
                                                         m.Current.Version == 1 &&
                                                         m.Current.DecimalPlaces == 6
                                                         ));

            await
            searchRepository
            .DidNotReceive()
            .Index(Arg.Any <List <CalculationIndex> >());
        }
        public async Task CreateCalculation_GivenValidCalculationWithNullFundingStream_AndSavesLogs()
        {
            //Arrange
            Calculation calculation = CreateCalculation();

            calculation.FundingStream = null;

            IEnumerable <Calculation> calculations = new[]
            {
                calculation
            };

            IEnumerable <Models.Specs.Calculation> calculationSpecifications = new[]
            {
                new Models.Specs.Calculation
                {
                    Id = calculation.CalculationSpecification.Id
                }
            };

            string json = JsonConvert.SerializeObject(calculation);

            Message message = new Message(Encoding.UTF8.GetBytes(json));

            message.UserProperties.Add("user-id", UserId);
            message.UserProperties.Add("user-name", Username);

            ICalculationsRepository repository = CreateCalculationsRepository();

            repository
            .CreateDraftCalculation(Arg.Any <Calculation>())
            .Returns(HttpStatusCode.Created);

            repository
            .GetCalculationsBySpecificationId(Arg.Is("any-spec-id"))
            .Returns(calculations);

            Models.Specs.SpecificationSummary specificationSummary = new Models.Specs.SpecificationSummary()
            {
                Id   = calculation.SpecificationId,
                Name = "Test Spec Name",
            };

            ISpecificationRepository specificationRepository = CreateSpecificationRepository();

            specificationRepository
            .GetSpecificationSummaryById(Arg.Is(calculation.SpecificationId))
            .Returns(specificationSummary);

            specificationRepository
            .GetCalculationSpecificationsForSpecification(Arg.Is(calculation.SpecificationId))
            .Returns(calculationSpecifications);

            ILogger logger = CreateLogger();

            ISearchRepository <CalculationIndex> searchRepository = CreateSearchRepository();

            Build build = new Build
            {
                SourceFiles = new List <SourceFile> {
                    new SourceFile()
                }
            };

            ISourceCodeService sourceCodeService = CreateSourceCodeService();

            sourceCodeService
            .Compile(Arg.Any <BuildProject>(), Arg.Any <IEnumerable <Models.Calcs.Calculation> >(), Arg.Any <CompilerOptions>())
            .Returns(build);

            CalculationService service = CreateCalculationService(
                calculationsRepository: repository,
                logger: logger, searchRepository:
                searchRepository,
                specificationRepository: specificationRepository,
                sourceCodeService: sourceCodeService);

            //Act
            await service.CreateCalculation(message);

            //Assert
            logger
            .Received(1)
            .Information($"Calculation with id: {calculation.Id} was successfully saved to Cosmos Db");

            await
            repository
            .Received(1)
            .CreateDraftCalculation(Arg.Is <Calculation>(m =>
                                                         m.Id == CalculationId &&
                                                         m.Current.PublishStatus == PublishStatus.Draft &&
                                                         m.Current.Author.Id == UserId &&
                                                         m.Current.Author.Name == Username &&
                                                         m.Current.Date.Date == DateTimeOffset.Now.Date &&
                                                         m.Current.Version == 1 &&
                                                         m.Current.DecimalPlaces == 6
                                                         ));

            await
            searchRepository
            .Received(1)
            .Index(Arg.Is <List <CalculationIndex> >(
                       m => m.First().Id == CalculationId &&
                       m.First().Name == "Test Calc Name" &&
                       m.First().CalculationSpecificationId == "any-calc-id" &&
                       m.First().CalculationSpecificationName == "Test Calc Name" &&
                       m.First().SpecificationId == "any-spec-id" &&
                       m.First().SpecificationName == "Test Spec Name" &&
                       m.First().FundingPeriodId == "18/19" &&
                       m.First().FundingPeriodName == "2018/2019" &&
                       m.First().FundingStreamId == string.Empty &&
                       m.First().FundingStreamName == "No funding stream set" &&
                       m.First().AllocationLineId == "test-alloc-id" &&
                       m.First().AllocationLineName == "test-alloc-name" &&
                       m.First().PolicySpecificationIds.First() == "policy-id" &&
                       m.First().PolicySpecificationNames.First() == "policy-name"
                       ));
        }