perfectsched 0.8.10 → 0.8.11

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.
@@ -0,0 +1,23 @@
1
+ require 'spec_helper'
2
+
3
+ describe Runner do
4
+ let (:client){ double('client') }
5
+ let (:task){ double('task', client: client) }
6
+ let (:runner){ Runner.new(task) }
7
+ describe '.new' do
8
+ subject { runner }
9
+ it { is_expected.to be_an_instance_of(Runner) }
10
+ end
11
+ describe '#task' do
12
+ subject { runner.task }
13
+ it { is_expected.to eq task }
14
+ end
15
+ describe '#schedules' do
16
+ subject { runner.schedules }
17
+ it do
18
+ schedule_collection = double('schedule_collection')
19
+ expect(ScheduleCollection).to receive(:new).with(client).and_return(schedule_collection)
20
+ is_expected.to eq schedule_collection
21
+ end
22
+ end
23
+ end
@@ -9,7 +9,7 @@ describe ScheduleCollection do
9
9
  end
10
10
 
11
11
  it 'is a ScheduleCollection' do
12
- sc.class.should == PerfectSched::ScheduleCollection
12
+ expect(sc.class).to eq(PerfectSched::ScheduleCollection)
13
13
  end
14
14
 
15
15
  it 'succeess add' do
@@ -19,9 +19,9 @@ describe ScheduleCollection do
19
19
  it 'fail duplicated add' do
20
20
  sc.add('sched01', 't01', {:cron=>'* * * * *', :timezone=>'UTC'})
21
21
 
22
- lambda {
22
+ expect {
23
23
  sc.add('sched01', 't01', {:cron=>'* * * * *', :timezone=>'UTC'})
24
- }.should raise_error AlreadyExistsError
24
+ }.to raise_error AlreadyExistsError
25
25
 
26
26
  sc['sched01'].delete!
27
27
 
@@ -34,25 +34,25 @@ describe ScheduleCollection do
34
34
  s01 = sc.add('sched01', 't01', :cron=>"* * * * *", :data=>{'k'=>1}, :next_time=>time)
35
35
 
36
36
  t01 = sc.poll(:alive_time=>120, :now=>time)
37
- t01.key.should == 'sched01'
38
- t01.type.should == 't01'
39
- t01.cron.should == "* * * * *"
40
- t01.delay.should == 0
41
- t01.data.should == {'k'=>1}
42
- t01.scheduled_time.should == time
37
+ expect(t01.key).to eq('sched01')
38
+ expect(t01.type).to eq('t01')
39
+ expect(t01.cron).to eq("* * * * *")
40
+ expect(t01.delay).to eq(0)
41
+ expect(t01.data).to eq({'k'=>1})
42
+ expect(t01.scheduled_time).to eq(time)
43
43
 
44
44
  t02 = sc.poll(:alive_time=>120, :now=>time+60)
45
- t02.should == nil
45
+ expect(t02).to eq(nil)
46
46
 
47
47
  t01.finish!
48
48
 
49
49
  t04 = sc.poll(:alive_time=>120, :now=>time+60)
50
- t04.key.should == 'sched01'
51
- t01.type.should == 't01'
52
- t04.cron.should == "* * * * *"
53
- t04.delay.should == 0
54
- t04.data.should == {'k'=>1}
55
- t04.scheduled_time.should == time+60
50
+ expect(t04.key).to eq('sched01')
51
+ expect(t01.type).to eq('t01')
52
+ expect(t04.cron).to eq("* * * * *")
53
+ expect(t04.delay).to eq(0)
54
+ expect(t04.data).to eq({'k'=>1})
55
+ expect(t04.scheduled_time).to eq(time+60)
56
56
  end
57
57
 
58
58
  it 'timezone' do
@@ -67,16 +67,16 @@ describe ScheduleCollection do
67
67
  #s02.key.should == 'sched02'
68
68
 
69
69
  t01 = sc.poll(:alive_time=>86400, :now=>time)
70
- t01.class.should == Task
71
- t01.key.should == 'sched01'
72
- t01.type.should == 't01'
73
- t01.scheduled_time.should == time
70
+ expect(t01.class).to eq(Task)
71
+ expect(t01.key).to eq('sched01')
72
+ expect(t01.type).to eq('t01')
73
+ expect(t01.scheduled_time).to eq(time)
74
74
 
75
75
  t02 = sc.poll(:alive_time=>86400, :now=>time+54000)
76
- t02.class.should == Task
77
- t02.key.should == 'sched02'
78
- t02.type.should == 't01'
79
- t02.scheduled_time.should == time+54000
76
+ expect(t02.class).to eq(Task)
77
+ expect(t02.key).to eq('sched02')
78
+ expect(t02.type).to eq('t01')
79
+ expect(t02.scheduled_time).to eq(time+54000)
80
80
  end
81
81
 
82
82
  it 'delay' do
@@ -85,43 +85,43 @@ describe ScheduleCollection do
85
85
  s01 = sc.add('sched01', 't01', :cron=>"0 * * * *", :delay=>30, :next_time=>time, :timezone=>'UTC')
86
86
 
87
87
  t01 = sc.poll(:alive_time=>86400, :now=>time)
88
- t01.should == nil
88
+ expect(t01).to eq(nil)
89
89
 
90
90
  t02 = sc.poll(:alive_time=>86400, :now=>time+30)
91
- t02.class.should == Task
92
- t02.key.should == 'sched01'
93
- t02.type.should == 't01'
94
- t02.scheduled_time.should == time
95
- t02.delay.should == 30
91
+ expect(t02.class).to eq(Task)
92
+ expect(t02.key).to eq('sched01')
93
+ expect(t02.type).to eq('t01')
94
+ expect(t02.scheduled_time).to eq(time)
95
+ expect(t02.delay).to eq(30)
96
96
 
97
97
  t02.finish!
98
98
 
99
99
  t03 = sc.poll(:alive_time=>86400, :now=>time+3600)
100
- t03.should == nil
100
+ expect(t03).to eq(nil)
101
101
 
102
102
  t04 = sc.poll(:alive_time=>86400, :now=>time+3630)
103
- t04.class.should == Task
104
- t04.key.should == 'sched01'
105
- t04.type.should == 't01'
106
- t04.scheduled_time.should == time+3600
107
- t04.delay.should == 30
103
+ expect(t04.class).to eq(Task)
104
+ expect(t04.key).to eq('sched01')
105
+ expect(t04.type).to eq('t01')
106
+ expect(t04.scheduled_time).to eq(time+3600)
107
+ expect(t04.delay).to eq(30)
108
108
  end
109
109
 
110
110
  it 'invalid cron format' do
111
- lambda {
111
+ expect {
112
112
  sc.add('sched01', 't01', :cron=>'???')
113
- }.should raise_error ArgumentError
113
+ }.to raise_error StandardError
114
114
 
115
- lambda {
115
+ expect {
116
116
  sc.add('sched01', 't01', :cron=>'* * * * * *')
117
- }.should raise_error ArgumentError
117
+ }.to raise_error StandardError
118
118
  end
119
119
 
120
120
  it 'fail duplicated add' do
121
121
  sc.add('sched01', 't01', :cron=>"0 * * * *")
122
- lambda {
122
+ expect {
123
123
  sc.add('sched01', 't01', :cron=>"0 * * * *")
124
- }.should raise_error AlreadyExistsError
124
+ }.to raise_error AlreadyExistsError
125
125
 
126
126
  sc['sched01'].delete!
127
127
 
@@ -142,31 +142,31 @@ describe ScheduleCollection do
142
142
  a.sort_by! {|s| s.key }
143
143
 
144
144
  s01 = a.shift
145
- s01.class.should == ScheduleWithMetadata
146
- s01.key.should == 'sched01'
147
- s01.type.should == 't01'
148
- s01.cron.should == '0 * * * *'
149
- s01.delay.should == 1
150
- s01.next_time.should == time
151
- s01.next_run_time.should == time+1
145
+ expect(s01.class).to eq(ScheduleWithMetadata)
146
+ expect(s01.key).to eq('sched01')
147
+ expect(s01.type).to eq('t01')
148
+ expect(s01.cron).to eq('0 * * * *')
149
+ expect(s01.delay).to eq(1)
150
+ expect(s01.next_time).to eq(time)
151
+ expect(s01.next_run_time).to eq(time+1)
152
152
 
153
153
  s02 = a.shift
154
- s02.class.should == ScheduleWithMetadata
155
- s02.key.should == 'sched02'
156
- s02.type.should == 't02'
157
- s02.cron.should == '0 * * * *'
158
- s02.delay.should == 2
159
- s02.next_time.should == time
160
- s02.next_run_time.should == time+2
154
+ expect(s02.class).to eq(ScheduleWithMetadata)
155
+ expect(s02.key).to eq('sched02')
156
+ expect(s02.type).to eq('t02')
157
+ expect(s02.cron).to eq('0 * * * *')
158
+ expect(s02.delay).to eq(2)
159
+ expect(s02.next_time).to eq(time)
160
+ expect(s02.next_run_time).to eq(time+2)
161
161
 
162
162
  s03 = a.shift
163
- s03.class.should == ScheduleWithMetadata
164
- s03.key.should == 'sched03'
165
- s03.type.should == 't03'
166
- s03.cron.should == '0 * * * *'
167
- s03.delay.should == 3
168
- s03.next_time.should == time
169
- s03.next_run_time.should == time+3600
163
+ expect(s03.class).to eq(ScheduleWithMetadata)
164
+ expect(s03.key).to eq('sched03')
165
+ expect(s03.type).to eq('t03')
166
+ expect(s03.cron).to eq('0 * * * *')
167
+ expect(s03.delay).to eq(3)
168
+ expect(s03.next_time).to eq(time)
169
+ expect(s03.next_run_time).to eq(time+3600)
170
170
  end
171
171
  end
172
172
 
@@ -0,0 +1,66 @@
1
+ require 'spec_helper'
2
+
3
+ describe Schedule do
4
+ let (:schedule){ Schedule.new(client, key) }
5
+ let (:client){ double('client') }
6
+ let (:key){ double('key') }
7
+ let (:ret){ double('ret') }
8
+ let (:options){ double('options') }
9
+ describe '.new' do
10
+ subject { schedule }
11
+ it { is_expected.to be_an_instance_of(Schedule) }
12
+ end
13
+ describe '#key' do
14
+ subject { schedule.key }
15
+ it { is_expected.to eq key }
16
+ end
17
+ describe '#delete!' do
18
+ subject { schedule.delete!(options) }
19
+ it do
20
+ expect(client).to receive(:delete).with(key, options).and_return(ret)
21
+ is_expected.to eq ret
22
+ end
23
+ end
24
+ describe '#metadata' do
25
+ subject { schedule.metadata(options) }
26
+ it do
27
+ expect(client).to receive(:get_schedule_metadata).with(key, options).and_return(ret)
28
+ is_expected.to eq ret
29
+ end
30
+ end
31
+ describe '#exists?' do
32
+ subject { schedule.exists?(options) }
33
+ context 'metadata() works' do
34
+ it do
35
+ expect(schedule).to receive(:metadata).with(options)
36
+ is_expected.to eq true
37
+ end
38
+ end
39
+ context 'metadata() raises NotFoundError' do
40
+ it do
41
+ expect(schedule).to receive(:metadata).with(options).and_raise(NotFoundError)
42
+ is_expected.to be false
43
+ end
44
+ end
45
+ end
46
+ describe '#inspect' do
47
+ subject { schedule.inspect }
48
+ it { is_expected.to eq "#<PerfectSched::Schedule @key=#{key.inspect}>" }
49
+ end
50
+ end
51
+
52
+ describe ScheduleWithMetadata do
53
+ let (:sm){ ScheduleWithMetadata.new(client, key, attributes) }
54
+ let (:client){ double('client') }
55
+ let (:key){ double('key') }
56
+ let (:ret){ double('ret') }
57
+ let (:attributes){ double('attributes') }
58
+ describe '.new' do
59
+ subject { sm }
60
+ it { is_expected.to be_an_instance_of(ScheduleWithMetadata) }
61
+ end
62
+ describe '#inspect' do
63
+ subject { sm.inspect }
64
+ it { is_expected.to eq "#<PerfectSched::ScheduleWithMetadata @key=#{key.inspect} @attributes=#{attributes.inspect}>" }
65
+ end
66
+ end
data/spec/spec_helper.rb CHANGED
@@ -1,7 +1,5 @@
1
1
  $LOAD_PATH.unshift(File.expand_path('../lib', File.dirname(__FILE__)))
2
2
 
3
- require 'perfectsched'
4
-
5
3
  if ENV['SIMPLE_COV']
6
4
  require 'simplecov'
7
5
  SimpleCov.start do
@@ -11,6 +9,13 @@ if ENV['SIMPLE_COV']
11
9
  end
12
10
  end
13
11
 
12
+ require 'perfectsched'
13
+
14
+ if ENV['CI']
15
+ require 'coveralls'
16
+ Coveralls.wear!
17
+ end
18
+
14
19
  require 'fileutils'
15
20
 
16
21
  def test_sched_config
data/spec/task_spec.rb ADDED
@@ -0,0 +1,51 @@
1
+ require 'spec_helper'
2
+
3
+ describe PerfectSched::Task do
4
+ let (:client){ double('client') }
5
+ let (:key){ double('key') }
6
+ let (:attributes){ double('attributes') }
7
+ let (:scheduled_time){ double('scheduled_time') }
8
+ let (:task_token){ double('task_token') }
9
+ let (:task){ Task.new(client, key, attributes, scheduled_time, task_token) }
10
+
11
+ describe '.new' do
12
+ it 'returns a Task' do
13
+ expect(task).to be_an_instance_of(Task)
14
+ expect(task.instance_variable_get(:@scheduled_time)).to eq(scheduled_time)
15
+ expect(task.instance_variable_get(:@task_token)).to eq(task_token)
16
+ end
17
+ end
18
+
19
+ describe '#scheduled_time' do
20
+ it 'returns the scheduled_time' do
21
+ expect(task.scheduled_time).to eq(scheduled_time)
22
+ end
23
+ end
24
+
25
+ describe '#release!' do
26
+ it 'calls client.release' do
27
+ options = double('options')
28
+ ret = double('ret')
29
+ expect(client).to receive(:release).with(task_token, options).and_return(ret)
30
+ expect(task.release!(options)).to eq(ret)
31
+ end
32
+ end
33
+
34
+ describe '#retry!' do
35
+ it 'calls client.retry' do
36
+ options = double('options')
37
+ ret = double('ret')
38
+ expect(client).to receive(:retry).with(task_token, options).and_return(ret)
39
+ expect(task.retry!(options)).to eq(ret)
40
+ end
41
+ end
42
+
43
+ describe '#finish!' do
44
+ it 'calls client.finish' do
45
+ options = double('options')
46
+ ret = double('ret')
47
+ expect(client).to receive(:finish).with(task_token, options).and_return(ret)
48
+ expect(task.finish!(options)).to eq(ret)
49
+ end
50
+ end
51
+ end
data/spec/worker_spec.rb CHANGED
@@ -1,58 +1,201 @@
1
1
  require 'spec_helper'
2
2
 
3
- class TestHandler < PerfectSched::Application::Base
4
- def run
5
- puts "TestHandler: #{task}"
6
- if task.data['raise_error']
7
- raise "expected error test"
3
+ describe Worker do
4
+ let (:logger){ double('logger').as_null_object }
5
+ let (:runner){ double('runner') }
6
+ let (:config){ {} }
7
+ let (:worker){ Worker.new(runner, config) }
8
+ before do
9
+ allow(DaemonsLogger).to receive(:new).and_return(logger)
10
+ end
11
+
12
+ describe '.run' do
13
+ it 'calls Worker.new.run without block' do
14
+ expect(worker).to receive(:run).with(no_args)
15
+ expect(Worker).to receive(:new).with(runner, config) do |*args, &block|
16
+ expect(block).to be_nil
17
+ worker
18
+ end
19
+ Worker.run(runner, config)
8
20
  end
9
- if num = task.data['sleep']
10
- sleep num
21
+ it 'calls Worker.new.run with block' do
22
+ expect(worker).to receive(:run).with(no_args)
23
+ expect(Worker).to receive(:new).with(runner, nil) do |*args, &block|
24
+ expect(block).to be_a(Proc)
25
+ worker
26
+ end
27
+ Worker.run(runner){ }
11
28
  end
12
- puts "Task finished"
13
29
  end
14
30
 
15
- def kill(reason)
16
- puts "kill: #{reason.class}: #{reason}"
31
+ describe '.new' do
32
+ it 'creates a Worker without block' do
33
+ expect(worker).to be_an_instance_of(Worker)
34
+ expect(worker.instance_variable_get(:@runner)).to eq(runner)
35
+ expect(worker.instance_variable_get(:@config_load_proc)).to be_an_instance_of(Proc)
36
+ expect(worker.instance_variable_get(:@finished)).to be false
37
+ end
38
+ it 'creates a Worker with block' do
39
+ worker = Worker.new(runner){ }
40
+ expect(worker).to be_an_instance_of(Worker)
41
+ expect(worker.instance_variable_get(:@runner)).to eq(runner)
42
+ expect(worker.instance_variable_get(:@config_load_proc)).to be_an_instance_of(Proc)
43
+ expect(worker.instance_variable_get(:@finished)).to be false
44
+ end
17
45
  end
18
- end
19
-
20
- class TestApp < PerfectSched::Application::Dispatch
21
- route 'test' => TestHandler
22
- end
23
46
 
24
- describe Worker do
25
- before do
26
- create_test_sched.close
27
- @worker = Worker.new(TestApp, test_sched_config)
28
- @thread = Thread.new {
29
- @worker.run
30
- }
47
+ describe '#run' do
48
+ let (:sig) do
49
+ sig = double('sig')
50
+ expect(sig).to receive(:stop)
51
+ sig
52
+ end
53
+ let (:engine) do
54
+ engine = double('engine')
55
+ expect(engine).to receive(:run){ worker.instance_variable_set(:@finished, true) }
56
+ expect(engine).to receive(:shutdown)
57
+ engine
58
+ end
59
+ it 'creates a Worker without block' do
60
+ expect(worker).to receive(:install_signal_handlers).and_return(sig)
61
+ expect(Engine).to receive(:new).with(runner, kind_of(Hash)).and_return(engine)
62
+ expect(worker.instance_variable_get(:@runner)).to eq(runner)
63
+ expect(worker.instance_variable_get(:@config_load_proc)).to be_an_instance_of(Proc)
64
+ expect(worker.instance_variable_get(:@finished)).to be false
65
+ expect(worker.run).to be_nil
66
+ end
67
+ it 'rescues error' do
68
+ allow(worker).to receive(:install_signal_handlers).and_raise(RuntimeError)
69
+ expect(worker.run).to be_nil
70
+ end
31
71
  end
32
72
 
33
- after do
34
- @worker.stop
35
- @thread.join
73
+ describe '#stop' do
74
+ context 'engine is not set' do
75
+ it 'returns true' do
76
+ expect(worker.stop).to be true
77
+ expect(worker.instance_variable_get(:@finished)).to be true
78
+ end
79
+ end
80
+ context 'engine is set' do
81
+ let (:engine){ double('engine') }
82
+ before do
83
+ worker.instance_variable_set(:@engine, engine)
84
+ end
85
+ context 'succeed to stop engine' do
86
+ before do
87
+ expect(engine).to receive(:stop)
88
+ end
89
+ it 'returns true' do
90
+ expect(worker.stop).to be true
91
+ expect(worker.instance_variable_get(:@finished)).to be true
92
+ end
93
+ end
94
+ context 'fail to stop engine' do
95
+ before do
96
+ expect(engine).to receive(:stop).and_raise(RuntimeError)
97
+ end
98
+ it 'returns false' do
99
+ expect(worker.stop).to be false
100
+ expect(worker.instance_variable_get(:@finished)).to be true
101
+ end
102
+ end
103
+ end
36
104
  end
37
105
 
38
- def add(*args)
39
- sc = get_test_sched
40
- sc.add(*args)
41
- sc.close
106
+ describe '#restart' do
107
+ let (:engine){ double('engine') }
108
+ let (:old_engine){ double('old_engine') }
109
+ before do
110
+ worker.instance_variable_set(:@engine, old_engine)
111
+ expect(Engine).to receive(:new).with(runner, kind_of(Hash)).and_return(engine)
112
+ end
113
+ context 'succeed to shutdown old engine' do
114
+ before do
115
+ expect(old_engine).to receive(:shutdown)
116
+ end
117
+ it 'returns true' do
118
+ expect(worker.restart).to be true
119
+ end
120
+ end
121
+ context 'fail to shutdown old engine' do
122
+ before do
123
+ expect(old_engine).to receive(:shutdown).and_raise(RuntimeError)
124
+ end
125
+ it 'returns false' do
126
+ expect(worker.restart).to be false
127
+ end
128
+ end
42
129
  end
43
130
 
44
- it 'run' do
45
- TestHandler.any_instance.should_receive(:run).once
46
- add('key', 'test', {:cron=>'* * * * *', :next_time=>Time.now.to_i-60})
47
- sleep 2
131
+ describe '#replace' do
132
+ context 'called at the first time' do
133
+ let (:pid){ double('pid') }
134
+ it 'returns self' do
135
+ expect(Process).to receive(:spawn).with(*([$0]+ARGV)).and_return(pid)
136
+ expect(worker).to receive(:stop)
137
+ expect(worker.replace).to eq(worker)
138
+ end
139
+ it 'returns self' do
140
+ command = double('command')
141
+ expect(Process).to receive(:spawn).with(command).and_return(pid)
142
+ expect(worker).to receive(:stop)
143
+ expect(worker.replace(command)).to eq(worker)
144
+ end
145
+ end
146
+ context 'already called' do
147
+ it 'returns true' do
148
+ expect(worker).to receive(:stop).and_raise(RuntimeError)
149
+ expect(worker.replace(double)).to be false
150
+ end
151
+ end
48
152
  end
49
153
 
50
- it 'term signal' do
51
- sleep 1
52
- Process.kill(:TERM, Process.pid)
53
- puts "finish expected..."
54
- @thread.join
154
+ describe '#logrotated' do
155
+ it 'returns true' do
156
+ expect(logger).to receive(:reopen!)
157
+ expect(worker.logrotated).to be true
158
+ end
159
+ it 'rescues error and returns false' do
160
+ expect(logger).to receive(:reopen!).and_raise(RuntimeError)
161
+ expect(worker.logrotated).to be false
162
+ end
55
163
  end
56
164
 
165
+ describe 'install_signal_handlers' do
166
+ let (:engine){ double('engine', shutdown: nil) }
167
+ before do
168
+ expect(Engine).to receive(:new).with(runner, kind_of(Hash)).and_return(engine)
169
+ end
170
+ it 'traps TERM and stop the worker' do
171
+ allow(engine).to receive(:run){ Process.kill(:TERM, $$) }
172
+ expect(worker).to receive(:stop).and_call_original
173
+ worker.run
174
+ end
175
+ it 'traps INT and stop the worker' do
176
+ allow(engine).to receive(:run){ Process.kill(:INT, $$) }
177
+ expect(worker).to receive(:stop).and_call_original
178
+ worker.run
179
+ end
180
+ it 'traps QUIT and stop the worker' do
181
+ allow(engine).to receive(:run){ Process.kill(:QUIT, $$) }
182
+ expect(worker).to receive(:stop).and_call_original
183
+ worker.run
184
+ end
185
+ it 'traps USR1 and restart the worker' do
186
+ allow(engine).to receive(:run){ Process.kill(:USR1, $$) }
187
+ expect(worker).to receive(:restart){ worker.stop }
188
+ worker.run
189
+ end
190
+ it 'traps HUP and restart the worker' do
191
+ allow(engine).to receive(:run){ Process.kill(:HUP, $$) }
192
+ expect(worker).to receive(:restart){ worker.stop }
193
+ worker.run
194
+ end
195
+ it 'traps USR2 and logrotated' do
196
+ allow(engine).to receive(:run){ Process.kill(:USR2, $$) }
197
+ expect(worker).to receive(:logrotated){ worker.stop }
198
+ worker.run
199
+ end
200
+ end
57
201
  end
58
-