164 lines
4.4 KiB
Go
164 lines
4.4 KiB
Go
package coinglass
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"errors"
|
|
"io"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"net/url"
|
|
"strconv"
|
|
"sync/atomic"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
type netHTTPDoer struct {
|
|
client *http.Client
|
|
}
|
|
|
|
func (d netHTTPDoer) Do(ctx context.Context, req httpRequest) (*httpResponse, error) {
|
|
httpReq, err := http.NewRequestWithContext(ctx, http.MethodGet, req.URL, nil)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
httpReq.Header = req.Header.Clone()
|
|
|
|
resp, err := d.client.Do(httpReq)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
body, err := io.ReadAll(resp.Body)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &httpResponse{
|
|
StatusCode: resp.StatusCode,
|
|
Header: resp.Header.Clone(),
|
|
Body: body,
|
|
}, nil
|
|
}
|
|
|
|
func TestClientGetPlaintext_HappyPath(t *testing.T) {
|
|
const (
|
|
path = "/api/index/v2/liqHeatMap"
|
|
token = "dfa89d5d00cf4000"
|
|
)
|
|
|
|
plaintext := `{"instrument":{"exName":"Binance","instrumentId":"BTCUSDT"},"liq":[[1,2,3.4]]}`
|
|
|
|
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
require.Equal(t, path, r.URL.Path)
|
|
require.Equal(t, "true", r.URL.Query().Get("merge"))
|
|
require.Equal(t, "Binance_BTCUSDT", r.URL.Query().Get("symbol"))
|
|
require.NotEmpty(t, r.URL.Query().Get("data"))
|
|
require.Equal(t, "true", r.Header.Get("Encryption"))
|
|
require.Equal(t, defaultOrigin, r.Header.Get("Origin"))
|
|
require.NotEmpty(t, r.Header.Get("Cache-Ts-V2"))
|
|
|
|
cacheTs := r.Header.Get("Cache-Ts-V2")
|
|
_, err := strconv.ParseInt(cacheTs, 10, 64)
|
|
require.NoError(t, err)
|
|
|
|
w.Header().Set("v", "0")
|
|
w.Header().Set("user", encryptForTest(t, userKeyFromSeed(cacheTs), token))
|
|
_ = json.NewEncoder(w).Encode(map[string]any{
|
|
"code": "0",
|
|
"msg": "success",
|
|
"data": encryptForTest(t, bodyKeyFromToken(token), plaintext),
|
|
})
|
|
}))
|
|
defer ts.Close()
|
|
|
|
client := newTestClient(t, ts.URL)
|
|
got, err := client.GetPlaintext(context.Background(), path, url.Values{
|
|
"merge": {"true"},
|
|
"symbol": {"Binance_BTCUSDT"},
|
|
"interval": {"5"},
|
|
"limit": {"288"},
|
|
})
|
|
|
|
require.NoError(t, err)
|
|
require.JSONEq(t, plaintext, string(got))
|
|
}
|
|
|
|
func TestClientGetPlaintext_RetriesFakeSuccessOnce(t *testing.T) {
|
|
var attempts int32
|
|
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
atomic.AddInt32(&attempts, 1)
|
|
_ = json.NewEncoder(w).Encode(map[string]any{
|
|
"success": true,
|
|
"code": "0",
|
|
"msg": "success",
|
|
"data": nil,
|
|
})
|
|
}))
|
|
defer ts.Close()
|
|
|
|
client := newTestClient(t, ts.URL)
|
|
_, err := client.GetPlaintext(context.Background(), "/api/index/v2/liqHeatMap", nil)
|
|
|
|
require.ErrorIs(t, err, ErrFakeSuccess)
|
|
require.Equal(t, int32(2), atomic.LoadInt32(&attempts))
|
|
}
|
|
|
|
func TestClientGetPlaintext_BusinessErrorDoesNotRetry(t *testing.T) {
|
|
var attempts int32
|
|
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
atomic.AddInt32(&attempts, 1)
|
|
_ = json.NewEncoder(w).Encode(map[string]any{
|
|
"success": false,
|
|
"code": "40000",
|
|
"msg": "40000",
|
|
})
|
|
}))
|
|
defer ts.Close()
|
|
|
|
client := newTestClient(t, ts.URL)
|
|
_, err := client.GetPlaintext(context.Background(), "/api/index/v2/liqHeatMap", nil)
|
|
|
|
require.Error(t, err)
|
|
require.True(t, errors.Is(err, ErrAPIBusiness))
|
|
require.Equal(t, int32(1), atomic.LoadInt32(&attempts))
|
|
}
|
|
|
|
func TestClientGetPlaintext_MissingDecryptHeadersIsFakeSuccess(t *testing.T) {
|
|
const token = "dfa89d5d00cf4000"
|
|
|
|
var attempts int32
|
|
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
atomic.AddInt32(&attempts, 1)
|
|
_ = json.NewEncoder(w).Encode(map[string]any{
|
|
"code": "0",
|
|
"msg": "success",
|
|
"data": encryptForTest(t, bodyKeyFromToken(token), `{"ok":true}`),
|
|
})
|
|
}))
|
|
defer ts.Close()
|
|
|
|
client := newTestClient(t, ts.URL)
|
|
_, err := client.GetPlaintext(context.Background(), "/api/index/v2/liqHeatMap", nil)
|
|
|
|
require.ErrorIs(t, err, ErrFakeSuccess)
|
|
require.Equal(t, int32(2), atomic.LoadInt32(&attempts))
|
|
}
|
|
|
|
func newTestClient(t *testing.T, baseURL string) *Client {
|
|
t.Helper()
|
|
client, err := newClientWithDoer(ClientOptions{
|
|
BaseURL: baseURL,
|
|
TOTPSecret: "JBSWY3DPEHPK3PXP",
|
|
FakeSuccessRetryWait: time.Nanosecond,
|
|
}, netHTTPDoer{client: http.DefaultClient})
|
|
require.NoError(t, err)
|
|
client.now = func() time.Time {
|
|
return time.Unix(1735689600, 123*int64(time.Millisecond))
|
|
}
|
|
return client
|
|
}
|