зеркало из 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"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<configuration>
|
<configuration>
|
||||||
<packageSources>
|
<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="NuGet" value="https://api.nuget.org/v3/index.json" />
|
||||||
|
<add key="StressTools" value="https://www.myget.org/F/aspnetstress/api/v3/index.json" />
|
||||||
</packageSources>
|
</packageSources>
|
||||||
</configuration>
|
</configuration>
|
||||||
|
|
|
@ -15,8 +15,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{BB74
|
||||||
EndProject
|
EndProject
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{C1B84D1C-2AF9-419D-BD57-16B87F377256}"
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{C1B84D1C-2AF9-419D-BD57-16B87F377256}"
|
||||||
EndProject
|
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}"
|
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
|
EndProject
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "websites", "websites", "{6BF7AF55-1A79-4C18-9DA7-68F52D319A3A}"
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "websites", "websites", "{6BF7AF55-1A79-4C18-9DA7-68F52D319A3A}"
|
||||||
|
@ -29,10 +27,6 @@ Global
|
||||||
Release|Any CPU = Release|Any CPU
|
Release|Any CPU = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
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.ActiveCfg = Debug|Any CPU
|
||||||
{489E5EDA-D686-4B57-9C5D-70B7879EF7E8}.Debug|Any CPU.Build.0 = 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
|
{489E5EDA-D686-4B57-9C5D-70B7879EF7E8}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
@ -46,7 +40,6 @@ Global
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(NestedProjects) = preSolution
|
GlobalSection(NestedProjects) = preSolution
|
||||||
{1C90BF69-88B0-4079-9F90-48FE5ABE3B25} = {C1B84D1C-2AF9-419D-BD57-16B87F377256}
|
|
||||||
{489E5EDA-D686-4B57-9C5D-70B7879EF7E8} = {7B63597D-863D-46C4-9F9E-D60E74435E81}
|
{489E5EDA-D686-4B57-9C5D-70B7879EF7E8} = {7B63597D-863D-46C4-9F9E-D60E74435E81}
|
||||||
{6BF7AF55-1A79-4C18-9DA7-68F52D319A3A} = {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}
|
{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,43 +2,33 @@
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using Microsoft.AspNet.StressFramework;
|
|
||||||
using Microsoft.AspNet.WebUtilities;
|
using Microsoft.AspNet.WebUtilities;
|
||||||
using Xunit;
|
using Microsoft.Xunit.Performance;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Stress.Tests
|
namespace Microsoft.AspNet.Stress.Tests
|
||||||
{
|
{
|
||||||
public class SmokeTest
|
public class SmokeTest
|
||||||
{
|
{
|
||||||
[StressTest]
|
[Benchmark]
|
||||||
public StressRunSetup SmokeyMcSmokeTest()
|
[MeasureInstructionsRetired]
|
||||||
|
public void SmokeyMcSmokeTest()
|
||||||
{
|
{
|
||||||
|
// Arrange
|
||||||
var formData = "first=second&third=fourth&fifth=sixth";
|
var formData = "first=second&third=fourth&fifth=sixth";
|
||||||
var formReader = new FormReader(formData);
|
var formReader = new FormReader(formData);
|
||||||
var pairs = new List<KeyValuePair<string, string>>();
|
var pairs = new List<KeyValuePair<string, string>>();
|
||||||
var cancellationToken = new CancellationToken();
|
var cancellationToken = new CancellationToken();
|
||||||
var expectedPairs = new Dictionary<string, string>
|
|
||||||
{
|
|
||||||
{ "first", "second" },
|
|
||||||
{ "third", "fourth" },
|
|
||||||
{ "fifth", "sixth" },
|
|
||||||
}.ToList();
|
|
||||||
|
|
||||||
return StressRunSetup.CreateTest(
|
|
||||||
async () =>
|
|
||||||
{
|
|
||||||
// Act
|
// Act
|
||||||
|
Benchmark.IterateAsync(async () =>
|
||||||
|
{
|
||||||
var pair = await formReader.ReadNextPairAsync(cancellationToken);
|
var pair = await formReader.ReadNextPairAsync(cancellationToken);
|
||||||
while (pair != null)
|
while (pair != null)
|
||||||
{
|
{
|
||||||
pairs.Add(pair.Value);
|
pairs.Add(pair.Value);
|
||||||
pair = await formReader.ReadNextPairAsync(cancellationToken);
|
pair = await formReader.ReadNextPairAsync(cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assert
|
|
||||||
Assert.Equal(expectedPairs, pairs);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,23 +1,21 @@
|
||||||
{
|
{
|
||||||
"version": "1.0.0-*",
|
"version": "1.0.0-*",
|
||||||
"commands": {
|
"commands": {
|
||||||
"test": "xunit.runner.dnx"
|
"test": "xunit.runner.dnx",
|
||||||
|
"stress": "aspnet.xunit.performance.run"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Microsoft.AspNet.StressFramework": "",
|
"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-*"
|
"Microsoft.AspNet.WebUtilities": "1.0.0-*"
|
||||||
},
|
},
|
||||||
"frameworks": {
|
"frameworks": {
|
||||||
"dnx451": {
|
"dnx46": {
|
||||||
"frameworkAssemblies": {
|
"frameworkAssemblies": {
|
||||||
"System.Net.Http": "4.0.0.0"
|
"System.Net.Http": "4.0.0.0"
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"dnxcore50": {
|
|
||||||
"dependencies": {
|
|
||||||
"System.Runtime": "4.0.21-beta-*",
|
|
||||||
"System.Net.Http": "4.0.1-beta-*"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче