Files
lukaszraczylo 607c3e8ddd test(bench): cross-library benchmarks vs top 5 go telegram libraries
Adds test/benchmarks/ as a separate Go module so competitor deps
(go-telegram-bot-api/v5, telebot.v3, go-telegram/bot, telego,
echotron/v3) stay out of the root go.mod.

Hot paths covered:
  - Webhook decode  (small Update -> typed Update struct)
  - Large unmarshal (Update with entities + reply markup + photo array)
  - API round-trip  (sendMessage against httptest.Server)
  - Dispatch route  (20 handlers, last-registered matches)

Results on Apple M4 Max / go1.26.2: ours wins 3 of 4 paths and is
2nd of 5 in the round-trip path. Full report at
docs/benchmarks/2026-05-10-comparison.md, raw output committed under
test/benchmarks/results/.

Caveats called out in the report:
  - codec asymmetry (we ship goccy/go-json; competitors mostly stdlib)
  - echotron call bench skipped — built-in rate limiter not externally
    configurable; would measure throttling, not the library
  - dispatch bench limited to libs with a public sync entry point
    (ours, telebot, gobot); gotba has no dispatcher, telego/echotron
    use channel/per-chat paradigms not directly comparable

Also gitignores docs/superpowers/ (local brainstorm/spec scratch)
and regenerates docs/reference/dispatch.md after the new
Router.Process method.
2026-05-10 21:52:00 +01:00

81 lines
1.8 KiB
Go

// Webhook decode benchmarks: parse a small text-message Update from a fixed
// JSON payload using each library's typed Update struct. Pure CPU — no
// network. Stresses the JSON codec each library ships with by default.
package benchmarks
import (
"encoding/json"
"testing"
"github.com/lukaszraczylo/go-telegram/api"
"github.com/lukaszraczylo/go-telegram/test/benchmarks/shared"
echotron "github.com/NicoNex/echotron/v3"
tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5"
gobotmodels "github.com/go-telegram/bot/models"
telego "github.com/mymmrac/telego"
tele "gopkg.in/telebot.v3"
)
var smallUpdateBytes = []byte(shared.SmallUpdateJSON)
func BenchmarkWebhook_ours(b *testing.B) {
b.ReportAllocs()
for b.Loop() {
var u api.Update
if err := json.Unmarshal(smallUpdateBytes, &u); err != nil {
b.Fatal(err)
}
}
}
func BenchmarkWebhook_gotba(b *testing.B) {
b.ReportAllocs()
for b.Loop() {
var u tgbotapi.Update
if err := json.Unmarshal(smallUpdateBytes, &u); err != nil {
b.Fatal(err)
}
}
}
func BenchmarkWebhook_telebot(b *testing.B) {
b.ReportAllocs()
for b.Loop() {
var u tele.Update
if err := json.Unmarshal(smallUpdateBytes, &u); err != nil {
b.Fatal(err)
}
}
}
func BenchmarkWebhook_gobot(b *testing.B) {
b.ReportAllocs()
for b.Loop() {
var u gobotmodels.Update
if err := json.Unmarshal(smallUpdateBytes, &u); err != nil {
b.Fatal(err)
}
}
}
func BenchmarkWebhook_telego(b *testing.B) {
b.ReportAllocs()
for b.Loop() {
var u telego.Update
if err := json.Unmarshal(smallUpdateBytes, &u); err != nil {
b.Fatal(err)
}
}
}
func BenchmarkWebhook_echotron(b *testing.B) {
b.ReportAllocs()
for b.Loop() {
var u echotron.Update
if err := json.Unmarshal(smallUpdateBytes, &u); err != nil {
b.Fatal(err)
}
}
}