paperclip-cloudfiles 2.3.1.1.0

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 (49) hide show
  1. data/LICENSE +26 -0
  2. data/README.rdoc +176 -0
  3. data/Rakefile +105 -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 +1 -0
  8. data/lib/paperclip.rb +356 -0
  9. data/lib/paperclip/attachment.rb +414 -0
  10. data/lib/paperclip/callback_compatability.rb +33 -0
  11. data/lib/paperclip/geometry.rb +115 -0
  12. data/lib/paperclip/interpolations.rb +108 -0
  13. data/lib/paperclip/iostream.rb +59 -0
  14. data/lib/paperclip/matchers.rb +4 -0
  15. data/lib/paperclip/matchers/have_attached_file_matcher.rb +49 -0
  16. data/lib/paperclip/matchers/validate_attachment_content_type_matcher.rb +65 -0
  17. data/lib/paperclip/matchers/validate_attachment_presence_matcher.rb +48 -0
  18. data/lib/paperclip/matchers/validate_attachment_size_matcher.rb +85 -0
  19. data/lib/paperclip/processor.rb +49 -0
  20. data/lib/paperclip/storage.rb +369 -0
  21. data/lib/paperclip/thumbnail.rb +73 -0
  22. data/lib/paperclip/upfile.rb +49 -0
  23. data/shoulda_macros/paperclip.rb +117 -0
  24. data/tasks/paperclip_tasks.rake +79 -0
  25. data/test/attachment_test.rb +780 -0
  26. data/test/cloudfiles.yml +13 -0
  27. data/test/database.yml +4 -0
  28. data/test/fixtures/12k.png +0 -0
  29. data/test/fixtures/50x50.png +0 -0
  30. data/test/fixtures/5k.png +0 -0
  31. data/test/fixtures/bad.png +1 -0
  32. data/test/fixtures/s3.yml +8 -0
  33. data/test/fixtures/text.txt +0 -0
  34. data/test/fixtures/twopage.pdf +0 -0
  35. data/test/geometry_test.rb +177 -0
  36. data/test/helper.rb +111 -0
  37. data/test/integration_test.rb +483 -0
  38. data/test/interpolations_test.rb +124 -0
  39. data/test/iostream_test.rb +78 -0
  40. data/test/matchers/have_attached_file_matcher_test.rb +21 -0
  41. data/test/matchers/validate_attachment_content_type_matcher_test.rb +31 -0
  42. data/test/matchers/validate_attachment_presence_matcher_test.rb +23 -0
  43. data/test/matchers/validate_attachment_size_matcher_test.rb +51 -0
  44. data/test/paperclip_test.rb +319 -0
  45. data/test/processor_test.rb +10 -0
  46. data/test/storage_test.rb +549 -0
  47. data/test/thumbnail_test.rb +227 -0
  48. data/test/upfile_test.rb +28 -0
  49. metadata +175 -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,549 @@
1
+ require 'test/helper'
2
+ require 'aws/s3'
3
+
4
+ class StorageTest < Test::Unit::TestCase
5
+ def rails_env(env)
6
+ silence_warnings do
7
+ Object.const_set(:RAILS_ENV, env)
8
+ end
9
+ end
10
+
11
+ context "Parsing S3 credentials" do
12
+ setup do
13
+ AWS::S3::Base.stubs(:establish_connection!)
14
+ rebuild_model :storage => :s3,
15
+ :bucket => "testing",
16
+ :s3_credentials => {:not => :important}
17
+
18
+ @dummy = Dummy.new
19
+ @avatar = @dummy.avatar
20
+
21
+ @current_env = RAILS_ENV
22
+ end
23
+
24
+ teardown do
25
+ rails_env(@current_env)
26
+ end
27
+
28
+ should "get the correct credentials when RAILS_ENV is production" do
29
+ rails_env("production")
30
+ assert_equal({:key => "12345"},
31
+ @avatar.parse_credentials('production' => {:key => '12345'},
32
+ :development => {:key => "54321"}))
33
+ end
34
+
35
+ should "get the correct credentials when RAILS_ENV is development" do
36
+ rails_env("development")
37
+ assert_equal({:key => "54321"},
38
+ @avatar.parse_credentials('production' => {:key => '12345'},
39
+ :development => {:key => "54321"}))
40
+ end
41
+
42
+ should "return the argument if the key does not exist" do
43
+ rails_env("not really an env")
44
+ assert_equal({:test => "12345"}, @avatar.parse_credentials(:test => "12345"))
45
+ end
46
+ end
47
+
48
+ context "Parsing Cloud Files credentials" do
49
+ setup do
50
+ CloudFiles::Connection.stubs(:new).returns(true)
51
+
52
+ rebuild_model :storage => :cloud_files,
53
+ :bucket => "testing",
54
+ :cloudfiles_credentials => {:not => :important}
55
+
56
+
57
+ @dummy = Dummy.new
58
+ @avatar = @dummy.avatar
59
+ @current_env = RAILS_ENV
60
+ end
61
+
62
+ teardown do
63
+ Object.const_set("RAILS_ENV", @current_env)
64
+ end
65
+
66
+ should "get the correct credentials when RAILS_ENV is production" do
67
+ Object.const_set('RAILS_ENV', "production")
68
+ assert_equal({:username => "minter"},
69
+ @avatar.parse_credentials('production' => {:username => 'minter'},
70
+ :development => {:username => "mcornick"}))
71
+ end
72
+
73
+ should "get the correct credentials when RAILS_ENV is development" do
74
+ Object.const_set('RAILS_ENV', "development")
75
+ assert_equal({:key => "mcornick"},
76
+ @avatar.parse_credentials('production' => {:key => 'minter'},
77
+ :development => {:key => "mcornick"}))
78
+ end
79
+
80
+ should "return the argument if the key does not exist" do
81
+ Object.const_set('RAILS_ENV', "not really an env")
82
+ assert_equal({:test => "minter"}, @avatar.parse_credentials(:test => "minter"))
83
+ end
84
+ end
85
+
86
+
87
+ context "" do
88
+ setup do
89
+ AWS::S3::Base.stubs(:establish_connection!)
90
+ rebuild_model :storage => :s3,
91
+ :s3_credentials => {},
92
+ :bucket => "bucket",
93
+ :path => ":attachment/:basename.:extension",
94
+ :url => ":s3_path_url"
95
+ @dummy = Dummy.new
96
+ @dummy.avatar = StringIO.new(".")
97
+ end
98
+
99
+ should "return a url based on an S3 path" do
100
+ assert_match %r{^http://s3.amazonaws.com/bucket/avatars/stringio.txt}, @dummy.avatar.url
101
+ end
102
+ end
103
+ c0045182.cdn.cloudfiles.rackspacecloud.com
104
+ context "" do
105
+ setup do
106
+ container = mock
107
+ container.stubs(:make_public).returns(true)
108
+ container.stubs(:public_url).returns('http://c0010181.cdn.cloudfiles.rackspacecloud.com/avatars/stringio.txt')
109
+ container.stubs(:cdn_url).returns('http://c0010181.cdn.cloudfiles.rackspacecloud.com')
110
+ connection = mock
111
+ connection.stubs(:create_container).returns(container)
112
+ CloudFiles::Connection.expects(:new).returns(connection)
113
+
114
+ rebuild_model :storage => :cloud_files,
115
+ :cloudfiles_credentials => {},
116
+ :container => "container",
117
+ :path => ":attachment/:basename.:extension"
118
+ @dummy = Dummy.new
119
+ @dummy.avatar = StringIO.new(".")
120
+ end
121
+
122
+ should "return a url based on an Cloud Files path" do
123
+ assert_match %r{^http://c0010181.cdn.cloudfiles.rackspacecloud.com/avatars/stringio.txt}, @dummy.avatar.url
124
+ end
125
+ end
126
+
127
+
128
+ context "" do
129
+ setup do
130
+ AWS::S3::Base.stubs(:establish_connection!)
131
+ rebuild_model :storage => :s3,
132
+ :s3_credentials => {},
133
+ :bucket => "bucket",
134
+ :path => ":attachment/:basename.:extension",
135
+ :url => ":s3_domain_url"
136
+ @dummy = Dummy.new
137
+ @dummy.avatar = StringIO.new(".")
138
+ end
139
+
140
+ should "return a url based on an S3 subdomain" do
141
+ assert_match %r{^http://bucket.s3.amazonaws.com/avatars/stringio.txt}, @dummy.avatar.url
142
+ end
143
+ end
144
+
145
+ context "" do
146
+ setup do
147
+ AWS::S3::Base.stubs(:establish_connection!)
148
+ rebuild_model :storage => :s3,
149
+ :s3_credentials => {
150
+ :production => { :bucket => "prod_bucket" },
151
+ :development => { :bucket => "dev_bucket" }
152
+ },
153
+ :s3_host_alias => "something.something.com",
154
+ :path => ":attachment/:basename.:extension",
155
+ :url => ":s3_alias_url"
156
+ @dummy = Dummy.new
157
+ @dummy.avatar = StringIO.new(".")
158
+ end
159
+
160
+ should "return a url based on the host_alias" do
161
+ assert_match %r{^http://something.something.com/avatars/stringio.txt}, @dummy.avatar.url
162
+ end
163
+ end
164
+
165
+ context "Generating a url with an expiration" do
166
+ setup do
167
+ AWS::S3::Base.stubs(:establish_connection!)
168
+ rebuild_model :storage => :s3,
169
+ :s3_credentials => {
170
+ :production => { :bucket => "prod_bucket" },
171
+ :development => { :bucket => "dev_bucket" }
172
+ },
173
+ :s3_host_alias => "something.something.com",
174
+ :path => ":attachment/:basename.:extension",
175
+ :url => ":s3_alias_url"
176
+
177
+ rails_env("production")
178
+
179
+ @dummy = Dummy.new
180
+ @dummy.avatar = StringIO.new(".")
181
+
182
+ AWS::S3::S3Object.expects(:url_for).with("avatars/stringio.txt", "prod_bucket", { :expires_in => 3600 })
183
+
184
+ @dummy.avatar.expiring_url
185
+ end
186
+
187
+ should "should succeed" do
188
+ assert true
189
+ end
190
+ end
191
+
192
+ context "Parsing S3 credentials with a bucket in them" do
193
+ setup do
194
+ AWS::S3::Base.stubs(:establish_connection!)
195
+ rebuild_model :storage => :s3,
196
+ :s3_credentials => {
197
+ :production => { :bucket => "prod_bucket" },
198
+ :development => { :bucket => "dev_bucket" }
199
+ }
200
+ @dummy = Dummy.new
201
+ @old_env = RAILS_ENV
202
+ end
203
+
204
+ teardown{ rails_env(@old_env) }
205
+
206
+ should "get the right bucket in production" do
207
+ rails_env("production")
208
+ assert_equal "prod_bucket", @dummy.avatar.bucket_name
209
+ end
210
+
211
+ should "get the right bucket in development" do
212
+ rails_env("development")
213
+ assert_equal "dev_bucket", @dummy.avatar.bucket_name
214
+ end
215
+ end
216
+
217
+ context "Parsing Cloud Files credentials with a container in them" do
218
+ setup do
219
+ #CloudFiles::Connection.expects(:new).returns(true)
220
+ #CloudFiles::Connection.any_instance.stubs(:create_container).returns(true)
221
+ rebuild_model :storage => :cloud_files,
222
+ :cloudfiles_credentials => {
223
+ :production => { :container => "prod_container" },
224
+ :development => { :container => "dev_container" }
225
+ }
226
+ @dummy = Dummy.new
227
+ @old_env = RAILS_ENV
228
+ end
229
+
230
+ teardown{ Object.const_set("RAILS_ENV", @old_env) }
231
+
232
+ should "get the right container in production" do
233
+ Object.const_set("RAILS_ENV", "production")
234
+ assert_equal "prod_container", @dummy.avatar.container_name
235
+ end
236
+
237
+ should "get the right bucket in development" do
238
+ Object.const_set("RAILS_ENV", "development")
239
+ assert_equal "dev_container", @dummy.avatar.container_name
240
+ end
241
+ end
242
+
243
+
244
+ context "An attachment with S3 storage" do
245
+ setup do
246
+ rebuild_model :storage => :s3,
247
+ :bucket => "testing",
248
+ :path => ":attachment/:style/:basename.:extension",
249
+ :s3_credentials => {
250
+ 'access_key_id' => "12345",
251
+ 'secret_access_key' => "54321"
252
+ }
253
+ end
254
+
255
+ should "be extended by the S3 module" do
256
+ assert Dummy.new.avatar.is_a?(Paperclip::Storage::S3)
257
+ end
258
+
259
+ should "not be extended by the Filesystem module" do
260
+ assert ! Dummy.new.avatar.is_a?(Paperclip::Storage::Filesystem)
261
+ end
262
+
263
+ context "when assigned" do
264
+ setup do
265
+ @file = File.new(File.join(File.dirname(__FILE__), 'fixtures', '5k.png'), 'rb')
266
+ @dummy = Dummy.new
267
+ @dummy.avatar = @file
268
+ end
269
+
270
+ teardown { @file.close }
271
+
272
+ should "not get a bucket to get a URL" do
273
+ @dummy.avatar.expects(:s3).never
274
+ @dummy.avatar.expects(:s3_bucket).never
275
+ assert_match %r{^http://s3\.amazonaws\.com/testing/avatars/original/5k\.png}, @dummy.avatar.url
276
+ end
277
+
278
+ context "and saved" do
279
+ setup do
280
+ AWS::S3::S3Object.stubs(:store).with(@dummy.avatar.path, anything, 'testing', :content_type => 'image/png', :access => :public_read)
281
+ @dummy.save
282
+ end
283
+
284
+ should "succeed" do
285
+ assert true
286
+ end
287
+ end
288
+
289
+ context "and remove" do
290
+ setup do
291
+ AWS::S3::S3Object.stubs(:exists?).returns(true)
292
+ AWS::S3::S3Object.stubs(:delete)
293
+ @dummy.destroy_attached_files
294
+ end
295
+
296
+ should "succeed" do
297
+ assert true
298
+ end
299
+ end
300
+ end
301
+ end
302
+
303
+ context "An attachment with Cloud Files storage" do
304
+ setup do
305
+ rebuild_model :storage => :cloud_files,
306
+ :container => "testing",
307
+ :path => ":attachment/:style/:basename.:extension",
308
+ :cloudfiles_credentials => {
309
+ 'username' => "minter",
310
+ 'api_key' => "xxxxxxx"
311
+ }
312
+ end
313
+
314
+ should "be extended by the CloudFile module" do
315
+ CloudFiles::Connection.stubs(:new).returns(true)
316
+ assert Dummy.new.avatar.is_a?(Paperclip::Storage::CloudFile)
317
+ end
318
+
319
+ should "not be extended by the Filesystem module" do
320
+ CloudFiles::Connection.stubs(:new).returns(true)
321
+ assert ! Dummy.new.avatar.is_a?(Paperclip::Storage::Filesystem)
322
+ end
323
+
324
+ # context "when assigned" do
325
+ # setup do
326
+ # @cf_mock = stub
327
+ # CloudFiles::Connection.expects(:new).returns(@cf_mock)
328
+ # @file = File.new(File.join(File.dirname(__FILE__), 'fixtures', '5k.png'), 'rb')
329
+ # @dummy = Dummy.new
330
+ # @dummy.avatar = @file
331
+ # end
332
+ #
333
+ # teardown { @file.close }
334
+ #
335
+ # context "and saved" do
336
+ # setup do
337
+ # @container_mock = stub
338
+ # @object_mock = stub
339
+ # @cf_mock.expects(:create_container).with("testing").returns(@container_mock)
340
+ # @container_mock.expects(:make_public).returns(true)
341
+ # @container_mock.expects(:create_object).returns(@object_mock)
342
+ # @object_mock.expects(:write).returns(true)
343
+ # @dummy.save
344
+ # end
345
+ #
346
+ # should "succeed" do
347
+ # assert true
348
+ # end
349
+ # end
350
+ #
351
+ # context "and remove" do
352
+ # setup do
353
+ # @container_mock = stub
354
+ # print "DEBUG: ContainerMock is #{@container_mock}\n"
355
+ # @object_mock = stub
356
+ # print "DEBUG: Object Mock is #{@object_mock}\n"
357
+ # @cf_mock.expects(:create_container).with("testing").returns(@container_mock)
358
+ # @container_mock.expects(:make_public).returns(true)
359
+ # @container_mock.stubs(:object_exists?).returns(true)
360
+ # @container_mock.expects(:delete_object).with('avatars/original/5k.png').returns(true)
361
+ # @dummy.destroy_attached_files
362
+ # end
363
+ #
364
+ # should "succeed" do
365
+ # assert true
366
+ # end
367
+ # end
368
+ # end
369
+ end
370
+
371
+
372
+ context "An attachment with S3 storage and bucket defined as a Proc" do
373
+ setup do
374
+ AWS::S3::Base.stubs(:establish_connection!)
375
+ rebuild_model :storage => :s3,
376
+ :bucket => lambda { |attachment| "bucket_#{attachment.instance.other}" },
377
+ :s3_credentials => {:not => :important}
378
+ end
379
+
380
+ should "get the right bucket name" do
381
+ assert "bucket_a", Dummy.new(:other => 'a').avatar.bucket_name
382
+ assert "bucket_b", Dummy.new(:other => 'b').avatar.bucket_name
383
+ end
384
+ end
385
+
386
+ context "An attachment with Cloud Files storage and container defined as a Proc" do
387
+ setup do
388
+ CloudFiles::Connection.stubs(:new).returns(true)
389
+ rebuild_model :storage => :cloud_files,
390
+ :bucket => lambda { |attachment| "container_#{attachment.instance.other}" },
391
+ :cloudfiles_credentials => {:not => :important}
392
+ end
393
+
394
+ should "get the right container name" do
395
+ assert "container_a", Dummy.new(:other => 'a').avatar.container_name
396
+ assert "container_b", Dummy.new(:other => 'b').avatar.container_name
397
+ end
398
+ end
399
+
400
+
401
+ context "An attachment with S3 storage and specific s3 headers set" do
402
+ setup do
403
+ AWS::S3::Base.stubs(:establish_connection!)
404
+ rebuild_model :storage => :s3,
405
+ :bucket => "testing",
406
+ :path => ":attachment/:style/:basename.:extension",
407
+ :s3_credentials => {
408
+ 'access_key_id' => "12345",
409
+ 'secret_access_key' => "54321"
410
+ },
411
+ :s3_headers => {'Cache-Control' => 'max-age=31557600'}
412
+ end
413
+
414
+ context "when assigned" do
415
+ setup do
416
+ @file = File.new(File.join(File.dirname(__FILE__), 'fixtures', '5k.png'), 'rb')
417
+ @dummy = Dummy.new
418
+ @dummy.avatar = @file
419
+ end
420
+
421
+ teardown { @file.close }
422
+
423
+ context "and saved" do
424
+ setup do
425
+ AWS::S3::Base.stubs(:establish_connection!)
426
+ AWS::S3::S3Object.stubs(:store).with(@dummy.avatar.path,
427
+ anything,
428
+ 'testing',
429
+ :content_type => 'image/png',
430
+ :access => :public_read,
431
+ 'Cache-Control' => 'max-age=31557600')
432
+ @dummy.save
433
+ end
434
+
435
+ should "succeed" do
436
+ assert true
437
+ end
438
+ end
439
+ end
440
+ end
441
+
442
+ context "with S3 credentials in a YAML file" do
443
+ setup do
444
+ ENV['S3_KEY'] = 'env_key'
445
+ ENV['S3_BUCKET'] = 'env_bucket'
446
+ ENV['S3_SECRET'] = 'env_secret'
447
+
448
+ rails_env('test')
449
+
450
+ rebuild_model :storage => :s3,
451
+ :s3_credentials => File.new(File.join(File.dirname(__FILE__), "fixtures/s3.yml"))
452
+
453
+ Dummy.delete_all
454
+
455
+ @dummy = Dummy.new
456
+ end
457
+
458
+ should "run it the file through ERB" do
459
+ assert_equal 'env_bucket', @dummy.avatar.bucket_name
460
+ assert_equal 'env_key', AWS::S3::Base.connection.options[:access_key_id]
461
+ assert_equal 'env_secret', AWS::S3::Base.connection.options[:secret_access_key]
462
+ end
463
+ end
464
+
465
+ unless ENV["S3_TEST_BUCKET"].blank?
466
+ context "Using S3 for real, an attachment with S3 storage" do
467
+ setup do
468
+ rebuild_model :styles => { :thumb => "100x100", :square => "32x32#" },
469
+ :storage => :s3,
470
+ :bucket => ENV["S3_TEST_BUCKET"],
471
+ :path => ":class/:attachment/:id/:style.:extension",
472
+ :s3_credentials => File.new(File.join(File.dirname(__FILE__), "s3.yml"))
473
+
474
+ Dummy.delete_all
475
+ @dummy = Dummy.new
476
+ end
477
+
478
+ should "be extended by the S3 module" do
479
+ assert Dummy.new.avatar.is_a?(Paperclip::Storage::S3)
480
+ end
481
+
482
+ context "when assigned" do
483
+ setup do
484
+ @file = File.new(File.join(File.dirname(__FILE__), 'fixtures', '5k.png'), 'rb')
485
+ @dummy.avatar = @file
486
+ end
487
+
488
+ teardown { @file.close }
489
+
490
+ should "still return a Tempfile when sent #to_file" do
491
+ assert_equal Tempfile, @dummy.avatar.to_file.class
492
+ end
493
+
494
+ context "and saved" do
495
+ setup do
496
+ @dummy.save
497
+ end
498
+
499
+ should "be on S3" do
500
+ assert true
501
+ end
502
+ end
503
+ end
504
+ end
505
+ end
506
+
507
+ unless ENV["CF_TEST_BUCKET"].blank?
508
+ context "Using CloudFiles for real, an attachment with CloudFiles storage" do
509
+ setup do
510
+ rebuild_model :styles => { :thumb => "100x100", :square => "32x32#" },
511
+ :storage => :cloud_files,
512
+ :container => ENV["CF_TEST_BUCKET"],
513
+ :path => ":class/:attachment/:id/:style.:extension",
514
+ :cloudfiles_credentials => File.new(File.join(File.dirname(__FILE__), "cloudfiles.yml"))
515
+
516
+ Dummy.delete_all
517
+ @dummy = Dummy.new
518
+ end
519
+
520
+ should "be extended by the CloudFile module" do
521
+ assert Dummy.new.avatar.is_a?(Paperclip::Storage::CloudFile)
522
+ end
523
+
524
+ context "when assigned" do
525
+ setup do
526
+ @file = File.new(File.join(File.dirname(__FILE__), 'fixtures', '5k.png'), 'rb')
527
+ @dummy.avatar = @file
528
+ end
529
+
530
+ teardown { @file.close }
531
+
532
+ should "still return a Tempfile when sent #to_io" do
533
+ assert_equal Tempfile, @dummy.avatar.to_io.class
534
+ end
535
+
536
+ context "and saved" do
537
+ setup do
538
+ @dummy.save
539
+ end
540
+
541
+ should "be on Cloud Files" do
542
+ assert true
543
+ end
544
+ end
545
+ end
546
+ end
547
+ end
548
+
549
+ end