Skip to content

Commit 8dfe249

Browse files
authored
Merge pull request #505 from alphagov/fix-off-by-one-closing-dates
Make sure jobs run at midnight in the application time zone
2 parents 69d5171 + f699910 commit 8dfe249

7 files changed

Lines changed: 154 additions & 51 deletions

File tree

app/jobs/close_petitions_job.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
class ClosePetitionsJob < ActiveJob::Base
22
queue_as :high_priority
33

4-
def perform
5-
Petition.close_petitions!
4+
def perform(time)
5+
Petition.close_petitions!(time.in_time_zone)
66
end
77
end

app/jobs/debated_petitions_job.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
class DebatedPetitionsJob < ActiveJob::Base
22
queue_as :high_priority
33

4-
def perform
5-
Petition.mark_petitions_as_debated!
4+
def perform(date)
5+
Petition.mark_petitions_as_debated!(date.to_date)
66
end
77
end

app/models/petition.rb

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -281,12 +281,12 @@ def sanitized_tag(tag)
281281
"[#{tag.gsub(/[\[\]%]/,'')}]"
282282
end
283283

284-
def in_need_of_marking_as_debated
285-
where(scheduled_debate_state.and(debate_date_in_the_past))
284+
def in_need_of_marking_as_debated(date = Date.current)
285+
where(scheduled_debate_state.and(debate_date_in_the_past(date)))
286286
end
287287

288-
def mark_petitions_as_debated!
289-
in_need_of_marking_as_debated.update_all(debate_state: 'debated')
288+
def mark_petitions_as_debated!(date = Date.current)
289+
in_need_of_marking_as_debated(date).update_all(debate_state: 'debated')
290290
end
291291

292292
private
@@ -303,8 +303,8 @@ def awaiting_debate_state
303303
arel_table[:debate_state].eq('awaiting')
304304
end
305305

306-
def debate_date_in_the_past
307-
arel_table[:scheduled_debate_date].lt(Date.current)
306+
def debate_date_in_the_past(date)
307+
arel_table[:scheduled_debate_date].lt(date)
308308
end
309309

310310
def scheduled_debate_state

config/schedule.rb

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,10 @@
3535
runner "PetitionCountJob.perform_later"
3636
end
3737

38-
every :day, at: '0.00am' do
39-
runner "ClosePetitionsJob.perform_later"
38+
every :day, at: '7.00am' do
39+
rake "epets:petitions:close", output: nil
4040
end
4141

42-
every :day, at: '0.00am' do
43-
runner "DebatedPetitionsJob.perform_later"
42+
every :day, at: '7.15am' do
43+
rake "epets:petitions:debated", output: nil
4444
end

lib/tasks/petitions.rake

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
namespace :epets do
2+
namespace :petitions do
3+
desc "Add task to the queue to close petitions at midnight"
4+
task :close => :environment do
5+
time = Date.tomorrow.beginning_of_day
6+
ClosePetitionsJob.set(wait_until: time).perform_later(time.iso8601)
7+
end
8+
9+
desc "Add task to the queue to mark petitions as debated at midnight"
10+
task :debated => :environment do
11+
date = Date.tomorrow
12+
DebatedPetitionsJob.set(wait_until: date.beginning_of_day).perform_later(date.iso8601)
13+
end
14+
end
15+
end
Lines changed: 63 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,75 @@
11
require 'rails_helper'
22

33
RSpec.describe ClosePetitionsJob, type: :job do
4-
let!(:petition) { FactoryGirl.create(:open_petition, open_at: open_at) }
4+
context "for a petition opened in the winter" do
5+
let!(:petition) {
6+
FactoryGirl.create(:open_petition, open_at: "2015-12-29T10:00:00Z")
7+
}
58

6-
context "when a petition is in the open state and closing date has not passed" do
7-
let(:open_at) { Site.opened_at_for_closing(1.day.from_now) }
9+
around do |example|
10+
travel_to(now)
11+
example.run
12+
travel_back
13+
end
14+
15+
context "and the closing date has not passed" do
16+
let(:now) { "2016-06-28T07:00:00Z".in_time_zone }
17+
18+
it "does not change the petition state" do
19+
expect{
20+
perform_enqueued_jobs {
21+
described_class.perform_later(Date.tomorrow.beginning_of_day.iso8601)
22+
}
23+
}.not_to change{ petition.reload.state }
24+
end
25+
end
26+
27+
context "and the closing date has passed" do
28+
let(:now) { "2016-06-29T07:00:00Z".in_time_zone }
829

9-
it "does not close the petition" do
10-
expect{
11-
perform_enqueued_jobs {
12-
described_class.perform_later
13-
}
14-
}.not_to change{ petition.reload.state }
30+
it "does change the petition debate state" do
31+
expect{
32+
perform_enqueued_jobs {
33+
described_class.perform_later(Date.tomorrow.beginning_of_day.iso8601)
34+
}
35+
}.to change{ petition.reload.state }.from("open").to("closed")
36+
end
1537
end
1638
end
1739

18-
context "when a petition is in the open state and closed_at has passed" do
19-
let(:open_at) { Site.opened_at_for_closing(1.day.ago) }
40+
context "for a petition opened in the summer" do
41+
let!(:petition) {
42+
FactoryGirl.create(:open_petition, open_at: "2016-06-29T10:00:00Z")
43+
}
44+
45+
around do |example|
46+
travel_to(now)
47+
example.run
48+
travel_back
49+
end
50+
51+
context "and the debate date has not passed" do
52+
let(:now) { "2016-12-28T07:00:00Z".in_time_zone }
53+
54+
it "does not change the petition state" do
55+
expect{
56+
perform_enqueued_jobs {
57+
described_class.perform_later(Date.tomorrow.beginning_of_day.iso8601)
58+
}
59+
}.not_to change{ petition.reload.state }
60+
end
61+
end
62+
63+
context "and the debate date has passed" do
64+
let(:now) { "2016-12-29T07:00:00Z".in_time_zone }
2065

21-
it "does close the petition" do
22-
expect{
23-
perform_enqueued_jobs {
24-
described_class.perform_later
25-
}
26-
}.to change{ petition.reload.state }.from('open').to('closed')
66+
it "does change the petition state" do
67+
expect{
68+
perform_enqueued_jobs {
69+
described_class.perform_later(Date.tomorrow.beginning_of_day.iso8601)
70+
}
71+
}.to change{ petition.reload.state }.from("open").to("closed")
72+
end
2773
end
2874
end
2975
end
Lines changed: 62 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,89 @@
11
require 'rails_helper'
22

33
RSpec.describe DebatedPetitionsJob, type: :job do
4-
context "when a petition is in the scheduled debate state and the debate date has not passed" do
4+
context "for a petition with a scheduled debate date in the winter" do
55
let(:petition) {
66
FactoryGirl.build(:open_petition,
77
debate_state: 'scheduled',
8-
scheduled_debate_date: Date.tomorrow
8+
scheduled_debate_date: "2015-12-29"
99
)
1010
}
1111

12-
before do
13-
petition.save
12+
let(:open_at) { "2015-12-01T10:00:00Z".in_time_zone }
13+
14+
around do |example|
15+
travel_to(open_at) { petition.save }
16+
travel_to(now)
17+
example.run
18+
travel_back
19+
end
20+
21+
context "and the debate date has not passed" do
22+
let(:now) { "2015-12-28T07:15:00Z".in_time_zone }
23+
24+
it "does not change the petition debate state" do
25+
expect{
26+
perform_enqueued_jobs {
27+
described_class.perform_later(Date.tomorrow.iso8601)
28+
}
29+
}.not_to change{ petition.reload.debate_state }
30+
end
1431
end
1532

16-
it "does not close the petition" do
17-
expect{
18-
perform_enqueued_jobs {
19-
described_class.perform_later
20-
}
21-
}.not_to change{ petition.reload.debate_state }
33+
context "and the debate date has passed" do
34+
let(:now) { "2015-12-29T07:15:00Z".in_time_zone }
35+
36+
it "does change the petition debate state" do
37+
expect{
38+
perform_enqueued_jobs {
39+
described_class.perform_later(Date.tomorrow.iso8601)
40+
}
41+
}.to change{ petition.reload.debate_state }.from("scheduled").to("debated")
42+
end
2243
end
2344
end
2445

25-
context "when a petition is in the scheduled debate state and the debate date has passed" do
46+
context "for a petition with a scheduled debate date in the summer" do
2647
let(:petition) {
2748
FactoryGirl.build(:open_petition,
2849
debate_state: 'scheduled',
29-
scheduled_debate_date: Date.tomorrow
50+
scheduled_debate_date: "2016-06-29"
3051
)
3152
}
3253

54+
let(:open_at) { "2016-06-01T10:00:00Z".in_time_zone }
55+
3356
before do
34-
travel_to(2.days.ago) do
35-
petition.save
57+
travel_to(open_at) { petition.save }
58+
travel_to(now)
59+
end
60+
61+
after do
62+
travel_back
63+
end
64+
65+
context "and the debate date has not passed" do
66+
let(:now) { "2016-06-28T07:15:00Z".in_time_zone }
67+
68+
it "does not change the petition debate state" do
69+
expect{
70+
perform_enqueued_jobs {
71+
described_class.perform_later(Date.tomorrow.iso8601)
72+
}
73+
}.not_to change{ petition.reload.debate_state }
3674
end
3775
end
3876

39-
it "does close the petition" do
40-
expect{
41-
perform_enqueued_jobs {
42-
described_class.perform_later
43-
}
44-
}.to change{ petition.reload.debate_state }.from("scheduled").to("debated")
77+
context "and the debate date has passed" do
78+
let(:now) { "2016-06-29T07:15:00Z".in_time_zone }
79+
80+
it "does change the petition debate state" do
81+
expect{
82+
perform_enqueued_jobs {
83+
described_class.perform_later(Date.tomorrow.iso8601)
84+
}
85+
}.to change{ petition.reload.debate_state }.from("scheduled").to("debated")
86+
end
4587
end
4688
end
4789
end

0 commit comments

Comments
 (0)