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")
}
}