Files
go-kv/wal/writer_test.go
T
dailz 56bec62a6e fix: add write-stopped test and remove VKValueLogPointer from test logic
- Add TestWriteStoppedAfterIOError verifying ErrCommitUnknown → write-stopped
  transition after I/O failure (DoD requirement)
- Replace VKValueLogPointer with VKInline in segment_writer_test.go large
  batch test (9 × 4KB entries, still tests multi-fragment)
- Replace put_vlptr_val_empty with put_inline_val_empty in entry_test.go
- VKValueLogPointer remains only in constants_test.go (enum value check)
2026-06-12 14:39:16 +08:00

167 lines
3.7 KiB
Go

package wal
import (
"errors"
"fmt"
"sync"
"testing"
"github.com/dailz/go-kv/config"
"github.com/dailz/go-kv/errkit"
)
func newTestWalWriter(t *testing.T) *WalWriter {
t.Helper()
cfg := config.Defaults()
ww, err := NewWalWriter(&cfg, t.TempDir(), 0, 0)
if err != nil {
t.Fatalf("NewWalWriter: %v", err)
}
t.Cleanup(func() {
if err := ww.Close(); err != nil {
t.Fatalf("Close: %v", err)
}
})
return ww
}
func TestWalWriterSinglePut(t *testing.T) {
ww := newTestWalWriter(t)
if err := ww.Put([]byte("k1"), []byte("v1")); err != nil {
t.Fatalf("Put: %v", err)
}
got := ww.Get([]byte("k1"))
if !got.Found {
t.Fatal("Get(k1) not found")
}
if string(got.Value) != "v1" {
t.Fatalf("Get(k1) value = %q, want %q", got.Value, "v1")
}
}
func TestWalWriterMultiplePuts(t *testing.T) {
ww := newTestWalWriter(t)
for i := range 10 {
key := fmt.Appendf(nil, "k%d", i)
value := fmt.Appendf(nil, "v%d", i)
if err := ww.Put(key, value); err != nil {
t.Fatalf("Put(%q): %v", key, err)
}
}
for i := range 10 {
key := fmt.Appendf(nil, "k%d", i)
want := fmt.Sprintf("v%d", i)
got := ww.Get(key)
if !got.Found {
t.Fatalf("Get(%q) not found", key)
}
if string(got.Value) != want {
t.Fatalf("Get(%q) value = %q, want %q", key, got.Value, want)
}
}
}
func TestWalWriterGroupCommit(t *testing.T) {
ww := newTestWalWriter(t)
const writers = 5
var wg sync.WaitGroup
errCh := make(chan error, writers)
for i := range writers {
wg.Go(func() {
key := fmt.Appendf(nil, "group-k%d", i)
value := fmt.Appendf(nil, "group-v%d", i)
if err := ww.Put(key, value); err != nil {
errCh <- fmt.Errorf("put %d: %w", i, err)
}
})
}
wg.Wait()
close(errCh)
for err := range errCh {
if err != nil {
t.Fatal(err)
}
}
for i := range writers {
key := fmt.Appendf(nil, "group-k%d", i)
want := fmt.Sprintf("group-v%d", i)
got := ww.Get(key)
if !got.Found {
t.Fatalf("Get(%q) not found", key)
}
if string(got.Value) != want {
t.Fatalf("Get(%q) value = %q, want %q", key, got.Value, want)
}
}
}
func TestWalWriterDelete(t *testing.T) {
ww := newTestWalWriter(t)
if err := ww.Put([]byte("k"), []byte("v")); err != nil {
t.Fatalf("Put: %v", err)
}
if err := ww.Delete([]byte("k")); err != nil {
t.Fatalf("Delete: %v", err)
}
got := ww.Get([]byte("k"))
if got.Found {
t.Fatalf("Get(k) found deleted key with value %q", got.Value)
}
}
// TestWriteStoppedAfterIOError verifies: I/O failure during AppendBatch →
// ErrCommitUnknown returned, write-stopped state entered, subsequent writes
// return ErrWriteStopped.
func TestWriteStoppedAfterIOError(t *testing.T) {
cfg := config.Defaults()
ww, err := NewWalWriter(&cfg, t.TempDir(), 0, 0)
if err != nil {
t.Fatalf("NewWalWriter: %v", err)
}
if err := ww.Put([]byte("ok-key"), []byte("ok-val")); err != nil {
t.Fatalf("initial Put: %v", err)
}
// Close the fd to force AppendBatch → stopWithError(ErrCommitUnknown).
if err := ww.segManager.active.fd.Close(); err != nil {
t.Fatalf("close fd: %v", err)
}
err = ww.Put([]byte("fail-key"), []byte("fail-val"))
if err == nil {
t.Fatal("expected error from Put after I/O failure, got nil")
}
if !errors.Is(err, errkit.ErrCommitUnknown) {
t.Errorf("Put error = %v, want ErrCommitUnknown", err)
}
if !ww.IsWriteStopped() {
t.Fatal("IsWriteStopped() = false, want true after I/O error")
}
err = ww.Put([]byte("after-key"), []byte("after-val"))
if !errors.Is(err, errkit.ErrWriteStopped) {
t.Errorf("Put after write-stopped error = %v, want ErrWriteStopped", err)
}
err = ww.Delete([]byte("after-key"))
if !errors.Is(err, errkit.ErrWriteStopped) {
t.Errorf("Delete after write-stopped error = %v, want ErrWriteStopped", err)
}
_ = ww.Close()
}