package oltp
import (
"path/filepath"
"testing"
"craftdesign.group/quarry/internal/uv"
)
// One row per name: a write applies only by fossil's rule, a tombstone
// keeps its row, the catalog is per repository, and a rebuild replaces
// a repository's rows and records the bucket it came from.
func TestUnversionedCatalog(t *testing.T) {
d, err := Open(filepath.Join(t.TempDir(), "oltp.db"))
if err != nil {
t.Fatal(err)
}
defer d.Close()
if files, err := d.UVFiles("w"); err != nil || len(files) != 0 {
t.Fatalf("FAIL: empty catalog = %v %v", files, err)
}
if _, ok, err := d.UVSource("w"); ok || err != nil {
t.Fatalf("FAIL: a source before any build: %v %v", ok, err)
}
put := func(f uv.File) bool {
t.Helper()
applied, err := d.PutUVFile("w", f)
if err != nil {
t.Fatal(err)
}
return applied
}
if !put(uv.File{Name: "a.txt", Mtime: 100, Hash: "bb", Size: 3, Who: "lou"}) {
t.Error("FAIL: the first write did not apply")
}
if put(uv.File{Name: "a.txt", Mtime: 99, Hash: "cc", Size: 4, Who: "mallory"}) {
t.Error("FAIL: an older write applied")
}
if put(uv.File{Name: "gone.txt", Mtime: 5, Deleted: true, Who: "lou"}) {
t.Error("FAIL: a tombstone for a name never held applied")
}
if !put(uv.File{Name: "a.txt", Mtime: 200, Deleted: true, Who: "dan"}) {
t.Error("FAIL: a newer tombstone did not apply")
}
f, ok, err := d.UVFile("w", "a.txt")
if err != nil || !ok || !f.Deleted || f.Hash != "" || f.Size != 0 || f.Mtime != 200 || f.Who != "dan" || f.At == "" {
t.Errorf("FAIL: tombstone row = %+v %v %v", f, ok, err)
}
if !put(uv.File{Name: "a.txt", Mtime: 300, Hash: "dd", Size: 7, Who: "lou"}) {
t.Error("FAIL: a newer write did not revive the name")
}
if _, ok, _ := d.UVFile("other", "a.txt"); ok {
t.Error("FAIL: a row leaked into another repository")
}
rebuilt := []uv.File{
{Name: "z.tgz", Mtime: 10, Hash: "ee", Size: 9, Who: "ci"},
{Name: "old.txt", Mtime: 11, Deleted: true, Who: "dan"},
}
if err := d.ReplaceUVCatalog("w", "https://acct.example/files", rebuilt); err != nil {
t.Fatal(err)
}
files, err := d.UVFiles("w")
if err != nil || len(files) != 2 || files[0].Name != "old.txt" || !files[0].Deleted || files[1].Name != "z.tgz" || files[1].Hash != "ee" || files[1].Who != "ci" {
t.Errorf("FAIL: rebuilt catalog = %+v %v", files, err)
}
if src, ok, err := d.UVSource("w"); !ok || err != nil || src != "https://acct.example/files" {
t.Errorf("FAIL: source = %q %v %v", src, ok, err)
}
if err := d.DropUVCatalog("w"); err != nil {
t.Fatal(err)
}
if files, _ := d.UVFiles("w"); len(files) != 0 {
t.Errorf("FAIL: drop left %v", files)
}
if _, ok, _ := d.UVSource("w"); ok {
t.Error("FAIL: drop left the source, so nothing would rebuild")
}
t.Log("ok: the catalog keeps one row per name by fossil's rule and rebuilds whole")
}