private IEnumerable <StatementSyntax> CreateNamespaceFunctionPointers(IEnumerable <Calculation> calculations) { foreach (Calculation calculation in calculations) { StringBuilder sourceCode = new StringBuilder(); CalculationVersion currentCalculationVersion = calculation.Current; if (string.IsNullOrWhiteSpace(currentCalculationVersion.SourceCodeName)) { throw new InvalidOperationException($"Calculation source code name is not populated for calc {calculation.Id}"); } // Add attributes to describe calculation and calculation specification sourceCode.AppendLine($"<Calculation(Id := \"{calculation.Id}\", Name := \"{calculation.Name}\", CalculationDataType := \"{calculation.Current.DataType}\")>"); // Add attribute for calculation description if (currentCalculationVersion.Description.IsNotNullOrWhitespace()) { sourceCode.AppendLine($"<Description(Description := \"{currentCalculationVersion.Description?.Replace("\"", "\"\"")}\")>"); } sourceCode.AppendLine($"Public {currentCalculationVersion.SourceCodeName} As Func(Of {GetDataType(calculation.Current.DataType, calculation.Name)}) = Nothing"); sourceCode.AppendLine(); yield return(ParseSourceCodeToStatementSyntax(sourceCode)); } }
public void CalculationVersionCalculationViewModel_MapsAsExpected(CalculationVersion source, CalculationViewModel destination) { // Arrange var config = new MapperConfiguration(c => c.AddProfile <FrontEndMappingProfile>()); IMapper mapper = new Mapper(config); //Act var result = mapper.Map(source, destination); //Assert result?.Description .Should().Be(destination?.Description); if (result?.LastModified != null) { result.LastModified .Should().Be(destination.LastModified); } result?.LastModifiedByName .Should().Be(destination?.LastModifiedByName); result?.SourceCode .Should().Be(destination?.SourceCode); result?.CalculationType .Should().Be(destination?.CalculationType); result?.PublishStatus .Should().Be(destination?.PublishStatus); //Final deep check - do this last so we can get descriptive errors before, but this'll catch anything else that's slipped through JsonConvert.SerializeObject(destination) .Should().Be(JsonConvert.SerializeObject(result)); }
public async Task GetCalculationByName_GivenSpecificationExistsAndCalculationExists_ReturnsSuccess() { //Arrange CalculationVersion calculationVersion = new CalculationVersion { Name = CalculationName, Date = new DateTimeOffset(2013, 1, 2, 3, 4, 55, TimeSpan.Zero), }; Calculation calc = new Calculation { Current = calculationVersion }; CalculationGetModel model = new CalculationGetModel { SpecificationId = SpecificationId, Name = CalculationName }; ILogger logger = CreateLogger(); ICalculationsRepository calculationsRepository = CreateCalculationsRepository(); calculationsRepository .GetCalculationsBySpecificationIdAndCalculationName(Arg.Is(SpecificationId), Arg.Is(CalculationName)) .Returns(calc); CalculationService service = CreateCalculationService(calculationsRepository: calculationsRepository, logger: logger); //Act IActionResult result = await service.GetCalculationByName(model); //Assert result .Should() .BeOfType <OkObjectResult>() .Which .Value .Should() .BeEquivalentTo(new CalculationResponseModel() { Name = CalculationName, SourceCode = "Return 0", LastUpdated = new DateTimeOffset(2013, 1, 2, 3, 4, 55, TimeSpan.Zero), }); }
public static CalculationVersionResponseModel ToResponseModel(this CalculationVersion version) { return(new CalculationVersionResponseModel() { Author = version.Author, CalculationId = version.Id, CalculationType = version.CalculationType, LastUpdated = version.Date, Name = version.Name, Namespace = version.Namespace, PublishStatus = version.PublishStatus, SourceCode = version.SourceCode, SourceCodeName = version.SourceCodeName, Version = version.Version, WasTemplateCalculation = version.WasTemplateCalculation, Description = version.Description, }); }
public async Task EditCalculationStatus_GivenNewStatusOfUpdated_UpdatesSearchReturnsOK() { //Arrange EditStatusModel CalculationEditStatusModel = new EditStatusModel { PublishStatus = PublishStatus.Updated }; string json = JsonConvert.SerializeObject(CalculationEditStatusModel); 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> { { "calculationId", new StringValues(CalculationId) }, }); request .Query .Returns(queryStringValues); request .Body .Returns(stream); request .HttpContext .Returns(context); ILogger logger = CreateLogger(); Calculation calculation = CreateCalculation(); calculation.Current.PublishStatus = PublishStatus.Approved; CalculationVersion calculationVersion = calculation.Current.Clone() as CalculationVersion; calculationVersion.PublishStatus = PublishStatus.Updated; ICalculationsRepository CalculationsRepository = CreateCalculationsRepository(); CalculationsRepository .GetCalculationById(Arg.Is(CalculationId)) .Returns(calculation); CalculationsRepository .UpdateCalculation(Arg.Any <Calculation>()) .Returns(HttpStatusCode.OK); ISearchRepository <CalculationIndex> searchRepository = CreateSearchRepository(); Models.Specs.SpecificationSummary specificationSummary = new Models.Specs.SpecificationSummary(); ISpecificationRepository specificationRepository = CreateSpecificationRepository(); specificationRepository .GetSpecificationSummaryById(Arg.Is(calculation.SpecificationId)) .Returns(specificationSummary); IVersionRepository <CalculationVersion> versionRepository = CreateCalculationVersionRepository(); versionRepository .CreateVersion(Arg.Any <CalculationVersion>(), Arg.Any <CalculationVersion>()) .Returns(calculationVersion); Build build = new Build { SourceFiles = new List <SourceFile> { new SourceFile() } }; BuildProject buildProject = new BuildProject(); IBuildProjectsService buildProjectsService = CreateBuildProjectsService(); buildProjectsService .GetBuildProjectForSpecificationId(Arg.Is(calculation.SpecificationId)) .Returns(buildProject); ISourceCodeService sourceCodeService = CreateSourceCodeService(); sourceCodeService .Compile(Arg.Any <BuildProject>(), Arg.Any <IEnumerable <Models.Calcs.Calculation> >(), Arg.Any <CompilerOptions>()) .Returns(build); CalculationService service = CreateCalculationService( logger: logger, calculationsRepository: CalculationsRepository, searchRepository: searchRepository, specificationRepository: specificationRepository, calculationVersionRepository: versionRepository, sourceCodeService: sourceCodeService, buildProjectsService: buildProjectsService); //Act IActionResult result = await service.UpdateCalculationStatus(request); //Arrange result .Should() .BeOfType <OkObjectResult>() .Which .Value .Should() .BeOfType <PublishStatusResultModel>() .Which .PublishStatus .Should() .Be(PublishStatus.Updated); calculation .Current .PublishStatus .Should() .Be(PublishStatus.Updated); await searchRepository .Received(1) .Index(Arg.Is <IEnumerable <CalculationIndex> >(m => m.First().Status == "Updated")); }
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 OnGet_WhencalculationVersionsListReturned() { // Arrange ICalculationsApiClient calcsClient = Substitute.For <ICalculationsApiClient>(); ISpecsApiClient specsClient = Substitute.For <ISpecsApiClient>(); IMapper mapper = MappingHelper.CreateFrontEndMapper(); ILogger logger = Substitute.For <ILogger>(); Calculation expectedCalculation = new Calculation() { CalculationSpecification = new Reference("1", "Calc spec"), Id = "2", Name = "Specs Calculation", FundingPeriodName = "2018/19", SpecificationId = "1", PublishStatus = PublishStatus.Draft, LastModifiedBy = new Reference("1", "Matt Vallily"), SourceCode = "Public Function GetProductResult(rid As String) As Decimal 'change to As String if text product Dim result As Decimal = 0 'change to As String if text product Dim P04_Learners As Decimal = products.1819_Additional_Funding.P04_Learner_Numbers Dim P03_Rate As Decimal = products.1819_Additional_Funding.P03_Maths_Top_Up_Rate result = P03_Rate * P04_learners Return result End Function", Version = 4 }; IEnumerable <int> versions = new List <int> { 1, 2 }; string calculationId = "1"; Clients.SpecsClient.Models.CalculationCurrentVersion specCalculation = new Clients.SpecsClient.Models.CalculationCurrentVersion() { Id = "1", Name = "Test spec", Description = "Test description", AllocationLine = new Reference("1", "Test Allocation") }; // build two versions for feeding the left and right panel CalculationVersion calver1 = new CalculationVersion() { DecimalPlaces = 2, Version = "1", Date = new DateTime(2018, 1, 1, 10, 23, 34), Author = new Reference("1", "Clifford"), Status = "Draft", SourceCode = "Test" }; CalculationVersion calver2 = new CalculationVersion() { DecimalPlaces = 2, Version = "2", Date = new DateTime(2018, 1, 1, 10, 23, 34), Author = new Reference("2", "Clifford"), Status = "Draft", SourceCode = "Test" }; IEnumerable <CalculationVersion> calcVerArray = new List <CalculationVersion> { calver1, calver2 }; calcVerArray.AsEnumerable(); calcsClient .GetCalculationById(calculationId) .Returns(new ApiResponse <Clients.CalcsClient.Models.Calculation>(System.Net.HttpStatusCode.OK, expectedCalculation)); specsClient .GetCalculationById("1", calculationId) .Returns(new ApiResponse <CalculateFunding.Frontend.Clients.SpecsClient.Models.CalculationCurrentVersion>(System.Net.HttpStatusCode.OK, specCalculation)); // CalculateFunding.Frontend.Clients.SpecsClient.Models calcsClient .GetMultipleVersionsByCalculationId(versions, calculationId) .Returns(new ApiResponse <IEnumerable <CalculationVersion> >(System.Net.HttpStatusCode.OK, calcVerArray)); DiffCalculationModel diffCalcPageModel = new DiffCalculationModel(specsClient, calcsClient, mapper); // Act IActionResult result = await diffCalcPageModel.OnGet(versions, calculationId); // Assert result.Should().NotBeNull(); diffCalcPageModel.RightCalculationDiffModel.Version.Should().Be(calver2.Version); diffCalcPageModel.LeftCalcualationDiffModel.Version.Should().Be(calver1.Version); }
public async Task OnGet_WhenCalculationExists_ThenCalculationReturned() { // Arrange ICalculationsApiClient calcsClient = Substitute.For <ICalculationsApiClient>(); ISpecsApiClient specsClient = Substitute.For <ISpecsApiClient>(); IMapper mapper = MappingHelper.CreateFrontEndMapper(); ILogger logger = Substitute.For <ILogger>(); string calculationId = "1"; Calculation expectedCalculation = new Calculation() { Id = "1", Name = "Specs Calculation", FundingPeriodName = "2018/19", SpecificationId = "3", PublishStatus = PublishStatus.Draft, LastModifiedBy = new Reference("1", "Matt Vallily"), SourceCode = "Public Function GetProductResult(rid As String) As Decimal 'change to As String if text product Dim result As Decimal = 0 'change to As String if text product Dim P04_Learners As Decimal = products.1819_Additional_Funding.P04_Learner_Numbers Dim P03_Rate As Decimal = products.1819_Additional_Funding.P03_Maths_Top_Up_Rate result = P03_Rate * P04_learners Return result End Function", Version = 4, CalculationSpecification = new Reference("1", "Test Spec") }; calcsClient .GetCalculationById(calculationId) .Returns(new ApiResponse <Calculation>(System.Net.HttpStatusCode.OK, expectedCalculation)); Clients.SpecsClient.Models.CalculationCurrentVersion specCalculation = new Clients.SpecsClient.Models.CalculationCurrentVersion() { Id = "1", Name = "Test spec", Description = "Test description", AllocationLine = new Reference("1", "Test Allocation") }; specsClient .GetCalculationById(expectedCalculation.SpecificationId, calculationId) .Returns(new ApiResponse <Clients.SpecsClient.Models.CalculationCurrentVersion>(System.Net.HttpStatusCode.OK, specCalculation)); CalculationVersion calcsVersion1 = new CalculationVersion() { Status = "Draft", Version = "1", DecimalPlaces = 4, Date = new DateTime(2018, 1, 1, 12, 34, 45, 03), Author = new Reference("1", "Matt Vallily"), SourceCode = "Public Function GetProductResult(rid As String) As Decimal 'change to As String if text product Dim result As Decimal = 0 'change to As String if text product Dim P04_Learners As Decimal = products.1819_Additional_Funding.P04_Learner_Numbers Dim P03_Rate As Decimal = products.1819_Additional_Funding.P03_Maths_Top_Up_Rate result = P03_Rate * P04_learners Return result End Function", }; CalculationVersion calcsVersion2 = new CalculationVersion() { Status = "Draft", Version = "2", DecimalPlaces = 4, Date = new DateTime(2018, 1, 2, 12, 34, 45, 03), Author = new Reference("1", "Matt Vallily"), SourceCode = "Public Function GetProductResult(rid As String) As Decimal 'change to As String if text product Dim result As Decimal = 0 'change to As String if text product Dim P04_Learners As Decimal = products.1819_Additional_Funding.P04_Learner_Numbers Dim P03_Rate As Decimal = products.1819_Additional_Funding.P03_Maths_Top_Up_Rate result = P03_Rate * P04_learners Return result End Function", }; CalculationVersion calcsVersion3 = new CalculationVersion() { Status = "Draft", Version = "3", DecimalPlaces = 4, Date = new DateTime(2018, 1, 3, 12, 34, 45, 03), Author = new Reference("1", "Matt Vallily"), SourceCode = "Public Function GetProductResult(rid As String) As Decimal 'change to As String if text product Dim result As Decimal = 0 'change to As String if text product Dim P04_Learners As Decimal = products.1819_Additional_Funding.P04_Learner_Numbers Dim P03_Rate As Decimal = products.1819_Additional_Funding.P03_Maths_Top_Up_Rate result = P03_Rate * P04_learners Return result End Function", }; IEnumerable <CalculationVersion> calculationVersion = new List <CalculationVersion>() { calcsVersion1, calcsVersion2, calcsVersion3 }; calcsClient .GetAllVersionsByCalculationId(calculationId) .Returns(new ApiResponse <IEnumerable <CalculationVersion> >(System.Net.HttpStatusCode.OK, calculationVersion)); ComparePageModel comparePageModel = new ComparePageModel(specsClient, calcsClient, mapper); // Act IActionResult result = await comparePageModel.OnGet(calculationId); // Assert result.Should().NotBeNull(); comparePageModel.Calculation.Should().NotBeNull(); comparePageModel.Calculation.Description.Should().Be(specCalculation.Description); comparePageModel.Calculation.Name.Should().Be(expectedCalculation.Name); comparePageModel.Calculations.Select(f => f.Version).Should().BeInDescendingOrder(); comparePageModel.Calculations.Should().HaveCount(3); ViewModels.Calculations.CalculationVersionViewModel firstCalculation = comparePageModel.Calculations.First(); firstCalculation.Version.Should().Be(calcsVersion3.Version); }
public async Task UpdateCalculationCodeOnCalculationChange_WhenNoCalculationsFoundReferencingCalculationToBeUpdated_ThenNoCalculationsUpdated() { // Arrange ICalculationsRepository calculationsRepository = CreateCalculationsRepository(); ISpecificationsApiClient specificationsApiClient = CreateSpecificationsApiClient(); IVersionRepository <CalculationVersion> versionRepository = CreateCalculationVersionRepository(); CalculationService service = CreateCalculationService(calculationsRepository: calculationsRepository, specificationsApiClient: specificationsApiClient, calculationVersionRepository: versionRepository); const string specificationId = "specId"; const string calculationId = "updatedCalc"; CalculationVersionComparisonModel comparison = new CalculationVersionComparisonModel() { CalculationId = calculationId, CurrentName = "Calculation To Update", PreviousName = "Original Name", SpecificationId = specificationId, }; Reference user = new Reference("userId", "User Name"); List <Calculation> calculations = new List <Calculation>() { new Calculation { Id = calculationId, SpecificationId = specificationId, Current = new CalculationVersion { SourceCode = "Return 10", Name = "Calculation to Update", CalculationType = CalculationType.Template, Description = "Calculation Description" } }, new Calculation { Id = "referenceCalc", SpecificationId = specificationId, Current = new CalculationVersion { SourceCode = "Return 50", Name = "Calling Calculation To Update", CalculationType = CalculationType.Template, Description = "Calculation Description", } } }; calculationsRepository .GetCalculationsBySpecificationId(Arg.Is(specificationId)) .Returns(calculations); calculationsRepository .UpdateCalculation(Arg.Any <Calculation>()) .Returns(HttpStatusCode.OK); calculationsRepository .GetCalculationById(Arg.Is(calculations[0].Id)) .Returns(calculations[0]); SpecModel.SpecificationSummary specification = new SpecModel.SpecificationSummary() { Id = specificationId, Name = "Specification Name", }; specificationsApiClient .GetSpecificationSummaryById(Arg.Is(specificationId)) .Returns(new Common.ApiClient.Models.ApiResponse <SpecModel.SpecificationSummary>(HttpStatusCode.OK, specification)); CalculationVersion calculationVersion = new CalculationVersion { SourceCode = "Return CalculationToUpdate()", Version = 2 }; versionRepository .CreateVersion(Arg.Any <CalculationVersion>(), Arg.Any <CalculationVersion>()) .Returns(calculationVersion); // Act IEnumerable <Calculation> updatedCalculations = await service.UpdateCalculationCodeOnCalculationChange(comparison, user); // Assert updatedCalculations .Should() .HaveCount(0); }
public async Task UpdateCalculationCodeOnCalculationChange_WhenCalculationsFoundReferencingCalculationToBeUpdated_ThenSourceCodeUpdated() { // Arrange ICalculationsRepository calculationsRepository = CreateCalculationsRepository(); ISpecificationsApiClient specificationsApiClient = CreateSpecificationsApiClient(); IVersionRepository <CalculationVersion> versionRepository = CreateCalculationVersionRepository(); IBuildProjectsService buildProjectsService = CreateBuildProjectsService(); ISourceCodeService sourceCodeService = CreateSourceCodeService(); CalculationService service = CreateCalculationService(calculationsRepository: calculationsRepository, specificationsApiClient: specificationsApiClient, calculationVersionRepository: versionRepository, buildProjectsService: buildProjectsService, sourceCodeService: sourceCodeService); const string specificationId = "specId"; const string calculationId = "updatedCalc"; const string originalCodeUpdate = @"Dim test as OriginalNameOptions? OriginalNameOptions.enumName Return Calculations.OriginalName()"; const string newCodeUpdated = @"Dim test as CalculationToUpdateOptions? CalculationToUpdateOptions.enumName Return Calculations.CalculationToUpdate()"; const string originalCodeIgnore = "Return 10"; const string fundingStreamId = "fundingstreamid"; CalculationVersionComparisonModel comparison = new CalculationVersionComparisonModel() { CalculationId = calculationId, CurrentName = "Calculation To Update", PreviousName = "Original Name", SpecificationId = specificationId, CalculationDataType = CalculationDataType.Enum, Namespace = "Calculations" }; Reference user = new Reference("userId", "User Name"); List <Calculation> calculations = new List <Calculation> { new Calculation { Id = calculationId, SpecificationId = specificationId, FundingStreamId = fundingStreamId, Current = new CalculationVersion { SourceCode = originalCodeIgnore, Name = "Calculation to Update", CalculationType = CalculationType.Template, Description = "Calculation Description", DataType = CalculationDataType.Enum } }, new Calculation { Id = "referenceCalc", SpecificationId = specificationId, FundingStreamId = fundingStreamId, Current = new CalculationVersion { SourceCode = originalCodeUpdate, Name = "Calling Calculation To Update", CalculationType = CalculationType.Template, Description = "Calculation Description" } } }; calculationsRepository .GetCalculationsBySpecificationId(Arg.Is(specificationId)) .Returns(calculations); calculationsRepository .UpdateCalculation(Arg.Any <Calculation>()) .Returns(HttpStatusCode.OK); calculationsRepository .GetCalculationById(Arg.Is(calculations[0].Id)) .Returns(calculations[0]); SpecModel.SpecificationSummary specification = new SpecModel.SpecificationSummary() { Id = specificationId, Name = "Specification Name", FundingStreams = new [] { new Reference(fundingStreamId, "fundingStreamName"), } }; specificationsApiClient .GetSpecificationSummaryById(Arg.Is(specificationId)) .Returns(new Common.ApiClient.Models.ApiResponse <SpecModel.SpecificationSummary>(HttpStatusCode.OK, specification)); CalculationVersion calculationVersion = new CalculationVersion { SourceCode = newCodeUpdated, Version = 2 }; versionRepository .CreateVersion(Arg.Is <CalculationVersion>(_ => _.SourceCode == newCodeUpdated), Arg.Any <CalculationVersion>()) .Returns(calculationVersion); buildProjectsService .GetBuildProjectForSpecificationId(specificationId) .Returns(new BuildProject()); sourceCodeService .Compile(Arg.Any <BuildProject>(), Arg.Any <IEnumerable <Calculation> >(), Arg.Any <CompilerOptions>()) .Returns(new Build()); // Act IEnumerable <Calculation> updatedCalculations = await service.UpdateCalculationCodeOnCalculationChange(comparison, user); // Assert updatedCalculations .Should() .HaveCount(1); Calculation calculation = updatedCalculations.Single(); calculation.Current.SourceCode .Should() .Be(newCodeUpdated); calculation.Current.Version .Should() .Be(2); calculation.Id .Should() .Be("referenceCalc"); }
public async Task CreateAdditionalCalculation_GivenCalcSaves_ReturnsOKObjectResult() { //Arrange string cacheKey = $"{CacheKeys.CalculationsMetadataForSpecification}{SpecificationId}"; CalculationCreateModel model = CreateCalculationCreateModel(); Reference author = CreateAuthor(); ICalculationsRepository calculationsRepository = CreateCalculationsRepository(); calculationsRepository .CreateDraftCalculation(Arg.Any <Calculation>()) .Returns(HttpStatusCode.OK); IVersionRepository <CalculationVersion> versionRepository = CreateCalculationVersionRepository(); ISearchRepository <CalculationIndex> searchRepository = CreateSearchRepository(); IJobManagement jobManagement = CreateJobManagement(); jobManagement .QueueJob(Arg.Any <JobCreateModel>()) .Returns(new Job { Id = "job-id-1" }); ISpecificationsApiClient specificationsApiClient = CreateSpecificationsApiClient(); specificationsApiClient .GetSpecificationSummaryById(Arg.Is(SpecificationId)) .Returns(new ApiResponse <SpecificationSummary>( HttpStatusCode.OK, new SpecificationSummary { Id = SpecificationId, FundingPeriod = new FundingPeriod { Id = FundingPeriodId } } )); ILogger logger = CreateLogger(); ICacheProvider cacheProvider = CreateCacheProvider(); ICodeContextCache codeContextCache = Substitute.For <ICodeContextCache>(); IResultsApiClient resultsApiClient = CreateResultsApiClient(); CalculationService calculationService = CreateCalculationService( calculationsRepository: calculationsRepository, calculationVersionRepository: versionRepository, searchRepository: searchRepository, jobManagement: jobManagement, logger: logger, cacheProvider: cacheProvider, specificationsApiClient: specificationsApiClient, codeContextCache: codeContextCache, resultsApiClient: resultsApiClient); IEnumerable <CalculationIndex> indexedCalculations = null; await searchRepository .Index(Arg.Do <IEnumerable <CalculationIndex> >(m => indexedCalculations = m )); CalculationVersion savedCalculationVersion = null; await versionRepository .SaveVersion(Arg.Do <CalculationVersion>(m => savedCalculationVersion = m)); //Act IActionResult result = await calculationService.CreateAdditionalCalculation(SpecificationId, model, author, CorrelationId); //Assert result .Should() .BeAssignableTo <OkObjectResult>(); Calculation calculation = (result as OkObjectResult).Value as Calculation; await jobManagement .Received(1) .QueueJob(Arg.Is <JobCreateModel>( m => m.InvokerUserDisplayName == Username && m.InvokerUserId == UserId && m.JobDefinitionId == JobConstants.DefinitionNames.CreateInstructAllocationJob && m.Properties["specification-id"] == SpecificationId )); logger .Received(1) .Information(Arg.Is($"New job of type '{JobConstants.DefinitionNames.CreateInstructAllocationJob}' created with id: 'job-id-1'")); await versionRepository .Received(1) .SaveVersion(Arg.Is <CalculationVersion>(m => m.PublishStatus == Models.Versioning.PublishStatus.Draft && m.Author.Id == UserId && m.Author.Name == Username && m.Date.Date == DateTimeOffset.Now.Date && m.Version == 1 && m.SourceCode == model.SourceCode && m.Description == model.Description && m.ValueType == model.ValueType && m.CalculationType == CalculationType.Additional && m.WasTemplateCalculation == false && m.Namespace == CalculationNamespace.Additional && m.Name == model.Name && m.SourceCodeName == new VisualBasicTypeIdentifierGenerator().GenerateIdentifier(model.Name) && m.DataType == CalculationDataType.Decimal )); await searchRepository .Received(1) .Index(Arg.Any <IEnumerable <CalculationIndex> >()); indexedCalculations .Should() .BeEquivalentTo(new List <CalculationIndex>() { new CalculationIndex() { CalculationType = "Additional", Description = "test description", FundingStreamId = "fs-1", FundingStreamName = model.FundingStreamName, Id = model.Id, Name = model.Name, Namespace = "Additional", SpecificationId = "spec-id-1", SpecificationName = "spec-id-1_specificationName", Status = "Draft", ValueType = "Currency", WasTemplateCalculation = false, LastUpdatedDate = savedCalculationVersion.Date, } }); //!string.IsNullOrWhiteSpace(m.First().Id) && //m.First().Name == model.Name && //m.First().SpecificationId == SpecificationId && //m.First().SpecificationName == model.SpecificationName && //m.First().ValueType == model.ValueType.ToString() && //m.First().CalculationType == CalculationType.Additional.ToString() && //m.First().Namespace == CalculationNamespace.Additional.ToString() && //m.First().FundingStreamId == model.FundingStreamId && //m.First().FundingStreamName == model.FundingStreamName && //m.First().WasTemplateCalculation == false && //m.First().Description == model.Description && //m.First().Status == calculation.Current.PublishStatus.ToString() await cacheProvider .Received(1) .RemoveAsync <List <CalculationMetadata> >(Arg.Is(cacheKey)); await codeContextCache .Received(1) .QueueCodeContextCacheUpdate(SpecificationId); }
public async Task EditCalculationStatus_GivenNewStatusOfUpdated_UpdatesSearchReturnsOK() { //Arrange EditStatusModel CalculationEditStatusModel = new EditStatusModel { PublishStatus = PublishStatus.Updated }; ILogger logger = CreateLogger(); Calculation calculation = CreateCalculation(); calculation.Current.PublishStatus = PublishStatus.Approved; CalculationVersion calculationVersion = calculation.Current.Clone() as CalculationVersion; calculationVersion.PublishStatus = PublishStatus.Updated; ICalculationsRepository CalculationsRepository = CreateCalculationsRepository(); CalculationsRepository .GetCalculationById(Arg.Is(CalculationId)) .Returns(calculation); CalculationsRepository .UpdateCalculation(Arg.Any <Calculation>()) .Returns(HttpStatusCode.OK); ISearchRepository <CalculationIndex> searchRepository = CreateSearchRepository(); SpecModel.SpecificationSummary specificationSummary = new SpecModel.SpecificationSummary() { Id = calculation.SpecificationId, Name = "spec name", FundingStreams = new[] { new Reference(calculation.FundingStreamId, "funding stream name") } }; ISpecificationsApiClient specificationsApiClient = CreateSpecificationsApiClient(); specificationsApiClient .GetSpecificationSummaryById(Arg.Is(calculation.SpecificationId)) .Returns(new Common.ApiClient.Models.ApiResponse <SpecModel.SpecificationSummary>(HttpStatusCode.OK, specificationSummary)); IVersionRepository <CalculationVersion> versionRepository = CreateCalculationVersionRepository(); versionRepository .CreateVersion(Arg.Any <CalculationVersion>(), Arg.Any <CalculationVersion>()) .Returns(calculationVersion); Build build = new Build { SourceFiles = new List <SourceFile> { new SourceFile() } }; BuildProject buildProject = new BuildProject(); IBuildProjectsService buildProjectsService = CreateBuildProjectsService(); buildProjectsService .GetBuildProjectForSpecificationId(Arg.Is(calculation.SpecificationId)) .Returns(buildProject); ISourceCodeService sourceCodeService = CreateSourceCodeService(); sourceCodeService .Compile(Arg.Any <BuildProject>(), Arg.Any <IEnumerable <Models.Calcs.Calculation> >(), Arg.Any <CompilerOptions>()) .Returns(build); CalculationService service = CreateCalculationService( logger: logger, calculationsRepository: CalculationsRepository, searchRepository: searchRepository, specificationsApiClient: specificationsApiClient, calculationVersionRepository: versionRepository, sourceCodeService: sourceCodeService, buildProjectsService: buildProjectsService); //Act IActionResult result = await service.UpdateCalculationStatus(CalculationId, CalculationEditStatusModel); //Arrange result .Should() .BeOfType <OkObjectResult>() .Which .Value .Should() .BeOfType <PublishStatusResultModel>() .Which .PublishStatus .Should() .Be(PublishStatus.Updated); calculation .Current .PublishStatus .Should() .Be(PublishStatus.Updated); }
public async Task UpdateCalculationCodeOnCalculationSpecificationChange_WhenNoCalculationsFoundReferencingCalculationToBeUpdated_ThenNoCalculationsUpdated() { // Arrange ICalculationsRepository calculationsRepository = CreateCalculationsRepository(); ISpecificationRepository specificationRepository = CreateSpecificationRepository(); IVersionRepository <CalculationVersion> versionRepository = CreateCalculationVersionRepository(); ICalculationCodeReferenceUpdate calculationCodeReferenceUpdate = FakeCalculationCodeReferenceUpdate(); CalculationService service = CreateCalculationService(calculationsRepository: calculationsRepository, specificationRepository: specificationRepository, calculationVersionRepository: versionRepository, calculationCodeReferenceUpdate: calculationCodeReferenceUpdate); const string specificationId = "specId"; const string calculationId = "updatedCalc"; Models.Specs.CalculationVersionComparisonModel comparison = new Models.Specs.CalculationVersionComparisonModel() { CalculationId = calculationId, Current = new Models.Specs.Calculation { Id = "calcSpec1", Name = "Calculation to update", CalculationType = Models.Specs.CalculationType.Funding, }, Previous = new Models.Specs.Calculation { Id = "calcSpec1", Name = "Original Name", CalculationType = Models.Specs.CalculationType.Funding, }, SpecificationId = specificationId, }; Reference user = new Reference("userId", "User Name"); List <Calculation> calculations = new List <Calculation>() { new Calculation { Id = calculationId, Name = "Calculation to Update", SpecificationId = specificationId, FundingPeriod = new Reference("fp1", "Funding Period"), CalculationSpecification = new Reference("calcSpec1", "Calculation to Update"), CalculationType = CalculationType.Funding, Description = "Calculation Description", BuildProjectId = "bpC1", Policies = new List <Reference>(), Current = new CalculationVersion { SourceCode = "Return 10", DecimalPlaces = 6, } }, new Calculation { Id = "referenceCalc", Name = "Calling Calculation To Update", SpecificationId = specificationId, FundingPeriod = new Reference("fp1", "Funding Period"), CalculationSpecification = new Reference("calcSpec1", "Calculation to Update"), CalculationType = CalculationType.Funding, Description = "Calculation Description", BuildProjectId = "bpC1", Policies = new List <Reference>(), Current = new CalculationVersion { SourceCode = "Return 50", DecimalPlaces = 6, } } }; calculationsRepository .GetCalculationsBySpecificationId(Arg.Is(specificationId)) .Returns(calculations); calculationsRepository .UpdateCalculation(Arg.Any <Calculation>()) .Returns(HttpStatusCode.OK); calculationsRepository .GetCalculationById(Arg.Is(calculations[0].Id)) .Returns(calculations[0]); Models.Specs.SpecificationSummary specification = new Models.Specs.SpecificationSummary() { Id = specificationId, Name = "Specification Name", }; specificationRepository .GetSpecificationSummaryById(Arg.Is(specificationId)) .Returns(specification); CalculationVersion calculationVersion = new CalculationVersion { SourceCode = "Return CalculationToUpdate()", Version = 2 }; versionRepository .CreateVersion(Arg.Any <CalculationVersion>(), Arg.Any <CalculationVersion>()) .Returns(calculationVersion); // Act IEnumerable <Calculation> updatedCalculations = await service.UpdateCalculationCodeOnCalculationSpecificationChange(comparison, user); // Assert updatedCalculations .Should() .HaveCount(0); calculationCodeReferenceUpdate .Received(calculations.Count) .ReplaceSourceCodeReferences(Arg.Any <string>(), VisualBasicTypeGenerator.GenerateIdentifier(comparison.Previous.Name), VisualBasicTypeGenerator.GenerateIdentifier(comparison.Current.Name)); foreach (Calculation calculation in calculations) { calculationCodeReferenceUpdate .Received(1) .ReplaceSourceCodeReferences(calculation.Current.SourceCode, VisualBasicTypeGenerator.GenerateIdentifier(comparison.Previous.Name), VisualBasicTypeGenerator.GenerateIdentifier(comparison.Current.Name)); } }
public CalculationBuilder WithCurrentVersion(CalculationVersion calculationVersion) { _calculationVersion = calculationVersion; return(this); }
public async Task <CreateCalculationResponse> CreateCalculation(string specificationId, CalculationCreateModel model, CalculationNamespace calculationNamespace, CalculationType calculationType, Reference author, string correlationId, CalculationDataType calculationDataType = CalculationDataType.Decimal, bool initiateCalcRun = true, IEnumerable <string> allowedEnumTypeValues = null) { Guard.ArgumentNotNull(model, nameof(model)); Guard.ArgumentNotNull(author, nameof(author)); if (string.IsNullOrWhiteSpace(model.Id)) { model.Id = Guid.NewGuid().ToString(); } model.SpecificationId = specificationId; model.CalculationType = calculationType; ValidationResult validationResult = await _calculationCreateModelValidator.ValidateAsync(model); if (!validationResult.IsValid) { return(new CreateCalculationResponse { ValidationResult = validationResult, ErrorType = CreateCalculationErrorType.InvalidRequest }); } Calculation calculation = new Calculation { Id = model.Id, FundingStreamId = model.FundingStreamId, SpecificationId = model.SpecificationId }; CalculationVersion calculationVersion = new CalculationVersion { CalculationId = calculation.Id, PublishStatus = PublishStatus.Draft, Author = author, Date = DateTimeOffset.Now.ToLocalTime(), Version = 1, SourceCode = model.SourceCode, Description = model.Description, ValueType = model.ValueType.Value, CalculationType = calculationType, WasTemplateCalculation = false, Namespace = calculationNamespace, Name = model.Name, DataType = calculationDataType, AllowedEnumTypeValues = allowedEnumTypeValues != null ? new List <string>(allowedEnumTypeValues) : Enumerable.Empty <string>() }; calculation.Current = calculationVersion; bool?nameValidResult = await _calculationNameInUseCheck.IsCalculationNameInUse(calculation.SpecificationId, calculation.Name, null); if (nameValidResult == true) { string error = $"Calculation with the same generated source code name already exists in this specification. Calculation Name {calculation.Name} and Specification {calculation.SpecificationId}"; _logger.Error(error); return(new CreateCalculationResponse { ErrorMessage = error, ErrorType = CreateCalculationErrorType.InvalidRequest }); } calculation.Current.SourceCodeName = _typeIdentifierGenerator.GenerateIdentifier(calculation.Name); HttpStatusCode result = await _calculationRepositoryPolicy.ExecuteAsync(() => _calculationsRepository.CreateDraftCalculation(calculation)); if (result.IsSuccess()) { await _calculationVersionsRepositoryPolicy.ExecuteAsync(() => _calculationVersionRepository.SaveVersion(calculationVersion)); await UpdateSearch(calculation, model.SpecificationName, model.FundingStreamName); string cacheKey = $"{CacheKeys.CalculationsMetadataForSpecification}{specificationId}"; await _cachePolicy.ExecuteAsync(() => _cacheProvider.RemoveAsync <List <CalculationMetadata> >(cacheKey)); if (!initiateCalcRun) { return(new CreateCalculationResponse { Succeeded = true, Calculation = calculation }); } try { Job job = await SendInstructAllocationsToJobService(calculation.SpecificationId, author.Id, author.Name, new Trigger { EntityId = calculation.Id, EntityType = nameof(Calculation), Message = $"Saving calculation: '{calculation.Id}' for specification: '{calculation.SpecificationId}'" }, correlationId); if (job != null) { _logger.Information($"New job of type '{JobConstants.DefinitionNames.CreateInstructAllocationJob}' created with id: '{job.Id}'"); return(new CreateCalculationResponse { Succeeded = true, Calculation = calculation }); } else { string errorMessage = $"Failed to create job of type '{JobConstants.DefinitionNames.CreateInstructAllocationJob}' on specification '{calculation.SpecificationId}'"; _logger.Error(errorMessage); return(new CreateCalculationResponse { ErrorType = CreateCalculationErrorType.Exception, ErrorMessage = errorMessage }); } } catch (Exception ex) { return(new CreateCalculationResponse { ErrorMessage = ex.Message, ErrorType = CreateCalculationErrorType.Exception }); } } else { string errorMessage = $"There was problem creating a new calculation with name {calculation.Name} in Cosmos Db with status code {(int)result}"; _logger.Error(errorMessage); return(new CreateCalculationResponse { ErrorMessage = errorMessage, ErrorType = CreateCalculationErrorType.Exception }); } }