diaspora-vines 0.1.2

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 (174) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +3 -0
  3. data/LICENSE +19 -0
  4. data/README.md +7 -0
  5. data/Rakefile +23 -0
  6. data/bin/vines +4 -0
  7. data/conf/certs/README +39 -0
  8. data/conf/certs/ca-bundle.crt +3895 -0
  9. data/conf/config.rb +42 -0
  10. data/lib/vines/cli.rb +132 -0
  11. data/lib/vines/cluster/connection.rb +26 -0
  12. data/lib/vines/cluster/publisher.rb +55 -0
  13. data/lib/vines/cluster/pubsub.rb +92 -0
  14. data/lib/vines/cluster/sessions.rb +125 -0
  15. data/lib/vines/cluster/subscriber.rb +108 -0
  16. data/lib/vines/cluster.rb +246 -0
  17. data/lib/vines/command/bcrypt.rb +12 -0
  18. data/lib/vines/command/cert.rb +50 -0
  19. data/lib/vines/command/init.rb +68 -0
  20. data/lib/vines/command/ldap.rb +38 -0
  21. data/lib/vines/command/restart.rb +12 -0
  22. data/lib/vines/command/schema.rb +24 -0
  23. data/lib/vines/command/start.rb +28 -0
  24. data/lib/vines/command/stop.rb +18 -0
  25. data/lib/vines/config/host.rb +125 -0
  26. data/lib/vines/config/port.rb +132 -0
  27. data/lib/vines/config/pubsub.rb +108 -0
  28. data/lib/vines/config.rb +223 -0
  29. data/lib/vines/contact.rb +111 -0
  30. data/lib/vines/daemon.rb +78 -0
  31. data/lib/vines/error.rb +150 -0
  32. data/lib/vines/jid.rb +95 -0
  33. data/lib/vines/kit.rb +23 -0
  34. data/lib/vines/log.rb +24 -0
  35. data/lib/vines/router.rb +179 -0
  36. data/lib/vines/stanza/iq/auth.rb +18 -0
  37. data/lib/vines/stanza/iq/disco_info.rb +45 -0
  38. data/lib/vines/stanza/iq/disco_items.rb +29 -0
  39. data/lib/vines/stanza/iq/error.rb +16 -0
  40. data/lib/vines/stanza/iq/ping.rb +16 -0
  41. data/lib/vines/stanza/iq/private_storage.rb +83 -0
  42. data/lib/vines/stanza/iq/query.rb +10 -0
  43. data/lib/vines/stanza/iq/result.rb +16 -0
  44. data/lib/vines/stanza/iq/roster.rb +140 -0
  45. data/lib/vines/stanza/iq/session.rb +17 -0
  46. data/lib/vines/stanza/iq/vcard.rb +56 -0
  47. data/lib/vines/stanza/iq/version.rb +25 -0
  48. data/lib/vines/stanza/iq.rb +48 -0
  49. data/lib/vines/stanza/message.rb +40 -0
  50. data/lib/vines/stanza/presence/error.rb +23 -0
  51. data/lib/vines/stanza/presence/probe.rb +37 -0
  52. data/lib/vines/stanza/presence/subscribe.rb +42 -0
  53. data/lib/vines/stanza/presence/subscribed.rb +51 -0
  54. data/lib/vines/stanza/presence/unavailable.rb +15 -0
  55. data/lib/vines/stanza/presence/unsubscribe.rb +38 -0
  56. data/lib/vines/stanza/presence/unsubscribed.rb +38 -0
  57. data/lib/vines/stanza/presence.rb +141 -0
  58. data/lib/vines/stanza/pubsub/create.rb +39 -0
  59. data/lib/vines/stanza/pubsub/delete.rb +41 -0
  60. data/lib/vines/stanza/pubsub/publish.rb +66 -0
  61. data/lib/vines/stanza/pubsub/subscribe.rb +44 -0
  62. data/lib/vines/stanza/pubsub/unsubscribe.rb +30 -0
  63. data/lib/vines/stanza/pubsub.rb +22 -0
  64. data/lib/vines/stanza.rb +175 -0
  65. data/lib/vines/storage/ldap.rb +71 -0
  66. data/lib/vines/storage/local.rb +139 -0
  67. data/lib/vines/storage/null.rb +39 -0
  68. data/lib/vines/storage/sql.rb +138 -0
  69. data/lib/vines/storage.rb +239 -0
  70. data/lib/vines/store.rb +110 -0
  71. data/lib/vines/stream/client/auth.rb +74 -0
  72. data/lib/vines/stream/client/auth_restart.rb +29 -0
  73. data/lib/vines/stream/client/bind.rb +72 -0
  74. data/lib/vines/stream/client/bind_restart.rb +24 -0
  75. data/lib/vines/stream/client/closed.rb +13 -0
  76. data/lib/vines/stream/client/ready.rb +17 -0
  77. data/lib/vines/stream/client/session.rb +210 -0
  78. data/lib/vines/stream/client/start.rb +27 -0
  79. data/lib/vines/stream/client/tls.rb +38 -0
  80. data/lib/vines/stream/client.rb +84 -0
  81. data/lib/vines/stream/component/handshake.rb +26 -0
  82. data/lib/vines/stream/component/ready.rb +23 -0
  83. data/lib/vines/stream/component/start.rb +19 -0
  84. data/lib/vines/stream/component.rb +58 -0
  85. data/lib/vines/stream/http/auth.rb +22 -0
  86. data/lib/vines/stream/http/bind.rb +32 -0
  87. data/lib/vines/stream/http/bind_restart.rb +37 -0
  88. data/lib/vines/stream/http/ready.rb +29 -0
  89. data/lib/vines/stream/http/request.rb +172 -0
  90. data/lib/vines/stream/http/session.rb +120 -0
  91. data/lib/vines/stream/http/sessions.rb +65 -0
  92. data/lib/vines/stream/http/start.rb +23 -0
  93. data/lib/vines/stream/http.rb +157 -0
  94. data/lib/vines/stream/parser.rb +79 -0
  95. data/lib/vines/stream/sasl.rb +128 -0
  96. data/lib/vines/stream/server/auth.rb +13 -0
  97. data/lib/vines/stream/server/auth_restart.rb +13 -0
  98. data/lib/vines/stream/server/final_restart.rb +21 -0
  99. data/lib/vines/stream/server/outbound/auth.rb +31 -0
  100. data/lib/vines/stream/server/outbound/auth_restart.rb +20 -0
  101. data/lib/vines/stream/server/outbound/auth_result.rb +32 -0
  102. data/lib/vines/stream/server/outbound/final_features.rb +28 -0
  103. data/lib/vines/stream/server/outbound/final_restart.rb +20 -0
  104. data/lib/vines/stream/server/outbound/start.rb +20 -0
  105. data/lib/vines/stream/server/outbound/tls.rb +30 -0
  106. data/lib/vines/stream/server/outbound/tls_result.rb +34 -0
  107. data/lib/vines/stream/server/ready.rb +24 -0
  108. data/lib/vines/stream/server/start.rb +13 -0
  109. data/lib/vines/stream/server/tls.rb +13 -0
  110. data/lib/vines/stream/server.rb +150 -0
  111. data/lib/vines/stream/state.rb +60 -0
  112. data/lib/vines/stream.rb +247 -0
  113. data/lib/vines/token_bucket.rb +55 -0
  114. data/lib/vines/user.rb +123 -0
  115. data/lib/vines/version.rb +6 -0
  116. data/lib/vines/xmpp_server.rb +25 -0
  117. data/lib/vines.rb +203 -0
  118. data/test/cluster/publisher_test.rb +57 -0
  119. data/test/cluster/sessions_test.rb +47 -0
  120. data/test/cluster/subscriber_test.rb +109 -0
  121. data/test/config/host_test.rb +369 -0
  122. data/test/config/pubsub_test.rb +187 -0
  123. data/test/config_test.rb +732 -0
  124. data/test/contact_test.rb +102 -0
  125. data/test/error_test.rb +58 -0
  126. data/test/ext/nokogiri.rb +14 -0
  127. data/test/jid_test.rb +147 -0
  128. data/test/kit_test.rb +31 -0
  129. data/test/router_test.rb +243 -0
  130. data/test/stanza/iq/disco_info_test.rb +78 -0
  131. data/test/stanza/iq/disco_items_test.rb +49 -0
  132. data/test/stanza/iq/private_storage_test.rb +184 -0
  133. data/test/stanza/iq/roster_test.rb +229 -0
  134. data/test/stanza/iq/session_test.rb +25 -0
  135. data/test/stanza/iq/vcard_test.rb +146 -0
  136. data/test/stanza/iq/version_test.rb +64 -0
  137. data/test/stanza/iq_test.rb +70 -0
  138. data/test/stanza/message_test.rb +126 -0
  139. data/test/stanza/presence/probe_test.rb +50 -0
  140. data/test/stanza/presence/subscribe_test.rb +83 -0
  141. data/test/stanza/pubsub/create_test.rb +116 -0
  142. data/test/stanza/pubsub/delete_test.rb +169 -0
  143. data/test/stanza/pubsub/publish_test.rb +309 -0
  144. data/test/stanza/pubsub/subscribe_test.rb +205 -0
  145. data/test/stanza/pubsub/unsubscribe_test.rb +148 -0
  146. data/test/stanza_test.rb +85 -0
  147. data/test/storage/ldap_test.rb +201 -0
  148. data/test/storage/local_test.rb +59 -0
  149. data/test/storage/mock_redis.rb +97 -0
  150. data/test/storage/null_test.rb +29 -0
  151. data/test/storage/storage_tests.rb +182 -0
  152. data/test/storage_test.rb +85 -0
  153. data/test/store_test.rb +130 -0
  154. data/test/stream/client/auth_test.rb +137 -0
  155. data/test/stream/client/ready_test.rb +47 -0
  156. data/test/stream/client/session_test.rb +27 -0
  157. data/test/stream/component/handshake_test.rb +52 -0
  158. data/test/stream/component/ready_test.rb +103 -0
  159. data/test/stream/component/start_test.rb +39 -0
  160. data/test/stream/http/auth_test.rb +70 -0
  161. data/test/stream/http/ready_test.rb +86 -0
  162. data/test/stream/http/request_test.rb +209 -0
  163. data/test/stream/http/sessions_test.rb +49 -0
  164. data/test/stream/http/start_test.rb +50 -0
  165. data/test/stream/parser_test.rb +122 -0
  166. data/test/stream/sasl_test.rb +195 -0
  167. data/test/stream/server/auth_test.rb +61 -0
  168. data/test/stream/server/outbound/auth_test.rb +75 -0
  169. data/test/stream/server/ready_test.rb +98 -0
  170. data/test/test_helper.rb +42 -0
  171. data/test/token_bucket_test.rb +44 -0
  172. data/test/user_test.rb +96 -0
  173. data/vines.gemspec +30 -0
  174. metadata +387 -0
data/lib/vines.rb ADDED
@@ -0,0 +1,203 @@
1
+ # encoding: UTF-8
2
+
3
+ module Vines
4
+ NAMESPACES = {
5
+ :stream => 'http://etherx.jabber.org/streams'.freeze,
6
+ :client => 'jabber:client'.freeze,
7
+ :server => 'jabber:server'.freeze,
8
+ :component => 'jabber:component:accept'.freeze,
9
+ :roster => 'jabber:iq:roster'.freeze,
10
+ :non_sasl => 'jabber:iq:auth'.freeze,
11
+ :storage => 'jabber:iq:private'.freeze,
12
+ :version => 'jabber:iq:version'.freeze,
13
+ :sasl => 'urn:ietf:params:xml:ns:xmpp-sasl'.freeze,
14
+ :tls => 'urn:ietf:params:xml:ns:xmpp-tls'.freeze,
15
+ :bind => 'urn:ietf:params:xml:ns:xmpp-bind'.freeze,
16
+ :session => 'urn:ietf:params:xml:ns:xmpp-session'.freeze,
17
+ :ping => 'urn:xmpp:ping'.freeze,
18
+ :pubsub => 'http://jabber.org/protocol/pubsub'.freeze,
19
+ :pubsub_event => 'http://jabber.org/protocol/pubsub#event'.freeze,
20
+ :pubsub_create => 'http://jabber.org/protocol/pubsub#create-nodes'.freeze,
21
+ :pubsub_delete => 'http://jabber.org/protocol/pubsub#delete-nodes'.freeze,
22
+ :pubsub_instant => 'http://jabber.org/protocol/pubsub#instant-nodes'.freeze,
23
+ :pubsub_item_ids => 'http://jabber.org/protocol/pubsub#item-ids'.freeze,
24
+ :pubsub_publish => 'http://jabber.org/protocol/pubsub#publish'.freeze,
25
+ :pubsub_subscribe => 'http://jabber.org/protocol/pubsub#subscribe'.freeze,
26
+ :disco_items => 'http://jabber.org/protocol/disco#items'.freeze,
27
+ :disco_info => 'http://jabber.org/protocol/disco#info'.freeze,
28
+ :http_bind => 'http://jabber.org/protocol/httpbind'.freeze,
29
+ :bosh => 'urn:xmpp:xbosh'.freeze,
30
+ :vcard => 'vcard-temp'.freeze,
31
+ :si => 'http://jabber.org/protocol/si'.freeze,
32
+ :byte_streams => 'http://jabber.org/protocol/bytestreams'.freeze
33
+ }.freeze
34
+
35
+ module Log
36
+ @@logger = nil
37
+ def log
38
+ unless @@logger
39
+ @@logger = Logger.new(STDOUT)
40
+ @@logger.level = Logger::INFO
41
+ @@logger.progname = 'vines'
42
+ @@logger.formatter = Class.new(Logger::Formatter) do
43
+ def initialize
44
+ @time = "%Y-%m-%dT%H:%M:%SZ".freeze
45
+ @fmt = "[%s] %5s -- %s: %s\n".freeze
46
+ end
47
+ def call(severity, time, program, msg)
48
+ @fmt % [time.utc.strftime(@time), severity, program, msg2str(msg)]
49
+ end
50
+ end.new
51
+ end
52
+ @@logger
53
+ end
54
+ end
55
+ end
56
+
57
+ begin
58
+ # try to initialize diaspora AppConfig
59
+ require "#{Dir.pwd}/config/load_config.rb"
60
+ rescue LoadError
61
+ puts "Cannot find Diaspora environment! Fallback to vines configuration."
62
+ end
63
+
64
+ %w[
65
+ base64
66
+ bcrypt
67
+ digest/sha1
68
+ em-hiredis
69
+ eventmachine
70
+ fiber
71
+ fileutils
72
+ http/parser
73
+ json
74
+ logger
75
+ net/ldap
76
+ nokogiri
77
+ openssl
78
+ optparse
79
+ resolv
80
+ set
81
+ socket
82
+ yaml
83
+
84
+ vines/cli
85
+ vines/log
86
+ vines/jid
87
+
88
+ vines/stanza
89
+ vines/stanza/iq
90
+ vines/stanza/iq/query
91
+ vines/stanza/iq/auth
92
+ vines/stanza/iq/disco_info
93
+ vines/stanza/iq/disco_items
94
+ vines/stanza/iq/error
95
+ vines/stanza/iq/ping
96
+ vines/stanza/iq/private_storage
97
+ vines/stanza/iq/result
98
+ vines/stanza/iq/roster
99
+ vines/stanza/iq/session
100
+ vines/stanza/iq/vcard
101
+ vines/stanza/iq/version
102
+ vines/stanza/message
103
+ vines/stanza/presence
104
+ vines/stanza/presence/error
105
+ vines/stanza/presence/probe
106
+ vines/stanza/presence/subscribe
107
+ vines/stanza/presence/subscribed
108
+ vines/stanza/presence/unavailable
109
+ vines/stanza/presence/unsubscribe
110
+ vines/stanza/presence/unsubscribed
111
+ vines/stanza/pubsub
112
+ vines/stanza/pubsub/create
113
+ vines/stanza/pubsub/delete
114
+ vines/stanza/pubsub/publish
115
+ vines/stanza/pubsub/subscribe
116
+ vines/stanza/pubsub/unsubscribe
117
+
118
+ vines/storage
119
+ vines/storage/ldap
120
+ vines/storage/local
121
+ vines/storage/sql
122
+ vines/storage/null
123
+
124
+ vines/config
125
+ vines/config/host
126
+ vines/config/port
127
+ vines/config/pubsub
128
+
129
+ vines/store
130
+ vines/contact
131
+ vines/daemon
132
+ vines/error
133
+ vines/kit
134
+ vines/router
135
+ vines/token_bucket
136
+ vines/user
137
+ vines/version
138
+ vines/xmpp_server
139
+
140
+ vines/cluster
141
+ vines/cluster/connection
142
+ vines/cluster/publisher
143
+ vines/cluster/pubsub
144
+ vines/cluster/sessions
145
+ vines/cluster/subscriber
146
+
147
+ vines/stream
148
+ vines/stream/sasl
149
+ vines/stream/state
150
+ vines/stream/parser
151
+
152
+ vines/stream/client
153
+ vines/stream/client/session
154
+ vines/stream/client/start
155
+ vines/stream/client/tls
156
+ vines/stream/client/auth_restart
157
+ vines/stream/client/auth
158
+ vines/stream/client/bind_restart
159
+ vines/stream/client/bind
160
+ vines/stream/client/ready
161
+ vines/stream/client/closed
162
+
163
+ vines/stream/component
164
+ vines/stream/component/start
165
+ vines/stream/component/handshake
166
+ vines/stream/component/ready
167
+
168
+ vines/stream/http
169
+ vines/stream/http/session
170
+ vines/stream/http/sessions
171
+ vines/stream/http/request
172
+ vines/stream/http/start
173
+ vines/stream/http/auth
174
+ vines/stream/http/bind_restart
175
+ vines/stream/http/bind
176
+ vines/stream/http/ready
177
+
178
+ vines/stream/server
179
+ vines/stream/server/start
180
+ vines/stream/server/tls
181
+ vines/stream/server/auth_restart
182
+ vines/stream/server/auth
183
+ vines/stream/server/final_restart
184
+ vines/stream/server/ready
185
+
186
+ vines/stream/server/outbound/start
187
+ vines/stream/server/outbound/tls
188
+ vines/stream/server/outbound/tls_result
189
+ vines/stream/server/outbound/auth_restart
190
+ vines/stream/server/outbound/auth
191
+ vines/stream/server/outbound/auth_result
192
+ vines/stream/server/outbound/final_restart
193
+ vines/stream/server/outbound/final_features
194
+
195
+ vines/command/bcrypt
196
+ vines/command/cert
197
+ vines/command/init
198
+ vines/command/ldap
199
+ vines/command/restart
200
+ vines/command/schema
201
+ vines/command/start
202
+ vines/command/stop
203
+ ].each {|f| require f }
@@ -0,0 +1,57 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'test_helper'
4
+
5
+ describe Vines::Cluster::Publisher do
6
+ subject { Vines::Cluster::Publisher.new(cluster) }
7
+ let(:connection) { MiniTest::Mock.new }
8
+ let(:cluster) { MiniTest::Mock.new }
9
+
10
+ before do
11
+ cluster.expect :id, 'abc'
12
+ cluster.expect :connection, connection
13
+ end
14
+
15
+ describe '#broadcast' do
16
+ before do
17
+ msg = {from: 'abc', type: 'online', time: Time.now.to_i}.to_json
18
+ connection.expect :publish, nil, ["cluster:nodes:all", msg]
19
+ end
20
+
21
+ it 'publishes the message to every cluster node' do
22
+ subject.broadcast(:online)
23
+ connection.verify
24
+ cluster.verify
25
+ end
26
+ end
27
+
28
+ describe '#route' do
29
+ let(:stanza) { "<message>hello</message>" }
30
+
31
+ before do
32
+ msg = {from: 'abc', type: 'stanza', stanza: stanza}.to_json
33
+ connection.expect :publish, nil, ["cluster:nodes:node-42", msg]
34
+ end
35
+
36
+ it 'publishes the message to just one cluster node' do
37
+ subject.route(stanza, "node-42")
38
+ connection.verify
39
+ cluster.verify
40
+ end
41
+ end
42
+
43
+ describe '#update_user' do
44
+ let(:jid) { Vines::JID.new('alice@wonderland.lit') }
45
+
46
+ before do
47
+ msg = {from: 'abc', type: 'user', jid: jid.to_s}.to_json
48
+ connection.expect :publish, nil, ["cluster:nodes:node-42", msg]
49
+ end
50
+
51
+ it 'publishes the new user to just one cluster node' do
52
+ subject.update_user(jid, "node-42")
53
+ connection.verify
54
+ cluster.verify
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,47 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'test_helper'
4
+ require 'storage/storage_tests'
5
+ require 'storage/mock_redis'
6
+
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' }
13
+
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
27
+ end
28
+ end
29
+ end
30
+
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])
38
+
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
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,109 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'test_helper'
4
+
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 }
10
+
11
+ before do
12
+ cluster.expect :id, 'abc'
13
+ end
14
+
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
28
+ end
29
+
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
41
+ end
42
+
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
54
+ end
55
+
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
68
+
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
87
+
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
108
+ end
109
+ end