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);