PageRenderTime 73ms CodeModel.GetById 1ms app.highlight 62ms RepoModel.GetById 1ms app.codeStats 1ms

/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
   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('rewrites the outgoing message async', function (done) {
 592            var socket = new Socket(server.addr);
 593
 594            primus.on('connection', function (spark) {
 595              spark.on('data', function (data) {
 596                expect(data).to.be.a('object');
 597                expect(data.meta).to.equal('meta');
 598                expect(data.message).to.equal('foo');
 599
 600                spark.end();
 601                done();
 602              });
 603            });
 604
 605            socket.transform('outgoing', function (data, next) {
 606              expect(data).to.be.a('object');
 607              expect(data.data).to.equal('foo');
 608
 609              setTimeout(function () {
 610                data.data = {
 611                  message: 'foo',
 612                  meta: 'meta'
 613                };
 614
 615                next();
 616              }, 10);
 617            });
 618
 619            socket.write('foo');
 620          });
 621
 622          it('prevents the message from being written', function (done) {
 623            var socket = new Socket(server.addr);
 624
 625            socket.transform('outgoing', function (data) {
 626              setTimeout(function () {
 627                socket.end();
 628                done();
 629              }, 0);
 630
 631              return false;
 632            });
 633
 634            socket.on('outgoing::data', function () {
 635              throw new Error('return false should prevent this emit');
 636            }).write('foo');
 637          });
 638
 639          it('prevents the message from being written async', function (done) {
 640            var socket = new Socket(server.addr);
 641
 642            socket.transform('outgoing', function (data, next) {
 643              setTimeout(function () {
 644                next(undefined, false);
 645
 646                setTimeout(function () {
 647                  socket.end();
 648                  done();
 649                }, 100);
 650              }, 10);
 651            });
 652
 653            socket.on('outgoing::data', function () {
 654              throw new Error('return false should prevent this emit');
 655            }).write('foo');
 656          });
 657        });
 658
 659        describe('incoming', function () {
 660          it('rewrites the incoming message', function (done) {
 661            var socket = new Socket(server.addr);
 662
 663            primus.on('connection', function (spark) {
 664              spark.write('foo');
 665            });
 666
 667            socket.transform('incoming', function (data) {
 668              expect(data).to.be.a('object');
 669              expect(data.data).to.equal('foo');
 670
 671              data.data = {
 672                message: 'foo',
 673                meta: 'meta'
 674              };
 675            });
 676
 677            socket.on('data', function (data) {
 678              expect(data).to.be.a('object');
 679              expect(data.meta).to.equal('meta');
 680              expect(data.message).to.equal('foo');
 681
 682              socket.end();
 683              done();
 684            });
 685          });
 686
 687          it('rewrites the incoming message async', function (done) {
 688            var socket = new Socket(server.addr);
 689
 690            primus.on('connection', function (spark) {
 691              spark.write('foo');
 692            });
 693
 694            socket.transform('incoming', function (data, next) {
 695              expect(data).to.be.a('object');
 696              expect(data.data).to.equal('foo');
 697
 698              setTimeout(function () {
 699                data.data = {
 700                  message: 'foo',
 701                  meta: 'meta'
 702                };
 703
 704                next();
 705              }, 100);
 706            });
 707
 708            socket.on('data', function (data) {
 709              expect(data).to.be.a('object');
 710              expect(data.meta).to.equal('meta');
 711              expect(data.message).to.equal('foo');
 712
 713              socket.end();
 714              done();
 715            });
 716          });
 717
 718          it('prevents the message from being emitted', function (done) {
 719            var socket = new Socket(server.addr);
 720
 721            primus.on('connection', function (spark) {
 722              spark.write('foo');
 723            });
 724
 725            socket.transform('incoming', function (data) {
 726              setTimeout(function () {
 727                socket.end();
 728                done();
 729              }, 0);
 730
 731              return false;
 732            });
 733
 734            socket.on('data', function () {
 735              throw new Error('return false should prevent this emit');
 736            });
 737          });
 738
 739          it('prevents the message from being emitted async', function (done) {
 740            var socket = new Socket(server.addr);
 741
 742            primus.on('connection', function (spark) {
 743              spark.write('foo');
 744            });
 745
 746            socket.transform('incoming', function (data, next) {
 747              setTimeout(function () {
 748                setTimeout(function () {
 749                  socket.end();
 750                  done();
 751                }, 100);
 752
 753                next(undefined, false);
 754              }, 10);
 755            });
 756
 757            socket.on('data', function () {
 758              throw new Error('return false should prevent this emit');
 759            });
 760          });
 761        });
 762      });
 763    });
 764
 765    describe('.createSocket', function () {
 766      it('can connect to the server', function (done) {
 767        var PSocket = Primus.createSocket({
 768              transformer: transformer,
 769              pathname: server.pathname
 770            })
 771          , socket = new PSocket(server.addr);
 772
 773        socket.on('open', function () {
 774          socket.end();
 775          done();
 776        });
 777      });
 778
 779      it('should accept plugins', function (done) {
 780        var PSocket = Primus.createSocket({
 781              transformer: transformer,
 782              pathname: server.pathname,
 783              plugin: {
 784                emit: emitter
 785              }
 786            })
 787          , socket = new PSocket(server.addr);
 788
 789        expect(socket.$emit).to.be.a('function');
 790        socket.on('open', function () {
 791          socket.end();
 792          done();
 793        });
 794      });
 795    });
 796
 797    describe('Authorization', function () {
 798      it('support declined authorization', function (done) {
 799        primus.authorize(function auth(req, next) {
 800          expect(req.headers).to.be.a('object');
 801
 802          next(new Error('I failed'));
 803        });
 804
 805        primus.on('connection', function (spark) {
 806          throw new Error('Auth should be called');
 807        });
 808
 809        var Socket = Primus.createSocket({
 810              transformer: transformer,
 811              pathname: server.pathname,
 812              authorization: true
 813            })
 814          , socket = new Socket(server.addr);
 815
 816        socket.on('end', done);
 817        socket.on('reconnect', function () {
 818          throw new Error('fuck');
 819        });
 820      });
 821
 822      it('support declined authorization with status code', function (done) {
 823        primus.authorize(function auth(req, next) {
 824          expect(req.headers).to.be.a('object');
 825
 826          var err = new Error('I failed');
 827          err.statusCode = 404;
 828
 829          next(err);
 830        });
 831
 832        primus.on('connection', function (spark) {
 833          throw new Error('Auth should be called');
 834        });
 835
 836        var Socket = Primus.createSocket({
 837              transformer: transformer,
 838              pathname: server.pathname,
 839              authorization: true
 840            })
 841          , socket = new Socket(server.addr);
 842
 843        socket.on('end', done);
 844        socket.on('reconnect', function () {
 845          throw new Error('fuck');
 846        });
 847      });
 848
 849      it('support declined authorization with message and www-authenticate header', function (done) {
 850        primus.authorize(function auth(req, next) {
 851          expect(req.headers).to.be.a('object');
 852
 853          var err = new Error('I failed');
 854          err.authenticate = 'Basic realm="primus"';
 855
 856          next(err);
 857        });
 858
 859        primus.on('connection', function (spark) {
 860          throw new Error('Auth should be called');
 861        });
 862
 863        var Socket = Primus.createSocket({
 864              transformer: transformer,
 865              pathname: server.pathname,
 866              authorization: true
 867            })
 868          , socket = new Socket(server.addr);
 869
 870        socket.on('outgoing::open', function () {
 871          if (socket.socket.on) {
 872            socket.socket.on('unexpected-response', function (req, res) {
 873              expect(res.statusCode).to.equal(401);
 874              expect(res.headers['www-authenticate']).to.equal('Basic realm="primus"');
 875
 876              var data = '';
 877
 878              res.on('data', function (v) {
 879                data += v;
 880              });
 881
 882              res.on('end', function () {
 883                var obj = JSON.parse(data);
 884                expect(obj).to.eql({error: 'I failed'});
 885                socket.socket.emit('error', new Error(obj.error));
 886              });
 887            });
 888          }
 889        });
 890
 891        socket.on('end', done);
 892        socket.on('reconnect', function () {
 893          throw new Error('reconnect should not be called');
 894        });
 895      });
 896
 897      it('support accepted authorization', function (done) {
 898        primus.authorize(function auth(req, next) {
 899          expect(req.headers).to.be.a('object');
 900
 901          next();
 902        });
 903
 904        primus.on('connection', function (spark) {
 905          spark.end();
 906        });
 907
 908        var socket = new Socket(server.addr);
 909
 910        socket.on('end', done);
 911        socket.on('reconnect', function () {
 912          throw new Error('fuck');
 913        });
 914      });
 915
 916      it('communicates over an authorized connection', function (done) {
 917        primus.authorize(function auth(req, next) {
 918          expect(req.headers).to.be.a('object');
 919
 920          setTimeout(next, 20);
 921        });
 922
 923        primus.on('connection', function (spark) {
 924          spark.on('data', function (data) {
 925            expect(data).to.equal('balls');
 926            spark.end();
 927          });
 928        });
 929
 930        var socket = new Socket(server.addr);
 931        socket.on('end', done);
 932        socket.write('balls');
 933      });
 934
 935      if (transformer.toLowerCase() === 'websockets')
 936      it('should connect using basic auth', function (done) {
 937        primus.on('connection', function (spark) {
 938          expect(spark.headers.authorization).to.equal('Basic dXNyOnBhc3M=');
 939          socket.end();
 940        });
 941
 942        var socket = new Socket(server.make_addr('usr:pass', '?foo=bar'));
 943        socket.on('end', done);
 944      });
 945
 946      it('should emit a timeout event if it cannot connect in a timely manner', function (done) {
 947        primus.authorize(function (req, next) {
 948          setTimeout(next, 1000);
 949        });
 950
 951        var socket = new Socket(server.make_addr('usr:pass', '?foo=bar'), {
 952          timeout: 500
 953        });
 954
 955        socket.on('timeout', done);
 956      });
 957
 958      it('should reconnect after the timeout', function (done) {
 959        primus.authorize(function (req, next) {
 960          setTimeout(next, 1000);
 961        });
 962
 963        var socket = new Socket(server.addr, { timeout: 10 })
 964          , pattern = [];
 965
 966        socket.on('timeout', function () {
 967          pattern.push('timeout');
 968        });
 969
 970        socket.once('reconnecting', function () {
 971          pattern.push('reconnecting');
 972        });
 973
 974        socket.once('reconnect', function () {
 975          pattern.push('reconnect');
 976          expect(pattern.join(',')).to.equal('timeout,reconnecting,reconnect');
 977
 978          socket.end();
 979          // outgoing::reconnect is emitted after reconnect whatever we do
 980          socket.removeAllListeners('outgoing::reconnect');
 981          done();
 982        });
 983      });
 984    });
 985
 986    describe('Server', function () {
 987      it('emits a `connection` event before any `data` event', function (done) {
 988        var create = 10
 989          , foo = 0;
 990
 991        primus.on('connection', function (spark) {
 992          spark.on('data', function (data) {
 993            if ('foo' === data) {
 994              if (++foo === create) done();
 995            }
 996          });
 997        });
 998
 999        for (var i = 0; i < create; i++) {
1000          (new Socket(server.addr)).write('foo');
1001        }
1002      });
1003
1004      it('emits `end` when the connection is closed', function (done) {
1005        primus.on('connection', function (spark) {
1006          spark.on('end', done);
1007        });
1008
1009        var socket = new Socket(server.addr);
1010
1011        socket.on('open', function () {
1012          socket.end();
1013        });
1014      });
1015
1016      it('should emit an `error` when it fails to encode the data', function (done) {
1017        primus.on('connection', function (spark) {
1018          var data = { foo: 'bar' };
1019          data.recusrive = data;
1020
1021          spark.on('error', function (err) {
1022            expect(err).to.not.be.a('string');
1023            expect(err.message).to.include('JSON');
1024
1025            socket.end();
1026            done();
1027          });
1028
1029          spark.write(data);
1030        });
1031
1032        var socket = new Socket(server.addr);
1033      });
1034
1035      it('should receive querystrings', function (done) {
1036        primus.on('connection', function (spark) {
1037          expect(spark.query).to.be.a('object');
1038
1039          if (
1040            (transformer.toLowerCase() !== 'sockjs') &&
1041            (transformer_name.toLowerCase() !== 'unixdomainwebsockets')
1042          ) {
1043            expect(spark.query.foo).to.equal('bar');
1044          }
1045
1046          socket.end();
1047        });
1048
1049        var socket = new Socket(server.make_addr(null, '?foo=bar'));
1050        socket.on('end', done);
1051      });
1052
1053      it('should receive all headers', function (done) {
1054        primus.on('connection', function (spark) {
1055          expect(spark.headers).to.be.a('object');
1056          expect(spark.headers).to.have.property('connection');
1057
1058          socket.end();
1059        });
1060
1061        var socket = new Socket(server.make_addr(null, '?foo=bar'));
1062        socket.on('end', done);
1063      });
1064
1065      it('should not trigger a reconnect when we end the connection', function (done) {
1066        primus.on('connection', function (spark) {
1067          spark.end();
1068        });
1069
1070        var socket = new Socket(server.addr);
1071
1072        socket.on('end', done);
1073        socket.on('reconnect', function () {
1074          throw new Error('fuck');
1075        });
1076      });
1077
1078      if (transformer_name.toLowerCase() !== 'unixdomainwebsockets') {
1079      it('should still allow requests to the original listener', function (done) {
1080        request(
1081          server.addr +'/nothrow',
1082          function (err, res, body) {
1083            if (err) return done(err);
1084
1085            expect(body).to.equal('original listener');
1086            done();
1087          }
1088        );
1089      });
1090
1091      it('responds to library requests', function (done) {
1092        request(
1093          server.addr + '/primus/primus.js',
1094          function (err, res, body) {
1095            if (err) return done(err);
1096
1097            expect(res.statusCode).to.equal(200);
1098            expect(res.headers['content-type']).to.equal('text/javascript; charset=utf-8');
1099            expect(body).to.equal(primus.library());
1100            done();
1101          }
1102        );
1103      });
1104
1105      it('handles requests to non existing routes captured by primus', function (done) {
1106        this.timeout(100);
1107        request(
1108          server.addr + '/primus.js',
1109          function (err, res, body) {
1110            if (err) return done(err);
1111
1112            done();
1113          }
1114        );
1115      });
1116
1117      it('correctly handles requests when a middleware returns an error', function (done) {
1118        primus.before('foo', function foo(req, res, next) {
1119          next(new Error('foo failed'));
1120        });
1121
1122        primus.on('connection', function (spark) {
1123          throw new Error('connection should not be triggered');
1124        });
1125
1126        var socket = new Socket(server.addr, { strategy: false });
1127        socket.on('end', done);
1128      });
1129
1130      it('correctly parses the ip address', function (done) {
1131        primus.on('connection', function (spark) {
1132          var address = spark.address;
1133          expect(address.port).to.not.equal(0);
1134          expect(address.port).to.not.equal(server.portnumber);
1135
1136          spark.end();
1137          done();
1138        });
1139
1140        var socket = new Socket(server.addr);
1141      });
1142      } // !unixdomainwebsockets
1143
1144      it('uses x-forwarded headers over the connection ip address', function (done) {
1145        primus.on('connection', function (spark) {
1146          spark.headers['x-forwarded-for'] = '13.3.37.1,12.12.12.12';
1147          spark.headers['x-forwarded-port'] = '9083,1334';
1148
1149          expect(spark.address.ip).to.equal('13.3.37.1');
1150          expect(spark.address.port).to.equal(9083);
1151
1152          spark.end();
1153          done();
1154        });
1155
1156        var socket = new Socket(server.addr);
1157      });
1158
1159      if (transformer_name.toLowerCase() !== 'unixdomainwebsockets') {
1160      it('exposes a spec file with the correct transformer', function (done) {
1161        request(
1162          server.addr +'/primus/spec',
1163          function (err, res, body) {
1164            if (err) return done(err);
1165            body = JSON.parse(body);
1166
1167            expect(body.transformer).to.equal(transformer.toLowerCase());
1168            expect(body.version).to.equal(primus.version);
1169            expect(body.pathname).to.equal('/primus');
1170            expect(body.parser).to.equal('json');
1171            done();
1172          }
1173        );
1174      });
1175      } // !unixdomainwebsockets
1176
1177      it('doesnt crash when we write to a closed connection', function (done) {
1178        primus.on('connection', function (spark) {
1179          spark.on('end', function () {
1180            spark.write('I should not crash');
1181
1182            setTimeout(function () {
1183              spark.write('the server should ignore me');
1184
1185              setTimeout(done, 10);
1186            }, 10);
1187          });
1188        });
1189
1190        var socket = new Socket(server.addr);
1191        socket.on('open', function () {
1192          socket.end();
1193        });
1194      });
1195
1196      it('should make the spark available to the parser', function (done) {
1197        var rnd = Math.random(),
1198            parser = primus.parser;
1199
1200        primus.parsers({
1201          decoder: function (data, fn) {
1202            expect(this.foobar).to.equal(rnd);
1203            parser.decoder.call(this, data, function (err, decoded) {
1204              expect(err).not.to.exist;
1205              expect(decoded).to.eql({ echo: 'pong' });
1206              fn(null, decoded);
1207            });
1208          },
1209
1210          encoder: function (data, fn) {
1211            expect(this.foobar).to.equal(rnd);
1212            parser.encoder.call(this, data, fn);
1213            if (data === 'pong') {
1214              done();
1215            }
1216          }
1217        });
1218
1219        primus.on('connection', function (spark) {
1220          spark.foobar = rnd;
1221        });
1222
1223        var socket = new Socket(server.addr);
1224
1225        socket.on('open', function () {
1226          socket.write({ echo: 'pong' });
1227        });
1228      });
1229
1230      describe('#transform', function () {
1231        it('thrown an error if an invalid type is given', function (done) {
1232          try { primus.transform('cowsack', function () {}); }
1233          catch (e) {
1234            expect(e.message).to.contain('transformer');
1235            done();
1236          }
1237        });
1238
1239        describe('outgoing', function () {
1240          it('rewrites the outgoing message', function (done) {
1241            primus.transform('outgoing', function (data) {
1242              expect(data).to.be.a('object');
1243              expect(data.data).to.equal('foo');
1244
1245              data.data = {
1246                message: 'foo',
1247                meta: 'meta'
1248              };
1249            });
1250
1251            primus.on('connection', function (spark) {
1252              setTimeout(function () {
1253                spark.write('foo');
1254              }, 10);
1255            });
1256
1257            var socket = new Socket(server.addr);
1258
1259            socket.on('data', function (data) {
1260              expect(data).to.be.a('object');
1261              expect(data.meta).to.equal('meta');
1262              expect(data.message).to.equal('foo');
1263
1264              socket.end();
1265              done();
1266            });
1267          });
1268
1269          it('prevents the message from being written', function (done) {
1270            primus.transform('outgoing', function () {
1271              setTimeout(function () {
1272                socket.end();
1273                done();
1274              }, 0);
1275
1276              return false;
1277            });
1278
1279            primus.on('connection', function (spark) {
1280              spark.on('outgoing::data', function (data) {
1281                if (~data.indexOf('foo')) throw new Error('return false should prevent this emit');
1282              });
1283
1284              spark.write('foo');
1285            });
1286
1287            var socket = new Socket(server.addr);
1288          });
1289        });
1290
1291        describe('incoming', function () {
1292          it('rewrites the incoming message', function (done) {
1293            primus.transform('incoming', function (data) {
1294              expect(data).to.be.a('object');
1295              expect(data.data).to.equal('foo');
1296
1297              data.data = {
1298                message: 'foo',
1299                meta: 'meta'
1300              };
1301            });
1302
1303            primus.on('connection', function (spark) {
1304              spark.on('data', function (data) {
1305                expect(data).to.be.a('object');
1306                expect(data.meta).to.equal('meta');
1307                expect(data.message).to.equal('foo');
1308
1309                spark.end();
1310                done();
1311              });
1312            });
1313
1314            var socket = new Socket(server.addr);
1315            socket.write('foo');
1316          });
1317
1318          it('prevents the message from being emitted', function (done) {
1319            primus.transform('incoming', function (data) {
1320              setTimeout(function () {
1321                socket.end();
1322                done();
1323              }, 0);
1324
1325              return false;
1326            });
1327
1328            primus.on('connection', function (spark) {
1329              spark.on('data', function () {
1330                throw new Error('return false should prevent this emit');
1331              });
1332            });
1333
1334            var socket = new Socket(server.addr);
1335            socket.write('foo');
1336          });
1337        });
1338      });
1339
1340      describe('#id', function () {
1341        it('should receive the id', function (done) {
1342          primus.on('connection', function (spark) {
1343            socket.id(function (id) {
1344              expect(id).to.equal(spark.id);
1345              spark.end();
1346              done();
1347            });
1348          });
1349
1350          var socket = new Socket(server.addr);
1351        });
1352      });
1353    });
1354  });
1355};