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