diff --git a/Capnp.Net.Runtime.Tests/EdgeCaseHandling.cs b/Capnp.Net.Runtime.Tests/EdgeCaseHandling.cs index b399f0a..0986996 100644 --- a/Capnp.Net.Runtime.Tests/EdgeCaseHandling.cs +++ b/Capnp.Net.Runtime.Tests/EdgeCaseHandling.cs @@ -1179,7 +1179,77 @@ namespace Capnp.Net.Runtime.Tests Assert.AreEqual(Message.WHICH.Call, _.which); Assert.AreEqual(MessageTarget.WHICH.ImportedCap, _.Call.Target.which); Assert.AreEqual(27u, _.Call.Target.ImportedCap); + + tester.Send(_1 => + { + _1.which = Message.WHICH.Return; + _1.Return.AnswerId = _.Call.QuestionId; + _1.Return.which = Return.WHICH.Results; + _1.Return.Results.CapTable.Init(1); + _1.Return.Results.CapTable[0].which = CapDescriptor.WHICH.ThirdPartyHosted; + _1.Return.Results.CapTable[0].ThirdPartyHosted.VineId = 27; + _1.Return.Results.Content.SetCapability(0); + }); }); } + + [TestMethod] + public void NoneImportBootstrap() + { + var tester = new RpcEngineTester(); + + var cap = tester.RealEnd.QueryMain(); + var proxy = new BareProxy(cap); + + tester.Recv(_ => { + Assert.AreEqual(Message.WHICH.Bootstrap, _.which); + + tester.Send(_1 => + { + _1.which = Message.WHICH.Return; + _1.Return.AnswerId = _.Bootstrap.QuestionId; + _1.Return.which = Return.WHICH.Results; + _1.Return.Results.CapTable.Init(1); + _1.Return.Results.CapTable[0].which = CapDescriptor.WHICH.None; + }); + }); + + tester.Recv(_ => { + Assert.AreEqual(Message.WHICH.Finish, _.which); + }); + + var answer = proxy.Call(1, 2, DynamicSerializerState.CreateForRpc()); + var task = Impatient.MakePipelineAware(answer, _ => _); + Assert.IsTrue(task.IsFaulted); + Assert.IsFalse(tester.IsDismissed); + } + + [TestMethod] + public void UnknownImportBootstrap() + { + var tester = new RpcEngineTester(); + + var cap = tester.RealEnd.QueryMain(); + var proxy = new BareProxy(cap); + + tester.Recv(_ => { + Assert.AreEqual(Message.WHICH.Bootstrap, _.which); + + tester.Send(_1 => + { + _1.which = Message.WHICH.Return; + _1.Return.AnswerId = _.Bootstrap.QuestionId; + _1.Return.which = Return.WHICH.Results; + _1.Return.Results.CapTable.Init(1); + _1.Return.Results.CapTable[0].which = (CapDescriptor.WHICH)27; + }); + }); + + tester.Recv(_ => { + Assert.AreEqual(Message.WHICH.Unimplemented, _.which); + }); + + Assert.IsFalse(tester.IsDismissed); + } } } diff --git a/Capnp.Net.Runtime.Tests/ImpatientTests.cs b/Capnp.Net.Runtime.Tests/ImpatientTests.cs new file mode 100644 index 0000000..e32c89f --- /dev/null +++ b/Capnp.Net.Runtime.Tests/ImpatientTests.cs @@ -0,0 +1,191 @@ +using Capnp.Net.Runtime.Tests.GenImpls; +using Capnp.Rpc; +using Capnproto_test.Capnp.Test; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; + +namespace Capnp.Net.Runtime.Tests +{ + [TestClass] + [TestCategory("Coverage")] + public class ImpatientTests + { + [TestMethod] + public async Task Unwrap() + { + var impl = new TestInterfaceImpl2(); + Assert.AreEqual(impl, await impl.Unwrap()); + Assert.IsNull(await default(ITestInterface).Unwrap()); + var tcs = new TaskCompletionSource(); + tcs.SetResult(null); + Assert.IsNull(await tcs.Task.Eager(true).Unwrap()); + var excepted = Task.FromException(new InvalidTimeZoneException("So annoying")); + await Assert.ThrowsExceptionAsync(async () => await excepted.Eager(true).Unwrap()); + } + + [TestMethod] + public async Task MaybeTailCall3() + { + bool flag = false; + + SerializerState Fn(int a, int b, int c) + { + Assert.AreEqual(0, a); + Assert.AreEqual(1, b); + Assert.AreEqual(2, c); + flag = true; + return null; + } + + var t = Task.FromResult((0, 1, 2)); + await Impatient.MaybeTailCall(t, Fn); + Assert.IsTrue(flag); + } + + [TestMethod] + public async Task MaybeTailCall4() + { + bool flag = false; + + SerializerState Fn(int a, int b, int c, int d) + { + Assert.AreEqual(0, a); + Assert.AreEqual(1, b); + Assert.AreEqual(2, c); + Assert.AreEqual(3, d); + flag = true; + return null; + } + + var t = Task.FromResult((0, 1, 2, 3)); + await Impatient.MaybeTailCall(t, Fn); + Assert.IsTrue(flag); + } + + [TestMethod] + public async Task MaybeTailCall5() + { + bool flag = false; + + SerializerState Fn(int a, int b, int c, int d, int e) + { + Assert.AreEqual(0, a); + Assert.AreEqual(1, b); + Assert.AreEqual(2, c); + Assert.AreEqual(3, d); + Assert.AreEqual(4, e); + flag = true; + return null; + } + + var t = Task.FromResult((0, 1, 2, 3, 4)); + await Impatient.MaybeTailCall(t, Fn); + Assert.IsTrue(flag); + } + + [TestMethod] + public async Task MaybeTailCall6() + { + bool flag = false; + + SerializerState Fn(int a, int b, int c, int d, int e, int f) + { + Assert.AreEqual(0, a); + Assert.AreEqual(1, b); + Assert.AreEqual(2, c); + Assert.AreEqual(3, d); + Assert.AreEqual(4, e); + Assert.AreEqual(5, f); + flag = true; + return null; + } + + var t = Task.FromResult((0, 1, 2, 3, 4, 5)); + await Impatient.MaybeTailCall(t, Fn); + Assert.IsTrue(flag); + } + + [TestMethod] + public async Task MaybeTailCall7() + { + bool flag = false; + + SerializerState Fn(int a, int b, int c, int d, int e, int f, int g) + { + Assert.AreEqual(0, a); + Assert.AreEqual(1, b); + Assert.AreEqual(2, c); + Assert.AreEqual(3, d); + Assert.AreEqual(4, e); + Assert.AreEqual(5, f); + Assert.AreEqual(6, g); + flag = true; + return null; + } + + var t = Task.FromResult((0, 1, 2, 3, 4, 5, 6)); + await Impatient.MaybeTailCall(t, Fn); + Assert.IsTrue(flag); + } + + class PromisedAnswerMock : IPromisedAnswer + { + readonly TaskCompletionSource _tcs = new TaskCompletionSource(); + public Task WhenReturned => _tcs.Task; + + public bool IsTailCall => false; + + public ConsumedCapability Access(MemberAccessPath access) + { + throw new NotImplementedException(); + } + + public ConsumedCapability Access(MemberAccessPath access, Task proxyTask) + { + throw new NotImplementedException(); + } + + public void Dispose() + { + } + } + + [TestMethod] + public void ObsoleteGetAnswer() + { + var answer = new PromisedAnswerMock(); + Assert.ThrowsException(() => Impatient.GetAnswer(answer.WhenReturned)); + var t = Impatient.MakePipelineAware(answer, _ => _); + Assert.AreEqual(answer, Impatient.GetAnswer(t)); + } + + [TestMethod] + public async Task Access() + { + var answer = new PromisedAnswerMock(); + var cap = Impatient.Access(answer.WhenReturned, new MemberAccessPath(), Task.FromResult(new TestInterfaceImpl2())); + using (var proxy = new BareProxy(cap)) + { + await proxy.WhenResolved; + } + } + + [TestMethod] + public void ObsoletePseudoEager() + { + var task = Task.FromResult(new TestInterfaceImpl2()); + Assert.IsTrue(task.PseudoEager() is Proxy proxy && proxy.WhenResolved.IsCompleted); + } + + [TestMethod] + public void Eager() + { + var task = Task.FromResult(new TestInterfaceImpl2()); + Assert.ThrowsException(() => task.Eager(false)); + Assert.ThrowsException(() => task.Eager()); + } + } +} diff --git a/Capnp.Net.Runtime.Tests/Interception.cs b/Capnp.Net.Runtime.Tests/Interception.cs index 0e0e010..4d86f85 100644 --- a/Capnp.Net.Runtime.Tests/Interception.cs +++ b/Capnp.Net.Runtime.Tests/Interception.cs @@ -67,9 +67,8 @@ namespace Capnp.Net.Runtime.Tests using (server) using (client) { - //client.WhenConnected.Wait(); - var counters = new Counters(); + server.Main = policy.Attach(new TestInterfaceImpl(counters)); using (var main = client.GetMain()) { @@ -696,5 +695,35 @@ namespace Capnp.Net.Runtime.Tests } } + [TestMethod] + public void AttachWrongUse() + { + var impl = new TestInterfaceImpl2(); + Assert.ThrowsException(() => default(IInterceptionPolicy).Attach(impl)); + Assert.ThrowsException(() => new MyPolicy("x").Attach(default(ITestInterface))); + } + + [TestMethod] + public void DetachWrongUse() + { + var impl = new TestInterfaceImpl2(); + Assert.ThrowsException(() => default(IInterceptionPolicy).Detach(impl)); + Assert.ThrowsException(() => new MyPolicy("x").Detach(default(ITestInterface))); + } + + [TestMethod] + public void AttachDetach() + { + ConsumedCapability GetCap(object obj) => ((Proxy)obj).ConsumedCap; + + var a = new MyPolicy("a"); + var b = new MyPolicy("b"); + var c = new MyPolicy("c"); + var proxy = Proxy.Share(new TestInterfaceImpl2()); + var attached = a.Attach(b.Attach(c.Attach(proxy))); + Assert.AreEqual(GetCap(attached), GetCap(b.Attach(attached))); + var detached = c.Detach(a.Detach(b.Detach(attached))); + Assert.AreEqual(GetCap(proxy), GetCap(detached)); + } } } diff --git a/Capnp.Net.Runtime.Tests/TcpRpc.cs b/Capnp.Net.Runtime.Tests/TcpRpc.cs index af749ba..1782101 100644 --- a/Capnp.Net.Runtime.Tests/TcpRpc.cs +++ b/Capnp.Net.Runtime.Tests/TcpRpc.cs @@ -719,7 +719,7 @@ namespace Capnp.Net.Runtime.Tests } [TestMethod] - public void Server() + public void Server1() { var cbb = new BufferBlock(); var server = new TcpRpcServer(); @@ -808,5 +808,72 @@ namespace Capnp.Net.Runtime.Tests server.Dispose(); } + + [TestMethod] + public void Server2() + { + var server = new TcpRpcServer(); + server.Main = new TestInterfaceImpl2(); + var tracer = new FrameTracing.RpcFrameTracer(Console.Out); + server.OnConnectionChanged += (s, a) => + { + server.Dispose(); + }; + + server.StartAccepting(IPAddress.Any, TcpPort); + + var client1 = new TcpRpcClient("localhost", TcpPort); + Assert.IsTrue(client1.WhenConnected.Wait(MediumNonDbgTimeout)); + Assert.IsTrue(SpinWait.SpinUntil(() => client1.State == ConnectionState.Down, MediumNonDbgTimeout)); + } + + [TestMethod] + public void Server3() + { + using (var server = new TcpRpcServer()) + { + server.Main = new TestInterfaceImpl2(); + var tracer = new FrameTracing.RpcFrameTracer(Console.Out); + server.OnConnectionChanged += (s, a) => + { + a.Connection.Close(); + }; + + server.StartAccepting(IPAddress.Any, TcpPort); + + var client1 = new TcpRpcClient("localhost", TcpPort); + Assert.IsTrue(client1.WhenConnected.Wait(MediumNonDbgTimeout)); + Assert.IsTrue(SpinWait.SpinUntil(() => client1.State == ConnectionState.Down, MediumNonDbgTimeout)); + } + } + + [TestMethod] + public void Client() + { + using (var server = new TcpRpcServer()) + using (var client = new TcpRpcClient()) + { + Assert.IsFalse(client.IsComputing); + Assert.IsFalse(client.IsWaitingForData); + Assert.AreEqual(0L, client.SendCount); + Assert.AreEqual(0L, client.RecvCount); + Assert.ThrowsException(() => client.GetMain()); + Assert.ThrowsException(() => client.AttachTracer(null)); + Assert.ThrowsException(() => client.InjectMidlayer(null)); + server.StartAccepting(IPAddress.Any, TcpPort); + client.Connect("localhost", TcpPort); + Assert.ThrowsException(() => client.Connect("localhost", TcpPort)); + Assert.IsTrue(client.WhenConnected.Wait(MediumNonDbgTimeout)); + Assert.ThrowsException(() => client.AttachTracer(new FrameTracing.RpcFrameTracer(Console.Out, false))); + Assert.ThrowsException(() => client.InjectMidlayer(_ => _)); + Assert.AreEqual(TcpPort, client.RemotePort); + Assert.IsTrue(client.LocalPort != 0); + Assert.AreEqual(0L, client.SendCount); + Assert.AreEqual(0L, client.RecvCount); + Assert.IsTrue(SpinWait.SpinUntil(() => client.IsWaitingForData, MediumNonDbgTimeout)); + ((IConnection)client).Close(); + Assert.IsTrue(SpinWait.SpinUntil(() => client.State == ConnectionState.Down, MediumNonDbgTimeout)); + } + } } } diff --git a/Capnp.Net.Runtime/Rpc/Interception/Interceptor.cs b/Capnp.Net.Runtime/Rpc/Interception/Interceptor.cs index b951676..ae692fd 100644 --- a/Capnp.Net.Runtime/Rpc/Interception/Interceptor.cs +++ b/Capnp.Net.Runtime/Rpc/Interception/Interceptor.cs @@ -9,9 +9,6 @@ namespace Capnp.Rpc.Interception /// public static class Interceptor { - static readonly ConditionalWeakTable _interceptMap = - new ConditionalWeakTable(); - /// /// Attach this policy to given capability. /// diff --git a/Capnp.Net.Runtime/Rpc/Proxy.cs b/Capnp.Net.Runtime/Rpc/Proxy.cs index f82b6e0..48657ff 100644 --- a/Capnp.Net.Runtime/Rpc/Proxy.cs +++ b/Capnp.Net.Runtime/Rpc/Proxy.cs @@ -58,7 +58,7 @@ namespace Capnp.Rpc /// /// Underlying low-level capability /// - protected internal ConsumedCapability ConsumedCap => _disposedValue ? + public ConsumedCapability ConsumedCap => _disposedValue ? throw new ObjectDisposedException(nameof(Proxy)) : _consumedCap; ///