feat: sync Bot API gateway support

This commit is contained in:
A 2026-07-09 13:49:24 +08:00
parent 9a501f900a
commit 4c0cc2b7a7
44 changed files with 4609 additions and 49 deletions

View file

@ -0,0 +1,76 @@
package rpc
import (
"context"
"sync"
"testing"
"time"
"go.uber.org/zap/zaptest"
)
// TestBotAPIEnqueueDispatcherSynchronousBeforeRun 锁定未启动时的同步回退:
// 测试/未装配场景下 enqueue 行为与旧版完全一致job 在调用方 goroutine 内即时执行)。
func TestBotAPIEnqueueDispatcherSynchronousBeforeRun(t *testing.T) {
d := newBotAPIEnqueueDispatcher(zaptest.NewLogger(t), 4)
ran := false
d.Enqueue(context.Background(), func(context.Context) { ran = true })
if !ran {
t.Fatal("job must run synchronously before Run is called")
}
}
// TestBotAPIEnqueueDispatcherFIFOOrder 锁定启动后单 worker FIFO同一 bot 的
// update_id 顺序必须与 enqueue 顺序一致(乱序会让 bot 侧 getUpdates 看到错序消息)。
func TestBotAPIEnqueueDispatcherFIFOOrder(t *testing.T) {
d := newBotAPIEnqueueDispatcher(zaptest.NewLogger(t), 16)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
go d.Run(ctx)
for !d.started.Load() {
time.Sleep(time.Millisecond)
}
var mu sync.Mutex
var order []int
done := make(chan struct{})
for i := 0; i < 5; i++ {
i := i
d.Enqueue(context.Background(), func(context.Context) {
mu.Lock()
order = append(order, i)
if len(order) == 5 {
close(done)
}
mu.Unlock()
})
}
select {
case <-done:
case <-time.After(2 * time.Second):
t.Fatal("jobs did not complete")
}
mu.Lock()
defer mu.Unlock()
for i, got := range order {
if got != i {
t.Fatalf("order = %v, want FIFO", order)
}
}
}
// TestBotAPIEnqueueDispatcherFallsBackWhenFull 锁定队列满时的同步回退Bot API 队列行
// 是投递真值(无 getDifference 类兜底),满时发送者多等一次 INSERT绝不丢。
func TestBotAPIEnqueueDispatcherFallsBackWhenFull(t *testing.T) {
d := newBotAPIEnqueueDispatcher(zaptest.NewLogger(t), 1)
d.started.Store(true) // 模拟已启动但 worker 不消费(阻塞场景)
// 塞满容量 1 的队列。
d.Enqueue(context.Background(), func(context.Context) {})
ran := false
d.Enqueue(context.Background(), func(context.Context) { ran = true })
if !ran {
t.Fatal("job must fall back to synchronous execution when queue is full")
}
}