a fake bot API to test the poller against (V-637)

An httptest server that hands out one batch of updates per getUpdates call
and records everything else, plus a recorder for what the poller asked the
daemon to do.
This commit is contained in:
2026-08-06 20:53:48 +04:00
parent d42372e996
commit 38be702188
@@ -0,0 +1,123 @@
// 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)},
}}
}