package oltp
import (
"errors"
"path/filepath"
"testing"
"time"
)
// One open request per agent, act and input; a decision lands once,
// and only by the owner; a request nobody answered in time closes.
func TestASignOffIsDecidedOnceByItsOwner(t *testing.T) {
db, err := Open(filepath.Join(t.TempDir(), "o.db"))
if err != nil {
t.Fatal(err)
}
defer db.Close()
ask := SignOff{Agent: "bot", Owner: "ann", Op: "repo.delete", Repo: "r", Code: "c", Input: `{"name":"r"}`, Summary: "delete r"}
first, err := db.RequestSignOff(ask)
if err != nil || first.ID == "" || first.State != "pending" {
t.Fatalf("FAIL: %+v %v", first, err)
}
if again, _ := db.RequestSignOff(ask); again.ID != first.ID {
t.Errorf("FAIL: the same request made twice is two requests")
}
if _, err := db.DecideSignOff(first.ID, "mallory", true); !errors.Is(err, ErrSignOffClosed) {
t.Errorf("FAIL: somebody else decided it: %v", err)
}
if got, err := db.DecideSignOff(first.ID, "ann", true); err != nil || got.State != "approved" {
t.Fatalf("FAIL: the owner's decision: %+v %v", got, err)
}
if _, err := db.DecideSignOff(first.ID, "ann", false); !errors.Is(err, ErrSignOffClosed) {
t.Errorf("FAIL: a second decision landed: %v", err)
}
if err := db.FailSignOff(first.ID, "it broke"); err != nil {
t.Fatal(err)
}
if got, _, _ := db.SignOffByID(first.ID); got.State != "failed" || got.Err != "it broke" {
t.Errorf("FAIL: the failure was not kept: %+v", got)
}
// Past the window: closed on read, refused on decision, and a new
// request may be made.
old, err := db.RequestSignOff(SignOff{Agent: "bot", Owner: "ann", Op: "repo.remove", Repo: "r", Code: "c", Input: "{}", Summary: "x"})
if err != nil {
t.Fatal(err)
}
stale := time.Now().UTC().Add(-SignOffWindow - time.Minute).Format(time.RFC3339)
if _, err := db.w.Exec(`UPDATE signoff SET requested = ? WHERE id = ?`, stale, old.ID); err != nil {
t.Fatal(err)
}
if _, err := db.DecideSignOff(old.ID, "ann", true); !errors.Is(err, ErrSignOffClosed) {
t.Errorf("FAIL: an expired request was approved: %v", err)
}
list, _ := db.SignOffsFor("ann", 10)
for _, s := range list {
if s.ID == old.ID && s.State == "pending" {
t.Errorf("FAIL: an expired request reads as waiting")
}
}
if fresh, err := db.RequestSignOff(SignOff{Agent: "bot", Owner: "ann", Op: "repo.remove", Repo: "r", Code: "c", Input: "{}", Summary: "x"}); err != nil || fresh.ID == old.ID {
t.Errorf("FAIL: asking again after expiry: %+v %v", fresh, err)
}
}