PageRenderTime 53ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/activejob/test/cases/logging_test.rb

https://github.com/foca/rails
Ruby | 300 lines | 257 code | 42 blank | 1 comment | 2 complexity | 541f1bf0881ce309720b0b2db042b5f3 MD5 | raw file
Possible License(s): ISC
  1. # frozen_string_literal: true
  2. require "helper"
  3. require "active_support/log_subscriber/test_helper"
  4. require "active_support/core_ext/numeric/time"
  5. require "jobs/hello_job"
  6. require "jobs/logging_job"
  7. require "jobs/overridden_logging_job"
  8. require "jobs/nested_job"
  9. require "jobs/rescue_job"
  10. require "jobs/retry_job"
  11. require "jobs/disable_log_job"
  12. require "jobs/abort_before_enqueue_job"
  13. require "models/person"
  14. class LoggingTest < ActiveSupport::TestCase
  15. include ActiveJob::TestHelper
  16. include ActiveSupport::LogSubscriber::TestHelper
  17. include ActiveSupport::Logger::Severity
  18. class TestLogger < ActiveSupport::Logger
  19. def initialize
  20. @file = StringIO.new
  21. super(@file)
  22. end
  23. def messages
  24. @file.rewind
  25. @file.read
  26. end
  27. end
  28. def setup
  29. super
  30. JobBuffer.clear
  31. @old_logger = ActiveJob::Base.logger
  32. @logger = ActiveSupport::TaggedLogging.new(TestLogger.new)
  33. set_logger @logger
  34. ActiveJob::LogSubscriber.attach_to :active_job
  35. end
  36. def teardown
  37. super
  38. ActiveJob::LogSubscriber.log_subscribers.pop
  39. set_logger @old_logger
  40. end
  41. def set_logger(logger)
  42. ActiveJob::Base.logger = logger
  43. end
  44. def subscribed(&block)
  45. [].tap do |events|
  46. ActiveSupport::Notifications.subscribed(-> (*args) { events << args }, /enqueue.*\.active_job/, &block)
  47. end
  48. end
  49. def test_uses_active_job_as_tag
  50. HelloJob.perform_later "Cristian"
  51. assert_match(/\[ActiveJob\]/, @logger.messages)
  52. end
  53. def test_uses_job_name_as_tag
  54. perform_enqueued_jobs do
  55. LoggingJob.perform_later "Dummy"
  56. assert_match(/\[LoggingJob\]/, @logger.messages)
  57. end
  58. end
  59. def test_uses_job_id_as_tag
  60. perform_enqueued_jobs do
  61. LoggingJob.perform_later "Dummy"
  62. assert_match(/\[LOGGING-JOB-ID\]/, @logger.messages)
  63. end
  64. end
  65. def test_logs_correct_queue_name
  66. original_queue_name = LoggingJob.queue_name
  67. LoggingJob.queue_as :php_jobs
  68. LoggingJob.perform_later("Dummy")
  69. assert_match(/to .*?\(php_jobs\).*/, @logger.messages)
  70. ensure
  71. LoggingJob.queue_name = original_queue_name
  72. end
  73. def test_globalid_parameter_logging
  74. perform_enqueued_jobs do
  75. person = Person.new(123)
  76. LoggingJob.perform_later person
  77. assert_match(%r{Enqueued.*gid://aj/Person/123}, @logger.messages)
  78. assert_match(%r{Dummy, here is it: #<Person:.*>}, @logger.messages)
  79. assert_match(%r{Performing.*gid://aj/Person/123}, @logger.messages)
  80. end
  81. end
  82. def test_globalid_nested_parameter_logging
  83. perform_enqueued_jobs do
  84. person = Person.new(123)
  85. LoggingJob.perform_later(person: person)
  86. assert_match(%r{Enqueued.*gid://aj/Person/123}, @logger.messages)
  87. assert_match(%r{Dummy, here is it: .*#<Person:.*>}, @logger.messages)
  88. assert_match(%r{Performing.*gid://aj/Person/123}, @logger.messages)
  89. end
  90. end
  91. def test_enqueue_job_logging
  92. events = subscribed { HelloJob.perform_later "Cristian" }
  93. assert_match(/Enqueued HelloJob \(Job ID: .*?\) to .*?:.*Cristian/, @logger.messages)
  94. assert_equal(events.count, 1)
  95. key, * = events.first
  96. assert_equal(key, "enqueue.active_job")
  97. end
  98. def test_enqueue_job_log_error_when_callback_chain_is_halted
  99. events = subscribed { AbortBeforeEnqueueJob.perform_later }
  100. assert_match(/Failed enqueuing AbortBeforeEnqueueJob.* a before_enqueue callback halted/, @logger.messages)
  101. assert_equal(events.count, 1)
  102. key, * = events.first
  103. assert_equal(key, "enqueue.active_job")
  104. end
  105. def test_enqueue_job_log_error_when_error_is_raised_during_callback_chain
  106. events = subscribed do
  107. assert_raises(AbortBeforeEnqueueJob::MyError) do
  108. AbortBeforeEnqueueJob.perform_later(:raise)
  109. end
  110. end
  111. assert_match(/Failed enqueuing AbortBeforeEnqueueJob/, @logger.messages)
  112. assert_equal(events.count, 1)
  113. key, * = events.first
  114. assert_equal(key, "enqueue.active_job")
  115. end
  116. def test_perform_job_logging
  117. perform_enqueued_jobs do
  118. LoggingJob.perform_later "Dummy"
  119. assert_match(/Performing LoggingJob \(Job ID: .*?\) from .*? with arguments:.*Dummy/, @logger.messages)
  120. assert_match(/enqueued at /, @logger.messages)
  121. assert_match(/Dummy, here is it: Dummy/, @logger.messages)
  122. assert_match(/Performed LoggingJob \(Job ID: .*?\) from .*? in .*ms/, @logger.messages)
  123. end
  124. end
  125. def test_perform_job_log_error_when_callback_chain_is_halted
  126. subscribed { AbortBeforeEnqueueJob.perform_now }
  127. assert_match(/Error performing AbortBeforeEnqueueJob.* a before_perform callback halted/, @logger.messages)
  128. end
  129. def test_perform_job_doesnt_log_error_when_job_returns_falsy_value
  130. job = Class.new(ActiveJob::Base) do
  131. def perform
  132. nil
  133. end
  134. end
  135. subscribed { job.perform_now }
  136. assert_no_match(/Error performing AbortBeforeEnqueueJob.* a before_perform callback halted/, @logger.messages)
  137. end
  138. def test_perform_job_doesnt_log_error_when_job_is_performed_multiple_times_and_fail_the_first_time
  139. job = Class.new(ActiveJob::Base) do
  140. before_perform do
  141. throw(:abort) if arguments[0].pop == :abort
  142. end
  143. def perform(_)
  144. end
  145. end.new([:dont_abort, :abort])
  146. subscribed do
  147. job.perform_now
  148. job.perform_now
  149. end
  150. assert_equal(1, @logger.messages.scan(/a before_perform callback halted the job execution/).size)
  151. end
  152. def test_perform_disabled_job_logging
  153. perform_enqueued_jobs do
  154. DisableLogJob.perform_later "Dummy"
  155. assert_no_match(/Enqueued DisableLogJob \(Job ID: .*?\) from .*? with arguments:.*Dummy/, @logger.messages)
  156. assert_no_match(/Performing DisableLogJob \(Job ID: .*?\) from .*? with arguments:.*Dummy/, @logger.messages)
  157. assert_match(/enqueued at /, @logger.messages)
  158. assert_match(/Dummy, here is it: Dummy/, @logger.messages)
  159. assert_match(/Performed DisableLogJob \(Job ID: .*?\) from .*? in .*ms/, @logger.messages)
  160. end
  161. end
  162. def test_perform_nested_jobs_logging
  163. perform_enqueued_jobs do
  164. NestedJob.perform_later
  165. assert_match(/\[LoggingJob\] \[.*?\]/, @logger.messages)
  166. assert_match(/\[ActiveJob\] Enqueued NestedJob \(Job ID: .*\) to/, @logger.messages)
  167. assert_match(/\[ActiveJob\] \[NestedJob\] \[NESTED-JOB-ID\] Performing NestedJob \(Job ID: .*?\) from/, @logger.messages)
  168. assert_match(/\[ActiveJob\] \[NestedJob\] \[NESTED-JOB-ID\] Enqueued LoggingJob \(Job ID: .*?\) to .* with arguments: "NestedJob"/, @logger.messages)
  169. assert_match(/\[ActiveJob\].*\[LoggingJob\] \[LOGGING-JOB-ID\] Performing LoggingJob \(Job ID: .*?\) from .* with arguments: "NestedJob"/, @logger.messages)
  170. assert_match(/\[ActiveJob\].*\[LoggingJob\] \[LOGGING-JOB-ID\] Dummy, here is it: NestedJob/, @logger.messages)
  171. assert_match(/\[ActiveJob\].*\[LoggingJob\] \[LOGGING-JOB-ID\] Performed LoggingJob \(Job ID: .*?\) from .* in/, @logger.messages)
  172. assert_match(/\[ActiveJob\] \[NestedJob\] \[NESTED-JOB-ID\] Performed NestedJob \(Job ID: .*?\) from .* in/, @logger.messages)
  173. end
  174. end
  175. def test_enqueue_at_job_logging
  176. events = subscribed { HelloJob.set(wait_until: 24.hours.from_now).perform_later "Cristian" }
  177. assert_match(/Enqueued HelloJob \(Job ID: .*\) to .*? at.*Cristian/, @logger.messages)
  178. assert_equal(events.count, 1)
  179. key, * = events.first
  180. assert_equal(key, "enqueue_at.active_job")
  181. rescue NotImplementedError
  182. skip
  183. end
  184. def test_enqueue_at_job_log_error_when_callback_chain_is_halted
  185. events = subscribed { AbortBeforeEnqueueJob.set(wait: 1.second).perform_later }
  186. assert_match(/Failed enqueuing AbortBeforeEnqueueJob.* a before_enqueue callback halted/, @logger.messages)
  187. assert_equal(events.count, 1)
  188. key, * = events.first
  189. assert_equal(key, "enqueue_at.active_job")
  190. end
  191. def test_enqueue_at_job_log_error_when_error_is_raised_during_callback_chain
  192. events = subscribed do
  193. assert_raises(AbortBeforeEnqueueJob::MyError) do
  194. AbortBeforeEnqueueJob.set(wait: 1.second).perform_later(:raise)
  195. end
  196. end
  197. assert_match(/Failed enqueuing AbortBeforeEnqueueJob/, @logger.messages)
  198. assert_equal(events.count, 1)
  199. key, * = events.first
  200. assert_equal(key, "enqueue_at.active_job")
  201. end
  202. def test_enqueue_in_job_logging
  203. events = subscribed { HelloJob.set(wait: 2.seconds).perform_later "Cristian" }
  204. assert_match(/Enqueued HelloJob \(Job ID: .*\) to .*? at.*Cristian/, @logger.messages)
  205. assert_equal(events.count, 1)
  206. key, * = events.first
  207. assert_equal(key, "enqueue_at.active_job")
  208. rescue NotImplementedError
  209. skip
  210. end
  211. def test_for_tagged_logger_support_is_consistent
  212. set_logger ::Logger.new(nil)
  213. OverriddenLoggingJob.perform_later "Dummy"
  214. end
  215. def test_job_error_logging
  216. perform_enqueued_jobs do
  217. RescueJob.perform_later "other"
  218. rescue RescueJob::OtherError
  219. assert_match(/Performing RescueJob \(Job ID: .*?\) from .*? with arguments:.*other/, @logger.messages)
  220. assert_match(/Error performing RescueJob \(Job ID: .*?\) from .*? in .*ms: RescueJob::OtherError \(Bad hair\):\n.*\brescue_job\.rb:\d+:in `perform'/, @logger.messages)
  221. end
  222. end
  223. def test_job_no_error_logging_on_rescuable_job
  224. perform_enqueued_jobs { RescueJob.perform_later "david" }
  225. assert_match(/Performing RescueJob \(Job ID: .*?\) from .*? with arguments:.*david/, @logger.messages)
  226. assert_no_match(/Error performing RescueJob \(Job ID: .*?\) from .*? in .*ms: ArgumentError \(Hair too good\):\n.*\brescue_job\.rb:\d+:in `perform'/, @logger.messages)
  227. end
  228. def test_enqueue_retry_logging
  229. perform_enqueued_jobs do
  230. RetryJob.perform_later "DefaultsError", 2
  231. assert_match(/Retrying RetryJob \(Job ID: .*?\) after \d+ attempts in 3 seconds, due to a DefaultsError.*\./, @logger.messages)
  232. end
  233. end
  234. def test_enqueue_retry_logging_on_retry_job
  235. perform_enqueued_jobs { RescueJob.perform_later "david" }
  236. assert_match(/Retrying RescueJob \(Job ID: .*?\) after \d+ attempts in 0 seconds\./, @logger.messages)
  237. end
  238. def test_retry_stopped_logging
  239. perform_enqueued_jobs do
  240. RetryJob.perform_later "CustomCatchError", 6
  241. assert_match(/Stopped retrying RetryJob \(Job ID: .*?\) due to a CustomCatchError.*, which reoccurred on \d+ attempts\./, @logger.messages)
  242. end
  243. end
  244. def test_retry_stopped_logging_without_block
  245. perform_enqueued_jobs do
  246. RetryJob.perform_later "DefaultsError", 6
  247. rescue DefaultsError
  248. assert_match(/Stopped retrying RetryJob \(Job ID: .*?\) due to a DefaultsError.*, which reoccurred on \d+ attempts\./, @logger.messages)
  249. end
  250. end
  251. def test_discard_logging
  252. perform_enqueued_jobs do
  253. RetryJob.perform_later "DiscardableError", 2
  254. assert_match(/Discarded RetryJob \(Job ID: .*?\) due to a DiscardableError.*\./, @logger.messages)
  255. end
  256. end
  257. end