Make test-bless.js more thorough and related fixes

MultiPart: 1/2
Change-Id: I18175330473837afbbdbabd61443615119d485e5
diff --git a/src/rpc/server-router.js b/src/rpc/server-router.js
index 4c649ae..5c327fe 100644
--- a/src/rpc/server-router.js
+++ b/src/rpc/server-router.js
@@ -148,11 +148,11 @@
                                             router._typeEncoder),
                               Outgoing.AUTHORIZATION_RESPONSE, null, messageId);
   }).catch(function(e) {
-    var errMsg = {
+    var authReply = new AuthReply({
       err: ErrorConversion.fromNativeValue(e, router._appName,
                                            decodedRequest.call.method)
-    };
-    router._proxy.sendRequest(hexVom.encode(errMsg, undefined,
+    });
+    router._proxy.sendRequest(hexVom.encode(authReply, undefined,
                                             router._typeEncoder),
                               Outgoing.AUTHORIZATION_RESPONSE, null,
                               messageId);
diff --git a/test/integration/test-bless.js b/test/integration/test-bless.js
index a3f147e..7fc6de9 100644
--- a/test/integration/test-bless.js
+++ b/test/integration/test-bless.js
@@ -28,6 +28,11 @@
     runtime.principal.blessSelf(runtime.getContext(), 'blessedname')
     .then(function(blessings) {
       validateBlessings(t, blessings);
+      t.equal(blessings.chains.length, 1, 'Has exactly one chain');
+      t.equal(blessings.chains[0].length, 1, 'Chain has exactly one blessing');
+      t.equal(blessings.chains[0][0].extension, 'blessedname',
+        'Has correct extension');
+      t.equal(blessings.chains[0][0].caveats.length, 0, 'Has no caveats');
       rt.close(t.end);
     }).catch(function(err) {
       t.error(err);
@@ -45,11 +50,17 @@
 
     rt = runtime;
 
-    runtime.principal.blessSelf(runtime.getContext(), 'blessedname',
-      security.createExpiryCaveat(new Date()),
+    var cav = security.createExpiryCaveat(new Date());
+    runtime.principal.blessSelf(runtime.getContext(), 'blessedname', cav,
       function(err, blessings) {
       t.error(err);
       validateBlessings(t, blessings);
+      t.equal(blessings.chains.length, 1, 'Has exactly one chain');
+      t.equal(blessings.chains[0].length, 1, 'Chain has exactly one blessing');
+      t.equal(blessings.chains[0][0].extension, 'blessedname',
+        'Has correct extension');
+      t.equal(blessings.chains[0][0].caveats.length, 1, 'Has one caveat');
+      t.deepEqual(blessings.chains[0][0].caveats[0], cav, 'Has correct caveat');
       rt.close(t.end);
     });
   });
@@ -89,11 +100,20 @@
       var rt = vanadium.runtimeForContext(ctx);
       var secCall = serverCall.securityCall;
       var remoteKey = secCall.remoteBlessings.publicKey;
+      var expiryCav = security.createExpiryCaveat(new Date(Date.now() - 1000));
+      var constCav = security.createConstCaveat(true);
       rt.principal.bless(ctx, remoteKey, secCall.localBlessings,
-       'ext', security.createExpiryCaveat(new Date(Date.now() - 1000)),
-       security.createConstCaveat(true), function(err, blessings) {
+       'ext', expiryCav, constCav, function(err, blessings) {
          t.notOk(err, 'No error expected during bless');
          validateBlessings(t, blessings);
+         for (var i = 0; i < blessings.chains.length; i++) {
+           var chain = blessings.chains[i];
+           t.equal(chain[chain.length - 1].extension, 'ext',
+            'Expected final extension to match');
+           t.deepEqual(chain[chain.length - 1].caveats.sort(objectSorter),
+             [expiryCav, constCav].sort(objectSorter),
+             'Has correct caveats');
+         }
          cb(null, null);
        });
     }
@@ -159,47 +179,88 @@
     });
 });
 
-// TODO(bprosnitz) This test is weak. Improve it.
+// Tests add roots by trying to invoke a method with a blessing not in the
+// roots and then adding it to the roots.
 test('Test add roots', function(t) {
-  var rt;
-  vanadium.init(config, function(err, runtime) {
+  var service = {
+    method: function(ctx, serverCall) {
+      return 'aResponse';
+    }
+  };
+
+  var authorizer = function(ctx, securityCall) {
+    var hasBlessedName = securityCall.remoteBlessingStrings.some(function(str) {
+      return str === 'blessedname';
+    });
+    if (hasBlessedName) {
+      return Promise.resolve();
+    }
+    return Promise.reject(new Error('Expected blessedname in blessings'));
+  };
+
+  serve('testing/addroots', leafDispatcher(service, authorizer),
+    function(err, res) {
     if (err) {
       t.end(err);
+      return;
     }
 
-    rt = runtime;
-
-    runtime.principal.blessSelf(runtime.getContext(), 'blessedname')
-    .then(function(blessings) {
+    var runtime = res.runtime;
+    var ctx = runtime.getContext();
+    var blessings;
+    var origDefault;
+    var origTripDot;
+    runtime.principal.blessSelf(ctx, 'blessedname')
+    .then(function(selfBlessings) {
+      blessings = selfBlessings;
       validateBlessings(t, blessings);
-
-      return runtime.principal.addToRoots(runtime.getContext(), blessings);
+      // Get the original blessings used for '...' and save them for later.
+      return runtime.principal.blessingStore.forPeer(ctx, '...');
+    }).then(function(oldBlessings) {
+      origTripDot = oldBlessings;
+      // Replace it with the union of the old and the new self-blessing
+      return vanadium.security.unionOfBlessings(ctx, oldBlessings, blessings);
+    }).then(function(unionedBlessings) {
+      return runtime.principal.blessingStore.set(ctx, unionedBlessings, '...');
     }).then(function() {
-      rt.close(t.end);
+      // Get the original default blessings and save them for later.
+      return runtime.principal.blessingStore.getDefault(ctx);
+    }).then(function(oldDefault) {
+      origDefault = oldDefault;
+      // Replace it with the union of the old and the new self-blessing
+      return vanadium.security.unionOfBlessings(ctx, oldDefault, blessings);
+    }).then(function(unionedBlessings) {
+      return runtime.principal.blessingStore.setDefault(ctx, unionedBlessings);
     }).catch(function(err) {
-      t.error(err, 'either blessSelf or addToRoots errored ' + err);
-      rt.close(t.end);
+      t.error('Failed to configure blessings: ' + err);
+    }).then(function() {
+      // Attempt to call the method; it should fail.
+      return res.service.method(ctx);
+    }).then(function() {
+      t.error('Method call unexpectedly succeeded without valid roots');
+    }).catch(function() {
+      return runtime.principal.addToRoots(ctx, blessings);
+    }).then(function() {
+      // Call the method after addToRoots; it should succeed.
+      return res.service.method(ctx);
+    }).then(function(result) {
+      t.equal(result, 'aResponse', 'Got correct result');
+    }).catch(function(err) {
+      t.error('either blessSelf or addToRoots errored ' + err);
+    }).then(function() {
+      // Reset the blessingStore for default blessings.
+      return runtime.principal.blessingStore.setDefault(ctx, origDefault);
+    }).then(function() {
+      // Reset the blessingStore for peer '...'
+      return runtime.principal.blessingStore.set(ctx, origTripDot, '...');
+    }).catch(function(err) {
+      t.error('Unexpected error resetting blessing store');
+    }).then(function(){
+      res.end(t);
     });
   });
 });
 
-test('Test fetching blessing debug string', function(t) {
-  var rt;
-  vanadium.init(config, function(err, runtime) {
-    if (err) {
-      t.end(err);
-    }
-
-    rt = runtime;
-
-    runtime.principal.blessSelf(runtime.getContext(), 'blessedname')
-    .then(function(blessings) {
-      t.ok(blessings.chains[0][0].extension === 'blessedname',
-        'Blessing had correct extension');
-      rt.close(t.end);
-    }).catch(function(err) {
-      t.error(err);
-      rt.close(t.end);
-    });
-  });
-});
+function objectSorter(a, b) {
+  return JSON.stringify(a) < JSON.stringify(b);
+}
diff --git a/test/integration/test-remote-blessings.js b/test/integration/test-remote-blessings.js
index 84d0316..4c3548b 100644
--- a/test/integration/test-remote-blessings.js
+++ b/test/integration/test-remote-blessings.js
@@ -14,7 +14,8 @@
   t.ok(Array.isArray(blessings), 'blessings is an array');
   t.ok(blessings.length > 0, 'blessings has at least one blessing');
   t.ok(defaultBlessingRegex.test(blessings[0]),
-      'blessings[0] matches the default blessing regex.');
+      'blessings[0]: ' + blessings[0] +
+      ' should match the default blessings regex ' + defaultBlessingRegex);
 }
 
 var serverName = 'foo';