Skip to content

Commit

Permalink
Testing Framework (subquery#1584)
Browse files Browse the repository at this point in the history
* implement runTest

* check handler kind for running test

* implement testing service

* run tests in sandbox

* build test files through subql build

* run handlers in sandbox

* cleanup sandbox script and improve logging

* index data with `IndexerManager.indexData`

* use indexBlock() instead of indexData() for tests

* add getter _name to entities during codegen

* code cleanup

* improve logging

* improve logging

* bug fixes

* code cleanup

* improve logging

* indexBlock: get datasource from arguments

* move testingService to node-core

* code cleanup

* update ci

* code cleanup

* cleanup

* cleanup

* cleanup

* handle 0 test cases
  • Loading branch information
guplersaxanoid authored Apr 20, 2023
1 parent ce1e500 commit ccd1d1a
Show file tree
Hide file tree
Showing 38 changed files with 683 additions and 55 deletions.
5 changes: 5 additions & 0 deletions .github/workflows/gh-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,11 @@ jobs:
package-path: packages/types
repo-token: ${{ secrets.REPO_TOKEN }}

- uses: ./.github/actions/create-release
with:
package-path: packages/testing
repo-token: ${{ secrets.REPO_TOKEN }}

- uses: ./.github/actions/create-release
with:
package-path: packages/utils
Expand Down
12 changes: 12 additions & 0 deletions .github/workflows/prerelease.yml
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,11 @@ jobs:
with:
paths: packages/validator

- uses: marceloprado/has-changed-path@v1
id: changed-testing
with:
paths: packages/testing

- run: yarn

- name: build
Expand Down Expand Up @@ -149,6 +154,13 @@ jobs:
package-path: packages/cli
npm-token: ${{ secrets.NPM_TOKEN }}

- name: Bump testing & deploy
if: steps.changed-testing.outputs.changed == 'true'
uses: ./.github/actions/create-prerelease
with:
package-path: packages/testing
npm-token: ${{ secrets.NPM_TOKEN }}

- name: Commit changes
uses: EndBug/add-and-commit@v5
with:
Expand Down
13 changes: 13 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,11 @@ jobs:
with:
paths: packages/validator

- uses: marceloprado/has-changed-path@v1
id: changed-types
with:
paths: packages/testing

- run: yarn

- name: build
Expand Down Expand Up @@ -158,3 +163,11 @@ jobs:
package-path: packages/cli
repo-token: ${{ secrets.REPO_TOKEN }}
npm-token: ${{ secrets.NPM_TOKEN }}

- name: Publish Testing
if: steps.changed-testing.outputs.changed == 'true'
uses: ./.github/actions/create-release
with:
package-path: packages/testing
repo-token: ${{ secrets.REPO_TOKEN }}
npm-token: ${{ secrets.NPM_TOKEN }}
13 changes: 11 additions & 2 deletions packages/cli/src/commands/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import {lstatSync, readFileSync} from 'fs';
import path from 'path';
import {Command, Flags} from '@oclif/core';
import glob from 'glob';
import {runWebpack} from '../controller/build-controller';

export default class Build extends Command {
Expand Down Expand Up @@ -33,8 +34,16 @@ export default class Build extends Command {
const defaultEntry = path.join(directory, 'src/index.ts');
const outputDir = path.resolve(directory, flags.output ?? 'dist');

let buildEntries: {[key: string]: string} = {};
buildEntries.index = defaultEntry;
let buildEntries: {[key: string]: string} = {
index: defaultEntry,
};

const testFiles = glob.sync(path.join(directory, 'src/test/**/*.test.ts'));
testFiles.forEach((testFile) => {
const relativePath = path.relative(path.join(directory, 'src/test'), testFile);
const testName = relativePath.replace('.ts', '');
buildEntries[`test/${testName}`] = testFile;
});

if (pjson.exports && typeof pjson.exports !== 'string') {
buildEntries = Object.entries(pjson.exports as Record<string, string>).reduce(
Expand Down
6 changes: 5 additions & 1 deletion packages/cli/src/template/model.ts.ejs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {<% props.importEnums.forEach(function(e){ %>
<% }); %>} from '../enums'
<% } %>

export type <%= props.className %>Props = Omit<<%=props.className %>, NonNullable<FunctionPropertyNames<<%=props.className %>>>>;
export type <%= props.className %>Props = Omit<<%=props.className %>, NonNullable<FunctionPropertyNames<<%=props.className %>>>| '_name'>;

export class <%= props.className %> implements Entity {

Expand All @@ -25,6 +25,10 @@ export class <%= props.className %> implements Entity {
public <%= field.name %><%= field.required ? "" : "?" %>: <%= field.type %><%= field.isArray ? "[]" : "" %>;
<% }); %>

get _name(): string {
return '<%=props.entityName %>';
}

async save(): Promise<void>{
let id = this.id;
assert(id !== null, "Cannot save <%=props.className %> entity without an ID");
Expand Down
5 changes: 3 additions & 2 deletions packages/node-core/src/api.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export abstract class ApiService {

abstract init(): Promise<ApiService>;
abstract get api(): any; /*ApiWrapper*/
abstract fetchBlocks(batch: number[]): Promise<any>;

async fetchBlocksGeneric<T>(
fetchFuncProvider: FetchFunctionProvider<T>,
Expand All @@ -29,7 +30,7 @@ export abstract class ApiService {
): Promise<T[]> {
{
let reconnectAttempts = 0;
while (reconnectAttempts < MAX_RECONNECT_ATTEMPTS) {
while (reconnectAttempts < numAttempts) {
try {
// Get the latest fetch function from the provider
const fetchFunc = fetchFuncProvider();
Expand All @@ -40,7 +41,7 @@ export abstract class ApiService {
reconnectAttempts++;
}
}
throw new Error(`Maximum number of retries (${MAX_RECONNECT_ATTEMPTS}) reached.`);
throw new Error(`Maximum number of retries (${numAttempts}) reached.`);
}
}
}
8 changes: 5 additions & 3 deletions packages/node-core/src/indexer/benchmark.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,11 @@ export class BenchmarkService {
logger.info(
this.targetHeight === this.lastRegisteredHeight && this.blockPerSecond === 0
? 'Fully synced, waiting for new blocks'
: `${this.blockPerSecond.toFixed(2)} blocks/s. Target height: ${this.targetHeight.toLocaleString()}. Current height: ${
this.currentProcessingHeight.toLocaleString()
}. Estimated time remaining: ${this.blockPerSecond === 0 ? 'unknown' : durationStr}`
: `${this.blockPerSecond.toFixed(
2
)} blocks/s. Target height: ${this.targetHeight.toLocaleString()}. Current height: ${this.currentProcessingHeight.toLocaleString()}. Estimated time remaining: ${
this.blockPerSecond === 0 ? 'unknown' : durationStr
}`
);
}
this.lastRegisteredHeight = this.currentProcessingHeight;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ function isNullMerkelRoot(operationHash: Uint8Array): boolean {
return u8aEq(operationHash, NULL_MERKEL_ROOT);
}

export abstract class BaseBlockDispatcher<Q extends IQueue> implements IBlockDispatcher {
export abstract class BaseBlockDispatcher<Q extends IQueue, DS> implements IBlockDispatcher {
protected _latestBufferedHeight: number;
protected _processedBlockCount: number;
protected latestProcessedHeight: number;
Expand All @@ -60,7 +60,7 @@ export abstract class BaseBlockDispatcher<Q extends IQueue> implements IBlockDis
protected nodeConfig: NodeConfig,
protected eventEmitter: EventEmitter2,
private project: ISubqueryProject<IProjectNetworkConfig>,
protected projectService: IProjectService,
protected projectService: IProjectService<DS>,
protected queue: Q,
protected smartBatchService: SmartBatchService,
protected storeService: StoreService,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ type BatchBlockFetcher<B> = (heights: number[]) => Promise<B[]>;
* @description Intended to behave the same as WorkerBlockDispatcherService but doesn't use worker threads or any parallel processing
*/
export abstract class BlockDispatcher<B, DS>
extends BaseBlockDispatcher<Queue<number>>
extends BaseBlockDispatcher<Queue<number>, DS>
implements OnApplicationShutdown
{
private processQueue: AutoQueue<void>;
Expand All @@ -42,7 +42,7 @@ export abstract class BlockDispatcher<B, DS>
constructor(
nodeConfig: NodeConfig,
eventEmitter: EventEmitter2,
projectService: IProjectService,
projectService: IProjectService<DS>,
smartBatchService: SmartBatchService,
storeService: StoreService,
storeCacheService: StoreCacheService,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ type Worker = {
};

export abstract class WorkerBlockDispatcher<DS, W extends Worker>
extends BaseBlockDispatcher<AutoQueue<void>>
extends BaseBlockDispatcher<AutoQueue<void>, DS>
implements OnApplicationShutdown
{
protected workers: W[];
Expand All @@ -43,7 +43,7 @@ export abstract class WorkerBlockDispatcher<DS, W extends Worker>
constructor(
nodeConfig: NodeConfig,
eventEmitter: EventEmitter2,
projectService: IProjectService,
projectService: IProjectService<DS>,
smartBatchService: SmartBatchService,
storeService: StoreService,
storeCacheService: StoreCacheService,
Expand Down
1 change: 1 addition & 0 deletions packages/node-core/src/indexer/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,4 @@ export * from './sandbox';
export * from './smartBatch.service';
export * from './dynamic-ds.service';
export * from './blockDispatcher';
export * from './testing.service';
25 changes: 25 additions & 0 deletions packages/node-core/src/indexer/sandbox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,3 +155,28 @@ export class IndexerSandbox extends Sandbox {
this.freeze(logger, 'logger');
}
}

export class TestSandbox extends Sandbox {
constructor(option: SandboxOption, config: NodeConfig) {
super(
{
...option,
},
new VMScript(`const tests = require('${option.entry}');`, path.join(option.root, 'sandbox')),
config
);
this.injectGlobals(option);
}

private injectGlobals({store}: SandboxOption) {
if (store) {
this.freeze(store, 'store');
}
this.freeze(logger, 'logger');
}

async getTests() {
await this.runTimeout(1000);
return this.getGlobal('subqlTests');
}
}
Loading

0 comments on commit ccd1d1a

Please sign in to comment.