Database { public static native void WatchPatterns(String name, byte[] resumeMarker, List<CollectionRowPattern> patterns, WatchPatternsCallbacks callbacks) throws VError;  static native VersionedPermissions GetPermissions(String name); static native void SetPermissions(String name, VersionedPermissions permissions); static native void Create(String name, Permissions permissions); static native void Destroy(String name); static native boolean Exists(String name); static native String BeginBatch(String name, BatchOptions options); static native List<Id> ListCollections(String name, String batchHandle); static native void Commit(String name, String batchHandle); static native void Abort(String name, String batchHandle); static native byte[] GetResumeMarker(String name, String batchHandle); static native List<Id> ListSyncgroups(String name); static native void CreateSyncgroup(String name, Id syncgroupId, SyncgroupSpec spec, SyncgroupMemberInfo info); static native SyncgroupSpec JoinSyncgroup(String name, String remoteSyncbaseName, List<String> expectedSyncbaseBlessings, Id syncgroupId, SyncgroupMemberInfo info); static native void LeaveSyncgroup(String name, Id syncgroupId); static native void DestroySyncgroup(String name, Id syncgroupId); static native void EjectFromSyncgroup(String name, Id syncgroupId, String member); static native VersionedSyncgroupSpec GetSyncgroupSpec(String name, Id syncgroupId); static native void SetSyncgroupSpec(String name, Id syncgroupId, VersionedSyncgroupSpec spec); static native Map<String, SyncgroupMemberInfo> GetSyncgroupMembers(String name, Id syncgroupId); static native void WatchPatterns(String name, byte[] resumeMarker, List<CollectionRowPattern> patterns, WatchPatternsCallbacks callbacks); static native long SyncgroupInvitesNewScan(String name, SyncgroupInvitesCallbacks callbacks); static native void SyncgroupInvitesStopScan(long id);  }
@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")); 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); } }