blob: dfc5b6350c681323cb03765da70dc36c4517841d [file] [log] [blame]
// Copyright 2016 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.syncbase.internal;
import com.google.common.util.concurrent.SettableFuture;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import io.v.syncbase.core.CollectionRowPattern;
import io.v.syncbase.core.Id;
import io.v.syncbase.core.SyncgroupMemberInfo;
import io.v.syncbase.core.SyncgroupSpec;
import io.v.syncbase.core.VError;
import io.v.syncbase.core.VersionedPermissions;
import io.v.syncbase.core.VersionedSyncgroupSpec;
import io.v.syncbase.core.WatchChange;
import static io.v.syncbase.core.TestConstants.anyCollectionPermissions;
import static io.v.syncbase.core.TestConstants.anyDbPermissions;
import static io.v.syncbase.core.TestConstants.anySyncgroupPermissions;
import static java.util.Collections.singletonList;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
public class DatabaseTest {
@ClassRule
public static final TemporaryFolder folder = new TemporaryFolder();
@BeforeClass
public static void setUp() throws Exception {
System.loadLibrary("syncbase");
Service.Init(folder.newFolder().getAbsolutePath(), true, 0);
Service.Login("", "");
}
@AfterClass
public static void tearDown() throws Exception {
Service.Shutdown();
}
@Test
public void createDatabase() {
Id dbId = new Id("idp:a:angrybirds", "create_db");
String dbName = dbId.encode();
// The instance is empty so creating of a database should succeed.
try {
Database.Create(dbName, anyDbPermissions());
} catch (VError vError) {
vError.printStackTrace();
fail(vError.toString());
}
// Creating the same database should raise an exception.
boolean exceptionThrown = false;
try {
Database.Create(dbName, anyDbPermissions());
} catch (VError vError) {
assertEquals("v.io/v23/verror.Exist", vError.id);
assertNotNull(vError.message);
assertNotNull(vError.stack);
assertEquals(0, vError.actionCode);
exceptionThrown = true;
}
assertTrue(exceptionThrown);
}
@Test
public void destroyDatabase() {
Id dbId = new Id("idp:a:angrybirds", "destroy_db");
String dbName = dbId.encode();
try {
// The instance is empty so creating of a database should succeed.
Database.Create(dbName, anyDbPermissions());
Database.Destroy(dbName);
} catch (VError vError) {
vError.printStackTrace();
fail(vError.toString());
}
}
@Test
public void existsDatabase() {
Id dbId = new Id("idp:a:angrybirds", "exists_db");
String dbName = dbId.encode();
try {
// We have not created the database yet so Exists should fail.
assertFalse(Database.Exists(dbName));
// The instance is empty so creating of a database should succeed.
Database.Create(dbName, anyDbPermissions());
// Exists should succeed now.
assertTrue(Database.Exists(dbName));
} catch (VError vError) {
vError.printStackTrace();
fail(vError.toString());
}
}
@Test
public void permissions() {
Id dbId = new Id("idp:a:angrybirds", "permissions_db");
String dbName = dbId.encode();
try {
Database.Create(dbName, anyDbPermissions());
VersionedPermissions versionedPermissions1 = Database.GetPermissions(dbName);
assertNotNull(versionedPermissions1);
assertTrue(versionedPermissions1.version.length() > 0);
String json = new String(versionedPermissions1.permissions.json);
assertTrue(json.contains("Admin"));
Database.SetPermissions(dbName, versionedPermissions1);
VersionedPermissions versionedPermissions2 = Database.GetPermissions(dbName);
assertNotEquals(versionedPermissions1.version, versionedPermissions2.version);
assertEquals(json, new String(versionedPermissions2.permissions.json));
} catch (VError vError) {
vError.printStackTrace();
fail(vError.toString());
}
}
@Test
public void abortDatabase() {
Id dbId = new Id("idp:a:angrybirds", "abort_db");
String dbName = dbId.encode();
Id collectionId = new Id("...", "collection");
String collectionName = Util.NamingJoin(Arrays.asList(dbName, collectionId.encode()));
try {
Database.Create(dbName, anyDbPermissions());
String batchHandle = Database.BeginBatch(dbName, null);
Collection.Create(collectionName, batchHandle, anyCollectionPermissions());
Database.Abort(dbName, batchHandle);
batchHandle = Database.BeginBatch(dbName, null);
// This should work because we Abort the previous batch.
Collection.Create(collectionName, batchHandle, anyCollectionPermissions());
Database.Commit(dbName, batchHandle);
} catch (VError vError) {
vError.printStackTrace();
fail(vError.toString());
}
}
@Test
public void listCollections() {
Id dbId = new Id("idp:a:angrybirds", "list_db");
String dbName = dbId.encode();
try {
Database.Create(dbName, anyDbPermissions());
String batchHandle = Database.BeginBatch(dbName, null);
assertNotNull(batchHandle);
List<Id> collections = Database.ListCollections(dbName, batchHandle);
assertNotNull(collections);
assertEquals(0, collections.size());
} catch (VError vError) {
vError.printStackTrace();
fail(vError.toString());
}
}
@Test
public void getResumeMarker() {
Id dbId = new Id("idp:a:angrybirds", "get_resume_marker");
String dbName = dbId.encode();
try {
Database.Create(dbName, anyDbPermissions());
String batchHandle = Database.BeginBatch(dbName, null);
byte[] marker = Database.GetResumeMarker(dbName, batchHandle);
assertNotNull(marker);
assertTrue(marker.length > 0);
} catch (VError vError) {
vError.printStackTrace();
fail(vError.toString());
}
}
@Test
public void createSyncgroup() {
Id dbId = new Id("idp:a:angrybirds", "create_syncgroups");
String dbName = dbId.encode();
Id sgId = new Id("...", "syncgroup");
Id collectionId = new Id("...", "collection");
String collectionName = Util.NamingJoin(Arrays.asList(dbName, collectionId.encode()));
try {
Database.Create(dbName, anyDbPermissions());
String batchHandle = Database.BeginBatch(dbId.encode(), null);
Collection.Create(collectionName, batchHandle, anyCollectionPermissions());
Database.Commit(dbName, batchHandle);
SyncgroupSpec spec = new SyncgroupSpec();
spec.collections = singletonList(collectionId);
spec.permissions = anySyncgroupPermissions();
SyncgroupMemberInfo info = new SyncgroupMemberInfo();
// TODO(razvanm): Pick some meaningful values.
info.syncPriority = 1;
info.blobDevType = 2;
Database.CreateSyncgroup(dbName, sgId, spec, info);
List<Id> syncgroups = Database.ListSyncgroups(dbName);
assertEquals(1, syncgroups.size());
Id actual = syncgroups.get(0);
assertEquals(sgId.blessing, actual.blessing);
assertEquals(sgId.name, actual.name);
VersionedSyncgroupSpec verSpec = Database.GetSyncgroupSpec(dbName, sgId);
assertNotNull(verSpec.version);
assertTrue(verSpec.version.length() > 0);
assertNotNull(verSpec.syncgroupSpec);
assertEquals(1, verSpec.syncgroupSpec.collections.size());
// The trim is used to remove a new line.
assertEquals(
new String(spec.permissions.json),
new String(verSpec.syncgroupSpec.permissions.json).trim());
actual = syncgroups.get(0);
assertEquals(sgId.blessing, actual.blessing);
assertEquals(sgId.name, actual.name);
verSpec.syncgroupSpec.description = "Dummy description";
Database.SetSyncgroupSpec(dbName, sgId, verSpec);
assertEquals(verSpec.syncgroupSpec.description, Database.GetSyncgroupSpec(dbName, sgId).syncgroupSpec.description);
Map<String, SyncgroupMemberInfo> members = Database.GetSyncgroupMembers(dbName, sgId);
assertNotNull(members);
assertEquals(1, members.size());
assertTrue(members.keySet().iterator().next().length() > 0);
assertEquals(info.syncPriority, members.values().iterator().next().syncPriority);
assertEquals(info.blobDevType, members.values().iterator().next().blobDevType);
} catch (VError vError) {
vError.printStackTrace();
fail(vError.toString());
}
}
@Test
public void listSyncgroups() {
Id dbId = new Id("idp:a:angrybirds", "list_syncgroups");
String dbName = dbId.encode();
try {
Database.Create(dbName, anyDbPermissions());
List<Id> syncgroups = Database.ListSyncgroups(dbName);
assertNotNull(syncgroups);
assertEquals(0, syncgroups.size());
} catch (VError vError) {
vError.printStackTrace();
fail(vError.toString());
}
}
@Test
public void destroySyncgroup() {
Id dbId = new Id("idp:a:angrybirds", "destroy_syncgroup");
String dbName = dbId.encode();
Id sgId = new Id("idp:u:alice", "syncgroup");
// TODO(razvanm): We'll have to update this after the destroy lands.
boolean exceptionThrown = false;
try {
Database.Create(dbName, anyDbPermissions());
Database.DestroySyncgroup(dbName, sgId);
} catch (VError vError) {
assertEquals("v.io/v23/verror.NotImplemented", vError.id);
exceptionThrown = true;
}
assertTrue(exceptionThrown);
}
@Test
public void joinSyncgroup() {
Id dbId = new Id("idp:a:angrybirds", "join_syncgroup");
String dbName = dbId.encode();
Id sgId = new Id("idp:u:alice", "syncgroup");
boolean exceptionThrown = false;
try {
Database.JoinSyncgroup(
dbName, "", new ArrayList<String>(), sgId, new SyncgroupMemberInfo());
} catch (VError vError) {
assertEquals("v.io/v23/verror.NoExist", vError.id);
assertNotNull(vError.message);
assertNotNull(vError.stack);
assertEquals(0, vError.actionCode);
exceptionThrown = true;
}
assertTrue(exceptionThrown);
}
@Test
public void leaveSyncgroup() {
Id dbId = new Id("idp:a:angrybirds", "leave_syncgroups");
String dbName = dbId.encode();
Id sgId = new Id("idp:u:alice", "syncgroup");
boolean exceptionThrown = false;
try {
Database.Create(dbName, anyDbPermissions());
Database.LeaveSyncgroup(dbName, sgId);
} catch (VError vError) {
assertEquals("v.io/v23/verror.NotImplemented", vError.id);
exceptionThrown = true;
}
assertTrue(exceptionThrown);
}
@Test
public void ejectFromSyncgroup() {
Id dbId = new Id("idp:a:angrybirds", "eject_from_syncgroup");
String dbName = dbId.encode();
Id sgId = new Id("idp:u:alice", "syncgroup");
boolean exceptionThrown = false;
try {
Database.Create(dbName, anyDbPermissions());
Database.EjectFromSyncgroup(dbName, sgId, "");
} catch (VError vError) {
assertEquals("v.io/v23/verror.NotImplemented", vError.id);
exceptionThrown = true;
}
assertTrue(exceptionThrown);
}
@Test
public void watchPattersEmptyPattern() {
Id dbId = new Id("idp:a:angrybirds", "watch_patterns_empty");
String dbName = dbId.encode();
final SettableFuture<Void> done = SettableFuture.create();
try {
Database.Create(dbName, anyDbPermissions());
String batchHandle = Database.BeginBatch(dbName, null);
byte[] marker = Database.GetResumeMarker(dbName, batchHandle);
List<CollectionRowPattern> patterns = singletonList(new CollectionRowPattern());
Database.WatchPatterns(dbName, marker, patterns, new Database.WatchPatternsCallbacks() {
@Override
public void onChange(WatchChange watchChange) {
fail("Unexpected onChange: " + watchChange);
}
@Override
public void onError(VError vError) {
assertEquals("v.io/v23/verror.BadArg", vError.id);
done.set(null);
}
});
} catch (VError vError) {
vError.printStackTrace();
fail(vError.toString());
}
try {
done.get(1, TimeUnit.SECONDS);
} catch (InterruptedException | TimeoutException | ExecutionException e) {
fail("Timeout waiting for onError");
}
}
@Test
public void watchPatterns() {
Id dbId = new Id("idp:a:angrybirds", "watch_patterns");
String dbName = dbId.encode();
Id collectionId = new Id("...", "collection");
String collectionName = Util.NamingJoin(Arrays.asList(dbName, collectionId.encode()));
String keyName = Util.NamingJoin(Arrays.asList(collectionName, "key"));
// Reference: release/go/src/v.io/v23/vom/testdata/data81/vomdata.vdl
byte[] vomValue = {(byte)0x81, 0x06, 0x03, 'a', 'b', 'c'};
final SettableFuture<Void> done = SettableFuture.create();
try {
Database.Create(dbName, anyDbPermissions());
String batchHandle = Database.BeginBatch(dbName, null);
Collection.Create(collectionName, batchHandle, anyCollectionPermissions());
CollectionRowPattern pattern = new CollectionRowPattern();
pattern.collectionBlessing = collectionId.blessing;
pattern.collectionName = collectionId.name;
List<CollectionRowPattern> patterns = singletonList(pattern);
Database.WatchPatterns(dbName, new byte[]{}, patterns,
new Database.WatchPatternsCallbacks() {
@Override
public void onChange(WatchChange watchChange) {
done.set(null);
}
@Override
public void onError(VError vError) {
assertEquals("v.io/v23/verror.Unknown", vError.id);
assertEquals("context canceled", vError.message);
assertEquals(0, vError.actionCode); }
});
Database.Commit(dbName, batchHandle);
batchHandle = Database.BeginBatch(dbName, null);
Row.Put(keyName, batchHandle, vomValue);
Database.Commit(dbName, batchHandle);
} catch (VError vError) {
vError.printStackTrace();
fail(vError.toString());
}
try {
done.get(1, TimeUnit.SECONDS);
} catch (InterruptedException|ExecutionException|TimeoutException e) {
fail("Timeout waiting for onChange: " + e);
}
}
}