public async Task IsCalculationNameValid_WhenCalculationDoesNotExist_ThenReturnsOkResult() { // Arrange string specificationId = "spec1"; ISpecificationRepository specificationRepository = CreateSpecificationRepository(); specificationRepository .GetSpecificationSummaryById(Arg.Is(specificationId)) .Returns(new SpecificationSummary { Id = specificationId }); ICalculationsRepository calculationsRepository = CreateCalculationsRepository(); calculationsRepository .GetCalculationsBySpecificationId(Arg.Is(specificationId)) .Returns(new List <Models.Calcs.Calculation>()); CalculationService service = CreateCalculationService(specificationRepository: specificationRepository, calculationsRepository: calculationsRepository); // Act IActionResult result = await service.IsCalculationNameValid(specificationId, "calc1", null); // Assert result .Should() .BeOfType <OkResult>(); }
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 GetEffectivePermissionsForUser_WhenNotFoundInCacheButSpecificationNotFound_ThenPreconditionFailedResultReturned() { // Arrange ICacheProvider cacheProvider = CreateCacheProvider(); EffectiveSpecificationPermission cachedPermission = null; cacheProvider .GetHashValue <EffectiveSpecificationPermission>(Arg.Is($"{CacheKeys.EffectivePermissions}:{UserId}"), Arg.Is(SpecificationId)) .Returns(cachedPermission); ISpecificationRepository specificationRepository = CreateSpecificationRepository(); SpecificationSummary specificationSummary = null; specificationRepository .GetSpecificationSummaryById(Arg.Is(SpecificationId)) .Returns(specificationSummary); FundingStreamPermissionService service = CreateService( specificationRepository: specificationRepository, cacheProvider: cacheProvider); // Act IActionResult result = await service.GetEffectivePermissionsForUser(UserId, SpecificationId, null); // 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 async Task IsCalculationNameValid_WhenSameCalculation_ThenReturnsOkResult() { // Arrange string specificationId = "spec1"; string calcName = "calc1"; string calcSpecId = "calc-spec-id-1"; ISpecificationRepository specificationRepository = CreateSpecificationRepository(); specificationRepository .GetSpecificationSummaryById(Arg.Is(specificationId)) .Returns(new SpecificationSummary { Id = specificationId }); List <Models.Calcs.Calculation> existingCalcs = new List <Models.Calcs.Calculation> { new Models.Calcs.Calculation { Name = calcName, SourceCodeName = calcName, Id = "calc-1", CalculationSpecification = new Common.Models.Reference { Id = calcSpecId } } }; ICalculationsRepository calculationsRepository = CreateCalculationsRepository(); calculationsRepository .GetCalculationsBySpecificationId(Arg.Is(specificationId)) .Returns(existingCalcs); CalculationService service = CreateCalculationService(specificationRepository: specificationRepository, calculationsRepository: calculationsRepository); // Act IActionResult result = await service.IsCalculationNameValid(specificationId, calcName, calcSpecId); // Assert result .Should() .BeOfType <OkResult>(); }
public async Task IsCalculationNameValid_WhenSpecificationDoesNotExist_ThenReturnsNotFoundResult() { // Arrange string specificationId = "spec1"; ISpecificationRepository specificationRepository = CreateSpecificationRepository(); specificationRepository .GetSpecificationSummaryById(Arg.Is(specificationId)) .Returns((SpecificationSummary)null); CalculationService service = CreateCalculationService(specificationRepository: specificationRepository); // Act IActionResult result = await service.IsCalculationNameValid(specificationId, "calc1", null); // Assert result .Should() .BeOfType <NotFoundResult>(); }
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 EditCalculationStatus_GivenCalculationIsApprovedButNewStatusIsDraft_UpdatesSearchReturnsOK() { //Arrange EditStatusModel CalculationEditStatusModel = new EditStatusModel { PublishStatus = PublishStatus.Draft }; 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; ICalculationsRepository CalculationsRepository = CreateCalculationsRepository(); CalculationsRepository .GetCalculationById(Arg.Is(CalculationId)) .Returns(calculation); CalculationsRepository .UpdateCalculation(Arg.Any <Calculation>()) .Returns(HttpStatusCode.OK); Models.Specs.SpecificationSummary specificationSummary = new Models.Specs.SpecificationSummary(); ISpecificationRepository specificationRepository = CreateSpecificationRepository(); specificationRepository .GetSpecificationSummaryById(Arg.Is(calculation.SpecificationId)) .Returns(specificationSummary); ISearchRepository <CalculationIndex> searchRepository = CreateSearchRepository(); CalculationService service = CreateCalculationService( logger: logger, calculationsRepository: CalculationsRepository, searchRepository: searchRepository, specificationRepository: specificationRepository); //Act IActionResult result = await service.UpdateCalculationStatus(request); //Arrange result .Should() .BeOfType <BadRequestObjectResult>() .Which .Value .Should() .Be("Publish status can't be changed to Draft from Updated or Approved"); calculation .Current .PublishStatus .Should() .Be(PublishStatus.Approved); await searchRepository .Received(0) .Index(Arg.Any <IEnumerable <CalculationIndex> >()); }
public async Task EditCalculationStatus_GivenNewStatusButUpdatingDbReturnsBadRequest_ReturnsStatusCode400() { //Arrange EditStatusModel CalculationEditStatusModel = new EditStatusModel { PublishStatus = PublishStatus.Approved }; 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(); ICalculationsRepository CalculationsRepository = CreateCalculationsRepository(); CalculationsRepository .GetCalculationById(Arg.Is(CalculationId)) .Returns(calculation); CalculationsRepository .UpdateCalculation(Arg.Any <Calculation>()) .Returns(HttpStatusCode.BadRequest); Models.Specs.SpecificationSummary specificationSummary = new Models.Specs.SpecificationSummary(); ISpecificationRepository specificationRepository = CreateSpecificationRepository(); specificationRepository .GetSpecificationSummaryById(Arg.Is(calculation.SpecificationId)) .Returns(specificationSummary); CalculationService service = CreateCalculationService( logger: logger, calculationsRepository: CalculationsRepository, specificationRepository: specificationRepository); //Act IActionResult result = await service.UpdateCalculationStatus(request); //Arrange result .Should() .BeAssignableTo <StatusCodeResult>() .Which .StatusCode .Should() .Be(400); }
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" )); }
public async Task GetEffectivePermissionsForUser_WhenNotFoundInCacheResultsAreQueriedWithMultipleFundingStreamAndNoPermissionsAreInRepository_ThenOkResultReturnedWithNoPermissions() { // Arrange IUserRepository userRepository = CreateUserRepository(); ISpecificationRepository specificationRepository = CreateSpecificationRepository(); ICacheProvider cacheProvider = CreateCacheProvider(); IMapper mapper = CreateMappingConfiguration(); EffectiveSpecificationPermission cachedPermission = null; cacheProvider .GetHashValue <EffectiveSpecificationPermission>(Arg.Is($"{CacheKeys.EffectivePermissions}:{UserId}"), Arg.Is(SpecificationId)) .Returns(cachedPermission); SpecificationSummary specificationSummary = new SpecificationSummary() { Id = SpecificationId, FundingStreams = new List <Reference>() { new Reference("fs1", "Funding Stream 1"), new Reference("fs2", "Funding Stream 2") } }; specificationRepository .GetSpecificationSummaryById(Arg.Is(SpecificationId)) .Returns(specificationSummary); FundingStreamPermission fs1Permission = null; userRepository .GetFundingStreamPermission(Arg.Is(UserId), Arg.Is("fs1")) .Returns(fs1Permission); FundingStreamPermission fs2Permission = null; userRepository .GetFundingStreamPermission(Arg.Is(UserId), Arg.Is("fs2")) .Returns(fs2Permission); FundingStreamPermissionService service = CreateService(userRepository, specificationRepository, cacheProvider: cacheProvider, mapper: mapper); // Act IActionResult result = await service.GetEffectivePermissionsForUser(UserId, SpecificationId, null); // Assert result .Should() .BeOfType <OkObjectResult>() .Which .Value .Should() .BeEquivalentTo(new EffectiveSpecificationPermission() { UserId = UserId, SpecificationId = SpecificationId, CanApproveFunding = false, CanCreateSpecification = false, CanMapDatasets = false, CanChooseFunding = false, CanEditCalculations = false, CanEditSpecification = false, CanPublishFunding = false, CanAdministerFundingStream = false, CanApproveSpecification = false, CanCreateQaTests = false, CanEditQaTests = false, CanRefreshFunding = false, }); await cacheProvider .Received(1) .SetHashValue( Arg.Is($"{CacheKeys.EffectivePermissions}:{UserId}"), Arg.Is(SpecificationId), Arg.Is <EffectiveSpecificationPermission>(p => !p.CanApproveFunding && !p.CanChooseFunding && !p.CanCreateSpecification && !p.CanEditCalculations && !p.CanEditSpecification && !p.CanMapDatasets && !p.CanPublishFunding && !p.CanAdministerFundingStream && !p.CanApproveSpecification && !p.CanCreateQaTests && !p.CanEditQaTests && !p.CanRefreshFunding && p.SpecificationId == SpecificationId && p.UserId == UserId )); }
public async Task RunTests(Message message) { Stopwatch runTestsStopWatch = Stopwatch.StartNew(); string specificationId = message.UserProperties["specificationId"].ToString(); if (string.IsNullOrWhiteSpace(specificationId)) { _logger.Error("Null or empty specification id provided"); return; } BuildProject buildProject = await _builProjectsRepositoryPolicy.ExecuteAsync(() => _buildProjectRepository.GetBuildProjectBySpecificationId(specificationId)); if (buildProject == null) { _logger.Error("A null build project was provided to UpdateAllocations"); throw new ArgumentNullException(nameof(buildProject)); } string cacheKey = message.UserProperties["providerResultsCacheKey"].ToString(); if (string.IsNullOrWhiteSpace(cacheKey)) { _logger.Error("Null or empty cache key provided"); return; } Stopwatch providerResultsQueryStopwatch = Stopwatch.StartNew(); IEnumerable <ProviderResult> providerResults = await _cacheProviderPolicy.ExecuteAsync(() => _cacheProvider.GetAsync <List <ProviderResult> >($"{CacheKeys.ProviderResultBatch}{cacheKey}")); providerResultsQueryStopwatch.Stop(); if (providerResults.IsNullOrEmpty()) { _logger.Error($"No provider results found in cache for key: {cacheKey}"); return; } await _cacheProviderPolicy.ExecuteAsync(() => _cacheProvider.RemoveAsync <List <ProviderResult> >($"{CacheKeys.ProviderResultBatch}{cacheKey}")); Stopwatch testScenariosStopwatch = Stopwatch.StartNew(); IEnumerable <TestScenario> testScenarios = await _scenariosRepositoryPolicy.ExecuteAsync(() => _scenariosRepository.GetTestScenariosBySpecificationId(specificationId)); testScenariosStopwatch.Stop(); if (testScenarios.IsNullOrEmpty()) { _logger.Warning($"No test scenarios found for specification id: {specificationId}"); return; } Stopwatch specificationLookupStopwatch = Stopwatch.StartNew(); SpecificationSummary specification = await _specificationRepositoryPolicy.ExecuteAsync(() => _specificationRepository.GetSpecificationSummaryById(specificationId)); specificationLookupStopwatch.Stop(); if (specification == null) { _logger.Error($"No specification found for specification id: {specificationId}"); return; } IEnumerable <string> providerIds = providerResults.Select(m => m.Provider.Id); Stopwatch providerSourceDatasetsStopwatch = Stopwatch.StartNew(); IEnumerable <ProviderSourceDataset> sourceDatasets = await _providerSourceDatasetsRepositoryPolicy.ExecuteAsync(() => _providerSourceDatasetsRepository.GetProviderSourceDatasetsByProviderIdsAndSpecificationId(providerIds, specificationId)); providerSourceDatasetsStopwatch.Stop(); if (sourceDatasets.IsNullOrEmpty()) { _logger.Error($"No source datasets found for specification id: {specificationId}"); return; } byte[] assembly = await _calculationsRepository.GetAssemblyBySpecificationId(specificationId); if (assembly.IsNullOrEmpty()) { _logger.Error($"No assemblyfor specification id: {specificationId}"); return; } buildProject.Build.Assembly = assembly; Stopwatch existingTestResultsStopwatch = Stopwatch.StartNew(); IEnumerable <TestScenarioResult> testScenarioResults = await _testResultsRepositoryPolicy.ExecuteAsync(() => _testResultsRepository.GetCurrentTestResults(providerIds, specificationId)); existingTestResultsStopwatch.Stop(); Stopwatch runTestsStopwatch = Stopwatch.StartNew(); IEnumerable <TestScenarioResult> results = await _testEngine.RunTests(testScenarios, providerResults, sourceDatasets, testScenarioResults.ToList(), specification, buildProject); runTestsStopwatch.Stop(); Stopwatch saveResultsStopwatch = new Stopwatch(); if (results.Any()) { saveResultsStopwatch.Start(); HttpStatusCode status = await _testResultsService.SaveTestProviderResults(results, providerResults); saveResultsStopwatch.Stop(); if (!status.IsSuccess()) { _logger.Error($"Failed to save test results with status code: {status.ToString()}"); } } runTestsStopWatch.Stop(); IDictionary <string, double> metrics = new Dictionary <string, double>() { { "tests-run-totalMs", runTestsStopWatch.ElapsedMilliseconds }, { "tests-run-testScenarioQueryMs", testScenariosStopwatch.ElapsedMilliseconds }, { "tests-run-numberOfTestScenarios", testScenarios.Count() }, { "tests-run-providersResultsQueryMs", providerResultsQueryStopwatch.ElapsedMilliseconds }, { "tests-run-totalProvidersProcessed", providerIds.Count() }, { "tests-run-specificationQueryMs", specificationLookupStopwatch.ElapsedMilliseconds }, { "tests-run-providerSourceDatasetsQueryMs", providerSourceDatasetsStopwatch.ElapsedMilliseconds }, { "tests-run-existingTestsQueryMs", existingTestResultsStopwatch.ElapsedMilliseconds }, { "tests-run-existingTestScenarioResultsTotal", testScenarioResults.Count() }, { "tests-run-runTestsMs", runTestsStopwatch.ElapsedMilliseconds }, }; if (results.Any()) { metrics.Add("tests-run-saveTestResultsMs", saveResultsStopwatch.ElapsedMilliseconds); metrics.Add("tests-run-numberOfSavedResults", results.Count()); } _telemetry.TrackEvent("RunTests", new Dictionary <string, string>() { { "specificationId", specificationId }, { "buildProjectId", buildProject.Id }, { "cacheKey", cacheKey }, }, metrics ); }
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 async Task <IActionResult> GetEffectivePermissionsForUser(string userId, string specificationId, HttpRequest request) { 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 { SpecificationSummary specification = await _specificationsRepositoryPolicy.ExecuteAsync(() => _specificationsRepository.GetSpecificationSummaryById(specificationId)); if (specification == null) { return(new PreconditionFailedResult("Specification not found")); } 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, CanPublishFunding = false, CanAdministerFundingStream = false, CanApproveSpecification = false, CanCreateQaTests = false, CanDeleteCalculations = false, CanDeleteSpecification = false, CanDeleteQaTests = false, CanEditQaTests = false, CanRefreshFunding = 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)); } }