blob: ef71c65b65b70667e826d16cbfb0f4353b722632 [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 syncbase_test
import (
"bytes"
"fmt"
"io/ioutil"
"os"
"reflect"
"time"
"v.io/syncbase/v23/syncbase"
"v.io/syncbase/v23/syncbase/nosql"
tu "v.io/syncbase/v23/syncbase/testutil"
"v.io/v23"
_ "v.io/x/ref/runtime/factories/generic"
"v.io/x/ref/test/modules"
"v.io/x/ref/test/v23tests"
)
//go:generate v23 test generate
const (
syncbaseName = "syncbase" // Name that syncbase mounts itself at.
)
// TODO(sadovsky): All tests in this file should be updated so that the client
// carries blessing "root/client", so that access is not granted anywhere just
// because the server blessing name is a prefix of the client blessing name or
// vice versa.
func V23TestSyncbasedPutGet(t *v23tests.T) {
v23tests.RunRootMT(t, "--v23.tcp.address=127.0.0.1:0")
clientCreds, _ := t.Shell().NewChildCredentials("server/client")
serverCreds, _ := t.Shell().NewChildCredentials("server")
cleanup := tu.StartSyncbased(t, serverCreds, syncbaseName, "",
`{"Read": {"In":["root/server/client"]}, "Write": {"In":["root/server/client"]}}`)
defer cleanup()
tu.RunClient(t, clientCreds, runTestSyncbasedPutGet)
}
var runTestSyncbasedPutGet = modules.Register(func(env *modules.Env, args ...string) error {
ctx, shutdown := v23.Init()
defer shutdown()
// Create app, database and table.
a := syncbase.NewService(syncbaseName).App("a")
if err := a.Create(ctx, nil); err != nil {
return fmt.Errorf("unable to create an app: %v", err)
}
d := a.NoSQLDatabase("d", nil)
if err := d.Create(ctx, nil); err != nil {
return fmt.Errorf("unable to create a database: %v", err)
}
if err := d.CreateTable(ctx, "tb", nil); err != nil {
return fmt.Errorf("unable to create a table: %v", err)
}
tb := d.Table("tb")
// Do Put followed by Get on a row.
r := tb.Row("r")
if err := r.Put(ctx, "testkey"); err != nil {
return fmt.Errorf("r.Put() failed: %v", err)
}
var result string
if err := r.Get(ctx, &result); err != nil {
return fmt.Errorf("r.Get() failed: %v", err)
}
if got, want := result, "testkey"; got != want {
return fmt.Errorf("unexpected value: got %q, want %q", got, want)
}
return nil
}, "runTestSyncbasedPutGet")
func V23TestServiceRestart(t *v23tests.T) {
v23tests.RunRootMT(t, "--v23.tcp.address=127.0.0.1:0")
clientCreds, _ := t.Shell().NewChildCredentials("server/client")
serverCreds, _ := t.Shell().NewChildCredentials("server")
rootDir, err := ioutil.TempDir("", "syncbase_leveldb")
if err != nil {
tu.V23Fatalf(t, "can't create temp dir: %v", err)
}
perms := tu.DefaultPerms("root/server/client")
buf := new(bytes.Buffer)
perms.WriteTo(buf)
permsLiteral := buf.String()
cleanup := tu.StartSyncbased(t, serverCreds, syncbaseName, rootDir, permsLiteral)
tu.RunClient(t, clientCreds, runCreateHierarchy)
tu.RunClient(t, clientCreds, runCheckHierarchy)
cleanup()
cleanup = tu.StartSyncbased(t, serverCreds, syncbaseName, rootDir, permsLiteral)
// TODO(sadovsky): This time.Sleep() is needed so that we wait for the
// syncbased server to initialize before sending it RPCs from
// runCheckHierarchy. Without this sleep, we get errors like "Apps do not
// match: got [], want [a1 a2]". It'd be nice if tu.StartSyncbased would wait
// until the server reports that it's ready, and/or if Glob wouldn't return an
// empty result set before the server is ready. (Perhaps the latter happens
// because the mount table doesn't care that the glob receiver itself doesn't
// exist?)
time.Sleep(2 * time.Second)
tu.RunClient(t, clientCreds, runCheckHierarchy)
cleanup()
if err := os.RemoveAll(rootDir); err != nil {
tu.V23Fatalf(t, "can't remove dir %v: %v", rootDir, err)
}
}
// Creates apps, dbs, tables, and rows.
var runCreateHierarchy = modules.Register(func(env *modules.Env, args ...string) error {
ctx, shutdown := v23.Init()
defer shutdown()
s := syncbase.NewService(syncbaseName)
for _, a := range []syncbase.App{s.App("a1"), s.App("a2")} {
if err := a.Create(ctx, nil); err != nil {
return fmt.Errorf("a.Create() failed: %v", err)
}
for _, d := range []nosql.Database{a.NoSQLDatabase("d1", nil), a.NoSQLDatabase("d2", nil)} {
if err := d.Create(ctx, nil); err != nil {
return fmt.Errorf("d.Create() failed: %v", err)
}
for _, tb := range []nosql.Table{d.Table("tb1"), d.Table("tb2")} {
if err := d.CreateTable(ctx, tb.Name(), nil); err != nil {
return fmt.Errorf("d.CreateTable() failed: %v", err)
}
for _, k := range []string{"foo", "bar"} {
if err := tb.Put(ctx, k, k); err != nil {
return fmt.Errorf("tb.Put() failed: %v", err)
}
}
}
}
}
return nil
}, "runCreateHierarchy")
// Checks for the apps, dbs, tables, and rows created by runCreateHierarchy.
var runCheckHierarchy = modules.Register(func(env *modules.Env, args ...string) error {
ctx, shutdown := v23.Init()
defer shutdown()
s := syncbase.NewService(syncbaseName)
var got, want []string
var err error
if got, err = s.ListApps(ctx); err != nil {
return fmt.Errorf("s.ListApps() failed: %v", err)
}
want = []string{"a1", "a2"}
if !reflect.DeepEqual(got, want) {
return fmt.Errorf("Apps do not match: got %v, want %v", got, want)
}
for _, aName := range want {
a := s.App(aName)
if got, err = a.ListDatabases(ctx); err != nil {
return fmt.Errorf("a.ListDatabases() failed: %v", err)
}
want = []string{"d1", "d2"}
if !reflect.DeepEqual(got, want) {
return fmt.Errorf("Databases do not match: got %v, want %v", got, want)
}
for _, dName := range want {
d := a.NoSQLDatabase(dName, nil)
if got, err = d.ListTables(ctx); err != nil {
return fmt.Errorf("d.ListTables() failed: %v", err)
}
want = []string{"tb1", "tb2"}
if !reflect.DeepEqual(got, want) {
return fmt.Errorf("Tables do not match: got %v, want %v", got, want)
}
for _, tbName := range want {
tb := d.Table(tbName)
if err := tu.ScanMatches(ctx, tb, nosql.Prefix(""), []string{"bar", "foo"}, []interface{}{"bar", "foo"}); err != nil {
return err
}
}
}
}
return nil
}, "runCheckHierarchy")