blob: 8328fda561fdefd51da61073dfb9eda6db640a55 [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 vsync
// Utilities for testing sync.
import (
"fmt"
"os"
"path"
"testing"
"time"
wire "v.io/syncbase/v23/services/syncbase/nosql"
"v.io/syncbase/x/ref/services/syncbase/clock"
"v.io/syncbase/x/ref/services/syncbase/server/interfaces"
"v.io/syncbase/x/ref/services/syncbase/server/util"
"v.io/syncbase/x/ref/services/syncbase/server/watchable"
"v.io/syncbase/x/ref/services/syncbase/store"
"v.io/v23/context"
"v.io/v23/rpc"
"v.io/v23/security/access"
"v.io/v23/verror"
"v.io/x/ref/test"
)
// mockService emulates a Syncbase service that includes store and sync.
// It is used to access a mock application.
type mockService struct {
engine string
dir string
st store.Store
sync *syncService
shutdown func()
}
func (s *mockService) St() store.Store {
return s.st
}
func (s *mockService) Sync() interfaces.SyncServerMethods {
return s.sync
}
func (s *mockService) App(ctx *context.T, call rpc.ServerCall, appName string) (interfaces.App, error) {
return &mockApp{st: s.st}, nil
}
func (s *mockService) AppNames(ctx *context.T, call rpc.ServerCall) ([]string, error) {
return []string{"mockapp"}, nil
}
// mockApp emulates a Syncbase App. It is used to access a mock database.
type mockApp struct {
st store.Store
}
func (a *mockApp) NoSQLDatabase(ctx *context.T, call rpc.ServerCall, dbName string) (interfaces.Database, error) {
return &mockDatabase{st: a.st}, nil
}
func (a *mockApp) NoSQLDatabaseNames(ctx *context.T, call rpc.ServerCall) ([]string, error) {
return []string{"mockdb"}, nil
}
func (a *mockApp) CreateNoSQLDatabase(ctx *context.T, call rpc.ServerCall, dbName string, perms access.Permissions, metadata *wire.SchemaMetadata) error {
return verror.NewErrNotImplemented(ctx)
}
func (a *mockApp) DeleteNoSQLDatabase(ctx *context.T, call rpc.ServerCall, dbName string) error {
return verror.NewErrNotImplemented(ctx)
}
func (a *mockApp) SetDatabasePerms(ctx *context.T, call rpc.ServerCall, dbName string, perms access.Permissions, version string) error {
return verror.NewErrNotImplemented(ctx)
}
func (a *mockApp) Service() interfaces.Service {
return nil
}
func (a *mockApp) Name() string {
return "mockapp"
}
// mockDatabase emulates a Syncbase Database. It is used to test sync functionality.
type mockDatabase struct {
st store.Store
}
func (d *mockDatabase) St() store.Store {
return d.st
}
func (d *mockDatabase) CheckPermsInternal(ctx *context.T, call rpc.ServerCall, st store.StoreReader) error {
return verror.NewErrNotImplemented(ctx)
}
func (d *mockDatabase) SetPermsInternal(ctx *context.T, call rpc.ServerCall, perms access.Permissions, version string) error {
return verror.NewErrNotImplemented(ctx)
}
func (d *mockDatabase) Name() string {
return "mockdb"
}
func (d *mockDatabase) App() interfaces.App {
return nil
}
// createService creates a mock Syncbase service used for testing sync functionality.
func createService(t *testing.T) *mockService {
ctx, shutdown := test.V23Init()
engine := "leveldb"
opts := util.OpenOptions{CreateIfMissing: true, ErrorIfExists: false}
dir := fmt.Sprintf("%s/vsync_test_%d_%d", os.TempDir(), os.Getpid(), time.Now().UnixNano())
st, err := util.OpenStore(engine, path.Join(dir, engine), opts)
if err != nil {
t.Fatalf("cannot create store %s (%s): %v", engine, dir, err)
}
vclock := clock.NewVClock(st)
st, err = watchable.Wrap(st, vclock, &watchable.Options{
ManagedPrefixes: []string{util.RowPrefix, util.PermsPrefix},
})
s := &mockService{
st: st,
engine: engine,
dir: dir,
shutdown: shutdown,
}
if s.sync, err = New(ctx, nil, s, nil, dir); err != nil {
util.DestroyStore(engine, dir)
t.Fatalf("cannot create sync service: %v", err)
}
return s
}
// destroyService cleans up the mock Syncbase service.
func destroyService(t *testing.T, s *mockService) {
defer s.shutdown()
defer s.sync.Close()
if err := util.DestroyStore(s.engine, s.dir); err != nil {
t.Fatalf("cannot destroy store %s (%s): %v", s.engine, s.dir, err)
}
}
// makeRowKey returns the database row key for a given application key.
func makeRowKey(key string) string {
return util.JoinKeyParts(util.RowPrefix, key)
}