paperclip-cloudfiles 2.3.1.1.0

Sign up to get free protection for your applications and to get access to all the features.
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