concurrent-ruby 0.2.0 → 0.2.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 +275 -275
- data/lib/concurrent.rb +28 -28
- data/lib/concurrent/agent.rb +114 -114
- data/lib/concurrent/cached_thread_pool.rb +131 -129
- data/lib/concurrent/defer.rb +65 -65
- data/lib/concurrent/event.rb +60 -60
- data/lib/concurrent/event_machine_defer_proxy.rb +23 -23
- data/lib/concurrent/executor.rb +96 -95
- data/lib/concurrent/fixed_thread_pool.rb +99 -95
- data/lib/concurrent/functions.rb +120 -120
- data/lib/concurrent/future.rb +42 -42
- data/lib/concurrent/global_thread_pool.rb +16 -16
- data/lib/concurrent/goroutine.rb +29 -29
- data/lib/concurrent/null_thread_pool.rb +22 -22
- data/lib/concurrent/obligation.rb +67 -67
- data/lib/concurrent/promise.rb +174 -174
- data/lib/concurrent/reactor.rb +166 -166
- data/lib/concurrent/reactor/drb_async_demux.rb +83 -83
- data/lib/concurrent/reactor/tcp_sync_demux.rb +131 -131
- data/lib/concurrent/supervisor.rb +105 -100
- data/lib/concurrent/thread_pool.rb +76 -76
- data/lib/concurrent/utilities.rb +32 -32
- 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 +187 -187
- data/md/future.md +83 -83
- data/md/goroutine.md +52 -52
- data/md/obligation.md +32 -32
- data/md/promise.md +227 -227
- data/md/thread_pool.md +224 -224
- data/spec/concurrent/agent_spec.rb +386 -386
- data/spec/concurrent/cached_thread_pool_spec.rb +125 -125
- data/spec/concurrent/defer_spec.rb +195 -195
- data/spec/concurrent/event_machine_defer_proxy_spec.rb +256 -256
- data/spec/concurrent/event_spec.rb +134 -134
- data/spec/concurrent/executor_spec.rb +200 -200
- data/spec/concurrent/fixed_thread_pool_spec.rb +83 -83
- data/spec/concurrent/functions_spec.rb +217 -217
- data/spec/concurrent/future_spec.rb +108 -108
- data/spec/concurrent/global_thread_pool_spec.rb +38 -38
- data/spec/concurrent/goroutine_spec.rb +67 -67
- data/spec/concurrent/null_thread_pool_spec.rb +57 -54
- data/spec/concurrent/obligation_shared.rb +132 -132
- data/spec/concurrent/promise_spec.rb +312 -312
- data/spec/concurrent/reactor/drb_async_demux_spec.rb +196 -196
- data/spec/concurrent/reactor/tcp_sync_demux_spec.rb +410 -410
- data/spec/concurrent/reactor_spec.rb +364 -364
- data/spec/concurrent/supervisor_spec.rb +269 -258
- data/spec/concurrent/thread_pool_shared.rb +204 -204
- data/spec/concurrent/utilities_spec.rb +74 -74
- data/spec/spec_helper.rb +32 -32
- metadata +20 -16
- checksums.yaml +0 -7
@@ -1,125 +1,125 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
require_relative 'thread_pool_shared'
|
3
|
-
|
4
|
-
module Concurrent
|
5
|
-
|
6
|
-
describe CachedThreadPool do
|
7
|
-
|
8
|
-
subject { CachedThreadPool.new }
|
9
|
-
|
10
|
-
it_should_behave_like 'Thread Pool'
|
11
|
-
|
12
|
-
context '#initialize' do
|
13
|
-
|
14
|
-
it 'aliases Concurrent#new_cached_thread_pool' do
|
15
|
-
pool = Concurrent.new_cached_thread_pool
|
16
|
-
pool.should be_a(CachedThreadPool)
|
17
|
-
pool.size.should eq 0
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
context '#kill' do
|
22
|
-
|
23
|
-
it 'kills all threads' do
|
24
|
-
Thread.should_receive(:kill).at_least(5).times
|
25
|
-
pool = CachedThreadPool.new
|
26
|
-
5.times{ sleep(0.1); pool << proc{ sleep(1) } }
|
27
|
-
sleep(1)
|
28
|
-
pool.kill
|
29
|
-
sleep(0.1)
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
context '#size' do
|
34
|
-
|
35
|
-
it 'returns zero for a new thread pool' do
|
36
|
-
subject.size.should eq 0
|
37
|
-
end
|
38
|
-
|
39
|
-
it 'returns the size of the subject when running' do
|
40
|
-
5.times{ sleep(0.1); subject << proc{ sleep(1) } }
|
41
|
-
subject.size.should eq 5
|
42
|
-
end
|
43
|
-
|
44
|
-
it 'returns zero once shut down' do
|
45
|
-
subject.shutdown
|
46
|
-
subject.size.should eq 0
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
context 'worker creation and caching' do
|
51
|
-
|
52
|
-
it 'creates new workers when there are none available' do
|
53
|
-
subject.size.should eq 0
|
54
|
-
5.times{ sleep(0.1); subject << proc{ sleep(1000) } }
|
55
|
-
sleep(1)
|
56
|
-
subject.size.should eq 5
|
57
|
-
end
|
58
|
-
|
59
|
-
it 'uses existing idle threads' do
|
60
|
-
5.times{ sleep(0.05); subject << proc{ sleep(0.5) } }
|
61
|
-
sleep(1)
|
62
|
-
3.times{ sleep(0.1); subject << proc{ sleep(0.5) } }
|
63
|
-
subject.size.should eq 5
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
context 'garbage collection' do
|
68
|
-
|
69
|
-
subject{ CachedThreadPool.new(gc_interval: 1, thread_idleime: 1) }
|
70
|
-
|
71
|
-
it 'starts when the first thread is added to the pool' do
|
72
|
-
subject.should_receive(:collect_garbage)
|
73
|
-
subject << proc{ nil }
|
74
|
-
sleep(0.1)
|
75
|
-
end
|
76
|
-
|
77
|
-
it 'removes from pool any thread that has been idle too long' do
|
78
|
-
subject << proc{ nil }
|
79
|
-
subject.size.should eq 1
|
80
|
-
sleep(1.5)
|
81
|
-
subject.size.should eq 0
|
82
|
-
end
|
83
|
-
|
84
|
-
it 'removed from pool any dead thread' do
|
85
|
-
subject << proc{ raise StandardError }
|
86
|
-
subject.size.should eq 1
|
87
|
-
sleep(1.5)
|
88
|
-
subject.size.should eq 0
|
89
|
-
end
|
90
|
-
|
91
|
-
it 'resets the working count appropriately' do
|
92
|
-
subject << proc{ sleep(1000) }
|
93
|
-
sleep(0.1)
|
94
|
-
subject << proc{ raise StandardError }
|
95
|
-
sleep(0.1)
|
96
|
-
subject << proc{ nil }
|
97
|
-
|
98
|
-
sleep(0.1)
|
99
|
-
subject.working.should eq 2
|
100
|
-
|
101
|
-
sleep(1.5)
|
102
|
-
subject.working.should eq 1
|
103
|
-
end
|
104
|
-
|
105
|
-
it 'stops collection when the pool size becomes zero' do
|
106
|
-
3.times{ sleep(0.1); subject << proc{ sleep(0.5) } }
|
107
|
-
subject.instance_variable_get(:@collector).status.should eq 'sleep'
|
108
|
-
sleep(1.5)
|
109
|
-
subject.instance_variable_get(:@collector).status.should be_false
|
110
|
-
end
|
111
|
-
end
|
112
|
-
|
113
|
-
context '#status' do
|
114
|
-
|
115
|
-
it 'returns an empty collection when the pool is empty' do
|
116
|
-
subject.status.should be_empty
|
117
|
-
end
|
118
|
-
|
119
|
-
it 'returns one status object for each thread in the pool' do
|
120
|
-
3.times{ sleep(0.1); subject << proc{ sleep(0.5) } }
|
121
|
-
subject.status.length.should eq 3
|
122
|
-
end
|
123
|
-
end
|
124
|
-
end
|
125
|
-
end
|
1
|
+
require 'spec_helper'
|
2
|
+
require_relative 'thread_pool_shared'
|
3
|
+
|
4
|
+
module Concurrent
|
5
|
+
|
6
|
+
describe CachedThreadPool do
|
7
|
+
|
8
|
+
subject { CachedThreadPool.new }
|
9
|
+
|
10
|
+
it_should_behave_like 'Thread Pool'
|
11
|
+
|
12
|
+
context '#initialize' do
|
13
|
+
|
14
|
+
it 'aliases Concurrent#new_cached_thread_pool' do
|
15
|
+
pool = Concurrent.new_cached_thread_pool
|
16
|
+
pool.should be_a(CachedThreadPool)
|
17
|
+
pool.size.should eq 0
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
context '#kill' do
|
22
|
+
|
23
|
+
it 'kills all threads' do
|
24
|
+
Thread.should_receive(:kill).at_least(5).times
|
25
|
+
pool = CachedThreadPool.new
|
26
|
+
5.times{ sleep(0.1); pool << proc{ sleep(1) } }
|
27
|
+
sleep(1)
|
28
|
+
pool.kill
|
29
|
+
sleep(0.1)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
context '#size' do
|
34
|
+
|
35
|
+
it 'returns zero for a new thread pool' do
|
36
|
+
subject.size.should eq 0
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'returns the size of the subject when running' do
|
40
|
+
5.times{ sleep(0.1); subject << proc{ sleep(1) } }
|
41
|
+
subject.size.should eq 5
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'returns zero once shut down' do
|
45
|
+
subject.shutdown
|
46
|
+
subject.size.should eq 0
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
context 'worker creation and caching' do
|
51
|
+
|
52
|
+
it 'creates new workers when there are none available' do
|
53
|
+
subject.size.should eq 0
|
54
|
+
5.times{ sleep(0.1); subject << proc{ sleep(1000) } }
|
55
|
+
sleep(1)
|
56
|
+
subject.size.should eq 5
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'uses existing idle threads' do
|
60
|
+
5.times{ sleep(0.05); subject << proc{ sleep(0.5) } }
|
61
|
+
sleep(1)
|
62
|
+
3.times{ sleep(0.1); subject << proc{ sleep(0.5) } }
|
63
|
+
subject.size.should eq 5
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
context 'garbage collection' do
|
68
|
+
|
69
|
+
subject{ CachedThreadPool.new(gc_interval: 1, thread_idleime: 1) }
|
70
|
+
|
71
|
+
it 'starts when the first thread is added to the pool' do
|
72
|
+
subject.should_receive(:collect_garbage)
|
73
|
+
subject << proc{ nil }
|
74
|
+
sleep(0.1)
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'removes from pool any thread that has been idle too long' do
|
78
|
+
subject << proc{ nil }
|
79
|
+
subject.size.should eq 1
|
80
|
+
sleep(1.5)
|
81
|
+
subject.size.should eq 0
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'removed from pool any dead thread' do
|
85
|
+
subject << proc{ raise StandardError }
|
86
|
+
subject.size.should eq 1
|
87
|
+
sleep(1.5)
|
88
|
+
subject.size.should eq 0
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'resets the working count appropriately' do
|
92
|
+
subject << proc{ sleep(1000) }
|
93
|
+
sleep(0.1)
|
94
|
+
subject << proc{ raise StandardError }
|
95
|
+
sleep(0.1)
|
96
|
+
subject << proc{ nil }
|
97
|
+
|
98
|
+
sleep(0.1)
|
99
|
+
subject.working.should eq 2
|
100
|
+
|
101
|
+
sleep(1.5)
|
102
|
+
subject.working.should eq 1
|
103
|
+
end
|
104
|
+
|
105
|
+
it 'stops collection when the pool size becomes zero' do
|
106
|
+
3.times{ sleep(0.1); subject << proc{ sleep(0.5) } }
|
107
|
+
subject.instance_variable_get(:@collector).status.should eq 'sleep'
|
108
|
+
sleep(1.5)
|
109
|
+
subject.instance_variable_get(:@collector).status.should be_false
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
context '#status' do
|
114
|
+
|
115
|
+
it 'returns an empty collection when the pool is empty' do
|
116
|
+
subject.status.should be_empty
|
117
|
+
end
|
118
|
+
|
119
|
+
it 'returns one status object for each thread in the pool' do
|
120
|
+
3.times{ sleep(0.1); subject << proc{ sleep(0.5) } }
|
121
|
+
subject.status.length.should eq 3
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
@@ -1,195 +1,195 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
module Concurrent
|
4
|
-
|
5
|
-
describe Defer do
|
6
|
-
|
7
|
-
before(:each) do
|
8
|
-
Defer.thread_pool = FixedThreadPool.new(1)
|
9
|
-
end
|
10
|
-
|
11
|
-
context '#initialize' do
|
12
|
-
|
13
|
-
it 'raises an exception if no block or operation given' do
|
14
|
-
lambda {
|
15
|
-
Defer.new
|
16
|
-
}.should raise_error(ArgumentError)
|
17
|
-
end
|
18
|
-
|
19
|
-
it 'raises an exception if both a block and an operation given' do
|
20
|
-
lambda {
|
21
|
-
operation = proc{ nil }
|
22
|
-
Defer.new(op: operation){ nil }
|
23
|
-
}.should raise_error(ArgumentError)
|
24
|
-
end
|
25
|
-
|
26
|
-
it 'starts the thread if an operation is given' do
|
27
|
-
Defer.thread_pool.should_receive(:post).once.with(any_args())
|
28
|
-
operation = proc{ nil }
|
29
|
-
Defer.new(op: operation)
|
30
|
-
end
|
31
|
-
|
32
|
-
it 'does not start the thread if neither a callback or errorback is given' do
|
33
|
-
Defer.thread_pool.should_not_receive(:post)
|
34
|
-
Defer.new{ nil }
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
context '#then' do
|
39
|
-
|
40
|
-
it 'raises an exception if no block given' do
|
41
|
-
lambda {
|
42
|
-
Defer.new{ nil }.then
|
43
|
-
}.should raise_error(ArgumentError)
|
44
|
-
end
|
45
|
-
|
46
|
-
it 'raises an exception if called twice' do
|
47
|
-
lambda {
|
48
|
-
Defer.new{ nil }.then{|result| nil }.then{|result| nil }
|
49
|
-
}.should raise_error(IllegalMethodCallError)
|
50
|
-
end
|
51
|
-
|
52
|
-
it 'raises an exception if an operation was provided at construction' do
|
53
|
-
lambda {
|
54
|
-
operation = proc{ nil }
|
55
|
-
Defer.new(op: operation).then{|result| nil }
|
56
|
-
}.should raise_error(IllegalMethodCallError)
|
57
|
-
end
|
58
|
-
|
59
|
-
it 'raises an exception if a callback was provided at construction' do
|
60
|
-
lambda {
|
61
|
-
callback = proc{|result|nil }
|
62
|
-
Defer.new(callback: callback){ nil }.then{|result| nil }
|
63
|
-
}.should raise_error(IllegalMethodCallError)
|
64
|
-
end
|
65
|
-
|
66
|
-
it 'returns self' do
|
67
|
-
deferred = Defer.new{ nil }
|
68
|
-
deferred.then{|result| nil }.should eq deferred
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
context '#rescue' do
|
73
|
-
|
74
|
-
it 'raises an exception if no block given' do
|
75
|
-
lambda {
|
76
|
-
Defer.new{ nil }.rescue
|
77
|
-
}.should raise_error(ArgumentError)
|
78
|
-
end
|
79
|
-
|
80
|
-
it 'raises an exception if called twice' do
|
81
|
-
lambda {
|
82
|
-
Defer.new{ nil }.rescue{ nil }.rescue{ nil }
|
83
|
-
}.should raise_error(IllegalMethodCallError)
|
84
|
-
end
|
85
|
-
|
86
|
-
it 'raises an exception if an operation was provided at construction' do
|
87
|
-
lambda {
|
88
|
-
operation = proc{ nil }
|
89
|
-
Defer.new(op: operation).rescue{|ex| nil }
|
90
|
-
}.should raise_error(IllegalMethodCallError)
|
91
|
-
end
|
92
|
-
|
93
|
-
it 'raises an exception if an errorback was provided at construction' do
|
94
|
-
lambda {
|
95
|
-
errorback = proc{|ex| nil }
|
96
|
-
Defer.new(errorback: errorback){ nil }.rescue{|ex| nil }
|
97
|
-
}.should raise_error(IllegalMethodCallError)
|
98
|
-
end
|
99
|
-
|
100
|
-
it 'returns self' do
|
101
|
-
deferred = Defer.new{ nil }
|
102
|
-
deferred.rescue{|ex| nil }.should eq deferred
|
103
|
-
end
|
104
|
-
|
105
|
-
it 'aliases #catch' do
|
106
|
-
lambda {
|
107
|
-
Defer.new{ nil }.catch{|ex| nil }
|
108
|
-
}.should_not raise_error
|
109
|
-
end
|
110
|
-
|
111
|
-
it 'aliases #on_error' do
|
112
|
-
lambda {
|
113
|
-
Defer.new{ nil }.on_error{|ex| nil }
|
114
|
-
}.should_not raise_error
|
115
|
-
end
|
116
|
-
end
|
117
|
-
|
118
|
-
context '#go' do
|
119
|
-
|
120
|
-
it 'starts the thread if not started' do
|
121
|
-
deferred = Defer.new{ nil }
|
122
|
-
Defer.thread_pool.should_receive(:post).once.with(any_args())
|
123
|
-
deferred.go
|
124
|
-
end
|
125
|
-
|
126
|
-
it 'does nothing if called more than once' do
|
127
|
-
deferred = Defer.new{ nil }
|
128
|
-
deferred.go
|
129
|
-
Defer.thread_pool.should_not_receive(:post)
|
130
|
-
deferred.go
|
131
|
-
end
|
132
|
-
|
133
|
-
it 'does nothing if thread started at construction' do
|
134
|
-
operation = proc{ nil }
|
135
|
-
callback = proc{|result| nil }
|
136
|
-
errorback = proc{|ex| nil }
|
137
|
-
deferred = Defer.new(op: operation, callback: callback, errorback: errorback)
|
138
|
-
Defer.thread_pool.should_not_receive(:post)
|
139
|
-
deferred.go
|
140
|
-
end
|
141
|
-
end
|
142
|
-
|
143
|
-
context 'fulfillment' do
|
144
|
-
|
145
|
-
it 'runs the operation' do
|
146
|
-
@expected = false
|
147
|
-
Defer.new{ @expected = true }.go
|
148
|
-
sleep(0.1)
|
149
|
-
@expected.should be_true
|
150
|
-
end
|
151
|
-
|
152
|
-
it 'calls the callback when the operation is successful' do
|
153
|
-
@expected = false
|
154
|
-
Defer.new{ true }.then{|result| @expected = true }.go
|
155
|
-
sleep(0.1)
|
156
|
-
@expected.should be_true
|
157
|
-
end
|
158
|
-
|
159
|
-
it 'passes the result of the block to the callback' do
|
160
|
-
@expected = false
|
161
|
-
Defer.new{ 'w00t' }.then{|result| @expected = result }.go
|
162
|
-
sleep(0.1)
|
163
|
-
@expected.should eq 'w00t'
|
164
|
-
end
|
165
|
-
|
166
|
-
it 'does not call the errorback when the operation is successful' do
|
167
|
-
@expected = true
|
168
|
-
Defer.new{ nil }.rescue{|ex| @expected = false }.go
|
169
|
-
sleep(0.1)
|
170
|
-
@expected.should be_true
|
171
|
-
end
|
172
|
-
|
173
|
-
it 'calls the errorback if the operation throws an exception' do
|
174
|
-
@expected = false
|
175
|
-
Defer.new{ raise StandardError }.rescue{|ex| @expected = true }.go
|
176
|
-
sleep(0.1)
|
177
|
-
@expected.should be_true
|
178
|
-
end
|
179
|
-
|
180
|
-
it 'passes the exception object to the errorback' do
|
181
|
-
@expected = nil
|
182
|
-
Defer.new{ raise StandardError }.rescue{|ex| @expected = ex }.go
|
183
|
-
sleep(0.1)
|
184
|
-
@expected.should be_a(StandardError)
|
185
|
-
end
|
186
|
-
|
187
|
-
it 'does not call the callback when the operation fails' do
|
188
|
-
@expected = true
|
189
|
-
Defer.new{ raise StandardError }.then{|result| @expected = false }.go
|
190
|
-
sleep(0.1)
|
191
|
-
@expected.should be_true
|
192
|
-
end
|
193
|
-
end
|
194
|
-
end
|
195
|
-
end
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Concurrent
|
4
|
+
|
5
|
+
describe Defer do
|
6
|
+
|
7
|
+
before(:each) do
|
8
|
+
Defer.thread_pool = FixedThreadPool.new(1)
|
9
|
+
end
|
10
|
+
|
11
|
+
context '#initialize' do
|
12
|
+
|
13
|
+
it 'raises an exception if no block or operation given' do
|
14
|
+
lambda {
|
15
|
+
Defer.new
|
16
|
+
}.should raise_error(ArgumentError)
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'raises an exception if both a block and an operation given' do
|
20
|
+
lambda {
|
21
|
+
operation = proc{ nil }
|
22
|
+
Defer.new(op: operation){ nil }
|
23
|
+
}.should raise_error(ArgumentError)
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'starts the thread if an operation is given' do
|
27
|
+
Defer.thread_pool.should_receive(:post).once.with(any_args())
|
28
|
+
operation = proc{ nil }
|
29
|
+
Defer.new(op: operation)
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'does not start the thread if neither a callback or errorback is given' do
|
33
|
+
Defer.thread_pool.should_not_receive(:post)
|
34
|
+
Defer.new{ nil }
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
context '#then' do
|
39
|
+
|
40
|
+
it 'raises an exception if no block given' do
|
41
|
+
lambda {
|
42
|
+
Defer.new{ nil }.then
|
43
|
+
}.should raise_error(ArgumentError)
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'raises an exception if called twice' do
|
47
|
+
lambda {
|
48
|
+
Defer.new{ nil }.then{|result| nil }.then{|result| nil }
|
49
|
+
}.should raise_error(IllegalMethodCallError)
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'raises an exception if an operation was provided at construction' do
|
53
|
+
lambda {
|
54
|
+
operation = proc{ nil }
|
55
|
+
Defer.new(op: operation).then{|result| nil }
|
56
|
+
}.should raise_error(IllegalMethodCallError)
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'raises an exception if a callback was provided at construction' do
|
60
|
+
lambda {
|
61
|
+
callback = proc{|result|nil }
|
62
|
+
Defer.new(callback: callback){ nil }.then{|result| nil }
|
63
|
+
}.should raise_error(IllegalMethodCallError)
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'returns self' do
|
67
|
+
deferred = Defer.new{ nil }
|
68
|
+
deferred.then{|result| nil }.should eq deferred
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
context '#rescue' do
|
73
|
+
|
74
|
+
it 'raises an exception if no block given' do
|
75
|
+
lambda {
|
76
|
+
Defer.new{ nil }.rescue
|
77
|
+
}.should raise_error(ArgumentError)
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'raises an exception if called twice' do
|
81
|
+
lambda {
|
82
|
+
Defer.new{ nil }.rescue{ nil }.rescue{ nil }
|
83
|
+
}.should raise_error(IllegalMethodCallError)
|
84
|
+
end
|
85
|
+
|
86
|
+
it 'raises an exception if an operation was provided at construction' do
|
87
|
+
lambda {
|
88
|
+
operation = proc{ nil }
|
89
|
+
Defer.new(op: operation).rescue{|ex| nil }
|
90
|
+
}.should raise_error(IllegalMethodCallError)
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'raises an exception if an errorback was provided at construction' do
|
94
|
+
lambda {
|
95
|
+
errorback = proc{|ex| nil }
|
96
|
+
Defer.new(errorback: errorback){ nil }.rescue{|ex| nil }
|
97
|
+
}.should raise_error(IllegalMethodCallError)
|
98
|
+
end
|
99
|
+
|
100
|
+
it 'returns self' do
|
101
|
+
deferred = Defer.new{ nil }
|
102
|
+
deferred.rescue{|ex| nil }.should eq deferred
|
103
|
+
end
|
104
|
+
|
105
|
+
it 'aliases #catch' do
|
106
|
+
lambda {
|
107
|
+
Defer.new{ nil }.catch{|ex| nil }
|
108
|
+
}.should_not raise_error
|
109
|
+
end
|
110
|
+
|
111
|
+
it 'aliases #on_error' do
|
112
|
+
lambda {
|
113
|
+
Defer.new{ nil }.on_error{|ex| nil }
|
114
|
+
}.should_not raise_error
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
context '#go' do
|
119
|
+
|
120
|
+
it 'starts the thread if not started' do
|
121
|
+
deferred = Defer.new{ nil }
|
122
|
+
Defer.thread_pool.should_receive(:post).once.with(any_args())
|
123
|
+
deferred.go
|
124
|
+
end
|
125
|
+
|
126
|
+
it 'does nothing if called more than once' do
|
127
|
+
deferred = Defer.new{ nil }
|
128
|
+
deferred.go
|
129
|
+
Defer.thread_pool.should_not_receive(:post)
|
130
|
+
deferred.go
|
131
|
+
end
|
132
|
+
|
133
|
+
it 'does nothing if thread started at construction' do
|
134
|
+
operation = proc{ nil }
|
135
|
+
callback = proc{|result| nil }
|
136
|
+
errorback = proc{|ex| nil }
|
137
|
+
deferred = Defer.new(op: operation, callback: callback, errorback: errorback)
|
138
|
+
Defer.thread_pool.should_not_receive(:post)
|
139
|
+
deferred.go
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
context 'fulfillment' do
|
144
|
+
|
145
|
+
it 'runs the operation' do
|
146
|
+
@expected = false
|
147
|
+
Defer.new{ @expected = true }.go
|
148
|
+
sleep(0.1)
|
149
|
+
@expected.should be_true
|
150
|
+
end
|
151
|
+
|
152
|
+
it 'calls the callback when the operation is successful' do
|
153
|
+
@expected = false
|
154
|
+
Defer.new{ true }.then{|result| @expected = true }.go
|
155
|
+
sleep(0.1)
|
156
|
+
@expected.should be_true
|
157
|
+
end
|
158
|
+
|
159
|
+
it 'passes the result of the block to the callback' do
|
160
|
+
@expected = false
|
161
|
+
Defer.new{ 'w00t' }.then{|result| @expected = result }.go
|
162
|
+
sleep(0.1)
|
163
|
+
@expected.should eq 'w00t'
|
164
|
+
end
|
165
|
+
|
166
|
+
it 'does not call the errorback when the operation is successful' do
|
167
|
+
@expected = true
|
168
|
+
Defer.new{ nil }.rescue{|ex| @expected = false }.go
|
169
|
+
sleep(0.1)
|
170
|
+
@expected.should be_true
|
171
|
+
end
|
172
|
+
|
173
|
+
it 'calls the errorback if the operation throws an exception' do
|
174
|
+
@expected = false
|
175
|
+
Defer.new{ raise StandardError }.rescue{|ex| @expected = true }.go
|
176
|
+
sleep(0.1)
|
177
|
+
@expected.should be_true
|
178
|
+
end
|
179
|
+
|
180
|
+
it 'passes the exception object to the errorback' do
|
181
|
+
@expected = nil
|
182
|
+
Defer.new{ raise StandardError }.rescue{|ex| @expected = ex }.go
|
183
|
+
sleep(0.1)
|
184
|
+
@expected.should be_a(StandardError)
|
185
|
+
end
|
186
|
+
|
187
|
+
it 'does not call the callback when the operation fails' do
|
188
|
+
@expected = true
|
189
|
+
Defer.new{ raise StandardError }.then{|result| @expected = false }.go
|
190
|
+
sleep(0.1)
|
191
|
+
@expected.should be_true
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|