rocketjob 1.3.0 → 2.0.0.rc1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +201 -0
  3. data/README.md +15 -10
  4. data/bin/rocketjob +3 -1
  5. data/bin/rocketjob_perf +92 -0
  6. data/lib/rocket_job/cli.rb +71 -31
  7. data/lib/rocket_job/config.rb +21 -23
  8. data/lib/rocket_job/dirmon_entry.rb +63 -45
  9. data/lib/rocket_job/extensions/aasm.rb +56 -0
  10. data/lib/rocket_job/extensions/mongo.rb +23 -0
  11. data/lib/rocket_job/job.rb +9 -433
  12. data/lib/rocket_job/jobs/dirmon_job.rb +20 -20
  13. data/lib/rocket_job/jobs/simple_job.rb +12 -0
  14. data/lib/rocket_job/plugins/document.rb +69 -0
  15. data/lib/rocket_job/plugins/job/callbacks.rb +92 -0
  16. data/lib/rocket_job/plugins/job/defaults.rb +40 -0
  17. data/lib/rocket_job/plugins/job/logger.rb +36 -0
  18. data/lib/rocket_job/plugins/job/model.rb +288 -0
  19. data/lib/rocket_job/plugins/job/persistence.rb +167 -0
  20. data/lib/rocket_job/plugins/job/state_machine.rb +166 -0
  21. data/lib/rocket_job/plugins/job/worker.rb +167 -0
  22. data/lib/rocket_job/plugins/restart.rb +54 -0
  23. data/lib/rocket_job/plugins/singleton.rb +26 -0
  24. data/lib/rocket_job/plugins/state_machine.rb +105 -0
  25. data/lib/rocket_job/version.rb +1 -1
  26. data/lib/rocket_job/worker.rb +150 -119
  27. data/lib/rocketjob.rb +43 -21
  28. data/test/config_test.rb +12 -0
  29. data/test/dirmon_entry_test.rb +81 -85
  30. data/test/dirmon_job_test.rb +40 -28
  31. data/test/job_test.rb +14 -257
  32. data/test/plugins/job/callbacks_test.rb +163 -0
  33. data/test/plugins/job/defaults_test.rb +52 -0
  34. data/test/plugins/job/logger_test.rb +58 -0
  35. data/test/plugins/job/model_test.rb +97 -0
  36. data/test/plugins/job/persistence_test.rb +81 -0
  37. data/test/plugins/job/state_machine_test.rb +118 -0
  38. data/test/plugins/job/worker_test.rb +183 -0
  39. data/test/plugins/restart_test.rb +185 -0
  40. data/test/plugins/singleton_test.rb +94 -0
  41. data/test/plugins/state_machine_event_callbacks_test.rb +101 -0
  42. data/test/plugins/state_machine_test.rb +64 -0
  43. data/test/test_helper.rb +3 -36
  44. metadata +64 -19
  45. data/lib/rocket_job/concerns/singleton.rb +0 -33
  46. data/lib/rocket_job/concerns/worker.rb +0 -214
  47. data/test/files/_archive/archived.txt +0 -3
  48. data/test/job_worker_test.rb +0 -86
  49. data/test/jobs/test_job.rb +0 -46
  50. data/test/worker_test.rb +0 -97
@@ -0,0 +1,81 @@
1
+ require_relative '../../test_helper'
2
+
3
+ module Plugins
4
+ module Job
5
+ # Unit Test for RocketJob::Job
6
+ class PersistenceTest < Minitest::Test
7
+
8
+ class PersistJob < RocketJob::Job
9
+ rocket_job do |job|
10
+ job.priority = 53
11
+ end
12
+
13
+ def perform(hash)
14
+ hash
15
+ end
16
+ end
17
+
18
+ describe RocketJob::Plugins::Job::Persistence do
19
+ before do
20
+ @description = 'Hello World'
21
+ @arguments = [{key: 'value'}]
22
+ @job = PersistJob.new(
23
+ description: @description,
24
+ arguments: [{key: 'value'}],
25
+ destroy_on_complete: false
26
+ )
27
+ end
28
+
29
+ after do
30
+ @job.destroy if @job && !@job.new_record?
31
+ end
32
+
33
+ describe '.config' do
34
+ it 'support multiple databases' do
35
+ assert_equal 'test_rocketjob', RocketJob::Job.collection.db.name
36
+ end
37
+ end
38
+
39
+ describe '.rocket_job' do
40
+ it 'sets defaults after initialize' do
41
+ assert_equal 53, @job.priority
42
+ end
43
+ end
44
+
45
+ describe '#reload' do
46
+ it 'handle hash' do
47
+ assert_equal 'value', @job.arguments.first[:key]
48
+ @job.worker_name = nil
49
+ @job.save!
50
+ @job.worker_name = '123'
51
+ @job.reload
52
+ assert @job.arguments.first.is_a?(ActiveSupport::HashWithIndifferentAccess), @job.arguments.first.class.ai
53
+ assert_equal 'value', @job.arguments.first['key']
54
+ assert_equal 'value', @job.arguments.first[:key]
55
+ assert_equal nil, @job.worker_name
56
+ end
57
+ end
58
+
59
+ describe '#save!' do
60
+ it 'save a blank job' do
61
+ @job.save!
62
+ assert_nil @job.worker_name
63
+ assert_nil @job.completed_at
64
+ assert @job.created_at
65
+ assert_equal @description, @job.description
66
+ assert_equal false, @job.destroy_on_complete
67
+ assert_nil @job.expires_at
68
+ assert_equal @arguments, @job.arguments
69
+ assert_equal 0, @job.percent_complete
70
+ assert_equal 53, @job.priority
71
+ assert_equal 0, @job.failure_count
72
+ assert_nil @job.run_at
73
+ assert_nil @job.started_at
74
+ assert_equal :queued, @job.state
75
+ end
76
+ end
77
+
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,118 @@
1
+ require_relative '../../test_helper'
2
+ module Plugins
3
+ module Job
4
+ # Unit Test for RocketJob::Job
5
+ class StateMachineTest < Minitest::Test
6
+
7
+ class StateMachineJob < RocketJob::Job
8
+ def perform
9
+ end
10
+ end
11
+
12
+ describe RocketJob::Plugins::Job::StateMachine do
13
+ before do
14
+ @job = StateMachineJob.new
15
+ end
16
+
17
+ after do
18
+ @job.destroy if @job && !@job.new_record?
19
+ end
20
+
21
+ describe '#requeue!' do
22
+ it 'requeue jobs from dead workers' do
23
+ worker_name = 'server:12345'
24
+ @job.worker_name = worker_name
25
+ @job.start!
26
+ assert @job.running?
27
+
28
+ @job.requeue!(worker_name)
29
+ @job.reload
30
+
31
+ assert @job.queued?
32
+ assert_equal nil, @job.worker_name
33
+ end
34
+ end
35
+
36
+ describe '#requeue' do
37
+ it 'requeue jobs from dead workers' do
38
+ worker_name = 'server:12345'
39
+ @job.worker_name = worker_name
40
+ assert @job.valid?, @job.errors.messages
41
+ @job.start!
42
+ assert @job.running?, @job.state
43
+
44
+ @job.requeue(worker_name)
45
+ assert @job.queued?
46
+ assert_equal nil, @job.worker_name
47
+
48
+ @job.reload
49
+ assert @job.running?
50
+ assert_equal worker_name, @job.worker_name
51
+ end
52
+ end
53
+
54
+ describe '#after_complete' do
55
+ it 'destroy on complete' do
56
+ @job.destroy_on_complete = true
57
+ @job.perform_now
58
+ assert @job.completed?, @job.state
59
+ assert_equal 0, RocketJob::Job.where(id: @job.id).count
60
+ end
61
+ end
62
+
63
+ describe '#fail!' do
64
+ it 'fail with message' do
65
+ @job.start!
66
+ @job.fail!('myworker:2323', 'oh no')
67
+ assert @job.failed?
68
+ assert exc = @job.exception
69
+ assert_equal 'RocketJob::JobException', exc.class_name
70
+ assert_equal 'oh no', exc.message
71
+ end
72
+
73
+ it 'fail with no arguments' do
74
+ @job.start!
75
+ @job.fail!
76
+ assert @job.failed?
77
+ assert exc = @job.exception
78
+ assert_equal 'RocketJob::JobException', exc.class_name
79
+ assert_equal nil, exc.message
80
+ assert_equal nil, exc.worker_name
81
+ assert_equal [], exc.backtrace
82
+ end
83
+
84
+ it 'fail with exception' do
85
+ @job.start!
86
+ exception = RuntimeError.new('Oh no')
87
+ @job.fail!('myworker:2323', exception)
88
+ assert @job.failed?
89
+ assert exc = @job.exception
90
+ assert_equal exception.class.name, exc.class_name
91
+ assert_equal exception.message, exc.message
92
+ assert_equal [], exc.backtrace
93
+ end
94
+ end
95
+
96
+ describe '#retry!' do
97
+ it 'retry failed jobs' do
98
+ worker_name = 'server:12345'
99
+ @job.worker_name = worker_name
100
+ @job.start!
101
+ assert @job.running?
102
+ assert_equal worker_name, @job.worker_name
103
+
104
+ @job.fail!(worker_name, 'oh no')
105
+ assert @job.failed?
106
+ assert_equal 'oh no', @job.exception.message
107
+
108
+ @job.retry!
109
+ assert @job.queued?
110
+ assert_equal nil, @job.worker_name
111
+ assert_equal nil, @job.exception
112
+ end
113
+ end
114
+
115
+ end
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,183 @@
1
+ require_relative '../../test_helper'
2
+
3
+ module Plugins
4
+ module Job
5
+ # Unit Test for RocketJob::Job
6
+ class WorkerTest < Minitest::Test
7
+ class QuietJob < RocketJob::Job
8
+ # Test increasing log level for debugging purposes
9
+ def perform
10
+ logger.trace 'enable tracing level for just the job instance'
11
+ end
12
+ end
13
+
14
+ class NoisyJob < RocketJob::Job
15
+ # Test silencing noisy logging
16
+ def perform
17
+ logger.info 'some very noisy logging'
18
+ end
19
+ end
20
+
21
+ class SumJob < RocketJob::Job
22
+ rocket_job do |job|
23
+ job.destroy_on_complete = false
24
+ job.collect_output = true
25
+ job.priority = 51
26
+ end
27
+
28
+ def perform(first, second)
29
+ first + second
30
+ end
31
+ end
32
+
33
+ describe RocketJob::Plugins::Job::Worker do
34
+ before do
35
+ RocketJob::Job.destroy_all
36
+ end
37
+
38
+ after do
39
+ @job.destroy if @job && !@job.new_record?
40
+ end
41
+
42
+ describe '.rocket_job_next_job' do
43
+ before do
44
+ @job = QuietJob.new
45
+ @worker = RocketJob::Worker.new(name: 'worker:123')
46
+ end
47
+
48
+ it 'return nil when no jobs available' do
49
+ assert_equal nil, RocketJob::Job.rocket_job_next_job(@worker.name)
50
+ end
51
+
52
+ it 'return the first job' do
53
+ @job.save!
54
+ assert job = RocketJob::Job.rocket_job_next_job(@worker.name), 'Failed to find job'
55
+ assert_equal @job.id, job.id
56
+ end
57
+
58
+ it 'Ignore future dated jobs' do
59
+ @job.run_at = Time.now + 1.hour
60
+ @job.save!
61
+ assert_equal nil, RocketJob::Job.rocket_job_next_job(@worker.name)
62
+ end
63
+
64
+ it 'Process future dated jobs when time is now' do
65
+ @job.run_at = Time.now
66
+ @job.save!
67
+ assert job = RocketJob::Job.rocket_job_next_job(@worker.name), 'Failed to find future job'
68
+ assert_equal @job.id, job.id
69
+ end
70
+
71
+ it 'Skip expired jobs' do
72
+ count = RocketJob::Job.count
73
+ @job.expires_at = Time.now - 100
74
+ @job.save!
75
+ assert_equal nil, RocketJob::Job.rocket_job_next_job(@worker.name)
76
+ assert_equal count, RocketJob::Job.count
77
+ end
78
+ end
79
+
80
+ describe '#perform_now' do
81
+ it 'calls perform method' do
82
+ @job = SumJob.new(arguments: [10, 5])
83
+ assert_equal 15, @job.perform_now['result']
84
+ assert @job.completed?, @job.attributes.ai
85
+ assert_equal 15, @job.result['result']
86
+ end
87
+
88
+ it 'saves exception' do
89
+ @job = SumJob.new(arguments: ['10', 5])
90
+ assert_raises TypeError do
91
+ @job.perform_now
92
+ end
93
+ assert @job.exception.backtrace
94
+ assert_equal 'TypeError', @job.exception.class_name
95
+ if RUBY_VERSION.to_f < 2.0
96
+ assert_equal "can't convert Fixnum into String", @job.exception.message
97
+ else
98
+ assert_equal 'no implicit conversion of Fixnum into String', @job.exception.message
99
+ end
100
+ assert_equal 'inline', @job.exception.worker_name
101
+ end
102
+
103
+ it 'silence logging when log_level is set' do
104
+ @job = NoisyJob.new
105
+ @job.log_level = :warn
106
+ logged = false
107
+ @job.logger.stub(:log_internal, -> level, index, message, payload, exception { logged = true if message.include?('some very noisy logging') }) do
108
+ @job.perform_now
109
+ end
110
+ assert_equal false, logged
111
+ end
112
+
113
+ it 'raise logging when log_level is set' do
114
+ @job = QuietJob.new
115
+ @job.log_level = :trace
116
+ logged = false
117
+ # Raise global log level to :info
118
+ SemanticLogger.stub(:default_level_index, 3) do
119
+ @job.logger.stub(:log_internal, -> { logged = true }) do
120
+ @job.perform_now
121
+ end
122
+ end
123
+ assert_equal false, logged
124
+ end
125
+ end
126
+
127
+ describe '.perform_later' do
128
+ it 'queues the job for processing' do
129
+ RocketJob::Config.stub(:inline_mode, false) do
130
+ @job = SumJob.perform_later(1, 23)
131
+ end
132
+ assert @job.queued?
133
+
134
+ # Manually run the job
135
+ @job.perform_now
136
+ assert @job.completed?, @job.attributes.ai
137
+ assert_equal 24, @job.result['result']
138
+
139
+ assert_nil @job.worker_name
140
+ assert @job.completed_at
141
+ assert @job.created_at
142
+ assert_equal false, @job.destroy_on_complete
143
+ assert_nil @job.expires_at
144
+ assert_equal 100, @job.percent_complete
145
+ assert_equal 51, @job.priority
146
+ assert_equal 0, @job.failure_count
147
+ assert_nil @job.run_at
148
+ assert @job.started_at
149
+ end
150
+
151
+ it 'runs the job immediately when inline_mode = true' do
152
+ RocketJob::Config.stub(:inline_mode, true) do
153
+ @job = SumJob.perform_later(1, 23)
154
+ end
155
+
156
+ assert @job.completed?, @job.attributes.ai
157
+ assert_equal 24, @job.result['result']
158
+
159
+ assert_nil @job.worker_name
160
+ assert @job.completed_at
161
+ assert @job.created_at
162
+ assert_equal false, @job.destroy_on_complete
163
+ assert_nil @job.expires_at
164
+ assert_equal 100, @job.percent_complete
165
+ assert_equal 51, @job.priority
166
+ assert_equal 0, @job.failure_count
167
+ assert_nil @job.run_at
168
+ assert @job.started_at
169
+ end
170
+ end
171
+
172
+ describe '.perform_now' do
173
+ it 'run the job immediately' do
174
+ @job = SumJob.perform_now(1, 5)
175
+ assert_equal true, @job.completed?
176
+ assert_equal 6, @job.result['result']
177
+ end
178
+ end
179
+
180
+ end
181
+ end
182
+ end
183
+ end
@@ -0,0 +1,185 @@
1
+ require_relative '../test_helper'
2
+
3
+ # Unit Test for RocketJob::Job
4
+ module Plugins
5
+ class RestartTest < Minitest::Test
6
+ class RestartableJob < RocketJob::Job
7
+ include RocketJob::Plugins::Restart
8
+
9
+ def perform
10
+ 'DONE'
11
+ end
12
+ end
13
+
14
+ describe RocketJob::Plugins::Restart do
15
+ before do
16
+ # destroy_all could create new instances
17
+ RestartableJob.delete_all
18
+ assert_equal 0, RestartableJob.count
19
+ end
20
+
21
+ after do
22
+ @job.delete if @job && !@job.new_record?
23
+ RestartableJob.delete_all
24
+ end
25
+
26
+ describe '#create!' do
27
+ it 'queues a new job' do
28
+ @job = RestartableJob.create!
29
+ assert @job.valid?
30
+ refute @job.new_record?
31
+ end
32
+ end
33
+
34
+ describe '#save!' do
35
+ it 'queues a new job' do
36
+ @job = RestartableJob.new
37
+ @job.save!
38
+ assert @job.valid?
39
+ refute @job.new_record?
40
+ end
41
+ end
42
+
43
+ describe '#abort!' do
44
+ it 'queues a new job on abort' do
45
+ @job = RestartableJob.create!
46
+ @job.abort!
47
+ assert_equal 2, RestartableJob.count
48
+ assert other = RestartableJob.where(id: {'$ne' => @job.id}).first
49
+ refute_equal @job.id, other.id
50
+ assert other.queued?
51
+ end
52
+
53
+ it 'does not queue a new job when expired' do
54
+ @job = RestartableJob.create!(expires_at: Time.now - 1.day)
55
+ assert @job.expired?
56
+ @job.abort!
57
+ assert_equal 1, RestartableJob.count
58
+ assert_equal nil, RestartableJob.where(id: {'$ne' => @job.id}).first
59
+ end
60
+ end
61
+
62
+ describe '#complete' do
63
+ it 'queues a new job when destroy_on_complete' do
64
+ assert_equal 0, RestartableJob.count
65
+ @job = RestartableJob.create!(destroy_on_complete: true)
66
+ @job.perform_now
67
+ assert @job.completed?, @job.attributes.ai
68
+ assert_equal 1, RestartableJob.count, RestartableJob.all.to_a.ai
69
+ end
70
+
71
+ it 'queues a new job when not destroy_on_complete' do
72
+ @job = RestartableJob.create!(destroy_on_complete: false)
73
+ @job.perform_now
74
+ assert @job.completed?
75
+ assert_equal 2, RestartableJob.count
76
+ end
77
+
78
+ it 'does not queue a new job when expired' do
79
+ @job = RestartableJob.create!(expires_at: Time.now - 1.day)
80
+ @job.perform_now
81
+ assert @job.expired?
82
+ assert @job.completed?
83
+ assert_equal 0, RestartableJob.count
84
+ end
85
+ end
86
+
87
+ describe '#pause' do
88
+ it 'does not enqueues a new job when paused' do
89
+ @job = RestartableJob.new
90
+ @job.start
91
+ @job.pause!
92
+ assert @job.paused?
93
+ assert_equal 1, RestartableJob.count
94
+ end
95
+ end
96
+
97
+ describe '#fail' do
98
+ it 'aborts from queued' do
99
+ @job = RestartableJob.new
100
+ assert @job.queued?
101
+ @job.fail
102
+ assert @job.aborted?
103
+ end
104
+
105
+ it 'aborts from running' do
106
+ @job = RestartableJob.new
107
+ @job.start
108
+ assert @job.running?
109
+ @job.fail
110
+ assert @job.aborted?
111
+ end
112
+
113
+ it 'aborts from paused' do
114
+ @job = RestartableJob.new
115
+ @job.start
116
+ @job.pause
117
+ assert @job.paused?
118
+ @job.fail
119
+ assert @job.aborted?
120
+ end
121
+
122
+ it 'does not queue a new job when expired' do
123
+ @job = RestartableJob.new(expires_at: Time.now - 1.day)
124
+ @job.start!
125
+ assert @job.running?
126
+ assert @job.expired?
127
+ assert_equal 1, RestartableJob.count
128
+ assert_equal nil, RestartableJob.where(id: {'$ne' => @job.id}).first
129
+ end
130
+ end
131
+
132
+ describe '#create_new_instance' do
133
+ it 'sets job back to queued state' do
134
+ @job = RestartableJob.create!(destroy_on_complete: true)
135
+ @job.perform_now
136
+ assert_equal 1, RestartableJob.count
137
+ assert job2 = RestartableJob.where(id: {'$ne' => @job.id}).first
138
+ assert job2.queued?, job2.attributes.ai
139
+ end
140
+
141
+ it 'excludes attributes related to running jobs' do
142
+ @job = RestartableJob.create!(destroy_on_complete: true, expires_at: Time.now + 1.day)
143
+ refute @job.expired?
144
+ @job.perform_now
145
+ assert_equal 1, RestartableJob.count
146
+ assert job2 = RestartableJob.where(id: {'$ne' => @job.id}).first
147
+ assert job2.queued?, job2.attributes.ai
148
+
149
+ # Copy across all attributes, except
150
+ @job.attributes.each_pair do |key, value|
151
+ next if RocketJob::Plugins::Restart::RESTART_EXCLUDES.include?(key)
152
+ assert_equal value, job2[key], "Attributes are supposed to be copied across. For #{key}"
153
+ end
154
+
155
+ assert_equal :queued, job2.state
156
+ assert job2.created_at
157
+ assert_equal nil, job2.started_at
158
+ assert_equal nil, job2.completed_at
159
+ assert_equal 0, job2.failure_count
160
+ assert_equal nil, job2.worker_name
161
+ assert_equal 0, job2.percent_complete
162
+ assert_equal nil, job2.exception
163
+ assert_equal({}, job2.result)
164
+ end
165
+
166
+ it 'copies run_at when it is in the future' do
167
+ @job = RestartableJob.create!(run_at: Time.now + 1.day, destroy_on_complete: true)
168
+ @job.perform_now
169
+ assert_equal 1, RestartableJob.count
170
+ assert job2 = RestartableJob.where(id: {'$ne' => @job.id}).first
171
+ assert job2.run_at, job2.attributes.ai
172
+ end
173
+
174
+ it 'does not copy run_at when it is in the past' do
175
+ @job = RestartableJob.create!(run_at: Time.now - 1.day, destroy_on_complete: true)
176
+ @job.perform_now
177
+ assert_equal 1, RestartableJob.count
178
+ assert job2 = RestartableJob.where(id: {'$ne' => @job.id}).first
179
+ assert_equal nil, job2.run_at
180
+ end
181
+ end
182
+
183
+ end
184
+ end
185
+ end
@@ -0,0 +1,94 @@
1
+ require_relative '../test_helper'
2
+
3
+ module Plugins
4
+ # Unit Test for RocketJob::Job
5
+ class SingletonTest < Minitest::Test
6
+
7
+ class SingletonJob < RocketJob::Job
8
+ include RocketJob::Plugins::Singleton
9
+
10
+ def perform
11
+ end
12
+ end
13
+
14
+ describe RocketJob::Plugins::Singleton do
15
+ before do
16
+ SingletonJob.delete_all
17
+ end
18
+
19
+ after do
20
+ @job.destroy if @job && !@job.new_record?
21
+ end
22
+
23
+ describe '#rocket_job_singleton_active?' do
24
+ it 'returns false if no jobs of this class are active' do
25
+ @job = SingletonJob.new
26
+ assert_equal false, @job.rocket_job_singleton_active?
27
+ end
28
+
29
+ it 'excludes self when queued from check' do
30
+ @job = SingletonJob.create
31
+ assert @job.queued?
32
+ assert_equal false, @job.rocket_job_singleton_active?
33
+ end
34
+
35
+ it 'excludes self when started from check' do
36
+ @job = SingletonJob.new
37
+ @job.start!
38
+ assert @job.running?
39
+ assert_equal false, @job.rocket_job_singleton_active?
40
+ end
41
+
42
+ it 'returns true when other jobs of this class are queued' do
43
+ @job = SingletonJob.create!
44
+ job2 = SingletonJob.new
45
+ assert_equal true, job2.rocket_job_singleton_active?
46
+ end
47
+
48
+ it 'returns true when other jobs of this class are running' do
49
+ @job = SingletonJob.new
50
+ @job.start!
51
+ job2 = SingletonJob.new
52
+ assert_equal true, job2.rocket_job_singleton_active?
53
+ end
54
+
55
+ it 'returns false when other jobs of this class are not active' do
56
+ @job = SingletonJob.new
57
+ @job.perform_now
58
+ @job.save!
59
+ assert @job.completed?
60
+ job2 = SingletonJob.new
61
+ assert_equal false, job2.rocket_job_singleton_active?
62
+ end
63
+ end
64
+
65
+ describe 'validation' do
66
+ it 'passes if another job is not active' do
67
+ @job = SingletonJob.new
68
+ @job.perform_now
69
+ @job.save!
70
+ job2 = SingletonJob.new
71
+ assert_equal true, job2.valid?
72
+ end
73
+
74
+ it 'fails if another job is active' do
75
+ @job = SingletonJob.new
76
+ @job.start!
77
+ job2 = SingletonJob.new
78
+ refute job2.valid?
79
+ assert_equal ['Another instance of Plugins::SingletonTest::SingletonJob is already queued or running'], job2.errors.messages[:state]
80
+ end
81
+
82
+ it 'passes if another job is active, but this job is not' do
83
+ @job = SingletonJob.new
84
+ @job.start!
85
+ job2 = SingletonJob.new
86
+ job2.abort
87
+ assert job2.valid?
88
+ job2.save!
89
+ end
90
+ end
91
+
92
+ end
93
+ end
94
+ end