~ntt-pf-lab/nova/monkey_patch_notification

« back to all changes in this revision

Viewing changes to vendor/Twisted-10.0.0/twisted/test/test_jelly.py

  • Committer: Jesse Andrews
  • Date: 2010-05-28 06:05:26 UTC
  • Revision ID: git-v1:bf6e6e718cdc7488e2da87b21e258ccc065fe499
initial commit

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (c) 2001-2009 Twisted Matrix Laboratories.
 
2
# See LICENSE for details.
 
3
 
 
4
"""
 
5
Test cases for L{jelly} object serialization.
 
6
"""
 
7
 
 
8
import datetime
 
9
 
 
10
try:
 
11
    import decimal
 
12
except ImportError:
 
13
    decimal = None
 
14
 
 
15
from twisted.spread import jelly, pb
 
16
from twisted.python.compat import set, frozenset
 
17
 
 
18
from twisted.trial import unittest
 
19
 
 
20
 
 
21
 
 
22
class TestNode(object, jelly.Jellyable):
 
23
    """
 
24
    An object to test jellyfying of new style class instances.
 
25
    """
 
26
    classAttr = 4
 
27
 
 
28
    def __init__(self, parent=None):
 
29
        if parent:
 
30
            self.id = parent.id + 1
 
31
            parent.children.append(self)
 
32
        else:
 
33
            self.id = 1
 
34
        self.parent = parent
 
35
        self.children = []
 
36
 
 
37
 
 
38
 
 
39
class A:
 
40
    """
 
41
    Dummy class.
 
42
    """
 
43
 
 
44
    def amethod(self):
 
45
        """
 
46
        Method tp be used in serialization tests.
 
47
        """
 
48
 
 
49
 
 
50
 
 
51
def afunc(self):
 
52
    """
 
53
    A dummy function to test function serialization.
 
54
    """
 
55
 
 
56
 
 
57
 
 
58
class B:
 
59
    """
 
60
    Dummy class.
 
61
    """
 
62
 
 
63
    def bmethod(self):
 
64
        """
 
65
        Method to be used in serialization tests.
 
66
        """
 
67
 
 
68
 
 
69
 
 
70
class C:
 
71
    """
 
72
    Dummy class.
 
73
    """
 
74
 
 
75
    def cmethod(self):
 
76
        """
 
77
        Method to be used in serialization tests.
 
78
        """
 
79
 
 
80
 
 
81
 
 
82
class D(object):
 
83
    """
 
84
    Dummy new-style class.
 
85
    """
 
86
 
 
87
 
 
88
 
 
89
class SimpleJellyTest:
 
90
    def __init__(self, x, y):
 
91
        self.x = x
 
92
        self.y = y
 
93
 
 
94
    def isTheSameAs(self, other):
 
95
        return self.__dict__ == other.__dict__
 
96
 
 
97
 
 
98
 
 
99
class JellyTestCase(unittest.TestCase):
 
100
    """
 
101
    Testcases for L{jelly} module serialization.
 
102
 
 
103
    @cvar decimalData: serialized version of decimal data, to be used in tests.
 
104
    @type decimalData: C{list}
 
105
    """
 
106
 
 
107
    def _testSecurity(self, inputList, atom):
 
108
        """
 
109
        Helper test method to test security options for a type.
 
110
 
 
111
        @param inputList: a sample input for the type.
 
112
        @param inputList: C{list}
 
113
 
 
114
        @param atom: atom identifier for the type.
 
115
        @type atom: C{str}
 
116
        """
 
117
        c = jelly.jelly(inputList)
 
118
        taster = jelly.SecurityOptions()
 
119
        taster.allowBasicTypes()
 
120
        # By default, it should succeed
 
121
        jelly.unjelly(c, taster)
 
122
        taster.allowedTypes.pop(atom)
 
123
        # But it should raise an exception when disallowed
 
124
        self.assertRaises(jelly.InsecureJelly, jelly.unjelly, c, taster)
 
125
 
 
126
 
 
127
    def test_methodSelfIdentity(self):
 
128
        a = A()
 
129
        b = B()
 
130
        a.bmethod = b.bmethod
 
131
        b.a = a
 
132
        im_ = jelly.unjelly(jelly.jelly(b)).a.bmethod
 
133
        self.assertEquals(im_.im_class, im_.im_self.__class__)
 
134
 
 
135
 
 
136
    def test_methodsNotSelfIdentity(self):
 
137
        """
 
138
        If a class change after an instance has been created, L{jelly.unjelly}
 
139
        shoud raise a C{TypeError} when trying to unjelly the instance.
 
140
        """
 
141
        a = A()
 
142
        b = B()
 
143
        c = C()
 
144
        a.bmethod = c.cmethod
 
145
        b.a = a
 
146
        savecmethod = C.cmethod
 
147
        del C.cmethod
 
148
        try:
 
149
            self.assertRaises(TypeError, jelly.unjelly, jelly.jelly(b))
 
150
        finally:
 
151
            C.cmethod = savecmethod
 
152
 
 
153
 
 
154
    def test_newStyle(self):
 
155
        n = D()
 
156
        n.x = 1
 
157
        n2 = D()
 
158
        n.n2 = n2
 
159
        n.n3 = n2
 
160
        c = jelly.jelly(n)
 
161
        m = jelly.unjelly(c)
 
162
        self.assertIsInstance(m, D)
 
163
        self.assertIdentical(m.n2, m.n3)
 
164
 
 
165
 
 
166
    def test_typeOldStyle(self):
 
167
        """
 
168
        Test that an old style class type can be jellied and unjellied
 
169
        to the original type.
 
170
        """
 
171
        t = [C]
 
172
        r = jelly.unjelly(jelly.jelly(t))
 
173
        self.assertEquals(t, r)
 
174
 
 
175
 
 
176
    def test_typeNewStyle(self):
 
177
        """
 
178
        Test that a new style class type can be jellied and unjellied
 
179
        to the original type.
 
180
        """
 
181
        t = [D]
 
182
        r = jelly.unjelly(jelly.jelly(t))
 
183
        self.assertEquals(t, r)
 
184
 
 
185
 
 
186
    def test_typeBuiltin(self):
 
187
        """
 
188
        Test that a builtin type can be jellied and unjellied to the original
 
189
        type.
 
190
        """
 
191
        t = [str]
 
192
        r = jelly.unjelly(jelly.jelly(t))
 
193
        self.assertEquals(t, r)
 
194
 
 
195
 
 
196
    def test_dateTime(self):
 
197
        dtn = datetime.datetime.now()
 
198
        dtd = datetime.datetime.now() - dtn
 
199
        input = [dtn, dtd]
 
200
        c = jelly.jelly(input)
 
201
        output = jelly.unjelly(c)
 
202
        self.assertEquals(input, output)
 
203
        self.assertNotIdentical(input, output)
 
204
 
 
205
 
 
206
    def test_decimal(self):
 
207
        """
 
208
        Jellying L{decimal.Decimal} instances and then unjellying the result
 
209
        should produce objects which represent the values of the original
 
210
        inputs.
 
211
        """
 
212
        inputList = [decimal.Decimal('9.95'),
 
213
                     decimal.Decimal(0),
 
214
                     decimal.Decimal(123456),
 
215
                     decimal.Decimal('-78.901')]
 
216
        c = jelly.jelly(inputList)
 
217
        output = jelly.unjelly(c)
 
218
        self.assertEquals(inputList, output)
 
219
        self.assertNotIdentical(inputList, output)
 
220
 
 
221
 
 
222
    decimalData = ['list', ['decimal', 995, -2], ['decimal', 0, 0],
 
223
                           ['decimal', 123456, 0], ['decimal', -78901, -3]]
 
224
 
 
225
 
 
226
    def test_decimalUnjelly(self):
 
227
        """
 
228
        Unjellying the s-expressions produced by jelly for L{decimal.Decimal}
 
229
        instances should result in L{decimal.Decimal} instances with the values
 
230
        represented by the s-expressions.
 
231
 
 
232
        This test also verifies that C{self.decimalData} contains valid jellied
 
233
        data.  This is important since L{test_decimalMissing} re-uses
 
234
        C{self.decimalData} and is expected to be unable to produce
 
235
        L{decimal.Decimal} instances even though the s-expression correctly
 
236
        represents a list of them.
 
237
        """
 
238
        expected = [decimal.Decimal('9.95'),
 
239
                    decimal.Decimal(0),
 
240
                    decimal.Decimal(123456),
 
241
                    decimal.Decimal('-78.901')]
 
242
        output = jelly.unjelly(self.decimalData)
 
243
        self.assertEquals(output, expected)
 
244
 
 
245
 
 
246
    def test_decimalMissing(self):
 
247
        """
 
248
        If decimal is unavailable on the unjelly side, L{jelly.unjelly} should
 
249
        gracefully return L{jelly.Unpersistable} objects.
 
250
        """
 
251
        self.patch(jelly, 'decimal', None)
 
252
        output = jelly.unjelly(self.decimalData)
 
253
        self.assertEquals(len(output), 4)
 
254
        for i in range(4):
 
255
            self.assertIsInstance(output[i], jelly.Unpersistable)
 
256
        self.assertEquals(output[0].reason,
 
257
            "Could not unpersist decimal: 9.95")
 
258
        self.assertEquals(output[1].reason,
 
259
            "Could not unpersist decimal: 0")
 
260
        self.assertEquals(output[2].reason,
 
261
            "Could not unpersist decimal: 123456")
 
262
        self.assertEquals(output[3].reason,
 
263
            "Could not unpersist decimal: -78.901")
 
264
 
 
265
 
 
266
    def test_decimalSecurity(self):
 
267
        """
 
268
        By default, C{decimal} objects should be allowed by
 
269
        L{jelly.SecurityOptions}. If not allowed, L{jelly.unjelly} should raise
 
270
        L{jelly.InsecureJelly} when trying to unjelly it.
 
271
        """
 
272
        inputList = [decimal.Decimal('9.95')]
 
273
        self._testSecurity(inputList, "decimal")
 
274
 
 
275
    if decimal is None:
 
276
        skipReason = "decimal not available"
 
277
        test_decimal.skip = skipReason
 
278
        test_decimalUnjelly.skip = skipReason
 
279
        test_decimalSecurity.skip = skipReason
 
280
 
 
281
 
 
282
    def test_set(self):
 
283
        """
 
284
        Jellying C{set} instances and then unjellying the result
 
285
        should produce objects which represent the values of the original
 
286
        inputs.
 
287
        """
 
288
        inputList = [set([1, 2, 3])]
 
289
        output = jelly.unjelly(jelly.jelly(inputList))
 
290
        self.assertEquals(inputList, output)
 
291
        self.assertNotIdentical(inputList, output)
 
292
 
 
293
 
 
294
    def test_frozenset(self):
 
295
        """
 
296
        Jellying C{frozenset} instances and then unjellying the result
 
297
        should produce objects which represent the values of the original
 
298
        inputs.
 
299
        """
 
300
        inputList = [frozenset([1, 2, 3])]
 
301
        output = jelly.unjelly(jelly.jelly(inputList))
 
302
        self.assertEquals(inputList, output)
 
303
        self.assertNotIdentical(inputList, output)
 
304
 
 
305
 
 
306
    def test_setSecurity(self):
 
307
        """
 
308
        By default, C{set} objects should be allowed by
 
309
        L{jelly.SecurityOptions}. If not allowed, L{jelly.unjelly} should raise
 
310
        L{jelly.InsecureJelly} when trying to unjelly it.
 
311
        """
 
312
        inputList = [set([1, 2, 3])]
 
313
        self._testSecurity(inputList, "set")
 
314
 
 
315
 
 
316
    def test_frozensetSecurity(self):
 
317
        """
 
318
        By default, C{frozenset} objects should be allowed by
 
319
        L{jelly.SecurityOptions}. If not allowed, L{jelly.unjelly} should raise
 
320
        L{jelly.InsecureJelly} when trying to unjelly it.
 
321
        """
 
322
        inputList = [frozenset([1, 2, 3])]
 
323
        self._testSecurity(inputList, "frozenset")
 
324
 
 
325
 
 
326
    def test_oldSets(self):
 
327
        """
 
328
        Test jellying C{sets.Set}: it should serialize to the same thing as
 
329
        C{set} jelly, and be unjellied as C{set} if available.
 
330
        """
 
331
        inputList = [jelly._sets.Set([1, 2, 3])]
 
332
        inputJelly = jelly.jelly(inputList)
 
333
        self.assertEquals(inputJelly, jelly.jelly([set([1, 2, 3])]))
 
334
        output = jelly.unjelly(inputJelly)
 
335
        # Even if the class is different, it should coerce to the same list
 
336
        self.assertEquals(list(inputList[0]), list(output[0]))
 
337
        if set is jelly._sets.Set:
 
338
            self.assertIsInstance(output[0], jelly._sets.Set)
 
339
        else:
 
340
            self.assertIsInstance(output[0], set)
 
341
 
 
342
 
 
343
    def test_oldImmutableSets(self):
 
344
        """
 
345
        Test jellying C{sets.ImmutableSet}: it should serialize to the same
 
346
        thing as C{frozenset} jelly, and be unjellied as C{frozenset} if
 
347
        available.
 
348
        """
 
349
        inputList = [jelly._sets.ImmutableSet([1, 2, 3])]
 
350
        inputJelly = jelly.jelly(inputList)
 
351
        self.assertEquals(inputJelly, jelly.jelly([frozenset([1, 2, 3])]))
 
352
        output = jelly.unjelly(inputJelly)
 
353
        # Even if the class is different, it should coerce to the same list
 
354
        self.assertEquals(list(inputList[0]), list(output[0]))
 
355
        if frozenset is jelly._sets.ImmutableSet:
 
356
            self.assertIsInstance(output[0], jelly._sets.ImmutableSet)
 
357
        else:
 
358
            self.assertIsInstance(output[0], frozenset)
 
359
 
 
360
 
 
361
    def test_simple(self):
 
362
        """
 
363
        Simplest test case.
 
364
        """
 
365
        self.failUnless(SimpleJellyTest('a', 'b').isTheSameAs(
 
366
                        SimpleJellyTest('a', 'b')))
 
367
        a = SimpleJellyTest(1, 2)
 
368
        cereal = jelly.jelly(a)
 
369
        b = jelly.unjelly(cereal)
 
370
        self.failUnless(a.isTheSameAs(b))
 
371
 
 
372
 
 
373
    def test_identity(self):
 
374
        """
 
375
        Test to make sure that objects retain identity properly.
 
376
        """
 
377
        x = []
 
378
        y = (x)
 
379
        x.append(y)
 
380
        x.append(y)
 
381
        self.assertIdentical(x[0], x[1])
 
382
        self.assertIdentical(x[0][0], x)
 
383
        s = jelly.jelly(x)
 
384
        z = jelly.unjelly(s)
 
385
        self.assertIdentical(z[0], z[1])
 
386
        self.assertIdentical(z[0][0], z)
 
387
 
 
388
 
 
389
    def test_unicode(self):
 
390
        x = unicode('blah')
 
391
        y = jelly.unjelly(jelly.jelly(x))
 
392
        self.assertEquals(x, y)
 
393
        self.assertEquals(type(x), type(y))
 
394
 
 
395
 
 
396
    def test_stressReferences(self):
 
397
        reref = []
 
398
        toplevelTuple = ({'list': reref}, reref)
 
399
        reref.append(toplevelTuple)
 
400
        s = jelly.jelly(toplevelTuple)
 
401
        z = jelly.unjelly(s)
 
402
        self.assertIdentical(z[0]['list'], z[1])
 
403
        self.assertIdentical(z[0]['list'][0], z)
 
404
 
 
405
 
 
406
    def test_moreReferences(self):
 
407
        a = []
 
408
        t = (a,)
 
409
        a.append((t,))
 
410
        s = jelly.jelly(t)
 
411
        z = jelly.unjelly(s)
 
412
        self.assertIdentical(z[0][0][0], z)
 
413
 
 
414
 
 
415
    def test_typeSecurity(self):
 
416
        """
 
417
        Test for type-level security of serialization.
 
418
        """
 
419
        taster = jelly.SecurityOptions()
 
420
        dct = jelly.jelly({})
 
421
        self.assertRaises(jelly.InsecureJelly, jelly.unjelly, dct, taster)
 
422
 
 
423
 
 
424
    def test_newStyleClasses(self):
 
425
        j = jelly.jelly(D)
 
426
        uj = jelly.unjelly(D)
 
427
        self.assertIdentical(D, uj)
 
428
 
 
429
 
 
430
    def test_lotsaTypes(self):
 
431
        """
 
432
        Test for all types currently supported in jelly
 
433
        """
 
434
        a = A()
 
435
        jelly.unjelly(jelly.jelly(a))
 
436
        jelly.unjelly(jelly.jelly(a.amethod))
 
437
        items = [afunc, [1, 2, 3], not bool(1), bool(1), 'test', 20.3,
 
438
                 (1, 2, 3), None, A, unittest, {'a': 1}, A.amethod]
 
439
        for i in items:
 
440
            self.assertEquals(i, jelly.unjelly(jelly.jelly(i)))
 
441
 
 
442
 
 
443
    def test_setState(self):
 
444
        global TupleState
 
445
        class TupleState:
 
446
            def __init__(self, other):
 
447
                self.other = other
 
448
            def __getstate__(self):
 
449
                return (self.other,)
 
450
            def __setstate__(self, state):
 
451
                self.other = state[0]
 
452
            def __hash__(self):
 
453
                return hash(self.other)
 
454
        a = A()
 
455
        t1 = TupleState(a)
 
456
        t2 = TupleState(a)
 
457
        t3 = TupleState((t1, t2))
 
458
        d = {t1: t1, t2: t2, t3: t3, "t3": t3}
 
459
        t3prime = jelly.unjelly(jelly.jelly(d))["t3"]
 
460
        self.assertIdentical(t3prime.other[0].other, t3prime.other[1].other)
 
461
 
 
462
 
 
463
    def test_classSecurity(self):
 
464
        """
 
465
        Test for class-level security of serialization.
 
466
        """
 
467
        taster = jelly.SecurityOptions()
 
468
        taster.allowInstancesOf(A, B)
 
469
        a = A()
 
470
        b = B()
 
471
        c = C()
 
472
        # add a little complexity to the data
 
473
        a.b = b
 
474
        a.c = c
 
475
        # and a backreference
 
476
        a.x = b
 
477
        b.c = c
 
478
        # first, a friendly insecure serialization
 
479
        friendly = jelly.jelly(a, taster)
 
480
        x = jelly.unjelly(friendly, taster)
 
481
        self.assertIsInstance(x.c, jelly.Unpersistable)
 
482
        # now, a malicious one
 
483
        mean = jelly.jelly(a)
 
484
        self.assertRaises(jelly.InsecureJelly, jelly.unjelly, mean, taster)
 
485
        self.assertIdentical(x.x, x.b, "Identity mismatch")
 
486
        # test class serialization
 
487
        friendly = jelly.jelly(A, taster)
 
488
        x = jelly.unjelly(friendly, taster)
 
489
        self.assertIdentical(x, A, "A came back: %s" % x)
 
490
 
 
491
 
 
492
    def test_unjellyable(self):
 
493
        """
 
494
        Test that if Unjellyable is used to deserialize a jellied object,
 
495
        state comes out right.
 
496
        """
 
497
        class JellyableTestClass(jelly.Jellyable):
 
498
            pass
 
499
        jelly.setUnjellyableForClass(JellyableTestClass, jelly.Unjellyable)
 
500
        input = JellyableTestClass()
 
501
        input.attribute = 'value'
 
502
        output = jelly.unjelly(jelly.jelly(input))
 
503
        self.assertEquals(output.attribute, 'value')
 
504
        self.assertIsInstance(output, jelly.Unjellyable)
 
505
 
 
506
 
 
507
    def test_persistentStorage(self):
 
508
        perst = [{}, 1]
 
509
        def persistentStore(obj, jel, perst = perst):
 
510
            perst[1] = perst[1] + 1
 
511
            perst[0][perst[1]] = obj
 
512
            return str(perst[1])
 
513
 
 
514
        def persistentLoad(pidstr, unj, perst = perst):
 
515
            pid = int(pidstr)
 
516
            return perst[0][pid]
 
517
 
 
518
        a = SimpleJellyTest(1, 2)
 
519
        b = SimpleJellyTest(3, 4)
 
520
        c = SimpleJellyTest(5, 6)
 
521
 
 
522
        a.b = b
 
523
        a.c = c
 
524
        c.b = b
 
525
 
 
526
        jel = jelly.jelly(a, persistentStore = persistentStore)
 
527
        x = jelly.unjelly(jel, persistentLoad = persistentLoad)
 
528
 
 
529
        self.assertIdentical(x.b, x.c.b)
 
530
        self.failUnless(perst[0], "persistentStore was not called.")
 
531
        self.assertIdentical(x.b, a.b, "Persistent storage identity failure.")
 
532
 
 
533
 
 
534
    def test_newStyleClassesAttributes(self):
 
535
        n = TestNode()
 
536
        n1 = TestNode(n)
 
537
        n11 = TestNode(n1)
 
538
        n2 = TestNode(n)
 
539
        # Jelly it
 
540
        jel = jelly.jelly(n)
 
541
        m = jelly.unjelly(jel)
 
542
        # Check that it has been restored ok
 
543
        self._check_newstyle(n, m)
 
544
 
 
545
 
 
546
    def _check_newstyle(self, a, b):
 
547
        self.assertEqual(a.id, b.id)
 
548
        self.assertEqual(a.classAttr, 4)
 
549
        self.assertEqual(b.classAttr, 4)
 
550
        self.assertEqual(len(a.children), len(b.children))
 
551
        for x, y in zip(a.children, b.children):
 
552
            self._check_newstyle(x, y)
 
553
 
 
554
 
 
555
 
 
556
class ClassA(pb.Copyable, pb.RemoteCopy):
 
557
    def __init__(self):
 
558
        self.ref = ClassB(self)
 
559
 
 
560
 
 
561
 
 
562
class ClassB(pb.Copyable, pb.RemoteCopy):
 
563
    def __init__(self, ref):
 
564
        self.ref = ref
 
565
 
 
566
 
 
567
 
 
568
class CircularReferenceTestCase(unittest.TestCase):
 
569
    """
 
570
    Tests for circular references handling in the jelly/unjelly process.
 
571
    """
 
572
 
 
573
    def test_simpleCircle(self):
 
574
        jelly.setUnjellyableForClass(ClassA, ClassA)
 
575
        jelly.setUnjellyableForClass(ClassB, ClassB)
 
576
        a = jelly.unjelly(jelly.jelly(ClassA()))
 
577
        self.assertIdentical(a.ref.ref, a,
 
578
            "Identity not preserved in circular reference")
 
579
 
 
580
 
 
581
    def test_circleWithInvoker(self):
 
582
        class DummyInvokerClass:
 
583
            pass
 
584
        dummyInvoker = DummyInvokerClass()
 
585
        dummyInvoker.serializingPerspective = None
 
586
        a0 = ClassA()
 
587
        jelly.setUnjellyableForClass(ClassA, ClassA)
 
588
        jelly.setUnjellyableForClass(ClassB, ClassB)
 
589
        j = jelly.jelly(a0, invoker=dummyInvoker)
 
590
        a1 = jelly.unjelly(j)
 
591
        self.failUnlessIdentical(a1.ref.ref, a1,
 
592
            "Identity not preserved in circular reference")
 
593
 
 
594
 
 
595
    def test_set(self):
 
596
        """
 
597
        Check that a C{set} can contain a circular reference and be serialized
 
598
        and unserialized without losing the reference.
 
599
        """
 
600
        s = set()
 
601
        a = SimpleJellyTest(s, None)
 
602
        s.add(a)
 
603
        res = jelly.unjelly(jelly.jelly(a))
 
604
        self.assertIsInstance(res.x, set)
 
605
        self.assertEquals(list(res.x), [res])
 
606
 
 
607
 
 
608
    def test_frozenset(self):
 
609
        """
 
610
        Check that a C{frozenset} can contain a circular reference and be
 
611
        serializeserialized without losing the reference.
 
612
        """
 
613
        a = SimpleJellyTest(None, None)
 
614
        s = frozenset([a])
 
615
        a.x = s
 
616
        res = jelly.unjelly(jelly.jelly(a))
 
617
        self.assertIsInstance(res.x, frozenset)
 
618
        self.assertEquals(list(res.x), [res])