spec_builder.rb 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. require 'rack/builder'
  2. require 'rack/lint'
  3. require 'rack/mock'
  4. require 'rack/showexceptions'
  5. require 'rack/urlmap'
  6. class NothingMiddleware
  7. def initialize(app)
  8. @app = app
  9. end
  10. def call(env)
  11. @@env = env
  12. response = @app.call(env)
  13. response
  14. end
  15. def self.env
  16. @@env
  17. end
  18. end
  19. describe Rack::Builder do
  20. def builder(&block)
  21. Rack::Lint.new Rack::Builder.new(&block)
  22. end
  23. def builder_to_app(&block)
  24. Rack::Lint.new Rack::Builder.new(&block).to_app
  25. end
  26. it "supports mapping" do
  27. app = builder_to_app do
  28. map '/' do |outer_env|
  29. run lambda { |inner_env| [200, {"Content-Type" => "text/plain"}, ['root']] }
  30. end
  31. map '/sub' do
  32. run lambda { |inner_env| [200, {"Content-Type" => "text/plain"}, ['sub']] }
  33. end
  34. end
  35. Rack::MockRequest.new(app).get("/").body.to_s.should.equal 'root'
  36. Rack::MockRequest.new(app).get("/sub").body.to_s.should.equal 'sub'
  37. end
  38. it "doesn't dupe env even when mapping" do
  39. app = builder_to_app do
  40. use NothingMiddleware
  41. map '/' do |outer_env|
  42. run lambda { |inner_env|
  43. inner_env['new_key'] = 'new_value'
  44. [200, {"Content-Type" => "text/plain"}, ['root']]
  45. }
  46. end
  47. end
  48. Rack::MockRequest.new(app).get("/").body.to_s.should.equal 'root'
  49. NothingMiddleware.env['new_key'].should.equal 'new_value'
  50. end
  51. it "chains apps by default" do
  52. app = builder_to_app do
  53. use Rack::ShowExceptions
  54. run lambda { |env| raise "bzzzt" }
  55. end
  56. Rack::MockRequest.new(app).get("/").should.be.server_error
  57. Rack::MockRequest.new(app).get("/").should.be.server_error
  58. Rack::MockRequest.new(app).get("/").should.be.server_error
  59. end
  60. it "has implicit #to_app" do
  61. app = builder do
  62. use Rack::ShowExceptions
  63. run lambda { |env| raise "bzzzt" }
  64. end
  65. Rack::MockRequest.new(app).get("/").should.be.server_error
  66. Rack::MockRequest.new(app).get("/").should.be.server_error
  67. Rack::MockRequest.new(app).get("/").should.be.server_error
  68. end
  69. it "supports blocks on use" do
  70. app = builder do
  71. use Rack::ShowExceptions
  72. use Rack::Auth::Basic do |username, password|
  73. 'secret' == password
  74. end
  75. run lambda { |env| [200, {"Content-Type" => "text/plain"}, ['Hi Boss']] }
  76. end
  77. response = Rack::MockRequest.new(app).get("/")
  78. response.should.be.client_error
  79. response.status.should.equal 401
  80. # with auth...
  81. response = Rack::MockRequest.new(app).get("/",
  82. 'HTTP_AUTHORIZATION' => 'Basic ' + ["joe:secret"].pack("m*"))
  83. response.status.should.equal 200
  84. response.body.to_s.should.equal 'Hi Boss'
  85. end
  86. it "has explicit #to_app" do
  87. app = builder do
  88. use Rack::ShowExceptions
  89. run lambda { |env| raise "bzzzt" }
  90. end
  91. Rack::MockRequest.new(app).get("/").should.be.server_error
  92. Rack::MockRequest.new(app).get("/").should.be.server_error
  93. Rack::MockRequest.new(app).get("/").should.be.server_error
  94. end
  95. it "can mix map and run for endpoints" do
  96. app = builder do
  97. map '/sub' do
  98. run lambda { |inner_env| [200, {"Content-Type" => "text/plain"}, ['sub']] }
  99. end
  100. run lambda { |inner_env| [200, {"Content-Type" => "text/plain"}, ['root']] }
  101. end
  102. Rack::MockRequest.new(app).get("/").body.to_s.should.equal 'root'
  103. Rack::MockRequest.new(app).get("/sub").body.to_s.should.equal 'sub'
  104. end
  105. it "accepts middleware-only map blocks" do
  106. app = builder do
  107. map('/foo') { use Rack::ShowExceptions }
  108. run lambda { |env| raise "bzzzt" }
  109. end
  110. proc { Rack::MockRequest.new(app).get("/") }.should.raise(RuntimeError)
  111. Rack::MockRequest.new(app).get("/foo").should.be.server_error
  112. end
  113. should "initialize apps once" do
  114. app = builder do
  115. class AppClass
  116. def initialize
  117. @called = 0
  118. end
  119. def call(env)
  120. raise "bzzzt" if @called > 0
  121. @called += 1
  122. [200, {'Content-Type' => 'text/plain'}, ['OK']]
  123. end
  124. end
  125. use Rack::ShowExceptions
  126. run AppClass.new
  127. end
  128. Rack::MockRequest.new(app).get("/").status.should.equal 200
  129. Rack::MockRequest.new(app).get("/").should.be.server_error
  130. end
  131. it "allows use after run" do
  132. app = builder do
  133. run lambda { |env| raise "bzzzt" }
  134. use Rack::ShowExceptions
  135. end
  136. Rack::MockRequest.new(app).get("/").should.be.server_error
  137. Rack::MockRequest.new(app).get("/").should.be.server_error
  138. Rack::MockRequest.new(app).get("/").should.be.server_error
  139. end
  140. it 'complains about a missing run' do
  141. proc do
  142. Rack::Lint.new Rack::Builder.app { use Rack::ShowExceptions }
  143. end.should.raise(RuntimeError)
  144. end
  145. describe "parse_file" do
  146. def config_file(name)
  147. File.join(File.dirname(__FILE__), 'builder', name)
  148. end
  149. it "parses commented options" do
  150. app, options = Rack::Builder.parse_file config_file('options.ru')
  151. options[:debug].should.be.true
  152. Rack::MockRequest.new(app).get("/").body.to_s.should.equal 'OK'
  153. end
  154. it "removes __END__ before evaluating app" do
  155. app, options = Rack::Builder.parse_file config_file('end.ru')
  156. options = nil # ignored, prevents warning
  157. Rack::MockRequest.new(app).get("/").body.to_s.should.equal 'OK'
  158. end
  159. it "supports multi-line comments" do
  160. lambda {
  161. Rack::Builder.parse_file config_file('comment.ru')
  162. }.should.not.raise(SyntaxError)
  163. end
  164. it "requires anything not ending in .ru" do
  165. $: << File.dirname(__FILE__)
  166. app, options = Rack::Builder.parse_file 'builder/anything'
  167. Rack::MockRequest.new(app).get("/").body.to_s.should.equal 'OK'
  168. $:.pop
  169. end
  170. end
  171. end