cloudfuji_paperclip 2.4.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (105) hide show
  1. data/.gitignore +22 -0
  2. data/.travis.yml +13 -0
  3. data/Appraisals +14 -0
  4. data/CONTRIBUTING.md +38 -0
  5. data/Gemfile +5 -0
  6. data/Gemfile.lock +137 -0
  7. data/LICENSE +26 -0
  8. data/README.md +444 -0
  9. data/Rakefile +41 -0
  10. data/cucumber/paperclip_steps.rb +6 -0
  11. data/features/basic_integration.feature +46 -0
  12. data/features/rake_tasks.feature +63 -0
  13. data/features/step_definitions/attachment_steps.rb +65 -0
  14. data/features/step_definitions/html_steps.rb +15 -0
  15. data/features/step_definitions/rails_steps.rb +182 -0
  16. data/features/step_definitions/s3_steps.rb +14 -0
  17. data/features/step_definitions/web_steps.rb +209 -0
  18. data/features/support/env.rb +8 -0
  19. data/features/support/fakeweb.rb +3 -0
  20. data/features/support/fixtures/.boot_config.rb.swo +0 -0
  21. data/features/support/fixtures/boot_config.txt +15 -0
  22. data/features/support/fixtures/gemfile.txt +5 -0
  23. data/features/support/fixtures/preinitializer.txt +20 -0
  24. data/features/support/paths.rb +28 -0
  25. data/features/support/rails.rb +46 -0
  26. data/features/support/selectors.rb +19 -0
  27. data/gemfiles/rails2.gemfile +9 -0
  28. data/gemfiles/rails3.gemfile +9 -0
  29. data/gemfiles/rails3_1.gemfile +9 -0
  30. data/generators/paperclip/USAGE +5 -0
  31. data/generators/paperclip/paperclip_generator.rb +27 -0
  32. data/generators/paperclip/templates/paperclip_migration.rb.erb +19 -0
  33. data/init.rb +4 -0
  34. data/lib/generators/paperclip/USAGE +8 -0
  35. data/lib/generators/paperclip/paperclip_generator.rb +33 -0
  36. data/lib/generators/paperclip/templates/paperclip_migration.rb.erb +19 -0
  37. data/lib/paperclip/attachment.rb +468 -0
  38. data/lib/paperclip/callback_compatibility.rb +61 -0
  39. data/lib/paperclip/geometry.rb +120 -0
  40. data/lib/paperclip/interpolations.rb +174 -0
  41. data/lib/paperclip/iostream.rb +45 -0
  42. data/lib/paperclip/matchers/have_attached_file_matcher.rb +57 -0
  43. data/lib/paperclip/matchers/validate_attachment_content_type_matcher.rb +81 -0
  44. data/lib/paperclip/matchers/validate_attachment_presence_matcher.rb +54 -0
  45. data/lib/paperclip/matchers/validate_attachment_size_matcher.rb +95 -0
  46. data/lib/paperclip/matchers.rb +64 -0
  47. data/lib/paperclip/missing_attachment_styles.rb +87 -0
  48. data/lib/paperclip/processor.rb +58 -0
  49. data/lib/paperclip/railtie.rb +31 -0
  50. data/lib/paperclip/schema.rb +39 -0
  51. data/lib/paperclip/storage/filesystem.rb +81 -0
  52. data/lib/paperclip/storage/fog.rb +174 -0
  53. data/lib/paperclip/storage/s3.rb +333 -0
  54. data/lib/paperclip/storage.rb +3 -0
  55. data/lib/paperclip/style.rb +103 -0
  56. data/lib/paperclip/thumbnail.rb +105 -0
  57. data/lib/paperclip/upfile.rb +62 -0
  58. data/lib/paperclip/url_generator.rb +64 -0
  59. data/lib/paperclip/version.rb +3 -0
  60. data/lib/paperclip.rb +487 -0
  61. data/lib/tasks/paperclip.rake +101 -0
  62. data/paperclip.gemspec +41 -0
  63. data/rails/init.rb +2 -0
  64. data/shoulda_macros/paperclip.rb +124 -0
  65. data/test/.gitignore +1 -0
  66. data/test/attachment_test.rb +1116 -0
  67. data/test/database.yml +4 -0
  68. data/test/fixtures/12k.png +0 -0
  69. data/test/fixtures/50x50.png +0 -0
  70. data/test/fixtures/5k.png +0 -0
  71. data/test/fixtures/animated.gif +0 -0
  72. data/test/fixtures/bad.png +1 -0
  73. data/test/fixtures/fog.yml +8 -0
  74. data/test/fixtures/question?mark.png +0 -0
  75. data/test/fixtures/s3.yml +8 -0
  76. data/test/fixtures/spaced file.png +0 -0
  77. data/test/fixtures/text.txt +1 -0
  78. data/test/fixtures/twopage.pdf +0 -0
  79. data/test/fixtures/uppercase.PNG +0 -0
  80. data/test/geometry_test.rb +206 -0
  81. data/test/helper.rb +177 -0
  82. data/test/integration_test.rb +654 -0
  83. data/test/interpolations_test.rb +216 -0
  84. data/test/iostream_test.rb +71 -0
  85. data/test/matchers/have_attached_file_matcher_test.rb +24 -0
  86. data/test/matchers/validate_attachment_content_type_matcher_test.rb +87 -0
  87. data/test/matchers/validate_attachment_presence_matcher_test.rb +26 -0
  88. data/test/matchers/validate_attachment_size_matcher_test.rb +51 -0
  89. data/test/paperclip_missing_attachment_styles_test.rb +80 -0
  90. data/test/paperclip_test.rb +390 -0
  91. data/test/processor_test.rb +10 -0
  92. data/test/schema_test.rb +98 -0
  93. data/test/storage/filesystem_test.rb +56 -0
  94. data/test/storage/fog_test.rb +219 -0
  95. data/test/storage/s3_live_test.rb +138 -0
  96. data/test/storage/s3_test.rb +943 -0
  97. data/test/style_test.rb +209 -0
  98. data/test/support/mock_attachment.rb +22 -0
  99. data/test/support/mock_interpolator.rb +24 -0
  100. data/test/support/mock_model.rb +2 -0
  101. data/test/support/mock_url_generator_builder.rb +27 -0
  102. data/test/thumbnail_test.rb +383 -0
  103. data/test/upfile_test.rb +53 -0
  104. data/test/url_generator_test.rb +187 -0
  105. metadata +404 -0
@@ -0,0 +1,943 @@
1
+ require './test/helper'
2
+ require 'aws'
3
+
4
+ class S3Test < Test::Unit::TestCase
5
+ def rails_env(env)
6
+ silence_warnings do
7
+ Object.const_set(:Rails, stub('Rails', :env => env))
8
+ end
9
+ end
10
+
11
+ def setup
12
+ AWS.config(:access_key_id => "TESTKEY", :secret_access_key => "TESTSECRET", :stub_requests => true)
13
+ end
14
+
15
+ def teardown
16
+ AWS.config(:access_key_id => nil, :secret_access_key => nil, :stub_requests => nil)
17
+ end
18
+
19
+ context "Parsing S3 credentials" do
20
+ setup do
21
+ @proxy_settings = {:host => "127.0.0.1", :port => 8888, :user => "foo", :password => "bar"}
22
+ rebuild_model :storage => :s3,
23
+ :bucket => "testing",
24
+ :http_proxy => @proxy_settings,
25
+ :s3_credentials => {:not => :important}
26
+
27
+ @dummy = Dummy.new
28
+ @avatar = @dummy.avatar
29
+ end
30
+
31
+ should "get the correct credentials when RAILS_ENV is production" do
32
+ rails_env("production")
33
+ assert_equal({:key => "12345"},
34
+ @avatar.parse_credentials('production' => {:key => '12345'},
35
+ :development => {:key => "54321"}))
36
+ end
37
+
38
+ should "get the correct credentials when RAILS_ENV is development" do
39
+ rails_env("development")
40
+ assert_equal({:key => "54321"},
41
+ @avatar.parse_credentials('production' => {:key => '12345'},
42
+ :development => {:key => "54321"}))
43
+ end
44
+
45
+ should "return the argument if the key does not exist" do
46
+ rails_env("not really an env")
47
+ assert_equal({:test => "12345"}, @avatar.parse_credentials(:test => "12345"))
48
+ end
49
+
50
+ should "support HTTP proxy settings" do
51
+ rails_env("development")
52
+ assert_equal(true, @avatar.using_http_proxy?)
53
+ assert_equal(@proxy_settings[:host], @avatar.http_proxy_host)
54
+ assert_equal(@proxy_settings[:port], @avatar.http_proxy_port)
55
+ assert_equal(@proxy_settings[:user], @avatar.http_proxy_user)
56
+ assert_equal(@proxy_settings[:password], @avatar.http_proxy_password)
57
+ end
58
+
59
+ end
60
+
61
+ context ":bucket option via :s3_credentials" do
62
+
63
+ setup do
64
+ rebuild_model :storage => :s3, :s3_credentials => {:bucket => 'testing'}
65
+ @dummy = Dummy.new
66
+ end
67
+
68
+ should "populate #bucket_name" do
69
+ assert_equal @dummy.avatar.bucket_name, 'testing'
70
+ end
71
+
72
+ end
73
+
74
+ context ":bucket option" do
75
+
76
+ setup do
77
+ rebuild_model :storage => :s3, :bucket => "testing", :s3_credentials => {}
78
+ @dummy = Dummy.new
79
+ end
80
+
81
+ should "populate #bucket_name" do
82
+ assert_equal @dummy.avatar.bucket_name, 'testing'
83
+ end
84
+
85
+ end
86
+
87
+ context "missing :bucket option" do
88
+
89
+ setup do
90
+ rebuild_model :storage => :s3,
91
+ #:bucket => "testing", # intentionally left out
92
+ :http_proxy => @proxy_settings,
93
+ :s3_credentials => {:not => :important}
94
+
95
+ @dummy = Dummy.new
96
+ @dummy.avatar = StringIO.new(".")
97
+
98
+ end
99
+
100
+ should "raise an argument error" do
101
+ exception = assert_raise(ArgumentError) { @dummy.save }
102
+ assert_match /missing required :bucket option/, exception.message
103
+ end
104
+
105
+ end
106
+
107
+ context "" do
108
+ setup do
109
+ rebuild_model :storage => :s3,
110
+ :s3_credentials => {},
111
+ :bucket => "bucket",
112
+ :path => ":attachment/:basename.:extension",
113
+ :url => ":s3_path_url"
114
+ @dummy = Dummy.new
115
+ @dummy.avatar = StringIO.new(".")
116
+ end
117
+
118
+ should "return a url based on an S3 path" do
119
+ assert_match %r{^http://s3.amazonaws.com/bucket/avatars/stringio.txt}, @dummy.avatar.url
120
+ end
121
+
122
+ should "use the correct bucket" do
123
+ assert_equal "bucket", @dummy.avatar.s3_bucket.name
124
+ end
125
+
126
+ should "use the correct key" do
127
+ assert_equal "avatars/stringio.txt", @dummy.avatar.s3_object.key
128
+ end
129
+
130
+ end
131
+
132
+ context "An attachment that uses S3 for storage and has the style in the path" do
133
+ setup do
134
+ rebuild_model :storage => :s3,
135
+ :bucket => "testing",
136
+ :path => ":attachment/:style/:basename.:extension",
137
+ :styles => {
138
+ :thumb => "80x80>"
139
+ },
140
+ :s3_credentials => {
141
+ 'access_key_id' => "12345",
142
+ 'secret_access_key' => "54321"
143
+ }
144
+
145
+ @dummy = Dummy.new
146
+ @dummy.avatar = StringIO.new(".")
147
+ @avatar = @dummy.avatar
148
+ end
149
+
150
+ should "use an S3 object based on the correct path for the default style" do
151
+ assert_equal("avatars/original/stringio.txt", @dummy.avatar.s3_object.key)
152
+ end
153
+
154
+ should "use an S3 object based on the correct path for the custom style" do
155
+ assert_equal("avatars/thumb/stringio.txt", @dummy.avatar.s3_object(:thumb).key)
156
+ end
157
+ end
158
+
159
+ context "s3_host_name" do
160
+ setup do
161
+ rebuild_model :storage => :s3,
162
+ :s3_credentials => {},
163
+ :bucket => "bucket",
164
+ :path => ":attachment/:basename.:extension",
165
+ :s3_host_name => "s3-ap-northeast-1.amazonaws.com"
166
+ @dummy = Dummy.new
167
+ @dummy.avatar = StringIO.new(".")
168
+ end
169
+
170
+ should "return a url based on an :s3_host_name path" do
171
+ assert_match %r{^http://s3-ap-northeast-1.amazonaws.com/bucket/avatars/stringio.txt}, @dummy.avatar.url
172
+ end
173
+
174
+ should "use the S3 bucket with the correct host name" do
175
+ assert_equal "s3-ap-northeast-1.amazonaws.com", @dummy.avatar.s3_bucket.config.s3_endpoint
176
+ end
177
+ end
178
+
179
+ context "An attachment that uses S3 for storage and has styles that return different file types" do
180
+ setup do
181
+ rebuild_model :styles => { :large => ['500x500#', :jpg] },
182
+ :storage => :s3,
183
+ :bucket => "bucket",
184
+ :path => ":attachment/:basename.:extension",
185
+ :s3_credentials => {
186
+ 'access_key_id' => "12345",
187
+ 'secret_access_key' => "54321"
188
+ }
189
+
190
+ @dummy = Dummy.new
191
+ @dummy.avatar = File.new(fixture_file('5k.png'), 'rb')
192
+ end
193
+
194
+ should "return a url containing the correct original file mime type" do
195
+ assert_match /.+\/5k.png/, @dummy.avatar.url
196
+ end
197
+
198
+ should 'use the correct key for the original file mime type' do
199
+ assert_match /.+\/5k.png/, @dummy.avatar.s3_object.key
200
+ end
201
+
202
+ should "return a url containing the correct processed file mime type" do
203
+ assert_match /.+\/5k.jpg/, @dummy.avatar.url(:large)
204
+ end
205
+
206
+ should "use the correct key for the processed file mime type" do
207
+ assert_match /.+\/5k.jpg/, @dummy.avatar.s3_object(:large).key
208
+ end
209
+ end
210
+
211
+ context "An attachment that uses S3 for storage and has spaces in file name" do
212
+ setup do
213
+ rebuild_model :styles => { :large => ['500x500#', :jpg] },
214
+ :storage => :s3,
215
+ :bucket => "bucket",
216
+ :s3_credentials => {
217
+ 'access_key_id' => "12345",
218
+ 'secret_access_key' => "54321"
219
+ }
220
+
221
+ @dummy = Dummy.new
222
+ @dummy.avatar = File.new(fixture_file('spaced file.png'), 'rb')
223
+ end
224
+
225
+ should "return an unescaped version for path" do
226
+ assert_match /.+\/spaced file\.png/, @dummy.avatar.path
227
+ end
228
+
229
+ should "return an escaped version for url" do
230
+ assert_match /.+\/spaced%20file\.png/, @dummy.avatar.url
231
+ end
232
+ end
233
+
234
+ context "" do
235
+ setup do
236
+ rebuild_model :storage => :s3,
237
+ :s3_credentials => {},
238
+ :bucket => "bucket",
239
+ :path => ":attachment/:basename.:extension",
240
+ :url => ":s3_domain_url"
241
+ @dummy = Dummy.new
242
+ @dummy.avatar = StringIO.new(".")
243
+ end
244
+
245
+ should "return a url based on an S3 subdomain" do
246
+ assert_match %r{^http://bucket.s3.amazonaws.com/avatars/stringio.txt}, @dummy.avatar.url
247
+ end
248
+ end
249
+
250
+ context "" do
251
+ setup do
252
+ rebuild_model :storage => :s3,
253
+ :s3_credentials => {
254
+ :production => { :bucket => "prod_bucket" },
255
+ :development => { :bucket => "dev_bucket" }
256
+ },
257
+ :s3_host_alias => "something.something.com",
258
+ :path => ":attachment/:basename.:extension",
259
+ :url => ":s3_alias_url"
260
+ @dummy = Dummy.new
261
+ @dummy.avatar = StringIO.new(".")
262
+ end
263
+
264
+ should "return a url based on the host_alias" do
265
+ assert_match %r{^http://something.something.com/avatars/stringio.txt}, @dummy.avatar.url
266
+ end
267
+ end
268
+
269
+ context "generating a url with a proc as the host alias" do
270
+ setup do
271
+ rebuild_model :storage => :s3,
272
+ :s3_credentials => { :bucket => "prod_bucket" },
273
+ :s3_host_alias => Proc.new{|atch| "cdn#{atch.instance.counter % 4}.example.com"},
274
+ :path => ":attachment/:basename.:extension",
275
+ :url => ":s3_alias_url"
276
+ Dummy.class_eval do
277
+ def counter
278
+ @counter ||= 0
279
+ @counter += 1
280
+ @counter
281
+ end
282
+ end
283
+ @dummy = Dummy.new
284
+ @dummy.avatar = StringIO.new(".")
285
+ end
286
+
287
+ should "return a url based on the host_alias" do
288
+ assert_match %r{^http://cdn1.example.com/avatars/stringio.txt}, @dummy.avatar.url
289
+ assert_match %r{^http://cdn2.example.com/avatars/stringio.txt}, @dummy.avatar.url
290
+ end
291
+
292
+ should "still return the bucket name" do
293
+ assert_equal "prod_bucket", @dummy.avatar.bucket_name
294
+ end
295
+
296
+ end
297
+
298
+ context "" do
299
+ setup do
300
+ rebuild_model :storage => :s3,
301
+ :s3_credentials => {},
302
+ :bucket => "bucket",
303
+ :path => ":attachment/:basename.:extension",
304
+ :url => ":asset_host"
305
+ @dummy = Dummy.new
306
+ @dummy.avatar = StringIO.new(".")
307
+ end
308
+
309
+ should "return a relative URL for Rails to calculate assets host" do
310
+ assert_match %r{^avatars/stringio\.txt}, @dummy.avatar.url
311
+ end
312
+ end
313
+
314
+ context "Generating a secure url with an expiration" do
315
+ setup do
316
+ rebuild_model :storage => :s3,
317
+ :s3_credentials => {
318
+ :production => { :bucket => "prod_bucket" },
319
+ :development => { :bucket => "dev_bucket" }
320
+ },
321
+ :s3_host_alias => "something.something.com",
322
+ :s3_permissions => "private",
323
+ :path => ":attachment/:basename.:extension",
324
+ :url => ":s3_alias_url"
325
+
326
+ rails_env("production")
327
+
328
+ @dummy = Dummy.new
329
+ @dummy.avatar = StringIO.new(".")
330
+
331
+ object = stub
332
+ @dummy.avatar.stubs(:s3_object).returns(object)
333
+ object.expects(:url_for).with(:read, :expires => 3600, :secure => true)
334
+
335
+ @dummy.avatar.expiring_url
336
+ end
337
+
338
+ should "should succeed" do
339
+ assert true
340
+ end
341
+ end
342
+
343
+ context "Generating a url with an expiration for each style" do
344
+ setup do
345
+ rebuild_model :storage => :s3,
346
+ :s3_credentials => {
347
+ :production => { :bucket => "prod_bucket" },
348
+ :development => { :bucket => "dev_bucket" }
349
+ },
350
+ :s3_permissions => :private,
351
+ :s3_host_alias => "something.something.com",
352
+ :path => ":attachment/:style/:basename.:extension",
353
+ :url => ":s3_alias_url"
354
+
355
+ rails_env("production")
356
+
357
+ @dummy = Dummy.new
358
+ @dummy.avatar = StringIO.new(".")
359
+ end
360
+
361
+ should "should generate a url for the thumb" do
362
+ object = stub
363
+ @dummy.avatar.stubs(:s3_object).with(:thumb).returns(object)
364
+ object.expects(:url_for).with(:read, :expires => 1800, :secure => true)
365
+ @dummy.avatar.expiring_url(1800, :thumb)
366
+ end
367
+
368
+ should "should generate a url for the default style" do
369
+ object = stub
370
+ @dummy.avatar.stubs(:s3_object).with(:original).returns(object)
371
+ object.expects(:url_for).with(:read, :expires => 1800, :secure => true)
372
+ @dummy.avatar.expiring_url(1800)
373
+ end
374
+ end
375
+
376
+ context "Parsing S3 credentials with a bucket in them" do
377
+ setup do
378
+ rebuild_model :storage => :s3,
379
+ :s3_credentials => {
380
+ :production => { :bucket => "prod_bucket" },
381
+ :development => { :bucket => "dev_bucket" }
382
+ }
383
+ @dummy = Dummy.new
384
+ end
385
+
386
+ should "get the right bucket in production" do
387
+ rails_env("production")
388
+ assert_equal "prod_bucket", @dummy.avatar.bucket_name
389
+ assert_equal "prod_bucket", @dummy.avatar.s3_bucket.name
390
+ end
391
+
392
+ should "get the right bucket in development" do
393
+ rails_env("development")
394
+ assert_equal "dev_bucket", @dummy.avatar.bucket_name
395
+ assert_equal "dev_bucket", @dummy.avatar.s3_bucket.name
396
+ end
397
+ end
398
+
399
+ context "Parsing S3 credentials with a s3_host_name in them" do
400
+ setup do
401
+ rebuild_model :storage => :s3,
402
+ :bucket => 'testing',
403
+ :s3_credentials => {
404
+ :production => { :s3_host_name => "s3-world-end.amazonaws.com" },
405
+ :development => { :s3_host_name => "s3-ap-northeast-1.amazonaws.com" }
406
+ }
407
+ @dummy = Dummy.new
408
+ end
409
+
410
+ should "get the right s3_host_name in production" do
411
+ rails_env("production")
412
+ assert_match %r{^s3-world-end.amazonaws.com}, @dummy.avatar.s3_host_name
413
+ assert_match %r{^s3-world-end.amazonaws.com}, @dummy.avatar.s3_bucket.config.s3_endpoint
414
+ end
415
+
416
+ should "get the right s3_host_name in development" do
417
+ rails_env("development")
418
+ assert_match %r{^s3-ap-northeast-1.amazonaws.com}, @dummy.avatar.s3_host_name
419
+ assert_match %r{^s3-ap-northeast-1.amazonaws.com}, @dummy.avatar.s3_bucket.config.s3_endpoint
420
+ end
421
+
422
+ should "get the right s3_host_name if the key does not exist" do
423
+ rails_env("test")
424
+ assert_match %r{^s3.amazonaws.com}, @dummy.avatar.s3_host_name
425
+ assert_match %r{^s3.amazonaws.com}, @dummy.avatar.s3_bucket.config.s3_endpoint
426
+ end
427
+ end
428
+
429
+ context "An attachment with S3 storage" do
430
+ setup do
431
+ rebuild_model :storage => :s3,
432
+ :bucket => "testing",
433
+ :path => ":attachment/:style/:basename.:extension",
434
+ :s3_credentials => {
435
+ 'access_key_id' => "12345",
436
+ 'secret_access_key' => "54321"
437
+ }
438
+ end
439
+
440
+ should "be extended by the S3 module" do
441
+ assert Dummy.new.avatar.is_a?(Paperclip::Storage::S3)
442
+ end
443
+
444
+ should "not be extended by the Filesystem module" do
445
+ assert ! Dummy.new.avatar.is_a?(Paperclip::Storage::Filesystem)
446
+ end
447
+
448
+ context "when assigned" do
449
+ setup do
450
+ @file = File.new(fixture_file('5k.png'), 'rb')
451
+ @dummy = Dummy.new
452
+ @dummy.avatar = @file
453
+ end
454
+
455
+ teardown { @file.close }
456
+
457
+ should "not get a bucket to get a URL" do
458
+ @dummy.avatar.expects(:s3).never
459
+ @dummy.avatar.expects(:s3_bucket).never
460
+ assert_match %r{^http://s3\.amazonaws\.com/testing/avatars/original/5k\.png}, @dummy.avatar.url
461
+ end
462
+
463
+ context "and saved" do
464
+ setup do
465
+ object = stub
466
+ @dummy.avatar.stubs(:s3_object).returns(object)
467
+ object.expects(:write).with(anything,
468
+ :content_type => "image/png",
469
+ :acl => :public_read)
470
+ @dummy.save
471
+ end
472
+
473
+ should "succeed" do
474
+ assert true
475
+ end
476
+ end
477
+
478
+ should "delete tempfiles" do
479
+ File.stubs(:exist?).returns(true)
480
+ Paperclip::Tempfile.any_instance.expects(:close).at_least_once()
481
+ Paperclip::Tempfile.any_instance.expects(:unlink).at_least_once()
482
+
483
+ @dummy.save!
484
+ end
485
+
486
+ context "and saved without a bucket" do
487
+ setup do
488
+ AWS::S3::BucketCollection.any_instance.expects(:create).with("testing")
489
+ AWS::S3::S3Object.any_instance.stubs(:write).
490
+ raises(AWS::S3::Errors::NoSuchBucket.new(stub,
491
+ stub(:status => 404,
492
+ :body => "<foo/>"))).
493
+ then.returns(nil)
494
+ @dummy.save
495
+ end
496
+
497
+ should "succeed" do
498
+ assert true
499
+ end
500
+ end
501
+
502
+ context "and remove" do
503
+ setup do
504
+ AWS::S3::S3Object.any_instance.stubs(:exists?).returns(true)
505
+ AWS::S3::S3Object.any_instance.stubs(:delete)
506
+ @dummy.destroy_attached_files
507
+ end
508
+
509
+ should "succeed" do
510
+ assert true
511
+ end
512
+ end
513
+ end
514
+ end
515
+
516
+ context "An attachment with S3 storage and bucket defined as a Proc" do
517
+ setup do
518
+ rebuild_model :storage => :s3,
519
+ :bucket => lambda { |attachment| "bucket_#{attachment.instance.other}" },
520
+ :s3_credentials => {:not => :important}
521
+ end
522
+
523
+ should "get the right bucket name" do
524
+ assert "bucket_a", Dummy.new(:other => 'a').avatar.bucket_name
525
+ assert "bucket_a", Dummy.new(:other => 'a').avatar.s3_bucket.name
526
+ assert "bucket_b", Dummy.new(:other => 'b').avatar.bucket_name
527
+ assert "bucket_b", Dummy.new(:other => 'b').avatar.s3_bucket.name
528
+ end
529
+ end
530
+
531
+ context "An attachment with S3 storage and specific s3 headers set" do
532
+ setup do
533
+ rebuild_model :storage => :s3,
534
+ :bucket => "testing",
535
+ :path => ":attachment/:style/:basename.:extension",
536
+ :s3_credentials => {
537
+ 'access_key_id' => "12345",
538
+ 'secret_access_key' => "54321"
539
+ },
540
+ :s3_headers => {'Cache-Control' => 'max-age=31557600'}
541
+ end
542
+
543
+ context "when assigned" do
544
+ setup do
545
+ @file = File.new(fixture_file('5k.png'), 'rb')
546
+ @dummy = Dummy.new
547
+ @dummy.avatar = @file
548
+ end
549
+
550
+ teardown { @file.close }
551
+
552
+ context "and saved" do
553
+ setup do
554
+ object = stub
555
+ @dummy.avatar.stubs(:s3_object).returns(object)
556
+ object.expects(:write).with(anything,
557
+ :content_type => "image/png",
558
+ :acl => :public_read,
559
+ :cache_control => 'max-age=31557600')
560
+ @dummy.save
561
+ end
562
+
563
+ should "succeed" do
564
+ assert true
565
+ end
566
+ end
567
+ end
568
+ end
569
+
570
+ context "An attachment with S3 storage and metadata set using header names" do
571
+ setup do
572
+ rebuild_model :storage => :s3,
573
+ :bucket => "testing",
574
+ :path => ":attachment/:style/:basename.:extension",
575
+ :s3_credentials => {
576
+ 'access_key_id' => "12345",
577
+ 'secret_access_key' => "54321"
578
+ },
579
+ :s3_headers => {'x-amz-meta-color' => 'red'}
580
+ end
581
+
582
+ context "when assigned" do
583
+ setup do
584
+ @file = File.new(File.join(File.dirname(__FILE__), '..', 'fixtures', '5k.png'), 'rb')
585
+ @dummy = Dummy.new
586
+ @dummy.avatar = @file
587
+ end
588
+
589
+ teardown { @file.close }
590
+
591
+ context "and saved" do
592
+ setup do
593
+ object = stub
594
+ @dummy.avatar.stubs(:s3_object).returns(object)
595
+ object.expects(:write).with(anything,
596
+ :content_type => "image/png",
597
+ :acl => :public_read,
598
+ :metadata => { "color" => "red" })
599
+ @dummy.save
600
+ end
601
+
602
+ should "succeed" do
603
+ assert true
604
+ end
605
+ end
606
+ end
607
+ end
608
+
609
+ context "An attachment with S3 storage and metadata set using the :s3_metadata option" do
610
+ setup do
611
+ rebuild_model :storage => :s3,
612
+ :bucket => "testing",
613
+ :path => ":attachment/:style/:basename.:extension",
614
+ :s3_credentials => {
615
+ 'access_key_id' => "12345",
616
+ 'secret_access_key' => "54321"
617
+ },
618
+ :s3_metadata => { "color" => "red" }
619
+ end
620
+
621
+ context "when assigned" do
622
+ setup do
623
+ @file = File.new(File.join(File.dirname(__FILE__), '..', 'fixtures', '5k.png'), 'rb')
624
+ @dummy = Dummy.new
625
+ @dummy.avatar = @file
626
+ end
627
+
628
+ teardown { @file.close }
629
+
630
+ context "and saved" do
631
+ setup do
632
+ object = stub
633
+ @dummy.avatar.stubs(:s3_object).returns(object)
634
+ object.expects(:write).with(anything,
635
+ :content_type => "image/png",
636
+ :acl => :public_read,
637
+ :metadata => { "color" => "red" })
638
+ @dummy.save
639
+ end
640
+
641
+ should "succeed" do
642
+ assert true
643
+ end
644
+ end
645
+ end
646
+ end
647
+
648
+ context "An attachment with S3 storage and storage class set using the header name" do
649
+ setup do
650
+ rebuild_model :storage => :s3,
651
+ :bucket => "testing",
652
+ :path => ":attachment/:style/:basename.:extension",
653
+ :s3_credentials => {
654
+ 'access_key_id' => "12345",
655
+ 'secret_access_key' => "54321"
656
+ },
657
+ :s3_headers => { "x-amz-storage-class" => "reduced_redundancy" }
658
+ end
659
+
660
+ context "when assigned" do
661
+ setup do
662
+ @file = File.new(File.join(File.dirname(__FILE__), '..', 'fixtures', '5k.png'), 'rb')
663
+ @dummy = Dummy.new
664
+ @dummy.avatar = @file
665
+ end
666
+
667
+ teardown { @file.close }
668
+
669
+ context "and saved" do
670
+ setup do
671
+ object = stub
672
+ @dummy.avatar.stubs(:s3_object).returns(object)
673
+ object.expects(:write).with(anything,
674
+ :content_type => "image/png",
675
+ :acl => :public_read,
676
+ :storage_class => "reduced_redundancy")
677
+ @dummy.save
678
+ end
679
+
680
+ should "succeed" do
681
+ assert true
682
+ end
683
+ end
684
+ end
685
+ end
686
+
687
+ context "An attachment with S3 storage and storage class set using the :storage_class option" do
688
+ setup do
689
+ rebuild_model :storage => :s3,
690
+ :bucket => "testing",
691
+ :path => ":attachment/:style/:basename.:extension",
692
+ :s3_credentials => {
693
+ 'access_key_id' => "12345",
694
+ 'secret_access_key' => "54321"
695
+ },
696
+ :s3_storage_class => :reduced_redundancy
697
+ end
698
+
699
+ context "when assigned" do
700
+ setup do
701
+ @file = File.new(File.join(File.dirname(__FILE__), '..', 'fixtures', '5k.png'), 'rb')
702
+ @dummy = Dummy.new
703
+ @dummy.avatar = @file
704
+ end
705
+
706
+ teardown { @file.close }
707
+
708
+ context "and saved" do
709
+ setup do
710
+ object = stub
711
+ @dummy.avatar.stubs(:s3_object).returns(object)
712
+ object.expects(:write).with(anything,
713
+ :content_type => "image/png",
714
+ :acl => :public_read,
715
+ :storage_class => :reduced_redundancy)
716
+ @dummy.save
717
+ end
718
+
719
+ should "succeed" do
720
+ assert true
721
+ end
722
+ end
723
+ end
724
+ end
725
+
726
+ context "with S3 credentials supplied as Pathname" do
727
+ setup do
728
+ ENV['S3_KEY'] = 'pathname_key'
729
+ ENV['S3_BUCKET'] = 'pathname_bucket'
730
+ ENV['S3_SECRET'] = 'pathname_secret'
731
+
732
+ rails_env('test')
733
+
734
+ rebuild_model :storage => :s3,
735
+ :s3_credentials => Pathname.new(fixture_file('s3.yml'))
736
+
737
+ Dummy.delete_all
738
+ @dummy = Dummy.new
739
+ end
740
+
741
+ should "parse the credentials" do
742
+ assert_equal 'pathname_bucket', @dummy.avatar.bucket_name
743
+ assert_equal 'pathname_key', @dummy.avatar.s3_bucket.config.access_key_id
744
+ assert_equal 'pathname_secret', @dummy.avatar.s3_bucket.config.secret_access_key
745
+ end
746
+ end
747
+
748
+ context "with S3 credentials in a YAML file" do
749
+ setup do
750
+ ENV['S3_KEY'] = 'env_key'
751
+ ENV['S3_BUCKET'] = 'env_bucket'
752
+ ENV['S3_SECRET'] = 'env_secret'
753
+
754
+ rails_env('test')
755
+
756
+ rebuild_model :storage => :s3,
757
+ :s3_credentials => File.new(fixture_file('s3.yml'))
758
+
759
+ Dummy.delete_all
760
+
761
+ @dummy = Dummy.new
762
+ end
763
+
764
+ should "run the file through ERB" do
765
+ assert_equal 'env_bucket', @dummy.avatar.bucket_name
766
+ assert_equal 'env_key', @dummy.avatar.s3_bucket.config.access_key_id
767
+ assert_equal 'env_secret', @dummy.avatar.s3_bucket.config.secret_access_key
768
+ end
769
+ end
770
+
771
+ context "S3 Permissions" do
772
+ context "defaults to :public_read" do
773
+ setup do
774
+ rebuild_model :storage => :s3,
775
+ :bucket => "testing",
776
+ :path => ":attachment/:style/:basename.:extension",
777
+ :s3_credentials => {
778
+ 'access_key_id' => "12345",
779
+ 'secret_access_key' => "54321"
780
+ }
781
+ end
782
+
783
+ context "when assigned" do
784
+ setup do
785
+ @file = File.new(fixture_file('5k.png'), 'rb')
786
+ @dummy = Dummy.new
787
+ @dummy.avatar = @file
788
+ end
789
+
790
+ teardown { @file.close }
791
+
792
+ context "and saved" do
793
+ setup do
794
+ object = stub
795
+ @dummy.avatar.stubs(:s3_object).returns(object)
796
+ object.expects(:write).with(anything,
797
+ :content_type => "image/png",
798
+ :acl => :public_read)
799
+ @dummy.save
800
+ end
801
+
802
+ should "succeed" do
803
+ assert true
804
+ end
805
+ end
806
+ end
807
+ end
808
+
809
+ context "string permissions set" do
810
+ setup do
811
+ rebuild_model :storage => :s3,
812
+ :bucket => "testing",
813
+ :path => ":attachment/:style/:basename.:extension",
814
+ :s3_credentials => {
815
+ 'access_key_id' => "12345",
816
+ 'secret_access_key' => "54321"
817
+ },
818
+ :s3_permissions => :private
819
+ end
820
+
821
+ context "when assigned" do
822
+ setup do
823
+ @file = File.new(fixture_file('5k.png'), 'rb')
824
+ @dummy = Dummy.new
825
+ @dummy.avatar = @file
826
+ end
827
+
828
+ teardown { @file.close }
829
+
830
+ context "and saved" do
831
+ setup do
832
+ object = stub
833
+ @dummy.avatar.stubs(:s3_object).returns(object)
834
+ object.expects(:write).with(anything,
835
+ :content_type => "image/png",
836
+ :acl => :private)
837
+ @dummy.save
838
+ end
839
+
840
+ should "succeed" do
841
+ assert true
842
+ end
843
+ end
844
+ end
845
+ end
846
+
847
+ context "hash permissions set" do
848
+ setup do
849
+ rebuild_model :storage => :s3,
850
+ :bucket => "testing",
851
+ :path => ":attachment/:style/:basename.:extension",
852
+ :styles => {
853
+ :thumb => "80x80>"
854
+ },
855
+ :s3_credentials => {
856
+ 'access_key_id' => "12345",
857
+ 'secret_access_key' => "54321"
858
+ },
859
+ :s3_permissions => {
860
+ :original => :private,
861
+ :thumb => :public_read
862
+ }
863
+ end
864
+
865
+ context "when assigned" do
866
+ setup do
867
+ @file = File.new(fixture_file('5k.png'), 'rb')
868
+ @dummy = Dummy.new
869
+ @dummy.avatar = @file
870
+ end
871
+
872
+ teardown { @file.close }
873
+
874
+ context "and saved" do
875
+ setup do
876
+ [:thumb, :original].each do |style|
877
+ object = stub
878
+ @dummy.avatar.stubs(:s3_object).with(style).returns(object)
879
+ object.expects(:write).with(anything,
880
+ :content_type => "image/png",
881
+ :acl => style == :thumb ? :public_read : :private)
882
+ end
883
+ @dummy.save
884
+ end
885
+
886
+ should "succeed" do
887
+ assert true
888
+ end
889
+ end
890
+ end
891
+ end
892
+
893
+ context "proc permission set" do
894
+ setup do
895
+ rebuild_model(
896
+ :storage => :s3,
897
+ :bucket => "testing",
898
+ :path => ":attachment/:style/:basename.:extension",
899
+ :styles => {
900
+ :thumb => "80x80>"
901
+ },
902
+ :s3_credentials => {
903
+ 'access_key_id' => "12345",
904
+ 'secret_access_key' => "54321"
905
+ },
906
+ :s3_permissions => lambda {|attachment, style|
907
+ attachment.instance.private_attachment? && style.to_sym != :thumb ? :private : :public_read
908
+ }
909
+ )
910
+ end
911
+
912
+ context "when assigned" do
913
+ setup do
914
+ @file = File.new(fixture_file('5k.png'), 'rb')
915
+ @dummy = Dummy.new
916
+ @dummy.stubs(:private_attachment? => true)
917
+ @dummy.avatar = @file
918
+ end
919
+
920
+ teardown { @file.close }
921
+
922
+ context "and saved" do
923
+ setup do
924
+ [:thumb, :original].each do |style|
925
+ object = stub
926
+ @dummy.avatar.stubs(:s3_object).with(style).returns(object)
927
+ object.expects(:write).with(anything,
928
+ :content_type => "image/png",
929
+ :acl => style == :thumb ? :public_read : :private)
930
+ end
931
+ @dummy.save
932
+ end
933
+
934
+ should "succeed" do
935
+ assert @dummy.avatar.url().include? "https://"
936
+ assert @dummy.avatar.url(:thumb).include? "http://"
937
+ end
938
+ end
939
+ end
940
+
941
+ end
942
+ end
943
+ end