Skip to content

Commit c2ec696

Browse files
committed
Improve tests in preparation for bumping Rails dependency
1 parent 845d36e commit c2ec696

File tree

11 files changed

+84
-75
lines changed

11 files changed

+84
-75
lines changed

app/models/solid_queue/semaphore.rb

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,6 @@ def signal
5252
end
5353

5454
private
55-
5655
attr_accessor :job
5756

5857
def attempt_creation
@@ -63,7 +62,9 @@ def attempt_creation
6362
end
6463
end
6564

66-
def check_limit_or_decrement = limit == 1 ? false : attempt_decrement
65+
def check_limit_or_decrement
66+
limit == 1 ? false : attempt_decrement
67+
end
6768

6869
def attempt_decrement
6970
Semaphore.available.where(key: key).update_all([ "value = value - 1, expires_at = ?", expires_at ]) > 0

test/integration/concurrency_controls_test.rb

Lines changed: 14 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,6 @@ class ConcurrencyControlsTest < ActiveSupport::TestCase
1818

1919
teardown do
2020
terminate_process(@pid) if process_exists?(@pid)
21-
22-
SolidQueue::Job.destroy_all
23-
SolidQueue::Process.destroy_all
24-
SolidQueue::Semaphore.delete_all
2521
end
2622

2723
test "run several conflicting jobs over the same record sequentially" do
@@ -33,8 +29,8 @@ class ConcurrencyControlsTest < ActiveSupport::TestCase
3329
SequentialUpdateResultJob.perform_later(@result, name: name)
3430
end
3531

36-
wait_for_jobs_to_finish_for(3.seconds)
37-
assert_no_pending_jobs
32+
wait_for_jobs_to_finish_for(5.seconds)
33+
assert_no_unfinished_jobs
3834

3935
assert_stored_sequence @result, ("A".."K").to_a
4036
end
@@ -51,7 +47,7 @@ class ConcurrencyControlsTest < ActiveSupport::TestCase
5147
end
5248

5349
wait_for_jobs_to_finish_for(5.seconds)
54-
assert_no_pending_jobs
50+
assert_no_unfinished_jobs
5551

5652
assert_stored_sequence @result, ("A".."K").to_a
5753
end
@@ -78,8 +74,8 @@ class ConcurrencyControlsTest < ActiveSupport::TestCase
7874
end
7975
end
8076

81-
wait_for_jobs_to_finish_for(3.seconds)
82-
assert_no_pending_jobs
77+
wait_for_jobs_to_finish_for(5.seconds)
78+
assert_no_unfinished_jobs
8379

8480
# C would have started in the beginning, seeing the status empty, and would finish after
8581
# all other jobs, so it'll do the last update with only itself
@@ -96,7 +92,7 @@ class ConcurrencyControlsTest < ActiveSupport::TestCase
9692
SequentialUpdateResultJob.perform_later(@result, name: name)
9793
end
9894

99-
wait_for_jobs_to_finish_for(3.seconds)
95+
wait_for_jobs_to_finish_for(5.seconds)
10096
assert_equal 3, SolidQueue::FailedExecution.count
10197

10298
assert_stored_sequence @result, [ "B", "D", "F" ] + ("G".."K").to_a
@@ -106,8 +102,8 @@ class ConcurrencyControlsTest < ActiveSupport::TestCase
106102
# Simulate a scenario where we got an available semaphore and some stuck jobs
107103
job = SequentialUpdateResultJob.perform_later(@result, name: "A")
108104

109-
wait_for_jobs_to_finish_for(3.seconds)
110-
assert_no_pending_jobs
105+
wait_for_jobs_to_finish_for(5.seconds)
106+
assert_no_unfinished_jobs
111107

112108
wait_while_with_timeout(1.second) { SolidQueue::Semaphore.where(value: 0).any? }
113109
# Lock the semaphore so we can enqueue jobs and leave them blocked
@@ -128,8 +124,8 @@ class ConcurrencyControlsTest < ActiveSupport::TestCase
128124
assert SolidQueue::Semaphore.signal(job)
129125

130126
# And wait for the dispatcher to release the jobs
131-
wait_for_jobs_to_finish_for(3.seconds)
132-
assert_no_pending_jobs
127+
wait_for_jobs_to_finish_for(5.seconds)
128+
assert_no_unfinished_jobs
133129

134130
# We can't ensure the order between B and C, because it depends on which worker wins when
135131
# unblocking, as one will try to unblock B and another C
@@ -139,8 +135,8 @@ class ConcurrencyControlsTest < ActiveSupport::TestCase
139135
test "rely on dispatcher to unblock blocked executions with an expired semaphore" do
140136
# Simulate a scenario where we got an available semaphore and some stuck jobs
141137
job = SequentialUpdateResultJob.perform_later(@result, name: "A")
142-
wait_for_jobs_to_finish_for(3.seconds)
143-
assert_no_pending_jobs
138+
wait_for_jobs_to_finish_for(5.seconds)
139+
assert_no_unfinished_jobs
144140

145141
wait_while_with_timeout(1.second) { SolidQueue::Semaphore.where(value: 0).any? }
146142
# Lock the semaphore so we can enqueue jobs and leave them blocked
@@ -160,8 +156,8 @@ class ConcurrencyControlsTest < ActiveSupport::TestCase
160156
SolidQueue::BlockedExecution.update_all(expires_at: 15.minutes.ago)
161157

162158
# And wait for dispatcher to release the jobs
163-
wait_for_jobs_to_finish_for(3.seconds)
164-
assert_no_pending_jobs
159+
wait_for_jobs_to_finish_for(5.seconds)
160+
assert_no_unfinished_jobs
165161

166162
# We can't ensure the order between B and C, because it depends on which worker wins when
167163
# unblocking, as one will try to unblock B and another C
@@ -198,7 +194,6 @@ class ConcurrencyControlsTest < ActiveSupport::TestCase
198194
end
199195

200196
private
201-
202197
def assert_stored_sequence(result, *sequences)
203198
expected = sequences.map { |sequence| "seq: " + sequence.map { |name| "s#{name}c#{name}" }.join }
204199
skip_active_record_query_cache do

test/integration/forked_processes_lifecycle_test.rb

Lines changed: 31 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,13 @@ class ForkedProcessesLifecycleTest < ActiveSupport::TestCase
1515

1616
teardown do
1717
terminate_process(@pid) if process_exists?(@pid)
18-
19-
SolidQueue::Process.destroy_all
20-
SolidQueue::Job.destroy_all
21-
JobResult.delete_all
2218
end
2319

2420
test "enqueue jobs in multiple queues" do
2521
6.times { |i| enqueue_store_result_job("job_#{i}") }
2622
6.times { |i| enqueue_store_result_job("job_#{i}", :default) }
2723

28-
wait_for_jobs_to_finish_for(0.5.seconds)
24+
wait_for_jobs_to_finish_for(2.seconds)
2925

3026
assert_equal 12, JobResult.count
3127
6.times { |i| assert_completed_job_results("job_#{i}", :background) }
@@ -63,17 +59,18 @@ class ForkedProcessesLifecycleTest < ActiveSupport::TestCase
6359
signal_process(@pid, :TERM, wait: 0.1.second)
6460
end
6561

66-
sleep(0.5.seconds)
62+
sleep(1.second)
6763
assert_clean_termination
6864
end
6965

7066
test "quit supervisor while there are jobs in-flight" do
7167
no_pause = enqueue_store_result_job("no pause")
72-
pause = enqueue_store_result_job("pause", pause: 1.seconds)
68+
pause = enqueue_store_result_job("pause", pause: 1.second)
7369

74-
signal_process(@pid, :QUIT, wait: 0.5.second)
75-
wait_for_jobs_to_finish_for(2.5.seconds)
70+
signal_process(@pid, :QUIT, wait: 0.4.second)
71+
wait_for_jobs_to_finish_for(2.seconds, except: pause)
7672

73+
wait_while_with_timeout(2.seconds) { process_exists?(@pid) }
7774
assert_not process_exists?(@pid)
7875

7976
assert_completed_job_results("no pause")
@@ -90,8 +87,8 @@ class ForkedProcessesLifecycleTest < ActiveSupport::TestCase
9087
no_pause = enqueue_store_result_job("no pause")
9188
pause = enqueue_store_result_job("pause", pause: 0.2.seconds)
9289

93-
signal_process(@pid, :TERM, wait: 0.1.second)
94-
wait_for_jobs_to_finish_for(0.5.seconds)
90+
signal_process(@pid, :TERM, wait: 0.3.second)
91+
wait_for_jobs_to_finish_for(3.seconds)
9592

9693
assert_completed_job_results("no pause")
9794
assert_completed_job_results("pause")
@@ -108,7 +105,7 @@ class ForkedProcessesLifecycleTest < ActiveSupport::TestCase
108105
pause = enqueue_store_result_job("pause", pause: 0.2.seconds)
109106

110107
signal_process(@pid, :INT, wait: 0.1.second)
111-
wait_for_jobs_to_finish_for(0.5.seconds)
108+
wait_for_jobs_to_finish_for(2.second)
112109

113110
assert_completed_job_results("no pause")
114111
assert_completed_job_results("pause")
@@ -124,8 +121,9 @@ class ForkedProcessesLifecycleTest < ActiveSupport::TestCase
124121
no_pause = enqueue_store_result_job("no pause")
125122
pause = enqueue_store_result_job("pause", pause: SolidQueue.shutdown_timeout + 10.second)
126123

127-
signal_process(@pid, :TERM, wait: 0.1.second)
128-
wait_for_jobs_to_finish_for(SolidQueue.shutdown_timeout + 0.1.second)
124+
signal_process(@pid, :TERM, wait: 0.5.second)
125+
126+
sleep(SolidQueue.shutdown_timeout + 0.5.second)
129127

130128
assert_completed_job_results("no pause")
131129
assert_job_status(no_pause, :finished)
@@ -152,12 +150,12 @@ class ForkedProcessesLifecycleTest < ActiveSupport::TestCase
152150
2.times { enqueue_store_result_job("no error", :default, pause: 0.01) }
153151
error3 = enqueue_store_result_job("error", :default, exception: RuntimeError)
154152

155-
wait_for_jobs_to_finish_for(0.5.seconds)
153+
wait_for_jobs_to_finish_for(2.second, except: [ error1, error2, error3 ])
156154

157155
assert_completed_job_results("no error", :background, 3)
158156
assert_completed_job_results("no error", :default, 4)
159157

160-
assert_failures 3
158+
wait_while_with_timeout(1.second) { SolidQueue::FailedExecution.count < 3 }
161159
[ error1, error2, error3 ].each do |job|
162160
assert_job_status(job, :failed)
163161
end
@@ -177,7 +175,7 @@ class ForkedProcessesLifecycleTest < ActiveSupport::TestCase
177175

178176
2.times { enqueue_store_result_job("no exit", :background) }
179177

180-
wait_for_jobs_to_finish_for(5.seconds)
178+
wait_for_jobs_to_finish_for(3.seconds, except: [ exit_job, pause_job ])
181179

182180
assert_completed_job_results("no exit", :default, 2)
183181
assert_completed_job_results("no exit", :background, 4)
@@ -208,6 +206,7 @@ class ForkedProcessesLifecycleTest < ActiveSupport::TestCase
208206
assert_nil SolidQueue::Process.find_by(id: worker.id)
209207

210208
# Jobs were completed
209+
wait_for_jobs_to_finish_for(1.second)
211210
assert_completed_job_results("pause", :background)
212211
assert_completed_job_results("pause", :default)
213212

@@ -218,7 +217,7 @@ class ForkedProcessesLifecycleTest < ActiveSupport::TestCase
218217
# And they can process jobs just fine
219218
enqueue_store_result_job("no_pause")
220219
enqueue_store_result_job("no_pause", :default)
221-
wait_for_jobs_to_finish_for(0.2.seconds)
220+
wait_for_jobs_to_finish_for(1.second)
222221

223222
assert_completed_job_results("no_pause", :background)
224223
assert_completed_job_results("no_pause", :default)
@@ -228,19 +227,18 @@ class ForkedProcessesLifecycleTest < ActiveSupport::TestCase
228227
end
229228

230229
test "kill worker individually" do
231-
killed_pause = enqueue_store_result_job("killed_pause", pause: 1.seconds)
230+
killed_pause = enqueue_store_result_job("killed_pause", pause: 1.second)
232231
enqueue_store_result_job("pause", :default, pause: 0.5.seconds)
233232

234233
worker = find_processes_registered_as("Worker").detect { |process| process.metadata["queues"].include? "background" }
235-
236-
signal_process(worker.pid, :KILL, wait: 0.3.second)
234+
signal_process(worker.pid, :KILL, wait: 0.5.seconds)
237235

238236
# Worker didn't have time to clean up or finish the work
239-
sleep(0.7.second)
237+
sleep(0.5.second)
240238
assert SolidQueue::Process.exists?(id: worker.id)
241239

242240
# And there's a new worker that has been registered for the background queue
243-
wait_for_registered_processes(4, timeout: 3.second)
241+
wait_for_registered_processes(4, timeout: 5.second)
244242

245243
# The job in the background queue was left claimed as the worker couldn't
246244
# finish orderly
@@ -252,7 +250,7 @@ class ForkedProcessesLifecycleTest < ActiveSupport::TestCase
252250
# The two current workers can process jobs just fine
253251
enqueue_store_result_job("no_pause")
254252
enqueue_store_result_job("no_pause", :default)
255-
wait_for_jobs_to_finish_for(0.5.seconds)
253+
sleep(2.seconds)
256254

257255
assert_completed_job_results("no_pause", :background)
258256
assert_completed_job_results("no_pause", :default)
@@ -291,11 +289,15 @@ def enqueue_store_result_job(value, queue_name = :background, **options)
291289
end
292290

293291
def assert_completed_job_results(value, queue_name = :background, count = 1)
294-
assert_equal count, JobResult.where(queue_name: queue_name, status: "completed", value: value).count
292+
skip_active_record_query_cache do
293+
assert_equal count, JobResult.where(queue_name: queue_name, status: "completed", value: value).count
294+
end
295295
end
296296

297297
def assert_started_job_result(value, queue_name = :background, count = 1)
298-
assert_equal count, JobResult.where(queue_name: queue_name, status: "started", value: value).count
298+
skip_active_record_query_cache do
299+
assert_equal count, JobResult.where(queue_name: queue_name, status: "started", value: value).count
300+
end
299301
end
300302

301303
def assert_job_status(active_job, status)
@@ -311,10 +313,8 @@ def assert_job_status(active_job, status)
311313
end
312314

313315
def assert_no_claimed_jobs
314-
assert SolidQueue::ClaimedExecution.none?
315-
end
316-
317-
def assert_failures(count)
318-
assert_equal count, SolidQueue::FailedExecution.count
316+
skip_active_record_query_cache do
317+
assert SolidQueue::ClaimedExecution.none?
318+
end
319319
end
320320
end

test/integration/puma/plugin_testing.rb

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,16 +32,14 @@ module PluginTesting
3232
teardown do
3333
terminate_process(@pid, signal: :INT) if process_exists?(@pid)
3434

35-
wait_for_registered_processes 0, timeout: 1.second
36-
37-
JobResult.delete_all
35+
wait_for_registered_processes 0, timeout: 2.seconds
3836
end
3937
end
4038

4139
test "perform jobs inside puma's process" do
4240
StoreResultJob.perform_later(:puma_plugin)
4341

44-
wait_for_jobs_to_finish_for(1.second)
42+
wait_for_jobs_to_finish_for(2.seconds)
4543
assert_equal 1, JobResult.where(queue_name: :background, status: "completed", value: :puma_plugin).count
4644
end
4745

test/integration/recurring_tasks_test.rb

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ class RecurringTasksTest < ActiveSupport::TestCase
2121
end
2222

2323
test "enqueue and process periodic tasks" do
24-
wait_for_jobs_to_be_enqueued(2, timeout: 2.seconds)
25-
wait_for_jobs_to_finish_for(2.seconds)
24+
wait_for_jobs_to_be_enqueued(2, timeout: 2.5.seconds)
25+
wait_for_jobs_to_finish_for(2.5.seconds)
2626

2727
terminate_process(@pid)
2828

@@ -33,7 +33,7 @@ class RecurringTasksTest < ActiveSupport::TestCase
3333
assert_equal "StoreResultJob", job.class_name
3434
end
3535

36-
assert_equal 2, JobResult.count
36+
assert JobResult.count >= 2
3737
JobResult.all.each do |result|
3838
assert_equal "custom_status", result.status
3939
assert_equal "42", result.value
@@ -43,6 +43,8 @@ class RecurringTasksTest < ActiveSupport::TestCase
4343

4444
test "persist and delete configured tasks" do
4545
configured_task = { periodic_store_result: { class: "StoreResultJob", schedule: "every second" } }
46+
# Wait for concurrency schedule loading after process registration
47+
sleep(0.5)
4648

4749
assert_recurring_tasks configured_task
4850
terminate_process(@pid)
@@ -53,6 +55,9 @@ class RecurringTasksTest < ActiveSupport::TestCase
5355
@pid = run_supervisor_as_fork
5456
wait_for_registered_processes(4, timeout: 3.second)
5557

58+
# Wait for concurrency schedule loading after process registration
59+
sleep(0.5)
60+
5661
assert_recurring_tasks configured_task
5762

5863
another_task = { example_task: { class: "AddToBufferJob", schedule: "every hour", args: [ 42 ] } }

test/models/solid_queue/job_test.rb

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,6 @@
33
class SolidQueue::JobTest < ActiveSupport::TestCase
44
self.use_transactional_tests = false
55

6-
teardown do
7-
SolidQueue::Job.destroy_all
8-
JobResult.delete_all
9-
end
10-
116
class NonOverlappingJob < ApplicationJob
127
limits_concurrency key: ->(job_result, **) { job_result }
138

test/test_helper.rb

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,24 @@ class ActiveSupport::TestCase
3232
if SolidQueue.supervisor_pidfile && File.exist?(SolidQueue.supervisor_pidfile)
3333
File.delete(SolidQueue.supervisor_pidfile)
3434
end
35+
36+
unless self.class.use_transactional_tests
37+
SolidQueue::Job.destroy_all
38+
SolidQueue::Process.destroy_all
39+
SolidQueue::Semaphore.delete_all
40+
SolidQueue::RecurringTask.delete_all
41+
JobResult.delete_all
42+
end
3543
end
3644

3745
private
38-
def wait_for_jobs_to_finish_for(timeout = 1.second)
39-
wait_while_with_timeout(timeout) { SolidQueue::Job.where(finished_at: nil).any? }
46+
def wait_for_jobs_to_finish_for(timeout = 1.second, except: [])
47+
wait_while_with_timeout(timeout) do
48+
SolidQueue::Job.where.not(active_job_id: Array(except).map(&:job_id)).where(finished_at: nil).any?
49+
end
4050
end
4151

42-
def assert_no_pending_jobs
52+
def assert_no_unfinished_jobs
4353
skip_active_record_query_cache do
4454
assert SolidQueue::Job.where(finished_at: nil).none?
4555
end

0 commit comments

Comments
 (0)