public async Task CreateAdditionalCalculation_GivenCreateJobReturnsNull_ReturnsInternalServerError() { //Arrange 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((Job)null); ISpecificationsApiClient specificationsApiClient = CreateSpecificationsApiClient(); specificationsApiClient .GetSpecificationSummaryById(Arg.Is(SpecificationId)) .Returns(new ApiResponse <SpecificationSummary>( HttpStatusCode.OK, new SpecificationSummary { Id = SpecificationId } )); ILogger logger = CreateLogger(); CalculationService calculationService = CreateCalculationService( calculationsRepository: calculationsRepository, calculationVersionRepository: versionRepository, searchRepository: searchRepository, jobManagement: jobManagement, logger: logger, specificationsApiClient: specificationsApiClient); //Act IActionResult result = await calculationService.CreateAdditionalCalculation(SpecificationId, model, author, CorrelationId); //Assert result .Should() .BeOfType <InternalServerErrorResult>() .Which .Value .Should() .Be($"Failed to create job of type '{JobConstants.DefinitionNames.CreateInstructAllocationJob}' on specification '{SpecificationId}'"); logger .Received(1) .Error(Arg.Is($"Failed to create job of type '{JobConstants.DefinitionNames.CreateInstructAllocationJob}' on specification '{SpecificationId}'")); }
public async Task CreateAdditionalCalculation_GivenValidationFails_ReturnsBadRequest() { //Arrange string correlationId = "any-id"; CalculationCreateModel model = new CalculationCreateModel(); Reference author = new Reference(); ValidationResult validationResult = new ValidationResult(new[] { new ValidationFailure("prop1", "oh no an error!!!") }); IValidator <CalculationCreateModel> validator = CreateCalculationCreateModelValidator(validationResult); ISpecificationsApiClient specificationsApiClient = CreateSpecificationsApiClient(); specificationsApiClient .GetSpecificationSummaryById(Arg.Is(SpecificationId)) .Returns(new ApiResponse <SpecificationSummary>( HttpStatusCode.OK, new SpecificationSummary { Id = SpecificationId } )); CalculationService calculationService = CreateCalculationService(calculationCreateModelValidator: validator, specificationsApiClient: specificationsApiClient); //Act IActionResult result = await calculationService.CreateAdditionalCalculation(SpecificationId, model, author, correlationId); //Assert result .Should() .BeAssignableTo <BadRequestObjectResult>(); }
public async Task IsCalculationNameValid_WhenCalculationDoesNotExist_ThenReturnsOkResult() { // Arrange string specificationId = "spec1"; ISpecificationsApiClient specificationsApiClient = CreateSpecificationsApiClient(); specificationsApiClient .GetSpecificationSummaryById(Arg.Is(specificationId)) .Returns(new Common.ApiClient.Models.ApiResponse <SpecModel.SpecificationSummary>(HttpStatusCode.OK, new SpecModel.SpecificationSummary { Id = specificationId })); ICalculationsRepository calculationsRepository = CreateCalculationsRepository(); calculationsRepository .GetCalculationsBySpecificationId(Arg.Is(specificationId)) .Returns(new List <Calculation>()); CalculationService service = CreateCalculationService(specificationsApiClient: specificationsApiClient, calculationsRepository: calculationsRepository); // Act IActionResult result = await service.IsCalculationNameValid(specificationId, "calc1", null); // Assert result .Should() .BeOfType <OkResult>(); }
public async Task ValidateAsync_WhenSpecificationCanNotBeFound_ValidIsFalse() { //Arrange CalculationCreateModel model = CreateModel(); ISpecificationsApiClient specificationsApiClient = CreateSpecificationsApiClient(); specificationsApiClient .GetSpecificationSummaryById(Arg.Is(model.SpecificationId)) .Returns(new Common.ApiClient.Models.ApiResponse <SpecModel.SpecificationSummary>(HttpStatusCode.OK, null)); CalculationCreateModelValidator validator = CreateValidator(specificationsApiClient: specificationsApiClient); //Act ValidationResult result = await validator.ValidateAsync(model); //Assert result .IsValid .Should() .BeFalse(); result.Errors .Should() .Contain(_ => _.ErrorMessage == "Failed to find specification for provided specification id."); }
public async Task ValidateAsync_WhenSpecificationDoesNotContainFundingStreamValidIsFalse() { //Arrange CalculationCreateModel model = CreateModel(); SpecModel.SpecificationSummary specificationSummary = new SpecModel.SpecificationSummary { FundingStreams = new[] { new Reference() } }; ISpecificationsApiClient specificationsApiClient = CreateSpecificationsApiClient(); specificationsApiClient .GetSpecificationSummaryById(Arg.Is(model.SpecificationId)) .Returns(new Common.ApiClient.Models.ApiResponse <SpecModel.SpecificationSummary>(HttpStatusCode.OK, specificationSummary)); CalculationCreateModelValidator validator = CreateValidator(specificationsApiClient: specificationsApiClient); //Act ValidationResult result = await validator.ValidateAsync(model); //Assert result .IsValid .Should() .BeFalse(); result.Errors .Should() .Contain(_ => _.ErrorMessage == "The funding stream id provided is not associated with the provided specification."); }
public async Task <ApiSpecificationSummary> GetSpecificationSummaryById(string specificationId) { Guard.IsNullOrWhiteSpace(specificationId, nameof(specificationId)); ApiResponse <ApiSpecificationSummary> specificationSummaryResponse = await _resiliencePolicy.ExecuteAsync(() => _specifications.GetSpecificationSummaryById(specificationId)); return(specificationSummaryResponse?.Content); }
public async Task <IActionResult> GetPreviousProfilesForSpecificationForProviderForFundingLine( string specificationId, string providerId, string fundingStreamId, string fundingLineCode) { Guard.ArgumentNotNull(fundingStreamId, nameof(fundingStreamId)); Guard.ArgumentNotNull(specificationId, nameof(specificationId)); Guard.ArgumentNotNull(providerId, nameof(providerId)); Guard.ArgumentNotNull(fundingLineCode, nameof(fundingLineCode)); ApiResponse <IEnumerable <FundingLineChange> > fundingLineApiResponse = await _publishingApiClient .GetPreviousProfilesForSpecificationForProviderForFundingLine( specificationId, providerId, fundingStreamId, fundingLineCode); IActionResult fundingLineErrorResult = fundingLineApiResponse.IsSuccessOrReturnFailureResult(nameof(PublishedProviderVersion)); if (fundingLineErrorResult != null) { return(fundingLineErrorResult); } ApiResponse <ProviderVersionSearchResult> providerResponse = await _providersApiClient.GetCurrentProviderForFundingStream(fundingStreamId, providerId); IActionResult providerErrorResult = providerResponse.IsSuccessOrReturnFailureResult(nameof(ProviderVersionSearchResult)); if (providerErrorResult != null) { return(providerErrorResult); } ApiResponse <SpecificationSummary> specificationResponse = await _specificationsApiClient.GetSpecificationSummaryById(specificationId); IActionResult specificationErrorResult = specificationResponse.IsSuccessOrReturnFailureResult(nameof(SpecificationSummary)); if (specificationErrorResult != null) { return(specificationErrorResult); } SpecificationSummary specification = specificationResponse.Content; return(Ok(new FundingLineChangesViewModel { ProviderName = providerResponse.Content.Name, SpecificationName = specification.Name, FundingPeriodName = specification.FundingPeriod.Name, FundingLineChanges = fundingLineApiResponse.Content })); }
public async Task ValidateAsync_WhenSourceCodeDoesNotCompile__ValidIsFalse() { //Arrange CalculationCreateModel model = CreateModel(); model.CalculationType = CalculationType.Additional; ICalculationsRepository calculationsRepository = CreateCalculationRepository(); calculationsRepository .GetCalculationsBySpecificationIdAndCalculationName(Arg.Is(model.SpecificationId), Arg.Is(model.Name)) .Returns((Calculation)null); SpecModel.SpecificationSummary specificationSummary = new SpecModel.SpecificationSummary { Name = "spec name", FundingStreams = new[] { new Reference(model.FundingStreamId, "funding stream name") } }; ISpecificationsApiClient specificationsApiClient = CreateSpecificationsApiClient(); specificationsApiClient .GetSpecificationSummaryById(Arg.Is(model.SpecificationId)) .Returns(new Common.ApiClient.Models.ApiResponse <SpecModel.SpecificationSummary>(HttpStatusCode.OK, specificationSummary)); PreviewResponse previewResponse = new PreviewResponse { CompilerOutput = new Build { CompilerMessages = new List <CompilerMessage> { new CompilerMessage { Message = "Failed" } } } }; IPreviewService previewService = CreatePreviewService(previewResponse); CalculationCreateModelValidator validator = CreateValidator( calculationsRepository, previewService: previewService, specificationsApiClient: specificationsApiClient); //Act ValidationResult result = await validator.ValidateAsync(model); //Assert result .IsValid .Should() .BeFalse(); result.Errors .Should() .Contain(_ => _.ErrorMessage == "There are errors in the source code provided"); }
private void AndSpecification() { _specificationSummary = NewSpecificationSummary(_ => _.WithId(SpecificationId) .WithFundingStreamIds(new[] { FundingStreamId }) .WithFundingPeriodId(FundingPeriodId) .WithTemplateIds((FundingStreamId, "1.0"))); _specificationsApiClient.GetSpecificationSummaryById(SpecificationId) .Returns(new ApiResponse <SpecificationSummary>(HttpStatusCode.OK, _specificationSummary)); }
private async Task <SpecificationSummary> GetSpecificationSummary(string specificationId) { ApiResponse <SpecificationSummary> specificationQuery = await _specificationsApiPolicy.ExecuteAsync(() => _specificationsApiClient.GetSpecificationSummaryById(specificationId)); if (specificationQuery == null || specificationQuery.StatusCode != HttpStatusCode.OK || specificationQuery.Content == null) { throw new InvalidOperationException("Specification summary is null"); } return(specificationQuery.Content); }
private void AndTheSpecificationIsReturned() { _specificationApiClient.GetSpecificationSummaryById(Arg.Is(_specificationId)) .Returns(new ApiResponse <SpecificationSummary> ( HttpStatusCode.OK, new SpecificationSummary { Id = _specificationId, FundingPeriod = new Reference(_fundingPeriodId, "") } ));; }
public async Task CreateAdditionalCalculation_GivenSavingDraftCalcFails_ReturnsInternalServerErrorResult() { //Arrange string correlationId = "any-id"; CalculationCreateModel model = CreateCalculationCreateModel(); Reference author = CreateAuthor(); ICalculationsRepository calculationsRepository = CreateCalculationsRepository(); calculationsRepository .CreateDraftCalculation(Arg.Any <Calculation>()) .Returns(HttpStatusCode.BadRequest); ISpecificationsApiClient specificationsApiClient = CreateSpecificationsApiClient(); specificationsApiClient .GetSpecificationSummaryById(Arg.Is(SpecificationId)) .Returns(new ApiResponse <SpecificationSummary>( HttpStatusCode.OK, new SpecificationSummary { Id = SpecificationId } )); ILogger logger = CreateLogger(); CalculationService calculationService = CreateCalculationService(logger: logger, calculationsRepository: calculationsRepository, specificationsApiClient: specificationsApiClient); string errorMessage = $"There was problem creating a new calculation with name {CalculationName} in Cosmos Db with status code 400"; //Act IActionResult result = await calculationService.CreateAdditionalCalculation(SpecificationId, model, author, correlationId); //Assert result .Should() .BeAssignableTo <InternalServerErrorResult>() .Which .Value .Should() .Be(errorMessage); logger .Received(1) .Error(Arg.Is(errorMessage)); }
public async Task <IActionResult> ReIndex() { IEnumerable <DocumentEntity <TestScenario> > testScenarios = await _scenariosRepository.GetAllTestScenarios(); List <ScenarioIndex> testScenarioIndexes = new List <ScenarioIndex>(); Dictionary <string, SpecModel.SpecificationSummary> specifications = new Dictionary <string, SpecModel.SpecificationSummary>(); foreach (DocumentEntity <TestScenario> entity in testScenarios) { TestScenario testScenario = entity.Content; SpecModel.SpecificationSummary specificationSummary = null; if (!specifications.ContainsKey(testScenario.SpecificationId)) { Common.ApiClient.Models.ApiResponse <SpecModel.SpecificationSummary> specificationApiResponse = await _specificationsApiClientPolicy.ExecuteAsync(() => _specificationsApiClient.GetSpecificationSummaryById(testScenario.SpecificationId)); specificationSummary = specificationApiResponse.Content; specifications.Add(testScenario.SpecificationId, specificationSummary); } else { specificationSummary = specifications[testScenario.SpecificationId]; } testScenarioIndexes.Add(new ScenarioIndex() { Id = testScenario.Id, Name = testScenario.Name, Description = testScenario.Current.Description, LastUpdatedDate = entity.UpdatedAt, FundingStreamIds = testScenario.Current?.FundingStreamIds.ToArray(), FundingStreamNames = specificationSummary.FundingStreams.Select(s => s.Name).ToArray(), FundingPeriodId = testScenario.Current?.FundingPeriodId, FundingPeriodName = specificationSummary.FundingPeriod.Name, SpecificationId = testScenario.SpecificationId, SpecificationName = specificationSummary.Name, Status = Enum.GetName(typeof(PublishStatus), testScenario.Current.PublishStatus), }); } await _searchRepository.Index(testScenarioIndexes); return(new OkObjectResult($"Updated {testScenarioIndexes.Count} records")); }
public async Task EditCalculationStatus_GivenNewStatusButUpdatingDbReturnsBadRequest_ReturnsStatusCode400() { //Arrange EditStatusModel CalculationEditStatusModel = new EditStatusModel { PublishStatus = PublishStatus.Approved }; ILogger logger = CreateLogger(); Calculation calculation = CreateCalculation(); ICalculationsRepository CalculationsRepository = CreateCalculationsRepository(); CalculationsRepository .GetCalculationById(Arg.Is(CalculationId)) .Returns(calculation); CalculationsRepository .UpdateCalculation(Arg.Any <Calculation>()) .Returns(HttpStatusCode.BadRequest); SpecModel.SpecificationSummary specificationSummary = new SpecModel.SpecificationSummary(); ISpecificationsApiClient specificationsApiClient = CreateSpecificationsApiClient(); specificationsApiClient .GetSpecificationSummaryById(Arg.Is(calculation.SpecificationId)) .Returns(new Common.ApiClient.Models.ApiResponse <SpecModel.SpecificationSummary>(HttpStatusCode.OK, specificationSummary)); CalculationService service = CreateCalculationService( logger: logger, calculationsRepository: CalculationsRepository, specificationsApiClient: specificationsApiClient); //Act IActionResult result = await service.UpdateCalculationStatus(CalculationId, CalculationEditStatusModel); //Arrange result .Should() .BeAssignableTo <StatusCodeResult>() .Which .StatusCode .Should() .Be(400); }
public async Task GetEffectivePermissionsForUser_WhenNotFoundInCacheButSpecificationNotFound_ThenPreconditionFailedResultReturned() { // Arrange ICacheProvider cacheProvider = CreateCacheProvider(); EffectiveSpecificationPermission cachedPermission = null; cacheProvider .GetHashValue <EffectiveSpecificationPermission>(Arg.Is($"{CacheKeys.EffectivePermissions}:{UserId}"), Arg.Is(SpecificationId)) .Returns(cachedPermission); ISpecificationsApiClient specificationsApiClient = CreateSpecificationsApiClient(); SpecModel.SpecificationSummary specificationSummary = null; specificationsApiClient .GetSpecificationSummaryById(Arg.Is(SpecificationId)) .Returns(new ApiResponse <SpecModel.SpecificationSummary>(HttpStatusCode.OK, specificationSummary)); FundingStreamPermissionService service = CreateService( specificationsApiClient: specificationsApiClient, cacheProvider: cacheProvider); // Act IActionResult result = await service.GetEffectivePermissionsForUser(UserId, SpecificationId); // Assert result .Should() .BeOfType <PreconditionFailedResult>() .Which .Value .Should() .Be("Specification not found"); await cacheProvider .Received(1) .GetHashValue <EffectiveSpecificationPermission>(Arg.Is($"{CacheKeys.EffectivePermissions}:{UserId}"), Arg.Is(SpecificationId)); await cacheProvider .Received(0) .SetHashValue( Arg.Is($"{CacheKeys.EffectivePermissions}:{UserId}"), Arg.Is(SpecificationId), Arg.Any <EffectiveSpecificationPermission>()); }
public override async Task Process(Message message) { Guard.ArgumentNotNull(message, nameof(message)); string specificationId = UserPropertyFrom(message, "specification-id"); IEnumerable <Calculation> calculations = (await _calculationRepositoryPolicy.ExecuteAsync(() => _calculationsRepository.GetCalculationsBySpecificationId(specificationId))) .ToArraySafe(); if (calculations.IsNullOrEmpty()) { string calcNotFoundMessage = $"No calculations found for specification id: {specificationId}"; _logger.Information(calcNotFoundMessage); return; } foreach (Calculation calculation in calculations) { calculation.Current.PublishStatus = Models.Versioning.PublishStatus.Approved; } ApiResponse <SpecModel.SpecificationSummary> specificationApiResponse = await _specificationsApiClientPolicy.ExecuteAsync(() => _specificationsApiClient.GetSpecificationSummaryById(specificationId)); if (!specificationApiResponse.StatusCode.IsSuccess() || specificationApiResponse.Content == null) { throw new NonRetriableException("Specification not found"); } SpecModel.SpecificationSummary specificationSummary = specificationApiResponse.Content; await _calculationRepositoryPolicy.ExecuteAsync(() => _calculationsRepository.UpdateCalculations(calculations)); await UpdateSearch(calculations, specificationSummary); IEnumerable <Task> tasks = calculations.Select(_ => UpdateCalculationInCache(_.ToResponseModel())); await TaskHelper.WhenAllAndThrow(tasks.ToArraySafe()); await UpdateCalculationsInCache(specificationSummary); }
public async Task IsCalculationNameValid_WhenSameCalculation_ThenReturnsOkResult() { // Arrange string specificationId = "spec1"; string calcName = "calc1"; string calcSpecId = "calc-1"; ISpecificationsApiClient specificationsApiClient = CreateSpecificationsApiClient(); specificationsApiClient .GetSpecificationSummaryById(Arg.Is(specificationId)) .Returns(new Common.ApiClient.Models.ApiResponse <SpecModel.SpecificationSummary>(HttpStatusCode.OK, new SpecModel.SpecificationSummary { Id = specificationId })); List <Calculation> existingCalcs = new List <Calculation> { new Calculation { Current = new CalculationVersion { Name = calcName, SourceCodeName = calcName }, Id = "calc-1" } }; ICalculationsRepository calculationsRepository = CreateCalculationsRepository(); calculationsRepository .GetCalculationsBySpecificationId(Arg.Is(specificationId)) .Returns(existingCalcs); CalculationService service = CreateCalculationService(specificationsApiClient: specificationsApiClient, calculationsRepository: calculationsRepository); // Act IActionResult result = await service.IsCalculationNameValid(specificationId, calcName, calcSpecId); // Assert result .Should() .BeOfType <OkResult>(); }
public async Task <IActionResult> GetSpecificationById(string specificationId) { Guard.IsNullOrWhiteSpace(specificationId, nameof(specificationId)); ApiResponse <SpecificationSummary> apiResponse = await _specificationsApiClient.GetSpecificationSummaryById(specificationId); if (apiResponse.StatusCode == HttpStatusCode.OK) { return(Ok(apiResponse.Content)); } if (apiResponse.StatusCode == HttpStatusCode.BadRequest) { return(new BadRequestResult()); } return(new StatusCodeResult((int)apiResponse.StatusCode)); }
public async Task ValidateAsync_WhenValidModel_ValidIsTrue() { //Arrange CalculationCreateModel model = CreateModel(); ICalculationsRepository calculationsRepository = CreateCalculationRepository(); calculationsRepository .GetCalculationsBySpecificationIdAndCalculationName(Arg.Is(model.SpecificationId), Arg.Is(model.Name)) .Returns((Calculation)null); SpecModel.SpecificationSummary specificationSummary = new SpecModel.SpecificationSummary { Name = "spec name", FundingStreams = new[] { new Reference(model.FundingStreamId, "funding stream name") } }; ISpecificationsApiClient specificationsApiClient = CreateSpecificationsApiClient(); specificationsApiClient .GetSpecificationSummaryById(Arg.Is(model.SpecificationId)) .Returns(new Common.ApiClient.Models.ApiResponse <SpecModel.SpecificationSummary>(HttpStatusCode.OK, specificationSummary)); CalculationCreateModelValidator validator = CreateValidator( calculationsRepository, specificationsApiClient: specificationsApiClient); //Act ValidationResult result = await validator.ValidateAsync(model); //Assert result .IsValid .Should() .BeTrue(); model.SpecificationName .Should() .Be("spec name"); model.FundingStreamName .Should() .Be("funding stream name"); }
public async Task <IActionResult> GetSources(string specificationId) { Guard.IsNullOrWhiteSpace(specificationId, nameof(specificationId)); ApiResponse <SpecificationSummary> specificationResponse = await _specificationsApiClient.GetSpecificationSummaryById(specificationId); if (specificationResponse.StatusCode != HttpStatusCode.OK) { return(new StatusCodeResult((int)specificationResponse.StatusCode)); } SpecificationDatasetRelationshipsViewModel viewModel = await PopulateViewModel(specificationResponse.Content); if (viewModel == null) { return(new StatusCodeResult(500)); } return(new OkObjectResult(viewModel)); }
private static ISpecificationsApiClient CreateSpecificationsApiClient() { ISpecificationsApiClient specificationsApiClient = Substitute.For <ISpecificationsApiClient>(); SpecModel.SpecificationSummary specificationSummary = new SpecModel.SpecificationSummary() { TemplateIds = new Dictionary <string, string> { { "fs-1", "2.2" } }, FundingStreams = new List <Reference>() { new Reference("fs-1", "PE and Sports"), }, }; specificationsApiClient .GetSpecificationSummaryById(Arg.Any <string>()) .Returns(new ApiResponse <SpecModel.SpecificationSummary>(HttpStatusCode.OK, specificationSummary)); return(specificationsApiClient); }
public async Task IsCalculationNameValid_WhenSpecificationDoesNotExist_ThenReturnsNotFoundResult() { // Arrange string specificationId = "spec1"; ISpecificationsApiClient specificationsApiClient = CreateSpecificationsApiClient(); specificationsApiClient .GetSpecificationSummaryById(Arg.Is(specificationId)) .Returns(new Common.ApiClient.Models.ApiResponse <SpecModel.SpecificationSummary>(HttpStatusCode.OK, null)); CalculationService service = CreateCalculationService(specificationsApiClient: specificationsApiClient); // Act IActionResult result = await service.IsCalculationNameValid(specificationId, "calc1", null); // Assert result .Should() .BeOfType <NotFoundResult>(); }
public async Task EditCalculationStatus_GivenNewStatusButNoSpecSummaryFound_ReturnsPreConditionFailed() { //Arrange EditStatusModel CalculationEditStatusModel = new EditStatusModel { PublishStatus = PublishStatus.Approved }; ILogger logger = CreateLogger(); Calculation calculation = CreateCalculation(); ICalculationsRepository CalculationsRepository = CreateCalculationsRepository(); CalculationsRepository .GetCalculationById(Arg.Is(CalculationId)) .Returns(calculation); ISpecificationsApiClient specificationsApiClient = CreateSpecificationsApiClient(); specificationsApiClient .GetSpecificationSummaryById(Arg.Is(calculation.SpecificationId)) .Returns(new Common.ApiClient.Models.ApiResponse <SpecModel.SpecificationSummary>(HttpStatusCode.OK, null)); CalculationService service = CreateCalculationService( logger: logger, calculationsRepository: CalculationsRepository, specificationsApiClient: specificationsApiClient); //Act IActionResult result = await service.UpdateCalculationStatus(CalculationId, CalculationEditStatusModel); //Arrange result .Should() .BeAssignableTo <PreconditionFailedResult>() .Which .Value .Should() .Be("Specification not found"); }
public async Task ValidateAsync_WhenFundingStreamIdEmptyForAdditionalCalcs_ValidIsTrue() { //Arrange CalculationCreateModel model = CreateModel(CalculationType.Additional); model.FundingStreamId = string.Empty; ISpecificationsApiClient specificationsApiClient = CreateSpecificationsApiClient(); specificationsApiClient .GetSpecificationSummaryById(Arg.Is(model.SpecificationId)) .Returns(new Common.ApiClient.Models.ApiResponse <SpecModel.SpecificationSummary>(HttpStatusCode.OK, new SpecModel.SpecificationSummary())); CalculationCreateModelValidator validator = CreateValidator(specificationsApiClient: specificationsApiClient); //Act ValidationResult result = await validator.ValidateAsync(model); //Assert result .IsValid .Should() .BeTrue(); }
private void GivenTheApiResponseContentForTheSpecificationId(ApiSpecificationSummary specificationSummary, string specificationId) { _specifications.GetSpecificationSummaryById(specificationId) .Returns(new ApiResponse <ApiSpecificationSummary>(HttpStatusCode.OK, specificationSummary)); }
public async Task <IActionResult> GetEffectivePermissionsForUser(string userId, string specificationId) { if (string.IsNullOrWhiteSpace(userId)) { return(new BadRequestObjectResult($"{nameof(userId)} is empty or null")); } if (string.IsNullOrWhiteSpace(specificationId)) { return(new BadRequestObjectResult($"{nameof(specificationId)} is empty or null")); } EffectiveSpecificationPermission cachedPermissions = await _cacheProviderPolicy.ExecuteAsync(() => _cacheProvider.GetHashValue <EffectiveSpecificationPermission>($"{CacheKeys.EffectivePermissions}:{userId}", specificationId)); if (cachedPermissions != null) { return(new OkObjectResult(cachedPermissions)); } else { ApiResponse <SpecModel.SpecificationSummary> specificationApiResponse = await _specificationsApiClientPolicy.ExecuteAsync(() => _specificationsApiClient.GetSpecificationSummaryById(specificationId)); if (!specificationApiResponse.StatusCode.IsSuccess() || specificationApiResponse.Content == null) { return(new PreconditionFailedResult("Specification not found")); } SpecModel.SpecificationSummary specification = specificationApiResponse.Content; List <FundingStreamPermission> permissionsForUser = new List <FundingStreamPermission>(); foreach (Reference fundingStream in specification.FundingStreams) { FundingStreamPermission permission = await _userRepositoryPolicy.ExecuteAsync(() => _userRepository.GetFundingStreamPermission(userId, fundingStream.Id)); if (permission != null) { permissionsForUser.Add(permission); } else { // Add permission for this funding stream with no permissions - used further down to calculate permissions (required for pessimistic permissions) permissionsForUser.Add(new FundingStreamPermission { UserId = userId, FundingStreamId = fundingStream.Id, CanApproveFunding = false, CanChooseFunding = false, CanCreateSpecification = false, CanEditCalculations = false, CanEditSpecification = false, CanMapDatasets = false, CanReleaseFunding = false, CanAdministerFundingStream = false, CanApproveSpecification = false, CanCreateQaTests = false, CanDeleteCalculations = false, CanDeleteSpecification = false, CanDeleteQaTests = false, CanEditQaTests = false, CanRefreshFunding = false, CanCreateTemplates = false, CanEditTemplates = false, CanDeleteTemplates = false, CanApproveTemplates = false, CanCreateProfilePattern = false, CanEditProfilePattern = false, CanDeleteProfilePattern = false, CanAssignProfilePattern = false, CanApplyCustomProfilePattern = false, CanApproveCalculations = false, CanApproveAnyCalculations = false, CanApproveAllCalculations = false }); } } EffectiveSpecificationPermission specificationPermissions = GeneratePermissions(permissionsForUser, specificationId, userId); string userPermissionHashKey = $"{CacheKeys.EffectivePermissions}:{userId}"; // Does the hash set for this user already exist - used to determine the timeout for the hash set below bool existingHashSetExists = await _cacheProviderPolicy.ExecuteAsync(() => _cacheProvider.HashSetExists(userPermissionHashKey)); // Cache effective permissions for the specification / user await _cacheProviderPolicy.ExecuteAsync(() => _cacheProvider.SetHashValue(userPermissionHashKey, specificationId, specificationPermissions)); // If the hash set does not exist, then set an expiry for the whole hash set. This stops the users permissions being stored indefinitely if (!existingHashSetExists) { await _cacheProviderPolicy.ExecuteAsync(() => _cacheProvider.SetHashExpiry(userPermissionHashKey, DateTime.UtcNow.AddHours(12))); } return(new OkObjectResult(specificationPermissions)); } }
public async Task <IActionResult> SaveVersion(CreateNewTestScenarioVersion scenarioVersion, Reference user, string correlationId) { if (scenarioVersion == null) { _logger.Error("A null scenario version was provided"); return(new BadRequestObjectResult("Null or empty calculation Id provided")); } BadRequestObjectResult validationResult = (await _createNewTestScenarioVersionValidator.ValidateAsync(scenarioVersion)).PopulateModelState(); if (validationResult != null) { return(validationResult); } TestScenario testScenario = null; if (!string.IsNullOrEmpty(scenarioVersion.Id)) { testScenario = await _scenariosRepository.GetTestScenarioById(scenarioVersion.Id); } bool saveAsVersion = true; Common.ApiClient.Models.ApiResponse <SpecModel.SpecificationSummary> specificationApiResponse = await _specificationsApiClientPolicy.ExecuteAsync(() => _specificationsApiClient.GetSpecificationSummaryById(scenarioVersion.SpecificationId)); if (!specificationApiResponse.StatusCode.IsSuccess() || specificationApiResponse.Content == null) { _logger.Error($"Unable to find a specification for specification id : {scenarioVersion.SpecificationId}"); return(new StatusCodeResult(412)); } SpecModel.SpecificationSummary specification = specificationApiResponse.Content; if (testScenario == null) { string Id = Guid.NewGuid().ToString(); testScenario = new TestScenario { Id = Id, SpecificationId = specification.Id, Name = scenarioVersion.Name, Current = new TestScenarioVersion { Date = DateTimeOffset.Now.ToLocalTime(), TestScenarioId = Id, PublishStatus = PublishStatus.Draft, Version = 1, Author = user, Gherkin = scenarioVersion.Scenario, Description = scenarioVersion.Description, FundingPeriodId = specification.FundingPeriod.Id, FundingStreamIds = specification.FundingStreams.Select(s => s.Id).ToArraySafe(), } }; } else { testScenario.Name = scenarioVersion.Name; saveAsVersion = !string.Equals(scenarioVersion.Scenario, testScenario.Current.Gherkin) || scenarioVersion.Description != testScenario.Current.Description; TestScenarioVersion newVersion = testScenario.Current.Clone() as TestScenarioVersion; if (saveAsVersion == true) { newVersion.Author = user; newVersion.Gherkin = scenarioVersion.Scenario; newVersion.Description = scenarioVersion.Description; newVersion.FundingStreamIds = specification.FundingStreams.Select(s => s.Id).ToArraySafe(); newVersion.FundingPeriodId = specification.FundingPeriod.Id; newVersion = await _versionRepository.CreateVersion(newVersion, testScenario.Current); testScenario.Current = newVersion; } } HttpStatusCode statusCode = await _scenariosRepository.SaveTestScenario(testScenario); if (!statusCode.IsSuccess()) { _logger.Error($"Failed to save test scenario with status code: {statusCode}"); return(new StatusCodeResult((int)statusCode)); } await _versionRepository.SaveVersion(testScenario.Current); ScenarioIndex scenarioIndex = CreateScenarioIndexFromScenario(testScenario, specification); await _searchRepository.Index(new List <ScenarioIndex> { scenarioIndex }); await _cacheProvider.RemoveAsync <List <TestScenario> >($"{CacheKeys.TestScenarios}{testScenario.SpecificationId}"); await _cacheProvider.RemoveAsync <GherkinParseResult>($"{CacheKeys.GherkinParseResult}{testScenario.Id}"); IEnumerable <Common.ApiClient.Calcs.Models.Calculation> calculations = await _calcsRepositoryPolicy.ExecuteAsync(() => _calcsRepository.GetCurrentCalculationsBySpecificationId(specification.Id)); if (calculations.IsNullOrEmpty()) { _logger.Information($"No calculations found to test for specification id: '{specification.Id}'"); } else { try { JobsModels.Trigger trigger = new JobsModels.Trigger { EntityId = testScenario.Id, EntityType = nameof(TestScenario), Message = $"Saving test scenario: '{testScenario.Id}'" }; bool generateCalculationAggregations = SourceCodeHelpers.HasCalculationAggregateFunctionParameters(calculations.Select(m => m.SourceCode)); JobsModels.Job job = await SendInstructAllocationsToJobService(specification.Id, user, trigger, correlationId, generateCalculationAggregations); _logger.Information($"New job of type '{job.JobDefinitionId}' created with id: '{job.Id}'"); } catch (Exception ex) { _logger.Error(ex, $"Failed to create job of type '{JobConstants.DefinitionNames.CreateInstructAllocationJob}' on specification '{specification.Id}'"); return(new InternalServerErrorResult($"An error occurred attempting to execute calculations prior to running tests on specification '{specification.Id}'")); } } CurrentTestScenario testScenarioResult = await _scenariosRepository.GetCurrentTestScenarioById(testScenario.Id); return(new OkObjectResult(testScenarioResult)); }
public async Task PreviewCalculationResult_GivenCachedAggregateValuesExist_CalculateProviderResultsCallReceived() { IAllocationModel allocationModel = Substitute.For <IAllocationModel>(); _calculationEngine .GenerateAllocationModel(Arg.Any <Assembly>()) .Returns(allocationModel); ProviderVersionSearchResult providerVersionSearchResult = new ProviderVersionSearchResult { UKPRN = providerId }; IEnumerable <string> dataDefinitionRelationshipIds = new List <string>(); SpecificationSummary specificationSummary = new SpecificationSummary { DataDefinitionRelationshipIds = dataDefinitionRelationshipIds, ProviderVersionId = providerVersionId }; _specificationsApiClient .GetSpecificationSummaryById(Arg.Is(specificationId)) .Returns(new ApiResponse <SpecificationSummary>(HttpStatusCode.OK, specificationSummary)); _providersApiClient .GetProviderByIdFromProviderVersion(Arg.Is(providerVersionId), Arg.Is(providerId)) .Returns(new ApiResponse <ProviderVersionSearchResult>(HttpStatusCode.OK, providerVersionSearchResult)); CalculationSummaryModel previewCalculationSummaryModel = new CalculationSummaryModel(); IEnumerable <CalculationSummaryModel> calculationSummaryModels = new List <CalculationSummaryModel> { new CalculationSummaryModel(), new CalculationSummaryModel() }; List <CalculationSummaryModel> expectedCalculationSummaryModels = calculationSummaryModels.ToList(); expectedCalculationSummaryModels.Add(previewCalculationSummaryModel); _calculationsRepository .GetCalculationSummariesForSpecification(Arg.Is(specificationId)) .Returns(calculationSummaryModels); Dictionary <string, ProviderSourceDataset> sourceDatasets = new Dictionary <string, ProviderSourceDataset>(); Dictionary <string, Dictionary <string, ProviderSourceDataset> > providerSourceDatasets = new Dictionary <string, Dictionary <string, ProviderSourceDataset> > { { providerId, sourceDatasets } }; _providerSourceDatasetsRepository .GetProviderSourceDatasetsByProviderIdsAndRelationshipIds( Arg.Is(specificationId), Arg.Is <IEnumerable <string> >(_ => _ != null && _.Count() == 1 && _.FirstOrDefault() == providerId), Arg.Is <IEnumerable <string> >(_ => _ != null && _.SequenceEqual(dataDefinitionRelationshipIds))) .Returns(providerSourceDatasets); IEnumerable <CalculationAggregation> calculationAggregations = new List <CalculationAggregation>(); _calculationAggregationService .BuildAggregations(Arg.Is <BuildAggregationRequest>(_ => _ != null && _.SpecificationId == specificationId)) .Returns(calculationAggregations); PreviewCalculationRequest previewCalculationRequest = new PreviewCalculationRequest { AssemblyContent = MockData.GetMockAssembly(), PreviewCalculationSummaryModel = previewCalculationSummaryModel }; IActionResult actionResult = await _calculationEnginePreviewService.PreviewCalculationResult(specificationId, providerId, previewCalculationRequest); _calculationEngine .Received(1) .CalculateProviderResults( Arg.Is(allocationModel), specificationId, Arg.Is <IEnumerable <CalculationSummaryModel> >(_ => _.SequenceEqual(expectedCalculationSummaryModels)), Arg.Is <ProviderSummary>(_ => _.UKPRN == providerId), Arg.Is <Dictionary <string, ProviderSourceDataset> >(_ => _.SequenceEqual(sourceDatasets)), Arg.Is <IEnumerable <CalculationAggregation> >(_ => _.SequenceEqual(calculationAggregations))); }
public override async Task Process(Message message) { Guard.ArgumentNotNull(message, nameof(message)); string specificationId = UserPropertyFrom(message, "specification-id"); string fundingStreamId = UserPropertyFrom(message, "fundingstream-id"); string templateVersion = UserPropertyFrom(message, "template-version"); string correlationId = message.GetCorrelationId(); Reference author = message.GetUserDetails(); TemplateMapping templateMapping = await _calculationsRepositoryPolicy.ExecuteAsync( () => _calculationsRepository.GetTemplateMapping(specificationId, fundingStreamId)); if (templateMapping == null) { LogAndThrowException( $"Did not locate Template Mapping for funding stream id {fundingStreamId} and specification id {specificationId}"); } ApiResponse <SpecificationSummary> specificationApiResponse = await _specificationsApiClientPolicy.ExecuteAsync(() => _specificationsApiClient.GetSpecificationSummaryById(specificationId)); if (!specificationApiResponse.StatusCode.IsSuccess() || specificationApiResponse.Content == null) { LogAndThrowException( $"Did not locate specification : {specificationId}"); } SpecificationSummary specificationSummary = specificationApiResponse.Content; ApiResponse <TemplateMetadataContents> templateContentsResponse = await _policiesResiliencePolicy.ExecuteAsync( () => _policiesApiClient.GetFundingTemplateContents(fundingStreamId, specificationSummary.FundingPeriod.Id, templateVersion)); TemplateMetadataContents templateMetadataContents = templateContentsResponse?.Content; if (templateMetadataContents == null) { LogAndThrowException( $"Did not locate Template Metadata Contents for funding stream id {fundingStreamId}, funding period id {specificationSummary.FundingPeriod.Id} and template version {templateVersion}"); } TemplateMappingItem[] mappingsWithoutCalculations = templateMapping.TemplateMappingItems.Where(_ => _.CalculationId.IsNullOrWhitespace()) .ToArray(); FundingLine[] flattenedFundingLines = templateMetadataContents.RootFundingLines.Flatten(_ => _.FundingLines).ToArray(); IDictionary <uint, Calculation> uniqueTemplateCalculations = flattenedFundingLines .SelectMany(_ => _.Calculations.Flatten(cal => cal.Calculations)) .GroupBy(x => x.TemplateCalculationId) .Select(x => x.FirstOrDefault()) .ToDictionary(_ => _.TemplateCalculationId); TemplateMappingItem[] mappingsWithCalculations = templateMapping.TemplateMappingItems.Where(_ => !_.CalculationId.IsNullOrWhitespace()) .ToArray(); int startingItemCount = 1; await NotifyProgress(startingItemCount); await EnsureAllExistingCalculationsModified(mappingsWithCalculations, specificationSummary, correlationId, author, uniqueTemplateCalculations, startingItemCount); TemplateMappingItem[] newMappingsWithCalculations = await EnsureAllRequiredCalculationsExist(mappingsWithoutCalculations, mappingsWithCalculations, fundingStreamId, specificationSummary, author, correlationId, startingItemCount += mappingsWithCalculations.Length, uniqueTemplateCalculations); // refresh template mapping await RefreshTemplateMapping(specificationId, fundingStreamId, templateMapping); await InitiateCalculationRun(specificationId, author, correlationId); await QueueUpdateCodeContextJob(specificationId); }
public CalculationCreateModelValidator( ICalculationsRepository calculationRepository, IPreviewService previewService, ISpecificationsApiClient specificationsApiClient, ICalcsResiliencePolicies calcsResiliencePolicies) { Guard.ArgumentNotNull(calculationRepository, nameof(calculationRepository)); Guard.ArgumentNotNull(previewService, nameof(previewService)); Guard.ArgumentNotNull(specificationsApiClient, nameof(specificationsApiClient)); Guard.ArgumentNotNull(calcsResiliencePolicies, nameof(calcsResiliencePolicies)); Guard.ArgumentNotNull(calcsResiliencePolicies?.SpecificationsApiClient, nameof(calcsResiliencePolicies.SpecificationsApiClient)); _calculationRepository = calculationRepository; _previewService = previewService; _specificationsApiClient = specificationsApiClient; _specificationsApiClientPolicy = calcsResiliencePolicies.SpecificationsApiClient; CascadeMode = CascadeMode.StopOnFirstFailure; RuleFor(model => model.SpecificationId) .NotEmpty() .NotNull() .WithMessage("Null or empty specification id provided."); RuleFor(model => model.ValueType) .NotNull() .WithMessage("Null value type was provided."); RuleFor(model => model.Name) .Custom((name, context) => { CalculationCreateModel calculationCreateModel = context.ParentContext.InstanceToValidate as CalculationCreateModel; if (string.IsNullOrWhiteSpace(calculationCreateModel.Name)) { context.AddFailure("Null or empty calculation name provided."); } else { if (!string.IsNullOrWhiteSpace(calculationCreateModel.SpecificationId)) { Calculation calculation = _calculationRepository.GetCalculationsBySpecificationIdAndCalculationName(calculationCreateModel.SpecificationId, calculationCreateModel.Name).Result; if (calculation != null) { context.AddFailure($"A calculation already exists with the name: '{calculationCreateModel.Name}' for this specification"); } } } }); RuleFor(model => model.SourceCode) .Custom((sc, context) => { CalculationCreateModel calculationCreateModel = context.ParentContext.InstanceToValidate as CalculationCreateModel; if (string.IsNullOrWhiteSpace(calculationCreateModel.SourceCode)) { context.AddFailure("Null or empty source code provided."); } else { if (calculationCreateModel.CalculationType == CalculationType.Additional) { PreviewRequest previewRequest = new PreviewRequest { SpecificationId = calculationCreateModel.SpecificationId, CalculationId = calculationCreateModel.Id, Name = calculationCreateModel.Name, SourceCode = calculationCreateModel.SourceCode }; IActionResult result = _previewService.Compile(previewRequest).Result; OkObjectResult okObjectResult = result as OkObjectResult; PreviewResponse response = okObjectResult.Value as PreviewResponse; if (response != null) { if (!response.CompilerOutput.CompilerMessages.IsNullOrEmpty()) { context.AddFailure("There are errors in the source code provided"); } } } } }); RuleFor(model => model.FundingStreamId) .Custom((fs, context) => { CalculationCreateModel calculationCreateModel = context.ParentContext.InstanceToValidate as CalculationCreateModel; //only validate funding stream id for template calcs var isTemplateCalculation = calculationCreateModel.CalculationType == CalculationType.Template; if (isTemplateCalculation && string.IsNullOrWhiteSpace(calculationCreateModel.FundingStreamId)) { context.AddFailure("Null or empty funding stream id provided."); } else { ApiResponse <SpecModel.SpecificationSummary> specificationApiResponse = _specificationsApiClientPolicy.ExecuteAsync(() => _specificationsApiClient.GetSpecificationSummaryById(calculationCreateModel.SpecificationId)).GetAwaiter().GetResult(); if (specificationApiResponse == null || !specificationApiResponse.StatusCode.IsSuccess() || specificationApiResponse.Content == null) { context.AddFailure("Failed to find specification for provided specification id."); } else { SpecModel.SpecificationSummary specificationSummary = specificationApiResponse.Content; //I don't want to have to fetch the spec summary again outside of this method to get the name and funding stream so we set them on input model here calculationCreateModel.SpecificationName = specificationSummary.Name; //only validate funding stream ids for template calcs if (!isTemplateCalculation) { return; } Reference fundingStream = specificationSummary.FundingStreams.FirstOrDefault(m => m.Id == calculationCreateModel.FundingStreamId); if (fundingStream == null) { context.AddFailure("The funding stream id provided is not associated with the provided specification."); } else { calculationCreateModel.FundingStreamName = fundingStream.Name; } } } }); }