~wallyworld/lazr.restful/namedpost-url-change-1056666

« back to all changes in this revision

Viewing changes to src/lazr/restful/tests/test_declarations.py

  • Committer: Leonard Richardson
  • Date: 2011-03-09 17:05:42 UTC
  • mfrom: (176.4.16 must-specify-version)
  • Revision ID: leonard.richardson@canonical.com-20110309170542-ptak8uq9ffrov12y
[r=abentley] Make it possible to require an explicit version number for every exported field.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
import unittest
2
 
 
3
1
from zope.component import (
4
2
    adapts, getMultiAdapter, getSiteManager, getUtility, provideUtility)
5
3
from zope.component.interfaces import ComponentLookupError
10
8
from zope.security.management import endInteraction, newInteraction
11
9
 
12
10
from lazr.restful.declarations import (
13
 
    export_as_webservice_entry, exported, export_read_operation,
14
 
    export_write_operation, mutator_for, operation_for_version,
15
 
    operation_parameters)
 
11
    export_as_webservice_entry,
 
12
    exported,
 
13
    export_read_operation,
 
14
    export_write_operation,
 
15
    generate_entry_interfaces,
 
16
    mutator_for,
 
17
    operation_for_version,
 
18
    operation_parameters,
 
19
    )
16
20
from lazr.restful.fields import Reference
17
21
from lazr.restful.interfaces import (
18
22
    IEntry, IResourceGETOperation, IWebServiceConfiguration,
22
26
    AttemptToContributeToNonExportedInterface,
23
27
    ConflictInContributingInterfaces, find_interfaces_and_contributors)
24
28
from lazr.restful._resource import EntryAdapterUtility, EntryResource
25
 
from lazr.restful.testing.webservice import FakeRequest
 
29
from lazr.restful.testing.webservice import (
 
30
    FakeRequest,
 
31
    TestCaseWithWebServiceFixtures,
 
32
    )
26
33
from lazr.restful.testing.helpers import (
27
34
    create_test_module, TestWebServiceConfiguration, register_test_module)
28
35
 
29
36
 
30
 
class ContributingInterfacesTestCase(unittest.TestCase):
 
37
class ContributingInterfacesTestCase(TestCaseWithWebServiceFixtures):
31
38
    """Tests for interfaces that contribute fields/operations to others."""
32
39
 
33
40
    def setUp(self):
34
 
        provideUtility(
35
 
            TestWebServiceConfiguration(), IWebServiceConfiguration)
 
41
        super(ContributingInterfacesTestCase, self).setUp()
36
42
        sm = getSiteManager()
37
 
        sm.registerUtility(
38
 
            ITestServiceRequestBeta, IWebServiceVersion, name='beta')
39
 
        sm.registerUtility(
40
 
            ITestServiceRequest10, IWebServiceVersion, name='1.0')
41
43
        sm.registerAdapter(ProductToHasBugsAdapter)
42
44
        sm.registerAdapter(ProjectToHasBugsAdapter)
43
45
        sm.registerAdapter(ProductToHasBranchesAdapter)
44
46
        sm.registerAdapter(DummyFieldMarshaller)
45
 
        self.beta_request = FakeRequest(version='beta')
46
 
        alsoProvides(
47
 
            self.beta_request, getUtility(IWebServiceVersion, name='beta'))
48
47
        self.one_zero_request = FakeRequest(version='1.0')
49
48
        alsoProvides(
50
49
            self.one_zero_request, getUtility(IWebServiceVersion, name='1.0'))
 
50
        self.two_zero_request = FakeRequest(version='2.0')
 
51
        alsoProvides(
 
52
            self.two_zero_request, getUtility(IWebServiceVersion, name='2.0'))
51
53
        self.product = Product()
52
54
        self.project = Project()
53
55
 
59
61
        # access .bug_count.
60
62
        self.product._bug_count = 10
61
63
        register_test_module('testmod', IProduct, IHasBugs)
62
 
        adapter = getMultiAdapter((self.product, self.beta_request), IEntry)
 
64
        adapter = getMultiAdapter((self.product, self.one_zero_request), IEntry)
63
65
        self.assertEqual(adapter.bug_count, 10)
64
66
 
65
67
    def test_operations(self):
68
70
        self.product._bug_count = 10
69
71
        register_test_module('testmod', IProduct, IHasBugs)
70
72
        adapter = getMultiAdapter(
71
 
            (self.product, self.beta_request),
 
73
            (self.product, self.one_zero_request),
72
74
            IResourceGETOperation, name='getBugsCount')
73
75
        self.assertEqual(adapter(), '10')
74
76
 
75
77
    def test_contributing_interface_with_differences_between_versions(self):
76
 
        # In the 'beta' version, IHasBranches.development_branches is exported
77
 
        # with its original name whereas for the '1.0' version it's exported
78
 
        # as 'development_branch_10'.
 
78
        # In the '1.0' version, IHasBranches.development_branches is exported
 
79
        # with its original name whereas for the '2.0' version it's exported
 
80
        # as 'development_branch_20'.
79
81
        self.product._dev_branch = Branch('A product branch')
80
82
        register_test_module('testmod', IProduct, IHasBranches)
81
 
        adapter = getMultiAdapter((self.product, self.beta_request), IEntry)
 
83
        adapter = getMultiAdapter((self.product, self.one_zero_request), IEntry)
82
84
        self.assertEqual(adapter.development_branch, self.product._dev_branch)
83
85
 
84
86
        adapter = getMultiAdapter(
85
 
            (self.product, self.one_zero_request), IEntry)
 
87
            (self.product, self.two_zero_request), IEntry)
86
88
        self.assertEqual(
87
 
            adapter.development_branch_10, self.product._dev_branch)
 
89
            adapter.development_branch_20, self.product._dev_branch)
88
90
 
89
91
    def test_mutator_for_just_one_version(self):
90
 
        # On the 'beta' version, IHasBranches contributes a read only
91
 
        # development_branch field, but on version '1.0' that field can be
 
92
        # On the '1.0' version, IHasBranches contributes a read only
 
93
        # development_branch field, but on version '2.0' that field can be
92
94
        # modified as we define a mutator for it.
93
95
        self.product._dev_branch = Branch('A product branch')
94
96
        register_test_module('testmod', IProduct, IHasBranches)
95
 
        adapter = getMultiAdapter((self.product, self.beta_request), IEntry)
 
97
        adapter = getMultiAdapter((self.product, self.one_zero_request), IEntry)
96
98
        try:
97
99
            adapter.development_branch = None
98
100
        except AttributeError:
99
101
            pass
100
102
        else:
101
103
            self.fail('IHasBranches.development_branch should be read-only '
102
 
                      'on the beta version')
 
104
                      'on the 1.0 version')
103
105
 
104
106
        adapter = getMultiAdapter(
105
 
            (self.product, self.one_zero_request), IEntry)
106
 
        self.assertEqual(
107
 
            adapter.development_branch_10, self.product._dev_branch)
108
 
        adapter.development_branch_10 = None
109
 
        self.assertEqual(
110
 
            adapter.development_branch_10, None)
 
107
            (self.product, self.two_zero_request), IEntry)
 
108
        self.assertEqual(
 
109
            adapter.development_branch_20, self.product._dev_branch)
 
110
        adapter.development_branch_20 = None
 
111
        self.assertEqual(
 
112
            adapter.development_branch_20, None)
111
113
 
112
114
    def test_contributing_to_multiple_interfaces(self):
113
115
        # Check that the webservice adapter for both IProduct and IProject
115
117
        self.product._bug_count = 10
116
118
        self.project._bug_count = 100
117
119
        register_test_module('testmod', IProduct, IProject, IHasBugs)
118
 
        adapter = getMultiAdapter((self.product, self.beta_request), IEntry)
 
120
        adapter = getMultiAdapter((self.product, self.one_zero_request), IEntry)
119
121
        self.assertEqual(adapter.bug_count, 10)
120
122
 
121
 
        adapter = getMultiAdapter((self.project, self.beta_request), IEntry)
 
123
        adapter = getMultiAdapter((self.project, self.one_zero_request), IEntry)
122
124
        self.assertEqual(adapter.bug_count, 100)
123
125
 
124
126
    def test_multiple_contributing_interfaces(self):
127
129
        self.product._bug_count = 10
128
130
        self.product._dev_branch = Branch('A product branch')
129
131
        register_test_module('testmod', IProduct, IHasBugs, IHasBranches)
130
 
        adapter = getMultiAdapter((self.product, self.beta_request), IEntry)
 
132
        adapter = getMultiAdapter((self.product, self.one_zero_request), IEntry)
131
133
        self.assertEqual(adapter.bug_count, 10)
132
134
        self.assertEqual(adapter.development_branch, self.product._dev_branch)
133
135
 
139
141
        class Empty:
140
142
            implements(IEmpty)
141
143
        register_test_module('testmod', IEmpty)
142
 
        entry_resource = EntryResource(Empty(), self.beta_request)
 
144
        entry_resource = EntryResource(Empty(), self.one_zero_request)
143
145
        self.assertEquals({}, entry_resource.entry._orig_interfaces)
144
146
        self.assertEquals([], entry_resource.redacted_fields)
145
147
 
148
150
        # interface where the field is defined and adapt the context to that
149
151
        # interface before accessing that field.
150
152
        register_test_module('testmod', IProduct, IHasBugs, IHasBranches)
151
 
        entry_resource = EntryResource(self.product, self.beta_request)
 
153
        entry_resource = EntryResource(self.product, self.one_zero_request)
152
154
        self.assertEquals([], entry_resource.redacted_fields)
153
155
 
154
156
    def test_redacted_fields_with_permission_checker(self):
161
163
            secure_product = ProxyFactory(
162
164
                self.product,
163
165
                checker=MultiChecker([(IProduct, 'zope.Public')]))
164
 
            entry_resource = EntryResource(secure_product, self.beta_request)
 
166
            entry_resource = EntryResource(secure_product, self.one_zero_request)
165
167
            self.assertEquals([], entry_resource.redacted_fields)
166
168
        finally:
167
169
            endInteraction()
183
185
        register_test_module('testmod', IProduct, IHasBranches)
184
186
        self.assertRaises(
185
187
            ComponentLookupError,
186
 
            getMultiAdapter, (dummy, self.beta_request), IEntry)
 
188
            getMultiAdapter, (dummy, self.one_zero_request), IEntry)
187
189
 
188
190
    def test_cannot_contribute_to_non_exported_interface(self):
189
191
        # A contributing interface can only contribute to exported interfaces.
218
220
        # different adapters, its type name is that of the main interface and
219
221
        # not one of its contributors.
220
222
        register_test_module('testmod', IProduct, IHasBugs)
221
 
        adapter = getMultiAdapter((self.product, self.beta_request), IEntry)
 
223
        adapter = getMultiAdapter((self.product, self.one_zero_request), IEntry)
222
224
        self.assertEqual(
223
225
            'product', EntryAdapterUtility(adapter.__class__).singular_type)
224
226
 
308
310
    not_exported = TextLine(title=u'Not exported')
309
311
    development_branch = exported(
310
312
        Reference(schema=IBranch, readonly=True),
311
 
        ('1.0', dict(exported_as='development_branch_10')),
312
 
        ('beta', dict(exported_as='development_branch')))
 
313
        ('2.0', dict(exported_as='development_branch_20')),
 
314
        ('1.0', dict(exported_as='development_branch')))
313
315
 
314
316
    @mutator_for(development_branch)
315
317
    @export_write_operation()
316
318
    @operation_parameters(value=TextLine())
317
 
    @operation_for_version('1.0')
 
319
    @operation_for_version('2.0')
318
320
    def set_dev_branch(value):
319
321
        pass
320
322
 
342
344
    adapts(Interface, IHTTPRequest)
343
345
 
344
346
 
345
 
class ITestServiceRequestBeta(IWebServiceVersion):
346
 
    pass
347
 
class ITestServiceRequest10(IWebServiceVersion):
348
 
    pass
 
347
# Classes for TestReqireExplicitVersions
 
348
 
 
349
class IFieldExportedWithoutAsOf(Interface):
 
350
    export_as_webservice_entry()
 
351
 
 
352
    field = exported(TextLine(), exported=True)
 
353
 
 
354
 
 
355
class IFieldExportedToEarliestVersionUsingAsOf(Interface):
 
356
    export_as_webservice_entry()
 
357
 
 
358
    field = exported(TextLine(), as_of='1.0')
 
359
 
 
360
 
 
361
class IFieldExportedToLatestVersionUsingAsOf(Interface):
 
362
    export_as_webservice_entry()
 
363
 
 
364
    field = exported(TextLine(), as_of='2.0')
 
365
 
 
366
 
 
367
class IFieldDefiningAttributesBeforeAsOf(Interface):
 
368
    export_as_webservice_entry()
 
369
 
 
370
    field = exported(TextLine(), ('1.0', dict(exported=True)),
 
371
                     as_of='2.0')
 
372
 
 
373
class IFieldAsOfNonexistentVersion(Interface):
 
374
    export_as_webservice_entry()
 
375
 
 
376
    field = exported(TextLine(), as_of='nosuchversion')
 
377
 
 
378
 
 
379
class IFieldDoubleDefinition(Interface):
 
380
    export_as_webservice_entry()
 
381
 
 
382
    field = exported(TextLine(), ('2.0', dict(exported_as='name2')),
 
383
                     exported_as='name2', as_of='2.0')
 
384
 
 
385
 
 
386
class TestRequireExplicitVersions(TestCaseWithWebServiceFixtures):
 
387
    """Test behavior when require_explicit_versions is True."""
 
388
 
 
389
    def setUp(self):
 
390
        super(TestRequireExplicitVersions, self).setUp()
 
391
        self.utility = getUtility(IWebServiceConfiguration)
 
392
        self.utility.require_explicit_versions = True
 
393
 
 
394
    def _assertRaises(self, exception, func, *args, **kwargs):
 
395
        # Approximate the behavior of testtools assertRaises, which
 
396
        # returns the raised exception. I couldn't get
 
397
        # testtools.TestCase to play nicely with zope's Cleanup class.
 
398
        self.assertRaises(exception, func, *args, **kwargs)
 
399
        try:
 
400
            func(*args, **kwargs)
 
401
        except Exception, e:
 
402
            return e
 
403
 
 
404
    def test_field_exported_as_of_earlier_version_is_exported_in_subsequent_versions(self):
 
405
        # If you export a field as_of version 1.0, it's present in
 
406
        # 1.0's version of the entry and in all subsequent versions.
 
407
        interfaces = generate_entry_interfaces(
 
408
            IFieldExportedToEarliestVersionUsingAsOf, [],
 
409
            *self.utility.active_versions)
 
410
        interface_10 = interfaces[0][1]
 
411
        interface_20 = interfaces[1][1]
 
412
        self.assertEquals(interface_10.names(), ['field'])
 
413
        self.assertEquals(interface_20.names(), ['field'])
 
414
 
 
415
    def test_field_exported_as_of_later_version_is_not_exported_in_earlier_versions(self):
 
416
        # If you export a field as_of version 2.0, it's not present in
 
417
        # 1.0's version of the entry.
 
418
        interfaces = generate_entry_interfaces(
 
419
            IFieldExportedToLatestVersionUsingAsOf, [],
 
420
            *self.utility.active_versions)
 
421
        interface_10 = interfaces[0][1]
 
422
        interface_20 = interfaces[1][1]
 
423
        self.assertEquals(interface_10.names(), [])
 
424
        self.assertEquals(interface_20.names(), ['field'])
 
425
 
 
426
    def test_field_not_exported_using_as_of_fails(self):
 
427
        # If you export a field without specifying as_of, you get an
 
428
        # error.
 
429
        exception = self._assertRaises(
 
430
            ValueError, generate_entry_interfaces,
 
431
            IFieldExportedWithoutAsOf, [], *self.utility.active_versions)
 
432
        self.assertEquals(
 
433
            str(exception),
 
434
            ('Field "field" in interface "IFieldExportedWithoutAsOf": '
 
435
             'Field was exported in version 1.0, but not by using as_of. '
 
436
             'The service configuration requires that you use as_of.')
 
437
            )
 
438
 
 
439
    def test_field_cannot_be_both_exported_and_not_exported(self):
 
440
        # If you use the as_of keyword argument, you can't also set
 
441
        # the exported keyword argument to False.
 
442
        exception = self._assertRaises(
 
443
            ValueError, exported, TextLine(), as_of='1.0', exported=False)
 
444
        self.assertEquals(
 
445
                str(exception),
 
446
                ('as_of=1.0 says to export TextLine, but exported=False '
 
447
                 'says not to.'))
 
448
 
 
449
    def test_field_exported_as_of_nonexistent_version_fails(self):
 
450
        # You can't export a field as_of a nonexistent version.
 
451
        exception = self._assertRaises(
 
452
            ValueError, generate_entry_interfaces,
 
453
            IFieldAsOfNonexistentVersion, [],
 
454
            *self.utility.active_versions)
 
455
        self.assertEquals(
 
456
            str(exception),
 
457
            ('Field "field" in interface "IFieldAsOfNonexistentVersion": '
 
458
             'Unrecognized version "nosuchversion".'))
 
459
 
 
460
    def test_field_exported_with_duplicate_attributes_fails(self):
 
461
        # You can't provide a dictionary of attributes for the
 
462
        # version specified in as_of.
 
463
        exception = self._assertRaises(
 
464
            ValueError, generate_entry_interfaces,
 
465
            IFieldDoubleDefinition, [], *self.utility.active_versions)
 
466
        self.assertEquals(
 
467
            str(exception),
 
468
            ('Field "field" in interface "IFieldDoubleDefinition": '
 
469
             'Duplicate annotations for version "2.0".'))
 
470
 
 
471
    def test_field_with_annotations_that_precede_as_of_fails(self):
 
472
        # You can't provide a dictionary of attributes for a version
 
473
        # preceding the version specified in as_of.
 
474
        exception = self._assertRaises(
 
475
            ValueError, generate_entry_interfaces,
 
476
            IFieldDefiningAttributesBeforeAsOf, [],
 
477
            *self.utility.active_versions)
 
478
        self.assertEquals(
 
479
            str(exception),
 
480
            ('Field "field" in interface '
 
481
             '"IFieldDefiningAttributesBeforeAsOf": Version "1.0" defined '
 
482
             'after the later version "2.0".'))