Skip to content

Commit 0bb8389

Browse files
Enable Test Proxy logging in Test Framework (#37994)
* Add AMQP constructor to ServiceBusMessage * Enable logging for test proxy integration * Clean up * readme * add section * revert default * Add locking * Add AspNetCore Info logging * reduce delay to 20ms * Put all proxy logging behind flag instead of allowing loglevel config * Fix wrapping * Split out CheckForErrors to make it sync
1 parent b01abf1 commit 0bb8389

File tree

4 files changed

+63
-5
lines changed

4 files changed

+63
-5
lines changed

sdk/core/Azure.Core.TestFramework/README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,11 @@ The key integration points between the Test Framework and the Test Proxy are:
380380
- InstrumentClientOptions method of `RecordedTestBase` - calling this on your client options will set the [ClientOptions.Transport property](https://learn.microsoft.com/dotnet/api/azure.core.clientoptions.transport?view=azure-dotnet) to be [ProxyTransport](https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/core/Azure.Core.TestFramework/src/ProxyTransport.cs) to your client options when in `Playback` or `Record` mode. The ProxyTransport will send all requests to the Test Proxy.
381381
- [TestProxy.cs](https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/core/Azure.Core.TestFramework/src/TestProxy.cs) - This class is responsible for starting and stopping the Test Proxy process, as well as reporting any errors that occur in the Test Proxy process. The Test Proxy process is started automatically when running tests in `Record` or `Playback` mode, and is stopped automatically when the test run is complete. The Test Proxy process is shared between tests and test classes within a process.
382382

383+
#### Including Test Proxy Logs
384+
385+
In order to enable Test Proxy logging, you can either set the `AZURE_ENABLE_TEST_PROXY_LOGGING`
386+
environment variable or the `EnableTestProxyLogging` [runsetting](https://github.com/Azure/azure-sdk-for-net/blob/main/eng/nunit.runsettings) parameter to `true`.
387+
383388
## Unit tests
384389

385390
The Test Framework provides several classes that can help you write unit tests for your client library. Unit tests are helpful for scenarios that would be tricky to test with a recorded test, such as simulating certain error scenarios.

sdk/core/Azure.Core.TestFramework/src/RecordedTestBase.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -458,7 +458,10 @@ public virtual async Task StopTestRecordingAsync()
458458
}
459459
}
460460

461-
_proxy?.CheckForErrors();
461+
if (_proxy != null)
462+
{
463+
await _proxy.CheckProxyOutputAsync();
464+
}
462465
}
463466

464467
protected internal override object InstrumentClient(Type clientType, object client, IEnumerable<IInterceptor> preInterceptors)

sdk/core/Azure.Core.TestFramework/src/TestEnvironment.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -650,6 +650,22 @@ internal static bool EnableFiddler
650650
}
651651
}
652652

653+
/// <summary>
654+
/// Determines whether to enable proxy logging beyond errors.
655+
/// </summary>
656+
internal static bool EnableProxyLogging
657+
{
658+
get
659+
{
660+
string switchString = TestContext.Parameters["EnableProxyLogging"] ??
661+
Environment.GetEnvironmentVariable("AZURE_ENABLE_PROXY_LOGGING");
662+
663+
bool.TryParse(switchString, out bool enableProxyLogging);
664+
665+
return enableProxyLogging;
666+
}
667+
}
668+
653669
private void BootStrapTestResources()
654670
{
655671
lock (s_syncLock)

sdk/core/Azure.Core.TestFramework/src/TestProxy.cs

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
using System.Reflection;
1010
using System.Runtime.InteropServices;
1111
using System.Text;
12+
using System.Threading;
1213
using System.Threading.Tasks;
1314
using Azure.Core.Pipeline;
1415
using NUnit.Framework;
@@ -38,6 +39,8 @@ public class TestProxy
3839
private readonly StringBuilder _errorBuffer = new();
3940
private static readonly object _lock = new();
4041
private static TestProxy _shared;
42+
private readonly StringBuilder _output = new();
43+
private static readonly bool s_enableProxyLogging;
4144

4245
static TestProxy()
4346
{
@@ -56,6 +59,7 @@ static TestProxy()
5659
s_dotNetExe = Path.Combine(installDir, dotNetExeName);
5760

5861
bool HasDotNetExe(string dotnetDir) => dotnetDir != null && File.Exists(Path.Combine(dotnetDir, dotNetExeName));
62+
s_enableProxyLogging = TestEnvironment.EnableProxyLogging;
5963
}
6064

6165
private TestProxy(string proxyPath, bool debugMode = false)
@@ -74,7 +78,9 @@ private TestProxy(string proxyPath, bool debugMode = false)
7478
EnvironmentVariables =
7579
{
7680
["ASPNETCORE_URLS"] = $"http://{IpAddress}:0;https://{IpAddress}:0",
81+
["Logging__LogLevel__Azure.Sdk.Tools.TestProxy"] = s_enableProxyLogging ? "Debug" : "Error",
7782
["Logging__LogLevel__Default"] = "Error",
83+
["Logging__LogLevel__Microsoft.AspNetCore"] = s_enableProxyLogging ? "Information" : "Error",
7884
["Logging__LogLevel__Microsoft.Hosting.Lifetime"] = "Information",
7985
["ASPNETCORE_Kestrel__Certificates__Default__Path"] = TestEnvironment.DevCertPath,
8086
["ASPNETCORE_Kestrel__Certificates__Default__Password"] = TestEnvironment.DevCertPassword
@@ -133,14 +139,24 @@ private TestProxy(string proxyPath, bool debugMode = false)
133139
var options = new TestProxyClientOptions();
134140
Client = new TestProxyRestClient(new ClientDiagnostics(options), HttpPipelineBuilder.Build(options), new Uri($"http://{IpAddress}:{_proxyPortHttp}"));
135141

136-
// For some reason draining the standard output stream is necessary to keep the test-proxy process healthy. Otherwise requests
137-
// start timing out. This only seems to happen when not specifying a port.
138142
_ = Task.Run(
139143
() =>
140144
{
141145
while (!_testProxyProcess.HasExited && !_testProxyProcess.StandardOutput.EndOfStream)
142146
{
143-
_testProxyProcess.StandardOutput.ReadLine();
147+
if (s_enableProxyLogging)
148+
{
149+
lock (_output)
150+
{
151+
_output.AppendLine(_testProxyProcess.StandardOutput.ReadLine());
152+
}
153+
}
154+
// For some reason draining the standard output stream is necessary to keep the test-proxy process healthy, even
155+
// when we are not outputting logs. Otherwise, requests start timing out.
156+
else
157+
{
158+
_testProxyProcess.StandardOutput.ReadLine();
159+
}
144160
}
145161
});
146162
}
@@ -204,7 +220,25 @@ private static bool TryParsePort(string output, string scheme, out int? port)
204220
return false;
205221
}
206222

207-
public void CheckForErrors()
223+
public async Task CheckProxyOutputAsync()
224+
{
225+
if (s_enableProxyLogging)
226+
{
227+
// add a small delay to allow the log output for the just finished test to be collected into the _output StringBuilder
228+
await Task.Delay(20);
229+
230+
// lock to avoid any race conditions caused by appending to the StringBuilder while calling ToString
231+
lock (_output)
232+
{
233+
TestContext.Out.WriteLine(_output.ToString());
234+
_output.Clear();
235+
}
236+
}
237+
238+
CheckForErrors();
239+
}
240+
241+
private void CheckForErrors()
208242
{
209243
if (_errorBuffer.Length > 0)
210244
{

0 commit comments

Comments
 (0)