store: replace go errors with verrors
Though this change is not very small, it is just a couple of
rules applied across the code.
Change-Id: I88e0088bb40e5218e24fbe093b2f726342bc607a
diff --git a/services/syncbase/store/invalid_types.go b/services/syncbase/store/invalid_types.go
index 83e73e9..6353a02 100644
--- a/services/syncbase/store/invalid_types.go
+++ b/services/syncbase/store/invalid_types.go
@@ -12,12 +12,12 @@
// Close implements the store.Snapshot interface.
func (s *InvalidSnapshot) Close() error {
- return s.Error
+ return WrapError(s.Error)
}
// Get implements the store.StoreReader interface.
func (s *InvalidSnapshot) Get(key, valbuf []byte) ([]byte, error) {
- return valbuf, s.Error
+ return valbuf, WrapError(s.Error)
}
// Scan implements the store.StoreReader interface.
@@ -48,7 +48,7 @@
// Err implements the store.Stream interface.
func (s *InvalidStream) Err() error {
- return s.Error
+ return WrapError(s.Error)
}
// Cancel implements the store.Stream interface.
@@ -68,7 +68,7 @@
// Get implements the store.StoreReader interface.
func (tx *InvalidTransaction) Get(key, valbuf []byte) ([]byte, error) {
- return valbuf, tx.Error
+ return valbuf, WrapError(tx.Error)
}
// Scan implements the store.StoreReader interface.
@@ -78,20 +78,20 @@
// Put implements the store.StoreWriter interface.
func (tx *InvalidTransaction) Put(key, value []byte) error {
- return tx.Error
+ return WrapError(tx.Error)
}
// Delete implements the store.StoreWriter interface.
func (tx *InvalidTransaction) Delete(key []byte) error {
- return tx.Error
+ return WrapError(tx.Error)
}
// Commit implements the store.Transaction interface.
func (tx *InvalidTransaction) Commit() error {
- return tx.Error
+ return WrapError(tx.Error)
}
// Abort implements the store.Transaction interface.
func (tx *InvalidTransaction) Abort() error {
- return tx.Error
+ return WrapError(tx.Error)
}
diff --git a/services/syncbase/store/leveldb/db.go b/services/syncbase/store/leveldb/db.go
index 5e45bd3..a09c8f1 100644
--- a/services/syncbase/store/leveldb/db.go
+++ b/services/syncbase/store/leveldb/db.go
@@ -11,15 +11,11 @@
// #include "syncbase_leveldb.h"
import "C"
import (
- "errors"
"sync"
"unsafe"
"v.io/syncbase/x/ref/services/syncbase/store"
-)
-
-var (
- errClosedStore = errors.New("closed store")
+ "v.io/v23/verror"
)
// db is a wrapper around LevelDB that implements the store.Store interface.
@@ -70,7 +66,7 @@
d.mu.Lock()
defer d.mu.Unlock()
if d.err != nil {
- return d.err
+ return store.WrapError(d.err)
}
d.node.close()
C.leveldb_close(d.cDb)
@@ -79,7 +75,7 @@
d.readOptions = nil
C.leveldb_writeoptions_destroy(d.writeOptions)
d.writeOptions = nil
- d.err = errors.New("closed store")
+ d.err = verror.New(verror.ErrCanceled, nil, "closed store")
return nil
}
@@ -154,7 +150,7 @@
d.mu.RLock()
defer d.mu.RUnlock()
if d.err != nil {
- return valbuf, d.err
+ return valbuf, store.WrapError(d.err)
}
var cError *C.char
var valLen C.size_t
@@ -164,7 +160,7 @@
return valbuf, err
}
if val == nil {
- return valbuf, &store.ErrUnknownKey{Key: string(key)}
+ return valbuf, verror.New(store.ErrUnknownKey, nil, string(key))
}
defer C.leveldb_free(unsafe.Pointer(val))
return store.CopyBytes(valbuf, goBytes(val, valLen)), nil
diff --git a/services/syncbase/store/leveldb/snapshot.go b/services/syncbase/store/leveldb/snapshot.go
index 0d78f03..62dc77f 100644
--- a/services/syncbase/store/leveldb/snapshot.go
+++ b/services/syncbase/store/leveldb/snapshot.go
@@ -7,10 +7,10 @@
// #include "leveldb/c.h"
import "C"
import (
- "errors"
"sync"
"v.io/syncbase/x/ref/services/syncbase/store"
+ "v.io/v23/verror"
)
// snapshot is a wrapper around LevelDB snapshot that implements
@@ -49,14 +49,14 @@
s.mu.Lock()
defer s.mu.Unlock()
if s.err != nil {
- return s.err
+ return store.WrapError(s.err)
}
s.node.close()
C.leveldb_readoptions_destroy(s.cOpts)
s.cOpts = nil
C.leveldb_release_snapshot(s.d.cDb, s.cSnapshot)
s.cSnapshot = nil
- s.err = errors.New("closed snapshot")
+ s.err = verror.New(verror.ErrCanceled, nil, "closed snapshot")
return nil
}
@@ -65,7 +65,7 @@
s.mu.RLock()
defer s.mu.RUnlock()
if s.err != nil {
- return valbuf, s.err
+ return valbuf, store.WrapError(s.err)
}
return s.d.getWithOpts(key, valbuf, s.cOpts)
}
diff --git a/services/syncbase/store/leveldb/stream.go b/services/syncbase/store/leveldb/stream.go
index b528626..ec167c3 100644
--- a/services/syncbase/store/leveldb/stream.go
+++ b/services/syncbase/store/leveldb/stream.go
@@ -9,10 +9,10 @@
import "C"
import (
"bytes"
- "errors"
"sync"
"v.io/syncbase/x/ref/services/syncbase/store"
+ "v.io/v23/verror"
)
// stream is a wrapper around LevelDB iterator that implements
@@ -113,7 +113,7 @@
func (s *stream) Err() error {
s.mu.Lock()
defer s.mu.Unlock()
- return s.err
+ return store.WrapError(s.err)
}
// Cancel implements the store.Stream interface.
@@ -131,7 +131,7 @@
s.key = store.CopyBytes(nil, s.cKey())
s.value = store.CopyBytes(nil, s.cVal())
}
- s.err = errors.New("canceled stream")
+ s.err = verror.New(verror.ErrCanceled, nil, "canceled stream")
s.destroyLeveldbIter()
}
diff --git a/services/syncbase/store/leveldb/transaction.go b/services/syncbase/store/leveldb/transaction.go
index 64ea397..609e55f 100644
--- a/services/syncbase/store/leveldb/transaction.go
+++ b/services/syncbase/store/leveldb/transaction.go
@@ -7,17 +7,18 @@
// #include "leveldb/c.h"
import "C"
import (
- "errors"
"sync"
"v.io/syncbase/x/ref/services/syncbase/store"
+ "v.io/v23/verror"
)
// transaction is a wrapper around LevelDB WriteBatch that implements
// the store.Transaction interface.
type transaction struct {
- node *resourceNode
+ // mu protects the state of the transaction.
mu sync.Mutex
+ node *resourceNode
d *db
snapshot store.Snapshot
batch *C.leveldb_writebatch_t
@@ -60,7 +61,7 @@
tx.mu.Lock()
defer tx.mu.Unlock()
if tx.err != nil {
- return valbuf, tx.err
+ return valbuf, store.WrapError(tx.err)
}
return tx.snapshot.Get(key, valbuf)
}
@@ -80,7 +81,7 @@
tx.mu.Lock()
defer tx.mu.Unlock()
if tx.err != nil {
- return tx.err
+ return store.WrapError(tx.err)
}
cKey, cKeyLen := cSlice(key)
cVal, cValLen := cSlice(value)
@@ -93,7 +94,7 @@
tx.mu.Lock()
defer tx.mu.Unlock()
if tx.err != nil {
- return tx.err
+ return store.WrapError(tx.err)
}
cKey, cKeyLen := cSlice(key)
C.leveldb_writebatch_delete(tx.batch, cKey, cKeyLen)
@@ -105,17 +106,20 @@
tx.mu.Lock()
defer tx.mu.Unlock()
if tx.err != nil {
- return tx.err
+ return store.WrapError(tx.err)
}
tx.d.mu.Lock()
defer tx.d.mu.Unlock()
var cError *C.char
C.leveldb_write(tx.d.cDb, tx.cOpts, tx.batch, &cError)
if err := goError(cError); err != nil {
- tx.err = errors.New("already attempted to commit transaction")
+ // Once Commit() has failed with store.ErrConcurrentTransaction, subsequent
+ // ops on the transaction will fail with the following error.
+ tx.err = verror.New(verror.ErrBadState, nil, "already attempted to commit transaction")
+ tx.close()
return err
}
- tx.err = errors.New("committed transaction")
+ tx.err = verror.New(verror.ErrBadState, nil, "committed transaction")
tx.close()
return nil
}
@@ -124,10 +128,10 @@
func (tx *transaction) Abort() error {
tx.mu.Lock()
defer tx.mu.Unlock()
- if tx.batch == nil {
- return tx.err
+ if tx.err != nil {
+ return store.WrapError(tx.err)
}
- tx.err = errors.New("aborted transaction")
+ tx.err = verror.New(verror.ErrCanceled, nil, "aborted transaction")
tx.close()
return nil
}
diff --git a/services/syncbase/store/leveldb/util.go b/services/syncbase/store/leveldb/util.go
index af08336..dce69bb 100644
--- a/services/syncbase/store/leveldb/util.go
+++ b/services/syncbase/store/leveldb/util.go
@@ -7,9 +7,10 @@
// #include "leveldb/c.h"
import "C"
import (
- "errors"
"reflect"
"unsafe"
+
+ "v.io/v23/verror"
)
// goError copies C error into Go heap and frees C buffer.
@@ -17,7 +18,7 @@
if cError == nil {
return nil
}
- err := errors.New(C.GoString(cError))
+ err := verror.New(verror.ErrInternal, nil, C.GoString(cError))
C.leveldb_free(unsafe.Pointer(cError))
return err
}
diff --git a/services/syncbase/store/memstore/snapshot.go b/services/syncbase/store/memstore/snapshot.go
index c7c016f..a080032 100644
--- a/services/syncbase/store/memstore/snapshot.go
+++ b/services/syncbase/store/memstore/snapshot.go
@@ -5,14 +5,10 @@
package memstore
import (
- "errors"
"sync"
"v.io/syncbase/x/ref/services/syncbase/store"
-)
-
-var (
- errClosedSnapshot = errors.New("closed snapshot")
+ "v.io/v23/verror"
)
type snapshot struct {
@@ -32,18 +28,14 @@
return &snapshot{data: dataCopy}
}
-func (s *snapshot) error() error {
- return s.err
-}
-
// Close implements the store.Snapshot interface.
func (s *snapshot) Close() error {
s.mu.Lock()
defer s.mu.Unlock()
- if err := s.error(); err != nil {
- return err
+ if s.err != nil {
+ return store.WrapError(s.err)
}
- s.err = errClosedSnapshot
+ s.err = verror.New(verror.ErrCanceled, nil, "closed snapshot")
return nil
}
@@ -51,12 +43,12 @@
func (s *snapshot) Get(key, valbuf []byte) ([]byte, error) {
s.mu.Lock()
defer s.mu.Unlock()
- if err := s.error(); err != nil {
- return valbuf, err
+ if s.err != nil {
+ return valbuf, store.WrapError(s.err)
}
value, ok := s.data[string(key)]
if !ok {
- return valbuf, &store.ErrUnknownKey{Key: string(key)}
+ return valbuf, verror.New(store.ErrUnknownKey, nil, string(key))
}
return store.CopyBytes(valbuf, value), nil
}
@@ -65,8 +57,8 @@
func (s *snapshot) Scan(start, limit []byte) store.Stream {
s.mu.Lock()
defer s.mu.Unlock()
- if err := s.error(); err != nil {
- return &store.InvalidStream{err}
+ if s.err != nil {
+ return &store.InvalidStream{s.err}
}
return newStream(s, start, limit)
}
diff --git a/services/syncbase/store/memstore/store.go b/services/syncbase/store/memstore/store.go
index 4aa7a6e..a6b5aee 100644
--- a/services/syncbase/store/memstore/store.go
+++ b/services/syncbase/store/memstore/store.go
@@ -10,11 +10,13 @@
"sync"
"v.io/syncbase/x/ref/services/syncbase/store"
+ "v.io/v23/verror"
)
type memstore struct {
mu sync.Mutex
data map[string][]byte
+ err error
// Most recent sequence number handed out.
lastSeq uint64
// Value of lastSeq at the time of the most recent commit.
@@ -30,7 +32,12 @@
// Close implements the store.Store interface.
func (st *memstore) Close() error {
- // TODO(sadovsky): Make all subsequent method calls and stream advances fail.
+ st.mu.Lock()
+ defer st.mu.Unlock()
+ if st.err != nil {
+ return store.WrapError(st.err)
+ }
+ st.err = verror.New(verror.ErrCanceled, nil, "closed store")
return nil
}
@@ -38,9 +45,12 @@
func (st *memstore) Get(key, valbuf []byte) ([]byte, error) {
st.mu.Lock()
defer st.mu.Unlock()
+ if st.err != nil {
+ return valbuf, store.WrapError(st.err)
+ }
value, ok := st.data[string(key)]
if !ok {
- return valbuf, &store.ErrUnknownKey{Key: string(key)}
+ return valbuf, verror.New(store.ErrUnknownKey, nil, string(key))
}
return store.CopyBytes(valbuf, value), nil
}
@@ -49,6 +59,9 @@
func (st *memstore) Scan(start, limit []byte) store.Stream {
st.mu.Lock()
defer st.mu.Unlock()
+ if st.err != nil {
+ return &store.InvalidStream{st.err}
+ }
return newStream(newSnapshot(st), start, limit)
}
@@ -70,6 +83,9 @@
func (st *memstore) NewTransaction() store.Transaction {
st.mu.Lock()
defer st.mu.Unlock()
+ if st.err != nil {
+ return &store.InvalidTransaction{st.err}
+ }
st.lastSeq++
return newTransaction(st, st.lastSeq)
}
@@ -78,5 +94,8 @@
func (st *memstore) NewSnapshot() store.Snapshot {
st.mu.Lock()
defer st.mu.Unlock()
+ if st.err != nil {
+ return &store.InvalidSnapshot{st.err}
+ }
return newSnapshot(st)
}
diff --git a/services/syncbase/store/memstore/store_test.go b/services/syncbase/store/memstore/store_test.go
index 4211225..357cf20 100644
--- a/services/syncbase/store/memstore/store_test.go
+++ b/services/syncbase/store/memstore/store_test.go
@@ -24,13 +24,13 @@
runTest(t, test.RunSnapshotTest)
}
-// TODO(rogulenko): Enable this test once memstore.Close causes memstore to
-// disallow subsequent operations.
-/*
func TestStoreState(t *testing.T) {
runTest(t, test.RunStoreStateTest)
}
+// TODO(rogulenko): Enable this test once memstore.Close closes all downstream
+// resources.
+/*
func TestClose(t *testing.T) {
runTest(t, test.RunCloseTest)
}
diff --git a/services/syncbase/store/memstore/stream.go b/services/syncbase/store/memstore/stream.go
index f60e27e..09ccfe3 100644
--- a/services/syncbase/store/memstore/stream.go
+++ b/services/syncbase/store/memstore/stream.go
@@ -5,11 +5,11 @@
package memstore
import (
- "errors"
"sort"
"sync"
"v.io/syncbase/x/ref/services/syncbase/store"
+ "v.io/v23/verror"
)
type stream struct {
@@ -82,12 +82,15 @@
func (s *stream) Err() error {
s.mu.Lock()
defer s.mu.Unlock()
- return s.err
+ return store.WrapError(s.err)
}
// Cancel implements the store.Stream interface.
func (s *stream) Cancel() {
s.mu.Lock()
defer s.mu.Unlock()
- s.err = errors.New("canceled stream")
+ if s.err != nil {
+ return
+ }
+ s.err = verror.New(verror.ErrCanceled, nil, "canceled stream")
}
diff --git a/services/syncbase/store/memstore/transaction.go b/services/syncbase/store/memstore/transaction.go
index 3298ff1..ba14496 100644
--- a/services/syncbase/store/memstore/transaction.go
+++ b/services/syncbase/store/memstore/transaction.go
@@ -5,19 +5,15 @@
package memstore
import (
- "errors"
"sync"
"time"
"v.io/syncbase/x/ref/services/syncbase/store"
+ "v.io/v23/verror"
)
-var (
- txnTimeout = time.Duration(5) * time.Second
- errExpiredTxn = errors.New("expired transaction")
- errCommittedTxn = errors.New("committed transaction")
- errAbortedTxn = errors.New("aborted transaction")
- errAttemptedCommit = errors.New("already attempted to commit transaction")
+const (
+ txnTimeout = time.Duration(5) * time.Second
)
type transaction struct {
@@ -53,10 +49,10 @@
func (tx *transaction) error() error {
if tx.err != nil {
- return tx.err
+ return store.WrapError(tx.err)
}
if tx.expired() {
- return errExpiredTxn
+ return verror.New(verror.ErrBadState, nil, "expired transaction")
}
return nil
}
@@ -117,11 +113,11 @@
defer tx.st.mu.Unlock() // note, defer is last-in-first-out
if tx.seq <= tx.st.lastCommitSeq {
// Once Commit() has failed with store.ErrConcurrentTransaction, subsequent
- // ops on the transaction will fail with errAttemptedCommit.
- tx.err = errAttemptedCommit
- return &store.ErrConcurrentTransaction{}
+ // ops on the transaction will fail with the following error.
+ tx.err = verror.New(verror.ErrBadState, nil, "already attempted to commit transaction")
+ return store.NewErrConcurrentTransaction(nil)
}
- tx.err = errCommittedTxn
+ tx.err = verror.New(verror.ErrBadState, nil, "committed transaction")
for k, v := range tx.puts {
tx.st.data[k] = v
}
@@ -140,6 +136,6 @@
return err
}
tx.sn.Close()
- tx.err = errAbortedTxn
+ tx.err = verror.New(verror.ErrCanceled, nil, "aborted transaction")
return nil
}
diff --git a/services/syncbase/store/model.go b/services/syncbase/store/model.go
index f772f40..1fcdd55 100644
--- a/services/syncbase/store/model.go
+++ b/services/syncbase/store/model.go
@@ -108,7 +108,6 @@
// Err returns a non-nil error iff the stream encountered any errors. Err does
// not block.
- // TODO(rogulenko): define an error type.
Err() error
// Cancel notifies the stream provider that it can stop producing elements.
@@ -118,17 +117,3 @@
// Cancel causes Advance to subsequently return false. Cancel does not block.
Cancel()
}
-
-type ErrConcurrentTransaction struct{}
-
-func (e *ErrConcurrentTransaction) Error() string {
- return "concurrent transaction"
-}
-
-type ErrUnknownKey struct {
- Key string
-}
-
-func (err *ErrUnknownKey) Error() string {
- return "unknown key: " + err.Key
-}
diff --git a/services/syncbase/store/model.vdl b/services/syncbase/store/model.vdl
new file mode 100644
index 0000000..b8dbb79
--- /dev/null
+++ b/services/syncbase/store/model.vdl
@@ -0,0 +1,14 @@
+// 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 store
+
+error (
+ // ConcurrentTransaction means that the current transaction was not committed
+ // because its read set was invalidated by some other transaction.
+ ConcurrentTransaction() {"en":"Concurrent transaction{:_}"}
+
+ // UnknownKey means the given key does not exist in the store.
+ UnknownKey() {"en":"Unknown key{:_}"}
+)
diff --git a/services/syncbase/store/model.vdl.go b/services/syncbase/store/model.vdl.go
new file mode 100644
index 0000000..12c235c
--- /dev/null
+++ b/services/syncbase/store/model.vdl.go
@@ -0,0 +1,38 @@
+// 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.
+
+// This file was auto-generated by the vanadium vdl tool.
+// Source: model.vdl
+
+package store
+
+import (
+ // VDL system imports
+ "v.io/v23/context"
+ "v.io/v23/i18n"
+ "v.io/v23/verror"
+)
+
+var (
+ // ConcurrentTransaction means that the current transaction was not committed
+ // because its read set was invalidated by some other transaction.
+ ErrConcurrentTransaction = verror.Register("v.io/syncbase/x/ref/services/syncbase/store.ConcurrentTransaction", verror.NoRetry, "{1:}{2:} Concurrent transaction{:_}")
+ // UnknownKey means the given key does not exist in the store.
+ ErrUnknownKey = verror.Register("v.io/syncbase/x/ref/services/syncbase/store.UnknownKey", verror.NoRetry, "{1:}{2:} Unknown key{:_}")
+)
+
+func init() {
+ i18n.Cat().SetWithBase(i18n.LangID("en"), i18n.MsgID(ErrConcurrentTransaction.ID), "{1:}{2:} Concurrent transaction{:_}")
+ i18n.Cat().SetWithBase(i18n.LangID("en"), i18n.MsgID(ErrUnknownKey.ID), "{1:}{2:} Unknown key{:_}")
+}
+
+// NewErrConcurrentTransaction returns an error with the ErrConcurrentTransaction ID.
+func NewErrConcurrentTransaction(ctx *context.T) error {
+ return verror.New(ErrConcurrentTransaction, ctx)
+}
+
+// NewErrUnknownKey returns an error with the ErrUnknownKey ID.
+func NewErrUnknownKey(ctx *context.T) error {
+ return verror.New(ErrUnknownKey, ctx)
+}
diff --git a/services/syncbase/store/test/snapshot.go b/services/syncbase/store/test/snapshot.go
index 0276fd1..0c65de7 100644
--- a/services/syncbase/store/test/snapshot.go
+++ b/services/syncbase/store/test/snapshot.go
@@ -5,10 +5,10 @@
package test
import (
- "strings"
"testing"
"v.io/syncbase/x/ref/services/syncbase/store"
+ "v.io/v23/verror"
)
// RunSnapshotTest verifies store.Snapshot operations.
@@ -31,15 +31,12 @@
t.Fatalf("can't close the snapshot: %v", err)
}
expectedErr := "closed snapshot"
- if err := snapshot.Close(); !strings.Contains(err.Error(), expectedErr) {
- t.Fatalf("unexpected error: got %v, want %v", err, expectedErr)
- }
- if _, err := snapshot.Get(key1, nil); !strings.Contains(err.Error(), expectedErr) {
- t.Fatalf("unexpected error: got %v, want %v", err, expectedErr)
- }
+ verifyError(t, snapshot.Close(), expectedErr, verror.ErrCanceled.ID)
+
+ _, err := snapshot.Get(key1, nil)
+ verifyError(t, err, expectedErr, verror.ErrCanceled.ID)
+
s = snapshot.Scan([]byte("a"), []byte("z"))
verifyAdvance(t, s, nil, nil)
- if err := s.Err(); !strings.Contains(err.Error(), expectedErr) {
- t.Fatalf("unexpected error: got %v, want %v", err, expectedErr)
- }
+ verifyError(t, s.Err(), expectedErr, verror.ErrCanceled.ID)
}
diff --git a/services/syncbase/store/test/store.go b/services/syncbase/store/test/store.go
index 5ce2d9f..0a081fd 100644
--- a/services/syncbase/store/test/store.go
+++ b/services/syncbase/store/test/store.go
@@ -7,10 +7,10 @@
import (
"fmt"
"math/rand"
- "strings"
"testing"
"v.io/syncbase/x/ref/services/syncbase/store"
+ "v.io/v23/verror"
)
type operation int
@@ -184,31 +184,24 @@
t.Fatalf("can't close the store: %v", err)
}
expectedErr := "closed store"
- if err := st.Close(); !strings.Contains(err.Error(), expectedErr) {
- t.Fatalf("unexpected error: got %v, want %v", err, expectedErr)
- }
+ verifyError(t, st.Close(), expectedErr, verror.ErrCanceled.ID)
+
s = st.Scan([]byte("a"), []byte("z"))
verifyAdvance(t, s, nil, nil)
- if err := s.Err(); !strings.Contains(err.Error(), expectedErr) {
- t.Fatalf("unexpected error: got %v, want %v", err, expectedErr)
- }
+ verifyError(t, s.Err(), expectedErr, verror.ErrCanceled.ID)
+
snapshot := st.NewSnapshot()
- if _, err := snapshot.Get(key1, nil); !strings.Contains(err.Error(), expectedErr) {
- t.Fatalf("unexpected error: got %v, want %v", err, expectedErr)
- }
+ _, err := snapshot.Get(key1, nil)
+ verifyError(t, err, expectedErr, verror.ErrCanceled.ID)
+
tx := st.NewTransaction()
- if _, err := tx.Get(key1, nil); !strings.Contains(err.Error(), expectedErr) {
- t.Fatalf("unexpected error: got %v, want %v", err, expectedErr)
- }
- if _, err := st.Get(key1, nil); !strings.Contains(err.Error(), expectedErr) {
- t.Fatalf("unexpected error: got %v, want %v", err, expectedErr)
- }
- if err := st.Put(key1, value1); !strings.Contains(err.Error(), expectedErr) {
- t.Fatalf("unexpected error: got %v, want %v", err, expectedErr)
- }
- if err := st.Delete(key1); !strings.Contains(err.Error(), expectedErr) {
- t.Fatalf("unexpected error: got %v, want %v", err, expectedErr)
- }
+ _, err = tx.Get(key1, nil)
+ verifyError(t, err, expectedErr, verror.ErrCanceled.ID)
+
+ _, err = st.Get(key1, nil)
+ verifyError(t, err, expectedErr, verror.ErrCanceled.ID)
+ verifyError(t, st.Put(key1, value1), expectedErr, verror.ErrCanceled.ID)
+ verifyError(t, st.Delete(key1), expectedErr, verror.ErrCanceled.ID)
}
// RunCloseTest verifies that child objects are closed when the parent object is
@@ -235,20 +228,14 @@
st.Close()
for _, stream := range streams {
- if got, want := stream.Err().Error(), "canceled stream"; !strings.Contains(got, want) {
- t.Fatalf("unexpected error: got %v, want %v", got, want)
- }
+ verifyError(t, stream.Err(), "canceled stream", verror.ErrCanceled.ID)
}
for _, snapshot := range snapshots {
_, err := snapshot.Get(key1, nil)
- if got, want := err.Error(), "closed snapshot"; !strings.Contains(got, want) {
- t.Fatalf("unexpected error: got %v, want %v", got, want)
- }
+ verifyError(t, err, "closed snapshot", verror.ErrCanceled.ID)
}
for _, tx := range transactions {
_, err := tx.Get(key1, nil)
- if got, want := err.Error(), "aborted transaction"; !strings.Contains(got, want) {
- t.Fatalf("unexpected error: got %v, want %v", got, want)
- }
+ verifyError(t, err, "aborted transaction", verror.ErrCanceled.ID)
}
}
diff --git a/services/syncbase/store/test/stream.go b/services/syncbase/store/test/stream.go
index 4caeb7c..28e6e32 100644
--- a/services/syncbase/store/test/stream.go
+++ b/services/syncbase/store/test/stream.go
@@ -6,10 +6,10 @@
import (
"bytes"
- "strings"
"testing"
"v.io/syncbase/x/ref/services/syncbase/store"
+ "v.io/v23/verror"
)
// RunStreamTest verifies store.Stream operations.
@@ -37,7 +37,5 @@
}
}
verifyAdvance(t, s, nil, nil)
- if !strings.Contains(s.Err().Error(), "canceled stream") {
- t.Fatalf("unexpected steam error: %v", s.Err())
- }
+ verifyError(t, s.Err(), "canceled stream", verror.ErrCanceled.ID)
}
diff --git a/services/syncbase/store/test/transaction.go b/services/syncbase/store/test/transaction.go
index e078e49..70dac8f 100644
--- a/services/syncbase/store/test/transaction.go
+++ b/services/syncbase/store/test/transaction.go
@@ -8,28 +8,28 @@
"fmt"
"math/rand"
"strconv"
- "strings"
"sync"
"testing"
"v.io/syncbase/x/ref/services/syncbase/store"
+ "v.io/v23/verror"
)
// RunTransactionTest verifies operations that modify the state of a
// store.Transaction.
func RunTransactionStateTest(t *testing.T, st store.Store) {
- abortFunctions := []func(t *testing.T, tx store.Transaction) string{
- func(t *testing.T, tx store.Transaction) string {
+ abortFunctions := []func(t *testing.T, tx store.Transaction) (string, verror.ID){
+ func(t *testing.T, tx store.Transaction) (string, verror.ID) {
if err := tx.Abort(); err != nil {
- t.Fatalf("can't abort the transaction: %v", err)
+ Fatalf(t, "can't abort the transaction: %v", err)
}
- return "aborted transaction"
+ return "aborted transaction", verror.ErrCanceled.ID
},
- func(t *testing.T, tx store.Transaction) string {
+ func(t *testing.T, tx store.Transaction) (string, verror.ID) {
if err := tx.Commit(); err != nil {
- t.Fatalf("can't commit the transaction: %v", err)
+ Fatalf(t, "can't commit the transaction: %v", err)
}
- return "committed transaction"
+ return "committed transaction", verror.ErrBadState.ID
},
}
for _, fn := range abortFunctions {
@@ -46,27 +46,18 @@
verifyAdvance(t, s, nil, nil)
// Test functions after Abort.
- expectedErr := fn(t, tx)
- if err := tx.Abort(); !strings.Contains(err.Error(), expectedErr) {
- t.Fatalf("unexpected error: got %v, want %v", err, expectedErr)
- }
- if err := tx.Commit(); !strings.Contains(err.Error(), expectedErr) {
- t.Fatalf("unexpected error: got %v, want %v", err, expectedErr)
- }
+ expectedErr, expectedID := fn(t, tx)
+ verifyError(t, tx.Abort(), expectedErr, expectedID)
+ verifyError(t, tx.Commit(), expectedErr, expectedID)
+
s = tx.Scan([]byte("a"), []byte("z"))
verifyAdvance(t, s, nil, nil)
- if err := s.Err(); !strings.Contains(err.Error(), expectedErr) {
- t.Fatalf("unexpected error: got %v, want %v", err, expectedErr)
- }
- if _, err := tx.Get(key1, nil); !strings.Contains(err.Error(), expectedErr) {
- t.Fatalf("unexpected error: got %v, want %v", err, expectedErr)
- }
- if err := tx.Put(key1, value1); !strings.Contains(err.Error(), expectedErr) {
- t.Fatalf("unexpected error: got %v, want %v", err, expectedErr)
- }
- if err := tx.Delete(key1); !strings.Contains(err.Error(), expectedErr) {
- t.Fatalf("unexpected error: got %v, want %v", err, expectedErr)
- }
+ verifyError(t, s.Err(), expectedErr, expectedID)
+
+ _, err := tx.Get(key1, nil)
+ verifyError(t, err, expectedErr, expectedID)
+ verifyError(t, tx.Put(key1, value1), expectedErr, expectedID)
+ verifyError(t, tx.Delete(key1), expectedErr, expectedID)
}
}
diff --git a/services/syncbase/store/test/util.go b/services/syncbase/store/test/util.go
index 3f8ca38..296a678 100644
--- a/services/syncbase/store/test/util.go
+++ b/services/syncbase/store/test/util.go
@@ -6,11 +6,12 @@
import (
"bytes"
- "reflect"
"runtime/debug"
+ "strings"
"testing"
"v.io/syncbase/x/ref/services/syncbase/store"
+ "v.io/v23/verror"
)
// verifyGet verifies that st.Get(key) == value. If value is nil, verifies that
@@ -27,9 +28,7 @@
}
} else {
valbuf, err = st.Get(key, valbuf)
- if !reflect.DeepEqual(&store.ErrUnknownKey{Key: string(key)}, err) {
- Fatalf(t, "unexpected get error for key %q: %v", key, err)
- }
+ verifyError(t, err, string(key), store.ErrUnknownKey.ID)
valcopy := []byte("tmp")
// Verify that valbuf is not modified if the key is not found.
if !bytes.Equal(valbuf, valcopy) {
@@ -62,6 +61,15 @@
}
}
+func verifyError(t *testing.T, err error, substr string, errorID verror.ID) {
+ if got := verror.ErrorID(err); got != errorID {
+ Fatalf(t, "unexpected error ID: got %v, want %v", got, errorID)
+ }
+ if !strings.Contains(err.Error(), substr) {
+ Fatalf(t, "unexpected error: got %v, want %v", err, substr)
+ }
+}
+
func Fatalf(t *testing.T, format string, args ...interface{}) {
debug.PrintStack()
t.Fatalf(format, args...)
diff --git a/services/syncbase/store/util.go b/services/syncbase/store/util.go
index 82a8350..447c305 100644
--- a/services/syncbase/store/util.go
+++ b/services/syncbase/store/util.go
@@ -4,6 +4,10 @@
package store
+import (
+ "v.io/v23/verror"
+)
+
// TODO(sadovsky): Add retry loop.
func RunInTransaction(st Store, fn func(st StoreReadWriter) error) error {
tx := st.NewTransaction()
@@ -38,3 +42,17 @@
copy(dst, src)
return dst
}
+
+// WrapError wraps the given err with a verror. It is a no-op if the err is nil.
+// The returned error contains the current stack trace, but retains the input
+// error's IDAction pair. If the given error is not a verror, the IDAction pair
+// of the returned error will be (ErrUnknown.ID, NoRetry).
+func WrapError(err error) error {
+ if err == nil {
+ return nil
+ }
+ return verror.New(verror.IDAction{
+ verror.ErrorID(err),
+ verror.Action(err),
+ }, nil, err)
+}