Mail::Message#== does not work when on the cusp between two seconds
- Dominant language
- Ruby
- Stars
- 3.7k
- Forks
- 934
- PR merge metrics
- No merged PRs in 30d
Description
I was scratching my head over a strange RSpec test failure for a while:
```
Failure/Error: expect(subject).to eq(mail_obj)
expected: #
got: #
(compared using ==)
Diff:
(Diff is actually empty) # I wrote this line myself
```
Note that the object_ids are the same for "expected" and "got".
I'm pretty sure it's this line in `def ==(other)`
```ruby
dup.tap { |m| m.message_id = '' }.encoded ==
other.dup.tap { |m| m.message_id = '' }.encoded
```
I think that `dup.tap { |m| m.message_id = '' }.encoded` was evaluated right at the end of a second, and `other.dup.tap { |m| m.message_id = '' }.encoded` was evaluated right at the start of the next second. This would explain the failure.
Further evidence:
```ruby
m = Mail::Message.new
Timecop.scale(1000) { m == m } # Evaluates to false
m == m # Evaluates to true
(1..10000).to_a.reject { |_index| m == m } # This evaluated to [12, 5013, 5928, 7780] for me
# Second to make sure it wasn't a fluke
(1..10000).to_a.reject { |_index| m == m } # This evaluated to [1022, 2717, 4377, 5292, 6012] for me
# This returns empty array
Timecop.freeze(Time.now) do
(1..10000).to_a.reject { |_index| m == m }
end
```
Contributor guide
Research direction
Start at Mail::Message#==, particularly the two encoded comparisons shown in the issue. Reproduce the failure with Timecop.scale or verify the stable behavior with Timecop.freeze. Done means comparing a message with itself remains true across the second boundary and the reported RSpec equality failure is resolved.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- ruby
- Domain
- backend
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100