diff --git a/tools/test-proxy/Azure.Sdk.Tools.TestProxy.Tests/AdminTests.cs b/tools/test-proxy/Azure.Sdk.Tools.TestProxy.Tests/AdminTests.cs index 15e366fb345..a925c4c9ce3 100644 --- a/tools/test-proxy/Azure.Sdk.Tools.TestProxy.Tests/AdminTests.cs +++ b/tools/test-proxy/Azure.Sdk.Tools.TestProxy.Tests/AdminTests.cs @@ -41,7 +41,7 @@ public async void TestAddSanitizersThrowsOnEmptyArray() httpContext.Request.Body = TestHelpers.GenerateStreamRequestBody(requestBody); httpContext.Request.ContentLength = httpContext.Request.Body.Length; - testRecordingHandler.SanitizerRegistry.ResetSessionSanitizers(); + await testRecordingHandler.SanitizerRegistry.ResetSessionSanitizers(); var controller = new Admin(testRecordingHandler, _nullLogger) { @@ -64,7 +64,7 @@ public async void TestAddSanitizersHandlesPopulatedArray() RecordingHandler testRecordingHandler = new RecordingHandler(Directory.GetCurrentDirectory()); var httpContext = new DefaultHttpContext(); - var defaultSessionSanitizers = testRecordingHandler.SanitizerRegistry.GetSanitizers(); + var defaultSessionSanitizers = await testRecordingHandler.SanitizerRegistry.GetSanitizers(); string requestBody = @"[ { @@ -88,7 +88,7 @@ public async void TestAddSanitizersHandlesPopulatedArray() httpContext.Request.Body = TestHelpers.GenerateStreamRequestBody(requestBody); httpContext.Request.ContentLength = httpContext.Request.Body.Length; - testRecordingHandler.SanitizerRegistry.ResetSessionSanitizers(); + await testRecordingHandler.SanitizerRegistry.ResetSessionSanitizers(); httpContext.Response.Body = new MemoryStream(); var controller = new Admin(testRecordingHandler, _nullLogger) @@ -100,7 +100,7 @@ public async void TestAddSanitizersHandlesPopulatedArray() }; await controller.AddSanitizers(); - var amendedSessionSanitizers = testRecordingHandler.SanitizerRegistry.GetSanitizers(); + var amendedSessionSanitizers = await testRecordingHandler.SanitizerRegistry.GetSanitizers(); Assert.Equal(defaultSessionSanitizers.Count + 2, amendedSessionSanitizers.Count); Assert.True(amendedSessionSanitizers[defaultSessionSanitizers.Count] is GeneralRegexSanitizer); @@ -144,7 +144,7 @@ public async void TestAddSanitizersThrowsOnSingleBadInput() httpContext.Request.Body = TestHelpers.GenerateStreamRequestBody(requestBody); httpContext.Request.ContentLength = httpContext.Request.Body.Length; - testRecordingHandler.SanitizerRegistry.Clear(); + await testRecordingHandler.SanitizerRegistry.Clear(); var controller = new Admin(testRecordingHandler, _nullLogger) { @@ -174,7 +174,7 @@ public async void TestAddSanitizerThrowsOnInvalidAbstractionId() HttpContext = httpContext } }; - testRecordingHandler.SanitizerRegistry.Clear(); + await testRecordingHandler.SanitizerRegistry.Clear(); var assertion = await Assert.ThrowsAsync( async () => await controller.AddSanitizer() @@ -195,7 +195,7 @@ public async void TestAddSanitizerThrowsOnEmptyAbstractionId() HttpContext = httpContext } }; - testRecordingHandler.SanitizerRegistry.Clear(); + await testRecordingHandler.SanitizerRegistry.Clear(); var assertion = await Assert.ThrowsAsync( async () => await controller.AddSanitizer() @@ -302,7 +302,7 @@ public async Task TestSetMatcher() HttpContext = httpContext } }; - testRecordingHandler.SanitizerRegistry.Clear(); + await testRecordingHandler.SanitizerRegistry.Clear(); await controller.SetMatcher(); var result = testRecordingHandler.Matcher; @@ -433,7 +433,7 @@ public async void TestAddSanitizer() HttpContext = httpContext } }; - testRecordingHandler.SanitizerRegistry.Clear(); + await testRecordingHandler.SanitizerRegistry.Clear(); await controller.AddSanitizer(); httpContext.Response.Body.Seek(0, SeekOrigin.Begin); @@ -442,7 +442,7 @@ public async void TestAddSanitizer() Assert.Equal((int)HttpStatusCode.OK, httpContext.Response.StatusCode); Assert.True(!string.IsNullOrWhiteSpace(response.RootElement.GetProperty("Sanitizer").GetString())); - var result = testRecordingHandler.SanitizerRegistry.GetSanitizers().First(); + var result = (await testRecordingHandler.SanitizerRegistry.GetSanitizers()).First(); Assert.True(result is HeaderRegexSanitizer); } @@ -464,10 +464,10 @@ public async void TestAddSanitizerWithOddDefaults() HttpContext = httpContext } }; - testRecordingHandler.SanitizerRegistry.Clear(); + await testRecordingHandler.SanitizerRegistry.Clear(); await controller.AddSanitizer(); - var result = testRecordingHandler.SanitizerRegistry.GetSanitizers().First(); + var result = (await testRecordingHandler.SanitizerRegistry.GetSanitizers()).First(); Assert.True(result is BodyKeySanitizer); } @@ -487,7 +487,7 @@ public async void TestAddSanitizerWrongEmptyValue() HttpContext = httpContext } }; - testRecordingHandler.SanitizerRegistry.Clear(); + await testRecordingHandler.SanitizerRegistry.Clear(); var assertion = await Assert.ThrowsAsync( async () => await controller.AddSanitizer() @@ -511,10 +511,10 @@ public async void TestAddSanitizerAcceptableEmptyValue() HttpContext = httpContext } }; - testRecordingHandler.SanitizerRegistry.Clear(); + await testRecordingHandler.SanitizerRegistry.Clear(); await controller.AddSanitizer(); - var result = testRecordingHandler.SanitizerRegistry.GetSanitizers().First(); + var result = (await testRecordingHandler.SanitizerRegistry.GetSanitizers()).First(); Assert.True(result is HeaderRegexSanitizer); } @@ -541,7 +541,7 @@ public async void TestAddSanitizerIndividualRecording() }; await controller.AddSanitizer(); - var result = testRecordingHandler.SanitizerRegistry.GetSanitizers(testRecordingHandler.PlaybackSessions[recordingId]).Last(); + var result = (await testRecordingHandler.SanitizerRegistry.GetSanitizers(testRecordingHandler.PlaybackSessions[recordingId])).Last(); Assert.True(result is HeaderRegexSanitizer); } @@ -588,7 +588,7 @@ public async Task GenerateInstanceThrowsOnBadBodyFormat() } }; - testRecordingHandler.SanitizerRegistry.Clear(); + await testRecordingHandler.SanitizerRegistry.Clear(); var assertion = await Assert.ThrowsAsync( async () => await controller.AddSanitizer() @@ -615,7 +615,7 @@ public async Task AddSanitizerThrowsOnAdditionOfBadRegex() } }; - testRecordingHandler.SanitizerRegistry.Clear(); + await testRecordingHandler.SanitizerRegistry.Clear(); var assertion = await Assert.ThrowsAsync( async () => await controller.AddSanitizer() @@ -778,12 +778,12 @@ public async Task TestAddSanitizerWithInvalidConditionJson(string requestBody, s } }; - testRecordingHandler.SanitizerRegistry.Clear(); + await testRecordingHandler.SanitizerRegistry.Clear(); var assertion = await Assert.ThrowsAsync( async () => await controller.AddSanitizer() ); Assert.Equal(HttpStatusCode.BadRequest, assertion.StatusCode); - Assert.Empty(testRecordingHandler.SanitizerRegistry.GetSanitizers()); + Assert.Empty(await testRecordingHandler.SanitizerRegistry.GetSanitizers()); Assert.Contains(errorText, assertion.Message); } @@ -807,10 +807,10 @@ public async Task TestAddSanitizerWithValidUriRegexCondition(string requestBody, } }; - testRecordingHandler.SanitizerRegistry.Clear(); + await testRecordingHandler.SanitizerRegistry.Clear(); await controller.AddSanitizer(); - var appliedSanitizers = testRecordingHandler.SanitizerRegistry.GetSanitizers(); + var appliedSanitizers = await testRecordingHandler.SanitizerRegistry.GetSanitizers(); Assert.Single(appliedSanitizers); Assert.True(appliedSanitizers.First() is GeneralRegexSanitizer); @@ -896,7 +896,7 @@ public async Task TestAddSanitizerThrowsOnMissingRequiredArgument() } }; - testRecordingHandler.SanitizerRegistry.Clear(); + await testRecordingHandler.SanitizerRegistry.Clear(); var assertion = await Assert.ThrowsAsync( async () => await controller.AddSanitizer() @@ -926,10 +926,10 @@ public async Task TestAddSanitizerContinuesWithTwoRequiredParams() } }; - testRecordingHandler.SanitizerRegistry.Clear(); + await testRecordingHandler.SanitizerRegistry.Clear(); await controller.AddSanitizer(); - var addedSanitizer = testRecordingHandler.SanitizerRegistry.GetSanitizers().First(); + var addedSanitizer = (await testRecordingHandler.SanitizerRegistry.GetSanitizers()).First(); Assert.True(addedSanitizer is HeaderStringSanitizer); var actualTargetString = (string)typeof(HeaderStringSanitizer).GetField("_targetValue", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(addedSanitizer); @@ -1025,7 +1025,7 @@ public async Task RemoveSanitizerSucceedsForExistingSessionSanitizer() } }; - var expectedSanitizerCount = testRecordingHandler.SanitizerRegistry.GetSanitizers().Count; + var expectedSanitizerCount = (await testRecordingHandler.SanitizerRegistry.GetSanitizers()).Count; await controller.RemoveSanitizers(new RemoveSanitizerList() { Sanitizers = new List() { "AZSDK0000" } }); httpContext.Response.Body.Seek(0, SeekOrigin.Begin); @@ -1038,14 +1038,14 @@ public async Task RemoveSanitizerSucceedsForExistingSessionSanitizer() Assert.Single(returnedSanitizerIds); Assert.Equal("AZSDK0000", returnedSanitizerIds.First()); - Assert.Equal(expectedSanitizerCount - 1, testRecordingHandler.SanitizerRegistry.GetSanitizers().Count); + Assert.Equal(expectedSanitizerCount - 1, (await testRecordingHandler.SanitizerRegistry.GetSanitizers()).Count); } [Fact] public async Task RemoveSanitizerSucceedsForAddedRecordingSanitizer() { RecordingHandler testRecordingHandler = new RecordingHandler(Directory.GetCurrentDirectory()); - testRecordingHandler.SanitizerRegistry.Clear(); + await testRecordingHandler.SanitizerRegistry.Clear(); var httpContext = new DefaultHttpContext(); await testRecordingHandler.StartPlaybackAsync("Test.RecordEntries/oauth_request_with_variables.json", httpContext.Response); var recordingId = httpContext.Response.Headers["x-recording-id"]; @@ -1062,11 +1062,11 @@ public async Task RemoveSanitizerSucceedsForAddedRecordingSanitizer() }; var session = testRecordingHandler.GetActiveSession(recordingId); - var forRemoval = testRecordingHandler.RegisterSanitizer(new HeaderRegexSanitizer("Content-Type"), recordingId); - testRecordingHandler.RegisterSanitizer(new HeaderRegexSanitizer("Connection"), recordingId); + var forRemoval = await testRecordingHandler.RegisterSanitizer(new HeaderRegexSanitizer("Content-Type"), recordingId); + await testRecordingHandler.RegisterSanitizer(new HeaderRegexSanitizer("Connection"), recordingId); await controller.RemoveSanitizers(new RemoveSanitizerList() { Sanitizers = new List() { forRemoval } }); - var activeRecordingSanitizers = testRecordingHandler.SanitizerRegistry.GetSanitizers(session); + var activeRecordingSanitizers = await testRecordingHandler.SanitizerRegistry.GetSanitizers(session); Assert.Single(activeRecordingSanitizers); var privateSetting = (string)typeof(HeaderRegexSanitizer).GetField("_targetKey", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(activeRecordingSanitizers.First()); @@ -1077,7 +1077,7 @@ public async Task RemoveSanitizerSucceedsForAddedRecordingSanitizer() public async void GetSanitizersReturnsSessionSanitizers() { RecordingHandler testRecordingHandler = new RecordingHandler(Directory.GetCurrentDirectory()); - testRecordingHandler.RegisterSanitizer(new HeaderRegexSanitizer("Connection")); + await testRecordingHandler.RegisterSanitizer(new HeaderRegexSanitizer("Connection")); var httpContext = new DefaultHttpContext(); httpContext.Response.Body = new MemoryStream(); @@ -1112,7 +1112,7 @@ public async Task GetSanitizersReturnsRecordingSanitizers() { RecordingHandler testRecordingHandler = new RecordingHandler(Directory.GetCurrentDirectory()); var httpContext = new DefaultHttpContext(); - testRecordingHandler.SanitizerRegistry.Clear(); + await testRecordingHandler.SanitizerRegistry.Clear(); await testRecordingHandler.StartPlaybackAsync("Test.RecordEntries/oauth_request_with_variables.json", httpContext.Response); var recordingId = httpContext.Response.Headers["x-recording-id"]; httpContext.Request.Headers["x-recording-id"] = recordingId; @@ -1125,7 +1125,7 @@ public async Task GetSanitizersReturnsRecordingSanitizers() } }; - testRecordingHandler.RegisterSanitizer(new HeaderRegexSanitizer("Connection"), recordingId); + await testRecordingHandler.RegisterSanitizer(new HeaderRegexSanitizer("Connection"), recordingId); await controller.GetSanitizers(); httpContext.Response.Body.Seek(0, SeekOrigin.Begin); diff --git a/tools/test-proxy/Azure.Sdk.Tools.TestProxy.Tests/InfoTests.cs b/tools/test-proxy/Azure.Sdk.Tools.TestProxy.Tests/InfoTests.cs index 64e51757b52..dacb6934adf 100644 --- a/tools/test-proxy/Azure.Sdk.Tools.TestProxy.Tests/InfoTests.cs +++ b/tools/test-proxy/Azure.Sdk.Tools.TestProxy.Tests/InfoTests.cs @@ -18,8 +18,11 @@ namespace Azure.Sdk.Tools.TestProxy.Tests { public class InfoTests { - private int DefaultExtensionCount { get { return new RecordingHandler(null).SanitizerRegistry.GetSanitizers().Count; } } - + private async Task GetDefaultExtensionCount(){ + var handler = new RecordingHandler(null); + return (await handler.SanitizerRegistry.GetSanitizers()).Count; + } + [Fact] public void TestReflectionModelBuild() { @@ -45,12 +48,12 @@ public void TestReflectionModelBuild() } [Fact] - public void TestReflectionModelWithAdvancedType() + public async void TestReflectionModelWithAdvancedType() { RecordingHandler testRecordingHandler = new RecordingHandler(Directory.GetCurrentDirectory()); var httpContext = new DefaultHttpContext(); - testRecordingHandler.SanitizerRegistry.Clear(); - testRecordingHandler.SanitizerRegistry.Register(new GeneralRegexSanitizer(value: "A new value", condition: new ApplyCondition() { UriRegex= ".+/Tables" })); + await testRecordingHandler.SanitizerRegistry.Clear(); + await testRecordingHandler.SanitizerRegistry.Register(new GeneralRegexSanitizer(value: "A new value", condition: new ApplyCondition() { UriRegex= ".+/Tables" })); var controller = new Info(testRecordingHandler) { @@ -74,24 +77,26 @@ public async Task TestReflectionModelWithTargetRecordSession() var recordingId = httpContext.Response.Headers["x-recording-id"].ToString(); - testRecordingHandler.RegisterSanitizer(new UriRegexSanitizer(regex: "ABC123"), recordingId); - testRecordingHandler.RegisterSanitizer(new BodyRegexSanitizer(regex: ".+?"), recordingId); + await testRecordingHandler.RegisterSanitizer(new UriRegexSanitizer(regex: "ABC123"), recordingId); + await testRecordingHandler.RegisterSanitizer(new BodyRegexSanitizer(regex: ".+?"), recordingId); testRecordingHandler.SetMatcherForRecording(recordingId, new CustomDefaultMatcher(compareBodies: false, excludedHeaders: "an-excluded-header")); var model = new ActiveMetadataModel(testRecordingHandler, recordingId); var descriptions = model.Descriptions.ToList(); + int defaultExtensionCount = await GetDefaultExtensionCount(); + // we should have exactly DefaultExtensionCount + 2 if we're counting all the customizations appropriately - Assert.True(descriptions.Count == DefaultExtensionCount + 3); + Assert.True(descriptions.Count == defaultExtensionCount + 3); Assert.True(model.Matchers.Count() == 1); - Assert.True(model.Sanitizers.Count() == DefaultExtensionCount + 2); + Assert.True(model.Sanitizers.Count() == defaultExtensionCount + 2); // confirm that the overridden matcher is showing up - Assert.True(descriptions[DefaultExtensionCount].ConstructorDetails.Arguments[1].Item2 == "\"ABC123\""); - Assert.True(descriptions[DefaultExtensionCount + 1].ConstructorDetails.Arguments[1].Item2 == "\".+?\""); + Assert.True(descriptions[defaultExtensionCount].ConstructorDetails.Arguments[1].Item2 == "\"ABC123\""); + Assert.True(descriptions[defaultExtensionCount + 1].ConstructorDetails.Arguments[1].Item2 == "\".+?\""); // and finally confirm our sanitizers are what we expect - Assert.True(descriptions[DefaultExtensionCount + 2].Name == "CustomDefaultMatcher"); + Assert.True(descriptions[defaultExtensionCount + 2].Name == "CustomDefaultMatcher"); } } } diff --git a/tools/test-proxy/Azure.Sdk.Tools.TestProxy.Tests/LoggingTests.cs b/tools/test-proxy/Azure.Sdk.Tools.TestProxy.Tests/LoggingTests.cs index c42ab33783a..24af1277aa2 100644 --- a/tools/test-proxy/Azure.Sdk.Tools.TestProxy.Tests/LoggingTests.cs +++ b/tools/test-proxy/Azure.Sdk.Tools.TestProxy.Tests/LoggingTests.cs @@ -52,7 +52,7 @@ public async Task PlaybackLogsSanitizedRequest() HttpResponse response = new DefaultHttpContext().Response; await testRecordingHandler.HandlePlaybackRequest(recordingId, request, response); - AssertLogs(logger, 5, 9, 12); + AssertLogs(logger, 4, 8, 12); } finally { @@ -88,7 +88,7 @@ public async Task RecordingHandlerLogsSanitizedRequests() var recordingId = httpContext.Response.Headers["x-recording-id"].ToString(); await testRecordingHandler.HandleRecordRequestAsync(recordingId, request, httpContext.Response); - testRecordingHandler.StopRecording(recordingId); + await testRecordingHandler.StopRecording(recordingId); try { diff --git a/tools/test-proxy/Azure.Sdk.Tools.TestProxy.Tests/PlaybackTests.cs b/tools/test-proxy/Azure.Sdk.Tools.TestProxy.Tests/PlaybackTests.cs index 73c67f044d3..b4a68b67967 100644 --- a/tools/test-proxy/Azure.Sdk.Tools.TestProxy.Tests/PlaybackTests.cs +++ b/tools/test-proxy/Azure.Sdk.Tools.TestProxy.Tests/PlaybackTests.cs @@ -63,7 +63,7 @@ public async void TestStartPlaybackInMemory() await recordController.Start(); var inMemId = recordContext.Response.Headers["x-recording-id"].ToString(); recordContext.Request.Headers["x-recording-id"] = new string[] { inMemId }; - recordController.Stop(); + await recordController.Stop(); // apply same recordingId when starting in-memory session var playbackContext = new DefaultHttpContext(); @@ -175,7 +175,7 @@ public async void TestStopPlaybackInMemory() await recordController.Start(); var inMemId = recordContext.Response.Headers["x-recording-id"].ToString(); recordContext.Request.Headers["x-recording-id"] = new string[] { inMemId }; - recordController.Stop(); + await recordController.Stop(); var playbackContext = new DefaultHttpContext(); playbackContext.Request.Headers["x-recording-id"] = inMemId; diff --git a/tools/test-proxy/Azure.Sdk.Tools.TestProxy.Tests/RecordSessionTests.cs b/tools/test-proxy/Azure.Sdk.Tools.TestProxy.Tests/RecordSessionTests.cs index c3562c89370..c0f902dc12a 100644 --- a/tools/test-proxy/Azure.Sdk.Tools.TestProxy.Tests/RecordSessionTests.cs +++ b/tools/test-proxy/Azure.Sdk.Tools.TestProxy.Tests/RecordSessionTests.cs @@ -163,7 +163,7 @@ public async Task CanRoundTripDockerDigest() var recordingId = ctx.Response.Headers["x-recording-id"].ToString(); var session = handler.RecordingSessions[recordingId]; session.Session.Entries.Add(testEntry); - handler.StopRecording(recordingId); + await handler.StopRecording(recordingId); // now load it, did we avoid mangling it? var sessionFromDisk = TestHelpers.LoadRecordSession(Path.Combine(testFolder, testName)); @@ -630,14 +630,14 @@ public void RecordMatcherThrowsExceptionsWhenNoRecordsLeft() } [Fact] - public void RecordingSessionSanitizeSanitizesVariables() + public async Task RecordingSessionSanitizeSanitizesVariables() { var sanitizer = new TestSanitizer(); var session = new RecordSession(); session.Variables["A"] = "secret"; session.Variables["B"] = "Totally not a secret"; - session.Sanitize(sanitizer); + await session.Sanitize(sanitizer); Assert.Equal("SANITIZED", session.Variables["A"]); Assert.Equal("Totally not a SANITIZED", session.Variables["B"]); diff --git a/tools/test-proxy/Azure.Sdk.Tools.TestProxy.Tests/RecordTests.cs b/tools/test-proxy/Azure.Sdk.Tools.TestProxy.Tests/RecordTests.cs index 82fdb96b679..8259e4ea09b 100644 --- a/tools/test-proxy/Azure.Sdk.Tools.TestProxy.Tests/RecordTests.cs +++ b/tools/test-proxy/Azure.Sdk.Tools.TestProxy.Tests/RecordTests.cs @@ -89,7 +89,7 @@ public async Task TestStopRecordingSimple(string targetFile, string additionalEn httpContext.Request.Headers["x-recording-skip"] = additionalEntryModeHeader; } - controller.Stop(); + await controller.Stop(); if (string.IsNullOrEmpty(additionalEntryModeHeader)) { @@ -129,8 +129,8 @@ public async Task TestStopRecordingThrowsOnInvalidSkipValue() httpContext.Request.Headers["x-recording-skip"] = additionalEntryModeHeader; - var resultingException = Assert.Throws( - () => controller.Stop() + var resultingException = await Assert.ThrowsAsync( + async () => await controller.Stop() ); Assert.Equal("When stopping a recording and providing a \"x-recording-skip\" value, only value \"request-response\" is accepted.", resultingException.Message); @@ -162,7 +162,7 @@ public async Task TestStopRecordingInMemory(string additionalEntryModeHeader) recordContext.Request.Headers["x-recording-skip"] = additionalEntryModeHeader; } - recordController.Stop(); + await recordController.Stop(); if (string.IsNullOrEmpty(additionalEntryModeHeader)) { diff --git a/tools/test-proxy/Azure.Sdk.Tools.TestProxy.Tests/RecordingHandlerTests.cs b/tools/test-proxy/Azure.Sdk.Tools.TestProxy.Tests/RecordingHandlerTests.cs index f2be9e6e9cb..5edb697dea3 100644 --- a/tools/test-proxy/Azure.Sdk.Tools.TestProxy.Tests/RecordingHandlerTests.cs +++ b/tools/test-proxy/Azure.Sdk.Tools.TestProxy.Tests/RecordingHandlerTests.cs @@ -81,7 +81,7 @@ enum CheckSkips Default = IncludeTransforms | IncludeSanitizers | IncludeMatcher } - private void _checkDefaultExtensions(RecordingHandler handlerForTest, CheckSkips skipsToCheck = CheckSkips.Default) + private async Task _checkDefaultExtensions(RecordingHandler handlerForTest, CheckSkips skipsToCheck = CheckSkips.Default) { if (skipsToCheck.HasFlag(CheckSkips.IncludeTransforms)) { @@ -100,7 +100,7 @@ private void _checkDefaultExtensions(RecordingHandler handlerForTest, CheckSkips if (skipsToCheck.HasFlag(CheckSkips.IncludeSanitizers)) { - var sanitizers = handlerForTest.SanitizerRegistry.GetSanitizers(); + var sanitizers = await handlerForTest.SanitizerRegistry.GetSanitizers(); Assert.Equal(DefaultExtensionCount, sanitizers.Count); Assert.IsType(sanitizers[0]); @@ -167,35 +167,35 @@ public void TestGetHeaderSilentOnAcceptableHeaderMiss() } [Fact] - public void TestResetAfterAddition() + public async Task TestResetAfterAddition() { // arrange RecordingHandler testRecordingHandler = new RecordingHandler(Directory.GetCurrentDirectory()); // act - testRecordingHandler.SanitizerRegistry.Register(new BodyRegexSanitizer("sanitized", ".*")); + await testRecordingHandler.SanitizerRegistry.Register(new BodyRegexSanitizer("sanitized", ".*")); testRecordingHandler.Matcher = new BodilessMatcher(); testRecordingHandler.Transforms.Add(new ApiVersionTransform()); - testRecordingHandler.SetDefaultExtensions(); + await testRecordingHandler.SetDefaultExtensions(); //assert - _checkDefaultExtensions(testRecordingHandler); + await _checkDefaultExtensions(testRecordingHandler); } [Fact] - public void TestResetAfterRemoval() + public async Task TestResetAfterRemoval() { // arrange RecordingHandler testRecordingHandler = new RecordingHandler(Directory.GetCurrentDirectory()); // act - testRecordingHandler.SanitizerRegistry.Clear(); + await testRecordingHandler.SanitizerRegistry.Clear(); testRecordingHandler.Matcher = null; testRecordingHandler.Transforms.Clear(); - testRecordingHandler.SetDefaultExtensions(); + await testRecordingHandler.SetDefaultExtensions(); //assert - _checkDefaultExtensions(testRecordingHandler); + await _checkDefaultExtensions(testRecordingHandler); } [Fact] @@ -206,18 +206,18 @@ public async Task TestResetTargetsRecordingOnly() await testRecordingHandler.StartRecordingAsync("recordingings/cool.json", httpContext.Response); var recordingId = httpContext.Response.Headers["x-recording-id"].ToString(); - testRecordingHandler.SanitizerRegistry.Clear(); - testRecordingHandler.SanitizerRegistry.Register(new BodyRegexSanitizer("sanitized", ".*")); - testRecordingHandler.RegisterSanitizer(new GeneralRegexSanitizer("sanitized", ".*"), recordingId); - testRecordingHandler.SetDefaultExtensions(recordingId); + await testRecordingHandler.SanitizerRegistry.Clear(); + await testRecordingHandler.SanitizerRegistry.Register(new BodyRegexSanitizer("sanitized", ".*")); + await testRecordingHandler.RegisterSanitizer(new GeneralRegexSanitizer("sanitized", ".*"), recordingId); + await testRecordingHandler.SetDefaultExtensions(recordingId); var session = testRecordingHandler.RecordingSessions.First().Value; var recordingSanitizers = testRecordingHandler.SanitizerRegistry.GetSanitizers(session); - var sessionSanitizers = testRecordingHandler.SanitizerRegistry.GetSanitizers(); + var sessionSanitizers = await testRecordingHandler.SanitizerRegistry.GetSanitizers(); // session sanitizer is still set to a single one Assert.Single(sessionSanitizers); Assert.IsType(sessionSanitizers[0]); - _checkDefaultExtensions(testRecordingHandler, CheckSkips.IncludeMatcher | CheckSkips.IncludeTransforms); + await _checkDefaultExtensions(testRecordingHandler, CheckSkips.IncludeMatcher | CheckSkips.IncludeTransforms); Assert.Equal(session.AppliedSanitizers, testRecordingHandler.SanitizerRegistry.SessionSanitizers); Assert.Empty(session.AdditionalTransforms); Assert.Null(session.CustomMatcher); @@ -231,22 +231,22 @@ public async Task TestResetTargetsSessionOnly() await testRecordingHandler.StartRecordingAsync("recordingings/cool.json", httpContext.Response); var recordingId = httpContext.Response.Headers["x-recording-id"].ToString(); - testRecordingHandler.SanitizerRegistry.Clear(); - testRecordingHandler.SanitizerRegistry.Register(new BodyRegexSanitizer("sanitized", ".*")); + await testRecordingHandler.SanitizerRegistry.Clear(); + await testRecordingHandler.SanitizerRegistry.Register(new BodyRegexSanitizer("sanitized", ".*")); testRecordingHandler.Transforms.Clear(); - testRecordingHandler.RegisterSanitizer(new GeneralRegexSanitizer("sanitized", ".*"), recordingId); - testRecordingHandler.SetDefaultExtensions(recordingId); + await testRecordingHandler.RegisterSanitizer(new GeneralRegexSanitizer("sanitized", ".*"), recordingId); + await testRecordingHandler.SetDefaultExtensions(recordingId); var session = testRecordingHandler.RecordingSessions.First().Value; // check that the individual session had reset sanitizers - Assert.Equal(testRecordingHandler.SanitizerRegistry.GetSanitizers(), testRecordingHandler.SanitizerRegistry.GetSanitizers(session)); + Assert.Equal(await testRecordingHandler.SanitizerRegistry.GetSanitizers(), await testRecordingHandler.SanitizerRegistry.GetSanitizers(session)); // stop the recording to clear out the session cache - testRecordingHandler.StopRecording(recordingId); + await testRecordingHandler.StopRecording(recordingId); // then verify that the session level is NOT reset. - Assert.Single(testRecordingHandler.SanitizerRegistry.GetSanitizers()); - Assert.IsType(testRecordingHandler.SanitizerRegistry.GetSanitizers().First()); + Assert.Single(await testRecordingHandler.SanitizerRegistry.GetSanitizers()); + Assert.IsType((await testRecordingHandler.SanitizerRegistry.GetSanitizers()).First()); } [Fact] @@ -257,8 +257,8 @@ public async Task TestResetExtensionsFailsWithActiveSessions() await testRecordingHandler.StartRecordingAsync("recordingings/cool.json", httpContext.Response); var recordingId = httpContext.Response.Headers["x-recording-id"].ToString(); - var assertion = Assert.Throws( - () => testRecordingHandler.SetDefaultExtensions() + var assertion = await Assert.ThrowsAsync( + async () => await testRecordingHandler.SetDefaultExtensions() ); Assert.StartsWith("There are a total of 1 active sessions. Remove these sessions before hitting Admin/Reset.", assertion.Message); @@ -337,7 +337,7 @@ public async Task TestWriteAbsoluteRecording() await recordingHandler.StartRecordingAsync(pathToRecording, httpContext.Response); var sessionId = httpContext.Response.Headers["x-recording-id"].ToString(); - recordingHandler.StopRecording(sessionId); + await recordingHandler.StopRecording(sessionId); try { @@ -360,7 +360,7 @@ public async Task TestWriteRelativeRecording() await recordingHandler.StartRecordingAsync(pathToRecording, httpContext.Response); var sessionId = httpContext.Response.Headers["x-recording-id"].ToString(); - recordingHandler.StopRecording(sessionId); + await recordingHandler.StopRecording(sessionId); try @@ -393,7 +393,7 @@ public async Task TestCanSkipRecordingRequestBody() CreateRecordModeRequest(httpContext, "request-body"); await recordingHandler.HandleRecordRequestAsync(sessionId, httpContext.Request, httpContext.Response); - recordingHandler.StopRecording(sessionId); + await recordingHandler.StopRecording(sessionId); try { @@ -441,7 +441,7 @@ public async Task TestCanSkipRecordingEntireRequestResponse() httpContext.Request.Body = TestHelpers.GenerateStreamRequestBody("{ \"key\": \"value\" }"); await recordingHandler.HandleRecordRequestAsync(sessionId, httpContext.Request, httpContext.Response); - recordingHandler.StopRecording(sessionId); + await recordingHandler.StopRecording(sessionId); try { @@ -545,7 +545,7 @@ public async Task TestStopRecordingWithVariables() await recordingHandler.StartRecordingAsync(pathToRecording, startHttpContext.Response); var sessionId = startHttpContext.Response.Headers["x-recording-id"].ToString(); - recordingHandler.StopRecording(sessionId, variables: new SortedDictionary(dict)); + await recordingHandler.StopRecording(sessionId, variables: new SortedDictionary(dict)); var storedVariables = TestHelpers.LoadRecordSession(Path.Combine(tmpPath, pathToRecording)).Session.Variables; Assert.Equal(dict.Count, storedVariables.Count); @@ -566,7 +566,7 @@ public async Task TestStopRecordingWithoutVariables() await recordingHandler.StartRecordingAsync(pathToRecording, httpContext.Response); var sessionId = httpContext.Response.Headers["x-recording-id"].ToString(); - recordingHandler.StopRecording(sessionId, variables: new SortedDictionary()); + await recordingHandler.StopRecording(sessionId, variables: new SortedDictionary()); var storedVariables = TestHelpers.LoadRecordSession(Path.Combine(tmpPath, pathToRecording)).Session.Variables; @@ -583,7 +583,7 @@ public async Task TestStopRecordingNullVariables() await recordingHandler.StartRecordingAsync(pathToRecording, httpContext.Response); var sessionId = httpContext.Response.Headers["x-recording-id"].ToString(); - recordingHandler.StopRecording(sessionId, variables: null); + await recordingHandler.StopRecording(sessionId, variables: null); var storedVariables = TestHelpers.LoadRecordSession(Path.Combine(tmpPath, pathToRecording)).Session.Variables; @@ -734,7 +734,7 @@ public async Task TestRecordWithGZippedContent() httpContext.Request.Body = new MemoryStream(CompressionUtilities.CompressBody(bodyBytes, httpContext.Request.Headers)); await recordingHandler.HandleRecordRequestAsync(recordingId, httpContext.Request, httpContext.Response); - recordingHandler.StopRecording(recordingId); + await recordingHandler.StopRecording(recordingId); try { diff --git a/tools/test-proxy/Azure.Sdk.Tools.TestProxy.Tests/SanitizerTests.cs b/tools/test-proxy/Azure.Sdk.Tools.TestProxy.Tests/SanitizerTests.cs index d26089f1d32..47b322f9c1d 100644 --- a/tools/test-proxy/Azure.Sdk.Tools.TestProxy.Tests/SanitizerTests.cs +++ b/tools/test-proxy/Azure.Sdk.Tools.TestProxy.Tests/SanitizerTests.cs @@ -8,6 +8,7 @@ using System.IO; using System.Linq; using System.Reflection; +using System.Runtime.CompilerServices; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; @@ -27,61 +28,61 @@ public class SanitizerTests public string scopeClean = @"scope\=(?[^&]*)"; [Fact] - public void OauthResponseSanitizerCleansV2AuthRequest() + public async void OauthResponseSanitizerCleansV2AuthRequest() { var session = TestHelpers.LoadRecordSession("Test.RecordEntries/oauth_request.json"); - - session.Session.Sanitize(OAuthResponseSanitizer); + + await session.Session.Sanitize(OAuthResponseSanitizer); Assert.Empty(session.Session.Entries); } [Fact] - public void SanitizerDecodesUnicodeAmpersandSanitizesClientIdAndSecret() + public async void SanitizerDecodesUnicodeAmpersandSanitizesClientIdAndSecret() { var session = TestHelpers.LoadRecordSession("Test.RecordEntries/request_with_encoding.json"); var clientSan = new BodyRegexSanitizer(regex: "(client_id=)(?[^&\\\"]+)", groupForReplace: "cid"); var secretSan = new BodyRegexSanitizer(regex: "client_secret=(?[^&\\\"]+)", groupForReplace: "secret"); - session.Session.Sanitize(clientSan); - session.Session.Sanitize(secretSan); + await session.Session.Sanitize(clientSan); + await session.Session.Sanitize(secretSan); Assert.Equal("client_id=Sanitized&grant_type=client_credentials&client_info=1&client_secret=Sanitized&claims=%7B%22access_token=blahblah", Encoding.UTF8.GetString(session.Session.Entries[0].Request.Body)); } [Fact] - public void EnsureSASCleanupDoesntOverrunInXML() + public async void EnsureSASCleanupDoesntOverrunInXML() { var sanitizerDictionary = new SanitizerDictionary(); var sessionwithXmlBody = TestHelpers.LoadRecordSession("Test.RecordEntries/xml_body_with_sas_present.json"); Assert.True(sanitizerDictionary.Sanitizers.TryGetValue("AZSDK1007", out RegisteredSanitizer SASURISanitizer)); - sessionwithXmlBody.Session.Sanitize(SASURISanitizer.Sanitizer); + await sessionwithXmlBody.Session.Sanitize(SASURISanitizer.Sanitizer); Assert.Contains("1024/1024", Encoding.UTF8.GetString(sessionwithXmlBody.Session.Entries[0].Response.Body)); } [Fact] - public void OauthResponseSanitizerCleansNonV2AuthRequest() + public async void OauthResponseSanitizerCleansNonV2AuthRequest() { var session = TestHelpers.LoadRecordSession("Test.RecordEntries/oauth_request.json"); session.Session.Entries[0].RequestUri = "https://login.microsoftonline.com/12345678-1234-1234-1234-123456789012/oauth2/token"; - session.Session.Sanitize(OAuthResponseSanitizer); + await session.Session.Sanitize(OAuthResponseSanitizer); Assert.Empty(session.Session.Entries); } [Fact] - public void OauthResponseSanitizerNotAggressive() + public async void OauthResponseSanitizerNotAggressive() { var session = TestHelpers.LoadRecordSession("Test.RecordEntries/post_delete_get_content.json"); var expectedCount = session.Session.Entries.Count; - session.Session.Sanitize(OAuthResponseSanitizer); + await session.Session.Sanitize(OAuthResponseSanitizer); Assert.Equal(expectedCount, session.Session.Entries.Count); } @@ -90,13 +91,13 @@ public void OauthResponseSanitizerNotAggressive() [InlineData("uri", "\"/oauth2(?:/v2.0)?/token\"")] [InlineData("body", "\"/oauth2(?:/v2.0)?/token\"")] [InlineData("header", "\"/oauth2(?:/v2.0)?/token\"")] - public void RegexEntrySanitizerNoOpsOnNonMatch(string target, string regex) + public async void RegexEntrySanitizerNoOpsOnNonMatch(string target, string regex) { var session = TestHelpers.LoadRecordSession("Test.RecordEntries/post_delete_get_content.json"); var sanitizer = new RegexEntrySanitizer(target, regex); var expectedCount = session.Session.Entries.Count; - session.Session.Sanitize(sanitizer); + await session.Session.Sanitize(sanitizer); Assert.Equal(expectedCount, session.Session.Entries.Count); } @@ -106,25 +107,25 @@ public void RegexEntrySanitizerNoOpsOnNonMatch(string target, string regex) [InlineData("uri", "fakeazsdktestaccount", 0)] [InlineData("body", "listtable09bf2a3d", 10)] [InlineData("header", "a50f2f9c-b830-11eb-b8c8-10e7c6392c5a", 10)] - public void RegexEntrySanitizerCorrectlySanitizes(string target, string regex, int endCount) + public async void RegexEntrySanitizerCorrectlySanitizes(string target, string regex, int endCount) { var session = TestHelpers.LoadRecordSession("Test.RecordEntries/post_delete_get_content.json"); var sanitizer = new RegexEntrySanitizer(target, regex); var expectedCount = session.Session.Entries.Count; - session.Session.Sanitize(sanitizer); + await session.Session.Sanitize(sanitizer); Assert.Equal(endCount, session.Session.Entries.Count); } [Fact] - public void RegexEntrySanitizerCorrectlySanitizesSpecific() + public async void RegexEntrySanitizerCorrectlySanitizesSpecific() { var session = TestHelpers.LoadRecordSession("Test.RecordEntries/response_with_xml_body.json"); var sanitizer = new RegexEntrySanitizer("header", "b24f75a9-b830-11eb-b949-10e7c6392c5a"); var expectedCount = session.Session.Entries.Count; - session.Session.Sanitize(sanitizer); + await session.Session.Sanitize(sanitizer); Assert.Equal(2, session.Session.Entries.Count); Assert.Equal("b25bf92a-b830-11eb-947a-10e7c6392c5a", session.Session.Entries[0].Request.Headers["x-ms-client-request-id"][0].ToString()); @@ -152,7 +153,7 @@ public async Task RegexEntrySanitizerCreatesOverAPI(string body) { RecordingHandler testRecordingHandler = new RecordingHandler(Directory.GetCurrentDirectory()); - testRecordingHandler.SanitizerRegistry.Clear(); + await testRecordingHandler.SanitizerRegistry.Clear(); var httpContext = new DefaultHttpContext(); httpContext.Request.Headers["x-abstraction-identifier"] = "RegexEntrySanitizer"; httpContext.Request.Body = TestHelpers.GenerateStreamRequestBody(body); @@ -169,7 +170,7 @@ public async Task RegexEntrySanitizerCreatesOverAPI(string body) }; await controller.AddSanitizer(); - var sanitizer = testRecordingHandler.SanitizerRegistry.GetSanitizers()[0]; + var sanitizer = (await testRecordingHandler.SanitizerRegistry.GetSanitizers())[0]; Assert.True(sanitizer is RegexEntrySanitizer); @@ -179,13 +180,13 @@ public async Task RegexEntrySanitizerCreatesOverAPI(string body) [Fact] - public void UriRegexSanitizerReplacesTableName() + public async void UriRegexSanitizerReplacesTableName() { var session = TestHelpers.LoadRecordSession("Test.RecordEntries/post_delete_get_content.json"); var originalValue = session.Session.Entries[0].RequestUri; var uriSanitizer = new UriRegexSanitizer(value: "fakeaccount", regex: lookaheadReplaceRegex); - session.Session.Sanitize(uriSanitizer); + await session.Session.Sanitize(uriSanitizer); var testValue = session.Session.Entries[0].RequestUri; @@ -194,13 +195,13 @@ public void UriRegexSanitizerReplacesTableName() } [Fact] - public void UriRegexSanitizerAggressivenessCheck() + public async void UriRegexSanitizerAggressivenessCheck() { var session = TestHelpers.LoadRecordSession("Test.RecordEntries/oauth_request.json"); var originalValue = session.Session.Entries[0].RequestUri; var uriSanitizer = new UriRegexSanitizer(value: "fakeaccount", regex: lookaheadReplaceRegex); - session.Session.Sanitize(uriSanitizer); + await session.Session.Sanitize(uriSanitizer); var testValue = session.Session.Entries[0].RequestUri; @@ -209,7 +210,7 @@ public void UriRegexSanitizerAggressivenessCheck() [Fact] - public void GeneralRegexSanitizerAppliesToAllSets() + public async void GeneralRegexSanitizerAppliesToAllSets() { // arrange var session = TestHelpers.LoadRecordSession("Test.RecordEntries/post_delete_get_content.json"); @@ -229,8 +230,8 @@ public void GeneralRegexSanitizerAppliesToAllSets() var accountNameSanitizer = new GeneralRegexSanitizer(value: genericAValue, regex: realAValue); // act - session.Session.Sanitize(tableNameSanitizer); - session.Session.Sanitize(accountNameSanitizer); + await session.Session.Sanitize(tableNameSanitizer); + await session.Session.Sanitize(accountNameSanitizer); var locationHeaderValue = targetEntry.Response.Headers["Location"].First(); // assert that we successfully changed a header, the body, and the uri @@ -255,14 +256,14 @@ public void GeneralRegexSanitizerAppliesToAllSets() } [Fact] - public void ReplaceRequestSubscriptionId() + public async void voidReplaceRequestSubscriptionId() { var session = TestHelpers.LoadRecordSession("Test.RecordEntries/request_with_subscriptionid.json"); var targetEntry = session.Session.Entries.First(); var originalUri = targetEntry.RequestUri.ToString(); var subscriptionIdReplaceSanitizer = new UriSubscriptionIdSanitizer(); - session.Session.Sanitize(subscriptionIdReplaceSanitizer); + await session.Session.Sanitize(subscriptionIdReplaceSanitizer); var sanitizedUri = targetEntry.RequestUri; Assert.NotEqual(originalUri, sanitizedUri); @@ -272,14 +273,14 @@ public void ReplaceRequestSubscriptionId() } [Fact] - public void ReplaceRequestSubscriptionIdNoAction() + public async void ReplaceRequestSubscriptionIdNoAction() { var session = TestHelpers.LoadRecordSession("Test.RecordEntries/oauth_request.json"); var targetEntry = session.Session.Entries.First(); var originalUri = targetEntry.RequestUri.ToString(); var subscriptionIdReplaceSanitizer = new UriSubscriptionIdSanitizer(); - session.Session.Sanitize(subscriptionIdReplaceSanitizer); + await session.Session.Sanitize(subscriptionIdReplaceSanitizer); var sanitizedUri = targetEntry.RequestUri; // no action should have taken place here. @@ -287,7 +288,7 @@ public void ReplaceRequestSubscriptionIdNoAction() } [Fact] - public void HeaderRegexSanitizerSimpleReplace() + public async void HeaderRegexSanitizerSimpleReplace() { var session = TestHelpers.LoadRecordSession("Test.RecordEntries/post_delete_get_content.json"); var targetEntry = session.Session.Entries[0]; @@ -296,7 +297,7 @@ public void HeaderRegexSanitizerSimpleReplace() // where we have a key, a regex, and no groupname. var headerRegexSanitizer = new HeaderRegexSanitizer(targetKey, value: "fakeaccount", regex: lookaheadReplaceRegex); - session.Session.Sanitize(headerRegexSanitizer); + await session.Session.Sanitize(headerRegexSanitizer); var testValue = targetEntry.Response.Headers[targetKey].First(); @@ -306,35 +307,35 @@ public void HeaderRegexSanitizerSimpleReplace() [Fact] - public void HeaderRegexSanitizerMultipartReplace() + public async void HeaderRegexSanitizerMultipartReplace() { var session = TestHelpers.LoadRecordSession("Test.RecordEntries/multipart_header.json"); var targetEntry = session.Session.Entries[0]; var targetKey = "Cookie"; var headerRegexSanitizer = new HeaderRegexSanitizer(targetKey, value: "REDACTED", regex: "SuperDifferent"); - session.Session.Sanitize(headerRegexSanitizer); + await session.Session.Sanitize(headerRegexSanitizer); Assert.Equal("REDACTEDCookie", targetEntry.Request.Headers[targetKey][0]); Assert.Equal("KindaDifferentCookie", targetEntry.Request.Headers[targetKey][1]); } [Fact] - public void HeaderRegexSanitizerMultipartReplaceLatterOnly() + public async void HeaderRegexSanitizerMultipartReplaceLatterOnly() { var session = TestHelpers.LoadRecordSession("Test.RecordEntries/multipart_header.json"); var targetEntry = session.Session.Entries[0]; var targetKey = "Cookie"; var headerRegexSanitizer = new HeaderRegexSanitizer(targetKey, value: "REDACTED", regex: "KindaDifferent"); - session.Session.Sanitize(headerRegexSanitizer); + await session.Session.Sanitize(headerRegexSanitizer); Assert.Equal("SuperDifferentCookie", targetEntry.Request.Headers[targetKey][0]); Assert.Equal("REDACTEDCookie", targetEntry.Request.Headers[targetKey][1]); } [Fact] - public void HeaderRegexSanitizerGroupedRegexReplace() + public async void HeaderRegexSanitizerGroupedRegexReplace() { var session = TestHelpers.LoadRecordSession("Test.RecordEntries/post_delete_get_content.json"); var targetKey = "Location"; @@ -343,7 +344,7 @@ public void HeaderRegexSanitizerGroupedRegexReplace() // where we have a key, a regex, and a groupname to replace with value Y var headerRegexSanitizer = new HeaderRegexSanitizer(targetKey, value: "fakeaccount", regex: capturingGroupReplaceRegex, groupForReplace: "account"); - session.Session.Sanitize(headerRegexSanitizer); + await session.Session.Sanitize(headerRegexSanitizer); var testValue = targetEntry.Response.Headers[targetKey].First(); @@ -352,7 +353,7 @@ public void HeaderRegexSanitizerGroupedRegexReplace() } [Fact] - public void HeaderRegexSanitizerAggressivenessCheck() + public async void HeaderRegexSanitizerAggressivenessCheck() { var session = TestHelpers.LoadRecordSession("Test.RecordEntries/post_delete_get_content.json"); var targetEntry = session.Session.Entries[0]; @@ -361,7 +362,7 @@ public void HeaderRegexSanitizerAggressivenessCheck() // where we find a key, but there is nothing to be done by the sanitizer var headerRegexSanitizer = new HeaderRegexSanitizer(targetKey, value: "fakeaccount", regex: capturingGroupReplaceRegex, groupForReplace: "account"); - session.Session.Sanitize(headerRegexSanitizer); + await session.Session.Sanitize(headerRegexSanitizer); var newResult = targetEntry.Response.Headers[targetKey].First(); @@ -369,7 +370,7 @@ public void HeaderRegexSanitizerAggressivenessCheck() } [Fact] - public void BodyRegexSanitizerCleansJSON() + public async void BodyRegexSanitizerCleansJSON() { var session = TestHelpers.LoadRecordSession("Test.RecordEntries/post_delete_get_content.json"); var targetEntry = session.Session.Entries[0]; @@ -377,19 +378,19 @@ public void BodyRegexSanitizerCleansJSON() var replaceTableNameRegex = "TableName\"\\s*:\\s*\"(?[a-z0-9]+)\""; var bodyRegexSanitizer = new BodyRegexSanitizer(value: "afaketable", regex: replaceTableNameRegex, groupForReplace: "tablename"); - session.Session.Sanitize(bodyRegexSanitizer); + await session.Session.Sanitize(bodyRegexSanitizer); Assert.Contains("\"TableName\":\"afaketable\"", Encoding.UTF8.GetString(targetEntry.Response.Body)); } [Fact] - public void BodyRegexSanitizerCleansText() + public async void BodyRegexSanitizerCleansText() { var session = TestHelpers.LoadRecordSession("Test.RecordEntries/oauth_request.json"); var targetEntry = session.Session.Entries[0]; var bodyRegexSanitizer = new BodyRegexSanitizer(value: "sanitized.scope", regex: scopeClean, groupForReplace: "scope"); - session.Session.Sanitize(bodyRegexSanitizer); + await session.Session.Sanitize(bodyRegexSanitizer); var expectedBodyStartsWith = "scope=sanitized.scope&client_id"; @@ -397,66 +398,66 @@ public void BodyRegexSanitizerCleansText() } [Fact] - public void BodyRegexSanitizerIgnoresNonTextualBodies() + public async void BodyRegexSanitizerIgnoresNonTextualBodies() { var session = TestHelpers.LoadRecordSession("Test.RecordEntries/request_with_binary_content.json"); var targetEntry = session.Session.Entries[0]; var content = Encoding.UTF8.GetString(targetEntry.Request.Body); var bodyRegexSanitizer = new BodyRegexSanitizer(regex: ".*"); - session.Session.Sanitize(bodyRegexSanitizer); + await session.Session.Sanitize(bodyRegexSanitizer); Assert.Equal(content, Encoding.UTF8.GetString(targetEntry.Request.Body)); } [Fact] - public void BodyRegexSanitizerQuietlyExits() + public async void BodyRegexSanitizerQuietlyExits() { var session = TestHelpers.LoadRecordSession("Test.RecordEntries/post_delete_get_content.json"); var targetEntry = session.Session.Entries[0]; var beforeUpdate = targetEntry.Request.Body; var bodyRegexSanitizer = new BodyRegexSanitizer(value: "fakeaccount", regex: capturingGroupReplaceRegex, groupForReplace: "account"); - session.Session.Sanitize(bodyRegexSanitizer); + await session.Session.Sanitize(bodyRegexSanitizer); Assert.Equal(beforeUpdate, targetEntry.Request.Body); } [Fact] - public void RemoveHeaderSanitizerQuietlyExits() + public async void RemoveHeaderSanitizerQuietlyExits() { var session = TestHelpers.LoadRecordSession("Test.RecordEntries/post_delete_get_content.json"); var targetEntry = session.Session.Entries[0]; var requestHeaderCountBefore = targetEntry.Request.Headers.Count; var removeHeaderSanitizer = new RemoveHeaderSanitizer(headersForRemoval: "fakeaccount"); - session.Session.Sanitize(removeHeaderSanitizer); + await session.Session.Sanitize(removeHeaderSanitizer); Assert.Equal(requestHeaderCountBefore, targetEntry.Request.Headers.Count); } [Fact] - public void RemoveHeaderSanitizerRemovesSingleHeader() + public async void RemoveHeaderSanitizerRemovesSingleHeader() { var session = TestHelpers.LoadRecordSession("Test.RecordEntries/post_delete_get_content.json"); var targetEntry = session.Session.Entries[0]; var headerForRemoval = "DataServiceVersion"; var removeHeaderSanitizer = new RemoveHeaderSanitizer(headersForRemoval: headerForRemoval); - session.Session.Sanitize(removeHeaderSanitizer); + await session.Session.Sanitize(removeHeaderSanitizer); Assert.False(targetEntry.Request.Headers.ContainsKey(headerForRemoval)); } [Fact] - public void RemoveHeaderSanitizerRemovesMultipleHeaders() + public async void RemoveHeaderSanitizerRemovesMultipleHeaders() { var session = TestHelpers.LoadRecordSession("Test.RecordEntries/post_delete_get_content.json"); var targetEntry = session.Session.Entries[0]; var headerForRemoval = "DataServiceVersion, Date,User-Agent"; // please note the wonky spacing is intentional var removeHeaderSanitizer = new RemoveHeaderSanitizer(headersForRemoval: headerForRemoval); - session.Session.Sanitize(removeHeaderSanitizer); + await session.Session.Sanitize(removeHeaderSanitizer); foreach(var header in headerForRemoval.Split(",").Select(x => x.Trim())) { @@ -465,14 +466,14 @@ public void RemoveHeaderSanitizerRemovesMultipleHeaders() } [Fact] - public void BodyKeySanitizerKeyReplace() + public async void BodyKeySanitizerKeyReplace() { var session = TestHelpers.LoadRecordSession("Test.RecordEntries/post_delete_get_content.json"); var targetEntry = session.Session.Entries[0]; var replacementValue = "sanitized.tablename"; var bodyKeySanitizer = new BodyKeySanitizer(jsonPath: "$.TableName", value: replacementValue); - session.Session.Sanitize(bodyKeySanitizer); + await session.Session.Sanitize(bodyKeySanitizer); var newBody = Encoding.UTF8.GetString(targetEntry.Request.Body); Assert.Contains(replacementValue, newBody); @@ -480,46 +481,46 @@ public void BodyKeySanitizerKeyReplace() } [Fact] - public void BodyKeySanitizerIgnoresNulls() + public async void BodyKeySanitizerIgnoresNulls() { var session = TestHelpers.LoadRecordSession("Test.RecordEntries/response_with_null_secrets.json"); var targetEntry = session.Session.Entries[0]; var replacementValue = "sanitized.tablename"; var originalBody = Encoding.UTF8.GetString(targetEntry.Request.Body); var bodyKeySanitizer = new BodyKeySanitizer(jsonPath: "$.connectionString", value: replacementValue); - session.Session.Sanitize(bodyKeySanitizer); + await session.Session.Sanitize(bodyKeySanitizer); var newBody = Encoding.UTF8.GetString(targetEntry.Request.Body); Assert.Equal(originalBody, newBody); } [Fact] - public void BodyKeySanitizerHandlesNonJSON() + public async void BodyKeySanitizerHandlesNonJSON() { var session = TestHelpers.LoadRecordSession("Test.RecordEntries/oauth_request.json"); var targetEntry = session.Session.Entries[0]; var replacementValue = "sanitized.tablename"; var bodyKeySanitizer = new BodyKeySanitizer(jsonPath: "$.TableName", value: replacementValue); - session.Session.Sanitize(bodyKeySanitizer); + await session.Session.Sanitize(bodyKeySanitizer); Assert.DoesNotContain(replacementValue, Encoding.UTF8.GetString(targetEntry.Request.Body)); } [Fact] - public void BodyKeySanitizerRegexReplace() + public async void BodyKeySanitizerRegexReplace() { var session = TestHelpers.LoadRecordSession("Test.RecordEntries/post_delete_get_content.json"); var targetEntry = session.Session.Entries[0]; var bodyKeySanitizer = new BodyKeySanitizer(jsonPath: "$.TableName", value: "TABLE_ID_IS_SANITIZED", regex: @"(?<=listtable)(?[a-z0-9]+)", groupForReplace: "tableid"); - session.Session.Sanitize(bodyKeySanitizer); + await session.Session.Sanitize(bodyKeySanitizer); Assert.Contains("listtableTABLE_ID_IS_SANITIZED", Encoding.UTF8.GetString(targetEntry.Response.Body)); } [Fact] - public void BodyKeySanitizerQuietlyExits() + public async void BodyKeySanitizerQuietlyExits() { var session = TestHelpers.LoadRecordSession("Test.RecordEntries/post_delete_get_content.json"); var targetEntry = session.Session.Entries[0]; @@ -527,7 +528,7 @@ public void BodyKeySanitizerQuietlyExits() var bodyKeySanitizer = new BodyKeySanitizer(jsonPath: "$.Location", value: replacementValue); var originalValue = Encoding.UTF8.GetString(targetEntry.Request.Body); - session.Session.Sanitize(bodyKeySanitizer); + await session.Session.Sanitize(bodyKeySanitizer); var newValue = Encoding.UTF8.GetString(targetEntry.Request.Body); Assert.DoesNotContain(replacementValue, newValue); @@ -536,14 +537,14 @@ public void BodyKeySanitizerQuietlyExits() [Fact] - public void ContinuationSanitizerSingleReplace() + public async void ContinuationSanitizerSingleReplace() { var session = TestHelpers.LoadRecordSession("Test.RecordEntries/requests_with_continuation.json"); var continueSanitizer = new ContinuationSanitizer("correlationId", "guid", resetAfterFirst: "false"); var targetKey = "correlationId"; var originalRequestGuid = session.Session.Entries[0].Response.Headers[targetKey].First(); - session.Session.Sanitize(continueSanitizer); + await session.Session.Sanitize(continueSanitizer); var firstRequest = session.Session.Entries[0].Response.Headers[targetKey].First(); var firstResponse = session.Session.Entries[1].Request.Headers[targetKey].First(); @@ -557,14 +558,14 @@ public void ContinuationSanitizerSingleReplace() } [Fact] - public void ContinuationSanitizerMultipleReplace() + public async void ContinuationSanitizerMultipleReplace() { var session = TestHelpers.LoadRecordSession("Test.RecordEntries/requests_with_continuation.json"); var continueSanitizer = new ContinuationSanitizer("correlationId", "guid", resetAfterFirst: "true"); var targetKey = "correlationId"; var originalSendGuid = session.Session.Entries[0].Response.Headers[targetKey].First(); - session.Session.Sanitize(continueSanitizer); + await session.Session.Sanitize(continueSanitizer); var firstRequest = session.Session.Entries[0].Response.Headers[targetKey].First(); var firstResponse = session.Session.Entries[1].Request.Headers[targetKey].First(); @@ -578,14 +579,14 @@ public void ContinuationSanitizerMultipleReplace() } [Fact] - public void ContinuationSanitizerNonExistentKey() + public async void ContinuationSanitizerNonExistentKey() { var session = TestHelpers.LoadRecordSession("Test.RecordEntries/requests_with_continuation.json"); var continueSanitizer = new ContinuationSanitizer("non-existent-key", "guid", resetAfterFirst: "true"); var targetKey = "correlationId"; var originalSendGuid = session.Session.Entries[0].Response.Headers[targetKey].First(); - session.Session.Sanitize(continueSanitizer); + await session.Session.Sanitize(continueSanitizer); var firstRequest = session.Session.Entries[0].Response.Headers[targetKey].First(); var firstResponse = session.Session.Entries[1].Request.Headers[targetKey].First(); @@ -599,13 +600,13 @@ public void ContinuationSanitizerNonExistentKey() } [Fact] - public void ConditionalSanitizeUriRegexAppliesForRegex() + public async void ConditionalSanitizeUriRegexAppliesForRegex() { var session = TestHelpers.LoadRecordSession("Test.RecordEntries/response_with_xml_body.json"); var targetHeader = "x-ms-version"; var removeHeadersSanitizer = new RemoveHeaderSanitizer(targetHeader, condition: new ApplyCondition() { UriRegex = @".+/Tables.*" }); - session.Session.Sanitize(removeHeadersSanitizer); + await session.Session.Sanitize(removeHeadersSanitizer); var firstEntry = session.Session.Entries[0]; // this entry should be untouched by sanitization, it's request URI should not match the regex above var secondEntry = session.Session.Entries[1]; @@ -617,18 +618,18 @@ public void ConditionalSanitizeUriRegexAppliesForRegex() } [Fact] - public void ConditionalSanitizeUriRegexProperlySkips() + public async void ConditionalSanitizeUriRegexProperlySkips() { var session = TestHelpers.LoadRecordSession("Test.RecordEntries/response_with_xml_body.json"); var targetHeader = "x-ms-version"; var removeHeadersSanitizer = new RemoveHeaderSanitizer(targetHeader, condition: new ApplyCondition() { UriRegex = @".+/token" }); - session.Session.Sanitize(removeHeadersSanitizer); + await session.Session.Sanitize(removeHeadersSanitizer); Assert.DoesNotContain(false, session.Session.Entries.Select(x => x.Request.Headers.ContainsKey(targetHeader))); } [Fact] - public void GenStringSanitizerAppliesForMultipleComponents() + public async void GenStringSanitizerAppliesForMultipleComponents() { var session = TestHelpers.LoadRecordSession("Test.RecordEntries/post_delete_get_content.json"); var targetString = "listtable09bf2a3d"; @@ -640,7 +641,7 @@ public void GenStringSanitizerAppliesForMultipleComponents() var originalLocation = targetEntry.Response.Headers["Location"].First().ToString(); var sanitizer = new GeneralStringSanitizer(targetString, replacementString); - session.Session.Sanitize(sanitizer); + await session.Session.Sanitize(sanitizer); var resultRequestBody = Encoding.UTF8.GetString(targetEntry.Request.Body); var resultResponseBody = Encoding.UTF8.GetString(targetEntry.Response.Body); @@ -651,12 +652,12 @@ public void GenStringSanitizerAppliesForMultipleComponents() Assert.NotEqual(originalRequestBody, resultRequestBody); Assert.DoesNotContain(targetString, resultRequestBody); Assert.Contains(replacementString, resultRequestBody); - + // result body Assert.NotEqual(originalResponseBody, resultResponseBody); Assert.DoesNotContain(targetString, resultResponseBody); Assert.Contains(replacementString, resultResponseBody); - + // uri Assert.NotEqual(originalLocation, resultLocation); Assert.DoesNotContain(targetString, resultLocation); @@ -664,7 +665,7 @@ public void GenStringSanitizerAppliesForMultipleComponents() } [Fact] - public void GenStringSanitizerQuietExitForAllHttpComponents() + public async void GenStringSanitizerQuietExitForAllHttpComponents() { var session = TestHelpers.LoadRecordSession("Test.RecordEntries/post_delete_get_content.json"); var untouchedSession = TestHelpers.LoadRecordSession("Test.RecordEntries/post_delete_get_content.json"); @@ -676,7 +677,7 @@ public void GenStringSanitizerQuietExitForAllHttpComponents() var matcher = new RecordMatcher(); var sanitizer = new GeneralStringSanitizer(targetString, replacementString); - session.Session.Sanitize(sanitizer); + await session.Session.Sanitize(sanitizer); var resultRequestBody = Encoding.UTF8.GetString(targetEntry.Request.Body); var resultResponseBody = Encoding.UTF8.GetString(targetEntry.Response.Body); @@ -697,15 +698,15 @@ public void GenStringSanitizerQuietExitForAllHttpComponents() [InlineData("Accept-Encoding", ",", "", "Test.RecordEntries/post_delete_get_content.json")] [InlineData("Accept", "*/*", "", "Test.RecordEntries/oauth_request_with_variables.json")] [InlineData("User-Agent", ".19041-SP0", "", "Test.RecordEntries/post_delete_get_content.json")] - public void HeaderStringSanitizerApplies(string targetKey, string targetValue, string replacementValue, string recordingFile) + public async void HeaderStringSanitizerApplies(string targetKey, string targetValue, string replacementValue, string recordingFile) { var session = TestHelpers.LoadRecordSession(recordingFile); var targetEntry = session.Session.Entries[0]; var originalHeaderValue = targetEntry.Request.Headers[targetKey].First().ToString(); - + var sanitizer = new HeaderStringSanitizer(targetKey, targetValue, value: replacementValue); - session.Session.Sanitize(sanitizer); - + await session.Session.Sanitize(sanitizer); + var resultHeaderValue = targetEntry.Request.Headers[targetKey].First().ToString(); Assert.NotEqual(resultHeaderValue, originalHeaderValue); @@ -715,7 +716,7 @@ public void HeaderStringSanitizerApplies(string targetKey, string targetValue, s [Theory] [InlineData("DataServiceVersion", "application/json", "", "Test.RecordEntries/post_delete_get_content.json")] - public void HeaderStringSanitizerQuietlyExits(string targetKey, string targetValue, string replacementValue, string recordingFile) + public async void HeaderStringSanitizerQuietlyExits(string targetKey, string targetValue, string replacementValue, string recordingFile) { var session = TestHelpers.LoadRecordSession(recordingFile); var untouchedSession = TestHelpers.LoadRecordSession(recordingFile); @@ -724,7 +725,7 @@ public void HeaderStringSanitizerQuietlyExits(string targetKey, string targetVal var matcher = new RecordMatcher(); var sanitizer = new HeaderStringSanitizer(targetKey, targetValue, value: replacementValue); - session.Session.Sanitize(sanitizer); + await session.Session.Sanitize(sanitizer); Assert.Equal(0, matcher.CompareHeaderDictionaries(targetUntouchedEntry.Request.Headers, targetEntry.Request.Headers, new HashSet(), new HashSet())); Assert.Equal(0, matcher.CompareHeaderDictionaries(targetUntouchedEntry.Response.Headers, targetEntry.Response.Headers, new HashSet(), new HashSet())); @@ -735,14 +736,14 @@ public void HeaderStringSanitizerQuietlyExits(string targetKey, string targetVal [InlineData("%20profile%20offline", "", "Test.RecordEntries/oauth_request.json")] [InlineData("|,&x-client-last-telemetry=2|0|", "", "Test.RecordEntries/oauth_request.json")] [InlineData("}", "", "Test.RecordEntries/response_with_null_secrets.json")] - public void BodyStringSanitizerApplies(string targetValue, string replacementValue, string recordingFile) + public async void BodyStringSanitizerApplies(string targetValue, string replacementValue, string recordingFile) { var session = TestHelpers.LoadRecordSession(recordingFile); var targetEntry = session.Session.Entries[0]; var originalBodyValue = Encoding.UTF8.GetString(targetEntry.Request.Body); var sanitizer = new BodyStringSanitizer(targetValue, value: replacementValue); - session.Session.Sanitize(sanitizer); + await session.Session.Sanitize(sanitizer); var resultBodyValue = Encoding.UTF8.GetString(targetEntry.Request.Body); @@ -755,7 +756,7 @@ public void BodyStringSanitizerApplies(string targetValue, string replacementVal [InlineData("TableNames", "", "Test.RecordEntries/response_with_null_secrets.json")] [InlineData("d2270777-c002-0072-313d-4ce19f000000", "", "Test.RecordEntries/response_with_null_secrets.json")] [InlineData(".19041-SP0", "", "Test.RecordEntries/response_with_null_secrets.json")] - public void BodyStringSanitizerQuietlyExits(string targetValue, string replacementValue, string recordingFile) + public async void BodyStringSanitizerQuietlyExits(string targetValue, string replacementValue, string recordingFile) { var session = TestHelpers.LoadRecordSession(recordingFile); var untouchedSession = TestHelpers.LoadRecordSession(recordingFile); @@ -765,7 +766,7 @@ public void BodyStringSanitizerQuietlyExits(string targetValue, string replaceme var matcher = new RecordMatcher(); var sanitizer = new BodyStringSanitizer(targetValue, value: replacementValue); - session.Session.Sanitize(sanitizer); + await session.Session.Sanitize(sanitizer); var resultBodyValue = Encoding.UTF8.GetString(targetEntry.Request.Body); Assert.Equal(0, matcher.CompareBodies(targetUntouchedEntry.Request.Body, targetEntry.Request.Body)); @@ -773,14 +774,14 @@ public void BodyStringSanitizerQuietlyExits(string targetValue, string replaceme } [Fact] - public void BodyStringSanitizerIgnoresNonTextualBodies() + public async void BodyStringSanitizerIgnoresNonTextualBodies() { var session = TestHelpers.LoadRecordSession("Test.RecordEntries/request_with_binary_content.json"); var targetEntry = session.Session.Entries[0]; var content = Encoding.UTF8.GetString(targetEntry.Request.Body); var bodyStringSanitizer = new BodyStringSanitizer("content"); - session.Session.Sanitize(bodyStringSanitizer); + await session.Session.Sanitize(bodyStringSanitizer); Assert.Equal(content, Encoding.UTF8.GetString(targetEntry.Request.Body)); } @@ -789,7 +790,7 @@ public void BodyStringSanitizerIgnoresNonTextualBodies() [InlineData("/v2.0/", "", "Test.RecordEntries/oauth_request.json")] [InlineData("https://management.azure.com/subscriptions/12345678-1234-1234-5678-123456789010", "", "Test.RecordEntries/request_with_subscriptionid.json")] [InlineData("?api-version=2019-05-01", "", "Test.RecordEntries/request_with_subscriptionid.json")] - public void UriStringSanitizerApplies(string targetValue, string replacementValue, string recordingFile) + public async void UriStringSanitizerApplies(string targetValue, string replacementValue, string recordingFile) { var session = TestHelpers.LoadRecordSession(recordingFile); var untouchedSession = TestHelpers.LoadRecordSession(recordingFile); @@ -799,7 +800,7 @@ public void UriStringSanitizerApplies(string targetValue, string replacementValu var matcher = new RecordMatcher(); var sanitizer = new UriStringSanitizer(targetValue, replacementValue); - session.Session.Sanitize(sanitizer); + await session.Session.Sanitize(sanitizer); var originalUriValue = targetUntouchedEntry.RequestUri.ToString(); var resultUriValue = targetEntry.RequestUri.ToString(); @@ -811,7 +812,7 @@ public void UriStringSanitizerApplies(string targetValue, string replacementValu [Theory] [InlineData("fakeazsdktestaccount2", " AdditionalTransforms { get; } = new List(); - public readonly object SanitizerLock = new object(); + public SemaphoreSlim SanitizerLock = new SemaphoreSlim(1); public List AppliedSanitizers { get; set; } = new List(); public List ForRemoval { get; } = new List(); @@ -50,9 +51,10 @@ public ModifiableRecordSession(RecordSession session, SanitizerDictionary saniti public int PlaybackResponseTime { get; set; } - public void ResetExtensions(SanitizerDictionary sanitizerDictionary) + public async void ResetExtensions(SanitizerDictionary sanitizerDictionary) { - lock (SanitizerLock) + await SanitizerLock.WaitAsync(); + try { AdditionalTransforms.Clear(); AppliedSanitizers = new List(); @@ -62,6 +64,10 @@ public void ResetExtensions(SanitizerDictionary sanitizerDictionary) CustomMatcher = null; Client = null; } + finally + { + SanitizerLock.Release(); + } } } } diff --git a/tools/test-proxy/Azure.Sdk.Tools.TestProxy/Common/RecordSession.cs b/tools/test-proxy/Azure.Sdk.Tools.TestProxy/Common/RecordSession.cs index 37cdda83b09..e7ef8fa41cc 100644 --- a/tools/test-proxy/Azure.Sdk.Tools.TestProxy/Common/RecordSession.cs +++ b/tools/test-proxy/Azure.Sdk.Tools.TestProxy/Common/RecordSession.cs @@ -6,6 +6,8 @@ using System.IO; using System.Linq; using System.Text.Json; +using System.Threading; +using System.Threading.Tasks; namespace Azure.Sdk.Tools.TestProxy.Common { @@ -20,6 +22,8 @@ public class RecordSession //Used only for deserializing track 1 session record files public Dictionary> Names { get; set; } = new Dictionary>(); + public SemaphoreSlim EntryLock { get; set; } = new SemaphoreSlim(1); + public void Serialize(Utf8JsonWriter jsonWriter) { jsonWriter.WriteStartObject(); @@ -74,12 +78,24 @@ public static RecordSession Deserialize(JsonElement element) return session; } - public void Record(RecordEntry entry) + public async Task Record(RecordEntry entry, bool shouldLock = true) { - lock (Entries) + if (shouldLock) + { + await EntryLock.WaitAsync(); + } + + try { Entries.Add(entry); } + finally + { + if (shouldLock) + { + EntryLock.Release(); + } + } } public RecordEntry Lookup(RecordEntry requestEntry, RecordMatcher matcher, IEnumerable sanitizers, bool remove = true, string sessionId = null) @@ -91,37 +107,78 @@ public RecordEntry Lookup(RecordEntry requestEntry, RecordMatcher matcher, IEnum // normalize request body with STJ using relaxed escaping to match behavior when Deserializing from session files RecordEntry.NormalizeJsonBody(requestEntry.Request); + RecordEntry entry = matcher.FindMatch(requestEntry, Entries); if (remove) { Entries.Remove(entry); - DebugLogger.LogDebug($"We successfully matched and popped request URI {entry.RequestUri} for recordingId {sessionId}"); + DebugLogger.LogDebug($"We successfully matched and popped request URI {entry.RequestUri} for recordingId {sessionId??"Unknown"}"); } return entry; } - public void Remove(RecordEntry entry) + public async Task Remove(RecordEntry entry, bool shouldLock = true) { - Entries.Remove(entry); + if (shouldLock) + { + await EntryLock.WaitAsync(); + } + + try + { + Entries.Remove(entry); + } + finally + { + if (shouldLock) + { + EntryLock.Release(); + } + } } - public void Sanitize(RecordedTestSanitizer sanitizer) + public async Task Sanitize(RecordedTestSanitizer sanitizer, bool shouldLock = true) { - lock (Entries) + if (shouldLock) + { + await EntryLock.WaitAsync(); + } + + try { sanitizer.Sanitize(this); } + finally + { + if (shouldLock) + { + EntryLock.Release(); + } + } } - public void Sanitize(IEnumerable sanitizers) + + public async Task Sanitize(IEnumerable sanitizers, bool shouldLock = true) { - lock (Entries) + if (shouldLock) + { + await EntryLock.WaitAsync(); + } + + try { - foreach(var sanitizer in sanitizers) + foreach (var sanitizer in sanitizers) { sanitizer.Sanitize(this); } } + finally + { + if (shouldLock) + { + EntryLock.Release(); + } + } } } } diff --git a/tools/test-proxy/Azure.Sdk.Tools.TestProxy/Common/RecordTransport.cs b/tools/test-proxy/Azure.Sdk.Tools.TestProxy/Common/RecordTransport.cs index 96231dc4e76..1fd441e6b5f 100644 --- a/tools/test-proxy/Azure.Sdk.Tools.TestProxy/Common/RecordTransport.cs +++ b/tools/test-proxy/Azure.Sdk.Tools.TestProxy/Common/RecordTransport.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. using Azure.Core; @@ -35,27 +35,27 @@ public RecordTransport(RecordSession session, HttpPipelineTransport innerTranspo public override void Process(HttpMessage message) { _innerTransport.Process(message); - Record(message); + Record(message).Wait(); } public override async ValueTask ProcessAsync(HttpMessage message) { await _innerTransport.ProcessAsync(message); - Record(message); + await Record(message); } - private void Record(HttpMessage message) + private async Task Record(HttpMessage message) { RecordEntry recordEntry = CreateEntry(message.Request, message.Response); switch (_filter(recordEntry)) { case EntryRecordMode.Record: - _session.Record(recordEntry); + await _session.Record(recordEntry); break; case EntryRecordMode.RecordWithoutRequestBody: recordEntry.Request.Body = null; - _session.Record(recordEntry); + await _session.Record(recordEntry); break; default: break; diff --git a/tools/test-proxy/Azure.Sdk.Tools.TestProxy/Common/SanitizerDictionary.cs b/tools/test-proxy/Azure.Sdk.Tools.TestProxy/Common/SanitizerDictionary.cs index cb2ef138140..de5a49e5ddf 100644 --- a/tools/test-proxy/Azure.Sdk.Tools.TestProxy/Common/SanitizerDictionary.cs +++ b/tools/test-proxy/Azure.Sdk.Tools.TestProxy/Common/SanitizerDictionary.cs @@ -4,6 +4,7 @@ using System.Text.Json; using System.Text.RegularExpressions; using System.Threading; +using System.Threading.Tasks; using Azure.Sdk.Tools.TestProxy.Common.Exceptions; using Azure.Sdk.Tools.TestProxy.Sanitizers; @@ -42,11 +43,10 @@ public class SanitizerDictionary // so that when we start a new recording we can properly // apply only the sanitizers that have been registered at the global level public List SessionSanitizers = new List(); - - public readonly object SessionSanitizerLock = new object(); + public SemaphoreSlim SessionSanitizerLock { get; set; } = new SemaphoreSlim(1); public SanitizerDictionary() { - ResetSessionSanitizers(); + ResetSessionSanitizers().Wait(); } /* @@ -697,9 +697,10 @@ public SanitizerDictionary() { /// /// Used to update the session sanitizers to their default configuration. /// - public void ResetSessionSanitizers() + public async Task ResetSessionSanitizers() { - lock (SessionSanitizerLock) + await SessionSanitizerLock.WaitAsync(); + try { var expectedSanitizers = DefaultSanitizerList; @@ -716,6 +717,10 @@ public void ResetSessionSanitizers() SessionSanitizers = DefaultSanitizerList.Select(x => x.Id).ToList(); } + finally + { + SessionSanitizerLock.Release(); + } } /// @@ -723,18 +728,18 @@ public void ResetSessionSanitizers() /// /// /// - public List GetSanitizers(ModifiableRecordSession session) + public async Task> GetSanitizers(ModifiableRecordSession session) { - return GetRegisteredSanitizers(session).Select(x => x.Sanitizer).ToList(); + return (await GetRegisteredSanitizers(session)).Select(x => x.Sanitizer).ToList(); } /// /// Gets a list of sanitizers that should be applied for the session level. /// /// - public List GetSanitizers() + public async Task> GetSanitizers() { - return GetRegisteredSanitizers().Select(x => x.Sanitizer).ToList(); + return (await GetRegisteredSanitizers()).Select(x => x.Sanitizer).ToList(); } /// @@ -742,9 +747,10 @@ public List GetSanitizers() /// /// /// - public List GetRegisteredSanitizers(ModifiableRecordSession session) + public async Task> GetRegisteredSanitizers(ModifiableRecordSession session) { - lock (session.SanitizerLock) + await session.SanitizerLock.WaitAsync(); + try { var sanitizers = new List(); @@ -762,18 +768,22 @@ public List GetRegisteredSanitizers(ModifiableRecordSession return sanitizers; } + finally + { + session.SanitizerLock.Release(); + } } /// /// Gets the set of registered sanitizers for the session level. /// /// - public List GetRegisteredSanitizers() + public async Task> GetRegisteredSanitizers() { - lock (SessionSanitizerLock) + var sanitizers = new List(); + await SessionSanitizerLock.WaitAsync(); + try { - var sanitizers = new List(); - foreach (var id in SessionSanitizers) { if (Sanitizers.TryGetValue(id, out RegisteredSanitizer sanitizer)) @@ -781,9 +791,13 @@ public List GetRegisteredSanitizers() sanitizers.Add(sanitizer); } } - - return sanitizers; } + finally + { + SessionSanitizerLock.Release(); + } + + return sanitizers; } private bool _register(RecordedTestSanitizer sanitizer, string id) @@ -805,11 +819,12 @@ private bool _register(RecordedTestSanitizer sanitizer, string id) /// /// The Id of the newly registered sanitizer. /// - public string Register(RecordedTestSanitizer sanitizer) + public async Task Register(RecordedTestSanitizer sanitizer) { var strCurrent = IdFactory.GetNextId().ToString(); - lock (SessionSanitizerLock) + await SessionSanitizerLock.WaitAsync(); + try { if (_register(sanitizer, strCurrent)) { @@ -817,6 +832,10 @@ public string Register(RecordedTestSanitizer sanitizer) return strCurrent; } } + finally + { + SessionSanitizerLock.Release(); + } throw new HttpException(System.Net.HttpStatusCode.InternalServerError, $"Unable to register global sanitizer id \"{strCurrent}\" with value '{JsonSerializer.Serialize(sanitizer)}'"); } @@ -827,11 +846,12 @@ public string Register(RecordedTestSanitizer sanitizer) /// /// The Id of the newly registered sanitizer. /// - public string Register(ModifiableRecordSession session, RecordedTestSanitizer sanitizer) + public async Task Register(ModifiableRecordSession session, RecordedTestSanitizer sanitizer) { var strCurrent = IdFactory.GetNextId().ToString(); - lock (session.SanitizerLock) + await SessionSanitizerLock.WaitAsync(); + try { if (_register(sanitizer, strCurrent)) @@ -842,6 +862,10 @@ public string Register(ModifiableRecordSession session, RecordedTestSanitizer sa return strCurrent; } } + finally + { + SessionSanitizerLock.Release(); + } return string.Empty; } @@ -852,9 +876,10 @@ public string Register(ModifiableRecordSession session, RecordedTestSanitizer sa /// /// /// - public string Unregister(string sanitizerId) + public async Task Unregister(string sanitizerId) { - lock (SessionSanitizerLock) + await SessionSanitizerLock.WaitAsync(); + try { if (SessionSanitizers.Contains(sanitizerId)) { @@ -862,6 +887,10 @@ public string Unregister(string sanitizerId) return sanitizerId; } } + finally + { + SessionSanitizerLock.Release(); + } throw new HttpException(System.Net.HttpStatusCode.BadRequest, $"The requested sanitizer for removal \"{sanitizerId}\" is not active at the session level."); } @@ -873,9 +902,10 @@ public string Unregister(string sanitizerId) /// /// /// - public string Unregister(string sanitizerId, ModifiableRecordSession session) + public async Task Unregister(string sanitizerId, ModifiableRecordSession session) { - lock (session.SanitizerLock) + await session.SanitizerLock.WaitAsync(); + try { if (session.AppliedSanitizers.Contains(sanitizerId)) { @@ -883,6 +913,10 @@ public string Unregister(string sanitizerId, ModifiableRecordSession session) return sanitizerId; } } + finally + { + session.SanitizerLock.Release(); + } throw new HttpException(System.Net.HttpStatusCode.BadRequest, $"The requested sanitizer for removal \"{sanitizerId}\" is not active on recording/playback with id \"{session.SessionId}\"."); } @@ -902,12 +936,17 @@ public void Cleanup(ModifiableRecordSession session) /// /// Not publically available via an API Route, but used to remove all of the active default session sanitizers. /// - public void Clear() + public async Task Clear() { - lock (SessionSanitizerLock) + await SessionSanitizerLock.WaitAsync(); + try { SessionSanitizers.Clear(); } + finally + { + SessionSanitizerLock.Release(); + } } } } diff --git a/tools/test-proxy/Azure.Sdk.Tools.TestProxy/Models/ActiveMetadataModel.cs b/tools/test-proxy/Azure.Sdk.Tools.TestProxy/Models/ActiveMetadataModel.cs index 458e6d87dbe..26854d20bdf 100644 --- a/tools/test-proxy/Azure.Sdk.Tools.TestProxy/Models/ActiveMetadataModel.cs +++ b/tools/test-proxy/Azure.Sdk.Tools.TestProxy/Models/ActiveMetadataModel.cs @@ -3,6 +3,7 @@ using Azure.Sdk.Tools.TestProxy.Common; using System.Collections.Concurrent; using Azure.Sdk.Tools.TestProxy.Common.Exceptions; +using System.Threading.Tasks; namespace Azure.Sdk.Tools.TestProxy.Models { @@ -15,18 +16,18 @@ public ActiveMetadataModel(string recordingId) public ActiveMetadataModel(RecordingHandler pageRecordingHandler) { - Descriptions = _populateFromHandler(pageRecordingHandler, ""); + Descriptions = _populateFromHandler(pageRecordingHandler, "").Result; } public ActiveMetadataModel(RecordingHandler pageRecordingHandler, string recordingId) { RecordingId = recordingId; - Descriptions = _populateFromHandler(pageRecordingHandler, recordingId); + Descriptions = _populateFromHandler(pageRecordingHandler, recordingId).Result; } public string RecordingId { get; set; } - private List _populateFromHandler(RecordingHandler handler, string recordingId) + private async Task> _populateFromHandler(RecordingHandler handler, string recordingId) { var transforms = (IEnumerable) handler.Transforms; var matcher = handler.Matcher; @@ -38,14 +39,14 @@ private List _populateFromHandler(RecordingHandler handler, s handler.InMemorySessions }; - var sanitizers = handler.SanitizerRegistry.GetRegisteredSanitizers(); + var sanitizers = await handler.SanitizerRegistry.GetRegisteredSanitizers(); var recordingFound = false; if (!string.IsNullOrWhiteSpace(recordingId)){ foreach (var sessionDict in searchCollections) { if (sessionDict.TryGetValue(recordingId, out var session)) { - sanitizers = handler.SanitizerRegistry.GetRegisteredSanitizers(session); + sanitizers = await handler.SanitizerRegistry.GetRegisteredSanitizers(session); transforms = transforms.Concat(session.AdditionalTransforms); if (session.CustomMatcher != null) diff --git a/tools/test-proxy/Azure.Sdk.Tools.TestProxy/Record.cs b/tools/test-proxy/Azure.Sdk.Tools.TestProxy/Record.cs index dec80453111..1674eb17c51 100644 --- a/tools/test-proxy/Azure.Sdk.Tools.TestProxy/Record.cs +++ b/tools/test-proxy/Azure.Sdk.Tools.TestProxy/Record.cs @@ -69,7 +69,7 @@ public async Task Push([FromBody()] IDictionary options = null) [HttpPost] [AllowEmptyBody] - public void Stop([FromBody()] IDictionary variables = null) + public async Task Stop([FromBody()] IDictionary variables = null) { string id = RecordingHandler.GetHeader(Request, "x-recording-id"); bool save = true; @@ -87,7 +87,7 @@ public void Stop([FromBody()] IDictionary variables = null) DebugLogger.LogAdminRequestDetails(_logger, Request); - _recordingHandler.StopRecording(id, variables: variables, saveRecording: save); + await _recordingHandler.StopRecording(id, variables: variables, saveRecording: save); } public async Task HandleRequest() diff --git a/tools/test-proxy/Azure.Sdk.Tools.TestProxy/RecordingHandler.cs b/tools/test-proxy/Azure.Sdk.Tools.TestProxy/RecordingHandler.cs index 962b623fd8a..59f540977da 100644 --- a/tools/test-proxy/Azure.Sdk.Tools.TestProxy/RecordingHandler.cs +++ b/tools/test-proxy/Azure.Sdk.Tools.TestProxy/RecordingHandler.cs @@ -85,7 +85,7 @@ public RecordingHandler(string targetDirectory, IAssetsStore store = null, Store { ContextDirectory = targetDirectory; - SetDefaultExtensions(); + SetDefaultExtensions().Wait(); Store = store; if (store == null) @@ -102,7 +102,7 @@ public RecordingHandler(string targetDirectory, IAssetsStore store = null, Store #endregion #region recording functionality - public void StopRecording(string sessionId, IDictionary variables = null, bool saveRecording = true) + public async Task StopRecording(string sessionId, IDictionary variables = null, bool saveRecording = true) { var id = Guid.NewGuid().ToString(); @@ -113,8 +113,8 @@ public void StopRecording(string sessionId, IDictionary variable return; } - var sanitizers = SanitizerRegistry.GetSanitizers(recordingSession); - recordingSession.Session.Sanitize(sanitizers); + var sanitizers = await SanitizerRegistry.GetSanitizers(recordingSession); + await recordingSession.Session.Sanitize(sanitizers); if (variables != null) { @@ -197,7 +197,7 @@ public async Task HandleRecordRequestAsync(string recordingId, HttpRequest incom throw new HttpException(HttpStatusCode.BadRequest, $"There is no active recording session under id {recordingId}."); } - var sanitizers = SanitizerRegistry.GetSanitizers(session); + var sanitizers = await SanitizerRegistry.GetSanitizers(session); DebugLogger.LogRequestDetails(incomingRequest, sanitizers); @@ -249,10 +249,15 @@ public async Task HandleRecordRequestAsync(string recordingId, HttpRequest incom if (mode != EntryRecordMode.DontRecord) { - lock (session.Session.Entries) + await session.Session.EntryLock.WaitAsync(); + try { session.Session.Entries.Add(entry); } + finally + { + session.Session.EntryLock.Release(); + } Interlocked.Increment(ref Startup.RequestsRecorded); } @@ -394,7 +399,6 @@ public async Task StartPlaybackAsync(string sessionId, HttpResponse outgoingResp { Path = path }; - DebugLogger.LogInformation($"Recording file {assetsPath} is associated with recording id {id}"); } if (!PlaybackSessions.TryAdd(id, session)) @@ -411,7 +415,6 @@ public async Task StartPlaybackAsync(string sessionId, HttpResponse outgoingResp // Write to the response await outgoingResponse.WriteAsync(json); - DebugLogger.LogTrace($"PLAYBACK START END {id}."); } @@ -453,26 +456,32 @@ public async Task HandlePlaybackRequest(string recordingId, HttpRequest incoming throw new HttpException(HttpStatusCode.BadRequest, $"There is no active playback session under recording id {recordingId}."); } - var sanitizers = SanitizerRegistry.GetSanitizers(session); + var sanitizers = await SanitizerRegistry.GetSanitizers(session); if (!session.IsSanitized) { // we don't need to re-sanitize with recording-applicable sanitizers every time. just the very first one - lock (session.SanitizerLock) + await session.SanitizerLock.WaitAsync(); + try { if (!session.IsSanitized) { - session.Session.Sanitize(sanitizers); + await session.Session.Sanitize(sanitizers, false); session.IsSanitized = true; } } + finally + { + session.SanitizerLock.Release(); + } } DebugLogger.LogRequestDetails(incomingRequest, sanitizers); var entry = (await CreateEntryAsync(incomingRequest).ConfigureAwait(false)).Item1; - lock (session.Session.Entries) + await session.Session.EntryLock.WaitAsync(); + try { // Session may be removed later, but only after response has been fully written var match = session.Session.Lookup(entry, session.CustomMatcher ?? Matcher, sanitizers, remove: false, sessionId: recordingId); @@ -500,7 +509,7 @@ public async Task HandlePlaybackRequest(string recordingId, HttpRequest incoming outgoingResponse.ContentLength = bodyData.Length; } - WriteBodyBytes(bodyData, session.PlaybackResponseTime, outgoingResponse); + await WriteBodyBytes(bodyData, session.PlaybackResponseTime, outgoingResponse); } Interlocked.Increment(ref Startup.RequestsPlayedBack); @@ -517,9 +526,13 @@ public async Task HandlePlaybackRequest(string recordingId, HttpRequest incoming if (remove) { - session.Session.Remove(match); + await session.Session.Remove(match, shouldLock: false); } } + finally + { + session.Session.EntryLock.Release(); + } } public byte[][] GetBatches(byte[] bodyData, int batchCount) @@ -548,35 +561,7 @@ public byte[][] GetBatches(byte[] bodyData, int batchCount) return batches; } - public void WriteBodyBytes(byte[] bodyData, int playbackResponseTime, HttpResponse outgoingResponse) - { - if (playbackResponseTime > 0) - { - int batchCount = 10; - int sleepLength = playbackResponseTime / batchCount; - - byte[][] chunks = GetBatches(bodyData, batchCount); - - for (int i = 0; i < chunks.Length; i++) - { - var chunk = chunks[i]; - - outgoingResponse.Body.Write(chunk, 0, chunk.Length); - - if (i != chunks.Length - 1) - { - Thread.Sleep(sleepLength); - } - } - - } - else - { - outgoingResponse.Body.Write(bodyData, 0, bodyData.Length); - } - } - - public async Task WriteBodyBytesAsync(byte[] bodyData, int playbackResponseTime, HttpResponse outgoingResponse) + public async Task WriteBodyBytes(byte[] bodyData, int playbackResponseTime, HttpResponse outgoingResponse) { if (playbackResponseTime > 0) { @@ -941,33 +926,27 @@ public ModifiableRecordSession GetActiveSession(string recordingId) throw new HttpException(HttpStatusCode.BadRequest, $"{recordingId} is not an active session for either record or playback. Check the value being passed and try again."); } - public string UnregisterSanitizer(string sanitizerId, string recordingId = null) + public async Task UnregisterSanitizer(string sanitizerId, string recordingId = null) { if (!string.IsNullOrWhiteSpace(recordingId)) { var session = GetActiveSession(recordingId); - - lock (session) - { - return SanitizerRegistry.Unregister(sanitizerId, session); - } + return await SanitizerRegistry.Unregister(sanitizerId, session); } - return SanitizerRegistry.Unregister(sanitizerId); + return await SanitizerRegistry.Unregister(sanitizerId); } - public string RegisterSanitizer(RecordedTestSanitizer sanitizer, string recordingId = null) + public async Task RegisterSanitizer(RecordedTestSanitizer sanitizer, string recordingId = null) { if (!string.IsNullOrWhiteSpace(recordingId)) { var session = GetActiveSession(recordingId); - lock(session) - { - return SanitizerRegistry.Register(session, sanitizer); - } + return await SanitizerRegistry.Register(session, sanitizer); } - return SanitizerRegistry.Register(sanitizer); + + return await SanitizerRegistry.Register(sanitizer); } public void AddTransformToRecording(string recordingId, ResponseTransform transform) @@ -991,7 +970,7 @@ public void SetMatcherForRecording(string recordingId, RecordMatcher matcher) session.CustomMatcher = matcher; } - public void SetDefaultExtensions(string recordingId = null) + public async Task SetDefaultExtensions(string recordingId = null) { if (recordingId != null) { @@ -1054,7 +1033,7 @@ public void SetDefaultExtensions(string recordingId = null) throw new HttpException(HttpStatusCode.BadRequest, sb.ToString()); } - SanitizerRegistry.ResetSessionSanitizers(); + await SanitizerRegistry.ResetSessionSanitizers(); Transforms = new List { diff --git a/tools/test-proxy/Azure.Sdk.Tools.TestProxy/Startup.cs b/tools/test-proxy/Azure.Sdk.Tools.TestProxy/Startup.cs index e4f1a073273..6e021b99187 100644 --- a/tools/test-proxy/Azure.Sdk.Tools.TestProxy/Startup.cs +++ b/tools/test-proxy/Azure.Sdk.Tools.TestProxy/Startup.cs @@ -207,11 +207,6 @@ public void ConfigureServices(IServiceCollection services) }); }); - services.Configure(options => - { - options.AllowSynchronousIO = true; - }); - services.AddControllers(options => { options.InputFormatters.Add(new EmptyBodyFormatter());