Skip to content

Commit 6f02d33

Browse files
committed
Improve test coverage.
1 parent 426c42e commit 6f02d33

File tree

17 files changed

+489
-137
lines changed

17 files changed

+489
-137
lines changed

lib/async/scheduler.rb

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -102,11 +102,7 @@ def raise(*arguments)
102102
end
103103

104104
def resume(fiber, *arguments)
105-
if Fiber.scheduler
106-
@selector.resume(fiber, *arguments)
107-
else
108-
@selector.push(fiber)
109-
end
105+
@selector.resume(fiber, *arguments)
110106
end
111107

112108
# Invoked when a fiber tries to perform a blocking operation which cannot continue. A corresponding call {unblock} must be performed to allow this fiber to continue.

lib/async/task.rb

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -163,15 +163,15 @@ def stop(later = false)
163163
if self.running?
164164
if self.current?
165165
if later
166-
Fiber.scheduler.push Stop::Later.new(self)
166+
Fiber.scheduler.push(Stop::Later.new(self))
167167
else
168168
raise Stop, "Stopping current task!"
169169
end
170170
elsif @fiber&.alive?
171171
begin
172172
Fiber.scheduler.raise(@fiber, Stop)
173173
rescue FiberError
174-
Fiber.scheduler.push Stop::Later.new(self)
174+
Fiber.scheduler.push(Stop::Later.new(self))
175175
end
176176
end
177177
else
@@ -206,17 +206,13 @@ def running?
206206
# Whether we can remove this node from the reactor graph.
207207
# @returns [Boolean]
208208
def finished?
209-
super && @status != :running
209+
super && @fiber.nil?
210210
end
211211

212212
def failed?
213213
@status == :failed
214214
end
215215

216-
def stopping?
217-
@status == :stopping
218-
end
219-
220216
def stopped?
221217
@status == :stopped
222218
end

spec/async/clock_spec.rb

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,27 @@
4545
expect(subject.total).to be_within(0.02 * Q).of(0.2)
4646
end
4747

48-
context 'with given total' do
49-
subject {described_class.new(1.5)}
48+
describe '#total' do
49+
context 'with initial duration' do
50+
let(:clock) {described_class.new(1.5)}
51+
subject(:total) {clock.total}
52+
53+
it{is_expected.to be == 1.5}
54+
end
55+
56+
it "can accumulate time" do
57+
subject.start!
58+
total = subject.total
59+
expect(total).to be >= 0
60+
sleep(0.0001)
61+
expect(subject.total).to be >= total
62+
end
63+
end
64+
65+
describe '.start' do
66+
let(:clock) {described_class.start}
67+
subject(:total) {clock.total}
5068

51-
it{is_expected.to have_attributes(total: 1.5)}
69+
it {is_expected.to be >= 0.0}
5270
end
5371
end

spec/async/node_spec.rb

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,29 @@
2222

2323
require 'async/node'
2424

25-
RSpec.describe Async::Node do
25+
RSpec.describe Async::Children do
26+
context "with no children" do
27+
describe '#nil?' do
28+
it {is_expected.to be_nil}
29+
end
30+
31+
describe '#empty?' do
32+
it {is_expected.to be_empty}
33+
end
34+
35+
describe '#transients?' do
36+
it {is_expected.to_not be_transients}
37+
end
38+
end
39+
end
40+
41+
RSpec.describe Async::Node do
42+
describe '#children?' do
43+
context "with no children" do
44+
it {is_expected.to_not be_children}
45+
end
46+
end
47+
2648
describe '#parent=' do
2749
let(:child) {Async::Node.new(subject)}
2850

@@ -44,6 +66,14 @@
4466
expect(child.parent).to be_nil
4567
expect(subject.children).to be_nil
4668
end
69+
70+
it "can move a child from one parent to another" do
71+
another_parent = Async::Node.new
72+
child.parent = another_parent
73+
74+
expect(subject.children).to be_empty
75+
expect(child.parent).to be == another_parent
76+
end
4777
end
4878

4979
describe '#print_hierarchy' do
@@ -152,6 +182,20 @@
152182
expect(subject.children.size).to be == 2
153183
expect(subject.children.each.to_a).to be == bottom
154184
end
185+
186+
it "deletes children that are also finished" do
187+
middle = Async::Node.new(subject)
188+
bottom = Async::Node.new(middle)
189+
190+
allow(middle).to receive(:finished?).and_return(true)
191+
allow(bottom).to receive(:finished?).and_return(true)
192+
193+
middle.consume
194+
195+
expect(subject.children).to be_empty
196+
expect(middle.children).to be_nil
197+
expect(bottom.parent).to be_nil
198+
end
155199
end
156200

157201
describe '#annotate' do

spec/async/queue_spec.rb

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,26 @@
2929
require_relative 'chainable_async_examples'
3030

3131
RSpec.shared_context Async::Queue do
32+
describe '#each' do
33+
it 'can enumerate queue items' do
34+
reactor.async do |task|
35+
10.times do |item|
36+
task.sleep(0.0001)
37+
subject.enqueue(item)
38+
end
39+
40+
subject.enqueue(nil)
41+
end
42+
43+
items = []
44+
subject.each do |item|
45+
items << item
46+
end
47+
48+
expect(items).to be == 10.times.to_a
49+
end
50+
end
51+
3252
it 'should process items in order' do
3353
reactor.async do |task|
3454
10.times do |i|

spec/async/reactor_spec.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,8 @@
113113

114114
child.stop
115115
end
116+
117+
subject.run
116118
end
117119
end
118120

spec/async/scheduler_spec.rb

Lines changed: 11 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -18,19 +18,12 @@
1818
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
1919
# THE SOFTWARE.
2020

21+
require 'async/rspec'
2122
require 'async/reactor'
2223
require 'async/barrier'
2324
require 'net/http'
2425

25-
RSpec.describe Async::Scheduler do
26-
include_context Async::RSpec::Reactor
27-
28-
it "can intercept sleep" do
29-
expect(reactor).to receive(:kernel_sleep).with(0.001)
30-
31-
sleep(0.001)
32-
end
33-
26+
RSpec.describe Async::Scheduler do
3427
describe 'Fiber.schedule' do
3528
it "can start child task" do
3629
fiber = nil
@@ -44,115 +37,23 @@
4437
expect(fiber).to_not be_nil
4538
expect(fiber).to be_kind_of(Fiber)
4639
end
47-
end
48-
49-
describe 'Process.wait' do
50-
it "can wait on child process" do
51-
expect(reactor).to receive(:process_wait).and_call_original
52-
53-
pid = ::Process.spawn("true")
54-
_, status = Process.wait2(pid)
55-
expect(status).to be_success
56-
end
57-
end
58-
59-
describe 'Kernel#system' do
60-
it "can execute child process" do
61-
# expect(reactor).to receive(:process_wait).and_call_original
62-
63-
::Kernel.system("true")
64-
expect($?).to be_success
65-
end
66-
end
67-
68-
describe 'Kernel#`' do
69-
it "can execute child process and capture output" do
70-
expect(`echo OK`).to be == "OK\n"
71-
expect($?).to be_success
72-
end
73-
74-
it "can execute child process with delay and capture output" do
75-
expect(`sleep 1; echo OK`).to be == "OK\n"
76-
expect($?).to be_success
77-
end
78-
end
79-
80-
describe 'IO.pipe' do
81-
let(:message) {"Helloooooo World!"}
8240

83-
it "can send message via pipe" do
84-
input, output = IO.pipe
41+
it "can schedule task before starting scheduler" do
42+
sequence = []
8543

86-
reactor.async do
87-
sleep(0.001)
44+
thread = Thread.new do
45+
scheduler = Async::Scheduler.new
8846

89-
message.each_char do |character|
90-
output.write(character)
47+
scheduler.async do
48+
sequence << :running
9149
end
9250

93-
output.close
51+
Fiber.set_scheduler(scheduler)
9452
end
9553

96-
expect(input.read).to be == message
97-
98-
ensure
99-
input.close
100-
output.close
101-
end
102-
103-
it "can fetch website using Net::HTTP" do
104-
barrier = Async::Barrier.new
105-
events = []
106-
107-
3.times do |i|
108-
barrier.async do
109-
events << i
110-
response = Net::HTTP.get(URI "https://www.codeotaku.com/index")
111-
expect(response).to_not be_nil
112-
events << i
113-
end
114-
end
115-
116-
barrier.wait
117-
118-
# The requests all get started concurrently:
119-
expect(events.first(3)).to be == [0, 1, 2]
120-
end
121-
end
122-
123-
context "with thread" do
124-
it "can join thread" do
125-
queue = Thread::Queue.new
126-
thread = Thread.new{queue.pop}
127-
128-
waiting = 0
129-
130-
3.times do
131-
Async do
132-
waiting += 1
133-
thread.join
134-
waiting -= 1
135-
end
136-
end
137-
138-
expect(waiting).to be == 3
139-
queue.close
140-
end
141-
end
142-
143-
context "with queue" do
144-
subject {::Thread::Queue.new}
145-
let(:item) {"Hello World"}
146-
147-
it "can pass items between thread and fiber" do
148-
Async do
149-
expect(subject.pop).to be == item
150-
end
54+
thread.join
15155

152-
::Thread.new do
153-
expect(Fiber).to be_blocking
154-
subject.push(item)
155-
end.join
56+
expect(sequence).to be == [:running]
15657
end
15758
end
15859
end

0 commit comments

Comments
 (0)