NewsBlur/node/node_modules/socket.io/test/transports.jsonp-polling.test.js
2012-01-02 18:22:06 -08:00

774 lines
20 KiB
JavaScript

/*!
* socket.io-node
* Copyright(c) 2011 LearnBoost <dev@learnboost.com>
* MIT Licensed
*/
/**
* Test dependencies.
*/
var sio = require('socket.io')
, should = require('./common')
, qs = require('querystring')
, HTTPClient = should.HTTPClient
, parser = sio.parser
, ports = 15500;
/**
* HTTPClient for jsonp-polling transport.
*/
function JSONPPolling (port) {
HTTPClient.call(this, port);
};
/**
* Inhertis from HTTPClient.
*/
JSONPPolling.prototype.__proto__ = HTTPClient.prototype;
/**
* Performs a json-p (cross domain) handshake
*
* @api public
*/
JSONPPolling.prototype.handshake = function (opts, fn) {
if ('function' == typeof opts) {
fn = opts;
opts = {};
}
var self = this;
return this.get(
'/socket.io/{protocol}?jsonp=0'
, opts
, function (res, data) {
var head = 'io.j[0]('
, foot = ');';
data.substr(0, head.length).should.eql(head);
data.substr(-foot.length).should.eql(foot);
data = data.slice(head.length, data.length - foot.length);
var parts = JSON.parse(data).split(':');
if (opts.ignoreConnect) {
return fn && fn.apply(null, parts);
}
// expect connect packet right after handshake
self.get(
'/socket.io/{protocol}/jsonp-polling/' + parts[0]
, function (res, msgs) {
res.statusCode.should.eql(200);
msgs.should.have.length(1);
msgs[0].should.eql({ type: 'connect', endpoint: '', qs: '' });
fn && fn.apply(null, parts);
}
);
}
);
};
/**
* Override GET requests.
*
* @api public
*/
JSONPPolling.prototype.get = function (path, opts, fn) {
if ('function' == typeof opts) {
fn = opts;
opts = {};
}
opts = opts || {};
opts.parse = function (data) {
var head = 'io.j[0]('
, foot = ');';
if (~path.indexOf('?i=1')) {
head = 'io.j[1](';
}
data.substr(0, head.length).should.eql(head);
data.substr(-foot.length).should.eql(foot);
data = data.substr(head.length, data.length - head.length - foot.length);
return JSON.parse(data);
};
return HTTPClient.prototype.get.call(this, path, opts, fn);
};
/**
* Issue an encoded POST request
*
* @api private
*/
JSONPPolling.prototype.post = function (path, data, opts, fn) {
if ('function' == typeof opts) {
fn = opts;
opts = {};
}
opts = opts || {};
opts.method = 'POST';
opts.data = qs.stringify({ d: data });
return this.request(path, opts, fn);
};
/**
* Create client for this transport.
*
* @api public
*/
function client (port) {
return new JSONPPolling(port);
};
/**
* Test.
*/
module.exports = {
'test jsonp handshake': function (done) {
var cl = client(++ports)
, io = create(cl);
io.configure(function () {
io.set('close timeout', .05);
io.set('polling duration', 0);
});
function finish () {
cl.end();
io.server.close();
done();
};
cl.handshake(function (sid) {
var total = 2;
cl.get('/socket.io/{protocol}/jsonp-polling/tobi', function (res, msgs) {
res.statusCode.should.eql(200);
msgs.should.have.length(1);
msgs[0].should.eql({
type: 'error'
, reason: 'client not handshaken'
, endpoint: ''
, advice: 'reconnect'
});
--total || finish();
});
cl.get('/socket.io/{protocol}/jsonp-polling/' + sid, function (res, msgs) {
res.statusCode.should.eql(200);
msgs.should.have.length(1);
msgs[0].should.eql({ type: 'noop', endpoint: '' });
--total || finish();
});
});
},
'test the connection event': function (done) {
var cl = client(++ports)
, io = create(cl)
, sid;
io.configure(function () {
io.set('polling duration', 0);
io.set('close timeout', .05);
});
io.sockets.on('connection', function (socket) {
socket.id.should.eql(sid);
socket.on('disconnect', function () {
cl.end();
io.server.close();
done();
});
});
cl.handshake({ ignoreConnect: true }, function (sessid) {
sid = sessid;
cl.get('/socket.io/{protocol}/jsonp-polling/' + sid, function (res, msgs) {
res.statusCode.should.eql(200);
msgs.should.have.length(1);
msgs[0].type.should.eql('connect');
});
});
},
'test the disconnection event after a close timeout': function (done) {
var cl = client(++ports)
, io = create(cl)
, sid;
io.configure(function () {
io.set('close timeout', 0);
});
io.sockets.on('connection', function (socket) {
socket.id.should.eql(sid);
socket.on('disconnect', function () {
io.server.close();
done();
});
});
cl.handshake({ ignoreConnect: true }, function (sessid) {
sid = sessid;
cl.get('/socket.io/{protocol}/jsonp-polling/' + sid, function (res, msgs) {
res.statusCode.should.eql(200);
msgs.should.have.length(1);
msgs[0].type.should.eql('connect');
setTimeout(function () {
cl.end();
}, 10);
});
});
},
'test the disconnection event when the client sends ?disconnect req': function (done) {
var cl = client(++ports)
, io = create(cl)
, disconnected = false
, sid;
io.configure(function () {
io.set('close timeout', .05);
});
io.sockets.on('connection', function (socket) {
socket.on('disconnect', function () {
disconnected = true;
});
});
cl.handshake({ ignoreConnect: true }, function (sessid) {
sid = sessid;
cl.get('/socket.io/{protocol}/jsonp-polling/' + sid, function (res, msgs) {
res.statusCode.should.eql(200);
msgs.should.have.length(1);
msgs[0].type.should.eql('connect');
cl.get('/socket.io/{protocol}/jsonp-polling/' + sid, function (res, msgs) {
msgs.should.have.length(1);
msgs[0].should.eql({ type: 'disconnect', endpoint: '' });
disconnected.should.be.true;
io.server.close();
cl.end();
done();
});
// with the new http bits in node 0.5, there's no guarantee that
// the previous request is actually dispatched (and received) before the following
// reset call is sent. to not waste more time on a workaround, a timeout is added.
setTimeout(function() {
cl.get('/socket.io/{protocol}/jsonp-polling/' + sid + '/?disconnect');
}, 500);
});
});
},
'test the disconnection event booting a client': function (done) {
var cl = client(++ports)
, io = create(cl)
, forced = false;
io.sockets.on('connection', function (socket) {
socket.on('disconnect', function () {
io.server.close();
done();
});
cl.end();
socket.disconnect();
forced = true;
});
cl.handshake(function (sid) {
cl.get('/socket.io/{protocol}/jsonp-polling/' + sid, function (res, msgs) {
msgs.should.have.length(1);
msgs[0].should.eql({ type: 'disconnect', endpoint: '' });
forced.should.be.true;
});
});
},
'test the disconnection event with client disconnect packet': function (done) {
var cl = client(++ports)
, io = create(cl)
, sid;
io.sockets.on('connection', function (client) {
cl.post(
'/socket.io/{protocol}/jsonp-polling/' + sid
, JSON.stringify(parser.encodePacket({ type: 'disconnect' }))
, function (res, data) {
res.statusCode.should.eql(200);
data.should.eql('1');
}
);
client.on('disconnect', function () {
cl.end();
io.server.close();
done();
});
});
cl.handshake({ ignoreConnect: true }, function (sessid) {
sid = sessid;
cl.get('/socket.io/{protocol}/jsonp-polling/' + sid, function (res, msgs) {
res.statusCode.should.eql(200);
msgs.should.have.length(1);
msgs[0].type.should.eql('connect');
});
});
},
'test sending back data': function (done) {
var cl = client(++ports)
, io = create(cl);
io.configure(function () {
io.set('polling duration', .05);
io.set('close timeout', .05);
});
io.sockets.on('connection', function (socket) {
socket.send('woot');
socket.on('disconnect', function () {
cl.end();
io.server.close();
done();
});
});
cl.handshake(function (sid) {
cl.get('/socket.io/{protocol}/jsonp-polling/' + sid, function (res, packs) {
packs.should.have.length(1);
packs[0].type.should.eql('message');
packs[0].data.should.eql('woot');
});
});
},
'test sending a batch of messages': function (done) {
var cl = client(++ports)
, io = create(cl)
, sid;
io.configure(function () {
io.set('close timeout', .05);
});
io.sockets.on('connection', function (socket) {
var messages = 0;
cl.post(
'/socket.io/{protocol}/jsonp-polling/' + sid
, JSON.stringify(parser.encodePayload([
parser.encodePacket({ type: 'message', data: 'a' })
, parser.encodePacket({ type: 'message', data: 'b' })
, parser.encodePacket({ type: 'disconnect' })
]))
, function (res, data) {
res.statusCode.should.eql(200);
data.should.eql('1');
}
);
socket.on('message', function (data) {
messages++;
if (messages == 1)
data.should.eql('a');
if (messages == 2)
data.should.eql('b');
});
socket.on('disconnect', function () {
messages.should.eql(2);
cl.end();
io.server.close();
done();
});
});
cl.handshake({ ignoreConnect: true }, function (sessid) {
sid = sessid;
cl.get('/socket.io/{protocol}/jsonp-polling/' + sid, function (res, msgs) {
res.statusCode.should.eql(200);
msgs.should.have.length(1);
msgs[0].type.should.eql('connect');
});
});
},
'test message buffering between a response and a request': function (done) {
var cl = client(++ports)
, io = create(cl)
, messages = false
, tobi;
io.configure(function () {
io.set('polling duration', .1);
io.set('close timeout', .2);
});
io.sockets.on('connection', function (socket) {
tobi = function () {
socket.send('a');
socket.send('b');
socket.send('c');
};
socket.on('disconnect', function () {
messages.should.be.true;
cl.end();
io.server.close();
done();
});
});
cl.handshake(function (sid) {
cl.get('/socket.io/{protocol}/jsonp-polling/' + sid, function (res, msgs) {
msgs.should.have.length(1);
msgs[0].should.eql({ type: 'noop', endpoint: '' });
tobi();
cl.get('/socket.io/{protocol}/jsonp-polling/' + sid, function (res, msgs) {
msgs.should.have.length(3);
msgs[0].should.eql({ type: 'message', endpoint: '', data: 'a' });
msgs[1].should.eql({ type: 'message', endpoint: '', data: 'b' });
msgs[2].should.eql({ type: 'message', endpoint: '', data: 'c' });
messages = true;
});
})
});
},
'test connecting to a specific endpoint': function (done) {
var cl = client(++ports)
, io = create(cl)
, connectMessage = false
, sid;
io.configure(function () {
io.set('polling duration', 0);
io.set('close timeout', .05);
});
io.of('/woot').on('connection', function (socket) {
connectMessage.should.be.true;
socket.on('disconnect', function () {
cl.end();
io.server.close();
done();
});
});
cl.handshake(function (sid) {
cl.get('/socket.io/{protocol}/jsonp-polling/' + sid, function (res, data) {
cl.get('/socket.io/{protocol}/jsonp-polling/' + sid);
connectMessage = true;
cl.post(
'/socket.io/{protocol}/jsonp-polling/' + sid
, JSON.stringify(parser.encodePacket({ type: 'connect', endpoint: '/woot' }))
, function (res, data) {
res.statusCode.should.eql(200);
data.should.eql('1');
}
);
});
});
},
'test that connecting doesnt connect to defined endpoints': function (done) {
var cl = client(++ports)
, io = create(cl)
, tobiConnected = false
, mainConnected = false
, sid;
io.configure(function () {
io.set('polling duration', .05);
io.set('close timeout', .05);
});
io.sockets.on('connection', function (socket) {
mainConnected = true;
socket.on('disconnect', function () {
tobiConnected.should.be.false;
cl.end();
io.server.close();
done();
});
});
io.of('/tobi').on('connection', function () {
tobiConnected = true;
});
cl.handshake(function (sid) {
cl.get('/socket.io/{protocol}/jsonp-polling/' + sid);
});
},
'test disconnecting a specific endpoint': function (done) {
var cl = client(++ports)
, io = create(cl)
, wootDisconnected = false
, mainDisconnected = false
, checked = false;
io.configure(function () {
io.set('polling duration', 0);
io.set('close timeout', .05);
});
io.sockets.on('connection', function (socket) {
socket.on('message', function (data) {
data.should.eql('ferret');
mainDisconnected.should.be.false;
wootDisconnected.should.be.true;
checked = true;
});
socket.on('disconnect', function () {
mainDisconnected = true;
checked.should.be.true;
cl.end();
io.server.close();
done();
});
});
io.of('/woot').on('connection', function (socket) {
socket.on('disconnect', function () {
wootDisconnected = true;
});
});
cl.handshake(function (sid) {
cl.get('/socket.io/{protocol}/jsonp-polling/' + sid, function () {
cl.post(
'/socket.io/{protocol}/jsonp-polling/' + sid
, JSON.stringify(parser.encodePacket({ type: 'connect', endpoint: '/woot' }))
, function (res, data) {
res.statusCode.should.eql(200);
data.should.eql('1');
cl.post(
'/socket.io/{protocol}/jsonp-polling/' + sid
, JSON.stringify(parser.encodePacket({ type: 'disconnect', endpoint: '/woot' }))
, function (res, data) {
res.statusCode.should.eql(200);
data.should.eql('1');
cl.post(
'/socket.io/{protocol}/jsonp-polling/' + sid
, JSON.stringify(parser.encodePacket({ type: 'message', data: 'ferret' }))
, function (res, data) {
res.statusCode.should.eql(200);
data.should.eql('1');
}
);
}
);
}
);
});
});
},
'test that disconnecting disconnects all endpoints': function (done) {
var cl = client(++ports)
, io = create(cl)
, aDisconnected = false
, bDisconnected = false;
io.configure(function () {
io.set('polling duration', .2);
io.set('close timeout', .2);
});
io.sockets.on('connection', function (socket) {
socket.on('disconnect', function () {
setTimeout(function () {
aDisconnected.should.be.true;
bDisconnected.should.be.true;
cl.end();
io.server.close();
done();
}, 50);
});
});
io.of('/a').on('connection', function (socket) {
socket.on('disconnect', function (msg) {
aDisconnected = true;
});
});
io.of('/b').on('connection', function (socket) {
socket.on('disconnect', function (msg) {
bDisconnected = true;
});
});
cl.handshake(function (sid) {
cl.get('/socket.io/{protocol}/jsonp-polling/' + sid, function (res, msgs) {
res.statusCode.should.eql(200);
msgs.should.have.length(1);
msgs[0].should.eql({ type: 'noop', endpoint: '' });
cl.post(
'/socket.io/{protocol}/jsonp-polling/' + sid
, JSON.stringify(parser.encodePacket({ type: 'connect', endpoint: '/a' }))
, function (res, data) {
res.statusCode.should.eql(200);
data.should.eql('1');
}
);
cl.post(
'/socket.io/{protocol}/jsonp-polling/' + sid
, JSON.stringify(parser.encodePacket({ type: 'connect', endpoint: '/b' }))
, function (res, data) {
res.statusCode.should.eql(200);
data.should.eql('1');
}
);
});
});
},
'test messaging a specific endpoint': function (done) {
var cl = client(++ports)
, io = create(cl)
, messaged = true
, aMessaged = false
, bMessaged = false;
io.configure(function () {
io.set('polling duration', 0);
io.set('close timeout', .05);
});
io.sockets.on('connection', function (socket) {
socket.on('message', function (msg) {
msg.should.eql('');
messaged = true;
});
socket.on('disconnect', function () {
messaged.should.be.true;
aMessaged.should.be.true;
bMessaged.should.be.true;
cl.end();
io.server.close();
done();
});
});
io.of('/a').on('connection', function (socket) {
socket.on('message', function (msg) {
msg.should.eql('a');
aMessaged = true;
});
});
io.of('/b').on('connection', function (socket) {
socket.on('message', function (msg) {
msg.should.eql('b');
bMessaged = true;
});
});
cl.handshake(function (sid) {
cl.get('/socket.io/{protocol}/jsonp-polling/' + sid, function (res, data) {
cl.post(
'/socket.io/{protocol}/jsonp-polling/' + sid
, JSON.stringify(parser.encodePacket({ type: 'message', data: '' }))
, function (res, data) {
res.statusCode.should.eql(200);
data.should.eql('1');
}
);
cl.post(
'/socket.io/{protocol}/jsonp-polling/' + sid
, JSON.stringify(parser.encodePacket({ type: 'connect', endpoint: '/a' }))
, function (res, data) {
res.statusCode.should.eql(200);
data.should.eql('1');
cl.post(
'/socket.io/{protocol}/jsonp-polling/' + sid
, JSON.stringify(parser.encodePacket({ type: 'message', endpoint: '/a', data: 'a' }))
, function (res, data) {
res.statusCode.should.eql(200);
data.should.eql('1');
}
);
}
);
cl.post(
'/socket.io/{protocol}/jsonp-polling/' + sid
, JSON.stringify(parser.encodePacket({ type: 'connect', endpoint: '/b' }))
, function (res, data) {
res.statusCode.should.eql(200);
data.should.eql('1');
cl.post(
'/socket.io/{protocol}/jsonp-polling/' + sid
, JSON.stringify(parser.encodePacket({ type: 'message', endpoint: '/b', data: 'b' }))
, function (res, data) {
res.statusCode.should.eql(200);
data.should.eql('1');
}
);
}
);
});
});
}
};