Skip to content
quarry Artifact [ceb3729f9b]
Login

Artifact [ceb3729f9b]

Artifact ceb3729f9b71564ceb40160fa2cf502571978f16733967d3b276293dfabed408:


package oltp

import (
	"path/filepath"
	"testing"
)

func TestAutoAcceptRoundTrip(t *testing.T) {
	db, err := Open(filepath.Join(t.TempDir(), "o.db"))
	if err != nil {
		t.Fatal(err)
	}
	defer db.Close()
	if _, ok := db.AutoAcceptOf("alpha", "l1"); ok {
		t.Fatal("armed before anyone armed it")
	}
	if err := db.SetAutoAccept("alpha", "l1", "dan"); err != nil {
		t.Fatal(err)
	}
	if err := db.SetAutoAccept("alpha", "l1", "mel"); err != nil {
		t.Fatal(err) // re-arming moves the hand
	}
	if by, ok := db.AutoAcceptOf("alpha", "l1"); !ok || by != "mel" {
		t.Fatalf("armed by %q, want mel", by)
	}
	all, err := db.AutoAccepts()
	if err != nil || len(all) != 1 || all[0].Account != "mel" {
		t.Fatalf("list: %v %v", all, err)
	}
	if err := db.ClearAutoAccept("alpha", "l1"); err != nil {
		t.Fatal(err)
	}
	if _, ok := db.AutoAcceptOf("alpha", "l1"); ok {
		t.Fatal("still armed after clearing")
	}
	if err := db.ClearAutoAccept("alpha", "l1"); err != nil {
		t.Fatal("clearing twice must be harmless")
	}
}

// autoDB is an empty forge database, named so the arm tests read as
// being about arms rather than about opening a file.
func autoDB(t *testing.T) *DB {
	t.Helper()
	db, err := Open(filepath.Join(t.TempDir(), "o.db"))
	if err != nil {
		t.Fatal(err)
	}
	t.Cleanup(func() { db.Close() })
	return db
}

// An armed landing has to be able to say what it is waiting on. The
// sweep knows — it gets the real refusal from the deferred accept — and
// before this the answer went only to the forge's log, where a reader
// looking at the record could not reach it. Worse, the ordinary
// red-checks wait logs NOTHING by design, so an arm stuck on something
// else looked exactly like one that was working.
func TestAnArmRecordsWhatItIsWaitingOn(t *testing.T) {
	db := autoDB(t)
	if err := db.SetAutoAccept("quarry", "abc", "dmestas"); err != nil {
		t.Fatal(err)
	}
	// A fresh arm has nothing to report, which is not the same as being
	// stuck: it has not tried yet.
	st, ok := db.AutoStateOf("quarry", "abc")
	if !ok || st.Account != "dmestas" {
		t.Fatalf("FAIL: the arm reads back as %+v (ok=%v)", st, ok)
	}
	if st.Waiting != "" {
		t.Errorf("FAIL: a fresh arm claims to be waiting on %q", st.Waiting)
	}

	db.SetAutoWaiting("quarry", "abc", `repository "quarry" is still starting`)
	st, _ = db.AutoStateOf("quarry", "abc")
	if st.Waiting == "" {
		t.Error("FAIL: the reason was not recorded")
	}
	if st.At == "" {
		t.Error("FAIL: a recorded reason carries no time, so a reader cannot tell a stale one")
	}
	// Arming is unchanged by the note: the hand that writes the accept
	// is still whoever armed it.
	if who, ok := db.AutoAcceptOf("quarry", "abc"); !ok || who != "dmestas" {
		t.Errorf("FAIL: the note moved the arming hand to %q", who)
	}

	// Cleared when a try gets further, so a stale reason cannot sit
	// there describing a wait that is over.
	db.SetAutoWaiting("quarry", "abc", "")
	st, _ = db.AutoStateOf("quarry", "abc")
	if st.Waiting != "" || st.At != "" {
		t.Errorf("FAIL: clearing left %+v", st)
	}

	// And a note on something not armed is harmless, because the sweep
	// races a disarm by nature.
	db.SetAutoWaiting("quarry", "nope", "whatever")
	if _, ok := db.AutoStateOf("quarry", "nope"); ok {
		t.Error("FAIL: a note created an arm that nobody armed")
	}
}