Files
seaweedfs/weed/storage/blockvol/resize_test.go
T
Ping QiuandClaude Opus 4.6 531ee764ee feat: Phase 5 CP5-3 -- CHAP auth, online resize, Prometheus metrics, 12 tests
CHAP authentication (RFC 7143 S12.1):
- auth.go: CHAPAuthenticator with MD5 challenge-response, ValidateCHAPConfig
- login.go: multi-PDU SecurityNeg flow (challenge → verify → transit)
- main.go: -chap-user/-chap-secret CLI flags with validation

Online volume expand:
- blockvol.go: Expand() with flusher pause, snapMu TOCTOU guard, alignment check
- Rejects shrink (ErrShrinkNotSupported) and resize with active snapshots

Prometheus metrics:
- metrics.go: metricsAdapter wrapping BlockDevice, 15 metrics (counters,
  histograms, gauge funcs for WAL/dirty-map/epoch/role/snapshots)
- Dedicated prometheus.NewRegistry() per server instance

Admin HTTP endpoints:
- POST /snapshot (create/delete/restore/list)
- POST /resize (online expand)
- GET /metrics (Prometheus text format)
- VolumeSize added to /status response

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 01:43:42 -08:00

145 lines
3.5 KiB
Go

package blockvol
import (
"bytes"
"os"
"path/filepath"
"testing"
)
// TestResize_ExpandWorks grows a 1MB volume to 2MB, writes to the new region,
// and reads back to verify.
func TestResize_ExpandWorks(t *testing.T) {
dir := t.TempDir()
path := filepath.Join(dir, "expand.blk")
vol, err := CreateBlockVol(path, CreateOptions{
VolumeSize: 1024 * 1024, // 1MB
BlockSize: 4096,
WALSize: 64 * 1024, // 64KB (small for test)
})
if err != nil {
t.Fatalf("create: %v", err)
}
defer vol.Close()
// Write to last block of original size.
lastLBA := uint64((1024*1024)/4096 - 1)
data := make([]byte, 4096)
for i := range data {
data[i] = 0xAA
}
if err := vol.WriteLBA(lastLBA, data); err != nil {
t.Fatalf("write last block: %v", err)
}
// Expand to 2MB.
newSize := uint64(2 * 1024 * 1024)
if err := vol.Expand(newSize); err != nil {
t.Fatalf("expand: %v", err)
}
// Verify volume size updated.
if vol.Info().VolumeSize != newSize {
t.Fatalf("expected VolumeSize=%d, got %d", newSize, vol.Info().VolumeSize)
}
// Write to a block in the new region.
newLBA := uint64((1024 * 1024) / 4096) // first block in expanded region
data2 := make([]byte, 4096)
for i := range data2 {
data2[i] = 0xBB
}
if err := vol.WriteLBA(newLBA, data2); err != nil {
t.Fatalf("write new region: %v", err)
}
// Read back old data.
got, err := vol.ReadLBA(lastLBA, 4096)
if err != nil {
t.Fatalf("read old block: %v", err)
}
if !bytes.Equal(got, data) {
t.Fatal("old block data mismatch after expand")
}
// Read back new data.
got2, err := vol.ReadLBA(newLBA, 4096)
if err != nil {
t.Fatalf("read new block: %v", err)
}
if !bytes.Equal(got2, data2) {
t.Fatal("new block data mismatch after expand")
}
// Verify file size on disk.
fi, _ := os.Stat(path)
extentStart := vol.super.WALOffset + vol.super.WALSize
expected := int64(extentStart + newSize)
if fi.Size() != expected {
t.Fatalf("file size: expected %d, got %d", expected, fi.Size())
}
}
// TestResize_ShrinkRejected verifies that attempting to shrink returns an error.
func TestResize_ShrinkRejected(t *testing.T) {
dir := t.TempDir()
path := filepath.Join(dir, "shrink.blk")
vol, err := CreateBlockVol(path, CreateOptions{
VolumeSize: 1024 * 1024,
BlockSize: 4096,
WALSize: 64 * 1024,
})
if err != nil {
t.Fatalf("create: %v", err)
}
defer vol.Close()
err = vol.Expand(512 * 1024) // shrink
if err != ErrShrinkNotSupported {
t.Fatalf("expected ErrShrinkNotSupported, got %v", err)
}
// Same size = no-op.
if err := vol.Expand(1024 * 1024); err != nil {
t.Fatalf("same-size expand should be no-op: %v", err)
}
}
// TestResize_WithSnapshotsRejected verifies that resize is blocked when
// snapshots are active.
func TestResize_WithSnapshotsRejected(t *testing.T) {
dir := t.TempDir()
path := filepath.Join(dir, "snap-resize.blk")
vol, err := CreateBlockVol(path, CreateOptions{
VolumeSize: 1024 * 1024,
BlockSize: 4096,
WALSize: 64 * 1024,
})
if err != nil {
t.Fatalf("create: %v", err)
}
defer vol.Close()
// Create a snapshot.
if err := vol.CreateSnapshot(1); err != nil {
t.Fatalf("create snapshot: %v", err)
}
// Try to expand -- should fail.
err = vol.Expand(2 * 1024 * 1024)
if err != ErrSnapshotsPreventResize {
t.Fatalf("expected ErrSnapshotsPreventResize, got %v", err)
}
// Delete snapshot, then expand should work.
if err := vol.DeleteSnapshot(1); err != nil {
t.Fatalf("delete snapshot: %v", err)
}
if err := vol.Expand(2 * 1024 * 1024); err != nil {
t.Fatalf("expand after snapshot delete: %v", err)
}
}