зеркало из https://github.com/aspnet/Stress.git
Let tests return both host and driver
This commit is contained in:
Родитель
9801e861fe
Коммит
27fada51fd
|
@ -0,0 +1,26 @@
|
|||
using System;
|
||||
|
||||
namespace Microsoft.AspNet.StressFramework
|
||||
{
|
||||
public class BasicDriver : IStressTestDriver
|
||||
{
|
||||
private readonly Action _execute;
|
||||
private readonly Action _setup;
|
||||
|
||||
public BasicDriver(Action setup, Action execute)
|
||||
{
|
||||
_setup = setup;
|
||||
_execute = execute;
|
||||
}
|
||||
|
||||
public void Setup() => _setup();
|
||||
|
||||
public void Run(int driverIterations)
|
||||
{
|
||||
for (var i = 0; i < driverIterations; i++)
|
||||
{
|
||||
_execute();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.AspNet.StressFramework
|
||||
{
|
||||
internal class BasicHost : IStressTestHost
|
||||
{
|
||||
private Func<Task> _execute;
|
||||
private Action _setup;
|
||||
|
||||
public BasicHost(Action setup, Func<Task> execute)
|
||||
{
|
||||
_setup = setup;
|
||||
_execute = execute;
|
||||
}
|
||||
|
||||
public void Run(StressTestHostContext context)
|
||||
{
|
||||
for (var i = 0; i < context.Iterations; i++)
|
||||
{
|
||||
_execute();
|
||||
}
|
||||
}
|
||||
|
||||
public void Setup(StressTestHostContext context)
|
||||
{
|
||||
_setup();
|
||||
|
||||
for (var i = 0; i < context.WarmupIterations; i++)
|
||||
{
|
||||
_execute();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
namespace Microsoft.AspNet.StressFramework
|
||||
{
|
||||
public interface IStressTestDriver
|
||||
{
|
||||
void Setup();
|
||||
|
||||
void Run(int driverIterations);
|
||||
}
|
||||
}
|
|
@ -1,12 +1,9 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.AspNet.StressFramework
|
||||
namespace Microsoft.AspNet.StressFramework
|
||||
{
|
||||
public interface IStressTestHost
|
||||
{
|
||||
void Setup(StressTestHostContext context);
|
||||
|
||||
void Run(StressTestHostContext context);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Microsoft.Dnx.Runtime;
|
||||
|
||||
namespace Microsoft.AspNet.StressFramework
|
||||
{
|
||||
|
@ -11,7 +10,7 @@ namespace Microsoft.AspNet.StressFramework
|
|||
public int Main(string[] args)
|
||||
{
|
||||
Console.WriteLine($"[Host:{Process.GetCurrentProcess().Id}] Host Launched");
|
||||
if(args.Length != 4)
|
||||
if (args.Length != 4)
|
||||
{
|
||||
Console.Error.WriteLine("Usage: stresshost <LOCK_NAME> <TEST_LIBRARY> <TEST_CLASS> <TEST_METHOD>");
|
||||
return -1;
|
||||
|
@ -24,22 +23,24 @@ namespace Microsoft.AspNet.StressFramework
|
|||
|
||||
// Find the class
|
||||
var asm = Assembly.Load(new AssemblyName(libraryName));
|
||||
if (asm == null) {
|
||||
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) {
|
||||
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(IStressTestHost).IsAssignableFrom(m.ReturnType) &&
|
||||
m.IsPublic &&
|
||||
.SingleOrDefault(m =>
|
||||
m.Name.Equals(methodName) &&
|
||||
typeof(StressRunSetup).IsAssignableFrom(m.ReturnType) &&
|
||||
m.IsPublic &&
|
||||
m.GetParameters().Length == 0);
|
||||
if(method == null)
|
||||
if (method == null)
|
||||
{
|
||||
Console.Error.WriteLine($"Failed to locate method: {methodName} in {className}");
|
||||
return -4;
|
||||
|
@ -47,13 +48,21 @@ namespace Microsoft.AspNet.StressFramework
|
|||
|
||||
// Construct the class and invoke the method
|
||||
var instance = Activator.CreateInstance(typ);
|
||||
var host = (IStressTestHost)method.Invoke(instance, new object[0]);
|
||||
var setup = (StressRunSetup)method.Invoke(instance, new object[0]);
|
||||
|
||||
SyncGate.WaitFor(lockName);
|
||||
var context = new StressTestHostContext
|
||||
{
|
||||
Iterations = setup.HostIterations,
|
||||
WarmupIterations = setup.WarmupIterations
|
||||
};
|
||||
setup.Host.Setup(context);
|
||||
|
||||
var syncGate = new SyncGate(lockName);
|
||||
syncGate.Wait();
|
||||
|
||||
// Run the host
|
||||
Console.WriteLine($"[Host:{Process.GetCurrentProcess().Id}] Host Released");
|
||||
host.Run(new StressTestHostContext());
|
||||
setup.Host.Run(context);
|
||||
|
||||
Console.WriteLine($"[Host:{Process.GetCurrentProcess().Id}] Host Completed");
|
||||
return 0;
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
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 HostIterations { get; set; } = 0;
|
||||
|
||||
public int DriverIterations { get; set; } = 10;
|
||||
|
||||
public static StressRunSetup CreateTest(Action setup, Func<Task> execute)
|
||||
{
|
||||
var host = new BasicHost(setup, execute);
|
||||
var driver = new BasicDriver(
|
||||
setup: () => { },
|
||||
execute: () => { });
|
||||
|
||||
return new StressRunSetup
|
||||
{
|
||||
Host = host,
|
||||
Driver = driver,
|
||||
DriverIterations = 0,
|
||||
HostIterations = 10
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,5 +3,8 @@
|
|||
// TODO: Put helpers for iteration here
|
||||
public class StressTestHostContext
|
||||
{
|
||||
public int WarmupIterations { get; set; }
|
||||
|
||||
public int Iterations { get; set; }
|
||||
}
|
||||
}
|
|
@ -5,21 +5,21 @@ using System.Reflection;
|
|||
|
||||
namespace Microsoft.AspNet.StressFramework
|
||||
{
|
||||
internal class StressTestHostProcess
|
||||
internal class StressTestHostProcess : IDisposable
|
||||
{
|
||||
private SyncGate _syncGate;
|
||||
public SyncGate SyncGate { get; }
|
||||
|
||||
public Process Process { get; }
|
||||
|
||||
public StressTestHostProcess(SyncGate syncGate, Process process)
|
||||
{
|
||||
_syncGate = syncGate;
|
||||
SyncGate = syncGate;
|
||||
Process = process;
|
||||
}
|
||||
|
||||
public void BeginIterations()
|
||||
{
|
||||
_syncGate.Release();
|
||||
SyncGate.Release();
|
||||
}
|
||||
|
||||
internal static StressTestHostProcess Launch(string assembly, string type, string method)
|
||||
|
@ -48,5 +48,10 @@ namespace Microsoft.AspNet.StressFramework
|
|||
process.BeginErrorReadLine();
|
||||
return new StressTestHostProcess(syncGate, process);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Process.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -81,12 +81,20 @@ namespace Microsoft.AspNet.StressFramework
|
|||
Console.WriteLine($"[Driver:{Process.GetCurrentProcess().Id}] Launching Host");
|
||||
|
||||
// Launch the host to run the test
|
||||
var setup = InvokeTestMethodAsync(instance);
|
||||
setup.Driver.Setup();
|
||||
var host = LaunchHost(TestMethod);
|
||||
|
||||
Console.WriteLine($"[Driver:{Process.GetCurrentProcess().Id}] Releasing Host");
|
||||
var stopwatch = Stopwatch.StartNew();
|
||||
host.BeginIterations();
|
||||
host.Process.WaitForExit();
|
||||
host.SyncGate.Release();
|
||||
setup.Driver.Run(setup.DriverIterations);
|
||||
|
||||
if (setup.HostIterations != 0)
|
||||
{
|
||||
host.Process.WaitForExit();
|
||||
}
|
||||
|
||||
stopwatch.Stop();
|
||||
Console.WriteLine($"[Driver:{Process.GetCurrentProcess().Id}] Host Terminated");
|
||||
|
||||
|
@ -119,14 +127,9 @@ namespace Microsoft.AspNet.StressFramework
|
|||
method.Name);
|
||||
}
|
||||
|
||||
private async Task InvokeTestMethodAsync(object instance)
|
||||
private StressRunSetup InvokeTestMethodAsync(object instance)
|
||||
{
|
||||
var result = TestMethod.Invoke(instance, TestMethodArguments);
|
||||
var task = result as Task;
|
||||
if (task != null)
|
||||
{
|
||||
await task;
|
||||
}
|
||||
return (StressRunSetup)TestMethod.Invoke(instance, TestMethodArguments);
|
||||
}
|
||||
|
||||
private static string GetFramework()
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.AspNet.StressFramework
|
||||
{
|
||||
|
@ -23,7 +20,7 @@ namespace Microsoft.AspNet.StressFramework
|
|||
{
|
||||
}
|
||||
|
||||
private SyncGate(string name)
|
||||
public SyncGate(string name)
|
||||
{
|
||||
// Create a named semaphore
|
||||
Name = name;
|
||||
|
@ -43,7 +40,7 @@ namespace Microsoft.AspNet.StressFramework
|
|||
}
|
||||
}
|
||||
|
||||
private void Wait()
|
||||
public void Wait()
|
||||
{
|
||||
_sem.WaitOne();
|
||||
}
|
||||
|
|
|
@ -1,13 +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.
|
||||
|
||||
namespace Microsoft.AspNet.Stress.Mvc.Tests
|
||||
{
|
||||
public class HelloWorldFixture : MvcFixture
|
||||
{
|
||||
public HelloWorldFixture()
|
||||
: base(new HelloWorldMvc.Startup())
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,31 +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.Net;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Stress.Mvc.Tests;
|
||||
using Microsoft.AspNet.StressFramework;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Stress.Tests
|
||||
{
|
||||
public class HelloWorldTest : IClassFixture<HelloWorldFixture>
|
||||
{
|
||||
public HelloWorldTest(HelloWorldFixture fixture)
|
||||
{
|
||||
Fixture = fixture;
|
||||
}
|
||||
|
||||
public MvcFixture Fixture { get; }
|
||||
|
||||
[StressTest]
|
||||
public async Task Index()
|
||||
{
|
||||
// Act
|
||||
var result = await Fixture.Client.GetAsync("");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.OK, result.StatusCode);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,119 +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.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Versioning;
|
||||
using Microsoft.AspNet.Builder;
|
||||
using Microsoft.AspNet.Hosting;
|
||||
using Microsoft.AspNet.Mvc.Actions;
|
||||
using Microsoft.AspNet.TestHost;
|
||||
using Microsoft.Dnx.Runtime;
|
||||
using Microsoft.Dnx.Runtime.Infrastructure;
|
||||
using Microsoft.Framework.DependencyInjection;
|
||||
|
||||
namespace Microsoft.AspNet.Stress.Mvc.Tests
|
||||
{
|
||||
public class MvcFixture : IDisposable
|
||||
{
|
||||
public MvcFixture(object startupInstance)
|
||||
{
|
||||
var startupTypeInfo = startupInstance.GetType().GetTypeInfo();
|
||||
var configureMethod = (Action<IApplicationBuilder>)startupTypeInfo
|
||||
.DeclaredMethods
|
||||
.First(m => m.Name == "Configure")
|
||||
.CreateDelegate(typeof(Action<IApplicationBuilder>), startupInstance);
|
||||
|
||||
var configureServices = (Action<IServiceCollection>)startupTypeInfo
|
||||
.DeclaredMethods
|
||||
.First(m => m.Name == "ConfigureServices")
|
||||
.CreateDelegate(typeof(Action<IServiceCollection>), startupInstance);
|
||||
|
||||
Server = TestServer.Create(
|
||||
CallContextServiceLocator.Locator.ServiceProvider,
|
||||
configureMethod,
|
||||
configureServices: InitializeServices(startupTypeInfo.Assembly, configureServices));
|
||||
|
||||
Client = Server.CreateClient();
|
||||
Client.BaseAddress = new Uri("http://localhost");
|
||||
}
|
||||
|
||||
public TestServer Server { get; }
|
||||
|
||||
public HttpClient Client { get; }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Client.Dispose();
|
||||
Server.Dispose();
|
||||
}
|
||||
|
||||
public static Func<IServiceCollection, IServiceProvider> InitializeServices(
|
||||
Assembly startupAssembly,
|
||||
Action<IServiceCollection> next)
|
||||
{
|
||||
var applicationServices = CallContextServiceLocator.Locator.ServiceProvider;
|
||||
var libraryManager = applicationServices.GetRequiredService<ILibraryManager>();
|
||||
|
||||
var applicationName = startupAssembly.GetName().Name;
|
||||
var library = libraryManager.GetLibrary(applicationName);
|
||||
var applicationRoot = Path.GetDirectoryName(library.Path);
|
||||
|
||||
var applicationEnvironment = applicationServices.GetRequiredService<IApplicationEnvironment>();
|
||||
|
||||
return (services) =>
|
||||
{
|
||||
services.AddInstance<IApplicationEnvironment>(
|
||||
new TestApplicationEnvironment(applicationEnvironment, applicationName, applicationRoot));
|
||||
|
||||
var hostingEnvironment = new HostingEnvironment();
|
||||
hostingEnvironment.Initialize(applicationRoot, "Production");
|
||||
services.AddInstance<IHostingEnvironment>(hostingEnvironment);
|
||||
|
||||
var assemblyProvider = new StaticAssemblyProvider();
|
||||
assemblyProvider.CandidateAssemblies.Add(startupAssembly);
|
||||
services.AddInstance(assemblyProvider);
|
||||
|
||||
next(services);
|
||||
|
||||
return services.BuildServiceProvider();
|
||||
};
|
||||
}
|
||||
|
||||
private class TestApplicationEnvironment : IApplicationEnvironment
|
||||
{
|
||||
private readonly IApplicationEnvironment _original;
|
||||
|
||||
public TestApplicationEnvironment(IApplicationEnvironment original, string name, string path)
|
||||
{
|
||||
_original = original;
|
||||
|
||||
ApplicationName = name;
|
||||
ApplicationBasePath = path;
|
||||
}
|
||||
|
||||
public string ApplicationBasePath { get; }
|
||||
|
||||
public string ApplicationName { get; }
|
||||
|
||||
public string ApplicationVersion => _original.ApplicationVersion;
|
||||
|
||||
public string Configuration => _original.Configuration;
|
||||
|
||||
public FrameworkName RuntimeFramework => _original.RuntimeFramework;
|
||||
|
||||
public object GetData(string name)
|
||||
{
|
||||
return _original.GetData(name);
|
||||
}
|
||||
|
||||
public void SetData(string name, object value)
|
||||
{
|
||||
_original.SetData(name, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.StressFramework;
|
||||
|
||||
namespace Microsoft.AspNet.Stress.Tests
|
||||
{
|
||||
public class HostingModelTest : IStressTestHost
|
||||
{
|
||||
public void Run(StressTestHostContext context)
|
||||
{
|
||||
Console.WriteLine("Ran in the host!");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,16 +1,49 @@
|
|||
// 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 System.Linq;
|
||||
using System.Threading;
|
||||
using Microsoft.AspNet.StressFramework;
|
||||
using Microsoft.AspNet.WebUtilities;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Stress.Tests
|
||||
{
|
||||
public class SmokeTest
|
||||
{
|
||||
[StressTest]
|
||||
public IStressTestHost SmokeyMcSmokeTest()
|
||||
public StressRunSetup SmokeyMcSmokeTest()
|
||||
{
|
||||
return new HostingModelTest();
|
||||
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(
|
||||
() =>
|
||||
{
|
||||
// Setup
|
||||
},
|
||||
async () =>
|
||||
{
|
||||
// Act
|
||||
var pair = await formReader.ReadNextPairAsync(cancellationToken);
|
||||
while (pair != null)
|
||||
{
|
||||
pairs.Add(pair.Value);
|
||||
pair = await formReader.ReadNextPairAsync(cancellationToken);
|
||||
}
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expectedPairs, pairs);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче