comparison src/test/test_gateway.py @ 369:dabee42494ac

config file + cleaning: - SàT Pubsub can now be configured using the same config file as SàT itself (i.e. sat.conf or .sat.conf), in the same locations (/etc, local dir, xdg dir). Its options must be in the "pubsub" section - options on command line override config options - removed tap and http files which are not used anymore - changed directory structure to put source in src, to be coherent with SàT and Libervia - changed options name, db* become db_*, secret become xmpp_pwd - an exception is raised if jid or xmpp_pwd is are not configured
author Goffi <goffi@goffi.org>
date Fri, 02 Mar 2018 12:59:38 +0100
parents sat_pubsub/test/test_gateway.py@618a92080812
children aa3a464df605
comparison
equal deleted inserted replaced
368:618a92080812 369:dabee42494ac
1 #!/usr/bin/python
2 #-*- coding: utf-8 -*-
3
4 # Copyright (c) 2003-2011 Ralph Meijer
5 # Copyright (c) 2012-2018 Jérôme Poisson
6
7
8 # This program is free software: you can redistribute it and/or modify
9 # it under the terms of the GNU Affero General Public License as published by
10 # the Free Software Foundation, either version 3 of the License, or
11 # (at your option) any later version.
12
13 # This program is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU Affero General Public License for more details.
17
18 # You should have received a copy of the GNU Affero General Public License
19 # along with this program. If not, see <http://www.gnu.org/licenses/>.
20 # --
21
22 # This program is based on Idavoll (http://idavoll.ik.nu/),
23 # originaly written by Ralph Meijer (http://ralphm.net/blog/)
24 # It is sublicensed under AGPL v3 (or any later version) as allowed by the original
25 # license.
26
27 # --
28
29 # Here is a copy of the original license:
30
31 # Copyright (c) 2003-2011 Ralph Meijer
32
33 # Permission is hereby granted, free of charge, to any person obtaining
34 # a copy of this software and associated documentation files (the
35 # "Software"), to deal in the Software without restriction, including
36 # without limitation the rights to use, copy, modify, merge, publish,
37 # distribute, sublicense, and/or sell copies of the Software, and to
38 # permit persons to whom the Software is furnished to do so, subject to
39 # the following conditions:
40
41 # The above copyright notice and this permission notice shall be
42 # included in all copies or substantial portions of the Software.
43
44 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
45 # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
46 # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
47 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
48 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
49 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
50 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
51
52
53 """
54 Tests for L{idavoll.gateway}.
55
56 Note that some tests are functional tests that require a running idavoll
57 service.
58 """
59
60 from StringIO import StringIO
61
62 import simplejson
63
64 from twisted.internet import defer
65 from twisted.trial import unittest
66 from twisted.web import error, http, http_headers, server
67 from twisted.web.test import requesthelper
68 from twisted.words.xish import domish
69 from twisted.words.protocols.jabber.jid import JID
70
71 from sat_pubsub import gateway
72 from sat_pubsub.backend import BackendService
73 from sat_pubsub.memory_storage import Storage
74
75 AGENT = "Idavoll Test Script"
76 NS_ATOM = "http://www.w3.org/2005/Atom"
77
78 TEST_ENTRY = domish.Element((NS_ATOM, 'entry'))
79 TEST_ENTRY.addElement("id",
80 content="urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a")
81 TEST_ENTRY.addElement("title", content="Atom-Powered Robots Run Amok")
82 TEST_ENTRY.addElement("author").addElement("name", content="John Doe")
83 TEST_ENTRY.addElement("content", content="Some text.")
84
85 baseURI = "http://localhost:8086/"
86 component = "pubsub"
87 componentJID = JID(component)
88 ownerJID = JID('owner@example.org')
89
90 def _render(resource, request):
91 result = resource.render(request)
92 if isinstance(result, str):
93 request.write(result)
94 request.finish()
95 return defer.succeed(None)
96 elif result is server.NOT_DONE_YET:
97 if request.finished:
98 return defer.succeed(None)
99 else:
100 return request.notifyFinish()
101 else:
102 raise ValueError("Unexpected return value: %r" % (result,))
103
104
105 class DummyRequest(requesthelper.DummyRequest):
106
107 def __init__(self, *args, **kwargs):
108 requesthelper.DummyRequest.__init__(self, *args, **kwargs)
109 self.requestHeaders = http_headers.Headers()
110
111
112
113 class GetServiceAndNodeTest(unittest.TestCase):
114 """
115 Tests for {gateway.getServiceAndNode}.
116 """
117
118 def test_basic(self):
119 """
120 getServiceAndNode parses an XMPP URI with node parameter.
121 """
122 uri = b'xmpp:pubsub.example.org?;node=test'
123 service, nodeIdentifier = gateway.getServiceAndNode(uri)
124 self.assertEqual(JID(u'pubsub.example.org'), service)
125 self.assertEqual(u'test', nodeIdentifier)
126
127
128 def test_schemeEmpty(self):
129 """
130 If the URI scheme is empty, an exception is raised.
131 """
132 uri = b'pubsub.example.org'
133 self.assertRaises(gateway.XMPPURIParseError,
134 gateway.getServiceAndNode, uri)
135
136
137 def test_schemeNotXMPP(self):
138 """
139 If the URI scheme is not 'xmpp', an exception is raised.
140 """
141 uri = b'mailto:test@example.org'
142 self.assertRaises(gateway.XMPPURIParseError,
143 gateway.getServiceAndNode, uri)
144
145
146 def test_authorityPresent(self):
147 """
148 If the URI has an authority component, an exception is raised.
149 """
150 uri = b'xmpp://pubsub.example.org/'
151 self.assertRaises(gateway.XMPPURIParseError,
152 gateway.getServiceAndNode, uri)
153
154
155 def test_queryEmpty(self):
156 """
157 If there is no query component, the nodeIdentifier is empty.
158 """
159 uri = b'xmpp:pubsub.example.org'
160 service, nodeIdentifier = gateway.getServiceAndNode(uri)
161
162 self.assertEqual(JID(u'pubsub.example.org'), service)
163 self.assertEqual(u'', nodeIdentifier)
164
165
166 def test_jidInvalid(self):
167 """
168 If the JID from the path component is invalid, an exception is raised.
169 """
170 uri = b'xmpp:@@pubsub.example.org?;node=test'
171 self.assertRaises(gateway.XMPPURIParseError,
172 gateway.getServiceAndNode, uri)
173
174
175 def test_pathEmpty(self):
176 """
177 If there is no path component, an exception is raised.
178 """
179 uri = b'xmpp:?node=test'
180 self.assertRaises(gateway.XMPPURIParseError,
181 gateway.getServiceAndNode, uri)
182
183
184 def test_nodeAbsent(self):
185 """
186 If the node parameter is missing, the nodeIdentifier is empty.
187 """
188 uri = b'xmpp:pubsub.example.org?'
189 service, nodeIdentifier = gateway.getServiceAndNode(uri)
190
191 self.assertEqual(JID(u'pubsub.example.org'), service)
192 self.assertEqual(u'', nodeIdentifier)
193
194
195
196 class GetXMPPURITest(unittest.TestCase):
197 """
198 Tests for L{gateway.getXMPPURITest}.
199 """
200
201 def test_basic(self):
202 uri = gateway.getXMPPURI(JID(u'pubsub.example.org'), u'test')
203 self.assertEqual('xmpp:pubsub.example.org?;node=test', uri)
204
205
206 class CreateResourceTest(unittest.TestCase):
207 """
208 Tests for L{gateway.CreateResource}.
209 """
210
211 def setUp(self):
212 self.backend = BackendService(Storage())
213 self.resource = gateway.CreateResource(self.backend, componentJID,
214 ownerJID)
215
216
217 def test_get(self):
218 """
219 The method GET is not supported.
220 """
221 request = DummyRequest([b''])
222 self.assertRaises(error.UnsupportedMethod,
223 _render, self.resource, request)
224
225
226 def test_post(self):
227 """
228 Upon a POST, a new node is created and the URI returned.
229 """
230 request = DummyRequest([b''])
231 request.method = 'POST'
232
233 def gotNodes(nodeIdentifiers, uri):
234 service, nodeIdentifier = gateway.getServiceAndNode(uri)
235 self.assertIn(nodeIdentifier, nodeIdentifiers)
236
237 def rendered(result):
238 self.assertEqual('application/json',
239 request.outgoingHeaders['content-type'])
240 payload = simplejson.loads(b''.join(request.written))
241 self.assertIn('uri', payload)
242 d = self.backend.getNodes()
243 d.addCallback(gotNodes, payload['uri'])
244 return d
245
246 d = _render(self.resource, request)
247 d.addCallback(rendered)
248 return d
249
250
251
252 class DeleteResourceTest(unittest.TestCase):
253 """
254 Tests for L{gateway.DeleteResource}.
255 """
256
257 def setUp(self):
258 self.backend = BackendService(Storage())
259 self.resource = gateway.DeleteResource(self.backend, componentJID,
260 ownerJID)
261
262
263 def test_get(self):
264 """
265 The method GET is not supported.
266 """
267 request = DummyRequest([b''])
268 self.assertRaises(error.UnsupportedMethod,
269 _render, self.resource, request)
270
271
272 def test_post(self):
273 """
274 Upon a POST, a new node is created and the URI returned.
275 """
276 request = DummyRequest([b''])
277 request.method = b'POST'
278
279 def rendered(result):
280 self.assertEqual(http.NO_CONTENT, request.responseCode)
281
282 def nodeCreated(nodeIdentifier):
283 uri = gateway.getXMPPURI(componentJID, nodeIdentifier)
284 request.args[b'uri'] = [uri]
285 request.content = StringIO(b'')
286
287 return _render(self.resource, request)
288
289 d = self.backend.createNode(u'test', ownerJID)
290 d.addCallback(nodeCreated)
291 d.addCallback(rendered)
292 return d
293
294
295 def test_postWithRedirect(self):
296 """
297 Upon a POST, a new node is created and the URI returned.
298 """
299 request = DummyRequest([b''])
300 request.method = b'POST'
301 otherNodeURI = b'xmpp:pubsub.example.org?node=other'
302
303 def rendered(result):
304 self.assertEqual(http.NO_CONTENT, request.responseCode)
305 self.assertEqual(1, len(deletes))
306 nodeIdentifier, owner, redirectURI = deletes[-1]
307 self.assertEqual(otherNodeURI, redirectURI)
308
309 def nodeCreated(nodeIdentifier):
310 uri = gateway.getXMPPURI(componentJID, nodeIdentifier)
311 request.args[b'uri'] = [uri]
312 payload = {b'redirect_uri': otherNodeURI}
313 body = simplejson.dumps(payload)
314 request.content = StringIO(body)
315 return _render(self.resource, request)
316
317 def deleteNode(nodeIdentifier, owner, redirectURI):
318 deletes.append((nodeIdentifier, owner, redirectURI))
319 return defer.succeed(nodeIdentifier)
320
321 deletes = []
322 self.patch(self.backend, 'deleteNode', deleteNode)
323 d = self.backend.createNode(u'test', ownerJID)
324 d.addCallback(nodeCreated)
325 d.addCallback(rendered)
326 return d
327
328
329 def test_postUnknownNode(self):
330 """
331 If the node to be deleted is unknown, 404 Not Found is returned.
332 """
333 request = DummyRequest([b''])
334 request.method = b'POST'
335
336 def rendered(result):
337 self.assertEqual(http.NOT_FOUND, request.responseCode)
338
339 uri = gateway.getXMPPURI(componentJID, u'unknown')
340 request.args[b'uri'] = [uri]
341 request.content = StringIO(b'')
342
343 d = _render(self.resource, request)
344 d.addCallback(rendered)
345 return d
346
347
348 def test_postMalformedXMPPURI(self):
349 """
350 If the XMPP URI is malformed, Bad Request is returned.
351 """
352 request = DummyRequest([b''])
353 request.method = b'POST'
354
355 def rendered(result):
356 self.assertEqual(http.BAD_REQUEST, request.responseCode)
357
358 uri = 'xmpp:@@@@'
359 request.args[b'uri'] = [uri]
360 request.content = StringIO(b'')
361
362 d = _render(self.resource, request)
363 d.addCallback(rendered)
364 return d
365
366
367 def test_postURIMissing(self):
368 """
369 If no URI is passed, 400 Bad Request is returned.
370 """
371 request = DummyRequest([b''])
372 request.method = b'POST'
373
374 def rendered(result):
375 self.assertEqual(http.BAD_REQUEST, request.responseCode)
376
377 request.content = StringIO(b'')
378
379 d = _render(self.resource, request)
380 d.addCallback(rendered)
381 return d
382
383
384
385 class CallbackResourceTest(unittest.TestCase):
386 """
387 Tests for L{gateway.CallbackResource}.
388 """
389
390 def setUp(self):
391 self.callbackEvents = []
392 self.resource = gateway.CallbackResource(self._callback)
393
394
395 def _callback(self, payload, headers):
396 self.callbackEvents.append((payload, headers))
397
398
399 def test_get(self):
400 """
401 The method GET is not supported.
402 """
403 request = DummyRequest([b''])
404 self.assertRaises(error.UnsupportedMethod,
405 _render, self.resource, request)
406
407
408 def test_post(self):
409 """
410 The body posted is passed to the callback.
411 """
412 request = DummyRequest([b''])
413 request.method = 'POST'
414 request.content = StringIO(b'<root><child/></root>')
415
416 def rendered(result):
417 self.assertEqual(1, len(self.callbackEvents))
418 payload, headers = self.callbackEvents[-1]
419 self.assertEqual('root', payload.name)
420
421 self.assertEqual(http.NO_CONTENT, request.responseCode)
422 self.assertFalse(b''.join(request.written))
423
424 d = _render(self.resource, request)
425 d.addCallback(rendered)
426 return d
427
428
429 def test_postEvent(self):
430 """
431 If the Event header is set, the payload is empty and the header passed.
432 """
433 request = DummyRequest([b''])
434 request.method = 'POST'
435 request.requestHeaders.addRawHeader(b'Event', b'DELETE')
436 request.content = StringIO(b'')
437
438 def rendered(result):
439 self.assertEqual(1, len(self.callbackEvents))
440 payload, headers = self.callbackEvents[-1]
441 self.assertIdentical(None, payload)
442 self.assertEqual(['DELETE'], headers.getRawHeaders(b'Event'))
443 self.assertFalse(b''.join(request.written))
444
445 d = _render(self.resource, request)
446 d.addCallback(rendered)
447 return d
448
449
450
451 class GatewayTest(unittest.TestCase):
452 timeout = 2
453
454 def setUp(self):
455 self.client = gateway.GatewayClient(baseURI)
456 self.client.startService()
457 self.addCleanup(self.client.stopService)
458
459 def trapConnectionRefused(failure):
460 from twisted.internet.error import ConnectionRefusedError
461 failure.trap(ConnectionRefusedError)
462 raise unittest.SkipTest("Gateway to test against is not available")
463
464 def trapNotFound(failure):
465 from twisted.web.error import Error
466 failure.trap(Error)
467
468 d = self.client.ping()
469 d.addErrback(trapConnectionRefused)
470 d.addErrback(trapNotFound)
471 return d
472
473
474 def tearDown(self):
475 return self.client.stopService()
476
477
478 def test_create(self):
479
480 def cb(response):
481 self.assertIn('uri', response)
482
483 d = self.client.create()
484 d.addCallback(cb)
485 return d
486
487 def test_publish(self):
488
489 def cb(response):
490 self.assertIn('uri', response)
491
492 d = self.client.publish(TEST_ENTRY)
493 d.addCallback(cb)
494 return d
495
496 def test_publishExistingNode(self):
497
498 def cb2(response, xmppURI):
499 self.assertEquals(xmppURI, response['uri'])
500
501 def cb1(response):
502 xmppURI = response['uri']
503 d = self.client.publish(TEST_ENTRY, xmppURI)
504 d.addCallback(cb2, xmppURI)
505 return d
506
507 d = self.client.create()
508 d.addCallback(cb1)
509 return d
510
511 def test_publishNonExisting(self):
512 def cb(err):
513 self.assertEqual('404', err.status)
514
515 d = self.client.publish(TEST_ENTRY, 'xmpp:%s?node=test' % component)
516 self.assertFailure(d, error.Error)
517 d.addCallback(cb)
518 return d
519
520 def test_delete(self):
521 def cb(response):
522 xmppURI = response['uri']
523 d = self.client.delete(xmppURI)
524 return d
525
526 d = self.client.create()
527 d.addCallback(cb)
528 return d
529
530 def test_deleteWithRedirect(self):
531 def cb(response):
532 xmppURI = response['uri']
533 redirectURI = 'xmpp:%s?node=test' % component
534 d = self.client.delete(xmppURI, redirectURI)
535 return d
536
537 d = self.client.create()
538 d.addCallback(cb)
539 return d
540
541 def test_deleteNotification(self):
542 def onNotification(data, headers):
543 try:
544 self.assertTrue(headers.hasHeader('Event'))
545 self.assertEquals(['DELETED'], headers.getRawHeaders('Event'))
546 self.assertFalse(headers.hasHeader('Link'))
547 except:
548 self.client.deferred.errback()
549 else:
550 self.client.deferred.callback(None)
551
552 def cb(response):
553 xmppURI = response['uri']
554 d = self.client.subscribe(xmppURI)
555 d.addCallback(lambda _: xmppURI)
556 return d
557
558 def cb2(xmppURI):
559 d = self.client.delete(xmppURI)
560 return d
561
562 self.client.callback = onNotification
563 self.client.deferred = defer.Deferred()
564 d = self.client.create()
565 d.addCallback(cb)
566 d.addCallback(cb2)
567 return defer.gatherResults([d, self.client.deferred])
568
569 def test_deleteNotificationWithRedirect(self):
570 redirectURI = 'xmpp:%s?node=test' % component
571
572 def onNotification(data, headers):
573 try:
574 self.assertTrue(headers.hasHeader('Event'))
575 self.assertEquals(['DELETED'], headers.getRawHeaders('Event'))
576 self.assertEquals(['<%s>; rel=alternate' % redirectURI],
577 headers.getRawHeaders('Link'))
578 except:
579 self.client.deferred.errback()
580 else:
581 self.client.deferred.callback(None)
582
583 def cb(response):
584 xmppURI = response['uri']
585 d = self.client.subscribe(xmppURI)
586 d.addCallback(lambda _: xmppURI)
587 return d
588
589 def cb2(xmppURI):
590 d = self.client.delete(xmppURI, redirectURI)
591 return d
592
593 self.client.callback = onNotification
594 self.client.deferred = defer.Deferred()
595 d = self.client.create()
596 d.addCallback(cb)
597 d.addCallback(cb2)
598 return defer.gatherResults([d, self.client.deferred])
599
600 def test_list(self):
601 d = self.client.listNodes()
602 return d
603
604 def test_subscribe(self):
605 def cb(response):
606 xmppURI = response['uri']
607 d = self.client.subscribe(xmppURI)
608 return d
609
610 d = self.client.create()
611 d.addCallback(cb)
612 return d
613
614 def test_subscribeGetNotification(self):
615
616 def onNotification(data, headers):
617 self.client.deferred.callback(None)
618
619 def cb(response):
620 xmppURI = response['uri']
621 d = self.client.subscribe(xmppURI)
622 d.addCallback(lambda _: xmppURI)
623 return d
624
625 def cb2(xmppURI):
626 d = self.client.publish(TEST_ENTRY, xmppURI)
627 return d
628
629
630 self.client.callback = onNotification
631 self.client.deferred = defer.Deferred()
632 d = self.client.create()
633 d.addCallback(cb)
634 d.addCallback(cb2)
635 return defer.gatherResults([d, self.client.deferred])
636
637
638 def test_subscribeTwiceGetNotification(self):
639
640 def onNotification1(data, headers):
641 d = client1.stopService()
642 d.chainDeferred(client1.deferred)
643
644 def onNotification2(data, headers):
645 d = client2.stopService()
646 d.chainDeferred(client2.deferred)
647
648 def cb(response):
649 xmppURI = response['uri']
650 d = client1.subscribe(xmppURI)
651 d.addCallback(lambda _: xmppURI)
652 return d
653
654 def cb2(xmppURI):
655 d = client2.subscribe(xmppURI)
656 d.addCallback(lambda _: xmppURI)
657 return d
658
659 def cb3(xmppURI):
660 d = self.client.publish(TEST_ENTRY, xmppURI)
661 return d
662
663
664 client1 = gateway.GatewayClient(baseURI, callbackPort=8088)
665 client1.startService()
666 client1.callback = onNotification1
667 client1.deferred = defer.Deferred()
668 client2 = gateway.GatewayClient(baseURI, callbackPort=8089)
669 client2.startService()
670 client2.callback = onNotification2
671 client2.deferred = defer.Deferred()
672
673 d = self.client.create()
674 d.addCallback(cb)
675 d.addCallback(cb2)
676 d.addCallback(cb3)
677 dl = defer.gatherResults([d, client1.deferred, client2.deferred])
678 return dl
679
680
681 def test_subscribeGetDelayedNotification(self):
682
683 def onNotification(data, headers):
684 self.client.deferred.callback(None)
685
686 def cb(response):
687 xmppURI = response['uri']
688 self.assertNot(self.client.deferred.called)
689 d = self.client.publish(TEST_ENTRY, xmppURI)
690 d.addCallback(lambda _: xmppURI)
691 return d
692
693 def cb2(xmppURI):
694 d = self.client.subscribe(xmppURI)
695 return d
696
697
698 self.client.callback = onNotification
699 self.client.deferred = defer.Deferred()
700 d = self.client.create()
701 d.addCallback(cb)
702 d.addCallback(cb2)
703 return defer.gatherResults([d, self.client.deferred])
704
705 def test_subscribeGetDelayedNotification2(self):
706 """
707 Test that subscribing as second results in a notification being sent.
708 """
709
710 def onNotification1(data, headers):
711 client1.deferred.callback(None)
712 client1.stopService()
713
714 def onNotification2(data, headers):
715 client2.deferred.callback(None)
716 client2.stopService()
717
718 def cb(response):
719 xmppURI = response['uri']
720 self.assertNot(client1.deferred.called)
721 self.assertNot(client2.deferred.called)
722 d = self.client.publish(TEST_ENTRY, xmppURI)
723 d.addCallback(lambda _: xmppURI)
724 return d
725
726 def cb2(xmppURI):
727 d = client1.subscribe(xmppURI)
728 d.addCallback(lambda _: xmppURI)
729 return d
730
731 def cb3(xmppURI):
732 d = client2.subscribe(xmppURI)
733 return d
734
735 client1 = gateway.GatewayClient(baseURI, callbackPort=8088)
736 client1.startService()
737 client1.callback = onNotification1
738 client1.deferred = defer.Deferred()
739 client2 = gateway.GatewayClient(baseURI, callbackPort=8089)
740 client2.startService()
741 client2.callback = onNotification2
742 client2.deferred = defer.Deferred()
743
744
745 d = self.client.create()
746 d.addCallback(cb)
747 d.addCallback(cb2)
748 d.addCallback(cb3)
749 dl = defer.gatherResults([d, client1.deferred, client2.deferred])
750 return dl
751
752
753 def test_subscribeNonExisting(self):
754 def cb(err):
755 self.assertEqual('403', err.status)
756
757 d = self.client.subscribe('xmpp:%s?node=test' % component)
758 self.assertFailure(d, error.Error)
759 d.addCallback(cb)
760 return d
761
762
763 def test_subscribeRootGetNotification(self):
764
765 def clean(rootNode):
766 return self.client.unsubscribe(rootNode)
767
768 def onNotification(data, headers):
769 self.client.deferred.callback(None)
770
771 def cb(response):
772 xmppURI = response['uri']
773 jid, nodeIdentifier = gateway.getServiceAndNode(xmppURI)
774 rootNode = gateway.getXMPPURI(jid, '')
775
776 d = self.client.subscribe(rootNode)
777 d.addCallback(lambda _: self.addCleanup(clean, rootNode))
778 d.addCallback(lambda _: xmppURI)
779 return d
780
781 def cb2(xmppURI):
782 return self.client.publish(TEST_ENTRY, xmppURI)
783
784
785 self.client.callback = onNotification
786 self.client.deferred = defer.Deferred()
787 d = self.client.create()
788 d.addCallback(cb)
789 d.addCallback(cb2)
790 return defer.gatherResults([d, self.client.deferred])
791
792
793 def test_unsubscribeNonExisting(self):
794 def cb(err):
795 self.assertEqual('403', err.status)
796
797 d = self.client.unsubscribe('xmpp:%s?node=test' % component)
798 self.assertFailure(d, error.Error)
799 d.addCallback(cb)
800 return d
801
802
803 def test_items(self):
804 def cb(response):
805 xmppURI = response['uri']
806 d = self.client.items(xmppURI)
807 return d
808
809 d = self.client.publish(TEST_ENTRY)
810 d.addCallback(cb)
811 return d
812
813
814 def test_itemsMaxItems(self):
815 def cb(response):
816 xmppURI = response['uri']
817 d = self.client.items(xmppURI, 2)
818 return d
819
820 d = self.client.publish(TEST_ENTRY)
821 d.addCallback(cb)
822 return d