1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
|
require File.expand_path('../helper', __FILE__)
class StreamingTest < Test::Unit::TestCase
Stream = Sinatra::Helpers::Stream
it 'returns the concatenated body' do
mock_app do
get('/') do
stream do |out|
out << "Hello" << " "
out << "World!"
end
end
end
get('/')
assert_body "Hello World!"
end
it 'always yields strings' do
stream = Stream.new { |out| out << :foo }
stream.each { |str| assert_equal 'foo', str }
end
it 'postpones body generation' do
step = 0
stream = Stream.new do |out|
10.times do
out << step
step += 1
end
end
stream.each do |s|
assert_equal s, step.to_s
step += 1
end
end
it 'calls the callback after it is done' do
step = 0
final = 0
stream = Stream.new { |_| 10.times { step += 1 }}
stream.callback { final = step }
stream.each {|_|}
assert_equal 10, final
end
it 'does not trigger the callback if close is set to :keep_open' do
step = 0
final = 0
stream = Stream.new(Stream, :keep_open) { |_| 10.times { step += 1 } }
stream.callback { final = step }
stream.each {|_|}
assert_equal 0, final
end
it 'allows adding more than one callback' do
a = b = false
stream = Stream.new { }
stream.callback { a = true }
stream.callback { b = true }
stream.each {|_| }
assert a, 'should trigger first callback'
assert b, 'should trigger second callback'
end
class MockScheduler
def initialize(*) @schedule, @defer = [], [] end
def schedule(&block) @schedule << block end
def defer(&block) @defer << block end
def schedule!(*) @schedule.pop.call until @schedule.empty? end
def defer!(*) @defer.pop.call until @defer.empty? end
end
it 'allows dropping in another scheduler' do
scheduler = MockScheduler.new
processing = sending = done = false
stream = Stream.new(scheduler) do |out|
processing = true
out << :foo
end
stream.each { sending = true}
stream.callback { done = true }
scheduler.schedule!
assert !processing
assert !sending
assert !done
scheduler.defer!
assert processing
assert !sending
assert !done
scheduler.schedule!
assert sending
assert done
end
it 'schedules exceptions to be raised on the main thread/event loop/...' do
scheduler = MockScheduler.new
Stream.new(scheduler) { fail 'should be caught' }.each { }
scheduler.defer!
assert_raise(RuntimeError) { scheduler.schedule! }
end
it 'does not trigger an infinite loop if you call close in a callback' do
stream = Stream.new { |out| out.callback { out.close }}
stream.each { |_| }
end
it 'gives access to route specific params' do
mock_app do
get('/:name') do
stream { |o| o << params[:name] }
end
end
get '/foo'
assert_body 'foo'
end
it 'sets up async.close if available' do
ran = false
mock_app do
get('/') do
close = Object.new
def close.callback; yield end
def close.errback; end
env['async.close'] = close
stream(:keep_open) do |out|
out.callback { ran = true }
end
end
end
get '/'
assert ran
end
it 'has a public interface to inspect its open/closed state' do
stream = Stream.new(Stream) { |out| out << :foo }
assert !stream.closed?
stream.close
assert stream.closed?
end
end
|