remotable_spec.rb 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. # frozen_string_literal: true
  2. require 'rails_helper'
  3. RSpec.describe Remotable do
  4. let(:foo_class) do
  5. Class.new do
  6. def initialize
  7. @attrs = {}
  8. end
  9. def [](arg)
  10. @attrs[arg]
  11. end
  12. def []=(arg1, arg2)
  13. @attrs[arg1] = arg2
  14. end
  15. def hoge=(arg); end
  16. def hoge_file_name; end
  17. def hoge_file_name=(arg); end
  18. def has_attribute?(arg); end
  19. def self.attachment_definitions
  20. { hoge: nil }
  21. end
  22. end
  23. end
  24. let(:attribute_name) { :"#{hoge}_remote_url" }
  25. let(:code) { 200 }
  26. let(:file) { 'filename="foo.txt"' }
  27. let(:foo) { foo_class.new }
  28. let(:headers) { { 'content-disposition' => file } }
  29. let(:hoge) { :hoge }
  30. let(:url) { 'https://google.com' }
  31. before do
  32. foo_class.include described_class
  33. foo_class.remotable_attachment :hoge, 1.kilobyte
  34. end
  35. it 'defines a method #hoge_remote_url=' do
  36. expect(foo).to respond_to(:hoge_remote_url=)
  37. end
  38. it 'defines a method #reset_hoge!' do
  39. expect(foo).to respond_to(:reset_hoge!)
  40. end
  41. it 'defines a method #download_hoge!' do
  42. expect(foo).to respond_to(:download_hoge!)
  43. end
  44. describe '#hoge_remote_url=' do
  45. before do
  46. stub_request(:get, url).to_return(status: code, headers: headers)
  47. end
  48. it 'always returns its argument' do
  49. [nil, '', [], {}].each do |arg|
  50. expect(foo.hoge_remote_url = arg).to be arg
  51. end
  52. end
  53. context 'with an invalid URL' do
  54. before do
  55. parsed = instance_double(Addressable::URI)
  56. allow(parsed).to receive(:normalize).with(no_args).and_raise(Addressable::URI::InvalidURIError)
  57. allow(Addressable::URI).to receive(:parse).with(url).and_return(parsed)
  58. end
  59. it 'makes no request' do
  60. foo.hoge_remote_url = url
  61. expect(a_request(:get, url)).to_not have_been_made
  62. end
  63. end
  64. context 'with scheme that is neither http nor https' do
  65. let(:url) { 'ftp://google.com' }
  66. it 'makes no request' do
  67. foo.hoge_remote_url = url
  68. expect(a_request(:get, url)).to_not have_been_made
  69. end
  70. end
  71. context 'with relative URL' do
  72. let(:url) { 'https:///path' }
  73. it 'makes no request' do
  74. foo.hoge_remote_url = url
  75. expect(a_request(:get, url)).to_not have_been_made
  76. end
  77. end
  78. context 'when URL has not changed' do
  79. it 'makes no request if file is already saved' do
  80. allow(foo).to receive(:[]).with(attribute_name).and_return(url)
  81. allow(foo).to receive(:hoge_file_name).and_return('foo.jpg')
  82. foo.hoge_remote_url = url
  83. expect(a_request(:get, url)).to_not have_been_made
  84. end
  85. it 'makes request if file is not already saved' do
  86. allow(foo).to receive(:[]).with(attribute_name).and_return(url)
  87. allow(foo).to receive(:hoge_file_name).and_return(nil)
  88. foo.hoge_remote_url = url
  89. expect(a_request(:get, url)).to have_been_made
  90. end
  91. end
  92. context 'when instance has no attribute for URL' do
  93. before do
  94. allow(foo).to receive(:has_attribute?).with(attribute_name).and_return(false)
  95. end
  96. it 'does not try to write attribute' do
  97. allow(foo).to receive('[]=').with(attribute_name, url)
  98. foo.hoge_remote_url = url
  99. expect(foo).to_not have_received('[]=').with(attribute_name, url)
  100. end
  101. end
  102. context 'when instance has an attribute for URL' do
  103. before do
  104. allow(foo).to receive(:has_attribute?).with(attribute_name).and_return(true)
  105. end
  106. it 'does not try to write attribute' do
  107. allow(foo).to receive('[]=').with(attribute_name, url)
  108. foo.hoge_remote_url = url
  109. expect(foo).to have_received('[]=').with(attribute_name, url)
  110. end
  111. end
  112. context 'with a valid URL' do
  113. it 'makes a request' do
  114. foo.hoge_remote_url = url
  115. expect(a_request(:get, url)).to have_been_made
  116. end
  117. context 'when the response is not successful' do
  118. let(:code) { 500 }
  119. it 'does not assign file' do
  120. allow(foo).to receive(:public_send)
  121. allow(foo).to receive(:public_send)
  122. foo.hoge_remote_url = url
  123. expect(foo).to_not have_received(:public_send).with("#{hoge}=", any_args)
  124. expect(foo).to_not have_received(:public_send).with("#{hoge}_file_name=", any_args)
  125. end
  126. end
  127. context 'when the response is successful' do
  128. let(:code) { 200 }
  129. context 'when contains Content-Disposition header' do
  130. let(:file) { 'filename="foo.txt"' }
  131. let(:headers) { { 'content-disposition' => file } }
  132. it 'assigns file' do
  133. response_with_limit = ResponseWithLimit.new(nil, 0)
  134. allow(ResponseWithLimit).to receive(:new).with(anything, anything).and_return(response_with_limit)
  135. allow(foo).to receive(:public_send)
  136. foo.hoge_remote_url = url
  137. expect(foo).to have_received(:public_send).with(:"download_#{hoge}!", url)
  138. allow(foo).to receive(:public_send)
  139. foo.download_hoge!(url)
  140. expect(foo).to have_received(:public_send).with(:"#{hoge}=", response_with_limit)
  141. end
  142. end
  143. end
  144. context 'when an error is raised during the request' do
  145. before do
  146. stub_request(:get, url).to_raise(error_class)
  147. end
  148. error_classes = [
  149. HTTP::TimeoutError,
  150. HTTP::ConnectionError,
  151. OpenSSL::SSL::SSLError,
  152. Paperclip::Errors::NotIdentifiedByImageMagickError,
  153. Addressable::URI::InvalidURIError,
  154. ]
  155. error_classes.each do |error_class|
  156. let(:error_class) { error_class }
  157. it 'calls Rails.logger.debug' do
  158. allow(Rails.logger).to receive(:debug)
  159. foo.hoge_remote_url = url
  160. expect(Rails.logger).to have_received(:debug) do |&block|
  161. expect(block.call).to match(/^Error fetching remote #{hoge}: /)
  162. end
  163. end
  164. end
  165. end
  166. end
  167. end
  168. end