Align Data.Raw decoding with Substrate (32-bytes) (#3573)

* Align Data.Raw decoding with Substrate (32-bytes)

* CHANGELOG

* Encoding test updates

* provider.disconnect

* Adjust provider tests

* Unique connection URLs

* Dangling tests

* detectOpenHandles

* Additional

* Remove rx test (catered for by Promise wrap)

* Additional cleanups to tests
This commit is contained in:
Jaco
2021-05-27 10:18:56 +02:00
committed by GitHub
parent 7497ac723f
commit 2d02f61fa7
34 changed files with 1173 additions and 1209 deletions
+8 -2
View File
@@ -45,6 +45,8 @@ export class MockProvider implements ProviderInterface {
private emitter = new EventEmitter();
private intervalId?: NodeJS.Timeout | null;
public isUpdating = true;
private registry: Registry;
@@ -104,8 +106,12 @@ export class MockProvider implements ProviderInterface {
// noop
}
// eslint-disable-next-line @typescript-eslint/require-await
public async disconnect (): Promise<void> {
// noop
if (this.intervalId) {
clearInterval(this.intervalId);
this.intervalId = null;
}
}
public get isConnected (): boolean {
@@ -175,7 +181,7 @@ export class MockProvider implements ProviderInterface {
const query = decorateStorage(this.registry, metadata.asLatest, metadata.version);
// Do something every 1 seconds
setInterval((): void => {
this.intervalId = setInterval((): void => {
if (!this.isUpdating) {
return;
}
@@ -15,6 +15,10 @@ describe('on', (): void => {
mock = new MockProvider(registry);
});
afterEach(async () => {
await mock.disconnect();
});
it('it emits both connected and disconnected events', (done): void => {
const events: Record<string, boolean> = { connected: false, disconnected: false };
@@ -13,6 +13,10 @@ describe('send', (): void => {
mock = new MockProvider(registry);
});
afterEach(async () => {
await mock.disconnect();
});
it('fails on non-supported methods', (): Promise<any> => {
return mock
.send('something_invalid', [])
@@ -13,6 +13,10 @@ describe('subscribe', (): void => {
mock = new MockProvider(registry);
});
afterEach(async () => {
await mock.disconnect();
});
it('fails on unknown methods', (): Promise<number | void> => {
return mock
.subscribe('test', 'test_notFound')
@@ -29,28 +33,28 @@ describe('subscribe', (): void => {
});
});
it('calls back with the last known value', (done): Promise<number> => {
it('calls back with the last known value', (done): void => {
mock.isUpdating = false;
mock.subscriptions.chain_subscribeNewHead.lastValue = 'testValue';
return mock.subscribe('chain_newHead', 'chain_subscribeNewHead', (_: any, value: string): void => {
mock.subscribe('chain_newHead', 'chain_subscribeNewHead', (_: any, value: string): void => {
expect(value).toEqual('testValue');
done();
});
}).catch(console.error);
});
it('calls back with new headers', (done): Promise<number> => {
return mock.subscribe('chain_newHead', 'chain_subscribeNewHead', (_: any, header: { number: number }): void => {
it('calls back with new headers', (done): void => {
mock.subscribe('chain_newHead', 'chain_subscribeNewHead', (_: any, header: { number: number }): void => {
if (header.number === 4) {
done();
}
});
}).catch(console.error);
});
it('handles errors withing callbacks gracefully', (done): Promise<number> => {
it('handles errors withing callbacks gracefully', (done): void => {
let hasThrown = false;
return mock.subscribe('chain_newHead', 'chain_subscribeNewHead', (_: any, header: { number: number }): void => {
mock.subscribe('chain_newHead', 'chain_subscribeNewHead', (_: any, header: { number: number }): void => {
if (!hasThrown) {
hasThrown = true;
@@ -60,6 +64,6 @@ describe('subscribe', (): void => {
if (header.number === 3) {
done();
}
});
}).catch(console.error);
});
});
@@ -20,6 +20,10 @@ describe('unsubscribe', (): void => {
});
});
afterEach(async () => {
await mock.disconnect();
});
it('fails on unknown ids', (): Promise<boolean> => {
return mock
.unsubscribe('chain_newHead', 'chain_subscribeNewHead', 5)
+42 -19
View File
@@ -3,9 +3,11 @@
import type { Mock } from './../mock/types';
import { mockWs, TEST_WS_URL } from '../../test/mockWs';
import { mockWs } from '../../test/mockWs';
import { WsProvider } from './';
const TEST_WS_URL = 'ws://localhost-connect.spec.ts:9988';
function sleepMs (ms = 0): Promise<void> {
return new Promise((resolve) => setTimeout(resolve, ms));
}
@@ -15,7 +17,7 @@ describe('onConnect', (): void => {
beforeEach((): void => {
jest.setTimeout(30000);
mocks = [mockWs([])];
mocks = [mockWs([], TEST_WS_URL)];
});
afterEach((): void => {
@@ -27,9 +29,19 @@ describe('onConnect', (): void => {
});
});
it('Does not connect when autoConnect is false', (): void => {
it('Does not connect when autoConnect is false', async () => {
const provider: WsProvider = new WsProvider(TEST_WS_URL, 0);
await sleepMs(100); // Hack to give the provider time to connect
expect(provider.isConnected).toBe(false);
await provider.connect();
await sleepMs(100); // Hack to give the provider time to connect
expect(provider.isConnected).toBe(true);
await provider.disconnect();
await sleepMs(100); // Hack to give the provider time to connect
expect(provider.isConnected).toBe(false);
});
@@ -38,6 +50,8 @@ describe('onConnect', (): void => {
await sleepMs(100); // Hack to give the provider time to connect
expect(provider.isConnected).toBe(true);
await provider.disconnect();
});
it('Creates a new WebSocket instance by calling the connect() method', async () => {
@@ -50,7 +64,9 @@ describe('onConnect', (): void => {
await sleepMs(100); // Hack to give the provider time to connect
expect(provider.isConnected).toBe(true);
expect(mocks[0].server.clients().length).toBe(1);
expect(mocks[0].server.clients()).toHaveLength(1);
await provider.disconnect();
});
it('Connects to first endpoint when an array is given', async () => {
@@ -60,22 +76,26 @@ describe('onConnect', (): void => {
await sleepMs(100); // Hack to give the provider time to connect
expect(provider.isConnected).toBe(true);
await provider.disconnect();
});
it('Connects to the second endpoint when the first is unreachable', async () => {
/* eslint-disable @typescript-eslint/no-empty-function */
jest.spyOn(console, 'error').mockImplementation((): void => {});
const endpoints: string[] = ['ws://localhost:9956', TEST_WS_URL];
const endpoints: string[] = ['ws://localhost-connect.spec.ts:9956', TEST_WS_URL];
const provider: WsProvider = new WsProvider(endpoints, 1);
await sleepMs(100); // Hack to give the provider time to connect
expect(provider.isConnected).toBe(true);
await provider.disconnect();
});
it('Connects to the second endpoint when the first is dropped', async () => {
const endpoints: string[] = [TEST_WS_URL, 'ws://localhost:9957'];
const endpoints: string[] = [TEST_WS_URL, 'ws://localhost-connect.spec.ts:9957'];
mocks.push(mockWs([], endpoints[1]));
@@ -83,26 +103,27 @@ describe('onConnect', (): void => {
await sleepMs(100); // Hack to give the provider time to connect
// Check that first server is connected
expect(mocks[0].server.clients().length).toBe(1);
expect(mocks[1].server.clients().length).toBe(0);
expect(mocks[0].server.clients()).toHaveLength(1);
expect(mocks[1].server.clients()).toHaveLength(0);
// Close connection from first server
mocks[0].server.clients()[0].close();
await sleepMs(100);
// Check that second server is connected
expect(mocks[1].server.clients().length).toBe(1);
expect(mocks[1].server.clients()).toHaveLength(1);
expect(provider.isConnected).toBe(true);
await provider.disconnect();
});
it('Round-robin of endpoints on WsProvider', async () => {
const rounds = 5;
const endpoints: string[] = [
TEST_WS_URL,
'ws://localhost:9956',
'ws://localhost:9957',
'ws://invalid:9956',
'ws://localhost:9958'
'ws://localhost-connect.spec.ts:9956',
'ws://localhost-connect.spec.ts:9957',
'ws://invalid-connect.spec.ts:9956',
'ws://localhost-connect.spec.ts:9958'
];
mocks.push(mockWs([], endpoints[1]));
@@ -117,18 +138,20 @@ describe('onConnect', (): void => {
];
const provider: WsProvider = new WsProvider(endpoints, 1);
for (let round = 0; round < rounds; round++) {
for (let index = 0; index < mocks.length; index++) {
for (let round = 0; round < 5; round++) {
for (let mock = 0; mock < mocks.length; mock++) {
await sleepMs(100); // Hack to give the provider time to connect
// Check that first server is connected and the next one isn't
expect(mocks[index].server.clients().length).toBe(1);
expect(mockNext[index].server.clients().length).toBe(0);
expect(mocks[mock].server.clients()).toHaveLength(1);
expect(mockNext[mock].server.clients()).toHaveLength(0);
expect(provider.isConnected).toBe(true);
// Close connection from first server
mocks[index].server.clients()[0].close();
mocks[mock].server.clients()[0].close();
}
}
await provider.disconnect();
});
});
+25 -23
View File
@@ -1,25 +1,32 @@
// Copyright 2017-2021 @polkadot/rpc-provider authors & contributors
// SPDX-License-Identifier: Apache-2.0
import { mockWs, TEST_WS_URL } from '../../test/mockWs';
import { mockWs } from '../../test/mockWs';
import { Mock } from './../mock/types';
import { WsProvider } from './';
let ws: WsProvider;
const TEST_WS_URL = 'ws://localhost-index.spec.ts:9977';
let provider: WsProvider | null;
let mock: Mock;
function createWs (requests: any[], autoConnect: number | undefined = 1000): WsProvider {
mock = mockWs(requests);
ws = new WsProvider(TEST_WS_URL, autoConnect);
function createWs (requests: any[], autoConnect = 1000, headers?: Record<string, string>): WsProvider {
mock = mockWs(requests, TEST_WS_URL);
provider = new WsProvider(TEST_WS_URL, autoConnect, headers);
return ws;
return provider;
}
describe('Ws', (): void => {
afterEach((): void => {
afterEach(async () => {
if (mock) {
mock.done();
}
if (provider) {
await provider.disconnect();
provider = null;
}
});
it('returns the connected state', (): void => {
@@ -28,10 +35,8 @@ describe('Ws', (): void => {
).toEqual(false);
});
it('allows you to initialize the provider with custom headers', (): void => {
expect(
(): WsProvider => new WsProvider(TEST_WS_URL, 1000, { foo: 'bar' })
).not.toThrow();
it('allows you to initialize the provider with custom headers', () => {
createWs([], 100, { foo: 'bar' });
});
});
@@ -42,10 +47,9 @@ describe('Endpoint Parsing', (): void => {
});
it('Throws when WsProvider endpoint is an invalid string', () => {
expect(() => {
/* eslint-disable no-new */
new WsProvider('http://127.0.0.1:9955', 0);
}).toThrowError(/^Endpoint should start with /);
expect(
() => new WsProvider('http://127.0.0.1:9955', 0)
).toThrowError(/^Endpoint should start with /);
});
it('Succeeds when WsProvider endpoint is a valid array', () => {
@@ -58,18 +62,16 @@ describe('Endpoint Parsing', (): void => {
it('Throws when WsProvider endpoint is an empty array', () => {
const endpoints: string[] = [];
expect(() => {
/* eslint-disable no-new */
new WsProvider(endpoints, 0);
}).toThrowError('WsProvider requires at least one Endpoint');
expect(
() => new WsProvider(endpoints, 0)
).toThrowError('WsProvider requires at least one Endpoint');
});
it('Throws when WsProvider endpoint is an invalid array', () => {
const endpoints: string[] = ['ws://127.0.0.1:9955', 'http://bad.co:9944', 'ws://mychain.com:9933'];
expect(() => {
/* eslint-disable no-new */
new WsProvider(endpoints, 0);
}).toThrowError(/^Endpoint should start with /);
expect(
() => new WsProvider(endpoints, 0)
).toThrowError(/^Endpoint should start with /);
});
});
+11 -4
View File
@@ -3,17 +3,19 @@
import type { Constructor } from '@polkadot/types/types';
import { mockWs, TEST_WS_URL } from '../../test/mockWs';
import { mockWs } from '../../test/mockWs';
import { Global, Mock } from './../mock/types';
import { WsProvider } from './';
declare const global: Global;
let provider: WsProvider;
const TEST_WS_URL = 'ws://localhost-send.spec.ts:9965';
let provider: WsProvider | null;
let mock: Mock;
function createMock (requests: any[]): void {
mock = mockWs(requests);
mock = mockWs(requests, TEST_WS_URL);
}
function createWs (autoConnect = 1000): Promise<WsProvider> {
@@ -29,12 +31,17 @@ describe('send', (): void => {
globalWs = global.WebSocket;
});
afterEach((): void => {
afterEach(async () => {
global.WebSocket = globalWs;
if (mock) {
mock.done();
}
if (provider) {
await provider.disconnect();
provider = null;
}
});
it('handles internal errors', (): Promise<any> => {
+2 -2
View File
@@ -6,13 +6,13 @@ import { WsProvider } from './';
describe('state', (): void => {
it('requires an ws:// prefixed endpoint', (): void => {
expect(
(): WsProvider => new WsProvider('http://', 0)
() => new WsProvider('http://', 0)
).toThrow(/with 'ws/);
});
it('allows wss:// endpoints', (): void => {
expect(
(): WsProvider => new WsProvider('wss://', 0)
() => new WsProvider('wss://', 0)
).not.toThrow();
});
});
+13 -6
View File
@@ -3,23 +3,25 @@
import type { Constructor } from '@polkadot/types/types';
import { mockWs, TEST_WS_URL } from '../../test/mockWs';
import { mockWs } from '../../test/mockWs';
import { Global, Mock } from './../mock/types';
import { WsProvider } from './';
declare const global: Global;
let ws: WsProvider;
const TEST_WS_URL = 'ws://localhost-subscribe.test.ts:9933';
let provider: WsProvider | null;
let mock: Mock;
function createMock (requests: any[]): void {
mock = mockWs(requests);
mock = mockWs(requests, TEST_WS_URL);
}
function createWs (autoConnect = 1000): Promise<WsProvider> {
ws = new WsProvider(TEST_WS_URL, autoConnect);
provider = new WsProvider(TEST_WS_URL, autoConnect);
return ws.isReady;
return provider.isReady;
}
describe('subscribe', (): void => {
@@ -29,12 +31,17 @@ describe('subscribe', (): void => {
globalWs = global.WebSocket;
});
afterEach((): void => {
afterEach(async () => {
global.WebSocket = globalWs;
if (mock) {
mock.done();
}
if (provider) {
await provider.disconnect();
provider = null;
}
});
it('adds subscriptions', (): Promise<void> => {
@@ -3,23 +3,25 @@
import type { Constructor } from '@polkadot/types/types';
import { mockWs, TEST_WS_URL } from '../../test/mockWs';
import { mockWs } from '../../test/mockWs';
import { Global, Mock } from './../mock/types';
import { WsProvider } from './';
declare const global: Global;
let ws: WsProvider;
const TEST_WS_URL = 'ws://localhost-unsubscribe.test.ts:9933';
let provider: WsProvider | null;
let mock: Mock;
function createMock (requests: any): void {
mock = mockWs(requests);
mock = mockWs(requests, TEST_WS_URL);
}
function createWs (autoConnect = 1000): Promise<WsProvider> {
ws = new WsProvider(TEST_WS_URL, autoConnect);
provider = new WsProvider(TEST_WS_URL, autoConnect);
return ws.isReady;
return provider.isReady;
}
describe('subscribe', (): void => {
@@ -29,12 +31,17 @@ describe('subscribe', (): void => {
globalWs = global.WebSocket;
});
afterEach((): void => {
afterEach(async () => {
global.WebSocket = globalWs;
if (mock) {
mock.done();
}
if (provider) {
await provider.disconnect();
provider = null;
}
});
it('removes subscriptions', (): Promise<boolean> => {