Add type-safe hash types for cache storage

Define ContentHash, VariantKey, and PathHash types to replace
raw strings, providing compile-time type safety for storage
operations. Update storage layer to use typed parameters,
refactor cache to use variant storage keyed by VariantKey,
and implement source content reuse on cache misses.
This commit is contained in:
2026-01-08 16:55:20 -08:00
parent 555f150179
commit be293906bc
9 changed files with 476 additions and 381 deletions

View File

@@ -30,7 +30,8 @@ func TestContentStorage_StoreAndLoad(t *testing.T) {
}
// Verify file exists at expected path
expectedPath := filepath.Join(tmpDir, hash[0:2], hash[2:4], hash)
hashStr := string(hash)
expectedPath := filepath.Join(tmpDir, hashStr[0:2], hashStr[2:4], hashStr)
if _, err := os.Stat(expectedPath); err != nil {
t.Errorf("File not at expected path %s: %v", expectedPath, err)
}
@@ -83,7 +84,7 @@ func TestContentStorage_LoadNotFound(t *testing.T) {
t.Fatalf("NewContentStorage() error = %v", err)
}
_, err = storage.Load("nonexistent")
_, err = storage.Load(ContentHash("nonexistent"))
if err != ErrNotFound {
t.Errorf("Load() error = %v, want ErrNotFound", err)
}
@@ -123,24 +124,29 @@ func TestContentStorage_DeleteNonexistent(t *testing.T) {
}
// Should not error
if err := storage.Delete("nonexistent"); err != nil {
if err := storage.Delete(ContentHash("nonexistent")); err != nil {
t.Errorf("Delete() error = %v, want nil", err)
}
}
func TestContentStorage_Path(t *testing.T) {
func TestContentStorage_HashToPath(t *testing.T) {
tmpDir := t.TempDir()
storage, err := NewContentStorage(tmpDir)
if err != nil {
t.Fatalf("NewContentStorage() error = %v", err)
}
hash := "abcdef0123456789"
path := storage.Path(hash)
expected := filepath.Join(tmpDir, "ab", "cd", hash)
// Test by storing and verifying the resulting path structure
content := []byte("test content for path verification")
hash, _, err := storage.Store(bytes.NewReader(content))
if err != nil {
t.Fatalf("Store() error = %v", err)
}
if path != expected {
t.Errorf("Path() = %q, want %q", path, expected)
hashStr := string(hash)
expectedPath := filepath.Join(tmpDir, hashStr[0:2], hashStr[2:4], hashStr)
if _, err := os.Stat(expectedPath); err != nil {
t.Errorf("File not at expected path %s: %v", expectedPath, err)
}
}
@@ -169,7 +175,7 @@ func TestMetadataStorage_StoreAndLoad(t *testing.T) {
}
// Verify file exists at expected path
expectedPath := filepath.Join(tmpDir, "cdn.example.com", pathHash+".json")
expectedPath := filepath.Join(tmpDir, "cdn.example.com", string(pathHash)+".json")
if _, err := os.Stat(expectedPath); err != nil {
t.Errorf("File not at expected path %s: %v", expectedPath, err)
}
@@ -208,7 +214,7 @@ func TestMetadataStorage_LoadNotFound(t *testing.T) {
t.Fatalf("NewMetadataStorage() error = %v", err)
}
_, err = storage.Load("example.com", "nonexistent")
_, err = storage.Load("example.com", PathHash("nonexistent"))
if err != ErrNotFound {
t.Errorf("Load() error = %v, want ErrNotFound", err)
}
@@ -264,8 +270,8 @@ func TestHashPath(t *testing.T) {
}
// Hash should be 64 hex chars (256 bits)
if len(hash1) != 64 {
t.Errorf("HashPath() length = %d, want 64", len(hash1))
if len(string(hash1)) != 64 {
t.Errorf("HashPath() length = %d, want 64", len(string(hash1)))
}
}
@@ -299,8 +305,8 @@ func TestCacheKey(t *testing.T) {
}
// Key should be 64 hex chars
if len(key1) != 64 {
t.Errorf("CacheKey() length = %d, want 64", len(key1))
if len(string(key1)) != 64 {
t.Errorf("CacheKey() length = %d, want 64", len(string(key1)))
}
// Different size should produce different key