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

Side by Side Diff: common/data/treapstore/store_test.go

Issue 2607663002: Add treapstore, a treap-based in-memory data store (Closed)
Patch Set: Fix test race, better docs, valid zero values. Created 3 years, 11 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 | « common/data/treapstore/store.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
(Empty)
1 // Copyright 2016 The LUCI Authors. All rights reserved.
2 // Use of this source code is governed under the Apache License, Version 2.0
3 // that can be found in the LICENSE file.
4
5 package treapstore
6
7 import (
8 "fmt"
9 "strconv"
10 "strings"
11 "testing"
12
13 "github.com/luci/gtreap"
14
15 . "github.com/smartystreets/goconvey/convey"
16 )
17
18 func stringCompare(a, b interface{}) int {
19 return strings.Compare(a.(string), b.(string))
20 }
21
22 func putMulti(c *Collection, vs ...string) {
23 for _, v := range vs {
24 c.Put(v)
25 }
26 }
27
28 func iterAll(it *gtreap.Iterator) []string {
29 all := []string{}
30 for {
31 v, ok := it.Next()
32 if !ok {
33 return all
34 }
35 all = append(all, v.(string))
36 }
37 }
38
39 func TestStore(t *testing.T) {
40 t.Parallel()
41
42 Convey(`Testing a string Store`, t, func() {
43 st := New()
44 coll := st.CreateCollection("test", stringCompare)
45
46 Convey(`When empty`, func() {
47 checkEmpty := func(c *Collection) {
48 So(c.Get("foo"), ShouldBeNil)
49 So(iterAll(c.Iterator("")), ShouldResemble, []st ring{})
50 }
51
52 // Check the basic Store.
53 checkEmpty(coll)
54
55 // Take a snapshot, then mutate the base Store. Assert t hat the snapshot
56 // is still empty.
57 snap := st.Snapshot()
58 coll.Put("foo")
59 checkEmpty(snap.GetCollection("test"))
60 })
61
62 Convey(`With keys`, func() {
63 putMulti(coll, "x", "w", "b", "a")
64
65 Convey(`Can iterate`, func() {
66 checkKeys := func(coll *Collection, keys ...stri ng) {
67 for _, k := range keys {
68 So(coll.Get(k), ShouldEqual, k)
69 }
70
71 So(iterAll(coll.Iterator("")), ShouldRes emble, keys)
72 for i, k := range keys {
73 So(iterAll(coll.Iterator(k)), Sh ouldResemble, keys[i:])
74 So(iterAll(coll.Iterator(k+"1")) , ShouldResemble, keys[i+1:])
75 }
76 }
77 checkKeys(coll, "a", "b", "w", "x")
78
79 // Take a snapshot, then mutate the base Store. Assert that the snapshot
80 // is still empty.
81 snap := st.Snapshot()
82 snapColl := snap.GetCollection("test")
83 putMulti(coll, "foo")
84 coll.Delete("b")
85 checkKeys(snapColl, "a", "b", "w", "x")
86 checkKeys(coll, "a", "foo", "w", "x")
87 })
88
89 Convey(`Modified after a snapshot`, func() {
90 snap := st.Snapshot()
91 snapColl := snap.GetCollection("test")
92 putMulti(coll, "z")
93
94 Convey(`A snapshot of a snapshot is itself.`, fu nc() {
95 So(snap.Snapshot(), ShouldEqual, snap)
96 })
97
98 Convey(`A snapshot is read-only, and cannot crea te collections.`, func() {
99 So(func() { snap.CreateCollection("new", stringCompare) }, ShouldPanic)
100 })
101
102 Convey(`Can get its collection name`, func() {
103 So(coll.Name(), ShouldEqual, "test")
104 So(snapColl.Name(), ShouldEqual, "test")
105 })
106
107 Convey(`Can fetch the Min and Max`, func() {
108 So(coll.Min(), ShouldResemble, "a")
109 So(coll.Max(), ShouldResemble, "z")
110
111 So(snapColl.Min(), ShouldResemble, "a")
112 So(snapColl.Max(), ShouldResemble, "x")
113 })
114
115 Convey(`Cannot Put to a read-only snapshot.`, fu nc() {
116 So(func() { snapColl.Put("panic") }, Sho uldPanic)
117 })
118 })
119 })
120
121 Convey(`Creating a Collection with a duplicate name will panic.` , func() {
122 So(func() { st.CreateCollection("test", stringCompare) } , ShouldPanic)
123 })
124
125 Convey(`With multiple Collections`, func() {
126 for _, v := range []string{"foo", "bar", "baz"} {
127 st.CreateCollection(v, stringCompare)
128 }
129 So(st.GetCollectionNames(), ShouldResemble, []string{"ba r", "baz", "foo", "test"})
130 snap := st.Snapshot()
131 So(snap.GetCollectionNames(), ShouldResemble, []string{" bar", "baz", "foo", "test"})
132
133 Convey(`When new Collections are added, names remain sor ted.`, func() {
134 for _, v := range []string{"app", "cat", "bas", "qux"} {
135 st.CreateCollection(v, stringCompare)
136 }
137 So(st.GetCollectionNames(), ShouldResemble,
138 []string{"app", "bar", "bas", "baz", "ca t", "foo", "qux", "test"})
139 So(st.Snapshot().GetCollectionNames(), ShouldRes emble,
140 []string{"app", "bar", "bas", "baz", "ca t", "foo", "qux", "test"})
141 So(snap.GetCollectionNames(), ShouldResemble, [] string{"bar", "baz", "foo", "test"})
142 })
143 })
144 })
145 }
146
147 func TestStoreZeroValue(t *testing.T) {
148 t.Parallel()
149
150 Convey(`A Store's zero value is valid, empty, and read-only.`, t, func() {
151 s := Store{}
152
153 So(s.IsReadOnly(), ShouldBeTrue)
154 So(s.GetCollectionNames(), ShouldBeNil)
155 So(s.GetCollection("foo"), ShouldBeNil)
156 So(s.Snapshot(), ShouldEqual, &s)
157 })
158 }
159
160 func TestCollectionZeroValue(t *testing.T) {
161 t.Parallel()
162
163 Convey(`A Collection's zero value is valid, empty, and read-only.`, t, f unc() {
164 c := Collection{}
165
166 So(c.IsReadOnly(), ShouldBeTrue)
167 So(c.Name(), ShouldEqual, "")
168 So(c.Get("foo"), ShouldBeNil)
169 So(c.Min(), ShouldBeNil)
170 So(c.Max(), ShouldBeNil)
171
172 it := c.Iterator(nil)
173 So(it, ShouldNotBeNil)
174 So(iterAll(it), ShouldHaveLength, 0)
175 })
176 }
177
178 // TestStoreParallel performs several rounds of parallel accesses. Each round
179 // takes a snapshot of the "head" Store, then simultaneusly dispatches a round
180 // of parallel writes agains the "head" store, reads against the snapshot, and
181 // reads against the "head" store.
182 //
183 // This is meant to be run with "-race" to trigger on race conditions.
184 func TestStoreParallel(t *testing.T) {
185 t.Parallel()
186
187 Convey(`Testing a string Store for parallel access.`, t, func() {
188 const (
189 readers = 128
190 writers = 16
191 rounds = 8
192 )
193
194 head := New()
195 head.CreateCollection("", stringCompare)
196 var snaps []*Store
197
198 // Dispatch readers.
199 doReads := func() int {
200 readDoneC := make(chan int, readers)
201 for i := 0; i < readers; i++ {
202 go func() {
203 var (
204 doneC = make(chan int, 1+len(sna ps))
205 )
206
207 // "head"
208 go func() {
209 doneC <- len(iterAll(head.GetCol lection("").Iterator("")))
210 }()
211
212 // "snap"
213 for _, snap := range snaps {
214 go func(snap *Store) {
215 doneC <- len(iterAll(sna p.GetCollection("").Iterator("")))
216 }(snap)
217 }
218
219 total := 0
220 for i := 0; i < 1+len(snaps); i++ {
221 total += <-doneC
222 }
223 readDoneC <- total
224 }()
225 }
226
227 total := 0
228 for i := 0; i < readers; i++ {
229 total += <-readDoneC
230 }
231 return total
232 }
233
234 // Dispatch writers.
235 doWrite := func(base string) {
236 writeDoneC := make(chan struct{}, writers)
237 for i := 0; i < writers; i++ {
238 go func(idx int) {
239 head.GetCollection("").Put(fmt.Sprintf(" %s.%d", base, idx))
240 writeDoneC <- struct{}{}
241 }(i)
242 }
243
244 for i := 0; i < writers; i++ {
245 <-writeDoneC
246 }
247 }
248
249 // Main loop.
250 for i := 0; i < rounds; i++ {
251 writeDoneC := make(chan struct{})
252 readDoneC := make(chan int)
253 go func() {
254 doWrite(strconv.Itoa(i))
255 close(writeDoneC)
256 }()
257 // The first round has to actually create the Collection .
258 go func() {
259 readDoneC <- doReads()
260 }()
261
262 <-writeDoneC
263 So(<-readDoneC, ShouldBeGreaterThan, 0)
264 snaps = append(snaps, head.Snapshot())
265 }
266 })
267 }
OLDNEW
« no previous file with comments | « common/data/treapstore/store.go ('k') | logdog/common/storage/bigtable/testing.go » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698