Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add more format validation and better error messages #25

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/explorers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { TRANSACTION_APIS } from '../constants/api';
import { ExplorerAPI, TExplorerFunctionsArray } from '../models/Explorers';
import { ethereumRPCParsingFunction } from './rpc/ethereum';
import { bitcoinRPCParsingFunction } from './rpc/bitcoin';
import ensureExplorerAPIValidity from '../utils/ensureExplorerAPIValidity';

export interface TDefaultExplorersPerBlockchain {
bitcoin: TExplorerFunctionsArray;
Expand Down Expand Up @@ -93,6 +94,7 @@ export function getRPCExplorers (customExplorerAPIs?: ExplorerAPI[]): Partial<TE
}

export function prepareExplorerAPIs (customExplorerAPIs: ExplorerAPI[]): TExplorerAPIs {
ensureExplorerAPIValidity(customExplorerAPIs);
const { bitcoin, ethereum } = getDefaultExplorers(customExplorerAPIs);
const { custom: rpcCustomExplorers } = getRPCExplorers(customExplorerAPIs.filter(e => e.apiType === 'rpc'));
const restCustomExplorers = explorerFactory(customExplorerAPIs.filter(e => e.apiType !== 'rpc'));
Expand Down
8 changes: 5 additions & 3 deletions src/utils/ensureExplorerAPIValidity.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { ExplorerAPI } from '../models/Explorers';

function isPriorityValid (explorerAPI: ExplorerAPI): boolean {
return explorerAPI.priority >= 0;
return explorerAPI.priority >= 0 && explorerAPI.priority <= 1;
}

function isParsingFunctionValid (explorerAPI: ExplorerAPI): boolean {
Expand All @@ -14,11 +14,13 @@ export default function ensureExplorerAPIValidity (explorerAPIs: ExplorerAPI[] =
}

if (explorerAPIs.some(explorerAPI => !isPriorityValid(explorerAPI))) {
throw new Error('One or more of your custom explorer APIs has a priority set below zero');
throw new Error('One or more of your custom explorer APIs has a priority set below 0 or above 1. ' +
'Use 0 to give precedence to custom explorers over the default ones, or 1 for the contrary.');
}

if (explorerAPIs.some(explorerAPI => !isParsingFunctionValid(explorerAPI))) {
throw new Error('One or more of your custom explorer APIs does not have a parsing function');
throw new Error('One or more of your custom explorer APIs does not have a parsing function. ' +
'Parsing functions are required to convert the data received from the explorer.');
}

return true;
Expand Down
22 changes: 22 additions & 0 deletions tests/explorers/explorer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -290,5 +290,27 @@ describe('Blockchain Explorers test suite', function () {
expect(JSON.stringify(output)).toEqual(JSON.stringify(expectedExplorers));
});
});

describe('given the explorers provided are invalid', function () {
it('should throw an error', function () {
const fixtureCustomExplorerAPI: ExplorerAPI[] = [{
serviceURL: 'https://explorer-example.com',
priority: -1,
parsingFunction: (): TransactionData => {
return {
remoteHash: 'a',
issuingAddress: 'b',
time: 'c',
revokedAddresses: ['d']
};
}
}];
const expectedExplorers: TExplorerAPIs = getDefaultExplorers();
expectedExplorers.custom = explorerFactory(fixtureCustomExplorerAPI);
expect(() => prepareExplorerAPIs(fixtureCustomExplorerAPI))
.toThrow('One or more of your custom explorer APIs has a priority set below 0 or above 1. ' +
'Use 0 to give precedence to custom explorers over the default ones, or 1 for the contrary.');
});
});
});
});
54 changes: 52 additions & 2 deletions tests/lookForTx/lookForTx.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,13 @@ import * as explorers from '../../src/explorers';
import { TransactionData } from '../../src/models/TransactionData';
import CONFIG from '../../src/constants/config';
import lookForTx, { getExplorersByChain } from '../../src/lookForTx';
import { ExplorerAPI } from '../../src/models/Explorers';

describe('lookForTx test suite', function () {
const MOCK_TRANSACTION_ID = 'mock-transaction-id';

describe('given there are no custom explorers', function () {
it('should call and resolve from the explorers passed', async function () {
it('should call and resolve from the default explorers', async function () {
const mockTxData: TransactionData = {
revokedAddresses: [],
time: '2020-04-20T00:00:00Z',
Expand All @@ -33,7 +34,56 @@ describe('lookForTx test suite', function () {
});
});

describe('given it is called with a transactionId, a chain and a certificateVersion', function () {
describe('given some custom explorers are passed', function () {
describe('when it is a valid custom explorer API object', function () {
describe('and the custom explorer API is set an invalid priority', function () {
it('should throw an error', async function () {
const fixtureExplorerAPI: ExplorerAPI[] = [{
serviceURL: 'https://explorer-example.com',
priority: -1,
parsingFunction: (): TransactionData => {
return {
remoteHash: 'a',
issuingAddress: 'b',
time: 'c',
revokedAddresses: ['d']
};
}
}];

await expect(async () => {
await lookForTx({
transactionId: 'a-transaction-id',
chain: SupportedChains.Bitcoin,
explorerAPIs: fixtureExplorerAPI
});
}).rejects.toThrow('One or more of your custom explorer APIs has a priority set below 0 or above 1. ' +
'Use 0 to give precedence to custom explorers over the default ones, or 1 for the contrary.');
});
});

describe('and the custom explorer API has a missing parsing function', function () {
it('should throw an error', async function () {
const fixtureExplorerAPI: ExplorerAPI[] = [{
serviceURL: 'https://explorer-example.com',
priority: 0,
parsingFunction: undefined
}];

await expect(async () => {
await lookForTx({
transactionId: 'a-transaction-id',
chain: SupportedChains.Bitcoin,
explorerAPIs: fixtureExplorerAPI
});
}).rejects.toThrow('One or more of your custom explorer APIs does not have a parsing function. ' +
'Parsing functions are required to convert the data received from the explorer.');
});
});
});
});

describe('given it is called with a transactionId and a chain', function () {
describe('given the chain is invalid', function () {
it('should throw an error', async function () {
await expect(lookForTx({
Expand Down
6 changes: 4 additions & 2 deletions tests/utils/ensureExplorerAPIValidity.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ describe('ensureExplorerAPIValidity test suite', function () {
it('should throw the right error', function () {
expect(() => {
ensureExplorerAPIValidity(fixtureExplorerAPIs);
}).toThrow('One or more of your custom explorer APIs has a priority set below zero');
}).toThrow('One or more of your custom explorer APIs has a priority set below 0 or above 1. ' +
'Use 0 to give precedence to custom explorers over the default ones, or 1 for the contrary.');
});
});

Expand All @@ -34,7 +35,8 @@ describe('ensureExplorerAPIValidity test suite', function () {
it('should throw the right error', function () {
expect(() => {
ensureExplorerAPIValidity(fixtureExplorerAPIs);
}).toThrow('One or more of your custom explorer APIs does not have a parsing function');
}).toThrow('One or more of your custom explorer APIs does not have a parsing function. ' +
'Parsing functions are required to convert the data received from the explorer.');
});
});

Expand Down