shingara-blather 0.4.8
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.
- data/LICENSE +22 -0
- data/README.md +162 -0
- data/examples/echo.rb +18 -0
- data/examples/execute.rb +16 -0
- data/examples/ping_pong.rb +37 -0
- data/examples/print_hierarchy.rb +76 -0
- data/examples/rosterprint.rb +14 -0
- data/examples/stream_only.rb +27 -0
- data/examples/xmpp4r/echo.rb +35 -0
- data/lib/blather/client/client.rb +310 -0
- data/lib/blather/client/dsl/pubsub.rb +170 -0
- data/lib/blather/client/dsl.rb +264 -0
- data/lib/blather/client.rb +87 -0
- data/lib/blather/core_ext/nokogiri.rb +40 -0
- data/lib/blather/errors/sasl_error.rb +43 -0
- data/lib/blather/errors/stanza_error.rb +107 -0
- data/lib/blather/errors/stream_error.rb +82 -0
- data/lib/blather/errors.rb +69 -0
- data/lib/blather/jid.rb +142 -0
- data/lib/blather/roster.rb +111 -0
- data/lib/blather/roster_item.rb +122 -0
- data/lib/blather/stanza/disco/disco_info.rb +176 -0
- data/lib/blather/stanza/disco/disco_items.rb +132 -0
- data/lib/blather/stanza/disco.rb +25 -0
- data/lib/blather/stanza/iq/query.rb +53 -0
- data/lib/blather/stanza/iq/roster.rb +179 -0
- data/lib/blather/stanza/iq.rb +138 -0
- data/lib/blather/stanza/message.rb +332 -0
- data/lib/blather/stanza/presence/status.rb +212 -0
- data/lib/blather/stanza/presence/subscription.rb +101 -0
- data/lib/blather/stanza/presence.rb +163 -0
- data/lib/blather/stanza/pubsub/affiliations.rb +79 -0
- data/lib/blather/stanza/pubsub/create.rb +65 -0
- data/lib/blather/stanza/pubsub/errors.rb +18 -0
- data/lib/blather/stanza/pubsub/event.rb +123 -0
- data/lib/blather/stanza/pubsub/items.rb +103 -0
- data/lib/blather/stanza/pubsub/publish.rb +103 -0
- data/lib/blather/stanza/pubsub/retract.rb +92 -0
- data/lib/blather/stanza/pubsub/subscribe.rb +68 -0
- data/lib/blather/stanza/pubsub/subscription.rb +134 -0
- data/lib/blather/stanza/pubsub/subscriptions.rb +81 -0
- data/lib/blather/stanza/pubsub/unsubscribe.rb +68 -0
- data/lib/blather/stanza/pubsub.rb +129 -0
- data/lib/blather/stanza/pubsub_owner/delete.rb +52 -0
- data/lib/blather/stanza/pubsub_owner/purge.rb +52 -0
- data/lib/blather/stanza/pubsub_owner.rb +51 -0
- data/lib/blather/stanza.rb +149 -0
- data/lib/blather/stream/client.rb +31 -0
- data/lib/blather/stream/component.rb +38 -0
- data/lib/blather/stream/features/resource.rb +63 -0
- data/lib/blather/stream/features/sasl.rb +187 -0
- data/lib/blather/stream/features/session.rb +44 -0
- data/lib/blather/stream/features/tls.rb +28 -0
- data/lib/blather/stream/features.rb +53 -0
- data/lib/blather/stream/parser.rb +102 -0
- data/lib/blather/stream.rb +231 -0
- data/lib/blather/xmpp_node.rb +218 -0
- data/lib/blather.rb +78 -0
- data/spec/blather/client/client_spec.rb +559 -0
- data/spec/blather/client/dsl/pubsub_spec.rb +462 -0
- data/spec/blather/client/dsl_spec.rb +143 -0
- data/spec/blather/core_ext/nokogiri_spec.rb +83 -0
- data/spec/blather/errors/sasl_error_spec.rb +33 -0
- data/spec/blather/errors/stanza_error_spec.rb +129 -0
- data/spec/blather/errors/stream_error_spec.rb +108 -0
- data/spec/blather/errors_spec.rb +33 -0
- data/spec/blather/jid_spec.rb +87 -0
- data/spec/blather/roster_item_spec.rb +96 -0
- data/spec/blather/roster_spec.rb +103 -0
- data/spec/blather/stanza/discos/disco_info_spec.rb +226 -0
- data/spec/blather/stanza/discos/disco_items_spec.rb +148 -0
- data/spec/blather/stanza/iq/query_spec.rb +64 -0
- data/spec/blather/stanza/iq/roster_spec.rb +140 -0
- data/spec/blather/stanza/iq_spec.rb +45 -0
- data/spec/blather/stanza/message_spec.rb +132 -0
- data/spec/blather/stanza/presence/status_spec.rb +132 -0
- data/spec/blather/stanza/presence/subscription_spec.rb +105 -0
- data/spec/blather/stanza/presence_spec.rb +66 -0
- data/spec/blather/stanza/pubsub/affiliations_spec.rb +57 -0
- data/spec/blather/stanza/pubsub/create_spec.rb +56 -0
- data/spec/blather/stanza/pubsub/event_spec.rb +84 -0
- data/spec/blather/stanza/pubsub/items_spec.rb +79 -0
- data/spec/blather/stanza/pubsub/publish_spec.rb +83 -0
- data/spec/blather/stanza/pubsub/retract_spec.rb +75 -0
- data/spec/blather/stanza/pubsub/subscribe_spec.rb +61 -0
- data/spec/blather/stanza/pubsub/subscription_spec.rb +97 -0
- data/spec/blather/stanza/pubsub/subscriptions_spec.rb +59 -0
- data/spec/blather/stanza/pubsub/unsubscribe_spec.rb +61 -0
- data/spec/blather/stanza/pubsub_owner/delete_spec.rb +50 -0
- data/spec/blather/stanza/pubsub_owner/purge_spec.rb +50 -0
- data/spec/blather/stanza/pubsub_owner_spec.rb +27 -0
- data/spec/blather/stanza/pubsub_spec.rb +67 -0
- data/spec/blather/stanza_spec.rb +116 -0
- data/spec/blather/stream/client_spec.rb +1011 -0
- data/spec/blather/stream/component_spec.rb +95 -0
- data/spec/blather/stream/parser_spec.rb +145 -0
- data/spec/blather/xmpp_node_spec.rb +231 -0
- data/spec/fixtures/pubsub.rb +311 -0
- data/spec/spec_helper.rb +43 -0
- metadata +249 -0
|
@@ -0,0 +1,559 @@
|
|
|
1
|
+
require File.join(File.dirname(__FILE__), *%w[.. .. spec_helper])
|
|
2
|
+
require 'blather/client/client'
|
|
3
|
+
|
|
4
|
+
describe Blather::Client do
|
|
5
|
+
before do
|
|
6
|
+
@client = Blather::Client.new
|
|
7
|
+
@stream = mock()
|
|
8
|
+
@stream.stubs(:send)
|
|
9
|
+
@jid = Blather::JID.new('n@d/r')
|
|
10
|
+
@client.post_init @stream, @jid
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
it 'provides a Blather::JID reader' do
|
|
14
|
+
@client.must_respond_to :jid
|
|
15
|
+
@client.jid.must_equal @jid
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
it 'provides a reader for the roster' do
|
|
19
|
+
@client.must_respond_to :roster
|
|
20
|
+
@client.roster.must_be_kind_of Blather::Roster
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
it 'provides a status reader' do
|
|
24
|
+
@client.must_respond_to :status
|
|
25
|
+
@client.status = :away
|
|
26
|
+
@client.status.must_equal :away
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it 'can be setup' do
|
|
30
|
+
@client.must_respond_to :setup
|
|
31
|
+
@client.setup('me@me.com', 'pass').must_equal @client
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
it 'knows if it has been setup' do
|
|
35
|
+
@client.must_respond_to :setup?
|
|
36
|
+
@client.setup?.must_equal false
|
|
37
|
+
@client.setup 'me@me.com', 'pass'
|
|
38
|
+
@client.setup?.must_equal true
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
it 'cannot be run before being setup' do
|
|
42
|
+
lambda { @client.run }.must_raise RuntimeError
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
it 'starts up a Component connection when setup without a node' do
|
|
46
|
+
setup = 'pubsub.jabber.local', 'secret'
|
|
47
|
+
@client.setup *setup
|
|
48
|
+
Blather::Stream::Component.expects(:start).with @client, *setup
|
|
49
|
+
@client.run
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
it 'starts up a Client connection when setup with a node' do
|
|
53
|
+
setup = 'test@jabber.local', 'secret'
|
|
54
|
+
@client.setup *setup
|
|
55
|
+
Blather::Stream::Client.expects(:start).with @client, *setup
|
|
56
|
+
@client.run
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
it 'writes to the connection the closes when #close is called' do
|
|
60
|
+
stream = mock()
|
|
61
|
+
stream.expects(:close_connection_after_writing)
|
|
62
|
+
@client.setup('me.com', 'secret')
|
|
63
|
+
@client.post_init stream, Blather::JID.new('me.com')
|
|
64
|
+
@client.close
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
it 'shuts down EM when #unbind is called if it is running' do
|
|
68
|
+
EM.expects(:reactor_running?).returns true
|
|
69
|
+
EM.expects(:stop)
|
|
70
|
+
@client.unbind
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
it 'does nothing when #unbind is called and EM is not running' do
|
|
74
|
+
EM.expects(:reactor_running?).returns false
|
|
75
|
+
EM.expects(:stop).never
|
|
76
|
+
@client.unbind
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
it 'calls the :disconnected handler with #unbind is called' do
|
|
80
|
+
EM.expects(:reactor_running?).returns false
|
|
81
|
+
disconnected = mock()
|
|
82
|
+
disconnected.expects(:call)
|
|
83
|
+
@client.register_handler(:disconnected) { disconnected.call }
|
|
84
|
+
@client.unbind
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
it 'does not call EM.stop on #unbind if a handler returns positive' do
|
|
88
|
+
EM.expects(:reactor_running?).never
|
|
89
|
+
EM.expects(:stop).never
|
|
90
|
+
disconnected = mock()
|
|
91
|
+
disconnected.expects(:call).returns true
|
|
92
|
+
@client.register_handler(:disconnected) { disconnected.call }
|
|
93
|
+
@client.unbind
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
it 'calls EM.stop on #unbind if a handler returns negative' do
|
|
97
|
+
EM.expects(:reactor_running?).returns true
|
|
98
|
+
EM.expects(:stop)
|
|
99
|
+
disconnected = mock()
|
|
100
|
+
disconnected.expects(:call).returns false
|
|
101
|
+
@client.register_handler(:disconnected) { disconnected.call }
|
|
102
|
+
@client.unbind
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
it 'can register a temporary handler based on stanza ID' do
|
|
106
|
+
stanza = Blather::Stanza::Iq.new
|
|
107
|
+
response = mock()
|
|
108
|
+
response.expects(:call)
|
|
109
|
+
@client.register_tmp_handler(stanza.id) { |_| response.call }
|
|
110
|
+
@client.receive_data stanza
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
it 'removes a tmp handler as soon as it is used' do
|
|
114
|
+
stanza = Blather::Stanza::Iq.new
|
|
115
|
+
response = mock()
|
|
116
|
+
response.expects(:call)
|
|
117
|
+
@client.register_tmp_handler(stanza.id) { |_| response.call }
|
|
118
|
+
@client.receive_data stanza
|
|
119
|
+
@client.receive_data stanza
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
it 'will create a handler then write the stanza' do
|
|
123
|
+
stanza = Blather::Stanza::Iq.new
|
|
124
|
+
response = mock()
|
|
125
|
+
response.expects(:call)
|
|
126
|
+
@client.expects(:write).with do |s|
|
|
127
|
+
@client.receive_data stanza
|
|
128
|
+
s.must_equal stanza
|
|
129
|
+
end
|
|
130
|
+
@client.write_with_handler(stanza) { |_| response.call }
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
it 'can register a handler' do
|
|
134
|
+
stanza = Blather::Stanza::Iq.new
|
|
135
|
+
response = mock()
|
|
136
|
+
response.expects(:call).times(2)
|
|
137
|
+
@client.register_handler(:iq) { |_| response.call }
|
|
138
|
+
@client.receive_data stanza
|
|
139
|
+
@client.receive_data stanza
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
it 'allows for breaking out of handlers' do
|
|
143
|
+
stanza = Blather::Stanza::Iq.new
|
|
144
|
+
response = mock(:iq => nil)
|
|
145
|
+
@client.register_handler(:iq) do |_|
|
|
146
|
+
response.iq
|
|
147
|
+
throw :halt
|
|
148
|
+
response.fail
|
|
149
|
+
end
|
|
150
|
+
@client.receive_data stanza
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
it 'allows for passing to the next handler of the same type' do
|
|
154
|
+
stanza = Blather::Stanza::Iq.new
|
|
155
|
+
response = mock(:iq1 => nil, :iq2 => nil)
|
|
156
|
+
@client.register_handler(:iq) do |_|
|
|
157
|
+
response.iq1
|
|
158
|
+
throw :pass
|
|
159
|
+
response.fail
|
|
160
|
+
end
|
|
161
|
+
@client.register_handler(:iq) do |_|
|
|
162
|
+
response.iq2
|
|
163
|
+
end
|
|
164
|
+
@client.receive_data stanza
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
it 'allows for passing to the next handler in the hierarchy' do
|
|
168
|
+
stanza = Blather::Stanza::Iq::Query.new
|
|
169
|
+
response = mock(:query => nil, :iq => nil)
|
|
170
|
+
@client.register_handler(:query) do |_|
|
|
171
|
+
response.query
|
|
172
|
+
throw :pass
|
|
173
|
+
response.fail
|
|
174
|
+
end
|
|
175
|
+
@client.register_handler(:iq) { |_| response.iq }
|
|
176
|
+
@client.receive_data stanza
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
describe 'Blather::Client#write' do
|
|
181
|
+
before do
|
|
182
|
+
@client = Blather::Client.new
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
it 'writes to the stream' do
|
|
186
|
+
stanza = Blather::Stanza::Iq.new
|
|
187
|
+
stream = mock()
|
|
188
|
+
stream.expects(:send).with stanza
|
|
189
|
+
@client.setup('me@me.com', 'me')
|
|
190
|
+
@client.post_init stream, Blather::JID.new('me.com')
|
|
191
|
+
@client.write stanza
|
|
192
|
+
end
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
describe 'Blather::Client#status=' do
|
|
196
|
+
before do
|
|
197
|
+
@client = Blather::Client.new
|
|
198
|
+
@stream = mock()
|
|
199
|
+
@stream.stubs(:send)
|
|
200
|
+
@client.post_init @stream, Blather::JID.new('n@d/r')
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
it 'updates the state when not sending to a Blather::JID' do
|
|
204
|
+
@stream.stubs(:write)
|
|
205
|
+
@client.status.wont_equal :away
|
|
206
|
+
@client.status = :away, 'message'
|
|
207
|
+
@client.status.must_equal :away
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
it 'does not update the state when sending to a Blather::JID' do
|
|
211
|
+
@stream.stubs(:write)
|
|
212
|
+
@client.status.wont_equal :away
|
|
213
|
+
@client.status = :away, 'message', 'me@me.com'
|
|
214
|
+
@client.status.wont_equal :away
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
it 'writes the new status to the stream' do
|
|
218
|
+
Blather::Stanza::Presence::Status.stubs(:next_id).returns 0
|
|
219
|
+
status = [:away, 'message']
|
|
220
|
+
@stream.expects(:send).with do |s|
|
|
221
|
+
s.must_be_kind_of Blather::Stanza::Presence::Status
|
|
222
|
+
s.to_s.must_equal Blather::Stanza::Presence::Status.new(*status).to_s
|
|
223
|
+
end
|
|
224
|
+
@client.status = status
|
|
225
|
+
end
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
describe 'Blather::Client default handlers' do
|
|
229
|
+
before do
|
|
230
|
+
@client = Blather::Client.new
|
|
231
|
+
@stream = mock()
|
|
232
|
+
@stream.stubs(:send)
|
|
233
|
+
@client.post_init @stream, Blather::JID.new('n@d/r')
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
it 're-raises errors' do
|
|
237
|
+
err = Blather::BlatherError.new
|
|
238
|
+
lambda { @client.receive_data err }.must_raise Blather::BlatherError
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
# it 'responds to iq:get with a "service-unavailable" error' do
|
|
242
|
+
# get = Blather::Stanza::Iq.new :get
|
|
243
|
+
# err = Blather::StanzaError.new(get, 'service-unavailable', :cancel).to_node
|
|
244
|
+
# @client.expects(:write).with err
|
|
245
|
+
# @client.receive_data get
|
|
246
|
+
# end
|
|
247
|
+
|
|
248
|
+
# it 'responds to iq:get with a "service-unavailable" error' do
|
|
249
|
+
# get = Blather::Stanza::Iq.new :get
|
|
250
|
+
# err = Blather::StanzaError.new(get, 'service-unavailable', :cancel).to_node
|
|
251
|
+
# @client.expects(:write).with { |n| n.to_s.must_equal err.to_s }
|
|
252
|
+
# @client.receive_data get
|
|
253
|
+
# end
|
|
254
|
+
|
|
255
|
+
# it 'responds to iq:set with a "service-unavailable" error' do
|
|
256
|
+
# get = Blather::Stanza::Iq.new :set
|
|
257
|
+
# err = Blather::StanzaError.new(get, 'service-unavailable', :cancel).to_node
|
|
258
|
+
# @client.expects(:write).with { |n| n.to_s.must_equal err.to_s }
|
|
259
|
+
# @client.receive_data get
|
|
260
|
+
# end
|
|
261
|
+
|
|
262
|
+
it 'handles status changes by updating the roster if the status is from a Blather::JID in the roster' do
|
|
263
|
+
jid = 'friend@jabber.local'
|
|
264
|
+
status = Blather::Stanza::Presence::Status.new :away
|
|
265
|
+
status.stubs(:from).returns jid
|
|
266
|
+
roster_item = mock()
|
|
267
|
+
roster_item.expects(:status=).with status
|
|
268
|
+
@client.stubs(:roster).returns({status.from => roster_item})
|
|
269
|
+
@client.receive_data status
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
it 'lets status stanzas fall through to other handlers' do
|
|
273
|
+
jid = 'friend@jabber.local'
|
|
274
|
+
status = Blather::Stanza::Presence::Status.new :away
|
|
275
|
+
status.stubs(:from).returns jid
|
|
276
|
+
roster_item = mock()
|
|
277
|
+
roster_item.expects(:status=).with status
|
|
278
|
+
@client.stubs(:roster).returns({status.from => roster_item})
|
|
279
|
+
|
|
280
|
+
response = mock()
|
|
281
|
+
response.expects(:call).with jid
|
|
282
|
+
@client.register_handler(:status) { |s| response.call s.from.to_s }
|
|
283
|
+
@client.receive_data status
|
|
284
|
+
end
|
|
285
|
+
|
|
286
|
+
it 'handles an incoming roster node by processing it through the roster' do
|
|
287
|
+
roster = Blather::Stanza::Iq::Roster.new
|
|
288
|
+
client_roster = mock()
|
|
289
|
+
client_roster.expects(:process).with roster
|
|
290
|
+
@client.stubs(:roster).returns client_roster
|
|
291
|
+
@client.receive_data roster
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
it 'handles an incoming roster node by processing it through the roster' do
|
|
295
|
+
roster = Blather::Stanza::Iq::Roster.new
|
|
296
|
+
client_roster = mock()
|
|
297
|
+
client_roster.expects(:process).with roster
|
|
298
|
+
@client.stubs(:roster).returns client_roster
|
|
299
|
+
|
|
300
|
+
response = mock()
|
|
301
|
+
response.expects(:call)
|
|
302
|
+
@client.register_handler(:roster) { |_| response.call }
|
|
303
|
+
@client.receive_data roster
|
|
304
|
+
end
|
|
305
|
+
end
|
|
306
|
+
|
|
307
|
+
describe 'Blather::Client with a Component stream' do
|
|
308
|
+
before do
|
|
309
|
+
class MockComponent < Blather::Stream::Component; def initialize(); end; end
|
|
310
|
+
@stream = MockComponent.new('')
|
|
311
|
+
@stream.stubs(:send_data)
|
|
312
|
+
@client = Blather::Client.new
|
|
313
|
+
@client.setup('me.com', 'secret')
|
|
314
|
+
end
|
|
315
|
+
|
|
316
|
+
it 'calls the ready handler when sent post_init' do
|
|
317
|
+
ready = mock()
|
|
318
|
+
ready.expects(:call)
|
|
319
|
+
@client.register_handler(:ready) { ready.call }
|
|
320
|
+
@client.post_init @stream
|
|
321
|
+
end
|
|
322
|
+
end
|
|
323
|
+
|
|
324
|
+
describe 'Blather::Client with a Client stream' do
|
|
325
|
+
before do
|
|
326
|
+
class MockClientStream < Blather::Stream::Client; def initialize(); end; end
|
|
327
|
+
@stream = MockClientStream.new('')
|
|
328
|
+
@client = Blather::Client.new
|
|
329
|
+
Blather::Stream::Client.stubs(:start).returns @stream
|
|
330
|
+
@client.setup('me@me.com', 'secret').run
|
|
331
|
+
end
|
|
332
|
+
|
|
333
|
+
it 'sends a request for the roster when post_init is called' do
|
|
334
|
+
@stream.expects(:send).with { |stanza| stanza.must_be_kind_of Blather::Stanza::Iq::Roster }
|
|
335
|
+
@client.post_init @stream, Blather::JID.new('n@d/r')
|
|
336
|
+
end
|
|
337
|
+
|
|
338
|
+
it 'calls the ready handler after post_init and roster is received' do
|
|
339
|
+
result_roster = Blather::Stanza::Iq::Roster.new :result
|
|
340
|
+
@stream.stubs(:send).with { |s| result_roster.id = s.id; @client.receive_data result_roster; true }
|
|
341
|
+
|
|
342
|
+
ready = mock()
|
|
343
|
+
ready.expects(:call)
|
|
344
|
+
@client.register_handler(:ready) { ready.call }
|
|
345
|
+
@client.post_init @stream, Blather::JID.new('n@d/r')
|
|
346
|
+
end
|
|
347
|
+
end
|
|
348
|
+
|
|
349
|
+
describe 'Blather::Client filters' do
|
|
350
|
+
before do
|
|
351
|
+
@client = Blather::Client.new
|
|
352
|
+
@stream = mock()
|
|
353
|
+
@stream.stubs(:send)
|
|
354
|
+
@client.post_init @stream, Blather::JID.new('n@d/r')
|
|
355
|
+
end
|
|
356
|
+
|
|
357
|
+
it 'raises an error when an invalid filter type is registered' do
|
|
358
|
+
lambda { @client.register_filter(:invalid) {} }.must_raise RuntimeError
|
|
359
|
+
end
|
|
360
|
+
|
|
361
|
+
it 'can be guarded' do
|
|
362
|
+
stanza = Blather::Stanza::Iq.new
|
|
363
|
+
ready = mock()
|
|
364
|
+
ready.expects(:call).once
|
|
365
|
+
@client.register_filter(:before, :iq, :id => stanza.id) { |_| ready.call }
|
|
366
|
+
@client.register_filter(:before, :iq, :id => 'not-id') { |_| ready.call }
|
|
367
|
+
@client.receive_data stanza
|
|
368
|
+
end
|
|
369
|
+
|
|
370
|
+
it 'can pass to the next handler' do
|
|
371
|
+
stanza = Blather::Stanza::Iq.new
|
|
372
|
+
ready = mock()
|
|
373
|
+
ready.expects(:call).once
|
|
374
|
+
@client.register_filter(:before) { |_| throw :pass; ready.call }
|
|
375
|
+
@client.register_filter(:before) { |_| ready.call }
|
|
376
|
+
@client.receive_data stanza
|
|
377
|
+
end
|
|
378
|
+
|
|
379
|
+
it 'runs them in order' do
|
|
380
|
+
stanza = Blather::Stanza::Iq.new
|
|
381
|
+
count = 0
|
|
382
|
+
@client.register_filter(:before) { |_| count.must_equal 0; count = 1 }
|
|
383
|
+
@client.register_filter(:before) { |_| count.must_equal 1; count = 2 }
|
|
384
|
+
@client.register_handler(:iq) { |_| count.must_equal 2; count = 3 }
|
|
385
|
+
@client.register_filter(:after) { |_| count.must_equal 3; count = 4 }
|
|
386
|
+
@client.register_filter(:after) { |_| count.must_equal 4 }
|
|
387
|
+
@client.receive_data stanza
|
|
388
|
+
end
|
|
389
|
+
|
|
390
|
+
it 'can modify the stanza' do
|
|
391
|
+
stanza = Blather::Stanza::Iq.new
|
|
392
|
+
stanza.from = 'from@test.local'
|
|
393
|
+
new_jid = 'before@filter.local'
|
|
394
|
+
ready = mock()
|
|
395
|
+
ready.expects(:call).with new_jid
|
|
396
|
+
@client.register_filter(:before) { |s| s.from = new_jid }
|
|
397
|
+
@client.register_handler(:iq) { |s| ready.call s.from.to_s }
|
|
398
|
+
@client.receive_data stanza
|
|
399
|
+
end
|
|
400
|
+
|
|
401
|
+
it 'can halt the handler chain' do
|
|
402
|
+
stanza = Blather::Stanza::Iq.new
|
|
403
|
+
ready = mock()
|
|
404
|
+
ready.expects(:call).never
|
|
405
|
+
@client.register_filter(:before) { |_| throw :halt }
|
|
406
|
+
@client.register_handler(:iq) { |_| ready.call }
|
|
407
|
+
@client.receive_data stanza
|
|
408
|
+
end
|
|
409
|
+
|
|
410
|
+
it 'can be specific to a handler' do
|
|
411
|
+
stanza = Blather::Stanza::Iq.new
|
|
412
|
+
ready = mock()
|
|
413
|
+
ready.expects(:call).once
|
|
414
|
+
@client.register_filter(:before, :iq) { |_| ready.call }
|
|
415
|
+
@client.register_filter(:before, :message) { |_| ready.call }
|
|
416
|
+
@client.receive_data stanza
|
|
417
|
+
end
|
|
418
|
+
end
|
|
419
|
+
|
|
420
|
+
describe 'Blather::Client guards' do
|
|
421
|
+
before do
|
|
422
|
+
stream = mock()
|
|
423
|
+
stream.stubs(:send)
|
|
424
|
+
@client = Blather::Client.new
|
|
425
|
+
@client.post_init stream, Blather::JID.new('n@d/r')
|
|
426
|
+
@stanza = Blather::Stanza::Iq.new
|
|
427
|
+
@response = mock()
|
|
428
|
+
end
|
|
429
|
+
|
|
430
|
+
it 'can be a symbol' do
|
|
431
|
+
@response.expects :call
|
|
432
|
+
@client.register_handler(:iq, :chat?) { |_| @response.call }
|
|
433
|
+
|
|
434
|
+
@stanza.expects(:chat?).returns true
|
|
435
|
+
@client.receive_data @stanza
|
|
436
|
+
|
|
437
|
+
@stanza.expects(:chat?).returns false
|
|
438
|
+
@client.receive_data @stanza
|
|
439
|
+
end
|
|
440
|
+
|
|
441
|
+
it 'can be a hash with string match' do
|
|
442
|
+
@response.expects :call
|
|
443
|
+
@client.register_handler(:iq, :body => 'exit') { |_| @response.call }
|
|
444
|
+
|
|
445
|
+
@stanza.expects(:body).returns 'exit'
|
|
446
|
+
@client.receive_data @stanza
|
|
447
|
+
|
|
448
|
+
@stanza.expects(:body).returns 'not-exit'
|
|
449
|
+
@client.receive_data @stanza
|
|
450
|
+
end
|
|
451
|
+
|
|
452
|
+
it 'can be a hash with a value' do
|
|
453
|
+
@response.expects :call
|
|
454
|
+
@client.register_handler(:iq, :number => 0) { |_| @response.call }
|
|
455
|
+
|
|
456
|
+
@stanza.expects(:number).returns 0
|
|
457
|
+
@client.receive_data @stanza
|
|
458
|
+
|
|
459
|
+
@stanza.expects(:number).returns 1
|
|
460
|
+
@client.receive_data @stanza
|
|
461
|
+
end
|
|
462
|
+
|
|
463
|
+
it 'can be a hash with a regexp' do
|
|
464
|
+
@response.expects :call
|
|
465
|
+
@client.register_handler(:iq, :body => /exit/) { |_| @response.call }
|
|
466
|
+
|
|
467
|
+
@stanza.expects(:body).returns 'more than just exit, but exit still'
|
|
468
|
+
@client.receive_data @stanza
|
|
469
|
+
|
|
470
|
+
@stanza.expects(:body).returns 'keyword not found'
|
|
471
|
+
@client.receive_data @stanza
|
|
472
|
+
|
|
473
|
+
@stanza.expects(:body).returns nil
|
|
474
|
+
@client.receive_data @stanza
|
|
475
|
+
end
|
|
476
|
+
|
|
477
|
+
it 'can be a hash with an array' do
|
|
478
|
+
@response.expects(:call).times(2)
|
|
479
|
+
@client.register_handler(:iq, :type => [:result, :error]) { |_| @response.call }
|
|
480
|
+
|
|
481
|
+
stanza = Blather::Stanza::Iq.new
|
|
482
|
+
stanza.expects(:type).at_least_once.returns :result
|
|
483
|
+
@client.receive_data stanza
|
|
484
|
+
|
|
485
|
+
stanza = Blather::Stanza::Iq.new
|
|
486
|
+
stanza.expects(:type).at_least_once.returns :error
|
|
487
|
+
@client.receive_data stanza
|
|
488
|
+
|
|
489
|
+
stanza = Blather::Stanza::Iq.new
|
|
490
|
+
stanza.expects(:type).at_least_once.returns :get
|
|
491
|
+
@client.receive_data stanza
|
|
492
|
+
end
|
|
493
|
+
|
|
494
|
+
it 'chained are treated like andand (short circuited)' do
|
|
495
|
+
@response.expects :call
|
|
496
|
+
@client.register_handler(:iq, :type => :get, :body => 'test') { |_| @response.call }
|
|
497
|
+
|
|
498
|
+
stanza = Blather::Stanza::Iq.new
|
|
499
|
+
stanza.expects(:type).at_least_once.returns :get
|
|
500
|
+
stanza.expects(:body).returns 'test'
|
|
501
|
+
@client.receive_data stanza
|
|
502
|
+
|
|
503
|
+
stanza = Blather::Stanza::Iq.new
|
|
504
|
+
stanza.expects(:type).at_least_once.returns :set
|
|
505
|
+
stanza.expects(:body).never
|
|
506
|
+
@client.receive_data stanza
|
|
507
|
+
end
|
|
508
|
+
|
|
509
|
+
it 'within an Array are treated as oror (short circuited)' do
|
|
510
|
+
@response.expects(:call).times 2
|
|
511
|
+
@client.register_handler(:iq, [{:type => :get}, {:body => 'test'}]) { |_| @response.call }
|
|
512
|
+
|
|
513
|
+
stanza = Blather::Stanza::Iq.new
|
|
514
|
+
stanza.expects(:type).at_least_once.returns :set
|
|
515
|
+
stanza.expects(:body).returns 'test'
|
|
516
|
+
@client.receive_data stanza
|
|
517
|
+
|
|
518
|
+
stanza = Blather::Stanza::Iq.new
|
|
519
|
+
stanza.stubs(:type).at_least_once.returns :get
|
|
520
|
+
stanza.expects(:body).never
|
|
521
|
+
@client.receive_data stanza
|
|
522
|
+
end
|
|
523
|
+
|
|
524
|
+
it 'can be a lambda' do
|
|
525
|
+
@response.expects :call
|
|
526
|
+
@client.register_handler(:iq, lambda { |s| s.number % 3 == 0 }) { |_| @response.call }
|
|
527
|
+
|
|
528
|
+
@stanza.expects(:number).at_least_once.returns 3
|
|
529
|
+
@client.receive_data @stanza
|
|
530
|
+
|
|
531
|
+
@stanza.expects(:number).at_least_once.returns 2
|
|
532
|
+
@client.receive_data @stanza
|
|
533
|
+
end
|
|
534
|
+
|
|
535
|
+
it 'can be an xpath and will send the result to the handler' do
|
|
536
|
+
@response.expects(:call).with do |stanza, xpath|
|
|
537
|
+
xpath.must_be_instance_of Nokogiri::XML::NodeSet
|
|
538
|
+
xpath.wont_be_empty
|
|
539
|
+
stanza.must_equal @stanza
|
|
540
|
+
end
|
|
541
|
+
@client.register_handler(:iq, "/iq[@id='#{@stanza.id}']") { |stanza, xpath| @response.call stanza, xpath }
|
|
542
|
+
@client.receive_data @stanza
|
|
543
|
+
end
|
|
544
|
+
|
|
545
|
+
it 'can be an xpath with namespaces and will send the result to the handler' do
|
|
546
|
+
@stanza = Blather::Stanza.import(parse_stanza('<message><foo xmlns="http://bar.com"></message>').root)
|
|
547
|
+
@response.expects(:call).with do |stanza, xpath|
|
|
548
|
+
xpath.must_be_instance_of Nokogiri::XML::NodeSet
|
|
549
|
+
xpath.wont_be_empty
|
|
550
|
+
stanza.must_equal @stanza
|
|
551
|
+
end
|
|
552
|
+
@client.register_handler(:message, "/message/bar:foo", :bar => 'http://bar.com') { |stanza, xpath| @response.call stanza, xpath }
|
|
553
|
+
@client.receive_data @stanza
|
|
554
|
+
end
|
|
555
|
+
|
|
556
|
+
it 'raises an error when a bad guard is tried' do
|
|
557
|
+
lambda { @client.register_handler(:iq, 0) {} }.must_raise RuntimeError
|
|
558
|
+
end
|
|
559
|
+
end
|