remotable_spec.rb 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  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. before do
  23. class Foo
  24. include Remotable
  25. remotable_attachment :hoge, 1.kilobyte
  26. end
  27. end
  28. let(:attribute_name) { "#{hoge}_remote_url".to_sym }
  29. let(:code) { 200 }
  30. let(:file) { 'filename="foo.txt"' }
  31. let(:foo) { Foo.new }
  32. let(:headers) { { 'content-disposition' => file } }
  33. let(:hoge) { :hoge }
  34. let(:url) { 'https://google.com' }
  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. allow(Addressable::URI).to receive_message_chain(:parse, :normalize).with(url).with(no_args).and_raise(Addressable::URI::InvalidURIError)
  56. end
  57. it 'makes no request' do
  58. foo.hoge_remote_url = url
  59. expect(a_request(:get, url)).to_not have_been_made
  60. end
  61. end
  62. context 'with scheme that is neither http nor https' do
  63. let(:url) { 'ftp://google.com' }
  64. it 'makes no request' do
  65. foo.hoge_remote_url = url
  66. expect(a_request(:get, url)).to_not have_been_made
  67. end
  68. end
  69. context 'with relative URL' do
  70. let(:url) { 'https:///path' }
  71. it 'makes no request' do
  72. foo.hoge_remote_url = url
  73. expect(a_request(:get, url)).to_not have_been_made
  74. end
  75. end
  76. context 'when URL has not changed' do
  77. it 'makes no request if file is already saved' do
  78. allow(foo).to receive(:[]).with(attribute_name).and_return(url)
  79. allow(foo).to receive(:hoge_file_name).and_return('foo.jpg')
  80. foo.hoge_remote_url = url
  81. expect(a_request(:get, url)).to_not have_been_made
  82. end
  83. it 'makes request if file is not already saved' do
  84. allow(foo).to receive(:[]).with(attribute_name).and_return(url)
  85. allow(foo).to receive(:hoge_file_name).and_return(nil)
  86. foo.hoge_remote_url = url
  87. expect(a_request(:get, url)).to have_been_made
  88. end
  89. end
  90. context 'when instance has no attribute for URL' do
  91. before do
  92. allow(foo).to receive(:has_attribute?).with(attribute_name).and_return(false)
  93. end
  94. it 'does not try to write attribute' do
  95. expect(foo).to_not receive('[]=').with(attribute_name, url)
  96. foo.hoge_remote_url = url
  97. end
  98. end
  99. context 'when instance has an attribute for URL' do
  100. before do
  101. allow(foo).to receive(:has_attribute?).with(attribute_name).and_return(true)
  102. end
  103. it 'does not try to write attribute' do
  104. expect(foo).to receive('[]=').with(attribute_name, url)
  105. foo.hoge_remote_url = url
  106. end
  107. end
  108. context 'with a valid URL' do
  109. it 'makes a request' do
  110. foo.hoge_remote_url = url
  111. expect(a_request(:get, url)).to have_been_made
  112. end
  113. context 'when the response is not successful' do
  114. let(:code) { 500 }
  115. it 'does not assign file' do
  116. expect(foo).not_to receive(:public_send).with("#{hoge}=", any_args)
  117. expect(foo).not_to receive(:public_send).with("#{hoge}_file_name=", any_args)
  118. foo.hoge_remote_url = url
  119. end
  120. end
  121. context 'when the response is successful' do
  122. let(:code) { 200 }
  123. context 'and contains Content-Disposition header' do
  124. let(:file) { 'filename="foo.txt"' }
  125. let(:headers) { { 'content-disposition' => file } }
  126. it 'assigns file' do
  127. response_with_limit = ResponseWithLimit.new(nil, 0)
  128. allow(ResponseWithLimit).to receive(:new).with(anything, anything).and_return(response_with_limit)
  129. expect(foo).to receive(:public_send).with("download_#{hoge}!", url)
  130. foo.hoge_remote_url = url
  131. expect(foo).to receive(:public_send).with("#{hoge}=", response_with_limit)
  132. foo.download_hoge!(url)
  133. end
  134. end
  135. end
  136. context 'when an error is raised during the request' do
  137. before do
  138. stub_request(:get, url).to_raise(error_class)
  139. end
  140. error_classes = [
  141. HTTP::TimeoutError,
  142. HTTP::ConnectionError,
  143. OpenSSL::SSL::SSLError,
  144. Paperclip::Errors::NotIdentifiedByImageMagickError,
  145. Addressable::URI::InvalidURIError,
  146. ]
  147. error_classes.each do |error_class|
  148. let(:error_class) { error_class }
  149. it 'calls Rails.logger.debug' do
  150. expect(Rails.logger).to receive(:debug).with(/^Error fetching remote #{hoge}: /)
  151. foo.hoge_remote_url = url
  152. end
  153. end
  154. end
  155. end
  156. end
  157. end