Merge "ref/runtime/rpc: Implement the real constructor functinos for xserver."
diff --git a/services/syncbase/server/nosql/database.go b/services/syncbase/server/nosql/database.go
index 172eca5..1755076 100644
--- a/services/syncbase/server/nosql/database.go
+++ b/services/syncbase/server/nosql/database.go
@@ -17,8 +17,8 @@
 	"v.io/v23/rpc"
 	"v.io/v23/security/access"
 	wire "v.io/v23/services/syncbase/nosql"
-	"v.io/v23/syncbase/nosql/query_db"
-	"v.io/v23/syncbase/nosql/query_exec"
+	"v.io/v23/syncbase/nosql/query"
+	"v.io/v23/syncbase/nosql/query/exec"
 	"v.io/v23/vdl"
 	"v.io/v23/verror"
 	"v.io/v23/vom"
@@ -254,7 +254,7 @@
 	if err := d.checkSchemaVersion(ctx, schemaVersion); err != nil {
 		return err
 	}
-	impl := func(headers []string, rs ResultStream, err error) error {
+	impl := func(headers []string, rs query.ResultStream, err error) error {
 		if err != nil {
 			return err
 		}
@@ -282,9 +282,8 @@
 		sntx = d.st.NewSnapshot()
 		defer sntx.Abort()
 	}
-	// queryDb implements query_db.Database
-	// which is needed by the query package's
-	// Exec function.
+	// queryDb implements the query.Database interface, which is needed by the
+	// exec.Exec function.
 	db := &queryDb{
 		ctx:  ctx,
 		call: call,
@@ -292,7 +291,7 @@
 		sntx: sntx,
 	}
 
-	return impl(query_exec.Exec(db, q))
+	return impl(exec.Exec(db, q))
 }
 
 func (d *databaseReq) SetPermissions(ctx *context.T, call rpc.ServerCall, perms access.Permissions, version string) error {
@@ -336,36 +335,6 @@
 }
 
 ////////////////////////////////////////
-// ResultStream interface
-
-// ResultStream is an interface for iterating through results (a.k.a, rows) returned from a
-// query.  Each resulting rows are arrays of vdl objects.
-type ResultStream interface {
-	// Advance stages an element so the client can retrieve it with Result.
-	// Advance returns true iff there is a result to retrieve. The client must
-	// call Advance before calling Result. The client must call Cancel if it
-	// does not iterate through all elements (i.e. until Advance returns false).
-	// Advance may block if an element is not immediately available.
-	Advance() bool
-
-	// Result returns the row (i.e., array of vdl Values) that was staged by Advance.
-	// Result may panic if Advance returned false or was not called at all.
-	// Result does not block.
-	Result() []*vdl.Value
-
-	// Err returns a non-nil error iff the stream encountered any errors. Err does
-	// not block.
-	Err() error
-
-	// Cancel notifies the ResultStream provider that it can stop producing results.
-	// The client must call Cancel if it does not iterate through all results
-	// (i.e. until Advance returns false). Cancel is idempotent and can be called
-	// concurrently with a goroutine that is iterating via Advance/Result.
-	// Cancel causes Advance to subsequently return false. Cancel does not block.
-	Cancel()
-}
-
-////////////////////////////////////////
 // interfaces.Database methods
 
 func (d *database) St() store.Store {
@@ -408,9 +377,9 @@
 }
 
 ////////////////////////////////////////
-// query_db implementation
+// query interface implementations
 
-// Implement query_db's Database, Table and KeyValueStream interfaces.
+// queryDb implements query.Database.
 type queryDb struct {
 	ctx  *context.T
 	call wire.DatabaseExecServerCall
@@ -422,7 +391,7 @@
 	return db.ctx
 }
 
-func (db *queryDb) GetTable(name string) (query_db.Table, error) {
+func (db *queryDb) GetTable(name string) (query.Table, error) {
 	tDb := &tableDb{
 		qdb: db,
 		req: &tableReq{
@@ -437,16 +406,18 @@
 	return tDb, nil
 }
 
+// tableDb implements query.Table.
 type tableDb struct {
 	qdb *queryDb
 	req *tableReq
 }
 
-func (t *tableDb) Scan(keyRanges query_db.KeyRanges) (query_db.KeyValueStream, error) {
+func (t *tableDb) Scan(keyRanges query.KeyRanges) (query.KeyValueStream, error) {
 	streams := []store.Stream{}
 	for _, keyRange := range keyRanges {
-		// TODO(jkline): For now, acquire all of the streams at once to minimize the race condition.
-		//               Need a way to Scan multiple ranges at the same state of uncommitted changes.
+		// TODO(jkline): For now, acquire all of the streams at once to minimize the
+		// race condition. Need a way to Scan multiple ranges at the same state of
+		// uncommitted changes.
 		streams = append(streams, t.qdb.sntx.Scan(util.ScanRangeArgs(util.JoinKeyParts(util.RowPrefix, t.req.name), keyRange.Start, keyRange.Limit)))
 	}
 	return &kvs{
@@ -458,6 +429,7 @@
 	}, nil
 }
 
+// kvs implements query.KeyValueStream.
 type kvs struct {
 	t         *tableDb
 	curr      int
diff --git a/services/syncbase/server/server_test.go b/services/syncbase/server/server_test.go
index 66c1f41..7aa6560 100644
--- a/services/syncbase/server/server_test.go
+++ b/services/syncbase/server/server_test.go
@@ -11,8 +11,8 @@
 import (
 	"testing"
 
-	tu "v.io/v23/syncbase/testutil"
 	_ "v.io/x/ref/runtime/factories/generic"
+	tu "v.io/x/ref/services/syncbase/testutil"
 )
 
 ////////////////////////////////////////
diff --git a/services/syncbase/testutil/doc.go b/services/syncbase/testutil/doc.go
new file mode 100644
index 0000000..fe7013d
--- /dev/null
+++ b/services/syncbase/testutil/doc.go
@@ -0,0 +1,6 @@
+// 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 testutil defines helpers for Syncbase tests.
+package testutil
diff --git a/services/syncbase/testutil/layer.go b/services/syncbase/testutil/layer.go
new file mode 100644
index 0000000..55e49f1
--- /dev/null
+++ b/services/syncbase/testutil/layer.go
@@ -0,0 +1,447 @@
+// 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 testutil
+
+import (
+	"fmt"
+	"reflect"
+	"testing"
+
+	"v.io/v23/context"
+	"v.io/v23/security"
+	"v.io/v23/security/access"
+	"v.io/v23/syncbase"
+	"v.io/v23/syncbase/nosql"
+	"v.io/v23/syncbase/util"
+	"v.io/v23/verror"
+	"v.io/x/lib/vlog"
+	"v.io/x/ref/test/testutil"
+)
+
+// TestCreate tests that object creation works as expected.
+func TestCreate(t *testing.T, ctx *context.T, i interface{}) {
+	parent := makeLayer(i)
+	self := parent.Child("self")
+	child := self.Child("child")
+
+	// child.Create should fail since self does not exist.
+	if err := child.Create(ctx, nil); verror.ErrorID(err) != verror.ErrNoExist.ID {
+		t.Fatalf("child.Create() should have failed: %v", err)
+	}
+
+	assertExists(t, ctx, self, "self", false)
+	// TODO(ivanpi): Exists on child when parent does not exist currently fails
+	// with an error instead of returning false.
+	//assertExists(t, ctx, child, "child", false)
+
+	// Create self.
+	if err := self.Create(ctx, nil); err != nil {
+		t.Fatalf("self.Create() failed: %v", err)
+	}
+	if gotPerms, wantPerms := getPermsOrDie(t, ctx, self), DefaultPerms("root/client"); !reflect.DeepEqual(gotPerms, wantPerms) {
+		t.Errorf("Perms do not match: got %v, want %v", gotPerms, wantPerms)
+	}
+
+	assertExists(t, ctx, self, "self", true)
+	assertExists(t, ctx, child, "child", false)
+
+	// child.Create should now succeed.
+	if err := child.Create(ctx, nil); err != nil {
+		t.Fatalf("child.Create() failed: %v", err)
+	}
+
+	assertExists(t, ctx, child, "child", true)
+
+	// self.Create should fail since self already exists.
+	if err := self.Create(ctx, nil); verror.ErrorID(err) != verror.ErrExist.ID {
+		t.Fatalf("self.Create() should have failed: %v", err)
+	}
+
+	assertExists(t, ctx, self, "self", true)
+
+	// Test create with non-default perms.
+	self2 := parent.Child("self2")
+	perms := access.Permissions{}
+	perms.Add(security.BlessingPattern("root/client"), string(access.Admin))
+	if err := self2.Create(ctx, perms); err != nil {
+		t.Fatalf("self2.Create() failed: %v", err)
+	}
+	if gotPerms, wantPerms := getPermsOrDie(t, ctx, self2), perms; !reflect.DeepEqual(gotPerms, wantPerms) {
+		t.Errorf("Perms do not match: got %v, want %v", gotPerms, wantPerms)
+	}
+
+	// Even though self2 exists, Exists returns false because Read access is needed.
+	assertExists(t, ctx, self2, "self2", false)
+
+	// Test that create fails if the parent perms disallow access.
+	perms = DefaultPerms("root/client")
+	perms.Blacklist("root/client", string(access.Write))
+	if err := parent.SetPermissions(ctx, perms, ""); err != nil {
+		t.Fatalf("parent.SetPermissions() failed: %v", err)
+	}
+	self3 := parent.Child("self3")
+	if err := self3.Create(ctx, nil); verror.ErrorID(err) != verror.ErrNoAccess.ID {
+		t.Fatalf("self3.Create() should have failed: %v", err)
+	}
+
+	assertExists(t, ctx, self, "self", true)
+	assertExists(t, ctx, self3, "self3", false)
+}
+
+// TestDelete tests that object deletion works as expected.
+func TestDelete(t *testing.T, ctx *context.T, i interface{}) {
+	parent := makeLayer(i)
+	self := parent.Child("self")
+	child := self.Child("child")
+
+	// Create self.
+	if err := self.Create(ctx, nil); err != nil {
+		t.Fatalf("self.Create() failed: %v", err)
+	}
+
+	assertExists(t, ctx, self, "self", true)
+
+	// self.Create should fail, since self already exists.
+	if err := self.Create(ctx, nil); verror.ErrorID(err) != verror.ErrExist.ID {
+		t.Fatalf("self.Create() should have failed: %v", err)
+	}
+
+	assertExists(t, ctx, self, "self", true)
+
+	// By default, self perms are copied from parent, so self.Delete should
+	// succeed.
+	if err := self.Delete(ctx); err != nil {
+		t.Fatalf("self.Delete() failed: %v", err)
+	}
+
+	assertExists(t, ctx, self, "self", false)
+
+	// child.Create should fail, since self does not exist.
+	if err := child.Create(ctx, nil); verror.ErrorID(err) != verror.ErrNoExist.ID {
+		t.Fatalf("child.Create() should have failed: %v", err)
+	}
+
+	assertExists(t, ctx, self, "self", false)
+	// TODO(ivanpi): Exists on child when parent does not exist currently fails
+	// with an error instead of returning false.
+	//assertExists(t, ctx, child, "child", false)
+
+	// self.Create should succeed, since self was deleted.
+	if err := self.Create(ctx, nil); err != nil {
+		t.Fatalf("self.Create() failed: %v", err)
+	}
+
+	assertExists(t, ctx, self, "self", true)
+	assertExists(t, ctx, child, "child", false)
+
+	// Test that delete fails if the perms disallow access.
+	self2 := parent.Child("self2")
+	if err := self2.Create(ctx, nil); err != nil {
+		t.Fatalf("self2.Create() failed: %v", err)
+	}
+	perms := DefaultPerms("root/client")
+	perms.Blacklist("root/client", string(access.Write))
+	if err := self2.SetPermissions(ctx, perms, ""); err != nil {
+		t.Fatalf("self2.SetPermissions() failed: %v", err)
+	}
+	if err := self2.Delete(ctx); verror.ErrorID(err) != verror.ErrNoAccess.ID {
+		t.Fatalf("self2.Delete() should have failed: %v", err)
+	}
+
+	assertExists(t, ctx, self2, "self2", true)
+
+	// Test that delete succeeds even if the parent perms disallow access.
+	perms = DefaultPerms("root/client")
+	perms.Blacklist("root/client", string(access.Write))
+	if err := parent.SetPermissions(ctx, perms, ""); err != nil {
+		t.Fatalf("parent.SetPermissions() failed: %v", err)
+	}
+	if err := self.Delete(ctx); err != nil {
+		t.Fatalf("self.Delete() failed: %v", err)
+	}
+
+	assertExists(t, ctx, self, "self", false)
+
+	// Test that delete is idempotent.
+	if err := self.Delete(ctx); err != nil {
+		t.Fatalf("self.Delete() failed: %v", err)
+	}
+
+	assertExists(t, ctx, self, "self", false)
+}
+
+func TestListChildren(t *testing.T, ctx *context.T, i interface{}) {
+	self := makeLayer(i)
+
+	var got, want []string
+	var err error
+
+	got, err = self.ListChildren(ctx)
+	want = []string{}
+	if err != nil {
+		t.Fatalf("self.ListChildren() failed: %v", err)
+	}
+	if !reflect.DeepEqual(got, want) {
+		t.Fatalf("Lists do not match: got %v, want %v", got, want)
+	}
+
+	if err := self.Child("y").Create(ctx, nil); err != nil {
+		t.Fatalf("y.Create() failed: %v", err)
+	}
+	got, err = self.ListChildren(ctx)
+	want = []string{"y"}
+	if err != nil {
+		t.Fatalf("self.ListChildren() failed: %v", err)
+	}
+	if !reflect.DeepEqual(got, want) {
+		t.Fatalf("Lists do not match: got %v, want %v", got, want)
+	}
+
+	if err := self.Child("x").Create(ctx, nil); err != nil {
+		t.Fatalf("x.Create() failed: %v", err)
+	}
+	got, err = self.ListChildren(ctx)
+	want = []string{"x", "y"}
+	if err != nil {
+		t.Fatalf("self.ListChildren() failed: %v", err)
+	}
+	if !reflect.DeepEqual(got, want) {
+		t.Fatalf("Lists do not match: got %v, want %v", got, want)
+	}
+}
+
+// TestPerms tests that {Set,Get}Permissions work as expected.
+// TODO(sadovsky): All Vanadium {Set,Get}Permissions tests ought to share this
+// test implementation. :)
+// Mirrors v.io/groups/x/ref/services/groups/internal/server/server_test.go.
+func TestPerms(t *testing.T, ctx *context.T, ac util.AccessController) {
+	myperms := access.Permissions{}
+	myperms.Add(security.BlessingPattern("root/client"), string(access.Admin))
+	// Demonstrate that myperms differs from the current perms.
+	if reflect.DeepEqual(myperms, getPermsOrDie(t, ctx, ac)) {
+		t.Fatalf("Permissions should not match: %v", myperms)
+	}
+
+	var permsBefore, permsAfter access.Permissions
+	var versionBefore, versionAfter string
+
+	getPermsAndVersionOrDie := func() (access.Permissions, string) {
+		perms, version, err := ac.GetPermissions(ctx)
+		if err != nil {
+			// Use Fatalf rather than t.Fatalf so we get a stack trace.
+			Fatalf(t, "GetPermissions failed: %v", err)
+		}
+		return perms, version
+	}
+
+	// SetPermissions with bad version should fail.
+	permsBefore, versionBefore = getPermsAndVersionOrDie()
+	if err := ac.SetPermissions(ctx, myperms, "20"); verror.ErrorID(err) != verror.ErrBadVersion.ID {
+		t.Fatal("SetPermissions should have failed with version error")
+	}
+	// Since SetPermissions failed, perms and version should not have changed.
+	permsAfter, versionAfter = getPermsAndVersionOrDie()
+	if !reflect.DeepEqual(permsAfter, permsBefore) {
+		t.Errorf("Perms do not match: got %v, want %v", permsAfter, permsBefore)
+	}
+	if versionAfter != versionBefore {
+		t.Errorf("Versions do not match: got %v, want %v", versionAfter, versionBefore)
+	}
+
+	// SetPermissions with correct version should succeed.
+	permsBefore, versionBefore = permsAfter, versionAfter
+	if err := ac.SetPermissions(ctx, myperms, versionBefore); err != nil {
+		t.Fatalf("SetPermissions failed: %v", err)
+	}
+	// Check that perms and version actually changed.
+	permsAfter, versionAfter = getPermsAndVersionOrDie()
+	if !reflect.DeepEqual(permsAfter, myperms) {
+		t.Errorf("Perms do not match: got %v, want %v", permsAfter, myperms)
+	}
+	if versionBefore == versionAfter {
+		t.Errorf("Versions should not match: %v", versionBefore)
+	}
+
+	// SetPermissions with empty version should succeed.
+	permsBefore, versionBefore = permsAfter, versionAfter
+	myperms.Add(security.BlessingPattern("root/client"), string(access.Read))
+	if err := ac.SetPermissions(ctx, myperms, ""); err != nil {
+		t.Fatalf("SetPermissions failed: %v", err)
+	}
+	// Check that perms and version actually changed.
+	permsAfter, versionAfter = getPermsAndVersionOrDie()
+	if !reflect.DeepEqual(permsAfter, myperms) {
+		t.Errorf("Perms do not match: got %v, want %v", permsAfter, myperms)
+	}
+	if versionBefore == versionAfter {
+		t.Errorf("Versions should not match: %v", versionBefore)
+	}
+
+	// SetPermissions with unchanged perms should succeed, and version should
+	// still change.
+	permsBefore, versionBefore = permsAfter, versionAfter
+	if err := ac.SetPermissions(ctx, myperms, ""); err != nil {
+		t.Fatalf("SetPermissions failed: %v", err)
+	}
+	// Check that perms did not change and version did change.
+	permsAfter, versionAfter = getPermsAndVersionOrDie()
+	if !reflect.DeepEqual(permsAfter, permsBefore) {
+		t.Errorf("Perms do not match: got %v, want %v", permsAfter, permsBefore)
+	}
+	if versionBefore == versionAfter {
+		t.Errorf("Versions should not match: %v", versionBefore)
+	}
+
+	// Take away our access. SetPermissions and GetPermissions should fail.
+	if err := ac.SetPermissions(ctx, access.Permissions{}, ""); err != nil {
+		t.Fatalf("SetPermissions failed: %v", err)
+	}
+	if _, _, err := ac.GetPermissions(ctx); verror.ErrorID(err) != verror.ErrNoAccess.ID {
+		t.Fatal("GetPermissions should have failed with access error")
+	}
+	if err := ac.SetPermissions(ctx, myperms, ""); verror.ErrorID(err) != verror.ErrNoAccess.ID {
+		t.Fatal("SetPermissions should have failed with access error")
+	}
+}
+
+////////////////////////////////////////
+// Internal helpers
+
+const notAvailable = "not available"
+
+type layer interface {
+	util.AccessController
+	Create(ctx *context.T, perms access.Permissions) error
+	// TODO(aghassemi): Rename to Destroy and drop Destroy impls below once
+	// Table.Delete is renamed to Destroy.
+	Delete(ctx *context.T) error
+	Exists(ctx *context.T) (bool, error)
+	ListChildren(ctx *context.T) ([]string, error)
+	Child(childName string) layer
+}
+
+type service struct {
+	syncbase.Service
+}
+
+func (s *service) Create(ctx *context.T, perms access.Permissions) error {
+	panic(notAvailable)
+}
+func (s *service) Delete(ctx *context.T) error {
+	panic(notAvailable)
+}
+func (s *service) Exists(ctx *context.T) (bool, error) {
+	panic(notAvailable)
+}
+func (s *service) ListChildren(ctx *context.T) ([]string, error) {
+	return s.ListApps(ctx)
+}
+func (s *service) Child(childName string) layer {
+	return makeLayer(s.App(childName))
+}
+
+type app struct {
+	syncbase.App
+}
+
+func (a *app) ListChildren(ctx *context.T) ([]string, error) {
+	return a.ListDatabases(ctx)
+}
+func (a *app) Child(childName string) layer {
+	return makeLayer(a.NoSQLDatabase(childName, nil))
+}
+func (a *app) Delete(ctx *context.T) error {
+	return a.Destroy(ctx)
+}
+
+type database struct {
+	nosql.Database
+}
+
+func (d *database) ListChildren(ctx *context.T) ([]string, error) {
+	return d.ListTables(ctx)
+}
+func (d *database) Child(childName string) layer {
+	return &table{Table: d.Table(childName), d: d}
+}
+func (d *database) Delete(ctx *context.T) error {
+	return d.Destroy(ctx)
+}
+
+type table struct {
+	nosql.Table
+	d nosql.Database
+}
+
+func (t *table) Create(ctx *context.T, perms access.Permissions) error {
+	return t.d.CreateTable(ctx, t.Name(), perms)
+}
+func (t *table) Delete(ctx *context.T) error {
+	return t.d.DeleteTable(ctx, t.Name())
+}
+func (t *table) SetPermissions(ctx *context.T, perms access.Permissions, version string) error {
+	return t.Table.SetPermissions(ctx, nosql.Prefix(""), perms)
+}
+func (t *table) GetPermissions(ctx *context.T) (perms access.Permissions, version string, err error) {
+	permsList, err := t.Table.GetPermissions(ctx, "")
+	if len(permsList) != 1 || permsList[0].Prefix.Prefix() != "" {
+		panic(fmt.Sprintf("unexpected perms list: %v", permsList))
+	}
+	return permsList[0].Perms, "", nil
+}
+func (t *table) ListChildren(ctx *context.T) ([]string, error) {
+	panic(notAvailable)
+}
+func (t *table) Child(childName string) layer {
+	return &row{t.Row(childName)}
+}
+
+type row struct {
+	nosql.Row
+}
+
+func (r *row) Create(ctx *context.T, perms access.Permissions) error {
+	if perms != nil {
+		panic(fmt.Sprintf("bad perms: %v", perms))
+	}
+	return r.Put(ctx, true)
+}
+func (r *row) Delete(ctx *context.T) error {
+	return r.Delete(ctx)
+}
+func (r *row) SetPermissions(ctx *context.T, perms access.Permissions, version string) error {
+	panic(notAvailable)
+}
+func (r *row) GetPermissions(ctx *context.T) (perms access.Permissions, version string, err error) {
+	panic(notAvailable)
+}
+func (r *row) ListChildren(ctx *context.T) ([]string, error) {
+	panic(notAvailable)
+}
+func (r *row) Child(childName string) layer {
+	panic(notAvailable)
+}
+
+func makeLayer(i interface{}) layer {
+	switch t := i.(type) {
+	case syncbase.Service:
+		return &service{t}
+	case syncbase.App:
+		return &app{t}
+	case nosql.Database:
+		return &database{t}
+	default:
+		vlog.Fatalf("unexpected type: %T", t)
+	}
+	return nil
+}
+
+func assertExists(t *testing.T, ctx *context.T, l layer, name string, want bool) {
+	if got, err := l.Exists(ctx); err != nil {
+		t.Fatal(testutil.FormatLogLine(2, "%s.Exists() failed: %v", name, err))
+	} else if got != want {
+		t.Error(testutil.FormatLogLine(2, "%s.Exists() got %v, want %v", name, got, want))
+	}
+}
diff --git a/services/syncbase/testutil/util.go b/services/syncbase/testutil/util.go
new file mode 100644
index 0000000..658794e
--- /dev/null
+++ b/services/syncbase/testutil/util.go
@@ -0,0 +1,291 @@
+// 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 testutil
+
+import (
+	"fmt"
+	"io/ioutil"
+	"os"
+	"reflect"
+	"runtime/debug"
+	"testing"
+
+	"v.io/v23"
+	"v.io/v23/context"
+	"v.io/v23/security"
+	"v.io/v23/security/access"
+	wire "v.io/v23/services/syncbase/nosql"
+	"v.io/v23/syncbase"
+	"v.io/v23/syncbase/nosql"
+	"v.io/v23/syncbase/util"
+	"v.io/v23/vdl"
+	"v.io/v23/verror"
+	"v.io/x/lib/vlog"
+	"v.io/x/ref/lib/flags"
+	"v.io/x/ref/lib/xrpc"
+	"v.io/x/ref/services/syncbase/server"
+	tsecurity "v.io/x/ref/test/testutil"
+)
+
+func Fatal(t *testing.T, args ...interface{}) {
+	debug.PrintStack()
+	t.Fatal(args...)
+}
+
+func Fatalf(t *testing.T, format string, args ...interface{}) {
+	debug.PrintStack()
+	t.Fatalf(format, args...)
+}
+
+func CreateApp(t *testing.T, ctx *context.T, s syncbase.Service, name string) syncbase.App {
+	a := s.App(name)
+	if err := a.Create(ctx, nil); err != nil {
+		Fatalf(t, "a.Create() failed: %v", err)
+	}
+	return a
+}
+
+func CreateNoSQLDatabase(t *testing.T, ctx *context.T, a syncbase.App, name string) nosql.Database {
+	d := a.NoSQLDatabase(name, nil)
+	if err := d.Create(ctx, nil); err != nil {
+		Fatalf(t, "d.Create() failed: %v", err)
+	}
+	return d
+}
+
+func CreateTable(t *testing.T, ctx *context.T, d nosql.Database, name string) nosql.Table {
+	if err := d.CreateTable(ctx, name, nil); err != nil {
+		Fatalf(t, "d.CreateTable() failed: %v", err)
+	}
+	return d.Table(name)
+}
+
+// TODO(sadovsky): Drop the 'perms' argument. The only client that passes
+// non-nil, syncgroup_test.go, should use SetupOrDieCustom instead.
+func SetupOrDie(perms access.Permissions) (clientCtx *context.T, serverName string, cleanup func()) {
+	_, clientCtx, serverName, _, cleanup = SetupOrDieCustom("client", "server", perms)
+	return
+}
+
+func SetupOrDieCustom(clientSuffix, serverSuffix string, perms access.Permissions) (ctx, clientCtx *context.T, serverName string, rootp security.Principal, cleanup func()) {
+	// TODO(mattr): Instead of SetDefaultHostPort the arguably more correct thing
+	// would be to call v.io/x/ref/test.Init() from the test packages that import
+	// the profile.  Note you should only call that from the package that imports
+	// the profile, not from libraries like this.  Also, it would be better if
+	// v23.Init was test.V23Init().
+	flags.SetDefaultHostPort("127.0.0.1:0")
+	ctx, shutdown := v23.Init()
+
+	rootp = tsecurity.NewPrincipal("root")
+	clientCtx, serverCtx := NewCtx(ctx, rootp, clientSuffix), NewCtx(ctx, rootp, serverSuffix)
+
+	if perms == nil {
+		perms = DefaultPerms(fmt.Sprintf("%s/%s", "root", clientSuffix))
+	}
+	serverName, stopServer := newServer(serverCtx, perms)
+	cleanup = func() {
+		stopServer()
+		shutdown()
+	}
+	return
+}
+
+func DefaultPerms(patterns ...string) access.Permissions {
+	perms := access.Permissions{}
+	for _, tag := range access.AllTypicalTags() {
+		for _, pattern := range patterns {
+			perms.Add(security.BlessingPattern(pattern), string(tag))
+		}
+	}
+	return perms
+}
+
+func ScanMatches(ctx *context.T, tb nosql.Table, r nosql.RowRange, wantKeys []string, wantValues []interface{}) error {
+	if len(wantKeys) != len(wantValues) {
+		return fmt.Errorf("bad input args")
+	}
+	it := tb.Scan(ctx, r)
+	gotKeys := []string{}
+	for it.Advance() {
+		gotKey := it.Key()
+		gotKeys = append(gotKeys, gotKey)
+		i := len(gotKeys) - 1
+		if i >= len(wantKeys) {
+			continue
+		}
+		// Check key.
+		wantKey := wantKeys[i]
+		if gotKey != wantKey {
+			return fmt.Errorf("Keys do not match: got %q, want %q", gotKey, wantKey)
+		}
+		// Check value.
+		wantValue := wantValues[i]
+		gotValue := reflect.Zero(reflect.TypeOf(wantValue)).Interface()
+		if err := it.Value(&gotValue); err != nil {
+			return fmt.Errorf("it.Value() failed: %v", err)
+		}
+		if !reflect.DeepEqual(gotValue, wantValue) {
+			return fmt.Errorf("Values do not match: got %v, want %v", gotValue, wantValue)
+		}
+	}
+	if err := it.Err(); err != nil {
+		return fmt.Errorf("tb.Scan() failed: %v", err)
+	}
+	if len(gotKeys) != len(wantKeys) {
+		return fmt.Errorf("Unmatched keys: got %v, want %v", gotKeys, wantKeys)
+	}
+	return nil
+}
+
+func CheckScan(t *testing.T, ctx *context.T, tb nosql.Table, r nosql.RowRange, wantKeys []string, wantValues []interface{}) {
+	if err := ScanMatches(ctx, tb, r, wantKeys, wantValues); err != nil {
+		Fatalf(t, err.Error())
+	}
+}
+
+func CheckExec(t *testing.T, ctx *context.T, db nosql.DatabaseHandle, q string, wantHeaders []string, wantResults [][]*vdl.Value) {
+	gotHeaders, it, err := db.Exec(ctx, q)
+	if err != nil {
+		t.Errorf("query %q: got %v, want nil", q, err)
+	}
+	if !reflect.DeepEqual(gotHeaders, wantHeaders) {
+		t.Errorf("query %q: got %v, want %v", q, gotHeaders, wantHeaders)
+	}
+	gotResults := [][]*vdl.Value{}
+	for it.Advance() {
+		gotResult := it.Result()
+		gotResults = append(gotResults, gotResult)
+	}
+	if it.Err() != nil {
+		t.Errorf("query %q: got %v, want nil", q, it.Err())
+	}
+	if !reflect.DeepEqual(gotResults, wantResults) {
+		t.Errorf("query %q: got %v, want %v", q, gotResults, wantResults)
+	}
+}
+
+func CheckExecError(t *testing.T, ctx *context.T, db nosql.DatabaseHandle, q string, wantErrorID verror.ID) {
+	_, rs, err := db.Exec(ctx, q)
+	if err == nil {
+		if rs.Advance() {
+			t.Errorf("query %q: got true, want false", q)
+		}
+		err = rs.Err()
+	}
+	if verror.ErrorID(err) != wantErrorID {
+		t.Errorf("%q", verror.DebugString(err))
+		t.Errorf("query %q: got %v, want: %v", q, verror.ErrorID(err), wantErrorID)
+	}
+}
+
+// CheckWatch checks that the sequence of elements from the watch stream starts
+// with the given slice of watch changes.
+func CheckWatch(t *testing.T, wstream nosql.WatchStream, changes []nosql.WatchChange) {
+	for _, want := range changes {
+		if !wstream.Advance() {
+			Fatalf(t, "wstream.Advance() reached the end: %v", wstream.Err())
+		}
+		if got := wstream.Change(); !reflect.DeepEqual(got, want) {
+			Fatalf(t, "unexpected watch change: got %v, want %v", got, want)
+		}
+	}
+}
+
+type MockSchemaUpgrader struct {
+	CallCount int
+}
+
+func (msu *MockSchemaUpgrader) Run(db nosql.Database, oldVersion, newVersion int32) error {
+	msu.CallCount++
+	return nil
+}
+
+var _ nosql.SchemaUpgrader = (*MockSchemaUpgrader)(nil)
+
+func DefaultSchema(version int32) *nosql.Schema {
+	return &nosql.Schema{
+		Metadata: wire.SchemaMetadata{
+			Version: version,
+		},
+		Upgrader: nosql.SchemaUpgrader(&MockSchemaUpgrader{}),
+	}
+}
+
+////////////////////////////////////////
+// Internal helpers
+
+func getPermsOrDie(t *testing.T, ctx *context.T, ac util.AccessController) access.Permissions {
+	perms, _, err := ac.GetPermissions(ctx)
+	if err != nil {
+		Fatalf(t, "GetPermissions failed: %v", err)
+	}
+	return perms
+}
+
+func newServer(serverCtx *context.T, perms access.Permissions) (string, func()) {
+	if perms == nil {
+		vlog.Fatal("perms must be specified")
+	}
+	rootDir, err := ioutil.TempDir("", "syncbase")
+	if err != nil {
+		vlog.Fatal("ioutil.TempDir() failed: ", err)
+	}
+	service, err := server.NewService(serverCtx, nil, server.ServiceOptions{
+		Perms:   perms,
+		RootDir: rootDir,
+		Engine:  "leveldb",
+	})
+	if err != nil {
+		vlog.Fatal("server.NewService() failed: ", err)
+	}
+	s, err := xrpc.NewDispatchingServer(serverCtx, "", server.NewDispatcher(service))
+	if err != nil {
+		vlog.Fatal("xrpc.NewDispatchingServer() failed: ", err)
+	}
+	name := s.Status().Endpoints[0].Name()
+	return name, func() {
+		s.Stop()
+		os.RemoveAll(rootDir)
+	}
+}
+
+// Creates a new context object with blessing "root/<suffix>", configured to
+// present this blessing when acting as a server as well as when acting as a
+// client and talking to a server that presents a blessing rooted at "root".
+func NewCtx(ctx *context.T, rootp security.Principal, suffix string) *context.T {
+	// Principal for the new context.
+	p := tsecurity.NewPrincipal(suffix)
+
+	// Bless the new principal as "root/<suffix>".
+	blessings, err := rootp.Bless(p.PublicKey(), rootp.BlessingStore().Default(), suffix, security.UnconstrainedUse())
+	if err != nil {
+		vlog.Fatal("rootp.Bless() failed: ", err)
+	}
+
+	// Make it so users of the new context present their "root/<suffix>" blessing
+	// when talking to servers with blessings rooted at "root".
+	if _, err := p.BlessingStore().Set(blessings, security.BlessingPattern("root")); err != nil {
+		vlog.Fatal("p.BlessingStore().Set() failed: ", err)
+	}
+
+	// Make it so that when users of the new context act as a server, they present
+	// their "root/<suffix>" blessing.
+	if err := p.BlessingStore().SetDefault(blessings); err != nil {
+		vlog.Fatal("p.BlessingStore().SetDefault() failed: ", err)
+	}
+
+	// Have users of the prepared context treat root's public key as an authority
+	// on all blessings rooted at "root".
+	if err := p.AddToRoots(blessings); err != nil {
+		vlog.Fatal("p.AddToRoots() failed: ", err)
+	}
+
+	resCtx, err := v23.WithPrincipal(ctx, p)
+	if err != nil {
+		vlog.Fatal("v23.WithPrincipal() failed: ", err)
+	}
+
+	return resCtx
+}
diff --git a/services/syncbase/testutil/v23util.go b/services/syncbase/testutil/v23util.go
new file mode 100644
index 0000000..ef2c3f6
--- /dev/null
+++ b/services/syncbase/testutil/v23util.go
@@ -0,0 +1,76 @@
+// 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 testutil
+
+import (
+	"bytes"
+	"io/ioutil"
+	"log"
+	"os"
+	"runtime/debug"
+	"syscall"
+
+	"v.io/x/ref/test/modules"
+	"v.io/x/ref/test/v23tests"
+)
+
+// StartSyncbased starts a syncbased process, intended to be accessed from an
+// integration test (run using --v23.tests). The returned cleanup function
+// should be called once the syncbased process is no longer needed.
+func StartSyncbased(t *v23tests.T, creds *modules.CustomCredentials, name, rootDir, permsLiteral string) (cleanup func()) {
+	syncbased := t.BuildV23Pkg("v.io/x/ref/services/syncbase/syncbased")
+	// Create root dir for the store.
+	rmRootDir := false
+	if rootDir == "" {
+		var err error
+		rootDir, err = ioutil.TempDir("", "syncbase_leveldb")
+		if err != nil {
+			V23Fatalf(t, "can't create temp dir: %v", err)
+		}
+		rmRootDir = true
+	}
+	// Start syncbased.
+	invocation := syncbased.WithStartOpts(syncbased.StartOpts().WithCustomCredentials(creds)).Start(
+		"--v23.tcp.address=127.0.0.1:0",
+		"--v23.permissions.literal", permsLiteral,
+		"--name="+name,
+		"--root-dir="+rootDir)
+	return func() {
+		// TODO(sadovsky): Something's broken here. If the syncbased invocation
+		// fails (e.g. if NewService returns an error), currently it's possible for
+		// the test to fail without the crash error getting logged. This makes
+		// debugging a challenge.
+		go invocation.Kill(syscall.SIGINT)
+		stdout, stderr := bytes.NewBuffer(nil), bytes.NewBuffer(nil)
+		if err := invocation.Shutdown(stdout, stderr); err != nil {
+			log.Printf("syncbased terminated with an error: %v\nstdout: %v\nstderr: %v\n", err, stdout, stderr)
+		}
+		if rmRootDir {
+			if err := os.RemoveAll(rootDir); err != nil {
+				V23Fatalf(t, "can't remove dir %v: %v", rootDir, err)
+			}
+		}
+	}
+}
+
+// RunClient runs modules.Program and waits until it terminates.
+func RunClient(t *v23tests.T, creds *modules.CustomCredentials, program modules.Program, args ...string) {
+	client, err := t.Shell().StartWithOpts(
+		t.Shell().DefaultStartOpts().WithCustomCredentials(creds),
+		nil,
+		program, args...)
+	if err != nil {
+		V23Fatalf(t, "unable to start the client: %v", err)
+	}
+	stdout, stderr := bytes.NewBuffer(nil), bytes.NewBuffer(nil)
+	if err := client.Shutdown(stdout, stderr); err != nil {
+		V23Fatalf(t, "client failed: %v\nstdout: %v\nstderr: %v\n", err, stdout, stderr)
+	}
+}
+
+func V23Fatalf(t *v23tests.T, format string, args ...interface{}) {
+	debug.PrintStack()
+	t.Fatalf(format, args...)
+}
diff --git a/services/syncbase/vsync/sync_state_test.go b/services/syncbase/vsync/sync_state_test.go
index 01315a7..b621fdc 100644
--- a/services/syncbase/vsync/sync_state_test.go
+++ b/services/syncbase/vsync/sync_state_test.go
@@ -141,7 +141,7 @@
 //////////////////////////////
 // Helpers
 
-// TODO(hpucha): Look into using v.io/v23/syncbase/testutil.Fatalf()
+// TODO(hpucha): Look into using v.io/x/ref/services/syncbase/testutil.Fatalf()
 // for getting the stack trace. Right now cannot import the package due to a
 // cycle.