Merge "core.js: Cleaning up security docs."
diff --git a/extension/manifest.json b/extension/manifest.json
index 665efe8..e0424cb 100644
--- a/extension/manifest.json
+++ b/extension/manifest.json
@@ -1,6 +1,6 @@
 {
   "name": "Vanadium Extension",
-  "version": "0.0.59",
+  "version": "0.0.60",
   "description": "Access and create Vanadium services from JavaScript.",
   "manifest_version": 2,
   "icons": {
diff --git a/src/gen-vdl/v.io/v23/rpc/index.js b/src/gen-vdl/v.io/v23/rpc/index.js
index 3ce4409..5c9a115 100644
--- a/src/gen-vdl/v.io/v23/rpc/index.js
+++ b/src/gen-vdl/v.io/v23/rpc/index.js
@@ -35,7 +35,7 @@
 _typeBlessingsRequest.fields = [{name: "Key", type: vdl.types.UINT64}, {name: "Blessings", type: _type1}];
 _typeRequest.kind = vdl.kind.STRUCT;
 _typeRequest.name = "v.io/v23/rpc.Request";
-_typeRequest.fields = [{name: "Suffix", type: vdl.types.STRING}, {name: "Method", type: vdl.types.STRING}, {name: "NumPosArgs", type: vdl.types.UINT64}, {name: "EndStreamArgs", type: vdl.types.BOOL}, {name: "Deadline", type: new time.WireDeadline()._type}, {name: "GrantedBlessings", type: new security.WireBlessings()._type}, {name: "Blessings", type: _typeBlessingsRequest}, {name: "Discharges", type: _type2}, {name: "TraceRequest", type: new vtrace.Request()._type}];
+_typeRequest.fields = [{name: "Suffix", type: vdl.types.STRING}, {name: "Method", type: vdl.types.STRING}, {name: "NumPosArgs", type: vdl.types.UINT64}, {name: "EndStreamArgs", type: vdl.types.BOOL}, {name: "Deadline", type: new time.WireDeadline()._type}, {name: "GrantedBlessings", type: new security.WireBlessings()._type}, {name: "Blessings", type: _typeBlessingsRequest}, {name: "Discharges", type: _type2}, {name: "TraceRequest", type: new vtrace.Request()._type}, {name: "Language", type: vdl.types.STRING}];
 _typeResponse.kind = vdl.kind.STRUCT;
 _typeResponse.name = "v.io/v23/rpc.Response";
 _typeResponse.fields = [{name: "Error", type: vdl.types.ERROR}, {name: "EndStreamResults", type: vdl.types.BOOL}, {name: "NumPosResults", type: vdl.types.UINT64}, {name: "TraceResponse", type: new vtrace.Response()._type}, {name: "AckBlessings", type: vdl.types.BOOL}];
diff --git a/src/gen-vdl/v.io/x/ref/services/wspr/internal/app/index.js b/src/gen-vdl/v.io/x/ref/services/wspr/internal/app/index.js
index 69b7bf9..9c4d3eb 100644
--- a/src/gen-vdl/v.io/x/ref/services/wspr/internal/app/index.js
+++ b/src/gen-vdl/v.io/x/ref/services/wspr/internal/app/index.js
@@ -68,7 +68,7 @@
 _typeRpcCallOption.fields = [{name: "AllowedServersPolicy", type: _type2}, {name: "RetryTimeout", type: new time.Duration()._type}, {name: "UseGranter", type: _typeGranterHandle}];
 _typeRpcRequest.kind = vdl.kind.STRUCT;
 _typeRpcRequest.name = "v.io/x/ref/services/wspr/internal/app.RpcRequest";
-_typeRpcRequest.fields = [{name: "Name", type: vdl.types.STRING}, {name: "Method", type: vdl.types.STRING}, {name: "NumInArgs", type: vdl.types.INT32}, {name: "NumOutArgs", type: vdl.types.INT32}, {name: "IsStreaming", type: vdl.types.BOOL}, {name: "Deadline", type: new time.WireDeadline()._type}, {name: "TraceRequest", type: new vtrace.Request()._type}, {name: "CallOptions", type: _type1}];
+_typeRpcRequest.fields = [{name: "Name", type: vdl.types.STRING}, {name: "Method", type: vdl.types.STRING}, {name: "NumInArgs", type: vdl.types.INT32}, {name: "NumOutArgs", type: vdl.types.INT32}, {name: "IsStreaming", type: vdl.types.BOOL}, {name: "Deadline", type: new time.WireDeadline()._type}, {name: "TraceRequest", type: new vtrace.Request()._type}, {name: "Context", type: new server.Context()._type}, {name: "CallOptions", type: _type1}];
 _typeRpcResponse.kind = vdl.kind.STRUCT;
 _typeRpcResponse.name = "v.io/x/ref/services/wspr/internal/app.RpcResponse";
 _typeRpcResponse.fields = [{name: "OutArgs", type: _type3}, {name: "TraceResponse", type: new vtrace.Response()._type}];
diff --git a/src/gen-vdl/v.io/x/ref/services/wspr/internal/rpc/server/index.js b/src/gen-vdl/v.io/x/ref/services/wspr/internal/rpc/server/index.js
index 4ff928b..cd45b2d 100644
--- a/src/gen-vdl/v.io/x/ref/services/wspr/internal/rpc/server/index.js
+++ b/src/gen-vdl/v.io/x/ref/services/wspr/internal/rpc/server/index.js
@@ -29,6 +29,7 @@
 var _type6 = new vdl.Type();
 var _typeCaveatValidationRequest = new vdl.Type();
 var _typeCaveatValidationResponse = new vdl.Type();
+var _typeContext = new vdl.Type();
 var _typeSecurityCall = new vdl.Type();
 var _typeServerRpcRequest = new vdl.Type();
 var _typeServerRpcRequestCall = new vdl.Type();
@@ -52,10 +53,13 @@
 _type6.elem = new principal.JsBlessings()._type;
 _typeCaveatValidationRequest.kind = vdl.kind.STRUCT;
 _typeCaveatValidationRequest.name = "v.io/x/ref/services/wspr/internal/rpc/server.CaveatValidationRequest";
-_typeCaveatValidationRequest.fields = [{name: "Call", type: _typeSecurityCall}, {name: "Cavs", type: _type3}];
+_typeCaveatValidationRequest.fields = [{name: "Call", type: _typeSecurityCall}, {name: "Context", type: _typeContext}, {name: "Cavs", type: _type3}];
 _typeCaveatValidationResponse.kind = vdl.kind.STRUCT;
 _typeCaveatValidationResponse.name = "v.io/x/ref/services/wspr/internal/rpc/server.CaveatValidationResponse";
 _typeCaveatValidationResponse.fields = [{name: "Results", type: _type5}];
+_typeContext.kind = vdl.kind.STRUCT;
+_typeContext.name = "v.io/x/ref/services/wspr/internal/rpc/server.Context";
+_typeContext.fields = [{name: "Language", type: vdl.types.STRING}];
 _typeSecurityCall.kind = vdl.kind.STRUCT;
 _typeSecurityCall.name = "v.io/x/ref/services/wspr/internal/rpc/server.SecurityCall";
 _typeSecurityCall.fields = [{name: "Method", type: vdl.types.STRING}, {name: "Suffix", type: vdl.types.STRING}, {name: "MethodTags", type: _type1}, {name: "LocalBlessings", type: new principal.JsBlessings()._type}, {name: "LocalBlessingStrings", type: _type2}, {name: "RemoteBlessings", type: new principal.JsBlessings()._type}, {name: "RemoteBlessingStrings", type: _type2}, {name: "LocalEndpoint", type: vdl.types.STRING}, {name: "RemoteEndpoint", type: vdl.types.STRING}];
@@ -64,7 +68,7 @@
 _typeServerRpcRequest.fields = [{name: "ServerId", type: vdl.types.UINT32}, {name: "Handle", type: vdl.types.INT32}, {name: "Method", type: vdl.types.STRING}, {name: "Args", type: _type1}, {name: "Call", type: _typeServerRpcRequestCall}];
 _typeServerRpcRequestCall.kind = vdl.kind.STRUCT;
 _typeServerRpcRequestCall.name = "v.io/x/ref/services/wspr/internal/rpc/server.ServerRpcRequestCall";
-_typeServerRpcRequestCall.fields = [{name: "SecurityCall", type: _typeSecurityCall}, {name: "Deadline", type: new time.WireDeadline()._type}, {name: "TraceRequest", type: new vtrace.Request()._type}, {name: "GrantedBlessings", type: _type6}];
+_typeServerRpcRequestCall.fields = [{name: "SecurityCall", type: _typeSecurityCall}, {name: "Deadline", type: new time.WireDeadline()._type}, {name: "Context", type: _typeContext}, {name: "TraceRequest", type: new vtrace.Request()._type}, {name: "GrantedBlessings", type: _type6}];
 _type1.freeze();
 _type2.freeze();
 _type3.freeze();
@@ -73,11 +77,13 @@
 _type6.freeze();
 _typeCaveatValidationRequest.freeze();
 _typeCaveatValidationResponse.freeze();
+_typeContext.freeze();
 _typeSecurityCall.freeze();
 _typeServerRpcRequest.freeze();
 _typeServerRpcRequestCall.freeze();
 module.exports.CaveatValidationRequest = (vdl.registry.lookupOrCreateConstructor(_typeCaveatValidationRequest));
 module.exports.CaveatValidationResponse = (vdl.registry.lookupOrCreateConstructor(_typeCaveatValidationResponse));
+module.exports.Context = (vdl.registry.lookupOrCreateConstructor(_typeContext));
 module.exports.SecurityCall = (vdl.registry.lookupOrCreateConstructor(_typeSecurityCall));
 module.exports.ServerRpcRequest = (vdl.registry.lookupOrCreateConstructor(_typeServerRpcRequest));
 module.exports.ServerRpcRequestCall = (vdl.registry.lookupOrCreateConstructor(_typeServerRpcRequestCall));
diff --git a/src/proxy/websocket.js b/src/proxy/websocket.js
index 9deb710..b2d33f9 100644
--- a/src/proxy/websocket.js
+++ b/src/proxy/websocket.js
@@ -7,12 +7,13 @@
  * @fileoverview WebSocket client implementation
  */
 
-var WebSocket = require('ws');
-var Deferred = require('./../lib/deferred');
-var vlog = require('./../lib/vlog');
-var Proxy = require('./index');
 var isBrowser = require('is-browser');
+var WebSocket = require('ws');
+
 var byteUtil = require('../vdl/byte-util');
+var Deferred = require('./../lib/deferred');
+var Proxy = require('./index');
+var vlog = require('./../lib/vlog');
 var vom = require('../vom');
 
 /**
@@ -75,13 +76,11 @@
     // TODO(jasoncampbell): there can be more errors than just failed
     // connection, additionally there can be more than one error emitted. We
     // should take care to cover these cases.
-    // TODO(nlacasse): Add tests that check for this error when bad wspr url is
-    // provided.
-    var error = new Error('Failed to connect to wspr at url ' + self.url +
-        ': ' + e.message);
+    e.message = 'Failed to connect to wspr at url ' + self.url +
+        ': ' + e.message;
 
-    vlog.logger.error(error);
-    deferred.reject(error);
+    vlog.logger.error(e);
+    deferred.reject(e);
   };
 
   websocket.onmessage = function(frame) {
diff --git a/src/rpc/client.js b/src/rpc/client.js
index 1a2d20f..f27971d 100644
--- a/src/rpc/client.js
+++ b/src/rpc/client.js
@@ -44,7 +44,6 @@
 var Blessings = require('../security/blessings');
 var JsBlessings =
   require('../gen-vdl/v.io/x/ref/services/wspr/internal/principal').JsBlessings;
-var SharedContextKeys = require('../runtime/shared-context-keys');
 
 
 var OutstandingRPC = function(ctx, options, cb) {
@@ -280,6 +279,7 @@
     timeout.noDeadline = true;
   }
 
+  var language = this._ctx.value(SharedContextKeys.LANG_KEY) || '';
   var jsonMessage = {
     name: this._name,
     method: this._methodName,
@@ -289,7 +289,10 @@
     isStreaming: this._isStreaming,
     traceRequest: vtrace.request(this._ctx),
     deadline: timeout,
-    callOptions: this._callOptions
+    callOptions: this._callOptions,
+    context: {
+      language: language,
+    }
   };
 
   var header = new RpcRequest(jsonMessage);
diff --git a/src/rpc/server-router.js b/src/rpc/server-router.js
index db5fb5d..fa11661 100644
--- a/src/rpc/server-router.js
+++ b/src/rpc/server-router.js
@@ -42,7 +42,7 @@
   require('../gen-vdl/v.io/x/ref/services/wspr/internal/principal').JsBlessings;
 var WireBlessings =
   require('../gen-vdl/v.io/v23/security').WireBlessings;
-
+var SharedContextKeys = require('../runtime/shared-context-keys');
 
 /**
  * A router that handles routing incoming requests to the right
@@ -112,11 +112,14 @@
     this._proxy.sendRequest(data, Outgoing.AUTHORIZATION_RESPONSE,
         null, messageId);
   }
+
+  var ctx = this._rootCtx.withValue(SharedContextKeys.LANG_KEY,
+                                    request.context.language);
   var server = this._servers[request.serverId];
   if (!server) {
     var data = JSON.stringify({
       // TODO(bjornick): Use the real context
-      err: new verror.ExistsError(this._rootCtx, 'unknown server')
+      err: new verror.ExistsError(ctx, 'unknown server')
     });
     this._proxy.sendRequest(data, Outgoing.AUTHORIZATION_RESPONSE,
         null, messageId);
@@ -124,7 +127,7 @@
   }
   var router = this;
   var call = new SecurityCall(request.call, this._controller);
-  var ctx = this._rootCtx;
+
   server.handleAuthorization(request.handle, ctx, call).then(function() {
     router._proxy.sendRequest('{}', Outgoing.AUTHORIZATION_RESPONSE, null,
         messageId);
@@ -167,7 +170,8 @@
 Router.prototype.handleCaveatValidationRequest = function(messageId, request) {
   var resultPromises = new Array(request.cavs.length);
   var call = new SecurityCall(request.call);
-  var ctx = this._rootCtx;
+  var ctx = this._rootCtx.withValue(SharedContextKeys.LANG_KEY,
+                                    request.context.language);
   for (var i = 0; i < request.cavs.length; i++) {
     resultPromises[i] = this._validateChain(ctx, call, request.cavs[i]);
   }
@@ -303,6 +307,8 @@
   } else {
     ctx = ctx.withCancel();
   }
+  ctx = ctx.withValue(SharedContextKeys.LANG_KEY,
+                      request.call.context.language);
   // Plumb through the vtrace ids
   var suffix = request.call.securityCall.suffix;
   var spanName = '<jsserver>"'+suffix+'".'+request.method;
diff --git a/src/vdl/canonicalize.js b/src/vdl/canonicalize.js
index 871ec4e..31392c4 100644
--- a/src/vdl/canonicalize.js
+++ b/src/vdl/canonicalize.js
@@ -33,7 +33,7 @@
 var util = require('./util.js');
 var stringify = require('./stringify.js');
 var typeCompatible = require('./type-compatible.js');
-var typeObjectFromkind = require('./type-object-from-kind.js');
+var typeObjectFromKind = require('./type-object-from-kind.js');
 var nativeTypeRegistry = require('./native-type-registry');
 require('./es6-shim');
 
@@ -654,13 +654,13 @@
   if (!type.hasOwnProperty('kind')) {
     throw new TypeError('kind not specified');
   }
-  if (typeof type.kind !== 'number') {
+  if (typeof type.kind !== 'string') {
     throw new TypeError('kind expected to be a number. Got ' + type.kind);
   }
 
   // The Type for each kind has its own Type Object.
   // Verify deeply that the given type is in the correct form.
-  var typeOfType = typeObjectFromkind(type.kind);
+  var typeOfType = typeObjectFromKind(type.kind);
 
   // If the type has a field that is not relevant to its kind, then throw.
   Object.keys(type).forEach(function(key) {
diff --git a/src/vdl/error-conversion.js b/src/vdl/error-conversion.js
index c788178..1f30af6 100644
--- a/src/vdl/error-conversion.js
+++ b/src/vdl/error-conversion.js
@@ -143,7 +143,18 @@
   var errID = err.id || unknown.id;
   var errRetryCode = err.retryCode || unknown.retryCode;
 
+  var errProps = {};
   if (err instanceof Error) {
+    Object.getOwnPropertyNames(err).forEach(function(propName) {
+      if (propName === 'message') {
+        // Skip 'message' field since we set that ourselves to be enumerable.
+        return;
+      }
+      errProps[propName] = Object.getOwnPropertyDescriptor(err, propName);
+      // Set the property to non-enumerable.
+      errProps[propName].enumerable = false;
+    });
+
     message = err.message;
 
     paramList = ['app', 'call', message];
@@ -169,12 +180,17 @@
   var EConstructor = errorMap[errID] || verror.UnknownError;
   var e = new EConstructor(args);
 
-  // Fill the remaining error parameters. By using new on an Error, we will have
-  // a stack trace. Add the correct id, retryCode, message, etc.
+  // Add properties from original error.
+  Object.defineProperties(e, errProps);
+
+  // Add verror fields.
   e.id = errID;
   e.retryCode = errRetryCode;
   e.resetArgs.apply(e, paramList);
+
+  // Add message and msg so that they will be enumerable.
   e.message = message;
   e.msg = message;
+
   return e;
 }
diff --git a/src/vdl/kind.js b/src/vdl/kind.js
index beb369f..30d01ff 100644
--- a/src/vdl/kind.js
+++ b/src/vdl/kind.js
@@ -7,8 +7,6 @@
  * @private
  */
 
-var kindCount = 0;
-
 /**
  * @summary Namespace of constants for VDL kinds.
  * @description Namespace of constants for VDL kinds.
@@ -20,113 +18,98 @@
   /**
    * @const
    */
-  ANY: kindCount++,
+  ANY: 'any',
   /**
    * @const
    */
-  OPTIONAL: kindCount++,
+  OPTIONAL: 'optional',
   // Scalar kinds
   /**
    * @const
    */
-  BOOL: kindCount++,
+  BOOL: 'bool',
   /**
    * @const
    */
-  BYTE: kindCount++,
+  BYTE: 'byte',
   /**
    * @const
    */
-  UINT16: kindCount++,
+  UINT16: 'uint16',
   /**
    * @const
    */
-  UINT32: kindCount++,
+  UINT32: 'uint32',
   /**
    * @const
    */
-  UINT64: kindCount++,
+  UINT64: 'uint64',
   /**
    * @const
    */
-  INT16: kindCount++,
+  INT16: 'int16',
   /**
    * @const
    */
-  INT32: kindCount++,
+  INT32: 'int32',
   /**
    * @const
    */
-  INT64: kindCount++,
+  INT64: 'int64',
   /**
    * @const
    */
-  FLOAT32: kindCount++,
+  FLOAT32: 'float32',
   /**
    * @const
    */
-  FLOAT64: kindCount++,
+  FLOAT64: 'float64',
   /**
    * @const
    */
-  COMPLEX64: kindCount++,
+  COMPLEX64: 'complex64',
   /**
    * @const
    */
-  COMPLEX128: kindCount++,
+  COMPLEX128: 'complex128',
   /**
    * @const
    */
-  STRING: kindCount++,
+  STRING: 'string',
   /**
    * @const
    */
-  ENUM: kindCount++,
+  ENUM: 'enum',
   /**
    * @const
    */
-  TYPEOBJECT: kindCount++,
+  TYPEOBJECT: 'typeobject',
   // Composite kinds
   /**
    * @const
    */
-  ARRAY: kindCount++,
+  ARRAY: 'array',
   /**
    * @const
    */
-  LIST: kindCount++,
+  LIST: 'list',
   /**
    * @const
    */
-  SET: kindCount++,
+  SET: 'set',
   /**
    * @const
    */
-  MAP: kindCount++,
+  MAP: 'map',
   /**
    * @const
    */
-  STRUCT: kindCount++,
+  STRUCT: 'struct',
   /**
    * Union is like struct, but with only 1 field filled in.
    * @const
    */
-  UNION: kindCount++,
-};
-
-/**
- * Returns the human-readable name for a kind.
- * @param {module:vanadium.vdl.kind} k The kind to print out.
- * @return {string} Human-readable name for the kind.
- */
-kind.kindStr = function(k) {
-  var kindKeys = Object.keys(kind).filter(function(key) {
-    return kind[key] === k;
-  });
-  if (kindKeys.length !== 1) {
-    throw new TypeError('kind: ' + k + ' is not a known kind');
-  }
-  return kindKeys[0].toLowerCase(); // There should only be 1 result.
+  UNION: 'union',
 };
 
 module.exports = kind;
diff --git a/src/vdl/registry.js b/src/vdl/registry.js
index 68ee5ab..61190ab 100644
--- a/src/vdl/registry.js
+++ b/src/vdl/registry.js
@@ -31,7 +31,7 @@
   // constructor for those structs should be Type.
   Object.keys(kind).forEach(function(key) {
     var k = kind[key];
-    if (typeof k === 'number') {
+    if (typeof k === 'string') {
       var typeOfType = typeObjectFromKind(k);
       map.set(typeOfType, Type);
     }
diff --git a/src/vdl/type-object-from-kind.js b/src/vdl/type-object-from-kind.js
index 796d940..8ce6cc0 100644
--- a/src/vdl/type-object-from-kind.js
+++ b/src/vdl/type-object-from-kind.js
@@ -11,7 +11,7 @@
 var Type = require('./type.js');
 var types = require('./types.js');
 
-module.exports = typeObjectFromkind;
+module.exports = typeObjectFromKind;
 
 // All Types below are constructed with 'isValidated' set to true. This avoids a
 // cyclic dependency with canonicalize.js and type.js.
@@ -21,7 +21,7 @@
   fields: [
     {
       name: 'Kind',
-      type: types.UINT32
+      type: types.STRING
     },
     {
       name: 'Name',
@@ -36,7 +36,7 @@
   fields: [
     {
       name: 'Kind',
-      type: types.UINT32
+      type: types.STRING
     },
     {
       name: 'Name',
@@ -55,7 +55,7 @@
   fields: [
     {
       name: 'Kind',
-      type: types.UINT32
+      type: types.STRING
     },
     {
       name: 'Name',
@@ -77,7 +77,7 @@
   fields: [
     {
       name: 'Kind',
-      type: types.UINT32
+      type: types.STRING
     },
     {
       name: 'Name',
@@ -96,7 +96,7 @@
   fields: [
     {
       name: 'Kind',
-      type: types.UINT32
+      type: types.STRING
     },
     {
       name: 'Name',
@@ -119,7 +119,7 @@
   fields: [
     {
       name: 'Kind',
-      type: types.UINT32
+      type: types.STRING
     },
     {
       name: 'Name',
@@ -138,7 +138,7 @@
   fields: [
     {
       name: 'Kind',
-      type: types.UINT32
+      type: types.STRING
     },
     {
       name: 'Name',
@@ -161,7 +161,7 @@
   fields: [
     {
       name: 'Kind',
-      type: types.UINT32
+      type: types.STRING
     },
     {
       name: 'Name',
@@ -195,7 +195,7 @@
   fields: [
     {
       name: 'Kind',
-      type: types.UINT32
+      type: types.STRING
     },
     {
       name: 'Name',
@@ -229,7 +229,7 @@
  * @param {kind} k The kind.
  * @return {TypeObject} The corresponding type object.
  */
-function typeObjectFromkind(k) {
+function typeObjectFromKind(k) {
   switch (k) {
     case kind.BOOL:
     case kind.BYTE:
diff --git a/src/vdl/type.js b/src/vdl/type.js
index 497003e..40a769d 100644
--- a/src/vdl/type.js
+++ b/src/vdl/type.js
@@ -138,6 +138,6 @@
       });
       return s + '}';
     default:
-      return s + kind.kindStr(t.kind);
+      return s + t.kind;
   }
 }
diff --git a/test/integration/test-client-bind-to.js b/test/integration/test-client-bind-to.js
index 53eb28c..bda032f 100644
--- a/test/integration/test-client-bind-to.js
+++ b/test/integration/test-client-bind-to.js
@@ -97,7 +97,9 @@
   vanadium.init({ wspr: 'http://bad-address.tld' }, onruntime);
 
   function onruntime(err, runtime) {
-    assert.ok(err instanceof Error);
+    assert.ok(err instanceof Error, 'returns an error');
+    assert.ok(err.message.indexOf('Failed to connect') >= 0,
+              'error is connection error');
     assert.end();
   }
 });
@@ -114,7 +116,9 @@
     assert.error('should not have succeeded');
     assert.end();
   }, function(err) {
-    assert.ok(err instanceof Error);
+    assert.ok(err instanceof Error, 'returns an error');
+    assert.ok(err.message.indexOf('Failed to connect') >= 0,
+              'error is connection error');
     assert.end();
   });
 });
diff --git a/test/integration/test-server-call.js b/test/integration/test-server-call.js
new file mode 100644
index 0000000..b4eb53c
--- /dev/null
+++ b/test/integration/test-server-call.js
@@ -0,0 +1,165 @@
+// Copyright 2015 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+var test = require('prova');
+var serve = require('./serve');
+var leafDispatcher = require('../../src/rpc/leaf-dispatcher');
+
+// Services that handles anything in a/b/* where b is the service name
+var dispatcher = leafDispatcher({
+  getSuffix: function(ctx, serverCall) {
+    return serverCall.securityCall.suffix;
+  },
+  getContext: function(ctx, serverCall) {
+    return serverCall;
+  },
+  getArgs: function(ctx, serverCall, a, b, c, $stream, cb) {
+    var results = {
+      call: serverCall,
+      a: a,
+      b: b,
+      c: c
+    };
+
+    cb(null, results);
+  }
+});
+
+var expectedContext = {
+  suffix: 'suf',
+  methodTags: []
+};
+
+function contains(actual, expected, assert) {
+  for (var key in expected) {
+    if (!expected.hasOwnProperty(key)) {
+      continue;
+    }
+    assert.deepEqual(actual[key], expected[key]);
+  }
+}
+
+var defaultBlessingRegex = require('./default-blessing-regex');
+
+function blessingStringsMatch(strings, regex, assert) {
+  assert.ok(strings.length > 0, 'Context has strings');
+
+  for (var i = 0; i < strings.length; i++) {
+    assert.ok(regex.test(strings[i]),
+        'string[' + i + '] matches expected name');
+  }
+}
+
+function validateEndpoint(ep, assert) {
+  assert.ok(typeof ep === 'string',
+            'Endpoint should be string');
+  assert.ok(ep !== '', 'endpoint should not be empty');
+}
+
+function validateContext(call, assert) {
+  blessingStringsMatch(call.localBlessingStrings, defaultBlessingRegex,
+                         assert);
+  blessingStringsMatch(call.remoteBlessingStrings, defaultBlessingRegex,
+                         assert);
+  validateEndpoint(call.localEndpoint, assert);
+  validateEndpoint(call.remoteEndpoint, assert);
+}
+
+test('Test non-empty suffix is available in context', function(assert) {
+  serve('a/b', dispatcher, function(err, res, end) {
+    assert.error(err, 'should not error on serve(...)');
+    var client = res.runtime.newClient();
+    var ctx = res.runtime.getContext();
+    client.bindTo(ctx, 'a/b/foo', function(err, service) {
+      assert.error(err, 'should not error on runtime.bindTo(...)');
+
+      service.getSuffix(ctx, function(err, suffix) {
+        assert.error(err, 'should not error on getSuffix(...)');
+        assert.equal(suffix, 'foo');
+        end(assert);
+      });
+    });
+  });
+});
+
+test('Test empty suffix is available in context - ', function(assert) {
+  serve('a/b', dispatcher, function(err, res, end) {
+    assert.error(err, 'should not error on serve(...)');
+
+    var client = res.runtime.newClient();
+    var ctx = res.runtime.getContext();
+    client.bindTo(ctx, 'a/b', function(err, service) {
+      assert.error(err, 'should not error on runtime.bindTo(...)');
+
+      service.getSuffix(ctx, function(err, suffix) {
+        assert.error(err, 'should not error on getSuffix(...)');
+        assert.equal(suffix, '');
+        end(assert);
+      });
+    });
+  });
+});
+
+test('Test nested suffix /parent/suffix ', function(assert) {
+  serve('a/b', dispatcher, function(err, res, end) {
+    assert.error(err, 'should not error on serve(...)');
+    var client = res.runtime.newClient();
+    var ctx = res.runtime.getContext();
+    client.bindTo(ctx, 'a/b/parent/suf', function(err, service) {
+      assert.error(err, 'should not error on runtime.bindTo(...)');
+
+      service.getSuffix(ctx, function(err, suffix) {
+        assert.error(err, 'should not error on getSuffix(...)');
+        assert.equal(suffix, 'parent/suf');
+        end(assert);
+      });
+    });
+  });
+});
+
+test('Test context object', function(assert) {
+  serve('a/b', dispatcher, function(err, res, end) {
+    assert.error(err, 'should not error on serve(...)');
+
+    var client = res.runtime.newClient();
+    var ctx = res.runtime.getContext();
+    client.bindTo(ctx, 'a/b/suf', function(err, service) {
+      assert.error(err, 'should not error on runtime.bindTo(...)');
+
+      service.getContext(ctx, function(err, call) {
+        assert.error(err, 'should not error on getContext(...)');
+        contains(call.securityCall, expectedContext, assert);
+        validateContext(call.securityCall, assert);
+        end(assert);
+      });
+    });
+  });
+});
+
+test('Test context object and injected stream', function(assert) {
+  serve('a/b', dispatcher, function(err, res, end) {
+    assert.error(err, 'should not error on serve(...)');
+
+    var client = res.runtime.newClient();
+    var ctx = res.runtime.getContext();
+    client.bindTo(ctx, 'a/b/suf', function(err, service) {
+      assert.error(err, 'should not error on runtime.bindTo(...)');
+
+      service.getArgs(ctx, '-a-','-b-','-c-', function(err, results) {
+        assert.error(err, 'service.getArgs(...) should not error');
+
+        contains(results, {
+          a: '-a-',
+          b: '-b-',
+          c: '-c-'
+        }, assert);
+
+        var call = results.call.securityCall;
+        contains(call, expectedContext, assert);
+        validateContext(call, assert);
+        end(assert);
+      });
+    });
+  });
+});
diff --git a/test/integration/test-server-context.js b/test/integration/test-server-context.js
index b4eb53c..d84a9d3 100644
--- a/test/integration/test-server-context.js
+++ b/test/integration/test-server-context.js
@@ -5,161 +5,29 @@
 var test = require('prova');
 var serve = require('./serve');
 var leafDispatcher = require('../../src/rpc/leaf-dispatcher');
-
-// Services that handles anything in a/b/* where b is the service name
+var LANG_KEY = require('../../src/runtime/shared-context-keys').LANG_KEY;
 var dispatcher = leafDispatcher({
-  getSuffix: function(ctx, serverCall) {
-    return serverCall.securityCall.suffix;
-  },
-  getContext: function(ctx, serverCall) {
-    return serverCall;
-  },
-  getArgs: function(ctx, serverCall, a, b, c, $stream, cb) {
-    var results = {
-      call: serverCall,
-      a: a,
-      b: b,
-      c: c
-    };
-
-    cb(null, results);
+  test: function(ctx, serverCall) {
+    return ctx.value(LANG_KEY);
+  }
+}, function auth(ctx, call) {
+  if (ctx.value(LANG_KEY) !== 'my-lang') {
+    throw new Error('bad lang ' + ctx.value(LANG_KEY));
   }
 });
-
-var expectedContext = {
-  suffix: 'suf',
-  methodTags: []
-};
-
-function contains(actual, expected, assert) {
-  for (var key in expected) {
-    if (!expected.hasOwnProperty(key)) {
-      continue;
-    }
-    assert.deepEqual(actual[key], expected[key]);
-  }
-}
-
-var defaultBlessingRegex = require('./default-blessing-regex');
-
-function blessingStringsMatch(strings, regex, assert) {
-  assert.ok(strings.length > 0, 'Context has strings');
-
-  for (var i = 0; i < strings.length; i++) {
-    assert.ok(regex.test(strings[i]),
-        'string[' + i + '] matches expected name');
-  }
-}
-
-function validateEndpoint(ep, assert) {
-  assert.ok(typeof ep === 'string',
-            'Endpoint should be string');
-  assert.ok(ep !== '', 'endpoint should not be empty');
-}
-
-function validateContext(call, assert) {
-  blessingStringsMatch(call.localBlessingStrings, defaultBlessingRegex,
-                         assert);
-  blessingStringsMatch(call.remoteBlessingStrings, defaultBlessingRegex,
-                         assert);
-  validateEndpoint(call.localEndpoint, assert);
-  validateEndpoint(call.remoteEndpoint, assert);
-}
-
-test('Test non-empty suffix is available in context', function(assert) {
-  serve('a/b', dispatcher, function(err, res, end) {
+test('Test language in context', function(assert) {
+  serve('context', dispatcher, function(err, res, end) {
     assert.error(err, 'should not error on serve(...)');
     var client = res.runtime.newClient();
-    var ctx = res.runtime.getContext();
-    client.bindTo(ctx, 'a/b/foo', function(err, service) {
-      assert.error(err, 'should not error on runtime.bindTo(...)');
-
-      service.getSuffix(ctx, function(err, suffix) {
-        assert.error(err, 'should not error on getSuffix(...)');
-        assert.equal(suffix, 'foo');
-        end(assert);
-      });
-    });
-  });
-});
-
-test('Test empty suffix is available in context - ', function(assert) {
-  serve('a/b', dispatcher, function(err, res, end) {
-    assert.error(err, 'should not error on serve(...)');
-
-    var client = res.runtime.newClient();
-    var ctx = res.runtime.getContext();
-    client.bindTo(ctx, 'a/b', function(err, service) {
-      assert.error(err, 'should not error on runtime.bindTo(...)');
-
-      service.getSuffix(ctx, function(err, suffix) {
-        assert.error(err, 'should not error on getSuffix(...)');
-        assert.equal(suffix, '');
-        end(assert);
-      });
-    });
-  });
-});
-
-test('Test nested suffix /parent/suffix ', function(assert) {
-  serve('a/b', dispatcher, function(err, res, end) {
-    assert.error(err, 'should not error on serve(...)');
-    var client = res.runtime.newClient();
-    var ctx = res.runtime.getContext();
-    client.bindTo(ctx, 'a/b/parent/suf', function(err, service) {
-      assert.error(err, 'should not error on runtime.bindTo(...)');
-
-      service.getSuffix(ctx, function(err, suffix) {
-        assert.error(err, 'should not error on getSuffix(...)');
-        assert.equal(suffix, 'parent/suf');
-        end(assert);
-      });
-    });
-  });
-});
-
-test('Test context object', function(assert) {
-  serve('a/b', dispatcher, function(err, res, end) {
-    assert.error(err, 'should not error on serve(...)');
-
-    var client = res.runtime.newClient();
-    var ctx = res.runtime.getContext();
-    client.bindTo(ctx, 'a/b/suf', function(err, service) {
-      assert.error(err, 'should not error on runtime.bindTo(...)');
-
-      service.getContext(ctx, function(err, call) {
-        assert.error(err, 'should not error on getContext(...)');
-        contains(call.securityCall, expectedContext, assert);
-        validateContext(call.securityCall, assert);
-        end(assert);
-      });
-    });
-  });
-});
-
-test('Test context object and injected stream', function(assert) {
-  serve('a/b', dispatcher, function(err, res, end) {
-    assert.error(err, 'should not error on serve(...)');
-
-    var client = res.runtime.newClient();
-    var ctx = res.runtime.getContext();
-    client.bindTo(ctx, 'a/b/suf', function(err, service) {
-      assert.error(err, 'should not error on runtime.bindTo(...)');
-
-      service.getArgs(ctx, '-a-','-b-','-c-', function(err, results) {
-        assert.error(err, 'service.getArgs(...) should not error');
-
-        contains(results, {
-          a: '-a-',
-          b: '-b-',
-          c: '-c-'
-        }, assert);
-
-        var call = results.call.securityCall;
-        contains(call, expectedContext, assert);
-        validateContext(call, assert);
-        end(assert);
-      });
+    var ctx = res.runtime.getContext().withValue(LANG_KEY, 'my-lang');
+    client.bindTo(ctx, 'context').then(function(service) {
+      return service.test(ctx);
+    }).then(function(lang) {
+      assert.equal(lang, 'my-lang');
+      res.end(assert);
+    }).catch(function(err) {
+      assert.error(err);
+      res.end(assert);
     });
   });
 });
diff --git a/test/vdl/test-canonicalize.js b/test/vdl/test-canonicalize.js
index 7cc19e4..ac3deb2 100644
--- a/test/vdl/test-canonicalize.js
+++ b/test/vdl/test-canonicalize.js
@@ -1040,7 +1040,7 @@
     t.equal(output2Str, expectedStr, name + ' - idempotent');
 
     // Post-canonicalization, the type is still a TypeObject.
-    t.deepEqual(output._type, types.TYPEOBJECT, name + ' - is TypeObject');
+    t.deepEqual(output._type, types.TYPEOBJECT, name + ' - type is TypeObject');
   }
   t.end();
 });
diff --git a/test/vdl/test-vdl-errors.js b/test/vdl/test-vdl-errors.js
index b242931..156520a 100644
--- a/test/vdl/test-vdl-errors.js
+++ b/test/vdl/test-vdl-errors.js
@@ -61,16 +61,73 @@
   });
 }
 
-var unknownError = (new verror.UnknownError(null));
 test('var struct = ec.fromNativeValue(err)', function(assert) {
   var err = new Error(message);
-  var struct = ec.fromNativeValue(err, 'app', 'call');
-  struct.paramList = deepUnwrapParamList(struct.paramList);
+
+  // Add properties that NodeJS errors commonly have.
+  Object.defineProperties(err, {
+    arguments: {
+      value: undefined,
+      writable: true,
+      enumerable: false,
+      configurable: true
+    },
+    type: {
+      value: undefined,
+      writable: true,
+      enumerable: false,
+      configurable: true
+    },
+    errno: {
+      value: 34,
+      writable: true,
+      enumerable: true,
+      configurable: true
+    },
+    code: {
+      value: 'ENOENT',
+      writable: true,
+      enumerable: true,
+      configurable: true
+    },
+    path: {
+      value: '',
+      writable: true,
+      enumerable: true,
+      configurable: true
+    }
+  });
+
+  var verr = ec.fromNativeValue(err, 'app', 'call');
+  verr.paramList = deepUnwrapParamList(verr.paramList);
+
+  // Check that verr has the correct enumerable properties.
   var expectedError = new verror.UnknownError(null);
-  expectedError.message = message;
-  expectedError.msg = message;
-  expectedError.paramList = ['app', 'call', message];
-  assert.deepEqual(struct, expectedError);
+  expectedError.message = err.message;
+  expectedError.msg = err.message;
+  expectedError.paramList = ['app', 'call', err.message];
+  assert.deepEqual(verr, expectedError);
+
+  // Check that verr has the same properties (including non-enumerable
+  // properties) as the native error.
+  Object.getOwnPropertyNames(err).forEach(function(propName) {
+    assert.ok(verr.hasOwnProperty(propName), 'verror has expected property');
+    if (propName !== 'stack') {
+      // err.stack is a getter that returns different strings based on the
+      // error value, so we cannot check equality.
+      assert.equals(verr[propName], err[propName],
+                    'property matches original error');
+    }
+  });
+
+  // Check that 'code' and 'errno' properties are preserved from original
+  // error, and are not enumerable.
+  (['code', 'errno']).forEach(function(prop) {
+    assert.equal(verr[prop], err[prop], 'has the correct value for ' + prop );
+    assert.equal(Object.getOwnPropertyDescriptor(verr, 'code').enumerable,
+                 false, 'property ' + prop + ' is not enumerable');
+  });
+
   assert.end();
 });
 
@@ -99,6 +156,7 @@
 });
 
 test('Error => Struct => Error', function(assert) {
+  var unknownError = new verror.UnknownError(null);
   var message = 'testing JS error conversion';
   var original = new Error(message);
   var struct = ec.fromNativeValue(original);