forked from rails/rails
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Publish AS::Executor and AS::Reloader APIs
These should allow external code to run blocks of user code to do "work", at a similar unit size to a web request, without needing to get intimate with ActionDipatch.
- Loading branch information
Showing
33 changed files
with
782 additions
and
307 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
require 'rack/body_proxy' | ||
|
||
module ActionDispatch | ||
class Executor | ||
def initialize(app, executor) | ||
@app, @executor = app, executor | ||
end | ||
|
||
def call(env) | ||
state = @executor.run! | ||
begin | ||
response = @app.call(env) | ||
returned = response << ::Rack::BodyProxy.new(response.pop) { state.complete! } | ||
ensure | ||
state.complete! unless returned | ||
end | ||
end | ||
end | ||
end |
21 changes: 0 additions & 21 deletions
21
actionpack/lib/action_dispatch/middleware/load_interlock.rb
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
require 'abstract_unit' | ||
|
||
class ExecutorTest < ActiveSupport::TestCase | ||
class MyBody < Array | ||
def initialize(&block) | ||
@on_close = block | ||
end | ||
|
||
def foo | ||
"foo" | ||
end | ||
|
||
def bar | ||
"bar" | ||
end | ||
|
||
def close | ||
@on_close.call if @on_close | ||
end | ||
end | ||
|
||
def test_returned_body_object_always_responds_to_close | ||
body = call_and_return_body | ||
assert_respond_to body, :close | ||
end | ||
|
||
def test_returned_body_object_always_responds_to_close_even_if_called_twice | ||
body = call_and_return_body | ||
assert_respond_to body, :close | ||
body.close | ||
|
||
body = call_and_return_body | ||
assert_respond_to body, :close | ||
body.close | ||
end | ||
|
||
def test_returned_body_object_behaves_like_underlying_object | ||
body = call_and_return_body do | ||
b = MyBody.new | ||
b << "hello" | ||
b << "world" | ||
[200, { "Content-Type" => "text/html" }, b] | ||
end | ||
assert_equal 2, body.size | ||
assert_equal "hello", body[0] | ||
assert_equal "world", body[1] | ||
assert_equal "foo", body.foo | ||
assert_equal "bar", body.bar | ||
end | ||
|
||
def test_it_calls_close_on_underlying_object_when_close_is_called_on_body | ||
close_called = false | ||
body = call_and_return_body do | ||
b = MyBody.new do | ||
close_called = true | ||
end | ||
[200, { "Content-Type" => "text/html" }, b] | ||
end | ||
body.close | ||
assert close_called | ||
end | ||
|
||
def test_returned_body_object_responds_to_all_methods_supported_by_underlying_object | ||
body = call_and_return_body do | ||
[200, { "Content-Type" => "text/html" }, MyBody.new] | ||
end | ||
assert_respond_to body, :size | ||
assert_respond_to body, :each | ||
assert_respond_to body, :foo | ||
assert_respond_to body, :bar | ||
end | ||
|
||
def test_run_callbacks_are_called_before_close | ||
running = false | ||
executor.to_run { running = true } | ||
|
||
body = call_and_return_body | ||
assert running | ||
|
||
running = false | ||
body.close | ||
assert !running | ||
end | ||
|
||
def test_complete_callbacks_are_called_on_close | ||
completed = false | ||
executor.to_complete { completed = true } | ||
|
||
body = call_and_return_body | ||
assert !completed | ||
|
||
body.close | ||
assert completed | ||
end | ||
|
||
def test_complete_callbacks_are_called_on_exceptions | ||
completed = false | ||
executor.to_complete { completed = true } | ||
|
||
begin | ||
call_and_return_body do | ||
raise "error" | ||
end | ||
rescue | ||
end | ||
|
||
assert completed | ||
end | ||
|
||
def test_callbacks_execute_in_shared_context | ||
result = false | ||
executor.to_run { @in_shared_context = true } | ||
executor.to_complete { result = @in_shared_context } | ||
|
||
call_and_return_body.close | ||
assert result | ||
assert !defined?(@in_shared_context) # it's not in the test itself | ||
end | ||
|
||
private | ||
def call_and_return_body(&block) | ||
app = middleware(block || proc { [200, {}, 'response'] }) | ||
_, _, body = app.call({'rack.input' => StringIO.new('')}) | ||
body | ||
end | ||
|
||
def middleware(inner_app) | ||
ActionDispatch::Executor.new(inner_app, executor) | ||
end | ||
|
||
def executor | ||
@executor ||= Class.new(ActiveSupport::Executor) | ||
end | ||
end |
Oops, something went wrong.