Exemplo n.º 1
0
        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"));
        }
Exemplo n.º 3
0
        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);
        }
Exemplo n.º 4
0
        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);
            }
        }
Exemplo n.º 6
0
        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}'"));
        }
Exemplo n.º 10
0
        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));
        }
Exemplo n.º 13
0
        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)
                );
        }