mirror of
https://github.com/fullstack-cash/bch-api.git
synced 2026-09-22 01:02:05 -07:00
Forked from rest.bitcoin.com commit 50f5c6ed1bd8d10b72bb8851972446240604eee6 5-3-2019
This commit is contained in:
@@ -0,0 +1,287 @@
|
||||
"use strict"
|
||||
|
||||
//const chai = require("chai");
|
||||
const assert = require("assert")
|
||||
const httpMocks = require("node-mocks-http")
|
||||
const rawTransactionsRoute = require("../../dist/routes/v1/rawtransactions")
|
||||
|
||||
// Used for debugging.
|
||||
const util = require("util")
|
||||
util.inspect.defaultOptions = {
|
||||
showHidden: true,
|
||||
colors: true
|
||||
}
|
||||
|
||||
describe("#RawTransactionsRouter", () => {
|
||||
describe("#root", () => {
|
||||
it("should return 'rawtransactions' for GET /", () => {
|
||||
const mockRequest = httpMocks.createRequest({
|
||||
method: "GET",
|
||||
url: "/"
|
||||
})
|
||||
const mockResponse = httpMocks.createResponse()
|
||||
rawTransactionsRoute(mockRequest, mockResponse)
|
||||
const actualResponseBody = mockResponse._getData()
|
||||
const expectedResponseBody = {
|
||||
status: "rawtransactions"
|
||||
}
|
||||
assert.deepEqual(JSON.parse(actualResponseBody), expectedResponseBody)
|
||||
})
|
||||
})
|
||||
|
||||
describe("#DecodeRawTransaction", () => {
|
||||
it("should GET /decodeRawTransaction/:hex", done => {
|
||||
const mockRequest = httpMocks.createRequest({
|
||||
method: "GET",
|
||||
url:
|
||||
'/decodeRawTransaction/["0200000001d0ba1330194111747e0b1784ab62126871c87acad3b6dc3a339b261ad974e940010000006b483045022100a284b4ac5ed55ac0e2baa02b6bdabbf06f98d2bf6b3fdcea1aea50f55766afd002206181c8e60f738116ba6e16177f3d408e8da2c463c69b27c2531fab84b63a63b24121022d426ef365d6480b127b4980afa4b9415cad5e6f0a9e11b1536d3523597197f3ffffffff02011d0000000000001976a91479d3297d1823149f4ec61df31d19f2fad5390c0288ac0000000000000000116a0f23424348466f7245766572796f6e6500000000"%5D'
|
||||
})
|
||||
const mockResponse = httpMocks.createResponse({
|
||||
eventEmitter: require("events").EventEmitter
|
||||
})
|
||||
rawTransactionsRoute(mockRequest, mockResponse)
|
||||
|
||||
mockResponse.on("end", () => {
|
||||
const actualResponseBody = Object.keys(
|
||||
JSON.parse(mockResponse._getData())[0]
|
||||
)
|
||||
//console.log(`actualResponseBody: ${util.inspect(actualResponseBody)}`)
|
||||
assert.deepEqual(actualResponseBody, [
|
||||
"txid",
|
||||
"hash",
|
||||
"size",
|
||||
"version",
|
||||
"locktime",
|
||||
"vin",
|
||||
"vout"
|
||||
])
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("#DecodeScript", () => {
|
||||
it("should GET /decodeScript/:script", done => {
|
||||
const mockRequest = httpMocks.createRequest({
|
||||
method: "GET",
|
||||
url:
|
||||
'/decodeScript/["4830450221009a51e00ec3524a7389592bc27bea4af5104a59510f5f0cfafa64bbd5c164ca2e02206c2a8bbb47eabdeed52f17d7df668d521600286406930426e3a9415fe10ed592012102e6e1423f7abde8b70bca3e78a7d030e5efabd3eb35c19302542b5fe7879c1a16"%5D'
|
||||
})
|
||||
const mockResponse = httpMocks.createResponse({
|
||||
eventEmitter: require("events").EventEmitter
|
||||
})
|
||||
rawTransactionsRoute(mockRequest, mockResponse)
|
||||
|
||||
mockResponse.on("end", () => {
|
||||
const actualResponseBody = Object.keys(
|
||||
JSON.parse(mockResponse._getData())[0]
|
||||
)
|
||||
assert.deepEqual(actualResponseBody, ["asm", "type", "p2sh"])
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("#GetRawTransaction", () => {
|
||||
it("should GET /getRawTransaction/:txid", done => {
|
||||
const mockRequest = httpMocks.createRequest({
|
||||
method: "GET",
|
||||
url:
|
||||
'/getRawTransaction/["0e3e2357e806b6cdb1f70b54c3a3a17b6714ee1f0e68bebb44a74b1efd512098"%5D'
|
||||
})
|
||||
const mockResponse = httpMocks.createResponse({
|
||||
eventEmitter: require("events").EventEmitter
|
||||
})
|
||||
rawTransactionsRoute(mockRequest, mockResponse)
|
||||
|
||||
mockResponse.on("end", () => {
|
||||
const actualResponseBody = JSON.parse(mockResponse._getData())
|
||||
assert.equal(
|
||||
actualResponseBody,
|
||||
"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0704ffff001d0104ffffffff0100f2052a0100000043410496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52da7589379515d4e0a604f8141781e62294721166bf621e73a82cbf2342c858eeac00000000"
|
||||
)
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("#SendRawTransaction", () => {
|
||||
it("should POST /sendRawTransaction/:hex single tx hex", done => {
|
||||
const mockRequest = httpMocks.createRequest({
|
||||
method: "POST",
|
||||
url:
|
||||
'/sendRawTransaction/["01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0704ffff001d0104ffffffff0100f2052a0100000043410496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52da7589379515d4e0a604f8141781e62294721166bf621e73a82cbf2342c858eeac00000000"%5D'
|
||||
})
|
||||
const mockResponse = httpMocks.createResponse({
|
||||
eventEmitter: require("events").EventEmitter
|
||||
})
|
||||
rawTransactionsRoute(mockRequest, mockResponse)
|
||||
|
||||
mockResponse.on("end", () => {
|
||||
const actualResponseBody = JSON.parse(mockResponse._getData())[0]
|
||||
assert.equal(actualResponseBody, "transaction already in block chain")
|
||||
done()
|
||||
})
|
||||
})
|
||||
//
|
||||
// it("should POST /sendRawTransaction/:hex array", (done) => {
|
||||
// let hex1 = '020000000148735fcdac94c51459f7d8f787cf363c618125bc0f9092092ed2ebccd0f5557e0000000069463043021f4e3dd1fadb3e8fabdbd94b125d7e97932f72bb08118407e49cf505e7f5f63b022062eee3c5d94b4bc6b68ab0018876e9661b257f1e8487173876faccf7d3a2220541210313299e9ec7a9e62789094b850ab6f71df7c39af7c03568027c24d0bc9eda930dffffffff017b140000000000001976a914e11ed7fd6416d8f5c58a1cb3e1b0005c3cab092f88ac00000000';
|
||||
// let hex2 = '0200000001a1b5849a5026642d5e28abdb4e98aa483adc20daab44c39e2f41acf72aa8c845000000006b483045022100994ab28c7df64852057c3ab965148ef2b5456233c12774087e88a62bbc27d4230220504d1096ac52915d32d2356ba5ae82f202543b88c24b4643800919e85da333984121039c48c06ce551810a2eeedf516c77995a922ca65c4e9e9a0a07288a6fae149eb2ffffffff013b1e0000000000001976a9140377597dd75d41398259c36d05a5a68ba0af782d88ac00000000';
|
||||
// let arr = [hex1, hex2];
|
||||
// let mockRequest = httpMocks.createRequest({
|
||||
// method: "POST",
|
||||
// url: '/sendRawTransaction/' + arr
|
||||
// });
|
||||
// let mockResponse = httpMocks.createResponse({
|
||||
// eventEmitter: require('events').EventEmitter
|
||||
// });
|
||||
// rawTransactionsRoute(mockRequest, mockResponse);
|
||||
//
|
||||
// mockResponse.on('end', () => {
|
||||
// let actualResponseBody = mockResponse._getData();
|
||||
// assert.equal(actualResponseBody, 'transaction already in block chain');
|
||||
// done();
|
||||
// });
|
||||
// });
|
||||
})
|
||||
|
||||
/*
|
||||
describe("#change", () => {
|
||||
it("should POST /change/:rawtx/:prevTxs/:destination/:fee", done => {
|
||||
const mockRequest = httpMocks.createRequest({
|
||||
method: "POST",
|
||||
url:
|
||||
'/change/0100000001b15ee60431ef57ec682790dec5a3c0d83a0c360633ea8308fbf6d5fc10a779670400000000ffffffff025c0d00000000000047512102f3e471222bb57a7d416c82bf81c627bfcd2bdc47f36e763ae69935bba4601ece21021580b888ff56feb27f17f08802ebed26258c23697d6a462d43fc13b565fda2dd52aeaa0a0000000000001976a914946cb2e08075bcbaf157e47bcb67eb2b2339d24288ac00000000/[{"txid":"6779a710fcd5f6fb0883ea3306360c3ad8c0a3c5de902768ec57ef3104e65eb1","vout":4,"scriptPubKey":"76a9147b25205fd98d462880a3e5b0541235831ae959e588ac","value":0.00068257}]/bchtest:qq2j9gp97gm9a6lwvhxc4zu28qvqm0x4j5e72v7ejg/0.00003500'
|
||||
})
|
||||
const mockResponse = httpMocks.createResponse({
|
||||
eventEmitter: require("events").EventEmitter
|
||||
})
|
||||
rawTransactionsRoute(mockRequest, mockResponse)
|
||||
|
||||
mockResponse.on("end", () => {
|
||||
const actualResponseBody = JSON.parse(mockResponse._getData())
|
||||
assert.equal(
|
||||
actualResponseBody,
|
||||
"0100000001b15ee60431ef57ec682790dec5a3c0d83a0c360633ea8308fbf6d5fc10a779670400000000ffffffff03efe40000000000001976a9141522a025f2365eebee65cd8a8b8a38180dbcd59588ac5c0d00000000000047512102f3e471222bb57a7d416c82bf81c627bfcd2bdc47f36e763ae69935bba4601ece21021580b888ff56feb27f17f08802ebed26258c23697d6a462d43fc13b565fda2dd52aeaa0a0000000000001976a914946cb2e08075bcbaf157e47bcb67eb2b2339d24288ac00000000"
|
||||
)
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
*/
|
||||
|
||||
describe("#input", () => {
|
||||
it("should POST /input/:rawTx/:txid/:n", done => {
|
||||
const mockRequest = httpMocks.createRequest({
|
||||
method: "POST",
|
||||
url:
|
||||
"/input/01000000000000000000/b006729017df05eda586df9ad3f8ccfee5be340aadf88155b784d1fc0e8342ee/0"
|
||||
})
|
||||
const mockResponse = httpMocks.createResponse({
|
||||
eventEmitter: require("events").EventEmitter
|
||||
})
|
||||
rawTransactionsRoute(mockRequest, mockResponse)
|
||||
|
||||
mockResponse.on("end", () => {
|
||||
const actualResponseBody = JSON.parse(mockResponse._getData())
|
||||
assert.equal(
|
||||
actualResponseBody,
|
||||
"0100000001ee42830efcd184b75581f8ad0a34bee5feccf8d39adf86a5ed05df17907206b00000000000ffffffff0000000000"
|
||||
)
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("#opReturn", () => {
|
||||
it("should POST /opReturn/:rawTx/:payload", done => {
|
||||
const mockRequest = httpMocks.createRequest({
|
||||
method: "POST",
|
||||
url: "/opReturn/01000000000000000000/00000000000000020000000006dac2c0"
|
||||
})
|
||||
const mockResponse = httpMocks.createResponse({
|
||||
eventEmitter: require("events").EventEmitter
|
||||
})
|
||||
rawTransactionsRoute(mockRequest, mockResponse)
|
||||
|
||||
mockResponse.on("end", () => {
|
||||
const actualResponseBody = JSON.parse(mockResponse._getData())
|
||||
assert.equal(
|
||||
actualResponseBody,
|
||||
"0100000000010000000000000000166a140877686300000000000000020000000006dac2c000000000"
|
||||
)
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
/*
|
||||
describe("#reference", () => {
|
||||
it("should POST /reference/:rawTx/:destination", done => {
|
||||
const mockRequest = httpMocks.createRequest({
|
||||
method: "POST",
|
||||
url:
|
||||
"/reference/0100000001a7a9402ecd77f3c9f745793c9ec805bfa2e14b89877581c734c774864247e6f50400000000ffffffff03aa0a0000000000001976a9146d18edfe073d53f84dd491dae1379f8fb0dfe5d488ac5c0d0000000000004751210252ce4bdd3ce38b4ebbc5a6e1343608230da508ff12d23d85b58c964204c4cef3210294cc195fc096f87d0f813a337ae7e5f961b1c8a18f1f8604a909b3a5121f065b52aeaa0a0000000000001976a914946cb2e08075bcbaf157e47bcb67eb2b2339d24288ac00000000/bchtest:qq2j9gp97gm9a6lwvhxc4zu28qvqm0x4j5e72v7ejg?amount=0.005"
|
||||
})
|
||||
const mockResponse = httpMocks.createResponse({
|
||||
eventEmitter: require("events").EventEmitter
|
||||
})
|
||||
rawTransactionsRoute(mockRequest, mockResponse)
|
||||
|
||||
mockResponse.on("end", () => {
|
||||
const actualResponseBody = JSON.parse(mockResponse._getData())
|
||||
assert.equal(
|
||||
actualResponseBody,
|
||||
"0100000001a7a9402ecd77f3c9f745793c9ec805bfa2e14b89877581c734c774864247e6f50400000000ffffffff04aa0a0000000000001976a9146d18edfe073d53f84dd491dae1379f8fb0dfe5d488ac5c0d0000000000004751210252ce4bdd3ce38b4ebbc5a6e1343608230da508ff12d23d85b58c964204c4cef3210294cc195fc096f87d0f813a337ae7e5f961b1c8a18f1f8604a909b3a5121f065b52aeaa0a0000000000001976a914946cb2e08075bcbaf157e47bcb67eb2b2339d24288ac20a10700000000001976a9141522a025f2365eebee65cd8a8b8a38180dbcd59588ac00000000"
|
||||
)
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
*/
|
||||
|
||||
/*
|
||||
describe("#decodeTransaction", () => {
|
||||
it("should POST /decodeTransaction/:rawTx", done => {
|
||||
const mockRequest = httpMocks.createRequest({
|
||||
method: "POST",
|
||||
url:
|
||||
'/decodeTransaction/010000000163af14ce6d477e1c793507e32a5b7696288fa89705c0d02a3f66beb3c5b8afee0100000000ffffffff02ac020000000000004751210261ea979f6a06f9dafe00fb1263ea0aca959875a7073556a088cdfadcd494b3752102a3fd0a8a067e06941e066f78d930bfc47746f097fcd3f7ab27db8ddf37168b6b52ae22020000000000001976a914946cb2e08075bcbaf157e47bcb67eb2b2339d24288ac00000000?prevTxs=[{"txid":"eeafb8c5b3be663f2ad0c00597a88f2896765b2ae30735791c7e476dce14af63","vout":1,"scriptPubKey":"76a9149084c0bd89289bc025d0264f7f23148fb683d56c88ac","value":0.0001123}]'
|
||||
})
|
||||
const mockResponse = httpMocks.createResponse({
|
||||
eventEmitter: require("events").EventEmitter
|
||||
})
|
||||
rawTransactionsRoute(mockRequest, mockResponse)
|
||||
|
||||
mockResponse.on("end", () => {
|
||||
const actualResponseBody = mockResponse._getData()
|
||||
assert.equal(actualResponseBody, "Not a Master Protocol transaction")
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
*/
|
||||
|
||||
describe("#create", () => {
|
||||
it("should POST /create/:inputs/:outputs", done => {
|
||||
const mockRequest = httpMocks.createRequest({
|
||||
method: "POST",
|
||||
url:
|
||||
'/create/ [{"txid":"eeafb8c5b3be663f2ad0c00597a88f2896765b2ae30735791c7e476dce14af63","vout":1}]/{}'
|
||||
})
|
||||
const mockResponse = httpMocks.createResponse({
|
||||
eventEmitter: require("events").EventEmitter
|
||||
})
|
||||
rawTransactionsRoute(mockRequest, mockResponse)
|
||||
|
||||
mockResponse.on("end", () => {
|
||||
const actualResponseBody = JSON.parse(mockResponse._getData())
|
||||
assert.equal(
|
||||
actualResponseBody,
|
||||
"020000000163af14ce6d477e1c793507e32a5b7696288fa89705c0d02a3f66beb3c5b8afee0100000000ffffffff0000000000"
|
||||
)
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,203 @@
|
||||
"use strict"
|
||||
|
||||
//const chai = require("chai");
|
||||
const assert = require("assert")
|
||||
const httpMocks = require("node-mocks-http")
|
||||
const addressRoute = require("../../dist/routes/v1/address")
|
||||
|
||||
const util = require("util")
|
||||
util.inspect.defaultOptions = {
|
||||
showHidden: true,
|
||||
colors: true
|
||||
}
|
||||
|
||||
describe("#AddressRouter", () => {
|
||||
describe("#root", () => {
|
||||
it("should return 'address' for GET /", () => {
|
||||
const mockRequest = httpMocks.createRequest({
|
||||
method: "GET",
|
||||
url: "/"
|
||||
})
|
||||
const mockResponse = httpMocks.createResponse()
|
||||
addressRoute(mockRequest, mockResponse)
|
||||
const actualResponseBody = mockResponse._getData()
|
||||
const expectedResponseBody = {
|
||||
status: "address"
|
||||
}
|
||||
assert.deepEqual(JSON.parse(actualResponseBody), expectedResponseBody)
|
||||
})
|
||||
})
|
||||
|
||||
describe("#AddressDetails", () => {
|
||||
it("should GET /details/:address single address", done => {
|
||||
const mockRequest = httpMocks.createRequest({
|
||||
method: "GET",
|
||||
url: '/details/["qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c"%5D'
|
||||
})
|
||||
const mockResponse = httpMocks.createResponse({
|
||||
eventEmitter: require("events").EventEmitter
|
||||
})
|
||||
addressRoute(mockRequest, mockResponse)
|
||||
|
||||
mockResponse.on("end", () => {
|
||||
const actualResponseBody = Object.keys(
|
||||
JSON.parse(mockResponse._getData())[0]
|
||||
)
|
||||
assert.deepEqual(actualResponseBody, [
|
||||
"balance",
|
||||
"balanceSat",
|
||||
"totalReceived",
|
||||
"totalReceivedSat",
|
||||
"totalSent",
|
||||
"totalSentSat",
|
||||
"unconfirmedBalance",
|
||||
"unconfirmedBalanceSat",
|
||||
"unconfirmedTxAppearances",
|
||||
"txAppearances",
|
||||
"transactions",
|
||||
"legacyAddress",
|
||||
"cashAddress"
|
||||
])
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
it("should GET /details/:address array of addresses", done => {
|
||||
const mockRequest = httpMocks.createRequest({
|
||||
method: "GET",
|
||||
url:
|
||||
'/details/["qql6r7khtjgwy3ufnjtsczvaf925hyw49cudht57tr", "qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c"%5D'
|
||||
})
|
||||
const mockResponse = httpMocks.createResponse({
|
||||
eventEmitter: require("events").EventEmitter
|
||||
})
|
||||
addressRoute(mockRequest, mockResponse)
|
||||
|
||||
mockResponse.on("end", () => {
|
||||
const actualResponseBody = Object.keys(
|
||||
JSON.parse(mockResponse._getData())[0]
|
||||
)
|
||||
assert.deepEqual(actualResponseBody, [
|
||||
"balance",
|
||||
"balanceSat",
|
||||
"totalReceived",
|
||||
"totalReceivedSat",
|
||||
"totalSent",
|
||||
"totalSentSat",
|
||||
"unconfirmedBalance",
|
||||
"unconfirmedBalanceSat",
|
||||
"unconfirmedTxAppearances",
|
||||
"txAppearances",
|
||||
"transactions",
|
||||
"legacyAddress",
|
||||
"cashAddress"
|
||||
])
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("#AddressUtxo", () => {
|
||||
it("should GET /utxo/:address single address", done => {
|
||||
const mockRequest = httpMocks.createRequest({
|
||||
method: "GET",
|
||||
url: '/utxo/["qpk4hk3wuxe2uqtqc97n8atzrrr6r5mleczf9sur4h"%5D'
|
||||
})
|
||||
const mockResponse = httpMocks.createResponse({
|
||||
eventEmitter: require("events").EventEmitter
|
||||
})
|
||||
addressRoute(mockRequest, mockResponse)
|
||||
|
||||
mockResponse.on("end", () => {
|
||||
const actualResponseBody = Object.keys(
|
||||
JSON.parse(mockResponse._getData())[0][0]
|
||||
)
|
||||
assert.deepEqual(actualResponseBody, [
|
||||
"txid",
|
||||
"vout",
|
||||
"scriptPubKey",
|
||||
"amount",
|
||||
"satoshis",
|
||||
"height",
|
||||
"confirmations",
|
||||
"legacyAddress",
|
||||
"cashAddress"
|
||||
])
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
it("should GET /utxo/:address array of addresses", done => {
|
||||
const mockRequest = httpMocks.createRequest({
|
||||
method: "GET",
|
||||
url:
|
||||
'/utxo/["qz4q7h2jxmfhg3l7r7zeumzgeh7gyp6shuqmq5h6np", "qzqlp044n3qn7kntlc0mr5tp2a0ee0vvyq9yyyyjh0"%5D'
|
||||
})
|
||||
const mockResponse = httpMocks.createResponse({
|
||||
eventEmitter: require("events").EventEmitter
|
||||
})
|
||||
addressRoute(mockRequest, mockResponse)
|
||||
|
||||
mockResponse.on("end", () => {
|
||||
const actualResponseBody = Object.keys(
|
||||
JSON.parse(mockResponse._getData())[1][0]
|
||||
)
|
||||
assert.deepEqual(actualResponseBody, [
|
||||
"txid",
|
||||
"vout",
|
||||
"scriptPubKey",
|
||||
"amount",
|
||||
"satoshis",
|
||||
"height",
|
||||
"confirmations",
|
||||
"legacyAddress",
|
||||
"cashAddress"
|
||||
])
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("#AddressUnconfirmed", () => {
|
||||
it("should GET /unconfirmed/:address single address", done => {
|
||||
const mockRequest = httpMocks.createRequest({
|
||||
method: "GET",
|
||||
url: '/unconfirmed/["qql6r7khtjgwy3ufnjtsczvaf925hyw49cudht57tr"%5D'
|
||||
})
|
||||
const mockResponse = httpMocks.createResponse({
|
||||
eventEmitter: require("events").EventEmitter
|
||||
})
|
||||
addressRoute(mockRequest, mockResponse)
|
||||
|
||||
mockResponse.on("end", () => {
|
||||
const actualResponseBody = Object.keys(
|
||||
JSON.parse(mockResponse._getData())[0]
|
||||
)
|
||||
assert.deepEqual(actualResponseBody, [])
|
||||
// assert.deepEqual(actualResponseBody, [ 'txid', 'vout', 'scriptPubKey', 'amount', 'satoshis', 'height', 'confirmations', 'legacyAddress', 'cashAddress']);
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
it("should GET /unconfirmed/:address array of addresses", done => {
|
||||
const mockRequest = httpMocks.createRequest({
|
||||
method: "GET",
|
||||
url:
|
||||
'/unconfirmed/["qql6r7khtjgwy3ufnjtsczvaf925hyw49cudht57tr", "qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c"%5D'
|
||||
})
|
||||
const mockResponse = httpMocks.createResponse({
|
||||
eventEmitter: require("events").EventEmitter
|
||||
})
|
||||
addressRoute(mockRequest, mockResponse)
|
||||
|
||||
mockResponse.on("end", () => {
|
||||
const actualResponseBody = Object.keys(
|
||||
JSON.parse(mockResponse._getData())[0]
|
||||
)
|
||||
assert.deepEqual(actualResponseBody, [])
|
||||
// assert.deepEqual(actualResponseBody, [ 'txid', 'vout', 'scriptPubKey', 'amount', 'satoshis', 'height', 'confirmations', 'legacyAddress', 'cashAddress']);
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,101 @@
|
||||
"use strict"
|
||||
|
||||
//const chai = require("chai");
|
||||
const assert = require("assert")
|
||||
const httpMocks = require("node-mocks-http")
|
||||
const blockRoute = require("../../dist/routes/v1/block")
|
||||
|
||||
describe("#BlockRouter", () => {
|
||||
describe("#root", () => {
|
||||
it("should return 'block' for GET /", () => {
|
||||
const mockRequest = httpMocks.createRequest({
|
||||
method: "GET",
|
||||
url: "/"
|
||||
})
|
||||
const mockResponse = httpMocks.createResponse()
|
||||
blockRoute(mockRequest, mockResponse)
|
||||
const actualResponseBody = mockResponse._getData()
|
||||
const expectedResponseBody = {
|
||||
status: "block"
|
||||
}
|
||||
assert.deepEqual(JSON.parse(actualResponseBody), expectedResponseBody)
|
||||
})
|
||||
})
|
||||
|
||||
describe("#BlockDetails", () => {
|
||||
it("should GET /details/:id height", done => {
|
||||
const mockRequest = httpMocks.createRequest({
|
||||
method: "GET",
|
||||
url: "/details/549608"
|
||||
})
|
||||
const mockResponse = httpMocks.createResponse({
|
||||
eventEmitter: require("events").EventEmitter
|
||||
})
|
||||
blockRoute(mockRequest, mockResponse)
|
||||
mockResponse.on("end", () => {
|
||||
const actualResponseBody = Object.keys(
|
||||
JSON.parse(mockResponse._getData())
|
||||
)
|
||||
|
||||
assert.deepEqual(actualResponseBody, [
|
||||
"hash",
|
||||
"size",
|
||||
"height",
|
||||
"version",
|
||||
"merkleroot",
|
||||
"tx",
|
||||
"time",
|
||||
"nonce",
|
||||
"bits",
|
||||
"difficulty",
|
||||
"chainwork",
|
||||
"confirmations",
|
||||
"previousblockhash",
|
||||
"nextblockhash",
|
||||
"reward",
|
||||
"isMainChain",
|
||||
"poolInfo"
|
||||
])
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
it("should GET /details/:id hash", done => {
|
||||
const mockRequest = httpMocks.createRequest({
|
||||
method: "GET",
|
||||
url:
|
||||
"/details/00000000000000000182bf5782f3d43b1a8fceccb50253eb61e58cba7b240edc"
|
||||
})
|
||||
const mockResponse = httpMocks.createResponse({
|
||||
eventEmitter: require("events").EventEmitter
|
||||
})
|
||||
blockRoute(mockRequest, mockResponse)
|
||||
|
||||
mockResponse.on("end", () => {
|
||||
const actualResponseBody = Object.keys(
|
||||
JSON.parse(mockResponse._getData())
|
||||
)
|
||||
assert.deepEqual(actualResponseBody, [
|
||||
"hash",
|
||||
"size",
|
||||
"height",
|
||||
"version",
|
||||
"merkleroot",
|
||||
"tx",
|
||||
"time",
|
||||
"nonce",
|
||||
"bits",
|
||||
"difficulty",
|
||||
"chainwork",
|
||||
"confirmations",
|
||||
"previousblockhash",
|
||||
"nextblockhash",
|
||||
"reward",
|
||||
"isMainChain",
|
||||
"poolInfo"
|
||||
])
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,593 @@
|
||||
"use strict"
|
||||
|
||||
//const chai = require("chai");
|
||||
const assert = require("assert")
|
||||
const httpMocks = require("node-mocks-http")
|
||||
const blockchainRoute = require("../../dist/routes/v1/blockchain")
|
||||
|
||||
describe("#BlockchainRouter", () => {
|
||||
describe("#root", () => {
|
||||
it("should return 'blockchain' for GET /", () => {
|
||||
const mockRequest = httpMocks.createRequest({
|
||||
method: "GET",
|
||||
url: "/"
|
||||
})
|
||||
const mockResponse = httpMocks.createResponse()
|
||||
blockchainRoute(mockRequest, mockResponse)
|
||||
const actualResponseBody = mockResponse._getData()
|
||||
const expectedResponseBody = {
|
||||
status: "blockchain"
|
||||
}
|
||||
assert.deepEqual(JSON.parse(actualResponseBody), expectedResponseBody)
|
||||
})
|
||||
})
|
||||
|
||||
describe("#BlockchainGetBestBlockHash", () => {
|
||||
it("should GET /getBestBlockHash ", done => {
|
||||
const mockRequest = httpMocks.createRequest({
|
||||
method: "GET",
|
||||
url: "/getBestBlockHash"
|
||||
})
|
||||
const mockResponse = httpMocks.createResponse({
|
||||
eventEmitter: require("events").EventEmitter
|
||||
})
|
||||
blockchainRoute(mockRequest, mockResponse)
|
||||
|
||||
mockResponse.on("end", () => {
|
||||
const actualResponseBody = JSON.parse(mockResponse._getData())
|
||||
assert.equal(actualResponseBody.length, 64)
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("#BlockchainGetBlock", () => {
|
||||
it("should GET /getBlock/:id w/ verbose=true", done => {
|
||||
const mockRequest = httpMocks.createRequest({
|
||||
method: "GET",
|
||||
url:
|
||||
"/getblock/00000000000000000182bf5782f3d43b1a8fceccb50253eb61e58cba7b240edc?verbose=true"
|
||||
})
|
||||
const mockResponse = httpMocks.createResponse({
|
||||
eventEmitter: require("events").EventEmitter
|
||||
})
|
||||
blockchainRoute(mockRequest, mockResponse)
|
||||
|
||||
mockResponse.on("end", () => {
|
||||
const actualResponseBody = Object.keys(
|
||||
JSON.parse(mockResponse._getData())
|
||||
)
|
||||
assert.deepEqual(actualResponseBody, [
|
||||
"hash",
|
||||
"confirmations",
|
||||
"size",
|
||||
"height",
|
||||
"version",
|
||||
"versionHex",
|
||||
"merkleroot",
|
||||
"tx",
|
||||
"time",
|
||||
"mediantime",
|
||||
"nonce",
|
||||
"bits",
|
||||
"difficulty",
|
||||
"chainwork",
|
||||
"previousblockhash",
|
||||
"nextblockhash"
|
||||
])
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
it("should GET /getBlock/:id w/ verbose=false", done => {
|
||||
const mockRequest = httpMocks.createRequest({
|
||||
method: "GET",
|
||||
url:
|
||||
"/getblock/00000000000000000182bf5782f3d43b1a8fceccb50253eb61e58cba7b240edc?verbose=false"
|
||||
})
|
||||
const mockResponse = httpMocks.createResponse({
|
||||
eventEmitter: require("events").EventEmitter
|
||||
})
|
||||
blockchainRoute(mockRequest, mockResponse)
|
||||
|
||||
mockResponse.on("end", () => {
|
||||
const actualResponseBody = mockResponse._getData()
|
||||
assert.equal(actualResponseBody.length, 34638)
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
// TODO - Why is this test failing?
|
||||
// describe("#BlockchainGetBlockchainInfo", () => {
|
||||
// it("should GET /getBlockchainInfo ", done => {
|
||||
// const mockRequest = httpMocks.createRequest({
|
||||
// method: "GET",
|
||||
// url: "/getBlockchainInfo"
|
||||
// })
|
||||
// const mockResponse = httpMocks.createResponse({
|
||||
// eventEmitter: require("events").EventEmitter
|
||||
// })
|
||||
// blockchainRoute(mockRequest, mockResponse)
|
||||
//
|
||||
// mockResponse.on("end", () => {
|
||||
// const actualResponseBody = Object.keys(
|
||||
// JSON.parse(mockResponse._getData())
|
||||
// )
|
||||
// assert.deepEqual(actualResponseBody, [
|
||||
// "chain",
|
||||
// "blocks",
|
||||
// "headers",
|
||||
// "bestblockhash",
|
||||
// "difficulty",
|
||||
// "mediantime",
|
||||
// "verificationprogress",
|
||||
// "chainwork",
|
||||
// "pruned",
|
||||
// "softforks",
|
||||
// "bip9_softforks"
|
||||
// ])
|
||||
// done()
|
||||
// })
|
||||
// })
|
||||
// })
|
||||
|
||||
describe("#BlockchainGetBlockCount", () => {
|
||||
it("should GET /getBlockCount ", done => {
|
||||
const mockRequest = httpMocks.createRequest({
|
||||
method: "GET",
|
||||
url: "/getBlockCount"
|
||||
})
|
||||
const mockResponse = httpMocks.createResponse({
|
||||
eventEmitter: require("events").EventEmitter
|
||||
})
|
||||
blockchainRoute(mockRequest, mockResponse)
|
||||
|
||||
mockResponse.on("end", () => {
|
||||
const actualResponseBody = parseInt(mockResponse._getData())
|
||||
assert.equal(typeof actualResponseBody, "number")
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("#BlockchainGetBlockHash", () => {
|
||||
it("should GET /getBlockHash/:height ", done => {
|
||||
const mockRequest = httpMocks.createRequest({
|
||||
method: "GET",
|
||||
url: "/getBlockhash/[0, 1, 2, 3, 532646]"
|
||||
})
|
||||
const mockResponse = httpMocks.createResponse({
|
||||
eventEmitter: require("events").EventEmitter
|
||||
})
|
||||
blockchainRoute(mockRequest, mockResponse)
|
||||
|
||||
mockResponse.on("end", () => {
|
||||
const actualResponseBody = JSON.parse(mockResponse._getData())[0]
|
||||
assert.equal(
|
||||
actualResponseBody,
|
||||
"000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"
|
||||
)
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("#BlockchainGetBlockHeader", () => {
|
||||
it("should GET /getBlockHeader/:hash w/ verbose=true", done => {
|
||||
const mockRequest = httpMocks.createRequest({
|
||||
method: "GET",
|
||||
url:
|
||||
'/getBlockHeader/["00000000000000000182bf5782f3d43b1a8fceccb50253eb61e58cba7b240edc"%5D?verbose=true'
|
||||
})
|
||||
const mockResponse = httpMocks.createResponse({
|
||||
eventEmitter: require("events").EventEmitter
|
||||
})
|
||||
blockchainRoute(mockRequest, mockResponse)
|
||||
|
||||
mockResponse.on("end", () => {
|
||||
const actualResponseBody = Object.keys(
|
||||
JSON.parse(mockResponse._getData())[0]
|
||||
)
|
||||
assert.deepEqual(actualResponseBody, [
|
||||
"hash",
|
||||
"confirmations",
|
||||
"height",
|
||||
"version",
|
||||
"versionHex",
|
||||
"merkleroot",
|
||||
"time",
|
||||
"mediantime",
|
||||
"nonce",
|
||||
"bits",
|
||||
"difficulty",
|
||||
"chainwork",
|
||||
"previousblockhash",
|
||||
"nextblockhash"
|
||||
])
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
it("should GET /getBlockHeader/:hash w/ verbose=false", done => {
|
||||
const mockRequest = httpMocks.createRequest({
|
||||
method: "GET",
|
||||
url:
|
||||
'/getBlockHeader/00000000000000000182bf5782f3d43b1a8fceccb50253eb61e58cba7b240edc"%5D?verbose=false'
|
||||
})
|
||||
const mockResponse = httpMocks.createResponse({
|
||||
eventEmitter: require("events").EventEmitter
|
||||
})
|
||||
blockchainRoute(mockRequest, mockResponse)
|
||||
|
||||
mockResponse.on("end", () => {
|
||||
const actualResponseBody = JSON.parse(mockResponse._getData())
|
||||
assert.deepEqual(actualResponseBody.length, 160)
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("#BlockchainGetChainTips", () => {
|
||||
it("should GET /getChainTips ", done => {
|
||||
const mockRequest = httpMocks.createRequest({
|
||||
method: "GET",
|
||||
url: "/getChainTips"
|
||||
})
|
||||
const mockResponse = httpMocks.createResponse({
|
||||
eventEmitter: require("events").EventEmitter
|
||||
})
|
||||
blockchainRoute(mockRequest, mockResponse)
|
||||
|
||||
mockResponse.on("end", () => {
|
||||
const actualResponseBody = Object.keys(
|
||||
JSON.parse(mockResponse._getData())[0]
|
||||
)
|
||||
assert.deepEqual(actualResponseBody, [
|
||||
"height",
|
||||
"hash",
|
||||
"branchlen",
|
||||
"status"
|
||||
])
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("#BlockchainGetDifficulty", () => {
|
||||
it("should GET /getDifficulty ", done => {
|
||||
const mockRequest = httpMocks.createRequest({
|
||||
method: "GET",
|
||||
url: "/getDifficulty"
|
||||
})
|
||||
const mockResponse = httpMocks.createResponse({
|
||||
eventEmitter: require("events").EventEmitter
|
||||
})
|
||||
blockchainRoute(mockRequest, mockResponse)
|
||||
|
||||
mockResponse.on("end", () => {
|
||||
const actualResponseBody = parseFloat(mockResponse._getData())
|
||||
assert.equal(typeof actualResponseBody, "number")
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("#BlockchainGetMempoolAncestors", () => {
|
||||
it("should GET /getMempoolAncestors/:txid w/ verbose=true", done => {
|
||||
const mockRequest = httpMocks.createRequest({
|
||||
method: "GET",
|
||||
url:
|
||||
'/getMempoolAncestors/["53735a4ddb828825d6e3f52d045f4c151b2b3d51d631bc581e62f31184b151d6"%5D?verbose=true'
|
||||
})
|
||||
const mockResponse = httpMocks.createResponse({
|
||||
eventEmitter: require("events").EventEmitter
|
||||
})
|
||||
blockchainRoute(mockRequest, mockResponse)
|
||||
|
||||
mockResponse.on("end", () => {
|
||||
const actualResponseBody = JSON.parse(mockResponse._getData())[0]
|
||||
assert.equal(actualResponseBody, "Transaction not in mempool")
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
it("should GET /getMempoolAncestors/:txid w/ verbose=false", done => {
|
||||
const mockRequest = httpMocks.createRequest({
|
||||
method: "GET",
|
||||
url:
|
||||
'/getMempoolAncestors/["53735a4ddb828825d6e3f52d045f4c151b2b3d51d631bc581e62f31184b151d6"%5D?verbose=false'
|
||||
})
|
||||
const mockResponse = httpMocks.createResponse({
|
||||
eventEmitter: require("events").EventEmitter
|
||||
})
|
||||
blockchainRoute(mockRequest, mockResponse)
|
||||
|
||||
mockResponse.on("end", () => {
|
||||
const actualResponseBody = JSON.parse(mockResponse._getData())[0]
|
||||
assert.equal(actualResponseBody, "Transaction not in mempool")
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("#BlockchainGetMempoolDescendants", () => {
|
||||
it("should GET /getMempoolDescendants/:txid w/ verbose=true", done => {
|
||||
const mockRequest = httpMocks.createRequest({
|
||||
method: "GET",
|
||||
url:
|
||||
'/getMempoolDescendants/["53735a4ddb828825d6e3f52d045f4c151b2b3d51d631bc581e62f31184b151d6"%5D?verbose=true'
|
||||
})
|
||||
const mockResponse = httpMocks.createResponse({
|
||||
eventEmitter: require("events").EventEmitter
|
||||
})
|
||||
blockchainRoute(mockRequest, mockResponse)
|
||||
|
||||
mockResponse.on("end", () => {
|
||||
const actualResponseBody = JSON.parse(mockResponse._getData())[0]
|
||||
assert.equal(actualResponseBody, "Transaction not in mempool")
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
it("should GET /getMempoolDescendants/:txid w/ verbose=false", done => {
|
||||
const mockRequest = httpMocks.createRequest({
|
||||
method: "GET",
|
||||
url:
|
||||
'/getMempoolDescendants/["53735a4ddb828825d6e3f52d045f4c151b2b3d51d631bc581e62f31184b151d6"%5D?verbose=false'
|
||||
})
|
||||
const mockResponse = httpMocks.createResponse({
|
||||
eventEmitter: require("events").EventEmitter
|
||||
})
|
||||
blockchainRoute(mockRequest, mockResponse)
|
||||
|
||||
mockResponse.on("end", () => {
|
||||
const actualResponseBody = JSON.parse(mockResponse._getData())[0]
|
||||
assert.equal(actualResponseBody, "Transaction not in mempool")
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("#BlockchainGetMempoolEntry", () => {
|
||||
it("should GET /getMempoolEntry/:txid ", done => {
|
||||
const mockRequest = httpMocks.createRequest({
|
||||
method: "GET",
|
||||
url:
|
||||
'/getMempoolEntry/["53735a4ddb828825d6e3f52d045f4c151b2b3d51d631bc581e62f31184b151d6"%5D'
|
||||
})
|
||||
const mockResponse = httpMocks.createResponse({
|
||||
eventEmitter: require("events").EventEmitter
|
||||
})
|
||||
blockchainRoute(mockRequest, mockResponse)
|
||||
|
||||
mockResponse.on("end", () => {
|
||||
const actualResponseBody = JSON.parse(mockResponse._getData())[0]
|
||||
// TODO: create a tx send it to mempool. Then spend the utxo in another tx and call that enpoind w/ the 2nd txid.
|
||||
assert.equal(actualResponseBody, "Transaction not in mempool")
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("#BlockchainGetMempoolInfo", () => {
|
||||
it("should GET /getMempoolInfo ", done => {
|
||||
const mockRequest = httpMocks.createRequest({
|
||||
method: "GET",
|
||||
url: "/getMempoolInfo"
|
||||
})
|
||||
const mockResponse = httpMocks.createResponse({
|
||||
eventEmitter: require("events").EventEmitter
|
||||
})
|
||||
blockchainRoute(mockRequest, mockResponse)
|
||||
|
||||
mockResponse.on("end", () => {
|
||||
const actualResponseBody = Object.keys(
|
||||
JSON.parse(mockResponse._getData())
|
||||
)
|
||||
assert.deepEqual(actualResponseBody, [
|
||||
"size",
|
||||
"bytes",
|
||||
"usage",
|
||||
"maxmempool",
|
||||
"mempoolminfee"
|
||||
])
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("#BlockchainGetRawMempool", () => {
|
||||
it("should GET /getRawMempool w/ verbose=true", done => {
|
||||
const mockRequest = httpMocks.createRequest({
|
||||
method: "GET",
|
||||
url: "/getRawMempool?verbose=true"
|
||||
})
|
||||
const mockResponse = httpMocks.createResponse({
|
||||
eventEmitter: require("events").EventEmitter
|
||||
})
|
||||
blockchainRoute(mockRequest, mockResponse)
|
||||
|
||||
mockResponse.on("end", () => {
|
||||
const actualResponseBody = Object.keys(
|
||||
JSON.parse(mockResponse._getData())
|
||||
)
|
||||
assert(actualResponseBody.length > 1)
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
it("should GET /getRawMempool w/ verbose=false", done => {
|
||||
const mockRequest = httpMocks.createRequest({
|
||||
method: "GET",
|
||||
url: "/getRawMempool?verbose=false"
|
||||
})
|
||||
const mockResponse = httpMocks.createResponse({
|
||||
eventEmitter: require("events").EventEmitter
|
||||
})
|
||||
blockchainRoute(mockRequest, mockResponse)
|
||||
|
||||
mockResponse.on("end", () => {
|
||||
const actualResponseBody = JSON.parse(mockResponse._getData())
|
||||
assert(actualResponseBody.length > 1)
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
// TODO - Why is this test failing?
|
||||
// describe("#BlockchainGetTxOut", () => {
|
||||
// it("should GET /getTxOut/:txid/:n w/ verbose=true", done => {
|
||||
// const mockRequest = httpMocks.createRequest({
|
||||
// method: "GET",
|
||||
// url:
|
||||
// "/getTxOut/ac0e82ea84f93444602a99199dd80793f79a8ece5ac86156d2fff34f0bad44b2/0?verbose=true"
|
||||
// })
|
||||
// const mockResponse = httpMocks.createResponse({
|
||||
// eventEmitter: require("events").EventEmitter
|
||||
// })
|
||||
// blockchainRoute(mockRequest, mockResponse)
|
||||
//
|
||||
// mockResponse.on("end", () => {
|
||||
// const actualResponseBody = Object.keys(
|
||||
// JSON.parse(mockResponse._getData())
|
||||
// )
|
||||
// assert.deepEqual(actualResponseBody, [
|
||||
// "bestblock",
|
||||
// "confirmations",
|
||||
// "value",
|
||||
// "scriptPubKey",
|
||||
// "coinbase"
|
||||
// ])
|
||||
// done()
|
||||
// })
|
||||
// })
|
||||
//
|
||||
// it("should GET /getTxOut/:txid/:n w/ verbose=false", done => {
|
||||
// const mockRequest = httpMocks.createRequest({
|
||||
// method: "GET",
|
||||
// url:
|
||||
// "/getTxOut/ac0e82ea84f93444602a99199dd80793f79a8ece5ac86156d2fff34f0bad44b2/0?verbose=false"
|
||||
// })
|
||||
// const mockResponse = httpMocks.createResponse({
|
||||
// eventEmitter: require("events").EventEmitter
|
||||
// })
|
||||
// blockchainRoute(mockRequest, mockResponse)
|
||||
//
|
||||
// mockResponse.on("end", () => {
|
||||
// const actualResponseBody = Object.keys(
|
||||
// JSON.parse(mockResponse._getData())
|
||||
// )
|
||||
// assert.deepEqual(actualResponseBody, [
|
||||
// "bestblock",
|
||||
// "confirmations",
|
||||
// "value",
|
||||
// "scriptPubKey",
|
||||
// "coinbase"
|
||||
// ])
|
||||
// done()
|
||||
// })
|
||||
// })
|
||||
// })
|
||||
|
||||
describe("#BlockchainGetTxOutProof", () => {
|
||||
it("should GET /getTxOutProof/:txid", done => {
|
||||
const mockRequest = httpMocks.createRequest({
|
||||
method: "GET",
|
||||
url:
|
||||
"/getTxOutProof/53735a4ddb828825d6e3f52d045f4c151b2b3d51d631bc581e62f31184b151d6"
|
||||
})
|
||||
const mockResponse = httpMocks.createResponse({
|
||||
eventEmitter: require("events").EventEmitter
|
||||
})
|
||||
blockchainRoute(mockRequest, mockResponse)
|
||||
|
||||
mockResponse.on("end", () => {
|
||||
const actualResponseBody = mockResponse._getData()
|
||||
assert.equal(
|
||||
actualResponseBody.message,
|
||||
"JSON value is not an array as expected"
|
||||
)
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
//
|
||||
// describe("#BlockchainPreciousBlock", () => {
|
||||
// it("should GET /preciousBlock/:hash", (done) => {
|
||||
// let mockRequest = httpMocks.createRequest({
|
||||
// method: "GET",
|
||||
// url: "/preciousBlock/00000000000000000108641af52e01a447b1f9d801571f93a0f20a8cbf80c236"
|
||||
// });
|
||||
// let mockResponse = httpMocks.createResponse({
|
||||
// eventEmitter: require('events').EventEmitter
|
||||
// });
|
||||
// blockchainRoute(mockRequest, mockResponse);
|
||||
//
|
||||
// mockResponse.on('end', () => {
|
||||
// let actualResponseBody = mockResponse._getData();
|
||||
// assert.equal(JSON.parse(actualResponseBody), "null" );
|
||||
// done();
|
||||
// });
|
||||
// });
|
||||
// });
|
||||
//
|
||||
// describe("#BlockchainPruneBlockchain", () => {
|
||||
// it("should POST /pruneBlockchain/:height ", (done) => {
|
||||
// let mockRequest = httpMocks.createRequest({
|
||||
// method: "POST",
|
||||
// url: "/pruneBlockchain/530384"
|
||||
// });
|
||||
// let mockResponse = httpMocks.createResponse({
|
||||
// eventEmitter: require('events').EventEmitter
|
||||
// });
|
||||
// blockchainRoute(mockRequest, mockResponse);
|
||||
//
|
||||
// mockResponse.on('end', () => {
|
||||
// let actualResponseBody = mockResponse._getData();
|
||||
// assert.equal(actualResponseBody, "Cannot prune blocks because node is not in prune mode." );
|
||||
// done();
|
||||
// });
|
||||
// });
|
||||
// });
|
||||
//
|
||||
// describe("#BlockchainVerifyChain", () => {
|
||||
// it("should GET /verifyChain", (done) => {
|
||||
// let mockRequest = httpMocks.createRequest({
|
||||
// method: "GET",
|
||||
// url: "/verifyChain"
|
||||
// });
|
||||
// let mockResponse = httpMocks.createResponse({
|
||||
// eventEmitter: require('events').EventEmitter
|
||||
// });
|
||||
// blockchainRoute(mockRequest, mockResponse);
|
||||
//
|
||||
// mockResponse.on('end', () => {
|
||||
// let actualResponseBody = JSON.parse(mockResponse._getData());
|
||||
// assert.equal(actualResponseBody, true);
|
||||
// done();
|
||||
// });
|
||||
// });
|
||||
// });
|
||||
|
||||
describe("#BlockchainVerifyTxOutProof", () => {
|
||||
it("should GET /verifyTxOutProof/:proof", done => {
|
||||
const mockRequest = httpMocks.createRequest({
|
||||
method: "GET",
|
||||
url:
|
||||
"/verifyTxOutProof/53735a4ddb828825d6e3f52d045f4c151b2b3d51d631bc581e62f31184b151d6"
|
||||
})
|
||||
const mockResponse = httpMocks.createResponse({
|
||||
eventEmitter: require("events").EventEmitter
|
||||
})
|
||||
blockchainRoute(mockRequest, mockResponse)
|
||||
|
||||
mockResponse.on("end", () => {
|
||||
const actualResponseBody = mockResponse._getData()
|
||||
assert.equal(
|
||||
actualResponseBody.message,
|
||||
"CDataStream::read(): end of data: iostream error"
|
||||
)
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,64 @@
|
||||
"use strict"
|
||||
|
||||
//const chai = require("chai");
|
||||
const assert = require("assert")
|
||||
//const expect = chai.expect;
|
||||
const httpMocks = require("node-mocks-http")
|
||||
const controlRoute = require("../../dist/routes/v1/control")
|
||||
|
||||
describe("#ControlRouter", () => {
|
||||
describe("#root", () => {
|
||||
it("should return 'control' for GET /", () => {
|
||||
const mockRequest = httpMocks.createRequest({
|
||||
method: "GET",
|
||||
url: "/"
|
||||
})
|
||||
const mockResponse = httpMocks.createResponse()
|
||||
controlRoute(mockRequest, mockResponse)
|
||||
const actualResponseBody = mockResponse._getData()
|
||||
const expectedResponseBody = {
|
||||
status: "control"
|
||||
}
|
||||
assert.deepEqual(JSON.parse(actualResponseBody), expectedResponseBody)
|
||||
})
|
||||
})
|
||||
/*
|
||||
describe("#GetInfo", () => {
|
||||
it("should GET /getInfo", (done) => {
|
||||
let mockRequest = httpMocks.createRequest({
|
||||
method: "GET",
|
||||
url: "/getInfo"
|
||||
});
|
||||
let mockResponse = httpMocks.createResponse({
|
||||
eventEmitter: require('events').EventEmitter
|
||||
});
|
||||
controlRoute(mockRequest, mockResponse);
|
||||
|
||||
mockResponse.on('end', () => {
|
||||
let actualResponseBody = Object.keys(JSON.parse(mockResponse._getData()));
|
||||
assert.deepEqual(actualResponseBody, [ 'version', 'protocolversion', 'blocks', 'timeoffset', 'connections', 'proxy', 'difficulty', 'testnet', 'paytxfee', 'relayfee', 'errors' ]);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
//
|
||||
// describe("#GetMemoryInfo", () => {
|
||||
// it("should GET /getMemoryInfo ", (done) => {
|
||||
// let mockRequest = httpMocks.createRequest({
|
||||
// method: "GET",
|
||||
// url: "/getMemoryInfo"
|
||||
// });
|
||||
// let mockResponse = httpMocks.createResponse({
|
||||
// eventEmitter: require('events').EventEmitter
|
||||
// });
|
||||
// controlRoute(mockRequest, mockResponse);
|
||||
//
|
||||
// mockResponse.on('end', () => {
|
||||
// let actualResponseBody = Object.keys(JSON.parse(mockResponse._getData()).locked);
|
||||
// assert.deepEqual(actualResponseBody, [ 'used', 'free', 'total', 'locked', 'chunks_used', 'chunks_free' ]);
|
||||
// done();
|
||||
// });
|
||||
// });
|
||||
// });
|
||||
*/
|
||||
})
|
||||
@@ -0,0 +1,485 @@
|
||||
"use strict"
|
||||
|
||||
//const chai = require("chai");
|
||||
const assert = require("assert")
|
||||
const httpMocks = require("node-mocks-http")
|
||||
const dataRetrieval = require("../../dist/routes/v1/dataRetrieval")
|
||||
|
||||
describe("#dataRetrievalRouter", () => {
|
||||
describe("#root", () => {
|
||||
it("should return 'dataRetrieval' for GET /", () => {
|
||||
const mockRequest = httpMocks.createRequest({
|
||||
method: "GET",
|
||||
url: "/"
|
||||
})
|
||||
const mockResponse = httpMocks.createResponse()
|
||||
dataRetrieval(mockRequest, mockResponse)
|
||||
const actualResponseBody = mockResponse._getData()
|
||||
const expectedResponseBody = {
|
||||
status: "dataRetrieval"
|
||||
}
|
||||
assert.deepEqual(JSON.parse(actualResponseBody), expectedResponseBody)
|
||||
})
|
||||
})
|
||||
|
||||
describe("#balancesForAddress", () => {
|
||||
it("should GET /balancesForAddress/:address", done => {
|
||||
const mockRequest = httpMocks.createRequest({
|
||||
method: "GET",
|
||||
url:
|
||||
"/balancesForAddress/bitcoincash:qqnjqejdq77pjqhg2y009fck50wdzzh3mc667y7075"
|
||||
})
|
||||
const mockResponse = httpMocks.createResponse({
|
||||
eventEmitter: require("events").EventEmitter
|
||||
})
|
||||
dataRetrieval(mockRequest, mockResponse)
|
||||
|
||||
mockResponse.on("end", () => {
|
||||
const actualResponseBody = JSON.parse(mockResponse._getData())
|
||||
assert.deepEqual(actualResponseBody[0], {
|
||||
propertyid: 189,
|
||||
balance: "1.0",
|
||||
reserved: "0.0"
|
||||
})
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
/*
|
||||
describe("#balancesForId", () => {
|
||||
it("should GET /balancesForId/:propertyId", done => {
|
||||
const mockRequest = httpMocks.createRequest({
|
||||
method: "GET",
|
||||
url: "/balancesForId/189"
|
||||
})
|
||||
const mockResponse = httpMocks.createResponse({
|
||||
eventEmitter: require("events").EventEmitter
|
||||
})
|
||||
dataRetrieval(mockRequest, mockResponse)
|
||||
|
||||
mockResponse.on("end", () => {
|
||||
const actualResponseBody = JSON.parse(mockResponse._getData())[0]
|
||||
//console.log(`actualResponseBody: ${JSON.stringify(actualResponseBody, null, 2)}`)
|
||||
|
||||
assert.deepEqual(actualResponseBody, {
|
||||
address: "bitcoincash:qzgvcvfkupltwn2k8c0y8hddhwffxg7p35s834qcuz",
|
||||
balance: "1.0",
|
||||
reserved: "0.0"
|
||||
})
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
*/
|
||||
describe("#balanceAddressAndPropertyId", () => {
|
||||
it("should GET /balance/:address/:propertyId", done => {
|
||||
const mockRequest = httpMocks.createRequest({
|
||||
method: "GET",
|
||||
url:
|
||||
"/balance/bitcoincash:qqnjqejdq77pjqhg2y009fck50wdzzh3mc667y7075/189"
|
||||
})
|
||||
const mockResponse = httpMocks.createResponse({
|
||||
eventEmitter: require("events").EventEmitter
|
||||
})
|
||||
dataRetrieval(mockRequest, mockResponse)
|
||||
|
||||
mockResponse.on("end", () => {
|
||||
const actualResponseBody = JSON.parse(mockResponse._getData())
|
||||
assert.deepEqual(actualResponseBody, {
|
||||
balance: "1.0",
|
||||
reserved: "0.0"
|
||||
})
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("#balancesHash", () => {
|
||||
it("should GET /balancesHash/:propertyId", done => {
|
||||
const mockRequest = httpMocks.createRequest({
|
||||
method: "GET",
|
||||
url: "/balancesHash/127"
|
||||
})
|
||||
const mockResponse = httpMocks.createResponse({
|
||||
eventEmitter: require("events").EventEmitter
|
||||
})
|
||||
dataRetrieval(mockRequest, mockResponse)
|
||||
|
||||
mockResponse.on("end", () => {
|
||||
const actualResponseBody = Object.keys(
|
||||
JSON.parse(mockResponse._getData())
|
||||
)
|
||||
assert.deepEqual(actualResponseBody, [
|
||||
"block",
|
||||
"blockhash",
|
||||
"propertyid",
|
||||
"balanceshash"
|
||||
])
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("#crowdSale", () => {
|
||||
it("should GET /crowdSale/:propertyId", done => {
|
||||
const mockRequest = httpMocks.createRequest({
|
||||
method: "GET",
|
||||
url: "/crowdSale/190"
|
||||
})
|
||||
const mockResponse = httpMocks.createResponse({
|
||||
eventEmitter: require("events").EventEmitter
|
||||
})
|
||||
dataRetrieval(mockRequest, mockResponse)
|
||||
|
||||
mockResponse.on("end", () => {
|
||||
const actualResponseBody = Object.keys(
|
||||
JSON.parse(mockResponse._getData())
|
||||
)
|
||||
|
||||
assert.deepEqual(actualResponseBody, [
|
||||
"propertyid",
|
||||
"name",
|
||||
"active",
|
||||
"issuer",
|
||||
"propertyiddesired",
|
||||
"precision",
|
||||
"tokensperunit",
|
||||
"earlybonus",
|
||||
"starttime",
|
||||
"deadline",
|
||||
"amountraised",
|
||||
"tokensissued",
|
||||
"addedissuertokens",
|
||||
"closedearly",
|
||||
"maxtokens",
|
||||
"endedtime",
|
||||
"closetx"
|
||||
])
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("#currentConsensusHash", () => {
|
||||
it("should GET /currentConsensusHash", done => {
|
||||
const mockRequest = httpMocks.createRequest({
|
||||
method: "GET",
|
||||
url: "/currentConsensusHash"
|
||||
})
|
||||
const mockResponse = httpMocks.createResponse({
|
||||
eventEmitter: require("events").EventEmitter
|
||||
})
|
||||
dataRetrieval(mockRequest, mockResponse)
|
||||
|
||||
mockResponse.on("end", () => {
|
||||
const actualResponseBody = Object.keys(
|
||||
JSON.parse(mockResponse._getData())
|
||||
)
|
||||
assert.deepEqual(actualResponseBody, [
|
||||
"block",
|
||||
"blockhash",
|
||||
"consensushash"
|
||||
])
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("#grants", () => {
|
||||
it("should GET /grants/:propertyId", done => {
|
||||
const mockRequest = httpMocks.createRequest({
|
||||
method: "GET",
|
||||
url: "/grants/189"
|
||||
})
|
||||
const mockResponse = httpMocks.createResponse({
|
||||
eventEmitter: require("events").EventEmitter
|
||||
})
|
||||
dataRetrieval(mockRequest, mockResponse)
|
||||
|
||||
mockResponse.on("end", () => {
|
||||
const actualResponseBody = Object.keys(
|
||||
JSON.parse(mockResponse._getData())
|
||||
)
|
||||
|
||||
assert.deepEqual(actualResponseBody, [
|
||||
"propertyid",
|
||||
"name",
|
||||
"issuer",
|
||||
"creationtxid",
|
||||
"totaltokens",
|
||||
"issuances"
|
||||
])
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
/*
|
||||
describe("#info", () => {
|
||||
it("should GET /info", done => {
|
||||
const mockRequest = httpMocks.createRequest({
|
||||
method: "GET",
|
||||
url: "/info"
|
||||
})
|
||||
const mockResponse = httpMocks.createResponse({
|
||||
eventEmitter: require("events").EventEmitter
|
||||
})
|
||||
dataRetrieval(mockRequest, mockResponse)
|
||||
|
||||
mockResponse.on("end", () => {
|
||||
const actualResponseBody = Object.keys(
|
||||
JSON.parse(mockResponse._getData())
|
||||
)
|
||||
assert.deepEqual(actualResponseBody, [
|
||||
"wormholeversion_int",
|
||||
"wormholeversion",
|
||||
"bitcoincoreversion",
|
||||
"block",
|
||||
"blocktime",
|
||||
"blocktransactions",
|
||||
"totaltrades",
|
||||
"totaltransactions",
|
||||
"alerts"
|
||||
])
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
*/
|
||||
describe("#payload", () => {
|
||||
it("should GET /payload/:txid", done => {
|
||||
const mockRequest = httpMocks.createRequest({
|
||||
method: "GET",
|
||||
url:
|
||||
"/payload/709d1346a781e7e0064393c9b3f0e846ee445958946352b5928084e8d9a410cc"
|
||||
})
|
||||
const mockResponse = httpMocks.createResponse({
|
||||
eventEmitter: require("events").EventEmitter
|
||||
})
|
||||
dataRetrieval(mockRequest, mockResponse)
|
||||
|
||||
mockResponse.on("end", () => {
|
||||
const actualResponseBody = Object.keys(
|
||||
JSON.parse(mockResponse._getData())
|
||||
)
|
||||
assert.deepEqual(actualResponseBody, ["payload", "payloadsize"])
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("#property", () => {
|
||||
it("should GET /property/:propertyId", done => {
|
||||
const mockRequest = httpMocks.createRequest({
|
||||
method: "GET",
|
||||
url: "/property/127"
|
||||
})
|
||||
const mockResponse = httpMocks.createResponse({
|
||||
eventEmitter: require("events").EventEmitter
|
||||
})
|
||||
dataRetrieval(mockRequest, mockResponse)
|
||||
|
||||
mockResponse.on("end", () => {
|
||||
const actualResponseBody = Object.keys(
|
||||
JSON.parse(mockResponse._getData())
|
||||
)
|
||||
assert.deepEqual(actualResponseBody, [
|
||||
"propertyid",
|
||||
"name",
|
||||
"category",
|
||||
"subcategory",
|
||||
"data",
|
||||
"url",
|
||||
"precision",
|
||||
"issuer",
|
||||
"creationtxid",
|
||||
"fixedissuance",
|
||||
"managedissuance",
|
||||
"totaltokens"
|
||||
])
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("#seedBlocks", () => {
|
||||
it("should GET /seedBlocks/:startBlock/:endBlock", done => {
|
||||
const mockRequest = httpMocks.createRequest({
|
||||
method: "GET",
|
||||
url: "/seedBlocks/290000/300000"
|
||||
})
|
||||
const mockResponse = httpMocks.createResponse({
|
||||
eventEmitter: require("events").EventEmitter
|
||||
})
|
||||
dataRetrieval(mockRequest, mockResponse)
|
||||
|
||||
mockResponse.on("end", () => {
|
||||
const actualResponseBody = Object.keys(
|
||||
JSON.parse(mockResponse._getData())
|
||||
)
|
||||
assert.deepEqual(actualResponseBody, [])
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
/*
|
||||
describe("#STO", () => {
|
||||
it("should GET /STO/:txid", done => {
|
||||
const mockRequest = httpMocks.createRequest({
|
||||
method: "GET",
|
||||
//url: "/STO/ac2df919be43fa793ff4955019195481878e0f0cab39834ad911124fdacfc603/*",
|
||||
url: "/STO/744b6b3c287d836814c615b532737c080d07ddb48d891f9b0159196ee910b45c/*",
|
||||
});
|
||||
const mockResponse = httpMocks.createResponse({
|
||||
eventEmitter: require("events").EventEmitter,
|
||||
});
|
||||
dataRetrieval(mockRequest, mockResponse);
|
||||
|
||||
mockResponse.on("end", () => {
|
||||
const actualResponseBody = Object.keys(JSON.parse(mockResponse._getData()));
|
||||
assert.deepEqual(actualResponseBody, [
|
||||
"txid",
|
||||
"fee",
|
||||
"sendingaddress",
|
||||
"ismine",
|
||||
"version",
|
||||
"type_int",
|
||||
"type",
|
||||
"propertyid",
|
||||
"precision",
|
||||
"ecosystem",
|
||||
"category",
|
||||
"subcategory",
|
||||
"propertyname",
|
||||
"data",
|
||||
"url",
|
||||
"amount",
|
||||
"valid",
|
||||
"blockhash",
|
||||
"blocktime",
|
||||
"positioninblock",
|
||||
"block",
|
||||
"confirmations",
|
||||
]);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
*/
|
||||
describe("#transaction", () => {
|
||||
it("should GET /transaction/:txid", done => {
|
||||
const mockRequest = httpMocks.createRequest({
|
||||
method: "GET",
|
||||
//url: "/transaction/ac2df919be43fa793ff4955019195481878e0f0cab39834ad911124fdacfc603",
|
||||
url:
|
||||
"/transaction/744b6b3c287d836814c615b532737c080d07ddb48d891f9b0159196ee910b45c"
|
||||
})
|
||||
const mockResponse = httpMocks.createResponse({
|
||||
eventEmitter: require("events").EventEmitter
|
||||
})
|
||||
dataRetrieval(mockRequest, mockResponse)
|
||||
|
||||
mockResponse.on("end", () => {
|
||||
const actualResponseBody = Object.keys(
|
||||
JSON.parse(mockResponse._getData())
|
||||
)
|
||||
|
||||
assert.deepEqual(actualResponseBody, [
|
||||
"txid",
|
||||
"fee",
|
||||
"sendingaddress",
|
||||
"ismine",
|
||||
"version",
|
||||
"type_int",
|
||||
"type",
|
||||
"propertyid",
|
||||
"precision",
|
||||
//"ecosystem",
|
||||
//"category",
|
||||
//"subcategory",
|
||||
//"propertyname",
|
||||
//"data",
|
||||
//"url",
|
||||
//"amount",
|
||||
"valid",
|
||||
"blockhash",
|
||||
"blocktime",
|
||||
"positioninblock",
|
||||
"block",
|
||||
"confirmations"
|
||||
])
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("#blockTransactions", () => {
|
||||
it("should GET /blockTransactions/:index", done => {
|
||||
const mockRequest = httpMocks.createRequest({
|
||||
method: "GET",
|
||||
url: "/blockTransactions/279007"
|
||||
})
|
||||
const mockResponse = httpMocks.createResponse({
|
||||
eventEmitter: require("events").EventEmitter
|
||||
})
|
||||
dataRetrieval(mockRequest, mockResponse)
|
||||
|
||||
mockResponse.on("end", () => {
|
||||
const actualResponseBody = Object.keys(
|
||||
JSON.parse(mockResponse._getData())
|
||||
)
|
||||
assert.deepEqual(actualResponseBody, [])
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("#pendingTransactions", () => {
|
||||
it("should GET /pendingTransactions", done => {
|
||||
const mockRequest = httpMocks.createRequest({
|
||||
method: "GET",
|
||||
url: "/pendingTransactions"
|
||||
})
|
||||
const mockResponse = httpMocks.createResponse({
|
||||
eventEmitter: require("events").EventEmitter
|
||||
})
|
||||
dataRetrieval(mockRequest, mockResponse)
|
||||
|
||||
mockResponse.on("end", () => {
|
||||
const actualResponseBody = Object.keys(
|
||||
JSON.parse(mockResponse._getData())
|
||||
)
|
||||
assert.equal(Array.isArray(actualResponseBody), true)
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("#properties", () => {
|
||||
it("should GET /properties", done => {
|
||||
const mockRequest = httpMocks.createRequest({
|
||||
method: "GET",
|
||||
url: "/properties"
|
||||
})
|
||||
const mockResponse = httpMocks.createResponse({
|
||||
eventEmitter: require("events").EventEmitter
|
||||
})
|
||||
dataRetrieval(mockRequest, mockResponse)
|
||||
|
||||
mockResponse.on("end", () => {
|
||||
const actualResponseBody = Object.keys(
|
||||
JSON.parse(mockResponse._getData())[0]
|
||||
)
|
||||
assert.deepEqual(actualResponseBody, [
|
||||
"propertyid",
|
||||
"name",
|
||||
"category",
|
||||
"subcategory",
|
||||
"data",
|
||||
"url",
|
||||
"precision"
|
||||
])
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,44 @@
|
||||
"use strict"
|
||||
|
||||
// const chai = require("chai");
|
||||
const assert = require("assert")
|
||||
// const expect = chai.expect;
|
||||
const httpMocks = require("node-mocks-http")
|
||||
const generatingRoute = require("../../dist/routes/v1/generating")
|
||||
|
||||
describe("#GeneratingRouter", () => {
|
||||
describe("#root", () => {
|
||||
it("should return 'generating' for GET /", () => {
|
||||
const mockRequest = httpMocks.createRequest({
|
||||
method: "GET",
|
||||
url: "/"
|
||||
})
|
||||
const mockResponse = httpMocks.createResponse()
|
||||
generatingRoute(mockRequest, mockResponse)
|
||||
const actualResponseBody = mockResponse._getData()
|
||||
const expectedResponseBody = {
|
||||
status: "generating"
|
||||
}
|
||||
assert.deepEqual(JSON.parse(actualResponseBody), expectedResponseBody)
|
||||
})
|
||||
})
|
||||
//
|
||||
// describe("#GeneratingGenerateToAddress", () => {
|
||||
// it("should POST /generateToAddress/:n/:address ", (done) => {
|
||||
// let mockRequest = httpMocks.createRequest({
|
||||
// method: "POST",
|
||||
// url: "/generateToAddress/1/qrff52mj0ml4scljzxrex7ses2gst42k9sfz2lftjq"
|
||||
// });
|
||||
// let mockResponse = httpMocks.createResponse({
|
||||
// eventEmitter: require('events').EventEmitter
|
||||
// });
|
||||
// generatingRoute(mockRequest, mockResponse);
|
||||
//
|
||||
// mockResponse.on('end', () => {
|
||||
// let actualResponseBody = mockResponse._getData();
|
||||
// assert.equal(actualResponseBody, "JSON value is not an integer as expected");
|
||||
// done();
|
||||
// });
|
||||
// });
|
||||
// });
|
||||
})
|
||||
@@ -0,0 +1,24 @@
|
||||
"use strict"
|
||||
|
||||
//const chai = require("chai");
|
||||
const assert = require("assert")
|
||||
const httpMocks = require("node-mocks-http")
|
||||
const healthCheckRoute = require("../../dist/routes/v1/health-check")
|
||||
|
||||
describe("#HealthCheckRouter", () => {
|
||||
describe("#root", () => {
|
||||
it("should return 'winning' for GET /", () => {
|
||||
const mockRequest = httpMocks.createRequest({
|
||||
method: "GET",
|
||||
url: "/"
|
||||
})
|
||||
const mockResponse = httpMocks.createResponse()
|
||||
healthCheckRoute(mockRequest, mockResponse)
|
||||
const actualResponseBody = mockResponse._getData()
|
||||
const expectedResponseBody = {
|
||||
status: "winning"
|
||||
}
|
||||
assert.deepEqual(JSON.parse(actualResponseBody), expectedResponseBody)
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,114 @@
|
||||
"use strict"
|
||||
|
||||
//const chai = require("chai");
|
||||
const assert = require("assert")
|
||||
//const expect = chai.expect;
|
||||
const httpMocks = require("node-mocks-http")
|
||||
const miningRoute = require("../../dist/routes/v1/mining")
|
||||
|
||||
describe("#MiningRouter", () => {
|
||||
describe("#root", () => {
|
||||
it("should return 'mining' for GET /", () => {
|
||||
const mockRequest = httpMocks.createRequest({
|
||||
method: "GET",
|
||||
url: "/"
|
||||
})
|
||||
const mockResponse = httpMocks.createResponse()
|
||||
miningRoute(mockRequest, mockResponse)
|
||||
const actualResponseBody = mockResponse._getData()
|
||||
const expectedResponseBody = {
|
||||
status: "mining"
|
||||
}
|
||||
assert.deepEqual(JSON.parse(actualResponseBody), expectedResponseBody)
|
||||
})
|
||||
})
|
||||
|
||||
//
|
||||
// describe("#MiningGetBlockTemplate", () => {
|
||||
// it("should GET /getBlockTemplate", (done) => {
|
||||
// let mockRequest = httpMocks.createRequest({
|
||||
// method: "GET",
|
||||
// url: "/getBlockTemplate/{}"
|
||||
// });
|
||||
// let mockResponse = httpMocks.createResponse({
|
||||
// eventEmitter: require('events').EventEmitter
|
||||
// });
|
||||
// miningRoute(mockRequest, mockResponse);
|
||||
//
|
||||
// mockResponse.on('end', () => {
|
||||
// let actualResponseBody = mockResponse._getData();
|
||||
// assert.equal(actualResponseBody, 'JSON value is not an object as expected');
|
||||
// done();
|
||||
// });
|
||||
// });
|
||||
// });
|
||||
|
||||
describe("#MiningGetMiningInfo", () => {
|
||||
it("should GET /getMiningInfo", done => {
|
||||
const mockRequest = httpMocks.createRequest({
|
||||
method: "GET",
|
||||
url: "/getMiningInfo"
|
||||
})
|
||||
const mockResponse = httpMocks.createResponse({
|
||||
eventEmitter: require("events").EventEmitter
|
||||
})
|
||||
miningRoute(mockRequest, mockResponse)
|
||||
|
||||
mockResponse.on("end", () => {
|
||||
const actualResponseBody = Object.keys(
|
||||
JSON.parse(mockResponse._getData())
|
||||
)
|
||||
assert.deepEqual(actualResponseBody, [
|
||||
"blocks",
|
||||
"currentblocksize",
|
||||
"currentblocktx",
|
||||
"difficulty",
|
||||
"blockprioritypercentage",
|
||||
"errors",
|
||||
"networkhashps",
|
||||
"pooledtx",
|
||||
"chain"
|
||||
])
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("#MiningGetNetworkHashps", () => {
|
||||
it("should GET /getNetworkHashps", done => {
|
||||
const mockRequest = httpMocks.createRequest({
|
||||
method: "GET",
|
||||
url: "/getNetworkHashps"
|
||||
})
|
||||
const mockResponse = httpMocks.createResponse({
|
||||
eventEmitter: require("events").EventEmitter
|
||||
})
|
||||
miningRoute(mockRequest, mockResponse)
|
||||
|
||||
mockResponse.on("end", () => {
|
||||
const actualResponseBody = parseInt(mockResponse._getData())
|
||||
assert.equal(typeof actualResponseBody, "number")
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
//
|
||||
// describe("#MiningSubmitBlock", () => {
|
||||
// it("should POST /SubmitBlock", (done) => {
|
||||
// let mockRequest = httpMocks.createRequest({
|
||||
// method: "POST",
|
||||
// url: "/submitBlock/000000000000000000df19ff517463e288aca3de261ece7d53f97da65f9b7b8d"
|
||||
// });
|
||||
// let mockResponse = httpMocks.createResponse({
|
||||
// eventEmitter: require('events').EventEmitter
|
||||
// });
|
||||
// miningRoute(mockRequest, mockResponse);
|
||||
//
|
||||
// mockResponse.on('end', () => {
|
||||
// let actualResponseBody = mockResponse._getData();
|
||||
// assert.equal(actualResponseBody, "Block decode failed");
|
||||
// done();
|
||||
// });
|
||||
// });
|
||||
// });
|
||||
})
|
||||
@@ -0,0 +1,120 @@
|
||||
"use strict"
|
||||
|
||||
//const chai = require("chai");
|
||||
const assert = require("assert")
|
||||
//const expect = chai.expect;
|
||||
const httpMocks = require("node-mocks-http")
|
||||
const networkRoute = require("../../dist/routes/v1/network")
|
||||
|
||||
describe("#NetworkRouter", () => {
|
||||
describe("#root", () => {
|
||||
it("should return 'network' for GET /", () => {
|
||||
const mockRequest = httpMocks.createRequest({
|
||||
method: "GET",
|
||||
url: "/"
|
||||
})
|
||||
const mockResponse = httpMocks.createResponse()
|
||||
networkRoute(mockRequest, mockResponse)
|
||||
const actualResponseBody = mockResponse._getData()
|
||||
const expectedResponseBody = {
|
||||
status: "network"
|
||||
}
|
||||
assert.deepEqual(JSON.parse(actualResponseBody), expectedResponseBody)
|
||||
})
|
||||
})
|
||||
//
|
||||
// describe("#NetworkGetConnectionCount", () => {
|
||||
// it("should GET /getConnectionCount ", (done) => {
|
||||
// let mockRequest = httpMocks.createRequest({
|
||||
// method: "GET",
|
||||
// url: "/getConnectionCount"
|
||||
// });
|
||||
// let mockResponse = httpMocks.createResponse({
|
||||
// eventEmitter: require('events').EventEmitter
|
||||
// });
|
||||
// networkRoute(mockRequest, mockResponse);
|
||||
//
|
||||
// mockResponse.on('end', () => {
|
||||
// let actualResponseBody = parseInt(mockResponse._getData());
|
||||
// assert.equal(typeof actualResponseBody, "number");
|
||||
// done();
|
||||
// });
|
||||
// });
|
||||
// });
|
||||
//
|
||||
// describe("#NetworkGetNetTotals", () => {
|
||||
// it("should GET /getNetTotals ", (done) => {
|
||||
// let mockRequest = httpMocks.createRequest({
|
||||
// method: "GET",
|
||||
// url: "/getNetTotals"
|
||||
// });
|
||||
// let mockResponse = httpMocks.createResponse({
|
||||
// eventEmitter: require('events').EventEmitter
|
||||
// });
|
||||
// networkRoute(mockRequest, mockResponse);
|
||||
//
|
||||
// mockResponse.on('end', () => {
|
||||
// let actualResponseBody = Object.keys(JSON.parse(mockResponse._getData()));
|
||||
// assert.deepEqual(actualResponseBody, [ 'totalbytesrecv', 'totalbytessent', 'timemillis', 'uploadtarget' ]);
|
||||
// done();
|
||||
// });
|
||||
// });
|
||||
// });
|
||||
//
|
||||
// describe("#NetworkGetNetworkInfo", () => {
|
||||
// it("should GET /getNetworkInfo", (done) => {
|
||||
// let mockRequest = httpMocks.createRequest({
|
||||
// method: "GET",
|
||||
// url: "/getNetworkInfo"
|
||||
// });
|
||||
// let mockResponse = httpMocks.createResponse({
|
||||
// eventEmitter: require('events').EventEmitter
|
||||
// });
|
||||
// networkRoute(mockRequest, mockResponse);
|
||||
//
|
||||
// mockResponse.on('end', () => {
|
||||
// let actualResponseBody = Object.keys(JSON.parse(mockResponse._getData()));
|
||||
// assert.deepEqual(actualResponseBody, [ 'version', 'subversion', 'protocolversion', 'localservices', 'localrelay', 'timeoffset', 'networkactive', 'connections', 'networks', 'relayfee', 'incrementalfee', 'localaddresses', 'warnings' ]);
|
||||
// done();
|
||||
// });
|
||||
// });
|
||||
// });
|
||||
//
|
||||
// describe("#NetworkGetPeerInfo", () => {
|
||||
// it("should GET /getPeerInfo", (done) => {
|
||||
// let mockRequest = httpMocks.createRequest({
|
||||
// method: "GET",
|
||||
// url: "/getPeerInfo"
|
||||
// });
|
||||
// let mockResponse = httpMocks.createResponse({
|
||||
// eventEmitter: require('events').EventEmitter
|
||||
// });
|
||||
// networkRoute(mockRequest, mockResponse);
|
||||
//
|
||||
// mockResponse.on('end', () => {
|
||||
// let actualResponseBody = Object.keys(JSON.parse(mockResponse._getData())[0]);
|
||||
// assert.deepEqual(actualResponseBody, [ 'id', 'addr', 'addrlocal', 'services', 'relaytxes', 'lastsend', 'lastrecv', 'bytessent', 'bytesrecv', 'conntime', 'timeoffset', 'pingtime', 'minping', 'version', 'subver', 'inbound', 'addnode', 'startingheight', 'banscore', 'synced_headers', 'synced_blocks', 'inflight', 'whitelisted', 'bytessent_per_msg', 'bytesrecv_per_msg' ]);
|
||||
// done();
|
||||
// });
|
||||
// });
|
||||
// });
|
||||
//
|
||||
// describe("#NetworkPing", () => {
|
||||
// it("should GET /ping", (done) => {
|
||||
// let mockRequest = httpMocks.createRequest({
|
||||
// method: "GET",
|
||||
// url: "/ping"
|
||||
// });
|
||||
// let mockResponse = httpMocks.createResponse({
|
||||
// eventEmitter: require('events').EventEmitter
|
||||
// });
|
||||
// networkRoute(mockRequest, mockResponse);
|
||||
//
|
||||
// mockResponse.on('end', () => {
|
||||
// let actualResponseBody = JSON.parse(mockResponse._getData());
|
||||
// assert.equal(actualResponseBody, 'null');
|
||||
// done();
|
||||
// });
|
||||
// });
|
||||
// });
|
||||
})
|
||||
@@ -0,0 +1,308 @@
|
||||
"use strict"
|
||||
//const chai = require("chai");
|
||||
const assert = require("assert")
|
||||
const httpMocks = require("node-mocks-http")
|
||||
const payloadCreation = require("../../dist/routes/v1/payloadCreation")
|
||||
|
||||
describe("#payloadCreationRouter", () => {
|
||||
describe("#root", () => {
|
||||
it("should return 'payloadCreation' for GET /", () => {
|
||||
const mockRequest = httpMocks.createRequest({
|
||||
method: "GET",
|
||||
url: "/"
|
||||
})
|
||||
const mockResponse = httpMocks.createResponse()
|
||||
payloadCreation(mockRequest, mockResponse)
|
||||
const actualResponseBody = mockResponse._getData()
|
||||
const expectedResponseBody = {
|
||||
status: "payloadCreation"
|
||||
}
|
||||
assert.deepEqual(JSON.parse(actualResponseBody), expectedResponseBody)
|
||||
})
|
||||
})
|
||||
|
||||
describe("#burnBCH", () => {
|
||||
it("should GET /burnBCH", done => {
|
||||
const mockRequest = httpMocks.createRequest({
|
||||
method: "GET",
|
||||
url: "/burnBCH"
|
||||
})
|
||||
const mockResponse = httpMocks.createResponse({
|
||||
eventEmitter: require("events").EventEmitter
|
||||
})
|
||||
payloadCreation(mockRequest, mockResponse)
|
||||
|
||||
mockResponse.on("end", () => {
|
||||
const actualResponseBody = JSON.parse(mockResponse._getData())
|
||||
assert.equal(actualResponseBody, "00000044")
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("#changeIssuer", () => {
|
||||
it("should POST /changeIssuer/:propertyId", done => {
|
||||
const mockRequest = httpMocks.createRequest({
|
||||
method: "POST",
|
||||
url: "/changeIssuer/3"
|
||||
})
|
||||
const mockResponse = httpMocks.createResponse({
|
||||
eventEmitter: require("events").EventEmitter
|
||||
})
|
||||
payloadCreation(mockRequest, mockResponse)
|
||||
|
||||
mockResponse.on("end", () => {
|
||||
const actualResponseBody = JSON.parse(mockResponse._getData())
|
||||
assert.equal(actualResponseBody, "0000004600000003")
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("#closeCrowdSale", () => {
|
||||
it("should POST /closeCrowdSale/:propertyId", done => {
|
||||
const mockRequest = httpMocks.createRequest({
|
||||
method: "POST",
|
||||
url: "/closeCrowdSale/70"
|
||||
})
|
||||
const mockResponse = httpMocks.createResponse({
|
||||
eventEmitter: require("events").EventEmitter
|
||||
})
|
||||
payloadCreation(mockRequest, mockResponse)
|
||||
|
||||
mockResponse.on("end", () => {
|
||||
const actualResponseBody = JSON.parse(mockResponse._getData())
|
||||
assert.equal(actualResponseBody, "0000003500000046")
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("#grant", () => {
|
||||
it("should POST /grant/:propertyId/:amount", done => {
|
||||
const mockRequest = httpMocks.createRequest({
|
||||
method: "POST",
|
||||
url: "/grant/189/7000"
|
||||
})
|
||||
const mockResponse = httpMocks.createResponse({
|
||||
eventEmitter: require("events").EventEmitter
|
||||
})
|
||||
payloadCreation(mockRequest, mockResponse)
|
||||
|
||||
mockResponse.on("end", () => {
|
||||
const actualResponseBody = JSON.parse(mockResponse._getData())
|
||||
|
||||
assert.equal(actualResponseBody, "00000037000000bd000000000001117000")
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("#crowdsale", () => {
|
||||
// CT 10/25/18: This test is commented out because I can't figure out how to
|
||||
// test a thrown error with node-mocks-http. z
|
||||
/*
|
||||
it("should reject invalid date", done => {
|
||||
try {
|
||||
const mockRequest = httpMocks.createRequest({
|
||||
method: "POST",
|
||||
url:
|
||||
"/crowdsale/1/1/0/Companies/Bitcoin-Mining/Quantum-Miner/www.example.com/Quantum -Miner-Tokens/1/100/7308955112/30/0/192978657"
|
||||
})
|
||||
const mockResponse = httpMocks.createResponse({
|
||||
eventEmitter: require("events").EventEmitter
|
||||
})
|
||||
payloadCreation(mockRequest, mockResponse)
|
||||
|
||||
mockResponse.on("end", () => {
|
||||
const actualResponseBody = JSON.parse(mockResponse._getData())
|
||||
console.log(
|
||||
`actualResponseBody: ${JSON.stringify(actualResponseBody, null, 2)}`
|
||||
)
|
||||
//assert.equal(
|
||||
// actualResponseBody,
|
||||
// "0000003301000100000000436f6d70616e69657300426974636f696e2d4d696e696e67005175616e74756d2d4d696e6572007777772e6578616d706c652e636f6d005175616e74756d202d4d696e65722d546f6b656e73000000000100000002540be40000000000586846801e0000000000730634ca"
|
||||
//)
|
||||
assert.equal(true, true)
|
||||
done()
|
||||
})
|
||||
} catch (err) {
|
||||
console.log(`Error: ${JSON.stringify(err, null, 2)}`)
|
||||
assert.equal(true, true)
|
||||
done()
|
||||
}
|
||||
})
|
||||
*/
|
||||
|
||||
it("should POST /crowdsale/:ecosystem/:propertyPrecision/:previousId/:category/:subcategory/:name/:url/:data/:propertyIdDesired/:tokensPerUnit/:deadline/:earlyBonus/:undefine/:totalNumber", done => {
|
||||
const mockRequest = httpMocks.createRequest({
|
||||
method: "POST",
|
||||
url:
|
||||
"/crowdsale/1/1/0/Companies/Bitcoin-Mining/Quantum-Miner/www.example.com/Quantum -Miner-Tokens/1/100/1483228800/30/0/192978657"
|
||||
})
|
||||
const mockResponse = httpMocks.createResponse({
|
||||
eventEmitter: require("events").EventEmitter
|
||||
})
|
||||
payloadCreation(mockRequest, mockResponse)
|
||||
|
||||
mockResponse.on("end", () => {
|
||||
const actualResponseBody = JSON.parse(mockResponse._getData())
|
||||
assert.equal(
|
||||
actualResponseBody,
|
||||
"0000003301000100000000436f6d70616e69657300426974636f696e2d4d696e696e67005175616e74756d2d4d696e6572007777772e6578616d706c652e636f6d005175616e74756d202d4d696e65722d546f6b656e73000000000100000002540be40000000000586846801e0000000000730634ca"
|
||||
)
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("#fixed", () => {
|
||||
it("should POST /fixed/:ecosystem/:propertyPrecision/:previousId/:category/:subcategory/:name/:url/:data/:amount", done => {
|
||||
const mockRequest = httpMocks.createRequest({
|
||||
method: "POST",
|
||||
url:
|
||||
"/fixed/1/1/0/Companies/Bitcoin-Mining/Quantum-Miner/www.example.com/Quantum-Miner-Tokens/1000000"
|
||||
})
|
||||
const mockResponse = httpMocks.createResponse({
|
||||
eventEmitter: require("events").EventEmitter
|
||||
})
|
||||
payloadCreation(mockRequest, mockResponse)
|
||||
|
||||
mockResponse.on("end", () => {
|
||||
const actualResponseBody = JSON.parse(mockResponse._getData())
|
||||
assert.equal(
|
||||
actualResponseBody,
|
||||
"0000003201000100000000436f6d70616e69657300426974636f696e2d4d696e696e67005175616e74756d2d4d696e6572007777772e6578616d706c652e636f6d005175616e74756d2d4d696e65722d546f6b656e73000000000000989680"
|
||||
)
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("#managed", () => {
|
||||
it("should POST /managed/:ecosystem/:propertyPrecision/:previousId/:category/:subcategory/:name/:url/:data", done => {
|
||||
const mockRequest = httpMocks.createRequest({
|
||||
method: "POST",
|
||||
url:
|
||||
"/managed/1/1/0/Companies/Bitcoin-Mining/Quantum-Miner/www.example.com/Quantum-Miner-Tokens"
|
||||
})
|
||||
const mockResponse = httpMocks.createResponse({
|
||||
eventEmitter: require("events").EventEmitter
|
||||
})
|
||||
payloadCreation(mockRequest, mockResponse)
|
||||
|
||||
mockResponse.on("end", () => {
|
||||
const actualResponseBody = JSON.parse(mockResponse._getData())
|
||||
assert.equal(
|
||||
actualResponseBody,
|
||||
"0000003601000100000000436f6d70616e69657300426974636f696e2d4d696e696e67005175616e74756d2d4d696e6572007777772e6578616d706c652e636f6d005175616e74756d2d4d696e65722d546f6b656e7300"
|
||||
)
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("#participateCrowdSale", () => {
|
||||
it("should POST /participateCrowdSale/:amount", done => {
|
||||
const mockRequest = httpMocks.createRequest({
|
||||
method: "POST",
|
||||
url: "/participateCrowdSale/100.0"
|
||||
})
|
||||
const mockResponse = httpMocks.createResponse({
|
||||
eventEmitter: require("events").EventEmitter
|
||||
})
|
||||
payloadCreation(mockRequest, mockResponse)
|
||||
|
||||
mockResponse.on("end", () => {
|
||||
const actualResponseBody = JSON.parse(mockResponse._getData())
|
||||
assert.equal(actualResponseBody, "000000010000000100000002540be400")
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("#revoke", () => {
|
||||
it("should POST /revoke/:propertyId/:amount", done => {
|
||||
const mockRequest = httpMocks.createRequest({
|
||||
method: "POST",
|
||||
//url: "/revoke/3/100", // testnet
|
||||
url: "/revoke/189/100"
|
||||
})
|
||||
const mockResponse = httpMocks.createResponse({
|
||||
eventEmitter: require("events").EventEmitter
|
||||
})
|
||||
payloadCreation(mockRequest, mockResponse)
|
||||
|
||||
mockResponse.on("end", () => {
|
||||
const actualResponseBody = JSON.parse(mockResponse._getData())
|
||||
//console.log(`actualResponseBody: ${JSON.stringify(actualResponseBody, null, 2)}`);
|
||||
|
||||
assert.equal(actualResponseBody, "00000038000000bd00000000000003e800")
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("#sendAll", () => {
|
||||
it("should POST /sendAll/:ecosystem", done => {
|
||||
const mockRequest = httpMocks.createRequest({
|
||||
method: "POST",
|
||||
//url: "/sendAll/2", // testnet
|
||||
url: "/sendAll/1" // mainnet
|
||||
})
|
||||
const mockResponse = httpMocks.createResponse({
|
||||
eventEmitter: require("events").EventEmitter
|
||||
})
|
||||
payloadCreation(mockRequest, mockResponse)
|
||||
|
||||
mockResponse.on("end", () => {
|
||||
const actualResponseBody = JSON.parse(mockResponse._getData())
|
||||
//console.log(`actualResponseBody: ${JSON.stringify(actualResponseBody, null, 2)}`);
|
||||
|
||||
assert.equal(actualResponseBody, "0000000401")
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("#simpleSend", () => {
|
||||
it("should POST /simpleSend/:propertyId/:amount", done => {
|
||||
const mockRequest = httpMocks.createRequest({
|
||||
method: "POST",
|
||||
url: "/simpleSend/1/100.0"
|
||||
})
|
||||
const mockResponse = httpMocks.createResponse({
|
||||
eventEmitter: require("events").EventEmitter
|
||||
})
|
||||
payloadCreation(mockRequest, mockResponse)
|
||||
|
||||
mockResponse.on("end", () => {
|
||||
const actualResponseBody = JSON.parse(mockResponse._getData())
|
||||
assert.equal(actualResponseBody, "000000000000000100000002540be400")
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("#STO", () => {
|
||||
it("should POST /STO/:propertyId/:amount", done => {
|
||||
const mockRequest = httpMocks.createRequest({
|
||||
method: "POST",
|
||||
url: "/STO/3/5000"
|
||||
})
|
||||
const mockResponse = httpMocks.createResponse({
|
||||
eventEmitter: require("events").EventEmitter
|
||||
})
|
||||
payloadCreation(mockRequest, mockResponse)
|
||||
|
||||
mockResponse.on("end", () => {
|
||||
const actualResponseBody = JSON.parse(mockResponse._getData())
|
||||
assert.equal(
|
||||
actualResponseBody,
|
||||
"0000000300000003000000000000138800000003"
|
||||
)
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
+191
@@ -0,0 +1,191 @@
|
||||
"use strict"
|
||||
|
||||
//const chai = require("chai");
|
||||
const assert = require("assert")
|
||||
const httpMocks = require("node-mocks-http")
|
||||
const slpRoute = require("../../dist/routes/v1/slp")
|
||||
|
||||
describe("#SlpRouter", () => {
|
||||
describe("#root", () => {
|
||||
it("should return 'slp' for GET /", () => {
|
||||
const mockRequest = httpMocks.createRequest({
|
||||
method: "GET",
|
||||
url: "/"
|
||||
})
|
||||
const mockResponse = httpMocks.createResponse()
|
||||
slpRoute(mockRequest, mockResponse)
|
||||
const actualResponseBody = mockResponse._getData()
|
||||
const expectedResponseBody = {
|
||||
status: "slp"
|
||||
}
|
||||
assert.deepEqual(JSON.parse(actualResponseBody), expectedResponseBody)
|
||||
})
|
||||
})
|
||||
|
||||
describe("#listTokens", () => {
|
||||
it("should GET /list", done => {
|
||||
const mockRequest = httpMocks.createRequest({
|
||||
method: "GET",
|
||||
url: "/list"
|
||||
})
|
||||
const mockResponse = httpMocks.createResponse({
|
||||
eventEmitter: require("events").EventEmitter
|
||||
})
|
||||
slpRoute(mockRequest, mockResponse)
|
||||
|
||||
mockResponse.on("end", () => {
|
||||
const actualResponseBody = Object.keys(
|
||||
JSON.parse(mockResponse._getData())[0]
|
||||
)
|
||||
assert.deepEqual(actualResponseBody, [
|
||||
"id",
|
||||
"timestamp",
|
||||
"symbol",
|
||||
"name",
|
||||
"document"
|
||||
])
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("#listTokenById", () => {
|
||||
it("should GET /list/:tokenId", done => {
|
||||
const mockRequest = httpMocks.createRequest({
|
||||
method: "GET",
|
||||
url:
|
||||
"/list/259908ae44f46ef585edef4bcc1e50dc06e4c391ac4be929fae27235b8158cf1"
|
||||
})
|
||||
const mockResponse = httpMocks.createResponse({
|
||||
eventEmitter: require("events").EventEmitter
|
||||
})
|
||||
slpRoute(mockRequest, mockResponse)
|
||||
|
||||
mockResponse.on("end", () => {
|
||||
const actualResponseBody = Object.keys(
|
||||
JSON.parse(mockResponse._getData())
|
||||
)
|
||||
assert.deepEqual(actualResponseBody, [
|
||||
"id",
|
||||
"timestamp",
|
||||
"symbol",
|
||||
"name",
|
||||
"document"
|
||||
])
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("#balancesForAddress", () => {
|
||||
it("should GET /balancesForAddress/:address", done => {
|
||||
const mockRequest = httpMocks.createRequest({
|
||||
method: "GET",
|
||||
url:
|
||||
"/balancesForAddress/simpleledger:qz9tzs6d5097ejpg279rg0rnlhz546q4fsnck9wh5m"
|
||||
})
|
||||
const mockResponse = httpMocks.createResponse({
|
||||
eventEmitter: require("events").EventEmitter
|
||||
})
|
||||
slpRoute(mockRequest, mockResponse)
|
||||
|
||||
mockResponse.on("end", () => {
|
||||
const actualResponseBody = Object.keys(
|
||||
JSON.parse(mockResponse._getData())
|
||||
)
|
||||
assert.deepEqual(actualResponseBody, [
|
||||
"satoshis_available",
|
||||
"satoshis_locked_in_minting_baton",
|
||||
"satoshis_locked_in_token",
|
||||
"1cda254d0a995c713b7955298ed246822bee487458cd9747a91d9e81d9d28125",
|
||||
"047918c612e94cce03876f1ad2bd6c9da43b586026811d9b0d02c3c3e910f972",
|
||||
"slpAddress",
|
||||
"cashAddress",
|
||||
"legacyAddress"
|
||||
])
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("#balanceForAddressById", () => {
|
||||
it("should GET /balance/:address/:id", done => {
|
||||
const mockRequest = httpMocks.createRequest({
|
||||
method: "GET",
|
||||
url:
|
||||
"/balance/simpleledger:qz9tzs6d5097ejpg279rg0rnlhz546q4fsnck9wh5m/1cda254d0a995c713b7955298ed246822bee487458cd9747a91d9e81d9d28125"
|
||||
})
|
||||
const mockResponse = httpMocks.createResponse({
|
||||
eventEmitter: require("events").EventEmitter
|
||||
})
|
||||
slpRoute(mockRequest, mockResponse)
|
||||
|
||||
mockResponse.on("end", () => {
|
||||
const actualResponseBody = Object.keys(
|
||||
JSON.parse(mockResponse._getData())
|
||||
)
|
||||
assert.deepEqual(actualResponseBody, [
|
||||
"id",
|
||||
"timestamp",
|
||||
"symbol",
|
||||
"name",
|
||||
"document",
|
||||
"balance",
|
||||
"slpAddress",
|
||||
"cashAddress",
|
||||
"legacyAddress"
|
||||
])
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
//
|
||||
// describe("#balancesForToken", () => {
|
||||
// it("should GET /balancesForToken/:tokenId", done => {
|
||||
// const mockRequest = httpMocks.createRequest({
|
||||
// method: "GET",
|
||||
// url:
|
||||
// "/balancesForToken/d7c32d972a21b664f60b5fc422900179d8883dec7bd61418434aa12b09b99c12"
|
||||
// })
|
||||
// const mockResponse = httpMocks.createResponse({
|
||||
// eventEmitter: require("events").EventEmitter
|
||||
// })
|
||||
// slpRoute(mockRequest, mockResponse)
|
||||
//
|
||||
// mockResponse.on("end", () => {
|
||||
// const actualResponseBody = Object.keys(
|
||||
// JSON.parse(mockResponse._getData())[0]
|
||||
// )
|
||||
// assert.deepEqual(actualResponseBody, ["balance", "address"])
|
||||
// done()
|
||||
// })
|
||||
// })
|
||||
// })
|
||||
|
||||
// TODO: Why does this test time out?
|
||||
// describe("#addressConvert", () => {
|
||||
// it("should GET /address/convert/:address", done => {
|
||||
// const mockRequest = httpMocks.createRequest({
|
||||
// method: "GET",
|
||||
// url:
|
||||
// "/address/convert/simpleledger:qz9tzs6d5097ejpg279rg0rnlhz546q4fsnck9wh5m"
|
||||
// })
|
||||
// const mockResponse = httpMocks.createResponse({
|
||||
// eventEmitter: require("events").EventEmitter
|
||||
// })
|
||||
// slpRoute(mockRequest, mockResponse)
|
||||
//
|
||||
// mockResponse.on("end", () => {
|
||||
// const actualResponseBody = Object.keys(
|
||||
// JSON.parse(mockResponse._getData())
|
||||
// )
|
||||
// assert.deepEqual(actualResponseBody, [
|
||||
// "slpAddress",
|
||||
// "cashAddress",
|
||||
// "legacyAddress"
|
||||
// ])
|
||||
// done()
|
||||
// })
|
||||
// })
|
||||
// })
|
||||
})
|
||||
@@ -0,0 +1,96 @@
|
||||
"use strict"
|
||||
|
||||
//const chai = require("chai");
|
||||
const assert = require("assert")
|
||||
const httpMocks = require("node-mocks-http")
|
||||
const transactionRoute = require("../../dist/routes/v1/transaction")
|
||||
|
||||
describe("#TransactionRouter", () => {
|
||||
describe("#root", () => {
|
||||
it("should return 'transaction' for GET /", () => {
|
||||
const mockRequest = httpMocks.createRequest({
|
||||
method: "GET",
|
||||
url: "/"
|
||||
})
|
||||
const mockResponse = httpMocks.createResponse()
|
||||
transactionRoute(mockRequest, mockResponse)
|
||||
const actualResponseBody = mockResponse._getData()
|
||||
const expectedResponseBody = {
|
||||
status: "transaction"
|
||||
}
|
||||
assert.deepEqual(JSON.parse(actualResponseBody), expectedResponseBody)
|
||||
})
|
||||
})
|
||||
|
||||
describe("#TransactionDetails", () => {
|
||||
it("should GET /details/:txid single txid", done => {
|
||||
const mockRequest = httpMocks.createRequest({
|
||||
method: "GET",
|
||||
url:
|
||||
'/details/["78b5847f469f3e96b68c49097261d19c10ca5830c1e883333eb80e9252d9df86"%5D'
|
||||
})
|
||||
const mockResponse = httpMocks.createResponse({
|
||||
eventEmitter: require("events").EventEmitter
|
||||
})
|
||||
transactionRoute(mockRequest, mockResponse)
|
||||
|
||||
mockResponse.on("end", () => {
|
||||
const actualResponseBody = Object.keys(
|
||||
JSON.parse(mockResponse._getData())[0]
|
||||
)
|
||||
assert.deepEqual(actualResponseBody, [
|
||||
"txid",
|
||||
"version",
|
||||
"locktime",
|
||||
"vin",
|
||||
"vout",
|
||||
"blockhash",
|
||||
"blockheight",
|
||||
"confirmations",
|
||||
"time",
|
||||
"blocktime",
|
||||
"valueOut",
|
||||
"size",
|
||||
"valueIn",
|
||||
"fees"
|
||||
])
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
it("should GET /details/:txid array", done => {
|
||||
const mockRequest = httpMocks.createRequest({
|
||||
method: "GET",
|
||||
url:
|
||||
'/details/["113f1fe1c454a56436d4f93c7c6e315d1ed985d111299e9c2a3e2d3d1e9f177f", "f813f112cadd8b32670486dedcf81b4c2242c967759c9b61dee20b7e0830bb85"%5D'
|
||||
})
|
||||
const mockResponse = httpMocks.createResponse({
|
||||
eventEmitter: require("events").EventEmitter
|
||||
})
|
||||
transactionRoute(mockRequest, mockResponse)
|
||||
|
||||
mockResponse.on("end", () => {
|
||||
const actualResponseBody = Object.keys(
|
||||
JSON.parse(mockResponse._getData())[0]
|
||||
)
|
||||
assert.deepEqual(actualResponseBody, [
|
||||
"txid",
|
||||
"version",
|
||||
"locktime",
|
||||
"vin",
|
||||
"vout",
|
||||
"blockhash",
|
||||
"blockheight",
|
||||
"confirmations",
|
||||
"time",
|
||||
"blocktime",
|
||||
"valueOut",
|
||||
"size",
|
||||
"valueIn",
|
||||
"fees"
|
||||
])
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,53 @@
|
||||
"use strict"
|
||||
|
||||
//const chai = require("chai");
|
||||
const assert = require("assert")
|
||||
const httpMocks = require("node-mocks-http")
|
||||
const utilRoute = require("../../dist/routes/v1/util")
|
||||
|
||||
describe("#UtilRouter", () => {
|
||||
describe("#root", () => {
|
||||
it("should return 'util' for GET /", () => {
|
||||
const mockRequest = httpMocks.createRequest({
|
||||
method: "GET",
|
||||
url: "/"
|
||||
})
|
||||
const mockResponse = httpMocks.createResponse()
|
||||
utilRoute(mockRequest, mockResponse)
|
||||
const actualResponseBody = mockResponse._getData()
|
||||
const expectedResponseBody = {
|
||||
status: "util"
|
||||
}
|
||||
assert.deepEqual(JSON.parse(actualResponseBody), expectedResponseBody)
|
||||
})
|
||||
})
|
||||
|
||||
describe("#ValidateAddress", () => {
|
||||
it("should GET /validateAddress/:address", done => {
|
||||
const mockRequest = httpMocks.createRequest({
|
||||
method: "GET",
|
||||
url:
|
||||
"/validateAddress/bitcoincash:qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c"
|
||||
})
|
||||
const mockResponse = httpMocks.createResponse({
|
||||
eventEmitter: require("events").EventEmitter
|
||||
})
|
||||
utilRoute(mockRequest, mockResponse)
|
||||
|
||||
mockResponse.on("end", () => {
|
||||
const actualResponseBody = Object.keys(
|
||||
JSON.parse(mockResponse._getData())
|
||||
)
|
||||
assert.deepEqual(actualResponseBody, [
|
||||
"isvalid",
|
||||
"address",
|
||||
"scriptPubKey",
|
||||
"ismine",
|
||||
"iswatchonly",
|
||||
"isscript"
|
||||
])
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
+1373
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,610 @@
|
||||
"use strict"
|
||||
|
||||
const blockRoute = require("../../dist/routes/v2/block")
|
||||
const chai = require("chai")
|
||||
const assert = chai.assert
|
||||
const nock = require("nock") // HTTP mocking
|
||||
|
||||
let originalEnvVars // Used during transition from integration to unit tests.
|
||||
|
||||
// Mocking data.
|
||||
const { mockReq, mockRes } = require("./mocks/express-mocks")
|
||||
const mockData = require("./mocks/block-mock")
|
||||
|
||||
// Used for debugging.
|
||||
const util = require("util")
|
||||
util.inspect.defaultOptions = { depth: 1 }
|
||||
|
||||
describe("#Block", () => {
|
||||
let req, res
|
||||
|
||||
before(() => {
|
||||
// Save existing environment variables.
|
||||
originalEnvVars = {
|
||||
BITCOINCOM_BASEURL: process.env.BITCOINCOM_BASEURL,
|
||||
RPC_BASEURL: process.env.RPC_BASEURL,
|
||||
RPC_USERNAME: process.env.RPC_USERNAME,
|
||||
RPC_PASSWORD: process.env.RPC_PASSWORD
|
||||
}
|
||||
|
||||
// Set default environment variables for unit tests.
|
||||
if (!process.env.TEST) process.env.TEST = "unit"
|
||||
if (process.env.TEST === "unit") {
|
||||
process.env.BITCOINCOM_BASEURL = "http://fakeurl/api/"
|
||||
process.env.RPC_BASEURL = "http://fakeurl/api"
|
||||
process.env.RPC_USERNAME = "fakeusername"
|
||||
process.env.RPC_PASSWORD = "fakepassword"
|
||||
}
|
||||
})
|
||||
|
||||
// Setup the mocks before each test.
|
||||
beforeEach(() => {
|
||||
// Mock the req and res objects used by Express routes.
|
||||
req = mockReq
|
||||
res = mockRes
|
||||
|
||||
// Explicitly reset the parmas and body.
|
||||
req.params = {}
|
||||
req.body = {}
|
||||
|
||||
// Activate nock if it's inactive.
|
||||
if (!nock.isActive()) nock.activate()
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
// Clean up HTTP mocks.
|
||||
nock.cleanAll() // clear interceptor list.
|
||||
nock.restore()
|
||||
})
|
||||
|
||||
after(() => {
|
||||
// Restore any pre-existing environment variables.
|
||||
process.env.BITCOINCOM_BASEURL = originalEnvVars.BITCOINCOM_BASEURL
|
||||
process.env.RPC_BASEURL = originalEnvVars.RPC_BASEURL
|
||||
process.env.RPC_USERNAME = originalEnvVars.RPC_USERNAME
|
||||
process.env.RPC_PASSWORD = originalEnvVars.RPC_PASSWORD
|
||||
})
|
||||
|
||||
describe("#root", () => {
|
||||
// root route handler.
|
||||
const root = blockRoute.testableComponents.root
|
||||
|
||||
it("should respond to GET for base route", async () => {
|
||||
const result = root(req, res)
|
||||
|
||||
assert.equal(result.status, "block", "Returns static string")
|
||||
})
|
||||
})
|
||||
|
||||
describe("#detailsByHashSingle", () => {
|
||||
const detailsByHash = blockRoute.testableComponents.detailsByHashSingle
|
||||
|
||||
it("should throw an error for an empty hash", async () => {
|
||||
req.params.hash = ""
|
||||
|
||||
const result = await detailsByHash(req, res)
|
||||
|
||||
assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
|
||||
assert.include(
|
||||
result.error,
|
||||
"hash must not be empty",
|
||||
"Proper error message"
|
||||
)
|
||||
})
|
||||
|
||||
it("should throw 50X when network issues", async () => {
|
||||
// Save the existing RPC URL.
|
||||
const savedUrl = process.env.BITCOINCOM_BASEURL
|
||||
|
||||
// Manipulate the URL to cause a 500 network error.
|
||||
process.env.BITCOINCOM_BASEURL = "http://fakeurl/api/"
|
||||
|
||||
req.params.hash = "abc123"
|
||||
const result = await detailsByHash(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
// Restore the saved URL.
|
||||
process.env.BITCOINCOM_BASEURL = savedUrl
|
||||
|
||||
assert.isAbove(res.statusCode, 499, "HTTP status code 50X expected.")
|
||||
//assert.include(result.error, "ENOTFOUND", "Error message expected")
|
||||
})
|
||||
|
||||
it("should throw an error for invalid hash", async () => {
|
||||
req.params.hash = "abc123"
|
||||
|
||||
// Mock the Insight URL for unit tests.
|
||||
if (process.env.TEST === "unit") {
|
||||
nock(`${process.env.BITCOINCOM_BASEURL}`)
|
||||
.get(`/block/${req.params.hash}`)
|
||||
.reply(404, "Not found")
|
||||
}
|
||||
|
||||
const result = await detailsByHash(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.include(result.error, "Not found", "Proper error message")
|
||||
})
|
||||
|
||||
it("should GET /detailsByHash/:hash", async () => {
|
||||
req.params.hash =
|
||||
"00000000000000645dec6503d3f5eafb0d2537a7a28f181d721dec7c44154c79"
|
||||
|
||||
// Mock the Insight URL for unit tests.
|
||||
if (process.env.TEST === "unit") {
|
||||
nock(`${process.env.BITCOINCOM_BASEURL}`)
|
||||
.get(`/block/${req.params.hash}`)
|
||||
.reply(200, mockData.mockBlockDetails)
|
||||
}
|
||||
|
||||
const result = await detailsByHash(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.hasAnyKeys(result, [
|
||||
"hash",
|
||||
"size",
|
||||
"height",
|
||||
"version",
|
||||
"merkleroot",
|
||||
"tx",
|
||||
"time",
|
||||
"nonce",
|
||||
"bits",
|
||||
"difficulty",
|
||||
"chainwork",
|
||||
"confirmations",
|
||||
"previousblockhash",
|
||||
"nextblockhash",
|
||||
"reward",
|
||||
"isMainChain",
|
||||
"poolInfo"
|
||||
])
|
||||
assert.isArray(result.tx)
|
||||
})
|
||||
})
|
||||
|
||||
describe("#detailsByHashBulk", () => {
|
||||
// details route handler.
|
||||
const detailsByHashBulk = blockRoute.testableComponents.detailsByHashBulk
|
||||
|
||||
it("should throw an error for an empty body", async () => {
|
||||
req.body = {}
|
||||
|
||||
const result = await detailsByHashBulk(req, res)
|
||||
|
||||
assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
|
||||
assert.include(
|
||||
result.error,
|
||||
"hashes needs to be an array",
|
||||
"Proper error message"
|
||||
)
|
||||
})
|
||||
|
||||
it("should error on non-array single address", async () => {
|
||||
req.body = {
|
||||
hashes:
|
||||
"00000000000000645dec6503d3f5eafb0d2537a7a28f181d721dec7c44154c79"
|
||||
}
|
||||
|
||||
const result = await detailsByHashBulk(req, res)
|
||||
|
||||
assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
|
||||
assert.include(
|
||||
result.error,
|
||||
"hashes needs to be an array",
|
||||
"Proper error message"
|
||||
)
|
||||
})
|
||||
|
||||
it("should throw 400 error if addresses array is too large", async () => {
|
||||
const testArray = []
|
||||
for (var i = 0; i < 25; i++) testArray.push("")
|
||||
|
||||
req.body.hashes = testArray
|
||||
|
||||
const result = await detailsByHashBulk(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.hasAllKeys(result, ["error"])
|
||||
assert.include(result.error, "Array too large")
|
||||
})
|
||||
|
||||
it("should throw an error for an invalid hash", async () => {
|
||||
req.body = {
|
||||
hashes: [`abc123`]
|
||||
}
|
||||
|
||||
const result = await detailsByHashBulk(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
|
||||
assert.include(result.error, "Invalid hash", "Proper error message")
|
||||
})
|
||||
|
||||
it("should throw 500 when network issues", async () => {
|
||||
const savedUrl = process.env.BITCOINCOM_BASEURL
|
||||
|
||||
try {
|
||||
req.body = {
|
||||
hashes: [
|
||||
"00000000000000645dec6503d3f5eafb0d2537a7a28f181d721dec7c44154c79"
|
||||
]
|
||||
}
|
||||
|
||||
// Switch the Insight URL to something that will error out.
|
||||
process.env.BITCOINCOM_BASEURL = "http://fakeurl/api/"
|
||||
|
||||
const result = await detailsByHashBulk(req, res)
|
||||
|
||||
// Restore the saved URL.
|
||||
process.env.BITCOINCOM_BASEURL = savedUrl
|
||||
|
||||
assert.equal(res.statusCode, 500, "HTTP status code 500 expected.")
|
||||
assert.include(result.error, "ENOTFOUND", "Error message expected")
|
||||
} catch (err) {
|
||||
// Restore the saved URL.
|
||||
process.env.BITCOINCOM_BASEURL = savedUrl
|
||||
}
|
||||
})
|
||||
|
||||
it("should get details for a single hash", async () => {
|
||||
req.body = {
|
||||
hashes: [
|
||||
"00000000000000645dec6503d3f5eafb0d2537a7a28f181d721dec7c44154c79"
|
||||
]
|
||||
}
|
||||
|
||||
// Mock the Insight URL for unit tests.
|
||||
if (process.env.TEST === "unit") {
|
||||
nock(`${process.env.BITCOINCOM_BASEURL}`)
|
||||
.get(`/block/${req.body.hashes[0]}`)
|
||||
.reply(200, mockData.mockBlockDetails)
|
||||
}
|
||||
|
||||
// Call the details API.
|
||||
const result = await detailsByHashBulk(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
// Assert that required fields exist in the returned object.
|
||||
assert.equal(result.length, 1, "Array with one entry")
|
||||
assert.hasAllKeys(result[0], [
|
||||
"bits",
|
||||
"chainwork",
|
||||
"confirmations",
|
||||
"difficulty",
|
||||
"hash",
|
||||
"height",
|
||||
"isMainChain",
|
||||
"merkleroot",
|
||||
"nextblockhash",
|
||||
"nonce",
|
||||
"poolInfo",
|
||||
"previousblockhash",
|
||||
"reward",
|
||||
"size",
|
||||
"time",
|
||||
"tx",
|
||||
"version"
|
||||
])
|
||||
})
|
||||
|
||||
it("should get details for multiple hashes", async () => {
|
||||
req.body = {
|
||||
hashes: [
|
||||
`00000000000000645dec6503d3f5eafb0d2537a7a28f181d721dec7c44154c79`,
|
||||
`00000000c2b2c19cf499f57d5b0f724c6df753330d7acc7d4a8ebe412d427bd0`
|
||||
]
|
||||
}
|
||||
|
||||
// Mock the Insight URL for unit tests.
|
||||
if (process.env.TEST === "unit") {
|
||||
nock(`${process.env.BITCOINCOM_BASEURL}`)
|
||||
.get(`/block/${req.body.hashes[0]}`)
|
||||
.reply(200, mockData.mockBlockDetails)
|
||||
|
||||
nock(`${process.env.BITCOINCOM_BASEURL}`)
|
||||
.get(`/block/${req.body.hashes[1]}`)
|
||||
.reply(200, mockData.mockBlockDetails)
|
||||
}
|
||||
|
||||
// Call the details API.
|
||||
const result = await detailsByHashBulk(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.equal(result.length, 2, "2 outputs for 2 inputs")
|
||||
})
|
||||
|
||||
it("should throw an error if hash not found", async () => {
|
||||
req.body = {
|
||||
hashes: [
|
||||
`00000000000000645dec6503d3f5eafb0d2537a7a28f181d721dec7c44abcdef`
|
||||
]
|
||||
}
|
||||
|
||||
// Mock the Insight URL for unit tests.
|
||||
if (process.env.TEST === "unit") {
|
||||
nock(`${process.env.BITCOINCOM_BASEURL}`)
|
||||
.get(`/block/${req.body.hashes[0]}`)
|
||||
//.reply(404, { error: { message: "Not Found" } })
|
||||
.reply(404, "Not found")
|
||||
}
|
||||
|
||||
const result = await detailsByHashBulk(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.equal(res.statusCode, 404, "HTTP status code 404 expected.")
|
||||
assert.include(result.error, "Not found", "Proper error message")
|
||||
})
|
||||
})
|
||||
|
||||
describe("Block Details By Height", () => {
|
||||
// block route handler.
|
||||
const detailsByHeight = blockRoute.testableComponents.detailsByHeightSingle
|
||||
|
||||
it("should throw an error for an empty height", async () => {
|
||||
req.params.height = ""
|
||||
|
||||
const result = await detailsByHeight(req, res)
|
||||
|
||||
assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
|
||||
assert.include(
|
||||
result.error,
|
||||
"height must not be empty",
|
||||
"Proper error message"
|
||||
)
|
||||
})
|
||||
|
||||
it("should throw 500 when network issues", async () => {
|
||||
// Save the existing RPC URL.
|
||||
const savedUrl = process.env.BITCOINCOM_BASEURL
|
||||
const savedUrl2 = process.env.RPC_BASEURL
|
||||
|
||||
// Manipulate the URL to cause a 500 network error.
|
||||
process.env.BITCOINCOM_BASEURL = "http://fakeurl/api/"
|
||||
process.env.RPC_BASEURL = "http://fakeurl/api/"
|
||||
|
||||
req.params.height = "abc123"
|
||||
const result = await detailsByHeight(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
// Restore the saved URL.
|
||||
process.env.BITCOINCOM_BASEURL = savedUrl
|
||||
process.env.RPC_BASEURL = savedUrl2
|
||||
|
||||
assert.isAbove(
|
||||
res.statusCode,
|
||||
499,
|
||||
"HTTP status code 500 or great expected."
|
||||
)
|
||||
//assert.include(result.error, "ENOTFOUND", "Error message expected")
|
||||
})
|
||||
|
||||
it("should throw an error for invalid height", async () => {
|
||||
req.params.height = "abc123"
|
||||
|
||||
// Mock the RPC call for unit tests.
|
||||
if (process.env.TEST === "unit") {
|
||||
nock(`${process.env.RPC_BASEURL}`)
|
||||
.post(``)
|
||||
.reply(500, {
|
||||
error: {
|
||||
code: -1,
|
||||
message: "JSON value is not an integer as expected"
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const result = await detailsByHeight(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
|
||||
assert.include(
|
||||
result.error,
|
||||
"JSON value is not an integer as expected",
|
||||
"Proper error message"
|
||||
)
|
||||
})
|
||||
|
||||
it("should GET /detailsByHeight/:height", async () => {
|
||||
// Mock the RPC call for unit tests.
|
||||
if (process.env.TEST === "unit") {
|
||||
nock(`${process.env.RPC_BASEURL}`)
|
||||
.post(``)
|
||||
.reply(200, { result: mockData.mockBlockHash })
|
||||
}
|
||||
|
||||
// Mock the Insight URL for unit tests.
|
||||
if (process.env.TEST === "unit") {
|
||||
nock(`${process.env.BITCOINCOM_BASEURL}`)
|
||||
.get(
|
||||
`/block/00000000000000645dec6503d3f5eafb0d2537a7a28f181d721dec7c44154c79`
|
||||
)
|
||||
.reply(200, mockData.mockBlockDetails)
|
||||
}
|
||||
|
||||
req.params.height = 500000
|
||||
|
||||
const result = await detailsByHeight(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.hasAnyKeys(result, [
|
||||
"hash",
|
||||
"size",
|
||||
"height",
|
||||
"version",
|
||||
"merkleroot",
|
||||
"tx",
|
||||
"time",
|
||||
"nonce",
|
||||
"bits",
|
||||
"difficulty",
|
||||
"chainwork",
|
||||
"confirmations",
|
||||
"previousblockhash",
|
||||
"nextblockhash",
|
||||
"reward",
|
||||
"isMainChain",
|
||||
"poolInfo"
|
||||
])
|
||||
assert.isArray(result.tx)
|
||||
})
|
||||
})
|
||||
|
||||
describe("#detailsByHeightBulk", () => {
|
||||
// details route handler.
|
||||
const detailsByHeightBulk =
|
||||
blockRoute.testableComponents.detailsByHeightBulk
|
||||
|
||||
it("should throw an error for an empty body", async () => {
|
||||
req.body = {}
|
||||
|
||||
const result = await detailsByHeightBulk(req, res)
|
||||
|
||||
assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
|
||||
assert.include(
|
||||
result.error,
|
||||
"heights needs to be an array",
|
||||
"Proper error message"
|
||||
)
|
||||
})
|
||||
|
||||
it("should error on non-array single height", async () => {
|
||||
req.body = {
|
||||
heights: 500000
|
||||
}
|
||||
|
||||
const result = await detailsByHeightBulk(req, res)
|
||||
|
||||
assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
|
||||
assert.include(
|
||||
result.error,
|
||||
"heights needs to be an array",
|
||||
"Proper error message"
|
||||
)
|
||||
})
|
||||
|
||||
it("should throw 400 error if addresses array is too large", async () => {
|
||||
const testArray = []
|
||||
for (var i = 0; i < 25; i++) testArray.push("")
|
||||
|
||||
req.body.heights = testArray
|
||||
|
||||
const result = await detailsByHeightBulk(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.hasAllKeys(result, ["error"])
|
||||
assert.include(result.error, "Array too large")
|
||||
})
|
||||
|
||||
it("should throw error for an invalid height", async () => {
|
||||
// Mock the RPC call for unit tests.
|
||||
if (process.env.TEST === "unit") {
|
||||
nock(`${process.env.RPC_BASEURL}`)
|
||||
.post(``)
|
||||
.reply(500, {
|
||||
error: {
|
||||
code: -1,
|
||||
message: "JSON value is not an integer as expected"
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
req.body.heights = [`abc123`]
|
||||
|
||||
const result = await detailsByHeightBulk(req, res)
|
||||
// console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
|
||||
})
|
||||
|
||||
it("should throw 500 when network issues", async () => {
|
||||
const savedUrl = process.env.BITCOINCOM_BASEURL
|
||||
|
||||
try {
|
||||
req.body.heights = [`500000`]
|
||||
|
||||
// Switch the Insight URL to something that will error out.
|
||||
process.env.BITCOINCOM_BASEURL = "http://fakeurl/api/"
|
||||
|
||||
const result = await detailsByHeightBulk(req, res)
|
||||
|
||||
// Restore the saved URL.
|
||||
process.env.BITCOINCOM_BASEURL = savedUrl
|
||||
|
||||
assert.equal(res.statusCode, 500, "HTTP status code 500 expected.")
|
||||
assert.include(result.error, "ENOTFOUND", "Error message expected")
|
||||
} catch (err) {
|
||||
// Restore the saved URL.
|
||||
process.env.BITCOINCOM_BASEURL = savedUrl
|
||||
}
|
||||
})
|
||||
|
||||
it("should get details for a single height", async () => {
|
||||
req.body.heights = [`500000`]
|
||||
|
||||
// Mock the Insight URL for unit tests.
|
||||
if (process.env.TEST === "unit") {
|
||||
nock(`${process.env.RPC_BASEURL}`)
|
||||
.post(``)
|
||||
.reply(200, { result: mockData.mockBlockHash })
|
||||
|
||||
nock(`${process.env.BITCOINCOM_BASEURL}`)
|
||||
.get(`/block/${mockData.mockBlockHash}`)
|
||||
.reply(200, mockData.mockBlockDetails)
|
||||
}
|
||||
|
||||
// Call the details API.
|
||||
const result = await detailsByHeightBulk(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
// Assert that required fields exist in the returned object.
|
||||
assert.equal(result.length, 1, "Array with one entry")
|
||||
assert.hasAllKeys(result[0], [
|
||||
"bits",
|
||||
"chainwork",
|
||||
"confirmations",
|
||||
"difficulty",
|
||||
"hash",
|
||||
"height",
|
||||
"isMainChain",
|
||||
"merkleroot",
|
||||
"nextblockhash",
|
||||
"nonce",
|
||||
"poolInfo",
|
||||
"previousblockhash",
|
||||
"reward",
|
||||
"size",
|
||||
"time",
|
||||
"tx",
|
||||
"version"
|
||||
])
|
||||
})
|
||||
|
||||
it("should get details for multiple block heights", async () => {
|
||||
req.body = {
|
||||
heights: [`500000`, `500001`]
|
||||
}
|
||||
|
||||
// Mock the Insight URL for unit tests.
|
||||
if (process.env.TEST === "unit") {
|
||||
nock(`${process.env.RPC_BASEURL}`)
|
||||
.post(``)
|
||||
.times(2)
|
||||
.reply(200, { result: mockData.mockBlockHash })
|
||||
|
||||
nock(`${process.env.BITCOINCOM_BASEURL}`)
|
||||
.get(`/block/${mockData.mockBlockHash}`)
|
||||
.times(2)
|
||||
.reply(200, mockData.mockBlockDetails)
|
||||
}
|
||||
|
||||
// Call the details API.
|
||||
const result = await detailsByHeightBulk(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.equal(result.length, 2, "2 outputs for 2 inputs")
|
||||
})
|
||||
})
|
||||
})
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
TESTS FOR THE CONTROL.JS LIBRARY
|
||||
|
||||
This test file uses the environment variable TEST to switch between unit
|
||||
and integration tests. By default, TEST is set to 'unit'. Set this variable
|
||||
to 'integration' to run the tests against BCH mainnet.
|
||||
|
||||
*/
|
||||
|
||||
"use strict"
|
||||
|
||||
const chai = require("chai")
|
||||
const assert = chai.assert
|
||||
const controlRoute = require("../../dist/routes/v2/control")
|
||||
const nock = require("nock") // HTTP mocking
|
||||
|
||||
let originalEnvVars // Used during transition from integration to unit tests.
|
||||
|
||||
// Mocking data.
|
||||
const { mockReq, mockRes } = require("./mocks/express-mocks")
|
||||
const mockData = require("./mocks/control-mock")
|
||||
|
||||
// Used for debugging.
|
||||
const util = require("util")
|
||||
util.inspect.defaultOptions = { depth: 1 }
|
||||
|
||||
describe("#ControlRouter", () => {
|
||||
let req, res
|
||||
|
||||
before(() => {
|
||||
// Save existing environment variables.
|
||||
originalEnvVars = {
|
||||
BITCOINCOM_BASEURL: process.env.BITCOINCOM_BASEURL,
|
||||
RPC_BASEURL: process.env.RPC_BASEURL,
|
||||
RPC_USERNAME: process.env.RPC_USERNAME,
|
||||
RPC_PASSWORD: process.env.RPC_PASSWORD
|
||||
}
|
||||
|
||||
// Set default environment variables for unit tests.
|
||||
if (!process.env.TEST) process.env.TEST = "unit"
|
||||
if (process.env.TEST === "unit") {
|
||||
process.env.BITCOINCOM_BASEURL = "http://fakeurl/api/"
|
||||
process.env.RPC_BASEURL = "http://fakeurl/api"
|
||||
process.env.RPC_USERNAME = "fakeusername"
|
||||
process.env.RPC_PASSWORD = "fakepassword"
|
||||
}
|
||||
})
|
||||
|
||||
// Setup the mocks before each test.
|
||||
beforeEach(() => {
|
||||
// Mock the req and res objects used by Express routes.
|
||||
req = mockReq
|
||||
res = mockRes
|
||||
|
||||
// Explicitly reset the parmas and body.
|
||||
req.params = {}
|
||||
req.body = {}
|
||||
req.query = {}
|
||||
|
||||
// Activate nock if it's inactive.
|
||||
if (!nock.isActive()) nock.activate()
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
// Clean up HTTP mocks.
|
||||
nock.cleanAll() // clear interceptor list.
|
||||
nock.restore()
|
||||
})
|
||||
|
||||
after(() => {
|
||||
// Restore any pre-existing environment variables.
|
||||
process.env.BITCOINCOM_BASEURL = originalEnvVars.BITCOINCOM_BASEURL
|
||||
process.env.RPC_BASEURL = originalEnvVars.RPC_BASEURL
|
||||
process.env.RPC_USERNAME = originalEnvVars.RPC_USERNAME
|
||||
process.env.RPC_PASSWORD = originalEnvVars.RPC_PASSWORD
|
||||
})
|
||||
|
||||
describe("#root", async () => {
|
||||
// root route handler.
|
||||
const root = controlRoute.testableComponents.root
|
||||
|
||||
it("should respond to GET for base route", async () => {
|
||||
const result = root(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.equal(result.status, "control", "Returns static string")
|
||||
})
|
||||
})
|
||||
|
||||
describe("#GetInfo", () => {
|
||||
const getInfo = controlRoute.testableComponents.getInfo
|
||||
|
||||
it("should throw 500 when network issues", async () => {
|
||||
// Save the existing RPC URL.
|
||||
const savedUrl = process.env.RPC_BASEURL
|
||||
|
||||
// Manipulate the URL to cause a 500 network error.
|
||||
process.env.RPC_BASEURL = "http://fakeurl/api/"
|
||||
|
||||
const result = await getInfo(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
// Restore the saved URL.
|
||||
process.env.RPC_BASEURL = savedUrl
|
||||
|
||||
assert.isAbove(
|
||||
res.statusCode,
|
||||
499,
|
||||
"HTTP status code 500 or greater expected."
|
||||
)
|
||||
//assert.include(result.error, "ENOTFOUND", "Error message expected")
|
||||
})
|
||||
|
||||
it("should get info on the full node", async () => {
|
||||
// Mock the RPC call for unit tests.
|
||||
if (process.env.TEST === "unit") {
|
||||
nock(`${process.env.RPC_BASEURL}`)
|
||||
.post(``)
|
||||
.reply(200, { result: mockData.mockGetInfo })
|
||||
}
|
||||
|
||||
const result = await getInfo(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.hasAnyKeys(result, [
|
||||
"version",
|
||||
"protocolversion",
|
||||
"blocks",
|
||||
"timeoffset",
|
||||
"connections",
|
||||
"proxy",
|
||||
"difficulty",
|
||||
"testnet",
|
||||
"paytxfee",
|
||||
"relayfee",
|
||||
"errors"
|
||||
])
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
End-to-end tests for the Address endpoint.
|
||||
These tests assume that the repo is running locally and pointed at TESTNET
|
||||
*/
|
||||
|
||||
"use strict"
|
||||
|
||||
const rp = require("request-promise")
|
||||
|
||||
const rawtransactions = require("../../../dist/routes/v2/address")
|
||||
|
||||
/*
|
||||
This unconfirmed utxo test needs to be expanded in the future to automatically
|
||||
create a transaction. For now, that is done manually and the address provided
|
||||
as a constant.
|
||||
|
||||
1. Start rest running locally, pointed at TESTNET.
|
||||
2. Fund each address with a small amount of tBCH
|
||||
3. Run this program with `node address.js`
|
||||
4. If successful, it will return the unconfirmed UTXOs.
|
||||
*/
|
||||
const addr1 = "bchtest:qpdcp5pv7qphu5tsjfgwezld9n9aq9ue6swgqpf45c"
|
||||
const addr2 = "bchtest:qzpvx999fagau0xqmvu3xvll9evapge7u5hcgeknzv"
|
||||
|
||||
async function testSingleUnconfirmed() {
|
||||
try {
|
||||
const options = {
|
||||
method: "GET",
|
||||
uri: `http://localhost:3000/v2/address/unconfirmed/${addr1}`,
|
||||
resolveWithFullResponse: true,
|
||||
json: true
|
||||
}
|
||||
|
||||
const result = await rp(options)
|
||||
// console.log(`result.body: ${JSON.stringify(result.body, null, 2)}`)
|
||||
} catch (err) {
|
||||
// console.log(`Error: `, err)
|
||||
}
|
||||
}
|
||||
testSingleUnconfirmed()
|
||||
|
||||
async function testDoubleUnconfirmed() {
|
||||
try {
|
||||
const options = {
|
||||
method: "POST",
|
||||
uri: `http://localhost:3000/v2/address/unconfirmed`,
|
||||
resolveWithFullResponse: true,
|
||||
json: true,
|
||||
body: {
|
||||
addresses: [addr1, addr2]
|
||||
}
|
||||
}
|
||||
|
||||
const result = await rp(options)
|
||||
// console.log(`result.body: ${JSON.stringify(result.body, null, 2)}`)
|
||||
} catch (err) {
|
||||
// console.log(`Error: `, err)
|
||||
}
|
||||
}
|
||||
testDoubleUnconfirmed()
|
||||
@@ -0,0 +1,29 @@
|
||||
"use strict"
|
||||
|
||||
/**
|
||||
* Read more about panda here: https://panda-suite.github.io/
|
||||
*/
|
||||
const panda = require("pandacash-core")
|
||||
|
||||
const runLocalNode = done => {
|
||||
const server = panda.server({
|
||||
// always the same mnemonic
|
||||
// mnemonic: "cigar magnet ocean purchase travel damp snack alone theme budget wagon wrong",
|
||||
seedAccounts: true,
|
||||
enableLogs: false,
|
||||
debug: false
|
||||
})
|
||||
|
||||
server.listen({
|
||||
port: 48332,
|
||||
walletPort: 48333,
|
||||
}, (err, pandaCashCore) => {
|
||||
if (err) return console.error(err)
|
||||
|
||||
done()
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
runLocalNode
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
This directory contains integration tests. To run them requires that
|
||||
a local copy of rest.bitcoin.com is running. The tests in this directory are
|
||||
exactly the same calls that end users would use for their app to interact
|
||||
directly with rest.bitcoin.com.
|
||||
|
||||
At present, this directory focuses on raw-transations. But more integration tests
|
||||
will be added.
|
||||
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
*/
|
||||
|
||||
"use strict"
|
||||
|
||||
const chai = require("chai")
|
||||
const assert = chai.assert
|
||||
const axios = require("axios")
|
||||
|
||||
// Used for debugging.
|
||||
const util = require("util")
|
||||
util.inspect.defaultOptions = { depth: 1 }
|
||||
|
||||
const SERVER = `https://rest.btctest.net/v2/`
|
||||
//const SERVER = `http://localhost:3000/v2/`
|
||||
|
||||
describe("#rate limits", () => {
|
||||
it("should get control/getInfo() with no auth", async () => {
|
||||
const options = {
|
||||
method: "GET",
|
||||
url: `${SERVER}control/getInfo`
|
||||
}
|
||||
|
||||
const result = await axios(options)
|
||||
//console.log(`result.status: ${result.status}`)
|
||||
//console.log(`result.data: ${util.inspect(result.data)}`)
|
||||
|
||||
assert.equal(result.status, 200)
|
||||
assert.hasAnyKeys(result.data, ["version"])
|
||||
})
|
||||
|
||||
it("should trigger rate-limit handler if rate limits exceeds 60 request per minute", async () => {
|
||||
try {
|
||||
// Actual rate limit is 60 per minute X 4 nodes = 240 rpm.
|
||||
const options = {
|
||||
method: "GET",
|
||||
url: `${SERVER}control/getInfo`
|
||||
}
|
||||
|
||||
const promises = []
|
||||
for (let i = 0; i < 250; i++) {
|
||||
const promise = axios(options)
|
||||
promises.push(promise)
|
||||
}
|
||||
|
||||
await Promise.all(promises)
|
||||
|
||||
assert.equal(true, false, "Unexpected result!")
|
||||
} catch (err) {
|
||||
//console.log(`err.response: ${util.inspect(err.response)}`)
|
||||
|
||||
assert.equal(err.response.status, 429)
|
||||
assert.include(err.response.data.error, "Too many requests")
|
||||
}
|
||||
})
|
||||
|
||||
it("should not trigger rate-limit handler if correct pro-tier password is used", async () => {
|
||||
try {
|
||||
const username = "BITBOX"
|
||||
|
||||
// Pro-tier is accessed by using the right password.
|
||||
const password = "BITBOX"
|
||||
//const password = "something"
|
||||
|
||||
const combined = `${username}:${password}`
|
||||
const base64Credential = Buffer.from(combined).toString("base64")
|
||||
const readyCredential = `Basic ${base64Credential}`
|
||||
|
||||
const options = {
|
||||
method: "GET",
|
||||
url: `${SERVER}control/getInfo`,
|
||||
headers: { Authorization: readyCredential }
|
||||
}
|
||||
|
||||
const promises = []
|
||||
for (let i = 0; i < 250; i++) {
|
||||
const promise = axios(options)
|
||||
promises.push(promise)
|
||||
}
|
||||
|
||||
await Promise.all(promises)
|
||||
|
||||
assert.equal(true, true, "Not throwing an error is a pass!")
|
||||
} catch (err) {
|
||||
// console.log(`err.response: ${util.inspect(err.response)}`)
|
||||
|
||||
assert.equal(
|
||||
true,
|
||||
false,
|
||||
"This error handler should not have been triggered. Is the password correct?"
|
||||
)
|
||||
}
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,191 @@
|
||||
/*
|
||||
These integration tests are intended to be run against a live local copy of
|
||||
rest.bitcoin.com. They exercise the endpoints in the same way the SDK or
|
||||
end-user application would. These tests were created to replace the parts
|
||||
removed from the swagger UI, that otherwise would have excersiced these endpoints.
|
||||
|
||||
TODO:
|
||||
-/rawtransactions/sendRawTransaction is more appropropriate for an e2e test,
|
||||
so it is omitted here.
|
||||
*/
|
||||
|
||||
"use strict"
|
||||
|
||||
const chai = require("chai")
|
||||
const assert = chai.assert
|
||||
const rawtransactions = require("../../../dist/routes/v2/rawtransactions")
|
||||
const rp = require("request-promise")
|
||||
|
||||
// Used for debugging.
|
||||
const util = require("util")
|
||||
util.inspect.defaultOptions = { depth: 1 }
|
||||
|
||||
const mockData = require("../mocks/raw-transactions-mocks")
|
||||
|
||||
describe("#Raw-Transactions", () => {
|
||||
describe("#root", () => {
|
||||
it(`should return root`, async () => {
|
||||
const options = {
|
||||
method: "GET",
|
||||
uri: `http://localhost:3000/v2/rawtransactions/`,
|
||||
resolveWithFullResponse: true,
|
||||
json: true
|
||||
}
|
||||
|
||||
const result = await rp(options)
|
||||
//console.log(`result: ${JSON.stringify(result, null, 0)}`)
|
||||
|
||||
assert.equal(result.body.status, "rawtransactions")
|
||||
})
|
||||
})
|
||||
|
||||
describe("#whCreateTx", () => {
|
||||
it(`should return tx hex`, async () => {
|
||||
const minIn = {
|
||||
txid:
|
||||
"f7ed9cf23dee85910f6269c9a101a75fcfd2f3c6fc81f17fad824ff7aaf99ab2",
|
||||
vout: 1
|
||||
}
|
||||
|
||||
const options = {
|
||||
method: "PUT",
|
||||
uri: `http://localhost:3000/v2/rawtransactions/create`,
|
||||
resolveWithFullResponse: true,
|
||||
json: true,
|
||||
body: {
|
||||
//inputs: [mockData.mockWHCreateInput],
|
||||
inputs: [minIn],
|
||||
outputs: {}
|
||||
}
|
||||
}
|
||||
|
||||
const result = await rp(options)
|
||||
//console.log(`result.body: ${JSON.stringify(result.body, null, 0)}`)
|
||||
|
||||
assert.equal(
|
||||
result.body,
|
||||
"0200000001b29af9aaf74f82ad7ff181fcc6f3d2cf5fa701a1c969620f9185ee3df29cedf70100000000ffffffff0000000000"
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe("#whOpReturn", () => {
|
||||
it(`should return tx hex`, async () => {
|
||||
const options = {
|
||||
method: "PUT",
|
||||
uri: `http://localhost:3000/v2/rawtransactions/opreturn`,
|
||||
resolveWithFullResponse: true,
|
||||
json: true,
|
||||
body: {
|
||||
rawtx: "01000000000000000000",
|
||||
payload: "00000000000000020000000006dac2c0"
|
||||
}
|
||||
}
|
||||
|
||||
const result = await rp(options)
|
||||
//console.log(`result.body: ${JSON.stringify(result.body, null, 0)}`)
|
||||
|
||||
assert.equal(
|
||||
result.body,
|
||||
"0100000000010000000000000000166a140877686300000000000000020000000006dac2c000000000"
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe("#whReference", () => {
|
||||
it(`should return tx hex`, async () => {
|
||||
const options = {
|
||||
method: "PUT",
|
||||
uri: `http://localhost:3000/v2/rawtransactions/reference`,
|
||||
resolveWithFullResponse: true,
|
||||
json: true,
|
||||
body: {
|
||||
rawtx:
|
||||
"0100000001a7a9402ecd77f3c9f745793c9ec805bfa2e14b89877581c734c774864247e6f50400000000ffffffff03aa0a0000000000001976a9146d18edfe073d53f84dd491dae1379f8fb0dfe5d488ac5c0d0000000000004751210252ce4bdd3ce38b4ebbc5a6e1343608230da508ff12d23d85b58c964204c4cef3210294cc195fc096f87d0f813a337ae7e5f961b1c8a18f1f8604a909b3a5121f065b52aeaa0a0000000000001976a914946cb2e08075bcbaf157e47bcb67eb2b2339d24288ac00000000",
|
||||
destination: "bitcoincash:qrn60nerx5zug4u4hal06atep3lzhtecvy4pxk75lf",
|
||||
amount: 0.005
|
||||
}
|
||||
}
|
||||
|
||||
const result = await rp(options)
|
||||
//console.log(`result.body: ${JSON.stringify(result.body, null, 0)}`)
|
||||
|
||||
assert.isString(result.body)
|
||||
})
|
||||
})
|
||||
|
||||
describe("#whChangeOutput", () => {
|
||||
it(`should return tx hex`, async () => {
|
||||
const options = {
|
||||
method: "PUT",
|
||||
uri: `http://localhost:3000/v2/rawtransactions/change`,
|
||||
resolveWithFullResponse: true,
|
||||
json: true,
|
||||
body: {
|
||||
rawtx:
|
||||
"0100000001b15ee60431ef57ec682790dec5a3c0d83a0c360633ea8308fbf6d5fc10a779670400000000ffffffff025c0d00000000000047512102f3e471222bb57a7d416c82bf81c627bfcd2bdc47f36e763ae69935bba4601ece21021580b888ff56feb27f17f08802ebed26258c23697d6a462d43fc13b565fda2dd52aeaa0a0000000000001976a914946cb2e08075bcbaf157e47bcb67eb2b2339d24288ac00000000",
|
||||
destination: "bitcoincash:qrn60nerx5zug4u4hal06atep3lzhtecvy4pxk75lf",
|
||||
prevtxs: [
|
||||
{
|
||||
txid:
|
||||
"6779a710fcd5f6fb0883ea3306360c3ad8c0a3c5de902768ec57ef3104e65eb1",
|
||||
vout: 4,
|
||||
scriptPubKey:
|
||||
"76a9147b25205fd98d462880a3e5b0541235831ae959e588ac",
|
||||
value: 0.00068257
|
||||
}
|
||||
],
|
||||
fee: 0.000035
|
||||
}
|
||||
}
|
||||
|
||||
const result = await rp(options)
|
||||
//console.log(`result.body: ${JSON.stringify(result.body, null, 0)}`)
|
||||
|
||||
assert.isString(result.body)
|
||||
})
|
||||
})
|
||||
|
||||
describe("#whInput", () => {
|
||||
it(`should return tx hex`, async () => {
|
||||
const options = {
|
||||
method: "PUT",
|
||||
uri: `http://localhost:3000/v2/rawtransactions/input`,
|
||||
resolveWithFullResponse: true,
|
||||
json: true,
|
||||
body: {
|
||||
txid:
|
||||
"b006729017df05eda586df9ad3f8ccfee5be340aadf88155b784d1fc0e8342ee",
|
||||
n: 0
|
||||
}
|
||||
}
|
||||
|
||||
const result = await rp(options)
|
||||
//console.log(`result.body: ${JSON.stringify(result.body, null, 0)}`)
|
||||
|
||||
assert.isString(result.body)
|
||||
})
|
||||
})
|
||||
|
||||
describe("#getRawTransaction", () => {
|
||||
it(`should return tx hex`, async () => {
|
||||
const options = {
|
||||
method: "POST",
|
||||
uri: `http://localhost:3000/v2/rawtransactions/getRawTransaction`,
|
||||
resolveWithFullResponse: true,
|
||||
json: true,
|
||||
body: {
|
||||
txids: [
|
||||
"0e3e2357e806b6cdb1f70b54c3a3a17b6714ee1f0e68bebb44a74b1efd512098"
|
||||
],
|
||||
verbose: true
|
||||
}
|
||||
}
|
||||
|
||||
const result = await rp(options)
|
||||
// console.log(`result.body: ${util.inspect(result.body)}`)
|
||||
|
||||
assert.isArray(result.body)
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,176 @@
|
||||
/*
|
||||
TESTS FOR THE MINING.TS LIBRARY
|
||||
|
||||
This test file uses the environment variable TEST to switch between unit
|
||||
and integration tests. By default, TEST is set to 'unit'. Set this variable
|
||||
to 'integration' to run the tests against BCH mainnet.
|
||||
*/
|
||||
|
||||
"use strict"
|
||||
|
||||
const chai = require("chai")
|
||||
const assert = chai.assert
|
||||
const miningRoute = require("../../dist/routes/v2/mining")
|
||||
const nock = require("nock") // HTTP mocking
|
||||
|
||||
let originalEnvVars // Used during transition from integration to unit tests.
|
||||
|
||||
// Mocking data.
|
||||
const { mockReq, mockRes } = require("./mocks/express-mocks")
|
||||
const mockData = require("./mocks/mining-mocks")
|
||||
|
||||
// Used for debugging.
|
||||
const util = require("util")
|
||||
util.inspect.defaultOptions = { depth: 1 }
|
||||
|
||||
describe("#Mining", () => {
|
||||
let req, res
|
||||
|
||||
before(() => {
|
||||
// Save existing environment variables.
|
||||
originalEnvVars = {
|
||||
BITCOINCOM_BASEURL: process.env.BITCOINCOM_BASEURL,
|
||||
RPC_BASEURL: process.env.RPC_BASEURL,
|
||||
RPC_USERNAME: process.env.RPC_USERNAME,
|
||||
RPC_PASSWORD: process.env.RPC_PASSWORD
|
||||
}
|
||||
|
||||
// Set default environment variables for unit tests.
|
||||
if (!process.env.TEST) process.env.TEST = "unit"
|
||||
if (process.env.TEST === "unit") {
|
||||
process.env.BITCOINCOM_BASEURL = "http://fakeurl/api/"
|
||||
process.env.RPC_BASEURL = "http://fakeurl/api"
|
||||
process.env.RPC_USERNAME = "fakeusername"
|
||||
process.env.RPC_PASSWORD = "fakepassword"
|
||||
}
|
||||
})
|
||||
|
||||
// Setup the mocks before each test.
|
||||
beforeEach(() => {
|
||||
// Mock the req and res objects used by Express routes.
|
||||
req = mockReq
|
||||
res = mockRes
|
||||
|
||||
// Explicitly reset the parmas and body.
|
||||
req.params = {}
|
||||
req.body = {}
|
||||
req.query = {}
|
||||
|
||||
// Activate nock if it's inactive.
|
||||
if (!nock.isActive()) nock.activate()
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
// Clean up HTTP mocks.
|
||||
nock.cleanAll() // clear interceptor list.
|
||||
nock.restore()
|
||||
})
|
||||
|
||||
after(() => {
|
||||
// Restore any pre-existing environment variables.
|
||||
process.env.BITCOINCOM_BASEURL = originalEnvVars.BITCOINCOM_BASEURL
|
||||
process.env.RPC_BASEURL = originalEnvVars.RPC_BASEURL
|
||||
process.env.RPC_USERNAME = originalEnvVars.RPC_USERNAME
|
||||
process.env.RPC_PASSWORD = originalEnvVars.RPC_PASSWORD
|
||||
})
|
||||
|
||||
describe("#root", async () => {
|
||||
// root route handler.
|
||||
const root = miningRoute.testableComponents.root
|
||||
|
||||
it("should respond to GET for base route", async () => {
|
||||
const result = root(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.equal(result.status, "mining", "Returns static string")
|
||||
})
|
||||
})
|
||||
|
||||
describe("#getMiningInfo", async () => {
|
||||
const getMiningInfo = miningRoute.testableComponents.getMiningInfo
|
||||
|
||||
it("should throw 503 when network issues", async () => {
|
||||
// Save the existing RPC URL.
|
||||
const savedUrl2 = process.env.RPC_BASEURL
|
||||
|
||||
// Manipulate the URL to cause a 500 network error.
|
||||
process.env.RPC_BASEURL = "http://fakeurl/api/"
|
||||
|
||||
const result = await getMiningInfo(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
// Restore the saved URL.
|
||||
process.env.RPC_BASEURL = savedUrl2
|
||||
|
||||
assert.isAbove(
|
||||
res.statusCode,
|
||||
499,
|
||||
"HTTP status code 500 or greater expected."
|
||||
)
|
||||
//assert.include(result.error,"Network error: Could not communicate with full node","Error message expected")
|
||||
})
|
||||
|
||||
it("should GET mining information", async () => {
|
||||
// Mock the RPC call for unit tests.
|
||||
if (process.env.TEST === "unit") {
|
||||
nock(`${process.env.RPC_BASEURL}`)
|
||||
.post(``)
|
||||
.reply(200, { result: mockData.mockMiningInfo })
|
||||
}
|
||||
|
||||
const result = await getMiningInfo(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.hasAllKeys(result, [
|
||||
"blocks",
|
||||
"currentblocksize",
|
||||
"currentblocktx",
|
||||
"difficulty",
|
||||
"blockprioritypercentage",
|
||||
"errors",
|
||||
"networkhashps",
|
||||
"pooledtx",
|
||||
"chain"
|
||||
])
|
||||
})
|
||||
})
|
||||
|
||||
describe("#getNetworkHashPS", async () => {
|
||||
const getNetworkHashPS = miningRoute.testableComponents.getNetworkHashPS
|
||||
|
||||
it("should throw 503 when network issues", async () => {
|
||||
// Save the existing RPC URL.
|
||||
const savedUrl2 = process.env.RPC_BASEURL
|
||||
|
||||
// Manipulate the URL to cause a 500 network error.
|
||||
process.env.RPC_BASEURL = "http://fakeurl/api/"
|
||||
|
||||
const result = await getNetworkHashPS(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
// Restore the saved URL.
|
||||
process.env.RPC_BASEURL = savedUrl2
|
||||
|
||||
assert.isAbove(
|
||||
res.statusCode,
|
||||
499,
|
||||
"HTTP status code 500 or greater expected."
|
||||
)
|
||||
//assert.include(result.error,"Network error: Could not communicate with full node","Error message expected")
|
||||
})
|
||||
|
||||
it("should GET Network Hash per second", async () => {
|
||||
// Mock the RPC call for unit tests.
|
||||
if (process.env.TEST === "unit") {
|
||||
nock(`${process.env.RPC_BASEURL}`)
|
||||
.post(``)
|
||||
.reply(200, { result: 517604755.6648782 })
|
||||
}
|
||||
|
||||
const result = await getNetworkHashPS(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.isNumber(result)
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
This library contains mocking data for running unit tests on the address route.
|
||||
*/
|
||||
|
||||
"use strict"
|
||||
|
||||
const mockAddressDetails = {
|
||||
addrStr: "1Fg4r9iDrEkCcDmHTy2T79EusNfhyQpu7W",
|
||||
balance: 0.00126419,
|
||||
balanceSat: 126419,
|
||||
totalReceived: 0.02175868,
|
||||
totalReceivedSat: 2175868,
|
||||
totalSent: 0.02049449,
|
||||
totalSentSat: 2049449,
|
||||
unconfirmedBalance: 0,
|
||||
unconfirmedBalanceSat: 0,
|
||||
unconfirmedTxApperances: 0,
|
||||
txApperances: 3,
|
||||
transactions: [
|
||||
"2dc053f55a666a3d2a08b1c680b704d62a55506d14ad884add87edcc56b9277d",
|
||||
"544c15ce35c0f2e808d28f29d6587f1ec9276233e29856b7f2938cf0daef0026",
|
||||
"81039b1d7b855b133f359f9dc65f776bd105650153a941675fedc504228ddbd3"
|
||||
],
|
||||
legacyAddress: "1Fg4r9iDrEkCcDmHTy2T79EusNfhyQpu7W",
|
||||
cashAddress: "bitcoincash:qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c"
|
||||
}
|
||||
|
||||
const mockUtxoDetails = [
|
||||
{
|
||||
txid: "15f6a584080b04911121fbaca7bfcf3dd64ef2bfa5a01daf31e05a296c3e5e9e",
|
||||
vout: 286,
|
||||
amount: 0.00001,
|
||||
satoshis: 1000,
|
||||
height: 546083,
|
||||
confirmations: 3490
|
||||
},
|
||||
{
|
||||
txid: "15f6a584080b04911121fbaca7bfcf3dd64ef2bfa5a01daf31e05a296c3e5e9e",
|
||||
vout: 287,
|
||||
amount: 0.00001,
|
||||
satoshis: 1000,
|
||||
height: 546083,
|
||||
confirmations: 3490
|
||||
},
|
||||
{
|
||||
txid: "15f6a584080b04911121fbaca7bfcf3dd64ef2bfa5a01daf31e05a296c3e5e9e",
|
||||
vout: 288,
|
||||
amount: 0.00001,
|
||||
satoshis: 1000,
|
||||
height: 546083,
|
||||
confirmations: 3490
|
||||
}
|
||||
]
|
||||
|
||||
const mockUnconfirmed = [
|
||||
{
|
||||
address: "1EzdL6TBbkNhnB2fYiBaKmcs5fxaoqwdAp",
|
||||
txid: "000c00a90fb5031da6e02f7625df2f8b35a4c16e6feb9fc72293e67e5ff75786",
|
||||
vout: 0,
|
||||
scriptPubKey: "76a914997fabcd94a1e2aaa13a7664362e5e7b96c169a988ac",
|
||||
amount: 0.00999626,
|
||||
satoshis: 999626,
|
||||
confirmations: 0,
|
||||
ts: 1537989425
|
||||
}
|
||||
]
|
||||
|
||||
const mockTransactions = {
|
||||
pagesTotal: 1,
|
||||
txs: [
|
||||
{
|
||||
txid: "000c00a90fb5031da6e02f7625df2f8b35a4c16e6feb9fc72293e67e5ff75786",
|
||||
version: 2,
|
||||
locktime: 549565,
|
||||
vin: [
|
||||
{
|
||||
txid:
|
||||
"45c891c6d44619fc85716ba1b593aa83ebc1e500fe611b1ab98531ea203a0f21",
|
||||
vout: 209,
|
||||
sequence: 4294967294,
|
||||
n: 0,
|
||||
scriptSig: {
|
||||
hex:
|
||||
"47304402205b136f348bedae61a87c0500979d47ab02c76f0e4aba866b94c4931fccb5d7dc0220757a141660475b0cd4cb8b1f54b1ace95105f5bea775e817b115fb589fe4477541210246daec651c506f353daa7468714399c773df42ac4d663022d0e446a3331ac64a",
|
||||
asm:
|
||||
"304402205b136f348bedae61a87c0500979d47ab02c76f0e4aba866b94c4931fccb5d7dc0220757a141660475b0cd4cb8b1f54b1ace95105f5bea775e817b115fb589fe44775[ALL|FORKID] 0246daec651c506f353daa7468714399c773df42ac4d663022d0e446a3331ac64a"
|
||||
},
|
||||
addr: "14TdovsQUL69xL5g3zSzhLpmDb93d9rU9m",
|
||||
valueSat: 1979534,
|
||||
value: 0.01979534,
|
||||
doubleSpentTxID: null
|
||||
},
|
||||
{
|
||||
txid:
|
||||
"6e5fa79547112a912adf6082c975dc80e282045193512ea369adb6bac7420674",
|
||||
vout: 147,
|
||||
sequence: 4294967294,
|
||||
n: 1,
|
||||
scriptSig: {
|
||||
hex:
|
||||
"473044022056674ac83a37d54ffec2c6d33cfc2ae2256f821b8bd818e1b6783356b49f3d28022046d3dd147c8fc51f2da5d16996a3cea1d7314e327aa1ae1017418737ed20136a4121038f23af565f68d8455e07e5c33c5cfc5114de2f478f035db23eb02f8ff5fe7f6e",
|
||||
asm:
|
||||
"3044022056674ac83a37d54ffec2c6d33cfc2ae2256f821b8bd818e1b6783356b49f3d28022046d3dd147c8fc51f2da5d16996a3cea1d7314e327aa1ae1017418737ed20136a[ALL|FORKID] 038f23af565f68d8455e07e5c33c5cfc5114de2f478f035db23eb02f8ff5fe7f6e"
|
||||
},
|
||||
addr: "1CEtC2fjELvmAzTd6MWuHb1gvuSq8x3Xpb",
|
||||
valueSat: 10466,
|
||||
value: 0.00010466,
|
||||
doubleSpentTxID: null
|
||||
}
|
||||
],
|
||||
vout: [
|
||||
{
|
||||
value: "0.00999626",
|
||||
n: 0,
|
||||
scriptPubKey: {
|
||||
hex: "76a914997fabcd94a1e2aaa13a7664362e5e7b96c169a988ac",
|
||||
asm:
|
||||
"OP_DUP OP_HASH160 997fabcd94a1e2aaa13a7664362e5e7b96c169a9 OP_EQUALVERIFY OP_CHECKSIG",
|
||||
addresses: ["1EzdL6TBbkNhnB2fYiBaKmcs5fxaoqwdAp"],
|
||||
type: "pubkeyhash"
|
||||
},
|
||||
spentTxId: null,
|
||||
spentIndex: null,
|
||||
spentHeight: null
|
||||
},
|
||||
{
|
||||
value: "0.00990000",
|
||||
n: 1,
|
||||
scriptPubKey: {
|
||||
hex: "76a914e3335e4d6babe61ea58311293c1c6bfe802801cb88ac",
|
||||
asm:
|
||||
"OP_DUP OP_HASH160 e3335e4d6babe61ea58311293c1c6bfe802801cb OP_EQUALVERIFY OP_CHECKSIG",
|
||||
addresses: ["1MiKvgaQTFCTEZbSDMZgw9ahaB52Cr4ofb"],
|
||||
type: "pubkeyhash"
|
||||
},
|
||||
spentTxId: null,
|
||||
spentIndex: null,
|
||||
spentHeight: null
|
||||
}
|
||||
],
|
||||
blockhash:
|
||||
"00000000000000000158b1a2883688873ec5ea076e3b0f576bcdfe1fd277880f",
|
||||
blockheight: 549601,
|
||||
confirmations: 5,
|
||||
time: 1537990026,
|
||||
blocktime: 1537990026,
|
||||
valueOut: 0.01989626,
|
||||
size: 372,
|
||||
valueIn: 0.0199,
|
||||
fees: 0.00000374
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
mockAddressDetails,
|
||||
mockUtxoDetails,
|
||||
mockUnconfirmed,
|
||||
mockTransactions
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
This library contains mocking data for running unit tests on the address route.
|
||||
*/
|
||||
|
||||
"use strict"
|
||||
|
||||
const mockBlockDetails = {
|
||||
hash: "00000000000000645dec6503d3f5eafb0d2537a7a28f181d721dec7c44154c79",
|
||||
size: 1319,
|
||||
height: 1267544,
|
||||
version: 536870912,
|
||||
merkleroot:
|
||||
"c2cd01ec2cf149acc7631385f89ae103d1a2ad212ab810c862d9680a811618ce",
|
||||
tx: [
|
||||
"52bfa89d449fef8070ec33e7a61f5ec8b5417ff62b050cd6a144ebce9557e0fa",
|
||||
"8988e8742d2523f667c2d1374861919e3a82903e059fec75c10795da2303b93b",
|
||||
"41def004f22b196d675566a6983ecf97611e72c48375b8ba779983d5ccd369d7",
|
||||
"8ca8efb06abb94395f8331f87e101504dcf66aee828f2111922f056971fa7502",
|
||||
"9ab409cbb203be7cf22bd6598d787fcdd5b417d885b72207ecc7253470770649"
|
||||
],
|
||||
time: 1542048973,
|
||||
nonce: 3936284753,
|
||||
bits: "1a03c148",
|
||||
difficulty: 4467892.99177529,
|
||||
chainwork: "00000000000000000000000000000000000000000000003ee27b503a064045bd",
|
||||
confirmations: 3,
|
||||
previousblockhash:
|
||||
"00000000000001891202cbe18729a02a8763cf04da0ca7aded6e6c7d9b500785",
|
||||
nextblockhash:
|
||||
"000000000000039b93b3f3403a0eb21150904b15229d998cf3788fd8bf192cc2",
|
||||
reward: 0.78125,
|
||||
isMainChain: true,
|
||||
poolInfo: {}
|
||||
}
|
||||
|
||||
const mockBlockHash =
|
||||
"00000000000000645dec6503d3f5eafb0d2537a7a28f181d721dec7c44154c79"
|
||||
|
||||
module.exports = {
|
||||
mockBlockDetails,
|
||||
mockBlockHash
|
||||
}
|
||||
@@ -0,0 +1,271 @@
|
||||
/*
|
||||
This library contains mocking data for running unit tests on the address route.
|
||||
*/
|
||||
|
||||
"use strict"
|
||||
|
||||
const mockBlockHash =
|
||||
"00000000000000645dec6503d3f5eafb0d2537a7a28f181d721dec7c44154c79"
|
||||
|
||||
const mockBlockchainInfo = {
|
||||
chain: "test",
|
||||
blocks: 1267694,
|
||||
headers: 1267694,
|
||||
bestblockhash:
|
||||
"000000000000013eaf80d1e157e32804c36a58ad0bb26ca59833880c80298780",
|
||||
difficulty: 4105763.969035785,
|
||||
mediantime: 1542131305,
|
||||
verificationprogress: 0.9999968911571566,
|
||||
chainwork: "00000000000000000000000000000000000000000000003f0443b0b5f02ce255",
|
||||
pruned: false,
|
||||
softforks: [
|
||||
{ id: "bip34", version: 2, reject: { status: true } },
|
||||
{ id: "bip66", version: 3, reject: { status: true } },
|
||||
{ id: "bip65", version: 4, reject: { status: true } }
|
||||
],
|
||||
bip9_softforks: {
|
||||
csv: {
|
||||
status: "active",
|
||||
startTime: 1456790400,
|
||||
timeout: 1493596800,
|
||||
since: 770112
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const mockChainTips = [
|
||||
{
|
||||
height: 1267696,
|
||||
hash: "000000000000035bfc43a642ebbff8cfc1e88b1d564de8b0a6c7e2797eeafb21",
|
||||
branchlen: 0,
|
||||
status: "active"
|
||||
},
|
||||
{
|
||||
height: 1267581,
|
||||
hash: "000000000001bd12e4124207682563135b21353ca3087bc6b0c409f7f9e1da91",
|
||||
branchlen: 1,
|
||||
status: "valid-fork"
|
||||
},
|
||||
{
|
||||
height: 1267375,
|
||||
hash: "00000000702036979df70236bcc45dfc72d43d5d0e6834007afa1fa627e49587",
|
||||
branchlen: 1036,
|
||||
status: "headers-only"
|
||||
},
|
||||
{
|
||||
height: 1266979,
|
||||
hash: "00000000e851abbde2174ccdc5c2508b909f81f23c4b7abeac864eee1a4891c7",
|
||||
branchlen: 1,
|
||||
status: "valid-fork"
|
||||
},
|
||||
{
|
||||
height: 1266973,
|
||||
hash: "000000007e1324d2900ed70947f89ab8fd4a267e87c9244c333215659a7370d5",
|
||||
branchlen: 1,
|
||||
status: "valid-fork"
|
||||
},
|
||||
{
|
||||
height: 1266967,
|
||||
hash: "000000000f37f12843d4800f50ec4de44dce0432e4d448242d43ff04a7a2948d",
|
||||
branchlen: 1,
|
||||
status: "valid-fork"
|
||||
},
|
||||
{
|
||||
height: 1266963,
|
||||
hash: "00000000ae11ec99e88898cbd72567cb4cb79e7fc13243357bef79632769deb4",
|
||||
branchlen: 1,
|
||||
status: "valid-fork"
|
||||
},
|
||||
{
|
||||
height: 1266962,
|
||||
hash: "000000004f97851259b4460a049e44fa5bd4beadee04a85bf81bd2e90c4f24f9",
|
||||
branchlen: 1,
|
||||
status: "valid-fork"
|
||||
},
|
||||
{
|
||||
height: 1266950,
|
||||
hash: "00000000d12a0e4a827f73ecaadb563df7e99817294939f2be8e943079dc60b2",
|
||||
branchlen: 1,
|
||||
status: "valid-fork"
|
||||
},
|
||||
{
|
||||
height: 1266944,
|
||||
hash: "00000000612d16af273217818e8e7ac5014a19f68ed04e1bc897b1be0a9c744f",
|
||||
branchlen: 1,
|
||||
status: "valid-fork"
|
||||
},
|
||||
{
|
||||
height: 1266941,
|
||||
hash: "0000000000002b91cdb15cacf3368da2c9ffce511d64092193b507dad75f4a27",
|
||||
branchlen: 1,
|
||||
status: "valid-fork"
|
||||
},
|
||||
{
|
||||
height: 1266896,
|
||||
hash: "000000000002745f67a66617b1f9f65c2dfb4c4b8a9ed9b1320b98d3ca46cbe5",
|
||||
branchlen: 1,
|
||||
status: "valid-fork"
|
||||
},
|
||||
{
|
||||
height: 1266481,
|
||||
hash: "0000000000036babee3ba7654cddb29a9fe5e85c9fbeb44bb53d5ffb694b9670",
|
||||
branchlen: 1,
|
||||
status: "valid-fork"
|
||||
},
|
||||
{
|
||||
height: 1266452,
|
||||
hash: "00000000502c3ab1490e0839780a4b441bbe21507c454545941e6adcde73c2ff",
|
||||
branchlen: 1,
|
||||
status: "valid-fork"
|
||||
},
|
||||
{
|
||||
height: 1266336,
|
||||
hash: "000000001c9a0b7cd9eb2210f69d5a9a3f4546ba3707deb40993d729190582d7",
|
||||
branchlen: 10,
|
||||
status: "headers-only"
|
||||
},
|
||||
{
|
||||
height: 1266097,
|
||||
hash: "000000000028ac0fbd18afe6f001f70cb7549bd2b3082d754dde88ee236368a2",
|
||||
branchlen: 1,
|
||||
status: "valid-fork"
|
||||
},
|
||||
{
|
||||
height: 1265522,
|
||||
hash: "00000000000000c6df7a2063030e6ce51399e470cc46e4bf6d67aa3f0feca98d",
|
||||
branchlen: 1,
|
||||
status: "valid-fork"
|
||||
},
|
||||
{
|
||||
height: 1265470,
|
||||
hash: "0000000000168e6442a595a02340fccf8dc2b0e8912c632d39e1f870685f6d7c",
|
||||
branchlen: 2,
|
||||
status: "valid-fork"
|
||||
},
|
||||
{
|
||||
height: 1265275,
|
||||
hash: "000000008bc2b37ae6af1b886b52e7e1c1122c12badc4ae6c13df64f789267cf",
|
||||
branchlen: 11027,
|
||||
status: "headers-only"
|
||||
},
|
||||
{
|
||||
height: 1265257,
|
||||
hash: "00000000005bc3e9973d7273211eab02ae02549c7ebae48764c0bd648d4d7bbe",
|
||||
branchlen: 114,
|
||||
status: "valid-fork"
|
||||
},
|
||||
{
|
||||
height: 1265254,
|
||||
hash: "0000000000e5b909d3541857315e9ee103b042d9ba661f25cc3e8fb25a96c8ce",
|
||||
branchlen: 111,
|
||||
status: "valid-fork"
|
||||
},
|
||||
{
|
||||
height: 1265245,
|
||||
hash: "000000000066eb8832f6f990baceb379536f437216e22475a6c1b9133d250cb8",
|
||||
branchlen: 102,
|
||||
status: "valid-fork"
|
||||
},
|
||||
{
|
||||
height: 1264455,
|
||||
hash: "00000000000001befc1bb17a23208d0b77b2449e37093ce8fbb5e346b19cafcc",
|
||||
branchlen: 1,
|
||||
status: "valid-headers"
|
||||
},
|
||||
{
|
||||
height: 1264373,
|
||||
hash: "00000000000001ed3747e04fb95054cac0358fb4d8009d1999fc3ea34413e84a",
|
||||
branchlen: 175,
|
||||
status: "valid-fork"
|
||||
},
|
||||
{
|
||||
height: 1263912,
|
||||
hash: "00000000000004635aecbcb97edcd6f5396483338838cb40da804eb354c68bde",
|
||||
branchlen: 1,
|
||||
status: "valid-fork"
|
||||
},
|
||||
{
|
||||
height: 1262906,
|
||||
hash: "00000000b31643d92a3e7c38e9755844fc8607e3f1055580a8ff28854e8a8ece",
|
||||
branchlen: 1,
|
||||
status: "valid-fork"
|
||||
},
|
||||
{
|
||||
height: 1255749,
|
||||
hash: "000000001dde5b015a99137f4cba87871370f4b6fcfbcc8b126547e6c33177da",
|
||||
branchlen: 129,
|
||||
status: "headers-only"
|
||||
},
|
||||
{
|
||||
height: 1188789,
|
||||
hash: "00000000af942ce4eb60b3213cbcb7c98a7330f1f8f1adb4b6376f5e822e15b2",
|
||||
branchlen: 92,
|
||||
status: "headers-only"
|
||||
}
|
||||
]
|
||||
|
||||
const mockMempoolInfo = {
|
||||
size: 87,
|
||||
bytes: 16816,
|
||||
usage: 66408,
|
||||
maxmempool: 300000000,
|
||||
mempoolminfee: 0
|
||||
}
|
||||
|
||||
const mockRawMempool = [
|
||||
"db045bc3bd1088fa91f5ebb05c35cb9e2a91a22377f79b465cc6920b9893123c",
|
||||
"6b3df7febf2b9834f1409155f88b866dd516b36376eae00e2b455df82e290405"
|
||||
]
|
||||
|
||||
const mockBlockHeaderConcise =
|
||||
"0000ff7f7d217c9b7845ea8b50d620c59a1bf7c276566406e9b7bc7e463e0000000000006d70322c0b697c1c81d2744f87f09f1e9780ba5d30338952e2cdc64e60456f8423bb0a5ceafa091a3e843526"
|
||||
|
||||
const mockBlockHeader = {
|
||||
hash: "00000000000008c3679777df34f1a09565f98b2400a05b7c8da72525fdca3900",
|
||||
confirmations: 7,
|
||||
height: 1272859,
|
||||
version: 2147418112,
|
||||
versionHex: "7fff0000",
|
||||
merkleroot:
|
||||
"846f45604ec6cde2528933305dba80971e9ff0874f74d2811c7c690b2c32706d",
|
||||
time: 1544207139,
|
||||
mediantime: 1544202884,
|
||||
nonce: 641041470,
|
||||
bits: "1a09faea",
|
||||
difficulty: 1681035.704111868,
|
||||
chainwork: "00000000000000000000000000000000000000000000003fc4752e608403be04",
|
||||
previousblockhash:
|
||||
"0000000000003e467ebcb7e906645676c2f71b9ac520d6508bea45789b7c217d",
|
||||
nextblockhash:
|
||||
"00000000000006899041cdfd6c0b73a97730c362346dde479b77414ad7f25ace"
|
||||
}
|
||||
|
||||
const mockTxOut = {
|
||||
bestblock: "00000000003a7f19730dd9f172d7466658a5c8833dd03ed8f4ba36e3d857b5e7",
|
||||
confirmations: 10,
|
||||
value: 0.0001,
|
||||
scriptPubKey: {
|
||||
asm:
|
||||
"OP_DUP OP_HASH160 0ee020c07f39526ac5505c54fa1ab98490979b83 OP_EQUALVERIFY OP_CHECKSIG",
|
||||
hex: "76a9140ee020c07f39526ac5505c54fa1ab98490979b8388ac",
|
||||
reqSigs: 1,
|
||||
type: "pubkeyhash",
|
||||
addresses: ["bchtest:qq8wqgxq0uu4y6k92pw9f7s6hxzfp9umsvtg39pzqf"]
|
||||
},
|
||||
coinbase: false
|
||||
}
|
||||
|
||||
const mockTxOutProof =
|
||||
"000000200798039affceb7a381e15dc62443c286efe7cae852393b656807000000000000cf9a7d6c654fd1c4558229a619a550ff749b373fa0f0027eed68b1abf6175d5c07c50f5cffff001d0452403b34000000070d0765da76980d542b5670d27ccda9e717073270f8921ad017deb7ee83fe6c4c22830a48cc8392197f1742a3d81805bd2aa4eb7469f38c74f674429d682cb87efcff1713fd0c388a50f0d11adf05363397ef79d16cdb786d47c941c2cb89f2588f42aced9c05f4203b4440616a9e4266ec47909b9580a643f402b5d4e82cc3cddd73df05a33abf6af3975d973d3033d10c4168a73d58d01f685a96d5a2519cd0de9c77faf3f8725ddf155cbdc8ab8102f173e2d0a0d74767f3bff22f588158d6d5bc71c079c7659cc864819c43877635007650502eb4060fcc9feec3280a41d602ad0a"
|
||||
|
||||
module.exports = {
|
||||
mockBlockHash,
|
||||
mockBlockchainInfo,
|
||||
mockChainTips,
|
||||
mockMempoolInfo,
|
||||
mockRawMempool,
|
||||
mockBlockHeaderConcise,
|
||||
mockBlockHeader,
|
||||
mockTxOut,
|
||||
mockTxOutProof
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
This library contains mocking data for running unit tests on the address route.
|
||||
*/
|
||||
|
||||
"use strict"
|
||||
|
||||
const mockGetInfo = {
|
||||
version: 170200,
|
||||
protocolversion: 70015,
|
||||
walletversion: 160300,
|
||||
balance: 0,
|
||||
blocks: 1266726,
|
||||
timeoffset: 0,
|
||||
connections: 8,
|
||||
proxy: "",
|
||||
difficulty: 1,
|
||||
testnet: true,
|
||||
keypoololdest: 1536331195,
|
||||
keypoolsize: 2000,
|
||||
paytxfee: 0,
|
||||
relayfee: 0.00001,
|
||||
errors: "Warning: unknown new rules activated (versionbit 28)"
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
mockGetInfo
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
Contains mocks of Express req and res objects.
|
||||
*/
|
||||
|
||||
"use strict"
|
||||
|
||||
const sinon = require("sinon")
|
||||
|
||||
// Inspect JS Objects.
|
||||
const util = require("util")
|
||||
util.inspect.defaultOptions = {
|
||||
showHidden: true,
|
||||
colors: true
|
||||
}
|
||||
|
||||
// mock for res.send()
|
||||
function fakeSend(arg) {
|
||||
//console.log(`res.send: ${util.inspect(arg)}`);
|
||||
mockRes.output = arg
|
||||
return arg
|
||||
}
|
||||
|
||||
// mock for res.json()
|
||||
function fakeJson(arg) {
|
||||
//console.log(`res.json: ${util.inspect(arg)}`);
|
||||
mockRes.output = arg
|
||||
return arg
|
||||
}
|
||||
|
||||
// mock for res.setStatus(num)
|
||||
const setStatusCode = arg => {
|
||||
mockRes.statusCode = arg
|
||||
}
|
||||
|
||||
const mockReq = {
|
||||
accepts: sinon.stub().returns({}),
|
||||
acceptsCharsets: sinon.stub().returns({}),
|
||||
acceptsEncodings: sinon.stub().returns({}),
|
||||
acceptsLanguages: sinon.stub().returns({}),
|
||||
body: {},
|
||||
flash: sinon.stub().returns({}),
|
||||
get: sinon.stub().returns({}),
|
||||
is: sinon.stub().returns({}),
|
||||
params: {},
|
||||
query: {},
|
||||
session: {},
|
||||
locals: {},
|
||||
headers: {}
|
||||
}
|
||||
|
||||
const mockRes = {
|
||||
append: sinon.stub().returns({}),
|
||||
attachement: sinon.stub().returns({}),
|
||||
clearCookie: sinon.stub().returns({}),
|
||||
cookie: sinon.stub().returns({}),
|
||||
download: sinon.stub().returns({}),
|
||||
end: sinon.stub().returns({}),
|
||||
format: {},
|
||||
get: sinon.stub().returns({}),
|
||||
headersSent: sinon.stub().returns({}),
|
||||
json: sinon.stub().callsFake(fakeJson),
|
||||
jsonp: sinon.stub().returns({}),
|
||||
links: sinon.stub().returns({}),
|
||||
locals: {},
|
||||
location: sinon.stub().returns({}),
|
||||
output: null, // Used for retrieving output data.
|
||||
redirect: sinon.stub().returns({}),
|
||||
render: sinon.stub().returns({}),
|
||||
send: sinon.stub().callsFake(fakeSend),
|
||||
sendFile: sinon.stub().returns({}),
|
||||
sendStatus: sinon.stub().returns({}),
|
||||
set: sinon.stub().returns({}),
|
||||
status: sinon.stub().callsFake(setStatusCode),
|
||||
statusCode: null, // Default value before calling stats();
|
||||
type: sinon.stub().returns({}),
|
||||
vary: sinon.stub().returns({}),
|
||||
write: sinon.stub().returns({}),
|
||||
setHeader: sinon.stub().returns({}),
|
||||
format: sinon.stub().returns({})
|
||||
}
|
||||
|
||||
const mockNext = sinon.stub().returns()
|
||||
|
||||
module.exports = {
|
||||
mockReq,
|
||||
mockRes,
|
||||
mockNext
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
This library contains mocking data for running unit tests on the address route.
|
||||
*/
|
||||
|
||||
"use strict"
|
||||
|
||||
const mockMiningInfo = {
|
||||
blocks: 1270185,
|
||||
currentblocksize: 0,
|
||||
currentblocktx: 0,
|
||||
difficulty: 1,
|
||||
blockprioritypercentage: 5,
|
||||
errors:
|
||||
"Warning: Unknown block versions being mined! It's possible unknown rules are in effect",
|
||||
networkhashps: 517410290.9365583,
|
||||
pooledtx: 5,
|
||||
chain: "test"
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
mockMiningInfo
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
This library contains mocking data for running unit tests.
|
||||
*/
|
||||
|
||||
"use strict"
|
||||
|
||||
const mockDecodeRawTransaction = {
|
||||
txid: "a332237d82a2543af1b0e1ae3c8cea1610c290ebcaf084a7e9894a61de0be988",
|
||||
hash: "a332237d82a2543af1b0e1ae3c8cea1610c290ebcaf084a7e9894a61de0be988",
|
||||
size: 226,
|
||||
version: 2,
|
||||
locktime: 0,
|
||||
vin: [
|
||||
{
|
||||
txid: "21cced645eab150585ed7ca7c96edebab5793cc0a3b3b286c42fd7d6d798b5b9",
|
||||
vout: 1,
|
||||
scriptSig: {
|
||||
asm:
|
||||
"3045022100a7b1b08956abb8d6f322aa709d8583c8ea492ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd41390[ALL|FORKID] 0360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab4667c57b2786f51c413d",
|
||||
hex:
|
||||
"483045022100a7b1b08956abb8d6f322aa709d8583c8ea492ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd4139041210360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab4667c57b2786f51c413d"
|
||||
},
|
||||
sequence: 4294967295
|
||||
}
|
||||
],
|
||||
vout: [
|
||||
{
|
||||
value: 0.0001,
|
||||
n: 0,
|
||||
scriptPubKey: {
|
||||
asm:
|
||||
"OP_DUP OP_HASH160 eb4b180def88e3f5625b2d8ae2c098ff7d85f664 OP_EQUALVERIFY OP_CHECKSIG",
|
||||
hex: "76a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac",
|
||||
reqSigs: 1,
|
||||
type: "pubkeyhash",
|
||||
addresses: [Array]
|
||||
}
|
||||
},
|
||||
{
|
||||
value: 0.09989752,
|
||||
n: 1,
|
||||
scriptPubKey: {
|
||||
asm:
|
||||
"OP_DUP OP_HASH160 eb4b180def88e3f5625b2d8ae2c098ff7d85f664 OP_EQUALVERIFY OP_CHECKSIG",
|
||||
hex: "76a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac",
|
||||
reqSigs: 1,
|
||||
type: "pubkeyhash",
|
||||
addresses: [Array]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
const mockDecodeScript = {
|
||||
asm:
|
||||
"0 0 -57 OP_NOP6 OP_LSHIFT OP_UNKNOWN OP_UNKNOWN OP_UNKNOWN c486b2b3a3c03c79b5bade6ec9a77ced850515ab5e64edcc21010000006b483045022100a7b1b08956abb8d6f322aa OP_2OVER OP_NUMEQUALVERIFY OP_OR OP_INVERT OP_UNKNOWN OP_UNKNOWN 2ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd4139041210360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab 67c57b2786f51c413dffffffff0210270000000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac786e9800000000001976a914eb4b180def88e3f5625b [error]",
|
||||
type: "nonstandard",
|
||||
p2sh: "bchtest:pzy6dwfy6yf373w0dr05a6flfqksurjhwcl3awhdvm"
|
||||
}
|
||||
|
||||
const mockRawTransactionConcise =
|
||||
"02000000014e6b52500110b1c30315b85805fb274f0f4afceffc1589f889b27709e59e987d000000006a473044022052762770baa71c1a0b9544ad0f1ea343d32c22aa87c5f8397b6852f464c15b1e02201f4390745cb470e21e0e3c14229f39fef55ea0643a4c997f99d9f3501eae09b7412103c346eee77a77a8d3e073dacc0532ca7a5b9747bc06d88bf091cac9f4bc8bb792ffffffff02d1778f950a0000001976a91436d2f27bbd826a86db1e93618ce3de89ef33169388ac80969800000000001976a914152ea3cd65f18cb8fa9146c84ea1a97af8f051de88ac00000000"
|
||||
|
||||
const mockRawTransactionVerbose = {
|
||||
hex:
|
||||
"02000000014e6b52500110b1c30315b85805fb274f0f4afceffc1589f889b27709e59e987d000000006a473044022052762770baa71c1a0b9544ad0f1ea343d32c22aa87c5f8397b6852f464c15b1e02201f4390745cb470e21e0e3c14229f39fef55ea0643a4c997f99d9f3501eae09b7412103c346eee77a77a8d3e073dacc0532ca7a5b9747bc06d88bf091cac9f4bc8bb792ffffffff02d1778f950a0000001976a91436d2f27bbd826a86db1e93618ce3de89ef33169388ac80969800000000001976a914152ea3cd65f18cb8fa9146c84ea1a97af8f051de88ac00000000",
|
||||
txid: "bd320377db7026a3dd5c7ec444596c0ee18fc25c4f34ee944adc03e432ce1971",
|
||||
hash: "bd320377db7026a3dd5c7ec444596c0ee18fc25c4f34ee944adc03e432ce1971",
|
||||
size: 225,
|
||||
version: 2,
|
||||
locktime: 0,
|
||||
vin: [
|
||||
{
|
||||
txid: "7d989ee50977b289f88915fceffc4a0f4f27fb0558b81503c3b1100150526b4e",
|
||||
vout: 0,
|
||||
scriptSig: {
|
||||
asm:
|
||||
"3044022052762770baa71c1a0b9544ad0f1ea343d32c22aa87c5f8397b6852f464c15b1e02201f4390745cb470e21e0e3c14229f39fef55ea0643a4c997f99d9f3501eae09b7[ALL|FORKID] 03c346eee77a77a8d3e073dacc0532ca7a5b9747bc06d88bf091cac9f4bc8bb792",
|
||||
hex:
|
||||
"473044022052762770baa71c1a0b9544ad0f1ea343d32c22aa87c5f8397b6852f464c15b1e02201f4390745cb470e21e0e3c14229f39fef55ea0643a4c997f99d9f3501eae09b7412103c346eee77a77a8d3e073dacc0532ca7a5b9747bc06d88bf091cac9f4bc8bb792"
|
||||
},
|
||||
sequence: 4294967295
|
||||
}
|
||||
],
|
||||
vout: [
|
||||
{
|
||||
value: 454.58880465,
|
||||
n: 0,
|
||||
scriptPubKey: {
|
||||
asm:
|
||||
"OP_DUP OP_HASH160 36d2f27bbd826a86db1e93618ce3de89ef331693 OP_EQUALVERIFY OP_CHECKSIG",
|
||||
hex: "76a91436d2f27bbd826a86db1e93618ce3de89ef33169388ac",
|
||||
reqSigs: 1,
|
||||
type: "pubkeyhash",
|
||||
addresses: ["bchtest:qqmd9unmhkpx4pkmr6fkrr8rm6y77vckjvqe8aey35"]
|
||||
}
|
||||
},
|
||||
{
|
||||
value: 0.1,
|
||||
n: 1,
|
||||
scriptPubKey: {
|
||||
asm:
|
||||
"OP_DUP OP_HASH160 152ea3cd65f18cb8fa9146c84ea1a97af8f051de OP_EQUALVERIFY OP_CHECKSIG",
|
||||
hex: "76a914152ea3cd65f18cb8fa9146c84ea1a97af8f051de88ac",
|
||||
reqSigs: 1,
|
||||
type: "pubkeyhash",
|
||||
addresses: ["bchtest:qq2jag7dvhccew86j9rvsn4p49a03uz3mcpw3d6aca"]
|
||||
}
|
||||
}
|
||||
],
|
||||
blockhash: "000000000000026fa244de975ca89ea08008aa566564ce2e8ebb3144361b601b",
|
||||
confirmations: 125,
|
||||
time: 1542646373,
|
||||
blocktime: 1542646373
|
||||
}
|
||||
|
||||
const mockWHDecode = {
|
||||
txid: "f8a9857fe3b8a288b5fcafb1b0fc196731f433add6d962f77acd7c10b970ff89",
|
||||
fee: "500",
|
||||
sendingaddress: "bchtest:qzjtnzcvzxx7s0na88yrg3zl28wwvfp97538sgrrmr",
|
||||
referenceaddress: "bchtest:qzjtnzcvzxx7s0na88yrg3zl28wwvfp97538sgrrmr",
|
||||
ismine: false,
|
||||
version: 0,
|
||||
type_int: 0,
|
||||
type: "Simple Send",
|
||||
propertyid: 368,
|
||||
precision: "8",
|
||||
amount: "10.00000000",
|
||||
valid: true,
|
||||
blockhash: "0000000046ba0bcef78caaa4492622176bbc563cf249ab52340a0449bc8e26f6",
|
||||
blocktime: 1542814183,
|
||||
positioninblock: 57,
|
||||
block: 1269008,
|
||||
confirmations: 2
|
||||
}
|
||||
|
||||
const mockWHCreateInput = {
|
||||
txid: "f7ed9cf23dee85910f6269c9a101a75fcfd2f3c6fc81f17fad824ff7aaf99ab2",
|
||||
vout: 1,
|
||||
scriptPubKey: "76a914a4b98b0c118de83e7d39c834445f51dce62425f588ac",
|
||||
amount: 0.09984138,
|
||||
satoshis: 9984138,
|
||||
height: 1269011,
|
||||
confirmations: 4,
|
||||
legacyAddress: "mvXwPH74hW2yVTWwDwzsjGoaUAqJvWk7ZJ",
|
||||
cashAddress: "bchtest:qzjtnzcvzxx7s0na88yrg3zl28wwvfp97538sgrrmr",
|
||||
value: 0.09984138
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
mockDecodeRawTransaction,
|
||||
mockDecodeScript,
|
||||
mockRawTransactionConcise,
|
||||
mockRawTransactionVerbose,
|
||||
mockWHDecode,
|
||||
mockWHCreateInput
|
||||
}
|
||||
@@ -0,0 +1,327 @@
|
||||
/*
|
||||
This library contains mocking data for running unit tests.
|
||||
*/
|
||||
|
||||
"use strict"
|
||||
|
||||
const mockList = {
|
||||
t: [
|
||||
{
|
||||
tokenDetails: {
|
||||
tokenIdHex:
|
||||
"df808a41672a0a0ae6475b44f272a107bc9961b90f29dc918d71301f24fe92fb",
|
||||
documentUri: "",
|
||||
documentSha256: "",
|
||||
symbol: "NAKAMOTO",
|
||||
name: "NAKAMOTO",
|
||||
decimals: 8
|
||||
},
|
||||
tokenStats: {
|
||||
qty_valid_txns_since_genesis: 241,
|
||||
qty_valid_token_utxos: 151,
|
||||
qty_valid_token_addresses: 113,
|
||||
qty_token_circulating_supply: "20995990",
|
||||
qty_token_burned: "4010",
|
||||
qty_token_minted: "21000000",
|
||||
qty_satoshis_locked_up: 81900
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
const mockSingleToken = {
|
||||
t: [
|
||||
{
|
||||
tokenDetails: {
|
||||
decimals: 8,
|
||||
tokenIdHex:
|
||||
"650dea14c77f4d749608e36e375450c9ac91deb8b1b53e50cb0de2059a52d19a",
|
||||
timestamp: "2018-08-26 07:06",
|
||||
transactionType: "GENESIS",
|
||||
versionType: 1,
|
||||
documentUri: "",
|
||||
documentSha256Hex: null,
|
||||
symbol: "",
|
||||
name: "TESTYCOIN",
|
||||
batonVout: null,
|
||||
containsBaton: false,
|
||||
genesisOrMintQuantity: "9999",
|
||||
sendOutputs: null
|
||||
},
|
||||
tokenStats: {
|
||||
block_created: 1253802,
|
||||
block_last_active_send: 1253802,
|
||||
block_last_active_mint: null,
|
||||
qty_valid_txns_since_genesis: 2,
|
||||
qty_valid_token_utxos: 0,
|
||||
qty_valid_token_addresses: 0,
|
||||
qty_token_minted: "9999",
|
||||
qty_token_burned: "9999",
|
||||
qty_token_circulating_supply: "0",
|
||||
qty_satoshis_locked_up: 0,
|
||||
minting_baton_status: "NEVER_CREATED"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
const mockSingleTokenError = {
|
||||
t: []
|
||||
}
|
||||
|
||||
const mockSingleAddress = {
|
||||
a: [
|
||||
{
|
||||
_id: "5c93ed62a19119333d1595bc",
|
||||
tokenDetails: {
|
||||
tokenIdHex:
|
||||
"6b081fcd1f78b187be1464313dac8ff257251b727a42b613552a4040870aeb29"
|
||||
},
|
||||
address: "slptest:pz0qcslrqn7hr44hsszwl4lw5r6udkg6zqv7sq3kk7",
|
||||
satoshis_balance: 546,
|
||||
token_balance: "4616984"
|
||||
}
|
||||
],
|
||||
t: [
|
||||
{
|
||||
tokenDetails: {
|
||||
decimals: 8,
|
||||
tokenIdHex:
|
||||
"6b081fcd1f78b187be1464313dac8ff257251b727a42b613552a4040870aeb29",
|
||||
timestamp: "2019-02-25 10:05",
|
||||
transactionType: "GENESIS",
|
||||
versionType: 1,
|
||||
documentUri: "https://developer.bitcoin.com",
|
||||
documentSha256Hex: "",
|
||||
symbol: "DEV",
|
||||
name: "DEVCOIN",
|
||||
batonVout: 2,
|
||||
containsBaton: true,
|
||||
genesisOrMintQuantity: "500000000",
|
||||
sendOutputs: null
|
||||
},
|
||||
tokenStats: {
|
||||
block_created: 571272,
|
||||
block_last_active_send: 574758,
|
||||
block_last_active_mint: 571272,
|
||||
qty_valid_txns_since_genesis: 172,
|
||||
qty_valid_token_utxos: 170,
|
||||
qty_valid_token_addresses: 170,
|
||||
qty_token_minted: "1000000000",
|
||||
qty_token_burned: "4.99999995",
|
||||
qty_token_circulating_supply: "999999995.00000005",
|
||||
qty_satoshis_locked_up: 92820,
|
||||
minting_baton_status: "ALIVE"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
const mockTx = {
|
||||
txid: "57b3082a2bf269b3d6f40fee7fb9c664e8256a88ca5ee2697c05b9457822d446",
|
||||
version: 2,
|
||||
locktime: 0,
|
||||
vin: [
|
||||
{
|
||||
txid: "61e71554a3dc18158f30d9e8f5c9b6641a789690b32302899f81cbea9fe3bb49",
|
||||
vout: 2,
|
||||
sequence: 4294967295,
|
||||
n: 0,
|
||||
scriptSig: {
|
||||
hex:
|
||||
"4730440220409e79fec552f01203f41d3d621ae3db89c720af261c8268ce5f0453de009f5d022001e7ffefeba7b0716d32ea55cb6ace267b6ee9cbcc8a017bb9c3b6acf7889418412103c87f0ec048a0771bdb60533d45cac88c6974afeb055a65edd663c2f947335585",
|
||||
asm:
|
||||
"30440220409e79fec552f01203f41d3d621ae3db89c720af261c8268ce5f0453de009f5d022001e7ffefeba7b0716d32ea55cb6ace267b6ee9cbcc8a017bb9c3b6acf7889418[ALL|FORKID] 03c87f0ec048a0771bdb60533d45cac88c6974afeb055a65edd663c2f947335585"
|
||||
},
|
||||
value: 546,
|
||||
legacyAddress: "mw22g57T9YA7MZQQu5eBDKj3PKTdt99oDL",
|
||||
cashAddress: "bchtest:qz4qnxcxwvmacgye8wlakhz0835x0w3vtvaga95c09"
|
||||
},
|
||||
{
|
||||
txid: "61e71554a3dc18158f30d9e8f5c9b6641a789690b32302899f81cbea9fe3bb49",
|
||||
vout: 1,
|
||||
sequence: 4294967295,
|
||||
n: 1,
|
||||
scriptSig: {
|
||||
hex:
|
||||
"483045022100a743bee56c99bd103be48a78fa4c7342100815d9d2448dbe6e1d338c3a13b241022066728b5279fc22eef5cd019582ff34771e29175835fc98aa3168a1548fd78ac8412103c87f0ec048a0771bdb60533d45cac88c6974afeb055a65edd663c2f947335585",
|
||||
asm:
|
||||
"3045022100a743bee56c99bd103be48a78fa4c7342100815d9d2448dbe6e1d338c3a13b241022066728b5279fc22eef5cd019582ff34771e29175835fc98aa3168a1548fd78ac8[ALL|FORKID] 03c87f0ec048a0771bdb60533d45cac88c6974afeb055a65edd663c2f947335585"
|
||||
},
|
||||
value: 546,
|
||||
legacyAddress: "mw22g57T9YA7MZQQu5eBDKj3PKTdt99oDL",
|
||||
cashAddress: "bchtest:qz4qnxcxwvmacgye8wlakhz0835x0w3vtvaga95c09"
|
||||
},
|
||||
{
|
||||
txid: "61e71554a3dc18158f30d9e8f5c9b6641a789690b32302899f81cbea9fe3bb49",
|
||||
vout: 3,
|
||||
sequence: 4294967295,
|
||||
n: 2,
|
||||
scriptSig: {
|
||||
hex:
|
||||
"483045022100821473902eec5f1ce7d43b1ba7f9ec453bfe8b8dfc3de3e0723c883ab109922f02206162960e80618531fab2c16aee260fddd7979bab62471c8686af7de75f8732ec412103c87f0ec048a0771bdb60533d45cac88c6974afeb055a65edd663c2f947335585",
|
||||
asm:
|
||||
"3045022100821473902eec5f1ce7d43b1ba7f9ec453bfe8b8dfc3de3e0723c883ab109922f02206162960e80618531fab2c16aee260fddd7979bab62471c8686af7de75f8732ec[ALL|FORKID] 03c87f0ec048a0771bdb60533d45cac88c6974afeb055a65edd663c2f947335585"
|
||||
},
|
||||
value: 9997521,
|
||||
legacyAddress: "mw22g57T9YA7MZQQu5eBDKj3PKTdt99oDL",
|
||||
cashAddress: "bchtest:qz4qnxcxwvmacgye8wlakhz0835x0w3vtvaga95c09"
|
||||
}
|
||||
],
|
||||
vout: [
|
||||
{
|
||||
value: "0.00000000",
|
||||
n: 0,
|
||||
scriptPubKey: {
|
||||
hex:
|
||||
"6a04534c500001010453454e44207ac7f4bb50b019fe0f5c81e3fc13fc0720e130282ea460768cafb49785eb2796080000000049504f80080000001c71e64280",
|
||||
asm:
|
||||
"OP_RETURN 5262419 1 1145980243 7ac7f4bb50b019fe0f5c81e3fc13fc0720e130282ea460768cafb49785eb2796 0000000049504f80 0000001c71e64280"
|
||||
},
|
||||
spentTxId: null,
|
||||
spentIndex: null,
|
||||
spentHeight: null
|
||||
},
|
||||
{
|
||||
value: "0.00000546",
|
||||
n: 1,
|
||||
scriptPubKey: {
|
||||
hex: "76a914396b8e57ad0cb58d30e2992f22047b3c20377aa688ac",
|
||||
asm:
|
||||
"OP_DUP OP_HASH160 396b8e57ad0cb58d30e2992f22047b3c20377aa6 OP_EQUALVERIFY OP_CHECKSIG",
|
||||
addresses: ["mkkZf7T3fU3vHSzNPy51HBmM46ghN1gnN9"],
|
||||
type: "pubkeyhash"
|
||||
},
|
||||
spentTxId: null,
|
||||
spentIndex: null,
|
||||
spentHeight: null
|
||||
},
|
||||
{
|
||||
value: "0.00000546",
|
||||
n: 2,
|
||||
scriptPubKey: {
|
||||
hex: "76a914aa099b067337dc20993bbfdb5c4f3c6867ba2c5b88ac",
|
||||
asm:
|
||||
"OP_DUP OP_HASH160 aa099b067337dc20993bbfdb5c4f3c6867ba2c5b OP_EQUALVERIFY OP_CHECKSIG",
|
||||
addresses: ["mw22g57T9YA7MZQQu5eBDKj3PKTdt99oDL"],
|
||||
type: "pubkeyhash"
|
||||
},
|
||||
spentTxId: null,
|
||||
spentIndex: null,
|
||||
spentHeight: null
|
||||
},
|
||||
{
|
||||
value: "0.09996891",
|
||||
n: 3,
|
||||
scriptPubKey: {
|
||||
hex: "76a914aa099b067337dc20993bbfdb5c4f3c6867ba2c5b88ac",
|
||||
asm:
|
||||
"OP_DUP OP_HASH160 aa099b067337dc20993bbfdb5c4f3c6867ba2c5b OP_EQUALVERIFY OP_CHECKSIG",
|
||||
addresses: ["mw22g57T9YA7MZQQu5eBDKj3PKTdt99oDL"],
|
||||
type: "pubkeyhash"
|
||||
},
|
||||
spentTxId: null,
|
||||
spentIndex: null,
|
||||
spentHeight: null
|
||||
}
|
||||
],
|
||||
blockhash: "000000000000ce978accc64a6bb567acf0c653c202309a0f8e220149bf0c6968",
|
||||
blockheight: 1287490,
|
||||
confirmations: 746,
|
||||
time: 1550855104,
|
||||
blocktime: 1550855104,
|
||||
valueOut: 0.09997983,
|
||||
size: 628,
|
||||
valueIn: 0.09998613,
|
||||
fees: 0.0000063,
|
||||
tokenInfo: {
|
||||
versionType: 1,
|
||||
transactionType: "SEND",
|
||||
tokenIdHex:
|
||||
"7ac7f4bb50b019fe0f5c81e3fc13fc0720e130282ea460768cafb49785eb2796",
|
||||
sendOutputs: ["0", "1230000000", "122170000000"]
|
||||
},
|
||||
tokenIsValid: true
|
||||
}
|
||||
|
||||
const mockConvert = {
|
||||
slpAddress: "slptest:qz35h5mfa8w2pqma2jq06lp7dnv5fxkp2shlcycvd5",
|
||||
cashAddress: "bchtest:qz35h5mfa8w2pqma2jq06lp7dnv5fxkp2svtllzmlf",
|
||||
legacyAddress: "mvQPGnzRT6gMWASZBMg7NcT3vmvsSKSQtf"
|
||||
}
|
||||
|
||||
const mockTokenDetails = {
|
||||
tokenIdHex:
|
||||
"df808a41672a0a0ae6475b44f272a107bc9961b90f29dc918d71301f24fe92fb",
|
||||
documentUri: "",
|
||||
symbol: "NAKAMOTO",
|
||||
name: "NAKAMOTO",
|
||||
decimals: 8,
|
||||
timestamp: "",
|
||||
containsBaton: true,
|
||||
versionType: 1
|
||||
}
|
||||
|
||||
const mockTokenStats = {
|
||||
qty_valid_txns_since_genesis: 241,
|
||||
qty_valid_token_utxos: 151,
|
||||
qty_valid_token_addresses: 113,
|
||||
qty_token_circulating_supply: "20995990",
|
||||
qty_token_burned: "4010",
|
||||
qty_token_minted: "21000000",
|
||||
qty_satoshis_locked_up: 81900
|
||||
}
|
||||
|
||||
const mockBalance = {
|
||||
slpAddress: "simpleledger:qp9d8mn8ypryfvea2mev0ggc3wg6plpn4suuaeuss3",
|
||||
satoshis_balance: 546,
|
||||
token_balance: "1000"
|
||||
}
|
||||
|
||||
const mockTransactions = [
|
||||
{
|
||||
txid: "a302f045be8efa1cd982833a7f187ff4fac8baac36da0c887eb2787d8b45e2af",
|
||||
tokenDetails: {
|
||||
valid: true,
|
||||
detail: {
|
||||
decimals: null,
|
||||
tokenIdHex:
|
||||
"495322b37d6b2eae81f045eda612b95870a0c2b6069c58f70cf8ef4e6a9fd43a",
|
||||
timestamp: null,
|
||||
transactionType: "MINT",
|
||||
versionType: 1,
|
||||
documentUri: null,
|
||||
documentSha256Hex: null,
|
||||
symbol: null,
|
||||
name: null,
|
||||
batonVout: 2,
|
||||
containsBaton: true,
|
||||
genesisOrMintQuantity: {
|
||||
$numberDecimal: "1000"
|
||||
},
|
||||
sendOutputs: null
|
||||
},
|
||||
invalidReason: null,
|
||||
schema_version: 30
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
const mockFoobar = {
|
||||
c: [],
|
||||
u: []
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
mockList,
|
||||
mockSingleToken,
|
||||
mockConvert,
|
||||
mockTokenDetails,
|
||||
mockTokenStats,
|
||||
mockTx,
|
||||
mockBalance,
|
||||
mockTransactions,
|
||||
mockSingleTokenError,
|
||||
mockSingleAddress,
|
||||
mockFoobar
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
Mocks used for unit tests that interact with slpjs.
|
||||
*/
|
||||
|
||||
"use strict"
|
||||
|
||||
const sinon = require("sinon")
|
||||
const proxyquire = require("proxyquire")
|
||||
const BigNumber = require("bignumber.js")
|
||||
const slpMocks = require("./slp-mocks")
|
||||
|
||||
// Mock the BitboxNetwork class.
|
||||
class BitboxNetwork {
|
||||
constructor() {}
|
||||
|
||||
async getAllSlpBalancesAndUtxos(address) {
|
||||
return {
|
||||
satoshis_available_bch: 9996891,
|
||||
satoshis_in_slp_baton: 546,
|
||||
satoshis_in_slp_token: 546,
|
||||
satoshis_in_invalid_token_dag: 0,
|
||||
satoshis_in_invalid_baton_dag: 0,
|
||||
slpTokenBalances: {
|
||||
"7ac7f4bb50b019fe0f5c81e3fc13fc0720e130282ea460768cafb49785eb2796": new BigNumber(
|
||||
123400000000
|
||||
)
|
||||
},
|
||||
slpTokenUtxos: {
|
||||
"7ac7f4bb50b019fe0f5c81e3fc13fc0720e130282ea460768cafb49785eb2796": []
|
||||
},
|
||||
slpBatonUtxos: {
|
||||
"7ac7f4bb50b019fe0f5c81e3fc13fc0720e130282ea460768cafb49785eb2796": []
|
||||
},
|
||||
nonSlpUtxos: [{}],
|
||||
invalidTokenUtxos: [],
|
||||
invalidBatonUtxos: []
|
||||
}
|
||||
}
|
||||
|
||||
async getTokenInformation(txid) {
|
||||
BigNumber.set({ DECIMAL_PLACES: 8, ROUNDING_MODE: 4 })
|
||||
|
||||
const obj = {
|
||||
versionType: 1,
|
||||
transactionType: 0,
|
||||
symbol: "SLPSDK",
|
||||
name: "SLP SDK example using BITBOX",
|
||||
documentUri: "developer.bitcoin.com",
|
||||
documentSha256: null,
|
||||
decimals: 8,
|
||||
batonVout: 2,
|
||||
containsBaton: true,
|
||||
genesisOrMintQuantity: new BigNumber(123400000000)
|
||||
}
|
||||
|
||||
return obj
|
||||
}
|
||||
|
||||
async getTransactionDetails(txid) {
|
||||
return slpMocks.mockTx
|
||||
}
|
||||
}
|
||||
|
||||
// Mock the slpjs library.
|
||||
const slpjs = {
|
||||
BitboxNetwork,
|
||||
slp: {},
|
||||
validator: {}
|
||||
}
|
||||
|
||||
module.exports = slpjs
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
This library contains mocking data for running unit tests on the address route.
|
||||
*/
|
||||
|
||||
"use strict"
|
||||
|
||||
/*
|
||||
const mockDetails = {
|
||||
txid: "6f235bd3a689f03c11969cd649ccad592462ca958bc519a30194e7a67b349a40",
|
||||
version: 2,
|
||||
locktime: 0,
|
||||
vin: [Array],
|
||||
vout: [Array],
|
||||
blockhash: "00000000e7232ff12462dedf9c11985f5b54202515277c337ccc59812758f28b",
|
||||
blockheight: 1270188,
|
||||
confirmations: 2,
|
||||
time: 1543436253,
|
||||
blocktime: 1543436253,
|
||||
valueOut: 450.78867333,
|
||||
size: 226,
|
||||
valueIn: 450.78867559,
|
||||
fees: 0.00000226
|
||||
}
|
||||
*/
|
||||
|
||||
const mockDetails = {
|
||||
txid: "6f235bd3a689f03c11969cd649ccad592462ca958bc519a30194e7a67b349a40",
|
||||
version: 2,
|
||||
locktime: 0,
|
||||
vin: [
|
||||
{
|
||||
txid: "273d616d1c48f4b075c497f36ffdc79da5c8d6ed75485808b3599aac504f8525",
|
||||
vout: 0,
|
||||
sequence: 4294967295,
|
||||
n: 0,
|
||||
scriptSig: [{}],
|
||||
addr: "bchtest:qqmd9unmhkpx4pkmr6fkrr8rm6y77vckjvqe8aey35",
|
||||
valueSat: 45078867559,
|
||||
value: 450.78867559,
|
||||
doubleSpentTxID: null
|
||||
}
|
||||
],
|
||||
vout: [
|
||||
{
|
||||
value: "450.68867333",
|
||||
n: 0,
|
||||
scriptPubKey: [{}],
|
||||
spentTxId: null,
|
||||
spentIndex: null,
|
||||
spentHeight: null
|
||||
},
|
||||
{
|
||||
value: "0.10000000",
|
||||
n: 1,
|
||||
scriptPubKey: [{}],
|
||||
spentTxId: null,
|
||||
spentIndex: null,
|
||||
spentHeight: null
|
||||
}
|
||||
],
|
||||
blockhash: "00000000e7232ff12462dedf9c11985f5b54202515277c337ccc59812758f28b",
|
||||
blockheight: 1270188,
|
||||
confirmations: 3,
|
||||
time: 1543436253,
|
||||
blocktime: 1543436253,
|
||||
valueOut: 450.78867333,
|
||||
size: 226,
|
||||
valueIn: 450.78867559,
|
||||
fees: 0.00000226
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
mockDetails
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
This library contains mocking data for running unit tests on the address route.
|
||||
*/
|
||||
|
||||
"use strict"
|
||||
|
||||
const mockAddress = {
|
||||
isvalid: true,
|
||||
address: "bchtest:qqqk4y6lsl5da64sg5qc3xezmplyu5kmpyz2ysaa5y",
|
||||
scriptPubKey: "76a914016a935f87e8deeab04501889b22d87e4e52db0988ac",
|
||||
ismine: false,
|
||||
iswatchonly: false,
|
||||
isscript: false
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
mockAddress
|
||||
}
|
||||
@@ -0,0 +1,164 @@
|
||||
"use strict"
|
||||
|
||||
const chai = require("chai")
|
||||
const assert = chai.assert
|
||||
const nock = require("nock") // HTTP mocking
|
||||
|
||||
// Used for debugging.
|
||||
const util = require("util")
|
||||
util.inspect.defaultOptions = { depth: 1 }
|
||||
|
||||
// Mocking data.
|
||||
const { mockReq, mockRes, mockNext } = require("./mocks/express-mocks")
|
||||
|
||||
// Libraries under test
|
||||
let rateLimitMiddleware = require("../../dist/middleware/route-ratelimit")
|
||||
const controlRoute = require("../../dist/routes/v2/control")
|
||||
|
||||
let req, res, next
|
||||
let originalEnvVars // Used during transition from integration to unit tests.
|
||||
|
||||
describe("#route-ratelimits", () => {
|
||||
before(() => {
|
||||
// Save existing environment variables.
|
||||
originalEnvVars = {
|
||||
BITCOINCOM_BASEURL: process.env.BITCOINCOM_BASEURL,
|
||||
RPC_BASEURL: process.env.RPC_BASEURL,
|
||||
RPC_USERNAME: process.env.RPC_USERNAME,
|
||||
RPC_PASSWORD: process.env.RPC_PASSWORD
|
||||
}
|
||||
})
|
||||
|
||||
// Setup the mocks before each test.
|
||||
beforeEach(() => {
|
||||
// Mock the req and res objects used by Express routes.
|
||||
req = mockReq
|
||||
res = mockRes
|
||||
next = mockNext
|
||||
|
||||
// Explicitly reset the parmas and body.
|
||||
req.params = {}
|
||||
req.body = {}
|
||||
req.query = {}
|
||||
})
|
||||
|
||||
describe("#routeRateLimit", () => {
|
||||
let routeRateLimit = rateLimitMiddleware.routeRateLimit
|
||||
const getInfo = controlRoute.testableComponents.getInfo
|
||||
|
||||
it("should pass through rate-limit middleware", async () => {
|
||||
req.baseUrl = "/v2"
|
||||
req.path = "/control/getInfo"
|
||||
req.method = "GET"
|
||||
|
||||
await routeRateLimit(req, res, next)
|
||||
|
||||
// next() will be called if rate-limit is not triggered
|
||||
assert.equal(next.called, true)
|
||||
})
|
||||
|
||||
it("should trigger rate-limit handler if rate limits exceeds 60 request per minute", async () => {
|
||||
req.baseUrl = "/v2"
|
||||
req.path = "/control/getInfo"
|
||||
req.method = "GET"
|
||||
|
||||
for (let i = 0; i < 65; i++) {
|
||||
next.reset() // reset the stubbed next() function.
|
||||
|
||||
await routeRateLimit(req, res, next)
|
||||
//console.log(`next() called: ${next.called}`)
|
||||
}
|
||||
|
||||
// Note: next() will be called unless the rate-limit kicks in.
|
||||
assert.equal(
|
||||
next.called,
|
||||
false,
|
||||
`next should not be called if rate limit was triggered.`
|
||||
)
|
||||
})
|
||||
|
||||
it("should NOT trigger rate-limit handler for pro-tier at 65 RPM", async () => {
|
||||
// Clear the require cache before running this test.
|
||||
delete require.cache[
|
||||
require.resolve("../../dist/middleware/route-ratelimit")
|
||||
]
|
||||
rateLimitMiddleware = require("../../dist/middleware/route-ratelimit")
|
||||
routeRateLimit = rateLimitMiddleware.routeRateLimit
|
||||
|
||||
req.baseUrl = "/v2"
|
||||
req.path = "/control/getInfo"
|
||||
req.method = "GET"
|
||||
|
||||
req.locals.proLimit = true
|
||||
|
||||
//console.log(`req.locals before test: ${util.inspect(req.locals)}`)
|
||||
|
||||
// Prepare the authorization header
|
||||
//req.headers.authorization = generateAuthHeader("BITBOX")
|
||||
|
||||
for (let i = 0; i < 65; i++) {
|
||||
next.reset() // reset the stubbed next() function.
|
||||
|
||||
await routeRateLimit(req, res, next)
|
||||
//console.log(`next() called: ${next.called}`)
|
||||
}
|
||||
|
||||
//console.log(`req.locals after test: ${util.inspect(req.locals)}`)
|
||||
|
||||
// Note: next() will be called unless the rate-limit kicks in.
|
||||
assert.equal(
|
||||
next.called,
|
||||
true,
|
||||
`next should be called if rate limit was not triggered.`
|
||||
)
|
||||
})
|
||||
|
||||
it("rate-limiting should still kick in at a higher RPM for pro-tier", async () => {
|
||||
// Clear the require cache before running this test.
|
||||
delete require.cache[
|
||||
require.resolve("../../dist/middleware/route-ratelimit")
|
||||
]
|
||||
rateLimitMiddleware = require("../../dist/middleware/route-ratelimit")
|
||||
routeRateLimit = rateLimitMiddleware.routeRateLimit
|
||||
|
||||
req.baseUrl = "/v2"
|
||||
req.path = "/control/getInfo"
|
||||
req.method = "GET"
|
||||
|
||||
req.locals.proLimit = true
|
||||
|
||||
//console.log(`req.locals before test: ${util.inspect(req.locals)}`)
|
||||
|
||||
// Prepare the authorization header
|
||||
//req.headers.authorization = generateAuthHeader("BITBOX")
|
||||
|
||||
for (let i = 0; i < 650; i++) {
|
||||
next.reset() // reset the stubbed next() function.
|
||||
|
||||
await routeRateLimit(req, res, next)
|
||||
//console.log(`next() called: ${next.called}`)
|
||||
}
|
||||
|
||||
//console.log(`req.locals after test: ${util.inspect(req.locals)}`)
|
||||
|
||||
// Note: next() will be called unless the rate-limit kicks in.
|
||||
assert.equal(
|
||||
next.called,
|
||||
false,
|
||||
`next should NOT be called if rate limit was triggered.`
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
// Generates a Basic authorization header.
|
||||
function generateAuthHeader(pass) {
|
||||
// https://en.wikipedia.org/wiki/Basic_access_authentication
|
||||
const username = "BITBOX"
|
||||
const combined = `${username}:${pass}`
|
||||
|
||||
var base64Credential = Buffer.from(combined).toString("base64")
|
||||
var readyCredential = `Basic ${base64Credential}`
|
||||
|
||||
return readyCredential
|
||||
}
|
||||
@@ -0,0 +1,807 @@
|
||||
/*
|
||||
TESTS FOR THE RAWTRANSACTIONS.TS LIBRARY
|
||||
|
||||
This test file uses the environment variable TEST to switch between unit
|
||||
and integration tests. By default, TEST is set to 'unit'. Set this variable
|
||||
to 'integration' to run the tests against BCH mainnet.
|
||||
|
||||
TODO:
|
||||
-Create e2e test for sendRawTransaction.
|
||||
|
||||
*/
|
||||
|
||||
"use strict"
|
||||
|
||||
const chai = require("chai")
|
||||
const assert = chai.assert
|
||||
const rawtransactions = require("../../dist/routes/v2/rawtransactions")
|
||||
const nock = require("nock") // HTTP mocking
|
||||
|
||||
let originalEnvVars // Used during transition from integration to unit tests.
|
||||
|
||||
// Mocking data.
|
||||
//delete require.cache[require.resolve("./mocks/express-mocks")] // Fixes bug
|
||||
const { mockReq, mockRes, mockNext } = require("./mocks/express-mocks")
|
||||
const mockData = require("./mocks/raw-transactions-mocks")
|
||||
|
||||
// Used for debugging.
|
||||
const util = require("util")
|
||||
util.inspect.defaultOptions = { depth: 5 }
|
||||
|
||||
describe("#Raw-Transactions", () => {
|
||||
let req, res, next
|
||||
|
||||
before(() => {
|
||||
// Save existing environment variables.
|
||||
originalEnvVars = {
|
||||
BITCOINCOM_BASEURL: process.env.BITCOINCOM_BASEURL,
|
||||
RPC_BASEURL: process.env.RPC_BASEURL,
|
||||
RPC_USERNAME: process.env.RPC_USERNAME,
|
||||
RPC_PASSWORD: process.env.RPC_PASSWORD
|
||||
}
|
||||
|
||||
// Set default environment variables for unit tests.
|
||||
if (!process.env.TEST) process.env.TEST = "unit"
|
||||
if (process.env.TEST === "unit") {
|
||||
process.env.BITCOINCOM_BASEURL = "http://fakeurl/api/"
|
||||
process.env.RPC_BASEURL = "http://fakeurl/api"
|
||||
process.env.RPC_USERNAME = "fakeusername"
|
||||
process.env.RPC_PASSWORD = "fakepassword"
|
||||
}
|
||||
})
|
||||
|
||||
// Setup the mocks before each test.
|
||||
beforeEach(() => {
|
||||
// Mock the req and res objects used by Express routes.
|
||||
req = mockReq
|
||||
res = mockRes
|
||||
next = mockNext
|
||||
|
||||
// Explicitly reset the parmas and body.
|
||||
req.params = {}
|
||||
req.body = {}
|
||||
req.query = {}
|
||||
req.locals = {}
|
||||
|
||||
// Activate nock if it's inactive.
|
||||
if (!nock.isActive()) nock.activate()
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
// Clean up HTTP mocks.
|
||||
nock.cleanAll() // clear interceptor list.
|
||||
nock.restore()
|
||||
})
|
||||
|
||||
after(() => {
|
||||
// Restore any pre-existing environment variables.
|
||||
process.env.BITCOINCOM_BASEURL = originalEnvVars.BITCOINCOM_BASEURL
|
||||
process.env.RPC_BASEURL = originalEnvVars.RPC_BASEURL
|
||||
process.env.RPC_USERNAME = originalEnvVars.RPC_USERNAME
|
||||
process.env.RPC_PASSWORD = originalEnvVars.RPC_PASSWORD
|
||||
})
|
||||
|
||||
describe("#root", async () => {
|
||||
// root route handler.
|
||||
const root = rawtransactions.testableComponents.root
|
||||
|
||||
it("should respond to GET for base route", async () => {
|
||||
const result = root(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.equal(result.status, "rawtransactions", "Returns static string")
|
||||
})
|
||||
})
|
||||
|
||||
describe("decodeRawTransactionSingle()", () => {
|
||||
// block route handler.
|
||||
const decodeRawTransaction =
|
||||
rawtransactions.testableComponents.decodeRawTransactionSingle
|
||||
|
||||
it("should throw error if hex is missing", async () => {
|
||||
const result = await decodeRawTransaction(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.hasAllKeys(result, ["error"])
|
||||
assert.include(result.error, "hex can not be empty")
|
||||
})
|
||||
|
||||
it("should throw 503 when network issues", async () => {
|
||||
// Save the existing RPC URL.
|
||||
const savedUrl2 = process.env.RPC_BASEURL
|
||||
|
||||
// Manipulate the URL to cause a 500 network error.
|
||||
process.env.RPC_BASEURL = "http://fakeurl/api/"
|
||||
|
||||
req.params.hex =
|
||||
"0200000001b9b598d7d6d72fc486b2b3a3c03c79b5bade6ec9a77ced850515ab5e64edcc21010000006b483045022100a7b1b08956abb8d6f322aa709d8583c8ea492ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd4139041210360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab4667c57b2786f51c413dffffffff0210270000000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac786e9800000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac00000000"
|
||||
|
||||
const result = await decodeRawTransaction(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
// Restore the saved URL.
|
||||
process.env.RPC_BASEURL = savedUrl2
|
||||
|
||||
assert.isAbove(
|
||||
res.statusCode,
|
||||
499,
|
||||
"HTTP status code 500 or greater expected."
|
||||
)
|
||||
//assert.include(result.error,"Network error: Could not communicate with full node","Error message expected")
|
||||
})
|
||||
|
||||
it("should GET /decodeRawTransaction", async () => {
|
||||
// Mock the RPC call for unit tests.
|
||||
if (process.env.TEST === "unit") {
|
||||
nock(`${process.env.RPC_BASEURL}`)
|
||||
.post(``)
|
||||
.reply(200, { result: mockData.mockDecodeRawTransaction })
|
||||
}
|
||||
|
||||
req.params.hex =
|
||||
"0200000001b9b598d7d6d72fc486b2b3a3c03c79b5bade6ec9a77ced850515ab5e64edcc21010000006b483045022100a7b1b08956abb8d6f322aa709d8583c8ea492ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd4139041210360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab4667c57b2786f51c413dffffffff0210270000000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac786e9800000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac00000000"
|
||||
|
||||
const result = await decodeRawTransaction(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.hasAnyKeys(result, [
|
||||
"txid",
|
||||
"hash",
|
||||
"size",
|
||||
"version",
|
||||
"locktime",
|
||||
"vin",
|
||||
"vout"
|
||||
])
|
||||
assert.isArray(result.vin)
|
||||
assert.isArray(result.vout)
|
||||
})
|
||||
})
|
||||
|
||||
describe("decodeRawTransactionBulk()", () => {
|
||||
const decodeRawTransactionBulk =
|
||||
rawtransactions.testableComponents.decodeRawTransactionBulk
|
||||
|
||||
it("should throw 400 error if hexes array is missing", async () => {
|
||||
const result = await decodeRawTransactionBulk(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.hasAllKeys(result, ["error"])
|
||||
assert.include(result.error, "hexes must be an array")
|
||||
})
|
||||
|
||||
it("should throw 400 error if hexes array is too large", async () => {
|
||||
const testArray = []
|
||||
for (var i = 0; i < 25; i++) testArray.push("")
|
||||
|
||||
req.body.hexes = testArray
|
||||
|
||||
const result = await decodeRawTransactionBulk(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.hasAllKeys(result, ["error"])
|
||||
assert.include(result.error, "Array too large")
|
||||
})
|
||||
|
||||
it("should throw 400 error if hexes is empty", async () => {
|
||||
req.body.hexes = [""]
|
||||
|
||||
const result = await decodeRawTransactionBulk(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.hasAllKeys(result, ["error"])
|
||||
assert.include(result.error, "Encountered empty hex")
|
||||
})
|
||||
|
||||
it("should error on non-array single hex", async () => {
|
||||
req.body.hexes =
|
||||
"0200000001b9b598d7d6d72fc486b2b3a3c03c79b5bade6ec9a77ced850515ab5e64edcc21010000006b483045022100a7b1b08956abb8d6f322aa709d8583c8ea492ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd4139041210360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab4667c57b2786f51c413dffffffff0210270000000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac786e9800000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac00000000"
|
||||
|
||||
const result = await decodeRawTransactionBulk(req, res)
|
||||
|
||||
assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
|
||||
assert.include(
|
||||
result.error,
|
||||
"hexes must be an array",
|
||||
"Proper error message"
|
||||
)
|
||||
})
|
||||
|
||||
it("should decode an array with a single hex", async () => {
|
||||
// Mock the RPC call for unit tests.
|
||||
if (process.env.TEST === "unit") {
|
||||
nock(`${process.env.RPC_BASEURL}`)
|
||||
.post(``)
|
||||
.reply(200, { result: mockData.mockDecodeRawTransaction })
|
||||
}
|
||||
|
||||
req.body.hexes = [
|
||||
"0200000001b9b598d7d6d72fc486b2b3a3c03c79b5bade6ec9a77ced850515ab5e64edcc21010000006b483045022100a7b1b08956abb8d6f322aa709d8583c8ea492ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd4139041210360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab4667c57b2786f51c413dffffffff0210270000000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac786e9800000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac00000000"
|
||||
]
|
||||
|
||||
const result = await decodeRawTransactionBulk(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.hasAnyKeys(result[0], [
|
||||
"txid",
|
||||
"hash",
|
||||
"size",
|
||||
"version",
|
||||
"locktime",
|
||||
"vin",
|
||||
"vout"
|
||||
])
|
||||
assert.isArray(result[0].vin)
|
||||
assert.isArray(result[0].vout)
|
||||
})
|
||||
|
||||
it("should decode an array with multiple hexes", async () => {
|
||||
// Mock the RPC call for unit tests.
|
||||
if (process.env.TEST === "unit") {
|
||||
nock(`${process.env.RPC_BASEURL}`)
|
||||
.post(``)
|
||||
.times(2)
|
||||
.reply(200, { result: mockData.mockDecodeRawTransaction })
|
||||
}
|
||||
|
||||
req.body.hexes = [
|
||||
"0200000001b9b598d7d6d72fc486b2b3a3c03c79b5bade6ec9a77ced850515ab5e64edcc21010000006b483045022100a7b1b08956abb8d6f322aa709d8583c8ea492ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd4139041210360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab4667c57b2786f51c413dffffffff0210270000000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac786e9800000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac00000000",
|
||||
"0200000001b9b598d7d6d72fc486b2b3a3c03c79b5bade6ec9a77ced850515ab5e64edcc21010000006b483045022100a7b1b08956abb8d6f322aa709d8583c8ea492ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd4139041210360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab4667c57b2786f51c413dffffffff0210270000000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac786e9800000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac00000000"
|
||||
]
|
||||
|
||||
const result = await decodeRawTransactionBulk(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.hasAnyKeys(result[0], [
|
||||
"txid",
|
||||
"hash",
|
||||
"size",
|
||||
"version",
|
||||
"locktime",
|
||||
"vin",
|
||||
"vout"
|
||||
])
|
||||
assert.isArray(result[0].vin)
|
||||
assert.isArray(result[0].vout)
|
||||
})
|
||||
})
|
||||
|
||||
describe("decodeScriptSingle()", () => {
|
||||
// block route handler.
|
||||
const decodeScriptSingle =
|
||||
rawtransactions.testableComponents.decodeScriptSingle
|
||||
|
||||
it("should throw error if hex is missing", async () => {
|
||||
const result = await decodeScriptSingle(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.hasAllKeys(result, ["error"])
|
||||
assert.include(result.error, "hex can not be empty")
|
||||
})
|
||||
|
||||
it("should throw 503 when network issues", async () => {
|
||||
// Save the existing RPC URL.
|
||||
const savedUrl2 = process.env.RPC_BASEURL
|
||||
|
||||
// Manipulate the URL to cause a 500 network error.
|
||||
process.env.RPC_BASEURL = "http://fakeurl/api/"
|
||||
|
||||
req.params.hex =
|
||||
"0200000001b9b598d7d6d72fc486b2b3a3c03c79b5bade6ec9a77ced850515ab5e64edcc21010000006b483045022100a7b1b08956abb8d6f322aa709d8583c8ea492ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd4139041210360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab4667c57b2786f51c413dffffffff0210270000000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac786e9800000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac00000000"
|
||||
|
||||
const result = await decodeScriptSingle(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
// Restore the saved URL.
|
||||
process.env.RPC_BASEURL = savedUrl2
|
||||
|
||||
assert.isAbove(
|
||||
res.statusCode,
|
||||
499,
|
||||
"HTTP status code 500 or greater expected."
|
||||
)
|
||||
//assert.include(result.error,"Network error: Could not communicate with full node","Error message expected")
|
||||
})
|
||||
|
||||
it("should GET /decodeScriptSingle", async () => {
|
||||
// Mock the RPC call for unit tests.
|
||||
if (process.env.TEST === "unit") {
|
||||
nock(`${process.env.RPC_BASEURL}`)
|
||||
.post(``)
|
||||
.reply(200, { result: mockData.mockDecodeScript })
|
||||
}
|
||||
|
||||
req.params.hex =
|
||||
"0200000001b9b598d7d6d72fc486b2b3a3c03c79b5bade6ec9a77ced850515ab5e64edcc21010000006b483045022100a7b1b08956abb8d6f322aa709d8583c8ea492ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd4139041210360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab4667c57b2786f51c413dffffffff0210270000000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac786e9800000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac00000000"
|
||||
|
||||
const result = await decodeScriptSingle(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.hasAllKeys(result, ["asm", "type", "p2sh"])
|
||||
})
|
||||
})
|
||||
|
||||
describe("decodeScriptBulk()", () => {
|
||||
const decodeScriptBulk = rawtransactions.testableComponents.decodeScriptBulk
|
||||
|
||||
it("should throw 400 error if hexes array is missing", async () => {
|
||||
const result = await decodeScriptBulk(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.hasAllKeys(result, ["error"])
|
||||
assert.include(result.error, "hexes must be an array")
|
||||
})
|
||||
|
||||
it("should throw 400 error if hexes array is too large", async () => {
|
||||
const testArray = []
|
||||
for (var i = 0; i < 25; i++) testArray.push("")
|
||||
|
||||
req.body.hexes = testArray
|
||||
|
||||
const result = await decodeScriptBulk(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.hasAllKeys(result, ["error"])
|
||||
assert.include(result.error, "Array too large")
|
||||
})
|
||||
|
||||
it("should throw 400 error if hexes is empty", async () => {
|
||||
req.body.hexes = [""]
|
||||
|
||||
const result = await decodeScriptBulk(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.hasAllKeys(result, ["error"])
|
||||
assert.include(result.error, "Encountered empty hex")
|
||||
})
|
||||
|
||||
it("should error on non-array single hex", async () => {
|
||||
req.body.hexes =
|
||||
"0200000001b9b598d7d6d72fc486b2b3a3c03c79b5bade6ec9a77ced850515ab5e64edcc21010000006b483045022100a7b1b08956abb8d6f322aa709d8583c8ea492ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd4139041210360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab4667c57b2786f51c413dffffffff0210270000000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac786e9800000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac00000000"
|
||||
|
||||
const result = await decodeScriptBulk(req, res)
|
||||
|
||||
assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
|
||||
assert.include(
|
||||
result.error,
|
||||
"hexes must be an array",
|
||||
"Proper error message"
|
||||
)
|
||||
})
|
||||
|
||||
it("should decode an array with a single hex", async () => {
|
||||
// Mock the RPC call for unit tests.
|
||||
if (process.env.TEST === "unit") {
|
||||
nock(`${process.env.RPC_BASEURL}`)
|
||||
.post(``)
|
||||
.reply(200, { result: mockData.mockDecodeScript })
|
||||
}
|
||||
|
||||
req.body.hexes = [
|
||||
"4830450221009a51e00ec3524a7389592bc27bea4af5104a59510f5f0cfafa64bbd5c164ca2e02206c2a8bbb47eabdeed52f17d7df668d521600286406930426e3a9415fe10ed592012102e6e1423f7abde8b70bca3e78a7d030e5efabd3eb35c19302542b5fe7879c1a16"
|
||||
]
|
||||
|
||||
const result = await decodeScriptBulk(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.hasAllKeys(result[0], ["asm", "type", "p2sh"])
|
||||
})
|
||||
|
||||
it("should decode an array with a multiple hexes", async () => {
|
||||
// Mock the RPC call for unit tests.
|
||||
if (process.env.TEST === "unit") {
|
||||
nock(`${process.env.RPC_BASEURL}`)
|
||||
.post(``)
|
||||
.times(2)
|
||||
.reply(200, { result: mockData.mockDecodeScript })
|
||||
}
|
||||
|
||||
req.body.hexes = [
|
||||
"4830450221009a51e00ec3524a7389592bc27bea4af5104a59510f5f0cfafa64bbd5c164ca2e02206c2a8bbb47eabdeed52f17d7df668d521600286406930426e3a9415fe10ed592012102e6e1423f7abde8b70bca3e78a7d030e5efabd3eb35c19302542b5fe7879c1a16",
|
||||
"4830450221009a51e00ec3524a7389592bc27bea4af5104a59510f5f0cfafa64bbd5c164ca2e02206c2a8bbb47eabdeed52f17d7df668d521600286406930426e3a9415fe10ed592012102e6e1423f7abde8b70bca3e78a7d030e5efabd3eb35c19302542b5fe7879c1a16"
|
||||
]
|
||||
|
||||
const result = await decodeScriptBulk(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.equal(result.length, 2)
|
||||
assert.hasAllKeys(result[0], ["asm", "type", "p2sh"])
|
||||
})
|
||||
})
|
||||
|
||||
describe("getRawTransactionBulk()", () => {
|
||||
// block route handler.
|
||||
const getRawTransactionBulk =
|
||||
rawtransactions.testableComponents.getRawTransactionBulk
|
||||
|
||||
it("should throw 400 error if txids array is missing", async () => {
|
||||
const result = await getRawTransactionBulk(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.hasAllKeys(result, ["error"])
|
||||
assert.include(result.error, "txids must be an array")
|
||||
})
|
||||
|
||||
it("should throw 400 error if txids array is too large", async () => {
|
||||
const testArray = []
|
||||
for (var i = 0; i < 25; i++) testArray.push("")
|
||||
|
||||
req.body.txids = testArray
|
||||
|
||||
const result = await getRawTransactionBulk(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.hasAllKeys(result, ["error"])
|
||||
assert.include(result.error, "Array too large")
|
||||
})
|
||||
|
||||
it("should throw 400 error if txid is empty", async () => {
|
||||
req.body.txids = [""]
|
||||
|
||||
const result = await getRawTransactionBulk(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.hasAllKeys(result, ["error"])
|
||||
assert.include(result.error, "Encountered empty TXID")
|
||||
})
|
||||
|
||||
it("should throw 400 error if txid is invalid", async () => {
|
||||
// Mock the RPC call for unit tests.
|
||||
if (process.env.TEST === "unit") {
|
||||
nock(`${process.env.RPC_BASEURL}`)
|
||||
.post(``)
|
||||
.reply(500, {
|
||||
error: { message: "parameter 1 must be of length 64 (not 6)" }
|
||||
})
|
||||
}
|
||||
|
||||
req.body.txids = ["abc123"]
|
||||
|
||||
const result = await getRawTransactionBulk(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.hasAllKeys(result, ["error"])
|
||||
assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
|
||||
assert.include(result.error, "parameter 1 must be of length 64 (not 6)")
|
||||
})
|
||||
|
||||
it("should get concise transaction data", async () => {
|
||||
// Mock the RPC call for unit tests.
|
||||
if (process.env.TEST === "unit") {
|
||||
nock(`${process.env.RPC_BASEURL}`)
|
||||
.post(``)
|
||||
.reply(200, { result: mockData.mockRawTransactionConcise })
|
||||
}
|
||||
|
||||
req.body.txids = [
|
||||
"bd320377db7026a3dd5c7ec444596c0ee18fc25c4f34ee944adc03e432ce1971"
|
||||
]
|
||||
|
||||
const result = await getRawTransactionBulk(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.isString(result[0])
|
||||
})
|
||||
|
||||
it("should get verbose transaction data", async () => {
|
||||
// Mock the RPC call for unit tests.
|
||||
if (process.env.TEST === "unit") {
|
||||
nock(`${process.env.RPC_BASEURL}`)
|
||||
.post(``)
|
||||
.reply(200, { result: mockData.mockRawTransactionVerbose })
|
||||
}
|
||||
|
||||
req.body.txids = [
|
||||
"bd320377db7026a3dd5c7ec444596c0ee18fc25c4f34ee944adc03e432ce1971"
|
||||
]
|
||||
req.body.verbose = true
|
||||
|
||||
const result = await getRawTransactionBulk(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.hasAnyKeys(result[0], [
|
||||
"hex",
|
||||
"txid",
|
||||
"hash",
|
||||
"size",
|
||||
"version",
|
||||
"locktime",
|
||||
"vin",
|
||||
"vout",
|
||||
"blockhash",
|
||||
"confirmations",
|
||||
"time",
|
||||
"blocktime"
|
||||
])
|
||||
assert.isArray(result[0].vin)
|
||||
assert.isArray(result[0].vout)
|
||||
})
|
||||
})
|
||||
|
||||
describe("getRawTransactionSingle()", () => {
|
||||
// block route handler.
|
||||
const getRawTransactionSingle =
|
||||
rawtransactions.testableComponents.getRawTransactionSingle
|
||||
|
||||
it("should throw 400 error if txid is missing", async () => {
|
||||
const result = await getRawTransactionSingle(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.hasAllKeys(result, ["error"])
|
||||
assert.include(result.error, "txid can not be empty")
|
||||
})
|
||||
|
||||
it("should throw 400 error if txid is invalid", async () => {
|
||||
// Mock the RPC call for unit tests.
|
||||
if (process.env.TEST === "unit") {
|
||||
nock(`${process.env.RPC_BASEURL}`)
|
||||
.post(``)
|
||||
.reply(500, {
|
||||
error: { message: "parameter 1 must be of length 64 (not 6)" }
|
||||
})
|
||||
}
|
||||
|
||||
req.params.txid = "abc123"
|
||||
|
||||
const result = await getRawTransactionSingle(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.hasAllKeys(result, ["error"])
|
||||
assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
|
||||
assert.include(result.error, "parameter 1 must be of length 64 (not 6)")
|
||||
})
|
||||
|
||||
it("should get concise transaction data", async () => {
|
||||
// Mock the RPC call for unit tests.
|
||||
if (process.env.TEST === "unit") {
|
||||
nock(`${process.env.RPC_BASEURL}`)
|
||||
.post(``)
|
||||
.reply(200, { result: mockData.mockRawTransactionConcise })
|
||||
}
|
||||
|
||||
req.params.txid =
|
||||
"bd320377db7026a3dd5c7ec444596c0ee18fc25c4f34ee944adc03e432ce1971"
|
||||
|
||||
const result = await getRawTransactionSingle(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.isString(result)
|
||||
})
|
||||
|
||||
it("should get verbose transaction data", async () => {
|
||||
// Mock the RPC call for unit tests.
|
||||
if (process.env.TEST === "unit") {
|
||||
nock(`${process.env.RPC_BASEURL}`)
|
||||
.post(``)
|
||||
.reply(200, { result: mockData.mockRawTransactionVerbose })
|
||||
}
|
||||
|
||||
req.params.txid =
|
||||
"bd320377db7026a3dd5c7ec444596c0ee18fc25c4f34ee944adc03e432ce1971"
|
||||
req.query.verbose = "true"
|
||||
|
||||
const result = await getRawTransactionSingle(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.hasAnyKeys(result, [
|
||||
"hex",
|
||||
"txid",
|
||||
"hash",
|
||||
"size",
|
||||
"version",
|
||||
"locktime",
|
||||
"vin",
|
||||
"vout",
|
||||
"blockhash",
|
||||
"confirmations",
|
||||
"time",
|
||||
"blocktime"
|
||||
])
|
||||
assert.isArray(result.vin)
|
||||
assert.isArray(result.vout)
|
||||
})
|
||||
})
|
||||
|
||||
describe("sendRawTransactionBulk()", () => {
|
||||
const sendRawTransaction =
|
||||
rawtransactions.testableComponents.sendRawTransactionBulk
|
||||
|
||||
it("should throw 400 error if hexs array is missing", async () => {
|
||||
const result = await sendRawTransaction(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.hasAllKeys(result, ["error"])
|
||||
assert.include(result.error, "hex must be an array")
|
||||
})
|
||||
|
||||
it("should throw 400 error if hexs array is too large", async () => {
|
||||
const testArray = []
|
||||
for (var i = 0; i < 25; i++) testArray.push("")
|
||||
|
||||
req.body.hexes = testArray
|
||||
|
||||
const result = await sendRawTransaction(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.hasAllKeys(result, ["error"])
|
||||
assert.include(result.error, "Array too large")
|
||||
})
|
||||
|
||||
it("should throw 400 error if hex array element is empty", async () => {
|
||||
req.body.hexes = [""]
|
||||
|
||||
const result = await sendRawTransaction(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.hasAllKeys(result, ["error"])
|
||||
assert.include(result.error, "Encountered empty hex")
|
||||
})
|
||||
|
||||
it("should throw 500 error if hex is invalid", async () => {
|
||||
// Mock the RPC call for unit tests.
|
||||
if (process.env.TEST === "unit") {
|
||||
nock(`${process.env.RPC_BASEURL}`)
|
||||
.post(``)
|
||||
.reply(500, {
|
||||
error: { message: "TX decode failed" }
|
||||
})
|
||||
}
|
||||
|
||||
req.body.hexes = ["abc123"]
|
||||
|
||||
const result = await sendRawTransaction(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.hasAllKeys(result, ["error"])
|
||||
assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
|
||||
assert.include(result.error, "TX decode failed")
|
||||
})
|
||||
|
||||
it("should submit hex encoded transaction", async () => {
|
||||
// This is a difficult test to run as transaction hex is invalid after a
|
||||
// block confirmation. So the unit tests simulates what the output 'should'
|
||||
// be, but the integration asserts an expected failure.
|
||||
|
||||
// Mock the RPC call for unit tests.
|
||||
if (process.env.TEST === "unit") {
|
||||
nock(`${process.env.RPC_BASEURL}`)
|
||||
.post(``)
|
||||
.reply(200, {
|
||||
result:
|
||||
"aef8848396e67532b42008b9d75b5a5a3459a6717740f31f0553b74102b4b118"
|
||||
})
|
||||
}
|
||||
|
||||
req.body.hexes = [
|
||||
"0200000001189f7cf4303e2e0bcc5af4be323b9b397dd4104ca2de09528eb90a1450b8a999010000006a4730440220212ec2ffce136a30cec1bc86a40b08a2afdeb6f8dbd652d7bcb07b1aad6dfa8c022041f59585273b89d88879a9a531ba3272dc953f48ff57dad955b2dee70e76c0624121030143ffd18f1c4add75c86b2f930d9551d51f7a6bd786314247022b7afc45d231ffffffff0230d39700000000001976a914af64a026e06910c59463b000d18c3d125d7e951a88ac58c20000000000001976a914af64a026e06910c59463b000d18c3d125d7e951a88ac00000000"
|
||||
]
|
||||
|
||||
const result = await sendRawTransaction(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
if (process.env.TEST === "unit") {
|
||||
assert.isArray(result)
|
||||
assert.isString(result[0])
|
||||
|
||||
// Integration test
|
||||
} else {
|
||||
assert.hasAllKeys(result, ["error"])
|
||||
assert.include(result.error, "transaction already in block chain")
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe("sendRawTransactionSingle()", () => {
|
||||
// block route handler.
|
||||
const sendRawTransaction =
|
||||
rawtransactions.testableComponents.sendRawTransactionSingle
|
||||
|
||||
it("should throw an error for an empty hex", async () => {
|
||||
req.params.hex = ""
|
||||
|
||||
const result = await sendRawTransaction(req, res)
|
||||
|
||||
assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
|
||||
assert.include(
|
||||
result.error,
|
||||
"Encountered empty hex",
|
||||
"Proper error message"
|
||||
)
|
||||
})
|
||||
|
||||
it("should throw an error for a non-string", async () => {
|
||||
req.params.hex = 456
|
||||
|
||||
const result = await sendRawTransaction(req, res)
|
||||
|
||||
assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
|
||||
assert.include(
|
||||
result.error,
|
||||
"hex must be a string",
|
||||
"Proper error message"
|
||||
)
|
||||
})
|
||||
|
||||
it("should throw 500 when network issues", async () => {
|
||||
// Save the existing RPC URL.
|
||||
const savedUrl = process.env.BITCOINCOM_BASEURL
|
||||
const savedUrl2 = process.env.RPC_BASEURL
|
||||
|
||||
// Manipulate the URL to cause a 500 network error.
|
||||
process.env.BITCOINCOM_BASEURL = "http://fakeurl/api/"
|
||||
process.env.RPC_BASEURL = "http://fakeurl/api/"
|
||||
|
||||
req.params.hex =
|
||||
"0200000001189f7cf4303e2e0bcc5af4be323b9b397dd4104ca2de09528eb90a1450b8a999010000006a4730440220212ec2ffce136a30cec1bc86a40b08a2afdeb6f8dbd652d7bcb07b1aad6dfa8c022041f59585273b89d88879a9a531ba3272dc953f48ff57dad955b2dee70e76c0624121030143ffd18f1c4add75c86b2f930d9551d51f7a6bd786314247022b7afc45d231ffffffff0230d39700000000001976a914af64a026e06910c59463b000d18c3d125d7e951a88ac58c20000000000001976a914af64a026e06910c59463b000d18c3d125d7e951a88ac00000000"
|
||||
const result = await sendRawTransaction(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
// Restore the saved URL.
|
||||
process.env.BITCOINCOM_BASEURL = savedUrl
|
||||
process.env.RPC_BASEURL = savedUrl2
|
||||
|
||||
assert.isAbove(
|
||||
res.statusCode,
|
||||
499,
|
||||
"HTTP status code 500 or great expected."
|
||||
)
|
||||
})
|
||||
|
||||
it("should throw an error for invalid hex", async () => {
|
||||
req.params.hex = "abc123"
|
||||
|
||||
// Mock the RPC call for unit tests.
|
||||
if (process.env.TEST === "unit") {
|
||||
nock(`${process.env.RPC_BASEURL}`)
|
||||
.post(``)
|
||||
.reply(500, {
|
||||
error: { message: "TX decode failed" }
|
||||
})
|
||||
}
|
||||
|
||||
const result = await sendRawTransaction(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.hasAllKeys(result, ["error"])
|
||||
assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
|
||||
assert.include(result.error, "TX decode failed")
|
||||
})
|
||||
|
||||
it("should GET /sendRawTransaction/:hex", async () => {
|
||||
// This is a difficult test to run as transaction hex is invalid after a
|
||||
// block confirmation. So the unit tests simulates what the output 'should'
|
||||
// be, but the integration asserts an expected failure.
|
||||
|
||||
// Mock the RPC call for unit tests.
|
||||
if (process.env.TEST === "unit") {
|
||||
nock(`${process.env.RPC_BASEURL}`)
|
||||
.post(``)
|
||||
.reply(200, {
|
||||
result:
|
||||
"aef8848396e67532b42008b9d75b5a5a3459a6717740f31f0553b74102b4b118"
|
||||
})
|
||||
}
|
||||
|
||||
req.params.hex =
|
||||
"0200000001189f7cf4303e2e0bcc5af4be323b9b397dd4104ca2de09528eb90a1450b8a999010000006a4730440220212ec2ffce136a30cec1bc86a40b08a2afdeb6f8dbd652d7bcb07b1aad6dfa8c022041f59585273b89d88879a9a531ba3272dc953f48ff57dad955b2dee70e76c0624121030143ffd18f1c4add75c86b2f930d9551d51f7a6bd786314247022b7afc45d231ffffffff0230d39700000000001976a914af64a026e06910c59463b000d18c3d125d7e951a88ac58c20000000000001976a914af64a026e06910c59463b000d18c3d125d7e951a88ac00000000"
|
||||
|
||||
const result = await sendRawTransaction(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
if (process.env.TEST === "unit") {
|
||||
assert.isString(result)
|
||||
|
||||
// Integration test
|
||||
} else {
|
||||
assert.hasAllKeys(result, ["error"])
|
||||
assert.include(result.error, "transaction already in block chain")
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
+971
@@ -0,0 +1,971 @@
|
||||
/*
|
||||
TESTS FOR THE SLP.TS LIBRARY
|
||||
|
||||
This test file uses the environment variable TEST to switch between unit
|
||||
and integration tests. By default, TEST is set to 'unit'. Set this variable
|
||||
to 'integration' to run the tests against BCH mainnet.
|
||||
|
||||
TODO:
|
||||
-See listSingleToken() tests.
|
||||
*/
|
||||
|
||||
"use strict"
|
||||
|
||||
const chai = require("chai")
|
||||
const assert = chai.assert
|
||||
const nock = require("nock") // HTTP mocking
|
||||
const sinon = require("sinon")
|
||||
const proxyquire = require("proxyquire").noPreserveCache()
|
||||
|
||||
// Prepare the slpRoute for stubbing dependcies on slpjs.
|
||||
const slpRoute = require("../../dist/routes/v2/slp")
|
||||
const pathStub = {} // Used to stub methods within slpjs.
|
||||
const slpRouteStub = proxyquire("../../dist/routes/v2/slp", { slpjs: pathStub })
|
||||
|
||||
let originalEnvVars // Used during transition from integration to unit tests.
|
||||
|
||||
// Mocking data.
|
||||
const { mockReq, mockRes } = require("./mocks/express-mocks")
|
||||
const mockData = require("./mocks/slp-mocks")
|
||||
const slpjsMock = require("./mocks/slpjs-mocks")
|
||||
|
||||
// Used for debugging.
|
||||
const util = require("util")
|
||||
util.inspect.defaultOptions = { depth: 1 }
|
||||
|
||||
describe("#SLP", () => {
|
||||
let req, res, mockServerUrl
|
||||
let sandbox
|
||||
|
||||
before(() => {
|
||||
// Save existing environment variables.
|
||||
originalEnvVars = {
|
||||
BITDB_URL: process.env.BITDB_URL,
|
||||
BITCOINCOM_BASEURL: process.env.BITCOINCOM_BASEURL,
|
||||
SLPDB_URL: process.env.SLPDB_URL
|
||||
}
|
||||
|
||||
// Set default environment variables for unit tests.
|
||||
if (!process.env.TEST) process.env.TEST = "unit"
|
||||
|
||||
// Block network connections for unit tests.
|
||||
if (process.env.TEST === "unit") {
|
||||
process.env.BITDB_URL = "http://fakeurl/"
|
||||
process.env.BITCOINCOM_BASEURL = "http://fakeurl/"
|
||||
process.env.SLPDB_URL = "http://fakeurl/"
|
||||
mockServerUrl = `http://fakeurl`
|
||||
}
|
||||
})
|
||||
|
||||
// Setup the mocks before each test.
|
||||
beforeEach(() => {
|
||||
// Mock the req and res objects used by Express routes.
|
||||
req = mockReq
|
||||
res = mockRes
|
||||
|
||||
// Explicitly reset the parmas and body.
|
||||
//req.params = {}
|
||||
req.body = {}
|
||||
req.query = {}
|
||||
req.locals = {}
|
||||
|
||||
// Activate nock if it's inactive.
|
||||
if (!nock.isActive()) nock.activate()
|
||||
|
||||
sandbox = sinon.createSandbox()
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
// Clean up HTTP mocks.
|
||||
nock.cleanAll() // clear interceptor list.
|
||||
nock.restore()
|
||||
|
||||
sandbox.restore()
|
||||
})
|
||||
|
||||
after(() => {
|
||||
// Restore any pre-existing environment variables.
|
||||
process.env.BITDB_URL = originalEnvVars.BITDB_URL
|
||||
process.env.BITCOINCOM_BASEURL = originalEnvVars.BITCOINCOM_BASEURL
|
||||
process.env.SLPDB_URL = originalEnvVars.SLPDB_URL
|
||||
})
|
||||
|
||||
describe("#root", async () => {
|
||||
// root route handler.
|
||||
const root = slpRoute.testableComponents.root
|
||||
|
||||
it("should respond to GET for base route", async () => {
|
||||
const result = root(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.equal(result.status, "slp", "Returns static string")
|
||||
})
|
||||
})
|
||||
|
||||
describe("list()", () => {
|
||||
// list route handler
|
||||
const list = slpRoute.testableComponents.list
|
||||
|
||||
it("should throw 500 when network issues", async () => {
|
||||
// Save the existing SLPDB_URL.
|
||||
const savedUrl2 = process.env.SLPDB_URL
|
||||
|
||||
// Manipulate the URL to cause a 500 network error.
|
||||
process.env.SLPDB_URL = "http://fakeurl/api/"
|
||||
|
||||
const result = await list(req, res)
|
||||
// console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
// Restore the saved URL.
|
||||
process.env.SLPDB_URL = savedUrl2
|
||||
|
||||
assert.isAbove(
|
||||
res.statusCode,
|
||||
499,
|
||||
"HTTP status code 500 or greater expected."
|
||||
)
|
||||
//assert.include(result.error,"Network error: Could not communicate with full node","Error message expected")
|
||||
})
|
||||
|
||||
it("should GET list", async () => {
|
||||
// Mock the RPC call for unit tests.
|
||||
if (process.env.TEST === "unit") {
|
||||
const b64 = `eyJ2IjozLCJxIjp7ImRiIjpbInQiXSwiZmluZCI6eyIkcXVlcnkiOnt9fSwicHJvamVjdCI6eyJ0b2tlbkRldGFpbHMiOjEsInRva2VuU3RhdHMiOjEsIl9pZCI6MH0sImxpbWl0IjoxMDB9fQ==`
|
||||
|
||||
nock(process.env.SLPDB_URL)
|
||||
.get(uri => uri.includes("/"))
|
||||
.reply(200, mockData.mockList)
|
||||
}
|
||||
|
||||
const result = await list(req, res)
|
||||
// console.log(`test result: ${util.inspect(result)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.hasAnyKeys(result[0], [
|
||||
"id",
|
||||
"timestamp",
|
||||
"symbol",
|
||||
"name",
|
||||
"documentUri",
|
||||
"documentHash",
|
||||
"decimals",
|
||||
"initialTokenQty"
|
||||
])
|
||||
})
|
||||
})
|
||||
|
||||
describe("listSingleToken()", () => {
|
||||
const listSingleToken = slpRoute.testableComponents.listSingleToken
|
||||
|
||||
it("should throw 400 if tokenId is empty", async () => {
|
||||
const result = await listSingleToken(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.hasAllKeys(result, ["error"])
|
||||
assert.include(result.error, "tokenId can not be empty")
|
||||
})
|
||||
|
||||
it("should throw 503 when network issues", async () => {
|
||||
// Save the existing BITDB_URL.
|
||||
const savedUrl2 = process.env.SLPDB_URL
|
||||
|
||||
// Manipulate the URL to cause a 500 network error.
|
||||
process.env.SLPDB_URL = "http://fakeurl/api/"
|
||||
|
||||
req.params.tokenId =
|
||||
"650dea14c77f4d749608e36e375450c9ac91deb8b1b53e50cb0de2059a52d19a"
|
||||
|
||||
const result = await listSingleToken(req, res)
|
||||
// console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
// Restore the saved URL.
|
||||
process.env.SLPDB_URL = savedUrl2
|
||||
|
||||
assert.isAbove(
|
||||
res.statusCode,
|
||||
499,
|
||||
"HTTP status code 500 or greater expected."
|
||||
)
|
||||
//assert.include(result.error,"Network error: Could not communicate with full node","Error message expected")
|
||||
})
|
||||
|
||||
it("should return 'not found' for mainnet txid on testnet", async () => {
|
||||
// Mock the RPC call for unit tests.
|
||||
if (process.env.TEST === "unit") {
|
||||
nock(mockServerUrl)
|
||||
.get(uri => uri.includes("/"))
|
||||
.reply(200, mockData.mockSingleToken)
|
||||
}
|
||||
|
||||
req.params.tokenId =
|
||||
// testnet
|
||||
//"650dea14c77f4d749608e36e375450c9ac91deb8b1b53e50cb0de2059a52d19a"
|
||||
// mainnet
|
||||
"259908ae44f46ef585edef4bcc1e50dc06e4c391ac4be929fae27235b8158cf1"
|
||||
|
||||
const result = await listSingleToken(req, res)
|
||||
// console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.hasAllKeys(result, ["id"])
|
||||
assert.include(result.id, "not found")
|
||||
})
|
||||
|
||||
it("should get token information", async () => {
|
||||
// testnet
|
||||
const tokenIdToTest =
|
||||
"650dea14c77f4d749608e36e375450c9ac91deb8b1b53e50cb0de2059a52d19a"
|
||||
|
||||
// Mock the RPC call for unit tests.
|
||||
if (process.env.TEST === "unit") {
|
||||
nock(mockServerUrl)
|
||||
.get(uri => uri.includes("/"))
|
||||
.reply(200, mockData.mockSingleToken)
|
||||
}
|
||||
|
||||
req.params.tokenId = tokenIdToTest
|
||||
|
||||
const result = await listSingleToken(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.hasAllKeys(result, [
|
||||
"id",
|
||||
"blockCreated",
|
||||
"blockLastActiveMint",
|
||||
"blockLastActiveSend",
|
||||
"circulatingSupply",
|
||||
"containsBaton",
|
||||
"mintingBatonStatus",
|
||||
"txnsSinceGenesis",
|
||||
"versionType",
|
||||
"timestamp",
|
||||
"symbol",
|
||||
"name",
|
||||
"documentUri",
|
||||
"documentHash",
|
||||
"decimals",
|
||||
"initialTokenQty",
|
||||
"totalBurned",
|
||||
"totalMinted",
|
||||
"validAddresses"
|
||||
])
|
||||
})
|
||||
})
|
||||
|
||||
describe("listBulkToken()", () => {
|
||||
const listBulkToken = slpRoute.testableComponents.listBulkToken
|
||||
|
||||
it("should throw 400 if tokenIds array is empty", async () => {
|
||||
const result = await listBulkToken(req, res)
|
||||
// console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.hasAllKeys(result, ["error"])
|
||||
assert.include(result.error, "tokenIds needs to be an array")
|
||||
assert.equal(res.statusCode, 400)
|
||||
})
|
||||
|
||||
it("should throw 400 error if array is too large", async () => {
|
||||
const testArray = []
|
||||
for (var i = 0; i < 25; i++) testArray.push("")
|
||||
|
||||
req.body.tokenIds = testArray
|
||||
|
||||
const result = await listBulkToken(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.hasAllKeys(result, ["error"])
|
||||
assert.include(result.error, "Array too large")
|
||||
})
|
||||
|
||||
it("should throw 400 if tokenId is empty", async () => {
|
||||
// Mock the RPC call for unit tests.
|
||||
if (process.env.TEST === "unit") {
|
||||
nock(mockServerUrl)
|
||||
.get(uri => uri.includes("/"))
|
||||
.reply(200, mockData.mockEmptyTokenId)
|
||||
}
|
||||
req.body.tokenIds = ""
|
||||
|
||||
const result = await listBulkToken(req, res)
|
||||
// console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.hasAllKeys(result, ["error"])
|
||||
assert.include(
|
||||
result.error,
|
||||
"tokenIds needs to be an array. Use GET for single tokenId."
|
||||
)
|
||||
})
|
||||
|
||||
it("should throw 503 when network issues", async () => {
|
||||
// Save the existing BITDB_URL.
|
||||
const savedUrl2 = process.env.SLPDB_URL
|
||||
|
||||
// Manipulate the URL to cause a 500 network error.
|
||||
process.env.SLPDB_URL = "http://fakeurl/api/"
|
||||
|
||||
req.body.tokenIds = [
|
||||
"650dea14c77f4d749608e36e375450c9ac91deb8b1b53e50cb0de2059a52d19a"
|
||||
]
|
||||
|
||||
const result = await listBulkToken(req, res)
|
||||
// console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
// Restore the saved URL.
|
||||
process.env.SLPDB_URL = savedUrl2
|
||||
|
||||
assert.isAbove(
|
||||
res.statusCode,
|
||||
499,
|
||||
"HTTP status code 500 or greater expected."
|
||||
)
|
||||
//assert.include(result.error,"Network error: Could not communicate with full node","Error message expected")
|
||||
})
|
||||
|
||||
it("should return 'not found' for mainnet txid on testnet", async () => {
|
||||
// Mock the RPC call for unit tests.
|
||||
if (process.env.TEST === "unit") {
|
||||
nock(mockServerUrl)
|
||||
.get(uri => uri.includes("/"))
|
||||
.reply(200, mockData.mockSingleTokenError)
|
||||
}
|
||||
|
||||
req.body.tokenIds =
|
||||
// testnet
|
||||
//"650dea14c77f4d749608e36e375450c9ac91deb8b1b53e50cb0de2059a52d19a"
|
||||
// mainnet
|
||||
["0b314bc2b2905b8844222871c6b665ae3494117c83b11302824561bb904efb6b"]
|
||||
|
||||
const result = await listBulkToken(req, res)
|
||||
// console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.hasAllKeys(result[0], ["id", "valid"])
|
||||
assert.strictEqual(result[0].valid, false)
|
||||
})
|
||||
|
||||
it("should get token information for single token ID", async () => {
|
||||
// Mock the RPC call for unit tests.
|
||||
if (process.env.TEST === "unit") {
|
||||
nock(mockServerUrl)
|
||||
.get(uri => uri.includes("/"))
|
||||
.reply(200, mockData.mockSingleToken)
|
||||
}
|
||||
|
||||
req.body.tokenIds =
|
||||
// testnet
|
||||
["650dea14c77f4d749608e36e375450c9ac91deb8b1b53e50cb0de2059a52d19a"]
|
||||
|
||||
const result = await listBulkToken(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.hasAllKeys(result[0], [
|
||||
"blockCreated",
|
||||
"blockLastActiveMint",
|
||||
"blockLastActiveSend",
|
||||
"circulatingSupply",
|
||||
"containsBaton",
|
||||
"mintingBatonStatus",
|
||||
"txnsSinceGenesis",
|
||||
"versionType",
|
||||
"timestamp",
|
||||
"symbol",
|
||||
"name",
|
||||
"documentUri",
|
||||
"documentHash",
|
||||
"decimals",
|
||||
"initialTokenQty",
|
||||
"id",
|
||||
"totalBurned",
|
||||
"totalMinted",
|
||||
"validAddresses"
|
||||
])
|
||||
})
|
||||
|
||||
it("should get token information for multiple token IDs", async () => {
|
||||
// Mock the RPC call for unit tests.
|
||||
if (process.env.TEST === "unit") {
|
||||
nock(mockServerUrl)
|
||||
.get(uri => uri.includes("/"))
|
||||
.times(2)
|
||||
.reply(200, mockData.mockSingleToken)
|
||||
}
|
||||
|
||||
req.body.tokenIds =
|
||||
// testnet
|
||||
[
|
||||
"650dea14c77f4d749608e36e375450c9ac91deb8b1b53e50cb0de2059a52d19a",
|
||||
"c35a87afad11c8d086c1449ffd8b0a84324e72b15b1bcfdf166a493551b4eea6"
|
||||
]
|
||||
|
||||
const result = await listBulkToken(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.hasAllKeys(result[0], [
|
||||
"blockCreated",
|
||||
"blockLastActiveMint",
|
||||
"blockLastActiveSend",
|
||||
"circulatingSupply",
|
||||
"containsBaton",
|
||||
"mintingBatonStatus",
|
||||
"txnsSinceGenesis",
|
||||
"versionType",
|
||||
"timestamp",
|
||||
"symbol",
|
||||
"name",
|
||||
"documentUri",
|
||||
"documentHash",
|
||||
"decimals",
|
||||
"initialTokenQty",
|
||||
"id",
|
||||
"totalBurned",
|
||||
"totalMinted",
|
||||
"validAddresses"
|
||||
])
|
||||
})
|
||||
})
|
||||
|
||||
describe("balancesForAddress()", () => {
|
||||
const balancesForAddress = slpRoute.testableComponents.balancesForAddress
|
||||
|
||||
it("should throw 400 if address is empty", async () => {
|
||||
const result = await balancesForAddress(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.hasAllKeys(result, ["error"])
|
||||
assert.include(result.error, "address can not be empty")
|
||||
})
|
||||
|
||||
it("should throw 400 if address is invalid", async () => {
|
||||
req.params.address = "badAddress"
|
||||
|
||||
const result = await balancesForAddress(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.hasAllKeys(result, ["error"])
|
||||
assert.include(result.error, "Invalid BCH address.")
|
||||
})
|
||||
|
||||
it("should throw 400 if address network mismatch", async () => {
|
||||
req.params.address =
|
||||
"simpleledger:qr5agtachyxvrwxu76vzszan5pnvuzy8duhv4lxrsk"
|
||||
|
||||
const result = await balancesForAddress(req, res)
|
||||
// console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.hasAllKeys(result, ["error"])
|
||||
assert.include(result.error, "Invalid")
|
||||
})
|
||||
|
||||
it("should throw 5XX error when network issues", async () => {
|
||||
// Save the existing SLPDB_URL.
|
||||
const savedUrl2 = process.env.SLPDB_URL
|
||||
|
||||
// Manipulate the URL to cause a 500 network error.
|
||||
process.env.SLPDB_URL = "http://fakeurl/api/"
|
||||
|
||||
req.params.address = "slptest:qz35h5mfa8w2pqma2jq06lp7dnv5fxkp2shlcycvd5"
|
||||
|
||||
const result = await balancesForAddress(req, res)
|
||||
// console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
// Restore the saved URL.
|
||||
process.env.SLPDB_URL = savedUrl2
|
||||
|
||||
assert.isAbove(
|
||||
res.statusCode,
|
||||
499,
|
||||
"HTTP status code 500 or greater expected."
|
||||
)
|
||||
assert.include(
|
||||
result.error,
|
||||
"Network error: Could not communicate",
|
||||
"Error message expected"
|
||||
)
|
||||
})
|
||||
|
||||
it("should get token balance for an address", async () => {
|
||||
// Mock the RPC call for unit tests.
|
||||
if (process.env.TEST === "unit") {
|
||||
nock(mockServerUrl)
|
||||
.get(uri => uri.includes("/"))
|
||||
.times(2)
|
||||
.reply(200, mockData.mockSingleAddress)
|
||||
}
|
||||
|
||||
req.params.address = "slptest:pz0qcslrqn7hr44hsszwl4lw5r6udkg6zqv7sq3kk7"
|
||||
|
||||
const result = await balancesForAddress(req, res)
|
||||
// console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.hasAllKeys(result[0], [
|
||||
"tokenId",
|
||||
"balance",
|
||||
"slpAddress",
|
||||
"decimalCount"
|
||||
])
|
||||
})
|
||||
})
|
||||
|
||||
describe("balancesForAddressByTokenID()", () => {
|
||||
const balancesForAddressByTokenID =
|
||||
slpRoute.testableComponents.balancesForAddressByTokenID
|
||||
|
||||
it("should throw 400 if address is empty", async () => {
|
||||
req.params.address = ""
|
||||
req.params.tokenId =
|
||||
"650dea14c77f4d749608e36e375450c9ac91deb8b1b53e50cb0de2059a52d19a"
|
||||
const result = await balancesForAddressByTokenID(req, res)
|
||||
// console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.hasAllKeys(result, ["error"])
|
||||
assert.include(result.error, "address can not be empty")
|
||||
})
|
||||
|
||||
it("should throw 400 if tokenId is empty", async () => {
|
||||
req.params.address =
|
||||
"simpleledger:qr5agtachyxvrwxu76vzszan5pnvuzy8duhv4lxrsk"
|
||||
req.params.tokenId = ""
|
||||
const result = await balancesForAddressByTokenID(req, res)
|
||||
// console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.hasAllKeys(result, ["error"])
|
||||
assert.include(result.error, "tokenId can not be empty")
|
||||
})
|
||||
|
||||
it("should throw 400 if address is invalid", async () => {
|
||||
req.params.address = "badAddress"
|
||||
req.params.tokenId =
|
||||
"650dea14c77f4d749608e36e375450c9ac91deb8b1b53e50cb0de2059a52d19a"
|
||||
|
||||
const result = await balancesForAddressByTokenID(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.hasAllKeys(result, ["error"])
|
||||
assert.include(result.error, "Invalid BCH address.")
|
||||
})
|
||||
|
||||
it("should throw 400 if address network mismatch", async () => {
|
||||
req.params.address =
|
||||
"simpleledger:qr5agtachyxvrwxu76vzszan5pnvuzy8duhv4lxrsk"
|
||||
|
||||
const result = await balancesForAddressByTokenID(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.hasAllKeys(result, ["error"])
|
||||
assert.include(result.error, "Invalid")
|
||||
})
|
||||
|
||||
it("should throw 5XX error when network issues", async () => {
|
||||
// Save the existing SLPDB_URL.
|
||||
const savedUrl2 = process.env.SLPDB_URL
|
||||
|
||||
// Manipulate the URL to cause a 500 network error.
|
||||
process.env.SLPDB_URL = "http://fakeurl/api/"
|
||||
|
||||
req.params.address = "slptest:qz4qnxcxwvmacgye8wlakhz0835x0w3vtvxu67w0ac"
|
||||
req.params.tokenId =
|
||||
"7ac7f4bb50b019fe0f5c81e3fc13fc0720e130282ea460768cafb49785eb2796"
|
||||
|
||||
const result = await balancesForAddressByTokenID(req, res)
|
||||
// console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
// Restore the saved URL.
|
||||
process.env.SLPDB_URL = savedUrl2
|
||||
|
||||
assert.isAbove(
|
||||
res.statusCode,
|
||||
499,
|
||||
"HTTP status code 500 or greater expected."
|
||||
)
|
||||
assert.include(
|
||||
result.error,
|
||||
"Network error: Could not communicate",
|
||||
"Error message expected"
|
||||
)
|
||||
})
|
||||
|
||||
it("should get token information", async () => {
|
||||
if (process.env.TEST === "unit") {
|
||||
nock(mockServerUrl)
|
||||
.get(uri => uri.includes("/"))
|
||||
.times(2)
|
||||
.reply(200, mockData.mockSingleAddress)
|
||||
}
|
||||
|
||||
req.params.address = "slptest:pz0qcslrqn7hr44hsszwl4lw5r6udkg6zqv7sq3kk7"
|
||||
req.params.tokenId =
|
||||
"6b081fcd1f78b187be1464313dac8ff257251b727a42b613552a4040870aeb29"
|
||||
|
||||
const result = await balancesForAddressByTokenID(req, res)
|
||||
// console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
// TODO - add decimalCount
|
||||
// assert.hasAllKeys(result, ["tokenId", "balance", "decimalCount"])
|
||||
assert.hasAllKeys(result, ["tokenId", "balance"])
|
||||
})
|
||||
})
|
||||
|
||||
describe("convertAddressSingle()", () => {
|
||||
const convertAddressSingle =
|
||||
slpRoute.testableComponents.convertAddressSingle
|
||||
|
||||
it("should throw 400 if address is empty", async () => {
|
||||
req.params.address = ""
|
||||
const result = await convertAddressSingle(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.hasAllKeys(result, ["error"])
|
||||
assert.include(result.error, "address can not be empty")
|
||||
})
|
||||
//
|
||||
it("should convert address", async () => {
|
||||
// Mock the RPC call for unit tests.
|
||||
if (process.env.TEST === "unit") {
|
||||
nock(`${process.env.SLPDB_URL}`)
|
||||
.post(``)
|
||||
.reply(200, { result: mockData.mockConvert })
|
||||
}
|
||||
|
||||
req.params.address = "slptest:qz35h5mfa8w2pqma2jq06lp7dnv5fxkp2shlcycvd5"
|
||||
|
||||
const result = await convertAddressSingle(req, res)
|
||||
// console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.hasAllKeys(result, ["cashAddress", "legacyAddress", "slpAddress"])
|
||||
})
|
||||
})
|
||||
|
||||
describe("convertAddressBulk()", () => {
|
||||
const convertAddressBulk = slpRoute.testableComponents.convertAddressBulk
|
||||
|
||||
it("should throw 400 if addresses array is empty", async () => {
|
||||
const result = await convertAddressBulk(req, res)
|
||||
// console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.hasAllKeys(result, ["error"])
|
||||
assert.include(result.error, "addresses needs to be an array")
|
||||
assert.equal(res.statusCode, 400)
|
||||
})
|
||||
|
||||
it("should throw 400 error if array is too large", async () => {
|
||||
const testArray = []
|
||||
for (var i = 0; i < 25; i++) testArray.push("")
|
||||
|
||||
req.body.addresses = testArray
|
||||
|
||||
const result = await convertAddressBulk(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.hasAllKeys(result, ["error"])
|
||||
assert.include(result.error, "Array too large")
|
||||
})
|
||||
|
||||
it("should error on malformed address", async () => {
|
||||
try {
|
||||
req.body.addresses = ["bitcoincash:qzs02v05l7qs5s5dwuj0cx5ehjm2c"]
|
||||
|
||||
await convertAddressBulk(req, res)
|
||||
|
||||
assert.equal(true, false, "Unsupported address format")
|
||||
} catch (err) {
|
||||
// console.log(`err.message: ${util.inspect(err.message)}`)
|
||||
|
||||
assert.include(err.message, `Unsupported address format`)
|
||||
}
|
||||
})
|
||||
|
||||
it("should validate array with single element", async () => {
|
||||
req.body.addresses = [
|
||||
"bitcoincash:qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c"
|
||||
]
|
||||
|
||||
const result = await convertAddressBulk(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.hasAllKeys(result[0], [
|
||||
"slpAddress",
|
||||
"cashAddress",
|
||||
"legacyAddress"
|
||||
])
|
||||
})
|
||||
|
||||
it("should validate array with multiple elements", async () => {
|
||||
req.body.addresses = [
|
||||
"bitcoincash:qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c",
|
||||
"bitcoincash:qrehqueqhw629p6e57994436w730t4rzasnly00ht0"
|
||||
]
|
||||
|
||||
const result = await convertAddressBulk(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.hasAllKeys(result[0], [
|
||||
"slpAddress",
|
||||
"cashAddress",
|
||||
"legacyAddress"
|
||||
])
|
||||
})
|
||||
})
|
||||
|
||||
describe("validateBulk()", () => {
|
||||
const validateBulk = slpRoute.testableComponents.validateBulk
|
||||
|
||||
it("should throw 400 if txid array is empty", async () => {
|
||||
const result = await validateBulk(req, res)
|
||||
// console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.hasAllKeys(result, ["error"])
|
||||
assert.include(result.error, "txids needs to be an array")
|
||||
assert.equal(res.statusCode, 400)
|
||||
})
|
||||
|
||||
it("should throw 400 error if array is too large", async () => {
|
||||
const testArray = []
|
||||
for (var i = 0; i < 25; i++) testArray.push("")
|
||||
|
||||
req.body.txids = testArray
|
||||
|
||||
const result = await validateBulk(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.hasAllKeys(result, ["error"])
|
||||
assert.include(result.error, "Array too large")
|
||||
})
|
||||
|
||||
it("should validate array with single element", async () => {
|
||||
// Mock the RPC call for unit tests.
|
||||
if (process.env.TEST === "unit") {
|
||||
sandbox
|
||||
.stub(slpRoute.testableComponents, "isValidSlpTxid")
|
||||
.resolves(true)
|
||||
}
|
||||
|
||||
req.body.txids = [
|
||||
"78d57a82a0dd9930cc17843d9d06677f267777dd6b25055bad0ae43f1b884091"
|
||||
]
|
||||
|
||||
const result = await validateBulk(req, res)
|
||||
// console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.hasAllKeys(result[0], ["txid", "valid"])
|
||||
})
|
||||
|
||||
it("should validate array with two elements", async () => {
|
||||
// Mock the RPC call for unit tests.
|
||||
if (process.env.TEST === "unit") {
|
||||
sandbox
|
||||
.stub(slpRoute.testableComponents, "isValidSlpTxid")
|
||||
.resolves(true)
|
||||
}
|
||||
|
||||
req.body.txids = [
|
||||
"78d57a82a0dd9930cc17843d9d06677f267777dd6b25055bad0ae43f1b884091",
|
||||
"82d996847a861b08b1601284ef7d40a1777d019154a6c4ed11571609dd3555ac"
|
||||
]
|
||||
|
||||
const result = await validateBulk(req, res)
|
||||
// console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.hasAllKeys(result[0], ["txid", "valid"])
|
||||
assert.equal(result.length, 2)
|
||||
})
|
||||
})
|
||||
|
||||
describe("tokenStatsSingle()", () => {
|
||||
const tokenStatsSingle = slpRoute.testableComponents.tokenStats
|
||||
|
||||
it("should throw 400 if tokenID is empty", async () => {
|
||||
req.params.tokenId = ""
|
||||
const result = await tokenStatsSingle(req, res)
|
||||
// console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.hasAllKeys(result, ["error"])
|
||||
assert.include(result.error, "tokenId can not be empty")
|
||||
})
|
||||
//
|
||||
it("should get token stats for tokenId", async () => {
|
||||
// Mock the RPC call for unit tests.
|
||||
if (process.env.TEST === "unit") {
|
||||
nock(`${process.env.SLPDB_URL}`)
|
||||
.get(uri => uri.includes("/"))
|
||||
.reply(200, {
|
||||
t: [
|
||||
{
|
||||
tokenDetails: mockData.mockTokenDetails,
|
||||
tokenStats: mockData.mockTokenStats
|
||||
}
|
||||
]
|
||||
})
|
||||
}
|
||||
|
||||
req.params.tokenId =
|
||||
"37279c7dc81ceb34d12f03344b601c582e931e05d0e552c29c428bfa39d39af3"
|
||||
|
||||
const result = await tokenStatsSingle(req, res)
|
||||
// console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.hasAllKeys(result, [
|
||||
"blockCreated",
|
||||
"blockLastActiveMint",
|
||||
"blockLastActiveSend",
|
||||
"containsBaton",
|
||||
"initialTokenQty",
|
||||
"mintingBatonStatus",
|
||||
"circulatingSupply",
|
||||
"decimals",
|
||||
"documentHash",
|
||||
"versionType",
|
||||
"timestamp",
|
||||
"documentUri",
|
||||
"name",
|
||||
"symbol",
|
||||
"id",
|
||||
"totalBurned",
|
||||
"totalMinted",
|
||||
"txnsSinceGenesis",
|
||||
"validAddresses"
|
||||
])
|
||||
})
|
||||
})
|
||||
|
||||
describe("balancesForTokenSingle()", () => {
|
||||
const balancesForTokenSingle =
|
||||
slpRoute.testableComponents.balancesForTokenSingle
|
||||
|
||||
it("should throw 400 if tokenID is empty", async () => {
|
||||
req.params.tokenId = ""
|
||||
const result = await balancesForTokenSingle(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.hasAllKeys(result, ["error"])
|
||||
assert.include(result.error, "tokenId can not be empty")
|
||||
})
|
||||
//
|
||||
it("should get balances for tokenId", async () => {
|
||||
// Mock the RPC call for unit tests.
|
||||
if (process.env.TEST === "unit") {
|
||||
nock(`${process.env.SLPDB_URL}`)
|
||||
.get(uri => uri.includes("/"))
|
||||
.reply(200, {
|
||||
a: [mockData.mockBalance]
|
||||
})
|
||||
}
|
||||
|
||||
req.params.tokenId =
|
||||
"37279c7dc81ceb34d12f03344b601c582e931e05d0e552c29c428bfa39d39af3"
|
||||
|
||||
const result = await balancesForTokenSingle(req, res)
|
||||
// console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.hasAllKeys(result[0], ["tokenId", "slpAddress", "tokenBalance"])
|
||||
})
|
||||
})
|
||||
|
||||
describe("txDetails()", () => {
|
||||
let txDetails = slpRoute.testableComponents.txDetails
|
||||
|
||||
it("should throw 400 if txid is empty", async () => {
|
||||
const result = await txDetails(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.hasAllKeys(result, ["error"])
|
||||
assert.include(result.error, "txid can not be empty")
|
||||
})
|
||||
|
||||
it("should throw 400 for malformed txid", async () => {
|
||||
req.params.txid =
|
||||
"57b3082a2bf269b3d6f40fee7fb9c664e8256a88ca5ee2697c05b9457"
|
||||
|
||||
const result = await txDetails(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.hasAllKeys(result, ["error"])
|
||||
assert.include(result.error, "This is not a txid")
|
||||
})
|
||||
|
||||
it("should throw 400 for non-existant txid", async () => {
|
||||
// Integration test
|
||||
if (process.env.TEST !== "unit") {
|
||||
req.params.txid =
|
||||
"57b3082a2bf269b3d6f40fee7fb9c664e8256a88ca5ee2697c05b94578223333"
|
||||
|
||||
const result = await txDetails(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.hasAllKeys(result, ["error"])
|
||||
assert.include(result.error, "TXID not found")
|
||||
}
|
||||
})
|
||||
|
||||
it("should get tx details with token info", async () => {
|
||||
if (process.env.TEST === "unit") {
|
||||
// Mock the slpjs library for unit tests.
|
||||
pathStub.BitboxNetwork = slpjsMock.BitboxNetwork
|
||||
txDetails = slpRouteStub.testableComponents.txDetails
|
||||
}
|
||||
|
||||
req.params.txid =
|
||||
"57b3082a2bf269b3d6f40fee7fb9c664e8256a88ca5ee2697c05b9457822d446"
|
||||
|
||||
const result = await txDetails(req, res)
|
||||
//console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.hasAnyKeys(result, ["tokenIsValid", "tokenInfo"])
|
||||
})
|
||||
})
|
||||
|
||||
describe("txsTokenIdAddressSingle()", () => {
|
||||
const txsTokenIdAddressSingle =
|
||||
slpRoute.testableComponents.txsTokenIdAddressSingle
|
||||
|
||||
it("should throw 400 if tokenId is empty", async () => {
|
||||
req.params.tokenId = ""
|
||||
const result = await txsTokenIdAddressSingle(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.hasAllKeys(result, ["error"])
|
||||
assert.include(result.error, "tokenId can not be empty")
|
||||
})
|
||||
|
||||
it("should throw 400 if address is empty", async () => {
|
||||
req.params.tokenId =
|
||||
"495322b37d6b2eae81f045eda612b95870a0c2b6069c58f70cf8ef4e6a9fd43a"
|
||||
req.params.address = ""
|
||||
const result = await txsTokenIdAddressSingle(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.hasAllKeys(result, ["error"])
|
||||
assert.include(result.error, "address can not be empty")
|
||||
})
|
||||
/*
|
||||
it("should get tx details with tokenId and address", async () => {
|
||||
if (process.env.TEST === "unit") {
|
||||
nock(`${process.env.SLPDB_URL}`)
|
||||
.get(uri => uri.includes("/"))
|
||||
.reply(200, {
|
||||
c: mockData.mockTransactions
|
||||
})
|
||||
}
|
||||
|
||||
//req.params.tokenId =
|
||||
// "37279c7dc81ceb34d12f03344b601c582e931e05d0e552c29c428bfa39d39af3"
|
||||
//req.params.address = "slptest:qr83cu3p7yg9yac7qthwm0nul2ev2kukvsqmes3vl0"
|
||||
|
||||
req.params.tokenId =
|
||||
"7ac7f4bb50b019fe0f5c81e3fc13fc0720e130282ea460768cafb49785eb2796"
|
||||
req.params.address = "slptest:qpwa35xq0q0cnmdu0rwzkct369hddzsqpsqdzw6h9h"
|
||||
|
||||
|
||||
const result = await txsTokenIdAddressSingle(req, res)
|
||||
console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.hasAnyKeys(result[0], ["txid", "tokenDetails"])
|
||||
})
|
||||
*/
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,333 @@
|
||||
/*
|
||||
TESTS FOR THE TRANSACTION.TS LIBRARY
|
||||
|
||||
This test file uses the environment variable TEST to switch between unit
|
||||
and integration tests. By default, TEST is set to 'unit'. Set this variable
|
||||
to 'integration' to run the tests against BCH mainnet.
|
||||
|
||||
TODO:
|
||||
-See "should throw an error for an invalid txid" for detailsSingle:
|
||||
--The error handler should be refactored to return an intelligent error message,
|
||||
instead of the 503 error it is returning now.
|
||||
*/
|
||||
|
||||
"use strict"
|
||||
|
||||
const chai = require("chai")
|
||||
const assert = chai.assert
|
||||
const transactionRoute = require("../../dist/routes/v2/transaction")
|
||||
const nock = require("nock") // HTTP mocking
|
||||
|
||||
let originalEnvVars // Used during transition from integration to unit tests.
|
||||
|
||||
// Mocking data.
|
||||
const { mockReq, mockRes } = require("./mocks/express-mocks")
|
||||
const mockData = require("./mocks/transaction-mocks")
|
||||
|
||||
// Used for debugging.
|
||||
const util = require("util")
|
||||
util.inspect.defaultOptions = { depth: 1 }
|
||||
|
||||
describe("#Transactions", () => {
|
||||
let req, res
|
||||
|
||||
before(() => {
|
||||
// Save existing environment variables.
|
||||
originalEnvVars = {
|
||||
BITCOINCOM_BASEURL: process.env.BITCOINCOM_BASEURL,
|
||||
RPC_BASEURL: process.env.RPC_BASEURL,
|
||||
RPC_USERNAME: process.env.RPC_USERNAME,
|
||||
RPC_PASSWORD: process.env.RPC_PASSWORD
|
||||
}
|
||||
|
||||
// Set default environment variables for unit tests.
|
||||
if (!process.env.TEST) process.env.TEST = "unit"
|
||||
if (process.env.TEST === "unit") {
|
||||
process.env.BITCOINCOM_BASEURL = "http://fakeurl/api/"
|
||||
process.env.RPC_BASEURL = "http://fakeurl/api"
|
||||
process.env.RPC_USERNAME = "fakeusername"
|
||||
process.env.RPC_PASSWORD = "fakepassword"
|
||||
}
|
||||
})
|
||||
|
||||
// Setup the mocks before each test.
|
||||
beforeEach(() => {
|
||||
// Mock the req and res objects used by Express routes.
|
||||
req = mockReq
|
||||
res = mockRes
|
||||
|
||||
// Explicitly reset the parmas and body.
|
||||
req.params = {}
|
||||
req.body = {}
|
||||
req.query = {}
|
||||
|
||||
// Activate nock if it's inactive.
|
||||
if (!nock.isActive()) nock.activate()
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
// Clean up HTTP mocks.
|
||||
nock.cleanAll() // clear interceptor list.
|
||||
nock.restore()
|
||||
})
|
||||
|
||||
after(() => {
|
||||
// Restore any pre-existing environment variables.
|
||||
process.env.BITCOINCOM_BASEURL = originalEnvVars.BITCOINCOM_BASEURL
|
||||
process.env.RPC_BASEURL = originalEnvVars.RPC_BASEURL
|
||||
process.env.RPC_USERNAME = originalEnvVars.RPC_USERNAME
|
||||
process.env.RPC_PASSWORD = originalEnvVars.RPC_PASSWORD
|
||||
})
|
||||
|
||||
describe("#root", async () => {
|
||||
// root route handler.
|
||||
const root = transactionRoute.testableComponents.root
|
||||
|
||||
it("should respond to GET for base route", async () => {
|
||||
const result = root(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.equal(result.status, "transaction", "Returns static string")
|
||||
})
|
||||
})
|
||||
|
||||
describe("#detailsBulk", async () => {
|
||||
const detailsBulk = transactionRoute.testableComponents.detailsBulk
|
||||
|
||||
it("should throw an error for an empty body", async () => {
|
||||
req.body = {}
|
||||
|
||||
const result = await detailsBulk(req, res)
|
||||
|
||||
assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
|
||||
assert.include(
|
||||
result.error,
|
||||
"txids needs to be an array",
|
||||
"Proper error message"
|
||||
)
|
||||
})
|
||||
|
||||
it("should error on non-array single txid", async () => {
|
||||
req.body = {
|
||||
txids: `6f235bd3a689f03c11969cd649ccad592462ca958bc519a30194e7a67b349a40`
|
||||
}
|
||||
|
||||
const result = await detailsBulk(req, res)
|
||||
|
||||
assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
|
||||
assert.include(
|
||||
result.error,
|
||||
"txids needs to be an array",
|
||||
"Proper error message"
|
||||
)
|
||||
})
|
||||
|
||||
it("should throw an error for an invalid txid", async () => {
|
||||
const fakeTXID = `02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`
|
||||
|
||||
// Mock the Insight URL for unit tests.
|
||||
if (process.env.TEST === "unit") {
|
||||
nock(`${process.env.BITCOINCOM_BASEURL}`)
|
||||
.get(`/tx/${fakeTXID}`)
|
||||
.reply(400, {
|
||||
result: { error: "parameter 1 must be hexadecimal string" }
|
||||
})
|
||||
}
|
||||
|
||||
req.body = {
|
||||
txids: [fakeTXID]
|
||||
}
|
||||
|
||||
const result = await detailsBulk(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
|
||||
})
|
||||
|
||||
it("should process a single txid", async () => {
|
||||
const txid = `6f235bd3a689f03c11969cd649ccad592462ca958bc519a30194e7a67b349a40`
|
||||
|
||||
// Mock the Insight URL for unit tests.
|
||||
if (process.env.TEST === "unit") {
|
||||
nock(`${process.env.BITCOINCOM_BASEURL}`)
|
||||
.get(`/tx/${txid}`)
|
||||
.reply(200, mockData.mockDetails)
|
||||
}
|
||||
|
||||
req.body = {
|
||||
txids: [txid]
|
||||
}
|
||||
|
||||
const result = await detailsBulk(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.hasAnyKeys(result[0], [
|
||||
"txid",
|
||||
"version",
|
||||
"locktime",
|
||||
"vin",
|
||||
"vout",
|
||||
"blockhash",
|
||||
"blockheight",
|
||||
"confirmations",
|
||||
"time",
|
||||
"blocktime",
|
||||
"valueOut",
|
||||
"size",
|
||||
"valueIn",
|
||||
"fees"
|
||||
])
|
||||
})
|
||||
|
||||
it("should process a multiple txids", async () => {
|
||||
const txid1 = `6f235bd3a689f03c11969cd649ccad592462ca958bc519a30194e7a67b349a40`
|
||||
const txid2 = `8d4fd4dcaa9d8051dc7d862dc23d8aa23e20b77b9c928c49380685459caa7043`
|
||||
|
||||
// Mock the Insight URL for unit tests.
|
||||
if (process.env.TEST === "unit") {
|
||||
nock(`${process.env.BITCOINCOM_BASEURL}`)
|
||||
.get(`/tx/${txid1}`)
|
||||
.reply(200, mockData.mockDetails)
|
||||
}
|
||||
|
||||
// Mock the Insight URL for unit tests.
|
||||
if (process.env.TEST === "unit") {
|
||||
nock(`${process.env.BITCOINCOM_BASEURL}`)
|
||||
.get(`/tx/${txid2}`)
|
||||
.reply(200, mockData.mockDetails)
|
||||
}
|
||||
|
||||
req.body = {
|
||||
txids: [txid1, txid2]
|
||||
}
|
||||
|
||||
const result = await detailsBulk(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.hasAnyKeys(result[0], [
|
||||
"txid",
|
||||
"version",
|
||||
"locktime",
|
||||
"vin",
|
||||
"vout",
|
||||
"blockhash",
|
||||
"blockheight",
|
||||
"confirmations",
|
||||
"time",
|
||||
"blocktime",
|
||||
"valueOut",
|
||||
"size",
|
||||
"valueIn",
|
||||
"fees"
|
||||
])
|
||||
})
|
||||
})
|
||||
|
||||
describe("#detailsSingle", () => {
|
||||
// details route handler.
|
||||
const detailsSingle = transactionRoute.testableComponents.detailsSingle
|
||||
|
||||
it("should throw 400 if txid is empty", async () => {
|
||||
const result = await detailsSingle(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.hasAllKeys(result, ["error"])
|
||||
assert.include(result.error, "txid can not be empty")
|
||||
})
|
||||
|
||||
it("should error on an array", async () => {
|
||||
req.params.txid = [`qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`]
|
||||
|
||||
const result = await detailsSingle(req, res)
|
||||
|
||||
assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
|
||||
assert.include(
|
||||
result.error,
|
||||
"txid can not be an array",
|
||||
"Proper error message"
|
||||
)
|
||||
})
|
||||
|
||||
it("should throw an error for an invalid txid", async () => {
|
||||
if (process.env.TEST !== "unit") {
|
||||
req.params.txid = `02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`
|
||||
|
||||
const result = await detailsSingle(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
// The error handling code should probably be updated to respond with a better
|
||||
// error message.
|
||||
assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
|
||||
assert.include(
|
||||
result.error,
|
||||
"parameter 1 must be hexadecimal string",
|
||||
"Proper error message"
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
it("should throw 500 when network issues", async () => {
|
||||
const savedUrl = process.env.BITCOINCOM_BASEURL
|
||||
|
||||
try {
|
||||
req.params.txid = `6f235bd3a689f03c11969cd649ccad592462ca958bc519a30194e7a67b349a40`
|
||||
|
||||
// Switch the Insight URL to something that will error out.
|
||||
process.env.BITCOINCOM_BASEURL = "http://fakeurl/api/"
|
||||
|
||||
const result = await detailsSingle(req, res)
|
||||
|
||||
// Restore the saved URL.
|
||||
process.env.BITCOINCOM_BASEURL = savedUrl
|
||||
|
||||
assert.isAbove(
|
||||
res.statusCode,
|
||||
499,
|
||||
"HTTP status code 500 or greater expected."
|
||||
)
|
||||
//assert.include(result.error,"Network error: Could not communicate with full node","Error message expected")
|
||||
} catch (err) {
|
||||
// Restore the saved URL.
|
||||
process.env.BITCOINCOM_BASEURL = savedUrl
|
||||
}
|
||||
})
|
||||
|
||||
it("should get details for a single address", async () => {
|
||||
const txid = `6f235bd3a689f03c11969cd649ccad592462ca958bc519a30194e7a67b349a40`
|
||||
req.params.txid = txid
|
||||
|
||||
// Mock the Insight URL for unit tests.
|
||||
if (process.env.TEST === "unit") {
|
||||
nock(`${process.env.BITCOINCOM_BASEURL}`)
|
||||
.get(`/tx/${txid}`)
|
||||
.reply(200, mockData.mockDetails)
|
||||
}
|
||||
|
||||
// Call the details API.
|
||||
const result = await detailsSingle(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
// Assert that required fields exist in the returned object.
|
||||
assert.hasAllKeys(result, [
|
||||
"txid",
|
||||
"version",
|
||||
"locktime",
|
||||
"vin",
|
||||
"vout",
|
||||
"blockhash",
|
||||
"blockheight",
|
||||
"confirmations",
|
||||
"time",
|
||||
"blocktime",
|
||||
"valueOut",
|
||||
"size",
|
||||
"valueIn",
|
||||
"fees"
|
||||
])
|
||||
assert.isArray(result.vin)
|
||||
assert.isArray(result.vout)
|
||||
})
|
||||
})
|
||||
})
|
||||
+300
@@ -0,0 +1,300 @@
|
||||
/*
|
||||
TESTS FOR THE UTIL.TS LIBRARY
|
||||
|
||||
This test file uses the environment variable TEST to switch between unit
|
||||
and integration tests. By default, TEST is set to 'unit'. Set this variable
|
||||
to 'integration' to run the tests against BCH mainnet.
|
||||
*/
|
||||
|
||||
"use strict"
|
||||
|
||||
const chai = require("chai")
|
||||
const assert = chai.assert
|
||||
const utilRoute = require("../../dist/routes/v2/util")
|
||||
const nock = require("nock") // HTTP mocking
|
||||
|
||||
let originalEnvVars // Used during transition from integration to unit tests.
|
||||
|
||||
// Mocking data.
|
||||
const { mockReq, mockRes } = require("./mocks/express-mocks")
|
||||
const mockData = require("./mocks/util-mocks")
|
||||
|
||||
// Used for debugging.
|
||||
const util = require("util")
|
||||
util.inspect.defaultOptions = { depth: 1 }
|
||||
|
||||
describe("#Util", () => {
|
||||
let req, res
|
||||
|
||||
before(() => {
|
||||
// Save existing environment variables.
|
||||
originalEnvVars = {
|
||||
BITCOINCOM_BASEURL: process.env.BITCOINCOM_BASEURL,
|
||||
RPC_BASEURL: process.env.RPC_BASEURL,
|
||||
RPC_USERNAME: process.env.RPC_USERNAME,
|
||||
RPC_PASSWORD: process.env.RPC_PASSWORD
|
||||
}
|
||||
|
||||
// Set default environment variables for unit tests.
|
||||
if (!process.env.TEST) process.env.TEST = "unit"
|
||||
if (process.env.TEST === "unit") {
|
||||
process.env.BITCOINCOM_BASEURL = "http://fakeurl/api/"
|
||||
process.env.RPC_BASEURL = "http://fakeurl/api"
|
||||
process.env.RPC_USERNAME = "fakeusername"
|
||||
process.env.RPC_PASSWORD = "fakepassword"
|
||||
}
|
||||
})
|
||||
|
||||
// Setup the mocks before each test.
|
||||
beforeEach(() => {
|
||||
// Mock the req and res objects used by Express routes.
|
||||
req = mockReq
|
||||
res = mockRes
|
||||
|
||||
// Explicitly reset the parmas and body.
|
||||
req.params = {}
|
||||
req.body = {}
|
||||
req.query = {}
|
||||
|
||||
// Activate nock if it's inactive.
|
||||
if (!nock.isActive()) nock.activate()
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
// Clean up HTTP mocks.
|
||||
nock.cleanAll() // clear interceptor list.
|
||||
nock.restore()
|
||||
})
|
||||
|
||||
after(() => {
|
||||
// Restore any pre-existing environment variables.
|
||||
process.env.BITCOINCOM_BASEURL = originalEnvVars.BITCOINCOM_BASEURL
|
||||
process.env.RPC_BASEURL = originalEnvVars.RPC_BASEURL
|
||||
process.env.RPC_USERNAME = originalEnvVars.RPC_USERNAME
|
||||
process.env.RPC_PASSWORD = originalEnvVars.RPC_PASSWORD
|
||||
})
|
||||
|
||||
describe("#root", async () => {
|
||||
// root route handler.
|
||||
const root = utilRoute.testableComponents.root
|
||||
|
||||
it("should respond to GET for base route", async () => {
|
||||
const result = root(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.equal(result.status, "util", "Returns static string")
|
||||
})
|
||||
})
|
||||
|
||||
describe("#validateAddressSingle", async () => {
|
||||
const validateAddress = utilRoute.testableComponents.validateAddressSingle
|
||||
|
||||
it("should throw an error for an empty address", async () => {
|
||||
const result = await validateAddress(req, res)
|
||||
|
||||
assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
|
||||
assert.include(
|
||||
result.error,
|
||||
"address can not be empty",
|
||||
"Proper error message"
|
||||
)
|
||||
})
|
||||
|
||||
it("should throw 503 when network issues", async () => {
|
||||
// Save the existing RPC URL.
|
||||
const savedUrl2 = process.env.RPC_BASEURL
|
||||
|
||||
// Manipulate the URL to cause a 500 network error.
|
||||
process.env.RPC_BASEURL = "http://fakeurl/api/"
|
||||
|
||||
req.params.address = `bchtest:qqqk4y6lsl5da64sg5qc3xezmplyu5kmpyz2ysaa5y`
|
||||
|
||||
const result = await validateAddress(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
// Restore the saved URL.
|
||||
process.env.RPC_BASEURL = savedUrl2
|
||||
|
||||
assert.isAbove(
|
||||
res.statusCode,
|
||||
499,
|
||||
"HTTP status code 500 or greater expected."
|
||||
)
|
||||
//assert.include(result.error,"Network error: Could not communicate with full node","Error message expected")
|
||||
})
|
||||
|
||||
it("should validate address", async () => {
|
||||
// Mock the RPC call for unit tests.
|
||||
if (process.env.TEST === "unit") {
|
||||
nock(`${process.env.RPC_BASEURL}`)
|
||||
.post(``)
|
||||
.reply(200, { result: mockData.mockAddress })
|
||||
}
|
||||
|
||||
req.params.address = `bchtest:qqqk4y6lsl5da64sg5qc3xezmplyu5kmpyz2ysaa5y`
|
||||
|
||||
const result = await validateAddress(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.hasAllKeys(result, [
|
||||
"isvalid",
|
||||
"address",
|
||||
"scriptPubKey",
|
||||
"ismine",
|
||||
"iswatchonly",
|
||||
"isscript"
|
||||
])
|
||||
})
|
||||
})
|
||||
|
||||
describe("#validateAddressBulk", async () => {
|
||||
const validateAddressBulk = utilRoute.testableComponents.validateAddressBulk
|
||||
|
||||
it("should throw an error for an empty body", async () => {
|
||||
const result = await validateAddressBulk(req, res)
|
||||
|
||||
assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
|
||||
assert.include(
|
||||
result.error,
|
||||
"addresses needs to be an array. Use GET for single address.",
|
||||
"Proper error message"
|
||||
)
|
||||
})
|
||||
|
||||
it("should error on non-array single address", async () => {
|
||||
req.body = {
|
||||
addresses: `bchtest:qqqk4y6lsl5da64sg5qc3xezmplyu5kmpyz2ysaa5y`
|
||||
}
|
||||
|
||||
const result = await validateAddressBulk(req, res)
|
||||
|
||||
assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
|
||||
assert.include(
|
||||
result.error,
|
||||
"addresses needs to be an array. Use GET for single address.",
|
||||
"Proper error message"
|
||||
)
|
||||
})
|
||||
|
||||
it("should throw 400 error if addresses array is too large", async () => {
|
||||
const testArray = []
|
||||
for (var i = 0; i < 25; i++) testArray.push("")
|
||||
|
||||
req.body.addresses = testArray
|
||||
|
||||
const result = await validateAddressBulk(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.hasAllKeys(result, ["error"])
|
||||
assert.include(result.error, "Array too large")
|
||||
})
|
||||
|
||||
it("should error on invalid address", async () => {
|
||||
req.body = {
|
||||
addresses: [`bchtest:qqqk4y6lsl5da64sg5qc3xezmpl`]
|
||||
}
|
||||
|
||||
const result = await validateAddressBulk(req, res)
|
||||
|
||||
assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
|
||||
assert.include(
|
||||
result.error,
|
||||
"Invalid BCH address. Double check your address is valid",
|
||||
"Proper error message"
|
||||
)
|
||||
})
|
||||
|
||||
it("should error on mainnet address when using testnet", async () => {
|
||||
req.body = {
|
||||
addresses: [`bitcoincash:qrcc3jsqpgwqcdru70sk54sd0g3l04q7c53ycm6ucj`]
|
||||
}
|
||||
|
||||
const result = await validateAddressBulk(req, res)
|
||||
|
||||
assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
|
||||
assert.include(
|
||||
result.error,
|
||||
"Invalid network. Trying to use a testnet address on mainnet, or vice versa.",
|
||||
"Proper error message"
|
||||
)
|
||||
})
|
||||
|
||||
it("should throw 503 when network issues", async () => {
|
||||
// Save the existing RPC URL.
|
||||
const savedUrl2 = process.env.RPC_BASEURL
|
||||
|
||||
// Manipulate the URL to cause a 500 network error.
|
||||
process.env.RPC_BASEURL = "http://fakeurl/api/"
|
||||
|
||||
req.body.addresses = [
|
||||
`bchtest:qqqk4y6lsl5da64sg5qc3xezmplyu5kmpyz2ysaa5y`
|
||||
]
|
||||
|
||||
const result = await validateAddressBulk(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
// Restore the saved URL.
|
||||
process.env.RPC_BASEURL = savedUrl2
|
||||
|
||||
assert.isAbove(
|
||||
res.statusCode,
|
||||
499,
|
||||
"HTTP status code 500 or greater expected."
|
||||
)
|
||||
})
|
||||
|
||||
it("should validate a single address", async () => {
|
||||
// Mock the RPC call for unit tests.
|
||||
if (process.env.TEST === "unit") {
|
||||
nock(`${process.env.RPC_BASEURL}`)
|
||||
.post(``)
|
||||
.reply(200, { result: mockData.mockAddress })
|
||||
}
|
||||
|
||||
req.body.addresses = [
|
||||
`bchtest:qqqk4y6lsl5da64sg5qc3xezmplyu5kmpyz2ysaa5y`
|
||||
]
|
||||
|
||||
const result = await validateAddressBulk(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.hasAllKeys(result[0], [
|
||||
"isvalid",
|
||||
"address",
|
||||
"scriptPubKey",
|
||||
"ismine",
|
||||
"iswatchonly",
|
||||
"isscript"
|
||||
])
|
||||
})
|
||||
|
||||
it("should validate a multiple addresses", async () => {
|
||||
// Mock the RPC call for unit tests.
|
||||
if (process.env.TEST === "unit") {
|
||||
nock(`${process.env.RPC_BASEURL}`)
|
||||
.post(``)
|
||||
.times(2)
|
||||
.reply(200, { result: mockData.mockAddress })
|
||||
}
|
||||
|
||||
req.body.addresses = [
|
||||
`bchtest:qqqk4y6lsl5da64sg5qc3xezmplyu5kmpyz2ysaa5y`,
|
||||
`bchtest:qqqk4y6lsl5da64sg5qc3xezmplyu5kmpyz2ysaa5y`
|
||||
]
|
||||
|
||||
const result = await validateAddressBulk(req, res)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.hasAllKeys(result[0], [
|
||||
"isvalid",
|
||||
"address",
|
||||
"scriptPubKey",
|
||||
"ismine",
|
||||
"iswatchonly",
|
||||
"isscript"
|
||||
])
|
||||
})
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user