205 lines
		
	
	
	
		
			5.5 KiB
		
	
	
	
		
			Ruby
		
	
	
	
	
	
			
		
		
	
	
			205 lines
		
	
	
	
		
			5.5 KiB
		
	
	
	
		
			Ruby
		
	
	
	
	
	
| # frozen_string_literal: true
 | |
| 
 | |
| require 'rails_helper'
 | |
| 
 | |
| RSpec.describe Remotable do
 | |
|   let(:foo_class) do
 | |
|     Class.new do
 | |
|       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
 | |
|   end
 | |
| 
 | |
|   let(:attribute_name) { "#{hoge}_remote_url".to_sym }
 | |
|   let(:code)           { 200 }
 | |
|   let(:file)           { 'filename="foo.txt"' }
 | |
|   let(:foo)            { foo_class.new }
 | |
|   let(:headers)        { { 'content-disposition' => file } }
 | |
|   let(:hoge)           { :hoge }
 | |
|   let(:url)            { 'https://google.com' }
 | |
| 
 | |
|   before do
 | |
|     foo_class.include described_class
 | |
|     foo_class.remotable_attachment :hoge, 1.kilobyte
 | |
|   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
 | |
| 
 | |
|   it 'defines a method #download_hoge!' do
 | |
|     expect(foo).to respond_to(:download_hoge!)
 | |
|   end
 | |
| 
 | |
|   describe '#hoge_remote_url=' do
 | |
|     before do
 | |
|       stub_request(:get, url).to_return(status: code, headers: headers)
 | |
|     end
 | |
| 
 | |
|     it 'always returns its argument' do
 | |
|       [nil, '', [], {}].each do |arg|
 | |
|         expect(foo.hoge_remote_url = arg).to be arg
 | |
|       end
 | |
|     end
 | |
| 
 | |
|     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
 | |
|         foo.hoge_remote_url = url
 | |
|         expect(a_request(:get, url)).to_not have_been_made
 | |
|       end
 | |
|     end
 | |
| 
 | |
|     context 'with scheme that is neither http nor https' do
 | |
|       let(:url) { 'ftp://google.com' }
 | |
| 
 | |
|       it 'makes no request' do
 | |
|         foo.hoge_remote_url = url
 | |
|         expect(a_request(:get, url)).to_not have_been_made
 | |
|       end
 | |
|     end
 | |
| 
 | |
|     context 'with relative URL' do
 | |
|       let(:url) { 'https:///path' }
 | |
| 
 | |
|       it 'makes no request' do
 | |
|         foo.hoge_remote_url = url
 | |
|         expect(a_request(:get, url)).to_not have_been_made
 | |
|       end
 | |
|     end
 | |
| 
 | |
|     context 'when URL has not changed' do
 | |
|       it 'makes no request if file is already 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(a_request(:get, url)).to_not have_been_made
 | |
|       end
 | |
| 
 | |
|       it 'makes request if file is not already 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(a_request(:get, url)).to have_been_made
 | |
|       end
 | |
|     end
 | |
| 
 | |
|     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
 | |
|         foo.hoge_remote_url = url
 | |
|         expect(a_request(:get, url)).to have_been_made
 | |
|       end
 | |
| 
 | |
|       context 'when the response is not successful' do
 | |
|         let(:code) { 500 }
 | |
| 
 | |
|         it 'does not assign file' do
 | |
|           expect(foo).to_not receive(:public_send).with("#{hoge}=", any_args)
 | |
|           expect(foo).to_not receive(:public_send).with("#{hoge}_file_name=", any_args)
 | |
| 
 | |
|           foo.hoge_remote_url = url
 | |
|         end
 | |
|       end
 | |
| 
 | |
|       context 'when the response is successful' do
 | |
|         let(:code) { 200 }
 | |
| 
 | |
|         context 'when contains Content-Disposition header' do
 | |
|           let(:file)      { 'filename="foo.txt"' }
 | |
|           let(:headers)   { { 'content-disposition' => file } }
 | |
| 
 | |
|           it 'assigns file' do
 | |
|             response_with_limit = ResponseWithLimit.new(nil, 0)
 | |
| 
 | |
|             allow(ResponseWithLimit).to receive(:new).with(anything, anything).and_return(response_with_limit)
 | |
| 
 | |
|             expect(foo).to receive(:public_send).with("download_#{hoge}!", url)
 | |
| 
 | |
|             foo.hoge_remote_url = url
 | |
| 
 | |
|             expect(foo).to receive(:public_send).with("#{hoge}=", response_with_limit)
 | |
| 
 | |
|             foo.download_hoge!(url)
 | |
|           end
 | |
|         end
 | |
|       end
 | |
| 
 | |
|       context 'when an error is raised during the request' do
 | |
|         before do
 | |
|           stub_request(:get, url).to_raise(error_class)
 | |
|         end
 | |
| 
 | |
|         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) do |&block|
 | |
|               expect(block.call).to match(/^Error fetching remote #{hoge}: /)
 | |
|             end
 | |
|             foo.hoge_remote_url = url
 | |
|           end
 | |
|         end
 | |
|       end
 | |
|     end
 | |
|   end
 | |
| end
 |