Switch tests to use aspnet.xunit.performance

This commit is contained in:
Pranav K 2015-10-02 16:19:35 -07:00
Родитель cd30ee9821
Коммит 131ea13e15
44 изменённых файлов: 38 добавлений и 1541 удалений

Просмотреть файл

@ -1,7 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<add key="AspNetLiteDev" value="https://www.myget.org/F/aspnetlitedev/api/v2" />
<add key="AspNetLiteDev" value="https://www.myget.org/F/aspnetcidev/api/v2" />
<add key="NuGet" value="https://api.nuget.org/v3/index.json" />
<add key="StressTools" value="https://www.myget.org/F/aspnetstress/api/v3/index.json" />
</packageSources>
</configuration>

Просмотреть файл

@ -15,8 +15,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{BB74
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{C1B84D1C-2AF9-419D-BD57-16B87F377256}"
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.StressFramework", "src\Microsoft.AspNet.StressFramework\Microsoft.AspNet.StressFramework.xproj", "{1C90BF69-88B0-4079-9F90-48FE5ABE3B25}"
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Stress.Tests", "test\Microsoft.AspNet.Stress.Tests\Microsoft.AspNet.Stress.Tests.xproj", "{489E5EDA-D686-4B57-9C5D-70B7879EF7E8}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "websites", "websites", "{6BF7AF55-1A79-4C18-9DA7-68F52D319A3A}"
@ -29,10 +27,6 @@ Global
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{1C90BF69-88B0-4079-9F90-48FE5ABE3B25}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1C90BF69-88B0-4079-9F90-48FE5ABE3B25}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1C90BF69-88B0-4079-9F90-48FE5ABE3B25}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1C90BF69-88B0-4079-9F90-48FE5ABE3B25}.Release|Any CPU.Build.0 = Release|Any CPU
{489E5EDA-D686-4B57-9C5D-70B7879EF7E8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{489E5EDA-D686-4B57-9C5D-70B7879EF7E8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{489E5EDA-D686-4B57-9C5D-70B7879EF7E8}.Release|Any CPU.ActiveCfg = Release|Any CPU
@ -46,7 +40,6 @@ Global
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{1C90BF69-88B0-4079-9F90-48FE5ABE3B25} = {C1B84D1C-2AF9-419D-BD57-16B87F377256}
{489E5EDA-D686-4B57-9C5D-70B7879EF7E8} = {7B63597D-863D-46C4-9F9E-D60E74435E81}
{6BF7AF55-1A79-4C18-9DA7-68F52D319A3A} = {7B63597D-863D-46C4-9F9E-D60E74435E81}
{DF9C97D9-66EE-4171-9748-AF67057DC7AC} = {6BF7AF55-1A79-4C18-9DA7-68F52D319A3A}

Просмотреть файл

@ -1,37 +0,0 @@
using System;
using System.Threading.Tasks;
namespace Microsoft.AspNet.StressFramework
{
public class BasicDriver : IStressTestDriver
{
private readonly IStressTestHost _host;
private readonly Func<Task> _execute;
public BasicDriver(Func<Task> execute)
{
_execute = execute;
}
public void Setup(StressTestDriverContext context)
{
context.Setup.Host.Setup();
}
public async Task RunAsync(StressTestDriverContext context)
{
StressTestTrace.WriteRawLine("Begin warmup");
for (var i = 0; i < context.Setup.WarmupIterations; i++)
{
await _execute();
}
StressTestTrace.WriteRawLine("End warmup");
for (var i = 0; i < context.Setup.Iterations; i++)
{
await _execute();
}
}
}
}

Просмотреть файл

@ -1,36 +0,0 @@
using System;
using System.Threading.Tasks;
namespace Microsoft.AspNet.StressFramework
{
public class BasicHost : IStressTestHost
{
private Func<Task> _execute;
public BasicHost(Func<Task> execute)
{
_execute = execute;
}
public void Run(StressTestHostContext context)
{
Console.WriteLine("Executing host.");
for (var i = 0; i < context.WarmupIterations; i++)
{
_execute();
}
for (var i = 0; i < context.Iterations; i++)
{
_execute();
}
Console.WriteLine("Done executing host.");
}
public void Setup()
{
}
}
}

Просмотреть файл

@ -1,31 +0,0 @@
using System;
using System.Threading.Tasks;
namespace Microsoft.AspNet.StressFramework
{
public class BenchmarkingDriver : IStressTestDriver, IDisposable
{
private StressTestHostProcess _process;
public void Setup(StressTestDriverContext context)
{
StressTestTrace.WriteLine("Initializing Host");
_process = StressTestHostProcess.Launch(context.TestMethod, StressTestTrace.WriteRawLine);
}
public Task RunAsync(StressTestDriverContext context)
{
StressTestTrace.WriteLine("Host Start");
_process.BeginIterations();
_process.Process.WaitForExit();
StressTestTrace.WriteLine("Host End");
return Task.FromResult(0);
}
public void Dispose()
{
_process?.Dispose();
}
}
}

Просмотреть файл

@ -1,29 +0,0 @@
using System;
using System.Diagnostics;
namespace Microsoft.AspNet.StressFramework
{
public struct CpuTime
{
public TimeSpan KernelTime { get; }
public TimeSpan UserTime { get; }
public CpuTime(TimeSpan kernelTime, TimeSpan userTime)
{
KernelTime = kernelTime;
UserTime = userTime;
}
public static CpuTime Capture(Process process)
{
return new CpuTime(
process.PrivilegedProcessorTime,
process.UserProcessorTime);
}
public override string ToString()
{
return $"K: {KernelTime}; U: {UserTime}";
}
}
}

Просмотреть файл

@ -1,17 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Microsoft.AspNet.StressFramework.Collectors
{
public struct ElapsedTime
{
public TimeSpan Elapsed { get; }
public ElapsedTime(TimeSpan elapsed)
{
Elapsed = elapsed;
}
}
}

Просмотреть файл

@ -1,20 +0,0 @@
namespace Microsoft.AspNet.StressFramework.Collectors
{
public interface ICollector
{
/// <summary>
/// Called by the stress framework to initialize the collector, before any iterations have been run
/// </summary>
void Initialize();
/// <summary>
/// Called by the stress framework before a non-warmup iteration is executed.
/// </summary>
void BeginIteration(StressTestIterationContext context);
/// <summary>
/// Called by the stress framework after a non-warmup iteration is executed.
/// </summary>
void EndIteration(StressTestIterationContext context);
}
}

Просмотреть файл

@ -1,47 +0,0 @@
using System;
using System.Diagnostics;
namespace Microsoft.AspNet.StressFramework
{
public struct MemoryUsage
{
public long HeapMemoryBytes { get; }
public long WorkingSet { get; }
public long PrivateBytes { get; }
public MemoryUsage(long heapMemoryBytes, long workingSet, long privateBytes)
{
HeapMemoryBytes = heapMemoryBytes;
WorkingSet = workingSet;
PrivateBytes = privateBytes;
}
public static MemoryUsage Capture(Process process)
{
// Get the GC to run fully
for(int i = 0; i < 5; i++)
{
GC.GetTotalMemory(forceFullCollection: true);
}
var heap = GC.GetTotalMemory(forceFullCollection: true);
return new MemoryUsage(
heap,
process.WorkingSet64,
process.PrivateMemorySize64);
}
public override string ToString()
{
return $"Heap: {HeapMemoryBytes / 1024.0:0.00}KB, WorkingSet: {WorkingSet / 1024.0:0.00}KB, Private: {PrivateBytes / 1024.0:0.00}KB";
}
public static MemoryUsage Compare(MemoryUsage start, MemoryUsage end)
{
return new MemoryUsage(
end.HeapMemoryBytes - start.HeapMemoryBytes,
end.WorkingSet - start.WorkingSet,
end.PrivateBytes - start.PrivateBytes);
}
}
}

Просмотреть файл

@ -1,29 +0,0 @@
using System;
using Xunit.Abstractions;
namespace Microsoft.AspNet.StressFramework.Collectors
{
public class Metric
{
private Metric(DateTime timestampUtc, int iteration, object value)
{
Value = value;
Iteration = iteration;
TimestampUtc = timestampUtc;
}
public object Value { get; }
public int Iteration { get; }
public DateTime TimestampUtc { get; }
public static Metric Create(int iteration, object value)
{
return new Metric(DateTime.UtcNow, iteration, value);
}
public override string ToString()
{
return $"[{Iteration}|{TimestampUtc.ToLocalTime().ToString("O")}] {Value}";
}
}
}

Просмотреть файл

@ -1,19 +0,0 @@
using System.Collections.Generic;
using System.Linq;
using Xunit.Abstractions;
namespace Microsoft.AspNet.StressFramework.Collectors
{
public class MetricsRecordedMessage : IMessageSinkMessage
{
public MetricsRecordedMessage(ITest test, IEnumerable<Metric> metrics)
{
Test = test;
Metrics = metrics.ToList().AsReadOnly();
}
public ITest Test { get; }
public IReadOnlyList<Metric> Metrics { get; }
}
}

Просмотреть файл

@ -1,11 +0,0 @@
using System.Threading.Tasks;
namespace Microsoft.AspNet.StressFramework
{
public interface IStressTestDriver
{
void Setup(StressTestDriverContext context);
Task RunAsync(StressTestDriverContext context);
}
}

Просмотреть файл

@ -1,9 +0,0 @@
namespace Microsoft.AspNet.StressFramework
{
public interface IStressTestHost
{
void Setup();
void Run(StressTestHostContext context);
}
}

Просмотреть файл

@ -1,64 +0,0 @@
using System;
using System.Diagnostics;
namespace Microsoft.AspNet.StressFramework
{
public class KestrelHost : IStressTestHost, IDisposable
{
private readonly string _applicationPath;
private Process _process;
public KestrelHost(string applicationPath)
{
_applicationPath = applicationPath;
}
public void Setup()
{
var dnxProcess = Process.GetCurrentProcess();
_process = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = dnxProcess.MainModule.FileName,
Arguments = "kestrel",
WorkingDirectory = _applicationPath,
RedirectStandardError = true,
RedirectStandardOutput = true,
UseShellExecute = false,
CreateNoWindow = true
}
};
_process.OutputDataReceived += (sender, args) =>
{
StressTestTrace.WriteRawLine(args.Data);
};
_process.ErrorDataReceived += (sender, args) =>
{
StressTestTrace.WriteRawLine(args.Data);
};
_process.Start();
_process.BeginOutputReadLine();
_process.BeginErrorReadLine();
}
public void Run(StressTestHostContext context)
{
// Do nothing
}
public void Dispose()
{
if (!_process.HasExited)
{
_process.Kill();
}
_process.Dispose();
}
}
}

Просмотреть файл

@ -1,20 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
<PropertyGroup Label="Globals">
<ProjectGuid>1c90bf69-88b0-4079-9f90-48fe5abe3b25</ProjectGuid>
<RootNamespace>Microsoft.AspNet.StressFramework</RootNamespace>
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\artifacts\bin\$(MSBuildProjectName)\</OutputPath>
</PropertyGroup>
<PropertyGroup>
<SchemaVersion>2.0</SchemaVersion>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
</Project>

Просмотреть файл

@ -1,30 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.Dnx.Runtime;
using Microsoft.Dnx.Runtime.Infrastructure;
namespace Microsoft.AspNet.StressFramework
{
internal static class PlatformHelper
{
private static Lazy<IRuntimeEnvironment> _runtimeEnv = new Lazy<IRuntimeEnvironment>(() =>
(IRuntimeEnvironment)CallContextServiceLocator
.Locator
.ServiceProvider
.GetService(typeof(IRuntimeEnvironment)));
private static Lazy<bool> _isMono = new Lazy<bool>(() => RuntimeEnvironment.RuntimeType.Equals("Mono", StringComparison.OrdinalIgnoreCase));
private static Lazy<bool> _isWindows = new Lazy<bool>(() => RuntimeEnvironment.OperatingSystem.Equals("Windows", StringComparison.OrdinalIgnoreCase));
private static Lazy<bool> _isLinux = new Lazy<bool>(() => RuntimeEnvironment.OperatingSystem.Equals("Linux", StringComparison.OrdinalIgnoreCase));
private static Lazy<bool> _isMac = new Lazy<bool>(() => RuntimeEnvironment.OperatingSystem.Equals("Darwin", StringComparison.OrdinalIgnoreCase));
public static bool IsMono { get { return _isMono.Value; } }
public static bool IsWindows { get { return _isWindows.Value; } }
public static bool IsLinux { get { return _isLinux.Value; } }
public static bool IsMac { get { return _isMac.Value; } }
internal static IRuntimeEnvironment RuntimeEnvironment { get { return _runtimeEnv.Value; } }
}
}

Просмотреть файл

@ -1,76 +0,0 @@
using System;
using System.Linq;
using System.Reflection;
namespace Microsoft.AspNet.StressFramework
{
public class Program
{
public int Main(string[] args)
{
StressTestTrace.SetIsHost();
StressTestTrace.WriteLine("Host Launched");
if (args.Length != 3)
{
Console.Error.WriteLine("Usage: stresshost <TEST_LIBRARY> <TEST_CLASS> <TEST_METHOD>");
return -1;
}
var libraryName = args[0];
var className = args[1];
var methodName = args[2];
// Find the class
var asm = Assembly.Load(new AssemblyName(libraryName));
if (asm == null)
{
Console.Error.WriteLine($"Failed to load assembly: {libraryName}");
return -2;
}
var typ = asm.GetExportedTypes().FirstOrDefault(t => t.FullName.Equals(className));
if (typ == null)
{
Console.Error.WriteLine($"Failed to locate type: {className} in {libraryName}");
return -3;
}
var method = typ.GetMethods()
.SingleOrDefault(m =>
m.Name.Equals(methodName) &&
typeof(StressRunSetup).IsAssignableFrom(m.ReturnType) &&
m.IsPublic &&
m.GetParameters().Length == 0);
if (method == null)
{
Console.Error.WriteLine($"Failed to locate method: {methodName} in {className}");
return -4;
}
// Construct the class and invoke the method
var instance = Activator.CreateInstance(typ);
var setup = (StressRunSetup)method.Invoke(instance, new object[0]);
StressTestTrace.WriteLine("Host Ready for release");
setup.Host.Setup();
// Read the release message from the standard input
var released = Console.ReadLine();
if (!string.Equals(StressTestHostProcess.ReleaseMessage, released, StringComparison.Ordinal))
{
StressTestTrace.WriteLine("Host received invalid release message. Aborting");
}
// Run the host
StressTestTrace.WriteLine("Host Released");
var context = new StressTestHostContext
{
Iterations = setup.Iterations,
WarmupIterations = setup.WarmupIterations
};
setup.Host.Run(context);
StressTestTrace.WriteLine("Host Completed");
return 0;
}
}
}

Просмотреть файл

@ -1,28 +0,0 @@
using System.Collections.Generic;
using System.Linq;
using Xunit;
using Xunit.Abstractions;
namespace Microsoft.AspNet.StressFramework.Reporters
{
public class AggregateStressTestRunnerMessageHandler : StressTestRunnerMessageHandlerBase
{
private readonly List<IMessageSink> _messageHandlers;
public AggregateStressTestRunnerMessageHandler(IRunnerLogger logger)
: base(logger)
{
_messageHandlers = new List<IMessageSink>();
}
public void AddMessageHandler(IMessageSink messageHandler)
{
_messageHandlers.Add(messageHandler);
}
public override bool OnMessage(IMessageSinkMessage message)
{
return _messageHandlers.Aggregate(true, (current, next) => current && next.OnMessage(message));
}
}
}

Просмотреть файл

@ -1,41 +0,0 @@
using Microsoft.Framework.Configuration;
namespace Microsoft.AspNet.StressFramework.Reporters
{
public class BaselineConfiguration
{
private const string BaselineConfigurationSectionName = "baselineConfig";
private const string DefaultFolder = "StressBaselines";
private const int DefaultHeapMemoryFailPercentThreshold = 100;
public BaselineConfiguration()
{
Folder = DefaultFolder;
HeapMemoryFailPercentThreshold = DefaultHeapMemoryFailPercentThreshold;
}
public BaselineConfiguration(IConfigurationRoot configuration)
: this()
{
var baselineConfig = configuration.GetSection(BaselineConfigurationSectionName);
if (baselineConfig != null)
{
var folder = baselineConfig[nameof(Folder)];
if (string.IsNullOrEmpty(folder))
{
Folder = folder;
}
var failPercentThresholdString = baselineConfig[nameof(HeapMemoryFailPercentThreshold)];
if (string.IsNullOrEmpty(failPercentThresholdString))
{
HeapMemoryFailPercentThreshold = int.Parse(failPercentThresholdString);
}
}
}
public string Folder { get; }
public int HeapMemoryFailPercentThreshold { get; }
}
}

Просмотреть файл

@ -1,19 +0,0 @@
using Xunit;
using Xunit.Abstractions;
namespace Microsoft.AspNet.StressFramework.Reporters
{
public class DefaultStressTestRunnerReporter : DefaultRunnerReporter
{
internal const string Command = "stress";
public override string RunnerSwitch => Command;
public override string Description => "doesn't output stress test results.";
public override IMessageSink CreateMessageHandler(IRunnerLogger logger)
{
return new DefaultRunnerReporterMessageHandler(logger);
}
}
}

Просмотреть файл

@ -1,93 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Microsoft.AspNet.StressFramework.Collectors;
using Xunit.Abstractions;
namespace Microsoft.AspNet.StressFramework.Reporters
{
public static class StressTestOutputManager
{
private const string FileFormat = "{displayName}.{uniqueID}.metrics.csv";
private const string OutputDirectoryName = "TestOutput";
public static IReadOnlyList<Metric> ReadBaseline(ITest test)
{
var fileLocation = GetFileLocation(test);
// Assume the directory and file exists, if not we'll explode with a more informative error.
var fileLines = File.ReadAllLines(fileLocation);
try
{
var metrics = new List<Metric>();
// File format is CSV, start at index 1 to avoid the columns
for (var i = 1; i < fileLines.Length; i++)
{
var data = fileLines[i].Split(',');
var iteration = int.Parse(data[0]);
var elapsedTimeTicks = long.Parse(data[4]);
var elapsedTime = new ElapsedTime(TimeSpan.FromTicks(elapsedTimeTicks));
var elapsedTimeMetric = Metric.Create(iteration, elapsedTime);
metrics.Add(elapsedTimeMetric);
var heapMemoryBytes = long.Parse(data[1]);
var workingSet = long.Parse(data[2]);
var privateBytes = long.Parse(data[3]);
var memoryUsage = new MemoryUsage(heapMemoryBytes, workingSet, privateBytes);
var memoryUsageMetric = Metric.Create(iteration, memoryUsage);
metrics.Add(memoryUsageMetric);
}
return metrics;
}
catch (Exception ex)
{
throw new InvalidDataException(
$"Could not parse test file '{fileLocation}':{Environment.NewLine}Error: {ex.Message}", ex);
}
}
public static string WriteTestOutput(IReadOnlyList<Metric> metrics, ITest test)
{
var outputDirectory = GetOutputDirectoryLocation();
if (!Directory.Exists(outputDirectory))
{
Directory.CreateDirectory(outputDirectory);
}
var fileLocation = GetFileLocation(test);
using (var writer = new StreamWriter(new FileStream(fileLocation, FileMode.Create)))
{
writer.WriteLine("Iteration,Heap,WorkingSet,PrivateBytes,ElapsedTicks");
foreach (var iteration in metrics.GroupBy(g => g.Iteration).OrderBy(g => g.Key))
{
var elapsed = (ElapsedTime)iteration.Single(m => m.Value is ElapsedTime).Value;
var mem = (MemoryUsage)iteration.Single(m => m.Value is MemoryUsage).Value;
writer.WriteLine($"{iteration.Key},{mem.HeapMemoryBytes},{mem.WorkingSet},{mem.PrivateBytes},{elapsed.Elapsed.Ticks}");
}
}
return fileLocation;
}
private static string GetFileLocation(ITest test)
{
var outputDirectory = GetOutputDirectoryLocation();
var outputFile = Path.Combine(
outputDirectory,
string.Format(FileFormat, test.TestCase.DisplayName, test.TestCase.UniqueID));
return outputFile;
}
private static string GetOutputDirectoryLocation()
{
return Path.Combine(Directory.GetCurrentDirectory(), OutputDirectoryName);
}
}
}

Просмотреть файл

@ -1,53 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNet.StressFramework.Collectors;
using Xunit;
namespace Microsoft.AspNet.StressFramework.Reporters
{
public class StressTestRunnerBaselineMessageHandler : StressTestRunnerMessageHandlerBase
{
private readonly BaselineConfiguration _configuration;
public StressTestRunnerBaselineMessageHandler(BaselineConfiguration configuration, IRunnerLogger logger)
: base(logger)
{
_configuration = configuration;
}
protected override bool Visit(MetricsRecordedMessage metricsRecordedMessage)
{
var targetMetrics = metricsRecordedMessage.Metrics;
var baselineMetrics = StressTestOutputManager.ReadBaseline(metricsRecordedMessage.Test);
// Could be smarter here and throw away outliers etc.
var baselineHeapMemoryUsageAverage = AverageHeapMemoryUsage(baselineMetrics);
var targetHeapMemoryUsageAverage = AverageHeapMemoryUsage(targetMetrics);
var combinedHeapMemoryUsageAverage = (baselineHeapMemoryUsageAverage + targetHeapMemoryUsageAverage) / 2;
var percentDifference =
(Math.Abs(baselineHeapMemoryUsageAverage - targetHeapMemoryUsageAverage) / combinedHeapMemoryUsageAverage) * 100;
if (percentDifference > _configuration.HeapMemoryFailPercentThreshold)
{
Logger.LogError(
$@"Current stress test run resulted in an unexpectedly different heap memory usage.
Current run usage average: {targetHeapMemoryUsageAverage} bytes
Baseline run usage average: {baselineHeapMemoryUsageAverage} bytes
% Difference: {percentDifference}%
Fail threshold: {_configuration.HeapMemoryFailPercentThreshold}%");
}
return base.Visit(metricsRecordedMessage);
}
private static double AverageHeapMemoryUsage(IEnumerable<Metric> metrics)
{
return metrics
.Where(metric => metric.Value is MemoryUsage)
.Select(metric => ((MemoryUsage)metric.Value).HeapMemoryBytes)
.Average(heapMemoryUsage => heapMemoryUsage);
}
}
}

Просмотреть файл

@ -1,31 +0,0 @@
using Xunit;
using Xunit.Abstractions;
namespace Microsoft.AspNet.StressFramework.Reporters
{
public class StressTestRunnerBaselineReporter : DefaultRunnerReporter
{
internal const string Command = "stressbaseline";
private readonly BaselineConfiguration _configuration;
public StressTestRunnerBaselineReporter()
: this(new BaselineConfiguration())
{
}
public StressTestRunnerBaselineReporter(BaselineConfiguration configuration)
{
_configuration = configuration;
}
public override string RunnerSwitch => Command;
public override string Description => "compares stress run results to existing CSV stress test baselines.";
public override IMessageSink CreateMessageHandler(IRunnerLogger logger)
{
return new StressTestRunnerBaselineMessageHandler(_configuration, logger);
}
}
}

Просмотреть файл

@ -1,26 +0,0 @@
using System.Diagnostics;
using Microsoft.AspNet.StressFramework.Collectors;
using Xunit;
namespace Microsoft.AspNet.StressFramework.Reporters
{
public class StressTestRunnerCSVMessageHandler : StressTestRunnerMessageHandlerBase
{
public StressTestRunnerCSVMessageHandler(IRunnerLogger logger)
: base(logger)
{
}
protected override bool Visit(MetricsRecordedMessage metricsRecordedMessage)
{
Debug.Assert(metricsRecordedMessage.Test.TestCase is StressTestCase);
var fileLocation = StressTestOutputManager.WriteTestOutput(metricsRecordedMessage.Metrics, metricsRecordedMessage.Test);
Logger.LogMessage(
$"Stress test {metricsRecordedMessage.Test.DisplayName} metrics file generated at: {fileLocation}");
return true;
}
}
}

Просмотреть файл

@ -1,19 +0,0 @@
using Xunit;
using Xunit.Abstractions;
namespace Microsoft.AspNet.StressFramework.Reporters
{
public class StressTestRunnerCSVReporter : DefaultRunnerReporter
{
internal const string Command = "stresscsv";
public override string RunnerSwitch => Command;
public override string Description => "output stress test results to CSV files. 1 CSV file per test.";
public override IMessageSink CreateMessageHandler(IRunnerLogger logger)
{
return new StressTestRunnerCSVMessageHandler(logger);
}
}
}

Просмотреть файл

@ -1,81 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using Microsoft.Framework.Configuration;
using Xunit;
using Xunit.Abstractions;
namespace Microsoft.AspNet.StressFramework.Reporters
{
public class StressTestRunnerConfigReporter : DefaultRunnerReporter
{
private const string StressConfigFileName = "stressConfig.json";
private const string CommandConfigName = "Command";
private IEnumerable<IRunnerReporter> _activeReporters;
public override string RunnerSwitch => "stressconfig";
public override string Description => "determine stress output mechanism based on ";
public override IMessageSink CreateMessageHandler(IRunnerLogger logger)
{
if (_activeReporters == null)
{
var reporters = new List<IRunnerReporter>();
var stressConfigFile = new FileInfo(StressConfigFileName);
if (!stressConfigFile.Exists)
{
throw new InvalidOperationException(
$"Cannot determine stress configuration. {StressConfigFileName} does not exist.");
}
var config = new ConfigurationBuilder(".").AddJsonFile(StressConfigFileName).Build();
var reporterBuilders = new Dictionary<string, Func<IRunnerReporter>>(StringComparer.OrdinalIgnoreCase)
{
{ DefaultStressTestRunnerReporter.Command, () => new DefaultStressTestRunnerReporter() },
{ StressTestRunnerCSVReporter.Command, () => new StressTestRunnerCSVReporter() },
{
StressTestRunnerBaselineReporter.Command,
() =>
{
var baselineConfiguration = new BaselineConfiguration(config);
var baselineReporter = new StressTestRunnerBaselineReporter(baselineConfiguration);
return baselineReporter;
}
},
};
// Can expand this to support multiple, comma separated commands.
// Ex: "stressbaseline,stresscsv" to signal that we want to run a baseline and then save the results.
var command = config[CommandConfigName];
Func<IRunnerReporter> reporterBuilder;
if (string.IsNullOrEmpty(command))
{
reporterBuilder = reporterBuilders[DefaultStressTestRunnerReporter.Command];
}
else if (!reporterBuilders.TryGetValue(command, out reporterBuilder))
{
throw new InvalidOperationException(
$"Unknown {CommandConfigName} value in {StressConfigFileName}.");
}
var reporter = reporterBuilder();
reporters.Add(reporter);
_activeReporters = reporters;
}
var aggregateMessageHandler = new AggregateStressTestRunnerMessageHandler(logger);
foreach (var reporter in _activeReporters)
{
var resolvedMessageHandler = reporter.CreateMessageHandler(logger);
aggregateMessageHandler.AddMessageHandler(resolvedMessageHandler);
}
return aggregateMessageHandler;
}
}
}

Просмотреть файл

@ -1,38 +0,0 @@
using System;
using Microsoft.AspNet.StressFramework.Collectors;
using Xunit;
using Xunit.Abstractions;
namespace Microsoft.AspNet.StressFramework.Reporters
{
public abstract class StressTestRunnerMessageHandlerBase : DefaultRunnerReporterMessageHandler
{
public StressTestRunnerMessageHandlerBase(IRunnerLogger logger)
: base(logger)
{
}
public override bool OnMessage(IMessageSinkMessage message)
{
return DoVisit<MetricsRecordedMessage>(message, (t, m) => t.Visit(m)) &&
base.OnMessage(message);
}
protected virtual bool Visit(MetricsRecordedMessage metric)
{
return true;
}
bool DoVisit<TMessage>(IMessageSinkMessage message, Func<StressTestRunnerMessageHandlerBase, TMessage, bool> callback)
where TMessage : class, IMessageSinkMessage
{
var castMessage = message as TMessage;
if (castMessage != null)
{
return callback(this, castMessage);
}
return true;
}
}
}

Просмотреть файл

@ -1,40 +0,0 @@
using System;
using System.Threading.Tasks;
namespace Microsoft.AspNet.StressFramework
{
public class StressRunSetup
{
public IStressTestHost Host { get; set; }
public IStressTestDriver Driver { get; set; }
public int WarmupIterations { get; set; } = 1;
public int Iterations { get; set; } = 50;
public static StressRunSetup CreateTest(Func<Task> execute)
{
var host = new BasicHost(execute);
var driver = new BenchmarkingDriver();
return new StressRunSetup
{
Host = host,
Driver = driver,
};
}
public static StressRunSetup CreateClientServerTest(string applicationPath, Func<Task> execute)
{
var host = new KestrelHost(applicationPath);
var driver = new BasicDriver(execute);
return new StressRunSetup
{
Host = host,
Driver = driver,
};
}
}
}

Просмотреть файл

@ -1,16 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Xunit;
using Xunit.Sdk;
namespace Microsoft.AspNet.StressFramework
{
[XunitTestCaseDiscoverer("Microsoft.AspNet.StressFramework.StressTestDiscoverer", "Microsoft.AspNet.StressFramework")]
public class StressTestAttribute : FactAttribute
{
public int Iterations { get; set; } = 100;
public int WarmupIterations { get; set; } = 1;
}
}

Просмотреть файл

@ -1,82 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNet.StressFramework.Collectors;
using Xunit;
using Xunit.Abstractions;
using Xunit.Sdk;
namespace Microsoft.AspNet.StressFramework
{
public class StressTestCase : XunitTestCase
{
#if DNX451
[NonSerialized]
#endif
private readonly List<ICollector> _collectors;
#if DNX451
[NonSerialized]
#endif
private readonly IMessageSink _diagnosticMessageSink;
public StressTestCase(
int iterations,
int warmupIterations,
IMessageSink diagnosticMessageSink,
ITestMethod testMethod,
object[] testMethodArguments)
: base(diagnosticMessageSink, Xunit.Sdk.TestMethodDisplay.Method, testMethod, null)
{
var suppliedDisplayName = TestMethod.Method.GetCustomAttributes(typeof(FactAttribute))
.First()
.GetNamedArgument<string>("DisplayName");
// Load collectors
_collectors = TestMethod.Method
.GetCustomAttributes(typeof(ICollector))
.OfType<ReflectionAttributeInfo>()
.Select(r => r.Attribute)
.OfType<ICollector>()
.ToList();
_diagnosticMessageSink = diagnosticMessageSink;
DisplayName = suppliedDisplayName ?? BaseDisplayName;
Iterations = iterations;
WarmupIterations = warmupIterations;
TestMethodArguments = testMethodArguments?.ToArray();
}
public int Iterations { get; private set; }
public int WarmupIterations { get; private set; }
public override Task<RunSummary> RunAsync(
IMessageSink diagnosticMessageSink,
IMessageBus messageBus,
object[] constructorArguments,
ExceptionAggregator aggregator,
CancellationTokenSource cancellationTokenSource)
{
var runner = new StressTestRunner(
this,
DisplayName,
SkipReason,
constructorArguments,
TestMethodArguments,
messageBus,
aggregator,
cancellationTokenSource,
_diagnosticMessageSink,
_collectors);
return runner.RunAsync();
}
}
}

Просмотреть файл

@ -1,35 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using Xunit.Abstractions;
using Xunit.Sdk;
namespace Microsoft.AspNet.StressFramework
{
public class StressTestDiscoverer : IXunitTestCaseDiscoverer
{
private readonly IMessageSink _messageSink;
public StressTestDiscoverer(IMessageSink messageSink)
{
_messageSink = messageSink;
}
public virtual IEnumerable<IXunitTestCase> Discover(
ITestFrameworkDiscoveryOptions discoveryOptions,
ITestMethod testMethod,
IAttributeInfo attribute)
{
var tests = new List<IXunitTestCase>();
tests.Add(new StressTestCase(
attribute.GetNamedArgument<int>(nameof(StressTestAttribute.Iterations)),
attribute.GetNamedArgument<int>(nameof(StressTestAttribute.WarmupIterations)),
_messageSink,
testMethod,
null));
return tests;
}
}
}

Просмотреть файл

@ -1,11 +0,0 @@
using System.Reflection;
namespace Microsoft.AspNet.StressFramework
{
public class StressTestDriverContext
{
public MethodInfo TestMethod { get; set; }
public StressRunSetup Setup { get; set; }
}
}

Просмотреть файл

@ -1,10 +0,0 @@
namespace Microsoft.AspNet.StressFramework
{
// TODO: Put helpers for iteration here
public class StressTestHostContext
{
public int WarmupIterations { get; set; }
public int Iterations { get; set; }
}
}

Просмотреть файл

@ -1,59 +0,0 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Reflection;
namespace Microsoft.AspNet.StressFramework
{
internal class StressTestHostProcess : IDisposable
{
public static readonly string ReleaseMessage = "RELEASE_STRESS_TEST_HOST";
public Process Process { get; }
public StressTestHostProcess(Process process)
{
Process = process;
}
public void BeginIterations()
{
Process.StandardInput.WriteLine(ReleaseMessage);
}
internal static StressTestHostProcess Launch(MethodInfo testMethod, Action<string> outputWriter)
{
var assembly = testMethod.DeclaringType.GetTypeInfo().Assembly.GetName().Name;
var type = testMethod.DeclaringType.FullName;
var method = testMethod.Name;
var me = Process.GetCurrentProcess();
var process = new Process();
process.StartInfo.FileName = me.MainModule.FileName;
process.StartInfo.Arguments = $"{typeof(Program).GetTypeInfo().Assembly.GetName().Name} \"{assembly}\" \"{type}\" \"{method}\"";
process.StartInfo.WorkingDirectory = Directory.GetCurrentDirectory();
process.StartInfo.RedirectStandardError = true;
process.StartInfo.RedirectStandardInput = true;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.UseShellExecute = false;
process.StartInfo.CreateNoWindow = true;
process.OutputDataReceived += (sender, args) =>
{
outputWriter(args.Data);
};
process.ErrorDataReceived += (sender, args) =>
{
outputWriter(args.Data);
};
process.Start();
process.BeginOutputReadLine();
process.BeginErrorReadLine();
return new StressTestHostProcess(process);
}
public void Dispose()
{
Process.Dispose();
}
}
}

Просмотреть файл

@ -1,61 +0,0 @@
using System.Collections.Generic;
using System.Diagnostics;
using Microsoft.AspNet.StressFramework.Collectors;
using Xunit.Sdk;
namespace Microsoft.AspNet.StressFramework
{
public class StressTestIterationContext
{
private readonly IList<ICollector> _collectors;
private readonly Stopwatch _stopwatch = new Stopwatch();
private readonly List<Metric> _recordings = new List<Metric>();
private readonly IMessageBus _bus;
private readonly Process _me;
public IReadOnlyList<Metric> Recordings { get; }
public int Iteration { get; }
public StressTestIterationContext(int iteration, IList<ICollector> collectors, IMessageBus bus)
{
Iteration = iteration;
_collectors = collectors;
_bus = bus;
_me = Process.GetCurrentProcess();
// The read-only wrapper IS live updated by changes to the underlying list
// https://msdn.microsoft.com/query/dev14.query?appId=Dev14IDEF1&l=EN-US&k=k(System.Collections.Generic.List`1.AsReadOnly);k(SolutionItemsProject);k(DevLang-csharp)&rd=true
Recordings = _recordings.AsReadOnly();
}
/// <summary>
/// Record a metric
/// </summary>
public void Record<T>(T data)
{
var metric = Metric.Create(Iteration, data);
_recordings.Add(metric);
}
public void BeginIteration()
{
foreach (var collector in _collectors)
{
collector.BeginIteration(this);
}
// Start capturing elapsed time
_stopwatch.Start();
}
public void EndIteration()
{
// Stop capturing elapsed time
_stopwatch.Stop();
// Record the elapsed time and memory usage
_recordings.Add(Metric.Create(Iteration, new ElapsedTime(_stopwatch.Elapsed)));
}
}
}

Просмотреть файл

@ -1,152 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using Xunit.Abstractions;
using Xunit.Sdk;
using System.Collections.Generic;
using Microsoft.AspNet.StressFramework.Collectors;
#if DNXCORE50 || DNX451
using Microsoft.Dnx.Runtime;
using Microsoft.Dnx.Runtime.Infrastructure;
#else
using XunitDiagnosticMessage = Xunit.Sdk.DiagnosticMessage;
#endif
namespace Microsoft.AspNet.StressFramework
{
public class StressTestRunner : TestRunner<StressTestCase>
{
private readonly IList<ICollector> _collectors;
public StressTestRunner(
StressTestCase test,
string displayName,
string skipReason,
object[] constructorArguments,
object[] testMethodArguments,
IMessageBus messageBus,
ExceptionAggregator aggregator,
CancellationTokenSource cancellationTokenSource,
IMessageSink diagnosticMessageSink,
IList<ICollector> collectors)
: base(
new StressTestTest() { DisplayName = displayName, TestCase = test },
messageBus,
((ReflectionTypeInfo)test.TestMethod.TestClass.Class).Type,
constructorArguments,
((ReflectionMethodInfo)test.TestMethod.Method).MethodInfo,
testMethodArguments,
skipReason,
aggregator,
cancellationTokenSource)
{
_collectors = collectors;
}
protected async override Task<Tuple<decimal, string>> InvokeTestAsync(ExceptionAggregator aggregator)
{
var output = string.Empty;
TestOutputHelper testOutputHelper = null;
foreach (object obj in ConstructorArguments)
{
testOutputHelper = obj as TestOutputHelper;
if (testOutputHelper != null)
{
break;
}
}
if (testOutputHelper != null)
{
testOutputHelper.Initialize(MessageBus, Test);
}
var instance = Activator.CreateInstance(TestClass, ConstructorArguments);
foreach (var collector in _collectors)
{
collector.Initialize();
}
try
{
// Launch the host to run the test
var setup = InvokeTestMethodAsync(instance);
var context = new StressTestDriverContext
{
Setup = setup,
TestMethod = TestMethod,
};
setup.Driver.Setup(context);
var stopwatch = Stopwatch.StartNew();
try
{
await aggregator.RunAsync(() => setup.Driver.RunAsync(context));
}
finally
{
var disposable = setup.Host as IDisposable;
disposable?.Dispose();
disposable = setup.Driver as IDisposable;
disposable?.Dispose();
}
stopwatch.Stop();
var executionTime = (decimal)stopwatch.Elapsed.TotalSeconds;
if (testOutputHelper != null)
{
output = testOutputHelper.Output;
testOutputHelper.Uninitialize();
}
return Tuple.Create(executionTime, output);
}
catch (Exception ex)
{
aggregator.Add(ex);
return Tuple.Create(0m, output);
}
finally
{
(instance as IDisposable)?.Dispose();
}
}
private StressRunSetup InvokeTestMethodAsync(object instance)
{
return (StressRunSetup)TestMethod.Invoke(instance, TestMethodArguments);
}
private static string GetFramework()
{
#if DNX451 || DNXCORE50
var services = CallContextServiceLocator.Locator.ServiceProvider;
var env = (IRuntimeEnvironment)services.GetService(typeof(IRuntimeEnvironment));
return "DNX." + env.RuntimeType;
#else
return ".NETFramework";
#endif
}
private static string GetMachineName()
{
return Environment.GetEnvironmentVariable("COMPUTERNAME");
}
private class StressTestTest : ITest
{
public string DisplayName { get; set; }
public ITestCase TestCase { get; set; }
}
}
}

Просмотреть файл

@ -1,30 +0,0 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
namespace Microsoft.AspNet.StressFramework
{
internal static class StressTestTrace
{
private static readonly Process Me = Process.GetCurrentProcess();
private static string _hostOrDriver = "Driver";
public static void WriteLine(string line)
{
WriteRawLine($"[{_hostOrDriver}:{Me.Id}] {line}");
}
internal static void WriteRawLine(string line)
{
Console.WriteLine(line);
}
public static void SetIsHost()
{
_hostOrDriver = "Host";
}
}
}

Просмотреть файл

@ -1,21 +0,0 @@
{
"version": "1.0.0-*",
"dependencies": {
"Microsoft.Framework.Configuration.Json": "1.0.0-*",
"xunit.assert": "2.1.0-*",
"xunit.core": "2.1.0-*",
"xunit.runner.dnx": "2.1.0-*"
},
"frameworks": {
"dnx451": {
"frameworkAssemblies": {
"System.Reflection": "4.0.0.0"
}
},
"dnxcore50": {
"dependencies": {
"System.Runtime": "4.0.21-beta-*"
}
}
}
}

Просмотреть файл

@ -0,0 +1,5 @@
{
"frameworks": {
"dnx451": {}
}
}

Просмотреть файл

@ -1,21 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
<PropertyGroup Label="Globals">
<ProjectGuid>f4279585-9a04-408c-9ad6-ba4b058f739f</ProjectGuid>
<RootNamespace>Microsoft.AspNet.Stress.Mvc.Tests</RootNamespace>
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\artifacts\bin\$(MSBuildProjectName)\</OutputPath>
</PropertyGroup>
<PropertyGroup>
<SchemaVersion>2.0</SchemaVersion>
</PropertyGroup>
<ItemGroup>
<Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" />
</ItemGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
</Project>

Просмотреть файл

@ -1,14 +0,0 @@
{
"version": "1.0.0-*",
"commands": {
"test": "xunit.runner.dnx"
},
"dependencies": {
"Microsoft.AspNet.StressFramework": "",
"Microsoft.AspNet.TestHost": "1.0.0-*"
},
"frameworks": {
"dnx451": { },
"dnxcore50": { }
}
}

Просмотреть файл

@ -1,34 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.IO;
using System.Net;
using System.Net.Http;
using Microsoft.AspNet.StressFramework;
using Xunit;
namespace Microsoft.AspNet.Stress.Tests
{
public class MvcSmokeTest
{
[StressTest]
public StressRunSetup IndexTest()
{
var applicationPath = Path.Combine(Directory.GetCurrentDirectory(), "..", "websites", "HelloWorldMvc");
var client = new HttpClient();
client.BaseAddress = new Uri("http://localhost:5001/");
return StressRunSetup.CreateClientServerTest(applicationPath,
async () =>
{
var result = await client.GetAsync("Home/Index");
// Assert
Assert.Equal(HttpStatusCode.OK, result.StatusCode);
Assert.Equal("Hello World!", await result.Content.ReadAsStringAsync());
});
}
}
}

Просмотреть файл

@ -2,44 +2,34 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using Microsoft.AspNet.StressFramework;
using Microsoft.AspNet.WebUtilities;
using Xunit;
using Microsoft.Xunit.Performance;
namespace Microsoft.AspNet.Stress.Tests
{
public class SmokeTest
{
[StressTest]
public StressRunSetup SmokeyMcSmokeTest()
[Benchmark]
[MeasureInstructionsRetired]
public void SmokeyMcSmokeTest()
{
// Arrange
var formData = "first=second&third=fourth&fifth=sixth";
var formReader = new FormReader(formData);
var pairs = new List<KeyValuePair<string, string>>();
var cancellationToken = new CancellationToken();
var expectedPairs = new Dictionary<string, string>
{
{ "first", "second" },
{ "third", "fourth" },
{ "fifth", "sixth" },
}.ToList();
return StressRunSetup.CreateTest(
async () =>
// Act
Benchmark.IterateAsync(async () =>
{
var pair = await formReader.ReadNextPairAsync(cancellationToken);
while (pair != null)
{
// Act
var pair = await formReader.ReadNextPairAsync(cancellationToken);
while (pair != null)
{
pairs.Add(pair.Value);
pair = await formReader.ReadNextPairAsync(cancellationToken);
}
// Assert
Assert.Equal(expectedPairs, pairs);
});
pairs.Add(pair.Value);
pair = await formReader.ReadNextPairAsync(cancellationToken);
}
});
}
}
}

Просмотреть файл

@ -1,23 +1,21 @@
{
"version": "1.0.0-*",
"commands": {
"test": "xunit.runner.dnx"
},
"dependencies": {
"Microsoft.AspNet.StressFramework": "",
"Microsoft.AspNet.WebUtilities": "1.0.0-*"
},
"frameworks": {
"dnx451": {
"frameworkAssemblies": {
"System.Net.Http": "4.0.0.0"
}
"version": "1.0.0-*",
"commands": {
"test": "xunit.runner.dnx",
"stress": "aspnet.xunit.performance.run"
},
"dnxcore50": {
"dependencies": {
"System.Runtime": "4.0.21-beta-*",
"System.Net.Http": "4.0.1-beta-*"
}
"dependencies": {
"aspnet.xunit.performance.execution": "1.0.0-*",
"aspnet.xunit.performance.run": "1.0.0-*",
"xunit": "2.1.0-*",
"xunit.runner.dnx": "2.1.0-*",
"Microsoft.AspNet.WebUtilities": "1.0.0-*"
},
"frameworks": {
"dnx46": {
"frameworkAssemblies": {
"System.Net.Http": "4.0.0.0"
}
}
}
}
}