vines 0.4.5 → 0.4.6

Sign up to get free protection for your applications and to get access to all the features.
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