mirror of
https://github.com/cerc-io/watcher-ts
synced 2025-01-06 19:38:05 +00:00
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:
parent
dab2d6d3e7
commit
ceb0a3de23
@ -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
|
* `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`.
|
* 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
packages/cli/config.yaml
Normal file
12
packages/cli/config.yaml
Normal 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: ""
|
34
packages/cli/graphql/azimuth-query.graphql
Normal file
34
packages/cli/graphql/azimuth-query.graphql
Normal file
@ -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
|
||||||
|
}
|
||||||
|
}
|
12
packages/cli/graphql/non-subgraph-query.graphql
Normal file
12
packages/cli/graphql/non-subgraph-query.graphql
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
getSyncStatus {
|
||||||
|
initialIndexedBlockHash
|
||||||
|
initialIndexedBlockNumber
|
||||||
|
latestCanonicalBlockHash
|
||||||
|
latestIndexedBlockHash
|
||||||
|
latestCanonicalBlockNumber
|
||||||
|
latestIndexedBlockNumber
|
||||||
|
latestProcessedBlockHash
|
||||||
|
latestProcessedBlockNumber
|
||||||
|
}
|
||||||
|
}
|
19
packages/cli/graphql/subgraph-query.graphql
Normal file
19
packages/cli/graphql/subgraph-query.graphql
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
getSyncStatus {
|
||||||
|
initialIndexedBlockHash
|
||||||
|
initialIndexedBlockNumber
|
||||||
|
latestCanonicalBlockHash
|
||||||
|
latestIndexedBlockHash
|
||||||
|
latestCanonicalBlockNumber
|
||||||
|
latestIndexedBlockNumber
|
||||||
|
latestProcessedBlockHash
|
||||||
|
latestProcessedBlockNumber
|
||||||
|
}
|
||||||
|
_meta {
|
||||||
|
block {
|
||||||
|
hash
|
||||||
|
number
|
||||||
|
timestamp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -8,7 +8,8 @@
|
|||||||
"build": "yarn clean && tsc && yarn copy-assets",
|
"build": "yarn clean && tsc && yarn copy-assets",
|
||||||
"clean": "rm -rf ./dist",
|
"clean": "rm -rf ./dist",
|
||||||
"copy-assets": "copyfiles -u 1 src/**/*.gql 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": {
|
"dependencies": {
|
||||||
"@apollo/client": "^3.7.1",
|
"@apollo/client": "^3.7.1",
|
||||||
@ -27,7 +28,11 @@
|
|||||||
"debug": "^4.3.1",
|
"debug": "^4.3.1",
|
||||||
"ethers": "^5.4.4",
|
"ethers": "^5.4.4",
|
||||||
"express": "^4.18.2",
|
"express": "^4.18.2",
|
||||||
|
"graphql": "^15.5.0",
|
||||||
|
"graphql-request": "^6.1.0",
|
||||||
"graphql-subscriptions": "^2.0.0",
|
"graphql-subscriptions": "^2.0.0",
|
||||||
|
"js-yaml": "^4.0.0",
|
||||||
|
"json-diff": "^0.5.4",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"pluralize": "^8.0.0",
|
"pluralize": "^8.0.0",
|
||||||
"reflect-metadata": "^0.1.13",
|
"reflect-metadata": "^0.1.13",
|
||||||
@ -36,6 +41,8 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/express": "^4.17.14",
|
"@types/express": "^4.17.14",
|
||||||
|
"@types/js-yaml": "^4.0.3",
|
||||||
|
"@types/json-diff": "^0.5.2",
|
||||||
"@types/node": "16.11.7",
|
"@types/node": "16.11.7",
|
||||||
"@types/pluralize": "^0.0.29",
|
"@types/pluralize": "^0.0.29",
|
||||||
"@types/yargs": "^17.0.0",
|
"@types/yargs": "^17.0.0",
|
||||||
|
90
packages/cli/src/compare-gql.ts
Normal file
90
packages/cli/src/compare-gql.ts
Normal 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);
|
||||||
|
});
|
24
yarn.lock
24
yarn.lock
@ -1226,7 +1226,7 @@
|
|||||||
"@graphql-typed-document-node/core" "^3.1.1"
|
"@graphql-typed-document-node/core" "^3.1.1"
|
||||||
tslib "^2.4.0"
|
tslib "^2.4.0"
|
||||||
|
|
||||||
"@graphql-typed-document-node/core@^3.1.1":
|
"@graphql-typed-document-node/core@^3.1.1", "@graphql-typed-document-node/core@^3.2.0":
|
||||||
version "3.2.0"
|
version "3.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/@graphql-typed-document-node/core/-/core-3.2.0.tgz#5f3d96ec6b2354ad6d8a28bf216a1d97b5426861"
|
resolved "https://registry.yarnpkg.com/@graphql-typed-document-node/core/-/core-3.2.0.tgz#5f3d96ec6b2354ad6d8a28bf216a1d97b5426861"
|
||||||
integrity sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ==
|
integrity sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ==
|
||||||
@ -6512,6 +6512,13 @@ cross-fetch@^3.1.4:
|
|||||||
dependencies:
|
dependencies:
|
||||||
node-fetch "2.6.7"
|
node-fetch "2.6.7"
|
||||||
|
|
||||||
|
cross-fetch@^3.1.5:
|
||||||
|
version "3.1.8"
|
||||||
|
resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.8.tgz#0327eba65fd68a7d119f8fb2bf9334a1a7956f82"
|
||||||
|
integrity sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==
|
||||||
|
dependencies:
|
||||||
|
node-fetch "^2.6.12"
|
||||||
|
|
||||||
cross-spawn@^6.0.5:
|
cross-spawn@^6.0.5:
|
||||||
version "6.0.5"
|
version "6.0.5"
|
||||||
resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz"
|
resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz"
|
||||||
@ -9021,6 +9028,14 @@ graphql-compose@^9.0.3:
|
|||||||
dependencies:
|
dependencies:
|
||||||
graphql-type-json "0.3.2"
|
graphql-type-json "0.3.2"
|
||||||
|
|
||||||
|
graphql-request@^6.1.0:
|
||||||
|
version "6.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/graphql-request/-/graphql-request-6.1.0.tgz#f4eb2107967af3c7a5907eb3131c671eac89be4f"
|
||||||
|
integrity sha512-p+XPfS4q7aIpKVcgmnZKhMNqhltk20hfXtkaIkTfjjmiKMJ5xrt5c743cL03y/K7y1rg3WrIC49xGiEQ4mxdNw==
|
||||||
|
dependencies:
|
||||||
|
"@graphql-typed-document-node/core" "^3.2.0"
|
||||||
|
cross-fetch "^3.1.5"
|
||||||
|
|
||||||
graphql-subscriptions@^2.0.0:
|
graphql-subscriptions@^2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
resolved "https://registry.npmjs.org/graphql-subscriptions/-/graphql-subscriptions-2.0.0.tgz"
|
resolved "https://registry.npmjs.org/graphql-subscriptions/-/graphql-subscriptions-2.0.0.tgz"
|
||||||
@ -12223,6 +12238,13 @@ node-fetch@^2.6.1:
|
|||||||
resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz"
|
resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz"
|
||||||
integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==
|
integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==
|
||||||
|
|
||||||
|
node-fetch@^2.6.12:
|
||||||
|
version "2.7.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d"
|
||||||
|
integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==
|
||||||
|
dependencies:
|
||||||
|
whatwg-url "^5.0.0"
|
||||||
|
|
||||||
node-fetch@~1.7.1:
|
node-fetch@~1.7.1:
|
||||||
version "1.7.3"
|
version "1.7.3"
|
||||||
resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz"
|
resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz"
|
||||||
|
Loading…
Reference in New Issue
Block a user