public async Task UpdateTestResultsForSpecification_GivenNoChangesDetected_LogsAndReturns() { //Arrange const string specificationId = "spec-id"; SpecificationVersionComparisonModel specificationVersionComparison = new SpecificationVersionComparisonModel() { Id = specificationId, Current = new SpecificationVersion { Name = "any name" }, Previous = new SpecificationVersion { Name = "any name" } }; string json = JsonConvert.SerializeObject(specificationVersionComparison); Message message = new Message(Encoding.UTF8.GetBytes(json)); ILogger logger = CreateLogger(); TestResultsService service = CreateTestResultsService(logger: logger); //Act await service.Process(message); //Assert logger .Received(1) .Information(Arg.Is($"No changes detected")); }
public async Task UpdateCalculationsForSpecification_GivenModelHasNoChanges_LogsAndReturns() { //Arrange SpecificationVersionComparisonModel specificationVersionComparison = new SpecificationVersionComparisonModel() { Current = new SpecificationVersion { FundingPeriod = new Reference { Id = "fp1" } }, Previous = new SpecificationVersion { FundingPeriod = new Reference { Id = "fp1" } } }; string json = JsonConvert.SerializeObject(specificationVersionComparison); Message message = new Message(Encoding.UTF8.GetBytes(json)); ILogger logger = CreateLogger(); CalculationService service = CreateCalculationService(logger: logger); //Act await service.Run(message); //Assert logger .Received(1) .Information(Arg.Is("No changes detected")); }
public void GetMessageBodyStringFromMessage_GivenUnCompressedBody_ReturnsJson() { //Arrange SpecificationVersionComparisonModel specificationVersionComparison = new SpecificationVersionComparisonModel() { Id = "spec-1", Current = new Models.Messages.SpecificationVersion { FundingPeriod = new Reference { Id = "fp1" }, Name = "any-name" }, Previous = new Models.Messages.SpecificationVersion { FundingPeriod = new Reference { Id = "fp1" } } }; string json = JsonConvert.SerializeObject(specificationVersionComparison); byte[] messageBytes = Encoding.UTF8.GetBytes(json); Message message = new Message(messageBytes); //Act string result = MessageExtensions.GetMessageBodyStringFromMessage(message); //Assert result .Should() .BeEquivalentTo(json); }
public async Task UpdateTestResultsForSpecification(Message message) { SpecificationVersionComparisonModel specificationVersionComparison = message.GetPayloadAsInstanceOf <SpecificationVersionComparisonModel>(); if (specificationVersionComparison == null || specificationVersionComparison.Current == null) { _logger.Error("A null specificationVersionComparison was provided to UpdateTestResultsForSpecification"); throw new InvalidModelException(nameof(SpecificationVersionComparisonModel), new[] { "Null or invalid model provided" }); } if (specificationVersionComparison.Current.Name == specificationVersionComparison.Previous.Name) { _logger.Information("No changes detected"); return; } bool keepSearching = true; while (keepSearching) { SearchResults <TestScenarioResultIndex> results = await _searchRepository.Search("", new SearchParameters { Skip = 0, Top = 1000, SearchMode = SearchMode.Any, Filter = $"specificationId eq '{specificationVersionComparison.Id}' and specificationName ne '{specificationVersionComparison.Current.Name}'", QueryType = QueryType.Full }); if (results.Results.IsNullOrEmpty()) { keepSearching = false; } else { IEnumerable <TestScenarioResultIndex> indexResults = results.Results.Select(m => m.Result); if (results.Results.Count < 1000) { keepSearching = false; } foreach (TestScenarioResultIndex scenarioResultIndex in indexResults) { scenarioResultIndex.SpecificationName = specificationVersionComparison.Current.Name; } IEnumerable <IndexError> indexErrors = await _searchRepository.Index(indexResults); if (indexErrors.Any()) { _logger.Error($"The following errors occcurred while updating test results for specification id: {specificationVersionComparison.Id}, {string.Join(";", indexErrors.Select(m => m.ErrorMessage))}"); } } } }
public override async Task Process(Message message) { SpecificationVersionComparisonModel versionComparison = message.GetPayloadAsInstanceOf <SpecificationVersionComparisonModel>(); if (versionComparison == null || versionComparison.Current == null || versionComparison.Previous == null) { _logger.Error($"A null versionComparison was provided to users"); throw new InvalidModelException(nameof(SpecificationVersionComparisonModel), new[] { "Null or invalid model provided" }); } string specificationId = versionComparison.Id; if (string.IsNullOrWhiteSpace(specificationId)) { _logger.Error($"A null specificationId was provided to users in model"); throw new InvalidModelException(nameof(SpecificationVersionComparisonModel), new[] { "Null or invalid specificationId on model" }); } IEnumerable <string> previousFundingStreams = versionComparison.Previous.FundingStreams.OrderBy(c => c.Id).Select(f => f.Id); IEnumerable <string> currentFundingStreams = versionComparison.Current.FundingStreams.OrderBy(c => c.Id).Select(f => f.Id); if (!previousFundingStreams.SequenceEqual(currentFundingStreams)) { _logger.Information("Found changed funding streams for specification '{SpecificationId}' Previous: {PreviousFundingStreams} Current {CurrentFundingStreams}", specificationId, previousFundingStreams, currentFundingStreams); Dictionary <string, bool> userIds = new Dictionary <string, bool>(); IEnumerable <string> allFundingStreamIds = previousFundingStreams.Union(currentFundingStreams); foreach (string fundingStreamId in allFundingStreamIds) { IEnumerable <FundingStreamPermission> userPermissions = await _userRepositoryPolicy.ExecuteAsync(() => _userRepository.GetUsersWithFundingStreamPermissions(fundingStreamId)); foreach (FundingStreamPermission permission in userPermissions) { if (!userIds.ContainsKey(permission.UserId)) { userIds.Add(permission.UserId, true); } } } foreach (string userId in userIds.Keys) { _logger.Information("Clearing effective permissions for userId '{UserId}' for specification '{SpecificationId}'", userId, specificationId); await _cacheProviderPolicy.ExecuteAsync(() => _cacheProvider.DeleteHashKey <EffectiveSpecificationPermission>($"{CacheKeys.EffectivePermissions}:{userId}", specificationId)); } } else { _logger.Information("No funding streams have changed for specification '{SpecificationId}' which require effective permission clearing.", specificationId); } }
public async Task UpdateTestResultsForSpecification_GivenNoResultsFoundInSearch_DoesNotUpdateSearch() { //Arrange const string specificationId = "spec-id"; SpecificationVersionComparisonModel specificationVersionComparison = new SpecificationVersionComparisonModel() { Id = specificationId, Current = new SpecificationVersion { Name = "new name" }, Previous = new SpecificationVersion { Name = "any name" } }; string json = JsonConvert.SerializeObject(specificationVersionComparison); Message message = new Message(Encoding.UTF8.GetBytes(json)); ILogger logger = CreateLogger(); SearchResults <TestScenarioResultIndex> searchResult = new SearchResults <TestScenarioResultIndex>(); ISearchRepository <TestScenarioResultIndex> searchRepository = CreateSearchRespository(); searchRepository .Search(Arg.Is(""), Arg.Any <SearchParameters>()) .Returns(searchResult); TestResultsService service = CreateTestResultsService(logger: logger, searchRepository: searchRepository); //Act await service.Process(message); //Assert await searchRepository .Received(1) .Search(Arg.Is(""), Arg.Is <SearchParameters>( m => m.Skip == 0 && m.Top == 1000 && m.SearchMode == SearchMode.Any && m.Filter == $"specificationId eq '{specificationVersionComparison.Id}' and specificationName ne '{specificationVersionComparison.Current.Name}'" )); await searchRepository .DidNotReceive() .Index(Arg.Any <IEnumerable <TestScenarioResultIndex> >()); }
public async Task UpdateCalculationsForSpecification_GivenModelHasChangedFundingPeriodsButCalcculationsCouldNotBeFound_LogsAndReturns() { //Arrange const string specificationId = "spec-id"; SpecificationVersionComparisonModel specificationVersionComparison = new SpecificationVersionComparisonModel() { Id = specificationId, Current = new SpecificationVersion { FundingPeriod = new Reference { Id = "fp2" } }, Previous = new SpecificationVersion { FundingPeriod = new Reference { Id = "fp1" } } }; string json = JsonConvert.SerializeObject(specificationVersionComparison); Message message = new Message(Encoding.UTF8.GetBytes(json)); ILogger logger = CreateLogger(); ICalculationsRepository calculationsRepository = CreateCalculationsRepository(); calculationsRepository .GetCalculationsBySpecificationId(Arg.Is(specificationId)) .Returns((IEnumerable <Calculation>)null); CalculationService service = CreateCalculationService(calculationsRepository, logger); //Act await service.Run(message); //Assert logger .Received(1) .Information(Arg.Is($"No calculations found for specification id: {specificationId}")); }
public async Task UpdateCalculationsForSpecification_GivenModelHasChangedPolicyNameAndSourceCodeContainsCalculationAggregate_SavesChangesEnsuresGenerateAggregationsJobCreated() { // Arrange const string specificationId = "spec-id"; SpecificationVersionComparisonModel specificationVersionComparison = new SpecificationVersionComparisonModel() { Id = specificationId, Current = new SpecificationVersion { FundingPeriod = new Reference { Id = "fp1" }, Name = "any-name" }, Previous = new SpecificationVersion { FundingPeriod = new Reference { Id = "fp1" } } }; string json = JsonConvert.SerializeObject(specificationVersionComparison); Message message = new Message(Encoding.UTF8.GetBytes(json)); message.UserProperties.Add("user-id", UserId); message.UserProperties.Add("user-name", Username); ILogger logger = CreateLogger(); IEnumerable <Calculation> calcs = new[] { new Calculation { SpecificationId = "spec-id", Id = "any-id", Current = new CalculationVersion { Author = new Reference(UserId, Username), Date = DateTimeOffset.Now, PublishStatus = PublishStatus.Draft, SourceCode = "return Min(calc1)", Version = 1, Name = "any name", CalculationType = CalculationType.Template } } }; BuildProject buildProject = new BuildProject { Id = "build-project-1", SpecificationId = specificationId }; ICalculationsRepository calculationsRepository = CreateCalculationsRepository(); calculationsRepository .GetCalculationsBySpecificationId(Arg.Is(specificationId)) .Returns(calcs); IBuildProjectsService buildProjectsService = CreateBuildProjectsService(); buildProjectsService .GetBuildProjectForSpecificationId(Arg.Is(specificationId)) .Returns(buildProject); IJobManagement jobManagement = CreateJobManagement(); jobManagement .QueueJob(Arg.Any <JobCreateModel>()) .Returns(new Job { Id = "job-id-1", JobDefinitionId = JobConstants.DefinitionNames.CreateInstructGenerateAggregationsAllocationJob }); CalculationService service = CreateCalculationService( calculationsRepository, logger, buildProjectsService: buildProjectsService, jobManagement: jobManagement); // Act await service.Run(message); // Assert await jobManagement .Received(1) .QueueJob(Arg.Is <JobCreateModel>( m => m.InvokerUserDisplayName == Username && m.InvokerUserId == UserId && m.JobDefinitionId == JobConstants.DefinitionNames.CreateInstructGenerateAggregationsAllocationJob && m.Properties["specification-id"] == specificationId && m.Trigger.EntityId == specificationId && m.Trigger.EntityType == "Specification" && m.Trigger.Message == $"Updating calculations for specification: '{specificationId}'" )); logger .Received(1) .Information(Arg.Is($"New job of type '{JobConstants.DefinitionNames.CreateInstructGenerateAggregationsAllocationJob}' created with id: 'job-id-1'")); }
public async Task UpdateCalculationsForSpecification_GivenModelHasChangedPolicyNameButCreatingJobReturnsNull_LogsError() { // Arrange const string specificationId = "spec-id"; SpecificationVersionComparisonModel specificationVersionComparison = new SpecificationVersionComparisonModel() { Id = specificationId, Current = new SpecificationVersion { FundingPeriod = new Reference { Id = "fp1" }, Name = "any-name" }, Previous = new SpecificationVersion { FundingPeriod = new Reference { Id = "fp1" } } }; string json = JsonConvert.SerializeObject(specificationVersionComparison); Message message = new Message(Encoding.UTF8.GetBytes(json)); message.UserProperties.Add("user-id", UserId); message.UserProperties.Add("user-name", Username); ILogger logger = CreateLogger(); IEnumerable <Calculation> calcs = new[] { new Calculation { SpecificationId = "spec-id", Id = "any-id", Current = new CalculationVersion { Author = new Reference(UserId, Username), Date = DateTimeOffset.Now, PublishStatus = PublishStatus.Draft, SourceCode = "source code", Version = 1, Name = "any name", CalculationType = CalculationType.Template } } }; BuildProject buildProject = new BuildProject { Id = "build-project-1", SpecificationId = specificationId }; ICalculationsRepository calculationsRepository = CreateCalculationsRepository(); calculationsRepository .GetCalculationsBySpecificationId(Arg.Is(specificationId)) .Returns(calcs); IBuildProjectsService buildProjectsService = CreateBuildProjectsService(); buildProjectsService .GetBuildProjectForSpecificationId(Arg.Is(specificationId)) .Returns(buildProject); IJobManagement jobManagement = CreateJobManagement(); jobManagement .QueueJob(Arg.Any <JobCreateModel>()) .Returns((Job)null); CalculationService service = CreateCalculationService( calculationsRepository, logger, buildProjectsService: buildProjectsService, jobManagement: jobManagement); // Act Func <Task> test = async() => await service.Run(message); // Assert test .Should() .ThrowExactly <RetriableException>() .Which .Message .Should() .Be($"Failed to create job: '{JobConstants.DefinitionNames.CreateInstructAllocationJob} for specification id '{specificationId}'"); 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 && m.Trigger.EntityId == specificationId && m.Trigger.EntityType == "Specification" && m.Trigger.Message == $"Updating calculations for specification: '{specificationId}'" )); logger .Received(1) .Error(Arg.Is($"Failed to create job: '{JobConstants.DefinitionNames.CreateInstructAllocationJob} for specification id '{specificationId}'")); }
public async Task UpdateTestResultsForSpecification_GivenResultsReturnedButIndexeingCausesErrors_LogsErrors() { //Arrange const string specificationId = "spec-id"; SpecificationVersionComparisonModel specificationVersionComparison = new SpecificationVersionComparisonModel() { Id = specificationId, Current = new SpecificationVersion { Name = "new name" }, Previous = new SpecificationVersion { Name = "any name" } }; string json = JsonConvert.SerializeObject(specificationVersionComparison); Message message = new Message(Encoding.UTF8.GetBytes(json)); ILogger logger = CreateLogger(); SearchResults <TestScenarioResultIndex> searchResult = new SearchResults <TestScenarioResultIndex> { Results = new List <CalculateFunding.Repositories.Common.Search.SearchResult <TestScenarioResultIndex> > { new CalculateFunding.Repositories.Common.Search.SearchResult <TestScenarioResultIndex> { Result = new TestScenarioResultIndex() }, new CalculateFunding.Repositories.Common.Search.SearchResult <TestScenarioResultIndex> { Result = new TestScenarioResultIndex() }, new CalculateFunding.Repositories.Common.Search.SearchResult <TestScenarioResultIndex> { Result = new TestScenarioResultIndex() } } }; IEnumerable <IndexError> indexErrors = new[] { new IndexError { ErrorMessage = "an error" } }; ISearchRepository <TestScenarioResultIndex> searchRepository = CreateSearchRespository(); searchRepository .Search(Arg.Is(""), Arg.Any <SearchParameters>()) .Returns(searchResult); searchRepository .Index(Arg.Any <IEnumerable <TestScenarioResultIndex> >()) .Returns(indexErrors); TestResultsService service = CreateTestResultsService(logger: logger, searchRepository: searchRepository); //Act await service.Process(message); //Assert await searchRepository .Received(1) .Search(Arg.Is(""), Arg.Is <SearchParameters>( m => m.Skip == 0 && m.Top == 1000 && m.SearchMode == SearchMode.Any && m.Filter == $"specificationId eq '{specificationVersionComparison.Id}' and specificationName ne '{specificationVersionComparison.Current.Name}'" )); await searchRepository .Received(1) .Index(Arg.Is <IEnumerable <TestScenarioResultIndex> >(m => m.Count() == 3)); logger .Received(1) .Error($"The following errors occcurred while updating test results for specification id: {specificationId}, an error"); }
public async Task OnSpecificationUpdate_WhenFundingStreamOnSpecificationHasNotChanged_ThenNoEffectiveUserPermissionsCleared() { // Arrange SpecificationVersionComparisonModel comparisonModel = new SpecificationVersionComparisonModel() { Current = new Models.Messages.SpecificationVersion() { SpecificationId = SpecificationId, FundingStreams = new List <Reference>() { new Reference("fs1", "Funding Stream 1"), } }, Previous = new Models.Messages.SpecificationVersion() { SpecificationId = SpecificationId, FundingStreams = new List <Reference>() { new Reference("fs1", "Funding Stream 1"), } }, Id = SpecificationId, }; string json = JsonConvert.SerializeObject(comparisonModel); Message message = new Message(Encoding.UTF8.GetBytes(json)); ICacheProvider cacheProvider = CreateCacheProvider(); IUserRepository userRepository = CreateUserRepository(); ILogger logger = CreateLogger(); FundingStreamPermissionService service = CreateService( userRepository: userRepository, cacheProvider: cacheProvider, logger: logger); // Act await service.Process(message); // Assert await userRepository .Received(0) .GetUsersWithFundingStreamPermissions(Arg.Any <string>()); await cacheProvider .Received(0) .DeleteHashKey <EffectiveSpecificationPermission>(Arg.Is <string>(c => c.StartsWith(CacheKeys.EffectivePermissions)), Arg.Is(SpecificationId)); logger .Received(1) .Information( Arg.Is("No funding streams have changed for specification '{SpecificationId}' which require effective permission clearing."), Arg.Is(SpecificationId) ); logger .Received(0) .Information( Arg.Is("Clearing effective permissions for userId '{UserId}' for specification '{SpecificationId}'"), Arg.Any <string>(), Arg.Is(SpecificationId)); }
public async Task OnSpecificationUpdate_WhenFundingStreamOnSpecificationIsAddedAndNoUserPermissionsExist_ThenNoEffectiveUserPermissionsCleared() { // Arrange SpecificationVersionComparisonModel comparisonModel = new SpecificationVersionComparisonModel() { Current = new Models.Messages.SpecificationVersion() { SpecificationId = SpecificationId, FundingStreams = new List <Reference>() { new Reference("fs1", "Funding Stream 1"), new Reference("fs2", "Funding Stream 2"), } }, Previous = new Models.Messages.SpecificationVersion() { SpecificationId = SpecificationId, FundingStreams = new List <Reference>() { new Reference("fs1", "Funding Stream 1"), } }, Id = SpecificationId, }; string json = JsonConvert.SerializeObject(comparisonModel); Message message = new Message(Encoding.UTF8.GetBytes(json)); ICacheProvider cacheProvider = CreateCacheProvider(); IUserRepository userRepository = CreateUserRepository(); List <FundingStreamPermission> fs1Permissions = new List <FundingStreamPermission>(); List <FundingStreamPermission> fs2Permissions = new List <FundingStreamPermission>(); userRepository .GetUsersWithFundingStreamPermissions(Arg.Is("fs1")) .Returns(fs1Permissions); userRepository .GetUsersWithFundingStreamPermissions(Arg.Is("fs2")) .Returns(fs2Permissions); ILogger logger = CreateLogger(); FundingStreamPermissionService service = CreateService( userRepository: userRepository, cacheProvider: cacheProvider, logger: logger); // Act await service.Process(message); // Assert await userRepository .Received(1) .GetUsersWithFundingStreamPermissions(Arg.Is("fs1")); await userRepository .Received(1) .GetUsersWithFundingStreamPermissions(Arg.Is("fs2")); await cacheProvider .Received(0) .DeleteHashKey <EffectiveSpecificationPermission>(Arg.Is <string>(c => c.StartsWith(CacheKeys.EffectivePermissions)), Arg.Is(SpecificationId)); logger .Received(1) .Information( Arg.Is("Found changed funding streams for specification '{SpecificationId}' Previous: {PreviousFundingStreams} Current {CurrentFundingStreams}"), Arg.Is(SpecificationId), Arg.Is <IEnumerable <string> >(c => c.Count() == 1), Arg.Is <IEnumerable <string> >(c => c.Count() == 2) ); logger .Received(0) .Information( Arg.Is("Clearing effective permissions for userId '{UserId}' for specification '{SpecificationId}'"), Arg.Any <string>(), Arg.Is(SpecificationId)); }
public async Task UpdateScenarioForSpecification(Message message) { SpecificationVersionComparisonModel specificationVersionComparison = message.GetPayloadAsInstanceOf <SpecificationVersionComparisonModel>(); if (specificationVersionComparison == null || specificationVersionComparison.Current == null) { _logger.Error("A null specificationVersionComparison was provided to UpdateScenarioForSpecification"); throw new InvalidModelException(nameof(Models.Specs.SpecificationVersionComparisonModel), new[] { "Null or invalid model provided" }); } if (specificationVersionComparison.HasNoChanges && !specificationVersionComparison.HasNameChange) { _logger.Information("No changes detected"); return; } string specificationId = specificationVersionComparison.Id; IEnumerable <TestScenario> scenarios = await _scenariosRepository.GetTestScenariosBySpecificationId(specificationId); if (scenarios.IsNullOrEmpty()) { _logger.Information($"No scenarios found for specification id: {specificationId}"); return; } IEnumerable <string> fundingStreamIds = specificationVersionComparison.Current.FundingStreams?.Select(m => m.Id); IList <ScenarioIndex> scenarioIndexes = new List <ScenarioIndex>(); IList <TestScenarioVersion> scenarioVersions = new List <TestScenarioVersion>(); foreach (TestScenario scenario in scenarios) { TestScenarioVersion newVersion = new TestScenarioVersion { FundingPeriodId = specificationVersionComparison.Current.FundingPeriod.Id, FundingStreamIds = specificationVersionComparison.Current.FundingStreams.Select(m => m.Id), Author = scenario.Current.Author, Gherkin = scenario.Current.Gherkin, Description = scenario.Current.Description, PublishStatus = scenario.Current.PublishStatus }; newVersion = await _versionRepository.CreateVersion(newVersion, scenario.Current); scenario.Current = newVersion; scenarioVersions.Add(newVersion); ScenarioIndex scenarioIndex = CreateScenarioIndexFromScenario(scenario, new SpecificationSummary { Id = specificationVersionComparison.Id, Name = specificationVersionComparison.Current.Name, FundingPeriod = specificationVersionComparison.Current.FundingPeriod, FundingStreams = specificationVersionComparison.Current.FundingStreams }); scenarioIndexes.Add(scenarioIndex); } await TaskHelper.WhenAllAndThrow( _scenariosRepository.SaveTestScenarios(scenarios), _versionRepository.SaveVersions(scenarioVersions), _searchRepository.Index(scenarioIndexes) ); }