blob: 7db175555eeca7cb84cbfec57c30aea484d58379 [file] [log] [blame]
Jatin Lodhia45a1fa82015-06-18 11:51:04 -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 watchable
6
7import (
8 "fmt"
9 "io/ioutil"
Raja Daoudd4543072015-06-30 11:15:55 -070010 "math"
Jatin Lodhia101bd212015-06-22 13:35:53 -070011 "time"
Jatin Lodhia45a1fa82015-06-18 11:51:04 -070012
13 "v.io/syncbase/x/ref/services/syncbase/clock"
14 "v.io/syncbase/x/ref/services/syncbase/store"
15 "v.io/syncbase/x/ref/services/syncbase/store/leveldb"
16 "v.io/syncbase/x/ref/services/syncbase/store/memstore"
17 "v.io/v23/vom"
18)
19
20// This file provides utility methods for tests related to watchable store.
21
Adam Sadovsky4dcc3532015-07-31 13:54:19 -070022////////////////////////////////////////////////////////////
23// Functions for store creation/cleanup
Jatin Lodhia45a1fa82015-06-18 11:51:04 -070024
Jatin Lodhia101bd212015-06-22 13:35:53 -070025// createStore returns a store along with a function to destroy the store
26// once it is no longer needed.
Adam Sadovsky4dcc3532015-07-31 13:54:19 -070027func createStore() (store.Store, func()) {
Jatin Lodhia45a1fa82015-06-18 11:51:04 -070028 var st store.Store
Adam Sadovsky4dcc3532015-07-31 13:54:19 -070029 // With Memstore, TestReadWriteRandom is slow with ManagedPrefixes=nil since
30 // every watchable.Store.Get() takes a snapshot, and memstore snapshots are
31 // relatively expensive since the entire data map is copied. LevelDB snapshots
32 // are cheap, so with LevelDB ManagedPrefixes=nil is still reasonably fast.
33 if false {
Jatin Lodhia45a1fa82015-06-18 11:51:04 -070034 st = memstore.New()
35 return st, func() {
36 st.Close()
37 }
38 } else {
39 st = createLevelDB(getPath())
40 return st, func() {
41 destroyLevelDB(st, getPath())
42 }
43 }
44}
45
46func getPath() string {
47 path, err := ioutil.TempDir("", "syncbase_leveldb")
48 if err != nil {
49 panic(fmt.Sprintf("can't create temp dir: %v", err))
50 }
51 return path
52}
53
54func createLevelDB(path string) store.Store {
Adam Sadovskyb6a5aa32015-07-07 13:05:26 -070055 st, err := leveldb.Open(path, leveldb.OpenOptions{CreateIfMissing: true, ErrorIfExists: true})
Jatin Lodhia45a1fa82015-06-18 11:51:04 -070056 if err != nil {
57 panic(fmt.Sprintf("can't open db at %v: %v", path, err))
58 }
59 return st
60}
61
62func destroyLevelDB(st store.Store, path string) {
63 st.Close()
64 if err := leveldb.Destroy(path); err != nil {
65 panic(fmt.Sprintf("can't destroy db at %v: %v", path, err))
66 }
67}
68
Adam Sadovsky4dcc3532015-07-31 13:54:19 -070069////////////////////////////////////////////////////////////
70// Functions related to watchable store
Jatin Lodhia45a1fa82015-06-18 11:51:04 -070071
72func getSeq(st Store) uint64 {
73 wst := st.(*wstore)
74 return wst.seq
75}
76
77func setMockSystemClock(st Store, mockClock clock.SystemClock) {
78 wst := st.(*wstore)
79 wst.clock.SetSystemClock(mockClock)
80}
81
Adam Sadovsky4dcc3532015-07-31 13:54:19 -070082// logEntryReader provides a stream-like interface to scan over the log entries
Raja Daoudd4543072015-06-30 11:15:55 -070083// of a single batch, starting for a given sequence number. It opens a stream
84// that scans the log from the sequence number given. It stops after reading
85// the last entry in that batch (indicated by a false Continued flag).
Adam Sadovsky4dcc3532015-07-31 13:54:19 -070086type logEntryReader struct {
Raja Daoudd4543072015-06-30 11:15:55 -070087 stream store.Stream // scan stream on the store Database
88 done bool // true after reading the last batch entry
89 key string // key of most recent log entry read
90 entry LogEntry // most recent log entry read
Jatin Lodhia45a1fa82015-06-18 11:51:04 -070091}
92
Adam Sadovsky4dcc3532015-07-31 13:54:19 -070093func newLogEntryReader(st store.Store, seq uint64) *logEntryReader {
Raja Daoudd4543072015-06-30 11:15:55 -070094 stream := st.Scan([]byte(getLogEntryKey(seq)), []byte(getLogEntryKey(math.MaxUint64)))
Adam Sadovsky4dcc3532015-07-31 13:54:19 -070095 return &logEntryReader{stream: stream}
Jatin Lodhia45a1fa82015-06-18 11:51:04 -070096}
97
Adam Sadovsky4dcc3532015-07-31 13:54:19 -070098func (ler *logEntryReader) Advance() bool {
Raja Daoudd4543072015-06-30 11:15:55 -070099 if ler.done {
100 return false
101 }
102
103 if ler.stream.Advance() {
104 ler.key = string(ler.stream.Key(nil))
105 if err := vom.Decode(ler.stream.Value(nil), &ler.entry); err != nil {
106 panic(fmt.Errorf("Failed to decode LogEntry for key: %q", ler.key))
107 }
108 if ler.entry.Continued == false {
109 ler.done = true
110 }
111 return true
112 }
113
114 ler.key = ""
115 ler.entry = LogEntry{}
116 return false
Jatin Lodhia45a1fa82015-06-18 11:51:04 -0700117}
118
Adam Sadovsky4dcc3532015-07-31 13:54:19 -0700119func (ler *logEntryReader) GetEntry() (string, LogEntry) {
Raja Daoudd4543072015-06-30 11:15:55 -0700120 return ler.key, ler.entry
Jatin Lodhia45a1fa82015-06-18 11:51:04 -0700121}
122
Adam Sadovsky4dcc3532015-07-31 13:54:19 -0700123////////////////////////////////////////////////////////////
124// Clock related utility code
Jatin Lodhia45a1fa82015-06-18 11:51:04 -0700125
Adam Sadovsky4dcc3532015-07-31 13:54:19 -0700126type mockSystemClock struct {
Jatin Lodhia101bd212015-06-22 13:35:53 -0700127 time time.Time // current time returned by call to Now()
128 increment time.Duration // how much to increment the clock by for subsequent calls to Now()
Jatin Lodhia45a1fa82015-06-18 11:51:04 -0700129}
130
Adam Sadovsky4dcc3532015-07-31 13:54:19 -0700131func newMockSystemClock(firstTimestamp time.Time, increment time.Duration) *mockSystemClock {
132 return &mockSystemClock{
Jatin Lodhia45a1fa82015-06-18 11:51:04 -0700133 time: firstTimestamp,
134 increment: increment,
135 }
136}
137
Adam Sadovsky4dcc3532015-07-31 13:54:19 -0700138func (sc *mockSystemClock) Now() time.Time {
Jatin Lodhia45a1fa82015-06-18 11:51:04 -0700139 now := sc.time
Jatin Lodhia101bd212015-06-22 13:35:53 -0700140 sc.time = sc.time.Add(sc.increment)
Jatin Lodhia45a1fa82015-06-18 11:51:04 -0700141 return now
142}
143
Adam Sadovsky4dcc3532015-07-31 13:54:19 -0700144var _ clock.SystemClock = (*mockSystemClock)(nil)