1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 """testsuite base classes and helpers for diffing strings
19 """
20
21 from twisted.spread import pb
22 from twisted.internet import reactor, defer, selectreactor
23 from twisted.scripts import trial
24 from twisted.trial import unittest, util
25
26 from flumotion.common import log
27 from flumotion.configure import configure
28
29 __version__ = "$Rev$"
30
31
32 try:
33 _getConfig = trial.getConfig
34 except AttributeError:
35
36 _getConfig = dict
37
38
39 -def attr(*args, **kwargs):
40 """Decorator that adds attributes to objects.
41
42 It can be used to set the 'slow', 'skip', or 'todo' flags in test cases.
43 """
44
45 def wrap(func):
46 for name in args:
47
48 setattr(func, name, True)
49 for name, value in kwargs.items():
50 setattr(func, name, value)
51 return func
52 return wrap
53
54
55 -class TestCase(unittest.TestCase, log.Loggable):
56
57
58
59
60 supportedReactors = [selectreactor.SelectReactor]
61
62
63 if not hasattr(unittest.TestCase, 'failUnlessFailure'):
64
66
67 def _cb(result):
68 self.fail("did not catch an error, instead got %r" %
69 (result, ))
70
71 def _eb(failure):
72 failure.trap(*expectedFailures)
73 return failure.value
74 return deferred.addCallbacks(_cb, _eb)
75 assertFailure = failUnlessFailure
76
77
78
79 - def __init__(self, methodName=' impossible-name '):
123
125 """
126 Return whether this test has been marked as slow. Checks on the
127 instance first, then the class, then the module, then packages. As
128 soon as it finds something with a C{slow} attribute, returns that.
129 Returns C{False} if it cannot find anything.
130 """
131 return util.acquireAttribute(self._parents, 'slow', False)
132
133
134
135 - def debug(self, *args, **kwargs):
137
138
139
140
141
142
144
145 type = "client"
146 remoteRoot = None
147
148 - def run(self, port):
149 """
150 Start the client by connecting to the server on the given port.
151
152 @type port: int
153
154 @rtype: L{twisted.internet.defer.Deferred}
155 """
156 self._f = pb.PBClientFactory()
157 self._p = reactor.connectTCP("127.0.0.1", port, self._f)
158 d = self._f.getRootObject()
159 d.addCallback(self._gotRootObject)
160 return d
161
163 """
164 Stop the client.
165
166 @rtype: L{twisted.internet.defer.Deferred}
167 """
168 self._p.disconnect()
169 return self._dDisconnect
170
180
182
183 self.object = object
184
185
188
189
192
193
195 logCategory = "testmanagerroot"
196
198 """
199 Called by a TestClient to announce the type of client, and give
200 a reference.
201 """
202 self.debug('remote_identify: who %r, ref %r' % (who, reference))
203 key = who + 'Reference'
204 setattr(self, key, reference)
205
207
208 self.object = object
209
210
212
213 - def run(self, rootClass):
214 """
215 Run the test manager. Return port it is listening on.
216
217 @type rootClass: subclass of L{TestManagerRoot}
218
219 @rtype: int
220 """
221 self.root = rootClass()
222 factory = pb.PBServerFactory(self.root)
223 factory.unsafeTracebacks = 1
224 self._p = reactor.listenTCP(0, factory, interface="127.0.0.1")
225 port = self._p.getHost().port
226 return port
227
229 """
230 Stop the server.
231 """
232 return self._p.stopListening()
233
234
236 """
237 I combine a manager and a client to test passing back and forth objects.
238 """
239 logCategory = "testpb"
240
244
248
250 d = self.manager.stop()
251 d.addCallback(lambda r: self.client.stop())
252 return d
253
254 - def send(self, object):
255 """
256 Send the object from client to server.
257 Return the server's idea of the object.
258 """
259 self.debug('sending object %r from broker %r' % (
260 object, self.client.remoteRoot.broker))
261 d = self.client.remoteRoot.callRemote('receive', object)
262 d.addCallback(lambda r: self.manager.root.object)
263 return d
264
266 """
267 Receive the object from server to client.
268 Return the client's idea of the object.
269 """
270 self.debug('receiving object %r' % object)
271 d = self.manager.root.clientReference.callRemote('receive', object)
272 d.addCallback(lambda r: self.client.object)
273 return d
274
275
277
279 from flumotion.twisted import pb
280 from flumotion.common import server, connection
281 from flumotion.manager import manager, config
282 from StringIO import StringIO
283
284 managerConf = """
285 <planet>
286 <manager name="planet">
287 <host>localhost</host>
288 <port>0</port>
289 <transport>tcp</transport>
290 <component name="manager-bouncer" type="htpasswdcrypt-bouncer">
291 <property name="data"><![CDATA[
292 user:PSfNpHTkpTx1M
293 ]]></property>
294 </component>
295 </manager>
296 </planet>
297 """
298
299 conf = config.ManagerConfigParser(StringIO(managerConf)).manager
300 self.vishnu = manager.Vishnu(conf.name,
301 unsafeTracebacks=True)
302 self.vishnu.loadManagerConfigurationXML(StringIO(managerConf))
303 s = server.Server(self.vishnu)
304 if conf.transport == "ssl":
305 p = s.startSSL(conf.host, conf.port, conf.certificate,
306 configure.configdir)
307 elif conf.transport == "tcp":
308 p = s.startTCP(conf.host, conf.port)
309 self.tport = p
310 self.port = p.getHost().port
311 i = connection.PBConnectionInfo('localhost', self.port,
312 conf.transport == 'ssl',
313 pb.Authenticator(username='user',
314 password='test'))
315 self.connectionInfo = i
316
318
319 try:
320 self.flushLoggedErrors(*types)
321 except AttributeError:
322 from twisted.python import log as tlog
323 tlog.flushErrors(*types)
324
332
333
334 -def _diff(old, new, desc):
335 import difflib
336 lines = difflib.unified_diff(old, new)
337 lines = list(lines)
338 if not lines:
339 return
340 output = ''
341 for line in lines:
342 output += '%s: %s\n' % (desc, line[:-1])
343
344 raise AssertionError(
345 ("\nError while comparing strings:\n"
346 "%s") % (output, ))
347
348
350
351 def _tolines(s):
352 return [line + '\n' for line in s.split('\n')]
353
354 return _diff(_tolines(orig),
355 _tolines(new),
356 desc=desc)
357