~ibid-core/ibid/old-trunk-1.6

« back to all changes in this revision

Viewing changes to ibid/test/test_core.py

  • Committer: Stefano Rivera
  • Date: 2010-02-23 22:11:25 UTC
  • mfrom: (818.5.12 testage)
  • Revision ID: stefano@rivera.za.net-20100223221125-xwfvg0nmrno86nxl
Test suites for ibid.core and ibid.event.
https://code.launchpad.net/~ibid-dev/ibid/testage/+merge/17994

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (c) 2010, Jeremy Thurgood
 
2
# Released under terms of the MIT/X/Expat Licence. See COPYING for details.
 
3
from datetime import datetime, timedelta
 
4
 
 
5
from twisted.trial import unittest
 
6
from twisted.internet import defer, reactor
 
7
 
 
8
import ibid
 
9
from ibid import core, event
 
10
 
 
11
 
 
12
def _defer_cb(dfr, *args, **kw):
 
13
    "Call in the future to allow thread stuff to happen."
 
14
    reactor.callLater(0.01, dfr.callback, *args, **kw)
 
15
 
 
16
 
 
17
class TestProcessor(object):
 
18
    """
 
19
    A processor object stub.
 
20
    """
 
21
    name = 'testprocessor'
 
22
 
 
23
    def __init__(self, proc_func):
 
24
        self.proc_func = proc_func
 
25
 
 
26
    def process(self, event):
 
27
        self.proc_func(event)
 
28
 
 
29
 
 
30
class TestSource(object):
 
31
    """
 
32
    A source object stub.
 
33
    """
 
34
    def __init__(self):
 
35
        self._msgs = []
 
36
 
 
37
    def send(self, response):
 
38
        self._msgs.append(response)
 
39
 
 
40
 
 
41
class TestDispatcher(unittest.TestCase):
 
42
    """
 
43
    Test the Dispatcher class.
 
44
    """
 
45
 
 
46
    def setUp(self):
 
47
        ibid.processors[:] = []
 
48
        ibid.sources.clear()
 
49
        self.dispatcher = core.Dispatcher()
 
50
 
 
51
    def tearDown(self):
 
52
        ibid.processors[:] = []
 
53
        ibid.sources.clear()
 
54
 
 
55
    def _add_processor(self, proc_func):
 
56
        "Add a processor to the dispatch chain."
 
57
        ibid.processors.append(TestProcessor(proc_func))
 
58
 
 
59
    def _ev(self, source='fakesource', type='testmessage'):
 
60
        "Create an event with some default values."
 
61
        return event.Event(source, type)
 
62
 
 
63
    def _defer_assertions(self, callback, result):
 
64
        "Create a deferred to assert things that only happen later."
 
65
        dfr = defer.Deferred()
 
66
        dfr.addCallback(callback, self)
 
67
        _defer_cb(dfr, result)
 
68
        return dfr
 
69
 
 
70
    def _dispatch_and_assert(self, callback, ev):
 
71
        """
 
72
        Dispatch an event and add an assertion callback to the
 
73
        resulting deferred.
 
74
        """
 
75
        dfr = self.dispatcher.dispatch(ev)
 
76
        dfr.addCallback(callback, self)
 
77
        return dfr
 
78
 
 
79
    def test_process_no_processors(self):
 
80
        "With no processors, an event is unmodified."
 
81
        ev = self._ev()
 
82
        pev = self.dispatcher._process(ev)
 
83
        self.assertEqual(ev, pev)
 
84
        self.assertEqual([], pev.responses)
 
85
 
 
86
    def test_dispatch_no_processors(self):
 
87
        "With no processors, an event is unmodified."
 
88
        ev = self._ev()
 
89
        def _cb(_ev, _self):
 
90
            _self.assertEqual(ev, _ev)
 
91
            _self.assertEqual([], _ev.responses)
 
92
        return self._dispatch_and_assert(_cb, ev)
 
93
 
 
94
    def test_process_noop_processor(self):
 
95
        "A passive processor is called, but does not modify."
 
96
        ev = self._ev()
 
97
        procs = [0]
 
98
        def prc(e):
 
99
            procs[0] += 1
 
100
        self._add_processor(prc)
 
101
        pev = self.dispatcher._process(ev)
 
102
        self.assertEqual(ev, pev)
 
103
        self.assertEqual([], pev.responses)
 
104
        self.assertEqual([1], procs)
 
105
        self.assertEqual(False, pev.processed)
 
106
    
 
107
    def test_dispatch_noop_processor(self):
 
108
        "A passive processor is called, but does not modify the event."
 
109
        ev = self._ev()
 
110
        procs = [0]
 
111
        def prc(e):
 
112
            procs[0] += 1
 
113
        self._add_processor(prc)
 
114
        def _cb(_ev, _self):
 
115
            _self.assertEqual(ev, _ev)
 
116
            _self.assertEqual([], _ev.responses)
 
117
            _self.assertEqual([1], procs)
 
118
            _self.assertEqual(False, _ev.processed)
 
119
        return self._dispatch_and_assert(_cb, ev)
 
120
 
 
121
    def test_process_simple_reply(self):
 
122
        "A processor can add a reply."
 
123
        ev = self._ev()
 
124
        def prc(e):
 
125
            e.addresponse(u'foo')
 
126
        self._add_processor(prc)
 
127
        pev = self.dispatcher._process(ev)
 
128
        self.assertEqual(ev, pev)
 
129
        self.assertTrue('complain' not in pev)
 
130
        self.assertEqual([{'reply': u'foo',
 
131
                           'target': None,
 
132
                           'source': 'fakesource',
 
133
                           'address': True,
 
134
                           'conflate': True}], pev.responses)
 
135
        self.assertEqual(True, pev.processed)
 
136
 
 
137
    def test_dispatch_simple_reply(self):
 
138
        "A processor can add a reply."
 
139
        ev = self._ev()
 
140
        def prc(e):
 
141
            e.addresponse(u'foo')
 
142
        self._add_processor(prc)
 
143
        def _cb(_ev, _self):
 
144
            _self.assertEqual(ev, _ev)
 
145
            _self.assertTrue('complain' not in _ev)
 
146
            _self.assertEqual([{'reply': u'foo',
 
147
                                'target': None,
 
148
                                'source': 'fakesource',
 
149
                                'address': True,
 
150
                                'conflate': True}], _ev.responses)
 
151
            _self.assertEqual(True, _ev.processed)
 
152
        return self._dispatch_and_assert(_cb, ev)
 
153
 
 
154
    def test_process_broken_processor(self):
 
155
        "If a processor dies, we complain and carry on."
 
156
        ev = self._ev()
 
157
        def prc(e):
 
158
            assert False
 
159
        self._add_processor(prc)
 
160
        pev = self.dispatcher._process(ev)
 
161
        self.assertEqual(ev, pev)
 
162
        self.assertEqual('exception', pev.complain)
 
163
        self.assertEqual([], pev.responses)
 
164
        self.assertEqual(True, pev.processed)
 
165
 
 
166
    def test_dispatch_broken_processor(self):
 
167
        "If a processor dies, we complain and carry on."
 
168
        ev = self._ev()
 
169
        def prc(e):
 
170
            assert False
 
171
        self._add_processor(prc)
 
172
        def _cb(_ev, _self):
 
173
            _self.assertEqual(ev, _ev)
 
174
            _self.assertEqual('exception', _ev.complain)
 
175
            _self.assertEqual([], _ev.responses)
 
176
            _self.assertEqual(True, _ev.processed)
 
177
        return self._dispatch_and_assert(_cb, ev)
 
178
 
 
179
    def test_process_double_reply(self):
 
180
        "We can add multiple replies to an event."
 
181
        ev = self._ev()
 
182
        def prc(e):
 
183
            e.addresponse(u'foo')
 
184
            e.addresponse(u'bar')
 
185
        self._add_processor(prc)
 
186
        pev = self.dispatcher._process(ev)
 
187
        self.assertEqual(ev, pev)
 
188
        self.assertTrue('complain' not in pev)
 
189
        self.assertEqual([{'reply': u'foo',
 
190
                           'target': None,
 
191
                           'source': 'fakesource',
 
192
                           'address': True,
 
193
                           'conflate': True},
 
194
                          {'reply': u'bar',
 
195
                           'target': None,
 
196
                           'source': 'fakesource',
 
197
                           'address': True,
 
198
                           'conflate': True}], pev.responses)
 
199
        self.assertEqual(True, pev.processed)
 
200
 
 
201
    def test_dispatch_double_reply(self):
 
202
        "We can add multiple replies to an event."
 
203
        ev = self._ev()
 
204
        def prc(e):
 
205
            e.addresponse(u'foo')
 
206
            e.addresponse(u'bar')
 
207
        self._add_processor(prc)
 
208
        def _cb(_ev, _self):
 
209
            _self.assertEqual(ev, _ev)
 
210
            _self.assertTrue('complain' not in _ev)
 
211
            _self.assertEqual([{'reply': u'foo',
 
212
                                'target': None,
 
213
                                'source': 'fakesource',
 
214
                                'address': True,
 
215
                                'conflate': True},
 
216
                               {'reply': u'bar',
 
217
                                'target': None,
 
218
                                'source': 'fakesource',
 
219
                                'address': True,
 
220
                                'conflate': True}], _ev.responses)
 
221
            _self.assertEqual(True, _ev.processed)
 
222
        return self._dispatch_and_assert(_cb, ev)
 
223
 
 
224
    def test_process_reply_send_invalid_source(self):
 
225
        "Messages to invalid sources get silently swallowed."
 
226
        ev = self._ev()
 
227
        def prc(e):
 
228
            e.addresponse(u'foo')
 
229
            e.addresponse(u'bar', source='testsource')
 
230
        self._add_processor(prc)
 
231
        pev = self.dispatcher._process(ev)
 
232
        self.assertEqual(ev, pev)
 
233
        self.assertTrue('complain' not in pev)
 
234
        self.assertEqual([{'reply': u'foo',
 
235
                           'target': None,
 
236
                           'source': 'fakesource',
 
237
                           'address': True,
 
238
                           'conflate': True}], pev.responses)
 
239
        self.assertEqual(True, pev.processed)
 
240
 
 
241
    def test_dispatch_reply_send_invalid_source(self):
 
242
        "Messages to invalid sources get silently swallowed."
 
243
        ev = self._ev()
 
244
        def prc(e):
 
245
            e.addresponse(u'foo')
 
246
            e.addresponse(u'bar', source='testsource')
 
247
        self._add_processor(prc)
 
248
        def _cb(_ev, _self):
 
249
            _self.assertEqual(ev, _ev)
 
250
            _self.assertTrue('complain' not in _ev)
 
251
            _self.assertEqual([{'reply': u'foo',
 
252
                                'target': None,
 
253
                                'source': 'fakesource',
 
254
                                'address': True,
 
255
                                'conflate': True}], _ev.responses)
 
256
            self.assertEqual(True, _ev.processed)
 
257
        return self._dispatch_and_assert(_cb, ev)
 
258
 
 
259
    def test_process_reply_send_valid_source(self):
 
260
        "Messages to other sources get sent."
 
261
        src = TestSource()
 
262
        ibid.sources['testsource'] = src
 
263
        ev = self._ev()
 
264
        def prc(e):
 
265
            e.addresponse(u'foo')
 
266
            e.addresponse(u'bar', source='testsource')
 
267
        self._add_processor(prc)
 
268
        pev = self.dispatcher._process(ev)
 
269
        self.assertEqual(ev, pev)
 
270
        self.assertTrue('complain' not in pev)
 
271
        self.assertEqual([{'reply': u'foo',
 
272
                           'target': None,
 
273
                           'source': 'fakesource',
 
274
                           'address': True,
 
275
                           'conflate': True}], pev.responses)
 
276
        self.assertEqual(True, pev.processed)
 
277
        def _cb(_src, _self):
 
278
            _self.assertEqual([{'reply': u'bar',
 
279
                                'target': None,
 
280
                                'source': 'testsource',
 
281
                                'address': True,
 
282
                                'conflate': True}], _src._msgs)
 
283
        return self._defer_assertions(_cb, src)
 
284
 
 
285
    def test_dispatch_reply_send_valid_source(self):
 
286
        "Messages to other sources get sent."
 
287
        src = TestSource()
 
288
        ibid.sources['testsource'] = src
 
289
        ev = self._ev()
 
290
        def prc(e):
 
291
            e.addresponse(u'foo')
 
292
            e.addresponse(u'bar', source='testsource')
 
293
        self._add_processor(prc)
 
294
        def _cb(_ev, _self):
 
295
            _self.assertEqual(ev, _ev)
 
296
            _self.assertTrue('complain' not in _ev)
 
297
            _self.assertEqual([{'reply': u'foo',
 
298
                                'target': None,
 
299
                                'source': 'fakesource',
 
300
                                'address': True,
 
301
                                'conflate': True}], _ev.responses)
 
302
            _self.assertEqual(True, _ev.processed)
 
303
            _self.assertEqual([{'reply': u'bar',
 
304
                                'target': None,
 
305
                                'source': 'testsource',
 
306
                                'address': True,
 
307
                                'conflate': True}], src._msgs)
 
308
        return self._dispatch_and_assert(_cb, ev)
 
309
 
 
310
    def test_call_later_no_args(self):
 
311
        "Calling later calls stuff later."
 
312
        ev = self._ev()
 
313
        ev.channel = None
 
314
        ev.public = None
 
315
        dfr = defer.Deferred()
 
316
        tm = datetime.now()
 
317
        def _cl(_ev):
 
318
            _ev.did_stuff = True
 
319
            dfr.callback(_ev)
 
320
        def _cb(_ev, _self, _oev):
 
321
            _self.assertTrue(tm + timedelta(seconds=0.01) < datetime.now())
 
322
            _self.assertTrue(_ev.did_stuff)
 
323
            _self.assertFalse(hasattr(_oev, 'did_stuff'))
 
324
        dfr.addCallback(_cb, self, ev)
 
325
        self.dispatcher.call_later(0.01, _cl, ev)
 
326
        return dfr
 
327
 
 
328
    def test_call_later_args(self):
 
329
        "Calling later with args calls stuff later."
 
330
        ev = self._ev()
 
331
        ev.channel = None
 
332
        ev.public = None
 
333
        dfr = defer.Deferred()
 
334
        tm = datetime.now()
 
335
        def _cl(_ev, val):
 
336
            _ev.did_stuff = val
 
337
            dfr.callback(_ev)
 
338
        def _cb(_ev, _self, _oev):
 
339
            _self.assertTrue(tm + timedelta(seconds=0.01) < datetime.now())
 
340
            _self.assertEqual('thingy', _ev.did_stuff)
 
341
            _self.assertFalse(hasattr(_oev, 'did_stuff'))
 
342
        dfr.addCallback(_cb, self, ev)
 
343
        self.dispatcher.call_later(0.01, _cl, ev, 'thingy')
 
344
        return dfr
 
345
 
 
346
    def test_call_later_kwargs(self):
 
347
        "Calling later with kwargs calls stuff later."
 
348
        ev = self._ev()
 
349
        ev.channel = None
 
350
        ev.public = None
 
351
        dfr = defer.Deferred()
 
352
        tm = datetime.now()
 
353
        def _cl(_ev, val='default'):
 
354
            _ev.did_stuff = val
 
355
            dfr.callback(_ev)
 
356
        def _cb(_ev, _self, _oev):
 
357
            _self.assertTrue(tm + timedelta(seconds=0.01) < datetime.now())
 
358
            _self.assertEqual('thingy', _ev.did_stuff)
 
359
            _self.assertFalse(hasattr(_oev, 'did_stuff'))
 
360
        dfr.addCallback(_cb, self, ev)
 
361
        self.dispatcher.call_later(0.01, _cl, ev, val='thingy')
 
362
        return dfr
 
363
 
 
364
    def test_call_later_reply(self):
 
365
        "Calling later can send responses."
 
366
        src = TestSource()
 
367
        ibid.sources['testsource'] = src
 
368
        ev = self._ev()
 
369
        ev.channel = None
 
370
        ev.public = None
 
371
        dfr = defer.Deferred()
 
372
        tm = datetime.now()
 
373
        def _cl(_ev):
 
374
            _ev.addresponse(u'This happens later.', source='testsource')
 
375
            _defer_cb(dfr, _ev)
 
376
        def _cb(_ev, _self, _src):
 
377
            _self.assertTrue(tm + timedelta(seconds=0.01) < datetime.now())
 
378
            _self.assertEqual([{'reply': u'This happens later.',
 
379
                                'target': None,
 
380
                                'source': 'testsource',
 
381
                                'address': True,
 
382
                                'conflate': True}], _src._msgs)
 
383
        dfr.addCallback(_cb, self, src)
 
384
        self.dispatcher.call_later(0.01, _cl, ev)
 
385
        return dfr
 
386
 
 
387
    def test_call_later_multi_reply(self):
 
388
        "Calling later can send many responses."
 
389
        src = TestSource()
 
390
        ibid.sources['fakesource'] = src
 
391
        ibid.sources['testsource'] = src
 
392
        ev = self._ev()
 
393
        ev.channel = None
 
394
        ev.public = None
 
395
        dfr = defer.Deferred()
 
396
        tm = datetime.now()
 
397
        def _cl(_ev):
 
398
            _ev.addresponse(u'This happens later.')
 
399
            _ev.addresponse(u'So does this.', source='testsource')
 
400
            _defer_cb(dfr, _ev)
 
401
        def _cb(_ev, _self, _src):
 
402
            _self.assertTrue(tm + timedelta(seconds=0.01) < datetime.now())
 
403
            # Order is reversed because 'fakesource' waits until
 
404
            # processing is finished.
 
405
            _self.assertEqual([{'reply': u'So does this.',
 
406
                                'target': None,
 
407
                                'source': 'testsource',
 
408
                                'address': True,
 
409
                                'conflate': True},
 
410
                               {'reply': u'This happens later.',
 
411
                                'target': None,
 
412
                                'source': 'fakesource',
 
413
                                'address': True,
 
414
                                'conflate': True},
 
415
                               ], _src._msgs)
 
416
        dfr.addCallback(_cb, self, src)
 
417
        self.dispatcher.call_later(0.01, _cl, ev)
 
418
        return dfr
 
419
 
 
420
# vi: set et sta sw=4 ts=4: