diff --git a/package.json b/package.json index 5fae3e2..92095fb 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,7 @@ "test": "npm run lint && npm run test-v3", "lint": "standard --env mocha --fix", "test-v3": "export NETWORK=mainnet && nyc --reporter=text mocha --timeout 60000 test/v3/", - "test:temp": "export NETWORK=mainnet && export TEST=integration && mocha --timeout 25000 test/v3/encryption.js", + "test:temp": "export NETWORK=mainnet && export TEST=integration && mocha --timeout 25000 test/v3/integration/price.js", "test:integration": "mocha test/v3/integration", "test:integration:slpdb": "mocha --timeout 25000 -g '#validate2Single' test/v3/integration/slp*.js", "coverage": "nyc report --reporter=text-lcov | coveralls", diff --git a/src/routes/v3/price.js b/src/routes/v3/price.js index 32e5ec5..bf16183 100644 --- a/src/routes/v3/price.js +++ b/src/routes/v3/price.js @@ -24,11 +24,14 @@ class Price { this.routeUtils = routeUtils this.priceUrl = 'https://api.coinbase.com/v2/exchange-rates?currency=BCH' + this.coinexPriceUrl = + 'https://api.coinex.com/v1/market/ticker?market=bchausdt' this.router = express.Router() this.router.get('/', _this.root) this.router.get('/usd', _this.getUSD) this.router.get('/rates', _this.getBCHRate) + this.router.get('/bchausd', _this.getBCHAUSD) } // DRY error handler. @@ -53,7 +56,7 @@ class Price { * @api {get} /price/usd Get the USD price of BCH * @apiName Get the USD price of BCH * @apiGroup Price - * @apiDescription Get the USD price of BCH + * @apiDescription Get the USD price of BCH from Coinbase. * * * @apiExample Example usage: @@ -85,7 +88,7 @@ class Price { * @api {get} /price/usd Get rates for several different currencies * @apiName Get rates for several different currencies * @apiGroup Price - * @apiDescription Get rates for several different currencies + * @apiDescription Get rates for several different currencies from Coinbase. * * * @apiExample Example usage: @@ -113,6 +116,40 @@ class Price { return _this.errorHandler(err, res) } } + + /** + * @api {get} /price/bchausd Get the USD price of BCHA + * @apiName Get the USD price of BCHA + * @apiGroup Price + * @apiDescription Get the USD price of BCHA from Coinex. + * + * + * @apiExample Example usage: + * curl -X GET "https://api.fullstack.cash/v3/price/bchausd" -H "accept: application/json" + * + */ + async getBCHAUSD (req, res, next) { + try { + // Request options + const opt = { + method: 'get', + baseURL: this.coinexPriceUrl, + timeout: 15000 + } + + const response = await axios.request(opt) + // console.log(`response.data: ${JSON.stringify(response.data, null, 2)}`) + + const price = Number(response.data.data.ticker.last) + + return res.json({ usd: price }) + } catch (err) { + // Write out error to error log. + wlogger.error('Error in price.js/getBCHAUSD().', err) + + return _this.errorHandler(err, res) + } + } } module.exports = Price diff --git a/test/v3/integration/price.js b/test/v3/integration/price.js index 33106ad..f15cd36 100644 --- a/test/v3/integration/price.js +++ b/test/v3/integration/price.js @@ -4,7 +4,7 @@ 'use strict' -// const assert = require('chai').assert +const assert = require('chai').assert // const axios = require('axios') // Used for debugging. @@ -29,6 +29,17 @@ describe('#price', () => { it('should get the USD price', async () => { const result = await price.getUSD(req, res) console.log(`result: ${util.inspect(result)}`) + + assert.isNumber(result.usd) + }) + }) + + describe('#getBCHAUSD', () => { + it('should get the USD price of BCHA', async () => { + const result = await price.getBCHAUSD(req, res) + console.log(`result: ${util.inspect(result)}`) + + assert.isNumber(result.usd) }) }) }) diff --git a/test/v3/mocks/price-mock.js b/test/v3/mocks/price-mock.js index 6e3168b..5bf3569 100644 --- a/test/v3/mocks/price-mock.js +++ b/test/v3/mocks/price-mock.js @@ -216,6 +216,26 @@ const mockCoinbaseFeed = { } } -module.exports = { - mockCoinbaseFeed +const mockCoinexFeed = { + code: 0, + data: { + date: 1605649499848, + ticker: { + vol: '26717.39062407', + low: '10.4000', + open: '11.8000', + high: '19.0029', + last: '18.5000', + buy: '18.0100', + buy_amount: '200.00000000', + sell: '18.5000', + sell_amount: '47.89580474' + } + }, + message: 'OK' +} + +module.exports = { + mockCoinbaseFeed, + mockCoinexFeed } diff --git a/test/v3/price.js b/test/v3/price.js index 23dab3e..691b4eb 100644 --- a/test/v3/price.js +++ b/test/v3/price.js @@ -211,4 +211,70 @@ describe('#PriceRouter', () => { assert.property(result, 'error') }) }) + + describe('#getBCHAUSD', () => { + // const getNetworkInfo = controlRoute.testableComponents.getNetworkInfo + + it('should throw 500 when network issues', async () => { + uut.coinexPriceUrl = 'http://fakeurl/api/' + + await uut.getBCHAUSD(req, res) + // console.log(`result: ${util.inspect(result)}`) + + assert.isAbove( + res.statusCode, + 499, + 'HTTP status code 500 or greater expected.' + ) + // console.log(res) + assert.include( + res.output.error, + 'Network error: Could not communicate with full node or other external service' + ) + }) + + it('returns proper error when downstream service stalls', async () => { + // Mock the timeout error. + sandbox.stub(uut.axios, 'request').throws({ code: 'ECONNABORTED' }) + + const result = await uut.getBCHAUSD(req, res) + // console.log(`result: ${JSON.stringify(result, null, 2)}`) + + assert.isAbove(res.statusCode, 499, 'HTTP status code 503 expected.') + assert.include( + result.error, + 'Could not communicate with full node', + 'Error message expected' + ) + }) + + it('returns proper error when downstream service is down', async () => { + // Mock the timeout error. + sandbox.stub(uut.axios, 'request').throws({ code: 'ECONNREFUSED' }) + + const result = await uut.getBCHAUSD(req, res) + // console.log(`result: ${JSON.stringify(result, null, 2)}`) + + assert.isAbove(res.statusCode, 499, 'HTTP status code 503 expected.') + assert.include( + result.error, + 'Could not communicate with full node', + 'Error message expected' + ) + }) + + it('should get the USD price of BCH', async () => { + // Mock the RPC call for unit tests. + if (process.env.TEST === 'unit') { + sandbox + .stub(uut.axios, 'request') + .resolves({ data: mockData.mockCoinexFeed }) + } + + const result = await uut.getBCHAUSD(req, res) + // console.log(`result: ${util.inspect(result)}`) + + assert.isNumber(result.usd) + }) + }) })