Repository: basho/riak-nodejs-client
Pull request #81 (2015-06-30 22:37:09)

Catch exception when JSON.parse throws exception.
Minor changes to the code in PR #78 (CLIENTS-500)

Thanks @mogadanez


Patch:
diff --git a/README.md b/README.md
index 21e7064..63ea4be 100644
--- a/README.md
+++ b/README.md
@@ -65,3 +65,4 @@ Thank you to all of our contributors!
 * [Charlie Zhang](https://github.com/charliezhang) 
 * [Colin Hemmings](https://github.com/gonzohunter)
 * [Timothy Stonis](https://github.com/tstonis)
+* [Aleksandr Popov](https://github.com/mogadanez)
diff --git a/lib/commands/kv/fetchvalue.js b/lib/commands/kv/fetchvalue.js
index 1e801c8..865e4ee 100644
--- a/lib/commands/kv/fetchvalue.js
+++ b/lib/commands/kv/fetchvalue.js
@@ -107,8 +107,7 @@ FetchValue.prototype.constructPbRequest = function() {
 
 };
 
-FetchValue.prototype.onSuccess = function(rpbGetResp) {
-
+FetchValue.prototype._parseResponse = function(rpbGetResp) {
     // If the response is null ... it means not found. Riak only sends
     // a message code and zero bytes when that's the case.
     // Because that makes sense!
@@ -157,9 +156,20 @@ FetchValue.prototype.onSuccess = function(rpbGetResp) {
     } else {
         response = { isNotFound: true, isUnchanged: false, vclock: null, values: [] };
     }
+    return response;
+};
 
-    this._callback(null, response);
+FetchValue.prototype.onSuccess = function(rpbGetResp) {
+    var response;
+    try {
+        response = this._parseResponse(rpbGetResp);
+    }
+    catch (err) {
+        this._callback(err, null);
+        return true;
+    }
 
+    this._callback(null, response);
     return true;
 };
 
diff --git a/lib/core/riakcluster.js b/lib/core/riakcluster.js
index a2991ad..896f8ef 100644
--- a/lib/core/riakcluster.js
+++ b/lib/core/riakcluster.js
@@ -176,7 +176,7 @@ RiakCluster.prototype._shutdown = function () {
  * Selects a RiakNode from the cluster and executes the command on it.
  * @method execute
  * @param {Object} riakCommand - the command to execute.
- * @param {RiakNode} [previous] the previos node this command was attempted on
+ * @param {RiakNode} [previous] the previous node this command was attempted on
  */
 RiakCluster.prototype.execute = function(riakCommand, previous) {
 


Test patch:
diff --git a/test/unit/kv/fetchvalue.js b/test/unit/kv/fetchvalue.js
index a6b4432..2150606 100644
--- a/test/unit/kv/fetchvalue.js
+++ b/test/unit/kv/fetchvalue.js
@@ -24,11 +24,39 @@ var RpbErrorResp = rpb.getProtoFor('RpbErrorResp');
 
 var assert = require('assert');
 
+function generateTestRpbContent(value, contentType) {
+    var rpbContent = new RpbContent();
+    rpbContent.setValue(new Buffer(value));
+    rpbContent.setContentType(new Buffer(contentType));
+
+    var pair = new RpbPair();
+    pair.setKey(new Buffer('email_bin'));
+    pair.setValue(new Buffer('roach@basho.com'));
+    rpbContent.indexes.push(pair);
+
+    pair = new RpbPair();
+    pair.setKey(new Buffer('metaKey1'));
+    pair.setValue(new Buffer('metaValue1'));
+    rpbContent.usermeta.push(pair);
+
+    var link = new RpbLink();
+    link.setBucket(new Buffer('b'));
+    link.setKey(new Buffer('k'));
+    link.setTag(new Buffer('t'));
+    rpbContent.links.push(link);
+    link = new RpbLink();
+    link.setBucket(new Buffer('b'));
+    link.setKey(new Buffer('k2'));
+    link.setTag(new Buffer('t2'));
+    rpbContent.links.push(link);
+    return rpbContent;
+}
+
 describe('FetchValue', function() {
 
     describe('Build', function() {
         it('should build a RpbGetReq correctly', function(done) {
-            
+
             var vclock = new Buffer(0);
             var fetchCommand = new FetchValue.Builder()
                .withBucketType('bucket_type')
@@ -44,9 +72,9 @@ describe('FetchValue', function() {
                .withTimeout(20000)
                .withCallback(function(){})
                .build();
-       
+
             var protobuf = fetchCommand.constructPbRequest();
-            
+
             assert.equal(protobuf.getType().toString('utf8'), 'bucket_type');
             assert.equal(protobuf.getBucket().toString('utf8'), 'bucket_name');
             assert.equal(protobuf.getKey().toString('utf8'), 'key');
@@ -59,96 +87,128 @@ describe('FetchValue', function() {
             assert(protobuf.getIfModified().toBuffer() !== null);
             assert.equal(protobuf.getTimeout(), 20000);
             done();
-            
+
         });
-        
+
         it('should take a RpbGetResp and call the users callback with the response', function(done) {
-            
-            var rpbContent = new RpbContent();
-            rpbContent.setValue(new Buffer('this is a value'));
-            rpbContent.setContentType(new Buffer('application/json'));
-            
-            var pair = new RpbPair();
-            pair.setKey(new Buffer('email_bin'));
-            pair.setValue(new Buffer('roach@basho.com'));
-            rpbContent.indexes.push(pair);
-            
-            pair = new RpbPair();
-            pair.setKey(new Buffer('metaKey1'));
-            pair.setValue(new Buffer('metaValue1'));
-            rpbContent.usermeta.push(pair);
-            
-            var link = new RpbLink();
-            link.setBucket(new Buffer('b'));
-            link.setKey(new Buffer('k'));
-            link.setTag(new Buffer('t'));
-            rpbContent.links.push(link);
-            link = new RpbLink();
-            link.setBucket(new Buffer('b'));
-            link.setKey(new Buffer('k2'));
-            link.setTag(new Buffer('t2'));
-            rpbContent.links.push(link);
-            
+
+            var rpbContent = generateTestRpbContent('this is a value', "application/json" );
+
             var rpbGetResp = new RpbGetResp();
             rpbGetResp.setContent(rpbContent);
             rpbGetResp.setVclock(new Buffer('1234'));
-            
+
             var callback = function(err, response) {
-                if (response) {
-                    assert.equal(response.values.length, 1);
-                    var riakObject = response.values[0];
-                    assert.equal(riakObject.getBucketType(), 'bucket_type');
-                    assert.equal(riakObject.getBucket(), 'bucket_name');
-                    assert.equal(riakObject.getKey(), 'key');
-                    assert.equal(riakObject.getContentType(), 'application/json');
-                    assert.equal(riakObject.hasIndexes(), true);
-                    assert.equal(riakObject.getIndex('email_bin')[0], 'roach@basho.com');
-                    assert.equal(riakObject.hasUserMeta(), true);
-                    assert.equal(riakObject.getUserMeta()[0].key, 'metaKey1');
-                    assert.equal(riakObject.getUserMeta()[0].value, 'metaValue1');
-                    assert.equal(riakObject.getLinks()[0].bucket, 'b');
-                    assert.equal(riakObject.getLinks()[0].key, 'k');
-                    assert.equal(riakObject.getLinks()[0].tag, 't');
-                    assert.equal(riakObject.getLinks()[1].bucket, 'b');
-                    assert.equal(riakObject.getLinks()[1].key, 'k2');
-                    assert.equal(riakObject.getLinks()[1].tag, 't2');
-                    assert.equal(riakObject.getVClock().toString('utf8'), '1234');
-                    done();
-                }
+                assert(!err, err);
+                assert(response, 'expected a response!');
+                assert.equal(response.values.length, 1);
+                var riakObject = response.values[0];
+                assert.equal(riakObject.getBucketType(), 'bucket_type');
+                assert.equal(riakObject.getBucket(), 'bucket_name');
+                assert.equal(riakObject.getKey(), 'key');
+                assert.equal(riakObject.getContentType(), 'application/json');
+                assert.equal(riakObject.hasIndexes(), true);
+                assert.equal(riakObject.getIndex('email_bin')[0], 'roach@basho.com');
+                assert.equal(riakObject.hasUserMeta(), true);
+                assert.equal(riakObject.getUserMeta()[0].key, 'metaKey1');
+                assert.equal(riakObject.getUserMeta()[0].value, 'metaValue1');
+                assert.equal(riakObject.getLinks()[0].bucket, 'b');
+                assert.equal(riakObject.getLinks()[0].key, 'k');
+                assert.equal(riakObject.getLinks()[0].tag, 't');
+                assert.equal(riakObject.getLinks()[1].bucket, 'b');
+                assert.equal(riakObject.getLinks()[1].key, 'k2');
+                assert.equal(riakObject.getLinks()[1].tag, 't2');
+                assert.equal(riakObject.getVClock().toString('utf8'), '1234');
+                done();
             };
-            
+
             var fetchCommand = new FetchValue.Builder()
                .withBucketType('bucket_type')
                .withBucket('bucket_name')
                .withKey('key')
                .withCallback(callback)
                .build();
-       
+
             fetchCommand.onSuccess(rpbGetResp);
        });
-       
-       it ('should take a RpbErrorResp and call the users callback with the error message', function(done) {
+
+        describe('when convertToJs provided as true', function(){
+
+            it('should take a RpbGetResp and call the users callback with the error when unable to parse', function(done) {
+                var rpbContent = generateTestRpbContent('this is a value', "text/plain");
+
+                var rpbGetResp = new RpbGetResp();
+                rpbGetResp.setContent(rpbContent);
+                rpbGetResp.setVclock(new Buffer('1234'));
+
+                var callback = function(err, response) {
+                    assert(err, 'expected an error!');
+                    assert(!response, 'did NOT expect a response!');
+                    done();
+                };
+
+                var fetchCommand = new FetchValue.Builder()
+                    .withBucketType('bucket_type')
+                    .withBucket('bucket_name')
+                    .withKey('key')
+                    .withConvertValueToJs(true)
+                    .withCallback(callback)
+                    .build();
+
+                fetchCommand.onSuccess(rpbGetResp);
+            });
+
+            it('should take a RpbGetResp and call the users callback with the parsed body if able to parse', function(done) {
+                var rpbContent = generateTestRpbContent('{"key":"value"}', "application/json");
+
+                var rpbGetResp = new RpbGetResp();
+                rpbGetResp.setContent(rpbContent);
+                rpbGetResp.setVclock(new Buffer('1234'));
+
+                var callback = function(err, response) {
+                    assert(!err, err);
+                    assert.equal(response.values.length, 1);
+                    var riakObject = response.values[0];
+                    var parsedValue = riakObject.getValue();
+                    assert(typeof parsedValue === "object");
+                    assert.equal(parsedValue.key, "value");
+                    done();
+                };
+
+                var fetchCommand = new FetchValue.Builder()
+                    .withBucketType('bucket_type')
+                    .withBucket('bucket_name')
+                    .withKey('key')
+                    .withConvertValueToJs(true)
+                    .withCallback(callback)
+                    .build();
+
+                fetchCommand.onSuccess(rpbGetResp);
+            });
+        });
+
+        it ('should take a RpbErrorResp and call the users callback with the error message', function(done) {
            var rpbErrorResp = new RpbErrorResp();
            rpbErrorResp.setErrmsg(new Buffer('this is an error'));
-           
+
            var callback = function(err, response) {
                if (err) {
                    assert.equal(err,'this is an error');
                    done();
                }
            };
-           
+
            var fetchCommand = new FetchValue.Builder()
                .withBucketType('bucket_type')
                .withBucket('bucket_name')
                .withKey('key')
                .withCallback(callback)
                .build();
-       
+
             fetchCommand.onRiakError(rpbErrorResp);
-           
-           
+
+
        });
-       
+
     });
 });