Mercurial > libervia-pubsub
comparison src/test/test_backend.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_backend.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.backend}. | |
55 """ | |
56 | |
57 from zope.interface import implements | |
58 from zope.interface.verify import verifyObject | |
59 | |
60 from twisted.internet import defer | |
61 from twisted.trial import unittest | |
62 from twisted.words.protocols.jabber import jid | |
63 from twisted.words.protocols.jabber.error import StanzaError | |
64 | |
65 from wokkel import iwokkel, pubsub | |
66 | |
67 from sat_pubsub import backend, error, iidavoll, const | |
68 | |
69 OWNER = jid.JID('owner@example.com') | |
70 OWNER_FULL = jid.JID('owner@example.com/home') | |
71 SERVICE = jid.JID('test.example.org') | |
72 NS_PUBSUB = 'http://jabber.org/protocol/pubsub' | |
73 | |
74 class BackendTest(unittest.TestCase): | |
75 | |
76 def test_interfaceIBackend(self): | |
77 self.assertTrue(verifyObject(iidavoll.IBackendService, | |
78 backend.BackendService(None))) | |
79 | |
80 | |
81 def test_deleteNode(self): | |
82 class TestNode: | |
83 nodeIdentifier = 'to-be-deleted' | |
84 def getAffiliation(self, entity): | |
85 if entity.userhostJID() == OWNER: | |
86 return defer.succeed('owner') | |
87 | |
88 class TestStorage: | |
89 def __init__(self): | |
90 self.deleteCalled = [] | |
91 | |
92 def getNode(self, nodeIdentifier): | |
93 return defer.succeed(TestNode()) | |
94 | |
95 def deleteNode(self, nodeIdentifier): | |
96 if nodeIdentifier in ['to-be-deleted']: | |
97 self.deleteCalled.append(nodeIdentifier) | |
98 return defer.succeed(None) | |
99 else: | |
100 return defer.fail(error.NodeNotFound()) | |
101 | |
102 def preDelete(data): | |
103 self.assertFalse(self.storage.deleteCalled) | |
104 preDeleteCalled.append(data) | |
105 return defer.succeed(None) | |
106 | |
107 def cb(result): | |
108 self.assertEquals(1, len(preDeleteCalled)) | |
109 data = preDeleteCalled[-1] | |
110 self.assertEquals('to-be-deleted', data['node'].nodeIdentifier) | |
111 self.assertTrue(self.storage.deleteCalled) | |
112 | |
113 self.storage = TestStorage() | |
114 self.backend = backend.BackendService(self.storage) | |
115 | |
116 preDeleteCalled = [] | |
117 | |
118 self.backend.registerPreDelete(preDelete) | |
119 d = self.backend.deleteNode('to-be-deleted', OWNER_FULL) | |
120 d.addCallback(cb) | |
121 return d | |
122 | |
123 | |
124 def test_deleteNodeRedirect(self): | |
125 uri = 'xmpp:%s?;node=test2' % (SERVICE.full(),) | |
126 | |
127 class TestNode: | |
128 nodeIdentifier = 'to-be-deleted' | |
129 def getAffiliation(self, entity): | |
130 if entity.userhostJID() == OWNER: | |
131 return defer.succeed('owner') | |
132 | |
133 class TestStorage: | |
134 def __init__(self): | |
135 self.deleteCalled = [] | |
136 | |
137 def getNode(self, nodeIdentifier): | |
138 return defer.succeed(TestNode()) | |
139 | |
140 def deleteNode(self, nodeIdentifier): | |
141 if nodeIdentifier in ['to-be-deleted']: | |
142 self.deleteCalled.append(nodeIdentifier) | |
143 return defer.succeed(None) | |
144 else: | |
145 return defer.fail(error.NodeNotFound()) | |
146 | |
147 def preDelete(data): | |
148 self.assertFalse(self.storage.deleteCalled) | |
149 preDeleteCalled.append(data) | |
150 return defer.succeed(None) | |
151 | |
152 def cb(result): | |
153 self.assertEquals(1, len(preDeleteCalled)) | |
154 data = preDeleteCalled[-1] | |
155 self.assertEquals('to-be-deleted', data['node'].nodeIdentifier) | |
156 self.assertEquals(uri, data['redirectURI']) | |
157 self.assertTrue(self.storage.deleteCalled) | |
158 | |
159 self.storage = TestStorage() | |
160 self.backend = backend.BackendService(self.storage) | |
161 | |
162 preDeleteCalled = [] | |
163 | |
164 self.backend.registerPreDelete(preDelete) | |
165 d = self.backend.deleteNode('to-be-deleted', OWNER, redirectURI=uri) | |
166 d.addCallback(cb) | |
167 return d | |
168 | |
169 | |
170 def test_createNodeNoID(self): | |
171 """ | |
172 Test creation of a node without a given node identifier. | |
173 """ | |
174 class TestStorage: | |
175 def getDefaultConfiguration(self, nodeType): | |
176 return {} | |
177 | |
178 def createNode(self, nodeIdentifier, requestor, config): | |
179 self.nodeIdentifier = nodeIdentifier | |
180 return defer.succeed(None) | |
181 | |
182 self.storage = TestStorage() | |
183 self.backend = backend.BackendService(self.storage) | |
184 self.storage.backend = self.backend | |
185 | |
186 def checkID(nodeIdentifier): | |
187 self.assertNotIdentical(None, nodeIdentifier) | |
188 self.assertIdentical(self.storage.nodeIdentifier, nodeIdentifier) | |
189 | |
190 d = self.backend.createNode(None, OWNER_FULL) | |
191 d.addCallback(checkID) | |
192 return d | |
193 | |
194 class NodeStore: | |
195 """ | |
196 I just store nodes to pose as an L{IStorage} implementation. | |
197 """ | |
198 def __init__(self, nodes): | |
199 self.nodes = nodes | |
200 | |
201 def getNode(self, nodeIdentifier): | |
202 try: | |
203 return defer.succeed(self.nodes[nodeIdentifier]) | |
204 except KeyError: | |
205 return defer.fail(error.NodeNotFound()) | |
206 | |
207 | |
208 def test_getNotifications(self): | |
209 """ | |
210 Ensure subscribers show up in the notification list. | |
211 """ | |
212 item = pubsub.Item() | |
213 sub = pubsub.Subscription('test', OWNER, 'subscribed') | |
214 | |
215 class TestNode: | |
216 def getSubscriptions(self, state=None): | |
217 return [sub] | |
218 | |
219 def cb(result): | |
220 self.assertEquals(1, len(result)) | |
221 subscriber, subscriptions, items = result[-1] | |
222 | |
223 self.assertEquals(OWNER, subscriber) | |
224 self.assertEquals({sub}, subscriptions) | |
225 self.assertEquals([item], items) | |
226 | |
227 self.storage = self.NodeStore({'test': TestNode()}) | |
228 self.backend = backend.BackendService(self.storage) | |
229 d = self.backend.getNotifications('test', [item]) | |
230 d.addCallback(cb) | |
231 return d | |
232 | |
233 def test_getNotificationsRoot(self): | |
234 """ | |
235 Ensure subscribers to the root node show up in the notification list | |
236 for leaf nodes. | |
237 | |
238 This assumes a flat node relationship model with exactly one collection | |
239 node: the root node. Each leaf node is automatically a child node | |
240 of the root node. | |
241 """ | |
242 item = pubsub.Item() | |
243 subRoot = pubsub.Subscription('', OWNER, 'subscribed') | |
244 | |
245 class TestNode: | |
246 def getSubscriptions(self, state=None): | |
247 return [] | |
248 | |
249 class TestRootNode: | |
250 def getSubscriptions(self, state=None): | |
251 return [subRoot] | |
252 | |
253 def cb(result): | |
254 self.assertEquals(1, len(result)) | |
255 subscriber, subscriptions, items = result[-1] | |
256 self.assertEquals(OWNER, subscriber) | |
257 self.assertEquals({subRoot}, subscriptions) | |
258 self.assertEquals([item], items) | |
259 | |
260 self.storage = self.NodeStore({'test': TestNode(), | |
261 '': TestRootNode()}) | |
262 self.backend = backend.BackendService(self.storage) | |
263 d = self.backend.getNotifications('test', [item]) | |
264 d.addCallback(cb) | |
265 return d | |
266 | |
267 | |
268 def test_getNotificationsMultipleNodes(self): | |
269 """ | |
270 Ensure that entities that subscribe to a leaf node as well as the | |
271 root node get exactly one notification. | |
272 """ | |
273 item = pubsub.Item() | |
274 sub = pubsub.Subscription('test', OWNER, 'subscribed') | |
275 subRoot = pubsub.Subscription('', OWNER, 'subscribed') | |
276 | |
277 class TestNode: | |
278 def getSubscriptions(self, state=None): | |
279 return [sub] | |
280 | |
281 class TestRootNode: | |
282 def getSubscriptions(self, state=None): | |
283 return [subRoot] | |
284 | |
285 def cb(result): | |
286 self.assertEquals(1, len(result)) | |
287 subscriber, subscriptions, items = result[-1] | |
288 | |
289 self.assertEquals(OWNER, subscriber) | |
290 self.assertEquals({sub, subRoot}, subscriptions) | |
291 self.assertEquals([item], items) | |
292 | |
293 self.storage = self.NodeStore({'test': TestNode(), | |
294 '': TestRootNode()}) | |
295 self.backend = backend.BackendService(self.storage) | |
296 d = self.backend.getNotifications('test', [item]) | |
297 d.addCallback(cb) | |
298 return d | |
299 | |
300 | |
301 def test_getDefaultConfiguration(self): | |
302 """ | |
303 L{backend.BackendService.getDefaultConfiguration} should return | |
304 a deferred that fires a dictionary with configuration values. | |
305 """ | |
306 | |
307 class TestStorage: | |
308 def getDefaultConfiguration(self, nodeType): | |
309 return { | |
310 "pubsub#persist_items": True, | |
311 "pubsub#deliver_payloads": True} | |
312 | |
313 def cb(options): | |
314 self.assertIn("pubsub#persist_items", options) | |
315 self.assertEqual(True, options["pubsub#persist_items"]) | |
316 | |
317 self.backend = backend.BackendService(TestStorage()) | |
318 d = self.backend.getDefaultConfiguration('leaf') | |
319 d.addCallback(cb) | |
320 return d | |
321 | |
322 | |
323 def test_getNodeConfiguration(self): | |
324 class testNode: | |
325 nodeIdentifier = 'node' | |
326 def getConfiguration(self): | |
327 return {'pubsub#deliver_payloads': True, | |
328 'pubsub#persist_items': False} | |
329 | |
330 class testStorage: | |
331 def getNode(self, nodeIdentifier): | |
332 return defer.succeed(testNode()) | |
333 | |
334 def cb(options): | |
335 self.assertIn("pubsub#deliver_payloads", options) | |
336 self.assertEqual(True, options["pubsub#deliver_payloads"]) | |
337 self.assertIn("pubsub#persist_items", options) | |
338 self.assertEqual(False, options["pubsub#persist_items"]) | |
339 | |
340 self.storage = testStorage() | |
341 self.backend = backend.BackendService(self.storage) | |
342 self.storage.backend = self.backend | |
343 | |
344 d = self.backend.getNodeConfiguration('node') | |
345 d.addCallback(cb) | |
346 return d | |
347 | |
348 | |
349 def test_setNodeConfiguration(self): | |
350 class testNode: | |
351 nodeIdentifier = 'node' | |
352 def getAffiliation(self, entity): | |
353 if entity.userhostJID() == OWNER: | |
354 return defer.succeed('owner') | |
355 def setConfiguration(self, options): | |
356 self.options = options | |
357 | |
358 class testStorage: | |
359 def __init__(self): | |
360 self.nodes = {'node': testNode()} | |
361 def getNode(self, nodeIdentifier): | |
362 return defer.succeed(self.nodes[nodeIdentifier]) | |
363 | |
364 def checkOptions(node): | |
365 options = node.options | |
366 self.assertIn("pubsub#deliver_payloads", options) | |
367 self.assertEqual(True, options["pubsub#deliver_payloads"]) | |
368 self.assertIn("pubsub#persist_items", options) | |
369 self.assertEqual(False, options["pubsub#persist_items"]) | |
370 | |
371 def cb(result): | |
372 d = self.storage.getNode('node') | |
373 d.addCallback(checkOptions) | |
374 return d | |
375 | |
376 self.storage = testStorage() | |
377 self.backend = backend.BackendService(self.storage) | |
378 self.storage.backend = self.backend | |
379 | |
380 options = {'pubsub#deliver_payloads': True, | |
381 'pubsub#persist_items': False} | |
382 | |
383 d = self.backend.setNodeConfiguration('node', options, OWNER_FULL) | |
384 d.addCallback(cb) | |
385 return d | |
386 | |
387 | |
388 def test_publishNoID(self): | |
389 """ | |
390 Test publish request with an item without a node identifier. | |
391 """ | |
392 class TestNode: | |
393 nodeType = 'leaf' | |
394 nodeIdentifier = 'node' | |
395 def getAffiliation(self, entity): | |
396 if entity.userhostJID() == OWNER: | |
397 return defer.succeed('owner') | |
398 def getConfiguration(self): | |
399 return {'pubsub#deliver_payloads': True, | |
400 'pubsub#persist_items': False, | |
401 const.OPT_PUBLISH_MODEL: const.VAL_PMODEL_OPEN} | |
402 | |
403 class TestStorage: | |
404 def getNode(self, nodeIdentifier): | |
405 return defer.succeed(TestNode()) | |
406 | |
407 def checkID(notification): | |
408 self.assertNotIdentical(None, notification['items'][0][2]['id']) | |
409 | |
410 self.storage = TestStorage() | |
411 self.backend = backend.BackendService(self.storage) | |
412 self.storage.backend = self.backend | |
413 | |
414 self.backend.registerNotifier(checkID) | |
415 | |
416 items = [pubsub.Item()] | |
417 d = self.backend.publish('node', items, OWNER_FULL) | |
418 return d | |
419 | |
420 | |
421 def test_notifyOnSubscription(self): | |
422 """ | |
423 Test notification of last published item on subscription. | |
424 """ | |
425 ITEM = "<item xmlns='%s' id='1'/>" % NS_PUBSUB | |
426 | |
427 class TestNode: | |
428 implements(iidavoll.ILeafNode) | |
429 nodeIdentifier = 'node' | |
430 nodeType = 'leaf' | |
431 def getAffiliation(self, entity): | |
432 if entity is OWNER: | |
433 return defer.succeed('owner') | |
434 def getConfiguration(self): | |
435 return {'pubsub#deliver_payloads': True, | |
436 'pubsub#persist_items': False, | |
437 'pubsub#send_last_published_item': 'on_sub', | |
438 const.OPT_ACCESS_MODEL: const.VAL_AMODEL_OPEN} | |
439 def getItems(self, authorized_groups, unrestricted, maxItems): | |
440 return defer.succeed([(ITEM, const.VAL_AMODEL_OPEN, None)]) | |
441 def addSubscription(self, subscriber, state, options): | |
442 self.subscription = pubsub.Subscription('node', subscriber, | |
443 state, options) | |
444 return defer.succeed(None) | |
445 def getSubscription(self, subscriber): | |
446 return defer.succeed(self.subscription) | |
447 def getNodeOwner(self): | |
448 return defer.succeed(OWNER) | |
449 | |
450 class TestStorage: | |
451 def getNode(self, nodeIdentifier): | |
452 return defer.succeed(TestNode()) | |
453 | |
454 def cb(data): | |
455 self.assertEquals('node', data['node'].nodeIdentifier) | |
456 self.assertEquals([ITEM], data['items']) | |
457 self.assertEquals(OWNER, data['subscription'].subscriber) | |
458 | |
459 self.storage = TestStorage() | |
460 self.backend = backend.BackendService(self.storage) | |
461 self.storage.backend = self.backend | |
462 | |
463 class Roster(object): | |
464 def getRoster(self, owner): | |
465 return {} | |
466 self.backend.roster = Roster() | |
467 | |
468 d1 = defer.Deferred() | |
469 d1.addCallback(cb) | |
470 self.backend.registerNotifier(d1.callback) | |
471 d2 = self.backend.subscribe('node', OWNER, OWNER_FULL) | |
472 return defer.gatherResults([d1, d2]) | |
473 | |
474 test_notifyOnSubscription.timeout = 2 | |
475 | |
476 | |
477 | |
478 class BaseTestBackend(object): | |
479 """ | |
480 Base class for backend stubs. | |
481 """ | |
482 | |
483 def supportsPublisherAffiliation(self): | |
484 return True | |
485 | |
486 | |
487 def supportsOutcastAffiliation(self): | |
488 return True | |
489 | |
490 | |
491 def supportsPersistentItems(self): | |
492 return True | |
493 | |
494 | |
495 def supportsInstantNodes(self): | |
496 return True | |
497 | |
498 def supportsItemAccess(self): | |
499 return True | |
500 | |
501 def supportsAutoCreate(self): | |
502 return True | |
503 | |
504 def supportsCreatorCheck(self): | |
505 return True | |
506 | |
507 def supportsGroupBlog(self): | |
508 return True | |
509 | |
510 def registerNotifier(self, observerfn, *args, **kwargs): | |
511 return | |
512 | |
513 | |
514 def registerPreDelete(self, preDeleteFn): | |
515 return | |
516 | |
517 | |
518 | |
519 class PubSubResourceFromBackendTest(unittest.TestCase): | |
520 | |
521 def test_interface(self): | |
522 resource = backend.PubSubResourceFromBackend(BaseTestBackend()) | |
523 self.assertTrue(verifyObject(iwokkel.IPubSubResource, resource)) | |
524 | |
525 | |
526 def test_preDelete(self): | |
527 """ | |
528 Test pre-delete sending out notifications to subscribers. | |
529 """ | |
530 | |
531 class TestBackend(BaseTestBackend): | |
532 preDeleteFn = None | |
533 | |
534 def registerPreDelete(self, preDeleteFn): | |
535 self.preDeleteFn = preDeleteFn | |
536 | |
537 def getSubscribers(self, nodeIdentifier): | |
538 return defer.succeed([OWNER]) | |
539 | |
540 def notifyDelete(service, nodeIdentifier, subscribers, | |
541 redirectURI=None): | |
542 self.assertEqual(SERVICE, service) | |
543 self.assertEqual('test', nodeIdentifier) | |
544 self.assertEqual([OWNER], subscribers) | |
545 self.assertIdentical(None, redirectURI) | |
546 d1.callback(None) | |
547 | |
548 d1 = defer.Deferred() | |
549 resource = backend.PubSubResourceFromBackend(TestBackend()) | |
550 resource.serviceJID = SERVICE | |
551 resource.pubsubService = pubsub.PubSubService() | |
552 resource.pubsubService.notifyDelete = notifyDelete | |
553 self.assertTrue(verifyObject(iwokkel.IPubSubResource, resource)) | |
554 self.assertNotIdentical(None, resource.backend.preDeleteFn) | |
555 | |
556 class TestNode: | |
557 implements(iidavoll.ILeafNode) | |
558 nodeIdentifier = 'test' | |
559 nodeType = 'leaf' | |
560 | |
561 data = {'node': TestNode()} | |
562 d2 = resource.backend.preDeleteFn(data) | |
563 return defer.DeferredList([d1, d2], fireOnOneErrback=1) | |
564 | |
565 | |
566 def test_preDeleteRedirect(self): | |
567 """ | |
568 Test pre-delete sending out notifications to subscribers. | |
569 """ | |
570 | |
571 uri = 'xmpp:%s?;node=test2' % (SERVICE.full(),) | |
572 | |
573 class TestBackend(BaseTestBackend): | |
574 preDeleteFn = None | |
575 | |
576 def registerPreDelete(self, preDeleteFn): | |
577 self.preDeleteFn = preDeleteFn | |
578 | |
579 def getSubscribers(self, nodeIdentifier): | |
580 return defer.succeed([OWNER]) | |
581 | |
582 def notifyDelete(service, nodeIdentifier, subscribers, | |
583 redirectURI=None): | |
584 self.assertEqual(SERVICE, service) | |
585 self.assertEqual('test', nodeIdentifier) | |
586 self.assertEqual([OWNER], subscribers) | |
587 self.assertEqual(uri, redirectURI) | |
588 d1.callback(None) | |
589 | |
590 d1 = defer.Deferred() | |
591 resource = backend.PubSubResourceFromBackend(TestBackend()) | |
592 resource.serviceJID = SERVICE | |
593 resource.pubsubService = pubsub.PubSubService() | |
594 resource.pubsubService.notifyDelete = notifyDelete | |
595 self.assertTrue(verifyObject(iwokkel.IPubSubResource, resource)) | |
596 self.assertNotIdentical(None, resource.backend.preDeleteFn) | |
597 | |
598 class TestNode: | |
599 implements(iidavoll.ILeafNode) | |
600 nodeIdentifier = 'test' | |
601 nodeType = 'leaf' | |
602 | |
603 data = {'node': TestNode(), | |
604 'redirectURI': uri} | |
605 d2 = resource.backend.preDeleteFn(data) | |
606 return defer.DeferredList([d1, d2], fireOnOneErrback=1) | |
607 | |
608 | |
609 def test_unsubscribeNotSubscribed(self): | |
610 """ | |
611 Test unsubscription request when not subscribed. | |
612 """ | |
613 | |
614 class TestBackend(BaseTestBackend): | |
615 def unsubscribe(self, nodeIdentifier, subscriber, requestor): | |
616 return defer.fail(error.NotSubscribed()) | |
617 | |
618 def cb(e): | |
619 self.assertEquals('unexpected-request', e.condition) | |
620 | |
621 resource = backend.PubSubResourceFromBackend(TestBackend()) | |
622 request = pubsub.PubSubRequest() | |
623 request.sender = OWNER | |
624 request.recipient = SERVICE | |
625 request.nodeIdentifier = 'test' | |
626 request.subscriber = OWNER | |
627 d = resource.unsubscribe(request) | |
628 self.assertFailure(d, StanzaError) | |
629 d.addCallback(cb) | |
630 return d | |
631 | |
632 | |
633 def test_getInfo(self): | |
634 """ | |
635 Test retrieving node information. | |
636 """ | |
637 | |
638 class TestBackend(BaseTestBackend): | |
639 def getNodeType(self, nodeIdentifier): | |
640 return defer.succeed('leaf') | |
641 | |
642 def getNodeMetaData(self, nodeIdentifier): | |
643 return defer.succeed({'pubsub#persist_items': True}) | |
644 | |
645 def cb(info): | |
646 self.assertIn('type', info) | |
647 self.assertEquals('leaf', info['type']) | |
648 self.assertIn('meta-data', info) | |
649 self.assertEquals({'pubsub#persist_items': True}, info['meta-data']) | |
650 | |
651 resource = backend.PubSubResourceFromBackend(TestBackend()) | |
652 d = resource.getInfo(OWNER, SERVICE, 'test') | |
653 d.addCallback(cb) | |
654 return d | |
655 | |
656 | |
657 def test_getConfigurationOptions(self): | |
658 class TestBackend(BaseTestBackend): | |
659 nodeOptions = { | |
660 "pubsub#persist_items": | |
661 {"type": "boolean", | |
662 "label": "Persist items to storage"}, | |
663 "pubsub#deliver_payloads": | |
664 {"type": "boolean", | |
665 "label": "Deliver payloads with event notifications"} | |
666 } | |
667 | |
668 resource = backend.PubSubResourceFromBackend(TestBackend()) | |
669 options = resource.getConfigurationOptions() | |
670 self.assertIn("pubsub#persist_items", options) | |
671 | |
672 | |
673 def test_default(self): | |
674 class TestBackend(BaseTestBackend): | |
675 def getDefaultConfiguration(self, nodeType): | |
676 options = {"pubsub#persist_items": True, | |
677 "pubsub#deliver_payloads": True, | |
678 "pubsub#send_last_published_item": 'on_sub', | |
679 } | |
680 return defer.succeed(options) | |
681 | |
682 def cb(options): | |
683 self.assertEquals(True, options["pubsub#persist_items"]) | |
684 | |
685 resource = backend.PubSubResourceFromBackend(TestBackend()) | |
686 request = pubsub.PubSubRequest() | |
687 request.sender = OWNER | |
688 request.recipient = SERVICE | |
689 request.nodeType = 'leaf' | |
690 d = resource.default(request) | |
691 d.addCallback(cb) | |
692 return d |