add capability tail call test

This commit is contained in:
Vaci Koblizek 2020-11-19 18:34:21 +00:00
parent 1366e28fd5
commit d3e639eaee
2 changed files with 44 additions and 2 deletions

View file

@ -66,7 +66,7 @@ class TestExtendsImpl extends Test.TestExtends2.Server {
} }
} }
public class CapabilityTest { public final class CapabilityTest {
@org.junit.Test @org.junit.Test
public void testBasic() { public void testBasic() {
@ -157,6 +157,40 @@ public class CapabilityTest {
Assert.assertEquals(1, chainedCallCount.value()); Assert.assertEquals(1, chainedCallCount.value());
} }
@org.junit.Test
public void testTailCall() {
var calleeCallCount = new Counter();
var callerCallCount = new Counter();
var callee = new Test.TestTailCallee.Client(
new RpcTestUtil.TestTailCalleeImpl(calleeCallCount));
var caller = new Test.TestTailCaller.Client(
new RpcTestUtil.TestTailCallerImpl(callerCallCount));
var request = caller.fooRequest();
request.getParams().setI(456);
request.getParams().setCallee(callee);
var promise = request.send();
var dependentCall0 = promise.getC().getCallSequenceRequest().send();
var response = promise.join();
Assert.assertEquals(456, response.getI());
Assert.assertEquals(456, response.getI());
var dependentCall1 = promise.getC().getCallSequenceRequest().send();
var dependentCall2 = response.getC().getCallSequenceRequest().send();
Assert.assertEquals(0, dependentCall0.join().getN());
Assert.assertEquals(1, dependentCall1.join().getN());
Assert.assertEquals(2, dependentCall2.join().getN());
Assert.assertEquals(1, calleeCallCount.value());
Assert.assertEquals(1, callerCallCount.value());
}
class TestThisCap extends Test.TestInterface.Server { class TestThisCap extends Test.TestInterface.Server {
Counter counter; Counter counter;

View file

@ -185,10 +185,18 @@ public final class Capability {
return null; return null;
} }
// We don't want to actually dispatch the call synchronously, because we don't want the callee
// to have any side effects before the promise is returned to the caller. This helps avoid
// race conditions.
//
// So, we do an evalLater() here.
//
// Note also that QueuedClient depends on this evalLater() to ensure that pipelined calls don't
// complete before 'whenMoreResolved()' promises resolve.
// TODO fix the above comment! we don't have the option of evalLater (yes)
var promise = this.whenResolved().thenCompose( var promise = this.whenResolved().thenCompose(
void_ -> this.callInternal(interfaceId, methodId, ctx)); void_ -> this.callInternal(interfaceId, methodId, ctx));
var pipelinePromise = promise.thenApply(x -> { var pipelinePromise = promise.thenApply(x -> {
ctx.releaseParams(); ctx.releaseParams();
return (PipelineHook)new LocalPipeline(ctx); return (PipelineHook)new LocalPipeline(ctx);