misha-resque-cleaner 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,206 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/test_helper')
2
+ require 'time'
3
+ describe "ResqueCleaner" do
4
+ before do
5
+ Resque.redis.flushall
6
+
7
+ @worker = Resque::Worker.new(:jobs,:jobs2)
8
+
9
+ # 3 BadJob at 2009-03-13
10
+ create_and_process_jobs :jobs, @worker, 3, Time.parse('2009-03-13'), BadJob
11
+ # 2 BadJob by Jason at 2009-03-13
12
+ create_and_process_jobs :jobs2, @worker, 2, Time.parse('2009-03-13'), BadJob, "Jason"
13
+
14
+ # 1 BadJob by Johnson at 2009-03-13
15
+ create_and_process_jobs :jobs, @worker, 1, Time.parse('2009-03-13'), BadJob, "Johnson"
16
+
17
+ # 7 BadJob at 2009-11-13
18
+ create_and_process_jobs :jobs, @worker, 7, Time.parse('2009-11-13'), BadJobWithSyntaxError
19
+ # 7 BadJob by Freddy at 2009-11-13
20
+ create_and_process_jobs :jobs2, @worker, 7, Time.parse('2009-11-13'), BadJob, "Freddy"
21
+
22
+ # 11 BadJob at 2010-08-13
23
+ create_and_process_jobs :jobs, @worker, 11, Time.parse('2010-08-13'), BadJob
24
+ # 11 BadJob by Jason at 2010-08-13
25
+ create_and_process_jobs :jobs2, @worker, 11, Time.parse('2010-08-13'), BadJob, "Jason"
26
+
27
+ @cleaner = Resque::Plugins::ResqueCleaner.new
28
+ @cleaner.print_message = false
29
+ end
30
+
31
+ it "#select_by_regex returns only Jason jobs" do
32
+ ret = @cleaner.select_by_regex(/Jason/)
33
+ assert_equal 13, ret.size
34
+ end
35
+
36
+ it "#select_by_regex returns an empty array if passed a non-regex" do
37
+ ['string', nil, 13, Class.new].each do |non_regex|
38
+ ret = @cleaner.select_by_regex(nil)
39
+ assert_equal 0, ret.size
40
+ end
41
+ end
42
+
43
+ it "#select returns failure jobs" do
44
+ ret = @cleaner.select
45
+ assert_equal 42, ret.size
46
+ end
47
+
48
+ it "#select works with a limit" do
49
+ @cleaner.limiter.maximum = 10
50
+ ret = @cleaner.select
51
+
52
+ # only maximum number
53
+ assert_equal 10, ret.size
54
+
55
+ # lait one
56
+ assert_equal Time.parse(ret[0]['failed_at']), Time.parse('2010-08-13')
57
+ end
58
+
59
+ it "#select with a block returns failure jobs which the block evaluates true" do
60
+ ret = @cleaner.select {|job| job["payload"]["args"][0]=="Jason"}
61
+ assert_equal 13, ret.size
62
+ end
63
+
64
+ it "#clear deletes failure jobs" do
65
+ cleared = @cleaner.clear
66
+ assert_equal 42, cleared
67
+ assert_equal 0, @cleaner.select.size
68
+ end
69
+
70
+ it "#clear with a block deletes failure jobs which the block evaluates true" do
71
+ cleared = @cleaner.clear{|job| job["payload"]["args"][0]=="Jason"}
72
+ assert_equal 13, cleared
73
+ assert_equal 42-13, @cleaner.select.size
74
+ assert_equal 0, @cleaner.select{|job| job["payload"]["args"][0]=="Jason"}.size
75
+ end
76
+
77
+ it "#requeue retries failure jobs" do
78
+ assert_equal 0, queue_size(:jobs,:jobs2)
79
+ requeued = @cleaner.requeue
80
+ assert_equal 42, requeued
81
+ assert_equal 42, @cleaner.select.size # it doesn't clear jobs
82
+ assert_equal 42, queue_size(:jobs,:jobs2)
83
+ end
84
+
85
+ it "#requeue with a block retries failure jobs which the block evaluates true" do
86
+ requeued = @cleaner.requeue{|job| job["payload"]["args"][0]=="Jason"}
87
+ assert_equal 13, requeued
88
+ assert_equal 13, queue_size(:jobs,:jobs2)
89
+ end
90
+
91
+ it "#requeue with clear option requeues and deletes failure jobs" do
92
+ assert_equal 0, queue_size(:jobs,:jobs2)
93
+ requeued = @cleaner.requeue(true)
94
+ assert_equal 42, requeued
95
+ assert_equal 42, queue_size(:jobs,:jobs2)
96
+ assert_equal 0, @cleaner.select.size
97
+ end
98
+
99
+ it "#requeue with :queue option requeues the jobs to the queue" do
100
+ assert_equal 0, queue_size(:jobs,:jobs2,:retry)
101
+ requeued = @cleaner.requeue false, :queue => :retry
102
+ assert_equal 42, requeued
103
+ assert_equal 42, @cleaner.select.size # it doesn't clear jobs
104
+ assert_equal 0, queue_size(:jobs,:jobs2)
105
+ assert_equal 42, queue_size(:retry)
106
+ end
107
+
108
+ it "#clear_stale deletes failure jobs which is queued before the last x enqueued" do
109
+ @cleaner.limiter.maximum = 10
110
+ @cleaner.clear_stale
111
+ assert_equal 10, @cleaner.failure.count
112
+ assert_equal Time.parse(@cleaner.failure_jobs[0]['failed_at']), Time.parse('2010-08-13')
113
+ end
114
+
115
+ it "FailedJobEx module extends job and provides some useful methods" do
116
+ # before 2009-04-01
117
+ ret = @cleaner.select {|j| j.before?('2009-04-01')}
118
+ assert_equal 6, ret.size
119
+
120
+ # after 2010-01-01
121
+ ret = @cleaner.select {|j| j.after?('2010-01-01')}
122
+ assert_equal 22, ret.size
123
+
124
+ # filter by class
125
+ ret = @cleaner.select {|j| j.klass?(BadJobWithSyntaxError)}
126
+ assert_equal 7, ret.size
127
+
128
+ # filter by exception
129
+ ret = @cleaner.select {|j| j.exception?(SyntaxError)}
130
+ assert_equal 7, ret.size
131
+
132
+ # filter by queue
133
+ ret = @cleaner.select {|j| j.queue?(:jobs2)}
134
+ assert_equal 20, ret.size
135
+
136
+ # combination
137
+ ret = @cleaner.select {|j| j.queue?(:jobs2) && j.before?('2009-12-01')}
138
+ assert_equal 9, ret.size
139
+
140
+ # combination 2
141
+ ret = @cleaner.select {|j| j['payload']['args']==['Jason'] && j.queue?(:jobs2)}
142
+ assert_equal 13, ret.size
143
+
144
+ # retried?
145
+ requeued = @cleaner.requeue{|j| j["payload"]["args"][0]=="Johnson"}
146
+ ret = @cleaner.select {|j| j.retried?}
147
+ assert_equal 1, ret.size
148
+ end
149
+
150
+ it "#stats_by_date returns stats grouped by date" do
151
+ ret = @cleaner.stats_by_date
152
+ assert_equal 6, ret['2009/03/13']
153
+ assert_equal 14, ret['2009/11/13']
154
+
155
+ # with block
156
+ ret = @cleaner.stats_by_date{|j| j['payload']['args']==['Jason']}
157
+ assert_equal 2, ret['2009/03/13']
158
+ assert_equal nil, ret['2009/11/13']
159
+ assert_equal 11, ret['2010/08/13']
160
+ end
161
+
162
+ it "#stats_by_class returns stats grouped by class" do
163
+ ret = @cleaner.stats_by_class
164
+ assert_equal 35, ret['BadJob']
165
+ assert_equal 7, ret['BadJobWithSyntaxError']
166
+ end
167
+
168
+ it "#stats_by_class works with broken log" do
169
+ add_empty_payload_failure
170
+ ret = @cleaner.stats_by_class
171
+ assert_equal 1, ret['UNKNOWN']
172
+ end
173
+
174
+ it "#stats_by_exception returns stats grouped by exception" do
175
+ ret = @cleaner.stats_by_exception
176
+ assert_equal 35, ret['RuntimeError']
177
+ assert_equal 7, ret['SyntaxError']
178
+ end
179
+
180
+ it "#lock ensures that a new failure job doesn't affect in a limit mode" do
181
+ @cleaner.limiter.maximum = 23
182
+ @cleaner.limiter.lock do
183
+ first = @cleaner.select[0]
184
+ assert_equal "Freddy", first["payload"]["args"][0]
185
+
186
+ create_and_process_jobs :jobs, @worker, 30, Time.parse('2010-10-10'), BadJob, "Jack"
187
+
188
+ first = @cleaner.select[0]
189
+ assert_equal "Freddy", first["payload"]["args"][0]
190
+ end
191
+ first = @cleaner.select[0]
192
+ assert_equal "Jack", first["payload"]["args"][0]
193
+ end
194
+
195
+ it "allows you to configure limiter" do
196
+ c = Resque::Plugins::ResqueCleaner.new
197
+ refute_equal c.limiter.maximum, 10_000
198
+
199
+ module Resque::Plugins
200
+ ResqueCleaner::Limiter.default_maximum = 10_000
201
+ end
202
+
203
+ c = Resque::Plugins::ResqueCleaner.new
204
+ assert_equal c.limiter.maximum, 10_000
205
+ end
206
+ end
@@ -0,0 +1,66 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/test_helper')
2
+
3
+ require 'digest/sha1'
4
+ require 'json'
5
+ require 'rack/test'
6
+
7
+ class Minitest::Spec
8
+ include Rack::Test::Methods
9
+ def app
10
+ Resque::Server.new
11
+ end
12
+ end
13
+
14
+ def setup_some_failed_jobs
15
+ Resque.redis.flushall
16
+
17
+ @worker = Resque::Worker.new(:jobs,:jobs2)
18
+
19
+ create_and_process_jobs :jobs, @worker, 1, Time.now, BadJobWithSyntaxError, "great_args"
20
+
21
+ 10.times {|i|
22
+ create_and_process_jobs :jobs, @worker, 1, Time.now, BadJob, "test_#{i}"
23
+ }
24
+
25
+ @cleaner = Resque::Plugins::ResqueCleaner.new
26
+ @cleaner.print_message = false
27
+ end
28
+
29
+ describe "resque-web" do
30
+ before do
31
+ setup_some_failed_jobs
32
+ end
33
+
34
+ it "#cleaner should respond with success" do
35
+ get "/cleaner"
36
+ assert last_response.body.include?('BadJob')
37
+ assert last_response.body =~ /\bException\b/
38
+ end
39
+
40
+ it "#cleaner_list should respond with success" do
41
+ get "/cleaner_list"
42
+ assert last_response.ok?, last_response.errors
43
+ end
44
+
45
+ it '#cleaner_list shows the failed jobs' do
46
+ get "/cleaner_list"
47
+ assert last_response.body.include?('BadJob')
48
+ end
49
+
50
+ it "#cleaner_list shows the failed jobs when we use a select_by_regex" do
51
+ get "/cleaner_list", :regex => "BadJob*"
52
+ assert last_response.body.include?('"BadJobWithSyntaxError"')
53
+ assert last_response.body.include?('"BadJob"')
54
+ end
55
+
56
+
57
+ it '#cleaner_exec clears job' do
58
+ post "/cleaner_exec", :action => "clear", :sha1 => Digest::SHA1.hexdigest(@cleaner.select[0].to_json)
59
+ assert_equal 10, @cleaner.select.size
60
+ end
61
+ it "#cleaner_dump should respond with success" do
62
+ get "/cleaner_dump"
63
+ assert last_response.ok?, last_response.errors
64
+ end
65
+ end
66
+
@@ -0,0 +1,131 @@
1
+ # Mostly copied from Resque in order to have similar test environment.
2
+ # https://github.com/defunkt/resque/blob/master/test/test_helper.rb
3
+
4
+ dir = File.dirname(File.expand_path(__FILE__))
5
+ $LOAD_PATH.unshift dir + '/../lib'
6
+ $TESTING = true
7
+ require 'rubygems'
8
+ require 'minitest'
9
+ require 'minitest/spec'
10
+ require 'minitest/autorun'
11
+ require 'resque'
12
+ require 'timecop'
13
+
14
+ begin
15
+ require 'leftright'
16
+ rescue LoadError
17
+ end
18
+ require 'resque'
19
+ require 'resque_cleaner'
20
+
21
+ $TEST_PID = Process.pid
22
+
23
+ #
24
+ # make sure we can run redis
25
+ #
26
+
27
+ if !system("which redis-server")
28
+ puts '', "** can't find `redis-server` in your path"
29
+ puts "** try running `sudo rake install`"
30
+ abort ''
31
+ end
32
+
33
+
34
+ #
35
+ # start our own redis when the tests start,
36
+ # kill it when they end
37
+ #
38
+ MiniTest.after_run {
39
+ if Process.pid == $TEST_PID
40
+ processes = `ps -A -o pid,command | grep [r]edis-test`.split($/)
41
+ pids = processes.map { |process| process.split(" ")[0] }
42
+ puts "Killing test redis server..."
43
+ pids.each { |pid| Process.kill("TERM", pid.to_i) }
44
+ dump = "test/dump.rdb"
45
+ File.delete(dump) if File.exist?(dump)
46
+ end
47
+ }
48
+
49
+ puts "Starting redis for testing at localhost:9736..."
50
+ `redis-server #{dir}/redis-test.conf`
51
+ Resque.redis = 'localhost:9736'
52
+
53
+
54
+ ##
55
+ # Helper to perform job classes
56
+ #
57
+ module PerformJob
58
+ def perform_job(klass, *args)
59
+ resque_job = Resque::Job.new(:testqueue, 'class' => klass, 'args' => args)
60
+ resque_job.perform
61
+ end
62
+ end
63
+
64
+ #
65
+ # fixture classes
66
+ #
67
+
68
+ class SomeJob
69
+ def self.perform(repo_id, path)
70
+ end
71
+ end
72
+
73
+ class SomeIvarJob < SomeJob
74
+ @queue = :ivar
75
+ end
76
+
77
+ class SomeMethodJob < SomeJob
78
+ def self.queue
79
+ :method
80
+ end
81
+ end
82
+
83
+ class BadJob
84
+ def self.perform(name=nil)
85
+ msg = name ? "Bad job, #{name}" : "Bad job!"
86
+ raise msg
87
+ end
88
+ end
89
+
90
+ class GoodJob
91
+ def self.perform(name)
92
+ "Good job, #{name}"
93
+ end
94
+ end
95
+
96
+ class BadJobWithSyntaxError
97
+ def self.perform
98
+ raise SyntaxError, "Extra Bad job!"
99
+ end
100
+ end
101
+
102
+ #
103
+ # helper methods
104
+ #
105
+
106
+ def create_and_process_jobs(queue,worker,num,date,job,*args)
107
+ Timecop.freeze(date) do
108
+ num.times do
109
+ Resque::Job.create(queue, job, *args)
110
+ end
111
+ worker.work(0)
112
+ end
113
+ end
114
+
115
+ def queue_size(*queues)
116
+ queues.inject(0){|sum,queue| sum + Resque.size(queue).to_i}
117
+ end
118
+
119
+ def add_empty_payload_failure
120
+ data = {
121
+ :failed_at => Time.now.strftime("%Y/%m/%d %H:%M:%S %Z"),
122
+ :payload => nil,
123
+ :exception => "Resque::DirtyExit",
124
+ :error => "Resque::DirtyExit",
125
+ :backtrace => [],
126
+ :worker => "worker",
127
+ :queue => "queue"
128
+ }
129
+ data = Resque.encode(data)
130
+ Resque.redis.rpush(:failed, data)
131
+ end
metadata ADDED
@@ -0,0 +1,109 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: misha-resque-cleaner
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.0
5
+ platform: ruby
6
+ authors:
7
+ - Tatsuya Ono
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-12-22 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: resque
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: minitest
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '5.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '5.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rack-test
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 0.6.0
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 0.6.0
55
+ description: |2
56
+ resque-cleaner maintains the cleanliness of failed jobs on Resque.
57
+ email: ononoma@gmail.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files:
61
+ - LICENSE
62
+ - README.md
63
+ - CHANGELOG.md
64
+ files:
65
+ - CHANGELOG.md
66
+ - LICENSE
67
+ - README.md
68
+ - Rakefile
69
+ - lib/resque-cleaner.rb
70
+ - lib/resque_cleaner.rb
71
+ - lib/resque_cleaner/server.rb
72
+ - lib/resque_cleaner/server/public/cleaner.css
73
+ - lib/resque_cleaner/server/views/_limiter.erb
74
+ - lib/resque_cleaner/server/views/_paginate.erb
75
+ - lib/resque_cleaner/server/views/_stats.erb
76
+ - lib/resque_cleaner/server/views/cleaner.erb
77
+ - lib/resque_cleaner/server/views/cleaner_exec.erb
78
+ - lib/resque_cleaner/server/views/cleaner_list.erb
79
+ - test/redis-test.conf
80
+ - test/resque_cleaner_test.rb
81
+ - test/resque_web_test.rb
82
+ - test/test_helper.rb
83
+ homepage: https://github.com/ono/resque-cleaner
84
+ licenses:
85
+ - MIT
86
+ metadata: {}
87
+ post_install_message:
88
+ rdoc_options:
89
+ - "--charset=UTF-8"
90
+ require_paths:
91
+ - lib
92
+ required_ruby_version: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: 1.9.3
97
+ required_rubygems_version: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - ">="
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ requirements: []
103
+ rubyforge_project:
104
+ rubygems_version: 2.4.5
105
+ signing_key:
106
+ specification_version: 4
107
+ summary: Resque plugin cleaning up failed jobs.
108
+ test_files: []
109
+ has_rdoc: