aldebaran 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. data/.gitignore +13 -0
  2. data/.travis.yml +16 -0
  3. data/.yardopts +4 -0
  4. data/AUTHORS +4 -0
  5. data/Gemfile +77 -0
  6. data/KNOWN_ISSUES +5 -0
  7. data/LICENSE +22 -0
  8. data/README.rdoc +1900 -0
  9. data/Rakefile +175 -0
  10. data/aldebaran.gemspec +19 -0
  11. data/lib/aldebaran.rb +7 -0
  12. data/lib/aldebaran/base.rb +1600 -0
  13. data/lib/aldebaran/images/404.png +0 -0
  14. data/lib/aldebaran/images/500.png +0 -0
  15. data/lib/aldebaran/main.rb +28 -0
  16. data/lib/aldebaran/showexceptions.rb +340 -0
  17. data/lib/aldebaran/version.rb +3 -0
  18. data/test/aldebaran_test.rb +17 -0
  19. data/test/base_test.rb +160 -0
  20. data/test/builder_test.rb +95 -0
  21. data/test/coffee_test.rb +92 -0
  22. data/test/contest.rb +98 -0
  23. data/test/creole_test.rb +65 -0
  24. data/test/delegator_test.rb +162 -0
  25. data/test/encoding_test.rb +20 -0
  26. data/test/erb_test.rb +104 -0
  27. data/test/extensions_test.rb +100 -0
  28. data/test/filter_test.rb +397 -0
  29. data/test/haml_test.rb +101 -0
  30. data/test/helper.rb +115 -0
  31. data/test/helpers_test.rb +1192 -0
  32. data/test/less_test.rb +67 -0
  33. data/test/liquid_test.rb +59 -0
  34. data/test/mapped_error_test.rb +259 -0
  35. data/test/markaby_test.rb +80 -0
  36. data/test/markdown_test.rb +81 -0
  37. data/test/middleware_test.rb +68 -0
  38. data/test/nokogiri_test.rb +69 -0
  39. data/test/public/favicon.ico +0 -0
  40. data/test/radius_test.rb +59 -0
  41. data/test/rdoc_test.rb +65 -0
  42. data/test/readme_test.rb +136 -0
  43. data/test/request_test.rb +45 -0
  44. data/test/response_test.rb +61 -0
  45. data/test/result_test.rb +98 -0
  46. data/test/route_added_hook_test.rb +59 -0
  47. data/test/routing_test.rb +1096 -0
  48. data/test/sass_test.rb +115 -0
  49. data/test/scss_test.rb +88 -0
  50. data/test/server_test.rb +48 -0
  51. data/test/settings_test.rb +493 -0
  52. data/test/slim_test.rb +98 -0
  53. data/test/static_test.rb +178 -0
  54. data/test/streaming_test.rb +100 -0
  55. data/test/templates_test.rb +298 -0
  56. data/test/textile_test.rb +65 -0
  57. data/test/views/a/in_a.str +1 -0
  58. data/test/views/ascii.erb +2 -0
  59. data/test/views/b/in_b.str +1 -0
  60. data/test/views/calc.html.erb +1 -0
  61. data/test/views/error.builder +3 -0
  62. data/test/views/error.erb +3 -0
  63. data/test/views/error.haml +3 -0
  64. data/test/views/error.sass +2 -0
  65. data/test/views/explicitly_nested.str +1 -0
  66. data/test/views/foo/hello.test +1 -0
  67. data/test/views/hello.builder +1 -0
  68. data/test/views/hello.coffee +1 -0
  69. data/test/views/hello.creole +1 -0
  70. data/test/views/hello.erb +1 -0
  71. data/test/views/hello.haml +1 -0
  72. data/test/views/hello.less +5 -0
  73. data/test/views/hello.liquid +1 -0
  74. data/test/views/hello.mab +1 -0
  75. data/test/views/hello.md +1 -0
  76. data/test/views/hello.nokogiri +1 -0
  77. data/test/views/hello.radius +1 -0
  78. data/test/views/hello.rdoc +1 -0
  79. data/test/views/hello.sass +2 -0
  80. data/test/views/hello.scss +3 -0
  81. data/test/views/hello.slim +1 -0
  82. data/test/views/hello.str +1 -0
  83. data/test/views/hello.test +1 -0
  84. data/test/views/hello.textile +1 -0
  85. data/test/views/layout2.builder +3 -0
  86. data/test/views/layout2.erb +2 -0
  87. data/test/views/layout2.haml +2 -0
  88. data/test/views/layout2.liquid +2 -0
  89. data/test/views/layout2.mab +2 -0
  90. data/test/views/layout2.nokogiri +3 -0
  91. data/test/views/layout2.radius +2 -0
  92. data/test/views/layout2.slim +3 -0
  93. data/test/views/layout2.str +2 -0
  94. data/test/views/layout2.test +1 -0
  95. data/test/views/nested.str +1 -0
  96. data/test/views/utf8.erb +2 -0
  97. metadata +231 -0
@@ -0,0 +1,28 @@
1
+ require 'aldebaran/base'
2
+
3
+ module Aldebaran
4
+ class Application < Base
5
+
6
+ # we assume that the first file that requires 'aldebaran' is the
7
+ # app_file. all other path related options are calculated based
8
+ # on this path by default.
9
+ set :app_file, caller_files.first || $0
10
+
11
+ set :run, Proc.new { $0 == app_file }
12
+
13
+ if run? && ARGV.any?
14
+ require 'optparse'
15
+ OptionParser.new { |op|
16
+ op.on('-x') { set :lock, true }
17
+ op.on('-e env') { |val| set :environment, val.to_sym }
18
+ op.on('-s server') { |val| set :server, val }
19
+ op.on('-p port') { |val| set :port, Integer(val) }
20
+ op.on('-o addr') { |val| set :bind, val }
21
+ }.parse!(ARGV.dup)
22
+ end
23
+ end
24
+
25
+ at_exit { Application.run! if $!.nil? && Application.run? }
26
+ end
27
+
28
+ include Aldebaran::Delegator
@@ -0,0 +1,340 @@
1
+ require 'rack/showexceptions'
2
+
3
+ module Aldebaran
4
+ # Aldebaran::ShowExceptions catches all exceptions raised from the app it
5
+ # wraps. It shows a useful backtrace with the sourcefile and clickable
6
+ # context, the whole Rack environment and the request data.
7
+ #
8
+ # Be careful when you use this on public-facing sites as it could reveal
9
+ # information helpful to attackers.
10
+ class ShowExceptions < Rack::ShowExceptions
11
+ @@eats_errors = Object.new
12
+ def @@eats_errors.flush(*) end
13
+ def @@eats_errors.puts(*) end
14
+
15
+ def initialize(app)
16
+ @app = app
17
+ @template = ERB.new(TEMPLATE)
18
+ end
19
+
20
+ def call(env)
21
+ @app.call(env)
22
+ rescue Exception => e
23
+ errors, env["rack.errors"] = env["rack.errors"], @@eats_errors
24
+
25
+ if respond_to?(:prefers_plain_text?) and prefers_plain_text?(env)
26
+ content_type = "text/plain"
27
+ body = [dump_exception(e)]
28
+ else
29
+ content_type = "text/html"
30
+ body = pretty(env, e)
31
+ end
32
+
33
+ env["rack.errors"] = errors
34
+
35
+ [500,
36
+ {"Content-Type" => content_type,
37
+ "Content-Length" => Rack::Utils.bytesize(body.join).to_s},
38
+ body]
39
+ end
40
+
41
+ private
42
+
43
+ def frame_class(frame)
44
+ if frame.filename =~ /lib\/aldebaran.*\.rb/
45
+ "framework"
46
+ elsif (defined?(Gem) && frame.filename.include?(Gem.dir)) ||
47
+ frame.filename =~ /\/bin\/(\w+)$/
48
+ "system"
49
+ else
50
+ "app"
51
+ end
52
+ end
53
+
54
+ TEMPLATE = <<-HTML # :nodoc:
55
+ <!DOCTYPE html>
56
+ <html>
57
+ <head>
58
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
59
+ <title><%=h exception.class %> at <%=h path %></title>
60
+
61
+ <script type="text/javascript">
62
+ //<!--
63
+ function toggle(id) {
64
+ var pre = document.getElementById("pre-" + id);
65
+ var post = document.getElementById("post-" + id);
66
+ var context = document.getElementById("context-" + id);
67
+
68
+ if (pre.style.display == 'block') {
69
+ pre.style.display = 'none';
70
+ post.style.display = 'none';
71
+ context.style.background = "none";
72
+ } else {
73
+ pre.style.display = 'block';
74
+ post.style.display = 'block';
75
+ context.style.background = "#fffed9";
76
+ }
77
+ }
78
+
79
+ function toggleBacktrace(){
80
+ var bt = document.getElementById("backtrace");
81
+ var toggler = document.getElementById("expando");
82
+
83
+ if (bt.className == 'condensed') {
84
+ bt.className = 'expanded';
85
+ toggler.innerHTML = "(condense)";
86
+ } else {
87
+ bt.className = 'condensed';
88
+ toggler.innerHTML = "(expand)";
89
+ }
90
+ }
91
+ //-->
92
+ </script>
93
+
94
+ <style type="text/css" media="screen">
95
+ * {margin: 0; padding: 0; border: 0; outline: 0;}
96
+ div.clear {clear: both;}
97
+ body {background: #EEEEEE; margin: 0; padding: 0;
98
+ font-family: 'Lucida Grande', 'Lucida Sans Unicode',
99
+ 'Garuda';}
100
+ code {font-family: 'Lucida Console', monospace;
101
+ font-size: 12px;}
102
+ li {height: 18px;}
103
+ ul {list-style: none; margin: 0; padding: 0;}
104
+ ol:hover {cursor: pointer;}
105
+ ol li {white-space: pre;}
106
+ #explanation {font-size: 12px; color: #666666;
107
+ margin: 20px 0 0 100px;}
108
+ /* WRAP */
109
+ #wrap {width: 1000px; background: #FFFFFF; margin: 0 auto;
110
+ padding: 30px 50px 20px 50px;
111
+ border-left: 1px solid #DDDDDD;
112
+ border-right: 1px solid #DDDDDD;}
113
+ /* HEADER */
114
+ #header {margin: 0 auto 25px auto;}
115
+ #header img {float: left;}
116
+ #header #summary {float: left; margin: 12px 0 0 20px; width:660px;
117
+ font-family: 'Lucida Grande', 'Lucida Sans Unicode';}
118
+ h1 {margin: 0; font-size: 36px; color: #981919;}
119
+ h2 {margin: 0; font-size: 22px; color: #333333;}
120
+ #header ul {margin: 0; font-size: 12px; color: #666666;}
121
+ #header ul li strong{color: #444444;}
122
+ #header ul li {display: inline; padding: 0 10px;}
123
+ #header ul li.first {padding-left: 0;}
124
+ #header ul li.last {border: 0; padding-right: 0;}
125
+ /* BODY */
126
+ #backtrace,
127
+ #get,
128
+ #post,
129
+ #cookies,
130
+ #rack {width: 980px; margin: 0 auto 10px auto;}
131
+ p#nav {float: right; font-size: 14px;}
132
+ /* BACKTRACE */
133
+ a#expando {float: left; padding-left: 5px; color: #666666;
134
+ font-size: 14px; text-decoration: none; cursor: pointer;}
135
+ a#expando:hover {text-decoration: underline;}
136
+ h3 {float: left; width: 100px; margin-bottom: 10px;
137
+ color: #981919; font-size: 14px; font-weight: bold;}
138
+ #nav a {color: #666666; text-decoration: none; padding: 0 5px;}
139
+ #backtrace li.frame-info {background: #f7f7f7; padding-left: 10px;
140
+ font-size: 12px; color: #333333;}
141
+ #backtrace ul {list-style-position: outside; border: 1px solid #E9E9E9;
142
+ border-bottom: 0;}
143
+ #backtrace ol {width: 920px; margin-left: 50px;
144
+ font: 10px 'Lucida Console', monospace; color: #666666;}
145
+ #backtrace ol li {border: 0; border-left: 1px solid #E9E9E9;
146
+ padding: 2px 0;}
147
+ #backtrace ol code {font-size: 10px; color: #555555; padding-left: 5px;}
148
+ #backtrace-ul li {border-bottom: 1px solid #E9E9E9; height: auto;
149
+ padding: 3px 0;}
150
+ #backtrace-ul .code {padding: 6px 0 4px 0;}
151
+ #backtrace.condensed .system,
152
+ #backtrace.condensed .framework {display:none;}
153
+ /* REQUEST DATA */
154
+ p.no-data {padding-top: 2px; font-size: 12px; color: #666666;}
155
+ table.req {width: 980px; text-align: left; font-size: 12px;
156
+ color: #666666; padding: 0; border-spacing: 0;
157
+ border: 1px solid #EEEEEE; border-bottom: 0;
158
+ border-left: 0;
159
+ clear:both}
160
+ table.req tr th {padding: 2px 10px; font-weight: bold;
161
+ background: #F7F7F7; border-bottom: 1px solid #EEEEEE;
162
+ border-left: 1px solid #EEEEEE;}
163
+ table.req tr td {padding: 2px 20px 2px 10px;
164
+ border-bottom: 1px solid #EEEEEE;
165
+ border-left: 1px solid #EEEEEE;}
166
+ /* HIDE PRE/POST CODE AT START */
167
+ .pre-context,
168
+ .post-context {display: none;}
169
+
170
+ table td.code {width:750px}
171
+ table td.code div {width:750px;overflow:hidden}
172
+ </style>
173
+ </head>
174
+ <body>
175
+ <div id="wrap">
176
+ <div id="header">
177
+ <img src="<%= env['SCRIPT_NAME'] %>/__aldebaran__/500.png" alt="application error" height="161" width="313" />
178
+ <div id="summary">
179
+ <h1><strong><%=h exception.class %></strong> at <strong><%=h path %>
180
+ </strong></h1>
181
+ <h2><%=h exception.message %></h2>
182
+ <ul>
183
+ <li class="first"><strong>file:</strong> <code>
184
+ <%=h frames.first.filename.split("/").last %></code></li>
185
+ <li><strong>location:</strong> <code><%=h frames.first.function %>
186
+ </code></li>
187
+ <li class="last"><strong>line:
188
+ </strong> <%=h frames.first.lineno %></li>
189
+ </ul>
190
+ </div>
191
+ <div class="clear"></div>
192
+ </div>
193
+
194
+ <div id="backtrace" class='condensed'>
195
+ <h3>BACKTRACE</h3>
196
+ <p><a href="#" id="expando"
197
+ onclick="toggleBacktrace(); return false">(expand)</a></p>
198
+ <p id="nav"><strong>JUMP TO:</strong>
199
+ <a href="#get-info">GET</a>
200
+ <a href="#post-info">POST</a>
201
+ <a href="#cookie-info">COOKIES</a>
202
+ <a href="#env-info">ENV</a>
203
+ </p>
204
+ <div class="clear"></div>
205
+
206
+ <ul id="backtrace-ul">
207
+
208
+ <% id = 1 %>
209
+ <% frames.each do |frame| %>
210
+ <% if frame.context_line && frame.context_line != "#" %>
211
+
212
+ <li class="frame-info <%= frame_class(frame) %>">
213
+ <code><%=h frame.filename %></code> in
214
+ <code><strong><%=h frame.function %></strong></code>
215
+ </li>
216
+
217
+ <li class="code <%= frame_class(frame) %>">
218
+ <% if frame.pre_context %>
219
+ <ol start="<%=h frame.pre_context_lineno + 1 %>"
220
+ class="pre-context" id="pre-<%= id %>"
221
+ onclick="toggle(<%= id %>);">
222
+ <% frame.pre_context.each do |line| %>
223
+ <li class="pre-context-line"><code><%=h line %></code></li>
224
+ <% end %>
225
+ </ol>
226
+ <% end %>
227
+
228
+ <ol start="<%= frame.lineno %>" class="context" id="<%= id %>"
229
+ onclick="toggle(<%= id %>);">
230
+ <li class="context-line" id="context-<%= id %>"><code><%=
231
+ h frame.context_line %></code></li>
232
+ </ol>
233
+
234
+ <% if frame.post_context %>
235
+ <ol start="<%=h frame.lineno + 1 %>" class="post-context"
236
+ id="post-<%= id %>" onclick="toggle(<%= id %>);">
237
+ <% frame.post_context.each do |line| %>
238
+ <li class="post-context-line"><code><%=h line %></code></li>
239
+ <% end %>
240
+ </ol>
241
+ <% end %>
242
+ <div class="clear"></div>
243
+ </li>
244
+
245
+ <% end %>
246
+
247
+ <% id += 1 %>
248
+ <% end %>
249
+
250
+ </ul>
251
+ </div> <!-- /BACKTRACE -->
252
+
253
+ <div id="get">
254
+ <h3 id="get-info">GET</h3>
255
+ <% if req.GET and not req.GET.empty? %>
256
+ <table class="req">
257
+ <tr>
258
+ <th>Variable</th>
259
+ <th>Value</th>
260
+ </tr>
261
+ <% req.GET.sort_by { |k, v| k.to_s }.each { |key, val| %>
262
+ <tr>
263
+ <td><%=h key %></td>
264
+ <td class="code"><div><%=h val.inspect %></div></td>
265
+ </tr>
266
+ <% } %>
267
+ </table>
268
+ <% else %>
269
+ <p class="no-data">No GET data.</p>
270
+ <% end %>
271
+ <div class="clear"></div>
272
+ </div> <!-- /GET -->
273
+
274
+ <div id="post">
275
+ <h3 id="post-info">POST</h3>
276
+ <% if req.POST and not req.POST.empty? %>
277
+ <table class="req">
278
+ <tr>
279
+ <th>Variable</th>
280
+ <th>Value</th>
281
+ </tr>
282
+ <% req.POST.sort_by { |k, v| k.to_s }.each { |key, val| %>
283
+ <tr>
284
+ <td><%=h key %></td>
285
+ <td class="code"><div><%=h val.inspect %></div></td>
286
+ </tr>
287
+ <% } %>
288
+ </table>
289
+ <% else %>
290
+ <p class="no-data">No POST data.</p>
291
+ <% end %>
292
+ <div class="clear"></div>
293
+ </div> <!-- /POST -->
294
+
295
+ <div id="cookies">
296
+ <h3 id="cookie-info">COOKIES</h3>
297
+ <% unless req.cookies.empty? %>
298
+ <table class="req">
299
+ <tr>
300
+ <th>Variable</th>
301
+ <th>Value</th>
302
+ </tr>
303
+ <% req.cookies.each { |key, val| %>
304
+ <tr>
305
+ <td><%=h key %></td>
306
+ <td class="code"><div><%=h val.inspect %></div></td>
307
+ </tr>
308
+ <% } %>
309
+ </table>
310
+ <% else %>
311
+ <p class="no-data">No cookie data.</p>
312
+ <% end %>
313
+ <div class="clear"></div>
314
+ </div> <!-- /COOKIES -->
315
+
316
+ <div id="rack">
317
+ <h3 id="env-info">Rack ENV</h3>
318
+ <table class="req">
319
+ <tr>
320
+ <th>Variable</th>
321
+ <th>Value</th>
322
+ </tr>
323
+ <% env.sort_by { |k, v| k.to_s }.each { |key, val| %>
324
+ <tr>
325
+ <td><%=h key %></td>
326
+ <td class="code"><div><%=h val %></div></td>
327
+ </tr>
328
+ <% } %>
329
+ </table>
330
+ <div class="clear"></div>
331
+ </div> <!-- /RACK ENV -->
332
+
333
+ <p id="explanation">You're seeing this error because you have
334
+ enabled the <code>show_exceptions</code> setting.</p>
335
+ </div> <!-- /WRAP -->
336
+ </body>
337
+ </html>
338
+ HTML
339
+ end
340
+ end
@@ -0,0 +1,3 @@
1
+ module Aldebaran
2
+ VERSION = '1.0.1'
3
+ end
@@ -0,0 +1,17 @@
1
+ require File.expand_path('../helper', __FILE__)
2
+
3
+ class AldebaranTest < Test::Unit::TestCase
4
+ it 'creates a new aldebaran::Base subclass on new' do
5
+ app =
6
+ aldebaran.new do
7
+ get '/' do
8
+ 'Hello World'
9
+ end
10
+ end
11
+ assert_same aldebaran::Base, app.superclass
12
+ end
13
+
14
+ it "responds to #template_cache" do
15
+ assert_kind_of Tilt::Cache, aldebaran::Base.new!.template_cache
16
+ end
17
+ end
@@ -0,0 +1,160 @@
1
+ require File.expand_path('../helper', __FILE__)
2
+
3
+ class BaseTest < Test::Unit::TestCase
4
+ def test_default
5
+ assert true
6
+ end
7
+
8
+ describe 'aldebaran::Base subclasses' do
9
+ class TestApp < aldebaran::Base
10
+ get '/' do
11
+ 'Hello World'
12
+ end
13
+ end
14
+
15
+ it 'include Rack::Utils' do
16
+ assert TestApp.included_modules.include?(Rack::Utils)
17
+ end
18
+
19
+ it 'processes requests with #call' do
20
+ assert TestApp.respond_to?(:call)
21
+
22
+ request = Rack::MockRequest.new(TestApp)
23
+ response = request.get('/')
24
+ assert response.ok?
25
+ assert_equal 'Hello World', response.body
26
+ end
27
+
28
+ class TestApp < aldebaran::Base
29
+ get '/state' do
30
+ @foo ||= "new"
31
+ body = "Foo: #{@foo}"
32
+ @foo = 'discard'
33
+ body
34
+ end
35
+ end
36
+
37
+ it 'does not maintain state between requests' do
38
+ request = Rack::MockRequest.new(TestApp)
39
+ 2.times do
40
+ response = request.get('/state')
41
+ assert response.ok?
42
+ assert_equal 'Foo: new', response.body
43
+ end
44
+ end
45
+
46
+ it "passes the subclass to configure blocks" do
47
+ ref = nil
48
+ TestApp.configure { |app| ref = app }
49
+ assert_equal TestApp, ref
50
+ end
51
+
52
+ it "allows the configure block arg to be omitted and does not change context" do
53
+ context = nil
54
+ TestApp.configure { context = self }
55
+ assert_equal self, context
56
+ end
57
+ end
58
+
59
+ describe "aldebaran::Base as Rack middleware" do
60
+ app = lambda { |env|
61
+ headers = {'X-Downstream' => 'true'}
62
+ headers['X-Route-Missing'] = env['aldebaran.route-missing'] || ''
63
+ [210, headers, ['Hello from downstream']] }
64
+
65
+ class TestMiddleware < aldebaran::Base
66
+ end
67
+
68
+ it 'creates a middleware that responds to #call with .new' do
69
+ middleware = TestMiddleware.new(app)
70
+ assert middleware.respond_to?(:call)
71
+ end
72
+
73
+ it 'exposes the downstream app' do
74
+ middleware = TestMiddleware.new!(app)
75
+ assert_same app, middleware.app
76
+ end
77
+
78
+ class TestMiddleware < aldebaran::Base
79
+ def route_missing
80
+ env['aldebaran.route-missing'] = '1'
81
+ super
82
+ end
83
+
84
+ get '/' do
85
+ 'Hello from middleware'
86
+ end
87
+ end
88
+
89
+ middleware = TestMiddleware.new(app)
90
+ request = Rack::MockRequest.new(middleware)
91
+
92
+ it 'intercepts requests' do
93
+ response = request.get('/')
94
+ assert response.ok?
95
+ assert_equal 'Hello from middleware', response.body
96
+ end
97
+
98
+ it 'automatically forwards requests downstream when no matching route found' do
99
+ response = request.get('/missing')
100
+ assert_equal 210, response.status
101
+ assert_equal 'Hello from downstream', response.body
102
+ end
103
+
104
+ it 'calls #route_missing before forwarding downstream' do
105
+ response = request.get('/missing')
106
+ assert_equal '1', response['X-Route-Missing']
107
+ end
108
+
109
+ class TestMiddleware < aldebaran::Base
110
+ get '/low-level-forward' do
111
+ app.call(env)
112
+ end
113
+ end
114
+
115
+ it 'can call the downstream app directly and return result' do
116
+ response = request.get('/low-level-forward')
117
+ assert_equal 210, response.status
118
+ assert_equal 'true', response['X-Downstream']
119
+ assert_equal 'Hello from downstream', response.body
120
+ end
121
+
122
+ class TestMiddleware < aldebaran::Base
123
+ get '/explicit-forward' do
124
+ response['X-Middleware'] = 'true'
125
+ res = forward
126
+ assert_nil res
127
+ assert_equal 210, response.status
128
+ assert_equal 'true', response['X-Downstream']
129
+ assert_equal ['Hello from downstream'], response.body
130
+ 'Hello after explicit forward'
131
+ end
132
+ end
133
+
134
+ it 'forwards the request downstream and integrates the response into the current context' do
135
+ response = request.get('/explicit-forward')
136
+ assert_equal 210, response.status
137
+ assert_equal 'true', response['X-Downstream']
138
+ assert_equal 'Hello after explicit forward', response.body
139
+ assert_equal '28', response['Content-Length']
140
+ end
141
+
142
+ app_content_length = lambda {|env|
143
+ [200, {'Content-Length' => '16'}, 'From downstream!']}
144
+
145
+ class TestMiddlewareContentLength < aldebaran::Base
146
+ get '/forward' do
147
+ res = forward
148
+ 'From after explicit forward!'
149
+ end
150
+ end
151
+
152
+ middleware_content_length = TestMiddlewareContentLength.new(app_content_length)
153
+ request_content_length = Rack::MockRequest.new(middleware_content_length)
154
+
155
+ it "sets content length for last response" do
156
+ response = request_content_length.get('/forward')
157
+ assert_equal '28', response['Content-Length']
158
+ end
159
+ end
160
+ end