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,53 +1,46 @@
1
1
  # encoding: UTF-8
2
2
 
3
- require 'vines'
4
- require 'ext/nokogiri'
3
+ require 'test_helper'
5
4
  require 'storage/storage_tests'
6
5
  require 'storage/mock_redis'
7
- require 'minitest/autorun'
8
6
 
9
- class ClusterSessionsTest < MiniTest::Unit::TestCase
10
- def setup
11
- @connection = MockRedis.new
12
- @cluster = MiniTest::Mock.new
13
- @cluster.expect(:connection, @connection)
14
- end
7
+ describe Vines::Cluster::Sessions do
8
+ subject { Vines::Cluster::Sessions.new(cluster) }
9
+ let(:connection) { MockRedis.new }
10
+ let(:cluster) { OpenStruct.new(id: 'abc', connection: connection) }
11
+ let(:jid1) { 'alice@wonderland.lit/tea' }
12
+ let(:jid2) { 'alice@wonderland.lit/cake' }
15
13
 
16
- def test_save
17
- StorageTests::EMLoop.new do
18
- @cluster.expect(:id, 'abc')
19
- jid1 = 'alice@wonderland.lit/tea'
20
- jid2 = 'alice@wonderland.lit/cake'
21
- sessions = Vines::Cluster::Sessions.new(@cluster)
22
- sessions.save(jid1, {available: true, interested: true})
23
- sessions.save(jid2, {available: false, interested: false})
24
- EM.next_tick do
25
- session1 = {node: 'abc', available: true, interested: true}
26
- session2 = {node: 'abc', available: false, interested: false}
27
- assert_equal 2, @connection.db["sessions:alice@wonderland.lit"].size
28
- assert_equal session1.to_json, @connection.db["sessions:alice@wonderland.lit"]['tea']
29
- assert_equal session2.to_json, @connection.db["sessions:alice@wonderland.lit"]['cake']
30
- assert_equal [jid1, jid2], @connection.db["cluster:nodes:abc"].to_a
31
- assert @cluster.verify
14
+ describe 'when saving to the cluster' do
15
+ it 'writes to a redis hash' do
16
+ StorageTests::EMLoop.new do
17
+ subject.save(jid1, {available: true, interested: true})
18
+ subject.save(jid2, {available: false, interested: false})
19
+ EM.next_tick do
20
+ session1 = {node: 'abc', available: true, interested: true}
21
+ session2 = {node: 'abc', available: false, interested: false}
22
+ connection.db["sessions:alice@wonderland.lit"].size.must_equal 2
23
+ connection.db["sessions:alice@wonderland.lit"]['tea'].must_equal session1.to_json
24
+ connection.db["sessions:alice@wonderland.lit"]['cake'].must_equal session2.to_json
25
+ connection.db["cluster:nodes:abc"].to_a.must_equal [jid1, jid2]
26
+ end
32
27
  end
33
28
  end
34
29
  end
35
30
 
36
- def test_delete
37
- StorageTests::EMLoop.new do
38
- jid1 = 'alice@wonderland.lit/tea'
39
- jid2 = 'alice@wonderland.lit/cake'
40
- @connection.db["sessions:alice@wonderland.lit"] = {}
41
- @connection.db["sessions:alice@wonderland.lit"]['tea'] = {node: 'abc', available: true}.to_json
42
- @connection.db["sessions:alice@wonderland.lit"]['cake'] = {node: 'abc', available: true}.to_json
43
- @connection.db["cluster:nodes:abc"] = Set.new([jid1, jid2])
31
+ describe 'when deleting from the cluster' do
32
+ it 'removes from a redis hash' do
33
+ StorageTests::EMLoop.new do
34
+ connection.db["sessions:alice@wonderland.lit"] = {}
35
+ connection.db["sessions:alice@wonderland.lit"]['tea'] = {node: 'abc', available: true}.to_json
36
+ connection.db["sessions:alice@wonderland.lit"]['cake'] = {node: 'abc', available: true}.to_json
37
+ connection.db["cluster:nodes:abc"] = Set.new([jid1, jid2])
44
38
 
45
- sessions = Vines::Cluster::Sessions.new(@cluster)
46
- sessions.delete(jid1)
47
- EM.next_tick do
48
- assert_equal 1, @connection.db["sessions:alice@wonderland.lit"].size
49
- assert_equal [jid2], @connection.db["cluster:nodes:abc"].to_a
50
- assert @cluster.verify
39
+ subject.delete(jid1)
40
+ EM.next_tick do
41
+ connection.db["sessions:alice@wonderland.lit"].size.must_equal 1
42
+ connection.db["cluster:nodes:abc"].to_a.must_equal [jid2]
43
+ end
51
44
  end
52
45
  end
53
46
  end
@@ -1,94 +1,109 @@
1
1
  # encoding: UTF-8
2
2
 
3
- require 'vines'
4
- require 'ext/nokogiri'
5
- require 'minitest/autorun'
6
-
7
- class ClusterSubscriberTest < MiniTest::Unit::TestCase
8
- def setup
9
- @connection = MiniTest::Mock.new
10
- @cluster = MiniTest::Mock.new
11
- @cluster.expect(:id, 'abc')
12
- end
13
-
14
- def test_subscribe
15
- @cluster.expect(:connect, @connection)
16
- @connection.expect(:subscribe, nil, ['cluster:nodes:all'])
17
- @connection.expect(:subscribe, nil, ['cluster:nodes:abc'])
18
- @connection.expect(:on, nil, [:message])
19
- subscriber = Vines::Cluster::Subscriber.new(@cluster)
20
- subscriber.subscribe
21
- assert @connection.verify
22
- assert @cluster.verify
23
- end
3
+ require 'test_helper'
24
4
 
25
- def test_heartbeat
26
- now = Time.now.to_i
27
- msg = {from: 'node-42', type: 'heartbeat', time: now}.to_json
28
- @cluster.expect(:poke, nil, ['node-42', now])
5
+ describe Vines::Cluster::Subscriber do
6
+ subject { Vines::Cluster::Subscriber.new(cluster) }
7
+ let(:connection) { MiniTest::Mock.new }
8
+ let(:cluster) { MiniTest::Mock.new }
9
+ let(:now) { Time.now.to_i }
29
10
 
30
- subscriber = Vines::Cluster::Subscriber.new(@cluster)
31
- subscriber.send(:on_message, 'cluster:nodes:all', msg)
32
- assert @connection.verify
33
- assert @cluster.verify
11
+ before do
12
+ cluster.expect :id, 'abc'
34
13
  end
35
14
 
36
- def test_online
37
- now = Time.now.to_i
38
- msg = {from: 'node-42', type: 'online', time: now}.to_json
39
- @cluster.expect(:poke, nil, ['node-42', now])
40
-
41
- subscriber = Vines::Cluster::Subscriber.new(@cluster)
42
- subscriber.send(:on_message, 'cluster:nodes:all', msg)
43
- assert @connection.verify
44
- assert @cluster.verify
15
+ describe '#subscribe' do
16
+ before do
17
+ cluster.expect :connect, connection
18
+ connection.expect :subscribe, nil, ['cluster:nodes:all']
19
+ connection.expect :subscribe, nil, ['cluster:nodes:abc']
20
+ connection.expect :on, nil, [:message]
21
+ end
22
+
23
+ it 'subscribes to its own channel and the broadcast channel' do
24
+ subject.subscribe
25
+ connection.verify
26
+ cluster.verify
27
+ end
45
28
  end
46
29
 
47
- def test_offline
48
- now = Time.now.to_i
49
- msg = {from: 'node-42', type: 'offline', time: now}.to_json
50
- @cluster.expect(:delete_sessions, nil, ['node-42'])
51
-
52
- subscriber = Vines::Cluster::Subscriber.new(@cluster)
53
- subscriber.send(:on_message, 'cluster:nodes:all', msg)
54
- assert @connection.verify
55
- assert @cluster.verify
30
+ describe 'when receiving a heartbeat broadcast message' do
31
+ before do
32
+ cluster.expect :poke, nil, ['node-42', now]
33
+ end
34
+
35
+ it 'pokes the session manager for the broadcasting node' do
36
+ msg = {from: 'node-42', type: 'heartbeat', time: now}.to_json
37
+ subject.send(:on_message, 'cluster:nodes:all', msg)
38
+ connection.verify
39
+ cluster.verify
40
+ end
56
41
  end
57
42
 
58
- def test_route_stanza
59
- stanza = "<message to='alice@wonderland.lit/tea'>hello</message>"
60
- node = Nokogiri::XML(stanza).root rescue nil
61
- msg = {from: 'node-42', type: 'stanza', stanza: stanza}.to_json
62
-
63
- stream = MiniTest::Mock.new
64
- stream.expect(:write, nil, [node])
65
- @cluster.expect(:connected_resources, [stream], ['alice@wonderland.lit/tea'])
66
-
67
- subscriber = Vines::Cluster::Subscriber.new(@cluster)
68
- subscriber.send(:on_message, 'cluster:nodes:abc', msg)
69
- assert stream.verify
70
- assert @connection.verify
71
- assert @cluster.verify
43
+ describe 'when receiving an initial online broadcast message' do
44
+ before do
45
+ cluster.expect :poke, nil, ['node-42', now]
46
+ end
47
+
48
+ it 'pokes the session manager for the broadcasting node' do
49
+ msg = {from: 'node-42', type: 'online', time: now}.to_json
50
+ subject.send(:on_message, 'cluster:nodes:all', msg)
51
+ connection.verify
52
+ cluster.verify
53
+ end
72
54
  end
73
55
 
74
- def test_update_user
75
- alice = Vines::User.new(jid: 'alice@wonderland.lit/tea')
76
- msg = {from: 'node-42', type: 'user', jid: alice.jid.to_s}.to_json
77
-
78
- storage = MiniTest::Mock.new
79
- storage.expect(:find_user, alice, [alice.jid.bare])
80
-
81
- stream = MiniTest::Mock.new
82
- stream.expect(:user, alice)
56
+ describe 'when receiving an offline broadcast message' do
57
+ before do
58
+ cluster.expect :delete_sessions, nil, ['node-42']
59
+ end
60
+
61
+ it 'deletes the sessions for the broadcasting node' do
62
+ msg = {from: 'node-42', type: 'offline', time: now}.to_json
63
+ subject.send(:on_message, 'cluster:nodes:all', msg)
64
+ connection.verify
65
+ cluster.verify
66
+ end
67
+ end
83
68
 
84
- @cluster.expect(:storage, storage, ['wonderland.lit'])
85
- @cluster.expect(:connected_resources, [stream], [alice.jid.bare])
69
+ describe 'when receiving a stanza routed to my node' do
70
+ let(:stream) { MiniTest::Mock.new }
71
+ let(:stanza) { "<message to='alice@wonderland.lit/tea'>hello</message>" }
72
+ let(:xml) { Nokogiri::XML(stanza).root }
73
+
74
+ before do
75
+ stream.expect :write, nil, [xml]
76
+ cluster.expect :connected_resources, [stream], ['alice@wonderland.lit/tea']
77
+ end
78
+
79
+ it 'writes the stanza to the connected user streams' do
80
+ msg = {from: 'node-42', type: 'stanza', stanza: stanza}.to_json
81
+ subject.send(:on_message, 'cluster:nodes:abc', msg)
82
+ stream.verify
83
+ connection.verify
84
+ cluster.verify
85
+ end
86
+ end
86
87
 
87
- subscriber = Vines::Cluster::Subscriber.new(@cluster)
88
- subscriber.send(:on_message, 'cluster:nodes:abc', msg)
89
- assert storage.verify
90
- assert stream.verify
91
- assert @connection.verify
92
- assert @cluster.verify
88
+ describe 'when receiving a user update message to my node' do
89
+ let(:alice) { Vines::User.new(jid: 'alice@wonderland.lit/tea') }
90
+ let(:storage) { MiniTest::Mock.new }
91
+ let(:stream) { MiniTest::Mock.new }
92
+
93
+ before do
94
+ storage.expect :find_user, alice, [alice.jid.bare]
95
+ stream.expect :user, alice
96
+ cluster.expect :storage, storage, ['wonderland.lit']
97
+ cluster.expect :connected_resources, [stream], [alice.jid.bare]
98
+ end
99
+
100
+ it 'reloads the user from storage and updates their connected streams' do
101
+ msg = {from: 'node-42', type: 'user', jid: alice.jid.to_s}.to_json
102
+ subject.send(:on_message, 'cluster:nodes:abc', msg)
103
+ storage.verify
104
+ stream.verify
105
+ connection.verify
106
+ cluster.verify
107
+ end
93
108
  end
94
109
  end
@@ -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 HostTest < MiniTest::Unit::TestCase
5
+ describe Vines::Config::Host do
8
6
  def test_missing_storage
9
7
  assert_raises(RuntimeError) do
10
8
  Vines::Config.new do
@@ -1,181 +1,187 @@
1
1
  # encoding: UTF-8
2
2
 
3
- require 'tmpdir'
4
- require 'vines'
5
- require 'ext/nokogiri'
6
- require 'minitest/autorun'
3
+ require 'test_helper'
7
4
 
8
- class ConfigPubSubTest < MiniTest::Unit::TestCase
9
- def setup
5
+ describe Vines::Config::PubSub do
6
+ subject { config.pubsub('topics.wonderland.lit') }
7
+ let(:alice) { Vines::JID.new('alice@wonderland.lit') }
8
+ let(:romeo) { Vines::JID.new('romeo@verona.lit') }
9
+ let(:config) do
10
10
  @config = Vines::Config.new do
11
11
  host 'wonderland.lit' do
12
12
  storage(:fs) { dir Dir.tmpdir }
13
13
  pubsub 'topics'
14
14
  end
15
15
  end
16
- @pubsub = @config.pubsub('topics.wonderland.lit')
17
16
  end
18
17
 
19
- def test_add_node
18
+ it 'adds and deletes a topic node' do
20
19
  topic = 'rhode_island_is_neither_a_road_nor_an_island'
21
- refute @pubsub.node?(topic)
22
- @pubsub.add_node(topic)
23
- assert @pubsub.node?(topic)
24
- @pubsub.delete_node(topic)
25
- refute @pubsub.node?(topic)
20
+ refute subject.node?(topic)
21
+ subject.add_node(topic)
22
+ assert subject.node?(topic)
23
+ subject.delete_node(topic)
24
+ refute subject.node?(topic)
26
25
  end
27
26
 
28
- def test_delete_missing_node
27
+ it 'ignores deleting a missing topic node' do
29
28
  topic = 'kittens_vs_puppies'
30
- refute @pubsub.node?(topic)
31
- @pubsub.delete_node(topic)
32
- refute @pubsub.node?(topic)
29
+ refute subject.node?(topic)
30
+ subject.delete_node(topic)
31
+ refute subject.node?(topic)
33
32
  end
34
33
 
35
- def test_subscribe_with_jid
34
+ it 'subscribes a jid to a node' do
36
35
  topic = 'with_jid'
37
36
  jid = Vines::JID.new('alice@wonderland.lit')
38
- @pubsub.add_node(topic)
39
- @pubsub.subscribe(topic, jid)
40
- assert @pubsub.subscribed?(topic, jid.to_s)
41
- assert @pubsub.subscribed?(topic, jid)
37
+ subject.add_node(topic)
38
+ subject.subscribe(topic, jid)
39
+ assert subject.subscribed?(topic, jid.to_s)
40
+ assert subject.subscribed?(topic, jid)
42
41
  end
43
42
 
44
- def test_subscribe_remote_jid_not_allowed
43
+ it 'does not allow remote jids to subscribe to a node by default' do
45
44
  topic = 'remote_jids_failed'
46
45
  jid = 'romeo@verona.lit'
47
- @pubsub.add_node(topic)
48
- @pubsub.subscribe(topic, jid)
49
- refute @pubsub.subscribed?(topic, jid)
46
+ subject.add_node(topic)
47
+ subject.subscribe(topic, jid)
48
+ refute subject.subscribed?(topic, jid)
50
49
  end
51
50
 
52
- def test_subscribe_remote_jid_is_allowed
51
+ it 'allows remote jid subscriptions when cross domain messages are enabled' do
53
52
  topic = 'remote_jids_allowed'
54
53
  jid = 'romeo@verona.lit'
55
- @config.vhost('wonderland.lit').cross_domain_messages true
56
- @pubsub.add_node(topic)
57
- @pubsub.subscribe(topic, jid)
58
- assert @pubsub.subscribed?(topic, jid)
54
+ config.vhost('wonderland.lit').cross_domain_messages true
55
+ subject.add_node(topic)
56
+ subject.subscribe(topic, jid)
57
+ assert subject.subscribed?(topic, jid)
59
58
  end
60
59
 
61
- def test_subscribe_missing_node
60
+ it 'ignores subscribing to a missing node' do
62
61
  topic = 'bogus'
63
62
  jid = 'alice@wonderland.lit'
64
- refute @pubsub.node?(topic)
65
- @pubsub.subscribe(topic, jid)
66
- refute @pubsub.node?(topic)
67
- refute @pubsub.subscribed?(topic, jid)
63
+ refute subject.node?(topic)
64
+ subject.subscribe(topic, jid)
65
+ refute subject.node?(topic)
66
+ refute subject.subscribed?(topic, jid)
68
67
  end
69
68
 
70
- def test_unsubscribe_deletes_node
69
+ it 'deletes the node after unsubscribing' do
71
70
  topic = 'delete_me'
72
71
  jid = 'alice@wonderland.lit/tea'
73
- @pubsub.add_node(topic)
74
- @pubsub.subscribe(topic, jid)
75
- assert @pubsub.subscribed?(topic, jid)
76
- @pubsub.unsubscribe(topic, jid)
77
- refute @pubsub.subscribed?(topic, jid)
78
- refute @pubsub.node?(topic)
72
+ subject.add_node(topic)
73
+ subject.subscribe(topic, jid)
74
+ assert subject.subscribed?(topic, jid)
75
+ subject.unsubscribe(topic, jid)
76
+ refute subject.subscribed?(topic, jid)
77
+ refute subject.node?(topic)
79
78
  end
80
79
 
81
- def test_unsubscribe_all
80
+ it 'unsubscribes a jid from all topics' do
82
81
  topic = 'pirates_vs_ninjas'
83
82
  topic2 = 'pirates_vs_ninjas_2'
84
83
  jid = 'alice@wonderland.lit'
85
84
  jid2 = 'hatter@wonderland.lit'
86
- @pubsub.add_node(topic)
87
- @pubsub.add_node(topic2)
88
-
89
- @pubsub.subscribe(topic, jid)
90
- @pubsub.subscribe(topic, jid2)
91
- @pubsub.subscribe(topic2, jid)
92
- assert @pubsub.subscribed?(topic, jid)
93
- assert @pubsub.subscribed?(topic, jid2)
94
- assert @pubsub.subscribed?(topic2, jid)
95
-
96
- @pubsub.unsubscribe_all(jid)
97
- refute @pubsub.node?(topic2)
98
- refute @pubsub.subscribed?(topic, jid)
99
- refute @pubsub.subscribed?(topic2, jid)
100
- assert @pubsub.subscribed?(topic, jid2)
85
+ subject.add_node(topic)
86
+ subject.add_node(topic2)
87
+
88
+ subject.subscribe(topic, jid)
89
+ subject.subscribe(topic, jid2)
90
+ subject.subscribe(topic2, jid)
91
+ assert subject.subscribed?(topic, jid)
92
+ assert subject.subscribed?(topic, jid2)
93
+ assert subject.subscribed?(topic2, jid)
94
+
95
+ subject.unsubscribe_all(jid)
96
+ refute subject.node?(topic2)
97
+ refute subject.subscribed?(topic, jid)
98
+ refute subject.subscribed?(topic2, jid)
99
+ assert subject.subscribed?(topic, jid2)
101
100
  end
102
101
 
103
- def test_publish
104
- topic = 'pirates_vs_ninjas'
105
- alice = Vines::JID.new('alice@wonderland.lit')
106
- romeo = Vines::JID.new('romeo@verona.lit')
107
-
108
- @config.vhost('wonderland.lit').cross_domain_messages true
109
- def @config.router
110
- unless @mock_router
111
- @mock_router = MiniTest::Mock.new
112
- def @mock_router.nodes; @nodes; end
113
- def @mock_router.route(node)
102
+ describe 'when publishing a message to a topic node' do
103
+ let(:xml) do
104
+ node(%q{
105
+ <iq type='set' to='topics.wonderland.lit'>
106
+ <pubsub xmlns='http://jabber.org/protocol/pubsub'>
107
+ <publish node='pirates_vs_ninjas'>
108
+ <item id='item_42'>
109
+ <entry xmlns='http://www.w3.org/2005/Atom'>
110
+ <title>Test</title>
111
+ <summary>This is a summary.</summary>
112
+ </entry>
113
+ </item>
114
+ </publish>
115
+ </pubsub>
116
+ </iq>})
117
+ end
118
+
119
+ let(:recipient) do
120
+ recipient = MiniTest::Mock.new
121
+ recipient.expect :user, Vines::User.new(jid: alice)
122
+ class << recipient
123
+ attr_accessor :nodes
124
+ def write(node)
114
125
  @nodes ||= []
115
126
  @nodes << node
116
127
  end
117
128
  end
118
- @mock_router
129
+ recipient
119
130
  end
120
131
 
121
- recipient = recipient(alice)
122
- @config.router.expect(:connected_resources, [recipient], [alice, 'topics.wonderland.lit'])
123
-
124
- @pubsub.add_node(topic)
125
- @pubsub.subscribe(topic, alice)
126
- @pubsub.subscribe(topic, romeo)
127
- assert @pubsub.subscribed?(topic, alice)
128
- assert @pubsub.subscribed?(topic, romeo)
129
-
130
- node = node(%q{
131
- <iq type='set' to='topics.wonderland.lit'>
132
- <pubsub xmlns='http://jabber.org/protocol/pubsub'>
133
- <publish node='pirates_vs_ninjas'>
134
- <item id='item_42'>
135
- <entry xmlns='http://www.w3.org/2005/Atom'>
136
- <title>Test</title>
137
- <summary>This is a summary.</summary>
138
- </entry>
139
- </item>
140
- </publish>
141
- </pubsub>
142
- </iq>
143
- }.strip.gsub(/\n|\s{2,}/, ''))
144
- expected = node.clone
145
-
146
- @pubsub.publish(topic, node)
147
-
148
- assert @config.router.verify
149
- assert recipient.verify
150
-
151
- # id is random
152
- refute_nil recipient.nodes[0]['id']
153
- refute_nil @config.router.nodes[0]['id']
154
- recipient.nodes[0].remove_attribute('id')
155
- @config.router.nodes[0].remove_attribute('id')
156
-
157
- expected['to'] = 'alice@wonderland.lit'
158
- expected['from'] = 'topics.wonderland.lit'
159
- assert_equal expected, recipient.nodes[0]
160
-
161
- expected['to'] = 'romeo@verona.lit'
162
- assert_equal expected, @config.router.nodes[0]
163
- end
132
+ before do
133
+ router = MiniTest::Mock.new
134
+ router.expect :connected_resources, [recipient], [alice, 'topics.wonderland.lit']
135
+ class << router
136
+ attr_accessor :nodes
137
+ def route(node)
138
+ @nodes ||= []
139
+ @nodes << node
140
+ end
141
+ end
142
+
143
+ class << config
144
+ attr_accessor :router
145
+ end
146
+ config.router = router
147
+ config.vhost('wonderland.lit').cross_domain_messages true
148
+
149
+ subject.add_node(topic)
150
+ subject.subscribe(topic, alice)
151
+ subject.subscribe(topic, romeo)
152
+ end
153
+
154
+ let(:topic) { 'pirates_vs_ninjas' }
155
+
156
+ it 'writes the message to local connected resource streams' do
157
+ expected = xml.clone
158
+ expected['to'] = 'alice@wonderland.lit'
159
+ expected['from'] = 'topics.wonderland.lit'
164
160
 
165
- private
161
+ subject.publish(topic, xml)
162
+ config.router.verify
163
+ recipient.verify
166
164
 
167
- def recipient(jid)
168
- recipient = MiniTest::Mock.new
169
- recipient.expect(:user, Vines::User.new(jid: jid))
170
- def recipient.nodes; @nodes; end
171
- def recipient.write(node)
172
- @nodes ||= []
173
- @nodes << node
165
+ # id is random
166
+ received = recipient.nodes.first
167
+ received['id'].wont_be_nil
168
+ received.remove_attribute('id')
169
+ received.must_equal expected
174
170
  end
175
- recipient
176
- end
177
171
 
178
- def node(xml)
179
- Nokogiri::XML(xml).root
172
+ it 'routes the message to remote jids' do
173
+ expected = xml.clone
174
+ expected['to'] = 'romeo@verona.lit'
175
+ expected['from'] = 'topics.wonderland.lit'
176
+
177
+ subject.publish(topic, xml)
178
+ config.router.verify
179
+
180
+ # id is random
181
+ routed = config.router.nodes.first
182
+ routed['id'].wont_be_nil
183
+ routed.remove_attribute('id')
184
+ routed.must_equal expected
185
+ end
180
186
  end
181
187
  end