require 'resolv'
require 'spec_helper'
describe Blather::Stream::Client do
let(:client) { mock 'Client' }
let(:server_port) { 50000 - rand(1000) }
let(:jid) { Blather::JID.new 'n@d/r' }
let(:authcid) { nil }
before do
[:unbind, :post_init, :jid=].each do |m|
client.stubs(m) unless client.respond_to?(m)
end
client.stubs(:jid).returns jid
EM.stubs(:next_tick).yields
end
def mocked_server(times = nil, &block)
MockServer.any_instance.expects(:receive_data).send(*(times ? [:times, times] : [:at_least, 1])).with &block
EventMachine::run {
EM.add_timer(0.5) { EM.stop if EM.reactor_running? }
# Mocked server
EventMachine::start_server '127.0.0.1', server_port, ServerMock
# Blather::Stream connection
EM.connect('127.0.0.1', server_port, Blather::Stream::Client, client, jid, 'pass', nil, authcid) { |c| @stream = c }
}
end
it 'can be started' do
params = [client, 'n@d/r', 'pass', 'host', 1234]
EM.expects(:connect).with do |*parms|
parms[0].should == 'host'
parms[1].should == 1234
parms[3].should == client
parms[5].should == 'pass'
parms[4].should == Blather::JID.new('n@d/r')
end
Blather::Stream::Client.start *params
end
it 'attempts to find the SRV record if a host is not provided' do
dns = mock(:sort! => nil, :empty? => false)
dns.expects(:detect).yields(mock({
:target => 'd',
:port => 5222
}))
Resolv::DNS.expects(:open).yields(mock(:getresources => dns))
client = Class.new
EM.expects(:connect).with do |*parms|
parms[0].should == 'd'
parms[1].should == 5222
parms[3].should == client
parms[5].should == 'pass'
parms[4].should == Blather::JID.new('n@d/r')
end
Blather::Stream::Client.start client, 'n@d/r', 'pass'
end
it 'will attempt as many connections as it takes' do
dns = [mock(:target => 'd', :port => 5222), mock(:target => 'g', :port => 1234)]
dns.stubs(:sort!) #ignore sorting
Resolv::DNS.expects(:open).yields(mock(:getresources => dns))
client = Class.new
EM.expects(:connect).with do |*parms|
raise Blather::Stream::NoConnection if parms[0] == 'd'
parms[0].should == 'g'
parms[1].should == 1234
parms[3].should == client
parms[5].should == 'pass'
parms[4].should == Blather::JID.new('n@d/r')
end
Blather::Stream::Client.start client, 'n@d/r', 'pass'
end
it 'will not attempt to connect more often than necessary' do
dns = [mock(:target => 'd', :port => 5222), mock()]
dns.stubs(:sort!) #ignore sorting
Resolv::DNS.expects(:open).yields(mock(:getresources => dns))
client = Class.new
EM.expects(:connect).with do |*parms|
parms[0].should == 'd'
parms[1].should == 5222
parms[3].should == client
parms[5].should == 'pass'
parms[4].should == Blather::JID.new('n@d/r')
end
Blather::Stream::Client.start client, 'n@d/r', 'pass'
end
it 'can figure out the host to use based on the jid' do
Resolv::DNS.expects(:open).yields(mock(:getresources => mock(:empty? => true)))
client = Class.new
params = [client, 'n@d/r', 'pass', nil, 5222]
EM.expects(:connect).with do |*parms|
parms[0].should == 'd'
parms[1].should == 5222
parms[3].should == client
parms[5].should == 'pass'
parms[4].should == Blather::JID.new('n@d/r')
end
Blather::Stream::Client.start client, 'n@d/r', 'pass'
end
it 'raises a NoConnection exception if the connection is unbound before it can be completed' do
proc do
EventMachine::run {
EM.add_timer(0.5) { EM.stop if EM.reactor_running? }
Blather::Stream::Client.start client, jid, 'pass', '127.0.0.1', 50000 - rand(1000)
}
end.should raise_error Blather::Stream::ConnectionFailed
end
it 'starts the stream once the connection is complete' do
mocked_server(1) { |val, _| EM.stop; val.should match(/stream:stream/) }
end
it 'sends stanzas to the client when the stream is ready' do
client.expects(:receive_data).with do |n|
EM.stop
n.should be_kind_of Blather::Stanza::Message
end
mocked_server(1) do |val, server|
val.should match(/stream:stream/)
server.send_data ""
server.send_data "Message!"
server.send_data ""
true
end
end
it 'puts itself in the stopped state and calls @client.unbind when unbound' do
client.expects(:unbind).at_least_once
started = false
mocked_server(2) do |val, server|
if !started
started = true
server.send_data ""
server.send_data ""
val.should match(/stream:stream/)
else
EM.stop
@stream.should_not be_stopped
@stream.unbind
@stream.should be_stopped
end
end
end
it 'will be in the negotiating state during feature negotiations' do
state = nil
client.expects(:receive_data).with do |n|
EM.stop
state.should == :negotiated
@stream.negotiating?.should == false
end
mocked_server(2) do |val, server|
case state
when nil
state = :started
server.send_data ""
server.send_data ""
true
when :started
state = :negotiated
@stream.negotiating?.should == true
server.send_data ""
server.send_data "Message!"
true
else
EM.stop
false
end
end
end
it 'stops when sent ' do
state = nil
mocked_server(3) do |val, server|
case state
when nil
state = :started
server.send_data ""
server.send_data ""
val.should match(/stream:stream/)
when :started
state = :stopped
server.send_data ''
@stream.stopped?.should == false
when :stopped
EM.stop
@stream.stopped?.should == true
val.should == ''
else
EM.stop
false
end
end
end
it 'sends client an error on stream:error' do
client.expects(:receive_data).with do |v|
v.name.should == :conflict
v.text.should == 'Already signed in'
v.to_s.should == "Stream Error (conflict): #{v.text}"
end
state = nil
mocked_server(3) do |val, server|
case state
when nil
state = :started
server.send_data ""
server.send_data ""
val.should match(/stream:stream/)
when :started
state = :stopped
server.send_data ""
server.send_data "Already signed in"
val.should match(/bind/)
when :stopped
EM.stop
val.should == ""
else
EM.stop
false
end
end
end
it 'skips features it is unable to handle' do
state = nil
mocked_server do |val, server|
case state
when nil
state = :started
server.send_data ""
server.send_data ""
val.should match(/stream:stream/)
when :started
EM.stop
val.should match(/starttls/)
else
EM.stop
false
end
end
end
it 'starts TLS when asked' do
state = nil
mocked_server(3) do |val, server|
case state
when nil
state = :started
server.send_data ""
server.send_data ""
val.should match(/stream:stream/)
when :started
state = :tls
@stream.expects(:start_tls)
server.send_data ""
val.should match(/starttls/)
when :tls
EM.stop
true
else
EM.stop
false
end
end
end
it 'will fail if TLS negotiation fails' do
client.expects(:receive_data).with { |v| v.should be_kind_of Blather::Stream::TLS::TLSFailure }
state = nil
mocked_server(3) do |val, server|
case state
when nil
state = :started
server.send_data ""
val.should match(/stream:stream/)
when :started
state = :tls
@stream.expects(:start_tls).never
server.send_data ""
val.should match(/starttls/)
when :tls
EM.stop
val.should == ""
else
EM.stop
false
end
end
end
it 'will fail if a bad node comes through TLS negotiations' do
client.expects(:receive_data).with do |v|
v.should be_kind_of Blather::Stream::TLS::TLSFailure
end
state = nil
mocked_server(3) do |val, server|
case state
when nil
state = :started
server.send_data ""
server.send_data ""
val.should match(/stream:stream/)
when :started
state = :tls
@stream.expects(:start_tls).never
server.send_data ""
val.should match(/starttls/)
when :tls
EM.stop
val.should == ""
else
EM.stop
false
end
end
end
it 'connects via SASL MD5 when asked' do
Time.any_instance.stubs(:to_f).returns(1.1)
state = nil
mocked_server(5) do |val, server|
case state
when nil
state = :started
server.send_data "DIGEST-MD5"
val.should match(/stream:stream/)
when :started
state = :auth_sent
server.send_data "cmVhbG09InNvbWVyZWFsbSIsbm9uY2U9Ik9BNk1HOXRFUUdtMmhoIixxb3A9ImF1dGgiLGNoYXJzZXQ9dXRmLTgsYWxnb3JpdGhtPW1kNS1zZXNzCg=="
val.should match(/auth.*DIGEST\-MD5/)
when :auth_sent
state = :response1_sent
server.send_data "cnNwYXV0aD1lYTQwZjYwMzM1YzQyN2I1NTI3Yjg0ZGJhYmNkZmZmZAo="
val.should ==('bm9uY2U9Ik9BNk1HOXRFUUdtMmhoIixjaGFyc2V0PXV0Zi04LHVzZXJuYW1lPSJuIixyZWFsbT0ic29tZXJlYWxtIixjbm9uY2U9Ijc3N2Q0NWJiYmNkZjUwZDQ5YzQyYzcwYWQ3YWNmNWZlIixuYz0wMDAwMDAwMSxxb3A9YXV0aCxkaWdlc3QtdXJpPSJ4bXBwL2QiLHJlc3BvbnNlPTZiNTlhY2Q1ZWJmZjhjZTA0NTYzMGFiMDU2Zjg3MTdm')
when :response1_sent
state = :response2_sent
server.send_data ""
val.should match(%r{})
when :response2_sent
EM.stop
state = :complete
val.should match(/stream:stream/)
else
EM.stop
false
end
end
end
it 'will connect via SSL PLAIN when asked' do
state = nil
mocked_server(3) do |val, server|
case state
when nil
state = :started
server.send_data "PLAIN"
val.should match(/stream:stream/)
when :started
state = :auth_sent
server.send_data ""
Nokogiri::XML(val).to_xml.should == Nokogiri::XML('bkBkAG4AcGFzcw==').to_xml
when :auth_sent
EM.stop
state = :complete
val.should match(/stream:stream/)
else
EM.stop
false
end
end
end
context "with an alternative authcid specified" do
let(:authcid) { 'doo' }
it 'connects via SASL MD5 when asked' do
Time.any_instance.stubs(:to_f).returns(1.1)
state = nil
mocked_server(5) do |val, server|
case state
when nil
state = :started
server.send_data "DIGEST-MD5"
val.should match(/stream:stream/)
when :started
state = :auth_sent
server.send_data "cmVhbG09InNvbWVyZWFsbSIsbm9uY2U9Ik9BNk1HOXRFUUdtMmhoIixxb3A9ImF1dGgiLGNoYXJzZXQ9dXRmLTgsYWxnb3JpdGhtPW1kNS1zZXNzCg=="
val.should match(/auth.*DIGEST\-MD5/)
when :auth_sent
state = :response1_sent
server.send_data "cnNwYXV0aD1lYTQwZjYwMzM1YzQyN2I1NTI3Yjg0ZGJhYmNkZmZmZAo="
val.should ==('bm9uY2U9Ik9BNk1HOXRFUUdtMmhoIixjaGFyc2V0PXV0Zi04LHVzZXJuYW1lPSJkb28iLHJlYWxtPSJzb21lcmVhbG0iLGNub25jZT0iNzc3ZDQ1YmJiY2RmNTBkNDljNDJjNzBhZDdhY2Y1ZmUiLG5jPTAwMDAwMDAxLHFvcD1hdXRoLGRpZ2VzdC11cmk9InhtcHAvZCIscmVzcG9uc2U9YzBhMzQ4MDkyOWJmMDFiMWUyODc0NTE1YWQ5ZjNlYzE=')
when :response1_sent
state = :response2_sent
server.send_data ""
val.should match(%r{})
when :response2_sent
EM.stop
state = :complete
val.should match(/stream:stream/)
else
EM.stop
false
end
end
end
it 'will connect via SSL PLAIN when asked' do
state = nil
mocked_server(3) do |val, server|
case state
when nil
state = :started
server.send_data "PLAIN"
val.should match(/stream:stream/)
when :started
state = :auth_sent
server.send_data ""
Nokogiri::XML(val).to_xml.should == Nokogiri::XML('bkBkAGRvbwBwYXNz').to_xml
when :auth_sent
EM.stop
state = :complete
val.should match(/stream:stream/)
else
EM.stop
false
end
end
end
end
it 'will connect via SSL ANONYMOUS when asked' do
state = nil
mocked_server(3) do |val, server|
case state
when nil
state = :started
server.send_data "ANONYMOUS"
val.should match(/stream:stream/)
when :started
state = :auth_sent
server.send_data ""
Nokogiri::XML(val).to_xml.should == Nokogiri::XML('').to_xml
when :auth_sent
EM.stop
state = :complete
val.should match(/stream:stream/)
else
EM.stop
false
end
end
end
context "if the JID node is blank" do
let(:jid) { Blather::JID.new '@d' }
it 'connects via ANONYMOUS if the Blather::JID has a blank node' do
state = nil
mocked_server(3) do |val, server|
case state
when nil
state = :started
server.send_data "DIGEST-MD5PLAINANONYMOUS"
val.should match(/stream:stream/)
when :started
state = :auth_sent
server.send_data ""
Nokogiri::XML(val).to_xml.should == Nokogiri::XML('').to_xml
when :auth_sent
EM.stop
state = :complete
val.should match(/stream:stream/)
else
EM.stop
false
end
end
end
it 'fails if asked to connect via ANONYMOUS but the server does not support it' do
client.expects(:receive_data).with { |s| s.should be_instance_of Blather::BlatherError }
state = nil
mocked_server(2) do |val, server|
case state
when nil
state = :started
server.send_data ""
server.send_data "DIGEST-MD5PLAIN"
val.should match(/stream:stream/)
when :started
EM.stop
val.should match(/stream:stream/)
else
EM.stop
false
end
end
end
end
it 'tries each possible mechanism until it fails completely' do
client.expects(:receive_data).with do |n|
n.should be_kind_of(Blather::SASLError)
n.name.should == :not_authorized
end
state = nil
mocked_server(5) do |val, server|
case state
when nil
state = :started
server.send_data ""
server.send_data "DIGEST-MD5PLAINANONYMOUS"
val.should match(/stream:stream/)
when :started
state = :failed_md5
server.send_data ""
val.should match(/mechanism="DIGEST-MD5"/)
when :failed_md5
state = :failed_plain
server.send_data ""
val.should match(/mechanism="PLAIN"/)
when :failed_plain
state = :failed_anon
server.send_data ""
val.should match(/mechanism="ANONYMOUS"/)
when :failed_anon
EM.stop
state = :complete
val.should match(/\/stream:stream/)
else
EM.stop
false
end
end
end
it 'tries each mechanism until it succeeds' do
state = nil
mocked_server(4) do |val, server|
case state
when nil
state = :started
server.send_data "DIGEST-MD5PLAINANONYMOUS"
val.should match(/stream:stream/)
when :started
state = :failed_md5
server.send_data ""
val.should match(/mechanism="DIGEST-MD5"/)
when :failed_md5
state = :plain_sent
server.send_data ""
val.should match(/mechanism="PLAIN"/)
when :plain_sent
EM.stop
val.should match(/stream:stream/)
else
EM.stop
false
end
end
end
it 'will ignore methods it does not understand' do
state = nil
mocked_server(3) do |val, server|
case state
when nil
state = :started
server.send_data ""
server.send_data "CRAM-MD5PLAIN"
val.should match(/stream:stream/)
when :started
state = :auth_sent
server.send_data ""
Nokogiri::XML(val).to_xml.should == Nokogiri::XML('bkBkAG4AcGFzcw==').to_xml
when :auth_sent
EM.stop
state = :complete
val.should match(/stream:stream/)
else
EM.stop
false
end
end
end
%w[ aborted
incorrect-encoding
invalid-authzid
invalid-mechanism
mechanism-too-weak
not-authorized
temporary-auth-failure
].each do |error_type|
it "fails on #{error_type}" do
client.expects(:receive_data).with do |n|
n.name.should == error_type.gsub('-','_').to_sym
end
state = nil
mocked_server(3) do |val, server|
case state
when nil
state = :started
server.send_data "PLAIN"
val.should match(/stream:stream/)
when :started
state = :auth_sent
server.send_data "<#{error_type} />"
Nokogiri::XML(val).to_xml.should == Nokogiri::XML('bkBkAG4AcGFzcw==').to_xml
when :auth_sent
EM.stop
state = :complete
val.should match(/\/stream:stream/)
else
EM.stop
false
end
end
end
end
it 'fails when an unknown node comes through during SASL negotiation' do
client.expects(:receive_data).with do |n|
n.should be_instance_of Blather::UnknownResponse
n.node.element_name.should == 'foo-bar'
end
state = nil
mocked_server(3) do |val, server|
case state
when nil
state = :started
server.send_data "PLAIN"
val.should match(/stream:stream/)
when :started
state = :auth_sent
server.send_data ""
Nokogiri::XML(val).to_xml.should == Nokogiri::XML('bkBkAG4AcGFzcw==').to_xml
when :auth_sent
EM.stop
state = :complete
val.should match(/\/stream:stream/)
else
EM.stop
false
end
end
end
context "when the JID doesn't set a resource" do
let(:jid) { Blather::JID.new 'n@d' }
it 'will bind to a resource set by the server' do
state = nil
mocked_server(3) do |val, server|
case state
when nil
state = :started
server.send_data ""
server.send_data ""
val.should match(/stream:stream/)
when :started
state = :complete
val =~ %r{]+id="([^"]+)"}
server.send_data "#{jid}/server_resource"
server.send_data ""
val.should match(%r{})
when :complete
EM.stop
@stream.jid.should == Blather::JID.new('n@d/server_resource')
else
EM.stop
false
end
end
end
it 'will error out if the bind ID mismatches' do
state = nil
mocked_server(3) do |val, server|
case state
when nil
state = :started
server.send_data ""
server.send_data ""
val.should match(/stream:stream/)
when :started
state = :complete
val =~ %r{]+id="([^"]+)"}
client.expects(:receive_data).with("BIND result ID mismatch. Expected: #{$1}. Received: #{$1}-bad")
server.send_data "#{jid}/server_resource"
val.should match(%r{})
when :complete
EM.stop
true
else
EM.stop
false
end
end
end
end
it 'will bind to a resource set by the client' do
state = nil
mocked_server(3) do |val, server|
case state
when nil
state = :started
server.send_data ""
val.should match(/stream:stream/)
when :started
state = :complete
doc = parse_stanza val
doc.xpath('/iq/bind_ns:bind/bind_ns:resource[.="r"]', :bind_ns => Blather::Stream::Resource::BIND_NS).should_not be_empty
server.send_data "#{jid}"
server.send_data ""
true
when :complete
EM.stop
@stream.jid.should == Blather::JID.new('n@d/r')
else
EM.stop
false
end
end
end
it 'will return an error if resource binding errors out' do
client.expects(:receive_data).with do |n|
n.name.should == :bad_request
end
state = nil
mocked_server(3) do |val, server|
case state
when nil
state = :started
server.send_data ""
val.should match(/stream:stream/)
when :started
state = :complete
doc = parse_stanza val
doc.xpath('/iq/bind_ns:bind/bind_ns:resource[.="r"]', :bind_ns => Blather::Stream::Resource::BIND_NS).should_not be_empty
server.send_data "r"
true
when :complete
EM.stop
val.should match(/\/stream:stream/)
else
EM.stop
false
end
end
end
it 'will return an error if an unknown node comes through during resouce binding' do
client.expects(:receive_data).with do |n|
n.should be_instance_of Blather::UnknownResponse
n.node.element_name.should == 'foo-bar'
end
state = nil
mocked_server(3) do |val, server|
case state
when nil
state = :started
server.send_data ""
server.send_data ""
val.should match(/stream:stream/)
when :started
state = :complete
doc = parse_stanza val
doc.xpath('/iq/bind_ns:bind/bind_ns:resource[.="r"]', :bind_ns => Blather::Stream::Resource::BIND_NS).should_not be_empty
server.send_data ""
true
when :complete
EM.stop
val.should match(/\/stream:stream/)
else
EM.stop
false
end
end
end
it 'will establish a session if requested' do
client.expects(:post_init)
state = nil
mocked_server(3) do |val, server|
case state
when nil
state = :started
server.send_data ""
server.send_data ""
val.should match(/stream:stream/)
when :started
state = :completed
doc = parse_stanza val
doc.find('/iq[@type="set" and @to="d"]/sess_ns:session', :sess_ns => Blather::Stream::Session::SESSION_NS).should_not be_empty
server.send_data ""
server.send_data ""
true
when :completed
EM.stop
true
else
EM.stop
false
end
end
end
it 'will establish a session only after a bind' do
# fixes #95 client auth issue w/ Tigase: handles random order of stream:features items, f.e. before
# thx @pmashchak
state = nil
mocked_server(3) do |val, server|
case state
when nil
state = :started
server.send_data ""
server.send_data ""
val.should match(/stream:stream/)
when :started
state = :complete
doc = parse_stanza val
doc.find('/iq[@type="set"]/bind_ns:bind', :bind_ns => Blather::Stream::Resource::BIND_NS).should_not be_empty
server.send_data "#{client.jid}"
true
when :complete
doc = parse_stanza val
doc.find('/iq[@type="set"]/sess_ns:session', :sess_ns => Blather::Stream::Session::SESSION_NS).should_not be_empty
EM.stop
true
else
EM.stop
false
end
end
end
it 'will attempt to establish a session immediately after a bind' do
state = nil
mocked_server(3) do |val, server|
case state
when nil
state = :started
server.send_data ""
server.send_data ""
val.should match(/stream:stream/)
when :started
state = :complete
doc = parse_stanza val
doc.find('/iq[@type="set"]/bind_ns:bind', :bind_ns => Blather::Stream::Resource::BIND_NS).should_not be_empty
server.send_data "#{client.jid}"
true
when :complete
doc = parse_stanza val
doc.find('/iq[@type="set"]/sess_ns:session', :sess_ns => Blather::Stream::Session::SESSION_NS).should_not be_empty
EM.stop
true
else
EM.stop
false
end
end
end
it 'will return an error if session establishment errors out' do
client.expects(:receive_data).with do |n|
n.name.should == :internal_server_error
end
state = nil
mocked_server(3) do |val, server|
case state
when nil
state = :started
server.send_data ""
server.send_data ""
val.should match(/stream:stream/)
when :started
state = :completed
doc = parse_stanza val
doc.find('/iq[@type="set" and @to="d"]/sess_ns:session', :sess_ns => Blather::Stream::Session::SESSION_NS).should_not be_empty
server.send_data ""
true
when :completed
EM.stop
val.should match(/\/stream:stream/)
else
EM.stop
false
end
end
end
it 'will return an error if an unknown node come through during session establishment' do
client.expects(:receive_data).with do |n|
n.should be_instance_of Blather::UnknownResponse
n.node.element_name.should == 'foo-bar'
end
state = nil
mocked_server(3) do |val, server|
case state
when nil
state = :started
server.send_data ""
server.send_data ""
val.should match(/stream:stream/)
when :started
state = :completed
doc = parse_stanza val
doc.find('/iq[@type="set" and @to="d"]/sess_ns:session', :sess_ns => Blather::Stream::Session::SESSION_NS).should_not be_empty
server.send_data ''
true
when :completed
EM.stop
val.should match(/\/stream:stream/)
else
EM.stop
false
end
end
end
it 'sends client an error and reply to the server on parse error' do
client.expects(:receive_data).with do |v|
v.should be_kind_of Blather::ParseError
v.message.should match(/match/)
end
state = nil
mocked_server(3) do |val, server|
case state
when nil
state = :started
server.send_data ""
server.send_data ""
val.should match(/stream:stream/)
when :started
state = :parse_error
val.should match(/bind/)
server.send_data ""
true
when :parse_error
EM.stop
val.should == ""
else
EM.stop
false
end
end
end
it 'sends stanzas to the wire ensuring "from" is the full JID if set' do
msg = Blather::Stanza::Message.new 'to@jid.com', 'body'
msg.from = 'node@jid.com'
comp = Blather::Stream::Client.new nil, client, 'node@jid.com/resource', 'pass'
comp.expects(:send_data).with { |s| s.should match(/^]*from="node@jid\.com\/resource"/) }
comp.send msg
end
it 'sends stanzas to the wire leaving "from" nil if not set' do
msg = Blather::Stanza::Message.new 'to@jid.com', 'body'
comp = Blather::Stream::Client.new nil, client, 'node@jid.com/resource', 'pass'
comp.expects(:send_data).with { |s| s.should_not match(/^]*from=/); true }
comp.send msg
end
it 'sends stanza errors to the wire correctly' do
stanza = Blather::Stanza::Iq.new :set, 'foo@bar.com', '123'
error = Blather::StanzaError.new(stanza, 'registration-required', :cancel)
comp = Blather::Stream::Client.new nil, client, 'node@jid.com/resource', 'pass'
comp.expects(:send_data).with { |s| s.should match(/"
server.send_data "PLAIN"
val.should match(/stream:stream/)
when :sasl_attempted
state = :sasl_failed
server.send_data ""
val.should match(/auth/)
when :sasl_failed
state = :registered
server.send_data ""
val.should match(/jabber:iq:register/)
when :registered
state = :authenticated
server.send_data ""
val.should match(/mechanism="PLAIN"/)
when :authenticated
EM.stop
val.should match(/stream:stream/)
else
EM.stop
false
end
end
end
it 'fails when in-band registration failed' do
client.expects(:receive_data).with { |n| n.should be_instance_of Blather::BlatherError }
state = nil
mocked_server(4) do |val, server|
case state
when nil
state = :sasl_attempted
server.send_data ""
server.send_data "PLAIN"
val.should match(/stream:stream/)
when :sasl_attempted
state = :sasl_failed
server.send_data ""
val.should match(/auth/)
when :sasl_failed
state = :registration_failed
server.send_data ""
val.should match(/jabber:iq:register/)
when :registration_failed
EM.stop
val.should match(/\/stream:stream/)
else
EM.stop
false
end
end
end
end