mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-05-13 23:16:45 +00:00
1395 lines
30 KiB
Go
1395 lines
30 KiB
Go
package kline
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"math/rand"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
"github.com/thrasher-corp/gocryptotrader/common"
|
|
"github.com/thrasher-corp/gocryptotrader/currency"
|
|
"github.com/thrasher-corp/gocryptotrader/database"
|
|
"github.com/thrasher-corp/gocryptotrader/database/drivers"
|
|
"github.com/thrasher-corp/gocryptotrader/database/repository/candle"
|
|
"github.com/thrasher-corp/gocryptotrader/database/repository/exchange"
|
|
"github.com/thrasher-corp/gocryptotrader/database/testhelpers"
|
|
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
|
|
"github.com/thrasher-corp/gocryptotrader/exchanges/order"
|
|
)
|
|
|
|
var (
|
|
verbose = false
|
|
testExchanges = []exchange.Details{{Name: "one"}}
|
|
)
|
|
|
|
func TestValidateData(t *testing.T) {
|
|
t.Parallel()
|
|
err := validateData(nil)
|
|
if err == nil {
|
|
t.Error("error cannot be nil")
|
|
}
|
|
|
|
var empty []order.TradeHistory
|
|
err = validateData(empty)
|
|
if err == nil {
|
|
t.Error("error cannot be nil")
|
|
}
|
|
|
|
tn := time.Now()
|
|
trade1 := []order.TradeHistory{
|
|
{Timestamp: tn.Add(2 * time.Minute), TID: "2"},
|
|
{Timestamp: tn.Add(time.Minute), TID: "1"},
|
|
{Timestamp: tn.Add(3 * time.Minute), TID: "3"},
|
|
}
|
|
|
|
err = validateData(trade1)
|
|
if err == nil {
|
|
t.Error("error cannot be nil")
|
|
}
|
|
|
|
trade2 := []order.TradeHistory{
|
|
{Timestamp: tn.Add(2 * time.Minute), TID: "2", Amount: 1, Price: 0},
|
|
}
|
|
|
|
err = validateData(trade2)
|
|
if err == nil {
|
|
t.Error("error cannot be nil")
|
|
}
|
|
|
|
trade3 := []order.TradeHistory{
|
|
{TID: "2", Amount: 1, Price: 0},
|
|
}
|
|
|
|
err = validateData(trade3)
|
|
if err == nil {
|
|
t.Error("error cannot be nil")
|
|
}
|
|
|
|
trade4 := []order.TradeHistory{
|
|
{Timestamp: tn.Add(2 * time.Minute), TID: "2", Amount: 1, Price: 1000},
|
|
{Timestamp: tn.Add(time.Minute), TID: "1", Amount: 1, Price: 1001},
|
|
{Timestamp: tn.Add(3 * time.Minute), TID: "3", Amount: 1, Price: 1001.5},
|
|
}
|
|
|
|
err = validateData(trade4)
|
|
if !errors.Is(err, nil) {
|
|
t.Errorf("received '%v' expected '%v'", err, nil)
|
|
}
|
|
|
|
if trade4[0].TID != "1" || trade4[1].TID != "2" || trade4[2].TID != "3" {
|
|
t.Error("trade history sorted incorrectly")
|
|
}
|
|
}
|
|
|
|
func TestCreateKline(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
pair := currency.NewPair(currency.BTC, currency.USD)
|
|
_, err := CreateKline(nil, OneMin, pair, asset.Spot, "Binance")
|
|
if !errors.Is(err, errInsufficientTradeData) {
|
|
t.Fatalf("received: '%v' but expected '%v'", err, errInsufficientTradeData)
|
|
}
|
|
|
|
tradeTotal := 24000
|
|
trades := make([]order.TradeHistory, tradeTotal)
|
|
execution := time.Now()
|
|
for x := range tradeTotal {
|
|
price, rndTime := 1000+float64(rand.Intn(1000)), rand.Intn(10) //nolint:gosec // no need to import crypo/rand for testing
|
|
execution = execution.Add(time.Duration(rndTime) * time.Second)
|
|
trades[x] = order.TradeHistory{
|
|
Timestamp: execution,
|
|
Amount: 1, // Keep as one for counting
|
|
Price: price,
|
|
}
|
|
}
|
|
|
|
_, err = CreateKline(trades, 0, pair, asset.Spot, "Binance")
|
|
if !errors.Is(err, ErrInvalidInterval) {
|
|
t.Fatalf("received: '%v' but expected '%v'", err, ErrInvalidInterval)
|
|
}
|
|
|
|
c, err := CreateKline(trades, OneMin, pair, asset.Spot, "Binance")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
var amounts float64
|
|
for x := range c.Candles {
|
|
amounts += c.Candles[x].Volume
|
|
}
|
|
if amounts != float64(tradeTotal) {
|
|
t.Fatalf("received: '%v' but expected '%v'", amounts, float64(tradeTotal))
|
|
}
|
|
}
|
|
|
|
func TestKlineWord(t *testing.T) {
|
|
t.Parallel()
|
|
if OneDay.Word() != "oneday" {
|
|
t.Fatalf("unexpected result: %v", OneDay.Word())
|
|
}
|
|
}
|
|
|
|
func TestKlineDuration(t *testing.T) {
|
|
t.Parallel()
|
|
if OneDay.Duration() != time.Hour*24 {
|
|
t.Fatalf("unexpected result: %v", OneDay.Duration())
|
|
}
|
|
}
|
|
|
|
func TestKlineShort(t *testing.T) {
|
|
t.Parallel()
|
|
assert.Equal(t, "24h", OneDay.Short(), "One day should show as 24h")
|
|
assert.Equal(t, "1h", OneHour.Short(), "One hour should truncate 0m0s suffix")
|
|
assert.Equal(t, "raw", Raw.Short(), "Raw should return raw")
|
|
}
|
|
|
|
func TestDurationToWord(t *testing.T) {
|
|
t.Parallel()
|
|
testCases := []struct {
|
|
name string
|
|
interval Interval
|
|
}{
|
|
{
|
|
"raw",
|
|
Raw,
|
|
},
|
|
{
|
|
"hundredmillisec",
|
|
HundredMilliseconds,
|
|
},
|
|
{
|
|
"thousandmillisec",
|
|
ThousandMilliseconds,
|
|
},
|
|
{
|
|
"tensec",
|
|
TenSecond,
|
|
},
|
|
{
|
|
"FifteenSecond",
|
|
FifteenSecond,
|
|
},
|
|
{
|
|
"OneMin",
|
|
OneMin,
|
|
},
|
|
{
|
|
"ThreeMin",
|
|
ThreeMin,
|
|
},
|
|
{
|
|
"FiveMin",
|
|
FiveMin,
|
|
},
|
|
{
|
|
"TenMin",
|
|
TenMin,
|
|
},
|
|
{
|
|
"FifteenMin",
|
|
FifteenMin,
|
|
},
|
|
{
|
|
"ThirtyMin",
|
|
ThirtyMin,
|
|
},
|
|
{
|
|
"OneHour",
|
|
OneHour,
|
|
},
|
|
{
|
|
"TwoHour",
|
|
TwoHour,
|
|
},
|
|
{
|
|
"FourHour",
|
|
FourHour,
|
|
},
|
|
{
|
|
"SixHour",
|
|
SixHour,
|
|
},
|
|
{
|
|
"EightHour",
|
|
OneHour * 8,
|
|
},
|
|
{
|
|
"TwelveHour",
|
|
TwelveHour,
|
|
},
|
|
{
|
|
"OneDay",
|
|
OneDay,
|
|
},
|
|
{
|
|
"ThreeDay",
|
|
ThreeDay,
|
|
},
|
|
{
|
|
"FiveDay",
|
|
FiveDay,
|
|
},
|
|
{
|
|
"FifteenDay",
|
|
FifteenDay,
|
|
},
|
|
{
|
|
"OneWeek",
|
|
OneWeek,
|
|
},
|
|
{
|
|
"TwoWeek",
|
|
TwoWeek,
|
|
},
|
|
{
|
|
"OneMonth",
|
|
OneMonth,
|
|
},
|
|
{
|
|
"ThreeMonth",
|
|
ThreeMonth,
|
|
},
|
|
{
|
|
"SixMonth",
|
|
SixMonth,
|
|
},
|
|
{
|
|
"OneYear",
|
|
OneYear,
|
|
},
|
|
{
|
|
"notfound",
|
|
Interval(time.Hour * 1337),
|
|
},
|
|
}
|
|
for x := range testCases {
|
|
test := testCases[x]
|
|
t.Run(test.name, func(t *testing.T) {
|
|
t.Parallel()
|
|
t.Helper()
|
|
v := durationToWord(test.interval)
|
|
if !strings.EqualFold(v, test.name) {
|
|
t.Fatalf("%v: received %v expected %v", test.name, v, test.name)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestTotalCandlesPerInterval(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tmNow := time.Now()
|
|
assert.Equal(t, uint64(0), TotalCandlesPerInterval(tmNow.AddDate(0, 0, 1), tmNow, OneMin))
|
|
|
|
start := time.Date(2019, 1, 1, 0, 0, 0, 0, time.UTC)
|
|
end := time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC)
|
|
|
|
testCases := []struct {
|
|
name string
|
|
interval Interval
|
|
expected uint64
|
|
}{
|
|
{
|
|
"FifteenSecond",
|
|
FifteenSecond,
|
|
2102400,
|
|
},
|
|
{
|
|
"OneMin",
|
|
OneMin,
|
|
525600,
|
|
},
|
|
{
|
|
"ThreeMin",
|
|
ThreeMin,
|
|
175200,
|
|
},
|
|
{
|
|
"FiveMin",
|
|
FiveMin,
|
|
105120,
|
|
},
|
|
{
|
|
"TenMin",
|
|
TenMin,
|
|
52560,
|
|
},
|
|
{
|
|
"FifteenMin",
|
|
FifteenMin,
|
|
35040,
|
|
},
|
|
{
|
|
"ThirtyMin",
|
|
ThirtyMin,
|
|
17520,
|
|
},
|
|
{
|
|
"OneHour",
|
|
OneHour,
|
|
8760,
|
|
},
|
|
{
|
|
"TwoHour",
|
|
TwoHour,
|
|
4380,
|
|
},
|
|
{
|
|
"FourHour",
|
|
FourHour,
|
|
2190,
|
|
},
|
|
{
|
|
"SixHour",
|
|
SixHour,
|
|
1460,
|
|
},
|
|
{
|
|
"EightHour",
|
|
OneHour * 8,
|
|
1095,
|
|
},
|
|
{
|
|
"TwelveHour",
|
|
TwelveHour,
|
|
730,
|
|
},
|
|
{
|
|
"OneDay",
|
|
OneDay,
|
|
365,
|
|
},
|
|
{
|
|
"ThreeDay",
|
|
ThreeDay,
|
|
121,
|
|
},
|
|
{
|
|
"FiveDay",
|
|
FiveDay,
|
|
73,
|
|
},
|
|
{
|
|
"FifteenDay",
|
|
FifteenDay,
|
|
24,
|
|
},
|
|
{
|
|
"OneWeek",
|
|
OneWeek,
|
|
52,
|
|
},
|
|
{
|
|
"TwoWeek",
|
|
TwoWeek,
|
|
26,
|
|
},
|
|
{
|
|
"OneMonth",
|
|
OneMonth,
|
|
12,
|
|
},
|
|
{
|
|
"OneYear",
|
|
OneYear,
|
|
1,
|
|
},
|
|
}
|
|
for x := range testCases {
|
|
test := testCases[x]
|
|
t.Run(test.name, func(t *testing.T) {
|
|
t.Parallel()
|
|
v := TotalCandlesPerInterval(start, end, test.interval)
|
|
if v != test.expected {
|
|
t.Fatalf("%v: received %v expected %v", test.name, v, test.expected)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestCalculateCandleDateRanges(t *testing.T) {
|
|
t.Parallel()
|
|
pt := time.Date(2019, 1, 1, 0, 0, 0, 0, time.UTC)
|
|
ft := time.Date(2222, 1, 1, 0, 0, 0, 0, time.UTC)
|
|
et := time.Date(2020, 1, 1, 1, 0, 0, 0, time.UTC)
|
|
|
|
_, err := CalculateCandleDateRanges(time.Time{}, time.Time{}, OneMin, 300)
|
|
assert.ErrorIs(t, err, common.ErrDateUnset)
|
|
|
|
_, err = CalculateCandleDateRanges(et, pt, OneMin, 300)
|
|
assert.ErrorIs(t, err, common.ErrStartAfterEnd)
|
|
|
|
_, err = CalculateCandleDateRanges(et, ft, 0, 300)
|
|
assert.ErrorIs(t, err, ErrInvalidInterval)
|
|
|
|
_, err = CalculateCandleDateRanges(et, et, OneMin, 300)
|
|
assert.ErrorIs(t, err, common.ErrStartEqualsEnd)
|
|
|
|
v, err := CalculateCandleDateRanges(pt, et, OneWeek, 300)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, int64(1546214400), v.Ranges[0].Start.Ticks)
|
|
|
|
v, err = CalculateCandleDateRanges(pt, et, OneWeek, 100)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, 1, len(v.Ranges))
|
|
assert.Equal(t, 52, len(v.Ranges[0].Intervals))
|
|
|
|
v, err = CalculateCandleDateRanges(et, ft, OneWeek, 5)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, 2108, len(v.Ranges))
|
|
assert.Equal(t, 5, len(v.Ranges[0].Intervals))
|
|
lenRanges := len(v.Ranges) - 1
|
|
lenIntervals := len(v.Ranges[lenRanges].Intervals) - 1
|
|
assert.True(t, v.Ranges[lenRanges].Intervals[lenIntervals].End.Equal(ft.Round(OneWeek.Duration())))
|
|
|
|
start := time.Date(2023, 1, 1, 0, 0, 0, 0, time.UTC)
|
|
end := start.Add(24 * time.Hour)
|
|
v, err = CalculateCandleDateRanges(start, end, OneDay, 0)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, uint64(1), v.Limit)
|
|
}
|
|
|
|
func TestItem_SortCandlesByTimestamp(t *testing.T) {
|
|
t.Parallel()
|
|
var tempKline = Item{
|
|
Exchange: "testExchange",
|
|
Pair: currency.NewPair(currency.BTC, currency.USDT),
|
|
Asset: asset.Spot,
|
|
Interval: OneDay,
|
|
}
|
|
|
|
for x := range 100 {
|
|
y := rand.Float64() //nolint:gosec // used for generating test data, no need to import crypo/rand
|
|
tempKline.Candles = append(tempKline.Candles,
|
|
Candle{
|
|
Time: time.Now().AddDate(0, 0, -x),
|
|
Open: y,
|
|
High: y + float64(x),
|
|
Low: y - float64(x),
|
|
Close: y,
|
|
Volume: y,
|
|
})
|
|
}
|
|
|
|
tempKline.SortCandlesByTimestamp(false)
|
|
if tempKline.Candles[0].Time.After(tempKline.Candles[1].Time) {
|
|
t.Fatal("expected kline.Candles to be in descending order")
|
|
}
|
|
|
|
tempKline.SortCandlesByTimestamp(true)
|
|
if tempKline.Candles[0].Time.Before(tempKline.Candles[1].Time) {
|
|
t.Fatal("expected kline.Candles to be in ascending order")
|
|
}
|
|
}
|
|
|
|
func setupTest(t *testing.T) {
|
|
t.Helper()
|
|
if verbose {
|
|
err := testhelpers.EnableVerboseTestOutput()
|
|
if err != nil {
|
|
fmt.Printf("failed to enable verbose test output: %v", err)
|
|
os.Exit(1)
|
|
}
|
|
}
|
|
|
|
testhelpers.MigrationDir = filepath.Join("..", "..", "database", "migrations")
|
|
testhelpers.PostgresTestDatabase = testhelpers.GetConnectionDetails()
|
|
testhelpers.TempDir = t.TempDir()
|
|
}
|
|
|
|
func TestStoreInDatabase(t *testing.T) {
|
|
setupTest(t)
|
|
|
|
testCases := []struct {
|
|
name string
|
|
config *database.Config
|
|
seedDB func(bool) error
|
|
runner func(t *testing.T)
|
|
closer func(dbConn *database.Instance) error
|
|
}{
|
|
{
|
|
name: "postgresql",
|
|
config: testhelpers.PostgresTestDatabase,
|
|
seedDB: seedDB,
|
|
},
|
|
{
|
|
name: "SQLite",
|
|
config: &database.Config{
|
|
Driver: database.DBSQLite3,
|
|
ConnectionDetails: drivers.ConnectionDetails{Database: "./testdb"},
|
|
},
|
|
seedDB: seedDB,
|
|
},
|
|
}
|
|
|
|
for x := range testCases {
|
|
test := testCases[x]
|
|
|
|
t.Run(test.name, func(t *testing.T) {
|
|
if !testhelpers.CheckValidConfig(&test.config.ConnectionDetails) {
|
|
t.Skip("database not configured skipping test")
|
|
}
|
|
|
|
dbConn, err := testhelpers.ConnectToDatabase(test.config)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if test.seedDB != nil {
|
|
err = test.seedDB(false)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
_, ohlcvData, err := genOHCLVData()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
r, err := StoreInDatabase(&ohlcvData, false)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if r != 365 {
|
|
t.Fatalf("unexpected number inserted: %v", r)
|
|
}
|
|
|
|
r, err = StoreInDatabase(&ohlcvData, true)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if r != 365 {
|
|
t.Fatalf("unexpected number inserted: %v", r)
|
|
}
|
|
|
|
err = testhelpers.CloseDatabase(dbConn)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
})
|
|
}
|
|
|
|
err := os.RemoveAll(testhelpers.TempDir)
|
|
if err != nil {
|
|
t.Fatalf("Failed to remove temp db file: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestLoadFromDatabase(t *testing.T) {
|
|
setupTest(t)
|
|
|
|
testCases := []struct {
|
|
name string
|
|
config *database.Config
|
|
seedDB func(bool) error
|
|
runner func(t *testing.T)
|
|
closer func(dbConn *database.Instance) error
|
|
}{
|
|
{
|
|
name: "postgresql",
|
|
config: testhelpers.PostgresTestDatabase,
|
|
seedDB: seedDB,
|
|
},
|
|
{
|
|
name: "SQLite",
|
|
config: &database.Config{
|
|
Driver: database.DBSQLite3,
|
|
ConnectionDetails: drivers.ConnectionDetails{Database: "./testdb"},
|
|
},
|
|
seedDB: seedDB,
|
|
},
|
|
}
|
|
|
|
for x := range testCases {
|
|
test := testCases[x]
|
|
|
|
t.Run(test.name, func(t *testing.T) {
|
|
if !testhelpers.CheckValidConfig(&test.config.ConnectionDetails) {
|
|
t.Skip("database not configured skipping test")
|
|
}
|
|
|
|
dbConn, err := testhelpers.ConnectToDatabase(test.config)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if test.seedDB != nil {
|
|
err = test.seedDB(true)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
p, err := currency.NewPairFromString("BTCUSDT")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
start := time.Date(2019, 1, 1, 0, 0, 0, 0, time.UTC)
|
|
end := start.AddDate(1, 0, 0)
|
|
ret, err := LoadFromDatabase(testExchanges[0].Name, p, asset.Spot, OneDay, start, end)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if ret.Exchange != testExchanges[0].Name {
|
|
t.Fatalf("incorrect data returned: %v", ret.Exchange)
|
|
}
|
|
|
|
err = testhelpers.CloseDatabase(dbConn)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
})
|
|
}
|
|
|
|
err := os.RemoveAll(testhelpers.TempDir)
|
|
if err != nil {
|
|
t.Fatalf("Failed to remove temp db file: %v", err)
|
|
}
|
|
}
|
|
|
|
// TODO: find a better way to handle this to remove duplication between candle test
|
|
func seedDB(includeOHLCVData bool) error {
|
|
err := exchange.InsertMany(testExchanges)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if includeOHLCVData {
|
|
data, _, err := genOHCLVData()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
_, err = candle.Insert(&data)
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func genOHCLVData() (out candle.Item, outItem Item, err error) {
|
|
exchangeUUID, err := exchange.UUIDByName(testExchanges[0].Name)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
out.ExchangeID = exchangeUUID.String()
|
|
out.Base = currency.BTC.String()
|
|
out.Quote = currency.USDT.String()
|
|
out.Interval = 86400
|
|
out.Asset = "spot"
|
|
|
|
start := time.Date(2019, 1, 1, 0, 0, 0, 0, time.UTC)
|
|
for x := range 365 {
|
|
out.Candles = append(out.Candles, candle.Candle{
|
|
Timestamp: start.Add(time.Hour * 24 * time.Duration(x)),
|
|
Open: 1000,
|
|
High: 1000,
|
|
Low: 1000,
|
|
Close: 1000,
|
|
Volume: 1000,
|
|
})
|
|
}
|
|
|
|
outItem.Interval = OneDay
|
|
outItem.Asset = asset.Spot
|
|
outItem.Pair = currency.NewPair(currency.BTC, currency.USDT)
|
|
outItem.Exchange = testExchanges[0].Name
|
|
|
|
for x := range 365 {
|
|
outItem.Candles = append(outItem.Candles, Candle{
|
|
Time: start.Add(time.Hour * 24 * time.Duration(x)),
|
|
Open: 1000,
|
|
High: 1000,
|
|
Low: 1000,
|
|
Close: 1000,
|
|
Volume: 1000,
|
|
})
|
|
}
|
|
|
|
return out, outItem, nil
|
|
}
|
|
|
|
func TestLoadCSV(t *testing.T) {
|
|
v, err := LoadFromGCTScriptCSV(filepath.Join("..", "..", "testdata", "binance_BTCUSDT_24h_2019_01_01_2020_01_01.csv"))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if v[0].Time.UTC() != time.Unix(1546300800, 0).UTC() {
|
|
t.Fatalf("unexpected value received: %v", v[0].Time)
|
|
}
|
|
|
|
if v[269].Close != 8177.91 {
|
|
t.Fatalf("unexpected value received: %v", v[269].Close)
|
|
}
|
|
|
|
if v[364].Open != 7246 {
|
|
t.Fatalf("unexpected value received: %v", v[364].Open)
|
|
}
|
|
}
|
|
|
|
func TestVerifyResultsHaveData(t *testing.T) {
|
|
t.Parallel()
|
|
tt1 := time.Now().Round(OneDay.Duration())
|
|
tt2 := tt1.Add(OneDay.Duration())
|
|
tt3 := tt2.Add(OneDay.Duration()) // end date no longer inclusive
|
|
dateRanges, err := CalculateCandleDateRanges(tt1, tt3, OneDay, 0)
|
|
if !errors.Is(err, nil) {
|
|
t.Errorf("received '%v' expected '%v'", err, nil)
|
|
}
|
|
if dateRanges.HasDataAtDate(tt1) {
|
|
t.Error("unexpected true value")
|
|
}
|
|
err = dateRanges.SetHasDataFromCandles([]Candle{
|
|
{
|
|
Time: tt1,
|
|
Low: 1337,
|
|
},
|
|
{
|
|
Time: tt2,
|
|
},
|
|
})
|
|
if !errors.Is(err, nil) {
|
|
t.Errorf("received '%v' expected '%v'", err, nil)
|
|
}
|
|
|
|
if !dateRanges.HasDataAtDate(tt1) {
|
|
t.Error("expected true")
|
|
}
|
|
err = dateRanges.SetHasDataFromCandles([]Candle{
|
|
{
|
|
Time: tt1,
|
|
},
|
|
{
|
|
Time: tt2,
|
|
Low: 1337,
|
|
},
|
|
})
|
|
if !errors.Is(err, nil) {
|
|
t.Errorf("received '%v' expected '%v'", err, nil)
|
|
}
|
|
if dateRanges.HasDataAtDate(tt1) {
|
|
t.Error("expected false")
|
|
}
|
|
}
|
|
|
|
func TestDataSummary(t *testing.T) {
|
|
t.Parallel()
|
|
tt1 := time.Now().Add(-time.Hour * 24).Round(OneDay.Duration())
|
|
tt2 := time.Now().Round(OneDay.Duration())
|
|
tt3 := time.Now().Add(time.Hour * 24).Round(OneDay.Duration())
|
|
dateRanges, err := CalculateCandleDateRanges(tt1, tt2, OneDay, 0)
|
|
if !errors.Is(err, nil) {
|
|
t.Errorf("received '%v' expected '%v'", err, nil)
|
|
}
|
|
result := dateRanges.DataSummary(false)
|
|
if len(result) != 1 {
|
|
t.Errorf("expected %v received %v", 1, len(result))
|
|
}
|
|
dateRanges, err = CalculateCandleDateRanges(tt1, tt3, OneDay, 0)
|
|
if !errors.Is(err, nil) {
|
|
t.Errorf("received '%v' expected '%v'", err, nil)
|
|
}
|
|
dateRanges.Ranges[0].Intervals[0].HasData = true
|
|
result = dateRanges.DataSummary(true)
|
|
if len(result) != 2 {
|
|
t.Errorf("expected %v received %v", 2, len(result))
|
|
}
|
|
result = dateRanges.DataSummary(false)
|
|
if len(result) != 1 {
|
|
t.Errorf("expected %v received %v", 1, len(result))
|
|
}
|
|
}
|
|
|
|
func TestHasDataAtDate(t *testing.T) {
|
|
t.Parallel()
|
|
tt1 := time.Now().Round(OneDay.Duration())
|
|
tt2 := tt1.Add(OneDay.Duration())
|
|
tt3 := tt2.Add(OneDay.Duration()) // end date no longer inclusive
|
|
dateRanges, err := CalculateCandleDateRanges(tt1, tt3, OneDay, 0)
|
|
if !errors.Is(err, nil) {
|
|
t.Errorf("received '%v' expected '%v'", err, nil)
|
|
}
|
|
if dateRanges.HasDataAtDate(tt2) {
|
|
t.Error("unexpected true value")
|
|
}
|
|
|
|
err = dateRanges.SetHasDataFromCandles([]Candle{
|
|
{
|
|
Time: tt1,
|
|
Close: 1337,
|
|
},
|
|
{
|
|
Time: tt2,
|
|
Close: 1337,
|
|
},
|
|
})
|
|
if !errors.Is(err, nil) {
|
|
t.Errorf("received '%v' expected '%v'", err, nil)
|
|
}
|
|
|
|
if !dateRanges.HasDataAtDate(tt2) {
|
|
t.Error("unexpected false value")
|
|
}
|
|
|
|
if dateRanges.HasDataAtDate(tt2.Add(time.Hour * 24)) {
|
|
t.Error("should not have data")
|
|
}
|
|
}
|
|
|
|
func TestIntervalsPerYear(t *testing.T) {
|
|
t.Parallel()
|
|
var i Interval
|
|
if i.IntervalsPerYear() != 0 {
|
|
t.Error("expected 0")
|
|
}
|
|
i = OneYear
|
|
if i.IntervalsPerYear() != 1.0 {
|
|
t.Error("expected 1")
|
|
}
|
|
i = OneDay
|
|
if i.IntervalsPerYear() != 365 {
|
|
t.Error("expected 365")
|
|
}
|
|
i = OneHour
|
|
if i.IntervalsPerYear() != 8760 {
|
|
t.Error("expected 8670")
|
|
}
|
|
i = TwoHour
|
|
if i.IntervalsPerYear() != 4380 {
|
|
t.Error("expected 4380")
|
|
}
|
|
i = TwoHour + FifteenSecond
|
|
if i.IntervalsPerYear() != 4370.893970893971 {
|
|
t.Error("expected 4370...")
|
|
}
|
|
}
|
|
|
|
// The purpose of this benchmark is to highlight that requesting
|
|
// '.Unix()` frequently is a slow process
|
|
func BenchmarkJustifyIntervalTimeStoringUnixValues1(b *testing.B) {
|
|
tt1 := time.Now()
|
|
tt2 := time.Now().Add(-time.Hour)
|
|
tt3 := time.Now().Add(time.Hour)
|
|
for b.Loop() {
|
|
if tt1.Unix() == tt2.Unix() || (tt1.Unix() > tt2.Unix() && tt1.Unix() < tt3.Unix()) {
|
|
continue
|
|
}
|
|
}
|
|
}
|
|
|
|
// The purpose of this benchmark is to highlight that storing the unix value
|
|
// at time of creation is dramatically faster than frequently requesting `.Unix()`
|
|
// at runtime at scale. When dealing with the backtester and comparing
|
|
// tens of thousands of candle times
|
|
func BenchmarkJustifyIntervalTimeStoringUnixValues2(b *testing.B) {
|
|
tt1 := time.Now().Unix()
|
|
tt2 := time.Now().Add(-time.Hour).Unix()
|
|
tt3 := time.Now().Add(time.Hour).Unix()
|
|
for b.Loop() {
|
|
if tt1 >= tt2 && tt1 <= tt3 {
|
|
continue
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestConvertToNewInterval(t *testing.T) {
|
|
_, err := (*Item)(nil).ConvertToNewInterval(OneMin)
|
|
if !errors.Is(err, errNilKline) {
|
|
t.Errorf("received '%v' expected '%v'", err, errNilKline)
|
|
}
|
|
|
|
_, err = (&Item{}).ConvertToNewInterval(OneMin)
|
|
if !errors.Is(err, ErrInvalidInterval) {
|
|
t.Errorf("received '%v' expected '%v'", err, ErrInvalidInterval)
|
|
}
|
|
|
|
old := &Item{
|
|
Exchange: "lol",
|
|
Pair: currency.NewPair(currency.BTC, currency.USDT),
|
|
Asset: asset.Spot,
|
|
Interval: OneDay,
|
|
Candles: []Candle{
|
|
{
|
|
Time: time.Now(),
|
|
Open: 1337,
|
|
High: 1339,
|
|
Low: 1336,
|
|
Close: 1338,
|
|
Volume: 1337,
|
|
},
|
|
{
|
|
Time: time.Now().AddDate(0, 0, 1),
|
|
Open: 1338,
|
|
High: 2000,
|
|
Low: 1332,
|
|
Close: 1696,
|
|
Volume: 6420,
|
|
},
|
|
{
|
|
Time: time.Now().AddDate(0, 0, 2),
|
|
Open: 1696,
|
|
High: 1998,
|
|
Low: 1337,
|
|
Close: 6969,
|
|
Volume: 2520,
|
|
},
|
|
},
|
|
}
|
|
|
|
_, err = old.ConvertToNewInterval(0)
|
|
if !errors.Is(err, ErrInvalidInterval) {
|
|
t.Errorf("received '%v' expected '%v'", err, ErrInvalidInterval)
|
|
}
|
|
_, err = old.ConvertToNewInterval(OneMin)
|
|
if !errors.Is(err, ErrCanOnlyUpscaleCandles) {
|
|
t.Errorf("received '%v' expected '%v'", err, ErrCanOnlyUpscaleCandles)
|
|
}
|
|
old.Interval = ThreeDay
|
|
_, err = old.ConvertToNewInterval(OneWeek)
|
|
if !errors.Is(err, ErrWholeNumberScaling) {
|
|
t.Errorf("received '%v' expected '%v'", err, ErrWholeNumberScaling)
|
|
}
|
|
|
|
old.Interval = OneDay
|
|
newInterval := ThreeDay
|
|
newCandle, err := old.ConvertToNewInterval(newInterval)
|
|
if !errors.Is(err, nil) {
|
|
t.Fatalf("received '%v' expected '%v'", err, nil)
|
|
}
|
|
if len(newCandle.Candles) != 1 {
|
|
t.Error("expected one candle")
|
|
}
|
|
if newCandle.Candles[0].Open != 1337 &&
|
|
newCandle.Candles[0].High != 2000 &&
|
|
newCandle.Candles[0].Low != 1332 &&
|
|
newCandle.Candles[0].Close != 6969 &&
|
|
newCandle.Candles[0].Volume != (2520+6420+1337) {
|
|
t.Error("unexpected updoot")
|
|
}
|
|
|
|
old.Candles = append(old.Candles, Candle{
|
|
Time: time.Now().AddDate(0, 0, 3),
|
|
Open: 6969,
|
|
High: 1998,
|
|
Low: 2342,
|
|
Close: 7777,
|
|
Volume: 111,
|
|
})
|
|
newCandle, err = old.ConvertToNewInterval(newInterval)
|
|
if !errors.Is(err, nil) {
|
|
t.Errorf("received '%v' expected '%v'", err, nil)
|
|
}
|
|
if len(newCandle.Candles) != 1 {
|
|
t.Error("expected one candle")
|
|
}
|
|
|
|
_, err = old.ConvertToNewInterval(OneMonth)
|
|
if !errors.Is(err, ErrInsufficientCandleData) {
|
|
t.Errorf("received '%v' expected '%v'", err, ErrInsufficientCandleData)
|
|
}
|
|
|
|
tn := time.Now().Truncate(time.Duration(OneDay))
|
|
|
|
// Test incorrectly padded candles
|
|
old.Candles = []Candle{
|
|
{
|
|
Time: tn,
|
|
Open: 1337,
|
|
High: 1339,
|
|
Low: 1336,
|
|
Close: 1338,
|
|
Volume: 1337,
|
|
},
|
|
{
|
|
Time: tn.AddDate(0, 0, 1),
|
|
Open: 1338,
|
|
High: 2000,
|
|
Low: 1332,
|
|
Close: 1696,
|
|
Volume: 6420,
|
|
},
|
|
{
|
|
Time: tn.AddDate(0, 0, 2),
|
|
Open: 1696,
|
|
High: 1998,
|
|
Low: 1337,
|
|
Close: 6969,
|
|
Volume: 2520,
|
|
},
|
|
// empty candle should be here <---
|
|
// aaaand empty candle should be here <---
|
|
{
|
|
Time: tn.AddDate(0, 0, 5),
|
|
Open: 6969,
|
|
High: 8888,
|
|
Low: 1111,
|
|
Close: 5555,
|
|
Volume: 2520,
|
|
},
|
|
{
|
|
Time: tn.AddDate(0, 0, 6),
|
|
// Empty end padding
|
|
},
|
|
{
|
|
Time: tn.AddDate(0, 0, 7),
|
|
// Empty end padding
|
|
},
|
|
{
|
|
Time: tn.AddDate(0, 0, 8),
|
|
// Empty end padding
|
|
},
|
|
}
|
|
|
|
_, err = old.ConvertToNewInterval(newInterval)
|
|
if !errors.Is(err, errCandleDataNotPadded) {
|
|
t.Errorf("received '%v' expected '%v'", err, errCandleDataNotPadded)
|
|
}
|
|
|
|
err = old.addPadding(tn, tn.AddDate(0, 0, 9), false)
|
|
if !errors.Is(err, nil) {
|
|
t.Fatalf("received '%v' expected '%v'", err, nil)
|
|
}
|
|
|
|
newCandle, err = old.ConvertToNewInterval(newInterval)
|
|
if !errors.Is(err, nil) {
|
|
t.Fatalf("received '%v' expected '%v'", err, nil)
|
|
}
|
|
|
|
if len(newCandle.Candles) != 3 {
|
|
t.Errorf("received '%v' expected '%v'", len(newCandle.Candles), 3)
|
|
}
|
|
}
|
|
|
|
func TestAddPadding(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tn := time.Now().Truncate(time.Duration(OneDay))
|
|
|
|
var k *Item
|
|
err := k.addPadding(tn, tn.AddDate(0, 0, 5), false)
|
|
if !errors.Is(err, errNilKline) {
|
|
t.Fatalf("received '%v' expected '%v'", err, errNilKline)
|
|
}
|
|
|
|
k = &Item{}
|
|
k.Candles = []Candle{
|
|
{
|
|
Time: tn,
|
|
Open: 1337,
|
|
High: 1339,
|
|
Low: 1336,
|
|
Close: 1338,
|
|
Volume: 1337,
|
|
},
|
|
}
|
|
err = k.addPadding(tn, tn.AddDate(0, 0, 5), false)
|
|
if !errors.Is(err, ErrInvalidInterval) {
|
|
t.Fatalf("received '%v' expected '%v'", err, ErrInvalidInterval)
|
|
}
|
|
|
|
k.Interval = OneDay
|
|
k.Candles = []Candle{
|
|
{
|
|
Time: tn.AddDate(0, 0, 1),
|
|
Open: 1338,
|
|
High: 2000,
|
|
Low: 1332,
|
|
Close: 1696,
|
|
Volume: 6420,
|
|
},
|
|
{
|
|
Time: tn,
|
|
Open: 1337,
|
|
High: 1339,
|
|
Low: 1336,
|
|
Close: 1338,
|
|
Volume: 1337,
|
|
},
|
|
}
|
|
err = k.addPadding(tn.AddDate(0, 0, 5), tn, false)
|
|
if !errors.Is(err, errCannotEstablishTimeWindow) {
|
|
t.Fatalf("received '%v' expected '%v'", err, errCannotEstablishTimeWindow)
|
|
}
|
|
|
|
k.Candles = []Candle{
|
|
{
|
|
Time: tn.Add(time.Hour * 8),
|
|
Open: 1337,
|
|
High: 1339,
|
|
Low: 1336,
|
|
Close: 1338,
|
|
Volume: 1337,
|
|
},
|
|
{
|
|
Time: tn.AddDate(0, 0, 1).Add(time.Hour * 8),
|
|
Open: 1338,
|
|
High: 2000,
|
|
Low: 1332,
|
|
Close: 1696,
|
|
Volume: 6420,
|
|
},
|
|
{
|
|
Time: tn.AddDate(0, 0, 2).Add(time.Hour * 8),
|
|
Open: 1696,
|
|
High: 1998,
|
|
Low: 1337,
|
|
Close: 6969,
|
|
Volume: 2520,
|
|
}}
|
|
|
|
err = k.addPadding(tn, tn.AddDate(0, 0, 3), false)
|
|
if !errors.Is(err, errCandleOpenTimeIsNotUTCAligned) {
|
|
t.Fatalf("received '%v' expected '%v'", err, errCandleOpenTimeIsNotUTCAligned)
|
|
}
|
|
|
|
k.Candles = []Candle{
|
|
{
|
|
Time: tn,
|
|
Open: 1337,
|
|
High: 1339,
|
|
Low: 1336,
|
|
Close: 1338,
|
|
Volume: 1337,
|
|
},
|
|
{
|
|
Time: tn.AddDate(0, 0, 1),
|
|
Open: 1338,
|
|
High: 2000,
|
|
Low: 1332,
|
|
Close: 1696,
|
|
Volume: 6420,
|
|
},
|
|
{
|
|
Time: tn.AddDate(0, 0, 2),
|
|
Open: 1696,
|
|
High: 1998,
|
|
Low: 1337,
|
|
Close: 6969,
|
|
Volume: 2520,
|
|
}}
|
|
|
|
err = k.addPadding(tn, tn.AddDate(0, 0, 3), false)
|
|
if !errors.Is(err, nil) {
|
|
t.Fatalf("received '%v' expected '%v'", err, nil)
|
|
}
|
|
|
|
if len(k.Candles) != 3 {
|
|
t.Fatalf("received '%v' expected '%v'", len(k.Candles), 3)
|
|
}
|
|
|
|
k.Candles = append(k.Candles, Candle{
|
|
Time: tn.AddDate(0, 0, 5),
|
|
Open: 6969,
|
|
High: 8888,
|
|
Low: 1111,
|
|
Close: 5555,
|
|
Volume: 2520,
|
|
})
|
|
|
|
err = k.addPadding(tn, tn.AddDate(0, 0, 6), false)
|
|
if !errors.Is(err, nil) {
|
|
t.Fatalf("received '%v' expected '%v'", err, nil)
|
|
}
|
|
|
|
if len(k.Candles) != 6 {
|
|
t.Fatalf("received '%v' expected '%v'", len(k.Candles), 6)
|
|
}
|
|
|
|
// No candles test when there is zero activity for that period
|
|
k.Candles = nil
|
|
|
|
err = k.addPadding(tn, tn.AddDate(0, 0, 6), false)
|
|
if !errors.Is(err, nil) {
|
|
t.Errorf("received '%v' expected '%v'", err, nil)
|
|
}
|
|
|
|
if len(k.Candles) != 6 {
|
|
t.Errorf("received '%v' expected '%v'", len(k.Candles), 6)
|
|
}
|
|
}
|
|
|
|
func TestGetClosePriceAtTime(t *testing.T) {
|
|
t.Parallel()
|
|
tt := time.Now()
|
|
k := Item{
|
|
Candles: []Candle{
|
|
{
|
|
Time: tt,
|
|
Close: 1337,
|
|
},
|
|
{
|
|
Time: tt.Add(time.Hour),
|
|
Close: 1338,
|
|
},
|
|
},
|
|
}
|
|
price, err := k.GetClosePriceAtTime(tt)
|
|
if !errors.Is(err, nil) {
|
|
t.Errorf("received '%v' expected '%v'", err, nil)
|
|
}
|
|
if price != 1337 {
|
|
t.Errorf("received '%v' expected '%v'", price, 1337)
|
|
}
|
|
_, err = k.GetClosePriceAtTime(tt.Add(time.Minute))
|
|
if !errors.Is(err, ErrNotFoundAtTime) {
|
|
t.Errorf("received '%v' expected '%v'", err, ErrNotFoundAtTime)
|
|
}
|
|
}
|
|
|
|
func TestDeployExchangeIntervals(t *testing.T) {
|
|
t.Parallel()
|
|
exchangeIntervals := DeployExchangeIntervals()
|
|
if exchangeIntervals.ExchangeSupported(OneWeek) {
|
|
t.Errorf("received '%v' expected '%v'", exchangeIntervals.ExchangeSupported(OneWeek), false)
|
|
}
|
|
|
|
exchangeIntervals = DeployExchangeIntervals(IntervalCapacity{Interval: OneWeek})
|
|
if !exchangeIntervals.ExchangeSupported(OneWeek) {
|
|
t.Errorf("received '%v' expected '%v'", exchangeIntervals.ExchangeSupported(OneWeek), true)
|
|
}
|
|
|
|
_, err := exchangeIntervals.Construct(0)
|
|
if !errors.Is(err, ErrInvalidInterval) {
|
|
t.Errorf("received '%v' expected '%v'", err, ErrInvalidInterval)
|
|
}
|
|
|
|
_, err = exchangeIntervals.Construct(OneMin)
|
|
if !errors.Is(err, ErrCannotConstructInterval) {
|
|
t.Errorf("received '%v' expected '%v'", err, ErrCannotConstructInterval)
|
|
}
|
|
|
|
request, err := exchangeIntervals.Construct(OneWeek)
|
|
if !errors.Is(err, nil) {
|
|
t.Errorf("received '%v' expected '%v'", err, nil)
|
|
}
|
|
|
|
if request != OneWeek {
|
|
t.Errorf("received '%v' expected '%v'", request, OneWeek)
|
|
}
|
|
|
|
exchangeIntervals = DeployExchangeIntervals(IntervalCapacity{Interval: OneWeek}, IntervalCapacity{Interval: OneDay})
|
|
|
|
request, err = exchangeIntervals.Construct(OneMonth)
|
|
if !errors.Is(err, nil) {
|
|
t.Errorf("received '%v' expected '%v'", err, nil)
|
|
}
|
|
|
|
if request != OneDay {
|
|
t.Errorf("received '%v' expected '%v'", request, OneDay)
|
|
}
|
|
}
|
|
|
|
func TestSetHasDataFromCandles(t *testing.T) {
|
|
t.Parallel()
|
|
ohc := getOneHour()
|
|
localEnd := ohc[len(ohc)-1].Time.Add(OneHour.Duration())
|
|
i, err := CalculateCandleDateRanges(ohc[0].Time, localEnd, OneHour, 100000)
|
|
if !errors.Is(err, nil) {
|
|
t.Errorf("received '%v' expected '%v'", err, nil)
|
|
}
|
|
|
|
err = i.SetHasDataFromCandles(ohc)
|
|
if !errors.Is(err, nil) {
|
|
t.Errorf("received '%v' expected '%v'", err, nil)
|
|
}
|
|
if !i.Start.Equal(ohc[0].Time) {
|
|
t.Errorf("received '%v' expected '%v'", i.Start.Time, ohc[0].Time)
|
|
}
|
|
if !i.End.Equal(localEnd) {
|
|
t.Errorf("received '%v' expected '%v'", i.End.Time, ohc[len(ohc)-1].Time)
|
|
}
|
|
|
|
k := Item{
|
|
Interval: OneHour,
|
|
Candles: ohc[2:],
|
|
}
|
|
err = k.addPadding(i.Start.Time, i.End.Time, false)
|
|
if !errors.Is(err, nil) {
|
|
t.Errorf("received '%v' expected '%v'", err, nil)
|
|
}
|
|
|
|
err = i.SetHasDataFromCandles(k.Candles)
|
|
if !errors.Is(err, nil) {
|
|
t.Errorf("received '%v' expected '%v'", err, nil)
|
|
}
|
|
if !i.Start.Equal(k.Candles[0].Time) {
|
|
t.Errorf("received '%v' expected '%v'", i.Start.Time, k.Candles[0].Time)
|
|
}
|
|
if i.HasDataAtDate(k.Candles[0].Time) {
|
|
t.Errorf("received '%v' expected '%v'", false, true)
|
|
}
|
|
if !i.HasDataAtDate(k.Candles[len(k.Candles)-1].Time) {
|
|
t.Errorf("received '%v' expected '%v'", true, false)
|
|
}
|
|
}
|
|
|
|
func TestGetIntervalResultLimit(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var e *ExchangeCapabilitiesEnabled
|
|
_, err := e.GetIntervalResultLimit(OneMin)
|
|
if !errors.Is(err, errExchangeCapabilitiesEnabledIsNil) {
|
|
t.Errorf("received '%v' expected '%v'", err, errExchangeCapabilitiesEnabledIsNil)
|
|
}
|
|
|
|
e = &ExchangeCapabilitiesEnabled{}
|
|
e.Intervals = ExchangeIntervals{}
|
|
_, err = e.GetIntervalResultLimit(OneDay)
|
|
if !errors.Is(err, errIntervalNotSupported) {
|
|
t.Errorf("received '%v' expected '%v'", err, errIntervalNotSupported)
|
|
}
|
|
|
|
e.Intervals = ExchangeIntervals{
|
|
supported: map[Interval]uint64{
|
|
OneDay: 100000,
|
|
OneMin: 0,
|
|
},
|
|
}
|
|
|
|
_, err = e.GetIntervalResultLimit(OneMin)
|
|
if !errors.Is(err, errCannotFetchIntervalLimit) {
|
|
t.Errorf("received '%v' expected '%v'", err, errCannotFetchIntervalLimit)
|
|
}
|
|
|
|
limit, err := e.GetIntervalResultLimit(OneDay)
|
|
if !errors.Is(err, nil) {
|
|
t.Errorf("received '%v' expected '%v'", err, nil)
|
|
}
|
|
|
|
if limit != 100000 {
|
|
t.Errorf("received '%v' expected '%v'", limit, 100000)
|
|
}
|
|
|
|
e.GlobalResultLimit = 1337
|
|
limit, err = e.GetIntervalResultLimit(OneMin)
|
|
if !errors.Is(err, nil) {
|
|
t.Errorf("received '%v' expected '%v'", err, nil)
|
|
}
|
|
|
|
if limit != 1337 {
|
|
t.Errorf("received '%v' expected '%v'", limit, 1337)
|
|
}
|
|
}
|
|
|
|
func TestUnmarshalJSON(t *testing.T) {
|
|
t.Parallel()
|
|
var i Interval
|
|
for _, tt := range []struct {
|
|
in string
|
|
exp Interval
|
|
}{{`"3m"`, ThreeMin}, {`"15s"`, FifteenSecond}, {`720000000000`, OneMin * 12}, {`"-1ns"`, Raw}, {`"raw"`, Raw}} {
|
|
err := i.UnmarshalJSON([]byte(tt.in))
|
|
assert.NoErrorf(t, err, "UnmarshalJSON should not error on %q", tt.in)
|
|
}
|
|
err := i.UnmarshalJSON([]byte(`"6hedgehogs"`))
|
|
assert.ErrorContains(t, err, "unknown unit", "UnmarshalJSON should error")
|
|
}
|