diff --git a/src/Platform/Microsoft.Testing.Extensions.Telemetry/AppInsightsProvider.cs b/src/Platform/Microsoft.Testing.Extensions.Telemetry/AppInsightsProvider.cs index 4724dc2c02..647c516d13 100644 --- a/src/Platform/Microsoft.Testing.Extensions.Telemetry/AppInsightsProvider.cs +++ b/src/Platform/Microsoft.Testing.Extensions.Telemetry/AppInsightsProvider.cs @@ -5,7 +5,9 @@ using System.Threading.Channels; #endif +#if DEBUG using Microsoft.Testing.Platform; +#endif using Microsoft.Testing.Platform.Configurations; using Microsoft.Testing.Platform.Helpers; using Microsoft.Testing.Platform.Logging; @@ -37,7 +39,6 @@ internal sealed partial class AppInsightsProvider : private readonly bool _isCi; private readonly IEnvironment _environment; private readonly ITestApplicationCancellationTokenSource _testApplicationCancellationTokenSource; - private readonly ITask _task; private readonly IClock _clock; private readonly ITelemetryInformation _telemetryInformation; private readonly ITelemetryClientFactory _telemetryClientFactory; @@ -96,7 +97,6 @@ public AppInsightsProvider( _environment = environment; _currentSessionId = sessionId; _testApplicationCancellationTokenSource = testApplicationCancellationTokenSource; - _task = task; _clock = clock; _telemetryInformation = telemetryInformation; _telemetryClientFactory = telemetryClientFactory; @@ -199,7 +199,6 @@ private async Task IngestLoopAsync() break; #endif case bool value: - RoslynDebug.Assert(false, $"Telemetry entry '{pair.Key}' contains a boolean value, boolean values should always be converted to string using: .{nameof(TelemetryExtensions.AsTelemetryBool)}()"); properties.Add(pair.Key, value.AsTelemetryBool()); break; default: diff --git a/test/UnitTests/Microsoft.Testing.Extensions.UnitTests/AppInsightsProviderTests.cs b/test/UnitTests/Microsoft.Testing.Extensions.UnitTests/AppInsightsProviderTests.cs index 2ae98ff5b1..bc69553fbf 100644 --- a/test/UnitTests/Microsoft.Testing.Extensions.UnitTests/AppInsightsProviderTests.cs +++ b/test/UnitTests/Microsoft.Testing.Extensions.UnitTests/AppInsightsProviderTests.cs @@ -15,6 +15,8 @@ namespace Microsoft.Testing.Extensions.UnitTests; [TestClass] public sealed class AppInsightsProviderTests { + public TestContext TestContext { get; set; } = null!; + [TestMethod] public void Platform_CancellationToken_Cancellation_Should_Exit_Gracefully() { @@ -152,4 +154,67 @@ public void Timeout_During_Dispose_Should_Exit_Gracefully() appInsightsProvider.Dispose(); #endif } + + [TestMethod] + public async Task LogEvent_WithBooleanProperty_ConvertsValueToTelemetryString() + { + Mock environment = new(); + Mock clock = new(); + Mock config = new(); + Mock telemetryInformation = new(); + + Mock loggerFactory = new(); + loggerFactory.Setup(x => x.CreateLogger(It.IsAny())).Returns(new Mock().Object); + + Dictionary capturedProperties = []; + using ManualResetEventSlim trackEventCalled = new(initialState: false); + Mock testTelemetryClient = new(); + testTelemetryClient.Setup(x => x.TrackEvent(It.IsAny(), It.IsAny>(), It.IsAny>())) + .Callback((string _, Dictionary properties, Dictionary _) => + { + foreach (KeyValuePair pair in properties) + { + capturedProperties[pair.Key] = pair.Value; + } + + trackEventCalled.Set(); + }); + + Mock telemetryClientFactory = new(); + telemetryClientFactory.Setup(x => x.Create(It.IsAny(), It.IsAny())).Returns(testTelemetryClient.Object); + + CancellationTokenSource cancellationTokenSource = new(); + Mock testApplicationCancellationTokenSource = new(); + testApplicationCancellationTokenSource.Setup(x => x.CancellationToken).Returns(cancellationTokenSource.Token); + + AppInsightsProvider appInsightsProvider = new( + environment.Object, + testApplicationCancellationTokenSource.Object, + new SystemTask(), + loggerFactory.Object, + clock.Object, + config.Object, + telemetryInformation.Object, + telemetryClientFactory.Object, + "sessionId"); + + await appInsightsProvider.LogEventAsync( + "Sample", + new Dictionary { ["my.bool"] = true }, + CancellationToken.None); + + // Wait for the consumer loop to actually invoke TrackEvent before disposing, + // otherwise the dispose-time flush window can elapse on slower runners (notably net472) + // before the payload is processed. + Assert.IsTrue(trackEventCalled.Wait(TimeSpan.FromSeconds(30), TestContext.CancellationToken), "Telemetry consumer did not invoke TrackEvent within the timeout."); + +#if NETCOREAPP + await appInsightsProvider.DisposeAsync(); +#else + appInsightsProvider.Dispose(); +#endif + + Assert.IsTrue(capturedProperties.TryGetValue("my.bool", out string? value), "Expected 'my.bool' property in tracked event."); + Assert.AreEqual(TelemetryProperties.True, value); + } }