Skip to content

Commit e490705

Browse files
committed
Full specs for Async module (with a few pending.
1 parent a0cb3a9 commit e490705

File tree

2 files changed

+159
-14
lines changed

2 files changed

+159
-14
lines changed

lib/concurrent/async.rb

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ module Concurrent
4747
# when the object is used exclusively on a single thread. Use only
4848
# asynchronous calls when the object is shared between threads.
4949
#
50+
# @since 0.6.0
51+
#
5052
# @see Concurrent::Obligation
5153
#
5254
# @see http://msdn.microsoft.com/en-us/library/hh191443.aspx Asynchronous Programming with Async and Await (C# and Visual Basic)
@@ -111,7 +113,7 @@ def initialize(delegate, mutex)
111113
#
112114
# @return [IVar] the result of the method call
113115
#
114-
# @raise [NoMethodError] the object does not respond to +method+ method
116+
# @raise [NameError] the object does not respond to +method+ method
115117
# @raise [ArgumentError] the given +args+ do not match the arity of +method+
116118
def method_missing(method, *args, &block)
117119
super unless @delegate.respond_to?(method)
@@ -128,7 +130,7 @@ def method_missing(method, *args, &block)
128130
rescue => reason
129131
# caught
130132
ensure
131-
ivar.complete(reason.nil?, value, reason)
133+
return ivar.complete(reason.nil?, value, reason)
132134
end
133135
end
134136

@@ -163,7 +165,7 @@ def initialize(delegate, mutex)
163165
#
164166
# @return [IVar] the result of the method call
165167
#
166-
# @raise [NoMethodError] the object does not respond to +method+ method
168+
# @raise [NameError] the object does not respond to +method+ method
167169
# @raise [ArgumentError] the given +args+ do not match the arity of +method+
168170
def method_missing(method, *args, &block)
169171
super unless @delegate.respond_to?(method)
@@ -205,7 +207,7 @@ def method_missing(method, *args, &block)
205207
#
206208
# @return [Concurrent::Future] the pending result of the asynchronous operation
207209
#
208-
# @raise [NoMethodError] the object does not respond to +method+ method
210+
# @raise [NameError] the object does not respond to +method+ method
209211
# @raise [ArgumentError] the given +args+ do not match the arity of +method+
210212
#
211213
# @see Concurrent::Future
@@ -237,7 +239,7 @@ def async
237239
#
238240
# @return [Concurrent::IVar] the completed result of the synchronous operation
239241
#
240-
# @raise [NoMethodError] the object does not respond to +method+ method
242+
# @raise [NameError] the object does not respond to +method+ method
241243
# @raise [ArgumentError] the given +args+ do not match the arity of +method+
242244
#
243245
# @see Concurrent::IVar

spec/concurrent/async_spec.rb

Lines changed: 152 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,22 @@ module Concurrent
44

55
describe Async do
66

7-
described_class do
8-
Class.new do
7+
subject do
8+
Class.new {
99
include Concurrent::Async
1010
def echo(msg)
11-
sleep(rand)
1211
msg
1312
end
14-
end
13+
def gather(first, second = nil)
14+
return first, second
15+
end
16+
def boom(ex = StandardError.new)
17+
raise ex
18+
end
19+
def wait(seconds)
20+
sleep(seconds)
21+
end
22+
}.new
1523
end
1624

1725
context '#validate_argc' do
@@ -40,7 +48,7 @@ def many(*args, &block) nil; end
4048
it 'does not raise an exception for correct zero arity' do
4149
expect {
4250
Async::validate_argc(subject, :zero)
43-
}.to_not raise_error
51+
}.not_to raise_error
4452
end
4553

4654
it 'raises an exception for too many args on a method with positive arity' do
@@ -58,7 +66,7 @@ def many(*args, &block) nil; end
5866
it 'does not raise an exception for correct positive arity' do
5967
expect {
6068
Async::validate_argc(subject, :three, 1, 2, 3)
61-
}.to_not raise_error
69+
}.not_to raise_error
6270
end
6371

6472
it 'raises an exception for too few args on a method with negative arity' do
@@ -76,16 +84,151 @@ def many(*args, &block) nil; end
7684
Async::validate_argc(subject, :many)
7785
Async::validate_argc(subject, :many, 1, 2)
7886
Async::validate_argc(subject, :many, 1, 2, 3, 4)
79-
}.to_not raise_error
87+
}.not_to raise_error
8088
end
8189
end
8290

8391
context '#async' do
84-
pending
92+
93+
it 'raises an error when calling a method that does not exist' do
94+
expect {
95+
subject.async.bogus
96+
}.to raise_error(StandardError)
97+
end
98+
99+
it 'raises an error when passing too few arguments' do
100+
expect {
101+
subject.async.gather
102+
}.to raise_error(ArgumentError)
103+
end
104+
105+
it 'raises an error when pasing too many arguments (arity >= 0)' do
106+
expect {
107+
subject.async.echo(1, 2, 3, 4, 5)
108+
}.to raise_error(StandardError)
109+
end
110+
111+
it 'returns a :pending Future' do
112+
val = subject.async.wait(5)
113+
val.should be_a Concurrent::Future
114+
val.should be_pending
115+
end
116+
117+
it 'sets the value on success' do
118+
val = subject.async.echo(:foo)
119+
val.value.should eq :foo
120+
val.should be_fulfilled
121+
end
122+
123+
it 'sets the reason on failure' do
124+
ex = ArgumentError.new
125+
val = subject.async.boom(ex)
126+
sleep(0.1)
127+
val.reason.should eq ex
128+
val.should be_rejected
129+
end
130+
131+
it 'sets the reason when giving too many optional arguments' do
132+
val = subject.async.gather(1, 2, 3, 4, 5)
133+
sleep(0.1)
134+
val.reason.should be_a StandardError
135+
val.should be_rejected
136+
end
137+
138+
it 'defines the method after the first call' do
139+
pending('failing inconsistently')
140+
expect { subject.async.method(:echo) }.to raise_error(NameError)
141+
subject.async.echo(:foo)
142+
sleep(0.1)
143+
expect { subject.async.method(:echo) }.not_to raise_error
144+
end
145+
146+
it 'does not define the method on name/arity exception' do
147+
pending('failing inconsistently')
148+
expect { subject.async.method(:bogus) }.to raise_error(NameError)
149+
expect { subject.async.bogus }.to raise_error(NameError)
150+
expect { subject.async.method(:bogus) }.to raise_error(NameError)
151+
end
152+
153+
it 'uses the same mutex as #await' do
154+
subject.await.mutex.should eq subject.async.mutex
155+
end
156+
157+
it 'is aliased as #future' do
158+
val = subject.future.wait(5)
159+
val.should be_a Concurrent::Future
160+
val.should be_pending
161+
end
85162
end
86163

87164
context '#await' do
88-
pending
165+
166+
it 'raises an error when calling a method that does not exist' do
167+
expect {
168+
subject.await.bogus
169+
}.to raise_error(StandardError)
170+
end
171+
172+
it 'raises an error when passing too few arguments' do
173+
expect {
174+
subject.await.gather
175+
}.to raise_error(ArgumentError)
176+
end
177+
178+
it 'raises an error when pasing too many arguments (arity >= 0)' do
179+
expect {
180+
subject.await.echo(1, 2, 3, 4, 5)
181+
}.to raise_error(StandardError)
182+
end
183+
184+
it 'returns a :fulfilled IVar' do
185+
val = subject.await.echo(5)
186+
val.should be_a Concurrent::IVar
187+
val.should be_fulfilled
188+
end
189+
190+
it 'sets the value on success' do
191+
val = subject.await.echo(:foo)
192+
val.value.should eq :foo
193+
val.should be_fulfilled
194+
end
195+
196+
it 'sets the reason on failure' do
197+
ex = ArgumentError.new
198+
val = subject.await.boom(ex)
199+
val.reason.should eq ex
200+
val.should be_rejected
201+
end
202+
203+
it 'sets the reason when giving too many optional arguments' do
204+
val = subject.await.gather(1, 2, 3, 4, 5)
205+
val.reason.should be_a StandardError
206+
val.should be_rejected
207+
end
208+
209+
it 'defines the method after the first call' do
210+
pending('failing inconsistently')
211+
expect { subject.await.method(:echo) }.to raise_error(NameError)
212+
subject.await.echo(:foo)
213+
expect { subject.await.method(:echo) }.not_to raise_error
214+
end
215+
216+
it 'does not define the method on name/arity exception' do
217+
pending('failing inconsistently')
218+
expect { subject.await.method(:bogus) }.to raise_error(NameError)
219+
expect { subject.await.bogus }.to raise_error(NameError)
220+
expect { subject.await.method(:bogus) }.to raise_error(NameError)
221+
end
222+
223+
it 'uses the same mutex as #async' do
224+
subject.await.mutex.should eq subject.async.mutex
225+
end
226+
227+
it 'is aliased as #defer' do
228+
val = subject.defer.echo(5)
229+
val.should be_a Concurrent::IVar
230+
val.should be_fulfilled
231+
end
89232
end
90233
end
91234
end

0 commit comments

Comments
 (0)