From cced0a7eb936f9bf9c688db2c0f2496bfc9833e8 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 --- CHANGELOG.md | 6 ++++++ lib/concurrent/edge/promises.rb | 4 ++-- spec/concurrent/edge/promises_spec.rb | 14 +++++++++++++- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d60334809..814750dba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## Current + +concurrent-ruby-edge: + +* (#659) Edge promises fail during error handling + ## Release v1.0.5, edge v0.3.1 (26 Feb 2017) concurrent-ruby: 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