Browse code
Merge pull request #3 from fiddlerwoaroof/master
Fixed up unit testing, ironed out a few bugs, and supported more of the server spec (notifications and error codes)
Showing 2 changed files
2 | 2 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,261 @@ |
1 |
+from twisted.trial import unittest |
|
2 |
+import StringIO |
|
3 |
+ |
|
4 |
+import mock |
|
5 |
+ |
|
6 |
+import jsonrpc.server |
|
7 |
+import jsonrpc.jsonutil |
|
8 |
+ |
|
9 |
+from twisted.web.test.test_web import DummyRequest |
|
10 |
+from twisted.internet.defer import succeed |
|
11 |
+from twisted.web.static import server |
|
12 |
+ |
|
13 |
+def _render(resource, request): |
|
14 |
+ result = resource.render(request) |
|
15 |
+ if isinstance(result, str): |
|
16 |
+ request.write(result) |
|
17 |
+ request.finish() |
|
18 |
+ return succeed(None) |
|
19 |
+ elif result is server.NOT_DONE_YET: |
|
20 |
+ if request.finished: |
|
21 |
+ return succeed(None) |
|
22 |
+ else: |
|
23 |
+ return request.notifyFinish() |
|
24 |
+ else: |
|
25 |
+ raise ValueError("Unexpected return value: %r" % (result,)) |
|
26 |
+ |
|
27 |
+class SimpleEventHandler(jsonrpc.server.ServerEvents): |
|
28 |
+ def log(self, result, request): pass |
|
29 |
+ |
|
30 |
+ def findmethod(self, method): |
|
31 |
+ if method in set(['echo', 'add']): |
|
32 |
+ return getattr(self, method) |
|
33 |
+ |
|
34 |
+ def add(self, a,b): |
|
35 |
+ return a+b |
|
36 |
+ |
|
37 |
+ def echo(self, v): return v |
|
38 |
+ |
|
39 |
+ |
|
40 |
+class TestJSONRPCServer(unittest.TestCase): |
|
41 |
+ |
|
42 |
+ def setUp(self): |
|
43 |
+ self.id_ = 'an_id' |
|
44 |
+ self.param = "some data" |
|
45 |
+ |
|
46 |
+ def test_invalid_data(self): |
|
47 |
+ resource = jsonrpc.server.JSON_RPC() |
|
48 |
+ resource.customize(SimpleEventHandler) |
|
49 |
+ |
|
50 |
+ request = DummyRequest(['']) |
|
51 |
+ request.getCookie = mock.Mock() |
|
52 |
+ request.content = StringIO.StringIO(' {"v": %s}, "method": "echo"}' % (jsonrpc.jsonutil.encode(self.param))) |
|
53 |
+ |
|
54 |
+ d = _render(resource, request) |
|
55 |
+ |
|
56 |
+ @d.addCallback |
|
57 |
+ def rendered(ignored): |
|
58 |
+ assert len(request.written) == 1 |
|
59 |
+ data = jsonrpc.jsonutil.decode(request.written[0]) |
|
60 |
+ |
|
61 |
+ assert data == {"jsonrpc": "2.0", "error": {"code": -32700, "message": "Parse error."}, "id": None} |
|
62 |
+ |
|
63 |
+ return d |
|
64 |
+ |
|
65 |
+ def test_wrongversion(self): |
|
66 |
+ resource = jsonrpc.server.JSON_RPC() |
|
67 |
+ resource.customize(SimpleEventHandler) |
|
68 |
+ |
|
69 |
+ request = DummyRequest(['']) |
|
70 |
+ request.getCookie = mock.Mock() |
|
71 |
+ request.content = StringIO.StringIO('{"jsonrpc": "2.1", "params": %s, "method": "echo", "id": "%s"}' % (jsonrpc.jsonutil.encode([self.param]), self.id_)) |
|
72 |
+ |
|
73 |
+ d = _render(resource, request) |
|
74 |
+ |
|
75 |
+ @d.addCallback |
|
76 |
+ def rendered(ignored): |
|
77 |
+ assert len(request.written) == 1 |
|
78 |
+ data = jsonrpc.jsonutil.decode(request.written[0]) |
|
79 |
+ assert data == {"jsonrpc": "2.0", "error": {"code": -32600, "message": "Invalid Request."}, "id": self.id_} |
|
80 |
+ return d |
|
81 |
+ |
|
82 |
+ |
|
83 |
+ def test_invalidmethodname(self): |
|
84 |
+ resource = jsonrpc.server.JSON_RPC() |
|
85 |
+ resource.customize(SimpleEventHandler) |
|
86 |
+ |
|
87 |
+ request = DummyRequest(['']) |
|
88 |
+ request.getCookie = mock.Mock() |
|
89 |
+ request.content = StringIO.StringIO('{"jsonrpc": "2.0", "params": %s, "method": 0, "id": "%s"}' % (jsonrpc.jsonutil.encode([self.param]), self.id_)) |
|
90 |
+ |
|
91 |
+ d = _render(resource, request) |
|
92 |
+ |
|
93 |
+ @d.addCallback |
|
94 |
+ def rendered(ignored): |
|
95 |
+ assert len(request.written) == 1 |
|
96 |
+ data = jsonrpc.jsonutil.decode(request.written[0]) |
|
97 |
+ assert data == {"jsonrpc": "2.0", "error": {"code": -32600, "message": "Invalid Request."}, "id": self.id_} |
|
98 |
+ return d |
|
99 |
+ |
|
100 |
+ def test_missingmethod(self): |
|
101 |
+ resource = jsonrpc.server.JSON_RPC() |
|
102 |
+ resource.customize(SimpleEventHandler) |
|
103 |
+ |
|
104 |
+ request = DummyRequest(['']) |
|
105 |
+ request.getCookie = mock.Mock() |
|
106 |
+ request.content = StringIO.StringIO('{"jsonrpc": "2.0", "params": %s, "method": "non_existent", "id": "%s"}' % (jsonrpc.jsonutil.encode([self.param]), self.id_)) |
|
107 |
+ |
|
108 |
+ d = _render(resource, request) |
|
109 |
+ |
|
110 |
+ @d.addCallback |
|
111 |
+ def rendered(ignored): |
|
112 |
+ assert len(request.written) == 1 |
|
113 |
+ data = jsonrpc.jsonutil.decode(request.written[0]) |
|
114 |
+ assert data == {"jsonrpc": "2.0", "error": {"code": -32601, "message": "Procedure not found."}, "id": self.id_} |
|
115 |
+ return d |
|
116 |
+ |
|
117 |
+ |
|
118 |
+ |
|
119 |
+ def test_simplecall(self): |
|
120 |
+ resource = jsonrpc.server.JSON_RPC() |
|
121 |
+ resource.customize(SimpleEventHandler) |
|
122 |
+ |
|
123 |
+ request = DummyRequest(['']) |
|
124 |
+ request.getCookie = mock.Mock() |
|
125 |
+ request.content = StringIO.StringIO('{"jsonrpc": "2.0", "params": %s, "method": "echo", "id": "%s"}' % (jsonrpc.jsonutil.encode([self.param]), self.id_)) |
|
126 |
+ |
|
127 |
+ d = _render(resource, request) |
|
128 |
+ |
|
129 |
+ @d.addCallback |
|
130 |
+ def rendered(ignored): |
|
131 |
+ assert len(request.written) == 1 |
|
132 |
+ data = jsonrpc.jsonutil.decode(request.written[0]) |
|
133 |
+ |
|
134 |
+ assert data['id'] == self.id_ |
|
135 |
+ assert data['result'] == self.param |
|
136 |
+ return d |
|
137 |
+ |
|
138 |
+ def test_notify(self): |
|
139 |
+ resource = jsonrpc.server.JSON_RPC() |
|
140 |
+ resource.customize(SimpleEventHandler) |
|
141 |
+ |
|
142 |
+ request = DummyRequest(['']) |
|
143 |
+ request.getCookie = mock.Mock() |
|
144 |
+ request.content = StringIO.StringIO('{"jsonrpc": "2.0", "params": {"v": %s}, "method": "echo"}' % (jsonrpc.jsonutil.encode(self.param))) |
|
145 |
+ |
|
146 |
+ d = _render(resource, request) |
|
147 |
+ |
|
148 |
+ @d.addCallback |
|
149 |
+ def rendered(ignored): |
|
150 |
+ assert len(request.written) == 0 |
|
151 |
+ |
|
152 |
+ return d |
|
153 |
+ |
|
154 |
+ |
|
155 |
+ def test_kwcall(self): |
|
156 |
+ resource = jsonrpc.server.JSON_RPC() |
|
157 |
+ resource.customize(SimpleEventHandler) |
|
158 |
+ |
|
159 |
+ request = DummyRequest(['']) |
|
160 |
+ request.getCookie = mock.Mock() |
|
161 |
+ request.content = StringIO.StringIO('{"jsonrpc": "2.0", "params": {"v": %s}, "method": "echo", "id": "%s"}' % (jsonrpc.jsonutil.encode(self.param), self.id_)) |
|
162 |
+ |
|
163 |
+ d = _render(resource, request) |
|
164 |
+ |
|
165 |
+ @d.addCallback |
|
166 |
+ def rendered(ignored): |
|
167 |
+ assert len(request.written) == 1 |
|
168 |
+ data = jsonrpc.jsonutil.decode(request.written[0]) |
|
169 |
+ |
|
170 |
+ assert data['id'] == self.id_ |
|
171 |
+ assert data['result'] == self.param |
|
172 |
+ |
|
173 |
+ return d |
|
174 |
+ |
|
175 |
+ |
|
176 |
+ def test_err(self): |
|
177 |
+ resource = jsonrpc.server.JSON_RPC() |
|
178 |
+ resource.customize(SimpleEventHandler) |
|
179 |
+ |
|
180 |
+ request = DummyRequest(['']) |
|
181 |
+ request.getCookie = mock.Mock() |
|
182 |
+ request.content = StringIO.StringIO('{"jsonrpc": "2.0", "params": [1, "sss"], "method": "add", "id": "%s"}' % self.id_) |
|
183 |
+ |
|
184 |
+ d = _render(resource, request) |
|
185 |
+ |
|
186 |
+ @d.addCallback |
|
187 |
+ def rendered(ignored, *a): |
|
188 |
+ assert len(request.written) == 1 |
|
189 |
+ data = jsonrpc.jsonutil.decode(request.written[0]) |
|
190 |
+ |
|
191 |
+ assert data['id'] == self.id_ |
|
192 |
+ assert data.get('error', False) |
|
193 |
+ return rendered |
|
194 |
+ |
|
195 |
+ def test_batchcall(self): |
|
196 |
+ resource = jsonrpc.server.JSON_RPC() |
|
197 |
+ resource.customize(SimpleEventHandler) |
|
198 |
+ |
|
199 |
+ request = DummyRequest(['']) |
|
200 |
+ request.content = StringIO.StringIO( |
|
201 |
+ '[{"jsonrpc": "2.0", "params": [1, 2], "method": "add", "id": "1"},' |
|
202 |
+ '{"jsonrpc": "2.0", "params": {"a": 3, "b": 2}, "method": "add", "id": "2"}]' |
|
203 |
+ ) |
|
204 |
+ request.getCookie = mock.Mock() |
|
205 |
+ |
|
206 |
+ d = _render(resource, request) |
|
207 |
+ |
|
208 |
+ @d.addCallback |
|
209 |
+ def rendered(ignored, *a): |
|
210 |
+ assert len(request.written) == 1 |
|
211 |
+ data = jsonrpc.jsonutil.decode(request.written[0]) |
|
212 |
+ assert len(data) == 2 |
|
213 |
+ assert set(x['id'] for x in data) == set("12") |
|
214 |
+ assert set(x['result'] for x in data) == set([3,5]) |
|
215 |
+ |
|
216 |
+ assert not any(x.get('error', False) for x in data) |
|
217 |
+ return rendered |
|
218 |
+ |
|
219 |
+ def test_batchcall_1err(self): |
|
220 |
+ resource = jsonrpc.server.JSON_RPC() |
|
221 |
+ resource.customize(SimpleEventHandler) |
|
222 |
+ |
|
223 |
+ request = DummyRequest(['']) |
|
224 |
+ request.content = StringIO.StringIO( |
|
225 |
+ '[{"jsonrpc": "2.0", "params": [1, 2], "method": "add", "id": "1"},' |
|
226 |
+ '{"jsonrpc": "2.0", "params": {"a": "3", "b": 2}, "method": "add", "id": "2"}]' |
|
227 |
+ ) |
|
228 |
+ request.getCookie = mock.Mock() |
|
229 |
+ |
|
230 |
+ d = _render(resource, request) |
|
231 |
+ |
|
232 |
+ @d.addCallback |
|
233 |
+ def rendered(ignored, *a): |
|
234 |
+ assert len(request.written) == 1 |
|
235 |
+ data = jsonrpc.jsonutil.decode(request.written[0]) |
|
236 |
+ assert len(data) == 2 |
|
237 |
+ assert set(x['id'] for x in data) == set("12") |
|
238 |
+ assert set(x.get('result', False) for x in data) == set([3,False]) |
|
239 |
+ |
|
240 |
+ assert len(filter(None, [x.get('error') for x in data])) == 1 |
|
241 |
+ return rendered |
|
242 |
+ |
|
243 |
+ |
|
244 |
+ def test_batchcall_emptylist(self): |
|
245 |
+ resource = jsonrpc.server.JSON_RPC() |
|
246 |
+ resource.customize(SimpleEventHandler) |
|
247 |
+ |
|
248 |
+ request = DummyRequest(['']) |
|
249 |
+ |
|
250 |
+ request.content = StringIO.StringIO('[]') |
|
251 |
+ request.getCookie = mock.Mock() |
|
252 |
+ |
|
253 |
+ d = _render(resource, request) |
|
254 |
+ |
|
255 |
+ @d.addCallback |
|
256 |
+ def rendered(ignored, *a): |
|
257 |
+ data = jsonrpc.jsonutil.decode(request.written[0]) |
|
258 |
+ assert data == {"jsonrpc": "2.0", "error": {"code": -32600, "message": "Invalid Request."}, "id": None} |
|
259 |
+ return rendered |
|
260 |
+ |
|
261 |
+ |