Skip to content

Commit 9bea3c0

Browse files
authored
Fix error on empty snapshot (#235)
1 parent 53755a2 commit 9bea3c0

File tree

3 files changed

+56
-16
lines changed

3 files changed

+56
-16
lines changed

source/snapshot/fetch_worker.go

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -257,11 +257,9 @@ func (f *FetchWorker) updateSnapshotEnd(ctx context.Context, tx pgx.Tx) error {
257257
return nil
258258
}
259259

260-
if err := tx.QueryRow(
261-
ctx,
262-
fmt.Sprintf("SELECT max(%s) FROM %s", f.conf.Key, f.conf.Table),
263-
).Scan(&f.snapshotEnd); err != nil {
264-
return fmt.Errorf("failed to query max on %q.%q: %w", f.conf.Table, f.conf.Key, err)
260+
query := fmt.Sprintf("SELECT COALESCE(max(%s), 0) FROM %s", f.conf.Key, f.conf.Table)
261+
if err := tx.QueryRow(ctx, query).Scan(&f.snapshotEnd); err != nil {
262+
return fmt.Errorf("failed to get snapshot end with query %q: %w", query, err)
265263
}
266264

267265
return nil

source/snapshot/fetch_worker_test.go

Lines changed: 42 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,40 @@ func Test_FetcherValidate(t *testing.T) {
201201
})
202202
}
203203

204+
func Test_FetcherRun_EmptySnapshot(t *testing.T) {
205+
var (
206+
is = is.New(t)
207+
ctx = test.Context(t)
208+
pool = test.ConnectPool(context.Background(), t, test.RegularConnString)
209+
table = test.SetupEmptyTestTable(context.Background(), t, pool)
210+
out = make(chan FetchData)
211+
testTomb = &tomb.Tomb{}
212+
)
213+
214+
f := NewFetchWorker(pool, out, FetchConfig{
215+
Table: table,
216+
Key: "id",
217+
})
218+
219+
testTomb.Go(func() error {
220+
ctx = testTomb.Context(ctx)
221+
defer close(out)
222+
223+
if err := f.Validate(ctx); err != nil {
224+
return err
225+
}
226+
return f.Run(ctx)
227+
})
228+
229+
var gotFetchData []FetchData
230+
for data := range out {
231+
gotFetchData = append(gotFetchData, data)
232+
}
233+
234+
is.NoErr(testTomb.Err())
235+
is.True(len(gotFetchData) == 0)
236+
}
237+
204238
func Test_FetcherRun_Initial(t *testing.T) {
205239
var (
206240
pool = test.ConnectPool(context.Background(), t, test.RegularConnString)
@@ -226,13 +260,13 @@ func Test_FetcherRun_Initial(t *testing.T) {
226260
return f.Run(ctx)
227261
})
228262

229-
var dd []FetchData
263+
var gotFetchData []FetchData
230264
for data := range out {
231-
dd = append(dd, data)
265+
gotFetchData = append(gotFetchData, data)
232266
}
233267

234268
is.NoErr(tt.Err())
235-
is.True(len(dd) == 4)
269+
is.True(len(gotFetchData) == 4)
236270

237271
expectedMatch := []opencdc.StructuredData{
238272
{"id": int64(1), "key": []uint8{49}, "column1": "foo", "column2": int32(123), "column3": false, "column4": 12.2, "column5": int64(4)},
@@ -241,17 +275,17 @@ func Test_FetcherRun_Initial(t *testing.T) {
241275
{"id": int64(4), "key": []uint8{52}, "column1": nil, "column2": nil, "column3": nil, "column4": 91.1, "column5": nil},
242276
}
243277

244-
for i, d := range dd {
278+
for i, got := range gotFetchData {
245279
t.Run(fmt.Sprintf("payload_%d", i+1), func(t *testing.T) {
246280
is := is.New(t)
247-
is.Equal(d.Key, opencdc.StructuredData{"id": int64(i + 1)})
248-
is.Equal("", cmp.Diff(expectedMatch[i], d.Payload))
281+
is.Equal(got.Key, opencdc.StructuredData{"id": int64(i + 1)})
282+
is.Equal("", cmp.Diff(expectedMatch[i], got.Payload))
249283

250-
is.Equal(d.Position, position.SnapshotPosition{
284+
is.Equal(got.Position, position.SnapshotPosition{
251285
LastRead: int64(i + 1),
252286
SnapshotEnd: 4,
253287
})
254-
is.Equal(d.Table, table)
288+
is.Equal(got.Table, table)
255289
})
256290
}
257291
}

test/helper.go

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ func ConnectSimple(ctx context.Context, t *testing.T, connString string) *pgx.Co
173173
}
174174

175175
// SetupTestTable creates a new table and returns its name.
176-
func SetupTestTable(ctx context.Context, t *testing.T, conn Querier) string {
176+
func SetupEmptyTestTable(ctx context.Context, t *testing.T, conn Querier) string {
177177
is := is.New(t)
178178

179179
table := RandomIdentifier(t)
@@ -189,14 +189,22 @@ func SetupTestTable(ctx context.Context, t *testing.T, conn Querier) string {
189189
is.NoErr(err)
190190
})
191191

192-
query = `
192+
return table
193+
}
194+
195+
// SetupTestTable creates a new table and returns its name.
196+
func SetupTestTable(ctx context.Context, t *testing.T, conn Querier) string {
197+
is := is.New(t)
198+
table := SetupEmptyTestTable(ctx, t, conn)
199+
200+
query := `
193201
INSERT INTO %s (key, column1, column2, column3, column4, column5)
194202
VALUES ('1', 'foo', 123, false, 12.2, 4),
195203
('2', 'bar', 456, true, 13.42, 8),
196204
('3', 'baz', 789, false, null, 9),
197205
('4', null, null, null, 91.1, null)`
198206
query = fmt.Sprintf(query, table)
199-
_, err = conn.Exec(ctx, query)
207+
_, err := conn.Exec(ctx, query)
200208
is.NoErr(err)
201209

202210
return table

0 commit comments

Comments
 (0)