Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prevent ActiveJob::DeserializationError when looking for active jobs with specific arguments in the queue #2036

Conversation

aymeric-ledorze
Copy link
Contributor

When running a test expecting to find active jobs in the queue with specific arguments, the have_enqueued_job.with and have_been_enqueued.with matchers will iterate over each queued active jobs, deserialize its arguments and check if it matches the expected value. However, the deserialization of some arguments may raise an ActiveJob::DeserializationError, for example for jobs having destroyed active records as arguments.
This is an issue since some active jobs may be generated by some code that we are not testing but will make our test fail since we have to deserialize their arguments anyway.

This PR prevents this crash from happening by rescuing all the raised ActiveJob::DeserializationError in the matcher when deserializing arguments. This operation is done at 3 different places:

  • when checking if a job arguments match the arguments specified in with(), if there is a deserialization error, return false
  • when passing arguments to the with block, if there is a deserialization error, pass an empty array
  • when displaying all queued jobs, if there is a deserialization error, print the serialized value

…ith specific arguments if one of the active jobs in the queue have undeserializable arguments
@@ -169,6 +173,10 @@ def set_expected_number(relativity, count)
end
end

def deserialize_arguments(job)
::ActiveJob::Arguments.deserialize(job[:args]) rescue nil
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we can't deserialize the args, the most we should do is return the original args.

if deserialized_args
RSpec::Mocks::ArgumentListMatcher.new(*@args).args_match?(*deserialized_args)
else
false
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we return the original arguments we avoid the if

@@ -98,7 +98,7 @@ def supports_block_expectations?
def check(jobs)
@matching_jobs, @unmatching_jobs = jobs.partition do |job|
if arguments_match?(job) && other_attributes_match?(job)
args = ::ActiveJob::Arguments.deserialize(job[:args])
args = deserialize_arguments(job) || []
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't need an || [] if we leave the original args as a replacement

@@ -125,7 +125,7 @@ def base_message

def base_job_message(job)
msg_parts = []
msg_parts << "with #{::ActiveJob::Arguments.deserialize(job[:args])}" if job[:args].any?
msg_parts << "with #{deserialize_arguments(job) || job[:args].inspect}" if job[:args].any?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This also won't need the || if we return the original args

@@ -169,6 +169,10 @@ def set_expected_number(relativity, count)
end
end

def deserialize_arguments(job)
::ActiveJob::Arguments.deserialize(job[:args]) rescue job[:args]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't we want to only rescue ActiveJob::DeserializationError?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, yes we do.

::ActiveJob::Arguments.deserialize(job[:args])
rescue ::ActiveJob::DeserializationError
job[:args]
end
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can use the inline form of rescue here:

def deserialize_arguments(job)
  ::ActiveJob::Arguments.deserialize(job[:args])
rescue ::ActiveJob::DeserializationError
  job[:args]
end

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In fact you'll need to in order to satisfy Rubocop!

@benoittgt
Copy link
Member

After this #2036 (comment)

LGTM 🎉

Thanks for the PR

@JonRowe
Copy link
Member

JonRowe commented Oct 23, 2018

Thanks, will merge when green

@JonRowe JonRowe merged commit 9d7c82f into rspec:master Oct 23, 2018
JonRowe added a commit that referenced this pull request Oct 23, 2018
JonRowe pushed a commit that referenced this pull request Oct 23, 2018
…bs (#2036)

Prevents an exception from being raised when looking for an ActiveJob with specific arguments if one or more of the active jobs in the queue have arguments that cannot be deserialised (e.g. if the record has now been deleted).
JonRowe added a commit that referenced this pull request Oct 23, 2018
sebjacobs pushed a commit to futurelearn/rspec-rails that referenced this pull request Mar 15, 2019
…bs (rspec#2036)

Prevents an exception from being raised when looking for an ActiveJob with specific arguments if one or more of the active jobs in the queue have arguments that cannot be deserialised (e.g. if the record has now been deleted).
sebjacobs pushed a commit to futurelearn/rspec-rails that referenced this pull request Mar 15, 2019
benoittgt pushed a commit to benoittgt/rspec-rails that referenced this pull request May 1, 2019
…bs (rspec#2036)

Prevents an exception from being raised when looking for an ActiveJob with specific arguments if one or more of the active jobs in the queue have arguments that cannot be deserialised (e.g. if the record has now been deleted).
benoittgt pushed a commit to benoittgt/rspec-rails that referenced this pull request May 1, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants