oahu-dragonfly 0.8.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.rspec +1 -0
- data/.yardopts +24 -0
- data/Gemfile +30 -0
- data/History.md +323 -0
- data/LICENSE +20 -0
- data/README.md +88 -0
- data/Rakefile +50 -0
- data/VERSION +1 -0
- data/config.ru +14 -0
- data/docs.watchr +1 -0
- data/dragonfly.gemspec +297 -0
- data/extra_docs/Analysers.md +66 -0
- data/extra_docs/Caching.md +23 -0
- data/extra_docs/Configuration.md +124 -0
- data/extra_docs/Couch.md +49 -0
- data/extra_docs/DataStorage.md +153 -0
- data/extra_docs/Encoding.md +67 -0
- data/extra_docs/GeneralUsage.md +121 -0
- data/extra_docs/Generators.md +60 -0
- data/extra_docs/Heroku.md +50 -0
- data/extra_docs/ImageMagick.md +125 -0
- data/extra_docs/Index.md +33 -0
- data/extra_docs/MimeTypes.md +40 -0
- data/extra_docs/Models.md +272 -0
- data/extra_docs/Mongo.md +45 -0
- data/extra_docs/Processing.md +77 -0
- data/extra_docs/Rack.md +52 -0
- data/extra_docs/Rails2.md +57 -0
- data/extra_docs/Rails3.md +62 -0
- data/extra_docs/Sinatra.md +25 -0
- data/extra_docs/URLs.md +169 -0
- data/features/images.feature +47 -0
- data/features/no_processing.feature +14 -0
- data/features/rails_3.0.5.feature +8 -0
- data/features/steps/common_steps.rb +8 -0
- data/features/steps/dragonfly_steps.rb +66 -0
- data/features/steps/rails_steps.rb +28 -0
- data/features/support/env.rb +13 -0
- data/features/support/setup.rb +32 -0
- data/fixtures/rails_3.0.5/files/app/models/album.rb +7 -0
- data/fixtures/rails_3.0.5/files/app/views/albums/new.html.erb +7 -0
- data/fixtures/rails_3.0.5/files/app/views/albums/show.html.erb +6 -0
- data/fixtures/rails_3.0.5/files/config/initializers/dragonfly.rb +4 -0
- data/fixtures/rails_3.0.5/files/features/manage_album_images.feature +38 -0
- data/fixtures/rails_3.0.5/files/features/step_definitions/helper_steps.rb +7 -0
- data/fixtures/rails_3.0.5/files/features/step_definitions/image_steps.rb +25 -0
- data/fixtures/rails_3.0.5/files/features/support/paths.rb +17 -0
- data/fixtures/rails_3.0.5/files/features/text_images.feature +7 -0
- data/fixtures/rails_3.0.5/template.rb +20 -0
- data/irbrc.rb +18 -0
- data/lib/dragonfly.rb +55 -0
- data/lib/dragonfly/active_model_extensions.rb +13 -0
- data/lib/dragonfly/active_model_extensions/attachment.rb +250 -0
- data/lib/dragonfly/active_model_extensions/attachment_class_methods.rb +148 -0
- data/lib/dragonfly/active_model_extensions/class_methods.rb +95 -0
- data/lib/dragonfly/active_model_extensions/instance_methods.rb +28 -0
- data/lib/dragonfly/active_model_extensions/validations.rb +41 -0
- data/lib/dragonfly/analyser.rb +58 -0
- data/lib/dragonfly/analysis/file_command_analyser.rb +32 -0
- data/lib/dragonfly/analysis/image_magick_analyser.rb +6 -0
- data/lib/dragonfly/app.rb +172 -0
- data/lib/dragonfly/config/heroku.rb +19 -0
- data/lib/dragonfly/config/image_magick.rb +6 -0
- data/lib/dragonfly/config/rails.rb +20 -0
- data/lib/dragonfly/configurable.rb +207 -0
- data/lib/dragonfly/core_ext/array.rb +7 -0
- data/lib/dragonfly/core_ext/hash.rb +7 -0
- data/lib/dragonfly/core_ext/object.rb +12 -0
- data/lib/dragonfly/core_ext/string.rb +9 -0
- data/lib/dragonfly/core_ext/symbol.rb +9 -0
- data/lib/dragonfly/data_storage.rb +9 -0
- data/lib/dragonfly/data_storage/couch_data_store.rb +64 -0
- data/lib/dragonfly/data_storage/file_data_store.rb +141 -0
- data/lib/dragonfly/data_storage/mongo_data_store.rb +86 -0
- data/lib/dragonfly/data_storage/s3data_store.rb +145 -0
- data/lib/dragonfly/encoder.rb +13 -0
- data/lib/dragonfly/encoding/image_magick_encoder.rb +6 -0
- data/lib/dragonfly/function_manager.rb +71 -0
- data/lib/dragonfly/generation/image_magick_generator.rb +6 -0
- data/lib/dragonfly/generator.rb +9 -0
- data/lib/dragonfly/hash_with_css_style_keys.rb +21 -0
- data/lib/dragonfly/image_magick/analyser.rb +51 -0
- data/lib/dragonfly/image_magick/config.rb +41 -0
- data/lib/dragonfly/image_magick/encoder.rb +57 -0
- data/lib/dragonfly/image_magick/generator.rb +145 -0
- data/lib/dragonfly/image_magick/processor.rb +99 -0
- data/lib/dragonfly/image_magick/utils.rb +72 -0
- data/lib/dragonfly/image_magick_utils.rb +4 -0
- data/lib/dragonfly/job.rb +451 -0
- data/lib/dragonfly/job_builder.rb +39 -0
- data/lib/dragonfly/job_definitions.rb +26 -0
- data/lib/dragonfly/job_endpoint.rb +15 -0
- data/lib/dragonfly/loggable.rb +28 -0
- data/lib/dragonfly/middleware.rb +20 -0
- data/lib/dragonfly/processing/image_magick_processor.rb +6 -0
- data/lib/dragonfly/processor.rb +9 -0
- data/lib/dragonfly/rails/images.rb +27 -0
- data/lib/dragonfly/response.rb +97 -0
- data/lib/dragonfly/routed_endpoint.rb +40 -0
- data/lib/dragonfly/serializer.rb +32 -0
- data/lib/dragonfly/server.rb +113 -0
- data/lib/dragonfly/simple_cache.rb +23 -0
- data/lib/dragonfly/temp_object.rb +175 -0
- data/lib/dragonfly/url_mapper.rb +78 -0
- data/samples/beach.png +0 -0
- data/samples/egg.png +0 -0
- data/samples/round.gif +0 -0
- data/samples/sample.docx +0 -0
- data/samples/taj.jpg +0 -0
- data/spec/dragonfly/active_model_extensions/model_spec.rb +1426 -0
- data/spec/dragonfly/active_model_extensions/spec_helper.rb +91 -0
- data/spec/dragonfly/analyser_spec.rb +123 -0
- data/spec/dragonfly/analysis/file_command_analyser_spec.rb +48 -0
- data/spec/dragonfly/app_spec.rb +135 -0
- data/spec/dragonfly/configurable_spec.rb +461 -0
- data/spec/dragonfly/core_ext/array_spec.rb +19 -0
- data/spec/dragonfly/core_ext/hash_spec.rb +19 -0
- data/spec/dragonfly/core_ext/string_spec.rb +17 -0
- data/spec/dragonfly/core_ext/symbol_spec.rb +17 -0
- data/spec/dragonfly/data_storage/couch_data_store_spec.rb +76 -0
- data/spec/dragonfly/data_storage/file_data_store_spec.rb +296 -0
- data/spec/dragonfly/data_storage/mongo_data_store_spec.rb +57 -0
- data/spec/dragonfly/data_storage/s3_data_store_spec.rb +258 -0
- data/spec/dragonfly/data_storage/shared_data_store_examples.rb +77 -0
- data/spec/dragonfly/function_manager_spec.rb +154 -0
- data/spec/dragonfly/hash_with_css_style_keys_spec.rb +24 -0
- data/spec/dragonfly/image_magick/analyser_spec.rb +64 -0
- data/spec/dragonfly/image_magick/encoder_spec.rb +41 -0
- data/spec/dragonfly/image_magick/generator_spec.rb +172 -0
- data/spec/dragonfly/image_magick/processor_spec.rb +233 -0
- data/spec/dragonfly/image_magick/utils_spec.rb +18 -0
- data/spec/dragonfly/job_builder_spec.rb +37 -0
- data/spec/dragonfly/job_definitions_spec.rb +35 -0
- data/spec/dragonfly/job_endpoint_spec.rb +173 -0
- data/spec/dragonfly/job_spec.rb +1046 -0
- data/spec/dragonfly/loggable_spec.rb +80 -0
- data/spec/dragonfly/middleware_spec.rb +47 -0
- data/spec/dragonfly/routed_endpoint_spec.rb +48 -0
- data/spec/dragonfly/serializer_spec.rb +61 -0
- data/spec/dragonfly/server_spec.rb +278 -0
- data/spec/dragonfly/simple_cache_spec.rb +27 -0
- data/spec/dragonfly/temp_object_spec.rb +306 -0
- data/spec/dragonfly/url_mapper_spec.rb +126 -0
- data/spec/functional/deprecations_spec.rb +51 -0
- data/spec/functional/image_magick_app_spec.rb +27 -0
- data/spec/functional/model_urls_spec.rb +85 -0
- data/spec/functional/remote_on_the_fly_spec.rb +51 -0
- data/spec/functional/to_response_spec.rb +31 -0
- data/spec/spec_helper.rb +51 -0
- data/spec/support/argument_matchers.rb +19 -0
- data/spec/support/image_matchers.rb +47 -0
- data/spec/support/simple_matchers.rb +53 -0
- data/yard/handlers/configurable_attr_handler.rb +38 -0
- data/yard/setup.rb +15 -0
- data/yard/templates/default/fulldoc/html/css/common.css +107 -0
- data/yard/templates/default/layout/html/layout.erb +89 -0
- data/yard/templates/default/module/html/configuration_summary.erb +31 -0
- data/yard/templates/default/module/setup.rb +17 -0
- metadata +544 -0
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Dragonfly::ImageMagick::Utils do
|
4
|
+
|
5
|
+
before(:each) do
|
6
|
+
@obj = Object.new
|
7
|
+
@obj.extend(Dragonfly::ImageMagick::Utils)
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should raise an error if the identify command isn't found" do
|
11
|
+
suppressing_stderr do
|
12
|
+
lambda{
|
13
|
+
@obj.send(:run, "non-existent-command")
|
14
|
+
}.should raise_error(Dragonfly::ImageMagick::Utils::ShellCommandFailed)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Dragonfly::JobBuilder do
|
4
|
+
|
5
|
+
describe "a multi-step job" do
|
6
|
+
|
7
|
+
before(:each) do
|
8
|
+
@job_builder = Dragonfly::JobBuilder.new do |size, format|
|
9
|
+
process :thumb, size
|
10
|
+
encode format unless format.nil?
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should correctly call job steps" do
|
15
|
+
job = mock
|
16
|
+
job.should_receive(:process).with(:thumb, '30x30#').and_return(job2=mock)
|
17
|
+
job2.should_receive(:encode).with(:jpg).and_return(job3=mock)
|
18
|
+
@job_builder.build(job, '30x30#', :jpg).should == job3
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should work consistently with bang methods" do
|
22
|
+
job = mock
|
23
|
+
job.should_receive(:process!).with(:thumb, '30x30#').and_return(job)
|
24
|
+
job.should_receive(:encode!).with(:jpg).and_return(job)
|
25
|
+
@job_builder.build!(job, '30x30#', :jpg).should == job
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should yield nil if the arg isn't passed in" do
|
29
|
+
job = mock
|
30
|
+
job.should_receive(:process).with(:thumb, '30x30#').and_return(job2=mock)
|
31
|
+
job2.should_not_receive(:encode)
|
32
|
+
@job_builder.build(job, '30x30#').should == job2
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Dragonfly::JobDefinitions do
|
4
|
+
|
5
|
+
describe "defining jobs" do
|
6
|
+
|
7
|
+
before(:each) do
|
8
|
+
@job_definitions = Dragonfly::JobDefinitions.new
|
9
|
+
@object = Object.new
|
10
|
+
@object.extend @job_definitions
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "a simple job" do
|
14
|
+
|
15
|
+
before(:each) do
|
16
|
+
@job_definitions.add :thumb do |size|
|
17
|
+
process :thumb, size
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
it "correctly call job steps" do
|
22
|
+
@object.should_receive(:process).with(:thumb, '30x30#').and_return(job=mock)
|
23
|
+
@object.thumb('30x30#').should == job
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should correctly call job steps when bang is given" do
|
27
|
+
@object.should_receive(:process!).with(:thumb, '30x30#').and_return(@object)
|
28
|
+
@object.thumb!('30x30#').should == @object
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
@@ -0,0 +1,173 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
## General tests for Response go here as it's a pretty simple wrapper around that
|
5
|
+
|
6
|
+
describe "Dragonfly::JobEndpoint Rack::Lint tests" do
|
7
|
+
before(:each) do
|
8
|
+
@app = test_app
|
9
|
+
@app.generator.add(:test_data){ "Test Data" }
|
10
|
+
@job = @app.generate(:test_data)
|
11
|
+
@endpoint = Rack::Lint.new(Dragonfly::JobEndpoint.new(@job))
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should pass for HEAD requests" do
|
15
|
+
Rack::MockRequest.new(@endpoint).request("HEAD", '')
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should pass for GET requests" do
|
19
|
+
Rack::MockRequest.new(@endpoint).request("GET", '')
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should pass for POST requests" do
|
23
|
+
Rack::MockRequest.new(@endpoint).request("POST", '')
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should pass for PUT requests" do
|
27
|
+
Rack::MockRequest.new(@endpoint).request("PUT", '')
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should pass for DELETE requests" do
|
31
|
+
Rack::MockRequest.new(@endpoint).request("DELETE", '')
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe Dragonfly::JobEndpoint do
|
36
|
+
|
37
|
+
def make_request(job, opts={})
|
38
|
+
endpoint = Dragonfly::JobEndpoint.new(job)
|
39
|
+
method = (opts.delete(:method) || :get).to_s.upcase
|
40
|
+
Rack::MockRequest.new(endpoint).request(method, '', opts)
|
41
|
+
end
|
42
|
+
|
43
|
+
before(:each) do
|
44
|
+
@app = test_app
|
45
|
+
@app.datastore.stub!(:retrieve).with('egg').and_return(["GUNGLE", {:name => 'gung.txt'}])
|
46
|
+
@job = @app.new_job.fetch('egg')
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should return a correct response to a successful GET request" do
|
50
|
+
response = make_request(@job)
|
51
|
+
response.status.should == 200
|
52
|
+
response['ETag'].should =~ /^"\w+"$/
|
53
|
+
response['Cache-Control'].should == "public, max-age=31536000"
|
54
|
+
response['Content-Type'].should == 'text/plain'
|
55
|
+
response['Content-Length'].should == '6'
|
56
|
+
response['Content-Disposition'].should == 'filename="gung.txt"'
|
57
|
+
response.body.should == 'GUNGLE'
|
58
|
+
end
|
59
|
+
|
60
|
+
it "should return the correct headers and no content to a successful HEAD request" do
|
61
|
+
response = make_request(@job, :method => :head)
|
62
|
+
response.status.should == 200
|
63
|
+
response['ETag'].should =~ /^"\w+"$/
|
64
|
+
response['Cache-Control'].should == "public, max-age=31536000"
|
65
|
+
response['Content-Type'].should == 'text/plain'
|
66
|
+
response['Content-Length'].should == '6'
|
67
|
+
response['Content-Disposition'].should == 'filename="gung.txt"'
|
68
|
+
response.body.should == ''
|
69
|
+
end
|
70
|
+
|
71
|
+
%w(POST PUT DELETE CUSTOM_METHOD).each do |method|
|
72
|
+
|
73
|
+
it "should return a 405 error for a #{method} request" do
|
74
|
+
response = make_request(@job, :method => method)
|
75
|
+
response.status.should == 405
|
76
|
+
response['Allow'].should == "GET, HEAD"
|
77
|
+
response['Content-Type'].should == 'text/plain'
|
78
|
+
response.body.should == "#{method} method not allowed"
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
|
83
|
+
it "should return 404 if the datastore raises data not found" do
|
84
|
+
@job.should_receive(:apply).and_raise(Dragonfly::DataStorage::DataNotFound)
|
85
|
+
response = make_request(@job)
|
86
|
+
response.status.should == 404
|
87
|
+
end
|
88
|
+
|
89
|
+
describe "ETag" do
|
90
|
+
it "should return an ETag" do
|
91
|
+
response = make_request(@job)
|
92
|
+
response.headers['ETag'].should =~ /^"\w+"$/
|
93
|
+
end
|
94
|
+
|
95
|
+
[
|
96
|
+
"dingle",
|
97
|
+
"dingle, eggheads",
|
98
|
+
'"dingle", "eggheads"',
|
99
|
+
'*'
|
100
|
+
].each do |header|
|
101
|
+
it "should return a 304 if the correct ETag is specified in HTTP_IF_NONE_MATCH header e.g. #{header}" do
|
102
|
+
@job.should_receive(:unique_signature).at_least(:once).and_return('dingle')
|
103
|
+
response = make_request(@job, 'HTTP_IF_NONE_MATCH' => header)
|
104
|
+
response.status.should == 304
|
105
|
+
response['ETag'].should == '"dingle"'
|
106
|
+
response['Cache-Control'].should == "public, max-age=31536000"
|
107
|
+
response.body.should be_empty
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
it "should not have applied any steps if the correct ETag is specified in HTTP_IF_NONE_MATCH header" do
|
112
|
+
response = make_request(@job, 'HTTP_IF_NONE_MATCH' => @job.unique_signature)
|
113
|
+
@job.applied_steps.should be_empty
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
describe "Content Disposition" do
|
118
|
+
before(:each) do
|
119
|
+
@app.encoder.add{|temp_object, format| temp_object }
|
120
|
+
end
|
121
|
+
|
122
|
+
describe "filename" do
|
123
|
+
it "should return the original name" do
|
124
|
+
response = make_request(@job)
|
125
|
+
response['Content-Disposition'].should == 'filename="gung.txt"'
|
126
|
+
end
|
127
|
+
it "should return a filename with a different extension if it's been encoded" do
|
128
|
+
response = make_request(@job.encode(:doogs))
|
129
|
+
response['Content-Disposition'].should == 'filename="gung.doogs"'
|
130
|
+
end
|
131
|
+
it "should not have the filename if name doesn't exist" do
|
132
|
+
response = make_request(@app.new_job("ADFSDF"))
|
133
|
+
response['Content-Disposition'].should be_nil
|
134
|
+
end
|
135
|
+
it "should cope with filenames with no ext" do
|
136
|
+
response = make_request(@app.new_job("ASDF", :name => 'asdf'))
|
137
|
+
response['Content-Disposition'].should == 'filename="asdf"'
|
138
|
+
end
|
139
|
+
it "should uri encode funny characters" do
|
140
|
+
response = make_request(@app.new_job("ASDF", :name => '£@$£ `'))
|
141
|
+
response['Content-Disposition'].should == 'filename="%C2%A3@$%C2%A3%20%60"'
|
142
|
+
end
|
143
|
+
it "should allow for setting the filename using a block" do
|
144
|
+
@app.content_filename = proc{|job, request|
|
145
|
+
job.basename.reverse.upcase + request['a']
|
146
|
+
}
|
147
|
+
response = make_request(@job, 'QUERY_STRING' => 'a=egg')
|
148
|
+
response['Content-Disposition'].should == 'filename="GNUGegg"'
|
149
|
+
end
|
150
|
+
it "should not include the filename if configured to be nil" do
|
151
|
+
@app.content_filename = nil
|
152
|
+
response = make_request(@job)
|
153
|
+
response['Content-Disposition'].should be_nil
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
describe "content disposition" do
|
158
|
+
it "should use the app's configured content-disposition" do
|
159
|
+
@app.content_disposition = :attachment
|
160
|
+
response = make_request(@job)
|
161
|
+
response['Content-Disposition'].should == 'attachment; filename="gung.txt"'
|
162
|
+
end
|
163
|
+
it "should allow using a block to set the content disposition" do
|
164
|
+
@app.content_disposition = proc{|job, request|
|
165
|
+
job.basename + request['blah']
|
166
|
+
}
|
167
|
+
response = make_request(@job, 'QUERY_STRING' => 'blah=yo')
|
168
|
+
response['Content-Disposition'].should == 'gungyo; filename="gung.txt"'
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
end
|
@@ -0,0 +1,1046 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
# Matchers
|
4
|
+
RSpec::Matchers.define :match_steps do |steps|
|
5
|
+
match do |given|
|
6
|
+
given.map{|step| step.class } == steps
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
describe Dragonfly::Job do
|
11
|
+
|
12
|
+
describe "Step types" do
|
13
|
+
|
14
|
+
{
|
15
|
+
Dragonfly::Job::Fetch => :fetch,
|
16
|
+
Dragonfly::Job::Process => :process,
|
17
|
+
Dragonfly::Job::Encode => :encode,
|
18
|
+
Dragonfly::Job::Generate => :generate,
|
19
|
+
Dragonfly::Job::FetchFile => :fetch_file,
|
20
|
+
Dragonfly::Job::FetchUrl => :fetch_url
|
21
|
+
}.each do |klass, step_name|
|
22
|
+
it "should return the correct step name for #{klass}" do
|
23
|
+
klass.step_name.should == step_name
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
{
|
28
|
+
Dragonfly::Job::Fetch => :f,
|
29
|
+
Dragonfly::Job::Process => :p,
|
30
|
+
Dragonfly::Job::Encode => :e,
|
31
|
+
Dragonfly::Job::Generate => :g,
|
32
|
+
Dragonfly::Job::FetchFile => :ff,
|
33
|
+
Dragonfly::Job::FetchUrl => :fu
|
34
|
+
}.each do |klass, abbreviation|
|
35
|
+
it "should return the correct abbreviation for #{klass}" do
|
36
|
+
klass.abbreviation.should == abbreviation
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe "step_names" do
|
41
|
+
it "should return the available step names" do
|
42
|
+
Dragonfly::Job.step_names.should == [:fetch, :process, :encode, :generate, :fetch_file, :fetch_url]
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
describe "without content" do
|
49
|
+
|
50
|
+
before(:each) do
|
51
|
+
@app = mock_app
|
52
|
+
@job = Dragonfly::Job.new(@app)
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should allow initializing with content" do
|
56
|
+
job = Dragonfly::Job.new(@app, 'eggheads')
|
57
|
+
job.data.should == 'eggheads'
|
58
|
+
end
|
59
|
+
|
60
|
+
describe "fetch" do
|
61
|
+
before(:each) do
|
62
|
+
@job.fetch!('some_uid')
|
63
|
+
end
|
64
|
+
|
65
|
+
it { @job.steps.should match_steps([Dragonfly::Job::Fetch]) }
|
66
|
+
|
67
|
+
it "should retrieve from the app's datastore when applied" do
|
68
|
+
@app.datastore.should_receive(:retrieve).with('some_uid').and_return('HELLO')
|
69
|
+
@job.data.should == 'HELLO'
|
70
|
+
end
|
71
|
+
|
72
|
+
it "should set extra data if returned from the datastore" do
|
73
|
+
@app.datastore.should_receive(:retrieve).with('some_uid').and_return(['HELLO', {:name => 'test.txt'}])
|
74
|
+
@job.data.should == 'HELLO'
|
75
|
+
@job.meta.should == {:name => 'test.txt'}
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
describe "process" do
|
80
|
+
it "should raise an error when applying" do
|
81
|
+
@job.process!(:resize, '20x30')
|
82
|
+
lambda{
|
83
|
+
@job.apply
|
84
|
+
}.should raise_error(Dragonfly::Job::NothingToProcess)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
describe "encode" do
|
89
|
+
it "should raise an error when applying" do
|
90
|
+
@job.encode!(:gif)
|
91
|
+
lambda{
|
92
|
+
@job.apply
|
93
|
+
}.should raise_error(Dragonfly::Job::NothingToEncode)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
describe "analyse" do
|
98
|
+
it "should raise an error" do
|
99
|
+
lambda{
|
100
|
+
@job.analyse(:width)
|
101
|
+
}.should raise_error(Dragonfly::Job::NothingToAnalyse)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
describe "generate" do
|
106
|
+
before(:each) do
|
107
|
+
@job.generate!(:plasma, 20, 30)
|
108
|
+
end
|
109
|
+
|
110
|
+
it { @job.steps.should match_steps([Dragonfly::Job::Generate]) }
|
111
|
+
|
112
|
+
it "should use the generator when applied" do
|
113
|
+
@app.generator.should_receive(:generate).with(:plasma, 20, 30).and_return('hi')
|
114
|
+
@job.data.should == 'hi'
|
115
|
+
end
|
116
|
+
|
117
|
+
it "should save extra data if the generator returns it" do
|
118
|
+
@app.generator.should_receive(:generate).with(:plasma, 20, 30).and_return(['hi', {:name => 'plasma.png'}])
|
119
|
+
@job.data.should == 'hi'
|
120
|
+
@job.meta.should == {:name => 'plasma.png'}
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
describe "fetch_file" do
|
125
|
+
before(:each) do
|
126
|
+
@job.fetch_file!(File.dirname(__FILE__) + '/../../samples/egg.png')
|
127
|
+
end
|
128
|
+
|
129
|
+
it { @job.steps.should match_steps([Dragonfly::Job::FetchFile]) }
|
130
|
+
|
131
|
+
it "should fetch the specified file when applied" do
|
132
|
+
@job.size.should == 62664
|
133
|
+
end
|
134
|
+
|
135
|
+
it "should set the name" do
|
136
|
+
@job.meta[:name].should == 'egg.png'
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
describe "fetch_url" do
|
141
|
+
before(:each) do
|
142
|
+
stub_request(:get, 'http://some.place.com').to_return(:body => 'result!')
|
143
|
+
stub_request(:get, 'https://some.place.com').to_return(:body => 'secure result!')
|
144
|
+
end
|
145
|
+
|
146
|
+
it {
|
147
|
+
@job.fetch_url!('some.url')
|
148
|
+
@job.steps.should match_steps([Dragonfly::Job::FetchUrl])
|
149
|
+
}
|
150
|
+
|
151
|
+
it "should fetch the specified url when applied" do
|
152
|
+
@job.fetch_url!('http://some.place.com')
|
153
|
+
@job.data.should == "result!"
|
154
|
+
end
|
155
|
+
|
156
|
+
it "should default to http" do
|
157
|
+
@job.fetch_url!('some.place.com')
|
158
|
+
@job.data.should == "result!"
|
159
|
+
end
|
160
|
+
|
161
|
+
it "should also work with https" do
|
162
|
+
@job.fetch_url!('https://some.place.com')
|
163
|
+
@job.data.should == "secure result!"
|
164
|
+
end
|
165
|
+
|
166
|
+
it "should set the name if there is one" do
|
167
|
+
@job.fetch_url!('some.place.com/dung.beetle')
|
168
|
+
@job.meta[:name].should == 'dung.beetle'
|
169
|
+
end
|
170
|
+
|
171
|
+
["some.place.com", "some.place.com/", "some.place.com/eggs/"].each do |url|
|
172
|
+
it "should not set the name if there isn't one, e.g. #{url}" do
|
173
|
+
@job.fetch_url!(url)
|
174
|
+
@job.meta[:name].should be_nil
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
end
|
180
|
+
|
181
|
+
describe "with content already there" do
|
182
|
+
|
183
|
+
before(:each) do
|
184
|
+
@app = mock_app
|
185
|
+
@job = Dragonfly::Job.new(@app, 'HELLO', :name => 'hello.txt', :a => :b)
|
186
|
+
@temp_object = @job.temp_object
|
187
|
+
end
|
188
|
+
|
189
|
+
describe "apply" do
|
190
|
+
it "should return itself" do
|
191
|
+
@job.apply.should == @job
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
describe "process" do
|
196
|
+
before(:each) do
|
197
|
+
@job.process!(:resize, '20x30')
|
198
|
+
end
|
199
|
+
|
200
|
+
it { @job.steps.should match_steps([Dragonfly::Job::Process]) }
|
201
|
+
|
202
|
+
it "should use the processor when applied" do
|
203
|
+
@app.processor.should_receive(:process).with(@temp_object, :resize, '20x30').and_return('hi')
|
204
|
+
@job.data.should == 'hi'
|
205
|
+
end
|
206
|
+
|
207
|
+
it "should maintain the meta attributes" do
|
208
|
+
@app.processor.should_receive(:process).with(@temp_object, :resize, '20x30').and_return('hi')
|
209
|
+
@job.data.should == 'hi'
|
210
|
+
@job.meta.should == {:name => 'hello.txt', :a => :b}
|
211
|
+
end
|
212
|
+
|
213
|
+
it "should allow returning an array with extra attributes from the processor" do
|
214
|
+
@app.processor.should_receive(:process).with(@temp_object, :resize, '20x30').and_return(['hi', {:name => 'hello_20x30.txt', :eggs => 'asdf'}])
|
215
|
+
@job.data.should == 'hi'
|
216
|
+
@job.meta.should == {:name => 'hello_20x30.txt', :a => :b, :eggs => 'asdf'}
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
describe "encode" do
|
221
|
+
before(:each) do
|
222
|
+
@job.encode!(:gif, :bitrate => 'mumma')
|
223
|
+
end
|
224
|
+
|
225
|
+
it { @job.steps.should match_steps([Dragonfly::Job::Encode]) }
|
226
|
+
|
227
|
+
it "should use the encoder when applied" do
|
228
|
+
@app.encoder.should_receive(:encode).with(@temp_object, :gif, :bitrate => 'mumma').and_return('alo')
|
229
|
+
@job.data.should == 'alo'
|
230
|
+
end
|
231
|
+
|
232
|
+
it "should maintain the meta and update the format" do
|
233
|
+
@app.encoder.should_receive(:encode).with(@temp_object, :gif, :bitrate => 'mumma').and_return('alo')
|
234
|
+
@job.data.should == 'alo'
|
235
|
+
@job.meta.should == {:name => 'hello.txt', :a => :b, :format => :gif}
|
236
|
+
end
|
237
|
+
|
238
|
+
it "should update the format even when not applied" do
|
239
|
+
@app.encoder.should_not_receive(:encode)
|
240
|
+
@job.meta[:format].should == :gif
|
241
|
+
end
|
242
|
+
|
243
|
+
it "should allow returning an array with extra attributes form the encoder" do
|
244
|
+
@app.encoder.should_receive(:encode).with(@temp_object, :gif, :bitrate => 'mumma').and_return(['alo', {:name => 'doobie', :eggs => 'fish'}])
|
245
|
+
@job.data.should == 'alo'
|
246
|
+
@job.meta.should == {:name => 'doobie', :a => :b, :eggs => 'fish', :format => :gif}
|
247
|
+
end
|
248
|
+
|
249
|
+
it "not allow overriding the format" do
|
250
|
+
@app.encoder.should_receive(:encode).with(@temp_object, :gif, :bitrate => 'mumma').and_return(['alo', {:format => :png}])
|
251
|
+
@job.apply.meta[:format].should == :gif
|
252
|
+
end
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
describe "analysis" do
|
257
|
+
before(:each) do
|
258
|
+
@app = test_app
|
259
|
+
@job = @app.new_job('HELLO')
|
260
|
+
@app.analyser.add(:num_letters){|temp_object, letter| temp_object.data.count(letter) }
|
261
|
+
end
|
262
|
+
it "should return correctly when calling analyse" do
|
263
|
+
@job.analyse(:num_letters, 'L').should == 2
|
264
|
+
end
|
265
|
+
it "should have mixed in the analyser method" do
|
266
|
+
@job.num_letters('L').should == 2
|
267
|
+
end
|
268
|
+
it "should return nil from analyse if calling any old method" do
|
269
|
+
@job.analyse(:robin_van_persie).should be_nil
|
270
|
+
end
|
271
|
+
it "should not allow calling any old method" do
|
272
|
+
lambda{
|
273
|
+
@job.robin_van_persie
|
274
|
+
}.should raise_error(NoMethodError)
|
275
|
+
end
|
276
|
+
it "should work correctly with chained jobs, applying before analysing" do
|
277
|
+
@app.processor.add(:double){|temp_object| temp_object.data * 2 }
|
278
|
+
@job.process(:double).num_letters('L').should == 4
|
279
|
+
end
|
280
|
+
end
|
281
|
+
|
282
|
+
describe "defining extra steps after applying" do
|
283
|
+
before(:each) do
|
284
|
+
@app = mock_app
|
285
|
+
@job = Dragonfly::Job.new(@app)
|
286
|
+
@job.temp_object = Dragonfly::TempObject.new("hello")
|
287
|
+
@job.process! :resize
|
288
|
+
@job.apply
|
289
|
+
@job.encode! :micky
|
290
|
+
end
|
291
|
+
it "should not call apply on already applied steps" do
|
292
|
+
@job.steps[0].should_not_receive(:apply)
|
293
|
+
@job.apply
|
294
|
+
end
|
295
|
+
it "should call apply on not yet applied steps" do
|
296
|
+
@job.steps[1].should_receive(:apply)
|
297
|
+
@job.apply
|
298
|
+
end
|
299
|
+
it "should return all steps" do
|
300
|
+
@job.steps.should match_steps([
|
301
|
+
Dragonfly::Job::Process,
|
302
|
+
Dragonfly::Job::Encode
|
303
|
+
])
|
304
|
+
end
|
305
|
+
it "should return applied steps" do
|
306
|
+
@job.applied_steps.should match_steps([
|
307
|
+
Dragonfly::Job::Process
|
308
|
+
])
|
309
|
+
end
|
310
|
+
it "should return the pending steps" do
|
311
|
+
@job.pending_steps.should match_steps([
|
312
|
+
Dragonfly::Job::Encode
|
313
|
+
])
|
314
|
+
end
|
315
|
+
it "should not call apply on any steps when already applied" do
|
316
|
+
@job.apply
|
317
|
+
@job.steps[0].should_not_receive(:apply)
|
318
|
+
@job.steps[1].should_not_receive(:apply)
|
319
|
+
@job.apply
|
320
|
+
end
|
321
|
+
end
|
322
|
+
|
323
|
+
describe "chaining" do
|
324
|
+
|
325
|
+
before(:each) do
|
326
|
+
@app = mock_app
|
327
|
+
@job = Dragonfly::Job.new(@app)
|
328
|
+
end
|
329
|
+
|
330
|
+
it "should return itself if bang is used" do
|
331
|
+
@job.fetch!('some_uid').should == @job
|
332
|
+
end
|
333
|
+
|
334
|
+
it "should return a new job if bang is not used" do
|
335
|
+
@job.fetch('some_uid').should_not == @job
|
336
|
+
end
|
337
|
+
|
338
|
+
describe "when a chained job is defined" do
|
339
|
+
before(:each) do
|
340
|
+
@job.fetch!('some_uid')
|
341
|
+
@job2 = @job.process(:resize, '30x30')
|
342
|
+
end
|
343
|
+
|
344
|
+
it "should return the correct steps for the original job" do
|
345
|
+
@job.applied_steps.should match_steps([
|
346
|
+
])
|
347
|
+
@job.pending_steps.should match_steps([
|
348
|
+
Dragonfly::Job::Fetch
|
349
|
+
])
|
350
|
+
end
|
351
|
+
|
352
|
+
it "should return the correct data for the original job" do
|
353
|
+
@job.data.should == 'SOME_DATA'
|
354
|
+
end
|
355
|
+
|
356
|
+
it "should return the correct steps for the new job" do
|
357
|
+
@job2.applied_steps.should match_steps([
|
358
|
+
])
|
359
|
+
@job2.pending_steps.should match_steps([
|
360
|
+
Dragonfly::Job::Fetch,
|
361
|
+
Dragonfly::Job::Process
|
362
|
+
])
|
363
|
+
end
|
364
|
+
|
365
|
+
it "should return the correct data for the new job" do
|
366
|
+
@job2.data.should == 'SOME_PROCESSED_DATA'
|
367
|
+
end
|
368
|
+
|
369
|
+
it "should not affect the other one when one is applied" do
|
370
|
+
@job.apply
|
371
|
+
@job.applied_steps.should match_steps([
|
372
|
+
Dragonfly::Job::Fetch
|
373
|
+
])
|
374
|
+
@job.pending_steps.should match_steps([
|
375
|
+
])
|
376
|
+
@job.temp_object.data.should == 'SOME_DATA'
|
377
|
+
@job2.applied_steps.should match_steps([
|
378
|
+
])
|
379
|
+
@job2.pending_steps.should match_steps([
|
380
|
+
Dragonfly::Job::Fetch,
|
381
|
+
Dragonfly::Job::Process
|
382
|
+
])
|
383
|
+
@job2.temp_object.should be_nil
|
384
|
+
end
|
385
|
+
end
|
386
|
+
|
387
|
+
end
|
388
|
+
|
389
|
+
describe "applied?" do
|
390
|
+
before(:each) do
|
391
|
+
@app = test_app
|
392
|
+
end
|
393
|
+
it "should return true when empty" do
|
394
|
+
@app.new_job.should be_applied
|
395
|
+
end
|
396
|
+
it "should return false when not applied" do
|
397
|
+
@app.fetch('eggs').should_not be_applied
|
398
|
+
end
|
399
|
+
it "should return true when applied" do
|
400
|
+
@app.datastore.should_receive(:retrieve).with('eggs').and_return("cracked")
|
401
|
+
job = @app.fetch('eggs').apply
|
402
|
+
job.should be_applied
|
403
|
+
end
|
404
|
+
end
|
405
|
+
|
406
|
+
describe "to_a" do
|
407
|
+
before(:each) do
|
408
|
+
@app = mock_app
|
409
|
+
end
|
410
|
+
it "should represent all the steps in array form" do
|
411
|
+
job = Dragonfly::Job.new(@app)
|
412
|
+
job.fetch! 'some_uid'
|
413
|
+
job.generate! :plasma # you wouldn't really call this after fetch but still works
|
414
|
+
job.process! :resize, '30x40'
|
415
|
+
job.encode! :gif, :bitrate => 20
|
416
|
+
job.to_a.should == [
|
417
|
+
[:f, 'some_uid'],
|
418
|
+
[:g, :plasma],
|
419
|
+
[:p, :resize, '30x40'],
|
420
|
+
[:e, :gif, {:bitrate => 20}]
|
421
|
+
]
|
422
|
+
end
|
423
|
+
end
|
424
|
+
|
425
|
+
describe "from_a" do
|
426
|
+
|
427
|
+
before(:each) do
|
428
|
+
@app = test_app
|
429
|
+
end
|
430
|
+
|
431
|
+
describe "a well-defined array" do
|
432
|
+
before(:each) do
|
433
|
+
@job = Dragonfly::Job.from_a([
|
434
|
+
[:f, 'some_uid'],
|
435
|
+
[:g, :plasma],
|
436
|
+
[:p, :resize, '30x40'],
|
437
|
+
[:e, :gif, {:bitrate => 20}]
|
438
|
+
], @app)
|
439
|
+
end
|
440
|
+
it "should have the correct step types" do
|
441
|
+
@job.steps.should match_steps([
|
442
|
+
Dragonfly::Job::Fetch,
|
443
|
+
Dragonfly::Job::Generate,
|
444
|
+
Dragonfly::Job::Process,
|
445
|
+
Dragonfly::Job::Encode
|
446
|
+
])
|
447
|
+
end
|
448
|
+
it "should have the correct args" do
|
449
|
+
@job.steps[0].args.should == ['some_uid']
|
450
|
+
@job.steps[1].args.should == [:plasma]
|
451
|
+
@job.steps[2].args.should == [:resize, '30x40']
|
452
|
+
@job.steps[3].args.should == [:gif, {:bitrate => 20}]
|
453
|
+
end
|
454
|
+
it "should have no applied steps" do
|
455
|
+
@job.applied_steps.should be_empty
|
456
|
+
end
|
457
|
+
it "should have all steps pending" do
|
458
|
+
@job.steps.should == @job.pending_steps
|
459
|
+
end
|
460
|
+
end
|
461
|
+
|
462
|
+
[
|
463
|
+
:f,
|
464
|
+
[:f],
|
465
|
+
[[]],
|
466
|
+
[[:egg]]
|
467
|
+
].each do |object|
|
468
|
+
it "should raise an error if the object passed in is #{object.inspect}" do
|
469
|
+
lambda {
|
470
|
+
Dragonfly::Job.from_a(object, @app)
|
471
|
+
}.should raise_error(Dragonfly::Job::InvalidArray)
|
472
|
+
end
|
473
|
+
end
|
474
|
+
|
475
|
+
it "should initialize an empty job if the array is empty" do
|
476
|
+
job = Dragonfly::Job.from_a([], @app)
|
477
|
+
job.steps.should be_empty
|
478
|
+
end
|
479
|
+
end
|
480
|
+
|
481
|
+
describe "serialization" do
|
482
|
+
before(:each) do
|
483
|
+
@app = test_app
|
484
|
+
@job = Dragonfly::Job.new(@app).fetch('uid').process(:resize_and_crop, :width => 270, :height => 92, :gravity => 'n')
|
485
|
+
end
|
486
|
+
it "should serialize itself" do
|
487
|
+
@job.serialize.should =~ /^\w{1,}$/
|
488
|
+
end
|
489
|
+
it "should deserialize to the same as the original" do
|
490
|
+
new_job = Dragonfly::Job.deserialize(@job.serialize, @app)
|
491
|
+
new_job.to_a.should == @job.to_a
|
492
|
+
end
|
493
|
+
it "should correctly deserialize a string serialized with ruby 1.8.7" do
|
494
|
+
job = Dragonfly::Job.deserialize('BAhbB1sHOgZmSSIIdWlkBjoGRVRbCDoGcDoUcmVzaXplX2FuZF9jcm9wewg6CndpZHRoaQIOAToLaGVpZ2h0aWE6DGdyYXZpdHlJIgZuBjsGVA', @app)
|
495
|
+
job.to_a.should == @job.to_a
|
496
|
+
end
|
497
|
+
it "should correctly deserialize a string serialized with ruby 1.9.2" do
|
498
|
+
job = Dragonfly::Job.deserialize('BAhbB1sHOgZmIgh1aWRbCDoGcDoUcmVzaXplX2FuZF9jcm9wewg6CndpZHRoaQIOAToLaGVpZ2h0aWE6DGdyYXZpdHkiBm4', @app)
|
499
|
+
job.to_a.should == @job.to_a
|
500
|
+
end
|
501
|
+
end
|
502
|
+
|
503
|
+
describe "to_app" do
|
504
|
+
before(:each) do
|
505
|
+
@app = test_app
|
506
|
+
@job = Dragonfly::Job.new(@app)
|
507
|
+
end
|
508
|
+
it "should return an endpoint" do
|
509
|
+
endpoint = @job.to_app
|
510
|
+
endpoint.should be_a(Dragonfly::JobEndpoint)
|
511
|
+
endpoint.job.should == @job
|
512
|
+
end
|
513
|
+
end
|
514
|
+
|
515
|
+
describe "url" do
|
516
|
+
before(:each) do
|
517
|
+
@app = test_app
|
518
|
+
@job = Dragonfly::Job.new(@app)
|
519
|
+
end
|
520
|
+
|
521
|
+
it "should return nil if there are no steps" do
|
522
|
+
@job.url.should be_nil
|
523
|
+
end
|
524
|
+
|
525
|
+
describe "using meta in the url" do
|
526
|
+
before(:each) do
|
527
|
+
@app.server.url_format = '/media/:job/:zoo'
|
528
|
+
@job.generate!(:fish)
|
529
|
+
end
|
530
|
+
it "should act as per usual if no params given" do
|
531
|
+
@job.url.should == "/media/#{@job.serialize}"
|
532
|
+
end
|
533
|
+
it "should add given params" do
|
534
|
+
@job.url(:zoo => 'jokes', :on => 'me').should == "/media/#{@job.serialize}/jokes?on=me"
|
535
|
+
end
|
536
|
+
it "should use the meta if it exists" do
|
537
|
+
@job.meta[:zoo] = 'hair'
|
538
|
+
@job.url.should == "/media/#{@job.serialize}/hair"
|
539
|
+
end
|
540
|
+
it "should not add an meta that isn't needed" do
|
541
|
+
@job.meta[:gump] = 'flub'
|
542
|
+
@job.url.should == "/media/#{@job.serialize}"
|
543
|
+
end
|
544
|
+
it "should override if a param is passed in" do
|
545
|
+
@job.meta[:zoo] = 'hair'
|
546
|
+
@job.url(:zoo => 'dare').should == "/media/#{@job.serialize}/dare"
|
547
|
+
end
|
548
|
+
|
549
|
+
describe "basename" do
|
550
|
+
before(:each) do
|
551
|
+
@app.server.url_format = '/:job/:basename'
|
552
|
+
@job.meta = {:name => 'hello.egg', :basename => 'hi'}
|
553
|
+
end
|
554
|
+
it "should use the meta if it exists" do
|
555
|
+
@job.url.should == "/#{@job.serialize}/hi"
|
556
|
+
end
|
557
|
+
it "should use the name if basename meta doesn't exist" do
|
558
|
+
@job.meta.delete(:basename)
|
559
|
+
@job.url.should == "/#{@job.serialize}/hello"
|
560
|
+
end
|
561
|
+
it "should not set if neither exist" do
|
562
|
+
@job.meta = {}
|
563
|
+
@job.url.should == "/#{@job.serialize}"
|
564
|
+
end
|
565
|
+
end
|
566
|
+
|
567
|
+
describe "ext" do
|
568
|
+
before(:each) do
|
569
|
+
@app.server.url_format = '/:job.:ext'
|
570
|
+
@job.meta = {:name => 'hello.egg', :ext => 'hi'}
|
571
|
+
end
|
572
|
+
it "should use the meta if it exists" do
|
573
|
+
@job.url.should == "/#{@job.serialize}.hi"
|
574
|
+
end
|
575
|
+
it "should use the name if ext meta doesn't exist" do
|
576
|
+
@job.meta.delete(:ext)
|
577
|
+
@job.url.should == "/#{@job.serialize}.egg"
|
578
|
+
end
|
579
|
+
it "should not set if neither exist" do
|
580
|
+
@job.meta = {}
|
581
|
+
@job.url.should == "/#{@job.serialize}"
|
582
|
+
end
|
583
|
+
end
|
584
|
+
|
585
|
+
describe "format" do
|
586
|
+
before(:each) do
|
587
|
+
@app.server.url_format = '/:job.:format'
|
588
|
+
@job.stub!(:ext).and_return("hi")
|
589
|
+
end
|
590
|
+
it "should use the meta if it exists" do
|
591
|
+
@job.meta = {:format => :txt}
|
592
|
+
@job.url.should == "/#{@job.serialize}.txt"
|
593
|
+
end
|
594
|
+
it "should use the ext if format meta doesn't exist" do
|
595
|
+
@job.url.should == "/#{@job.serialize}.hi"
|
596
|
+
end
|
597
|
+
it "should not use the ext if format meta doesn't exist and trust_file_extensions is switched off" do
|
598
|
+
@app.trust_file_extensions = false
|
599
|
+
@job.url.should == "/#{@job.serialize}"
|
600
|
+
end
|
601
|
+
it "should not set if neither exist" do
|
602
|
+
@job.should_receive(:ext).and_return nil
|
603
|
+
@job.url.should == "/#{@job.serialize}"
|
604
|
+
end
|
605
|
+
end
|
606
|
+
end
|
607
|
+
end
|
608
|
+
|
609
|
+
describe "to_fetched_job" do
|
610
|
+
before(:each) do
|
611
|
+
@app = test_app
|
612
|
+
@job = @app.create("HELLO")
|
613
|
+
end
|
614
|
+
it "should maintain the same temp_object and be already applied" do
|
615
|
+
new_job = @job.to_fetched_job('some_uid')
|
616
|
+
new_job.data.should == 'HELLO'
|
617
|
+
new_job.to_a.should == [
|
618
|
+
[:f, 'some_uid']
|
619
|
+
]
|
620
|
+
new_job.pending_steps.should be_empty
|
621
|
+
end
|
622
|
+
it "should maintain the meta" do
|
623
|
+
@job.meta = {:right => 'said fred'}
|
624
|
+
new_job = @job.to_fetched_job('some_uid')
|
625
|
+
new_job.meta.should == {:right => 'said fred'}
|
626
|
+
end
|
627
|
+
end
|
628
|
+
|
629
|
+
describe "to_unique_s" do
|
630
|
+
it "should use the arrays of args to create the string" do
|
631
|
+
job = test_app.fetch('uid').process(:gug, 4, :some => 'arg', :and => 'more')
|
632
|
+
job.to_unique_s.should == 'fuidpgug4andmoresomearg'
|
633
|
+
end
|
634
|
+
end
|
635
|
+
|
636
|
+
describe "sha" do
|
637
|
+
before(:each) do
|
638
|
+
@app = test_app
|
639
|
+
@job = @app.fetch('eggs')
|
640
|
+
end
|
641
|
+
|
642
|
+
it "should be of the correct format" do
|
643
|
+
@job.sha.should =~ /^\w{8}$/
|
644
|
+
end
|
645
|
+
|
646
|
+
it "should be the same for the same job steps" do
|
647
|
+
@app.fetch('eggs').sha.should == @job.sha
|
648
|
+
end
|
649
|
+
|
650
|
+
it "should be different for different jobs" do
|
651
|
+
@app.fetch('figs').sha.should_not == @job.sha
|
652
|
+
end
|
653
|
+
end
|
654
|
+
|
655
|
+
describe "validate_sha!" do
|
656
|
+
before(:each) do
|
657
|
+
@app = test_app
|
658
|
+
@job = @app.fetch('eggs')
|
659
|
+
end
|
660
|
+
it "should raise an error if nothing is given" do
|
661
|
+
lambda{
|
662
|
+
@job.validate_sha!(nil)
|
663
|
+
}.should raise_error(Dragonfly::Job::NoSHAGiven)
|
664
|
+
end
|
665
|
+
it "should raise an error if the wrong SHA is given" do
|
666
|
+
lambda{
|
667
|
+
@job.validate_sha!('asdf')
|
668
|
+
}.should raise_error(Dragonfly::Job::IncorrectSHA)
|
669
|
+
end
|
670
|
+
it "should return self if ok" do
|
671
|
+
@job.validate_sha!(@job.sha).should == @job
|
672
|
+
end
|
673
|
+
end
|
674
|
+
|
675
|
+
describe "setting the name" do
|
676
|
+
before(:each) do
|
677
|
+
@app = test_app
|
678
|
+
@job = @app.new_job("HELLO", :name => 'not.me')
|
679
|
+
end
|
680
|
+
it "should allow setting the name" do
|
681
|
+
@job.name = 'wassup.doc'
|
682
|
+
@job.name.should == 'wassup.doc'
|
683
|
+
end
|
684
|
+
end
|
685
|
+
|
686
|
+
describe "setting the meta" do
|
687
|
+
before(:each) do
|
688
|
+
@app = test_app
|
689
|
+
@job = @app.new_job("HiThere", :five => 'beans')
|
690
|
+
end
|
691
|
+
it "should allow setting the meta" do
|
692
|
+
@job.meta = {:doogie => 'ladders'}
|
693
|
+
@job.meta.should == {:doogie => 'ladders'}
|
694
|
+
end
|
695
|
+
it "should allow updating the meta" do
|
696
|
+
@job.meta[:doogie] = 'ladders'
|
697
|
+
@job.meta.should == {:five => 'beans', :doogie => 'ladders'}
|
698
|
+
end
|
699
|
+
end
|
700
|
+
|
701
|
+
describe "b64_data" do
|
702
|
+
before(:each) do
|
703
|
+
@app = test_app
|
704
|
+
end
|
705
|
+
it "should return a string using the data:URI schema" do
|
706
|
+
job = @app.new_job("HELLO", :name => 'text.txt')
|
707
|
+
job.b64_data.should == "data:text/plain;base64,SEVMTE8=\n"
|
708
|
+
end
|
709
|
+
end
|
710
|
+
|
711
|
+
describe "querying stuff without applying steps" do
|
712
|
+
before(:each) do
|
713
|
+
@app = test_app
|
714
|
+
end
|
715
|
+
|
716
|
+
describe "fetch_step" do
|
717
|
+
it "should return nil if it doesn't exist" do
|
718
|
+
@app.generate(:ponies).process(:jam).fetch_step.should be_nil
|
719
|
+
end
|
720
|
+
it "should return the fetch step otherwise" do
|
721
|
+
step = @app.fetch('hello').process(:cheese).fetch_step
|
722
|
+
step.should be_a(Dragonfly::Job::Fetch)
|
723
|
+
step.uid.should == 'hello'
|
724
|
+
end
|
725
|
+
end
|
726
|
+
describe "fetched uid" do
|
727
|
+
describe "when there's no fetch step" do
|
728
|
+
before(:each) do
|
729
|
+
@job = @app.new_job("AGG")
|
730
|
+
end
|
731
|
+
it "should return nil for uid" do
|
732
|
+
@job.uid.should be_nil
|
733
|
+
end
|
734
|
+
it "should return nil for uid_basename" do
|
735
|
+
@job.uid_basename.should be_nil
|
736
|
+
end
|
737
|
+
it "should return nil for uid_extname" do
|
738
|
+
@job.uid_extname.should be_nil
|
739
|
+
end
|
740
|
+
end
|
741
|
+
describe "when there is a fetch step" do
|
742
|
+
before(:each) do
|
743
|
+
@job = @app.fetch('gungedin/innit.blud')
|
744
|
+
end
|
745
|
+
it "should return the uid" do
|
746
|
+
@job.uid.should == 'gungedin/innit.blud'
|
747
|
+
end
|
748
|
+
it "should return the uid_basename" do
|
749
|
+
@job.uid_basename.should == 'innit'
|
750
|
+
end
|
751
|
+
it "should return the uid_extname" do
|
752
|
+
@job.uid_extname.should == '.blud'
|
753
|
+
end
|
754
|
+
end
|
755
|
+
end
|
756
|
+
|
757
|
+
describe "fetch_file_step" do
|
758
|
+
it "should return nil if it doesn't exist" do
|
759
|
+
@app.generate(:ponies).process(:jam).fetch_file_step.should be_nil
|
760
|
+
end
|
761
|
+
it "should return the fetch_file step otherwise" do
|
762
|
+
step = @app.fetch_file('/my/file.png').process(:cheese).fetch_file_step
|
763
|
+
step.should be_a(Dragonfly::Job::FetchFile)
|
764
|
+
step.path.should == '/my/file.png'
|
765
|
+
end
|
766
|
+
end
|
767
|
+
|
768
|
+
describe "fetch_url_step" do
|
769
|
+
it "should return nil if it doesn't exist" do
|
770
|
+
@app.generate(:ponies).fetch_url_step.should be_nil
|
771
|
+
end
|
772
|
+
it "should return the fetch_url step otherwise" do
|
773
|
+
step = @app.fetch_url('egg.heads').process(:cheese).fetch_url_step
|
774
|
+
step.should be_a(Dragonfly::Job::FetchUrl)
|
775
|
+
step.url.should == 'http://egg.heads'
|
776
|
+
end
|
777
|
+
end
|
778
|
+
|
779
|
+
describe "generate_step" do
|
780
|
+
it "should return nil if it doesn't exist" do
|
781
|
+
@app.fetch('many/ponies').process(:jam).generate_step.should be_nil
|
782
|
+
end
|
783
|
+
it "should return the generate step otherwise" do
|
784
|
+
step = @app.generate(:ponies).process(:cheese).generate_step
|
785
|
+
step.should be_a(Dragonfly::Job::Generate)
|
786
|
+
step.args.should == [:ponies]
|
787
|
+
end
|
788
|
+
end
|
789
|
+
|
790
|
+
describe "process_steps" do
|
791
|
+
it "should return the processing steps" do
|
792
|
+
job = @app.fetch('many/ponies').process(:jam).process(:eggs).encode(:gif)
|
793
|
+
job.process_steps.should match_steps([
|
794
|
+
Dragonfly::Job::Process,
|
795
|
+
Dragonfly::Job::Process
|
796
|
+
])
|
797
|
+
end
|
798
|
+
end
|
799
|
+
|
800
|
+
describe "encode_step" do
|
801
|
+
it "should return nil if it doesn't exist" do
|
802
|
+
@app.generate(:ponies).encode_step.should be_nil
|
803
|
+
end
|
804
|
+
it "should return the last encode step otherwise" do
|
805
|
+
step = @app.fetch('hello').encode(:smells).encode(:cheese).encode_step
|
806
|
+
step.should be_a(Dragonfly::Job::Encode)
|
807
|
+
step.format.should == :cheese
|
808
|
+
end
|
809
|
+
end
|
810
|
+
describe "encoded_format" do
|
811
|
+
it "should return nil if there's no encode step" do
|
812
|
+
@app.new_job('asdf').encoded_format.should be_nil
|
813
|
+
end
|
814
|
+
it "should return the last encoded format if it exists" do
|
815
|
+
@app.fetch('gungedin').encode(:a).encode(:b).encoded_format.should == :b
|
816
|
+
end
|
817
|
+
end
|
818
|
+
describe "encoded_extname" do
|
819
|
+
it "should return nil if there's no encode step" do
|
820
|
+
@app.new_job('asdf').encoded_extname.should be_nil
|
821
|
+
end
|
822
|
+
it "should return the last encoded format as an extname if it exists" do
|
823
|
+
@app.fetch('gungedin').encode(:a).encode(:b).encoded_extname.should == '.b'
|
824
|
+
end
|
825
|
+
end
|
826
|
+
end
|
827
|
+
|
828
|
+
describe "meta" do
|
829
|
+
before(:each) do
|
830
|
+
@app = test_app
|
831
|
+
@job = @app.new_job
|
832
|
+
end
|
833
|
+
it "should default meta to an empty hash" do
|
834
|
+
@job.meta.should == {}
|
835
|
+
end
|
836
|
+
it "should allow setting" do
|
837
|
+
@job.meta = {:a => :b}
|
838
|
+
@job.meta.should == {:a => :b}
|
839
|
+
end
|
840
|
+
it "should not allow setting as anything other than a hash" do
|
841
|
+
lambda{
|
842
|
+
@job.meta = 3
|
843
|
+
}.should raise_error(ArgumentError)
|
844
|
+
end
|
845
|
+
it "should allow setting on initialize" do
|
846
|
+
job = @app.new_job('asdf', :b => :c)
|
847
|
+
job.meta.should == {:b => :c}
|
848
|
+
end
|
849
|
+
it "should keep them when chained" do
|
850
|
+
@job.meta[:darn] = 'it'
|
851
|
+
@job.generate(:gollum).meta.should == {:darn => 'it'}
|
852
|
+
end
|
853
|
+
end
|
854
|
+
|
855
|
+
describe "name" do
|
856
|
+
before(:each) do
|
857
|
+
@app = test_app
|
858
|
+
end
|
859
|
+
it "should default to nil" do
|
860
|
+
job = @app.new_job('HELLO')
|
861
|
+
job.name.should be_nil
|
862
|
+
end
|
863
|
+
it "should use the meta" do
|
864
|
+
job = @app.new_job('HELLO')
|
865
|
+
job.meta[:name] = 'monkey.egg'
|
866
|
+
job.name.should == 'monkey.egg'
|
867
|
+
end
|
868
|
+
it "should allow setting" do
|
869
|
+
job = @app.new_job('HELLO')
|
870
|
+
job.name = "jonny.briggs"
|
871
|
+
job.meta[:name].should == 'jonny.briggs'
|
872
|
+
end
|
873
|
+
|
874
|
+
describe "ext" do
|
875
|
+
before(:each) do
|
876
|
+
@job = @app.new_job('asdf')
|
877
|
+
end
|
878
|
+
it "should use the correct extension from name" do
|
879
|
+
@job.name = 'hello.there.mate'
|
880
|
+
@job.ext.should == 'mate'
|
881
|
+
end
|
882
|
+
it "should be nil if name has none" do
|
883
|
+
@job.name = 'hello'
|
884
|
+
@job.ext.should be_nil
|
885
|
+
end
|
886
|
+
it "should be nil if name is nil" do
|
887
|
+
@job.name = nil
|
888
|
+
@job.ext.should be_nil
|
889
|
+
end
|
890
|
+
it "should use the meta first if set" do
|
891
|
+
@job.meta[:ext] = 'duggs'
|
892
|
+
@job.name = 'hello.there.mate'
|
893
|
+
@job.ext.should == 'duggs'
|
894
|
+
end
|
895
|
+
end
|
896
|
+
|
897
|
+
describe "basename" do
|
898
|
+
before(:each) do
|
899
|
+
@job = @app.new_job('asdf')
|
900
|
+
end
|
901
|
+
it "should use the correct basename from name" do
|
902
|
+
@job.name = 'hello.there.mate'
|
903
|
+
@job.basename.should == 'hello.there'
|
904
|
+
end
|
905
|
+
it "should be the name if it has no ext" do
|
906
|
+
@job.name = 'hello'
|
907
|
+
@job.basename.should == 'hello'
|
908
|
+
end
|
909
|
+
it "should be nil if name is nil" do
|
910
|
+
@job.name = nil
|
911
|
+
@job.basename.should be_nil
|
912
|
+
end
|
913
|
+
it "should use the meta first if set" do
|
914
|
+
@job.meta[:basename] = 'duggs'
|
915
|
+
@job.name = 'hello.there.mate'
|
916
|
+
@job.basename.should == 'duggs'
|
917
|
+
end
|
918
|
+
end
|
919
|
+
|
920
|
+
describe "format" do
|
921
|
+
before(:each) do
|
922
|
+
@app = test_app
|
923
|
+
end
|
924
|
+
it "should default to nil" do
|
925
|
+
job = @app.new_job("HELLO")
|
926
|
+
job.format.should be_nil
|
927
|
+
end
|
928
|
+
it "should use the meta format if it exists" do
|
929
|
+
job = @app.new_job("HELLO")
|
930
|
+
job.meta[:format] = :txt
|
931
|
+
job.format.should == :txt
|
932
|
+
end
|
933
|
+
it "should use the analyser format if it exists" do
|
934
|
+
@app.analyser.add :format do |temp_object|
|
935
|
+
:egg
|
936
|
+
end
|
937
|
+
job = @app.new_job("HELLO")
|
938
|
+
job.format.should == :egg
|
939
|
+
end
|
940
|
+
it "should use the file extension if it has no format" do
|
941
|
+
@job = @app.new_job("HIMATE", :name => 'test.pdf')
|
942
|
+
@job.format.should == :pdf
|
943
|
+
end
|
944
|
+
it "should not use the file extension if it's been switched off" do
|
945
|
+
@app.trust_file_extensions = false
|
946
|
+
@job = @app.new_job("HIMATE", :name => 'test.pdf')
|
947
|
+
@job.format.should be_nil
|
948
|
+
end
|
949
|
+
it "should prefer the set format over the file extension" do
|
950
|
+
job = @app.new_job("HELLO", :name => 'test.pdf', :format => :txt)
|
951
|
+
job.format.should == :txt
|
952
|
+
end
|
953
|
+
it "should prefer the file extension over the analysed format" do
|
954
|
+
@app.analyser.add :format do |temp_object|
|
955
|
+
:egg
|
956
|
+
end
|
957
|
+
job = @app.new_job("HELLO", :name => 'test.pdf')
|
958
|
+
job.format.should == :pdf
|
959
|
+
end
|
960
|
+
it "should apply the job" do
|
961
|
+
@app.generator.add(:test){ ["skid marks", {:name => 'terry.burton'}] }
|
962
|
+
job = @app.generate(:test)
|
963
|
+
job.format.should == :burton
|
964
|
+
job.should be_applied
|
965
|
+
end
|
966
|
+
end
|
967
|
+
|
968
|
+
describe "mime_type" do
|
969
|
+
before(:each) do
|
970
|
+
@app = test_app
|
971
|
+
end
|
972
|
+
it "should return the correct mime_type if the format is given" do
|
973
|
+
@job = @app.new_job("HIMATE")
|
974
|
+
@job.should_receive(:format).and_return(:tiff)
|
975
|
+
@job.mime_type.should == 'image/tiff'
|
976
|
+
end
|
977
|
+
it "should fall back to the mime_type analyser if the format is nil" do
|
978
|
+
@app.analyser.add :mime_type do |temp_object|
|
979
|
+
'image/jpeg'
|
980
|
+
end
|
981
|
+
@job = @app.new_job("HIMATE")
|
982
|
+
@job.mime_type.should == 'image/jpeg'
|
983
|
+
end
|
984
|
+
it "should fall back to the fallback mime_type if neither format or analyser exist" do
|
985
|
+
@app.new_job("HIMATE").mime_type.should == 'application/octet-stream'
|
986
|
+
end
|
987
|
+
end
|
988
|
+
|
989
|
+
end
|
990
|
+
|
991
|
+
describe "store" do
|
992
|
+
before(:each) do
|
993
|
+
@app = test_app
|
994
|
+
@app.generator.add(:test){ ["Toes", {:name => 'doogie.txt'}] }
|
995
|
+
@job = @app.generate(:test)
|
996
|
+
end
|
997
|
+
it "should store its data along with the meta" do
|
998
|
+
@job.meta[:eggs] = 'doolally'
|
999
|
+
@app.datastore.should_receive(:store).with(a_temp_object_with_data("Toes"), :meta => {:name => 'doogie.txt', :eggs => 'doolally'})
|
1000
|
+
@job.store
|
1001
|
+
end
|
1002
|
+
it "should add extra opts" do
|
1003
|
+
@app.datastore.should_receive(:store).with(a_temp_object_with_data("Toes"), :meta => {:name => 'doogie.txt'}, :path => 'blah')
|
1004
|
+
@job.store(:path => 'blah')
|
1005
|
+
end
|
1006
|
+
end
|
1007
|
+
|
1008
|
+
describe "dealing with original_filename" do
|
1009
|
+
before(:each) do
|
1010
|
+
@string = "terry"
|
1011
|
+
@string.stub!(:original_filename).and_return("gum.tree")
|
1012
|
+
@app = test_app
|
1013
|
+
@app.generator.add(:test){ @string }
|
1014
|
+
end
|
1015
|
+
it "should set it as the name" do
|
1016
|
+
@app.create(@string).name.should == 'gum.tree'
|
1017
|
+
end
|
1018
|
+
it "should prefer the initialized name over the original_filename" do
|
1019
|
+
@app.create(@string, :name => 'doo.berry').name.should == 'doo.berry'
|
1020
|
+
end
|
1021
|
+
it "should work with e.g. generators" do
|
1022
|
+
@app.generate(:test).apply.name.should == 'gum.tree'
|
1023
|
+
end
|
1024
|
+
it "should favour an e.g. generator returned name" do
|
1025
|
+
@app.generator.add(:test2){ [@string, {:name => 'gen.ome'}] }
|
1026
|
+
@app.generate(:test2).apply.name.should == 'gen.ome'
|
1027
|
+
end
|
1028
|
+
it "should not overwrite a set name" do
|
1029
|
+
job = @app.generate(:test)
|
1030
|
+
job.name = 'egg.mumma'
|
1031
|
+
job.apply.name.should == 'egg.mumma'
|
1032
|
+
end
|
1033
|
+
end
|
1034
|
+
|
1035
|
+
describe "deprecated meta format" do
|
1036
|
+
before(:each) do
|
1037
|
+
@app = test_app
|
1038
|
+
end
|
1039
|
+
it "should still work if the datastore/whatever returns meta nested in :meta key" do
|
1040
|
+
@app.datastore.should_receive(:retrieve).with('some_uid').and_return(['HELLO', {:name => 'test.txt', :meta => {:some => 'meta'}}])
|
1041
|
+
job = @app.fetch('some_uid').apply
|
1042
|
+
job.meta.should == {:name => 'test.txt', :some => 'meta'}
|
1043
|
+
end
|
1044
|
+
end
|
1045
|
+
|
1046
|
+
end
|