<XunitPackageVersion>2.4.1-pre.build.4059</XunitPackageVersion>
<XunitPerformanceApiPackageVersion>1.0.0-beta-build0015</XunitPerformanceApiPackageVersion>
<MicrosoftDiagnosticsTracingTraceEventPackageVersion>2.0.43</MicrosoftDiagnosticsTracingTraceEventPackageVersion>
+ <MicrosoftDiagnosticsToolsRuntimeClientVersion>1.0.4-preview6.19326.1</MicrosoftDiagnosticsToolsRuntimeClientVersion>
<CommandLineParserVersion>2.2.0</CommandLineParserVersion>
<!-- Scenario tests install this version of Microsoft.NetCore.App, then patch coreclr binaries via xcopy. At the moment it is
<PackageReference Include="System.Runtime.Intrinsics.Experimental">
<Version>$(MicrosoftPrivateCoreFxNETCoreAppVersion)</Version>
</PackageReference>
+ <PackageReference Include="Microsoft.Diagnostics.Tools.RuntimeClient">
+ <Version>$(MicrosoftDiagnosticsToolsRuntimeClientVersion)</Version>
+ </PackageReference>
</ItemGroup>
<PropertyGroup>
<TargetFramework>netcoreapp3.0</TargetFramework>
--- /dev/null
+// 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.Diagnostics.Tracing;
+using System.IO;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Collections.Generic;
+using Microsoft.Diagnostics.Tools.RuntimeClient;
+using Tracing.Tests.Common;
+
+namespace Tracing.Tests.BufferValidation
+{
+ public sealed class MyEventSource : EventSource
+ {
+ private MyEventSource() {}
+ public static MyEventSource Log = new MyEventSource();
+ public void MyEvent() { WriteEvent(1, "MyEvent"); }
+ }
+
+ public class BufferValidation
+ {
+ public static int Main(string[] args)
+ {
+ // This tests the resilience of message sending with
+ // smaller buffers, specifically 1MB and 4MB
+
+ var providers = new List<Provider>()
+ {
+ new Provider("MyEventSource")
+ };
+
+ var tests = new int[] { 0, 2 }
+ .Select(x => (uint)Math.Pow(2, x))
+ .Select(bufferSize => new SessionConfiguration(circularBufferSizeMB: bufferSize, format: EventPipeSerializationFormat.NetTrace, providers: providers))
+ .Select<SessionConfiguration, Func<int>>(configuration => () => IpcTraceTest.RunAndValidateEventCounts(_expectedEventCounts, _eventGeneratingAction, configuration));
+
+ foreach (var test in tests)
+ {
+ var ret = test();
+ if (ret < 0)
+ return ret;
+ }
+
+ return 100;
+ }
+
+ private static Dictionary<string, ExpectedEventCount> _expectedEventCounts = new Dictionary<string, ExpectedEventCount>()
+ {
+ // We're testing small buffer sizes, so we expect some [read: many] dropped events
+ // especially on the resource strapped CI machines. Since the number of dropped events
+ // can be quite large depending on the OS x Arch configuration, we'll only check
+ // for presence and leave counting events to the providervalidation test.
+ { "MyEventSource", -1 }
+ };
+
+ private static Action _eventGeneratingAction = () =>
+ {
+ foreach (var _ in Enumerable.Range(0,1000))
+ {
+ MyEventSource.Log.MyEvent();
+ }
+ };
+ }
+}
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <SchemaVersion>2.0</SchemaVersion>
+ <TargetFramework>netcoreapp3.0</TargetFramework>
+ <TargetFrameworkIdentifier>.NETCoreApp</TargetFrameworkIdentifier>
+ <ProjectGuid>{8E3244CB-407F-4142-BAAB-E7A55901A5FA}</ProjectGuid>
+ <OutputType>exe</OutputType>
+ <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+ <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir>
+ <CLRTestKind>BuildAndRun</CLRTestKind>
+ <DefineConstants>$(DefineConstants);STATIC</DefineConstants>
+ <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+ <CLRTestPriority>0</CLRTestPriority>
+ </PropertyGroup>
+ <!-- Default configurations to help VS understand the configurations -->
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
+ </PropertyGroup>
+ <ItemGroup>
+ <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies">
+ <Visible>False</Visible>
+ </CodeAnalysisDependentAssemblyPaths>
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="buffersize.cs" />
+ <ProjectReference Include="../common/common.csproj" />
+ </ItemGroup>
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+</Project>
--- /dev/null
+// 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.Diagnostics;
+using System.Diagnostics.Tracing;
+using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Collections.Generic;
+using Microsoft.Diagnostics.Tracing;
+using Microsoft.Diagnostics.Tools.RuntimeClient;
+
+namespace Tracing.Tests.Common
+{
+ public class ExpectedEventCount
+ {
+ // The acceptable percent error on the expected value
+ // represented as a floating point value in [0,1].
+ public float Error { get; private set; }
+
+ // The expected count of events. A value of -1 indicates
+ // that count does not matter, and we are simply testing
+ // that the provider exists in the trace.
+ public int Count { get; private set; }
+
+ public ExpectedEventCount(int count, float error = 0.0f)
+ {
+ Count = count;
+ Error = error;
+ }
+
+ public bool Validate(int actualValue)
+ {
+ return Count == -1 || CheckErrorBounds(actualValue);
+ }
+
+ public bool CheckErrorBounds(int actualValue)
+ {
+ return Math.Abs(actualValue - Count) <= (Count * Error);
+ }
+
+ public static implicit operator ExpectedEventCount(int i)
+ {
+ return new ExpectedEventCount(i);
+ }
+
+ public override string ToString()
+ {
+ return $"{Count} +- {Count * Error}";
+ }
+ }
+
+ // This event source is used by the test infra to
+ // to insure that providers have finished being enabled
+ // for the session being observed. Since the client API
+ // returns the pipe for reading _before_ it finishes
+ // enabling the providers to write to that session,
+ // we need to guarantee that our providers are on before
+ // sending events. This is a _unique_ problem I imagine
+ // should _only_ affect scenarios like these tests
+ // where the reading and sending of events are required
+ // to synchronize.
+ public sealed class SentinelEventSource : EventSource
+ {
+ private SentinelEventSource() {}
+ public static SentinelEventSource Log = new SentinelEventSource();
+ public void SentinelEvent() { WriteEvent(1, "SentinelEvent"); }
+ }
+
+ public static class SessionConfigurationExtensions
+ {
+ public static SessionConfiguration InjectSentinel(this SessionConfiguration sessionConfiguration)
+ {
+ var newProviderList = new List<Provider>(sessionConfiguration.Providers);
+ newProviderList.Add(new Provider("SentinelEventSource"));
+ return new SessionConfiguration(sessionConfiguration.CircularBufferSizeInMB, sessionConfiguration.Format, newProviderList.AsReadOnly());
+ }
+ }
+
+ public class IpcTraceTest
+ {
+ // This Action is executed while the trace is being collected.
+ private Action _eventGeneratingAction;
+
+ // A dictionary of event providers to number of events.
+ // A count of -1 indicates that you are only testing for the presence of the provider
+ // and don't care about the number of events sent
+ private Dictionary<string, ExpectedEventCount> _expectedEventCounts;
+ private Dictionary<string, int> _actualEventCounts = new Dictionary<string, int>();
+ private SessionConfiguration _sessionConfiguration;
+
+ // A function to be called with the EventPipeEventSource _before_
+ // the call to `source.Process()`. The function should return another
+ // function that will be called to check whether the optional test was validated.
+ // Example in situ: providervalidation.cs
+ private Func<EventPipeEventSource, Func<int>> _optionalTraceValidator;
+
+ IpcTraceTest(
+ Dictionary<string, ExpectedEventCount> expectedEventCounts,
+ Action eventGeneratingAction,
+ SessionConfiguration? sessionConfiguration = null,
+ Func<EventPipeEventSource, Func<int>> optionalTraceValidator = null)
+ {
+ _eventGeneratingAction = eventGeneratingAction;
+ _expectedEventCounts = expectedEventCounts;
+ _sessionConfiguration = sessionConfiguration?.InjectSentinel() ?? new SessionConfiguration(
+ circularBufferSizeMB: 1000,
+ format: EventPipeSerializationFormat.NetTrace,
+ providers: new List<Provider> { new Provider("Microsoft-Windows-DotNETRuntime") });
+ _optionalTraceValidator = optionalTraceValidator;
+ }
+
+ private int Fail(string message = "")
+ {
+ Console.WriteLine("Test FAILED!");
+ Console.WriteLine(message);
+ Console.WriteLine("Configuration:");
+ Console.WriteLine("{");
+ Console.WriteLine($"\tbufferSize: {_sessionConfiguration.CircularBufferSizeInMB},");
+ Console.WriteLine("\tproviders: [");
+ foreach (var provider in _sessionConfiguration.Providers)
+ {
+ Console.WriteLine($"\t\t{provider.ToString()},");
+ }
+ Console.WriteLine("\t]");
+ Console.WriteLine("}\n");
+ Console.WriteLine("Expected:");
+ Console.WriteLine("{");
+ foreach (var (k, v) in _expectedEventCounts)
+ {
+ Console.WriteLine($"\t\"{k}\" = {v}");
+ }
+ Console.WriteLine("}\n");
+
+ Console.WriteLine("Actual:");
+ Console.WriteLine("{");
+ foreach (var (k, v) in _actualEventCounts)
+ {
+ Console.WriteLine($"\t\"{k}\" = {v}");
+ }
+ Console.WriteLine("}");
+
+ return -1;
+ }
+
+ private int Validate()
+ {
+ var processId = Process.GetCurrentProcess().Id;
+ var binaryReader = EventPipeClient.CollectTracing(processId, _sessionConfiguration, out var eventpipeSessionId);
+ if (eventpipeSessionId == 0)
+ return -1;
+
+ // CollectTracing returns before EventPipe::Enable has returned, so the
+ // the sources we want to listen for may not have been enabled yet.
+ // We'll use this sentinel EventSource to check if Enable has finished
+ ManualResetEvent sentinelEventReceived = new ManualResetEvent(false);
+ var sentinelTask = new Task(() =>
+ {
+ while (!sentinelEventReceived.WaitOne(50))
+ {
+ SentinelEventSource.Log.SentinelEvent();
+ }
+ });
+ sentinelTask.Start();
+
+ EventPipeEventSource source = null;
+ Func<int> optionalTraceValidationCallback = null;
+ var readerTask = new Task(() =>
+ {
+ source = new EventPipeEventSource(binaryReader);
+ source.Dynamic.All += (eventData) =>
+ {
+ if (eventData.ProviderName == "SentinelEventSource")
+ {
+ sentinelEventReceived.Set();
+ }
+ else if (_actualEventCounts.TryGetValue(eventData.ProviderName, out _))
+ {
+ _actualEventCounts[eventData.ProviderName]++;
+ }
+ else
+ {
+ _actualEventCounts[eventData.ProviderName] = 1;
+ }
+ };
+
+ if (_optionalTraceValidator != null)
+ {
+ optionalTraceValidationCallback = _optionalTraceValidator(source);
+ }
+
+ source.Process();
+ });
+
+ readerTask.Start();
+ sentinelEventReceived.WaitOne();
+ _eventGeneratingAction();
+ EventPipeClient.StopTracing(processId, eventpipeSessionId);
+
+ readerTask.Wait();
+
+ foreach (var (provider, expectedCount) in _expectedEventCounts)
+ {
+ if (_actualEventCounts.TryGetValue(provider, out var actualCount))
+ {
+ if (!expectedCount.Validate(actualCount))
+ {
+ return Fail($"Event count mismatch for provider \"{provider}\": expected {expectedCount}, but saw {actualCount}");
+ }
+ }
+ else
+ {
+ return Fail($"No events for provider \"{provider}\"");
+ }
+ }
+
+ if (optionalTraceValidationCallback != null)
+ {
+ return optionalTraceValidationCallback();
+ }
+ else
+ {
+ return 100;
+ }
+ }
+
+ public static int RunAndValidateEventCounts(
+ Dictionary<string, ExpectedEventCount> expectedEventCounts,
+ Action eventGeneratingAction,
+ SessionConfiguration? sessionConfiguration = null,
+ Func<EventPipeEventSource, Func<int>> optionalTraceValidator = null)
+ {
+ Console.WriteLine("TEST STARTING");
+ var test = new IpcTraceTest(expectedEventCounts, eventGeneratingAction, sessionConfiguration, optionalTraceValidator);
+ try
+ {
+ var ret = test.Validate();
+ if (ret == 100)
+ Console.WriteLine("TEST PASSED!");
+ return ret;
+ }
+ catch (Exception e)
+ {
+ Console.WriteLine("TEST FAILED!");
+ Console.WriteLine(e);
+ return -1;
+ }
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <SchemaVersion>2.0</SchemaVersion>
+ <TargetFramework>netcoreapp3.0</TargetFramework>
+ <TargetFrameworkIdentifier>.NETCoreApp</TargetFrameworkIdentifier>
+ <ProjectGuid>{8E3244CB-407F-4142-BAAB-E7A55901A5FA}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+ <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir>
+ <CLRTestKind>SharedLibrary</CLRTestKind>
+ <!-- <DefineConstants>$(DefineConstants);STATIC</DefineConstants> -->
+ <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+ <IsTestProject>false</IsTestProject>
+ </PropertyGroup>
+ <!-- Default configurations to help VS understand the configurations -->
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
+ </PropertyGroup>
+ <ItemGroup>
+ <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies">
+ <Visible>False</Visible>
+ </CodeAnalysisDependentAssemblyPaths>
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="IpcTraceTest.cs" />
+ </ItemGroup>
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+</Project>
--- /dev/null
+// 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.Diagnostics.Tracing;
+using System.IO;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Collections.Generic;
+using Microsoft.Diagnostics.Tools.RuntimeClient;
+using Microsoft.Diagnostics.Tracing;
+using Tracing.Tests.Common;
+
+namespace Tracing.Tests.ProviderValidation
+{
+ public sealed class MyEventSource : EventSource
+ {
+ private MyEventSource() {}
+ public static MyEventSource Log = new MyEventSource();
+ public void MyEvent() { WriteEvent(1, "MyEvent"); }
+ }
+
+ public class ProviderValidation
+ {
+ public static int Main(string[] args)
+ {
+ // This test validates that the rundown events are present
+ // and that providers turned on that generate events are being written to
+ // the stream.
+
+ var providers = new List<Provider>()
+ {
+ new Provider("MyEventSource"),
+ new Provider("Microsoft-DotNETCore-SampleProfiler")
+ };
+
+ var tests = new int[] { 4, 10 }
+ .Select(x => (uint)Math.Pow(2, x))
+ .Select(bufferSize => new SessionConfiguration(circularBufferSizeMB: bufferSize, format: EventPipeSerializationFormat.NetTrace, providers: providers))
+ .Select<SessionConfiguration, Func<int>>(configuration => () => IpcTraceTest.RunAndValidateEventCounts(_expectedEventCounts, _eventGeneratingAction, configuration));
+
+ foreach (var test in tests)
+ {
+ var ret = test();
+ if (ret < 0)
+ return ret;
+ }
+
+ return 100;
+ }
+
+ private static Dictionary<string, ExpectedEventCount> _expectedEventCounts = new Dictionary<string, ExpectedEventCount>()
+ {
+ { "MyEventSource", new ExpectedEventCount(1000, 0.30f) },
+ { "Microsoft-Windows-DotNETRuntimeRundown", -1 },
+ { "Microsoft-DotNETCore-SampleProfiler", -1 }
+ };
+
+ private static Action _eventGeneratingAction = () =>
+ {
+ foreach (var _ in Enumerable.Range(0,1000))
+ {
+ MyEventSource.Log.MyEvent();
+ }
+ };
+ }
+}
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <SchemaVersion>2.0</SchemaVersion>
+ <TargetFramework>netcoreapp3.0</TargetFramework>
+ <TargetFrameworkIdentifier>.NETCoreApp</TargetFrameworkIdentifier>
+ <ProjectGuid>{8E3244CB-407F-4142-BAAB-E7A55901A5FA}</ProjectGuid>
+ <OutputType>exe</OutputType>
+ <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+ <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir>
+ <CLRTestKind>BuildAndRun</CLRTestKind>
+ <DefineConstants>$(DefineConstants);STATIC</DefineConstants>
+ <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+ <CLRTestPriority>0</CLRTestPriority>
+ </PropertyGroup>
+ <!-- Default configurations to help VS understand the configurations -->
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
+ </PropertyGroup>
+ <ItemGroup>
+ <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies">
+ <Visible>False</Visible>
+ </CodeAnalysisDependentAssemblyPaths>
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="providervalidation.cs" />
+ <ProjectReference Include="../common/common.csproj" />
+ </ItemGroup>
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+</Project>
--- /dev/null
+// 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.Diagnostics.Tracing;
+using System.IO;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Collections.Generic;
+using Microsoft.Diagnostics.Tools.RuntimeClient;
+using Microsoft.Diagnostics.Tracing;
+using Tracing.Tests.Common;
+using Microsoft.Diagnostics.Tracing.Parsers.Clr;
+
+namespace Tracing.Tests.RundownValidation
+{
+
+ public class RundownValidation
+ {
+ public static int Main(string[] args)
+ {
+ // This test validates that the rundown events are present
+ // and that the rundown contains the necessary events to get
+ // symbols in a nettrace file.
+
+ var providers = new List<Provider>()
+ {
+ new Provider("Microsoft-DotNETCore-SampleProfiler")
+ };
+
+ var configuration = new SessionConfiguration(circularBufferSizeMB: 1024, format: EventPipeSerializationFormat.NetTrace, providers: providers);
+ return IpcTraceTest.RunAndValidateEventCounts(_expectedEventCounts, _eventGeneratingAction, configuration, _DoesRundownContainMethodEvents);
+ }
+
+ private static Dictionary<string, ExpectedEventCount> _expectedEventCounts = new Dictionary<string, ExpectedEventCount>()
+ {
+ { "Microsoft-Windows-DotNETRuntimeRundown", -1 }
+ };
+
+ // We only care about rundown so skip generating any events.
+ private static Action _eventGeneratingAction = () => { };
+
+ private static Func<EventPipeEventSource, Func<int>> _DoesRundownContainMethodEvents = (source) =>
+ {
+ bool hasMethodDCStopVerbose = false;
+ bool hasMethodILToNativeMap = false;
+ ClrRundownTraceEventParser rundownParser = new ClrRundownTraceEventParser(source);
+ rundownParser.MethodDCStopVerbose += (eventData) => hasMethodDCStopVerbose = true;
+ rundownParser.MethodILToNativeMapDCStop += (eventData) => hasMethodILToNativeMap = true;
+ return () => hasMethodDCStopVerbose && hasMethodILToNativeMap ? 100 : -1;
+ };
+ }
+}
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <SchemaVersion>2.0</SchemaVersion>
+ <TargetFramework>netcoreapp3.0</TargetFramework>
+ <TargetFrameworkIdentifier>.NETCoreApp</TargetFrameworkIdentifier>
+ <ProjectGuid>{8E3244CB-407F-4142-BAAB-E7A55901A5FA}</ProjectGuid>
+ <OutputType>exe</OutputType>
+ <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+ <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir>
+ <CLRTestKind>BuildAndRun</CLRTestKind>
+ <DefineConstants>$(DefineConstants);STATIC</DefineConstants>
+ <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+ <CLRTestPriority>0</CLRTestPriority>
+ </PropertyGroup>
+ <!-- Default configurations to help VS understand the configurations -->
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
+ </PropertyGroup>
+ <ItemGroup>
+ <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies">
+ <Visible>False</Visible>
+ </CodeAnalysisDependentAssemblyPaths>
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="rundownvalidation.cs" />
+ <ProjectReference Include="../common/common.csproj" />
+ </ItemGroup>
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+</Project>