Merge lp:~free.ekanayaka/landscape-client/amp-test-readability into lp:~landscape/landscape-client/trunk
- amp-test-readability
- Merge into trunk
Status: | Merged | ||||
---|---|---|---|---|---|
Approved by: | Free Ekanayaka | ||||
Approved revision: | 674 | ||||
Merged at revision: | 674 | ||||
Proposed branch: | lp:~free.ekanayaka/landscape-client/amp-test-readability | ||||
Merge into: | lp:~landscape/landscape-client/trunk | ||||
Diff against target: |
781 lines (+168/-275) 2 files modified
landscape/lib/amp.py (+5/-5) landscape/lib/tests/test_amp.py (+163/-270) |
||||
To merge this branch: | bzr merge lp:~free.ekanayaka/landscape-client/amp-test-readability | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Chris Glass (community) | Approve | ||
Christopher Armstrong (community) | Approve | ||
Review via email: mp+163525@code.launchpad.net |
Commit message
This is the last branch I have around cleaning up the AMP-based machinery in the client. It essentially just change the tests:
- Drop the Words class, which had a bunch of ad-hoc methods used to exercise the behavior of the MethodCall protocol. Essentially each method was associated with a test, but the context was not clear by reading the test itself (you'd have to go and read the implementation in the Words class).
- Modify most methods to define the remotely-exposed method being tested, so the context is clear.
- Partially re-wrote RemoteObjectTest, which had a bunch of tests which were only duplicating tests from MethodCallTest. Now this test class has only tests that are really specific to RemoteObject.
Description of the change
This is the last branch I have around cleaning up the AMP-based machinery in the client. It essentially just change the tests:
- Drop the Words class, which had a bunch of ad-hoc methods used to exercise the behavior of the MethodCall protocol. Essentially each method was associated with a test, but the context was not clear by reading the test itself (you'd have to go and read the implementation in the Words class).
- Modify most methods to define the remotely-exposed method being tested, so the context is clear.
- Partially re-wrote RemoteObjectTest, which had a bunch of tests which were only duplicating tests from MethodCallTest. Now this test class has only tests that are really specific to RemoteObject.
Chris Glass (tribaal) wrote : | # |
Nice! +1
[1]
landscape/
Preview Diff
1 | === modified file 'landscape/lib/amp.py' |
2 | --- landscape/lib/amp.py 2013-05-07 15:55:25 +0000 |
3 | +++ landscape/lib/amp.py 2013-05-13 12:57:34 +0000 |
4 | @@ -216,8 +216,8 @@ |
5 | _chunk_size = MAX_VALUE_LENGTH |
6 | |
7 | def __init__(self, protocol, clock): |
8 | - self.protocol = protocol |
9 | - self.clock = clock |
10 | + self._protocol = protocol |
11 | + self._clock = clock |
12 | |
13 | def _call_remote_with_timeout(self, command, **kwargs): |
14 | """Send an L{AMP} command that will errback in case of a timeout. |
15 | @@ -240,9 +240,9 @@ |
16 | # The peer didn't respond on time, raise an error. |
17 | deferred.errback(MethodCallError("timeout")) |
18 | |
19 | - call = self.clock.callLater(self.timeout, handle_timeout) |
20 | + call = self._clock.callLater(self.timeout, handle_timeout) |
21 | |
22 | - result = self.protocol.callRemote(command, **kwargs) |
23 | + result = self._protocol.callRemote(command, **kwargs) |
24 | result.addBoth(handle_response) |
25 | return deferred |
26 | |
27 | @@ -273,7 +273,7 @@ |
28 | for chunk in chunks[:-1]: |
29 | |
30 | def create_send_chunk(sequence, chunk): |
31 | - send_chunk = lambda x: self.protocol.callRemote( |
32 | + send_chunk = lambda x: self._protocol.callRemote( |
33 | MethodCallChunk, sequence=sequence, chunk=chunk) |
34 | return send_chunk |
35 | |
36 | |
37 | === modified file 'landscape/lib/tests/test_amp.py' |
38 | --- landscape/lib/tests/test_amp.py 2013-05-06 18:17:43 +0000 |
39 | +++ landscape/lib/tests/test_amp.py 2013-05-13 12:57:34 +0000 |
40 | @@ -88,102 +88,18 @@ |
41 | self.connection.lose(self, Failure(ConnectionDone())) |
42 | |
43 | |
44 | -class WordsException(Exception): |
45 | - """Test exception.""" |
46 | - |
47 | - |
48 | -class Words(object): |
49 | - """ |
50 | - Test class to be used as target object of a L{MethodCallServerFactory}. |
51 | - """ |
52 | - |
53 | - def __init__(self, clock=None): |
54 | - self._clock = clock |
55 | - |
56 | - def secret(self): |
57 | - raise RuntimeError("I'm not supposed to be called!") |
58 | - |
59 | - def empty(self): |
60 | - pass |
61 | - |
62 | - def motd(self): |
63 | - return "Words are cool" |
64 | - |
65 | - def capitalize(self, word): |
66 | - return word.capitalize() |
67 | - |
68 | - def is_short(self, word): |
69 | - return len(word) < 4 |
70 | - |
71 | - def concatenate(self, word1, word2): |
72 | - return word1 + word2 |
73 | - |
74 | - def lower_case(self, word, index=None): |
75 | - if index is None: |
76 | - return word.lower() |
77 | - else: |
78 | - return word[:index] + word[index:].lower() |
79 | - |
80 | - def multiply_alphabetically(self, word_times): |
81 | - result = "" |
82 | - for word, times in sorted(word_times.iteritems()): |
83 | - result += word * times |
84 | - return result |
85 | - |
86 | - def meaning_of_life(self): |
87 | - |
88 | - class Complex(object): |
89 | - pass |
90 | - return Complex() |
91 | - |
92 | - def _check(self, word, seed, value=3): |
93 | - if seed == "cool" and value == 4: |
94 | - return "Guessed!" |
95 | - |
96 | - def guess(self, word, *args, **kwargs): |
97 | - return self._check(word, *args, **kwargs) |
98 | - |
99 | - def translate(self, word): |
100 | - raise WordsException("Unknown word") |
101 | - |
102 | - def google(self, word): |
103 | - deferred = Deferred() |
104 | - if word == "Landscape": |
105 | - self._clock.callLater(0.01, lambda: deferred.callback("Cool!")) |
106 | - elif word == "Easy query": |
107 | - deferred.callback("Done!") |
108 | - elif word == "Weird stuff": |
109 | - error = Exception("bad") |
110 | - self._clock.callLater(0.01, lambda: deferred.errback(error)) |
111 | - elif word == "Censored": |
112 | - deferred.errback(Exception("very bad")) |
113 | - elif word == "Long query": |
114 | - # Do nothing, the deferred won't be fired at all |
115 | - pass |
116 | - elif word == "Slowish query": |
117 | - # Fire the result after a while. |
118 | - self._clock.callLater(120.0, lambda: deferred.callback("Done!")) |
119 | - return deferred |
120 | - |
121 | - |
122 | -METHODS = ["empty", |
123 | - "motd", |
124 | - "capitalize", |
125 | - "is_short", |
126 | - "concatenate", |
127 | - "lower_case", |
128 | - "multiply_alphabetically", |
129 | - "translate", |
130 | - "meaning_of_life", |
131 | - "guess", |
132 | - "google"] |
133 | +class DummyObject(object): |
134 | + |
135 | + method = None |
136 | |
137 | |
138 | class MethodCallTest(LandscapeTest): |
139 | |
140 | def setUp(self): |
141 | super(MethodCallTest, self).setUp() |
142 | - server = MethodCallServerProtocol(Words(), METHODS) |
143 | + self.methods = ["method"] |
144 | + self.object = DummyObject() |
145 | + server = MethodCallServerProtocol(self.object, self.methods) |
146 | client = MethodCallClientProtocol() |
147 | self.connection = FakeConnection(client, server) |
148 | self.connection.make() |
149 | @@ -195,7 +111,8 @@ |
150 | If a method is not included in L{MethodCallServerFactory.methods} it |
151 | can't be called. |
152 | """ |
153 | - deferred = self.sender.send_method_call(method="secret", |
154 | + self.methods.remove("method") |
155 | + deferred = self.sender.send_method_call(method="method", |
156 | args=[], |
157 | kwargs={}) |
158 | self.connection.flush() |
159 | @@ -206,7 +123,8 @@ |
160 | A connected client can issue a L{MethodCall} without arguments and |
161 | with an empty response. |
162 | """ |
163 | - deferred = self.sender.send_method_call(method="empty", |
164 | + self.object.method = lambda: None |
165 | + deferred = self.sender.send_method_call(method="method", |
166 | args=[], |
167 | kwargs={}) |
168 | self.connection.flush() |
169 | @@ -217,18 +135,20 @@ |
170 | A connected client can issue a L{MethodCall} targeted to an |
171 | object method with a return value. |
172 | """ |
173 | - deferred = self.sender.send_method_call(method="motd", |
174 | + self.object.method = lambda: "Cool result" |
175 | + deferred = self.sender.send_method_call(method="method", |
176 | args=[], |
177 | kwargs={}) |
178 | self.connection.flush() |
179 | - self.assertEqual("Words are cool", self.successResultOf(deferred)) |
180 | + self.assertEqual("Cool result", self.successResultOf(deferred)) |
181 | |
182 | def test_with_one_argument(self): |
183 | """ |
184 | A connected AMP client can issue a L{MethodCall} with one argument and |
185 | a response value. |
186 | """ |
187 | - deferred = self.sender.send_method_call(method="capitalize", |
188 | + self.object.method = lambda word: word.capitalize() |
189 | + deferred = self.sender.send_method_call(method="method", |
190 | args=["john"], |
191 | kwargs={}) |
192 | self.connection.flush() |
193 | @@ -238,7 +158,8 @@ |
194 | """ |
195 | The return value of a L{MethodCall} argument can be a boolean. |
196 | """ |
197 | - deferred = self.sender.send_method_call(method="is_short", |
198 | + self.object.method = lambda word: len(word) < 3 |
199 | + deferred = self.sender.send_method_call(method="method", |
200 | args=["hi"], |
201 | kwargs={}) |
202 | self.connection.flush() |
203 | @@ -248,7 +169,8 @@ |
204 | """ |
205 | A connected client can issue a L{MethodCall} with many arguments. |
206 | """ |
207 | - deferred = self.sender.send_method_call(method="concatenate", |
208 | + self.object.method = lambda word1, word2: word1 + word2 |
209 | + deferred = self.sender.send_method_call(method="method", |
210 | args=["We ", "rock"], |
211 | kwargs={}) |
212 | self.connection.flush() |
213 | @@ -259,7 +181,8 @@ |
214 | A connected client can issue a L{MethodCall} for methods having |
215 | default arguments. |
216 | """ |
217 | - deferred = self.sender.send_method_call(method="lower_case", |
218 | + self.object.method = lambda word, index=0: word[index:].lower() |
219 | + deferred = self.sender.send_method_call(method="method", |
220 | args=["OHH"], |
221 | kwargs={}) |
222 | self.connection.flush() |
223 | @@ -271,29 +194,34 @@ |
224 | having default values in the target object. If a value is specified by |
225 | the caller it will be used in place of the default value |
226 | """ |
227 | - deferred = self.sender.send_method_call(method="lower_case", |
228 | - args=["OHH"], |
229 | + self.object.method = lambda word, index=0: word[index:].lower() |
230 | + deferred = self.sender.send_method_call(method="method", |
231 | + args=["ABC"], |
232 | kwargs={"index": 2}) |
233 | self.connection.flush() |
234 | - self.assertEqual("OHh", self.successResultOf(deferred)) |
235 | + self.assertEqual("c", self.successResultOf(deferred)) |
236 | |
237 | def test_with_dictionary_arguments(self): |
238 | """ |
239 | Method arguments passed to a L{MethodCall} can be dictionaries. |
240 | """ |
241 | - deferred = self.sender.send_method_call(method="multiply_" |
242 | - "alphabetically", |
243 | - args=[{"foo": 2, "bar": 3}], |
244 | + self.object.method = lambda d: "".join(d.keys()) * sum(d.values()) |
245 | + deferred = self.sender.send_method_call(method="method", |
246 | + args=[{"foo": 1, "bar": 2}], |
247 | kwargs={}) |
248 | self.connection.flush() |
249 | - self.assertEqual("barbarbarfoofoo", self.successResultOf(deferred)) |
250 | + self.assertEqual("foobarfoobarfoobar", self.successResultOf(deferred)) |
251 | |
252 | def test_with_non_serializable_return_value(self): |
253 | """ |
254 | If the target object method returns an object that can't be serialized, |
255 | - the L{MethodCall} result is C{None}. |
256 | + the L{MethodCall} raises an error. |
257 | """ |
258 | - deferred = self.sender.send_method_call(method="meaning_of_life", |
259 | + class Complex(object): |
260 | + pass |
261 | + |
262 | + self.object.method = lambda: Complex() |
263 | + deferred = self.sender.send_method_call(method="method", |
264 | args=[], |
265 | kwargs={}) |
266 | self.connection.flush() |
267 | @@ -304,206 +232,106 @@ |
268 | The L{MethodCall} protocol supports sending method calls with arguments |
269 | bigger than the maximum AMP parameter value size. |
270 | """ |
271 | - deferred = self.sender.send_method_call(method="is_short", |
272 | + self.object.method = lambda word: len(word) == 65535 |
273 | + deferred = self.sender.send_method_call(method="method", |
274 | args=["!" * 65535], |
275 | kwargs={}) |
276 | self.connection.flush() |
277 | - self.assertFalse(self.successResultOf(deferred)) |
278 | + self.assertTrue(self.successResultOf(deferred)) |
279 | |
280 | def test_with_long_argument_multiple_calls(self): |
281 | """ |
282 | The L{MethodCall} protocol supports concurrently sending multiple |
283 | method calls with arguments bigger than the maximum AMP value size. |
284 | """ |
285 | - deferred1 = self.sender.send_method_call(method="is_short", |
286 | + self.object.method = lambda word: len(word) |
287 | + deferred1 = self.sender.send_method_call(method="method", |
288 | args=["!" * 80000], |
289 | kwargs={}) |
290 | - deferred2 = self.sender.send_method_call(method="is_short", |
291 | + deferred2 = self.sender.send_method_call(method="method", |
292 | args=["*" * 90000], |
293 | kwargs={}) |
294 | |
295 | self.connection.flush() |
296 | - self.assertFalse(self.successResultOf(deferred1)) |
297 | - self.assertFalse(self.successResultOf(deferred2)) |
298 | + self.assertEqual(80000, self.successResultOf(deferred1)) |
299 | + self.assertEqual(90000, self.successResultOf(deferred2)) |
300 | |
301 | - def test_translate(self): |
302 | + def test_with_exception(self): |
303 | """ |
304 | If the target object method raises an exception, the remote call fails |
305 | with a L{MethodCallError}. |
306 | """ |
307 | - deferred = self.sender.send_method_call(method="translate", |
308 | - args=["hi"], |
309 | + self.object.method = lambda a, b: a / b |
310 | + deferred = self.sender.send_method_call(method="method", |
311 | + args=[1, 0], |
312 | kwargs={}) |
313 | self.connection.flush() |
314 | self.failureResultOf(deferred).trap(MethodCallError) |
315 | |
316 | - |
317 | -class RemoteObjectTest(LandscapeTest): |
318 | - |
319 | - def setUp(self): |
320 | - super(RemoteObjectTest, self).setUp() |
321 | - self.clock = Clock() |
322 | - self.factory = MethodCallClientFactory(self.clock) |
323 | - server_factory = MethodCallServerFactory(Words(self.clock), METHODS) |
324 | - self.connector = FakeConnector(self.factory, server_factory) |
325 | - self.connector.connect() |
326 | - self.remote = self.successResultOf(self.factory.getRemoteObject()) |
327 | - |
328 | - def test_method_call_sender_with_forbidden_method(self): |
329 | - """ |
330 | - A L{RemoteObject} can send L{MethodCall}s without arguments and withj |
331 | - an empty response. |
332 | - """ |
333 | - deferred = self.remote.secret() |
334 | - self.failureResultOf(deferred).trap(MethodCallError) |
335 | - |
336 | - def test_with_no_arguments(self): |
337 | - """ |
338 | - A L{RemoteObject} can send L{MethodCall}s without arguments and withj |
339 | - an empty response. |
340 | - """ |
341 | - deferred = self.remote.empty() |
342 | - self.assertIs(None, self.successResultOf(deferred)) |
343 | - |
344 | - def test_with_return_value(self): |
345 | - """ |
346 | - A L{RemoteObject} can send L{MethodCall}s without arguments and get |
347 | - back the value of the commands's response. |
348 | - """ |
349 | - deferred = self.remote.motd() |
350 | - self.assertEqual("Words are cool", self.successResultOf(deferred)) |
351 | - |
352 | - def test_with_one_argument(self): |
353 | - """ |
354 | - A L{RemoteObject} can send L{MethodCall}s with one argument and get |
355 | - the response value. |
356 | - """ |
357 | - deferred = self.remote.capitalize("john") |
358 | - self.assertEqual("John", self.successResultOf(deferred)) |
359 | - |
360 | - def test_with_one_keyword_argument(self): |
361 | - """ |
362 | - A L{RemoteObject} can send L{MethodCall}s with a named argument. |
363 | - """ |
364 | - deferred = self.remote.capitalize(word="john") |
365 | - self.assertEqual("John", self.successResultOf(deferred)) |
366 | - |
367 | - def test_with_boolean_return_value(self): |
368 | - """ |
369 | - The return value of a L{MethodCall} argument can be a boolean. |
370 | - """ |
371 | - return self.assertSuccess(self.remote.is_short("hi"), True) |
372 | - |
373 | - def test_with_many_arguments(self): |
374 | - """ |
375 | - A L{RemoteObject} can send L{MethodCall}s with more than one argument. |
376 | - """ |
377 | - deferred = self.remote.concatenate("You ", "rock") |
378 | - self.assertEqual("You rock", self.successResultOf(deferred)) |
379 | - |
380 | - def test_with_many_keyword_arguments(self): |
381 | - """ |
382 | - A L{RemoteObject} can send L{MethodCall}s with several |
383 | - named arguments. |
384 | - """ |
385 | - deferred = self.remote.concatenate(word2="rock", word1="You ") |
386 | - self.assertEqual("You rock", self.successResultOf(deferred)) |
387 | - |
388 | - def test_with_default_arguments(self): |
389 | - """ |
390 | - A L{RemoteObject} can send a L{MethodCall} having an argument with |
391 | - a default value. |
392 | - """ |
393 | - deferred = self.remote.lower_case("OHH") |
394 | - self.assertEqual("ohh", self.successResultOf(deferred)) |
395 | - |
396 | - def test_with_overriden_default_arguments(self): |
397 | - """ |
398 | - A L{RemoteObject} can send L{MethodCall}s overriding the default |
399 | - value of an argument. |
400 | - """ |
401 | - deferred = self.remote.lower_case("OHH", 2) |
402 | - self.assertEqual("OHh", self.successResultOf(deferred)) |
403 | - |
404 | - def test_with_dictionary_arguments(self): |
405 | - """ |
406 | - A L{RemoteObject} can send a L{MethodCall}s for methods requiring |
407 | - a dictionary arguments. |
408 | - """ |
409 | - deferred = self.remote.multiply_alphabetically({"foo": 2, "bar": 3}) |
410 | - self.assertEqual("barbarbarfoofoo", self.successResultOf(deferred)) |
411 | - |
412 | - def test_with_generic_args_and_kwargs(self): |
413 | - """ |
414 | - A L{RemoteObject} behaves well with L{MethodCall}s for methods |
415 | - having generic C{*args} and C{**kwargs} arguments. |
416 | - """ |
417 | - deferred = self.remote.guess("word", "cool", value=4) |
418 | - self.assertEqual("Guessed!", self.successResultOf(deferred)) |
419 | - |
420 | def test_with_successful_deferred(self): |
421 | """ |
422 | If the target object method returns a L{Deferred}, it is handled |
423 | transparently. |
424 | """ |
425 | + self.object.deferred = Deferred() |
426 | + self.object.method = lambda: self.object.deferred |
427 | result = [] |
428 | - deferred = self.remote.google("Landscape") |
429 | + deferred = self.sender.send_method_call(method="method", |
430 | + args=[], |
431 | + kwargs={}) |
432 | deferred.addCallback(result.append) |
433 | |
434 | + self.connection.flush() |
435 | + |
436 | # At this point the receiver is waiting for method to complete, so |
437 | # the deferred has not fired yet |
438 | self.assertEqual([], result) |
439 | |
440 | - # Simulate time advancing and the receiver responding |
441 | - self.clock.advance(0.5) |
442 | - self.connector.connection.flush() |
443 | + # Fire the deferred and let the receiver respond |
444 | + self.object.deferred.callback("Hey!") |
445 | + self.connection.flush() |
446 | |
447 | - self.assertEqual(["Cool!"], result) |
448 | + self.assertEqual(["Hey!"], result) |
449 | |
450 | def test_with_failing_deferred(self): |
451 | """ |
452 | If the target object method returns a failing L{Deferred}, a |
453 | L{MethodCallError} is raised. |
454 | """ |
455 | + self.object.deferred = Deferred() |
456 | + self.object.method = lambda: self.object.deferred |
457 | result = [] |
458 | - deferred = self.remote.google("Weird stuff") |
459 | + deferred = self.sender.send_method_call(method="method", |
460 | + args=[], |
461 | + kwargs={}) |
462 | deferred.addErrback(result.append) |
463 | |
464 | + self.connection.flush() |
465 | + |
466 | # At this point the receiver is waiting for method to complete, so |
467 | # the deferred has not fired yet |
468 | self.assertEqual([], result) |
469 | |
470 | # Simulate time advancing and the receiver responding |
471 | - self.clock.advance(0.5) |
472 | - self.connector.connection.flush() |
473 | + self.object.deferred.errback(Exception()) |
474 | + self.connection.flush() |
475 | |
476 | [failure] = result |
477 | failure.trap(MethodCallError) |
478 | |
479 | - def test_with_already_callback_deferred(self): |
480 | - """ |
481 | - The target object method can return an already fired L{Deferred}. |
482 | - """ |
483 | - deferred = self.remote.google("Easy query") |
484 | - self.assertEqual("Done!", self.successResultOf(deferred)) |
485 | - |
486 | - def test_with_already_errback_deferred(self): |
487 | - """ |
488 | - If the target object method can return an already failed L{Deferred}. |
489 | - """ |
490 | - deferred = self.remote.google("Censored") |
491 | - self.failureResultOf(deferred).trap(MethodCallError) |
492 | - |
493 | def test_with_deferred_timeout(self): |
494 | """ |
495 | If the peer protocol doesn't send a response for a deferred within |
496 | the given timeout, the method call fails. |
497 | """ |
498 | + self.object.method = lambda: Deferred() |
499 | result = [] |
500 | - deferred = self.remote.google("Long query") |
501 | + deferred = self.sender.send_method_call(method="method", |
502 | + args=[], |
503 | + kwargs={}) |
504 | deferred.addErrback(result.append) |
505 | |
506 | - self.clock.advance(60.0) |
507 | + self.clock.advance(60) |
508 | |
509 | [failure] = result |
510 | failure.trap(MethodCallError) |
511 | @@ -513,15 +341,71 @@ |
512 | If the peer protocol sends a late response for a request that has |
513 | already timeout, that response is ignored. |
514 | """ |
515 | + self.object.deferred = Deferred() |
516 | + self.object.method = lambda: self.object.deferred |
517 | result = [] |
518 | - deferred = self.remote.google("Slowish query") |
519 | + deferred = self.sender.send_method_call(method="method", |
520 | + args=[], |
521 | + kwargs={}) |
522 | deferred.addErrback(result.append) |
523 | |
524 | - self.clock.advance(120.0) |
525 | + self.clock.advance(60) |
526 | + self.object.deferred.callback("late") |
527 | |
528 | [failure] = result |
529 | failure.trap(MethodCallError) |
530 | |
531 | + |
532 | +class RemoteObjectTest(LandscapeTest): |
533 | + |
534 | + def setUp(self): |
535 | + super(RemoteObjectTest, self).setUp() |
536 | + self.methods = ["method"] |
537 | + self.object = DummyObject() |
538 | + self.clock = Clock() |
539 | + self.factory = MethodCallClientFactory(self.clock) |
540 | + server_factory = MethodCallServerFactory(self.object, self.methods) |
541 | + self.connector = FakeConnector(self.factory, server_factory) |
542 | + self.connector.connect() |
543 | + self.remote = self.successResultOf(self.factory.getRemoteObject()) |
544 | + |
545 | + def test_with_forbidden_method(self): |
546 | + """ |
547 | + A L{RemoteObject} can send L{MethodCall}s without arguments and withj |
548 | + an empty response. |
549 | + """ |
550 | + self.methods.remove("method") |
551 | + deferred = self.remote.method() |
552 | + failure = self.failureResultOf(deferred) |
553 | + self.assertEqual("Forbidden method 'method'", str(failure.value)) |
554 | + |
555 | + def test_with_no_arguments(self): |
556 | + """ |
557 | + A L{RemoteObject} can send L{MethodCall}s without arguments and with |
558 | + an empty response. |
559 | + """ |
560 | + self.object.method = lambda: None |
561 | + deferred = self.remote.method() |
562 | + self.assertIs(None, self.successResultOf(deferred)) |
563 | + |
564 | + def test_with_return_value(self): |
565 | + """ |
566 | + A L{RemoteObject} can send L{MethodCall}s without arguments and get |
567 | + back the value of the commands's response. |
568 | + """ |
569 | + self.object.method = lambda: "Cool" |
570 | + deferred = self.remote.method() |
571 | + self.assertEqual("Cool", self.successResultOf(deferred)) |
572 | + |
573 | + def test_with_arguments(self): |
574 | + """ |
575 | + A L{RemoteObject} can send L{MethodCall}s with one argument and get |
576 | + the response value. |
577 | + """ |
578 | + self.object.method = lambda word, times=2: word * times |
579 | + deferred = self.remote.method("hi", times=3) |
580 | + self.assertEqual("hihihi", self.successResultOf(deferred)) |
581 | + |
582 | def test_method_call_error(self): |
583 | """ |
584 | If a L{MethodCall} fails due to a L{MethodCallError}, |
585 | @@ -529,8 +413,9 @@ |
586 | C{retryOnReconnect} error is set, as a L{MethodCallError} is a |
587 | permanent failure that is not likely to ever succeed. |
588 | """ |
589 | + self.methods.remove("method") |
590 | self.factory.retryOnReconnect = True |
591 | - deferred = self.remote.secret() |
592 | + deferred = self.remote.method() |
593 | self.failureResultOf(deferred).trap(MethodCallError) |
594 | |
595 | def test_retry(self): |
596 | @@ -539,10 +424,11 @@ |
597 | factory, the L{RemoteObject} will transparently retry to perform |
598 | the L{MethodCall} requests that failed due to the broken connections. |
599 | """ |
600 | + self.object.method = lambda word: word.capitalize() |
601 | self.factory.factor = 0.19 |
602 | self.factory.retryOnReconnect = True |
603 | self.connector.disconnect() |
604 | - deferred = self.remote.capitalize("john") |
605 | + deferred = self.remote.method("john") |
606 | |
607 | # The deferred has not fired yet, because it's been put in the pending |
608 | # queue, until the call gets a chance to be retried upon reconnection |
609 | @@ -560,10 +446,11 @@ |
610 | the L{RemoteObject} will properly propagate the error to the original |
611 | caller. |
612 | """ |
613 | + self.methods.remove("method") |
614 | self.factory.factor = 0.19 |
615 | self.factory.retryOnReconnect = True |
616 | self.connector.disconnect() |
617 | - deferred = self.remote.secret() |
618 | + deferred = self.remote.method() |
619 | |
620 | # The deferred has not fired yet, because it's been put in the pending |
621 | # queue, until the call gets a chance to be retried upon reconnection |
622 | @@ -573,7 +460,7 @@ |
623 | self.clock.advance(1) |
624 | |
625 | failure = self.failureResultOf(deferred) |
626 | - self.assertEqual("Forbidden method 'secret'", str(failure.value)) |
627 | + self.assertEqual("Forbidden method 'method'", str(failure.value)) |
628 | |
629 | |
630 | class MethodCallClientFactoryTest(LandscapeTest): |
631 | @@ -657,26 +544,30 @@ |
632 | If the connection is lost, the L{RemoteObject} created by the creator |
633 | will transparently handle the reconnection. |
634 | """ |
635 | - server_factory = MethodCallServerFactory(Words(self.clock), METHODS) |
636 | + dummy_object = DummyObject() |
637 | + dummy_object.method = lambda: None |
638 | + server_factory = MethodCallServerFactory(dummy_object, ["method"]) |
639 | connector = FakeConnector(self.factory, server_factory) |
640 | connector.connect() |
641 | remote = self.successResultOf(self.factory.getRemoteObject()) |
642 | |
643 | connector.disconnect() |
644 | self.clock.advance(5) |
645 | - deferred = remote.empty() |
646 | + deferred = remote.method() |
647 | self.assertIsNone(self.successResultOf(deferred)) |
648 | |
649 | |
650 | -class MethodCallFunctionalTest(TestCase): |
651 | +class MethodCallFunctionalTest(LandscapeTest): |
652 | |
653 | def setUp(self): |
654 | super(MethodCallFunctionalTest, self).setUp() |
655 | + self.methods = ["method"] |
656 | + self.object = DummyObject() |
657 | + self.object.method = lambda word: word.capitalize() |
658 | self.socket = self.mktemp() |
659 | - self.server = MethodCallServerFactory(Words(reactor), METHODS) |
660 | + self.server = MethodCallServerFactory(self.object, self.methods) |
661 | self.client = MethodCallClientFactory(reactor) |
662 | self.port = reactor.listenUNIX(self.socket, self.server) |
663 | - #self.client.maxRetries = 0 # By default, don't try to reconnect |
664 | |
665 | def tearDown(self): |
666 | super(MethodCallFunctionalTest, self).tearDown() |
667 | @@ -691,7 +582,7 @@ |
668 | """ |
669 | connector = reactor.connectUNIX(self.socket, self.client) |
670 | remote = yield self.client.getRemoteObject() |
671 | - result = yield remote.capitalize("john") |
672 | + result = yield remote.method("john") |
673 | self.assertEqual(result, "John") |
674 | self.client.stopTrying() |
675 | connector.disconnect() |
676 | @@ -724,7 +615,7 @@ |
677 | yield deferred |
678 | |
679 | # The remote object is still working |
680 | - result = yield remote.capitalize("john") |
681 | + result = yield remote.method("john") |
682 | self.assertEqual(result, "John") |
683 | self.client.stopTrying() |
684 | connector.disconnect() |
685 | @@ -745,7 +636,7 @@ |
686 | connector.disconnect() |
687 | |
688 | # This call will fail but it's transparently retried |
689 | - result = yield remote.capitalize("john") |
690 | + result = yield remote.method("john") |
691 | self.assertEqual(result, "John") |
692 | self.client.stopTrying() |
693 | connector.disconnect() |
694 | @@ -757,6 +648,7 @@ |
695 | the L{RemoteObject} will properly propagate the error to the original |
696 | caller. |
697 | """ |
698 | + self.methods.remove("method") |
699 | self.client.factor = 0.01 # Try reconnecting very quickly |
700 | self.client.retryOnReconnect = True |
701 | connector = reactor.connectUNIX(self.socket, self.client) |
702 | @@ -766,7 +658,7 @@ |
703 | connector.disconnect() |
704 | |
705 | # A method call error is not retried |
706 | - yield self.assertFailure(remote.secret(), MethodCallError) |
707 | + yield self.assertFailure(remote.method(), MethodCallError) |
708 | self.client.stopTrying() |
709 | connector.disconnect() |
710 | |
711 | @@ -777,6 +669,7 @@ |
712 | connection is ready. If for whatever reason the connection drops |
713 | again very quickly, the C{_retry} method will behave as expected. |
714 | """ |
715 | + self.methods.remove("method") |
716 | self.client.factor = 0.01 # Try reconnecting very quickly |
717 | self.client.retryOnReconnect = True |
718 | connector = reactor.connectUNIX(self.socket, self.client) |
719 | @@ -787,7 +680,7 @@ |
720 | |
721 | def handle_reconnect(protocol): |
722 | # In this precise moment we have a newly connected protocol |
723 | - remote._sender.protocol = protocol |
724 | + remote._sender._protocol = protocol |
725 | |
726 | # Pretend that the connection is lost again very quickly |
727 | protocol.transport.loseConnection() |
728 | @@ -800,14 +693,14 @@ |
729 | self.client.notifyOnConnect(remote._handle_connect) |
730 | |
731 | def assert_failure(error): |
732 | - self.assertEqual(str(error), "Forbidden method 'secret'") |
733 | + self.assertEqual(str(error), "Forbidden method 'method'") |
734 | |
735 | # Use our own reconnect handler |
736 | self.client.dontNotifyOnConnect(remote._handle_connect) |
737 | self.client.notifyOnConnect(handle_reconnect) |
738 | |
739 | - error = yield self.assertFailure(remote.secret(), MethodCallError) |
740 | - self.assertEqual(str(error), "Forbidden method 'secret'") |
741 | + error = yield self.assertFailure(remote.method(), MethodCallError) |
742 | + self.assertEqual(str(error), "Forbidden method 'method'") |
743 | |
744 | self.client.stopTrying() |
745 | connector.disconnect() |
746 | @@ -827,11 +720,11 @@ |
747 | # Disconnect |
748 | connector.disconnect() |
749 | |
750 | - result1 = yield remote.guess("word", "cool", value=4) |
751 | - result2 = yield remote.motd() |
752 | + result1 = yield remote.method("john") |
753 | + result2 = yield remote.method("bill") |
754 | |
755 | - self.assertEqual(result1, "Guessed!") |
756 | - self.assertEqual(result2, "Words are cool") |
757 | + self.assertEqual(result1, "John") |
758 | + self.assertEqual(result2, "Bill") |
759 | self.client.stopTrying() |
760 | connector.disconnect() |
761 | |
762 | @@ -855,8 +748,8 @@ |
763 | |
764 | # Wait for reconnection and peform another call |
765 | yield deferred |
766 | - result = yield remote.motd() |
767 | - self.assertEqual(result, "Words are cool") |
768 | + result = yield remote.method("john") |
769 | + self.assertEqual(result, "John") |
770 | |
771 | self.client.stopTrying() |
772 | connector.disconnect() |
773 | @@ -877,7 +770,7 @@ |
774 | # Disconnect |
775 | connector.disconnect() |
776 | |
777 | - error = yield self.assertFailure(remote.modt(), MethodCallError) |
778 | + error = yield self.assertFailure(remote.method("foo"), MethodCallError) |
779 | self.assertEqual("timeout", str(error)) |
780 | |
781 | self.client.stopTrying() |
I like code removal :-) Words was really weird. +1