Skip to content
quarry Artifact [aaa52b9a0d]
Login

Artifact [aaa52b9a0d]

Artifact aaa52b9a0df9c9b5df022acb7c0d6b759b4d95b38e96d741ffd26c9d91990a1f:


package main

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

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

func TestOltpPathDefaultsBesideTheDerivedData(t *testing.T) {
	if got, want := oltpPath("", "/var/quarry/data"), "/var/quarry/data/oltp.db"; got != want {
		t.Errorf("default = %q, want %q — an existing single-node deployment must not move", got, want)
	}
	if got, want := oltpPath("/srv/shared/forge.db", "/var/quarry/data"), "/srv/shared/forge.db"; got != want {
		t.Errorf("explicit = %q, want %q", got, want)
	}
}

// The invariant the flag exists for: --data is DERIVED and disposable,
// the OLTP is TRUTH and is not. Wiping the derived directory must not
// cost an account.
//
// This is the property a multi-node deployment depends on — each node
// keeps its own index and archives locally and cheaply, while the one
// thing that cannot be recomputed is shared. If the two ever drift back
// into the same directory, this fails.
func TestWipingDerivedDataKeepsTheAccounts(t *testing.T) {
	root := t.TempDir()
	data := filepath.Join(root, "data")
	shared := filepath.Join(root, "shared")
	for _, d := range []string{data, shared} {
		if err := os.MkdirAll(d, 0o755); err != nil {
			t.Fatal(err)
		}
	}
	oltpFile := filepath.Join(shared, "oltp.db")

	db, err := oltp.Open(oltpPath(oltpFile, data))
	if err != nil {
		t.Fatal(err)
	}
	if err := db.AddAccount("keeper", "pw-keeper-123", false); err != nil {
		t.Fatal(err)
	}
	if err := db.SetCategoryCaps("alpha", "reader", "u"); err != nil {
		t.Fatal(err)
	}
	db.Close()

	// Derived state is written where a node keeps it, and then thrown
	// away exactly as a redeploy or a rebuild would.
	if err := os.WriteFile(filepath.Join(data, "index.db"), []byte("derived"), 0o644); err != nil {
		t.Fatal(err)
	}
	if err := os.RemoveAll(data); err != nil {
		t.Fatal(err)
	}
	if _, err := os.Stat(oltpFile); err != nil {
		t.Fatalf("wiping --data destroyed the OLTP: %v", err)
	}

	// A fresh node, same shared truth.
	if err := os.MkdirAll(data, 0o755); err != nil {
		t.Fatal(err)
	}
	db2, err := oltp.Open(oltpPath(oltpFile, data))
	if err != nil {
		t.Fatal(err)
	}
	defer db2.Close()
	if _, ok := db2.AccountByName("keeper"); !ok {
		t.Error("the account did not survive a wipe of the derived directory")
	}
	if got := db2.CategoryCaps("alpha", "reader"); got != "u" {
		t.Errorf("capability grant = %q, want %q", got, "u")
	}
}

// And the converse, which is the bug the flag removes: without it the
// OLTP lives inside the derived directory, so wiping derived state — a
// rebuild, a fresh node — takes the accounts with it.
func TestWithoutTheFlagAWipeCostsTheAccounts(t *testing.T) {
	data := filepath.Join(t.TempDir(), "data")
	if err := os.MkdirAll(data, 0o755); err != nil {
		t.Fatal(err)
	}
	db, err := oltp.Open(oltpPath("", data)) // the old, interleaved layout
	if err != nil {
		t.Fatal(err)
	}
	if err := db.AddAccount("doomed", "pw-doomed-123", false); err != nil {
		t.Fatal(err)
	}
	db.Close()

	if err := os.RemoveAll(data); err != nil {
		t.Fatal(err)
	}
	if err := os.MkdirAll(data, 0o755); err != nil {
		t.Fatal(err)
	}
	db2, err := oltp.Open(oltpPath("", data))
	if err != nil {
		t.Fatal(err)
	}
	defer db2.Close()
	if _, ok := db2.AccountByName("doomed"); ok {
		t.Error("expected the account to be gone; the interleaved layout is what --oltp exists to escape")
	}
}