PageRenderTime 30ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/test/transformer.base.js

https://github.com/OpenGrape/primus
JavaScript | 1355 lines | 1062 code | 279 blank | 14 comment | 31 complexity | 9bcc391e806e04d4808c4cb5e0f16dba MD5 | raw file
  1. 'use strict';
  2. module.exports = function base(transformer, pathname, transformer_name) {
  3. transformer_name = transformer_name || '';
  4. var EventEmitter = require('events').EventEmitter;
  5. var emitter = {
  6. server: function (primus) {
  7. primus.transform('incoming', function (packet) {
  8. var data = packet.data;
  9. if (!('object' === typeof data && 'event' in data && 'args' in data)) return;
  10. this.emit.apply(this, [data.event].concat(data.args));
  11. return false;
  12. });
  13. },
  14. client: function (primus) {
  15. primus.$emit = function trigger(event) {
  16. return this.write({
  17. event: event,
  18. args: Array.prototype.slice.call(arguments, 1)
  19. });
  20. };
  21. }
  22. };
  23. describe('Transformer: '+ (transformer_name || transformer), function () {
  24. var common = require('./common')
  25. , request = common.request
  26. , Primus = common.Primus
  27. , expect = common.expect
  28. , create = common.create
  29. , destroy
  30. , Socket
  31. , server
  32. , primus;
  33. beforeEach(function beforeEach(done) {
  34. var services = create(transformer, done, pathname);
  35. destroy = services.destroy;
  36. Socket = services.Socket;
  37. server = services.server;
  38. primus = services.primus;
  39. });
  40. afterEach(function afterEach(done) {
  41. primus.destroy(done);
  42. });
  43. describe('.Socket', function () {
  44. it('exposes a compatible socket', function () {
  45. expect(Socket).to.be.a('function');
  46. });
  47. it('emits an `open` event when its connected', function (done) {
  48. var socket = new Socket(server.addr);
  49. socket.on('open', function () {
  50. socket.end();
  51. done();
  52. });
  53. });
  54. it('exposes a .socket property', function (done) {
  55. var socket = new Socket(server.addr);
  56. socket.on('open', function () {
  57. expect(!!socket.socket).to.equal(true);
  58. socket.end();
  59. done();
  60. });
  61. });
  62. it('initialises without `new`', function (done) {
  63. var socket = Socket(server.addr, {
  64. timeout: 50000
  65. });
  66. expect(socket.options.timeout).to.equal(50000);
  67. socket.on('open', function () {
  68. socket.end();
  69. done();
  70. });
  71. });
  72. it('should not throw an error when we connect to a dead server', function (done) {
  73. var socket = new Socket('http://localhost:1024');
  74. socket.on('error', function () {
  75. done();
  76. });
  77. });
  78. it('should not open the socket if we set out state to manual', function (done) {
  79. var socket = new Socket(server.addr, {
  80. manual: true
  81. });
  82. socket.on('open', function () {
  83. throw new Error('I should be closed');
  84. });
  85. setTimeout(function () {
  86. socket.end();
  87. done();
  88. }, 100);
  89. });
  90. it('allows disabling of the reconnect functionality', function () {
  91. var socket = new Socket(server.addr, {
  92. strategy: false,
  93. manual: true
  94. });
  95. expect(socket.options.strategy).to.equal('');
  96. });
  97. it('sets reconnection strategies by default', function () {
  98. var socket = new Socket(server.addr, {
  99. manual: true
  100. });
  101. expect(socket.options.strategy).to.contain('disconnect');
  102. expect(socket.options.strategy).to.contain('timeout');
  103. expect(socket.options.strategy).to.contain('online');
  104. expect(socket.options.strategy).to.contain(',');
  105. });
  106. it('emits errors for incorrect context when theres a listener', function () {
  107. var socket = new Socket(server.addr, {
  108. manual: true
  109. }), calls = 0;
  110. try {
  111. socket.open.call(new EventEmitter());
  112. } catch (err) {
  113. expect(Object.prototype.toString.call(err)).to.equal('[object Error]');
  114. expect(err.message).to.contain('Primus#open');
  115. expect(err.message).to.contain('context');
  116. calls++;
  117. }
  118. expect(calls).to.equal(1);
  119. });
  120. it('should change readyStates', function (done) {
  121. var socket = new Socket(server.addr);
  122. expect(socket.readyState).to.equal(Socket.CLOSED);
  123. setTimeout(function () {
  124. expect(socket.readyState).to.equal(Socket.OPENING);
  125. }, 0);
  126. socket.on('open', function () {
  127. expect(socket.readyState).to.equal(Socket.OPEN);
  128. socket.end();
  129. }).on('end', function () {
  130. expect(socket.readyState).to.equal(Socket.CLOSED);
  131. done();
  132. });
  133. });
  134. it('should set the correct read/writable states', function (done) {
  135. var socket = new Socket(server.addr);
  136. expect(socket.readable).to.equal(true);
  137. expect(socket.writable).to.equal(true);
  138. socket.once('open', function () {
  139. expect(socket.readable).to.equal(true);
  140. expect(socket.writable).to.equal(true);
  141. socket.once('end', function () {
  142. expect(socket.readable).to.equal(false);
  143. expect(socket.writable).to.equal(false);
  144. socket.once('open', function () {
  145. expect(socket.readable).to.equal(true);
  146. expect(socket.writable).to.equal(true);
  147. socket.once('end', done).end();
  148. }).open();
  149. }).end();
  150. });
  151. });
  152. it('can be open and closed', function (done) {
  153. primus.on('connection', function (spark) {
  154. setTimeout(function () {
  155. spark.end();
  156. }, 10);
  157. });
  158. var socket = new Socket(server.addr);
  159. socket.once('open', function () {
  160. socket.once('end', function () {
  161. socket.open();
  162. socket.once('open', function () {
  163. socket.once('end', done);
  164. });
  165. });
  166. });
  167. });
  168. it('emits a readyStateChange event', function (done) {
  169. var socket = new Socket(server.addr)
  170. , state = socket.readyState
  171. , calls = 0;
  172. socket.on('readyStateChange', function () {
  173. expect(state).to.not.equal(socket.readyState);
  174. state = socket.readyState;
  175. calls++;
  176. });
  177. socket.on('open', function () {
  178. expect(!!socket.socket).to.equal(true);
  179. socket.end();
  180. }).on('end', function () {
  181. expect(calls).to.equal(3);
  182. done();
  183. });
  184. });
  185. it('emits an `end` event when its closed', function (done) {
  186. var socket = new Socket(server.addr);
  187. socket.on('open', function () {
  188. socket.end();
  189. }).on('end', done);
  190. });
  191. it('emits an `close` event when its closed', function (done) {
  192. var socket = new Socket(server.addr);
  193. socket.on('open', function () {
  194. socket.end();
  195. }).on('close', done);
  196. });
  197. it('only emits `end` once', function (done) {
  198. var socket = new Socket(server.addr);
  199. socket.on('open', function () {
  200. socket.end();
  201. socket.end();
  202. socket.end();
  203. socket.end();
  204. socket.end();
  205. socket.end();
  206. }).on('end', done);
  207. });
  208. it('sends & receives messages', function (done) {
  209. var socket = new Socket(server.addr);
  210. socket.on('data', function (message) {
  211. expect(message).to.equal('pong');
  212. socket.end();
  213. done();
  214. });
  215. socket.on('open', function () {
  216. socket.write({ echo: 'pong' });
  217. });
  218. });
  219. it('receives the raw packet data', function (done) {
  220. var socket = new Socket(server.addr);
  221. socket.on('data', function (message, raw) {
  222. var data = JSON.stringify(message);
  223. expect(message).to.equal('pong');
  224. expect(raw).to.not.equal(message);
  225. expect(data).to.equal(raw);
  226. socket.end();
  227. done();
  228. });
  229. socket.on('open', function () {
  230. socket.write({ echo: 'pong' });
  231. });
  232. });
  233. it('emits an `error` event when it cannot encode the data', function (done) {
  234. var socket = new Socket(server.addr);
  235. socket.on('open', function () {
  236. var data = { foo: 'bar' };
  237. data.recusrive = data;
  238. socket.write(data);
  239. }).on('error', function (err) {
  240. expect(err).to.not.be.instanceOf(String);
  241. expect(err.message).to.contain('JSON');
  242. socket.end();
  243. done();
  244. });
  245. });
  246. it('buffers messages before it connected', function (done) {
  247. var socket = new Socket(server.addr)
  248. , messages = 10
  249. , received = 0;
  250. for (var i = 0; i <= messages; i++) {
  251. socket.write({ echo: i });
  252. }
  253. socket.on('data', function (message) {
  254. expect(message).to.be.a('number');
  255. if (++received === messages) {
  256. socket.end();
  257. done();
  258. }
  259. });
  260. });
  261. it('should not reconnect when we close the connection', function (done) {
  262. var socket = new Socket(server.addr);
  263. socket.on('open', function (message) {
  264. socket.end();
  265. done();
  266. });
  267. socket.on('reconnect', function () {
  268. throw new Error('fuck');
  269. });
  270. });
  271. it('should clean up timers', function (done) {
  272. primus.on('connection', function (spark) {
  273. if (!reconnected) {
  274. reconnected = true;
  275. return spark.end(null, { reconnect: true });
  276. }
  277. spark.end();
  278. });
  279. var socket = new Socket(server.addr)
  280. , reconnected = false
  281. , closed = 0
  282. , opened = 0;
  283. socket.on('open', function () {
  284. if (++opened === 1) {
  285. expect(Object.keys(socket.timers).length).to.be.above(0);
  286. return;
  287. }
  288. expect(Object.keys(socket.timers).length).to.be.equal(0);
  289. });
  290. socket.on('close', function () {
  291. closed++;
  292. expect(Object.keys(socket.timers).length).to.equal(0);
  293. });
  294. socket.on('end', function () {
  295. expect(closed).to.be.equal(2);
  296. done();
  297. });
  298. });
  299. it('should not reconnect when strategy is false', function (done) {
  300. primus.on('connection', function (spark) {
  301. //
  302. // Kill a connection to trigger a reconnect
  303. //
  304. spark.end(null, { reconnect: true });
  305. });
  306. var socket = new Socket(server.addr, { strategy: false });
  307. socket.on('reconnect', function (message) {
  308. throw new Error('bad');
  309. });
  310. socket.on('end', done);
  311. });
  312. //
  313. // This also tests the reconnection when the connection closes unexpectedly
  314. //
  315. it('should allow to trigger a client-side reconnect from server', function (done) {
  316. primus.on('connection', function (spark) {
  317. if (!reconnected) {
  318. reconnected = true;
  319. spark.end(null, { reconnect: true });
  320. }
  321. });
  322. var socket = new Socket(server.addr)
  323. , reconnected = false
  324. , reconnect = false
  325. , opened = 0;
  326. socket.on('reconnect', function (message) {
  327. reconnect = true;
  328. });
  329. socket.on('open', function () {
  330. if (++opened !== 2) return;
  331. expect(reconnect).to.equal(true);
  332. socket.end();
  333. });
  334. socket.on('end', done);
  335. });
  336. it('should allow to stop the reconnection procedure', function (done) {
  337. primus.on('connection', function (spark) {
  338. spark.end(null, { reconnect: true });
  339. });
  340. var socket = new Socket(server.addr);
  341. socket.on('reconnecting', socket.end);
  342. socket.on('reconnect', function (message) {
  343. throw new Error('bad');
  344. });
  345. socket.on('end', done);
  346. });
  347. it('should allow access to the original HTTP request', function (done) {
  348. primus.on('connection', function (spark) {
  349. expect(spark.request).to.not.equal(undefined);
  350. expect(spark.request.headers).to.be.a('object');
  351. //
  352. // Timeout is added to ensure that a request had time to get closed.
  353. // As closed requests could add a bunch of issues.
  354. //
  355. setTimeout(function () {
  356. expect(spark.request).to.not.equal(undefined);
  357. spark.end();
  358. done();
  359. }, 100);
  360. });
  361. var socket = new Socket(server.addr);
  362. });
  363. it('should not increment the attempt if a backoff is running', function (done) {
  364. var socket = new Socket(server.addr);
  365. var backoff = {}
  366. , result = socket.backoff(function () {
  367. socket.end();
  368. }, backoff);
  369. expect(backoff.attempt).to.equal(1);
  370. expect(result).to.equal(socket);
  371. result = socket.backoff(function () {
  372. throw new Error('I should not be called yo');
  373. }, backoff);
  374. expect(backoff.attempt).to.equal(1);
  375. expect(result).to.equal(socket);
  376. socket.on('end', done);
  377. });
  378. it('should reset the reconnect details after a succesful reconnect', function (done) {
  379. var socket = new Socket(server.addr, {
  380. reconnect: {
  381. minDelay: 100,
  382. maxDelay: 2000
  383. }
  384. }), closed = 0;
  385. expect(!socket.attempt).to.equal(true);
  386. this.timeout(5000);
  387. socket.once('reconnect', function () {
  388. expect(!!socket.attempt).to.equal(true);
  389. expect(socket.attempt.attempt).to.be.above(0);
  390. expect(socket.attempt.minDelay).to.equal(100);
  391. expect(socket.attempt.maxDelay).to.equal(2000);
  392. expect(socket.attempt.timeout).to.be.below(2000);
  393. expect(socket.attempt.timeout).to.be.above(99);
  394. });
  395. socket.once('open', function () {
  396. try { server.close(); destroy(); }
  397. catch (e) { return done(e); }
  398. setTimeout(function () {
  399. var services = create(transformer, function () {}, server.portnumber);
  400. destroy = services.destroy;
  401. Socket = services.Socket;
  402. server = services.server;
  403. primus = services.primus;
  404. }, 100);
  405. socket.once('open', function () {
  406. socket.removeAllListeners('end');
  407. socket.end();
  408. // once from the reconnect, and once from the .end above
  409. expect(closed).to.equal(2);
  410. done();
  411. });
  412. });
  413. socket.on('close', function () {
  414. closed++;
  415. });
  416. socket.on('end', function () {
  417. done(new Error('I shouldnt end'));
  418. });
  419. });
  420. it('can force websocket avoidance', function (done) {
  421. var socket = new Socket(server.addr, {
  422. websockets: false
  423. });
  424. expect(socket.AVOID_WEBSOCKETS).to.equal(true);
  425. // open is done in a setTimeout 0 so if we end it now then we'll
  426. // miss the connection
  427. socket.on('open', function () {
  428. socket.end();
  429. });
  430. done();
  431. });
  432. describe('#transform', function () {
  433. it('thrown an error if an invalid type is given', function (done) {
  434. var socket = new Socket(server.addr);
  435. primus.on('connection', function (spark) {
  436. spark.end();
  437. done();
  438. });
  439. try { socket.transform('cowsack', function () {}); }
  440. catch (e) {
  441. expect(e.message).to.contain('transformer');
  442. }
  443. });
  444. describe('outgoing', function () {
  445. it('rewrites the outgoing message', function (done) {
  446. var socket = new Socket(server.addr);
  447. primus.on('connection', function (spark) {
  448. spark.on('data', function (data) {
  449. expect(data).to.be.a('object');
  450. expect(data.meta).to.equal('meta');
  451. expect(data.message).to.equal('foo');
  452. spark.end();
  453. done();
  454. });
  455. });
  456. socket.transform('outgoing', function (data) {
  457. expect(data).to.be.a('object');
  458. expect(data.data).to.equal('foo');
  459. data.data = {
  460. message: 'foo',
  461. meta: 'meta'
  462. };
  463. });
  464. socket.write('foo');
  465. });
  466. it('rewrites the outgoing message async', function (done) {
  467. var socket = new Socket(server.addr);
  468. primus.on('connection', function (spark) {
  469. spark.on('data', function (data) {
  470. expect(data).to.be.a('object');
  471. expect(data.meta).to.equal('meta');
  472. expect(data.message).to.equal('foo');
  473. spark.end();
  474. done();
  475. });
  476. });
  477. socket.transform('outgoing', function (data, next) {
  478. expect(data).to.be.a('object');
  479. expect(data.data).to.equal('foo');
  480. setTimeout(function () {
  481. data.data = {
  482. message: 'foo',
  483. meta: 'meta'
  484. };
  485. next();
  486. }, 10);
  487. });
  488. socket.write('foo');
  489. });
  490. it('prevents the message from being written', function (done) {
  491. var socket = new Socket(server.addr);
  492. socket.transform('outgoing', function (data) {
  493. setTimeout(function () {
  494. socket.end();
  495. done();
  496. }, 0);
  497. return false;
  498. });
  499. socket.on('outgoing::data', function () {
  500. throw new Error('return false should prevent this emit');
  501. }).write('foo');
  502. });
  503. it('prevents the message from being written async', function (done) {
  504. var socket = new Socket(server.addr);
  505. socket.transform('outgoing', function (data, next) {
  506. setTimeout(function () {
  507. next(undefined, false);
  508. setTimeout(function () {
  509. socket.end();
  510. done();
  511. }, 100);
  512. }, 10);
  513. });
  514. socket.on('outgoing::data', function () {
  515. throw new Error('return false should prevent this emit');
  516. }).write('foo');
  517. });
  518. });
  519. describe('incoming', function () {
  520. it('rewrites the incoming message', function (done) {
  521. var socket = new Socket(server.addr);
  522. primus.on('connection', function (spark) {
  523. spark.write('foo');
  524. });
  525. socket.transform('incoming', function (data) {
  526. expect(data).to.be.a('object');
  527. expect(data.data).to.equal('foo');
  528. data.data = {
  529. message: 'foo',
  530. meta: 'meta'
  531. };
  532. });
  533. socket.on('data', function (data) {
  534. expect(data).to.be.a('object');
  535. expect(data.meta).to.equal('meta');
  536. expect(data.message).to.equal('foo');
  537. socket.end();
  538. done();
  539. });
  540. });
  541. it('rewrites the incoming message async', function (done) {
  542. var socket = new Socket(server.addr);
  543. primus.on('connection', function (spark) {
  544. spark.write('foo');
  545. });
  546. socket.transform('incoming', function (data, next) {
  547. expect(data).to.be.a('object');
  548. expect(data.data).to.equal('foo');
  549. setTimeout(function () {
  550. data.data = {
  551. message: 'foo',
  552. meta: 'meta'
  553. };
  554. next();
  555. }, 100);
  556. });
  557. socket.on('data', function (data) {
  558. expect(data).to.be.a('object');
  559. expect(data.meta).to.equal('meta');
  560. expect(data.message).to.equal('foo');
  561. socket.end();
  562. done();
  563. });
  564. });
  565. it('prevents the message from being emitted', function (done) {
  566. var socket = new Socket(server.addr);
  567. primus.on('connection', function (spark) {
  568. spark.write('foo');
  569. });
  570. socket.transform('incoming', function (data) {
  571. setTimeout(function () {
  572. socket.end();
  573. done();
  574. }, 0);
  575. return false;
  576. });
  577. socket.on('data', function () {
  578. throw new Error('return false should prevent this emit');
  579. });
  580. });
  581. it('prevents the message from being emitted async', function (done) {
  582. var socket = new Socket(server.addr);
  583. primus.on('connection', function (spark) {
  584. spark.write('foo');
  585. });
  586. socket.transform('incoming', function (data, next) {
  587. setTimeout(function () {
  588. setTimeout(function () {
  589. socket.end();
  590. done();
  591. }, 100);
  592. next(undefined, false);
  593. }, 10);
  594. });
  595. socket.on('data', function () {
  596. throw new Error('return false should prevent this emit');
  597. });
  598. });
  599. });
  600. });
  601. });
  602. describe('.createSocket', function () {
  603. it('can connect to the server', function (done) {
  604. var PSocket = Primus.createSocket({
  605. transformer: transformer,
  606. pathname: server.pathname
  607. })
  608. , socket = new PSocket(server.addr);
  609. socket.on('open', function () {
  610. socket.end();
  611. done();
  612. });
  613. });
  614. it('should accept plugins', function (done) {
  615. var PSocket = Primus.createSocket({
  616. transformer: transformer,
  617. pathname: server.pathname,
  618. plugin: {
  619. emit: emitter
  620. }
  621. })
  622. , socket = new PSocket(server.addr);
  623. expect(socket.$emit).to.be.a('function');
  624. socket.on('open', function () {
  625. socket.end();
  626. done();
  627. });
  628. });
  629. });
  630. describe('Authorization', function () {
  631. it('support declined authorization', function (done) {
  632. primus.authorize(function auth(req, next) {
  633. expect(req.headers).to.be.a('object');
  634. next(new Error('I failed'));
  635. });
  636. primus.on('connection', function (spark) {
  637. throw new Error('Auth should be called');
  638. });
  639. var Socket = Primus.createSocket({
  640. transformer: transformer,
  641. pathname: server.pathname,
  642. authorization: true
  643. })
  644. , socket = new Socket(server.addr);
  645. socket.on('end', done);
  646. socket.on('reconnect', function () {
  647. throw new Error('fuck');
  648. });
  649. });
  650. it('support declined authorization with status code', function (done) {
  651. primus.authorize(function auth(req, next) {
  652. expect(req.headers).to.be.a('object');
  653. var err = new Error('I failed');
  654. err.statusCode = 404;
  655. next(err);
  656. });
  657. primus.on('connection', function (spark) {
  658. throw new Error('Auth should be called');
  659. });
  660. var Socket = Primus.createSocket({
  661. transformer: transformer,
  662. pathname: server.pathname,
  663. authorization: true
  664. })
  665. , socket = new Socket(server.addr);
  666. socket.on('end', done);
  667. socket.on('reconnect', function () {
  668. throw new Error('fuck');
  669. });
  670. });
  671. it('support declined authorization with message and www-authenticate header', function (done) {
  672. primus.authorize(function auth(req, next) {
  673. expect(req.headers).to.be.a('object');
  674. var err = new Error('I failed');
  675. err.authenticate = 'Basic realm="primus"';
  676. next(err);
  677. });
  678. primus.on('connection', function (spark) {
  679. throw new Error('Auth should be called');
  680. });
  681. var Socket = Primus.createSocket({
  682. transformer: transformer,
  683. pathname: server.pathname,
  684. authorization: true
  685. })
  686. , socket = new Socket(server.addr);
  687. socket.on('outgoing::open', function () {
  688. if (socket.socket.on) {
  689. socket.socket.on('unexpected-response', function (req, res) {
  690. expect(res.statusCode).to.equal(401);
  691. expect(res.headers['www-authenticate']).to.equal('Basic realm="primus"');
  692. var data = '';
  693. res.on('data', function (v) {
  694. data += v;
  695. });
  696. res.on('end', function () {
  697. var obj = JSON.parse(data);
  698. expect(obj).to.eql({error: 'I failed'});
  699. socket.socket.emit('error', new Error(obj.error));
  700. });
  701. });
  702. }
  703. });
  704. socket.on('end', done);
  705. socket.on('reconnect', function () {
  706. throw new Error('reconnect should not be called');
  707. });
  708. });
  709. it('support accepted authorization', function (done) {
  710. primus.authorize(function auth(req, next) {
  711. expect(req.headers).to.be.a('object');
  712. next();
  713. });
  714. primus.on('connection', function (spark) {
  715. spark.end();
  716. });
  717. var socket = new Socket(server.addr);
  718. socket.on('end', done);
  719. socket.on('reconnect', function () {
  720. throw new Error('fuck');
  721. });
  722. });
  723. it('communicates over an authorized connection', function (done) {
  724. primus.authorize(function auth(req, next) {
  725. expect(req.headers).to.be.a('object');
  726. setTimeout(next, 20);
  727. });
  728. primus.on('connection', function (spark) {
  729. spark.on('data', function (data) {
  730. expect(data).to.equal('balls');
  731. spark.end();
  732. });
  733. });
  734. var socket = new Socket(server.addr);
  735. socket.on('end', done);
  736. socket.write('balls');
  737. });
  738. if (transformer.toLowerCase() === 'websockets')
  739. it('should connect using basic auth', function (done) {
  740. primus.on('connection', function (spark) {
  741. expect(spark.headers.authorization).to.equal('Basic dXNyOnBhc3M=');
  742. socket.end();
  743. });
  744. var socket = new Socket(server.make_addr('usr:pass', '?foo=bar'));
  745. socket.on('end', done);
  746. });
  747. it('should emit a timeout event if it cannot connect in a timely manner', function (done) {
  748. primus.authorize(function (req, next) {
  749. setTimeout(next, 1000);
  750. });
  751. var socket = new Socket(server.make_addr('usr:pass', '?foo=bar'), {
  752. timeout: 500
  753. });
  754. socket.on('timeout', done);
  755. });
  756. it('should reconnect after the timeout', function (done) {
  757. primus.authorize(function (req, next) {
  758. setTimeout(next, 1000);
  759. });
  760. var socket = new Socket(server.addr, { timeout: 10 })
  761. , pattern = [];
  762. socket.on('timeout', function () {
  763. pattern.push('timeout');
  764. });
  765. socket.once('reconnecting', function () {
  766. pattern.push('reconnecting');
  767. });
  768. socket.once('reconnect', function () {
  769. pattern.push('reconnect');
  770. expect(pattern.join(',')).to.equal('timeout,reconnecting,reconnect');
  771. socket.end();
  772. // outgoing::reconnect is emitted after reconnect whatever we do
  773. socket.removeAllListeners('outgoing::reconnect');
  774. done();
  775. });
  776. });
  777. });
  778. describe('Server', function () {
  779. it('emits a `connection` event before any `data` event', function (done) {
  780. var create = 10
  781. , foo = 0;
  782. primus.on('connection', function (spark) {
  783. spark.on('data', function (data) {
  784. if ('foo' === data) {
  785. if (++foo === create) done();
  786. }
  787. });
  788. });
  789. for (var i = 0; i < create; i++) {
  790. (new Socket(server.addr)).write('foo');
  791. }
  792. });
  793. it('emits `end` when the connection is closed', function (done) {
  794. primus.on('connection', function (spark) {
  795. spark.on('end', done);
  796. });
  797. var socket = new Socket(server.addr);
  798. socket.on('open', function () {
  799. socket.end();
  800. });
  801. });
  802. it('should emit an `error` when it fails to encode the data', function (done) {
  803. primus.on('connection', function (spark) {
  804. var data = { foo: 'bar' };
  805. data.recusrive = data;
  806. spark.on('error', function (err) {
  807. expect(err).to.not.be.a('string');
  808. expect(err.message).to.include('JSON');
  809. socket.end();
  810. done();
  811. });
  812. spark.write(data);
  813. });
  814. var socket = new Socket(server.addr);
  815. });
  816. it('should receive querystrings', function (done) {
  817. primus.on('connection', function (spark) {
  818. expect(spark.query).to.be.a('object');
  819. if (
  820. (transformer.toLowerCase() !== 'sockjs') &&
  821. (transformer_name.toLowerCase() !== 'unixdomainwebsockets')
  822. ) {
  823. expect(spark.query.foo).to.equal('bar');
  824. }
  825. socket.end();
  826. });
  827. var socket = new Socket(server.make_addr(null, '?foo=bar'));
  828. socket.on('end', done);
  829. });
  830. it('should receive all headers', function (done) {
  831. primus.on('connection', function (spark) {
  832. expect(spark.headers).to.be.a('object');
  833. expect(spark.headers).to.have.property('connection');
  834. socket.end();
  835. });
  836. var socket = new Socket(server.make_addr(null, '?foo=bar'));
  837. socket.on('end', done);
  838. });
  839. it('should not trigger a reconnect when we end the connection', function (done) {
  840. primus.on('connection', function (spark) {
  841. spark.end();
  842. });
  843. var socket = new Socket(server.addr);
  844. socket.on('end', done);
  845. socket.on('reconnect', function () {
  846. throw new Error('fuck');
  847. });
  848. });
  849. if (transformer_name.toLowerCase() !== 'unixdomainwebsockets') {
  850. it('should still allow requests to the original listener', function (done) {
  851. request(
  852. server.addr +'/nothrow',
  853. function (err, res, body) {
  854. if (err) return done(err);
  855. expect(body).to.equal('original listener');
  856. done();
  857. }
  858. );
  859. });
  860. it('responds to library requests', function (done) {
  861. request(
  862. server.addr + '/primus/primus.js',
  863. function (err, res, body) {
  864. if (err) return done(err);
  865. expect(res.statusCode).to.equal(200);
  866. expect(res.headers['content-type']).to.equal('text/javascript; charset=utf-8');
  867. expect(body).to.equal(primus.library());
  868. done();
  869. }
  870. );
  871. });
  872. it('handles requests to non existing routes captured by primus', function (done) {
  873. this.timeout(100);
  874. request(
  875. server.addr + '/primus.js',
  876. function (err, res, body) {
  877. if (err) return done(err);
  878. done();
  879. }
  880. );
  881. });
  882. it('correctly handles requests when a middleware returns an error', function (done) {
  883. primus.before('foo', function foo(req, res, next) {
  884. next(new Error('foo failed'));
  885. });
  886. primus.on('connection', function (spark) {
  887. throw new Error('connection should not be triggered');
  888. });
  889. var socket = new Socket(server.addr, { strategy: false });
  890. socket.on('end', done);
  891. });
  892. it('correctly parses the ip address', function (done) {
  893. primus.on('connection', function (spark) {
  894. var address = spark.address;
  895. expect(address.port).to.not.equal(0);
  896. expect(address.port).to.not.equal(server.portnumber);
  897. spark.end();
  898. done();
  899. });
  900. var socket = new Socket(server.addr);
  901. });
  902. } // !unixdomainwebsockets
  903. it('uses x-forwarded headers over the connection ip address', function (done) {
  904. primus.on('connection', function (spark) {
  905. spark.headers['x-forwarded-for'] = '13.3.37.1,12.12.12.12';
  906. spark.headers['x-forwarded-port'] = '9083,1334';
  907. expect(spark.address.ip).to.equal('13.3.37.1');
  908. expect(spark.address.port).to.equal(9083);
  909. spark.end();
  910. done();
  911. });
  912. var socket = new Socket(server.addr);
  913. });
  914. if (transformer_name.toLowerCase() !== 'unixdomainwebsockets') {
  915. it('exposes a spec file with the correct transformer', function (done) {
  916. request(
  917. server.addr +'/primus/spec',
  918. function (err, res, body) {
  919. if (err) return done(err);
  920. body = JSON.parse(body);
  921. expect(body.transformer).to.equal(transformer.toLowerCase());
  922. expect(body.version).to.equal(primus.version);
  923. expect(body.pathname).to.equal('/primus');
  924. expect(body.parser).to.equal('json');
  925. done();
  926. }
  927. );
  928. });
  929. } // !unixdomainwebsockets
  930. it('doesnt crash when we write to a closed connection', function (done) {
  931. primus.on('connection', function (spark) {
  932. spark.on('end', function () {
  933. spark.write('I should not crash');
  934. setTimeout(function () {
  935. spark.write('the server should ignore me');
  936. setTimeout(done, 10);
  937. }, 10);
  938. });
  939. });
  940. var socket = new Socket(server.addr);
  941. socket.on('open', function () {
  942. socket.end();
  943. });
  944. });
  945. it('should make the spark available to the parser', function (done) {
  946. var rnd = Math.random(),
  947. parser = primus.parser;
  948. primus.parsers({
  949. decoder: function (data, fn) {
  950. expect(this.foobar).to.equal(rnd);
  951. parser.decoder.call(this, data, function (err, decoded) {
  952. expect(err).not.to.exist;
  953. expect(decoded).to.eql({ echo: 'pong' });
  954. fn(null, decoded);
  955. });
  956. },
  957. encoder: function (data, fn) {
  958. expect(this.foobar).to.equal(rnd);
  959. parser.encoder.call(this, data, fn);
  960. if (data === 'pong') {
  961. done();
  962. }
  963. }
  964. });
  965. primus.on('connection', function (spark) {
  966. spark.foobar = rnd;
  967. });
  968. var socket = new Socket(server.addr);
  969. socket.on('open', function () {
  970. socket.write({ echo: 'pong' });
  971. });
  972. });
  973. describe('#transform', function () {
  974. it('thrown an error if an invalid type is given', function (done) {
  975. try { primus.transform('cowsack', function () {}); }
  976. catch (e) {
  977. expect(e.message).to.contain('transformer');
  978. done();
  979. }
  980. });
  981. describe('outgoing', function () {
  982. it('rewrites the outgoing message', function (done) {
  983. primus.transform('outgoing', function (data) {
  984. expect(data).to.be.a('object');
  985. expect(data.data).to.equal('foo');
  986. data.data = {
  987. message: 'foo',
  988. meta: 'meta'
  989. };
  990. });
  991. primus.on('connection', function (spark) {
  992. setTimeout(function () {
  993. spark.write('foo');
  994. }, 10);
  995. });
  996. var socket = new Socket(server.addr);
  997. socket.on('data', function (data) {
  998. expect(data).to.be.a('object');
  999. expect(data.meta).to.equal('meta');
  1000. expect(data.message).to.equal('foo');
  1001. socket.end();
  1002. done();
  1003. });
  1004. });
  1005. it('prevents the message from being written', function (done) {
  1006. primus.transform('outgoing', function () {
  1007. setTimeout(function () {
  1008. socket.end();
  1009. done();
  1010. }, 0);
  1011. return false;
  1012. });
  1013. primus.on('connection', function (spark) {
  1014. spark.on('outgoing::data', function (data) {
  1015. if (~data.indexOf('foo')) throw new Error('return false should prevent this emit');
  1016. });
  1017. spark.write('foo');
  1018. });
  1019. var socket = new Socket(server.addr);
  1020. });
  1021. });
  1022. describe('incoming', function () {
  1023. it('rewrites the incoming message', function (done) {
  1024. primus.transform('incoming', function (data) {
  1025. expect(data).to.be.a('object');
  1026. expect(data.data).to.equal('foo');
  1027. data.data = {
  1028. message: 'foo',
  1029. meta: 'meta'
  1030. };
  1031. });
  1032. primus.on('connection', function (spark) {
  1033. spark.on('data', function (data) {
  1034. expect(data).to.be.a('object');
  1035. expect(data.meta).to.equal('meta');
  1036. expect(data.message).to.equal('foo');
  1037. spark.end();
  1038. done();
  1039. });
  1040. });
  1041. var socket = new Socket(server.addr);
  1042. socket.write('foo');
  1043. });
  1044. it('prevents the message from being emitted', function (done) {
  1045. primus.transform('incoming', function (data) {
  1046. setTimeout(function () {
  1047. socket.end();
  1048. done();
  1049. }, 0);
  1050. return false;
  1051. });
  1052. primus.on('connection', function (spark) {
  1053. spark.on('data', function () {
  1054. throw new Error('return false should prevent this emit');
  1055. });
  1056. });
  1057. var socket = new Socket(server.addr);
  1058. socket.write('foo');
  1059. });
  1060. });
  1061. });
  1062. describe('#id', function () {
  1063. it('should receive the id', function (done) {
  1064. primus.on('connection', function (spark) {
  1065. socket.id(function (id) {
  1066. expect(id).to.equal(spark.id);
  1067. spark.end();
  1068. done();
  1069. });
  1070. });
  1071. var socket = new Socket(server.addr);
  1072. });
  1073. });
  1074. });
  1075. });
  1076. };