Mercurial > libervia-pubsub
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 |