comparison idavoll/test/test_backend.py @ 206:274a45d2a5ab

Implement root collection that includes all leaf nodes.
author Ralph Meijer <ralphm@ik.nu>
date Mon, 04 Aug 2008 13:47:10 +0000
parents e6b710bf2b24
children 7f3ffb7a1a9e
comparison
equal deleted inserted replaced
205:e6b710bf2b24 206:274a45d2a5ab
2 # See LICENSE for details. 2 # See LICENSE for details.
3 3
4 """ 4 """
5 Tests for L{idavoll.backend}. 5 Tests for L{idavoll.backend}.
6 """ 6 """
7
8 from zope.interface import implements
9 from zope.interface.verify import verifyObject
7 10
8 from twisted.internet import defer 11 from twisted.internet import defer
9 from twisted.trial import unittest 12 from twisted.trial import unittest
10 from twisted.words.protocols.jabber import jid 13 from twisted.words.protocols.jabber import jid
11 from twisted.words.protocols.jabber.error import StanzaError 14 from twisted.words.protocols.jabber.error import StanzaError
12 15
13 from wokkel import pubsub 16 from wokkel import pubsub
14 17
15 from idavoll import backend, error 18 from idavoll import backend, error, iidavoll
16 19
17 OWNER = jid.JID('owner@example.com') 20 OWNER = jid.JID('owner@example.com')
18 NS_PUBSUB = 'http://jabber.org/protocol/pubsub' 21 NS_PUBSUB = 'http://jabber.org/protocol/pubsub'
19 22
20 class BackendTest(unittest.TestCase): 23 class BackendTest(unittest.TestCase):
24
25 def test_interfaceIBackend(self):
26 self.assertTrue(verifyObject(iidavoll.IBackendService,
27 backend.BackendService(None)))
28
29
21 def test_deleteNode(self): 30 def test_deleteNode(self):
22 class testNode: 31 class TestNode:
23 nodeIdentifier = 'to-be-deleted' 32 nodeIdentifier = 'to-be-deleted'
24 def getAffiliation(self, entity): 33 def getAffiliation(self, entity):
25 if entity is OWNER: 34 if entity is OWNER:
26 return defer.succeed('owner') 35 return defer.succeed('owner')
27 36
28 class testStorage: 37 class TestStorage:
29 def getNode(self, nodeIdentifier): 38 def getNode(self, nodeIdentifier):
30 return defer.succeed(testNode()) 39 return defer.succeed(TestNode())
31 40
32 def deleteNode(self, nodeIdentifier): 41 def deleteNode(self, nodeIdentifier):
33 if nodeIdentifier in ['to-be-deleted']: 42 if nodeIdentifier in ['to-be-deleted']:
34 self.deleteCalled = True 43 self.deleteCalled = True
35 return defer.succeed(None) 44 return defer.succeed(None)
42 51
43 def cb(result): 52 def cb(result):
44 self.assertTrue(self.preDeleteCalled) 53 self.assertTrue(self.preDeleteCalled)
45 self.assertTrue(self.storage.deleteCalled) 54 self.assertTrue(self.storage.deleteCalled)
46 55
47 self.storage = testStorage() 56 self.storage = TestStorage()
48 self.backend = backend.BackendService(self.storage) 57 self.backend = backend.BackendService(self.storage)
49 self.storage.backend = self.backend 58 self.storage.backend = self.backend
50 59
51 self.preDeleteCalled = False 60 self.preDeleteCalled = False
52 self.deleteCalled = False 61 self.deleteCalled = False
59 68
60 def test_createNodeNoID(self): 69 def test_createNodeNoID(self):
61 """ 70 """
62 Test creation of a node without a given node identifier. 71 Test creation of a node without a given node identifier.
63 """ 72 """
64 class testStorage: 73 class TestStorage:
65 def createNode(self, nodeIdentifier, requestor): 74 def getDefaultConfiguration(self, nodeType):
75 return {}
76
77 def createNode(self, nodeIdentifier, requestor, config):
66 self.nodeIdentifier = nodeIdentifier 78 self.nodeIdentifier = nodeIdentifier
67 return defer.succeed(None) 79 return defer.succeed(None)
68 80
69 self.storage = testStorage() 81 self.storage = TestStorage()
70 self.backend = backend.BackendService(self.storage) 82 self.backend = backend.BackendService(self.storage)
71 self.storage.backend = self.backend 83 self.storage.backend = self.backend
72 84
73 def checkID(nodeIdentifier): 85 def checkID(nodeIdentifier):
74 self.assertNotIdentical(None, nodeIdentifier) 86 self.assertNotIdentical(None, nodeIdentifier)
76 88
77 d = self.backend.createNode(None, OWNER) 89 d = self.backend.createNode(None, OWNER)
78 d.addCallback(checkID) 90 d.addCallback(checkID)
79 return d 91 return d
80 92
93 class NodeStore:
94 """
95 I just store nodes to pose as an L{IStorage} implementation.
96 """
97 def __init__(self, nodes):
98 self.nodes = nodes
99
100 def getNode(self, nodeIdentifier):
101 try:
102 return defer.succeed(self.nodes[nodeIdentifier])
103 except KeyError:
104 return defer.fail(error.NodeNotFound())
105
106
107 def test_getNotifications(self):
108 """
109 Ensure subscribers show up in the notification list.
110 """
111 item = pubsub.Item()
112 sub = pubsub.Subscription('test', OWNER, 'subscribed')
113
114 class TestNode:
115 def getSubscriptions(self, state=None):
116 return [sub]
117
118 def cb(result):
119 self.assertEquals(1, len(result))
120 subscriber, subscriptions, items = result[-1]
121
122 self.assertEquals(OWNER, subscriber)
123 self.assertEquals(set([sub]), subscriptions)
124 self.assertEquals([item], items)
125
126 self.storage = self.NodeStore({'test': TestNode()})
127 self.backend = backend.BackendService(self.storage)
128 d = self.backend.getNotifications('test', [item])
129 d.addCallback(cb)
130 return d
131
132 def test_getNotificationsRoot(self):
133 """
134 Ensure subscribers to the root node show up in the notification list
135 for leaf nodes.
136
137 This assumes a flat node relationship model with exactly one collection
138 node: the root node. Each leaf node is automatically a child node
139 of the root node.
140 """
141 item = pubsub.Item()
142 subRoot = pubsub.Subscription('', OWNER, 'subscribed')
143
144 class TestNode:
145 def getSubscriptions(self, state=None):
146 return []
147
148 class TestRootNode:
149 def getSubscriptions(self, state=None):
150 return [subRoot]
151
152 def cb(result):
153 self.assertEquals(1, len(result))
154 subscriber, subscriptions, items = result[-1]
155 self.assertEquals(OWNER, subscriber)
156 self.assertEquals(set([subRoot]), subscriptions)
157 self.assertEquals([item], items)
158
159 self.storage = self.NodeStore({'test': TestNode(),
160 '': TestRootNode()})
161 self.backend = backend.BackendService(self.storage)
162 d = self.backend.getNotifications('test', [item])
163 d.addCallback(cb)
164 return d
165
166
167 def test_getNotificationsMultipleNodes(self):
168 """
169 Ensure that entities that subscribe to a leaf node as well as the
170 root node get exactly one notification.
171 """
172 item = pubsub.Item()
173 sub = pubsub.Subscription('test', OWNER, 'subscribed')
174 subRoot = pubsub.Subscription('', OWNER, 'subscribed')
175
176 class TestNode:
177 def getSubscriptions(self, state=None):
178 return [sub]
179
180 class TestRootNode:
181 def getSubscriptions(self, state=None):
182 return [subRoot]
183
184 def cb(result):
185 self.assertEquals(1, len(result))
186 subscriber, subscriptions, items = result[-1]
187
188 self.assertEquals(OWNER, subscriber)
189 self.assertEquals(set([sub, subRoot]), subscriptions)
190 self.assertEquals([item], items)
191
192 self.storage = self.NodeStore({'test': TestNode(),
193 '': TestRootNode()})
194 self.backend = backend.BackendService(self.storage)
195 d = self.backend.getNotifications('test', [item])
196 d.addCallback(cb)
197 return d
198
81 199
82 def test_getDefaultConfiguration(self): 200 def test_getDefaultConfiguration(self):
83 """ 201 """
84 L{backend.BackendService.getDefaultConfiguration} should return 202 L{backend.BackendService.getDefaultConfiguration} should return
85 a deferred that fires a dictionary with configuration values. 203 a deferred that fires a dictionary with configuration values.
86 """ 204 """
205
206 class TestStorage:
207 def getDefaultConfiguration(self, nodeType):
208 return {
209 "pubsub#persist_items": True,
210 "pubsub#deliver_payloads": True}
87 211
88 def cb(options): 212 def cb(options):
89 self.assertIn("pubsub#persist_items", options) 213 self.assertIn("pubsub#persist_items", options)
90 self.assertEqual(True, options["pubsub#persist_items"]) 214 self.assertEqual(True, options["pubsub#persist_items"])
91 215
92 self.backend = backend.BackendService(None) 216 self.backend = backend.BackendService(TestStorage())
93 d = self.backend.getDefaultConfiguration() 217 d = self.backend.getDefaultConfiguration('leaf')
94 d.addCallback(cb) 218 d.addCallback(cb)
95 return d 219 return d
96 220
97 221
98 def test_getNodeConfiguration(self): 222 def test_getNodeConfiguration(self):
162 286
163 def test_publishNoID(self): 287 def test_publishNoID(self):
164 """ 288 """
165 Test publish request with an item without a node identifier. 289 Test publish request with an item without a node identifier.
166 """ 290 """
167 class testNode: 291 class TestNode:
292 nodeType = 'leaf'
168 nodeIdentifier = 'node' 293 nodeIdentifier = 'node'
169 def getAffiliation(self, entity): 294 def getAffiliation(self, entity):
170 if entity is OWNER: 295 if entity is OWNER:
171 return defer.succeed('owner') 296 return defer.succeed('owner')
172 def getConfiguration(self): 297 def getConfiguration(self):
173 return {'pubsub#deliver_payloads': True, 298 return {'pubsub#deliver_payloads': True,
174 'pubsub#persist_items': False} 299 'pubsub#persist_items': False}
175 300
176 class testStorage: 301 class TestStorage:
177 def getNode(self, nodeIdentifier): 302 def getNode(self, nodeIdentifier):
178 return defer.succeed(testNode()) 303 return defer.succeed(TestNode())
179 304
180 def checkID(notification): 305 def checkID(notification):
181 self.assertNotIdentical(None, notification['items'][0]['id']) 306 self.assertNotIdentical(None, notification['items'][0]['id'])
182 307
183 self.storage = testStorage() 308 self.storage = TestStorage()
184 self.backend = backend.BackendService(self.storage) 309 self.backend = backend.BackendService(self.storage)
185 self.storage.backend = self.backend 310 self.storage.backend = self.backend
186 311
187 self.backend.registerNotifier(checkID) 312 self.backend.registerNotifier(checkID)
188 313
195 """ 320 """
196 Test notification of last published item on subscription. 321 Test notification of last published item on subscription.
197 """ 322 """
198 ITEM = "<item xmlns='%s' id='1'/>" % NS_PUBSUB 323 ITEM = "<item xmlns='%s' id='1'/>" % NS_PUBSUB
199 324
200 class testNode: 325 class TestNode:
326 implements(iidavoll.ILeafNode)
201 nodeIdentifier = 'node' 327 nodeIdentifier = 'node'
328 nodeType = 'leaf'
202 def getAffiliation(self, entity): 329 def getAffiliation(self, entity):
203 if entity is OWNER: 330 if entity is OWNER:
204 return defer.succeed('owner') 331 return defer.succeed('owner')
205 def getConfiguration(self): 332 def getConfiguration(self):
206 return {'pubsub#deliver_payloads': True, 333 return {'pubsub#deliver_payloads': True,
207 'pubsub#persist_items': False, 334 'pubsub#persist_items': False,
208 'pubsub#send_last_published_item': 'on_sub'} 335 'pubsub#send_last_published_item': 'on_sub'}
209 def getItems(self, maxItems): 336 def getItems(self, maxItems):
210 return [ITEM] 337 return [ITEM]
211 def addSubscription(self, subscriber, state): 338 def addSubscription(self, subscriber, state, options):
339 self.subscription = pubsub.Subscription('node', subscriber,
340 state, options)
212 return defer.succeed(None) 341 return defer.succeed(None)
213 342 def getSubscription(self, subscriber):
214 class testStorage: 343 return defer.succeed(self.subscription)
344
345 class TestStorage:
215 def getNode(self, nodeIdentifier): 346 def getNode(self, nodeIdentifier):
216 return defer.succeed(testNode()) 347 return defer.succeed(TestNode())
217 348
218 def cb(data): 349 def cb(data):
219 self.assertEquals('node', data['nodeIdentifier']) 350 self.assertEquals('node', data['nodeIdentifier'])
220 self.assertEquals([ITEM], data['items']) 351 self.assertEquals([ITEM], data['items'])
221 self.assertEquals(OWNER, data['subscriber']) 352 self.assertEquals(OWNER, data['subscription'].subscriber)
222 353
223 self.storage = testStorage() 354 self.storage = TestStorage()
224 self.backend = backend.BackendService(self.storage) 355 self.backend = backend.BackendService(self.storage)
225 self.storage.backend = self.backend 356 self.storage.backend = self.backend
226 357
227 d1 = defer.Deferred() 358 d1 = defer.Deferred()
228 d1.addCallback(cb) 359 d1.addCallback(cb)
309 return d 440 return d
310 441
311 442
312 def test_getConfigurationOptions(self): 443 def test_getConfigurationOptions(self):
313 class TestBackend(BaseTestBackend): 444 class TestBackend(BaseTestBackend):
314 options = { 445 nodeOptions = {
315 "pubsub#persist_items": 446 "pubsub#persist_items":
316 {"type": "boolean", 447 {"type": "boolean",
317 "label": "Persist items to storage"}, 448 "label": "Persist items to storage"},
318 "pubsub#deliver_payloads": 449 "pubsub#deliver_payloads":
319 {"type": "boolean", 450 {"type": "boolean",
325 self.assertIn("pubsub#persist_items", options) 456 self.assertIn("pubsub#persist_items", options)
326 457
327 458
328 def test_getDefaultConfiguration(self): 459 def test_getDefaultConfiguration(self):
329 class TestBackend(BaseTestBackend): 460 class TestBackend(BaseTestBackend):
330 def getDefaultConfiguration(self): 461 def getDefaultConfiguration(self, nodeType):
331 options = {"pubsub#persist_items": True, 462 options = {"pubsub#persist_items": True,
332 "pubsub#deliver_payloads": True, 463 "pubsub#deliver_payloads": True,
333 "pubsub#send_last_published_item": 'on_sub', 464 "pubsub#send_last_published_item": 'on_sub',
334 } 465 }
335 return defer.succeed(options) 466 return defer.succeed(options)
336 467
337 def cb(options): 468 def cb(options):
338 self.assertEquals(True, options["pubsub#persist_items"]) 469 self.assertEquals(True, options["pubsub#persist_items"])
339 470
340 s = backend.PubSubServiceFromBackend(TestBackend()) 471 s = backend.PubSubServiceFromBackend(TestBackend())
341 d = s.getDefaultConfiguration(OWNER, 'test.example.org') 472 d = s.getDefaultConfiguration(OWNER, 'test.example.org', 'leaf')
342 d.addCallback(cb) 473 d.addCallback(cb)
343 return d 474 return d