comparison src/tmp/wokkel/test/test_pubsub.py @ 1438:0fb5785b4c63

add tests for sat.tmp.wokkel
author souliane <souliane@mailoo.org>
date Tue, 14 Jul 2015 15:22:02 +0200
parents
children
comparison
equal deleted inserted replaced
1437:a568fc14ab46 1438:0fb5785b4c63
1 # Copyright (c) Ralph Meijer.
2 # See LICENSE for details.
3
4 """
5 Tests for L{wokkel.pubsub}
6 """
7
8 from zope.interface import verify
9
10 from twisted.trial import unittest
11 from twisted.internet import defer
12 from twisted.words.xish import domish
13 from twisted.words.protocols.jabber import error
14 from twisted.words.protocols.jabber.jid import JID
15 from twisted.words.protocols.jabber.xmlstream import toResponse
16
17 from wokkel import data_form, disco, iwokkel, shim
18 from wokkel.generic import parseXml
19 from wokkel.test.helpers import TestableRequestHandlerMixin, XmlStreamStub
20
21 from sat.tmp.wokkel import pubsub
22
23 NS_PUBSUB = 'http://jabber.org/protocol/pubsub'
24 NS_PUBSUB_NODE_CONFIG = 'http://jabber.org/protocol/pubsub#node_config'
25 NS_PUBSUB_ERRORS = 'http://jabber.org/protocol/pubsub#errors'
26 NS_PUBSUB_EVENT = 'http://jabber.org/protocol/pubsub#event'
27 NS_PUBSUB_OWNER = 'http://jabber.org/protocol/pubsub#owner'
28 NS_PUBSUB_META_DATA = 'http://jabber.org/protocol/pubsub#meta-data'
29 NS_PUBSUB_SUBSCRIBE_OPTIONS = 'http://jabber.org/protocol/pubsub#subscribe_options'
30
31 def calledAsync(fn):
32 """
33 Function wrapper that fires a deferred upon calling the given function.
34 """
35 d = defer.Deferred()
36
37 def func(*args, **kwargs):
38 try:
39 result = fn(*args, **kwargs)
40 except:
41 d.errback()
42 else:
43 d.callback(result)
44
45 return d, func
46
47
48 class SubscriptionTest(unittest.TestCase):
49 """
50 Tests for L{pubsub.Subscription}.
51 """
52
53 def test_fromElement(self):
54 """
55 fromElement parses a subscription from XML DOM.
56 """
57 xml = """
58 <subscription node='test' jid='user@example.org/Home'
59 subscription='pending'/>
60 """
61 subscription = pubsub.Subscription.fromElement(parseXml(xml))
62 self.assertEqual('test', subscription.nodeIdentifier)
63 self.assertEqual(JID('user@example.org/Home'), subscription.subscriber)
64 self.assertEqual('pending', subscription.state)
65 self.assertIdentical(None, subscription.subscriptionIdentifier)
66
67
68 def test_fromElementWithSubscriptionIdentifier(self):
69 """
70 A subscription identifier in the subscription should be parsed, too.
71 """
72 xml = """
73 <subscription node='test' jid='user@example.org/Home' subid='1234'
74 subscription='pending'/>
75 """
76 subscription = pubsub.Subscription.fromElement(parseXml(xml))
77 self.assertEqual('1234', subscription.subscriptionIdentifier)
78
79
80 def test_toElement(self):
81 """
82 Rendering a Subscription should yield the proper attributes.
83 """
84 subscription = pubsub.Subscription('test',
85 JID('user@example.org/Home'),
86 'pending')
87 element = subscription.toElement()
88 self.assertEqual('subscription', element.name)
89 self.assertEqual(None, element.uri)
90 self.assertEqual('test', element.getAttribute('node'))
91 self.assertEqual('user@example.org/Home', element.getAttribute('jid'))
92 self.assertEqual('pending', element.getAttribute('subscription'))
93 self.assertFalse(element.hasAttribute('subid'))
94
95
96 def test_toElementEmptyNodeIdentifier(self):
97 """
98 The empty node identifier should not yield a node attribute.
99 """
100 subscription = pubsub.Subscription('',
101 JID('user@example.org/Home'),
102 'pending')
103 element = subscription.toElement()
104 self.assertFalse(element.hasAttribute('node'))
105
106
107 def test_toElementWithSubscriptionIdentifier(self):
108 """
109 The subscription identifier, if set, is in the subid attribute.
110 """
111 subscription = pubsub.Subscription('test',
112 JID('user@example.org/Home'),
113 'pending',
114 subscriptionIdentifier='1234')
115 element = subscription.toElement()
116 self.assertEqual('1234', element.getAttribute('subid'))
117
118
119
120 class PubSubClientTest(unittest.TestCase):
121 timeout = 2
122
123 def setUp(self):
124 self.stub = XmlStreamStub()
125 self.protocol = pubsub.PubSubClient()
126 self.protocol.xmlstream = self.stub.xmlstream
127 self.protocol.connectionInitialized()
128
129
130 def test_interface(self):
131 """
132 Do instances of L{pubsub.PubSubClient} provide L{iwokkel.IPubSubClient}?
133 """
134 verify.verifyObject(iwokkel.IPubSubClient, self.protocol)
135
136
137 def test_eventItems(self):
138 """
139 Test receiving an items event resulting in a call to itemsReceived.
140 """
141 message = domish.Element((None, 'message'))
142 message['from'] = 'pubsub.example.org'
143 message['to'] = 'user@example.org/home'
144 event = message.addElement((NS_PUBSUB_EVENT, 'event'))
145 items = event.addElement('items')
146 items['node'] = 'test'
147 item1 = items.addElement('item')
148 item1['id'] = 'item1'
149 item2 = items.addElement('retract')
150 item2['id'] = 'item2'
151 item3 = items.addElement('item')
152 item3['id'] = 'item3'
153
154 def itemsReceived(event):
155 self.assertEquals(JID('user@example.org/home'), event.recipient)
156 self.assertEquals(JID('pubsub.example.org'), event.sender)
157 self.assertEquals('test', event.nodeIdentifier)
158 self.assertEquals([item1, item2, item3], event.items)
159
160 d, self.protocol.itemsReceived = calledAsync(itemsReceived)
161 self.stub.send(message)
162 return d
163
164
165 def test_eventItemsCollection(self):
166 """
167 Test receiving an items event resulting in a call to itemsReceived.
168 """
169 message = domish.Element((None, 'message'))
170 message['from'] = 'pubsub.example.org'
171 message['to'] = 'user@example.org/home'
172 event = message.addElement((NS_PUBSUB_EVENT, 'event'))
173 items = event.addElement('items')
174 items['node'] = 'test'
175
176 headers = shim.Headers([('Collection', 'collection')])
177 message.addChild(headers)
178
179 def itemsReceived(event):
180 self.assertEquals(JID('user@example.org/home'), event.recipient)
181 self.assertEquals(JID('pubsub.example.org'), event.sender)
182 self.assertEquals('test', event.nodeIdentifier)
183 self.assertEquals({'Collection': ['collection']}, event.headers)
184
185 d, self.protocol.itemsReceived = calledAsync(itemsReceived)
186 self.stub.send(message)
187 return d
188
189
190 def test_eventItemsError(self):
191 """
192 An error message with embedded event should not be handled.
193
194 This test uses an items event, which should not result in itemsReceived
195 being called. In general message.handled should be False.
196 """
197 message = domish.Element((None, 'message'))
198 message['from'] = 'pubsub.example.org'
199 message['to'] = 'user@example.org/home'
200 message['type'] = 'error'
201 event = message.addElement((NS_PUBSUB_EVENT, 'event'))
202 items = event.addElement('items')
203 items['node'] = 'test'
204
205 class UnexpectedCall(Exception):
206 pass
207
208 def itemsReceived(event):
209 raise UnexpectedCall("Unexpected call to itemsReceived")
210
211 self.protocol.itemsReceived = itemsReceived
212 self.stub.send(message)
213 self.assertFalse(message.handled)
214
215
216 def test_eventDelete(self):
217 """
218 Test receiving a delete event resulting in a call to deleteReceived.
219 """
220 message = domish.Element((None, 'message'))
221 message['from'] = 'pubsub.example.org'
222 message['to'] = 'user@example.org/home'
223 event = message.addElement((NS_PUBSUB_EVENT, 'event'))
224 delete = event.addElement('delete')
225 delete['node'] = 'test'
226
227 def deleteReceived(event):
228 self.assertEquals(JID('user@example.org/home'), event.recipient)
229 self.assertEquals(JID('pubsub.example.org'), event.sender)
230 self.assertEquals('test', event.nodeIdentifier)
231
232 d, self.protocol.deleteReceived = calledAsync(deleteReceived)
233 self.stub.send(message)
234 return d
235
236
237 def test_eventDeleteRedirect(self):
238 """
239 Test receiving a delete event with a redirect URI.
240 """
241 message = domish.Element((None, 'message'))
242 message['from'] = 'pubsub.example.org'
243 message['to'] = 'user@example.org/home'
244 event = message.addElement((NS_PUBSUB_EVENT, 'event'))
245 delete = event.addElement('delete')
246 delete['node'] = 'test'
247 uri = 'xmpp:pubsub.example.org?;node=test2'
248 delete.addElement('redirect')['uri'] = uri
249
250 def deleteReceived(event):
251 self.assertEquals(JID('user@example.org/home'), event.recipient)
252 self.assertEquals(JID('pubsub.example.org'), event.sender)
253 self.assertEquals('test', event.nodeIdentifier)
254 self.assertEquals(uri, event.redirectURI)
255
256 d, self.protocol.deleteReceived = calledAsync(deleteReceived)
257 self.stub.send(message)
258 return d
259
260
261 def test_event_purge(self):
262 """
263 Test receiving a purge event resulting in a call to purgeReceived.
264 """
265 message = domish.Element((None, 'message'))
266 message['from'] = 'pubsub.example.org'
267 message['to'] = 'user@example.org/home'
268 event = message.addElement((NS_PUBSUB_EVENT, 'event'))
269 items = event.addElement('purge')
270 items['node'] = 'test'
271
272 def purgeReceived(event):
273 self.assertEquals(JID('user@example.org/home'), event.recipient)
274 self.assertEquals(JID('pubsub.example.org'), event.sender)
275 self.assertEquals('test', event.nodeIdentifier)
276
277 d, self.protocol.purgeReceived = calledAsync(purgeReceived)
278 self.stub.send(message)
279 return d
280
281
282 def test_createNode(self):
283 """
284 Test sending create request.
285 """
286
287 def cb(nodeIdentifier):
288 self.assertEquals('test', nodeIdentifier)
289
290 d = self.protocol.createNode(JID('pubsub.example.org'), 'test')
291 d.addCallback(cb)
292
293 iq = self.stub.output[-1]
294 self.assertEquals('pubsub.example.org', iq.getAttribute('to'))
295 self.assertEquals('set', iq.getAttribute('type'))
296 self.assertEquals('pubsub', iq.pubsub.name)
297 self.assertEquals(NS_PUBSUB, iq.pubsub.uri)
298 children = list(domish.generateElementsQNamed(iq.pubsub.children,
299 'create', NS_PUBSUB))
300 self.assertEquals(1, len(children))
301 child = children[0]
302 self.assertEquals('test', child['node'])
303
304 response = toResponse(iq, 'result')
305 self.stub.send(response)
306 return d
307
308
309 def test_createNodeInstant(self):
310 """
311 Test sending create request resulting in an instant node.
312 """
313
314 def cb(nodeIdentifier):
315 self.assertEquals('test', nodeIdentifier)
316
317 d = self.protocol.createNode(JID('pubsub.example.org'))
318 d.addCallback(cb)
319
320 iq = self.stub.output[-1]
321 children = list(domish.generateElementsQNamed(iq.pubsub.children,
322 'create', NS_PUBSUB))
323 child = children[0]
324 self.assertFalse(child.hasAttribute('node'))
325
326 response = toResponse(iq, 'result')
327 command = response.addElement((NS_PUBSUB, 'pubsub'))
328 create = command.addElement('create')
329 create['node'] = 'test'
330 self.stub.send(response)
331 return d
332
333
334 def test_createNodeRenamed(self):
335 """
336 Test sending create request resulting in renamed node.
337 """
338
339 def cb(nodeIdentifier):
340 self.assertEquals('test2', nodeIdentifier)
341
342 d = self.protocol.createNode(JID('pubsub.example.org'), 'test')
343 d.addCallback(cb)
344
345 iq = self.stub.output[-1]
346 children = list(domish.generateElementsQNamed(iq.pubsub.children,
347 'create', NS_PUBSUB))
348 child = children[0]
349 self.assertEquals('test', child['node'])
350
351 response = toResponse(iq, 'result')
352 command = response.addElement((NS_PUBSUB, 'pubsub'))
353 create = command.addElement('create')
354 create['node'] = 'test2'
355 self.stub.send(response)
356 return d
357
358
359 def test_createNodeWithSender(self):
360 """
361 Test sending create request from a specific JID.
362 """
363
364 d = self.protocol.createNode(JID('pubsub.example.org'), 'test',
365 sender=JID('user@example.org'))
366
367 iq = self.stub.output[-1]
368 self.assertEquals('user@example.org', iq['from'])
369
370 response = toResponse(iq, 'result')
371 self.stub.send(response)
372 return d
373
374
375 def test_createNodeWithConfig(self):
376 """
377 Test sending create request with configuration options
378 """
379
380 options = {
381 'pubsub#title': 'Princely Musings (Atom)',
382 'pubsub#deliver_payloads': True,
383 'pubsub#persist_items': '1',
384 'pubsub#max_items': '10',
385 'pubsub#access_model': 'open',
386 'pubsub#type': 'http://www.w3.org/2005/Atom',
387 }
388
389 d = self.protocol.createNode(JID('pubsub.example.org'), 'test',
390 sender=JID('user@example.org'),
391 options=options)
392
393 iq = self.stub.output[-1]
394
395 # check if there is exactly one configure element
396 children = list(domish.generateElementsQNamed(iq.pubsub.children,
397 'configure', NS_PUBSUB))
398 self.assertEqual(1, len(children))
399
400 # check that it has a configuration form
401 form = data_form.findForm(children[0], NS_PUBSUB_NODE_CONFIG)
402 self.assertEqual('submit', form.formType)
403
404
405 response = toResponse(iq, 'result')
406 self.stub.send(response)
407 return d
408
409
410 def test_deleteNode(self):
411 """
412 Test sending delete request.
413 """
414
415 d = self.protocol.deleteNode(JID('pubsub.example.org'), 'test')
416
417 iq = self.stub.output[-1]
418 self.assertEquals('pubsub.example.org', iq.getAttribute('to'))
419 self.assertEquals('set', iq.getAttribute('type'))
420 self.assertEquals('pubsub', iq.pubsub.name)
421 self.assertEquals(NS_PUBSUB_OWNER, iq.pubsub.uri)
422 children = list(domish.generateElementsQNamed(iq.pubsub.children,
423 'delete', NS_PUBSUB_OWNER))
424 self.assertEquals(1, len(children))
425 child = children[0]
426 self.assertEquals('test', child['node'])
427
428 response = toResponse(iq, 'result')
429 self.stub.send(response)
430 return d
431
432
433 def test_deleteNodeWithSender(self):
434 """
435 Test sending delete request.
436 """
437
438 d = self.protocol.deleteNode(JID('pubsub.example.org'), 'test',
439 sender=JID('user@example.org'))
440
441 iq = self.stub.output[-1]
442 self.assertEquals('user@example.org', iq['from'])
443
444 response = toResponse(iq, 'result')
445 self.stub.send(response)
446 return d
447
448
449 def test_publish(self):
450 """
451 Test sending publish request.
452 """
453
454 item = pubsub.Item()
455 d = self.protocol.publish(JID('pubsub.example.org'), 'test', [item])
456
457 iq = self.stub.output[-1]
458 self.assertEquals('pubsub.example.org', iq.getAttribute('to'))
459 self.assertEquals('set', iq.getAttribute('type'))
460 self.assertEquals('pubsub', iq.pubsub.name)
461 self.assertEquals(NS_PUBSUB, iq.pubsub.uri)
462 children = list(domish.generateElementsQNamed(iq.pubsub.children,
463 'publish', NS_PUBSUB))
464 self.assertEquals(1, len(children))
465 child = children[0]
466 self.assertEquals('test', child['node'])
467 items = list(domish.generateElementsQNamed(child.children,
468 'item', NS_PUBSUB))
469 self.assertEquals(1, len(items))
470 self.assertIdentical(item, items[0])
471
472 response = toResponse(iq, 'result')
473 self.stub.send(response)
474 return d
475
476
477 def test_publishNoItems(self):
478 """
479 Test sending publish request without items.
480 """
481
482 d = self.protocol.publish(JID('pubsub.example.org'), 'test')
483
484 iq = self.stub.output[-1]
485 self.assertEquals('pubsub.example.org', iq.getAttribute('to'))
486 self.assertEquals('set', iq.getAttribute('type'))
487 self.assertEquals('pubsub', iq.pubsub.name)
488 self.assertEquals(NS_PUBSUB, iq.pubsub.uri)
489 children = list(domish.generateElementsQNamed(iq.pubsub.children,
490 'publish', NS_PUBSUB))
491 self.assertEquals(1, len(children))
492 child = children[0]
493 self.assertEquals('test', child['node'])
494
495 response = toResponse(iq, 'result')
496 self.stub.send(response)
497 return d
498
499
500 def test_publishWithSender(self):
501 """
502 Test sending publish request from a specific JID.
503 """
504
505 item = pubsub.Item()
506 d = self.protocol.publish(JID('pubsub.example.org'), 'test', [item],
507 JID('user@example.org'))
508
509 iq = self.stub.output[-1]
510 self.assertEquals('user@example.org', iq['from'])
511
512 response = toResponse(iq, 'result')
513 self.stub.send(response)
514 return d
515
516
517 def test_subscribe(self):
518 """
519 Test sending subscription request.
520 """
521 d = self.protocol.subscribe(JID('pubsub.example.org'), 'test',
522 JID('user@example.org'))
523
524 iq = self.stub.output[-1]
525 self.assertEquals('pubsub.example.org', iq.getAttribute('to'))
526 self.assertEquals('set', iq.getAttribute('type'))
527 self.assertEquals('pubsub', iq.pubsub.name)
528 self.assertEquals(NS_PUBSUB, iq.pubsub.uri)
529 children = list(domish.generateElementsQNamed(iq.pubsub.children,
530 'subscribe', NS_PUBSUB))
531 self.assertEquals(1, len(children))
532 child = children[0]
533 self.assertEquals('test', child['node'])
534 self.assertEquals('user@example.org', child['jid'])
535
536 response = toResponse(iq, 'result')
537 pubsub = response.addElement((NS_PUBSUB, 'pubsub'))
538 subscription = pubsub.addElement('subscription')
539 subscription['node'] = 'test'
540 subscription['jid'] = 'user@example.org'
541 subscription['subscription'] = 'subscribed'
542 self.stub.send(response)
543 return d
544
545
546 def test_subscribeReturnsSubscription(self):
547 """
548 A successful subscription should return a Subscription instance.
549 """
550 def cb(subscription):
551 self.assertEqual(JID('user@example.org'), subscription.subscriber)
552
553 d = self.protocol.subscribe(JID('pubsub.example.org'), 'test',
554 JID('user@example.org'))
555 d.addCallback(cb)
556
557 iq = self.stub.output[-1]
558
559 response = toResponse(iq, 'result')
560 pubsub = response.addElement((NS_PUBSUB, 'pubsub'))
561 subscription = pubsub.addElement('subscription')
562 subscription['node'] = 'test'
563 subscription['jid'] = 'user@example.org'
564 subscription['subscription'] = 'subscribed'
565 self.stub.send(response)
566 return d
567
568
569 def test_subscribePending(self):
570 """
571 Test sending subscription request that results in a pending
572 subscription.
573 """
574 d = self.protocol.subscribe(JID('pubsub.example.org'), 'test',
575 JID('user@example.org'))
576
577 iq = self.stub.output[-1]
578 response = toResponse(iq, 'result')
579 command = response.addElement((NS_PUBSUB, 'pubsub'))
580 subscription = command.addElement('subscription')
581 subscription['node'] = 'test'
582 subscription['jid'] = 'user@example.org'
583 subscription['subscription'] = 'pending'
584 self.stub.send(response)
585 self.assertFailure(d, pubsub.SubscriptionPending)
586 return d
587
588
589 def test_subscribeUnconfigured(self):
590 """
591 Test sending subscription request that results in an unconfigured
592 subscription.
593 """
594 d = self.protocol.subscribe(JID('pubsub.example.org'), 'test',
595 JID('user@example.org'))
596
597 iq = self.stub.output[-1]
598 response = toResponse(iq, 'result')
599 command = response.addElement((NS_PUBSUB, 'pubsub'))
600 subscription = command.addElement('subscription')
601 subscription['node'] = 'test'
602 subscription['jid'] = 'user@example.org'
603 subscription['subscription'] = 'unconfigured'
604 self.stub.send(response)
605 self.assertFailure(d, pubsub.SubscriptionUnconfigured)
606 return d
607
608
609 def test_subscribeWithOptions(self):
610 options = {'pubsub#deliver': False}
611
612 d = self.protocol.subscribe(JID('pubsub.example.org'), 'test',
613 JID('user@example.org'),
614 options=options)
615 iq = self.stub.output[-1]
616
617 # Check options present
618 childNames = []
619 for element in iq.pubsub.elements():
620 if element.uri == NS_PUBSUB:
621 childNames.append(element.name)
622
623 self.assertEqual(['subscribe', 'options'], childNames)
624 form = data_form.findForm(iq.pubsub.options,
625 NS_PUBSUB_SUBSCRIBE_OPTIONS)
626 self.assertEqual('submit', form.formType)
627 form.typeCheck({'pubsub#deliver': {'type': 'boolean'}})
628 self.assertEqual(options, form.getValues())
629
630 # Send response
631 response = toResponse(iq, 'result')
632 pubsub = response.addElement((NS_PUBSUB, 'pubsub'))
633 subscription = pubsub.addElement('subscription')
634 subscription['node'] = 'test'
635 subscription['jid'] = 'user@example.org'
636 subscription['subscription'] = 'subscribed'
637 self.stub.send(response)
638
639 return d
640
641
642 def test_subscribeWithSender(self):
643 """
644 Test sending subscription request from a specific JID.
645 """
646 d = self.protocol.subscribe(JID('pubsub.example.org'), 'test',
647 JID('user@example.org'),
648 sender=JID('user@example.org'))
649
650 iq = self.stub.output[-1]
651 self.assertEquals('user@example.org', iq['from'])
652
653 response = toResponse(iq, 'result')
654 pubsub = response.addElement((NS_PUBSUB, 'pubsub'))
655 subscription = pubsub.addElement('subscription')
656 subscription['node'] = 'test'
657 subscription['jid'] = 'user@example.org'
658 subscription['subscription'] = 'subscribed'
659 self.stub.send(response)
660 return d
661
662
663 def test_subscribeReturningSubscriptionIdentifier(self):
664 """
665 Test sending subscription request with subscription identifier.
666 """
667 def cb(subscription):
668 self.assertEqual('1234', subscription.subscriptionIdentifier)
669
670 d = self.protocol.subscribe(JID('pubsub.example.org'), 'test',
671 JID('user@example.org'))
672 d.addCallback(cb)
673
674 iq = self.stub.output[-1]
675
676 response = toResponse(iq, 'result')
677 pubsub = response.addElement((NS_PUBSUB, 'pubsub'))
678 subscription = pubsub.addElement('subscription')
679 subscription['node'] = 'test'
680 subscription['jid'] = 'user@example.org'
681 subscription['subscription'] = 'subscribed'
682 subscription['subid'] = '1234'
683 self.stub.send(response)
684 return d
685
686
687 def test_unsubscribe(self):
688 """
689 Test sending unsubscription request.
690 """
691 d = self.protocol.unsubscribe(JID('pubsub.example.org'), 'test',
692 JID('user@example.org'))
693
694 iq = self.stub.output[-1]
695 self.assertEquals('pubsub.example.org', iq.getAttribute('to'))
696 self.assertEquals('set', iq.getAttribute('type'))
697 self.assertEquals('pubsub', iq.pubsub.name)
698 self.assertEquals(NS_PUBSUB, iq.pubsub.uri)
699 children = list(domish.generateElementsQNamed(iq.pubsub.children,
700 'unsubscribe', NS_PUBSUB))
701 self.assertEquals(1, len(children))
702 child = children[0]
703 self.assertEquals('test', child['node'])
704 self.assertEquals('user@example.org', child['jid'])
705
706 self.stub.send(toResponse(iq, 'result'))
707 return d
708
709
710 def test_unsubscribeWithSender(self):
711 """
712 Test sending unsubscription request from a specific JID.
713 """
714 d = self.protocol.unsubscribe(JID('pubsub.example.org'), 'test',
715 JID('user@example.org'),
716 sender=JID('user@example.org'))
717
718 iq = self.stub.output[-1]
719 self.assertEquals('user@example.org', iq['from'])
720 self.stub.send(toResponse(iq, 'result'))
721 return d
722
723
724 def test_unsubscribeWithSubscriptionIdentifier(self):
725 """
726 Test sending unsubscription request with subscription identifier.
727 """
728 d = self.protocol.unsubscribe(JID('pubsub.example.org'), 'test',
729 JID('user@example.org'),
730 subscriptionIdentifier='1234')
731
732 iq = self.stub.output[-1]
733 child = iq.pubsub.unsubscribe
734 self.assertEquals('1234', child['subid'])
735
736 self.stub.send(toResponse(iq, 'result'))
737 return d
738
739
740 def test_items(self):
741 """
742 Test sending items request.
743 """
744 def cb(items):
745 self.assertEquals([], items)
746
747 d = self.protocol.items(JID('pubsub.example.org'), 'test')
748 d.addCallback(cb)
749
750 iq = self.stub.output[-1]
751 self.assertEquals('pubsub.example.org', iq.getAttribute('to'))
752 self.assertEquals('get', iq.getAttribute('type'))
753 self.assertEquals('pubsub', iq.pubsub.name)
754 self.assertEquals(NS_PUBSUB, iq.pubsub.uri)
755 children = list(domish.generateElementsQNamed(iq.pubsub.children,
756 'items', NS_PUBSUB))
757 self.assertEquals(1, len(children))
758 child = children[0]
759 self.assertEquals('test', child['node'])
760
761 response = toResponse(iq, 'result')
762 items = response.addElement((NS_PUBSUB, 'pubsub')).addElement('items')
763 items['node'] = 'test'
764
765 self.stub.send(response)
766
767 return d
768
769
770 def test_itemsMaxItems(self):
771 """
772 Test sending items request, with limit on the number of items.
773 """
774 def cb(items):
775 self.assertEquals(2, len(items))
776 self.assertEquals([item1, item2], items)
777
778 d = self.protocol.items(JID('pubsub.example.org'), 'test', maxItems=2)
779 d.addCallback(cb)
780
781 iq = self.stub.output[-1]
782 self.assertEquals('pubsub.example.org', iq.getAttribute('to'))
783 self.assertEquals('get', iq.getAttribute('type'))
784 self.assertEquals('pubsub', iq.pubsub.name)
785 self.assertEquals(NS_PUBSUB, iq.pubsub.uri)
786 children = list(domish.generateElementsQNamed(iq.pubsub.children,
787 'items', NS_PUBSUB))
788 self.assertEquals(1, len(children))
789 child = children[0]
790 self.assertEquals('test', child['node'])
791 self.assertEquals('2', child['max_items'])
792
793 response = toResponse(iq, 'result')
794 items = response.addElement((NS_PUBSUB, 'pubsub')).addElement('items')
795 items['node'] = 'test'
796 item1 = items.addElement('item')
797 item1['id'] = 'item1'
798 item2 = items.addElement('item')
799 item2['id'] = 'item2'
800
801 self.stub.send(response)
802
803 return d
804
805
806 def test_itemsWithItemIdentifiers(self):
807 """
808 Test sending items request with item identifiers.
809 """
810 def cb(items):
811 self.assertEquals(2, len(items))
812 self.assertEquals([item1, item2], items)
813
814 d = self.protocol.items(JID('pubsub.example.org'), 'test',
815 itemIdentifiers=['item1', 'item2'])
816 d.addCallback(cb)
817
818 iq = self.stub.output[-1]
819 self.assertEquals('pubsub.example.org', iq.getAttribute('to'))
820 self.assertEquals('get', iq.getAttribute('type'))
821 self.assertEquals('pubsub', iq.pubsub.name)
822 self.assertEquals(NS_PUBSUB, iq.pubsub.uri)
823 children = list(domish.generateElementsQNamed(iq.pubsub.children,
824 'items', NS_PUBSUB))
825 self.assertEquals(1, len(children))
826 child = children[0]
827 self.assertEquals('test', child['node'])
828 itemIdentifiers = [item.getAttribute('id') for item in
829 domish.generateElementsQNamed(child.children, 'item',
830 NS_PUBSUB)]
831 self.assertEquals(['item1', 'item2'], itemIdentifiers)
832
833 response = toResponse(iq, 'result')
834 items = response.addElement((NS_PUBSUB, 'pubsub')).addElement('items')
835 items['node'] = 'test'
836 item1 = items.addElement('item')
837 item1['id'] = 'item1'
838 item2 = items.addElement('item')
839 item2['id'] = 'item2'
840
841 self.stub.send(response)
842
843 return d
844
845
846 def test_itemsWithSubscriptionIdentifier(self):
847 """
848 Test sending items request with a subscription identifier.
849 """
850
851 d = self.protocol.items(JID('pubsub.example.org'), 'test',
852 subscriptionIdentifier='1234')
853
854 iq = self.stub.output[-1]
855 child = iq.pubsub.items
856 self.assertEquals('1234', child['subid'])
857
858 response = toResponse(iq, 'result')
859 items = response.addElement((NS_PUBSUB, 'pubsub')).addElement('items')
860 items['node'] = 'test'
861
862 self.stub.send(response)
863 return d
864
865
866 def test_itemsWithSender(self):
867 """
868 Test sending items request from a specific JID.
869 """
870
871 d = self.protocol.items(JID('pubsub.example.org'), 'test',
872 sender=JID('user@example.org'))
873
874 iq = self.stub.output[-1]
875 self.assertEquals('user@example.org', iq['from'])
876
877 response = toResponse(iq, 'result')
878 items = response.addElement((NS_PUBSUB, 'pubsub')).addElement('items')
879 items['node'] = 'test'
880
881 self.stub.send(response)
882 return d
883
884
885 def test_retractItems(self):
886 """
887 Test sending items retraction.
888 """
889 d = self.protocol.retractItems(JID('pubsub.example.org'), 'test',
890 itemIdentifiers=['item1', 'item2'])
891
892 iq = self.stub.output[-1]
893 self.assertEquals('pubsub.example.org', iq.getAttribute('to'))
894 self.assertEquals('set', iq.getAttribute('type'))
895 self.assertEquals('pubsub', iq.pubsub.name)
896 self.assertEquals(NS_PUBSUB, iq.pubsub.uri)
897 children = list(domish.generateElementsQNamed(iq.pubsub.children,
898 'retract', NS_PUBSUB))
899 self.assertEquals(1, len(children))
900 child = children[0]
901 self.assertEquals('test', child['node'])
902 itemIdentifiers = [item.getAttribute('id') for item in
903 domish.generateElementsQNamed(child.children, 'item',
904 NS_PUBSUB)]
905 self.assertEquals(['item1', 'item2'], itemIdentifiers)
906
907 self.stub.send(toResponse(iq, 'result'))
908 return d
909
910
911 def test_retractItemsWithSender(self):
912 """
913 Test retracting items request from a specific JID.
914 """
915 d = self.protocol.retractItems(JID('pubsub.example.org'), 'test',
916 itemIdentifiers=['item1', 'item2'],
917 sender=JID('user@example.org'))
918
919 iq = self.stub.output[-1]
920 self.assertEquals('user@example.org', iq['from'])
921
922 self.stub.send(toResponse(iq, 'result'))
923 return d
924
925
926 def test_getOptions(self):
927 def cb(form):
928 self.assertEqual('form', form.formType)
929 self.assertEqual(NS_PUBSUB_SUBSCRIBE_OPTIONS, form.formNamespace)
930 field = form.fields['pubsub#deliver']
931 self.assertEqual('boolean', field.fieldType)
932 self.assertIdentical(True, field.value)
933 self.assertEqual('Enable delivery?', field.label)
934
935 d = self.protocol.getOptions(JID('pubsub.example.org'), 'test',
936 JID('user@example.org'),
937 sender=JID('user@example.org'))
938 d.addCallback(cb)
939
940 iq = self.stub.output[-1]
941 self.assertEqual('pubsub.example.org', iq.getAttribute('to'))
942 self.assertEqual('get', iq.getAttribute('type'))
943 self.assertEqual('pubsub', iq.pubsub.name)
944 self.assertEqual(NS_PUBSUB, iq.pubsub.uri)
945 children = list(domish.generateElementsQNamed(iq.pubsub.children,
946 'options', NS_PUBSUB))
947 self.assertEqual(1, len(children))
948 child = children[0]
949 self.assertEqual('test', child['node'])
950
951 self.assertEqual(0, len(child.children))
952
953 # Send response
954 form = data_form.Form('form', formNamespace=NS_PUBSUB_SUBSCRIBE_OPTIONS)
955 form.addField(data_form.Field('boolean', var='pubsub#deliver',
956 label='Enable delivery?',
957 value=True))
958 response = toResponse(iq, 'result')
959 response.addElement((NS_PUBSUB, 'pubsub'))
960 response.pubsub.addElement('options')
961 response.pubsub.options.addChild(form.toElement())
962 self.stub.send(response)
963
964 return d
965
966
967 def test_getOptionsWithSubscriptionIdentifier(self):
968 """
969 Getting options with a subid should have the subid in the request.
970 """
971
972 d = self.protocol.getOptions(JID('pubsub.example.org'), 'test',
973 JID('user@example.org'),
974 sender=JID('user@example.org'),
975 subscriptionIdentifier='1234')
976
977 iq = self.stub.output[-1]
978 child = iq.pubsub.options
979 self.assertEqual('1234', child['subid'])
980
981 # Send response
982 form = data_form.Form('form', formNamespace=NS_PUBSUB_SUBSCRIBE_OPTIONS)
983 form.addField(data_form.Field('boolean', var='pubsub#deliver',
984 label='Enable delivery?',
985 value=True))
986 response = toResponse(iq, 'result')
987 response.addElement((NS_PUBSUB, 'pubsub'))
988 response.pubsub.addElement('options')
989 response.pubsub.options.addChild(form.toElement())
990 self.stub.send(response)
991
992 return d
993
994
995 def test_setOptions(self):
996 """
997 setOptions should send out a options-set request.
998 """
999 options = {'pubsub#deliver': False}
1000
1001 d = self.protocol.setOptions(JID('pubsub.example.org'), 'test',
1002 JID('user@example.org'),
1003 options,
1004 sender=JID('user@example.org'))
1005
1006 iq = self.stub.output[-1]
1007 self.assertEqual('pubsub.example.org', iq.getAttribute('to'))
1008 self.assertEqual('set', iq.getAttribute('type'))
1009 self.assertEqual('pubsub', iq.pubsub.name)
1010 self.assertEqual(NS_PUBSUB, iq.pubsub.uri)
1011 children = list(domish.generateElementsQNamed(iq.pubsub.children,
1012 'options', NS_PUBSUB))
1013 self.assertEqual(1, len(children))
1014 child = children[0]
1015 self.assertEqual('test', child['node'])
1016
1017 form = data_form.findForm(child, NS_PUBSUB_SUBSCRIBE_OPTIONS)
1018 self.assertEqual('submit', form.formType)
1019 form.typeCheck({'pubsub#deliver': {'type': 'boolean'}})
1020 self.assertEqual(options, form.getValues())
1021
1022 response = toResponse(iq, 'result')
1023 self.stub.send(response)
1024
1025 return d
1026
1027
1028 def test_setOptionsWithSubscriptionIdentifier(self):
1029 """
1030 setOptions should send out a options-set request with subid.
1031 """
1032 options = {'pubsub#deliver': False}
1033
1034 d = self.protocol.setOptions(JID('pubsub.example.org'), 'test',
1035 JID('user@example.org'),
1036 options,
1037 subscriptionIdentifier='1234',
1038 sender=JID('user@example.org'))
1039
1040 iq = self.stub.output[-1]
1041 child = iq.pubsub.options
1042 self.assertEqual('1234', child['subid'])
1043
1044 form = data_form.findForm(child, NS_PUBSUB_SUBSCRIBE_OPTIONS)
1045 self.assertEqual('submit', form.formType)
1046 form.typeCheck({'pubsub#deliver': {'type': 'boolean'}})
1047 self.assertEqual(options, form.getValues())
1048
1049 response = toResponse(iq, 'result')
1050 self.stub.send(response)
1051
1052 return d
1053
1054
1055 class PubSubRequestTest(unittest.TestCase):
1056
1057 def test_fromElementUnknown(self):
1058 """
1059 An unknown verb raises NotImplementedError.
1060 """
1061
1062 xml = """
1063 <iq type='set' to='pubsub.example.org'
1064 from='user@example.org'>
1065 <pubsub xmlns='http://jabber.org/protocol/pubsub'>
1066 <non-existing-verb/>
1067 </pubsub>
1068 </iq>
1069 """
1070
1071 self.assertRaises(NotImplementedError,
1072 pubsub.PubSubRequest.fromElement, parseXml(xml))
1073
1074
1075 def test_fromElementKnownBadCombination(self):
1076 """
1077 Multiple verbs in an unknown configuration raises NotImplementedError.
1078 """
1079
1080 xml = """
1081 <iq type='set' to='pubsub.example.org'
1082 from='user@example.org'>
1083 <pubsub xmlns='http://jabber.org/protocol/pubsub'>
1084 <publish/>
1085 <create/>
1086 </pubsub>
1087 </iq>
1088 """
1089
1090 self.assertRaises(NotImplementedError,
1091 pubsub.PubSubRequest.fromElement, parseXml(xml))
1092
1093 def test_fromElementPublish(self):
1094 """
1095 Test parsing a publish request.
1096 """
1097
1098 xml = """
1099 <iq type='set' to='pubsub.example.org'
1100 from='user@example.org'>
1101 <pubsub xmlns='http://jabber.org/protocol/pubsub'>
1102 <publish node='test'/>
1103 </pubsub>
1104 </iq>
1105 """
1106
1107 request = pubsub.PubSubRequest.fromElement(parseXml(xml))
1108 self.assertEqual('publish', request.verb)
1109 self.assertEqual(JID('user@example.org'), request.sender)
1110 self.assertEqual(JID('pubsub.example.org'), request.recipient)
1111 self.assertEqual('test', request.nodeIdentifier)
1112 self.assertEqual([], request.items)
1113
1114
1115 def test_fromElementPublishItems(self):
1116 """
1117 Test parsing a publish request with items.
1118 """
1119
1120 xml = """
1121 <iq type='set' to='pubsub.example.org'
1122 from='user@example.org'>
1123 <pubsub xmlns='http://jabber.org/protocol/pubsub'>
1124 <publish node='test'>
1125 <item id="item1"/>
1126 <item id="item2"/>
1127 </publish>
1128 </pubsub>
1129 </iq>
1130 """
1131
1132 request = pubsub.PubSubRequest.fromElement(parseXml(xml))
1133 self.assertEqual(2, len(request.items))
1134 self.assertEqual(u'item1', request.items[0]["id"])
1135 self.assertEqual(u'item2', request.items[1]["id"])
1136
1137
1138 def test_fromElementPublishItemsOptions(self):
1139 """
1140 Test parsing a publish request with items and options.
1141
1142 Note that publishing options are not supported, but passing them
1143 shouldn't affect processing of the publish request itself.
1144 """
1145
1146 xml = """
1147 <iq type='set' to='pubsub.example.org'
1148 from='user@example.org'>
1149 <pubsub xmlns='http://jabber.org/protocol/pubsub'>
1150 <publish node='test'>
1151 <item id="item1"/>
1152 <item id="item2"/>
1153 </publish>
1154 <publish-options/>
1155 </pubsub>
1156 </iq>
1157 """
1158
1159 request = pubsub.PubSubRequest.fromElement(parseXml(xml))
1160 self.assertEqual(2, len(request.items))
1161 self.assertEqual(u'item1', request.items[0]["id"])
1162 self.assertEqual(u'item2', request.items[1]["id"])
1163
1164 def test_fromElementPublishNoNode(self):
1165 """
1166 A publish request to the root node should raise an exception.
1167 """
1168 xml = """
1169 <iq type='set' to='pubsub.example.org'
1170 from='user@example.org'>
1171 <pubsub xmlns='http://jabber.org/protocol/pubsub'>
1172 <publish/>
1173 </pubsub>
1174 </iq>
1175 """
1176
1177 err = self.assertRaises(error.StanzaError,
1178 pubsub.PubSubRequest.fromElement,
1179 parseXml(xml))
1180 self.assertEqual('bad-request', err.condition)
1181 self.assertEqual(NS_PUBSUB_ERRORS, err.appCondition.uri)
1182 self.assertEqual('nodeid-required', err.appCondition.name)
1183
1184
1185 def test_fromElementSubscribe(self):
1186 """
1187 Test parsing a subscription request.
1188 """
1189
1190 xml = """
1191 <iq type='set' to='pubsub.example.org'
1192 from='user@example.org'>
1193 <pubsub xmlns='http://jabber.org/protocol/pubsub'>
1194 <subscribe node='test' jid='user@example.org/Home'/>
1195 </pubsub>
1196 </iq>
1197 """
1198
1199 request = pubsub.PubSubRequest.fromElement(parseXml(xml))
1200 self.assertEqual('subscribe', request.verb)
1201 self.assertEqual(JID('user@example.org'), request.sender)
1202 self.assertEqual(JID('pubsub.example.org'), request.recipient)
1203 self.assertEqual('test', request.nodeIdentifier)
1204 self.assertEqual(JID('user@example.org/Home'), request.subscriber)
1205
1206
1207 def test_fromElementSubscribeEmptyNode(self):
1208 """
1209 Test parsing a subscription request to the root node.
1210 """
1211
1212 xml = """
1213 <iq type='set' to='pubsub.example.org'
1214 from='user@example.org'>
1215 <pubsub xmlns='http://jabber.org/protocol/pubsub'>
1216 <subscribe jid='user@example.org/Home'/>
1217 </pubsub>
1218 </iq>
1219 """
1220
1221 request = pubsub.PubSubRequest.fromElement(parseXml(xml))
1222 self.assertEqual('', request.nodeIdentifier)
1223
1224
1225 def test_fromElementSubscribeNoJID(self):
1226 """
1227 Subscribe requests without a JID should raise a bad-request exception.
1228 """
1229 xml = """
1230 <iq type='set' to='pubsub.example.org'
1231 from='user@example.org'>
1232 <pubsub xmlns='http://jabber.org/protocol/pubsub'>
1233 <subscribe node='test'/>
1234 </pubsub>
1235 </iq>
1236 """
1237 err = self.assertRaises(error.StanzaError,
1238 pubsub.PubSubRequest.fromElement,
1239 parseXml(xml))
1240 self.assertEqual('bad-request', err.condition)
1241 self.assertEqual(NS_PUBSUB_ERRORS, err.appCondition.uri)
1242 self.assertEqual('jid-required', err.appCondition.name)
1243
1244
1245 def test_fromElementSubscribeWithOptions(self):
1246 """
1247 Test parsing a subscription request.
1248 """
1249
1250 xml = """
1251 <iq type='set' to='pubsub.example.org'
1252 from='user@example.org'>
1253 <pubsub xmlns='http://jabber.org/protocol/pubsub'>
1254 <subscribe node='test' jid='user@example.org/Home'/>
1255 <options>
1256 <x xmlns="jabber:x:data" type='submit'>
1257 <field var='FORM_TYPE' type='hidden'>
1258 <value>http://jabber.org/protocol/pubsub#subscribe_options</value>
1259 </field>
1260 <field var='pubsub#deliver' type='boolean'
1261 label='Enable delivery?'>
1262 <value>1</value>
1263 </field>
1264 </x>
1265 </options>
1266 </pubsub>
1267 </iq>
1268 """
1269
1270 request = pubsub.PubSubRequest.fromElement(parseXml(xml))
1271 self.assertEqual('subscribe', request.verb)
1272 request.options.typeCheck({'pubsub#deliver': {'type': 'boolean'}})
1273 self.assertEqual({'pubsub#deliver': True}, request.options.getValues())
1274
1275
1276 def test_fromElementSubscribeWithOptionsBadFormType(self):
1277 """
1278 The options form should have the right type.
1279 """
1280
1281 xml = """
1282 <iq type='set' to='pubsub.example.org'
1283 from='user@example.org'>
1284 <pubsub xmlns='http://jabber.org/protocol/pubsub'>
1285 <subscribe node='test' jid='user@example.org/Home'/>
1286 <options>
1287 <x xmlns="jabber:x:data" type='result'>
1288 <field var='FORM_TYPE' type='hidden'>
1289 <value>http://jabber.org/protocol/pubsub#subscribe_options</value>
1290 </field>
1291 <field var='pubsub#deliver' type='boolean'
1292 label='Enable delivery?'>
1293 <value>1</value>
1294 </field>
1295 </x>
1296 </options>
1297 </pubsub>
1298 </iq>
1299 """
1300
1301 err = self.assertRaises(error.StanzaError,
1302 pubsub.PubSubRequest.fromElement,
1303 parseXml(xml))
1304 self.assertEqual('bad-request', err.condition)
1305 self.assertEqual("Unexpected form type 'result'", err.text)
1306 self.assertEqual(None, err.appCondition)
1307
1308
1309 def test_fromElementSubscribeWithOptionsEmpty(self):
1310 """
1311 When no (suitable) form is found, the options are empty.
1312 """
1313
1314 xml = """
1315 <iq type='set' to='pubsub.example.org'
1316 from='user@example.org'>
1317 <pubsub xmlns='http://jabber.org/protocol/pubsub'>
1318 <subscribe node='test' jid='user@example.org/Home'/>
1319 <options/>
1320 </pubsub>
1321 </iq>
1322 """
1323
1324 request = pubsub.PubSubRequest.fromElement(parseXml(xml))
1325 self.assertEqual('subscribe', request.verb)
1326 self.assertEqual({}, request.options.getValues())
1327
1328
1329 def test_fromElementUnsubscribe(self):
1330 """
1331 Test parsing an unsubscription request.
1332 """
1333
1334 xml = """
1335 <iq type='set' to='pubsub.example.org'
1336 from='user@example.org'>
1337 <pubsub xmlns='http://jabber.org/protocol/pubsub'>
1338 <unsubscribe node='test' jid='user@example.org/Home'/>
1339 </pubsub>
1340 </iq>
1341 """
1342
1343 request = pubsub.PubSubRequest.fromElement(parseXml(xml))
1344 self.assertEqual('unsubscribe', request.verb)
1345 self.assertEqual(JID('user@example.org'), request.sender)
1346 self.assertEqual(JID('pubsub.example.org'), request.recipient)
1347 self.assertEqual('test', request.nodeIdentifier)
1348 self.assertEqual(JID('user@example.org/Home'), request.subscriber)
1349
1350
1351 def test_fromElementUnsubscribeWithSubscriptionIdentifier(self):
1352 """
1353 Test parsing an unsubscription request with subscription identifier.
1354 """
1355
1356 xml = """
1357 <iq type='set' to='pubsub.example.org'
1358 from='user@example.org'>
1359 <pubsub xmlns='http://jabber.org/protocol/pubsub'>
1360 <unsubscribe node='test' jid='user@example.org/Home'
1361 subid='1234'/>
1362 </pubsub>
1363 </iq>
1364 """
1365
1366 request = pubsub.PubSubRequest.fromElement(parseXml(xml))
1367 self.assertEqual('1234', request.subscriptionIdentifier)
1368
1369
1370 def test_fromElementUnsubscribeNoJID(self):
1371 """
1372 Unsubscribe requests without a JID should raise a bad-request exception.
1373 """
1374 xml = """
1375 <iq type='set' to='pubsub.example.org'
1376 from='user@example.org'>
1377 <pubsub xmlns='http://jabber.org/protocol/pubsub'>
1378 <unsubscribe node='test'/>
1379 </pubsub>
1380 </iq>
1381 """
1382 err = self.assertRaises(error.StanzaError,
1383 pubsub.PubSubRequest.fromElement,
1384 parseXml(xml))
1385 self.assertEqual('bad-request', err.condition)
1386 self.assertEqual(NS_PUBSUB_ERRORS, err.appCondition.uri)
1387 self.assertEqual('jid-required', err.appCondition.name)
1388
1389
1390 def test_fromElementOptionsGet(self):
1391 """
1392 Test parsing a request for getting subscription options.
1393 """
1394
1395 xml = """
1396 <iq type='get' to='pubsub.example.org'
1397 from='user@example.org'>
1398 <pubsub xmlns='http://jabber.org/protocol/pubsub'>
1399 <options node='test' jid='user@example.org/Home'/>
1400 </pubsub>
1401 </iq>
1402 """
1403
1404 request = pubsub.PubSubRequest.fromElement(parseXml(xml))
1405 self.assertEqual('optionsGet', request.verb)
1406 self.assertEqual(JID('user@example.org'), request.sender)
1407 self.assertEqual(JID('pubsub.example.org'), request.recipient)
1408 self.assertEqual('test', request.nodeIdentifier)
1409 self.assertEqual(JID('user@example.org/Home'), request.subscriber)
1410
1411
1412 def test_fromElementOptionsGetWithSubscriptionIdentifier(self):
1413 """
1414 Test parsing a request for getting subscription options with subid.
1415 """
1416
1417 xml = """
1418 <iq type='get' to='pubsub.example.org'
1419 from='user@example.org'>
1420 <pubsub xmlns='http://jabber.org/protocol/pubsub'>
1421 <options node='test' jid='user@example.org/Home'
1422 subid='1234'/>
1423 </pubsub>
1424 </iq>
1425 """
1426
1427 request = pubsub.PubSubRequest.fromElement(parseXml(xml))
1428 self.assertEqual('1234', request.subscriptionIdentifier)
1429
1430
1431 def test_fromElementOptionsSet(self):
1432 """
1433 Test parsing a request for setting subscription options.
1434 """
1435
1436 xml = """
1437 <iq type='set' to='pubsub.example.org'
1438 from='user@example.org'>
1439 <pubsub xmlns='http://jabber.org/protocol/pubsub'>
1440 <options node='test' jid='user@example.org/Home'>
1441 <x xmlns='jabber:x:data' type='submit'>
1442 <field var='FORM_TYPE' type='hidden'>
1443 <value>http://jabber.org/protocol/pubsub#subscribe_options</value>
1444 </field>
1445 <field var='pubsub#deliver'><value>1</value></field>
1446 </x>
1447 </options>
1448 </pubsub>
1449 </iq>
1450 """
1451
1452 request = pubsub.PubSubRequest.fromElement(parseXml(xml))
1453 self.assertEqual('optionsSet', request.verb)
1454 self.assertEqual(JID('user@example.org'), request.sender)
1455 self.assertEqual(JID('pubsub.example.org'), request.recipient)
1456 self.assertEqual('test', request.nodeIdentifier)
1457 self.assertEqual(JID('user@example.org/Home'), request.subscriber)
1458 self.assertEqual({'pubsub#deliver': '1'}, request.options.getValues())
1459
1460
1461 def test_fromElementOptionsSetWithSubscriptionIdentifier(self):
1462 """
1463 Test parsing a request for setting subscription options with subid.
1464 """
1465
1466 xml = """
1467 <iq type='set' to='pubsub.example.org'
1468 from='user@example.org'>
1469 <pubsub xmlns='http://jabber.org/protocol/pubsub'>
1470 <options node='test' jid='user@example.org/Home'
1471 subid='1234'>
1472 <x xmlns='jabber:x:data' type='submit'>
1473 <field var='FORM_TYPE' type='hidden'>
1474 <value>http://jabber.org/protocol/pubsub#subscribe_options</value>
1475 </field>
1476 <field var='pubsub#deliver'><value>1</value></field>
1477 </x>
1478 </options>
1479 </pubsub>
1480 </iq>
1481 """
1482
1483 request = pubsub.PubSubRequest.fromElement(parseXml(xml))
1484 self.assertEqual('1234', request.subscriptionIdentifier)
1485
1486
1487 def test_fromElementOptionsSetCancel(self):
1488 """
1489 Test parsing a request for cancelling setting subscription options.
1490 """
1491
1492 xml = """
1493 <iq type='set' to='pubsub.example.org'
1494 from='user@example.org'>
1495 <pubsub xmlns='http://jabber.org/protocol/pubsub'>
1496 <options node='test' jid='user@example.org/Home'>
1497 <x xmlns='jabber:x:data' type='cancel'/>
1498 </options>
1499 </pubsub>
1500 </iq>
1501 """
1502
1503 request = pubsub.PubSubRequest.fromElement(parseXml(xml))
1504 self.assertEqual('cancel', request.options.formType)
1505
1506
1507 def test_fromElementOptionsSetBadFormType(self):
1508 """
1509 On a options set request unknown fields should be ignored.
1510 """
1511
1512 xml = """
1513 <iq type='set' to='pubsub.example.org'
1514 from='user@example.org'>
1515 <pubsub xmlns='http://jabber.org/protocol/pubsub'>
1516 <options node='test' jid='user@example.org/Home'>
1517 <x xmlns='jabber:x:data' type='result'>
1518 <field var='FORM_TYPE' type='hidden'>
1519 <value>http://jabber.org/protocol/pubsub#subscribe_options</value>
1520 </field>
1521 <field var='pubsub#deliver'><value>1</value></field>
1522 </x>
1523 </options>
1524 </pubsub>
1525 </iq>
1526 """
1527
1528 err = self.assertRaises(error.StanzaError,
1529 pubsub.PubSubRequest.fromElement,
1530 parseXml(xml))
1531 self.assertEqual('bad-request', err.condition)
1532 self.assertEqual("Unexpected form type 'result'", err.text)
1533 self.assertEqual(None, err.appCondition)
1534
1535
1536 def test_fromElementOptionsSetNoForm(self):
1537 """
1538 On a options set request a form is required.
1539 """
1540
1541 xml = """
1542 <iq type='set' to='pubsub.example.org'
1543 from='user@example.org'>
1544 <pubsub xmlns='http://jabber.org/protocol/pubsub'>
1545 <options node='test' jid='user@example.org/Home'/>
1546 </pubsub>
1547 </iq>
1548 """
1549 err = self.assertRaises(error.StanzaError,
1550 pubsub.PubSubRequest.fromElement,
1551 parseXml(xml))
1552 self.assertEqual('bad-request', err.condition)
1553 self.assertEqual(None, err.appCondition)
1554
1555
1556 def test_fromElementSubscriptions(self):
1557 """
1558 Test parsing a request for all subscriptions.
1559 """
1560
1561 xml = """
1562 <iq type='get' to='pubsub.example.org'
1563 from='user@example.org'>
1564 <pubsub xmlns='http://jabber.org/protocol/pubsub'>
1565 <subscriptions/>
1566 </pubsub>
1567 </iq>
1568 """
1569
1570 request = pubsub.PubSubRequest.fromElement(parseXml(xml))
1571 self.assertEqual('subscriptions', request.verb)
1572 self.assertEqual(JID('user@example.org'), request.sender)
1573 self.assertEqual(JID('pubsub.example.org'), request.recipient)
1574
1575
1576 def test_fromElementAffiliations(self):
1577 """
1578 Test parsing a request for all affiliations.
1579 """
1580
1581 xml = """
1582 <iq type='get' to='pubsub.example.org'
1583 from='user@example.org'>
1584 <pubsub xmlns='http://jabber.org/protocol/pubsub'>
1585 <affiliations/>
1586 </pubsub>
1587 </iq>
1588 """
1589
1590 request = pubsub.PubSubRequest.fromElement(parseXml(xml))
1591 self.assertEqual('affiliations', request.verb)
1592 self.assertEqual(JID('user@example.org'), request.sender)
1593 self.assertEqual(JID('pubsub.example.org'), request.recipient)
1594
1595
1596 def test_fromElementCreate(self):
1597 """
1598 Test parsing a request to create a node.
1599 """
1600
1601 xml = """
1602 <iq type='set' to='pubsub.example.org'
1603 from='user@example.org'>
1604 <pubsub xmlns='http://jabber.org/protocol/pubsub'>
1605 <create node='mynode'/>
1606 </pubsub>
1607 </iq>
1608 """
1609
1610 request = pubsub.PubSubRequest.fromElement(parseXml(xml))
1611 self.assertEqual('create', request.verb)
1612 self.assertEqual(JID('user@example.org'), request.sender)
1613 self.assertEqual(JID('pubsub.example.org'), request.recipient)
1614 self.assertEqual('mynode', request.nodeIdentifier)
1615 self.assertIdentical(None, request.options)
1616
1617
1618 def test_fromElementCreateInstant(self):
1619 """
1620 Test parsing a request to create an instant node.
1621 """
1622
1623 xml = """
1624 <iq type='set' to='pubsub.example.org'
1625 from='user@example.org'>
1626 <pubsub xmlns='http://jabber.org/protocol/pubsub'>
1627 <create/>
1628 </pubsub>
1629 </iq>
1630 """
1631
1632 request = pubsub.PubSubRequest.fromElement(parseXml(xml))
1633 self.assertIdentical(None, request.nodeIdentifier)
1634
1635
1636 def test_fromElementCreateConfigureEmpty(self):
1637 """
1638 Test parsing a request to create a node with an empty configuration.
1639 """
1640
1641 xml = """
1642 <iq type='set' to='pubsub.example.org'
1643 from='user@example.org'>
1644 <pubsub xmlns='http://jabber.org/protocol/pubsub'>
1645 <create node='mynode'/>
1646 <configure/>
1647 </pubsub>
1648 </iq>
1649 """
1650
1651 request = pubsub.PubSubRequest.fromElement(parseXml(xml))
1652 self.assertEqual({}, request.options.getValues())
1653 self.assertEqual(u'mynode', request.nodeIdentifier)
1654
1655
1656 def test_fromElementCreateConfigureEmptyWrongOrder(self):
1657 """
1658 Test parsing a request to create a node and configure, wrong order.
1659
1660 The C{configure} element should come after the C{create} request,
1661 but we should accept both orders.
1662 """
1663
1664 xml = """
1665 <iq type='set' to='pubsub.example.org'
1666 from='user@example.org'>
1667 <pubsub xmlns='http://jabber.org/protocol/pubsub'>
1668 <configure/>
1669 <create node='mynode'/>
1670 </pubsub>
1671 </iq>
1672 """
1673
1674 request = pubsub.PubSubRequest.fromElement(parseXml(xml))
1675 self.assertEqual({}, request.options.getValues())
1676 self.assertEqual(u'mynode', request.nodeIdentifier)
1677
1678
1679 def test_fromElementCreateConfigure(self):
1680 """
1681 Test parsing a request to create a node.
1682 """
1683
1684 xml = """
1685 <iq type='set' to='pubsub.example.org'
1686 from='user@example.org'>
1687 <pubsub xmlns='http://jabber.org/protocol/pubsub'>
1688 <create node='mynode'/>
1689 <configure>
1690 <x xmlns='jabber:x:data' type='submit'>
1691 <field var='FORM_TYPE' type='hidden'>
1692 <value>http://jabber.org/protocol/pubsub#node_config</value>
1693 </field>
1694 <field var='pubsub#access_model'><value>open</value></field>
1695 <field var='pubsub#persist_items'><value>0</value></field>
1696 </x>
1697 </configure>
1698 </pubsub>
1699 </iq>
1700 """
1701
1702 request = pubsub.PubSubRequest.fromElement(parseXml(xml))
1703 values = request.options
1704 self.assertIn('pubsub#access_model', values)
1705 self.assertEqual(u'open', values['pubsub#access_model'])
1706 self.assertIn('pubsub#persist_items', values)
1707 self.assertEqual(u'0', values['pubsub#persist_items'])
1708
1709
1710 def test_fromElementCreateConfigureBadFormType(self):
1711 """
1712 The form of a node creation request should have the right type.
1713 """
1714
1715 xml = """
1716 <iq type='set' to='pubsub.example.org'
1717 from='user@example.org'>
1718 <pubsub xmlns='http://jabber.org/protocol/pubsub'>
1719 <create node='mynode'/>
1720 <configure>
1721 <x xmlns='jabber:x:data' type='result'>
1722 <field var='FORM_TYPE' type='hidden'>
1723 <value>http://jabber.org/protocol/pubsub#node_config</value>
1724 </field>
1725 <field var='pubsub#access_model'><value>open</value></field>
1726 <field var='pubsub#persist_items'><value>0</value></field>
1727 </x>
1728 </configure>
1729 </pubsub>
1730 </iq>
1731 """
1732
1733 err = self.assertRaises(error.StanzaError,
1734 pubsub.PubSubRequest.fromElement,
1735 parseXml(xml))
1736 self.assertEqual('bad-request', err.condition)
1737 self.assertEqual("Unexpected form type 'result'", err.text)
1738 self.assertEqual(None, err.appCondition)
1739
1740
1741 def test_fromElementDefault(self):
1742 """
1743 Parsing default node configuration request sets required attributes.
1744
1745 Besides C{verb}, C{sender} and C{recipient}, we expect C{nodeType}
1746 to be set. If not passed it receives the default C{u'leaf'}.
1747 """
1748
1749 xml = """
1750 <iq type='get' to='pubsub.example.org'
1751 from='user@example.org'>
1752 <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
1753 <default/>
1754 </pubsub>
1755 </iq>
1756 """
1757
1758 request = pubsub.PubSubRequest.fromElement(parseXml(xml))
1759 self.assertEquals(u'default', request.verb)
1760 self.assertEquals(JID('user@example.org'), request.sender)
1761 self.assertEquals(JID('pubsub.example.org'), request.recipient)
1762 self.assertEquals(u'leaf', request.nodeType)
1763
1764
1765 def test_fromElementDefaultCollection(self):
1766 """
1767 Parsing default request for collection sets nodeType to collection.
1768 """
1769
1770 xml = """
1771 <iq type='get' to='pubsub.example.org'
1772 from='user@example.org'>
1773 <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
1774 <default>
1775 <x xmlns='jabber:x:data' type='submit'>
1776 <field var='FORM_TYPE' type='hidden'>
1777 <value>http://jabber.org/protocol/pubsub#node_config</value>
1778 </field>
1779 <field var='pubsub#node_type'>
1780 <value>collection</value>
1781 </field>
1782 </x>
1783 </default>
1784
1785 </pubsub>
1786 </iq>
1787 """
1788
1789 request = pubsub.PubSubRequest.fromElement(parseXml(xml))
1790 self.assertEquals('collection', request.nodeType)
1791
1792
1793 def test_fromElementConfigureGet(self):
1794 """
1795 Test parsing a node configuration get request.
1796 """
1797
1798 xml = """
1799 <iq type='get' to='pubsub.example.org'
1800 from='user@example.org'>
1801 <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
1802 <configure node='test'/>
1803 </pubsub>
1804 </iq>
1805 """
1806
1807 request = pubsub.PubSubRequest.fromElement(parseXml(xml))
1808 self.assertEqual('configureGet', request.verb)
1809 self.assertEqual(JID('user@example.org'), request.sender)
1810 self.assertEqual(JID('pubsub.example.org'), request.recipient)
1811 self.assertEqual('test', request.nodeIdentifier)
1812
1813
1814 def test_fromElementConfigureSet(self):
1815 """
1816 On a node configuration set request the Data Form is parsed.
1817 """
1818
1819 xml = """
1820 <iq type='set' to='pubsub.example.org'
1821 from='user@example.org'>
1822 <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
1823 <configure node='test'>
1824 <x xmlns='jabber:x:data' type='submit'>
1825 <field var='FORM_TYPE' type='hidden'>
1826 <value>http://jabber.org/protocol/pubsub#node_config</value>
1827 </field>
1828 <field var='pubsub#deliver_payloads'><value>0</value></field>
1829 <field var='pubsub#persist_items'><value>1</value></field>
1830 </x>
1831 </configure>
1832 </pubsub>
1833 </iq>
1834 """
1835
1836 request = pubsub.PubSubRequest.fromElement(parseXml(xml))
1837 self.assertEqual('configureSet', request.verb)
1838 self.assertEqual(JID('user@example.org'), request.sender)
1839 self.assertEqual(JID('pubsub.example.org'), request.recipient)
1840 self.assertEqual('test', request.nodeIdentifier)
1841 self.assertEqual({'pubsub#deliver_payloads': '0',
1842 'pubsub#persist_items': '1'},
1843 request.options.getValues())
1844
1845
1846 def test_fromElementConfigureSetCancel(self):
1847 """
1848 The node configuration is cancelled, so no options.
1849 """
1850
1851 xml = """
1852 <iq type='set' to='pubsub.example.org'
1853 from='user@example.org'>
1854 <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
1855 <configure node='test'>
1856 <x xmlns='jabber:x:data' type='cancel'/>
1857 </configure>
1858 </pubsub>
1859 </iq>
1860 """
1861
1862 request = pubsub.PubSubRequest.fromElement(parseXml(xml))
1863 self.assertEqual('cancel', request.options.formType)
1864
1865
1866 def test_fromElementConfigureSetBadFormType(self):
1867 """
1868 The form of a node configuraton set request should have the right type.
1869 """
1870
1871 xml = """
1872 <iq type='set' to='pubsub.example.org'
1873 from='user@example.org'>
1874 <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
1875 <configure node='test'>
1876 <x xmlns='jabber:x:data' type='result'>
1877 <field var='FORM_TYPE' type='hidden'>
1878 <value>http://jabber.org/protocol/pubsub#node_config</value>
1879 </field>
1880 <field var='pubsub#deliver_payloads'><value>0</value></field>
1881 <field var='x-myfield'><value>1</value></field>
1882 </x>
1883 </configure>
1884 </pubsub>
1885 </iq>
1886 """
1887
1888 err = self.assertRaises(error.StanzaError,
1889 pubsub.PubSubRequest.fromElement,
1890 parseXml(xml))
1891 self.assertEqual('bad-request', err.condition)
1892 self.assertEqual("Unexpected form type 'result'", err.text)
1893 self.assertEqual(None, err.appCondition)
1894
1895
1896 def test_fromElementConfigureSetNoForm(self):
1897 """
1898 On a node configuration set request a form is required.
1899 """
1900
1901 xml = """
1902 <iq type='set' to='pubsub.example.org'
1903 from='user@example.org'>
1904 <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
1905 <configure node='test'/>
1906 </pubsub>
1907 </iq>
1908 """
1909 err = self.assertRaises(error.StanzaError,
1910 pubsub.PubSubRequest.fromElement,
1911 parseXml(xml))
1912 self.assertEqual('bad-request', err.condition)
1913 self.assertEqual(None, err.appCondition)
1914
1915
1916 def test_fromElementItems(self):
1917 """
1918 Test parsing an items request.
1919 """
1920 xml = """
1921 <iq type='get' to='pubsub.example.org'
1922 from='user@example.org'>
1923 <pubsub xmlns='http://jabber.org/protocol/pubsub'>
1924 <items node='test'/>
1925 </pubsub>
1926 </iq>
1927 """
1928
1929 request = pubsub.PubSubRequest.fromElement(parseXml(xml))
1930 self.assertEqual('items', request.verb)
1931 self.assertEqual(JID('user@example.org'), request.sender)
1932 self.assertEqual(JID('pubsub.example.org'), request.recipient)
1933 self.assertEqual('test', request.nodeIdentifier)
1934 self.assertIdentical(None, request.maxItems)
1935 self.assertIdentical(None, request.subscriptionIdentifier)
1936 self.assertEqual([], request.itemIdentifiers)
1937
1938
1939 def test_fromElementItemsSubscriptionIdentifier(self):
1940 """
1941 Test parsing an items request with subscription identifier.
1942 """
1943 xml = """
1944 <iq type='get' to='pubsub.example.org'
1945 from='user@example.org'>
1946 <pubsub xmlns='http://jabber.org/protocol/pubsub'>
1947 <items node='test' subid='1234'/>
1948 </pubsub>
1949 </iq>
1950 """
1951
1952 request = pubsub.PubSubRequest.fromElement(parseXml(xml))
1953 self.assertEqual('1234', request.subscriptionIdentifier)
1954
1955
1956 def test_fromElementRetract(self):
1957 """
1958 Test parsing a retract request.
1959 """
1960
1961 xml = """
1962 <iq type='set' to='pubsub.example.org'
1963 from='user@example.org'>
1964 <pubsub xmlns='http://jabber.org/protocol/pubsub'>
1965 <retract node='test'>
1966 <item id='item1'/>
1967 <item id='item2'/>
1968 </retract>
1969 </pubsub>
1970 </iq>
1971 """
1972
1973 request = pubsub.PubSubRequest.fromElement(parseXml(xml))
1974 self.assertEqual('retract', request.verb)
1975 self.assertEqual(JID('user@example.org'), request.sender)
1976 self.assertEqual(JID('pubsub.example.org'), request.recipient)
1977 self.assertEqual('test', request.nodeIdentifier)
1978 self.assertEqual(['item1', 'item2'], request.itemIdentifiers)
1979
1980
1981 def test_fromElementPurge(self):
1982 """
1983 Test parsing a purge request.
1984 """
1985
1986 xml = """
1987 <iq type='set' to='pubsub.example.org'
1988 from='user@example.org'>
1989 <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
1990 <purge node='test'/>
1991 </pubsub>
1992 </iq>
1993 """
1994
1995 request = pubsub.PubSubRequest.fromElement(parseXml(xml))
1996 self.assertEqual('purge', request.verb)
1997 self.assertEqual(JID('user@example.org'), request.sender)
1998 self.assertEqual(JID('pubsub.example.org'), request.recipient)
1999 self.assertEqual('test', request.nodeIdentifier)
2000
2001
2002 def test_fromElementDelete(self):
2003 """
2004 Test parsing a delete request.
2005 """
2006
2007 xml = """
2008 <iq type='set' to='pubsub.example.org'
2009 from='user@example.org'>
2010 <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
2011 <delete node='test'/>
2012 </pubsub>
2013 </iq>
2014 """
2015
2016 request = pubsub.PubSubRequest.fromElement(parseXml(xml))
2017 self.assertEqual('delete', request.verb)
2018 self.assertEqual(JID('user@example.org'), request.sender)
2019 self.assertEqual(JID('pubsub.example.org'), request.recipient)
2020 self.assertEqual('test', request.nodeIdentifier)
2021
2022
2023
2024 class PubSubServiceTest(unittest.TestCase, TestableRequestHandlerMixin):
2025 """
2026 Tests for L{pubsub.PubSubService}.
2027 """
2028
2029 def setUp(self):
2030 self.stub = XmlStreamStub()
2031 self.resource = pubsub.PubSubResource()
2032 self.service = pubsub.PubSubService(self.resource)
2033 self.service.send = self.stub.xmlstream.send
2034
2035 def test_interface(self):
2036 """
2037 Do instances of L{pubsub.PubSubService} provide L{iwokkel.IPubSubService}?
2038 """
2039 verify.verifyObject(iwokkel.IPubSubService, self.service)
2040
2041
2042 def test_interfaceIDisco(self):
2043 """
2044 Do instances of L{pubsub.PubSubService} provide L{iwokkel.IDisco}?
2045 """
2046 verify.verifyObject(iwokkel.IDisco, self.service)
2047
2048
2049 def test_connectionMade(self):
2050 """
2051 Verify setup of observers in L{pubsub.connectionMade}.
2052 """
2053 requests = []
2054
2055 def handleRequest(iq):
2056 requests.append(iq)
2057
2058 self.service.xmlstream = self.stub.xmlstream
2059 self.service.handleRequest = handleRequest
2060 self.service.connectionMade()
2061
2062 for namespace in (NS_PUBSUB, NS_PUBSUB_OWNER):
2063 for stanzaType in ('get', 'set'):
2064 iq = domish.Element((None, 'iq'))
2065 iq['type'] = stanzaType
2066 iq.addElement((namespace, 'pubsub'))
2067 self.stub.xmlstream.dispatch(iq)
2068
2069 self.assertEqual(4, len(requests))
2070
2071
2072 def test_getDiscoInfo(self):
2073 """
2074 Test getDiscoInfo calls getNodeInfo and returns some minimal info.
2075 """
2076 def cb(info):
2077 discoInfo = disco.DiscoInfo()
2078 for item in info:
2079 discoInfo.append(item)
2080 self.assertIn(('pubsub', 'service'), discoInfo.identities)
2081 self.assertIn(disco.NS_DISCO_ITEMS, discoInfo.features)
2082
2083 d = self.service.getDiscoInfo(JID('user@example.org/home'),
2084 JID('pubsub.example.org'), '')
2085 d.addCallback(cb)
2086 return d
2087
2088
2089 def test_getDiscoInfoNodeType(self):
2090 """
2091 Test getDiscoInfo with node type.
2092 """
2093 def cb(info):
2094 discoInfo = disco.DiscoInfo()
2095 for item in info:
2096 discoInfo.append(item)
2097 self.assertIn(('pubsub', 'collection'), discoInfo.identities)
2098
2099 def getInfo(requestor, target, nodeIdentifier):
2100 return defer.succeed({'type': 'collection',
2101 'meta-data': {}})
2102
2103 self.resource.getInfo = getInfo
2104 d = self.service.getDiscoInfo(JID('user@example.org/home'),
2105 JID('pubsub.example.org'), '')
2106 d.addCallback(cb)
2107 return d
2108
2109
2110 def test_getDiscoInfoMetaData(self):
2111 """
2112 Test getDiscoInfo with returned meta data.
2113 """
2114 def cb(info):
2115 discoInfo = disco.DiscoInfo()
2116 for item in info:
2117 discoInfo.append(item)
2118
2119 self.assertIn(('pubsub', 'leaf'), discoInfo.identities)
2120 self.assertIn(NS_PUBSUB_META_DATA, discoInfo.extensions)
2121 form = discoInfo.extensions[NS_PUBSUB_META_DATA]
2122 self.assertIn('pubsub#node_type', form.fields)
2123
2124 def getInfo(requestor, target, nodeIdentifier):
2125 metaData = [{'var': 'pubsub#persist_items',
2126 'label': 'Persist items to storage',
2127 'value': True}]
2128 return defer.succeed({'type': 'leaf', 'meta-data': metaData})
2129
2130 self.resource.getInfo = getInfo
2131 d = self.service.getDiscoInfo(JID('user@example.org/home'),
2132 JID('pubsub.example.org'), '')
2133 d.addCallback(cb)
2134 return d
2135
2136
2137 def test_getDiscoInfoResourceFeatures(self):
2138 """
2139 Test getDiscoInfo with the resource features.
2140 """
2141 def cb(info):
2142 discoInfo = disco.DiscoInfo()
2143 for item in info:
2144 discoInfo.append(item)
2145 self.assertIn('http://jabber.org/protocol/pubsub#publish',
2146 discoInfo.features)
2147
2148 self.resource.features = ['publish']
2149 d = self.service.getDiscoInfo(JID('user@example.org/home'),
2150 JID('pubsub.example.org'), '')
2151 d.addCallback(cb)
2152 return d
2153
2154
2155 def test_getDiscoInfoBadResponse(self):
2156 """
2157 If getInfo returns invalid response, it should be logged, then ignored.
2158 """
2159 def cb(info):
2160 self.assertEquals([], info)
2161 self.assertEqual(1, len(self.flushLoggedErrors(TypeError)))
2162
2163 def getInfo(requestor, target, nodeIdentifier):
2164 return defer.succeed('bad response')
2165
2166 self.resource.getInfo = getInfo
2167 d = self.service.getDiscoInfo(JID('user@example.org/home'),
2168 JID('pubsub.example.org'), 'test')
2169 d.addCallback(cb)
2170 return d
2171
2172
2173 def test_getDiscoInfoException(self):
2174 """
2175 If getInfo returns invalid response, it should be logged, then ignored.
2176 """
2177 def cb(info):
2178 self.assertEquals([], info)
2179 self.assertEqual(1, len(self.flushLoggedErrors(NotImplementedError)))
2180
2181 def getInfo(requestor, target, nodeIdentifier):
2182 return defer.fail(NotImplementedError())
2183
2184 self.resource.getInfo = getInfo
2185 d = self.service.getDiscoInfo(JID('user@example.org/home'),
2186 JID('pubsub.example.org'), 'test')
2187 d.addCallback(cb)
2188 return d
2189
2190
2191 def test_getDiscoItemsRoot(self):
2192 """
2193 Test getDiscoItems on the root node.
2194 """
2195 def getNodes(requestor, service, nodeIdentifier):
2196 return defer.succeed(['node1', 'node2'])
2197
2198 def cb(items):
2199 self.assertEqual(2, len(items))
2200 item1, item2 = items
2201
2202 self.assertEqual(JID('pubsub.example.org'), item1.entity)
2203 self.assertEqual('node1', item1.nodeIdentifier)
2204
2205 self.assertEqual(JID('pubsub.example.org'), item2.entity)
2206 self.assertEqual('node2', item2.nodeIdentifier)
2207
2208 self.resource.getNodes = getNodes
2209 d = self.service.getDiscoItems(JID('user@example.org/home'),
2210 JID('pubsub.example.org'),
2211 '')
2212 d.addCallback(cb)
2213 return d
2214
2215
2216 def test_getDiscoItemsRootHideNodes(self):
2217 """
2218 Test getDiscoItems on the root node.
2219 """
2220 def getNodes(requestor, service, nodeIdentifier):
2221 raise Exception("Unexpected call to getNodes")
2222
2223 def cb(items):
2224 self.assertEqual([], items)
2225
2226 self.service.hideNodes = True
2227 self.resource.getNodes = getNodes
2228 d = self.service.getDiscoItems(JID('user@example.org/home'),
2229 JID('pubsub.example.org'),
2230 '')
2231 d.addCallback(cb)
2232 return d
2233
2234
2235 def test_getDiscoItemsNonRoot(self):
2236 """
2237 Test getDiscoItems on a non-root node.
2238 """
2239 def getNodes(requestor, service, nodeIdentifier):
2240 return defer.succeed(['node1', 'node2'])
2241
2242 def cb(items):
2243 self.assertEqual(2, len(items))
2244
2245 self.resource.getNodes = getNodes
2246 d = self.service.getDiscoItems(JID('user@example.org/home'),
2247 JID('pubsub.example.org'),
2248 'test')
2249 d.addCallback(cb)
2250 return d
2251
2252
2253 def test_on_publish(self):
2254 """
2255 A publish request should result in L{PubSubService.publish} being
2256 called.
2257 """
2258
2259 xml = """
2260 <iq type='set' to='pubsub.example.org'
2261 from='user@example.org'>
2262 <pubsub xmlns='http://jabber.org/protocol/pubsub'>
2263 <publish node='test'/>
2264 </pubsub>
2265 </iq>
2266 """
2267
2268 def publish(request):
2269 return defer.succeed(None)
2270
2271 self.resource.publish = publish
2272 verify.verifyObject(iwokkel.IPubSubResource, self.resource)
2273 return self.handleRequest(xml)
2274
2275
2276 def test_on_subscribe(self):
2277 """
2278 A successful subscription should return the current subscription.
2279 """
2280
2281 xml = """
2282 <iq type='set' to='pubsub.example.org'
2283 from='user@example.org'>
2284 <pubsub xmlns='http://jabber.org/protocol/pubsub'>
2285 <subscribe node='test' jid='user@example.org/Home'/>
2286 </pubsub>
2287 </iq>
2288 """
2289
2290 def subscribe(request):
2291 return defer.succeed(pubsub.Subscription(request.nodeIdentifier,
2292 request.subscriber,
2293 'subscribed'))
2294
2295 def cb(element):
2296 self.assertEqual('pubsub', element.name)
2297 self.assertEqual(NS_PUBSUB, element.uri)
2298 subscription = element.subscription
2299 self.assertEqual(NS_PUBSUB, subscription.uri)
2300 self.assertEqual('test', subscription['node'])
2301 self.assertEqual('user@example.org/Home', subscription['jid'])
2302 self.assertEqual('subscribed', subscription['subscription'])
2303
2304 self.resource.subscribe = subscribe
2305 verify.verifyObject(iwokkel.IPubSubResource, self.resource)
2306 d = self.handleRequest(xml)
2307 d.addCallback(cb)
2308 return d
2309
2310
2311 def test_on_subscribeEmptyNode(self):
2312 """
2313 A successful subscription on root node should return no node attribute.
2314 """
2315
2316 xml = """
2317 <iq type='set' to='pubsub.example.org'
2318 from='user@example.org'>
2319 <pubsub xmlns='http://jabber.org/protocol/pubsub'>
2320 <subscribe jid='user@example.org/Home'/>
2321 </pubsub>
2322 </iq>
2323 """
2324
2325 def subscribe(request):
2326 return defer.succeed(pubsub.Subscription(request.nodeIdentifier,
2327 request.subscriber,
2328 'subscribed'))
2329
2330 def cb(element):
2331 self.assertFalse(element.subscription.hasAttribute('node'))
2332
2333 self.resource.subscribe = subscribe
2334 verify.verifyObject(iwokkel.IPubSubResource, self.resource)
2335 d = self.handleRequest(xml)
2336 d.addCallback(cb)
2337 return d
2338
2339
2340 def test_on_subscribeSubscriptionIdentifier(self):
2341 """
2342 If a subscription returns a subid, this should be available.
2343 """
2344
2345 xml = """
2346 <iq type='set' to='pubsub.example.org'
2347 from='user@example.org'>
2348 <pubsub xmlns='http://jabber.org/protocol/pubsub'>
2349 <subscribe node='test' jid='user@example.org/Home'/>
2350 </pubsub>
2351 </iq>
2352 """
2353
2354 def subscribe(request):
2355 subscription = pubsub.Subscription(request.nodeIdentifier,
2356 request.subscriber,
2357 'subscribed',
2358 subscriptionIdentifier='1234')
2359 return defer.succeed(subscription)
2360
2361 def cb(element):
2362 self.assertEqual('1234', element.subscription.getAttribute('subid'))
2363
2364 self.resource.subscribe = subscribe
2365 verify.verifyObject(iwokkel.IPubSubResource, self.resource)
2366 d = self.handleRequest(xml)
2367 d.addCallback(cb)
2368 return d
2369
2370
2371 def test_on_unsubscribe(self):
2372 """
2373 A successful unsubscription should return an empty response.
2374 """
2375
2376 xml = """
2377 <iq type='set' to='pubsub.example.org'
2378 from='user@example.org'>
2379 <pubsub xmlns='http://jabber.org/protocol/pubsub'>
2380 <unsubscribe node='test' jid='user@example.org/Home'/>
2381 </pubsub>
2382 </iq>
2383 """
2384
2385 def unsubscribe(request):
2386 return defer.succeed(None)
2387
2388 def cb(element):
2389 self.assertIdentical(None, element)
2390
2391 self.resource.unsubscribe = unsubscribe
2392 verify.verifyObject(iwokkel.IPubSubResource, self.resource)
2393 d = self.handleRequest(xml)
2394 d.addCallback(cb)
2395 return d
2396
2397
2398 def test_on_unsubscribeSubscriptionIdentifier(self):
2399 """
2400 A successful unsubscription with subid should return an empty response.
2401 """
2402
2403 xml = """
2404 <iq type='set' to='pubsub.example.org'
2405 from='user@example.org'>
2406 <pubsub xmlns='http://jabber.org/protocol/pubsub'>
2407 <unsubscribe node='test' jid='user@example.org/Home' subid='1234'/>
2408 </pubsub>
2409 </iq>
2410 """
2411
2412 def unsubscribe(request):
2413 self.assertEqual('1234', request.subscriptionIdentifier)
2414 return defer.succeed(None)
2415
2416 def cb(element):
2417 self.assertIdentical(None, element)
2418
2419 self.resource.unsubscribe = unsubscribe
2420 verify.verifyObject(iwokkel.IPubSubResource, self.resource)
2421 d = self.handleRequest(xml)
2422 d.addCallback(cb)
2423 return d
2424
2425
2426 def test_on_optionsGet(self):
2427 """
2428 Getting subscription options is not supported.
2429 """
2430
2431 xml = """
2432 <iq type='get' to='pubsub.example.org'
2433 from='user@example.org'>
2434 <pubsub xmlns='http://jabber.org/protocol/pubsub'>
2435 <options node='test' jid='user@example.org/Home'/>
2436 </pubsub>
2437 </iq>
2438 """
2439
2440 def cb(result):
2441 self.assertEquals('feature-not-implemented', result.condition)
2442 self.assertEquals('unsupported', result.appCondition.name)
2443 self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
2444
2445 d = self.handleRequest(xml)
2446 self.assertFailure(d, error.StanzaError)
2447 d.addCallback(cb)
2448 return d
2449
2450
2451 def test_on_optionsSet(self):
2452 """
2453 Setting subscription options is not supported.
2454 """
2455
2456 xml = """
2457 <iq type='set' to='pubsub.example.org'
2458 from='user@example.org'>
2459 <pubsub xmlns='http://jabber.org/protocol/pubsub'>
2460 <options node='test' jid='user@example.org/Home'>
2461 <x xmlns='jabber:x:data' type='submit'>
2462 <field var='FORM_TYPE' type='hidden'>
2463 <value>http://jabber.org/protocol/pubsub#subscribe_options</value>
2464 </field>
2465 <field var='pubsub#deliver'><value>1</value></field>
2466 </x>
2467 </options>
2468 </pubsub>
2469 </iq>
2470 """
2471
2472 def cb(result):
2473 self.assertEquals('feature-not-implemented', result.condition)
2474 self.assertEquals('unsupported', result.appCondition.name)
2475 self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
2476
2477 d = self.handleRequest(xml)
2478 self.assertFailure(d, error.StanzaError)
2479 d.addCallback(cb)
2480 return d
2481
2482
2483 def test_on_subscriptions(self):
2484 """
2485 A subscriptions request should result in
2486 L{PubSubService.subscriptions} being called and the result prepared
2487 for the response.
2488 """
2489
2490 xml = """
2491 <iq type='get' to='pubsub.example.org'
2492 from='user@example.org'>
2493 <pubsub xmlns='http://jabber.org/protocol/pubsub'>
2494 <subscriptions/>
2495 </pubsub>
2496 </iq>
2497 """
2498
2499 def subscriptions(request):
2500 subscription = pubsub.Subscription('test', JID('user@example.org'),
2501 'subscribed')
2502 return defer.succeed([subscription])
2503
2504 def cb(element):
2505 self.assertEqual('pubsub', element.name)
2506 self.assertEqual(NS_PUBSUB, element.uri)
2507 self.assertEqual(NS_PUBSUB, element.subscriptions.uri)
2508 children = list(element.subscriptions.elements())
2509 self.assertEqual(1, len(children))
2510 subscription = children[0]
2511 self.assertEqual('subscription', subscription.name)
2512 self.assertEqual(NS_PUBSUB, subscription.uri, NS_PUBSUB)
2513 self.assertEqual('user@example.org', subscription['jid'])
2514 self.assertEqual('test', subscription['node'])
2515 self.assertEqual('subscribed', subscription['subscription'])
2516
2517 self.resource.subscriptions = subscriptions
2518 verify.verifyObject(iwokkel.IPubSubResource, self.resource)
2519 d = self.handleRequest(xml)
2520 d.addCallback(cb)
2521 return d
2522
2523
2524 def test_on_subscriptionsWithSubscriptionIdentifier(self):
2525 """
2526 A subscriptions request response should include subids, if set.
2527 """
2528
2529 xml = """
2530 <iq type='get' to='pubsub.example.org'
2531 from='user@example.org'>
2532 <pubsub xmlns='http://jabber.org/protocol/pubsub'>
2533 <subscriptions/>
2534 </pubsub>
2535 </iq>
2536 """
2537
2538 def subscriptions(request):
2539 subscription = pubsub.Subscription('test', JID('user@example.org'),
2540 'subscribed',
2541 subscriptionIdentifier='1234')
2542 return defer.succeed([subscription])
2543
2544 def cb(element):
2545 subscription = element.subscriptions.subscription
2546 self.assertEqual('1234', subscription['subid'])
2547
2548 self.resource.subscriptions = subscriptions
2549 verify.verifyObject(iwokkel.IPubSubResource, self.resource)
2550 d = self.handleRequest(xml)
2551 d.addCallback(cb)
2552 return d
2553
2554
2555 def test_on_affiliations(self):
2556 """
2557 A subscriptions request should result in
2558 L{PubSubService.affiliations} being called and the result prepared
2559 for the response.
2560 """
2561
2562 xml = """
2563 <iq type='get' to='pubsub.example.org'
2564 from='user@example.org'>
2565 <pubsub xmlns='http://jabber.org/protocol/pubsub'>
2566 <affiliations/>
2567 </pubsub>
2568 </iq>
2569 """
2570
2571 def affiliations(request):
2572 affiliation = ('test', 'owner')
2573 return defer.succeed([affiliation])
2574
2575 def cb(element):
2576 self.assertEqual('pubsub', element.name)
2577 self.assertEqual(NS_PUBSUB, element.uri)
2578 self.assertEqual(NS_PUBSUB, element.affiliations.uri)
2579 children = list(element.affiliations.elements())
2580 self.assertEqual(1, len(children))
2581 affiliation = children[0]
2582 self.assertEqual('affiliation', affiliation.name)
2583 self.assertEqual(NS_PUBSUB, affiliation.uri)
2584 self.assertEqual('test', affiliation['node'])
2585 self.assertEqual('owner', affiliation['affiliation'])
2586
2587 self.resource.affiliations = affiliations
2588 verify.verifyObject(iwokkel.IPubSubResource, self.resource)
2589 d = self.handleRequest(xml)
2590 d.addCallback(cb)
2591 return d
2592
2593
2594 def test_on_create(self):
2595 """
2596 Replies to create node requests don't return the created node.
2597 """
2598
2599 xml = """
2600 <iq type='set' to='pubsub.example.org'
2601 from='user@example.org'>
2602 <pubsub xmlns='http://jabber.org/protocol/pubsub'>
2603 <create node='mynode'/>
2604 </pubsub>
2605 </iq>
2606 """
2607
2608 def create(request):
2609 return defer.succeed(request.nodeIdentifier)
2610
2611 def cb(element):
2612 self.assertIdentical(None, element)
2613
2614 self.resource.create = create
2615 verify.verifyObject(iwokkel.IPubSubResource, self.resource)
2616 d = self.handleRequest(xml)
2617 d.addCallback(cb)
2618 return d
2619
2620
2621 def test_on_createChanged(self):
2622 """
2623 Replies to create node requests return the created node if changed.
2624 """
2625
2626 xml = """
2627 <iq type='set' to='pubsub.example.org'
2628 from='user@example.org'>
2629 <pubsub xmlns='http://jabber.org/protocol/pubsub'>
2630 <create node='mynode'/>
2631 </pubsub>
2632 </iq>
2633 """
2634
2635 def create(request):
2636 return defer.succeed(u'myrenamednode')
2637
2638 def cb(element):
2639 self.assertEqual('pubsub', element.name)
2640 self.assertEqual(NS_PUBSUB, element.uri)
2641 self.assertEqual(NS_PUBSUB, element.create.uri)
2642 self.assertEqual(u'myrenamednode',
2643 element.create.getAttribute('node'))
2644
2645 self.resource.create = create
2646 verify.verifyObject(iwokkel.IPubSubResource, self.resource)
2647 d = self.handleRequest(xml)
2648 d.addCallback(cb)
2649 return d
2650
2651
2652 def test_on_createInstant(self):
2653 """
2654 Replies to create instant node requests return the created node.
2655 """
2656
2657 xml = """
2658 <iq type='set' to='pubsub.example.org'
2659 from='user@example.org'>
2660 <pubsub xmlns='http://jabber.org/protocol/pubsub'>
2661 <create/>
2662 </pubsub>
2663 </iq>
2664 """
2665
2666 def create(request):
2667 return defer.succeed(u'random')
2668
2669 def cb(element):
2670 self.assertEqual('pubsub', element.name)
2671 self.assertEqual(NS_PUBSUB, element.uri)
2672 self.assertEqual(NS_PUBSUB, element.create.uri)
2673 self.assertEqual(u'random', element.create.getAttribute('node'))
2674
2675 self.resource.create = create
2676 verify.verifyObject(iwokkel.IPubSubResource, self.resource)
2677 d = self.handleRequest(xml)
2678 d.addCallback(cb)
2679 return d
2680
2681
2682 def test_on_createWithConfig(self):
2683 """
2684 On a node create with configuration request the Data Form is parsed and
2685 L{PubSubResource.create} is called with the passed options.
2686 """
2687
2688 xml = """
2689 <iq type='set' to='pubsub.example.org'
2690 from='user@example.org'>
2691 <pubsub xmlns='http://jabber.org/protocol/pubsub'>
2692 <create node='mynode'/>
2693 <configure>
2694 <x xmlns='jabber:x:data' type='submit'>
2695 <field var='FORM_TYPE' type='hidden'>
2696 <value>http://jabber.org/protocol/pubsub#node_config</value>
2697 </field>
2698 <field var='pubsub#deliver_payloads'><value>0</value></field>
2699 <field var='pubsub#persist_items'><value>1</value></field>
2700 </x>
2701 </configure>
2702 </pubsub>
2703 </iq>
2704 """
2705
2706 def getConfigurationOptions():
2707 return {
2708 "pubsub#persist_items":
2709 {"type": "boolean",
2710 "label": "Persist items to storage"},
2711 "pubsub#deliver_payloads":
2712 {"type": "boolean",
2713 "label": "Deliver payloads with event notifications"}
2714 }
2715
2716 def create(request):
2717 self.assertEqual({'pubsub#deliver_payloads': False,
2718 'pubsub#persist_items': True},
2719 request.options.getValues())
2720 return defer.succeed(None)
2721
2722 self.resource.getConfigurationOptions = getConfigurationOptions
2723 self.resource.create = create
2724 verify.verifyObject(iwokkel.IPubSubResource, self.resource)
2725 return self.handleRequest(xml)
2726
2727
2728 def test_on_default(self):
2729 """
2730 A default request returns default options filtered by available fields.
2731 """
2732
2733 xml = """
2734 <iq type='get' to='pubsub.example.org'
2735 from='user@example.org'>
2736 <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
2737 <default/>
2738 </pubsub>
2739 </iq>
2740 """
2741 fieldDefs = {
2742 "pubsub#persist_items":
2743 {"type": "boolean",
2744 "label": "Persist items to storage"},
2745 "pubsub#deliver_payloads":
2746 {"type": "boolean",
2747 "label": "Deliver payloads with event notifications"}
2748 }
2749
2750 def getConfigurationOptions():
2751 return fieldDefs
2752
2753 def default(request):
2754 return defer.succeed({'pubsub#persist_items': 'false',
2755 'x-myfield': '1'})
2756
2757 def cb(element):
2758 self.assertEquals('pubsub', element.name)
2759 self.assertEquals(NS_PUBSUB_OWNER, element.uri)
2760 self.assertEquals(NS_PUBSUB_OWNER, element.default.uri)
2761 form = data_form.Form.fromElement(element.default.x)
2762 self.assertEquals(NS_PUBSUB_NODE_CONFIG, form.formNamespace)
2763 form.typeCheck(fieldDefs)
2764 self.assertIn('pubsub#persist_items', form.fields)
2765 self.assertFalse(form.fields['pubsub#persist_items'].value)
2766 self.assertNotIn('x-myfield', form.fields)
2767
2768 self.resource.getConfigurationOptions = getConfigurationOptions
2769 self.resource.default = default
2770 verify.verifyObject(iwokkel.IPubSubResource, self.resource)
2771 d = self.handleRequest(xml)
2772 d.addCallback(cb)
2773 return d
2774
2775
2776 def test_on_defaultUnknownNodeType(self):
2777 """
2778 Unknown node types yield non-acceptable.
2779
2780 Both C{getConfigurationOptions} and C{default} must not be called.
2781 """
2782
2783 xml = """
2784 <iq type='get' to='pubsub.example.org'
2785 from='user@example.org'>
2786 <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
2787 <default>
2788 <x xmlns='jabber:x:data' type='submit'>
2789 <field var='FORM_TYPE' type='hidden'>
2790 <value>http://jabber.org/protocol/pubsub#node_config</value>
2791 </field>
2792 <field var='pubsub#node_type'>
2793 <value>unknown</value>
2794 </field>
2795 </x>
2796 </default>
2797
2798 </pubsub>
2799 </iq>
2800 """
2801
2802 def getConfigurationOptions():
2803 self.fail("Unexpected call to getConfigurationOptions")
2804
2805 def default(request):
2806 self.fail("Unexpected call to default")
2807
2808 def cb(result):
2809 self.assertEquals('not-acceptable', result.condition)
2810
2811 self.resource.getConfigurationOptions = getConfigurationOptions
2812 self.resource.default = default
2813 verify.verifyObject(iwokkel.IPubSubResource, self.resource)
2814 d = self.handleRequest(xml)
2815 self.assertFailure(d, error.StanzaError)
2816 d.addCallback(cb)
2817 return d
2818
2819
2820 def test_on_configureGet(self):
2821 """
2822 On a node configuration get
2823 requestL{PubSubResource.configureGet} is called and results in a
2824 data form with the configuration.
2825 """
2826
2827 xml = """
2828 <iq type='get' to='pubsub.example.org'
2829 from='user@example.org'>
2830 <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
2831 <configure node='test'/>
2832 </pubsub>
2833 </iq>
2834 """
2835
2836 def getConfigurationOptions():
2837 return {
2838 "pubsub#persist_items":
2839 {"type": "boolean",
2840 "label": "Persist items to storage"},
2841 "pubsub#deliver_payloads":
2842 {"type": "boolean",
2843 "label": "Deliver payloads with event notifications"},
2844 "pubsub#owner":
2845 {"type": "jid-single",
2846 "label": "Owner of the node"}
2847 }
2848
2849 def configureGet(request):
2850 return defer.succeed({'pubsub#deliver_payloads': '0',
2851 'pubsub#persist_items': '1',
2852 'pubsub#owner': JID('user@example.org'),
2853 'x-myfield': 'a'})
2854
2855 def cb(element):
2856 self.assertEqual('pubsub', element.name)
2857 self.assertEqual(NS_PUBSUB_OWNER, element.uri)
2858 self.assertEqual(NS_PUBSUB_OWNER, element.configure.uri)
2859 form = data_form.Form.fromElement(element.configure.x)
2860 self.assertEqual(NS_PUBSUB_NODE_CONFIG, form.formNamespace)
2861 fields = form.fields
2862
2863 self.assertIn('pubsub#deliver_payloads', fields)
2864 field = fields['pubsub#deliver_payloads']
2865 self.assertEqual('boolean', field.fieldType)
2866 field.typeCheck()
2867 self.assertEqual(False, field.value)
2868
2869 self.assertIn('pubsub#persist_items', fields)
2870 field = fields['pubsub#persist_items']
2871 self.assertEqual('boolean', field.fieldType)
2872 field.typeCheck()
2873 self.assertEqual(True, field.value)
2874
2875 self.assertIn('pubsub#owner', fields)
2876 field = fields['pubsub#owner']
2877 self.assertEqual('jid-single', field.fieldType)
2878 field.typeCheck()
2879 self.assertEqual(JID('user@example.org'), field.value)
2880
2881 self.assertNotIn('x-myfield', fields)
2882
2883 self.resource.getConfigurationOptions = getConfigurationOptions
2884 self.resource.configureGet = configureGet
2885 verify.verifyObject(iwokkel.IPubSubResource, self.resource)
2886 d = self.handleRequest(xml)
2887 d.addCallback(cb)
2888 return d
2889
2890
2891 def test_on_configureSet(self):
2892 """
2893 On a node configuration set request the Data Form is parsed and
2894 L{PubSubResource.configureSet} is called with the passed options.
2895 """
2896
2897 xml = """
2898 <iq type='set' to='pubsub.example.org'
2899 from='user@example.org'>
2900 <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
2901 <configure node='test'>
2902 <x xmlns='jabber:x:data' type='submit'>
2903 <field var='FORM_TYPE' type='hidden'>
2904 <value>http://jabber.org/protocol/pubsub#node_config</value>
2905 </field>
2906 <field var='pubsub#deliver_payloads'><value>0</value></field>
2907 <field var='pubsub#persist_items'><value>1</value></field>
2908 </x>
2909 </configure>
2910 </pubsub>
2911 </iq>
2912 """
2913
2914 def getConfigurationOptions():
2915 return {
2916 "pubsub#persist_items":
2917 {"type": "boolean",
2918 "label": "Persist items to storage"},
2919 "pubsub#deliver_payloads":
2920 {"type": "boolean",
2921 "label": "Deliver payloads with event notifications"}
2922 }
2923
2924 def configureSet(request):
2925 self.assertEqual({'pubsub#deliver_payloads': False,
2926 'pubsub#persist_items': True},
2927 request.options.getValues())
2928 return defer.succeed(None)
2929
2930 self.resource.getConfigurationOptions = getConfigurationOptions
2931 self.resource.configureSet = configureSet
2932 verify.verifyObject(iwokkel.IPubSubResource, self.resource)
2933 return self.handleRequest(xml)
2934
2935
2936 def test_on_configureSetCancel(self):
2937 """
2938 The node configuration is cancelled,
2939 L{PubSubResource.configureSet} not called.
2940 """
2941
2942 xml = """
2943 <iq type='set' to='pubsub.example.org'
2944 from='user@example.org'>
2945 <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
2946 <configure node='test'>
2947 <x xmlns='jabber:x:data' type='cancel'>
2948 <field var='FORM_TYPE' type='hidden'>
2949 <value>http://jabber.org/protocol/pubsub#node_config</value>
2950 </field>
2951 </x>
2952 </configure>
2953 </pubsub>
2954 </iq>
2955 """
2956
2957 def configureSet(request):
2958 self.fail("Unexpected call to setConfiguration")
2959
2960 self.resource.configureSet = configureSet
2961 verify.verifyObject(iwokkel.IPubSubResource, self.resource)
2962 return self.handleRequest(xml)
2963
2964
2965 def test_on_configureSetIgnoreUnknown(self):
2966 """
2967 On a node configuration set request unknown fields should be ignored.
2968 """
2969
2970 xml = """
2971 <iq type='set' to='pubsub.example.org'
2972 from='user@example.org'>
2973 <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
2974 <configure node='test'>
2975 <x xmlns='jabber:x:data' type='submit'>
2976 <field var='FORM_TYPE' type='hidden'>
2977 <value>http://jabber.org/protocol/pubsub#node_config</value>
2978 </field>
2979 <field var='pubsub#deliver_payloads'><value>0</value></field>
2980 <field var='x-myfield'><value>1</value></field>
2981 </x>
2982 </configure>
2983 </pubsub>
2984 </iq>
2985 """
2986
2987 def getConfigurationOptions():
2988 return {
2989 "pubsub#persist_items":
2990 {"type": "boolean",
2991 "label": "Persist items to storage"},
2992 "pubsub#deliver_payloads":
2993 {"type": "boolean",
2994 "label": "Deliver payloads with event notifications"}
2995 }
2996
2997 def configureSet(request):
2998 self.assertEquals(['pubsub#deliver_payloads'],
2999 request.options.keys())
3000
3001 self.resource.getConfigurationOptions = getConfigurationOptions
3002 self.resource.configureSet = configureSet
3003 verify.verifyObject(iwokkel.IPubSubResource, self.resource)
3004 return self.handleRequest(xml)
3005
3006
3007 def test_on_configureSetBadFormType(self):
3008 """
3009 On a node configuration set request unknown fields should be ignored.
3010 """
3011
3012 xml = """
3013 <iq type='set' to='pubsub.example.org'
3014 from='user@example.org'>
3015 <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
3016 <configure node='test'>
3017 <x xmlns='jabber:x:data' type='result'>
3018 <field var='FORM_TYPE' type='hidden'>
3019 <value>http://jabber.org/protocol/pubsub#node_config</value>
3020 </field>
3021 <field var='pubsub#deliver_payloads'><value>0</value></field>
3022 <field var='x-myfield'><value>1</value></field>
3023 </x>
3024 </configure>
3025 </pubsub>
3026 </iq>
3027 """
3028
3029 def cb(result):
3030 self.assertEquals('bad-request', result.condition)
3031 self.assertEqual("Unexpected form type 'result'", result.text)
3032
3033 d = self.handleRequest(xml)
3034 self.assertFailure(d, error.StanzaError)
3035 d.addCallback(cb)
3036 return d
3037
3038
3039 def test_on_items(self):
3040 """
3041 On a items request, return all items for the given node.
3042 """
3043 xml = """
3044 <iq type='get' to='pubsub.example.org'
3045 from='user@example.org'>
3046 <pubsub xmlns='http://jabber.org/protocol/pubsub'>
3047 <items node='test'/>
3048 </pubsub>
3049 </iq>
3050 """
3051
3052 def items(request):
3053 return defer.succeed([pubsub.Item('current')])
3054
3055 def cb(element):
3056 self.assertEqual(NS_PUBSUB, element.uri)
3057 self.assertEqual(NS_PUBSUB, element.items.uri)
3058 self.assertEqual(1, len(element.items.children))
3059 item = element.items.children[-1]
3060 self.assertTrue(domish.IElement.providedBy(item))
3061 self.assertEqual('item', item.name)
3062 self.assertEqual(NS_PUBSUB, item.uri)
3063 self.assertEqual('current', item['id'])
3064
3065 self.resource.items = items
3066 verify.verifyObject(iwokkel.IPubSubResource, self.resource)
3067 d = self.handleRequest(xml)
3068 d.addCallback(cb)
3069 return d
3070
3071
3072 def test_on_retract(self):
3073 """
3074 A retract request should result in L{PubSubResource.retract}
3075 being called.
3076 """
3077
3078 xml = """
3079 <iq type='set' to='pubsub.example.org'
3080 from='user@example.org'>
3081 <pubsub xmlns='http://jabber.org/protocol/pubsub'>
3082 <retract node='test'>
3083 <item id='item1'/>
3084 <item id='item2'/>
3085 </retract>
3086 </pubsub>
3087 </iq>
3088 """
3089
3090 def retract(request):
3091 return defer.succeed(None)
3092
3093 self.resource.retract = retract
3094 verify.verifyObject(iwokkel.IPubSubResource, self.resource)
3095 return self.handleRequest(xml)
3096
3097
3098 def test_on_purge(self):
3099 """
3100 A purge request should result in L{PubSubResource.purge} being
3101 called.
3102 """
3103
3104 xml = """
3105 <iq type='set' to='pubsub.example.org'
3106 from='user@example.org'>
3107 <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
3108 <purge node='test'/>
3109 </pubsub>
3110 </iq>
3111 """
3112
3113 def purge(request):
3114 return defer.succeed(None)
3115
3116 self.resource.purge = purge
3117 verify.verifyObject(iwokkel.IPubSubResource, self.resource)
3118 return self.handleRequest(xml)
3119
3120
3121 def test_on_delete(self):
3122 """
3123 A delete request should result in L{PubSubResource.delete} being
3124 called.
3125 """
3126
3127 xml = """
3128 <iq type='set' to='pubsub.example.org'
3129 from='user@example.org'>
3130 <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
3131 <delete node='test'/>
3132 </pubsub>
3133 </iq>
3134 """
3135
3136 def delete(request):
3137 return defer.succeed(None)
3138
3139 self.resource.delete = delete
3140 verify.verifyObject(iwokkel.IPubSubResource, self.resource)
3141 return self.handleRequest(xml)
3142
3143
3144 def test_notifyPublish(self):
3145 """
3146 Publish notifications are sent to the subscribers.
3147 """
3148 subscriber = JID('user@example.org')
3149 subscriptions = [pubsub.Subscription('test', subscriber, 'subscribed')]
3150 items = [pubsub.Item('current')]
3151 notifications = [(subscriber, subscriptions, items)]
3152 self.service.notifyPublish(JID('pubsub.example.org'), 'test',
3153 notifications)
3154 message = self.stub.output[-1]
3155
3156 self.assertEquals('message', message.name)
3157 self.assertIdentical(None, message.uri)
3158 self.assertEquals('user@example.org', message['to'])
3159 self.assertEquals('pubsub.example.org', message['from'])
3160 self.assertTrue(message.event)
3161 self.assertEquals(NS_PUBSUB_EVENT, message.event.uri)
3162 self.assertTrue(message.event.items)
3163 self.assertEquals(NS_PUBSUB_EVENT, message.event.items.uri)
3164 self.assertTrue(message.event.items.hasAttribute('node'))
3165 self.assertEquals('test', message.event.items['node'])
3166 itemElements = list(domish.generateElementsQNamed(
3167 message.event.items.children, 'item', NS_PUBSUB_EVENT))
3168 self.assertEquals(1, len(itemElements))
3169 self.assertEquals('current', itemElements[0].getAttribute('id'))
3170
3171
3172 def test_notifyPublishCollection(self):
3173 """
3174 Publish notifications are sent to the subscribers of collections.
3175
3176 The node the item was published to is on the C{items} element, while
3177 the subscribed-to node is in the C{'Collections'} SHIM header.
3178 """
3179 subscriber = JID('user@example.org')
3180 subscriptions = [pubsub.Subscription('', subscriber, 'subscribed')]
3181 items = [pubsub.Item('current')]
3182 notifications = [(subscriber, subscriptions, items)]
3183 self.service.notifyPublish(JID('pubsub.example.org'), 'test',
3184 notifications)
3185 message = self.stub.output[-1]
3186
3187 self.assertTrue(message.event.items.hasAttribute('node'))
3188 self.assertEquals('test', message.event.items['node'])
3189 headers = shim.extractHeaders(message)
3190 self.assertIn('Collection', headers)
3191 self.assertIn('', headers['Collection'])
3192
3193
3194 def test_notifyDelete(self):
3195 """
3196 Subscribers should be sent a delete notification.
3197 """
3198 subscriptions = [JID('user@example.org')]
3199 self.service.notifyDelete(JID('pubsub.example.org'), 'test',
3200 subscriptions)
3201 message = self.stub.output[-1]
3202
3203 self.assertEquals('message', message.name)
3204 self.assertIdentical(None, message.uri)
3205 self.assertEquals('user@example.org', message['to'])
3206 self.assertEquals('pubsub.example.org', message['from'])
3207 self.assertTrue(message.event)
3208 self.assertEqual(NS_PUBSUB_EVENT, message.event.uri)
3209 self.assertTrue(message.event.delete)
3210 self.assertEqual(NS_PUBSUB_EVENT, message.event.delete.uri)
3211 self.assertTrue(message.event.delete.hasAttribute('node'))
3212 self.assertEqual('test', message.event.delete['node'])
3213
3214
3215 def test_notifyDeleteRedirect(self):
3216 """
3217 Subscribers should be sent a delete notification with redirect.
3218 """
3219 redirectURI = 'xmpp:pubsub.example.org?;node=test2'
3220 subscriptions = [JID('user@example.org')]
3221 self.service.notifyDelete(JID('pubsub.example.org'), 'test',
3222 subscriptions, redirectURI)
3223 message = self.stub.output[-1]
3224
3225 self.assertEquals('message', message.name)
3226 self.assertIdentical(None, message.uri)
3227 self.assertEquals('user@example.org', message['to'])
3228 self.assertEquals('pubsub.example.org', message['from'])
3229 self.assertTrue(message.event)
3230 self.assertEqual(NS_PUBSUB_EVENT, message.event.uri)
3231 self.assertTrue(message.event.delete)
3232 self.assertEqual(NS_PUBSUB_EVENT, message.event.delete.uri)
3233 self.assertTrue(message.event.delete.hasAttribute('node'))
3234 self.assertEqual('test', message.event.delete['node'])
3235 self.assertTrue(message.event.delete.redirect)
3236 self.assertEqual(NS_PUBSUB_EVENT, message.event.delete.redirect.uri)
3237 self.assertTrue(message.event.delete.redirect.hasAttribute('uri'))
3238 self.assertEqual(redirectURI, message.event.delete.redirect['uri'])
3239
3240
3241 def test_on_subscriptionsGet(self):
3242 """
3243 Getting subscription options is not supported.
3244 """
3245
3246 xml = """
3247 <iq type='get' to='pubsub.example.org'
3248 from='user@example.org'>
3249 <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
3250 <subscriptions/>
3251 </pubsub>
3252 </iq>
3253 """
3254
3255 def cb(result):
3256 self.assertEquals('feature-not-implemented', result.condition)
3257 self.assertEquals('unsupported', result.appCondition.name)
3258 self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
3259 self.assertEquals('manage-subscriptions',
3260 result.appCondition['feature'])
3261
3262 d = self.handleRequest(xml)
3263 self.assertFailure(d, error.StanzaError)
3264 d.addCallback(cb)
3265 return d
3266
3267
3268 def test_on_subscriptionsSet(self):
3269 """
3270 Setting subscription options is not supported.
3271 """
3272
3273 xml = """
3274 <iq type='set' to='pubsub.example.org'
3275 from='user@example.org'>
3276 <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
3277 <subscriptions/>
3278 </pubsub>
3279 </iq>
3280 """
3281
3282 def cb(result):
3283 self.assertEquals('feature-not-implemented', result.condition)
3284 self.assertEquals('unsupported', result.appCondition.name)
3285 self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
3286 self.assertEquals('manage-subscriptions',
3287 result.appCondition['feature'])
3288
3289 d = self.handleRequest(xml)
3290 self.assertFailure(d, error.StanzaError)
3291 d.addCallback(cb)
3292 return d
3293
3294
3295 def test_on_affiliationsGet(self):
3296 """
3297 Getting node affiliations should have.
3298 """
3299
3300 xml = """
3301 <iq type='get' to='pubsub.example.org'
3302 from='user@example.org'>
3303 <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
3304 <affiliations node='test'/>
3305 </pubsub>
3306 </iq>
3307 """
3308
3309 def affiliationsGet(request):
3310 self.assertEquals('test', request.nodeIdentifier)
3311 return defer.succeed({JID('user@example.org'): 'owner'})
3312
3313 def cb(element):
3314 self.assertEquals(u'pubsub', element.name)
3315 self.assertEquals(NS_PUBSUB_OWNER, element.uri)
3316 self.assertEquals(NS_PUBSUB_OWNER, element.affiliations.uri)
3317 self.assertEquals(u'test', element.affiliations[u'node'])
3318 children = list(element.affiliations.elements())
3319 self.assertEquals(1, len(children))
3320 affiliation = children[0]
3321 self.assertEquals(u'affiliation', affiliation.name)
3322 self.assertEquals(NS_PUBSUB_OWNER, affiliation.uri)
3323 self.assertEquals(u'user@example.org', affiliation[u'jid'])
3324 self.assertEquals(u'owner', affiliation[u'affiliation'])
3325
3326 self.resource.affiliationsGet = affiliationsGet
3327 verify.verifyObject(iwokkel.IPubSubResource, self.resource)
3328 d = self.handleRequest(xml)
3329 d.addCallback(cb)
3330 return d
3331
3332
3333 def test_on_affiliationsGetEmptyNode(self):
3334 """
3335 Getting node affiliations without node should assume empty node.
3336 """
3337
3338 xml = """
3339 <iq type='get' to='pubsub.example.org'
3340 from='user@example.org'>
3341 <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
3342 <affiliations/>
3343 </pubsub>
3344 </iq>
3345 """
3346
3347 def affiliationsGet(request):
3348 self.assertEqual('', request.nodeIdentifier)
3349 return defer.succeed({})
3350
3351 def cb(element):
3352 self.assertFalse(element.affiliations.hasAttribute(u'node'))
3353
3354 self.resource.affiliationsGet = affiliationsGet
3355 verify.verifyObject(iwokkel.IPubSubResource, self.resource)
3356 d = self.handleRequest(xml)
3357 d.addCallback(cb)
3358 return d
3359
3360
3361 def test_on_affiliationsSet(self):
3362 """
3363 Setting node affiliations has the affiliations to be modified.
3364 """
3365
3366 xml = """
3367 <iq type='set' to='pubsub.example.org'
3368 from='user@example.org'>
3369 <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
3370 <affiliations node='test'>
3371 <affiliation jid='other@example.org' affiliation='publisher'/>
3372 </affiliations>
3373 </pubsub>
3374 </iq>
3375 """
3376
3377 def affiliationsSet(request):
3378 self.assertEquals(u'test', request.nodeIdentifier)
3379 otherJID = JID(u'other@example.org')
3380 self.assertIn(otherJID, request.affiliations)
3381 self.assertEquals(u'publisher', request.affiliations[otherJID])
3382
3383 self.resource.affiliationsSet = affiliationsSet
3384 return self.handleRequest(xml)
3385
3386
3387 def test_on_affiliationsSetBareJID(self):
3388 """
3389 Affiliations are always on the bare JID.
3390 """
3391
3392 xml = """
3393 <iq type='set' to='pubsub.example.org'
3394 from='user@example.org'>
3395 <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
3396 <affiliations node='test'>
3397 <affiliation jid='other@example.org/Home'
3398 affiliation='publisher'/>
3399 </affiliations>
3400 </pubsub>
3401 </iq>
3402 """
3403
3404 def affiliationsSet(request):
3405 otherJID = JID(u'other@example.org')
3406 self.assertIn(otherJID, request.affiliations)
3407
3408 self.resource.affiliationsSet = affiliationsSet
3409 return self.handleRequest(xml)
3410
3411
3412 def test_on_affiliationsSetMultipleForSameEntity(self):
3413 """
3414 Setting node affiliations can only have one item per entity.
3415 """
3416
3417 xml = """
3418 <iq type='set' to='pubsub.example.org'
3419 from='user@example.org'>
3420 <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
3421 <affiliations node='test'>
3422 <affiliation jid='other@example.org' affiliation='publisher'/>
3423 <affiliation jid='other@example.org' affiliation='owner'/>
3424 </affiliations>
3425 </pubsub>
3426 </iq>
3427 """
3428
3429 def cb(result):
3430 self.assertEquals('bad-request', result.condition)
3431
3432 d = self.handleRequest(xml)
3433 self.assertFailure(d, error.StanzaError)
3434 d.addCallback(cb)
3435 return d
3436
3437
3438 def test_on_affiliationsSetMissingJID(self):
3439 """
3440 Setting node affiliations must include a JID per affiliation.
3441 """
3442
3443 xml = """
3444 <iq type='set' to='pubsub.example.org'
3445 from='user@example.org'>
3446 <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
3447 <affiliations node='test'>
3448 <affiliation affiliation='publisher'/>
3449 </affiliations>
3450 </pubsub>
3451 </iq>
3452 """
3453
3454 def cb(result):
3455 self.assertEquals('bad-request', result.condition)
3456
3457 d = self.handleRequest(xml)
3458 self.assertFailure(d, error.StanzaError)
3459 d.addCallback(cb)
3460 return d
3461
3462
3463 def test_on_affiliationsSetMissingAffiliation(self):
3464 """
3465 Setting node affiliations must include an affiliation.
3466 """
3467
3468 xml = """
3469 <iq type='set' to='pubsub.example.org'
3470 from='user@example.org'>
3471 <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
3472 <affiliations node='test'>
3473 <affiliation jid='other@example.org'/>
3474 </affiliations>
3475 </pubsub>
3476 </iq>
3477 """
3478
3479 def cb(result):
3480 self.assertEquals('bad-request', result.condition)
3481
3482 d = self.handleRequest(xml)
3483 self.assertFailure(d, error.StanzaError)
3484 d.addCallback(cb)
3485 return d
3486
3487
3488
3489 class PubSubServiceWithoutResourceTest(unittest.TestCase, TestableRequestHandlerMixin):
3490
3491 def setUp(self):
3492 self.stub = XmlStreamStub()
3493 self.service = pubsub.PubSubService()
3494 self.service.send = self.stub.xmlstream.send
3495
3496
3497 def test_getDiscoInfo(self):
3498 """
3499 Test getDiscoInfo calls getNodeInfo and returns some minimal info.
3500 """
3501 def cb(info):
3502 discoInfo = disco.DiscoInfo()
3503 for item in info:
3504 discoInfo.append(item)
3505 self.assertIn(('pubsub', 'service'), discoInfo.identities)
3506 self.assertIn(disco.NS_DISCO_ITEMS, discoInfo.features)
3507
3508 d = self.service.getDiscoInfo(JID('user@example.org/home'),
3509 JID('pubsub.example.org'), '')
3510 d.addCallback(cb)
3511 return d
3512
3513
3514 def test_publish(self):
3515 """
3516 Non-overridden L{PubSubService.publish} yields unsupported error.
3517 """
3518
3519 xml = """
3520 <iq type='set' to='pubsub.example.org'
3521 from='user@example.org'>
3522 <pubsub xmlns='http://jabber.org/protocol/pubsub'>
3523 <publish node='mynode'/>
3524 </pubsub>
3525 </iq>
3526 """
3527
3528 def cb(result):
3529 self.assertEquals('feature-not-implemented', result.condition)
3530 self.assertEquals('unsupported', result.appCondition.name)
3531 self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
3532 self.assertEquals('publish', result.appCondition['feature'])
3533
3534 d = self.handleRequest(xml)
3535 self.assertFailure(d, error.StanzaError)
3536 d.addCallback(cb)
3537 return d
3538
3539
3540 def test_subscribe(self):
3541 """
3542 Non-overridden L{PubSubService.subscribe} yields unsupported error.
3543 """
3544
3545 xml = """
3546 <iq type='set' to='pubsub.example.org'
3547 from='user@example.org'>
3548 <pubsub xmlns='http://jabber.org/protocol/pubsub'>
3549 <subscribe node='test' jid='user@example.org/Home'/>
3550 </pubsub>
3551 </iq>
3552 """
3553
3554 def cb(result):
3555 self.assertEquals('feature-not-implemented', result.condition)
3556 self.assertEquals('unsupported', result.appCondition.name)
3557 self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
3558 self.assertEquals('subscribe', result.appCondition['feature'])
3559
3560 d = self.handleRequest(xml)
3561 self.assertFailure(d, error.StanzaError)
3562 d.addCallback(cb)
3563 return d
3564
3565
3566 def test_unsubscribe(self):
3567 """
3568 Non-overridden L{PubSubService.unsubscribe} yields unsupported error.
3569 """
3570
3571 xml = """
3572 <iq type='set' to='pubsub.example.org'
3573 from='user@example.org'>
3574 <pubsub xmlns='http://jabber.org/protocol/pubsub'>
3575 <unsubscribe node='test' jid='user@example.org/Home'/>
3576 </pubsub>
3577 </iq>
3578 """
3579
3580 def cb(result):
3581 self.assertEquals('feature-not-implemented', result.condition)
3582 self.assertEquals('unsupported', result.appCondition.name)
3583 self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
3584 self.assertEquals('subscribe', result.appCondition['feature'])
3585
3586 d = self.handleRequest(xml)
3587 self.assertFailure(d, error.StanzaError)
3588 d.addCallback(cb)
3589 return d
3590
3591
3592 def test_subscriptions(self):
3593 """
3594 Non-overridden L{PubSubService.subscriptions} yields unsupported error.
3595 """
3596
3597 xml = """
3598 <iq type='get' to='pubsub.example.org'
3599 from='user@example.org'>
3600 <pubsub xmlns='http://jabber.org/protocol/pubsub'>
3601 <subscriptions/>
3602 </pubsub>
3603 </iq>
3604 """
3605
3606 def cb(result):
3607 self.assertEquals('feature-not-implemented', result.condition)
3608 self.assertEquals('unsupported', result.appCondition.name)
3609 self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
3610 self.assertEquals('retrieve-subscriptions',
3611 result.appCondition['feature'])
3612
3613 d = self.handleRequest(xml)
3614 self.assertFailure(d, error.StanzaError)
3615 d.addCallback(cb)
3616 return d
3617
3618
3619 def test_affiliations(self):
3620 """
3621 Non-overridden L{PubSubService.affiliations} yields unsupported error.
3622 """
3623
3624 xml = """
3625 <iq type='get' to='pubsub.example.org'
3626 from='user@example.org'>
3627 <pubsub xmlns='http://jabber.org/protocol/pubsub'>
3628 <affiliations/>
3629 </pubsub>
3630 </iq>
3631 """
3632
3633 def cb(result):
3634 self.assertEquals('feature-not-implemented', result.condition)
3635 self.assertEquals('unsupported', result.appCondition.name)
3636 self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
3637 self.assertEquals('retrieve-affiliations',
3638 result.appCondition['feature'])
3639
3640 d = self.handleRequest(xml)
3641 self.assertFailure(d, error.StanzaError)
3642 d.addCallback(cb)
3643 return d
3644
3645
3646 def test_create(self):
3647 """
3648 Non-overridden L{PubSubService.create} yields unsupported error.
3649 """
3650
3651 xml = """
3652 <iq type='set' to='pubsub.example.org'
3653 from='user@example.org'>
3654 <pubsub xmlns='http://jabber.org/protocol/pubsub'>
3655 <create node='mynode'/>
3656 </pubsub>
3657 </iq>
3658 """
3659
3660 def cb(result):
3661 self.assertEquals('feature-not-implemented', result.condition)
3662 self.assertEquals('unsupported', result.appCondition.name)
3663 self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
3664 self.assertEquals('create-nodes', result.appCondition['feature'])
3665
3666 d = self.handleRequest(xml)
3667 self.assertFailure(d, error.StanzaError)
3668 d.addCallback(cb)
3669 return d
3670
3671
3672 def test_getDefaultConfiguration(self):
3673 """
3674 Non-overridden L{PubSubService.getDefaultConfiguration} yields
3675 unsupported error.
3676 """
3677
3678 xml = """
3679 <iq type='get' to='pubsub.example.org'
3680 from='user@example.org'>
3681 <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
3682 <default/>
3683 </pubsub>
3684 </iq>
3685 """
3686
3687 def cb(result):
3688 self.assertEquals('feature-not-implemented', result.condition)
3689 self.assertEquals('unsupported', result.appCondition.name)
3690 self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
3691 self.assertEquals('retrieve-default', result.appCondition['feature'])
3692
3693 d = self.handleRequest(xml)
3694 self.assertFailure(d, error.StanzaError)
3695 d.addCallback(cb)
3696 return d
3697
3698
3699 def test_getConfiguration(self):
3700 """
3701 Non-overridden L{PubSubService.getConfiguration} yields unsupported
3702 error.
3703 """
3704
3705 xml = """
3706 <iq type='get' to='pubsub.example.org'
3707 from='user@example.org'>
3708 <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
3709 <configure/>
3710 </pubsub>
3711 </iq>
3712 """
3713
3714 def cb(result):
3715 self.assertEquals('feature-not-implemented', result.condition)
3716 self.assertEquals('unsupported', result.appCondition.name)
3717 self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
3718 self.assertEquals('config-node', result.appCondition['feature'])
3719
3720 d = self.handleRequest(xml)
3721 self.assertFailure(d, error.StanzaError)
3722 d.addCallback(cb)
3723 return d
3724
3725
3726 def test_setConfiguration(self):
3727 """
3728 Non-overridden L{PubSubService.setConfiguration} yields unsupported
3729 error.
3730 """
3731
3732 xml = """
3733 <iq type='set' to='pubsub.example.org'
3734 from='user@example.org'>
3735 <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
3736 <configure node='test'>
3737 <x xmlns='jabber:x:data' type='submit'>
3738 <field var='FORM_TYPE' type='hidden'>
3739 <value>http://jabber.org/protocol/pubsub#node_config</value>
3740 </field>
3741 <field var='pubsub#deliver_payloads'><value>0</value></field>
3742 <field var='pubsub#persist_items'><value>1</value></field>
3743 </x>
3744 </configure>
3745 </pubsub>
3746 </iq>
3747 """
3748
3749 def cb(result):
3750 self.assertEquals('feature-not-implemented', result.condition)
3751 self.assertEquals('unsupported', result.appCondition.name)
3752 self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
3753 self.assertEquals('config-node', result.appCondition['feature'])
3754
3755 d = self.handleRequest(xml)
3756 self.assertFailure(d, error.StanzaError)
3757 d.addCallback(cb)
3758 return d
3759
3760
3761 def test_setConfigurationOptionsDict(self):
3762 """
3763 Options should be passed as a dictionary, not a form.
3764 """
3765
3766 xml = """
3767 <iq type='set' to='pubsub.example.org'
3768 from='user@example.org'>
3769 <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
3770 <configure node='test'>
3771 <x xmlns='jabber:x:data' type='submit'>
3772 <field var='FORM_TYPE' type='hidden'>
3773 <value>http://jabber.org/protocol/pubsub#node_config</value>
3774 </field>
3775 <field var='pubsub#deliver_payloads'><value>0</value></field>
3776 <field var='pubsub#persist_items'><value>1</value></field>
3777 </x>
3778 </configure>
3779 </pubsub>
3780 </iq>
3781 """
3782
3783 def getConfigurationOptions():
3784 return {
3785 "pubsub#persist_items":
3786 {"type": "boolean",
3787 "label": "Persist items to storage"},
3788 "pubsub#deliver_payloads":
3789 {"type": "boolean",
3790 "label": "Deliver payloads with event notifications"}
3791 }
3792
3793 def setConfiguration(requestor, service, nodeIdentifier, options):
3794 self.assertIn('pubsub#deliver_payloads', options)
3795 self.assertFalse(options['pubsub#deliver_payloads'])
3796 self.assertIn('pubsub#persist_items', options)
3797 self.assertTrue(options['pubsub#persist_items'])
3798
3799 self.service.getConfigurationOptions = getConfigurationOptions
3800 self.service.setConfiguration = setConfiguration
3801 return self.handleRequest(xml)
3802
3803
3804 def test_items(self):
3805 """
3806 Non-overridden L{PubSubService.items} yields unsupported error.
3807 """
3808 xml = """
3809 <iq type='get' to='pubsub.example.org'
3810 from='user@example.org'>
3811 <pubsub xmlns='http://jabber.org/protocol/pubsub'>
3812 <items node='test'/>
3813 </pubsub>
3814 </iq>
3815 """
3816
3817 def cb(result):
3818 self.assertEquals('feature-not-implemented', result.condition)
3819 self.assertEquals('unsupported', result.appCondition.name)
3820 self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
3821 self.assertEquals('retrieve-items', result.appCondition['feature'])
3822
3823 d = self.handleRequest(xml)
3824 self.assertFailure(d, error.StanzaError)
3825 d.addCallback(cb)
3826 return d
3827
3828
3829 def test_retract(self):
3830 """
3831 Non-overridden L{PubSubService.retract} yields unsupported error.
3832 """
3833 xml = """
3834 <iq type='set' to='pubsub.example.org'
3835 from='user@example.org'>
3836 <pubsub xmlns='http://jabber.org/protocol/pubsub'>
3837 <retract node='test'>
3838 <item id='item1'/>
3839 <item id='item2'/>
3840 </retract>
3841 </pubsub>
3842 </iq>
3843 """
3844
3845 def cb(result):
3846 self.assertEquals('feature-not-implemented', result.condition)
3847 self.assertEquals('unsupported', result.appCondition.name)
3848 self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
3849 self.assertEquals('retract-items', result.appCondition['feature'])
3850
3851 d = self.handleRequest(xml)
3852 self.assertFailure(d, error.StanzaError)
3853 d.addCallback(cb)
3854 return d
3855
3856
3857 def test_purge(self):
3858 """
3859 Non-overridden L{PubSubService.purge} yields unsupported error.
3860 """
3861 xml = """
3862 <iq type='set' to='pubsub.example.org'
3863 from='user@example.org'>
3864 <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
3865 <purge node='test'/>
3866 </pubsub>
3867 </iq>
3868 """
3869
3870 def cb(result):
3871 self.assertEquals('feature-not-implemented', result.condition)
3872 self.assertEquals('unsupported', result.appCondition.name)
3873 self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
3874 self.assertEquals('purge-nodes', result.appCondition['feature'])
3875
3876 d = self.handleRequest(xml)
3877 self.assertFailure(d, error.StanzaError)
3878 d.addCallback(cb)
3879 return d
3880
3881
3882 def test_delete(self):
3883 """
3884 Non-overridden L{PubSubService.delete} yields unsupported error.
3885 """
3886 xml = """
3887 <iq type='set' to='pubsub.example.org'
3888 from='user@example.org'>
3889 <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
3890 <delete node='test'/>
3891 </pubsub>
3892 </iq>
3893 """
3894
3895 def cb(result):
3896 self.assertEquals('feature-not-implemented', result.condition)
3897 self.assertEquals('unsupported', result.appCondition.name)
3898 self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
3899 self.assertEquals('delete-nodes', result.appCondition['feature'])
3900
3901 d = self.handleRequest(xml)
3902 self.assertFailure(d, error.StanzaError)
3903 d.addCallback(cb)
3904 return d
3905
3906
3907 def test_unknown(self):
3908 """
3909 Unknown verb yields unsupported error.
3910 """
3911 xml = """
3912 <iq type='get' to='pubsub.example.org'
3913 from='user@example.org'>
3914 <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
3915 <affiliations node='test'/>
3916 </pubsub>
3917 </iq>
3918 """
3919
3920 def cb(result):
3921 self.assertEquals('feature-not-implemented', result.condition)
3922 self.assertEquals('unsupported', result.appCondition.name)
3923 self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
3924
3925 d = self.handleRequest(xml)
3926 self.assertFailure(d, error.StanzaError)
3927 d.addCallback(cb)
3928 return d
3929
3930
3931
3932 class PubSubResourceTest(unittest.TestCase):
3933
3934 def setUp(self):
3935 self.resource = pubsub.PubSubResource()
3936
3937
3938 def test_interface(self):
3939 """
3940 Do instances of L{pubsub.PubSubResource} provide L{iwokkel.IPubSubResource}?
3941 """
3942 verify.verifyObject(iwokkel.IPubSubResource, self.resource)
3943
3944
3945 def test_getNodes(self):
3946 """
3947 Default getNodes returns an empty list.
3948 """
3949 def cb(nodes):
3950 self.assertEquals([], nodes)
3951
3952 d = self.resource.getNodes(JID('user@example.org/home'),
3953 JID('pubsub.example.org'),
3954 '')
3955 d.addCallback(cb)
3956 return d
3957
3958
3959 def test_publish(self):
3960 """
3961 Non-overridden L{PubSubResource.publish} yields unsupported
3962 error.
3963 """
3964
3965 def cb(result):
3966 self.assertEquals('feature-not-implemented', result.condition)
3967 self.assertEquals('unsupported', result.appCondition.name)
3968 self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
3969 self.assertEquals('publish', result.appCondition['feature'])
3970
3971 d = self.resource.publish(pubsub.PubSubRequest())
3972 self.assertFailure(d, error.StanzaError)
3973 d.addCallback(cb)
3974 return d
3975
3976
3977 def test_subscribe(self):
3978 """
3979 Non-overridden subscriptions yields unsupported error.
3980 """
3981
3982 def cb(result):
3983 self.assertEquals('feature-not-implemented', result.condition)
3984 self.assertEquals('unsupported', result.appCondition.name)
3985 self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
3986 self.assertEquals('subscribe', result.appCondition['feature'])
3987
3988 d = self.resource.subscribe(pubsub.PubSubRequest())
3989 self.assertFailure(d, error.StanzaError)
3990 d.addCallback(cb)
3991 return d
3992
3993
3994 def test_unsubscribe(self):
3995 """
3996 Non-overridden unsubscribe yields unsupported error.
3997 """
3998
3999 def cb(result):
4000 self.assertEquals('feature-not-implemented', result.condition)
4001 self.assertEquals('unsupported', result.appCondition.name)
4002 self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
4003 self.assertEquals('subscribe', result.appCondition['feature'])
4004
4005 d = self.resource.unsubscribe(pubsub.PubSubRequest())
4006 self.assertFailure(d, error.StanzaError)
4007 d.addCallback(cb)
4008 return d
4009
4010
4011 def test_subscriptions(self):
4012 """
4013 Non-overridden subscriptions yields unsupported error.
4014 """
4015
4016 def cb(result):
4017 self.assertEquals('feature-not-implemented', result.condition)
4018 self.assertEquals('unsupported', result.appCondition.name)
4019 self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
4020 self.assertEquals('retrieve-subscriptions',
4021 result.appCondition['feature'])
4022
4023 d = self.resource.subscriptions(pubsub.PubSubRequest())
4024 self.assertFailure(d, error.StanzaError)
4025 d.addCallback(cb)
4026 return d
4027
4028
4029 def test_affiliations(self):
4030 """
4031 Non-overridden affiliations yields unsupported error.
4032 """
4033
4034 def cb(result):
4035 self.assertEquals('feature-not-implemented', result.condition)
4036 self.assertEquals('unsupported', result.appCondition.name)
4037 self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
4038 self.assertEquals('retrieve-affiliations',
4039 result.appCondition['feature'])
4040
4041 d = self.resource.affiliations(pubsub.PubSubRequest())
4042 self.assertFailure(d, error.StanzaError)
4043 d.addCallback(cb)
4044 return d
4045
4046
4047 def test_create(self):
4048 """
4049 Non-overridden create yields unsupported error.
4050 """
4051
4052 def cb(result):
4053 self.assertEquals('feature-not-implemented', result.condition)
4054 self.assertEquals('unsupported', result.appCondition.name)
4055 self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
4056 self.assertEquals('create-nodes', result.appCondition['feature'])
4057
4058 d = self.resource.create(pubsub.PubSubRequest())
4059 self.assertFailure(d, error.StanzaError)
4060 d.addCallback(cb)
4061 return d
4062
4063
4064 def test_default(self):
4065 """
4066 Non-overridden default yields unsupported error.
4067 """
4068
4069 def cb(result):
4070 self.assertEquals('feature-not-implemented', result.condition)
4071 self.assertEquals('unsupported', result.appCondition.name)
4072 self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
4073 self.assertEquals('retrieve-default',
4074 result.appCondition['feature'])
4075
4076 d = self.resource.default(pubsub.PubSubRequest())
4077 self.assertFailure(d, error.StanzaError)
4078 d.addCallback(cb)
4079 return d
4080
4081
4082 def test_configureGet(self):
4083 """
4084 Non-overridden configureGet yields unsupported
4085 error.
4086 """
4087
4088 def cb(result):
4089 self.assertEquals('feature-not-implemented', result.condition)
4090 self.assertEquals('unsupported', result.appCondition.name)
4091 self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
4092 self.assertEquals('config-node', result.appCondition['feature'])
4093
4094 d = self.resource.configureGet(pubsub.PubSubRequest())
4095 self.assertFailure(d, error.StanzaError)
4096 d.addCallback(cb)
4097 return d
4098
4099
4100 def test_configureSet(self):
4101 """
4102 Non-overridden configureSet yields unsupported error.
4103 """
4104
4105 def cb(result):
4106 self.assertEquals('feature-not-implemented', result.condition)
4107 self.assertEquals('unsupported', result.appCondition.name)
4108 self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
4109 self.assertEquals('config-node', result.appCondition['feature'])
4110
4111 d = self.resource.configureSet(pubsub.PubSubRequest())
4112 self.assertFailure(d, error.StanzaError)
4113 d.addCallback(cb)
4114 return d
4115
4116
4117 def test_items(self):
4118 """
4119 Non-overridden items yields unsupported error.
4120 """
4121
4122 def cb(result):
4123 self.assertEquals('feature-not-implemented', result.condition)
4124 self.assertEquals('unsupported', result.appCondition.name)
4125 self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
4126 self.assertEquals('retrieve-items', result.appCondition['feature'])
4127
4128 d = self.resource.items(pubsub.PubSubRequest())
4129 self.assertFailure(d, error.StanzaError)
4130 d.addCallback(cb)
4131 return d
4132
4133
4134 def test_retract(self):
4135 """
4136 Non-overridden retract yields unsupported error.
4137 """
4138
4139 def cb(result):
4140 self.assertEquals('feature-not-implemented', result.condition)
4141 self.assertEquals('unsupported', result.appCondition.name)
4142 self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
4143 self.assertEquals('retract-items', result.appCondition['feature'])
4144
4145 d = self.resource.retract(pubsub.PubSubRequest())
4146 self.assertFailure(d, error.StanzaError)
4147 d.addCallback(cb)
4148 return d
4149
4150
4151 def test_purge(self):
4152 """
4153 Non-overridden purge yields unsupported error.
4154 """
4155
4156 def cb(result):
4157 self.assertEquals('feature-not-implemented', result.condition)
4158 self.assertEquals('unsupported', result.appCondition.name)
4159 self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
4160 self.assertEquals('purge-nodes', result.appCondition['feature'])
4161
4162 d = self.resource.purge(pubsub.PubSubRequest())
4163 self.assertFailure(d, error.StanzaError)
4164 d.addCallback(cb)
4165 return d
4166
4167
4168 def test_delete(self):
4169 """
4170 Non-overridden delete yields unsupported error.
4171 """
4172
4173 def cb(result):
4174 self.assertEquals('feature-not-implemented', result.condition)
4175 self.assertEquals('unsupported', result.appCondition.name)
4176 self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
4177 self.assertEquals('delete-nodes', result.appCondition['feature'])
4178
4179 d = self.resource.delete(pubsub.PubSubRequest())
4180 self.assertFailure(d, error.StanzaError)
4181 d.addCallback(cb)
4182 return d
4183
4184
4185 def test_affiliationsGet(self):
4186 """
4187 Non-overridden owner affiliations get yields unsupported error.
4188 """
4189
4190 def cb(result):
4191 self.assertEquals('feature-not-implemented', result.condition)
4192 self.assertEquals('unsupported', result.appCondition.name)
4193 self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
4194 self.assertEquals('modify-affiliations',
4195 result.appCondition['feature'])
4196
4197 d = self.resource.affiliationsGet(pubsub.PubSubRequest())
4198 self.assertFailure(d, error.StanzaError)
4199 d.addCallback(cb)
4200 return d
4201
4202
4203 def test_affiliationsSet(self):
4204 """
4205 Non-overridden owner affiliations set yields unsupported error.
4206 """
4207
4208 def cb(result):
4209 self.assertEquals('feature-not-implemented', result.condition)
4210 self.assertEquals('unsupported', result.appCondition.name)
4211 self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
4212 self.assertEquals('modify-affiliations',
4213 result.appCondition['feature'])
4214
4215 d = self.resource.affiliationsSet(pubsub.PubSubRequest())
4216 self.assertFailure(d, error.StanzaError)
4217 d.addCallback(cb)
4218 return d