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

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

Issue 1838803002: LogDog: BigTable batching schema. (Closed) Base URL: https://github.com/luci/luci-go@recordio-split
Patch Set: Minor comments and quality of code tweaks. Created 4 years, 8 months 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 | « server/logdog/storage/bigtable/storage.go ('k') | server/logdog/storage/memory/memory.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 Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 package bigtable 5 package bigtable
6 6
7 import ( 7 import (
8 "bytes" 8 "bytes"
9 "errors" 9 "errors"
10 "testing" 10 "testing"
11 "time" 11 "time"
12 12
13 "github.com/luci/gkvlite" 13 "github.com/luci/gkvlite"
14 "github.com/luci/luci-go/common/logdog/types" 14 "github.com/luci/luci-go/common/logdog/types"
15 "github.com/luci/luci-go/common/recordio"
15 "github.com/luci/luci-go/server/logdog/storage" 16 "github.com/luci/luci-go/server/logdog/storage"
16 "golang.org/x/net/context" 17 "golang.org/x/net/context"
17 "google.golang.org/cloud/bigtable" 18 "google.golang.org/cloud/bigtable"
18 19
20 . "github.com/luci/luci-go/common/testing/assertions"
19 . "github.com/smartystreets/goconvey/convey" 21 . "github.com/smartystreets/goconvey/convey"
20 ) 22 )
21 23
22 // btTableTest is an in-memory implementation of btTable interface for testing. 24 // btTableTest is an in-memory implementation of btTable interface for testing.
23 // 25 //
24 // This is a simple implementation; not an efficient one. 26 // This is a simple implementation; not an efficient one.
25 type btTableTest struct { 27 type btTableTest struct {
26 s *gkvlite.Store 28 s *gkvlite.Store
27 c *gkvlite.Collection 29 c *gkvlite.Collection
28 30
(...skipping 27 matching lines...) Expand all
56 if t.err != nil { 58 if t.err != nil {
57 return t.err 59 return t.err
58 } 60 }
59 61
60 enc := []byte(rk.encode()) 62 enc := []byte(rk.encode())
61 coll := t.collection() 63 coll := t.collection()
62 if item, _ := coll.Get(enc); item != nil { 64 if item, _ := coll.Get(enc); item != nil {
63 return storage.ErrExists 65 return storage.ErrExists
64 } 66 }
65 67
66 » if err := coll.Set(enc, d); err != nil { 68 » clone := make([]byte, len(d))
69 » copy(clone, d)
70 » if err := coll.Set(enc, clone); err != nil {
67 panic(err) 71 panic(err)
68 } 72 }
69 return nil 73 return nil
70 } 74 }
71 75
72 func (t *btTableTest) getLogData(c context.Context, rk *rowKey, limit int, keysO nly bool, cb btGetCallback) error { 76 func (t *btTableTest) getLogData(c context.Context, rk *rowKey, limit int, keysO nly bool, cb btGetCallback) error {
73 if t.err != nil { 77 if t.err != nil {
74 return t.err 78 return t.err
75 } 79 }
76 80
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
130 return result 134 return result
131 } 135 }
132 136
133 func TestStorage(t *testing.T) { 137 func TestStorage(t *testing.T) {
134 t.Parallel() 138 t.Parallel()
135 139
136 Convey(`A BigTable storage instance bound to a testing BigTable instance `, t, func() { 140 Convey(`A BigTable storage instance bound to a testing BigTable instance `, t, func() {
137 bt := btTableTest{} 141 bt := btTableTest{}
138 defer bt.close() 142 defer bt.close()
139 143
140 » » s := btStorage{ 144 » » s := newBTStorage(context.Background(), Options{
141 » » » Options: &Options{ 145 » » » Project: "test-project",
142 » » » » Project: "test-project", 146 » » » Zone: "test-zone",
143 » » » » Zone: "test-zone", 147 » » » Cluster: "test-cluster",
144 » » » » Cluster: "test-cluster", 148 » » » LogTable: "test-log-table",
145 » » » » LogTable: "test-log-table", 149 » » }, nil, nil)
146 » » » }, 150
147 » » » ctx: context.Background(), 151 » » s.raw = &bt
148 » » » client: nil, 152 » » defer s.Close()
149 » » » table: &bt,
150 » » }
151 153
152 get := func(path string, index int, limit int) ([]string, error) { 154 get := func(path string, index int, limit int) ([]string, error) {
153 req := storage.GetRequest{ 155 req := storage.GetRequest{
154 Path: types.StreamPath(path), 156 Path: types.StreamPath(path),
155 Index: types.MessageIndex(index), 157 Index: types.MessageIndex(index),
156 Limit: limit, 158 Limit: limit,
157 } 159 }
158 got := []string{} 160 got := []string{}
159 » » » err := s.Get(&req, func(idx types.MessageIndex, d []byte ) bool { 161 » » » err := s.Get(req, func(idx types.MessageIndex, d []byte) bool {
160 got = append(got, string(d)) 162 got = append(got, string(d))
161 return true 163 return true
162 }) 164 })
163 return got, err 165 return got, err
164 } 166 }
165 167
166 » » put := func(path string, index int, d string) error { 168 » » put := func(path string, index int, d ...string) error {
167 » » » return s.Put(&storage.PutRequest{ 169 » » » data := make([][]byte, len(d))
168 » » » » Path: types.StreamPath(path), 170 » » » for i, v := range d {
169 » » » » Index: types.MessageIndex(index), 171 » » » » data[i] = []byte(v)
170 » » » » Value: []byte(d), 172 » » » }
173
174 » » » return s.Put(storage.PutRequest{
175 » » » » Path: types.StreamPath(path),
176 » » » » Index: types.MessageIndex(index),
177 » » » » Values: data,
171 }) 178 })
172 } 179 }
173 180
174 » » Convey(`With row data: A{0, 1, 2}, B{10, 12, 13}`, func() { 181 » » ekey := func(p string, v int64) string {
175 » » » So(put("A", 0, "0"), ShouldBeNil) 182 » » » return newRowKey(p, v).encode()
176 » » » So(put("A", 1, "1"), ShouldBeNil) 183 » » }
177 » » » So(put("A", 2, "2"), ShouldBeNil) 184 » » records := func(s ...string) []byte {
185 » » » buf := bytes.Buffer{}
186 » » » w := recordio.NewWriter(&buf)
187
188 » » » for _, v := range s {
189 » » » » if _, err := w.Write([]byte(v)); err != nil {
190 » » » » » panic(err)
191 » » » » }
192 » » » » if err := w.Flush(); err != nil {
193 » » » » » panic(err)
194 » » » » }
195 » » » }
196
197 » » » return buf.Bytes()
198 » » }
199
200 » » Convey(`With an artificial maximum BigTable row size of two reco rds`, func() {
201 » » » // Artificially constrain row size. 4 = 2*{size/1, data/ 1} RecordIO
202 » » » // entries.
203 » » » s.maxRowSize = 4
204
205 » » » Convey(`Will split row data that overflows the table int o multiple rows.`, func() {
206 » » » » So(put("A", 0, "0", "1", "2", "3"), ShouldBeNil)
207
208 » » » » So(bt.dataMap(), ShouldResemble, map[string][]by te{
209 » » » » » ekey("A", 1): records("0", "1"),
210 » » » » » ekey("A", 3): records("2", "3"),
211 » » » » })
212 » » » })
213
214 » » » Convey(`Loading a single row data beyond the maximum row size will fail.`, func() {
215 » » » » So(put("A", 0, "0123"), ShouldErrLike, "single r ow entry exceeds maximum size")
216 » » » })
217 » » })
218
219 » » Convey(`With row data: A{0, 1, 2, 3, 4}, B{10, 12, 13}`, func() {
220 » » » So(put("A", 0, "0", "1", "2"), ShouldBeNil)
221 » » » So(put("A", 3, "3", "4"), ShouldBeNil)
178 So(put("B", 10, "10"), ShouldBeNil) 222 So(put("B", 10, "10"), ShouldBeNil)
179 » » » So(put("B", 12, "12"), ShouldBeNil) 223 » » » So(put("B", 12, "12", "13"), ShouldBeNil)
180 » » » So(put("B", 13, "13"), ShouldBeNil)
181
182 » » » ekey := func(p string, v int64) string {
183 » » » » return newRowKey(p, v).encode()
184 » » » }
185 224
186 Convey(`Testing "Put"...`, func() { 225 Convey(`Testing "Put"...`, func() {
187 Convey(`Loads the row data.`, func() { 226 Convey(`Loads the row data.`, func() {
188 So(bt.dataMap(), ShouldResemble, map[str ing][]byte{ 227 So(bt.dataMap(), ShouldResemble, map[str ing][]byte{
189 » » » » » » ekey("A", 0): []byte("0"), 228 » » » » » » ekey("A", 2): records("0", "1", "2"),
190 » » » » » » ekey("A", 1): []byte("1"), 229 » » » » » » ekey("A", 4): records("3", "4") ,
191 » » » » » » ekey("A", 2): []byte("2"), 230 » » » » » » ekey("B", 10): records("10"),
192 » » » » » » ekey("B", 10): []byte("10"), 231 » » » » » » ekey("B", 13): records("12", "13 "),
193 » » » » » » ekey("B", 12): []byte("12"),
194 » » » » » » ekey("B", 13): []byte("13"),
195 }) 232 })
196 }) 233 })
197 }) 234 })
198 235
199 Convey(`Testing "Get"...`, func() { 236 Convey(`Testing "Get"...`, func() {
200 Convey(`Can fetch the full row, "A".`, func() { 237 Convey(`Can fetch the full row, "A".`, func() {
201 got, err := get("A", 0, 0) 238 got, err := get("A", 0, 0)
202 So(err, ShouldBeNil) 239 So(err, ShouldBeNil)
203 » » » » » So(got, ShouldResemble, []string{"0", "1 ", "2"}) 240 » » » » » So(got, ShouldResemble, []string{"0", "1 ", "2", "3", "4"})
241 » » » » })
242
243 » » » » Convey(`Will fetch A{1, 2, 3, 4} with when index =1.`, func() {
244 » » » » » got, err := get("A", 1, 0)
245 » » » » » So(err, ShouldBeNil)
246 » » » » » So(got, ShouldResemble, []string{"1", "2 ", "3", "4"})
204 }) 247 })
205 248
206 Convey(`Will fetch A{1, 2} with when index=1 and limit=2.`, func() { 249 Convey(`Will fetch A{1, 2} with when index=1 and limit=2.`, func() {
207 got, err := get("A", 1, 2) 250 got, err := get("A", 1, 2)
208 So(err, ShouldBeNil) 251 So(err, ShouldBeNil)
209 So(got, ShouldResemble, []string{"1", "2 "}) 252 So(got, ShouldResemble, []string{"1", "2 "})
210 }) 253 })
211 254
212 Convey(`Will fetch B{10, 12, 13} for B.`, func() { 255 Convey(`Will fetch B{10, 12, 13} for B.`, func() {
213 got, err := get("B", 0, 0) 256 got, err := get("B", 0, 0)
(...skipping 13 matching lines...) Expand all
227 So(got, ShouldResemble, []string{}) 270 So(got, ShouldResemble, []string{})
228 }) 271 })
229 }) 272 })
230 273
231 Convey(`Testing "Tail"...`, func() { 274 Convey(`Testing "Tail"...`, func() {
232 tail := func(path string) (string, error) { 275 tail := func(path string) (string, error) {
233 got, _, err := s.Tail(types.StreamPath(p ath)) 276 got, _, err := s.Tail(types.StreamPath(p ath))
234 return string(got), err 277 return string(got), err
235 } 278 }
236 279
237 » » » » Convey(`A tail request for "A" returns A{2, 1, 0 }.`, func() { 280 » » » » Convey(`A tail request for "A" returns A{4}.`, f unc() {
238 got, err := tail("A") 281 got, err := tail("A")
239 So(err, ShouldBeNil) 282 So(err, ShouldBeNil)
240 » » » » » So(got, ShouldEqual, "2") 283 » » » » » So(got, ShouldEqual, "4")
241 }) 284 })
242 285
243 Convey(`A tail request for "B" returns B{13}.`, func() { 286 Convey(`A tail request for "B" returns B{13}.`, func() {
244 got, err := tail("B") 287 got, err := tail("B")
245 So(err, ShouldBeNil) 288 So(err, ShouldBeNil)
246 So(got, ShouldEqual, "13") 289 So(got, ShouldEqual, "13")
247 }) 290 })
248 291
249 Convey(`A tail request for "INVALID" errors NOT FOUND.`, func() { 292 Convey(`A tail request for "INVALID" errors NOT FOUND.`, func() {
250 _, err := tail("INVALID") 293 _, err := tail("INVALID")
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
296 }) 339 })
297 340
298 Convey(`With return an error if the configuration fails to apply.`, func() { 341 Convey(`With return an error if the configuration fails to apply.`, func() {
299 bt.err = errors.New("test error") 342 bt.err = errors.New("test error")
300 343
301 So(s.Config(cfg), ShouldEqual, bt.err) 344 So(s.Config(cfg), ShouldEqual, bt.err)
302 }) 345 })
303 }) 346 })
304 }) 347 })
305 } 348 }
OLDNEW
« no previous file with comments | « server/logdog/storage/bigtable/storage.go ('k') | server/logdog/storage/memory/memory.go » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698