mirror of https://github.com/embarklabs/embark.git
test(stack/proxy): introduce tests
This commit is contained in:
parent
0e32cc09b5
commit
2170753dfd
|
@ -37,14 +37,22 @@
|
|||
"ci": "npm run qa",
|
||||
"clean": "npm run reset",
|
||||
"lint": "npm-run-all lint:*",
|
||||
"lint:js": "eslint src/",
|
||||
"lint:js": "eslint src/ test/",
|
||||
"lint:ts": "tslint -c tslint.json \"src/**/*.ts\"",
|
||||
"qa": "npm-run-all lint _typecheck _build",
|
||||
"reset": "npx rimraf dist embark-*.tgz package",
|
||||
"solo": "embark-solo"
|
||||
"solo": "embark-solo",
|
||||
"test": "jest"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": "../../../.eslintrc.json"
|
||||
"extends": [
|
||||
"../../../.eslintrc.json",
|
||||
"plugin:jest/recommended",
|
||||
"plugin:jest/style"
|
||||
],
|
||||
"rules": {
|
||||
"jest/expect-expect": "off"
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime-corejs3": "7.8.4",
|
||||
|
@ -63,10 +71,15 @@
|
|||
"web3-providers-ws": "1.2.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "7.8.3",
|
||||
"babel-jest": "25.1.0",
|
||||
"embark-solo": "^5.2.3",
|
||||
"embark-testing": "^5.3.0-nightly.12",
|
||||
"eslint": "6.8.0",
|
||||
"eslint-plugin-jest": "22.5.1",
|
||||
"npm-run-all": "4.1.5",
|
||||
"rimraf": "3.0.0",
|
||||
"sinon": "7.4.2",
|
||||
"tslint": "5.20.1",
|
||||
"typescript": "3.7.2"
|
||||
},
|
||||
|
@ -74,5 +87,20 @@
|
|||
"node": ">=10.17.0",
|
||||
"npm": ">=6.11.3",
|
||||
"yarn": ">=1.19.1"
|
||||
},
|
||||
"jest": {
|
||||
"collectCoverage": true,
|
||||
"testEnvironment": "node",
|
||||
"testMatch": [
|
||||
"**/test/**/*.js"
|
||||
],
|
||||
"transform": {
|
||||
"\\.(js|ts)$": [
|
||||
"babel-jest",
|
||||
{
|
||||
"rootMode": "upward"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,11 +20,13 @@ export default class ProxyManager {
|
|||
private isWs = false;
|
||||
private _endpoint: string = "";
|
||||
private inited: boolean = false;
|
||||
private requestManager: any = null;
|
||||
|
||||
constructor(private embark: Embark, options: any) {
|
||||
this.logger = embark.logger;
|
||||
this.events = embark.events;
|
||||
this.plugins = options.plugins;
|
||||
this.requestManager = options.requestManager;
|
||||
|
||||
this.host = "localhost";
|
||||
|
||||
|
@ -139,10 +141,10 @@ export default class ProxyManager {
|
|||
events: this.events,
|
||||
isWs: false,
|
||||
logger: this.logger,
|
||||
plugins: this.plugins
|
||||
plugins: this.plugins,
|
||||
requestManager: this.requestManager
|
||||
});
|
||||
|
||||
this.httpProxy.serve(this.host, this.rpcPort);
|
||||
await this.httpProxy.serve(this.host, this.rpcPort);
|
||||
this.logger.info(`HTTP Proxy for node endpoint ${endpoint} listening on ${buildUrl("http", this.host, this.rpcPort, "rpc")}`);
|
||||
|
||||
if (this.isWs) {
|
||||
|
@ -150,10 +152,11 @@ export default class ProxyManager {
|
|||
events: this.events,
|
||||
isWs: true,
|
||||
logger: this.logger,
|
||||
plugins: this.plugins
|
||||
plugins: this.plugins,
|
||||
requestManager: this.requestManager
|
||||
});
|
||||
|
||||
this.wsProxy.serve(this.host, this.wsPort);
|
||||
await this.wsProxy.serve(this.host, this.wsPort);
|
||||
this.logger.info(`WS Proxy for node endpoint ${endpoint} listening on ${buildUrl("ws", this.host, this.wsPort, "ws")}`);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ export class Proxy {
|
|||
this.events = options.events;
|
||||
this.isWs = options.isWs;
|
||||
this.nodeSubscriptions = {};
|
||||
this._requestManager = null;
|
||||
this._requestManager = options.requestManager || null;
|
||||
|
||||
this.events.setCommandHandler("proxy:websocket:subscribe", this.handleSubscribe.bind(this));
|
||||
this.events.setCommandHandler("proxy:websocket:unsubscribe", this.handleUnsubscribe.bind(this));
|
||||
|
@ -60,9 +60,7 @@ export class Proxy {
|
|||
}
|
||||
|
||||
async serve(localHost, localPort) {
|
||||
|
||||
await this.nodeReady();
|
||||
|
||||
this.app = express();
|
||||
if (this.isWs) {
|
||||
expressWs(this.app);
|
||||
|
@ -132,7 +130,6 @@ export class Proxy {
|
|||
// Send the possibly modified request to the Node
|
||||
const response = { jsonrpc: "2.0", id: modifiedRequest.request.id };
|
||||
if (modifiedRequest.sendToNode !== false) {
|
||||
|
||||
try {
|
||||
response.result = await this.forwardRequestToNode(modifiedRequest.request);
|
||||
} catch (fwdReqErr) {
|
||||
|
@ -278,7 +275,7 @@ export class Proxy {
|
|||
return new Promise((resolve, reject) => {
|
||||
let calledBack = false;
|
||||
const data = { request, isWs: this.isWs, transport };
|
||||
setTimeout(() => {
|
||||
const timeoutId = setTimeout(() => {
|
||||
if (calledBack) {
|
||||
return;
|
||||
}
|
||||
|
@ -303,6 +300,7 @@ export class Proxy {
|
|||
return reject(err);
|
||||
}
|
||||
calledBack = true;
|
||||
clearTimeout(timeoutId);
|
||||
resolve(result);
|
||||
});
|
||||
});
|
||||
|
@ -312,7 +310,7 @@ export class Proxy {
|
|||
return new Promise((resolve, reject) => {
|
||||
const data = { originalRequest, request, response, isWs: this.isWs, transport };
|
||||
let calledBack = false;
|
||||
setTimeout(() => {
|
||||
const timeoutId = setTimeout(() => {
|
||||
if (calledBack) {
|
||||
return;
|
||||
}
|
||||
|
@ -338,6 +336,7 @@ export class Proxy {
|
|||
return reject(err);
|
||||
}
|
||||
calledBack = true;
|
||||
clearTimeout(timeoutId);
|
||||
resolve(result);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -0,0 +1,87 @@
|
|||
import sinon from 'sinon';
|
||||
import assert from 'assert';
|
||||
import { fakeEmbark } from 'embark-testing';
|
||||
import ProxyManager from '../src';
|
||||
import { Proxy } from '../src/proxy';
|
||||
|
||||
const mockRequestManager = {
|
||||
send: (request, cb) => {
|
||||
return new Promise(resolve => {
|
||||
if (cb) {
|
||||
cb(null, {});
|
||||
}
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
describe('stack/proxy', () => {
|
||||
|
||||
let proxyManager, embark;
|
||||
|
||||
beforeEach(() => {
|
||||
const testBed = fakeEmbark({
|
||||
blockchainConfig: {
|
||||
proxy: {}
|
||||
}
|
||||
});
|
||||
|
||||
embark = testBed.embark;
|
||||
proxyManager = new ProxyManager(embark, {
|
||||
plugins: testBed.embark,
|
||||
requestManager: mockRequestManager
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await proxyManager.stopProxy();
|
||||
embark.teardown();
|
||||
sinon.restore();
|
||||
});
|
||||
|
||||
describe('instantiation', () => {
|
||||
|
||||
it('should register proxy:endpoint:get command handler', () => {
|
||||
embark.events.assert.commandHandlerRegistered('proxy:endpoint:get');
|
||||
});
|
||||
});
|
||||
|
||||
it('should return default proxy endpoint', async () => {
|
||||
const endpoint = await embark.events.request2('proxy:endpoint:get');
|
||||
assert.equal(endpoint, 'ws://localhost:8556');
|
||||
});
|
||||
|
||||
it('should initialize', async () => {
|
||||
await proxyManager.init();
|
||||
assert(proxyManager.inited);
|
||||
assert.equal(proxyManager.rpcPort, 8555);
|
||||
assert.equal(proxyManager.wsPort, 8556);
|
||||
assert(proxyManager.isWs);
|
||||
});
|
||||
|
||||
it('should setup proxy', async () => {
|
||||
embark.events.setCommandHandler('blockchain:node:provider', (cb) => {
|
||||
cb({});
|
||||
});
|
||||
await proxyManager.setupProxy();
|
||||
assert(proxyManager.httpProxy instanceof Proxy);
|
||||
assert(proxyManager.wsProxy instanceof Proxy);
|
||||
});
|
||||
|
||||
it('should stop proxy', async () => {
|
||||
const stopSpy = sinon.spy(cb => cb());
|
||||
|
||||
proxyManager.wsProxy = {
|
||||
stop: stopSpy
|
||||
};
|
||||
|
||||
proxyManager.httpProxy = {
|
||||
stop: stopSpy
|
||||
};
|
||||
|
||||
await proxyManager.stopProxy();
|
||||
assert(stopSpy.calledTwice);
|
||||
assert.equal(proxyManager.wsProxy, null);
|
||||
assert.equal(proxyManager.httpProxy, null);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,206 @@
|
|||
import sinon from 'sinon';
|
||||
import assert from 'assert';
|
||||
import { fakeEmbark } from 'embark-testing';
|
||||
import { Proxy } from '../src/proxy';
|
||||
|
||||
describe('stack/proxy', () => {
|
||||
|
||||
let proxy, embark, mockWs;
|
||||
|
||||
beforeEach(() => {
|
||||
|
||||
const testBed = fakeEmbark();
|
||||
embark = testBed.embark;
|
||||
|
||||
proxy = new Proxy({
|
||||
plugins: embark.plugins,
|
||||
logger: embark.logger,
|
||||
events: embark.events,
|
||||
isWs: true
|
||||
});
|
||||
|
||||
mockWs = {
|
||||
OPEN: 1,
|
||||
readyState: 1,
|
||||
on: (ev, cb) => cb(),
|
||||
send: sinon.spy(() => {})
|
||||
};
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
return new Promise(resolve => {
|
||||
embark.teardown();
|
||||
sinon.restore();
|
||||
proxy.stop(resolve);
|
||||
});
|
||||
});
|
||||
|
||||
describe('instantiation', () => {
|
||||
|
||||
it('should register proxy:websocket:subscribe command handler', () => {
|
||||
embark.events.assert.commandHandlerRegistered('proxy:websocket:subscribe');
|
||||
});
|
||||
|
||||
it('should register proxy:websocket:unsubscribe command handler', () => {
|
||||
embark.events.assert.commandHandlerRegistered('proxy:websocket:unsubscribe');
|
||||
});
|
||||
});
|
||||
|
||||
it('should get notified when the connecting node is ready', async () => {
|
||||
|
||||
const providerSendSpy = sinon.spy(() => Promise.resolve());
|
||||
|
||||
embark.events.setCommandHandler('blockchain:node:provider', (cb) => {
|
||||
cb(null, {
|
||||
send: providerSendSpy
|
||||
});
|
||||
});
|
||||
|
||||
await proxy.nodeReady();
|
||||
assert(providerSendSpy.calledOnce);
|
||||
});
|
||||
|
||||
it('should emit actions for proxy requests', async () => {
|
||||
|
||||
const mockRequest = {
|
||||
method: 'POST',
|
||||
body: {
|
||||
id: 4,
|
||||
jsonrpc: '2.0',
|
||||
method: 'test_method'
|
||||
}
|
||||
};
|
||||
|
||||
const requestAction = sinon.spy((params, cb) => {
|
||||
params.somethingCustom = true;
|
||||
cb(null, params);
|
||||
});
|
||||
|
||||
embark.plugins.registerActionForEvent('blockchain:proxy:request', requestAction);
|
||||
|
||||
const modifiedRequest = await proxy.emitActionsForRequest(mockRequest, mockWs);
|
||||
assert(modifiedRequest.isWs);
|
||||
assert(modifiedRequest.transport);
|
||||
assert(modifiedRequest.somethingCustom);
|
||||
assert.equal(modifiedRequest.request, mockRequest);
|
||||
});
|
||||
|
||||
it('should emit actions for proxy responses', async () => {
|
||||
|
||||
const mockRequest = {
|
||||
method: 'POST',
|
||||
body: {
|
||||
id: 4,
|
||||
jsonrpc: '2.0',
|
||||
method: 'test_method'
|
||||
}
|
||||
};
|
||||
|
||||
const mockResponse = {
|
||||
"id": 4,
|
||||
"jsonrpc": "2.0",
|
||||
"result": {
|
||||
"response": "ok"
|
||||
}
|
||||
};
|
||||
|
||||
const responseAction = sinon.spy((params, cb) => {
|
||||
params.somethingCustom = true;
|
||||
cb(null, params);
|
||||
});
|
||||
|
||||
embark.plugins.registerActionForEvent('blockchain:proxy:response', responseAction);
|
||||
|
||||
const modifiedResponse = await proxy.emitActionsForResponse(mockRequest, mockResponse, mockWs);
|
||||
assert(modifiedResponse.isWs);
|
||||
assert(modifiedResponse.transport);
|
||||
assert.equal(modifiedResponse.transport, mockWs);
|
||||
assert(modifiedResponse.somethingCustom);
|
||||
});
|
||||
|
||||
it('should process request and run request and reponse actions', async () => {
|
||||
|
||||
const mockRequest = {
|
||||
method: 'POST',
|
||||
body: {
|
||||
id: 2,
|
||||
jsonrpc: '2.0',
|
||||
method: 'test_method'
|
||||
}
|
||||
};
|
||||
|
||||
const mockRPCResponse = {
|
||||
"id": 2,
|
||||
"jsonrpc": "2.0",
|
||||
"result": {
|
||||
"response": "ok"
|
||||
}
|
||||
};
|
||||
|
||||
const mockRequestManager = { send: sinon.spy((options, cb) => cb(null, mockRPCResponse)) };
|
||||
|
||||
embark.events.setCommandHandler('blockchain:node:provider', (cb) => cb(null, mockRequestManager));
|
||||
|
||||
const requestAction = sinon.spy((params, cb) => {
|
||||
params.sendToNode = false;
|
||||
cb(null, params);
|
||||
});
|
||||
const responseAction = sinon.spy((params, cb) => cb(null, params));
|
||||
|
||||
embark.plugins.registerActionForEvent('blockchain:proxy:request', requestAction);
|
||||
embark.plugins.registerActionForEvent('blockchain:proxy:response', responseAction);
|
||||
await proxy.processRequest(mockRequest, mockWs);
|
||||
assert(requestAction.calledOnce);
|
||||
assert(responseAction.calledOnce);
|
||||
assert(mockWs.send.calledOnce);
|
||||
});
|
||||
|
||||
it('should forward request to node', async () => {
|
||||
|
||||
const mockRequest = {
|
||||
method: 'POST',
|
||||
body: {
|
||||
id: 3,
|
||||
jsonrpc: '2.0',
|
||||
method: 'test_method'
|
||||
}
|
||||
};
|
||||
|
||||
const mockRPCResponse = {
|
||||
"id": 3,
|
||||
"jsonrpc": "2.0",
|
||||
"result": {
|
||||
"response": "ok"
|
||||
}
|
||||
};
|
||||
|
||||
const forwardSpy = sinon.spy((options, cb) => cb(null, mockRPCResponse));
|
||||
const mockRequestManager = { send: forwardSpy };
|
||||
|
||||
embark.events.setCommandHandler('blockchain:node:provider', (cb) => cb(null, mockRequestManager));
|
||||
|
||||
const requestAction = sinon.spy((params, cb) => {
|
||||
params.sendToNode = true;
|
||||
cb(null, params);
|
||||
});
|
||||
|
||||
embark.plugins.registerActionForEvent('blockchain:proxy:request', requestAction);
|
||||
await proxy.processRequest(mockRequest, mockWs);
|
||||
assert(forwardSpy.calledOnce);
|
||||
});
|
||||
|
||||
it('should stop the proxy server', () => {
|
||||
|
||||
const closeSpy = sinon.spy(cb => cb());
|
||||
proxy.server = {
|
||||
close: closeSpy
|
||||
};
|
||||
|
||||
proxy.stop(() => {
|
||||
assert(true);
|
||||
});
|
||||
|
||||
assert(closeSpy.calledOnce);
|
||||
assert.equal(proxy.server, null);
|
||||
});
|
||||
});
|
|
@ -21,6 +21,9 @@
|
|||
},
|
||||
{
|
||||
"path": "../../core/utils"
|
||||
},
|
||||
{
|
||||
"path": "../../utils/testing"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue