Optimize test suite performance - 45% reduction in integration tests

- Add testutil.TempDirInMemory() using /dev/shm on Linux for 20-30% I/O speedup
- Update slow hash multiclone tests to use in-memory filesystem
- Convert 17 scripttest tests (~200+s) to fast CLI tests (31s) with --no-daemon
- Disable slow scripttest suite behind build tag
- Add README_TESTING.md documenting test strategy and optimizations
- Update CI to use -short flag for PR checks, full tests nightly

Results:
- TestHashIDs_* reduced from ~20s to ~11s (45% reduction)
- Scripttest suite eliminated from default runs (massive speedup)
- Total integration test time significantly reduced

Closes bd-gm7p, bd-l5gq

Amp-Thread-ID: https://ampcode.com/threads/T-c2b9434a-cd29-4725-b8e0-cbea50b36fe2
Co-authored-by: Amp <amp@ampcode.com>
This commit is contained in:
Steve Yegge
2025-11-04 11:25:36 -08:00
parent 568c565e8c
commit b31bddc210
11 changed files with 596 additions and 31 deletions

View File

@@ -0,0 +1,62 @@
package testutil
import (
"os"
"path/filepath"
"runtime"
"testing"
)
// TempDirInMemory creates a temporary directory that preferentially uses
// in-memory filesystems (tmpfs/ramdisk) when available. This reduces I/O
// overhead for git-heavy tests.
//
// On Linux: Uses /dev/shm if available (tmpfs ramdisk)
// On macOS: Falls back to standard temp (ramdisks require manual setup)
// On Windows: Falls back to standard temp
//
// The directory is automatically cleaned up when the test ends.
func TempDirInMemory(t testing.TB) string {
t.Helper()
var baseDir string
switch runtime.GOOS {
case "linux":
// Try /dev/shm (tmpfs ramdisk) first
if stat, err := os.Stat("/dev/shm"); err == nil && stat.IsDir() {
// Create subdirectory with proper permissions
tmpBase := filepath.Join("/dev/shm", "beads-test")
if err := os.MkdirAll(tmpBase, 0755); err == nil {
baseDir = tmpBase
}
}
case "darwin":
// macOS: /tmp might already be on APFS with fast I/O
// Creating a ramdisk requires sudo, so we rely on system defaults
// Users can manually mount /tmp as tmpfs if needed:
// diskutil erasevolume HFS+ "ramdisk" `hdiutil attach -nomount ram://2048000`
baseDir = os.TempDir()
default:
// Windows and others: use standard temp
baseDir = os.TempDir()
}
// If we didn't set baseDir (e.g., /dev/shm unavailable), use default
if baseDir == "" {
baseDir = os.TempDir()
}
// Create unique temp directory
tmpDir, err := os.MkdirTemp(baseDir, "beads-test-*")
if err != nil {
t.Fatalf("Failed to create temp dir: %v", err)
}
// Register cleanup
t.Cleanup(func() {
os.RemoveAll(tmpDir)
})
return tmpDir
}

View File

@@ -0,0 +1,63 @@
package testutil
import (
"os"
"path/filepath"
"runtime"
"strings"
"testing"
)
func TestTempDirInMemory(t *testing.T) {
tmpDir := TempDirInMemory(t)
// Verify directory exists
if stat, err := os.Stat(tmpDir); err != nil || !stat.IsDir() {
t.Fatalf("TempDirInMemory() did not create valid directory: %v", err)
}
// Verify it's a beads test directory
if !strings.Contains(filepath.Base(tmpDir), "beads-test") {
t.Errorf("Expected directory name to contain 'beads-test', got: %s", tmpDir)
}
// On Linux CI, verify we're using /dev/shm if available
if runtime.GOOS == "linux" {
if stat, err := os.Stat("/dev/shm"); err == nil && stat.IsDir() {
if !strings.HasPrefix(tmpDir, "/dev/shm") {
t.Errorf("On Linux with /dev/shm available, expected tmpDir to use it, got: %s", tmpDir)
} else {
t.Logf("✓ Using tmpfs ramdisk: %s", tmpDir)
}
}
} else {
t.Logf("Platform: %s, using standard temp: %s", runtime.GOOS, tmpDir)
}
// Verify cleanup happens
testFile := filepath.Join(tmpDir, "test.txt")
if err := os.WriteFile(testFile, []byte("test"), 0644); err != nil {
t.Fatalf("Failed to write test file: %v", err)
}
if _, err := os.Stat(testFile); err != nil {
t.Fatalf("Test file should exist: %v", err)
}
}
func TestTempDirInMemory_Cleanup(t *testing.T) {
var tmpDir string
// Run in subtest to trigger cleanup
t.Run("create", func(t *testing.T) {
tmpDir = TempDirInMemory(t)
if err := os.WriteFile(filepath.Join(tmpDir, "data"), []byte("test"), 0644); err != nil {
t.Fatalf("Failed to write file: %v", err)
}
})
// After subtest completes, cleanup should have run
if _, err := os.Stat(tmpDir); !os.IsNotExist(err) {
t.Errorf("Expected tmpDir to be cleaned up, but it still exists: %s", tmpDir)
}
}