faraday/fiat/coincap_api_test.go
Elle Mouton dffb00929f
fiat: add Currency field to the Price struct
Add Currency field to the price struct so that Price can be used to
represent any currency.
2021-08-27 16:02:01 +02:00

206 lines
4.8 KiB
Go

package fiat
import (
"context"
"encoding/json"
"testing"
"time"
"github.com/shopspring/decimal"
"github.com/stretchr/testify/require"
)
// TestCoinCapGetPrices tests splitting of a query period into the number of
// requests required to obtain the desired granularity.
func TestCoinCapGetPrices(t *testing.T) {
now := time.Now()
twoDaysAgo := now.Add(time.Hour * -24 * 2)
tests := []struct {
name string
granularity Granularity
startTime time.Time
endTime time.Time
expectedCallCount int
expectedErr error
}{
{
name: "single point in time",
granularity: GranularityMinute,
startTime: now,
endTime: now,
expectedCallCount: 1,
expectedErr: nil,
},
{
// One minute has a maximum 24H period, two days ago
// less the buffer we add to our start time should
// produce exactly 2 queries.
name: "exact period including buffer",
granularity: GranularityMinute,
startTime: twoDaysAgo.Add(time.Minute),
endTime: now,
expectedCallCount: 2,
expectedErr: nil,
},
{
// One minute has a maximum 24H period, two days ago
// should require 3 due to our buffer of 1 minute.
name: "extra for buffer",
granularity: GranularityMinute,
startTime: twoDaysAgo,
endTime: now,
expectedCallCount: 3,
expectedErr: nil,
},
}
for _, test := range tests {
test := test
t.Run(test.name, func(t *testing.T) {
mock := &fakeQuery{}
// Create a mocked query function which will track
// our call count and error as required for the test.
query := func(_, _ time.Time,
_ Granularity) ([]byte, error) {
if err := mock.call(); err != nil {
return nil, err
}
return nil, nil
}
// Create a mocked convert function.
convert := func([]byte) ([]*Price, error) {
return nil, nil
}
coinCapAPI := coinCapAPI{
granularity: test.granularity,
query: query,
convert: convert,
}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
_, err := coinCapAPI.rawPriceData(
ctx, test.startTime, test.endTime,
)
if err != test.expectedErr {
t.Fatalf("expected: %v,got: %v",
test.expectedErr, err)
}
if test.expectedCallCount != mock.callCount {
t.Fatalf("expected call count: %v, got: %v",
test.expectedCallCount,
mock.callCount)
}
})
}
}
// TestBestGranularity tests getting of the lowest granularity possible for
// a given query duration.
func TestBestGranularity(t *testing.T) {
tests := []struct {
name string
duration time.Duration
granularity Granularity
err error
}{
{
name: "equal to interval max",
duration: GranularityMinute.maximumQuery,
granularity: GranularityMinute,
err: nil,
},
{
name: "less than interval",
duration: time.Second,
granularity: GranularityMinute,
err: nil,
},
{
name: "within 15 min period",
duration: Granularity15Minute.maximumQuery - 100,
granularity: Granularity15Minute,
err: nil,
},
{
name: "too long",
duration: GranularityDay.maximumQuery + 1,
granularity: Granularity{},
err: ErrQueryTooLong,
},
}
for _, test := range tests {
test := test
t.Run(test.name, func(t *testing.T) {
t.Parallel()
best, err := BestGranularity(test.duration)
require.Equal(t, test.err, err)
require.Equal(t, test.granularity, best)
})
}
}
// TestParseCoinCapData adds a test which checks that we appropriately parse
// the price and timestamp data returned by coincap's api.
func TestParseCoinCapData(t *testing.T) {
var (
// Create two prices, one which is a float to ensure that we
// are correctly parsing them.
price1 = decimal.NewFromFloat(10.1)
price2 = decimal.NewFromInt(110000)
// Create two timestamps, each representing our time in
// milliseconds.
time1 = time.Unix(10000, 0)
time2 = time.Unix(2000, 0)
)
// Create the struct we expect to receive from coincap and marshal it
// into bytes. We set our timestamps to Unix() *1000 so that our time
// stamps are expressed in milliseconds.
resps := coinCapResponse{
Data: []*coinCapDataPoint{
{
Price: price1.String(),
Timestamp: time1.Unix() * 1000,
},
{
Price: price2.String(),
Timestamp: time2.Unix() * 1000,
},
},
}
bytes, err := json.Marshal(resps)
require.NoError(t, err)
prices, err := parseCoinCapData(bytes)
require.NoError(t, err)
expectedPrices := []*Price{
{
Price: price1,
Timestamp: time1,
Currency: coinCapDefaultCurrency,
},
{
Price: price2,
Timestamp: time2,
Currency: coinCapDefaultCurrency,
},
}
require.Equal(t, expectedPrices, prices)
}