File: streaming_test.rb

package info (click to toggle)
ruby-sinatra 1.4.5-1
  • links: PTS, VCS
  • area: main
  • in suites: jessie, jessie-kfreebsd
  • size: 1,524 kB
  • ctags: 483
  • sloc: ruby: 9,521; makefile: 5
file content (149 lines) | stat: -rw-r--r-- 3,606 bytes parent folder | download | duplicates (2)
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