catstodon/spec/models/concerns/remotable_spec.rb
Eugen Rochko 354fdd317e
Fix attachment not being re-downloaded even if file is not stored (#12125)
Change the behaviour of remotable concern. Previously, it would skip
downloading an attachment if the stored remote URL is identical to
the new one. Now it would not be skipped if the attachment is not
actually currently stored by Paperclip.
2019-10-09 07:10:46 +02:00

230 lines
6.9 KiB
Ruby

# frozen_string_literal: true
require 'rails_helper'
RSpec.describe Remotable do
class Foo
def initialize
@attrs = {}
end
def [](arg)
@attrs[arg]
end
def []=(arg1, arg2)
@attrs[arg1] = arg2
end
def hoge=(arg); end
def hoge_file_name; end
def hoge_file_name=(arg); end
def has_attribute?(arg); end
def self.attachment_definitions
{ hoge: nil }
end
end
context 'Remotable module is included' do
before do
class Foo
include Remotable
remotable_attachment :hoge, 1.kilobyte
end
end
let(:attribute_name) { "#{hoge}_remote_url".to_sym }
let(:code) { 200 }
let(:file) { 'filename="foo.txt"' }
let(:foo) { Foo.new }
let(:headers) { { 'content-disposition' => file } }
let(:hoge) { :hoge }
let(:url) { 'https://google.com' }
let(:request) do
stub_request(:get, url)
.to_return(status: code, headers: headers)
end
it 'defines a method #hoge_remote_url=' do
expect(foo).to respond_to(:hoge_remote_url=)
end
it 'defines a method #reset_hoge!' do
expect(foo).to respond_to(:reset_hoge!)
end
describe '#hoge_remote_url' do
before do
request
end
it 'always returns arg' do
[nil, '', [], {}].each do |arg|
expect(foo.hoge_remote_url = arg).to be arg
end
end
context 'Addressable::URI::InvalidURIError raised' do
it 'makes no request' do
allow(Addressable::URI).to receive_message_chain(:parse, :normalize)
.with(url).with(no_args).and_raise(Addressable::URI::InvalidURIError)
foo.hoge_remote_url = url
expect(request).not_to have_been_requested
end
end
context 'scheme is neither http nor https' do
let(:url) { 'ftp://google.com' }
it 'makes no request' do
foo.hoge_remote_url = url
expect(request).not_to have_been_requested
end
end
context 'parsed_url.host is empty' do
it 'makes no request' do
parsed_url = double(scheme: 'https', host: double(blank?: true))
allow(Addressable::URI).to receive_message_chain(:parse, :normalize)
.with(url).with(no_args).and_return(parsed_url)
foo.hoge_remote_url = url
expect(request).not_to have_been_requested
end
end
context 'parsed_url.host is nil' do
it 'makes no request' do
parsed_url = Addressable::URI.parse('https:https://example.com/path/file.png')
allow(Addressable::URI).to receive_message_chain(:parse, :normalize)
.with(url).with(no_args).and_return(parsed_url)
foo.hoge_remote_url = url
expect(request).not_to have_been_requested
end
end
context 'foo[attribute_name] == url' do
it 'makes no request if file is saved' do
allow(foo).to receive(:[]).with(attribute_name).and_return(url)
allow(foo).to receive(:hoge_file_name).and_return('foo.jpg')
foo.hoge_remote_url = url
expect(request).not_to have_been_requested
end
it 'makes request if file is not saved' do
allow(foo).to receive(:[]).with(attribute_name).and_return(url)
allow(foo).to receive(:hoge_file_name).and_return(nil)
foo.hoge_remote_url = url
expect(request).to have_been_requested
end
end
context "scheme is https, parsed_url.host isn't empty, and foo[attribute_name] != url" do
it 'makes a request' do
foo.hoge_remote_url = url
expect(request).to have_been_requested
end
context 'response.code != 200' do
let(:code) { 500 }
it 'calls not send' do
expect(foo).not_to receive(:send).with("#{hoge}=", any_args)
expect(foo).not_to receive(:send).with("#{hoge}_file_name=", any_args)
foo.hoge_remote_url = url
end
end
context 'response.code == 200' do
let(:code) { 200 }
context 'response contains headers["content-disposition"]' do
let(:file) { 'filename="foo.txt"' }
let(:headers) { { 'content-disposition' => file } }
it 'calls send' do
string_io = StringIO.new('')
extname = '.txt'
basename = '0123456789abcdef'
allow(SecureRandom).to receive(:hex).and_return(basename)
allow(StringIO).to receive(:new).with(anything).and_return(string_io)
expect(foo).to receive(:send).with("#{hoge}=", string_io)
expect(foo).to receive(:send).with("#{hoge}_file_name=", basename + extname)
foo.hoge_remote_url = url
end
end
context 'if has_attribute?' do
it 'calls foo[attribute_name] = url' do
allow(foo).to receive(:has_attribute?).with(attribute_name).and_return(true)
expect(foo).to receive('[]=').with(attribute_name, url)
foo.hoge_remote_url = url
end
end
context 'unless has_attribute?' do
it 'calls not foo[attribute_name] = url' do
allow(foo).to receive(:has_attribute?)
.with(attribute_name).and_return(false)
expect(foo).not_to receive('[]=').with(attribute_name, url)
foo.hoge_remote_url = url
end
end
end
context 'an error raised during the request' do
let(:request) { stub_request(:get, url).to_raise(error_class) }
error_classes = [
HTTP::TimeoutError,
HTTP::ConnectionError,
OpenSSL::SSL::SSLError,
Paperclip::Errors::NotIdentifiedByImageMagickError,
Addressable::URI::InvalidURIError,
]
error_classes.each do |error_class|
let(:error_class) { error_class }
it 'calls Rails.logger.debug' do
expect(Rails.logger).to receive(:debug).with(/^Error fetching remote #{hoge}: /)
foo.hoge_remote_url = url
end
end
end
end
end
describe '#reset_hoge!' do
context 'if url.blank?' do
it 'returns nil, without clearing foo[attribute_name] and calling #hoge_remote_url=' do
url = nil
expect(foo).not_to receive(:send).with(:hoge_remote_url=, url)
foo[attribute_name] = url
expect(foo.reset_hoge!).to be_nil
expect(foo[attribute_name]).to be_nil
end
end
context 'unless url.blank?' do
it 'clears foo[attribute_name] and calls #hoge_remote_url=' do
foo[attribute_name] = url
expect(foo).to receive(:send).with(:hoge_remote_url=, url)
foo.reset_hoge!
expect(foo[attribute_name]).to be ''
end
end
end
end
end