airbrush 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +4 -0
- data/Manifest.txt +55 -0
- data/README.txt +39 -0
- data/Rakefile +4 -0
- data/bin/airbrush +61 -0
- data/bin/airbrush-example-client +60 -0
- data/config/hoe.rb +71 -0
- data/config/requirements.rb +17 -0
- data/lib/airbrush/client.rb +53 -0
- data/lib/airbrush/core_ext/get_args.rb +94 -0
- data/lib/airbrush/core_ext/timestamped_logger.rb +10 -0
- data/lib/airbrush/handler.rb +18 -0
- data/lib/airbrush/listeners/listener.rb +45 -0
- data/lib/airbrush/listeners/memcache.rb +53 -0
- data/lib/airbrush/listeners/socket.rb +0 -0
- data/lib/airbrush/listeners/webservice.rb +0 -0
- data/lib/airbrush/processors/image/image_processor.rb +31 -0
- data/lib/airbrush/processors/image/profiles/cmyk-profile.icc +0 -0
- data/lib/airbrush/processors/image/profiles/srgb-profile.icc +0 -0
- data/lib/airbrush/processors/image/rmagick.rb +116 -0
- data/lib/airbrush/processors/processor.rb +43 -0
- data/lib/airbrush/publishers/http.rb +13 -0
- data/lib/airbrush/publishers/memcache.rb +24 -0
- data/lib/airbrush/publishers/publisher.rb +16 -0
- data/lib/airbrush/server.rb +20 -0
- data/lib/airbrush/version.rb +9 -0
- data/lib/airbrush.rb +30 -0
- data/log/debug.log +0 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/script/txt2html +74 -0
- data/setup.rb +1585 -0
- data/spec/airbrush/client_spec.rb +87 -0
- data/spec/airbrush/core_ext/get_args_spec.rb +0 -0
- data/spec/airbrush/handler_spec.rb +44 -0
- data/spec/airbrush/listeners/listener_spec.rb +18 -0
- data/spec/airbrush/listeners/memcache_spec.rb +131 -0
- data/spec/airbrush/processors/image/image_processor_spec.rb +56 -0
- data/spec/airbrush/processors/image/rmagick_spec.rb +179 -0
- data/spec/airbrush/processors/processor_spec.rb +110 -0
- data/spec/airbrush/publishers/memcache_spec.rb +46 -0
- data/spec/airbrush/publishers/publisher_spec.rb +17 -0
- data/spec/airbrush/server_spec.rb +57 -0
- data/spec/airbrush_spec.rb +9 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +10 -0
- data/tasks/deployment.rake +34 -0
- data/tasks/environment.rake +7 -0
- data/tasks/rspec.rake +36 -0
- data/tasks/website.rake +17 -0
- data/website/index.html +11 -0
- data/website/index.txt +39 -0
- data/website/javascripts/rounded_corners_lite.inc.js +285 -0
- data/website/stylesheets/screen.css +138 -0
- data/website/template.rhtml +48 -0
- metadata +161 -0
@@ -0,0 +1,87 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper.rb'
|
2
|
+
require 'starling'
|
3
|
+
|
4
|
+
describe Airbrush::Client, 'job management' do
|
5
|
+
|
6
|
+
before do
|
7
|
+
@id = :id
|
8
|
+
@command = :command
|
9
|
+
@args = {}
|
10
|
+
@results = { :results => 'results' }
|
11
|
+
@queue = 'incoming'
|
12
|
+
@response_timeout = 5.minutes
|
13
|
+
@queue_validity = 15.minutes
|
14
|
+
|
15
|
+
@server = mock(Starling)
|
16
|
+
@server.stub!(:set).and_return
|
17
|
+
@server.stub!(:get).and_return(@results)
|
18
|
+
Starling.stub!(:new).and_return(@server)
|
19
|
+
|
20
|
+
@host = 'host'
|
21
|
+
@client = Airbrush::Client.new(@host, @queue, @response_timeout, @queue_validity)
|
22
|
+
end
|
23
|
+
|
24
|
+
describe 'when created' do
|
25
|
+
|
26
|
+
it 'should support a configurable target memcache host' do
|
27
|
+
@client.host.should == @host
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'should support a configurable inbound queue name' do
|
31
|
+
@client.incoming_queue.should == @queue
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'should support a configurable target memcache host' do
|
35
|
+
@client.response_timeout.should == @response_timeout
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'should support a configurable queue validity' do
|
39
|
+
@client.queue_validity.should == @queue_validity
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
describe 'job management' do
|
45
|
+
|
46
|
+
it 'should allow a job to be posted' do
|
47
|
+
@client.should respond_to(:process)
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'should allow access to the results returned by a job' do
|
51
|
+
@client.process(@id, @command, @args).should == @results
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
|
56
|
+
describe 'a posted job' do
|
57
|
+
|
58
|
+
it 'should raise an error if the id is not valid' do
|
59
|
+
lambda { @client.process(nil, @command, @args) }.should raise_error
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'should raise an error if the command is not valid' do
|
63
|
+
lambda { @client.process(@id, nil, @args) }.should raise_error
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'should raise an error if the args are not valid' do
|
67
|
+
lambda { @client.process(@id, @command, nil) }.should raise_error
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'should support optional arguments' do
|
71
|
+
lambda { @client.process(@id, @command) }.should_not raise_error
|
72
|
+
end
|
73
|
+
|
74
|
+
it 'should time out after 2 minutes seconds of inactivity' do
|
75
|
+
Airbrush::Client::DEFAULT_RESPONSE_TIMEOUT.should == 2.minutes
|
76
|
+
Timeout.should_receive(:timeout).and_return
|
77
|
+
@client.process(@id, @command)
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'should add the job into the incoming process queue' do
|
81
|
+
@server.should_receive(:set).with(@queue, { :id => @id, :command => @command, :args => @args }, @queue_validity, false)
|
82
|
+
@client.process(@id, @command, @args)
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
File without changes
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper.rb'
|
2
|
+
|
3
|
+
describe Airbrush::Handler, 'during creation' do
|
4
|
+
|
5
|
+
it 'should raise an error if given a nil processor' do
|
6
|
+
lambda { Airbrush::Handler.new(nil, Airbrush::Publishers::Publisher.new) }.should raise_error
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'should raise an error if given a nil publisher' do
|
10
|
+
lambda { Airbrush::Handler.new(Airbrush::Processors::Processor.new, nil) }.should raise_error
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
|
15
|
+
describe Airbrush::Handler, 'when processing a request' do
|
16
|
+
|
17
|
+
before do
|
18
|
+
@processor = mock(Airbrush::Processors::Processor)
|
19
|
+
@processor.stub!(:dispatch).and_return(true)
|
20
|
+
|
21
|
+
@publisher = mock(Airbrush::Publishers::Publisher)
|
22
|
+
@publisher.stub!(:publish).and_return
|
23
|
+
|
24
|
+
@handler = Airbrush::Handler.new(@processor, @publisher)
|
25
|
+
|
26
|
+
@id = 'id'
|
27
|
+
@command = :command
|
28
|
+
@args = {}
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'should pass the request to the processor' do
|
32
|
+
@processor.should_receive(:dispatch).with(@command, @args).and_return(true)
|
33
|
+
@handler.process @id, @command, @args
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'should publish the processors result' do
|
37
|
+
@publisher.should_receive(:publish).with(@id, true).and_return
|
38
|
+
@handler.process @id, @command, @args
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'should handle errors raised from the processor gracefully'
|
42
|
+
it 'should handle errors raised from the publisher gracefully'
|
43
|
+
|
44
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../spec_helper.rb'
|
2
|
+
|
3
|
+
describe Airbrush::Listeners::Listener, 'when created' do
|
4
|
+
|
5
|
+
before do
|
6
|
+
@listener = Airbrush::Listeners::Listener.new
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'should provide access to the handler instance' do
|
10
|
+
@listener.handler = Airbrush::Handler.new(mock(Airbrush::Processors::Processor), mock(Airbrush::Publishers::Publisher))
|
11
|
+
@listener.handler.should_not be_nil
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'should raise an error if start is attempted (since its an abstract class)' do
|
15
|
+
lambda { @listener.start }.should raise_error
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
@@ -0,0 +1,131 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../spec_helper.rb'
|
2
|
+
require 'starling'
|
3
|
+
|
4
|
+
describe Airbrush::Listeners::Memcache, 'initialization' do
|
5
|
+
|
6
|
+
before do
|
7
|
+
@host = 'host'
|
8
|
+
@frequency = 5
|
9
|
+
end
|
10
|
+
|
11
|
+
describe Airbrush::Listeners::Memcache, 'when created' do
|
12
|
+
|
13
|
+
before do
|
14
|
+
@memcache = Airbrush::Listeners::Memcache.new(@host, @frequency)
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'should configure access to the remote memcache server host' do
|
18
|
+
@memcache.host.should == @host
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'should configure the poll frequency time' do
|
22
|
+
@memcache.poll_frequency.should == @frequency
|
23
|
+
end
|
24
|
+
|
25
|
+
# future
|
26
|
+
it 'should accept a configurable incoming job queue name'
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
describe Airbrush::Listeners::Memcache, 'signal handling' do
|
31
|
+
|
32
|
+
before do
|
33
|
+
Signal.stub!(:trap).and_return
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'should catch sigint and disconnect from the memcache server' do
|
37
|
+
Signal.should_receive(:trap).with('INT').and_return
|
38
|
+
Airbrush::Listeners::Memcache.new(@host, @frequency)
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
describe Airbrush::Listeners::Memcache, 'when started' do
|
44
|
+
|
45
|
+
before do
|
46
|
+
@op = { :command => :command, :args => {}, :id => 'id' }
|
47
|
+
@server = mock(MemCache)
|
48
|
+
@server.stub!(:get).and_return(@op)
|
49
|
+
MemCache.stub!(:new).and_return(@server)
|
50
|
+
|
51
|
+
@handler = mock(Airbrush::Handler)
|
52
|
+
@handler.stub!(:process).and_return
|
53
|
+
|
54
|
+
@memcache = Airbrush::Listeners::Memcache.new(@host)
|
55
|
+
@memcache.handler = @handler
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'should connect to the remote memcache server' # REVISIT: can't call start since it loops forever
|
59
|
+
|
60
|
+
it 'should poll the remote memcache server for jobs' # REVISIT: can't call start since it loops forever
|
61
|
+
|
62
|
+
it 'should sleep 2 seconds inbetween memcache server polls' # REVISIT: can't call start since it loops forever
|
63
|
+
|
64
|
+
it 'should ensure remote jobs are contained inside a hash' do
|
65
|
+
@server.stub!(:get).and_return("bad format")
|
66
|
+
@handler.should_not_receive(:process)
|
67
|
+
@memcache.send :process, @server
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'should ensure remote jobs include a :id key' do
|
71
|
+
@server.stub!(:get).and_return(@op.except(:id))
|
72
|
+
@handler.should_not_receive(:process)
|
73
|
+
@memcache.send :process, @server
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'should ensure remote jobs include a :command key' do
|
77
|
+
@server.stub!(:get).and_return(@op.except(:command))
|
78
|
+
@handler.should_not_receive(:process)
|
79
|
+
@memcache.send :process, @server
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'should ensure remote jobs include an :args key' do
|
83
|
+
@server.stub!(:get).and_return(@op.except(:args))
|
84
|
+
@handler.should_not_receive(:process)
|
85
|
+
@memcache.send :process, @server
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'should log invalid jobs' do
|
89
|
+
@server.stub!(:get).and_return('invalid job')
|
90
|
+
@server.stub!(:valid?).and_return(false)
|
91
|
+
@server.log.should_receive(:error).and_return
|
92
|
+
@handler.should_not_receive(:process)
|
93
|
+
@memcache.send :process, @server
|
94
|
+
end
|
95
|
+
|
96
|
+
it 'should ignore invalid jobs (ie. invalid jobs should not halt processing)' do
|
97
|
+
@server.stub!(:get).and_return(nil)
|
98
|
+
@handler.should_not_receive(:process)
|
99
|
+
|
100
|
+
lambda { @memcache.send :process, @server }.should_not raise_error
|
101
|
+
end
|
102
|
+
|
103
|
+
it 'should pass valid jobs to the handler' do
|
104
|
+
@handler.should_receive(:process).with(@op[:id], @op[:command], @op[:args]).and_return
|
105
|
+
@memcache.send :process, @op
|
106
|
+
end
|
107
|
+
|
108
|
+
it 'should log errors return from the handler' do
|
109
|
+
@server.stub!(:get).and_return(@op)
|
110
|
+
@server.log.should_receive(:error).twice.and_return
|
111
|
+
@handler.should_receive(:process).with(@op[:id], @op[:command], @op[:args]).and_raise('Error')
|
112
|
+
@memcache.send :process, @op
|
113
|
+
end
|
114
|
+
|
115
|
+
it 'should ignore errors returned from the handler (ie. errors raised from the handler should not halt processing)' do
|
116
|
+
@server.stub!(:get).and_return(@op)
|
117
|
+
@handler.stub!(:process).and_raise("Test Error")
|
118
|
+
|
119
|
+
lambda { @memcache.send :process, @server }.should_not raise_error
|
120
|
+
end
|
121
|
+
|
122
|
+
it 'should accept a configurable poll time frequency' do
|
123
|
+
@memcache = Airbrush::Listeners::Memcache.new(@host, 10)
|
124
|
+
@memcache.poll_frequency.should == 10
|
125
|
+
end
|
126
|
+
|
127
|
+
# future
|
128
|
+
it 'should automatically discover the target memcache host address via dnssd'
|
129
|
+
end
|
130
|
+
|
131
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../../spec_helper.rb'
|
2
|
+
|
3
|
+
class MyImageProcessor < Airbrush::Processors::Image::ImageProcessor
|
4
|
+
before_filter :before
|
5
|
+
after_filter :after
|
6
|
+
|
7
|
+
def command
|
8
|
+
'no op'
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class MyExtraImageProcessor < Airbrush::Processors::Image::ImageProcessor
|
13
|
+
before_filter :before_extra
|
14
|
+
after_filter :after_extra
|
15
|
+
|
16
|
+
def command
|
17
|
+
'no op'
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe Airbrush::Processors::Image::ImageProcessor, 'filter definitions' do
|
22
|
+
|
23
|
+
before do
|
24
|
+
@processor1 = MyImageProcessor.new
|
25
|
+
@processor2 = MyExtraImageProcessor.new
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'should not override filters from other processors' do
|
29
|
+
@processor1.before_filters.should == [ :before ]
|
30
|
+
@processor2.before_filters.should == [ :before_extra ]
|
31
|
+
|
32
|
+
@processor1.after_filters.should == [ :after ]
|
33
|
+
@processor2.after_filters.should == [ :after_extra ]
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
describe Airbrush::Processors::Image::ImageProcessor, 'when dispatching' do
|
39
|
+
|
40
|
+
before do
|
41
|
+
@args = {}
|
42
|
+
@processor = MyImageProcessor.new
|
43
|
+
@processor.stub!(:filter_dispatch).and_return
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'should invoke before filters before sending operation' do
|
47
|
+
@processor.should_receive(:filter_dispatch).with(:before, @args).and_return
|
48
|
+
@processor.dispatch :command, @args
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'should invoke after filters after sending operation' do
|
52
|
+
@processor.should_receive(:filter_dispatch).with(:after, @args).and_return
|
53
|
+
@processor.dispatch :command, @args
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
@@ -0,0 +1,179 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../../spec_helper.rb'
|
2
|
+
require 'RMagick'
|
3
|
+
|
4
|
+
describe Airbrush::Processors::Image::Rmagick do
|
5
|
+
|
6
|
+
before do
|
7
|
+
@image = 'image'
|
8
|
+
@columns = 1500; @rows = 1000
|
9
|
+
@blob = 'blob'
|
10
|
+
|
11
|
+
@rm_image = mock(Object)
|
12
|
+
@rm_image.stub!(:change_geometry).and_return
|
13
|
+
@rm_image.stub!(:crop!).and_return
|
14
|
+
@rm_image.stub!(:crop_resized!).and_return
|
15
|
+
@rm_image.stub!(:ensure_rgb!).and_return
|
16
|
+
@rm_image.stub!(:to_blob).and_return(@blob)
|
17
|
+
@rm_image.stub!(:format=).and_return('JPEG')
|
18
|
+
@rm_image.stub!(:columns).and_return(@columns)
|
19
|
+
@rm_image.stub!(:rows).and_return(@rows)
|
20
|
+
Magick::Image.stub!(:from_blob).and_return([@rm_image])
|
21
|
+
|
22
|
+
@processor = Airbrush::Processors::Image::Rmagick.new
|
23
|
+
end
|
24
|
+
|
25
|
+
describe 'when resizing' do
|
26
|
+
|
27
|
+
it 'should auto calculate width/height when passed a single value' do
|
28
|
+
Magick::Image.should_receive(:from_blob).and_return([@rm_image])
|
29
|
+
@processor.should_receive(:calculate_dimensions).with(@image, 300).and_return([300,200])
|
30
|
+
|
31
|
+
@processor.resize @image, 300
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'should preprocess images before resizing' do
|
35
|
+
@processor.resize @image, 300, 200
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'should change the geometry of the image' do
|
39
|
+
@rm_image.should_receive(:change_geometry).and_return
|
40
|
+
@processor.resize @image, 300, 200
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'should convert images to rgb if required' do
|
44
|
+
@rm_image.should_receive(:ensure_rgb!).and_return
|
45
|
+
@processor.resize @image, 300, 200
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'should return the raw image data back to the caller' do
|
49
|
+
@rm_image.should_receive(:to_blob).and_return('blob')
|
50
|
+
@processor.resize(@image, 300, 200).should == { :image => "blob", :height => 1000, :width => 1500 }
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
describe 'when cropping' do
|
56
|
+
|
57
|
+
it 'should preprocess images before cropping' do
|
58
|
+
@processor.crop @image, 10, 10, 100, 100
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'should change the geometry of the image' do
|
62
|
+
@rm_image.should_receive(:crop!).and_return
|
63
|
+
@processor.crop @image, 10, 10, 100, 100
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'should convert images to rgb if required' do
|
67
|
+
@rm_image.should_receive(:ensure_rgb!).and_return
|
68
|
+
@processor.resize @image, 300, 200
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'should return the raw image data back to the caller' do
|
72
|
+
@rm_image.should_receive(:to_blob).and_return('blob')
|
73
|
+
@processor.crop(@image, 10, 10, 100, 100).should == { :image => "blob", :height => 1000, :width => 1500 }
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
|
78
|
+
describe 'when performing a resized crop' do
|
79
|
+
|
80
|
+
it 'should preprocess images before resizing/cropping' do
|
81
|
+
@processor.crop_resize @image, 75, 75
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'should change the geometry of the image' do
|
85
|
+
@rm_image.should_receive(:crop_resized!).and_return
|
86
|
+
@processor.crop_resize @image, 75, 75
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'should convert images to rgb if required' do
|
90
|
+
@rm_image.should_receive(:ensure_rgb!).and_return
|
91
|
+
@processor.resize @image, 300, 200
|
92
|
+
end
|
93
|
+
|
94
|
+
it 'should return the raw image data back to the caller' do
|
95
|
+
@rm_image.should_receive(:to_blob).and_return('blob')
|
96
|
+
@processor.crop_resize(@image, 75, 75).should == { :image => "blob", :height => 1000, :width => 1500 }
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
100
|
+
|
101
|
+
describe 'when generating previews' do
|
102
|
+
|
103
|
+
it 'should change the geometry of the image' do
|
104
|
+
@rm_image.should_receive(:crop_resized!).twice.and_return
|
105
|
+
@processor.previews @image, { :small => [200,100], :large => [500,250] }
|
106
|
+
end
|
107
|
+
|
108
|
+
it 'should return the raw image data back to the caller' do
|
109
|
+
@rm_image.should_receive(:to_blob).twice.and_return('blob')
|
110
|
+
@processor.previews(@image, { :small => [200,100], :large => [500,250] }).should == { :small=> { :image => "blob", :height => 1000, :width => 1500 }, :large=> { :image => "blob", :height => 1000, :width => 1500 }, :original => [1500, 1000] }
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
114
|
+
|
115
|
+
describe 'dimension calculation' do
|
116
|
+
|
117
|
+
it 'should automatically recognize images in portrait mode' do
|
118
|
+
@processor.send(:calculate_dimensions, @rm_image, 300).should == [300,200]
|
119
|
+
end
|
120
|
+
|
121
|
+
it 'should automatically recognize images in landscape mode' do
|
122
|
+
@rm_image.stub!(:columns).and_return(1000)
|
123
|
+
@rm_image.stub!(:rows).and_return(1500)
|
124
|
+
@processor.send(:calculate_dimensions, @rm_image, 300).should == [200,300]
|
125
|
+
end
|
126
|
+
|
127
|
+
it 'should automatically clip resizes if they are larger than the original' do
|
128
|
+
@processor.send(:calculate_dimensions, @rm_image, 2000).should == [1500,1000]
|
129
|
+
end
|
130
|
+
|
131
|
+
end
|
132
|
+
|
133
|
+
end
|
134
|
+
|
135
|
+
describe Magick::Image, 'when created' do
|
136
|
+
|
137
|
+
before do
|
138
|
+
@image = Magick::Image.new(200, 100)
|
139
|
+
end
|
140
|
+
|
141
|
+
it 'should be able to convert the profile to srgb when requested' do
|
142
|
+
@image.should respond_to(:ensure_rgb!)
|
143
|
+
end
|
144
|
+
|
145
|
+
end
|
146
|
+
|
147
|
+
describe Magick::Image, 'when converting images to sRGB' do
|
148
|
+
|
149
|
+
before do
|
150
|
+
@image = Magick::Image.new(200, 100)
|
151
|
+
@image.stub!(:add_profile).and_return
|
152
|
+
end
|
153
|
+
|
154
|
+
it 'should return if the image is already in sRGB colour space' do
|
155
|
+
@image.colorspace = Magick::RGBColorspace
|
156
|
+
@image.should_not_receive(:add_profile)
|
157
|
+
@image.ensure_rgb!
|
158
|
+
end
|
159
|
+
|
160
|
+
it 'should log a warning if a non CMYK/RGB image is encountered' do
|
161
|
+
@image.colorspace = Magick::Rec709LumaColorspace
|
162
|
+
@image.should_not_receive(:add_profile)
|
163
|
+
@image.log.should_receive(:warn).and_return
|
164
|
+
@image.ensure_rgb!
|
165
|
+
end
|
166
|
+
|
167
|
+
it 'should add a CMYK profile if the image does not have a profile and is in CMYK colour space' do
|
168
|
+
@image.colorspace = Magick::CMYKColorspace
|
169
|
+
@image.should_receive(:add_profile).twice.and_return
|
170
|
+
@image.ensure_rgb!
|
171
|
+
end
|
172
|
+
|
173
|
+
it 'should add a sRGB profile if the image is in CMYK colour space' do
|
174
|
+
@image.colorspace = Magick::CMYKColorspace
|
175
|
+
@image.should_receive(:add_profile).with(Magick::Image::SCT_SRGB_ICC).and_return
|
176
|
+
@image.ensure_rgb!
|
177
|
+
end
|
178
|
+
|
179
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../spec_helper.rb'
|
2
|
+
|
3
|
+
class MyProcessor < Airbrush::Processors::Processor
|
4
|
+
|
5
|
+
def my_action(one, two, three = '3')
|
6
|
+
[ one, two, three ]
|
7
|
+
end
|
8
|
+
|
9
|
+
end
|
10
|
+
|
11
|
+
describe Airbrush::Processors::Processor, 'abstract class' do
|
12
|
+
|
13
|
+
before do
|
14
|
+
@processor = Airbrush::Processors::Processor.new
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'should return an error from dispatch if the requested command is not implemented by the processor' do
|
18
|
+
@processor.dispatch(:blah, {}).should == { :exception => "ERROR: Received error during processor dispatch for command 'blah' ()", :message => 'Unknown processor operation blah ()' }
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
describe Airbrush::Processors::Processor, 'argument handling' do
|
24
|
+
|
25
|
+
before do
|
26
|
+
@processor = MyProcessor.new
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'should inspect the target action for its parameters and assign them via the argument hash' do
|
30
|
+
params = @processor.send :assign, :my_action, { :one => 'a', :two => 'b', :three => 'c' }
|
31
|
+
params.should == %w( a b c )
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'should respect default values when present in action signatures, but not in the argument hash' do
|
35
|
+
params = @processor.send :assign, :my_action, { :one => 'a', :two => 'b' }
|
36
|
+
params.should == %w( a b 3 )
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'should raise an error if an action signature value is missing from the argument hash and does not have a default value' do
|
40
|
+
lambda { @processor.send(:assign, :my_action, { :one => 'a' }) }.should raise_error
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
describe Airbrush::Processors::Processor, 'when processing' do
|
46
|
+
|
47
|
+
before do
|
48
|
+
@processor = MyProcessor.new
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'should invoke the requested target action' do
|
52
|
+
@processor.dispatch(:my_action, { :one => 'a', :two => 'b' }).should == %w( a b 3 )
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
describe Airbrush::Processors::Processor, 'error handling' do
|
57
|
+
|
58
|
+
before do
|
59
|
+
@error = 'an error string'
|
60
|
+
@processor = MyProcessor.new
|
61
|
+
@processor.stub!(:my_action).and_raise(@error)
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'should return an error from dispatch if the requested command raises an exception during processing' do
|
65
|
+
@processor.should_receive(:my_action).and_raise(@error)
|
66
|
+
@options = { :one => 'a', :two => 'b', :three => 'c' }
|
67
|
+
@processor.dispatch(:my_action, @options).should == { :exception => "ERROR: Received error during processor dispatch for command 'my_action' (#{@options.inspect})", :message => @error }
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
|
72
|
+
class FilteredProcessor < Airbrush::Processors::Processor
|
73
|
+
filter_params :password
|
74
|
+
|
75
|
+
def command(username, password); 'no op'; end
|
76
|
+
end
|
77
|
+
|
78
|
+
class ExtraFilteredProcessor < Airbrush::Processors::Processor
|
79
|
+
filter_params :username
|
80
|
+
|
81
|
+
def command(username, password); 'no_op'; end
|
82
|
+
end
|
83
|
+
|
84
|
+
describe Airbrush::Processors::Processor, 'filter definitions' do
|
85
|
+
|
86
|
+
before do
|
87
|
+
@processor1 = FilteredProcessor.new
|
88
|
+
@processor2 = ExtraFilteredProcessor.new
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'should not override filters from other processors' do
|
92
|
+
@processor1.filtered_params.should == [ :password ]
|
93
|
+
@processor2.filtered_params.should == [ :username ]
|
94
|
+
end
|
95
|
+
|
96
|
+
describe 'filtering' do
|
97
|
+
|
98
|
+
before do
|
99
|
+
@params = { :username => 'username', :password => 'password' }
|
100
|
+
end
|
101
|
+
|
102
|
+
it 'should replace market parameter keys with a new value' do
|
103
|
+
{ @processor1 => :password, @processor2 => :username }.each do |processor, filtered|
|
104
|
+
processor.send(:filter, @params).should == @params.update(filtered => '[FILTERED]')
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
109
|
+
|
110
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../spec_helper.rb'
|
2
|
+
require 'starling'
|
3
|
+
|
4
|
+
describe Airbrush::Publishers::Memcache, 'when created' do
|
5
|
+
|
6
|
+
before do
|
7
|
+
@host = 'host'
|
8
|
+
@memcache = Airbrush::Publishers::Memcache.new(@host)
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'should configure access to the remote memcache server host' do
|
12
|
+
@memcache.host.should == @host
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
|
17
|
+
describe Airbrush::Publishers::Memcache, 'when publishing' do
|
18
|
+
|
19
|
+
before do
|
20
|
+
@host = 'host'
|
21
|
+
@server = mock(MemCache)
|
22
|
+
@server.stub!(:set).and_return
|
23
|
+
MemCache.stub!(:new).and_return(@server)
|
24
|
+
@results = "results"
|
25
|
+
@id = 'id'
|
26
|
+
|
27
|
+
@memcache = Airbrush::Publishers::Memcache.new(@host)
|
28
|
+
@memcache.stub!(:unique_name).and_return('unique')
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'should connect to the remote memcache server' do
|
32
|
+
MemCache.should_receive(:new).and_return(@server)
|
33
|
+
@memcache.publish(@id, @results)
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'should calculate a unique memcache queue name for publishing results' do
|
37
|
+
@memcache.should_receive(:unique_name).with(@id).and_return('unique')
|
38
|
+
@memcache.publish(@id, @results)
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'should publish the given results to the remote memcache server' do
|
42
|
+
@server.should_receive(:set).with('unique', @results).and_return
|
43
|
+
@memcache.publish(@id, @results)
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../spec_helper.rb'
|
2
|
+
|
3
|
+
describe Airbrush::Publishers::Publisher, 'when created' do
|
4
|
+
|
5
|
+
before do
|
6
|
+
@publisher = Airbrush::Publishers::Publisher.new
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'should be able to create a unique name given an id' do
|
10
|
+
@publisher.send(:unique_name, 'id').should == 'id'
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'should accept a symbol as an id to make unique' do
|
14
|
+
@publisher.send(:unique_name, :id).should == 'id'
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|