Refactoring: Moved Job#timeplan calculations into dedicated class
This commit is contained in:
parent
58c685f833
commit
2632d9fc6b
4 changed files with 318 additions and 320 deletions
|
@ -13,8 +13,7 @@ class Job < ApplicationModel
|
|||
store :perform
|
||||
validates :name, presence: true
|
||||
|
||||
before_create :updated_matching, :update_next_run_at
|
||||
before_update :updated_matching, :update_next_run_at
|
||||
before_save :updated_matching, :update_next_run_at
|
||||
|
||||
sanitized_html :note
|
||||
|
||||
|
@ -117,29 +116,7 @@ job.run(true)
|
|||
end
|
||||
|
||||
def in_timeplan?(time = Time.zone.now)
|
||||
day_map = {
|
||||
0 => 'Sun',
|
||||
1 => 'Mon',
|
||||
2 => 'Tue',
|
||||
3 => 'Wed',
|
||||
4 => 'Thu',
|
||||
5 => 'Fri',
|
||||
6 => 'Sat',
|
||||
}
|
||||
|
||||
# check day
|
||||
return false if !timeplan['days']
|
||||
return false if !timeplan['days'][day_map[time.wday]]
|
||||
|
||||
# check hour
|
||||
return false if !timeplan['hours']
|
||||
return false if !timeplan['hours'][time.hour.to_s] && !timeplan['hours'][time.hour]
|
||||
|
||||
# check min
|
||||
return false if !timeplan['minutes']
|
||||
return false if !timeplan['minutes'][match_minutes(time.min).to_s] && !timeplan['minutes'][match_minutes(time.min)]
|
||||
|
||||
true
|
||||
Job::TimeplanCalculation.new(timeplan).contains?(time)
|
||||
end
|
||||
|
||||
def matching_count
|
||||
|
@ -148,120 +125,23 @@ job.run(true)
|
|||
end
|
||||
|
||||
def next_run_at_calculate(time = Time.zone.now)
|
||||
if last_run_at
|
||||
diff = time - last_run_at
|
||||
if diff.positive?
|
||||
time += 10.minutes
|
||||
end
|
||||
end
|
||||
day_map = {
|
||||
0 => 'Sun',
|
||||
1 => 'Mon',
|
||||
2 => 'Tue',
|
||||
3 => 'Wed',
|
||||
4 => 'Thu',
|
||||
5 => 'Fri',
|
||||
6 => 'Sat',
|
||||
}
|
||||
return nil if !active
|
||||
return nil if !timeplan['days']
|
||||
return nil if !timeplan['hours']
|
||||
return nil if !timeplan['minutes']
|
||||
|
||||
# loop week days
|
||||
(0..7).each do |day_counter|
|
||||
time_to_check = nil
|
||||
day_to_check = if day_counter.zero?
|
||||
time
|
||||
else
|
||||
time + 1.day
|
||||
end
|
||||
if !timeplan['days'][day_map[day_to_check.wday]]
|
||||
|
||||
# start on next day at 00:00:00
|
||||
time = day_to_check - day_to_check.sec.seconds
|
||||
time -= day_to_check.min.minutes
|
||||
time -= day_to_check.hour.hours
|
||||
next
|
||||
end
|
||||
|
||||
min = day_to_check.min
|
||||
min = if min < 10
|
||||
0
|
||||
elsif min < 20
|
||||
10
|
||||
elsif min < 30
|
||||
20
|
||||
elsif min < 40
|
||||
30
|
||||
elsif min < 50
|
||||
40
|
||||
else
|
||||
50
|
||||
end
|
||||
|
||||
# move to [0-5]0:00 time stamps
|
||||
day_to_check = day_to_check - day_to_check.min.minutes + min.minutes
|
||||
day_to_check -= day_to_check.sec.seconds
|
||||
|
||||
# loop minutes till next full hour
|
||||
if day_to_check.min.nonzero?
|
||||
(0..5).each do |minute_counter|
|
||||
if minute_counter.nonzero?
|
||||
break if day_to_check.min.zero?
|
||||
|
||||
day_to_check += 10.minutes
|
||||
end
|
||||
next if !timeplan['hours'][day_to_check.hour] && !timeplan['hours'][day_to_check.hour.to_s]
|
||||
next if !timeplan['minutes'][match_minutes(day_to_check.min)] && !timeplan['minutes'][match_minutes(day_to_check.min).to_s]
|
||||
|
||||
return day_to_check
|
||||
end
|
||||
end
|
||||
|
||||
# loop hours
|
||||
hour_to_check = nil
|
||||
(0..23).each do |hour_counter|
|
||||
hour_to_check = day_to_check + hour_counter.hours
|
||||
|
||||
# start on next day
|
||||
if hour_to_check.day != day_to_check.day
|
||||
time = day_to_check - day_to_check.hour.hours
|
||||
break
|
||||
end
|
||||
|
||||
# ignore not configured hours
|
||||
next if !timeplan['hours'][hour_to_check.hour] && !timeplan['hours'][hour_to_check.hour.to_s]
|
||||
return nil if !hour_to_check
|
||||
|
||||
# loop minutes
|
||||
minute_to_check = nil
|
||||
(0..5).each do |minute_counter|
|
||||
minute_to_check = hour_to_check + minute_counter.minutes * 10
|
||||
next if !timeplan['minutes'][match_minutes(minute_to_check.min)] && !timeplan['minutes'][match_minutes(minute_to_check.min).to_s]
|
||||
|
||||
time_to_check = minute_to_check
|
||||
break
|
||||
end
|
||||
next if !minute_to_check
|
||||
|
||||
return time_to_check
|
||||
end
|
||||
|
||||
if last_run_at && (time - last_run_at).positive?
|
||||
time += 10.minutes
|
||||
end
|
||||
nil
|
||||
|
||||
Job::TimeplanCalculation.new(timeplan).next_at(time)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def updated_matching
|
||||
self.matching = matching_count
|
||||
true
|
||||
end
|
||||
|
||||
def update_next_run_at
|
||||
self.next_run_at = next_run_at_calculate
|
||||
true
|
||||
end
|
||||
|
||||
def match_minutes(minutes)
|
||||
|
|
105
app/models/job/timeplan_calculation.rb
Normal file
105
app/models/job/timeplan_calculation.rb
Normal file
|
@ -0,0 +1,105 @@
|
|||
# Copyright (C) 2012-2021 Zammad Foundation, http://zammad-foundation.org/
|
||||
|
||||
class Job::TimeplanCalculation
|
||||
DAY_MAP = {
|
||||
0 => 'Sun',
|
||||
1 => 'Mon',
|
||||
2 => 'Tue',
|
||||
3 => 'Wed',
|
||||
4 => 'Thu',
|
||||
5 => 'Fri',
|
||||
6 => 'Sat'
|
||||
}.freeze
|
||||
|
||||
attr_reader :timeplan
|
||||
|
||||
def initialize(timeplan)
|
||||
@timeplan = timeplan.deep_transform_keys(&:to_s)
|
||||
end
|
||||
|
||||
def contains?(time)
|
||||
return false if !valid?
|
||||
|
||||
day?(time) && hour?(time) && minute?(time)
|
||||
end
|
||||
|
||||
def next_at(time)
|
||||
return nil if !valid?
|
||||
|
||||
next_run_at_same_day(time) || next_run_at_coming_week(time)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def valid?
|
||||
timeplan.key?('days') && timeplan.key?('hours') && timeplan.key?('minutes')
|
||||
end
|
||||
|
||||
def match_minutes(minutes)
|
||||
minutes / 10 * 10
|
||||
end
|
||||
|
||||
def day?(time)
|
||||
timeplan['days'][DAY_MAP[time.wday]]
|
||||
end
|
||||
|
||||
def hour?(time)
|
||||
timeplan.dig 'hours', time.hour.to_s
|
||||
end
|
||||
|
||||
def minute?(time)
|
||||
timeplan.dig 'minutes', match_minutes(time.min).to_s
|
||||
end
|
||||
|
||||
def loop_minutes(base_time)
|
||||
return if !hour?(base_time)
|
||||
|
||||
0
|
||||
.step(50, 10)
|
||||
.lazy
|
||||
.map { |minute| base_time.change min: minute }
|
||||
.find { |time| minute?(time) }
|
||||
end
|
||||
|
||||
def loop_hours(base_time)
|
||||
return if !day?(base_time)
|
||||
|
||||
(base_time.hour..23)
|
||||
.lazy
|
||||
.map { |hour| loop_minutes base_time.change hour: hour }
|
||||
.find(&:present?)
|
||||
end
|
||||
|
||||
def loop_partial_hour(base_time)
|
||||
return if !day?(base_time)
|
||||
|
||||
base_time
|
||||
.min
|
||||
.step(50, 10)
|
||||
.lazy
|
||||
.map { |minute| base_time.change(min: minute) }
|
||||
.find { |time| hour?(time) && minute?(time) }
|
||||
end
|
||||
|
||||
def next_run_at_same_day(time)
|
||||
day_to_check = time.change min: match_minutes(time.min)
|
||||
|
||||
if day_to_check.min.nonzero?
|
||||
date = loop_partial_hour(day_to_check)
|
||||
|
||||
return date if date
|
||||
|
||||
day_to_check = day_to_check.change(min: 0)
|
||||
day_to_check += 1.hour
|
||||
end
|
||||
|
||||
loop_hours(day_to_check)
|
||||
end
|
||||
|
||||
def next_run_at_coming_week(time)
|
||||
(1..7)
|
||||
.lazy
|
||||
.map { |day| loop_hours (time + day.day).midnight }
|
||||
.find(&:present?)
|
||||
end
|
||||
end
|
207
spec/models/job/timeplan_calculation_spec.rb
Normal file
207
spec/models/job/timeplan_calculation_spec.rb
Normal file
|
@ -0,0 +1,207 @@
|
|||
# Copyright (C) 2012-2021 Zammad Foundation, http://zammad-foundation.org/
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Job::TimeplanCalculation do
|
||||
subject(:instance) { described_class.new(timeplan) }
|
||||
|
||||
describe '#contains?' do
|
||||
context 'without a valid timeplan' do
|
||||
let(:timeplan) { {} }
|
||||
|
||||
it { is_expected.not_to be_contains(Time.zone.now) }
|
||||
end
|
||||
|
||||
context 'with monday 09:20' do
|
||||
let(:timeplan) { { 'days' => { 'Mon' => true }, 'hours' => { '9' => true }, 'minutes' => { '20' => true } } }
|
||||
|
||||
it { is_expected.to be_contains(Time.zone.parse('2020-12-28 09:20')) }
|
||||
it { is_expected.to be_contains(Time.zone.parse('2020-12-21 09:20')) }
|
||||
it { is_expected.not_to be_contains(Time.zone.parse('2020-12-21 10:20')) }
|
||||
it { is_expected.not_to be_contains(Time.zone.parse('2020-12-21 9:10')) }
|
||||
it { is_expected.not_to be_contains(Time.zone.parse('2020-12-22 9:20')) }
|
||||
it { is_expected.not_to be_contains(Time.zone.parse('2020-12-20 9:20')) }
|
||||
end
|
||||
|
||||
context 'with monday and tuesday 09:20' do
|
||||
let(:timeplan) { { 'days' => { 'Mon' => true, 'Tue' => true }, 'hours' => { '9' => true }, 'minutes' => { '20' => true } } }
|
||||
|
||||
it { is_expected.to be_contains(Time.zone.parse('2020-12-28 09:20')) }
|
||||
it { is_expected.to be_contains(Time.zone.parse('2020-12-21 09:20')) }
|
||||
it { is_expected.not_to be_contains(Time.zone.parse('2020-12-21 10:20')) }
|
||||
it { is_expected.not_to be_contains(Time.zone.parse('2020-12-21 9:10')) }
|
||||
it { is_expected.to be_contains(Time.zone.parse('2020-12-22 9:20')) }
|
||||
it { is_expected.not_to be_contains(Time.zone.parse('2020-12-20 9:20')) }
|
||||
end
|
||||
|
||||
context 'with monday 09:20 and 10:20' do
|
||||
let(:timeplan) { { 'days' => { 'Mon' => true }, 'hours' => { '9' => true, '10' => true }, 'minutes' => { '20' => true } } }
|
||||
|
||||
it { is_expected.to be_contains(Time.zone.parse('2020-12-28 09:20')) }
|
||||
it { is_expected.to be_contains(Time.zone.parse('2020-12-21 09:20')) }
|
||||
it { is_expected.to be_contains(Time.zone.parse('2020-12-21 10:20')) }
|
||||
it { is_expected.not_to be_contains(Time.zone.parse('2020-12-21 9:10')) }
|
||||
it { is_expected.not_to be_contains(Time.zone.parse('2020-12-22 9:20')) }
|
||||
it { is_expected.not_to be_contains(Time.zone.parse('2020-12-20 9:20')) }
|
||||
end
|
||||
|
||||
context 'with monday 09:20 and 9:10' do
|
||||
let(:timeplan) { { 'days' => { 'Mon' => true }, 'hours' => { '9' => true }, 'minutes' => { '20' => true, '10' => true } } }
|
||||
|
||||
it { is_expected.to be_contains(Time.zone.parse('2020-12-28 09:20')) }
|
||||
it { is_expected.to be_contains(Time.zone.parse('2020-12-21 09:20')) }
|
||||
it { is_expected.not_to be_contains(Time.zone.parse('2020-12-21 10:20')) }
|
||||
it { is_expected.to be_contains(Time.zone.parse('2020-12-21 9:10')) }
|
||||
it { is_expected.not_to be_contains(Time.zone.parse('2020-12-22 9:20')) }
|
||||
it { is_expected.not_to be_contains(Time.zone.parse('2020-12-20 9:20')) }
|
||||
end
|
||||
end
|
||||
|
||||
describe 'next_at?' do
|
||||
context 'without a valid timeplan' do
|
||||
let(:timeplan) { {} }
|
||||
|
||||
it { expect(instance.next_at(Time.zone.now)).to be_nil }
|
||||
end
|
||||
|
||||
context 'with monday 09:20' do
|
||||
let(:timeplan) { { 'days' => { 'Mon' => true }, 'hours' => { '9' => true }, 'minutes' => { '20' => true } } }
|
||||
|
||||
it { expect(instance.next_at(Time.zone.parse('2020-12-28 09:31'))).to eq(Time.zone.parse('2021-01-04 09:20')) }
|
||||
it { expect(instance.next_at(Time.zone.parse('2020-12-28 09:30'))).to eq(Time.zone.parse('2021-01-04 09:20')) }
|
||||
it { expect(instance.next_at(Time.zone.parse('2020-12-28 09:20'))).to eq(Time.zone.parse('2020-12-28 09:20')) }
|
||||
it { expect(instance.next_at(Time.zone.parse('2020-12-21 09:21'))).to eq(Time.zone.parse('2020-12-21 09:20')) }
|
||||
it { expect(instance.next_at(Time.zone.parse('2020-12-21 09:35'))).to eq(Time.zone.parse('2020-12-28 09:20')) }
|
||||
it { expect(instance.next_at(Time.zone.parse('2020-12-21 10:20'))).to eq(Time.zone.parse('2020-12-28 09:20')) }
|
||||
it { expect(instance.next_at(Time.zone.parse('2020-12-21 10:21'))).to eq(Time.zone.parse('2020-12-28 09:20')) }
|
||||
it { expect(instance.next_at(Time.zone.parse('2020-12-21 9:10'))).to eq(Time.zone.parse('2020-12-21 09:20')) }
|
||||
it { expect(instance.next_at(Time.zone.parse('2020-12-22 9:20'))).to eq(Time.zone.parse('2020-12-28 09:20')) }
|
||||
it { expect(instance.next_at(Time.zone.parse('2020-12-20 9:20'))).to eq(Time.zone.parse('2020-12-21 09:20')) }
|
||||
end
|
||||
|
||||
context 'with monday and tuesday 09:20' do
|
||||
let(:timeplan) { { 'days' => { 'Mon' => true, 'Tue' => true }, 'hours' => { '9' => true }, 'minutes' => { '20' => true } } }
|
||||
|
||||
it { expect(instance.next_at(Time.zone.parse('2020-12-28 09:30'))).to eq(Time.zone.parse('2020-12-29 09:20')) }
|
||||
it { expect(instance.next_at(Time.zone.parse('2020-12-29 09:30'))).to eq(Time.zone.parse('2021-01-04 09:20')) }
|
||||
it { expect(instance.next_at(Time.zone.parse('2020-12-21 09:25'))).to eq(Time.zone.parse('2020-12-21 09:20')) }
|
||||
it { expect(instance.next_at(Time.zone.parse('2020-12-21 09:35'))).to eq(Time.zone.parse('2020-12-22 09:20')) }
|
||||
it { expect(instance.next_at(Time.zone.parse('2020-12-21 10:20'))).to eq(Time.zone.parse('2020-12-22 09:20')) }
|
||||
it { expect(instance.next_at(Time.zone.parse('2020-12-21 10:21'))).to eq(Time.zone.parse('2020-12-22 09:20')) }
|
||||
it { expect(instance.next_at(Time.zone.parse('2020-12-21 9:10'))).to eq(Time.zone.parse('2020-12-21 09:20')) }
|
||||
it { expect(instance.next_at(Time.zone.parse('2020-12-22 9:30'))).to eq(Time.zone.parse('2020-12-28 09:20')) }
|
||||
it { expect(instance.next_at(Time.zone.parse('2020-12-20 9:20'))).to eq(Time.zone.parse('2020-12-21 09:20')) }
|
||||
end
|
||||
|
||||
context 'with monday 09:20 and 10:20' do
|
||||
let(:timeplan) { { 'days' => { 'Mon' => true }, 'hours' => { '9' => true, '10' => true }, 'minutes' => { '20' => true } } }
|
||||
|
||||
it { expect(instance.next_at(Time.zone.parse('2020-12-28 09:30'))).to eq(Time.zone.parse('2020-12-28 10:20')) }
|
||||
it { expect(instance.next_at(Time.zone.parse('2020-12-21 09:30'))).to eq(Time.zone.parse('2020-12-21 10:20')) }
|
||||
it { expect(instance.next_at(Time.zone.parse('2020-12-21 09:35'))).to eq(Time.zone.parse('2020-12-21 10:20')) }
|
||||
it { expect(instance.next_at(Time.zone.parse('2020-12-21 08:07'))).to eq(Time.zone.parse('2020-12-21 09:20')) }
|
||||
it { expect(instance.next_at(Time.zone.parse('2020-12-21 10:30'))).to eq(Time.zone.parse('2020-12-28 09:20')) }
|
||||
it { expect(instance.next_at(Time.zone.parse('2020-12-21 10:31'))).to eq(Time.zone.parse('2020-12-28 09:20')) }
|
||||
it { expect(instance.next_at(Time.zone.parse('2020-12-21 9:10'))).to eq(Time.zone.parse('2020-12-21 09:20')) }
|
||||
it { expect(instance.next_at(Time.zone.parse('2020-12-21 9:47'))).to eq(Time.zone.parse('2020-12-21 10:20')) }
|
||||
it { expect(instance.next_at(Time.zone.parse('2020-12-22 9:20'))).to eq(Time.zone.parse('2020-12-28 09:20')) }
|
||||
it { expect(instance.next_at(Time.zone.parse('2020-12-20 9:30'))).to eq(Time.zone.parse('2020-12-21 09:20')) }
|
||||
end
|
||||
|
||||
context 'with monday 09:30 and 9:10' do
|
||||
let(:timeplan) { { 'days' => { 'Mon' => true }, 'hours' => { '9' => true }, 'minutes' => { '30' => true, '10' => true } } }
|
||||
|
||||
it { expect(instance.next_at(Time.zone.parse('2020-12-28 09:40'))).to eq(Time.zone.parse('2021-01-04 09:10')) }
|
||||
it { expect(instance.next_at(Time.zone.parse('2020-12-21 09:40'))).to eq(Time.zone.parse('2020-12-28 09:10')) }
|
||||
it { expect(instance.next_at(Time.zone.parse('2020-12-21 09:30'))).to eq(Time.zone.parse('2020-12-21 09:30')) }
|
||||
it { expect(instance.next_at(Time.zone.parse('2020-12-21 09:25'))).to eq(Time.zone.parse('2020-12-21 09:30')) }
|
||||
it { expect(instance.next_at(Time.zone.parse('2020-12-21 09:35'))).to eq(Time.zone.parse('2020-12-21 09:30')) }
|
||||
it { expect(instance.next_at(Time.zone.parse('2020-12-21 09:45'))).to eq(Time.zone.parse('2020-12-28 09:10')) }
|
||||
it { expect(instance.next_at(Time.zone.parse('2020-12-21 08:07'))).to eq(Time.zone.parse('2020-12-21 09:10')) }
|
||||
it { expect(instance.next_at(Time.zone.parse('2020-12-21 10:20'))).to eq(Time.zone.parse('2020-12-28 09:10')) }
|
||||
it { expect(instance.next_at(Time.zone.parse('2020-12-21 10:21'))).to eq(Time.zone.parse('2020-12-28 09:10')) }
|
||||
it { expect(instance.next_at(Time.zone.parse('2020-12-21 9:10'))).to eq(Time.zone.parse('2020-12-21 09:10')) }
|
||||
it { expect(instance.next_at(Time.zone.parse('2020-12-21 9:20'))).to eq(Time.zone.parse('2020-12-21 09:30')) }
|
||||
it { expect(instance.next_at(Time.zone.parse('2020-12-22 9:20'))).to eq(Time.zone.parse('2020-12-28 09:10')) }
|
||||
it { expect(instance.next_at(Time.zone.parse('2020-12-20 9:20'))).to eq(Time.zone.parse('2020-12-21 09:10')) }
|
||||
end
|
||||
end
|
||||
|
||||
describe 'legacy tests moved from Job model' do
|
||||
let(:job) { create(:job, :never_on) }
|
||||
let(:timeplan) { job.timeplan }
|
||||
let(:time) { Time.current }
|
||||
|
||||
context 'when the current day, hour, and minute all match true values in #timeplan' do
|
||||
it 'for Symbol/Integer keys returns true' do
|
||||
timeplan[:days].transform_keys!(&:to_sym)[time.strftime('%a').to_sym] = true
|
||||
timeplan[:hours].transform_keys!(&:to_i)[time.hour] = true
|
||||
timeplan[:minutes].transform_keys!(&:to_i)[time.min.floor(-1)] = true
|
||||
|
||||
expect(instance.contains?(time)).to be(true)
|
||||
end
|
||||
|
||||
it 'for String keys returns true' do
|
||||
timeplan[:days].transform_keys!(&:to_s)[time.strftime('%a')] = true
|
||||
timeplan[:hours].transform_keys!(&:to_s)[time.hour.to_s] = true
|
||||
timeplan[:minutes].transform_keys!(&:to_s)[time.min.floor(-1).to_s] = true
|
||||
|
||||
expect(instance.contains?(time)).to be(true)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the current day does not match a true value in #timeplan' do
|
||||
it 'for Symbol/Integer keys returns false' do
|
||||
timeplan[:days].transform_keys!(&:to_sym).transform_values! { true }[time.strftime('%a').to_sym] = false
|
||||
timeplan[:hours].transform_keys!(&:to_i)[time.hour] = true
|
||||
timeplan[:minutes].transform_keys!(&:to_i)[time.min.floor(-1)] = true
|
||||
|
||||
expect(instance.contains?(time)).to be(false)
|
||||
end
|
||||
|
||||
it 'for String keys returns false' do
|
||||
timeplan[:days].transform_keys!(&:to_s).transform_values! { true }[time.strftime('%a')] = false
|
||||
timeplan[:hours].transform_keys!(&:to_s)[time.hour.to_s] = true
|
||||
timeplan[:minutes].transform_keys!(&:to_s)[time.min.floor(-1).to_s] = true
|
||||
|
||||
expect(instance.contains?(time)).to be(false)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the current hour does not match a true value in #timeplan' do
|
||||
it 'for Symbol/Integer keys returns false' do
|
||||
timeplan[:days].transform_keys!(&:to_sym)[time.strftime('%a').to_sym] = true
|
||||
timeplan[:hours].transform_keys!(&:to_i).transform_values! { true }[time.hour] = false
|
||||
timeplan[:minutes].transform_keys!(&:to_i)[time.min.floor(-1)] = true
|
||||
|
||||
expect(instance.contains?(time)).to be(false)
|
||||
end
|
||||
|
||||
it 'for String keys returns false' do
|
||||
timeplan[:days].transform_keys!(&:to_s)[time.strftime('%a')] = true
|
||||
timeplan[:hours].transform_keys!(&:to_s).transform_values! { true }[time.hour.to_s] = false
|
||||
timeplan[:minutes].transform_keys!(&:to_s)[time.min.floor(-1).to_s] = true
|
||||
|
||||
expect(instance.contains?(time)).to be(false)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the current minute does not match a true value in #timeplan' do
|
||||
it 'for Symbol/Integer keys returns false' do
|
||||
timeplan[:days].transform_keys!(&:to_sym)[time.strftime('%a').to_sym] = true
|
||||
timeplan[:hours].transform_keys!(&:to_i)[time.hour] = true
|
||||
timeplan[:minutes].transform_keys!(&:to_i).transform_values! { true }[time.min.floor(-1)] = false
|
||||
|
||||
expect(instance.contains?(time)).to be(false)
|
||||
end
|
||||
|
||||
it 'for String keys returns false' do
|
||||
timeplan[:days].transform_keys!(&:to_s)[time.strftime('%a')] = true
|
||||
timeplan[:hours].transform_keys!(&:to_s)[time.hour.to_s] = true
|
||||
timeplan[:minutes].transform_keys!(&:to_s).transform_values! { true }[time.min.floor(-1).to_s] = false
|
||||
|
||||
expect(instance.contains?(time)).to be(false)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -345,200 +345,6 @@ RSpec.describe Job, type: :model do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#in_timeplan?' do
|
||||
subject(:job) { create(:job, :never_on) }
|
||||
|
||||
context 'when the current day, hour, and minute all match true values in #timeplan' do
|
||||
context 'for Symbol/Integer keys' do
|
||||
before do
|
||||
job.update(
|
||||
timeplan: {
|
||||
days: job.timeplan[:days]
|
||||
.transform_keys(&:to_sym)
|
||||
.merge(Time.current.strftime('%a').to_sym => true),
|
||||
hours: job.timeplan[:hours]
|
||||
.transform_keys(&:to_i)
|
||||
.merge(Time.current.hour => true),
|
||||
minutes: job.timeplan[:minutes]
|
||||
.transform_keys(&:to_i)
|
||||
.merge(Time.current.min.floor(-1) => true),
|
||||
}
|
||||
)
|
||||
end
|
||||
|
||||
it 'returns true' do
|
||||
expect(job.in_timeplan?).to be(true)
|
||||
end
|
||||
end
|
||||
|
||||
context 'for String keys' do
|
||||
before do
|
||||
job.update(
|
||||
timeplan: {
|
||||
days: job.timeplan[:days]
|
||||
.transform_keys(&:to_s)
|
||||
.merge(Time.current.strftime('%a') => true),
|
||||
hours: job.timeplan[:hours]
|
||||
.transform_keys(&:to_s)
|
||||
.merge(Time.current.hour.to_s => true),
|
||||
minutes: job.timeplan[:minutes]
|
||||
.transform_keys(&:to_s)
|
||||
.merge(Time.current.min.floor(-1).to_s => true),
|
||||
}
|
||||
)
|
||||
end
|
||||
|
||||
it 'returns true' do
|
||||
expect(job.in_timeplan?).to be(true)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the current day does not match a true value in #timeplan' do
|
||||
context 'for Symbol/Integer keys' do
|
||||
before do
|
||||
job.update(
|
||||
timeplan: {
|
||||
days: job.timeplan[:days]
|
||||
.transform_keys(&:to_sym)
|
||||
.transform_values { true }
|
||||
.merge(Time.current.strftime('%a').to_sym => false),
|
||||
hours: job.timeplan[:hours]
|
||||
.transform_keys(&:to_i)
|
||||
.merge(Time.current.hour => true),
|
||||
minutes: job.timeplan[:minutes]
|
||||
.transform_keys(&:to_i)
|
||||
.merge(Time.current.min.floor(-1) => true),
|
||||
}
|
||||
)
|
||||
end
|
||||
|
||||
it 'returns false' do
|
||||
expect(job.in_timeplan?).to be(false)
|
||||
end
|
||||
end
|
||||
|
||||
context 'for String keys' do
|
||||
before do
|
||||
job.update(
|
||||
timeplan: {
|
||||
days: job.timeplan[:days]
|
||||
.transform_keys(&:to_s)
|
||||
.transform_values { true }
|
||||
.merge(Time.current.strftime('%a') => false),
|
||||
hours: job.timeplan[:hours]
|
||||
.transform_keys(&:to_s)
|
||||
.merge(Time.current.hour.to_s => true),
|
||||
minutes: job.timeplan[:minutes]
|
||||
.transform_keys(&:to_s)
|
||||
.merge(Time.current.min.floor(-1).to_s => true),
|
||||
}
|
||||
)
|
||||
end
|
||||
|
||||
it 'returns false' do
|
||||
expect(job.in_timeplan?).to be(false)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the current hour does not match a true value in #timeplan' do
|
||||
context 'for Symbol/Integer keys' do
|
||||
before do
|
||||
job.update(
|
||||
timeplan: {
|
||||
days: job.timeplan[:days]
|
||||
.transform_keys(&:to_sym)
|
||||
.merge(Time.current.strftime('%a').to_sym => true),
|
||||
hours: job.timeplan[:hours]
|
||||
.transform_keys(&:to_i)
|
||||
.transform_values { true }
|
||||
.merge(Time.current.hour => false),
|
||||
minutes: job.timeplan[:minutes]
|
||||
.transform_keys(&:to_i)
|
||||
.merge(Time.current.min.floor(-1) => true),
|
||||
}
|
||||
)
|
||||
end
|
||||
|
||||
it 'returns false' do
|
||||
expect(job.in_timeplan?).to be(false)
|
||||
end
|
||||
end
|
||||
|
||||
context 'for String keys' do
|
||||
before do
|
||||
job.update(
|
||||
timeplan: {
|
||||
days: job.timeplan[:days]
|
||||
.transform_keys(&:to_s)
|
||||
.merge(Time.current.strftime('%a') => true),
|
||||
hours: job.timeplan[:hours]
|
||||
.transform_keys(&:to_s)
|
||||
.transform_values { true }
|
||||
.merge(Time.current.hour.to_s => false),
|
||||
minutes: job.timeplan[:minutes]
|
||||
.transform_keys(&:to_s)
|
||||
.merge(Time.current.min.floor(-1).to_s => true),
|
||||
}
|
||||
)
|
||||
end
|
||||
|
||||
it 'returns false' do
|
||||
expect(job.in_timeplan?).to be(false)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the current minute does not match a true value in #timeplan' do
|
||||
context 'for Symbol/Integer keys' do
|
||||
before do
|
||||
job.update(
|
||||
timeplan: {
|
||||
days: job.timeplan[:days]
|
||||
.transform_keys(&:to_sym)
|
||||
.merge(Time.current.strftime('%a').to_sym => true),
|
||||
hours: job.timeplan[:hours]
|
||||
.transform_keys(&:to_i)
|
||||
.merge(Time.current.hour => true),
|
||||
minutes: job.timeplan[:minutes]
|
||||
.transform_keys(&:to_i)
|
||||
.transform_values { true }
|
||||
.merge(Time.current.min.floor(-1) => false),
|
||||
}
|
||||
)
|
||||
end
|
||||
|
||||
it 'returns false' do
|
||||
expect(job.in_timeplan?).to be(false)
|
||||
end
|
||||
end
|
||||
|
||||
context 'for String keys' do
|
||||
before do
|
||||
job.update(
|
||||
timeplan: {
|
||||
days: job.timeplan[:days]
|
||||
.transform_keys(&:to_s)
|
||||
.merge(Time.current.strftime('%a') => true),
|
||||
hours: job.timeplan[:hours]
|
||||
.transform_keys(&:to_s)
|
||||
.merge(Time.current.hour.to_s => true),
|
||||
minutes: job.timeplan[:minutes]
|
||||
.transform_keys(&:to_s)
|
||||
.transform_values { true }
|
||||
.merge(Time.current.min.floor(-1).to_s => false),
|
||||
}
|
||||
)
|
||||
end
|
||||
|
||||
it 'returns false' do
|
||||
expect(job.in_timeplan?).to be(false)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'Attributes:' do
|
||||
|
|
Loading…
Reference in a new issue