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.
- checksums.yaml +7 -0
- data/Gemfile +3 -0
- data/LICENSE +19 -0
- data/README.md +7 -0
- data/Rakefile +23 -0
- data/bin/vines +4 -0
- data/conf/certs/README +39 -0
- data/conf/certs/ca-bundle.crt +3895 -0
- data/conf/config.rb +42 -0
- data/lib/vines/cli.rb +132 -0
- data/lib/vines/cluster/connection.rb +26 -0
- data/lib/vines/cluster/publisher.rb +55 -0
- data/lib/vines/cluster/pubsub.rb +92 -0
- data/lib/vines/cluster/sessions.rb +125 -0
- data/lib/vines/cluster/subscriber.rb +108 -0
- data/lib/vines/cluster.rb +246 -0
- data/lib/vines/command/bcrypt.rb +12 -0
- data/lib/vines/command/cert.rb +50 -0
- data/lib/vines/command/init.rb +68 -0
- data/lib/vines/command/ldap.rb +38 -0
- data/lib/vines/command/restart.rb +12 -0
- data/lib/vines/command/schema.rb +24 -0
- data/lib/vines/command/start.rb +28 -0
- data/lib/vines/command/stop.rb +18 -0
- data/lib/vines/config/host.rb +125 -0
- data/lib/vines/config/port.rb +132 -0
- data/lib/vines/config/pubsub.rb +108 -0
- data/lib/vines/config.rb +223 -0
- data/lib/vines/contact.rb +111 -0
- data/lib/vines/daemon.rb +78 -0
- data/lib/vines/error.rb +150 -0
- data/lib/vines/jid.rb +95 -0
- data/lib/vines/kit.rb +23 -0
- data/lib/vines/log.rb +24 -0
- data/lib/vines/router.rb +179 -0
- data/lib/vines/stanza/iq/auth.rb +18 -0
- data/lib/vines/stanza/iq/disco_info.rb +45 -0
- data/lib/vines/stanza/iq/disco_items.rb +29 -0
- data/lib/vines/stanza/iq/error.rb +16 -0
- data/lib/vines/stanza/iq/ping.rb +16 -0
- data/lib/vines/stanza/iq/private_storage.rb +83 -0
- data/lib/vines/stanza/iq/query.rb +10 -0
- data/lib/vines/stanza/iq/result.rb +16 -0
- data/lib/vines/stanza/iq/roster.rb +140 -0
- data/lib/vines/stanza/iq/session.rb +17 -0
- data/lib/vines/stanza/iq/vcard.rb +56 -0
- data/lib/vines/stanza/iq/version.rb +25 -0
- data/lib/vines/stanza/iq.rb +48 -0
- data/lib/vines/stanza/message.rb +40 -0
- data/lib/vines/stanza/presence/error.rb +23 -0
- data/lib/vines/stanza/presence/probe.rb +37 -0
- data/lib/vines/stanza/presence/subscribe.rb +42 -0
- data/lib/vines/stanza/presence/subscribed.rb +51 -0
- data/lib/vines/stanza/presence/unavailable.rb +15 -0
- data/lib/vines/stanza/presence/unsubscribe.rb +38 -0
- data/lib/vines/stanza/presence/unsubscribed.rb +38 -0
- data/lib/vines/stanza/presence.rb +141 -0
- data/lib/vines/stanza/pubsub/create.rb +39 -0
- data/lib/vines/stanza/pubsub/delete.rb +41 -0
- data/lib/vines/stanza/pubsub/publish.rb +66 -0
- data/lib/vines/stanza/pubsub/subscribe.rb +44 -0
- data/lib/vines/stanza/pubsub/unsubscribe.rb +30 -0
- data/lib/vines/stanza/pubsub.rb +22 -0
- data/lib/vines/stanza.rb +175 -0
- data/lib/vines/storage/ldap.rb +71 -0
- data/lib/vines/storage/local.rb +139 -0
- data/lib/vines/storage/null.rb +39 -0
- data/lib/vines/storage/sql.rb +138 -0
- data/lib/vines/storage.rb +239 -0
- data/lib/vines/store.rb +110 -0
- data/lib/vines/stream/client/auth.rb +74 -0
- data/lib/vines/stream/client/auth_restart.rb +29 -0
- data/lib/vines/stream/client/bind.rb +72 -0
- data/lib/vines/stream/client/bind_restart.rb +24 -0
- data/lib/vines/stream/client/closed.rb +13 -0
- data/lib/vines/stream/client/ready.rb +17 -0
- data/lib/vines/stream/client/session.rb +210 -0
- data/lib/vines/stream/client/start.rb +27 -0
- data/lib/vines/stream/client/tls.rb +38 -0
- data/lib/vines/stream/client.rb +84 -0
- data/lib/vines/stream/component/handshake.rb +26 -0
- data/lib/vines/stream/component/ready.rb +23 -0
- data/lib/vines/stream/component/start.rb +19 -0
- data/lib/vines/stream/component.rb +58 -0
- data/lib/vines/stream/http/auth.rb +22 -0
- data/lib/vines/stream/http/bind.rb +32 -0
- data/lib/vines/stream/http/bind_restart.rb +37 -0
- data/lib/vines/stream/http/ready.rb +29 -0
- data/lib/vines/stream/http/request.rb +172 -0
- data/lib/vines/stream/http/session.rb +120 -0
- data/lib/vines/stream/http/sessions.rb +65 -0
- data/lib/vines/stream/http/start.rb +23 -0
- data/lib/vines/stream/http.rb +157 -0
- data/lib/vines/stream/parser.rb +79 -0
- data/lib/vines/stream/sasl.rb +128 -0
- data/lib/vines/stream/server/auth.rb +13 -0
- data/lib/vines/stream/server/auth_restart.rb +13 -0
- data/lib/vines/stream/server/final_restart.rb +21 -0
- data/lib/vines/stream/server/outbound/auth.rb +31 -0
- data/lib/vines/stream/server/outbound/auth_restart.rb +20 -0
- data/lib/vines/stream/server/outbound/auth_result.rb +32 -0
- data/lib/vines/stream/server/outbound/final_features.rb +28 -0
- data/lib/vines/stream/server/outbound/final_restart.rb +20 -0
- data/lib/vines/stream/server/outbound/start.rb +20 -0
- data/lib/vines/stream/server/outbound/tls.rb +30 -0
- data/lib/vines/stream/server/outbound/tls_result.rb +34 -0
- data/lib/vines/stream/server/ready.rb +24 -0
- data/lib/vines/stream/server/start.rb +13 -0
- data/lib/vines/stream/server/tls.rb +13 -0
- data/lib/vines/stream/server.rb +150 -0
- data/lib/vines/stream/state.rb +60 -0
- data/lib/vines/stream.rb +247 -0
- data/lib/vines/token_bucket.rb +55 -0
- data/lib/vines/user.rb +123 -0
- data/lib/vines/version.rb +6 -0
- data/lib/vines/xmpp_server.rb +25 -0
- data/lib/vines.rb +203 -0
- data/test/cluster/publisher_test.rb +57 -0
- data/test/cluster/sessions_test.rb +47 -0
- data/test/cluster/subscriber_test.rb +109 -0
- data/test/config/host_test.rb +369 -0
- data/test/config/pubsub_test.rb +187 -0
- data/test/config_test.rb +732 -0
- data/test/contact_test.rb +102 -0
- data/test/error_test.rb +58 -0
- data/test/ext/nokogiri.rb +14 -0
- data/test/jid_test.rb +147 -0
- data/test/kit_test.rb +31 -0
- data/test/router_test.rb +243 -0
- data/test/stanza/iq/disco_info_test.rb +78 -0
- data/test/stanza/iq/disco_items_test.rb +49 -0
- data/test/stanza/iq/private_storage_test.rb +184 -0
- data/test/stanza/iq/roster_test.rb +229 -0
- data/test/stanza/iq/session_test.rb +25 -0
- data/test/stanza/iq/vcard_test.rb +146 -0
- data/test/stanza/iq/version_test.rb +64 -0
- data/test/stanza/iq_test.rb +70 -0
- data/test/stanza/message_test.rb +126 -0
- data/test/stanza/presence/probe_test.rb +50 -0
- data/test/stanza/presence/subscribe_test.rb +83 -0
- data/test/stanza/pubsub/create_test.rb +116 -0
- data/test/stanza/pubsub/delete_test.rb +169 -0
- data/test/stanza/pubsub/publish_test.rb +309 -0
- data/test/stanza/pubsub/subscribe_test.rb +205 -0
- data/test/stanza/pubsub/unsubscribe_test.rb +148 -0
- data/test/stanza_test.rb +85 -0
- data/test/storage/ldap_test.rb +201 -0
- data/test/storage/local_test.rb +59 -0
- data/test/storage/mock_redis.rb +97 -0
- data/test/storage/null_test.rb +29 -0
- data/test/storage/storage_tests.rb +182 -0
- data/test/storage_test.rb +85 -0
- data/test/store_test.rb +130 -0
- data/test/stream/client/auth_test.rb +137 -0
- data/test/stream/client/ready_test.rb +47 -0
- data/test/stream/client/session_test.rb +27 -0
- data/test/stream/component/handshake_test.rb +52 -0
- data/test/stream/component/ready_test.rb +103 -0
- data/test/stream/component/start_test.rb +39 -0
- data/test/stream/http/auth_test.rb +70 -0
- data/test/stream/http/ready_test.rb +86 -0
- data/test/stream/http/request_test.rb +209 -0
- data/test/stream/http/sessions_test.rb +49 -0
- data/test/stream/http/start_test.rb +50 -0
- data/test/stream/parser_test.rb +122 -0
- data/test/stream/sasl_test.rb +195 -0
- data/test/stream/server/auth_test.rb +61 -0
- data/test/stream/server/outbound/auth_test.rb +75 -0
- data/test/stream/server/ready_test.rb +98 -0
- data/test/test_helper.rb +42 -0
- data/test/token_bucket_test.rb +44 -0
- data/test/user_test.rb +96 -0
- data/vines.gemspec +30 -0
- metadata +387 -0
@@ -0,0 +1,309 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require 'test_helper'
|
4
|
+
|
5
|
+
describe Vines::Stanza::PubSub::Publish do
|
6
|
+
subject { Vines::Stanza::PubSub::Publish.new(xml, stream) }
|
7
|
+
let(:user) { Vines::User.new(jid: 'alice@wonderland.lit/tea') }
|
8
|
+
let(:stream) { MiniTest::Mock.new }
|
9
|
+
let(:config) do
|
10
|
+
Vines::Config.new do
|
11
|
+
host 'wonderland.lit' do
|
12
|
+
storage(:fs) { dir Dir.tmpdir }
|
13
|
+
pubsub 'games'
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
before do
|
19
|
+
class << stream
|
20
|
+
attr_accessor :config, :nodes, :user
|
21
|
+
def write(node)
|
22
|
+
@nodes ||= []
|
23
|
+
@nodes << node
|
24
|
+
end
|
25
|
+
end
|
26
|
+
stream.config = config
|
27
|
+
stream.user = user
|
28
|
+
end
|
29
|
+
|
30
|
+
describe 'when missing a to address' do
|
31
|
+
let(:xml) { publish('') }
|
32
|
+
|
33
|
+
it 'raises a feature-not-implemented stanza error' do
|
34
|
+
stream.expect(:domain, 'wonderland.lit')
|
35
|
+
-> { subject.process }.must_raise Vines::StanzaErrors::FeatureNotImplemented
|
36
|
+
stream.verify
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe 'when addressed to bare server domain' do
|
41
|
+
let(:xml) { publish('wonderland.lit') }
|
42
|
+
|
43
|
+
it 'raises a feature-not-implemented stanza error' do
|
44
|
+
-> { subject.process }.must_raise Vines::StanzaErrors::FeatureNotImplemented
|
45
|
+
stream.verify
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe 'when addressed to a non-pubsub component' do
|
50
|
+
let(:router) { MiniTest::Mock.new }
|
51
|
+
let(:xml) { publish('bogus.wonderland.lit') }
|
52
|
+
|
53
|
+
before do
|
54
|
+
router.expect :route, nil, [xml]
|
55
|
+
stream.expect :router, router
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'routes rather than handle locally' do
|
59
|
+
subject.process
|
60
|
+
stream.verify
|
61
|
+
router.verify
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe 'when publishing to multiple nodes' do
|
66
|
+
let(:xml) do
|
67
|
+
node(%q{
|
68
|
+
<iq type='set' to='games.wonderland.lit' id='42'>
|
69
|
+
<pubsub xmlns='http://jabber.org/protocol/pubsub'>
|
70
|
+
<publish node='game_13'>
|
71
|
+
<item id='item_42'>
|
72
|
+
<entry xmlns='http://www.w3.org/2005/Atom'>
|
73
|
+
<title>Test</title>
|
74
|
+
<summary>This is a summary.</summary>
|
75
|
+
</entry>
|
76
|
+
</item>
|
77
|
+
</publish>
|
78
|
+
<publish node='game_13'>
|
79
|
+
<item id='item_42'>
|
80
|
+
<entry xmlns='http://www.w3.org/2005/Atom'>
|
81
|
+
<title>Test</title>
|
82
|
+
<summary>This is a summary.</summary>
|
83
|
+
</entry>
|
84
|
+
</item>
|
85
|
+
</publish>
|
86
|
+
</pubsub>
|
87
|
+
</iq>
|
88
|
+
})
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'raises a bad-request stanza error' do
|
92
|
+
-> { subject.process }.must_raise Vines::StanzaErrors::BadRequest
|
93
|
+
stream.verify
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
describe 'when publishing multiple items' do
|
98
|
+
let(:pubsub) { MiniTest::Mock.new }
|
99
|
+
let(:xml) do
|
100
|
+
node(%q{
|
101
|
+
<iq type='set' to='games.wonderland.lit' id='42'>
|
102
|
+
<pubsub xmlns='http://jabber.org/protocol/pubsub'>
|
103
|
+
<publish node='game_13'>
|
104
|
+
<item id='item_42'>
|
105
|
+
<entry xmlns='http://www.w3.org/2005/Atom'>
|
106
|
+
<title>Test</title>
|
107
|
+
<summary>This is a summary.</summary>
|
108
|
+
</entry>
|
109
|
+
</item>
|
110
|
+
<item id="item_43">bad</item>
|
111
|
+
</publish>
|
112
|
+
</pubsub>
|
113
|
+
</iq>
|
114
|
+
})
|
115
|
+
end
|
116
|
+
|
117
|
+
it 'raises a bad-request stanza error' do
|
118
|
+
pubsub.expect :node?, true, ['game_13']
|
119
|
+
subject.stub :pubsub, pubsub do
|
120
|
+
-> { subject.process }.must_raise Vines::StanzaErrors::BadRequest
|
121
|
+
end
|
122
|
+
stream.verify
|
123
|
+
pubsub.verify
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
describe 'when publishing one item with multiple payloads' do
|
128
|
+
let(:pubsub) { MiniTest::Mock.new }
|
129
|
+
let(:xml) do
|
130
|
+
node(%q{
|
131
|
+
<iq type='set' to='games.wonderland.lit' id='42'>
|
132
|
+
<pubsub xmlns='http://jabber.org/protocol/pubsub'>
|
133
|
+
<publish node='game_13'>
|
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
|
+
<entry>bad</entry>
|
140
|
+
</item>
|
141
|
+
</publish>
|
142
|
+
</pubsub>
|
143
|
+
</iq>
|
144
|
+
})
|
145
|
+
end
|
146
|
+
|
147
|
+
it 'raises a bad-request stanza error' do
|
148
|
+
pubsub.expect :node?, true, ['game_13']
|
149
|
+
subject.stub :pubsub, pubsub do
|
150
|
+
-> { subject.process }.must_raise Vines::StanzaErrors::BadRequest
|
151
|
+
end
|
152
|
+
stream.verify
|
153
|
+
pubsub.verify
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
describe 'when publishing with no payload' do
|
158
|
+
let(:pubsub) { MiniTest::Mock.new }
|
159
|
+
let(:xml) do
|
160
|
+
node(%q{
|
161
|
+
<iq type='set' to='games.wonderland.lit' id='42'>
|
162
|
+
<pubsub xmlns='http://jabber.org/protocol/pubsub'>
|
163
|
+
<publish node='game_13'>
|
164
|
+
<item id='item_42'>
|
165
|
+
</item>
|
166
|
+
</publish>
|
167
|
+
</pubsub>
|
168
|
+
</iq>
|
169
|
+
})
|
170
|
+
end
|
171
|
+
|
172
|
+
it 'raises a bad-request stanza error' do
|
173
|
+
pubsub.expect :node?, true, ['game_13']
|
174
|
+
subject.stub :pubsub, pubsub do
|
175
|
+
-> { subject.process }.must_raise Vines::StanzaErrors::BadRequest
|
176
|
+
end
|
177
|
+
stream.verify
|
178
|
+
pubsub.verify
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
describe 'when publishing to a missing node' do
|
183
|
+
let(:xml) { publish('games.wonderland.lit') }
|
184
|
+
|
185
|
+
it 'raises an item-not-found stanza error' do
|
186
|
+
-> { subject.process }.must_raise Vines::StanzaErrors::ItemNotFound
|
187
|
+
stream.verify
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
describe 'when publishing an item without an id' do
|
192
|
+
let(:pubsub) { MiniTest::Mock.new }
|
193
|
+
let(:xml) { publish('games.wonderland.lit', '') }
|
194
|
+
let(:broadcast) { message_broadcast('') }
|
195
|
+
let(:response) do
|
196
|
+
node(%q{
|
197
|
+
<iq from="games.wonderland.lit" id="42" to="alice@wonderland.lit/tea" type="result">
|
198
|
+
<pubsub xmlns="http://jabber.org/protocol/pubsub">
|
199
|
+
<publish node="game_13">
|
200
|
+
<item/>
|
201
|
+
</publish>
|
202
|
+
</pubsub>
|
203
|
+
</iq>})
|
204
|
+
end
|
205
|
+
|
206
|
+
before do
|
207
|
+
pubsub.expect :node?, true, ['game_13']
|
208
|
+
def pubsub.published; @published; end
|
209
|
+
def pubsub.publish(node, message)
|
210
|
+
@published ||= []
|
211
|
+
@published << [node, message]
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
it 'generates an item id in the response' do
|
216
|
+
subject.stub :pubsub, pubsub do
|
217
|
+
subject.process
|
218
|
+
end
|
219
|
+
stream.verify
|
220
|
+
pubsub.verify
|
221
|
+
stream.nodes.size.must_equal 1
|
222
|
+
|
223
|
+
# id is random
|
224
|
+
item = stream.nodes.first.xpath('ns:pubsub/ns:publish/ns:item',
|
225
|
+
'ns' => 'http://jabber.org/protocol/pubsub').first
|
226
|
+
item['id'].wont_be_nil
|
227
|
+
item.remove_attribute('id')
|
228
|
+
stream.nodes.first.must_equal response
|
229
|
+
end
|
230
|
+
|
231
|
+
it 'broadcasts the message with the generated item id' do
|
232
|
+
subject.stub :pubsub, pubsub do
|
233
|
+
subject.process
|
234
|
+
end
|
235
|
+
stream.verify
|
236
|
+
pubsub.verify
|
237
|
+
stream.nodes.size.must_equal 1
|
238
|
+
|
239
|
+
published_node, published_message = *pubsub.published[0]
|
240
|
+
published_node.must_equal 'game_13'
|
241
|
+
# id is random
|
242
|
+
item = published_message.xpath('ns:event/ns:items/ns:item',
|
243
|
+
'ns' => 'http://jabber.org/protocol/pubsub#event').first
|
244
|
+
item['id'].wont_be_nil
|
245
|
+
item.remove_attribute('id')
|
246
|
+
published_message.must_equal broadcast
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
describe 'when publishing a valid stanza' do
|
251
|
+
let(:pubsub) { MiniTest::Mock.new }
|
252
|
+
let(:xml) { publish('games.wonderland.lit') }
|
253
|
+
let(:response) { result(user.jid, 'games.wonderland.lit') }
|
254
|
+
let(:broadcast) { message_broadcast('item_42') }
|
255
|
+
|
256
|
+
it 'broadcasts and returns result to sender' do
|
257
|
+
pubsub.expect :node?, true, ['game_13']
|
258
|
+
pubsub.expect :publish, nil, ['game_13', broadcast]
|
259
|
+
|
260
|
+
subject.stub :pubsub, pubsub do
|
261
|
+
subject.process
|
262
|
+
end
|
263
|
+
|
264
|
+
stream.nodes.size.must_equal 1
|
265
|
+
stream.nodes.first.must_equal response
|
266
|
+
stream.verify
|
267
|
+
pubsub.verify
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
private
|
272
|
+
|
273
|
+
def message_broadcast(item_id)
|
274
|
+
item_id = (item_id.nil? || item_id.empty?) ? ' ' : " id='#{item_id}' "
|
275
|
+
node(%Q{
|
276
|
+
<message>
|
277
|
+
<event xmlns="http://jabber.org/protocol/pubsub#event">
|
278
|
+
<items node="game_13">
|
279
|
+
<item#{item_id}publisher="alice@wonderland.lit/tea">
|
280
|
+
<entry xmlns="http://www.w3.org/2005/Atom">
|
281
|
+
<title>Test</title>
|
282
|
+
<summary>This is a summary.</summary>
|
283
|
+
</entry>
|
284
|
+
</item>
|
285
|
+
</items>
|
286
|
+
</event>
|
287
|
+
</message>})
|
288
|
+
end
|
289
|
+
|
290
|
+
def publish(to, item_id='item_42')
|
291
|
+
item_id = "id='#{item_id}'" unless item_id.nil? || item_id.empty?
|
292
|
+
body = %Q{
|
293
|
+
<pubsub xmlns='http://jabber.org/protocol/pubsub'>
|
294
|
+
<publish node='game_13'>
|
295
|
+
<item #{item_id}>
|
296
|
+
<entry xmlns='http://www.w3.org/2005/Atom'>
|
297
|
+
<title>Test</title>
|
298
|
+
<summary>This is a summary.</summary>
|
299
|
+
</entry>
|
300
|
+
</item>
|
301
|
+
</publish>
|
302
|
+
</pubsub>}
|
303
|
+
iq(type: 'set', to: to, id: 42, body: body)
|
304
|
+
end
|
305
|
+
|
306
|
+
def result(to, from)
|
307
|
+
iq(from: from, id: 42, to: to, type: 'result')
|
308
|
+
end
|
309
|
+
end
|
@@ -0,0 +1,205 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require 'test_helper'
|
4
|
+
|
5
|
+
describe Vines::Stanza::PubSub::Subscribe do
|
6
|
+
subject { Vines::Stanza::PubSub::Subscribe.new(xml, stream) }
|
7
|
+
let(:alice) { Vines::User.new(jid: 'alice@wonderland.lit/tea') }
|
8
|
+
let(:stream) { MiniTest::Mock.new }
|
9
|
+
let(:config) do
|
10
|
+
Vines::Config.new do
|
11
|
+
host 'wonderland.lit' do
|
12
|
+
storage(:fs) { dir Dir.tmpdir }
|
13
|
+
pubsub 'games'
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
before do
|
19
|
+
class << stream
|
20
|
+
attr_accessor :config, :domain, :nodes, :user
|
21
|
+
def write(node)
|
22
|
+
@nodes ||= []
|
23
|
+
@nodes << node
|
24
|
+
end
|
25
|
+
end
|
26
|
+
stream.config = config
|
27
|
+
stream.user = alice
|
28
|
+
stream.domain = 'wonderland.lit'
|
29
|
+
end
|
30
|
+
|
31
|
+
describe 'when missing a to address' do
|
32
|
+
let(:xml) do
|
33
|
+
node(%q{
|
34
|
+
<iq type='set' id='42'>
|
35
|
+
<pubsub xmlns='http://jabber.org/protocol/pubsub'>
|
36
|
+
<subscribe node='game_13' jid="alice@wonderland.lit/tea"/>
|
37
|
+
</pubsub>
|
38
|
+
</iq>
|
39
|
+
})
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'raises a feature-not-implemented stanza error' do
|
43
|
+
-> { subject.process }.must_raise Vines::StanzaErrors::FeatureNotImplemented
|
44
|
+
stream.verify
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe 'when addressed to a bare server domain' do
|
49
|
+
let(:xml) do
|
50
|
+
node(%q{
|
51
|
+
<iq type='set' to='wonderland.lit' id='42'>
|
52
|
+
<pubsub xmlns='http://jabber.org/protocol/pubsub'>
|
53
|
+
<subscribe node='game_13' jid="alice@wonderland.lit/tea"/>
|
54
|
+
</pubsub>
|
55
|
+
</iq>
|
56
|
+
})
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'raises a feature-not-implemented stanza error' do
|
60
|
+
-> { subject.process }.must_raise Vines::StanzaErrors::FeatureNotImplemented
|
61
|
+
stream.verify
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe 'when addressed to a non-pubsub address' do
|
66
|
+
let(:router) { MiniTest::Mock.new }
|
67
|
+
let(:xml) do
|
68
|
+
node(%q{
|
69
|
+
<iq type='set' to='bogus.wonderland.lit' id='42'>
|
70
|
+
<pubsub xmlns='http://jabber.org/protocol/pubsub'>
|
71
|
+
<subscribe node='game_13' jid="alice@wonderland.lit/tea"/>
|
72
|
+
</pubsub>
|
73
|
+
</iq>
|
74
|
+
})
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'routes rather than handle locally' do
|
78
|
+
router.expect :route, nil, [xml]
|
79
|
+
stream.expect :router, router
|
80
|
+
|
81
|
+
subject.process
|
82
|
+
stream.verify
|
83
|
+
router.verify
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
describe 'when stanza contains multiple subscribe elements' do
|
88
|
+
let(:xml) do
|
89
|
+
node(%q{
|
90
|
+
<iq type='set' to='games.wonderland.lit' id='42'>
|
91
|
+
<pubsub xmlns='http://jabber.org/protocol/pubsub'>
|
92
|
+
<subscribe node='game_13' jid="alice@wonderland.lit/tea"/>
|
93
|
+
<subscribe node='game_14' jid="alice@wonderland.lit/tea"/>
|
94
|
+
</pubsub>
|
95
|
+
</iq>
|
96
|
+
})
|
97
|
+
end
|
98
|
+
|
99
|
+
it 'raises a bad-request stanza error' do
|
100
|
+
-> { subject.process }.must_raise Vines::StanzaErrors::BadRequest
|
101
|
+
stream.verify
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
describe 'when stanza is missing a subscribe element' do
|
106
|
+
let(:xml) do
|
107
|
+
node(%q{
|
108
|
+
<iq type='set' to='games.wonderland.lit' id='42'>
|
109
|
+
<pubsub xmlns='http://jabber.org/protocol/pubsub'>
|
110
|
+
<subscribe node='game_13' jid="alice@wonderland.lit/tea"/>
|
111
|
+
</pubsub>
|
112
|
+
</iq>
|
113
|
+
})
|
114
|
+
end
|
115
|
+
|
116
|
+
it 'raises an item-not-found stanza error' do
|
117
|
+
-> { subject.process }.must_raise Vines::StanzaErrors::ItemNotFound
|
118
|
+
stream.verify
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
describe 'when attempting to subscribe to a node twice' do
|
123
|
+
let(:pubsub) { MiniTest::Mock.new }
|
124
|
+
let(:xml) do
|
125
|
+
node(%q{
|
126
|
+
<iq type='set' to='games.wonderland.lit' id='42'>
|
127
|
+
<pubsub xmlns='http://jabber.org/protocol/pubsub'>
|
128
|
+
<subscribe node='game_13' jid="alice@wonderland.lit/tea"/>
|
129
|
+
</pubsub>
|
130
|
+
</iq>
|
131
|
+
})
|
132
|
+
end
|
133
|
+
|
134
|
+
before do
|
135
|
+
pubsub.expect :node?, true, ['game_13']
|
136
|
+
pubsub.expect :subscribed?, true, ['game_13', alice.jid]
|
137
|
+
end
|
138
|
+
|
139
|
+
it 'raises a policy-violation stanza error' do
|
140
|
+
subject.stub :pubsub, pubsub do
|
141
|
+
-> { subject.process }.must_raise Vines::StanzaErrors::PolicyViolation
|
142
|
+
end
|
143
|
+
stream.verify
|
144
|
+
pubsub.verify
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
describe 'when subscribing with an illegal jid' do
|
149
|
+
let(:xml) do
|
150
|
+
node(%q{
|
151
|
+
<iq type='set' to='games.wonderland.lit' id='42'>
|
152
|
+
<pubsub xmlns='http://jabber.org/protocol/pubsub'>
|
153
|
+
<subscribe node='game_13' jid="not_alice@wonderland.lit/tea"/>
|
154
|
+
</pubsub>
|
155
|
+
</iq>
|
156
|
+
})
|
157
|
+
end
|
158
|
+
|
159
|
+
it 'raises a bad-request stanza error' do
|
160
|
+
-> { subject.process }.must_raise Vines::StanzaErrors::BadRequest
|
161
|
+
stream.verify
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
describe 'when subscribing with a valid stanza' do
|
166
|
+
let(:xml) do
|
167
|
+
node(%q{
|
168
|
+
<iq type='set' to='games.wonderland.lit' id='42'>
|
169
|
+
<pubsub xmlns='http://jabber.org/protocol/pubsub'>
|
170
|
+
<subscribe node='game_13' jid="alice@wonderland.lit/tea"/>
|
171
|
+
</pubsub>
|
172
|
+
</iq>
|
173
|
+
})
|
174
|
+
end
|
175
|
+
|
176
|
+
let(:expected) do
|
177
|
+
node(%q{
|
178
|
+
<iq from="games.wonderland.lit" id="42" to="alice@wonderland.lit/tea" type="result">
|
179
|
+
<pubsub xmlns="http://jabber.org/protocol/pubsub">
|
180
|
+
<subscription node="game_13" jid="alice@wonderland.lit/tea" subscription="subscribed"/>
|
181
|
+
</pubsub>
|
182
|
+
</iq>
|
183
|
+
})
|
184
|
+
end
|
185
|
+
|
186
|
+
let(:pubsub) { MiniTest::Mock.new }
|
187
|
+
|
188
|
+
before do
|
189
|
+
pubsub.expect :node?, true, ['game_13']
|
190
|
+
pubsub.expect :subscribed?, false, ['game_13', alice.jid]
|
191
|
+
pubsub.expect :subscribe, nil, ['game_13', alice.jid]
|
192
|
+
end
|
193
|
+
|
194
|
+
it 'writes a result stanza to the stream' do
|
195
|
+
subject.stub :pubsub, pubsub do
|
196
|
+
subject.process
|
197
|
+
end
|
198
|
+
|
199
|
+
stream.verify
|
200
|
+
pubsub.verify
|
201
|
+
stream.nodes.size.must_equal 1
|
202
|
+
stream.nodes.first.must_equal expected
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
@@ -0,0 +1,148 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require 'test_helper'
|
4
|
+
|
5
|
+
describe Vines::Stanza::PubSub::Unsubscribe do
|
6
|
+
subject { Vines::Stanza::PubSub::Unsubscribe.new(xml, stream) }
|
7
|
+
let(:user) { Vines::User.new(jid: 'alice@wonderland.lit/tea') }
|
8
|
+
let(:stream) { MiniTest::Mock.new }
|
9
|
+
let(:config) do
|
10
|
+
Vines::Config.new do
|
11
|
+
host 'wonderland.lit' do
|
12
|
+
storage(:fs) { dir Dir.tmpdir }
|
13
|
+
pubsub 'games'
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
before do
|
19
|
+
class << stream
|
20
|
+
attr_accessor :config, :nodes, :user
|
21
|
+
def write(node)
|
22
|
+
@nodes ||= []
|
23
|
+
@nodes << node
|
24
|
+
end
|
25
|
+
end
|
26
|
+
stream.config = config
|
27
|
+
stream.user = user
|
28
|
+
end
|
29
|
+
|
30
|
+
describe 'when missing a to address' do
|
31
|
+
let(:xml) { unsubscribe('') }
|
32
|
+
|
33
|
+
it 'raises a feature-not-implemented stanza error' do
|
34
|
+
stream.expect :domain, 'wonderland.lit'
|
35
|
+
-> { subject.process }.must_raise Vines::StanzaErrors::FeatureNotImplemented
|
36
|
+
stream.verify
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe 'when addressed to bare server domain' do
|
41
|
+
let(:xml) { unsubscribe('wonderland.lit') }
|
42
|
+
|
43
|
+
it 'raises a feature-not-implemented stanza error' do
|
44
|
+
-> { subject.process }.must_raise Vines::StanzaErrors::FeatureNotImplemented
|
45
|
+
stream.verify
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe 'when addressed to a non-pubsub component' do
|
50
|
+
let(:router) { MiniTest::Mock.new }
|
51
|
+
let(:xml) { unsubscribe('bogus.wonderland.lit') }
|
52
|
+
|
53
|
+
before do
|
54
|
+
router.expect :route, nil, [xml]
|
55
|
+
stream.expect :router, router
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'routes rather than handle locally' do
|
59
|
+
subject.process
|
60
|
+
stream.verify
|
61
|
+
router.verify
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe 'when attempting to unsubscribe from multiple nodes' do
|
66
|
+
let(:xml) { unsubscribe('games.wonderland.lit', true) }
|
67
|
+
|
68
|
+
it 'raises a bad-request stanza error' do
|
69
|
+
-> { subject.process }.must_raise Vines::StanzaErrors::BadRequest
|
70
|
+
stream.verify
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
describe 'when unsubscribing from a missing node' do
|
75
|
+
let(:xml) { unsubscribe('games.wonderland.lit') }
|
76
|
+
|
77
|
+
it 'raises an item-not-found stanza error' do
|
78
|
+
-> { subject.process }.must_raise Vines::StanzaErrors::ItemNotFound
|
79
|
+
stream.verify
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
describe 'when unsubscribing without a subscription' do
|
84
|
+
let(:pubsub) { MiniTest::Mock.new }
|
85
|
+
let(:xml) { unsubscribe('games.wonderland.lit') }
|
86
|
+
|
87
|
+
before do
|
88
|
+
pubsub.expect :node?, true, ['game_13']
|
89
|
+
pubsub.expect :subscribed?, false, ['game_13', user.jid]
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'raises an unexpected-request stanza error' do
|
93
|
+
subject.stub :pubsub, pubsub do
|
94
|
+
-> { subject.process }.must_raise Vines::StanzaErrors::UnexpectedRequest
|
95
|
+
end
|
96
|
+
stream.verify
|
97
|
+
pubsub.verify
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
describe 'when unsubscribing an illegal jid' do
|
102
|
+
let(:xml) { unsubscribe('games.wonderland.lit', false, 'not_alice@wonderland.lit/tea') }
|
103
|
+
|
104
|
+
it 'raises a forbidden stanza error' do
|
105
|
+
-> { subject.process }.must_raise Vines::StanzaErrors::Forbidden
|
106
|
+
stream.verify
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
describe 'when given a valid stanza' do
|
111
|
+
let(:pubsub) { MiniTest::Mock.new }
|
112
|
+
let(:xml) { unsubscribe('games.wonderland.lit') }
|
113
|
+
let(:expected) { result(user.jid, 'games.wonderland.lit') }
|
114
|
+
|
115
|
+
before do
|
116
|
+
pubsub.expect :node?, true, ['game_13']
|
117
|
+
pubsub.expect :subscribed?, true, ['game_13', user.jid]
|
118
|
+
pubsub.expect :unsubscribe, nil, ['game_13', user.jid]
|
119
|
+
end
|
120
|
+
|
121
|
+
it 'sends an iq result stanza to sender' do
|
122
|
+
subject.stub :pubsub, pubsub do
|
123
|
+
subject.process
|
124
|
+
end
|
125
|
+
|
126
|
+
stream.nodes.size.must_equal 1
|
127
|
+
stream.nodes.first.must_equal expected
|
128
|
+
stream.verify
|
129
|
+
pubsub.verify
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
private
|
134
|
+
|
135
|
+
def unsubscribe(to, multiple=false, jid=user.jid)
|
136
|
+
extra = "<unsubscribe node='game_14' jid='#{jid}'/>" if multiple
|
137
|
+
body = %Q{
|
138
|
+
<pubsub xmlns='http://jabber.org/protocol/pubsub'>
|
139
|
+
<unsubscribe node='game_13' jid="#{jid}"/>
|
140
|
+
#{extra}
|
141
|
+
</pubsub>}
|
142
|
+
iq(type: 'set', to: to, id: 42, body: body)
|
143
|
+
end
|
144
|
+
|
145
|
+
def result(to, from)
|
146
|
+
iq(from: from, id: 42, to: to, type: 'result')
|
147
|
+
end
|
148
|
+
end
|