forked from asonix/mastodon
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.
230 lines
6.9 KiB
Ruby
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
|