paperclip 4.3.7 → 5.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (103) hide show
  1. checksums.yaml +4 -4
  2. data/.codeclimate.yml +17 -0
  3. data/.hound.yml +5 -16
  4. data/.travis.yml +15 -12
  5. data/Appraisals +4 -8
  6. data/CONTRIBUTING.md +16 -5
  7. data/Gemfile +3 -8
  8. data/LICENSE +1 -1
  9. data/NEWS +86 -31
  10. data/README.md +220 -146
  11. data/Rakefile +1 -1
  12. data/UPGRADING +12 -9
  13. data/features/basic_integration.feature +3 -2
  14. data/features/migration.feature +0 -24
  15. data/features/step_definitions/attachment_steps.rb +6 -6
  16. data/features/step_definitions/rails_steps.rb +29 -28
  17. data/features/step_definitions/s3_steps.rb +2 -2
  18. data/features/support/env.rb +1 -0
  19. data/features/support/paths.rb +1 -1
  20. data/features/support/rails.rb +0 -24
  21. data/gemfiles/4.2.gemfile +3 -5
  22. data/gemfiles/{3.2.gemfile → 5.0.gemfile} +4 -6
  23. data/lib/paperclip.rb +12 -11
  24. data/lib/paperclip/attachment.rb +25 -14
  25. data/lib/paperclip/attachment_registry.rb +2 -1
  26. data/lib/paperclip/callbacks.rb +8 -6
  27. data/lib/paperclip/content_type_detector.rb +3 -2
  28. data/lib/paperclip/errors.rb +3 -1
  29. data/lib/paperclip/glue.rb +1 -1
  30. data/lib/paperclip/has_attached_file.rb +7 -1
  31. data/lib/paperclip/helpers.rb +14 -10
  32. data/lib/paperclip/interpolations.rb +1 -1
  33. data/lib/paperclip/io_adapters/abstract_adapter.rb +25 -3
  34. data/lib/paperclip/io_adapters/attachment_adapter.rb +10 -5
  35. data/lib/paperclip/io_adapters/data_uri_adapter.rb +8 -8
  36. data/lib/paperclip/io_adapters/empty_string_adapter.rb +5 -4
  37. data/lib/paperclip/io_adapters/file_adapter.rb +12 -6
  38. data/lib/paperclip/io_adapters/http_url_proxy_adapter.rb +7 -7
  39. data/lib/paperclip/io_adapters/identity_adapter.rb +12 -6
  40. data/lib/paperclip/io_adapters/nil_adapter.rb +8 -5
  41. data/lib/paperclip/io_adapters/registry.rb +6 -2
  42. data/lib/paperclip/io_adapters/stringio_adapter.rb +9 -6
  43. data/lib/paperclip/io_adapters/uploaded_file_adapter.rb +10 -6
  44. data/lib/paperclip/io_adapters/uri_adapter.rb +17 -14
  45. data/lib/paperclip/matchers/validate_attachment_content_type_matcher.rb +4 -4
  46. data/lib/paperclip/processor.rb +5 -4
  47. data/lib/paperclip/schema.rb +2 -8
  48. data/lib/paperclip/storage/filesystem.rb +13 -2
  49. data/lib/paperclip/storage/fog.rb +18 -12
  50. data/lib/paperclip/storage/s3.rb +85 -57
  51. data/lib/paperclip/thumbnail.rb +14 -4
  52. data/lib/paperclip/url_generator.rb +16 -13
  53. data/lib/paperclip/validators.rb +1 -1
  54. data/lib/paperclip/validators/attachment_size_validator.rb +1 -7
  55. data/lib/paperclip/version.rb +3 -1
  56. data/lib/tasks/paperclip.rake +18 -4
  57. data/paperclip.gemspec +12 -9
  58. data/spec/paperclip/attachment_processing_spec.rb +2 -4
  59. data/spec/paperclip/attachment_registry_spec.rb +28 -0
  60. data/spec/paperclip/attachment_spec.rb +72 -18
  61. data/spec/paperclip/has_attached_file_spec.rb +24 -8
  62. data/spec/paperclip/integration_spec.rb +4 -3
  63. data/spec/paperclip/io_adapters/abstract_adapter_spec.rb +45 -22
  64. data/spec/paperclip/io_adapters/attachment_adapter_spec.rb +6 -3
  65. data/spec/paperclip/io_adapters/data_uri_adapter_spec.rb +7 -1
  66. data/spec/paperclip/io_adapters/file_adapter_spec.rb +2 -2
  67. data/spec/paperclip/io_adapters/http_url_proxy_adapter_spec.rb +18 -1
  68. data/spec/paperclip/io_adapters/identity_adapter_spec.rb +1 -1
  69. data/spec/paperclip/io_adapters/registry_spec.rb +2 -2
  70. data/spec/paperclip/io_adapters/stringio_adapter_spec.rb +1 -1
  71. data/spec/paperclip/io_adapters/uploaded_file_adapter_spec.rb +5 -5
  72. data/spec/paperclip/io_adapters/uri_adapter_spec.rb +48 -3
  73. data/spec/paperclip/matchers/validate_attachment_content_type_matcher_spec.rb +10 -0
  74. data/spec/paperclip/paperclip_spec.rb +3 -33
  75. data/spec/paperclip/storage/fog_spec.rb +26 -0
  76. data/spec/paperclip/storage/s3_live_spec.rb +20 -14
  77. data/spec/paperclip/storage/s3_spec.rb +357 -190
  78. data/spec/paperclip/tempfile_spec.rb +35 -0
  79. data/spec/paperclip/thumbnail_spec.rb +35 -32
  80. data/spec/paperclip/url_generator_spec.rb +54 -43
  81. data/spec/paperclip/validators/attachment_size_validator_spec.rb +26 -20
  82. data/spec/paperclip/validators_spec.rb +5 -5
  83. data/spec/spec_helper.rb +6 -2
  84. data/spec/support/assertions.rb +12 -1
  85. data/spec/support/conditional_filter_helper.rb +5 -0
  86. data/spec/support/mock_attachment.rb +2 -0
  87. data/spec/support/mock_url_generator_builder.rb +2 -2
  88. data/spec/support/model_reconstruction.rb +9 -1
  89. data/spec/support/reporting.rb +11 -0
  90. metadata +61 -158
  91. data/cucumber/paperclip_steps.rb +0 -6
  92. data/gemfiles/4.1.gemfile +0 -19
  93. data/lib/paperclip/deprecations.rb +0 -42
  94. data/lib/paperclip/locales/de.yml +0 -18
  95. data/lib/paperclip/locales/es.yml +0 -18
  96. data/lib/paperclip/locales/ja.yml +0 -18
  97. data/lib/paperclip/locales/pt-BR.yml +0 -18
  98. data/lib/paperclip/locales/zh-CN.yml +0 -18
  99. data/lib/paperclip/locales/zh-HK.yml +0 -18
  100. data/lib/paperclip/locales/zh-TW.yml +0 -18
  101. data/spec/paperclip/deprecations_spec.rb +0 -65
  102. data/spec/support/deprecations.rb +0 -9
  103. data/spec/support/rails_helpers.rb +0 -7
@@ -17,22 +17,26 @@ describe Paperclip::Shoulda::Matchers::ValidateAttachmentContentTypeMatcher do
17
17
 
18
18
  it "rejects a class with no validation" do
19
19
  expect(matcher).to_not accept(Dummy)
20
+ expect { matcher.failure_message }.to_not raise_error
20
21
  end
21
22
 
22
23
  it 'rejects a class when the validation fails' do
23
24
  Dummy.validates_attachment_content_type :avatar, content_type: %r{audio/.*}
24
25
  expect(matcher).to_not accept(Dummy)
26
+ expect { matcher.failure_message }.to_not raise_error
25
27
  end
26
28
 
27
29
  it "accepts a class with a matching validation" do
28
30
  Dummy.validates_attachment_content_type :avatar, content_type: %r{image/.*}
29
31
  expect(matcher).to accept(Dummy)
32
+ expect { matcher.failure_message }.to_not raise_error
30
33
  end
31
34
 
32
35
  it "accepts a class with other validations but matching types" do
33
36
  Dummy.validates_presence_of :title
34
37
  Dummy.validates_attachment_content_type :avatar, content_type: %r{image/.*}
35
38
  expect(matcher).to accept(Dummy)
39
+ expect { matcher.failure_message }.to_not raise_error
36
40
  end
37
41
 
38
42
  it "accepts a class that matches and a matcher that only specifies 'allowing'" do
@@ -40,6 +44,7 @@ describe Paperclip::Shoulda::Matchers::ValidateAttachmentContentTypeMatcher do
40
44
  matcher = plain_matcher.allowing(%w(image/png image/jpeg))
41
45
 
42
46
  expect(matcher).to accept(Dummy)
47
+ expect { matcher.failure_message }.to_not raise_error
43
48
  end
44
49
 
45
50
  it "rejects a class that does not match and a matcher that only specifies 'allowing'" do
@@ -47,6 +52,7 @@ describe Paperclip::Shoulda::Matchers::ValidateAttachmentContentTypeMatcher do
47
52
  matcher = plain_matcher.allowing(%w(image/png image/jpeg))
48
53
 
49
54
  expect(matcher).to_not accept(Dummy)
55
+ expect { matcher.failure_message }.to_not raise_error
50
56
  end
51
57
 
52
58
  it "accepts a class that matches and a matcher that only specifies 'rejecting'" do
@@ -54,6 +60,7 @@ describe Paperclip::Shoulda::Matchers::ValidateAttachmentContentTypeMatcher do
54
60
  matcher = plain_matcher.rejecting(%w(audio/mp3 application/octet-stream))
55
61
 
56
62
  expect(matcher).to accept(Dummy)
63
+ expect { matcher.failure_message }.to_not raise_error
57
64
  end
58
65
 
59
66
  it "rejects a class that does not match and a matcher that only specifies 'rejecting'" do
@@ -61,6 +68,7 @@ describe Paperclip::Shoulda::Matchers::ValidateAttachmentContentTypeMatcher do
61
68
  matcher = plain_matcher.rejecting(%w(audio/mp3 application/octet-stream))
62
69
 
63
70
  expect(matcher).to_not accept(Dummy)
71
+ expect { matcher.failure_message }.to_not raise_error
64
72
  end
65
73
 
66
74
  context "using an :if to control the validation" do
@@ -75,12 +83,14 @@ describe Paperclip::Shoulda::Matchers::ValidateAttachmentContentTypeMatcher do
75
83
  dummy = Dummy.new
76
84
  dummy.go = true
77
85
  expect(matcher).to accept(dummy)
86
+ expect { matcher.failure_message }.to_not raise_error
78
87
  end
79
88
 
80
89
  it "does not run the validation if the control is false" do
81
90
  dummy = Dummy.new
82
91
  dummy.go = false
83
92
  expect(matcher).to_not accept(dummy)
93
+ expect { matcher.failure_message }.to_not raise_error
84
94
  end
85
95
  end
86
96
 
@@ -29,7 +29,9 @@ describe Paperclip do
29
29
  Paperclip.options[:command_path] = "/opt/my_app/bin"
30
30
  Paperclip.run("convert", "stuff")
31
31
  Paperclip.run("convert", "more_stuff")
32
- assert_equal 1, [Cocaine::CommandLine.path].flatten.size
32
+
33
+ cmd_path = Paperclip.options[:command_path]
34
+ assert_equal 1, Cocaine::CommandLine.path.scan(cmd_path).count
33
35
  end
34
36
  end
35
37
 
@@ -109,7 +111,6 @@ describe Paperclip do
109
111
 
110
112
  context "An ActiveRecord model with an 'avatar' attachment" do
111
113
  before do
112
- Paperclip::Deprecations.stubs(:check)
113
114
  rebuild_model path: "tmp/:class/omg/:style.:extension"
114
115
  @file = File.new(fixture_file("5k.png"), 'rb')
115
116
  end
@@ -124,37 +125,6 @@ describe Paperclip do
124
125
  end
125
126
  end
126
127
 
127
- if using_protected_attributes?
128
- context "that is attr_protected" do
129
- before do
130
- Dummy.class_eval do
131
- attr_protected :avatar
132
- end
133
- @dummy = Dummy.new
134
- end
135
-
136
- it "does not assign the avatar on mass-set" do
137
- @dummy.attributes = { other: "I'm set!",
138
- avatar: @file }
139
-
140
- assert_equal "I'm set!", @dummy.other
141
- assert ! @dummy.avatar?
142
- end
143
-
144
- it "allows assigment on normal set" do
145
- @dummy.other = "I'm set!"
146
- @dummy.avatar = @file
147
-
148
- assert_equal "I'm set!", @dummy.other
149
- assert @dummy.avatar?
150
- end
151
- end
152
- end
153
-
154
- it "calls Paperclip::Deprecations.check" do
155
- expect(Paperclip::Deprecations).to have_received(:check)
156
- end
157
-
158
128
  context "with a subclass" do
159
129
  before do
160
130
  class ::SubDummy < Dummy; end
@@ -183,6 +183,13 @@ describe Paperclip::Storage::Fog do
183
183
  tempfile.close
184
184
  end
185
185
 
186
+ it 'is able to be handled when missing while copying to a local file' do
187
+ tempfile = Tempfile.new("known_location")
188
+ tempfile.binmode
189
+ assert_equal false, @dummy.avatar.copy_to_local_file(:original, tempfile.path)
190
+ tempfile.close
191
+ end
192
+
186
193
  it "passes the content type to the Fog::Storage::AWS::Files instance" do
187
194
  Fog::Storage::AWS::Files.any_instance.expects(:create).with do |hash|
188
195
  hash[:content_type]
@@ -266,6 +273,22 @@ describe Paperclip::Storage::Fog do
266
273
  end
267
274
  end
268
275
 
276
+ context "with fog_public as a proc" do
277
+ let(:proc) { ->(attachment) { !attachment } }
278
+
279
+ before do
280
+ rebuild_model(@options.merge(fog_public: proc))
281
+ @dummy = Dummy.new
282
+ @dummy.avatar = StringIO.new(".")
283
+ @dummy.save
284
+ end
285
+
286
+ it "sets the @fog_public instance variable to false" do
287
+ assert_equal proc, @dummy.avatar.instance_variable_get("@options")[:fog_public]
288
+ assert_equal false, @dummy.avatar.fog_public
289
+ end
290
+ end
291
+
269
292
  context "with styles set and fog_public set to false" do
270
293
  before do
271
294
  rebuild_model(@options.merge(fog_public: false, styles: { medium: "300x300>", thumb: "100x100>" }))
@@ -418,6 +441,9 @@ describe Paperclip::Storage::Fog do
418
441
  assert @connection.directories.get(@dynamic_fog_directory).inspect
419
442
  end
420
443
 
444
+ it "provides an url using dynamic bucket name" do
445
+ assert_match(/^https:\/\/dynamicpaperclip.s3.amazonaws.com\/avatars\/5k.png\?\d*$/, @dummy.avatar.url)
446
+ end
421
447
  end
422
448
 
423
449
  context "with a proc for the fog_host evaluating a model method" do
@@ -8,9 +8,10 @@ unless ENV["S3_BUCKET"].blank?
8
8
  storage: :s3,
9
9
  bucket: ENV["S3_BUCKET"],
10
10
  path: ":class/:attachment/:id/:style.:extension",
11
+ s3_region: ENV["S3_REGION"],
11
12
  s3_credentials: {
12
- aws_access_key_id: ENV['AWS_ACCESS_KEY_ID'],
13
- aws_secre_access_key: ENV['AWS_SECRET_ACCESS_KEY']
13
+ access_key_id: ENV['AWS_ACCESS_KEY_ID'],
14
+ secret_access_key: ENV['AWS_SECRET_ACCESS_KEY']
14
15
  }
15
16
 
16
17
  @file = File.new(fixture_file("5k.png"))
@@ -45,9 +46,10 @@ unless ENV["S3_BUCKET"].blank?
45
46
  storage: :s3,
46
47
  bucket: ENV["S3_BUCKET"],
47
48
  path: ":class/:attachment/:id/:style.:extension",
49
+ s3_region: ENV["S3_REGION"],
48
50
  s3_credentials: {
49
- aws_access_key_id: ENV['AWS_ACCESS_KEY_ID'],
50
- aws_secre_access_key: ENV['AWS_SECRET_ACCESS_KEY']
51
+ access_key_id: ENV['AWS_ACCESS_KEY_ID'],
52
+ secret_access_key: ENV['AWS_SECRET_ACCESS_KEY']
51
53
  }
52
54
 
53
55
  @dummy = Dummy.new
@@ -64,9 +66,10 @@ unless ENV["S3_BUCKET"].blank?
64
66
  storage: :s3,
65
67
  bucket: ENV["S3_BUCKET"],
66
68
  path: ":class/:attachment/:id/:style.:extension",
69
+ s3_region: ENV["S3_REGION"],
67
70
  s3_credentials: {
68
- aws_access_key_id: ENV['AWS_ACCESS_KEY_ID'],
69
- aws_secre_access_key: ENV['AWS_SECRET_ACCESS_KEY']
71
+ access_key_id: ENV['AWS_ACCESS_KEY_ID'],
72
+ secret_access_key: ENV['AWS_SECRET_ACCESS_KEY']
70
73
  }
71
74
 
72
75
  Dummy.delete_all
@@ -105,9 +108,12 @@ unless ENV["S3_BUCKET"].blank?
105
108
  rebuild_model styles: { thumb: "100x100", square: "32x32#" },
106
109
  storage: :s3,
107
110
  bucket: ENV["S3_BUCKET"],
111
+ s3_region: ENV["S3_REGION"],
112
+ url: ":s3_domain_url",
113
+ path: "/:class/:attachment/:id_partition/:style/:filename",
108
114
  s3_credentials: {
109
- aws_access_key_id: ENV['AWS_ACCESS_KEY_ID'],
110
- aws_secre_access_key: ENV['AWS_SECRET_ACCESS_KEY']
115
+ access_key_id: ENV['AWS_ACCESS_KEY_ID'],
116
+ secret_access_key: ENV['AWS_SECRET_ACCESS_KEY']
111
117
  }
112
118
 
113
119
  Dummy.delete_all
@@ -136,7 +142,7 @@ unless ENV["S3_BUCKET"].blank?
136
142
  it "is destroyable" do
137
143
  url = @dummy.avatar.url
138
144
  @dummy.destroy
139
- assert_not_found_response url
145
+ assert_forbidden_response url
140
146
  end
141
147
  end
142
148
 
@@ -146,12 +152,12 @@ unless ENV["S3_BUCKET"].blank?
146
152
  storage: :s3,
147
153
  bucket: ENV["S3_BUCKET"],
148
154
  path: ":class/:attachment/:id/:style.:extension",
155
+ s3_region: ENV["S3_REGION"],
149
156
  s3_credentials: {
150
- aws_access_key_id: ENV['AWS_ACCESS_KEY_ID'],
151
- aws_secre_access_key: ENV['AWS_SECRET_ACCESS_KEY']
157
+ access_key_id: ENV['AWS_ACCESS_KEY_ID'],
158
+ secret_access_key: ENV['AWS_SECRET_ACCESS_KEY']
152
159
  },
153
- s3_server_side_encryption: :aes256
154
-
160
+ s3_server_side_encryption: "AES256"
155
161
  Dummy.delete_all
156
162
  @dummy = Dummy.new
157
163
  end
@@ -173,7 +179,7 @@ unless ENV["S3_BUCKET"].blank?
173
179
  end
174
180
 
175
181
  it "is encrypted on S3" do
176
- assert @dummy.avatar.s3_object.server_side_encryption == :aes256
182
+ assert @dummy.avatar.s3_object.server_side_encryption == "AES256"
177
183
  end
178
184
  end
179
185
  end
@@ -3,17 +3,20 @@ require 'aws-sdk'
3
3
 
4
4
  describe Paperclip::Storage::S3 do
5
5
  before do
6
- AWS.stub!
6
+ Aws.config[:stub_responses] = true
7
+ end
8
+
9
+ def aws2_add_region
10
+ { s3_region: 'us-east-1' }
7
11
  end
8
12
 
9
13
  context "Parsing S3 credentials" do
10
14
  before do
11
15
  @proxy_settings = {host: "127.0.0.1", port: 8888, user: "foo", password: "bar"}
12
- rebuild_model storage: :s3,
16
+ rebuild_model (aws2_add_region).merge storage: :s3,
13
17
  bucket: "testing",
14
18
  http_proxy: @proxy_settings,
15
19
  s3_credentials: {not: :important}
16
-
17
20
  @dummy = Dummy.new
18
21
  @avatar = @dummy.avatar
19
22
  end
@@ -55,7 +58,8 @@ describe Paperclip::Storage::S3 do
55
58
  context ":bucket option via :s3_credentials" do
56
59
 
57
60
  before do
58
- rebuild_model storage: :s3, s3_credentials: {bucket: 'testing'}
61
+ rebuild_model (aws2_add_region).merge storage: :s3,
62
+ s3_credentials: {bucket: 'testing'}
59
63
  @dummy = Dummy.new
60
64
  end
61
65
 
@@ -68,7 +72,8 @@ describe Paperclip::Storage::S3 do
68
72
  context ":bucket option" do
69
73
 
70
74
  before do
71
- rebuild_model storage: :s3, bucket: "testing", s3_credentials: {}
75
+ rebuild_model (aws2_add_region).merge storage: :s3,
76
+ bucket: "testing", s3_credentials: {}
72
77
  @dummy = Dummy.new
73
78
  end
74
79
 
@@ -81,7 +86,7 @@ describe Paperclip::Storage::S3 do
81
86
  context "missing :bucket option" do
82
87
 
83
88
  before do
84
- rebuild_model storage: :s3,
89
+ rebuild_model (aws2_add_region).merge storage: :s3,
85
90
  http_proxy: @proxy_settings,
86
91
  s3_credentials: {not: :important}
87
92
 
@@ -98,7 +103,7 @@ describe Paperclip::Storage::S3 do
98
103
 
99
104
  context "" do
100
105
  before do
101
- rebuild_model storage: :s3,
106
+ rebuild_model (aws2_add_region).merge storage: :s3,
102
107
  s3_credentials: {},
103
108
  bucket: "bucket",
104
109
  path: ":attachment/:basename:dotextension",
@@ -109,7 +114,7 @@ describe Paperclip::Storage::S3 do
109
114
  end
110
115
 
111
116
  it "returns a url based on an S3 path" do
112
- assert_match %r{^http://s3.amazonaws.com/bucket/avatars/data[^\.]}, @dummy.avatar.url
117
+ assert_match %r{^//s3.amazonaws.com/bucket/avatars/data[^\.]}, @dummy.avatar.url
113
118
  end
114
119
 
115
120
  it "uses the correct bucket" do
@@ -125,8 +130,8 @@ describe Paperclip::Storage::S3 do
125
130
  ["http", :http, ""].each do |protocol|
126
131
  context "as #{protocol.inspect}" do
127
132
  before do
128
- rebuild_model storage: :s3, s3_protocol: protocol
129
-
133
+ rebuild_model (aws2_add_region).merge storage: :s3,
134
+ s3_protocol: protocol
130
135
  @dummy = Dummy.new
131
136
  end
132
137
 
@@ -139,7 +144,7 @@ describe Paperclip::Storage::S3 do
139
144
 
140
145
  context "s3_protocol: 'https'" do
141
146
  before do
142
- rebuild_model storage: :s3,
147
+ rebuild_model (aws2_add_region).merge storage: :s3,
143
148
  s3_credentials: {},
144
149
  s3_protocol: 'https',
145
150
  bucket: "bucket",
@@ -156,7 +161,7 @@ describe Paperclip::Storage::S3 do
156
161
 
157
162
  context "s3_protocol: ''" do
158
163
  before do
159
- rebuild_model storage: :s3,
164
+ rebuild_model (aws2_add_region).merge storage: :s3,
160
165
  s3_credentials: {},
161
166
  s3_protocol: '',
162
167
  bucket: "bucket",
@@ -173,7 +178,7 @@ describe Paperclip::Storage::S3 do
173
178
 
174
179
  context "s3_protocol: :https" do
175
180
  before do
176
- rebuild_model storage: :s3,
181
+ rebuild_model (aws2_add_region).merge storage: :s3,
177
182
  s3_credentials: {},
178
183
  s3_protocol: :https,
179
184
  bucket: "bucket",
@@ -190,7 +195,7 @@ describe Paperclip::Storage::S3 do
190
195
 
191
196
  context "s3_protocol: ''" do
192
197
  before do
193
- rebuild_model storage: :s3,
198
+ rebuild_model (aws2_add_region).merge storage: :s3,
194
199
  s3_credentials: {},
195
200
  s3_protocol: '',
196
201
  bucket: "bucket",
@@ -207,7 +212,7 @@ describe Paperclip::Storage::S3 do
207
212
 
208
213
  context "An attachment that uses S3 for storage and has the style in the path" do
209
214
  before do
210
- rebuild_model storage: :s3,
215
+ rebuild_model (aws2_add_region).merge storage: :s3,
211
216
  bucket: "testing",
212
217
  path: ":attachment/:style/:basename:dotextension",
213
218
  styles: {
@@ -232,30 +237,33 @@ describe Paperclip::Storage::S3 do
232
237
  end
233
238
  end
234
239
 
240
+ # if using aws-sdk-v2, the s3_host_name will be defined by the s3_region
235
241
  context "s3_host_name" do
236
242
  before do
237
243
  rebuild_model storage: :s3,
238
244
  s3_credentials: {},
239
245
  bucket: "bucket",
240
246
  path: ":attachment/:basename:dotextension",
241
- s3_host_name: "s3-ap-northeast-1.amazonaws.com"
247
+ s3_host_name: "s3-ap-northeast-1.amazonaws.com",
248
+ s3_region: "ap-northeast-1"
242
249
  @dummy = Dummy.new
243
250
  @dummy.avatar = stringy_file
244
251
  @dummy.stubs(:new_record?).returns(false)
245
252
  end
246
253
 
247
254
  it "returns a url based on an :s3_host_name path" do
248
- assert_match %r{^http://s3-ap-northeast-1.amazonaws.com/bucket/avatars/data[^\.]}, @dummy.avatar.url
255
+ assert_match %r{^//s3-ap-northeast-1.amazonaws.com/bucket/avatars/data[^\.]}, @dummy.avatar.url
249
256
  end
250
257
 
251
258
  it "uses the S3 bucket with the correct host name" do
252
- assert_equal "s3-ap-northeast-1.amazonaws.com", @dummy.avatar.s3_bucket.config.s3_endpoint
259
+ assert_equal "s3.ap-northeast-1.amazonaws.com",
260
+ @dummy.avatar.s3_bucket.client.config.endpoint.host
253
261
  end
254
262
  end
255
263
 
256
264
  context "dynamic s3_host_name" do
257
265
  before do
258
- rebuild_model storage: :s3,
266
+ rebuild_model (aws2_add_region).merge storage: :s3,
259
267
  s3_credentials: {},
260
268
  bucket: "bucket",
261
269
  path: ":attachment/:basename:dotextension",
@@ -270,14 +278,67 @@ describe Paperclip::Storage::S3 do
270
278
 
271
279
  it "uses s3_host_name as a proc if available" do
272
280
  @dummy.value = "s3.something.com"
273
- assert_equal "http://s3.something.com/bucket/avatars/data", @dummy.avatar.url(:original, timestamp: false)
281
+ assert_equal "//s3.something.com/bucket/avatars/data", @dummy.avatar.url(:original, timestamp: false)
282
+ end
283
+ end
284
+
285
+ context "use_accelerate_endpoint", if: aws_accelerate_available? do
286
+ context "defaults to false" do
287
+ before do
288
+ rebuild_model(
289
+ storage: :s3,
290
+ s3_credentials: {},
291
+ bucket: "bucket",
292
+ path: ":attachment/:basename:dotextension",
293
+ s3_host_name: "s3-ap-northeast-1.amazonaws.com",
294
+ s3_region: "ap-northeast-1",
295
+ )
296
+ @dummy = Dummy.new
297
+ @dummy.avatar = stringy_file
298
+ @dummy.stubs(:new_record?).returns(false)
299
+ end
300
+
301
+ it "returns a url based on an :s3_host_name path" do
302
+ assert_match %r{^//s3-ap-northeast-1.amazonaws.com/bucket/avatars/data[^\.]},
303
+ @dummy.avatar.url
304
+ end
305
+
306
+ it "uses the S3 client with the use_accelerate_endpoint config is false" do
307
+ expect(@dummy.avatar.s3_bucket.client.config.use_accelerate_endpoint).to be(false)
308
+ end
309
+ end
310
+
311
+ context "set to true", if: aws_accelerate_available? do
312
+ before do
313
+ rebuild_model(
314
+ storage: :s3,
315
+ s3_credentials: {},
316
+ bucket: "bucket",
317
+ path: ":attachment/:basename:dotextension",
318
+ s3_host_name: "s3-accelerate.amazonaws.com",
319
+ s3_region: "ap-northeast-1",
320
+ use_accelerate_endpoint: true,
321
+ )
322
+ @dummy = Dummy.new
323
+ @dummy.avatar = stringy_file
324
+ @dummy.stubs(:new_record?).returns(false)
325
+ end
326
+
327
+ it "returns a url based on an :s3_host_name path" do
328
+ assert_match %r{^//s3-accelerate.amazonaws.com/bucket/avatars/data[^\.]},
329
+ @dummy.avatar.url
330
+ end
331
+
332
+ it "uses the S3 client with the use_accelerate_endpoint config is true" do
333
+ expect(@dummy.avatar.s3_bucket.client.config.use_accelerate_endpoint).to be(true)
334
+ end
274
335
  end
275
336
  end
276
337
 
277
338
  context "An attachment that uses S3 for storage and has styles that return different file types" do
278
339
  before do
279
- rebuild_model styles: { large: ['500x500#', :jpg] },
280
- storage: :s3,
340
+ rebuild_model (aws2_add_region).merge storage: :s3,
341
+ styles: { large: ['500x500#', :jpg] },
281
342
  bucket: "bucket",
282
343
  path: ":attachment/:basename:dotextension",
283
344
  s3_credentials: {
@@ -311,8 +372,10 @@ describe Paperclip::Storage::S3 do
311
372
 
312
373
  context "An attachment that uses S3 for storage and has a proc for styles" do
313
374
  before do
314
- rebuild_model styles: lambda { |attachment| attachment.instance.counter; {thumbnail: { geometry: "50x50#", s3_headers: {'Cache-Control' => 'max-age=31557600'}} }},
315
- storage: :s3,
375
+ rebuild_model (aws2_add_region).merge storage: :s3,
376
+ styles: lambda { |attachment| attachment.instance.counter
377
+ {thumbnail: { geometry: "50x50#",
378
+ s3_headers: {'Cache-Control' => 'max-age=31557600'}} }},
316
379
  bucket: "bucket",
317
380
  path: ":attachment/:style/:basename:dotextension",
318
381
  s3_credentials: {
@@ -336,8 +399,14 @@ describe Paperclip::Storage::S3 do
336
399
  object = stub
337
400
  @dummy.avatar.stubs(:s3_object).with(:original).returns(object)
338
401
  @dummy.avatar.stubs(:s3_object).with(:thumbnail).returns(object)
339
- object.expects(:write).with(anything, content_type: 'image/png', acl: :public_read)
340
- object.expects(:write).with(anything, content_type: 'image/png', acl: :public_read, cache_control: 'max-age=31557600')
402
+
403
+ object.expects(:upload_file)
404
+ .with(anything, content_type: 'image/png',
405
+ acl: :"public-read")
406
+ object.expects(:upload_file)
407
+ .with(anything, content_type: 'image/png',
408
+ acl: :"public-read",
409
+ cache_control: 'max-age=31557600')
341
410
  @dummy.save
342
411
  end
343
412
 
@@ -348,11 +417,63 @@ describe Paperclip::Storage::S3 do
348
417
  end
349
418
  end
350
419
 
420
+ context "An attachment that uses S3 for storage and has styles" do
421
+ before do
422
+ rebuild_model(
423
+ (aws2_add_region).merge(
424
+ storage: :s3,
425
+ styles: { thumb: ["90x90#", :jpg] },
426
+ bucket: "bucket",
427
+ s3_credentials: {
428
+ "access_key_id" => "12345",
429
+ "secret_access_key" => "54321" }
430
+ )
431
+ )
432
+
433
+ @file = File.new(fixture_file("5k.png"), "rb")
434
+ @dummy = Dummy.new
435
+ @dummy.avatar = @file
436
+ @dummy.save
437
+ end
438
+
439
+ context "reprocess" do
440
+ before do
441
+ @object = stub
442
+ @dummy.avatar.stubs(:s3_object).with(:original).returns(@object)
443
+ @dummy.avatar.stubs(:s3_object).with(:thumb).returns(@object)
444
+ @object.stubs(:get).yields(@file.read)
445
+ @object.stubs(:exists?).returns(true)
446
+ end
447
+
448
+ it "uploads original" do
449
+ @object.expects(:upload_file).with(
450
+ anything,
451
+ content_type: "image/png",
452
+ acl: :"public-read").returns(true)
453
+ @object.expects(:upload_file).with(
454
+ anything,
455
+ content_type: "image/jpeg",
456
+ acl: :"public-read").returns(true)
457
+ @dummy.avatar.reprocess!
458
+ end
459
+
460
+ it "doesn't upload original" do
461
+ @object.expects(:upload_file).with(
462
+ anything,
463
+ content_type: "image/jpeg",
464
+ acl: :"public-read").returns(true)
465
+ @dummy.avatar.reprocess!(:thumb)
466
+ end
467
+ end
468
+
469
+ after { @file.close }
470
+ end
471
+
351
472
  context "An attachment that uses S3 for storage and has spaces in file name" do
352
473
  before do
353
474
  rebuild_model(
475
+ (aws2_add_region).merge storage: :s3,
354
476
  styles: { large: ["500x500#", :jpg] },
355
- storage: :s3,
356
477
  bucket: "bucket",
357
478
  s3_credentials: { "access_key_id" => "12345",
358
479
  "secret_access_key" => "54321" }
@@ -376,8 +497,8 @@ describe Paperclip::Storage::S3 do
376
497
 
377
498
  context "An attachment that uses S3 for storage and has a question mark in file name" do
378
499
  before do
379
- rebuild_model styles: { large: ['500x500#', :jpg] },
380
- storage: :s3,
500
+ rebuild_model (aws2_add_region).merge storage: :s3,
501
+ styles: { large: ['500x500#', :jpg] },
381
502
  bucket: "bucket",
382
503
  s3_credentials: {
383
504
  'access_key_id' => "12345",
@@ -390,7 +511,7 @@ describe Paperclip::Storage::S3 do
390
511
  "question?mark.png"
391
512
  end
392
513
  end
393
- file = Paperclip.io_adapters.for(stringio)
514
+ file = Paperclip.io_adapters.for(stringio, hash_digest: Digest::MD5)
394
515
  @dummy = Dummy.new
395
516
  @dummy.avatar = file
396
517
  @dummy.save
@@ -408,7 +529,7 @@ describe Paperclip::Storage::S3 do
408
529
 
409
530
  context "" do
410
531
  before do
411
- rebuild_model storage: :s3,
532
+ rebuild_model (aws2_add_region).merge storage: :s3,
412
533
  s3_credentials: {},
413
534
  bucket: "bucket",
414
535
  path: ":attachment/:basename:dotextension",
@@ -419,14 +540,14 @@ describe Paperclip::Storage::S3 do
419
540
  end
420
541
 
421
542
  it "returns a url based on an S3 subdomain" do
422
- assert_match %r{^http://bucket.s3.amazonaws.com/avatars/data[^\.]}, @dummy.avatar.url
543
+ assert_match %r{^//bucket.s3.amazonaws.com/avatars/data[^\.]}, @dummy.avatar.url
423
544
  end
424
545
  end
425
546
 
426
547
  context "" do
427
548
  before do
428
549
  rebuild_model(
429
- storage: :s3,
550
+ (aws2_add_region).merge storage: :s3,
430
551
  s3_credentials: {
431
552
  production: { bucket: "prod_bucket" },
432
553
  development: { bucket: "dev_bucket" }
@@ -442,13 +563,40 @@ describe Paperclip::Storage::S3 do
442
563
  end
443
564
 
444
565
  it "returns a url based on the host_alias" do
445
- assert_match %r{^http://something.something.com/avatars/data[^\.]}, @dummy.avatar.url
566
+ assert_match %r{^//something.something.com/avatars/data[^\.]}, @dummy.avatar.url
567
+ end
568
+ end
569
+
570
+ context "generating a url with a prefixed host alias" do
571
+ before do
572
+ rebuild_model(
573
+ aws2_add_region.merge(
574
+ storage: :s3,
575
+ s3_credentials: {
576
+ production: { bucket: "prod_bucket" },
577
+ development: { bucket: "dev_bucket" },
578
+ },
579
+ bucket: "bucket",
580
+ s3_host_alias: "something.something.com",
581
+ s3_prefixes_in_alias: 2,
582
+ path: "prefix1/prefix2/:attachment/:basename:dotextension",
583
+ url: ":s3_alias_url",
584
+ )
585
+ )
586
+ @dummy = Dummy.new
587
+ @dummy.avatar = stringy_file
588
+ @dummy.stubs(:new_record?).returns(false)
589
+ end
590
+
591
+ it "returns a url with the prefixes removed" do
592
+ assert_match %r{^//something.something.com/avatars/data[^\.]},
593
+ @dummy.avatar.url
446
594
  end
447
595
  end
448
596
 
449
597
  context "generating a url with a proc as the host alias" do
450
598
  before do
451
- rebuild_model storage: :s3,
599
+ rebuild_model (aws2_add_region).merge storage: :s3,
452
600
  s3_credentials: { bucket: "prod_bucket" },
453
601
  s3_host_alias: Proc.new{|atch| "cdn#{atch.instance.counter % 4}.example.com"},
454
602
  path: ":attachment/:basename:dotextension",
@@ -466,8 +614,8 @@ describe Paperclip::Storage::S3 do
466
614
  end
467
615
 
468
616
  it "returns a url based on the host_alias" do
469
- assert_match %r{^http://cdn1.example.com/avatars/data[^\.]}, @dummy.avatar.url
470
- assert_match %r{^http://cdn2.example.com/avatars/data[^\.]}, @dummy.avatar.url
617
+ assert_match %r{^//cdn1.example.com/avatars/data[^\.]}, @dummy.avatar.url
618
+ assert_match %r{^//cdn2.example.com/avatars/data[^\.]}, @dummy.avatar.url
471
619
  end
472
620
 
473
621
  it "still returns the bucket name" do
@@ -478,7 +626,7 @@ describe Paperclip::Storage::S3 do
478
626
 
479
627
  context "" do
480
628
  before do
481
- rebuild_model storage: :s3,
629
+ rebuild_model (aws2_add_region).merge storage: :s3,
482
630
  s3_credentials: {},
483
631
  bucket: "bucket",
484
632
  path: ":attachment/:basename:dotextension",
@@ -509,7 +657,7 @@ describe Paperclip::Storage::S3 do
509
657
  url: ":s3_alias_url"
510
658
  }
511
659
 
512
- rebuild_model base_options.merge(options)
660
+ rebuild_model (aws2_add_region).merge base_options.merge(options)
513
661
  }
514
662
  end
515
663
 
@@ -522,8 +670,8 @@ describe Paperclip::Storage::S3 do
522
670
 
523
671
  object = stub
524
672
  @dummy.avatar.stubs(:s3_object).returns(object)
525
- object.expects(:url_for).with(:read, expires: 3600, secure: true)
526
673
 
674
+ object.expects(:presigned_url).with(:get, expires_in: 3600)
527
675
  @dummy.avatar.expiring_url
528
676
  end
529
677
  end
@@ -537,8 +685,9 @@ describe Paperclip::Storage::S3 do
537
685
 
538
686
  object = stub
539
687
  @dummy.avatar.stubs(:s3_object).returns(object)
540
- object.expects(:url_for).with(:read, expires: 3600, secure: true, response_content_disposition: "inline")
541
-
688
+ object.expects(:presigned_url)
689
+ .with(:get, expires_in: 3600,
690
+ response_content_disposition: "inline")
542
691
  @dummy.avatar.expiring_url
543
692
  end
544
693
  end
@@ -559,8 +708,8 @@ describe Paperclip::Storage::S3 do
559
708
 
560
709
  object = stub
561
710
  @dummy.avatar.stubs(:s3_object).returns(object)
562
- object.expects(:url_for).with(:read, expires: 3600, secure: true, response_content_type: "image/png")
563
-
711
+ object.expects(:presigned_url)
712
+ .with(:get, expires_in: 3600, response_content_type: "image/png")
564
713
  @dummy.avatar.expiring_url
565
714
  end
566
715
  end
@@ -588,15 +737,15 @@ describe Paperclip::Storage::S3 do
588
737
 
589
738
  context "Generating a url with an expiration for each style" do
590
739
  before do
591
- rebuild_model storage: :s3,
740
+ rebuild_model (aws2_add_region).merge storage: :s3,
592
741
  s3_credentials: {
593
- production: { bucket: "prod_bucket" },
594
- development: { bucket: "dev_bucket" }
595
- },
596
- s3_permissions: :private,
597
- s3_host_alias: "something.something.com",
598
- path: ":attachment/:style/:basename:dotextension",
599
- url: ":s3_alias_url"
742
+ production: { bucket: "prod_bucket" },
743
+ development: { bucket: "dev_bucket" }
744
+ },
745
+ s3_permissions: :private,
746
+ s3_host_alias: "something.something.com",
747
+ path: ":attachment/:style/:basename:dotextension",
748
+ url: ":s3_alias_url"
600
749
 
601
750
  rails_env("production") do
602
751
  @dummy = Dummy.new
@@ -607,26 +756,26 @@ describe Paperclip::Storage::S3 do
607
756
  it "generates a url for the thumb" do
608
757
  object = stub
609
758
  @dummy.avatar.stubs(:s3_object).with(:thumb).returns(object)
610
- object.expects(:url_for).with(:read, expires: 1800, secure: true)
759
+ object.expects(:presigned_url).with(:get, expires_in: 1800)
611
760
  @dummy.avatar.expiring_url(1800, :thumb)
612
761
  end
613
762
 
614
763
  it "generates a url for the default style" do
615
764
  object = stub
616
765
  @dummy.avatar.stubs(:s3_object).with(:original).returns(object)
617
- object.expects(:url_for).with(:read, expires: 1800, secure: true)
766
+ object.expects(:presigned_url).with(:get, expires_in: 1800)
618
767
  @dummy.avatar.expiring_url(1800)
619
768
  end
620
769
  end
621
770
 
622
771
  context "Parsing S3 credentials with a bucket in them" do
623
772
  before do
624
- rebuild_model storage: :s3,
773
+ rebuild_model (aws2_add_region).merge storage: :s3,
625
774
  s3_credentials: {
626
- production: { bucket: "prod_bucket" },
627
- development: { bucket: "dev_bucket" }
628
- }
629
- @dummy = Dummy.new
775
+ production: { bucket: "prod_bucket" },
776
+ development: { bucket: "dev_bucket" }
777
+ }
778
+ @dummy = Dummy.new
630
779
  end
631
780
 
632
781
  it "gets the right bucket in production" do
@@ -644,47 +793,59 @@ describe Paperclip::Storage::S3 do
644
793
  end
645
794
  end
646
795
 
796
+ # for aws-sdk-v2 the bucket.name is determined by the :s3_region
647
797
  context "Parsing S3 credentials with a s3_host_name in them" do
648
798
  before do
649
799
  rebuild_model storage: :s3,
650
800
  bucket: 'testing',
651
801
  s3_credentials: {
652
- production: { s3_host_name: "s3-world-end.amazonaws.com" },
653
- development: { s3_host_name: "s3-ap-northeast-1.amazonaws.com" }
802
+ production: {
803
+ s3_region: "world-end",
804
+ s3_host_name: "s3-world-end.amazonaws.com" },
805
+ development: {
806
+ s3_region: "ap-northeast-1",
807
+ s3_host_name: "s3-ap-northeast-1.amazonaws.com" },
808
+ test: {
809
+ s3_region: "" }
654
810
  }
655
- @dummy = Dummy.new
811
+ @dummy = Dummy.new
656
812
  end
657
813
 
658
814
  it "gets the right s3_host_name in production" do
659
815
  rails_env("production") do
660
816
  assert_match %r{^s3-world-end.amazonaws.com}, @dummy.avatar.s3_host_name
661
- assert_match %r{^s3-world-end.amazonaws.com}, @dummy.avatar.s3_bucket.config.s3_endpoint
817
+ assert_match %r{^s3.world-end.amazonaws.com},
818
+ @dummy.avatar.s3_bucket.client.config.endpoint.host
662
819
  end
663
820
  end
664
821
 
665
822
  it "gets the right s3_host_name in development" do
666
823
  rails_env("development") do
667
- assert_match %r{^s3-ap-northeast-1.amazonaws.com}, @dummy.avatar.s3_host_name
668
- assert_match %r{^s3-ap-northeast-1.amazonaws.com}, @dummy.avatar.s3_bucket.config.s3_endpoint
824
+ assert_match %r{^s3.ap-northeast-1.amazonaws.com},
825
+ @dummy.avatar.s3_host_name
826
+ assert_match %r{^s3.ap-northeast-1.amazonaws.com},
827
+ @dummy.avatar.s3_bucket.client.config.endpoint.host
669
828
  end
670
829
  end
671
830
 
672
831
  it "gets the right s3_host_name if the key does not exist" do
673
832
  rails_env("test") do
674
833
  assert_match %r{^s3.amazonaws.com}, @dummy.avatar.s3_host_name
675
- assert_match %r{^s3.amazonaws.com}, @dummy.avatar.s3_bucket.config.s3_endpoint
834
+ assert_raises(Aws::Errors::MissingRegionError) do
835
+ @dummy.avatar.s3_bucket.client.config.endpoint.host
836
+ end
676
837
  end
677
838
  end
678
839
  end
679
840
 
680
841
  context "An attachment with S3 storage" do
681
842
  before do
682
- rebuild_model storage: :s3,
843
+ rebuild_model (aws2_add_region).merge storage: :s3,
683
844
  bucket: "testing",
684
845
  path: ":attachment/:style/:basename:dotextension",
685
846
  s3_credentials: {
686
- aws_access_key_id: "12345",
687
- aws_secret_access_key: "54321"
847
+ access_key_id: "12345",
848
+ secret_access_key: "54321"
688
849
  }
689
850
  end
690
851
 
@@ -709,20 +870,19 @@ describe Paperclip::Storage::S3 do
709
870
  it "does not get a bucket to get a URL" do
710
871
  @dummy.avatar.expects(:s3).never
711
872
  @dummy.avatar.expects(:s3_bucket).never
712
- assert_match %r{^http://s3\.amazonaws\.com/testing/avatars/original/5k\.png}, @dummy.avatar.url
873
+ assert_match %r{^//s3\.amazonaws\.com/testing/avatars/original/5k\.png}, @dummy.avatar.url
713
874
  end
714
875
 
715
876
  it "is rewound after flush_writes" do
716
877
  @dummy.avatar.instance_eval "def after_flush_writes; end"
717
- @dummy.avatar.stubs(:s3_object).returns(stub(write: true))
718
-
878
+ @dummy.avatar.stubs(:s3_object).returns(stub(upload_file: true))
719
879
  files = @dummy.avatar.queued_for_write.values.each(&:read)
720
880
  @dummy.save
721
881
  assert files.none?(&:eof?), "Expect all the files to be rewound."
722
882
  end
723
883
 
724
884
  it "is removed after after_flush_writes" do
725
- @dummy.avatar.stubs(:s3_object).returns(stub(write: true))
885
+ @dummy.avatar.stubs(:s3_object).returns(stub(upload_file: true))
726
886
  paths = @dummy.avatar.queued_for_write.values.map(&:path)
727
887
  @dummy.save
728
888
  assert paths.none?{ |path| File.exist?(path) },
@@ -731,10 +891,10 @@ describe Paperclip::Storage::S3 do
731
891
 
732
892
  it "will retry to save again but back off on SlowDown" do
733
893
  @dummy.avatar.stubs(:sleep)
734
- AWS::S3::S3Object.any_instance.stubs(:write).
735
- raises(AWS::S3::Errors::SlowDown.new(stub, stub(status: 503, body: "")))
736
-
737
- expect {@dummy.save}.to raise_error(AWS::S3::Errors::SlowDown)
894
+ Aws::S3::Object.any_instance.stubs(:upload_file).
895
+ raises(Aws::S3::Errors::SlowDown.new(stub,
896
+ stub(status: 503, body: "")))
897
+ expect {@dummy.save}.to raise_error(Aws::S3::Errors::SlowDown)
738
898
  expect(@dummy.avatar).to have_received(:sleep).with(1)
739
899
  expect(@dummy.avatar).to have_received(:sleep).with(2)
740
900
  expect(@dummy.avatar).to have_received(:sleep).with(4)
@@ -746,9 +906,8 @@ describe Paperclip::Storage::S3 do
746
906
  before do
747
907
  object = stub
748
908
  @dummy.avatar.stubs(:s3_object).returns(object)
749
- object.expects(:write).with(anything,
750
- content_type: "image/png",
751
- acl: :public_read)
909
+ object.expects(:upload_file)
910
+ .with(anything, content_type: 'image/png', acl: :"public-read")
752
911
  @dummy.save
753
912
  end
754
913
 
@@ -759,12 +918,11 @@ describe Paperclip::Storage::S3 do
759
918
 
760
919
  context "and saved without a bucket" do
761
920
  before do
762
- AWS::S3::BucketCollection.any_instance.expects(:create).with("testing")
763
- AWS::S3::S3Object.any_instance.stubs(:write).
764
- raises(AWS::S3::Errors::NoSuchBucket.new(stub,
765
- stub(status: 404,
766
- body: "<foo/>"))).
767
- then.returns(nil)
921
+ Aws::S3::Bucket.any_instance.expects(:create)
922
+ Aws::S3::Object.any_instance.stubs(:upload_file).
923
+ raises(Aws::S3::Errors::NoSuchBucket
924
+ .new(stub,
925
+ stub(status: 404, body: "<foo/>"))).then.returns(nil)
768
926
  @dummy.save
769
927
  end
770
928
 
@@ -775,8 +933,8 @@ describe Paperclip::Storage::S3 do
775
933
 
776
934
  context "and remove" do
777
935
  before do
778
- AWS::S3::S3Object.any_instance.stubs(:exists?).returns(true)
779
- AWS::S3::S3Object.any_instance.stubs(:delete)
936
+ Aws::S3::Object.any_instance.stubs(:exists?).returns(true)
937
+ Aws::S3::Object.any_instance.stubs(:delete)
780
938
  @dummy.destroy
781
939
  end
782
940
 
@@ -787,7 +945,9 @@ describe Paperclip::Storage::S3 do
787
945
 
788
946
  context 'that the file were missing' do
789
947
  before do
790
- AWS::S3::S3Object.any_instance.stubs(:exists?).raises(AWS::Errors::Base)
948
+ Aws::S3::Object.any_instance.stubs(:exists?)
949
+ .raises(Aws::S3::Errors::ServiceError.new("rspec stub raises",
950
+ "object exists?"))
791
951
  end
792
952
 
793
953
  it 'returns false on exists?' do
@@ -799,7 +959,7 @@ describe Paperclip::Storage::S3 do
799
959
 
800
960
  context "An attachment with S3 storage and bucket defined as a Proc" do
801
961
  before do
802
- rebuild_model storage: :s3,
962
+ rebuild_model (aws2_add_region).merge storage: :s3,
803
963
  bucket: lambda { |attachment| "bucket_#{attachment.instance.other}" },
804
964
  s3_credentials: {not: :important}
805
965
  end
@@ -814,7 +974,7 @@ describe Paperclip::Storage::S3 do
814
974
 
815
975
  context "An attachment with S3 storage and S3 credentials defined as a Proc" do
816
976
  before do
817
- rebuild_model storage: :s3,
977
+ rebuild_model (aws2_add_region).merge storage: :s3,
818
978
  bucket: {not: :important},
819
979
  s3_credentials: lambda { |attachment|
820
980
  Hash['access_key_id' => "access#{attachment.instance.other}", 'secret_access_key' => "secret#{attachment.instance.other}"]
@@ -831,22 +991,23 @@ describe Paperclip::Storage::S3 do
831
991
  before do
832
992
  class DummyCredentialProvider; end
833
993
 
834
- rebuild_model storage: :s3,
994
+ rebuild_model (aws2_add_region).merge storage: :s3,
835
995
  bucket: "testing",
836
996
  s3_credentials: {
837
- credential_provider: DummyCredentialProvider.new
997
+ credentials: DummyCredentialProvider.new
838
998
  }
839
- @dummy = Dummy.new
999
+ @dummy = Dummy.new
840
1000
  end
841
1001
 
842
1002
  it "sets the credential-provider" do
843
- expect(@dummy.avatar.s3_bucket.config.credential_provider).to be_a DummyCredentialProvider
1003
+ expect(@dummy.avatar.s3_bucket.client.config.credentials).to be_a DummyCredentialProvider
844
1004
  end
845
1005
  end
846
1006
 
847
1007
  context "An attachment with S3 storage and S3 credentials in an unsupported manor" do
848
1008
  before do
849
- rebuild_model storage: :s3, bucket: "testing", s3_credentials: ["unsupported"]
1009
+ rebuild_model (aws2_add_region).merge storage: :s3,
1010
+ bucket: "testing", s3_credentials: ["unsupported"]
850
1011
  @dummy = Dummy.new
851
1012
  end
852
1013
 
@@ -859,7 +1020,7 @@ describe Paperclip::Storage::S3 do
859
1020
 
860
1021
  context "An attachment with S3 storage and S3 credentials not supplied" do
861
1022
  before do
862
- rebuild_model storage: :s3, bucket: "testing"
1023
+ rebuild_model (aws2_add_region).merge storage: :s3, bucket: "testing"
863
1024
  @dummy = Dummy.new
864
1025
  end
865
1026
 
@@ -870,7 +1031,7 @@ describe Paperclip::Storage::S3 do
870
1031
 
871
1032
  context "An attachment with S3 storage and specific s3 headers set" do
872
1033
  before do
873
- rebuild_model storage: :s3,
1034
+ rebuild_model (aws2_add_region).merge storage: :s3,
874
1035
  bucket: "testing",
875
1036
  path: ":attachment/:style/:basename:dotextension",
876
1037
  s3_credentials: {
@@ -893,10 +1054,12 @@ describe Paperclip::Storage::S3 do
893
1054
  before do
894
1055
  object = stub
895
1056
  @dummy.avatar.stubs(:s3_object).returns(object)
896
- object.expects(:write).with(anything,
897
- content_type: "image/png",
898
- acl: :public_read,
899
- cache_control: 'max-age=31557600')
1057
+
1058
+ object.expects(:upload_file)
1059
+ .with(anything,
1060
+ content_type: 'image/png',
1061
+ acl: :"public-read",
1062
+ cache_control: 'max-age=31557600')
900
1063
  @dummy.save
901
1064
  end
902
1065
 
@@ -909,7 +1072,7 @@ describe Paperclip::Storage::S3 do
909
1072
 
910
1073
  context "An attachment with S3 storage and metadata set using header names" do
911
1074
  before do
912
- rebuild_model storage: :s3,
1075
+ rebuild_model (aws2_add_region).merge storage: :s3,
913
1076
  bucket: "testing",
914
1077
  path: ":attachment/:style/:basename:dotextension",
915
1078
  s3_credentials: {
@@ -932,10 +1095,12 @@ describe Paperclip::Storage::S3 do
932
1095
  before do
933
1096
  object = stub
934
1097
  @dummy.avatar.stubs(:s3_object).returns(object)
935
- object.expects(:write).with(anything,
936
- content_type: "image/png",
937
- acl: :public_read,
938
- metadata: { "color" => "red" })
1098
+
1099
+ object.expects(:upload_file)
1100
+ .with(anything,
1101
+ content_type: 'image/png',
1102
+ acl: :"public-read",
1103
+ metadata: { "color" => "red" })
939
1104
  @dummy.save
940
1105
  end
941
1106
 
@@ -948,7 +1113,7 @@ describe Paperclip::Storage::S3 do
948
1113
 
949
1114
  context "An attachment with S3 storage and metadata set using the :s3_metadata option" do
950
1115
  before do
951
- rebuild_model storage: :s3,
1116
+ rebuild_model (aws2_add_region).merge storage: :s3,
952
1117
  bucket: "testing",
953
1118
  path: ":attachment/:style/:basename:dotextension",
954
1119
  s3_credentials: {
@@ -971,10 +1136,12 @@ describe Paperclip::Storage::S3 do
971
1136
  before do
972
1137
  object = stub
973
1138
  @dummy.avatar.stubs(:s3_object).returns(object)
974
- object.expects(:write).with(anything,
975
- content_type: "image/png",
976
- acl: :public_read,
977
- metadata: { "color" => "red" })
1139
+
1140
+ object.expects(:upload_file)
1141
+ .with(anything,
1142
+ content_type: 'image/png',
1143
+ acl: :"public-read",
1144
+ metadata: { "color" => "red" })
978
1145
  @dummy.save
979
1146
  end
980
1147
 
@@ -988,7 +1155,7 @@ describe Paperclip::Storage::S3 do
988
1155
  context "An attachment with S3 storage and storage class set" do
989
1156
  context "using the header name" do
990
1157
  before do
991
- rebuild_model storage: :s3,
1158
+ rebuild_model (aws2_add_region).merge storage: :s3,
992
1159
  bucket: "testing",
993
1160
  path: ":attachment/:style/:basename:dotextension",
994
1161
  s3_credentials: {
@@ -1011,10 +1178,12 @@ describe Paperclip::Storage::S3 do
1011
1178
  before do
1012
1179
  object = stub
1013
1180
  @dummy.avatar.stubs(:s3_object).returns(object)
1014
- object.expects(:write).with(anything,
1015
- content_type: "image/png",
1016
- acl: :public_read,
1017
- storage_class: "reduced_redundancy")
1181
+
1182
+ object.expects(:upload_file)
1183
+ .with(anything,
1184
+ content_type: 'image/png',
1185
+ acl: :"public-read",
1186
+ storage_class: "reduced_redundancy")
1018
1187
  @dummy.save
1019
1188
  end
1020
1189
 
@@ -1027,7 +1196,7 @@ describe Paperclip::Storage::S3 do
1027
1196
 
1028
1197
  context "using per style hash" do
1029
1198
  before do
1030
- rebuild_model :storage => :s3,
1199
+ rebuild_model (aws2_add_region).merge :storage => :s3,
1031
1200
  :bucket => "testing",
1032
1201
  :path => ":attachment/:style/:basename.:extension",
1033
1202
  :styles => {
@@ -1056,9 +1225,15 @@ describe Paperclip::Storage::S3 do
1056
1225
  object = stub
1057
1226
  [:thumb, :original].each do |style|
1058
1227
  @dummy.avatar.stubs(:s3_object).with(style).returns(object)
1059
- expected_options = {:content_type => "image/png", :acl => :public_read}
1228
+
1229
+ expected_options = {
1230
+ :content_type => "image/png",
1231
+ acl: :"public-read"
1232
+ }
1060
1233
  expected_options.merge!(:storage_class => :reduced_redundancy) if style == :thumb
1061
- object.expects(:write).with(anything, expected_options)
1234
+
1235
+ object.expects(:upload_file)
1236
+ .with(anything, expected_options)
1062
1237
  end
1063
1238
  @dummy.save
1064
1239
  end
@@ -1072,7 +1247,7 @@ describe Paperclip::Storage::S3 do
1072
1247
 
1073
1248
  context "using global hash option" do
1074
1249
  before do
1075
- rebuild_model :storage => :s3,
1250
+ rebuild_model (aws2_add_region).merge :storage => :s3,
1076
1251
  :bucket => "testing",
1077
1252
  :path => ":attachment/:style/:basename.:extension",
1078
1253
  :styles => {
@@ -1099,9 +1274,11 @@ describe Paperclip::Storage::S3 do
1099
1274
  object = stub
1100
1275
  [:thumb, :original].each do |style|
1101
1276
  @dummy.avatar.stubs(:s3_object).with(style).returns(object)
1102
- object.expects(:write).with(anything, :content_type => "image/png",
1103
- :acl => :public_read,
1104
- :storage_class => :reduced_redundancy)
1277
+
1278
+ object.expects(:upload_file)
1279
+ .with(anything, :content_type => "image/png",
1280
+ acl: :"public-read",
1281
+ :storage_class => :reduced_redundancy)
1105
1282
  end
1106
1283
  @dummy.save
1107
1284
  end
@@ -1118,7 +1295,7 @@ describe Paperclip::Storage::S3 do
1118
1295
  [nil, false, ''].each do |tech|
1119
1296
  before do
1120
1297
  rebuild_model(
1121
- storage: :s3,
1298
+ (aws2_add_region).merge storage: :s3,
1122
1299
  bucket: "testing",
1123
1300
  path: ":attachment/:style/:basename:dotextension",
1124
1301
  s3_credentials: {
@@ -1140,9 +1317,9 @@ describe Paperclip::Storage::S3 do
1140
1317
  before do
1141
1318
  object = stub
1142
1319
  @dummy.avatar.stubs(:s3_object).returns(object)
1143
- object.expects(:write).with(anything,
1144
- content_type: "image/png",
1145
- acl: :public_read)
1320
+
1321
+ object.expects(:upload_file)
1322
+ .with(anything, :content_type => "image/png", acl: :"public-read")
1146
1323
  @dummy.save
1147
1324
  end
1148
1325
 
@@ -1156,14 +1333,14 @@ describe Paperclip::Storage::S3 do
1156
1333
 
1157
1334
  context "An attachment with S3 storage and using AES256 encryption" do
1158
1335
  before do
1159
- rebuild_model storage: :s3,
1336
+ rebuild_model (aws2_add_region).merge storage: :s3,
1160
1337
  bucket: "testing",
1161
1338
  path: ":attachment/:style/:basename:dotextension",
1162
1339
  s3_credentials: {
1163
1340
  'access_key_id' => "12345",
1164
1341
  'secret_access_key' => "54321"
1165
1342
  },
1166
- s3_server_side_encryption: :aes256
1343
+ s3_server_side_encryption: "AES256"
1167
1344
  end
1168
1345
 
1169
1346
  context "when assigned" do
@@ -1179,10 +1356,11 @@ describe Paperclip::Storage::S3 do
1179
1356
  before do
1180
1357
  object = stub
1181
1358
  @dummy.avatar.stubs(:s3_object).returns(object)
1182
- object.expects(:write).with(anything,
1183
- content_type: "image/png",
1184
- acl: :public_read,
1185
- server_side_encryption: :aes256)
1359
+
1360
+ object.expects(:upload_file)
1361
+ .with(anything, content_type: "image/png",
1362
+ acl: :"public-read",
1363
+ server_side_encryption: "AES256")
1186
1364
  @dummy.save
1187
1365
  end
1188
1366
 
@@ -1195,7 +1373,7 @@ describe Paperclip::Storage::S3 do
1195
1373
 
1196
1374
  context "An attachment with S3 storage and storage class set using the :storage_class option" do
1197
1375
  before do
1198
- rebuild_model storage: :s3,
1376
+ rebuild_model (aws2_add_region).merge storage: :s3,
1199
1377
  bucket: "testing",
1200
1378
  path: ":attachment/:style/:basename:dotextension",
1201
1379
  s3_credentials: {
@@ -1218,10 +1396,12 @@ describe Paperclip::Storage::S3 do
1218
1396
  before do
1219
1397
  object = stub
1220
1398
  @dummy.avatar.stubs(:s3_object).returns(object)
1221
- object.expects(:write).with(anything,
1222
- content_type: "image/png",
1223
- acl: :public_read,
1224
- storage_class: :reduced_redundancy)
1399
+
1400
+ object.expects(:upload_file)
1401
+ .with(anything,
1402
+ content_type: "image/png",
1403
+ acl: :"public-read",
1404
+ storage_class: :reduced_redundancy)
1225
1405
  @dummy.save
1226
1406
  end
1227
1407
 
@@ -1239,7 +1419,7 @@ describe Paperclip::Storage::S3 do
1239
1419
  ENV['S3_SECRET'] = 'pathname_secret'
1240
1420
 
1241
1421
  rails_env('test') do
1242
- rebuild_model storage: :s3,
1422
+ rebuild_model (aws2_add_region).merge storage: :s3,
1243
1423
  s3_credentials: Pathname.new(fixture_file('s3.yml'))
1244
1424
 
1245
1425
  Dummy.delete_all
@@ -1249,8 +1429,12 @@ describe Paperclip::Storage::S3 do
1249
1429
 
1250
1430
  it "parses the credentials" do
1251
1431
  assert_equal 'pathname_bucket', @dummy.avatar.bucket_name
1252
- assert_equal 'pathname_key', @dummy.avatar.s3_bucket.config.access_key_id
1253
- assert_equal 'pathname_secret', @dummy.avatar.s3_bucket.config.secret_access_key
1432
+
1433
+ assert_equal 'pathname_key',
1434
+ @dummy.avatar.s3_bucket.client.config.access_key_id
1435
+
1436
+ assert_equal 'pathname_secret',
1437
+ @dummy.avatar.s3_bucket.client.config.secret_access_key
1254
1438
  end
1255
1439
  end
1256
1440
 
@@ -1261,7 +1445,7 @@ describe Paperclip::Storage::S3 do
1261
1445
  ENV['S3_SECRET'] = 'env_secret'
1262
1446
 
1263
1447
  rails_env('test') do
1264
- rebuild_model storage: :s3,
1448
+ rebuild_model (aws2_add_region).merge storage: :s3,
1265
1449
  s3_credentials: File.new(fixture_file('s3.yml'))
1266
1450
 
1267
1451
  Dummy.delete_all
@@ -1272,15 +1456,19 @@ describe Paperclip::Storage::S3 do
1272
1456
 
1273
1457
  it "runs the file through ERB" do
1274
1458
  assert_equal 'env_bucket', @dummy.avatar.bucket_name
1275
- assert_equal 'env_key', @dummy.avatar.s3_bucket.config.access_key_id
1276
- assert_equal 'env_secret', @dummy.avatar.s3_bucket.config.secret_access_key
1459
+
1460
+ assert_equal 'env_key',
1461
+ @dummy.avatar.s3_bucket.client.config.access_key_id
1462
+
1463
+ assert_equal 'env_secret',
1464
+ @dummy.avatar.s3_bucket.client.config.secret_access_key
1277
1465
  end
1278
1466
  end
1279
1467
 
1280
1468
  context "S3 Permissions" do
1281
1469
  context "defaults to :public_read" do
1282
1470
  before do
1283
- rebuild_model storage: :s3,
1471
+ rebuild_model (aws2_add_region).merge storage: :s3,
1284
1472
  bucket: "testing",
1285
1473
  path: ":attachment/:style/:basename:dotextension",
1286
1474
  s3_credentials: {
@@ -1302,9 +1490,9 @@ describe Paperclip::Storage::S3 do
1302
1490
  before do
1303
1491
  object = stub
1304
1492
  @dummy.avatar.stubs(:s3_object).returns(object)
1305
- object.expects(:write).with(anything,
1306
- content_type: "image/png",
1307
- acl: :public_read)
1493
+
1494
+ object.expects(:upload_file)
1495
+ .with(anything, content_type: "image/png", acl: :"public-read")
1308
1496
  @dummy.save
1309
1497
  end
1310
1498
 
@@ -1317,7 +1505,7 @@ describe Paperclip::Storage::S3 do
1317
1505
 
1318
1506
  context "string permissions set" do
1319
1507
  before do
1320
- rebuild_model storage: :s3,
1508
+ rebuild_model (aws2_add_region).merge storage: :s3,
1321
1509
  bucket: "testing",
1322
1510
  path: ":attachment/:style/:basename:dotextension",
1323
1511
  s3_credentials: {
@@ -1340,9 +1528,9 @@ describe Paperclip::Storage::S3 do
1340
1528
  before do
1341
1529
  object = stub
1342
1530
  @dummy.avatar.stubs(:s3_object).returns(object)
1343
- object.expects(:write).with(anything,
1344
- content_type: "image/png",
1345
- acl: :private)
1531
+
1532
+ object.expects(:upload_file)
1533
+ .with(anything, content_type: "image/png", acl: :private)
1346
1534
  @dummy.save
1347
1535
  end
1348
1536
 
@@ -1355,7 +1543,7 @@ describe Paperclip::Storage::S3 do
1355
1543
 
1356
1544
  context "hash permissions set" do
1357
1545
  before do
1358
- rebuild_model storage: :s3,
1546
+ rebuild_model (aws2_add_region).merge storage: :s3,
1359
1547
  bucket: "testing",
1360
1548
  path: ":attachment/:style/:basename:dotextension",
1361
1549
  styles: {
@@ -1385,9 +1573,11 @@ describe Paperclip::Storage::S3 do
1385
1573
  [:thumb, :original].each do |style|
1386
1574
  object = stub
1387
1575
  @dummy.avatar.stubs(:s3_object).with(style).returns(object)
1388
- object.expects(:write).with(anything,
1389
- content_type: "image/png",
1390
- acl: style == :thumb ? :public_read : :private)
1576
+
1577
+ object.expects(:upload_file)
1578
+ .with(anything,
1579
+ content_type: "image/png",
1580
+ acl: style == :thumb ? :public_read : :private)
1391
1581
  end
1392
1582
  @dummy.save
1393
1583
  end
@@ -1402,7 +1592,7 @@ describe Paperclip::Storage::S3 do
1402
1592
  context "proc permission set" do
1403
1593
  before do
1404
1594
  rebuild_model(
1405
- storage: :s3,
1595
+ (aws2_add_region).merge storage: :s3,
1406
1596
  bucket: "testing",
1407
1597
  path: ":attachment/:style/:basename:dotextension",
1408
1598
  styles: {
@@ -1413,40 +1603,17 @@ describe Paperclip::Storage::S3 do
1413
1603
  'secret_access_key' => "54321"
1414
1604
  },
1415
1605
  s3_permissions: lambda {|attachment, style|
1416
- attachment.instance.private_attachment? && style.to_sym != :thumb ? :private : :public_read
1606
+ attachment.instance.private_attachment? && style.to_sym != :thumb ? :private : :"public-read"
1417
1607
  }
1418
1608
  )
1419
1609
  end
1420
-
1421
- context "when assigned" do
1422
- before do
1423
- @file = File.new(fixture_file('5k.png'), 'rb')
1424
- @dummy = Dummy.new
1425
- @dummy.stubs(:private_attachment? => true)
1426
- @dummy.avatar = @file
1427
- end
1428
-
1429
- after { @file.close }
1430
-
1431
- context "and saved" do
1432
- before do
1433
- @dummy.save
1434
- end
1435
-
1436
- it "succeeds" do
1437
- assert @dummy.avatar.url().include? "https://"
1438
- assert @dummy.avatar.url(:thumb).include? "http://"
1439
- end
1440
- end
1441
- end
1442
-
1443
1610
  end
1444
1611
  end
1445
1612
 
1446
1613
  context "An attachment with S3 storage and metadata set using a proc as headers" do
1447
1614
  before do
1448
1615
  rebuild_model(
1449
- storage: :s3,
1616
+ (aws2_add_region).merge storage: :s3,
1450
1617
  bucket: "testing",
1451
1618
  path: ":attachment/:style/:basename:dotextension",
1452
1619
  styles: {
@@ -1477,10 +1644,12 @@ describe Paperclip::Storage::S3 do
1477
1644
  [:thumb, :original].each do |style|
1478
1645
  object = stub
1479
1646
  @dummy.avatar.stubs(:s3_object).with(style).returns(object)
1480
- object.expects(:write).with(anything,
1481
- content_type: "image/png",
1482
- acl: :public_read,
1483
- content_disposition: 'attachment; filename="Custom Avatar Name.png"')
1647
+
1648
+ object.expects(:upload_file)
1649
+ .with(anything,
1650
+ content_type: "image/png",
1651
+ acl: :"public-read",
1652
+ content_disposition: 'attachment; filename="Custom Avatar Name.png"')
1484
1653
  end
1485
1654
  @dummy.save
1486
1655
  end
@@ -1494,7 +1663,7 @@ describe Paperclip::Storage::S3 do
1494
1663
 
1495
1664
  context "path is a proc" do
1496
1665
  before do
1497
- rebuild_model storage: :s3,
1666
+ rebuild_model (aws2_add_region).merge storage: :s3,
1498
1667
  path: ->(attachment) { attachment.instance.attachment_path }
1499
1668
 
1500
1669
  @dummy = Dummy.new
@@ -1511,7 +1680,6 @@ describe Paperclip::Storage::S3 do
1511
1680
  end
1512
1681
  end
1513
1682
 
1514
-
1515
1683
  private
1516
1684
 
1517
1685
  def rails_env(env)
@@ -1522,5 +1690,4 @@ describe Paperclip::Storage::S3 do
1522
1690
  Rails.env = stored_env
1523
1691
  end
1524
1692
  end
1525
-
1526
1693
  end