concurrent-ruby 0.5.0 → 0.6.0.pre.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +88 -77
  3. data/lib/concurrent.rb +17 -2
  4. data/lib/concurrent/actor.rb +17 -0
  5. data/lib/concurrent/actor_context.rb +31 -0
  6. data/lib/concurrent/actor_ref.rb +39 -0
  7. data/lib/concurrent/agent.rb +12 -3
  8. data/lib/concurrent/async.rb +290 -0
  9. data/lib/concurrent/atomic.rb +5 -9
  10. data/lib/concurrent/cached_thread_pool.rb +39 -137
  11. data/lib/concurrent/channel/blocking_ring_buffer.rb +60 -0
  12. data/lib/concurrent/channel/buffered_channel.rb +83 -0
  13. data/lib/concurrent/channel/channel.rb +11 -0
  14. data/lib/concurrent/channel/probe.rb +19 -0
  15. data/lib/concurrent/channel/ring_buffer.rb +54 -0
  16. data/lib/concurrent/channel/unbuffered_channel.rb +34 -0
  17. data/lib/concurrent/channel/waitable_list.rb +38 -0
  18. data/lib/concurrent/configuration.rb +92 -0
  19. data/lib/concurrent/dataflow.rb +9 -3
  20. data/lib/concurrent/delay.rb +88 -0
  21. data/lib/concurrent/exchanger.rb +31 -0
  22. data/lib/concurrent/fixed_thread_pool.rb +28 -122
  23. data/lib/concurrent/future.rb +10 -5
  24. data/lib/concurrent/immediate_executor.rb +3 -2
  25. data/lib/concurrent/ivar.rb +2 -1
  26. data/lib/concurrent/java_cached_thread_pool.rb +45 -0
  27. data/lib/concurrent/java_fixed_thread_pool.rb +37 -0
  28. data/lib/concurrent/java_thread_pool_executor.rb +194 -0
  29. data/lib/concurrent/per_thread_executor.rb +23 -0
  30. data/lib/concurrent/postable.rb +2 -0
  31. data/lib/concurrent/processor_count.rb +125 -0
  32. data/lib/concurrent/promise.rb +42 -18
  33. data/lib/concurrent/ruby_cached_thread_pool.rb +37 -0
  34. data/lib/concurrent/ruby_fixed_thread_pool.rb +31 -0
  35. data/lib/concurrent/ruby_thread_pool_executor.rb +268 -0
  36. data/lib/concurrent/ruby_thread_pool_worker.rb +69 -0
  37. data/lib/concurrent/simple_actor_ref.rb +124 -0
  38. data/lib/concurrent/thread_local_var.rb +1 -1
  39. data/lib/concurrent/thread_pool_executor.rb +30 -0
  40. data/lib/concurrent/timer_task.rb +13 -10
  41. data/lib/concurrent/tvar.rb +212 -0
  42. data/lib/concurrent/utilities.rb +1 -0
  43. data/lib/concurrent/version.rb +1 -1
  44. data/spec/concurrent/actor_context_spec.rb +37 -0
  45. data/spec/concurrent/actor_ref_shared.rb +313 -0
  46. data/spec/concurrent/actor_spec.rb +9 -1
  47. data/spec/concurrent/agent_spec.rb +97 -96
  48. data/spec/concurrent/async_spec.rb +320 -0
  49. data/spec/concurrent/cached_thread_pool_shared.rb +137 -0
  50. data/spec/concurrent/channel/blocking_ring_buffer_spec.rb +149 -0
  51. data/spec/concurrent/channel/buffered_channel_spec.rb +151 -0
  52. data/spec/concurrent/channel/channel_spec.rb +37 -0
  53. data/spec/concurrent/channel/probe_spec.rb +49 -0
  54. data/spec/concurrent/channel/ring_buffer_spec.rb +126 -0
  55. data/spec/concurrent/channel/unbuffered_channel_spec.rb +132 -0
  56. data/spec/concurrent/configuration_spec.rb +134 -0
  57. data/spec/concurrent/dataflow_spec.rb +109 -27
  58. data/spec/concurrent/delay_spec.rb +77 -0
  59. data/spec/concurrent/exchanger_spec.rb +66 -0
  60. data/spec/concurrent/fixed_thread_pool_shared.rb +136 -0
  61. data/spec/concurrent/future_spec.rb +60 -51
  62. data/spec/concurrent/global_thread_pool_shared.rb +33 -0
  63. data/spec/concurrent/immediate_executor_spec.rb +4 -25
  64. data/spec/concurrent/ivar_spec.rb +36 -23
  65. data/spec/concurrent/java_cached_thread_pool_spec.rb +64 -0
  66. data/spec/concurrent/java_fixed_thread_pool_spec.rb +64 -0
  67. data/spec/concurrent/java_thread_pool_executor_spec.rb +71 -0
  68. data/spec/concurrent/obligation_shared.rb +32 -20
  69. data/spec/concurrent/{global_thread_pool_spec.rb → per_thread_executor_spec.rb} +9 -13
  70. data/spec/concurrent/processor_count_spec.rb +20 -0
  71. data/spec/concurrent/promise_spec.rb +29 -41
  72. data/spec/concurrent/ruby_cached_thread_pool_spec.rb +69 -0
  73. data/spec/concurrent/ruby_fixed_thread_pool_spec.rb +39 -0
  74. data/spec/concurrent/ruby_thread_pool_executor_spec.rb +183 -0
  75. data/spec/concurrent/simple_actor_ref_spec.rb +219 -0
  76. data/spec/concurrent/thread_pool_class_cast_spec.rb +40 -0
  77. data/spec/concurrent/thread_pool_executor_shared.rb +155 -0
  78. data/spec/concurrent/thread_pool_shared.rb +98 -36
  79. data/spec/concurrent/tvar_spec.rb +137 -0
  80. data/spec/spec_helper.rb +4 -0
  81. data/spec/support/functions.rb +4 -0
  82. metadata +85 -20
  83. data/lib/concurrent/cached_thread_pool/worker.rb +0 -91
  84. data/lib/concurrent/channel.rb +0 -63
  85. data/lib/concurrent/fixed_thread_pool/worker.rb +0 -54
  86. data/lib/concurrent/global_thread_pool.rb +0 -42
  87. data/spec/concurrent/cached_thread_pool_spec.rb +0 -101
  88. data/spec/concurrent/channel_spec.rb +0 -86
  89. data/spec/concurrent/fixed_thread_pool_spec.rb +0 -92
  90. data/spec/concurrent/uses_global_thread_pool_shared.rb +0 -64
@@ -0,0 +1,219 @@
1
+ require 'spec_helper'
2
+ require_relative 'actor_ref_shared'
3
+
4
+ module Concurrent
5
+
6
+ describe SimpleActorRef do
7
+
8
+ after(:each) do
9
+ subject.shutdown
10
+ sleep(0.1)
11
+ end
12
+
13
+ subject do
14
+ shared_actor_test_class.spawn
15
+ end
16
+
17
+ it_should_behave_like :actor_ref
18
+
19
+ context 'construction' do
20
+
21
+ it 'supports :args being nil' do
22
+ subject = shared_actor_test_class.spawn
23
+ actor = subject.instance_variable_get(:@actor)
24
+ actor.argv.should be_empty
25
+ end
26
+
27
+ it 'passes all :args option to the actor constructor' do
28
+ subject = shared_actor_test_class.spawn(args: [1, 2, 3, 4])
29
+ actor = subject.instance_variable_get(:@actor)
30
+ actor.argv.should eq [1, 2, 3, 4]
31
+ end
32
+
33
+ it 'passes the options hash to the ActorRef constructor' do
34
+ subject # prevent the after(:all) block from breaking this test
35
+ opts = {foo: :bar, hello: :world}
36
+ described_class.should_receive(:new).once.with(anything, opts)
37
+ shared_actor_test_class.spawn(opts)
38
+ end
39
+ end
40
+
41
+ context 'supervision' do
42
+
43
+ it 'does not start a new thread on construction' do
44
+ Thread.should_not_receive(:new).with(any_args)
45
+ subject = shared_actor_test_class.spawn
46
+ end
47
+
48
+ it 'starts a new thread on the first post' do
49
+ thread = Thread.new{ nil }
50
+ Thread.should_receive(:new).once.with(no_args).and_return(thread)
51
+ subject << :foo
52
+ end
53
+
54
+ it 'does not start a new thread after the first post' do
55
+ subject << :foo
56
+ sleep(0.1)
57
+ expected = Thread.list.length
58
+ 5.times{ subject << :foo }
59
+ Thread.list.length.should eq expected
60
+ end
61
+
62
+ it 'starts a new thread when the prior thread has died' do
63
+ subject << :foo
64
+ sleep(0.1)
65
+
66
+ subject << :terminate
67
+ sleep(0.1)
68
+
69
+ thread = Thread.new{ nil }
70
+ Thread.should_receive(:new).once.with(no_args).and_return(thread)
71
+ subject << :foo
72
+ end
73
+
74
+ it 'does not reset the thread after shutdown' do
75
+ thread = Thread.new{ nil }
76
+ Thread.should_receive(:new).once.with(no_args).and_return(thread)
77
+ subject << :foo
78
+ sleep(0.1)
79
+
80
+ subject.shutdown
81
+ sleep(0.1)
82
+
83
+ subject << :foo
84
+ end
85
+
86
+ it 'calls #on_start when the thread is first started' do
87
+ actor = subject.instance_variable_get(:@actor)
88
+ actor.should_receive(:on_start).once.with(no_args)
89
+ subject << :foo
90
+ end
91
+
92
+ it 'calls #on_reset when the thread is started after the first time' do
93
+ actor = subject.instance_variable_get(:@actor)
94
+ actor.should_receive(:on_reset).once.with(no_args)
95
+ subject << :terminate
96
+ sleep(0.1)
97
+ subject << :foo
98
+ end
99
+ end
100
+
101
+ context 'abort_on_exception' do
102
+
103
+ after(:each) do
104
+ @ref.shutdown if @ref
105
+ end
106
+
107
+ it 'gets set on the actor thread' do
108
+ @ref = shared_actor_test_class.spawn(abort_on_exception: true)
109
+ @ref << :foo
110
+ sleep(0.1)
111
+ @ref.instance_variable_get(:@thread).abort_on_exception.should be_true
112
+
113
+ @ref = shared_actor_test_class.spawn(abort_on_exception: false)
114
+ @ref << :foo
115
+ sleep(0.1)
116
+ @ref.instance_variable_get(:@thread).abort_on_exception.should be_false
117
+ end
118
+
119
+ it 'defaults to true' do
120
+ @ref = shared_actor_test_class.spawn
121
+ @ref << :foo
122
+ sleep(0.1)
123
+ @ref.instance_variable_get(:@thread).abort_on_exception.should be_true
124
+ end
125
+ end
126
+
127
+ context 'reset_on_error' do
128
+
129
+ after(:each) do
130
+ @ref.shutdown if @ref
131
+ end
132
+
133
+ it 'causes #on_reset to be called on exception when true' do
134
+ @ref = shared_actor_test_class.spawn(reset_on_error: true)
135
+ actor = @ref.instance_variable_get(:@actor)
136
+ actor.should_receive(:on_reset).once.with(no_args)
137
+ @ref << :poison
138
+ sleep(0.1)
139
+ end
140
+
141
+ it 'prevents #on_reset form being called on exception when false' do
142
+ @ref = shared_actor_test_class.spawn(reset_on_error: false)
143
+ actor = @ref.instance_variable_get(:@actor)
144
+ actor.should_not_receive(:on_reset).with(any_args)
145
+ @ref << :poison
146
+ sleep(0.1)
147
+ end
148
+
149
+ it 'defaults to true' do
150
+ @ref = shared_actor_test_class.spawn
151
+ actor = @ref.instance_variable_get(:@actor)
152
+ actor.should_receive(:on_reset).once.with(no_args)
153
+ @ref << :poison
154
+ sleep(0.1)
155
+ end
156
+ end
157
+
158
+ context 'rescue_exception' do
159
+
160
+ after(:each) do
161
+ @ref.shutdown if @ref
162
+ end
163
+
164
+ it 'rescues Exception in the actor thread when true' do
165
+ @ref = shared_actor_test_class.spawn(
166
+ abort_on_exception: false,
167
+ rescue_exception: true
168
+ )
169
+
170
+ ivar = @ref.post(:poison)
171
+ sleep(0.1)
172
+ ivar.reason.should be_a StandardError
173
+
174
+ ivar = @ref.post(:bullet)
175
+ sleep(0.1)
176
+ ivar.reason.should be_a Exception
177
+ end
178
+
179
+ it 'rescues StandardError in the actor thread when false' do
180
+ @ref = shared_actor_test_class.spawn(
181
+ abort_on_exception: false,
182
+ rescue_exception: false
183
+ )
184
+
185
+ ivar = @ref.post(:poison)
186
+ sleep(0.1)
187
+ ivar.reason.should be_a StandardError
188
+
189
+ ivar = @ref.post(:bullet)
190
+ sleep(0.1)
191
+ ivar.reason.should be_nil
192
+ end
193
+
194
+ it 'defaults to false' do
195
+ @ref = shared_actor_test_class.spawn(abort_on_exception: false)
196
+
197
+ ivar = @ref.post(:poison)
198
+ sleep(0.1)
199
+ ivar.reason.should be_a StandardError
200
+
201
+ ivar = @ref.post(:bullet)
202
+ sleep(0.1)
203
+ ivar.reason.should be_nil
204
+ end
205
+ end
206
+
207
+ context '#shutdown' do
208
+
209
+ it 'calls #on_shutdown when shutdown' do
210
+ actor = subject.instance_variable_get(:@actor)
211
+ actor.should_receive(:on_shutdown).once.with(no_args)
212
+ subject << :foo
213
+ sleep(0.1)
214
+
215
+ subject.shutdown
216
+ end
217
+ end
218
+ end
219
+ end
@@ -0,0 +1,40 @@
1
+ require 'spec_helper'
2
+
3
+ module Concurrent
4
+
5
+ describe ThreadPoolExecutor do
6
+ if jruby?
7
+ it 'inherits from JavaThreadPoolExecutor' do
8
+ ThreadPoolExecutor.ancestors.should include(JavaThreadPoolExecutor)
9
+ end
10
+ else
11
+ it 'inherits from RubyThreadPoolExecutor' do
12
+ ThreadPoolExecutor.ancestors.should include(RubyThreadPoolExecutor)
13
+ end
14
+ end
15
+ end
16
+
17
+ describe CachedThreadPool do
18
+ if jruby?
19
+ it 'inherits from JavaCachedThreadPool' do
20
+ CachedThreadPool.ancestors.should include(JavaCachedThreadPool)
21
+ end
22
+ else
23
+ it 'inherits from RubyCachedThreadPool' do
24
+ CachedThreadPool.ancestors.should include(RubyCachedThreadPool)
25
+ end
26
+ end
27
+ end
28
+
29
+ describe FixedThreadPool do
30
+ if jruby?
31
+ it 'inherits from JavaFixedThreadPool' do
32
+ FixedThreadPool.ancestors.should include(JavaFixedThreadPool)
33
+ end
34
+ else
35
+ it 'inherits from RubyFixedThreadPool' do
36
+ FixedThreadPool.ancestors.should include(RubyFixedThreadPool)
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,155 @@
1
+ require 'spec_helper'
2
+ require_relative 'thread_pool_shared'
3
+
4
+ share_examples_for :thread_pool_executor do
5
+
6
+ after(:each) do
7
+ subject.kill
8
+ sleep(0.1)
9
+ end
10
+
11
+ it_should_behave_like :thread_pool
12
+
13
+ context '#initialize' do
14
+
15
+ it 'defaults :min_length to DEFAULT_MIN_POOL_SIZE' do
16
+ subject = described_class.new
17
+ subject.min_length.should eq described_class::DEFAULT_MIN_POOL_SIZE
18
+ end
19
+
20
+ it 'defaults :max_length to DEFAULT_MAX_POOL_SIZE' do
21
+ subject = described_class.new
22
+ subject.max_length.should eq described_class::DEFAULT_MAX_POOL_SIZE
23
+ end
24
+
25
+ it 'defaults :idletime to DEFAULT_THREAD_IDLETIMEOUT' do
26
+ subject = described_class.new
27
+ subject.idletime.should eq described_class::DEFAULT_THREAD_IDLETIMEOUT
28
+ end
29
+
30
+ it 'defaults :max_queue to DEFAULT_MAX_QUEUE_SIZE' do
31
+ subject = described_class.new
32
+ subject.max_queue.should eq described_class::DEFAULT_MAX_QUEUE_SIZE
33
+ end
34
+
35
+ it 'accepts all valid overflow policies' do
36
+ Concurrent::RubyThreadPoolExecutor::OVERFLOW_POLICIES.each do |policy|
37
+ subject = described_class.new(overflow_policy: policy)
38
+ subject.overflow_policy.should eq policy
39
+ end
40
+ end
41
+
42
+ it 'defaults :overflow_policy to :abort' do
43
+ subject = described_class.new
44
+ subject.overflow_policy.should eq :abort
45
+ end
46
+
47
+ it 'raises an exception if :min_threads is less than zero' do
48
+ expect {
49
+ described_class.new(min_threads: -1)
50
+ }.to raise_error(ArgumentError)
51
+ end
52
+
53
+ it 'raises an exception if :max_threads is not greater than zero' do
54
+ expect {
55
+ described_class.new(max_threads: 0)
56
+ }.to raise_error(ArgumentError)
57
+ end
58
+
59
+ it 'raises an exception if given an invalid :overflow_policy' do
60
+ expect {
61
+ described_class.new(overflow_policy: :bogus)
62
+ }.to raise_error(ArgumentError)
63
+ end
64
+ end
65
+
66
+ context '#max_queue' do
67
+
68
+ let!(:expected_max){ 100 }
69
+ subject{ described_class.new(max_queue: expected_max) }
70
+
71
+ it 'returns the set value on creation' do
72
+ subject.max_queue.should eq expected_max
73
+ end
74
+
75
+ it 'returns the set value when running' do
76
+ 5.times{ subject.post{ sleep(0.1) } }
77
+ sleep(0.1)
78
+ subject.max_queue.should eq expected_max
79
+ end
80
+
81
+ it 'returns the set value after stopping' do
82
+ 5.times{ subject.post{ sleep(0.1) } }
83
+ sleep(0.1)
84
+ subject.shutdown
85
+ subject.wait_for_termination(1)
86
+ subject.max_queue.should eq expected_max
87
+ end
88
+ end
89
+
90
+ context '#queue_length' do
91
+
92
+ let!(:expected_max){ 10 }
93
+ subject do
94
+ described_class.new(
95
+ min_threads: 2,
96
+ max_threads: 5,
97
+ max_queue: expected_max,
98
+ overflow_policy: :discard
99
+ )
100
+ end
101
+
102
+ it 'returns zero on creation' do
103
+ subject.queue_length.should eq 0
104
+ end
105
+
106
+ it 'returns zero when there are no enqueued tasks' do
107
+ 5.times{ subject.post{ nil } }
108
+ sleep(0.1)
109
+ subject.queue_length.should eq 0
110
+ end
111
+
112
+ it 'returns the size of the queue when tasks are enqueued' do
113
+ 100.times{ subject.post{ sleep(0.5) } }
114
+ sleep(0.1)
115
+ subject.queue_length.should > 0
116
+ end
117
+
118
+ it 'returns zero when stopped' do
119
+ 100.times{ subject.post{ sleep(0.5) } }
120
+ sleep(0.1)
121
+ subject.shutdown
122
+ subject.wait_for_termination(1)
123
+ subject.queue_length.should eq 0
124
+ end
125
+
126
+ it 'can never be greater than :max_queue' do
127
+ 100.times{ subject.post{ sleep(0.5) } }
128
+ sleep(0.1)
129
+ subject.queue_length.should <= expected_max
130
+ end
131
+ end
132
+
133
+ context '#remaining_capacity' do
134
+
135
+ let!(:expected_max){ 100 }
136
+ subject{ described_class.new(max_queue: expected_max) }
137
+
138
+ it 'returns -1 when :max_queue is set to zero' do
139
+ executor = described_class.new(max_queue: 0)
140
+ executor.remaining_capacity.should eq -1
141
+ end
142
+
143
+ it 'returns :max_length on creation' do
144
+ subject.remaining_capacity.should eq expected_max
145
+ end
146
+
147
+ it 'returns :max_length when stopped' do
148
+ 100.times{ subject.post{ nil } }
149
+ sleep(0.1)
150
+ subject.shutdown
151
+ subject.wait_for_termination(1)
152
+ subject.remaining_capacity.should eq expected_max
153
+ end
154
+ end
155
+ end
@@ -1,4 +1,5 @@
1
1
  require 'spec_helper'
2
+ require_relative 'global_thread_pool_shared'
2
3
 
3
4
  share_examples_for :thread_pool do
4
5
 
@@ -7,6 +8,79 @@ share_examples_for :thread_pool do
7
8
  sleep(0.1)
8
9
  end
9
10
 
11
+ it_should_behave_like :global_thread_pool
12
+
13
+ context '#scheduled_task_count' do
14
+
15
+ it 'returns zero on creation' do
16
+ subject.scheduled_task_count.should eq 0
17
+ end
18
+
19
+ it 'returns the approximate number of tasks that have been post thus far' do
20
+ 10.times{ subject.post{ nil } }
21
+ sleep(0.1)
22
+ subject.scheduled_task_count.should > 0
23
+ end
24
+
25
+ it 'returns the approximate number of tasks that were post' do
26
+ 10.times{ subject.post{ nil } }
27
+ sleep(0.1)
28
+ subject.shutdown
29
+ subject.wait_for_termination(1)
30
+ subject.scheduled_task_count.should > 0
31
+ end
32
+ end
33
+
34
+ context '#completed_task_count' do
35
+
36
+ it 'returns zero on creation' do
37
+ subject.completed_task_count.should eq 0
38
+ end
39
+
40
+ it 'returns the approximate number of tasks that have been completed thus far' do
41
+ 5.times{ subject.post{ raise StandardError } }
42
+ 5.times{ subject.post{ nil } }
43
+ sleep(0.1)
44
+ subject.completed_task_count.should > 0
45
+ end
46
+
47
+ it 'returns the approximate number of tasks that were completed' do
48
+ 5.times{ subject.post{ raise StandardError } }
49
+ 5.times{ subject.post{ nil } }
50
+ sleep(0.1)
51
+ subject.shutdown
52
+ subject.wait_for_termination(1)
53
+ subject.completed_task_count.should > 0
54
+ end
55
+ end
56
+
57
+ context '#length' do
58
+
59
+ it 'returns zero on creation' do
60
+ subject.length.should eq 0
61
+ end
62
+
63
+ it 'returns a non-zero while shutting down' do
64
+ 5.times{ subject.post{ sleep(0.1) } }
65
+ subject.shutdown
66
+ subject.length.should > 0
67
+ end
68
+
69
+ it 'returns zero once shut down' do
70
+ 5.times{ subject.post{ sleep(0.1) } }
71
+ sleep(0.1)
72
+ subject.shutdown
73
+ subject.wait_for_termination(1)
74
+ subject.length.should eq 0
75
+ end
76
+
77
+ it 'aliased as #current_length' do
78
+ 5.times{ subject.post{ sleep(0.1) } }
79
+ sleep(0.1)
80
+ subject.current_length.should eq subject.length
81
+ end
82
+ end
83
+
10
84
  context '#running?' do
11
85
 
12
86
  it 'returns true when the thread pool is running' do
@@ -16,16 +90,19 @@ share_examples_for :thread_pool do
16
90
  it 'returns false when the thread pool is shutting down' do
17
91
  subject.post{ sleep(1) }
18
92
  subject.shutdown
93
+ subject.wait_for_termination(1)
19
94
  subject.should_not be_running
20
95
  end
21
96
 
22
97
  it 'returns false when the thread pool is shutdown' do
23
98
  subject.shutdown
99
+ subject.wait_for_termination(1)
24
100
  subject.should_not be_running
25
101
  end
26
102
 
27
103
  it 'returns false when the thread pool is killed' do
28
- subject.shutdown
104
+ subject.kill
105
+ subject.wait_for_termination(1)
29
106
  subject.should_not be_running
30
107
  end
31
108
  end
@@ -83,55 +160,40 @@ share_examples_for :thread_pool do
83
160
  @expected.should be_false
84
161
  end
85
162
 
86
- it 'attempts to kill all in-progress tasks' do
87
- @expected = false
88
- subject.post{ sleep(1); @expected = true }
89
- sleep(0.1)
90
- subject.kill
91
- sleep(1)
92
- @expected.should be_false
93
- end
94
-
95
163
  it 'rejects all pending tasks' do
96
- @expected = false
97
- subject.post{ sleep(0.5) }
98
- subject.post{ sleep(0.5); @expected = true }
164
+ subject.post{ sleep(1) }
99
165
  sleep(0.1)
100
166
  subject.kill
101
- sleep(1)
102
- @expected.should be_false
167
+ sleep(0.1)
168
+ subject.post{ nil }.should be_false
103
169
  end
104
170
 
105
171
  it 'kills all threads' do
106
- before_thread_count = Thread.list.size
107
- 100.times { subject << proc{ sleep(1) } }
108
- sleep(0.1)
109
- Thread.list.size.should > before_thread_count
110
- subject.kill
111
- sleep(0.1)
112
- Thread.list.size.should == before_thread_count
172
+ unless jruby? # this check is incorrect, want to check for class
173
+ pending('brittle test--counting threads is not reliable')
174
+ before_thread_count = Thread.list.size
175
+ 100.times { subject << proc{ sleep(1) } }
176
+ sleep(0.1)
177
+ Thread.list.size.should > before_thread_count
178
+ subject.kill
179
+ sleep(0.1)
180
+ Thread.list.size.should == before_thread_count
181
+ end
113
182
  end
114
183
  end
115
184
 
116
185
  context '#wait_for_termination' do
117
186
 
118
- it 'immediately returns true when no threads running' do
187
+ it 'immediately returns true when no operations are pending' do
119
188
  subject.shutdown
120
- subject.wait_for_termination.should be_true
189
+ subject.wait_for_termination(0).should be_true
121
190
  end
122
191
 
123
192
  it 'returns true after shutdown has complete' do
124
- 10.times { subject << proc{ sleep(0.1) } }
125
- sleep(0.1)
126
- subject.shutdown
127
- subject.wait_for_termination.should be_true
128
- end
129
-
130
- it 'blocks indefinitely when timeout is nil' do
131
- subject.post{ sleep(1) }
193
+ 10.times { subject << proc{ nil } }
132
194
  sleep(0.1)
133
195
  subject.shutdown
134
- subject.wait_for_termination(nil).should be_true
196
+ subject.wait_for_termination(1).should be_true
135
197
  end
136
198
 
137
199
  it 'returns true when shutdown sucessfully completes before timeout' do
@@ -142,10 +204,10 @@ share_examples_for :thread_pool do
142
204
  end
143
205
 
144
206
  it 'returns false when shutdown fails to complete before timeout' do
145
- subject.post{ sleep }
207
+ (subject.length + 10).times{ subject.post{ sleep(1) } }
146
208
  sleep(0.1)
147
209
  subject.shutdown
148
- subject.wait_for_termination(1).should be_false
210
+ subject.wait_for_termination(0).should be_false
149
211
  end
150
212
  end
151
213
 
@@ -158,7 +220,7 @@ share_examples_for :thread_pool do
158
220
  end
159
221
 
160
222
  it 'returns true when the block is added to the queue' do
161
- subject.post{ sleep }.should be_true
223
+ subject.post{ nil }.should be_true
162
224
  end
163
225
 
164
226
  it 'calls the block with the given arguments' do