airbrush 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. data/History.txt +4 -0
  2. data/Manifest.txt +55 -0
  3. data/README.txt +39 -0
  4. data/Rakefile +4 -0
  5. data/bin/airbrush +61 -0
  6. data/bin/airbrush-example-client +60 -0
  7. data/config/hoe.rb +71 -0
  8. data/config/requirements.rb +17 -0
  9. data/lib/airbrush/client.rb +53 -0
  10. data/lib/airbrush/core_ext/get_args.rb +94 -0
  11. data/lib/airbrush/core_ext/timestamped_logger.rb +10 -0
  12. data/lib/airbrush/handler.rb +18 -0
  13. data/lib/airbrush/listeners/listener.rb +45 -0
  14. data/lib/airbrush/listeners/memcache.rb +53 -0
  15. data/lib/airbrush/listeners/socket.rb +0 -0
  16. data/lib/airbrush/listeners/webservice.rb +0 -0
  17. data/lib/airbrush/processors/image/image_processor.rb +31 -0
  18. data/lib/airbrush/processors/image/profiles/cmyk-profile.icc +0 -0
  19. data/lib/airbrush/processors/image/profiles/srgb-profile.icc +0 -0
  20. data/lib/airbrush/processors/image/rmagick.rb +116 -0
  21. data/lib/airbrush/processors/processor.rb +43 -0
  22. data/lib/airbrush/publishers/http.rb +13 -0
  23. data/lib/airbrush/publishers/memcache.rb +24 -0
  24. data/lib/airbrush/publishers/publisher.rb +16 -0
  25. data/lib/airbrush/server.rb +20 -0
  26. data/lib/airbrush/version.rb +9 -0
  27. data/lib/airbrush.rb +30 -0
  28. data/log/debug.log +0 -0
  29. data/script/destroy +14 -0
  30. data/script/generate +14 -0
  31. data/script/txt2html +74 -0
  32. data/setup.rb +1585 -0
  33. data/spec/airbrush/client_spec.rb +87 -0
  34. data/spec/airbrush/core_ext/get_args_spec.rb +0 -0
  35. data/spec/airbrush/handler_spec.rb +44 -0
  36. data/spec/airbrush/listeners/listener_spec.rb +18 -0
  37. data/spec/airbrush/listeners/memcache_spec.rb +131 -0
  38. data/spec/airbrush/processors/image/image_processor_spec.rb +56 -0
  39. data/spec/airbrush/processors/image/rmagick_spec.rb +179 -0
  40. data/spec/airbrush/processors/processor_spec.rb +110 -0
  41. data/spec/airbrush/publishers/memcache_spec.rb +46 -0
  42. data/spec/airbrush/publishers/publisher_spec.rb +17 -0
  43. data/spec/airbrush/server_spec.rb +57 -0
  44. data/spec/airbrush_spec.rb +9 -0
  45. data/spec/spec.opts +1 -0
  46. data/spec/spec_helper.rb +10 -0
  47. data/tasks/deployment.rake +34 -0
  48. data/tasks/environment.rake +7 -0
  49. data/tasks/rspec.rake +36 -0
  50. data/tasks/website.rake +17 -0
  51. data/website/index.html +11 -0
  52. data/website/index.txt +39 -0
  53. data/website/javascripts/rounded_corners_lite.inc.js +285 -0
  54. data/website/stylesheets/screen.css +138 -0
  55. data/website/template.rhtml +48 -0
  56. 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