I'm having trouble stubbing Aws::S3::Object#exists? in some tests. Can you help point me in the right direction?
# In irb console, `irb -raws-sdk`
# Setup stubbing for S3 HeadObject
# NB that 'NoSuchKey' is the error returned by S3's HeadObject call: http://git.io/vzfWF
Aws.config.merge!(stub_responses: true, s3: {stub_responses: {head_object: "NoSuckKey" }})
# Test an object's existence via a bucket
Aws::S3::Object.new(key: 'k', bucket_name: 'b').exists?
The actual behavior (as of the current version 2.2.10) is that it raises an Aws::S3::Errors::NoSuckKey error.
I'd expect this to return false without raising an error, since that's the behavior when not stubbing; and I've stubbed out the API response to be the same as when the object doesn't exist.
I tried to track this down further, but got stuck trying to figure out how the Aws::S3::Errors::NoSuckKey gets turned into a Waiters::Errors::WaiterFailed that's rescued by Resource#exists?.
Any tips for how to stub Resource#exists?
Thanks for all your awesome work. :smile:
The bucket exists waiters is checking for a 404 status code, not a specific error code. The HTTP spec requires the the response to a HEAD request not contain a body. Since Amazon S3 normally returns error codes and messages in the body, the HEAD response becomes a simple HTTP 404 not found.
This is where things break down. The client response stubbing interface for errors cheats a little and assumes that the status code is a 400 for all stubbed response. This is largely because we don't have an exhaustive list of errors and their status codes. This could be improved with what we do know, but currently it does not. To make things more difficult, we do have have sufficient information from the status code to disambiguate between NoSuchKey and NoSuchBucket 404 errors.
That said, you can achieve what you require, but it is small bit of extra work.
Aws.config[:s3] = {
stub_responses: {
head_object: { status_code: 404, headers: {}, body: '', }
}
}
Aws::S3::Object.new(key: 'k', bucket_name: 'b').exists?
#=> false
Hope this helps.
That works like a charm. Thanks for explaining, @trevorrowe!
It is helpful, but it always returns false, no matter what the key is. How can I make the #exist? depend on the key parameter? What if I want it to return true based on a stubbed existing object?
@dominikdarnel You can check out my comment on this issue
Most helpful comment
The bucket exists waiters is checking for a 404 status code, not a specific error code. The HTTP spec requires the the response to a HEAD request not contain a body. Since Amazon S3 normally returns error codes and messages in the body, the HEAD response becomes a simple HTTP 404 not found.
This is where things break down. The client response stubbing interface for errors cheats a little and assumes that the status code is a 400 for all stubbed response. This is largely because we don't have an exhaustive list of errors and their status codes. This could be improved with what we do know, but currently it does not. To make things more difficult, we do have have sufficient information from the status code to disambiguate between NoSuchKey and NoSuchBucket 404 errors.
That said, you can achieve what you require, but it is small bit of extra work.
Hope this helps.