background_services_spec.rb 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. # Copyright (C) 2012-2024 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 contain_exactly(BackgroundServices::Service::ProcessScheduledJobs, BackgroundServices::Service::ProcessDelayedJobs)
  32. end
  33. end
  34. describe '#run', ensure_threads_exited: true do
  35. let(:config) { described_class::ServiceConfig.new(service: SampleService, disabled: false, workers: 0) }
  36. it 'runs given services' do
  37. allow(instance).to receive(:run_service)
  38. ensure_block_keeps_running { instance.run }
  39. expect(instance).to have_received(:run_service).with(config)
  40. end
  41. end
  42. describe '#run_service' do
  43. let(:config) { described_class::ServiceConfig.new(service: SampleService, disabled: is_disabled, workers: workers_count) }
  44. let(:is_disabled) { false }
  45. before do
  46. allow(instance).to receive(:start_as_forks)
  47. allow(instance).to receive(:start_as_thread)
  48. end
  49. shared_examples 'stops early if disabled' do
  50. context 'when disabled' do
  51. let(:is_disabled) { true }
  52. it 'stops early if disabled', :aggregate_failures do
  53. allow(Rails.logger).to receive(:debug)
  54. instance.send(:run_service, config)
  55. expect(Rails.logger).to have_received(:debug).with(no_args) do |&block|
  56. expect(block.call).to match(%r{Skipping disabled service})
  57. end
  58. end
  59. end
  60. end
  61. shared_examples 'calls pre_run' do
  62. it 'calls pre_run' do
  63. allow(config.service).to receive(:pre_run)
  64. instance.send(:run_service, config)
  65. expect(config.service).to have_received(:pre_run)
  66. end
  67. end
  68. context 'when workers present' do
  69. let(:workers_count) { 1 }
  70. include_examples 'stops early if disabled'
  71. include_examples 'calls pre_run'
  72. it 'starts as fork' do
  73. instance.send(:run_service, config)
  74. expect(instance).to have_received(:start_as_forks).with(config.service, config.workers)
  75. end
  76. end
  77. context 'when workers not present' do
  78. let(:workers_count) { 0 }
  79. include_examples 'stops early if disabled'
  80. include_examples 'calls pre_run'
  81. it 'starts as thread' do
  82. instance.send(:run_service, config)
  83. expect(instance).to have_received(:start_as_thread).with(config.service)
  84. end
  85. end
  86. end
  87. describe '#start_as_forks' do
  88. context 'with a file check' do
  89. after do
  90. File.delete ProcessService.path
  91. end
  92. it 'runs Service#run' do
  93. instance.send(:start_as_forks, ProcessService, 1)
  94. sleep 0.1 until File.exist? ProcessService.path
  95. expect(File.read(ProcessService.path)).to eq('run')
  96. end
  97. end
  98. it 'forks a new process' do
  99. process_pids = instance.send(:start_as_forks, SampleService, 1)
  100. Process.wait process_pids.first
  101. expect($CHILD_STATUS).to be_success
  102. end
  103. end
  104. describe '#start_as_thread', ensure_threads_exited: true do
  105. let(:config) { described_class::ServiceConfig.new(service: SampleService, disabled: false, workers: 0) }
  106. context 'with logging' do
  107. let(:log) { [] }
  108. before do
  109. allow_any_instance_of(SampleService).to receive(:run) do
  110. log << :run_called
  111. end
  112. end
  113. it 'runs Service#run' do
  114. instance.send(:start_as_thread, SampleService)
  115. sleep 0.1 until log.any?
  116. expect(log).to be_present
  117. end
  118. end
  119. it 'starts a new thread' do
  120. thread = instance.send(:start_as_thread, SampleService)
  121. expect(thread).to be_alive
  122. end
  123. end
  124. end