e3c8979e8d
- cmd/fn/doctor.go - cmd/fn/main.go - cpp/apps/primitives_gallery/playground/tables/CMakeLists.txt - cpp/apps/primitives_gallery/playground/tables/data_table.cpp - cpp/apps/primitives_gallery/playground/tables/data_table_logic.cpp - cpp/apps/primitives_gallery/playground/tables/data_table_logic.h - cpp/apps/primitives_gallery/playground/tables/self_test.cpp - cpp/apps/primitives_gallery/playground/tables/tql.cpp - cpp/apps/primitives_gallery/playground/tables/viz.cpp - cpp/apps/primitives_gallery/playground/tables/viz.h - ... Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
211 lines
5.3 KiB
Go
211 lines
5.3 KiB
Go
package infra
|
|
|
|
import (
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
// makeTestVaultFile creates a minimal VaultFile for testing.
|
|
func makeTestVaultFile(relPath, mime, bucket, subBucket string) VaultFile {
|
|
return VaultFile{
|
|
VaultID: "test_vault",
|
|
VaultName: "test",
|
|
RelPath: relPath,
|
|
Size: 100,
|
|
Mtime: time.Now().Unix(),
|
|
Sha256: "abc123def456abc123def456abc123def456abc123def456abc123def456abc1",
|
|
Mime: mime,
|
|
Ext: ".csv",
|
|
Bucket: bucket,
|
|
SubBucket: subBucket,
|
|
}
|
|
}
|
|
|
|
func openInMemoryVaultIndex(t *testing.T) interface{ Close() error } {
|
|
t.Helper()
|
|
dir := t.TempDir()
|
|
db, err := VaultIndexOpen(dir)
|
|
if err != nil {
|
|
t.Fatalf("VaultIndexOpen: %v", err)
|
|
}
|
|
return db
|
|
}
|
|
|
|
func TestVaultIndexWrite_FreshInsert(t *testing.T) {
|
|
t.Run("N archivos nuevos — Inserted=N", func(t *testing.T) {
|
|
dir := t.TempDir()
|
|
db, err := VaultIndexOpen(dir)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer db.Close()
|
|
|
|
files := []VaultFile{
|
|
makeTestVaultFile("data/raw/a.csv", "text/csv", "data", "raw"),
|
|
makeTestVaultFile("data/raw/b.csv", "text/csv", "data", "raw"),
|
|
makeTestVaultFile("knowledge/decisions/x.md", "text/markdown", "knowledge", "decisions"),
|
|
}
|
|
|
|
report, err := VaultIndexWrite(db, files, false)
|
|
if err != nil {
|
|
t.Fatalf("VaultIndexWrite: %v", err)
|
|
}
|
|
if report.Inserted != 3 {
|
|
t.Errorf("Inserted = %d, want 3", report.Inserted)
|
|
}
|
|
if report.Updated != 0 {
|
|
t.Errorf("Updated = %d, want 0", report.Updated)
|
|
}
|
|
if report.Pruned != 0 {
|
|
t.Errorf("Pruned = %d, want 0", report.Pruned)
|
|
}
|
|
if report.FTS != 3 {
|
|
t.Errorf("FTS = %d, want 3", report.FTS)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestVaultIndexWrite_Upsert(t *testing.T) {
|
|
t.Run("re-escritura con mtime distinto — Updated=N", func(t *testing.T) {
|
|
dir := t.TempDir()
|
|
db, err := VaultIndexOpen(dir)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer db.Close()
|
|
|
|
files := []VaultFile{
|
|
makeTestVaultFile("data/raw/a.csv", "text/csv", "data", "raw"),
|
|
makeTestVaultFile("data/raw/b.csv", "text/csv", "data", "raw"),
|
|
}
|
|
|
|
if _, err := VaultIndexWrite(db, files, false); err != nil {
|
|
t.Fatalf("first write: %v", err)
|
|
}
|
|
|
|
// Modify mtime to simulate file change.
|
|
files[0].Mtime = time.Now().Unix() + 100
|
|
files[1].Mtime = time.Now().Unix() + 200
|
|
|
|
report, err := VaultIndexWrite(db, files, false)
|
|
if err != nil {
|
|
t.Fatalf("second write: %v", err)
|
|
}
|
|
if report.Inserted != 0 {
|
|
t.Errorf("Inserted = %d, want 0", report.Inserted)
|
|
}
|
|
if report.Updated != 2 {
|
|
t.Errorf("Updated = %d, want 2", report.Updated)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestVaultIndexWrite_Prune(t *testing.T) {
|
|
t.Run("prune elimina filas ausentes", func(t *testing.T) {
|
|
dir := t.TempDir()
|
|
db, err := VaultIndexOpen(dir)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer db.Close()
|
|
|
|
// Write A and B.
|
|
ab := []VaultFile{
|
|
makeTestVaultFile("data/raw/a.csv", "text/csv", "data", "raw"),
|
|
makeTestVaultFile("data/raw/b.csv", "text/csv", "data", "raw"),
|
|
}
|
|
if _, err := VaultIndexWrite(db, ab, false); err != nil {
|
|
t.Fatalf("first write: %v", err)
|
|
}
|
|
|
|
// Write only A with prune=true — B should be deleted.
|
|
onlyA := []VaultFile{ab[0]}
|
|
report, err := VaultIndexWrite(db, onlyA, true)
|
|
if err != nil {
|
|
t.Fatalf("prune write: %v", err)
|
|
}
|
|
if report.Pruned != 1 {
|
|
t.Errorf("Pruned = %d, want 1", report.Pruned)
|
|
}
|
|
|
|
// Verify B is gone.
|
|
var count int
|
|
err = db.QueryRow(`SELECT count(*) FROM files WHERE rel_path = 'data/raw/b.csv'`).Scan(&count)
|
|
if err != nil {
|
|
t.Fatalf("query: %v", err)
|
|
}
|
|
if count != 0 {
|
|
t.Errorf("b.csv still present after prune")
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestVaultIndexWrite_NoPrune(t *testing.T) {
|
|
t.Run("sin prune, filas previas persisten", func(t *testing.T) {
|
|
dir := t.TempDir()
|
|
db, err := VaultIndexOpen(dir)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer db.Close()
|
|
|
|
ab := []VaultFile{
|
|
makeTestVaultFile("data/raw/a.csv", "text/csv", "data", "raw"),
|
|
makeTestVaultFile("data/raw/b.csv", "text/csv", "data", "raw"),
|
|
}
|
|
if _, err := VaultIndexWrite(db, ab, false); err != nil {
|
|
t.Fatalf("first write: %v", err)
|
|
}
|
|
|
|
// Write only A without prune — B must remain.
|
|
onlyA := []VaultFile{ab[0]}
|
|
report, err := VaultIndexWrite(db, onlyA, false)
|
|
if err != nil {
|
|
t.Fatalf("second write: %v", err)
|
|
}
|
|
if report.Pruned != 0 {
|
|
t.Errorf("Pruned = %d, want 0", report.Pruned)
|
|
}
|
|
|
|
var count int
|
|
err = db.QueryRow(`SELECT count(*) FROM files`).Scan(&count)
|
|
if err != nil {
|
|
t.Fatalf("query: %v", err)
|
|
}
|
|
if count != 2 {
|
|
t.Errorf("files count = %d, want 2", count)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestVaultIndexWrite_FTSMatch(t *testing.T) {
|
|
t.Run("FTS5 MATCH funciona tras escritura", func(t *testing.T) {
|
|
dir := t.TempDir()
|
|
db, err := VaultIndexOpen(dir)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer db.Close()
|
|
|
|
files := []VaultFile{
|
|
makeTestVaultFile("data/raw/foo_report.csv", "text/csv", "data", "raw"),
|
|
makeTestVaultFile("data/raw/bar_data.csv", "text/csv", "data", "raw"),
|
|
}
|
|
if _, err := VaultIndexWrite(db, files, false); err != nil {
|
|
t.Fatalf("write: %v", err)
|
|
}
|
|
|
|
// FTS5 on rel_path column: MATCH 'foo*'
|
|
var count int
|
|
err = db.QueryRow(
|
|
`SELECT count(*) FROM files_fts WHERE files_fts MATCH 'rel_path:foo*'`,
|
|
).Scan(&count)
|
|
if err != nil {
|
|
t.Fatalf("FTS MATCH query: %v", err)
|
|
}
|
|
if count != 1 {
|
|
t.Errorf("FTS MATCH rel_path:foo* = %d rows, want 1", count)
|
|
}
|
|
})
|
|
}
|