Skip to content

Commit b89d910

Browse files
committed
streaming(fullhistory): restore the ServeReads-error startup test
The serve+ingest rework dropped TestStartStreaming_ServeReadsErrorSurfaces, leaving the ServeReads-error return path untested — and that path now does more than before: it must close the already-opened resume hot DB so a restart can reacquire the rocksdb LOCK. Restore the test adapted to the new flow: a fake core with a blocking getter so ServeReads is reached, then assert the wrapped "serve reads" error surfaces (not classified clean), core was started, and the resume hot DB is reopenable afterward (its LOCK was released).
1 parent 51c311a commit b89d910

1 file changed

Lines changed: 29 additions & 0 deletions

File tree

cmd/stellar-rpc/internal/fullhistory/streaming/startup_test.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -502,6 +502,35 @@ func TestStartStreaming_FirstStartServeIngestCleanShutdown(t *testing.T) {
502502
assert.Equal(t, HotReady, state)
503503
}
504504

505+
// A ServeReads error is surfaced wrapped as a restartable failure (NOT clean) and
506+
// the already-opened resume hot DB is closed on the way out, so a restart can
507+
// reopen it (the rocksdb LOCK is released). ServeReads runs after the hot DB
508+
// opens and core starts but before the blocking ingestion loop, so startStreaming
509+
// returns synchronously here.
510+
func TestStartStreaming_ServeReadsErrorSurfaces(t *testing.T) {
511+
cat, _ := testCatalog(t)
512+
pinGenesis(t, cat)
513+
core := &fakeCore{getter: &fakeLedgerGetter{frames: map[uint32][]byte{}, blockOnCtx: true}}
514+
tip := &fakeTipBackend{tips: []uint32{chunk.FirstLedgerSeq + 10}} // young: no backfill
515+
cfg := startTestConfig(t, cat, tip, core, nil)
516+
cfg.ServeReads = func(context.Context) error { return errors.New("rpc bind failed") }
517+
518+
err := startStreaming(context.Background(), cfg)
519+
require.Error(t, err)
520+
require.Contains(t, err.Error(), "serve reads")
521+
require.NotErrorIs(t, err, context.Canceled, "a ServeReads error is restartable, not a clean shutdown")
522+
require.Equal(t, int32(1), core.openedCount.Load(), "core was started before serving")
523+
524+
// The resume hot DB was closed on the error path (LOCK released): reopening it
525+
// succeeds. Its key is still "ready" — only the handle was released, not the DB.
526+
state, err := cat.HotState(chunk.IDFromLedger(chunk.FirstLedgerSeq))
527+
require.NoError(t, err)
528+
require.Equal(t, HotReady, state)
529+
db, err := openHotTierForChunk(cat, chunk.IDFromLedger(chunk.FirstLedgerSeq), silentLogger())
530+
require.NoError(t, err, "the resume hot DB is reopenable — startStreaming released its LOCK")
531+
require.NoError(t, db.Close())
532+
}
533+
505534
// startStreaming fatals on a true first start when the tip is unavailable: the
506535
// error is ErrFirstStartNoTip and NEITHER the hot DB nor core is opened.
507536
func TestStartStreaming_FirstStartNoTipFatal(t *testing.T) {

0 commit comments

Comments
 (0)