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.
Files changed (89) hide show
  1. data/Gemfile +3 -0
  2. data/README.md +48 -0
  3. data/Rakefile +6 -58
  4. data/bin/vines +12 -2
  5. data/conf/certs/ca-bundle.crt +568 -39
  6. data/conf/config.rb +9 -42
  7. data/lib/vines.rb +1 -8
  8. data/lib/vines/command/cert.rb +4 -4
  9. data/lib/vines/command/init.rb +3 -3
  10. data/lib/vines/config.rb +9 -0
  11. data/lib/vines/kit.rb +2 -7
  12. data/lib/vines/storage/local.rb +50 -17
  13. data/lib/vines/store.rb +6 -4
  14. data/lib/vines/stream.rb +1 -1
  15. data/lib/vines/stream/http/session.rb +0 -0
  16. data/lib/vines/stream/http/sessions.rb +0 -0
  17. data/lib/vines/stream/parser.rb +3 -2
  18. data/lib/vines/token_bucket.rb +19 -10
  19. data/lib/vines/version.rb +1 -1
  20. data/test/cluster/publisher_test.rb +45 -33
  21. data/test/cluster/sessions_test.rb +32 -39
  22. data/test/cluster/subscriber_test.rb +93 -78
  23. data/test/config/host_test.rb +2 -4
  24. data/test/config/pubsub_test.rb +132 -126
  25. data/test/config_test.rb +2 -4
  26. data/test/contact_test.rb +80 -66
  27. data/test/error_test.rb +54 -55
  28. data/test/jid_test.rb +1 -2
  29. data/test/kit_test.rb +22 -17
  30. data/test/router_test.rb +187 -146
  31. data/test/stanza/iq/disco_info_test.rb +59 -59
  32. data/test/stanza/iq/disco_items_test.rb +36 -34
  33. data/test/stanza/iq/private_storage_test.rb +138 -143
  34. data/test/stanza/iq/roster_test.rb +198 -175
  35. data/test/stanza/iq/session_test.rb +17 -18
  36. data/test/stanza/iq/vcard_test.rb +117 -116
  37. data/test/stanza/iq/version_test.rb +47 -46
  38. data/test/stanza/iq_test.rb +53 -49
  39. data/test/stanza/message_test.rb +92 -89
  40. data/test/stanza/presence/probe_test.rb +2 -5
  41. data/test/stanza/presence/subscribe_test.rb +67 -54
  42. data/test/stanza/pubsub/create_test.rb +86 -108
  43. data/test/stanza/pubsub/delete_test.rb +141 -114
  44. data/test/stanza/pubsub/publish_test.rb +256 -320
  45. data/test/stanza/pubsub/subscribe_test.rb +169 -150
  46. data/test/stanza/pubsub/unsubscribe_test.rb +111 -142
  47. data/test/stanza_test.rb +61 -54
  48. data/test/storage/ldap_test.rb +1 -2
  49. data/test/storage/local_test.rb +3 -5
  50. data/test/storage/null_test.rb +3 -4
  51. data/test/storage/storage_tests.rb +1 -3
  52. data/test/storage_test.rb +1 -2
  53. data/test/store_test.rb +1 -2
  54. data/test/stream/client/auth_test.rb +61 -63
  55. data/test/stream/client/ready_test.rb +7 -8
  56. data/test/stream/client/session_test.rb +19 -18
  57. data/test/stream/component/handshake_test.rb +40 -37
  58. data/test/stream/component/ready_test.rb +76 -61
  59. data/test/stream/component/start_test.rb +7 -8
  60. data/test/stream/http/auth_test.rb +3 -4
  61. data/test/stream/http/ready_test.rb +52 -60
  62. data/test/stream/http/request_test.rb +1 -3
  63. data/test/stream/http/sessions_test.rb +2 -3
  64. data/test/stream/http/start_test.rb +3 -4
  65. data/test/stream/parser_test.rb +3 -4
  66. data/test/stream/sasl_test.rb +105 -86
  67. data/test/stream/server/auth_test.rb +40 -36
  68. data/test/stream/server/outbound/auth_test.rb +3 -4
  69. data/test/stream/server/ready_test.rb +51 -51
  70. data/test/test_helper.rb +42 -0
  71. data/test/token_bucket_test.rb +38 -18
  72. data/test/user_test.rb +79 -49
  73. data/vines.gemspec +33 -0
  74. data/web/chat/javascripts/app.js +1 -1
  75. data/web/lib/coffeescripts/layout.coffee +1 -1
  76. data/web/lib/javascripts/base.js +10 -10
  77. data/web/lib/javascripts/jquery.js +4 -4
  78. metadata +31 -128
  79. data/README +0 -35
  80. data/lib/vines/storage/couchdb.rb +0 -129
  81. data/lib/vines/storage/mongodb.rb +0 -132
  82. data/lib/vines/storage/redis.rb +0 -127
  83. data/lib/vines/storage/sql.rb +0 -220
  84. data/test/rake_test_loader.rb +0 -17
  85. data/test/storage/couchdb_test.rb +0 -107
  86. data/test/storage/mock_mongo.rb +0 -40
  87. data/test/storage/mongodb_test.rb +0 -81
  88. data/test/storage/redis_test.rb +0 -51
  89. data/test/storage/sql_test.rb +0 -62
@@ -1,10 +1,8 @@
1
1
  # encoding: UTF-8
2
2
 
3
- require 'tmpdir'
4
- require 'vines'
5
- require 'minitest/autorun'
3
+ require 'test_helper'
6
4
 
7
- class ConfigTest < MiniTest::Unit::TestCase
5
+ describe Vines::Config do
8
6
  def test_missing_host
9
7
  assert_raises(RuntimeError) do
10
8
  Vines::Config.new do
@@ -1,88 +1,102 @@
1
1
  # encoding: UTF-8
2
2
 
3
- require 'vines'
4
- require 'ext/nokogiri'
5
- require 'minitest/autorun'
6
-
7
- class ContactTest < MiniTest::Unit::TestCase
8
- def test_equality
9
- alice = Vines::Contact.new(:jid => 'alice@wonderland.lit')
10
- alice2 = Vines::Contact.new(:jid => 'alice@wonderland.lit')
11
- hatter = Vines::Contact.new(:jid => 'hatter@wonderland.lit')
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
- def test_initialize_missing_jid_raises
25
- assert_raises(ArgumentError) { Vines::Contact.new }
26
- assert_raises(ArgumentError) { Vines::Contact.new(:jid => '') }
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
- def test_initialize_domain_only_jid_does_not_raise
30
- contact = Vines::Contact.new(:jid => 'tea.wonderland.lit')
31
- assert_equal 'tea.wonderland.lit', contact.jid.to_s
32
- end
18
+ it 'uses class in equality check' do
19
+ (subject <=> 42).must_be_nil
20
+ end
33
21
 
34
- def test_to_roster_xml_sorts_groups
35
- contact = Vines::Contact.new(
36
- :jid => 'a@wonderland.lit',
37
- :name => "Contact 1",
38
- :groups => %w[B A])
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
- expected = %q{
41
- <item jid="a@wonderland.lit" name="Contact 1" subscription="none">
42
- <group>A</group>
43
- <group>B</group>
44
- </item>
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
- assert_equal expected, contact.to_roster_xml.to_xml(:indent => 0).gsub(/\n/, '')
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
- def test_send_roster_push
51
- contact = Vines::Contact.new(
52
- :jid => 'alice@wonderland.lit',
53
- :name => "Alice",
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
- contact.send_roster_push(recipient)
66
- assert recipient.verify
67
- assert_equal 1, recipient.nodes.size
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
- expected = node(%q{
70
- <iq to="hatter@wonderland.lit" type="set">
71
- <query xmlns="jabber:iq:roster">
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
- </query>
77
- </iq>
78
- }.strip.gsub(/\n/, '').gsub(/\s{2,}/, ''))
79
- recipient.nodes[0].remove_attribute('id') # id is random
80
- assert_equal expected, recipient.nodes[0]
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
- private
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
- def node(xml)
86
- Nokogiri::XML(xml).root
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
@@ -1,59 +1,58 @@
1
1
  # encoding: UTF-8
2
2
 
3
- require 'vines'
4
- require 'minitest/autorun'
5
-
6
- class ErrorTest < MiniTest::Unit::TestCase
7
- def test_sasl_error_without_text
8
- expected = %q{<failure xmlns="urn:ietf:params:xml:ns:xmpp-sasl"><temporary-auth-failure/></failure>}
9
- assert_equal expected, Vines::SaslErrors::TemporaryAuthFailure.new.to_xml
10
- end
11
-
12
- def test_sasl_error_with_text
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
- assert_equal expected, Vines::SaslErrors::TemporaryAuthFailure.new('busted').to_xml
16
- end
17
-
18
- def test_stream_error_without_text
19
- expected = %q{<stream:error><internal-server-error xmlns="urn:ietf:params:xml:ns:xmpp-streams"/></stream:error>}
20
- assert_equal expected, Vines::StreamErrors::InternalServerError.new.to_xml
21
- end
22
-
23
- def test_stream_error_with_text
24
- text = %q{<text xmlns="urn:ietf:params:xml:ns:xmpp-streams" xml:lang="en">busted</text>}
25
- expected = %q{<stream:error><internal-server-error xmlns="urn:ietf:params:xml:ns:xmpp-streams"/>%s</stream:error>} % text
26
- assert_equal expected, Vines::StreamErrors::InternalServerError.new('busted').to_xml
27
- end
28
-
29
- def test_stanza_error_with_bad_type
30
- node = node('<message/>')
31
- assert_raises(RuntimeError) { Vines::StanzaErrors::BadRequest.new(node, 'bogus') }
32
- end
33
-
34
- def test_stanza_error_with_bad_stanza
35
- node = node('<bogus/>')
36
- assert_raises(RuntimeError) { Vines::StanzaErrors::BadRequest.new(node, 'modify') }
37
- end
38
-
39
- def test_stanza_error_without_text
40
- error = %q{<error type="modify"><bad-request xmlns="urn:ietf:params:xml:ns:xmpp-stanzas"/></error>}
41
- expected = %q{<message from="hatter@wonderland.lit" to="alice@wonderland.lit" type="error">%s</message>} % error
42
- node = node(%Q{<message from="alice@wonderland.lit" to="hatter@wonderland.lit"/>})
43
- assert_equal expected, Vines::StanzaErrors::BadRequest.new(node, 'modify').to_xml
44
- end
45
-
46
- def test_stanza_error_with_text
47
- text = %q{<text xmlns="urn:ietf:params:xml:ns:xmpp-stanzas" xml:lang="en">busted</text>}
48
- error = %q{<error type="modify"><bad-request xmlns="urn:ietf:params:xml:ns:xmpp-stanzas"/>%s</error>} % text
49
- expected = %q{<message id="42" type="error">%s</message>} % error
50
- node = node(%Q{<message id="42"/>})
51
- assert_equal expected, Vines::StanzaErrors::BadRequest.new(node, 'modify', 'busted').to_xml
52
- end
53
-
54
- private
55
-
56
- def node(xml)
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
@@ -1,7 +1,6 @@
1
1
  # encoding: UTF-8
2
2
 
3
- require 'vines'
4
- require 'minitest/autorun'
3
+ require 'test_helper'
5
4
 
6
5
  describe Vines::JID do
7
6
  it 'handles empty input' do
@@ -1,26 +1,31 @@
1
1
  # encoding: UTF-8
2
2
 
3
- require 'vines'
4
- require 'minitest/autorun'
3
+ require 'test_helper'
5
4
 
6
- class KitTest < MiniTest::Unit::TestCase
7
- def test_hmac
8
- assert_equal 128, Vines::Kit.hmac('secret', 'username').length
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')
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
- def test_uuid
15
- ids = Array.new(1000) { Vines::Kit.uuid }
16
- assert ids.all? {|id| !id.nil? }
17
- assert ids.all? {|id| id.length == 36 }
18
- assert ids.all? {|id| id.match(/\w{8}-\w{4}-[4]\w{3}-[89ab]\w{3}-\w{12}/) }
19
- assert_equal ids.length, ids.uniq.length
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
- def test_auth_token
23
- refute_equal Vines::Kit.auth_token, Vines::Kit.auth_token
24
- assert_equal 128, Vines::Kit.auth_token.length
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
@@ -1,202 +1,243 @@
1
1
  # encoding: UTF-8
2
2
 
3
- require 'tmpdir'
4
- require 'vines'
5
- require 'minitest/autorun'
6
-
7
- class RouterTest < MiniTest::Unit::TestCase
8
- def setup
9
- @alice = Vines::JID.new('alice@wonderland.lit/tea')
10
- @config = Vines::Config.new do
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
- def test_connected_resources
20
- cake = 'alice@wonderland.lit/cake'
21
- assert_equal 0, @router.connected_resources(@alice, @alice).size
22
- assert_equal 0, @router.connected_resources(cake, @alice).size
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
- stream1, stream2 = stream(@alice), stream(cake)
26
- @router << stream1
27
- @router << stream2
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
- assert_equal 1, @router.connected_resources(@alice, @alice).size
30
- assert_equal @alice, @router.connected_resources(@alice, @alice)[0].user.jid
34
+ streams = subject.connected_resources(alice, alice)
35
+ streams.size.must_equal 1
36
+ streams.first.user.jid.must_equal alice
31
37
 
32
- assert_equal 1, @router.connected_resources(cake, @alice).size
33
- assert_equal cake, @router.connected_resources(cake, @alice)[0].user.jid.to_s
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
- assert_equal 2, @router.connected_resources(@alice.bare, @alice).size
36
- assert_equal 2, @router.size
37
- assert stream1.verify
38
- assert stream2.verify
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
- def test_connected_resources_checks_allowed
42
- romeo = 'romeo@verona.lit/party'
43
- stream1, stream2 = stream(@alice), stream(romeo)
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
- assert_equal 2, @router.size
48
- assert_equal 0, @router.connected_resources(@alice, romeo).size
49
- @config.vhost('wonderland.lit').cross_domain_messages true
50
- assert_equal 1, @router.connected_resources(@alice, romeo).size
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
- assert stream1.verify
53
- assert stream2.verify
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
- def test_available_resources
57
- cake = 'alice@wonderland.lit/cake'
58
- assert_equal 0, @router.available_resources(@alice, @alice).size
59
- assert_equal 0, @router.available_resources(cake, @alice).size
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
- stream1, stream2 = stream(@alice), stream(cake)
63
- stream1.expect(:available?, true)
64
- stream2.expect(:available?, false)
65
- @router << stream1
66
- @router << stream2
77
+ before do
78
+ stream1.send 'available?=', true
79
+ stream2.send 'available?=', false
80
+ end
67
81
 
68
- assert_equal 1, @router.available_resources(@alice, @alice).size
69
- assert_equal @alice, @router.available_resources(@alice, @alice)[0].user.jid
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
- assert_equal 1, @router.available_resources(cake, @alice).size
72
- assert_equal @alice, @router.available_resources(cake, @alice)[0].user.jid
92
+ streams = [alice, cake, alice.bare].map do |jid|
93
+ subject.available_resources(jid, alice)
94
+ end.flatten
73
95
 
74
- assert_equal 1, @router.available_resources(@alice.bare, @alice).size
75
- assert_equal @alice, @router.available_resources(@alice.bare, @alice)[0].user.jid
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
- assert_equal 2, @router.size
78
- assert stream1.verify
79
- assert stream2.verify
101
+ subject.size.must_equal 2
102
+ end
80
103
  end
81
104
 
82
- def test_interested_resources
83
- hatter = 'hatter@wonderland.lit/cake'
84
- assert_equal 0, @router.interested_resources(@alice, @alice).size
85
- assert_equal 0, @router.interested_resources(hatter, @alice).size
86
- assert_equal 0, @router.interested_resources(@alice, hatter, @alice).size
87
- assert_equal 0, @router.size
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
- stream1, stream2 = stream(@alice), stream(hatter)
90
- stream1.expect(:interested?, true)
91
- stream2.expect(:interested?, false)
92
- @router << stream1
93
- @router << stream2
114
+ describe '#interested_resources' do
115
+ let(:stream1) { stream(alice) }
116
+ let(:stream2) { stream(hatter) }
94
117
 
95
- assert_equal 0, @router.interested_resources('bogus@wonderland.lit', @alice).size
118
+ before do
119
+ stream1.send 'interested?=', true
120
+ stream2.send 'interested?=', false
121
+ subject << stream1
122
+ subject << stream2
123
+ end
96
124
 
97
- assert_equal 1, @router.interested_resources(@alice, hatter, @alice).size
98
- assert_equal 1, @router.interested_resources([@alice, hatter], @alice).size
99
- assert_equal @alice, @router.interested_resources(@alice, hatter, @alice)[0].user.jid
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
- assert_equal 0, @router.interested_resources(hatter, @alice).size
102
- assert_equal 0, @router.interested_resources([hatter], @alice).size
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
- assert_equal 1, @router.interested_resources(@alice.bare, @alice).size
105
- assert_equal @alice, @router.interested_resources(@alice.bare, @alice)[0].user.jid
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
- assert_equal 2, @router.size
108
- assert stream1.verify
109
- assert stream2.verify
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
- def test_delete
113
- hatter = 'hatter@wonderland.lit/cake'
114
- assert_equal 0, @router.size
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
- assert_equal 2, @router.size
150
+ it 'correctly adds and removes streams' do
151
+ subject.size.must_equal 0
121
152
 
122
- @router.delete(stream2)
123
- assert_equal 1, @router.size
153
+ subject << stream1
154
+ subject << stream2
155
+ subject.size.must_equal 2
124
156
 
125
- @router.delete(stream2)
126
- assert_equal 1, @router.size
157
+ subject.delete(stream2)
158
+ subject.size.must_equal 1
127
159
 
128
- @router.delete(stream1)
129
- assert_equal 0, @router.size
160
+ subject.delete(stream2)
161
+ subject.size.must_equal 1
130
162
 
131
- assert stream1.verify
132
- assert stream2.verify
163
+ subject.delete(stream1)
164
+ subject.size.must_equal 0
165
+ end
133
166
  end
134
167
 
135
- def test_multiple_component_streams_are_load_balanced
136
- stream1 = component('tea.wonderland.lit')
137
- stream2 = component('tea.wonderland.lit')
138
- @router << stream1
139
- @router << stream2
140
- stanza = Nokogiri::XML('<message from="alice@wonderland.lit" to="tea.wonderland.lit">test</message>').root
141
- 100.times { @router.route(stanza) }
142
-
143
- assert_equal 100, stream1.count + stream2.count
144
- assert stream1.count > 33
145
- assert stream2.count > 33
146
- assert stream1.verify
147
- assert stream2.verify
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
- def test_multiple_s2s_streams_are_load_balanced
151
- @config.vhost('wonderland.lit').cross_domain_messages true
152
- stream1 = s2s('wonderland.lit', 'verona.lit')
153
- stream2 = s2s('wonderland.lit', 'verona.lit')
154
- @router << stream1
155
- @router << stream2
156
- stanza = Nokogiri::XML('<message from="alice@wonderland.lit" to="romeo@verona.lit">test</message>').root
157
- 100.times { @router.route(stanza) }
158
-
159
- assert_equal 100, stream1.count + stream2.count
160
- assert stream1.count > 33
161
- assert stream2.count > 33
162
- assert stream1.verify
163
- assert stream2.verify
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
- stream = MiniTest::Mock.new
170
- stream.expect(:connected?, true)
171
- stream.expect(:stream_type, :client)
172
- stream.expect(:user, Vines::User.new(jid: jid))
173
- stream
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
- stream = MiniTest::Mock.new
178
- stream.expect(:stream_type, :component)
179
- stream.expect(:remote_domain, jid)
180
- stream.expect(:ready?, true)
181
- def stream.count; @count || 0; end
182
- def stream.write(stanza)
183
- @count ||= 0
184
- @count += 1
185
- end
186
- stream
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
- stream = MiniTest::Mock.new
191
- stream.expect(:stream_type, :server)
192
- stream.expect(:domain, domain)
193
- stream.expect(:remote_domain, remote_domain)
194
- stream.expect(:ready?, true)
195
- def stream.count; @count || 0; end
196
- def stream.write(stanza)
197
- @count ||= 0
198
- @count += 1
199
- end
200
- stream
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