PageRenderTime 157ms CodeModel.GetById 68ms app.highlight 81ms RepoModel.GetById 1ms app.codeStats 0ms

/test/transformer.base.js

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