cloudfuji_paperclip 2.4.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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