Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(537)

Side by Side Diff: logdog/common/storage/bigtable/storage_test.go

Issue 2435113002: LogDog: Add Storage-layer data caching. (Closed)
Patch Set: Fix byteLimit bug. Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « logdog/common/storage/bigtable/storage.go ('k') | logdog/common/storage/bigtable/testing.go » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 The LUCI Authors. All rights reserved. 1 // Copyright 2015 The LUCI Authors. All rights reserved.
2 // Use of this source code is governed under the Apache License, Version 2.0 2 // Use of this source code is governed under the Apache License, Version 2.0
3 // that can be found in the LICENSE file. 3 // that can be found in the LICENSE file.
4 4
5 package bigtable 5 package bigtable
6 6
7 import ( 7 import (
8 "bytes" 8 "bytes"
9 "fmt"
10 "strconv" 9 "strconv"
11 "testing" 10 "testing"
12 "time"
13 11
14 "github.com/luci/gkvlite"
15 "github.com/luci/luci-go/common/config" 12 "github.com/luci/luci-go/common/config"
16 "github.com/luci/luci-go/common/data/recordio" 13 "github.com/luci/luci-go/common/data/recordio"
17 "github.com/luci/luci-go/logdog/common/storage" 14 "github.com/luci/luci-go/logdog/common/storage"
18 "github.com/luci/luci-go/logdog/common/types" 15 "github.com/luci/luci-go/logdog/common/types"
19 "golang.org/x/net/context" 16 "golang.org/x/net/context"
20 17
21 . "github.com/luci/luci-go/common/testing/assertions" 18 . "github.com/luci/luci-go/common/testing/assertions"
22 . "github.com/smartystreets/goconvey/convey" 19 . "github.com/smartystreets/goconvey/convey"
23 ) 20 )
24 21
25 // btTableTest is an in-memory implementation of btTable interface for testing.
26 //
27 // This is a simple implementation; not an efficient one.
28 type btTableTest struct {
29 s *gkvlite.Store
30 c *gkvlite.Collection
31
32 // err, if true, is the error immediately returned by functions.
33 err error
34
35 // maxLogAge is the currently-configured maximum log age.
36 maxLogAge time.Duration
37 }
38
39 func (t *btTableTest) close() {
40 if t.s != nil {
41 t.s.Close()
42 t.s = nil
43 }
44 }
45
46 func (t *btTableTest) collection() *gkvlite.Collection {
47 if t.s == nil {
48 var err error
49 t.s, err = gkvlite.NewStore(nil)
50 if err != nil {
51 panic(err)
52 }
53 t.c = t.s.MakePrivateCollection(bytes.Compare)
54 }
55 return t.c
56 }
57
58 func (t *btTableTest) putLogData(c context.Context, rk *rowKey, d []byte) error {
59 if t.err != nil {
60 return t.err
61 }
62
63 // Record/count sanity check.
64 records, err := recordio.Split(d)
65 if err != nil {
66 return err
67 }
68 if int64(len(records)) != rk.count {
69 return fmt.Errorf("count mismatch (%d != %d)", len(records), rk. count)
70 }
71
72 enc := []byte(rk.encode())
73 coll := t.collection()
74 if item, _ := coll.Get(enc); item != nil {
75 return storage.ErrExists
76 }
77
78 clone := make([]byte, len(d))
79 copy(clone, d)
80 if err := coll.Set(enc, clone); err != nil {
81 panic(err)
82 }
83 return nil
84 }
85
86 func (t *btTableTest) getLogData(c context.Context, rk *rowKey, limit int, keysO nly bool, cb btGetCallback) error {
87 if t.err != nil {
88 return t.err
89 }
90
91 enc := []byte(rk.encode())
92 prefix := rk.pathPrefix()
93 var ierr error
94 err := t.collection().VisitItemsAscend(enc, !keysOnly, func(i *gkvlite.I tem) bool {
95 var drk *rowKey
96 drk, ierr = decodeRowKey(string(i.Key))
97 if ierr != nil {
98 return false
99 }
100 if drk.pathPrefix() != prefix {
101 return false
102 }
103
104 rowData := i.Val
105 if keysOnly {
106 rowData = nil
107 }
108
109 if ierr = cb(drk, rowData); ierr != nil {
110 if ierr == errStop {
111 ierr = nil
112 }
113 return false
114 }
115
116 if limit > 0 {
117 limit--
118 if limit == 0 {
119 return false
120 }
121 }
122
123 return true
124 })
125 if err != nil {
126 panic(err)
127 }
128 return ierr
129 }
130
131 func (t *btTableTest) setMaxLogAge(c context.Context, d time.Duration) error {
132 if t.err != nil {
133 return t.err
134 }
135 t.maxLogAge = d
136 return nil
137 }
138
139 func (t *btTableTest) dataMap() map[string][]byte {
140 result := map[string][]byte{}
141
142 err := t.collection().VisitItemsAscend([]byte(nil), true, func(i *gkvlit e.Item) bool {
143 result[string(i.Key)] = i.Val
144 return true
145 })
146 if err != nil {
147 panic(err)
148 }
149 return result
150 }
151
152 func mustGetIndex(e *storage.Entry) types.MessageIndex { 22 func mustGetIndex(e *storage.Entry) types.MessageIndex {
153 idx, err := e.GetStreamIndex() 23 idx, err := e.GetStreamIndex()
154 if err != nil { 24 if err != nil {
155 panic(err) 25 panic(err)
156 } 26 }
157 return idx 27 return idx
158 } 28 }
159 29
160 func TestStorage(t *testing.T) { 30 func TestStorage(t *testing.T) {
161 t.Parallel() 31 t.Parallel()
162 32
163 Convey(`A BigTable storage instance bound to a testing BigTable instance `, t, func() { 33 Convey(`A BigTable storage instance bound to a testing BigTable instance `, t, func() {
164 » » bt := btTableTest{} 34 » » s := NewMemoryInstance(context.Background(), Options{})
165 » » defer bt.close()
166
167 » » s := newBTStorage(context.Background(), Options{
168 » » » Project: "test-project",
169 » » » Instance: "test-instance",
170 » » » LogTable: "test-log-table",
171 » » }, nil, nil)
172
173 » » s.raw = &bt
174 defer s.Close() 35 defer s.Close()
175 36
176 project := config.ProjectName("test-project") 37 project := config.ProjectName("test-project")
177 get := func(path string, index int, limit int, keysOnly bool) ([ ]string, error) { 38 get := func(path string, index int, limit int, keysOnly bool) ([ ]string, error) {
178 req := storage.GetRequest{ 39 req := storage.GetRequest{
179 Project: project, 40 Project: project,
180 Path: types.StreamPath(path), 41 Path: types.StreamPath(path),
181 Index: types.MessageIndex(index), 42 Index: types.MessageIndex(index),
182 Limit: limit, 43 Limit: limit,
183 KeysOnly: keysOnly, 44 KeysOnly: keysOnly,
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
223 panic(err) 84 panic(err)
224 } 85 }
225 } 86 }
226 87
227 return buf.Bytes() 88 return buf.Bytes()
228 } 89 }
229 90
230 Convey(`With an artificial maximum BigTable row size of two reco rds`, func() { 91 Convey(`With an artificial maximum BigTable row size of two reco rds`, func() {
231 // Artificially constrain row size. 4 = 2*{size/1, data/ 1} RecordIO 92 // Artificially constrain row size. 4 = 2*{size/1, data/ 1} RecordIO
232 // entries. 93 // entries.
233 » » » s.maxRowSize = 4 94 » » » s.SetMaxRowSize(4)
234 95
235 Convey(`Will split row data that overflows the table int o multiple rows.`, func() { 96 Convey(`Will split row data that overflows the table int o multiple rows.`, func() {
236 So(put("A", 0, "0", "1", "2", "3"), ShouldBeNil) 97 So(put("A", 0, "0", "1", "2", "3"), ShouldBeNil)
237 98
238 » » » » So(bt.dataMap(), ShouldResemble, map[string][]by te{ 99 » » » » So(s.DataMap(), ShouldResemble, map[string][]byt e{
239 ekey("A", 1, 2): records("0", "1"), 100 ekey("A", 1, 2): records("0", "1"),
240 ekey("A", 3, 2): records("2", "3"), 101 ekey("A", 3, 2): records("2", "3"),
241 }) 102 })
242 }) 103 })
243 104
244 Convey(`Loading a single row data beyond the maximum row size will fail.`, func() { 105 Convey(`Loading a single row data beyond the maximum row size will fail.`, func() {
245 So(put("A", 0, "0123"), ShouldErrLike, "single r ow entry exceeds maximum size") 106 So(put("A", 0, "0123"), ShouldErrLike, "single r ow entry exceeds maximum size")
246 }) 107 })
247 }) 108 })
248 109
249 Convey(`With row data: A{0, 1, 2, 3, 4}, B{10, 12, 13}`, func() { 110 Convey(`With row data: A{0, 1, 2, 3, 4}, B{10, 12, 13}`, func() {
250 So(put("A", 0, "0", "1", "2"), ShouldBeNil) 111 So(put("A", 0, "0", "1", "2"), ShouldBeNil)
251 So(put("A", 3, "3", "4"), ShouldBeNil) 112 So(put("A", 3, "3", "4"), ShouldBeNil)
252 So(put("B", 10, "10"), ShouldBeNil) 113 So(put("B", 10, "10"), ShouldBeNil)
253 So(put("B", 12, "12", "13"), ShouldBeNil) 114 So(put("B", 12, "12", "13"), ShouldBeNil)
254 115
255 Convey(`Testing "Put"...`, func() { 116 Convey(`Testing "Put"...`, func() {
256 Convey(`Loads the row data.`, func() { 117 Convey(`Loads the row data.`, func() {
257 » » » » » So(bt.dataMap(), ShouldResemble, map[str ing][]byte{ 118 » » » » » So(s.DataMap(), ShouldResemble, map[stri ng][]byte{
258 ekey("A", 2, 3): records("0", " 1", "2"), 119 ekey("A", 2, 3): records("0", " 1", "2"),
259 ekey("A", 4, 2): records("3", " 4"), 120 ekey("A", 4, 2): records("3", " 4"),
260 ekey("B", 10, 1): records("10"), 121 ekey("B", 10, 1): records("10"),
261 ekey("B", 13, 2): records("12", "13"), 122 ekey("B", 13, 2): records("12", "13"),
262 }) 123 })
263 }) 124 })
264 }) 125 })
265 126
266 Convey(`Testing "Get"...`, func() { 127 Convey(`Testing "Get"...`, func() {
267 Convey(`Can fetch the full row, "A".`, func() { 128 Convey(`Can fetch the full row, "A".`, func() {
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after
355 }) 216 })
356 217
357 Convey(`A tail request for "INVALID" errors NOT FOUND.`, func() { 218 Convey(`A tail request for "INVALID" errors NOT FOUND.`, func() {
358 _, err := tail("INVALID") 219 _, err := tail("INVALID")
359 So(err, ShouldEqual, storage.ErrDoesNotE xist) 220 So(err, ShouldEqual, storage.ErrDoesNotE xist)
360 }) 221 })
361 }) 222 })
362 }) 223 })
363 }) 224 })
364 } 225 }
OLDNEW
« no previous file with comments | « logdog/common/storage/bigtable/storage.go ('k') | logdog/common/storage/bigtable/testing.go » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698