Created an in memory host for testing purposes and added the appropriate
APIs to allow sending requests through the pipeline easily.
This commit is contained in:
parent
b366cb1cd0
commit
8ca4a331e2
24
Hosting.sln
24
Hosting.sln
|
|
@ -1,7 +1,7 @@
|
||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
# Visual Studio 2013
|
# Visual Studio 2013
|
||||||
VisualStudioVersion = 12.0.21005.1
|
VisualStudioVersion = 12.0.30319.0
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{E0497F39-AFFB-4819-A116-E39E361915AB}"
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{E0497F39-AFFB-4819-A116-E39E361915AB}"
|
||||||
EndProject
|
EndProject
|
||||||
|
|
@ -27,6 +27,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KWebStartup.k10", "samples\
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KWebStartup.net45", "samples\KWebStartup\KWebStartup.net45.csproj", "{B5939234-73ED-4DAD-A2C6-D61AA6DFB406}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KWebStartup.net45", "samples\KWebStartup\KWebStartup.net45.csproj", "{B5939234-73ED-4DAD-A2C6-D61AA6DFB406}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNet.TestHost.Tests.net45", "test\Microsoft.AspNet.TestHost.Tests\Microsoft.AspNet.TestHost.Tests.net45.csproj", "{A19DBFCE-7B43-4BC6-9C3B-A47EBB65E145}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNet.TestHost.net45", "src\Microsoft.AspNet.TestHost\Microsoft.AspNet.TestHost.net45.csproj", "{25E1550A-A73F-4E06-9F13-9F72695ADFC8}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
|
@ -61,19 +65,29 @@ Global
|
||||||
{B5939234-73ED-4DAD-A2C6-D61AA6DFB406}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{B5939234-73ED-4DAD-A2C6-D61AA6DFB406}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{B5939234-73ED-4DAD-A2C6-D61AA6DFB406}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{B5939234-73ED-4DAD-A2C6-D61AA6DFB406}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{B5939234-73ED-4DAD-A2C6-D61AA6DFB406}.Release|Any CPU.Build.0 = Release|Any CPU
|
{B5939234-73ED-4DAD-A2C6-D61AA6DFB406}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{A19DBFCE-7B43-4BC6-9C3B-A47EBB65E145}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{A19DBFCE-7B43-4BC6-9C3B-A47EBB65E145}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{A19DBFCE-7B43-4BC6-9C3B-A47EBB65E145}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{A19DBFCE-7B43-4BC6-9C3B-A47EBB65E145}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{25E1550A-A73F-4E06-9F13-9F72695ADFC8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{25E1550A-A73F-4E06-9F13-9F72695ADFC8}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{25E1550A-A73F-4E06-9F13-9F72695ADFC8}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{25E1550A-A73F-4E06-9F13-9F72695ADFC8}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(NestedProjects) = preSolution
|
GlobalSection(NestedProjects) = preSolution
|
||||||
{93FB86DB-7D2A-46CE-AFD2-0B53E6A8CF69} = {E0497F39-AFFB-4819-A116-E39E361915AB}
|
{D546290B-E280-4D99-BA9C-0D364A0AFB54} = {93FB86DB-7D2A-46CE-AFD2-0B53E6A8CF69}
|
||||||
{EB784E77-FD42-46EC-9C8C-502B78962407} = {E0497F39-AFFB-4819-A116-E39E361915AB}
|
{DBB72F0F-755D-41CF-8FE2-F4B6AE214E91} = {EB784E77-FD42-46EC-9C8C-502B78962407}
|
||||||
{80588AF3-6B14-4D11-9DC4-1EF6453B54C9} = {FEB39027-9158-4DE2-997F-7ADAEF8188D0}
|
{80588AF3-6B14-4D11-9DC4-1EF6453B54C9} = {FEB39027-9158-4DE2-997F-7ADAEF8188D0}
|
||||||
{F4C7B46C-B39F-4172-9C3A-05352183D469} = {93FB86DB-7D2A-46CE-AFD2-0B53E6A8CF69}
|
{F4C7B46C-B39F-4172-9C3A-05352183D469} = {93FB86DB-7D2A-46CE-AFD2-0B53E6A8CF69}
|
||||||
{D546290B-E280-4D99-BA9C-0D364A0AFB54} = {93FB86DB-7D2A-46CE-AFD2-0B53E6A8CF69}
|
|
||||||
{FD9833B9-3FB1-4612-BBB4-64F539DB0F8B} = {EB784E77-FD42-46EC-9C8C-502B78962407}
|
{FD9833B9-3FB1-4612-BBB4-64F539DB0F8B} = {EB784E77-FD42-46EC-9C8C-502B78962407}
|
||||||
{DBB72F0F-755D-41CF-8FE2-F4B6AE214E91} = {EB784E77-FD42-46EC-9C8C-502B78962407}
|
{93FB86DB-7D2A-46CE-AFD2-0B53E6A8CF69} = {E0497F39-AFFB-4819-A116-E39E361915AB}
|
||||||
|
{EB784E77-FD42-46EC-9C8C-502B78962407} = {E0497F39-AFFB-4819-A116-E39E361915AB}
|
||||||
{C0235BA1-9198-42C0-92D8-7578E9B9D96B} = {C30C98CD-3D69-4AE9-B680-0E0E6D8834C6}
|
{C0235BA1-9198-42C0-92D8-7578E9B9D96B} = {C30C98CD-3D69-4AE9-B680-0E0E6D8834C6}
|
||||||
{B5939234-73ED-4DAD-A2C6-D61AA6DFB406} = {C30C98CD-3D69-4AE9-B680-0E0E6D8834C6}
|
{B5939234-73ED-4DAD-A2C6-D61AA6DFB406} = {C30C98CD-3D69-4AE9-B680-0E0E6D8834C6}
|
||||||
|
{A19DBFCE-7B43-4BC6-9C3B-A47EBB65E145} = {FEB39027-9158-4DE2-997F-7ADAEF8188D0}
|
||||||
|
{25E1550A-A73F-4E06-9F13-9F72695ADFC8} = {93FB86DB-7D2A-46CE-AFD2-0B53E6A8CF69}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
EndGlobal
|
EndGlobal
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using Microsoft.AspNet.HttpFeature;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.TestHost
|
||||||
|
{
|
||||||
|
internal class RequestInformation : IHttpRequestInformation
|
||||||
|
{
|
||||||
|
public RequestInformation()
|
||||||
|
{
|
||||||
|
Headers = new Dictionary<string, string[]>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
PathBase = "";
|
||||||
|
Body = Stream.Null;
|
||||||
|
Protocol = "HTTP/1.1";
|
||||||
|
}
|
||||||
|
|
||||||
|
public Stream Body { get; set; }
|
||||||
|
|
||||||
|
public IDictionary<string, string[]> Headers { get; set; }
|
||||||
|
|
||||||
|
public string Method { get; set; }
|
||||||
|
|
||||||
|
public string Path { get; set; }
|
||||||
|
|
||||||
|
public string PathBase { get; set; }
|
||||||
|
|
||||||
|
public string Protocol { get; set; }
|
||||||
|
|
||||||
|
public string QueryString { get; set; }
|
||||||
|
|
||||||
|
public string Scheme { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using Microsoft.AspNet.HttpFeature;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.TestHost
|
||||||
|
{
|
||||||
|
internal class ResponseInformation : IHttpResponseInformation
|
||||||
|
{
|
||||||
|
public ResponseInformation()
|
||||||
|
{
|
||||||
|
Headers = new Dictionary<string, string[]>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
Body = new MemoryStream();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int StatusCode { get; set; }
|
||||||
|
|
||||||
|
public string ReasonPhrase { get; set; }
|
||||||
|
|
||||||
|
public IDictionary<string, string[]> Headers { get; set; }
|
||||||
|
|
||||||
|
public Stream Body { get; set; }
|
||||||
|
|
||||||
|
public void OnSendingHeaders(Action<object> callback, object state)
|
||||||
|
{
|
||||||
|
// TODO: Figure out how to implement this thing.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,206 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNet.Abstractions;
|
||||||
|
using Microsoft.AspNet.FeatureModel;
|
||||||
|
using Microsoft.AspNet.HttpFeature;
|
||||||
|
using Microsoft.AspNet.PipelineCore;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.TestHost
|
||||||
|
{
|
||||||
|
public class TestClient
|
||||||
|
{
|
||||||
|
private readonly Func<object, Task> _pipeline;
|
||||||
|
|
||||||
|
public TestClient(Func<object, Task> pipeline)
|
||||||
|
{
|
||||||
|
_pipeline = pipeline;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<HttpResponse> SendAsync(string method,
|
||||||
|
string url,
|
||||||
|
IDictionary<string, string[]> headers = null,
|
||||||
|
Stream body = null,
|
||||||
|
Action<HttpRequest> onSendingRequest = null)
|
||||||
|
{
|
||||||
|
return await SendAsync(method, new Uri(url), headers, body, onSendingRequest);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<HttpResponse> SendAsync(string method,
|
||||||
|
Uri uri,
|
||||||
|
IDictionary<string, string[]> headers = null,
|
||||||
|
Stream body = null,
|
||||||
|
Action<HttpRequest> onSendingRequest = null)
|
||||||
|
{
|
||||||
|
var request = CreateRequest(method, uri, headers, body);
|
||||||
|
var response = new ResponseInformation();
|
||||||
|
|
||||||
|
var features = new FeatureCollection();
|
||||||
|
features.Add(typeof(IHttpRequestInformation), request);
|
||||||
|
features.Add(typeof(IHttpResponseInformation), response);
|
||||||
|
var httpContext = new DefaultHttpContext(features);
|
||||||
|
|
||||||
|
if (onSendingRequest != null)
|
||||||
|
{
|
||||||
|
onSendingRequest(httpContext.Request);
|
||||||
|
}
|
||||||
|
await _pipeline(features);
|
||||||
|
|
||||||
|
response.Body.Seek(0, SeekOrigin.Begin);
|
||||||
|
return httpContext.Response;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IHttpRequestInformation CreateRequest(
|
||||||
|
string method,
|
||||||
|
Uri uri,
|
||||||
|
IDictionary<string, string[]> headers,
|
||||||
|
Stream body)
|
||||||
|
{
|
||||||
|
var request = new RequestInformation();
|
||||||
|
request.Method = method;
|
||||||
|
request.Scheme = uri.Scheme;
|
||||||
|
request.Path = PathString.FromUriComponent(uri).Value;
|
||||||
|
request.QueryString = QueryString.FromUriComponent(uri).Value;
|
||||||
|
request.Headers = headers ?? request.Headers;
|
||||||
|
if (!request.Headers.ContainsKey("Host"))
|
||||||
|
{
|
||||||
|
var host = new string[1];
|
||||||
|
if (uri.IsDefaultPort)
|
||||||
|
{
|
||||||
|
host[0] = uri.Host;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
host[0] = uri.GetComponents(UriComponents.HostAndPort, UriFormat.UriEscaped);
|
||||||
|
}
|
||||||
|
request.Headers["Host"] = host;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (body != null)
|
||||||
|
{
|
||||||
|
EnsureContentLength(request.Headers, body);
|
||||||
|
request.Body = body;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
request.Body = Stream.Null;
|
||||||
|
}
|
||||||
|
return request;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<HttpResponse> GetAsync(string url)
|
||||||
|
{
|
||||||
|
var uri = new Uri(url);
|
||||||
|
return await GetAsync(uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<HttpResponse> GetAsync(Uri uri)
|
||||||
|
{
|
||||||
|
return await SendAsync("GET", uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<string> GetStringAsync(string url)
|
||||||
|
{
|
||||||
|
var uri = new Uri(url);
|
||||||
|
return await GetStringAsync(uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<string> GetStringAsync(Uri uri)
|
||||||
|
{
|
||||||
|
var response = await GetAsync(uri);
|
||||||
|
return await new StreamReader(response.Body).ReadToEndAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Stream> GetStreamAsync(string url)
|
||||||
|
{
|
||||||
|
var uri = new Uri(url);
|
||||||
|
return await GetStreamAsync(uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Stream> GetStreamAsync(Uri uri)
|
||||||
|
{
|
||||||
|
var response = await GetAsync(uri);
|
||||||
|
return response.Body;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<HttpResponse> PostAsync(
|
||||||
|
string url,
|
||||||
|
string content,
|
||||||
|
string contentType,
|
||||||
|
Action<HttpRequest> onSendingRequest = null)
|
||||||
|
{
|
||||||
|
return await PostAsync(new Uri(url), content, contentType, onSendingRequest);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<HttpResponse> PostAsync(
|
||||||
|
Uri url,
|
||||||
|
string content,
|
||||||
|
string contentType,
|
||||||
|
Action<HttpRequest> onSendingRequest = null)
|
||||||
|
{
|
||||||
|
var bytes = GetBytes(content);
|
||||||
|
var headers = CreateContentHeaders(contentType, bytes.Length);
|
||||||
|
var body = new MemoryStream(bytes);
|
||||||
|
|
||||||
|
return await SendAsync("POST", url, headers, body, onSendingRequest);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<HttpResponse> PutAsync(
|
||||||
|
string url,
|
||||||
|
string content,
|
||||||
|
string contentType,
|
||||||
|
Action<HttpRequest> onSendingRequest = null)
|
||||||
|
{
|
||||||
|
return await PutAsync(new Uri(url), content, contentType, onSendingRequest);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<HttpResponse> PutAsync(
|
||||||
|
Uri url,
|
||||||
|
string content,
|
||||||
|
string contentType,
|
||||||
|
Action<HttpRequest> onSendingRequest = null)
|
||||||
|
{
|
||||||
|
var bytes = GetBytes(content);
|
||||||
|
var headers = CreateContentHeaders(contentType, bytes.Length);
|
||||||
|
var body = new MemoryStream(bytes);
|
||||||
|
|
||||||
|
return await SendAsync("PUT", url, headers, body, onSendingRequest);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<HttpResponse> DeleteAsync(string url)
|
||||||
|
{
|
||||||
|
return await DeleteAsync(new Uri(url));
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<HttpResponse> DeleteAsync(Uri uri)
|
||||||
|
{
|
||||||
|
return await SendAsync("DELETE", uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void EnsureContentLength(IDictionary<string, string[]> dictionary, Stream body)
|
||||||
|
{
|
||||||
|
if (!dictionary.ContainsKey("Content-Length"))
|
||||||
|
{
|
||||||
|
dictionary["Content-Length"] = new[] { body.Length.ToString(CultureInfo.InvariantCulture) };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte[] GetBytes(string content)
|
||||||
|
{
|
||||||
|
var bytes = Encoding.UTF8.GetBytes(content);
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Dictionary<string, string[]> CreateContentHeaders(string contentType, int contentLength)
|
||||||
|
{
|
||||||
|
return new Dictionary<string, string[]>(StringComparer.OrdinalIgnoreCase)
|
||||||
|
{
|
||||||
|
{ "Content-Type", new [] { contentType } },
|
||||||
|
{ "Content-Length", new [] { contentLength.ToString(CultureInfo.InvariantCulture) } }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,109 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Runtime.Versioning;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNet.Abstractions;
|
||||||
|
using Microsoft.AspNet.ConfigurationModel;
|
||||||
|
using Microsoft.AspNet.DependencyInjection;
|
||||||
|
using Microsoft.AspNet.DependencyInjection.Fallback;
|
||||||
|
using Microsoft.AspNet.Hosting;
|
||||||
|
using Microsoft.AspNet.Hosting.Server;
|
||||||
|
using Microsoft.AspNet.Hosting.Startup;
|
||||||
|
using Microsoft.Net.Runtime;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.TestHost
|
||||||
|
{
|
||||||
|
public class TestServer : IServerFactory, IDisposable
|
||||||
|
{
|
||||||
|
private static readonly string ServerName = typeof(TestServer).FullName;
|
||||||
|
private static readonly ServerInformation ServerInfo = new ServerInformation();
|
||||||
|
private Func<object, Task> _appDelegate;
|
||||||
|
private TestClient _handler;
|
||||||
|
|
||||||
|
public TestServer(IConfiguration config, IServiceProvider serviceProvider, Action<IBuilder> appStartup)
|
||||||
|
{
|
||||||
|
var env = serviceProvider.GetService<IApplicationEnvironment>();
|
||||||
|
if (env == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentException("IApplicationEnvironment couldn't be resolved.", "serviceProvider");
|
||||||
|
}
|
||||||
|
|
||||||
|
HostingContext hostContext = new HostingContext()
|
||||||
|
{
|
||||||
|
ApplicationName = env.ApplicationName,
|
||||||
|
Configuration = config,
|
||||||
|
ServerFactory = this,
|
||||||
|
Services = serviceProvider,
|
||||||
|
ApplicationStartup = appStartup
|
||||||
|
};
|
||||||
|
|
||||||
|
var engine = serviceProvider.GetService<IHostingEngine>();
|
||||||
|
var disposable = engine.Start(hostContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TestServer Create<TStartup>(IServiceProvider provider)
|
||||||
|
{
|
||||||
|
var startupLoader = new StartupLoader(provider, new NullStartupLoader());
|
||||||
|
var name = typeof(TStartup).AssemblyQualifiedName;
|
||||||
|
var diagnosticMessages = new List<string>();
|
||||||
|
return Create(provider, startupLoader.LoadStartup(name, diagnosticMessages));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TestServer Create(IServiceProvider provider, Action<IBuilder> app)
|
||||||
|
{
|
||||||
|
var collection = new ServiceCollection();
|
||||||
|
var hostingServices = HostingServices.GetDefaultServices();
|
||||||
|
|
||||||
|
var config = new Configuration();
|
||||||
|
collection.Add(hostingServices);
|
||||||
|
|
||||||
|
var serviceProvider = collection.BuildServiceProvider(provider);
|
||||||
|
return new TestServer(config, serviceProvider, app);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TestClient Handler
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_handler == null)
|
||||||
|
{
|
||||||
|
_handler = new TestClient(_appDelegate);
|
||||||
|
}
|
||||||
|
|
||||||
|
return _handler;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public IServerInformation Initialize(IConfiguration configuration)
|
||||||
|
{
|
||||||
|
return ServerInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IDisposable Start(IServerInformation serverInformation, Func<object, Task> application)
|
||||||
|
{
|
||||||
|
if (!(serverInformation.GetType() == typeof(ServerInformation)))
|
||||||
|
{
|
||||||
|
throw new ArgumentException(string.Format("The server must be {0}", ServerName), "serverInformation");
|
||||||
|
}
|
||||||
|
|
||||||
|
_appDelegate = application;
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
// IServerFactory.Start needs to return an IDisposable. Typically this IDisposable instance is used to
|
||||||
|
// clear any server resources when tearing down the host. In our case we don't have anything to clear
|
||||||
|
// so we just implement IDisposable and do nothing.
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ServerInformation : IServerInformation
|
||||||
|
{
|
||||||
|
public string Name
|
||||||
|
{
|
||||||
|
get { return TestServer.ServerName; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
{
|
||||||
|
"version" : "0.1-alpha-*",
|
||||||
|
"dependencies": {
|
||||||
|
"System.Reflection": "4.0.10.0",
|
||||||
|
"System.Runtime" : "4.0.20.0",
|
||||||
|
"Microsoft.AspNet.Abstractions": "0.1-alpha-*",
|
||||||
|
"Microsoft.AspNet.ConfigurationModel": "0.1-alpha-*",
|
||||||
|
"Microsoft.AspNet.DependencyInjection": "0.1-alpha-*",
|
||||||
|
"Microsoft.AspNet.FeatureModel": "0.1-alpha-*",
|
||||||
|
"Microsoft.AspNet.Hosting": "0.1-alpha-*",
|
||||||
|
"Microsoft.AspNet.HttpFeature": "0.1-alpha-*",
|
||||||
|
"Microsoft.AspNet.PipelineCore": "0.1-alpha-*",
|
||||||
|
"Microsoft.AspNet.Security.DataProtection": "0.1-alpha-*"
|
||||||
|
},
|
||||||
|
"configurations": {
|
||||||
|
"net45": {
|
||||||
|
"dependencies": {
|
||||||
|
"System.Collections": "4.0.0.0",
|
||||||
|
"System.ComponentModel": "4.0.0.0",
|
||||||
|
"System.Globalization": "4.0.10.0",
|
||||||
|
"System.Linq": "4.0.0.0",
|
||||||
|
"System.Reflection": "4.0.10.0",
|
||||||
|
"System.Runtime": "4.0.20.0",
|
||||||
|
"System.Runtime.Extensions": "4.0.10.0",
|
||||||
|
"System.Runtime.Serialization.Primitives": "4.0.0.0",
|
||||||
|
"System.Threading": "4.0.0.0",
|
||||||
|
"System.Threading.Tasks": "4.0.0.0",
|
||||||
|
"System.Threading.Thread": "4.0.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
using System;
|
||||||
|
using System.Runtime.Versioning;
|
||||||
|
using Microsoft.Net.Runtime;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.TestHost.Tests
|
||||||
|
{
|
||||||
|
public class TestApplicationEnvironment : IApplicationEnvironment
|
||||||
|
{
|
||||||
|
public string ApplicationName
|
||||||
|
{
|
||||||
|
get { return "Test App environment"; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Version
|
||||||
|
{
|
||||||
|
get { return "1.0.0"; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public string ApplicationBasePath
|
||||||
|
{
|
||||||
|
get { return Environment.CurrentDirectory; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public FrameworkName TargetFramework
|
||||||
|
{
|
||||||
|
get { return new FrameworkName(".NETFramework", new Version(4, 5)); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,153 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Runtime.Versioning;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNet.Abstractions;
|
||||||
|
using Microsoft.AspNet.DependencyInjection;
|
||||||
|
using Microsoft.AspNet.DependencyInjection.Fallback;
|
||||||
|
using Microsoft.Net.Runtime;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.TestHost.Tests
|
||||||
|
{
|
||||||
|
public class TestClientTests
|
||||||
|
{
|
||||||
|
private readonly IServiceProvider _services;
|
||||||
|
private readonly TestServer _server;
|
||||||
|
|
||||||
|
public TestClientTests()
|
||||||
|
{
|
||||||
|
_services = new ServiceCollection()
|
||||||
|
.AddSingleton<IApplicationEnvironment, TestApplicationEnvironment>()
|
||||||
|
.BuildServiceProvider();
|
||||||
|
|
||||||
|
_server = TestServer.Create(_services, app => app.Run(async ctx => { }));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task SendAsync_ConfiguresRequestProperly()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var client = _server.Handler;
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var response = await client.SendAsync("GET", "http://localhost:12345/Home/Index?id=3&name=peter#fragment");
|
||||||
|
var request = response.HttpContext.Request;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.NotNull(request);
|
||||||
|
Assert.Equal("HTTP/1.1", request.Protocol);
|
||||||
|
Assert.Equal("GET", request.Method);
|
||||||
|
Assert.Equal("http", request.Scheme);
|
||||||
|
Assert.Equal("localhost:12345", request.Host.Value);
|
||||||
|
Assert.Equal("", request.PathBase.Value);
|
||||||
|
Assert.True(request.Path.HasValue);
|
||||||
|
Assert.Equal("/Home/Index", request.Path.Value);
|
||||||
|
Assert.Equal("?id=3&name=peter", request.QueryString.Value);
|
||||||
|
Assert.Null(request.ContentLength);
|
||||||
|
Assert.Equal(1, request.Headers.Count);
|
||||||
|
Assert.True(request.Headers.ContainsKey("Host"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task SendAsync_InvokesCallbackWhenPassed()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var client = _server.Handler;
|
||||||
|
var invoked = false;
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var response = await client.SendAsync("GET", "http://localhost:12345/", null, null, _ => invoked = true);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.True(invoked);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task SendAsync_RespectsExistingHost()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var client = _server.Handler;
|
||||||
|
var headers = new Dictionary<string, string[]> { { "Host", new string[] { "server:12345" } } };
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var response = await client.SendAsync("GET", "http://localhost:12345/Home/", headers);
|
||||||
|
var request = response.HttpContext.Request;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal("server:12345", request.Host.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task SendAsync_RespectsArgumentBody()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var client = _server.Handler;
|
||||||
|
var headers = new Dictionary<string, string[]> { { "Content-Type", new string[] { "text/plain" } } };
|
||||||
|
var body = new MemoryStream();
|
||||||
|
new StreamWriter(body).Write("Hello world");
|
||||||
|
body.Position = 0;
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var response = await client.SendAsync("POST", "http://host/", headers, body);
|
||||||
|
var request = response.HttpContext.Request;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Same(body, request.Body);
|
||||||
|
Assert.Equal(0, request.Body.Position);
|
||||||
|
Assert.Equal(body.Length, request.ContentLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task SendAsync_RewindsTheResponseStream()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var server = TestServer.Create(_services, app => app.Run(ctx => ctx.Response.WriteAsync("Hello world")));
|
||||||
|
var client = server.Handler;
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var response = await client.SendAsync("GET", "http://localhost");
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(0, response.Body.Position);
|
||||||
|
Assert.Equal("Hello world", new StreamReader(response.Body).ReadToEnd());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task PutAsyncWorks()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
RequestDelegate appDelegate = async ctx =>
|
||||||
|
await ctx.Response.WriteAsync(new StreamReader(ctx.Request.Body).ReadToEnd());
|
||||||
|
var server = TestServer.Create(_services, app => app.Run(appDelegate));
|
||||||
|
var client = server.Handler;
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var response = await client.PutAsync("http://localhost:12345", "Hello world", "text/plain");
|
||||||
|
var request = response.HttpContext.Request;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal("PUT", request.Method);
|
||||||
|
Assert.Equal("Hello world", new StreamReader(response.Body).ReadToEnd());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task PostAsyncWorks()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
RequestDelegate appDelegate = async ctx =>
|
||||||
|
await ctx.Response.WriteAsync(new StreamReader(ctx.Request.Body).ReadToEnd());
|
||||||
|
var server = TestServer.Create(_services, app => app.Run(appDelegate));
|
||||||
|
var client = server.Handler;
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var response = await client.PostAsync("http://localhost:12345", "Hello world", "text/plain");
|
||||||
|
var request = response.HttpContext.Request;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal("POST", request.Method);
|
||||||
|
Assert.Equal("Hello world", new StreamReader(response.Body).ReadToEnd());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,74 @@
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Runtime.Versioning;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNet.Abstractions;
|
||||||
|
using Microsoft.AspNet.DependencyInjection;
|
||||||
|
using Microsoft.AspNet.DependencyInjection.Fallback;
|
||||||
|
using Microsoft.Net.Runtime;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.TestHost.Tests
|
||||||
|
{
|
||||||
|
public class TestServerTests
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void CreateWithDelegate()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var services = new ServiceCollection()
|
||||||
|
.AddSingleton<IApplicationEnvironment, TestApplicationEnvironment>()
|
||||||
|
.BuildServiceProvider();
|
||||||
|
|
||||||
|
// Act & Assert
|
||||||
|
Assert.DoesNotThrow(() => TestServer.Create(services, app => { }));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task CreateWithGeneric()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var services = new ServiceCollection()
|
||||||
|
.AddSingleton<IApplicationEnvironment, TestApplicationEnvironment>()
|
||||||
|
.BuildServiceProvider();
|
||||||
|
|
||||||
|
var server = TestServer.Create<Startup>(services);
|
||||||
|
var client = server.Handler;
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var response = await client.GetAsync("http://any");
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal("Startup", new StreamReader(response.Body).ReadToEnd());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ThrowsIfNoApplicationEnvironmentIsRegisteredWithTheProvider()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var services = new ServiceCollection()
|
||||||
|
.BuildServiceProvider();
|
||||||
|
|
||||||
|
// Act & Assert
|
||||||
|
Assert.Throws<ArgumentException>(
|
||||||
|
"serviceProvider",
|
||||||
|
() => TestServer.Create<Startup>(services));
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Startup
|
||||||
|
{
|
||||||
|
public void Configuration(IBuilder builder)
|
||||||
|
{
|
||||||
|
builder.Run(ctx => ctx.Response.WriteAsync("Startup"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class AnotherStartup
|
||||||
|
{
|
||||||
|
public void Configuration(IBuilder builder)
|
||||||
|
{
|
||||||
|
builder.Run(ctx => ctx.Response.WriteAsync("Another Startup"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
{
|
||||||
|
"version" : "0.1-alpha-*",
|
||||||
|
"dependencies": {
|
||||||
|
"System.Reflection": "4.0.10.0",
|
||||||
|
"System.Runtime" : "4.0.20.0",
|
||||||
|
"Microsoft.AspNet.Abstractions": "0.1-alpha-*",
|
||||||
|
"Microsoft.AspNet.ConfigurationModel": "0.1-alpha-*",
|
||||||
|
"Microsoft.AspNet.DependencyInjection": "0.1-alpha-*",
|
||||||
|
"Microsoft.AspNet.FeatureModel": "0.1-alpha-*",
|
||||||
|
"Microsoft.AspNet.Hosting": "",
|
||||||
|
"Microsoft.AspNet.TestHost": "",
|
||||||
|
"Microsoft.AspNet.HttpFeature": "0.1-alpha-*",
|
||||||
|
"Microsoft.AspNet.PipelineCore": "0.1-alpha-*",
|
||||||
|
"Microsoft.AspNet.Security.DataProtection": "0.1-alpha-*",
|
||||||
|
"xunit.abstractions": "2.0.0-aspnet-*",
|
||||||
|
"xunit.assert": "2.0.0-aspnet-*",
|
||||||
|
"xunit.core": "2.0.0-aspnet-*",
|
||||||
|
"xunit.execution": "2.0.0-aspnet-*",
|
||||||
|
"Xunit.KRunner": "0.1-alpha-*"
|
||||||
|
},
|
||||||
|
"commands": {
|
||||||
|
"test": "Xunit.KRunner"
|
||||||
|
},
|
||||||
|
"configurations": {
|
||||||
|
"net45": {
|
||||||
|
"dependencies": {
|
||||||
|
"System.Collections": "4.0.0.0",
|
||||||
|
"System.ComponentModel": "4.0.0.0",
|
||||||
|
"System.Globalization": "4.0.10.0",
|
||||||
|
"System.Linq": "4.0.0.0",
|
||||||
|
"System.Reflection": "4.0.10.0",
|
||||||
|
"System.Runtime": "4.0.20.0",
|
||||||
|
"System.Runtime.Extensions": "4.0.10.0",
|
||||||
|
"System.Runtime.Serialization.Primitives": "4.0.0.0",
|
||||||
|
"System.Threading": "4.0.0.0",
|
||||||
|
"System.Threading.Tasks": "4.0.0.0",
|
||||||
|
"System.Threading.Thread": "4.0.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue