38be702188
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.
124 lines
2.9 KiB
Go
124 lines
2.9 KiB
Go
// 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)},
|
|
}}
|
|
}
|