зеркало из https://github.com/aspnet/Stress.git
Switch tests to use aspnet.xunit.performance
This commit is contained in:
Родитель
cd30ee9821
Коммит
131ea13e15
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче