concurrent-ruby 0.5.0 → 0.6.0.pre.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +88 -77
- data/lib/concurrent.rb +17 -2
- data/lib/concurrent/actor.rb +17 -0
- data/lib/concurrent/actor_context.rb +31 -0
- data/lib/concurrent/actor_ref.rb +39 -0
- data/lib/concurrent/agent.rb +12 -3
- data/lib/concurrent/async.rb +290 -0
- data/lib/concurrent/atomic.rb +5 -9
- data/lib/concurrent/cached_thread_pool.rb +39 -137
- data/lib/concurrent/channel/blocking_ring_buffer.rb +60 -0
- data/lib/concurrent/channel/buffered_channel.rb +83 -0
- data/lib/concurrent/channel/channel.rb +11 -0
- data/lib/concurrent/channel/probe.rb +19 -0
- data/lib/concurrent/channel/ring_buffer.rb +54 -0
- data/lib/concurrent/channel/unbuffered_channel.rb +34 -0
- data/lib/concurrent/channel/waitable_list.rb +38 -0
- data/lib/concurrent/configuration.rb +92 -0
- data/lib/concurrent/dataflow.rb +9 -3
- data/lib/concurrent/delay.rb +88 -0
- data/lib/concurrent/exchanger.rb +31 -0
- data/lib/concurrent/fixed_thread_pool.rb +28 -122
- data/lib/concurrent/future.rb +10 -5
- data/lib/concurrent/immediate_executor.rb +3 -2
- data/lib/concurrent/ivar.rb +2 -1
- data/lib/concurrent/java_cached_thread_pool.rb +45 -0
- data/lib/concurrent/java_fixed_thread_pool.rb +37 -0
- data/lib/concurrent/java_thread_pool_executor.rb +194 -0
- data/lib/concurrent/per_thread_executor.rb +23 -0
- data/lib/concurrent/postable.rb +2 -0
- data/lib/concurrent/processor_count.rb +125 -0
- data/lib/concurrent/promise.rb +42 -18
- data/lib/concurrent/ruby_cached_thread_pool.rb +37 -0
- data/lib/concurrent/ruby_fixed_thread_pool.rb +31 -0
- data/lib/concurrent/ruby_thread_pool_executor.rb +268 -0
- data/lib/concurrent/ruby_thread_pool_worker.rb +69 -0
- data/lib/concurrent/simple_actor_ref.rb +124 -0
- data/lib/concurrent/thread_local_var.rb +1 -1
- data/lib/concurrent/thread_pool_executor.rb +30 -0
- data/lib/concurrent/timer_task.rb +13 -10
- data/lib/concurrent/tvar.rb +212 -0
- data/lib/concurrent/utilities.rb +1 -0
- data/lib/concurrent/version.rb +1 -1
- data/spec/concurrent/actor_context_spec.rb +37 -0
- data/spec/concurrent/actor_ref_shared.rb +313 -0
- data/spec/concurrent/actor_spec.rb +9 -1
- data/spec/concurrent/agent_spec.rb +97 -96
- data/spec/concurrent/async_spec.rb +320 -0
- data/spec/concurrent/cached_thread_pool_shared.rb +137 -0
- data/spec/concurrent/channel/blocking_ring_buffer_spec.rb +149 -0
- data/spec/concurrent/channel/buffered_channel_spec.rb +151 -0
- data/spec/concurrent/channel/channel_spec.rb +37 -0
- data/spec/concurrent/channel/probe_spec.rb +49 -0
- data/spec/concurrent/channel/ring_buffer_spec.rb +126 -0
- data/spec/concurrent/channel/unbuffered_channel_spec.rb +132 -0
- data/spec/concurrent/configuration_spec.rb +134 -0
- data/spec/concurrent/dataflow_spec.rb +109 -27
- data/spec/concurrent/delay_spec.rb +77 -0
- data/spec/concurrent/exchanger_spec.rb +66 -0
- data/spec/concurrent/fixed_thread_pool_shared.rb +136 -0
- data/spec/concurrent/future_spec.rb +60 -51
- data/spec/concurrent/global_thread_pool_shared.rb +33 -0
- data/spec/concurrent/immediate_executor_spec.rb +4 -25
- data/spec/concurrent/ivar_spec.rb +36 -23
- data/spec/concurrent/java_cached_thread_pool_spec.rb +64 -0
- data/spec/concurrent/java_fixed_thread_pool_spec.rb +64 -0
- data/spec/concurrent/java_thread_pool_executor_spec.rb +71 -0
- data/spec/concurrent/obligation_shared.rb +32 -20
- data/spec/concurrent/{global_thread_pool_spec.rb → per_thread_executor_spec.rb} +9 -13
- data/spec/concurrent/processor_count_spec.rb +20 -0
- data/spec/concurrent/promise_spec.rb +29 -41
- data/spec/concurrent/ruby_cached_thread_pool_spec.rb +69 -0
- data/spec/concurrent/ruby_fixed_thread_pool_spec.rb +39 -0
- data/spec/concurrent/ruby_thread_pool_executor_spec.rb +183 -0
- data/spec/concurrent/simple_actor_ref_spec.rb +219 -0
- data/spec/concurrent/thread_pool_class_cast_spec.rb +40 -0
- data/spec/concurrent/thread_pool_executor_shared.rb +155 -0
- data/spec/concurrent/thread_pool_shared.rb +98 -36
- data/spec/concurrent/tvar_spec.rb +137 -0
- data/spec/spec_helper.rb +4 -0
- data/spec/support/functions.rb +4 -0
- metadata +85 -20
- data/lib/concurrent/cached_thread_pool/worker.rb +0 -91
- data/lib/concurrent/channel.rb +0 -63
- data/lib/concurrent/fixed_thread_pool/worker.rb +0 -54
- data/lib/concurrent/global_thread_pool.rb +0 -42
- data/spec/concurrent/cached_thread_pool_spec.rb +0 -101
- data/spec/concurrent/channel_spec.rb +0 -86
- data/spec/concurrent/fixed_thread_pool_spec.rb +0 -92
- data/spec/concurrent/uses_global_thread_pool_shared.rb +0 -64
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require_relative 'dereferenceable_shared'
|
3
|
+
require_relative 'obligation_shared'
|
4
|
+
|
5
|
+
module Concurrent
|
6
|
+
|
7
|
+
describe Delay do
|
8
|
+
|
9
|
+
context 'behavior' do
|
10
|
+
|
11
|
+
# dereferenceable
|
12
|
+
|
13
|
+
def dereferenceable_subject(value, opts = {})
|
14
|
+
delay = Delay.new(opts){ value }
|
15
|
+
delay.tap{ delay.value }
|
16
|
+
end
|
17
|
+
|
18
|
+
it_should_behave_like :dereferenceable
|
19
|
+
|
20
|
+
# obligation
|
21
|
+
|
22
|
+
let!(:fulfilled_value) { 10 }
|
23
|
+
let!(:rejected_reason) { StandardError.new('mojo jojo') }
|
24
|
+
|
25
|
+
let(:pending_subject) do
|
26
|
+
Delay.new{ fulfilled_value }
|
27
|
+
end
|
28
|
+
|
29
|
+
let(:fulfilled_subject) do
|
30
|
+
delay = Delay.new{ fulfilled_value }
|
31
|
+
delay.tap{ delay.value }
|
32
|
+
end
|
33
|
+
|
34
|
+
let(:rejected_subject) do
|
35
|
+
delay = Delay.new{ raise rejected_reason }
|
36
|
+
delay.tap{ delay.value }
|
37
|
+
end
|
38
|
+
|
39
|
+
it_should_behave_like :obligation
|
40
|
+
end
|
41
|
+
|
42
|
+
context '#initialize' do
|
43
|
+
|
44
|
+
it 'sets the state to :pending' do
|
45
|
+
Delay.new{ nil }.state.should eq :pending
|
46
|
+
Delay.new{ nil }.should be_pending
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'raises an exception when no block given' do
|
50
|
+
expect {
|
51
|
+
Delay.new
|
52
|
+
}.to raise_error(ArgumentError)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
context '#value' do
|
57
|
+
|
58
|
+
let(:task){ proc{ nil } }
|
59
|
+
|
60
|
+
it 'does not call the block before #value is called' do
|
61
|
+
task.should_not_receive(:call).with(any_args)
|
62
|
+
Delay.new(&task)
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'calls the block when #value is called' do
|
66
|
+
task.should_receive(:call).once.with(any_args).and_return(nil)
|
67
|
+
Delay.new(&task).value
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'only calls the block once no matter how often #value is called' do
|
71
|
+
task.should_receive(:call).once.with(any_args).and_return(nil)
|
72
|
+
delay = Delay.new(&task)
|
73
|
+
5.times{ delay.value }
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Concurrent
|
4
|
+
|
5
|
+
describe Exchanger do
|
6
|
+
|
7
|
+
subject { Exchanger.new }
|
8
|
+
let!(:exchanger) { subject } # let is not thread safe, let! creates the object before ensuring uniqueness
|
9
|
+
|
10
|
+
describe 'exchange' do
|
11
|
+
context 'without timeout' do
|
12
|
+
it 'should block' do
|
13
|
+
t = Thread.new { exchanger.exchange(1) }
|
14
|
+
sleep(0.1)
|
15
|
+
t.status.should eq 'sleep'
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'should receive the other value' do
|
19
|
+
first_value = nil
|
20
|
+
second_value = nil
|
21
|
+
|
22
|
+
Thread.new { first_value = exchanger.exchange(2) }
|
23
|
+
Thread.new { second_value = exchanger.exchange(4) }
|
24
|
+
|
25
|
+
sleep(0.1)
|
26
|
+
|
27
|
+
first_value.should eq 4
|
28
|
+
second_value.should eq 2
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'can be reused' do
|
32
|
+
first_value = nil
|
33
|
+
second_value = nil
|
34
|
+
|
35
|
+
Thread.new { first_value = exchanger.exchange(1) }
|
36
|
+
Thread.new { second_value = exchanger.exchange(0) }
|
37
|
+
|
38
|
+
sleep(0.1)
|
39
|
+
|
40
|
+
Thread.new { first_value = exchanger.exchange(10) }
|
41
|
+
Thread.new { second_value = exchanger.exchange(12) }
|
42
|
+
|
43
|
+
sleep(0.1)
|
44
|
+
|
45
|
+
first_value.should eq 12
|
46
|
+
second_value.should eq 10
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
context 'with timeout' do
|
51
|
+
it 'should block until timeout' do
|
52
|
+
value = 0
|
53
|
+
|
54
|
+
t = Thread.new { value = exchanger.exchange(2, 0.2) }
|
55
|
+
|
56
|
+
sleep(0.1)
|
57
|
+
t.status.should eq 'sleep'
|
58
|
+
|
59
|
+
sleep(0.2)
|
60
|
+
|
61
|
+
value.should be_nil
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,136 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require_relative 'thread_pool_shared'
|
3
|
+
|
4
|
+
share_examples_for :fixed_thread_pool do
|
5
|
+
|
6
|
+
let!(:num_threads){ 5 }
|
7
|
+
subject { described_class.new(num_threads) }
|
8
|
+
|
9
|
+
after(:each) do
|
10
|
+
subject.kill
|
11
|
+
sleep(0.1)
|
12
|
+
end
|
13
|
+
|
14
|
+
it_should_behave_like :thread_pool
|
15
|
+
|
16
|
+
context '#initialize' do
|
17
|
+
|
18
|
+
it 'raises an exception when the pool length is less than one' do
|
19
|
+
lambda {
|
20
|
+
described_class.new(0)
|
21
|
+
}.should raise_error(ArgumentError)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
context '#min_length' do
|
26
|
+
|
27
|
+
it 'returns :num_threads on creation' do
|
28
|
+
subject.min_length.should eq num_threads
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'returns :num_threads while running' do
|
32
|
+
10.times{ subject.post{ nil } }
|
33
|
+
sleep(0.1)
|
34
|
+
subject.min_length.should eq num_threads
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'returns :num_threads once shutdown' do
|
38
|
+
10.times{ subject.post{ nil } }
|
39
|
+
sleep(0.1)
|
40
|
+
subject.shutdown
|
41
|
+
subject.wait_for_termination(1)
|
42
|
+
subject.min_length.should eq num_threads
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
context '#max_length' do
|
47
|
+
|
48
|
+
it 'returns :num_threads on creation' do
|
49
|
+
subject.max_length.should eq num_threads
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'returns :num_threads while running' do
|
53
|
+
10.times{ subject.post{ nil } }
|
54
|
+
sleep(0.1)
|
55
|
+
subject.max_length.should eq num_threads
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'returns :num_threads once shutdown' do
|
59
|
+
10.times{ subject.post{ nil } }
|
60
|
+
sleep(0.1)
|
61
|
+
subject.shutdown
|
62
|
+
subject.wait_for_termination(1)
|
63
|
+
subject.max_length.should eq num_threads
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
context '#length' do
|
68
|
+
|
69
|
+
it 'returns :num_threads while running' do
|
70
|
+
10.times{ subject.post{ nil } }
|
71
|
+
sleep(0.1)
|
72
|
+
subject.length.should eq num_threads
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
context '#largest_length' do
|
77
|
+
|
78
|
+
it 'returns zero on creation' do
|
79
|
+
subject.largest_length.should eq 0
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'returns :num_threads while running' do
|
83
|
+
10.times{ subject.post{ nil } }
|
84
|
+
sleep(0.1)
|
85
|
+
subject.largest_length.should eq num_threads
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'returns :num_threads once shutdown' do
|
89
|
+
10.times{ subject.post{ nil } }
|
90
|
+
sleep(0.1)
|
91
|
+
subject.shutdown
|
92
|
+
subject.wait_for_termination(1)
|
93
|
+
subject.largest_length.should eq num_threads
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
context '#status' do
|
98
|
+
|
99
|
+
it 'returns an array' do
|
100
|
+
subject.stub(:warn)
|
101
|
+
subject.status.should be_kind_of(Array)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
context '#idletime' do
|
106
|
+
|
107
|
+
it 'returns zero' do
|
108
|
+
subject.idletime.should eq 0
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
context '#kill' do
|
113
|
+
|
114
|
+
it 'attempts to kill all in-progress tasks' do
|
115
|
+
thread_count = [subject.length, 5].max
|
116
|
+
@expected = false
|
117
|
+
thread_count.times{ subject.post{ sleep(1) } }
|
118
|
+
subject.post{ @expected = true }
|
119
|
+
sleep(0.1)
|
120
|
+
subject.kill
|
121
|
+
sleep(0.1)
|
122
|
+
@expected.should be_false
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
context 'worker creation and caching' do
|
127
|
+
|
128
|
+
it 'never creates more than :num_threads threads' do
|
129
|
+
pool = described_class.new(5)
|
130
|
+
100.times{ pool << proc{ sleep(1) } }
|
131
|
+
sleep(0.1)
|
132
|
+
pool.current_length.should eq 5
|
133
|
+
pool.kill
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
@@ -1,41 +1,37 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
require_relative 'dereferenceable_shared'
|
3
3
|
require_relative 'obligation_shared'
|
4
|
-
require_relative 'uses_global_thread_pool_shared'
|
5
4
|
|
6
5
|
module Concurrent
|
7
6
|
|
8
7
|
describe Future do
|
9
8
|
|
10
9
|
let!(:value) { 10 }
|
11
|
-
|
10
|
+
let(:executor) { PerThreadExecutor.new }
|
12
11
|
|
13
|
-
|
14
|
-
Future.
|
12
|
+
subject do
|
13
|
+
Future.new(executor: executor){
|
14
|
+
value
|
15
|
+
}.execute.tap{ sleep(0.1) }
|
15
16
|
end
|
16
17
|
|
17
18
|
context 'behavior' do
|
18
19
|
|
19
|
-
# uses_global_thread_pool
|
20
|
-
|
21
|
-
let!(:thread_pool_user){ Future }
|
22
|
-
it_should_behave_like Concurrent::UsesGlobalThreadPool
|
23
|
-
|
24
20
|
# obligation
|
25
21
|
|
26
22
|
let!(:fulfilled_value) { 10 }
|
27
23
|
let!(:rejected_reason) { StandardError.new('mojo jojo') }
|
28
24
|
|
29
25
|
let(:pending_subject) do
|
30
|
-
Future.new{ sleep(3); fulfilled_value }.execute
|
26
|
+
Future.new(executor: executor){ sleep(3); fulfilled_value }.execute
|
31
27
|
end
|
32
28
|
|
33
29
|
let(:fulfilled_subject) do
|
34
|
-
Future.new{ fulfilled_value }.execute.tap{ sleep(0.1) }
|
30
|
+
Future.new(executor: executor){ fulfilled_value }.execute.tap{ sleep(0.1) }
|
35
31
|
end
|
36
32
|
|
37
33
|
let(:rejected_subject) do
|
38
|
-
Future.new{ raise rejected_reason }.execute.tap{ sleep(0.1) }
|
34
|
+
Future.new(executor: executor){ raise rejected_reason }.execute.tap{ sleep(0.1) }
|
39
35
|
end
|
40
36
|
|
41
37
|
it_should_behave_like :obligation
|
@@ -43,10 +39,12 @@ module Concurrent
|
|
43
39
|
# dereferenceable
|
44
40
|
|
45
41
|
def dereferenceable_subject(value, opts = {})
|
42
|
+
opts = opts.merge(executor: executor)
|
46
43
|
Future.new(opts){ value }.execute.tap{ sleep(0.1) }
|
47
44
|
end
|
48
45
|
|
49
46
|
def dereferenceable_observable(opts = {})
|
47
|
+
opts = opts.merge(executor: executor)
|
50
48
|
Future.new(opts){ 'value' }
|
51
49
|
end
|
52
50
|
|
@@ -59,8 +57,8 @@ module Concurrent
|
|
59
57
|
end
|
60
58
|
|
61
59
|
context 'subclassing' do
|
62
|
-
|
63
|
-
subject{ Future.execute{ 42 } }
|
60
|
+
|
61
|
+
subject{ Future.execute(executor: executor){ 42 } }
|
64
62
|
|
65
63
|
it 'protects #set' do
|
66
64
|
expect{ subject.set(100) }.to raise_error
|
@@ -77,14 +75,10 @@ module Concurrent
|
|
77
75
|
|
78
76
|
context '#initialize' do
|
79
77
|
|
80
|
-
|
81
|
-
Future.new{ nil }.should be_unscheduled
|
82
|
-
end
|
78
|
+
let(:executor) { ImmediateExecutor.new }
|
83
79
|
|
84
|
-
it '
|
85
|
-
Future.
|
86
|
-
Thread.should_not_receive(:new).with(any_args)
|
87
|
-
Future.new{ nil }
|
80
|
+
it 'sets the state to :unscheduled' do
|
81
|
+
Future.new(executor: executor){ nil }.should be_unscheduled
|
88
82
|
end
|
89
83
|
|
90
84
|
it 'raises an exception when no block given' do
|
@@ -92,13 +86,34 @@ module Concurrent
|
|
92
86
|
Future.new.execute
|
93
87
|
}.to raise_error(ArgumentError)
|
94
88
|
end
|
89
|
+
|
90
|
+
it 'uses the executor given with the :executor option' do
|
91
|
+
executor.should_receive(:post)
|
92
|
+
Future.execute(executor: executor){ nil }
|
93
|
+
end
|
94
|
+
|
95
|
+
it 'uses the global operation pool when :operation is true' do
|
96
|
+
Concurrent.configuration.should_receive(:global_operation_pool).and_return(executor)
|
97
|
+
Future.execute(operation: true){ nil }
|
98
|
+
end
|
99
|
+
|
100
|
+
it 'uses the global task pool when :task is true' do
|
101
|
+
Concurrent.configuration.should_receive(:global_task_pool).and_return(executor)
|
102
|
+
Future.execute(task: true){ nil }
|
103
|
+
end
|
104
|
+
|
105
|
+
it 'uses the global task pool by default' do
|
106
|
+
Concurrent.configuration.should_receive(:global_task_pool).and_return(executor)
|
107
|
+
Future.execute{ nil }
|
108
|
+
end
|
95
109
|
end
|
96
110
|
|
97
111
|
context 'instance #execute' do
|
98
112
|
|
99
113
|
it 'does nothing unless the state is :unscheduled' do
|
100
|
-
|
101
|
-
|
114
|
+
executor = ImmediateExecutor.new
|
115
|
+
executor.should_not_receive(:post).with(any_args)
|
116
|
+
future = Future.new(executor: executor){ nil }
|
102
117
|
future.instance_variable_set(:@state, :pending)
|
103
118
|
future.execute
|
104
119
|
future.instance_variable_set(:@state, :rejected)
|
@@ -108,37 +123,35 @@ module Concurrent
|
|
108
123
|
end
|
109
124
|
|
110
125
|
it 'posts the block given on construction' do
|
111
|
-
|
112
|
-
future = Future.new { nil }
|
126
|
+
executor.should_receive(:post).with(any_args)
|
127
|
+
future = Future.new(executor: executor){ nil }
|
113
128
|
future.execute
|
114
129
|
end
|
115
130
|
|
116
131
|
it 'sets the state to :pending' do
|
117
|
-
future = Future.new { sleep(0.1) }
|
132
|
+
future = Future.new(executor: executor){ sleep(0.1) }
|
118
133
|
future.execute
|
119
134
|
future.should be_pending
|
120
135
|
end
|
121
136
|
|
122
137
|
it 'returns self' do
|
123
|
-
future = Future.new { nil }
|
138
|
+
future = Future.new(executor: executor){ nil }
|
124
139
|
future.execute.should be future
|
125
140
|
end
|
126
141
|
end
|
127
142
|
|
128
143
|
context 'class #execute' do
|
129
144
|
|
130
|
-
|
131
|
-
Future.thread_pool = ImmediateExecutor.new
|
132
|
-
end
|
145
|
+
let(:executor) { ImmediateExecutor.new }
|
133
146
|
|
134
147
|
it 'creates a new Future' do
|
135
|
-
future = Future.execute{ nil }
|
148
|
+
future = Future.execute(executor: executor){ nil }
|
136
149
|
future.should be_a(Future)
|
137
150
|
end
|
138
151
|
|
139
152
|
it 'passes the block to the new Future' do
|
140
153
|
@expected = false
|
141
|
-
Future.execute { @expected = true }
|
154
|
+
Future.execute(executor: executor){ @expected = true }
|
142
155
|
@expected.should be_true
|
143
156
|
end
|
144
157
|
|
@@ -152,33 +165,31 @@ module Concurrent
|
|
152
165
|
|
153
166
|
context 'fulfillment' do
|
154
167
|
|
155
|
-
|
156
|
-
Future.thread_pool = ImmediateExecutor.new
|
157
|
-
end
|
168
|
+
let(:executor) { ImmediateExecutor.new }
|
158
169
|
|
159
170
|
it 'passes all arguments to handler' do
|
160
171
|
@expected = false
|
161
|
-
Future.new{ @expected = true }.execute
|
172
|
+
Future.new(executor: executor){ @expected = true }.execute
|
162
173
|
@expected.should be_true
|
163
174
|
end
|
164
175
|
|
165
176
|
it 'sets the value to the result of the handler' do
|
166
|
-
future = Future.new{ 42 }.execute
|
177
|
+
future = Future.new(executor: executor){ 42 }.execute
|
167
178
|
future.value.should eq 42
|
168
179
|
end
|
169
180
|
|
170
181
|
it 'sets the state to :fulfilled when the block completes' do
|
171
|
-
future = Future.new{ 42 }.execute
|
182
|
+
future = Future.new(executor: executor){ 42 }.execute
|
172
183
|
future.should be_fulfilled
|
173
184
|
end
|
174
185
|
|
175
186
|
it 'sets the value to nil when the handler raises an exception' do
|
176
|
-
future = Future.new{ raise StandardError }.execute
|
187
|
+
future = Future.new(executor: executor){ raise StandardError }.execute
|
177
188
|
future.value.should be_nil
|
178
189
|
end
|
179
190
|
|
180
191
|
it 'sets the state to :rejected when the handler raises an exception' do
|
181
|
-
future = Future.new{ raise StandardError }.execute
|
192
|
+
future = Future.new(executor: executor){ raise StandardError }.execute
|
182
193
|
future.should be_rejected
|
183
194
|
end
|
184
195
|
|
@@ -196,9 +207,7 @@ module Concurrent
|
|
196
207
|
|
197
208
|
context 'observation' do
|
198
209
|
|
199
|
-
|
200
|
-
Future.thread_pool = ImmediateExecutor.new
|
201
|
-
end
|
210
|
+
let(:executor) { ImmediateExecutor.new }
|
202
211
|
|
203
212
|
let(:clazz) do
|
204
213
|
Class.new do
|
@@ -216,7 +225,7 @@ module Concurrent
|
|
216
225
|
let(:observer) { clazz.new }
|
217
226
|
|
218
227
|
it 'notifies all observers on fulfillment' do
|
219
|
-
future = Future.new{ 42 }
|
228
|
+
future = Future.new(executor: executor){ 42 }
|
220
229
|
future.add_observer(observer)
|
221
230
|
|
222
231
|
future.execute
|
@@ -226,7 +235,7 @@ module Concurrent
|
|
226
235
|
end
|
227
236
|
|
228
237
|
it 'notifies all observers on rejection' do
|
229
|
-
future = Future.new{ raise StandardError }
|
238
|
+
future = Future.new(executor: executor){ raise StandardError }
|
230
239
|
future.add_observer(observer)
|
231
240
|
|
232
241
|
future.execute
|
@@ -236,19 +245,19 @@ module Concurrent
|
|
236
245
|
end
|
237
246
|
|
238
247
|
it 'notifies an observer added after fulfillment' do
|
239
|
-
future = Future.new{ 42 }.execute
|
248
|
+
future = Future.new(executor: executor){ 42 }.execute
|
240
249
|
future.add_observer(observer)
|
241
250
|
observer.value.should == 42
|
242
251
|
end
|
243
252
|
|
244
253
|
it 'notifies an observer added after rejection' do
|
245
|
-
future = Future.new{ raise StandardError }.execute
|
254
|
+
future = Future.new(executor: executor){ raise StandardError }.execute
|
246
255
|
future.add_observer(observer)
|
247
256
|
observer.reason.should be_a(StandardError)
|
248
257
|
end
|
249
258
|
|
250
259
|
it 'does not notify existing observers when a new observer added after fulfillment' do
|
251
|
-
future = Future.new{ 42 }.execute
|
260
|
+
future = Future.new(executor: executor){ 42 }.execute
|
252
261
|
future.add_observer(observer)
|
253
262
|
|
254
263
|
observer.count.should == 1
|
@@ -261,7 +270,7 @@ module Concurrent
|
|
261
270
|
end
|
262
271
|
|
263
272
|
it 'does not notify existing observers when a new observer added after rejection' do
|
264
|
-
future = Future.new{ raise StandardError }.execute
|
273
|
+
future = Future.new(executor: executor){ raise StandardError }.execute
|
265
274
|
future.add_observer(observer)
|
266
275
|
|
267
276
|
observer.count.should == 1
|
@@ -285,7 +294,7 @@ module Concurrent
|
|
285
294
|
end
|
286
295
|
|
287
296
|
it 'should notify observers outside mutex lock' do
|
288
|
-
future = Future.new{ 42 }
|
297
|
+
future = Future.new(executor: executor){ 42 }
|
289
298
|
obs = reentrant_observer(future)
|
290
299
|
|
291
300
|
future.add_observer(obs)
|
@@ -295,7 +304,7 @@ module Concurrent
|
|
295
304
|
end
|
296
305
|
|
297
306
|
it 'should notify a new observer added after fulfillment outside lock' do
|
298
|
-
future = Future.new{ 42 }.execute
|
307
|
+
future = Future.new(executor: executor){ 42 }.execute
|
299
308
|
obs = reentrant_observer(future)
|
300
309
|
|
301
310
|
future.add_observer(obs)
|