concurrent-ruby 0.1.0 → 0.1.1.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.
- data/LICENSE +21 -21
- data/README.md +279 -224
- data/lib/concurrent.rb +27 -20
- data/lib/concurrent/agent.rb +106 -130
- data/lib/concurrent/cached_thread_pool.rb +130 -122
- data/lib/concurrent/defer.rb +67 -69
- data/lib/concurrent/drb_async_demux.rb +72 -0
- data/lib/concurrent/event.rb +60 -60
- data/lib/concurrent/event_machine_defer_proxy.rb +23 -23
- data/lib/concurrent/executor.rb +87 -0
- data/lib/concurrent/fixed_thread_pool.rb +89 -89
- data/lib/concurrent/functions.rb +120 -0
- data/lib/concurrent/future.rb +52 -42
- data/lib/concurrent/global_thread_pool.rb +3 -3
- data/lib/concurrent/goroutine.rb +29 -25
- data/lib/concurrent/obligation.rb +67 -121
- data/lib/concurrent/promise.rb +172 -194
- data/lib/concurrent/reactor.rb +162 -0
- data/lib/concurrent/smart_mutex.rb +66 -0
- data/lib/concurrent/tcp_sync_demux.rb +96 -0
- data/lib/concurrent/thread_pool.rb +65 -61
- data/lib/concurrent/utilities.rb +34 -0
- data/lib/concurrent/version.rb +3 -3
- data/lib/concurrent_ruby.rb +1 -1
- data/md/agent.md +123 -123
- data/md/defer.md +174 -174
- data/md/event.md +32 -32
- data/md/executor.md +176 -0
- data/md/future.md +83 -83
- data/md/goroutine.md +52 -52
- data/md/obligation.md +32 -32
- data/md/promise.md +225 -225
- data/md/thread_pool.md +197 -197
- data/spec/concurrent/agent_spec.rb +376 -405
- data/spec/concurrent/cached_thread_pool_spec.rb +112 -112
- data/spec/concurrent/defer_spec.rb +209 -199
- data/spec/concurrent/event_machine_defer_proxy_spec.rb +250 -246
- data/spec/concurrent/event_spec.rb +134 -134
- data/spec/concurrent/executor_spec.rb +146 -0
- data/spec/concurrent/fixed_thread_pool_spec.rb +84 -84
- data/spec/concurrent/functions_spec.rb +57 -0
- data/spec/concurrent/future_spec.rb +125 -115
- data/spec/concurrent/goroutine_spec.rb +67 -52
- data/spec/concurrent/obligation_shared.rb +121 -121
- data/spec/concurrent/promise_spec.rb +299 -310
- data/spec/concurrent/smart_mutex_spec.rb +234 -0
- data/spec/concurrent/thread_pool_shared.rb +209 -209
- data/spec/concurrent/utilities_spec.rb +74 -0
- data/spec/spec_helper.rb +21 -19
- metadata +38 -14
- checksums.yaml +0 -7
@@ -0,0 +1,234 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Concurrent
|
4
|
+
|
5
|
+
describe SmartMutex do
|
6
|
+
|
7
|
+
subject{ SmartMutex.new }
|
8
|
+
|
9
|
+
def fly_solo
|
10
|
+
Thread.stub(:list).and_return(Array.new)
|
11
|
+
end
|
12
|
+
|
13
|
+
def run_with_the_pack
|
14
|
+
Thread.stub(:list).and_return([1,2,3,4])
|
15
|
+
end
|
16
|
+
|
17
|
+
context '#initialize' do
|
18
|
+
|
19
|
+
it 'creates a new mutex' do
|
20
|
+
Mutex.should_receive(:new).with(no_args())
|
21
|
+
SmartMutex.new
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
context '#alone?' do
|
26
|
+
|
27
|
+
it 'returns true when there is only one thread' do
|
28
|
+
fly_solo
|
29
|
+
subject.alone?.should be_true
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'returns false when there is more than one thread' do
|
33
|
+
run_with_the_pack
|
34
|
+
subject.alone?.should be_false
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
context '#lock' do
|
39
|
+
|
40
|
+
it 'does not lock when there is only one thread' do
|
41
|
+
fly_solo
|
42
|
+
|
43
|
+
mutex = Mutex.new
|
44
|
+
mutex.should_not_receive(:lock)
|
45
|
+
Mutex.should_receive(:new).with(no_args()).and_return(mutex)
|
46
|
+
|
47
|
+
subject.lock
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'locks when not locked and there is more than one thread' do
|
51
|
+
run_with_the_pack
|
52
|
+
|
53
|
+
mutex = Mutex.new
|
54
|
+
mutex.should_receive(:lock)
|
55
|
+
Mutex.should_receive(:new).with(no_args()).and_return(mutex)
|
56
|
+
|
57
|
+
subject.lock
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'raises an exception when locked and there is more than one thread' do
|
61
|
+
run_with_the_pack
|
62
|
+
subject.lock
|
63
|
+
lambda {
|
64
|
+
subject.lock
|
65
|
+
}.should raise_error(ThreadError)
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'does not raise an exception when lock called twice and there is only one thread' do
|
69
|
+
fly_solo
|
70
|
+
subject.lock
|
71
|
+
lambda {
|
72
|
+
subject.lock
|
73
|
+
}.should_not raise_error
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'returns self' do
|
77
|
+
fly_solo
|
78
|
+
mutex = SmartMutex.new
|
79
|
+
mutex.lock.should eq mutex
|
80
|
+
|
81
|
+
run_with_the_pack
|
82
|
+
mutex.lock.should eq mutex
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
context '#locked?' do
|
87
|
+
|
88
|
+
it 'returns false when there is only one thread' do
|
89
|
+
fly_solo
|
90
|
+
subject.should_not be_locked
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'returns true when locked and there is more than one thread' do
|
94
|
+
run_with_the_pack
|
95
|
+
subject.lock
|
96
|
+
subject.should be_locked
|
97
|
+
end
|
98
|
+
|
99
|
+
it 'returns false when not locked and there is more than one thread' do
|
100
|
+
run_with_the_pack
|
101
|
+
subject.should_not be_locked
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
context '#sleep' do
|
106
|
+
|
107
|
+
it 'sleeps when there is only one thread' do
|
108
|
+
fly_solo
|
109
|
+
Kernel.should_receive(:sleep).with(0.1).and_return(0.1)
|
110
|
+
subject.sleep(0.1)
|
111
|
+
end
|
112
|
+
|
113
|
+
it 'sleeps when locked and there is more than one thread' do
|
114
|
+
mutex = Mutex.new
|
115
|
+
mutex.should_receive(:sleep).with(0.1).and_return(0.1)
|
116
|
+
Mutex.should_receive(:new).with(no_args()).and_return(mutex)
|
117
|
+
|
118
|
+
run_with_the_pack
|
119
|
+
subject.lock
|
120
|
+
subject.sleep(0.1)
|
121
|
+
end
|
122
|
+
|
123
|
+
it 'raises an exception when not locked and there is more than one thread' do
|
124
|
+
run_with_the_pack
|
125
|
+
lambda {
|
126
|
+
subject.sleep(0.1)
|
127
|
+
}.should raise_error(ThreadError)
|
128
|
+
end
|
129
|
+
|
130
|
+
it 'returns the number of seconds slept' do
|
131
|
+
fly_solo
|
132
|
+
subject.sleep(1).should eq 1
|
133
|
+
|
134
|
+
run_with_the_pack
|
135
|
+
subject.lock
|
136
|
+
subject.sleep(1).should eq 1
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
context '#synchronize' do
|
141
|
+
|
142
|
+
it 'yields to the block when there is only one thread' do
|
143
|
+
fly_solo
|
144
|
+
@expected = false
|
145
|
+
subject.synchronize{ @expected = true }
|
146
|
+
@expected.should be_true
|
147
|
+
end
|
148
|
+
|
149
|
+
it 'locks when there is more than one thread' do
|
150
|
+
mutex = Mutex.new
|
151
|
+
mutex.should_receive(:synchronize).with(no_args())
|
152
|
+
Mutex.should_receive(:new).with(no_args()).and_return(mutex)
|
153
|
+
|
154
|
+
run_with_the_pack
|
155
|
+
subject.synchronize{ nil }
|
156
|
+
end
|
157
|
+
|
158
|
+
it 'yields to the block when there is more than one thread' do
|
159
|
+
run_with_the_pack
|
160
|
+
@expected = false
|
161
|
+
subject.synchronize{ @expected = true }
|
162
|
+
@expected.should be_true
|
163
|
+
end
|
164
|
+
|
165
|
+
it 'returns the result of the block' do
|
166
|
+
fly_solo
|
167
|
+
subject.synchronize{ 42 }.should eq 42
|
168
|
+
|
169
|
+
run_with_the_pack
|
170
|
+
subject.synchronize{ 42 }.should eq 42
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
context '#try_lock' do
|
175
|
+
|
176
|
+
it 'returns true when there is only one thread' do
|
177
|
+
fly_solo
|
178
|
+
subject.try_lock.should be_true
|
179
|
+
end
|
180
|
+
|
181
|
+
it 'returns true when the lock is obtained and there is more than one thread' do
|
182
|
+
run_with_the_pack
|
183
|
+
subject.try_lock.should be_true
|
184
|
+
end
|
185
|
+
|
186
|
+
it 'returns false when the lock is not obtained and there is more than one thread' do
|
187
|
+
run_with_the_pack
|
188
|
+
subject.lock
|
189
|
+
subject.try_lock.should be_false
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
context '#unlock' do
|
194
|
+
|
195
|
+
it 'does not unlock when there is only one thread' do
|
196
|
+
fly_solo
|
197
|
+
|
198
|
+
mutex = Mutex.new
|
199
|
+
mutex.should_not_receive(:unlock)
|
200
|
+
Mutex.should_receive(:new).with(no_args()).and_return(mutex)
|
201
|
+
|
202
|
+
subject.unlock
|
203
|
+
end
|
204
|
+
|
205
|
+
it 'unlocks when locked and there is more than one thread' do
|
206
|
+
run_with_the_pack
|
207
|
+
|
208
|
+
mutex = Mutex.new
|
209
|
+
mutex.should_receive(:unlock)
|
210
|
+
Mutex.should_receive(:new).with(no_args()).and_return(mutex)
|
211
|
+
|
212
|
+
subject.lock
|
213
|
+
subject.unlock
|
214
|
+
end
|
215
|
+
|
216
|
+
it 'raises an exception when not locked and there is more than one thread' do
|
217
|
+
run_with_the_pack
|
218
|
+
lambda {
|
219
|
+
subject.unlock
|
220
|
+
}.should raise_error(ThreadError)
|
221
|
+
end
|
222
|
+
|
223
|
+
it 'returns self' do
|
224
|
+
fly_solo
|
225
|
+
mutex = SmartMutex.new
|
226
|
+
mutex.unlock.should eq mutex
|
227
|
+
|
228
|
+
run_with_the_pack
|
229
|
+
mutex.lock
|
230
|
+
mutex.unlock.should eq mutex
|
231
|
+
end
|
232
|
+
end
|
233
|
+
end
|
234
|
+
end
|
@@ -1,209 +1,209 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
module Concurrent
|
4
|
-
|
5
|
-
share_examples_for 'Thread Pool' do
|
6
|
-
|
7
|
-
context '#running?' do
|
8
|
-
|
9
|
-
it 'returns true when the thread pool is running' do
|
10
|
-
subject.should be_running
|
11
|
-
end
|
12
|
-
|
13
|
-
it 'returns false when the thread pool is shutting down' do
|
14
|
-
subject.post{ sleep(1) }
|
15
|
-
subject.shutdown
|
16
|
-
subject.should_not be_running
|
17
|
-
end
|
18
|
-
|
19
|
-
it 'returns false when the thread pool is shutdown' do
|
20
|
-
subject.shutdown
|
21
|
-
subject.should_not be_running
|
22
|
-
end
|
23
|
-
|
24
|
-
it 'returns false when the thread pool is killed' do
|
25
|
-
subject.shutdown
|
26
|
-
subject.should_not be_running
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
context '#shutdown?' do
|
31
|
-
|
32
|
-
it 'returns true if #shutdown has been called' do
|
33
|
-
subject.shutdown
|
34
|
-
subject.should be_shutdown
|
35
|
-
end
|
36
|
-
|
37
|
-
it 'returns false when running' do
|
38
|
-
subject.should_not be_shutdown
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
context '#killed?' do
|
43
|
-
|
44
|
-
it 'returns true if tasks were killed at shutdown' do
|
45
|
-
subject.post{ sleep(1) }
|
46
|
-
subject.kill
|
47
|
-
subject.should be_killed
|
48
|
-
end
|
49
|
-
|
50
|
-
it 'returns false when running' do
|
51
|
-
subject.should_not be_killed
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
context '#shutdown' do
|
56
|
-
|
57
|
-
it 'stops accepting new tasks' do
|
58
|
-
subject.post{ sleep(1) }
|
59
|
-
subject.shutdown
|
60
|
-
@expected = false
|
61
|
-
subject.post{ @expected = true }.should be_false
|
62
|
-
sleep(1)
|
63
|
-
@expected.should be_false
|
64
|
-
end
|
65
|
-
|
66
|
-
it 'allows in-progress tasks to complete' do
|
67
|
-
@expected = false
|
68
|
-
subject.post{ sleep(0.5); @expected = true }
|
69
|
-
subject.shutdown
|
70
|
-
sleep(1)
|
71
|
-
@expected.should be_true
|
72
|
-
end
|
73
|
-
|
74
|
-
it 'allows pending tasks to complete' do
|
75
|
-
@expected = false
|
76
|
-
subject.post{ sleep(0.2) }
|
77
|
-
subject.post{ sleep(0.2); @expected = true }
|
78
|
-
subject.shutdown
|
79
|
-
sleep(1)
|
80
|
-
@expected.should be_true
|
81
|
-
end
|
82
|
-
|
83
|
-
it 'allows threads to exit normally' do
|
84
|
-
pool = FixedThreadPool.new(5)
|
85
|
-
pool.shutdown
|
86
|
-
sleep(1)
|
87
|
-
pool.status.should be_empty
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
context '#kill' do
|
92
|
-
|
93
|
-
it 'stops accepting new tasks' do
|
94
|
-
subject.post{ sleep(1) }
|
95
|
-
subject.kill
|
96
|
-
@expected = false
|
97
|
-
subject.post{ @expected = true }.should be_false
|
98
|
-
sleep(1)
|
99
|
-
@expected.should be_false
|
100
|
-
end
|
101
|
-
|
102
|
-
it 'attempts to kill all in-progress tasks' do
|
103
|
-
@expected = false
|
104
|
-
subject.post{ sleep(1); @expected = true }
|
105
|
-
subject.kill
|
106
|
-
sleep(1)
|
107
|
-
@expected.should be_false
|
108
|
-
end
|
109
|
-
|
110
|
-
it 'rejects all pending tasks' do
|
111
|
-
@expected = false
|
112
|
-
subject.post{ sleep(0.5) }
|
113
|
-
subject.post{ sleep(0.5); @expected = true }
|
114
|
-
subject.kill
|
115
|
-
sleep(1)
|
116
|
-
@expected.should be_false
|
117
|
-
end
|
118
|
-
end
|
119
|
-
|
120
|
-
context '#wait_for_termination' do
|
121
|
-
|
122
|
-
it 'immediately returns true after shutdown has complete' do
|
123
|
-
subject.shutdown
|
124
|
-
subject.wait_for_termination.should be_true
|
125
|
-
end
|
126
|
-
|
127
|
-
it 'blocks indefinitely when timeout it nil' do
|
128
|
-
subject.post{ sleep(1) }
|
129
|
-
subject.shutdown
|
130
|
-
subject.wait_for_termination(nil).should be_true
|
131
|
-
end
|
132
|
-
|
133
|
-
it 'returns true when shutdown sucessfully completes before timeout' do
|
134
|
-
subject.post{ sleep(0.5) }
|
135
|
-
subject.shutdown
|
136
|
-
subject.wait_for_termination(1).should be_true
|
137
|
-
end
|
138
|
-
|
139
|
-
it 'returns false when shutdown fails to complete before timeout' do
|
140
|
-
subject.post{ sleep(1) }
|
141
|
-
subject.shutdown
|
142
|
-
subject.wait_for_termination(0.5).should be_true
|
143
|
-
end
|
144
|
-
end
|
145
|
-
|
146
|
-
context '#post' do
|
147
|
-
|
148
|
-
it 'raises an exception if no block is given' do
|
149
|
-
lambda {
|
150
|
-
subject.post
|
151
|
-
}.should raise_error(ArgumentError)
|
152
|
-
end
|
153
|
-
|
154
|
-
it 'returns true when the block is added to the queue' do
|
155
|
-
subject.post{ nil }.should be_true
|
156
|
-
end
|
157
|
-
|
158
|
-
it 'calls the block with the given arguments' do
|
159
|
-
@expected = nil
|
160
|
-
subject.post(1, 2, 3)do |a, b, c|
|
161
|
-
@expected = a + b + c
|
162
|
-
end
|
163
|
-
sleep(0.1)
|
164
|
-
@expected.should eq 6
|
165
|
-
end
|
166
|
-
|
167
|
-
it 'rejects the block while shutting down' do
|
168
|
-
pool = FixedThreadPool.new(5)
|
169
|
-
pool.post{ sleep(1) }
|
170
|
-
pool.shutdown
|
171
|
-
@expected = nil
|
172
|
-
pool.post(1, 2, 3)do |a, b, c|
|
173
|
-
@expected = a + b + c
|
174
|
-
end
|
175
|
-
@expected.should be_nil
|
176
|
-
end
|
177
|
-
|
178
|
-
it 'returns false while shutting down' do
|
179
|
-
subject.post{ sleep(1) }
|
180
|
-
subject.shutdown
|
181
|
-
subject.post{ nil }.should be_false
|
182
|
-
end
|
183
|
-
|
184
|
-
it 'rejects the block once shutdown' do
|
185
|
-
pool = FixedThreadPool.new(5)
|
186
|
-
pool.shutdown
|
187
|
-
@expected = nil
|
188
|
-
pool.post(1, 2, 3)do |a, b, c|
|
189
|
-
@expected = a + b + c
|
190
|
-
end
|
191
|
-
@expected.should be_nil
|
192
|
-
end
|
193
|
-
|
194
|
-
it 'returns false once shutdown' do
|
195
|
-
subject.post{ nil }
|
196
|
-
subject.shutdown
|
197
|
-
sleep(0.1)
|
198
|
-
subject.post{ nil }.should be_false
|
199
|
-
end
|
200
|
-
|
201
|
-
it 'aliases #<<' do
|
202
|
-
@expected = false
|
203
|
-
subject << proc { @expected = true }
|
204
|
-
sleep(0.1)
|
205
|
-
@expected.should be_true
|
206
|
-
end
|
207
|
-
end
|
208
|
-
end
|
209
|
-
end
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Concurrent
|
4
|
+
|
5
|
+
share_examples_for 'Thread Pool' do
|
6
|
+
|
7
|
+
context '#running?' do
|
8
|
+
|
9
|
+
it 'returns true when the thread pool is running' do
|
10
|
+
subject.should be_running
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'returns false when the thread pool is shutting down' do
|
14
|
+
subject.post{ sleep(1) }
|
15
|
+
subject.shutdown
|
16
|
+
subject.should_not be_running
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'returns false when the thread pool is shutdown' do
|
20
|
+
subject.shutdown
|
21
|
+
subject.should_not be_running
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'returns false when the thread pool is killed' do
|
25
|
+
subject.shutdown
|
26
|
+
subject.should_not be_running
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
context '#shutdown?' do
|
31
|
+
|
32
|
+
it 'returns true if #shutdown has been called' do
|
33
|
+
subject.shutdown
|
34
|
+
subject.should be_shutdown
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'returns false when running' do
|
38
|
+
subject.should_not be_shutdown
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
context '#killed?' do
|
43
|
+
|
44
|
+
it 'returns true if tasks were killed at shutdown' do
|
45
|
+
subject.post{ sleep(1) }
|
46
|
+
subject.kill
|
47
|
+
subject.should be_killed
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'returns false when running' do
|
51
|
+
subject.should_not be_killed
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
context '#shutdown' do
|
56
|
+
|
57
|
+
it 'stops accepting new tasks' do
|
58
|
+
subject.post{ sleep(1) }
|
59
|
+
subject.shutdown
|
60
|
+
@expected = false
|
61
|
+
subject.post{ @expected = true }.should be_false
|
62
|
+
sleep(1)
|
63
|
+
@expected.should be_false
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'allows in-progress tasks to complete' do
|
67
|
+
@expected = false
|
68
|
+
subject.post{ sleep(0.5); @expected = true }
|
69
|
+
subject.shutdown
|
70
|
+
sleep(1)
|
71
|
+
@expected.should be_true
|
72
|
+
end
|
73
|
+
|
74
|
+
it 'allows pending tasks to complete' do
|
75
|
+
@expected = false
|
76
|
+
subject.post{ sleep(0.2) }
|
77
|
+
subject.post{ sleep(0.2); @expected = true }
|
78
|
+
subject.shutdown
|
79
|
+
sleep(1)
|
80
|
+
@expected.should be_true
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'allows threads to exit normally' do
|
84
|
+
pool = FixedThreadPool.new(5)
|
85
|
+
pool.shutdown
|
86
|
+
sleep(1)
|
87
|
+
pool.status.should be_empty
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
context '#kill' do
|
92
|
+
|
93
|
+
it 'stops accepting new tasks' do
|
94
|
+
subject.post{ sleep(1) }
|
95
|
+
subject.kill
|
96
|
+
@expected = false
|
97
|
+
subject.post{ @expected = true }.should be_false
|
98
|
+
sleep(1)
|
99
|
+
@expected.should be_false
|
100
|
+
end
|
101
|
+
|
102
|
+
it 'attempts to kill all in-progress tasks' do
|
103
|
+
@expected = false
|
104
|
+
subject.post{ sleep(1); @expected = true }
|
105
|
+
subject.kill
|
106
|
+
sleep(1)
|
107
|
+
@expected.should be_false
|
108
|
+
end
|
109
|
+
|
110
|
+
it 'rejects all pending tasks' do
|
111
|
+
@expected = false
|
112
|
+
subject.post{ sleep(0.5) }
|
113
|
+
subject.post{ sleep(0.5); @expected = true }
|
114
|
+
subject.kill
|
115
|
+
sleep(1)
|
116
|
+
@expected.should be_false
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
context '#wait_for_termination' do
|
121
|
+
|
122
|
+
it 'immediately returns true after shutdown has complete' do
|
123
|
+
subject.shutdown
|
124
|
+
subject.wait_for_termination.should be_true
|
125
|
+
end
|
126
|
+
|
127
|
+
it 'blocks indefinitely when timeout it nil' do
|
128
|
+
subject.post{ sleep(1) }
|
129
|
+
subject.shutdown
|
130
|
+
subject.wait_for_termination(nil).should be_true
|
131
|
+
end
|
132
|
+
|
133
|
+
it 'returns true when shutdown sucessfully completes before timeout' do
|
134
|
+
subject.post{ sleep(0.5) }
|
135
|
+
subject.shutdown
|
136
|
+
subject.wait_for_termination(1).should be_true
|
137
|
+
end
|
138
|
+
|
139
|
+
it 'returns false when shutdown fails to complete before timeout' do
|
140
|
+
subject.post{ sleep(1) }
|
141
|
+
subject.shutdown
|
142
|
+
subject.wait_for_termination(0.5).should be_true
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
context '#post' do
|
147
|
+
|
148
|
+
it 'raises an exception if no block is given' do
|
149
|
+
lambda {
|
150
|
+
subject.post
|
151
|
+
}.should raise_error(ArgumentError)
|
152
|
+
end
|
153
|
+
|
154
|
+
it 'returns true when the block is added to the queue' do
|
155
|
+
subject.post{ nil }.should be_true
|
156
|
+
end
|
157
|
+
|
158
|
+
it 'calls the block with the given arguments' do
|
159
|
+
@expected = nil
|
160
|
+
subject.post(1, 2, 3)do |a, b, c|
|
161
|
+
@expected = a + b + c
|
162
|
+
end
|
163
|
+
sleep(0.1)
|
164
|
+
@expected.should eq 6
|
165
|
+
end
|
166
|
+
|
167
|
+
it 'rejects the block while shutting down' do
|
168
|
+
pool = FixedThreadPool.new(5)
|
169
|
+
pool.post{ sleep(1) }
|
170
|
+
pool.shutdown
|
171
|
+
@expected = nil
|
172
|
+
pool.post(1, 2, 3)do |a, b, c|
|
173
|
+
@expected = a + b + c
|
174
|
+
end
|
175
|
+
@expected.should be_nil
|
176
|
+
end
|
177
|
+
|
178
|
+
it 'returns false while shutting down' do
|
179
|
+
subject.post{ sleep(1) }
|
180
|
+
subject.shutdown
|
181
|
+
subject.post{ nil }.should be_false
|
182
|
+
end
|
183
|
+
|
184
|
+
it 'rejects the block once shutdown' do
|
185
|
+
pool = FixedThreadPool.new(5)
|
186
|
+
pool.shutdown
|
187
|
+
@expected = nil
|
188
|
+
pool.post(1, 2, 3)do |a, b, c|
|
189
|
+
@expected = a + b + c
|
190
|
+
end
|
191
|
+
@expected.should be_nil
|
192
|
+
end
|
193
|
+
|
194
|
+
it 'returns false once shutdown' do
|
195
|
+
subject.post{ nil }
|
196
|
+
subject.shutdown
|
197
|
+
sleep(0.1)
|
198
|
+
subject.post{ nil }.should be_false
|
199
|
+
end
|
200
|
+
|
201
|
+
it 'aliases #<<' do
|
202
|
+
@expected = false
|
203
|
+
subject << proc { @expected = true }
|
204
|
+
sleep(0.1)
|
205
|
+
@expected.should be_true
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|