Skip to content
quarry Artifact [c4273877ba]
Login

Artifact [c4273877ba]

Artifact c4273877ba5bc1902466a389065cb10ad13c57e69d916ea00fbd53cd072c5e1a:


package index

import (
	"os"
	"path/filepath"
	"strings"
	"testing"
)

// Close waits for the rewarms it started.
//
// A fold spawns one recompute per branch that was warm, off the request
// path. Nothing owned those goroutines: Close returned while they were
// still querying, so the handle went away underneath them. In a test
// that surfaced as SQLite recreating a -wal file inside a directory
// t.TempDir was removing — "directory not empty", failing a test whose
// assertions had all passed. In a running forge it is a query against a
// closed database at shutdown or when a repository is unregistered.
func TestCloseWaitsForTheRewarmsItStarted(t *testing.T) {
	dir := t.TempDir()
	ix, err := Open(filepath.Join(dir, "i.db"))
	if err != nil {
		t.Fatal(err)
	}
	ciu(t, ix, "a1", "dan", "trunk", "2026-06-01T09:00:00")
	if _, err := ix.ActivityDays(""); err != nil {
		t.Fatal(err)
	}
	// A fold invalidates and rewarms what was warm.
	ciu(t, ix, "a2", "dan", "trunk", "2026-06-02T09:00:00")
	ix.invalidateCounts()

	if err := ix.Close(); err != nil {
		t.Fatalf("close: %v", err)
	}
	// Nothing is still running, so nothing can put a file back.
	ix.warmMu.Lock()
	inflight := len(ix.warming)
	ix.warmMu.Unlock()
	if inflight != 0 {
		t.Errorf("FAIL: Close returned with %d rewarm(s) still in flight", inflight)
	}

	// The directory is quiet: removing it must not race a writer.
	if err := os.RemoveAll(dir); err != nil {
		t.Fatalf("FAIL: the store is still being written after Close: %v", err)
	}
	if _, err := os.Stat(dir); !os.IsNotExist(err) {
		t.Errorf("FAIL: %s survived removal, so something recreated it: %v", dir, err)
	}
}

// A closing index starts no new rewarm. The next reader pays a cold
// read — the same cost as never having warmed it, and far cheaper than
// a query against a database that is going away.
func TestAClosingIndexStartsNoRewarm(t *testing.T) {
	ix, err := Open(filepath.Join(t.TempDir(), "i.db"))
	if err != nil {
		t.Fatal(err)
	}
	ciu(t, ix, "a1", "dan", "trunk", "2026-06-01T09:00:00")
	if _, err := ix.ActivityDays(""); err != nil {
		t.Fatal(err)
	}
	if err := ix.Close(); err != nil {
		t.Fatal(err)
	}
	// After Close, a fold's rewarm request is refused rather than run.
	ix.rewarmActivityDays([]string{"", "trunk"})
	ix.warmMu.Lock()
	started := len(ix.warming)
	ix.warmMu.Unlock()
	if started != 0 {
		t.Errorf("FAIL: %d rewarm(s) started on a closed index", started)
	}
}

// Close is idempotent enough to be called twice without hanging: the
// second call waits on a WaitGroup nobody will add to.
func TestCloseTwiceDoesNotHang(t *testing.T) {
	ix, err := Open(filepath.Join(t.TempDir(), "i.db"))
	if err != nil {
		t.Fatal(err)
	}
	if err := ix.Close(); err != nil {
		t.Fatal(err)
	}
	if err := ix.Close(); err != nil && !strings.Contains(err.Error(), "closed") {
		t.Logf("second close: %v", err)
	}
}