PageRenderTime 49ms CodeModel.GetById 9ms RepoModel.GetById 0ms app.codeStats 0ms

/test/transformer.base.js

https://github.com/primus/primus
JavaScript | 1404 lines | 1092 code | 289 blank | 23 comment | 31 complexity | 716d888753749d9688c457a655d5c332 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, 'json', 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. }, 100);
  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, 'json', 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. it('supports async connection events', function (done) {
  433. var pre;
  434. primus.on('connection', function (spark, next) {
  435. setTimeout(function () {
  436. pre = 'async';
  437. next();
  438. }, 10);
  439. });
  440. primus.on('connection', function (spark) {
  441. expect(pre).to.equal('async');
  442. spark.end();
  443. done();
  444. });
  445. //
  446. // Connect AFTER the things are called
  447. //
  448. var socket = new Socket(server.addr);
  449. });
  450. describe('#transform', function () {
  451. it('thrown an error if an invalid type is given', function (done) {
  452. var socket = new Socket(server.addr);
  453. primus.on('connection', function (spark) {
  454. spark.end();
  455. done();
  456. });
  457. try { socket.transform('cowsack', function () {}); }
  458. catch (e) {
  459. expect(e.message).to.contain('transformer');
  460. }
  461. });
  462. describe('outgoing', function () {
  463. it('rewrites the outgoing message', function (done) {
  464. var socket = new Socket(server.addr);
  465. primus.on('connection', function (spark) {
  466. spark.on('data', function (data) {
  467. expect(data).to.be.a('object');
  468. expect(data.meta).to.equal('meta');
  469. expect(data.message).to.equal('foo');
  470. spark.end();
  471. done();
  472. });
  473. });
  474. socket.transform('outgoing', function (data) {
  475. expect(data).to.be.a('object');
  476. expect(data.data).to.equal('foo');
  477. data.data = {
  478. message: 'foo',
  479. meta: 'meta'
  480. };
  481. });
  482. socket.write('foo');
  483. });
  484. it('rewrites the outgoing message async', function (done) {
  485. var socket = new Socket(server.addr);
  486. primus.on('connection', function (spark) {
  487. spark.on('data', function (data) {
  488. expect(data).to.be.a('object');
  489. expect(data.meta).to.equal('meta');
  490. expect(data.message).to.equal('foo');
  491. spark.end();
  492. done();
  493. });
  494. });
  495. socket.transform('outgoing', function (data, next) {
  496. expect(data).to.be.a('object');
  497. expect(data.data).to.equal('foo');
  498. setTimeout(function () {
  499. data.data = {
  500. message: 'foo',
  501. meta: 'meta'
  502. };
  503. next();
  504. }, 10);
  505. });
  506. socket.write('foo');
  507. });
  508. it('prevents the message from being written', function (done) {
  509. var socket = new Socket(server.addr);
  510. socket.transform('outgoing', function (data) {
  511. setTimeout(function () {
  512. socket.end();
  513. done();
  514. }, 0);
  515. return false;
  516. });
  517. socket.on('outgoing::data', function () {
  518. throw new Error('return false should prevent this emit');
  519. }).write('foo');
  520. });
  521. it('prevents the message from being written async', function (done) {
  522. var socket = new Socket(server.addr);
  523. socket.transform('outgoing', function (data, next) {
  524. setTimeout(function () {
  525. next(undefined, false);
  526. setTimeout(function () {
  527. socket.end();
  528. done();
  529. }, 100);
  530. }, 10);
  531. });
  532. socket.on('outgoing::data', function () {
  533. throw new Error('return false should prevent this emit');
  534. }).write('foo');
  535. });
  536. });
  537. describe('incoming', function () {
  538. it('rewrites the incoming message', function (done) {
  539. var socket = new Socket(server.addr);
  540. primus.on('connection', function (spark) {
  541. spark.write('foo');
  542. });
  543. socket.transform('incoming', function (data) {
  544. expect(data).to.be.a('object');
  545. expect(data.data).to.equal('foo');
  546. data.data = {
  547. message: 'foo',
  548. meta: 'meta'
  549. };
  550. });
  551. socket.on('data', function (data) {
  552. expect(data).to.be.a('object');
  553. expect(data.meta).to.equal('meta');
  554. expect(data.message).to.equal('foo');
  555. socket.end();
  556. done();
  557. });
  558. });
  559. it('rewrites the incoming message async', function (done) {
  560. var socket = new Socket(server.addr);
  561. primus.on('connection', function (spark) {
  562. spark.write('foo');
  563. });
  564. socket.transform('incoming', function (data, next) {
  565. expect(data).to.be.a('object');
  566. expect(data.data).to.equal('foo');
  567. setTimeout(function () {
  568. data.data = {
  569. message: 'foo',
  570. meta: 'meta'
  571. };
  572. next();
  573. }, 100);
  574. });
  575. socket.on('data', function (data) {
  576. expect(data).to.be.a('object');
  577. expect(data.meta).to.equal('meta');
  578. expect(data.message).to.equal('foo');
  579. socket.end();
  580. done();
  581. });
  582. });
  583. it('prevents the message from being emitted', function (done) {
  584. var socket = new Socket(server.addr);
  585. primus.on('connection', function (spark) {
  586. spark.write('foo');
  587. });
  588. socket.transform('incoming', function (data) {
  589. setTimeout(function () {
  590. socket.end();
  591. done();
  592. }, 0);
  593. return false;
  594. });
  595. socket.on('data', function () {
  596. throw new Error('return false should prevent this emit');
  597. });
  598. });
  599. it('prevents the message from being emitted async', function (done) {
  600. var socket = new Socket(server.addr);
  601. primus.on('connection', function (spark) {
  602. spark.write('foo');
  603. });
  604. socket.transform('incoming', function (data, next) {
  605. setTimeout(function () {
  606. setTimeout(function () {
  607. socket.end();
  608. done();
  609. }, 100);
  610. next(undefined, false);
  611. }, 10);
  612. });
  613. socket.on('data', function () {
  614. throw new Error('return false should prevent this emit');
  615. });
  616. });
  617. });
  618. });
  619. });
  620. describe('.createSocket', function () {
  621. it('can connect to the server', function (done) {
  622. var PSocket = Primus.createSocket({
  623. transformer: transformer,
  624. pathname: server.pathname
  625. })
  626. , socket = new PSocket(server.addr);
  627. socket.on('open', function () {
  628. socket.end();
  629. done();
  630. });
  631. });
  632. it('should accept plugins', function (done) {
  633. var PSocket = Primus.createSocket({
  634. transformer: transformer,
  635. pathname: server.pathname,
  636. plugin: {
  637. emit: emitter
  638. }
  639. })
  640. , socket = new PSocket(server.addr);
  641. expect(socket.$emit).to.be.a('function');
  642. socket.on('open', function () {
  643. socket.end();
  644. done();
  645. });
  646. });
  647. });
  648. describe('Authorization', function () {
  649. it('support declined authorization', function (done) {
  650. primus.authorize(function auth(req, next) {
  651. expect(req.headers).to.be.a('object');
  652. next(new Error('I failed'));
  653. });
  654. primus.on('connection', function (spark) {
  655. throw new Error('Auth should be called');
  656. });
  657. var Socket = Primus.createSocket({
  658. transformer: transformer,
  659. pathname: server.pathname,
  660. authorization: true
  661. })
  662. , socket = new Socket(server.addr);
  663. socket.on('end', done);
  664. socket.on('reconnect', function () {
  665. throw new Error('fuck');
  666. });
  667. });
  668. it('support declined authorization with status code', function (done) {
  669. primus.authorize(function auth(req, next) {
  670. expect(req.headers).to.be.a('object');
  671. var err = new Error('I failed');
  672. err.statusCode = 404;
  673. next(err);
  674. });
  675. primus.on('connection', function (spark) {
  676. throw new Error('Auth should be called');
  677. });
  678. var Socket = Primus.createSocket({
  679. transformer: transformer,
  680. pathname: server.pathname,
  681. authorization: true
  682. })
  683. , socket = new Socket(server.addr);
  684. socket.on('end', done);
  685. socket.on('reconnect', function () {
  686. throw new Error('fuck');
  687. });
  688. });
  689. it('support declined authorization with message and www-authenticate header', function (done) {
  690. primus.authorize(function auth(req, next) {
  691. expect(req.headers).to.be.a('object');
  692. var err = new Error('I failed');
  693. err.authenticate = 'Basic realm="primus"';
  694. next(err);
  695. });
  696. primus.on('connection', function (spark) {
  697. throw new Error('Auth should be called');
  698. });
  699. var Socket = Primus.createSocket({
  700. transformer: transformer,
  701. pathname: server.pathname,
  702. authorization: true
  703. })
  704. , socket = new Socket(server.addr);
  705. socket.on('outgoing::open', function () {
  706. if (socket.socket.on) {
  707. socket.socket.on('unexpected-response', function (req, res) {
  708. expect(res.statusCode).to.equal(401);
  709. expect(res.headers['www-authenticate']).to.equal('Basic realm="primus"');
  710. var data = '';
  711. res.on('data', function (v) {
  712. data += v;
  713. });
  714. res.on('end', function () {
  715. var obj = JSON.parse(data);
  716. expect(obj).to.eql({error: 'I failed'});
  717. socket.socket.emit('error', new Error(obj.error));
  718. });
  719. });
  720. }
  721. });
  722. socket.on('end', done);
  723. socket.on('reconnect', function () {
  724. throw new Error('reconnect should not be called');
  725. });
  726. });
  727. it('support accepted authorization', function (done) {
  728. primus.authorize(function auth(req, next) {
  729. expect(req.headers).to.be.a('object');
  730. next();
  731. });
  732. primus.on('connection', function (spark) {
  733. spark.end();
  734. });
  735. var socket = new Socket(server.addr);
  736. socket.on('end', done);
  737. socket.on('reconnect', function () {
  738. throw new Error('fuck');
  739. });
  740. });
  741. it('communicates over an authorized connection', function (done) {
  742. primus.authorize(function auth(req, next) {
  743. expect(req.headers).to.be.a('object');
  744. setTimeout(next, 20);
  745. });
  746. primus.on('connection', function (spark) {
  747. spark.on('data', function (data) {
  748. expect(data).to.equal('balls');
  749. spark.end();
  750. });
  751. });
  752. var socket = new Socket(server.addr);
  753. socket.on('end', done);
  754. socket.write('balls');
  755. });
  756. it('receives pre-parsed ip adresses', function (done) {
  757. primus.authorize(function auth(req, next) {
  758. expect(req.forwarded).to.be.a('object');
  759. expect(req.forwarded.ip).to.be.a('string');
  760. expect(req.forwarded.port).to.be.a('number');
  761. setTimeout(next, 0);
  762. });
  763. primus.on('connection', function (spark) {
  764. spark.end();
  765. });
  766. var socket = new Socket(server.addr);
  767. socket.on('end', done);
  768. socket.write('balls');
  769. });
  770. if (transformer.toLowerCase() === 'websockets')
  771. it('should connect using basic auth', function (done) {
  772. primus.on('connection', function (spark) {
  773. expect(spark.headers.authorization).to.equal('Basic dXNyOnBhc3M=');
  774. socket.end();
  775. });
  776. var socket = new Socket(server.make_addr('usr:pass', '?foo=bar'));
  777. socket.on('end', done);
  778. });
  779. it('should emit a timeout event if it cannot connect in a timely manner', function (done) {
  780. primus.authorize(function (req, next) {
  781. setTimeout(next, 1000);
  782. });
  783. var socket = new Socket(server.make_addr('usr:pass', '?foo=bar'), {
  784. timeout: 500
  785. });
  786. socket.on('timeout', done);
  787. });
  788. it('should reconnect after the timeout', function (done) {
  789. primus.authorize(function (req, next) {
  790. setTimeout(next, 1000);
  791. });
  792. var socket = new Socket(server.addr, { timeout: 10 })
  793. , pattern = [];
  794. socket.on('timeout', function () {
  795. pattern.push('timeout');
  796. });
  797. socket.once('reconnecting', function () {
  798. pattern.push('reconnecting');
  799. });
  800. socket.once('reconnect', function () {
  801. pattern.push('reconnect');
  802. expect(pattern.join(',')).to.equal('timeout,reconnecting,reconnect');
  803. socket.end();
  804. // outgoing::reconnect is emitted after reconnect whatever we do
  805. socket.removeAllListeners('outgoing::reconnect');
  806. done();
  807. });
  808. });
  809. });
  810. describe('Server', function () {
  811. it('emits a `connection` event before any `data` event', function (done) {
  812. var create = 10
  813. , foo = 0;
  814. primus.on('connection', function (spark) {
  815. spark.on('data', function (data) {
  816. if ('foo' === data) {
  817. if (++foo === create) done();
  818. }
  819. });
  820. });
  821. for (var i = 0; i < create; i++) {
  822. (new Socket(server.addr)).write('foo');
  823. }
  824. });
  825. it('emits `end` when the connection is closed', function (done) {
  826. primus.on('connection', function (spark) {
  827. spark.on('end', done);
  828. });
  829. var socket = new Socket(server.addr);
  830. socket.on('open', function () {
  831. socket.end();
  832. });
  833. });
  834. it('should emit an `error` when it fails to encode the data', function (done) {
  835. primus.on('connection', function (spark) {
  836. var data = { foo: 'bar' };
  837. data.recusrive = data;
  838. spark.on('error', function (err) {
  839. expect(err).to.not.be.a('string');
  840. expect(err.message).to.include('JSON');
  841. socket.end();
  842. done();
  843. });
  844. spark.write(data);
  845. });
  846. var socket = new Socket(server.addr);
  847. });
  848. it('should receive querystrings', function (done) {
  849. primus.on('connection', function (spark) {
  850. expect(spark.query).to.be.a('object');
  851. if (
  852. (transformer.toLowerCase() !== 'sockjs') &&
  853. (transformer_name.toLowerCase() !== 'unixdomainwebsockets')
  854. ) {
  855. expect(spark.query.foo).to.equal('bar');
  856. }
  857. socket.end();
  858. });
  859. var socket = new Socket(server.make_addr(null, '?foo=bar'));
  860. socket.on('end', done);
  861. });
  862. it('should receive all headers', function (done) {
  863. primus.on('connection', function (spark) {
  864. expect(spark.headers).to.be.a('object');
  865. expect(spark.headers).to.have.property('connection');
  866. socket.end();
  867. });
  868. var socket = new Socket(server.make_addr(null, '?foo=bar'));
  869. socket.on('end', done);
  870. });
  871. it('should not trigger a reconnect when we end the connection', function (done) {
  872. primus.on('connection', function (spark) {
  873. spark.end();
  874. });
  875. var socket = new Socket(server.addr);
  876. socket.on('end', done);
  877. socket.on('reconnect', function () {
  878. throw new Error('fuck');
  879. });
  880. });
  881. if (transformer_name.toLowerCase() !== 'unixdomainwebsockets') {
  882. it('should still allow requests to the original listener', function (done) {
  883. request(
  884. server.addr +'/nothrow',
  885. function (err, res, body) {
  886. if (err) return done(err);
  887. expect(body).to.equal('original listener');
  888. done();
  889. }
  890. );
  891. });
  892. it('responds to library requests', function (done) {
  893. request(
  894. server.addr + '/primus/primus.js',
  895. function (err, res, body) {
  896. if (err) return done(err);
  897. expect(res.statusCode).to.equal(200);
  898. expect(res.headers['content-type']).to.equal('text/javascript; charset=utf-8');
  899. expect(body).to.equal(primus.library());
  900. done();
  901. }
  902. );
  903. });
  904. it('handles requests to non existing routes captured by primus', function (done) {
  905. this.timeout(100);
  906. request(
  907. server.addr + '/primus.js',
  908. function (err, res, body) {
  909. if (err) return done(err);
  910. done();
  911. }
  912. );
  913. });
  914. it('correctly handles requests when a middleware returns an error', function (done) {
  915. primus.before('foo', function foo(req, res, next) {
  916. next(new Error('foo failed'));
  917. });
  918. primus.on('connection', function (spark) {
  919. throw new Error('connection should not be triggered');
  920. });
  921. var socket = new Socket(server.addr, { strategy: false });
  922. socket.on('end', done);
  923. });
  924. it('correctly parses the ip address', function (done) {
  925. primus.on('connection', function (spark) {
  926. var address = spark.address;
  927. expect(address.port).to.not.equal(0);
  928. expect(address.port).to.not.equal(server.portnumber);
  929. spark.end();
  930. done();
  931. });
  932. var socket = new Socket(server.addr);
  933. });
  934. } // !unixdomainwebsockets
  935. it('uses x-forwarded headers over the connection ip address', function (done) {
  936. primus.on('connection', function (spark) {
  937. spark.headers['x-forwarded-for'] = '13.3.37.1,12.12.12.12';
  938. spark.headers['x-forwarded-port'] = '9083,1334';
  939. //
  940. // Side note here, we don't want to re-use the detection from the
  941. // middleware here as we don't want to go through the hassle of adding
  942. // a real-proxy in our tests. We merely want to test if it will look
  943. // at the x-forwarded-headers instead of the pure IP address.
  944. //
  945. delete spark.request.forwarded;
  946. expect(spark.address.ip).to.equal('13.3.37.1');
  947. expect(spark.address.port).to.equal(9083);
  948. spark.end();
  949. done();
  950. });
  951. var socket = new Socket(server.addr);
  952. });
  953. if (transformer_name.toLowerCase() !== 'unixdomainwebsockets') {
  954. it('exposes a spec file with the correct transformer', function (done) {
  955. request(
  956. server.addr +'/primus/spec',
  957. function (err, res, body) {
  958. if (err) return done(err);
  959. body = JSON.parse(body);
  960. expect(body.transformer).to.equal(transformer.toLowerCase());
  961. expect(body.version).to.equal(primus.version);
  962. expect(body.pathname).to.equal('/primus');
  963. expect(body.parser).to.equal('json');
  964. done();
  965. }
  966. );
  967. });
  968. } // !unixdomainwebsockets
  969. it('doesnt crash when we write to a closed connection', function (done) {
  970. primus.on('connection', function (spark) {
  971. spark.on('end', function () {
  972. spark.write('I should not crash');
  973. setTimeout(function () {
  974. spark.write('the server should ignore me');
  975. setTimeout(done, 10);
  976. }, 10);
  977. });
  978. });
  979. var socket = new Socket(server.addr);
  980. socket.on('open', function () {
  981. socket.end();
  982. });
  983. });
  984. it('should make the spark available to the parser', function (done) {
  985. var rnd = Math.random(),
  986. parser = primus.parser;
  987. primus.parsers({
  988. decoder: function (data, fn) {
  989. expect(this.foobar).to.equal(rnd);
  990. parser.decoder.call(this, data, function (err, decoded) {
  991. expect(err).not.to.exist;
  992. expect(decoded).to.eql({ echo: 'pong' });
  993. fn(null, decoded);
  994. });
  995. },
  996. encoder: function (data, fn) {
  997. expect(this.foobar).to.equal(rnd);
  998. parser.encoder.call(this, data, fn);
  999. if (data === 'pong') {
  1000. done();
  1001. }
  1002. }
  1003. });
  1004. primus.on('connection', function (spark) {
  1005. spark.foobar = rnd;
  1006. });
  1007. var socket = new Socket(server.addr);
  1008. socket.on('open', function () {
  1009. socket.write({ echo: 'pong' });
  1010. });
  1011. });
  1012. describe('#transform', function () {
  1013. it('thrown an error if an invalid type is given', function (done) {
  1014. try { primus.transform('cowsack', function () {}); }
  1015. catch (e) {
  1016. expect(e.message).to.contain('transformer');
  1017. done();
  1018. }
  1019. });
  1020. describe('outgoing', function () {
  1021. it('rewrites the outgoing message', function (done) {
  1022. primus.transform('outgoing', function (data) {
  1023. expect(data).to.be.a('object');
  1024. expect(data.data).to.equal('foo');
  1025. data.data = {
  1026. message: 'foo',
  1027. meta: 'meta'
  1028. };
  1029. });
  1030. primus.on('connection', function (spark) {
  1031. setTimeout(function () {
  1032. spark.write('foo');
  1033. }, 10);
  1034. });
  1035. var socket = new Socket(server.addr);
  1036. socket.on('data', function (data) {
  1037. expect(data).to.be.a('object');
  1038. expect(data.meta).to.equal('meta');
  1039. expect(data.message).to.equal('foo');
  1040. socket.end();
  1041. done();
  1042. });
  1043. });
  1044. it('prevents the message from being written', function (done) {
  1045. primus.transform('outgoing', function () {
  1046. setTimeout(function () {
  1047. socket.end();
  1048. done();
  1049. }, 0);
  1050. return false;
  1051. });
  1052. primus.on('connection', function (spark) {
  1053. spark.on('outgoing::data', function (data) {
  1054. if (~data.indexOf('foo')) throw new Error('return false should prevent this emit');
  1055. });
  1056. spark.write('foo');
  1057. });
  1058. var socket = new Socket(server.addr);
  1059. });
  1060. });
  1061. describe('incoming', function () {
  1062. it('rewrites the incoming message', function (done) {
  1063. primus.transform('incoming', function (data) {
  1064. expect(data).to.be.a('object');
  1065. expect(data.data).to.equal('foo');
  1066. data.data = {
  1067. message: 'foo',
  1068. meta: 'meta'
  1069. };
  1070. });
  1071. primus.on('connection', function (spark) {
  1072. spark.on('data', function (data) {
  1073. expect(data).to.be.a('object');
  1074. expect(data.meta).to.equal('meta');
  1075. expect(data.message).to.equal('foo');
  1076. spark.end();
  1077. done();
  1078. });
  1079. });
  1080. var socket = new Socket(server.addr);
  1081. socket.write('foo');
  1082. });
  1083. it('prevents the message from being emitted', function (done) {
  1084. primus.transform('incoming', function (data) {
  1085. setTimeout(function () {
  1086. socket.end();
  1087. done();
  1088. }, 0);
  1089. return false;
  1090. });
  1091. primus.on('connection', function (spark) {
  1092. spark.on('data', function () {
  1093. throw new Error('return false should prevent this emit');
  1094. });
  1095. });
  1096. var socket = new Socket(server.addr);
  1097. socket.write('foo');
  1098. });
  1099. });
  1100. });
  1101. describe('#id', function () {
  1102. it('should receive the id', function (done) {
  1103. primus.on('connection', function (spark) {
  1104. socket.id(function (id) {
  1105. expect(id).to.equal(spark.id);
  1106. spark.end();
  1107. done();
  1108. });
  1109. });
  1110. var socket = new Socket(server.addr);
  1111. });
  1112. });
  1113. });
  1114. });
  1115. };