Make SocketOutput more testable

- Added a MockLibUv class
- Create a SocketOutputTests class
This commit is contained in:
Stephen Halter 2015-07-24 16:47:05 -07:00
parent c345849707
commit cce9d8f09c
6 changed files with 298 additions and 67 deletions

View File

@ -14,11 +14,8 @@ namespace Microsoft.AspNet.Server.Kestrel
public class KestrelEngine : IDisposable
{
public KestrelEngine(ILibraryManager libraryManager, IApplicationShutdown appShutdownService)
: this(appShutdownService)
{
AppShutdown = appShutdownService;
Threads = new List<KestrelThread>();
Listeners = new List<Listener>();
Memory = new MemoryPool();
Libuv = new Libuv();
var libraryPath = default(string);
@ -61,6 +58,21 @@ namespace Microsoft.AspNet.Server.Kestrel
Libuv.Load(libraryPath);
}
// For testing
internal KestrelEngine(Libuv uv, IApplicationShutdown appShutdownService)
: this(appShutdownService)
{
Libuv = uv;
}
private KestrelEngine(IApplicationShutdown appShutdownService)
{
AppShutdown = appShutdownService;
Threads = new List<KestrelThread>();
Listeners = new List<Listener>();
Memory = new MemoryPool();
}
public Libuv Libuv { get; private set; }
public IMemoryPool Memory { get; set; }
public IApplicationShutdown AppShutdown { get; private set; }

View File

@ -84,16 +84,16 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate int uv_loop_init(UvLoopHandle a0);
uv_loop_init _uv_loop_init = default(uv_loop_init);
protected delegate int uv_loop_init(UvLoopHandle a0);
protected uv_loop_init _uv_loop_init = default(uv_loop_init);
public void loop_init(UvLoopHandle handle)
{
Check(_uv_loop_init(handle));
}
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate int uv_loop_close(IntPtr a0);
uv_loop_close _uv_loop_close = default(uv_loop_close);
protected delegate int uv_loop_close(IntPtr a0);
protected uv_loop_close _uv_loop_close = default(uv_loop_close);
public void loop_close(UvLoopHandle handle)
{
handle.Validate(closed: true);
@ -101,8 +101,8 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
}
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate int uv_run(UvLoopHandle handle, int mode);
uv_run _uv_run = default(uv_run);
protected delegate int uv_run(UvLoopHandle handle, int mode);
protected uv_run _uv_run = default(uv_run);
public int run(UvLoopHandle handle, int mode)
{
handle.Validate();
@ -110,8 +110,8 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
}
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate void uv_stop(UvLoopHandle handle);
uv_stop _uv_stop = default(uv_stop);
protected delegate void uv_stop(UvLoopHandle handle);
protected uv_stop _uv_stop = default(uv_stop);
public void stop(UvLoopHandle handle)
{
handle.Validate();
@ -119,8 +119,8 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
}
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate void uv_ref(UvHandle handle);
uv_ref _uv_ref = default(uv_ref);
protected delegate void uv_ref(UvHandle handle);
protected uv_ref _uv_ref = default(uv_ref);
public void @ref(UvHandle handle)
{
handle.Validate();
@ -128,8 +128,8 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
}
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate void uv_unref(UvHandle handle);
uv_unref _uv_unref = default(uv_unref);
protected delegate void uv_unref(UvHandle handle);
protected uv_unref _uv_unref = default(uv_unref);
public void unref(UvHandle handle)
{
handle.Validate();
@ -140,8 +140,8 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void uv_close_cb(IntPtr handle);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate void uv_close(IntPtr handle, uv_close_cb close_cb);
uv_close _uv_close = default(uv_close);
protected delegate void uv_close(IntPtr handle, uv_close_cb close_cb);
protected uv_close _uv_close = default(uv_close);
public void close(UvHandle handle, uv_close_cb close_cb)
{
handle.Validate(closed: true);
@ -155,8 +155,8 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void uv_async_cb(IntPtr handle);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate int uv_async_init(UvLoopHandle loop, UvAsyncHandle handle, uv_async_cb cb);
uv_async_init _uv_async_init = default(uv_async_init);
protected delegate int uv_async_init(UvLoopHandle loop, UvAsyncHandle handle, uv_async_cb cb);
protected uv_async_init _uv_async_init = default(uv_async_init);
public void async_init(UvLoopHandle loop, UvAsyncHandle handle, uv_async_cb cb)
{
loop.Validate();
@ -165,16 +165,16 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
}
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate int uv_async_send(UvAsyncHandle handle);
uv_async_send _uv_async_send = default(uv_async_send);
protected delegate int uv_async_send(UvAsyncHandle handle);
protected uv_async_send _uv_async_send = default(uv_async_send);
public void async_send(UvAsyncHandle handle)
{
Check(_uv_async_send(handle));
}
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate int uv_tcp_init(UvLoopHandle loop, UvTcpHandle handle);
uv_tcp_init _uv_tcp_init = default(uv_tcp_init);
protected delegate int uv_tcp_init(UvLoopHandle loop, UvTcpHandle handle);
protected uv_tcp_init _uv_tcp_init = default(uv_tcp_init);
public void tcp_init(UvLoopHandle loop, UvTcpHandle handle)
{
loop.Validate();
@ -183,8 +183,8 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
}
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate int uv_tcp_bind(UvTcpHandle handle, ref sockaddr addr, int flags);
uv_tcp_bind _uv_tcp_bind = default(uv_tcp_bind);
protected delegate int uv_tcp_bind(UvTcpHandle handle, ref sockaddr addr, int flags);
protected uv_tcp_bind _uv_tcp_bind = default(uv_tcp_bind);
public void tcp_bind(UvTcpHandle handle, ref sockaddr addr, int flags)
{
handle.Validate();
@ -192,8 +192,8 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
}
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate int uv_tcp_open(UvTcpHandle handle, IntPtr hSocket);
uv_tcp_open _uv_tcp_open = default(uv_tcp_open);
protected delegate int uv_tcp_open(UvTcpHandle handle, IntPtr hSocket);
protected uv_tcp_open _uv_tcp_open = default(uv_tcp_open);
public void tcp_open(UvTcpHandle handle, IntPtr hSocket)
{
handle.Validate();
@ -201,8 +201,8 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
}
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate int uv_pipe_init(UvLoopHandle loop, UvPipeHandle handle, int ipc);
uv_pipe_init _uv_pipe_init = default(uv_pipe_init);
protected delegate int uv_pipe_init(UvLoopHandle loop, UvPipeHandle handle, int ipc);
protected uv_pipe_init _uv_pipe_init = default(uv_pipe_init);
public void pipe_init(UvLoopHandle loop, UvPipeHandle handle, bool ipc)
{
loop.Validate();
@ -211,8 +211,8 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
}
[UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
delegate int uv_pipe_bind(UvPipeHandle loop, string name);
uv_pipe_bind _uv_pipe_bind = default(uv_pipe_bind);
protected delegate int uv_pipe_bind(UvPipeHandle loop, string name);
protected uv_pipe_bind _uv_pipe_bind = default(uv_pipe_bind);
public void pipe_bind(UvPipeHandle handle, string name)
{
handle.Validate();
@ -222,8 +222,8 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void uv_connection_cb(IntPtr server, int status);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate int uv_listen(UvStreamHandle handle, int backlog, uv_connection_cb cb);
uv_listen _uv_listen = default(uv_listen);
protected delegate int uv_listen(UvStreamHandle handle, int backlog, uv_connection_cb cb);
protected uv_listen _uv_listen = default(uv_listen);
public void listen(UvStreamHandle handle, int backlog, uv_connection_cb cb)
{
handle.Validate();
@ -231,8 +231,8 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
}
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate int uv_accept(UvStreamHandle server, UvStreamHandle client);
uv_accept _uv_accept = default(uv_accept);
protected delegate int uv_accept(UvStreamHandle server, UvStreamHandle client);
protected uv_accept _uv_accept = default(uv_accept);
public void accept(UvStreamHandle server, UvStreamHandle client)
{
server.Validate();
@ -243,8 +243,8 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void uv_connect_cb(IntPtr req, int status);
[UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
unsafe delegate int uv_pipe_connect(UvConnectRequest req, UvPipeHandle handle, string name, uv_connect_cb cb);
uv_pipe_connect _uv_pipe_connect = default(uv_pipe_connect);
unsafe protected delegate int uv_pipe_connect(UvConnectRequest req, UvPipeHandle handle, string name, uv_connect_cb cb);
protected uv_pipe_connect _uv_pipe_connect = default(uv_pipe_connect);
unsafe public void pipe_connect(UvConnectRequest req, UvPipeHandle handle, string name, uv_connect_cb cb)
{
req.Validate();
@ -257,8 +257,8 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void uv_read_cb(IntPtr server, int nread, ref uv_buf_t buf);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate int uv_read_start(UvStreamHandle handle, uv_alloc_cb alloc_cb, uv_read_cb read_cb);
uv_read_start _uv_read_start = default(uv_read_start);
protected delegate int uv_read_start(UvStreamHandle handle, uv_alloc_cb alloc_cb, uv_read_cb read_cb);
protected uv_read_start _uv_read_start = default(uv_read_start);
public void read_start(UvStreamHandle handle, uv_alloc_cb alloc_cb, uv_read_cb read_cb)
{
handle.Validate();
@ -266,8 +266,8 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
}
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate int uv_read_stop(UvStreamHandle handle);
uv_read_stop _uv_read_stop = default(uv_read_stop);
protected delegate int uv_read_stop(UvStreamHandle handle);
protected uv_read_stop _uv_read_stop = default(uv_read_stop);
public void read_stop(UvStreamHandle handle)
{
handle.Validate();
@ -275,8 +275,8 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
}
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate int uv_try_write(UvStreamHandle handle, Libuv.uv_buf_t[] bufs, int nbufs);
uv_try_write _uv_try_write = default(uv_try_write);
protected delegate int uv_try_write(UvStreamHandle handle, Libuv.uv_buf_t[] bufs, int nbufs);
protected uv_try_write _uv_try_write = default(uv_try_write);
public int try_write(UvStreamHandle handle, Libuv.uv_buf_t[] bufs, int nbufs)
{
handle.Validate();
@ -286,8 +286,8 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void uv_write_cb(IntPtr req, int status);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
unsafe delegate int uv_write(UvRequest req, UvStreamHandle handle, Libuv.uv_buf_t* bufs, int nbufs, uv_write_cb cb);
uv_write _uv_write = default(uv_write);
unsafe protected delegate int uv_write(UvRequest req, UvStreamHandle handle, Libuv.uv_buf_t* bufs, int nbufs, uv_write_cb cb);
protected uv_write _uv_write = default(uv_write);
unsafe public void write(UvRequest req, UvStreamHandle handle, Libuv.uv_buf_t* bufs, int nbufs, uv_write_cb cb)
{
req.Validate();
@ -296,8 +296,8 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
}
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
unsafe delegate int uv_write2(UvRequest req, UvStreamHandle handle, Libuv.uv_buf_t* bufs, int nbufs, UvStreamHandle sendHandle, uv_write_cb cb);
uv_write2 _uv_write2 = default(uv_write2);
unsafe protected delegate int uv_write2(UvRequest req, UvStreamHandle handle, Libuv.uv_buf_t* bufs, int nbufs, UvStreamHandle sendHandle, uv_write_cb cb);
protected uv_write2 _uv_write2 = default(uv_write2);
unsafe public void write2(UvRequest req, UvStreamHandle handle, Libuv.uv_buf_t* bufs, int nbufs, UvStreamHandle sendHandle, uv_write_cb cb)
{
req.Validate();
@ -308,8 +308,8 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void uv_shutdown_cb(IntPtr req, int status);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate int uv_shutdown(UvShutdownReq req, UvStreamHandle handle, uv_shutdown_cb cb);
uv_shutdown _uv_shutdown = default(uv_shutdown);
protected delegate int uv_shutdown(UvShutdownReq req, UvStreamHandle handle, uv_shutdown_cb cb);
protected uv_shutdown _uv_shutdown = default(uv_shutdown);
public void shutdown(UvShutdownReq req, UvStreamHandle handle, uv_shutdown_cb cb)
{
req.Validate();
@ -318,8 +318,8 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
}
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate IntPtr uv_err_name(int err);
uv_err_name _uv_err_name = default(uv_err_name);
protected delegate IntPtr uv_err_name(int err);
protected uv_err_name _uv_err_name = default(uv_err_name);
public unsafe String err_name(int err)
{
IntPtr ptr = _uv_err_name(err);
@ -327,8 +327,8 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
}
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate IntPtr uv_strerror(int err);
uv_strerror _uv_strerror = default(uv_strerror);
protected delegate IntPtr uv_strerror(int err);
protected uv_strerror _uv_strerror = default(uv_strerror);
public unsafe String strerror(int err)
{
IntPtr ptr = _uv_strerror(err);
@ -336,42 +336,42 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
}
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate int uv_loop_size();
uv_loop_size _uv_loop_size = default(uv_loop_size);
protected delegate int uv_loop_size();
protected uv_loop_size _uv_loop_size = default(uv_loop_size);
public int loop_size()
{
return _uv_loop_size();
}
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate int uv_handle_size(HandleType handleType);
uv_handle_size _uv_handle_size = default(uv_handle_size);
protected delegate int uv_handle_size(HandleType handleType);
protected uv_handle_size _uv_handle_size = default(uv_handle_size);
public int handle_size(HandleType handleType)
{
return _uv_handle_size(handleType);
}
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate int uv_req_size(RequestType reqType);
uv_req_size _uv_req_size = default(uv_req_size);
protected delegate int uv_req_size(RequestType reqType);
protected uv_req_size _uv_req_size = default(uv_req_size);
public int req_size(RequestType reqType)
{
return _uv_req_size(reqType);
}
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate int uv_ip4_addr(string ip, int port, out sockaddr addr);
protected delegate int uv_ip4_addr(string ip, int port, out sockaddr addr);
uv_ip4_addr _uv_ip4_addr = default(uv_ip4_addr);
protected uv_ip4_addr _uv_ip4_addr = default(uv_ip4_addr);
public int ip4_addr(string ip, int port, out sockaddr addr, out Exception error)
{
return Check(_uv_ip4_addr(ip, port, out addr), out error);
}
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate int uv_ip6_addr(string ip, int port, out sockaddr addr);
protected delegate int uv_ip6_addr(string ip, int port, out sockaddr addr);
uv_ip6_addr _uv_ip6_addr = default(uv_ip6_addr);
protected uv_ip6_addr _uv_ip6_addr = default(uv_ip6_addr);
public int ip6_addr(string ip, int port, out sockaddr addr, out Exception error)
{
return Check(_uv_ip6_addr(ip, port, out addr), out error);
@ -380,8 +380,8 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void uv_walk_cb(IntPtr handle, IntPtr arg);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
unsafe delegate int uv_walk(UvLoopHandle loop, uv_walk_cb walk_cb, IntPtr arg);
uv_walk _uv_walk = default(uv_walk);
unsafe protected delegate int uv_walk(UvLoopHandle loop, uv_walk_cb walk_cb, IntPtr arg);
protected uv_walk _uv_walk = default(uv_walk);
unsafe public void walk(UvLoopHandle loop, uv_walk_cb walk_cb, IntPtr arg)
{
loop.Validate();

View File

@ -14,7 +14,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
public abstract class UvMemory : SafeHandle
{
protected Libuv _uv;
private int _threadId;
protected int _threadId;
public UvMemory() : base(IntPtr.Zero, true)
{

View File

@ -2,5 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Reflection;
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("Microsoft.AspNet.Server.KestrelTests")]
[assembly: AssemblyMetadata("Serviceable", "True")]

View File

@ -0,0 +1,133 @@
// 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.Threading;
using Microsoft.AspNet.Server.Kestrel;
using Microsoft.AspNet.Server.Kestrel.Http;
using Microsoft.AspNet.Server.Kestrel.Networking;
using Microsoft.AspNet.Server.KestrelTests.TestHelpers;
using Xunit;
namespace Microsoft.AspNet.Server.KestrelTests
{
public class SocketOutputTests
{
[Fact]
public void CanWrite1MB()
{
// This test was added because when initially implementing write-behind buffering in
// SocketOutput, the write callback would never be invoked for writes larger than
// _maxBytesPreCompleted even after the write actually completed.
// Arrange
var mockLibuv = new MockLibuv
{
OnWrite = (socket, buffers, triggerCompleted) =>
{
triggerCompleted(0);
return 0;
}
};
using (var kestrelEngine = new KestrelEngine(mockLibuv, new ShutdownNotImplemented()))
{
kestrelEngine.Start(count: 1);
var kestrelThread = kestrelEngine.Threads[0];
var socket = new MockSocket(kestrelThread.Loop.ThreadId);
var socketOutput = new SocketOutput(kestrelThread, socket);
// I doubt _maxBytesPreCompleted will ever be over a MB. If it is, we should change this test.
var bufferSize = 1048576;
var buffer = new ArraySegment<byte>(new byte[bufferSize], 0, bufferSize);
var completedWh = new ManualResetEventSlim();
Action<Exception, object> onCompleted = (ex, state) =>
{
Assert.Null(ex);
Assert.Null(state);
completedWh.Set();
};
// Act
socketOutput.Write(buffer, onCompleted, state: null);
// Assert
Assert.True(completedWh.Wait(100));
}
}
[Fact]
public void WritesDontCompleteImmediatelyWhenTooManyBytesAreAlreadyPreCompleted()
{
// This should match _maxBytesPreCompleted in SocketOutput
var maxBytesPreCompleted = 65536;
var completeQueue = new Queue<Action<int>>();
// Arrange
var mockLibuv = new MockLibuv
{
OnWrite = (socket, buffers, triggerCompleted) =>
{
completeQueue.Enqueue(triggerCompleted);
return 0;
}
};
using (var kestrelEngine = new KestrelEngine(mockLibuv, new ShutdownNotImplemented()))
{
kestrelEngine.Start(count: 1);
var kestrelThread = kestrelEngine.Threads[0];
var socket = new MockSocket(kestrelThread.Loop.ThreadId);
var socketOutput = new SocketOutput(kestrelThread, socket);
var bufferSize = maxBytesPreCompleted;
var buffer = new ArraySegment<byte>(new byte[bufferSize], 0, bufferSize);
var completedWh = new ManualResetEventSlim();
Action<Exception, object> onCompleted = (ex, state) =>
{
Assert.Null(ex);
Assert.Null(state);
completedWh.Set();
};
// Act
socketOutput.Write(buffer, onCompleted, state: null);
// Assert
// The first write should pre-complete since it is <= _maxBytesPreCompleted.
Assert.True(completedWh.Wait(100));
// Arrange
completedWh.Reset();
// Act
socketOutput.Write(buffer, onCompleted, state: null);
// Assert
// Too many bytes are already pre-completed for the second write to pre-complete.
Assert.False(completedWh.Wait(100));
// Act
completeQueue.Dequeue()(0);
// Assert
// Finishing the first write should allow the second write to pre-complete.
Assert.True(completedWh.Wait(100));
}
}
private class MockSocket : UvStreamHandle
{
public MockSocket(int threadId)
{
// Set the handle to something other than IntPtr.Zero
// so handle.Validate doesn't fail in Libuv.write
handle = (IntPtr)1;
_threadId = threadId;
}
protected override bool ReleaseHandle()
{
// No-op
return true;
}
}
}
}

View File

@ -0,0 +1,84 @@
using System;
using System.Threading;
using Microsoft.AspNet.Server.Kestrel.Networking;
namespace Microsoft.AspNet.Server.KestrelTests.TestHelpers
{
public class MockLibuv : Libuv
{
private UvAsyncHandle _postHandle;
private uv_async_cb _onPost;
private bool _stopLoop;
private readonly ManualResetEventSlim _loopWh = new ManualResetEventSlim();
private Func<UvStreamHandle, ArraySegment<ArraySegment<byte>>, Action<int>, int> _onWrite;
unsafe public MockLibuv()
{
_uv_write = UvWrite;
_uv_async_send = postHandle =>
{
_loopWh.Set();
return 0;
};
_uv_async_init = (loop, postHandle, callback) =>
{
_postHandle = postHandle;
_onPost = callback;
return 0;
};
_uv_run = (loopHandle, mode) =>
{
while (!_stopLoop)
{
_loopWh.Wait();
_loopWh.Reset();
_onPost(_postHandle.InternalGetHandle());
}
_postHandle.Dispose();
loopHandle.Dispose();
return 0;
};
_uv_stop = handle =>
{
_stopLoop = true;
_loopWh.Set();
};
_uv_req_size = reqType => IntPtr.Size;
_uv_loop_size = () => IntPtr.Size;
_uv_handle_size = handleType => IntPtr.Size;
_uv_loop_init = loop => 0;
_uv_tcp_init = (loopHandle, tcpHandle) => 0;
_uv_close = (handle, callback) => callback(handle);
_uv_loop_close = handle => 0;
_uv_unref = handle => { };
_uv_walk = (loop, callback, ignore) => 0;
}
public Func<UvStreamHandle, ArraySegment<ArraySegment<byte>>, Action<int>, int> OnWrite
{
get
{
return _onWrite;
}
set
{
_onWrite = value;
}
}
unsafe private int UvWrite(UvRequest req, UvStreamHandle handle, uv_buf_t* bufs, int nbufs, uv_write_cb cb)
{
return _onWrite(handle, new ArraySegment<ArraySegment<byte>>(), status => cb(req.InternalGetHandle(), status));
}
}
}