<commit_before>'use strict';

const expect = require('chai').expect;
const f = require('util').format;
const setupDatabase = require('./shared').setupDatabase;

describe('Cursor tests', function() {
  before(function() {
    return setupDatabase(this.configuration);
  });

  it('Should iterate cursor', {
    metadata: {
      requires: { topology: ['single', 'replicaset', 'sharded'] }
    },

    test: function(done) {
      const server = this.configuration.newTopology();
      server.on('connect', function(_server) {
        var ns = f('integration_tests.cursor1');
        // Execute the write
        _server.insert(
          ns,
          [{ a: 1 }, { a: 2 }, { a: 3 }],
          {
            writeConcern: { w: 1 },
            ordered: true
          },
          function(err, results) {
            expect(err).to.be.null;
            expect(results.result.n).to.equal(3);

            // Execute find
            var cursor = _server.cursor(ns, {
              find: ns,
              query: {},
              batchSize: 2
            });

            // Execute next
            cursor.next(function(nextCursorErr, nextCursorD) {
              expect(nextCursorErr).to.be.null;
              expect(nextCursorD.a).to.equal(1);
              expect(cursor.bufferedCount()).to.equal(1);

              // Kill the cursor
              cursor.next(function(killCursorErr, killCursorD) {
                expect(killCursorErr).to.be.null;
                expect(killCursorD.a).to.equal(2);
                expect(cursor.bufferedCount()).to.equal(0);
                // Destroy the server connection
                _server.destroy();
                // Finish the test
                done();
              });
            });
          }
        );
      });

      // Start connection
      server.connect();
    }
  });

  it('Should iterate cursor but readBuffered', {
    metadata: {
      requires: { topology: ['single', 'replicaset', 'sharded'] }
    },

    test: function(done) {
      const server = this.configuration.newTopology();
      var ns = f('%s.cursor2', this.configuration.db);
      // Add event listeners
      server.on('connect', function(_server) {
        // Execute the write
        _server.insert(
          ns,
          [{ a: 1 }, { a: 2 }, { a: 3 }, { a: 4 }, { a: 5 }],
          {
            writeConcern: { w: 1 },
            ordered: true
          },
          function(err, results) {
            expect(err).to.be.null;
            expect(results.result.n).to.equal(5);

            // Execute find
            var cursor = _server.cursor(ns, {
              find: ns,
              query: {},
              batchSize: 5
            });

            // Execute next
            cursor.next(function(nextCursorErr, nextCursorD) {
              expect(nextCursorErr).to.be.null;
              expect(nextCursorD.a).to.equal(1);
              expect(cursor.bufferedCount()).to.equal(4);

              // Read the buffered Count
              cursor.readBufferedDocuments(cursor.bufferedCount());

              // Get the next item
              cursor.next(function(secondCursorErr, secondCursorD) {
                expect(secondCursorErr).to.be.null;
                expect(secondCursorD).to.be.null;

                // Destroy the server connection
                _server.destroy();
                // Finish the test
                done();
              });
            });
          }
        );
      });

      // Start connection
      server.connect();
    }
  });

  it('Should callback exhausted cursor with error', {
    metadata: {
      requires: { topology: ['single', 'replicaset', 'sharded'] }
    },

    test: function(done) {
      const server = this.configuration.newTopology();
      var ns = f('%s.cursor3', this.configuration.db);
      // Add event listeners
      server.on('connect', function(_server) {
        // Execute the write
        _server.insert(
          ns,
          [{ a: 1 }],
          {
            writeConcern: { w: 1 },
            ordered: true
          },
          function(err, results) {
            expect(err).to.be.null;
            expect(results.result.n).to.equal(1);

            // Execute find
            var cursor = _server.cursor(ns, { find: ns, query: {}, batchSize: 5 });

            // Execute next
            cursor.next(function(nextCursorErr, nextCursorD) {
              expect(nextCursorErr).to.be.null;
              expect(nextCursorD.a).to.equal(1);

              // Get the next item
              cursor.next(function(secondCursorErr, secondCursorD) {
                expect(secondCursorErr).to.be.null;
                expect(secondCursorD).to.be.null;

                cursor.next(function(thirdCursorErr, thirdCursorD) {
                  expect(thirdCursorErr).to.be.ok;
                  expect(thirdCursorD).to.be.undefined;
                  // Destroy the server connection
                  _server.destroy();
                  // Finish the test
                  done();
                });
              });
            });
          }
        );
      });

      // Start connection
      server.connect();
    }
  });

  it('Should force a getMore call to happen', {
    metadata: {
      requires: { topology: ['single', 'replicaset', 'sharded'] }
    },

    test: function(done) {
      const server = this.configuration.newTopology();
      var ns = f('%s.cursor4', this.configuration.db);
      // Add event listeners
      server.on('connect', function(_server) {
        // Execute the write
        _server.insert(
          ns,
          [{ a: 1 }, { a: 2 }, { a: 3 }],
          {
            writeConcern: { w: 1 },
            ordered: true
          },
          function(err, results) {
            expect(err).to.be.null;
            expect(results.result.n).to.equal(3);

            // Execute find
            var cursor = _server.cursor(ns, { find: ns, query: {}, batchSize: 2 });

            // Execute next
            cursor.next(function(nextCursorErr, nextCursorD) {
              expect(nextCursorErr).to.be.null;
              expect(nextCursorD.a).to.equal(1);

              // Get the next item
              cursor.next(function(secondCursorErr, secondCursorD) {
                expect(secondCursorErr).to.be.null;
                expect(secondCursorD.a).to.equal(2);

                cursor.next(function(thirdCursorErr, thirdCursorD) {
                  expect(thirdCursorErr).to.be.null;
                  expect(thirdCursorD.a).to.equal(3);
                  // Destroy the server connection
                  _server.destroy();
                  // Finish the test
                  done();
                });
              });
            });
          }
        );
      });

      // Start connection
      server.connect();
    }
  });

  it('Should force a getMore call to happen then call killCursor', {
    metadata: {
      requires: { topology: ['single', 'replicaset', 'sharded'] }
    },

    test: function(done) {
      const server = this.configuration.newTopology();
      var ns = f('%s.cursor4', this.configuration.db);
      // Add event listeners
      server.on('connect', function(_server) {
        // Execute the write
        _server.insert(
          ns,
          [{ a: 1 }, { a: 2 }, { a: 3 }],
          {
            writeConcern: { w: 1 },
            ordered: true
          },
          function(err, results) {
            expect(err).to.be.null;
            expect(results.result.n).to.equal(3);

            // Execute find
            var cursor = _server.cursor(ns, { find: ns, query: {}, batchSize: 2 });

            // Execute next
            cursor.next(function(nextCursorErr, nextCursorD) {
              expect(nextCursorErr).to.be.null;
              expect(nextCursorD.a).to.equal(1);

              // Get the next item
              cursor.next(function(secondCursorErr, secondCursorD) {
                expect(secondCursorErr).to.be.null;
                expect(secondCursorD.a).to.equal(2);

                // Kill cursor
                cursor.kill(function() {
                  // Should error out
                  cursor.next(function(thirdCursorErr, thirdCursorD) {
                    expect(thirdCursorErr).to.not.exist;
                    expect(thirdCursorD).to.not.exist;

                    // Destroy the server connection
                    _server.destroy();
                    // Finish the test
                    done();
                  });
                });
              });
            });
          }
        );
      });

      // Start connection
      server.connect();
    }
  });

  // Skipped due to usage of the topology manager
  it.skip('Should fail cursor correctly after server restart', {
    metadata: {
      requires: { topology: ['single'] }
    },

    test: function(done) {
      var self = this;

      // Attempt to connect
      var server = new Server({
        host: this.configuration.host,
        port: this.configuration.port,
        bson: new Bson()
      });

      var ns = f('%s.cursor5', this.configuration.db);
      // Add event listeners
      server.on('connect', function(_server) {
        // Execute the write
        _server.insert(
          ns,
          [{ a: 1 }, { a: 2 }, { a: 3 }],
          {
            writeConcern: { w: 1 },
            ordered: true
          },
          function(err, results) {
            expect(err).to.be.null;
            expect(results.result.n).to.equal(3);

            // Execute find
            var cursor = _server.cursor(ns, { find: ns, query: {}, batchSize: 2 });

            // Execute next
            cursor.next(function(nextCursorErr, nextCursorD) {
              expect(nextCursorErr).to.be.null;
              expect(nextCursorD.a).to.equal(1);

              // Get the next item
              cursor.next(function(secondCursorErr, secondCursorD) {
                expect(secondCursorErr).to.be.null;
                expect(secondCursorD.a).to.equal(2);

                self.configuration.manager.restart(false).then(function() {
                  // Should error out
                  cursor.next(function(thirdCursorErr, thirdCursorD) {
                    expect(thirdCursorErr).to.be.ok;
                    expect(thirdCursorD).to.be.undefined;

                    // Destroy the server connection
                    _server.destroy();
                    // Finish the test
                    done();
                  });
                });
              });
            });
          }
        );
      });

      // Start connection
      server.connect();
    }
  });

  it('Should finish cursor correctly after all sockets to pool destroyed', {
    metadata: {
      requires: {
        topology: ['single'],
        os: '!darwin' // remove os restriction when SERVER-32477 is resolved
      }
    },

    test: function(done) {
      const server = this.configuration.newTopology();
      var ns = f('%s.cursor6', this.configuration.db);
      // Add event listeners
      server.on('connect', function(_server) {
        // Execute the write
        _server.insert(
          ns,
          [{ a: 1 }, { a: 2 }, { a: 3 }],
          {
            writeConcern: { w: 1 },
            ordered: true
          },
          function(err, results) {
            expect(err).to.be.null;
            expect(results.result.n).to.equal(3);

            // Execute find
            var cursor = _server.cursor(ns, { find: ns, query: {}, batchSize: 2 });

            // Execute next
            cursor.next(function(nextCursorErr, nextCursorD) {
              expect(nextCursorErr).to.be.null;
              expect(nextCursorD.a).to.equal(1);

              // Get the next item
              cursor.next(function(secondCursorErr, secondCursorD) {
                expect(secondCursorErr).to.be.null;
                expect(secondCursorD.a).to.equal(2);

                // Should be able to continue cursor after reconnect
                _server.once('reconnect', function() {
                  cursor.next(function(thirdCursorErr, thirdCursorD) {
                    expect(thirdCursorErr).to.be.null;
                    expect(thirdCursorD.a).to.equal(3);

                    // Destroy the server connection
                    _server.destroy();
                    // Finish the test
                    done();
                  });
                });

                // Destroy all active connections in the pool
                var connections = _server.s.pool.allConnections();
                for (var i = 0; i < connections.length; i++) {
                  connections[i].write('!@#!@#SADASDSA!@#!@#!@#!@#!@');
                }
              });
            });
          }
        );
      });

      // Start connection
      server.connect();
    }
  });

  it('Should not leak connnection workItem elements when using killCursor', {
    metadata: {
      requires: { topology: ['single'] }
    },

    test: function(done) {
      const server = this.configuration.newTopology();
      var ns = f('%s.cursor4', this.configuration.db);
      // Add event listeners
      server.on('connect', function(_server) {
        // Execute the write
        _server.insert(
          ns,
          [{ a: 1 }, { a: 2 }, { a: 3 }],
          {
            writeConcern: { w: 1 },
            ordered: true
          },
          function(err, results) {
            expect(err).to.be.null;
            expect(results.result.n).to.equal(3);

            // Execute find
            var cursor = _server.cursor(ns, { find: ns, query: {}, batchSize: 2 });

            // Execute next
            cursor.next(function(nextCursorErr, nextCursorD) {
              expect(nextCursorErr).to.be.null;
              expect(nextCursorD.a).to.equal(1);

              // Kill cursor
              cursor.kill(function() {
                // Add a small delay so that the work can be queued after the kill
                // callback has executed
                setImmediate(function() {
                  var connections = _server.s.pool.allConnections();
                  for (var i = 0; i < connections.length; i++) {
                    expect(connections[i].workItems.length).to.equal(0);
                  }

                  // Destroy the server connection
                  _server.destroy();
                  // Finish the test
                  done();
                }, 100);
              });
            });
          }
        );
      });

      // Start connection
      server.connect();
    }
  });

  // NOTE: a notoriously flakey test, needs rewriting
  it.skip('should not hang if autoReconnect=false and pools sockets all timed out', {
    metadata: { requires: { topology: ['single'] } },
    test: function(done) {
      var configuration = this.configuration,
        Server = require('../../../lib/topologies/server'),
        bson = require('bson');

      // Attempt to connect
      var server = new Server({
        host: configuration.host,
        port: configuration.port,
        bson: new bson(),
        // Nasty edge case: small timeout, small pool, no auto reconnect
        socketTimeout: 250,
        size: 1,
        reconnect: false
      });

      var ns = f('%s.cursor7', configuration.db);
      server.on('connect', function() {
        // Execute the write
        server.insert(
          ns,
          [{ a: 1 }],
          {
            writeConcern: { w: 1 },
            ordered: true
          },
          function(err, results) {
            expect(err).to.not.exist;
            expect(results.result.n).to.equal(1);

            // Execute slow find
            var cursor = server.cursor(ns, {
              find: ns,
              query: { $where: 'sleep(250) || true' },
              batchSize: 1
            });

            // Execute next
            cursor.next(function(err) {
              expect(err).to.exist;

              cursor = server.cursor(ns, {
                find: ns,
                query: {},
                batchSize: 1
              });

              cursor.next(function(err) {
                expect(err).to.exist;
                done();
              });
            });
          }
        );
      });

      // Start connection
      server.connect();
    }
  });
});
<commit_msg>test(cursor): use `newTopology` in cursor test<commit_after>'use strict';

const expect = require('chai').expect;
const f = require('util').format;
const setupDatabase = require('./shared').setupDatabase;

describe('Cursor tests', function() {
  before(function() {
    return setupDatabase(this.configuration);
  });

  it('Should iterate cursor', {
    metadata: {
      requires: { topology: ['single', 'replicaset', 'sharded'] }
    },

    test: function(done) {
      const server = this.configuration.newTopology();
      server.on('connect', function(_server) {
        var ns = f('integration_tests.cursor1');
        // Execute the write
        _server.insert(
          ns,
          [{ a: 1 }, { a: 2 }, { a: 3 }],
          {
            writeConcern: { w: 1 },
            ordered: true
          },
          function(err, results) {
            expect(err).to.be.null;
            expect(results.result.n).to.equal(3);

            // Execute find
            var cursor = _server.cursor(ns, {
              find: ns,
              query: {},
              batchSize: 2
            });

            // Execute next
            cursor.next(function(nextCursorErr, nextCursorD) {
              expect(nextCursorErr).to.be.null;
              expect(nextCursorD.a).to.equal(1);
              expect(cursor.bufferedCount()).to.equal(1);

              // Kill the cursor
              cursor.next(function(killCursorErr, killCursorD) {
                expect(killCursorErr).to.be.null;
                expect(killCursorD.a).to.equal(2);
                expect(cursor.bufferedCount()).to.equal(0);
                // Destroy the server connection
                _server.destroy();
                // Finish the test
                done();
              });
            });
          }
        );
      });

      // Start connection
      server.connect();
    }
  });

  it('Should iterate cursor but readBuffered', {
    metadata: {
      requires: { topology: ['single', 'replicaset', 'sharded'] }
    },

    test: function(done) {
      const server = this.configuration.newTopology();
      var ns = f('%s.cursor2', this.configuration.db);
      // Add event listeners
      server.on('connect', function(_server) {
        // Execute the write
        _server.insert(
          ns,
          [{ a: 1 }, { a: 2 }, { a: 3 }, { a: 4 }, { a: 5 }],
          {
            writeConcern: { w: 1 },
            ordered: true
          },
          function(err, results) {
            expect(err).to.be.null;
            expect(results.result.n).to.equal(5);

            // Execute find
            var cursor = _server.cursor(ns, {
              find: ns,
              query: {},
              batchSize: 5
            });

            // Execute next
            cursor.next(function(nextCursorErr, nextCursorD) {
              expect(nextCursorErr).to.be.null;
              expect(nextCursorD.a).to.equal(1);
              expect(cursor.bufferedCount()).to.equal(4);

              // Read the buffered Count
              cursor.readBufferedDocuments(cursor.bufferedCount());

              // Get the next item
              cursor.next(function(secondCursorErr, secondCursorD) {
                expect(secondCursorErr).to.be.null;
                expect(secondCursorD).to.be.null;

                // Destroy the server connection
                _server.destroy();
                // Finish the test
                done();
              });
            });
          }
        );
      });

      // Start connection
      server.connect();
    }
  });

  it('Should callback exhausted cursor with error', {
    metadata: {
      requires: { topology: ['single', 'replicaset', 'sharded'] }
    },

    test: function(done) {
      const server = this.configuration.newTopology();
      var ns = f('%s.cursor3', this.configuration.db);
      // Add event listeners
      server.on('connect', function(_server) {
        // Execute the write
        _server.insert(
          ns,
          [{ a: 1 }],
          {
            writeConcern: { w: 1 },
            ordered: true
          },
          function(err, results) {
            expect(err).to.be.null;
            expect(results.result.n).to.equal(1);

            // Execute find
            var cursor = _server.cursor(ns, { find: ns, query: {}, batchSize: 5 });

            // Execute next
            cursor.next(function(nextCursorErr, nextCursorD) {
              expect(nextCursorErr).to.be.null;
              expect(nextCursorD.a).to.equal(1);

              // Get the next item
              cursor.next(function(secondCursorErr, secondCursorD) {
                expect(secondCursorErr).to.be.null;
                expect(secondCursorD).to.be.null;

                cursor.next(function(thirdCursorErr, thirdCursorD) {
                  expect(thirdCursorErr).to.be.ok;
                  expect(thirdCursorD).to.be.undefined;
                  // Destroy the server connection
                  _server.destroy();
                  // Finish the test
                  done();
                });
              });
            });
          }
        );
      });

      // Start connection
      server.connect();
    }
  });

  it('Should force a getMore call to happen', {
    metadata: {
      requires: { topology: ['single', 'replicaset', 'sharded'] }
    },

    test: function(done) {
      const server = this.configuration.newTopology();
      var ns = f('%s.cursor4', this.configuration.db);
      // Add event listeners
      server.on('connect', function(_server) {
        // Execute the write
        _server.insert(
          ns,
          [{ a: 1 }, { a: 2 }, { a: 3 }],
          {
            writeConcern: { w: 1 },
            ordered: true
          },
          function(err, results) {
            expect(err).to.be.null;
            expect(results.result.n).to.equal(3);

            // Execute find
            var cursor = _server.cursor(ns, { find: ns, query: {}, batchSize: 2 });

            // Execute next
            cursor.next(function(nextCursorErr, nextCursorD) {
              expect(nextCursorErr).to.be.null;
              expect(nextCursorD.a).to.equal(1);

              // Get the next item
              cursor.next(function(secondCursorErr, secondCursorD) {
                expect(secondCursorErr).to.be.null;
                expect(secondCursorD.a).to.equal(2);

                cursor.next(function(thirdCursorErr, thirdCursorD) {
                  expect(thirdCursorErr).to.be.null;
                  expect(thirdCursorD.a).to.equal(3);
                  // Destroy the server connection
                  _server.destroy();
                  // Finish the test
                  done();
                });
              });
            });
          }
        );
      });

      // Start connection
      server.connect();
    }
  });

  it('Should force a getMore call to happen then call killCursor', {
    metadata: {
      requires: { topology: ['single', 'replicaset', 'sharded'] }
    },

    test: function(done) {
      const server = this.configuration.newTopology();
      var ns = f('%s.cursor4', this.configuration.db);
      // Add event listeners
      server.on('connect', function(_server) {
        // Execute the write
        _server.insert(
          ns,
          [{ a: 1 }, { a: 2 }, { a: 3 }],
          {
            writeConcern: { w: 1 },
            ordered: true
          },
          function(err, results) {
            expect(err).to.be.null;
            expect(results.result.n).to.equal(3);

            // Execute find
            var cursor = _server.cursor(ns, { find: ns, query: {}, batchSize: 2 });

            // Execute next
            cursor.next(function(nextCursorErr, nextCursorD) {
              expect(nextCursorErr).to.be.null;
              expect(nextCursorD.a).to.equal(1);

              // Get the next item
              cursor.next(function(secondCursorErr, secondCursorD) {
                expect(secondCursorErr).to.be.null;
                expect(secondCursorD.a).to.equal(2);

                // Kill cursor
                cursor.kill(function() {
                  // Should error out
                  cursor.next(function(thirdCursorErr, thirdCursorD) {
                    expect(thirdCursorErr).to.not.exist;
                    expect(thirdCursorD).to.not.exist;

                    // Destroy the server connection
                    _server.destroy();
                    // Finish the test
                    done();
                  });
                });
              });
            });
          }
        );
      });

      // Start connection
      server.connect();
    }
  });

  // Skipped due to usage of the topology manager
  it.skip('Should fail cursor correctly after server restart', {
    metadata: {
      requires: { topology: ['single'] }
    },

    test: function(done) {
      var self = this;
      const server = this.configuration.newTopology();
      var ns = f('%s.cursor5', this.configuration.db);
      // Add event listeners
      server.on('connect', function(_server) {
        // Execute the write
        _server.insert(
          ns,
          [{ a: 1 }, { a: 2 }, { a: 3 }],
          {
            writeConcern: { w: 1 },
            ordered: true
          },
          function(err, results) {
            expect(err).to.be.null;
            expect(results.result.n).to.equal(3);

            // Execute find
            var cursor = _server.cursor(ns, { find: ns, query: {}, batchSize: 2 });

            // Execute next
            cursor.next(function(nextCursorErr, nextCursorD) {
              expect(nextCursorErr).to.be.null;
              expect(nextCursorD.a).to.equal(1);

              // Get the next item
              cursor.next(function(secondCursorErr, secondCursorD) {
                expect(secondCursorErr).to.be.null;
                expect(secondCursorD.a).to.equal(2);

                self.configuration.manager.restart(false).then(function() {
                  // Should error out
                  cursor.next(function(thirdCursorErr, thirdCursorD) {
                    expect(thirdCursorErr).to.be.ok;
                    expect(thirdCursorD).to.be.undefined;

                    // Destroy the server connection
                    _server.destroy();
                    // Finish the test
                    done();
                  });
                });
              });
            });
          }
        );
      });

      // Start connection
      server.connect();
    }
  });

  it('Should finish cursor correctly after all sockets to pool destroyed', {
    metadata: {
      requires: {
        topology: ['single'],
        os: '!darwin' // remove os restriction when SERVER-32477 is resolved
      }
    },

    test: function(done) {
      const server = this.configuration.newTopology();
      var ns = f('%s.cursor6', this.configuration.db);
      // Add event listeners
      server.on('connect', function(_server) {
        // Execute the write
        _server.insert(
          ns,
          [{ a: 1 }, { a: 2 }, { a: 3 }],
          {
            writeConcern: { w: 1 },
            ordered: true
          },
          function(err, results) {
            expect(err).to.be.null;
            expect(results.result.n).to.equal(3);

            // Execute find
            var cursor = _server.cursor(ns, { find: ns, query: {}, batchSize: 2 });

            // Execute next
            cursor.next(function(nextCursorErr, nextCursorD) {
              expect(nextCursorErr).to.be.null;
              expect(nextCursorD.a).to.equal(1);

              // Get the next item
              cursor.next(function(secondCursorErr, secondCursorD) {
                expect(secondCursorErr).to.be.null;
                expect(secondCursorD.a).to.equal(2);

                // Should be able to continue cursor after reconnect
                _server.once('reconnect', function() {
                  cursor.next(function(thirdCursorErr, thirdCursorD) {
                    expect(thirdCursorErr).to.be.null;
                    expect(thirdCursorD.a).to.equal(3);

                    // Destroy the server connection
                    _server.destroy();
                    // Finish the test
                    done();
                  });
                });

                // Destroy all active connections in the pool
                var connections = _server.s.pool.allConnections();
                for (var i = 0; i < connections.length; i++) {
                  connections[i].write('!@#!@#SADASDSA!@#!@#!@#!@#!@');
                }
              });
            });
          }
        );
      });

      // Start connection
      server.connect();
    }
  });

  it('Should not leak connnection workItem elements when using killCursor', {
    metadata: {
      requires: { topology: ['single'] }
    },

    test: function(done) {
      const server = this.configuration.newTopology();
      var ns = f('%s.cursor4', this.configuration.db);
      // Add event listeners
      server.on('connect', function(_server) {
        // Execute the write
        _server.insert(
          ns,
          [{ a: 1 }, { a: 2 }, { a: 3 }],
          {
            writeConcern: { w: 1 },
            ordered: true
          },
          function(err, results) {
            expect(err).to.be.null;
            expect(results.result.n).to.equal(3);

            // Execute find
            var cursor = _server.cursor(ns, { find: ns, query: {}, batchSize: 2 });

            // Execute next
            cursor.next(function(nextCursorErr, nextCursorD) {
              expect(nextCursorErr).to.be.null;
              expect(nextCursorD.a).to.equal(1);

              // Kill cursor
              cursor.kill(function() {
                // Add a small delay so that the work can be queued after the kill
                // callback has executed
                setImmediate(function() {
                  var connections = _server.s.pool.allConnections();
                  for (var i = 0; i < connections.length; i++) {
                    expect(connections[i].workItems.length).to.equal(0);
                  }

                  // Destroy the server connection
                  _server.destroy();
                  // Finish the test
                  done();
                }, 100);
              });
            });
          }
        );
      });

      // Start connection
      server.connect();
    }
  });

  // NOTE: a notoriously flakey test, needs rewriting
  it.skip('should not hang if autoReconnect=false and pools sockets all timed out', {
    metadata: { requires: { topology: ['single'] } },
    test: function(done) {
      var configuration = this.configuration,
        Server = require('../../../lib/topologies/server'),
        bson = require('bson');

      // Attempt to connect
      var server = new Server({
        host: configuration.host,
        port: configuration.port,
        bson: new bson(),
        // Nasty edge case: small timeout, small pool, no auto reconnect
        socketTimeout: 250,
        size: 1,
        reconnect: false
      });

      var ns = f('%s.cursor7', configuration.db);
      server.on('connect', function() {
        // Execute the write
        server.insert(
          ns,
          [{ a: 1 }],
          {
            writeConcern: { w: 1 },
            ordered: true
          },
          function(err, results) {
            expect(err).to.not.exist;
            expect(results.result.n).to.equal(1);

            // Execute slow find
            var cursor = server.cursor(ns, {
              find: ns,
              query: { $where: 'sleep(250) || true' },
              batchSize: 1
            });

            // Execute next
            cursor.next(function(err) {
              expect(err).to.exist;

              cursor = server.cursor(ns, {
                find: ns,
                query: {},
                batchSize: 1
              });

              cursor.next(function(err) {
                expect(err).to.exist;
                done();
              });
            });
          }
        );
      });

      // Start connection
      server.connect();
    }
  });
});
<|endoftext|>


<commit_before>"use strict";

var f = require('util').format
  , Long = require('bson').Long;

exports['Should correctly reconnect to server with automatic reconnect enabled'] = {
  metadata: {
    requires: {
      topology: "single"
    }
  },

  test: function(configuration, test) {
    var Server = configuration.require.Server
      , ReadPreference = configuration.require.ReadPreference;

    // Attempt to connect
    var server = new Server({
        host: configuration.host
      , port: configuration.port
      , reconnect: true
      , reconnectInterval: 50
    })

    // Test flags
    var emittedClose = false;

    // Add event listeners
    server.on('connect', function(_server) {
      // Execute the command
      _server.command("system.$cmd", {ismaster: true}, {readPreference: new ReadPreference('primary')}, function(err, result) {
        test.equal(null, err)
        // Write garbage, force socket closure
        try {
          var a = new Buffer(100);
          for(var i = 0; i < 100; i++) a[i] = i;
          result.connection.write(a);
        } catch(err) {}

        // Ensure the server died
        setTimeout(function() {
          // Attempt a proper command
          _server.command("system.$cmd", {ismaster: true}, {readPreference: new ReadPreference('primary')}, function(err, result) {
            test.ok(err != null);
          });
        }, 100);
      });
    });

    server.once('close', function() {
      emittedClose = true;
    });

    server.once('reconnect', function() {
      test.equal(true, emittedClose);
      test.equal(true, server.isConnected());
      server.destroy();
      test.done();
    });

    // Start connection
    server.connect();
  }
}

exports['Should correctly reconnect to server with automatic reconnect disabled'] = {
  metadata: {
    requires: {
      topology: "single"
    }
  },

  test: function(configuration, test) {
    var Server = configuration.require.Server
      , ReadPreference = configuration.require.ReadPreference;

    // Attempt to connect
    var server = new Server({
        host: configuration.host
      , port: configuration.port
      , reconnect: false
    })

    // Test flags
    var emittedClose = false;

    // Add event listeners
    server.on('connect', function(_server) {
      // Execute the command
      _server.command("system.$cmd", {ismaster: true}, {readPreference: new ReadPreference('primary')}, function(err, result) {
        test.equal(null, err)
        // Write garbage, force socket closure
        try {
          var a = new Buffer(1000);
          for(var i = 0; i < 100; i++) a[i] = i;
          result.connection.write(a);
        } catch(err) {}

        setTimeout(function() {
          // Attempt a proper command
          _server.command("system.$cmd", {ismaster: true}, {readPreference: new ReadPreference('primary')}, function(err, result) {
            console.dir(err)
            test.ok(err != null);
          });
        }, 1);
      });
    });

    server.on('close', function() {
      emittedClose = true;
    });

    setTimeout(function() {
      test.equal(true, emittedClose);
      test.equal(false, server.isConnected());
      server.destroy();
      test.done();
    }, 500);

    // Start connection
    server.connect();
  }
}<commit_msg>Set pool in test to size 1<commit_after>"use strict";

var f = require('util').format
  , Long = require('bson').Long;

exports['Should correctly reconnect to server with automatic reconnect enabled'] = {
  metadata: {
    requires: {
      topology: "single"
    }
  },

  test: function(configuration, test) {
    var Server = configuration.require.Server
      , ReadPreference = configuration.require.ReadPreference;

    // Attempt to connect
    var server = new Server({
        host: configuration.host
      , port: configuration.port
      , reconnect: true
      , reconnectInterval: 50
    })

    // Test flags
    var emittedClose = false;

    // Add event listeners
    server.on('connect', function(_server) {
      // Execute the command
      _server.command("system.$cmd", {ismaster: true}, {readPreference: new ReadPreference('primary')}, function(err, result) {
        test.equal(null, err)
        // Write garbage, force socket closure
        try {
          var a = new Buffer(100);
          for(var i = 0; i < 100; i++) a[i] = i;
          result.connection.write(a);
        } catch(err) {}

        // Ensure the server died
        setTimeout(function() {
          // Attempt a proper command
          _server.command("system.$cmd", {ismaster: true}, {readPreference: new ReadPreference('primary')}, function(err, result) {
            test.ok(err != null);
          });
        }, 100);
      });
    });

    server.once('close', function() {
      emittedClose = true;
    });

    server.once('reconnect', function() {
      test.equal(true, emittedClose);
      test.equal(true, server.isConnected());
      server.destroy();
      test.done();
    });

    // Start connection
    server.connect();
  }
}

exports['Should correctly reconnect to server with automatic reconnect disabled'] = {
  metadata: {
    requires: {
      topology: "single"
    }
  },

  test: function(configuration, test) {
    var Server = configuration.require.Server
      , ReadPreference = configuration.require.ReadPreference;

    // Attempt to connect
    var server = new Server({
        host: configuration.host
      , port: configuration.port
      , reconnect: false
      , size: 1
    })

    // Test flags
    var emittedClose = false;

    // Add event listeners
    server.on('connect', function(_server) {
      // Execute the command
      _server.command("system.$cmd", {ismaster: true}, {readPreference: new ReadPreference('primary')}, function(err, result) {
        test.equal(null, err)
        // Write garbage, force socket closure
        try {
          var a = new Buffer(1000);
          for(var i = 0; i < 100; i++) a[i] = i;
          result.connection.write(a);
        } catch(err) {}

        process.nextTick(function() {
          // Attempt a proper command
          _server.command("system.$cmd", {ismaster: true}, {readPreference: new ReadPreference('primary')}, function(err, result) {
            console.dir(err)
            test.ok(err != null);
          });
        });
      });
    });

    server.on('close', function() {
      emittedClose = true;
    });

    setTimeout(function() {
      test.equal(true, emittedClose);
      test.equal(false, server.isConnected());
      server.destroy();
      test.done();
    }, 500);

    // Start connection
    server.connect();
  }
}<|endoftext|>


<commit_before>/*
 * file-maxfiles-test.js: Tests for instances of the File transport setting the max file size,
 * and setting a number for max files created.
 * maxSize * maxFiles = total storage used by winston.
 *
 * (C) 2011 Daniel Aristizabal
 * MIT LICENSE
 *
 */

var assert = require('assert'),
    exec = require('child_process').exec,
    fs = require('fs'),
    path = require('path'),
    vows = require('vows'),
    winston = require('../../lib/winston'),
    helpers = require('../helpers');

var maxfilesTransport = new winston.transports.File({
  timestamp: false,
  json: false,
  filename: path.join(__dirname, '..', 'fixtures', 'logs', 'testmaxfiles.log'),
  maxsize: 4096,
  maxFiles: 3
});

vows.describe('winston/transports/file/maxfiles').addBatch({
  "An instance of the File Transport": {
    "when passed a valid filename": {
      topic: maxfilesTransport,
      "should be a valid transporter": function (transportTest) {
        helpers.assertFile(transportTest);
      },
      "should set the maxFiles option correctly": function (transportTest) {
        assert.isNumber(transportTest.maxFiles);
      }
    },
    "when delete old test files": {
      topic: function () {
        exec('rm -rf ' + path.join(__dirname, '..', 'fixtures', 'logs', 'testmaxfiles*'), this.callback);
      },
      "and when passed more files than the maxFiles": {
        topic: function () {
          var that = this,
              created = 0;

          function data(ch) {
            return new Array(1018).join(String.fromCharCode(65 + ch));
          };

          function logKbytes(kbytes, txt) {
            //
            // With no timestamp and at the info level,
            // winston adds exactly 7 characters:
            // [info](4)[ :](2)[\n](1)
            //
            for (var i = 0; i < kbytes; i++) {
              maxfilesTransport.log('info', data(txt), null, function () { });
            }
          }

          maxfilesTransport.on('logged', function () {
            if (++created === 6) {
              return that.callback();
            }

            logKbytes(4, created);
          });

          logKbytes(4, created);
        },
        "should be only 3 files called 5.log, 4.log and 3.log": function () {
          for (var num = 0; num < 6; num++) {
            var file = !num ? 'testmaxfiles.log' : 'testmaxfiles' + num + '.log',
                fullpath = path.join(__dirname, '..', 'fixtures', 'logs', file);

            // There should be no files with that name
            if (num >= 0 && num < 3) {
              assert.throws(function () {
                fs.statSync(fullpath);
              }, Error);
            } else {
              // The other files should be exist
              assert.doesNotThrow(function () {
                  fs.statSync(fullpath);
              }, Error);
            }
          }
        },
        "should have the correct content": function () {
          ['D', 'E', 'F'].forEach(function (name, inx) {
            var counter = inx + 3,
                logsDir = path.join(__dirname, '..', 'fixtures', 'logs'),
                content = fs.readFileSync(path.join(logsDir, 'testmaxfiles' + counter + '.log'), 'utf-8');
            // The content minus the 7 characters added by winston
            assert.lengthOf(content.match(new RegExp(name, 'g')), 4068);
          });
        }
      }
    }
  }
}).export(module);
<commit_msg>indent<commit_after>/*
 * file-maxfiles-test.js: Tests for instances of the File transport setting the max file size,
 * and setting a number for max files created.
 * maxSize * maxFiles = total storage used by winston.
 *
 * (C) 2011 Daniel Aristizabal
 * MIT LICENSE
 *
 */

var assert = require('assert'),
    exec = require('child_process').exec,
    fs = require('fs'),
    path = require('path'),
    vows = require('vows'),
    winston = require('../../lib/winston'),
    helpers = require('../helpers');

var maxfilesTransport = new winston.transports.File({
  timestamp: false,
  json: false,
  filename: path.join(__dirname, '..', 'fixtures', 'logs', 'testmaxfiles.log'),
  maxsize: 4096,
  maxFiles: 3
});

vows.describe('winston/transports/file/maxfiles').addBatch({
  "An instance of the File Transport": {
    "when passed a valid filename": {
      topic: maxfilesTransport,
      "should be a valid transporter": function (transportTest) {
        helpers.assertFile(transportTest);
      },
      "should set the maxFiles option correctly": function (transportTest) {
        assert.isNumber(transportTest.maxFiles);
      }
    },
    "when delete old test files": {
      topic: function () {
        exec('rm -rf ' + path.join(__dirname, '..', 'fixtures', 'logs', 'testmaxfiles*'), this.callback);
      },
      "and when passed more files than the maxFiles": {
        topic: function () {
          var that = this,
              created = 0;

          function data(ch) {
            return new Array(1018).join(String.fromCharCode(65 + ch));
          };

          function logKbytes(kbytes, txt) {
            //
            // With no timestamp and at the info level,
            // winston adds exactly 7 characters:
            // [info](4)[ :](2)[\n](1)
            //
            for (var i = 0; i < kbytes; i++) {
              maxfilesTransport.log('info', data(txt), null, function () { });
            }
          }

          maxfilesTransport.on('logged', function () {
            if (++created === 6) {
              return that.callback();
            }

            logKbytes(4, created);
          });

          logKbytes(4, created);
        },
        "should be only 3 files called 5.log, 4.log and 3.log": function () {
          for (var num = 0; num < 6; num++) {
            var file = !num ? 'testmaxfiles.log' : 'testmaxfiles' + num + '.log',
                fullpath = path.join(__dirname, '..', 'fixtures', 'logs', file);

            // There should be no files with that name
            if (num >= 0 && num < 3) {
              assert.throws(function () {
                fs.statSync(fullpath);
              }, Error);
            } else {
              // The other files should be exist
              assert.doesNotThrow(function () {
                fs.statSync(fullpath);
              }, Error);
            }
          }
        },
        "should have the correct content": function () {
          ['D', 'E', 'F'].forEach(function (name, inx) {
            var counter = inx + 3,
                logsDir = path.join(__dirname, '..', 'fixtures', 'logs'),
                content = fs.readFileSync(path.join(logsDir, 'testmaxfiles' + counter + '.log'), 'utf-8');
            // The content minus the 7 characters added by winston
            assert.lengthOf(content.match(new RegExp(name, 'g')), 4068);
          });
        }
      }
    }
  }
}).export(module);
<|endoftext|>


<commit_before>/**
 * Toolbar.spec.js
 * (c) 2015~ Summernote Team
 * summernote may be freely distributed under the MIT license./
 */
/* jshint unused: false */
define([
  'chai',
  'summernote/lite/module/Toolbar'
], function (chai, Toolbar) {
  'use strict';

  var expect = chai.expect;

  describe('lite:module.Toolbar', function () {
  });
});
<commit_msg>Remove a spec.<commit_after><|endoftext|>


<commit_before>import nock from 'nock'
const root = require('root-path')
require(root('test/setup'))
var factories = require(root('test/setup/factories'))
const model = factories.mock.model

const destroyAllPushNotifications = () => {
  return PushNotification.fetchAll()
  .then(pns => pns.map(pn => pn.destroy()))
}

const relations = [
  'activity',
  'activity.post',
  'activity.post.user',
  'activity.post.communities',
  'activity.comment',
  'activity.comment.user',
  'activity.comment.post',
  'activity.comment.post.communities',
  'activity.community',
  'activity.reader',
  'activity.actor'
]

describe('Notification', function () {
  var post, comment, activity, community, reader, actor, device

  before(() => {
    return factories.user({name: 'Joe'}).save()
    .then(u => actor = u)
    .then(() => factories.post({name: 'My Post', user_id: actor.id, description: 'The body of the post'}).save())
    .then(p => post = p)
    .then(() => new Comment({text: 'hi', user_id: actor.id, post_id: post.id}).save())
    .then(c => comment = c)
    .then(() => factories.community({name: 'My Community'}).save())
    .then(c => community = c)
    .then(() => community.posts().attach(post))
    .then(() => factories.user({email: 'readersemail@hylo.com'}).save())
    .then(u => reader = u)
    .then(() => new Device({
      user_id: reader.id,
      token: 'eieio',
      version: 20,
      enabled: true
    }).save())
    .then(d => device = d)
    .then(() => new Activity({
      post_id: post.id
    }).save())
    .then(a => activity = a)
  })

  beforeEach(() => destroyAllPushNotifications())

  describe('.send', () => {
    beforeEach(() => {
      nock(OneSignal.host).post('/api/v1/notifications')
      .reply(200, {result: 'success'})
    })

    it('sends a push for a new post', () => {
      return new Activity({
        post_id: post.id,
        meta: {reasons: [`newPost: ${community.id}`]},
        reader_id: reader.id,
        actor_id: actor.id
      }).save()
      .then(activity => new Notification({
        activity_id: activity.id,
        medium: Notification.MEDIUM.Push
      }).save())
      .then(notification => notification.load(relations))
      .then(notification => notification.send())
      .then(() => PushNotification.where({device_token: device.get('token')}).fetchAll())
      .then(pns => {
        expect(pns).to.exist
        expect(pns.length).to.equal(1)
        var pn = pns.first()
        expect(pn.get('alert')).to.equal('Joe posted "My Post" in My Community')
      })
    })

    it('sends a push for a mention in a post', () => {
      return new Activity({
        post_id: post.id,
        meta: {reasons: ['mention']},
        reader_id: reader.id,
        actor_id: actor.id
      }).save()
      .then(activity => new Notification({
        activity_id: activity.id,
        medium: Notification.MEDIUM.Push
      }).save())
      .then(notification => notification.load(relations))
      .then(notification => notification.send())
      .then(() => PushNotification.where({device_token: device.get('token')}).fetchAll())
      .then(pns => {
        expect(pns).to.exist
        expect(pns.length).to.equal(1)
        var pn = pns.first()
        expect(pn.get('alert')).to.equal('Joe mentioned you in "My Post"')
      })
    })

    it('sends a push for a comment', () => {
      return new Activity({
        comment_id: comment.id,
        meta: {reasons: ['newComment']},
        reader_id: reader.id,
        actor_id: actor.id
      }).save()
      .then(activity => new Notification({
        activity_id: activity.id,
        medium: Notification.MEDIUM.Push
      }).save())
      .then(notification => notification.load(relations))
      .then(notification => notification.send())
      .then(() => PushNotification.where({device_token: device.get('token')}).fetchAll())
      .then(pns => {
        expect(pns).to.exist
        expect(pns.length).to.equal(1)
        var pn = pns.first()
        expect(pn.get('alert')).to.equal(`Joe: "${comment.get('text')}" (in "My Post")`)
      })
    })

    it('sends a push for a mention in a comment', () => {
      return new Activity({
        comment_id: comment.id,
        meta: {reasons: ['commentMention']},
        reader_id: reader.id,
        actor_id: actor.id
      }).save()
      .then(activity => new Notification({
        activity_id: activity.id,
        medium: Notification.MEDIUM.Push
      }).save())
      .then(notification => notification.load(relations))
      .then(notification => notification.send())
      .then(() => PushNotification.where({device_token: device.get('token')}).fetchAll())
      .then(pns => {
        expect(pns).to.exist
        expect(pns.length).to.equal(1)
        var pn = pns.first()
        expect(pn.get('alert')).to.equal('Joe mentioned you: "hi" (in "My Post")')
      })
    })

    it('sends an email for a mention in a post', () => {
      var originalMethod = Email.sendPostMentionNotification

      Email.sendPostMentionNotification = spy(opts => {
        expect(opts).to.contain({
          email: 'readersemail@hylo.com'
        })

        expect(opts.sender).to.contain({
          name: 'Joe (via Hylo)'
        })

        expect(opts.data).to.contain({
          community_name: 'My Community',
          post_user_name: 'Joe',
          post_description: 'The body of the post',
          post_title: 'My Post'
        })
      })

      return new Activity({
        post_id: post.id,
        meta: {reasons: ['mention']},
        reader_id: reader.id,
        actor_id: actor.id
      }).save()
      .then(activity => new Notification({
        activity_id: activity.id,
        medium: Notification.MEDIUM.Email
      }).save())
      .then(notification => notification.load(relations))
      .then(notification => notification.send())
      .then(() => {
        expect(Email.sendPostMentionNotification).to.have.been.called()
      })
      .then(() => {
        Email.sendPostMentionNotification = originalMethod
      })
    })

    it('sends an email for a comment', () => {
      var originalMethod = Email.sendNewCommentNotification

      Email.sendNewCommentNotification = spy(opts => {
        expect(opts).to.contain({
          email: 'readersemail@hylo.com'
        })

        expect(opts.sender).to.contain({
          name: 'Joe (via Hylo)'
        })

        expect(opts.data).to.contain({
          community_name: 'My Community',
          commenter_name: 'Joe',
          post_title: 'My Post'
        })
      })

      return new Activity({
        comment_id: comment.id,
        meta: {reasons: ['newComment']},
        reader_id: reader.id,
        actor_id: actor.id
      }).save()
      .then(activity => new Notification({
        activity_id: activity.id,
        medium: Notification.MEDIUM.Email
      }).save())
      .then(notification => notification.load(relations))
      .then(notification => notification.send())
      .then(() => {
        expect(Email.sendNewCommentNotification).to.have.been.called()
      })
      .then(() => {
        Email.sendNewCommentNotification = originalMethod
      })
    })

    it('sends an email for a mention in a comment', () => {
      var originalMethod = Email.sendNewCommentNotification

      Email.sendNewCommentNotification = spy(opts => {
        expect(opts).to.contain({
          email: 'readersemail@hylo.com',
          version: 'mention'
        })

        expect(opts.sender).to.contain({
          name: 'Joe (via Hylo)'
        })

        expect(opts.data).to.contain({
          community_name: 'My Community',
          commenter_name: 'Joe',
          post_title: 'My Post'
        })
      })

      return new Activity({
        comment_id: comment.id,
        meta: {reasons: ['commentMention']},
        reader_id: reader.id,
        actor_id: actor.id
      }).save()
      .then(activity => new Notification({
        activity_id: activity.id,
        medium: Notification.MEDIUM.Email
      }).save())
      .then(notification => notification.load(relations))
      .then(notification => notification.send())
      .then(() => {
        expect(Email.sendNewCommentNotification).to.have.been.called()
      })
      .then(() => {
        Email.sendNewCommentNotification = originalMethod
      })
    })
  })

  describe('#findUnsent', () => {
    it('returns the unsent', () => {
      return Promise.join(
        new Notification({
          activity_id: activity.id,
          medium: Notification.MEDIUM.Email,
          sent_at: (new Date()).toISOString()
        }).save(),
        new Notification({
          activity_id: activity.id,
          medium: Notification.MEDIUM.Push
        }).save(),
        new Notification({
          activity_id: activity.id,
          medium: Notification.MEDIUM.InApp
        }).save())
      .then(() => Notification.findUnsent())
      .then(notifications => {
        expect(notifications.length).to.equal(2)
        expect(notifications.pluck('medium').sort()).to.deep.equal([
          Notification.MEDIUM.Push,
          Notification.MEDIUM.InApp
        ].sort())
      })
    })
  })

  describe('sendCommentNotificationEmail', () => {
    var original, args, community
    beforeEach(() => {
      original = Email.sendNewCommentNotification
      Email.sendNewCommentNotification = spy(x => args = x)
      community = factories.community()
      return community.save()
    })

    afterEach(() => {
      Email.sendNewCommentNotification = original
    })

    it('sets the correct email attributes', () => {
      const note = new Notification()

      note.relations = {
        activity: model({
          comment_id: 5,
          relations: {
            comment: model({
              id: 5,
              text: 'I have an opinion',
              relations: {
                post: model({
                  name: 'hello world',
                  relations: {
                    communities: [community]
                  }
                }),
                user: model({
                  id: 2,
                  name: 'Ka Mentor'
                })
              }
            }),
            reader: new User({
              id: 1,
              name: 'Reader Person',
              email: 'ilovenotifications@foo.com',
              created_at: new Date()
            })
          }
        })
      }

      return note.sendCommentNotificationEmail()
      .then(() => {
        expect(Email.sendNewCommentNotification).to.have.been.called()
        expect(args.data.post_label).to.equal('"hello world"')
      })
    })
  })
})
<commit_msg>tests<commit_after>import nock from 'nock'
const root = require('root-path')
require(root('test/setup'))
var factories = require(root('test/setup/factories'))
const model = factories.mock.model

const destroyAllPushNotifications = () => {
  return PushNotification.fetchAll()
  .then(pns => pns.map(pn => pn.destroy()))
}

const relations = [
  'activity',
  'activity.post',
  'activity.post.user',
  'activity.post.communities',
  'activity.comment',
  'activity.comment.user',
  'activity.comment.post',
  'activity.comment.post.communities',
  'activity.community',
  'activity.reader',
  'activity.actor'
]

describe('Notification', function () {
  var post, comment, activity, community, reader, actor, device

  before(() => {
    return factories.user({name: 'Joe'}).save()
    .then(u => actor = u)
    .then(() => factories.post({name: 'My Post', user_id: actor.id, description: 'The body of the post'}).save())
    .then(p => post = p)
    .then(() => new Comment({text: 'hi', user_id: actor.id, post_id: post.id}).save())
    .then(c => comment = c)
    .then(() => factories.community({name: 'My Community'}).save())
    .then(c => community = c)
    .then(() => community.posts().attach(post))
    .then(() => factories.user({email: 'readersemail@hylo.com'}).save())
    .then(u => reader = u)
    .then(() => new Device({
      user_id: reader.id,
      token: 'eieio',
      version: 20,
      enabled: true
    }).save())
    .then(d => device = d)
    .then(() => new Activity({
      post_id: post.id
    }).save())
    .then(a => activity = a)
  })

  beforeEach(() => destroyAllPushNotifications())

  describe('.send', () => {
    beforeEach(() => {
      nock(OneSignal.host).post('/api/v1/notifications')
      .reply(200, {result: 'success'})
    })

    it('sends a push for a new post', () => {
      return new Activity({
        post_id: post.id,
        meta: {reasons: [`newPost: ${community.id}`]},
        reader_id: reader.id,
        actor_id: actor.id
      }).save()
      .then(activity => new Notification({
        activity_id: activity.id,
        medium: Notification.MEDIUM.Push
      }).save())
      .then(notification => notification.load(relations))
      .then(notification => notification.send())
      .then(() => PushNotification.where({device_token: device.get('token')}).fetchAll())
      .then(pns => {
        expect(pns).to.exist
        expect(pns.length).to.equal(1)
        var pn = pns.first()
        expect(pn.get('alert')).to.equal('Joe posted "My Post" in My Community')
      })
    })

    it('sends a push for a mention in a post', () => {
      return new Activity({
        post_id: post.id,
        meta: {reasons: ['mention']},
        reader_id: reader.id,
        actor_id: actor.id
      }).save()
      .then(activity => new Notification({
        activity_id: activity.id,
        medium: Notification.MEDIUM.Push
      }).save())
      .then(notification => notification.load(relations))
      .then(notification => notification.send())
      .then(() => PushNotification.where({device_token: device.get('token')}).fetchAll())
      .then(pns => {
        expect(pns).to.exist
        expect(pns.length).to.equal(1)
        var pn = pns.first()
        expect(pn.get('alert')).to.equal('Joe mentioned you in "My Post"')
      })
    })

    it('sends a push for a comment', () => {
      return new Activity({
        comment_id: comment.id,
        meta: {reasons: ['newComment']},
        reader_id: reader.id,
        actor_id: actor.id
      }).save()
      .then(activity => new Notification({
        activity_id: activity.id,
        medium: Notification.MEDIUM.Push
      }).save())
      .then(notification => notification.load(relations))
      .then(notification => notification.send())
      .then(() => PushNotification.where({device_token: device.get('token')}).fetchAll())
      .then(pns => {
        expect(pns).to.exist
        expect(pns.length).to.equal(1)
        var pn = pns.first()
        expect(pn.get('alert')).to.equal(`Joe: "${comment.get('text')}" (in "My Post")`)
      })
    })

    it('sends a push for a mention in a comment', () => {
      return new Activity({
        comment_id: comment.id,
        meta: {reasons: ['commentMention']},
        reader_id: reader.id,
        actor_id: actor.id
      }).save()
      .then(activity => new Notification({
        activity_id: activity.id,
        medium: Notification.MEDIUM.Push
      }).save())
      .then(notification => notification.load(relations))
      .then(notification => notification.send())
      .then(() => PushNotification.where({device_token: device.get('token')}).fetchAll())
      .then(pns => {
        expect(pns).to.exist
        expect(pns.length).to.equal(1)
        var pn = pns.first()
        expect(pn.get('alert')).to.equal('Joe mentioned you: "hi" (in "My Post")')
      })
    })

    it('sends a push for a join request', () => {
      return new Activity({
        meta: {reasons: ['joinRequest']},
        reader_id: reader.id,
        actor_id: actor.id,
        community_id: community.id
      }).save()
      .then(activity => new Notification({
        activity_id: activity.id,
        medium: Notification.MEDIUM.Push
      }).save())
      .then(notification => notification.load(relations))
      .then(notification => notification.send())
      .then(() => PushNotification.where({device_token: device.get('token')}).fetchAll())
      .then(pns => {
        expect(pns).to.exist
        expect(pns.length).to.equal(1)
        var pn = pns.first()
        expect(pn.get('alert')).to.equal('Joe asked to join My Community')
      })
    })

    it('sends a push for an approved join request', () => {
      return new Activity({
        meta: {reasons: ['approvedJoinRequest']},
        reader_id: reader.id,
        actor_id: actor.id,
        community_id: community.id
      }).save()
      .then(activity => new Notification({
        activity_id: activity.id,
        medium: Notification.MEDIUM.Push
      }).save())
      .then(notification => notification.load(relations))
      .then(notification => notification.send())
      .then(() => PushNotification.where({device_token: device.get('token')}).fetchAll())
      .then(pns => {
        expect(pns).to.exist
        expect(pns.length).to.equal(1)
        var pn = pns.first()
        expect(pn.get('alert')).to.equal('Joe approved your request to join My Community')
      })
    })

    it('sends an email for a mention in a post', () => {
      var originalMethod = Email.sendPostMentionNotification

      Email.sendPostMentionNotification = spy(opts => {
        expect(opts).to.contain({
          email: 'readersemail@hylo.com'
        })

        expect(opts.sender).to.contain({
          name: 'Joe (via Hylo)'
        })

        expect(opts.data).to.contain({
          community_name: 'My Community',
          post_user_name: 'Joe',
          post_description: 'The body of the post',
          post_title: 'My Post'
        })
      })

      return new Activity({
        post_id: post.id,
        meta: {reasons: ['mention']},
        reader_id: reader.id,
        actor_id: actor.id
      }).save()
      .then(activity => new Notification({
        activity_id: activity.id,
        medium: Notification.MEDIUM.Email
      }).save())
      .then(notification => notification.load(relations))
      .then(notification => notification.send())
      .then(() => {
        expect(Email.sendPostMentionNotification).to.have.been.called()
      })
      .then(() => {
        Email.sendPostMentionNotification = originalMethod
      })
    })

    it('sends an email for a comment', () => {
      var originalMethod = Email.sendNewCommentNotification

      Email.sendNewCommentNotification = spy(opts => {
        expect(opts).to.contain({
          email: 'readersemail@hylo.com'
        })

        expect(opts.sender).to.contain({
          name: 'Joe (via Hylo)'
        })

        expect(opts.data).to.contain({
          community_name: 'My Community',
          commenter_name: 'Joe',
          post_title: 'My Post'
        })
      })

      return new Activity({
        comment_id: comment.id,
        meta: {reasons: ['newComment']},
        reader_id: reader.id,
        actor_id: actor.id
      }).save()
      .then(activity => new Notification({
        activity_id: activity.id,
        medium: Notification.MEDIUM.Email
      }).save())
      .then(notification => notification.load(relations))
      .then(notification => notification.send())
      .then(() => {
        expect(Email.sendNewCommentNotification).to.have.been.called()
      })
      .then(() => {
        Email.sendNewCommentNotification = originalMethod
      })
    })

    it('sends an email for a mention in a comment', () => {
      var originalMethod = Email.sendNewCommentNotification

      Email.sendNewCommentNotification = spy(opts => {
        expect(opts).to.contain({
          email: 'readersemail@hylo.com',
          version: 'mention'
        })

        expect(opts.sender).to.contain({
          name: 'Joe (via Hylo)'
        })

        expect(opts.data).to.contain({
          community_name: 'My Community',
          commenter_name: 'Joe',
          post_title: 'My Post'
        })
      })

      return new Activity({
        comment_id: comment.id,
        meta: {reasons: ['commentMention']},
        reader_id: reader.id,
        actor_id: actor.id
      }).save()
      .then(activity => new Notification({
        activity_id: activity.id,
        medium: Notification.MEDIUM.Email
      }).save())
      .then(notification => notification.load(relations))
      .then(notification => notification.send())
      .then(() => {
        expect(Email.sendNewCommentNotification).to.have.been.called()
      })
      .then(() => {
        Email.sendNewCommentNotification = originalMethod
      })
    })

    it('sends an email for a joinRequest', () => {
      var originalMethod = Email.sendJoinRequestNotification

      Email.sendJoinRequestNotification = spy(opts => {
        expect(opts).to.contain({
          email: 'readersemail@hylo.com'
        })

        expect(opts.sender).to.contain({
          name: 'Joe (via Hylo)'
        })

        expect(opts.data).to.contain({
          community_name: 'My Community',
          requester_name: 'Joe'
        })
      })

      return new Activity({
        community_id: community.id,
        meta: {reasons: ['joinRequest']},
        reader_id: reader.id,
        actor_id: actor.id
      }).save()
      .then(activity => new Notification({
        activity_id: activity.id,
        medium: Notification.MEDIUM.Email
      }).save())
      .then(notification => notification.load(relations))
      .then(notification => notification.send())
      .then(() => {
        expect(Email.sendJoinRequestNotification).to.have.been.called()
      })
      .then(() => {
        Email.sendJoinRequestNotification = originalMethod
      })
    })

    it('sends an email for an approvedJoinRequest', () => {
      var originalMethod = Email.sendApprovedJoinRequestNotification

      Email.sendApprovedJoinRequestNotification = spy(opts => {
        expect(opts).to.contain({
          email: 'readersemail@hylo.com'
        })

        expect(opts.sender).to.contain({
          name: 'Joe (via Hylo)'
        })

        expect(opts.data).to.contain({
          community_name: 'My Community',
          approver_name: 'Joe'
        })
      })

      return new Activity({
        community_id: community.id,
        meta: {reasons: ['approvedJoinRequest']},
        reader_id: reader.id,
        actor_id: actor.id
      }).save()
      .then(activity => new Notification({
        activity_id: activity.id,
        medium: Notification.MEDIUM.Email
      }).save())
      .then(notification => notification.load(relations))
      .then(notification => notification.send())
      .then(() => {
        expect(Email.sendApprovedJoinRequestNotification).to.have.been.called()
      })
      .then(() => {
        Email.sendApprovedJoinRequestNotification = originalMethod
      })
    })
  })

  describe('#findUnsent', () => {
    it('returns the unsent', () => {
      return Promise.join(
        new Notification({
          activity_id: activity.id,
          medium: Notification.MEDIUM.Email,
          sent_at: (new Date()).toISOString()
        }).save(),
        new Notification({
          activity_id: activity.id,
          medium: Notification.MEDIUM.Push
        }).save(),
        new Notification({
          activity_id: activity.id,
          medium: Notification.MEDIUM.InApp
        }).save())
      .then(() => Notification.findUnsent())
      .then(notifications => {
        expect(notifications.length).to.equal(2)
        expect(notifications.pluck('medium').sort()).to.deep.equal([
          Notification.MEDIUM.Push,
          Notification.MEDIUM.InApp
        ].sort())
      })
    })
  })

  describe('sendCommentNotificationEmail', () => {
    var original, args, community
    beforeEach(() => {
      original = Email.sendNewCommentNotification
      Email.sendNewCommentNotification = spy(x => args = x)
      community = factories.community()
      return community.save()
    })

    afterEach(() => {
      Email.sendNewCommentNotification = original
    })

    it('sets the correct email attributes', () => {
      const note = new Notification()

      note.relations = {
        activity: model({
          comment_id: 5,
          relations: {
            comment: model({
              id: 5,
              text: 'I have an opinion',
              relations: {
                post: model({
                  name: 'hello world',
                  relations: {
                    communities: [community]
                  }
                }),
                user: model({
                  id: 2,
                  name: 'Ka Mentor'
                })
              }
            }),
            reader: new User({
              id: 1,
              name: 'Reader Person',
              email: 'ilovenotifications@foo.com',
              created_at: new Date()
            })
          }
        })
      }

      return note.sendCommentNotificationEmail()
      .then(() => {
        expect(Email.sendNewCommentNotification).to.have.been.called()
        expect(args.data.post_label).to.equal('"hello world"')
      })
    })
  })
})
<|endoftext|>


<commit_before>/**
 * # http.js
 * Copyright(c) 2019 Stefano Balietti
 * MIT Licensed
 *
 * Configuration file for Express server in nodegame-server
 */
module.exports = configure;

// ## Global scope

var express = require('express'),
    fs = require('fs'),
    path = require('path'),
    os = require('os'),
    J = require('nodegame-client').JSUS;

var mime = require('express').static.mime;

var bodyParser = require('body-parser'),
    cookieParser = require('cookie-parser'),
    errorHandler = require('errorhandler');

// var session = require('cookie-session')({ secret: 'secret' });

/**
 * ### configure
 *
 * Defines standard routes for the HTTP server
 *
 * @param {object} options The object containing the custom settings
 */
function configure(app, servernode) {
    var rootDir, publicDir;
    var resourceManager;
    var basepath;

    rootDir = servernode.rootDir;
    publicDir = path.join(rootDir, 'public');
    basepath = servernode.basepath || '';
    resourceManager = servernode.resourceManager;

    app.set('views', path.resolve(rootDir, 'views'));
    app.set('view engine', 'jade');
    app.set('view options', {layout: false});

    if (process.env.NODE_ENV === 'development') {
        app.use(express.static(publicDir));
        app.use(errorHandler());
    }
    else {
        app.use(express.static(publicDir, { maxAge: 3600000 }));
    }

    app.disable('x-powered-by');
    app.enable("jsonp callback");

    app.use(cookieParser());
    // app.use(bodyParser());
    app.use(bodyParser.json());
    app.use(bodyParser.urlencoded({ extended: true }));

    function sendFromPublic(type, req, res, headers) {
        var file, mimeType, charset, filePath;
        file = req.params[0];
        if (!file) return;

        // Build path in `public/`.
        file = path.join(type, file);

        // Build headers.
        if (!headers) {
            mimeType = mime.lookup(file);
            charset = mime.charsets.lookup(mimeType);
            headers = { 'Content-Type': mimeType };
            if (charset) headers.charset = charset;
        }

        // If it is not text, it was not cached.
        if (headers['Content-Type'].substring(0,4) !== 'text') {
            filePath = path.resolve(publicDir, file);
            res.sendFile(filePath);
            return;
        }

        // Already found in `public/` and cached.
        resourceManager.getFromPublic('/', file, function(cachedFile) {

            // File found in public (cached or loaded).
            if (cachedFile) {
                res.set(headers);
                res.status(200).send(cachedFile);
            }
            else {
                // Send 404.
                res.status(404).send('File not found.');
            }
        });
    }

    app.get(basepath + '/javascripts/*', function(req, res) {
        sendFromPublic('javascripts', req, res, {
            'Content-Type': 'text/javascript',
            'charset': 'utf-8'
        });
    });

    app.get(basepath + '/sounds/*', function(req, res) {
        sendFromPublic('sounds', req, res, {
            'Content-Type': 'sound/ogg'
        });
    });

    app.get(basepath + '/stylesheets/*', function(req, res) {
        sendFromPublic('stylesheets', req, res, {
            'Content-Type': 'text/css',
            'charset': 'utf-8'
        });
    });

    app.get(basepath + '/images/*', function(req, res) {
        sendFromPublic('images', req, res, {
            'Content-Type': 'image/png'
        });
    });

    app.get(basepath + '/pages/*', function(req, res) {
        sendFromPublic('pages', req, res, {
            'Content-Type': 'text/html',
            'charset': 'utf-8'
        });
    });

    app.get(basepath + '/lib/*', function(req, res) {
        sendFromPublic('lib', req, res);
    });

    app.get(basepath + '/', function(req, res, next) {
        var q, games = [];

        var gamesObj;
        var i, j;
        var colors;
        var name, card, color, filteredGames;

        if (servernode.defaultChannel) {
            next();
            return;
        }

        if (J.isEmpty(req.query)) {
            if (servernode.homePage === false ||
                servernode.homePage.enabled === false) {

                res.render('index_simple', {
                    title: 'Yay! nodeGame server is running.'
                });
            }
            else {
                colors = servernode.homePage.colors;
                gamesObj = servernode.info.games;
                listOfGames = J.keys(gamesObj);
                // Remove aliases.
                filteredGames = listOfGames.filter(function(name) {
                    return (!gamesObj[name].errored &&
                            (!gamesObj[name].alias ||
                             gamesObj[name].alias.indexOf(name) === -1));
                });
                if (J.isArray(servernode.homePage.cardsOrder)) {
                    filteredGames =
                        servernode.homePage.cardsOrder.filter(function(name) {
                            if (filteredGames.indexOf(name) !== -1) return true;
                            servernode.logger.error('homePage.cardsOrder ' +
                                                    'game not found: ' + name);
                        });
                }
                else {
                    filteredGames.sort();
                }
                i = 0;
                for (j = 0; j < filteredGames.length; j++) {
                    name = filteredGames[j];
                    if (i >= colors.length) i = 0;
                    color = colors[i];
                    // Mixout name and description from package.json
                    // if not in card, or if no card is defined.
                    card = J.mixout(gamesObj[name].info.card || {}, {
                        name: name.charAt(0).toUpperCase() + name.slice(1),
                        description: gamesObj[name].info.description
                    });
                    games.push({
                        name: card.name,
                        color: color,
                        url: card.url,
                        description: card.description,
                        publication: card.publication,
                        wiki: card.wiki,
                        icon: card.icon
                    });
                    i++;
                }
                res.render('homepage', {
                    title: servernode.homePage.title,
                    games: games,
                    nodeGameCard: servernode.homePage.nodeGameCard,
                    footerContent: servernode.homePage.footerContent,
                    logo: servernode.homePage.logo
                });
            }

            return;
        }

        if (servernode.enableInfoQuery) {

            q = req.query.q;
            if (!q) {
                res.status(400).send('Query must start with q=XXX');
                return;
            }

            switch(q) {
            case 'info':
                //console.log(servernode.info);
                res.status(200).send(servernode.info);
                break;

            case 'channels':
                //console.log(servernode.info);
                res.status(200).send(servernode.info.channels);
                break;

            case 'games':
                //console.log(servernode.info);
                res.status(200).send(servernode.info.games);
                break;
            default:
                res.status(400).send('Unknown query received.');
            }
        }
        else {
            res.status(403).end();
        }
    });

    return true;
}
<commit_msg>fixed infoQuery with default channel<commit_after>/**
 * # http.js
 * Copyright(c) 2019 Stefano Balietti
 * MIT Licensed
 *
 * Configuration file for Express server in nodegame-server
 */
module.exports = configure;

// ## Global scope

var express = require('express'),
    fs = require('fs'),
    path = require('path'),
    os = require('os'),
    J = require('nodegame-client').JSUS;

var mime = require('express').static.mime;

var bodyParser = require('body-parser'),
    cookieParser = require('cookie-parser'),
    errorHandler = require('errorhandler');

// var session = require('cookie-session')({ secret: 'secret' });

/**
 * ### configure
 *
 * Defines standard routes for the HTTP server
 *
 * @param {object} options The object containing the custom settings
 */
function configure(app, servernode) {
    var rootDir, publicDir;
    var resourceManager;
    var basepath;

    rootDir = servernode.rootDir;
    publicDir = path.join(rootDir, 'public');
    basepath = servernode.basepath || '';
    resourceManager = servernode.resourceManager;

    app.set('views', path.resolve(rootDir, 'views'));
    app.set('view engine', 'jade');
    app.set('view options', {layout: false});

    if (process.env.NODE_ENV === 'development') {
        app.use(express.static(publicDir));
        app.use(errorHandler());
    }
    else {
        app.use(express.static(publicDir, { maxAge: 3600000 }));
    }

    app.disable('x-powered-by');
    app.enable("jsonp callback");

    app.use(cookieParser());
    // app.use(bodyParser());
    app.use(bodyParser.json());
    app.use(bodyParser.urlencoded({ extended: true }));

    function sendFromPublic(type, req, res, headers) {
        var file, mimeType, charset, filePath;
        file = req.params[0];
        if (!file) return;

        // Build path in `public/`.
        file = path.join(type, file);

        // Build headers.
        if (!headers) {
            mimeType = mime.lookup(file);
            charset = mime.charsets.lookup(mimeType);
            headers = { 'Content-Type': mimeType };
            if (charset) headers.charset = charset;
        }

        // If it is not text, it was not cached.
        if (headers['Content-Type'].substring(0,4) !== 'text') {
            filePath = path.resolve(publicDir, file);
            res.sendFile(filePath);
            return;
        }

        // Already found in `public/` and cached.
        resourceManager.getFromPublic('/', file, function(cachedFile) {

            // File found in public (cached or loaded).
            if (cachedFile) {
                res.set(headers);
                res.status(200).send(cachedFile);
            }
            else {
                // Send 404.
                res.status(404).send('File not found.');
            }
        });
    }

    app.get(basepath + '/javascripts/*', function(req, res) {
        sendFromPublic('javascripts', req, res, {
            'Content-Type': 'text/javascript',
            'charset': 'utf-8'
        });
    });

    app.get(basepath + '/sounds/*', function(req, res) {
        sendFromPublic('sounds', req, res, {
            'Content-Type': 'sound/ogg'
        });
    });

    app.get(basepath + '/stylesheets/*', function(req, res) {
        sendFromPublic('stylesheets', req, res, {
            'Content-Type': 'text/css',
            'charset': 'utf-8'
        });
    });

    app.get(basepath + '/images/*', function(req, res) {
        sendFromPublic('images', req, res, {
            'Content-Type': 'image/png'
        });
    });

    app.get(basepath + '/pages/*', function(req, res) {
        sendFromPublic('pages', req, res, {
            'Content-Type': 'text/html',
            'charset': 'utf-8'
        });
    });

    app.get(basepath + '/lib/*', function(req, res) {
        sendFromPublic('lib', req, res);
    });

    app.get(basepath + '/', function(req, res, next) {
        var q, games = [];

        var gamesObj;
        var i, j;
        var colors;
        var name, card, color, filteredGames;

        // Must be first.
        if (!J.isEmpty(req.query)) {
            if (servernode.enableInfoQuery) {

                q = req.query.q;
                if (!q) {
                    res.status(400).send('Query must start with q=XXX');
                    return;
                }

                switch(q) {
                case 'info':
                    //console.log(servernode.info);
                    res.status(200).send(servernode.info);
                    break;

                case 'channels':
                    //console.log(servernode.info);
                    res.status(200).send(servernode.info.channels);
                    break;

                case 'games':
                    //console.log(servernode.info);
                    res.status(200).send(servernode.info.games);
                    break;
                default:
                    res.status(400).send('Unknown query received.');
                }
            }
            else {
                res.status(403).end();
            }

            return;
        }

        if (servernode.defaultChannel) {
            next();
            return;
        }

        if (servernode.homePage === false ||
            servernode.homePage.enabled === false) {

            res.render('index_simple', {
                title: 'Yay! nodeGame server is running.'
            });
        }
        else {
            colors = servernode.homePage.colors;
            gamesObj = servernode.info.games;
            listOfGames = J.keys(gamesObj);
            // Remove aliases.
            filteredGames = listOfGames.filter(function(name) {
                return (!gamesObj[name].errored &&
                        (!gamesObj[name].alias ||
                         gamesObj[name].alias.indexOf(name) === -1));
            });
            if (J.isArray(servernode.homePage.cardsOrder)) {
                filteredGames =
                    servernode.homePage.cardsOrder.filter(function(name) {
                        if (filteredGames.indexOf(name) !== -1) return true;
                        servernode.logger.error('homePage.cardsOrder ' +
                                                'game not found: ' + name);
                    });
            }
            else {
                filteredGames.sort();
            }
            i = 0;
            for (j = 0; j < filteredGames.length; j++) {
                name = filteredGames[j];
                if (i >= colors.length) i = 0;
                color = colors[i];
                // Mixout name and description from package.json
                // if not in card, or if no card is defined.
                card = J.mixout(gamesObj[name].info.card || {}, {
                    name: name.charAt(0).toUpperCase() + name.slice(1),
                    description: gamesObj[name].info.description
                });
                games.push({
                    name: card.name,
                    color: color,
                    url: card.url,
                    description: card.description,
                    publication: card.publication,
                    wiki: card.wiki,
                    icon: card.icon
                });
                i++;
            }
            res.render('homepage', {
                title: servernode.homePage.title,
                games: games,
                nodeGameCard: servernode.homePage.nodeGameCard,
                footerContent: servernode.homePage.footerContent,
                logo: servernode.homePage.logo
            });
        }

    });

    return true;
}
<|endoftext|>


<commit_before>/**
 * Welcome to io.js!
 * Created by CreaturePhil
 *
 * io.js contains standard streams.
 *
 *
 * @license MIT license
 */

/* This is for standard input for the primitive type number in JavaScript. Standard input is data (often text) going into a program.
 * The program requests data transfers by use of the read operation.
 * @param property is the user's property that will be set to info in the function,
 * file is the storage for the data, and user is an object having its property modified.
 * @return void
 */
function stdinNumber(file, user, property){
	var info = 0;
	var match = false;

	var data = fs.readFileSync('config/'+file,'utf8');

	var row = (''+data).split("\n");
	for (var i = row.length; i > -1; i--) {
		if (!row[i]) continue;
		var parts = row[i].split(",");
		var userid = toUserid(parts[0]);
		if (user.userid === userid) {
			info = Number(parts[1]);
			match = true;
			if (match === true) {
				break;
			}
		}
	}
	Object.defineProperty(user, property, { value : info, writable : true });
}

/* This is for standard output for the primitive type number in JavaScript.
 * Standard output is the stream where a program writes its output data.
 * The program requests data transfer with the write operation.
 * @param property is the user's property,
 * file is the storage for the data, user is an object having its property modified,
 * amount is how much you want to change the user's property,
 * @return void, this function just writes the info into the file
 */
function stdoutNumber(file, user, property, amount) {
	var data = fs.readFileSync('config/'+file,'utf8');
	var match = false;
	var info = 0;
	var row = (''+data).split("\n");
	var line = '';
	for (var i = row.length; i > -1; i--) {
		if (!row[i]) continue;
		var parts = row[i].split(",");
		var userid = toUserid(parts[0]);
		if (user.userid === userid) {
			info = Number(parts[1]);
			match = true;
			if (match === true) {
				line = line + row[i];
				break;
			}
		}
	}
	var total = info + amount;
	Object.defineProperty(user, property, { value : total, writable : true });
	if (match === true) {
		var re = new RegExp(line,"g");
		fs.readFile('config/'+file, 'utf8', function(err, data) {
		if (err) {
			return console.log(err);
		}
		var result = data.replace(re, user.userid+','+total);
		fs.writeFile('config/'+file, result, 'utf8', function(err) {
			if (err) return console.log(err);
		});
		});
	} else {
		var log = fs.createWriteStream('config/'+file, {'flags': 'a'});
		log.write("\n"+user.userid+','+total);
	}
}

/* This is for standard input for the primitive type string in JavaScript. Standard input is data (often text) going into a program.
 * The program requests data transfers by use of the read operation.
 * @param file is where the data is stored, user is the object having its property modified,
 * and property is the user's property being modified.
 * @return void
 */
function stdinString(file, user, property) {
		var info = "";
		var match = false;

    	var data = fs.readFileSync('config/'+file,'utf8');

        var row = (''+data).split("\n");
        for (var i = row.length; i > -1; i--) {
                if (!row[i]) continue;
                var parts = row[i].split(",");
                var userid = toUserid(parts[0]);
                if (user.userid == userid) {
                	info = String(parts[1]);
                    match = true;
                    if (match === true) {
                            break;
                    }
                }
        }
		Object.defineProperty(user, property, { value : info, writable : true });
}

/* This is for standard output for the primitive type string in JavaScript.
 * Standard output is the stream where a program writes its output data.
 * The program requests data transfer with the write operation.
 * @param file is where the data is stored, user is the object where it's parameter is being modified,
 * property is the user's property being modified, and
 * info is used to stored the new user's property and being written in the file.
 * @return void, this function just writes the info into the file
 */
function stdoutString(file, user, property, info) {
	var data = fs.readFileSync('config/'+file,'utf8');
	var match = false;
	var row = (''+data).split("\n");
	var line = '';
	for (var i = row.length; i > -1; i--) {
		if (!row[i]) continue;
		var parts = row[i].split(",");
		var userid = toUserid(parts[0]);
		if (user.userid == userid) {
			match = true;
			if (match === true) {
				line = line + row[i];
				break;
			}
		}
	}
	Object.defineProperty(user, property, { value : info, writable : true });
	if (match === true) {
		var re = new RegExp(line,"g");
		fs.readFile('config/'+file, 'utf8', function (err,data) {
		if (err) {
			return console.log(err);
		}
		var result = data.replace(re, user.userid+','+info);
		fs.writeFile('config/'+file, result, 'utf8', function (err) {
			if (err) return console.log(err);
		});
		});
	} else {
		var log = fs.createWriteStream('config/'+file, {'flags': 'a'});
		log.write("\n"+user.userid+','+info);
	}
}

exports.stdinNumber = stdinNumber;
exports.stdoutNumber = stdoutNumber;
exports.stdinString = stdinString;
exports.stdoutString = stdoutString;
<commit_msg>Delete io.js<commit_after><|endoftext|>


<commit_before>var controllers = {};

exports = module.exports = ControllerLoader;
function ControllerLoader(base_path) {
  this._template_loader = new TemplateLoader(base_path);

  var controllers_path = path.join(base_path, "app", "c");

  if (path.existsSync(controllers_path)) {
    ext.File.directory_descent_wrapper(controllers_path, function(controller_file) {
      var stats = fs.statSync(controller_file);
      if (!stats.isFile()) return;

      if (path.extname(controller_file) !== ".js") {
        Gourdian.logger.error("Warning: Controller files must have an extension of .js (omitting: " + controller_file + ")");
        return
      }

      var filename_wo_ext = controller_file.substring(0, controller_file.length - 3)
        , relative_file = filename_wo_ext.replace(controllers_path, "")
        , class_name = get_controller_name_from_prefix(relative_file)

      if (global[class_name] !== undefined) {
        Gourdian.logger.error("Warning: naming conflict (omitting:" + class_name + ")");
        return;
      }

      global[class_name] = controllers[class_name] = require(controller_file);
      Gourdian.logger.info("File: " + controller_file + " loaded as " + class_name);
    });
  }
}

ControllerLoader.prototype.run = function(route, client_session, request_body, response) {
  var action = this.get(route, client_session, request_body);

  Gourdian.logger.info("Serving: " + route.controller + "." + route.action);

  var action_result = action();

  // full response
  if (typeof action_result === "string") {
    response.writeHead(200, { "Content-Length": action_result.length, "Content-Type": "text/html" });
    response.end(action_result);

  // chunked response
  } else if (typeof action_result === "object") {
    var template_path = path.join(route.controller, route.action);

    Gourdian.logger.info("Looking up template for " + template_path);
    this._template_loader.run(template_path, "dust", action_result, response);
  }
}

ControllerLoader.prototype.get = function(route, client_session, request_body, socket, message, sockets) {
  Gourdian.logger.info("Looking up: " + route.controller + "." + route.action);
  var controller = get_controller_name_from_prefix(route.controller)
    , action = route.action;

  // ensure controller is in the cache
  if (controllers[controller] === undefined || !controllers[controller]) {
    Gourdian.logger.error("Warning: Controller " + controller + " not found");
    return false;
  }

  // ensure the controller properly instantiates and the action is a function
  var controller_instance = new controllers[controller];
  if (typeof controller_instance[action] !== "function") {
    Gourdian.logger.error("Warning: No action " + action + " on " + controller);
    return false;
  }

  // add context
  controller_instance.session = client_session;
  controller_instance.request_body = request_body;
  controller_instance.socket = socket;
  controller_instance.message = message;
  controller_instance.sockets = sockets;

  // return the action bound to the instance context, returning its value
  return (function () {
    return controller_instance[action].call(controller_instance);
  });
}

function get_controller_name_from_prefix(prefix) {
  return ext.Inflect.classify([prefix, "controller"].join("_"));
}
<commit_msg>whitespace<commit_after>var controllers = {};

exports = module.exports = ControllerLoader;
function ControllerLoader(base_path) {
  this._template_loader = new TemplateLoader(base_path);

  var controllers_path = path.join(base_path, "app", "c");

  if (path.existsSync(controllers_path)) {
    ext.File.directory_descent_wrapper(controllers_path, function(controller_file) {
      var stats = fs.statSync(controller_file);
      if (!stats.isFile()) return;

      if (path.extname(controller_file) !== ".js") {
        Gourdian.logger.error("Warning: Controller files must have an extension of .js (omitting: " + controller_file + ")");
        return
      }

      var filename_wo_ext = controller_file.substring(0, controller_file.length - 3)
        , relative_file = filename_wo_ext.replace(controllers_path, "")
        , class_name = get_controller_name_from_prefix(relative_file)

      if (global[class_name] !== undefined) {
        Gourdian.logger.error("Warning: naming conflict (omitting:" + class_name + ")");
        return;
      }

      global[class_name] = controllers[class_name] = require(controller_file);
      Gourdian.logger.info("File: " + controller_file + " loaded as " + class_name);
    });
  }
}

ControllerLoader.prototype.run = function(route, client_session, request_body, response) {
  var action = this.get(route, client_session, request_body);

  Gourdian.logger.info("Serving: " + route.controller + "." + route.action);

  var action_result = action();

  // full response
  if (typeof action_result === "string") {
    response.writeHead(200, { "Content-Length": action_result.length, "Content-Type": "text/html" });
    response.end(action_result);

  // chunked response
  } else if (typeof action_result === "object") {
    var template_path = path.join(route.controller, route.action);

    Gourdian.logger.info("Looking up template for " + template_path);
    this._template_loader.run(template_path, "dust", action_result, response);
  }
}

ControllerLoader.prototype.get = function(route, client_session, request_body, socket, message, sockets) {
  Gourdian.logger.info("Looking up: " + route.controller + "." + route.action);
  var controller = get_controller_name_from_prefix(route.controller)
    , action = route.action;

  // ensure controller is in the cache
  if (controllers[controller] === undefined || !controllers[controller]) {
    Gourdian.logger.error("Warning: Controller " + controller + " not found");
    return false;
  }

  // ensure the controller properly instantiates and the action is a function
  var controller_instance = new controllers[controller];
  if (typeof controller_instance[action] !== "function") {
    Gourdian.logger.error("Warning: No action " + action + " on " + controller);
    return false;
  }

  // add context
  controller_instance.session = client_session;
  controller_instance.request_body = request_body;
  controller_instance.socket = socket;
  controller_instance.message = message;
  controller_instance.sockets = sockets;

  // return the action bound to the instance context, returning its value
  return (function () {
    return controller_instance[action].call(controller_instance);
  });
}

function get_controller_name_from_prefix(prefix) {
  return ext.Inflect.classify([prefix, "controller"].join("_"));
}
<|endoftext|>