Merge lp:~leonardr/lazr.restful/make-test-class-public into lp:lazr.restful
- make-test-class-public
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Edwin Grubbs |
Approved revision: | 128 |
Merged at revision: | not available |
Proposed branch: | lp:~leonardr/lazr.restful/make-test-class-public |
Merge into: | lp:lazr.restful |
Prerequisite: | lp:~leonardr/lazr.restful/refactor-tag-request-with-version |
Diff against target: |
377 lines (+147/-135) 2 files modified
src/lazr/restful/testing/webservice.py (+138/-3) src/lazr/restful/tests/test_webservice.py (+9/-132) |
To merge this branch: | bzr merge lp:~leonardr/lazr.restful/make-test-class-public |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Edwin Grubbs (community) | code | Approve | |
Review via email: mp+20574@code.launchpad.net |
Commit message
Description of the change
Leonard Richardson (leonardr) wrote : | # |
Edwin Grubbs (edwin-grubbs) wrote : | # |
Hi Leonard,
The changes look good, but I got these errors when running the tests under python2.6. There were even more problems under python2.5.
-Edwin
Running lazr.restful.
Set up lazr.restful.
Set up lazr.restful.
Failure in test /home/egrubbs/
Traceback (most recent call last):
File "/usr/lib/
testMethod()
File "/usr/lib/
raise self.failureExc
AssertionError: Failed doctest test for field.txt
File "/home/
-------
File "/home/
Failed example:
print new_value
Differences (ndiff with -expected +actual):
- "http://
? ^^^^
+ "http:\
? + ^ +++++++
-------
File "/home/
Failed example:
print webservice(
Differences (ndiff with -expected +actual):
HTTP/1.1 209 Content Returned
- ...
+ Status: 209 Content Returned
+ Content-Length: 68
Content-Type: application/json
- ...
+ X-Powered-By: Zope (www.zope.org), Python (www.python.org)
<BLANKLINE>
- "http://
? ^^^
+ "http:\
? + + + ^^^^^^ +
Ran 9 tests with 1 failures and 0 errors in 2.391 seconds.
Running lazr.restful.
Tear down lazr.restful.
Tear down lazr.restful.
Set up lazr.restful.
Set up lazr.restful.
Ran 3 tests with 0 failures and 0 errors in 0.406 seconds.
Running lazr.restful.
Tear down lazr.restful.
Tear down lazr.restful.
Set up lazr.restful.
Leonard Richardson (leonardr) wrote : | # |
I think you're running the tests on an old version of simplejson. Can you run some code to see what version of simplejson you have? Here's what I get:
$ bin/py
>>> import simplejson
>>> simplejson.
'2.0.9'
Also try making this change to setup.py, rerun bin/buildout, and see if the problem goes away.
=== modified file 'setup.py'
--- setup.py 2009-10-07 18:54:39 +0000
+++ setup.py 2010-03-04 14:03:26 +0000
@@ -64,7 +64,7 @@
- 'simplejson',
+ 'simplejson>
'wsgiref',
Edwin Grubbs (edwin-grubbs) wrote : | # |
Hi Leonard,
Updating simplejson fixed it.
merge-approved
-Edwin
Preview Diff
1 | === modified file 'src/lazr/restful/testing/webservice.py' |
2 | --- src/lazr/restful/testing/webservice.py 2010-03-03 13:05:13 +0000 |
3 | +++ src/lazr/restful/testing/webservice.py 2010-03-03 17:07:18 +0000 |
4 | @@ -9,7 +9,11 @@ |
5 | 'ExampleWebServicePublication', |
6 | 'FakeRequest', |
7 | 'FakeResponse', |
8 | + 'IGenericEntry', |
9 | + 'IGenericCollection', |
10 | 'pprint_entry', |
11 | + 'WebServiceTestCase', |
12 | + 'WebServiceTestConfiguration' |
13 | 'WebServiceTestPublication', |
14 | 'WebServiceTestRequest', |
15 | 'TestPublication', |
16 | @@ -19,25 +23,39 @@ |
17 | import os |
18 | import traceback |
19 | import simplejson |
20 | +import sys |
21 | +from types import ModuleType |
22 | import urllib |
23 | +import unittest |
24 | from urlparse import urljoin |
25 | import wsgi_intercept |
26 | |
27 | -from zope.component import adapts, getUtility, queryMultiAdapter |
28 | -from zope.interface import implements |
29 | +from zope.component import ( |
30 | + adapts, getGlobalSiteManager, getUtility, queryMultiAdapter) |
31 | +from zope.configuration import xmlconfig |
32 | +from zope.interface import alsoProvides, implements, Interface |
33 | from zope.publisher.browser import BrowserRequest |
34 | from zope.publisher.interfaces.http import IHTTPApplicationRequest |
35 | from zope.publisher.paste import Application |
36 | from zope.proxy import ProxyBase |
37 | +from zope.schema import TextLine |
38 | from zope.security.checker import ProxyFactory |
39 | +from zope.testing.cleanup import CleanUp |
40 | from zope.traversing.browser.interfaces import IAbsoluteURL |
41 | |
42 | +from lazr.restful.declarations import ( |
43 | + collection_default_content, exported, |
44 | + export_as_webservice_collection, export_as_webservice_entry, |
45 | + export_read_operation, operation_parameters) |
46 | from lazr.restful.interfaces import ( |
47 | IServiceRootResource, IWebServiceClientRequest, |
48 | IWebServiceConfiguration, IWebServiceLayer, IWebServiceVersion) |
49 | from lazr.restful.publisher import ( |
50 | WebServicePublicationMixin, WebServiceRequestTraversal) |
51 | -from lazr.restful.simple import Publication, Request |
52 | +from lazr.restful.simple import ( |
53 | + BaseWebServiceConfiguration, Publication, Request, |
54 | + RootResourceAbsoluteURL, ServiceRootResource) |
55 | +from lazr.restful.utils import tag_request_with_version_name |
56 | |
57 | from lazr.uri import URI |
58 | |
59 | @@ -385,6 +403,121 @@ |
60 | raise ValueError(self.body) |
61 | |
62 | |
63 | +class WebServiceTestConfiguration(BaseWebServiceConfiguration): |
64 | + """A simple configuration for tests that need a running web service.""" |
65 | + implements(IWebServiceConfiguration) |
66 | + show_tracebacks = False |
67 | + active_versions = ['1.0', '2.0'] |
68 | + hostname = "webservice_test" |
69 | + last_version_with_mutator_named_operations = None |
70 | + |
71 | + def createRequest(self, body_instream, environ): |
72 | + request = Request(body_instream, environ) |
73 | + request.setPublication( |
74 | + WebServiceTestPublication(getUtility(IServiceRootResource))) |
75 | + tag_request_with_version_name(request, '2.0') |
76 | + return request |
77 | + |
78 | + |
79 | +class IWebServiceTestRequest10(IWebServiceClientRequest): |
80 | + """A marker interface for requests to the '1.0' web service.""" |
81 | + |
82 | + |
83 | +class IWebServiceTestRequest20(IWebServiceClientRequest): |
84 | + """A marker interface for requests to the '2.0' web service.""" |
85 | + |
86 | + |
87 | +class WebServiceTestCase(CleanUp, unittest.TestCase): |
88 | + """A test case for web service operations.""" |
89 | + |
90 | + testmodule_objects = [] |
91 | + |
92 | + def setUp(self): |
93 | + """Set the component registry with the given model.""" |
94 | + super(WebServiceTestCase, self).setUp() |
95 | + |
96 | + # Register a simple configuration object. |
97 | + webservice_configuration = WebServiceTestConfiguration() |
98 | + sm = getGlobalSiteManager() |
99 | + sm.registerUtility(webservice_configuration) |
100 | + |
101 | + # Register IWebServiceVersions for the |
102 | + # '1.0' and '2.0' web service versions. |
103 | + alsoProvides(IWebServiceTestRequest10, IWebServiceVersion) |
104 | + sm.registerUtility( |
105 | + IWebServiceTestRequest10, IWebServiceVersion, name='1.0') |
106 | + alsoProvides(IWebServiceTestRequest20, IWebServiceVersion) |
107 | + sm.registerUtility( |
108 | + IWebServiceTestRequest20, IWebServiceVersion, name='2.0') |
109 | + |
110 | + # Register a service root resource |
111 | + service_root = ServiceRootResource() |
112 | + sm.registerUtility(service_root, IServiceRootResource) |
113 | + |
114 | + # Register an IAbsoluteURL adapter for the service root resource. |
115 | + sm.registerAdapter( |
116 | + RootResourceAbsoluteURL, |
117 | + [IServiceRootResource, IWebServiceClientRequest], IAbsoluteURL) |
118 | + |
119 | + # Build a test module that exposes the given resource interfaces. |
120 | + testmodule = ModuleType('testmodule') |
121 | + for interface in self.testmodule_objects: |
122 | + setattr(testmodule, interface.__name__, interface) |
123 | + sys.modules['lazr.restful.testmodule'] = testmodule |
124 | + |
125 | + # Register the test module in the ZCML configuration: adapter |
126 | + # classes will be built automatically. |
127 | + xmlconfig.string(""" |
128 | + <configure |
129 | + xmlns="http://namespaces.zope.org/zope" |
130 | + xmlns:webservice="http://namespaces.canonical.com/webservice"> |
131 | + <include package="zope.component" file="meta.zcml" /> |
132 | + <include package="zope.security" file="meta.zcml"/> |
133 | + <include package="lazr.restful" file="meta.zcml" /> |
134 | + <include package="lazr.restful" file="configure.zcml" /> |
135 | + |
136 | + <adapter for="*" |
137 | + factory="zope.traversing.adapters.DefaultTraversable" |
138 | + provides="zope.traversing.interfaces.ITraversable" /> |
139 | + |
140 | + <webservice:register module="lazr.restful.testmodule" /> |
141 | + </configure> |
142 | + """) |
143 | + |
144 | + |
145 | +class IGenericEntry(Interface): |
146 | + """A simple, reusable entry interface for use in tests. |
147 | + |
148 | + The entry publishes one field and one named operation. |
149 | + """ |
150 | + export_as_webservice_entry() |
151 | + |
152 | + # pylint: disable-msg=E0213 |
153 | + a_field = exported( |
154 | + TextLine( |
155 | + title=u'A "field"', |
156 | + description=u'The only field that can be <> 0 in the entry.')) |
157 | + |
158 | + @operation_parameters( |
159 | + message=TextLine(title=u'Message to say')) |
160 | + @export_read_operation() |
161 | + def greet(message): |
162 | + """Print an appropriate greeting based on the message. |
163 | + |
164 | + :param message: This will be included in the greeting. |
165 | + """ |
166 | + |
167 | + |
168 | +class IGenericCollection(Interface): |
169 | + """A simple collection containing `IGenericEntry`, for use in tests.""" |
170 | + export_as_webservice_collection(IGenericEntry) |
171 | + |
172 | + # pylint: disable-msg=E0211 |
173 | + @collection_default_content() |
174 | + def getAll(): |
175 | + """Returns all the entries.""" |
176 | + |
177 | + |
178 | class DummyRootResource: |
179 | """A root resource that does nothing.""" |
180 | implements(IServiceRootResource) |
181 | @@ -403,3 +536,5 @@ |
182 | def __str__(self): |
183 | return "http://dummy" |
184 | __call__ = __str__ |
185 | + |
186 | + |
187 | |
188 | === modified file 'src/lazr/restful/tests/test_webservice.py' |
189 | --- src/lazr/restful/tests/test_webservice.py 2010-03-03 13:05:13 +0000 |
190 | +++ src/lazr/restful/tests/test_webservice.py 2010-03-03 17:07:18 +0000 |
191 | @@ -6,18 +6,14 @@ |
192 | |
193 | from cStringIO import StringIO |
194 | from operator import attrgetter |
195 | -import sys |
196 | -from types import ModuleType |
197 | import unittest |
198 | |
199 | from zope.component import getGlobalSiteManager, getUtility |
200 | -from zope.configuration import xmlconfig |
201 | -from zope.interface import alsoProvides, implements, Interface |
202 | +from zope.interface import implements, Interface |
203 | from zope.publisher.browser import TestRequest |
204 | from zope.schema import Date, Datetime, TextLine |
205 | from zope.security.management import ( |
206 | endInteraction, newInteraction, queryInteraction) |
207 | -from zope.testing.cleanup import CleanUp |
208 | from zope.traversing.browser.interfaces import IAbsoluteURL |
209 | |
210 | from lazr.restful.fields import Reference |
211 | @@ -25,15 +21,11 @@ |
212 | ICollection, IEntry, IEntryResource, IResourceGETOperation, |
213 | IServiceRootResource, IWebServiceConfiguration, |
214 | IWebServiceClientRequest, IWebServiceVersion) |
215 | -from lazr.restful import ( |
216 | - EntryResource, ServiceRootResource, ResourceGETOperation) |
217 | -from lazr.restful.simple import BaseWebServiceConfiguration, Request |
218 | -from lazr.restful.declarations import ( |
219 | - collection_default_content, exported, export_as_webservice_collection, |
220 | - export_as_webservice_entry, export_read_operation, operation_parameters) |
221 | -from lazr.restful.simple import RootResourceAbsoluteURL |
222 | +from lazr.restful import EntryResource, ResourceGETOperation |
223 | +from lazr.restful.declarations import exported, export_as_webservice_entry |
224 | from lazr.restful.testing.webservice import ( |
225 | - create_web_service_request, WebServiceTestPublication) |
226 | + create_web_service_request, IGenericCollection, IGenericEntry, |
227 | + WebServiceTestCase, WebServiceTestPublication) |
228 | from lazr.restful.testing.tales import test_tales |
229 | from lazr.restful.utils import ( |
230 | get_current_browser_request, get_current_web_service_request, |
231 | @@ -69,125 +61,10 @@ |
232 | IResourceGETOperation, name=name) |
233 | |
234 | |
235 | -class IGenericEntry(Interface): |
236 | - """A simple, reusable entry interface. |
237 | - |
238 | - This is the description of the entry. |
239 | - """ |
240 | - export_as_webservice_entry() |
241 | - |
242 | - # pylint: disable-msg=E0213 |
243 | - a_field = exported( |
244 | - TextLine( |
245 | - title=u'A "field"', |
246 | - description=u'The only field that can be <> 0 in the entry.')) |
247 | - |
248 | - @operation_parameters( |
249 | - message=TextLine(title=u'Message to say')) |
250 | - @export_read_operation() |
251 | - def greet(message): |
252 | - """Print an appropriate greeting based on the message. |
253 | - |
254 | - :param message: This will be included in the greeting. |
255 | - """ |
256 | - |
257 | - |
258 | -class IGenericCollection(Interface): |
259 | - """A simple collection containing `IGenericEntry`.""" |
260 | - export_as_webservice_collection(IGenericEntry) |
261 | - |
262 | - # pylint: disable-msg=E0211 |
263 | - @collection_default_content() |
264 | - def getAll(): |
265 | - """Returns all the entries.""" |
266 | - |
267 | - |
268 | -class IWebServiceRequest10(IWebServiceClientRequest): |
269 | - """A marker interface for requests to the '1.0' web service.""" |
270 | - |
271 | - |
272 | -class IWebServiceRequest20(IWebServiceClientRequest): |
273 | - """A marker interface for requests to the '2.0' web service.""" |
274 | - |
275 | - |
276 | -class SimpleWebServiceConfiguration(BaseWebServiceConfiguration): |
277 | - implements(IWebServiceConfiguration) |
278 | - show_tracebacks = False |
279 | - active_versions = ['1.0', '2.0'] |
280 | - hostname = "webservice_test" |
281 | - last_version_with_mutator_named_operations = None |
282 | - |
283 | - def createRequest(self, body_instream, environ): |
284 | - request = Request(body_instream, environ) |
285 | - request.version = '2.0' |
286 | - alsoProvides(request, IWebServiceRequest20) |
287 | - request.setPublication(WebServiceTestPublication( |
288 | - getUtility(IServiceRootResource))) |
289 | - request.annotations[request.VERSION_ANNOTATION] = '2.0' |
290 | - return request |
291 | - |
292 | - |
293 | -class WebServiceTestCase(CleanUp, unittest.TestCase): |
294 | - """A test case for web service operations.""" |
295 | - |
296 | - testmodule_objects = [] |
297 | - |
298 | - def setUp(self): |
299 | - """Set the component registry with the given model.""" |
300 | - super(WebServiceTestCase, self).setUp() |
301 | - |
302 | - # Register a simple configuration object. |
303 | - webservice_configuration = SimpleWebServiceConfiguration() |
304 | - sm = getGlobalSiteManager() |
305 | - sm.registerUtility(webservice_configuration) |
306 | - |
307 | - # Register IWebServiceVersions for the |
308 | - # '1.0' and '2.0' web service versions. |
309 | - alsoProvides(IWebServiceRequest10, IWebServiceVersion) |
310 | - sm.registerUtility( |
311 | - IWebServiceRequest10, IWebServiceVersion, name='1.0') |
312 | - alsoProvides(IWebServiceRequest20, IWebServiceVersion) |
313 | - sm.registerUtility( |
314 | - IWebServiceRequest20, IWebServiceVersion, name='2.0') |
315 | - |
316 | - # Register a service root resource |
317 | - service_root = ServiceRootResource() |
318 | - sm.registerUtility(service_root, IServiceRootResource) |
319 | - |
320 | - # Register an IAbsoluteURL adapter for the service root resource. |
321 | - sm.registerAdapter( |
322 | - RootResourceAbsoluteURL, |
323 | - [IServiceRootResource, IWebServiceClientRequest], IAbsoluteURL) |
324 | - |
325 | - # Build a test module that exposes the given resource interfaces. |
326 | - testmodule = ModuleType('testmodule') |
327 | - for interface in self.testmodule_objects: |
328 | - setattr(testmodule, interface.__name__, interface) |
329 | - sys.modules['lazr.restful.testmodule'] = testmodule |
330 | - |
331 | - # Register the test module in the ZCML configuration: adapter |
332 | - # classes will be built automatically. |
333 | - xmlconfig.string(""" |
334 | - <configure |
335 | - xmlns="http://namespaces.zope.org/zope" |
336 | - xmlns:webservice="http://namespaces.canonical.com/webservice"> |
337 | - <include package="zope.component" file="meta.zcml" /> |
338 | - <include package="zope.security" file="meta.zcml"/> |
339 | - <include package="lazr.restful" file="meta.zcml" /> |
340 | - <include package="lazr.restful" file="configure.zcml" /> |
341 | - |
342 | - <adapter for="*" |
343 | - factory="zope.traversing.adapters.DefaultTraversable" |
344 | - provides="zope.traversing.interfaces.ITraversable" /> |
345 | - |
346 | - <webservice:register module="lazr.restful.testmodule" /> |
347 | - </configure> |
348 | - """) |
349 | - |
350 | - |
351 | class IHas_getitem(Interface): |
352 | pass |
353 | |
354 | + |
355 | class Has_getitem: |
356 | implements(IHas_getitem) |
357 | def __getitem__(self, item): |
358 | @@ -320,8 +197,8 @@ |
359 | 'entry/wadl_entry:doc', entry=entry).splitlines() |
360 | self.assertEquals([ |
361 | '<wadl:doc xmlns="http://www.w3.org/1999/xhtml">', |
362 | - '<p>A simple, reusable entry interface.</p>', |
363 | - '<p>This is the description of the entry.</p>', |
364 | + '<p>A simple, reusable entry interface for use in tests.</p>', |
365 | + '<p>The entry publishes one field and one named operation.</p>', |
366 | '', |
367 | '</wadl:doc>'], doclines) |
368 | |
369 | @@ -339,7 +216,7 @@ |
370 | ).splitlines() |
371 | self.assertEquals([ |
372 | '<wadl:doc xmlns="http://www.w3.org/1999/xhtml">', |
373 | - 'A simple collection containing IGenericEntry.', |
374 | + 'A simple collection containing IGenericEntry, for use in tests.', |
375 | '</wadl:doc>'], doclines) |
376 | |
377 | def test_field_wadl_doc (self): |
lazr.restful's unit test file test_webservice.py used to have a class called WebServiceTestCase that would set up a dummy web service and run some unit tests against it. Over time, the amount of setup work necessary increased, to the point where WSTC was basically setting up a fully functional web service.
When integrating a new lazr.restful version into Launchpad, I noticed that Launchpad also had unit tests that ran against a web service, and that I could save myself a lot of trouble by writing unit tests that subclassed WebServiceTestCase. I did this, but I pledged to come back and move WSTC (and its dependent classes) into lazr.restful. testing. webservice, so that Launchpad wouldn't be importing classes from a lazr.restful unit test module.
This branch does basically that, and nothing else. The one fix I made in passing was to change SimpleWebServic eConfiguration. createRequest to use the utility function tag_request_ with_version_ name(), replacing code that was basically a copy of tag_request_ with_version_ name. I also had to change the WADL unit tests, because I fleshed out the doctest strings of IGenericEntry and IGenericConfigu ration.