Changeset View
Changeset View
Standalone View
Standalone View
apps/ecash-herald/test/chronikWsHandlerTests.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 cashaddr = require('ecashaddrjs'); | const cashaddr = require('ecashaddrjs'); | ||||
const blocks = require('./mocks/blocks'); | const unrevivedBlocks = require('./mocks/blocks'); | ||||
const { jsonReviver } = require('../src/utils'); | |||||
const blocks = JSON.parse(JSON.stringify(unrevivedBlocks), jsonReviver); | |||||
const { | const { | ||||
initializeWebsocket, | initializeWebsocket, | ||||
parseWebsocketMessage, | parseWebsocketMessage, | ||||
} = require('../src/chronikWsHandler'); | } = require('../src/chronikWsHandler'); | ||||
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'); | ||||
▲ Show 20 Lines • Show All 86 Lines • ▼ Show 20 Lines | it('parseWebsocketMessage returns false for a msg other than BlockConnected', async function () { | ||||
); | ); | ||||
// Check that sendMessage was not called | // Check that sendMessage was not called | ||||
assert.strictEqual(telegramBot.messageSent, false); | assert.strictEqual(telegramBot.messageSent, false); | ||||
assert.deepEqual(result, false); | assert.deepEqual(result, false); | ||||
} | } | ||||
}); | }); | ||||
it('parseWebsocketMessage creates and sends a telegram msg with prices for all mocked blocks on successful price API call', async function () { | it('parseWebsocketMessage creates and sends a telegram msg with prices and token send info for all mocked blocks on successful API calls', async function () { | ||||
// Initialize chronik mock | for (let i = 0; i < blocks.length; i += 1) { | ||||
// Initialize new chronik mock for each block | |||||
const mockedChronik = new MockChronikClient(); | const mockedChronik = new MockChronikClient(); | ||||
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; | ||||
// 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; | ||||
// Mock a chronik websocket msg of correct format | // Mock a chronik websocket msg of correct format | ||||
const mockWsMsg = { | const mockWsMsg = { | ||||
type: 'BlockConnected', | type: 'BlockConnected', | ||||
blockHash: thisBlockHash, | blockHash: thisBlockHash, | ||||
}; | }; | ||||
const telegramBot = new MockTelegramBot(); | const telegramBot = new MockTelegramBot(); | ||||
Show All 27 Lines | it('parseWebsocketMessage creates and sends a telegram msg with prices and token send info for all mocked blocks on successful API calls', 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('parseWebsocketMessage creates and sends a telegram msg without prices for all mocked blocks on failed price API call', async function () { | it('parseWebsocketMessage creates and sends a telegram msg without prices or token send info for all mocked blocks on failed API calls', 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 | |||||
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; | ||||
// Mock a chronik websocket msg of correct format | // Mock a chronik websocket msg of correct format | ||||
const mockWsMsg = { | const mockWsMsg = { | ||||
type: 'BlockConnected', | type: 'BlockConnected', | ||||
blockHash: thisBlockHash, | blockHash: thisBlockHash, | ||||
}; | }; | ||||
const telegramBot = new MockTelegramBot(); | const telegramBot = new MockTelegramBot(); | ||||
const channelId = mockChannelId; | const channelId = mockChannelId; | ||||
Show All 28 Lines | it('parseWebsocketMessage creates and sends a telegram msg without prices or token send info for all mocked blocks on failed API calls', async function () { | ||||
// Check that sendMessage was called successfully | // Check that sendMessage was called successfully | ||||
assert.strictEqual(telegramBot.messageSent, true); | assert.strictEqual(telegramBot.messageSent, true); | ||||
// 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('parseWebsocketMessage returns false if telegram msg fails to send', async function () { | it('parseWebsocketMessage returns false if telegram msg fails to send', async function () { | ||||
// Initialize chronik mock | for (let i = 0; i < blocks.length; i += 1) { | ||||
// Initialize new chronik mock for each block | |||||
const mockedChronik = new MockChronikClient(); | const mockedChronik = new MockChronikClient(); | ||||
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; | ||||
// 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), | |||||
}, | |||||
}, | |||||
}); | |||||
} | |||||
}); | |||||
} | |||||
// Mock a chronik websocket msg of correct format | // Mock a chronik websocket msg of correct format | ||||
const mockWsMsg = { | const mockWsMsg = { | ||||
type: 'BlockConnected', | type: 'BlockConnected', | ||||
blockHash: thisBlockHash, | blockHash: thisBlockHash, | ||||
}; | }; | ||||
const telegramBot = new MockTelegramBot(); | const telegramBot = new MockTelegramBot(); | ||||
telegramBot.setExpectedError( | telegramBot.setExpectedError( | ||||
'sendMessage', | 'sendMessage', | ||||
Show All 16 Lines |