RSpec Time comparision fails locally, passes CircleCI and Heroku - ruby-on-rails

My rspec test fails on local machine between 6:00pm and 6:59pm, but passes at before 5:59pm and after 7:00pm on the local machine,
It seems to pass on CircleCI and Heroku, but I do not know if CircleCI or Heroku fail at specific times.
I set my local computer time to UTC, and it seems #subscription.current_period_end is incorrect by 1 hour.
I suspect it has something to do with how my local machine handles the time vs CircleCi and Heroku. Any ideas how to address this issue?
Code:
def get_proration_date
Time.zone.now.to_i
end
Application.rb
config.active_record.default_timezone = :utc
config.time_zone = "UTC"
Rspec
it "should create upcoming_invoice with existing plan for the next_month if there are no changes to subscription(Mock Version)", live: false do
create_stripe_elements
stripe_gold_plan
#subscription = payment_gateway.create_subscription(plan: silver_plan, user: user,
coupon_id: #coupon.stripe_id, source_id_or_token: default_card_token)
invoice = payment_gateway.upcoming_invoice_for_update_plan(subscription: #subscription, to_plan: silver_plan,
coupon_id: "", proration_date: get_proration_date)
expect(invoice.lines.total_count).to eql(1)
expect(invoice.amount_due).to eql(silver_plan.amount)
expect(invoice.total).to eql(silver_plan.amount)
expect(Time.zone.at(invoice.next_payment_attempt)).to eql(#subscription.current_period_end)
delete_stripe_elements
end
Error
Failure/Error: expect(Time.zone.at(invoice.next_payment_attempt)).to eql(#subscription.current_period_end)
expected: 2020-09-27 00:20:20.000000000 +0000
got: 2020-09-27 01:20:20.000000000 +0000
(compared using eql?)
Diff:
## -1,2 +1,2 ##
-Sun, 27 Sep 2020 00:20:20 UTC +00:00
+Sun, 27 Sep 2020 01:20:20 UTC +00:00

Most likely you have a bug in time calculations, potentially a time zone-related one.
Fire up pry or byebug on your local machine when the time comparison fails in the test and figure out which time is the correct one. Then figure out why the other time is wrong and fix that.

Suggest that you always store everything as UTC. Log timestamps, payment timestamps, audit dates, whatever. Do all your date and time calculations and intervals using the UTC values. That way you never ever have an issue with figuring out what happened, and the order in which it happened, even when your users are in different time zones, or they check out their shopping cart at 01:59:59 on the morning when you switch out of daylight saving time in the autumn. If you have a requirement to display dates and times to your users, this is a presentation issue and you can always convert the UTC values to their local timezone values for display purposes.

It was a stripe issue. They do not finalize an invoice until 1 hour after invoice is created, hence I needed to add an hour. #subscription.current_period_end+1.hour

Related

Time zone change on DateTime method (Rails 4.2.8)

I am trying to upgrade from rails 4.2.7 to 4.2.8 and found a case where the DateTime method of rails switches the time zone to local on reload from database which was not seen in rails 4.2.7. On rails 4.2.8, the unit test of my app rely on the DateTime method to get beginning of the year,
DateTime.new(2019,1,1,0,0,0)
Tue, 01 Jan 2019 00:00:00 +0000
This resultant value, is passed as part of an object to,
Class:Machinist::ActiveRecord::Blueprint where the reload happens.
def reload(options = nil)
clear_aggregation_cache
clear_association_cache
self.class.connection.clear_query_cache
fresh_object =
if options && options[:lock]
self.class.unscoped { self.class.lock(options[:lock]).find(id) }
else
self.class.unscoped { self.class.find(id) }
end
#attributes = fresh_object.instance_variable_get('#attributes')
#new_record = false
self
end
The instance_variable_get method at,
#attributes = fresh_object.instance_variable_get('#attributes')
switches the time zone on Rails 4.2.8 to local(Mon, 31st Dec 2018 16:00:00 -0800) but not on 4.2.7 where just the time zone is switched and not the time (Tue, 1st Jan 2019 00:00:00 -0800). A similar method, Time.new() has got no problem with this as the time zone is set to local by default,
Time.new(2019,1,1,0,0,0)
2019-01-01 00:00:00 -0800
Trying to pinpoint what changed on rails 4.2.8 that doesn't let the time zones persist to UTC for the DateTime method on the reload.
Any insights on this are helpful.
Thanks

Unison fails because it cannot set time stamp

Trying to sync from a mac to a linux machine, I get multiple failures with a message of the following type:
100% 00:00 ETAFailed [www/sandbox/my-vue-buefy-project/node_modules/spdy-transport/lib/spdy-transport/protocol/spdy]:
Failed to set modification time of file /users/guerrini/www/sandbox/my-vue-buefy-project/node_modules/spdy-transport/lib/spdy-transport/protocol/.unison.spdy.1db0b477154fc6ddf40346e8e27082da.unison.tmp/constants.js
to 1970-01-01 at 1:00:00 (0.000000):
the time was set to 2018-04-12 at 8:49:57 (1523515797.000000) instead`
It seems that it cannot set the modification time and that it uses the current time instead. But, unfortunately, after this the synchronisation of all the files with the above modification date fails.
Moreover, I have tried to set modification date to the given time by hand with "touch" and it works.

How can I make this Time assertion match perfectly with either Time, Date, or DateTime

I have an assertion in a test that looks like this:
assert_equals object.sent_at, Time.now
When I run this test, I keep getting an error that looks like this
--- expected
+++ actual
## -1 +1 ##
-Fri, 04 Mar 2016 18:57:47 UTC +00:00
+Fri, 04 Mar 2016
I've tried a few combinations to make this test pass.
My actual code updates the sent_at value with a Time.now but its not quite in the perfect format. It is close but not enough to pass. How can I make this test pass.
Here are some combinations I've tried in my assertions:
Time.now.utc
Date.today
Time.now
and a lot of to_time , to_datetime etc. How can I make the test pass?
Old but still valid... The output shows that the comparison is against UTC which would be Time.current
At this time you would probably use:
assert_in_delta object.sent_at, Time.current, 1
To tolerate <1 second difference
Using Time#to_i isn't the best solution. If the task you are running takes more than a second the comparison would fail. Even if your task is fast enough, this comparison would fail:
time = Time.now # 2018-04-18 3:00:00.990
# after 20ms
assert_equal Time.now.to_i, time.to_i # Fails
Time.now would be 2018-04-18 3:00:01.010 and to_i would give you 2018-04-18 3:00:01 and time was 2018-04-18 3:00:00.990 and to_i: 2018-04-18 3:00:00. So the assert fails.
So, sometimes the test would pass and others would fail, depending on when (in miliseconds) it starts.
The better solution is to freeze the Time. You could use a gem like Timecop or write your own code, like (using MiniTest):
current_time = Time.now
# You need Mocha gem to use #stubs
Time.stubs(:now).returns(current_time)
You can also use a block, so that after the block the clock is back to normal
# For this you don't need Mocha
Time.stub :now, current_time do # stub goes away once the block is done
assert your_task
end
I think it is easiest to use Time#to_i to compare the time in seconds.
assert_equals object.sent_at.to_i, Time.now.to_i # seconds
You can use Timecop gem: https://github.com/travisjeffery/timecop
def test
Timecop.freeze do # Freeze current time
Time.now # some value
...
Time.now # The same value as previous
end
end

Single Sign-on - PingfFederate - How to set the date?

I noticed when PingFederate(PF) sends the date it is off by a day from my Rails app. It appears that the PF date is the one off by a day. For example in the PF SAML response I get:
<saml:Assertion ID="pEaf1kce93SpAxfIpuohOv6QP-T" IssueInstant="2014-05-03T03:15:20.020Z" Version="2.0" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">
and
<saml:Conditions NotBefore="2014-05-03T03:10:20.021Z" NotOnOrAfter="2014-05-03T03:20:20.021Z">
whereas in Rails I get
Time.now = 2014-05-02 20:15:19 -0700
which makes me think that I need to set the date in PF. Note that PF is running on the same computer that the Rails app is running on.
Is there a way to set the date in PF?
The time is off as well. Is there a way in PF to set the time too?
SAML assertions are always in UTC. Which is what PingFed is using. Set your Rails application to use UTC as well.
I don't see why you think that the time is off. Your time from Rails is 2015 and -7. That means in UTC, it's tomorrow at 0315 - when it was issued. PingFed is setting an allowance of +/-5 minutes, so the SP should not accept it before 0310 or after 0320.
Your server and PingFed are correct so far...

How to update expiration time in MemCached using Dalli?

I'm using Ruby on Rails (v3.2.13), Dalli (v2.6.4) and MemCached (v1.4.13).
I do caching like this:
result = Rails.cache.fetch("test_key", :expires_in => 1.week) do
get_data() # slow call, result of which should be cached
end
I want to update cache expiration date based on the data, since some of my data can be kept longer.
Right now the following code does the job:
if keep_longer(result)
Rails.cache.write("test_key", result, :expires_in => 6.months)
end
I know that MemCached supports "touch" command that allows to update expiration date without sending the value. And I don't see how to use it through the Dalli gem. Is there a way to update expiration date without resending the result?
UPDATE:
Rails.cache.dalli.touch('some_key', 24.hours)
This should work, but for me it doesn't. Does it work for you?
Here is small example you can try. After execution of the following code in the IRB
dc = Dalli::Client.new("localhost:11211")
dc.set("test_key", "test_value", 5.minutes)
dc.set( "key", "value", 5.minutes)
dc.touch( "key", 10.minutes)
I'm checking the expiration dates using telnet:
telnet localhost 11211
Then given the correct slab_id and using "stats cachedump" command I obtain expiration times in seconds:
stats cachedump 1 0
ITEM key [9 b; 1375733492 s]
ITEM test_key [14 b; 1375905957 s]
Note that the expiration time of the key "key" points to the past. When I expect it to be 300 seconds later than "test_key" expiration time. Also I noticed that "key" expiration time is approximately 1 second before the MemCached server has started. Which probably indicates that this key has no expiration time. And in fact "key" doesn't get deleted in the near future.
Am I doing something wrong or it is a bug of Dalli/MemCached?
Dalli does support this - there's a touch method on Dalli::Client that does exactly what it says on the tin. Rails.cache returns a cache store rather than the underlying Dalli object so you need to do
Rails.cache.dalli.touch('some_key', 24.hours)
To bump the cache entry's expiry time by 24 hours (and of course memcache may decide to drop the entry anyway)
I found that my version of MemCached (v1.4.13) has the bug: binary touch operation did not update expiration time correctly. This bug was fixed in v1.4.14 (release notes):
Fixed issue with invalid binary protocol touch command expiration time
The problem now: as of today versions v1.4.14 and later cannot be installed using apt-get.

Resources