Anonymous avatar Anonymous committed 89befee

API v2: Various tweaks:
* Added a manifest file to make './setup.py sdist' work correctly.
* Added a test to make sure documentation renders correctly on regular html GET requests (which it didn't, so made the main request trap slightly more lax).
* Fixed all test classes to properly implement inheritance (call 'home' to setup logging for instance).
* Made logging finally work. Makes it much easier to find the right spot in the environment log. Useful, Olemis - thanks.

Looking good now.

Comments (0)

Files changed (1)

t5437/t5437-protocol_api_v2-r7194.diff

 RPC Protocol API version 2
 
-diff -r 81472780cbdd trunk/setup.py
---- a/trunk/setup.py	Mon Apr 19 23:57:51 2010 -0500
-+++ b/trunk/setup.py	Tue Apr 20 00:18:44 2010 -0500
+diff --git a/trunk/MANIFEST.in b/trunk/MANIFEST.in
+new file mode 100644
+--- /dev/null
++++ b/trunk/MANIFEST.in
+@@ -0,0 +1,4 @@
++include README.wiki
++include tracrpc/htdocs/css/*.css
++include tracrpc/htdocs/js/*.js
++include tracrpc/templates/*.html
+diff --git a/trunk/setup.py b/trunk/setup.py
+--- a/trunk/setup.py
++++ b/trunk/setup.py
 @@ -28,7 +28,7 @@
      url='http://trac-hacks.org/wiki/XmlRpcPlugin',
      description='RPC interface to Trac',
      tests_require = test_deps,
      packages=find_packages(exclude=['*.tests']),
      package_data={
-diff -r 81472780cbdd trunk/tracrpc/api.py
---- a/trunk/tracrpc/api.py	Mon Apr 19 23:57:51 2010 -0500
-+++ b/trunk/tracrpc/api.py	Tue Apr 20 00:18:44 2010 -0500
+diff --git a/trunk/tracrpc/api.py b/trunk/tracrpc/api.py
+--- a/trunk/tracrpc/api.py
++++ b/trunk/tracrpc/api.py
 @@ -15,19 +15,41 @@
  from trac.perm import IPermissionRequestor
  
  
  class IXMLRPCHandler(Interface):
  
-diff -r 81472780cbdd trunk/tracrpc/json_rpc.py
---- a/trunk/tracrpc/json_rpc.py	Mon Apr 19 23:57:51 2010 -0500
-+++ b/trunk/tracrpc/json_rpc.py	Tue Apr 20 00:18:44 2010 -0500
+diff --git a/trunk/tracrpc/json_rpc.py b/trunk/tracrpc/json_rpc.py
+--- a/trunk/tracrpc/json_rpc.py
++++ b/trunk/tracrpc/json_rpc.py
 @@ -5,8 +5,9 @@
  (c) 2009      ::: www.CodeResort.com - BV Network AS (simon-code@bvnetwork.no)
  """
  
      def _json_error(self, e, c=None, r_id=None):
          """ Makes a response dictionary that is an error. """
-diff -r 81472780cbdd trunk/tracrpc/tests/__init__.py
---- a/trunk/tracrpc/tests/__init__.py	Mon Apr 19 23:57:51 2010 -0500
-+++ b/trunk/tracrpc/tests/__init__.py	Tue Apr 20 00:18:44 2010 -0500
+diff --git a/trunk/tracrpc/tests/__init__.py b/trunk/tracrpc/tests/__init__.py
+--- a/trunk/tracrpc/tests/__init__.py
++++ b/trunk/tracrpc/tests/__init__.py
 @@ -35,6 +35,7 @@
              print "Enabling RPC plugin and permissions..."
              env.config.set('components', 'tracrpc.*', 'enabled')
              self._tracadmin('permission', 'add', 'anonymous', 'XML_RPC')
              print "Created test environment: %s" % self.dirname
              parts = urllib2.urlparse.urlsplit(self.url)
-@@ -66,22 +67,56 @@
+@@ -66,22 +67,60 @@
                  os.path.realpath(__file__), '..', '..', '..', 'rpctestenv')),
                  '8765', 'http://127.0.0.1')
  
          import tracrpc.tests.wiki
 -        suite.addTest(tracrpc.tests.wiki.suite())
 +        suite.addTest(tracrpc.tests.wiki.test_suite())
++        import tracrpc.tests.web_ui
++        suite.addTest(tracrpc.tests.web_ui.test_suite())
          return suite
  
  except Exception, e:
 +    __unittest = 1          # Do not show this module in tracebacks
 +    class TracRpcTestCase(unittest.TestCase):
 +        def setUp(self):
-+            log = rpc_testenv.getLogger()
++            log = rpc_testenv.get_trac_environment().log
 +            log.info('=' * 70)
-+            log.info('(TEST) Starting %s', self._testMethodName)
++            log.info('(TEST) Starting %s.%s',
++                            self.__class__.__name__,
++                            self._testMethodName)
 +            log.info('=' * 70)
 +
 +        def failUnlessRaises(self, excClass, callableObj, *args, **kwargs):
 +                raise self.failureException, "Expected %s\n\nNothing raised" % excName
 +
 +        assertRaises = failUnlessRaises
-diff -r 81472780cbdd trunk/tracrpc/tests/api.py
---- a/trunk/tracrpc/tests/api.py	Mon Apr 19 23:57:51 2010 -0500
-+++ b/trunk/tracrpc/tests/api.py	Tue Apr 20 00:18:44 2010 -0500
-@@ -47,16 +47,20 @@
+diff --git a/trunk/tracrpc/tests/api.py b/trunk/tracrpc/tests/api.py
+--- a/trunk/tracrpc/tests/api.py
++++ b/trunk/tracrpc/tests/api.py
+@@ -9,14 +9,20 @@
+ import unittest
+ import urllib2
+ 
+-from tracrpc.tests import rpc_testenv
++from tracrpc.tests import rpc_testenv, TracRpcTestCase
+ 
+ from tracrpc.api import IRPCProtocol
+ 
+ from trac.core import *
+ from trac.test import Mock
+ 
+-class ProtocolProviderTestCase(unittest.TestCase):
++class ProtocolProviderTestCase(TracRpcTestCase):
++
++    def setUp(self):
++        TracRpcTestCase.setUp(self)
++
++    def tearDown(self):
++        TracRpcTestCase.tearDown(self)
+ 
+     def test_invalid_content_type(self):
+         req = urllib2.Request(rpc_testenv.url_anon,
+@@ -47,16 +53,20 @@
              "class DummyProvider(Component):\n"
              "    implements(IRPCProtocol)\n"
              "    def rpc_info(self):\n"
          rpc_testenv.restart()
          try:
              req = urllib2.Request(rpc_testenv.url_anon,
-@@ -65,7 +69,7 @@
+@@ -65,7 +75,7 @@
              self.assertEquals(200, resp.code)
              self.assertEquals("Got a result!", resp.read())
              self.assertEquals(resp.headers['Content-Type'],
          finally:
              # Clean up so that provider don't affect further tests
              os.unlink(provider)
-@@ -80,10 +84,21 @@
+@@ -80,10 +90,21 @@
              "class DummyProvider(Component):\n"
              "    implements(IRPCProtocol)\n"
              "    def rpc_info(self):\n"
              "        raise RPCError('No good.')")
          rpc_testenv.restart()
          # Make the request
-@@ -100,8 +115,8 @@
+@@ -100,8 +121,8 @@
              os.unlink(provider)
              rpc_testenv.restart()
  
  if __name__ == '__main__':
 -    unittest.main(defaultTest='suite')
 +    unittest.main(defaultTest='test_suite')
-diff -r 81472780cbdd trunk/tracrpc/tests/json_rpc.py
---- a/trunk/tracrpc/tests/json_rpc.py	Mon Apr 19 23:57:51 2010 -0500
-+++ b/trunk/tracrpc/tests/json_rpc.py	Tue Apr 20 00:18:44 2010 -0500
+diff --git a/trunk/tracrpc/tests/json_rpc.py b/trunk/tracrpc/tests/json_rpc.py
+--- a/trunk/tracrpc/tests/json_rpc.py
++++ b/trunk/tracrpc/tests/json_rpc.py
 @@ -14,10 +14,10 @@
  from tracrpc.util import StringIO
  
          def _anon_req(self, data):
              req = urllib2.Request(rpc_testenv.url_anon,
                          headers={'Content-Type': 'application/json'})
+@@ -39,10 +39,10 @@
+             return json.loads(resp.read())
+ 
+         def setUp(self):
+-            pass
++            TracRpcTestCase.setUp(self)
+ 
+         def tearDown(self):
+-            pass
++            TracRpcTestCase.tearDown(self)
+ 
+         def test_call(self):
+             result = self._anon_req(
 @@ -59,6 +59,7 @@
                      {'method': 'nonexisting', 'params': []}
                  ], 'id': 233}
  if __name__ == '__main__':
 -    unittest.main(defaultTest='suite')
 +    unittest.main(defaultTest='test_suite')
-diff -r 81472780cbdd trunk/tracrpc/tests/ticket.py
---- a/trunk/tracrpc/tests/ticket.py	Mon Apr 19 23:57:51 2010 -0500
-+++ b/trunk/tracrpc/tests/ticket.py	Tue Apr 20 00:18:44 2010 -0500
-@@ -12,9 +12,9 @@
+diff --git a/trunk/tracrpc/tests/ticket.py b/trunk/tracrpc/tests/ticket.py
+--- a/trunk/tracrpc/tests/ticket.py
++++ b/trunk/tracrpc/tests/ticket.py
+@@ -12,15 +12,19 @@
  import shutil
  import time
  
 +class RpcTicketTestCase(TracRpcTestCase):
      
      def setUp(self):
++        TracRpcTestCase.setUp(self)
          self.anon = xmlrpclib.ServerProxy(rpc_testenv.url_anon)
-@@ -124,8 +124,8 @@
+         self.user = xmlrpclib.ServerProxy(rpc_testenv.url_user)
+         self.admin = xmlrpclib.ServerProxy(rpc_testenv.url_admin)
+ 
++    def tearDown(self):
++        TracRpcTestCase.tearDown(self)
++
+     def test_getActions(self):
+         tid = self.admin.ticket.create("ticket_getActions", "kjsald", {})
+         actions = self.admin.ticket.getActions(tid)
+@@ -124,8 +128,8 @@
              self.admin.ticket.delete(tid1)
              self.admin.ticket.delete(tid2)
  
  if __name__ == '__main__':
 -    unittest.main(defaultTest='suite')
 +    unittest.main(defaultTest='test_suite')
-diff -r 81472780cbdd trunk/tracrpc/tests/wiki.py
---- a/trunk/tracrpc/tests/wiki.py	Mon Apr 19 23:57:51 2010 -0500
-+++ b/trunk/tracrpc/tests/wiki.py	Tue Apr 20 00:18:44 2010 -0500
-@@ -13,10 +13,10 @@
+diff --git a/trunk/tracrpc/tests/web_ui.py b/trunk/tracrpc/tests/web_ui.py
+new file mode 100644
+--- /dev/null
++++ b/trunk/tracrpc/tests/web_ui.py
+@@ -0,0 +1,39 @@
++# -*- coding: utf-8 -*-
++"""
++License: BSD
++
++(c) 2009      ::: www.CodeResort.com - BV Network AS (simon-code@bvnetwork.no)
++"""
++
++import unittest
++import urllib2
++
++from tracrpc.tests import rpc_testenv, TracRpcTestCase
++
++class DocumentationTestCase(TracRpcTestCase):
++
++    def setUp(self):
++        TracRpcTestCase.setUp(self)
++
++    def tearDown(self):
++        TracRpcTestCase.tearDown(self)
++
++    def test_documentation_render(self):
++        password_mgr = urllib2.HTTPPasswordMgrWithDefaultRealm()
++        handler = urllib2.HTTPBasicAuthHandler(password_mgr)
++        password_mgr.add_password(realm=None,
++                      uri=rpc_testenv.url_auth,
++                      user='user', passwd='user')
++        req = urllib2.Request(rpc_testenv.url_auth,
++                    headers={'Content-Type': 'text/html'})
++        resp = urllib2.build_opener(handler).open(req)
++        self.assertEquals(200, resp.code)
++        body = resp.read()
++        self.assertTrue('<h3 id="XML-RPC">XML-RPC</h3>' in body)
++        self.assertTrue('<h3 id="xmlrpc.ticket.status">' in body)
++
++def test_suite():
++    return unittest.makeSuite(DocumentationTestCase)
++
++if __name__ == '__main__':
++    unittest.main(defaultTest='test_suite')
+diff --git a/trunk/tracrpc/tests/wiki.py b/trunk/tracrpc/tests/wiki.py
+--- a/trunk/tracrpc/tests/wiki.py
++++ b/trunk/tracrpc/tests/wiki.py
+@@ -13,16 +13,20 @@
  
  from trac.util.compat import sorted
  
 +class RpcWikiTestCase(TracRpcTestCase):
      
      def setUp(self):
++        TracRpcTestCase.setUp(self)
          self.anon = xmlrpclib.ServerProxy(rpc_testenv.url_anon)
-@@ -60,8 +60,8 @@
+         self.user = xmlrpclib.ServerProxy(rpc_testenv.url_user)
+         self.admin = xmlrpclib.ServerProxy(rpc_testenv.url_admin)
+ 
++    def tearDown(self):
++        TracRpcTestCase.tearDown(self)
++
+     def test_attachments(self):
+         # Note: Quite similar to the tracrpc.tests.json.JsonTestCase.test_binary
+         image_url = os.path.join(rpc_testenv.trac_src, 'trac',
+@@ -60,8 +64,8 @@
          self.admin.wiki.deletePage('WikiOne')
          self.admin.wiki.deletePage('WikiTwo')
  
  if __name__ == '__main__':
 -    unittest.main(defaultTest='suite')
 +    unittest.main(defaultTest='test_suite')
-diff -r 81472780cbdd trunk/tracrpc/tests/xml_rpc.py
---- a/trunk/tracrpc/tests/xml_rpc.py	Mon Apr 19 23:57:51 2010 -0500
-+++ b/trunk/tracrpc/tests/xml_rpc.py	Tue Apr 20 00:18:44 2010 -0500
-@@ -9,9 +9,9 @@
+diff --git a/trunk/tracrpc/tests/xml_rpc.py b/trunk/tracrpc/tests/xml_rpc.py
+--- a/trunk/tracrpc/tests/xml_rpc.py
++++ b/trunk/tracrpc/tests/xml_rpc.py
+@@ -9,57 +9,62 @@
  
  import xmlrpclib
  
 +class RpcXmlTestCase(TracRpcTestCase):
      
      def setUp(self):
++        TracRpcTestCase.setUp(self)
          self.anon = xmlrpclib.ServerProxy(rpc_testenv.url_anon)
-@@ -22,44 +22,45 @@
+         self.user = xmlrpclib.ServerProxy(rpc_testenv.url_user)
+         self.admin = xmlrpclib.ServerProxy(rpc_testenv.url_admin)
+ 
++    def tearDown(self):
++        TracRpcTestCase.tearDown(self)
++
+     def test_xmlrpc_permission(self):
          # Test returned response if not XML_RPC permission
          rpc_testenv._tracadmin('permission', 'remove', 'anonymous',
                                  'XML_RPC')
          # Unicode version (encodable)
          from trac.util.text import to_unicode
          test_string = to_unicode(test_string)
-@@ -81,7 +82,7 @@
+@@ -81,7 +86,7 @@
          xmlrpc_now = to_xmlrpc_datetime(now)
          self.assertTrue(isinstance(xmlrpc_now, xmlrpclib.DateTime),
                  "Expected xmlprc_now to be an xmlrpclib.DateTime")
          now_from_xmlrpc = from_xmlrpc_datetime(xmlrpc_now)
          self.assertTrue(isinstance(now_from_xmlrpc, datetime),
                  "Expected now_from_xmlrpc to be a datetime")
-@@ -90,22 +91,18 @@
+@@ -90,22 +95,18 @@
  
      def test_resource_not_found(self):
          # A Ticket resource
  if __name__ == '__main__':
 -    unittest.main(defaultTest='suite')
 +    unittest.main(defaultTest='test_suite')
-diff -r 81472780cbdd trunk/tracrpc/web_ui.py
---- a/trunk/tracrpc/web_ui.py	Mon Apr 19 23:57:51 2010 -0500
-+++ b/trunk/tracrpc/web_ui.py	Tue Apr 20 00:18:44 2010 -0500
+diff --git a/trunk/tracrpc/util.py b/trunk/tracrpc/util.py
+--- a/trunk/tracrpc/util.py
++++ b/trunk/tracrpc/util.py
+@@ -33,12 +33,6 @@
+ except ImportError:
+     empty = None
+ 
+-def accepts_mimetype(req, mimetype):
+-    if isinstance(mimetype, basestring):
+-      mimetype = (mimetype,)
+-    accept = (req.get_header('Accept') or '').split(',')
+-    return any(x.strip().startswith(y) for x in accept for y in mimetype)
+-
+ def prepare_docs(text, indent=4):
+     r"""Remove leading whitespace"""
+     return ''.join(l[indent:] for l in text.splitlines(True))
+diff --git a/trunk/tracrpc/web_ui.py b/trunk/tracrpc/web_ui.py
+--- a/trunk/tracrpc/web_ui.py
++++ b/trunk/tracrpc/web_ui.py
 @@ -6,6 +6,10 @@
  (c) 2009      ::: www.CodeResort.com - BV Network AS (simon-code@bvnetwork.no)
  """
  from pkg_resources import resource_filename
  
  from genshi.builder import tag
-@@ -13,15 +17,19 @@
+@@ -13,16 +17,19 @@
  from genshi.template.text import TextTemplate
  
  from trac.core import *
  from trac.wiki.formatter import wiki_to_oneliner
  
 -from tracrpc.api import XMLRPCSystem, IRPCProtocol
+-from tracrpc.util import accepts_mimetype
 +from tracrpc.api import XMLRPCSystem, IRPCProtocol, ProtocolException, \
 +                          RPCError, ServiceException
- from tracrpc.util import accepts_mimetype
  
  __all__ = ['RPCWeb']
-@@ -59,13 +67,7 @@
+ 
+@@ -59,14 +66,8 @@
              # Perform the method call
              self.log.debug("RPC incoming request of content type '%s' " \
                      "dispatched to %s" % (content_type, repr(protocol)))
 -                self.log.error("Unhandled protocol error: %s" % to_unicode(e))
 -                req.send_error(None, template='', content_type='text/plain',
 -                        status=500, env=None, data=to_unicode(e))
+-        elif accepts_mimetype(req, 'text/html'):
 +            self._rpc_process(req, protocol, content_type)
-         elif accepts_mimetype(req, 'text/html'):
++        elif req.method == 'GET' and content_type.startswith('text/html'):
              return self._dump_docs(req)
          else:
-@@ -76,6 +78,8 @@
+             # Attempt at API call gone wrong. Raise a plain-text 415 error
+@@ -76,6 +77,8 @@
              req.send_error(None, template='', content_type='text/plain',
                      status=HTTPUnsupportedMediaType.code, env=None, data=body)
  
      def _dump_docs(self, req):
          # Dump RPC documentation
          req.perm.require('XML_RPC') # Need at least XML_RPC
-@@ -128,6 +132,66 @@
+@@ -128,6 +131,66 @@
              return "Error rendering protocol documentation. " \
                         "Contact your '''Trac''' administrator for details"
  
      # ITemplateProvider methods
  
      def get_htdocs_dirs(self):
-diff -r 81472780cbdd trunk/tracrpc/xml_rpc.py
---- a/trunk/tracrpc/xml_rpc.py	Mon Apr 19 23:57:51 2010 -0500
-+++ b/trunk/tracrpc/xml_rpc.py	Tue Apr 20 00:18:44 2010 -0500
+diff --git a/trunk/tracrpc/xml_rpc.py b/trunk/tracrpc/xml_rpc.py
+--- a/trunk/tracrpc/xml_rpc.py
++++ b/trunk/tracrpc/xml_rpc.py
 @@ -19,7 +19,7 @@
  from trac.util.text import to_unicode
  
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.