HEX
Server: nginx/1.24.0
System: Linux nowruzgan 6.8.0-57-generic #59-Ubuntu SMP PREEMPT_DYNAMIC Sat Mar 15 17:40:59 UTC 2025 x86_64
User: babak (1000)
PHP: 8.3.6
Disabled: NONE
Upload Files
File: /var/dev/nowruzgan/rest/node_modules/sails-hook-sockets/test/sails.sockets.test.js
/**
 * Module dependencies
 */

var util = require('util');
var assert = require('assert');
var async = require('async');
var _ = require('@sailshq/lodash');

var lifecycle = require('./helpers/lifecycle.helper');
var ERRORPACK = require('../lib/errors');



describe('low-level socket methods:', function (){

  before(lifecycle.setup);
  after(lifecycle.teardown);

  var sails;

  before(function() {
    sails = global._sails;
  });

  // Set up helper routes for the tests below
  before(function(){
    sails.get('/socketMethods/helpers/getIdOfRequestingSocket', function(req, res){
      return res.send(req.socket.id);
    });
  });





  // Use the globalized default sails instance
  var TEST_SERVER_PORT = 1577;


  // Connect a few additional sockets for use in the tests below
  // (these will hold **CLIENT-SIDE** SOCKETS!!)
  var starks = {
    ned: undefined,
    bran: undefined,
    jon: undefined,
    arya: undefined,
    sansa: undefined,
    ricket: undefined// or whatever his name is
  };

  // Create a variable to reference our original `io.socket` (the auto-connecting guy)
  // (these will hold a **CLIENT-SIDE** SOCKET!!)
  var theKing;

  before(function (done){

    // Thematically relevant reference to `io.socket`
    theKing = io.socket;
    // console.log('ok, now we\'ve connected the initial socket, let\'s connect some more...');
    async.each(_.keys(starks), function (key, next){
      // console.log('connecting socket for %s',key);
      starks[key] = io.sails.connect('http://localhost:'+TEST_SERVER_PORT, {
        multiplex: false
      });
      starks[key].on('connect', function(){
        // console.log('socket for %s connected!', key);
        next();
      });
    }, function (err) {
      if (err) return done(err);
      done(err);
    });

  });

  // •----------------------------------------•
  //
  //   ||   Nullipotent functions
  //   \/
  //
  // •----------------------------------------•


  describe('sails.sockets.get()', function (done){


    it('should throw USAGE error when called w/ no arguments', function (){
      assert.throws(function (){
        sails.sockets.get();
      }, ERRORPACK.USAGE.constructor);
    });
    it('should throw USAGE error when called w/ invalid socket id', function (){
      assert.throws(function (){
        sails.sockets.get([
          {
            something:'totally invalid'
          }
        ]);
      }, ERRORPACK.USAGE.constructor);
    });

    it('should return undefined when called w/ string or integer id which does not correspond w/ real socket', function (){
      assert.throws(function (){
        sails.sockets.get(7);
      }, ERRORPACK.NO_SUCH_SOCKET.constructor);
      assert.throws(function (){
        sails.sockets.get('7');
      }, ERRORPACK.NO_SUCH_SOCKET.constructor);
    });

    it('should return a Socket when called w/ a socket id which points to a real socket', function (done){

      _getSocketId(theKing, function (err, socketId) {
        if (err) return done(err);
        try {
          var socket = sails.sockets.get(socketId);
          assert(socket, 'expected socket to exist');
          assert(_.isString(socket.id), 'expected socket to look like a real Socket');
          assert(_.isFunction(socket.emit), 'expected socket to look like a real Socket');
        }
        catch (e) {
          return done(e);
        }
        return done();
      });
    });

  });

  describe('sails.sockets.getId()', function (done){

    var actualSocketId;
    before(function (){
      sails.get('/socketMethods/sails.sockets.getid', function (req, res){
        actualSocketId = req.socket.id;

        var result1 = sails.sockets.getId(req.socket);
        assert.equal(result1, actualSocketId);

        var result2 = sails.sockets.getId(req);
        assert.equal(result2, result1);

        return res.send(result1);
      });
    });

    it('should not crash or throw', function (done){
      theKing.get('/socketMethods/sails.sockets.getid', function (data, jwr){
        if (jwr.error) return done(jwr.error);
        return done();
      });
    });

    it('should return a string', function (done){
      theKing.get('/socketMethods/sails.sockets.getid', function (data, jwr){
        if (jwr.error) return done(jwr.error);
        assert(typeof data === 'string', 'should have returned a string, but instead got:'+data);
        return done();
      });
    });

    it('should return the proper socket id', function (done){
      theKing.get('/socketMethods/sails.sockets.getid', function (data, jwr){
        if (jwr.error) return done(jwr.error);
        assert.equal(data, actualSocketId, 'should have returned the proper socketId ('+actualSocketId+'), but instead got:'+data);
        return done();
      });
    });

  });




  describe('sails.sockets.join()', function (){
    before(function _setupRoutes(){
      sails.put('/socketMethods/join', function (req, res){
        // console.log('socket %s joining room %s', sails.sockets.id(req.socket), req.param('room'));
        sails.sockets.join(req, req.param('room'));
        return res.send();
      });
    });

    before(function _setupRoutes(){
      sails.put('/socketMethods/join_with_socket', function (req, res){
        // console.log('socket %s joining room %s', sails.sockets.id(req.socket), req.param('room'));
        sails.sockets.join(req.socket, req.param('room'));
        return res.send();
      });
    });

    before(function _setupRoutes(){
      sails.put('/socketMethods/join_with_id', function (req, res){
        // console.log('socket %s joining room %s', sails.sockets.id(req.socket), req.param('room'));
        sails.sockets.join(req.socket.id, req.param('room'));
        return res.send();
      });
    });

    describe('with a request object as argument', function() {
      it('should not crash', function (done){
        starks.bran.put('/socketMethods/join', {
          room: 'test'
        }, function (data, jwr) {
          if (jwr.error) return done(jwr.error);
          return done();
        });
      });
    });

    describe('with a socket object as argument', function() {
      it('should not crash', function (done){
        starks.bran.put('/socketMethods/join_with_socket', {
          room: 'test'
        }, function (data, jwr) {
          if (jwr.error) return done(jwr.error);
          return done();
        });
      });
    });

    describe('with a socket id as argument', function() {
      it('should not crash', function (done){
        starks.bran.put('/socketMethods/join_with_id', {
          room: 'test'
        }, function (data, jwr) {
          if (jwr.error) return done(jwr.error);
          return done();
        });
      });
    });

    describe('sails.sockets.leave()', function (done){
      before(function(){
        sails.delete('/socketMethods/leave', function(req, res){
          sails.sockets.leave(req, req.param('room'), function(err) {
            if (err) {return res.serverError(err);}
            var socket = sails.sockets.parseSocket(req.socket);
            // Return the list of rooms this socket is assigned to.
            // Since socket.io v1.4, rooms is an object
            var rooms = _.keys(socket.rooms);
            return res.json(rooms);
          });
        });
        sails.delete('/socketMethods/leave_with_socket', function(req, res){
          var result1 = sails.sockets.leave(req.socket, req.param('room'));
          return res.send(result1);
        });
        sails.delete('/socketMethods/leave_with_id', function(req, res){
          var result1 = sails.sockets.leave(req.socket.id, req.param('room'));
          return res.send(result1);
        });
      });
      before(function(done) {
        theKing.put('/socketMethods/join', { room: 'beast1' }, function (data, jwr) {
          theKing.put('/socketMethods/join', { room: 'beast2' }, function (data, jwr) {
            return done();
          });
        });
      });
      describe('with a request object as the first argument', function() {
        it('should remove the target room from the list of rooms a socket is connected to', function (done){
          theKing.delete('/socketMethods/leave', { room: 'beast1' }, function (rooms, jwr) {
            if (jwr.error) return done(jwr.error);
            assert.equal(rooms.length, 2, 'expected it to return a membership of 2 rooms; instead got '+util.inspect(rooms));
            assert(_.indexOf(rooms, 'beast1') === -1, 'expected `beast1` to have been removed from room membership list, but room membership is still: '+rooms);
            return done();
          });
        });
        it('should warn and not error if passing in null socket', function(done) {
          // Testing fix for #6
          var origWarn = sails.log.warn;
          var sawWarning = false;
          sails.log.warn = function(msg) {
            sawWarning = true;
            origWarn.apply(this, arguments);
            sails.log.warn = origWarn;
          };
          sails.sockets.leave(null);
          assert.equal(sawWarning, true);
          done();
        });
      });
      describe('with a socket object as the first argument', function() {
        it('should not crash', function(done) {
          theKing.delete('/socketMethods/leave_with_socket', {
            room: 'beast1'
          }, function (data, jwr) {
            if (jwr.error) return done(jwr.error);
            return done();
          });
        });
      });
      describe('with a socket id as the first argument', function() {
        it('should not crash', function(done) {
          theKing.delete('/socketMethods/leave_with_id', {
            room: 'beast1'
          }, function (data, jwr) {
            if (jwr.error) return done(jwr.error);
            return done();
          });
        });
      });
    });
  });




  describe('sails.sockets.broadcast()', function (done){
    before(function(done){
      sails.post('/socketMethods/broadcast', function(req, res){

        // supply "socketToOmit"
        var eventName = 'message';
        sails.sockets.broadcast(req.param('room'), eventName, req.param('data'), req);
        return res.send();
      });

      done();
    });

    describe('king\'s announcement', function (){

      before(function (done){

        // Have all of our starks except for Ned join the 'winterfell' room,
        // AND start listening for "message" events.
        async.each(_.keys(starks), function (key, next){

          // (skip ned)
          if (key === 'ned') return next();

          var clientSocket = starks[key];

          // Listen for message events
          clientSocket.on('message', function (event){
            clientSocket._testMsgsReceived = clientSocket._testMsgsReceived || [];
            clientSocket._testMsgsReceived.push(event);
          });

          // Join the "winterfell" room.
          clientSocket.put('/socketMethods/join', {
            room: 'winterfell'
          }, function (data, jwr) {
            if (jwr.error) return next(jwr.error);
            return next();
          });
        }, function (err){
          if (err) return done(err);

          // Now have the king also join "winterfell"...
          theKing.put('/socketMethods/join', {
            room: 'winterfell'
          }, function (data, jwr){
            if (jwr.error) return next(jwr.error);

            // ...listen for his own announcemnt...
            // (which he should ignore, because our test "broadcast" endpoint below uses the `socketToOmit` arg)
            theKing.on('message', function (event){
              theKing._testMsgsReceived = theKing._testMsgsReceived || [];
              theKing._testMsgsReceived.push(event);
            });

            // ...and make his announcement.
            theKing.post('/socketMethods/broadcast', {
              room: 'winterfell',
              data: {
                stuff: 'and things'
              }
            }, function (data, jwr) {
              if (jwr.error) return done(jwr.error);

              // wait a moment to give socket.io time to deliver the messages
              setTimeout(function (){
                done();
              }, 250);
            });

          });

        });

      });

      describe('living Starks (broadcast to room members)', function (){
        it('should have received a message', function (){
          _.each(starks, function (clientSocket, key){
            // Skip ned
            if (key === 'ned') {
              return;
            }
            assert(clientSocket._testMsgsReceived.length === 1, 'expecting 1 message to be received for the living starks, but got '+clientSocket._testMsgsReceived.length);
          });
        });
      });

      describe('Ned Stark (dont broadcast to outsiders)', function (){
        it('should not have received a message', function (){
          assert(!starks.ned._testMsgsReceived, 'expecting `_testMsgsReceived` to not exist, since no msgs were to be received for ned, but got '+util.inspect(starks.ned._testMsgsReceived));
        });
      });

      describe('The King (dont broadcast to `socketToOmit`)', function (){
        it('should not have received a message (since we used the `socketToOmit` arg)', function (){
          assert(!theKing._testMsgsReceived, 'expecting `_testMsgsReceived` to not exist, since no msgs were to be received for king, but got '+util.inspect(theKing._testMsgsReceived));
        });
      });
    });

  });




  describe('sails.sockets.broadcast() to socket rooms', function (done){
    before(function(){
      sails.post('/socketMethods/broadcastToSocketd', function(req, res){
        sails.sockets.broadcast(req.param('recipients'), undefined, req.param('data'));
        return res.send();
      });
      sails.post('/socketMethods/broadcastToSocketd/otherworldly', function(req, res){
        sails.sockets.broadcast(req.param('recipients'), 'otherworldly', req.param('data'));
        return res.send();
      });
    });

    before(function (done){

      // Look up the socket ids for each Stark
      var starkSocketIds = {};
      async.each(_.keys(starks), function (key, next){
        var clientSocket = starks[key];

        // Listen for the "otherwordly" event type
        clientSocket.on('otherworldly', function(event){
          clientSocket._otherworldlyMsgsReceived = clientSocket._otherworldlyMsgsReceived || [];
          clientSocket._otherworldlyMsgsReceived.push(event);
        });

        // Listen for the "message" event type
        clientSocket.on('message', function(event){
          clientSocket._genericMsgsReceived = clientSocket._genericMsgsReceived || [];
          clientSocket._genericMsgsReceived.push(event);
        });

        // Lookup socket id
        _getSocketId(clientSocket, function (err,socketId){
          if (err) return next(err);
          starkSocketIds[key] = socketId;
          return next();
        });
      }, function afterwards(err) {
        if (err) return done(err);

        // Now have each one of them emit a message to Ned
        async.each(_.keys(starks), function (firstName, next){
          // (skip ned)
          if (firstName === 'ned') return next();

          starks[firstName].post('/socketMethods/broadcastToSocketd/otherworldly', {
            recipients: starkSocketIds.ned,
            data: 'hi pops!'
          }, function (data, jwr){
            if (jwr.error) return next(jwr.error);
            return next();
          });
        }, function (err){
          if (err) return done(err);

          // Now have ricket (or whatever his name is) send a generic message to ned
          starks.ricket.post('/socketMethods/broadcastToSocketd', {
            recipients: starkSocketIds.ned,
            data: 'hi pops!'
          }, function (data, jwr){
            if (jwr.error) return done(jwr.error);

            // Now have Ned emit a message back addressing everyone else
            var arrayOfLivingStarkSocketIds = _.reduce(starkSocketIds, function (memo, socketId, firstName){
              if (firstName !== 'ned') memo.push(socketId);
              return memo;
            }, []);
            starks.ned.post('/socketMethods/broadcastToSocketd/otherworldly', {
              recipients: arrayOfLivingStarkSocketIds,
              data: 'hello children'
            }, function (data, jwr){
              if (jwr.error) return done(jwr.error);
              return done();
            });
          });

        });

      });

    });

    it('should not crash', function (done){
      done();
    });

    describe('living starks', function (){
      it('should have received 1 "otherwordly" msg', function(){
        _.each(starks, function (clientSocket, firstName) {
          // (skip ned)
          if (firstName === 'ned') {
            return;
          }
          assert.equal(clientSocket._otherworldlyMsgsReceived.length, 1, 'expected '+(_.keys(starks).length-1)+' "otherworldly" message for '+firstName+', but got '+clientSocket._otherworldlyMsgsReceived.length);
        });
      });
    });
    describe('ned', function (){
      it('should have received many "otherwordly" msgs', function(){
        assert.equal(starks.ned._otherworldlyMsgsReceived.length, (_.keys(starks).length-1), 'expected '+(_.keys(starks).length-1)+' "otherworldly" messages for Ned, but got '+starks.ned._otherworldlyMsgsReceived.length);
      });
      it('should have received one generic msg from ricket (or whatever his name is)', function(){
        assert.equal(starks.ned._genericMsgsReceived.length, 1, 'expected 1 generic message for Ned, but got '+starks.ned._genericMsgsReceived.length);
      });
    });

  });


  describe('sails.sockets.blast()', function (){
    before(function(){

      // Have the king and all starks listen for the dark mark
      var socketsWhoListenTotheDarkmark = [theKing].concat(_.values(starks));
      // console.log('sockets lisening for the darkmark:', socketsWhoListenTotheDarkmark);
      _.each(socketsWhoListenTotheDarkmark, function (clientSocket, firstName){
        clientSocket.on('darkmark', function (event){
          clientSocket._darkmarkMsgReceived = clientSocket._darkmarkMsgReceived || [];
          clientSocket._darkmarkMsgReceived.push(event);
        });
      });

      sails.post('/socketMethods/blast', function(req, res){
        sails.sockets.blast('darkmark', {
          stuff: 'yeah'
        });
        return res.send();
      });
    });

    it('should send a message to everyone (all starks)', function (done){
      theKing.post('/socketMethods/blast', function (data, jwr) {
        if (jwr.error) return done(jwr.error);

        // Wait a moment to give the sockets time to receive the msg
        setTimeout(function (){
          assert.equal(starks.ned._darkmarkMsgReceived.length, 1, 'expected Ned to receive 1 "darkmark" message, but got '+util.inspect(starks.ned._darkmarkMsgReceived, false, null));
          assert.equal(starks.bran._darkmarkMsgReceived.length, 1, 'expected bran to receive 1 "darkmark" message, but got '+util.inspect(starks.bran._darkmarkMsgReceived, false, null));
          assert.equal(starks.ricket._darkmarkMsgReceived.length, 1, 'expected ricket to receive 1 "darkmark" message, but got '+util.inspect(starks.ricket._darkmarkMsgReceived, false, null));
          assert.equal(starks.arya._darkmarkMsgReceived.length, 1, 'expected arya to receive 1 "darkmark" message, but got '+util.inspect(starks.arya._darkmarkMsgReceived, false, null));
          assert.equal(starks.sansa._darkmarkMsgReceived.length, 1, 'expected sansa to receive 1 "darkmark" message, but got '+util.inspect(starks.sansa._darkmarkMsgReceived, false, null));
          return done();
        }, 500);

      });
    });
  });


});






// Helper methods:
//

/**
 * Given a client-side socket, get its socket id.
 *
 * @param  {[type]}   clientSocket [description]
 * @param  {Function} cb           [description]
 * @return {[type]}                [description]
 */
function _getSocketId(clientSocket, cb){
  clientSocket.get('/socketMethods/helpers/getIdOfRequestingSocket', function (data, jwr){
    if (jwr.statusCode < 200 || jwr.statusCode > 300 || !jwr.body) {
      return cb(new Error('Unexpected result from test helper (statusCode='+jwr.statusCode+', body='+util.inspect(jwr.body, false, null)+')'));
    }
    return cb(null, jwr.body);
  });
}