diff --git a/client.go b/client.go index defbb85..2bd71c4 100644 --- a/client.go +++ b/client.go @@ -9,39 +9,26 @@ import ( "github.com/mrz1836/go-whatsonchain" ) -// httpInterface is used for the http client (mocking heimdall) -type httpInterface interface { +// HTTPInterface is used for the http client (mocking heimdall) +type HTTPInterface interface { Do(req *http.Request) (*http.Response, error) } -// preevInterface is an interface for the Preev Client -type preevInterface interface { - GetPair(ctx context.Context, pairID string) (pair *preev.Pair, err error) - GetPairs(ctx context.Context) (pairList *preev.PairList, err error) - GetTicker(ctx context.Context, pairID string) (ticker *preev.Ticker, err error) - GetTickers(ctx context.Context) (tickerList *preev.TickerList, err error) -} - -// whatsOnChainInterface is an interface for the WOC Client -type whatsOnChainInterface interface { - GetExchangeRate(ctx context.Context) (rate *whatsonchain.ExchangeRate, err error) -} - -// coinPaprikaInterface is an interface for the Coin Paprika Client -type coinPaprikaInterface interface { +// CoinPaprikaInterface is an interface for the Coin Paprika Client +type CoinPaprikaInterface interface { GetBaseAmountAndCurrencyID(currency string, amount float64) (string, float64) + GetHistoricalTickers(ctx context.Context, coinID string, start, end time.Time, limit int, quote tickerQuote, interval tickerInterval) (response *HistoricalResponse, err error) GetMarketPrice(ctx context.Context, coinID string) (response *TickerResponse, err error) GetPriceConversion(ctx context.Context, baseCurrencyID, quoteCurrencyID string, amount float64) (response *PriceConversionResponse, err error) IsAcceptedCurrency(currency string) bool - GetHistoricalTickers(ctx context.Context, coinID string, start, end time.Time, limit int, quote tickerQuote, interval tickerInterval) (response *HistoricalResponse, err error) } // Client is the parent struct that contains the provider clients and list of providers to use type Client struct { - CoinPaprika coinPaprikaInterface // Coin Paprika client - Preev preevInterface // Preev Client - Providers []Provider // List of providers to use (in order for fail-over) - WhatsOnChain whatsOnChainInterface // WhatsOnChain client + coinPaprika CoinPaprikaInterface // Coin Paprika client + preev preev.ClientInterface // Preev Client + providers []Provider // List of providers to use (in order for fail-over) + whatsOnChain whatsonchain.ChainService // WhatsOnChain (chain services) } // ClientOptions holds all the configuration for connection, dialer and transport @@ -120,14 +107,16 @@ func DefaultClientOptions() (clientOptions *ClientOptions) { } // NewClient creates a new client for requests -func NewClient(clientOptions *ClientOptions, customHTTPClient *http.Client, providers ...Provider) (client *Client) { - client = new(Client) +func NewClient(clientOptions *ClientOptions, customHTTPClient HTTPInterface, + providers ...Provider) ClientInterface { + + c := new(Client) // No providers? (Use the default set for now) if len(providers) == 0 { - client.Providers = defaultProviders + c.providers = defaultProviders } else { - client.Providers = providers + c.providers = providers } // Set default options if none are provided @@ -136,13 +125,60 @@ func NewClient(clientOptions *ClientOptions, customHTTPClient *http.Client, prov } // Create a client for Coin Paprika - client.CoinPaprika = createPaprikaClient(clientOptions, customHTTPClient) + c.coinPaprika = createPaprikaClient( + clientOptions, customHTTPClient, + ) // Create a client for Preev - client.Preev = preev.NewClient(clientOptions.ToPreevOptions(), customHTTPClient) + c.preev = preev.NewClient( + clientOptions.ToPreevOptions(), customHTTPClient, + ) // Create a client for WhatsOnChain - client.WhatsOnChain = whatsonchain.NewClient(whatsonchain.NetworkMain, clientOptions.ToWhatsOnChainOptions(), customHTTPClient) + c.whatsOnChain = whatsonchain.NewClient( + whatsonchain.NetworkMain, clientOptions.ToWhatsOnChainOptions(), customHTTPClient, + ) - return + return c +} + +// Providers is the list of providers +func (c *Client) Providers() []Provider { + return c.providers +} + +// CoinPaprika will return the client +func (c *Client) CoinPaprika() CoinPaprikaInterface { + return c.coinPaprika +} + +// SetCoinPaprika will set the client +func (c *Client) SetCoinPaprika(client CoinPaprikaInterface) { + if client != nil { + c.coinPaprika = client + } +} + +// Preev will return the client +func (c *Client) Preev() preev.ClientInterface { + return c.preev +} + +// SetPreev will set the client +func (c *Client) SetPreev(client preev.ClientInterface) { + if client != nil { + c.preev = client + } +} + +// WhatsOnChain will return the client +func (c *Client) WhatsOnChain() whatsonchain.ChainService { + return c.whatsOnChain +} + +// SetWhatsOnChain will set the client +func (c *Client) SetWhatsOnChain(client whatsonchain.ChainService) { + if client != nil { + c.whatsOnChain = client + } } diff --git a/client_test.go b/client_test.go index 0bd7eef..14a989c 100644 --- a/client_test.go +++ b/client_test.go @@ -17,9 +17,9 @@ func TestNewClient(t *testing.T) { assert.NotNil(t, client) // Test default providers - assert.Equal(t, ProviderCoinPaprika, client.Providers[0]) - assert.Equal(t, ProviderWhatsOnChain, client.Providers[1]) - assert.Equal(t, ProviderPreev, client.Providers[2]) + assert.Equal(t, ProviderCoinPaprika, client.Providers()[0]) + assert.Equal(t, ProviderWhatsOnChain, client.Providers()[1]) + assert.Equal(t, ProviderPreev, client.Providers()[2]) }) t.Run("custom http client", func(t *testing.T) { @@ -27,7 +27,7 @@ func TestNewClient(t *testing.T) { assert.NotNil(t, client) // Test custom providers - assert.Equal(t, ProviderPreev, client.Providers[0]) + assert.Equal(t, ProviderPreev, client.Providers()[0]) }) } diff --git a/coinpaprika.go b/coinpaprika.go index 96b3be1..7372b81 100644 --- a/coinpaprika.go +++ b/coinpaprika.go @@ -135,7 +135,7 @@ func (p PriceConversionResponse) GetSatoshi() (satoshi int64, err error) { // PaprikaClient is the client for Coin Paprika type PaprikaClient struct { - HTTPClient httpInterface // carries out the http operations (heimdall client) + HTTPClient HTTPInterface // carries out the http operations (heimdall client) UserAgent string } @@ -148,16 +148,10 @@ type lastRequest struct { } // createPaprikaClient will make a new http client based on the options provided -func createPaprikaClient(options *ClientOptions, customHTTPClient *http.Client) (c *PaprikaClient) { +func createPaprikaClient(options *ClientOptions, customHTTPClient HTTPInterface) CoinPaprikaInterface { // Create a client - c = new(PaprikaClient) - - // Is there a custom HTTP client to use? - if customHTTPClient != nil { - c.HTTPClient = customHTTPClient - return - } + c := new(PaprikaClient) // Set options (either default or user modified) if options == nil { @@ -167,6 +161,12 @@ func createPaprikaClient(options *ClientOptions, customHTTPClient *http.Client) // Set the user agent c.UserAgent = options.UserAgent + // Is there a custom HTTP client to use? + if customHTTPClient != nil { + c.HTTPClient = customHTTPClient + return c + } + // dial is the net dialer for clientDefaultTransport dial := &net.Dialer{KeepAlive: options.DialerKeepAlive, Timeout: options.DialerTimeout} @@ -209,7 +209,7 @@ func createPaprikaClient(options *ClientOptions, customHTTPClient *http.Client) ) } - return + return c } // GetBaseAmountAndCurrencyID will return an ID and default amount diff --git a/coinpaprika_test.go b/coinpaprika_test.go index 1e016b3..99a9d10 100644 --- a/coinpaprika_test.go +++ b/coinpaprika_test.go @@ -114,11 +114,10 @@ func (m *mockHTTPPaprika) Do(req *http.Request) (*http.Response, error) { } // newMockPaprikaClient returns a client for mocking (using a custom HTTP interface) -func newMockPaprikaClient(httpClient httpInterface) *Client { - client := NewClient(nil, nil) - cp := createPaprikaClient(nil, nil) - cp.HTTPClient = httpClient - client.CoinPaprika = cp +func newMockPaprikaClient(httpClient HTTPInterface) ClientInterface { + client := NewClient(nil, httpClient) + // cp := createPaprikaClient(nil, httpClient) + // client.CoinPaprika = cp return client } @@ -195,7 +194,7 @@ func TestPaprikaClient_GetBaseAmountAndCurrencyID(t *testing.T) { } for _, test := range tests { t.Run(test.testCase, func(t *testing.T) { - currencyName, amount := client.CoinPaprika.GetBaseAmountAndCurrencyID(test.currency, test.amount) + currencyName, amount := client.CoinPaprika().GetBaseAmountAndCurrencyID(test.currency, test.amount) assert.Equal(t, test.expectedAmount, amount) assert.Equal(t, test.expectedCurrency, currencyName) }) @@ -245,7 +244,7 @@ func TestPaprikaClient_GetPriceConversion(t *testing.T) { } for _, test := range tests { t.Run(test.testCase, func(t *testing.T) { - output, err := client.CoinPaprika.GetPriceConversion(context.Background(), test.baseCurrency, test.quoteCurrency, test.amount) + output, err := client.CoinPaprika().GetPriceConversion(context.Background(), test.baseCurrency, test.quoteCurrency, test.amount) assert.NoError(t, err) assert.NotNil(t, output) assert.Equal(t, test.expectedPrice, output.Price) @@ -279,7 +278,7 @@ func TestPaprikaClient_GetPriceConversion(t *testing.T) { } for _, test := range tests { t.Run(test.testCase, func(t *testing.T) { - output, err := client.CoinPaprika.GetPriceConversion(context.Background(), test.baseCurrency, test.quoteCurrency, test.amount) + output, err := client.CoinPaprika().GetPriceConversion(context.Background(), test.baseCurrency, test.quoteCurrency, test.amount) assert.Error(t, err) assert.NotNil(t, output) assert.Equal(t, test.expectedStatusCode, output.LastRequest.StatusCode) @@ -311,7 +310,7 @@ func TestPaprikaClient_GetMarketPrice(t *testing.T) { } for _, test := range tests { t.Run(test.testCase, func(t *testing.T) { - output, err := client.CoinPaprika.GetMarketPrice(context.Background(), test.coinID) + output, err := client.CoinPaprika().GetMarketPrice(context.Background(), test.coinID) assert.NoError(t, err) assert.NotNil(t, output) assert.Equal(t, test.expectedPrice, output.Quotes.USD.Price) @@ -339,7 +338,7 @@ func TestPaprikaClient_GetMarketPrice(t *testing.T) { } for _, test := range tests { t.Run(test.testCase, func(t *testing.T) { - output, err := client.CoinPaprika.GetMarketPrice(context.Background(), test.coinID) + output, err := client.CoinPaprika().GetMarketPrice(context.Background(), test.coinID) assert.Error(t, err) assert.NotNil(t, output) assert.Equal(t, test.expectedStatusCode, output.LastRequest.StatusCode) @@ -388,7 +387,7 @@ func TestPaprikaClient_IsAcceptedCurrency(t *testing.T) { } for _, test := range tests { t.Run(test.testCase, func(t *testing.T) { - found := client.CoinPaprika.IsAcceptedCurrency(test.currency) + found := client.CoinPaprika().IsAcceptedCurrency(test.currency) assert.Equal(t, test.expectedFound, found) }) } @@ -476,7 +475,7 @@ func TestPaprikaClient_GetHistoricalTickers(t *testing.T) { } for _, test := range tests { t.Run(test.testCase, func(t *testing.T) { - output, err := client.CoinPaprika.GetHistoricalTickers( + output, err := client.CoinPaprika().GetHistoricalTickers( context.Background(), test.coinID, test.start, test.end, test.limit, test.quote, test.interval, ) assert.NoError(t, err) @@ -489,7 +488,7 @@ func TestPaprikaClient_GetHistoricalTickers(t *testing.T) { }) t.Run("invalid start time", func(t *testing.T) { - output, err := client.CoinPaprika.GetHistoricalTickers( + output, err := client.CoinPaprika().GetHistoricalTickers( context.Background(), CoinPaprikaQuoteID, time.Time{}, time.Time{}, 100, TickerQuoteUSD, TickerInterval1h, ) assert.Error(t, err) @@ -498,7 +497,7 @@ func TestPaprikaClient_GetHistoricalTickers(t *testing.T) { }) t.Run("empty end time, bad start time", func(t *testing.T) { - output, err := client.CoinPaprika.GetHistoricalTickers( + output, err := client.CoinPaprika().GetHistoricalTickers( context.Background(), CoinPaprikaQuoteID, time.Now().UTC().Add(2*time.Hour), time.Time{}, 100, TickerQuoteUSD, TickerInterval1h, ) assert.Error(t, err) @@ -507,7 +506,7 @@ func TestPaprikaClient_GetHistoricalTickers(t *testing.T) { }) t.Run("same times", func(t *testing.T) { - output, err := client.CoinPaprika.GetHistoricalTickers( + output, err := client.CoinPaprika().GetHistoricalTickers( context.Background(), CoinPaprikaQuoteID, time.Date(2021, 1, 1, 1, 1, 1, 1, time.UTC), time.Date(2021, 1, 1, 1, 1, 1, 1, time.UTC), @@ -519,7 +518,7 @@ func TestPaprikaClient_GetHistoricalTickers(t *testing.T) { }) t.Run("over the limit", func(t *testing.T) { - output, err := client.CoinPaprika.GetHistoricalTickers( + output, err := client.CoinPaprika().GetHistoricalTickers( context.Background(), CoinPaprikaQuoteID, time.Date(2021, 1, 1, 1, 1, 1, 1, time.UTC), time.Date(2021, 1, 2, 1, 1, 1, 1, time.UTC), @@ -531,7 +530,7 @@ func TestPaprikaClient_GetHistoricalTickers(t *testing.T) { }) t.Run("no limit set - use default", func(t *testing.T) { - output, err := client.CoinPaprika.GetHistoricalTickers( + output, err := client.CoinPaprika().GetHistoricalTickers( context.Background(), CoinPaprikaQuoteID, time.Date(2021, 1, 1, 1, 1, 1, 1, time.UTC), time.Date(2021, 1, 2, 1, 1, 1, 1, time.UTC), @@ -543,7 +542,7 @@ func TestPaprikaClient_GetHistoricalTickers(t *testing.T) { }) t.Run("invalid ticker", func(t *testing.T) { - output, err := client.CoinPaprika.GetHistoricalTickers( + output, err := client.CoinPaprika().GetHistoricalTickers( context.Background(), "unknown", time.Date(2021, 1, 1, 1, 1, 1, 1, time.UTC), time.Date(2021, 1, 2, 1, 1, 1, 1, time.UTC), @@ -556,7 +555,7 @@ func TestPaprikaClient_GetHistoricalTickers(t *testing.T) { }) t.Run("error response", func(t *testing.T) { - output, err := client.CoinPaprika.GetHistoricalTickers( + output, err := client.CoinPaprika().GetHistoricalTickers( context.Background(), "error", time.Date(2021, 1, 1, 1, 1, 1, 1, time.UTC), time.Date(2021, 1, 2, 1, 1, 1, 1, time.UTC), @@ -572,7 +571,7 @@ func TestPaprikaClient_GetHistoricalTickers(t *testing.T) { client = newMockClient(&mockWOCValid{}, &mockPaprikaFailed{}, &mockPreevValid{}) assert.NotNil(t, client) - resp, rateErr := client.CoinPaprika.GetHistoricalTickers( + resp, rateErr := client.CoinPaprika().GetHistoricalTickers( context.Background(), CoinPaprikaQuoteID, time.Now().UTC().Add(-1*time.Hour), time.Now().UTC(), maxHistoricalLimit+1, TickerQuoteUSD, TickerInterval1h, ) assert.Error(t, rateErr) diff --git a/config.go b/config.go index 4dc3d60..51a98e7 100644 --- a/config.go +++ b/config.go @@ -5,7 +5,7 @@ import "strings" const ( // version is the current package version - version = "v0.1.15" + version = "v0.2.0" // defaultUserAgent is the default user agent for all requests defaultUserAgent string = "go-bsvrates: " + version diff --git a/conversions.go b/conversions.go index 3c258e0..2b578e5 100644 --- a/conversions.go +++ b/conversions.go @@ -20,19 +20,19 @@ func (c *Client) GetConversion(ctx context.Context, currency Currency, amount fl } // Loop providers and get a conversion value - for _, provider := range c.Providers { + for _, provider := range c.Providers() { providerUsed = provider switch provider { case ProviderCoinPaprika: var response *PriceConversionResponse - if response, err = c.CoinPaprika.GetPriceConversion( + if response, err = c.CoinPaprika().GetPriceConversion( ctx, USDCurrencyID, CoinPaprikaQuoteID, amount, ); err == nil && response != nil { satoshis, err = response.GetSatoshi() } case ProviderWhatsOnChain: var response *whatsonchain.ExchangeRate - if response, err = c.WhatsOnChain.GetExchangeRate(ctx); err == nil && response != nil { + if response, err = c.WhatsOnChain().GetExchangeRate(ctx); err == nil && response != nil { var rate float64 if rate, err = strconv.ParseFloat(response.Rate, 64); err == nil { satoshis, err = ConvertPriceToSatoshis(rate, amount) @@ -40,7 +40,7 @@ func (c *Client) GetConversion(ctx context.Context, currency Currency, amount fl } case ProviderPreev: var response *preev.Ticker - if response, err = c.Preev.GetTicker( + if response, err = c.Preev().GetTicker( ctx, PreevTickerID, ); err == nil && response != nil { satoshis, err = ConvertPriceToSatoshis(response.Prices.Ppi.LastPrice, amount) diff --git a/examples/get_historical_tickers/get_historical_tickers.go b/examples/get_historical_tickers/get_historical_tickers.go index 875346e..5f9524c 100644 --- a/examples/get_historical_tickers/get_historical_tickers.go +++ b/examples/get_historical_tickers/get_historical_tickers.go @@ -17,7 +17,7 @@ func main() { client := bsvrates.NewClient(nil, nil) // Get historical tickers - response, err := client.CoinPaprika.GetHistoricalTickers( + response, err := client.CoinPaprika().GetHistoricalTickers( context.Background(), bsvrates.CoinPaprikaQuoteID, time.Now().UTC().Add(-1*24*time.Hour), diff --git a/interface.go b/interface.go new file mode 100644 index 0000000..41bc539 --- /dev/null +++ b/interface.go @@ -0,0 +1,21 @@ +package bsvrates + +import ( + "context" + + "github.com/mrz1836/go-preev" + "github.com/mrz1836/go-whatsonchain" +) + +// ClientInterface is the BSVRate client interface +type ClientInterface interface { + CoinPaprika() CoinPaprikaInterface + GetConversion(ctx context.Context, currency Currency, amount float64) (satoshis int64, providerUsed Provider, err error) + GetRate(ctx context.Context, currency Currency) (rate float64, providerUsed Provider, err error) + Preev() preev.ClientInterface + Providers() []Provider + SetCoinPaprika(client CoinPaprikaInterface) + SetPreev(client preev.ClientInterface) + SetWhatsOnChain(client whatsonchain.ChainService) + WhatsOnChain() whatsonchain.ChainService +} diff --git a/mock_coinpaprika_test.go b/mock_coinpaprika_test.go new file mode 100644 index 0000000..110db5a --- /dev/null +++ b/mock_coinpaprika_test.go @@ -0,0 +1,119 @@ +package bsvrates + +import ( + "context" + "fmt" + "net/http" + "time" +) + +// mockPaprikaBase for mocking requests +type mockPaprikaBase struct{} + +// GetMarketPrice is a mock response +func (m *mockPaprikaBase) GetMarketPrice(_ context.Context, coinID string) (response *TickerResponse, err error) { + return +} + +// GetBaseAmountAndCurrencyID is a mock response +func (m *mockPaprikaBase) GetBaseAmountAndCurrencyID(currency string, _ float64) (string, float64) { + return currency, 0.01 +} + +// GetPriceConversion is a mock response +func (m *mockPaprikaBase) GetPriceConversion(context.Context, string, string, float64) (response *PriceConversionResponse, err error) { + return +} + +// GetHistoricalTickers is a mock response +func (m *mockPaprikaBase) GetHistoricalTickers(context.Context, string, time.Time, time.Time, int, + tickerQuote, tickerInterval) (response *HistoricalResponse, err error) { + return +} + +// IsAcceptedCurrency is a mock response +func (m *mockPaprikaBase) IsAcceptedCurrency(_ string) bool { + return true +} + +// mockPaprikaValid for mocking requests +type mockPaprikaValid struct { + mockPaprikaBase +} + +// GetMarketPrice is a mock response +func (m *mockPaprikaValid) GetMarketPrice(_ context.Context, coinID string) (response *TickerResponse, err error) { + + response = &TickerResponse{ + BetaValue: 1.39789, + CirculatingSupply: 18448838, + ID: coinID, + LastRequest: &lastRequest{ + Method: http.MethodGet, + StatusCode: http.StatusOK, + }, + LastUpdated: "2020-07-01T18:36:56Z", + MaxSupply: 21000000, + Name: "Bitcoin SV", + Quotes: ¤cy{USD: "e{ + Price: 158.49415248, + Volume24h: 719426754.25105, + Volume24hChange24h: -4.48, + MarketCap: 2924031833, + }}, + Rank: 6, + Symbol: "BSV", + TotalSupply: 18448838, + } + + return +} + +// GetPriceConversion is a mock response +func (m *mockPaprikaValid) GetPriceConversion(_ context.Context, baseCurrencyID, quoteCurrencyID string, amount float64) (response *PriceConversionResponse, err error) { + + response = &PriceConversionResponse{ + Amount: amount, + BaseCurrencyID: baseCurrencyID, + BaseCurrencyName: "US Dollars", + BasePriceLastUpdated: "2020-07-01T22:03:14Z", + Price: 0.006331560350007446, + QuoteCurrencyID: quoteCurrencyID, + QuoteCurrencyName: "Bitcoin SV", + QuotePriceLastUpdated: "2020-07-01T22:03:14Z", + } + + return +} + +// mockPaprikaFailed for mocking requests +type mockPaprikaFailed struct { + mockPaprikaBase +} + +// GetMarketPrice is a mock response +func (m *mockPaprikaFailed) GetMarketPrice(_ context.Context, _ string) (response *TickerResponse, err error) { + err = fmt.Errorf("request to paprika fails... 502") + return +} + +// GetBaseAmountAndCurrencyID is a mock response +func (m *mockPaprikaFailed) GetBaseAmountAndCurrencyID(_ string, _ float64) (string, float64) { + return "", 0 +} + +// GetPriceConversion is a mock response +func (m *mockPaprikaFailed) GetPriceConversion(_ context.Context, _, _ string, _ float64) (response *PriceConversionResponse, err error) { + return nil, fmt.Errorf("some error occurred") +} + +// GetHistoricalTickers is a mock response +func (m *mockPaprikaFailed) GetHistoricalTickers(_ context.Context, _ string, _, _ time.Time, _ int, + _ tickerQuote, _ tickerInterval) (response *HistoricalResponse, err error) { + return nil, fmt.Errorf("some error occurred") +} + +// IsAcceptedCurrency is a mock response +func (m *mockPaprikaFailed) IsAcceptedCurrency(_ string) bool { + return false +} diff --git a/mock_preev_test.go b/mock_preev_test.go new file mode 100644 index 0000000..203bb50 --- /dev/null +++ b/mock_preev_test.go @@ -0,0 +1,97 @@ +package bsvrates + +import ( + "context" + "fmt" + + "github.com/mrz1836/go-preev" +) + +// mockPreevValid for mocking requests +type mockPreevBase struct{} + +// GetPair is a mock response +func (m *mockPreevBase) GetPair(context.Context, string) (pair *preev.Pair, err error) { + return +} + +// GetPairs is a mock response +func (m *mockPreevBase) GetPairs(context.Context) (pairList *preev.PairList, err error) { + return +} + +// GetTicker is a mock response +func (m *mockPreevBase) GetTicker(context.Context, string) (ticker *preev.Ticker, err error) { + return +} + +// GetTickerHistory is a mock response +func (m *mockPreevBase) GetTickerHistory(context.Context, string, int64, int64, int64) (tickers []*preev.Ticker, err error) { + return +} + +// GetTickers is a mock response +func (m *mockPreevBase) GetTickers(context.Context) (tickerList *preev.TickerList, err error) { + return +} + +// LastRequest is a mock response +func (m *mockPreevBase) LastRequest() *preev.LastRequest { + return nil +} + +// UserAgent is a mock response +func (m *mockPreevBase) UserAgent() string { + return "default-user-agent" +} + +// mockPreevValid for mocking requests +type mockPreevValid struct { + mockPreevBase +} + +// GetTicker is a mock response +func (m *mockPreevValid) GetTicker(_ context.Context, pairID string) (ticker *preev.Ticker, err error) { + + ticker = &preev.Ticker{ + ID: pairID, + Timestamp: 1593628860, + Tx: &preev.Transaction{ + Hash: "175d87a3656a5d745af9fe9cee6afc0297a83fb317255962c40085eb31f06a4b", + Timestamp: 1593628871, + }, + Prices: &preev.PriceSource{ + Ppi: &preev.Price{ + LastPrice: 159.17, + Volume: 935279, + }, + }, + } + + return +} + +// mockPreevFailed for mocking requests +type mockPreevFailed struct { + mockPreevBase +} + +// GetPair is a mock response +func (m *mockPreevFailed) GetPair(context.Context, string) (pair *preev.Pair, err error) { + return nil, fmt.Errorf("some error occurred") +} + +// GetTicker is a mock response +func (m *mockPreevFailed) GetTicker(_ context.Context, _ string) (ticker *preev.Ticker, err error) { + return nil, fmt.Errorf("some error occurred") +} + +// GetTickers is a mock response +func (m *mockPreevFailed) GetTickers(_ context.Context) (tickerList *preev.TickerList, err error) { + return nil, fmt.Errorf("some error occurred") +} + +// GetPairs is a mock response +func (m *mockPreevFailed) GetPairs(_ context.Context) (pairList *preev.PairList, err error) { + return nil, fmt.Errorf("some error occurred") +} diff --git a/mock_whatsonchain_test.go b/mock_whatsonchain_test.go new file mode 100644 index 0000000..2998f54 --- /dev/null +++ b/mock_whatsonchain_test.go @@ -0,0 +1,52 @@ +package bsvrates + +import ( + "context" + + "github.com/mrz1836/go-whatsonchain" +) + +// mockWOCBase is the base +type mockWOCBase struct{} + +// GetChainInfo is a mock response +func (m *mockWOCBase) GetChainInfo(context.Context) (chainInfo *whatsonchain.ChainInfo, err error) { + return +} + +// GetCirculatingSupply is a mock response +func (m *mockWOCBase) GetCirculatingSupply(context.Context) (supply float64, err error) { + return +} + +// GetExchangeRate is a mock response +func (m *mockWOCBase) GetExchangeRate(context.Context) (rate *whatsonchain.ExchangeRate, err error) { + return +} + +// mockWOCValid for mocking requests +type mockWOCValid struct { + mockWOCBase +} + +// GetExchangeRate is a mock response +func (m *mockWOCValid) GetExchangeRate(_ context.Context) (rate *whatsonchain.ExchangeRate, err error) { + + rate = &whatsonchain.ExchangeRate{ + Rate: "159.01", + Currency: CurrencyToName(CurrencyDollars), + } + + return +} + +// mockWOCFailed for mocking requests +type mockWOCFailed struct { + mockWOCBase +} + +// GetExchangeRate is a mock response +func (m *mockWOCFailed) GetExchangeRate(_ context.Context) (rate *whatsonchain.ExchangeRate, err error) { + + return +} diff --git a/rates.go b/rates.go index 684282b..57337b7 100644 --- a/rates.go +++ b/rates.go @@ -23,22 +23,22 @@ func (c *Client) GetRate(ctx context.Context, currency Currency) (rate float64, } // Loop providers and get a rate - for _, provider := range c.Providers { + for _, provider := range c.Providers() { providerUsed = provider switch provider { case ProviderCoinPaprika: var response *TickerResponse - if response, err = c.CoinPaprika.GetMarketPrice(ctx, CoinPaprikaQuoteID); err == nil && response != nil { + if response, err = c.CoinPaprika().GetMarketPrice(ctx, CoinPaprikaQuoteID); err == nil && response != nil { rate = response.Quotes.USD.Price } case ProviderWhatsOnChain: var response *whatsonchain.ExchangeRate - if response, err = c.WhatsOnChain.GetExchangeRate(ctx); err == nil && response != nil { + if response, err = c.WhatsOnChain().GetExchangeRate(ctx); err == nil && response != nil { rate, err = strconv.ParseFloat(response.Rate, 64) } case ProviderPreev: var response *preev.Ticker - if response, err = c.Preev.GetTicker(ctx, PreevTickerID); err == nil && response != nil { + if response, err = c.Preev().GetTicker(ctx, PreevTickerID); err == nil && response != nil { rate = response.Prices.Ppi.LastPrice } case providerLast: diff --git a/rates_test.go b/rates_test.go index 968e5b2..e89898f 100644 --- a/rates_test.go +++ b/rates_test.go @@ -2,223 +2,20 @@ package bsvrates import ( "context" - "fmt" - "net/http" "testing" - "time" "github.com/mrz1836/go-preev" "github.com/mrz1836/go-whatsonchain" "github.com/stretchr/testify/assert" ) -// mockWOCValid for mocking requests -type mockWOCValid struct{} - -// GetExchangeRate is a mock response -func (m *mockWOCValid) GetExchangeRate(_ context.Context) (rate *whatsonchain.ExchangeRate, err error) { - - rate = &whatsonchain.ExchangeRate{ - Rate: "159.01", - Currency: CurrencyToName(CurrencyDollars), - } - - return -} - -// mockWOCFailed for mocking requests -type mockWOCFailed struct{} - -// GetExchangeRate is a mock response -func (m *mockWOCFailed) GetExchangeRate(_ context.Context) (rate *whatsonchain.ExchangeRate, err error) { - - return -} - -// mockPaprikaValid for mocking requests -type mockPaprikaValid struct{} - -// GetMarketPrice is a mock response -func (m *mockPaprikaValid) GetMarketPrice(_ context.Context, coinID string) (response *TickerResponse, err error) { - - response = &TickerResponse{ - BetaValue: 1.39789, - CirculatingSupply: 18448838, - ID: coinID, - LastRequest: &lastRequest{ - Method: http.MethodGet, - StatusCode: http.StatusOK, - }, - LastUpdated: "2020-07-01T18:36:56Z", - MaxSupply: 21000000, - Name: "Bitcoin SV", - Quotes: ¤cy{USD: "e{ - Price: 158.49415248, - Volume24h: 719426754.25105, - Volume24hChange24h: -4.48, - MarketCap: 2924031833, - }}, - Rank: 6, - Symbol: "BSV", - TotalSupply: 18448838, - } - - return -} - -// GetBaseAmountAndCurrencyID is a mock response -func (m *mockPaprikaValid) GetBaseAmountAndCurrencyID(currency string, _ float64) (string, float64) { - - // This is just a mock request - - return currency, 0.01 -} - -// GetPriceConversion is a mock response -func (m *mockPaprikaValid) GetPriceConversion(_ context.Context, baseCurrencyID, quoteCurrencyID string, amount float64) (response *PriceConversionResponse, err error) { - - response = &PriceConversionResponse{ - Amount: amount, - BaseCurrencyID: baseCurrencyID, - BaseCurrencyName: "US Dollars", - BasePriceLastUpdated: "2020-07-01T22:03:14Z", - Price: 0.006331560350007446, - QuoteCurrencyID: quoteCurrencyID, - QuoteCurrencyName: "Bitcoin SV", - QuotePriceLastUpdated: "2020-07-01T22:03:14Z", - } - - return -} - -// GetHistoricalTickers is a mock response -func (m *mockPaprikaValid) GetHistoricalTickers(_ context.Context, _ string, _, _ time.Time, _ int, - _ tickerQuote, _ tickerInterval) (response *HistoricalResponse, err error) { - - // This is just a mock response - - return -} - -// IsAcceptedCurrency is a mock response -func (m *mockPaprikaValid) IsAcceptedCurrency(_ string) bool { - - // This is just a mock response - - return true -} - -// mockPreevValid for mocking requests -type mockPreevValid struct{} - -// GetTicker is a mock response -func (m *mockPreevValid) GetTicker(_ context.Context, pairID string) (ticker *preev.Ticker, err error) { - - ticker = &preev.Ticker{ - ID: pairID, - Timestamp: 1593628860, - Tx: &preev.Transaction{ - Hash: "175d87a3656a5d745af9fe9cee6afc0297a83fb317255962c40085eb31f06a4b", - Timestamp: 1593628871, - }, - Prices: &preev.PriceSource{ - Ppi: &preev.Price{ - LastPrice: 159.17, - Volume: 935279, - }, - }, - } - - return -} - -// GetPair is a mock response -func (m *mockPreevValid) GetPair(_ context.Context, _ string) (pair *preev.Pair, err error) { - - return -} - -// GetPairs is a mock response -func (m *mockPreevValid) GetPairs(_ context.Context) (pairList *preev.PairList, err error) { - - return -} - -// GetTickers is a mock response -func (m *mockPreevValid) GetTickers(_ context.Context) (tickerList *preev.TickerList, err error) { - - return -} - -// mockPaprikaFailed for mocking requests -type mockPaprikaFailed struct{} - -// GetMarketPrice is a mock response -func (m *mockPaprikaFailed) GetMarketPrice(_ context.Context, _ string) (response *TickerResponse, err error) { - err = fmt.Errorf("request to paprika fails... 502") - return -} - -// GetBaseAmountAndCurrencyID is a mock response -func (m *mockPaprikaFailed) GetBaseAmountAndCurrencyID(_ string, _ float64) (string, float64) { - - return "", 0 -} - -// GetPriceConversion is a mock response -func (m *mockPaprikaFailed) GetPriceConversion(_ context.Context, _, _ string, _ float64) (response *PriceConversionResponse, err error) { - - return nil, fmt.Errorf("some error occurred") -} - -// GetHistoricalTickers is a mock response -func (m *mockPaprikaFailed) GetHistoricalTickers(_ context.Context, _ string, _, _ time.Time, _ int, - _ tickerQuote, _ tickerInterval) (response *HistoricalResponse, err error) { - - // This is just a mock response - - return nil, fmt.Errorf("some error occurred") -} - -// IsAcceptedCurrency is a mock response -func (m *mockPaprikaFailed) IsAcceptedCurrency(_ string) bool { - - return false -} - -// mockPreevFailed for mocking requests -type mockPreevFailed struct{} - -// GetPair is a mock response -func (m *mockPreevFailed) GetPair(_ context.Context, _ string) (pair *preev.Pair, err error) { - - return nil, fmt.Errorf("some error occurred") -} - -// GetTicker is a mock response -func (m *mockPreevFailed) GetTicker(_ context.Context, _ string) (ticker *preev.Ticker, err error) { - - return nil, fmt.Errorf("some error occurred") -} - -// GetTickers is a mock response -func (m *mockPreevFailed) GetTickers(_ context.Context) (tickerList *preev.TickerList, err error) { - - return nil, fmt.Errorf("some error occurred") -} - -// GetPairs is a mock response -func (m *mockPreevFailed) GetPairs(_ context.Context) (pairList *preev.PairList, err error) { - - return nil, fmt.Errorf("some error occurred") -} - // newMockClient returns a client for mocking -func newMockClient(wocClient whatsOnChainInterface, paprikaClient coinPaprikaInterface, preevClient preevInterface, providers ...Provider) *Client { +func newMockClient(wocClient whatsonchain.ChainService, paprikaClient CoinPaprikaInterface, + preevClient preev.ClientInterface, providers ...Provider) ClientInterface { client := NewClient(nil, nil, providers...) - client.WhatsOnChain = wocClient - client.CoinPaprika = paprikaClient - client.Preev = preevClient + client.SetWhatsOnChain(wocClient) + client.SetCoinPaprika(paprikaClient) + client.SetPreev(preevClient) return client }