mirror of
https://github.com/tiennm99/openai-status-bot.git
synced 2026-07-14 07:05:20 +00:00
205 lines
6.0 KiB
Go
205 lines
6.0 KiB
Go
package bot
|
|
|
|
import (
|
|
"context"
|
|
"log/slog"
|
|
"strings"
|
|
"testing"
|
|
|
|
tgmodels "github.com/go-telegram/bot/models"
|
|
"github.com/tiennm99/openai-status-bot/internal/mongostore"
|
|
openai "github.com/tiennm99/openai-status-bot/internal/openai"
|
|
)
|
|
|
|
type fakeTelegramSender struct {
|
|
replies []sentReply
|
|
}
|
|
|
|
type sentReply struct {
|
|
chatID int64
|
|
threadID *int
|
|
text string
|
|
}
|
|
|
|
func (f *fakeTelegramSender) SendText(_ context.Context, chatID int64, threadID *int, text string) error {
|
|
f.replies = append(f.replies, sentReply{chatID: chatID, threadID: threadID, text: text})
|
|
return nil
|
|
}
|
|
|
|
type fakeBotStatusClient struct {
|
|
summary openai.Summary
|
|
}
|
|
|
|
func (f fakeBotStatusClient) FetchSummary(context.Context) (openai.Summary, error) {
|
|
return f.summary, nil
|
|
}
|
|
|
|
func (f fakeBotStatusClient) FetchIncidents(context.Context) (openai.IncidentsResponse, error) {
|
|
return openai.IncidentsResponse{}, nil
|
|
}
|
|
|
|
type fakeBotStore struct {
|
|
sub mongostore.Subscriber
|
|
subscribed bool
|
|
types []string
|
|
components []string
|
|
savedOffsets []int64
|
|
}
|
|
|
|
func (f *fakeBotStore) AddSubscriber(_ context.Context, sub mongostore.Subscriber) error {
|
|
f.sub = sub
|
|
f.subscribed = true
|
|
f.types = mongostore.DefaultSubscriptionTypes()
|
|
return nil
|
|
}
|
|
|
|
func (f *fakeBotStore) GetSubscriber(context.Context, mongostore.Subscriber) (mongostore.Subscriber, bool, error) {
|
|
if !f.subscribed {
|
|
return mongostore.Subscriber{}, false, nil
|
|
}
|
|
sub := f.sub
|
|
sub.Types = append([]string{}, f.types...)
|
|
sub.Components = append([]string{}, f.components...)
|
|
return sub, true, nil
|
|
}
|
|
|
|
func (f *fakeBotStore) RemoveSubscriber(context.Context, mongostore.Subscriber) error {
|
|
f.subscribed = false
|
|
return nil
|
|
}
|
|
|
|
func (f *fakeBotStore) SaveTelegramOffset(_ context.Context, offset int64) error {
|
|
f.savedOffsets = append(f.savedOffsets, offset)
|
|
return nil
|
|
}
|
|
|
|
func (f *fakeBotStore) UpdateSubscriberTypes(_ context.Context, _ mongostore.Subscriber, types []string) (bool, error) {
|
|
if !f.subscribed {
|
|
return false, nil
|
|
}
|
|
f.types = append([]string{}, types...)
|
|
return true, nil
|
|
}
|
|
|
|
func (f *fakeBotStore) UpdateSubscriberSettings(_ context.Context, _ mongostore.Subscriber, types, components []string) (bool, error) {
|
|
if !f.subscribed {
|
|
return false, nil
|
|
}
|
|
f.types = append([]string{}, types...)
|
|
f.components = append([]string{}, components...)
|
|
return true, nil
|
|
}
|
|
|
|
func TestSubscribeComponentStoresComponentID(t *testing.T) {
|
|
bot, store, tg := newTestBot([]openai.Component{{ID: "c-api", Name: "API", Status: "operational"}})
|
|
store.subscribed = true
|
|
store.sub = mongostore.NewSubscriber(123, nil)
|
|
store.types = []string{mongostore.SubscriptionTypeIncident}
|
|
|
|
bot.handleMessage(context.Background(), messageText("/subscribe component api"))
|
|
|
|
if len(store.components) != 1 || store.components[0] != "c-api" {
|
|
t.Fatalf("components = %v, want [c-api]", store.components)
|
|
}
|
|
if !containsComponent(store.types, mongostore.SubscriptionTypeComponent) {
|
|
t.Fatalf("types = %v, want component enabled", store.types)
|
|
}
|
|
if len(tg.replies) != 1 || !strings.Contains(tg.replies[0].text, "Subscribed to component") {
|
|
t.Fatalf("reply = %v", tg.replies)
|
|
}
|
|
}
|
|
|
|
func TestSubscribeComponentAllEnablesComponentType(t *testing.T) {
|
|
bot, store, _ := newTestBot(nil)
|
|
store.subscribed = true
|
|
store.sub = mongostore.NewSubscriber(123, nil)
|
|
store.types = []string{mongostore.SubscriptionTypeIncident}
|
|
store.components = []string{"c-api"}
|
|
|
|
bot.handleMessage(context.Background(), messageText("/subscribe component all"))
|
|
|
|
if len(store.components) != 0 {
|
|
t.Fatalf("components = %v, want cleared", store.components)
|
|
}
|
|
if !containsComponent(store.types, mongostore.SubscriptionTypeComponent) {
|
|
t.Fatalf("types = %v, want component enabled", store.types)
|
|
}
|
|
}
|
|
|
|
func TestStatusAmbiguousComponentNameRequiresID(t *testing.T) {
|
|
bot, _, tg := newTestBot([]openai.Component{
|
|
{ID: "login-a", Name: "Login", Status: "operational"},
|
|
{ID: "login-b", Name: "Login", Status: "operational"},
|
|
})
|
|
|
|
bot.handleMessage(context.Background(), messageText("/status Login"))
|
|
|
|
if len(tg.replies) != 1 || !strings.Contains(tg.replies[0].text, "ambiguous") || !strings.Contains(tg.replies[0].text, "login-a") {
|
|
t.Fatalf("reply = %v", tg.replies)
|
|
}
|
|
}
|
|
|
|
func TestCommandForOtherBotIsIgnored(t *testing.T) {
|
|
bot, _, tg := newTestBot(nil)
|
|
|
|
bot.handleMessage(context.Background(), messageText("/start@OtherBot"))
|
|
|
|
if len(tg.replies) != 0 {
|
|
t.Fatalf("replies = %v, want none", tg.replies)
|
|
}
|
|
}
|
|
|
|
func TestHandleUpdateRepliesToThreadAndSavesNextOffset(t *testing.T) {
|
|
bot, store, tg := newTestBot(nil)
|
|
threadID := 42
|
|
|
|
bot.HandleUpdate(context.Background(), nil, &tgmodels.Update{
|
|
ID: 77,
|
|
Message: &tgmodels.Message{
|
|
Chat: tgmodels.Chat{ID: 123},
|
|
MessageThreadID: threadID,
|
|
Text: "/start",
|
|
},
|
|
})
|
|
|
|
if len(store.savedOffsets) != 1 || store.savedOffsets[0] != 78 {
|
|
t.Fatalf("savedOffsets = %v, want [78]", store.savedOffsets)
|
|
}
|
|
if len(tg.replies) != 1 {
|
|
t.Fatalf("replies = %v, want one reply", tg.replies)
|
|
}
|
|
if tg.replies[0].chatID != 123 {
|
|
t.Fatalf("chatID = %d, want 123", tg.replies[0].chatID)
|
|
}
|
|
if tg.replies[0].threadID == nil || *tg.replies[0].threadID != threadID {
|
|
t.Fatalf("threadID = %v, want %d", tg.replies[0].threadID, threadID)
|
|
}
|
|
}
|
|
|
|
func TestHandleUpdateSavesOffsetForNonCommandMessage(t *testing.T) {
|
|
bot, store, tg := newTestBot(nil)
|
|
|
|
bot.HandleUpdate(context.Background(), nil, &tgmodels.Update{
|
|
ID: 80,
|
|
Message: &tgmodels.Message{Chat: tgmodels.Chat{ID: 123}, Text: "hello"},
|
|
})
|
|
|
|
if len(tg.replies) != 0 {
|
|
t.Fatalf("replies = %v, want none", tg.replies)
|
|
}
|
|
if len(store.savedOffsets) != 1 || store.savedOffsets[0] != 81 {
|
|
t.Fatalf("savedOffsets = %v, want [81]", store.savedOffsets)
|
|
}
|
|
}
|
|
|
|
func newTestBot(components []openai.Component) (*App, *fakeBotStore, *fakeTelegramSender) {
|
|
tg := &fakeTelegramSender{}
|
|
store := &fakeBotStore{}
|
|
statusClient := fakeBotStatusClient{summary: openai.Summary{Components: components}}
|
|
return New(tg, statusClient, store, slog.Default(), "OpenAIStatusBot"), store, tg
|
|
}
|
|
|
|
func messageText(text string) MessageContext {
|
|
return MessageContext{Text: text, ChatID: 123}
|
|
}
|