blob: cee1c9e8f25a24eba4a63a78008e3758ef83733a [file] [log] [blame]
// Copyright 2015 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//
package io.v.impl.google.namespace;
import com.google.common.base.Function;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;
import com.google.common.util.concurrent.SettableFuture;
import com.google.common.util.concurrent.Uninterruptibles;
import io.v.v23.VIterable;
import junit.framework.TestCase;
import org.joda.time.Duration;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import io.v.impl.google.services.mounttable.MountTableServer;
import io.v.v23.V;
import io.v.v23.context.CancelableVContext;
import io.v.v23.context.VContext;
import io.v.v23.namespace.Namespace;
import io.v.v23.naming.Endpoint;
import io.v.v23.naming.GlobReply;
import io.v.v23.naming.MountEntry;
import io.v.v23.rpc.Callback;
import io.v.v23.rpc.ListenSpec;
import io.v.v23.rpc.Server;
import io.v.v23.rpc.ServerCall;
import io.v.v23.security.BlessingPattern;
import io.v.v23.security.VSecurity;
import io.v.v23.security.access.AccessList;
import io.v.v23.security.access.Constants;
import io.v.v23.security.access.Permissions;
import io.v.v23.services.permissions.ObjectServer;
import io.v.v23.verror.VException;
import static com.google.common.truth.Truth.assertThat;
/**
* Test the {@link NamespaceImpl} implementation.
*/
public class NamespaceTest extends TestCase {
private VContext ctx;
private VContext dummyServerCtx;
private Endpoint mountTableEndpoint;
private Endpoint dummyServerEndpoint;
@Override
protected void setUp() throws Exception {
ctx = V.init();
ctx = V.withListenSpec(ctx, V.getListenSpec(ctx).withAddress(
new ListenSpec.Address("tcp", "localhost:0")));
dummyServerCtx = V.withNewServer(ctx, "", new DummyServer(),
VSecurity.newAllowEveryoneAuthorizer());
Server dummyServer = V.getServer(dummyServerCtx);
assertThat(dummyServer).isNotNull();
assertThat(dummyServer.getStatus()).isNotNull();
assertThat(dummyServer.getStatus().getEndpoints()).isNotEmpty();
dummyServerEndpoint = dummyServer.getStatus().getEndpoints()[0];
AccessList acl = new AccessList(
ImmutableList.of(new BlessingPattern("...")), ImmutableList.<String>of());
Permissions allowAll = new Permissions(ImmutableMap.of(
Constants.READ.getValue(), acl,
Constants.WRITE.getValue(), acl,
Constants.ADMIN.getValue(), acl));
ctx = MountTableServer.withNewServer(ctx, new MountTableServer.Params()
.withPermissions(ImmutableMap.of("test", allowAll))
.withStatsPrefix("test"));
Server mtServer = V.getServer(ctx);
assertThat(mtServer).isNotNull();
assertThat(mtServer.getStatus()).isNotNull();
assertThat(mtServer.getStatus().getEndpoints()).isNotEmpty();
mountTableEndpoint = mtServer.getStatus().getEndpoints()[0];
Namespace n = V.getNamespace(ctx);
n.setRoots(ImmutableList.of(mountTableEndpoint.name()));
}
@Override
protected void tearDown() throws Exception {
Server mtServer = V.getServer(ctx);
if (mtServer != null) {
mtServer.stop();
}
Server dummyServer = V.getServer(dummyServerCtx);
if (dummyServer != null) {
dummyServer.stop();
}
}
private Iterable<String> globNames(Iterable<GlobReply> globReplies) {
return Iterables.transform(globReplies, new Function<GlobReply, String>() {
@Override
public String apply(GlobReply reply) {
if (reply instanceof GlobReply.Entry) {
return ((GlobReply.Entry) reply).getElem().getName();
} else {
return ((GlobReply.Error) reply).getElem().getError().getMessage();
}
}
});
}
public void testMountAndUnmount() throws Exception {
Namespace n = V.getNamespace(ctx);
n.mount(ctx, "test/test", dummyServerEndpoint.name(), Duration.standardDays(1));
assertThat(globNames(n.glob(ctx, "test/*"))).containsExactly("test/test");
n.unmount(ctx, "test/test", "");
assertThat(globNames(n.glob(ctx, "test/*"))).isEmpty();
}
public void testMountAndUnmountAsync() throws Exception {
Namespace n = V.getNamespace(ctx);
{
FutureCallback<Void> callback = new FutureCallback<>();
n.mount(ctx, "test/test", dummyServerEndpoint.name(), Duration.standardDays(1),
callback);
assertThat(
Uninterruptibles.getUninterruptibly(callback.getFuture(), 1, TimeUnit.SECONDS))
.isNull();
}
assertThat(globNames(n.glob(ctx, "test/*"))).containsExactly("test/test");
{
final FutureCallback<Void> callback = new FutureCallback<>();
n.unmount(ctx, "test/test", "", callback);
assertThat(
Uninterruptibles.getUninterruptibly(callback.getFuture(), 1, TimeUnit.SECONDS))
.isNull();
}
assertThat(globNames(n.glob(ctx, "test/*"))).isEmpty();
}
public void testDelete() throws Exception {
Namespace n = V.getNamespace(ctx);
n.mount(ctx, "test/test/test", dummyServerEndpoint.name(), Duration.standardDays(1));
n.mount(ctx, "test/test/test2", dummyServerEndpoint.name(), Duration.standardDays(1));
assertThat(globNames(n.glob(ctx, "test/*/*"))).containsExactly(
"test/test/test", "test/test/test2");
// Shouldn't delete anything since the dir contains children.
try {
n.delete(ctx, "test/test", false);
fail("Namespace.delete() should have failed because a directory has children");
} catch (VException e) {
// OK
}
assertThat(globNames(n.glob(ctx, "test/*/*"))).containsExactly(
"test/test/test", "test/test/test2");
n.delete(ctx, "test/test", true);
assertThat(globNames(n.glob(ctx, "test/*"))).isEmpty();
}
public void testDeleteAsync() throws Exception {
Namespace n = V.getNamespace(ctx);
n.mount(ctx, "test/test/test", dummyServerEndpoint.name(), Duration.standardDays(1));
n.mount(ctx, "test/test/test2", dummyServerEndpoint.name(), Duration.standardDays(1));
assertThat(globNames(n.glob(ctx, "test/*/*"))).containsExactly(
"test/test/test", "test/test/test2");
{
final FutureCallback<Void> callback = new FutureCallback<>();
n.delete(ctx, "test/test", false, callback);
try {
Uninterruptibles.getUninterruptibly(callback.getFuture());
fail("expected an ExecutionException whose cause is a VException");
} catch (ExecutionException e) {
assertThat(e.getCause()).isInstanceOf(VException.class);
}
}
assertThat(globNames(n.glob(ctx, "test/*/*"))).containsExactly(
"test/test/test", "test/test/test2");
{
final FutureCallback<Void> callback = new FutureCallback<>();
n.delete(ctx, "test/test", true, callback);
assertThat(Uninterruptibles.getUninterruptibly(
callback.getFuture(), 1, TimeUnit.SECONDS)).isNull();
}
assertThat(globNames(n.glob(ctx, "test/*"))).isEmpty();
}
public void testGlobAsync() throws Exception {
Namespace n = V.getNamespace(ctx);
n.mount(ctx, "test/test", dummyServerEndpoint.name(), Duration.standardDays(1));
{
final FutureCallback<VIterable<GlobReply>> callback = new FutureCallback<>();
n.glob(ctx, "test/*", callback);
List<GlobReply> reply = ImmutableList.copyOf(
Uninterruptibles.getUninterruptibly(callback.getFuture(), 1, TimeUnit.SECONDS));
assertThat(reply).hasSize(1);
assertThat(reply.get(0).getElem()).isInstanceOf(MountEntry.class);
assertThat(((MountEntry) (reply.get(0).getElem())).getName()).isEqualTo("test/test");
}
}
public void testGlobWithContextCancel() throws Exception {
Namespace n = V.getNamespace(ctx);
n.mount(ctx, "test/test", dummyServerEndpoint.name(), Duration.standardDays(1));
CancelableVContext cancelContext = ctx.withCancel();
FutureCallback<VIterable<GlobReply>> callback = new FutureCallback<>();
n.glob(cancelContext, "test/*", callback);
cancelContext.cancel();
List<GlobReply> replies = ImmutableList.copyOf(Uninterruptibles.getUninterruptibly(callback.getFuture(), 1, TimeUnit.SECONDS));
assertThat(replies).isEmpty();
}
public void testResolve() throws Exception {
Namespace n = V.getNamespace(ctx);
n.mount(ctx, "test/test", dummyServerEndpoint.name(), Duration.standardDays(1));
MountEntry entry = n.resolve(ctx, "test/test");
assertThat(entry).isNotNull();
assertThat(entry.getServers()).isNotNull();
assertThat(entry.getServers()).hasSize(1);
assertThat(entry.getServers().get(0).getServer()).isEqualTo(dummyServerEndpoint.name());
}
public void testResolveAsync() throws Exception {
Namespace n = V.getNamespace(ctx);
n.mount(ctx, "test/test", dummyServerEndpoint.name(), Duration.standardDays(1));
{
FutureCallback<MountEntry> callback = new FutureCallback<>();
n.resolve(ctx, "test/test", callback);
MountEntry entry =
Uninterruptibles.getUninterruptibly(callback.getFuture(), 1, TimeUnit.SECONDS);
assertThat(entry).isNotNull();
assertThat(entry.getServers()).isNotNull();
assertThat(entry.getServers()).hasSize(1);
assertThat(entry.getServers().get(0).getServer()).isEqualTo(dummyServerEndpoint
.name());
}
}
public void testResolveToMountTable() throws Exception {
Namespace n = V.getNamespace(ctx);
n.mount(ctx, "test/test", dummyServerEndpoint.name(), Duration.standardDays(1));
MountEntry entry = n.resolveToMountTable(ctx, "test/test");
assertThat(entry).isNotNull();
assertThat(entry.getServers()).isNotNull();
assertThat(entry.getServers()).hasSize(1);
assertThat(entry.getServers().get(0).getServer()).isEqualTo(mountTableEndpoint.name());
}
public void testResolveToMountTableAsync() throws Exception {
Namespace n = V.getNamespace(ctx);
n.mount(ctx, "test/test", dummyServerEndpoint.name(), Duration.standardDays(1));
{
FutureCallback<MountEntry> callback = new FutureCallback<>();
n.resolveToMountTable(ctx, "test/test", callback);
MountEntry entry =
Uninterruptibles.getUninterruptibly(callback.getFuture(), 1, TimeUnit.SECONDS);
assertThat(entry).isNotNull();
assertThat(entry.getServers()).isNotNull();
assertThat(entry.getServers()).hasSize(1);
assertThat(entry.getServers().get(0).getServer()).isEqualTo(mountTableEndpoint
.name());
}
}
public void testPermissionsAsync() throws Exception {
AccessList acl = new AccessList(ImmutableList.of(new BlessingPattern("...")),
ImmutableList.<String>of());
Namespace n = V.getNamespace(ctx);
n.mount(ctx, "test/test", dummyServerEndpoint.name(), Duration.standardDays(1));
{
final FutureCallback<Void> callback = new FutureCallback<>();
n.setPermissions(ctx, "test/test", new Permissions(ImmutableMap.of("1", acl)), "1",
callback);
assertThat(Uninterruptibles.getUninterruptibly(callback.getFuture(), 1,
TimeUnit.SECONDS)).isNull();
}
{
final FutureCallback<Map<String, Permissions>> callback = new FutureCallback<>();
n.getPermissions(ctx, "test/test", callback);
Map<String, Permissions> permissions =
Uninterruptibles.getUninterruptibly(callback.getFuture(), 1, TimeUnit.SECONDS);
assertThat(permissions).isNotNull();
assertThat(permissions).hasSize(1);
// TODO(sjr): figure out what is actually in this map
assertThat(permissions).containsKey("2");
}
}
private static class DummyServer implements ObjectServer {
@Override
public void setPermissions(VContext ctx, ServerCall call, Permissions permissions,
String version) throws VException {
throw new VException("Unimplemented!");
}
@Override
public GetPermissionsOut getPermissions(VContext ctx, ServerCall call) throws VException {
throw new VException("Unimplemented!");
}
}
private static class FutureCallback<T> implements Callback<T> {
private final SettableFuture<T> future = SettableFuture.create();
public Future<T> getFuture() {
return future;
}
@Override
public void onSuccess(T result) {
future.set(result);
}
@Override
public void onFailure(VException error) {
future.setException(error);
}
}
}