diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/DependencyInjectionEventSourceTests.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/DependencyInjectionEventSourceTests.cs index b4e3f4d55218ba..f23b2220592320 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/DependencyInjectionEventSourceTests.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/DependencyInjectionEventSourceTests.cs @@ -6,31 +6,17 @@ using System.Collections.Generic; using System.Diagnostics.Tracing; using System.Linq; -using System.Reflection; using Microsoft.Extensions.DependencyInjection.Specification.Fakes; using Newtonsoft.Json.Linq; using Xunit; namespace Microsoft.Extensions.DependencyInjection.Tests { - [CollectionDefinition(nameof(EventSourceTests), DisableParallelization = true)] - public class EventSourceTests : ICollectionFixture + public class DependencyInjectionEventSourceTests( + DependencyInjectionEventSourceTests.TestEventListenerFixture fixture) + : IClassFixture { - } - - [Collection(nameof(EventSourceTests))] - public class DependencyInjectionEventSourceTests : IDisposable - { - private readonly TestEventListener _listener = new TestEventListener(); - - public DependencyInjectionEventSourceTests() - { - // clear the provider list in between tests - typeof(DependencyInjectionEventSource).GetField("_providers", BindingFlags.NonPublic | BindingFlags.Instance) - .SetValue(DependencyInjectionEventSource.Log, new List>()); - - _listener.EnableEvents(DependencyInjectionEventSource.Log, EventLevel.Verbose); - } + private TestEventListener Listener => fixture.Listener; [Fact] public void ExistsWithCorrectId() @@ -58,9 +44,10 @@ public void EmitsCallSiteBuiltEvent() serviceCollection.AddTransient(); serviceCollection.AddSingleton(); - serviceCollection.BuildServiceProvider().GetService>(); + var serviceProvider = serviceCollection.BuildServiceProvider(); + serviceProvider.GetService>(); - var callsiteBuiltEvent = _listener.EventData.Single(e => e.EventName == "CallSiteBuilt"); + var callsiteBuiltEvent = Listener.EventDataFor(serviceProvider).Single(e => e.EventName == "CallSiteBuilt"); Assert.Equal( @@ -168,7 +155,7 @@ public void EmitsServiceResolvedEvent() serviceProvider.GetService(); serviceProvider.GetService(); - var serviceResolvedEvents = _listener.EventData.Where(e => e.EventName == "ServiceResolved").ToArray(); + var serviceResolvedEvents = Listener.EventDataFor(serviceProvider).Where(e => e.EventName == "ServiceResolved").ToArray(); Assert.Equal(3, serviceResolvedEvents.Length); foreach (var serviceResolvedEvent in serviceResolvedEvents) @@ -189,7 +176,7 @@ public void EmitsExpressionTreeBuiltEvent() serviceProvider.GetService(); - var expressionTreeGeneratedEvent = _listener.EventData.Single(e => e.EventName == "ExpressionTreeGenerated"); + var expressionTreeGeneratedEvent = Listener.EventDataFor(serviceProvider).Single(e => e.EventName == "ExpressionTreeGenerated"); Assert.Equal("Microsoft.Extensions.DependencyInjection.Specification.Fakes.IFakeService", GetProperty(expressionTreeGeneratedEvent, "serviceType")); Assert.Equal(9, GetProperty(expressionTreeGeneratedEvent, "nodeCount")); @@ -197,7 +184,6 @@ public void EmitsExpressionTreeBuiltEvent() } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/35753", TestPlatforms.Windows)] public void EmitsDynamicMethodBuiltEvent() { // Arrange @@ -208,7 +194,7 @@ public void EmitsDynamicMethodBuiltEvent() serviceProvider.GetService(); - var expressionTreeGeneratedEvent = _listener.EventData.Single(e => e.EventName == "DynamicMethodBuilt"); + var expressionTreeGeneratedEvent = Listener.EventDataFor(serviceProvider).Single(e => e.EventName == "DynamicMethodBuilt"); Assert.Equal("Microsoft.Extensions.DependencyInjection.Specification.Fakes.IFakeService", GetProperty(expressionTreeGeneratedEvent, "serviceType")); Assert.Equal(12, GetProperty(expressionTreeGeneratedEvent, "methodSize")); @@ -228,7 +214,7 @@ public void EmitsScopeDisposedEvent() scope.ServiceProvider.GetService(); } - var scopeDisposedEvent = _listener.EventData.Single(e => e.EventName == "ScopeDisposed"); + var scopeDisposedEvent = Listener.EventDataFor(serviceProvider).Single(e => e.EventName == "ScopeDisposed"); Assert.Equal(1, GetProperty(scopeDisposedEvent, "scopedServicesResolved")); Assert.Equal(1, GetProperty(scopeDisposedEvent, "disposableServices")); @@ -239,13 +225,15 @@ public void EmitsScopeDisposedEvent() public void EmitsServiceRealizationFailedEvent() { var exception = new Exception("Test error."); - DependencyInjectionEventSource.Log.ServiceRealizationFailed(exception, 1234); + var serviceProvider = new ServiceCollection().BuildServiceProvider(); + int hashCode = serviceProvider.GetHashCode(); + DependencyInjectionEventSource.Log.ServiceRealizationFailed(exception, hashCode); var eventName = nameof(DependencyInjectionEventSource.Log.ServiceRealizationFailed); - var serviceRealizationFailedEvent = _listener.EventData.Single(e => e.EventName == eventName); + var serviceRealizationFailedEvent = Listener.EventDataFor(serviceProvider).Single(e => e.EventName == eventName); Assert.Equal("System.Exception: Test error.", GetProperty(serviceRealizationFailedEvent, "exceptionMessage")); - Assert.Equal(1234, GetProperty(serviceRealizationFailedEvent, "serviceProviderHashCode")); + Assert.Equal(hashCode, GetProperty(serviceRealizationFailedEvent, "serviceProviderHashCode")); Assert.Equal(6, serviceRealizationFailedEvent.EventId); } @@ -266,7 +254,7 @@ public void EmitsServiceProviderBuilt() using ServiceProvider provider = serviceCollection.BuildServiceProvider(); - EventWrittenEventArgs serviceProviderBuiltEvent = _listener.EventData.Single(e => e.EventName == "ServiceProviderBuilt"); + EventWrittenEventArgs serviceProviderBuiltEvent = Listener.EventDataFor(provider).Single(e => e.EventName == "ServiceProviderBuilt"); GetProperty(serviceProviderBuiltEvent, "serviceProviderHashCode"); // assert hashcode exists as an int Assert.Equal(4, GetProperty(serviceProviderBuiltEvent, "singletonServices")); Assert.Equal(2, GetProperty(serviceProviderBuiltEvent, "scopedServices")); @@ -275,7 +263,7 @@ public void EmitsServiceProviderBuilt() Assert.Equal(1, GetProperty(serviceProviderBuiltEvent, "openGenericsServices")); Assert.Equal(7, serviceProviderBuiltEvent.EventId); - EventWrittenEventArgs serviceProviderDescriptorsEvent = _listener.EventData.Single(e => e.EventName == "ServiceProviderDescriptors"); + EventWrittenEventArgs serviceProviderDescriptorsEvent = Listener.EventDataFor(provider).Single(e => e.EventName == "ServiceProviderDescriptors"); Assert.Equal( string.Join(Environment.NewLine, "{", @@ -343,33 +331,77 @@ public void EmitsServiceProviderBuilt() [Fact] public void EmitsServiceProviderBuiltOnAttach() { - _listener.DisableEvents(DependencyInjectionEventSource.Log); - ServiceCollection serviceCollection = new(); serviceCollection.AddSingleton(new FakeDisposeCallback()); using ServiceProvider provider = serviceCollection.BuildServiceProvider(); - Assert.Empty(_listener.EventData); + using var listener = new TestEventListener(); + listener.EnableEvents(DependencyInjectionEventSource.Log, EventLevel.Verbose); + try + { + EventWrittenEventArgs serviceProviderBuiltEvent = listener.EventDataFor(provider).Single(e => e.EventName == "ServiceProviderBuilt"); + Assert.Equal(1, GetProperty(serviceProviderBuiltEvent, "singletonServices")); - _listener.EnableEvents(DependencyInjectionEventSource.Log, EventLevel.Verbose); + EventWrittenEventArgs serviceProviderDescriptorsEvent = listener.EventDataFor(provider).Single(e => e.EventName == "ServiceProviderDescriptors"); + Assert.NotNull(JObject.Parse(GetProperty(serviceProviderDescriptorsEvent, "descriptors"))); + } + finally + { + listener.DisableEvents(DependencyInjectionEventSource.Log); + } + } - EventWrittenEventArgs serviceProviderBuiltEvent = _listener.EventData.Single(e => e.EventName == "ServiceProviderBuilt"); - Assert.Equal(1, GetProperty(serviceProviderBuiltEvent, "singletonServices")); + private static bool TryGetProperty(EventWrittenEventArgs data, string propName, out T result) + { + if (data.PayloadNames is { } names && + data.Payload is { } payload && + names.IndexOf(propName) is var index and >= 0 && + payload[index] is T value) + { + result = value; + return true; + } - EventWrittenEventArgs serviceProviderDescriptorsEvent = _listener.EventData.Single(e => e.EventName == "ServiceProviderDescriptors"); - Assert.NotNull(JObject.Parse(GetProperty(serviceProviderDescriptorsEvent, "descriptors"))); + result = default; + return false; } - private T GetProperty(EventWrittenEventArgs data, string propName) - => (T)data.Payload[data.PayloadNames.IndexOf(propName)]; + private static T GetProperty(EventWrittenEventArgs data, string propName) => + TryGetProperty(data, propName, out T result) + ? result + : throw new ArgumentException($"No property {propName} with type {typeof(T)} found."); + + public class TestEventListenerFixture : IDisposable + { + internal TestEventListener Listener { get; } + + public TestEventListenerFixture() + { + Listener = new(); + Listener.EnableEvents(DependencyInjectionEventSource.Log, EventLevel.Verbose); + } + + public void Dispose() + { + Listener.DisableEvents(DependencyInjectionEventSource.Log); + Listener.Dispose(); + } + } - private class TestEventListener : EventListener + internal class TestEventListener : EventListener { private volatile bool _disposed; - private ConcurrentQueue _events = new ConcurrentQueue(); + private readonly ConcurrentQueue _events = new ConcurrentQueue(); + + public IEnumerable EventDataFor(IServiceProvider serviceProvider) + { + int hashCode = serviceProvider.GetHashCode(); - public IEnumerable EventData => _events; + return _events.Where(e => + e.PayloadNames?.IndexOf("serviceProviderHashCode") is { } index and >= 0 && + e.Payload?[index] as int? == hashCode); + } protected override void OnEventWritten(EventWrittenEventArgs eventData) { @@ -385,10 +417,5 @@ public override void Dispose() base.Dispose(); } } - - public void Dispose() - { - _listener.Dispose(); - } } }