sidetiq 0.3.7 → 0.4.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +1 -0
  3. data/CHANGELOG.md +16 -0
  4. data/LICENSE +2 -2
  5. data/README.md +9 -16
  6. data/Rakefile +2 -7
  7. data/examples/Procfile +2 -0
  8. data/examples/config.ru +15 -0
  9. data/examples/server.rb +17 -0
  10. data/examples/workers/failing.rb +13 -0
  11. data/examples/workers/simple.rb +10 -0
  12. data/lib/sidetiq/actor/clock.rb +31 -0
  13. data/lib/sidetiq/actor/handler.rb +7 -0
  14. data/lib/sidetiq/actor.rb +38 -0
  15. data/lib/sidetiq/api.rb +109 -0
  16. data/lib/sidetiq/clock.rb +3 -118
  17. data/lib/sidetiq/config.rb +8 -0
  18. data/lib/sidetiq/handler.rb +50 -0
  19. data/lib/sidetiq/lock/meta_data.rb +53 -0
  20. data/lib/sidetiq/lock/redis.rb +115 -0
  21. data/lib/sidetiq/lock/watcher.rb +41 -0
  22. data/lib/sidetiq/logging.rb +12 -0
  23. data/lib/sidetiq/middleware/history.rb +58 -0
  24. data/lib/sidetiq/schedulable.rb +6 -7
  25. data/lib/sidetiq/supervisor.rb +50 -0
  26. data/lib/sidetiq/version.rb +6 -3
  27. data/lib/sidetiq/views/_home_nav.erb +16 -0
  28. data/lib/sidetiq/views/_worker_nav.erb +22 -0
  29. data/lib/sidetiq/views/assets/styles.css +36 -0
  30. data/lib/sidetiq/views/history.erb +48 -0
  31. data/lib/sidetiq/views/locks.erb +48 -0
  32. data/lib/sidetiq/views/schedule.erb +59 -0
  33. data/lib/sidetiq/views/sidetiq.erb +39 -28
  34. data/lib/sidetiq/web.rb +36 -16
  35. data/lib/sidetiq.rb +34 -114
  36. data/sidetiq.gemspec +5 -2
  37. data/tasks/bundler.task +1 -0
  38. data/tasks/minitest.task +6 -0
  39. data/test/fixtures/optional_arguments_worker.rb +8 -0
  40. data/test/helper.rb +21 -6
  41. data/test/test_clock.rb +16 -24
  42. data/test/test_history.rb +60 -0
  43. data/test/test_lock_meta_data.rb +90 -0
  44. data/test/test_lock_redis.rb +63 -0
  45. data/test/test_version.rb +2 -1
  46. data/test/test_watcher.rb +24 -0
  47. data/test/test_web.rb +26 -2
  48. metadata +80 -12
  49. data/examples/simple.rb +0 -22
  50. data/lib/sidetiq/lock.rb +0 -63
  51. data/lib/sidetiq/middleware.rb +0 -23
  52. data/lib/sidetiq/views/sidetiq_details.erb +0 -49
  53. data/test/test_lock.rb +0 -30
  54. data/test/test_middleware.rb +0 -18
data/lib/sidetiq/web.rb CHANGED
@@ -5,38 +5,50 @@ module Sidetiq
5
5
  VIEWS = File.expand_path('views', File.dirname(__FILE__))
6
6
 
7
7
  def self.registered(app)
8
- app.helpers do
9
- def sidetiq_clock
10
- Sidetiq::Clock.instance
11
- end
8
+ app.get "/sidetiq" do
9
+ @schedules = Sidetiq.schedules
10
+ @time = Sidetiq.clock.gettime
11
+ erb File.read(File.join(VIEWS, 'sidetiq.erb'))
12
+ end
12
13
 
13
- def sidetiq_schedules
14
- sidetiq_clock.schedules
15
- end
14
+ app.get "/sidetiq/locks" do
15
+ @locks = Sidetiq::Lock::Redis.all.map(&:meta_data)
16
+
17
+ erb File.read(File.join(VIEWS, 'locks.erb'))
16
18
  end
17
19
 
18
- app.get "/sidetiq" do
19
- @schedules = sidetiq_schedules
20
- @time = sidetiq_clock.gettime
21
- erb File.read(File.join(VIEWS, 'sidetiq.erb'))
20
+ app.get "/sidetiq/:name/schedule" do
21
+ halt 404 unless (name = params[:name])
22
+
23
+ @time = Sidetiq.clock.gettime
24
+
25
+ @worker, @schedule = Sidetiq.schedules.select do |worker, _|
26
+ worker.name == name
27
+ end.flatten
28
+
29
+ erb File.read(File.join(VIEWS, 'schedule.erb'))
22
30
  end
23
31
 
24
- app.get "/sidetiq/:name" do
32
+ app.get "/sidetiq/:name/history" do
25
33
  halt 404 unless (name = params[:name])
26
34
 
27
- @time = sidetiq_clock.gettime
35
+ @time = Sidetiq.clock.gettime
28
36
 
29
- @worker, @schedule = sidetiq_schedules.select do |worker, _|
37
+ @worker, @schedule = Sidetiq.schedules.select do |worker, _|
30
38
  worker.name == name
31
39
  end.flatten
32
40
 
33
- erb File.read(File.join(VIEWS, 'sidetiq_details.erb'))
41
+ @history = Sidekiq.redis do |redis|
42
+ redis.lrange("sidetiq:#{@worker.name}:history", 0, -1)
43
+ end
44
+
45
+ erb File.read(File.join(VIEWS, 'history.erb'))
34
46
  end
35
47
 
36
48
  app.post "/sidetiq/:name/trigger" do
37
49
  halt 404 unless (name = params[:name])
38
50
 
39
- worker, _ = sidetiq_schedules.select do |w, _|
51
+ worker, _ = Sidetiq.schedules.select do |w, _|
40
52
  w.name == name
41
53
  end.flatten
42
54
 
@@ -44,6 +56,14 @@ module Sidetiq
44
56
 
45
57
  redirect "#{root_path}sidetiq"
46
58
  end
59
+
60
+ app.post "/sidetiq/:name/unlock" do
61
+ halt 404 unless (name = params[:name])
62
+
63
+ Sidetiq::Lock::Redis.new(name).unlock!
64
+
65
+ redirect "#{root_path}sidetiq/locks"
66
+ end
47
67
  end
48
68
  end
49
69
  end
data/lib/sidetiq.rb CHANGED
@@ -1,5 +1,4 @@
1
1
  # stdlib
2
- require 'monitor'
3
2
  require 'ostruct'
4
3
  require 'singleton'
5
4
  require 'socket'
@@ -7,134 +6,55 @@ require 'socket'
7
6
  # gems
8
7
  require 'ice_cube'
9
8
  require 'sidekiq'
9
+ require 'celluloid'
10
10
 
11
11
  # internal
12
12
  require 'sidetiq/config'
13
+ require 'sidetiq/logging'
14
+ require 'sidetiq/api'
13
15
  require 'sidetiq/clock'
14
- require 'sidetiq/lock'
15
- require 'sidetiq/middleware'
16
+ require 'sidetiq/handler'
17
+ require 'sidetiq/lock/meta_data'
18
+ require 'sidetiq/lock/redis'
16
19
  require 'sidetiq/schedule'
17
20
  require 'sidetiq/schedulable'
18
21
  require 'sidetiq/version'
19
22
 
23
+ # middleware
24
+ require 'sidetiq/middleware/history'
25
+
26
+ # actor topology
27
+ require 'sidetiq/actor'
28
+ require 'sidetiq/actor/clock'
29
+ require 'sidetiq/actor/handler'
30
+ require 'sidetiq/supervisor'
31
+
20
32
  # The Sidetiq namespace.
21
33
  module Sidetiq
34
+ include Sidetiq::API
35
+
36
+ # Expose all instance methods as singleton methods.
37
+ extend self
38
+
22
39
  class << self
23
40
  # Public: Setter for the Sidetiq logger.
24
41
  attr_writer :logger
42
+ end
25
43
 
26
- # Public: Reader for the Sidetiq logger.
27
- #
28
- # Defaults to `Sidekiq.logger`.
29
- def logger
30
- @logger ||= Sidekiq.logger
31
- end
32
-
33
- # Public: Returns an Array of workers including Sidetiq::Schedulable.
34
- def workers
35
- schedules.keys
36
- end
37
-
38
- # Public: Returns a Hash of Sidetiq::Schedule instances.
39
- def schedules
40
- Clock.mon_synchronize do
41
- Clock.schedules.dup
42
- end
43
- end
44
-
45
- # Public: Currently scheduled recurring jobs.
46
- #
47
- # worker - A Sidekiq::Worker class or String of the class name (optional)
48
- # block - An optional block that can be given to which each
49
- # Sidekiq::SortedEntry instance corresponding to a scheduled job will
50
- # be yielded.
51
- #
52
- # Examples
53
- #
54
- # Sidetiq.scheduled
55
- # # => [#<Sidekiq::SortedEntry>, ...]
56
- #
57
- # Sidetiq.scheduled(MyWorker)
58
- # # => [#<Sidekiq::SortedEntry>, ...]
59
- #
60
- # Sidetiq.scheduled("MyWorker")
61
- # # => [#<Sidekiq::SortedEntry>, ...]
62
- #
63
- # Sidetiq.scheduled do |job|
64
- # # do stuff ...
65
- # end
66
- # # => [#<Sidekiq::SortedEntry>, ...]
67
- #
68
- # Sidetiq.scheduled(MyWorker) do |job|
69
- # # do stuff ...
70
- # end
71
- # # => [#<Sidekiq::SortedEntry>, ...]
72
- #
73
- # Sidetiq.scheduled("MyWorker") do |job|
74
- # # do stuff ...
75
- # end
76
- # # => [#<Sidekiq::SortedEntry>, ...]
77
- #
78
- # Yields each Sidekiq::SortedEntry instance.
79
- # Returns an Array of Sidekiq::SortedEntry objects.
80
- def scheduled(worker = nil, &block)
81
- filter_set(Sidekiq::ScheduledSet.new, worker, &block)
82
- end
83
-
84
- # Public: Recurring jobs currently scheduled for retries.
85
- #
86
- # worker - A Sidekiq::Worker class or String of the class name (optional)
87
- # block - An optional block that can be given to which each
88
- # Sidekiq::SortedEntry instance corresponding to a scheduled job will
89
- # be yielded.
90
- #
91
- # Examples
92
- #
93
- # Sidetiq.retries
94
- # # => [#<Sidekiq::SortedEntry>, ...]
95
- #
96
- # Sidetiq.retries(MyWorker)
97
- # # => [#<Sidekiq::SortedEntry>, ...]
98
- #
99
- # Sidetiq.retries("MyWorker")
100
- # # => [#<Sidekiq::SortedEntry>, ...]
101
- #
102
- # Sidetiq.retries do |job|
103
- # # do stuff ...
104
- # end
105
- # # => [#<Sidekiq::SortedEntry>, ...]
106
- #
107
- # Sidetiq.retries(MyWorker) do |job|
108
- # # do stuff ...
109
- # end
110
- # # => [#<Sidekiq::SortedEntry>, ...]
111
- #
112
- # Sidetiq.retries("MyWorker") do |job|
113
- # # do stuff ...
114
- # end
115
- # # => [#<Sidekiq::SortedEntry>, ...]
116
- #
117
- # Yields each Sidekiq::SortedEntry instance.
118
- # Returns an Array of Sidekiq::SortedEntry objects.
119
- def retries(worker = nil, &block)
120
- filter_set(Sidekiq::RetrySet.new, worker, &block)
121
- end
122
-
123
- private
124
-
125
- def filter_set(set, worker, &block)
126
- worker = worker.constantize if worker.kind_of?(String)
127
-
128
- jobs = set.select do |job|
129
- klass = job.klass.constantize
130
- ret = klass.include?(Schedulable)
131
- ret = ret && klass == worker if worker
132
- ret
133
- end
44
+ # Public: Reader for the Sidetiq logger.
45
+ #
46
+ # Defaults to `Sidekiq.logger`.
47
+ def logger
48
+ @logger ||= Sidekiq.logger
49
+ end
134
50
 
135
- jobs.each(&block) if block_given?
51
+ # Public: Returns the Sidetiq::Clock actor.
52
+ def clock
53
+ Sidetiq::Supervisor.clock
54
+ end
136
55
 
137
- jobs
138
- end
56
+ # Public: Returns a Sidetiq::Handler worker.
57
+ def handler
58
+ Sidetiq::Supervisor.handler
139
59
  end
140
60
  end
data/sidetiq.gemspec CHANGED
@@ -19,13 +19,16 @@ Gem::Specification.new do |gem|
19
19
  gem.require_paths = ["lib"]
20
20
  gem.extensions = []
21
21
 
22
- gem.add_dependency 'sidekiq', '~> 2.14.0'
23
- gem.add_dependency 'ice_cube', '~> 0.11.0'
22
+ gem.add_dependency 'sidekiq', '~> 2.14.0'
23
+ gem.add_dependency 'celluloid', '>= 0.14.1'
24
+ gem.add_dependency 'ice_cube', '~> 0.11.0'
25
+ gem.add_dependency 'json'
24
26
 
25
27
  gem.add_development_dependency 'rake'
26
28
  gem.add_development_dependency 'sinatra'
27
29
  gem.add_development_dependency 'mocha'
28
30
  gem.add_development_dependency 'rack-test'
31
+ gem.add_development_dependency 'minitest', '~> 5.0.7'
29
32
 
30
33
  if RUBY_PLATFORM != "java"
31
34
  gem.add_development_dependency 'coveralls'
@@ -0,0 +1 @@
1
+ require 'bundler/gem_tasks'
@@ -0,0 +1,6 @@
1
+ require 'rake/testtask'
2
+
3
+ Rake::TestTask.new do |t|
4
+ t.pattern = 'test/**/test_*.rb'
5
+ end
6
+
@@ -0,0 +1,8 @@
1
+ class OptionalArgumentWorker
2
+ include Sidekiq::Worker
3
+ include Sidetiq::Schedulable
4
+
5
+ def perform(last_tick = nil)
6
+ end
7
+ end
8
+
data/test/helper.rb CHANGED
@@ -3,15 +3,26 @@ if RUBY_PLATFORM != "java"
3
3
  Coveralls.wear!
4
4
  end
5
5
 
6
- require 'minitest/autorun'
7
- require 'mocha/setup'
8
- require 'rack/test'
9
-
10
6
  require 'sidekiq'
11
7
  require 'sidekiq/testing'
12
8
 
9
+ require 'minitest'
10
+ require 'mocha/setup'
11
+ require 'rack/test'
12
+
13
13
  require 'sidetiq'
14
14
  require 'sidetiq/web'
15
+ require 'sidetiq/lock/watcher'
16
+
17
+ class Sidetiq::Supervisor
18
+ def self.clock
19
+ @clock ||= Sidetiq::Clock.new
20
+ end
21
+
22
+ def self.handler
23
+ Sidetiq::Handler.new
24
+ end
25
+ end
15
26
 
16
27
  # Keep the test output clean.
17
28
  Sidetiq.logger = Logger.new(nil)
@@ -34,13 +45,13 @@ class Sidekiq::Client
34
45
  end
35
46
  end
36
47
 
37
- class Sidetiq::TestCase < MiniTest::Unit::TestCase
48
+ class Sidetiq::TestCase < MiniTest::Test
38
49
  def setup
39
50
  Sidekiq.redis { |r| r.flushall }
40
51
  end
41
52
 
42
53
  def clock
43
- @clock ||= Sidetiq::Clock.instance
54
+ Sidetiq.clock
44
55
  end
45
56
 
46
57
  # Blatantly stolen from Sidekiq's test suite.
@@ -55,3 +66,7 @@ class Sidetiq::TestCase < MiniTest::Unit::TestCase
55
66
  end
56
67
  end
57
68
 
69
+ # Override Celluloid's at_exit hook manually.
70
+ at_exit {
71
+ exit Minitest.run(ARGV) || false
72
+ }
data/test/test_clock.rb CHANGED
@@ -1,30 +1,6 @@
1
1
  require_relative 'helper'
2
2
 
3
3
  class TestClock < Sidetiq::TestCase
4
- def test_delegates_to_instance
5
- Sidetiq::Clock.instance.expects(:foo).once
6
- Sidetiq::Clock.foo
7
- end
8
-
9
- def test_start_stop
10
- refute clock.ticking?
11
- assert_nil clock.thread
12
-
13
- clock.start!
14
- Thread.pass
15
- sleep 0.01
16
-
17
- assert clock.ticking?
18
- assert_kind_of Thread, clock.thread
19
-
20
- clock.stop!
21
- Thread.pass
22
- sleep 0.01
23
-
24
- refute clock.ticking?
25
- refute clock.thread.alive?
26
- end
27
-
28
4
  def test_gettime_seconds
29
5
  assert_equal clock.gettime.tv_sec, Time.now.tv_sec
30
6
  end
@@ -118,6 +94,22 @@ class TestClock < Sidetiq::TestCase
118
94
  clock.tick
119
95
  end
120
96
 
97
+ def test_enqueues_jobs_with_last_run_timestamp_if_optional_argument
98
+ schedule = Sidetiq::Schedule.new
99
+ schedule.hourly
100
+
101
+ time = Time.local(2011, 1, 1, 1, 30)
102
+
103
+ clock.stubs(:gettime).returns(time, time + 3600)
104
+ clock.stubs(:schedules).returns(OptionalArgumentWorker => schedule)
105
+
106
+ expected_first_tick = time + 1800
107
+
108
+ OptionalArgumentWorker.expects(:perform_at)
109
+ .with(expected_first_tick, -1).once
110
+ clock.tick
111
+ end
112
+
121
113
  def test_enqueues_jobs_correctly_for_splat_args_perform_methods
122
114
  schedule = Sidetiq::Schedule.new
123
115
  schedule.hourly
@@ -0,0 +1,60 @@
1
+ require_relative 'helper'
2
+
3
+ class TestHistory < Sidetiq::TestCase
4
+ class HistoryWorker
5
+ include Sidekiq::Worker
6
+ include Sidetiq::Schedulable
7
+ end
8
+
9
+ def test_success
10
+ middlewared do; end
11
+
12
+ entry = Sidekiq.redis do |redis|
13
+ redis.lrange('sidetiq:TestHistory::HistoryWorker:history', 0, -1)
14
+ end
15
+
16
+ actual = JSON.parse(entry[0], symbolize_names: true)
17
+
18
+ assert_equal 'success', actual[:status]
19
+
20
+ assert_empty actual[:error]
21
+ assert_empty actual[:backtrace]
22
+ assert_empty actual[:exception]
23
+
24
+ refute_empty actual[:node]
25
+ refute_empty actual[:timestamp]
26
+ end
27
+
28
+ def test_failure
29
+ begin
30
+ middlewared do
31
+ raise StandardError.new("failed")
32
+ end
33
+ rescue
34
+ end
35
+
36
+ entry = Sidekiq.redis do |redis|
37
+ redis.lrange('sidetiq:TestHistory::HistoryWorker:history', 0, -1)
38
+ end
39
+
40
+ actual = JSON.parse(entry[0], symbolize_names: true)
41
+
42
+ assert_equal 'failure', actual[:status]
43
+
44
+ assert_equal "failed", actual[:error]
45
+ assert_equal "StandardError", actual[:exception]
46
+ refute_empty actual[:backtrace]
47
+
48
+ refute_empty actual[:node]
49
+ refute_empty actual[:timestamp]
50
+ end
51
+
52
+ def middlewared
53
+ middleware = Sidetiq::Middleware::History.new
54
+
55
+ middleware.call(HistoryWorker.new, {}, 'default') do
56
+ yield
57
+ end
58
+ end
59
+ end
60
+
@@ -0,0 +1,90 @@
1
+ require_relative 'helper'
2
+
3
+ class TestLockMetaData < Sidetiq::TestCase
4
+ def new_without_params
5
+ md = Sidetiq::Lock::MetaData.new
6
+
7
+ assert_nil md.owner
8
+ assert_nil md.timestamp
9
+ assert_nil md.key
10
+ end
11
+
12
+ def new_with_empty_hash
13
+ md = Sidetiq::Lock::MetaData.new({})
14
+
15
+ assert_nil md.owner
16
+ assert_nil md.timestamp
17
+ assert_nil md.key
18
+ end
19
+
20
+ def test_from_json
21
+ json = { timestamp: 42, owner: "me", key: "foobar" }.to_json
22
+ md = Sidetiq::Lock::MetaData.from_json(json)
23
+
24
+ assert_equal 42, md.timestamp
25
+ assert_equal "me", md.owner
26
+ assert_equal "foobar", md.key
27
+ end
28
+
29
+ def test_from_json_with_empty_string_json
30
+ md = Sidetiq::Lock::MetaData.from_json(nil)
31
+
32
+ assert_nil md.owner
33
+ assert_nil md.timestamp
34
+ assert_nil md.key
35
+ end
36
+
37
+ def test_from_json_with_nil_json
38
+ md = Sidetiq::Lock::MetaData.from_json("")
39
+
40
+ assert_nil md.owner
41
+ assert_nil md.timestamp
42
+ assert_nil md.key
43
+ end
44
+
45
+ def test_pttl
46
+ lock = Sidetiq::Lock::Redis.new("foobar", 1000000)
47
+ md = Sidekiq.redis do |r|
48
+ lock.lock
49
+ Sidetiq::Lock::MetaData.from_json(r.get(lock.key))
50
+ end
51
+
52
+ # Allow 10 ms.
53
+ assert md.pttl <= 1000000
54
+ assert md.pttl > 999990
55
+ end
56
+
57
+ def test_from_json_with_malformed_json
58
+ Sidetiq::Lock::MetaData.expects(:handle_exception).once
59
+
60
+ md = Sidetiq::Lock::MetaData.from_json('invalid')
61
+
62
+ assert_nil md.owner
63
+ assert_nil md.timestamp
64
+ assert_nil md.key
65
+ end
66
+
67
+ def test_for_new_lock
68
+ md = Sidetiq::Lock::MetaData.for_new_lock("baz")
69
+
70
+ assert_equal Sidetiq::Lock::MetaData::OWNER, md.owner
71
+ assert_equal "baz", md.key
72
+
73
+ assert md.timestamp > 0
74
+ assert md.timestamp <= Time.now.to_f
75
+ end
76
+
77
+ def test_to_json
78
+ hash = { timestamp: 42, owner: "me", key: "foobar" }
79
+ md = Sidetiq::Lock::MetaData.new(hash)
80
+
81
+ assert_equal hash, JSON.parse(md.to_json, symbolize_names: true)
82
+ end
83
+
84
+ def test_to_s
85
+ md = Sidetiq::Lock::MetaData.new(timestamp: 42, owner: "me", key: "foobar")
86
+
87
+ assert_equal "Sidetiq::Lock on foobar set at 42 by me", md.to_s
88
+ end
89
+ end
90
+
@@ -0,0 +1,63 @@
1
+ require_relative 'helper'
2
+
3
+ class TestLockRedis < Sidetiq::TestCase
4
+ def test_locking
5
+ lock_name = SecureRandom.hex(8)
6
+ key = SecureRandom.hex(8)
7
+
8
+ Sidekiq.redis do |redis|
9
+ redis.set(key, 0)
10
+
11
+ 5.times.map do
12
+ Thread.start do
13
+ locked(lock_name) do |r|
14
+ sleep 0.1
15
+ r.incr(key)
16
+ end
17
+ end
18
+ end.each(&:join)
19
+
20
+ assert_equal "1", redis.get(key)
21
+ end
22
+ end
23
+
24
+ def test_all
25
+ Sidekiq.redis do |redis|
26
+ redis.set("sidetiq:Foobar:lock", 1)
27
+ end
28
+
29
+ locks = Sidetiq::Lock::Redis.all
30
+
31
+ assert_equal "sidetiq:Foobar:lock", locks.first.key
32
+ end
33
+
34
+ def test_unlock!
35
+ Sidekiq.redis do |redis|
36
+ redis.set("sidetiq:Foobar:lock", 1)
37
+
38
+ Sidetiq::Lock::Redis.new("Foobar").unlock!
39
+
40
+ assert_nil redis.get("sidetiq:Foobar:lock")
41
+ end
42
+ end
43
+
44
+ def test_lock_sets_correct_meta_data
45
+ key = SecureRandom.hex(8)
46
+ internal_key = "sidetiq:#{key}:lock"
47
+
48
+ locked(key) do |redis|
49
+ json = redis.get(internal_key)
50
+ md = Sidetiq::Lock::MetaData.from_json(json)
51
+
52
+ assert_equal Sidetiq::Lock::MetaData::OWNER, md.owner
53
+ assert_equal internal_key, md.key
54
+ end
55
+ end
56
+
57
+ def locked(lock_name)
58
+ Sidetiq::Lock::Redis.new(lock_name).synchronize do |redis|
59
+ yield redis
60
+ end
61
+ end
62
+ end
63
+
data/test/test_version.rb CHANGED
@@ -15,7 +15,8 @@ class TestVersion < Sidetiq::TestCase
15
15
 
16
16
  def test_string
17
17
  assert_equal Sidetiq::VERSION::STRING, [Sidetiq::VERSION::MAJOR,
18
- Sidetiq::VERSION::MINOR, Sidetiq::VERSION::PATCH].compact.join('.')
18
+ Sidetiq::VERSION::MINOR, Sidetiq::VERSION::PATCH,
19
+ Sidetiq::VERSION::SUFFIX].compact.join('.')
19
20
  end
20
21
  end
21
22
 
@@ -0,0 +1,24 @@
1
+ require_relative 'helper'
2
+
3
+ class TestWatcher < Sidetiq::TestCase
4
+ def setup
5
+ Sidetiq.config.lock.watcher.remove_lock = true
6
+ Sidetiq.config.lock.watcher.notify = true
7
+
8
+ @worker = Sidetiq::Lock::Watcher.new
9
+ end
10
+
11
+ def test_perform
12
+ Sidetiq::Lock::Redis.new("foobar", 1000000).lock
13
+
14
+ assert_equal 1, Sidetiq::Lock::Redis.all.length
15
+
16
+ @worker.expects(:handle_exception).once
17
+
18
+ @worker.perform
19
+
20
+ assert_equal 0, Sidetiq::Lock::Redis.all.length
21
+ end
22
+ end
23
+
24
+
data/test/test_web.rb CHANGED
@@ -33,8 +33,18 @@ class TestWeb < Sidetiq::TestCase
33
33
  end
34
34
  end
35
35
 
36
- def test_details_page
37
- get "/sidetiq/ScheduledWorker"
36
+ def test_locks_page
37
+ get "/sidetiq/locks"
38
+ assert_equal 200, last_response.status
39
+ end
40
+
41
+ def test_history_page
42
+ get "/sidetiq/ScheduledWorker/history"
43
+ assert_equal 200, last_response.status
44
+ end
45
+
46
+ def test_schedule_page
47
+ get "/sidetiq/ScheduledWorker/schedule"
38
48
  assert_equal 200, last_response.status
39
49
  schedule = clock.schedules[ScheduledWorker]
40
50
 
@@ -57,5 +67,19 @@ class TestWeb < Sidetiq::TestCase
57
67
  assert_equal "http://#{host}/sidetiq", last_response.location
58
68
  assert_equal 1, ScheduledWorker.jobs.size
59
69
  end
70
+
71
+ def test_unlock
72
+ Sidekiq.redis do |redis|
73
+ redis.set("sidetiq:Foo:lock", 1)
74
+ end
75
+
76
+ post "/sidetiq/Foo/unlock"
77
+ assert_equal 302, last_response.status
78
+ assert_equal "http://#{host}/sidetiq/locks", last_response.location
79
+
80
+ Sidekiq.redis do |redis|
81
+ assert_nil redis.get("sidetiq:Foo:lock")
82
+ end
83
+ end
60
84
  end
61
85