FILE / ScuroNeko/Laniakea

tgapi/api_test.go

Исходный файл и его история в репозитории.
FILE dev
Files
ScuroNeko 29b208eeec
Golang lint / lint (push) Successful in 11m32s
(new): v1.2 release
2026-08-19 14:58:25 +03:00

131 lines
3.4 KiB
Go

package tgapi
import (
"errors"
"io"
"net/http"
"strings"
"testing"
)
type roundTripFunc func(*http.Request) (*http.Response, error)
func (fn roundTripFunc) RoundTrip(req *http.Request) (*http.Response, error) {
return fn(req)
}
type closingTransport struct {
roundTripFunc
closed bool
}
func (t *closingTransport) CloseIdleConnections() {
t.closed = true
}
func TestAPILeavesAcceptEncodingToHTTPTransport(t *testing.T) {
var gotPath string
var gotAcceptEncoding string
client := &http.Client{
Transport: roundTripFunc(func(req *http.Request) (*http.Response, error) {
gotPath = req.URL.Path
gotAcceptEncoding = req.Header.Get("Accept-Encoding")
return &http.Response{
StatusCode: http.StatusOK,
Header: http.Header{"Content-Type": []string{"application/json"}},
Body: io.NopCloser(strings.NewReader(`{"ok":true,"result":{"id":1,"is_bot":true,"first_name":"Test"}}`)),
}, nil
}),
}
api := NewAPI(
NewAPIOpts("token").
SetAPIURL("https://example.test").
SetHTTPClient(client),
)
defer func() {
if err := api.Close(); err != nil {
t.Fatalf("Close returned error: %v", err)
}
}()
user, err := api.GetMe()
if err != nil {
t.Fatalf("GetMe returned error: %v", err)
}
if user.FirstName != "Test" {
t.Fatalf("unexpected first name: %q", user.FirstName)
}
if gotPath != "/bottoken/getMe" {
t.Fatalf("unexpected request path: %s", gotPath)
}
if gotAcceptEncoding != "" {
t.Fatalf("expected empty Accept-Encoding header, got %q", gotAcceptEncoding)
}
}
func TestAPICloseClosesIdleConnections(t *testing.T) {
transport := &closingTransport{
roundTripFunc: func(req *http.Request) (*http.Response, error) {
return &http.Response{
StatusCode: http.StatusOK,
Header: http.Header{"Content-Type": []string{"application/json"}},
Body: io.NopCloser(strings.NewReader(`{"ok":true,"result":{"id":1,"is_bot":true,"first_name":"Test"}}`)),
}, nil
},
}
api := NewAPI(
NewAPIOpts("token").
SetAPIURL("https://example.test").
SetHTTPClient(&http.Client{Transport: transport}),
)
if err := api.Close(); err != nil {
t.Fatalf("Close returned error: %v", err)
}
if !transport.closed {
t.Fatal("expected Close to close idle HTTP connections")
}
}
func TestAPIStopsAfterConfiguredRetryLimit(t *testing.T) {
calls := 0
client := &http.Client{Transport: roundTripFunc(func(_ *http.Request) (*http.Response, error) {
calls++
return &http.Response{
StatusCode: http.StatusOK,
Body: io.NopCloser(strings.NewReader(
`{"ok":false,"error_code":429,"description":"retry","parameters":{"retry_after":0}}`,
)),
}, nil
})}
api := NewAPI(NewAPIOpts("token").
SetAPIURL("https://example.test").
SetHTTPClient(client).
SetMaxRetries(2))
defer func() { _ = api.Close() }()
_, err := api.GetMe()
if !errors.Is(err, ErrRetryLimit) {
t.Fatalf("expected ErrRetryLimit, got %v", err)
}
var responseErr *ResponseError
if !errors.As(err, &responseErr) || responseErr.Code != http.StatusTooManyRequests {
t.Fatalf("expected wrapped 429 ResponseError, got %v", err)
}
if calls != 3 {
t.Fatalf("request count = %d, want 3", calls)
}
}
func TestReadBodyRejectsOversizedResponse(t *testing.T) {
body := io.NopCloser(io.LimitReader(strings.NewReader(strings.Repeat("x", maximumResponseSize+1)), maximumResponseSize+1))
_, err := readBody(body)
if !errors.Is(err, ErrResponseTooLarge) {
t.Fatalf("expected ErrResponseTooLarge, got %v", err)
}
}