background_services_spec.rb 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. # Copyright (C) 2012-2022 Zammad Foundation, https://zammad-foundation.org/
  2. require 'rails_helper'
  3. class SampleService
  4. def self.pre_run; end
  5. def run
  6. sleep 1
  7. end
  8. def self.service_name
  9. 'Sample'
  10. end
  11. def self.max_workers
  12. 1
  13. end
  14. end
  15. class ProcessService < SampleService
  16. def run
  17. f = File.new self.class.path, 'w'
  18. f.write 'run'
  19. f.close
  20. sleep 1
  21. end
  22. def self.path
  23. Rails.root.join('tmp/process.service')
  24. end
  25. end
  26. RSpec.describe BackgroundServices do
  27. let(:instance) { described_class.new(config) }
  28. let(:config) { [] }
  29. describe '.available_services' do
  30. it 'matches existing classes' do
  31. expect(described_class.available_services).to match_array [
  32. BackgroundServices::Service::ProcessScheduledJobs,
  33. BackgroundServices::Service::ProcessDelayedJobs
  34. ]
  35. end
  36. end
  37. describe '#run', ensure_threads_exited: true do
  38. let(:config) { described_class::ServiceConfig.new(service: SampleService, disabled: false, workers: 0) }
  39. it 'runs given services' do
  40. allow(instance).to receive(:run_service)
  41. thread = ensure_block_keeps_running_in_thread { instance.run }
  42. expect(instance).to have_received(:run_service).with(config)
  43. thread.join
  44. end
  45. end
  46. describe '#run_service' do
  47. let(:config) { described_class::ServiceConfig.new(service: SampleService, disabled: is_disabled, workers: workers_count) }
  48. let(:is_disabled) { false }
  49. before do
  50. allow(instance).to receive(:start_as_forks)
  51. allow(instance).to receive(:start_as_thread)
  52. end
  53. shared_examples 'stops early if disabled' do
  54. context 'when disabled' do
  55. let(:is_disabled) { true }
  56. it 'stops early if disabled' do # rubocop:disable RSpec/MultipleExpectations
  57. allow(Rails.logger).to receive(:debug)
  58. instance.send(:run_service, config)
  59. expect(Rails.logger).to have_received(:debug).with(no_args) do |&block|
  60. expect(block.call).to match(%r{Skipping disabled service})
  61. end
  62. end
  63. end
  64. end
  65. shared_examples 'calls pre_run' do
  66. it 'calls pre_run' do
  67. allow(config.service).to receive(:pre_run)
  68. instance.send(:run_service, config)
  69. expect(config.service).to have_received(:pre_run)
  70. end
  71. end
  72. context 'when workers present' do
  73. let(:workers_count) { 1 }
  74. include_examples 'stops early if disabled'
  75. include_examples 'calls pre_run'
  76. it 'starts as fork' do
  77. instance.send(:run_service, config)
  78. expect(instance).to have_received(:start_as_forks).with(config.service, config.workers)
  79. end
  80. end
  81. context 'when workers not present' do
  82. let(:workers_count) { 0 }
  83. include_examples 'stops early if disabled'
  84. include_examples 'calls pre_run'
  85. it 'starts as thread' do
  86. instance.send(:run_service, config)
  87. expect(instance).to have_received(:start_as_thread).with(config.service)
  88. end
  89. end
  90. end
  91. describe '#start_as_forks' do
  92. context 'with a file check' do
  93. after do
  94. File.delete ProcessService.path
  95. end
  96. it 'runs Service#run' do
  97. instance.send(:start_as_forks, ProcessService, 1)
  98. sleep 0.1
  99. f = File.open ProcessService.path, 'r'
  100. expect(f.read).to eq('run')
  101. end
  102. end
  103. it 'forks a new process' do
  104. process_pids = instance.send(:start_as_forks, SampleService, 1)
  105. Process.wait process_pids.first
  106. expect($CHILD_STATUS).to be_success
  107. end
  108. end
  109. describe '#start_as_thread', ensure_threads_exited: true do
  110. let(:config) { described_class::ServiceConfig.new(service: SampleService, disabled: false, workers: 0) }
  111. context 'with logging' do
  112. let(:log) { [] }
  113. before do
  114. allow_any_instance_of(SampleService).to receive(:run) do
  115. log << :run_called
  116. end
  117. end
  118. it 'runs Service#run' do
  119. instance.send(:start_as_thread, SampleService)
  120. sleep 0.1
  121. expect(log).to be_present
  122. end
  123. end
  124. it 'starts a new thread' do
  125. thread = instance.send(:start_as_thread, SampleService)
  126. expect(thread).to be_alive
  127. end
  128. end
  129. end