Skip to content

Commit

Permalink
test: 81% coverage on blockstore
Browse files Browse the repository at this point in the history
Coverage report available at: https://ipfs.io/ipfs/QmTuMtwGCfHrbYyZdQ1RaGNwS2MGsmAkjA8AaB69N7Ya1g/coverage.html#file0

Part of #3053

License: MIT
Signed-off-by: Jakub Sztandera <kubuxu@protonmail.ch>
  • Loading branch information
Kubuxu committed Aug 15, 2016
1 parent 16f8570 commit 44ef280
Show file tree
Hide file tree
Showing 4 changed files with 191 additions and 16 deletions.
140 changes: 125 additions & 15 deletions blocks/blockstore/arc_cache_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,16 @@ package blockstore

import (
"github.com/ipfs/go-ipfs/blocks"
"github.com/ipfs/go-ipfs/blocks/key"
"testing"

ds "gx/ipfs/QmTxLSvdhwg68WJimdS6icLPhZi28aTp6b7uihC2Yb47Xk/go-datastore"
syncds "gx/ipfs/QmTxLSvdhwg68WJimdS6icLPhZi28aTp6b7uihC2Yb47Xk/go-datastore/sync"
context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
)

var exampleBlock = blocks.NewBlock([]byte("foo"))

func testArcCached(bs GCBlockstore, ctx context.Context) (*arccache, error) {
if ctx == nil {
ctx = context.TODO()
Expand All @@ -24,15 +27,29 @@ func testArcCached(bs GCBlockstore, ctx context.Context) (*arccache, error) {
}
}

func TestRemoveCacheEntryOnDelete(t *testing.T) {
b := blocks.NewBlock([]byte("foo"))
func createStores(t *testing.T) (*arccache, *blockstore, *callbackDatastore) {
cd := &callbackDatastore{f: func() {}, ds: ds.NewMapDatastore()}
bs := NewBlockstore(syncds.MutexWrap(cd))
cachedbs, err := testArcCached(bs, nil)
arc, err := testArcCached(bs, nil)
if err != nil {
t.Fatal(err)
}
cachedbs.Put(b)
return arc, bs, cd
}

func trap(message string, cd *callbackDatastore, t *testing.T) {
cd.SetFunc(func() {
t.Fatal(message)
})
}
func untrap(cd *callbackDatastore) {
cd.SetFunc(func() {})
}

func TestRemoveCacheEntryOnDelete(t *testing.T) {
arc, _, cd := createStores(t)

arc.Put(exampleBlock)

cd.Lock()
writeHitTheDatastore := false
Expand All @@ -42,26 +59,119 @@ func TestRemoveCacheEntryOnDelete(t *testing.T) {
writeHitTheDatastore = true
})

cachedbs.DeleteBlock(b.Key())
cachedbs.Put(b)
arc.DeleteBlock(exampleBlock.Key())
arc.Put(exampleBlock)
if !writeHitTheDatastore {
t.Fail()
}
}

func TestElideDuplicateWrite(t *testing.T) {
cd := &callbackDatastore{f: func() {}, ds: ds.NewMapDatastore()}
bs := NewBlockstore(syncds.MutexWrap(cd))
cachedbs, err := testArcCached(bs, nil)
arc, _, cd := createStores(t)

arc.Put(exampleBlock)
trap("write hit datastore", cd, t)
arc.Put(exampleBlock)
}

func TestHasRequestTriggersCache(t *testing.T) {
arc, _, cd := createStores(t)

arc.Has(exampleBlock.Key())
trap("has hit datastore", cd, t)
if has, err := arc.Has(exampleBlock.Key()); has || err != nil {
t.Fatal("has was true but there is no such block")
}

untrap(cd)
err := arc.Put(exampleBlock)
if err != nil {
t.Fatal(err)
}

b1 := blocks.NewBlock([]byte("foo"))
trap("has hit datastore", cd, t)

cachedbs.Put(b1)
cd.SetFunc(func() {
t.Fatal("write hit the datastore")
})
cachedbs.Put(b1)
if has, err := arc.Has(exampleBlock.Key()); !has || err != nil {
t.Fatal("has returned invalid result")
}
}

func TestGetFillsCache(t *testing.T) {
arc, _, cd := createStores(t)

if bl, err := arc.Get(exampleBlock.Key()); bl != nil || err == nil {
t.Fatal("block was found or there was no error")
}

trap("has hit datastore", cd, t)

if has, err := arc.Has(exampleBlock.Key()); has || err != nil {
t.Fatal("has was true but there is no such block")
}

untrap(cd)

if err := arc.Put(exampleBlock); err != nil {
t.Fatal(err)
}

trap("has hit datastore", cd, t)

if has, err := arc.Has(exampleBlock.Key()); !has || err != nil {
t.Fatal("has returned invalid result")
}
}

func TestGetAndDeleteFalseShortCirciot(t *testing.T) {
arc, _, cd := createStores(t)

arc.Has(exampleBlock.Key())

trap("get hit datastore", cd, t)

if bl, err := arc.Get(exampleBlock.Key()); bl != nil || err != ErrNotFound {
t.Fatal("get returned invalid result")
}

if arc.DeleteBlock(exampleBlock.Key()) != ErrNotFound {
t.Fatal("expected ErrNotFound error")
}
}

func TestArcCreationFailure(t *testing.T) {
if arc, err := arcCached(nil, -1); arc != nil || err == nil {
t.Fatal("expected error and no cache")
}
}

func TestInvalidKey(t *testing.T) {
arc, _, _ := createStores(t)

bl, err := arc.Get(key.Key(""))

if bl != nil {
t.Fatal("blocks should be nil")
}
if err == nil {
t.Fatal("expected error")
}
}

func TestHasAfterSucessfulGetIsCached(t *testing.T) {
arc, bs, cd := createStores(t)

bs.Put(exampleBlock)

arc.Get(exampleBlock.Key())

trap("has hit datastore", cd, t)
arc.Has(exampleBlock.Key())
}

func TestPutManyCaches(t *testing.T) {
arc, _, cd := createStores(t)
arc.PutMany([]blocks.Block{exampleBlock})

trap("has hit datastore", cd, t)
arc.Has(exampleBlock.Key())
}
7 changes: 6 additions & 1 deletion blocks/blockstore/blockstore_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,16 +57,21 @@ func TestRuntimeHashing(t *testing.T) {
bs := NewBlockstore(ds_sync.MutexWrap(ds.NewMapDatastore()))
bl := blocks.NewBlock([]byte("some data"))
blBad, err := blocks.NewBlockWithHash([]byte("some other data"), bl.Key().ToMultihash())
bl2 := blocks.NewBlock([]byte("some other data"))
if err != nil {
t.Fatal("Debug is enabled")
}

bs.Put(blBad)
bs.Put(bl2)
bs.RuntimeHashing(true)

if _, err := bs.Get(bl.Key()); err != ErrHashMismatch {
t.Fatalf("Expected '%v' got '%v'\n", ErrHashMismatch, err)
}

if b, err := bs.Get(bl2.Key()); err != nil || b.String() != bl2.String() {
t.Fatal("got wrong blocks")
}
}

func newBlockStoreWithKeys(t *testing.T, d ds.Datastore, N int) (Blockstore, []key.Key) {
Expand Down
25 changes: 25 additions & 0 deletions blocks/blockstore/bloom_cache_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,31 @@ func TestHasIsBloomCached(t *testing.T) {
if float64(cacheFails)/float64(1000) > float64(0.05) {
t.Fatal("Bloom filter has cache miss rate of more than 5%")
}

cacheFails = 0
block := blocks.NewBlock([]byte("newBlock"))

cachedbs.PutMany([]blocks.Block{block})
if cacheFails != 2 {
t.Fatalf("expected two datastore hits: %d", cacheFails)
}
cachedbs.Put(block)
if cacheFails != 3 {
t.Fatalf("expected datastore hit: %d", cacheFails)
}

if has, err := cachedbs.Has(block.Key()); !has || err != nil {
t.Fatal("has gave wrong response")
}

bl, err := cachedbs.Get(block.Key())
if bl.String() != block.String() {
t.Fatal("block data doesn't match")
}

if err != nil {
t.Fatal("there should't be an error")
}
}

type callbackDatastore struct {
Expand Down
35 changes: 35 additions & 0 deletions blocks/blockstore/caching_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package blockstore

import "testing"

func TestCachingOptsLessThanZero(t *testing.T) {
opts := DefaultCacheOpts()
opts.HasARCCacheSize = -1

if _, err := CachedBlockstore(nil, nil, opts); err == nil {
t.Fatal()
}

opts = DefaultCacheOpts()
opts.HasBloomFilterSize = -1

if _, err := CachedBlockstore(nil, nil, opts); err == nil {
t.Fatal()
}

opts = DefaultCacheOpts()
opts.HasBloomFilterHashes = -1

if _, err := CachedBlockstore(nil, nil, opts); err == nil {
t.Fatal()
}
}

func TestBloomHashesAtZero(t *testing.T) {
opts := DefaultCacheOpts()
opts.HasBloomFilterHashes = 0

if _, err := CachedBlockstore(nil, nil, opts); err == nil {
t.Fatal()
}
}

0 comments on commit 44ef280

Please sign in to comment.