aboutsummaryrefslogtreecommitdiffstats
path: root/test/plum/test_flow_control.rb
blob: 316361c330b1354db1f0cb93b1c3ceb59b06b5f9 (plain)
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
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
require "test_helper"

using BinaryString

class FlowControlTest < Minitest::Test
  def test_flow_control_window_update_server
    open_server_connection { |con|
      before_ws = con.recv_remaining_window
      con.window_update(500)

      last = sent_frames.last
      assert_equal(:window_update, last.type)
      assert_equal(0, last.stream_id)
      assert_equal(500, last.payload.uint32)
      assert_equal(before_ws + 500, con.recv_remaining_window)
    }
  end

  def test_flow_control_window_update_stream
    open_new_stream { |stream|
      before_ws = stream.recv_remaining_window
      stream.window_update(500)

      last = sent_frames.last
      assert_equal(:window_update, last.type)
      assert_equal(stream.id, last.stream_id)
      assert_equal(500, last.payload.uint32)
      assert_equal(before_ws + 500, stream.recv_remaining_window)
    }
  end

  def test_flow_control_window_update_zero
    open_new_stream { |stream|
      assert_stream_error(:protocol_error) {
        stream.receive_frame Frame.new(type: :window_update,
                                       stream_id: stream.id,
                                       payload: "".push_uint32(0))
      }
    }
  end

  def test_flow_control_window_update_frame_size
    open_new_stream { |stream|
      assert_connection_error(:frame_size_error) {
        stream.receive_frame Frame.new(type: :window_update,
                                       stream_id: stream.id,
                                       payload: "".push_uint16(0))
      }
    }
  end

  def test_flow_control_dont_send_data_exceeding_send_window
    open_new_stream { |stream|
      con = stream.connection
      con << Frame.new(type: :settings,
                       stream_id: 0,
                       payload: "".push_uint16(Frame::SETTINGS_TYPE[:initial_window_size])
                                  .push_uint32(4*2+1)).assemble
      # only extend stream window size
      con << Frame.new(type: :window_update,
                       stream_id: stream.id,
                       payload: "".push_uint32(100)).assemble
      10.times { |i|
        stream.send Frame.new(type: :data,
                              stream_id: stream.id,
                              payload: "".push_uint32(i))
      }

      last = sent_frames.last
      assert_equal(1, last.payload.uint32)
    }
  end

  def test_flow_control_dont_send_data_upto_updated_send_window
    open_new_stream { |stream|
      con = stream.connection
      con << Frame.new(type: :settings,
                       stream_id: 0,
                       payload: "".push_uint16(Frame::SETTINGS_TYPE[:initial_window_size])
                                  .push_uint32(4*2+1)).assemble
      10.times { |i|
        stream.send Frame.new(type: :data,
                              stream_id: stream.id,
                              payload: "".push_uint32(i))
      }
      # only extend stream window size
      con << Frame.new(type: :window_update,
                       stream_id: stream.id,
                       payload: "".push_uint32(100)).assemble
      # and extend connection window size
      con << Frame.new(type: :window_update,
                       stream_id: 0,
                       payload: "".push_uint32(4*2+1)).assemble

      last = sent_frames.last
      assert_equal(3, last.payload.uint32)
    }
  end

  def test_flow_control_update_send_initial_window_size
    open_new_stream { |stream|
      con = stream.connection
      con << Frame.new(type: :settings,
                       stream_id: 0,
                       payload: "".push_uint16(Frame::SETTINGS_TYPE[:initial_window_size])
                                  .push_uint32(4*2+1)).assemble
      10.times { |i|
        stream.send Frame.new(type: :data,
                              stream_id: stream.id,
                              payload: "".push_uint32(i))
      }
      # only extend stream window size
      con << Frame.new(type: :window_update,
                       stream_id: stream.id,
                       payload: "".push_uint32(100)).assemble
      # and update initial window size
      con << Frame.new(type: :settings,
                       stream_id: 0,
                       payload: "".push_uint16(Frame::SETTINGS_TYPE[:initial_window_size])
                                  .push_uint32(4*4+1)).assemble

      last = sent_frames.reverse.find { |f| f.type == :data }
      assert_equal(3, last.payload.uint32)
    }
  end

  def test_flow_control_recv_window_exceeded
    prepare = ->(&blk) {
      open_new_stream { |stream|
        con = stream.connection
        con.settings(initial_window_size: 24)
        blk.call(con, stream)
      }
    }

    prepare.call { |con, stream|
      con.window_update(500) # extend only connection
      con << Frame.headers(stream.id, "", end_headers: true).assemble
      assert_stream_error(:flow_control_error) {
        con << Frame.data(stream.id, "\x00" * 30, end_stream: true).assemble
      }
    }

    prepare.call { |con, stream|
      stream.window_update(500) # extend only stream
      con << Frame.headers(stream.id, "", end_headers: true).assemble
      assert_connection_error(:flow_control_error) {
        con << Frame.data(stream.id, "\x00" * 30, end_stream: true).assemble
      }
    }
  end

  def test_flow_control_update_recv_initial_window_size
    open_new_stream { |stream|
      con = stream.connection
      con.settings(initial_window_size: 24)
      stream.window_update(1)
      con << Frame.headers(stream.id, "", end_headers: true).assemble
      con << Frame.data(stream.id, "\x00" * 20, end_stream: true).assemble
      assert_equal(4, con.recv_remaining_window)
      assert_equal(5, stream.recv_remaining_window)
      con.settings(initial_window_size: 60)
      assert_equal(40, con.recv_remaining_window)
      assert_equal(41, stream.recv_remaining_window)
    }
  end
end