Merge lp:~free.ekanayaka/landscape-client/amp-cleanup-6 into lp:~landscape/landscape-client/trunk
- amp-cleanup-6
- Merge into trunk
Status: | Merged | ||||
---|---|---|---|---|---|
Approved by: | Free Ekanayaka | ||||
Approved revision: | 670 | ||||
Merged at revision: | 666 | ||||
Proposed branch: | lp:~free.ekanayaka/landscape-client/amp-cleanup-6 | ||||
Merge into: | lp:~landscape/landscape-client/trunk | ||||
Diff against target: |
1005 lines (+180/-163) 21 files modified
landscape/amp.py (+7/-11) landscape/broker/amp.py (+3/-3) landscape/broker/tests/test_amp.py (+15/-13) landscape/broker/tests/test_service.py (+5/-1) landscape/configuration.py (+2/-1) landscape/lib/amp.py (+14/-0) landscape/lib/tests/test_amp.py (+17/-19) landscape/manager/tests/test_usermanager.py (+1/-1) landscape/manager/usermanager.py (+2/-4) landscape/monitor/tests/test_service.py (+0/-8) landscape/monitor/usermonitor.py (+2/-2) landscape/package/taskhandler.py (+1/-4) landscape/package/tests/test_changer.py (+1/-1) landscape/package/tests/test_taskhandler.py (+6/-9) landscape/reactor.py (+42/-25) landscape/service.py (+0/-5) landscape/tests/test_amp.py (+16/-20) landscape/tests/test_configuration.py (+42/-22) landscape/tests/test_service.py (+0/-5) landscape/tests/test_watchdog.py (+3/-8) landscape/watchdog.py (+1/-1) |
||||
To merge this branch: | bzr merge lp:~free.ekanayaka/landscape-client/amp-cleanup-6 | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Chris Glass (community) | Approve | ||
Christopher Armstrong (community) | Approve | ||
Geoff Teale (community) | Approve | ||
Review via email: mp+161643@code.launchpad.net |
Commit message
Another episode of the AMP-related cleanup:
- Rename landscape.
- Drop the landscape.
- Drop landscape.
- Update tests that were using FakeReactor.
- Make landscape.
- Drop landscape.
Description of the change
Another episode of the AMP-related cleanup:
- Rename landscape.
- Drop the landscape.
- Drop landscape.
- Update tests that were using FakeReactor.
- Make landscape.
- Drop landscape.
Christopher Armstrong (radix) wrote : | # |
Have you filed a bug about Twisted's AMP not supporting synchronous transports? I'm not really sure what that means, that's why I ask, so I can go check out the explanation on that bug.
[1] The code around the call to self._factory.
[2] It doesn't seem right that _socket_paths is a class attribute instead of an instance attribute
Everything else looks fine!
Chris Glass (tribaal) wrote : | # |
Looks good! Thanks for doing this cleanup.
[1]
landscape/
landscape/
Free Ekanayaka (free.ekanayaka) wrote : | # |
Hi Chris, thanks for the careful review. I've filed:
http://
describing the issue.
[1]
You're right, that code is only meant for unit tests. I've renamed MethodCallClien
# XXX support exposing fake asynchronous connections created by tests, so
# they can be flushed transparently and emulate a synchronous behavior. See
# also http://
# hack can be removed.
fake_connection = None
The FakeReactor.
connection = FakeConnection(
factory.
[2]
Yeah, that's indeed a hack. The problem is that FakeReactor instances for clients and servers need to be different. I added a comment:
# XXX probably this shouldn't be a class attribute, but we need client-side
# FakeReactor instaces to be aware of listening sockets created by
# server-side FakeReactor instances.
_socket_paths = {}
Maybe the way to solve it would be to add API for declaring a reactor "aware" of another reactor (so tests would need to call it explicitly). Suggestions are welcome.
- 669. By Free Ekanayaka
-
Address radix's comments
- 670. By Free Ekanayaka
-
Drop unused imports
Free Ekanayaka (free.ekanayaka) wrote : | # |
Hey Chris (Glass), unused imports fixed.
Preview Diff
1 | === modified file 'landscape/amp.py' | |||
2 | --- landscape/amp.py 2013-04-29 15:46:13 +0000 | |||
3 | +++ landscape/amp.py 2013-05-02 08:30:35 +0000 | |||
4 | @@ -17,11 +17,6 @@ | |||
5 | 17 | MethodCallClientFactory, MethodCallServerFactory, RemoteObject) | 17 | MethodCallClientFactory, MethodCallServerFactory, RemoteObject) |
6 | 18 | 18 | ||
7 | 19 | 19 | ||
8 | 20 | class ComponentProtocolClientFactory(MethodCallClientFactory): | ||
9 | 21 | |||
10 | 22 | initialDelay = 0.05 | ||
11 | 23 | |||
12 | 24 | |||
13 | 25 | class ComponentPublisher(object): | 20 | class ComponentPublisher(object): |
14 | 26 | """Publish a Landscape client component using a UNIX socket. | 21 | """Publish a Landscape client component using a UNIX socket. |
15 | 27 | 22 | ||
16 | @@ -35,6 +30,7 @@ | |||
17 | 35 | """ | 30 | """ |
18 | 36 | 31 | ||
19 | 37 | methods = ("ping", "exit") | 32 | methods = ("ping", "exit") |
20 | 33 | factory = MethodCallServerFactory | ||
21 | 38 | 34 | ||
22 | 39 | def __init__(self, component, reactor, config): | 35 | def __init__(self, component, reactor, config): |
23 | 40 | self._reactor = reactor | 36 | self._reactor = reactor |
24 | @@ -53,7 +49,7 @@ | |||
25 | 53 | return self._port.stopListening() | 49 | return self._port.stopListening() |
26 | 54 | 50 | ||
27 | 55 | 51 | ||
29 | 56 | class RemoteComponentConnector(object): | 52 | class ComponentConnector(object): |
30 | 57 | """Utility superclass for creating connections with a Landscape component. | 53 | """Utility superclass for creating connections with a Landscape component. |
31 | 58 | 54 | ||
32 | 59 | @cvar component: The class of the component to connect to, it is expected | 55 | @cvar component: The class of the component to connect to, it is expected |
33 | @@ -71,8 +67,8 @@ | |||
34 | 71 | 67 | ||
35 | 72 | @see: L{MethodCallClientFactory}. | 68 | @see: L{MethodCallClientFactory}. |
36 | 73 | """ | 69 | """ |
37 | 70 | factory = MethodCallClientFactory | ||
38 | 74 | component = None # Must be defined by sub-classes | 71 | component = None # Must be defined by sub-classes |
39 | 75 | factory = ComponentProtocolClientFactory | ||
40 | 76 | remote = RemoteObject | 72 | remote = RemoteObject |
41 | 77 | 73 | ||
42 | 78 | def __init__(self, reactor, config, retry_on_reconnect=False): | 74 | def __init__(self, reactor, config, retry_on_reconnect=False): |
43 | @@ -95,8 +91,8 @@ | |||
44 | 95 | result in a faster reconnection attempts pace. | 91 | result in a faster reconnection attempts pace. |
45 | 96 | @param quiet: A boolean indicating whether to log errors. | 92 | @param quiet: A boolean indicating whether to log errors. |
46 | 97 | """ | 93 | """ |
49 | 98 | reactor = self._reactor._reactor | 94 | factory = self.factory(self._reactor._reactor) |
50 | 99 | factory = self.factory(reactor) | 95 | factory.initialDelay = factory.delay = 0.05 |
51 | 100 | factory.retryOnReconnect = self._retry_on_reconnect | 96 | factory.retryOnReconnect = self._retry_on_reconnect |
52 | 101 | factory.remote = self.remote | 97 | factory.remote = self.remote |
53 | 102 | 98 | ||
54 | @@ -115,8 +111,8 @@ | |||
55 | 115 | if factor: | 111 | if factor: |
56 | 116 | factory.factor = factor | 112 | factory.factor = factor |
57 | 117 | socket_path = _get_socket_path(self.component, self._config) | 113 | socket_path = _get_socket_path(self.component, self._config) |
58 | 118 | self._connector = reactor.connectUNIX(socket_path, factory) | ||
59 | 119 | deferred = factory.getRemoteObject() | 114 | deferred = factory.getRemoteObject() |
60 | 115 | self._connector = self._reactor.connect_unix(socket_path, factory) | ||
61 | 120 | 116 | ||
62 | 121 | if not quiet: | 117 | if not quiet: |
63 | 122 | deferred.addErrback(log_error) | 118 | deferred.addErrback(log_error) |
64 | @@ -155,7 +151,7 @@ | |||
65 | 155 | def register(cls, connector_class): | 151 | def register(cls, connector_class): |
66 | 156 | """Register a connector for a Landscape component. | 152 | """Register a connector for a Landscape component. |
67 | 157 | 153 | ||
69 | 158 | @param connector_class: A sub-class of L{RemoteComponentConnector} | 154 | @param connector_class: A sub-class of L{ComponentConnector} |
70 | 159 | that can be used to connect to a certain component. | 155 | that can be used to connect to a certain component. |
71 | 160 | """ | 156 | """ |
72 | 161 | cls._by_name[connector_class.component.name] = connector_class | 157 | cls._by_name[connector_class.component.name] = connector_class |
73 | 162 | 158 | ||
74 | === modified file 'landscape/broker/amp.py' | |||
75 | --- landscape/broker/amp.py 2013-04-29 11:44:32 +0000 | |||
76 | +++ landscape/broker/amp.py 2013-05-02 08:30:35 +0000 | |||
77 | @@ -2,7 +2,7 @@ | |||
78 | 2 | 2 | ||
79 | 3 | from landscape.lib.amp import RemoteObject, MethodCallArgument | 3 | from landscape.lib.amp import RemoteObject, MethodCallArgument |
80 | 4 | from landscape.amp import ( | 4 | from landscape.amp import ( |
82 | 5 | RemoteComponentConnector, RemoteComponentsRegistry, ComponentPublisher) | 5 | ComponentConnector, RemoteComponentsRegistry, ComponentPublisher) |
83 | 6 | from landscape.broker.server import BrokerServer | 6 | from landscape.broker.server import BrokerServer |
84 | 7 | from landscape.broker.client import BrokerClient | 7 | from landscape.broker.client import BrokerClient |
85 | 8 | from landscape.monitor.monitor import Monitor | 8 | from landscape.monitor.monitor import Monitor |
86 | @@ -95,14 +95,14 @@ | |||
87 | 95 | "message") | 95 | "message") |
88 | 96 | 96 | ||
89 | 97 | 97 | ||
91 | 98 | class RemoteBrokerConnector(RemoteComponentConnector): | 98 | class RemoteBrokerConnector(ComponentConnector): |
92 | 99 | """Helper to create connections with the L{BrokerServer}.""" | 99 | """Helper to create connections with the L{BrokerServer}.""" |
93 | 100 | 100 | ||
94 | 101 | remote = RemoteBroker | 101 | remote = RemoteBroker |
95 | 102 | component = BrokerServer | 102 | component = BrokerServer |
96 | 103 | 103 | ||
97 | 104 | 104 | ||
99 | 105 | class RemoteClientConnector(RemoteComponentConnector): | 105 | class RemoteClientConnector(ComponentConnector): |
100 | 106 | """Helper to create connections with the L{BrokerServer}.""" | 106 | """Helper to create connections with the L{BrokerServer}.""" |
101 | 107 | 107 | ||
102 | 108 | component = BrokerClient | 108 | component = BrokerClient |
103 | 109 | 109 | ||
104 | === modified file 'landscape/broker/tests/test_amp.py' | |||
105 | --- landscape/broker/tests/test_amp.py 2013-04-15 09:03:43 +0000 | |||
106 | +++ landscape/broker/tests/test_amp.py 2013-05-02 08:30:35 +0000 | |||
107 | @@ -168,9 +168,11 @@ | |||
108 | 168 | L{RemoteBroker.listen_events} returns a deferred which fires when | 168 | L{RemoteBroker.listen_events} returns a deferred which fires when |
109 | 169 | the first of the given events occurs in the broker reactor. | 169 | the first of the given events occurs in the broker reactor. |
110 | 170 | """ | 170 | """ |
114 | 171 | result = self.remote.listen_events(["event1", "event2"]) | 171 | deferred = self.remote.listen_events(["event1", "event2"]) |
115 | 172 | self.reactor._reactor.callLater(0.05, self.reactor.fire, "event2") | 172 | self.reactor.call_later(0.05, self.reactor.fire, "event2") |
116 | 173 | return self.assertSuccess(result, "event2") | 173 | self.reactor.advance(0.05) |
117 | 174 | self.remote._factory.fake_connection.flush() | ||
118 | 175 | self.assertEqual("event2", self.successResultOf(deferred)) | ||
119 | 174 | 176 | ||
120 | 175 | def test_call_on_events(self): | 177 | def test_call_on_events(self): |
121 | 176 | """ | 178 | """ |
122 | @@ -182,10 +184,12 @@ | |||
123 | 182 | callback2 = self.mocker.mock() | 184 | callback2 = self.mocker.mock() |
124 | 183 | self.expect(callback2()).result(123) | 185 | self.expect(callback2()).result(123) |
125 | 184 | self.mocker.replay() | 186 | self.mocker.replay() |
130 | 185 | result = self.remote.call_on_event({"event1": callback1, | 187 | deferred = self.remote.call_on_event({"event1": callback1, |
131 | 186 | "event2": callback2}) | 188 | "event2": callback2}) |
132 | 187 | self.reactor._reactor.callLater(0.05, self.reactor.fire, "event2") | 189 | self.reactor.call_later(0.05, self.reactor.fire, "event2") |
133 | 188 | return self.assertSuccess(result, 123) | 190 | self.reactor.advance(0.05) |
134 | 191 | self.remote._factory.fake_connection.flush() | ||
135 | 192 | self.assertEqual(123, self.successResultOf(deferred)) | ||
136 | 189 | 193 | ||
137 | 190 | def test_fire_event(self): | 194 | def test_fire_event(self): |
138 | 191 | """ | 195 | """ |
139 | @@ -202,9 +206,8 @@ | |||
140 | 202 | """ | 206 | """ |
141 | 203 | Trying to call an non-exposed broker method results in a failure. | 207 | Trying to call an non-exposed broker method results in a failure. |
142 | 204 | """ | 208 | """ |
146 | 205 | result = self.remote._sender.send_method_call( | 209 | deferred = self.remote.get_clients() |
147 | 206 | method="get_clients", args=[], kwargs={}) | 210 | self.failureResultOf(deferred).trap(MethodCallError) |
145 | 207 | return self.assertFailure(result, MethodCallError) | ||
148 | 208 | 211 | ||
149 | 209 | 212 | ||
150 | 210 | class RemoteClientTest(LandscapeTest): | 213 | class RemoteClientTest(LandscapeTest): |
151 | @@ -263,6 +266,5 @@ | |||
152 | 263 | """ | 266 | """ |
153 | 264 | Trying to call an non-exposed client method results in a failure. | 267 | Trying to call an non-exposed client method results in a failure. |
154 | 265 | """ | 268 | """ |
158 | 266 | result = self.remote_client._sender.send_method_call( | 269 | deferred = self.remote_client.get_plugins() |
159 | 267 | method="get_plugins", args=[], kwargs={}) | 270 | self.failureResultOf(deferred).trap(MethodCallError) |
157 | 268 | return self.assertFailure(result, MethodCallError) | ||
160 | 269 | 271 | ||
161 | === modified file 'landscape/broker/tests/test_service.py' | |||
162 | --- landscape/broker/tests/test_service.py 2013-04-29 11:37:27 +0000 | |||
163 | +++ landscape/broker/tests/test_service.py 2013-05-02 08:30:35 +0000 | |||
164 | @@ -14,7 +14,11 @@ | |||
165 | 14 | 14 | ||
166 | 15 | def setUp(self): | 15 | def setUp(self): |
167 | 16 | super(BrokerServiceTest, self).setUp() | 16 | super(BrokerServiceTest, self).setUp() |
169 | 17 | self.service = BrokerService(self.config) | 17 | |
170 | 18 | class FakeBrokerService(BrokerService): | ||
171 | 19 | reactor_factory = FakeReactor | ||
172 | 20 | |||
173 | 21 | self.service = FakeBrokerService(self.config) | ||
174 | 18 | 22 | ||
175 | 19 | def test_persist(self): | 23 | def test_persist(self): |
176 | 20 | """ | 24 | """ |
177 | 21 | 25 | ||
178 | === modified file 'landscape/configuration.py' | |||
179 | --- landscape/configuration.py 2013-03-27 22:58:20 +0000 | |||
180 | +++ landscape/configuration.py 2013-05-02 08:30:35 +0000 | |||
181 | @@ -618,7 +618,8 @@ | |||
182 | 618 | 618 | ||
183 | 619 | 0.05 * (1 - 1.62 ** 14) / (1 - 1.62) = 69 seconds | 619 | 0.05 * (1 - 1.62 ** 14) / (1 - 1.62) = 69 seconds |
184 | 620 | """ | 620 | """ |
186 | 621 | reactor = TwistedReactor() | 621 | if reactor is None: |
187 | 622 | reactor = TwistedReactor() | ||
188 | 622 | exit_with_error = [] | 623 | exit_with_error = [] |
189 | 623 | 624 | ||
190 | 624 | def stop(error=None): | 625 | def stop(error=None): |
191 | 625 | 626 | ||
192 | === modified file 'landscape/lib/amp.py' | |||
193 | --- landscape/lib/amp.py 2013-04-30 16:21:01 +0000 | |||
194 | +++ landscape/lib/amp.py 2013-05-02 08:30:35 +0000 | |||
195 | @@ -349,6 +349,14 @@ | |||
196 | 349 | result.addCallback(self._handle_result, deferred) | 349 | result.addCallback(self._handle_result, deferred) |
197 | 350 | result.addErrback(self._handle_failure, method, args, kwargs, | 350 | result.addErrback(self._handle_failure, method, args, kwargs, |
198 | 351 | deferred) | 351 | deferred) |
199 | 352 | |||
200 | 353 | if self._factory.fake_connection is not None: | ||
201 | 354 | # Transparently flush the connection after a send_method_call | ||
202 | 355 | # invokation letting tests simulate a synchronous transport. | ||
203 | 356 | # This is needed because the Twisted's AMP implementation | ||
204 | 357 | # assume that the transport is asynchronous. | ||
205 | 358 | self._factory.fake_connection.flush() | ||
206 | 359 | |||
207 | 352 | return deferred | 360 | return deferred |
208 | 353 | 361 | ||
209 | 354 | return send_method_call | 362 | return send_method_call |
210 | @@ -487,6 +495,12 @@ | |||
211 | 487 | retryOnReconnect = False | 495 | retryOnReconnect = False |
212 | 488 | retryTimeout = None | 496 | retryTimeout = None |
213 | 489 | 497 | ||
214 | 498 | # XXX support exposing fake asynchronous connections created by tests, so | ||
215 | 499 | # they can be flushed transparently and emulate a synchronous behavior. See | ||
216 | 500 | # also http://twistedmatrix.com/trac/ticket/6502, once that's fixed this | ||
217 | 501 | # hack can be removed. | ||
218 | 502 | fake_connection = None | ||
219 | 503 | |||
220 | 490 | def __init__(self, reactor=None): | 504 | def __init__(self, reactor=None): |
221 | 491 | """ | 505 | """ |
222 | 492 | @param object: The object exposed by the L{MethodCallProtocol}s | 506 | @param object: The object exposed by the L{MethodCallProtocol}s |
223 | 493 | 507 | ||
224 | === modified file 'landscape/lib/tests/test_amp.py' | |||
225 | --- landscape/lib/tests/test_amp.py 2013-04-30 16:21:01 +0000 | |||
226 | +++ landscape/lib/tests/test_amp.py 2013-05-02 08:30:35 +0000 | |||
227 | @@ -1,28 +1,28 @@ | |||
228 | 1 | from twisted.internet import reactor | 1 | from twisted.internet import reactor |
229 | 2 | from twisted.internet.error import ConnectError, ConnectionDone | ||
230 | 3 | from twisted.internet.task import Clock | ||
231 | 2 | from twisted.internet.defer import Deferred, DeferredList | 4 | from twisted.internet.defer import Deferred, DeferredList |
232 | 3 | from twisted.internet.error import ConnectionDone, ConnectError | ||
233 | 4 | from twisted.internet.task import Clock | ||
234 | 5 | from twisted.protocols.amp import AMP | ||
235 | 6 | from twisted.python.failure import Failure | 5 | from twisted.python.failure import Failure |
236 | 7 | 6 | ||
237 | 8 | from landscape.lib.amp import ( | 7 | from landscape.lib.amp import ( |
238 | 9 | MethodCallError, MethodCallServerProtocol, MethodCallClientProtocol, | 8 | MethodCallError, MethodCallServerProtocol, MethodCallClientProtocol, |
239 | 10 | MethodCallServerFactory, MethodCallClientFactory, RemoteObject, | 9 | MethodCallServerFactory, MethodCallClientFactory, RemoteObject, |
241 | 11 | RemoteObjectConnector, MethodCallReceiver, MethodCallSender) | 10 | RemoteObjectConnector, MethodCallSender) |
242 | 12 | from landscape.tests.helpers import LandscapeTest | 11 | from landscape.tests.helpers import LandscapeTest |
243 | 13 | 12 | ||
244 | 14 | 13 | ||
245 | 15 | class FakeTransport(object): | 14 | class FakeTransport(object): |
246 | 16 | """Accumulate written data into a list.""" | 15 | """Accumulate written data into a list.""" |
247 | 17 | 16 | ||
249 | 18 | def __init__(self): | 17 | def __init__(self, connection): |
250 | 19 | self.stream = [] | 18 | self.stream = [] |
251 | 19 | self.connection = connection | ||
252 | 20 | 20 | ||
253 | 21 | def write(self, data): | 21 | def write(self, data): |
254 | 22 | self.stream.append(data) | 22 | self.stream.append(data) |
255 | 23 | 23 | ||
256 | 24 | def loseConnection(self): | 24 | def loseConnection(self): |
258 | 25 | raise NotImplemented() | 25 | self.connection.disconnect() |
259 | 26 | 26 | ||
260 | 27 | def getPeer(self): | 27 | def getPeer(self): |
261 | 28 | pass | 28 | pass |
262 | @@ -37,8 +37,16 @@ | |||
263 | 37 | def __init__(self, client, server): | 37 | def __init__(self, client, server): |
264 | 38 | self.client = client | 38 | self.client = client |
265 | 39 | self.server = server | 39 | self.server = server |
268 | 40 | self.server.makeConnection(FakeTransport()) | 40 | self.connect() |
269 | 41 | self.client.makeConnection(FakeTransport()) | 41 | |
270 | 42 | def connect(self): | ||
271 | 43 | self.server.makeConnection(FakeTransport(self)) | ||
272 | 44 | self.client.makeConnection(FakeTransport(self)) | ||
273 | 45 | |||
274 | 46 | def disconnect(self): | ||
275 | 47 | reason = Failure(ConnectionDone()) | ||
276 | 48 | connector = self | ||
277 | 49 | self.client.factory.clientConnectionLost(connector, reason) | ||
278 | 42 | 50 | ||
279 | 43 | def flush(self): | 51 | def flush(self): |
280 | 44 | """ | 52 | """ |
281 | @@ -338,17 +346,7 @@ | |||
282 | 338 | client.factory = WordsFactory(self.clock) | 346 | client.factory = WordsFactory(self.clock) |
283 | 339 | self.remote = RemoteObject(client.factory) | 347 | self.remote = RemoteObject(client.factory) |
284 | 340 | self.connection = FakeConnection(client, server) | 348 | self.connection = FakeConnection(client, server) |
296 | 341 | 349 | client.factory.fake_connection = self.connection | |
286 | 342 | send_method_call = self.remote._sender.send_method_call | ||
287 | 343 | |||
288 | 344 | def synchronous_send_method_call(method, args=[], kwargs={}): | ||
289 | 345 | # Transparently flush the connection after a send_method_call | ||
290 | 346 | # invocation | ||
291 | 347 | deferred = send_method_call(method, args=args, kwargs=kwargs) | ||
292 | 348 | self.connection.flush() | ||
293 | 349 | return deferred | ||
294 | 350 | |||
295 | 351 | self.remote._sender.send_method_call = synchronous_send_method_call | ||
297 | 352 | 350 | ||
298 | 353 | def test_method_call_sender_with_forbidden_method(self): | 351 | def test_method_call_sender_with_forbidden_method(self): |
299 | 354 | """ | 352 | """ |
300 | 355 | 353 | ||
301 | === modified file 'landscape/manager/tests/test_usermanager.py' | |||
302 | --- landscape/manager/tests/test_usermanager.py 2013-03-20 08:58:22 +0000 | |||
303 | +++ landscape/manager/tests/test_usermanager.py 2013-05-02 08:30:35 +0000 | |||
304 | @@ -422,7 +422,7 @@ | |||
305 | 422 | def handle_callback(ignored): | 422 | def handle_callback(ignored): |
306 | 423 | messages = self.broker_service.message_store.get_pending_messages() | 423 | messages = self.broker_service.message_store.get_pending_messages() |
307 | 424 | # Ignore the message created by plugin.run. | 424 | # Ignore the message created by plugin.run. |
309 | 425 | messages = sorted(messages[1:3], | 425 | messages = sorted([messages[1], messages[3]], |
310 | 426 | key=lambda message: message["operation-id"]) | 426 | key=lambda message: message["operation-id"]) |
311 | 427 | self.assertMessages(messages, | 427 | self.assertMessages(messages, |
312 | 428 | [{"type": "operation-result", | 428 | [{"type": "operation-result", |
313 | 429 | 429 | ||
314 | === modified file 'landscape/manager/usermanager.py' | |||
315 | --- landscape/manager/usermanager.py 2013-04-22 09:32:25 +0000 | |||
316 | +++ landscape/manager/usermanager.py 2013-05-02 08:30:35 +0000 | |||
317 | @@ -1,9 +1,7 @@ | |||
318 | 1 | import os | ||
319 | 2 | import logging | 1 | import logging |
320 | 3 | 2 | ||
321 | 4 | from landscape.lib.amp import RemoteObject | ||
322 | 5 | from landscape.lib.encoding import encode_dict_if_needed | 3 | from landscape.lib.encoding import encode_dict_if_needed |
324 | 6 | from landscape.amp import ComponentPublisher, RemoteComponentConnector | 4 | from landscape.amp import ComponentPublisher, ComponentConnector |
325 | 7 | 5 | ||
326 | 8 | from landscape.user.management import UserManagement | 6 | from landscape.user.management import UserManagement |
327 | 9 | from landscape.manager.plugin import ManagerPlugin | 7 | from landscape.manager.plugin import ManagerPlugin |
328 | @@ -158,6 +156,6 @@ | |||
329 | 158 | methods = ["get_locked_usernames"] | 156 | methods = ["get_locked_usernames"] |
330 | 159 | 157 | ||
331 | 160 | 158 | ||
333 | 161 | class RemoteUserManagerConnector(RemoteComponentConnector): | 159 | class RemoteUserManagerConnector(ComponentConnector): |
334 | 162 | 160 | ||
335 | 163 | component = UserManager | 161 | component = UserManager |
336 | 164 | 162 | ||
337 | === modified file 'landscape/monitor/tests/test_service.py' | |||
338 | --- landscape/monitor/tests/test_service.py 2013-04-29 11:37:27 +0000 | |||
339 | +++ landscape/monitor/tests/test_service.py 2013-05-02 08:30:35 +0000 | |||
340 | @@ -1,4 +1,3 @@ | |||
341 | 1 | from landscape.tests.mocker import ANY | ||
342 | 2 | from landscape.tests.helpers import LandscapeTest, FakeBrokerServiceHelper | 1 | from landscape.tests.helpers import LandscapeTest, FakeBrokerServiceHelper |
343 | 3 | from landscape.reactor import FakeReactor | 2 | from landscape.reactor import FakeReactor |
344 | 4 | from landscape.monitor.config import MonitorConfiguration, ALL_PLUGINS | 3 | from landscape.monitor.config import MonitorConfiguration, ALL_PLUGINS |
345 | @@ -46,13 +45,6 @@ | |||
346 | 46 | starts the plugins and register the monitor as broker client. It also | 45 | starts the plugins and register the monitor as broker client. It also |
347 | 47 | start listening on its own socket for incoming connections. | 46 | start listening on its own socket for incoming connections. |
348 | 48 | """ | 47 | """ |
349 | 49 | # FIXME: don't actually run the real register method, because at the | ||
350 | 50 | # moment the UserMonitor plugin still depends on DBus. We can probably | ||
351 | 51 | # drop this mocking once the AMP migration is completed. | ||
352 | 52 | for plugin in self.service.plugins: | ||
353 | 53 | plugin.register = self.mocker.mock() | ||
354 | 54 | plugin.register(ANY) | ||
355 | 55 | self.mocker.replay() | ||
356 | 56 | 48 | ||
357 | 57 | def stop_service(ignored): | 49 | def stop_service(ignored): |
358 | 58 | [connector] = self.broker_service.broker.get_connectors() | 50 | [connector] = self.broker_service.broker.get_connectors() |
359 | 59 | 51 | ||
360 | === modified file 'landscape/monitor/usermonitor.py' | |||
361 | --- landscape/monitor/usermonitor.py 2013-04-22 09:32:25 +0000 | |||
362 | +++ landscape/monitor/usermonitor.py 2013-05-02 08:30:35 +0000 | |||
363 | @@ -1,7 +1,7 @@ | |||
364 | 1 | from twisted.internet.defer import maybeDeferred | 1 | from twisted.internet.defer import maybeDeferred |
365 | 2 | 2 | ||
366 | 3 | from landscape.lib.log import log_failure | 3 | from landscape.lib.log import log_failure |
368 | 4 | from landscape.amp import ComponentPublisher, RemoteComponentConnector | 4 | from landscape.amp import ComponentPublisher, ComponentConnector |
369 | 5 | 5 | ||
370 | 6 | from landscape.monitor.plugin import MonitorPlugin | 6 | from landscape.monitor.plugin import MonitorPlugin |
371 | 7 | from landscape.user.changes import UserChanges | 7 | from landscape.user.changes import UserChanges |
372 | @@ -111,6 +111,6 @@ | |||
373 | 111 | methods = ["detect_changes"] | 111 | methods = ["detect_changes"] |
374 | 112 | 112 | ||
375 | 113 | 113 | ||
377 | 114 | class RemoteUserMonitorConnector(RemoteComponentConnector): | 114 | class RemoteUserMonitorConnector(ComponentConnector): |
378 | 115 | 115 | ||
379 | 116 | component = UserMonitor | 116 | component = UserMonitor |
380 | 117 | 117 | ||
381 | === modified file 'landscape/package/taskhandler.py' | |||
382 | --- landscape/package/taskhandler.py 2013-02-28 10:09:09 +0000 | |||
383 | +++ landscape/package/taskhandler.py 2013-05-02 08:30:35 +0000 | |||
384 | @@ -276,10 +276,7 @@ | |||
385 | 276 | 276 | ||
386 | 277 | def finish(): | 277 | def finish(): |
387 | 278 | connector.disconnect() | 278 | connector.disconnect() |
392 | 279 | # For some obscure reason our TwistedReactor.stop method calls | 279 | reactor.call_later(0, reactor.stop) |
389 | 280 | # reactor.crash() instead of reactor.stop(), which doesn't work | ||
390 | 281 | # here. Maybe TwistedReactor.stop should simply use reactor.stop(). | ||
391 | 282 | reactor.call_later(0, reactor._reactor.stop) | ||
393 | 283 | 280 | ||
394 | 284 | def got_error(failure): | 281 | def got_error(failure): |
395 | 285 | log_failure(failure) | 282 | log_failure(failure) |
396 | 286 | 283 | ||
397 | === modified file 'landscape/package/tests/test_changer.py' | |||
398 | --- landscape/package/tests/test_changer.py 2013-03-18 03:34:11 +0000 | |||
399 | +++ landscape/package/tests/test_changer.py 2013-05-02 08:30:35 +0000 | |||
400 | @@ -1479,7 +1479,7 @@ | |||
401 | 1479 | self.broker_service.reactor.advance(100) | 1479 | self.broker_service.reactor.advance(100) |
402 | 1480 | self.twisted_reactor.advance(10) | 1480 | self.twisted_reactor.advance(10) |
403 | 1481 | payloads = self.broker_service.exchanger._transport.payloads | 1481 | payloads = self.broker_service.exchanger._transport.payloads |
405 | 1482 | self.assertEqual(1, len(payloads)) | 1482 | self.assertEqual(0, len(payloads)) |
406 | 1483 | 1483 | ||
407 | 1484 | [arguments] = self.process_factory.spawns | 1484 | [arguments] = self.process_factory.spawns |
408 | 1485 | protocol = arguments[0] | 1485 | protocol = arguments[0] |
409 | 1486 | 1486 | ||
410 | === modified file 'landscape/package/tests/test_taskhandler.py' | |||
411 | --- landscape/package/tests/test_taskhandler.py 2012-05-10 00:34:13 +0000 | |||
412 | +++ landscape/package/tests/test_taskhandler.py 2013-05-02 08:30:35 +0000 | |||
413 | @@ -1,10 +1,9 @@ | |||
414 | 1 | import os | 1 | import os |
415 | 2 | 2 | ||
416 | 3 | from twisted.internet import reactor | ||
417 | 4 | from twisted.internet.defer import Deferred, fail | 3 | from twisted.internet.defer import Deferred, fail |
418 | 5 | 4 | ||
419 | 6 | from landscape.lib.lock import lock_path | 5 | from landscape.lib.lock import lock_path |
421 | 7 | from landscape.reactor import TwistedReactor | 6 | from landscape.reactor import TwistedReactor, FakeReactor |
422 | 8 | from landscape.broker.amp import RemoteBrokerConnector | 7 | from landscape.broker.amp import RemoteBrokerConnector |
423 | 9 | from landscape.package.taskhandler import ( | 8 | from landscape.package.taskhandler import ( |
424 | 10 | PackageTaskHandlerConfiguration, PackageTaskHandler, run_task_handler, | 9 | PackageTaskHandlerConfiguration, PackageTaskHandler, run_task_handler, |
425 | @@ -366,7 +365,8 @@ | |||
426 | 366 | reactor_mock.run() | 365 | reactor_mock.run() |
427 | 367 | self.mocker.call(lambda: call_when_running[0]()) | 366 | self.mocker.call(lambda: call_when_running[0]()) |
428 | 368 | connector_mock.disconnect() | 367 | connector_mock.disconnect() |
430 | 369 | reactor_mock.call_later(0, reactor.stop) | 368 | reactor_mock.call_later(0, ANY) |
431 | 369 | self.mocker.result(None) | ||
432 | 370 | 370 | ||
433 | 371 | # Okay, the whole playground is set. | 371 | # Okay, the whole playground is set. |
434 | 372 | self.mocker.replay() | 372 | self.mocker.replay() |
435 | @@ -433,12 +433,10 @@ | |||
436 | 433 | 433 | ||
437 | 434 | def test_errors_in_tasks_are_printed_and_exit_program(self): | 434 | def test_errors_in_tasks_are_printed_and_exit_program(self): |
438 | 435 | # Ignore a bunch of crap that we don't care about | 435 | # Ignore a bunch of crap that we don't care about |
439 | 436 | reactor_mock = self.mocker.patch(TwistedReactor) | ||
440 | 437 | init_logging_mock = self.mocker.replace("landscape.deployment" | 436 | init_logging_mock = self.mocker.replace("landscape.deployment" |
441 | 438 | ".init_logging", | 437 | ".init_logging", |
442 | 439 | passthrough=False) | 438 | passthrough=False) |
443 | 440 | init_logging_mock(ARGS) | 439 | init_logging_mock(ARGS) |
444 | 441 | reactor_mock.run() | ||
445 | 442 | 440 | ||
446 | 443 | class MyException(Exception): | 441 | class MyException(Exception): |
447 | 444 | pass | 442 | pass |
448 | @@ -450,8 +448,6 @@ | |||
449 | 450 | handler_mock = handler_factory_mock(ARGS) | 448 | handler_mock = handler_factory_mock(ARGS) |
450 | 451 | self.expect(handler_mock.run()).result(fail(MyException("Hey error"))) | 449 | self.expect(handler_mock.run()).result(fail(MyException("Hey error"))) |
451 | 452 | 450 | ||
452 | 453 | reactor_mock.call_later(0, reactor.stop) | ||
453 | 454 | |||
454 | 455 | self.mocker.replay() | 451 | self.mocker.replay() |
455 | 456 | 452 | ||
456 | 457 | # Ok now for some real stuff | 453 | # Ok now for some real stuff |
457 | @@ -460,7 +456,8 @@ | |||
458 | 460 | self.assertIn("MyException", self.logfile.getvalue()) | 456 | self.assertIn("MyException", self.logfile.getvalue()) |
459 | 461 | 457 | ||
460 | 462 | result = run_task_handler(handler_factory_mock, | 458 | result = run_task_handler(handler_factory_mock, |
462 | 463 | ["-c", self.config_filename]) | 459 | ["-c", self.config_filename], |
463 | 460 | reactor=FakeReactor()) | ||
464 | 464 | return result.addCallback(assert_log) | 461 | return result.addCallback(assert_log) |
465 | 465 | 462 | ||
466 | 466 | 463 | ||
467 | @@ -473,7 +470,7 @@ | |||
468 | 473 | The L{LazyRemoteBroker} class doesn't initialize the actual remote | 470 | The L{LazyRemoteBroker} class doesn't initialize the actual remote |
469 | 474 | broker until one of its attributes gets actually accessed. | 471 | broker until one of its attributes gets actually accessed. |
470 | 475 | """ | 472 | """ |
472 | 476 | reactor = TwistedReactor() | 473 | reactor = FakeReactor() |
473 | 477 | connector = RemoteBrokerConnector(reactor, self.broker_service.config) | 474 | connector = RemoteBrokerConnector(reactor, self.broker_service.config) |
474 | 478 | self.broker = LazyRemoteBroker(connector) | 475 | self.broker = LazyRemoteBroker(connector) |
475 | 479 | self.assertIs(self.broker._remote, None) | 476 | self.assertIs(self.broker._remote, None) |
476 | 480 | 477 | ||
477 | === modified file 'landscape/reactor.py' | |||
478 | --- landscape/reactor.py 2013-04-12 11:49:59 +0000 | |||
479 | +++ landscape/reactor.py 2013-05-02 08:30:35 +0000 | |||
480 | @@ -6,6 +6,8 @@ | |||
481 | 6 | import logging | 6 | import logging |
482 | 7 | import bisect | 7 | import bisect |
483 | 8 | 8 | ||
484 | 9 | from twisted.python.failure import Failure | ||
485 | 10 | from twisted.internet.error import ConnectError | ||
486 | 9 | from twisted.internet.threads import deferToThread | 11 | from twisted.internet.threads import deferToThread |
487 | 10 | 12 | ||
488 | 11 | from landscape.log import format_object | 13 | from landscape.log import format_object |
489 | @@ -110,33 +112,13 @@ | |||
490 | 110 | raise InvalidID("EventID instance expected, received %r" % id) | 112 | raise InvalidID("EventID instance expected, received %r" % id) |
491 | 111 | 113 | ||
492 | 112 | 114 | ||
493 | 113 | class UnixReactorMixin(object): | ||
494 | 114 | """Support listening on Unix domain sockets. | ||
495 | 115 | |||
496 | 116 | Note that this mixin uses the *real* Twisted reactor to open a *real* | ||
497 | 117 | socket. | ||
498 | 118 | |||
499 | 119 | Since it is used by *both* L{TwistedReactor} and L{FakeReactor}, this | ||
500 | 120 | means that the latter is not really fake in this sense and that unit | ||
501 | 121 | tests involving calls to this method won't be synchronous anymore. | ||
502 | 122 | |||
503 | 123 | For example, many tests under L{landscape.broker.tests} use C{listen_unix} | ||
504 | 124 | to setup a "real" remote broker and exercise the RPC/AMP functionality. See | ||
505 | 125 | in particular L{landscape.broker.tests.helpers.RemoteBrokerHelper}. | ||
506 | 126 | """ | ||
507 | 127 | |||
508 | 128 | def listen_unix(self, socket, factory): | ||
509 | 129 | """Start listening on a Unix socket.""" | ||
510 | 130 | return self._reactor.listenUNIX(socket, factory, wantPID=True) | ||
511 | 131 | |||
512 | 132 | |||
513 | 133 | class ReactorID(object): | 115 | class ReactorID(object): |
514 | 134 | 116 | ||
515 | 135 | def __init__(self, timeout): | 117 | def __init__(self, timeout): |
516 | 136 | self._timeout = timeout | 118 | self._timeout = timeout |
517 | 137 | 119 | ||
518 | 138 | 120 | ||
520 | 139 | class TwistedReactor(EventHandlingReactorMixin, UnixReactorMixin): | 121 | class TwistedReactor(EventHandlingReactorMixin): |
521 | 140 | """Wrap and add functionalities to the Twisted C{reactor}. | 122 | """Wrap and add functionalities to the Twisted C{reactor}. |
522 | 141 | 123 | ||
523 | 142 | This essentially a facade around the C{twisted.internet.reactor} and | 124 | This essentially a facade around the C{twisted.internet.reactor} and |
524 | @@ -239,6 +221,14 @@ | |||
525 | 239 | deferred.addCallback(on_success) | 221 | deferred.addCallback(on_success) |
526 | 240 | deferred.addErrback(on_failure) | 222 | deferred.addErrback(on_failure) |
527 | 241 | 223 | ||
528 | 224 | def listen_unix(self, socket, factory): | ||
529 | 225 | """Start listening on a Unix socket.""" | ||
530 | 226 | return self._reactor.listenUNIX(socket, factory, wantPID=True) | ||
531 | 227 | |||
532 | 228 | def connect_unix(self, socket, factory): | ||
533 | 229 | """Connect to a Unix socket.""" | ||
534 | 230 | return self._reactor.connectUNIX(socket, factory) | ||
535 | 231 | |||
536 | 242 | def run(self): | 232 | def run(self): |
537 | 243 | """Start the reactor, a C{"run"} event will be fired.""" | 233 | """Start the reactor, a C{"run"} event will be fired.""" |
538 | 244 | 234 | ||
539 | @@ -266,7 +256,7 @@ | |||
540 | 266 | self._data = data | 256 | self._data = data |
541 | 267 | 257 | ||
542 | 268 | 258 | ||
544 | 269 | class FakeReactor(EventHandlingReactorMixin, UnixReactorMixin): | 259 | class FakeReactor(EventHandlingReactorMixin): |
545 | 270 | """A fake reactor with the same API of L{TwistedReactor}. | 260 | """A fake reactor with the same API of L{TwistedReactor}. |
546 | 271 | 261 | ||
547 | 272 | This reactor emulates the asychronous interface of L{TwistedReactor}, but | 262 | This reactor emulates the asychronous interface of L{TwistedReactor}, but |
548 | @@ -279,6 +269,10 @@ | |||
549 | 279 | around Unix sockets), and implement a fake version C{listen_unix}, but this | 269 | around Unix sockets), and implement a fake version C{listen_unix}, but this |
550 | 280 | hasn't been done yet. | 270 | hasn't been done yet. |
551 | 281 | """ | 271 | """ |
552 | 272 | # XXX probably this shouldn't be a class attribute, but we need client-side | ||
553 | 273 | # FakeReactor instaces to be aware of listening sockets created by | ||
554 | 274 | # server-side FakeReactor instances. | ||
555 | 275 | _socket_paths = {} | ||
556 | 282 | 276 | ||
557 | 283 | def __init__(self): | 277 | def __init__(self): |
558 | 284 | super(FakeReactor, self).__init__() | 278 | super(FakeReactor, self).__init__() |
559 | @@ -287,8 +281,8 @@ | |||
560 | 287 | self.hosts = {} | 281 | self.hosts = {} |
561 | 288 | self._threaded_callbacks = [] | 282 | self._threaded_callbacks = [] |
562 | 289 | 283 | ||
565 | 290 | # We need a reference to the Twisted reactor as well to | 284 | # XXX we need a reference to the Twisted reactor as well because |
566 | 291 | # let Landscape services listen to Unix sockets | 285 | # some tests use it |
567 | 292 | from twisted.internet import reactor | 286 | from twisted.internet import reactor |
568 | 293 | self._reactor = reactor | 287 | self._reactor = reactor |
569 | 294 | 288 | ||
570 | @@ -326,7 +320,8 @@ | |||
571 | 326 | super(FakeReactor, self).cancel_call(id) | 320 | super(FakeReactor, self).cancel_call(id) |
572 | 327 | 321 | ||
573 | 328 | def call_when_running(self, f): | 322 | def call_when_running(self, f): |
575 | 329 | raise NotImplemented("The FakeReactor doesn't implement this.") | 323 | # Just schedule a call that will be kicked by the run() method. |
576 | 324 | self.call_later(0, f) | ||
577 | 330 | 325 | ||
578 | 331 | def call_in_main(self, f, *args, **kwargs): | 326 | def call_in_main(self, f, *args, **kwargs): |
579 | 332 | """Schedule a function for execution in the main thread.""" | 327 | """Schedule a function for execution in the main thread.""" |
580 | @@ -347,6 +342,28 @@ | |||
581 | 347 | self._in_thread(callback, errback, f, args, kwargs) | 342 | self._in_thread(callback, errback, f, args, kwargs) |
582 | 348 | self._run_threaded_callbacks() | 343 | self._run_threaded_callbacks() |
583 | 349 | 344 | ||
584 | 345 | def listen_unix(self, socket_path, factory): | ||
585 | 346 | |||
586 | 347 | class FakePort(object): | ||
587 | 348 | |||
588 | 349 | def stopListening(oself): | ||
589 | 350 | self._socket_paths.pop(socket_path) | ||
590 | 351 | |||
591 | 352 | self._socket_paths[socket_path] = factory | ||
592 | 353 | return FakePort() | ||
593 | 354 | |||
594 | 355 | def connect_unix(self, path, factory): | ||
595 | 356 | server = self._socket_paths.get(path) | ||
596 | 357 | from landscape.lib.tests.test_amp import FakeConnection | ||
597 | 358 | if server: | ||
598 | 359 | connection = FakeConnection(factory.buildProtocol(path), | ||
599 | 360 | server.buildProtocol(path)) | ||
600 | 361 | factory.fake_connection = connection | ||
601 | 362 | else: | ||
602 | 363 | connector = object() # Fake connector | ||
603 | 364 | failure = Failure(ConnectError("No such file or directory")) | ||
604 | 365 | factory.clientConnectionFailed(connector, failure) | ||
605 | 366 | |||
606 | 350 | def run(self): | 367 | def run(self): |
607 | 351 | """Continuously advance this reactor until reactor.stop() is called.""" | 368 | """Continuously advance this reactor until reactor.stop() is called.""" |
608 | 352 | self.fire("run") | 369 | self.fire("run") |
609 | 353 | 370 | ||
610 | === modified file 'landscape/service.py' | |||
611 | --- landscape/service.py 2013-04-29 11:44:32 +0000 | |||
612 | +++ landscape/service.py 2013-05-02 08:30:35 +0000 | |||
613 | @@ -1,4 +1,3 @@ | |||
614 | 1 | import os | ||
615 | 2 | import logging | 1 | import logging |
616 | 3 | import signal | 2 | import signal |
617 | 4 | 3 | ||
618 | @@ -42,15 +41,11 @@ | |||
619 | 42 | signal.signal( | 41 | signal.signal( |
620 | 43 | signal.SIGUSR1, | 42 | signal.SIGUSR1, |
621 | 44 | lambda signal, frame: reactor.callFromThread(rotate_logs)) | 43 | lambda signal, frame: reactor.callFromThread(rotate_logs)) |
622 | 45 | self.socket = os.path.join(self.config.sockets_path, | ||
623 | 46 | self.service_name + ".sock") | ||
624 | 47 | 44 | ||
625 | 48 | def startService(self): | 45 | def startService(self): |
626 | 49 | Service.startService(self) | 46 | Service.startService(self) |
627 | 50 | logging.info("%s started with config %s" % ( | 47 | logging.info("%s started with config %s" % ( |
628 | 51 | self.service_name.capitalize(), self.config.get_config_filename())) | 48 | self.service_name.capitalize(), self.config.get_config_filename())) |
629 | 52 | if hasattr(self, "factory"): | ||
630 | 53 | self.port = self.reactor.listen_unix(self.socket, self.factory) | ||
631 | 54 | 49 | ||
632 | 55 | def stopService(self): | 50 | def stopService(self): |
633 | 56 | # We don't need to call port.stopListening(), because the reactor | 51 | # We don't need to call port.stopListening(), because the reactor |
634 | 57 | 52 | ||
635 | === modified file 'landscape/tests/test_amp.py' | |||
636 | --- landscape/tests/test_amp.py 2013-04-22 09:32:25 +0000 | |||
637 | +++ landscape/tests/test_amp.py 2013-05-02 08:30:35 +0000 | |||
638 | @@ -4,9 +4,7 @@ | |||
639 | 4 | from landscape.tests.helpers import LandscapeTest | 4 | from landscape.tests.helpers import LandscapeTest |
640 | 5 | from landscape.reactor import FakeReactor | 5 | from landscape.reactor import FakeReactor |
641 | 6 | from landscape.deployment import Configuration | 6 | from landscape.deployment import Configuration |
645 | 7 | from landscape.amp import ( | 7 | from landscape.amp import ComponentPublisher, ComponentConnector |
643 | 8 | ComponentProtocolClientFactory, RemoteComponentConnector, | ||
644 | 9 | ComponentPublisher) | ||
646 | 10 | 8 | ||
647 | 11 | 9 | ||
648 | 12 | class TestComponent(object): | 10 | class TestComponent(object): |
649 | @@ -14,22 +12,21 @@ | |||
650 | 14 | name = "test" | 12 | name = "test" |
651 | 15 | 13 | ||
652 | 16 | 14 | ||
662 | 17 | class TestComponentProtocolFactory(ComponentProtocolClientFactory): | 15 | class TestComponentConnector(ComponentConnector): |
663 | 18 | 16 | ||
655 | 19 | maxRetries = 0 | ||
656 | 20 | initialDelay = 0.01 | ||
657 | 21 | |||
658 | 22 | |||
659 | 23 | class RemoteTestComponentConnector(RemoteComponentConnector): | ||
660 | 24 | |||
661 | 25 | factory = TestComponentProtocolFactory | ||
664 | 26 | component = TestComponent | 17 | component = TestComponent |
665 | 27 | 18 | ||
666 | 28 | 19 | ||
668 | 29 | class RemoteComponentTest(LandscapeTest): | 20 | class FakeAMP(object): |
669 | 21 | |||
670 | 22 | def __init__(self, locator): | ||
671 | 23 | self._locator = locator | ||
672 | 24 | |||
673 | 25 | |||
674 | 26 | class ComponentPublisherTest(LandscapeTest): | ||
675 | 30 | 27 | ||
676 | 31 | def setUp(self): | 28 | def setUp(self): |
678 | 32 | super(RemoteComponentTest, self).setUp() | 29 | super(ComponentPublisherTest, self).setUp() |
679 | 33 | reactor = FakeReactor() | 30 | reactor = FakeReactor() |
680 | 34 | config = Configuration() | 31 | config = Configuration() |
681 | 35 | config.data_path = self.makeDir() | 32 | config.data_path = self.makeDir() |
682 | @@ -38,7 +35,7 @@ | |||
683 | 38 | self.publisher = ComponentPublisher(self.component, reactor, config) | 35 | self.publisher = ComponentPublisher(self.component, reactor, config) |
684 | 39 | self.publisher.start() | 36 | self.publisher.start() |
685 | 40 | 37 | ||
687 | 41 | self.connector = RemoteTestComponentConnector(reactor, config) | 38 | self.connector = TestComponentConnector(reactor, config) |
688 | 42 | connected = self.connector.connect() | 39 | connected = self.connector.connect() |
689 | 43 | connected.addCallback(lambda remote: setattr(self, "remote", remote)) | 40 | connected.addCallback(lambda remote: setattr(self, "remote", remote)) |
690 | 44 | return connected | 41 | return connected |
691 | @@ -46,7 +43,7 @@ | |||
692 | 46 | def tearDown(self): | 43 | def tearDown(self): |
693 | 47 | self.connector.disconnect() | 44 | self.connector.disconnect() |
694 | 48 | self.publisher.stop() | 45 | self.publisher.stop() |
696 | 49 | super(RemoteComponentTest, self).tearDown() | 46 | super(ComponentPublisherTest, self).tearDown() |
697 | 50 | 47 | ||
698 | 51 | def test_ping(self): | 48 | def test_ping(self): |
699 | 52 | """ | 49 | """ |
700 | @@ -71,16 +68,15 @@ | |||
701 | 71 | return self.assertSuccess(result) | 68 | return self.assertSuccess(result) |
702 | 72 | 69 | ||
703 | 73 | 70 | ||
705 | 74 | class RemoteComponentConnectorTest(LandscapeTest): | 71 | class ComponentConnectorTest(LandscapeTest): |
706 | 75 | 72 | ||
707 | 76 | def setUp(self): | 73 | def setUp(self): |
709 | 77 | super(RemoteComponentConnectorTest, self).setUp() | 74 | super(ComponentConnectorTest, self).setUp() |
710 | 78 | self.reactor = FakeReactor() | 75 | self.reactor = FakeReactor() |
711 | 79 | self.config = Configuration() | 76 | self.config = Configuration() |
712 | 80 | self.config.data_path = self.makeDir() | 77 | self.config.data_path = self.makeDir() |
713 | 81 | self.makeDir(path=self.config.sockets_path) | 78 | self.makeDir(path=self.config.sockets_path) |
716 | 82 | self.connector = RemoteTestComponentConnector(self.reactor, | 79 | self.connector = TestComponentConnector(self.reactor, self.config) |
715 | 83 | self.config) | ||
717 | 84 | 80 | ||
718 | 85 | def test_connect_logs_errors(self): | 81 | def test_connect_logs_errors(self): |
719 | 86 | """ | 82 | """ |
720 | 87 | 83 | ||
721 | === modified file 'landscape/tests/test_configuration.py' | |||
722 | --- landscape/tests/test_configuration.py 2013-04-18 09:32:04 +0000 | |||
723 | +++ landscape/tests/test_configuration.py 2013-05-02 08:30:35 +0000 | |||
724 | @@ -5,9 +5,10 @@ | |||
725 | 5 | from cStringIO import StringIO | 5 | from cStringIO import StringIO |
726 | 6 | 6 | ||
727 | 7 | from twisted.internet.defer import succeed, fail | 7 | from twisted.internet.defer import succeed, fail |
728 | 8 | from twisted.internet.task import Clock | ||
729 | 8 | 9 | ||
730 | 9 | from landscape.lib.amp import MethodCallSender | 10 | from landscape.lib.amp import MethodCallSender |
732 | 10 | from landscape.reactor import TwistedReactor | 11 | from landscape.reactor import TwistedReactor, FakeReactor |
733 | 11 | from landscape.lib.fetch import HTTPCodeError, PyCurlError | 12 | from landscape.lib.fetch import HTTPCodeError, PyCurlError |
734 | 12 | from landscape.configuration import ( | 13 | from landscape.configuration import ( |
735 | 13 | print_text, LandscapeSetupScript, LandscapeSetupConfiguration, | 14 | print_text, LandscapeSetupScript, LandscapeSetupConfiguration, |
736 | @@ -1634,7 +1635,7 @@ | |||
737 | 1634 | registration_mock = self.mocker.replace(service.registration) | 1635 | registration_mock = self.mocker.replace(service.registration) |
738 | 1635 | config_mock = self.mocker.replace(service.config) | 1636 | config_mock = self.mocker.replace(service.config) |
739 | 1636 | print_text_mock = self.mocker.replace(print_text) | 1637 | print_text_mock = self.mocker.replace(print_text) |
741 | 1637 | reactor_mock = self.mocker.patch(TwistedReactor) | 1638 | reactor_mock = self.mocker.patch(FakeReactor) |
742 | 1638 | 1639 | ||
743 | 1639 | # This must necessarily happen in the following order. | 1640 | # This must necessarily happen in the following order. |
744 | 1640 | self.mocker.order() | 1641 | self.mocker.order() |
745 | @@ -1646,8 +1647,6 @@ | |||
746 | 1646 | time_mock.sleep(ANY) | 1647 | time_mock.sleep(ANY) |
747 | 1647 | self.mocker.count(1) | 1648 | self.mocker.count(1) |
748 | 1648 | 1649 | ||
749 | 1649 | reactor_mock.run() | ||
750 | 1650 | |||
751 | 1651 | # After a nice dance the configuration is reloaded. | 1650 | # After a nice dance the configuration is reloaded. |
752 | 1652 | config_mock.reload() | 1651 | config_mock.reload() |
753 | 1653 | 1652 | ||
754 | @@ -1665,6 +1664,10 @@ | |||
755 | 1665 | 1664 | ||
756 | 1666 | reactor_mock.stop() | 1665 | reactor_mock.stop() |
757 | 1667 | 1666 | ||
758 | 1667 | # This is actually called after everything else since all deferreds | ||
759 | 1668 | # are synchronous and callbacks will be executed immediately. | ||
760 | 1669 | reactor_mock.run() | ||
761 | 1670 | |||
762 | 1668 | # Nothing else is printed! | 1671 | # Nothing else is printed! |
763 | 1669 | print_text_mock(ANY) | 1672 | print_text_mock(ANY) |
764 | 1670 | self.mocker.count(0) | 1673 | self.mocker.count(0) |
765 | @@ -1672,7 +1675,8 @@ | |||
766 | 1672 | self.mocker.replay() | 1675 | self.mocker.replay() |
767 | 1673 | 1676 | ||
768 | 1674 | # DO IT! | 1677 | # DO IT! |
770 | 1675 | return register(self.config, print_text, sys.exit) | 1678 | return register(self.config, print_text, sys.exit, |
771 | 1679 | reactor=FakeReactor()) | ||
772 | 1676 | 1680 | ||
773 | 1677 | def test_register_failure(self): | 1681 | def test_register_failure(self): |
774 | 1678 | """ | 1682 | """ |
775 | @@ -1685,7 +1689,7 @@ | |||
776 | 1685 | registration_mock = self.mocker.replace(service.registration) | 1689 | registration_mock = self.mocker.replace(service.registration) |
777 | 1686 | config_mock = self.mocker.replace(service.config) | 1690 | config_mock = self.mocker.replace(service.config) |
778 | 1687 | print_text_mock = self.mocker.replace(print_text) | 1691 | print_text_mock = self.mocker.replace(print_text) |
780 | 1688 | reactor_mock = self.mocker.patch(TwistedReactor) | 1692 | reactor_mock = self.mocker.patch(FakeReactor) |
781 | 1689 | 1693 | ||
782 | 1690 | # This must necessarily happen in the following order. | 1694 | # This must necessarily happen in the following order. |
783 | 1691 | self.mocker.order() | 1695 | self.mocker.order() |
784 | @@ -1697,8 +1701,6 @@ | |||
785 | 1697 | time_mock.sleep(ANY) | 1701 | time_mock.sleep(ANY) |
786 | 1698 | self.mocker.count(1) | 1702 | self.mocker.count(1) |
787 | 1699 | 1703 | ||
788 | 1700 | reactor_mock.run() | ||
789 | 1701 | |||
790 | 1702 | # After a nice dance the configuration is reloaded. | 1704 | # After a nice dance the configuration is reloaded. |
791 | 1703 | config_mock.reload() | 1705 | config_mock.reload() |
792 | 1704 | 1706 | ||
793 | @@ -1717,6 +1719,10 @@ | |||
794 | 1717 | 1719 | ||
795 | 1718 | reactor_mock.stop() | 1720 | reactor_mock.stop() |
796 | 1719 | 1721 | ||
797 | 1722 | # This is actually called after everything else since all deferreds | ||
798 | 1723 | # are synchronous and callbacks will be executed immediately. | ||
799 | 1724 | reactor_mock.run() | ||
800 | 1725 | |||
801 | 1720 | # Nothing else is printed! | 1726 | # Nothing else is printed! |
802 | 1721 | print_text_mock(ANY) | 1727 | print_text_mock(ANY) |
803 | 1722 | self.mocker.count(0) | 1728 | self.mocker.count(0) |
804 | @@ -1724,7 +1730,9 @@ | |||
805 | 1724 | self.mocker.replay() | 1730 | self.mocker.replay() |
806 | 1725 | 1731 | ||
807 | 1726 | # DO IT! | 1732 | # DO IT! |
809 | 1727 | return register(self.config, print_text, sys.exit) | 1733 | exit = [] |
810 | 1734 | register(self.config, print_text, exit.append, reactor=FakeReactor()) | ||
811 | 1735 | self.assertEqual([2], exit) | ||
812 | 1728 | 1736 | ||
813 | 1729 | def test_register_exchange_failure(self): | 1737 | def test_register_exchange_failure(self): |
814 | 1730 | """ | 1738 | """ |
815 | @@ -1736,7 +1744,7 @@ | |||
816 | 1736 | registration_mock = self.mocker.replace(service.registration) | 1744 | registration_mock = self.mocker.replace(service.registration) |
817 | 1737 | config_mock = self.mocker.replace(service.config) | 1745 | config_mock = self.mocker.replace(service.config) |
818 | 1738 | print_text_mock = self.mocker.replace(print_text) | 1746 | print_text_mock = self.mocker.replace(print_text) |
820 | 1739 | reactor_mock = self.mocker.patch(TwistedReactor) | 1747 | reactor_mock = self.mocker.patch(FakeReactor) |
821 | 1740 | 1748 | ||
822 | 1741 | # This must necessarily happen in the following order. | 1749 | # This must necessarily happen in the following order. |
823 | 1742 | self.mocker.order() | 1750 | self.mocker.order() |
824 | @@ -1748,8 +1756,6 @@ | |||
825 | 1748 | time_mock.sleep(ANY) | 1756 | time_mock.sleep(ANY) |
826 | 1749 | self.mocker.count(1) | 1757 | self.mocker.count(1) |
827 | 1750 | 1758 | ||
828 | 1751 | reactor_mock.run() | ||
829 | 1752 | |||
830 | 1753 | # After a nice dance the configuration is reloaded. | 1759 | # After a nice dance the configuration is reloaded. |
831 | 1754 | config_mock.reload() | 1760 | config_mock.reload() |
832 | 1755 | 1761 | ||
833 | @@ -1767,6 +1773,10 @@ | |||
834 | 1767 | 1773 | ||
835 | 1768 | reactor_mock.stop() | 1774 | reactor_mock.stop() |
836 | 1769 | 1775 | ||
837 | 1776 | # This is actually called after everything else since all deferreds | ||
838 | 1777 | # are synchronous and callbacks will be executed immediately. | ||
839 | 1778 | reactor_mock.run() | ||
840 | 1779 | |||
841 | 1770 | # Nothing else is printed! | 1780 | # Nothing else is printed! |
842 | 1771 | print_text_mock(ANY) | 1781 | print_text_mock(ANY) |
843 | 1772 | self.mocker.count(0) | 1782 | self.mocker.count(0) |
844 | @@ -1774,7 +1784,9 @@ | |||
845 | 1774 | self.mocker.replay() | 1784 | self.mocker.replay() |
846 | 1775 | 1785 | ||
847 | 1776 | # DO IT! | 1786 | # DO IT! |
849 | 1777 | return register(self.config, print_text, sys.exit) | 1787 | exit = [] |
850 | 1788 | register(self.config, print_text, exit.append, reactor=FakeReactor()) | ||
851 | 1789 | self.assertEqual([2], exit) | ||
852 | 1778 | 1790 | ||
853 | 1779 | def test_register_timeout_failure(self): | 1791 | def test_register_timeout_failure(self): |
854 | 1780 | service = self.broker_service | 1792 | service = self.broker_service |
855 | @@ -1782,7 +1794,7 @@ | |||
856 | 1782 | registration_mock = self.mocker.replace(service.registration) | 1794 | registration_mock = self.mocker.replace(service.registration) |
857 | 1783 | config_mock = self.mocker.replace(service.config) | 1795 | config_mock = self.mocker.replace(service.config) |
858 | 1784 | print_text_mock = self.mocker.replace(print_text) | 1796 | print_text_mock = self.mocker.replace(print_text) |
860 | 1785 | reactor_mock = self.mocker.patch(TwistedReactor) | 1797 | reactor_mock = self.mocker.patch(FakeReactor) |
861 | 1786 | remote_mock = self.mocker.patch(RemoteBroker) | 1798 | remote_mock = self.mocker.patch(RemoteBroker) |
862 | 1787 | 1799 | ||
863 | 1788 | protocol_mock = self.mocker.patch(MethodCallSender) | 1800 | protocol_mock = self.mocker.patch(MethodCallSender) |
864 | @@ -1800,17 +1812,19 @@ | |||
865 | 1800 | time_mock.sleep(ANY) | 1812 | time_mock.sleep(ANY) |
866 | 1801 | self.mocker.count(1) | 1813 | self.mocker.count(1) |
867 | 1802 | 1814 | ||
869 | 1803 | reactor_mock.run() | 1815 | # After a nice dance the configuration is reloaded. |
870 | 1816 | config_mock.reload() | ||
871 | 1804 | 1817 | ||
872 | 1805 | remote_mock.call_on_event(ANY) | 1818 | remote_mock.call_on_event(ANY) |
873 | 1806 | self.mocker.result(succeed(None)) | 1819 | self.mocker.result(succeed(None)) |
874 | 1807 | 1820 | ||
875 | 1808 | # After a nice dance the configuration is reloaded. | ||
876 | 1809 | config_mock.reload() | ||
877 | 1810 | |||
878 | 1811 | registration_mock.register() | 1821 | registration_mock.register() |
879 | 1812 | self.mocker.passthrough() | 1822 | self.mocker.passthrough() |
880 | 1813 | 1823 | ||
881 | 1824 | # This is actually called after everything else since all deferreds | ||
882 | 1825 | # are synchronous and callbacks will be executed immediately. | ||
883 | 1826 | reactor_mock.run() | ||
884 | 1827 | |||
885 | 1814 | # Nothing else is printed! | 1828 | # Nothing else is printed! |
886 | 1815 | print_text_mock(ANY) | 1829 | print_text_mock(ANY) |
887 | 1816 | self.mocker.count(0) | 1830 | self.mocker.count(0) |
888 | @@ -1818,7 +1832,12 @@ | |||
889 | 1818 | self.mocker.replay() | 1832 | self.mocker.replay() |
890 | 1819 | 1833 | ||
891 | 1820 | # DO IT! | 1834 | # DO IT! |
893 | 1821 | return register(self.config, print_text, sys.exit) | 1835 | fake_reactor = FakeReactor() |
894 | 1836 | fake_reactor._reactor = Clock() | ||
895 | 1837 | deferred = register(self.config, print_text, sys.exit, | ||
896 | 1838 | reactor=fake_reactor) | ||
897 | 1839 | fake_reactor._reactor.advance(100) | ||
898 | 1840 | return deferred | ||
899 | 1822 | 1841 | ||
900 | 1823 | def test_register_bus_connection_failure(self): | 1842 | def test_register_bus_connection_failure(self): |
901 | 1824 | """ | 1843 | """ |
902 | @@ -1993,14 +2012,13 @@ | |||
903 | 1993 | remote_broker = self.mocker.mock() | 2012 | remote_broker = self.mocker.mock() |
904 | 1994 | 2013 | ||
905 | 1995 | print_text_mock = self.mocker.replace(print_text) | 2014 | print_text_mock = self.mocker.replace(print_text) |
907 | 1996 | reactor_mock = self.mocker.patch(TwistedReactor) | 2015 | reactor_mock = self.mocker.patch(FakeReactor) |
908 | 1997 | 2016 | ||
909 | 1998 | # This is unordered. It's just way too much of a pain. | 2017 | # This is unordered. It's just way too much of a pain. |
910 | 1999 | print_text_mock("Please wait... ", "") | 2018 | print_text_mock("Please wait... ", "") |
911 | 2000 | time_mock = self.mocker.replace("time") | 2019 | time_mock = self.mocker.replace("time") |
912 | 2001 | time_mock.sleep(ANY) | 2020 | time_mock.sleep(ANY) |
913 | 2002 | self.mocker.count(1) | 2021 | self.mocker.count(1) |
914 | 2003 | reactor_mock.run() | ||
915 | 2004 | 2022 | ||
916 | 2005 | # SNORE | 2023 | # SNORE |
917 | 2006 | connector = connector_factory(ANY, configuration) | 2024 | connector = connector_factory(ANY, configuration) |
918 | @@ -2025,10 +2043,12 @@ | |||
919 | 2025 | # WHOAH DUDE. This waits for callLater(0, reactor.stop). | 2043 | # WHOAH DUDE. This waits for callLater(0, reactor.stop). |
920 | 2026 | connector.disconnect() | 2044 | connector.disconnect() |
921 | 2027 | reactor_mock.stop() | 2045 | reactor_mock.stop() |
922 | 2046 | reactor_mock.run() | ||
923 | 2028 | 2047 | ||
924 | 2029 | self.mocker.replay() | 2048 | self.mocker.replay() |
925 | 2030 | 2049 | ||
927 | 2031 | return register(configuration, print_text, sys.exit, max_retries=0) | 2050 | return register(configuration, print_text, sys.exit, max_retries=0, |
928 | 2051 | reactor=FakeReactor()) | ||
929 | 2032 | 2052 | ||
930 | 2033 | 2053 | ||
931 | 2034 | class SSLCertificateDataTest(LandscapeConfigurationTest): | 2054 | class SSLCertificateDataTest(LandscapeConfigurationTest): |
932 | 2035 | 2055 | ||
933 | === modified file 'landscape/tests/test_service.py' | |||
934 | --- landscape/tests/test_service.py 2013-04-22 09:32:25 +0000 | |||
935 | +++ landscape/tests/test_service.py 2013-05-02 08:30:35 +0000 | |||
936 | @@ -7,7 +7,6 @@ | |||
937 | 7 | from landscape.reactor import FakeReactor | 7 | from landscape.reactor import FakeReactor |
938 | 8 | from landscape.deployment import Configuration | 8 | from landscape.deployment import Configuration |
939 | 9 | from landscape.service import LandscapeService | 9 | from landscape.service import LandscapeService |
940 | 10 | from landscape.amp import RemoteComponentConnector | ||
941 | 11 | from landscape.tests.helpers import LandscapeTest | 10 | from landscape.tests.helpers import LandscapeTest |
942 | 12 | 11 | ||
943 | 13 | 12 | ||
944 | @@ -15,10 +14,6 @@ | |||
945 | 15 | name = "monitor" | 14 | name = "monitor" |
946 | 16 | 15 | ||
947 | 17 | 16 | ||
948 | 18 | class RemoteTestComponentCreator(RemoteComponentConnector): | ||
949 | 19 | component = TestComponent | ||
950 | 20 | |||
951 | 21 | |||
952 | 22 | class TestService(LandscapeService): | 17 | class TestService(LandscapeService): |
953 | 23 | service_name = TestComponent.name | 18 | service_name = TestComponent.name |
954 | 24 | 19 | ||
955 | 25 | 20 | ||
956 | === modified file 'landscape/tests/test_watchdog.py' | |||
957 | --- landscape/tests/test_watchdog.py 2013-04-29 11:44:32 +0000 | |||
958 | +++ landscape/tests/test_watchdog.py 2013-05-02 08:30:35 +0000 | |||
959 | @@ -22,7 +22,7 @@ | |||
960 | 22 | from landscape.lib.dns import discover_server | 22 | from landscape.lib.dns import discover_server |
961 | 23 | from landscape.configuration import ( | 23 | from landscape.configuration import ( |
962 | 24 | fetch_base64_ssl_public_certificate, print_text) | 24 | fetch_base64_ssl_public_certificate, print_text) |
964 | 25 | from landscape.amp import ComponentProtocolClientFactory, RemoteComponentConnector | 25 | from landscape.amp import ComponentConnector |
965 | 26 | from landscape.broker.amp import RemoteBrokerConnector | 26 | from landscape.broker.amp import RemoteBrokerConnector |
966 | 27 | from landscape.deployment import Configuration | 27 | from landscape.deployment import Configuration |
967 | 28 | from landscape.reactor import TwistedReactor | 28 | from landscape.reactor import TwistedReactor |
968 | @@ -472,15 +472,9 @@ | |||
969 | 472 | name = "broker" | 472 | name = "broker" |
970 | 473 | 473 | ||
971 | 474 | 474 | ||
978 | 475 | class StubBrokerProtocolFactory(ComponentProtocolClientFactory): | 475 | class RemoteStubBrokerConnector(ComponentConnector): |
973 | 476 | |||
974 | 477 | initialDelay = 0.1 | ||
975 | 478 | |||
976 | 479 | |||
977 | 480 | class RemoteStubBrokerConnector(RemoteComponentConnector): | ||
979 | 481 | 476 | ||
980 | 482 | component = StubBroker | 477 | component = StubBroker |
981 | 483 | factory = StubBrokerProtocolFactory | ||
982 | 484 | 478 | ||
983 | 485 | 479 | ||
984 | 486 | class DaemonTestBase(LandscapeTest): | 480 | class DaemonTestBase(LandscapeTest): |
985 | @@ -945,6 +939,7 @@ | |||
986 | 945 | return RemoteBrokerConnector | 939 | return RemoteBrokerConnector |
987 | 946 | 940 | ||
988 | 947 | def test_is_running(self): | 941 | def test_is_running(self): |
989 | 942 | self.daemon._connector._reactor = self.broker_service.reactor | ||
990 | 948 | result = self.daemon.is_running() | 943 | result = self.daemon.is_running() |
991 | 949 | result.addCallback(self.assertTrue) | 944 | result.addCallback(self.assertTrue) |
992 | 950 | return result | 945 | return result |
993 | 951 | 946 | ||
994 | === modified file 'landscape/watchdog.py' | |||
995 | --- landscape/watchdog.py 2013-04-22 09:32:25 +0000 | |||
996 | +++ landscape/watchdog.py 2013-05-02 08:30:35 +0000 | |||
997 | @@ -68,7 +68,7 @@ | |||
998 | 68 | @cvar factor: The factor by which the delay between subsequent connection | 68 | @cvar factor: The factor by which the delay between subsequent connection |
999 | 69 | attempts will increase. | 69 | attempts will increase. |
1000 | 70 | 70 | ||
1002 | 71 | @param connector: The L{RemoteComponentConnector} of the daemon. | 71 | @param connector: The L{ComponentConnector} of the daemon. |
1003 | 72 | @param reactor: The reactor used to spawn the process and schedule timed | 72 | @param reactor: The reactor used to spawn the process and schedule timed |
1004 | 73 | calls. | 73 | calls. |
1005 | 74 | @param verbose: Optionally, report more information when running this | 74 | @param verbose: Optionally, report more information when running this |
+1
The duplication of comments in test_configuration is a bit odd, but I guess you're trying to ensure that point isn't missed.