diff --git a/packages/node-core/src/indexer/unfinalizedBlocks.service.spec.ts b/packages/node-core/src/indexer/unfinalizedBlocks.service.spec.ts index 97603639b3..c1181b0a1d 100644 --- a/packages/node-core/src/indexer/unfinalizedBlocks.service.spec.ts +++ b/packages/node-core/src/indexer/unfinalizedBlocks.service.spec.ts @@ -87,7 +87,7 @@ describe('UnfinalizedBlocksService', () => { }); afterEach(() => { - (unfinalizedBlocksService as unknown as any).unfinalizedBlocks = {}; + (unfinalizedBlocksService as unknown as any)._unfinalizedBlocks = {}; }); it('can set finalized block', () => { diff --git a/packages/node/src/indexer/api.service.spec.ts b/packages/node/src/indexer/api.service.spec.ts index 2937ac36f0..409d09e8a9 100644 --- a/packages/node/src/indexer/api.service.spec.ts +++ b/packages/node/src/indexer/api.service.spec.ts @@ -25,11 +25,11 @@ jest.mock('@polkadot/api', () => { consts: jest.fn(), disconnect: jest.fn(), })); - return { ApiPromise, WsProvider: jest.fn() }; + return { ApiPromise, WsProvider: jest.fn(() => ({ send: jest.fn() })) }; }); const testNetwork = { - endpoint: { 'ws://kusama.api.onfinality.io/public-ws': {} }, + endpoint: ['ws://kusama.api.onfinality.io/public-ws'], types: { TestType: 'u32', }, @@ -108,13 +108,9 @@ describe('ApiService', () => { nodeConfig, ); const { version } = require('../../package.json'); - expect(WsProvider).toHaveBeenCalledWith( - Object.keys(testNetwork.endpoint)[0], - 2500, - { - 'User-Agent': `SubQuery-Node ${version}`, - }, - ); + expect(WsProvider).toHaveBeenCalledWith(testNetwork.endpoint[0], 2500, { + 'User-Agent': `SubQuery-Node ${version}`, + }); expect(createSpy).toHaveBeenCalledWith({ provider: expect.anything(), throwOnConnect: expect.anything(), diff --git a/packages/node/src/indexer/project.service.spec.ts b/packages/node/src/indexer/project.service.spec.ts index 97c814056e..7d80bc555c 100644 --- a/packages/node/src/indexer/project.service.spec.ts +++ b/packages/node/src/indexer/project.service.spec.ts @@ -11,13 +11,14 @@ import { ProjectUpgradeService, upgradableSubqueryProject, DsProcessorService, - DynamicDsService + DynamicDsService, } from '@subql/node-core'; import { SubstrateDatasourceKind, SubstrateHandlerKind } from '@subql/types'; import { GraphQLSchema } from 'graphql'; import { BlockchainService } from '../blockchain.service'; import { SubqueryProject } from '../configure/SubqueryProject'; import { ApiService } from './api.service'; +import { RuntimeService } from './runtime/runtimeService'; function testSubqueryProject(): SubqueryProject { return { @@ -140,7 +141,11 @@ describe('ProjectService', () => { }, { provide: ProjectService, - useFactory: (apiService: ApiService, project: SubqueryProject, blockchainService: BlockchainService) => + useFactory: ( + apiService: ApiService, + project: SubqueryProject, + blockchainService: BlockchainService, + ) => new TestProjectService( { validateProjectCustomDatasources: jest.fn(), @@ -166,24 +171,34 @@ describe('ProjectService', () => { } as unknown as DynamicDsService, null as unknown as any, null as unknown as any, - blockchainService + blockchainService, ), - inject: ['APIService', 'ISubqueryProject', BlockchainService,], + inject: ['APIService', 'ISubqueryProject', 'IBlockchainService'], }, EventEmitter2, { provide: 'APIService', useFactory: ApiService.create, - inject: ['ISubqueryProject', ConnectionPoolService, EventEmitter2, NodeConfig] + inject: [ + 'ISubqueryProject', + ConnectionPoolService, + EventEmitter2, + NodeConfig, + ], }, { provide: ProjectUpgradeService, useValue: projectUpgrade, }, + { + provide: 'RuntimeService', + useFactory: (apiService) => new RuntimeService(apiService), + inject: ['APIService'], + }, { provide: 'IBlockchainService', useClass: BlockchainService, - } + }, ], imports: [EventEmitterModule.forRoot()], }).compile(); diff --git a/packages/node/src/indexer/x-provider/cachedProvider.ts b/packages/node/src/indexer/x-provider/cachedProvider.ts index c747238aab..9f4e94de5f 100644 --- a/packages/node/src/indexer/x-provider/cachedProvider.ts +++ b/packages/node/src/indexer/x-provider/cachedProvider.ts @@ -7,9 +7,9 @@ import { LRUCache } from 'lru-cache'; const MAX_CACHE_SIZE = 200; const CACHE_TTL = 60 * 1000; -export function createCachedProvider( - provider: ProviderInterface, -): ProviderInterface { +export function createCachedProvider< + P extends ProviderInterface = ProviderInterface, +>(provider: P): P { const cacheMap = new LRUCache>({ max: MAX_CACHE_SIZE, ttl: CACHE_TTL, diff --git a/packages/node/src/indexer/x-provider/x-provider.spec.ts b/packages/node/src/indexer/x-provider/x-provider.spec.ts index 24333cdea0..7d7e84c983 100644 --- a/packages/node/src/indexer/x-provider/x-provider.spec.ts +++ b/packages/node/src/indexer/x-provider/x-provider.spec.ts @@ -14,13 +14,16 @@ describe('ApiPromiseConnection', () => { let httpProvider: HttpProvider; beforeEach(async () => { - wsProvider = await new WsProvider( - 'wss://kusama.api.onfinality.io/public-ws', - ).isReady; - httpProvider = new HttpProvider('https://kusama.api.onfinality.io/public'); + const ws = await new WsProvider('wss://kusama.api.onfinality.io/public-ws') + .isReady; + const http = new HttpProvider('https://kusama.api.onfinality.io/public'); - jest.spyOn(wsProvider, 'send'); - jest.spyOn(httpProvider, 'send'); + wsProvider = createCachedProvider(ws); + httpProvider = createCachedProvider(http); + + // TODO these don't work any more because the send method gets replaced + jest.spyOn(ws, 'send'); + jest.spyOn(http, 'send'); }); afterEach(async () => { @@ -28,52 +31,43 @@ describe('ApiPromiseConnection', () => { }); it('should not make duplicate requests for state_getRuntimeVersion on wsProvider', async () => { - const cachedProvider = createCachedProvider(wsProvider); - await Promise.all([ - cachedProvider.send('state_getRuntimeVersion', [TEST_BLOCKHASH]), - cachedProvider.send('state_getRuntimeVersion', [TEST_BLOCKHASH]), + wsProvider.send('state_getRuntimeVersion', [TEST_BLOCKHASH]), + wsProvider.send('state_getRuntimeVersion', [TEST_BLOCKHASH]), ]); expect(wsProvider.send).toHaveBeenCalledTimes(1); }); it('should not make duplicate requests for chain_getHeader on wsProvider', async () => { - const cachedProvider = createCachedProvider(wsProvider); await Promise.all([ - cachedProvider.send('chain_getHeader', [TEST_BLOCKHASH]), - cachedProvider.send('chain_getHeader', [TEST_BLOCKHASH]), + wsProvider.send('chain_getHeader', [TEST_BLOCKHASH]), + wsProvider.send('chain_getHeader', [TEST_BLOCKHASH]), ]); expect(wsProvider.send).toHaveBeenCalledTimes(1); }); it('should not make duplicate requests for state_getRuntimeVersion on httpProvider', async () => { - const cachedProvider = createCachedProvider(httpProvider); - await Promise.all([ - cachedProvider.send('state_getRuntimeVersion', [TEST_BLOCKHASH]), - cachedProvider.send('state_getRuntimeVersion', [TEST_BLOCKHASH]), + httpProvider.send('state_getRuntimeVersion', [TEST_BLOCKHASH]), + httpProvider.send('state_getRuntimeVersion', [TEST_BLOCKHASH]), ]); expect(httpProvider.send).toHaveBeenCalledTimes(1); }); it('should not make duplicate requests for chain_getHeader on httpProvider', async () => { - const cachedProvider = createCachedProvider(httpProvider); - await Promise.all([ - cachedProvider.send('chain_getHeader', [TEST_BLOCKHASH]), - cachedProvider.send('chain_getHeader', [TEST_BLOCKHASH]), + httpProvider.send('chain_getHeader', [TEST_BLOCKHASH]), + httpProvider.send('chain_getHeader', [TEST_BLOCKHASH]), ]); expect(httpProvider.send).toHaveBeenCalledTimes(1); }); it('should not cache requests if there are no args', async () => { - const cachedProvider = createCachedProvider(httpProvider); - - const result1 = await cachedProvider.send('chain_getHeader', []); + const result1 = await httpProvider.send('chain_getHeader', []); // Enough time for a new block await delay(7); - const result2 = await cachedProvider.send('chain_getHeader', []); + const result2 = await httpProvider.send('chain_getHeader', []); expect(httpProvider.send).toHaveBeenCalledTimes(2); expect(result1).not.toEqual(result2);