Files
mcr/internal/storage/storage_test.go
Kyle Isom 3314b7a618 Batch A: blob storage layer, MCIAS auth, OCI token endpoint
Phase 2 — internal/storage/:
Content-addressed blob storage with atomic writes via rename.
BlobWriter stages data in uploads dir with running SHA-256 hash,
commits by verifying digest then renaming to layers/sha256/<prefix>/<hex>.
Reader provides Open, Stat, Delete, Exists with digest validation.

Phase 3 — internal/auth/ + internal/server/:
MCIAS client with Login and ValidateToken, 30s SHA-256-keyed cache
with lazy eviction and injectable clock for testing. TLS 1.3 minimum
with optional custom CA cert.
Chi router with RequireAuth middleware (Bearer token extraction,
WWW-Authenticate header, OCI error format), token endpoint (Basic
auth → bearer exchange via MCIAS), and /v2/ version check handler.

52 tests passing (14 storage + 9 auth + 9 server + 20 existing).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 14:51:19 -07:00

69 lines
2.0 KiB
Go

package storage
import (
"errors"
"path/filepath"
"testing"
)
func newTestStore(t *testing.T) *Store {
t.Helper()
dir := t.TempDir()
return New(filepath.Join(dir, "layers"), filepath.Join(dir, "uploads"))
}
func TestNew(t *testing.T) {
s := newTestStore(t)
if s == nil {
t.Fatal("New returned nil")
}
if s.layersPath == "" {
t.Fatal("layersPath is empty")
}
if s.uploadsPath == "" {
t.Fatal("uploadsPath is empty")
}
}
func TestValidateDigest(t *testing.T) {
valid := []string{
"sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"sha256:0000000000000000000000000000000000000000000000000000000000000000",
"sha256:abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789",
}
for _, d := range valid {
if err := validateDigest(d); err != nil {
t.Errorf("validateDigest(%q) = %v, want nil", d, err)
}
}
invalid := []string{
"",
"sha256:",
"sha256:abc",
"sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b85", // 63 chars
"sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b8555", // 65 chars
"sha256:E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", // uppercase
"md5:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", // wrong algo
"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", // missing prefix
"sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b85g", // non-hex char
}
for _, d := range invalid {
if err := validateDigest(d); !errors.Is(err, ErrInvalidDigest) {
t.Errorf("validateDigest(%q) = %v, want ErrInvalidDigest", d, err)
}
}
}
func TestBlobPath(t *testing.T) {
s := New("/data/layers", "/data/uploads")
digest := "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
got := s.blobPath(digest)
want := filepath.Join("/data/layers", "sha256", "e3",
"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855")
if got != want {
t.Fatalf("blobPath(%q)\n got %q\nwant %q", digest, got, want)
}
}