Repository: luin/ioredis
Pull request #295 (2016-05-07 09:21:48)

feat: add support for Node.js v6
Release notes: https://nodejs.org/en/blog/release/v6.0.0/


Patch:
diff --git a/.travis.yml b/.travis.yml
index a125fb3..3e79c12 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -5,8 +5,9 @@ node_js:
 - '0.11'
 - '0.12'
 - 'iojs'
-- '4.0'
-- '4.1'
+- '4'
+- '5'
+- '6'
 
 services:
 - redis-server
diff --git a/README.md b/README.md
index f0a8ecd..c0a6be1 100644
--- a/README.md
+++ b/README.md
@@ -563,7 +563,6 @@ Besides the above connection events, there are several other custom events:
 
 Event    | Description
 :------------- | :-------------
-authError | emits when the password specified in the options is wrong or the server doesn't require a password.
 select   | emits when the database changed. The argument is the new db number.
 
 ## Offline Queue
diff --git a/lib/cluster/index.js b/lib/cluster/index.js
index 926da18..959dc11 100644
--- a/lib/cluster/index.js
+++ b/lib/cluster/index.js
@@ -337,7 +337,7 @@ Cluster.prototype.refreshSlotsCache = function (callback) {
 };
 
 /**
- * Flush offline queue and command queue with error.
+ * Flush offline queue with error.
  *
  * @param {Error} error - The error object to send to the commands
  * @private
diff --git a/lib/redis.js b/lib/redis.js
index d119760..24b9e74 100644
--- a/lib/redis.js
+++ b/lib/redis.js
@@ -377,9 +377,14 @@ Redis.prototype.flushQueue = function (error, options) {
   }
 
   if (options.commandQueue) {
-    while (this.commandQueue.length > 0) {
-      item = this.commandQueue.shift();
-      item.command.reject(error);
+    if (this.commandQueue.length > 0) {
+      if (this.stream) {
+        this.stream.removeAllListeners('data');
+      }
+      while (this.commandQueue.length > 0) {
+        item = this.commandQueue.shift();
+        item.command.reject(error);
+      }
     }
   }
 };
diff --git a/lib/redis/event_handler.js b/lib/redis/event_handler.js
index 85ffcc9..c7407d6 100644
--- a/lib/redis/event_handler.js
+++ b/lib/redis/event_handler.js
@@ -11,16 +11,24 @@ exports.connectHandler = function (self) {
     self.resetCommandQueue();
 
     // AUTH command should be processed before any other commands
+    var flushed = false;
     if (self.condition.auth) {
       self.auth(self.condition.auth, function (err) {
         if (err) {
-          self.emit('authError', err);
+          if (err.message.indexOf('no password is set') === -1) {
+            flushed = true;
+            self.flushQueue(err);
+            self.silentEmit('error', err);
+            self.disconnect(true);
+          } else {
+            console.warn('[WARN] Redis server does not require a password, but a password was supplied.');
+          }
         }
       });
     }
 
     if (self.condition.select) {
-      self.selectBuffer(self.condition.select);
+      self.select(self.condition.select);
     }
 
     if (!self.options.enableReadyCheck) {
@@ -32,9 +40,10 @@ exports.connectHandler = function (self) {
     if (self.options.enableReadyCheck) {
       self._readyCheck(function (err, info) {
         if (err) {
-          self.flushQueue(new Error('Ready check failed: ' + err.message));
-          if (!self.condition.auth && err.message.split(' ')[0] === 'NOAUTH') {
-            self.emit('authError', err);
+          if (!flushed) {
+            self.flushQueue(new Error('Ready check failed: ' + err.message));
+            self.silentEmit('error', err);
+            self.disconnect(true);
           }
         } else {
           self.serverInfo = info;
@@ -147,7 +156,7 @@ exports.readyHandler = function (self) {
         // `SELECT` command is not valid in sub mode.
         if (self.condition.select !== finalSelect) {
           debug('connect to db [%d]', finalSelect);
-          self.selectBuffer(finalSelect);
+          self.select(finalSelect);
         }
         var subscribeChannels = condition.subscriber.channels('subscribe');
         if (subscribeChannels.length) {
@@ -192,7 +201,7 @@ exports.readyHandler = function (self) {
 
     if (self.condition.select !== finalSelect) {
       debug('connect to db [%d]', finalSelect);
-      self.selectBuffer(finalSelect);
+      self.select(finalSelect);
     }
   };
 };


Test patch:
diff --git a/test/functional/auth.js b/test/functional/auth.js
index 49fc8d9..5637bbb 100644
--- a/test/functional/auth.js
+++ b/test/functional/auth.js
@@ -41,44 +41,62 @@ describe('auth', function () {
     });
   });
 
-  it('should emit "authError" when the server doesn\'t need auth', function (done) {
+  it('should not emit "error" when the server doesn\'t need auth', function (done) {
     var server = new MockServer(17379, function (argv) {
       if (argv[0] === 'auth' && argv[1] === 'pass') {
         return new Error('ERR Client sent AUTH, but no password is set');
       }
     });
+    var errorEmited = false;
     var redis = new Redis({ port: 17379, password: 'pass' });
-    redis.on('authError', function (error) {
-      expect(error).to.have.property('message', 'ERR Client sent AUTH, but no password is set');
-      redis.disconnect();
-      server.disconnect();
-      done();
+    redis.on('error', function () {
+      errorEmited = true;
+    });
+    stub(console, 'warn', function (warn) {
+      expect(warn).to.match(/but a password was supplied/);
+      console.warn.restore();
+      setTimeout(function () {
+        expect(errorEmited).to.eql(false);
+        redis.disconnect();
+        server.disconnect();
+        done();
+      }, 0);
     });
   });
 
-  it('should emit "authError" when the password is wrong', function (done) {
+  it('should emit "error" when the password is wrong', function (done) {
     var server = new MockServer(17379, function (argv) {
       if (argv[0] === 'auth' && argv[1] === 'pass') {
         return new Error('ERR invalid password');
       }
     });
     var redis = new Redis({ port: 17379, password: 'pass' });
-    redis.on('authError', function (error) {
+    var pending = 2;
+    function check() {
+      if (!--pending) {
+        redis.disconnect();
+        server.disconnect();
+        done();
+      }
+    }
+    redis.on('error', function (error) {
       expect(error).to.have.property('message', 'ERR invalid password');
-      redis.disconnect();
-      server.disconnect();
-      done();
+      check();
+    });
+    redis.get('foo', function (err, res) {
+      expect(err.message).to.eql('ERR invalid password');
+      check();
     });
   });
 
-  it('should emit "authError" when password is not provided', function (done) {
+  it('should emit "error" when password is not provided', function (done) {
     var server = new MockServer(17379, function (argv) {
       if (argv[0] === 'info') {
         return new Error('NOAUTH Authentication required.');
       }
     });
     var redis = new Redis({ port: 17379 });
-    redis.on('authError', function (error) {
+    redis.on('error', function (error) {
       expect(error).to.have.property('message', 'NOAUTH Authentication required.');
       redis.disconnect();
       server.disconnect();
diff --git a/test/functional/drop_buffer_support.js b/test/functional/drop_buffer_support.js
index 9f16fd0..f8fd92b 100644
--- a/test/functional/drop_buffer_support.js
+++ b/test/functional/drop_buffer_support.js
@@ -87,5 +87,16 @@ describe('dropBufferSupport', function () {
         done();
       });
     });
+
+    it('should work with internal select command', function (done) {
+      var redis = new Redis({ dropBufferSupport: true, db: 1 });
+      var check = new Redis({ db: 1 });
+      redis.set('foo', 'bar', function () {
+        check.get('foo', function (err, res) {
+          expect(res).to.eql('bar');
+          done();
+        });
+      });
+    });
   });
 });
diff --git a/test/functional/ready_check.js b/test/functional/ready_check.js
index 4507d55..075f4fd 100644
--- a/test/functional/ready_check.js
+++ b/test/functional/ready_check.js
@@ -16,4 +16,20 @@ describe('ready_check', function () {
     });
     redis.connect();
   });
+
+  it('should reconnect when info return a error', function (done) {
+    var redis = new Redis({
+      lazyConnect: true,
+      retryStrategy: function () {
+        done();
+        return;
+      }
+    });
+
+    stub(redis, 'info', function (callback) {
+      callback(new Error('info error'));
+    });
+
+    redis.connect();
+  });
 });