package botlink import ( "context" "testing" flatbuffers "github.com/google/flatbuffers/go" "scrabble/pkg/fbs/scrabblefb" botlinkv1 "scrabble/pkg/proto/botlink/v1" telegramv1 "scrabble/pkg/proto/telegram/v1" ) // fakeSender records the delivery calls the executor makes. type fakeSender struct { notify []notifyCall text []textCall err error } type notifyCall struct { chatID int64 text, buttonText, startParam string } type textCall struct { chatID int64 text string } func (f *fakeSender) Notify(_ context.Context, chatID int64, text, buttonText, startParam string) error { f.notify = append(f.notify, notifyCall{chatID, text, buttonText, startParam}) return f.err } func (f *fakeSender) SendText(_ context.Context, chatID int64, text string) error { f.text = append(f.text, textCall{chatID, text}) return f.err } func yourTurnPayload(gameID string) []byte { b := flatbuffers.NewBuilder(0) gid := b.CreateString(gameID) scrabblefb.YourTurnEventStart(b) scrabblefb.YourTurnEventAddGameId(b, gid) b.Finish(scrabblefb.YourTurnEventEnd(b)) return b.FinishedBytes() } func notifyCmd(externalID, kind string, payload []byte, language string) *botlinkv1.Command { return &botlinkv1.Command{Payload: &botlinkv1.Command_Notify{Notify: &telegramv1.NotifyRequest{ ExternalId: externalID, Kind: kind, Payload: payload, Language: language, }}} } func TestExecutorNotifyDelivers(t *testing.T) { const gameID = "7c9e6679-7425-40de-944b-e07fc1f90ae7" sender := &fakeSender{} exec := NewExecutor(sender, 0, nil) delivered, err := exec.Handle(context.Background(), notifyCmd("12345", "your_turn", yourTurnPayload(gameID), "en")) if err != nil { t.Fatalf("handle: %v", err) } if !delivered { t.Fatal("expected delivered=true") } if len(sender.notify) != 1 { t.Fatalf("notify calls = %d, want 1", len(sender.notify)) } if got := sender.notify[0]; got.chatID != 12345 || got.startParam != "g"+gameID { t.Errorf("notify call = %+v, want chatID 12345 startParam g%s", got, gameID) } } func TestExecutorNotifySkipsUnrenderedKind(t *testing.T) { sender := &fakeSender{} exec := NewExecutor(sender, 0, nil) delivered, err := exec.Handle(context.Background(), notifyCmd("12345", "opponent_moved", nil, "en")) if err != nil { t.Fatalf("handle: %v", err) } if delivered { t.Error("expected delivered=false for an unrendered kind") } if len(sender.notify) != 0 { t.Errorf("sender called %d times, want 0", len(sender.notify)) } } func TestExecutorNotifyInvalidExternalID(t *testing.T) { exec := NewExecutor(&fakeSender{}, 0, nil) if _, err := exec.Handle(context.Background(), notifyCmd("not-a-number", "your_turn", yourTurnPayload("g"), "en")); err == nil { t.Error("expected an error for a non-numeric external_id") } } func TestExecutorSendToUser(t *testing.T) { sender := &fakeSender{} exec := NewExecutor(sender, 0, nil) cmd := &botlinkv1.Command{Payload: &botlinkv1.Command_SendToUser{SendToUser: &telegramv1.SendToUserRequest{ExternalId: "999", Text: "hi"}}} delivered, err := exec.Handle(context.Background(), cmd) if err != nil { t.Fatalf("handle: %v", err) } if !delivered || len(sender.text) != 1 || sender.text[0].chatID != 999 || sender.text[0].text != "hi" { t.Errorf("send to user = %v / calls %+v", delivered, sender.text) } } func TestExecutorSendToChannel(t *testing.T) { channelCmd := &botlinkv1.Command{Payload: &botlinkv1.Command_SendToChannel{SendToChannel: &telegramv1.SendToGameChannelRequest{Text: "news"}}} t.Run("unconfigured", func(t *testing.T) { exec := NewExecutor(&fakeSender{}, 0, nil) if _, err := exec.Handle(context.Background(), channelCmd); err == nil { t.Error("expected an error when no channel is configured") } }) t.Run("configured", func(t *testing.T) { sender := &fakeSender{} exec := NewExecutor(sender, 555, nil) delivered, err := exec.Handle(context.Background(), channelCmd) if err != nil { t.Fatalf("handle: %v", err) } if !delivered || len(sender.text) != 1 || sender.text[0].chatID != 555 { t.Errorf("send to channel: %+v", sender.text) } }) }