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.
Files changed (72) hide show
  1. logxpy/__init__.py +126 -0
  2. logxpy/_action.py +958 -0
  3. logxpy/_async.py +186 -0
  4. logxpy/_base.py +80 -0
  5. logxpy/_compat.py +71 -0
  6. logxpy/_config.py +45 -0
  7. logxpy/_dest.py +88 -0
  8. logxpy/_errors.py +58 -0
  9. logxpy/_fmt.py +68 -0
  10. logxpy/_generators.py +136 -0
  11. logxpy/_mask.py +23 -0
  12. logxpy/_message.py +195 -0
  13. logxpy/_output.py +517 -0
  14. logxpy/_pool.py +93 -0
  15. logxpy/_traceback.py +126 -0
  16. logxpy/_types.py +71 -0
  17. logxpy/_util.py +56 -0
  18. logxpy/_validation.py +486 -0
  19. logxpy/_version.py +21 -0
  20. logxpy/cli.py +61 -0
  21. logxpy/dask.py +172 -0
  22. logxpy/decorators.py +268 -0
  23. logxpy/filter.py +124 -0
  24. logxpy/journald.py +88 -0
  25. logxpy/json.py +149 -0
  26. logxpy/loggerx.py +253 -0
  27. logxpy/logwriter.py +84 -0
  28. logxpy/parse.py +191 -0
  29. logxpy/prettyprint.py +173 -0
  30. logxpy/serializers.py +36 -0
  31. logxpy/stdlib.py +23 -0
  32. logxpy/tai64n.py +45 -0
  33. logxpy/testing.py +472 -0
  34. logxpy/tests/__init__.py +9 -0
  35. logxpy/tests/common.py +36 -0
  36. logxpy/tests/strategies.py +231 -0
  37. logxpy/tests/test_action.py +1751 -0
  38. logxpy/tests/test_api.py +86 -0
  39. logxpy/tests/test_async.py +67 -0
  40. logxpy/tests/test_compat.py +13 -0
  41. logxpy/tests/test_config.py +21 -0
  42. logxpy/tests/test_coroutines.py +105 -0
  43. logxpy/tests/test_dask.py +211 -0
  44. logxpy/tests/test_decorators.py +54 -0
  45. logxpy/tests/test_filter.py +122 -0
  46. logxpy/tests/test_fmt.py +42 -0
  47. logxpy/tests/test_generators.py +292 -0
  48. logxpy/tests/test_journald.py +246 -0
  49. logxpy/tests/test_json.py +208 -0
  50. logxpy/tests/test_loggerx.py +44 -0
  51. logxpy/tests/test_logwriter.py +262 -0
  52. logxpy/tests/test_message.py +334 -0
  53. logxpy/tests/test_output.py +921 -0
  54. logxpy/tests/test_parse.py +309 -0
  55. logxpy/tests/test_pool.py +55 -0
  56. logxpy/tests/test_prettyprint.py +303 -0
  57. logxpy/tests/test_pyinstaller.py +35 -0
  58. logxpy/tests/test_serializers.py +36 -0
  59. logxpy/tests/test_stdlib.py +73 -0
  60. logxpy/tests/test_tai64n.py +66 -0
  61. logxpy/tests/test_testing.py +1051 -0
  62. logxpy/tests/test_traceback.py +251 -0
  63. logxpy/tests/test_twisted.py +814 -0
  64. logxpy/tests/test_util.py +45 -0
  65. logxpy/tests/test_validation.py +989 -0
  66. logxpy/twisted.py +265 -0
  67. logxpy-0.1.0.dist-info/METADATA +100 -0
  68. logxpy-0.1.0.dist-info/RECORD +72 -0
  69. logxpy-0.1.0.dist-info/WHEEL +5 -0
  70. logxpy-0.1.0.dist-info/entry_points.txt +2 -0
  71. logxpy-0.1.0.dist-info/licenses/LICENSE +201 -0
  72. 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))