You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. import { describe, it } from "mocha";
  2. import { RPCServer } from '../src/Backend'
  3. import * as uuidv4 from "uuid/v4"
  4. import { RPCSocket } from "../src/Frontend";
  5. import { SubscriptionResponse } from "../src/Types";
  6. import { makeSubResponse } from "../src/Utils";
  7. const add = (...args:number[]) => {return args.reduce((a,b)=>a+b, 0)}
  8. function makeServer(){
  9. let subcallback
  10. return new RPCServer<{ topic: string }>(20000, [{
  11. name: "test",
  12. exportRPCs: () => [
  13. {
  14. name: 'echo',
  15. call: async (s:string) => s,
  16. },{
  17. name: 'simpleSubscribe',
  18. hook: async(callback) => {
  19. subcallback = callback
  20. return makeSubResponse<{topic: string}>({topic: "test"})
  21. }
  22. },{
  23. name: 'subscribe',
  24. hook: async (callback) => {
  25. subcallback = callback
  26. return makeSubResponse<{topic: string}>({topic: "test"})
  27. },
  28. onClose: (res, rpc) => {
  29. console.log("onClose", rpc.name === 'subscribe' && res?"OK":"")
  30. subcallback = null
  31. },
  32. onCallback: (...args:any) => {
  33. console.log("onCallback", args[0] === "test" && args[1] === "callback"?"OK":"")
  34. }
  35. },
  36. add,
  37. function triggerCallback(...messages:any[]):number {return subcallback.apply({}, messages)},
  38. ]
  39. }],{
  40. connectionHandler: (socket) => { console.log("connectionHandler OK") },
  41. closeHandler: (socket) => { console.log("closeHandler OK") },
  42. errorHandler: (socket, err) => { console.error("errorHandler OK SO YOU SHOULDN'T SEE THIS"); throw err }
  43. })
  44. }
  45. describe('RPCServer', () => {
  46. let server: RPCServer<{ topic: string }, any>
  47. before((done) => {
  48. server = makeServer()
  49. done()
  50. })
  51. after(async() => {
  52. await server.destroy()
  53. })
  54. it('should be able to use all kinds of RPC definitions', (done) => {
  55. const echo = (x) => x
  56. const server = new RPCServer(20003, [{
  57. name: 'HelloWorldRPCGroup',
  58. exportRPCs: () => [
  59. echo, //named function variable
  60. function echof(x){ return x }, //named function
  61. {
  62. name: 'echoExplicit', //describing object
  63. call: async (x) => x
  64. }
  65. ]
  66. }])
  67. const client = new RPCSocket(20003, 'localhost')
  68. client.connect().then(async () => {
  69. const r0 = await client['HelloWorldRPCGroup'].echo('Hello')
  70. const r1 = await client['HelloWorldRPCGroup'].echof('World')
  71. const r2 = await client['HelloWorldRPCGroup'].echoExplicit('RPC!')
  72. if(r0 === 'Hello' && r1 === 'World' && r2 ==='RPC!'){
  73. client.destroy()
  74. server.destroy()
  75. done()
  76. }
  77. })
  78. })
  79. it('new RPCServer() should fail on bad RPC', (done) => {
  80. try{
  81. new RPCServer(20001, [{
  82. name: "bad",
  83. exportRPCs: () => [
  84. (aaa,bbb,ccc) => { return aaa+bbb+ccc }
  85. ]
  86. }])
  87. done(new Error("Didn't fail with bad RPC"))
  88. }catch(badRPCError){
  89. done()
  90. }
  91. })
  92. })
  93. describe('RPCSocket', () => {
  94. let client: RPCSocket
  95. let server: RPCServer<{topic: string}>
  96. before(async() => {
  97. server = makeServer()
  98. client = new RPCSocket(20000, "localhost")
  99. return await client.connect()
  100. })
  101. after(() => {
  102. client.destroy()
  103. server.destroy()
  104. })
  105. it('should have rpc echo', (done) => {
  106. client['test'].echo("x").then(x => {
  107. if(x === 'x')
  108. done()
  109. else
  110. done(new Error('echo RPC response did not match'))
  111. })
  112. })
  113. it('should add up to 6', (done) => {
  114. client['test'].add(1,2,3).then(x => {
  115. if(x === 6)
  116. done()
  117. else
  118. done(new Error('add RPC response did not match'))
  119. })
  120. })
  121. it('should subscribe with success', (done) => {
  122. client['test'].simpleSubscribe(console.log).then(res => {
  123. if(res.result === 'Success'){
  124. done()
  125. }else{
  126. console.error(res)
  127. done(new Error('Subscribe did not return success'))
  128. }
  129. })
  130. })
  131. it('subscribe should call back', (done) => {
  132. client['test'].subscribe((...args: any) => {
  133. if(args[0] === "test" && args[1] === "callback")
  134. done()
  135. else
  136. done(new Error("Bad callback value "+ args))
  137. }).then( async () => {
  138. await client['test'].triggerCallback("test", "callback")
  139. })
  140. })
  141. it('simpleSubscribe should call back', (done) => {
  142. client['test'].simpleSubscribe((...args: any) => {
  143. if(args[0] === "test_" && args[1] === "callback_")
  144. done()
  145. else
  146. done(new Error("Bad callback value "+ args))
  147. }).then( async () => {
  148. await client['test'].triggerCallback("test_", "callback_")
  149. })
  150. })
  151. })
  152. describe('It should do unhook', () => {
  153. let candy = "OK"
  154. let cb: Function
  155. let client: RPCSocket
  156. let server: RPCServer<{topic: string}>
  157. before(async() => {
  158. server = new RPCServer<{ topic: string }>(20000, [{
  159. name: "test",
  160. exportRPCs: () => [{
  161. name: 'subscribe',
  162. hook: async(callback):Promise<SubscriptionResponse<{topic:string}>> => {
  163. cb = <Function> callback
  164. return {
  165. result: "Success",
  166. uuid: uuidv4(),
  167. topic: "test"
  168. }
  169. }
  170. },
  171. function checkCandy():string { cb(candy); return candy },
  172. function stealCandy():string { candy = "_OK"; cb(candy); cb = (...any) => console.log.apply(console,["Server:", ...any]); return candy }
  173. ]
  174. }],{
  175. connectionHandler: (socket) => { console.log("connectionHandler OK") },
  176. closeHandler: (socket) => { console.log("closeHandler OK") },
  177. errorHandler: (socket, err) => { console.error("errorHandler OK SO YOU SHOULDN'T SEE THIS"); throw err }
  178. })
  179. client = new RPCSocket(20000, "localhost")
  180. return await client.connect()
  181. })
  182. after(() => {
  183. client.destroy()
  184. server.destroy()
  185. })
  186. it('Unhook+unsubscribe should stop callbacks', (done) => {
  187. client['test'].subscribe(c => console.log("Client: "+c)).then( async (res: SubscriptionResponse) => {
  188. const r1 = await client['test'].checkCandy()
  189. const r3 = await client['test'].stealCandy()
  190. client.unhook(res.uuid)
  191. console.log("---- No client output below this line")
  192. const r2 = await client['test'].checkCandy()
  193. const r4 = await client['test'].checkCandy()
  194. console.log("---- More output below")
  195. if(r1 === "OK" && r3 === "_OK" && r2 === "_OK" && r4 === "_OK")
  196. done()
  197. else
  198. done(new Error("Results did not match: "+[r1,r2,r3,r4]))
  199. })
  200. })
  201. })