vines 0.4.5 → 0.4.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Gemfile +3 -0
- data/README.md +48 -0
- data/Rakefile +6 -58
- data/bin/vines +12 -2
- data/conf/certs/ca-bundle.crt +568 -39
- data/conf/config.rb +9 -42
- data/lib/vines.rb +1 -8
- data/lib/vines/command/cert.rb +4 -4
- data/lib/vines/command/init.rb +3 -3
- data/lib/vines/config.rb +9 -0
- data/lib/vines/kit.rb +2 -7
- data/lib/vines/storage/local.rb +50 -17
- data/lib/vines/store.rb +6 -4
- data/lib/vines/stream.rb +1 -1
- data/lib/vines/stream/http/session.rb +0 -0
- data/lib/vines/stream/http/sessions.rb +0 -0
- data/lib/vines/stream/parser.rb +3 -2
- data/lib/vines/token_bucket.rb +19 -10
- data/lib/vines/version.rb +1 -1
- data/test/cluster/publisher_test.rb +45 -33
- data/test/cluster/sessions_test.rb +32 -39
- data/test/cluster/subscriber_test.rb +93 -78
- data/test/config/host_test.rb +2 -4
- data/test/config/pubsub_test.rb +132 -126
- data/test/config_test.rb +2 -4
- data/test/contact_test.rb +80 -66
- data/test/error_test.rb +54 -55
- data/test/jid_test.rb +1 -2
- data/test/kit_test.rb +22 -17
- data/test/router_test.rb +187 -146
- data/test/stanza/iq/disco_info_test.rb +59 -59
- data/test/stanza/iq/disco_items_test.rb +36 -34
- data/test/stanza/iq/private_storage_test.rb +138 -143
- data/test/stanza/iq/roster_test.rb +198 -175
- data/test/stanza/iq/session_test.rb +17 -18
- data/test/stanza/iq/vcard_test.rb +117 -116
- data/test/stanza/iq/version_test.rb +47 -46
- data/test/stanza/iq_test.rb +53 -49
- data/test/stanza/message_test.rb +92 -89
- data/test/stanza/presence/probe_test.rb +2 -5
- data/test/stanza/presence/subscribe_test.rb +67 -54
- data/test/stanza/pubsub/create_test.rb +86 -108
- data/test/stanza/pubsub/delete_test.rb +141 -114
- data/test/stanza/pubsub/publish_test.rb +256 -320
- data/test/stanza/pubsub/subscribe_test.rb +169 -150
- data/test/stanza/pubsub/unsubscribe_test.rb +111 -142
- data/test/stanza_test.rb +61 -54
- data/test/storage/ldap_test.rb +1 -2
- data/test/storage/local_test.rb +3 -5
- data/test/storage/null_test.rb +3 -4
- data/test/storage/storage_tests.rb +1 -3
- data/test/storage_test.rb +1 -2
- data/test/store_test.rb +1 -2
- data/test/stream/client/auth_test.rb +61 -63
- data/test/stream/client/ready_test.rb +7 -8
- data/test/stream/client/session_test.rb +19 -18
- data/test/stream/component/handshake_test.rb +40 -37
- data/test/stream/component/ready_test.rb +76 -61
- data/test/stream/component/start_test.rb +7 -8
- data/test/stream/http/auth_test.rb +3 -4
- data/test/stream/http/ready_test.rb +52 -60
- data/test/stream/http/request_test.rb +1 -3
- data/test/stream/http/sessions_test.rb +2 -3
- data/test/stream/http/start_test.rb +3 -4
- data/test/stream/parser_test.rb +3 -4
- data/test/stream/sasl_test.rb +105 -86
- data/test/stream/server/auth_test.rb +40 -36
- data/test/stream/server/outbound/auth_test.rb +3 -4
- data/test/stream/server/ready_test.rb +51 -51
- data/test/test_helper.rb +42 -0
- data/test/token_bucket_test.rb +38 -18
- data/test/user_test.rb +79 -49
- data/vines.gemspec +33 -0
- data/web/chat/javascripts/app.js +1 -1
- data/web/lib/coffeescripts/layout.coffee +1 -1
- data/web/lib/javascripts/base.js +10 -10
- data/web/lib/javascripts/jquery.js +4 -4
- metadata +31 -128
- data/README +0 -35
- data/lib/vines/storage/couchdb.rb +0 -129
- data/lib/vines/storage/mongodb.rb +0 -132
- data/lib/vines/storage/redis.rb +0 -127
- data/lib/vines/storage/sql.rb +0 -220
- data/test/rake_test_loader.rb +0 -17
- data/test/storage/couchdb_test.rb +0 -107
- data/test/storage/mock_mongo.rb +0 -40
- data/test/storage/mongodb_test.rb +0 -81
- data/test/storage/redis_test.rb +0 -51
- data/test/storage/sql_test.rb +0 -62
data/test/config_test.rb
CHANGED
@@ -1,10 +1,8 @@
|
|
1
1
|
# encoding: UTF-8
|
2
2
|
|
3
|
-
require '
|
4
|
-
require 'vines'
|
5
|
-
require 'minitest/autorun'
|
3
|
+
require 'test_helper'
|
6
4
|
|
7
|
-
|
5
|
+
describe Vines::Config do
|
8
6
|
def test_missing_host
|
9
7
|
assert_raises(RuntimeError) do
|
10
8
|
Vines::Config.new do
|
data/test/contact_test.rb
CHANGED
@@ -1,88 +1,102 @@
|
|
1
1
|
# encoding: UTF-8
|
2
2
|
|
3
|
-
require '
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
assert_nil alice <=> 42
|
14
|
-
|
15
|
-
assert alice == alice2
|
16
|
-
assert alice.eql?(alice2)
|
17
|
-
assert alice.hash == alice2.hash
|
18
|
-
|
19
|
-
refute alice == hatter
|
20
|
-
refute alice.eql?(hatter)
|
21
|
-
refute alice.hash == hatter.hash
|
3
|
+
require 'test_helper'
|
4
|
+
|
5
|
+
describe Vines::Contact do
|
6
|
+
subject do
|
7
|
+
Vines::Contact.new(
|
8
|
+
jid: 'alice@wonderland.lit',
|
9
|
+
name: "Alice",
|
10
|
+
groups: %w[Friends Buddies],
|
11
|
+
subscription: 'from')
|
22
12
|
end
|
23
13
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
end
|
14
|
+
describe 'contact equality checks' do
|
15
|
+
let(:alice) { Vines::Contact.new(jid: 'alice@wonderland.lit') }
|
16
|
+
let(:hatter) { Vines::Contact.new(jid: 'hatter@wonderland.lit') }
|
28
17
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
end
|
18
|
+
it 'uses class in equality check' do
|
19
|
+
(subject <=> 42).must_be_nil
|
20
|
+
end
|
33
21
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
22
|
+
it 'is equal to itself' do
|
23
|
+
assert subject == subject
|
24
|
+
assert subject.eql?(subject)
|
25
|
+
assert subject.hash == subject.hash
|
26
|
+
end
|
39
27
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
}.strip.gsub(/\n/, '').gsub(/\s{2,}/, '')
|
28
|
+
it 'is equal to another contact with the same jid' do
|
29
|
+
assert subject == alice
|
30
|
+
assert subject.eql?(alice)
|
31
|
+
assert subject.hash == alice.hash
|
32
|
+
end
|
46
33
|
|
47
|
-
|
34
|
+
it 'is not equal to a different jid' do
|
35
|
+
refute subject == hatter
|
36
|
+
refute subject.eql?(hatter)
|
37
|
+
refute subject.hash == hatter.hash
|
38
|
+
end
|
48
39
|
end
|
49
40
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
:
|
54
|
-
:groups => %w[Friends Buddies],
|
55
|
-
:subscription => 'from')
|
56
|
-
|
57
|
-
recipient = MiniTest::Mock.new
|
58
|
-
recipient.expect(:user, Vines::User.new(:jid => 'hatter@wonderland.lit'))
|
59
|
-
def recipient.nodes; @nodes; end
|
60
|
-
def recipient.write(node)
|
61
|
-
@nodes ||= []
|
62
|
-
@nodes << node
|
41
|
+
describe 'initialize' do
|
42
|
+
it 'raises when not given a jid' do
|
43
|
+
-> { Vines::Contact.new }.must_raise ArgumentError
|
44
|
+
-> { Vines::Contact.new(jid: '') }.must_raise ArgumentError
|
63
45
|
end
|
64
46
|
|
65
|
-
|
66
|
-
|
67
|
-
|
47
|
+
it 'accepts a domain-only jid' do
|
48
|
+
contact = Vines::Contact.new(jid: 'tea.wonderland.lit')
|
49
|
+
contact.jid.to_s.must_equal 'tea.wonderland.lit'
|
50
|
+
end
|
51
|
+
end
|
68
52
|
|
69
|
-
|
70
|
-
|
71
|
-
|
53
|
+
describe '#to_roster_xml' do
|
54
|
+
let(:expected) do
|
55
|
+
node(%q{
|
72
56
|
<item jid="alice@wonderland.lit" name="Alice" subscription="from">
|
73
57
|
<group>Buddies</group>
|
74
58
|
<group>Friends</group>
|
75
59
|
</item>
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
60
|
+
})
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'sorts group names' do
|
64
|
+
subject.to_roster_xml.must_equal expected
|
65
|
+
end
|
81
66
|
end
|
82
67
|
|
83
|
-
|
68
|
+
describe '#send_roster_push' do
|
69
|
+
let(:recipient) { MiniTest::Mock.new }
|
70
|
+
let(:expected) do
|
71
|
+
node(%q{
|
72
|
+
<iq to="hatter@wonderland.lit" type="set">
|
73
|
+
<query xmlns="jabber:iq:roster">
|
74
|
+
<item jid="alice@wonderland.lit" name="Alice" subscription="from">
|
75
|
+
<group>Buddies</group>
|
76
|
+
<group>Friends</group>
|
77
|
+
</item>
|
78
|
+
</query>
|
79
|
+
</iq>
|
80
|
+
})
|
81
|
+
end
|
84
82
|
|
85
|
-
|
86
|
-
|
83
|
+
before do
|
84
|
+
recipient.expect :user, Vines::User.new(jid: 'hatter@wonderland.lit')
|
85
|
+
class << recipient
|
86
|
+
attr_accessor :nodes
|
87
|
+
def write(node)
|
88
|
+
@nodes ||= []
|
89
|
+
@nodes << node
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
it '' do
|
95
|
+
subject.send_roster_push(recipient)
|
96
|
+
recipient.verify
|
97
|
+
recipient.nodes.size.must_equal 1
|
98
|
+
recipient.nodes.first.remove_attribute('id') # id is random
|
99
|
+
recipient.nodes.first.must_equal expected
|
100
|
+
end
|
87
101
|
end
|
88
102
|
end
|
data/test/error_test.rb
CHANGED
@@ -1,59 +1,58 @@
|
|
1
1
|
# encoding: UTF-8
|
2
2
|
|
3
|
-
require '
|
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
|
-
Nokogiri::XML(xml).root
|
3
|
+
require 'test_helper'
|
4
|
+
|
5
|
+
describe Vines::XmppError do
|
6
|
+
describe Vines::SaslErrors do
|
7
|
+
it 'does not require a text element' do
|
8
|
+
expected = %q{<failure xmlns="urn:ietf:params:xml:ns:xmpp-sasl"><temporary-auth-failure/></failure>}
|
9
|
+
Vines::SaslErrors::TemporaryAuthFailure.new.to_xml.must_equal expected
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'includes a text element when message is given' do
|
13
|
+
text = %q{<text xml:lang="en">busted</text>}
|
14
|
+
expected = %q{<failure xmlns="urn:ietf:params:xml:ns:xmpp-sasl"><temporary-auth-failure/>%s</failure>} % text
|
15
|
+
Vines::SaslErrors::TemporaryAuthFailure.new('busted').to_xml.must_equal expected
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe Vines::StreamErrors do
|
20
|
+
it 'does not require a text element' do
|
21
|
+
expected = %q{<stream:error><internal-server-error xmlns="urn:ietf:params:xml:ns:xmpp-streams"/></stream:error>}
|
22
|
+
Vines::StreamErrors::InternalServerError.new.to_xml.must_equal expected
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'includes a text element when message is given' do
|
26
|
+
text = %q{<text xmlns="urn:ietf:params:xml:ns:xmpp-streams" xml:lang="en">busted</text>}
|
27
|
+
expected = %q{<stream:error><internal-server-error xmlns="urn:ietf:params:xml:ns:xmpp-streams"/>%s</stream:error>} % text
|
28
|
+
Vines::StreamErrors::InternalServerError.new('busted').to_xml.must_equal expected
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe Vines::StanzaErrors do
|
33
|
+
it 'raises when given a bad type' do
|
34
|
+
node = node('<message/>')
|
35
|
+
-> { Vines::StanzaErrors::BadRequest.new(node, 'bogus') }.must_raise RuntimeError
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'raises when given a bad stanza' do
|
39
|
+
node = node('<bogus/>')
|
40
|
+
-> { Vines::StanzaErrors::BadRequest.new(node, 'modify') }.must_raise RuntimeError
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'does not require a text element' do
|
44
|
+
error = %q{<error type="modify"><bad-request xmlns="urn:ietf:params:xml:ns:xmpp-stanzas"/></error>}
|
45
|
+
expected = %q{<message from="hatter@wonderland.lit" to="alice@wonderland.lit" type="error">%s</message>} % error
|
46
|
+
node = node(%Q{<message from="alice@wonderland.lit" to="hatter@wonderland.lit"/>})
|
47
|
+
Vines::StanzaErrors::BadRequest.new(node, 'modify').to_xml.must_equal expected
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'includes a text element when message is given' do
|
51
|
+
text = %q{<text xmlns="urn:ietf:params:xml:ns:xmpp-stanzas" xml:lang="en">busted</text>}
|
52
|
+
error = %q{<error type="modify"><bad-request xmlns="urn:ietf:params:xml:ns:xmpp-stanzas"/>%s</error>} % text
|
53
|
+
expected = %q{<message id="42" type="error">%s</message>} % error
|
54
|
+
node = node(%Q{<message id="42"/>})
|
55
|
+
Vines::StanzaErrors::BadRequest.new(node, 'modify', 'busted').to_xml.must_equal expected
|
56
|
+
end
|
58
57
|
end
|
59
58
|
end
|
data/test/jid_test.rb
CHANGED
data/test/kit_test.rb
CHANGED
@@ -1,26 +1,31 @@
|
|
1
1
|
# encoding: UTF-8
|
2
2
|
|
3
|
-
require '
|
4
|
-
require 'minitest/autorun'
|
3
|
+
require 'test_helper'
|
5
4
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
5
|
+
describe Vines::Kit do
|
6
|
+
describe '#hmac' do
|
7
|
+
it 'generates a SHA-512 HMAC' do
|
8
|
+
Vines::Kit.hmac('secret', 'username').length.must_equal 128
|
9
|
+
assert_equal Vines::Kit.hmac('s1', 'u1'), Vines::Kit.hmac('s1', 'u1')
|
10
|
+
refute_equal Vines::Kit.hmac('s1', 'u1'), Vines::Kit.hmac('s2', 'u1')
|
11
|
+
refute_equal Vines::Kit.hmac('s1', 'u1'), Vines::Kit.hmac('s1', 'u2')
|
12
|
+
end
|
12
13
|
end
|
13
14
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
15
|
+
describe '#uuid' do
|
16
|
+
it 'returns a random uuid' do
|
17
|
+
ids = Array.new(1000) { Vines::Kit.uuid }
|
18
|
+
assert ids.all? {|id| !id.nil? }
|
19
|
+
assert ids.all? {|id| id.length == 36 }
|
20
|
+
assert ids.all? {|id| id.match(/\w{8}-\w{4}-[4]\w{3}-[89ab]\w{3}-\w{12}/) }
|
21
|
+
ids.uniq.length.must_equal ids.length
|
22
|
+
end
|
20
23
|
end
|
21
24
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
+
describe '#auth_token' do
|
26
|
+
it 'returns a random 128 character token' do
|
27
|
+
Vines::Kit.auth_token.wont_equal Vines::Kit.auth_token
|
28
|
+
Vines::Kit.auth_token.length.must_equal 128
|
29
|
+
end
|
25
30
|
end
|
26
31
|
end
|
data/test/router_test.rb
CHANGED
@@ -1,202 +1,243 @@
|
|
1
1
|
# encoding: UTF-8
|
2
2
|
|
3
|
-
require '
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
3
|
+
require 'test_helper'
|
4
|
+
|
5
|
+
describe Vines::Router do
|
6
|
+
subject { Vines::Router.new(config) }
|
7
|
+
let(:alice) { Vines::JID.new('alice@wonderland.lit/tea') }
|
8
|
+
let(:hatter) { 'hatter@wonderland.lit/cake' }
|
9
|
+
let(:romeo) { 'romeo@verona.lit/party' }
|
10
|
+
let(:config) do
|
11
|
+
Vines::Config.new do
|
11
12
|
host 'wonderland.lit' do
|
12
13
|
storage(:fs) { dir Dir.tmpdir }
|
13
14
|
components 'tea' => 'secr3t'
|
14
15
|
end
|
15
16
|
end
|
16
|
-
@router = Vines::Router.new(@config)
|
17
17
|
end
|
18
18
|
|
19
|
-
|
20
|
-
cake
|
21
|
-
|
22
|
-
|
23
|
-
assert_equal 0, @router.size
|
19
|
+
describe '#connected_resources' do
|
20
|
+
let(:cake) { 'alice@wonderland.lit/cake' }
|
21
|
+
let(:stream1) { stream(alice) }
|
22
|
+
let(:stream2) { stream(cake) }
|
24
23
|
|
25
|
-
|
26
|
-
|
27
|
-
|
24
|
+
it 'is empty before any streams are connected' do
|
25
|
+
subject.connected_resources(alice, alice).size.must_equal 0
|
26
|
+
subject.connected_resources(cake, alice).size.must_equal 0
|
27
|
+
subject.size.must_equal 0
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'returns only one stream matching full jid' do
|
31
|
+
subject << stream1
|
32
|
+
subject << stream2
|
28
33
|
|
29
|
-
|
30
|
-
|
34
|
+
streams = subject.connected_resources(alice, alice)
|
35
|
+
streams.size.must_equal 1
|
36
|
+
streams.first.user.jid.must_equal alice
|
31
37
|
|
32
|
-
|
33
|
-
|
38
|
+
streams = subject.connected_resources(cake, alice)
|
39
|
+
streams.size.must_equal 1
|
40
|
+
streams.first.user.jid.to_s.must_equal cake
|
41
|
+
end
|
34
42
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
43
|
+
it 'returns all streams matching bare jid' do
|
44
|
+
subject << stream1
|
45
|
+
subject << stream2
|
46
|
+
|
47
|
+
streams = subject.connected_resources(alice.bare, alice)
|
48
|
+
streams.size.must_equal 2
|
49
|
+
subject.size.must_equal 2
|
50
|
+
end
|
39
51
|
end
|
40
52
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
@router << stream1
|
45
|
-
@router << stream2
|
53
|
+
describe '#connected_resources with permissions' do
|
54
|
+
let(:stream1) { stream(alice) }
|
55
|
+
let(:stream2) { stream(romeo) }
|
46
56
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
57
|
+
before do
|
58
|
+
subject << stream1
|
59
|
+
subject << stream2
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'denies access when cross domain messages is off' do
|
63
|
+
subject.connected_resources(alice, romeo).size.must_equal 0
|
64
|
+
end
|
51
65
|
|
52
|
-
|
53
|
-
|
66
|
+
it 'allows access when cross domain messages is on' do
|
67
|
+
config.vhost('wonderland.lit').cross_domain_messages true
|
68
|
+
subject.connected_resources(alice, romeo).size.must_equal 1
|
69
|
+
end
|
54
70
|
end
|
55
71
|
|
56
|
-
|
57
|
-
cake
|
58
|
-
|
59
|
-
|
60
|
-
assert_equal 0, @router.size
|
72
|
+
describe '#available_resources' do
|
73
|
+
let(:cake) { 'alice@wonderland.lit/cake' }
|
74
|
+
let(:stream1) { stream(alice) }
|
75
|
+
let(:stream2) { stream(cake) }
|
61
76
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
@router << stream2
|
77
|
+
before do
|
78
|
+
stream1.send 'available?=', true
|
79
|
+
stream2.send 'available?=', false
|
80
|
+
end
|
67
81
|
|
68
|
-
|
69
|
-
|
82
|
+
it 'is empty before any streams are connected' do
|
83
|
+
subject.available_resources(alice, alice).size.must_equal 0
|
84
|
+
subject.available_resources(cake, alice).size.must_equal 0
|
85
|
+
subject.size.must_equal 0
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'returns available streams based on bare jid, not full jid' do
|
89
|
+
subject << stream1
|
90
|
+
subject << stream2
|
70
91
|
|
71
|
-
|
72
|
-
|
92
|
+
streams = [alice, cake, alice.bare].map do |jid|
|
93
|
+
subject.available_resources(jid, alice)
|
94
|
+
end.flatten
|
73
95
|
|
74
|
-
|
75
|
-
|
96
|
+
# should only have found alice's stream
|
97
|
+
streams.size.must_equal 3
|
98
|
+
streams.uniq.size.must_equal 1
|
99
|
+
streams.first.user.jid.must_equal alice
|
76
100
|
|
77
|
-
|
78
|
-
|
79
|
-
assert stream2.verify
|
101
|
+
subject.size.must_equal 2
|
102
|
+
end
|
80
103
|
end
|
81
104
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
105
|
+
describe '#interested_resources with no streams' do
|
106
|
+
it 'is empty before any streams are connected' do
|
107
|
+
subject.interested_resources(alice, alice).size.must_equal 0
|
108
|
+
subject.interested_resources(hatter, alice).size.must_equal 0
|
109
|
+
subject.interested_resources(alice, hatter, alice).size.must_equal 0
|
110
|
+
subject.size.must_equal 0
|
111
|
+
end
|
112
|
+
end
|
88
113
|
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
@router << stream1
|
93
|
-
@router << stream2
|
114
|
+
describe '#interested_resources' do
|
115
|
+
let(:stream1) { stream(alice) }
|
116
|
+
let(:stream2) { stream(hatter) }
|
94
117
|
|
95
|
-
|
118
|
+
before do
|
119
|
+
stream1.send 'interested?=', true
|
120
|
+
stream2.send 'interested?=', false
|
121
|
+
subject << stream1
|
122
|
+
subject << stream2
|
123
|
+
end
|
96
124
|
|
97
|
-
|
98
|
-
|
99
|
-
|
125
|
+
it 'does not find streams for unauthenticated jids' do
|
126
|
+
subject.interested_resources('bogus@wonderland.lit', alice).size.must_equal 0
|
127
|
+
end
|
100
128
|
|
101
|
-
|
102
|
-
|
129
|
+
it 'finds interested streams for full jids' do
|
130
|
+
subject.interested_resources(alice, hatter, alice).size.must_equal 1
|
131
|
+
subject.interested_resources([alice, hatter], alice).size.must_equal 1
|
132
|
+
subject.interested_resources(alice, hatter, alice)[0].user.jid.must_equal alice
|
133
|
+
end
|
103
134
|
|
104
|
-
|
105
|
-
|
135
|
+
it 'does not find streams for uninterested jids' do
|
136
|
+
subject.interested_resources(hatter, alice).size.must_equal 0
|
137
|
+
subject.interested_resources([hatter], alice).size.must_equal 0
|
138
|
+
end
|
106
139
|
|
107
|
-
|
108
|
-
|
109
|
-
|
140
|
+
it 'finds interested streams for bare jids' do
|
141
|
+
subject.interested_resources(alice.bare, alice).size.must_equal 1
|
142
|
+
subject.interested_resources(alice.bare, alice)[0].user.jid.must_equal alice
|
143
|
+
end
|
110
144
|
end
|
111
145
|
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
stream1, stream2 = stream(@alice), stream(hatter)
|
117
|
-
@router << stream1
|
118
|
-
@router << stream2
|
146
|
+
describe '#delete' do
|
147
|
+
let(:stream1) { stream(alice) }
|
148
|
+
let(:stream2) { stream(hatter) }
|
119
149
|
|
120
|
-
|
150
|
+
it 'correctly adds and removes streams' do
|
151
|
+
subject.size.must_equal 0
|
121
152
|
|
122
|
-
|
123
|
-
|
153
|
+
subject << stream1
|
154
|
+
subject << stream2
|
155
|
+
subject.size.must_equal 2
|
124
156
|
|
125
|
-
|
126
|
-
|
157
|
+
subject.delete(stream2)
|
158
|
+
subject.size.must_equal 1
|
127
159
|
|
128
|
-
|
129
|
-
|
160
|
+
subject.delete(stream2)
|
161
|
+
subject.size.must_equal 1
|
130
162
|
|
131
|
-
|
132
|
-
|
163
|
+
subject.delete(stream1)
|
164
|
+
subject.size.must_equal 0
|
165
|
+
end
|
133
166
|
end
|
134
167
|
|
135
|
-
|
136
|
-
stream1
|
137
|
-
stream2
|
138
|
-
@
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
168
|
+
describe 'load balanced component streams' do
|
169
|
+
let(:stream1) { component('tea.wonderland.lit') }
|
170
|
+
let(:stream2) { component('tea.wonderland.lit') }
|
171
|
+
let(:stanza) { node('<message from="alice@wonderland.lit" to="tea.wonderland.lit">test</message>')}
|
172
|
+
|
173
|
+
before do
|
174
|
+
subject << stream1
|
175
|
+
subject << stream2
|
176
|
+
end
|
177
|
+
|
178
|
+
it 'must evenly distribute routed stanzas to both streams' do
|
179
|
+
100.times { subject.route(stanza) }
|
180
|
+
|
181
|
+
(stream1.count + stream2.count).must_equal 100
|
182
|
+
stream1.count.must_be :>, 33
|
183
|
+
stream2.count.must_be :>, 33
|
184
|
+
end
|
148
185
|
end
|
149
186
|
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
187
|
+
describe 'load balanced s2s streams' do
|
188
|
+
let(:stream1) { s2s('wonderland.lit', 'verona.lit') }
|
189
|
+
let(:stream2) { s2s('wonderland.lit', 'verona.lit') }
|
190
|
+
let(:stanza) { node('<message from="alice@wonderland.lit" to="romeo@verona.lit">test</message>') }
|
191
|
+
|
192
|
+
before do
|
193
|
+
config.vhost('wonderland.lit').cross_domain_messages true
|
194
|
+
subject << stream1
|
195
|
+
subject << stream2
|
196
|
+
end
|
197
|
+
|
198
|
+
it 'must evenly distribute routed stanzas to both streams' do
|
199
|
+
100.times { subject.route(stanza) }
|
200
|
+
|
201
|
+
(stream1.count + stream2.count).must_equal 100
|
202
|
+
stream1.count.must_be :>, 33
|
203
|
+
stream2.count.must_be :>, 33
|
204
|
+
end
|
164
205
|
end
|
165
206
|
|
166
207
|
private
|
167
208
|
|
168
209
|
def stream(jid)
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
210
|
+
OpenStruct.new.tap do |stream|
|
211
|
+
stream.send('connected?=', true)
|
212
|
+
stream.stream_type = :client
|
213
|
+
stream.user = Vines::User.new(jid: jid)
|
214
|
+
end
|
174
215
|
end
|
175
216
|
|
176
217
|
def component(jid)
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
218
|
+
OpenStruct.new.tap do |stream|
|
219
|
+
stream.stream_type = :component
|
220
|
+
stream.remote_domain = jid
|
221
|
+
stream.send('ready?=', true)
|
222
|
+
def stream.count; @count || 0; end
|
223
|
+
def stream.write(stanza)
|
224
|
+
@count ||= 0
|
225
|
+
@count += 1
|
226
|
+
end
|
227
|
+
end
|
187
228
|
end
|
188
229
|
|
189
230
|
def s2s(domain, remote_domain)
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
231
|
+
OpenStruct.new.tap do |stream|
|
232
|
+
stream.stream_type = :server
|
233
|
+
stream.domain = domain
|
234
|
+
stream.remote_domain = remote_domain
|
235
|
+
stream.send('ready?=', true)
|
236
|
+
def stream.count; @count || 0; end
|
237
|
+
def stream.write(stanza)
|
238
|
+
@count ||= 0
|
239
|
+
@count += 1
|
240
|
+
end
|
241
|
+
end
|
201
242
|
end
|
202
243
|
end
|