Crystal: Failing test: HTTP::Cookie::Parser expired? by max-age=0

Created on 10 Apr 2020  路  18Comments  路  Source: crystal-lang/crystal

Hi,

Running the spec for the std I get the next broken test:

Failures:

  1) HTTP::Cookie::Parser expired? by max-age=0
     Failure/Error: parse_set_cookie("bla=1; max-age=0").expired?.should eq true

       Expected: true
            got: false

     # spec/std/http/cookie_spec.cr:215
bug stdlib

Most helpful comment

@RX14

For me, with this change, now the spec pass

All 18 comments

Hm, that seems strange. Possible cause could be a clock issue (low resolution for example) which results in Time.utc returning the same value when parsing max-age=0 and in expired? check.

Can you please share system info and Crystal version?
And what does 10.times { puts Time.utc.to_s("%Y-%m-%d %H:%M:%S.%N") } print?

version: 0.34.0
system: debian unstable (inside chroot)

2020-04-10 15:42:09.023243000
2020-04-10 15:42:09.023275000
2020-04-10 15:42:09.023291000
2020-04-10 15:42:09.023310000
2020-04-10 15:42:09.023319000
2020-04-10 15:42:09.023328000
2020-04-10 15:42:09.023337000
2020-04-10 15:42:09.023346000
2020-04-10 15:42:09.023355000
2020-04-10 15:42:09.023365000

Hi,

failed again:

Failures:

  1) HTTP::Cookie::Parser expired? by max-age=0
     Failure/Error: parse_set_cookie("bla=1; max-age=0").expired?.should eq true

       Expected: true
            got: false

     # spec/std/http/cookie_spec.cr:215

Finished in 30.41 seconds
9205 examples, 1 failures, 0 errors, 7 pending

Could you modify the spec so it shows why it fails? Specifically, print the current time and the cookie expiration time.

Is it a random failure or every time? @deiv

If it's non-deterministic it's probably an issue with the TSC counter (and thus all non-monotonic time) becoming non-monotonic due to spectre mitigations.

We should wait a small delta in the range of milliseconds before checking that it's expired, or apply a small negative delta to max-age, or treat max-age=0 differently.

Hi,

Totally reproducible (as I say. at least in a Debian unstable chroot).

If I add the next code to the spec, the spec passes:

- parse_set_cookie("bla=1; max-age=0").expired?.should eq true
+ cookie = parse_set_cookie("bla=1; max-age=0")
+ puts "cookie.expires"
+ puts cookie.expires.not_nil!.to_utc.to_s("%Y-%m-%d %H:%M:%S.%N")
+ puts "Time.utc"
+ puts Time.utc.to_s("%Y-%m-%d %H:%M:%S.%N")
+ cookie.expired?.should eq true
- parse_set_cookie("bla=1; max-age=0").expired?.should eq true

buiid log:

expired?
by max-age=0cookie.expires
2020-04-13 13:28:48.817609000
Time.utc
2020-04-13 13:28:48.817615000

Seems that the added code is letting the clock advance ...

Leaving untouched, the spec fails always.

What's the output of this:

puts Time.utc
cookie = parse_set_cookie("bla=1; max-age=0")
puts cookie.expires

@asterite

That's will give resolution until second not ? Is that you want ?

I forgot to say: If I run only the specific spec file inside the chroot, in any condifition it pass... I have to run all the std specs batery to expect the fail

Until we can understand why it fails, that is, until we can show what time values are failing, there's nothing we can do here.

@asterite

Eg: If I eval ./bin/crystal eval "puts Time.utc" it gives 2020-04-13 14:58:36 UTC, so we can only see the resolution until seconds, and there is some formatting execution meamwhile

Something like ?:

timeee = Time.utc
cookie = parse_set_cookie("bla=1; max-age=0")
puts timeee.nanosecond
puts cookie.expires.nanosecond

Taking care that we are in the same second ...

Yes, that sounds good. What's the output?

Maybe not just nanosecond, the formatting you used before is fine. But done like in your last snippet.

@asterite

yep, with the formatting better (nanoseconds was becuse the nerves of the live hehe)

Just running... waiting for the completion

Spec passed with:

cookie.expires

2020-04-13 16:10:28.754727000
Time.utc
2020-04-13 16:10:28.754726000

It's probably just the < instead of <= here: https://github.com/crystal-lang/crystal/blob/master/src/http/cookie.cr#L66

Time.utc easilly returns the same value multiple times: https://carc.in/#/r/8vrg

It's probably just the < instead of <= here: https://github.com/crystal-lang/crystal/blob/master/src/http/cookie.cr#L66

馃憤

I'd also write it like Time.utc >= e

I havent actually tested whether #9061 fixes this, so I'd like word if I was correct @deiv

@RX14

For me, with this change, now the spec pass

Was this page helpful?
0 / 5 - 0 ratings