scheduler_spec.rb 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. require 'rails_helper'
  2. RSpec.describe Scheduler do
  3. before do
  4. module SpecSpace
  5. class DelayedJobBackend
  6. def self.start
  7. # noop
  8. end
  9. # rubocop:disable Style/TrivialAccessors
  10. def self.reschedule=(reschedule)
  11. @reschedule = reschedule
  12. end
  13. def self.reschedule?(_delayed_job)
  14. @reschedule || false
  15. end
  16. end
  17. end
  18. end
  19. after do
  20. SpecSpace.send(:remove_const, :DelayedJobBackend)
  21. end
  22. describe '.failed_jobs' do
  23. it 'does list failed jobs' do
  24. job = create(:scheduler, status: 'error', active: false)
  25. failed_list = described_class.failed_jobs
  26. expect(failed_list).to be_present
  27. expect(failed_list).to include(job)
  28. end
  29. end
  30. describe '.restart_failed_jobs' do
  31. it 'does restart failed jobs' do
  32. job = create(:scheduler, status: 'error', active: false)
  33. described_class.restart_failed_jobs
  34. job.reload
  35. expect(job.active).to be true
  36. end
  37. end
  38. describe '._start_job' do
  39. it 'sets error status/message for failed jobs' do
  40. job = create(:scheduler)
  41. described_class._start_job(job)
  42. expect(job.status).to eq 'error'
  43. expect(job.active).to be false
  44. expect(job.error_message).to be_present
  45. end
  46. it 'executes job that is expected to succeed' do
  47. expect(Setting).to receive(:reload)
  48. job = create(:scheduler, method: 'Setting.reload')
  49. described_class._start_job(job)
  50. expect(job.status).to eq 'ok'
  51. end
  52. end
  53. describe '.cleanup' do
  54. it 'gets called by .threads' do
  55. expect(described_class).to receive(:cleanup).and_throw(:called)
  56. expect do
  57. described_class.threads
  58. end.to throw_symbol(:called)
  59. end
  60. context 'not called from .threads method' do
  61. it 'throws an exception' do
  62. expect do
  63. described_class.cleanup
  64. end.to raise_error(RuntimeError)
  65. end
  66. it 'throws no exception with force parameter' do
  67. expect do
  68. described_class.cleanup(force: true)
  69. end.not_to raise_error
  70. end
  71. end
  72. # helpers to avoid the throwing behaviour "describe"d above
  73. def simulate_threads_call
  74. threads
  75. end
  76. def threads
  77. described_class.cleanup
  78. end
  79. it 'keeps unlocked Delayed::Job-s' do
  80. # meta :)
  81. described_class.delay.cleanup
  82. expect do
  83. simulate_threads_call
  84. end.not_to change {
  85. Delayed::Job.count
  86. }
  87. end
  88. context 'locked Delayed::Job' do
  89. it 'gets destroyed' do
  90. # meta :)
  91. described_class.delay.cleanup
  92. # lock job (simluates interrupted scheduler task)
  93. locked_job = Delayed::Job.last
  94. locked_job.update!(locked_at: Time.zone.now)
  95. expect do
  96. simulate_threads_call
  97. end.to change {
  98. Delayed::Job.count
  99. }.by(-1)
  100. end
  101. context 'respond to reschedule?' do
  102. it 'gets rescheduled for positive responses' do
  103. SpecSpace::DelayedJobBackend.reschedule = true
  104. SpecSpace::DelayedJobBackend.delay.start
  105. # lock job (simluates interrupted scheduler task)
  106. locked_job = Delayed::Job.last
  107. locked_job.update!(locked_at: Time.zone.now)
  108. expect do
  109. simulate_threads_call
  110. end.to not_change {
  111. Delayed::Job.count
  112. }.and change {
  113. Delayed::Job.last.locked_at
  114. }
  115. end
  116. it 'gets destroyed for negative responses' do
  117. SpecSpace::DelayedJobBackend.reschedule = false
  118. SpecSpace::DelayedJobBackend.delay.start
  119. # lock job (simluates interrupted scheduler task)
  120. locked_job = Delayed::Job.last
  121. locked_job.update!(locked_at: Time.zone.now)
  122. expect do
  123. simulate_threads_call
  124. end.to change {
  125. Delayed::Job.count
  126. }.by(-1)
  127. end
  128. end
  129. end
  130. end
  131. end