package page_writer import ( "io" "testing" ) // TestShutdown_ReleasesWritableReservation verifies that calling Shutdown // on a pipeline with dirty-but-unsealed writable chunks returns those // chunks' reservations to the accountant. Regression for the Destroy() // path (truncate / metadata invalidation) which never flushes before // dropping the pipeline, so writable chunks would otherwise leak their // write-budget slots permanently. func TestShutdown_ReleasesWritableReservation(t *testing.T) { acc := NewWriteBufferAccountant(1024 * 1024) saveFn := func(io.Reader, int64, int64, int64, func()) {} up := NewUploadPipeline(nil, 64*1024, saveFn, 16, t.TempDir(), acc) // A small partial write lands in writableChunks as a mem chunk and // stays there (the chunk is not complete so maybeMoveToSealed is a // no-op) — exactly the state Destroy() can hit. buf := make([]byte, 128) if _, err := up.SaveDataAt(buf, 0, true, 1); err != nil { t.Fatalf("SaveDataAt: %v", err) } if got := acc.Used(); got != 64*1024 { t.Fatalf("expected 64KiB reserved after one write, got %d", got) } up.Shutdown() if got := acc.Used(); got != 0 { t.Fatalf("expected 0 used after Shutdown, got %d (writable reservation leaked)", got) } } // TestSealedChunk_FreeReferenceIsIdempotent verifies that FreeReference // releases the accountant slot exactly once even if it is invoked more // than once. This guards the path where Shutdown and the async uploader // goroutine both call FreeReference on the same sealed chunk: the second // call must be a no-op, not a double-release. func TestSealedChunk_FreeReferenceIsIdempotent(t *testing.T) { acc := NewWriteBufferAccountant(1024 * 1024) acc.Reserve(64 * 1024) sc := &SealedChunk{ chunk: NewMemChunk(0, 64*1024), referenceCounter: 1, accountant: acc, chunkSize: 64 * 1024, } sc.FreeReference("first") if got := acc.Used(); got != 0 { t.Fatalf("expected 0 used after first FreeReference, got %d", got) } sc.FreeReference("second") if got := acc.Used(); got != 0 { t.Fatalf("expected 0 used after second FreeReference, got %d (double release)", got) } }