blob: fd0f7674dd44dbfc8757a3122d85ac0df46983c4 [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 nosql
import (
"reflect"
"testing"
"v.io/v23"
"v.io/v23/rpc"
"v.io/v23/security"
"v.io/v23/security/access"
_ "v.io/x/ref/runtime/factories/generic"
"v.io/x/ref/services/syncbase/clock"
"v.io/x/ref/services/syncbase/server/util"
"v.io/x/ref/services/syncbase/server/watchable"
"v.io/x/ref/services/syncbase/store"
"v.io/x/ref/services/syncbase/store/memstore"
"v.io/x/ref/test"
"v.io/x/ref/test/testutil"
)
type mockCall struct {
security.Call
b security.Blessings
}
func (c *mockCall) Server() rpc.Server { return nil }
func (c *mockCall) GrantedBlessings() security.Blessings { return c.b }
func (c *mockCall) Security() security.Call { return c }
func (c *mockCall) LocalBlessings() security.Blessings { return c.b }
func (c *mockCall) RemoteBlessings() security.Blessings { return c.b }
func putOp(st store.Store, key, permKey string, permVersion []byte) watchable.OpPut {
version, _ := watchable.GetVersion(nil, st, []byte(key))
return watchable.OpPut{watchable.PutOp{
Key: []byte(key),
Version: version,
PermKey: []byte(permKey),
PermVersion: permVersion,
}}
}
// TestWatchLogPerms checks that the recorded prefix permissions object
// used to grant access to Put/Delete operations is correct.
func TestWatchLogPerms(t *testing.T) {
// Prepare V23.
ctx, shutdown := test.V23Init()
defer shutdown()
ctx, _ = v23.WithPrincipal(ctx, testutil.NewPrincipal("root"))
// Mock the service, store, db, table.
vClock := clock.NewVClockWithMockServices(memstore.New(), nil, nil)
st, _ := watchable.Wrap(memstore.New(), vClock, &watchable.Options{
ManagedPrefixes: []string{util.RowPrefix, util.PermsPrefix},
})
db := &databaseReq{database: &database{name: "d", st: st}}
tb := &tableReq{name: "tb", d: db}
// Mock create the table.
perms := access.Permissions{}
for _, tag := range access.AllTypicalTags() {
perms.Add(security.BlessingPattern("root"), string(tag))
}
util.Put(ctx, st, tb.stKey(), &tableData{
Name: tb.name,
Perms: perms,
})
util.Put(ctx, st, tb.prefixPermsKey(""), perms)
util.Put(ctx, st, tb.permsIndexStart(""), "")
util.Put(ctx, st, tb.permsIndexLimit(""), "")
call := &mockCall{b: v23.GetPrincipal(ctx).BlessingStore().Default()}
var expected []watchable.Op
resumeMarker, _ := watchable.GetResumeMarker(st)
// Generate Put/Delete events.
for i := 0; i < 5; i++ {
// Set initial prefix permissions.
if err := tb.SetPrefixPermissions(ctx, call, 0, "foo", perms); err != nil {
t.Fatalf("tb.SetPrefixPermissions failed: %v", err)
}
// Put.
row := &rowReq{key: "foobar", t: tb}
if err := row.Put(ctx, call, 0, []byte("value")); err != nil {
t.Fatalf("row.Put failed: %v", err)
}
permVersion, _ := watchable.GetVersion(ctx, st, []byte(tb.prefixPermsKey("foo")))
expected = append(expected, putOp(st, row.stKey(), tb.prefixPermsKey("foo"), permVersion))
// Delete.
if err := row.Delete(ctx, call, 0); err != nil {
t.Fatalf("row.Delete failed: %v", err)
}
deleteOp := watchable.OpDelete{watchable.DeleteOp{
Key: []byte(row.stKey()),
PermKey: []byte(tb.prefixPermsKey("foo")),
PermVersion: permVersion,
}}
expected = append(expected, deleteOp)
// DeleteRange.
if err := row.Put(ctx, call, 0, []byte("value")); err != nil {
t.Fatalf("row.Put failed: %v", err)
}
if err := tb.DeleteRange(ctx, call, 0, []byte("foo"), nil); err != nil {
t.Fatalf("tb.DeleteRange failed: %v", err)
}
expected = append(expected, deleteOp)
// SetPrefixPermissions.
if err := tb.SetPrefixPermissions(ctx, call, 0, "foobaz", perms); err != nil {
t.Fatalf("tb.SetPrefixPermissions failed: %v", err)
}
expected = append(expected, putOp(st, tb.prefixPermsKey("foobaz"), tb.prefixPermsKey("foo"), permVersion))
// SetPrefixPermissions again.
permVersion, _ = watchable.GetVersion(ctx, st, []byte(tb.prefixPermsKey("foobaz")))
if err := tb.SetPrefixPermissions(ctx, call, 0, "foobaz", perms); err != nil {
t.Fatalf("tb.SetPrefixPermissions failed: %v", err)
}
expected = append(expected, putOp(st, tb.prefixPermsKey("foobaz"), tb.prefixPermsKey("foobaz"), permVersion))
// DeletePrefixPermissions.
permVersion, _ = watchable.GetVersion(ctx, st, []byte(tb.prefixPermsKey("foobaz")))
if err := tb.DeletePrefixPermissions(ctx, call, 0, "foobaz"); err != nil {
t.Fatalf("tb.DeletePrefixPermissions failed: %v", err)
}
expected = append(expected, watchable.OpDelete{watchable.DeleteOp{
Key: []byte(tb.prefixPermsKey("foobaz")),
PermKey: []byte(tb.prefixPermsKey("foobaz")),
PermVersion: permVersion,
}})
}
expectedIndex := 0
for {
var logs []*watchable.LogEntry
if logs, resumeMarker, _ = watchable.ReadBatchFromLog(st, resumeMarker); logs == nil {
break
}
for _, logRecord := range logs {
if expectedIndex < len(expected) && reflect.DeepEqual(logRecord.Op, expected[expectedIndex]) {
expectedIndex++
}
}
}
if expectedIndex != len(expected) {
t.Fatalf("only %d out of %d record were found", expectedIndex, len(expected))
}
}