paperclip 2.3.11 → 2.3.16
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of paperclip might be problematic. Click here for more details.
- data/README.md +30 -4
- data/Rakefile +3 -3
- data/init.rb +3 -0
- data/lib/generators/paperclip/paperclip_generator.rb +3 -1
- data/lib/paperclip/attachment.rb +27 -12
- data/lib/paperclip/{callback_compatability.rb → callback_compatibility.rb} +0 -0
- data/lib/paperclip/geometry.rb +4 -1
- data/lib/paperclip/interpolations.rb +8 -3
- data/lib/paperclip/iostream.rb +1 -1
- data/lib/paperclip/matchers/validate_attachment_content_type_matcher.rb +20 -14
- data/lib/paperclip/processor.rb +1 -1
- data/lib/paperclip/storage/filesystem.rb +8 -3
- data/lib/paperclip/storage/fog.rb +48 -13
- data/lib/paperclip/storage/s3.rb +54 -16
- data/lib/paperclip/style.rb +4 -3
- data/lib/paperclip/thumbnail.rb +18 -3
- data/lib/paperclip/upfile.rb +20 -13
- data/lib/paperclip/version.rb +1 -1
- data/lib/paperclip.rb +60 -27
- data/lib/tasks/paperclip.rake +32 -23
- data/test/attachment_test.rb +116 -0
- data/test/fixtures/animated.gif +0 -0
- data/test/fog_test.rb +30 -19
- data/test/geometry_test.rb +29 -0
- data/test/helper.rb +3 -0
- data/test/integration_test.rb +40 -4
- data/test/interpolations_test.rb +14 -0
- data/test/matchers/validate_attachment_content_type_matcher_test.rb +42 -2
- data/test/paperclip_test.rb +18 -40
- data/test/storage_test.rb +244 -7
- data/test/style_test.rb +30 -5
- data/test/thumbnail_test.rb +111 -6
- data/test/upfile_test.rb +3 -2
- metadata +103 -122
- data/lib/paperclip/command_line.rb +0 -86
- data/test/command_line_test.rb +0 -138
data/test/geometry_test.rb
CHANGED
@@ -120,6 +120,35 @@ class GeometryTest < Test::Unit::TestCase
|
|
120
120
|
assert_raise(Paperclip::NotIdentifiedByImageMagickError){ @geo = Paperclip::Geometry.from_file(file) }
|
121
121
|
end
|
122
122
|
|
123
|
+
should "not generate from a blank filename" do
|
124
|
+
file = ""
|
125
|
+
assert_raise(Paperclip::NotIdentifiedByImageMagickError){ @geo = Paperclip::Geometry.from_file(file) }
|
126
|
+
end
|
127
|
+
|
128
|
+
should "not generate from a nil file" do
|
129
|
+
file = nil
|
130
|
+
assert_raise(Paperclip::NotIdentifiedByImageMagickError){ @geo = Paperclip::Geometry.from_file(file) }
|
131
|
+
end
|
132
|
+
|
133
|
+
should "not generate from a file with no path" do
|
134
|
+
file = mock("file", :path => "")
|
135
|
+
file.stubs(:respond_to?).with("path").returns(true)
|
136
|
+
assert_raise(Paperclip::NotIdentifiedByImageMagickError){ @geo = Paperclip::Geometry.from_file(file) }
|
137
|
+
end
|
138
|
+
|
139
|
+
should "let us know when a command isn't found versus a processing error" do
|
140
|
+
old_path = ENV['PATH']
|
141
|
+
begin
|
142
|
+
ENV['PATH'] = ''
|
143
|
+
assert_raises(Paperclip::CommandNotFoundError) do
|
144
|
+
file = File.join(File.dirname(__FILE__), "fixtures", "5k.png")
|
145
|
+
@geo = Paperclip::Geometry.from_file(file)
|
146
|
+
end
|
147
|
+
ensure
|
148
|
+
ENV['PATH'] = old_path
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
123
152
|
[['vertical', 900, 1440, true, false, false, 1440, 900, 0.625],
|
124
153
|
['horizontal', 1024, 768, false, true, false, 1024, 768, 1.3333],
|
125
154
|
['square', 100, 100, false, false, true, 100, 100, 1]].each do |args|
|
data/test/helper.rb
CHANGED
@@ -8,6 +8,7 @@ require 'mocha'
|
|
8
8
|
require 'active_record'
|
9
9
|
require 'active_record/version'
|
10
10
|
require 'active_support'
|
11
|
+
require 'mime/types'
|
11
12
|
|
12
13
|
puts "Testing against version #{ActiveRecord::VERSION::STRING}"
|
13
14
|
|
@@ -67,6 +68,7 @@ end
|
|
67
68
|
|
68
69
|
def rebuild_model options = {}
|
69
70
|
ActiveRecord::Base.connection.create_table :dummies, :force => true do |table|
|
71
|
+
table.column :title, :string
|
70
72
|
table.column :other, :string
|
71
73
|
table.column :avatar_file_name, :string
|
72
74
|
table.column :avatar_content_type, :string
|
@@ -85,6 +87,7 @@ def rebuild_class options = {}
|
|
85
87
|
include Paperclip::Glue
|
86
88
|
has_attached_file :avatar, options
|
87
89
|
end
|
90
|
+
Dummy.reset_column_information
|
88
91
|
end
|
89
92
|
|
90
93
|
class FakeModel
|
data/test/integration_test.rb
CHANGED
@@ -34,20 +34,20 @@ class IntegrationTest < Test::Unit::TestCase
|
|
34
34
|
should "create its thumbnails properly" do
|
35
35
|
assert_match /\b50x50\b/, `identify "#{@dummy.avatar.path(:thumb)}"`
|
36
36
|
end
|
37
|
-
|
37
|
+
|
38
38
|
context 'reprocessing with unreadable original' do
|
39
39
|
setup { File.chmod(0000, @dummy.avatar.path) }
|
40
|
-
|
40
|
+
|
41
41
|
should "not raise an error" do
|
42
42
|
assert_nothing_raised do
|
43
43
|
@dummy.avatar.reprocess!
|
44
44
|
end
|
45
45
|
end
|
46
|
-
|
46
|
+
|
47
47
|
should "return false" do
|
48
48
|
assert ! @dummy.avatar.reprocess!
|
49
49
|
end
|
50
|
-
|
50
|
+
|
51
51
|
teardown { File.chmod(0644, @dummy.avatar.path) }
|
52
52
|
end
|
53
53
|
|
@@ -58,6 +58,7 @@ class IntegrationTest < Test::Unit::TestCase
|
|
58
58
|
has_attached_file :avatar, :styles => { :thumb => "150x25#", :dynamic => lambda { |a| '50x50#' } }
|
59
59
|
end
|
60
60
|
@d2 = Dummy.find(@dummy.id)
|
61
|
+
@original_timestamp = @d2.avatar_updated_at
|
61
62
|
@d2.avatar.reprocess!
|
62
63
|
@d2.save
|
63
64
|
end
|
@@ -66,6 +67,10 @@ class IntegrationTest < Test::Unit::TestCase
|
|
66
67
|
assert_match /\b150x25\b/, `identify "#{@dummy.avatar.path(:thumb)}"`
|
67
68
|
assert_match /\b50x50\b/, `identify "#{@dummy.avatar.path(:dynamic)}"`
|
68
69
|
end
|
70
|
+
|
71
|
+
should "change the timestamp" do
|
72
|
+
assert_not_equal @original_timestamp, @d2.avatar_updated_at
|
73
|
+
end
|
69
74
|
end
|
70
75
|
end
|
71
76
|
|
@@ -383,6 +388,24 @@ class IntegrationTest < Test::Unit::TestCase
|
|
383
388
|
assert_equal "5k.png", @dummy.avatar_file_name
|
384
389
|
end
|
385
390
|
|
391
|
+
[000,002,022].each do |umask|
|
392
|
+
context "when the umask is #{umask}" do
|
393
|
+
setup do
|
394
|
+
@umask = File.umask umask
|
395
|
+
end
|
396
|
+
|
397
|
+
teardown do
|
398
|
+
File.umask @umask
|
399
|
+
end
|
400
|
+
|
401
|
+
should "respect the current umask" do
|
402
|
+
@dummy.avatar = @file
|
403
|
+
@dummy.save
|
404
|
+
assert_equal 0666&~umask, 0666&File.stat(@dummy.avatar.path).mode
|
405
|
+
end
|
406
|
+
end
|
407
|
+
end
|
408
|
+
|
386
409
|
context "that is assigned its file from another Paperclip attachment" do
|
387
410
|
setup do
|
388
411
|
@dummy2 = Dummy.new
|
@@ -399,6 +422,7 @@ class IntegrationTest < Test::Unit::TestCase
|
|
399
422
|
@dummy.save
|
400
423
|
assert_equal `identify -format "%wx%h" "#{@dummy.avatar.path(:original)}"`,
|
401
424
|
`identify -format "%wx%h" "#{@dummy2.avatar.path(:original)}"`
|
425
|
+
assert_equal @dummy.avatar_file_name, @dummy2.avatar_file_name
|
402
426
|
end
|
403
427
|
end
|
404
428
|
|
@@ -466,6 +490,18 @@ class IntegrationTest < Test::Unit::TestCase
|
|
466
490
|
@files_on_s3 = s3_files_for @dummy.avatar
|
467
491
|
end
|
468
492
|
|
493
|
+
context 'assigning itself to a new model' do
|
494
|
+
setup do
|
495
|
+
@d2 = Dummy.new
|
496
|
+
@d2.avatar = @dummy.avatar
|
497
|
+
@d2.save
|
498
|
+
end
|
499
|
+
|
500
|
+
should "have the same name as the old file" do
|
501
|
+
assert_equal @d2.avatar.original_filename, @dummy.avatar.original_filename
|
502
|
+
end
|
503
|
+
end
|
504
|
+
|
469
505
|
should "have the same contents as the original" do
|
470
506
|
@file.rewind
|
471
507
|
assert_equal @file.read, @files_on_s3[:original].read
|
data/test/interpolations_test.rb
CHANGED
@@ -50,6 +50,13 @@ class InterpolationsTest < Test::Unit::TestCase
|
|
50
50
|
assert_equal "png", Paperclip::Interpolations.extension(attachment, :style)
|
51
51
|
end
|
52
52
|
|
53
|
+
should "return the #to_param of the attachment" do
|
54
|
+
attachment = mock
|
55
|
+
attachment.expects(:to_param).returns("23-awesome")
|
56
|
+
attachment.expects(:instance).returns(attachment)
|
57
|
+
assert_equal "23-awesome", Paperclip::Interpolations.param(attachment, :style)
|
58
|
+
end
|
59
|
+
|
53
60
|
should "return the id of the attachment" do
|
54
61
|
attachment = mock
|
55
62
|
attachment.expects(:id).returns(23)
|
@@ -110,6 +117,13 @@ class InterpolationsTest < Test::Unit::TestCase
|
|
110
117
|
assert_equal "one.png", Paperclip::Interpolations.filename(attachment, :style)
|
111
118
|
end
|
112
119
|
|
120
|
+
should "return the filename as basename when extension is blank" do
|
121
|
+
attachment = mock
|
122
|
+
attachment.stubs(:styles).returns({})
|
123
|
+
attachment.stubs(:original_filename).returns("one")
|
124
|
+
assert_equal "one", Paperclip::Interpolations.filename(attachment, :style)
|
125
|
+
end
|
126
|
+
|
113
127
|
should "return the timestamp" do
|
114
128
|
now = Time.now
|
115
129
|
zone = 'UTC'
|
@@ -34,14 +34,54 @@ class ValidateAttachmentContentTypeMatcherTest < Test::Unit::TestCase
|
|
34
34
|
|
35
35
|
should_accept_dummy_class
|
36
36
|
end
|
37
|
-
|
37
|
+
|
38
38
|
context "given a class with other validations but matching types" do
|
39
39
|
setup do
|
40
40
|
@dummy_class.validates_presence_of :title
|
41
41
|
@dummy_class.validates_attachment_content_type :avatar, :content_type => %r{image/.*}
|
42
42
|
end
|
43
|
-
|
43
|
+
|
44
|
+
should_accept_dummy_class
|
45
|
+
end
|
46
|
+
|
47
|
+
context "given a class that matches and a matcher that only specifies 'allowing'" do
|
48
|
+
setup do
|
49
|
+
@dummy_class.validates_attachment_content_type :avatar, :content_type => %r{image/.*}
|
50
|
+
@matcher = self.class.validate_attachment_content_type(:avatar).
|
51
|
+
allowing(%w(image/png image/jpeg))
|
52
|
+
end
|
53
|
+
|
54
|
+
should_accept_dummy_class
|
55
|
+
end
|
56
|
+
|
57
|
+
context "given a class that does not match and a matcher that only specifies 'allowing'" do
|
58
|
+
setup do
|
59
|
+
@dummy_class.validates_attachment_content_type :avatar, :content_type => %r{audio/.*}
|
60
|
+
@matcher = self.class.validate_attachment_content_type(:avatar).
|
61
|
+
allowing(%w(image/png image/jpeg))
|
62
|
+
end
|
63
|
+
|
64
|
+
should_reject_dummy_class
|
65
|
+
end
|
66
|
+
|
67
|
+
context "given a class that matches and a matcher that only specifies 'rejecting'" do
|
68
|
+
setup do
|
69
|
+
@dummy_class.validates_attachment_content_type :avatar, :content_type => %r{image/.*}
|
70
|
+
@matcher = self.class.validate_attachment_content_type(:avatar).
|
71
|
+
rejecting(%w(audio/mp3 application/octet-stream))
|
72
|
+
end
|
73
|
+
|
44
74
|
should_accept_dummy_class
|
45
75
|
end
|
76
|
+
|
77
|
+
context "given a class that does not match and a matcher that only specifies 'rejecting'" do
|
78
|
+
setup do
|
79
|
+
@dummy_class.validates_attachment_content_type :avatar, :content_type => %r{audio/.*}
|
80
|
+
@matcher = self.class.validate_attachment_content_type(:avatar).
|
81
|
+
rejecting(%w(audio/mp3 application/octet-stream))
|
82
|
+
end
|
83
|
+
|
84
|
+
should_reject_dummy_class
|
85
|
+
end
|
46
86
|
end
|
47
87
|
end
|
data/test/paperclip_test.rb
CHANGED
@@ -2,44 +2,9 @@ require './test/helper'
|
|
2
2
|
|
3
3
|
class PaperclipTest < Test::Unit::TestCase
|
4
4
|
context "Calling Paperclip.run" do
|
5
|
-
|
6
|
-
|
7
|
-
Paperclip.
|
8
|
-
Paperclip::CommandLine.stubs(:'`')
|
9
|
-
end
|
10
|
-
|
11
|
-
should "execute the right command with :image_magick_path" do
|
12
|
-
Paperclip.options[:image_magick_path] = "/usr/bin"
|
13
|
-
Paperclip.expects(:log).with(includes('[DEPRECATION]'))
|
14
|
-
Paperclip.expects(:log).with(regexp_matches(%r{/usr/bin/convert ['"]one.jpg['"] ['"]two.jpg['"]}))
|
15
|
-
Paperclip::CommandLine.expects(:"`").with(regexp_matches(%r{/usr/bin/convert ['"]one.jpg['"] ['"]two.jpg['"]}))
|
16
|
-
Paperclip.run("convert", ":one :two", :one => "one.jpg", :two => "two.jpg")
|
17
|
-
end
|
18
|
-
|
19
|
-
should "execute the right command with :command_path" do
|
20
|
-
Paperclip.options[:command_path] = "/usr/bin"
|
21
|
-
Paperclip::CommandLine.expects(:"`").with(regexp_matches(%r{/usr/bin/convert ['"]one.jpg['"] ['"]two.jpg['"]}))
|
22
|
-
Paperclip.run("convert", ":one :two", :one => "one.jpg", :two => "two.jpg")
|
23
|
-
end
|
24
|
-
|
25
|
-
should "execute the right command with no path" do
|
26
|
-
Paperclip::CommandLine.expects(:"`").with(regexp_matches(%r{convert ['"]one.jpg['"] ['"]two.jpg['"]}))
|
27
|
-
Paperclip.run("convert", ":one :two", :one => "one.jpg", :two => "two.jpg")
|
28
|
-
end
|
29
|
-
|
30
|
-
should "tell you the command isn't there if the shell returns 127" do
|
31
|
-
with_exitstatus_returning(127) do
|
32
|
-
assert_raises(Paperclip::CommandNotFoundError) do
|
33
|
-
Paperclip.run("command")
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
should "tell you the command isn't there if an ENOENT is raised" do
|
39
|
-
assert_raises(Paperclip::CommandNotFoundError) do
|
40
|
-
Paperclip::CommandLine.stubs(:"`").raises(Errno::ENOENT)
|
41
|
-
Paperclip.run("command")
|
42
|
-
end
|
5
|
+
should "run the command with Cocaine" do
|
6
|
+
Cocaine::CommandLine.expects(:new).with("convert", "stuff").returns(stub(:run))
|
7
|
+
Paperclip.run("convert", "stuff")
|
43
8
|
end
|
44
9
|
end
|
45
10
|
|
@@ -72,6 +37,19 @@ class PaperclipTest < Test::Unit::TestCase
|
|
72
37
|
assert_equal ::Paperclip::Thumbnail, Paperclip.processor(:thumbnail)
|
73
38
|
end
|
74
39
|
|
40
|
+
should "get a class from a namespaced class name" do
|
41
|
+
class ::One; class Two; end; end
|
42
|
+
assert_equal ::One::Two, Paperclip.class_for("One::Two")
|
43
|
+
end
|
44
|
+
|
45
|
+
should "raise when class doesn't exist in specified namespace" do
|
46
|
+
class ::Three; end
|
47
|
+
class ::Four; end
|
48
|
+
assert_raise NameError do
|
49
|
+
Paperclip.class_for("Three::Four")
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
75
53
|
context "An ActiveRecord model with an 'avatar' attachment" do
|
76
54
|
setup do
|
77
55
|
rebuild_model :path => "tmp/:class/omg/:style.:extension"
|
@@ -223,7 +201,7 @@ class PaperclipTest < Test::Unit::TestCase
|
|
223
201
|
@dummy.valid?
|
224
202
|
end
|
225
203
|
should "not have an error when assigned a valid file" do
|
226
|
-
assert_equal 0, @dummy.errors.
|
204
|
+
assert_equal 0, @dummy.errors.size, @dummy.errors.full_messages.join(", ")
|
227
205
|
end
|
228
206
|
end
|
229
207
|
context "and assigned an invalid file" do
|
@@ -232,7 +210,7 @@ class PaperclipTest < Test::Unit::TestCase
|
|
232
210
|
@dummy.valid?
|
233
211
|
end
|
234
212
|
should "have an error when assigned a valid file" do
|
235
|
-
assert @dummy.errors.
|
213
|
+
assert @dummy.errors.size > 0
|
236
214
|
end
|
237
215
|
end
|
238
216
|
end
|
data/test/storage_test.rb
CHANGED
@@ -7,7 +7,7 @@ class StorageTest < Test::Unit::TestCase
|
|
7
7
|
Object.const_set(:Rails, stub('Rails', :env => env))
|
8
8
|
end
|
9
9
|
end
|
10
|
-
|
10
|
+
|
11
11
|
context "filesystem" do
|
12
12
|
setup do
|
13
13
|
rebuild_model :styles => { :thumbnail => "25x25#" }
|
@@ -15,16 +15,16 @@ class StorageTest < Test::Unit::TestCase
|
|
15
15
|
|
16
16
|
@dummy.avatar = File.open(File.join(File.dirname(__FILE__), "fixtures", "5k.png"))
|
17
17
|
end
|
18
|
-
|
18
|
+
|
19
19
|
should "allow file assignment" do
|
20
20
|
assert @dummy.save
|
21
21
|
end
|
22
|
-
|
22
|
+
|
23
23
|
should "store the original" do
|
24
24
|
@dummy.save
|
25
25
|
assert File.exists?(@dummy.avatar.path)
|
26
26
|
end
|
27
|
-
|
27
|
+
|
28
28
|
should "store the thumbnail" do
|
29
29
|
@dummy.save
|
30
30
|
assert File.exists?(@dummy.avatar.path(:thumbnail))
|
@@ -78,6 +78,49 @@ class StorageTest < Test::Unit::TestCase
|
|
78
78
|
assert_match %r{^http://s3.amazonaws.com/bucket/avatars/stringio.txt}, @dummy.avatar.url
|
79
79
|
end
|
80
80
|
end
|
81
|
+
|
82
|
+
context "s3_host_name" do
|
83
|
+
setup do
|
84
|
+
AWS::S3::Base.stubs(:establish_connection!)
|
85
|
+
rebuild_model :storage => :s3,
|
86
|
+
:s3_credentials => {},
|
87
|
+
:bucket => "bucket",
|
88
|
+
:path => ":attachment/:basename.:extension",
|
89
|
+
:s3_host_name => "s3-ap-northeast-1.amazonaws.com"
|
90
|
+
@dummy = Dummy.new
|
91
|
+
@dummy.avatar = StringIO.new(".")
|
92
|
+
end
|
93
|
+
|
94
|
+
should "return a url based on an :s3_host_name path" do
|
95
|
+
assert_match %r{^http://s3-ap-northeast-1.amazonaws.com/bucket/avatars/stringio.txt}, @dummy.avatar.url
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
context "An attachment that uses S3 for storage and has styles that return different file types" do
|
100
|
+
setup do
|
101
|
+
AWS::S3::Base.stubs(:establish_connection!)
|
102
|
+
rebuild_model :styles => { :large => ['500x500#', :jpg] },
|
103
|
+
:storage => :s3,
|
104
|
+
:bucket => "bucket",
|
105
|
+
:path => ":attachment/:basename.:extension",
|
106
|
+
:s3_credentials => {
|
107
|
+
'access_key_id' => "12345",
|
108
|
+
'secret_access_key' => "54321"
|
109
|
+
}
|
110
|
+
|
111
|
+
@dummy = Dummy.new
|
112
|
+
@dummy.avatar = File.new(File.join(File.dirname(__FILE__), 'fixtures', '5k.png'), 'rb')
|
113
|
+
end
|
114
|
+
|
115
|
+
should "return a url containing the correct original file mime type" do
|
116
|
+
assert_match /.+\/5k.png/, @dummy.avatar.url
|
117
|
+
end
|
118
|
+
|
119
|
+
should "return a url containing the correct processed file mime type" do
|
120
|
+
assert_match /.+\/5k.jpg/, @dummy.avatar.url(:large)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
81
124
|
context "" do
|
82
125
|
setup do
|
83
126
|
AWS::S3::Base.stubs(:establish_connection!)
|
@@ -94,6 +137,7 @@ class StorageTest < Test::Unit::TestCase
|
|
94
137
|
assert_match %r{^http://bucket.s3.amazonaws.com/avatars/stringio.txt}, @dummy.avatar.url
|
95
138
|
end
|
96
139
|
end
|
140
|
+
|
97
141
|
context "" do
|
98
142
|
setup do
|
99
143
|
AWS::S3::Base.stubs(:establish_connection!)
|
@@ -114,6 +158,45 @@ class StorageTest < Test::Unit::TestCase
|
|
114
158
|
end
|
115
159
|
end
|
116
160
|
|
161
|
+
context "generating a url with a proc as the host alias" do
|
162
|
+
setup do
|
163
|
+
AWS::S3::Base.stubs(:establish_connection!)
|
164
|
+
rebuild_model :storage => :s3,
|
165
|
+
:s3_credentials => { :bucket => "prod_bucket" },
|
166
|
+
:s3_host_alias => Proc.new { |image| "cdn#{image.size.to_i % 4}.example.com" },
|
167
|
+
:path => ":attachment/:basename.:extension",
|
168
|
+
:url => ":s3_alias_url"
|
169
|
+
@dummy = Dummy.new
|
170
|
+
@dummy.avatar = StringIO.new(".")
|
171
|
+
end
|
172
|
+
|
173
|
+
should "return a url based on the host_alias" do
|
174
|
+
assert_match %r{^http://cdn0.example.com/avatars/stringio.txt}, @dummy.avatar.url
|
175
|
+
end
|
176
|
+
|
177
|
+
should "still return the bucket name" do
|
178
|
+
assert_equal "prod_bucket", @dummy.avatar.bucket_name
|
179
|
+
end
|
180
|
+
|
181
|
+
end
|
182
|
+
|
183
|
+
context "" do
|
184
|
+
setup do
|
185
|
+
AWS::S3::Base.stubs(:establish_connection!)
|
186
|
+
rebuild_model :storage => :s3,
|
187
|
+
:s3_credentials => {},
|
188
|
+
:bucket => "bucket",
|
189
|
+
:path => ":attachment/:basename.:extension",
|
190
|
+
:url => ":asset_host"
|
191
|
+
@dummy = Dummy.new
|
192
|
+
@dummy.avatar = StringIO.new(".")
|
193
|
+
end
|
194
|
+
|
195
|
+
should "return a relative URL for Rails to calculate assets host" do
|
196
|
+
assert_match %r{^avatars/stringio.txt}, @dummy.avatar.url
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
117
200
|
context "Generating a secure url with an expiration" do
|
118
201
|
setup do
|
119
202
|
AWS::S3::Base.stubs(:establish_connection!)
|
@@ -150,6 +233,7 @@ class StorageTest < Test::Unit::TestCase
|
|
150
233
|
:production => { :bucket => "prod_bucket" },
|
151
234
|
:development => { :bucket => "dev_bucket" }
|
152
235
|
},
|
236
|
+
:s3_permissions => :private,
|
153
237
|
:s3_host_alias => "something.something.com",
|
154
238
|
:path => ":attachment/:style/:basename.:extension",
|
155
239
|
:url => ":s3_alias_url"
|
@@ -159,10 +243,10 @@ class StorageTest < Test::Unit::TestCase
|
|
159
243
|
@dummy = Dummy.new
|
160
244
|
@dummy.avatar = StringIO.new(".")
|
161
245
|
|
162
|
-
AWS::S3::S3Object.expects(:url_for).with("avatars/original/stringio.txt", "prod_bucket", { :expires_in => 3600, :use_ssl =>
|
246
|
+
AWS::S3::S3Object.expects(:url_for).with("avatars/original/stringio.txt", "prod_bucket", { :expires_in => 3600, :use_ssl => true })
|
163
247
|
@dummy.avatar.expiring_url
|
164
248
|
|
165
|
-
AWS::S3::S3Object.expects(:url_for).with("avatars/thumb/stringio.txt", "prod_bucket", { :expires_in => 1800, :use_ssl =>
|
249
|
+
AWS::S3::S3Object.expects(:url_for).with("avatars/thumb/stringio.txt", "prod_bucket", { :expires_in => 1800, :use_ssl => true })
|
166
250
|
@dummy.avatar.expiring_url(1800, :thumb)
|
167
251
|
end
|
168
252
|
|
@@ -193,6 +277,33 @@ class StorageTest < Test::Unit::TestCase
|
|
193
277
|
end
|
194
278
|
end
|
195
279
|
|
280
|
+
context "Parsing S3 credentials with a s3_host_name in them" do
|
281
|
+
setup do
|
282
|
+
AWS::S3::Base.stubs(:establish_connection!)
|
283
|
+
rebuild_model :storage => :s3,
|
284
|
+
:s3_credentials => {
|
285
|
+
:production => {:s3_host_name => "s3-world-end.amazonaws.com"},
|
286
|
+
:development => { :s3_host_name => "s3-ap-northeast-1.amazonaws.com" }
|
287
|
+
}
|
288
|
+
@dummy = Dummy.new
|
289
|
+
end
|
290
|
+
|
291
|
+
should "get the right s3_host_name in production" do
|
292
|
+
rails_env("production")
|
293
|
+
assert_match %r{^s3-world-end.amazonaws.com}, @dummy.avatar.s3_host_name
|
294
|
+
end
|
295
|
+
|
296
|
+
should "get the right s3_host_name in development" do
|
297
|
+
rails_env("development")
|
298
|
+
assert_match %r{^s3-ap-northeast-1.amazonaws.com}, @dummy.avatar.s3_host_name
|
299
|
+
end
|
300
|
+
|
301
|
+
should "get the right s3_host_name if the key does not exist" do
|
302
|
+
rails_env("test")
|
303
|
+
assert_match %r{^s3.amazonaws.com}, @dummy.avatar.s3_host_name
|
304
|
+
end
|
305
|
+
end
|
306
|
+
|
196
307
|
context "An attachment with S3 storage" do
|
197
308
|
setup do
|
198
309
|
rebuild_model :storage => :s3,
|
@@ -360,12 +471,138 @@ class StorageTest < Test::Unit::TestCase
|
|
360
471
|
@dummy = Dummy.new
|
361
472
|
end
|
362
473
|
|
363
|
-
should "run
|
474
|
+
should "run the file through ERB" do
|
364
475
|
assert_equal 'env_bucket', @dummy.avatar.bucket_name
|
365
476
|
assert_equal 'env_key', AWS::S3::Base.connection.options[:access_key_id]
|
366
477
|
assert_equal 'env_secret', AWS::S3::Base.connection.options[:secret_access_key]
|
367
478
|
end
|
368
479
|
end
|
480
|
+
|
481
|
+
context "S3 Permissions" do
|
482
|
+
context "defaults to public-read" do
|
483
|
+
setup do
|
484
|
+
rebuild_model :storage => :s3,
|
485
|
+
:bucket => "testing",
|
486
|
+
:path => ":attachment/:style/:basename.:extension",
|
487
|
+
:s3_credentials => {
|
488
|
+
'access_key_id' => "12345",
|
489
|
+
'secret_access_key' => "54321"
|
490
|
+
}
|
491
|
+
end
|
492
|
+
|
493
|
+
context "when assigned" do
|
494
|
+
setup do
|
495
|
+
@file = File.new(File.join(File.dirname(__FILE__), 'fixtures', '5k.png'), 'rb')
|
496
|
+
@dummy = Dummy.new
|
497
|
+
@dummy.avatar = @file
|
498
|
+
end
|
499
|
+
|
500
|
+
teardown { @file.close }
|
501
|
+
|
502
|
+
context "and saved" do
|
503
|
+
setup do
|
504
|
+
AWS::S3::Base.stubs(:establish_connection!)
|
505
|
+
AWS::S3::S3Object.expects(:store).with(@dummy.avatar.path,
|
506
|
+
anything,
|
507
|
+
'testing',
|
508
|
+
:content_type => 'image/png',
|
509
|
+
:access => :public_read)
|
510
|
+
@dummy.save
|
511
|
+
end
|
512
|
+
|
513
|
+
should "succeed" do
|
514
|
+
assert true
|
515
|
+
end
|
516
|
+
end
|
517
|
+
end
|
518
|
+
end
|
519
|
+
|
520
|
+
context "string permissions set" do
|
521
|
+
setup do
|
522
|
+
rebuild_model :storage => :s3,
|
523
|
+
:bucket => "testing",
|
524
|
+
:path => ":attachment/:style/:basename.:extension",
|
525
|
+
:s3_credentials => {
|
526
|
+
'access_key_id' => "12345",
|
527
|
+
'secret_access_key' => "54321"
|
528
|
+
},
|
529
|
+
:s3_permissions => 'private'
|
530
|
+
end
|
531
|
+
|
532
|
+
context "when assigned" do
|
533
|
+
setup do
|
534
|
+
@file = File.new(File.join(File.dirname(__FILE__), 'fixtures', '5k.png'), 'rb')
|
535
|
+
@dummy = Dummy.new
|
536
|
+
@dummy.avatar = @file
|
537
|
+
end
|
538
|
+
|
539
|
+
teardown { @file.close }
|
540
|
+
|
541
|
+
context "and saved" do
|
542
|
+
setup do
|
543
|
+
AWS::S3::Base.stubs(:establish_connection!)
|
544
|
+
AWS::S3::S3Object.expects(:store).with(@dummy.avatar.path,
|
545
|
+
anything,
|
546
|
+
'testing',
|
547
|
+
:content_type => 'image/png',
|
548
|
+
:access => 'private')
|
549
|
+
@dummy.save
|
550
|
+
end
|
551
|
+
|
552
|
+
should "succeed" do
|
553
|
+
assert true
|
554
|
+
end
|
555
|
+
end
|
556
|
+
end
|
557
|
+
end
|
558
|
+
|
559
|
+
context "hash permissions set" do
|
560
|
+
setup do
|
561
|
+
rebuild_model :storage => :s3,
|
562
|
+
:bucket => "testing",
|
563
|
+
:path => ":attachment/:style/:basename.:extension",
|
564
|
+
:styles => {
|
565
|
+
:thumb => "80x80>"
|
566
|
+
},
|
567
|
+
:s3_credentials => {
|
568
|
+
'access_key_id' => "12345",
|
569
|
+
'secret_access_key' => "54321"
|
570
|
+
},
|
571
|
+
:s3_permissions => {
|
572
|
+
:original => 'private',
|
573
|
+
:thumb => 'public-read'
|
574
|
+
}
|
575
|
+
end
|
576
|
+
|
577
|
+
context "when assigned" do
|
578
|
+
setup do
|
579
|
+
@file = File.new(File.join(File.dirname(__FILE__), 'fixtures', '5k.png'), 'rb')
|
580
|
+
@dummy = Dummy.new
|
581
|
+
@dummy.avatar = @file
|
582
|
+
end
|
583
|
+
|
584
|
+
teardown { @file.close }
|
585
|
+
|
586
|
+
context "and saved" do
|
587
|
+
setup do
|
588
|
+
AWS::S3::Base.stubs(:establish_connection!)
|
589
|
+
[:thumb, :original].each do |style|
|
590
|
+
AWS::S3::S3Object.expects(:store).with("avatars/#{style}/5k.png",
|
591
|
+
anything,
|
592
|
+
'testing',
|
593
|
+
:content_type => 'image/png',
|
594
|
+
:access => style == :thumb ? 'public-read' : 'private')
|
595
|
+
end
|
596
|
+
@dummy.save
|
597
|
+
end
|
598
|
+
|
599
|
+
should "succeed" do
|
600
|
+
assert true
|
601
|
+
end
|
602
|
+
end
|
603
|
+
end
|
604
|
+
end
|
605
|
+
end
|
369
606
|
|
370
607
|
unless ENV["S3_TEST_BUCKET"].blank?
|
371
608
|
context "Using S3 for real, an attachment with S3 storage" do
|