qrpc
Version:
very fast nodejs remote procedure call
209 lines (186 loc) • 7.1 kB
JavaScript
/**
* quick little rpc package
*
* Copyright (C) 2015-2017 Andras Radics
* Licensed under the Apache License, Version 2.0
*/
var QrpcServer = require('../lib/qrpc-server.js')
module.exports ={
'beforeEach': function(done) {
this.server = new QrpcServer()
this.socket = new MockSocket()
done()
},
'listen method': {
'error handling': {
'should throw error without listenFunc if no callback': function(t) {
try { this.server.listen(); t.fail() }
catch (e) { t.ok(true) }
t.done()
},
'should return error without listenFunc with callback': function(t) {
t.expect(1)
this.server.listen(null, function(err) {
t.assert(err instanceof Error)
t.done()
})
},
'should return error if already listening': function(t) {
this.server.setListenFunc(function(port, cb){ return cb() })
t.expect(2)
var self = this
this.server.listen(0, function(err) {
t.ifError(err)
self.server.listen(0, function(err) {
t.assert(err instanceof Error)
t.done()
})
})
},
'should return error if no handler defined': function(t) {
var call = { v: 1, id: 1, n: 'nonesuch' }
var written = null
var source = { read: function(){ return written ? null : JSON.stringify(call) + "\n" } }
var writable = { write: function(s, cb) { written = s; cb && cb() } }
this.server.setSource(source, writable)
var self = this
setTimeout(function() {
t.assert(written)
t.assert(JSON.parse(written).e.message.indexOf('no handler') > 0)
self.server.setCloseFunc(function(){})
self.server.close()
t.done()
}, 5)
},
},
'should call listenFunc': function(t) {
var called = false
var listenFunc = function(port, cb) { called = true; cb() }
this.server.setListenFunc(listenFunc)
this.server.listen(0, function(err) {
t.equal(called, true)
t.done()
})
},
},
'close method': {
'should return error without closeFunc': function(t) {
this.server.close(function(err) {
t.assert(err instanceof Error)
t.done()
})
},
'should call server.close if listening': function(t) {
var closed = false
var closeFunc = function(cb) { closed = true }
var listenFunc = function(port, cb) { cb() }
var server = this.server
server.setListenFunc(listenFunc)
server.setCloseFunc(closeFunc)
server.listen(0, function(err) {
server.close();
t.equal(closed, true)
t.done()
})
},
},
'addHandler method': {
'should accept name and function': function(t) {
t.equal(this.server.handlers['test1'], undefined)
var fn = function(){}
this.server.addHandler('test1', fn)
t.equal(this.server.handlers['test1'], fn)
t.done()
},
'should throw error if not a function': function(t) {
try { this.server.addHandler('test', 1); t.fail() }
catch (err) { t.ok(true) }
t.done()
},
'should consume newline terminated JSON messages': function(t) {
t.expect(1)
this.server.addHandler('test', function(req, res, next) {
t.deepEqual(req.m, {a:1, b:2})
t.done()
})
var msg = JSON.stringify({v: 1, id: 1, n: 'test', m: {a:1, b:2}}) + "\n"
this.server.onData('', msg)
},
},
'addHandlerNoResponse method': {
'should accept name and function': function(t) {
t.equal(this.server.handlers['test1'], undefined)
var fn = function(){}
this.server.addHandler('test1', fn)
t.equal(this.server.handlers['test1'], fn)
t.done()
},
'should throw error if not a function': function(t) {
try { this.server.addHandler('test', 1); t.fail() }
catch (err) { t.ok(true) }
t.done()
},
'should consume newline terminated JSON messages': function(t) {
t.expect(1)
this.server.addHandler('test', function(req, res, next) {
t.deepEqual(req.m, {a:1, b:2})
t.done()
})
var msg = JSON.stringify({v: 1, id: 1, n: 'test', m: {a:1, b:2}}) + "\n"
this.server.onData('', msg)
},
},
'wrap method': {
'should add handlers': function(t) {
this.server.wrap({test: function(){}})
t.equal(typeof this.server.handlers['test'], 'function')
t.done()
},
'should prefix handler names': function(t) {
this.server.wrap({test: function(){}}, {prefix: 'xy_'})
t.equal(typeof this.server.handlers['xy_test'], 'function')
t.done()
},
'should pass all call args to handler and return all response args to caller': function(t) {
var args = null, reply = []
this.server.wrap({
test: function() {
args = arguments
arguments[arguments.length - 1](new Error("testErr"), 4, 5, 'six')
}
})
var msg = JSON.stringify({ v: 1, id: 1, n: 'test', m: [1, 2, 'three']}) + "\n"
this.server.onData('', msg, {write: function(m){ reply.push(m) }})
setTimeout(function() {
t.equal(typeof args[3], 'function')
t.equal(args[0], 1)
t.equal(args[1], 2)
t.equal(args[2], 'three')
var msg = JSON.parse(reply[0])
t.equal(msg.m[0].message, "testErr")
t.equal(msg.m[1], 4)
t.equal(msg.m[2], 5)
t.equal(msg.m[3], 'six')
t.done()
}, 5)
},
},
}
var util = require('util')
var EventEmitter = require('events').EventEmitter
function MockSocket( ) {
EventEmitter.call(this)
var self = this
this._written = []
this.write = function(s) { self._written.push(s) }
this.pause = function() { }
this.resume = function() { }
return this
}
util.inherits(MockSocket, EventEmitter)
function createReplyChunk( written, reply, error ) {
var msg = JSON.parse(written)
var data = { v: 1, id: msg.id, m: reply, e: error }
return JSON.stringify(data) + "\n"
}