images map[string][]byte
}
-// Add makes update available to getUpdates.
-func (f *TelegramFake) Add(update TelegramUpdate) {
- f.mutex.Lock()
-
- f.updates = append(f.updates, update)
- f.mutex.Unlock()
+// newTelegramFake starts a fake Bot API server that stops at the end of the
+// test.
+func newTelegramFake(t *testing.T) *TelegramFake {
+ t.Helper()
- select {
- case f.added <- struct{}{}:
- default:
+ f := &TelegramFake{
+ added: make(chan struct{}, 1),
+ stopped: make(chan struct{}),
}
-}
-// Calls returns the calls so far.
-func (f *TelegramFake) Calls() []TelegramFakeCall {
- f.mutex.Lock()
- defer f.mutex.Unlock()
-
- 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.
-func (f *TelegramFake) Sent() []string {
- var texts []string
-
- for _, call := range f.Calls() {
- switch {
- case !call.ok:
- case call.method == "sendMessage":
- texts = append(texts, call.params["text"].(string))
- case call.method == "sendRichMessage":
- texts = append(texts, call.params["rich_message"].(map[string]any)["markdown"].(string))
- }
- }
+ f.Server = httptest.NewServer(http.HandlerFunc(f.serve))
+ t.Cleanup(f.Close)
+ t.Cleanup(func() {
+ close(f.stopped)
+ })
- return texts
+ return f
}
-func (f *TelegramFake) Image(id string, data []byte) {
- f.mutex.Lock()
- defer f.mutex.Unlock()
+// newTelegramLocalFake returns the same fake API without network goroutines.
+// Its RoundTrip handles requests directly for tests with fake time.
+func newTelegramLocalFake(t *testing.T) *TelegramFake {
+ t.Helper()
- if f.images == nil {
- f.images = make(map[string][]byte)
+ f := &TelegramFake{
+ Server: &httptest.Server{URL: "https://example.com"},
+ added: make(chan struct{}, 1),
+ stopped: make(chan struct{}),
}
- f.images[id] = data
-}
-
-// RoundTrip handles a request in memory, so synctest can control its timers.
-func (f *TelegramFake) RoundTrip(request *http.Request) (*http.Response, error) {
- response := httptest.NewRecorder()
- f.serve(response, request)
-
- ctx := request.Context()
- if ctx.Err() != nil {
- return nil, ctx.Err()
- }
+ t.Cleanup(func() {
+ close(f.stopped)
+ })
- return response.Result(), nil
+ return f
}
func (f *TelegramFake) serve(w http.ResponseWriter, r *http.Request) {
return
}
- _, _ = w.Write(data)
+ // The client can cancel a media request before this reply is
+ // written.
+ w.Write(data) // nolint: errcheck
return
}
wait = 1
}
- _, _ = fmt.Fprintf(w, `{"ok":false,"error_code":%d,"description":%q,"parameters":{"retry_after":%d}}`, status, description, wait)
+ // A test can cancel the request after the handler selects its
+ // reply.
+ fmt.Fprintf(w, `{"ok":false,"error_code":%d,"description":%q,"parameters":{"retry_after":%d}}`, status, description, wait) // nolint: errcheck
return
}
f.record(call)
if method == "getFile" {
- _ = json.NewEncoder(w).Encode(map[string]any{
+ // A cancelled client does not need a response body.
+ json.NewEncoder(w).Encode(map[string]any{ // nolint: errcheck
"ok": true,
"result": map[string]any{"file_path": params["file_id"]},
})
}
if method != "getUpdates" {
- _, _ = io.WriteString(w, `{"ok":true,"result":true}`)
+ // A cancelled client does not need a response body.
+ io.WriteString(w, `{"ok":true,"result":true}`) // nolint: errcheck
+
return
}
updates = f.from(offset)
}
- _ = json.NewEncoder(w).Encode(map[string]any{
+ // A cancelled client does not need a response body.
+ json.NewEncoder(w).Encode(map[string]any{ // nolint: errcheck
"ok": true,
"result": updates,
})
return updates
}
-// newTelegramFake starts a fake Bot API server that stops at the end of the
-// test.
-func newTelegramFake(t *testing.T) *TelegramFake {
- t.Helper()
+// Add makes update available to getUpdates.
+func (f *TelegramFake) Add(update TelegramUpdate) {
+ f.mutex.Lock()
- f := &TelegramFake{
- added: make(chan struct{}, 1),
- stopped: make(chan struct{}),
+ f.updates = append(f.updates, update)
+ f.mutex.Unlock()
+
+ select {
+ case f.added <- struct{}{}:
+ default:
}
+}
- f.Server = httptest.NewServer(http.HandlerFunc(f.serve))
- t.Cleanup(f.Close)
- t.Cleanup(func() {
- close(f.stopped)
- })
+// Sent returns the texts of the sendMessage calls and the Markdown of the
+// sendRichMessage calls that succeeded, in order.
+func (f *TelegramFake) Sent() []string {
+ var texts []string
- return f
+ for _, call := range f.Calls() {
+ switch {
+ case !call.ok:
+ case call.method == "sendMessage":
+ texts = append(texts, call.params["text"].(string))
+ case call.method == "sendRichMessage":
+ texts = append(texts, call.params["rich_message"].(map[string]any)["markdown"].(string))
+ }
+ }
+
+ return texts
}
-// newTelegramLocalFake returns the same fake API without network goroutines.
-// Its RoundTrip handles requests directly for tests with fake time.
-func newTelegramLocalFake(t *testing.T) *TelegramFake {
- t.Helper()
+// Calls returns the calls so far.
+func (f *TelegramFake) Calls() []TelegramFakeCall {
+ f.mutex.Lock()
+ defer f.mutex.Unlock()
- f := &TelegramFake{
- Server: &httptest.Server{URL: "https://example.com"},
- added: make(chan struct{}, 1),
- stopped: make(chan struct{}),
+ return append([]TelegramFakeCall(nil), f.calls...)
+}
+
+func (f *TelegramFake) Image(id string, data []byte) {
+ f.mutex.Lock()
+ defer f.mutex.Unlock()
+
+ if f.images == nil {
+ f.images = make(map[string][]byte)
}
- t.Cleanup(func() {
- close(f.stopped)
- })
- return f
+ f.images[id] = data
+}
+
+// RoundTrip handles a request in memory, so synctest can control its timers.
+func (f *TelegramFake) RoundTrip(request *http.Request) (*http.Response, error) {
+ response := httptest.NewRecorder()
+ f.serve(response, request)
+
+ ctx := request.Context()
+ if ctx.Err() != nil {
+ return nil, ctx.Err()
+ }
+
+ return response.Result(), nil
}
// telegramOwnerMessage returns a text message of the owner in the private chat.