From 3b76f7c969dfdf3999d4a212af78e4adce1f6642 Mon Sep 17 00:00:00 2001 From: David Abdemoulaie Date: Tue, 6 Jun 2017 15:44:07 -0500 Subject: [PATCH] Fix error handling in edge promises * Now properly handles errors raised within deeply nested futures. * `value!` now properly works with `rejected_future` Fixes #659 --- lib/concurrent/edge/promises.rb | 4 ++-- spec/concurrent/edge/promises_spec.rb | 14 +++++++++++++- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/lib/concurrent/edge/promises.rb b/lib/concurrent/edge/promises.rb index e139f9665..a5643237d 100644 --- a/lib/concurrent/edge/promises.rb +++ b/lib/concurrent/edge/promises.rb @@ -982,12 +982,12 @@ def value!(timeout = nil) # @return [Exception] def exception(*args) raise Concurrent::Error, 'it is not rejected' unless rejected? - reason = Array(internal_state.reason).compact + reason = Array(internal_state.reason).flatten.compact if reason.size > 1 Concurrent::MultipleErrors.new reason else ex = reason[0].exception(*args) - ex.set_backtrace ex.backtrace + caller + ex.set_backtrace Array(ex.backtrace) + caller ex end end diff --git a/spec/concurrent/edge/promises_spec.rb b/spec/concurrent/edge/promises_spec.rb index d543a0863..d32027f6c 100644 --- a/spec/concurrent/edge/promises_spec.rb +++ b/spec/concurrent/edge/promises_spec.rb @@ -220,9 +220,14 @@ def behaves_as_delay(delay, value) let(:a_future) { future { raise 'error' } } it 'raises a concurrent error' do - expect { zip(a_future).value! }.to raise_error(StandardError) + expect { zip(a_future).value! }.to raise_error(StandardError, 'error') end + context 'when deeply nested' do + it 'raises the original error' do + expect { zip(zip(a_future)).value! }.to raise_error(StandardError, 'error') + end + end end end @@ -242,6 +247,13 @@ def behaves_as_delay(delay, value) end end + describe '.rejected_future' do + it 'raises the correct error when passed an unraised error' do + f = rejected_future(StandardError.new('boom')) + expect { f.value! }.to raise_error(StandardError, 'boom') + end + end + describe 'Future' do it 'has sync and async callbacks' do callbacks_tester = ->(event_or_future) do