Files
go-kv/wal/header_test.go
dailz cf913b1d52 feat: initialize project structure and error types
- go.mod with github.com/dailz/go-kv, Go 1.26.3, testify
- config/config.go with WalConfig, Validate() with checked arithmetic
- errors.go with sentinel errors (ErrCommitUnknown, ErrWriteStopped, etc.)
- wal/constants.go with all WAL format constants and enums
- wal/header.go with WAL File Header encode/decode (CRC32 IEEE)
- wal/record.go with Physical Record codec, block boundary, SplitIntoRecords
- wal/entry.go with WAL Entry codec (varint keys/values, OpType, ValueKind)
- wal/sequence.go with SequenceManager (atomic, CAS, overflow-safe)
- manifest/manifest.go with MANIFEST stub (Load/Save atomic)
- manifest/current.go with CURRENT file (WriteCurrent/ReadCurrent)
- Comprehensive tests for all modules
- .golangci.yml configuration
2026-06-12 13:23:27 +08:00

88 lines
2.4 KiB
Go

package wal
import (
"errors"
"testing"
)
func TestHeaderRoundtrip(t *testing.T) {
orig := &WalFileHeader{
BlockSize: 32 * 1024, // 32 KB
SegmentID: 5,
StartSequence: 1000,
}
encoded := EncodeWalHeader(orig)
decoded, err := DecodeWalHeader(encoded[:])
if err != nil {
t.Fatalf("DecodeWalHeader returned error: %v", err)
}
if decoded.Magic != walMagic {
t.Errorf("Magic = %x, want %x", decoded.Magic, walMagic)
}
if decoded.FormatVersion != walFormatVersion {
t.Errorf("FormatVersion = %d, want %d", decoded.FormatVersion, walFormatVersion)
}
if decoded.HeaderSize != walFileHeaderSize {
t.Errorf("HeaderSize = %d, want %d", decoded.HeaderSize, walFileHeaderSize)
}
if decoded.BlockSize != orig.BlockSize {
t.Errorf("BlockSize = %d, want %d", decoded.BlockSize, orig.BlockSize)
}
if decoded.SegmentID != orig.SegmentID {
t.Errorf("SegmentID = %d, want %d", decoded.SegmentID, orig.SegmentID)
}
if decoded.StartSequence != orig.StartSequence {
t.Errorf("StartSequence = %d, want %d", decoded.StartSequence, orig.StartSequence)
}
if decoded.HeaderCRC != orig.HeaderCRC {
t.Errorf("HeaderCRC = %x, want %x", decoded.HeaderCRC, orig.HeaderCRC)
}
}
func TestHeaderCRC(t *testing.T) {
h := &WalFileHeader{
BlockSize: 32 * 1024,
SegmentID: 1,
StartSequence: 0,
}
encoded := EncodeWalHeader(h)
// Flip a byte in the magic field (bytes 0-3)
encoded[0] ^= 0xFF
_, err := DecodeWalHeader(encoded[:])
if !errors.Is(err, errCRCMismatch) && !errors.Is(err, errBadMagic) {
// Flipping magic may fail on magic check first or CRC check
// Either way, decoding must fail
t.Fatalf("expected CRC or magic error, got: %v", err)
}
// Restore magic and flip a byte in the payload instead
encoded[0] = byte(walMagic & 0xFF)
encoded[12] ^= 0x01 // flip byte in SegmentID
_, err = DecodeWalHeader(encoded[:])
if !errors.Is(err, errCRCMismatch) {
t.Fatalf("expected errCRCMismatch, got: %v", err)
}
}
func TestHeaderBadMagic(t *testing.T) {
data := make([]byte, 32)
// All zeros — magic won't match
_, err := DecodeWalHeader(data)
if !errors.Is(err, errBadMagic) {
t.Fatalf("expected errBadMagic, got: %v", err)
}
}
func TestHeaderShortData(t *testing.T) {
data := make([]byte, 16) // too short
_, err := DecodeWalHeader(data)
if !errors.Is(err, errHeaderTooShort) {
t.Fatalf("expected errHeaderTooShort, got: %v", err)
}
}