ungulate 0.1.4 → 0.2.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.
- 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
|