remotable_spec.rb 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. # frozen_string_literal: true
  2. require 'rails_helper'
  3. RSpec.describe Remotable do
  4. class Foo
  5. def initialize
  6. @attrs = {}
  7. end
  8. def [](arg)
  9. @attrs[arg]
  10. end
  11. def []=(arg1, arg2)
  12. @attrs[arg1] = arg2
  13. end
  14. def hoge=(arg); end
  15. def hoge_file_name; end
  16. def hoge_file_name=(arg); end
  17. def has_attribute?(arg); end
  18. def self.attachment_definitions
  19. { hoge: nil }
  20. end
  21. end
  22. context 'Remotable module is included' do
  23. before do
  24. class Foo
  25. include Remotable
  26. remotable_attachment :hoge, 1.kilobyte
  27. end
  28. end
  29. let(:attribute_name) { "#{hoge}_remote_url".to_sym }
  30. let(:code) { 200 }
  31. let(:file) { 'filename="foo.txt"' }
  32. let(:foo) { Foo.new }
  33. let(:headers) { { 'content-disposition' => file } }
  34. let(:hoge) { :hoge }
  35. let(:url) { 'https://google.com' }
  36. let(:request) do
  37. stub_request(:get, url)
  38. .to_return(status: code, headers: headers)
  39. end
  40. it 'defines a method #hoge_remote_url=' do
  41. expect(foo).to respond_to(:hoge_remote_url=)
  42. end
  43. it 'defines a method #reset_hoge!' do
  44. expect(foo).to respond_to(:reset_hoge!)
  45. end
  46. describe '#hoge_remote_url' do
  47. before do
  48. request
  49. end
  50. it 'always returns arg' do
  51. [nil, '', [], {}].each do |arg|
  52. expect(foo.hoge_remote_url = arg).to be arg
  53. end
  54. end
  55. context 'Addressable::URI::InvalidURIError raised' do
  56. it 'makes no request' do
  57. allow(Addressable::URI).to receive_message_chain(:parse, :normalize)
  58. .with(url).with(no_args).and_raise(Addressable::URI::InvalidURIError)
  59. foo.hoge_remote_url = url
  60. expect(request).not_to have_been_requested
  61. end
  62. end
  63. context 'scheme is neither http nor https' do
  64. let(:url) { 'ftp://google.com' }
  65. it 'makes no request' do
  66. foo.hoge_remote_url = url
  67. expect(request).not_to have_been_requested
  68. end
  69. end
  70. context 'parsed_url.host is empty' do
  71. it 'makes no request' do
  72. parsed_url = double(scheme: 'https', host: double(blank?: true))
  73. allow(Addressable::URI).to receive_message_chain(:parse, :normalize)
  74. .with(url).with(no_args).and_return(parsed_url)
  75. foo.hoge_remote_url = url
  76. expect(request).not_to have_been_requested
  77. end
  78. end
  79. context 'parsed_url.host is nil' do
  80. it 'makes no request' do
  81. parsed_url = Addressable::URI.parse('https:https://example.com/path/file.png')
  82. allow(Addressable::URI).to receive_message_chain(:parse, :normalize)
  83. .with(url).with(no_args).and_return(parsed_url)
  84. foo.hoge_remote_url = url
  85. expect(request).not_to have_been_requested
  86. end
  87. end
  88. context 'foo[attribute_name] == url' do
  89. it 'makes no request if file is saved' do
  90. allow(foo).to receive(:[]).with(attribute_name).and_return(url)
  91. allow(foo).to receive(:hoge_file_name).and_return('foo.jpg')
  92. foo.hoge_remote_url = url
  93. expect(request).not_to have_been_requested
  94. end
  95. it 'makes request if file is not saved' do
  96. allow(foo).to receive(:[]).with(attribute_name).and_return(url)
  97. allow(foo).to receive(:hoge_file_name).and_return(nil)
  98. foo.hoge_remote_url = url
  99. expect(request).to have_been_requested
  100. end
  101. end
  102. context "scheme is https, parsed_url.host isn't empty, and foo[attribute_name] != url" do
  103. it 'makes a request' do
  104. foo.hoge_remote_url = url
  105. expect(request).to have_been_requested
  106. end
  107. context 'response.code != 200' do
  108. let(:code) { 500 }
  109. it 'calls not send' do
  110. expect(foo).not_to receive(:send).with("#{hoge}=", any_args)
  111. expect(foo).not_to receive(:send).with("#{hoge}_file_name=", any_args)
  112. foo.hoge_remote_url = url
  113. end
  114. end
  115. context 'response.code == 200' do
  116. let(:code) { 200 }
  117. context 'response contains headers["content-disposition"]' do
  118. let(:file) { 'filename="foo.txt"' }
  119. let(:headers) { { 'content-disposition' => file } }
  120. it 'calls send' do
  121. string_io = StringIO.new('')
  122. extname = '.txt'
  123. basename = '0123456789abcdef'
  124. allow(SecureRandom).to receive(:hex).and_return(basename)
  125. allow(StringIO).to receive(:new).with(anything).and_return(string_io)
  126. expect(foo).to receive(:send).with("#{hoge}=", string_io)
  127. expect(foo).to receive(:send).with("#{hoge}_file_name=", basename + extname)
  128. foo.hoge_remote_url = url
  129. end
  130. end
  131. context 'if has_attribute?' do
  132. it 'calls foo[attribute_name] = url' do
  133. allow(foo).to receive(:has_attribute?).with(attribute_name).and_return(true)
  134. expect(foo).to receive('[]=').with(attribute_name, url)
  135. foo.hoge_remote_url = url
  136. end
  137. end
  138. context 'unless has_attribute?' do
  139. it 'calls not foo[attribute_name] = url' do
  140. allow(foo).to receive(:has_attribute?)
  141. .with(attribute_name).and_return(false)
  142. expect(foo).not_to receive('[]=').with(attribute_name, url)
  143. foo.hoge_remote_url = url
  144. end
  145. end
  146. end
  147. context 'an error raised during the request' do
  148. let(:request) { stub_request(:get, url).to_raise(error_class) }
  149. error_classes = [
  150. HTTP::TimeoutError,
  151. HTTP::ConnectionError,
  152. OpenSSL::SSL::SSLError,
  153. Paperclip::Errors::NotIdentifiedByImageMagickError,
  154. Addressable::URI::InvalidURIError,
  155. ]
  156. error_classes.each do |error_class|
  157. let(:error_class) { error_class }
  158. it 'calls Rails.logger.debug' do
  159. expect(Rails.logger).to receive(:debug).with(/^Error fetching remote #{hoge}: /)
  160. foo.hoge_remote_url = url
  161. end
  162. end
  163. end
  164. end
  165. end
  166. describe '#reset_hoge!' do
  167. context 'if url.blank?' do
  168. it 'returns nil, without clearing foo[attribute_name] and calling #hoge_remote_url=' do
  169. url = nil
  170. expect(foo).not_to receive(:send).with(:hoge_remote_url=, url)
  171. foo[attribute_name] = url
  172. expect(foo.reset_hoge!).to be_nil
  173. expect(foo[attribute_name]).to be_nil
  174. end
  175. end
  176. context 'unless url.blank?' do
  177. it 'clears foo[attribute_name] and calls #hoge_remote_url=' do
  178. foo[attribute_name] = url
  179. expect(foo).to receive(:send).with(:hoge_remote_url=, url)
  180. foo.reset_hoge!
  181. expect(foo[attribute_name]).to be ''
  182. end
  183. end
  184. end
  185. end
  186. end