Sync telesrv b96f2dd (feat(bot): complete keyboards callbacks and durable delivery). Skipped private docs and preserved public README files per sync rules; normalized the appearance seed log label for public naming.
191 lines
8.5 KiB
Go
191 lines
8.5 KiB
Go
package memory
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
"time"
|
|
|
|
"telesrv/internal/domain"
|
|
)
|
|
|
|
func botAPIMessageRequest(botID int64, kind domain.BotAPIUpdateKind, messageID int) domain.EnqueueBotAPIUpdateRequest {
|
|
return domain.EnqueueBotAPIUpdateRequest{
|
|
BotUserID: botID,
|
|
Kind: kind,
|
|
Peer: domain.Peer{Type: domain.PeerTypeUser, ID: 2001},
|
|
MessageID: messageID,
|
|
SourcePts: messageID,
|
|
Date: 1700000000 + messageID,
|
|
}
|
|
}
|
|
|
|
func TestBotAPIPollLeaseCompareOwnerAndExpiry(t *testing.T) {
|
|
ctx := context.Background()
|
|
store := NewBotAPIUpdateStore()
|
|
if acquired, err := store.AcquireBotAPIPollLease(ctx, 1001, "one", 20*time.Millisecond); err != nil || !acquired {
|
|
t.Fatalf("first acquire=%v err=%v", acquired, err)
|
|
}
|
|
if acquired, err := store.AcquireBotAPIPollLease(ctx, 1001, "two", time.Second); err != nil || acquired {
|
|
t.Fatalf("competing acquire=%v err=%v", acquired, err)
|
|
}
|
|
if err := store.ReleaseBotAPIPollLease(ctx, 1001, "stale"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if acquired, _ := store.AcquireBotAPIPollLease(ctx, 1001, "two", time.Second); acquired {
|
|
t.Fatal("stale release removed active owner")
|
|
}
|
|
time.Sleep(25 * time.Millisecond)
|
|
if acquired, err := store.AcquireBotAPIPollLease(ctx, 1001, "two", time.Second); err != nil || !acquired {
|
|
t.Fatalf("expired acquire=%v err=%v", acquired, err)
|
|
}
|
|
}
|
|
|
|
func TestBotAPIWebhookLeaseWakeAndAtomicDrop(t *testing.T) {
|
|
ctx := context.Background()
|
|
store := NewBotAPIUpdateStore()
|
|
if _, created, err := store.EnqueueBotAPIUpdate(ctx, botAPIMessageRequest(1001, domain.BotAPIUpdateMessage, 1)); err != nil || !created {
|
|
t.Fatalf("enqueue initial created=%v err=%v", created, err)
|
|
}
|
|
config := domain.BotAPIWebhook{BotUserID: 1001, URL: "https://example.test/hook", MaxConnections: 8}
|
|
if err := store.SetBotAPIWebhook(ctx, config, true); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if count, _ := store.PendingBotAPIUpdateCount(ctx, 1001); count != 0 {
|
|
t.Fatalf("pending after atomic drop=%d", count)
|
|
}
|
|
if acquired, err := store.AcquireBotAPIWebhookLease(ctx, 1001, "worker-1", time.Second); err != nil || !acquired {
|
|
t.Fatalf("lease acquire=%v err=%v", acquired, err)
|
|
}
|
|
if acquired, _ := store.AcquireBotAPIWebhookLease(ctx, 1001, "worker-2", time.Second); acquired {
|
|
t.Fatal("second webhook worker acquired active lease")
|
|
}
|
|
if err := store.RecordBotAPIWebhookSuccess(ctx, 1001, "worker-1", time.Now().Add(time.Hour)); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if due, err := store.ListDueBotAPIWebhooks(ctx, 10); err != nil || len(due) != 0 {
|
|
t.Fatalf("idle due=%#v err=%v", due, err)
|
|
}
|
|
if _, created, err := store.EnqueueBotAPIUpdate(ctx, botAPIMessageRequest(1001, domain.BotAPIUpdateMessage, 2)); err != nil || !created {
|
|
t.Fatalf("enqueue wake created=%v err=%v", created, err)
|
|
}
|
|
if due, err := store.ListDueBotAPIWebhooks(ctx, 10); err != nil || len(due) != 1 || due[0].BotUserID != 1001 {
|
|
t.Fatalf("woken due=%#v err=%v", due, err)
|
|
}
|
|
}
|
|
|
|
func TestBotAPIWebhookAllowedUpdatesOmissionPreservesPolicy(t *testing.T) {
|
|
ctx := context.Background()
|
|
store := NewBotAPIUpdateStore()
|
|
if err := store.SetBotAPIAllowedUpdates(ctx, 1001, []domain.BotAPIUpdateKind{domain.BotAPIUpdateCallbackQuery}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
config := domain.BotAPIWebhook{BotUserID: 1001, URL: "https://example.test/one", MaxConnections: 8}
|
|
if err := store.SetBotAPIWebhook(ctx, config, false); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
stored, found, err := store.BotAPIWebhook(ctx, 1001)
|
|
if err != nil || !found || len(stored.AllowedUpdates) != 1 || stored.AllowedUpdates[0] != domain.BotAPIUpdateCallbackQuery {
|
|
t.Fatalf("preserved webhook=%#v found=%v err=%v", stored, found, err)
|
|
}
|
|
if row, created, err := store.EnqueueBotAPIUpdate(ctx, botAPIMessageRequest(1001, domain.BotAPIUpdateMessage, 1)); err != nil || created || row.ID != 0 {
|
|
t.Fatalf("message bypassed preserved policy: row=%#v created=%v err=%v", row, created, err)
|
|
}
|
|
config.URL = "https://example.test/two"
|
|
config.AllowedUpdatesSet = true // Explicit empty resets to the default/all policy.
|
|
if err := store.SetBotAPIWebhook(ctx, config, false); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
stored, found, err = store.BotAPIWebhook(ctx, 1001)
|
|
if err != nil || !found || stored.AllowedUpdates != nil {
|
|
t.Fatalf("explicit empty webhook=%#v found=%v err=%v", stored, found, err)
|
|
}
|
|
if _, created, err := store.EnqueueBotAPIUpdate(ctx, botAPIMessageRequest(1001, domain.BotAPIUpdateMessage, 2)); err != nil || !created {
|
|
t.Fatalf("message after explicit reset created=%v err=%v", created, err)
|
|
}
|
|
}
|
|
|
|
func TestBotAPIUpdateCursorClampDropAndTail(t *testing.T) {
|
|
ctx := context.Background()
|
|
store := NewBotAPIUpdateStore()
|
|
for id := 1; id <= 5; id++ {
|
|
if _, created, err := store.EnqueueBotAPIUpdate(ctx, botAPIMessageRequest(1001, domain.BotAPIUpdateMessage, id)); err != nil || !created {
|
|
t.Fatalf("enqueue %d: created=%v err=%v", id, created, err)
|
|
}
|
|
}
|
|
tail, err := store.ListTailBotAPIUpdates(ctx, 1001, 2, 100)
|
|
if err != nil || len(tail) != 2 || tail[0].MessageID != 4 || tail[1].MessageID != 5 {
|
|
t.Fatalf("tail = %#v err=%v", tail, err)
|
|
}
|
|
if err := store.ConfirmBotAPIUpdates(ctx, 1001, 1<<60); err != nil {
|
|
t.Fatalf("confirm huge offset: %v", err)
|
|
}
|
|
confirmed, found, err := store.ConfirmedBotAPIUpdateID(ctx, 1001)
|
|
if err != nil || !found || confirmed != 5 {
|
|
t.Fatalf("confirmed = %d found=%v err=%v, want 5", confirmed, found, err)
|
|
}
|
|
row, created, err := store.EnqueueBotAPIUpdate(ctx, botAPIMessageRequest(1001, domain.BotAPIUpdateMessage, 6))
|
|
if err != nil || !created {
|
|
t.Fatalf("enqueue after huge offset: row=%#v created=%v err=%v", row, created, err)
|
|
}
|
|
if err := store.ConfirmBotAPIUpdates(ctx, 1001, 1<<60); err != nil {
|
|
t.Fatalf("repeat foreign offset: %v", err)
|
|
}
|
|
if confirmed, _, _ := store.ConfirmedBotAPIUpdateID(ctx, 1001); confirmed != 5 {
|
|
t.Fatalf("repeat foreign offset advanced cursor to %d, want 5", confirmed)
|
|
}
|
|
pending, err := store.ListBotAPIUpdates(ctx, 1001, confirmed+1, 100)
|
|
if err != nil || len(pending) != 1 || pending[0].MessageID != 6 {
|
|
t.Fatalf("pending after huge offset = %#v err=%v", pending, err)
|
|
}
|
|
if err := store.DropPendingBotAPIUpdates(ctx, 1001); err != nil {
|
|
t.Fatalf("drop pending: %v", err)
|
|
}
|
|
count, err := store.PendingBotAPIUpdateCount(ctx, 1001)
|
|
if err != nil || count != 0 {
|
|
t.Fatalf("pending count = %d err=%v", count, err)
|
|
}
|
|
}
|
|
|
|
func TestBotAPIAllowedUpdatesOnlyAffectsFutureEnqueue(t *testing.T) {
|
|
ctx := context.Background()
|
|
store := NewBotAPIUpdateStore()
|
|
first, created, err := store.EnqueueBotAPIUpdate(ctx, botAPIMessageRequest(1001, domain.BotAPIUpdateMessage, 1))
|
|
if err != nil || !created {
|
|
t.Fatalf("enqueue pre-policy: %#v created=%v err=%v", first, created, err)
|
|
}
|
|
if err := store.SetBotAPIAllowedUpdates(ctx, 1001, []domain.BotAPIUpdateKind{domain.BotAPIUpdateEditedMessage}); err != nil {
|
|
t.Fatalf("set policy: %v", err)
|
|
}
|
|
if row, created, err := store.EnqueueBotAPIUpdate(ctx, botAPIMessageRequest(1001, domain.BotAPIUpdateMessage, 2)); err != nil || created || row.ID != 0 {
|
|
t.Fatalf("filtered message = %#v created=%v err=%v", row, created, err)
|
|
}
|
|
if _, created, err := store.EnqueueBotAPIUpdate(ctx, botAPIMessageRequest(1001, domain.BotAPIUpdateEditedMessage, 3)); err != nil || !created {
|
|
t.Fatalf("allowed edit created=%v err=%v", created, err)
|
|
}
|
|
rows, err := store.ListBotAPIUpdates(ctx, 1001, 1, 100)
|
|
if err != nil || len(rows) != 2 || rows[0].ID != first.ID || rows[1].Kind != domain.BotAPIUpdateEditedMessage {
|
|
t.Fatalf("rows = %#v err=%v", rows, err)
|
|
}
|
|
}
|
|
|
|
func TestBotAPIInlineCallbackRoundTrip(t *testing.T) {
|
|
ctx := context.Background()
|
|
store := NewBotAPIUpdateStore()
|
|
callback := &domain.BotCallbackQuery{
|
|
ID: 77, BotUserID: 1001, UserID: 2001, ChatInstance: 99, Data: []byte("tap"),
|
|
InlineMessage: &domain.BotInlineMessageID{DCID: 2, OwnerID: 2001, ID: 15, AccessHash: 1234},
|
|
}
|
|
row, created, err := store.EnqueueBotAPIUpdate(ctx, domain.EnqueueBotAPIUpdateRequest{
|
|
BotUserID: 1001, Kind: domain.BotAPIUpdateCallbackQuery, Date: int(time.Now().Unix()), Callback: callback,
|
|
})
|
|
if err != nil || !created || row.MessageID != 0 || row.Peer != (domain.Peer{}) || row.Callback == nil ||
|
|
row.Callback.InlineMessage == nil || *row.Callback.InlineMessage != *callback.InlineMessage {
|
|
t.Fatalf("inline callback row=%#v created=%v err=%v", row, created, err)
|
|
}
|
|
callback.Data[0] = 'X'
|
|
callback.InlineMessage.ID = 99
|
|
rows, err := store.ListBotAPIUpdates(ctx, 1001, 1, 100)
|
|
if err != nil || len(rows) != 1 || string(rows[0].Callback.Data) != "tap" || rows[0].Callback.InlineMessage.ID != 15 {
|
|
t.Fatalf("inline callback rows=%#v err=%v", rows, err)
|
|
}
|
|
}
|