From a56d14b0bf7ec992777811e3907edde1a50e87b4 Mon Sep 17 00:00:00 2001 From: Samuel Williams Date: Sat, 12 Jul 2025 12:16:51 +1200 Subject: [PATCH 1/6] Verbose output. --- .github/workflows/test-coverage.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-coverage.yaml b/.github/workflows/test-coverage.yaml index f2a38c30..16a8bddd 100644 --- a/.github/workflows/test-coverage.yaml +++ b/.github/workflows/test-coverage.yaml @@ -57,7 +57,7 @@ jobs: - name: Run tests timeout-minutes: 5 - run: bundle exec bake test + run: bundle exec sus --verbose - uses: actions/upload-artifact@v4 with: From 9c875e9311d91081c839ac5d04ab347ef33cd6d3 Mon Sep 17 00:00:00 2001 From: Samuel Williams Date: Sat, 12 Jul 2025 15:40:50 +1200 Subject: [PATCH 2/6] Fix test race on `IO#write`. --- lib/async/task.rb | 2 +- test/async/limited_queue.rb | 13 ++++++------- test/async/task.rb | 38 ++++++++++++++++++++++--------------- 3 files changed, 30 insertions(+), 23 deletions(-) diff --git a/lib/async/task.rb b/lib/async/task.rb index 50f640a6..e366f972 100644 --- a/lib/async/task.rb +++ b/lib/async/task.rb @@ -136,7 +136,7 @@ def to_s # @deprecated Prefer {Kernel#sleep} except when compatibility with `stable-v1` is required. def sleep(duration = nil) - warn("`Async::Task#sleep` is deprecated, use `Kernel#sleep` instead.", uplevel: 1, category: :deprecated) if $VERBOSE + Kernel.warn("`Async::Task#sleep` is deprecated, use `Kernel#sleep` instead.", uplevel: 1, category: :deprecated) if $VERBOSE super end diff --git a/test/async/limited_queue.rb b/test/async/limited_queue.rb index f70cc5d2..1b0aa54b 100644 --- a/test/async/limited_queue.rb +++ b/test/async/limited_queue.rb @@ -87,17 +87,16 @@ def before with "#close" do it "signals tasks waiting to enqueue items when closed" do queue.enqueue(:item1) - + # This task will block as the queue is full: waiting_task = reactor.async do - queue.enqueue(:item2) + expect do + queue.enqueue(:item2) + end.to raise_exception(Async::Queue::ClosedError) end - + queue.close - - expect do - waiting_task.wait - end.to raise_exception(Async::Queue::ClosedError) + waiting_task.wait end end end diff --git a/test/async/task.rb b/test/async/task.rb index 2b4f2dbd..8d49e3b5 100644 --- a/test/async/task.rb +++ b/test/async/task.rb @@ -75,11 +75,13 @@ with "#current?" do it "can check if it is the currently running task" do + was_current = nil + task = reactor.async do |task| - expect(task).to be(:current?) - sleep(0.1) + was_current = task.current? end + expect(was_current).to be == true expect(task).not.to be(:current?) end end @@ -124,7 +126,8 @@ reactor.run do expect do reactor.async do |task| - expect(task).to receive(:warn).and_return(nil) + # Ensure the wait is executed before raising the exception: + task.yield raise "boom" end.wait @@ -154,19 +157,19 @@ it "can consume exceptions" do task = nil - expect do - task = reactor.async do |task| - expect(task).to receive(:warn).and_return(nil) - - raise "boom" - end - end.not.to raise_exception - reactor.run do expect do - task.wait - end.to raise_exception(RuntimeError, message: be =~ /boom/) + task = reactor.async do |task| + expect(task).to receive(:warn).and_return(nil) + + raise "boom" + end + end.not.to raise_exception end + + expect do + task.wait + end.to raise_exception(RuntimeError, message: be =~ /boom/) end it "won't consume non-StandardError exceptions" do @@ -508,6 +511,7 @@ it "can stop resumed task" do items = [1, 2, 3] + value = nil reactor.run do condition = Async::Condition.new @@ -520,11 +524,11 @@ end value = condition.wait # (2) value = Fiber.yield - expect(value).to be == 3 producer.stop # (5) [producer is resumed already] producer.stop end expect(items).to be == [1, 2] + expect(value).to be == 3 end it "can stop a child task with transient children" do @@ -720,7 +724,7 @@ def sleep_forever end innocent_task = reactor.async do |task| - expect{error_task.wait}.to raise_exception(RuntimeError, message: be =~ /boom/) + error_task.wait end expect do @@ -729,6 +733,10 @@ def sleep_forever expect(error_task).to be(:finished?) expect(innocent_task).to be(:finished?) + + expect do + innocent_task.wait + end.to raise_exception(RuntimeError, message: be =~ /boom/) end it "will not raise exception values returned by the task" do From 24ce6540d9144215b0f4915ec5a9e1665113e12d Mon Sep 17 00:00:00 2001 From: Samuel Williams Date: Sat, 12 Jul 2025 17:05:58 +1200 Subject: [PATCH 3/6] Fix race conditions due to `IO#write`. --- test/async/notification.rb | 2 -- test/io.rb | 8 ++++---- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/test/async/notification.rb b/test/async/notification.rb index cfbd2d36..18fcb8c6 100644 --- a/test/async/notification.rb +++ b/test/async/notification.rb @@ -31,7 +31,6 @@ expect(task.status).to be == :running - sequence << :yielding reactor.yield sequence << :finished @@ -41,7 +40,6 @@ :waiting, :running, :signalled, - :yielding, :resumed, :finished ] diff --git a/test/io.rb b/test/io.rb index 6c5a77ff..b58d509d 100644 --- a/test/io.rb +++ b/test/io.rb @@ -101,7 +101,7 @@ read_task = Async do expect do r.read(5) - end.to raise_exception(IOError, message: be =~ /stream closed/) + end.to raise_exception(IOError, message: be =~ /closed/) end r.close @@ -116,7 +116,7 @@ read_task = Async do expect do r.read(5) - end.to raise_exception(IOError, message: be =~ /stream closed/) + end.to raise_exception(IOError, message: be =~ /closed/) end close_task = Async do @@ -135,7 +135,7 @@ read_task = Async do expect do r.read(5) - end.to raise_exception(IOError, message: be =~ /stream closed/) + end.to raise_exception(IOError, message: be =~ /closed/) end close_thread = Thread.new do @@ -154,7 +154,7 @@ read_task = Async do expect do r.read(5) - end.to raise_exception(IOError, message: be =~ /stream closed/) + end.to raise_exception(IOError, message: be =~ /closed/) end close_thread = Thread.new do From 99878e0f855cc285540556b8afd9a049b818e3a8 Mon Sep 17 00:00:00 2001 From: Samuel Williams Date: Sat, 12 Jul 2025 17:17:47 +1200 Subject: [PATCH 4/6] Remove time component from barrier test. --- test/async/barrier.rb | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/test/async/barrier.rb b/test/async/barrier.rb index 79feda13..533453a6 100644 --- a/test/async/barrier.rb +++ b/test/async/barrier.rb @@ -18,29 +18,22 @@ with "#async" do let(:repeats) {40} - let(:delay) {0.01} it "should wait for all jobs to complete" do finished = 0 repeats.times.map do |i| barrier.async do |task| - sleep(delay) + task.yield finished += 1 - - # This task is a child task but not part of the barrier. - task.async do - sleep(delay*3) - end end end expect(barrier).not.to be(:empty?) - expect(finished).to be < repeats + expect(finished).to be <= repeats - duration = Async::Clock.measure{barrier.wait} + barrier.wait - expect(duration).to be_within(repeats * Sus::Fixtures::Time::QUANTUM).of(delay) expect(finished).to be == repeats expect(barrier).to be(:empty?) end From f5efbde602724f1add3f64af4f18d4ddcfa9daa8 Mon Sep 17 00:00:00 2001 From: Samuel Williams Date: Sat, 12 Jul 2025 23:00:42 +1200 Subject: [PATCH 5/6] Fix documentation coverage issues. --- lib/async/limited_queue.rb | 4 +--- lib/async/queue.rb | 1 + 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/async/limited_queue.rb b/lib/async/limited_queue.rb index 0c410ad5..a09c06c9 100644 --- a/lib/async/limited_queue.rb +++ b/lib/async/limited_queue.rb @@ -8,8 +8,6 @@ module Async class LimitedQueue < Queue - class << self - remove_method :new - end + singleton_class.remove_method(:new) end end diff --git a/lib/async/queue.rb b/lib/async/queue.rb index b1e3504e..35e6c6ec 100644 --- a/lib/async/queue.rb +++ b/lib/async/queue.rb @@ -133,6 +133,7 @@ def wait # A queue which limits the number of items that can be enqueued. # @public Since *Async v1*. class LimitedQueue < Queue + # @private This exists purely for emitting a warning. def self.new(...) warn("`require 'async/limited_queue'` to use `Async::LimitedQueue`.", uplevel: 1, category: :deprecated) if $VERBOSE From 9e21de56f67f9d19d31a5241f7df41f4351f80a1 Mon Sep 17 00:00:00 2001 From: Samuel Williams Date: Sun, 13 Jul 2025 22:06:56 +1200 Subject: [PATCH 6/6] Update dependency on `io-event`. --- async.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/async.gemspec b/async.gemspec index c60414bc..5244b433 100644 --- a/async.gemspec +++ b/async.gemspec @@ -27,7 +27,7 @@ Gem::Specification.new do |spec| spec.add_dependency "console", "~> 1.29" spec.add_dependency "fiber-annotation" - spec.add_dependency "io-event", "~> 1.11" + spec.add_dependency "io-event", "~> 1.12" spec.add_dependency "metrics", "~> 0.12" spec.add_dependency "traces", "~> 0.15" end