# encoding: UTF-8
require 'test_helper'
describe Vines::Router do
subject { Vines::Router.new(config) }
let(:alice) { Vines::JID.new('alice@wonderland.lit/tea') }
let(:hatter) { 'hatter@wonderland.lit/cake' }
let(:romeo) { 'romeo@verona.lit/party' }
let(:config) do
Vines::Config.new do
host 'wonderland.lit' do
storage(:fs) { dir Dir.tmpdir }
components 'tea' => 'secr3t'
end
end
end
describe '#connected_resources' do
let(:cake) { 'alice@wonderland.lit/cake' }
let(:stream1) { stream(alice) }
let(:stream2) { stream(cake) }
it 'is empty before any streams are connected' do
subject.connected_resources(alice, alice).size.must_equal 0
subject.connected_resources(cake, alice).size.must_equal 0
subject.size.must_equal 0
end
it 'returns only one stream matching full jid' do
subject << stream1
subject << stream2
streams = subject.connected_resources(alice, alice)
streams.size.must_equal 1
streams.first.user.jid.must_equal alice
streams = subject.connected_resources(cake, alice)
streams.size.must_equal 1
streams.first.user.jid.to_s.must_equal cake
end
it 'returns all streams matching bare jid' do
subject << stream1
subject << stream2
streams = subject.connected_resources(alice.bare, alice)
streams.size.must_equal 2
subject.size.must_equal 2
end
end
describe '#connected_resources with permissions' do
let(:stream1) { stream(alice) }
let(:stream2) { stream(romeo) }
before do
subject << stream1
subject << stream2
end
it 'denies access when cross domain messages is off' do
subject.connected_resources(alice, romeo).size.must_equal 0
end
it 'allows access when cross domain messages is on' do
config.vhost('wonderland.lit').cross_domain_messages true
subject.connected_resources(alice, romeo).size.must_equal 1
end
end
describe '#available_resources' do
let(:cake) { 'alice@wonderland.lit/cake' }
let(:stream1) { stream(alice) }
let(:stream2) { stream(cake) }
before do
stream1.send 'available?=', true
stream2.send 'available?=', false
end
it 'is empty before any streams are connected' do
subject.available_resources(alice, alice).size.must_equal 0
subject.available_resources(cake, alice).size.must_equal 0
subject.size.must_equal 0
end
it 'returns available streams based on bare jid, not full jid' do
subject << stream1
subject << stream2
streams = [alice, cake, alice.bare].map do |jid|
subject.available_resources(jid, alice)
end.flatten
# should only have found alice's stream
streams.size.must_equal 3
streams.uniq.size.must_equal 1
streams.first.user.jid.must_equal alice
subject.size.must_equal 2
end
end
describe '#interested_resources with no streams' do
it 'is empty before any streams are connected' do
subject.interested_resources(alice, alice).size.must_equal 0
subject.interested_resources(hatter, alice).size.must_equal 0
subject.interested_resources(alice, hatter, alice).size.must_equal 0
subject.size.must_equal 0
end
end
describe '#interested_resources' do
let(:stream1) { stream(alice) }
let(:stream2) { stream(hatter) }
before do
stream1.send 'interested?=', true
stream2.send 'interested?=', false
subject << stream1
subject << stream2
end
it 'does not find streams for unauthenticated jids' do
subject.interested_resources('bogus@wonderland.lit', alice).size.must_equal 0
end
it 'finds interested streams for full jids' do
subject.interested_resources(alice, hatter, alice).size.must_equal 1
subject.interested_resources([alice, hatter], alice).size.must_equal 1
subject.interested_resources(alice, hatter, alice)[0].user.jid.must_equal alice
end
it 'does not find streams for uninterested jids' do
subject.interested_resources(hatter, alice).size.must_equal 0
subject.interested_resources([hatter], alice).size.must_equal 0
end
it 'finds interested streams for bare jids' do
subject.interested_resources(alice.bare, alice).size.must_equal 1
subject.interested_resources(alice.bare, alice)[0].user.jid.must_equal alice
end
end
describe '#delete' do
let(:stream1) { stream(alice) }
let(:stream2) { stream(hatter) }
it 'correctly adds and removes streams' do
subject.size.must_equal 0
subject << stream1
subject << stream2
subject.size.must_equal 2
subject.delete(stream2)
subject.size.must_equal 1
subject.delete(stream2)
subject.size.must_equal 1
subject.delete(stream1)
subject.size.must_equal 0
end
end
describe 'load balanced component streams' do
let(:stream1) { component('tea.wonderland.lit') }
let(:stream2) { component('tea.wonderland.lit') }
let(:stanza) { node('test')}
before do
subject << stream1
subject << stream2
end
it 'must evenly distribute routed stanzas to both streams' do
100.times { subject.route(stanza) }
(stream1.count + stream2.count).must_equal 100
stream1.count.must_be :>, 33
stream2.count.must_be :>, 33
end
end
describe 'load balanced s2s streams' do
let(:stream1) { s2s('wonderland.lit', 'verona.lit') }
let(:stream2) { s2s('wonderland.lit', 'verona.lit') }
let(:stanza) { node('test') }
before do
config.vhost('wonderland.lit').cross_domain_messages true
subject << stream1
subject << stream2
end
it 'must evenly distribute routed stanzas to both streams' do
100.times { subject.route(stanza) }
(stream1.count + stream2.count).must_equal 100
stream1.count.must_be :>, 33
stream2.count.must_be :>, 33
end
end
private
def stream(jid)
OpenStruct.new.tap do |stream|
stream.send('connected?=', true)
stream.stream_type = :client
stream.user = Vines::User.new(jid: jid)
end
end
def component(jid)
OpenStruct.new.tap do |stream|
stream.stream_type = :component
stream.remote_domain = jid
stream.send('ready?=', true)
def stream.count; @count || 0; end
def stream.write(stanza)
@count ||= 0
@count += 1
end
end
end
def s2s(domain, remote_domain)
OpenStruct.new.tap do |stream|
stream.stream_type = :server
stream.domain = domain
stream.remote_domain = remote_domain
stream.send('ready?=', true)
def stream.count; @count || 0; end
def stream.write(stanza)
@count ||= 0
@count += 1
end
end
end
end