Unit tests for the ClientSession compression options and offer negotiation.

This commit is contained in:
James Coglan
2014-12-09 22:04:34 +00:00
parent 9795355d23
commit 4fe6dcc3ef
7 changed files with 403 additions and 9 deletions
+11
View File
@@ -0,0 +1,11 @@
language: ruby
rvm:
- 1.9.3
- 2.0.0
- 2.1.3
- jruby-18mode
- jruby-19mode
- rbx-2.2
script: bundle exec rspec -c spec/
+15 -3
View File
@@ -6,6 +6,8 @@ class PermessageDeflate
require root + '/permessage_deflate/client_session'
require root + '/permessage_deflate/server_session'
ConfigurationError = Class.new(ArgumentError)
module Extension
define_method(:name) { 'permessage-deflate' }
define_method(:type) { 'permessage' }
@@ -13,16 +15,26 @@ class PermessageDeflate
define_method(:rsv2) { false }
define_method(:rsv3) { false }
def configure(options)
options = (@options || {}).merge(options)
PermessageDeflate.new(options)
end
def create_client_session
ClientSession.new
ClientSession.new(@options || {})
end
def create_server_session(offers)
offers.each do |offer|
return ServerSession.new(offer) if ServerSession.valid_params?(offer)
return ServerSession.new(@options || {}, offer) if ServerSession.valid_params?(offer)
end
end
end
extend Extension
include Extension
extend Extension
def initialize(options)
@options = options
end
end
+37 -3
View File
@@ -12,14 +12,48 @@ class PermessageDeflate
end
def generate_offer
[{'client_max_window_bits' => true}]
offer = {}
if @accept_no_context_takeover
offer['client_no_context_takeover'] = true
end
if @accept_max_window_bits
raise ConfigurationError unless VALID_WINDOW_BITS.include?(@accept_max_window_bits)
offer['client_max_window_bits'] = @accept_max_window_bits
else
offer['client_max_window_bits'] = true
end
if @request_no_context_takeover
offer['server_no_context_takeover'] = true
end
if @request_max_window_bits
raise ConfigurationError unless VALID_WINDOW_BITS.include?(@request_max_window_bits)
offer['server_max_window_bits'] = @request_max_window_bits
end
offer
end
def activate(params)
return false unless ClientSession.valid_params?(params)
@own_context_takeover = !params['client_no_context_takeover']
@own_window_bits = params['client_max_window_bits'] || DEFAULT_MAX_WINDOW_BITS
if @accept_max_window_bits and params['client_max_window_bits']
return false if params['client_max_window_bits'] > @accept_max_window_bits
end
if @request_no_context_takeover and !params['server_no_context_takeover']
return false
end
if @request_max_window_bits
return false unless params['server_max_window_bits'] and params['server_max_window_bits'] <= @request_max_window_bits
end
@own_context_takeover = !(@accept_no_context_takeover || params['client_no_context_takeover'])
@own_window_bits = [@accept_max_window_bits, params['client_max_window_bits']].map { |x| x || DEFAULT_MAX_WINDOW_BITS }.min
@peer_context_takeover = !params['server_no_context_takeover']
@peer_window_bits = params['server_max_window_bits'] || DEFAULT_MAX_WINDOW_BITS
+2 -2
View File
@@ -11,8 +11,8 @@ class PermessageDeflate
true
end
def initialize(params)
super()
def initialize(options, params)
super(options)
@params = params
end
+12 -1
View File
@@ -31,6 +31,17 @@ class PermessageDeflate
true
end
def initialize(options)
@level = options[:level] || Zlib::DEFAULT_COMPRESSION
@mem_level = options[:mem_level] || Zlib::DEF_MEM_LEVEL
@strategy = options[:strategy] || Zlib::DEFAULT_STRATEGY
@accept_no_context_takeover = options[:no_context_takeover]
@accept_max_window_bits = options[:max_window_bits]
@request_no_context_takeover = options[:request_no_context_takeover]
@request_max_window_bits = options[:request_max_window_bits]
end
def valid_frame_rsv(frame)
if MESSAGE_OPCODES.include?(frame.opcode)
{:rsv1 => true, :rsv2 => false, :rsv3 => false}
@@ -86,7 +97,7 @@ class PermessageDeflate
def get_deflate
return @deflate if @deflate
deflate = Zlib::Deflate.new(Zlib::DEFAULT_COMPRESSION, -@own_window_bits)
deflate = Zlib::Deflate.new(@level, -@own_window_bits, @mem_level, @strategy)
@deflate = deflate if @own_context_takeover
deflate
end
@@ -0,0 +1,322 @@
require "spec_helper"
describe PermessageDeflate::ClientSession do
let(:ext) { PermessageDeflate.configure(options) }
let(:session) { ext.create_client_session }
let(:options) { {} }
let(:offer) { session.generate_offer }
let(:response) { {} }
let(:activate) { session.activate(response) }
let(:deflate) { double(:deflate, :deflate => "") }
let(:inflate) { double(:inflate, :inflate => "") }
let(:level) { Zlib::DEFAULT_COMPRESSION }
let(:mem_level) { Zlib::DEF_MEM_LEVEL }
let(:strategy) { Zlib::DEFAULT_STRATEGY }
let(:message) { Message.new("hello", true) }
def process_incoming_message
session.process_incoming_message(message)
end
def process_outgoing_message
session.process_outgoing_message(message)
end
describe "with default options" do
it "indicates support for client_max_window_bits" do
expect(offer).to eq("client_max_window_bits" => true)
end
describe "with an empty response" do
it "accepts the response" do
expect(activate).to be true
end
it "uses context takeover and 15 window bits for inflating incoming messages" do
activate
expect(Zlib::Inflate).to receive(:new).with(-15).exactly(1).and_return(inflate)
process_incoming_message
process_incoming_message
end
it "uses context takeover and 15 window bits for deflating outgoing messages" do
activate
expect(Zlib::Deflate).to receive(:new).with(level, -15, mem_level, strategy).exactly(1).and_return(deflate)
process_outgoing_message
process_outgoing_message
end
end
describe "when the response includes server_no_context_takeover" do
before { response["server_no_context_takeover"] = true }
it "accepts the response" do
expect(activate).to be true
end
it "uses no context takeover and 15 window bits for inflating incoming messages" do
activate
expect(Zlib::Inflate).to receive(:new).with(-15).exactly(2).and_return(inflate)
expect(inflate).to receive(:finish).exactly(2)
expect(inflate).to receive(:close).exactly(2)
process_incoming_message
process_incoming_message
end
end
describe "when the response includes client_no_context_takeover" do
before { response["client_no_context_takeover"] = true }
it "accepts the response" do
expect(activate).to be true
end
it "uses no context takeover and 15 window bits for deflating outgoing messages" do
activate
expect(Zlib::Deflate).to receive(:new).with(level, -15, mem_level, strategy).exactly(2).and_return(deflate)
expect(deflate).to receive(:finish).exactly(2)
expect(deflate).to receive(:close).exactly(2)
process_outgoing_message
process_outgoing_message
end
end
describe "when the response includes server_max_window_bits" do
before { response["server_max_window_bits"] = 8 }
it "accepts the response" do
expect(activate).to be true
end
it "uses context takeover and 8 window bits for inflating incoming messages" do
activate
expect(Zlib::Inflate).to receive(:new).with(-8).exactly(1).and_return(inflate)
process_incoming_message
process_incoming_message
end
end
describe "when the response includes invalid server_max_window_bits" do
before { response["server_max_window_bits"] = 20 }
it "rejects the response" do
expect(activate).to be false
end
end
describe "when the response includes client_max_window_bits" do
before { response["client_max_window_bits"] = 8 }
it "accepts the response" do
expect(activate).to be true
end
it "uses context takeover and 8 window bits for deflating outgoing messages" do
activate
expect(Zlib::Deflate).to receive(:new).with(level, -8, mem_level, strategy).exactly(1).and_return(deflate)
process_outgoing_message
process_outgoing_message
end
end
describe "when the response includes invalid client_max_window_bits" do
before { response["client_max_window_bits"] = 20 }
it "rejects the response" do
expect(activate).to be false
end
end
end
describe "with no_context_takeover" do
before { options[:no_context_takeover] = true }
it "sends client_no_context_takeover with no_context_takeover" do
expect(offer).to eq(
"client_no_context_takeover" => true,
"client_max_window_bits" => true
)
end
describe "with an empty response" do
it "accepts the response" do
expect(activate).to be true
end
it "uses no context takeover and 15 window bits for deflating outgoing messages" do
activate
expect(Zlib::Deflate).to receive(:new).with(level, -15, mem_level, strategy).exactly(2).and_return(deflate)
expect(deflate).to receive(:finish).exactly(2)
expect(deflate).to receive(:close).exactly(2)
process_outgoing_message
process_outgoing_message
end
end
end
describe "with max_window_bits" do
before { options[:max_window_bits] = 9 }
it "sends client_max_window_bits with max_window_bits" do
expect(offer).to eq("client_max_window_bits" => 9)
end
describe "with an empty response" do
it "accepts the response" do
expect(activate).to be true
end
it "uses context takeover and 9 window bits for deflating outgoing messages" do
activate
expect(Zlib::Deflate).to receive(:new).with(level, -9, mem_level, strategy).exactly(1).and_return(deflate)
process_outgoing_message
process_outgoing_message
end
end
describe "when the response has higher client_max_window_bits" do
before { response["client_max_window_bits"] = 10 }
it "does not accept the response" do
expect(activate).to be false
end
end
describe "when the response has lower client_max_window_bits" do
before { response["client_max_window_bits"] = 8 }
it "accepts the response" do
expect(activate).to be true
end
it "uses context takeover and 8 window bits for deflating outgoing messages" do
activate
expect(Zlib::Deflate).to receive(:new).with(level, -8, mem_level, strategy).exactly(1).and_return(deflate)
process_outgoing_message
process_outgoing_message
end
end
end
describe "with invalid max_window_bits" do
before { options[:max_window_bits] = 20 }
it "raises when generating the offer with invalid max_window_bits" do
expect { offer }.to raise_error
end
end
describe "with request_no_context_takeover" do
before { options[:request_no_context_takeover] = true }
it "sends server_no_context_takeover with request_no_context_takeover" do
expect(offer).to eq(
"client_max_window_bits" => true,
"server_no_context_takeover" => true
)
end
describe "with an empty response" do
it "rejects the response" do
expect(activate).to be false
end
end
describe "when the response includes server_no_context_takeover" do
before { response["server_no_context_takeover"] = true }
it "accepts the response" do
expect(activate).to be true
end
it "uses no no context takeover and 15 window bits for inflating incoming messages" do
activate
expect(Zlib::Inflate).to receive(:new).with(-15).exactly(2).and_return(inflate)
expect(inflate).to receive(:finish).exactly(2)
expect(inflate).to receive(:close).exactly(2)
process_incoming_message
process_incoming_message
end
end
end
describe "with request_max_window_bits" do
before { options[:request_max_window_bits] = 12 }
it "sends server_max_window_bits with request_max_window_bits" do
expect(offer).to eq(
"client_max_window_bits" => true,
"server_max_window_bits" => 12
)
end
describe "with an empty response" do
it "rejects the response" do
expect(activate).to be false
end
end
describe "when the response has higher server_max_window_bits" do
before { response["server_max_window_bits"] = 13 }
it "rejects the response" do
expect(activate).to be false
end
end
describe "when the response has lower server_max_window_bits" do
before { response["server_max_window_bits"] = 11 }
it "accepts the response" do
expect(activate).to be true
end
it "uses context takeover and 11 window bits for inflating incoming messages" do
activate
expect(Zlib::Inflate).to receive(:new).with(-11).exactly(1).and_return(inflate)
process_incoming_message
process_incoming_message
end
end
end
describe "with invalid request_max_window_bits" do
before { options[:request_max_window_bits] = 20 }
it "raises when generating an offer with invalid request_max_window_bits" do
expect { offer }.to raise_error
end
end
describe "with level" do
before { options[:level] = Zlib::BEST_SPEED }
it "sets the level of the deflate stream" do
activate
expect(Zlib::Deflate).to receive(:new).with(Zlib::BEST_SPEED, -15, mem_level, strategy).and_return(deflate)
process_outgoing_message
end
end
describe "with mem_level" do
before { options[:mem_level] = 5 }
it "sets the mem_level of the deflate stream" do
activate
expect(Zlib::Deflate).to receive(:new).with(level, -15, 5, strategy).and_return(deflate)
process_outgoing_message
end
end
describe "with strategy" do
before { options[:strategy] = Zlib::RLE }
it "sets the strategy of the deflate stream" do
activate
expect(Zlib::Deflate).to receive(:new).with(level, -15, mem_level, Zlib::RLE).and_return(deflate)
process_outgoing_message
end
end
end
+4
View File
@@ -0,0 +1,4 @@
require File.expand_path("../../lib/permessage_deflate", __FILE__)
class Message < Struct.new(:data, :rsv1)
end