paperclip 3.5.4 → 4.3.7
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of paperclip might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/.gitignore +0 -6
- data/.hound.yml +1066 -0
- data/.rubocop.yml +1 -0
- data/.travis.yml +11 -17
- data/Appraisals +6 -14
- data/CONTRIBUTING.md +13 -8
- data/Gemfile +16 -3
- data/LICENSE +1 -3
- data/NEWS +167 -49
- data/README.md +294 -75
- data/RELEASING.md +17 -0
- data/Rakefile +6 -8
- data/features/basic_integration.feature +24 -6
- data/features/step_definitions/attachment_steps.rb +30 -22
- data/features/step_definitions/html_steps.rb +2 -2
- data/features/step_definitions/rails_steps.rb +44 -14
- data/features/step_definitions/web_steps.rb +1 -103
- data/features/support/env.rb +2 -2
- data/features/support/file_helpers.rb +2 -2
- data/features/support/fixtures/gemfile.txt +1 -1
- data/features/support/rails.rb +2 -1
- data/gemfiles/3.2.gemfile +14 -6
- data/gemfiles/4.1.gemfile +19 -0
- data/gemfiles/4.2.gemfile +19 -0
- data/lib/generators/paperclip/paperclip_generator.rb +0 -2
- data/lib/generators/paperclip/templates/paperclip_migration.rb.erb +1 -1
- data/lib/paperclip/attachment.rb +132 -38
- data/lib/paperclip/attachment_registry.rb +1 -1
- data/lib/paperclip/callbacks.rb +11 -1
- data/lib/paperclip/content_type_detector.rb +25 -22
- data/lib/paperclip/deprecations.rb +42 -0
- data/lib/paperclip/errors.rb +5 -0
- data/lib/paperclip/file_command_content_type_detector.rb +6 -8
- data/lib/paperclip/geometry_detector_factory.rb +3 -1
- data/lib/paperclip/geometry_parser_factory.rb +1 -1
- data/lib/paperclip/has_attached_file.rb +10 -0
- data/lib/paperclip/interpolations/plural_cache.rb +6 -5
- data/lib/paperclip/interpolations.rb +25 -12
- data/lib/paperclip/io_adapters/abstract_adapter.rb +3 -1
- data/lib/paperclip/io_adapters/attachment_adapter.rb +4 -4
- data/lib/paperclip/io_adapters/data_uri_adapter.rb +5 -10
- data/lib/paperclip/io_adapters/stringio_adapter.rb +6 -10
- data/lib/paperclip/io_adapters/uri_adapter.rb +30 -11
- data/lib/paperclip/locales/de.yml +18 -0
- data/lib/paperclip/locales/en.yml +1 -0
- data/lib/paperclip/locales/es.yml +18 -0
- data/lib/paperclip/locales/ja.yml +18 -0
- data/lib/paperclip/locales/pt-BR.yml +18 -0
- data/lib/paperclip/locales/zh-CN.yml +18 -0
- data/lib/paperclip/locales/zh-HK.yml +18 -0
- data/lib/paperclip/locales/zh-TW.yml +18 -0
- data/lib/paperclip/matchers/have_attached_file_matcher.rb +2 -1
- data/lib/paperclip/matchers/validate_attachment_presence_matcher.rb +2 -1
- data/lib/paperclip/matchers/validate_attachment_size_matcher.rb +2 -1
- data/lib/paperclip/media_type_spoof_detector.rb +89 -0
- data/lib/paperclip/processor.rb +0 -37
- data/lib/paperclip/processor_helpers.rb +50 -0
- data/lib/paperclip/rails_environment.rb +25 -0
- data/lib/paperclip/schema.rb +10 -2
- data/lib/paperclip/storage/filesystem.rb +1 -1
- data/lib/paperclip/storage/fog.rb +18 -7
- data/lib/paperclip/storage/s3.rb +53 -22
- data/lib/paperclip/style.rb +8 -2
- data/lib/paperclip/tempfile_factory.rb +5 -1
- data/lib/paperclip/thumbnail.rb +12 -10
- data/lib/paperclip/url_generator.rb +11 -3
- data/lib/paperclip/validators/attachment_content_type_validator.rb +4 -0
- data/lib/paperclip/validators/attachment_file_name_validator.rb +80 -0
- data/lib/paperclip/validators/attachment_file_type_ignorance_validator.rb +29 -0
- data/lib/paperclip/validators/attachment_presence_validator.rb +4 -0
- data/lib/paperclip/validators/attachment_size_validator.rb +11 -3
- data/lib/paperclip/validators/media_type_spoof_detection_validator.rb +27 -0
- data/lib/paperclip/validators.rb +10 -3
- data/lib/paperclip/version.rb +1 -1
- data/lib/paperclip.rb +26 -8
- data/lib/tasks/paperclip.rake +17 -2
- data/paperclip.gemspec +16 -14
- data/shoulda_macros/paperclip.rb +0 -1
- data/spec/paperclip/attachment_definitions_spec.rb +13 -0
- data/{test/attachment_processing_test.rb → spec/paperclip/attachment_processing_spec.rb} +20 -21
- data/spec/paperclip/attachment_registry_spec.rb +130 -0
- data/{test/attachment_test.rb → spec/paperclip/attachment_spec.rb} +438 -397
- data/{test/content_type_detector_test.rb → spec/paperclip/content_type_detector_spec.rb} +16 -19
- data/spec/paperclip/deprecations_spec.rb +65 -0
- data/{test/file_command_content_type_detector_test.rb → spec/paperclip/file_command_content_type_detector_spec.rb} +5 -6
- data/spec/paperclip/filename_cleaner_spec.rb +14 -0
- data/spec/paperclip/geometry_detector_spec.rb +39 -0
- data/{test/geometry_parser_test.rb → spec/paperclip/geometry_parser_spec.rb} +27 -27
- data/{test/geometry_test.rb → spec/paperclip/geometry_spec.rb} +50 -52
- data/spec/paperclip/glue_spec.rb +44 -0
- data/{test/has_attached_file_test.rb → spec/paperclip/has_attached_file_spec.rb} +45 -28
- data/{test/integration_test.rb → spec/paperclip/integration_spec.rb} +134 -126
- data/{test/interpolations_test.rb → spec/paperclip/interpolations_spec.rb} +70 -46
- data/spec/paperclip/io_adapters/abstract_adapter_spec.rb +78 -0
- data/{test/io_adapters/attachment_adapter_test.rb → spec/paperclip/io_adapters/attachment_adapter_spec.rb} +27 -29
- data/{test/io_adapters/data_uri_adapter_test.rb → spec/paperclip/io_adapters/data_uri_adapter_spec.rb} +26 -17
- data/spec/paperclip/io_adapters/empty_string_adapter_spec.rb +17 -0
- data/{test/io_adapters/file_adapter_test.rb → spec/paperclip/io_adapters/file_adapter_spec.rb} +36 -40
- data/{test/io_adapters/http_url_proxy_adapter_test.rb → spec/paperclip/io_adapters/http_url_proxy_adapter_spec.rb} +31 -29
- data/spec/paperclip/io_adapters/identity_adapter_spec.rb +8 -0
- data/{test/io_adapters/nil_adapter_test.rb → spec/paperclip/io_adapters/nil_adapter_spec.rb} +7 -7
- data/{test/io_adapters/registry_test.rb → spec/paperclip/io_adapters/registry_spec.rb} +10 -7
- data/{test/io_adapters/stringio_adapter_test.rb → spec/paperclip/io_adapters/stringio_adapter_spec.rb} +20 -17
- data/{test/io_adapters/uploaded_file_adapter_test.rb → spec/paperclip/io_adapters/uploaded_file_adapter_spec.rb} +41 -41
- data/{test/io_adapters/uri_adapter_test.rb → spec/paperclip/io_adapters/uri_adapter_spec.rb} +53 -28
- data/spec/paperclip/matchers/have_attached_file_matcher_spec.rb +19 -0
- data/spec/paperclip/matchers/validate_attachment_content_type_matcher_spec.rb +99 -0
- data/spec/paperclip/matchers/validate_attachment_presence_matcher_spec.rb +69 -0
- data/spec/paperclip/matchers/validate_attachment_size_matcher_spec.rb +88 -0
- data/spec/paperclip/media_type_spoof_detector_spec.rb +79 -0
- data/spec/paperclip/meta_class_spec.rb +30 -0
- data/spec/paperclip/paperclip_missing_attachment_styles_spec.rb +84 -0
- data/{test/paperclip_test.rb → spec/paperclip/paperclip_spec.rb} +53 -48
- data/spec/paperclip/plural_cache_spec.rb +37 -0
- data/spec/paperclip/processor_helpers_spec.rb +57 -0
- data/{test/processor_test.rb → spec/paperclip/processor_spec.rb} +5 -5
- data/spec/paperclip/rails_environment_spec.rb +33 -0
- data/{test/rake_test.rb → spec/paperclip/rake_spec.rb} +15 -15
- data/spec/paperclip/schema_spec.rb +248 -0
- data/{test/storage/filesystem_test.rb → spec/paperclip/storage/filesystem_spec.rb} +18 -18
- data/spec/paperclip/storage/fog_spec.rb +535 -0
- data/spec/paperclip/storage/s3_live_spec.rb +182 -0
- data/spec/paperclip/storage/s3_spec.rb +1526 -0
- data/spec/paperclip/style_spec.rb +255 -0
- data/spec/paperclip/tempfile_factory_spec.rb +33 -0
- data/{test/thumbnail_test.rb → spec/paperclip/thumbnail_spec.rb} +123 -107
- data/spec/paperclip/url_generator_spec.rb +211 -0
- data/spec/paperclip/validators/attachment_content_type_validator_spec.rb +322 -0
- data/spec/paperclip/validators/attachment_file_name_validator_spec.rb +160 -0
- data/{test/validators/attachment_presence_validator_test.rb → spec/paperclip/validators/attachment_presence_validator_spec.rb} +20 -20
- data/{test/validators/attachment_size_validator_test.rb → spec/paperclip/validators/attachment_size_validator_spec.rb} +65 -58
- data/spec/paperclip/validators/media_type_spoof_detection_validator_spec.rb +52 -0
- data/spec/paperclip/validators_spec.rb +164 -0
- data/spec/spec_helper.rb +43 -0
- data/spec/support/assertions.rb +71 -0
- data/spec/support/deprecations.rb +9 -0
- data/spec/support/fake_model.rb +25 -0
- data/spec/support/fake_rails.rb +12 -0
- data/spec/support/fixtures/empty.html +1 -0
- data/spec/support/fixtures/empty.xlsx +0 -0
- data/spec/support/fixtures/spaced file.jpg +0 -0
- data/spec/support/matchers/accept.rb +5 -0
- data/spec/support/matchers/exist.rb +5 -0
- data/spec/support/matchers/have_column.rb +23 -0
- data/spec/support/model_reconstruction.rb +60 -0
- data/spec/support/rails_helpers.rb +7 -0
- data/spec/support/test_data.rb +13 -0
- data/spec/support/version_helper.rb +9 -0
- metadata +334 -219
- data/RUNNING_TESTS.md +0 -4
- data/gemfiles/3.0.gemfile +0 -11
- data/gemfiles/3.1.gemfile +0 -11
- data/gemfiles/4.0.gemfile +0 -11
- data/test/attachment_definitions_test.rb +0 -12
- data/test/attachment_registry_test.rb +0 -88
- data/test/filename_cleaner_test.rb +0 -14
- data/test/generator_test.rb +0 -84
- data/test/geometry_detector_test.rb +0 -24
- data/test/helper.rb +0 -232
- data/test/io_adapters/abstract_adapter_test.rb +0 -58
- data/test/io_adapters/empty_string_adapter_test.rb +0 -18
- data/test/io_adapters/identity_adapter_test.rb +0 -8
- data/test/matchers/have_attached_file_matcher_test.rb +0 -24
- data/test/matchers/validate_attachment_content_type_matcher_test.rb +0 -110
- data/test/matchers/validate_attachment_presence_matcher_test.rb +0 -69
- data/test/matchers/validate_attachment_size_matcher_test.rb +0 -86
- data/test/meta_class_test.rb +0 -32
- data/test/paperclip_missing_attachment_styles_test.rb +0 -90
- data/test/plural_cache_test.rb +0 -36
- data/test/schema_test.rb +0 -200
- data/test/storage/fog_test.rb +0 -473
- data/test/storage/s3_live_test.rb +0 -179
- data/test/storage/s3_test.rb +0 -1356
- data/test/style_test.rb +0 -213
- data/test/support/mock_model.rb +0 -2
- data/test/tempfile_factory_test.rb +0 -17
- data/test/url_generator_test.rb +0 -187
- data/test/validators/attachment_content_type_validator_test.rb +0 -324
- data/test/validators_test.rb +0 -61
- /data/{test → spec}/database.yml +0 -0
- /data/{test → spec/support}/fixtures/12k.png +0 -0
- /data/{test → spec/support}/fixtures/50x50.png +0 -0
- /data/{test → spec/support}/fixtures/5k.png +0 -0
- /data/{test → spec/support}/fixtures/animated +0 -0
- /data/{test → spec/support}/fixtures/animated.gif +0 -0
- /data/{test → spec/support}/fixtures/animated.unknown +0 -0
- /data/{test → spec/support}/fixtures/bad.png +0 -0
- /data/{test → spec/support}/fixtures/fog.yml +0 -0
- /data/{test → spec/support}/fixtures/rotated.jpg +0 -0
- /data/{test → spec/support}/fixtures/s3.yml +0 -0
- /data/{test → spec/support}/fixtures/spaced file.png +0 -0
- /data/{test → spec/support}/fixtures/text.txt +0 -0
- /data/{test → spec/support}/fixtures/twopage.pdf +0 -0
- /data/{test → spec/support}/fixtures/uppercase.PNG +0 -0
- /data/{test → spec}/support/mock_attachment.rb +0 -0
- /data/{test → spec}/support/mock_interpolator.rb +0 -0
- /data/{test → spec}/support/mock_url_generator_builder.rb +0 -0
@@ -0,0 +1,1526 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'aws-sdk'
|
3
|
+
|
4
|
+
describe Paperclip::Storage::S3 do
|
5
|
+
before do
|
6
|
+
AWS.stub!
|
7
|
+
end
|
8
|
+
|
9
|
+
context "Parsing S3 credentials" do
|
10
|
+
before do
|
11
|
+
@proxy_settings = {host: "127.0.0.1", port: 8888, user: "foo", password: "bar"}
|
12
|
+
rebuild_model storage: :s3,
|
13
|
+
bucket: "testing",
|
14
|
+
http_proxy: @proxy_settings,
|
15
|
+
s3_credentials: {not: :important}
|
16
|
+
|
17
|
+
@dummy = Dummy.new
|
18
|
+
@avatar = @dummy.avatar
|
19
|
+
end
|
20
|
+
|
21
|
+
it "gets the correct credentials when RAILS_ENV is production" do
|
22
|
+
rails_env("production") do
|
23
|
+
assert_equal({key: "12345"},
|
24
|
+
@avatar.parse_credentials('production' => {key: '12345'},
|
25
|
+
development: {key: "54321"}))
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
it "gets the correct credentials when RAILS_ENV is development" do
|
30
|
+
rails_env("development") do
|
31
|
+
assert_equal({key: "54321"},
|
32
|
+
@avatar.parse_credentials('production' => {key: '12345'},
|
33
|
+
development: {key: "54321"}))
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
it "returns the argument if the key does not exist" do
|
38
|
+
rails_env("not really an env") do
|
39
|
+
assert_equal({test: "12345"}, @avatar.parse_credentials(test: "12345"))
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
it "supports HTTP proxy settings" do
|
44
|
+
rails_env("development") do
|
45
|
+
assert_equal(true, @avatar.using_http_proxy?)
|
46
|
+
assert_equal(@proxy_settings[:host], @avatar.http_proxy_host)
|
47
|
+
assert_equal(@proxy_settings[:port], @avatar.http_proxy_port)
|
48
|
+
assert_equal(@proxy_settings[:user], @avatar.http_proxy_user)
|
49
|
+
assert_equal(@proxy_settings[:password], @avatar.http_proxy_password)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
context ":bucket option via :s3_credentials" do
|
56
|
+
|
57
|
+
before do
|
58
|
+
rebuild_model storage: :s3, s3_credentials: {bucket: 'testing'}
|
59
|
+
@dummy = Dummy.new
|
60
|
+
end
|
61
|
+
|
62
|
+
it "populates #bucket_name" do
|
63
|
+
assert_equal @dummy.avatar.bucket_name, 'testing'
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
context ":bucket option" do
|
69
|
+
|
70
|
+
before do
|
71
|
+
rebuild_model storage: :s3, bucket: "testing", s3_credentials: {}
|
72
|
+
@dummy = Dummy.new
|
73
|
+
end
|
74
|
+
|
75
|
+
it "populates #bucket_name" do
|
76
|
+
assert_equal @dummy.avatar.bucket_name, 'testing'
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
|
81
|
+
context "missing :bucket option" do
|
82
|
+
|
83
|
+
before do
|
84
|
+
rebuild_model storage: :s3,
|
85
|
+
http_proxy: @proxy_settings,
|
86
|
+
s3_credentials: {not: :important}
|
87
|
+
|
88
|
+
@dummy = Dummy.new
|
89
|
+
@dummy.avatar = stringy_file
|
90
|
+
|
91
|
+
end
|
92
|
+
|
93
|
+
it "raises an argument error" do
|
94
|
+
expect { @dummy.save }.to raise_error(ArgumentError, /missing required :bucket option/)
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
98
|
+
|
99
|
+
context "" do
|
100
|
+
before do
|
101
|
+
rebuild_model storage: :s3,
|
102
|
+
s3_credentials: {},
|
103
|
+
bucket: "bucket",
|
104
|
+
path: ":attachment/:basename:dotextension",
|
105
|
+
url: ":s3_path_url"
|
106
|
+
@dummy = Dummy.new
|
107
|
+
@dummy.avatar = stringy_file
|
108
|
+
@dummy.stubs(:new_record?).returns(false)
|
109
|
+
end
|
110
|
+
|
111
|
+
it "returns a url based on an S3 path" do
|
112
|
+
assert_match %r{^http://s3.amazonaws.com/bucket/avatars/data[^\.]}, @dummy.avatar.url
|
113
|
+
end
|
114
|
+
|
115
|
+
it "uses the correct bucket" do
|
116
|
+
assert_equal "bucket", @dummy.avatar.s3_bucket.name
|
117
|
+
end
|
118
|
+
|
119
|
+
it "uses the correct key" do
|
120
|
+
assert_equal "avatars/data", @dummy.avatar.s3_object.key
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
context "s3_protocol" do
|
125
|
+
["http", :http, ""].each do |protocol|
|
126
|
+
context "as #{protocol.inspect}" do
|
127
|
+
before do
|
128
|
+
rebuild_model storage: :s3, s3_protocol: protocol
|
129
|
+
|
130
|
+
@dummy = Dummy.new
|
131
|
+
end
|
132
|
+
|
133
|
+
it "returns the s3_protocol in string" do
|
134
|
+
assert_equal protocol.to_s, @dummy.avatar.s3_protocol
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
context "s3_protocol: 'https'" do
|
141
|
+
before do
|
142
|
+
rebuild_model storage: :s3,
|
143
|
+
s3_credentials: {},
|
144
|
+
s3_protocol: 'https',
|
145
|
+
bucket: "bucket",
|
146
|
+
path: ":attachment/:basename:dotextension"
|
147
|
+
@dummy = Dummy.new
|
148
|
+
@dummy.avatar = stringy_file
|
149
|
+
@dummy.stubs(:new_record?).returns(false)
|
150
|
+
end
|
151
|
+
|
152
|
+
it "returns a url based on an S3 path" do
|
153
|
+
assert_match %r{^https://s3.amazonaws.com/bucket/avatars/data[^\.]}, @dummy.avatar.url
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
context "s3_protocol: ''" do
|
158
|
+
before do
|
159
|
+
rebuild_model storage: :s3,
|
160
|
+
s3_credentials: {},
|
161
|
+
s3_protocol: '',
|
162
|
+
bucket: "bucket",
|
163
|
+
path: ":attachment/:basename:dotextension"
|
164
|
+
@dummy = Dummy.new
|
165
|
+
@dummy.avatar = stringy_file
|
166
|
+
@dummy.stubs(:new_record?).returns(false)
|
167
|
+
end
|
168
|
+
|
169
|
+
it "returns a protocol-relative URL" do
|
170
|
+
assert_match %r{^//s3.amazonaws.com/bucket/avatars/data[^\.]}, @dummy.avatar.url
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
context "s3_protocol: :https" do
|
175
|
+
before do
|
176
|
+
rebuild_model storage: :s3,
|
177
|
+
s3_credentials: {},
|
178
|
+
s3_protocol: :https,
|
179
|
+
bucket: "bucket",
|
180
|
+
path: ":attachment/:basename:dotextension"
|
181
|
+
@dummy = Dummy.new
|
182
|
+
@dummy.avatar = stringy_file
|
183
|
+
@dummy.stubs(:new_record?).returns(false)
|
184
|
+
end
|
185
|
+
|
186
|
+
it "returns a url based on an S3 path" do
|
187
|
+
assert_match %r{^https://s3.amazonaws.com/bucket/avatars/data[^\.]}, @dummy.avatar.url
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
context "s3_protocol: ''" do
|
192
|
+
before do
|
193
|
+
rebuild_model storage: :s3,
|
194
|
+
s3_credentials: {},
|
195
|
+
s3_protocol: '',
|
196
|
+
bucket: "bucket",
|
197
|
+
path: ":attachment/:basename:dotextension"
|
198
|
+
@dummy = Dummy.new
|
199
|
+
@dummy.avatar = stringy_file
|
200
|
+
@dummy.stubs(:new_record?).returns(false)
|
201
|
+
end
|
202
|
+
|
203
|
+
it "returns a url based on an S3 path" do
|
204
|
+
assert_match %r{^//s3.amazonaws.com/bucket/avatars/data[^\.]}, @dummy.avatar.url
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
context "An attachment that uses S3 for storage and has the style in the path" do
|
209
|
+
before do
|
210
|
+
rebuild_model storage: :s3,
|
211
|
+
bucket: "testing",
|
212
|
+
path: ":attachment/:style/:basename:dotextension",
|
213
|
+
styles: {
|
214
|
+
thumb: "80x80>"
|
215
|
+
},
|
216
|
+
s3_credentials: {
|
217
|
+
'access_key_id' => "12345",
|
218
|
+
'secret_access_key' => "54321"
|
219
|
+
}
|
220
|
+
|
221
|
+
@dummy = Dummy.new
|
222
|
+
@dummy.avatar = stringy_file
|
223
|
+
@avatar = @dummy.avatar
|
224
|
+
end
|
225
|
+
|
226
|
+
it "uses an S3 object based on the correct path for the default style" do
|
227
|
+
assert_equal("avatars/original/data", @dummy.avatar.s3_object.key)
|
228
|
+
end
|
229
|
+
|
230
|
+
it "uses an S3 object based on the correct path for the custom style" do
|
231
|
+
assert_equal("avatars/thumb/data", @dummy.avatar.s3_object(:thumb).key)
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
context "s3_host_name" do
|
236
|
+
before do
|
237
|
+
rebuild_model storage: :s3,
|
238
|
+
s3_credentials: {},
|
239
|
+
bucket: "bucket",
|
240
|
+
path: ":attachment/:basename:dotextension",
|
241
|
+
s3_host_name: "s3-ap-northeast-1.amazonaws.com"
|
242
|
+
@dummy = Dummy.new
|
243
|
+
@dummy.avatar = stringy_file
|
244
|
+
@dummy.stubs(:new_record?).returns(false)
|
245
|
+
end
|
246
|
+
|
247
|
+
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
|
249
|
+
end
|
250
|
+
|
251
|
+
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
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
context "dynamic s3_host_name" do
|
257
|
+
before do
|
258
|
+
rebuild_model storage: :s3,
|
259
|
+
s3_credentials: {},
|
260
|
+
bucket: "bucket",
|
261
|
+
path: ":attachment/:basename:dotextension",
|
262
|
+
s3_host_name: lambda {|a| a.instance.value }
|
263
|
+
@dummy = Dummy.new
|
264
|
+
class << @dummy
|
265
|
+
attr_accessor :value
|
266
|
+
end
|
267
|
+
@dummy.avatar = stringy_file
|
268
|
+
@dummy.stubs(:new_record?).returns(false)
|
269
|
+
end
|
270
|
+
|
271
|
+
it "uses s3_host_name as a proc if available" do
|
272
|
+
@dummy.value = "s3.something.com"
|
273
|
+
assert_equal "http://s3.something.com/bucket/avatars/data", @dummy.avatar.url(:original, timestamp: false)
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
277
|
+
context "An attachment that uses S3 for storage and has styles that return different file types" do
|
278
|
+
before do
|
279
|
+
rebuild_model styles: { large: ['500x500#', :jpg] },
|
280
|
+
storage: :s3,
|
281
|
+
bucket: "bucket",
|
282
|
+
path: ":attachment/:basename:dotextension",
|
283
|
+
s3_credentials: {
|
284
|
+
'access_key_id' => "12345",
|
285
|
+
'secret_access_key' => "54321"
|
286
|
+
}
|
287
|
+
|
288
|
+
File.open(fixture_file('5k.png'), 'rb') do |file|
|
289
|
+
@dummy = Dummy.new
|
290
|
+
@dummy.avatar = file
|
291
|
+
@dummy.stubs(:new_record?).returns(false)
|
292
|
+
end
|
293
|
+
end
|
294
|
+
|
295
|
+
it "returns a url containing the correct original file mime type" do
|
296
|
+
assert_match /.+\/5k.png/, @dummy.avatar.url
|
297
|
+
end
|
298
|
+
|
299
|
+
it 'uses the correct key for the original file mime type' do
|
300
|
+
assert_match /.+\/5k.png/, @dummy.avatar.s3_object.key
|
301
|
+
end
|
302
|
+
|
303
|
+
it "returns a url containing the correct processed file mime type" do
|
304
|
+
assert_match /.+\/5k.jpg/, @dummy.avatar.url(:large)
|
305
|
+
end
|
306
|
+
|
307
|
+
it "uses the correct key for the processed file mime type" do
|
308
|
+
assert_match /.+\/5k.jpg/, @dummy.avatar.s3_object(:large).key
|
309
|
+
end
|
310
|
+
end
|
311
|
+
|
312
|
+
context "An attachment that uses S3 for storage and has a proc for styles" do
|
313
|
+
before do
|
314
|
+
rebuild_model styles: lambda { |attachment| attachment.instance.counter; {thumbnail: { geometry: "50x50#", s3_headers: {'Cache-Control' => 'max-age=31557600'}} }},
|
315
|
+
storage: :s3,
|
316
|
+
bucket: "bucket",
|
317
|
+
path: ":attachment/:style/:basename:dotextension",
|
318
|
+
s3_credentials: {
|
319
|
+
'access_key_id' => "12345",
|
320
|
+
'secret_access_key' => "54321"
|
321
|
+
}
|
322
|
+
|
323
|
+
@file = File.new(fixture_file('5k.png'), 'rb')
|
324
|
+
|
325
|
+
Dummy.class_eval do
|
326
|
+
def counter
|
327
|
+
@counter ||= 0
|
328
|
+
@counter += 1
|
329
|
+
@counter
|
330
|
+
end
|
331
|
+
end
|
332
|
+
|
333
|
+
@dummy = Dummy.new
|
334
|
+
@dummy.avatar = @file
|
335
|
+
|
336
|
+
object = stub
|
337
|
+
@dummy.avatar.stubs(:s3_object).with(:original).returns(object)
|
338
|
+
@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')
|
341
|
+
@dummy.save
|
342
|
+
end
|
343
|
+
|
344
|
+
after { @file.close }
|
345
|
+
|
346
|
+
it "succeeds" do
|
347
|
+
assert_equal @dummy.counter, 7
|
348
|
+
end
|
349
|
+
end
|
350
|
+
|
351
|
+
context "An attachment that uses S3 for storage and has spaces in file name" do
|
352
|
+
before do
|
353
|
+
rebuild_model(
|
354
|
+
styles: { large: ["500x500#", :jpg] },
|
355
|
+
storage: :s3,
|
356
|
+
bucket: "bucket",
|
357
|
+
s3_credentials: { "access_key_id" => "12345",
|
358
|
+
"secret_access_key" => "54321" }
|
359
|
+
)
|
360
|
+
|
361
|
+
File.open(fixture_file("spaced file.png"), "rb") do |file|
|
362
|
+
@dummy = Dummy.new
|
363
|
+
@dummy.avatar = file
|
364
|
+
@dummy.stubs(:new_record?).returns(false)
|
365
|
+
end
|
366
|
+
end
|
367
|
+
|
368
|
+
it "returns a replaced version for path" do
|
369
|
+
assert_match /.+\/spaced_file\.png/, @dummy.avatar.path
|
370
|
+
end
|
371
|
+
|
372
|
+
it "returns a replaced version for url" do
|
373
|
+
assert_match /.+\/spaced_file\.png/, @dummy.avatar.url
|
374
|
+
end
|
375
|
+
end
|
376
|
+
|
377
|
+
context "An attachment that uses S3 for storage and has a question mark in file name" do
|
378
|
+
before do
|
379
|
+
rebuild_model styles: { large: ['500x500#', :jpg] },
|
380
|
+
storage: :s3,
|
381
|
+
bucket: "bucket",
|
382
|
+
s3_credentials: {
|
383
|
+
'access_key_id' => "12345",
|
384
|
+
'secret_access_key' => "54321"
|
385
|
+
}
|
386
|
+
|
387
|
+
stringio = stringy_file
|
388
|
+
class << stringio
|
389
|
+
def original_filename
|
390
|
+
"question?mark.png"
|
391
|
+
end
|
392
|
+
end
|
393
|
+
file = Paperclip.io_adapters.for(stringio)
|
394
|
+
@dummy = Dummy.new
|
395
|
+
@dummy.avatar = file
|
396
|
+
@dummy.save
|
397
|
+
@dummy.stubs(:new_record?).returns(false)
|
398
|
+
end
|
399
|
+
|
400
|
+
it "returns a replaced version for path" do
|
401
|
+
assert_match /.+\/question_mark\.png/, @dummy.avatar.path
|
402
|
+
end
|
403
|
+
|
404
|
+
it "returns a replaced version for url" do
|
405
|
+
assert_match /.+\/question_mark\.png/, @dummy.avatar.url
|
406
|
+
end
|
407
|
+
end
|
408
|
+
|
409
|
+
context "" do
|
410
|
+
before do
|
411
|
+
rebuild_model storage: :s3,
|
412
|
+
s3_credentials: {},
|
413
|
+
bucket: "bucket",
|
414
|
+
path: ":attachment/:basename:dotextension",
|
415
|
+
url: ":s3_domain_url"
|
416
|
+
@dummy = Dummy.new
|
417
|
+
@dummy.avatar = stringy_file
|
418
|
+
@dummy.stubs(:new_record?).returns(false)
|
419
|
+
end
|
420
|
+
|
421
|
+
it "returns a url based on an S3 subdomain" do
|
422
|
+
assert_match %r{^http://bucket.s3.amazonaws.com/avatars/data[^\.]}, @dummy.avatar.url
|
423
|
+
end
|
424
|
+
end
|
425
|
+
|
426
|
+
context "" do
|
427
|
+
before do
|
428
|
+
rebuild_model(
|
429
|
+
storage: :s3,
|
430
|
+
s3_credentials: {
|
431
|
+
production: { bucket: "prod_bucket" },
|
432
|
+
development: { bucket: "dev_bucket" }
|
433
|
+
},
|
434
|
+
bucket: "bucket",
|
435
|
+
s3_host_alias: "something.something.com",
|
436
|
+
path: ":attachment/:basename:dotextension",
|
437
|
+
url: ":s3_alias_url"
|
438
|
+
)
|
439
|
+
@dummy = Dummy.new
|
440
|
+
@dummy.avatar = stringy_file
|
441
|
+
@dummy.stubs(:new_record?).returns(false)
|
442
|
+
end
|
443
|
+
|
444
|
+
it "returns a url based on the host_alias" do
|
445
|
+
assert_match %r{^http://something.something.com/avatars/data[^\.]}, @dummy.avatar.url
|
446
|
+
end
|
447
|
+
end
|
448
|
+
|
449
|
+
context "generating a url with a proc as the host alias" do
|
450
|
+
before do
|
451
|
+
rebuild_model storage: :s3,
|
452
|
+
s3_credentials: { bucket: "prod_bucket" },
|
453
|
+
s3_host_alias: Proc.new{|atch| "cdn#{atch.instance.counter % 4}.example.com"},
|
454
|
+
path: ":attachment/:basename:dotextension",
|
455
|
+
url: ":s3_alias_url"
|
456
|
+
Dummy.class_eval do
|
457
|
+
def counter
|
458
|
+
@counter ||= 0
|
459
|
+
@counter += 1
|
460
|
+
@counter
|
461
|
+
end
|
462
|
+
end
|
463
|
+
@dummy = Dummy.new
|
464
|
+
@dummy.avatar = stringy_file
|
465
|
+
@dummy.stubs(:new_record?).returns(false)
|
466
|
+
end
|
467
|
+
|
468
|
+
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
|
471
|
+
end
|
472
|
+
|
473
|
+
it "still returns the bucket name" do
|
474
|
+
assert_equal "prod_bucket", @dummy.avatar.bucket_name
|
475
|
+
end
|
476
|
+
|
477
|
+
end
|
478
|
+
|
479
|
+
context "" do
|
480
|
+
before do
|
481
|
+
rebuild_model storage: :s3,
|
482
|
+
s3_credentials: {},
|
483
|
+
bucket: "bucket",
|
484
|
+
path: ":attachment/:basename:dotextension",
|
485
|
+
url: ":asset_host"
|
486
|
+
@dummy = Dummy.new
|
487
|
+
@dummy.avatar = stringy_file
|
488
|
+
@dummy.stubs(:new_record?).returns(false)
|
489
|
+
end
|
490
|
+
|
491
|
+
it "returns a relative URL for Rails to calculate assets host" do
|
492
|
+
assert_match %r{^avatars/data[^\.]}, @dummy.avatar.url
|
493
|
+
end
|
494
|
+
|
495
|
+
end
|
496
|
+
|
497
|
+
context "Generating a secure url with an expiration" do
|
498
|
+
before do
|
499
|
+
@build_model_with_options = lambda {|options|
|
500
|
+
base_options = {
|
501
|
+
storage: :s3,
|
502
|
+
s3_credentials: {
|
503
|
+
production: { bucket: "prod_bucket" },
|
504
|
+
development: { bucket: "dev_bucket" }
|
505
|
+
},
|
506
|
+
s3_host_alias: "something.something.com",
|
507
|
+
s3_permissions: "private",
|
508
|
+
path: ":attachment/:basename:dotextension",
|
509
|
+
url: ":s3_alias_url"
|
510
|
+
}
|
511
|
+
|
512
|
+
rebuild_model base_options.merge(options)
|
513
|
+
}
|
514
|
+
end
|
515
|
+
|
516
|
+
it "uses default options" do
|
517
|
+
@build_model_with_options[{}]
|
518
|
+
|
519
|
+
rails_env("production") do
|
520
|
+
@dummy = Dummy.new
|
521
|
+
@dummy.avatar = stringy_file
|
522
|
+
|
523
|
+
object = stub
|
524
|
+
@dummy.avatar.stubs(:s3_object).returns(object)
|
525
|
+
object.expects(:url_for).with(:read, expires: 3600, secure: true)
|
526
|
+
|
527
|
+
@dummy.avatar.expiring_url
|
528
|
+
end
|
529
|
+
end
|
530
|
+
|
531
|
+
it "allows overriding s3_url_options" do
|
532
|
+
@build_model_with_options[s3_url_options: { response_content_disposition: "inline" }]
|
533
|
+
|
534
|
+
rails_env("production") do
|
535
|
+
@dummy = Dummy.new
|
536
|
+
@dummy.avatar = stringy_file
|
537
|
+
|
538
|
+
object = stub
|
539
|
+
@dummy.avatar.stubs(:s3_object).returns(object)
|
540
|
+
object.expects(:url_for).with(:read, expires: 3600, secure: true, response_content_disposition: "inline")
|
541
|
+
|
542
|
+
@dummy.avatar.expiring_url
|
543
|
+
end
|
544
|
+
end
|
545
|
+
|
546
|
+
it "allows overriding s3_object options with a proc" do
|
547
|
+
@build_model_with_options[s3_url_options: lambda {|attachment| { response_content_type: attachment.avatar_content_type } }]
|
548
|
+
|
549
|
+
rails_env("production") do
|
550
|
+
@dummy = Dummy.new
|
551
|
+
|
552
|
+
@file = stringy_file
|
553
|
+
@file.stubs(:original_filename).returns("5k.png\n\n")
|
554
|
+
Paperclip.stubs(:run).returns('image/png')
|
555
|
+
@file.stubs(:content_type).returns("image/png\n\n")
|
556
|
+
@file.stubs(:to_tempfile).returns(@file)
|
557
|
+
|
558
|
+
@dummy.avatar = @file
|
559
|
+
|
560
|
+
object = stub
|
561
|
+
@dummy.avatar.stubs(:s3_object).returns(object)
|
562
|
+
object.expects(:url_for).with(:read, expires: 3600, secure: true, response_content_type: "image/png")
|
563
|
+
|
564
|
+
@dummy.avatar.expiring_url
|
565
|
+
end
|
566
|
+
end
|
567
|
+
end
|
568
|
+
|
569
|
+
context "#expiring_url" do
|
570
|
+
before { @dummy = Dummy.new }
|
571
|
+
|
572
|
+
context "with no attachment" do
|
573
|
+
before { assert(!@dummy.avatar.exists?) }
|
574
|
+
|
575
|
+
it "returns the default URL" do
|
576
|
+
assert_equal(@dummy.avatar.url, @dummy.avatar.expiring_url)
|
577
|
+
end
|
578
|
+
|
579
|
+
it 'generates a url for a style when a file does not exist' do
|
580
|
+
assert_equal(@dummy.avatar.url(:thumb), @dummy.avatar.expiring_url(3600, :thumb))
|
581
|
+
end
|
582
|
+
end
|
583
|
+
|
584
|
+
it "generates the same url when using Times and Integer offsets" do
|
585
|
+
assert_equal @dummy.avatar.expiring_url(1234), @dummy.avatar.expiring_url(Time.now + 1234)
|
586
|
+
end
|
587
|
+
end
|
588
|
+
|
589
|
+
context "Generating a url with an expiration for each style" do
|
590
|
+
before do
|
591
|
+
rebuild_model storage: :s3,
|
592
|
+
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"
|
600
|
+
|
601
|
+
rails_env("production") do
|
602
|
+
@dummy = Dummy.new
|
603
|
+
@dummy.avatar = stringy_file
|
604
|
+
end
|
605
|
+
end
|
606
|
+
|
607
|
+
it "generates a url for the thumb" do
|
608
|
+
object = stub
|
609
|
+
@dummy.avatar.stubs(:s3_object).with(:thumb).returns(object)
|
610
|
+
object.expects(:url_for).with(:read, expires: 1800, secure: true)
|
611
|
+
@dummy.avatar.expiring_url(1800, :thumb)
|
612
|
+
end
|
613
|
+
|
614
|
+
it "generates a url for the default style" do
|
615
|
+
object = stub
|
616
|
+
@dummy.avatar.stubs(:s3_object).with(:original).returns(object)
|
617
|
+
object.expects(:url_for).with(:read, expires: 1800, secure: true)
|
618
|
+
@dummy.avatar.expiring_url(1800)
|
619
|
+
end
|
620
|
+
end
|
621
|
+
|
622
|
+
context "Parsing S3 credentials with a bucket in them" do
|
623
|
+
before do
|
624
|
+
rebuild_model storage: :s3,
|
625
|
+
s3_credentials: {
|
626
|
+
production: { bucket: "prod_bucket" },
|
627
|
+
development: { bucket: "dev_bucket" }
|
628
|
+
}
|
629
|
+
@dummy = Dummy.new
|
630
|
+
end
|
631
|
+
|
632
|
+
it "gets the right bucket in production" do
|
633
|
+
rails_env("production") do
|
634
|
+
assert_equal "prod_bucket", @dummy.avatar.bucket_name
|
635
|
+
assert_equal "prod_bucket", @dummy.avatar.s3_bucket.name
|
636
|
+
end
|
637
|
+
end
|
638
|
+
|
639
|
+
it "gets the right bucket in development" do
|
640
|
+
rails_env("development") do
|
641
|
+
assert_equal "dev_bucket", @dummy.avatar.bucket_name
|
642
|
+
assert_equal "dev_bucket", @dummy.avatar.s3_bucket.name
|
643
|
+
end
|
644
|
+
end
|
645
|
+
end
|
646
|
+
|
647
|
+
context "Parsing S3 credentials with a s3_host_name in them" do
|
648
|
+
before do
|
649
|
+
rebuild_model storage: :s3,
|
650
|
+
bucket: 'testing',
|
651
|
+
s3_credentials: {
|
652
|
+
production: { s3_host_name: "s3-world-end.amazonaws.com" },
|
653
|
+
development: { s3_host_name: "s3-ap-northeast-1.amazonaws.com" }
|
654
|
+
}
|
655
|
+
@dummy = Dummy.new
|
656
|
+
end
|
657
|
+
|
658
|
+
it "gets the right s3_host_name in production" do
|
659
|
+
rails_env("production") do
|
660
|
+
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
|
662
|
+
end
|
663
|
+
end
|
664
|
+
|
665
|
+
it "gets the right s3_host_name in development" do
|
666
|
+
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
|
669
|
+
end
|
670
|
+
end
|
671
|
+
|
672
|
+
it "gets the right s3_host_name if the key does not exist" do
|
673
|
+
rails_env("test") do
|
674
|
+
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
|
676
|
+
end
|
677
|
+
end
|
678
|
+
end
|
679
|
+
|
680
|
+
context "An attachment with S3 storage" do
|
681
|
+
before do
|
682
|
+
rebuild_model storage: :s3,
|
683
|
+
bucket: "testing",
|
684
|
+
path: ":attachment/:style/:basename:dotextension",
|
685
|
+
s3_credentials: {
|
686
|
+
aws_access_key_id: "12345",
|
687
|
+
aws_secret_access_key: "54321"
|
688
|
+
}
|
689
|
+
end
|
690
|
+
|
691
|
+
it "is extended by the S3 module" do
|
692
|
+
assert Dummy.new.avatar.is_a?(Paperclip::Storage::S3)
|
693
|
+
end
|
694
|
+
|
695
|
+
it "won't be extended by the Filesystem module" do
|
696
|
+
assert ! Dummy.new.avatar.is_a?(Paperclip::Storage::Filesystem)
|
697
|
+
end
|
698
|
+
|
699
|
+
context "when assigned" do
|
700
|
+
before do
|
701
|
+
@file = File.new(fixture_file('5k.png'), 'rb')
|
702
|
+
@dummy = Dummy.new
|
703
|
+
@dummy.avatar = @file
|
704
|
+
@dummy.stubs(:new_record?).returns(false)
|
705
|
+
end
|
706
|
+
|
707
|
+
after { @file.close }
|
708
|
+
|
709
|
+
it "does not get a bucket to get a URL" do
|
710
|
+
@dummy.avatar.expects(:s3).never
|
711
|
+
@dummy.avatar.expects(:s3_bucket).never
|
712
|
+
assert_match %r{^http://s3\.amazonaws\.com/testing/avatars/original/5k\.png}, @dummy.avatar.url
|
713
|
+
end
|
714
|
+
|
715
|
+
it "is rewound after flush_writes" do
|
716
|
+
@dummy.avatar.instance_eval "def after_flush_writes; end"
|
717
|
+
@dummy.avatar.stubs(:s3_object).returns(stub(write: true))
|
718
|
+
|
719
|
+
files = @dummy.avatar.queued_for_write.values.each(&:read)
|
720
|
+
@dummy.save
|
721
|
+
assert files.none?(&:eof?), "Expect all the files to be rewound."
|
722
|
+
end
|
723
|
+
|
724
|
+
it "is removed after after_flush_writes" do
|
725
|
+
@dummy.avatar.stubs(:s3_object).returns(stub(write: true))
|
726
|
+
paths = @dummy.avatar.queued_for_write.values.map(&:path)
|
727
|
+
@dummy.save
|
728
|
+
assert paths.none?{ |path| File.exist?(path) },
|
729
|
+
"Expect all the files to be deleted."
|
730
|
+
end
|
731
|
+
|
732
|
+
it "will retry to save again but back off on SlowDown" do
|
733
|
+
@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)
|
738
|
+
expect(@dummy.avatar).to have_received(:sleep).with(1)
|
739
|
+
expect(@dummy.avatar).to have_received(:sleep).with(2)
|
740
|
+
expect(@dummy.avatar).to have_received(:sleep).with(4)
|
741
|
+
expect(@dummy.avatar).to have_received(:sleep).with(8)
|
742
|
+
expect(@dummy.avatar).to have_received(:sleep).with(16)
|
743
|
+
end
|
744
|
+
|
745
|
+
context "and saved" do
|
746
|
+
before do
|
747
|
+
object = stub
|
748
|
+
@dummy.avatar.stubs(:s3_object).returns(object)
|
749
|
+
object.expects(:write).with(anything,
|
750
|
+
content_type: "image/png",
|
751
|
+
acl: :public_read)
|
752
|
+
@dummy.save
|
753
|
+
end
|
754
|
+
|
755
|
+
it "succeeds" do
|
756
|
+
assert true
|
757
|
+
end
|
758
|
+
end
|
759
|
+
|
760
|
+
context "and saved without a bucket" do
|
761
|
+
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)
|
768
|
+
@dummy.save
|
769
|
+
end
|
770
|
+
|
771
|
+
it "succeeds" do
|
772
|
+
assert true
|
773
|
+
end
|
774
|
+
end
|
775
|
+
|
776
|
+
context "and remove" do
|
777
|
+
before do
|
778
|
+
AWS::S3::S3Object.any_instance.stubs(:exists?).returns(true)
|
779
|
+
AWS::S3::S3Object.any_instance.stubs(:delete)
|
780
|
+
@dummy.destroy
|
781
|
+
end
|
782
|
+
|
783
|
+
it "succeeds" do
|
784
|
+
assert true
|
785
|
+
end
|
786
|
+
end
|
787
|
+
|
788
|
+
context 'that the file were missing' do
|
789
|
+
before do
|
790
|
+
AWS::S3::S3Object.any_instance.stubs(:exists?).raises(AWS::Errors::Base)
|
791
|
+
end
|
792
|
+
|
793
|
+
it 'returns false on exists?' do
|
794
|
+
assert !@dummy.avatar.exists?
|
795
|
+
end
|
796
|
+
end
|
797
|
+
end
|
798
|
+
end
|
799
|
+
|
800
|
+
context "An attachment with S3 storage and bucket defined as a Proc" do
|
801
|
+
before do
|
802
|
+
rebuild_model storage: :s3,
|
803
|
+
bucket: lambda { |attachment| "bucket_#{attachment.instance.other}" },
|
804
|
+
s3_credentials: {not: :important}
|
805
|
+
end
|
806
|
+
|
807
|
+
it "gets the right bucket name" do
|
808
|
+
assert "bucket_a", Dummy.new(other: 'a').avatar.bucket_name
|
809
|
+
assert "bucket_a", Dummy.new(other: 'a').avatar.s3_bucket.name
|
810
|
+
assert "bucket_b", Dummy.new(other: 'b').avatar.bucket_name
|
811
|
+
assert "bucket_b", Dummy.new(other: 'b').avatar.s3_bucket.name
|
812
|
+
end
|
813
|
+
end
|
814
|
+
|
815
|
+
context "An attachment with S3 storage and S3 credentials defined as a Proc" do
|
816
|
+
before do
|
817
|
+
rebuild_model storage: :s3,
|
818
|
+
bucket: {not: :important},
|
819
|
+
s3_credentials: lambda { |attachment|
|
820
|
+
Hash['access_key_id' => "access#{attachment.instance.other}", 'secret_access_key' => "secret#{attachment.instance.other}"]
|
821
|
+
}
|
822
|
+
end
|
823
|
+
|
824
|
+
it "gets the right credentials" do
|
825
|
+
assert "access1234", Dummy.new(other: '1234').avatar.s3_credentials[:access_key_id]
|
826
|
+
assert "secret1234", Dummy.new(other: '1234').avatar.s3_credentials[:secret_access_key]
|
827
|
+
end
|
828
|
+
end
|
829
|
+
|
830
|
+
context "An attachment with S3 storage and S3 credentials with a :credential_provider" do
|
831
|
+
before do
|
832
|
+
class DummyCredentialProvider; end
|
833
|
+
|
834
|
+
rebuild_model storage: :s3,
|
835
|
+
bucket: "testing",
|
836
|
+
s3_credentials: {
|
837
|
+
credential_provider: DummyCredentialProvider.new
|
838
|
+
}
|
839
|
+
@dummy = Dummy.new
|
840
|
+
end
|
841
|
+
|
842
|
+
it "sets the credential-provider" do
|
843
|
+
expect(@dummy.avatar.s3_bucket.config.credential_provider).to be_a DummyCredentialProvider
|
844
|
+
end
|
845
|
+
end
|
846
|
+
|
847
|
+
context "An attachment with S3 storage and S3 credentials in an unsupported manor" do
|
848
|
+
before do
|
849
|
+
rebuild_model storage: :s3, bucket: "testing", s3_credentials: ["unsupported"]
|
850
|
+
@dummy = Dummy.new
|
851
|
+
end
|
852
|
+
|
853
|
+
it "does not accept the credentials" do
|
854
|
+
assert_raises(ArgumentError) do
|
855
|
+
@dummy.avatar.s3_credentials
|
856
|
+
end
|
857
|
+
end
|
858
|
+
end
|
859
|
+
|
860
|
+
context "An attachment with S3 storage and S3 credentials not supplied" do
|
861
|
+
before do
|
862
|
+
rebuild_model storage: :s3, bucket: "testing"
|
863
|
+
@dummy = Dummy.new
|
864
|
+
end
|
865
|
+
|
866
|
+
it "does not parse any credentials" do
|
867
|
+
assert_equal({}, @dummy.avatar.s3_credentials)
|
868
|
+
end
|
869
|
+
end
|
870
|
+
|
871
|
+
context "An attachment with S3 storage and specific s3 headers set" do
|
872
|
+
before do
|
873
|
+
rebuild_model storage: :s3,
|
874
|
+
bucket: "testing",
|
875
|
+
path: ":attachment/:style/:basename:dotextension",
|
876
|
+
s3_credentials: {
|
877
|
+
'access_key_id' => "12345",
|
878
|
+
'secret_access_key' => "54321"
|
879
|
+
},
|
880
|
+
s3_headers: {'Cache-Control' => 'max-age=31557600'}
|
881
|
+
end
|
882
|
+
|
883
|
+
context "when assigned" do
|
884
|
+
before do
|
885
|
+
@file = File.new(fixture_file('5k.png'), 'rb')
|
886
|
+
@dummy = Dummy.new
|
887
|
+
@dummy.avatar = @file
|
888
|
+
end
|
889
|
+
|
890
|
+
after { @file.close }
|
891
|
+
|
892
|
+
context "and saved" do
|
893
|
+
before do
|
894
|
+
object = stub
|
895
|
+
@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')
|
900
|
+
@dummy.save
|
901
|
+
end
|
902
|
+
|
903
|
+
it "succeeds" do
|
904
|
+
assert true
|
905
|
+
end
|
906
|
+
end
|
907
|
+
end
|
908
|
+
end
|
909
|
+
|
910
|
+
context "An attachment with S3 storage and metadata set using header names" do
|
911
|
+
before do
|
912
|
+
rebuild_model storage: :s3,
|
913
|
+
bucket: "testing",
|
914
|
+
path: ":attachment/:style/:basename:dotextension",
|
915
|
+
s3_credentials: {
|
916
|
+
'access_key_id' => "12345",
|
917
|
+
'secret_access_key' => "54321"
|
918
|
+
},
|
919
|
+
s3_headers: {'x-amz-meta-color' => 'red'}
|
920
|
+
end
|
921
|
+
|
922
|
+
context "when assigned" do
|
923
|
+
before do
|
924
|
+
@file = File.new(fixture_file('5k.png'), 'rb')
|
925
|
+
@dummy = Dummy.new
|
926
|
+
@dummy.avatar = @file
|
927
|
+
end
|
928
|
+
|
929
|
+
after { @file.close }
|
930
|
+
|
931
|
+
context "and saved" do
|
932
|
+
before do
|
933
|
+
object = stub
|
934
|
+
@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" })
|
939
|
+
@dummy.save
|
940
|
+
end
|
941
|
+
|
942
|
+
it "succeeds" do
|
943
|
+
assert true
|
944
|
+
end
|
945
|
+
end
|
946
|
+
end
|
947
|
+
end
|
948
|
+
|
949
|
+
context "An attachment with S3 storage and metadata set using the :s3_metadata option" do
|
950
|
+
before do
|
951
|
+
rebuild_model storage: :s3,
|
952
|
+
bucket: "testing",
|
953
|
+
path: ":attachment/:style/:basename:dotextension",
|
954
|
+
s3_credentials: {
|
955
|
+
'access_key_id' => "12345",
|
956
|
+
'secret_access_key' => "54321"
|
957
|
+
},
|
958
|
+
s3_metadata: { "color" => "red" }
|
959
|
+
end
|
960
|
+
|
961
|
+
context "when assigned" do
|
962
|
+
before do
|
963
|
+
@file = File.new(fixture_file('5k.png'), 'rb')
|
964
|
+
@dummy = Dummy.new
|
965
|
+
@dummy.avatar = @file
|
966
|
+
end
|
967
|
+
|
968
|
+
after { @file.close }
|
969
|
+
|
970
|
+
context "and saved" do
|
971
|
+
before do
|
972
|
+
object = stub
|
973
|
+
@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" })
|
978
|
+
@dummy.save
|
979
|
+
end
|
980
|
+
|
981
|
+
it "succeeds" do
|
982
|
+
assert true
|
983
|
+
end
|
984
|
+
end
|
985
|
+
end
|
986
|
+
end
|
987
|
+
|
988
|
+
context "An attachment with S3 storage and storage class set" do
|
989
|
+
context "using the header name" do
|
990
|
+
before do
|
991
|
+
rebuild_model storage: :s3,
|
992
|
+
bucket: "testing",
|
993
|
+
path: ":attachment/:style/:basename:dotextension",
|
994
|
+
s3_credentials: {
|
995
|
+
'access_key_id' => "12345",
|
996
|
+
'secret_access_key' => "54321"
|
997
|
+
},
|
998
|
+
s3_headers: { "x-amz-storage-class" => "reduced_redundancy" }
|
999
|
+
end
|
1000
|
+
|
1001
|
+
context "when assigned" do
|
1002
|
+
before do
|
1003
|
+
@file = File.new(fixture_file('5k.png'), 'rb')
|
1004
|
+
@dummy = Dummy.new
|
1005
|
+
@dummy.avatar = @file
|
1006
|
+
end
|
1007
|
+
|
1008
|
+
after { @file.close }
|
1009
|
+
|
1010
|
+
context "and saved" do
|
1011
|
+
before do
|
1012
|
+
object = stub
|
1013
|
+
@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")
|
1018
|
+
@dummy.save
|
1019
|
+
end
|
1020
|
+
|
1021
|
+
it "succeeds" do
|
1022
|
+
assert true
|
1023
|
+
end
|
1024
|
+
end
|
1025
|
+
end
|
1026
|
+
end
|
1027
|
+
|
1028
|
+
context "using per style hash" do
|
1029
|
+
before do
|
1030
|
+
rebuild_model :storage => :s3,
|
1031
|
+
:bucket => "testing",
|
1032
|
+
:path => ":attachment/:style/:basename.:extension",
|
1033
|
+
:styles => {
|
1034
|
+
:thumb => "80x80>"
|
1035
|
+
},
|
1036
|
+
:s3_credentials => {
|
1037
|
+
'access_key_id' => "12345",
|
1038
|
+
'secret_access_key' => "54321"
|
1039
|
+
},
|
1040
|
+
:s3_storage_class => {
|
1041
|
+
:thumb => :reduced_redundancy
|
1042
|
+
}
|
1043
|
+
end
|
1044
|
+
|
1045
|
+
context "when assigned" do
|
1046
|
+
before do
|
1047
|
+
@file = File.new(fixture_file('5k.png'), 'rb')
|
1048
|
+
@dummy = Dummy.new
|
1049
|
+
@dummy.avatar = @file
|
1050
|
+
end
|
1051
|
+
|
1052
|
+
after { @file.close }
|
1053
|
+
|
1054
|
+
context "and saved" do
|
1055
|
+
before do
|
1056
|
+
object = stub
|
1057
|
+
[:thumb, :original].each do |style|
|
1058
|
+
@dummy.avatar.stubs(:s3_object).with(style).returns(object)
|
1059
|
+
expected_options = {:content_type => "image/png", :acl => :public_read}
|
1060
|
+
expected_options.merge!(:storage_class => :reduced_redundancy) if style == :thumb
|
1061
|
+
object.expects(:write).with(anything, expected_options)
|
1062
|
+
end
|
1063
|
+
@dummy.save
|
1064
|
+
end
|
1065
|
+
|
1066
|
+
it "succeeds" do
|
1067
|
+
assert true
|
1068
|
+
end
|
1069
|
+
end
|
1070
|
+
end
|
1071
|
+
end
|
1072
|
+
|
1073
|
+
context "using global hash option" do
|
1074
|
+
before do
|
1075
|
+
rebuild_model :storage => :s3,
|
1076
|
+
:bucket => "testing",
|
1077
|
+
:path => ":attachment/:style/:basename.:extension",
|
1078
|
+
:styles => {
|
1079
|
+
:thumb => "80x80>"
|
1080
|
+
},
|
1081
|
+
:s3_credentials => {
|
1082
|
+
'access_key_id' => "12345",
|
1083
|
+
'secret_access_key' => "54321"
|
1084
|
+
},
|
1085
|
+
:s3_storage_class => :reduced_redundancy
|
1086
|
+
end
|
1087
|
+
|
1088
|
+
context "when assigned" do
|
1089
|
+
before do
|
1090
|
+
@file = File.new(fixture_file('5k.png'), 'rb')
|
1091
|
+
@dummy = Dummy.new
|
1092
|
+
@dummy.avatar = @file
|
1093
|
+
end
|
1094
|
+
|
1095
|
+
after { @file.close }
|
1096
|
+
|
1097
|
+
context "and saved" do
|
1098
|
+
before do
|
1099
|
+
object = stub
|
1100
|
+
[:thumb, :original].each do |style|
|
1101
|
+
@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)
|
1105
|
+
end
|
1106
|
+
@dummy.save
|
1107
|
+
end
|
1108
|
+
|
1109
|
+
it "succeeds" do
|
1110
|
+
assert true
|
1111
|
+
end
|
1112
|
+
end
|
1113
|
+
end
|
1114
|
+
end
|
1115
|
+
end
|
1116
|
+
|
1117
|
+
context "Can disable AES256 encryption multiple ways" do
|
1118
|
+
[nil, false, ''].each do |tech|
|
1119
|
+
before do
|
1120
|
+
rebuild_model(
|
1121
|
+
storage: :s3,
|
1122
|
+
bucket: "testing",
|
1123
|
+
path: ":attachment/:style/:basename:dotextension",
|
1124
|
+
s3_credentials: {
|
1125
|
+
'access_key_id' => "12345",
|
1126
|
+
'secret_access_key' => "54321"},
|
1127
|
+
s3_server_side_encryption: tech)
|
1128
|
+
end
|
1129
|
+
|
1130
|
+
context "when assigned" do
|
1131
|
+
before do
|
1132
|
+
@file = File.new(fixture_file('5k.png'), 'rb')
|
1133
|
+
@dummy = Dummy.new
|
1134
|
+
@dummy.avatar = @file
|
1135
|
+
end
|
1136
|
+
|
1137
|
+
after { @file.close }
|
1138
|
+
|
1139
|
+
context "and saved" do
|
1140
|
+
before do
|
1141
|
+
object = stub
|
1142
|
+
@dummy.avatar.stubs(:s3_object).returns(object)
|
1143
|
+
object.expects(:write).with(anything,
|
1144
|
+
content_type: "image/png",
|
1145
|
+
acl: :public_read)
|
1146
|
+
@dummy.save
|
1147
|
+
end
|
1148
|
+
|
1149
|
+
it "succeeds" do
|
1150
|
+
assert true
|
1151
|
+
end
|
1152
|
+
end
|
1153
|
+
end
|
1154
|
+
end
|
1155
|
+
end
|
1156
|
+
|
1157
|
+
context "An attachment with S3 storage and using AES256 encryption" do
|
1158
|
+
before do
|
1159
|
+
rebuild_model storage: :s3,
|
1160
|
+
bucket: "testing",
|
1161
|
+
path: ":attachment/:style/:basename:dotextension",
|
1162
|
+
s3_credentials: {
|
1163
|
+
'access_key_id' => "12345",
|
1164
|
+
'secret_access_key' => "54321"
|
1165
|
+
},
|
1166
|
+
s3_server_side_encryption: :aes256
|
1167
|
+
end
|
1168
|
+
|
1169
|
+
context "when assigned" do
|
1170
|
+
before do
|
1171
|
+
@file = File.new(fixture_file('5k.png'), 'rb')
|
1172
|
+
@dummy = Dummy.new
|
1173
|
+
@dummy.avatar = @file
|
1174
|
+
end
|
1175
|
+
|
1176
|
+
after { @file.close }
|
1177
|
+
|
1178
|
+
context "and saved" do
|
1179
|
+
before do
|
1180
|
+
object = stub
|
1181
|
+
@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)
|
1186
|
+
@dummy.save
|
1187
|
+
end
|
1188
|
+
|
1189
|
+
it "succeeds" do
|
1190
|
+
assert true
|
1191
|
+
end
|
1192
|
+
end
|
1193
|
+
end
|
1194
|
+
end
|
1195
|
+
|
1196
|
+
context "An attachment with S3 storage and storage class set using the :storage_class option" do
|
1197
|
+
before do
|
1198
|
+
rebuild_model storage: :s3,
|
1199
|
+
bucket: "testing",
|
1200
|
+
path: ":attachment/:style/:basename:dotextension",
|
1201
|
+
s3_credentials: {
|
1202
|
+
'access_key_id' => "12345",
|
1203
|
+
'secret_access_key' => "54321"
|
1204
|
+
},
|
1205
|
+
s3_storage_class: :reduced_redundancy
|
1206
|
+
end
|
1207
|
+
|
1208
|
+
context "when assigned" do
|
1209
|
+
before do
|
1210
|
+
@file = File.new(fixture_file('5k.png'), 'rb')
|
1211
|
+
@dummy = Dummy.new
|
1212
|
+
@dummy.avatar = @file
|
1213
|
+
end
|
1214
|
+
|
1215
|
+
after { @file.close }
|
1216
|
+
|
1217
|
+
context "and saved" do
|
1218
|
+
before do
|
1219
|
+
object = stub
|
1220
|
+
@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)
|
1225
|
+
@dummy.save
|
1226
|
+
end
|
1227
|
+
|
1228
|
+
it "succeeds" do
|
1229
|
+
assert true
|
1230
|
+
end
|
1231
|
+
end
|
1232
|
+
end
|
1233
|
+
end
|
1234
|
+
|
1235
|
+
context "with S3 credentials supplied as Pathname" do
|
1236
|
+
before do
|
1237
|
+
ENV['S3_KEY'] = 'pathname_key'
|
1238
|
+
ENV['S3_BUCKET'] = 'pathname_bucket'
|
1239
|
+
ENV['S3_SECRET'] = 'pathname_secret'
|
1240
|
+
|
1241
|
+
rails_env('test') do
|
1242
|
+
rebuild_model storage: :s3,
|
1243
|
+
s3_credentials: Pathname.new(fixture_file('s3.yml'))
|
1244
|
+
|
1245
|
+
Dummy.delete_all
|
1246
|
+
@dummy = Dummy.new
|
1247
|
+
end
|
1248
|
+
end
|
1249
|
+
|
1250
|
+
it "parses the credentials" do
|
1251
|
+
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
|
1254
|
+
end
|
1255
|
+
end
|
1256
|
+
|
1257
|
+
context "with S3 credentials in a YAML file" do
|
1258
|
+
before do
|
1259
|
+
ENV['S3_KEY'] = 'env_key'
|
1260
|
+
ENV['S3_BUCKET'] = 'env_bucket'
|
1261
|
+
ENV['S3_SECRET'] = 'env_secret'
|
1262
|
+
|
1263
|
+
rails_env('test') do
|
1264
|
+
rebuild_model storage: :s3,
|
1265
|
+
s3_credentials: File.new(fixture_file('s3.yml'))
|
1266
|
+
|
1267
|
+
Dummy.delete_all
|
1268
|
+
|
1269
|
+
@dummy = Dummy.new
|
1270
|
+
end
|
1271
|
+
end
|
1272
|
+
|
1273
|
+
it "runs the file through ERB" do
|
1274
|
+
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
|
1277
|
+
end
|
1278
|
+
end
|
1279
|
+
|
1280
|
+
context "S3 Permissions" do
|
1281
|
+
context "defaults to :public_read" do
|
1282
|
+
before do
|
1283
|
+
rebuild_model storage: :s3,
|
1284
|
+
bucket: "testing",
|
1285
|
+
path: ":attachment/:style/:basename:dotextension",
|
1286
|
+
s3_credentials: {
|
1287
|
+
'access_key_id' => "12345",
|
1288
|
+
'secret_access_key' => "54321"
|
1289
|
+
}
|
1290
|
+
end
|
1291
|
+
|
1292
|
+
context "when assigned" do
|
1293
|
+
before do
|
1294
|
+
@file = File.new(fixture_file('5k.png'), 'rb')
|
1295
|
+
@dummy = Dummy.new
|
1296
|
+
@dummy.avatar = @file
|
1297
|
+
end
|
1298
|
+
|
1299
|
+
after { @file.close }
|
1300
|
+
|
1301
|
+
context "and saved" do
|
1302
|
+
before do
|
1303
|
+
object = stub
|
1304
|
+
@dummy.avatar.stubs(:s3_object).returns(object)
|
1305
|
+
object.expects(:write).with(anything,
|
1306
|
+
content_type: "image/png",
|
1307
|
+
acl: :public_read)
|
1308
|
+
@dummy.save
|
1309
|
+
end
|
1310
|
+
|
1311
|
+
it "succeeds" do
|
1312
|
+
assert true
|
1313
|
+
end
|
1314
|
+
end
|
1315
|
+
end
|
1316
|
+
end
|
1317
|
+
|
1318
|
+
context "string permissions set" do
|
1319
|
+
before do
|
1320
|
+
rebuild_model storage: :s3,
|
1321
|
+
bucket: "testing",
|
1322
|
+
path: ":attachment/:style/:basename:dotextension",
|
1323
|
+
s3_credentials: {
|
1324
|
+
'access_key_id' => "12345",
|
1325
|
+
'secret_access_key' => "54321"
|
1326
|
+
},
|
1327
|
+
s3_permissions: :private
|
1328
|
+
end
|
1329
|
+
|
1330
|
+
context "when assigned" do
|
1331
|
+
before do
|
1332
|
+
@file = File.new(fixture_file('5k.png'), 'rb')
|
1333
|
+
@dummy = Dummy.new
|
1334
|
+
@dummy.avatar = @file
|
1335
|
+
end
|
1336
|
+
|
1337
|
+
after { @file.close }
|
1338
|
+
|
1339
|
+
context "and saved" do
|
1340
|
+
before do
|
1341
|
+
object = stub
|
1342
|
+
@dummy.avatar.stubs(:s3_object).returns(object)
|
1343
|
+
object.expects(:write).with(anything,
|
1344
|
+
content_type: "image/png",
|
1345
|
+
acl: :private)
|
1346
|
+
@dummy.save
|
1347
|
+
end
|
1348
|
+
|
1349
|
+
it "succeeds" do
|
1350
|
+
assert true
|
1351
|
+
end
|
1352
|
+
end
|
1353
|
+
end
|
1354
|
+
end
|
1355
|
+
|
1356
|
+
context "hash permissions set" do
|
1357
|
+
before do
|
1358
|
+
rebuild_model storage: :s3,
|
1359
|
+
bucket: "testing",
|
1360
|
+
path: ":attachment/:style/:basename:dotextension",
|
1361
|
+
styles: {
|
1362
|
+
thumb: "80x80>"
|
1363
|
+
},
|
1364
|
+
s3_credentials: {
|
1365
|
+
'access_key_id' => "12345",
|
1366
|
+
'secret_access_key' => "54321"
|
1367
|
+
},
|
1368
|
+
s3_permissions: {
|
1369
|
+
original: :private,
|
1370
|
+
thumb: :public_read
|
1371
|
+
}
|
1372
|
+
end
|
1373
|
+
|
1374
|
+
context "when assigned" do
|
1375
|
+
before do
|
1376
|
+
@file = File.new(fixture_file('5k.png'), 'rb')
|
1377
|
+
@dummy = Dummy.new
|
1378
|
+
@dummy.avatar = @file
|
1379
|
+
end
|
1380
|
+
|
1381
|
+
after { @file.close }
|
1382
|
+
|
1383
|
+
context "and saved" do
|
1384
|
+
before do
|
1385
|
+
[:thumb, :original].each do |style|
|
1386
|
+
object = stub
|
1387
|
+
@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)
|
1391
|
+
end
|
1392
|
+
@dummy.save
|
1393
|
+
end
|
1394
|
+
|
1395
|
+
it "succeeds" do
|
1396
|
+
assert true
|
1397
|
+
end
|
1398
|
+
end
|
1399
|
+
end
|
1400
|
+
end
|
1401
|
+
|
1402
|
+
context "proc permission set" do
|
1403
|
+
before do
|
1404
|
+
rebuild_model(
|
1405
|
+
storage: :s3,
|
1406
|
+
bucket: "testing",
|
1407
|
+
path: ":attachment/:style/:basename:dotextension",
|
1408
|
+
styles: {
|
1409
|
+
thumb: "80x80>"
|
1410
|
+
},
|
1411
|
+
s3_credentials: {
|
1412
|
+
'access_key_id' => "12345",
|
1413
|
+
'secret_access_key' => "54321"
|
1414
|
+
},
|
1415
|
+
s3_permissions: lambda {|attachment, style|
|
1416
|
+
attachment.instance.private_attachment? && style.to_sym != :thumb ? :private : :public_read
|
1417
|
+
}
|
1418
|
+
)
|
1419
|
+
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
|
+
end
|
1444
|
+
end
|
1445
|
+
|
1446
|
+
context "An attachment with S3 storage and metadata set using a proc as headers" do
|
1447
|
+
before do
|
1448
|
+
rebuild_model(
|
1449
|
+
storage: :s3,
|
1450
|
+
bucket: "testing",
|
1451
|
+
path: ":attachment/:style/:basename:dotextension",
|
1452
|
+
styles: {
|
1453
|
+
thumb: "80x80>"
|
1454
|
+
},
|
1455
|
+
s3_credentials: {
|
1456
|
+
'access_key_id' => "12345",
|
1457
|
+
'secret_access_key' => "54321"
|
1458
|
+
},
|
1459
|
+
s3_headers: lambda {|attachment|
|
1460
|
+
{'Content-Disposition' => "attachment; filename=\"#{attachment.name}\""}
|
1461
|
+
}
|
1462
|
+
)
|
1463
|
+
end
|
1464
|
+
|
1465
|
+
context "when assigned" do
|
1466
|
+
before do
|
1467
|
+
@file = File.new(fixture_file('5k.png'), 'rb')
|
1468
|
+
@dummy = Dummy.new
|
1469
|
+
@dummy.stubs(name: 'Custom Avatar Name.png')
|
1470
|
+
@dummy.avatar = @file
|
1471
|
+
end
|
1472
|
+
|
1473
|
+
after { @file.close }
|
1474
|
+
|
1475
|
+
context "and saved" do
|
1476
|
+
before do
|
1477
|
+
[:thumb, :original].each do |style|
|
1478
|
+
object = stub
|
1479
|
+
@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"')
|
1484
|
+
end
|
1485
|
+
@dummy.save
|
1486
|
+
end
|
1487
|
+
|
1488
|
+
it "succeeds" do
|
1489
|
+
assert true
|
1490
|
+
end
|
1491
|
+
end
|
1492
|
+
end
|
1493
|
+
end
|
1494
|
+
|
1495
|
+
context "path is a proc" do
|
1496
|
+
before do
|
1497
|
+
rebuild_model storage: :s3,
|
1498
|
+
path: ->(attachment) { attachment.instance.attachment_path }
|
1499
|
+
|
1500
|
+
@dummy = Dummy.new
|
1501
|
+
@dummy.class_eval do
|
1502
|
+
def attachment_path
|
1503
|
+
'/some/dynamic/path'
|
1504
|
+
end
|
1505
|
+
end
|
1506
|
+
@dummy.avatar = stringy_file
|
1507
|
+
end
|
1508
|
+
|
1509
|
+
it "returns a correct path" do
|
1510
|
+
assert_match '/some/dynamic/path', @dummy.avatar.path
|
1511
|
+
end
|
1512
|
+
end
|
1513
|
+
|
1514
|
+
|
1515
|
+
private
|
1516
|
+
|
1517
|
+
def rails_env(env)
|
1518
|
+
stored_env, Rails.env = Rails.env, env
|
1519
|
+
begin
|
1520
|
+
yield
|
1521
|
+
ensure
|
1522
|
+
Rails.env = stored_env
|
1523
|
+
end
|
1524
|
+
end
|
1525
|
+
|
1526
|
+
end
|