You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

201 lines
5.7 KiB

  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. it 'defines a method #download_hoge!' do
  47. expect(foo).to respond_to(:download_hoge!)
  48. end
  49. describe '#hoge_remote_url=' do
  50. before do
  51. request
  52. end
  53. it 'always returns arg' do
  54. [nil, '', [], {}].each do |arg|
  55. expect(foo.hoge_remote_url = arg).to be arg
  56. end
  57. end
  58. context 'Addressable::URI::InvalidURIError raised' do
  59. it 'makes no request' do
  60. allow(Addressable::URI).to receive_message_chain(:parse, :normalize)
  61. .with(url).with(no_args).and_raise(Addressable::URI::InvalidURIError)
  62. foo.hoge_remote_url = url
  63. expect(request).not_to have_been_requested
  64. end
  65. end
  66. context 'scheme is neither http nor https' do
  67. let(:url) { 'ftp://google.com' }
  68. it 'makes no request' do
  69. foo.hoge_remote_url = url
  70. expect(request).not_to have_been_requested
  71. end
  72. end
  73. context 'parsed_url.host is empty' do
  74. it 'makes no request' do
  75. parsed_url = double(scheme: 'https', host: double(blank?: true))
  76. allow(Addressable::URI).to receive_message_chain(:parse, :normalize)
  77. .with(url).with(no_args).and_return(parsed_url)
  78. foo.hoge_remote_url = url
  79. expect(request).not_to have_been_requested
  80. end
  81. end
  82. context 'parsed_url.host is nil' do
  83. it 'makes no request' do
  84. parsed_url = Addressable::URI.parse('https:https://example.com/path/file.png')
  85. allow(Addressable::URI).to receive_message_chain(:parse, :normalize)
  86. .with(url).with(no_args).and_return(parsed_url)
  87. foo.hoge_remote_url = url
  88. expect(request).not_to have_been_requested
  89. end
  90. end
  91. context 'foo[attribute_name] == url' do
  92. it 'makes no request if file is saved' do
  93. allow(foo).to receive(:[]).with(attribute_name).and_return(url)
  94. allow(foo).to receive(:hoge_file_name).and_return('foo.jpg')
  95. foo.hoge_remote_url = url
  96. expect(request).not_to have_been_requested
  97. end
  98. it 'makes request if file is not saved' do
  99. allow(foo).to receive(:[]).with(attribute_name).and_return(url)
  100. allow(foo).to receive(:hoge_file_name).and_return(nil)
  101. foo.hoge_remote_url = url
  102. expect(request).to have_been_requested
  103. end
  104. end
  105. context "scheme is https, parsed_url.host isn't empty, and foo[attribute_name] != url" do
  106. it 'makes a request' do
  107. foo.hoge_remote_url = url
  108. expect(request).to have_been_requested
  109. end
  110. context 'response.code != 200' do
  111. let(:code) { 500 }
  112. it 'calls not send' do
  113. expect(foo).not_to receive(:public_send).with("#{hoge}=", any_args)
  114. expect(foo).not_to receive(:public_send).with("#{hoge}_file_name=", any_args)
  115. foo.hoge_remote_url = url
  116. end
  117. end
  118. context 'response.code == 200' do
  119. let(:code) { 200 }
  120. context 'response contains headers["content-disposition"]' do
  121. let(:file) { 'filename="foo.txt"' }
  122. let(:headers) { { 'content-disposition' => file } }
  123. it 'calls send' do
  124. string_io = StringIO.new('')
  125. extname = '.txt'
  126. basename = '0123456789abcdef'
  127. allow(SecureRandom).to receive(:hex).and_return(basename)
  128. allow(StringIO).to receive(:new).with(anything).and_return(string_io)
  129. expect(foo).to receive(:public_send).with("download_#{hoge}!")
  130. foo.hoge_remote_url = url
  131. expect(foo).to receive(:public_send).with("#{hoge}=", string_io)
  132. expect(foo).to receive(:public_send).with("#{hoge}_file_name=", basename + extname)
  133. foo.download_hoge!
  134. end
  135. end
  136. end
  137. context 'an error raised during the request' do
  138. let(:request) { stub_request(:get, url).to_raise(error_class) }
  139. error_classes = [
  140. HTTP::TimeoutError,
  141. HTTP::ConnectionError,
  142. OpenSSL::SSL::SSLError,
  143. Paperclip::Errors::NotIdentifiedByImageMagickError,
  144. Addressable::URI::InvalidURIError,
  145. ]
  146. error_classes.each do |error_class|
  147. let(:error_class) { error_class }
  148. it 'calls Rails.logger.debug' do
  149. expect(Rails.logger).to receive(:debug).with(/^Error fetching remote #{hoge}: /)
  150. foo.hoge_remote_url = url
  151. end
  152. end
  153. end
  154. end
  155. end
  156. end
  157. end