From 629156647b3e425d4792dcaec62740576e878ff9 Mon Sep 17 00:00:00 2001 From: Samuel Williams Date: Thu, 10 Sep 2026 18:28:59 +1200 Subject: [PATCH 1/3] Add adapter close lifecycle Assisted-By: devx/b8194217-b20a-4799-b266-4910beb3ee2b --- lib/protocol/rack/adapter/generic.rb | 5 +++++ test/protocol/rack/adapter.rb | 17 +++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/lib/protocol/rack/adapter/generic.rb b/lib/protocol/rack/adapter/generic.rb index 21e83b6..91dbd45 100644 --- a/lib/protocol/rack/adapter/generic.rb +++ b/lib/protocol/rack/adapter/generic.rb @@ -44,6 +44,11 @@ def initialize(app) raise ArgumentError, "App must be callable!" unless @app.respond_to?(:call) end + # Close the Rack application if it exposes an application lifecycle hook. + def close + @app.close if @app.respond_to?(:close) + end + # The logger to use for this adapter. # # @returns [Console] The console logger. diff --git a/test/protocol/rack/adapter.rb b/test/protocol/rack/adapter.rb index ad3e245..401fe6e 100644 --- a/test/protocol/rack/adapter.rb +++ b/test/protocol/rack/adapter.rb @@ -19,6 +19,23 @@ expect(subject.parse_file(rackup_path)).to be_a(Proc) end + with "#close" do + it "closes the Rack application when supported" do + closed = false + app = ->(env){[200, {}, []]} + app.define_singleton_method(:close) {closed = true} + + subject.new(app).close + expect(closed).to be == true + end + + it "does nothing when the Rack application has no close hook" do + app = ->(env){[200, {}, []]} + + expect(subject.new(app).close).to be_nil + end + end + with ".make_response" do let(:env) {Rack::MockRequest.env_for("/")} From ac6abcd2ce3dc2d1b90d679bd60876919a420143 Mon Sep 17 00:00:00 2001 From: Samuel Williams Date: Thu, 10 Sep 2026 18:31:52 +1200 Subject: [PATCH 2/3] Keep adapter close independent of Rack application Assisted-By: devx/b8194217-b20a-4799-b266-4910beb3ee2b --- lib/protocol/rack/adapter/generic.rb | 3 +-- test/protocol/rack/adapter.rb | 10 ++-------- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/lib/protocol/rack/adapter/generic.rb b/lib/protocol/rack/adapter/generic.rb index 91dbd45..ebf7aa9 100644 --- a/lib/protocol/rack/adapter/generic.rb +++ b/lib/protocol/rack/adapter/generic.rb @@ -44,9 +44,8 @@ def initialize(app) raise ArgumentError, "App must be callable!" unless @app.respond_to?(:call) end - # Close the Rack application if it exposes an application lifecycle hook. + # Rack does not define an application lifecycle hook, so there is nothing to close. def close - @app.close if @app.respond_to?(:close) end # The logger to use for this adapter. diff --git a/test/protocol/rack/adapter.rb b/test/protocol/rack/adapter.rb index 401fe6e..bde0406 100644 --- a/test/protocol/rack/adapter.rb +++ b/test/protocol/rack/adapter.rb @@ -20,19 +20,13 @@ end with "#close" do - it "closes the Rack application when supported" do + it "does not impose a lifecycle hook on the Rack application" do closed = false app = ->(env){[200, {}, []]} app.define_singleton_method(:close) {closed = true} - subject.new(app).close - expect(closed).to be == true - end - - it "does nothing when the Rack application has no close hook" do - app = ->(env){[200, {}, []]} - expect(subject.new(app).close).to be_nil + expect(closed).to be == false end end From bf326b55afe98cd8d103fc72a6cfee76540fd0ce Mon Sep 17 00:00:00 2001 From: Samuel Williams Date: Thu, 10 Sep 2026 18:32:27 +1200 Subject: [PATCH 3/3] Test adapter close contract Assisted-By: devx/b8194217-b20a-4799-b266-4910beb3ee2b --- test/protocol/rack/adapter.rb | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/test/protocol/rack/adapter.rb b/test/protocol/rack/adapter.rb index bde0406..4281e38 100644 --- a/test/protocol/rack/adapter.rb +++ b/test/protocol/rack/adapter.rb @@ -20,13 +20,12 @@ end with "#close" do - it "does not impose a lifecycle hook on the Rack application" do - closed = false + it "can be closed" do app = ->(env){[200, {}, []]} - app.define_singleton_method(:close) {closed = true} + adapter = subject.new(app) - expect(subject.new(app).close).to be_nil - expect(closed).to be == false + expect(adapter).to be(:respond_to?, :close) + expect(adapter.close).to be_nil end end