public async Task When_UserAsksForMovieWithMostFields_Then_ReturnMovieProperly_Incomplete() { // arrange var client = Fixture.Server.CreateClient(); client.CreateSession(); var response = ResponseFactory.FromFiddlerLikeResponseFile($"{Fixture.StubsFolder}/OmdbApi/Real_Responses/Happy/200_ContainsMostFields_TheMatrix.txt"); var matrixMovieUrl = $"{MovieUrl}&t=matrix"; client.AppendHttpCallStub(HttpMethod.Get, new System.Uri(matrixMovieUrl), response); // act var httpResponse = await client.GetAsync("/api/movie/matrix"); // assert httpResponse.Should().NotBeNull(); httpResponse.StatusCode.Should().Be(HttpStatusCode.OK); var movie = JsonSerializer.Deserialize <MovieProject.Logic.DTO.Media>(await httpResponse.Content.ReadAsStringAsync()); movie.Should().NotBeNull(); movie.Id.Should().Be("tt0133093"); movie.Name.Should().Be("The Matrix"); movie.Year.Should().Be("1999"); movie.Runtime.Should().Be("136 min"); movie.Plot.Should().Be("A computer hacker learns from mysterious rebels about the true nature of his reality and his role in the war against its controllers."); }
public async Task When_UserAsksForMovieThatDoesntExist_Then_Return400Status() { // arrange var client = Fixture.Server.CreateClient(); client.CreateSession(); var response = ResponseFactory.FromFiddlerLikeResponseFile($"{Fixture.StubsFolder}/OmdbApi/Real_Responses/Happy/200_MovieNotFound.txt"); client.AppendHttpCallStub(HttpMethod.Get, new System.Uri($"{MovieUrl}&t=some_weird_title"), response); // act var httpResponse = await client.GetAsync("/api/movie/some_weird_title"); // assert logs var logs = client.GetSessionLogs(); logs.ShouldBeEmpty(); // assert outgoing var outgoingRequests = client.GetSessionOutgoingRequests(); outgoingRequests.Count.ShouldBe(1); outgoingRequests[0].GetEndpoint().ShouldBe($"GET {MovieUrl}&t=some_weird_title"); outgoingRequests[0].GetHeaderValue("Referer").ShouldBe(MovieProject.Logic.Constants.Website); // assert return httpResponse.StatusCode.ShouldBe(HttpStatusCode.NotFound); var message = await httpResponse.ReadBody(); message.ShouldBe("Search terms didn't match any movie"); }
public async Task When_DownstreamSystemReturnsInvalidJson_Then_LogError_And_ReturnDefaultErrorMessage() { // arrange var client = Fixture.Server.CreateClient(); client.CreateSession(); var response = ResponseFactory.FromFiddlerLikeResponseFile($"{Fixture.StubsFolder}/OmdbApi/Fake_Responses/Unhappy/200_Unexpected_Json.txt"); // we add it twice to account for the recall attempt client.AppendHttpCallStub(HttpMethod.Get, new System.Uri(MatrixMovieUrl), response); // act var httpResponse = await client.GetAsync("/api/movie/matrix"); using (new AssertionScope()) { // assert logs var logs = client.GetSessionLogs(); logs.Count.Should().Be(1); // we check that we log downstream errors specifically with extra details so we can easily debug, the format should be // Critical: URL returned invalid response: http status=XXX and body [FULL RESPONSE BODY HERE] logs[0].ToString().Should().StartWith($"Critical: GET {MatrixMovieUrl} had exception [DTO is invalid] while [processing response], response HttpStatus=200 and body=["); logs[0].Message.Should().Contain(@"""weirdRoot"":"); // assert outgoing var outgoingRequests = client.GetSessionOutgoingRequests(); AssertMatrixEndpointCalled(outgoingRequests[0]); // assert return httpResponse.StatusCode.Should().Be(HttpStatusCode.InternalServerError); var message = await httpResponse.ReadBody(); message.Should().Be(Constants.DownstreamErrorMessage); } }
public async Task When_Creating_Post_Success() { // arrange var client = Fixture.Server.CreateClient(); client.CreateSession(); var response = ResponseFactory.FromFiddlerLikeResponseFile($"{Fixture.StubsFolder}/PostApi/Real_Responses/Happy/200_Post.txt"); client.AppendHttpCallStub(HttpMethod.Post, new System.Uri(Url), response); var request = new Post { Body = "testPost", Title = "testTitle", UserId = 12345678 }; // act var post = await client.PostAsync("/api/post", new StringContent(JsonConvert.SerializeObject(request), Encoding.UTF8, "application/json")); // asserts post.StatusCode.Should().Be(HttpStatusCode.Created); client.GetSessionLogs().Should().BeEmpty(); var outgoingRequests = client.GetSessionOutgoingRequests(); outgoingRequests.Should().HaveCount(1); outgoingRequests[0].GetEndpoint().Should().Be("POST https://jsonplaceholder.typicode.com/post"); var requestBody = await outgoingRequests[0].ReadJsonBody <Post>(); requestBody.Should().BeEquivalentTo(request); }
public async Task Read200File() { var sut = ResponseFactory.FromFiddlerLikeResponseFile(FilesFolder + @"happy/200_MovieNotFound.txt"); sut.StatusCode.Should().Be(HttpStatusCode.OK); sut.Content.Headers.ShouldContainHeader("Content-Type", "application/json; charset=utf-8"); sut.Content.Headers.ShouldContainHeader("Expires", "Thu, 28 Feb 2019 10:42:23 GMT"); sut.Content.Headers.ShouldContainHeader("Last-Modified", "Wed, 27 Feb 2019 10:42:23 GMT"); sut.Headers.ShouldContainHeader("Date", "Wed, 27 Feb 2019 10:42:23 GMT"); sut.Headers.ShouldContainHeader("Set-Cookie", "__cfduid=d336dbbaa07967596b7d935784ddf84471551264143; expires=Thu, 27-Feb-20 10:42:23 GMT; path=/; domain=.omdbapi.com; HttpOnly"); sut.Headers.ShouldContainHeader("Cache-Control", "public, max-age=86400"); sut.Headers.ShouldContainHeader("Vary", "*"); sut.Headers.ShouldContainHeader("X-AspNet-Version", "4.0.30319"); sut.Headers.ShouldContainHeader("X-Powered-By", "ASP.NET"); sut.Headers.ShouldContainHeader("Access-Control-Allow-Origin", "*"); sut.Headers.ShouldContainHeader("CF-Cache-Status", "MISS"); sut.Headers.ShouldContainHeader("CF-RAY", "4afa0b5f1b756563-SYD"); sut.Headers.ShouldContainHeader("Server", "cloudflare"); var body = await sut.GetResponseString(); body.Should().Be(@"{ ""Response"": ""False"", ""Error"": ""Movie not found!"" }"); }
public void NoBody() { var fullFileName = FilesFolder + @"unhappy/401_NoBody.txt"; var response = ResponseFactory.FromFiddlerLikeResponseFile(fullFileName); response.StatusCode.Should().Be(System.Net.HttpStatusCode.Unauthorized); }
private void SetupGlobalStubs() { // this will be the default response, returned if it can't find a match for the session var response = ResponseFactory.FromFiddlerLikeResponseFile($"{StubsFolder}/OmdbApi/Fake_Responses/Happy/200_NoRunTime_NoPlot_YearTooOld.txt"); var comeAlongMovieUrl = $"{MovieUrl}&t=fantastika"; UnsessionedData.AppendGlobalHttpCallStub(HttpMethod.Get, new System.Uri(comeAlongMovieUrl), response); }
public void NoHttpStatusCode() { var fullFileName = FilesFolder + @"unhappy/NoHttpStatusCode.txt"; Action act = () => ResponseFactory.FromFiddlerLikeResponseFile(fullFileName); var exception = Assert.Throws <ArgumentException>(act); exception.Message.Should().Be($"File is not in the right format, please consult {Constants.Website}"); }
public void FileIsEmpty() { var fullFileName = FilesFolder + @"unhappy/Empty.txt"; Action act = () => ResponseFactory.FromFiddlerLikeResponseFile(fullFileName); var exception = Assert.Throws <ArgumentException>(act); exception.Message.Should().Be($"Content of {fullFileName} is empty"); }
public void FileDoesntExist() { var fullFileName = FilesFolder + "ThisFileDoesntExist.txt"; Action act = () => ResponseFactory.FromFiddlerLikeResponseFile(fullFileName); var exception = Assert.Throws <ArgumentException>(act); exception.Message.Should().Be($"Could not find file '{fullFileName}'"); }
public void InvalidHttpStatus() { var fullFileName = FilesFolder + @"unhappy/InvalidHttpStatus.txt"; Action act = () => ResponseFactory.FromFiddlerLikeResponseFile(fullFileName); var exception = Assert.Throws <ArgumentException>(act); exception.Message.Should().Be($"Not a valid Http Status code: 800"); }
public async Task Read424File() { var sut = ResponseFactory.FromFiddlerLikeResponseFile(FilesFolder + @"happy/424_NoHeaders.txt"); sut.StatusCode.Should().Be(HttpStatusCode.FailedDependency); var body = await sut.GetResponseString(); body.Should().Be(@"{""Content"":""No headers found here""}"); }
public async Task When_CallingManyWcfMethods_Then_CanPerformMath_Successfully() { // arrange var client = Fixture.Server.CreateClient(); client.CreateSession(); var addResponse = ResponseFactory.FromFiddlerLikeResponseFile($"{Fixture.StubsFolder}/MathWcf/Real_Responses/Happy/200_Add.txt"); client.AppendHttpCallStub(HttpMethod.Post, new System.Uri(Url), addResponse, new Dictionary <string, string>() { { "SOAPAction", @"""http://tempuri.org/Add""" } }); var minusResponse = ResponseFactory.FromFiddlerLikeResponseFile($"{Fixture.StubsFolder}/MathWcf/Real_Responses/Happy/200_Minus.txt"); client.AppendHttpCallStub(HttpMethod.Post, new System.Uri(Url), minusResponse, new Dictionary <string, string>() { { "SOAPAction", @"""http://tempuri.org/Subtract""" } }); // act var httpResponse = await client.GetAsync("/api/math/minus?firstNumber=7"); // asserts await Asserts("Subtract", "4"); // act httpResponse = await client.GetAsync("/api/math/add?firstNumber=7"); // asserts await Asserts("Add", "10"); async Task Asserts(string soapMethodName, string correctReturnedValue) { using (new AssertionScope()) { // assert logs var logs = client.GetSessionLogs(); logs.Should().BeEmpty(); // assert outgoing var outgoingRequests = client.GetSessionOutgoingRequests(); outgoingRequests.Last().GetEndpoint().Should().Be($"POST {Url}"); // only the last one matters, as they accumulate over the 2 requests outgoingRequests.Last().GetHeaderValue("SOAPAction").Should().Be(string.Format(@"""http://tempuri.org/{0}""", soapMethodName)); // assert return httpResponse.StatusCode.Should().Be(HttpStatusCode.OK); var returnedValue = await httpResponse.ReadBody(); returnedValue.Should().Be(correctReturnedValue); } } }
public void OnlyBody() { // should throw exception if we try to read with method FromFiddlerLikeResponseFile, but not FromBodyOnlyFile var fullFileName = FilesFolder + @"unhappy/OnlyBody.txt"; Action act = () => ResponseFactory.FromFiddlerLikeResponseFile(fullFileName); var exception = Assert.Throws <ArgumentException>(act); exception.Message.Should().Be($"File is not in the right format, please consult {Constants.Website}"); }
public async Task Read401File() { var sut = ResponseFactory.FromFiddlerLikeResponseFile(FilesFolder + @"happy/401_InvalidKey.txt"); sut.StatusCode.Should().Be(HttpStatusCode.Unauthorized); sut.Headers.ShouldContainHeader("Server", "cloudflare"); sut.Headers.ShouldContainHeader("CF-RAY", "4afa0cb0efb66563-SYD"); var body = await sut.GetResponseString(); body.Should().Be(@"{""Response"":""False"",""Error"":""Invalid API key!""}"); }
public async Task When_DownstreamSystemReturnsError_Then_LogError_And_ReturnDefaultErrorMessage(HttpStatusCode httpStatus, string fileName, string logContent) { // arrange // errors that are worth retrying bool isTransientDownstreamError = (int)httpStatus >= 500 || httpStatus == HttpStatusCode.RequestTimeout; var client = Fixture.Server.CreateClient(); client.CreateSession(); var response = ResponseFactory.FromFiddlerLikeResponseFile($"{Fixture.StubsFolder}/OmdbApi/{fileName}"); // we add it twice to account for the recall attempt client.AppendHttpCallStub(HttpMethod.Get, new System.Uri(MatrixMovieUrl), response); if (isTransientDownstreamError) { client.AppendHttpCallStub(HttpMethod.Get, new System.Uri(MatrixMovieUrl), response); } // act var httpResponse = await client.GetAsync("/api/movie/matrix"); using (new AssertionScope()) { // assert logs var logs = client.GetSessionLogs(); logs.Count.Should().Be(1); // we check that we log downstream errors specifically with extra details so we can easily debug, the format should be // Critical: URL returned invalid response: http status=XXX and body [FULL RESPONSE BODY HERE] logs[0].ToString().Should().StartWith($"Critical: GET {MatrixMovieUrl} had exception"); logs[0].Message.Should().Contain(logContent); logs[0].Message.Should().Contain($" response HttpStatus={(int)httpStatus} and body=["); // assert outgoing var outgoingRequests = client.GetSessionOutgoingRequests(); outgoingRequests.Count.Should().Be(isTransientDownstreamError ? 2 : 1); // 2 calls because we configured a retry AssertMatrixEndpointCalled(outgoingRequests[0]); if (isTransientDownstreamError) { AssertMatrixEndpointCalled(outgoingRequests[1]); } // assert return httpResponse.StatusCode.Should().Be(HttpStatusCode.InternalServerError); var message = await httpResponse.ReadBody(); message.Should().Be(Constants.DownstreamErrorMessage); } }
public async Task When_UserAsksForUserList_Then_ReturnListProperly() { // arrange var client = Fixture.Server.CreateClient(); client.CreateSession(); var response = ResponseFactory.FromFiddlerLikeResponseFile($"{Fixture.StubsFolder}/UserApi/Real_Responses/Happy/200_ListUsers.txt"); response.ModifyJsonBody <MovieProject.Logic.Proxy.DTO.User[]>(dto => { dto[0].Name = "Changed in code"; }); client.AppendHttpCallStub(HttpMethod.Get, new System.Uri(Url), response); // act var httpResponse = await client.GetAsync("/api/users"); using (new AssertionScope()) { // assert logs var logs = client.GetSessionLogs(); logs.Should().BeEmpty(); // assert outgoing var outgoingRequests = client.GetSessionOutgoingRequests(); outgoingRequests.Count.Should().Be(1); outgoingRequests[0].GetEndpoint().Should().Be($"GET {Url}"); outgoingRequests[0].GetHeaderValue("Referer").Should().Be(MovieProject.Logic.Constants.Website); // assert return httpResponse.StatusCode.Should().Be(HttpStatusCode.OK); var list = await httpResponse.ReadJsonBody <List <string> >(); list.Count.Should().Be(10); list[0].Should().Be("Changed in code"); list[1].Should().Be("Chelsey Dietrich"); list[2].Should().Be("Clementina DuBuque"); list[3].Should().Be("Clementine Bauch"); list[4].Should().Be("Ervin Howell"); list[5].Should().Be("Glenna Reichert"); list[6].Should().Be("Kurtis Weissnat"); list[7].Should().Be("Mrs. Dennis Schulist"); list[8].Should().Be("Nicholas Runolfsdottir V"); list[9].Should().Be("Patricia Lebsack"); } }
public async Task Read401File_WithoutBody() { var sut = ResponseFactory.FromFiddlerLikeResponseFile(FilesFolder + @"happy/401_Unauthorized_WithoutBody.txt"); sut.StatusCode.Should().Be(HttpStatusCode.Unauthorized); sut.Content.Headers.ShouldContainHeader("Expires", "Sat, 02 Mar 2019 02:53:56 GMT"); sut.Headers.ShouldContainHeader("Server", "Kestrel"); sut.Headers.ShouldContainHeader("Request-Context", "appId=cid-v1:494f2efb-2457-4434-a651-e820e8fa4933"); sut.Headers.ShouldContainHeader("Strict-Transport-Security", "max-age=2592000"); sut.Headers.ShouldContainHeader("Request-Id", "|27bb47e5-4fd78bc240436a6d."); sut.Headers.ShouldContainHeader("X-Powered-By", "ASP.NET"); sut.Headers.ShouldContainHeader("Date", "Sat, 02 Mar 2019 02:53:56 GMT"); sut.Headers.ShouldContainHeader("Connection", "keep-alive"); sut.Headers.ShouldContainHeader("x-cache-hit", "false"); sut.Headers.ShouldContainHeader("Cache-Control", "no-store, must-revalidate, no-cache"); // this seems to be resorted for some weird reason, but all the elements are still here :) var body = await sut.GetResponseString(); body.Should().BeNullOrEmpty(); }
public async Task When_UserAsksForMovieWithSomeInvalidValues_Then_ReturnMovieProperly() { // arrange var client = Fixture.Server.CreateClient(); client.CreateSession(); var response = ResponseFactory.FromFiddlerLikeResponseFile($"{Fixture.StubsFolder}/OmdbApi/Fake_Responses/Happy/200_NoRunTime_NoPlot_YearTooOld.txt"); var url = $"{MovieUrl}&t=fantastika"; client.AppendHttpCallStub(HttpMethod.Get, new System.Uri(url), response); // act var httpResponse = await client.GetAsync("/api/movie/fantastika"); using (new AssertionScope()) { // assert logs var logs = client.GetSessionLogs(); logs.Should().BeEmpty(); // assert outgoing var outgoingRequests = client.GetSessionOutgoingRequests(); outgoingRequests.Count.Should().Be(1); outgoingRequests[0].GetEndpoint().Should().Be($"GET {url}"); outgoingRequests[0].GetHeaderValue("Referer").Should().Be(Web.Constants.Referer); // assert return httpResponse.StatusCode.Should().Be(HttpStatusCode.OK); var movie = await httpResponse.ReadJsonBody <Web.DTO.Media>(); movie.Id.Should().Be("tt1185643"); movie.Name.Should().Be("Fantastika vs. Wonderwoman"); movie.Runtime.Should().Be("Unknown"); movie.Year.Should().Be("Unknown"); movie.Plot.Should().Be(""); } }
public async Task When_UserAsksForMovieWithMostFields_Then_ReturnMovieProperly() { // arrange var client = Fixture.Server.CreateClient(); client.CreateSession(); var response = ResponseFactory.FromFiddlerLikeResponseFile($"{Fixture.StubsFolder}/OmdbApi/Real_Responses/Happy/200_ContainsMostFields_TheMatrix.txt"); var matrixMovieUrl = $"{MovieUrl}&t=matrix"; client.AppendHttpCallStub(HttpMethod.Get, new System.Uri(matrixMovieUrl), response); // act var httpResponse = await client.GetAsync("/api/movie/matrix"); // assert logs var logs = client.GetSessionLogs(); logs.ShouldBeEmpty(); // assert outgoing var outgoingRequests = client.GetSessionOutgoingRequests(); outgoingRequests.Count.ShouldBe(1); outgoingRequests[0].GetEndpoint().ShouldBe($"GET {matrixMovieUrl}"); outgoingRequests[0].GetHeaderValue("Referer").ShouldBe(MovieProject.Logic.Constants.Website); // assert return httpResponse.StatusCode.ShouldBe(HttpStatusCode.OK); var movie = await httpResponse.ReadJsonBody <MovieProject.Logic.DTO.Media>(); movie.Id.ShouldBe("tt0133093"); movie.Name.ShouldBe("The Matrix"); movie.Year.ShouldBe("1999"); movie.Runtime.ShouldBe("2.3h"); movie.Plot.ShouldBe("A computer hacker learns from mysterious rebels about the true nature of his reality and his role in the war against its controllers."); movie.Language.ShouldBe(MovieProject.Logic.DTO.Media.Languages.English); }
public async Task When_UserAsksForMoviFewFields_Then_ReturnMovieProperly() { // arrange var client = Fixture.Server.CreateClient(); client.CreateSession(); var response = ResponseFactory.FromFiddlerLikeResponseFile($"{Fixture.StubsFolder}/OmdbApi/Real_Responses/Happy/200_FewFields_OldMovie.txt"); var url = $"{MovieUrl}&t=come along, do"; client.AppendHttpCallStub(HttpMethod.Get, new System.Uri(url), response); // act var httpResponse = await client.GetAsync("/api/movie/come along, do"); using (new AssertionScope()) { // assert logs var logs = client.GetSessionLogs(); logs.Should().BeEmpty(); // assert outgoing var outgoingRequests = client.GetSessionOutgoingRequests(); outgoingRequests.Count.Should().Be(1); outgoingRequests[0].GetEndpoint().Should().Be($"GET {url}"); outgoingRequests[0].GetHeaderValue("Referer").Should().Be(Web.Constants.Referer); // assert return httpResponse.StatusCode.Should().Be(HttpStatusCode.OK); var movie = await httpResponse.ReadJsonBody <Web.DTO.Media>(); movie.Id.Should().Be("tt0000182"); movie.Name.Should().Be("Come Along, Do!"); movie.Year.Should().Be("1898"); movie.Runtime.Should().Be("1 min"); movie.Plot.Should().Be("A couple look at a statue while eating in an art gallery."); } }
public async Task Read200WithComments() { var sut = ResponseFactory.FromFiddlerLikeResponseFile(FilesFolder + @"happy/200_WithComments.txt"); sut.StatusCode.Should().Be(HttpStatusCode.OK); var body = await sut.GetResponseString(); body.Should().Be(@"{""Content"":""testing comments""}"); sut.Content.Headers.ShouldContainHeader("Content-Type", "application/json; charset=utf-8"); sut.Content.Headers.ShouldContainHeader("Expires", "Mon, 04 Mar 2019 07:17:49 GMT"); sut.Content.Headers.ShouldContainHeader("Last-Modified", "Sun, 03 Mar 2019 07:17:48 GMT"); sut.Headers.ShouldContainHeader("Date", "Sun, 03 Mar 2019 07:17:49 GMT"); sut.Headers.ShouldContainHeader("Cache-Control", "public, max-age=86400"); sut.Headers.ShouldContainHeader("Vary", "*"); sut.Headers.ShouldContainHeader("X-AspNet-Version", "4.0.30319"); sut.Headers.ShouldContainHeader("X-Powered-By", "ASP.NET"); sut.Headers.ShouldContainHeader("Access-Control-Allow-Origin", "*"); sut.Headers.ShouldContainHeader("CF-Cache-Status", "MISS"); sut.Headers.ShouldContainHeader("CF-RAY", "4b19d532ce5419aa-SYD"); sut.Headers.ShouldContainHeader("Server", "cloudflare"); }
public static IServiceCollection AddInterceptionAndStubs(this IServiceCollection serviceCollection, ILogger logger) { // the bellow call won't be used if IWebHostBuilder.InterceptHttpCallsBeforeSending() is used (which happens in test projects) return(serviceCollection.InterceptHttpCallsAfterSending(async(intercept) => { bool IsHappyPath = false; // we check content length because downstream returns a 200 for not found, we can tell by the size it's likely a bad response if (intercept.Response?.IsSuccessStatusCode ?? false && intercept.Response.Content.Headers.ContentLength > 100) { IsHappyPath = true; if (intercept.Request.RequestUri.ToString().Contains("omdb")) { var movieName = intercept.Request.GetQueryValue("t"); await intercept.SaveAsRecording("omdb/new/happy", movieName.Replace(" ", "_"), 1); } else { var action = intercept.Request.GetSoapAction(); action = action.Split("/").LastOrDefault(); await intercept.SaveAsRecording("math/new/happy", action, howManyFilesToKeep: 50); } } var returnStubInstruction = intercept.HttpContextAccessor.GetRequestHeaderValue("SystemTestingTools_ReturnStub"); if (!string.IsNullOrEmpty(returnStubInstruction)) // someone is testing edge cases, we return the requested stub { var stub = ResponseFactory.FromFiddlerLikeResponseFile(intercept.RootStubsFolder.AppendPath(returnStubInstruction)); return intercept.ReturnStub(stub, "instructions from header"); } if (IsHappyPath) { return intercept.KeepResultUnchanged(); } await intercept.SaveAsRecording("new/unhappy"); var message = intercept.Summarize(); logger.LogError(intercept.Exception, message); // get the most recent recording (stub), so we can be sure to be testing against the latest if possible var recentRecording = RecordingCollection.Recordings.FirstOrDefault( recording => recording.File.Contains(@"new/happy") && recording.Request.RequestUri.PathAndQuery == intercept.Request.RequestUri.PathAndQuery && recording.Request.GetSoapAction() == intercept.Request.GetSoapAction()); if (recentRecording != null) { return intercept.ReturnRecording(recentRecording, message); } // fall back #1, return a recording from the pre-approved folder, stored in github and vouched by a developer; might not be the latest // but returns a good response to unblock developers var oldRecording = RecordingCollection.Recordings.FirstOrDefault( recording => recording.File.Contains(@"pre-approved/happy") && recording.Request.RequestUri.PathAndQuery == intercept.Request.RequestUri.PathAndQuery && recording.Request.GetSoapAction() == intercept.Request.GetSoapAction()); if (oldRecording != null) { return intercept.ReturnRecording(oldRecording, message); } // fall back #2, we return a dummy response var fallBackRecording = RecordingCollection.Recordings.FirstOrDefault( recording => recording.File.Contains("last_fallback")); if (fallBackRecording != null) { return intercept.ReturnRecording(fallBackRecording, message + " and could not find better match"); } return intercept.KeepResultUnchanged(); })); }
public async Task When_FilesAlreadyExistInFolder_And_ValidRequestResponse_Then_CreateTextFileInRightFormat_And_CanLoadFile() { // this test relies on usage of the FileSystem, it's unusual, but considered best balance // of efficient + realist testing vs potential downsides, using the temporary folder of the machine // should be ok // arrange if (Directory.Exists(folder)) { Directory.Delete(folder, true); // if folder exists, it was the result of previous tests } // create directory and some files in it, so we make sure our code creates the next file correctly Directory.CreateDirectory(folder); File.CreateText(Path.Combine(folder, "1_OK.txt")); File.CreateText(Path.Combine(folder, "2_Forbidden.txt")); File.CreateText(Path.Combine(folder, "28_Whatever.txt")); File.CreateText(Path.Combine(folder, "some_random_file.txt")); var input = new RequestResponse() { Metadata = new RequestResponse.MetadataInfo() { DateTime = System.DateTime.Parse("2019-03-17 15:44:37.597"), Timezone = "my_time_zone", LocalMachine = "Machine001", User = "******", RecordedFrom = @"MovieProject.Web 1.2.0.1 (htts://localhost/api/whatever?param=2)", ToolUrl = "http://www.whatever.com", ToolNameAndVersion = "SystemTestingTools 0.1.0.0" }, Request = new RequestResponse.RequestInfo() { Method = HttpMethod.Post, Url = "https://www.whatever.com/someendpoint", Body = @"{""user"":""Alan"", ""trickyField"":""--!?@Divider:"", ""trickyField2"":""HTTP/1.1 200 OK""}", Headers = new Dictionary <string, string>() { { "User-Agent", "MyApp" } } }, Response = new RequestResponse.ResponseInfo() { Status = HttpStatusCode.OK, Body = @"{""value"":""whatever"", ""trickyField"":""--!?@Divider:"", ""trickyField2"":""HTTP/1.1 200 OK""}", HttpVersion = new System.Version(1, 1), Headers = new Dictionary <string, string>() { { "Server", "Kestrel" } } } }; var sut = new FileWriter(folder); // act var fileName = sut.Write(input); // asserts fileName.ShouldBe("29_OK"); var createdFile = Path.Combine(folder, "29_OK.txt"); File.Exists(createdFile).ShouldBeTrue(); var content = File.ReadAllText(createdFile); content.ShouldBe(expectedFileContent); var deserializedResponse = ResponseFactory.FromFiddlerLikeResponseFile(createdFile); deserializedResponse.StatusCode.ShouldBe(input.Response.Status); (await deserializedResponse.Content.ReadAsStringAsync()).ShouldBe(input.Response.Body); foreach (var item in input.Response.Headers) { deserializedResponse.Headers.ShouldContainHeader(item.Key, item.Value); } }