perfectsched 0.8.10 → 0.8.11

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
-