package main // Withdraw (novox/hq issue 1081): the operator's decision that a reserved or proposed record is dropped, so its // number stays spent and the record stops asking anything of anyone. import ( "context" "strings" "testing" ) func TestAReservedRecordIsWithdrawnAtOnce(t *testing.T) { eachStore(t, func(t *testing.T, s Store) { w := imported(t, s) n := w.reserved(t, "author@test") key := Key{KindDecision, n} out, err := w.k.WithdrawRecord("operator@shanks", key, "never proposed") if err != nil { t.Fatal(err) } if out.Status != StatusWithdrawn || out.Record != key.String() { t.Fatalf("%+v", out) } e := mustGet(t, w.k.Store, key) if e.Current.Status != StatusWithdrawn { t.Fatalf("status %q", e.Current.Status) } }) } func TestAProposedRecordNeedingTheOperatorIsWithdrawnWithItsAskEndedAndItsReviewCleared(t *testing.T) { eachStore(t, func(t *testing.T, s Store) { w := imported(t, s) n := w.reserved(t, "author@test") key := Key{KindDecision, n} p := valid(n) p.NeedsOperator = true p.Brief = &Brief{Headline: "a test record that needs the operator", Summary: "the operator is asked, then the proposal is withdrawn."} if _, err := w.k.Propose("author@test", p); err != nil { t.Fatal(err) } w.reviewAll(t) before := mustGet(t, w.k.Store, key) if before.Current.Status != StatusProposed || before.Current.Ask == nil || before.Current.Ask.Said != AskWaiting { t.Fatalf("not waiting for the operator: %+v", before.Current) } why := "replaced by research on moving designs into the knowledge base" out, err := w.k.WithdrawRecord("operator@shanks", key, why) if err != nil { t.Fatal(err) } if out.Status != StatusWithdrawn { t.Fatalf("status %q", out.Status) } after := mustGet(t, w.k.Store, key) if after.Current.Status != StatusWithdrawn { t.Fatalf("status %q", after.Current.Status) } if after.Versions != before.Versions+1 { t.Fatalf("versions %d, want %d", after.Versions, before.Versions+1) } if after.Current.Ask == nil || after.Current.Ask.Said == AskWaiting { t.Fatalf("the waiting ask was not ended: %+v", after.Current.Ask) } if !contains(w.router.cancelled, before.Current.Ask.ID) { t.Fatalf("the router was not told to take back the ask %s: cancelled %v", before.Current.Ask.ID, w.router.cancelled) } if after.Current.Judging != nil { t.Fatalf("a pending review was not cleared: %+v", after.Current.Judging) } vs, err := w.k.Store.Versions(context.Background(), key) if err != nil { t.Fatal(err) } last := vs[len(vs)-1] if last.By != "operator@shanks" || !strings.Contains(last.Why, why) { t.Fatalf("the new version is not by the caller with the why: %+v", last) } }) } func TestAnAcceptedRecordRefusesWithdrawNamingWhy(t *testing.T) { eachStore(t, func(t *testing.T, s Store) { w := imported(t, s) n := w.reserved(t, "author@test") key := Key{KindDecision, n} w.accepted(t, "author@test", valid(n)) if _, err := w.k.WithdrawRecord("operator@shanks", key, "no longer wanted"); err == nil || !strings.Contains(err.Error(), "accepted") { t.Fatalf("err %v", err) } e := mustGet(t, w.k.Store, key) if e.Current.Status != StatusAccepted { t.Fatalf("an accepted record was changed: %q", e.Current.Status) } }) } func TestAWithdrawnRecordRefusesWithdrawAgain(t *testing.T) { eachStore(t, func(t *testing.T, s Store) { w := imported(t, s) n := w.reserved(t, "author@test") key := Key{KindDecision, n} if _, err := w.k.WithdrawRecord("operator@shanks", key, "first"); err != nil { t.Fatal(err) } if _, err := w.k.WithdrawRecord("operator@shanks", key, "again"); err == nil || !strings.Contains(err.Error(), "withdrawn") { t.Fatalf("err %v", err) } }) } func TestWithdrawNeedsWhyAndRefusesARecordItHoldsNoneOf(t *testing.T) { eachStore(t, func(t *testing.T, s Store) { w := imported(t, s) n := w.reserved(t, "author@test") if _, err := w.k.WithdrawRecord("operator@shanks", Key{KindDecision, n}, " "); err == nil { t.Fatal("an empty why was accepted") } if _, err := w.k.WithdrawRecord("operator@shanks", Key{KindDecision, 999999}, "why"); err == nil { t.Fatal("a record it holds none of was accepted") } }) }