javascript/core: allow raised exceptions in glob stream
SEE: vanadium/issues#587
Change-Id: I273d8979ef85484575f59ef90f81fb1f1be7808e
diff --git a/src/proxy/stream-handler.js b/src/proxy/stream-handler.js
index 9566da0..c76c6ee 100644
--- a/src/proxy/stream-handler.js
+++ b/src/proxy/stream-handler.js
@@ -76,6 +76,10 @@
emitStreamError(handler._stream,
new vError.InternalError(
handler._ctx, 'Failed to decode result: ', e));
+ }).catch(function(e) {
+ process.nextTick(function() {
+ throw e;
+ });
});
};
diff --git a/src/rpc/client.js b/src/rpc/client.js
index aca847f..d9ebfb9 100644
--- a/src/rpc/client.js
+++ b/src/rpc/client.js
@@ -251,9 +251,13 @@
var rpc = this;
return vom.decode(data, false, this._typeDecoder).then(function(data) {
rpc._def.stream._queueRead(data);
- }).catch(function(e) {
+ }, function(e) {
rpc.handleError(
new verror.InternalError(rpc._ctx, 'Failed to decode result: ', e));
+ }).catch(function(e) {
+ process.nextTick(function() {
+ throw e;
+ });
});
};
diff --git a/test/integration/test-js-client-server.js b/test/integration/test-js-client-server.js
index 7c58e0b..d909e9c 100644
--- a/test/integration/test-js-client-server.js
+++ b/test/integration/test-js-client-server.js
@@ -984,3 +984,52 @@
// 5. End the stream.
stream.end();
}
+
+test('Test server stream exception handling', function(assert) {
+ var exception;
+
+ if (typeof window === 'undefined') {
+ process.on('uncaughtException', function setexception(err) {
+ exception = err;
+ process.removeListener('uncaughtException', setexception);
+ });
+ } else {
+ window.onerror = function(message, url, line, column, err) {
+ exception = err;
+ // Put it back to the default
+ window.onerror = null;
+ };
+ }
+
+ var service = {
+ get: function get(context, serverCall, $stream, cb) {
+ $stream.on('end', cb.bind(null, null, {}));
+ $stream.on('error', cb);
+ $stream.on('data', function ondata(buffer) {
+ throw new Error('Woah!');
+ });
+ }
+ };
+
+ setup(service, function ready(err, context, remote, end) {
+ assert.error(err, 'should not error on setup');
+
+ var stream = remote.get(context, function(err) {
+ assert.error(err);
+ assert.ok(exception, 'stream exceptions should be raised');
+ end(assert);
+ }).stream;
+
+ stream.write('foo');
+ stream.end();
+ });
+
+ function setup(service, cb) {
+ var dispatcher = leafDispatcher(service);
+ var name = 'test/server-stream-exception';
+
+ serve(name, dispatcher, function(err, res) {
+ cb(err, res.runtime.getContext(), res.service, res.end);
+ });
+ }
+});
diff --git a/test/integration/test-namespace.js b/test/integration/test-namespace.js
index ee56a42..5712e4e 100644
--- a/test/integration/test-namespace.js
+++ b/test/integration/test-namespace.js
@@ -50,6 +50,60 @@
}
});
+test('Test glob().stream - exception handling', function(assert) {
+ vanadium.init(function onruntime(err, runtime) {
+ if (err) {
+ return end(err);
+ }
+
+ var namespace = runtime.namespace();
+ var context = runtime.getContext();
+ var promise = namespace.glob(context, '*');
+ var stream = promise.stream;
+ var exception;
+
+ promise.catch(function(err) {
+ assert.error(err, 'should not catch expceptions in stream');
+ });
+
+ if (typeof window === 'undefined') {
+ process.on('uncaughtException', function setexception(err) {
+ exception = err;
+ process.removeListener('uncaughtException', setexception);
+ });
+ } else {
+ window.onerror = function(message, url, line, column, err) {
+ exception = err;
+ // Put it back to the default
+ window.onerror = null;
+ };
+ }
+
+ // NOTE: Using assert.throws(fn) here is not possible since the fix is to
+ // use process.nextTick(...) wich will have the raised exception bypass the
+ // try/catch stack around where assert.throws(...) calls the passed in fn.
+ stream.once('data', function onentry(entry) {
+ throw new Error('Woah!');
+ });
+
+ stream.on('end', end);
+
+ function end(err) {
+ if (err) {
+ assert.error(err, 'should not error');
+ }
+
+ assert.ok(exception, 'glob-stream exceptions should be raised');
+
+ if (runtime) {
+ runtime.close(assert.end);
+ } else {
+ assert.end();
+ }
+ }
+ });
+});
+
test('Test globbing nested levels - glob(' + PREFIX + 'cottage/*/*/*)',
function(assert) {
var runtime;