jmcnevin-paperclip 2.4.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (71) hide show
  1. data/LICENSE +26 -0
  2. data/README.md +414 -0
  3. data/Rakefile +86 -0
  4. data/generators/paperclip/USAGE +5 -0
  5. data/generators/paperclip/paperclip_generator.rb +27 -0
  6. data/generators/paperclip/templates/paperclip_migration.rb.erb +19 -0
  7. data/init.rb +4 -0
  8. data/lib/generators/paperclip/USAGE +8 -0
  9. data/lib/generators/paperclip/paperclip_generator.rb +33 -0
  10. data/lib/generators/paperclip/templates/paperclip_migration.rb.erb +19 -0
  11. data/lib/paperclip.rb +480 -0
  12. data/lib/paperclip/attachment.rb +520 -0
  13. data/lib/paperclip/callback_compatibility.rb +61 -0
  14. data/lib/paperclip/geometry.rb +155 -0
  15. data/lib/paperclip/interpolations.rb +171 -0
  16. data/lib/paperclip/iostream.rb +45 -0
  17. data/lib/paperclip/matchers.rb +33 -0
  18. data/lib/paperclip/matchers/have_attached_file_matcher.rb +57 -0
  19. data/lib/paperclip/matchers/validate_attachment_content_type_matcher.rb +81 -0
  20. data/lib/paperclip/matchers/validate_attachment_presence_matcher.rb +54 -0
  21. data/lib/paperclip/matchers/validate_attachment_size_matcher.rb +95 -0
  22. data/lib/paperclip/missing_attachment_styles.rb +87 -0
  23. data/lib/paperclip/options.rb +78 -0
  24. data/lib/paperclip/processor.rb +58 -0
  25. data/lib/paperclip/railtie.rb +26 -0
  26. data/lib/paperclip/storage.rb +3 -0
  27. data/lib/paperclip/storage/filesystem.rb +81 -0
  28. data/lib/paperclip/storage/fog.rb +163 -0
  29. data/lib/paperclip/storage/s3.rb +270 -0
  30. data/lib/paperclip/style.rb +95 -0
  31. data/lib/paperclip/thumbnail.rb +105 -0
  32. data/lib/paperclip/upfile.rb +62 -0
  33. data/lib/paperclip/version.rb +3 -0
  34. data/lib/tasks/paperclip.rake +101 -0
  35. data/rails/init.rb +2 -0
  36. data/shoulda_macros/paperclip.rb +124 -0
  37. data/test/attachment_test.rb +1161 -0
  38. data/test/database.yml +4 -0
  39. data/test/fixtures/12k.png +0 -0
  40. data/test/fixtures/50x50.png +0 -0
  41. data/test/fixtures/5k.png +0 -0
  42. data/test/fixtures/animated.gif +0 -0
  43. data/test/fixtures/bad.png +1 -0
  44. data/test/fixtures/double spaces in name.png +0 -0
  45. data/test/fixtures/fog.yml +8 -0
  46. data/test/fixtures/s3.yml +8 -0
  47. data/test/fixtures/spaced file.png +0 -0
  48. data/test/fixtures/text.txt +1 -0
  49. data/test/fixtures/twopage.pdf +0 -0
  50. data/test/fixtures/uppercase.PNG +0 -0
  51. data/test/fog_test.rb +192 -0
  52. data/test/geometry_test.rb +206 -0
  53. data/test/helper.rb +158 -0
  54. data/test/integration_test.rb +781 -0
  55. data/test/interpolations_test.rb +202 -0
  56. data/test/iostream_test.rb +71 -0
  57. data/test/matchers/have_attached_file_matcher_test.rb +24 -0
  58. data/test/matchers/validate_attachment_content_type_matcher_test.rb +87 -0
  59. data/test/matchers/validate_attachment_presence_matcher_test.rb +26 -0
  60. data/test/matchers/validate_attachment_size_matcher_test.rb +51 -0
  61. data/test/options_test.rb +75 -0
  62. data/test/paperclip_missing_attachment_styles_test.rb +80 -0
  63. data/test/paperclip_test.rb +340 -0
  64. data/test/processor_test.rb +10 -0
  65. data/test/storage/filesystem_test.rb +56 -0
  66. data/test/storage/s3_live_test.rb +88 -0
  67. data/test/storage/s3_test.rb +689 -0
  68. data/test/style_test.rb +180 -0
  69. data/test/thumbnail_test.rb +383 -0
  70. data/test/upfile_test.rb +53 -0
  71. metadata +294 -0
@@ -0,0 +1,10 @@
1
+ require './test/helper'
2
+
3
+ class ProcessorTest < Test::Unit::TestCase
4
+ should "instantiate and call #make when sent #make to the class" do
5
+ processor = mock
6
+ processor.expects(:make).with()
7
+ Paperclip::Processor.expects(:new).with(:one, :two, :three).returns(processor)
8
+ Paperclip::Processor.make(:one, :two, :three)
9
+ end
10
+ end
@@ -0,0 +1,56 @@
1
+ require './test/helper'
2
+
3
+ class FileSystemTest < Test::Unit::TestCase
4
+ context "Filesystem" do
5
+ setup do
6
+ rebuild_model :styles => { :thumbnail => "25x25#" }
7
+ @dummy = Dummy.create!
8
+
9
+ @dummy.avatar = File.open(File.join(File.dirname(__FILE__), "..", "fixtures", "5k.png"))
10
+ end
11
+
12
+ should "allow file assignment" do
13
+ assert @dummy.save
14
+ end
15
+
16
+ should "store the original" do
17
+ @dummy.save
18
+ assert File.exists?(@dummy.avatar.path)
19
+ end
20
+
21
+ should "store the thumbnail" do
22
+ @dummy.save
23
+ assert File.exists?(@dummy.avatar.path(:thumbnail))
24
+ end
25
+
26
+ should "clean up file objects" do
27
+ File.stubs(:exist?).returns(true)
28
+ Paperclip::Tempfile.any_instance.expects(:close).at_least_once()
29
+ Paperclip::Tempfile.any_instance.expects(:unlink).at_least_once()
30
+
31
+ @dummy.save!
32
+ end
33
+
34
+ context "with file that has space in file name" do
35
+ setup do
36
+ rebuild_model :styles => { :thumbnail => "25x25#" }
37
+ @dummy = Dummy.create!
38
+
39
+ @dummy.avatar = File.open(File.join(File.dirname(__FILE__), "..", "fixtures", "spaced file.png"))
40
+ @dummy.save
41
+ end
42
+
43
+ should "store the file" do
44
+ assert File.exists?(@dummy.avatar.path)
45
+ end
46
+
47
+ should "store the path unescaped" do
48
+ assert_match /\/spaced file\.png/, @dummy.avatar.path
49
+ end
50
+
51
+ should "return an escaped version of URL" do
52
+ assert_match /\/spaced%20file\.png/, @dummy.avatar.url
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,88 @@
1
+ require './test/helper'
2
+ require 'aws/s3'
3
+
4
+ unless ENV["S3_TEST_BUCKET"].blank?
5
+ class S3LiveTest < Test::Unit::TestCase
6
+ context "Using S3 for real, an attachment with S3 storage" do
7
+ setup do
8
+ rebuild_model :styles => { :thumb => "100x100", :square => "32x32#" },
9
+ :storage => :s3,
10
+ :bucket => ENV["S3_TEST_BUCKET"],
11
+ :path => ":class/:attachment/:id/:style.:extension",
12
+ :s3_credentials => File.new(File.join(File.dirname(__FILE__), "..", "s3.yml"))
13
+
14
+ Dummy.delete_all
15
+ @dummy = Dummy.new
16
+ end
17
+
18
+ should "be extended by the S3 module" do
19
+ assert Dummy.new.avatar.is_a?(Paperclip::Storage::S3)
20
+ end
21
+
22
+ context "when assigned" do
23
+ setup do
24
+ @file = File.new(File.join(File.dirname(__FILE__), '..', 'fixtures', '5k.png'), 'rb')
25
+ @dummy.avatar = @file
26
+ end
27
+
28
+ teardown do
29
+ @file.close
30
+ @dummy.destroy
31
+ end
32
+
33
+ should "still return a Tempfile when sent #to_file" do
34
+ assert_equal Paperclip::Tempfile, @dummy.avatar.to_file.class
35
+ end
36
+
37
+ context "and saved" do
38
+ setup do
39
+ @dummy.save
40
+ end
41
+
42
+ should "be on S3" do
43
+ assert true
44
+ end
45
+
46
+ should "generate a tempfile with the right name" do
47
+ file = @dummy.avatar.to_file
48
+ assert_match /^original.*\.png$/, File.basename(file.path)
49
+ end
50
+ end
51
+ end
52
+ end
53
+
54
+ context "An attachment that uses S3 for storage and has spaces in file name" do
55
+ setup do
56
+ rebuild_model :styles => { :thumb => "100x100", :square => "32x32#" },
57
+ :storage => :s3,
58
+ :bucket => ENV["S3_TEST_BUCKET"],
59
+ :s3_credentials => File.new(File.join(File.dirname(__FILE__), "..", "s3.yml"))
60
+
61
+ Dummy.delete_all
62
+ @dummy = Dummy.new
63
+ @dummy.avatar = File.new(File.join(File.dirname(__FILE__), '..', 'fixtures', 'spaced file.png'), 'rb')
64
+ @dummy.save
65
+ end
66
+
67
+ teardown { @dummy.destroy }
68
+
69
+ should "return an unescaped version for path" do
70
+ assert_match /.+\/spaced file\.png/, @dummy.avatar.path
71
+ end
72
+
73
+ should "return an escaped version for url" do
74
+ assert_match /.+\/spaced%20file\.png/, @dummy.avatar.url
75
+ end
76
+
77
+ should "be accessible" do
78
+ assert_match /200 OK/, `curl -I #{@dummy.avatar.url}`
79
+ end
80
+
81
+ should "be destoryable" do
82
+ url = @dummy.avatar.url
83
+ @dummy.destroy
84
+ assert_match /404 Not Found/, `curl -I #{url}`
85
+ end
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,689 @@
1
+ require './test/helper'
2
+ require 'aws/s3'
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
+ context "Parsing S3 credentials" do
12
+ setup do
13
+ @proxy_settings = {:host => "127.0.0.1", :port => 8888, :user => "foo", :password => "bar"}
14
+ AWS::S3::Base.stubs(:establish_connection!)
15
+ rebuild_model :storage => :s3,
16
+ :bucket => "testing",
17
+ :http_proxy => @proxy_settings,
18
+ :s3_credentials => {:not => :important}
19
+
20
+ @dummy = Dummy.new
21
+ @avatar = @dummy.avatar
22
+ end
23
+
24
+ should "get the correct credentials when RAILS_ENV is production" do
25
+ rails_env("production")
26
+ assert_equal({:key => "12345"},
27
+ @avatar.parse_credentials('production' => {:key => '12345'},
28
+ :development => {:key => "54321"}))
29
+ end
30
+
31
+ should "get the correct credentials when RAILS_ENV is development" do
32
+ rails_env("development")
33
+ assert_equal({:key => "54321"},
34
+ @avatar.parse_credentials('production' => {:key => '12345'},
35
+ :development => {:key => "54321"}))
36
+ end
37
+
38
+ should "return the argument if the key does not exist" do
39
+ rails_env("not really an env")
40
+ assert_equal({:test => "12345"}, @avatar.parse_credentials(:test => "12345"))
41
+ end
42
+
43
+ should "support HTTP proxy settings" do
44
+ rails_env("development")
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
+
52
+ end
53
+
54
+ context "" do
55
+ setup do
56
+ AWS::S3::Base.stubs(:establish_connection!)
57
+ rebuild_model :storage => :s3,
58
+ :s3_credentials => {},
59
+ :bucket => "bucket",
60
+ :path => ":attachment/:basename.:extension",
61
+ :url => ":s3_path_url"
62
+ @dummy = Dummy.new
63
+ @dummy.avatar = StringIO.new(".")
64
+ end
65
+
66
+ should "return a url based on an S3 path" do
67
+ assert_match %r{^http://s3.amazonaws.com/bucket/avatars/stringio.txt}, @dummy.avatar.url
68
+ end
69
+ end
70
+
71
+ context "s3_host_name" do
72
+ setup do
73
+ AWS::S3::Base.stubs(:establish_connection!)
74
+ rebuild_model :storage => :s3,
75
+ :s3_credentials => {},
76
+ :bucket => "bucket",
77
+ :path => ":attachment/:basename.:extension",
78
+ :s3_host_name => "s3-ap-northeast-1.amazonaws.com"
79
+ @dummy = Dummy.new
80
+ @dummy.avatar = StringIO.new(".")
81
+ end
82
+
83
+ should "return a url based on an :s3_host_name path" do
84
+ assert_match %r{^http://s3-ap-northeast-1.amazonaws.com/bucket/avatars/stringio.txt}, @dummy.avatar.url
85
+ end
86
+ end
87
+
88
+ context "An attachment that uses S3 for storage and has styles that return different file types" do
89
+ setup do
90
+ AWS::S3::Base.stubs(:establish_connection!)
91
+ rebuild_model :styles => { :large => ['500x500#', :jpg] },
92
+ :storage => :s3,
93
+ :bucket => "bucket",
94
+ :path => ":attachment/:basename.:extension",
95
+ :s3_credentials => {
96
+ 'access_key_id' => "12345",
97
+ 'secret_access_key' => "54321"
98
+ }
99
+
100
+ @dummy = Dummy.new
101
+ @dummy.avatar = File.new(File.join(File.dirname(__FILE__), '..', 'fixtures', '5k.png'), 'rb')
102
+ end
103
+
104
+ should "return a url containing the correct original file mime type" do
105
+ assert_match /.+\/5k.png/, @dummy.avatar.url
106
+ end
107
+
108
+ should "return a url containing the correct processed file mime type" do
109
+ assert_match /.+\/5k.jpg/, @dummy.avatar.url(:large)
110
+ end
111
+ end
112
+
113
+ context "An attachment that uses S3 for storage and has spaces in file name" do
114
+ setup do
115
+ AWS::S3::Base.stubs(:establish_connection!)
116
+ rebuild_model :styles => { :large => ['500x500#', :jpg] },
117
+ :storage => :s3,
118
+ :bucket => "bucket",
119
+ :s3_credentials => {
120
+ 'access_key_id' => "12345",
121
+ 'secret_access_key' => "54321"
122
+ }
123
+
124
+ @dummy = Dummy.new
125
+ @dummy.avatar = File.new(File.join(File.dirname(__FILE__), '..', 'fixtures', 'spaced file.png'), 'rb')
126
+ end
127
+
128
+ should "return an unescaped version for path" do
129
+ assert_match /.+\/spaced file\.png/, @dummy.avatar.path
130
+ end
131
+
132
+ should "return an escaped version for url" do
133
+ assert_match /.+\/spaced%20file\.png/, @dummy.avatar.url
134
+ end
135
+ end
136
+
137
+ context "" do
138
+ setup do
139
+ AWS::S3::Base.stubs(:establish_connection!)
140
+ rebuild_model :storage => :s3,
141
+ :s3_credentials => {},
142
+ :bucket => "bucket",
143
+ :path => ":attachment/:basename.:extension",
144
+ :url => ":s3_domain_url"
145
+ @dummy = Dummy.new
146
+ @dummy.avatar = StringIO.new(".")
147
+ end
148
+
149
+ should "return a url based on an S3 subdomain" do
150
+ assert_match %r{^http://bucket.s3.amazonaws.com/avatars/stringio.txt}, @dummy.avatar.url
151
+ end
152
+ end
153
+
154
+ context "" do
155
+ setup do
156
+ AWS::S3::Base.stubs(:establish_connection!)
157
+ rebuild_model :storage => :s3,
158
+ :s3_credentials => {
159
+ :production => { :bucket => "prod_bucket" },
160
+ :development => { :bucket => "dev_bucket" }
161
+ },
162
+ :s3_host_alias => "something.something.com",
163
+ :path => ":attachment/:basename.:extension",
164
+ :url => ":s3_alias_url"
165
+ @dummy = Dummy.new
166
+ @dummy.avatar = StringIO.new(".")
167
+ end
168
+
169
+ should "return a url based on the host_alias" do
170
+ assert_match %r{^http://something.something.com/avatars/stringio.txt}, @dummy.avatar.url
171
+ end
172
+ end
173
+
174
+ context "generating a url with a proc as the host alias" do
175
+ setup do
176
+ AWS::S3::Base.stubs(:establish_connection!)
177
+ rebuild_model :storage => :s3,
178
+ :s3_credentials => { :bucket => "prod_bucket" },
179
+ :s3_host_alias => Proc.new{|atch| "cdn#{atch.instance.counter % 4}.example.com"},
180
+ :path => ":attachment/:basename.:extension",
181
+ :url => ":s3_alias_url"
182
+ Dummy.class_eval do
183
+ def counter
184
+ @counter ||= 0
185
+ @counter += 1
186
+ @counter
187
+ end
188
+ end
189
+ @dummy = Dummy.new
190
+ @dummy.avatar = StringIO.new(".")
191
+ end
192
+
193
+ should "return a url based on the host_alias" do
194
+ assert_match %r{^http://cdn1.example.com/avatars/stringio.txt}, @dummy.avatar.url
195
+ assert_match %r{^http://cdn2.example.com/avatars/stringio.txt}, @dummy.avatar.url
196
+ end
197
+
198
+ should "still return the bucket name" do
199
+ assert_equal "prod_bucket", @dummy.avatar.bucket_name
200
+ end
201
+
202
+ end
203
+
204
+ context "" do
205
+ setup do
206
+ AWS::S3::Base.stubs(:establish_connection!)
207
+ rebuild_model :storage => :s3,
208
+ :s3_credentials => {},
209
+ :bucket => "bucket",
210
+ :path => ":attachment/:basename.:extension",
211
+ :url => ":asset_host"
212
+ @dummy = Dummy.new
213
+ @dummy.avatar = StringIO.new(".")
214
+ end
215
+
216
+ should "return a relative URL for Rails to calculate assets host" do
217
+ assert_match %r{^avatars/stringio\.txt}, @dummy.avatar.url
218
+ end
219
+ end
220
+
221
+ context "Generating a secure url with an expiration" do
222
+ setup do
223
+ AWS::S3::Base.stubs(:establish_connection!)
224
+ rebuild_model :storage => :s3,
225
+ :s3_credentials => {
226
+ :production => { :bucket => "prod_bucket" },
227
+ :development => { :bucket => "dev_bucket" }
228
+ },
229
+ :s3_host_alias => "something.something.com",
230
+ :s3_permissions => "private",
231
+ :path => ":attachment/:basename.:extension",
232
+ :url => ":s3_alias_url"
233
+
234
+ rails_env("production")
235
+
236
+ @dummy = Dummy.new
237
+ @dummy.avatar = StringIO.new(".")
238
+
239
+ AWS::S3::S3Object.expects(:url_for).with("avatars/stringio.txt", "prod_bucket", { :expires_in => 3600, :use_ssl => true })
240
+
241
+ @dummy.avatar.expiring_url
242
+ end
243
+
244
+ should "should succeed" do
245
+ assert true
246
+ end
247
+ end
248
+
249
+ context "Generating a url with an expiration" do
250
+ setup do
251
+ AWS::S3::Base.stubs(:establish_connection!)
252
+ rebuild_model :storage => :s3,
253
+ :s3_credentials => {
254
+ :production => { :bucket => "prod_bucket" },
255
+ :development => { :bucket => "dev_bucket" }
256
+ },
257
+ :s3_permissions => :private,
258
+ :s3_host_alias => "something.something.com",
259
+ :path => ":attachment/:style/:basename.:extension",
260
+ :url => ":s3_alias_url"
261
+
262
+ rails_env("production")
263
+
264
+ @dummy = Dummy.new
265
+ @dummy.avatar = StringIO.new(".")
266
+
267
+ AWS::S3::S3Object.expects(:url_for).with("avatars/original/stringio.txt", "prod_bucket", { :expires_in => 3600, :use_ssl => true })
268
+ @dummy.avatar.expiring_url
269
+
270
+ AWS::S3::S3Object.expects(:url_for).with("avatars/thumb/stringio.txt", "prod_bucket", { :expires_in => 1800, :use_ssl => true })
271
+ @dummy.avatar.expiring_url(1800, :thumb)
272
+ end
273
+
274
+ should "should succeed" do
275
+ assert true
276
+ end
277
+ end
278
+
279
+ context "Parsing S3 credentials with a bucket in them" do
280
+ setup do
281
+ AWS::S3::Base.stubs(:establish_connection!)
282
+ rebuild_model :storage => :s3,
283
+ :s3_credentials => {
284
+ :production => { :bucket => "prod_bucket" },
285
+ :development => { :bucket => "dev_bucket" }
286
+ }
287
+ @dummy = Dummy.new
288
+ end
289
+
290
+ should "get the right bucket in production" do
291
+ rails_env("production")
292
+ assert_equal "prod_bucket", @dummy.avatar.bucket_name
293
+ end
294
+
295
+ should "get the right bucket in development" do
296
+ rails_env("development")
297
+ assert_equal "dev_bucket", @dummy.avatar.bucket_name
298
+ end
299
+ end
300
+
301
+ context "Parsing S3 credentials with a s3_host_name in them" do
302
+ setup do
303
+ AWS::S3::Base.stubs(:establish_connection!)
304
+ rebuild_model :storage => :s3,
305
+ :s3_credentials => {
306
+ :production => { :s3_host_name => "s3-world-end.amazonaws.com" },
307
+ :development => { :s3_host_name => "s3-ap-northeast-1.amazonaws.com" }
308
+ }
309
+ @dummy = Dummy.new
310
+ end
311
+
312
+ should "get the right s3_host_name in production" do
313
+ rails_env("production")
314
+ assert_match %r{^s3-world-end.amazonaws.com}, @dummy.avatar.s3_host_name
315
+ end
316
+
317
+ should "get the right s3_host_name in development" do
318
+ rails_env("development")
319
+ assert_match %r{^s3-ap-northeast-1.amazonaws.com}, @dummy.avatar.s3_host_name
320
+ end
321
+
322
+ should "get the right s3_host_name if the key does not exist" do
323
+ rails_env("test")
324
+ assert_match %r{^s3.amazonaws.com}, @dummy.avatar.s3_host_name
325
+ end
326
+ end
327
+
328
+ context "An attachment with S3 storage" do
329
+ setup do
330
+ rebuild_model :storage => :s3,
331
+ :bucket => "testing",
332
+ :path => ":attachment/:style/:basename.:extension",
333
+ :s3_credentials => {
334
+ 'access_key_id' => "12345",
335
+ 'secret_access_key' => "54321"
336
+ }
337
+ end
338
+
339
+ should "be extended by the S3 module" do
340
+ assert Dummy.new.avatar.is_a?(Paperclip::Storage::S3)
341
+ end
342
+
343
+ should "not be extended by the Filesystem module" do
344
+ assert ! Dummy.new.avatar.is_a?(Paperclip::Storage::Filesystem)
345
+ end
346
+
347
+ context "when assigned" do
348
+ setup do
349
+ @file = File.new(File.join(File.dirname(__FILE__), '..', 'fixtures', '5k.png'), 'rb')
350
+ @dummy = Dummy.new
351
+ @dummy.avatar = @file
352
+ end
353
+
354
+ teardown { @file.close }
355
+
356
+ should "not get a bucket to get a URL" do
357
+ @dummy.avatar.expects(:s3).never
358
+ @dummy.avatar.expects(:s3_bucket).never
359
+ assert_match %r{^http://s3\.amazonaws\.com/testing/avatars/original/5k\.png}, @dummy.avatar.url
360
+ end
361
+
362
+ context "and saved" do
363
+ setup do
364
+ AWS::S3::S3Object.stubs(:store).with(@dummy.avatar.path, anything, 'testing', :content_type => 'image/png', :access => :public_read)
365
+ @dummy.save
366
+ end
367
+
368
+ should "succeed" do
369
+ assert true
370
+ end
371
+ end
372
+
373
+ should "delete tempfiles" do
374
+ AWS::S3::S3Object.stubs(:store).with(@dummy.avatar.path, anything, 'testing', :content_type => 'image/png', :access => :public_read)
375
+ File.stubs(:exist?).returns(true)
376
+ Paperclip::Tempfile.any_instance.expects(:close).at_least_once()
377
+ Paperclip::Tempfile.any_instance.expects(:unlink).at_least_once()
378
+
379
+ @dummy.save!
380
+ end
381
+
382
+ context "and saved without a bucket" do
383
+ setup do
384
+ class AWS::S3::NoSuchBucket < AWS::S3::ResponseError
385
+ # Force the class to be created as a proper subclass of ResponseError thanks to AWS::S3's autocreation of exceptions
386
+ end
387
+ AWS::S3::Bucket.expects(:create).with("testing")
388
+ AWS::S3::S3Object.stubs(:store).raises(AWS::S3::NoSuchBucket.new(:message, :response)).then.returns(true)
389
+ @dummy.save
390
+ end
391
+
392
+ should "succeed" do
393
+ assert true
394
+ end
395
+ end
396
+
397
+ context "and remove" do
398
+ setup do
399
+ AWS::S3::S3Object.stubs(:exists?).returns(true)
400
+ AWS::S3::S3Object.stubs(:delete)
401
+ @dummy.destroy_attached_files
402
+ end
403
+
404
+ should "succeed" do
405
+ assert true
406
+ end
407
+ end
408
+ end
409
+ end
410
+
411
+ context "An attachment with S3 storage and bucket defined as a Proc" do
412
+ setup do
413
+ AWS::S3::Base.stubs(:establish_connection!)
414
+ rebuild_model :storage => :s3,
415
+ :bucket => lambda { |attachment| "bucket_#{attachment.instance.other}" },
416
+ :s3_credentials => {:not => :important}
417
+ end
418
+
419
+ should "get the right bucket name" do
420
+ assert "bucket_a", Dummy.new(:other => 'a').avatar.bucket_name
421
+ assert "bucket_b", Dummy.new(:other => 'b').avatar.bucket_name
422
+ end
423
+ end
424
+
425
+ context "An attachment with S3 storage and specific s3 headers set" do
426
+ setup do
427
+ AWS::S3::Base.stubs(:establish_connection!)
428
+ rebuild_model :storage => :s3,
429
+ :bucket => "testing",
430
+ :path => ":attachment/:style/:basename.:extension",
431
+ :s3_credentials => {
432
+ 'access_key_id' => "12345",
433
+ 'secret_access_key' => "54321"
434
+ },
435
+ :s3_headers => {'Cache-Control' => 'max-age=31557600'}
436
+ end
437
+
438
+ context "when assigned" do
439
+ setup do
440
+ @file = File.new(File.join(File.dirname(__FILE__), '..', 'fixtures', '5k.png'), 'rb')
441
+ @dummy = Dummy.new
442
+ @dummy.avatar = @file
443
+ end
444
+
445
+ teardown { @file.close }
446
+
447
+ context "and saved" do
448
+ setup do
449
+ AWS::S3::Base.stubs(:establish_connection!)
450
+ AWS::S3::S3Object.stubs(:store).with(@dummy.avatar.path,
451
+ anything,
452
+ 'testing',
453
+ :content_type => 'image/png',
454
+ :access => :public_read,
455
+ 'Cache-Control' => 'max-age=31557600')
456
+ @dummy.save
457
+ end
458
+
459
+ should "succeed" do
460
+ assert true
461
+ end
462
+ end
463
+ end
464
+ end
465
+
466
+ context "with S3 credentials supplied as Pathname" do
467
+ setup do
468
+ ENV['S3_KEY'] = 'pathname_key'
469
+ ENV['S3_BUCKET'] = 'pathname_bucket'
470
+ ENV['S3_SECRET'] = 'pathname_secret'
471
+
472
+ rails_env('test')
473
+
474
+ rebuild_model :storage => :s3,
475
+ :s3_credentials => Pathname.new(File.join(File.dirname(__FILE__))).join("../fixtures/s3.yml")
476
+
477
+ Dummy.delete_all
478
+ @dummy = Dummy.new
479
+ end
480
+
481
+ should "parse the credentials" do
482
+ assert_equal 'pathname_bucket', @dummy.avatar.bucket_name
483
+ assert_equal 'pathname_key', AWS::S3::Base.connection.options[:access_key_id]
484
+ assert_equal 'pathname_secret', AWS::S3::Base.connection.options[:secret_access_key]
485
+ end
486
+ end
487
+
488
+ context "with S3 credentials in a YAML file" do
489
+ setup do
490
+ ENV['S3_KEY'] = 'env_key'
491
+ ENV['S3_BUCKET'] = 'env_bucket'
492
+ ENV['S3_SECRET'] = 'env_secret'
493
+
494
+ rails_env('test')
495
+
496
+ rebuild_model :storage => :s3,
497
+ :s3_credentials => File.new(File.join(File.dirname(__FILE__), "../fixtures/s3.yml"))
498
+
499
+ Dummy.delete_all
500
+
501
+ @dummy = Dummy.new
502
+ end
503
+
504
+ should "run the file through ERB" do
505
+ assert_equal 'env_bucket', @dummy.avatar.bucket_name
506
+ assert_equal 'env_key', AWS::S3::Base.connection.options[:access_key_id]
507
+ assert_equal 'env_secret', AWS::S3::Base.connection.options[:secret_access_key]
508
+ end
509
+ end
510
+
511
+ context "S3 Permissions" do
512
+ context "defaults to :public_read" do
513
+ setup do
514
+ rebuild_model :storage => :s3,
515
+ :bucket => "testing",
516
+ :path => ":attachment/:style/:basename.:extension",
517
+ :s3_credentials => {
518
+ 'access_key_id' => "12345",
519
+ 'secret_access_key' => "54321"
520
+ }
521
+ end
522
+
523
+ context "when assigned" do
524
+ setup do
525
+ @file = File.new(File.join(File.dirname(__FILE__), '..', 'fixtures', '5k.png'), 'rb')
526
+ @dummy = Dummy.new
527
+ @dummy.avatar = @file
528
+ end
529
+
530
+ teardown { @file.close }
531
+
532
+ context "and saved" do
533
+ setup do
534
+ AWS::S3::Base.stubs(:establish_connection!)
535
+ AWS::S3::S3Object.expects(:store).with(@dummy.avatar.path,
536
+ anything,
537
+ 'testing',
538
+ :content_type => 'image/png',
539
+ :access => :public_read)
540
+ @dummy.save
541
+ end
542
+
543
+ should "succeed" do
544
+ assert true
545
+ end
546
+ end
547
+ end
548
+ end
549
+
550
+ context "string permissions set" do
551
+ setup do
552
+ rebuild_model :storage => :s3,
553
+ :bucket => "testing",
554
+ :path => ":attachment/:style/:basename.:extension",
555
+ :s3_credentials => {
556
+ 'access_key_id' => "12345",
557
+ 'secret_access_key' => "54321"
558
+ },
559
+ :s3_permissions => :private
560
+ end
561
+
562
+ context "when assigned" do
563
+ setup do
564
+ @file = File.new(File.join(File.dirname(__FILE__), '..', 'fixtures', '5k.png'), 'rb')
565
+ @dummy = Dummy.new
566
+ @dummy.avatar = @file
567
+ end
568
+
569
+ teardown { @file.close }
570
+
571
+ context "and saved" do
572
+ setup do
573
+ AWS::S3::Base.stubs(:establish_connection!)
574
+ AWS::S3::S3Object.expects(:store).with(@dummy.avatar.path,
575
+ anything,
576
+ 'testing',
577
+ :content_type => 'image/png',
578
+ :access => :private)
579
+ @dummy.save
580
+ end
581
+
582
+ should "succeed" do
583
+ assert true
584
+ end
585
+ end
586
+ end
587
+ end
588
+
589
+ context "hash permissions set" do
590
+ setup do
591
+ rebuild_model :storage => :s3,
592
+ :bucket => "testing",
593
+ :path => ":attachment/:style/:basename.:extension",
594
+ :styles => {
595
+ :thumb => "80x80>"
596
+ },
597
+ :s3_credentials => {
598
+ 'access_key_id' => "12345",
599
+ 'secret_access_key' => "54321"
600
+ },
601
+ :s3_permissions => {
602
+ :original => :private,
603
+ :thumb => :public_read
604
+ }
605
+ end
606
+
607
+ context "when assigned" do
608
+ setup do
609
+ @file = File.new(File.join(File.dirname(__FILE__), '..', 'fixtures', '5k.png'), 'rb')
610
+ @dummy = Dummy.new
611
+ @dummy.avatar = @file
612
+ end
613
+
614
+ teardown { @file.close }
615
+
616
+ context "and saved" do
617
+ setup do
618
+ AWS::S3::Base.stubs(:establish_connection!)
619
+ [:thumb, :original].each do |style|
620
+ AWS::S3::S3Object.expects(:store).with("avatars/#{style}/5k.png",
621
+ anything,
622
+ 'testing',
623
+ :content_type => 'image/png',
624
+ :access => style == :thumb ? :public_read : :private)
625
+ end
626
+ @dummy.save
627
+ end
628
+
629
+ should "succeed" do
630
+ assert true
631
+ end
632
+ end
633
+ end
634
+ end
635
+
636
+ context "proc permission set" do
637
+ setup do
638
+ rebuild_model(
639
+ :storage => :s3,
640
+ :bucket => "testing",
641
+ :path => ":attachment/:style/:basename.:extension",
642
+ :styles => {
643
+ :thumb => "80x80>"
644
+ },
645
+ :s3_credentials => {
646
+ 'access_key_id' => "12345",
647
+ 'secret_access_key' => "54321"
648
+ },
649
+ :s3_permissions => lambda {|attachment, style|
650
+ attachment.instance.private_attachment? && style.to_sym != :thumb ? :private : :public_read
651
+ }
652
+ )
653
+ end
654
+
655
+ context "when assigned" do
656
+ setup do
657
+ @file = File.new(File.join(File.dirname(__FILE__), '..', 'fixtures', '5k.png'), 'rb')
658
+ @dummy = Dummy.new
659
+ @dummy.stubs(:private_attachment? => true)
660
+ @dummy.avatar = @file
661
+ end
662
+
663
+ teardown { @file.close }
664
+
665
+ context "and saved" do
666
+ setup do
667
+ AWS::S3::Base.stubs(:establish_connection!)
668
+ [:thumb, :original].each do |style|
669
+ AWS::S3::S3Object.expects(:store).with(
670
+ "avatars/#{style}/5k.png",
671
+ anything,
672
+ 'testing',
673
+ :content_type => 'image/png',
674
+ :access => style == :thumb ? :public_read : :private
675
+ )
676
+ end
677
+ @dummy.save
678
+ end
679
+
680
+ should "succeed" do
681
+ assert @dummy.avatar.url().include? "https://"
682
+ assert @dummy.avatar.url(:thumb).include? "http://"
683
+ end
684
+ end
685
+ end
686
+
687
+ end
688
+ end
689
+ end