]> git.giacomolli.uk - onechat/blobdiff - telegram_api_test.go
Name and order the Telegram bot code
[onechat] / telegram_api_test.go
similarity index 68%
rename from botapi_test.go
rename to telegram_api_test.go
index fb57b45b468116c0687419123eedd7421c5fd738..bbfd93e8614d742ec15c057c3fbab2d1b77d5134 100644 (file)
@@ -16,22 +16,22 @@ import (
 )
 
 const (
 )
 
 const (
-       // testBotToken is the bot token of the tests. It has the form of a real
-       // token.
-       testBotToken = "123456:TEST-secret_token"
+       // telegramTestToken is the bot token of the tests. It has the form of a
+       // real token.
+       telegramTestToken = "123456:TEST-secret_token"
 
 
-       // testOwner is the user ID of the owner of the test bot.
-       testOwner = 4242
+       // telegramTestOwner is the user ID of the owner of the test bot.
+       telegramTestOwner = 4242
 )
 
 func TestGetUpdatesAsksForMessagesFromTheOffset(t *testing.T) {
 )
 
 func TestGetUpdatesAsksForMessagesFromTheOffset(t *testing.T) {
-       server := newFakeBot(t)
-       server.Add(botUpdate{
+       server := newTelegramFake(t)
+       server.Add(TelegramUpdate{
                UpdateID: 7,
                UpdateID: 7,
-               Message:  ownerMessage("hello"),
+               Message:  telegramOwnerMessage("hello"),
        })
 
        })
 
-       updates, err := newBotAPI(server.URL, testBotToken).GetUpdates(t.Context(), 7)
+       updates, err := newTelegramAPI(server.URL, telegramTestToken).GetUpdates(t.Context(), 7)
        require.NoError(t, err)
        require.Len(t, updates, 1)
        require.Equal(t, int64(7), updates[0].UpdateID)
        require.NoError(t, err)
        require.Len(t, updates, 1)
        require.Equal(t, int64(7), updates[0].UpdateID)
@@ -41,25 +41,25 @@ func TestGetUpdatesAsksForMessagesFromTheOffset(t *testing.T) {
        require.Equal(t, "getUpdates", call.method)
        require.Equal(t, map[string]any{
                "offset":          float64(7),
        require.Equal(t, "getUpdates", call.method)
        require.Equal(t, map[string]any{
                "offset":          float64(7),
-               "timeout":         float64(pollSeconds),
+               "timeout":         float64(telegramPollSeconds),
                "allowed_updates": []any{"message"},
        }, call.params)
 }
 
 func TestSendMessageSendsPlainText(t *testing.T) {
                "allowed_updates": []any{"message"},
        }, call.params)
 }
 
 func TestSendMessageSendsPlainText(t *testing.T) {
-       server := newFakeBot(t)
-       err := newBotAPI(server.URL, testBotToken).SendMessage(t.Context(), testOwner, "*not bold*", nil)
+       server := newTelegramFake(t)
+       err := newTelegramAPI(server.URL, telegramTestToken).SendMessage(t.Context(), telegramTestOwner, "*not bold*", nil)
        require.NoError(t, err)
 
        require.Equal(t, map[string]any{
        require.NoError(t, err)
 
        require.Equal(t, map[string]any{
-               "chat_id": float64(testOwner),
+               "chat_id": float64(telegramTestOwner),
                "text":    "*not bold*",
        }, server.Calls()[0].params)
 }
 
 func TestSendMessageSendsTheEntities(t *testing.T) {
                "text":    "*not bold*",
        }, server.Calls()[0].params)
 }
 
 func TestSendMessageSendsTheEntities(t *testing.T) {
-       server := newFakeBot(t)
-       err := newBotAPI(server.URL, testBotToken).SendMessage(t.Context(), testOwner, "a link", []botEntity{
+       server := newTelegramFake(t)
+       err := newTelegramAPI(server.URL, telegramTestToken).SendMessage(t.Context(), telegramTestOwner, "a link", []TelegramEntity{
                {
                        Type:   "text_link",
                        Offset: 2,
                {
                        Type:   "text_link",
                        Offset: 2,
@@ -80,15 +80,15 @@ func TestSendMessageSendsTheEntities(t *testing.T) {
 }
 
 func TestSendRichMessageSendsTheMarkdownUnchanged(t *testing.T) {
 }
 
 func TestSendRichMessageSendsTheMarkdownUnchanged(t *testing.T) {
-       server := newFakeBot(t)
+       server := newTelegramFake(t)
        markdown := "| a | b |\n|---|---|\n| **1** | `2` |"
        markdown := "| a | b |\n|---|---|\n| **1** | `2` |"
-       err := newBotAPI(server.URL, testBotToken).SendRichMessage(t.Context(), testOwner, markdown)
+       err := newTelegramAPI(server.URL, telegramTestToken).SendRichMessage(t.Context(), telegramTestOwner, markdown)
        require.NoError(t, err)
 
        call := server.Calls()[0]
        require.Equal(t, "sendRichMessage", call.method)
        require.Equal(t, map[string]any{
        require.NoError(t, err)
 
        call := server.Calls()[0]
        require.Equal(t, "sendRichMessage", call.method)
        require.Equal(t, map[string]any{
-               "chat_id": float64(testOwner),
+               "chat_id": float64(telegramTestOwner),
                "rich_message": map[string]any{
                        "markdown": markdown,
                },
                "rich_message": map[string]any{
                        "markdown": markdown,
                },
@@ -98,39 +98,39 @@ func TestSendRichMessageSendsTheMarkdownUnchanged(t *testing.T) {
 func TestSendCallsTimeOutOnAStalledConnection(t *testing.T) {
        testCases := []struct {
                method string
 func TestSendCallsTimeOutOnAStalledConnection(t *testing.T) {
        testCases := []struct {
                method string
-               send   func(ctx context.Context, api *botAPI) error
+               send   func(ctx context.Context, api *TelegramAPI) error
        }{
                {
                        method: "sendMessage",
        }{
                {
                        method: "sendMessage",
-                       send: func(ctx context.Context, api *botAPI) error {
-                               return api.SendMessage(ctx, testOwner, "hi", nil)
+                       send: func(ctx context.Context, api *TelegramAPI) error {
+                               return api.SendMessage(ctx, telegramTestOwner, "hi", nil)
                        },
                },
                {
                        method: "sendRichMessage",
                        },
                },
                {
                        method: "sendRichMessage",
-                       send: func(ctx context.Context, api *botAPI) error {
-                               return api.SendRichMessage(ctx, testOwner, "hi")
+                       send: func(ctx context.Context, api *TelegramAPI) error {
+                               return api.SendRichMessage(ctx, telegramTestOwner, "hi")
                        },
                },
        }
 
        for _, tc := range testCases {
                t.Run(tc.method, func(t *testing.T) {
                        },
                },
        }
 
        for _, tc := range testCases {
                t.Run(tc.method, func(t *testing.T) {
-                       server := newFakeBot(t)
-                       server.stall = func(call fakeBotCall) bool {
+                       server := newTelegramFake(t)
+                       server.stall = func(call TelegramFakeCall) bool {
                                return call.method == tc.method
                        }
 
                                return call.method == tc.method
                        }
 
-                       api := newBotAPI(server.URL, testBotToken)
+                       api := newTelegramAPI(server.URL, telegramTestToken)
                        api.sendTimeout = 50 * time.Millisecond
                        start := time.Now()
                        err := tc.send(t.Context(), api)
                        api.sendTimeout = 50 * time.Millisecond
                        start := time.Now()
                        err := tc.send(t.Context(), api)
-                       require.ErrorIs(t, err, errBotNetwork)
+                       require.ErrorIs(t, err, errTelegramNetwork)
                        require.Less(t, time.Since(start), 5*time.Second)
                        require.Less(t, time.Since(start), 5*time.Second)
-                       require.NotContains(t, err.Error(), testBotToken)
+                       require.NotContains(t, err.Error(), telegramTestToken)
                        require.NotContains(t, err.Error(), server.URL)
 
                        require.NotContains(t, err.Error(), server.URL)
 
-                       retry, _ := retryable(err)
+                       retry, _ := telegramRetryable(err)
                        require.True(t, retry)
 
                        api.sendTimeout = time.Hour
                        require.True(t, retry)
 
                        api.sendTimeout = time.Hour
@@ -187,7 +187,7 @@ func TestBotErrorsDoNotHoldTheToken(t *testing.T) {
                        name: "token echoed in a description is hidden",
                        reply: func(w http.ResponseWriter) {
                                w.WriteHeader(http.StatusUnauthorized)
                        name: "token echoed in a description is hidden",
                        reply: func(w http.ResponseWriter) {
                                w.WriteHeader(http.StatusUnauthorized)
-                               _, _ = io.WriteString(w, `{"ok":false,"error_code":401,"description":"Unauthorized: bot`+testBotToken+`"}`)
+                               _, _ = io.WriteString(w, `{"ok":false,"error_code":401,"description":"Unauthorized: bot`+telegramTestToken+`"}`)
                        },
                        retry:     false,
                        errorText: "Unauthorized: botTOKEN",
                        },
                        retry:     false,
                        errorText: "Unauthorized: botTOKEN",
@@ -238,72 +238,54 @@ func TestBotErrorsDoNotHoldTheToken(t *testing.T) {
                        }))
                        t.Cleanup(server.Close)
 
                        }))
                        t.Cleanup(server.Close)
 
-                       err := newBotAPI(server.URL, testBotToken).SendMessage(t.Context(), testOwner, "hi", nil)
+                       err := newTelegramAPI(server.URL, telegramTestToken).SendMessage(t.Context(), telegramTestOwner, "hi", nil)
                        require.ErrorContains(t, err, tc.errorText)
                        require.ErrorContains(t, err, tc.errorText)
-                       require.NotContains(t, err.Error(), testBotToken)
+                       require.NotContains(t, err.Error(), telegramTestToken)
                        require.NotContains(t, err.Error(), server.URL)
 
                        require.NotContains(t, err.Error(), server.URL)
 
-                       retry, wait := retryable(err)
+                       retry, wait := telegramRetryable(err)
                        require.Equal(t, tc.retry, retry)
                        require.Equal(t, tc.wait, wait)
                        require.Equal(t, tc.retry, retry)
                        require.Equal(t, tc.wait, wait)
-                       require.Equal(t, tc.rejected, rejected(err))
+                       require.Equal(t, tc.rejected, telegramRejected(err))
                })
        }
 
        server := httptest.NewServer(http.NotFoundHandler())
        server.Close()
 
                })
        }
 
        server := httptest.NewServer(http.NotFoundHandler())
        server.Close()
 
-       _, err := newBotAPI(server.URL, testBotToken).GetUpdates(t.Context(), 0)
-       require.ErrorIs(t, err, errBotNetwork)
-       require.NotContains(t, err.Error(), testBotToken)
+       _, err := newTelegramAPI(server.URL, telegramTestToken).GetUpdates(t.Context(), 0)
+       require.ErrorIs(t, err, errTelegramNetwork)
+       require.NotContains(t, err.Error(), telegramTestToken)
 }
 
 }
 
-// fakeBot is a fake Bot API server for testBotToken. getUpdates returns the
-// added updates from the offset on, or waits a short time when there are none.
-// The other methods succeed, unless fail gives an error answer for a call. An
-// answer with HTTP 429 asks for a wait of one second. When stall is true for a
-// call, the call gets no answer until the client gives it up or the test ends.
-// Fail and stall run with the mutex held.
-type fakeBot struct {
-       *httptest.Server
-
-       mutex   sync.Mutex
-       updates []botUpdate
-       calls   []fakeBotCall
-       fail    func(call fakeBotCall) (int, string)
-       stall   func(call fakeBotCall) bool
-       added   chan struct{}
-       stopped chan struct{}
-}
-
-// fakeBotCall is one call of the fake Bot API. OK tells if the call got a
+// TelegramFakeCall is one call of the fake Bot API. OK tells if the call got a
 // success answer.
 // success answer.
-type fakeBotCall struct {
+type TelegramFakeCall struct {
        method string
        params map[string]any
        ok     bool
 }
 
        method string
        params map[string]any
        ok     bool
 }
 
-// newFakeBot starts a fake Bot API server that stops at the end of the test.
-func newFakeBot(t *testing.T) *fakeBot {
-       t.Helper()
-
-       f := &fakeBot{
-               added:   make(chan struct{}, 1),
-               stopped: make(chan struct{}),
-       }
-
-       f.Server = httptest.NewServer(http.HandlerFunc(f.serve))
-       t.Cleanup(f.Close)
-       t.Cleanup(func() {
-               close(f.stopped)
-       })
+// TelegramFake is a fake Bot API server for telegramTestToken. getUpdates
+// returns the added updates from the offset on, or waits a short time when
+// there are none. The other methods succeed, unless fail gives an error answer
+// for a call. An answer with HTTP 429 asks for a wait of one second. When stall
+// is true for a call, the call gets no answer until the client gives it up or
+// the test ends. Fail and stall run with the mutex held.
+type TelegramFake struct {
+       *httptest.Server
 
 
-       return f
+       mutex   sync.Mutex
+       updates []TelegramUpdate
+       calls   []TelegramFakeCall
+       fail    func(call TelegramFakeCall) (int, string)
+       stall   func(call TelegramFakeCall) bool
+       added   chan struct{}
+       stopped chan struct{}
 }
 
 // Add makes update available to getUpdates.
 }
 
 // Add makes update available to getUpdates.
-func (f *fakeBot) Add(update botUpdate) {
+func (f *TelegramFake) Add(update TelegramUpdate) {
        f.mutex.Lock()
        f.updates = append(f.updates, update)
        f.mutex.Unlock()
        f.mutex.Lock()
        f.updates = append(f.updates, update)
        f.mutex.Unlock()
@@ -315,16 +297,16 @@ func (f *fakeBot) Add(update botUpdate) {
 }
 
 // Calls returns the calls so far.
 }
 
 // Calls returns the calls so far.
-func (f *fakeBot) Calls() []fakeBotCall {
+func (f *TelegramFake) Calls() []TelegramFakeCall {
        f.mutex.Lock()
        defer f.mutex.Unlock()
 
        f.mutex.Lock()
        defer f.mutex.Unlock()
 
-       return append([]fakeBotCall(nil), f.calls...)
+       return append([]TelegramFakeCall(nil), f.calls...)
 }
 
 // Sent returns the texts of the sendMessage calls and the Markdown of the
 // sendRichMessage calls that succeeded, in order.
 }
 
 // Sent returns the texts of the sendMessage calls and the Markdown of the
 // sendRichMessage calls that succeeded, in order.
-func (f *fakeBot) Sent() []string {
+func (f *TelegramFake) Sent() []string {
        var texts []string
        for _, call := range f.Calls() {
                switch {
        var texts []string
        for _, call := range f.Calls() {
                switch {
@@ -339,8 +321,8 @@ func (f *fakeBot) Sent() []string {
        return texts
 }
 
        return texts
 }
 
-func (f *fakeBot) serve(w http.ResponseWriter, r *http.Request) {
-       method, found := strings.CutPrefix(r.URL.Path, "/bot"+testBotToken+"/")
+func (f *TelegramFake) serve(w http.ResponseWriter, r *http.Request) {
+       method, found := strings.CutPrefix(r.URL.Path, "/bot"+telegramTestToken+"/")
        if !found {
                http.Error(w, `{"ok":false,"error_code":404,"description":"Not Found"}`, http.StatusNotFound)
                return
        if !found {
                http.Error(w, `{"ok":false,"error_code":404,"description":"Not Found"}`, http.StatusNotFound)
                return
@@ -353,7 +335,7 @@ func (f *fakeBot) serve(w http.ResponseWriter, r *http.Request) {
                return
        }
 
                return
        }
 
-       call := fakeBotCall{
+       call := TelegramFakeCall{
                method: method,
                params: params,
        }
                method: method,
                params: params,
        }
@@ -416,7 +398,7 @@ func (f *fakeBot) serve(w http.ResponseWriter, r *http.Request) {
 }
 
 // record keeps call.
 }
 
 // record keeps call.
-func (f *fakeBot) record(call fakeBotCall) {
+func (f *TelegramFake) record(call TelegramFakeCall) {
        f.mutex.Lock()
        defer f.mutex.Unlock()
 
        f.mutex.Lock()
        defer f.mutex.Unlock()
 
@@ -425,11 +407,11 @@ func (f *fakeBot) record(call fakeBotCall) {
 
 // from returns the updates from offset on, and forgets the ones before it, as
 // Telegram does.
 
 // from returns the updates from offset on, and forgets the ones before it, as
 // Telegram does.
-func (f *fakeBot) from(offset int64) []botUpdate {
+func (f *TelegramFake) from(offset int64) []TelegramUpdate {
        f.mutex.Lock()
        defer f.mutex.Unlock()
 
        f.mutex.Lock()
        defer f.mutex.Unlock()
 
-       var updates []botUpdate
+       var updates []TelegramUpdate
        kept := f.updates[:0]
        for _, update := range f.updates {
                if update.UpdateID >= offset {
        kept := f.updates[:0]
        for _, update := range f.updates {
                if update.UpdateID >= offset {
@@ -443,15 +425,34 @@ func (f *fakeBot) from(offset int64) []botUpdate {
        return updates
 }
 
        return updates
 }
 
-// ownerMessage returns a text message of the owner in the private chat.
-func ownerMessage(text string) *botMessage {
-       return &botMessage{
-               Chat: botChat{
-                       ID:   testOwner,
+// newTelegramFake starts a fake Bot API server that stops at the end of the
+// test.
+func newTelegramFake(t *testing.T) *TelegramFake {
+       t.Helper()
+
+       f := &TelegramFake{
+               added:   make(chan struct{}, 1),
+               stopped: make(chan struct{}),
+       }
+
+       f.Server = httptest.NewServer(http.HandlerFunc(f.serve))
+       t.Cleanup(f.Close)
+       t.Cleanup(func() {
+               close(f.stopped)
+       })
+
+       return f
+}
+
+// telegramOwnerMessage returns a text message of the owner in the private chat.
+func telegramOwnerMessage(text string) *TelegramMessage {
+       return &TelegramMessage{
+               Chat: TelegramChat{
+                       ID:   telegramTestOwner,
                        Type: "private",
                },
                        Type: "private",
                },
-               From: &botUser{
-                       ID: testOwner,
+               From: &TelegramUser{
+                       ID: telegramTestOwner,
                },
                Text: text,
        }
                },
                Text: text,
        }