Skip to content
quarry Artifact [824a365490]
Login

Artifact [824a365490]

Artifact 824a36549018ae1214a8000ee5cfa4500a3e9beb0a8dab7ff5d47af7e62d320c:


package ingest

import (
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"testing"

	"craftdesign.group/quarry/internal/index"
)

// withFailingFrames puts a zit on PATH whose `frames` delivers the
// whole census and then fails, so a rebuild fails after its folds.
func withFailingFrames(t *testing.T) {
	t.Helper()
	real, err := exec.LookPath("zit")
	if err != nil {
		t.Skip("zit not on PATH")
	}
	dir := t.TempDir()
	script := fmt.Sprintf("#!/bin/sh\nif [ \"$1\" = frames ]; then %q \"$@\"; echo 'frames: injected failure' >&2; exit 1; fi\nexec %q \"$@\"\n", real, real)
	if err := os.WriteFile(filepath.Join(dir, "zit"), []byte(script), 0o755); err != nil {
		t.Fatal(err)
	}
	t.Setenv("PATH", dir+string(os.PathListSeparator)+os.Getenv("PATH"))
}

// The search index is external content over search_doc, and rows a
// rebuild folds while its triggers are off never reach it. A rebuild
// that failed after folding put the triggers back without rebuilding
// search, so the next update of such a row told the index to delete an
// entry it never held, and SQLite answered "database disk image is
// malformed".
func TestAFailedRebuildLeavesSearchConsistentWithItsRows(t *testing.T) {
	p, ix, _ := testPipeline(t)
	if _, err := p.Sync(); err != nil {
		t.Fatal(err)
	}
	tl, _, err := ix.Timeline(index.TimelineFilter{Limit: 1, Kind: "ci"})
	if err != nil || len(tl) == 0 {
		t.Fatalf("no check-in to begin with: %v", err)
	}

	withFailingFrames(t)
	if _, err := p.Reindex(); err == nil {
		t.Fatal("a rebuild with a failing census read reported success")
	}

	c := tl[0]
	if err := ix.FoldCheckins([]index.CheckinRecord{{Hash: c.Hash, Date: c.Date, User: c.User, Comment: "zanzibarite reworded"}}); err != nil {
		t.Fatalf("FAIL: updating a row folded by the failed rebuild: %v", err)
	}
	rs, err := ix.Search("zanzibarite", "", 10)
	if err != nil {
		t.Fatalf("FAIL: search after the update: %v", err)
	}
	if len(rs) != 1 {
		t.Errorf("FAIL: the updated row is not findable: %+v", rs)
	} else {
		t.Log("ok: a row folded by a failed rebuild updates cleanly and is findable")
	}
}