Permalink
Fetching contributors…
Cannot retrieve contributors at this time
195 lines (164 sloc) 5.4 KB
require 'minitest/autorun'
require 'rack/lint'
require 'rack/lock'
require 'rack/mock'
class Lock
attr_reader :synchronized
def initialize
@synchronized = false
end
def lock
@synchronized = true
end
def unlock
@synchronized = false
end
end
module LockHelpers
def lock_app(app, lock = Lock.new)
app = if lock
Rack::Lock.new app, lock
else
Rack::Lock.new app
end
Rack::Lint.new app
end
end
describe Rack::Lock do
include LockHelpers
describe 'Proxy' do
include LockHelpers
it 'delegate each' do
env = Rack::MockRequest.env_for("/")
response = Class.new {
attr_accessor :close_called
def initialize; @close_called = false; end
def each; %w{ hi mom }.each { |x| yield x }; end
}.new
app = lock_app(lambda { |inner_env| [200, {"Content-Type" => "text/plain"}, response] })
response = app.call(env)[2]
list = []
response.each { |x| list << x }
list.must_equal %w{ hi mom }
end
it 'delegate to_path' do
lock = Lock.new
env = Rack::MockRequest.env_for("/")
res = ['Hello World']
def res.to_path ; "/tmp/hello.txt" ; end
app = Rack::Lock.new(lambda { |inner_env| [200, {"Content-Type" => "text/plain"}, res] }, lock)
body = app.call(env)[2]
body.must_respond_to :to_path
body.to_path.must_equal "/tmp/hello.txt"
end
it 'not delegate to_path if body does not implement it' do
env = Rack::MockRequest.env_for("/")
res = ['Hello World']
app = lock_app(lambda { |inner_env| [200, {"Content-Type" => "text/plain"}, res] })
body = app.call(env)[2]
body.wont_respond_to :to_path
end
end
it 'call super on close' do
env = Rack::MockRequest.env_for("/")
response = Class.new {
attr_accessor :close_called
def initialize; @close_called = false; end
def close; @close_called = true; end
}.new
app = lock_app(lambda { |inner_env| [200, {"Content-Type" => "text/plain"}, response] })
app.call(env)
response.close_called.must_equal false
response.close
response.close_called.must_equal true
end
it "not unlock until body is closed" do
lock = Lock.new
env = Rack::MockRequest.env_for("/")
response = Object.new
app = lock_app(lambda { |inner_env| [200, {"Content-Type" => "text/plain"}, response] }, lock)
lock.synchronized.must_equal false
response = app.call(env)[2]
lock.synchronized.must_equal true
response.close
lock.synchronized.must_equal false
end
it "return value from app" do
env = Rack::MockRequest.env_for("/")
body = [200, {"Content-Type" => "text/plain"}, %w{ hi mom }]
app = lock_app(lambda { |inner_env| body })
res = app.call(env)
res[0].must_equal body[0]
res[1].must_equal body[1]
res[2].to_enum.to_a.must_equal ["hi", "mom"]
end
it "call synchronize on lock" do
lock = Lock.new
env = Rack::MockRequest.env_for("/")
app = lock_app(lambda { |inner_env| [200, {"Content-Type" => "text/plain"}, %w{ a b c }] }, lock)
lock.synchronized.must_equal false
app.call(env)
lock.synchronized.must_equal true
end
it "unlock if the app raises" do
lock = Lock.new
env = Rack::MockRequest.env_for("/")
app = lock_app(lambda { raise Exception }, lock)
lambda { app.call(env) }.must_raise Exception
lock.synchronized.must_equal false
end
it "unlock if the app throws" do
lock = Lock.new
env = Rack::MockRequest.env_for("/")
app = lock_app(lambda {|_| throw :bacon }, lock)
lambda { app.call(env) }.must_throw :bacon
lock.synchronized.must_equal false
end
it "set multithread flag to false" do
app = lock_app(lambda { |env|
env['rack.multithread'].must_equal false
[200, {"Content-Type" => "text/plain"}, %w{ a b c }]
}, false)
env = Rack::MockRequest.env_for("/")
env['rack.multithread'].must_equal true
app.call(env)
env['rack.multithread'].must_equal true
end
it "reset original multithread flag when exiting lock" do
app = Class.new(Rack::Lock) {
def call(env)
env['rack.multithread'].must_equal true
super
end
}.new(lambda { |env| [200, {"Content-Type" => "text/plain"}, %w{ a b c }] })
Rack::Lint.new(app).call(Rack::MockRequest.env_for("/"))
end
it 'not unlock if an error is raised before the mutex is locked' do
lock = Class.new do
def initialize() @unlocked = false end
def unlocked?() @unlocked end
def lock() raise Exception end
def unlock() @unlocked = true end
end.new
env = Rack::MockRequest.env_for("/")
app = lock_app(proc { [200, {"Content-Type" => "text/plain"}, []] }, lock)
lambda { app.call(env) }.must_raise Exception
lock.unlocked?.must_equal false
end
it "not reset the environment while the body is proxied" do
proxy = Class.new do
attr_reader :env
def initialize(env) @env = env end
end
app = Rack::Lock.new lambda { |env| [200, {"Content-Type" => "text/plain"}, proxy.new(env)] }
response = app.call(Rack::MockRequest.env_for("/"))[2]
response.env['rack.multithread'].must_equal false
end
it "unlock if an exception occurs before returning" do
lock = Lock.new
env = Rack::MockRequest.env_for("/")
app = lock_app(proc { [].freeze }, lock)
lambda { app.call(env) }.must_raise Exception
lock.synchronized.must_equal false
end
end