From 453ee01dc574f776a34c6d2efa629772ee4c07b4 Mon Sep 17 00:00:00 2001 From: Elinor Fung Date: Tue, 22 Oct 2019 22:33:08 -0700 Subject: [PATCH] Add test project for binder tracing tests Add event listener for tests --- .../binding/tracing/BinderEventListener.cs | 104 ++++++++++++++++++ .../binding/tracing/BinderTracingTest.cs | 66 +++++++++++ .../binding/tracing/BinderTracingTest.csproj | 12 ++ 3 files changed, 182 insertions(+) create mode 100644 tests/src/Loader/binding/tracing/BinderEventListener.cs create mode 100644 tests/src/Loader/binding/tracing/BinderTracingTest.cs create mode 100644 tests/src/Loader/binding/tracing/BinderTracingTest.csproj diff --git a/tests/src/Loader/binding/tracing/BinderEventListener.cs b/tests/src/Loader/binding/tracing/BinderEventListener.cs new file mode 100644 index 000000000000..c40387893628 --- /dev/null +++ b/tests/src/Loader/binding/tracing/BinderEventListener.cs @@ -0,0 +1,104 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Diagnostics.Tracing; +using System.Linq; +using System.Threading; +using System.Reflection; +using Xunit; + +using Assert = Xunit.Assert; + +namespace BinderTracingTests +{ + internal class BindEvent + { + internal AssemblyName AssemblyName; + internal bool Success; + + internal Guid ActivityId; + internal Guid ParentActivityId; + + internal bool Completed; + internal bool Nested; + } + + internal sealed class BinderEventListener : EventListener + { + public Dictionary BindEvents = new Dictionary(); + + private const EventKeywords TasksFlowActivityIds = (EventKeywords)0x80; + private const EventKeywords BinderKeyword = (EventKeywords)0x4; + + private object eventsLock = new object(); + + public BindEvent[] WaitAndGetEventsForAssembly(string simpleName, int waitTimeoutInMs = 10000) + { + const int waitIntervalInMs = 50; + int timeWaitedInMs = 0; + do + { + lock (eventsLock) + { + var events = BindEvents.Values.Where(e => e.Completed && e.AssemblyName.Name == simpleName && !e.Nested); + if (events.Any()) + { + return events.ToArray(); + } + } + + Thread.Sleep(waitIntervalInMs); + timeWaitedInMs += waitIntervalInMs; + } while (timeWaitedInMs < waitTimeoutInMs); + + throw new TimeoutException($"Timed out waiting for bind events for {simpleName}"); + } + + protected override void OnEventSourceCreated(EventSource eventSource) + { + if (eventSource.Name == "Microsoft-Windows-DotNETRuntime") + { + EnableEvents(eventSource, EventLevel.Verbose, BinderKeyword); + } + else if (eventSource.Name == "System.Threading.Tasks.TplEventSource") + { + EnableEvents(eventSource, EventLevel.Verbose, TasksFlowActivityIds); + } + } + + protected override void OnEventWritten(EventWrittenEventArgs data) + { + if (data.EventSource.Name != "Microsoft-Windows-DotNETRuntime") + return; + + object GetData(string name) => data.Payload[data.PayloadNames.IndexOf(name)]; + string GetDataString(string name) => GetData(name).ToString(); + + lock (eventsLock) + { + switch (data.EventName) + { + case "AssemblyBindStart": + Assert.True(!BindEvents.ContainsKey(data.ActivityId), "AssemblyBindStart should not exist for same activity ID "); + var bindEvent = new BindEvent() + { + AssemblyName = new AssemblyName(GetDataString("AssemblyName")), + ActivityId = data.ActivityId, + ParentActivityId = data.RelatedActivityId, + Nested = BindEvents.ContainsKey(data.RelatedActivityId) + }; + BindEvents.Add(data.ActivityId, bindEvent); + break; + case "AssemblyBindStop": + Assert.True(BindEvents.ContainsKey(data.ActivityId), "AssemblyBindStop should have a matching AssemblyBindStart"); + BindEvents[data.ActivityId].Success = (bool)GetData("Success"); + BindEvents[data.ActivityId].Completed = true; + break; + } + } + } + } +} diff --git a/tests/src/Loader/binding/tracing/BinderTracingTest.cs b/tests/src/Loader/binding/tracing/BinderTracingTest.cs new file mode 100644 index 000000000000..332ae72a5131 --- /dev/null +++ b/tests/src/Loader/binding/tracing/BinderTracingTest.cs @@ -0,0 +1,66 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Linq; +using System.Reflection; +using System.Runtime.Loader; + +using Assert = Xunit.Assert; + +namespace BinderTracingTests +{ + class BinderTracingTest + { + public static void PlatformAssembly_DefaultALC() + { + Console.WriteLine($"Running {nameof(PlatformAssembly_DefaultALC)}..."); + using (var listener = new BinderEventListener()) + { + string assemblyName = "System.Xml"; + Assembly asm = Assembly.Load(assemblyName); + + BindEvent[] events = listener.WaitAndGetEventsForAssembly(assemblyName); + Assert.True(events.Length == 1, $"Bind event count for {assemblyName} - expected: 1, actual: {events.Length}"); + BindEvent bindEvent = events[0]; + Assert.True(bindEvent.Success, $"Expected bind for {assemblyName} to succeed"); + } + } + + public static void NonExistentAssembly_DefaultALC() + { + Console.WriteLine($"Running {nameof(NonExistentAssembly_DefaultALC)}..."); + using (var listener = new BinderEventListener()) + { + string assemblyName = "DoesNotExist"; + try + { + Assembly.Load(assemblyName); + } + catch { } + + BindEvent[] events = listener.WaitAndGetEventsForAssembly(assemblyName); + Assert.True(events.Length == 1, $"Bind event count for {assemblyName} - expected: 1, actual: {events.Length}"); + BindEvent bindEvent = events[0]; + Assert.False(bindEvent.Success, $"Expected bind for {assemblyName} to fail"); + } + } + + public static int Main(string[] unused) + { + try + { + PlatformAssembly_DefaultALC(); + NonExistentAssembly_DefaultALC(); + } + catch (Exception e) + { + Console.WriteLine($"Test Failure: {e}"); + return 101; + } + + return 100; + } + } +} diff --git a/tests/src/Loader/binding/tracing/BinderTracingTest.csproj b/tests/src/Loader/binding/tracing/BinderTracingTest.csproj new file mode 100644 index 000000000000..286fec50b3da --- /dev/null +++ b/tests/src/Loader/binding/tracing/BinderTracingTest.csproj @@ -0,0 +1,12 @@ + + + Exe + + + + + + + + +