blob: dbd0feaea235246d02c1a429a44c1980fcd31691 [file] [log] [blame]
Himabindu Puchad964ef02015-06-30 01:10:47 -07001// Copyright 2015 The Vanadium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package vsync
6
7import (
8 "fmt"
9 "math/rand"
10 "reflect"
11 "testing"
12 "time"
13
Himabindu Puchad964ef02015-06-30 01:10:47 -070014 "v.io/v23/naming"
15 "v.io/v23/rpc"
16 "v.io/v23/security"
Raja Daoudd4543072015-06-30 11:15:55 -070017 _ "v.io/x/ref/runtime/factories/generic"
Adam Sadovskyf2efeb52015-08-31 14:17:49 -070018 "v.io/x/ref/services/syncbase/server/interfaces"
19 "v.io/x/ref/services/syncbase/server/watchable"
Himabindu Puchad964ef02015-06-30 01:10:47 -070020)
21
22// TestDiffPrefixGenVectors tests diffing prefix gen vectors.
23func TestDiffPrefixGenVectors(t *testing.T) {
24 svc := createService(t)
25 defer destroyService(t, svc)
26 s := svc.sync
27 s.id = 10 //responder. Initiator is id 11.
28
29 tests := []struct {
30 respPVec, initPVec interfaces.PrefixGenVector
31 genDiffIn genRangeVector
32 genDiffWant genRangeVector
33 }{
34 { // responder and initiator are at identical vectors.
35 respPVec: interfaces.PrefixGenVector{10: 1, 11: 10, 12: 20, 13: 2},
36 initPVec: interfaces.PrefixGenVector{10: 1, 11: 10, 12: 20, 13: 2},
37 genDiffIn: make(genRangeVector),
38 },
39 { // responder and initiator are at identical vectors.
40 respPVec: interfaces.PrefixGenVector{10: 0},
41 initPVec: interfaces.PrefixGenVector{10: 0},
42 genDiffIn: make(genRangeVector),
43 },
44 { // responder has no updates.
45 respPVec: interfaces.PrefixGenVector{10: 0},
46 initPVec: interfaces.PrefixGenVector{10: 5, 11: 10, 12: 20, 13: 8},
47 genDiffIn: make(genRangeVector),
48 },
49 { // responder and initiator have no updates.
50 respPVec: interfaces.PrefixGenVector{10: 0},
51 initPVec: interfaces.PrefixGenVector{11: 0},
52 genDiffIn: make(genRangeVector),
53 },
54 { // responder is staler than initiator.
55 respPVec: interfaces.PrefixGenVector{10: 1, 11: 10, 12: 20, 13: 2},
56 initPVec: interfaces.PrefixGenVector{10: 1, 11: 10, 12: 20, 13: 8, 14: 5},
57 genDiffIn: make(genRangeVector),
58 },
59 { // responder is more up-to-date than initiator for local updates.
60 respPVec: interfaces.PrefixGenVector{10: 5, 11: 10, 12: 20, 13: 2},
61 initPVec: interfaces.PrefixGenVector{10: 1, 11: 10, 12: 20, 13: 2},
62 genDiffIn: make(genRangeVector),
63 genDiffWant: genRangeVector{10: &genRange{min: 2, max: 5}},
64 },
65 { // responder is fresher than initiator for local updates and one device.
66 respPVec: interfaces.PrefixGenVector{10: 5, 11: 10, 12: 22, 13: 2},
67 initPVec: interfaces.PrefixGenVector{10: 1, 11: 10, 12: 20, 13: 2, 14: 40},
68 genDiffIn: make(genRangeVector),
69 genDiffWant: genRangeVector{
70 10: &genRange{min: 2, max: 5},
71 12: &genRange{min: 21, max: 22},
72 },
73 },
74 { // responder is fresher than initiator in all but one device.
75 respPVec: interfaces.PrefixGenVector{10: 1, 11: 2, 12: 3, 13: 4},
76 initPVec: interfaces.PrefixGenVector{10: 0, 11: 2, 12: 0},
77 genDiffIn: make(genRangeVector),
78 genDiffWant: genRangeVector{
79 10: &genRange{min: 1, max: 1},
80 12: &genRange{min: 1, max: 3},
81 13: &genRange{min: 1, max: 4},
82 },
83 },
84 { // initiator has no updates.
85 respPVec: interfaces.PrefixGenVector{10: 1, 11: 2, 12: 3, 13: 4},
86 initPVec: interfaces.PrefixGenVector{},
87 genDiffIn: make(genRangeVector),
88 genDiffWant: genRangeVector{
89 10: &genRange{min: 1, max: 1},
90 11: &genRange{min: 1, max: 2},
91 12: &genRange{min: 1, max: 3},
92 13: &genRange{min: 1, max: 4},
93 },
94 },
95 { // initiator has no updates, pre-existing diff.
96 respPVec: interfaces.PrefixGenVector{10: 1, 11: 2, 12: 3, 13: 4},
97 initPVec: interfaces.PrefixGenVector{13: 1},
98 genDiffIn: genRangeVector{
99 10: &genRange{min: 5, max: 20},
100 13: &genRange{min: 1, max: 3},
101 },
102 genDiffWant: genRangeVector{
103 10: &genRange{min: 1, max: 20},
104 11: &genRange{min: 1, max: 2},
105 12: &genRange{min: 1, max: 3},
106 13: &genRange{min: 1, max: 4},
107 },
108 },
109 }
110
111 for _, test := range tests {
112 want := test.genDiffWant
113 got := test.genDiffIn
Raja Daoudccfd6c12015-08-03 18:46:28 -0700114 rSt := newResponderState(nil, nil, s, interfaces.DeltaReq{}, "fakeInitiator")
Himabindu Puchad964ef02015-06-30 01:10:47 -0700115 rSt.diff = got
116 rSt.diffPrefixGenVectors(test.respPVec, test.initPVec)
117 checkEqualDevRanges(t, got, want)
118 }
119}
120
121// TestSendDeltas tests the computation of the delta bound (computeDeltaBound)
122// and if the log records on the wire are correctly ordered (phases 2 and 3 of
123// SendDeltas).
124func TestSendDeltas(t *testing.T) {
125 appName := "mockapp"
126 dbName := "mockdb"
127
128 tests := []struct {
129 respVec, initVec, outVec interfaces.GenVector
130 respGen uint64
131 genDiff genRangeVector
132 keyPfxs []string
133 }{
134 { // Identical prefixes, local and remote updates.
135 respVec: interfaces.GenVector{
136 "foo": interfaces.PrefixGenVector{12: 8},
137 "foobar": interfaces.PrefixGenVector{12: 10},
138 },
139 initVec: interfaces.GenVector{
140 "foo": interfaces.PrefixGenVector{11: 5},
141 "foobar": interfaces.PrefixGenVector{11: 5},
142 },
143 respGen: 5,
144 outVec: interfaces.GenVector{
145 "foo": interfaces.PrefixGenVector{10: 5, 12: 8},
146 "foobar": interfaces.PrefixGenVector{10: 5, 12: 10},
147 },
148 genDiff: genRangeVector{
149 10: &genRange{min: 1, max: 5},
150 12: &genRange{min: 1, max: 10},
151 },
152 keyPfxs: []string{"baz", "wombat", "f", "foo", "foobar", ""},
153 },
154 { // Identical prefixes, local and remote updates.
155 respVec: interfaces.GenVector{
156 "bar": interfaces.PrefixGenVector{12: 20},
157 "foo": interfaces.PrefixGenVector{12: 8},
158 "foobar": interfaces.PrefixGenVector{12: 10},
159 },
160 initVec: interfaces.GenVector{
161 "foo": interfaces.PrefixGenVector{11: 5},
162 "foobar": interfaces.PrefixGenVector{11: 5, 12: 10},
163 "bar": interfaces.PrefixGenVector{10: 5, 11: 5, 12: 5},
164 },
165 respGen: 5,
166 outVec: interfaces.GenVector{
167 "foo": interfaces.PrefixGenVector{10: 5, 12: 8},
168 "foobar": interfaces.PrefixGenVector{10: 5, 12: 10},
169 "bar": interfaces.PrefixGenVector{10: 5, 12: 20},
170 },
171 genDiff: genRangeVector{
172 10: &genRange{min: 1, max: 5},
173 12: &genRange{min: 1, max: 20},
174 },
175 keyPfxs: []string{"baz", "wombat", "f", "foo", "foobar", "bar", "barbaz", ""},
176 },
177 { // Non-identical prefixes, local only updates.
178 initVec: interfaces.GenVector{
179 "foo": interfaces.PrefixGenVector{11: 5},
180 "foobar": interfaces.PrefixGenVector{11: 5},
181 },
182 respGen: 5,
183 outVec: interfaces.GenVector{
184 "foo": interfaces.PrefixGenVector{10: 5},
185 },
186 genDiff: genRangeVector{
187 10: &genRange{min: 1, max: 5},
188 },
189 keyPfxs: []string{"baz", "wombat", "f", "foo", "foobar", "", "fo", "fooxyz"},
190 },
191 { // Non-identical prefixes, local and remote updates.
192 respVec: interfaces.GenVector{
193 "f": interfaces.PrefixGenVector{12: 5, 13: 5},
194 "foo": interfaces.PrefixGenVector{12: 10, 13: 10},
195 "foobar": interfaces.PrefixGenVector{12: 20, 13: 20},
196 },
197 initVec: interfaces.GenVector{
198 "foo": interfaces.PrefixGenVector{11: 5, 12: 1},
199 },
200 respGen: 5,
201 outVec: interfaces.GenVector{
202 "foo": interfaces.PrefixGenVector{10: 5, 12: 10, 13: 10},
203 "foobar": interfaces.PrefixGenVector{10: 5, 12: 20, 13: 20},
204 },
205 genDiff: genRangeVector{
206 10: &genRange{min: 1, max: 5},
207 12: &genRange{min: 2, max: 20},
208 13: &genRange{min: 1, max: 20},
209 },
210 keyPfxs: []string{"baz", "wombat", "f", "foo", "foobar", "", "fo", "fooxyz"},
211 },
212 { // Non-identical prefixes, local and remote updates.
213 respVec: interfaces.GenVector{
214 "foobar": interfaces.PrefixGenVector{12: 20, 13: 20},
215 },
216 initVec: interfaces.GenVector{
217 "foo": interfaces.PrefixGenVector{11: 5, 12: 1},
218 },
219 respGen: 5,
220 outVec: interfaces.GenVector{
221 "foo": interfaces.PrefixGenVector{10: 5},
222 "foobar": interfaces.PrefixGenVector{10: 5, 12: 20, 13: 20},
223 },
224 genDiff: genRangeVector{
225 10: &genRange{min: 1, max: 5},
226 12: &genRange{min: 2, max: 20},
227 13: &genRange{min: 1, max: 20},
228 },
229 keyPfxs: []string{"baz", "wombat", "f", "foo", "foobar", "", "fo", "fooxyz"},
230 },
231 { // Non-identical prefixes, local and remote updates.
232 respVec: interfaces.GenVector{
233 "f": interfaces.PrefixGenVector{12: 20, 13: 20},
234 },
235 initVec: interfaces.GenVector{
236 "foo": interfaces.PrefixGenVector{11: 5, 12: 1},
237 },
238 respGen: 5,
239 outVec: interfaces.GenVector{
240 "foo": interfaces.PrefixGenVector{10: 5, 12: 20, 13: 20},
241 },
242 genDiff: genRangeVector{
243 10: &genRange{min: 1, max: 5},
244 12: &genRange{min: 2, max: 20},
245 13: &genRange{min: 1, max: 20},
246 },
247 keyPfxs: []string{"baz", "wombat", "f", "foo", "foobar", "", "fo", "fooxyz"},
248 },
249 { // Non-identical interleaving prefixes.
250 respVec: interfaces.GenVector{
251 "f": interfaces.PrefixGenVector{12: 20, 13: 10},
252 "foo": interfaces.PrefixGenVector{12: 30, 13: 20},
253 "foobar": interfaces.PrefixGenVector{12: 40, 13: 30},
254 },
255 initVec: interfaces.GenVector{
256 "fo": interfaces.PrefixGenVector{11: 5, 12: 1},
257 "foob": interfaces.PrefixGenVector{11: 5, 12: 10},
258 "foobarxyz": interfaces.PrefixGenVector{11: 5, 12: 20},
259 },
260 respGen: 5,
261 outVec: interfaces.GenVector{
262 "fo": interfaces.PrefixGenVector{10: 5, 12: 20, 13: 10},
263 "foo": interfaces.PrefixGenVector{10: 5, 12: 30, 13: 20},
264 "foobar": interfaces.PrefixGenVector{10: 5, 12: 40, 13: 30},
265 },
266 genDiff: genRangeVector{
267 10: &genRange{min: 1, max: 5},
268 12: &genRange{min: 2, max: 40},
269 13: &genRange{min: 1, max: 30},
270 },
271 keyPfxs: []string{"baz", "wombat", "f", "foo", "foobar", "", "fo", "foob", "foobarxyz", "fooxyz"},
272 },
273 { // Non-identical interleaving prefixes.
274 respVec: interfaces.GenVector{
275 "fo": interfaces.PrefixGenVector{12: 20, 13: 10},
276 "foob": interfaces.PrefixGenVector{12: 30, 13: 20},
277 "foobarxyz": interfaces.PrefixGenVector{12: 40, 13: 30},
278 },
279 initVec: interfaces.GenVector{
280 "f": interfaces.PrefixGenVector{11: 5, 12: 1},
281 "foo": interfaces.PrefixGenVector{11: 5, 12: 10},
282 "foobar": interfaces.PrefixGenVector{11: 5, 12: 20},
283 },
284 respGen: 5,
285 outVec: interfaces.GenVector{
286 "f": interfaces.PrefixGenVector{10: 5},
287 "fo": interfaces.PrefixGenVector{10: 5, 12: 20, 13: 10},
288 "foob": interfaces.PrefixGenVector{10: 5, 12: 30, 13: 20},
289 "foobarxyz": interfaces.PrefixGenVector{10: 5, 12: 40, 13: 30},
290 },
291 genDiff: genRangeVector{
292 10: &genRange{min: 1, max: 5},
293 12: &genRange{min: 2, max: 40},
294 13: &genRange{min: 1, max: 30},
295 },
296 keyPfxs: []string{"baz", "wombat", "f", "foo", "foobar", "", "fo", "foob", "foobarxyz", "fooxyz"},
297 },
298 { // Non-identical sibling prefixes.
299 respVec: interfaces.GenVector{
300 "foo": interfaces.PrefixGenVector{12: 20, 13: 10},
301 "foobarabc": interfaces.PrefixGenVector{12: 40, 13: 30},
302 "foobarxyz": interfaces.PrefixGenVector{12: 30, 13: 20},
303 },
304 initVec: interfaces.GenVector{
305 "foo": interfaces.PrefixGenVector{11: 5, 12: 1},
306 },
307 respGen: 5,
308 outVec: interfaces.GenVector{
309 "foo": interfaces.PrefixGenVector{10: 5, 12: 20, 13: 10},
310 "foobarabc": interfaces.PrefixGenVector{10: 5, 12: 40, 13: 30},
311 "foobarxyz": interfaces.PrefixGenVector{10: 5, 12: 30, 13: 20},
312 },
313 genDiff: genRangeVector{
314 10: &genRange{min: 1, max: 5},
315 12: &genRange{min: 2, max: 40},
316 13: &genRange{min: 1, max: 30},
317 },
318 keyPfxs: []string{"baz", "wombat", "f", "foo", "foobar", "", "foobarabc", "foobarxyz", "foobar123", "fooxyz"},
319 },
320 { // Non-identical prefixes, local and remote updates.
321 respVec: interfaces.GenVector{
322 "barbaz": interfaces.PrefixGenVector{12: 18},
323 "f": interfaces.PrefixGenVector{12: 30, 13: 5},
324 "foobar": interfaces.PrefixGenVector{12: 30, 13: 8},
325 },
326 initVec: interfaces.GenVector{
327 "foo": interfaces.PrefixGenVector{11: 5, 12: 5},
328 "foobar": interfaces.PrefixGenVector{11: 5, 12: 5},
329 "bar": interfaces.PrefixGenVector{10: 5, 11: 5, 12: 5},
330 },
331 respGen: 5,
332 outVec: interfaces.GenVector{
333 "foo": interfaces.PrefixGenVector{10: 5, 12: 30, 13: 5},
334 "foobar": interfaces.PrefixGenVector{10: 5, 12: 30, 13: 8},
335 "bar": interfaces.PrefixGenVector{10: 5},
336 "barbaz": interfaces.PrefixGenVector{10: 5, 12: 18},
337 },
338 genDiff: genRangeVector{
339 10: &genRange{min: 1, max: 5},
340 12: &genRange{min: 6, max: 30},
341 13: &genRange{min: 1, max: 8},
342 },
343 keyPfxs: []string{"baz", "wombat", "f", "foo", "foobar", "bar", "barbaz", ""},
344 },
345 }
346
347 for i, test := range tests {
348 svc := createService(t)
349 s := svc.sync
350 s.id = 10 //responder.
351
352 wantDiff, wantVec := test.genDiff, test.outVec
Himabindu Pucha0ff9b0c2015-07-14 11:40:45 -0700353 s.syncState[appDbName(appName, dbName)] = &dbSyncStateInMem{gen: test.respGen, checkptGen: test.respGen, genvec: test.respVec}
Himabindu Puchad964ef02015-06-30 01:10:47 -0700354
355 req := interfaces.DeltaReq{AppName: appName, DbName: dbName, InitVec: test.initVec}
Raja Daoudccfd6c12015-08-03 18:46:28 -0700356 rSt := newResponderState(nil, nil, s, req, "fakeInitiator")
Himabindu Puchad964ef02015-06-30 01:10:47 -0700357
358 rSt.computeDeltaBound(nil)
359 if rSt.errState != nil || !reflect.DeepEqual(rSt.outVec, wantVec) {
360 t.Fatalf("computeDeltaBound failed (I: %v), (R: %v, %v), got %v, want %v err %v", test.initVec, test.respGen, test.respVec, rSt.outVec, wantVec, rSt.errState)
361 }
362 checkEqualDevRanges(t, rSt.diff, wantDiff)
363
364 ////////////////////////////////////////
365 // Test sending deltas.
366
367 // Insert some log records to bootstrap testing below.
368 tRng := rand.New(rand.NewSource(int64(i)))
369 var wantRecs []*localLogRec
370 st := svc.St()
371 tx := st.NewTransaction()
372 objKeyPfxs := test.keyPfxs
373 j := 0
374 for id, r := range wantDiff {
375 pos := uint64(tRng.Intn(50) + 100*j)
376 for k := r.min; k <= r.max; k++ {
377 opfx := objKeyPfxs[tRng.Intn(len(objKeyPfxs))]
378 // Create holes in the log records.
379 if opfx == "" {
380 continue
381 }
Raja Daoud7cb71792015-07-08 12:00:33 -0700382 okey := makeRowKey(fmt.Sprintf("%s~%x", opfx, tRng.Int()))
Himabindu Puchad964ef02015-06-30 01:10:47 -0700383 vers := fmt.Sprintf("%x", tRng.Int())
384 rec := &localLogRec{
385 Metadata: interfaces.LogRecMetadata{Id: id, Gen: k, ObjId: okey, CurVers: vers, UpdTime: time.Now().UTC()},
386 Pos: pos + k,
387 }
388 if err := putLogRec(nil, tx, rec); err != nil {
389 t.Fatalf("putLogRec(%d:%d) failed rec %v err %v", id, k, rec, err)
390 }
Raja Daoud7cb71792015-07-08 12:00:33 -0700391 value := fmt.Sprintf("value_%s", okey)
392 if err := watchable.PutAtVersion(nil, tx, []byte(okey), []byte(value), []byte(vers)); err != nil {
393 t.Fatalf("PutAtVersion(%d:%d) failed rec %v value %s: err %v", id, k, rec, value, err)
394 }
Himabindu Puchad964ef02015-06-30 01:10:47 -0700395
396 initPfxs := extractAndSortPrefixes(test.initVec)
397 if !filterLogRec(rec, test.initVec, initPfxs) {
398 wantRecs = append(wantRecs, rec)
399 }
400 }
401 j++
402 }
403 if err := tx.Commit(); err != nil {
404 t.Fatalf("cannot commit putting log rec, err %v", err)
405 }
406
407 d := &dummyResponder{}
408 rSt.call = d
409 rSt.st, rSt.errState = rSt.sync.getDbStore(nil, nil, rSt.req.AppName, rSt.req.DbName)
410 if rSt.errState != nil {
411 t.Fatalf("filterAndSendDeltas failed to get store handle for app/db %v %v", rSt.req.AppName, rSt.req.DbName)
412 }
413 err := rSt.filterAndSendDeltas(nil)
414 if err != nil {
415 t.Fatalf("filterAndSendDeltas failed (I: %v), (R: %v, %v) err %v", test.initVec, test.respGen, test.respVec, err)
416 }
417 d.diffLogRecs(t, wantRecs, wantVec)
418
419 destroyService(t, svc)
420 }
421}
422
423//////////////////////////////
424// Helpers
425
426type dummyResponder struct {
427 start, finish int
428 gotRecs []*localLogRec
429 outVec interfaces.GenVector
430}
431
432func (d *dummyResponder) RecvStream() interface {
433 Advance() bool
434 Value() interfaces.DeltaReq
435 Err() error
436} {
437 return d
438}
439
440func (d *dummyResponder) Advance() bool {
441 return false
442}
443
444func (d *dummyResponder) Value() interfaces.DeltaReq {
445 return interfaces.DeltaReq{}
446}
447
448func (d *dummyResponder) Err() error { return nil }
449
450func (d *dummyResponder) SendStream() interface {
451 Send(item interfaces.DeltaResp) error
452} {
453 return d
454}
455
456func (d *dummyResponder) Send(item interfaces.DeltaResp) error {
457 switch v := item.(type) {
458 case interfaces.DeltaRespStart:
459 d.start++
460 case interfaces.DeltaRespFinish:
461 d.finish++
462 case interfaces.DeltaRespRespVec:
463 d.outVec = v.Value
464 case interfaces.DeltaRespRec:
465 d.gotRecs = append(d.gotRecs, &localLogRec{Metadata: v.Value.Metadata})
466 }
467 return nil
468}
469
470func (d *dummyResponder) Security() security.Call {
471 return nil
472}
473
474func (d *dummyResponder) Suffix() string {
475 return ""
476}
477
478func (d *dummyResponder) LocalEndpoint() naming.Endpoint {
479 return nil
480}
481
482func (d *dummyResponder) RemoteEndpoint() naming.Endpoint {
483 return nil
484}
485
486func (d *dummyResponder) GrantedBlessings() security.Blessings {
487 return security.Blessings{}
488}
489
Matt Rosencrantz98d6d7c2015-09-04 12:34:08 -0700490func (d *dummyResponder) Server() rpc.Server {
Himabindu Puchad964ef02015-06-30 01:10:47 -0700491 return nil
492}
493
494func (d *dummyResponder) diffLogRecs(t *testing.T, wantRecs []*localLogRec, wantVec interfaces.GenVector) {
495 if d.start != 1 || d.finish != 1 {
496 t.Fatalf("diffLogRecs incorrect start/finish records (%v, %v)", d.start, d.finish)
497 }
498 if len(d.gotRecs) != len(wantRecs) {
499 t.Fatalf("diffLogRecs failed, gotLen %v, wantLen %v\n", len(d.gotRecs), len(wantRecs))
500 }
501 for i, rec := range d.gotRecs {
502 if !reflect.DeepEqual(rec.Metadata, wantRecs[i].Metadata) {
503 t.Fatalf("diffLogRecs failed, i %v, got %v, want %v\n", i, rec.Metadata, wantRecs[i].Metadata)
504 }
505 }
506 if !reflect.DeepEqual(d.outVec, wantVec) {
507 t.Fatalf("diffLogRecs failed genvector, got %v, want %v\n", d.outVec, wantVec)
508 }
509}
510
511func checkEqualDevRanges(t *testing.T, s1, s2 genRangeVector) {
512 if len(s1) != len(s2) {
513 t.Fatalf("len(s1): %v != len(s2): %v", len(s1), len(s2))
514 }
515 for d1, r1 := range s1 {
516 if r2, ok := s2[d1]; !ok || !reflect.DeepEqual(r1, r2) {
517 t.Fatalf("Dev %v: r1 %v != r2 %v", d1, r1, r2)
518 }
519 }
520}