PageRenderTime 70ms CodeModel.GetById 2ms app.highlight 60ms RepoModel.GetById 1ms 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
   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, 'json', 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          }, 100);
 198        });
 199
 200        var socket = new Socket(server.addr);
 201
 202        socket.once('open', function () {
 203          socket.once('end', function () {
 204            socket.open();
 205
 206            socket.once('open', function () {
 207              socket.once('end', done);
 208            });
 209          });
 210        });
 211      });
 212
 213      it('emits a readyStateChange event', function (done) {
 214        var socket = new Socket(server.addr)
 215          , state = socket.readyState
 216          , calls = 0;
 217
 218        socket.on('readyStateChange', function () {
 219          expect(state).to.not.equal(socket.readyState);
 220          state = socket.readyState;
 221
 222          calls++;
 223        });
 224
 225        socket.on('open', function () {
 226          expect(!!socket.socket).to.equal(true);
 227          socket.end();
 228        }).on('end', function () {
 229          expect(calls).to.equal(3);
 230          done();
 231        });
 232      });
 233
 234      it('emits an `end` event when its closed', function (done) {
 235        var socket = new Socket(server.addr);
 236
 237        socket.on('open', function () {
 238          socket.end();
 239        }).on('end', done);
 240      });
 241
 242      it('emits an `close` event when its closed', function (done) {
 243        var socket = new Socket(server.addr);
 244
 245        socket.on('open', function () {
 246          socket.end();
 247        }).on('close', done);
 248      });
 249
 250      it('only emits `end` once', function (done) {
 251        var socket = new Socket(server.addr);
 252
 253        socket.on('open', function () {
 254          socket.end();
 255          socket.end();
 256          socket.end();
 257          socket.end();
 258          socket.end();
 259          socket.end();
 260        }).on('end', done);
 261      });
 262
 263      it('sends & receives messages', function (done) {
 264        var socket = new Socket(server.addr);
 265
 266        socket.on('data', function (message) {
 267          expect(message).to.equal('pong');
 268          socket.end();
 269          done();
 270        });
 271
 272        socket.on('open', function () {
 273          socket.write({ echo: 'pong' });
 274        });
 275      });
 276
 277      it('receives the raw packet data', function (done) {
 278        var socket = new Socket(server.addr);
 279
 280        socket.on('data', function (message, raw) {
 281          var data = JSON.stringify(message);
 282          expect(message).to.equal('pong');
 283
 284          expect(raw).to.not.equal(message);
 285          expect(data).to.equal(raw);
 286
 287          socket.end();
 288          done();
 289        });
 290
 291        socket.on('open', function () {
 292          socket.write({ echo: 'pong' });
 293        });
 294      });
 295
 296      it('emits an `error` event when it cannot encode the data', function (done) {
 297        var socket = new Socket(server.addr);
 298
 299        socket.on('open', function () {
 300          var data = { foo: 'bar' };
 301          data.recusrive = data;
 302
 303          socket.write(data);
 304        }).on('error', function (err) {
 305          expect(err).to.not.be.instanceOf(String);
 306          expect(err.message).to.contain('JSON');
 307
 308          socket.end();
 309          done();
 310        });
 311      });
 312
 313      it('buffers messages before it connected', function (done) {
 314        var socket = new Socket(server.addr)
 315          , messages = 10
 316          , received = 0;
 317
 318        for (var i = 0; i <= messages; i++) {
 319          socket.write({ echo: i });
 320        }
 321
 322        socket.on('data', function (message) {
 323          expect(message).to.be.a('number');
 324
 325          if (++received === messages) {
 326            socket.end();
 327            done();
 328          }
 329        });
 330      });
 331
 332      it('should not reconnect when we close the connection', function (done) {
 333        var socket = new Socket(server.addr);
 334
 335        socket.on('open', function (message) {
 336          socket.end();
 337          done();
 338        });
 339
 340        socket.on('reconnect', function () {
 341          throw new Error('fuck');
 342        });
 343      });
 344
 345      it('should clean up timers', function (done) {
 346        primus.on('connection', function (spark) {
 347          if (!reconnected) {
 348            reconnected = true;
 349            return spark.end(null, { reconnect: true });
 350          }
 351          spark.end();
 352        });
 353
 354        var socket = new Socket(server.addr)
 355          , reconnected = false
 356          , closed = 0
 357          , opened = 0;
 358
 359        socket.on('open', function () {
 360          if (++opened === 1) {
 361            expect(Object.keys(socket.timers).length).to.be.above(0);
 362            return;
 363          }
 364          expect(Object.keys(socket.timers).length).to.be.equal(0);
 365        });
 366
 367        socket.on('close', function () {
 368          closed++;
 369          expect(Object.keys(socket.timers).length).to.equal(0);
 370        });
 371
 372        socket.on('end', function () {
 373          expect(closed).to.be.equal(2);
 374          done();
 375        });
 376      });
 377
 378      it('should not reconnect when strategy is false', function (done) {
 379        primus.on('connection', function (spark) {
 380          //
 381          // Kill a connection to trigger a reconnect
 382          //
 383          spark.end(null, { reconnect: true });
 384        });
 385
 386        var socket = new Socket(server.addr, { strategy: false });
 387
 388        socket.on('reconnect', function (message) {
 389          throw new Error('bad');
 390        });
 391
 392        socket.on('end', done);
 393      });
 394
 395      //
 396      // This also tests the reconnection when the connection closes unexpectedly
 397      //
 398      it('should allow to trigger a client-side reconnect from server', function (done) {
 399        primus.on('connection', function (spark) {
 400          if (!reconnected) {
 401            reconnected = true;
 402            spark.end(null, { reconnect: true });
 403          }
 404        });
 405
 406        var socket = new Socket(server.addr)
 407          , reconnected = false
 408          , reconnect = false
 409          , opened = 0;
 410
 411        socket.on('reconnect', function (message) {
 412          reconnect = true;
 413        });
 414
 415        socket.on('open', function () {
 416          if (++opened !== 2) return;
 417
 418          expect(reconnect).to.equal(true);
 419          socket.end();
 420        });
 421
 422        socket.on('end', done);
 423      });
 424
 425      it('should allow to stop the reconnection procedure', function (done) {
 426        primus.on('connection', function (spark) {
 427          spark.end(null, { reconnect: true });
 428        });
 429
 430        var socket = new Socket(server.addr);
 431
 432        socket.on('reconnecting', socket.end);
 433
 434        socket.on('reconnect', function (message) {
 435          throw new Error('bad');
 436        });
 437
 438        socket.on('end', done);
 439      });
 440
 441      it('should allow access to the original HTTP request', function (done) {
 442        primus.on('connection', function (spark) {
 443          expect(spark.request).to.not.equal(undefined);
 444          expect(spark.request.headers).to.be.a('object');
 445
 446          //
 447          // Timeout is added to ensure that a request had time to get closed.
 448          // As closed requests could add a bunch of issues.
 449          //
 450          setTimeout(function () {
 451            expect(spark.request).to.not.equal(undefined);
 452            spark.end();
 453            done();
 454          }, 100);
 455        });
 456
 457        var socket = new Socket(server.addr);
 458      });
 459
 460      it('should not increment the attempt if a backoff is running', function (done) {
 461        var socket = new Socket(server.addr);
 462
 463        var backoff = {}
 464          , result = socket.backoff(function () {
 465              socket.end();
 466            }, backoff);
 467
 468        expect(backoff.attempt).to.equal(1);
 469        expect(result).to.equal(socket);
 470
 471        result = socket.backoff(function () {
 472          throw new Error('I should not be called yo');
 473        }, backoff);
 474
 475        expect(backoff.attempt).to.equal(1);
 476        expect(result).to.equal(socket);
 477
 478        socket.on('end', done);
 479      });
 480
 481      it('should reset the reconnect details after a succesful reconnect', function (done) {
 482        var socket = new Socket(server.addr, {
 483          reconnect: {
 484            minDelay: 100,
 485            maxDelay: 2000
 486          }
 487        }), closed = 0;
 488
 489        expect(!socket.attempt).to.equal(true);
 490        this.timeout(5000);
 491
 492        socket.once('reconnect', function () {
 493          expect(!!socket.attempt).to.equal(true);
 494          expect(socket.attempt.attempt).to.be.above(0);
 495          expect(socket.attempt.minDelay).to.equal(100);
 496          expect(socket.attempt.maxDelay).to.equal(2000);
 497          expect(socket.attempt.timeout).to.be.below(2000);
 498          expect(socket.attempt.timeout).to.be.above(99);
 499        });
 500
 501        socket.once('open', function () {
 502          try { server.close(); destroy(); }
 503          catch (e) { return done(e); }
 504
 505          setTimeout(function () {
 506            var services = create(transformer, 'json', function () {}, server.portnumber);
 507
 508            destroy = services.destroy;
 509            Socket = services.Socket;
 510            server = services.server;
 511            primus = services.primus;
 512          }, 100);
 513
 514          socket.once('open', function () {
 515            socket.removeAllListeners('end');
 516            socket.end();
 517
 518            // once from the reconnect, and once from the .end above
 519            expect(closed).to.equal(2);
 520            done();
 521          });
 522        });
 523
 524        socket.on('close', function () {
 525          closed++;
 526        });
 527
 528        socket.on('end', function () {
 529          done(new Error('I shouldnt end'));
 530        });
 531      });
 532
 533      it('can force websocket avoidance', function (done) {
 534        var socket = new Socket(server.addr, {
 535          websockets: false
 536        });
 537
 538        expect(socket.AVOID_WEBSOCKETS).to.equal(true);
 539
 540        // open is done in a setTimeout 0 so if we end it now then we'll
 541        // miss the connection
 542        socket.on('open', function () {
 543            socket.end();
 544        });
 545
 546        done();
 547      });
 548
 549      it('supports async connection events', function (done) {
 550        var pre;
 551
 552        primus.on('connection', function (spark, next) {
 553          setTimeout(function () {
 554            pre = 'async';
 555            next();
 556          }, 10);
 557        });
 558
 559        primus.on('connection', function (spark) {
 560          expect(pre).to.equal('async');
 561          spark.end();
 562          done();
 563        });
 564
 565        //
 566        // Connect AFTER the things are called
 567        //
 568        var socket = new Socket(server.addr);
 569      });
 570
 571      describe('#transform', function () {
 572        it('thrown an error if an invalid type is given', function (done) {
 573          var socket = new Socket(server.addr);
 574
 575          primus.on('connection', function (spark) {
 576            spark.end();
 577            done();
 578          });
 579
 580          try { socket.transform('cowsack', function () {}); }
 581          catch (e) {
 582            expect(e.message).to.contain('transformer');
 583          }
 584        });
 585
 586        describe('outgoing', function () {
 587          it('rewrites the outgoing message', function (done) {
 588            var socket = new Socket(server.addr);
 589
 590            primus.on('connection', function (spark) {
 591              spark.on('data', function (data) {
 592                expect(data).to.be.a('object');
 593                expect(data.meta).to.equal('meta');
 594                expect(data.message).to.equal('foo');
 595
 596                spark.end();
 597                done();
 598              });
 599            });
 600
 601            socket.transform('outgoing', function (data) {
 602              expect(data).to.be.a('object');
 603              expect(data.data).to.equal('foo');
 604
 605              data.data = {
 606                message: 'foo',
 607                meta: 'meta'
 608              };
 609            });
 610
 611            socket.write('foo');
 612          });
 613
 614          it('rewrites the outgoing message async', function (done) {
 615            var socket = new Socket(server.addr);
 616
 617            primus.on('connection', function (spark) {
 618              spark.on('data', function (data) {
 619                expect(data).to.be.a('object');
 620                expect(data.meta).to.equal('meta');
 621                expect(data.message).to.equal('foo');
 622
 623                spark.end();
 624                done();
 625              });
 626            });
 627
 628            socket.transform('outgoing', function (data, next) {
 629              expect(data).to.be.a('object');
 630              expect(data.data).to.equal('foo');
 631
 632              setTimeout(function () {
 633                data.data = {
 634                  message: 'foo',
 635                  meta: 'meta'
 636                };
 637
 638                next();
 639              }, 10);
 640            });
 641
 642            socket.write('foo');
 643          });
 644
 645          it('prevents the message from being written', function (done) {
 646            var socket = new Socket(server.addr);
 647
 648            socket.transform('outgoing', function (data) {
 649              setTimeout(function () {
 650                socket.end();
 651                done();
 652              }, 0);
 653
 654              return false;
 655            });
 656
 657            socket.on('outgoing::data', function () {
 658              throw new Error('return false should prevent this emit');
 659            }).write('foo');
 660          });
 661
 662          it('prevents the message from being written async', function (done) {
 663            var socket = new Socket(server.addr);
 664
 665            socket.transform('outgoing', function (data, next) {
 666              setTimeout(function () {
 667                next(undefined, false);
 668
 669                setTimeout(function () {
 670                  socket.end();
 671                  done();
 672                }, 100);
 673              }, 10);
 674            });
 675
 676            socket.on('outgoing::data', function () {
 677              throw new Error('return false should prevent this emit');
 678            }).write('foo');
 679          });
 680        });
 681
 682        describe('incoming', function () {
 683          it('rewrites the incoming message', function (done) {
 684            var socket = new Socket(server.addr);
 685
 686            primus.on('connection', function (spark) {
 687              spark.write('foo');
 688            });
 689
 690            socket.transform('incoming', function (data) {
 691              expect(data).to.be.a('object');
 692              expect(data.data).to.equal('foo');
 693
 694              data.data = {
 695                message: 'foo',
 696                meta: 'meta'
 697              };
 698            });
 699
 700            socket.on('data', function (data) {
 701              expect(data).to.be.a('object');
 702              expect(data.meta).to.equal('meta');
 703              expect(data.message).to.equal('foo');
 704
 705              socket.end();
 706              done();
 707            });
 708          });
 709
 710          it('rewrites the incoming message async', function (done) {
 711            var socket = new Socket(server.addr);
 712
 713            primus.on('connection', function (spark) {
 714              spark.write('foo');
 715            });
 716
 717            socket.transform('incoming', function (data, next) {
 718              expect(data).to.be.a('object');
 719              expect(data.data).to.equal('foo');
 720
 721              setTimeout(function () {
 722                data.data = {
 723                  message: 'foo',
 724                  meta: 'meta'
 725                };
 726
 727                next();
 728              }, 100);
 729            });
 730
 731            socket.on('data', function (data) {
 732              expect(data).to.be.a('object');
 733              expect(data.meta).to.equal('meta');
 734              expect(data.message).to.equal('foo');
 735
 736              socket.end();
 737              done();
 738            });
 739          });
 740
 741          it('prevents the message from being emitted', function (done) {
 742            var socket = new Socket(server.addr);
 743
 744            primus.on('connection', function (spark) {
 745              spark.write('foo');
 746            });
 747
 748            socket.transform('incoming', function (data) {
 749              setTimeout(function () {
 750                socket.end();
 751                done();
 752              }, 0);
 753
 754              return false;
 755            });
 756
 757            socket.on('data', function () {
 758              throw new Error('return false should prevent this emit');
 759            });
 760          });
 761
 762          it('prevents the message from being emitted async', function (done) {
 763            var socket = new Socket(server.addr);
 764
 765            primus.on('connection', function (spark) {
 766              spark.write('foo');
 767            });
 768
 769            socket.transform('incoming', function (data, next) {
 770              setTimeout(function () {
 771                setTimeout(function () {
 772                  socket.end();
 773                  done();
 774                }, 100);
 775
 776                next(undefined, false);
 777              }, 10);
 778            });
 779
 780            socket.on('data', function () {
 781              throw new Error('return false should prevent this emit');
 782            });
 783          });
 784        });
 785      });
 786    });
 787
 788    describe('.createSocket', function () {
 789      it('can connect to the server', function (done) {
 790        var PSocket = Primus.createSocket({
 791              transformer: transformer,
 792              pathname: server.pathname
 793            })
 794          , socket = new PSocket(server.addr);
 795
 796        socket.on('open', function () {
 797          socket.end();
 798          done();
 799        });
 800      });
 801
 802      it('should accept plugins', function (done) {
 803        var PSocket = Primus.createSocket({
 804              transformer: transformer,
 805              pathname: server.pathname,
 806              plugin: {
 807                emit: emitter
 808              }
 809            })
 810          , socket = new PSocket(server.addr);
 811
 812        expect(socket.$emit).to.be.a('function');
 813        socket.on('open', function () {
 814          socket.end();
 815          done();
 816        });
 817      });
 818    });
 819
 820    describe('Authorization', function () {
 821      it('support declined authorization', function (done) {
 822        primus.authorize(function auth(req, next) {
 823          expect(req.headers).to.be.a('object');
 824
 825          next(new Error('I failed'));
 826        });
 827
 828        primus.on('connection', function (spark) {
 829          throw new Error('Auth should be called');
 830        });
 831
 832        var Socket = Primus.createSocket({
 833              transformer: transformer,
 834              pathname: server.pathname,
 835              authorization: true
 836            })
 837          , socket = new Socket(server.addr);
 838
 839        socket.on('end', done);
 840        socket.on('reconnect', function () {
 841          throw new Error('fuck');
 842        });
 843      });
 844
 845      it('support declined authorization with status code', function (done) {
 846        primus.authorize(function auth(req, next) {
 847          expect(req.headers).to.be.a('object');
 848
 849          var err = new Error('I failed');
 850          err.statusCode = 404;
 851
 852          next(err);
 853        });
 854
 855        primus.on('connection', function (spark) {
 856          throw new Error('Auth should be called');
 857        });
 858
 859        var Socket = Primus.createSocket({
 860              transformer: transformer,
 861              pathname: server.pathname,
 862              authorization: true
 863            })
 864          , socket = new Socket(server.addr);
 865
 866        socket.on('end', done);
 867        socket.on('reconnect', function () {
 868          throw new Error('fuck');
 869        });
 870      });
 871
 872      it('support declined authorization with message and www-authenticate header', function (done) {
 873        primus.authorize(function auth(req, next) {
 874          expect(req.headers).to.be.a('object');
 875
 876          var err = new Error('I failed');
 877          err.authenticate = 'Basic realm="primus"';
 878
 879          next(err);
 880        });
 881
 882        primus.on('connection', function (spark) {
 883          throw new Error('Auth should be called');
 884        });
 885
 886        var Socket = Primus.createSocket({
 887              transformer: transformer,
 888              pathname: server.pathname,
 889              authorization: true
 890            })
 891          , socket = new Socket(server.addr);
 892
 893        socket.on('outgoing::open', function () {
 894          if (socket.socket.on) {
 895            socket.socket.on('unexpected-response', function (req, res) {
 896              expect(res.statusCode).to.equal(401);
 897              expect(res.headers['www-authenticate']).to.equal('Basic realm="primus"');
 898
 899              var data = '';
 900
 901              res.on('data', function (v) {
 902                data += v;
 903              });
 904
 905              res.on('end', function () {
 906                var obj = JSON.parse(data);
 907                expect(obj).to.eql({error: 'I failed'});
 908                socket.socket.emit('error', new Error(obj.error));
 909              });
 910            });
 911          }
 912        });
 913
 914        socket.on('end', done);
 915        socket.on('reconnect', function () {
 916          throw new Error('reconnect should not be called');
 917        });
 918      });
 919
 920      it('support accepted authorization', function (done) {
 921        primus.authorize(function auth(req, next) {
 922          expect(req.headers).to.be.a('object');
 923
 924          next();
 925        });
 926
 927        primus.on('connection', function (spark) {
 928          spark.end();
 929        });
 930
 931        var socket = new Socket(server.addr);
 932
 933        socket.on('end', done);
 934        socket.on('reconnect', function () {
 935          throw new Error('fuck');
 936        });
 937      });
 938
 939      it('communicates over an authorized connection', function (done) {
 940        primus.authorize(function auth(req, next) {
 941          expect(req.headers).to.be.a('object');
 942
 943          setTimeout(next, 20);
 944        });
 945
 946        primus.on('connection', function (spark) {
 947          spark.on('data', function (data) {
 948            expect(data).to.equal('balls');
 949            spark.end();
 950          });
 951        });
 952
 953        var socket = new Socket(server.addr);
 954        socket.on('end', done);
 955        socket.write('balls');
 956      });
 957
 958      it('receives pre-parsed ip adresses', function (done) {
 959        primus.authorize(function auth(req, next) {
 960          expect(req.forwarded).to.be.a('object');
 961          expect(req.forwarded.ip).to.be.a('string');
 962          expect(req.forwarded.port).to.be.a('number');
 963
 964          setTimeout(next, 0);
 965        });
 966
 967        primus.on('connection', function (spark) {
 968          spark.end();
 969        });
 970
 971        var socket = new Socket(server.addr);
 972        socket.on('end', done);
 973        socket.write('balls');
 974      });
 975
 976      if (transformer.toLowerCase() === 'websockets')
 977      it('should connect using basic auth', function (done) {
 978        primus.on('connection', function (spark) {
 979          expect(spark.headers.authorization).to.equal('Basic dXNyOnBhc3M=');
 980          socket.end();
 981        });
 982
 983        var socket = new Socket(server.make_addr('usr:pass', '?foo=bar'));
 984        socket.on('end', done);
 985      });
 986
 987      it('should emit a timeout event if it cannot connect in a timely manner', function (done) {
 988        primus.authorize(function (req, next) {
 989          setTimeout(next, 1000);
 990        });
 991
 992        var socket = new Socket(server.make_addr('usr:pass', '?foo=bar'), {
 993          timeout: 500
 994        });
 995
 996        socket.on('timeout', done);
 997      });
 998
 999      it('should reconnect after the timeout', function (done) {
1000        primus.authorize(function (req, next) {
1001          setTimeout(next, 1000);
1002        });
1003
1004        var socket = new Socket(server.addr, { timeout: 10 })
1005          , pattern = [];
1006
1007        socket.on('timeout', function () {
1008          pattern.push('timeout');
1009        });
1010
1011        socket.once('reconnecting', function () {
1012          pattern.push('reconnecting');
1013        });
1014
1015        socket.once('reconnect', function () {
1016          pattern.push('reconnect');
1017          expect(pattern.join(',')).to.equal('timeout,reconnecting,reconnect');
1018
1019          socket.end();
1020          // outgoing::reconnect is emitted after reconnect whatever we do
1021          socket.removeAllListeners('outgoing::reconnect');
1022          done();
1023        });
1024      });
1025    });
1026
1027    describe('Server', function () {
1028      it('emits a `connection` event before any `data` event', function (done) {
1029        var create = 10
1030          , foo = 0;
1031
1032        primus.on('connection', function (spark) {
1033          spark.on('data', function (data) {
1034            if ('foo' === data) {
1035              if (++foo === create) done();
1036            }
1037          });
1038        });
1039
1040        for (var i = 0; i < create; i++) {
1041          (new Socket(server.addr)).write('foo');
1042        }
1043      });
1044
1045      it('emits `end` when the connection is closed', function (done) {
1046        primus.on('connection', function (spark) {
1047          spark.on('end', done);
1048        });
1049
1050        var socket = new Socket(server.addr);
1051
1052        socket.on('open', function () {
1053          socket.end();
1054        });
1055      });
1056
1057      it('should emit an `error` when it fails to encode the data', function (done) {
1058        primus.on('connection', function (spark) {
1059          var data = { foo: 'bar' };
1060          data.recusrive = data;
1061
1062          spark.on('error', function (err) {
1063            expect(err).to.not.be.a('string');
1064            expect(err.message).to.include('JSON');
1065
1066            socket.end();
1067            done();
1068          });
1069
1070          spark.write(data);
1071        });
1072
1073        var socket = new Socket(server.addr);
1074      });
1075
1076      it('should receive querystrings', function (done) {
1077        primus.on('connection', function (spark) {
1078          expect(spark.query).to.be.a('object');
1079
1080          if (
1081            (transformer.toLowerCase() !== 'sockjs') &&
1082            (transformer_name.toLowerCase() !== 'unixdomainwebsockets')
1083          ) {
1084            expect(spark.query.foo).to.equal('bar');
1085          }
1086
1087          socket.end();
1088        });
1089
1090        var socket = new Socket(server.make_addr(null, '?foo=bar'));
1091        socket.on('end', done);
1092      });
1093
1094      it('should receive all headers', function (done) {
1095        primus.on('connection', function (spark) {
1096          expect(spark.headers).to.be.a('object');
1097          expect(spark.headers).to.have.property('connection');
1098
1099          socket.end();
1100        });
1101
1102        var socket = new Socket(server.make_addr(null, '?foo=bar'));
1103        socket.on('end', done);
1104      });
1105
1106      it('should not trigger a reconnect when we end the connection', function (done) {
1107        primus.on('connection', function (spark) {
1108          spark.end();
1109        });
1110
1111        var socket = new Socket(server.addr);
1112
1113        socket.on('end', done);
1114        socket.on('reconnect', function () {
1115          throw new Error('fuck');
1116        });
1117      });
1118
1119      if (transformer_name.toLowerCase() !== 'unixdomainwebsockets') {
1120      it('should still allow requests to the original listener', function (done) {
1121        request(
1122          server.addr +'/nothrow',
1123          function (err, res, body) {
1124            if (err) return done(err);
1125
1126            expect(body).to.equal('original listener');
1127            done();
1128          }
1129        );
1130      });
1131
1132      it('responds to library requests', function (done) {
1133        request(
1134          server.addr + '/primus/primus.js',
1135          function (err, res, body) {
1136            if (err) return done(err);
1137
1138            expect(res.statusCode).to.equal(200);
1139            expect(res.headers['content-type']).to.equal('text/javascript; charset=utf-8');
1140            expect(body).to.equal(primus.library());
1141            done();
1142          }
1143        );
1144      });
1145
1146      it('handles requests to non existing routes captured by primus', function (done) {
1147        this.timeout(100);
1148        request(
1149          server.addr + '/primus.js',
1150          function (err, res, body) {
1151            if (err) return done(err);
1152
1153            done();
1154          }
1155        );
1156      });
1157
1158      it('correctly handles requests when a middleware returns an error', function (done) {
1159        primus.before('foo', function foo(req, res, next) {
1160          next(new Error('foo failed'));
1161        });
1162
1163        primus.on('connection', function (spark) {
1164          throw new Error('connection should not be triggered');
1165        });
1166
1167        var socket = new Socket(server.addr, { strategy: false });
1168        socket.on('end', done);
1169      });
1170
1171      it('correctly parses the ip address', function (done) {
1172        primus.on('connection', function (spark) {
1173          var address = spark.address;
1174          expect(address.port).to.not.equal(0);
1175          expect(address.port).to.not.equal(server.portnumber);
1176
1177          spark.end();
1178          done();
1179        });
1180
1181        var socket = new Socket(server.addr);
1182      });
1183      } // !unixdomainwebsockets
1184
1185      it('uses x-forwarded headers over the connection ip address', function (done) {
1186        primus.on('connection', function (spark) {
1187          spark.headers['x-forwarded-for'] = '13.3.37.1,12.12.12.12';
1188          spark.headers['x-forwarded-port'] = '9083,1334';
1189
1190          //
1191          // Side note here, we don't want to re-use the detection from the
1192          // middleware here as we don't want to go through the hassle of adding
1193          // a real-proxy in our tests. We merely want to test if it will look
1194          // at the x-forwarded-headers instead of the pure IP address.
1195          //
1196          delete spark.request.forwarded;
1197
1198          expect(spark.address.ip).to.equal('13.3.37.1');
1199          expect(spark.address.port).to.equal(9083);
1200
1201          spark.end();
1202          done();
1203        });
1204
1205        var socket = new Socket(server.addr);
1206      });
1207
1208      if (transformer_name.toLowerCase() !== 'unixdomainwebsockets') {
1209      it('exposes a spec file with the correct transformer', function (done) {
1210        request(
1211          server.addr +'/primus/spec',
1212          function (err, res, body) {
1213            if (err) return done(err);
1214            body = JSON.parse(body);
1215
1216            expect(body.transformer).to.equal(transformer.toLowerCase());
1217            expect(body.version).to.equal(primus.version);
1218            expect(body.pathname).to.equal('/primus');
1219            expect(body.parser).to.equal('json');
1220            done();
1221          }
1222        );
1223      });
1224      } // !unixdomainwebsockets
1225
1226      it('doesnt crash when we write to a closed connection', function (done) {
1227        primus.on('connection', function (spark) {
1228          spark.on('end', function () {
1229            spark.write('I should not crash');
1230
1231            setTimeout(function () {
1232              spark.write('the server should ignore me');
1233
1234              setTimeout(done, 10);
1235            }, 10);
1236          });
1237        });
1238
1239        var socket = new Socket(server.addr);
1240        socket.on('open', function () {
1241          socket.end();
1242        });
1243      });
1244
1245      it('should make the spark available to the parser', function (done) {
1246        var rnd = Math.random(),
1247            parser = primus.parser;
1248
1249        primus.parsers({
1250          decoder: function (data, fn) {
1251            expect(this.foobar).to.equal(rnd);
1252            parser.decoder.call(this, data, function (err, decoded) {
1253              expect(err).not.to.exist;
1254              expect(decoded).to.eql({ echo: 'pong' });
1255              fn(null, decoded);
1256            });
1257          },
1258
1259          encoder: function (data, fn) {
1260            expect(this.foobar).to.equal(rnd);
1261            parser.encoder.call(this, data, fn);
1262            if (data === 'pong') {
1263              done();
1264            }
1265          }
1266        });
1267
1268        primus.on('connection', function (spark) {
1269          spark.foobar = rnd;
1270        });
1271
1272        var socket = new Socket(server.addr);
1273
1274        socket.on('open', function () {
1275          socket.write({ echo: 'pong' });
1276        });
1277      });
1278
1279      describe('#transform', function () {
1280        it('thrown an error if an invalid type is given', function (done) {
1281          try { primus.transform('cowsack', function () {}); }
1282          catch (e) {
1283            expect(e.message).to.contain('transformer');
1284            done();
1285          }
1286        });
1287
1288        describe('outgoing', function () {
1289          it('rewrites the outgoing message', function (done) {
1290            primus.transform('outgoing', function (data) {
1291              expect(data).to.be.a('object');
1292              expect(data.data).to.equal('foo');
1293
1294              data.data = {
1295                message: 'foo',
1296                meta: 'meta'
1297              };
1298            });
1299
1300            primus.on('connection', function (spark) {
1301              setTimeout(function () {
1302                spark.write('foo');
1303              }, 10);
1304            });
1305
1306            var socket = new Socket(server.addr);
1307
1308            socket.on('data', function (data) {
1309              expect(data).to.be.a('object');
1310              expect(data.meta).to.equal('meta');
1311              expect(data.message).to.equal('foo');
1312
1313              socket.end();
1314              done();
1315            });
1316          });
1317
1318          it('prevents the message from being written', function (done) {
1319            primus.transform('outgoing', function () {
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('outgoing::data', function (data) {
1330                if (~data.indexOf('foo')) throw new Error('return false should prevent this emit');
1331              });
1332
1333              spark.write('foo');
1334            });
1335
1336            var socket = new Socket(server.addr);
1337          });
1338        });
1339
1340        describe('incoming', function () {
1341          it('rewrites the incoming message', function (done) {
1342            primus.transform('incoming', function (data) {
1343              expect(data).to.be.a('object');
1344              expect(data.data).to.equal('foo');
1345
1346              data.data = {
1347                message: 'foo',
1348                meta: 'meta'
1349              };
1350            });
1351
1352            primus.on('connection', function (spark) {
1353              spark.on('data', function (data) {
1354                expect(data).to.be.a('object');
1355                expect(data.meta).to.equal('meta');
1356                expect(data.message).to.equal('foo');
1357
1358                spark.end();
1359                done();
1360              });
1361            });
1362
1363            var socket = new Socket(server.addr);
1364            socket.write('foo');
1365          });
1366
1367          it('prevents the message from being emitted', function (done) {
1368            primus.transform('incoming', function (data) {
1369              setTimeout(function () {
1370                socket.end();
1371                done();
1372              }, 0);
1373
1374              return false;
1375            });
1376
1377            primus.on('connection', function (spark) {
1378              spark.on('data', function () {
1379                throw new Error('return false should prevent this emit');
1380              });
1381            });
1382
1383            var socket = new Socket(server.addr);
1384            socket.write('foo');
1385          });
1386        });
1387      });
1388
1389      describe('#id', function () {
1390        it('should receive the id', function (done) {
1391          primus.on('connection', function (spark) {
1392            socket.id(function (id) {
1393              expect(id).to.equal(spark.id);
1394              spark.end();
1395              done();
1396            });
1397          });
1398
1399          var socket = new Socket(server.addr);
1400        });
1401      });
1402    });
1403  });
1404};