logxpy 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- logxpy/__init__.py +126 -0
- logxpy/_action.py +958 -0
- logxpy/_async.py +186 -0
- logxpy/_base.py +80 -0
- logxpy/_compat.py +71 -0
- logxpy/_config.py +45 -0
- logxpy/_dest.py +88 -0
- logxpy/_errors.py +58 -0
- logxpy/_fmt.py +68 -0
- logxpy/_generators.py +136 -0
- logxpy/_mask.py +23 -0
- logxpy/_message.py +195 -0
- logxpy/_output.py +517 -0
- logxpy/_pool.py +93 -0
- logxpy/_traceback.py +126 -0
- logxpy/_types.py +71 -0
- logxpy/_util.py +56 -0
- logxpy/_validation.py +486 -0
- logxpy/_version.py +21 -0
- logxpy/cli.py +61 -0
- logxpy/dask.py +172 -0
- logxpy/decorators.py +268 -0
- logxpy/filter.py +124 -0
- logxpy/journald.py +88 -0
- logxpy/json.py +149 -0
- logxpy/loggerx.py +253 -0
- logxpy/logwriter.py +84 -0
- logxpy/parse.py +191 -0
- logxpy/prettyprint.py +173 -0
- logxpy/serializers.py +36 -0
- logxpy/stdlib.py +23 -0
- logxpy/tai64n.py +45 -0
- logxpy/testing.py +472 -0
- logxpy/tests/__init__.py +9 -0
- logxpy/tests/common.py +36 -0
- logxpy/tests/strategies.py +231 -0
- logxpy/tests/test_action.py +1751 -0
- logxpy/tests/test_api.py +86 -0
- logxpy/tests/test_async.py +67 -0
- logxpy/tests/test_compat.py +13 -0
- logxpy/tests/test_config.py +21 -0
- logxpy/tests/test_coroutines.py +105 -0
- logxpy/tests/test_dask.py +211 -0
- logxpy/tests/test_decorators.py +54 -0
- logxpy/tests/test_filter.py +122 -0
- logxpy/tests/test_fmt.py +42 -0
- logxpy/tests/test_generators.py +292 -0
- logxpy/tests/test_journald.py +246 -0
- logxpy/tests/test_json.py +208 -0
- logxpy/tests/test_loggerx.py +44 -0
- logxpy/tests/test_logwriter.py +262 -0
- logxpy/tests/test_message.py +334 -0
- logxpy/tests/test_output.py +921 -0
- logxpy/tests/test_parse.py +309 -0
- logxpy/tests/test_pool.py +55 -0
- logxpy/tests/test_prettyprint.py +303 -0
- logxpy/tests/test_pyinstaller.py +35 -0
- logxpy/tests/test_serializers.py +36 -0
- logxpy/tests/test_stdlib.py +73 -0
- logxpy/tests/test_tai64n.py +66 -0
- logxpy/tests/test_testing.py +1051 -0
- logxpy/tests/test_traceback.py +251 -0
- logxpy/tests/test_twisted.py +814 -0
- logxpy/tests/test_util.py +45 -0
- logxpy/tests/test_validation.py +989 -0
- logxpy/twisted.py +265 -0
- logxpy-0.1.0.dist-info/METADATA +100 -0
- logxpy-0.1.0.dist-info/RECORD +72 -0
- logxpy-0.1.0.dist-info/WHEEL +5 -0
- logxpy-0.1.0.dist-info/entry_points.txt +2 -0
- logxpy-0.1.0.dist-info/licenses/LICENSE +201 -0
- logxpy-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,814 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Tests for L{eliot.twisted}.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import sys
|
|
6
|
+
from functools import wraps
|
|
7
|
+
|
|
8
|
+
try:
|
|
9
|
+
from twisted.internet.defer import Deferred, succeed, fail, returnValue
|
|
10
|
+
from twisted.trial.unittest import TestCase
|
|
11
|
+
from twisted.python.failure import Failure
|
|
12
|
+
from twisted.logger import globalLogPublisher
|
|
13
|
+
except ImportError:
|
|
14
|
+
# Make tests not run at all.
|
|
15
|
+
TestCase = object
|
|
16
|
+
else:
|
|
17
|
+
# Make sure we always import this if Twisted is available, so broken
|
|
18
|
+
# logwriter.py causes a failure:
|
|
19
|
+
from ..twisted import (
|
|
20
|
+
DeferredContext,
|
|
21
|
+
AlreadyFinished,
|
|
22
|
+
_passthrough,
|
|
23
|
+
redirectLogsForTrial,
|
|
24
|
+
_RedirectLogsForTrial,
|
|
25
|
+
TwistedDestination,
|
|
26
|
+
inline_callbacks,
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
from .test_generators import assert_expected_action_tree
|
|
30
|
+
|
|
31
|
+
from .._action import start_action, current_action, Action, TaskLevel
|
|
32
|
+
from .._output import MemoryLogger, Logger
|
|
33
|
+
from .._message import Message
|
|
34
|
+
from ..testing import assertContainsFields, capture_logging
|
|
35
|
+
from .. import removeDestination, addDestination
|
|
36
|
+
from .._traceback import write_traceback
|
|
37
|
+
from .common import FakeSys
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class PassthroughTests(TestCase):
|
|
41
|
+
"""
|
|
42
|
+
Tests for L{_passthrough}.
|
|
43
|
+
"""
|
|
44
|
+
|
|
45
|
+
def test_passthrough(self):
|
|
46
|
+
"""
|
|
47
|
+
L{_passthrough} returns the passed-in value.
|
|
48
|
+
"""
|
|
49
|
+
obj = object()
|
|
50
|
+
self.assertIs(obj, _passthrough(obj))
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def withActionContext(f):
|
|
54
|
+
"""
|
|
55
|
+
Decorator that calls a function with an action context.
|
|
56
|
+
|
|
57
|
+
@param f: A function.
|
|
58
|
+
"""
|
|
59
|
+
logger = MemoryLogger()
|
|
60
|
+
action = start_action(logger, "test")
|
|
61
|
+
|
|
62
|
+
@wraps(f)
|
|
63
|
+
def test(self):
|
|
64
|
+
with action.context():
|
|
65
|
+
return f(self)
|
|
66
|
+
|
|
67
|
+
return test
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
class DeferredContextTests(TestCase):
|
|
71
|
+
"""
|
|
72
|
+
Tests for L{DeferredContext}.
|
|
73
|
+
"""
|
|
74
|
+
|
|
75
|
+
def test_requireContext(self):
|
|
76
|
+
"""
|
|
77
|
+
L{DeferredContext} raises a L{RuntimeError} if it is called without an
|
|
78
|
+
action context.
|
|
79
|
+
"""
|
|
80
|
+
self.assertRaises(RuntimeError, DeferredContext, Deferred())
|
|
81
|
+
|
|
82
|
+
@withActionContext
|
|
83
|
+
def test_result(self):
|
|
84
|
+
"""
|
|
85
|
+
The passed-in L{Deferred} is available as the L{DeferredContext}'s
|
|
86
|
+
C{result} attribute.
|
|
87
|
+
"""
|
|
88
|
+
result = Deferred()
|
|
89
|
+
context = DeferredContext(result)
|
|
90
|
+
self.assertIs(context.result, result)
|
|
91
|
+
|
|
92
|
+
@withActionContext
|
|
93
|
+
def test_addCallbacksCallbackToDeferred(self):
|
|
94
|
+
"""
|
|
95
|
+
L{DeferredContext.addCallbacks} passes the given callback and its
|
|
96
|
+
corresponding arguments to the wrapped L{Deferred}'s
|
|
97
|
+
C{addCallbacks}.
|
|
98
|
+
"""
|
|
99
|
+
called = []
|
|
100
|
+
|
|
101
|
+
def f(value, x, y):
|
|
102
|
+
called.append((value, x, y))
|
|
103
|
+
|
|
104
|
+
result = Deferred()
|
|
105
|
+
context = DeferredContext(result)
|
|
106
|
+
context.addCallbacks(f, lambda x: None, (1,), {"y": 2})
|
|
107
|
+
result.callback(0)
|
|
108
|
+
self.assertEqual(called, [(0, 1, 2)])
|
|
109
|
+
|
|
110
|
+
@withActionContext
|
|
111
|
+
def test_addCallbacksErrbackToDeferred(self):
|
|
112
|
+
"""
|
|
113
|
+
L{DeferredContext.addCallbacks} passes the given errback and its
|
|
114
|
+
corresponding arguments to the wrapped L{Deferred}'s
|
|
115
|
+
C{addCallbacks}.
|
|
116
|
+
"""
|
|
117
|
+
called = []
|
|
118
|
+
|
|
119
|
+
def f(value, x, y):
|
|
120
|
+
value.trap(RuntimeError)
|
|
121
|
+
called.append((x, y))
|
|
122
|
+
|
|
123
|
+
result = Deferred()
|
|
124
|
+
context = DeferredContext(result)
|
|
125
|
+
context.addCallbacks(lambda x: None, f, None, None, (1,), {"y": 2})
|
|
126
|
+
result.errback(RuntimeError())
|
|
127
|
+
self.assertEqual(called, [(1, 2)])
|
|
128
|
+
|
|
129
|
+
@withActionContext
|
|
130
|
+
def test_addCallbacksWithOnlyCallback(self):
|
|
131
|
+
"""
|
|
132
|
+
L{DeferredContext.addCallbacks} can be called with a single argument, a
|
|
133
|
+
callback function, and passes it to the wrapped L{Deferred}'s
|
|
134
|
+
C{addCallbacks}.
|
|
135
|
+
"""
|
|
136
|
+
called = []
|
|
137
|
+
|
|
138
|
+
def f(value):
|
|
139
|
+
called.append(value)
|
|
140
|
+
|
|
141
|
+
result = Deferred()
|
|
142
|
+
context = DeferredContext(result)
|
|
143
|
+
context.addCallbacks(f)
|
|
144
|
+
result.callback(0)
|
|
145
|
+
self.assertEqual(called, [0])
|
|
146
|
+
|
|
147
|
+
@withActionContext
|
|
148
|
+
def test_addCallbacksWithOnlyCallbackErrorCase(self):
|
|
149
|
+
"""
|
|
150
|
+
L{DeferredContext.addCallbacks} can be called with a single argument, a
|
|
151
|
+
callback function, and passes a pass-through errback to the wrapped
|
|
152
|
+
L{Deferred}'s C{addCallbacks}.
|
|
153
|
+
"""
|
|
154
|
+
called = []
|
|
155
|
+
|
|
156
|
+
def f(value):
|
|
157
|
+
called.append(value)
|
|
158
|
+
|
|
159
|
+
class ExpectedException(Exception):
|
|
160
|
+
pass
|
|
161
|
+
|
|
162
|
+
result = Deferred()
|
|
163
|
+
context = DeferredContext(result)
|
|
164
|
+
context.addCallbacks(f)
|
|
165
|
+
result.errback(Failure(ExpectedException()))
|
|
166
|
+
self.assertEqual(called, [])
|
|
167
|
+
# The assertion is inside `failureResultOf`.
|
|
168
|
+
self.failureResultOf(result, ExpectedException)
|
|
169
|
+
|
|
170
|
+
@withActionContext
|
|
171
|
+
def test_addCallbacksReturnSelf(self):
|
|
172
|
+
"""
|
|
173
|
+
L{DeferredContext.addCallbacks} returns the L{DeferredContext}.
|
|
174
|
+
"""
|
|
175
|
+
result = Deferred()
|
|
176
|
+
context = DeferredContext(result)
|
|
177
|
+
self.assertIs(context, context.addCallbacks(lambda x: None, lambda x: None))
|
|
178
|
+
|
|
179
|
+
def test_addCallbacksCallbackContext(self):
|
|
180
|
+
"""
|
|
181
|
+
L{DeferedContext.addCallbacks} adds a callback that runs in context of
|
|
182
|
+
action that the L{DeferredContext} was created with.
|
|
183
|
+
"""
|
|
184
|
+
logger = MemoryLogger()
|
|
185
|
+
action1 = start_action(logger, "test")
|
|
186
|
+
action2 = start_action(logger, "test")
|
|
187
|
+
context = []
|
|
188
|
+
d = succeed(None)
|
|
189
|
+
with action1.context():
|
|
190
|
+
d = DeferredContext(d)
|
|
191
|
+
with action2.context():
|
|
192
|
+
d.addCallbacks(lambda x: context.append(current_action()), lambda x: x)
|
|
193
|
+
self.assertEqual(context, [action1])
|
|
194
|
+
|
|
195
|
+
def test_addCallbacksErrbackContext(self):
|
|
196
|
+
"""
|
|
197
|
+
L{DeferedContext.addCallbacks} adds an errback that runs in context of
|
|
198
|
+
action that the L{DeferredContext} was created with.
|
|
199
|
+
"""
|
|
200
|
+
logger = MemoryLogger()
|
|
201
|
+
action1 = start_action(logger, "test")
|
|
202
|
+
action2 = start_action(logger, "test")
|
|
203
|
+
context = []
|
|
204
|
+
d = fail(RuntimeError())
|
|
205
|
+
with action1.context():
|
|
206
|
+
d = DeferredContext(d)
|
|
207
|
+
with action2.context():
|
|
208
|
+
d.addCallbacks(lambda x: x, lambda x: context.append(current_action()))
|
|
209
|
+
self.assertEqual(context, [action1])
|
|
210
|
+
|
|
211
|
+
@withActionContext
|
|
212
|
+
def test_addCallbacksCallbackResult(self):
|
|
213
|
+
"""
|
|
214
|
+
A callback added with DeferredContext.addCallbacks has its result
|
|
215
|
+
passed on to the next callback.
|
|
216
|
+
"""
|
|
217
|
+
d = succeed(0)
|
|
218
|
+
d = DeferredContext(d)
|
|
219
|
+
d.addCallbacks(lambda x: [x, 1], lambda x: x)
|
|
220
|
+
self.assertEqual(self.successResultOf(d.result), [0, 1])
|
|
221
|
+
|
|
222
|
+
@withActionContext
|
|
223
|
+
def test_addCallbacksErrbackResult(self):
|
|
224
|
+
"""
|
|
225
|
+
An errback added with DeferredContext.addCallbacks has its result
|
|
226
|
+
passed on to the next callback.
|
|
227
|
+
"""
|
|
228
|
+
exception = ZeroDivisionError()
|
|
229
|
+
d = fail(exception)
|
|
230
|
+
d = DeferredContext(d)
|
|
231
|
+
d.addCallbacks(lambda x: x, lambda x: [x.value, 1])
|
|
232
|
+
self.assertEqual(self.successResultOf(d.result), [exception, 1])
|
|
233
|
+
|
|
234
|
+
def test_addActionFinishNoImmediateLogging(self):
|
|
235
|
+
"""
|
|
236
|
+
L{DeferredContext.addActionFinish} does not log anything if the
|
|
237
|
+
L{Deferred} hasn't fired yet.
|
|
238
|
+
"""
|
|
239
|
+
d = Deferred()
|
|
240
|
+
logger = MemoryLogger()
|
|
241
|
+
action = Action(logger, "uuid", TaskLevel(level=[1]), "sys:me")
|
|
242
|
+
with action.context():
|
|
243
|
+
DeferredContext(d).addActionFinish()
|
|
244
|
+
self.assertFalse(logger.messages)
|
|
245
|
+
|
|
246
|
+
def test_addActionFinishSuccess(self):
|
|
247
|
+
"""
|
|
248
|
+
When the L{Deferred} referred to by L{DeferredContext.addActionFinish}
|
|
249
|
+
fires successfully, a finish message is logged.
|
|
250
|
+
"""
|
|
251
|
+
d = Deferred()
|
|
252
|
+
logger = MemoryLogger()
|
|
253
|
+
action = Action(logger, "uuid", TaskLevel(level=[1]), "sys:me")
|
|
254
|
+
with action.context():
|
|
255
|
+
DeferredContext(d).addActionFinish()
|
|
256
|
+
d.callback("result")
|
|
257
|
+
assertContainsFields(
|
|
258
|
+
self,
|
|
259
|
+
logger.messages[0],
|
|
260
|
+
{
|
|
261
|
+
"task_uuid": "uuid",
|
|
262
|
+
"task_level": [1, 1],
|
|
263
|
+
"action_type": "sys:me",
|
|
264
|
+
"action_status": "succeeded",
|
|
265
|
+
},
|
|
266
|
+
)
|
|
267
|
+
|
|
268
|
+
def test_addActionFinishSuccessPassThrough(self):
|
|
269
|
+
"""
|
|
270
|
+
L{DeferredContext.addActionFinish} passes through a successful result
|
|
271
|
+
unchanged.
|
|
272
|
+
"""
|
|
273
|
+
d = Deferred()
|
|
274
|
+
logger = MemoryLogger()
|
|
275
|
+
action = Action(logger, "uuid", TaskLevel(level=[1]), "sys:me")
|
|
276
|
+
with action.context():
|
|
277
|
+
DeferredContext(d).addActionFinish()
|
|
278
|
+
d.callback("result")
|
|
279
|
+
result = []
|
|
280
|
+
d.addCallback(result.append)
|
|
281
|
+
self.assertEqual(result, ["result"])
|
|
282
|
+
|
|
283
|
+
def test_addActionFinishFailure(self):
|
|
284
|
+
"""
|
|
285
|
+
When the L{Deferred} referred to in L{DeferredContext.addActionFinish}
|
|
286
|
+
fires with an exception, a finish message is logged.
|
|
287
|
+
"""
|
|
288
|
+
d = Deferred()
|
|
289
|
+
logger = MemoryLogger()
|
|
290
|
+
action = Action(logger, "uuid", TaskLevel(level=[1]), "sys:me")
|
|
291
|
+
with action.context():
|
|
292
|
+
DeferredContext(d).addActionFinish()
|
|
293
|
+
exception = RuntimeError("because")
|
|
294
|
+
d.errback(exception)
|
|
295
|
+
assertContainsFields(
|
|
296
|
+
self,
|
|
297
|
+
logger.messages[0],
|
|
298
|
+
{
|
|
299
|
+
"task_uuid": "uuid",
|
|
300
|
+
"task_level": [1, 1],
|
|
301
|
+
"action_type": "sys:me",
|
|
302
|
+
"action_status": "failed",
|
|
303
|
+
"reason": "because",
|
|
304
|
+
"exception": "%s.RuntimeError" % (RuntimeError.__module__,),
|
|
305
|
+
},
|
|
306
|
+
)
|
|
307
|
+
d.addErrback(lambda _: None) # don't let Failure go to Twisted logs
|
|
308
|
+
|
|
309
|
+
def test_addActionFinishFailurePassThrough(self):
|
|
310
|
+
"""
|
|
311
|
+
L{DeferredContext.addActionFinish} passes through a failed result
|
|
312
|
+
unchanged.
|
|
313
|
+
"""
|
|
314
|
+
d = Deferred()
|
|
315
|
+
logger = MemoryLogger()
|
|
316
|
+
action = Action(logger, "uuid", TaskLevel(level=[1]), "sys:me")
|
|
317
|
+
with action.context():
|
|
318
|
+
DeferredContext(d).addActionFinish()
|
|
319
|
+
failure = Failure(RuntimeError())
|
|
320
|
+
d.errback(failure)
|
|
321
|
+
result = []
|
|
322
|
+
d.addErrback(result.append)
|
|
323
|
+
self.assertEqual(result, [failure])
|
|
324
|
+
|
|
325
|
+
@withActionContext
|
|
326
|
+
def test_addActionFinishRaisesAfterAddActionFinish(self):
|
|
327
|
+
"""
|
|
328
|
+
After L{DeferredContext.addActionFinish} is called, additional calls to
|
|
329
|
+
L{DeferredContext.addActionFinish} result in a L{AlreadyFinished}
|
|
330
|
+
exception.
|
|
331
|
+
"""
|
|
332
|
+
d = DeferredContext(Deferred())
|
|
333
|
+
d.addActionFinish()
|
|
334
|
+
self.assertRaises(AlreadyFinished, d.addActionFinish)
|
|
335
|
+
|
|
336
|
+
@withActionContext
|
|
337
|
+
def test_addCallbacksRaisesAfterAddActionFinish(self):
|
|
338
|
+
"""
|
|
339
|
+
After L{DeferredContext.addActionFinish} is called, additional calls to
|
|
340
|
+
L{DeferredContext.addCallbacks} result in a L{AlreadyFinished}
|
|
341
|
+
exception.
|
|
342
|
+
"""
|
|
343
|
+
d = DeferredContext(Deferred())
|
|
344
|
+
d.addActionFinish()
|
|
345
|
+
self.assertRaises(AlreadyFinished, d.addCallbacks, lambda x: x, lambda x: x)
|
|
346
|
+
|
|
347
|
+
@withActionContext
|
|
348
|
+
def test_addActionFinishResult(self):
|
|
349
|
+
"""
|
|
350
|
+
L{DeferredContext.addActionFinish} returns the L{Deferred}.
|
|
351
|
+
"""
|
|
352
|
+
d = Deferred()
|
|
353
|
+
self.assertIs(d, DeferredContext(d).addActionFinish())
|
|
354
|
+
|
|
355
|
+
# Having made sure DeferredContext.addCallbacks does the right thing
|
|
356
|
+
# regarding action contexts, for addCallback/addErrback/addBoth we only
|
|
357
|
+
# need to ensure that they call DeferredContext.addCallbacks.
|
|
358
|
+
|
|
359
|
+
@withActionContext
|
|
360
|
+
def test_addCallbackCallsAddCallbacks(self):
|
|
361
|
+
"""
|
|
362
|
+
L{DeferredContext.addCallback} passes its arguments on to
|
|
363
|
+
L{DeferredContext.addCallbacks}.
|
|
364
|
+
"""
|
|
365
|
+
result = Deferred()
|
|
366
|
+
context = DeferredContext(result)
|
|
367
|
+
called = []
|
|
368
|
+
|
|
369
|
+
def addCallbacks(
|
|
370
|
+
callback,
|
|
371
|
+
errback,
|
|
372
|
+
callbackArgs=None,
|
|
373
|
+
callbackKeywords=None,
|
|
374
|
+
errbackArgs=None,
|
|
375
|
+
errbackKeywords=None,
|
|
376
|
+
):
|
|
377
|
+
called.append(
|
|
378
|
+
(
|
|
379
|
+
callback,
|
|
380
|
+
errback,
|
|
381
|
+
callbackArgs,
|
|
382
|
+
callbackKeywords,
|
|
383
|
+
errbackArgs,
|
|
384
|
+
errbackKeywords,
|
|
385
|
+
)
|
|
386
|
+
)
|
|
387
|
+
|
|
388
|
+
context.addCallbacks = addCallbacks
|
|
389
|
+
|
|
390
|
+
def f(x, y, z):
|
|
391
|
+
return None
|
|
392
|
+
|
|
393
|
+
context.addCallback(f, 2, z=3)
|
|
394
|
+
self.assertEqual(called, [(f, _passthrough, (2,), {"z": 3}, None, None)])
|
|
395
|
+
|
|
396
|
+
@withActionContext
|
|
397
|
+
def test_addCallbackReturnsSelf(self):
|
|
398
|
+
"""
|
|
399
|
+
L{DeferredContext.addCallback} returns the L{DeferredContext}.
|
|
400
|
+
"""
|
|
401
|
+
result = Deferred()
|
|
402
|
+
context = DeferredContext(result)
|
|
403
|
+
self.assertIs(context, context.addCallback(lambda x: None))
|
|
404
|
+
|
|
405
|
+
@withActionContext
|
|
406
|
+
def test_addErrbackCallsAddCallbacks(self):
|
|
407
|
+
"""
|
|
408
|
+
L{DeferredContext.addErrback} passes its arguments on to
|
|
409
|
+
L{DeferredContext.addCallbacks}.
|
|
410
|
+
"""
|
|
411
|
+
result = Deferred()
|
|
412
|
+
context = DeferredContext(result)
|
|
413
|
+
called = []
|
|
414
|
+
|
|
415
|
+
def addCallbacks(
|
|
416
|
+
callback,
|
|
417
|
+
errback,
|
|
418
|
+
callbackArgs=None,
|
|
419
|
+
callbackKeywords=None,
|
|
420
|
+
errbackArgs=None,
|
|
421
|
+
errbackKeywords=None,
|
|
422
|
+
):
|
|
423
|
+
called.append(
|
|
424
|
+
(
|
|
425
|
+
callback,
|
|
426
|
+
errback,
|
|
427
|
+
callbackArgs,
|
|
428
|
+
callbackKeywords,
|
|
429
|
+
errbackArgs,
|
|
430
|
+
errbackKeywords,
|
|
431
|
+
)
|
|
432
|
+
)
|
|
433
|
+
|
|
434
|
+
context.addCallbacks = addCallbacks
|
|
435
|
+
|
|
436
|
+
def f(x, y, z):
|
|
437
|
+
pass
|
|
438
|
+
|
|
439
|
+
context.addErrback(f, 2, z=3)
|
|
440
|
+
self.assertEqual(called, [(_passthrough, f, None, None, (2,), {"z": 3})])
|
|
441
|
+
|
|
442
|
+
@withActionContext
|
|
443
|
+
def test_addErrbackReturnsSelf(self):
|
|
444
|
+
"""
|
|
445
|
+
L{DeferredContext.addErrback} returns the L{DeferredContext}.
|
|
446
|
+
"""
|
|
447
|
+
result = Deferred()
|
|
448
|
+
context = DeferredContext(result)
|
|
449
|
+
self.assertIs(context, context.addErrback(lambda x: None))
|
|
450
|
+
|
|
451
|
+
@withActionContext
|
|
452
|
+
def test_addBothCallsAddCallbacks(self):
|
|
453
|
+
"""
|
|
454
|
+
L{DeferredContext.addBoth} passes its arguments on to
|
|
455
|
+
L{DeferredContext.addCallbacks}.
|
|
456
|
+
"""
|
|
457
|
+
result = Deferred()
|
|
458
|
+
context = DeferredContext(result)
|
|
459
|
+
called = []
|
|
460
|
+
|
|
461
|
+
def addCallbacks(
|
|
462
|
+
callback,
|
|
463
|
+
errback,
|
|
464
|
+
callbackArgs=None,
|
|
465
|
+
callbackKeywords=None,
|
|
466
|
+
errbackArgs=None,
|
|
467
|
+
errbackKeywords=None,
|
|
468
|
+
):
|
|
469
|
+
called.append(
|
|
470
|
+
(
|
|
471
|
+
callback,
|
|
472
|
+
errback,
|
|
473
|
+
callbackArgs,
|
|
474
|
+
callbackKeywords,
|
|
475
|
+
errbackArgs,
|
|
476
|
+
errbackKeywords,
|
|
477
|
+
)
|
|
478
|
+
)
|
|
479
|
+
|
|
480
|
+
context.addCallbacks = addCallbacks
|
|
481
|
+
|
|
482
|
+
def f(x, y, z):
|
|
483
|
+
return None
|
|
484
|
+
|
|
485
|
+
context.addBoth(f, 2, z=3)
|
|
486
|
+
self.assertEqual(called, [(f, f, (2,), {"z": 3}, (2,), {"z": 3})])
|
|
487
|
+
|
|
488
|
+
@withActionContext
|
|
489
|
+
def test_addBothReturnsSelf(self):
|
|
490
|
+
"""
|
|
491
|
+
L{DeferredContext.addBoth} returns the L{DeferredContext}.
|
|
492
|
+
"""
|
|
493
|
+
result = Deferred()
|
|
494
|
+
context = DeferredContext(result)
|
|
495
|
+
self.assertIs(context, context.addBoth(lambda x: None))
|
|
496
|
+
|
|
497
|
+
|
|
498
|
+
class RedirectLogsForTrialTests(TestCase):
|
|
499
|
+
"""
|
|
500
|
+
Tests for L{redirectLogsForTrial}.
|
|
501
|
+
"""
|
|
502
|
+
|
|
503
|
+
def assertDestinationAdded(self, programPath):
|
|
504
|
+
"""
|
|
505
|
+
Assert that when running under the given program a new destination is
|
|
506
|
+
added by L{redirectLogsForTrial}.
|
|
507
|
+
|
|
508
|
+
@param programPath: A path to a program.
|
|
509
|
+
@type programPath: L{str}
|
|
510
|
+
"""
|
|
511
|
+
destination = _RedirectLogsForTrial(FakeSys([programPath], ""))()
|
|
512
|
+
self.assertIsInstance(destination, TwistedDestination)
|
|
513
|
+
# If this was not added as destination, removing it will raise an
|
|
514
|
+
# exception:
|
|
515
|
+
try:
|
|
516
|
+
removeDestination(destination)
|
|
517
|
+
except ValueError:
|
|
518
|
+
self.fail("Destination was not added.")
|
|
519
|
+
|
|
520
|
+
def test_withTrial(self):
|
|
521
|
+
"""
|
|
522
|
+
When C{sys.argv[0]} is C{"trial"} a new destination is added by
|
|
523
|
+
L{redirectLogsForTrial}.
|
|
524
|
+
"""
|
|
525
|
+
self.assertDestinationAdded("trial")
|
|
526
|
+
|
|
527
|
+
def test_withAbsoluteTrialPath(self):
|
|
528
|
+
"""
|
|
529
|
+
When C{sys.argv[0]} is an absolute path ending with C{"trial"} a new
|
|
530
|
+
destination is added by L{redirectLogsForTrial}.
|
|
531
|
+
"""
|
|
532
|
+
self.assertDestinationAdded("/usr/bin/trial")
|
|
533
|
+
|
|
534
|
+
def test_withRelativeTrialPath(self):
|
|
535
|
+
"""
|
|
536
|
+
When C{sys.argv[0]} is a relative path ending with C{"trial"} a new
|
|
537
|
+
destination is added by L{redirectLogsForTrial}.
|
|
538
|
+
"""
|
|
539
|
+
self.assertDestinationAdded("./trial")
|
|
540
|
+
|
|
541
|
+
def test_withoutTrialNoDestination(self):
|
|
542
|
+
"""
|
|
543
|
+
When C{sys.argv[0]} is not C{"trial"} no destination is added by
|
|
544
|
+
L{redirectLogsForTrial}.
|
|
545
|
+
"""
|
|
546
|
+
originalDestinations = Logger._destinations._destinations[:]
|
|
547
|
+
_RedirectLogsForTrial(FakeSys(["myprogram.py"], ""))()
|
|
548
|
+
self.assertEqual(Logger._destinations._destinations, originalDestinations)
|
|
549
|
+
|
|
550
|
+
def test_trialAsPathNoDestination(self):
|
|
551
|
+
"""
|
|
552
|
+
When C{sys.argv[0]} has C{"trial"} as directory name but not program
|
|
553
|
+
name no destination is added by L{redirectLogsForTrial}.
|
|
554
|
+
"""
|
|
555
|
+
originalDestinations = Logger._destinations._destinations[:]
|
|
556
|
+
_RedirectLogsForTrial(FakeSys(["./trial/myprogram.py"], ""))()
|
|
557
|
+
self.assertEqual(Logger._destinations._destinations, originalDestinations)
|
|
558
|
+
|
|
559
|
+
def test_withoutTrialResult(self):
|
|
560
|
+
"""
|
|
561
|
+
When not running under I{trial} L{None} is returned.
|
|
562
|
+
"""
|
|
563
|
+
self.assertIs(None, _RedirectLogsForTrial(FakeSys(["myprogram.py"], ""))())
|
|
564
|
+
|
|
565
|
+
def test_noDuplicateAdds(self):
|
|
566
|
+
"""
|
|
567
|
+
If a destination has already been added, calling
|
|
568
|
+
L{redirectLogsForTrial} a second time does not add another destination.
|
|
569
|
+
"""
|
|
570
|
+
redirect = _RedirectLogsForTrial(FakeSys(["trial"], ""))
|
|
571
|
+
destination = redirect()
|
|
572
|
+
self.addCleanup(removeDestination, destination)
|
|
573
|
+
originalDestinations = Logger._destinations._destinations[:]
|
|
574
|
+
redirect()
|
|
575
|
+
self.assertEqual(Logger._destinations._destinations, originalDestinations)
|
|
576
|
+
|
|
577
|
+
def test_noDuplicateAddsResult(self):
|
|
578
|
+
"""
|
|
579
|
+
If a destination has already been added, calling
|
|
580
|
+
L{redirectLogsForTrial} a second time returns L{None}.
|
|
581
|
+
"""
|
|
582
|
+
redirect = _RedirectLogsForTrial(FakeSys(["trial"], ""))
|
|
583
|
+
destination = redirect()
|
|
584
|
+
self.addCleanup(removeDestination, destination)
|
|
585
|
+
result = redirect()
|
|
586
|
+
self.assertIs(result, None)
|
|
587
|
+
|
|
588
|
+
def test_publicAPI(self):
|
|
589
|
+
"""
|
|
590
|
+
L{redirectLogsForTrial} is an instance of L{_RedirectLogsForTrial}.
|
|
591
|
+
"""
|
|
592
|
+
self.assertIsInstance(redirectLogsForTrial, _RedirectLogsForTrial)
|
|
593
|
+
|
|
594
|
+
def test_defaults(self):
|
|
595
|
+
"""
|
|
596
|
+
By default L{redirectLogsForTrial} looks at L{sys.argv}.
|
|
597
|
+
"""
|
|
598
|
+
self.assertEqual(redirectLogsForTrial._sys, sys)
|
|
599
|
+
|
|
600
|
+
|
|
601
|
+
class TwistedDestinationTests(TestCase):
|
|
602
|
+
"""
|
|
603
|
+
Tests for L{TwistedDestination}.
|
|
604
|
+
"""
|
|
605
|
+
|
|
606
|
+
def redirect_to_twisted(self):
|
|
607
|
+
"""
|
|
608
|
+
Redirect Eliot logs to Twisted.
|
|
609
|
+
|
|
610
|
+
@return: L{list} of L{dict} - the log messages written to Twisted will
|
|
611
|
+
eventually be appended to this list.
|
|
612
|
+
"""
|
|
613
|
+
written = []
|
|
614
|
+
|
|
615
|
+
def got_event(event):
|
|
616
|
+
if event.get("log_namespace") == "eliot":
|
|
617
|
+
written.append((event["log_level"].name, event["eliot"]))
|
|
618
|
+
|
|
619
|
+
globalLogPublisher.addObserver(got_event)
|
|
620
|
+
self.addCleanup(globalLogPublisher.removeObserver, got_event)
|
|
621
|
+
destination = TwistedDestination()
|
|
622
|
+
addDestination(destination)
|
|
623
|
+
self.addCleanup(removeDestination, destination)
|
|
624
|
+
return written
|
|
625
|
+
|
|
626
|
+
def redirect_to_list(self):
|
|
627
|
+
"""
|
|
628
|
+
Redirect Eliot logs to a list.
|
|
629
|
+
|
|
630
|
+
@return: L{list} that will have eventually have the written Eliot
|
|
631
|
+
messages added to it.
|
|
632
|
+
"""
|
|
633
|
+
written = []
|
|
634
|
+
destination = written.append
|
|
635
|
+
addDestination(destination)
|
|
636
|
+
self.addCleanup(removeDestination, destination)
|
|
637
|
+
return written
|
|
638
|
+
|
|
639
|
+
def test_normalMessages(self):
|
|
640
|
+
"""
|
|
641
|
+
Regular logxpy messages are pretty-printed to the given L{LogPublisher}.
|
|
642
|
+
"""
|
|
643
|
+
writtenToTwisted = self.redirect_to_twisted()
|
|
644
|
+
written = self.redirect_to_list()
|
|
645
|
+
logger = Logger()
|
|
646
|
+
Message.new(x=123, y=456).write(logger)
|
|
647
|
+
self.assertEqual(writtenToTwisted, [("info", written[0])])
|
|
648
|
+
|
|
649
|
+
def test_tracebackMessages(self):
|
|
650
|
+
"""
|
|
651
|
+
Traceback logxpy messages are written to the given L{LogPublisher} with
|
|
652
|
+
the traceback formatted for easier reading.
|
|
653
|
+
"""
|
|
654
|
+
writtenToTwisted = self.redirect_to_twisted()
|
|
655
|
+
written = self.redirect_to_list()
|
|
656
|
+
logger = Logger()
|
|
657
|
+
|
|
658
|
+
def raiser():
|
|
659
|
+
raise RuntimeError("because")
|
|
660
|
+
|
|
661
|
+
try:
|
|
662
|
+
raiser()
|
|
663
|
+
except Exception:
|
|
664
|
+
write_traceback(logger)
|
|
665
|
+
self.assertEqual(writtenToTwisted, [("critical", written[0])])
|
|
666
|
+
|
|
667
|
+
|
|
668
|
+
class InlineCallbacksTests(TestCase):
|
|
669
|
+
"""Tests for C{inline_callbacks}."""
|
|
670
|
+
|
|
671
|
+
# Get our custom assertion failure messages *and* the standard ones.
|
|
672
|
+
longMessage = True
|
|
673
|
+
|
|
674
|
+
def _a_b_test(self, logger, g):
|
|
675
|
+
"""A yield was done in between messages a and b inside C{inline_callbacks}."""
|
|
676
|
+
with start_action(action_type="the-action"):
|
|
677
|
+
self.assertIs(None, self.successResultOf(g()))
|
|
678
|
+
assert_expected_action_tree(self, logger, "the-action", ["a", "yielded", "b"])
|
|
679
|
+
|
|
680
|
+
@capture_logging(None)
|
|
681
|
+
def test_yield_none(self, logger):
|
|
682
|
+
def g():
|
|
683
|
+
Message.log(message_type="a")
|
|
684
|
+
yield
|
|
685
|
+
Message.log(message_type="b")
|
|
686
|
+
|
|
687
|
+
g = inline_callbacks(g, debug=True)
|
|
688
|
+
|
|
689
|
+
self._a_b_test(logger, g)
|
|
690
|
+
|
|
691
|
+
@capture_logging(None)
|
|
692
|
+
def test_yield_fired_deferred(self, logger):
|
|
693
|
+
def g():
|
|
694
|
+
Message.log(message_type="a")
|
|
695
|
+
yield succeed(None)
|
|
696
|
+
Message.log(message_type="b")
|
|
697
|
+
|
|
698
|
+
g = inline_callbacks(g, debug=True)
|
|
699
|
+
|
|
700
|
+
self._a_b_test(logger, g)
|
|
701
|
+
|
|
702
|
+
@capture_logging(None)
|
|
703
|
+
def test_yield_unfired_deferred(self, logger):
|
|
704
|
+
waiting = Deferred()
|
|
705
|
+
|
|
706
|
+
def g():
|
|
707
|
+
Message.log(message_type="a")
|
|
708
|
+
yield waiting
|
|
709
|
+
Message.log(message_type="b")
|
|
710
|
+
|
|
711
|
+
g = inline_callbacks(g, debug=True)
|
|
712
|
+
|
|
713
|
+
with start_action(action_type="the-action"):
|
|
714
|
+
d = g()
|
|
715
|
+
self.assertNoResult(waiting)
|
|
716
|
+
waiting.callback(None)
|
|
717
|
+
self.assertIs(None, self.successResultOf(d))
|
|
718
|
+
assert_expected_action_tree(self, logger, "the-action", ["a", "yielded", "b"])
|
|
719
|
+
|
|
720
|
+
@capture_logging(None)
|
|
721
|
+
def test_returnValue(self, logger):
|
|
722
|
+
result = object()
|
|
723
|
+
|
|
724
|
+
@inline_callbacks
|
|
725
|
+
def g():
|
|
726
|
+
if False:
|
|
727
|
+
yield
|
|
728
|
+
returnValue(result)
|
|
729
|
+
|
|
730
|
+
with start_action(action_type="the-action"):
|
|
731
|
+
d = g()
|
|
732
|
+
self.assertIs(result, self.successResultOf(d))
|
|
733
|
+
|
|
734
|
+
assert_expected_action_tree(self, logger, "the-action", [])
|
|
735
|
+
|
|
736
|
+
@capture_logging(None)
|
|
737
|
+
def test_returnValue_in_action(self, logger):
|
|
738
|
+
result = object()
|
|
739
|
+
|
|
740
|
+
@inline_callbacks
|
|
741
|
+
def g():
|
|
742
|
+
if False:
|
|
743
|
+
yield
|
|
744
|
+
with start_action(action_type="g"):
|
|
745
|
+
returnValue(result)
|
|
746
|
+
|
|
747
|
+
with start_action(action_type="the-action"):
|
|
748
|
+
d = g()
|
|
749
|
+
self.assertIs(result, self.successResultOf(d))
|
|
750
|
+
|
|
751
|
+
assert_expected_action_tree(self, logger, "the-action", [{"g": []}])
|
|
752
|
+
|
|
753
|
+
@capture_logging(None)
|
|
754
|
+
def test_nested_returnValue(self, logger):
|
|
755
|
+
result = object()
|
|
756
|
+
another = object()
|
|
757
|
+
|
|
758
|
+
def g():
|
|
759
|
+
d = h()
|
|
760
|
+
# Run h through to the end but ignore its result.
|
|
761
|
+
yield d
|
|
762
|
+
# Give back _our_ result.
|
|
763
|
+
returnValue(result)
|
|
764
|
+
|
|
765
|
+
g = inline_callbacks(g, debug=True)
|
|
766
|
+
|
|
767
|
+
def h():
|
|
768
|
+
yield
|
|
769
|
+
returnValue(another)
|
|
770
|
+
|
|
771
|
+
h = inline_callbacks(h, debug=True)
|
|
772
|
+
|
|
773
|
+
with start_action(action_type="the-action"):
|
|
774
|
+
d = g()
|
|
775
|
+
self.assertIs(result, self.successResultOf(d))
|
|
776
|
+
|
|
777
|
+
assert_expected_action_tree(self, logger, "the-action", ["yielded", "yielded"])
|
|
778
|
+
|
|
779
|
+
@capture_logging(None)
|
|
780
|
+
def test_async_returnValue(self, logger):
|
|
781
|
+
result = object()
|
|
782
|
+
waiting = Deferred()
|
|
783
|
+
|
|
784
|
+
@inline_callbacks
|
|
785
|
+
def g():
|
|
786
|
+
yield waiting
|
|
787
|
+
returnValue(result)
|
|
788
|
+
|
|
789
|
+
with start_action(action_type="the-action"):
|
|
790
|
+
d = g()
|
|
791
|
+
waiting.callback(None)
|
|
792
|
+
self.assertIs(result, self.successResultOf(d))
|
|
793
|
+
|
|
794
|
+
@capture_logging(None)
|
|
795
|
+
def test_nested_async_returnValue(self, logger):
|
|
796
|
+
result = object()
|
|
797
|
+
another = object()
|
|
798
|
+
|
|
799
|
+
waiting = Deferred()
|
|
800
|
+
|
|
801
|
+
@inline_callbacks
|
|
802
|
+
def g():
|
|
803
|
+
yield h()
|
|
804
|
+
returnValue(result)
|
|
805
|
+
|
|
806
|
+
@inline_callbacks
|
|
807
|
+
def h():
|
|
808
|
+
yield waiting
|
|
809
|
+
returnValue(another)
|
|
810
|
+
|
|
811
|
+
with start_action(action_type="the-action"):
|
|
812
|
+
d = g()
|
|
813
|
+
waiting.callback(None)
|
|
814
|
+
self.assertIs(result, self.successResultOf(d))
|