Changeset View
Changeset View
Standalone View
Standalone View
apps/ecash-herald/test/eventsTests.js
// Copyright (c) 2023 The Bitcoin developers | // Copyright (c) 2023 The Bitcoin developers | ||||
// Distributed under the MIT software license, see the accompanying | // Distributed under the MIT software license, see the accompanying | ||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php. | // file COPYING or http://www.opensource.org/licenses/mit-license.php. | ||||
'use strict'; | 'use strict'; | ||||
const assert = require('assert'); | const assert = require('assert'); | ||||
const config = require('../config'); | const config = require('../config'); | ||||
const blocks = require('./mocks/blocks'); | const unrevivedBlocks = require('./mocks/blocks'); | ||||
const { jsonReviver } = require('../src/utils'); | |||||
const blocks = JSON.parse(JSON.stringify(unrevivedBlocks), jsonReviver); | |||||
const { handleBlockConnected } = require('../src/events'); | const { handleBlockConnected } = require('../src/events'); | ||||
const { MockChronikClient } = require('./mocks/chronikMock'); | const { MockChronikClient } = require('./mocks/chronikMock'); | ||||
const { MockTelegramBot, mockChannelId } = require('./mocks/telegramBotMock'); | const { MockTelegramBot, mockChannelId } = require('./mocks/telegramBotMock'); | ||||
const axios = require('axios'); | const axios = require('axios'); | ||||
const MockAdapter = require('axios-mock-adapter'); | const MockAdapter = require('axios-mock-adapter'); | ||||
describe('ecash-herald events.js', async function () { | describe('ecash-herald events.js', async function () { | ||||
it('handleBlockConnected creates and sends a telegram msg with price info for all mocked blocks if api call succeeds', async function () { | it('handleBlockConnected creates and sends a telegram msg with price and token send info for all mocked blocks if api call succeeds', async function () { | ||||
// Initialize chronik mock | |||||
const mockedChronik = new MockChronikClient(); | |||||
for (let i = 0; i < blocks.length; i += 1) { | for (let i = 0; i < blocks.length; i += 1) { | ||||
// Initialize new chronik mock for each block | |||||
const mockedChronik = new MockChronikClient(); | |||||
const thisBlock = blocks[i]; | const thisBlock = blocks[i]; | ||||
const thisBlockHash = thisBlock.blockDetails.blockInfo.hash; | const thisBlockHash = thisBlock.blockDetails.blockInfo.hash; | ||||
const thisBlockChronikBlockResponse = thisBlock.blockDetails; | const thisBlockChronikBlockResponse = thisBlock.blockDetails; | ||||
// Tell mockedChronik what response we expect for chronik.block(thisBlockHash) | // Tell mockedChronik what response we expect for chronik.block(thisBlockHash) | ||||
mockedChronik.setMock('block', { | mockedChronik.setMock('block', { | ||||
input: thisBlockHash, | input: thisBlockHash, | ||||
output: thisBlockChronikBlockResponse, | output: thisBlockChronikBlockResponse, | ||||
}); | }); | ||||
// Tell mockedChronik what response we expect for chronik.tx | |||||
const { parsedBlock, tokenInfoMap } = thisBlock; | |||||
const { tokenIds } = parsedBlock; | |||||
// Will only have chronik call if the set is not empty | |||||
if (tokenIds.size > 0) { | |||||
// Instead of saving all the chronik responses as mocks, which would be very large | |||||
// Just set them as mocks based on tokenInfoMap, which contains the info we need | |||||
tokenIds.forEach(tokenId => { | |||||
mockedChronik.setMock('tx', { | |||||
input: tokenId, | |||||
output: { | |||||
slpTxData: { | |||||
genesisInfo: tokenInfoMap.get(tokenId), | |||||
}, | |||||
}, | |||||
}); | |||||
}); | |||||
} | |||||
const thisBlockExpectedMsgs = thisBlock.blockSummaryTgMsgs; | const thisBlockExpectedMsgs = thisBlock.blockSummaryTgMsgs; | ||||
const telegramBot = new MockTelegramBot(); | const telegramBot = new MockTelegramBot(); | ||||
const channelId = mockChannelId; | const channelId = mockChannelId; | ||||
// Mock coingecko price response | // Mock coingecko price response | ||||
// onNoMatch: 'throwException' helps to debug if mock is not being used | // onNoMatch: 'throwException' helps to debug if mock is not being used | ||||
const mock = new MockAdapter(axios, { | const mock = new MockAdapter(axios, { | ||||
Show All 25 Lines | it('handleBlockConnected creates and sends a telegram msg with price and token send info for all mocked blocks if api call succeeds', async function () { | ||||
options: config.tgMsgOptions, | options: config.tgMsgOptions, | ||||
}); | }); | ||||
} | } | ||||
// Check that the correct msg info was sent | // Check that the correct msg info was sent | ||||
assert.deepEqual(result, msgSuccessArray); | assert.deepEqual(result, msgSuccessArray); | ||||
} | } | ||||
}); | }); | ||||
it('handleBlockConnected creates and sends a telegram msg without price info for all mocked blocks if api call fails', async function () { | it('handleBlockConnected creates and sends a telegram msg without price or token info for all mocked blocks if api calls fail', async function () { | ||||
// Initialize chronik mock | |||||
const mockedChronik = new MockChronikClient(); | |||||
for (let i = 0; i < blocks.length; i += 1) { | for (let i = 0; i < blocks.length; i += 1) { | ||||
const thisBlock = blocks[i]; | const thisBlock = blocks[i]; | ||||
const thisBlockHash = thisBlock.blockDetails.blockInfo.hash; | const thisBlockHash = thisBlock.blockDetails.blockInfo.hash; | ||||
const thisBlockChronikBlockResponse = thisBlock.blockDetails; | const thisBlockChronikBlockResponse = thisBlock.blockDetails; | ||||
// Initialize chronik mock for each block | |||||
const mockedChronik = new MockChronikClient(); | |||||
// Tell mockedChronik what response we expect for chronik.block(thisBlockHash) | // Tell mockedChronik what response we expect for chronik.block(thisBlockHash) | ||||
mockedChronik.setMock('block', { | mockedChronik.setMock('block', { | ||||
input: thisBlockHash, | input: thisBlockHash, | ||||
output: thisBlockChronikBlockResponse, | output: thisBlockChronikBlockResponse, | ||||
}); | }); | ||||
// Tell mockedChronik what response we expect for chronik.tx | |||||
const { parsedBlock, tokenInfoMap } = thisBlock; | |||||
const { tokenIds } = parsedBlock; | |||||
// Will only have chronik call if the set is not empty | |||||
if (tokenIds.size > 0) { | |||||
// Instead of saving all the chronik responses as mocks, which would be very large | |||||
// Just set them as mocks based on tokenInfoMap, which contains the info we need | |||||
let index = 0; | |||||
tokenIds.forEach(tokenId => { | |||||
// If this is the first one, set an error response | |||||
if (index === 0) { | |||||
mockedChronik.setMock('tx', { | |||||
input: tokenId, | |||||
output: new Error('some error'), | |||||
}); | |||||
} else { | |||||
index += 1; | |||||
mockedChronik.setMock('tx', { | |||||
input: tokenId, | |||||
output: { | |||||
slpTxData: { | |||||
genesisInfo: tokenInfoMap.get(tokenId), | |||||
}, | |||||
}, | |||||
}); | |||||
} | |||||
}); | |||||
} | |||||
const thisBlockExpectedMsgs = | const thisBlockExpectedMsgs = | ||||
thisBlock.blockSummaryTgMsgsPriceFailure; | thisBlock.blockSummaryTgMsgsApiFailure; | ||||
const telegramBot = new MockTelegramBot(); | const telegramBot = new MockTelegramBot(); | ||||
const channelId = mockChannelId; | const channelId = mockChannelId; | ||||
// Mock coingecko price response | // Mock coingecko price response | ||||
// onNoMatch: 'throwException' helps to debug if mock is not being used | // onNoMatch: 'throwException' helps to debug if mock is not being used | ||||
const mock = new MockAdapter(axios, { | const mock = new MockAdapter(axios, { | ||||
onNoMatch: 'throwException', | onNoMatch: 'throwException', | ||||
Show All 23 Lines | it('handleBlockConnected creates and sends a telegram msg without price or token info for all mocked blocks if api calls fail', async function () { | ||||
}); | }); | ||||
} | } | ||||
// Check that the correct msg info was sent | // Check that the correct msg info was sent | ||||
assert.deepEqual(result, msgSuccessArray); | assert.deepEqual(result, msgSuccessArray); | ||||
} | } | ||||
}); | }); | ||||
it('handleBlockConnected sends desired backup msg if it encounters an error in message creation', async function () { | it('handleBlockConnected sends desired backup msg if it encounters an error in message creation', async function () { | ||||
// Initialize chronik mock | |||||
const mockedChronik = new MockChronikClient(); | |||||
for (let i = 0; i < blocks.length; i += 1) { | for (let i = 0; i < blocks.length; i += 1) { | ||||
// Initialize new chronik mock for each block | |||||
const mockedChronik = new MockChronikClient(); | |||||
const thisBlock = blocks[i]; | const thisBlock = blocks[i]; | ||||
const thisBlockHash = thisBlock.blockDetails.blockInfo.hash; | const thisBlockHash = thisBlock.blockDetails.blockInfo.hash; | ||||
// Tell mockedChronik what response we expect for chronik.block(thisBlockHash) | // Tell mockedChronik what response we expect for chronik.block(thisBlockHash) | ||||
mockedChronik.setMock('block', { | mockedChronik.setMock('block', { | ||||
input: thisBlockHash, | input: thisBlockHash, | ||||
output: null, | output: null, | ||||
}); | }); | ||||
Show All 21 Lines | it('handleBlockConnected sends desired backup msg if it encounters an error in message creation', async function () { | ||||
msg: expectedMsg, | msg: expectedMsg, | ||||
options: config.tgMsgOptions, | options: config.tgMsgOptions, | ||||
}); | }); | ||||
} | } | ||||
}); | }); | ||||
it('handleBlockConnected returns false if it encounters an error in telegram bot sendMessage routine', async function () { | it('handleBlockConnected returns false if it encounters an error in telegram bot sendMessage routine', async function () { | ||||
const wsTestAddress = | const wsTestAddress = | ||||
'ecash:prfhcnyqnl5cgrnmlfmms675w93ld7mvvqd0y8lz07'; | 'ecash:prfhcnyqnl5cgrnmlfmms675w93ld7mvvqd0y8lz07'; | ||||
// Initialize chronik mock | |||||
const mockedChronik = new MockChronikClient(wsTestAddress, []); | |||||
for (let i = 0; i < blocks.length; i += 1) { | for (let i = 0; i < blocks.length; i += 1) { | ||||
// Initialize new chronik mock for each block | |||||
const mockedChronik = new MockChronikClient(wsTestAddress, []); | |||||
const thisBlock = blocks[i]; | const thisBlock = blocks[i]; | ||||
const thisBlockHash = thisBlock.blockDetails.blockInfo.hash; | const thisBlockHash = thisBlock.blockDetails.blockInfo.hash; | ||||
const thisBlockChronikBlockResponse = thisBlock.blockDetails; | const thisBlockChronikBlockResponse = thisBlock.blockDetails; | ||||
// Tell mockedChronik what response we expect for chronik.block(thisBlockHash) | // Tell mockedChronik what response we expect for chronik.block(thisBlockHash) | ||||
mockedChronik.setMock('block', { | mockedChronik.setMock('block', { | ||||
input: thisBlockHash, | input: thisBlockHash, | ||||
output: thisBlockChronikBlockResponse, | output: thisBlockChronikBlockResponse, | ||||
}); | }); | ||||
// Tell mockedChronik what response we expect for chronik.tx | |||||
const { parsedBlock, tokenInfoMap } = thisBlock; | |||||
const { tokenIds } = parsedBlock; | |||||
// Will only have chronik call if the set is not empty | |||||
if (tokenIds.size > 0) { | |||||
// Instead of saving all the chronik responses as mocks, which would be very large | |||||
// Just set them as mocks based on tokenInfoMap, which contains the info we need | |||||
let index = 0; | |||||
tokenIds.forEach(tokenId => { | |||||
// If this is the first one, set an error response | |||||
if (index === 0) { | |||||
mockedChronik.setMock('tx', { | |||||
input: tokenId, | |||||
output: new Error('some error'), | |||||
}); | |||||
} else { | |||||
index += 1; | |||||
mockedChronik.setMock('tx', { | |||||
input: tokenId, | |||||
output: { | |||||
slpTxData: { | |||||
genesisInfo: tokenInfoMap.get(tokenId), | |||||
}, | |||||
}, | |||||
}); | |||||
} | |||||
}); | |||||
} | |||||
const telegramBot = new MockTelegramBot(); | const telegramBot = new MockTelegramBot(); | ||||
telegramBot.setExpectedError( | telegramBot.setExpectedError( | ||||
'sendMessage', | 'sendMessage', | ||||
'Error: message failed to send', | 'Error: message failed to send', | ||||
); | ); | ||||
const channelId = mockChannelId; | const channelId = mockChannelId; | ||||
const result = await handleBlockConnected( | const result = await handleBlockConnected( | ||||
Show All 11 Lines |