Skip to content
index.ts 3.55 KiB
Newer Older
// Copyright 2017-2022 Parity Technologies (UK) Ltd.
// This file is part of Substrate API Sidecar.
//
// Substrate API Sidecar is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

import { ArgumentParser } from 'argparse';
import { HOST, PORT } from '../helpers/consts';
import { IRequest, request } from '../helpers/request';
Bryan Chen's avatar
Bryan Chen committed
import * as endpoints from './endpoints';
Bryan Chen's avatar
Bryan Chen committed
	url: string;
Bryan Chen's avatar
Bryan Chen committed
	chain: keyof typeof endpoints;
// This is a shallow mock of the actual response from `/blocks/head`. We only need the number field.
interface IBlockResponse {
	number: string;
const main = async (args: ILatestE2eParser): Promise<StatusCode> => {
	const { Success, Failed } = StatusCode;

Bryan Chen's avatar
Bryan Chen committed
	const config = endpoints[args.chain] ?? endpoints.polkadot;

	let blockId: string;
	try {
		const res = await request('/blocks/head', HOST, PORT);
		blockId = (JSON.parse(res.data) as IBlockResponse).number;
	} catch (err) {
		throw `Error fetching the latest block: ${err as string}`;
	}

	/**
	 * Urls will contains all the urls including the base path of an endpoint,
	 * and seperate urls with the query params added. Anything that contains `{blockId}`
	 * will be replaced by the current blockId we are testing
	 */
	const urls: string[] = [];
	for (const endpoint in config) {
		const { path, queryParams } = config[endpoint];
		const formattedPath = path.replace('{blockId}', blockId);
		// Base endpoint with no query params attached
		urls.push(formattedPath);
		// Attach each of the query params to their own base path
		if (queryParams.length) {
			const tempPath = formattedPath.concat('?');
			const urlsWithParams = queryParams.map((param) => {
				return tempPath.concat(param).replace('{blockId}', blockId);
			});
			urls.push(...urlsWithParams);
		}
	}

Bryan Chen's avatar
Bryan Chen committed
	const url = new URL(args.url);
	const responses = await Promise.all(
		urls.map((u) => request(u, url.host, Number(url.port)))
	);
	const errors: IRequest[] = [];
	responses.forEach((res) => {
		if (res.statusCode && res.statusCode >= 400) {
			errors.push(res);
		}
	});
Bryan Chen's avatar
Bryan Chen committed
	logResults(errors);

	if (errors.length > 0) {
		console.log(`Finished with a status code of ${Failed}`);
		return Failed;
	} else {
		console.log(`Finished with a status code of ${Success}`);
		return Success;
	}
};

Bryan Chen's avatar
Bryan Chen committed
const logResults = (errors: IRequest[]) => {
	if (errors.length > 0) {
		console.log('Received the following errors:');
		errors.forEach((err) => {
			console.log('----------------------------------------------');
			console.log(`Queried Endpoint: ${err.path}`);
			console.log(`Status Code: ${err.statusCode as number}`);
			console.log(`Received logging: ${err.data}`);
		});
	} else {
		console.log('No errors were received');
	}

const parser = new ArgumentParser();

parser.add_argument('--chain', {
Bryan Chen's avatar
Bryan Chen committed
	choices: Object.keys(endpoints),
Bryan Chen's avatar
Bryan Chen committed
parser.add_argument('--url', {
	default: `${HOST}:${PORT}}`,
});

const args = parser.parse_args() as ILatestE2eParser;

main(args).finally(() => process.exit());