Use Go 1.5 vendoring instead of Godeps

Change made by:

- running "gvt fetch" on each of the packages mentioned in
  Godeps/Godeps.json
- `rm -rf Godeps`
- tweaking the build scripts to not mention Godeps
- tweaking the build scripts to test `./lib/...`, `./cmd/...` explicitly
  (to avoid testing vendor)
- tweaking the build scripts to not juggle GOPATH for Godeps and instead
  set GO15VENDOREXPERIMENT.

This also results in some updated packages at the same time I bet.

Building with Go 1.3 and 1.4 still *works* but won't use our vendored
dependencies - the user needs to have the actual packages in their
GOPATH then, which they'll get with a normal "go get". Building with Go
1.6+ will get our vendored dependencies by default even when not using
our build script, which is nice.

By doing this we gain some freedom in that we can pick and choose
manually what to include in vendor, as it's not based on just dependency
analysis of our own code. This is also a risk as we might pick up
dependencies we are unaware of, as the build may work locally with those
packages present in GOPATH. On the other hand the build server will
detect this as it has no packages in it's GOPATH beyond what is included
in the repo.

Recommended tool to manage dependencies is github.com/FiloSottile/gvt.
This commit is contained in:
Jakob Borg
2016-03-05 21:01:58 +01:00
parent 9259425a9a
commit 65aaa607ab
694 changed files with 65763 additions and 3541 deletions

View File

@@ -0,0 +1,222 @@
// Copyright (c) 2014, Suryandaru Triandana <syndtr@gmail.com>
// 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"
"math/rand"
. "github.com/onsi/gomega"
"github.com/syndtr/goleveldb/leveldb/errors"
"github.com/syndtr/goleveldb/leveldb/iterator"
"github.com/syndtr/goleveldb/leveldb/util"
)
type DB interface{}
type Put interface {
TestPut(key []byte, value []byte) error
}
type Delete interface {
TestDelete(key []byte) error
}
type Find interface {
TestFind(key []byte) (rkey, rvalue []byte, err error)
}
type Get interface {
TestGet(key []byte) (value []byte, err error)
}
type Has interface {
TestHas(key []byte) (ret bool, err error)
}
type NewIterator interface {
TestNewIterator(slice *util.Range) iterator.Iterator
}
type DBAct int
func (a DBAct) String() string {
switch a {
case DBNone:
return "none"
case DBPut:
return "put"
case DBOverwrite:
return "overwrite"
case DBDelete:
return "delete"
case DBDeleteNA:
return "delete_na"
}
return "unknown"
}
const (
DBNone DBAct = iota
DBPut
DBOverwrite
DBDelete
DBDeleteNA
)
type DBTesting struct {
Rand *rand.Rand
DB interface {
Get
Put
Delete
}
PostFn func(t *DBTesting)
Deleted, Present KeyValue
Act, LastAct DBAct
ActKey, LastActKey []byte
}
func (t *DBTesting) post() {
if t.PostFn != nil {
t.PostFn(t)
}
}
func (t *DBTesting) setAct(act DBAct, key []byte) {
t.LastAct, t.Act = t.Act, act
t.LastActKey, t.ActKey = t.ActKey, key
}
func (t *DBTesting) text() string {
return fmt.Sprintf("last action was <%v> %q, <%v> %q", t.LastAct, t.LastActKey, t.Act, t.ActKey)
}
func (t *DBTesting) Text() string {
return "DBTesting " + t.text()
}
func (t *DBTesting) TestPresentKV(key, value []byte) {
rvalue, err := t.DB.TestGet(key)
Expect(err).ShouldNot(HaveOccurred(), "Get on key %q, %s", key, t.text())
Expect(rvalue).Should(Equal(value), "Value for key %q, %s", key, t.text())
}
func (t *DBTesting) TestAllPresent() {
t.Present.IterateShuffled(t.Rand, func(i int, key, value []byte) {
t.TestPresentKV(key, value)
})
}
func (t *DBTesting) TestDeletedKey(key []byte) {
_, err := t.DB.TestGet(key)
Expect(err).Should(Equal(errors.ErrNotFound), "Get on deleted key %q, %s", key, t.text())
}
func (t *DBTesting) TestAllDeleted() {
t.Deleted.IterateShuffled(t.Rand, func(i int, key, value []byte) {
t.TestDeletedKey(key)
})
}
func (t *DBTesting) TestAll() {
dn := t.Deleted.Len()
pn := t.Present.Len()
ShuffledIndex(t.Rand, dn+pn, 1, func(i int) {
if i >= dn {
key, value := t.Present.Index(i - dn)
t.TestPresentKV(key, value)
} else {
t.TestDeletedKey(t.Deleted.KeyAt(i))
}
})
}
func (t *DBTesting) Put(key, value []byte) {
if new := t.Present.PutU(key, value); new {
t.setAct(DBPut, key)
} else {
t.setAct(DBOverwrite, key)
}
t.Deleted.Delete(key)
err := t.DB.TestPut(key, value)
Expect(err).ShouldNot(HaveOccurred(), t.Text())
t.TestPresentKV(key, value)
t.post()
}
func (t *DBTesting) PutRandom() bool {
if t.Deleted.Len() > 0 {
i := t.Rand.Intn(t.Deleted.Len())
key, value := t.Deleted.Index(i)
t.Put(key, value)
return true
}
return false
}
func (t *DBTesting) Delete(key []byte) {
if exist, value := t.Present.Delete(key); exist {
t.setAct(DBDelete, key)
t.Deleted.PutU(key, value)
} else {
t.setAct(DBDeleteNA, key)
}
err := t.DB.TestDelete(key)
Expect(err).ShouldNot(HaveOccurred(), t.Text())
t.TestDeletedKey(key)
t.post()
}
func (t *DBTesting) DeleteRandom() bool {
if t.Present.Len() > 0 {
i := t.Rand.Intn(t.Present.Len())
t.Delete(t.Present.KeyAt(i))
return true
}
return false
}
func (t *DBTesting) RandomAct(round int) {
for i := 0; i < round; i++ {
if t.Rand.Int()%2 == 0 {
t.PutRandom()
} else {
t.DeleteRandom()
}
}
}
func DoDBTesting(t *DBTesting) {
if t.Rand == nil {
t.Rand = NewRand()
}
t.DeleteRandom()
t.PutRandom()
t.DeleteRandom()
t.DeleteRandom()
for i := t.Deleted.Len() / 2; i >= 0; i-- {
t.PutRandom()
}
t.RandomAct((t.Deleted.Len() + t.Present.Len()) * 10)
// Additional iterator testing
if db, ok := t.DB.(NewIterator); ok {
iter := db.TestNewIterator(nil)
Expect(iter.Error()).NotTo(HaveOccurred())
it := IteratorTesting{
KeyValue: t.Present,
Iter: iter,
}
DoIteratorTesting(&it)
iter.Release()
}
}

View File

@@ -0,0 +1,21 @@
package testutil
import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)
func RunSuite(t GinkgoTestingT, name string) {
RunDefer()
SynchronizedBeforeSuite(func() []byte {
RunDefer("setup")
return nil
}, func(data []byte) {})
SynchronizedAfterSuite(func() {
RunDefer("teardown")
}, func() {})
RegisterFailHandler(Fail)
RunSpecs(t, name)
}

View File

@@ -0,0 +1,327 @@
// Copyright (c) 2014, Suryandaru Triandana <syndtr@gmail.com>
// 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"
"math/rand"
. "github.com/onsi/gomega"
"github.com/syndtr/goleveldb/leveldb/iterator"
)
type IterAct int
func (a IterAct) String() string {
switch a {
case IterNone:
return "none"
case IterFirst:
return "first"
case IterLast:
return "last"
case IterPrev:
return "prev"
case IterNext:
return "next"
case IterSeek:
return "seek"
case IterSOI:
return "soi"
case IterEOI:
return "eoi"
}
return "unknown"
}
const (
IterNone IterAct = iota
IterFirst
IterLast
IterPrev
IterNext
IterSeek
IterSOI
IterEOI
)
type IteratorTesting struct {
KeyValue
Iter iterator.Iterator
Rand *rand.Rand
PostFn func(t *IteratorTesting)
Pos int
Act, LastAct IterAct
once bool
}
func (t *IteratorTesting) init() {
if !t.once {
t.Pos = -1
t.once = true
}
}
func (t *IteratorTesting) post() {
if t.PostFn != nil {
t.PostFn(t)
}
}
func (t *IteratorTesting) setAct(act IterAct) {
t.LastAct, t.Act = t.Act, act
}
func (t *IteratorTesting) text() string {
return fmt.Sprintf("at pos %d and last action was <%v> -> <%v>", t.Pos, t.LastAct, t.Act)
}
func (t *IteratorTesting) Text() string {
return "IteratorTesting is " + t.text()
}
func (t *IteratorTesting) IsFirst() bool {
t.init()
return t.Len() > 0 && t.Pos == 0
}
func (t *IteratorTesting) IsLast() bool {
t.init()
return t.Len() > 0 && t.Pos == t.Len()-1
}
func (t *IteratorTesting) TestKV() {
t.init()
key, value := t.Index(t.Pos)
Expect(t.Iter.Key()).NotTo(BeNil())
Expect(t.Iter.Key()).Should(Equal(key), "Key is invalid, %s", t.text())
Expect(t.Iter.Value()).Should(Equal(value), "Value for key %q, %s", key, t.text())
}
func (t *IteratorTesting) First() {
t.init()
t.setAct(IterFirst)
ok := t.Iter.First()
Expect(t.Iter.Error()).ShouldNot(HaveOccurred())
if t.Len() > 0 {
t.Pos = 0
Expect(ok).Should(BeTrue(), t.Text())
t.TestKV()
} else {
t.Pos = -1
Expect(ok).ShouldNot(BeTrue(), t.Text())
}
t.post()
}
func (t *IteratorTesting) Last() {
t.init()
t.setAct(IterLast)
ok := t.Iter.Last()
Expect(t.Iter.Error()).ShouldNot(HaveOccurred())
if t.Len() > 0 {
t.Pos = t.Len() - 1
Expect(ok).Should(BeTrue(), t.Text())
t.TestKV()
} else {
t.Pos = 0
Expect(ok).ShouldNot(BeTrue(), t.Text())
}
t.post()
}
func (t *IteratorTesting) Next() {
t.init()
t.setAct(IterNext)
ok := t.Iter.Next()
Expect(t.Iter.Error()).ShouldNot(HaveOccurred())
if t.Pos < t.Len()-1 {
t.Pos++
Expect(ok).Should(BeTrue(), t.Text())
t.TestKV()
} else {
t.Pos = t.Len()
Expect(ok).ShouldNot(BeTrue(), t.Text())
}
t.post()
}
func (t *IteratorTesting) Prev() {
t.init()
t.setAct(IterPrev)
ok := t.Iter.Prev()
Expect(t.Iter.Error()).ShouldNot(HaveOccurred())
if t.Pos > 0 {
t.Pos--
Expect(ok).Should(BeTrue(), t.Text())
t.TestKV()
} else {
t.Pos = -1
Expect(ok).ShouldNot(BeTrue(), t.Text())
}
t.post()
}
func (t *IteratorTesting) Seek(i int) {
t.init()
t.setAct(IterSeek)
key, _ := t.Index(i)
oldKey, _ := t.IndexOrNil(t.Pos)
ok := t.Iter.Seek(key)
Expect(t.Iter.Error()).ShouldNot(HaveOccurred())
Expect(ok).Should(BeTrue(), fmt.Sprintf("Seek from key %q to %q, to pos %d, %s", oldKey, key, i, t.text()))
t.Pos = i
t.TestKV()
t.post()
}
func (t *IteratorTesting) SeekInexact(i int) {
t.init()
t.setAct(IterSeek)
var key0 []byte
key1, _ := t.Index(i)
if i > 0 {
key0, _ = t.Index(i - 1)
}
key := BytesSeparator(key0, key1)
oldKey, _ := t.IndexOrNil(t.Pos)
ok := t.Iter.Seek(key)
Expect(t.Iter.Error()).ShouldNot(HaveOccurred())
Expect(ok).Should(BeTrue(), fmt.Sprintf("Seek from key %q to %q (%q), to pos %d, %s", oldKey, key, key1, i, t.text()))
t.Pos = i
t.TestKV()
t.post()
}
func (t *IteratorTesting) SeekKey(key []byte) {
t.init()
t.setAct(IterSeek)
oldKey, _ := t.IndexOrNil(t.Pos)
i := t.Search(key)
ok := t.Iter.Seek(key)
Expect(t.Iter.Error()).ShouldNot(HaveOccurred())
if i < t.Len() {
key_, _ := t.Index(i)
Expect(ok).Should(BeTrue(), fmt.Sprintf("Seek from key %q to %q (%q), to pos %d, %s", oldKey, key, key_, i, t.text()))
t.Pos = i
t.TestKV()
} else {
Expect(ok).ShouldNot(BeTrue(), fmt.Sprintf("Seek from key %q to %q, %s", oldKey, key, t.text()))
}
t.Pos = i
t.post()
}
func (t *IteratorTesting) SOI() {
t.init()
t.setAct(IterSOI)
Expect(t.Pos).Should(BeNumerically("<=", 0), t.Text())
for i := 0; i < 3; i++ {
t.Prev()
}
t.post()
}
func (t *IteratorTesting) EOI() {
t.init()
t.setAct(IterEOI)
Expect(t.Pos).Should(BeNumerically(">=", t.Len()-1), t.Text())
for i := 0; i < 3; i++ {
t.Next()
}
t.post()
}
func (t *IteratorTesting) WalkPrev(fn func(t *IteratorTesting)) {
t.init()
for old := t.Pos; t.Pos > 0; old = t.Pos {
fn(t)
Expect(t.Pos).Should(BeNumerically("<", old), t.Text())
}
}
func (t *IteratorTesting) WalkNext(fn func(t *IteratorTesting)) {
t.init()
for old := t.Pos; t.Pos < t.Len()-1; old = t.Pos {
fn(t)
Expect(t.Pos).Should(BeNumerically(">", old), t.Text())
}
}
func (t *IteratorTesting) PrevAll() {
t.WalkPrev(func(t *IteratorTesting) {
t.Prev()
})
}
func (t *IteratorTesting) NextAll() {
t.WalkNext(func(t *IteratorTesting) {
t.Next()
})
}
func DoIteratorTesting(t *IteratorTesting) {
if t.Rand == nil {
t.Rand = NewRand()
}
t.SOI()
t.NextAll()
t.First()
t.SOI()
t.NextAll()
t.EOI()
t.PrevAll()
t.Last()
t.EOI()
t.PrevAll()
t.SOI()
t.NextAll()
t.PrevAll()
t.NextAll()
t.Last()
t.PrevAll()
t.First()
t.NextAll()
t.EOI()
ShuffledIndex(t.Rand, t.Len(), 1, func(i int) {
t.Seek(i)
})
ShuffledIndex(t.Rand, t.Len(), 1, func(i int) {
t.SeekInexact(i)
})
ShuffledIndex(t.Rand, t.Len(), 1, func(i int) {
t.Seek(i)
if i%2 != 0 {
t.PrevAll()
t.SOI()
} else {
t.NextAll()
t.EOI()
}
})
for _, key := range []string{"", "foo", "bar", "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"} {
t.SeekKey([]byte(key))
}
}

View File

@@ -0,0 +1,352 @@
// Copyright (c) 2014, Suryandaru Triandana <syndtr@gmail.com>
// 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"
"math/rand"
"sort"
"strings"
"github.com/syndtr/goleveldb/leveldb/util"
)
type KeyValueEntry struct {
key, value []byte
}
type KeyValue struct {
entries []KeyValueEntry
nbytes int
}
func (kv *KeyValue) Put(key, value []byte) {
if n := len(kv.entries); n > 0 && cmp.Compare(kv.entries[n-1].key, key) >= 0 {
panic(fmt.Sprintf("Put: keys are not in increasing order: %q, %q", kv.entries[n-1].key, key))
}
kv.entries = append(kv.entries, KeyValueEntry{key, value})
kv.nbytes += len(key) + len(value)
}
func (kv *KeyValue) PutString(key, value string) {
kv.Put([]byte(key), []byte(value))
}
func (kv *KeyValue) PutU(key, value []byte) bool {
if i, exist := kv.Get(key); !exist {
if i < kv.Len() {
kv.entries = append(kv.entries[:i+1], kv.entries[i:]...)
kv.entries[i] = KeyValueEntry{key, value}
} else {
kv.entries = append(kv.entries, KeyValueEntry{key, value})
}
kv.nbytes += len(key) + len(value)
return true
} else {
kv.nbytes += len(value) - len(kv.ValueAt(i))
kv.entries[i].value = value
}
return false
}
func (kv *KeyValue) PutUString(key, value string) bool {
return kv.PutU([]byte(key), []byte(value))
}
func (kv *KeyValue) Delete(key []byte) (exist bool, value []byte) {
i, exist := kv.Get(key)
if exist {
value = kv.entries[i].value
kv.DeleteIndex(i)
}
return
}
func (kv *KeyValue) DeleteIndex(i int) bool {
if i < kv.Len() {
kv.nbytes -= len(kv.KeyAt(i)) + len(kv.ValueAt(i))
kv.entries = append(kv.entries[:i], kv.entries[i+1:]...)
return true
}
return false
}
func (kv KeyValue) Len() int {
return len(kv.entries)
}
func (kv *KeyValue) Size() int {
return kv.nbytes
}
func (kv KeyValue) KeyAt(i int) []byte {
return kv.entries[i].key
}
func (kv KeyValue) ValueAt(i int) []byte {
return kv.entries[i].value
}
func (kv KeyValue) Index(i int) (key, value []byte) {
if i < 0 || i >= len(kv.entries) {
panic(fmt.Sprintf("Index #%d: out of range", i))
}
return kv.entries[i].key, kv.entries[i].value
}
func (kv KeyValue) IndexInexact(i int) (key_, key, value []byte) {
key, value = kv.Index(i)
var key0 []byte
var key1 = kv.KeyAt(i)
if i > 0 {
key0 = kv.KeyAt(i - 1)
}
key_ = BytesSeparator(key0, key1)
return
}
func (kv KeyValue) IndexOrNil(i int) (key, value []byte) {
if i >= 0 && i < len(kv.entries) {
return kv.entries[i].key, kv.entries[i].value
}
return nil, nil
}
func (kv KeyValue) IndexString(i int) (key, value string) {
key_, _value := kv.Index(i)
return string(key_), string(_value)
}
func (kv KeyValue) Search(key []byte) int {
return sort.Search(kv.Len(), func(i int) bool {
return cmp.Compare(kv.KeyAt(i), key) >= 0
})
}
func (kv KeyValue) SearchString(key string) int {
return kv.Search([]byte(key))
}
func (kv KeyValue) Get(key []byte) (i int, exist bool) {
i = kv.Search(key)
if i < kv.Len() && cmp.Compare(kv.KeyAt(i), key) == 0 {
exist = true
}
return
}
func (kv KeyValue) GetString(key string) (i int, exist bool) {
return kv.Get([]byte(key))
}
func (kv KeyValue) Iterate(fn func(i int, key, value []byte)) {
for i, x := range kv.entries {
fn(i, x.key, x.value)
}
}
func (kv KeyValue) IterateString(fn func(i int, key, value string)) {
kv.Iterate(func(i int, key, value []byte) {
fn(i, string(key), string(value))
})
}
func (kv KeyValue) IterateShuffled(rnd *rand.Rand, fn func(i int, key, value []byte)) {
ShuffledIndex(rnd, kv.Len(), 1, func(i int) {
fn(i, kv.entries[i].key, kv.entries[i].value)
})
}
func (kv KeyValue) IterateShuffledString(rnd *rand.Rand, fn func(i int, key, value string)) {
kv.IterateShuffled(rnd, func(i int, key, value []byte) {
fn(i, string(key), string(value))
})
}
func (kv KeyValue) IterateInexact(fn func(i int, key_, key, value []byte)) {
for i := range kv.entries {
key_, key, value := kv.IndexInexact(i)
fn(i, key_, key, value)
}
}
func (kv KeyValue) IterateInexactString(fn func(i int, key_, key, value string)) {
kv.IterateInexact(func(i int, key_, key, value []byte) {
fn(i, string(key_), string(key), string(value))
})
}
func (kv KeyValue) Clone() KeyValue {
return KeyValue{append([]KeyValueEntry{}, kv.entries...), kv.nbytes}
}
func (kv KeyValue) Slice(start, limit int) KeyValue {
if start < 0 || limit > kv.Len() {
panic(fmt.Sprintf("Slice %d .. %d: out of range", start, limit))
} else if limit < start {
panic(fmt.Sprintf("Slice %d .. %d: invalid range", start, limit))
}
return KeyValue{append([]KeyValueEntry{}, kv.entries[start:limit]...), kv.nbytes}
}
func (kv KeyValue) SliceKey(start, limit []byte) KeyValue {
start_ := 0
limit_ := kv.Len()
if start != nil {
start_ = kv.Search(start)
}
if limit != nil {
limit_ = kv.Search(limit)
}
return kv.Slice(start_, limit_)
}
func (kv KeyValue) SliceKeyString(start, limit string) KeyValue {
return kv.SliceKey([]byte(start), []byte(limit))
}
func (kv KeyValue) SliceRange(r *util.Range) KeyValue {
if r != nil {
return kv.SliceKey(r.Start, r.Limit)
}
return kv.Clone()
}
func (kv KeyValue) Range(start, limit int) (r util.Range) {
if kv.Len() > 0 {
if start == kv.Len() {
r.Start = BytesAfter(kv.KeyAt(start - 1))
} else {
r.Start = kv.KeyAt(start)
}
}
if limit < kv.Len() {
r.Limit = kv.KeyAt(limit)
}
return
}
func KeyValue_EmptyKey() *KeyValue {
kv := &KeyValue{}
kv.PutString("", "v")
return kv
}
func KeyValue_EmptyValue() *KeyValue {
kv := &KeyValue{}
kv.PutString("abc", "")
kv.PutString("abcd", "")
return kv
}
func KeyValue_OneKeyValue() *KeyValue {
kv := &KeyValue{}
kv.PutString("abc", "v")
return kv
}
func KeyValue_BigValue() *KeyValue {
kv := &KeyValue{}
kv.PutString("big1", strings.Repeat("1", 200000))
return kv
}
func KeyValue_SpecialKey() *KeyValue {
kv := &KeyValue{}
kv.PutString("\xff\xff", "v3")
return kv
}
func KeyValue_MultipleKeyValue() *KeyValue {
kv := &KeyValue{}
kv.PutString("a", "v")
kv.PutString("aa", "v1")
kv.PutString("aaa", "v2")
kv.PutString("aaacccccccccc", "v2")
kv.PutString("aaaccccccccccd", "v3")
kv.PutString("aaaccccccccccf", "v4")
kv.PutString("aaaccccccccccfg", "v5")
kv.PutString("ab", "v6")
kv.PutString("abc", "v7")
kv.PutString("abcd", "v8")
kv.PutString("accccccccccccccc", "v9")
kv.PutString("b", "v10")
kv.PutString("bb", "v11")
kv.PutString("bc", "v12")
kv.PutString("c", "v13")
kv.PutString("c1", "v13")
kv.PutString("czzzzzzzzzzzzzz", "v14")
kv.PutString("fffffffffffffff", "v15")
kv.PutString("g11", "v15")
kv.PutString("g111", "v15")
kv.PutString("g111\xff", "v15")
kv.PutString("zz", "v16")
kv.PutString("zzzzzzz", "v16")
kv.PutString("zzzzzzzzzzzzzzzz", "v16")
return kv
}
var keymap = []byte("012345678ABCDEFGHIJKLMNOPQRSTUVWXYabcdefghijklmnopqrstuvwxy")
func KeyValue_Generate(rnd *rand.Rand, n, minlen, maxlen, vminlen, vmaxlen int) *KeyValue {
if rnd == nil {
rnd = NewRand()
}
if maxlen < minlen {
panic("max len should >= min len")
}
rrand := func(min, max int) int {
if min == max {
return max
}
return rnd.Intn(max-min) + min
}
kv := &KeyValue{}
endC := byte(len(keymap) - 1)
gen := make([]byte, 0, maxlen)
for i := 0; i < n; i++ {
m := rrand(minlen, maxlen)
last := gen
retry:
gen = last[:m]
if k := len(last); m > k {
for j := k; j < m; j++ {
gen[j] = 0
}
} else {
for j := m - 1; j >= 0; j-- {
c := last[j]
if c == endC {
continue
}
gen[j] = c + 1
for j += 1; j < m; j++ {
gen[j] = 0
}
goto ok
}
if m < maxlen {
m++
goto retry
}
panic(fmt.Sprintf("only able to generate %d keys out of %d keys, try increasing max len", kv.Len(), n))
ok:
}
key := make([]byte, m)
for j := 0; j < m; j++ {
key[j] = keymap[gen[j]]
}
value := make([]byte, rrand(vminlen, vmaxlen))
for n := copy(value, []byte(fmt.Sprintf("v%d", i))); n < len(value); n++ {
value[n] = 'x'
}
kv.Put(key, value)
}
return kv
}

View File

@@ -0,0 +1,211 @@
// Copyright (c) 2014, Suryandaru Triandana <syndtr@gmail.com>
// 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"
"math/rand"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/syndtr/goleveldb/leveldb/errors"
"github.com/syndtr/goleveldb/leveldb/util"
)
func TestFind(db Find, kv KeyValue) {
ShuffledIndex(nil, kv.Len(), 1, func(i int) {
key_, key, value := kv.IndexInexact(i)
// Using exact key.
rkey, rvalue, err := db.TestFind(key)
Expect(err).ShouldNot(HaveOccurred(), "Error for key %q", key)
Expect(rkey).Should(Equal(key), "Key")
Expect(rvalue).Should(Equal(value), "Value for key %q", key)
// Using inexact key.
rkey, rvalue, err = db.TestFind(key_)
Expect(err).ShouldNot(HaveOccurred(), "Error for key %q (%q)", key_, key)
Expect(rkey).Should(Equal(key))
Expect(rvalue).Should(Equal(value), "Value for key %q (%q)", key_, key)
})
}
func TestFindAfterLast(db Find, kv KeyValue) {
var key []byte
if kv.Len() > 0 {
key_, _ := kv.Index(kv.Len() - 1)
key = BytesAfter(key_)
}
rkey, _, err := db.TestFind(key)
Expect(err).Should(HaveOccurred(), "Find for key %q yield key %q", key, rkey)
Expect(err).Should(Equal(errors.ErrNotFound))
}
func TestGet(db Get, kv KeyValue) {
ShuffledIndex(nil, kv.Len(), 1, func(i int) {
key_, key, value := kv.IndexInexact(i)
// Using exact key.
rvalue, err := db.TestGet(key)
Expect(err).ShouldNot(HaveOccurred(), "Error for key %q", key)
Expect(rvalue).Should(Equal(value), "Value for key %q", key)
// Using inexact key.
if len(key_) > 0 {
_, err = db.TestGet(key_)
Expect(err).Should(HaveOccurred(), "Error for key %q", key_)
Expect(err).Should(Equal(errors.ErrNotFound))
}
})
}
func TestHas(db Has, kv KeyValue) {
ShuffledIndex(nil, kv.Len(), 1, func(i int) {
key_, key, _ := kv.IndexInexact(i)
// Using exact key.
ret, err := db.TestHas(key)
Expect(err).ShouldNot(HaveOccurred(), "Error for key %q", key)
Expect(ret).Should(BeTrue(), "False for key %q", key)
// Using inexact key.
if len(key_) > 0 {
ret, err = db.TestHas(key_)
Expect(err).ShouldNot(HaveOccurred(), "Error for key %q", key_)
Expect(ret).ShouldNot(BeTrue(), "True for key %q", key)
}
})
}
func TestIter(db NewIterator, r *util.Range, kv KeyValue) {
iter := db.TestNewIterator(r)
Expect(iter.Error()).ShouldNot(HaveOccurred())
t := IteratorTesting{
KeyValue: kv,
Iter: iter,
}
DoIteratorTesting(&t)
iter.Release()
}
func KeyValueTesting(rnd *rand.Rand, kv KeyValue, p DB, setup func(KeyValue) DB, teardown func(DB)) {
if rnd == nil {
rnd = NewRand()
}
if p == nil {
BeforeEach(func() {
p = setup(kv)
})
if teardown != nil {
AfterEach(func() {
teardown(p)
})
}
}
It("Should find all keys with Find", func() {
if db, ok := p.(Find); ok {
TestFind(db, kv)
}
})
It("Should return error if Find on key after the last", func() {
if db, ok := p.(Find); ok {
TestFindAfterLast(db, kv)
}
})
It("Should only find exact key with Get", func() {
if db, ok := p.(Get); ok {
TestGet(db, kv)
}
})
It("Should only find present key with Has", func() {
if db, ok := p.(Has); ok {
TestHas(db, kv)
}
})
It("Should iterates and seeks correctly", func(done Done) {
if db, ok := p.(NewIterator); ok {
TestIter(db, nil, kv.Clone())
}
done <- true
}, 3.0)
It("Should iterates and seeks slice correctly", func(done Done) {
if db, ok := p.(NewIterator); ok {
RandomIndex(rnd, kv.Len(), Min(kv.Len(), 50), func(i int) {
type slice struct {
r *util.Range
start, limit int
}
key_, _, _ := kv.IndexInexact(i)
for _, x := range []slice{
{&util.Range{Start: key_, Limit: nil}, i, kv.Len()},
{&util.Range{Start: nil, Limit: key_}, 0, i},
} {
By(fmt.Sprintf("Random index of %d .. %d", x.start, x.limit), func() {
TestIter(db, x.r, kv.Slice(x.start, x.limit))
})
}
})
}
done <- true
}, 50.0)
It("Should iterates and seeks slice correctly", func(done Done) {
if db, ok := p.(NewIterator); ok {
RandomRange(rnd, kv.Len(), Min(kv.Len(), 50), func(start, limit int) {
By(fmt.Sprintf("Random range of %d .. %d", start, limit), func() {
r := kv.Range(start, limit)
TestIter(db, &r, kv.Slice(start, limit))
})
})
}
done <- true
}, 50.0)
}
func AllKeyValueTesting(rnd *rand.Rand, body, setup func(KeyValue) DB, teardown func(DB)) {
Test := func(kv *KeyValue) func() {
return func() {
var p DB
if setup != nil {
Defer("setup", func() {
p = setup(*kv)
})
}
if teardown != nil {
Defer("teardown", func() {
teardown(p)
})
}
if body != nil {
p = body(*kv)
}
KeyValueTesting(rnd, *kv, p, func(KeyValue) DB {
return p
}, nil)
}
}
Describe("with no key/value (empty)", Test(&KeyValue{}))
Describe("with empty key", Test(KeyValue_EmptyKey()))
Describe("with empty value", Test(KeyValue_EmptyValue()))
Describe("with one key/value", Test(KeyValue_OneKeyValue()))
Describe("with big value", Test(KeyValue_BigValue()))
Describe("with special key", Test(KeyValue_SpecialKey()))
Describe("with multiple key/value", Test(KeyValue_MultipleKeyValue()))
Describe("with generated key/value", Test(KeyValue_Generate(nil, 120, 1, 50, 10, 120)))
}

View File

@@ -0,0 +1,694 @@
// Copyright (c) 2014, Suryandaru Triandana <syndtr@gmail.com>
// 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"
"fmt"
"io"
"math/rand"
"os"
"path/filepath"
"runtime"
"strings"
"sync"
. "github.com/onsi/gomega"
"github.com/syndtr/goleveldb/leveldb/storage"
"github.com/syndtr/goleveldb/leveldb/util"
)
var (
storageMu sync.Mutex
storageUseFS = true
storageKeepFS = false
storageNum int
)
type StorageMode int
const (
ModeOpen StorageMode = 1 << iota
ModeCreate
ModeRemove
ModeRename
ModeRead
ModeWrite
ModeSync
ModeClose
)
const (
modeOpen = iota
modeCreate
modeRemove
modeRename
modeRead
modeWrite
modeSync
modeClose
modeCount
)
const (
typeManifest = iota
typeJournal
typeTable
typeTemp
typeCount
)
const flattenCount = modeCount * typeCount
func flattenType(m StorageMode, t storage.FileType) int {
var x int
switch m {
case ModeOpen:
x = modeOpen
case ModeCreate:
x = modeCreate
case ModeRemove:
x = modeRemove
case ModeRename:
x = modeRename
case ModeRead:
x = modeRead
case ModeWrite:
x = modeWrite
case ModeSync:
x = modeSync
case ModeClose:
x = modeClose
default:
panic("invalid storage mode")
}
x *= typeCount
switch t {
case storage.TypeManifest:
return x + typeManifest
case storage.TypeJournal:
return x + typeJournal
case storage.TypeTable:
return x + typeTable
case storage.TypeTemp:
return x + typeTemp
default:
panic("invalid file type")
}
}
func listFlattenType(m StorageMode, t storage.FileType) []int {
ret := make([]int, 0, flattenCount)
add := func(x int) {
x *= typeCount
switch {
case t&storage.TypeManifest != 0:
ret = append(ret, x+typeManifest)
case t&storage.TypeJournal != 0:
ret = append(ret, x+typeJournal)
case t&storage.TypeTable != 0:
ret = append(ret, x+typeTable)
case t&storage.TypeTemp != 0:
ret = append(ret, x+typeTemp)
}
}
switch {
case m&ModeOpen != 0:
add(modeOpen)
case m&ModeCreate != 0:
add(modeCreate)
case m&ModeRemove != 0:
add(modeRemove)
case m&ModeRename != 0:
add(modeRename)
case m&ModeRead != 0:
add(modeRead)
case m&ModeWrite != 0:
add(modeWrite)
case m&ModeSync != 0:
add(modeSync)
case m&ModeClose != 0:
add(modeClose)
}
return ret
}
func packFile(fd storage.FileDesc) uint64 {
if fd.Num>>(63-typeCount) != 0 {
panic("overflow")
}
return uint64(fd.Num<<typeCount) | uint64(fd.Type)
}
func unpackFile(x uint64) storage.FileDesc {
return storage.FileDesc{storage.FileType(x) & storage.TypeAll, int64(x >> typeCount)}
}
type emulatedError struct {
err error
}
func (err emulatedError) Error() string {
return fmt.Sprintf("emulated storage error: %v", err.err)
}
type storageLock struct {
s *Storage
r util.Releaser
}
func (l storageLock) Release() {
l.r.Release()
l.s.logI("storage lock released")
}
type reader struct {
s *Storage
fd storage.FileDesc
storage.Reader
}
func (r *reader) Read(p []byte) (n int, err error) {
err = r.s.emulateError(ModeRead, r.fd.Type)
if err == nil {
r.s.stall(ModeRead, r.fd.Type)
n, err = r.Reader.Read(p)
}
r.s.count(ModeRead, r.fd.Type, n)
if err != nil && err != io.EOF {
r.s.logI("read error, fd=%s n=%d err=%v", r.fd, n, err)
}
return
}
func (r *reader) ReadAt(p []byte, off int64) (n int, err error) {
err = r.s.emulateError(ModeRead, r.fd.Type)
if err == nil {
r.s.stall(ModeRead, r.fd.Type)
n, err = r.Reader.ReadAt(p, off)
}
r.s.count(ModeRead, r.fd.Type, n)
if err != nil && err != io.EOF {
r.s.logI("readAt error, fd=%s offset=%d n=%d err=%v", r.fd, off, n, err)
}
return
}
func (r *reader) Close() (err error) {
return r.s.fileClose(r.fd, r.Reader)
}
type writer struct {
s *Storage
fd storage.FileDesc
storage.Writer
}
func (w *writer) Write(p []byte) (n int, err error) {
err = w.s.emulateError(ModeWrite, w.fd.Type)
if err == nil {
w.s.stall(ModeWrite, w.fd.Type)
n, err = w.Writer.Write(p)
}
w.s.count(ModeWrite, w.fd.Type, n)
if err != nil && err != io.EOF {
w.s.logI("write error, fd=%s n=%d err=%v", w.fd, n, err)
}
return
}
func (w *writer) Sync() (err error) {
err = w.s.emulateError(ModeSync, w.fd.Type)
if err == nil {
w.s.stall(ModeSync, w.fd.Type)
err = w.Writer.Sync()
}
w.s.count(ModeSync, w.fd.Type, 0)
if err != nil {
w.s.logI("sync error, fd=%s err=%v", w.fd, err)
}
return
}
func (w *writer) Close() (err error) {
return w.s.fileClose(w.fd, w.Writer)
}
type Storage struct {
storage.Storage
path string
onClose func() (preserve bool, err error)
onLog func(str string)
lmu sync.Mutex
lb bytes.Buffer
mu sync.Mutex
rand *rand.Rand
// Open files, true=writer, false=reader
opens map[uint64]bool
counters [flattenCount]int
bytesCounter [flattenCount]int64
emulatedError [flattenCount]error
emulatedErrorOnce [flattenCount]bool
emulatedRandomError [flattenCount]error
emulatedRandomErrorProb [flattenCount]float64
stallCond sync.Cond
stalled [flattenCount]bool
}
func (s *Storage) log(skip int, str string) {
s.lmu.Lock()
defer s.lmu.Unlock()
_, file, line, ok := runtime.Caller(skip + 2)
if ok {
// Truncate file name at last file name separator.
if index := strings.LastIndex(file, "/"); index >= 0 {
file = file[index+1:]
} else if index = strings.LastIndex(file, "\\"); index >= 0 {
file = file[index+1:]
}
} else {
file = "???"
line = 1
}
fmt.Fprintf(&s.lb, "%s:%d: ", file, line)
lines := strings.Split(str, "\n")
if l := len(lines); l > 1 && lines[l-1] == "" {
lines = lines[:l-1]
}
for i, line := range lines {
if i > 0 {
s.lb.WriteString("\n\t")
}
s.lb.WriteString(line)
}
if s.onLog != nil {
s.onLog(s.lb.String())
s.lb.Reset()
} else {
s.lb.WriteByte('\n')
}
}
func (s *Storage) logISkip(skip int, format string, args ...interface{}) {
pc, _, _, ok := runtime.Caller(skip + 1)
if ok {
if f := runtime.FuncForPC(pc); f != nil {
fname := f.Name()
if index := strings.LastIndex(fname, "."); index >= 0 {
fname = fname[index+1:]
}
format = fname + ": " + format
}
}
s.log(skip+1, fmt.Sprintf(format, args...))
}
func (s *Storage) logI(format string, args ...interface{}) {
s.logISkip(1, format, args...)
}
func (s *Storage) OnLog(onLog func(log string)) {
s.lmu.Lock()
s.onLog = onLog
if s.lb.Len() != 0 {
log := s.lb.String()
s.onLog(log[:len(log)-1])
s.lb.Reset()
}
s.lmu.Unlock()
}
func (s *Storage) Log(str string) {
s.log(1, "Log: "+str)
s.Storage.Log(str)
}
func (s *Storage) Lock() (l storage.Lock, err error) {
l, err = s.Storage.Lock()
if err != nil {
s.logI("storage locking failed, err=%v", err)
} else {
s.logI("storage locked")
l = storageLock{s, l}
}
return
}
func (s *Storage) List(t storage.FileType) (fds []storage.FileDesc, err error) {
fds, err = s.Storage.List(t)
if err != nil {
s.logI("list failed, err=%v", err)
return
}
s.logI("list, type=0x%x count=%d", int(t), len(fds))
return
}
func (s *Storage) GetMeta() (fd storage.FileDesc, err error) {
fd, err = s.Storage.GetMeta()
if err != nil {
if !os.IsNotExist(err) {
s.logI("get meta failed, err=%v", err)
}
return
}
s.logI("get meta, fd=%s", fd)
return
}
func (s *Storage) SetMeta(fd storage.FileDesc) error {
ExpectWithOffset(1, fd.Type).To(Equal(storage.TypeManifest))
err := s.Storage.SetMeta(fd)
if err != nil {
s.logI("set meta failed, fd=%s err=%v", fd, err)
} else {
s.logI("set meta, fd=%s", fd)
}
return err
}
func (s *Storage) fileClose(fd storage.FileDesc, closer io.Closer) (err error) {
err = s.emulateError(ModeClose, fd.Type)
if err == nil {
s.stall(ModeClose, fd.Type)
}
x := packFile(fd)
s.mu.Lock()
defer s.mu.Unlock()
if err == nil {
ExpectWithOffset(2, s.opens).To(HaveKey(x), "File closed, fd=%s", fd)
err = closer.Close()
}
s.countNB(ModeClose, fd.Type, 0)
writer := s.opens[x]
if err != nil {
s.logISkip(1, "file close failed, fd=%s writer=%v err=%v", fd, writer, err)
} else {
s.logISkip(1, "file closed, fd=%s writer=%v", fd, writer)
delete(s.opens, x)
}
return
}
func (s *Storage) assertOpen(fd storage.FileDesc) {
x := packFile(fd)
ExpectWithOffset(2, s.opens).NotTo(HaveKey(x), "File open, fd=%s writer=%v", fd, s.opens[x])
}
func (s *Storage) Open(fd storage.FileDesc) (r storage.Reader, err error) {
err = s.emulateError(ModeOpen, fd.Type)
if err == nil {
s.stall(ModeOpen, fd.Type)
}
s.mu.Lock()
defer s.mu.Unlock()
if err == nil {
s.assertOpen(fd)
s.countNB(ModeOpen, fd.Type, 0)
r, err = s.Storage.Open(fd)
}
if err != nil {
s.logI("file open failed, fd=%s err=%v", fd, err)
} else {
s.logI("file opened, fd=%s", fd)
s.opens[packFile(fd)] = false
r = &reader{s, fd, r}
}
return
}
func (s *Storage) Create(fd storage.FileDesc) (w storage.Writer, err error) {
err = s.emulateError(ModeCreate, fd.Type)
if err == nil {
s.stall(ModeCreate, fd.Type)
}
s.mu.Lock()
defer s.mu.Unlock()
if err == nil {
s.assertOpen(fd)
s.countNB(ModeCreate, fd.Type, 0)
w, err = s.Storage.Create(fd)
}
if err != nil {
s.logI("file create failed, fd=%s err=%v", fd, err)
} else {
s.logI("file created, fd=%s", fd)
s.opens[packFile(fd)] = true
w = &writer{s, fd, w}
}
return
}
func (s *Storage) Remove(fd storage.FileDesc) (err error) {
err = s.emulateError(ModeRemove, fd.Type)
if err == nil {
s.stall(ModeRemove, fd.Type)
}
s.mu.Lock()
defer s.mu.Unlock()
if err == nil {
s.assertOpen(fd)
s.countNB(ModeRemove, fd.Type, 0)
err = s.Storage.Remove(fd)
}
if err != nil {
s.logI("file remove failed, fd=%s err=%v", fd, err)
} else {
s.logI("file removed, fd=%s", fd)
}
return
}
func (s *Storage) ForceRemove(fd storage.FileDesc) (err error) {
s.countNB(ModeRemove, fd.Type, 0)
if err = s.Storage.Remove(fd); err != nil {
s.logI("file remove failed (forced), fd=%s err=%v", fd, err)
} else {
s.logI("file removed (forced), fd=%s", fd)
}
return
}
func (s *Storage) Rename(oldfd, newfd storage.FileDesc) (err error) {
err = s.emulateError(ModeRename, oldfd.Type)
if err == nil {
s.stall(ModeRename, oldfd.Type)
}
s.mu.Lock()
defer s.mu.Unlock()
if err == nil {
s.assertOpen(oldfd)
s.assertOpen(newfd)
s.countNB(ModeRename, oldfd.Type, 0)
err = s.Storage.Rename(oldfd, newfd)
}
if err != nil {
s.logI("file rename failed, oldfd=%s newfd=%s err=%v", oldfd, newfd, err)
} else {
s.logI("file renamed, oldfd=%s newfd=%s", oldfd, newfd)
}
return
}
func (s *Storage) ForceRename(oldfd, newfd storage.FileDesc) (err error) {
s.countNB(ModeRename, oldfd.Type, 0)
if err = s.Storage.Rename(oldfd, newfd); err != nil {
s.logI("file rename failed (forced), oldfd=%s newfd=%s err=%v", oldfd, newfd, err)
} else {
s.logI("file renamed (forced), oldfd=%s newfd=%s", oldfd, newfd)
}
return
}
func (s *Storage) openFiles() string {
out := "Open files:"
for x, writer := range s.opens {
fd := unpackFile(x)
out += fmt.Sprintf("\n · fd=%s writer=%v", fd, writer)
}
return out
}
func (s *Storage) CloseCheck() {
s.mu.Lock()
defer s.mu.Unlock()
ExpectWithOffset(1, s.opens).To(BeEmpty(), s.openFiles())
}
func (s *Storage) OnClose(onClose func() (preserve bool, err error)) {
s.mu.Lock()
s.onClose = onClose
s.mu.Unlock()
}
func (s *Storage) Close() error {
s.mu.Lock()
defer s.mu.Unlock()
ExpectWithOffset(1, s.opens).To(BeEmpty(), s.openFiles())
err := s.Storage.Close()
if err != nil {
s.logI("storage closing failed, err=%v", err)
} else {
s.logI("storage closed")
}
var preserve bool
if s.onClose != nil {
var err0 error
if preserve, err0 = s.onClose(); err0 != nil {
s.logI("onClose error, err=%v", err0)
}
}
if s.path != "" {
if storageKeepFS || preserve {
s.logI("storage is preserved, path=%v", s.path)
} else {
if err1 := os.RemoveAll(s.path); err1 != nil {
s.logI("cannot remove storage, err=%v", err1)
} else {
s.logI("storage has been removed")
}
}
}
return err
}
func (s *Storage) countNB(m StorageMode, t storage.FileType, n int) {
s.counters[flattenType(m, t)]++
s.bytesCounter[flattenType(m, t)] += int64(n)
}
func (s *Storage) count(m StorageMode, t storage.FileType, n int) {
s.mu.Lock()
defer s.mu.Unlock()
s.countNB(m, t, n)
}
func (s *Storage) ResetCounter(m StorageMode, t storage.FileType) {
for _, x := range listFlattenType(m, t) {
s.counters[x] = 0
s.bytesCounter[x] = 0
}
}
func (s *Storage) Counter(m StorageMode, t storage.FileType) (count int, bytes int64) {
for _, x := range listFlattenType(m, t) {
count += s.counters[x]
bytes += s.bytesCounter[x]
}
return
}
func (s *Storage) emulateError(m StorageMode, t storage.FileType) error {
s.mu.Lock()
defer s.mu.Unlock()
x := flattenType(m, t)
if err := s.emulatedError[x]; err != nil {
if s.emulatedErrorOnce[x] {
s.emulatedError[x] = nil
}
return emulatedError{err}
}
if err := s.emulatedRandomError[x]; err != nil && s.rand.Float64() < s.emulatedRandomErrorProb[x] {
return emulatedError{err}
}
return nil
}
func (s *Storage) EmulateError(m StorageMode, t storage.FileType, err error) {
s.mu.Lock()
defer s.mu.Unlock()
for _, x := range listFlattenType(m, t) {
s.emulatedError[x] = err
s.emulatedErrorOnce[x] = false
}
}
func (s *Storage) EmulateErrorOnce(m StorageMode, t storage.FileType, err error) {
s.mu.Lock()
defer s.mu.Unlock()
for _, x := range listFlattenType(m, t) {
s.emulatedError[x] = err
s.emulatedErrorOnce[x] = true
}
}
func (s *Storage) EmulateRandomError(m StorageMode, t storage.FileType, prob float64, err error) {
s.mu.Lock()
defer s.mu.Unlock()
for _, x := range listFlattenType(m, t) {
s.emulatedRandomError[x] = err
s.emulatedRandomErrorProb[x] = prob
}
}
func (s *Storage) stall(m StorageMode, t storage.FileType) {
x := flattenType(m, t)
s.mu.Lock()
defer s.mu.Unlock()
for s.stalled[x] {
s.stallCond.Wait()
}
}
func (s *Storage) Stall(m StorageMode, t storage.FileType) {
s.mu.Lock()
defer s.mu.Unlock()
for _, x := range listFlattenType(m, t) {
s.stalled[x] = true
}
}
func (s *Storage) Release(m StorageMode, t storage.FileType) {
s.mu.Lock()
defer s.mu.Unlock()
for _, x := range listFlattenType(m, t) {
s.stalled[x] = false
}
s.stallCond.Broadcast()
}
func NewStorage() *Storage {
var (
stor storage.Storage
path string
)
if storageUseFS {
for {
storageMu.Lock()
num := storageNum
storageNum++
storageMu.Unlock()
path = filepath.Join(os.TempDir(), fmt.Sprintf("goleveldb-test%d0%d0%d", os.Getuid(), os.Getpid(), num))
if _, err := os.Stat(path); os.IsNotExist(err) {
stor, err = storage.OpenFile(path, false)
ExpectWithOffset(1, err).NotTo(HaveOccurred(), "creating storage at %s", path)
break
}
}
} else {
stor = storage.NewMemStorage()
}
s := &Storage{
Storage: stor,
path: path,
rand: NewRand(),
opens: make(map[uint64]bool),
}
s.stallCond.L = &s.mu
if s.path != "" {
s.logI("using FS storage")
s.logI("storage path: %s", s.path)
} else {
s.logI("using MEM storage")
}
return s
}

View File

@@ -0,0 +1,171 @@
// Copyright (c) 2014, Suryandaru Triandana <syndtr@gmail.com>
// 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"
"flag"
"math/rand"
"reflect"
"sync"
"github.com/onsi/ginkgo/config"
"github.com/syndtr/goleveldb/leveldb/comparer"
)
var (
runfn = make(map[string][]func())
runmu sync.Mutex
)
func Defer(args ...interface{}) bool {
var (
group string
fn func()
)
for _, arg := range args {
v := reflect.ValueOf(arg)
switch v.Kind() {
case reflect.String:
group = v.String()
case reflect.Func:
r := reflect.ValueOf(&fn).Elem()
r.Set(v)
}
}
if fn != nil {
runmu.Lock()
runfn[group] = append(runfn[group], fn)
runmu.Unlock()
}
return true
}
func RunDefer(groups ...string) bool {
if len(groups) == 0 {
groups = append(groups, "")
}
runmu.Lock()
var runfn_ []func()
for _, group := range groups {
runfn_ = append(runfn_, runfn[group]...)
delete(runfn, group)
}
runmu.Unlock()
for _, fn := range runfn_ {
fn()
}
return runfn_ != nil
}
func RandomSeed() int64 {
if !flag.Parsed() {
panic("random seed not initialized")
}
return config.GinkgoConfig.RandomSeed
}
func NewRand() *rand.Rand {
return rand.New(rand.NewSource(RandomSeed()))
}
var cmp = comparer.DefaultComparer
func BytesSeparator(a, b []byte) []byte {
if bytes.Equal(a, b) {
return b
}
i, n := 0, len(a)
if n > len(b) {
n = len(b)
}
for ; i < n && (a[i] == b[i]); i++ {
}
x := append([]byte{}, a[:i]...)
if i < n {
if c := a[i] + 1; c < b[i] {
return append(x, c)
}
x = append(x, a[i])
i++
}
for ; i < len(a); i++ {
if c := a[i]; c < 0xff {
return append(x, c+1)
} else {
x = append(x, c)
}
}
if len(b) > i && b[i] > 0 {
return append(x, b[i]-1)
}
return append(x, 'x')
}
func BytesAfter(b []byte) []byte {
var x []byte
for _, c := range b {
if c < 0xff {
return append(x, c+1)
} else {
x = append(x, c)
}
}
return append(x, 'x')
}
func RandomIndex(rnd *rand.Rand, n, round int, fn func(i int)) {
if rnd == nil {
rnd = NewRand()
}
for x := 0; x < round; x++ {
fn(rnd.Intn(n))
}
return
}
func ShuffledIndex(rnd *rand.Rand, n, round int, fn func(i int)) {
if rnd == nil {
rnd = NewRand()
}
for x := 0; x < round; x++ {
for _, i := range rnd.Perm(n) {
fn(i)
}
}
return
}
func RandomRange(rnd *rand.Rand, n, round int, fn func(start, limit int)) {
if rnd == nil {
rnd = NewRand()
}
for x := 0; x < round; x++ {
start := rnd.Intn(n)
length := 0
if j := n - start; j > 0 {
length = rnd.Intn(j)
}
fn(start, start+length)
}
return
}
func Max(x, y int) int {
if x > y {
return x
}
return y
}
func Min(x, y int) int {
if x < y {
return x
}
return y
}