package artifacts import ( "errors" "os" "path/filepath" "strings" "testing" ) func TestEnsureLayoutCreatesExpectedDirectories(t *testing.T) { store := NewLocalStore(t.TempDir()) paths, err := store.EnsureLayout("session-1") if err != nil { t.Fatalf("EnsureLayout() error = %v", err) } checkDirExists(t, paths.Root) checkDirExists(t, paths.InputsDir) checkDirExists(t, paths.AudioDir) checkDirExists(t, paths.TranscriptsDir) checkDirExists(t, paths.TranscriptsRawDir) checkDirExists(t, paths.TranscriptsTrimmedDir) checkDirExists(t, paths.ArtifactsDir) checkDirExists(t, paths.ConfigDir) checkDirExists(t, paths.LogsDir) if filepath.Base(paths.ManifestPath) != "manifest.json" { t.Fatalf("ManifestPath = %q, want basename manifest.json", paths.ManifestPath) } if filepath.Base(paths.LockPath) != ".lock" { t.Fatalf("LockPath = %q, want basename .lock", paths.LockPath) } } func TestChecksumCalculation(t *testing.T) { store := NewLocalStore(t.TempDir()) path := filepath.Join(t.TempDir(), "sample.txt") if err := os.WriteFile(path, []byte("hello"), 0o644); err != nil { t.Fatalf("WriteFile() error = %v", err) } checksum, err := store.Checksum(path) if err != nil { t.Fatalf("Checksum() error = %v", err) } const want = "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824" if checksum != want { t.Fatalf("checksum = %q, want %q", checksum, want) } } func TestLockAcquireRelease(t *testing.T) { store := NewLocalStore(t.TempDir()) lock, err := store.AcquireSessionLock("session-1") if err != nil { t.Fatalf("AcquireSessionLock() error = %v", err) } exists, err := store.Exists(lock.path) if err != nil { t.Fatalf("Exists() error = %v", err) } if !exists { t.Fatalf("expected lock file %q to exist", lock.path) } if err := store.ReleaseSessionLock(lock); err != nil { t.Fatalf("ReleaseSessionLock() error = %v", err) } exists, err = store.Exists(lock.path) if err != nil { t.Fatalf("Exists() error = %v", err) } if exists { t.Fatalf("expected lock file %q to be removed", lock.path) } } func TestLockConflict(t *testing.T) { store := NewLocalStore(t.TempDir()) lock1, err := store.AcquireSessionLock("session-1") if err != nil { t.Fatalf("first AcquireSessionLock() error = %v", err) } defer func() { _ = store.ReleaseSessionLock(lock1) }() _, err = store.AcquireSessionLock("session-1") if err == nil { t.Fatal("expected lock conflict error, got nil") } if !errors.Is(err, ErrLockConflict) { t.Fatalf("error = %v, want ErrLockConflict", err) } } func TestWriteFileAtomicAndOverwrite(t *testing.T) { store := NewLocalStore(t.TempDir()) path := filepath.Join(t.TempDir(), "out", "value.txt") if err := store.WriteFileAtomic(path, []byte("one"), 0o644); err != nil { t.Fatalf("first WriteFileAtomic() error = %v", err) } if err := store.WriteFileAtomic(path, []byte("two"), 0o644); err != nil { t.Fatalf("second WriteFileAtomic() error = %v", err) } data, err := os.ReadFile(path) if err != nil { t.Fatalf("ReadFile() error = %v", err) } if string(data) != "two" { t.Fatalf("file content = %q, want %q", string(data), "two") } entries, err := os.ReadDir(filepath.Dir(path)) if err != nil { t.Fatalf("ReadDir() error = %v", err) } for _, e := range entries { if strings.Contains(e.Name(), ".tmp-") { t.Fatalf("unexpected temp file residue: %s", e.Name()) } } } func TestCopyInput(t *testing.T) { root := t.TempDir() store := NewLocalStore(root) srcPath := filepath.Join(t.TempDir(), "speakers.yml") content := "alice: alice.flac\n" if err := os.WriteFile(srcPath, []byte(content), 0o644); err != nil { t.Fatalf("WriteFile() error = %v", err) } ref, err := store.CopyInput("session-1", srcPath, "inputs/speakers.yml") if err != nil { t.Fatalf("CopyInput() error = %v", err) } if ref.Kind != "input" { t.Fatalf("ref.Kind = %q, want %q", ref.Kind, "input") } if ref.RelativePath != filepath.Clean("inputs/speakers.yml") { t.Fatalf("ref.RelativePath = %q, want %q", ref.RelativePath, filepath.Clean("inputs/speakers.yml")) } if !strings.HasPrefix(ref.AbsolutePath, root) { t.Fatalf("ref.AbsolutePath = %q, want under workspace root %q", ref.AbsolutePath, root) } data, err := os.ReadFile(ref.AbsolutePath) if err != nil { t.Fatalf("ReadFile() error = %v", err) } if string(data) != content { t.Fatalf("copied content = %q, want %q", string(data), content) } } func checkDirExists(t *testing.T, path string) { t.Helper() info, err := os.Stat(path) if err != nil { t.Fatalf("Stat(%q) error = %v", path, err) } if !info.IsDir() { t.Fatalf("%q is not a directory", path) } }