Fix trying to write non-existent image remote URL attribute on preview cards (#14181)

Regression from #14145
This commit is contained in:
Eugen Rochko 2020-06-29 17:59:04 +02:00 committed by GitHub
parent fa183a51ab
commit 1b198d6489
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 152 additions and 145 deletions

View File

@ -7,8 +7,8 @@ module Remotable
def remotable_attachment(attachment_name, limit, suppress_errors: true, download_on_assign: true, attribute_name: nil) def remotable_attachment(attachment_name, limit, suppress_errors: true, download_on_assign: true, attribute_name: nil)
attribute_name ||= "#{attachment_name}_remote_url".to_sym attribute_name ||= "#{attachment_name}_remote_url".to_sym
define_method("download_#{attachment_name}!") do define_method("download_#{attachment_name}!") do |url = nil|
url = self[attribute_name] url ||= self[attribute_name]
return if url.blank? return if url.blank?
@ -51,9 +51,9 @@ module Remotable
define_method("#{attribute_name}=") do |url| define_method("#{attribute_name}=") do |url|
return if self[attribute_name] == url && public_send("#{attachment_name}_file_name").present? return if self[attribute_name] == url && public_send("#{attachment_name}_file_name").present?
self[attribute_name] = url self[attribute_name] = url if has_attribute?(attribute_name)
public_send("download_#{attachment_name}!") if download_on_assign public_send("download_#{attachment_name}!", url) if download_on_assign
end end
alias_method("reset_#{attachment_name}!", "download_#{attachment_name}!") alias_method("reset_#{attachment_name}!", "download_#{attachment_name}!")

View File

@ -29,10 +29,10 @@ RSpec.describe Remotable do
end end
end end
context 'Remotable module is included' do
before do before do
class Foo class Foo
include Remotable include Remotable
remotable_attachment :hoge, 1.kilobyte remotable_attachment :hoge, 1.kilobyte
end end
end end
@ -45,11 +45,6 @@ RSpec.describe Remotable do
let(:hoge) { :hoge } let(:hoge) { :hoge }
let(:url) { 'https://google.com' } 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 it 'defines a method #hoge_remote_url=' do
expect(foo).to respond_to(:hoge_remote_url=) expect(foo).to respond_to(:hoge_remote_url=)
end end
@ -64,98 +59,109 @@ RSpec.describe Remotable do
describe '#hoge_remote_url=' do describe '#hoge_remote_url=' do
before do before do
request stub_request(:get, url).to_return(status: code, headers: headers)
end end
it 'always returns arg' do it 'always returns its argument' do
[nil, '', [], {}].each do |arg| [nil, '', [], {}].each do |arg|
expect(foo.hoge_remote_url = arg).to be arg expect(foo.hoge_remote_url = arg).to be arg
end end
end end
context 'Addressable::URI::InvalidURIError raised' do context 'with an invalid URL' do
before do
allow(Addressable::URI).to receive_message_chain(:parse, :normalize).with(url).with(no_args).and_raise(Addressable::URI::InvalidURIError)
end
it 'makes no request' 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 foo.hoge_remote_url = url
expect(request).not_to have_been_requested expect(a_request(:get, url)).to_not have_been_made
end end
end end
context 'scheme is neither http nor https' do context 'with scheme that is neither http nor https' do
let(:url) { 'ftp://google.com' } let(:url) { 'ftp://google.com' }
it 'makes no request' do it 'makes no request' do
foo.hoge_remote_url = url foo.hoge_remote_url = url
expect(request).not_to have_been_requested expect(a_request(:get, url)).to_not have_been_made
end end
end end
context 'parsed_url.host is empty' do context 'with relative URL' do
let(:url) { 'https:///path' }
it 'makes no request' 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 foo.hoge_remote_url = url
expect(request).not_to have_been_requested expect(a_request(:get, url)).to_not have_been_made
end end
end end
context 'parsed_url.host is nil' do context 'when URL has not changed' do
it 'makes no request' do it 'makes no request if file is already saved' 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(:[]).with(attribute_name).and_return(url)
allow(foo).to receive(:hoge_file_name).and_return('foo.jpg') allow(foo).to receive(:hoge_file_name).and_return('foo.jpg')
foo.hoge_remote_url = url foo.hoge_remote_url = url
expect(request).not_to have_been_requested expect(a_request(:get, url)).to_not have_been_made
end end
it 'makes request if file is not saved' do it 'makes request if file is not already saved' do
allow(foo).to receive(:[]).with(attribute_name).and_return(url) allow(foo).to receive(:[]).with(attribute_name).and_return(url)
allow(foo).to receive(:hoge_file_name).and_return(nil) allow(foo).to receive(:hoge_file_name).and_return(nil)
foo.hoge_remote_url = url foo.hoge_remote_url = url
expect(request).to have_been_requested expect(a_request(:get, url)).to have_been_made
end end
end end
context "scheme is https, parsed_url.host isn't empty, and foo[attribute_name] != url" do context 'when instance has no attribute for URL' do
before do
allow(foo).to receive(:has_attribute?).with(attribute_name).and_return(false)
end
it 'does not try to write attribute' do
expect(foo).to_not receive('[]=').with(attribute_name, url)
foo.hoge_remote_url = url
end
end
context 'when instance has an attribute for URL' do
before do
allow(foo).to receive(:has_attribute?).with(attribute_name).and_return(true)
end
it 'does not try to write attribute' do
expect(foo).to receive('[]=').with(attribute_name, url)
foo.hoge_remote_url = url
end
end
context 'with a valid URL' do
it 'makes a request' do it 'makes a request' do
foo.hoge_remote_url = url foo.hoge_remote_url = url
expect(request).to have_been_requested expect(a_request(:get, url)).to have_been_made
end end
context 'response.code != 200' do context 'when the response is not successful' do
let(:code) { 500 } let(:code) { 500 }
it 'calls not send' do it 'does not assign file' do
expect(foo).not_to receive(:public_send).with("#{hoge}=", any_args) expect(foo).not_to receive(:public_send).with("#{hoge}=", any_args)
expect(foo).not_to receive(:public_send).with("#{hoge}_file_name=", any_args) expect(foo).not_to receive(:public_send).with("#{hoge}_file_name=", any_args)
foo.hoge_remote_url = url foo.hoge_remote_url = url
end end
end end
context 'response.code == 200' do context 'when the response is successful' do
let(:code) { 200 } let(:code) { 200 }
context 'response contains headers["content-disposition"]' do context 'and contains Content-Disposition header' do
let(:file) { 'filename="foo.txt"' } let(:file) { 'filename="foo.txt"' }
let(:headers) { { 'content-disposition' => file } } let(:headers) { { 'content-disposition' => file } }
it 'calls send' do it 'assigns file' do
string_io = StringIO.new('') string_io = StringIO.new('')
extname = '.txt' extname = '.txt'
basename = '0123456789abcdef' basename = '0123456789abcdef'
@ -163,20 +169,22 @@ RSpec.describe Remotable do
allow(SecureRandom).to receive(:hex).and_return(basename) allow(SecureRandom).to receive(:hex).and_return(basename)
allow(StringIO).to receive(:new).with(anything).and_return(string_io) allow(StringIO).to receive(:new).with(anything).and_return(string_io)
expect(foo).to receive(:public_send).with("download_#{hoge}!") expect(foo).to receive(:public_send).with("download_#{hoge}!", url)
foo.hoge_remote_url = url foo.hoge_remote_url = url
expect(foo).to receive(:public_send).with("#{hoge}=", string_io) expect(foo).to receive(:public_send).with("#{hoge}=", string_io)
expect(foo).to receive(:public_send).with("#{hoge}_file_name=", basename + extname) expect(foo).to receive(:public_send).with("#{hoge}_file_name=", basename + extname)
foo.download_hoge! foo.download_hoge!(url)
end end
end end
end end
context 'an error raised during the request' do context 'when an error is raised during the request' do
let(:request) { stub_request(:get, url).to_raise(error_class) } before do
stub_request(:get, url).to_raise(error_class)
end
error_classes = [ error_classes = [
HTTP::TimeoutError, HTTP::TimeoutError,
@ -198,4 +206,3 @@ RSpec.describe Remotable do
end end
end end
end end
end