remove CapabilityServerSetBase, add test case

This commit is contained in:
Vaci Koblizek 2020-11-26 16:01:40 +00:00
parent 60690c1e70
commit a2a17ea3cb
2 changed files with 88 additions and 24 deletions

View file

@ -21,16 +21,13 @@ package org.capnproto;
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE. // THE SOFTWARE.
import org.capnproto.AnyPointer;
import org.capnproto.CallContext;
import org.capnproto.Capability;
import org.capnproto.RpcException;
import org.capnproto.rpctest.Test; import org.capnproto.rpctest.Test;
import org.junit.Assert; import org.junit.Assert;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.atomic.AtomicBoolean;
class Counter { class Counter {
private int count = 0; private int count = 0;
@ -291,4 +288,70 @@ public final class CapabilityTest {
Assert.assertEquals(579, result.getTotalI()); Assert.assertEquals(579, result.getTotalI());
Assert.assertEquals(321, result.getTotalJ()); Assert.assertEquals(321, result.getTotalJ());
} }
@org.junit.Test
public void testCapabilityServerSet() {
var set1 = new Capability.CapabilityServerSet<Test.TestInterface.Server>();
var set2 = new Capability.CapabilityServerSet<Test.TestInterface.Server>();
var callCount = new Counter();
var clientStandalone = new Test.TestInterface.Client(new RpcTestUtil.TestInterfaceImpl(callCount));
var clientNull = new Test.TestInterface.Client();
var ownServer1 = new RpcTestUtil.TestInterfaceImpl(callCount);
var server1 = ownServer1;
var client1 = set1.add(Test.TestInterface.factory, ownServer1);
var ownServer2 = new RpcTestUtil.TestInterfaceImpl(callCount);
var server2 = ownServer2;
var client2 = set2.add(Test.TestInterface.factory, ownServer2);
// Getting the local server using the correct set works.
Assert.assertEquals(server1, set1.getLocalServer(client1).join());
Assert.assertEquals(server2, set2.getLocalServer(client2).join());
// Getting the local server using the wrong set doesn't work.
Assert.assertNull(set1.getLocalServer(client2).join());
Assert.assertNull(set2.getLocalServer(client1).join());
Assert.assertNull(set1.getLocalServer(clientStandalone).join());
Assert.assertNull(set1.getLocalServer(clientNull).join());
var promise = new CompletableFuture<Test.TestInterface.Client>();
var clientPromise = new Test.TestInterface.Client(promise);
var errorPromise = new CompletableFuture<Test.TestInterface.Client>();
var clientErrorPromise = new Test.TestInterface.Client(errorPromise);
var resolved1 = new AtomicBoolean(false);
var resolved2 = new AtomicBoolean(false);
var resolved3 = new AtomicBoolean(false);
var promise1 = set1.getLocalServer(clientPromise).thenAccept(server -> {
resolved1.set(true);
Assert.assertEquals(server1, server);
});
var promise2 = set2.getLocalServer(clientPromise).thenAccept(server -> {
resolved2.set(true);
Assert.assertNull(server);
});
var promise3 = set1.getLocalServer(clientErrorPromise).whenComplete((server, exc) -> {
resolved3.set(true);
Assert.assertNull(server);
Assert.assertNotNull(exc);
Assert.assertTrue(exc.getCause() instanceof RpcException);
});
Assert.assertFalse(resolved1.get());
Assert.assertFalse(resolved2.get());
Assert.assertFalse(resolved3.get());
promise.complete(client1);
errorPromise.completeExceptionally(RpcException.failed("foo"));
Assert.assertTrue(resolved1.get());
Assert.assertTrue(resolved2.get());
Assert.assertTrue(resolved3.get());
}
} }

View file

@ -136,7 +136,7 @@ public final class Capability {
this(other.hook); this(other.hook);
} }
public Client(Server server) { public <T extends Server> Client(T server) {
this(makeLocalClient(server)); this(makeLocalClient(server));
} }
@ -157,7 +157,7 @@ public final class Capability {
return this.hook; return this.hook;
} }
private static ClientHook makeLocalClient(Server server) { private static <T extends Server> ClientHook makeLocalClient(T server) {
return server.makeLocalClient(); return server.makeLocalClient();
} }
} }
@ -169,27 +169,27 @@ public final class Capability {
private ClientHook hook; private ClientHook hook;
ClientHook makeLocalClient() { ClientHook makeLocalClient() {
return new LocalClient(); return new LocalClient<>();
} }
ClientHook makeLocalClient(CapabilityServerSetBase capServerSet) { <T extends Server> ClientHook makeLocalClient(CapabilityServerSet<T> capServerSet) {
return new LocalClient(capServerSet); return new LocalClient<>(capServerSet);
} }
private final class LocalClient implements ClientHook { private final class LocalClient<T extends Server> implements ClientHook {
private CompletableFuture<java.lang.Void> resolveTask; private CompletableFuture<java.lang.Void> resolveTask;
private ClientHook resolved; private ClientHook resolved;
private boolean blocked = false; private boolean blocked = false;
private Throwable brokenException; private Throwable brokenException;
private final Queue<Runnable> blockedCalls = new ArrayDeque<>(); private final Queue<Runnable> blockedCalls = new ArrayDeque<>();
private final CapabilityServerSetBase capServerSet; private final CapabilityServerSet<T> capServerSet;
LocalClient() { LocalClient() {
this(null); this(null);
} }
LocalClient(CapabilityServerSetBase capServerSet) { LocalClient(CapabilityServerSet<T> capServerSet) {
Server.this.hook = this; Server.this.hook = this;
this.capServerSet = capServerSet; this.capServerSet = capServerSet;
var resolveTask = shortenPath(); var resolveTask = shortenPath();
@ -311,14 +311,17 @@ public final class Capability {
} }
} }
public CompletableFuture<Server> getLocalServer(CapabilityServerSetBase capServerSet) { public CompletableFuture<T> getLocalServer(CapabilityServerSet<T> capServerSet) {
if (this.capServerSet == capServerSet) { if (this.capServerSet == capServerSet) {
if (this.blocked) { if (this.blocked) {
var promise = new CompletableFuture<Server>(); var promise = new CompletableFuture<T>();
this.blockedCalls.add(() -> promise.complete(Server.this)); var server = (T)Server.this;
this.blockedCalls.add(() -> promise.complete(server));
return promise; return promise;
} }
return CompletableFuture.completedFuture(Server.this);
var server = (T)Server.this;
return CompletableFuture.completedFuture(server);
} }
return null; return null;
} }
@ -712,13 +715,13 @@ public final class Capability {
} }
} }
static class CapabilityServerSetBase { public static final class CapabilityServerSet<T extends Capability.Server> {
ClientHook addInternal(Server server) { ClientHook addInternal(T server) {
return server.makeLocalClient(this); return server.makeLocalClient(this);
} }
CompletableFuture<Server> getLocalServerInternal(ClientHook hook) { CompletableFuture<T> getLocalServerInternal(ClientHook hook) {
for (;;) { for (;;) {
var next = hook.getResolved(); var next = hook.getResolved();
if (next != null) { if (next != null) {
@ -728,8 +731,9 @@ public final class Capability {
break; break;
} }
} }
if (hook.getBrand() == Server.BRAND) { if (hook.getBrand() == Server.BRAND) {
var promise = ((Server.LocalClient)hook).getLocalServer(this); var promise = ((Server.LocalClient<T>)hook).getLocalServer(this);
if (promise != null) { if (promise != null) {
return promise; return promise;
} }
@ -744,12 +748,9 @@ public final class Capability {
} }
else { else {
// Cap is settled, so it definitely will never resolve to a member of this set. // Cap is settled, so it definitely will never resolve to a member of this set.
return CompletableFuture.completedFuture(null); return CompletableFuture.completedFuture(null);
} }
} }
}
public static final class CapabilityServerSet<T extends Capability.Server> extends CapabilityServerSetBase {
/** /**
* Create a new capability Client for the given Server and also add this server to the set. * Create a new capability Client for the given Server and also add this server to the set.