@@ -3,9 +3,11 @@ package litestream_test
33import (
44 "context"
55 "testing"
6+ "time"
67
78 "github.com/benbjohnson/litestream"
89 "github.com/benbjohnson/litestream/file"
10+ "github.com/benbjohnson/litestream/mock"
911 "github.com/superfly/ltx"
1012)
1113
@@ -29,8 +31,7 @@ func TestReplica_Sync(t *testing.T) {
2931 t .Logf ("position after sync: %s" , dpos .String ())
3032
3133 c := file .NewReplicaClient (t .TempDir ())
32- r := litestream .NewReplica (db )
33- c .Replica , r .Client = r , c
34+ r := litestream .NewReplicaWithClient (db , c )
3435
3536 if err := r .Sync (context .Background ()); err != nil {
3637 t .Fatal (err )
@@ -82,3 +83,143 @@ func TestReplica_Sync(t *testing.T) {
8283
8384 // TODO(ltx): Restore snapshot and verify
8485}
86+
87+ func TestReplica_CalcRestorePlan (t * testing.T ) {
88+ db , sqldb := MustOpenDBs (t )
89+ defer MustCloseDBs (t , db , sqldb )
90+
91+ t .Run ("SnapshotOnly" , func (t * testing.T ) {
92+ var c mock.ReplicaClient
93+ r := litestream .NewReplicaWithClient (db , & c )
94+ c .LTXFilesFunc = func (ctx context.Context , level int , seek ltx.TXID ) (ltx.FileIterator , error ) {
95+ if level == litestream .SnapshotLevel {
96+ return ltx .NewFileInfoSliceIterator ([]* ltx.FileInfo {{
97+ Level : litestream .SnapshotLevel ,
98+ MinTXID : 1 ,
99+ MaxTXID : 10 ,
100+ Size : 1024 ,
101+ CreatedAt : time .Now (),
102+ }}), nil
103+ }
104+ return ltx .NewFileInfoSliceIterator (nil ), nil
105+ }
106+
107+ plan , err := r .CalcRestorePlan (context .Background (), 10 )
108+ if err != nil {
109+ t .Fatalf ("unexpected error: %v" , err )
110+ }
111+ if got , want := len (plan ), 1 ; got != want {
112+ t .Fatalf ("n=%d, want %d" , got , want )
113+ }
114+ if plan [0 ].MaxTXID != 10 {
115+ t .Fatalf ("expected MaxTXID 10, got %d" , plan [0 ].MaxTXID )
116+ }
117+ })
118+
119+ t .Run ("SnapshotAndIncremental" , func (t * testing.T ) {
120+ var c mock.ReplicaClient
121+ r := litestream .NewReplicaWithClient (db , & c )
122+ c .LTXFilesFunc = func (ctx context.Context , level int , seek ltx.TXID ) (ltx.FileIterator , error ) {
123+ switch level {
124+ case litestream .SnapshotLevel :
125+ return ltx .NewFileInfoSliceIterator ([]* ltx.FileInfo {
126+ {Level : litestream .SnapshotLevel , MinTXID : 1 , MaxTXID : 5 },
127+ {Level : litestream .SnapshotLevel , MinTXID : 1 , MaxTXID : 15 },
128+ }), nil
129+ case 1 :
130+ return ltx .NewFileInfoSliceIterator ([]* ltx.FileInfo {
131+ {Level : 1 , MinTXID : 6 , MaxTXID : 7 },
132+ {Level : 1 , MinTXID : 8 , MaxTXID : 9 },
133+ {Level : 1 , MinTXID : 10 , MaxTXID : 12 },
134+ }), nil
135+ case 0 :
136+ return ltx .NewFileInfoSliceIterator ([]* ltx.FileInfo {
137+ {Level : 0 , MinTXID : 7 , MaxTXID : 7 },
138+ {Level : 0 , MinTXID : 8 , MaxTXID : 8 },
139+ {Level : 0 , MinTXID : 9 , MaxTXID : 9 },
140+ {Level : 0 , MinTXID : 10 , MaxTXID : 10 },
141+ {Level : 0 , MinTXID : 11 , MaxTXID : 11 },
142+ }), nil
143+ default :
144+ return ltx .NewFileInfoSliceIterator (nil ), nil
145+ }
146+ }
147+
148+ plan , err := r .CalcRestorePlan (context .Background (), 10 )
149+ if err != nil {
150+ t .Fatalf ("unexpected error: %v" , err )
151+ }
152+ if got , want := len (plan ), 4 ; got != want {
153+ t .Fatalf ("n=%v, want %v" , got , want )
154+ }
155+ if got , want := * plan [0 ], (ltx.FileInfo {Level : litestream .SnapshotLevel , MinTXID : 1 , MaxTXID : 5 }); got != want {
156+ t .Fatalf ("plan[0]=%#v, want %#v" , got , want )
157+ }
158+ if got , want := * plan [1 ], (ltx.FileInfo {Level : 1 , MinTXID : 6 , MaxTXID : 7 }); got != want {
159+ t .Fatalf ("plan[1]=%#v, want %#v" , got , want )
160+ }
161+ if got , want := * plan [2 ], (ltx.FileInfo {Level : 1 , MinTXID : 8 , MaxTXID : 9 }); got != want {
162+ t .Fatalf ("plan[2]=%#v, want %#v" , got , want )
163+ }
164+ if got , want := * plan [3 ], (ltx.FileInfo {Level : 0 , MinTXID : 10 , MaxTXID : 10 }); got != want {
165+ t .Fatalf ("plan[2]=%#v, want %#v" , got , want )
166+ }
167+ })
168+
169+ t .Run ("ErrNonContiguousFiles" , func (t * testing.T ) {
170+ var c mock.ReplicaClient
171+ r := litestream .NewReplicaWithClient (db , & c )
172+ c .LTXFilesFunc = func (ctx context.Context , level int , seek ltx.TXID ) (ltx.FileIterator , error ) {
173+ switch level {
174+ case litestream .SnapshotLevel :
175+ return ltx .NewFileInfoSliceIterator ([]* ltx.FileInfo {
176+ {Level : litestream .SnapshotLevel , MinTXID : 1 , MaxTXID : 5 },
177+ }), nil
178+ case 1 :
179+ return ltx .NewFileInfoSliceIterator ([]* ltx.FileInfo {
180+ {Level : 1 , MinTXID : 8 , MaxTXID : 9 },
181+ }), nil
182+ default :
183+ return ltx .NewFileInfoSliceIterator (nil ), nil
184+ }
185+ }
186+
187+ _ , err := r .CalcRestorePlan (context .Background (), 10 )
188+ if err == nil || err .Error () != `non-contiguous transaction files: prev=0000000000000005 filename=0000000000000008-0000000000000009.ltx` {
189+ t .Fatalf ("unexpected error: %q" , err )
190+ }
191+ })
192+
193+ t .Run ("ErrTxNotAvailable" , func (t * testing.T ) {
194+ var c mock.ReplicaClient
195+ r := litestream .NewReplicaWithClient (db , & c )
196+ c .LTXFilesFunc = func (ctx context.Context , level int , seek ltx.TXID ) (ltx.FileIterator , error ) {
197+ switch level {
198+ case litestream .SnapshotLevel :
199+ return ltx .NewFileInfoSliceIterator ([]* ltx.FileInfo {
200+ {Level : litestream .SnapshotLevel , MinTXID : 1 , MaxTXID : 10 },
201+ }), nil
202+ default :
203+ return ltx .NewFileInfoSliceIterator (nil ), nil
204+ }
205+ }
206+
207+ _ , err := r .CalcRestorePlan (context .Background (), 5 )
208+ if err != litestream .ErrTxNotAvailable {
209+ t .Fatalf ("expected ErrTxNotAvailable, got %v" , err )
210+ }
211+ })
212+
213+ t .Run ("ErrNoFiles" , func (t * testing.T ) {
214+ var c mock.ReplicaClient
215+ c .LTXFilesFunc = func (ctx context.Context , level int , seek ltx.TXID ) (ltx.FileIterator , error ) {
216+ return ltx .NewFileInfoSliceIterator (nil ), nil
217+ }
218+ r := litestream .NewReplicaWithClient (db , & c )
219+
220+ _ , err := r .CalcRestorePlan (context .Background (), 5 )
221+ if err != litestream .ErrTxNotAvailable {
222+ t .Fatalf ("expected ErrTxNotAvailable, got %v" , err )
223+ }
224+ })
225+ }
0 commit comments