github.com/cayleygraph/cayley@v0.7.7/graph/kv/kvtest/kvtest.go (about) 1 package kvtest 2 3 import ( 4 "context" 5 "reflect" 6 "testing" 7 8 "github.com/cayleygraph/cayley/graph" 9 "github.com/cayleygraph/cayley/graph/graphtest" 10 "github.com/cayleygraph/cayley/graph/graphtest/testutil" 11 "github.com/cayleygraph/cayley/graph/kv" 12 "github.com/cayleygraph/cayley/graph/shape" 13 "github.com/cayleygraph/quad" 14 hkv "github.com/hidal-go/hidalgo/kv" 15 "github.com/stretchr/testify/require" 16 ) 17 18 type DatabaseFunc func(t testing.TB) (hkv.KV, graph.Options, func()) 19 20 type Config struct { 21 AlwaysRunIntegration bool 22 } 23 24 func (c Config) quadStore() *graphtest.Config { 25 return &graphtest.Config{ 26 NoPrimitives: true, 27 AlwaysRunIntegration: c.AlwaysRunIntegration, 28 } 29 } 30 31 func newQuadStoreFunc(gen DatabaseFunc, bloom bool) testutil.DatabaseFunc { 32 return func(t testing.TB) (graph.QuadStore, graph.Options, func()) { 33 return newQuadStore(t, gen, bloom) 34 } 35 } 36 37 func NewQuadStoreFunc(gen DatabaseFunc) testutil.DatabaseFunc { 38 return newQuadStoreFunc(gen, true) 39 } 40 41 func newQuadStore(t testing.TB, gen DatabaseFunc, bloom bool) (graph.QuadStore, graph.Options, func()) { 42 db, opt, closer := gen(t) 43 if opt == nil { 44 opt = make(graph.Options) 45 } 46 if !bloom { 47 opt[kv.OptNoBloom] = true 48 } 49 err := kv.Init(db, opt) 50 if err != nil { 51 db.Close() 52 closer() 53 require.Fail(t, "init failed", "%v", err) 54 } 55 kdb, err := kv.New(db, opt) 56 if err != nil { 57 db.Close() 58 closer() 59 require.Fail(t, "create failed", "%v", err) 60 } 61 return kdb, opt, func() { 62 kdb.Close() 63 closer() 64 } 65 } 66 67 func NewQuadStore(t testing.TB, gen DatabaseFunc) (graph.QuadStore, graph.Options, func()) { 68 return newQuadStore(t, gen, true) 69 } 70 71 func TestAll(t *testing.T, gen DatabaseFunc, conf *Config) { 72 if conf == nil { 73 conf = &Config{} 74 } 75 qsgen := NewQuadStoreFunc(gen) 76 t.Run("qs", func(t *testing.T) { 77 graphtest.TestAll(t, qsgen, conf.quadStore()) 78 }) 79 qsgenNoBloom := newQuadStoreFunc(gen, false) 80 t.Run("qs-no-bloom", func(t *testing.T) { 81 graphtest.TestAll(t, qsgenNoBloom, conf.quadStore()) 82 }) 83 t.Run("optimize", func(t *testing.T) { 84 testOptimize(t, gen, conf) 85 }) 86 } 87 88 func testOptimize(t *testing.T, gen DatabaseFunc, _ *Config) { 89 ctx := context.TODO() 90 qs, opts, closer := NewQuadStore(t, gen) 91 defer closer() 92 93 testutil.MakeWriter(t, qs, opts, graphtest.MakeQuadSet()...) 94 95 // With an linksto-fixed pair 96 lto := shape.BuildIterator(qs, shape.Quads{ 97 {Dir: quad.Object, Values: shape.Lookup{quad.Raw("F")}}, 98 }) 99 100 oldIt := shape.BuildIterator(qs, shape.Quads{ 101 {Dir: quad.Object, Values: shape.Lookup{quad.Raw("F")}}, 102 }) 103 newIt, ok := lto.Optimize() 104 if ok { 105 t.Errorf("unexpected optimization step") 106 } 107 if _, ok := newIt.(*kv.QuadIterator); !ok { 108 t.Errorf("Optimized iterator type does not match original, got: %T", newIt) 109 } 110 111 newQuads := graphtest.IteratedQuads(t, qs, newIt) 112 oldQuads := graphtest.IteratedQuads(t, qs, oldIt) 113 if !reflect.DeepEqual(newQuads, oldQuads) { 114 t.Errorf("Optimized iteration does not match original") 115 } 116 117 oldIt.Next(ctx) 118 oldResults := make(map[string]graph.Ref) 119 oldIt.TagResults(oldResults) 120 newIt.Next(ctx) 121 newResults := make(map[string]graph.Ref) 122 newIt.TagResults(newResults) 123 if !reflect.DeepEqual(newResults, oldResults) { 124 t.Errorf("Discordant tag results, new:%v old:%v", newResults, oldResults) 125 } 126 } 127 128 func BenchmarkAll(t *testing.B, gen DatabaseFunc, conf *Config) { 129 if conf == nil { 130 conf = &Config{} 131 } 132 qsgen := NewQuadStoreFunc(gen) 133 t.Run("qs", func(t *testing.B) { 134 graphtest.BenchmarkAll(t, qsgen, conf.quadStore()) 135 }) 136 }