Let tests return both host and driver

This commit is contained in:
Pranav K 2015-09-09 16:15:11 -07:00
Родитель 9801e861fe
Коммит 27fada51fd
15 изменённых файлов: 189 добавлений и 217 удалений

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

@ -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);
});
}
}
}