Search code examples
ruby-on-railsrubyjobsrails-activejob

In what format is ActiveJob :at key


I am trying to understand in what format :at for ActiveJob is, so I can use assert_enqueued_with with :at parameter.

Currently I've got this test which passes:

tomorrow = 1.day.from_now.to_date
assert_enqueued_with(job: ActionMailer::DeliveryJob) do
  onboarding.start_onboarding
  job_date = ActiveJob::Base.queue_adapter.enqueued_jobs[0][:at]
  assert_equal tomorrow, Time.at(job_date).to_date
end

But then I've realised that assert_enqueued_with has :at parameter and I would prefer to use it instead of last two lines in the block. Problem is, tomorrow variable seems to be in a different format than :at, which makes this fail:

tomorrow = 1.day.from_now.to_date
assert_enqueued_with(job: ActionMailer::DeliveryJob, at: tomorrow) do
  onboarding.start_onboarding
end

with this error:

Minitest::Assertion: No enqueued job found with {:job=>ActionMailer::DeliveryJob, :at=>Wed, 31 May 2017 13:12:05 UTC +00:00}

As you can see, tomorrow is a date, say Wed, 31 May 2017, while job_date is some kind of a large number, say 1496236366.183789. Hence I am trying to convert tomorrow into the same format.

Would really appreciate some help with this. Perhaps I am using :at wrongly or you know what format :at in and help me convert tomorrow.

start_onboarding is just a AASM event, which calls this method to schedule email delivery (a bit modified for privacy reasons):

def notify(id)
  person = User.find(id) 
  PersonMailer.onboarding_reminder(person).
    deliver_later(wait_until: 1.day.from_now)
end

Solution

  • The argument for the wait_until method needs to match what your test uses. The date serialized into the queue does get turned into a float by rails. And in your #notify method, you're passing in a ActiveSupport::TimeWithZone instance when your test is passing in a Date instance.

    See here:

    1.day.from_now
    => Wed, 31 May 2017 13:56:36 UTC +00:00
    1.day.from_now.class
    => ActiveSupport::TimeWithZone
    1.day.from_now.to_date
    => Wed, 31 May 2017
    1.day.from_now.to_date.class
    => Date
    1.day.from_now == 1.day.from_now.to_date
    => false
    

    That means your job is getting enqueued with time information but your test is expecting a simple date. I'm not sure which is more correct the test date or the code date but they need to match for this test to pass.

    Per the comments, here's how you might use Timecop to help you out:

      tomorrow = 1.day.from_now.to_date
      Timecop.freeze(tomorrow)
      assert_enqueued_with(job: ActionMailer::DeliveryJob, at: tomorrow) do
        onboarding.start_onboarding
      end
      Timecop.return