Skip to content

Commit 5c8dd91

Browse files
committed
Fix flaky ItemizableUpdateService. Logic was order dependent and have removed the global Timecop freeze to be able to order Event entries.
1 parent bddc765 commit 5c8dd91

1 file changed

Lines changed: 39 additions & 40 deletions

File tree

spec/services/itemizable_update_service_spec.rb

Lines changed: 39 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
let(:item1) { create(:item, organization: organization, name: "My Item 1") }
66
let(:item2) { create(:item, organization: organization, name: "My Item 2") }
77
let(:item3) { create(:item, organization: organization, name: "My Item 3") }
8+
let(:two_days_ago) { 2.days.ago } # Store exact timestamp to be able to assert later
89
before(:each) do
910
TestInventory.create_inventory(storage_location.organization, {
1011
storage_location.id => {
@@ -18,12 +19,6 @@
1819
})
1920
end
2021

21-
around(:each) do |ex|
22-
freeze_time do
23-
ex.run
24-
end
25-
end
26-
2722
describe "increases" do
2823
let(:itemizable) do
2924
line_items = [
@@ -39,12 +34,12 @@
3934

4035
let(:attributes) do
4136
{
42-
issued_at: 2.days.ago,
37+
issued_at: two_days_ago,
4338
line_items_attributes: {"0": {item_id: item1.id, quantity: 2}, "1": {item_id: item2.id, quantity: 2}}
4439
}
4540
end
4641

47-
subject do
42+
def call_update_service
4843
described_class.call(itemizable: itemizable,
4944
params: attributes,
5045
event_class: DonationEvent)
@@ -53,19 +48,19 @@
5348
it "should update quantity in same storage location" do
5449
expect(storage_location.size).to eq(20)
5550
expect(new_storage_location.size).to eq(20)
56-
subject
51+
call_update_service
5752
expect(itemizable.reload.line_items.count).to eq(2)
5853
expect(itemizable.line_items.sum(&:quantity)).to eq(4)
5954
expect(storage_location.size).to eq(14)
6055
expect(new_storage_location.size).to eq(20)
61-
expect(itemizable.issued_at).to eq(2.days.ago)
56+
expect(itemizable.issued_at.to_fs(:db)).to eq(two_days_ago.to_fs(:db)) # Use to_fs to ignore nanosecond differences
6257
expect(UpdateExistingEvent.count).to eq(1)
6358
end
6459

6560
it "fails with a validation message for donation events with invalid issued_at" do
6661
attributes[:issued_at] = ""
6762

68-
expect { subject }.to raise_error do |e|
63+
expect { call_update_service }.to raise_error do |e|
6964
expect(e).to be_a(ActiveRecord::RecordInvalid)
7065
expect(e.message).to eq("Validation failed: Issue date can't be blank")
7166
end
@@ -75,7 +70,7 @@
7570
context "when there is no intervening audit" do
7671
it "should update quantity in different locations" do
7772
attributes[:storage_location_id] = new_storage_location.id
78-
subject
73+
call_update_service
7974
expect(itemizable.reload.line_items.count).to eq(2)
8075
expect(itemizable.line_items.sum(&:quantity)).to eq(4)
8176
expect(storage_location.size).to eq(10)
@@ -89,15 +84,15 @@
8984
"If you need to change the storage location, please delete this donation and create a new donation with the new storage location."
9085
create(:audit, :with_items, item: itemizable.items.first, organization: organization, storage_location: storage_location, status: "finalized")
9186
attributes[:storage_location_id] = new_storage_location.id
92-
expect { subject }.to raise_error(msg)
87+
expect { call_update_service }.to raise_error(msg)
9388
end
9489
end
9590
end
9691

9792
it "should raise an error if any item is inactive" do
9893
item1.update!(active: false)
9994
msg = "Update failed: The following items are currently inactive: My Item 1. Please reactivate them before continuing."
100-
expect { subject }.to raise_error(msg)
95+
expect { call_update_service }.to raise_error(msg)
10196
end
10297
end
10398

@@ -116,30 +111,30 @@
116111

117112
let(:attributes) do
118113
{
119-
issued_at: 2.days.ago,
114+
issued_at: two_days_ago,
120115
line_items_attributes: {"0": {item_id: item1.id, quantity: 2}, "1": {item_id: item2.id, quantity: 2}}
121116
}
122117
end
123118

124-
subject do
119+
def call_update_service
125120
described_class.call(itemizable: itemizable, params: attributes, event_class: DistributionEvent)
126121
end
127122

128123
it "should update quantity in same storage location" do
129124
expect(storage_location.size).to eq(20)
130125
expect(new_storage_location.size).to eq(20)
131-
subject
126+
call_update_service
132127
expect(itemizable.reload.line_items.count).to eq(2)
133128
expect(itemizable.line_items.sum(&:quantity)).to eq(4)
134129
expect(storage_location.size).to eq(26)
135130
expect(new_storage_location.size).to eq(20)
136-
expect(itemizable.issued_at).to eq(2.days.ago)
131+
expect(itemizable.issued_at.to_fs(:db)).to eq(two_days_ago.to_fs(:db)) # Use to_fs to ignore nanosecond differences
137132
end
138133

139134
it "fails with a validation message for distribution events with invalid issued_at" do
140135
attributes[:issued_at] = ""
141136

142-
expect { subject }.to raise_error do |e|
137+
expect { call_update_service }.to raise_error do |e|
143138
expect(e).to be_a(ActiveRecord::RecordInvalid)
144139
expect(e.message).to eq("Validation failed: Distribution date and time can't be blank")
145140
end
@@ -149,7 +144,7 @@
149144
context "when there is no intervening audit" do
150145
it "should update quantity in different locations" do
151146
attributes[:storage_location_id] = new_storage_location.id
152-
subject
147+
call_update_service
153148
expect(itemizable.reload.line_items.count).to eq(2)
154149
expect(itemizable.line_items.sum(&:quantity)).to eq(4)
155150
expect(storage_location.size).to eq(30)
@@ -163,15 +158,15 @@
163158
"If you need to change the storage location, please reclaim this distribution and create a new distribution from the new storage location."
164159
create(:audit, :with_items, item: itemizable.items.first, organization: organization, storage_location: storage_location, status: "finalized")
165160
attributes[:storage_location_id] = new_storage_location.id
166-
expect { subject }.to raise_error(msg)
161+
expect { call_update_service }.to raise_error(msg)
167162
end
168163
end
169164
end
170165

171166
it "should raise an error if any item is inactive" do
172167
item1.update!(active: false)
173168
msg = "Update failed: The following items are currently inactive: My Item 1. Please reactivate them before continuing."
174-
expect { subject }.to raise_error(msg)
169+
expect { call_update_service }.to raise_error(msg)
175170
end
176171
end
177172

@@ -188,12 +183,14 @@
188183
line_items: line_items,
189184
issued_at: 1.day.ago)
190185
end
186+
191187
let(:attributes) do
192188
{
193-
issued_at: 2.days.ago,
189+
issued_at: two_days_ago,
194190
line_items_attributes: {"0": {item_id: item1.id, quantity: 5}, "1": {item_id: item3.id, quantity: 50}}
195191
}
196192
end
193+
197194
it "should send an itemizable event if it already exists" do
198195
DonationEvent.publish(itemizable)
199196
expect(DonationEvent.count).to eq(1)
@@ -216,14 +213,8 @@
216213
expect(View::Inventory.total_inventory(organization.id)).to eq(75) # 40 - 5 (item1) - 10 (item2) + 50 (item3)
217214
end
218215
end
216+
219217
describe "with distributions" do
220-
before(:each) do
221-
TestInventory.create_inventory(storage_location.organization, {
222-
storage_location.id => {
223-
item3.id => 10
224-
}
225-
})
226-
end
227218
let(:itemizable) do
228219
line_items = [
229220
create(:line_item, item_id: item1.id, quantity: 5),
@@ -235,12 +226,22 @@
235226
line_items: line_items,
236227
issued_at: 1.day.ago)
237228
end
229+
238230
let(:attributes) do
239231
{
240-
issued_at: 2.days.ago,
232+
issued_at: two_days_ago,
241233
line_items_attributes: {"0": {item_id: item1.id, quantity: 2}, "1": {item_id: item3.id, quantity: 6}}
242234
}
243235
end
236+
237+
before(:each) do
238+
TestInventory.create_inventory(storage_location.organization, {
239+
storage_location.id => {
240+
item3.id => 10
241+
}
242+
})
243+
end
244+
244245
it "should send an itemizable event if it already exists" do
245246
DistributionEvent.publish(itemizable)
246247
expect(DistributionEvent.count).to eq(1)
@@ -264,10 +265,9 @@
264265
end
265266

266267
it "should raise an error if there is an intervening snapshot" do
267-
itemizable.save!
268-
travel(-1.week)
269-
SnapshotEvent.publish(organization)
270-
travel 1.week
268+
travel(-1.week) do
269+
SnapshotEvent.publish(organization)
270+
end
271271
itemizable.update!(created_at: 2.weeks.ago)
272272
expect do
273273
described_class.call(itemizable: itemizable, params: attributes, event_class: DistributionEvent)
@@ -276,16 +276,15 @@
276276

277277
it "should not raise an error if no inventory was changed" do
278278
no_change_attrs = {
279-
issued_at: 2.days.ago,
279+
issued_at: two_days_ago,
280280
line_items_attributes: {
281281
"0": {item_id: item1.id, quantity: 10},
282282
"1": {item_id: item2.id, quantity: 10}
283283
}
284284
}
285-
itemizable.save!
286-
travel(-1.week)
287-
SnapshotEvent.publish(organization)
288-
travel 1.week
285+
travel(-1.week) do
286+
SnapshotEvent.publish(organization)
287+
end
289288
itemizable.update!(created_at: 2.weeks.ago)
290289
expect do
291290
described_class.call(itemizable: itemizable, params: no_change_attrs, event_class: DistributionEvent)

0 commit comments

Comments
 (0)