Add CLI tool to compare watcher GQL responses (#494)

* Integrate gql response compare tool

* Add README for compare-gql tool

* Update readme

* Update CLI output logs

---------

Co-authored-by: neeraj <neeraj.rtly@gmail.com>
This commit is contained in:
2023-11-28 09:51:26 +05:30
committed by GitHub
co-authored by neeraj
parent dab2d6d3e7
commit ceb0a3de23
8 changed files with 238 additions and 2 deletions
+40
View File
@@ -54,3 +54,43 @@ A basic CLI to pass messages between peers using `stdin`/`stdout`
* `enable-debug-info`: Whether to broadcast node's info over pubsub on request
* The process starts reading from `stdin` and outputs messages from others peers over the `/chat/1.0.0` protocol to `stdout`.
## compare-gql
A basic CLI to to fetch and compare watcher GQL response.
* Create a `config.yaml` file in the following format in `packages/cli`:
```yaml
# Watcher URL
url: ""
# Boolean to specify if it is a subgraph watcher
isSubgraph: false
# File path for saving GQL result
gqlResultFilepath: "./result.json"
# Optional parameter to override default GQL query
graphqlQuery: ""
```
* Run the following command to fetch and save first GQL response:
```
yarn compare-gql --config config.yaml
```
* On running CLI for the first time
```
vulcanize:compare-gql Fetching response for the first time, re run CLI to compare with latest GQL response
```
* Re run CLI after some time (average time taken for new block in Ethereum: `~12 seconds`)
```
yarn compare-gql --config config.yaml
```
* The diff for latest and previous GQL responses is shown
+12
View File
@@ -0,0 +1,12 @@
# Watcher URL
url: ""
# Boolean to specify if it is a subgraph watcher
isSubgraph: false
# File path for saving GQL result
gqlResultFilepath: "./result.json"
# Optional parameter to override default GQL query
# Set GQL filepath containing query
graphqlQuery: ""
@@ -0,0 +1,34 @@
{
azimuthGetSyncStatus {
latestProcessedBlockNumber
latestIndexedBlockNumber
}
claimsGetSyncStatus {
latestProcessedBlockNumber
latestIndexedBlockNumber
}
censuresGetSyncStatus {
latestProcessedBlockNumber
latestIndexedBlockNumber
}
conditionalStarReleaseGetSyncStatus {
latestProcessedBlockNumber
latestIndexedBlockNumber
}
delegatedSendingGetSyncStatus {
latestProcessedBlockNumber
latestIndexedBlockNumber
}
eclipticGetSyncStatus {
latestProcessedBlockNumber
latestIndexedBlockNumber
}
linearStarReleaseGetSyncStatus {
latestProcessedBlockNumber
latestIndexedBlockNumber
}
pollsGetSyncStatus {
latestProcessedBlockNumber
latestIndexedBlockNumber
}
}
@@ -0,0 +1,12 @@
{
getSyncStatus {
initialIndexedBlockHash
initialIndexedBlockNumber
latestCanonicalBlockHash
latestIndexedBlockHash
latestCanonicalBlockNumber
latestIndexedBlockNumber
latestProcessedBlockHash
latestProcessedBlockNumber
}
}
@@ -0,0 +1,19 @@
{
getSyncStatus {
initialIndexedBlockHash
initialIndexedBlockNumber
latestCanonicalBlockHash
latestIndexedBlockHash
latestCanonicalBlockNumber
latestIndexedBlockNumber
latestProcessedBlockHash
latestProcessedBlockNumber
}
_meta {
block {
hash
number
timestamp
}
}
}
+8 -1
View File
@@ -8,7 +8,8 @@
"build": "yarn clean && tsc && yarn copy-assets",
"clean": "rm -rf ./dist",
"copy-assets": "copyfiles -u 1 src/**/*.gql dist/",
"chat": "DEBUG='vulcanize:*, laconic:*' node dist/chat.js"
"chat": "DEBUG='vulcanize:*, laconic:*' node dist/chat.js",
"compare-gql": "DEBUG='vulcanize:*' node dist/compare-gql.js"
},
"dependencies": {
"@apollo/client": "^3.7.1",
@@ -27,7 +28,11 @@
"debug": "^4.3.1",
"ethers": "^5.4.4",
"express": "^4.18.2",
"graphql": "^15.5.0",
"graphql-request": "^6.1.0",
"graphql-subscriptions": "^2.0.0",
"js-yaml": "^4.0.0",
"json-diff": "^0.5.4",
"lodash": "^4.17.21",
"pluralize": "^8.0.0",
"reflect-metadata": "^0.1.13",
@@ -36,6 +41,8 @@
},
"devDependencies": {
"@types/express": "^4.17.14",
"@types/js-yaml": "^4.0.3",
"@types/json-diff": "^0.5.2",
"@types/node": "16.11.7",
"@types/pluralize": "^0.0.29",
"@types/yargs": "^17.0.0",
+90
View File
@@ -0,0 +1,90 @@
import { request } from 'graphql-request';
import * as fs from 'fs';
import jsonDiff from 'json-diff';
import yargs from 'yargs';
import { hideBin } from 'yargs/helpers';
import path from 'path';
import yaml from 'js-yaml';
import debug from 'debug';
const SUBGRAPH_QUERY_FILEPATH = 'graphql/subgraph-query.graphql';
const NON_SUBGRAPH_QUERY_FILEPATH = 'graphql/non-subgraph-query.graphql';
const log = debug('vulcanize:compare-gql');
function readFromJSONFile (filename: string): {[key: string]: any} | null {
const fileContents = fs.readFileSync(filename, 'utf-8');
if (fileContents !== '') {
return JSON.parse(fileContents);
}
return null;
}
function getQuery (isSubgraph: boolean, queryFilepath?: string): any {
if (queryFilepath) {
return fs.readFileSync(queryFilepath, 'utf-8');
}
if (isSubgraph) {
return fs.readFileSync(SUBGRAPH_QUERY_FILEPATH, 'utf-8');
}
return fs.readFileSync(NON_SUBGRAPH_QUERY_FILEPATH, 'utf-8');
}
async function main (): Promise<void> {
const argv = await yargs(hideBin(process.argv))
.option('config', {
alias: 'c',
demandOption: true,
describe: 'Watcher config file path (yaml)',
type: 'string'
}).argv;
const configFilePath = path.resolve(argv.config);
const inputConfig = yaml.load(fs.readFileSync(configFilePath, 'utf8')) as any;
log('Config:', inputConfig);
const isSubgraph = inputConfig.isSubgraph;
const watcherUrl = inputConfig.url;
const configFileDirectory = path.dirname(configFilePath);
const gqlResultFilepath = path.resolve(configFileDirectory, inputConfig.gqlResultFilepath);
const graphqlQueryFilepath = inputConfig.graphqlQuery ? path.resolve(configFileDirectory, inputConfig.graphqlQuery) : undefined;
if (!fs.existsSync(gqlResultFilepath)) {
fs.writeFileSync(gqlResultFilepath, '', 'utf-8');
}
const query = getQuery(isSubgraph, graphqlQueryFilepath);
let gqlResponse;
try {
gqlResponse = await request(watcherUrl, query);
} catch (err) {
throw new Error('Error in GQL request: ' + (err as Error).message);
}
const readOutputData = readFromJSONFile(gqlResultFilepath);
if (readOutputData !== null) {
const diff = jsonDiff.diffString(readOutputData, gqlResponse);
if (diff !== '') {
log('Diff detected', diff);
} else {
log('No diff detected, GQL response', gqlResponse);
}
} else {
log('Fetching response for the first time, re run CLI to compare with latest GQL response');
}
fs.writeFileSync(gqlResultFilepath, JSON.stringify(gqlResponse, null, 2));
}
main().catch(err => {
log(err);
});