1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132 |
- import { describe, it } from "mocha";
- import { RPCServer, RPCSocket, Serializable } from '../Index'
- import { RPCExporter, Socket } from "../src/Interfaces";
- import { ConnectedSocket, Callback, GenericFunction } from "../src/Types";
- import * as log from 'why-is-node-running';
- import * as http from 'http';
- import * as express from 'express';
- import * as fetch from 'node-fetch';
- import { PromiseIO } from "../src/PromiseIO/Server";
- import { PromiseIOClient } from "../src/PromiseIO/Client";
- import { assert, expect } from 'chai';
- import { CLASSNAME_ATTRIBUTE, USER_DEFINED_TIMEOUT } from "../src/Strings";
- var should = require('chai').should();
- var chai = require("chai");
- var chaiAsPromised = require("chai-as-promised");
-
- chai.use(chaiAsPromised);
- const noop = (...args) => { }
-
- const add = (...args: number[]) => { return args.reduce((a, b) => a + b, 0) }
- function makeServer(onCallback = noop, connectionHandler = noop, hookCloseHandler = noop, closeHandler = noop, errorHandler = noop) {
- let subcallback
- const serv = new RPCServer([{
- name: 'test',
- RPCs: [
- {
- name: 'echo',
- call: async (s: string) => s,
- }, {
- name: 'complexSignature',
- call: async ([a, b]) => {
- return [b, a]
- }
- }, {
- name: 'simpleSubscribe',
- hook: async (callback) => {
- subcallback = callback
- return { topic: "test" }
- },
- onDestroy: hookCloseHandler
- }, {
- name: 'subscribe',
- hook: async (callback) => {
- subcallback = callback
- return { topic: "test" }
- },
- onDestroy: hookCloseHandler,
- onCallback: onCallback
- },
- add,
- function triggerCallback(...messages: any[]): number { return subcallback.apply({}, messages) },
- function brokenRPC() { throw new Error("Intended error") }
- ]
- }],
- {
- connectionHandler: connectionHandler,
- closeHandler: closeHandler,
- errorHandler: errorHandler
- })
- serv.listen(21010)
- return serv
- }
-
-
- describe('PromiseIO', () => {
-
- it("bind + fire", (done) => {
- const server = new PromiseIO()
- server.attach(new http.Server())
- server.on("socket", clientSocket => {
- clientSocket.bind("test123", (p1, p2) => {
- server.close()
- if (p1 === "p1" && p2 === "p2")
- done()
- })
- });
-
- server.listen(21003)
- PromiseIOClient.connect(21003, "localhost", { protocol: 'http' }).then(cli => {
- cli.fire("test123", "p1", "p2")
- cli.close()
- })
- })
-
- it("hook + call", (done) => {
- const server = new PromiseIO()
- server.attach(new http.Server())
- server.on("socket", clientSocket => {
- clientSocket.hook("test123", (p1, p2) => {
- if (p1 === "p1" && p2 === "p2")
- return "OK"
- })
- });
-
- server.listen(21003)
- PromiseIOClient.connect(21003, "localhost", { protocol: 'http' }).then(cli => {
- cli.call("test123", "p1", "p2").then(resp => {
- cli.close()
- server.close()
-
- if (resp === "OK")
- done()
- })
- })
- })
-
- it("on + emit", (done) => {
- const server = new PromiseIO()
- server.attach(new http.Server())
- server.on("socket", clientSocket => {
- clientSocket.on("test123", (p1, p2) => {
- server.close()
- if (p1 === "p1" && p2 === "p2")
- done()
- })
- });
-
- server.listen(21003)
- PromiseIOClient.connect(21003, "localhost", { protocol: 'http' }).then(cli => {
- cli.emit("test123", "p1", "p2")
- cli.close()
- })
- })
- })
-
- describe('RPCServer', () => {
- let client, server
- const echo = (x) => x
-
- before(done => {
- server = new RPCServer([{
- name: 'HelloWorldRPCGroup',
- RPCs: () => [
- echo, //named function variable
- function echof(x) { return x }, //named function
- {
- name: 'echoExplicit', //describing object
- call: async (x, y, z) => [x, y, z]
- }
- ]
- }])
- server.listen(21003)
- client = new RPCSocket(21003, 'localhost')
- done()
- })
-
- after(done => {
- client.close()
- server.close()
-
- done()
- })
-
- it('should be able to use all kinds of RPC definitions', async () => {
- await client.connect()
- const r0 = await client['HelloWorldRPCGroup'].echo('Hello')
- const r1 = await client['HelloWorldRPCGroup'].echof('World')
- const r2 = await client['HelloWorldRPCGroup'].echoExplicit('R', 'P', 'C!')
-
- expect(r0).to.be.equal('Hello')
- expect(r1).to.be.equal('World')
- expect(r2.join('')).to.be.equal('RPC!')
- })
-
- it('new RPCServer() should fail on unnamed RPC', async () => {
- expect(() => {
- const sv = new RPCServer([{
- name: 'bad',
- RPCs: () => [
- (aaa, bbb, ccc) => { return aaa + bbb + ccc }
- ]
- }])
- }).to.throw()
- })
- })
-
- describe('RPCServer with premade http server', () => {
- const echo = (x) => x
- const RPCs = [
- echo, //named function variable
- function echof(x) { return x }, //named function
- {
- name: 'echoExplicit', //describing object
- call: async (x, y, z) => [x, y, z]
- }
- ]
-
- const RPCExporters = [
- {
- name: 'HelloWorldRPCGroup',
- RPCs: RPCs,
- }
- ]
-
- const RPCExporters2 = [
- {
- name: 'Grp2',
- RPCs: [
- function test() { return "test" }
- ],
- }
- ]
-
- let client: RPCSocket, server: RPCServer
-
- before(done => {
- const expressServer = express()
- const httpServer = new http.Server(expressServer)
-
- expressServer.get('/REST_ping', (req, res) => {
- return res
- .send('REST_pong')
- .status(200)
- })
-
- server = new RPCServer(
- RPCExporters,
- )
- server.attach(httpServer)
- httpServer.listen(8080)
-
- client = new RPCSocket(8080, 'localhost')
-
- done()
- })
-
- after(done => {
- client.close()
- server.close()
-
- done()
- })
-
- it('should serve REST', async () => {
- const response = await fetch('http://localhost:8080/REST_ping')
- const text = await response.text()
- expect(text).to.be.equal("REST_pong")
- })
-
-
- it('should be able to use all kinds of RPC definitions', async () => {
- await client.connect()
- const r0 = await client['HelloWorldRPCGroup'].echo('Hello')
- const r1 = await client['HelloWorldRPCGroup'].echof('World')
- const r2 = await client['HelloWorldRPCGroup'].echoExplicit('R', 'P', 'C!')
- expect(r0).to.be.equal('Hello')
- expect(r1).to.be.equal('World')
- expect(r2.join('')).to.be.equal('RPC!')
- })
- })
-
- describe('should be able to attach to non-standard path', () => {
- let client: RPCSocket, server: RPCServer
- const echo = (x) => x
-
- before(done => {
- server = new RPCServer([{
- name: 'HelloWorldRPCGroup',
- RPCs: () => [
- echo, //named function variable
- function echof(x) { return x }, //named function
- {
- name: 'echoExplicit', //describing object
- call: async (x, y, z) => [x, y, z]
- }
- ]
- }])
- server.listen(21003, { path: '/test' })
- client = new RPCSocket(21003, 'localhost', { path: '/test' })
- done()
- })
-
- after(done => {
- client.close()
- server.close()
-
- done()
- })
-
- it('should be able to use all kinds of RPC definitions', async () => {
- await client.connect()
- const r0 = await client['HelloWorldRPCGroup'].echo('Hello')
- const r1 = await client['HelloWorldRPCGroup'].echof('World')
- const r2 = await client['HelloWorldRPCGroup'].echoExplicit('R', 'P', 'C!')
- expect(r0).to.be.equal('Hello')
- expect(r1).to.be.equal('World')
- expect(r2.join('')).to.be.equal('RPC!')
- })
- })
-
-
- describe('can attach multiple RPCServers to same http server', () => {
- const echo = (x) => x
- const RPCs = [
- echo, //named function variable
- function echof(x) { return x }, //named function
- {
- name: 'echoExplicit', //describing object
- call: async (x, y, z) => [x, y, z]
- }
- ]
-
- const RPCExporters = [
- {
- name: 'HelloWorldRPCGroup',
- RPCs: RPCs,
- }
- ]
-
- const RPCExporters2 = [
- {
- name: 'Grp2',
- RPCs: [
- function test() { return "/test" }
- ],
- }
- ]
- const callTimeout = 100;
-
- let client: RPCSocket, client2: RPCSocket, server: RPCServer, server2: RPCServer
-
- before(done => {
- const expressServer = express()
- const httpServer = new http.Server(expressServer)
-
- server = new RPCServer(
- RPCExporters,
- )
- server2 = new RPCServer(
- RPCExporters2
- )
-
- server.attach(httpServer)
- server2.attach(httpServer, {
- path: "test"
- })
-
- httpServer.listen(8080)
-
- new RPCSocket(8080, 'localhost').connect().then(sock => {
- client = sock
- new RPCSocket(8080, 'localhost', { path: "test", callTimeoutMs: callTimeout }).connect().then(sock2 => {
- client2 = sock2
- done()
- })
- })
- })
-
- after(done => {
- client.close()
- client2.close()
- server.close()
- server2.close()
-
- done()
- })
-
- it('both servers should answer', async () => {
- const res = await client['HelloWorldRPCGroup'].echo("test")
- expect(res).to.equal('test')
- const res2 = await client2['Grp2'].test()
- expect(res2).to.equal('/test')
- })
-
- it('server1 should answer after server2 is closed', async () => {
- server2.close()
- const res = await client['HelloWorldRPCGroup'].echo("test")
- expect(res).to.equal('test')
- return client2['Grp2'].test().should.eventually.be.rejectedWith(USER_DEFINED_TIMEOUT(callTimeout))
- })
- })
-
- describe("can attach second RPCServer if first is already running", () => {
-
- const RPCExporters = [
- {
- name: 'HelloWorldRPCGroup',
- RPCs: [
- function echo(x) { return x }, //named function variable
- function echof(x) { return x }, //named function
- {
- name: 'echoExplicit', //describing object
- call: async (x, y, z) => [x, y, z]
- }
- ],
- }
- ]
-
- const RPCExporters2 = [
- {
- name: 'Grp2',
- RPCs: [
- function test() { return "/test" }
- ],
- }
- ]
-
- it("attaches correctly", async () => {
- const expressServer = express()
- const httpServer = new http.Server(expressServer)
-
- const server = new RPCServer(
- RPCExporters,
- )
- const server2 = new RPCServer(
- RPCExporters2
- )
-
- server.attach(httpServer)
-
- httpServer.listen(8080)
- server2.attach(httpServer, {
- path: "test"
- })
-
- const sock = await new RPCSocket(8080, 'localhost').connect()
- const sock2 = await new RPCSocket(8080, 'localhost', { path: "test" }).connect()
- const resp = await sock2.Grp2.test()
- expect(resp).to.be.equal("/test")
-
- server.close()
- server2.close()
- sock.close()
- sock2.close()
- })
- })
-
- describe('Serverside Triggers', () => {
- let server, client
- const closerFunction = (done) => () => {
- client.close()
- server.close()
- done()
- }
-
- it('trigger onCallback', (done) => {
- server = makeServer(closerFunction(done))
- client = new RPCSocket(21010, "localhost")
- client.connect().then(_ => {
- client['test'].subscribe(noop).then(_ => client['test'].triggerCallback())
- })
- })
-
- /* testing framework has trouble terminating on this one
- it('trigger connectionHandler', (done) => {
- server = makeServer(undefined, closerFunction(done))
- client = new RPCSocket(21010, "localhost")
- client.connect()
- })
- */
-
- it('trigger hook closeHandler', (done) => {
- server = makeServer(undefined, undefined, closerFunction(done))
- client = new RPCSocket(21010, "localhost")
- client.connect().then(_ => {
- client['test'].subscribe(function cb() {
- cb['destroy']()
- }).then(_ => client['test'].triggerCallback())
- })
- })
-
-
- it('trigger global closeHandler', (done) => {
- server = makeServer(undefined, undefined, undefined, () => {
- server.close()
- done()
- })
- client = new RPCSocket(21010, "localhost")
- client.connect().then(_ => {
- client['test'].subscribe(noop).then(_ => client.close())
- })
- })
- })
-
- describe('RPCSocket', () => {
- let client: RPCSocket
- let server: RPCServer
-
- before(async () => {
- server = makeServer()
-
- client = new RPCSocket(21010, "localhost")
- return await client.connect()
- })
-
- after(() => {
- client.close()
- server.close()
- })
-
-
- it('should have rpc echo', async () => {
- const x = await client['test'].echo("x")
- expect(x).to.be.equal('x')
- })
-
- it('should add up to 6', async () => {
- const sum = await client['test'].add(1, 2, 3)
- expect(sum).to.be.equal(6)
- })
-
- it('should subscribe with success', async () => {
- const res = await client['test'].simpleSubscribe(noop)
- expect(res.topic).to.be.equal('test')
- })
-
- it('subscribe should call back', (done) => {
- client['test'].subscribe((...args: any) => {
- if (args[0] === "test" && args[1] === "callback")
- done()
- else
- done(new Error("Bad callback value " + args))
- }).then(async () => {
- await client['test'].triggerCallback("test", "callback")
- })
- })
-
- it('simpleSubscribe should call back', (done) => {
- client['test'].simpleSubscribe((...args: any) => {
- if (args[0] === "test_" && args[1] === "callback_")
- done()
- else
- done(new Error("Bad callback value " + args))
- }).then(async () => {
- await client['test'].triggerCallback("test_", "callback_")
- })
- })
- })
-
-
- describe('It should do unhook', () => {
- const yesCandy = "OK"
- const noCandy = "stolen"
- let candy = yesCandy
- let cb: Function
- let cb2: Function
- let client: RPCSocket
- let server: RPCServer
-
- before(async () => {
- server = new RPCServer([{
- name: "test",
- RPCs: () => [{
- name: 'subscribe',
- hook: async (callback): Promise<void> => {
- cb = <Function>callback
- return
- }
- },
- {
- name: 'subscribeWithParam',
- hook: async (param, callback): Promise<{ uuid: string }> => {
-
- if (param != "OK") {
- console.log("param was" + param);
- return {
- uuid: "no",
- }
- }
- cb2 = <Function>callback
- return {
- uuid: "OK",
- }
- }
- },
- function publish(): string { cb(candy); return candy },
- function unsubscribe(): string { candy = noCandy; cb(candy); cb = () => { }; return candy }
- ]
- }],
- {
- connectionHandler: noop,
- closeHandler: noop,
- errorHandler: (socket, err) => { throw err }
- })
- server.listen(21010)
- client = new RPCSocket(21010, "localhost")
- return await client.connect()
- })
-
- after(() => {
- client.close()
- server.close()
- })
-
- it('Subscribe with param', async () => {
- const res = await client['test'].subscribeWithParam("OK", noop)
- expect(res.uuid).to.be.equal(candy)
- })
-
- let run = 0
- const expected = [yesCandy, noCandy, noCandy, noCandy]
-
- it('Unhook+unsubscribe should stop callbacks', async () => {
- await client['test'].subscribe(function myCallback(c) {
- if (run == 1)
- (myCallback as any).destroy()
- expect(c).to.equal(expected[run++])
- })
-
- const r1 = await client['test'].publish()
- const r3 = await client['test'].unsubscribe()
- const r2 = await client['test'].publish()
- const r4 = await client['test'].publish()
-
- expect(r1).to.be.equal(yesCandy)
- expect(r2).to.be.equal(noCandy)
- expect(r3).to.be.equal(noCandy)
- expect(r4).to.be.equal(noCandy)
- })
- })
-
- type topicDTO = { topic: string; }
-
- type SesameTestIfc = {
- test: {
- checkCandy: () => Promise<string>
- subscribe: (callback: Callback<[string]>) => Promise<topicDTO>
- manyParams: <A = string, B = number, C = boolean, D = Object>(a: A, b: B, c: C, d: D) => Promise<[A, B, C, D]>
- }
- }
-
- describe('Sesame should unlock the socket', () => {
- let candy = "OK"
- let client: ConnectedSocket<SesameTestIfc>
- let server: RPCServer<SesameTestIfc>
- let cb: Function = (...args) => { }
-
- before((done) => {
- server = new RPCServer<SesameTestIfc>([{
- name: "test",
- RPCs: () => [
- {
- name: 'subscribe',
- hook: async (callback) => {
- cb = callback
- return {
- topic: 'test'
- }
- },
- onDestroy: noop
- },
- async function checkCandy() { cb(candy); cb = noop; return candy },
- async function manyParams(a, b, c, d) { return [a, b, c, d] }
- ],
- }], {
- sesame: (_sesame) => _sesame === 'sesame!'
- })
- server.listen(21004)
- const sock = new RPCSocket<SesameTestIfc>(21004, "localhost")
- sock.connect('sesame!').then(cli => {
- client = cli
- done()
- })
- })
-
- after(() => {
- client.close()
- server.close()
- })
-
- it('should work with sesame', async () => {
- const c = client.test.checkCandy()
- expect(c).to.exist
- })
-
- it('should work with multiple params', async () => {
- const c = await client.test['manyParams']('a', 'b', 'c', 'd')
- expect(c[0]).to.be.equal('a')
- expect(c[1]).to.be.equal('b')
- expect(c[2]).to.be.equal('c')
- expect(c[3]).to.be.equal('d')
- })
-
- it('should not work without sesame', async () => {
- const sock = new RPCSocket(21004, "localhost")
- const cli = await sock.connect()
- expect(cli.test).to.not.exist
- cli.close()
- sock.close()
- })
-
- it('should fail with wrong sesame', async () => {
- const sock = new RPCSocket(21004, "localhost")
- const cli = await sock.connect('iamwrong')
- expect(cli.test).to.not.exist
- cli.close()
- sock.close()
- })
-
- it('callback should work with sesame', (done) => {
- client.test.subscribe(function (c) {
- if (c === candy) {
- done()
- }
- }).then(d => {
- if (d.topic !== 'test')
- done('unexpected invalid response')
-
- client.test.checkCandy()
- })
- })
- })
-
-
- describe('Error handling', () => {
- const errtxt = "BAD BAD BAD"
-
- let createUser = async (user: { a: any, b: any }) => {
- throw new Error(errtxt)
- }
-
- it("RPC throws on client without handler", (done) => {
- let server = new RPCServer([{
- name: "createUser",
- RPCs: () => [{
- name: 'createUser' as 'createUser',
- call: createUser
- }]
- }])
- server.listen(21004)
-
- let sock = new RPCSocket(21004, 'localhost')
- sock.connect().then((cli) => {
- cli["createUser"]["createUser"]({
- a: 'a',
- b: 'b'
- })
- .then(r => {
- if (r != null)
- done(new Error("UNEXPECTED RESULT " + r))
- })
- .catch((e) => {
- if (e.message === errtxt)
- done()
- else
- done(e)
- })
- .finally(() => {
- cli.close()
- sock.close()
- server.close()
- })
- })
- })
-
- it("RPC throws on server with handler", (done) => {
- let server = new RPCServer([{
- name: "createUser",
- RPCs: () => [{
- name: 'createUser' as 'createUser',
- call: createUser
- }]
- }], {
- errorHandler: (socket, e, rpcName, args) => {
- done()
- }
- })
- server.listen(21004)
-
- let sock = new RPCSocket(21004, 'localhost')
- sock.connect().then((cli) => {
- cli["createUser"]["createUser"]({
- a: 'a',
- b: 'b'
- })
- .then(r => {
- if (r != null)
- done("UNEXPECTED RESULT " + r)
- })
- .catch((e) => {
- done("UNEXPECTED CLIENT ERROR " + e)
- done(e)
- })
- .finally(() => {
- cli.close()
- sock.close()
- server.close()
- })
- })
- })
- })
-
-
- describe("Errorhandler functionality", () => {
- const errtxt = "BAD BAD BAD"
-
- let createUser = async (user: { a: any, b: any }) => {
- throw new Error(errtxt)
- }
-
- it("correct values are passed to the handler", (done) => {
- let server = new RPCServer([{
- name: "createUser",
- RPCs: () => [{
- name: 'createUser' as 'createUser',
- call: createUser
- }]
- }], {
- errorHandler: (socket, e, rpcName, args) => {
- if (e.message === errtxt && rpcName === "createUser" && args[0]['a'] === 'a' && args[0]['b'] === 'b')
- done()
- }
- })
- server.listen(21004)
-
- let sock = new RPCSocket(21004, 'localhost')
- sock.connect().then((cli) => {
- cli["createUser"]["createUser"]({
- a: 'a',
- b: 'b'
- })
- .then(r => {
- if (r != null)
- done(new Error("UNEXPECTED RESULT " + r))
- })
- .catch((e) => {
- done(new Error("UNEXPECTED CLIENT ERROR " + e.message))
- })
- .finally(() => {
- cli.close()
- sock.close()
- server.close()
- })
- })
- })
-
- it("handler sees sesame", (done) => {
- let sesame = "AAAAAAAAAAAAAAA"
- let server = new RPCServer([{
- name: "createUser" as "createUser",
- RPCs: () => [{
- name: 'createUser' as 'createUser',
- call: createUser
- }]
- }], {
- sesame: sesame,
- errorHandler: (socket, e, rpcName, args) => {
- if (e.message === errtxt && rpcName === "createUser" && args[0] === sesame && args[1]['a'] === 'a' && args[1]['b'] === 'b')
- done()
- }
-
- })
- server.listen(21004)
-
- let sock = new RPCSocket(21004, 'localhost')
- sock.connect(sesame).then((cli) => {
- cli["createUser"]["createUser"]({
- a: 'a',
- b: 'b'
- })
- .then(r => {
- if (r != null)
- done(new Error("UNEXPECTED RESULT " + r))
- })
- .catch((e) => {
- done(new Error("UNEXPECTED CLIENT ERROR " + e))
- })
- .finally(() => {
- cli.close()
- sock.close()
- server.close()
- })
- })
- })
- })
-
- type myExporterIfc = {
- MyExporter: {
- myRPC: () => Promise<string>
- }
- }
-
- describe("Class binding", () => {
-
- let exporter1: MyExporter
- let serv: RPCServer<myExporterIfc>
- let sock: RPCSocket & myExporterIfc
- let allowed = true
- const SESAME = 'xyz'
-
- class MyExporter implements RPCExporter<myExporterIfc>{
- name = "MyExporter" as "MyExporter"
- RPCs = () => [
- this.myRPC
- ]
-
- myRPC = async () => {
- //serv.setExporters([new MyOtherExporter])
- return "Hello World"
- }
- }
-
- class MyOtherExporter implements RPCExporter<myExporterIfc>{
- name = "MyExporter" as "MyExporter"
- RPCs = () => [
- this.myRPC
- ]
-
- myRPC = async () => {
- return "Hello Borld"
- }
-
- }
-
- before(done => {
- exporter1 = new MyExporter()
- serv = new RPCServer<myExporterIfc>(
- [exporter1],
- {
- accessFilter: async (sesame, exporter) => {
- if (exporter.name === 'MyExporter') {
- if (!allowed) return false
- allowed = false
- return sesame === SESAME;
- } else {
- return false
- }
- },
- sesame: SESAME
- })
- serv.listen(21004)
- done()
- })
-
- beforeEach((done) => {
- const s = new RPCSocket<myExporterIfc>(21004, 'localhost')
- s.connect(SESAME).then(conn => {
- sock = conn
- done()
- })
- })
-
- afterEach((done) => {
- sock.close()
- done()
- })
-
- after(() => {
- serv.close()
- })
-
- it("use sesameFilter for available", (done) => {
- if (sock['MyExporter']) {
- allowed = false
- done()
- }
- else done(new Error("RPC supposed to be here"))
- })
-
- it("use sesameFilter", (done) => {
- if (!sock['MyExporter']) done()
- else done(new Error("RPC supposed to be gone"))
- })
- })
-
- /*
- describe('finally', () => {
- it('print open handles (Ignore `DNSCHANNEL` and `Immediate`)', () => {
- //log(console)
- })
- })
- */
-
-
- describe("attaching handlers before connecting", () => {
- it("fires error if server is unreachable", (done) => {
- const sock = new RPCSocket<myExporterIfc>(21004, 'localhost')
- let errorHandleCount = 0
-
- sock.on('error', (err) => {
- //attached listener fires first
- if (errorHandleCount != 0) {
- console.log("Error handler didn't fire first");
- } else {
- errorHandleCount++
- }
- })
-
- sock.connect().then(_ => {
- console.log("Unexpected successful connect")
- }).catch(e => {
- //catch clause fires second
- if (errorHandleCount != 1) {
- console.log("catch clause didn't fire second", errorHandleCount);
- } else {
- sock.close()
- done()
- }
- })
- })
-
- it("fires error if call is unknown", (done) => {
- const serv = new RPCServer().listen(21004)
- const sock = new RPCSocket(21004, 'localhost')
-
- sock.on('error', (err) => {
- sock.close()
- serv.close()
- done()
- })
-
- sock.connect().then(_ => {
- sock.call("unknownRPC123", "AAAAA").catch(e => { }).then(x => {
- console.log("X", x);
-
- })
- }).catch(e => {
- console.log("unexpected connect catch clause");
- done(e)
- })
- })
- })
-
- describe("class (de-)serialization", () => {
-
- @Serializable()
- class SubClass {
- fString = "F"
- }
-
- @Serializable()
- class TestClass {
- aString = "A"
- aNumber = 46
- aObject = {
- x: "x",
- y: undefined,
- sub: new SubClass()
- }
- aClassObject = new SubClass()
-
- public returnOK() {
- return "OK"
- }
- }
-
- const verifyObject = (obj: any) => {
- expect(obj).to.be.an.instanceOf(TestClass)
- expect(obj.aString).to.be.a('string')
- expect(obj.aNumber).to.be.a('number')
- expect(obj.aObject).to.be.a('object')
- expect(obj.aObject.x).to.be.a('string')
- expect(obj.aObject.y).to.be.undefined
- expect(obj.aObject.sub).to.be.an.instanceOf(SubClass)
- expect(obj.aClassObject).to.be.an.instanceOf(SubClass)
- expect(obj).to.not.have.key(CLASSNAME_ATTRIBUTE)
- expect(obj.aObject.sub).to.not.have.key(CLASSNAME_ATTRIBUTE)
- expect(obj.aClassObject).to.not.have.key(CLASSNAME_ATTRIBUTE)
- expect(obj.returnOK()).to.be.equal('OK')
- }
-
- describe("Responses", () => {
- type TestIfc = {
- Test: {
- returnClass: () => Promise<TestClass>
- classCallback: (callback: Callback<[TestClass]>) => Promise<TestClass>
- }
- }
-
- let myServer: RPCServer<TestIfc>;
- let mySocket: ConnectedSocket<TestIfc>;
-
- before(function (done) {
- myServer = new RPCServer<TestIfc>([{
- name: "Test",
- RPCs: [
- async function returnClass() {
- return new TestClass()
- }, {
- name: "classCallback",
- hook: async function (callback) {
- setTimeout(_ => callback(new TestClass()), 250)
- return new TestClass()
- }
- }
- ]
- }])
- myServer.listen(8084)
-
- new RPCSocket<TestIfc>(8084, 'localhost').connect().then(connsock => {
- mySocket = connsock
- done()
- })
- })
-
- after(function (done) {
- mySocket.close()
- myServer.close()
- done()
- })
-
-
- it("receives class object in call response", async () => {
- const obj: TestClass = await mySocket['Test'].returnClass()
- verifyObject(obj)
- })
-
- it("receives class object in hook response", async function () {
- const obj: TestClass = await mySocket.Test.classCallback(noop)
- verifyObject(obj)
- })
-
- it("receives class object in callback", function (done) {
- mySocket.Test.classCallback(function (cbValue) {
- verifyObject(cbValue)
- done()
- }).then(verifyObject)
- })
- })
- describe("Parameters", () => {
- it("Class object in call", function(done){
- const server = new RPCServer([
- {
- name: "Test",
- RPCs: [
- function callWithClass(testObj: TestClass){
- verifyObject(testObj)
- done()
- }
- ]
- }
- ]).listen(8086)
-
- new RPCSocket(8086, 'localhost').connect().then(sock => {
- sock['Test'].callWithClass(new TestClass()).then(_ => {
- sock.close()
- server.close()
- })
- })
- })
- })
- })
|