// intakeharness_test.go — a fake bot API and a recorder for what the poller // asked the daemon to do. Shared by the intake tests beside it. package telegramsink import ( "context" "encoding/json" "io" "net/http" "net/http/httptest" "strings" "sync" "testing" ) // fakeBot stands in for the bot API. It hands out queued updates once, records // every other call, and answers the ok=true envelope the poller checks. type fakeBot struct { mu sync.Mutex updates [][]update // one batch per getUpdates call, then empty calls []botCall srv *httptest.Server } type botCall struct { method string body map[string]any } func newFakeBot(t *testing.T, batches ...[]update) *fakeBot { t.Helper() b := &fakeBot{updates: batches} b.srv = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { method := r.URL.Path[strings.LastIndex(r.URL.Path, "/")+1:] raw, _ := io.ReadAll(r.Body) var body map[string]any _ = json.Unmarshal(raw, &body) b.mu.Lock() b.calls = append(b.calls, botCall{method: method, body: body}) var batch []update if method == "getUpdates" && len(b.updates) > 0 { batch, b.updates = b.updates[0], b.updates[1:] } b.mu.Unlock() w.Header().Set("Content-Type", "application/json") _ = json.NewEncoder(w).Encode(map[string]any{"ok": true, "result": batch}) })) t.Cleanup(b.srv.Close) return b } func (b *fakeBot) called(method string) []botCall { b.mu.Lock() defer b.mu.Unlock() var out []botCall for _, c := range b.calls { if c.method == method { out = append(out, c) } } return out } // recorder collects what the poller asked the daemon to do. type recorder struct { mu sync.Mutex turns []string conversation string traceID int64 corrections []correction reply string err error correctErr error } type correction struct { traceID int64 shouldBe string } func (r *recorder) turn(_ context.Context, conversation, text string) (string, int64, error) { r.mu.Lock() defer r.mu.Unlock() r.turns = append(r.turns, text) r.conversation = conversation return r.reply, r.traceID, r.err } func (r *recorder) correct(_ context.Context, traceID int64, shouldBe string) error { r.mu.Lock() defer r.mu.Unlock() r.corrections = append(r.corrections, correction{traceID, shouldBe}) return r.correctErr } func (r *recorder) took() []string { r.mu.Lock() defer r.mu.Unlock() return append([]string(nil), r.turns...) } const ownerChat = "4242" func newTestPoller(t *testing.T, b *fakeBot, rec *recorder) *Poller { t.Helper() sink, err := New(Config{BotToken: "secret-token", ChatID: ownerChat, BaseURL: b.srv.URL}) if err != nil { t.Fatal(err) } p, err := NewPoller(sink, rec.turn, rec.correct) if err != nil { t.Fatal(err) } return p } func msg(chatID, text string) update { return update{UpdateID: 7, Message: &message{ MessageID: 11, Text: text, Chat: chat{ID: json.Number(chatID)}, }} }