ungulate 0.1.4 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/VERSION +1 -1
- data/bin/ungulate_server.rb +22 -7
- data/features/image_resize.feature +2 -12
- data/features/notification_url.feature +14 -0
- data/features/resize_then_composite.feature +2 -1
- data/features/step_definitions/bucket_steps.rb +4 -0
- data/features/step_definitions/command_steps.rb +10 -1
- data/features/step_definitions/notification_steps.rb +23 -0
- data/features/step_definitions/queue_steps.rb +7 -21
- data/features/step_definitions/version_steps.rb +2 -2
- data/features/{support.rb → support/config.rb} +4 -0
- data/features/support/helpers.rb +21 -0
- data/features/support/put_server.rb +22 -0
- data/lib/ungulate.rb +64 -0
- data/lib/ungulate/blob_processor.rb +34 -0
- data/lib/ungulate/curl_http.rb +25 -0
- data/lib/ungulate/file_upload.rb +22 -16
- data/lib/ungulate/job.rb +23 -143
- data/lib/ungulate/rmagick_version_creator.rb +77 -0
- data/lib/ungulate/s3_storage.rb +41 -0
- data/lib/ungulate/server.rb +27 -7
- data/lib/ungulate/sqs_message_queue.rb +38 -0
- data/spec/fixtures/chuckle.jpg +0 -0
- data/spec/fixtures/chuckle.png +0 -0
- data/spec/fixtures/chuckle_converted.png +0 -0
- data/spec/fixtures/chuckle_converted_badly.png +0 -0
- data/spec/fixtures/chuckle_thumbnail.png +0 -0
- data/spec/fixtures/watermark.png +0 -0
- data/spec/lib/ungulate/blob_processor_spec.rb +68 -0
- data/spec/lib/ungulate/curl_http_spec.rb +20 -0
- data/spec/{ungulate → lib/ungulate}/file_upload_spec.rb +10 -27
- data/spec/lib/ungulate/job_spec.rb +120 -0
- data/spec/lib/ungulate/rmagick_version_creator_spec.rb +97 -0
- data/spec/lib/ungulate/s3_storage_spec.rb +74 -0
- data/spec/lib/ungulate/server_spec.rb +44 -0
- data/spec/lib/ungulate/sqs_message_queue_spec.rb +28 -0
- data/spec/{ungulate → lib/ungulate}/view_helpers_spec.rb +1 -1
- data/spec/lib/ungulate_spec.rb +24 -0
- data/spec/spec_helper.rb +73 -0
- metadata +67 -25
- data/spec/ungulate/job_spec.rb +0 -386
- data/spec/ungulate/server_spec.rb +0 -42
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'ungulate'
|
3
|
+
|
4
|
+
describe Ungulate do
|
5
|
+
describe "configuration" do
|
6
|
+
it "returns the same object every time" do
|
7
|
+
Ungulate.configuration.should equal(Ungulate.configuration)
|
8
|
+
end
|
9
|
+
|
10
|
+
it "yields the current configuration" do
|
11
|
+
Ungulate.configure do |config|
|
12
|
+
config.should == Ungulate::configuration
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
it "allows setting and retrieving values" do
|
17
|
+
Ungulate.configure do |config|
|
18
|
+
config.bob = 'tree'
|
19
|
+
end
|
20
|
+
|
21
|
+
Ungulate.configuration.bob.should == 'tree'
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,3 +1,76 @@
|
|
1
1
|
require 'ungulate'
|
2
2
|
require 'rspec'
|
3
3
|
|
4
|
+
RSpec.configure do |config|
|
5
|
+
def fixture_path(filename)
|
6
|
+
File.expand_path("fixtures/#{filename}", File.dirname(__FILE__))
|
7
|
+
end
|
8
|
+
|
9
|
+
def fixture(filename)
|
10
|
+
File.read fixture_path(filename)
|
11
|
+
end
|
12
|
+
|
13
|
+
def clear(queue)
|
14
|
+
puts "CLEAR"
|
15
|
+
(1..240).each do
|
16
|
+
queue.clear
|
17
|
+
size = queue.size
|
18
|
+
puts "queue size: #{size}"
|
19
|
+
return if size.zero?
|
20
|
+
sleep 1
|
21
|
+
puts "slept 1 second"
|
22
|
+
end
|
23
|
+
queue.size.should be_zero
|
24
|
+
end
|
25
|
+
|
26
|
+
def wait_for_non_empty(queue)
|
27
|
+
puts "WAIT FOR NON EMPTY"
|
28
|
+
(1..240).each do
|
29
|
+
size = queue.size
|
30
|
+
puts "queue size: #{size}"
|
31
|
+
return if size > 0
|
32
|
+
sleep 1
|
33
|
+
puts "slept 1 second"
|
34
|
+
end
|
35
|
+
queue.size.should_not be_zero
|
36
|
+
end
|
37
|
+
|
38
|
+
shared_examples_for "a message queue" do
|
39
|
+
it "has a name" do
|
40
|
+
new_queue.name.should be_present
|
41
|
+
end
|
42
|
+
|
43
|
+
it "can send and receive one deletable message at a time" do
|
44
|
+
queue = new_queue
|
45
|
+
clear(queue)
|
46
|
+
|
47
|
+
sent_bodies = Set.new %w(hello there how are you)
|
48
|
+
|
49
|
+
sent_bodies.each do |message|
|
50
|
+
puts "pushing #{message}"
|
51
|
+
queue.push(message)
|
52
|
+
end
|
53
|
+
|
54
|
+
queue = nil
|
55
|
+
|
56
|
+
new_queue_instance = new_queue
|
57
|
+
wait_for_non_empty(new_queue_instance)
|
58
|
+
|
59
|
+
received_bodies = Set.new
|
60
|
+
|
61
|
+
iterations = 0
|
62
|
+
messages = []
|
63
|
+
while (received_bodies != sent_bodies) && iterations < 30 do
|
64
|
+
messages << new_queue_instance.receive
|
65
|
+
bodies = messages.map(&:to_s)
|
66
|
+
received_bodies += bodies.select(&:present?)
|
67
|
+
iterations += 1
|
68
|
+
puts "iteration: #{iterations} :: messages: #{received_bodies.to_a.join(',')}"
|
69
|
+
end
|
70
|
+
|
71
|
+
messages.compact.each(&:delete)
|
72
|
+
|
73
|
+
received_bodies.should == sent_bodies
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ungulate
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 23
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
-
|
10
|
-
version: 0.
|
8
|
+
- 2
|
9
|
+
- 0
|
10
|
+
version: 0.2.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Andrew Bruce
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-
|
18
|
+
date: 2011-10-28 00:00:00 +01:00
|
19
19
|
default_executable: ungulate_server.rb
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -98,9 +98,25 @@ dependencies:
|
|
98
98
|
type: :runtime
|
99
99
|
version_requirements: *id005
|
100
100
|
- !ruby/object:Gem::Dependency
|
101
|
-
name:
|
101
|
+
name: hashie
|
102
102
|
prerelease: false
|
103
103
|
requirement: &id006 !ruby/object:Gem::Requirement
|
104
|
+
none: false
|
105
|
+
requirements:
|
106
|
+
- - ">="
|
107
|
+
- !ruby/object:Gem::Version
|
108
|
+
hash: 31
|
109
|
+
segments:
|
110
|
+
- 1
|
111
|
+
- 2
|
112
|
+
- 0
|
113
|
+
version: 1.2.0
|
114
|
+
type: :runtime
|
115
|
+
version_requirements: *id006
|
116
|
+
- !ruby/object:Gem::Dependency
|
117
|
+
name: rake
|
118
|
+
prerelease: false
|
119
|
+
requirement: &id007 !ruby/object:Gem::Requirement
|
104
120
|
none: false
|
105
121
|
requirements:
|
106
122
|
- - ">="
|
@@ -110,11 +126,11 @@ dependencies:
|
|
110
126
|
- 0
|
111
127
|
version: "0"
|
112
128
|
type: :development
|
113
|
-
version_requirements: *
|
129
|
+
version_requirements: *id007
|
114
130
|
- !ruby/object:Gem::Dependency
|
115
131
|
name: rspec
|
116
132
|
prerelease: false
|
117
|
-
requirement: &
|
133
|
+
requirement: &id008 !ruby/object:Gem::Requirement
|
118
134
|
none: false
|
119
135
|
requirements:
|
120
136
|
- - ">="
|
@@ -126,11 +142,11 @@ dependencies:
|
|
126
142
|
- 0
|
127
143
|
version: 2.4.0
|
128
144
|
type: :development
|
129
|
-
version_requirements: *
|
145
|
+
version_requirements: *id008
|
130
146
|
- !ruby/object:Gem::Dependency
|
131
147
|
name: cucumber
|
132
148
|
prerelease: false
|
133
|
-
requirement: &
|
149
|
+
requirement: &id009 !ruby/object:Gem::Requirement
|
134
150
|
none: false
|
135
151
|
requirements:
|
136
152
|
- - ">="
|
@@ -142,11 +158,11 @@ dependencies:
|
|
142
158
|
- 0
|
143
159
|
version: 0.10.0
|
144
160
|
type: :development
|
145
|
-
version_requirements: *
|
161
|
+
version_requirements: *id009
|
146
162
|
- !ruby/object:Gem::Dependency
|
147
163
|
name: i18n
|
148
164
|
prerelease: false
|
149
|
-
requirement: &
|
165
|
+
requirement: &id010 !ruby/object:Gem::Requirement
|
150
166
|
none: false
|
151
167
|
requirements:
|
152
168
|
- - ">="
|
@@ -158,11 +174,11 @@ dependencies:
|
|
158
174
|
- 0
|
159
175
|
version: 0.5.0
|
160
176
|
type: :development
|
161
|
-
version_requirements: *
|
177
|
+
version_requirements: *id010
|
162
178
|
- !ruby/object:Gem::Dependency
|
163
179
|
name: ruby-debug
|
164
180
|
prerelease: false
|
165
|
-
requirement: &
|
181
|
+
requirement: &id011 !ruby/object:Gem::Requirement
|
166
182
|
none: false
|
167
183
|
requirements:
|
168
184
|
- - ">="
|
@@ -172,7 +188,7 @@ dependencies:
|
|
172
188
|
- 0
|
173
189
|
version: "0"
|
174
190
|
type: :development
|
175
|
-
version_requirements: *
|
191
|
+
version_requirements: *id011
|
176
192
|
description: |
|
177
193
|
= Ungulate
|
178
194
|
|
@@ -225,22 +241,44 @@ files:
|
|
225
241
|
- features/camels.jpg
|
226
242
|
- features/cope_with_empty_queue.feature
|
227
243
|
- features/image_resize.feature
|
244
|
+
- features/notification_url.feature
|
228
245
|
- features/resize_then_composite.feature
|
246
|
+
- features/step_definitions/bucket_steps.rb
|
229
247
|
- features/step_definitions/command_steps.rb
|
248
|
+
- features/step_definitions/notification_steps.rb
|
230
249
|
- features/step_definitions/queue_steps.rb
|
231
250
|
- features/step_definitions/version_steps.rb
|
232
251
|
- features/superhugwatermark.png
|
233
|
-
- features/support.rb
|
252
|
+
- features/support/config.rb
|
253
|
+
- features/support/helpers.rb
|
254
|
+
- features/support/put_server.rb
|
255
|
+
- lib/ungulate/blob_processor.rb
|
256
|
+
- lib/ungulate/curl_http.rb
|
234
257
|
- lib/ungulate/file_upload.rb
|
235
258
|
- lib/ungulate/job.rb
|
259
|
+
- lib/ungulate/rmagick_version_creator.rb
|
260
|
+
- lib/ungulate/s3_storage.rb
|
236
261
|
- lib/ungulate/server.rb
|
262
|
+
- lib/ungulate/sqs_message_queue.rb
|
237
263
|
- lib/ungulate/view_helpers.rb
|
238
264
|
- lib/ungulate.rb
|
265
|
+
- spec/fixtures/chuckle.jpg
|
266
|
+
- spec/fixtures/chuckle.png
|
267
|
+
- spec/fixtures/chuckle_converted.png
|
268
|
+
- spec/fixtures/chuckle_converted_badly.png
|
269
|
+
- spec/fixtures/chuckle_thumbnail.png
|
270
|
+
- spec/fixtures/watermark.png
|
271
|
+
- spec/lib/ungulate/blob_processor_spec.rb
|
272
|
+
- spec/lib/ungulate/curl_http_spec.rb
|
273
|
+
- spec/lib/ungulate/file_upload_spec.rb
|
274
|
+
- spec/lib/ungulate/job_spec.rb
|
275
|
+
- spec/lib/ungulate/rmagick_version_creator_spec.rb
|
276
|
+
- spec/lib/ungulate/s3_storage_spec.rb
|
277
|
+
- spec/lib/ungulate/server_spec.rb
|
278
|
+
- spec/lib/ungulate/sqs_message_queue_spec.rb
|
279
|
+
- spec/lib/ungulate/view_helpers_spec.rb
|
280
|
+
- spec/lib/ungulate_spec.rb
|
239
281
|
- spec/spec_helper.rb
|
240
|
-
- spec/ungulate/file_upload_spec.rb
|
241
|
-
- spec/ungulate/job_spec.rb
|
242
|
-
- spec/ungulate/server_spec.rb
|
243
|
-
- spec/ungulate/view_helpers_spec.rb
|
244
282
|
has_rdoc: true
|
245
283
|
homepage: http://github.com/camelpunch/ungulate
|
246
284
|
licenses: []
|
@@ -276,8 +314,12 @@ signing_key:
|
|
276
314
|
specification_version: 3
|
277
315
|
summary: Process images using Amazon SQS and S3
|
278
316
|
test_files:
|
279
|
-
- spec/
|
280
|
-
- spec/ungulate/
|
281
|
-
- spec/ungulate/
|
282
|
-
- spec/ungulate/
|
283
|
-
- spec/ungulate/
|
317
|
+
- spec/lib/ungulate/file_upload_spec.rb
|
318
|
+
- spec/lib/ungulate/job_spec.rb
|
319
|
+
- spec/lib/ungulate/server_spec.rb
|
320
|
+
- spec/lib/ungulate/blob_processor_spec.rb
|
321
|
+
- spec/lib/ungulate/curl_http_spec.rb
|
322
|
+
- spec/lib/ungulate/rmagick_version_creator_spec.rb
|
323
|
+
- spec/lib/ungulate/s3_storage_spec.rb
|
324
|
+
- spec/lib/ungulate/sqs_message_queue_spec.rb
|
325
|
+
- spec/lib/ungulate/view_helpers_spec.rb
|
data/spec/ungulate/job_spec.rb
DELETED
@@ -1,386 +0,0 @@
|
|
1
|
-
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
-
require 'ungulate/job'
|
3
|
-
|
4
|
-
module Ungulate
|
5
|
-
describe Job do
|
6
|
-
let(:source_image) { stub('Source Image', :destroy! => nil) }
|
7
|
-
let(:processed_image_1) { stub('Image 1', :destroy! => nil) }
|
8
|
-
let(:processed_image_2) { stub('Image 2', :destroy! => nil) }
|
9
|
-
let(:curl_easy) { stub('Curl::Easy', :body_str => body_str) }
|
10
|
-
|
11
|
-
before do
|
12
|
-
ENV['AMAZON_ACCESS_KEY_ID'] = 'test-key-id'
|
13
|
-
ENV['AMAZON_SECRET_ACCESS_KEY'] = 'test-secret'
|
14
|
-
@bucket = mock('Bucket', :put => nil)
|
15
|
-
@sqs = mock('SqsGen2')
|
16
|
-
@s3 = mock('S3')
|
17
|
-
@q = mock('Queue')
|
18
|
-
@versions = {
|
19
|
-
:thumb => [ :resize_to_fit, 100, 200 ],
|
20
|
-
:large => [ :resize_to_fit, 200, 300 ],
|
21
|
-
}
|
22
|
-
|
23
|
-
Curl::Easy.stub(:http_get)
|
24
|
-
end
|
25
|
-
|
26
|
-
its(:versions) { should == [] }
|
27
|
-
|
28
|
-
describe :sqs do
|
29
|
-
before do
|
30
|
-
RightAws::SqsGen2.stub(:new).with('test-key-id', 'test-secret').and_return(@sqs)
|
31
|
-
end
|
32
|
-
|
33
|
-
it "should return a SqsGen2 instance using environment variables" do
|
34
|
-
Job.sqs.should == @sqs
|
35
|
-
end
|
36
|
-
|
37
|
-
it "should memoize" do
|
38
|
-
Job.instance_variable_set('@sqs', :cache)
|
39
|
-
Job.sqs.should == :cache
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
describe :pop do
|
44
|
-
before do
|
45
|
-
@job_attributes = {
|
46
|
-
:bucket => 'test-bucket',
|
47
|
-
:key => 'test-key',
|
48
|
-
:versions => @versions
|
49
|
-
}
|
50
|
-
|
51
|
-
@sqs.stub(:queue).with('test-queue').and_return(@q)
|
52
|
-
|
53
|
-
message = mock('Message', :to_s => :message_data)
|
54
|
-
|
55
|
-
@q.stub(:pop).and_return(message)
|
56
|
-
YAML.stub(:load).with(:message_data).and_return(:attributes)
|
57
|
-
|
58
|
-
Job.stub(:sqs).and_return(@sqs)
|
59
|
-
Job.stub(:s3).and_return(@s3)
|
60
|
-
|
61
|
-
@job = mock('Job', :attributes= => nil, :queue= => nil, :queue => @q)
|
62
|
-
Job.stub(:new).and_return(@job)
|
63
|
-
end
|
64
|
-
|
65
|
-
after { Job.pop('test-queue') }
|
66
|
-
|
67
|
-
it "should set attributes" do
|
68
|
-
@job.should_receive(:attributes=).with(:attributes)
|
69
|
-
end
|
70
|
-
|
71
|
-
it "should set the queue" do
|
72
|
-
@job.should_receive(:queue=).with(@q)
|
73
|
-
end
|
74
|
-
|
75
|
-
context "when YAML.load returns false" do
|
76
|
-
before do
|
77
|
-
YAML.stub(:load).with(:message_data).and_return(false)
|
78
|
-
end
|
79
|
-
|
80
|
-
it "should not set attributes" do
|
81
|
-
@job.should_not_receive(:attributes=)
|
82
|
-
end
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
|
-
describe :s3 do
|
87
|
-
before do
|
88
|
-
RightAws::S3.stub(:new).with('test-key-id', 'test-secret').and_return(@s3)
|
89
|
-
end
|
90
|
-
|
91
|
-
it "should return a S3 instance using environment variables" do
|
92
|
-
Job.s3.should == @s3
|
93
|
-
end
|
94
|
-
|
95
|
-
it "should memoize" do
|
96
|
-
Job.instance_variable_set('@s3', :cache)
|
97
|
-
Job.s3.should == :cache
|
98
|
-
end
|
99
|
-
end
|
100
|
-
|
101
|
-
describe :attributes= do
|
102
|
-
subject do
|
103
|
-
Job.stub_chain(:s3, :bucket).with('hello').and_return(@bucket)
|
104
|
-
|
105
|
-
job = Job.new
|
106
|
-
job.attributes = {
|
107
|
-
:bucket => 'hello',
|
108
|
-
:key => 'path/to/filename.gif',
|
109
|
-
:versions => @versions,
|
110
|
-
:notification_url => 'http://some.host/with/simple/path',
|
111
|
-
}
|
112
|
-
job
|
113
|
-
end
|
114
|
-
|
115
|
-
its(:bucket) { should == @bucket }
|
116
|
-
its(:key) { should == 'path/to/filename.gif' }
|
117
|
-
its(:versions) { should == @versions }
|
118
|
-
its(:notification_url) { should == 'http://some.host/with/simple/path' }
|
119
|
-
end
|
120
|
-
|
121
|
-
describe :source do
|
122
|
-
subject do
|
123
|
-
job = Job.new
|
124
|
-
job.stub(:key).and_return('test-key')
|
125
|
-
job.stub_chain(:bucket, :get).with('test-key').and_return(:s3_data)
|
126
|
-
job.source
|
127
|
-
end
|
128
|
-
|
129
|
-
it { should == :s3_data }
|
130
|
-
|
131
|
-
it "should memoize" do
|
132
|
-
job = Job.new
|
133
|
-
job.instance_variable_set('@source', :cache)
|
134
|
-
job.source.should == :cache
|
135
|
-
end
|
136
|
-
end
|
137
|
-
|
138
|
-
describe :image do
|
139
|
-
let(:blob) { 'asdf' }
|
140
|
-
|
141
|
-
it "returns a Magick::Image from the source" do
|
142
|
-
subject.stub(:source).and_return(blob)
|
143
|
-
Magick::Image.should_receive(:from_blob).with(blob).and_return([source_image])
|
144
|
-
subject.source_image.should == source_image
|
145
|
-
end
|
146
|
-
end
|
147
|
-
|
148
|
-
describe :image_from_instruction do
|
149
|
-
let(:instruction) { [ :composite, url, arg1, arg2 ] }
|
150
|
-
let(:overlay) { stub('Overlay', :destroy! => nil) }
|
151
|
-
let(:arg1) { 1 }
|
152
|
-
let(:arg2) { 2 }
|
153
|
-
let(:url) { 'https://www.some.url/' }
|
154
|
-
let(:body_str) { 'blob' }
|
155
|
-
|
156
|
-
before do
|
157
|
-
Curl::Easy.stub(:http_get).and_return(curl_easy)
|
158
|
-
Magick::Image.stub(:from_blob).and_return([overlay])
|
159
|
-
source_image.stub(:composite).and_return(processed_image_1)
|
160
|
-
end
|
161
|
-
|
162
|
-
context "when an argument is a URL" do
|
163
|
-
it "converts the URL to an Image" do
|
164
|
-
Curl::Easy.should_receive(:http_get).with(url).and_return(curl_easy)
|
165
|
-
Magick::Image.should_receive(:from_blob).with('blob').and_return([overlay])
|
166
|
-
source_image.should_receive(:composite).
|
167
|
-
with(overlay, arg1, arg2).
|
168
|
-
and_return(processed_image_1)
|
169
|
-
|
170
|
-
subject.image_from_instruction(source_image, instruction).
|
171
|
-
should == processed_image_1
|
172
|
-
end
|
173
|
-
|
174
|
-
it "caches the image blob in a hash for later reuse" do
|
175
|
-
subject.image_from_instruction(source_image, instruction)
|
176
|
-
Ungulate::Job.blobs_from_urls[url].should == 'blob'
|
177
|
-
end
|
178
|
-
|
179
|
-
context "image is already cached" do
|
180
|
-
it "reuses the cached image" do
|
181
|
-
subject.class.blobs_from_urls[url] = 'cachedblob'
|
182
|
-
Magick::Image.should_receive(:from_blob).with('cachedblob').and_return([overlay])
|
183
|
-
subject.image_from_instruction(source_image, instruction)
|
184
|
-
end
|
185
|
-
end
|
186
|
-
end
|
187
|
-
|
188
|
-
context "when argument isn't a valid http URL" do
|
189
|
-
let(:url) { 'somethingwithhttpinit' }
|
190
|
-
|
191
|
-
it "passes the argument through to the method" do
|
192
|
-
source_image.should_receive(:composite).
|
193
|
-
with(url, arg1, arg2).
|
194
|
-
and_return(processed_image_1)
|
195
|
-
|
196
|
-
subject.image_from_instruction(source_image, instruction)
|
197
|
-
end
|
198
|
-
end
|
199
|
-
|
200
|
-
context "when arguments are symbols" do
|
201
|
-
let(:arg1) { :center_gravity }
|
202
|
-
let(:arg2) { :soft_light_composite_op }
|
203
|
-
|
204
|
-
it "converts the symbols to Magick::XxXx constants" do
|
205
|
-
source_image.should_receive(:composite).
|
206
|
-
with(anything, Magick::CenterGravity, Magick::SoftLightCompositeOp).
|
207
|
-
and_return(processed_image_1)
|
208
|
-
|
209
|
-
subject.image_from_instruction(source_image, instruction)
|
210
|
-
end
|
211
|
-
end
|
212
|
-
end
|
213
|
-
|
214
|
-
describe :processed_versions do
|
215
|
-
let(:versions) do
|
216
|
-
{
|
217
|
-
:large => [ :resize_to_fit, 100, 200 ],
|
218
|
-
:small => [ :resize_to_fill, 64, 64 ],
|
219
|
-
}
|
220
|
-
end
|
221
|
-
|
222
|
-
before do
|
223
|
-
subject.stub(:versions).and_return(versions)
|
224
|
-
subject.stub(:key).and_return('someimage.jpg')
|
225
|
-
subject.stub(:source_image).and_return(source_image)
|
226
|
-
|
227
|
-
source_image.stub(:resize_to_fit).with(100, 200).and_return(processed_image_1)
|
228
|
-
source_image.stub(:resize_to_fill).with(64, 64).and_return(processed_image_2)
|
229
|
-
end
|
230
|
-
|
231
|
-
it "processes multiple versions" do
|
232
|
-
subject.processed_versions.should include([:large, processed_image_1])
|
233
|
-
subject.processed_versions.should include([:small, processed_image_2])
|
234
|
-
end
|
235
|
-
|
236
|
-
it "destroys the image object" do
|
237
|
-
source_image.should_receive(:destroy!)
|
238
|
-
subject.processed_versions
|
239
|
-
end
|
240
|
-
|
241
|
-
it "memoizes" do
|
242
|
-
subject.instance_variable_set('@processed_versions', :cache)
|
243
|
-
subject.processed_versions.should == :cache
|
244
|
-
end
|
245
|
-
|
246
|
-
context "with three 'method' arguments" do
|
247
|
-
let(:versions) do
|
248
|
-
{ :large => [ :some_method, 'some-value', 1, 2 ] }
|
249
|
-
end
|
250
|
-
|
251
|
-
it "passes each value" do
|
252
|
-
source_image.should_receive(:some_method).
|
253
|
-
with('some-value', 1, 2).
|
254
|
-
and_return(processed_image_1)
|
255
|
-
subject.processed_versions.should == [[:large, processed_image_1]]
|
256
|
-
end
|
257
|
-
end
|
258
|
-
|
259
|
-
context "with multiple instructions in a version" do
|
260
|
-
let(:versions) do
|
261
|
-
{
|
262
|
-
:large => [
|
263
|
-
[ :method_1, 'value-1' ],
|
264
|
-
[ :method_2, 'value-2' ]
|
265
|
-
]
|
266
|
-
}
|
267
|
-
end
|
268
|
-
|
269
|
-
before do
|
270
|
-
source_image.stub(:method_1).and_return(processed_image_1)
|
271
|
-
processed_image_1.stub(:method_2).and_return(processed_image_2)
|
272
|
-
end
|
273
|
-
|
274
|
-
it "chains the processing" do
|
275
|
-
subject.processed_versions.should == [[:large, processed_image_2]]
|
276
|
-
end
|
277
|
-
|
278
|
-
it "destroys intermediate images" do
|
279
|
-
processed_image_1.should_receive(:destroy!)
|
280
|
-
subject.processed_versions
|
281
|
-
end
|
282
|
-
end
|
283
|
-
end
|
284
|
-
|
285
|
-
describe :process do
|
286
|
-
before do
|
287
|
-
@big = mock('Image', :destroy! => nil, :to_blob => 'bigdata', :format => 'JPEG')
|
288
|
-
@little = mock('Image', :destroy! => nil, :to_blob => 'littledata', :format => 'JPEG')
|
289
|
-
@mime_type = mock('MimeType', :to_s => 'image/jpeg')
|
290
|
-
MIME::Types.stub(:type_for).with('JPEG').and_return(@mime_type)
|
291
|
-
end
|
292
|
-
|
293
|
-
subject do
|
294
|
-
job = Job.new
|
295
|
-
job.stub(:processed_versions).and_return([[:big, @big], [:little, @little]])
|
296
|
-
job.stub(:bucket).and_return(@bucket)
|
297
|
-
job.stub(:version_key).with(:big).and_return('path/to/someimage_big.jpg')
|
298
|
-
job.stub(:version_key).with(:little).and_return('path/to/someimage_little.jpg')
|
299
|
-
job.stub(:send_notification)
|
300
|
-
job
|
301
|
-
end
|
302
|
-
|
303
|
-
it "should destroy the image objects" do
|
304
|
-
@big.should_receive(:destroy!)
|
305
|
-
@little.should_receive(:destroy!)
|
306
|
-
subject.process
|
307
|
-
end
|
308
|
-
|
309
|
-
it "should send each processed version to S3" do
|
310
|
-
expected_headers = {
|
311
|
-
'Content-Type' => 'image/jpeg',
|
312
|
-
'Cache-Control' => 'max-age=2629743',
|
313
|
-
}
|
314
|
-
|
315
|
-
@bucket.should_receive(:put).with('path/to/someimage_big.jpg',
|
316
|
-
'bigdata',
|
317
|
-
{},
|
318
|
-
'public-read',
|
319
|
-
expected_headers)
|
320
|
-
@bucket.should_receive(:put).with('path/to/someimage_little.jpg',
|
321
|
-
'littledata',
|
322
|
-
{},
|
323
|
-
'public-read',
|
324
|
-
expected_headers)
|
325
|
-
subject.process
|
326
|
-
end
|
327
|
-
|
328
|
-
it "should notify" do
|
329
|
-
subject.should_receive(:send_notification)
|
330
|
-
subject.process
|
331
|
-
end
|
332
|
-
|
333
|
-
context "send_notification returns false" do
|
334
|
-
before do
|
335
|
-
subject.stub(:send_notification).and_return(false)
|
336
|
-
end
|
337
|
-
|
338
|
-
it "should return true" do
|
339
|
-
subject.process.should be_true
|
340
|
-
end
|
341
|
-
end
|
342
|
-
|
343
|
-
context "empty array" do
|
344
|
-
before do
|
345
|
-
subject.stub(:processed_versions).and_return([])
|
346
|
-
end
|
347
|
-
|
348
|
-
it "should not break" do
|
349
|
-
subject.process
|
350
|
-
end
|
351
|
-
end
|
352
|
-
end
|
353
|
-
|
354
|
-
describe :send_notification do
|
355
|
-
let(:url) { 'https://some-url' }
|
356
|
-
|
357
|
-
context "notification URL provided" do
|
358
|
-
it "should PUT to the URL" do
|
359
|
-
subject.stub(:notification_url).and_return(url)
|
360
|
-
Curl::Easy.should_receive(:http_put).with(url, '')
|
361
|
-
subject.send_notification
|
362
|
-
end
|
363
|
-
end
|
364
|
-
end
|
365
|
-
|
366
|
-
describe :version_key do
|
367
|
-
subject do
|
368
|
-
job = Job.new
|
369
|
-
job.stub(:key).and_return('path/to/some/file_name.png')
|
370
|
-
job.version_key(:extra_large)
|
371
|
-
end
|
372
|
-
|
373
|
-
it { should == 'path/to/some/file_name_extra_large.png' }
|
374
|
-
|
375
|
-
context "no leading path" do
|
376
|
-
subject do
|
377
|
-
job = Job.new
|
378
|
-
job.stub(:key).and_return('file_name.png')
|
379
|
-
job.version_key(:extra_large)
|
380
|
-
end
|
381
|
-
|
382
|
-
it { should == 'file_name_extra_large.png' }
|
383
|
-
end
|
384
|
-
end
|
385
|
-
end
|
386
|
-
end
|