Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Merging spanezz changes, providing alternate async tests.

  • Loading branch information...
commit 79918dabbdca033388fd4297ca9140b995572964 2 parents 00aea69 + 7f0ca8b
Josh Marshall authored
25  tests/helpers.py
... ...
@@ -1,7 +1,7 @@
1 1
 import threading
2 2
 import time
3  
-from tornado.httpclient import AsyncHTTPClient
4 3
 from tornadorpc import start_server, private, async
  4
+from tornado.httpclient import AsyncHTTPClient
5 5
 
6 6
 
7 7
 class Tree(object):
@@ -22,14 +22,6 @@ class TestHandler(object):
22 22
     def add(self, x, y):
23 23
         return x+y
24 24
 
25  
-    @async
26  
-    def async(self, url):
27  
-        async_client = AsyncHTTPClient()
28  
-        async_client.fetch(url, self._handle_response)
29  
-
30  
-    def _handle_response(self, response):
31  
-        self.result(response.code)
32  
-
33 25
     @private
34 26
     def private(self):
35 27
         # Should not be callable
@@ -42,6 +34,14 @@ def _private(self):
42 34
     def internal_error(self):
43 35
         raise Exception("Yar matey!")
44 36
 
  37
+    @async
  38
+    def async(self, url):
  39
+        async_client = AsyncHTTPClient()
  40
+        async_client.fetch(url, self._handle_response)
  41
+
  42
+    def _handle_response(self, response):
  43
+        self.result(response.code)
  44
+
45 45
 
46 46
 class TestServer(object):
47 47
 
@@ -49,6 +49,10 @@ class TestServer(object):
49 49
 
50 50
     @classmethod
51 51
     def start(cls, handler, port):
  52
+        # threading, while functional for testing the built-in python
  53
+        # clients, is an overly complicated solution for IOLoop based
  54
+        # servers. After implementing a tornado-based JSON-RPC client
  55
+        # and XML-RPC client, move this to an IOLoop based test case.
52 56
         if not cls.threads.get(port):
53 57
             cls.threads[port] = threading.Thread(
54 58
                 target=start_server,
@@ -65,9 +69,11 @@ class RPCTests(object):
65 69
 
66 70
     server = None
67 71
     handler = None
  72
+    io_loop = None
68 73
     port = 8002
69 74
 
70 75
     def setUp(self):
  76
+        super(RPCTests, self).setUp()
71 77
         self.server = TestServer.start(self.handler, self.port)
72 78
 
73 79
     def get_url(self):
@@ -87,6 +93,7 @@ def test_add(self):
87 93
         self.assertEqual(result, 11)
88 94
 
89 95
     def test_async(self):
  96
+        # this should be refactored to use Async RPC clients...
90 97
         url = 'http://www.google.com'
91 98
         client = self.get_client()
92 99
         result = client.async(url)
94  tests/test_async.py
... ...
@@ -0,0 +1,94 @@
  1
+import json
  2
+from tests.helpers import TestHandler
  3
+from tornado.httpclient import AsyncHTTPClient
  4
+from tornado.testing import AsyncHTTPTestCase
  5
+import tornado.web
  6
+from tornadorpc import async
  7
+from tornadorpc.xml import XMLRPCHandler
  8
+import xmlrpclib
  9
+
  10
+
  11
+class AsyncHandler(XMLRPCHandler, TestHandler):
  12
+
  13
+    @async
  14
+    def async_method(self, url):
  15
+        async_client = AsyncHTTPClient()
  16
+        async_client.fetch(url, self._handle_response)
  17
+
  18
+    @async
  19
+    def bad_async_method(self, url):
  20
+        async_client = AsyncHTTPClient()
  21
+        async_client.fetch(url, self._handle_response)
  22
+        return 5
  23
+
  24
+    def _handle_response(self, response):
  25
+        self.result(json.loads(response.body))
  26
+
  27
+
  28
+class AsyncXMLRPCClient(object):
  29
+
  30
+    def __init__(self, url, ioloop, fetcher):
  31
+        self._url = url
  32
+        self._ioloop = ioloop
  33
+        self._fetcher = fetcher
  34
+
  35
+    def __getattr__(self, attribute):
  36
+        return Caller(attribute, self)
  37
+
  38
+    def execute(self, method, params, keyword_params):
  39
+        if params and keyword_params:
  40
+            raise Exception(
  41
+                "Can't have both keyword and positional arguments.")
  42
+        arguments = params or keyword_params
  43
+        body = xmlrpclib.dumps(arguments, methodname=method)
  44
+        response = self._fetcher(self._url, method="POST", body=body)
  45
+        result, _ = xmlrpclib.loads(response.body)
  46
+        return result[0]
  47
+
  48
+
  49
+class Caller(object):
  50
+
  51
+    def __init__(self, namespace, client):
  52
+        self._namespace = namespace
  53
+        self._client = client
  54
+
  55
+    def __getattr__(self, namespace):
  56
+        self._namespace += "." + namespace
  57
+        return self
  58
+
  59
+    def __call__(self, *args, **kwargs):
  60
+        return self._client.execute(self._namespace, args, kwargs)
  61
+
  62
+
  63
+class AsyncTests(AsyncHTTPTestCase):
  64
+
  65
+    def get_app(self):
  66
+
  67
+        class IndexHandler(tornado.web.RequestHandler):
  68
+
  69
+            def get(self):
  70
+                self.finish({"foo": "bar"})
  71
+
  72
+        return tornado.web.Application([
  73
+            ("/", IndexHandler),
  74
+            ("/RPC2", AsyncHandler)
  75
+        ])
  76
+
  77
+    def get_client(self):
  78
+        return AsyncXMLRPCClient(
  79
+            url="/RPC2", ioloop=self.io_loop, fetcher=self.fetch)
  80
+
  81
+    def test_async_method(self):
  82
+        client = self.get_client()
  83
+        result = client.async_method(
  84
+            "http://localhost:%d/" % (self.get_http_port()))
  85
+        self.assertEqual({"foo": "bar"}, result)
  86
+
  87
+    def test_async_returns_non_none_raises_internal_error(self):
  88
+        client = self.get_client()
  89
+        try:
  90
+            client.bad_async_method(
  91
+                "http://localhost:%d/" % (self.get_http_port()))
  92
+            self.fail("xmlrpclib.Fault should have been raised.")
  93
+        except xmlrpclib.Fault, fault:
  94
+            self.assertEqual(-32603, fault.faultCode)
1  tests/test_xml.py
@@ -54,7 +54,6 @@ def test_internal_error(self):
54 54
 
55 55
     def test_parse_error(self):
56 56
         try:
57  
-            print self.get_url()
58 57
             urllib2.urlopen(self.get_url(), '<garbage/>')
59 58
         except xmlrpclib.Fault, f:
60 59
             self.assertEqual(-32700, f.faultCode)
13  tornadorpc/base.py
@@ -8,7 +8,6 @@
8 8
 You can use the utility functions like 'private' and 'start_server'.
9 9
 """
10 10
 
11  
-import logging
12 11
 from tornado.web import RequestHandler
13 12
 import tornado.web
14 13
 import tornado.ioloop
@@ -100,7 +99,7 @@ def dispatch(self, method_name, params):
100 99
         Handler class. Currently supports only positional
101 100
         or keyword arguments, not mixed.
102 101
         """
103  
-        if method_name in dir(RequestHandler):
  102
+        if hasattr(RequestHandler, method_name):
104 103
             # Pre-existing, not an implemented attribute
105 104
             return self.handler.result(self.faults.method_not_found())
106 105
         method = self.handler
@@ -116,7 +115,7 @@ def dispatch(self, method_name, params):
116 115
             # Not callable, so not a method
117 116
             return self.handler.result(self.faults.method_not_found())
118 117
         if method_name.startswith('_') or \
119  
-                ('private' in dir(method) and method.private is True):
  118
+                getattr(method, 'private', False) is True:
120 119
             # No, no. That's private.
121 120
             return self.handler.result(self.faults.method_not_found())
122 121
         args = []
@@ -141,14 +140,12 @@ def dispatch(self, method_name, params):
141 140
             self.traceback(method_name, params)
142 141
             return self.handler.result(self.faults.internal_error())
143 142
 
144  
-        if 'async' in dir(method) and method.async:
  143
+        if getattr(method, 'async', False):
145 144
             # Asynchronous response -- the method should have called
146 145
             # self.result(RESULT_VALUE)
147 146
             if response is not None:
148 147
                 # This should be deprecated to use self.result
149  
-                message = "Async results should use 'self.result()'"
150  
-                message += " Return result will be ignored."
151  
-                logging.warning(message)
  148
+                return self.handler.result(self.faults.internal_error())
152 149
         else:
153 150
             # Synchronous result -- we call result manually.
154 151
             return self.handler.result(response)
@@ -227,7 +224,7 @@ def check_method(self, attr_name, obj):
227 224
             raise AttributeError('Private object or method.')
228 225
         attr = getattr(obj, attr_name)
229 226
 
230  
-        if 'private' in dir(attr) and attr.private:
  227
+        if getattr(attr, 'private', False):
231 228
             raise AttributeError('Private object or method.')
232 229
         return attr
233 230
 

0 notes on commit 79918da

Please sign in to comment.
Something went wrong with that request. Please try again.