1
from landscape.tests.helpers import LandscapeTest, FakeRemoteBrokerHelper
3
from twisted.internet.defer import succeed, fail
5
from landscape.lib.bpickle import dumps
6
from landscape.lib.fetch import fetch
7
from landscape.broker.ping import PingClient, Pinger
8
from landscape.broker.registration import Identity
11
class FakePageGetter(object):
12
"""An fake web client."""
14
def __init__(self, response):
15
self.response = response
18
def get_page(self, url, post, headers, data):
20
A method which is supposed to act like a limited version of
21
L{landscape.lib.fetch.fetch}.
23
Record attempts to get pages, and return a deferred with pre-cooked
26
self.fetches.append((url, post, headers, data))
27
return dumps(self.response)
29
def failing_get_page(self, url, post, headers, data):
31
A method which is supposed to act like a limited version of
32
L{landscape.lib.fetch.fetch}.
34
Record attempts to get pages, and return a deferred with pre-cooked
37
raise AssertionError("That's a failure!")
40
class PingClientTest(LandscapeTest):
42
helpers = [FakeRemoteBrokerHelper]
44
def test_default_get_page(self):
46
The C{get_page} argument to L{PingClient} should be optional, and
47
default to L{twisted.web.client.getPage}.
49
client = PingClient(None, None, None)
50
self.assertEqual(client.get_page, fetch)
54
L{PingClient} should be able to send a web request to a specified URL
55
about a particular insecure ID.
57
client = FakePageGetter(None)
58
self.broker_service.identity.insecure_id = 10
59
url = "http://localhost/ping"
60
pinger = PingClient(self.broker_service.reactor, url,
61
self.broker_service.identity,
62
get_page=client.get_page)
66
[(url, True, {"Content-Type": "application/x-www-form-urlencoded"},
69
def test_ping_no_insecure_id(self):
71
If a L{PingClient} does not have an insecure-id yet, then the ping
74
client = FakePageGetter(None)
75
url = "http://localhost/ping"
76
pinger = PingClient(self.broker_service.reactor,
77
url, self.broker_service.identity,
78
get_page=client.get_page)
80
d.addCallback(self.assertEqual, False)
81
self.assertEquals(client.fetches, [])
83
def test_respond(self):
85
The L{PingClient.ping} fire the Deferred it returns with True if the
86
web request indicates that the computer has messages.
88
self.broker_service.identity.insecure_id = 23
89
client = FakePageGetter({"messages": True})
90
pinger = PingClient(self.broker_service.reactor,
91
None, self.broker_service.identity,
92
get_page=client.get_page)
94
d.addCallback(self.assertEqual, True)
96
def test_errback(self):
98
If a L{PingClient} does not have an insecure-id yet, then the ping
101
self.broker_service.identity.insecure_id = 23
102
client = FakePageGetter(None)
103
url = "http://localhost/ping"
104
pinger = PingClient(self.broker_service.reactor,
105
url, self.broker_service.identity,
106
get_page=client.failing_get_page)
109
def errback(failure):
110
failures.append(failure)
111
d.addErrback(errback)
112
self.assertEquals(len(failures), 1)
113
self.assertEquals(failures[0].getErrorMessage(), "That's a failure!")
114
self.assertEquals(failures[0].type, AssertionError)
117
class FakePingClient(object):
120
self.response = False
125
return succeed(self.response)
128
class PingerTest(LandscapeTest):
130
helpers = [FakeRemoteBrokerHelper]
132
# Tell the Plugin helper to not add a MessageExchange plugin, to interfere
133
# with our code which asserts stuff about when *our* plugin fires
135
install_exchanger = False
138
super(PingerTest, self).setUp()
139
self.url = "http://localhost:8081/whatever"
140
self.ping_client = FakePingClient()
141
def factory(reactor, url, insecure_id):
142
self.ping_client.url = url
143
self.ping_client.insecure_id = insecure_id
144
return self.ping_client
145
self.pinger = Pinger(self.broker_service.reactor,
146
self.url, self.broker_service.identity,
147
self.broker_service.exchanger,
148
interval=10, ping_client_factory=factory)
150
def test_default_ping_client(self):
152
The C{ping_client_factory} argument to L{Pinger} should be optional,
153
and default to L{PingClient}.
155
pinger = Pinger(self.broker_service.reactor, "http://foo.com/",
156
self.broker_service.identity,
157
self.broker_service.exchanger)
158
self.assertEqual(pinger.ping_client_factory, PingClient)
160
def test_occasional_ping(self):
162
The L{Pinger} should be able to occasionally ask if there are
166
self.broker_service.identity.insecure_id = 23
167
self.broker_service.reactor.advance(9)
168
self.assertEquals(self.ping_client.pings, 0)
169
self.broker_service.reactor.advance(1)
170
self.assertEquals(self.ping_client.pings, 1)
172
def test_set_insecure_id_message(self):
174
L{Pinger} should register a handler for the 'set-id' message
175
so that it can start pinging when an insecure-id has been
179
self.broker_service.identity.insecure_id = 42
180
self.broker_service.reactor.advance(10)
181
self.assertEquals(self.ping_client.pings, 1)
183
def test_load_insecure_id(self):
185
If the insecure-id has already been saved when the plugin is
186
registered, it should immediately start pinging.
188
self.broker_service.identity.insecure_id = 42
190
self.broker_service.reactor.advance(10)
191
self.assertEqual(self.ping_client.pings, 1)
193
def test_response(self):
195
When a ping indicates there are messages, an exchange should occur.
198
self.broker_service.identity.insecure_id = 42
200
self.ping_client.response = True
202
# 70 = ping delay + urgent exchange delay
203
self.broker_service.reactor.advance(70)
205
self.assertEquals(len(self.broker_service.transport.payloads), 1)
207
def test_negative_response(self):
209
When a ping indicates there are no messages, no exchange should occur.
212
self.broker_service.identity.insecure_id = 42
214
self.ping_client.response = False
215
self.broker_service.reactor.advance(10)
216
self.assertEquals(len(self.broker_service.transport.payloads), 0)
218
def test_ping_error(self):
220
When the web interaction fails for some reason, a message
223
self.log_helper.ignore_errors(ZeroDivisionError)
225
self.broker_service.identity.insecure_id = 42
228
return fail(ZeroDivisionError("Couldn't fetch page"))
229
self.ping_client.ping = bad_ping
231
self.broker_service.reactor.advance(10)
233
log = self.logfile.getvalue()
234
self.assertTrue("Error contacting ping server at "
235
"http://localhost:8081/whatever" in log)
236
self.assertTrue("ZeroDivisionError" in log)
237
self.assertTrue("Couldn't fetch page" in log)
239
def test_get_interval(self):
240
self.assertEquals(self.pinger.get_interval(), 10)
242
def test_set_intervals_handling(self):
245
self.broker_service.reactor.fire("message",
246
{"type": "set-intervals", "ping": 73})
247
self.assertEquals(self.pinger.get_interval(), 73)
249
# The server may set specific intervals only, not including the ping.
250
self.broker_service.reactor.fire("message", {"type": "set-intervals"})
251
self.assertEquals(self.pinger.get_interval(), 73)
253
self.broker_service.identity.insecure_id = 23
254
self.broker_service.reactor.advance(72)
255
self.assertEquals(self.ping_client.pings, 0)
256
self.broker_service.reactor.advance(1)
257
self.assertEquals(self.ping_client.pings, 1)