public async Task SearchActualBuilderAsyncTest(string searchTerm, string expectedComputedSearchTerm) { //Arrange //Reals var actualQueryBuilder = new DfcSearchQueryBuilder(); var actualManipulator = new JobProfileSearchManipulator(); //Fakes var fakeIndexClient = A.Fake <ISearchIndexClient>(o => o.Strict()); var fakeQueryConverter = A.Fake <IAzSearchQueryConverter>(o => o.Strict()); var fakeDocumentsOperation = A.Fake <IDocumentsOperations>(); var dummySearchProperty = A.Dummy <SearchProperties>(); var dummySearchParameters = A.Dummy <SearchParameters>(); var dummySearchResult = A.Dummy <Data.Model.SearchResult <JobProfileIndex> >(); var fakeLogger = A.Fake <IApplicationLogger>(); var policy = new TolerancePolicy(fakeLogger, new TransientFaultHandlingStrategy(new InMemoryConfigurationProvider())); //Configure A.CallTo(() => fakeQueryConverter.BuildSearchParameters(A <SearchProperties> ._)).Returns(dummySearchParameters); A.CallTo(() => fakeIndexClient.Documents).Returns(fakeDocumentsOperation); A.CallTo(() => fakeQueryConverter.ConvertToSearchResult(A <DocumentSearchResult <JobProfileIndex> > ._, A <SearchProperties> ._)).Returns(dummySearchResult); //Act var searchService = new DfcSearchQueryService <JobProfileIndex>(fakeIndexClient, fakeQueryConverter, actualQueryBuilder, actualManipulator, fakeLogger); await searchService.SearchAsync(searchTerm, dummySearchProperty); //Assert A.CallTo(() => fakeQueryConverter.BuildSearchParameters(A <SearchProperties> ._)).MustHaveHappened(); A.CallTo(() => fakeIndexClient.Documents).MustHaveHappened(); A.CallTo(() => fakeDocumentsOperation.SearchWithHttpMessagesAsync <JobProfileIndex>(A <string> .That.Contains(expectedComputedSearchTerm), A <SearchParameters> ._, A <SearchRequestOptions> ._, A <Dictionary <string, List <string> > > ._, A <CancellationToken> ._)).MustHaveHappened(); A.CallTo(() => fakeQueryConverter.ConvertToSearchResult(A <DocumentSearchResult <JobProfileIndex> > ._, A <SearchProperties> ._)).MustHaveHappened(); }
public async Task GetServiceStatusExceptionAsync() { //Arrange var fakeHttpClientService = A.Fake <IHttpClientService <ISpellcheckService> >(ops => ops.Strict()); var fakeLogger = A.Fake <IApplicationLogger>(ops => ops.Strict()); var policy = new TolerancePolicy(fakeLogger, new TransientFaultHandlingStrategy(new InMemoryConfigurationProvider())); var json = "{\"_type\": \"Cause Exception\"}"; var fakeHttpResponseMessage = new HttpResponseMessage { Content = new StringContent(json, Encoding.UTF8, "application/json"), StatusCode = System.Net.HttpStatusCode.ServiceUnavailable, ReasonPhrase = nameof(GetServiceStatusAsync) }; A.CallTo(() => fakeHttpClientService.GetAsync(A <string> ._, A <FaultToleranceType> ._)).Returns(fakeHttpResponseMessage); A.CallTo(() => fakeHttpClientService.AddHeader(Constants.OcpApimSubscriptionKey, A <string> ._)).Returns(true); A.CallTo(() => fakeLogger.LogExceptionWithActivityId(A <string> ._, A <Exception> ._)).Returns("Exception logged"); //Act var spellingService = new SpellCheckService(fakeHttpClientService, fakeLogger); var serviceStatus = await spellingService.GetCurrentStatusAsync(); //Asserts serviceStatus.Status.Should().NotBe(ServiceState.Green); serviceStatus.Notes.Should().Contain("Exception logged"); A.CallTo(() => fakeLogger.LogExceptionWithActivityId(A <string> ._, A <Exception> ._)).MustHaveHappened(); }
public async Task GetServiceStatusAsync(bool suggestionsReturned, ServiceState expectedServiceStatus, bool isResponseSuccess) { //Arrange var fakeHttpClientService = A.Fake <IHttpClientService <ISpellcheckService> >(ops => ops.Strict()); var fakeLogger = A.Fake <IApplicationLogger>(); var policy = new TolerancePolicy(fakeLogger, new TransientFaultHandlingStrategy(new InMemoryConfigurationProvider())); var json = suggestionsReturned ? "{\"_type\": \"SpellCheck\", \"flaggedTokens\": [{\"offset\": 0, \"token\": \"pluse\", \"type\": \"UnknownToken\", \"suggestions\": [{\"suggestion\": \"pulse\", \"score\": 1}]}]}\r\n" : "{\"_type\": \"SpellCheck\", \"flaggedTokens\": []}"; var fakeHttpResponseMessage = new HttpResponseMessage { Content = new StringContent(json, Encoding.UTF8, "application/json"), StatusCode = isResponseSuccess ? System.Net.HttpStatusCode.OK : System.Net.HttpStatusCode.ServiceUnavailable, ReasonPhrase = nameof(GetServiceStatusAsync) }; //Setup Dummies and Mocks A.CallTo(() => fakeHttpClientService.GetAsync(A <string> ._, A <FaultToleranceType> ._)).Returns(fakeHttpResponseMessage); A.CallTo(() => fakeHttpClientService.AddHeader(Constants.OcpApimSubscriptionKey, A <string> ._)).Returns(true); //Act var spellingService = new SpellCheckService(fakeHttpClientService, fakeLogger); var serviceStatus = await spellingService.GetCurrentStatusAsync(); //Asserts serviceStatus.Status.Should().Be(expectedServiceStatus); }
public async Task CheckSpellingAsyncTest(string term, bool suggestionsReturned, bool isResponseSuccess) { //Arrange var fakeHttpClientService = A.Fake <IHttpClientService <ISpellcheckService> >(ops => ops.Strict()); var fakeLogger = A.Fake <IApplicationLogger>(); var policy = new TolerancePolicy(fakeLogger, new TransientFaultHandlingStrategy(new InMemoryConfigurationProvider())); var json = suggestionsReturned ? "{\"_type\": \"SpellCheck\", \"flaggedTokens\": [{\"offset\": 0, \"token\": \"pluse\", \"type\": \"UnknownToken\", \"suggestions\": [{\"suggestion\": \"pulse\", \"score\": 1}]}]}\r\n" : "{\"_type\": \"SpellCheck\", \"flaggedTokens\": []}"; var fakeHttpResponseMessage = new HttpResponseMessage { Content = new StringContent(json, Encoding.UTF8, "application/json"), StatusCode = isResponseSuccess ? System.Net.HttpStatusCode.OK : System.Net.HttpStatusCode.ServiceUnavailable }; A.CallTo(() => fakeHttpClientService.GetAsync(A <string> ._, A <FaultToleranceType> ._)).Returns(fakeHttpResponseMessage); A.CallTo(() => fakeHttpClientService.AddHeader(Constants.OcpApimSubscriptionKey, A <string> ._)).Returns(true); //Act var spellingService = new SpellCheckService(fakeHttpClientService, fakeLogger); var result = await spellingService.CheckSpellingAsync(term); //Assert if (isResponseSuccess && suggestionsReturned) { result.HasCorrected.Should().BeTrue(); } else { result.HasCorrected.Should().BeFalse(); } }
public void ExecuteTestWithPredicate(string dependencyName, FaultToleranceType toleranceType) { //Assign var strategy = new TransientFaultHandlingStrategy(new InMemoryConfigurationProvider()); var fakeLogger = A.Fake <IApplicationLogger>(); //Act var actor = new TolerancePolicy(fakeLogger, strategy); //Assert //Assert switch (toleranceType) { case FaultToleranceType.WaitRetry: case FaultToleranceType.RetryWithCircuitBreaker: var executedNumberOfTimes = 0; Func <Task> result2 = async() => { await actor.ExecuteAsync( () => Task.FromResult(executedNumberOfTimes++), a => a < strategy.Retry, dependencyName, toleranceType); }; result2.Awaiting(async a => await a()).Should().NotThrow(); executedNumberOfTimes.Should().Be(strategy.Retry + 1); break; case FaultToleranceType.CircuitBreaker: Func <Task> result3 = async() => { int idx = 0; while (idx++ <= strategy.AllowedFaults) { try { await actor.ExecuteAsync(() => ThrowEx(), a => idx < strategy.AllowedFaults, dependencyName, toleranceType); } catch (NotImplementedException) { } } }; result3.Awaiting(async a => await a()).Should().Throw <BrokenCircuitException>(); break; default: Assert.False(true, "Missing implementation"); break; } }
public async Task SearchAsyncTest() { //Arrange var fakeIndexClient = A.Fake <ISearchIndexClient>(o => o.Strict()); var fakeQueryBuilder = A.Fake <ISearchQueryBuilder>(o => o.Strict()); var fakeQueryConverter = A.Fake <IAzSearchQueryConverter>(o => o.Strict()); var fakeDocumentsOperation = A.Fake <IDocumentsOperations>(); var dummySearchProperty = A.Dummy <SearchProperties>(); var dummySearchParameters = A.Dummy <SearchParameters>(); var dummySearchResult = A.Dummy <Data.Model.SearchResult <JobProfileIndex> >(); var fakeLogger = A.Fake <IApplicationLogger>(); var fakeManipulator = A.Fake <ISearchManipulator <JobProfileIndex> >(); var policy = new TolerancePolicy(fakeLogger, new TransientFaultHandlingStrategy(new InMemoryConfigurationProvider())); //Configure A.CallTo(() => fakeQueryBuilder.RemoveSpecialCharactersFromTheSearchTerm(A <string> ._, A <SearchProperties> ._)).Returns(CleanedSearchTerm); A.CallTo(() => fakeQueryBuilder.BuildContainPartialSearch(A <string> ._, A <SearchProperties> ._)).Returns(PartialTermToSearch); A.CallTo(() => fakeQueryBuilder.TrimCommonWordsAndSuffixes(A <string> ._, A <SearchProperties> ._)).Returns(TrimmedResults); A.CallTo(() => fakeQueryConverter.BuildSearchParameters(A <SearchProperties> ._)).Returns(dummySearchParameters); A.CallTo(() => fakeIndexClient.Documents).Returns(fakeDocumentsOperation); A.CallTo(() => fakeQueryConverter.ConvertToSearchResult(A <DocumentSearchResult <JobProfileIndex> > ._, A <SearchProperties> ._)).Returns(dummySearchResult); A.CallTo(() => fakeManipulator.BuildSearchExpression(A <string> ._, A <string> ._, A <string> ._, A <SearchProperties> ._)).Returns(nameof(fakeManipulator.BuildSearchExpression)); //Act var searchService = new DfcSearchQueryService <JobProfileIndex>(fakeIndexClient, fakeQueryConverter, fakeQueryBuilder, fakeManipulator, fakeLogger); await searchService.SearchAsync("searchTerm", dummySearchProperty); //Assert A.CallTo(() => fakeQueryBuilder.RemoveSpecialCharactersFromTheSearchTerm(A <string> .That.IsEqualTo(SearchTerm), A <SearchProperties> ._)).MustHaveHappened(); A.CallTo(() => fakeQueryBuilder.TrimCommonWordsAndSuffixes(A <string> .That.IsEqualTo(CleanedSearchTerm), A <SearchProperties> ._)).MustHaveHappened(); A.CallTo(() => fakeQueryBuilder.BuildContainPartialSearch(A <string> .That.IsEqualTo(TrimmedResults), A <SearchProperties> ._)).MustHaveHappened(); A.CallTo(() => fakeQueryConverter.BuildSearchParameters(A <SearchProperties> ._)).MustHaveHappened(); A.CallTo(() => fakeIndexClient.Documents).MustHaveHappened(); A.CallTo(() => fakeDocumentsOperation.SearchWithHttpMessagesAsync <JobProfileIndex>(A <string> .That.IsEqualTo(nameof(fakeManipulator.BuildSearchExpression)), A <SearchParameters> ._, A <SearchRequestOptions> ._, A <Dictionary <string, List <string> > > ._, A <CancellationToken> ._)).MustHaveHappened(); A.CallTo(() => fakeQueryConverter.ConvertToSearchResult(A <DocumentSearchResult <JobProfileIndex> > ._, A <SearchProperties> ._)).MustHaveHappened(); }
public void ExecuteTest(string dependencyName, FaultToleranceType toleranceType) { //Assign var strategy = new TransientFaultHandlingStrategy(new InMemoryConfigurationProvider()); var fakeLogger = A.Fake <IApplicationLogger>(); //Act var actor = new TolerancePolicy(fakeLogger, strategy); //Assert switch (toleranceType) { case FaultToleranceType.Timeout: Action result1 = () => actor.Execute(() => { SystemClock.Sleep(TimeSpan.FromSeconds(strategy.Timeout.Seconds + 1), CancellationToken.None); return(dependencyName); }, dependencyName, toleranceType); result1.Should().Throw <TimeoutRejectedException>(); break; case FaultToleranceType.Retry: var executedNumberOfTimes = 0; Action result2 = () => actor.Execute(() => { executedNumberOfTimes++; return(ThrowEx()); }, dependencyName, toleranceType); result2.Should().Throw <NotImplementedException>(); executedNumberOfTimes.Should().Be(strategy.Retry + 1); break; case FaultToleranceType.WaitRetry: TimeSpan delayResult = default; var exNumberOfTimes = 0; Action resultWait = () => { var delay = Stopwatch.StartNew(); try { actor.Execute( () => { exNumberOfTimes++; return(ThrowEx()); }, dependencyName, toleranceType); } finally { delay.Stop(); delayResult = delay.Elapsed; } }; resultWait.Should().Throw <NotImplementedException>(); exNumberOfTimes.Should().Be(strategy.Retry + 1); delayResult.Should().BeCloseTo(TimeSpan.FromSeconds(strategy.Wait.Seconds * strategy.Retry), Precision); break; case FaultToleranceType.CircuitBreaker: Action result3 = () => { int idx = 0; while (idx++ <= strategy.AllowedFaults) { try { actor.Execute(() => ThrowEx(), dependencyName, toleranceType); } catch (NotImplementedException) { } } }; result3.Should().Throw <BrokenCircuitException>(); break; case FaultToleranceType.RetryWithCircuitBreaker: var retriedBeforeBreakingCircuit = 0; Action result4 = () => { int idx = 0; while (idx++ <= strategy.AllowedFaults) { try { actor.Execute(() => { retriedBeforeBreakingCircuit++; return(ThrowEx()); }, dependencyName, toleranceType); } catch (NotImplementedException) { } } }; result4.Should().Throw <BrokenCircuitException>(); retriedBeforeBreakingCircuit.Should().Be(strategy.AllowedFaults * (strategy.Retry + 1)); break; default: Assert.False(true, "Missing implementation"); break; } }
public void ExecuteAsyncTest(string dependencyName, FaultToleranceType toleranceType) { //Assign var strategy = new TransientFaultHandlingStrategy(new InMemoryConfigurationProvider()); var fakeLogger = A.Fake <IApplicationLogger>(); //Act var actor = new TolerancePolicy(fakeLogger, strategy); //Assert switch (toleranceType) { case FaultToleranceType.Timeout: Func <Task> result1 = async() => await actor.ExecuteAsync(() => SystemClock.SleepAsync(TimeSpan.FromSeconds(strategy.Timeout.Seconds + 1), CancellationToken.None).ContinueWith(_ => dependencyName), dependencyName, toleranceType); result1.Awaiting(async a => await a()).Should().Throw <TimeoutRejectedException>(); break; case FaultToleranceType.Retry: var executedNumberOfTimes = 0; Func <Task> result2 = async() => await actor.ExecuteAsync(() => { executedNumberOfTimes++; return(ThrowEx()); }, dependencyName, toleranceType); result2.Awaiting(async a => await a()).Should().Throw <NotImplementedException>(); executedNumberOfTimes.Should().Be(strategy.Retry + 1); break; case FaultToleranceType.CircuitBreaker: Func <Task> result3 = async() => { int idx = 0; while (idx++ <= strategy.AllowedFaults) { try { await actor.ExecuteAsync(() => ThrowEx(), dependencyName, toleranceType); } catch (NotImplementedException) { } } }; result3.Awaiting(async a => await a()).Should().Throw <BrokenCircuitException>(); break; case FaultToleranceType.RetryWithCircuitBreaker: var retriedBeforeBreakingCircuit = 0; Func <Task> result4 = async() => { int idx = 0; while (idx++ <= strategy.AllowedFaults) { try { await actor.ExecuteAsync(() => { retriedBeforeBreakingCircuit++; return(ThrowEx()); }, dependencyName, toleranceType); } catch (NotImplementedException) { } } }; result4.Awaiting(async a => await a()).Should().Throw <BrokenCircuitException>(); retriedBeforeBreakingCircuit.Should().Be(strategy.AllowedFaults * (strategy.Retry + 1)); break; case FaultToleranceType.WaitRetry: var exNumberOfTimes = 0; Func <Task> result5 = async() => { await actor.ExecuteAsync( () => { exNumberOfTimes++; return(ThrowEx()); }, dependencyName, toleranceType); }; result5.Awaiting(async a => await a()).Should().Throw <NotImplementedException>(); exNumberOfTimes.Should().Be(strategy.Retry + 1); break; default: Assert.False(true, "Missing implementation"); break; } }