test/plum/test_flow_control.rb
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::WindowUpdate.new(stream.id, 0)
}
}
end
def test_flow_control_window_update_frame_size
open_new_stream { |stream|
assert_connection_error(:frame_size_error) {
stream.receive_frame Frame.craft(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::Settings.new(initial_window_size: 4 * 2 + 1).assemble
# only extend stream window size
con << Frame::WindowUpdate.new(stream.id, 100).assemble
10.times { |i|
stream.send Frame::Data.new(stream.id, "".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::Settings.new(initial_window_size: 4 * 2 + 1).assemble
10.times { |i|
stream.send Frame::Data.new(stream.id, "".push_uint32(i))
}
# only extend stream window size
con << Frame::WindowUpdate.new(stream.id, 100).assemble
# and extend connection window size
con << Frame::WindowUpdate.new(0, 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::Settings.new(initial_window_size: 4 * 2 + 1).assemble
10.times { |i|
stream.send Frame::Data.new(stream.id, "".push_uint32(i))
}
# only extend stream window size
con << Frame::WindowUpdate.new(stream.id, 100).assemble
# and update initial window size
con << Frame::Settings.new(initial_window_size: 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.new(stream.id, "", end_headers: true).assemble
assert_stream_error(:flow_control_error) {
con << Frame::Data.new(stream.id, "\x00" * 30, end_stream: true).assemble
}
}
prepare.call { |con, stream|
stream.window_update(500) # extend only stream
con << Frame::Headers.new(stream.id, "", end_headers: true).assemble
assert_connection_error(:flow_control_error) {
con << Frame::Data.new(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.new(stream.id, "", end_headers: true).assemble
con << Frame::Data.new(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