package web import ( "strings" "testing" "pete/internal/storage" ) // The retreat bulletin — gogobee's newest event type. // // The failure this guards against is silent and total: handleAdventureIngest // answers an unrecognized event_type with 400, and gogobee's sender treats any // non-2xx as a failure, retries eight times over ~two hours, and then PARKS the // row forever. So a gogobee that emits `retreat` against a Pete that doesn't // know the word doesn't log an error anyone reads — it just quietly drops every // retreat the realm ever files. Pete has to learn the word first, and this test // is what says he has. func TestAdventureIngest_AcceptsRetreat(t *testing.T) { const token = "s3cret-token" s, posted := newAdvServer(t, token) f := AdvFact{ GUID: "retreat:abc:1000", EventType: "retreat", Tier: "bulletin", Actors: []string{"Brannigan"}, Subject: "Brannigan", Zone: "the Underforge", Level: 12, Count: 3, Outcome: "retreated", OccurredAt: 1000, } if rw := postFact(t, s, token, f); rw.Code != 200 { t.Fatalf("ingest status = %d body=%s — Pete rejected a retreat, so gogobee will "+ "retry it eight times and park it forever", rw.Code, rw.Body.String()) } got, err := storage.GetStoryByGUID("retreat:abc:1000") if err != nil || got == nil { t.Fatalf("retreat was accepted but not stored: %v", err) } // It has to actually say what happened, in Pete's voice, using only the // supplied facts. body := got.Headline + " " + got.Lede for _, want := range []string{"Brannigan", "the Underforge"} { if !strings.Contains(body, want) { t.Errorf("rendered retreat is missing %q: %q", want, body) } } if !strings.Contains(got.Lede, "3 days in") { t.Errorf("the day count never made it into the copy: %q", got.Lede) } // Bulletin, not priority: a retreat goes in the daily digest, it does not // interrupt the room. Pete announcing every failed run live would be a // firehose — and an unkind one. if len(*posted) != 0 { t.Errorf("a bulletin was posted live: %+v", *posted) } }