public void GetForCandidateCalled(bool userActivated, bool sendSavedSearchAlerts, bool expectCall)
        {
            var candidateId          = Guid.NewGuid();
            var candidateSavedSearch = new CandidateSavedSearches {
                CandidateId = candidateId
            };

            var userReadRepository = new Mock <IUserReadRepository>();

            userReadRepository.Setup(r => r.Get(candidateId)).Returns(new UserBuilder(candidateId).Activated(userActivated).Build);
            var candidateReadRepository = new Mock <ICandidateReadRepository>();

            candidateReadRepository.Setup(r => r.Get(candidateId)).Returns(new CandidateBuilder(candidateId).EnableSavedSearchAlertsViaEmailAndText(sendSavedSearchAlerts).Build);
            var savedSearchReadRepository = new Mock <ISavedSearchReadRepository>();
            var processor = new SavedSearchProcessorBuilder().With(userReadRepository).With(candidateReadRepository).With(savedSearchReadRepository).Build();

            processor.ProcessCandidateSavedSearches(candidateSavedSearch);

            if (expectCall)
            {
                savedSearchReadRepository.Verify(r => r.GetForCandidate(candidateId), Times.Once);
            }
            else
            {
                savedSearchReadRepository.Verify(r => r.GetForCandidate(candidateId), Times.Never);
            }
        }
        public void QueueCandidateSavedSearches()
        {
            var stopwatch = new Stopwatch();

            stopwatch.Start();

            var candidateIds = _savedSearchReadRepository.GetCandidateIds();

            var message = string.Format("Querying candidate saved searches took {0}", stopwatch.Elapsed);

            var counter = 0;

            Parallel.ForEach(candidateIds, candidateId =>
            {
                var candidateSavedSearches = new CandidateSavedSearches
                {
                    CandidateId = candidateId
                };
                _serviceBus.PublishMessage(candidateSavedSearches);
                Interlocked.Increment(ref counter);
            });

            stopwatch.Stop();
            message += string.Format(". Queuing {0} candidate saved searches took {1}", counter, stopwatch.Elapsed);
            if (stopwatch.ElapsedMilliseconds > 60000)
            {
                _logService.Warn(message);
            }
            else
            {
                _logService.Info(message);
            }
        }
        public void RetrieveCandidateAndUser(bool userActivated)
        {
            var candidateId          = Guid.NewGuid();
            var candidateSavedSearch = new CandidateSavedSearches {
                CandidateId = candidateId
            };

            var userReadRepository = new Mock <IUserReadRepository>();

            userReadRepository.Setup(r => r.Get(candidateId)).Returns(new UserBuilder(candidateId).Activated(userActivated).Build());
            var candidateReadRepository = new Mock <ICandidateReadRepository>();

            candidateReadRepository.Setup(r => r.Get(candidateId)).Returns(new CandidateBuilder(candidateId).Build);
            var processor = new SavedSearchProcessorBuilder().With(userReadRepository).With(candidateReadRepository).Build();

            processor.ProcessCandidateSavedSearches(candidateSavedSearch);

            userReadRepository.Verify(r => r.Get(candidateId), Times.Once);
            if (userActivated)
            {
                candidateReadRepository.Verify(r => r.Get(candidateId), Times.Once);
            }
            else
            {
                candidateReadRepository.Verify(r => r.Get(candidateId), Times.Never);
            }
        }
        public void NewResults()
        {
            var candidateId          = Guid.NewGuid();
            var candidateSavedSearch = new CandidateSavedSearches {
                CandidateId = candidateId
            };

            var existingSearchResults = new ApprenticeshipSearchResultsBuilder().WithResultCount(2).Build();
            var dateProcessed         = new DateTime(2015, 01, 01);
            var savedSearches         = new Fixture().Build <SavedSearch>()
                                        .With(s => s.AlertsEnabled, true)
                                        .With(s => s.LastResultsHash, existingSearchResults.Results.GetResultsHash())
                                        .With(s => s.DateProcessed, dateProcessed)
                                        .CreateMany(1).ToList();

            var savedSearchReadRepository = new Mock <ISavedSearchReadRepository>();

            savedSearchReadRepository.Setup(r => r.GetForCandidate(candidateId)).Returns(savedSearches);
            var userReadRepository = new Mock <IUserReadRepository>();

            userReadRepository.Setup(r => r.Get(candidateId)).Returns(new UserBuilder(candidateId).Activated(true).Build);
            var candidateReadRepository = new Mock <ICandidateReadRepository>();

            candidateReadRepository.Setup(r => r.Get(candidateId)).Returns(new CandidateBuilder(candidateId).EnableSavedSearchAlertsViaEmailAndText(true).Build);
            var vacancySearchProvider = new Mock <IVacancySearchProvider <ApprenticeshipSearchResponse, ApprenticeshipSearchParameters> >();

            vacancySearchProvider.Setup(p => p.FindVacancies(It.IsAny <ApprenticeshipSearchParameters>())).Returns(new ApprenticeshipSearchResultsBuilder().WithResultCount(3).Build);
            var savedSearchAlertRepository    = new Mock <ISavedSearchAlertRepository>();
            SavedSearchAlert savedSearchAlert = null;

            savedSearchAlertRepository.Setup(r => r.Save(It.IsAny <SavedSearchAlert>())).Callback <SavedSearchAlert>(a => { savedSearchAlert = a; });
            var         savedSearchWriteRepository = new Mock <ISavedSearchWriteRepository>();
            SavedSearch savedSearch = null;

            savedSearchWriteRepository.Setup(r => r.Save(It.IsAny <SavedSearch>())).Callback <SavedSearch>(s => { savedSearch = s; });
            var processor = new SavedSearchProcessorBuilder().With(savedSearchReadRepository).With(userReadRepository).With(candidateReadRepository).With(vacancySearchProvider).With(savedSearchAlertRepository).With(savedSearchWriteRepository).Build();

            processor.ProcessCandidateSavedSearches(candidateSavedSearch);

            savedSearchWriteRepository.Verify(r => r.Save(It.IsAny <SavedSearch>()), Times.Once);
            savedSearch.Should().NotBeNull();
            savedSearch.LastResultsHash.Should().NotBeNullOrEmpty();
            savedSearch.DateProcessed.HasValue.Should().BeTrue();
            savedSearch.DateProcessed.Should().BeAfter(dateProcessed);
            savedSearchAlertRepository.Verify(r => r.GetUnsentSavedSearchAlert(It.IsAny <SavedSearch>()), Times.Once);
            savedSearchAlertRepository.Verify(r => r.Save(It.IsAny <SavedSearchAlert>()), Times.Once);
            savedSearchAlert.Should().NotBeNull();
            savedSearchAlert.Parameters.Should().Be(savedSearches.First());
            savedSearchAlert.Results.Should().NotBeNull();
            var results = savedSearchAlert.Results.ToList();

            results.Count.Should().Be(3);
            savedSearchAlert.BatchId.HasValue.Should().BeFalse();
            savedSearchAlert.SentDateTime.HasValue.Should().BeFalse();
        }
        public void ExecuteSearch(bool alertsEnabled)
        {
            var candidateId          = Guid.NewGuid();
            var candidateSavedSearch = new CandidateSavedSearches {
                CandidateId = candidateId
            };

            var savedSearchReadRepository = new Mock <ISavedSearchReadRepository>();

            savedSearchReadRepository.Setup(r => r.GetForCandidate(candidateId)).Returns(new Fixture().Build <SavedSearch>().With(s => s.AlertsEnabled, alertsEnabled).CreateMany(3).ToList());
            var userReadRepository = new Mock <IUserReadRepository>();

            userReadRepository.Setup(r => r.Get(candidateId)).Returns(new UserBuilder(candidateId).Activated(true).Build);
            var candidateReadRepository = new Mock <ICandidateReadRepository>();

            candidateReadRepository.Setup(r => r.Get(candidateId)).Returns(new CandidateBuilder(candidateId).EnableSavedSearchAlertsViaEmailAndText(true).Build);
            var vacancySearchProvider = new Mock <IVacancySearchProvider <ApprenticeshipSearchResponse, ApprenticeshipSearchParameters> >();
            ApprenticeshipSearchParameters searchParameters = null;

            vacancySearchProvider.Setup(p => p.FindVacancies(It.IsAny <ApprenticeshipSearchParameters>()))
            .Returns(new ApprenticeshipSearchResultsBuilder().WithResultCount(3).Build)
            .Callback <ApprenticeshipSearchParameters>(p => { searchParameters = p; });
            var processor = new SavedSearchProcessorBuilder().With(savedSearchReadRepository).With(userReadRepository).With(candidateReadRepository).With(vacancySearchProvider).Build();

            processor.ProcessCandidateSavedSearches(candidateSavedSearch);

            if (alertsEnabled)
            {
                vacancySearchProvider.Verify(sp => sp.FindVacancies(It.IsAny <ApprenticeshipSearchParameters>()), Times.Exactly(3));
                searchParameters.Should().NotBeNull();
            }
            else
            {
                vacancySearchProvider.Verify(sp => sp.FindVacancies(It.IsAny <ApprenticeshipSearchParameters>()), Times.Never);
                searchParameters.Should().BeNull();
            }
        }
        public void ExistingResults()
        {
            var candidateId          = Guid.NewGuid();
            var candidateSavedSearch = new CandidateSavedSearches {
                CandidateId = candidateId
            };

            var searchResults = new ApprenticeshipSearchResultsBuilder().WithResultCount(3).Build();

            var savedSearches = new Fixture().Build <SavedSearch>()
                                .With(s => s.AlertsEnabled, true)
                                .With(s => s.LastResultsHash, searchResults.Results.GetResultsHash())
                                .With(s => s.DateProcessed, new DateTime(2015, 01, 01))
                                .CreateMany(1).ToList();

            var savedSearchReadRepository = new Mock <ISavedSearchReadRepository>();

            savedSearchReadRepository.Setup(r => r.GetForCandidate(candidateId)).Returns(savedSearches);
            var userReadRepository = new Mock <IUserReadRepository>();

            userReadRepository.Setup(r => r.Get(candidateId)).Returns(new UserBuilder(candidateId).Activated(true).Build);
            var candidateReadRepository = new Mock <ICandidateReadRepository>();

            candidateReadRepository.Setup(r => r.Get(candidateId)).Returns(new CandidateBuilder(candidateId).EnableSavedSearchAlertsViaEmailAndText(true).Build);
            var vacancySearchProvider = new Mock <IVacancySearchProvider <ApprenticeshipSearchResponse, ApprenticeshipSearchParameters> >();

            vacancySearchProvider.Setup(p => p.FindVacancies(It.IsAny <ApprenticeshipSearchParameters>())).Returns(searchResults);
            var savedSearchAlertRepository = new Mock <ISavedSearchAlertRepository>();
            var savedSearchWriteRepository = new Mock <ISavedSearchWriteRepository>();
            var processor = new SavedSearchProcessorBuilder().With(savedSearchReadRepository).With(userReadRepository).With(candidateReadRepository).With(vacancySearchProvider).With(savedSearchAlertRepository).With(savedSearchWriteRepository).Build();

            processor.ProcessCandidateSavedSearches(candidateSavedSearch);

            savedSearchWriteRepository.Verify(r => r.Save(It.IsAny <SavedSearch>()), Times.Never);
            savedSearchAlertRepository.Verify(r => r.GetUnsentSavedSearchAlert(It.IsAny <SavedSearch>()), Times.Never);
            savedSearchAlertRepository.Verify(r => r.Save(It.IsAny <SavedSearchAlert>()), Times.Never);
        }
        public void ProcessCandidateSavedSearches(CandidateSavedSearches candidateSavedSearches)
        {
            var candidateId = candidateSavedSearches.CandidateId;

            var user = _userReadRepository.Get(candidateId);

            if (!user.IsActive())
            {
                return;
            }

            var candidate = _candidateReadRepository.Get(candidateId);

            if (!candidate.ShouldSendSavedSearchAlerts())
            {
                return;
            }

            var savedSearches = _savedSearchReadRepository.GetForCandidate(candidateId);

            if (savedSearches == null || !savedSearches.Any(s => s.AlertsEnabled))
            {
                return;
            }

            foreach (var savedSearch in savedSearches)
            {
                if (!HasGeoLocation(savedSearch))
                {
                    continue;
                }

                var searchParameters = SearchParametersFactory.Create(savedSearch);
                var searchResults    = _vacancySearchProvider.FindVacancies(searchParameters);
                var results          = searchResults.Results.ToList();

                if (results.Count == 0)
                {
                    _logService.Info("Saved search with id {0} returned no results", savedSearch.EntityId);
                    continue;
                }

                var resultsHash = results.GetResultsHash();

                if (savedSearch.LastResultsHash != resultsHash)
                {
                    _logService.Info("Saved search with id {0} returned new results", savedSearch.EntityId);

                    //Results are new
                    savedSearch.LastResultsHash = resultsHash;
                    //todo: once we have the vacancy posted date (March 2015) we may store this instead of the processed date
                    savedSearch.DateProcessed = DateTime.UtcNow;

                    if (savedSearch.AlertsEnabled)
                    {
                        var savedSearchAlert = _savedSearchAlertRepository.GetUnsentSavedSearchAlert(savedSearch) ?? new SavedSearchAlert {
                            Parameters = savedSearch
                        };
                        savedSearchAlert.Results = results;

                        _savedSearchAlertRepository.Save(savedSearchAlert);
                    }

                    _savedSearchWriteRepository.Save(savedSearch);
                }
            }
        }
        public void FindLocation(bool latLongSpecified, bool locationFound)
        {
            var candidateId          = Guid.NewGuid();
            var candidateSavedSearch = new CandidateSavedSearches {
                CandidateId = candidateId
            };

            var savedSearchReadRepository = new Mock <ISavedSearchReadRepository>();
            List <SavedSearch> savedSearches;

            if (latLongSpecified)
            {
                savedSearches = new Fixture().Build <SavedSearch>().With(s => s.AlertsEnabled, true).CreateMany(3).ToList();
            }
            else
            {
                savedSearches = new Fixture().Build <SavedSearch>()
                                .With(s => s.Latitude, null)
                                .With(s => s.Longitude, null)
                                .With(s => s.AlertsEnabled, true)
                                .CreateMany(3).ToList();
            }
            savedSearchReadRepository.Setup(r => r.GetForCandidate(candidateId)).Returns(savedSearches);
            var userReadRepository = new Mock <IUserReadRepository>();

            userReadRepository.Setup(r => r.Get(candidateId)).Returns(new UserBuilder(candidateId).Activated(true).Build);
            var candidateReadRepository = new Mock <ICandidateReadRepository>();

            candidateReadRepository.Setup(r => r.Get(candidateId)).Returns(new CandidateBuilder(candidateId).EnableSavedSearchAlertsViaEmailAndText(true).Build);
            var locationSearchService = new Mock <ILocationSearchService>();

            if (locationFound)
            {
                locationSearchService.Setup(s => s.FindLocation(It.IsAny <string>())).Returns(new Fixture().Build <Location>().CreateMany(3));
            }
            var vacancySearchProvider = new Mock <IVacancySearchProvider <ApprenticeshipSearchResponse, ApprenticeshipSearchParameters> >();
            ApprenticeshipSearchParameters searchParameters = null;

            vacancySearchProvider.Setup(p => p.FindVacancies(It.IsAny <ApprenticeshipSearchParameters>()))
            .Returns(new ApprenticeshipSearchResultsBuilder().WithResultCount(3).Build)
            .Callback <ApprenticeshipSearchParameters>(p => { searchParameters = p; });
            var savedSearchWriteRepository = new Mock <ISavedSearchWriteRepository>();
            var processor = new SavedSearchProcessorBuilder().With(savedSearchReadRepository).With(userReadRepository).With(candidateReadRepository).With(locationSearchService).With(vacancySearchProvider).With(savedSearchWriteRepository).Build();

            processor.ProcessCandidateSavedSearches(candidateSavedSearch);

            if (latLongSpecified)
            {
                locationSearchService.Verify(l => l.FindLocation(It.IsAny <string>()), Times.Never);
                savedSearchWriteRepository.Verify(p => p.Save(It.IsAny <SavedSearch>()), Times.Exactly(3));
                searchParameters.Should().NotBeNull();
                vacancySearchProvider.Verify(sp => sp.FindVacancies(It.IsAny <ApprenticeshipSearchParameters>()), Times.Exactly(3));
            }
            else
            {
                locationSearchService.Verify(l => l.FindLocation(It.IsAny <string>()), Times.Exactly(3));
                if (locationFound)
                {
                    //One save to update lat/long and one for the new results. 3 searches x 2 = 6
                    savedSearchWriteRepository.Verify(p => p.Save(It.IsAny <SavedSearch>()), Times.Exactly(6));
                    searchParameters.Should().NotBeNull();
                    vacancySearchProvider.Verify(sp => sp.FindVacancies(It.IsAny <ApprenticeshipSearchParameters>()), Times.Exactly(3));
                }
                else
                {
                    savedSearchWriteRepository.Verify(p => p.Save(It.IsAny <SavedSearch>()), Times.Never);
                    searchParameters.Should().BeNull();
                    vacancySearchProvider.Verify(sp => sp.FindVacancies(It.IsAny <ApprenticeshipSearchParameters>()), Times.Never);
                }
            }
        }