httpimagestore 1.8.1 → 1.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. checksums.yaml +15 -0
  2. data/Gemfile +7 -7
  3. data/Gemfile.lock +20 -20
  4. data/README.md +165 -37
  5. data/Rakefile +7 -2
  6. data/VERSION +1 -1
  7. data/bin/httpimagestore +74 -41
  8. data/lib/httpimagestore/configuration/file.rb +20 -11
  9. data/lib/httpimagestore/configuration/handler.rb +96 -257
  10. data/lib/httpimagestore/configuration/handler/source_store_base.rb +37 -0
  11. data/lib/httpimagestore/configuration/handler/statement.rb +114 -0
  12. data/lib/httpimagestore/configuration/identify.rb +17 -9
  13. data/lib/httpimagestore/configuration/output.rb +33 -61
  14. data/lib/httpimagestore/configuration/path.rb +2 -2
  15. data/lib/httpimagestore/configuration/request_state.rb +131 -0
  16. data/lib/httpimagestore/configuration/s3.rb +41 -29
  17. data/lib/httpimagestore/configuration/thumbnailer.rb +189 -96
  18. data/lib/httpimagestore/configuration/validate_hmac.rb +170 -0
  19. data/lib/httpimagestore/error_reporter.rb +6 -1
  20. data/lib/httpimagestore/ruby_string_template.rb +10 -19
  21. metadata +40 -102
  22. data/.rspec +0 -1
  23. data/features/cache-control.feature +0 -41
  24. data/features/compatibility.feature +0 -165
  25. data/features/data-uri.feature +0 -55
  26. data/features/encoding.feature +0 -103
  27. data/features/error-reporting.feature +0 -281
  28. data/features/flexi.feature +0 -259
  29. data/features/health-check.feature +0 -29
  30. data/features/request-matching.feature +0 -211
  31. data/features/rewrite.feature +0 -122
  32. data/features/s3-store-and-thumbnail.feature +0 -82
  33. data/features/source-failover.feature +0 -71
  34. data/features/step_definitions/httpimagestore_steps.rb +0 -203
  35. data/features/storage.feature +0 -198
  36. data/features/support/env.rb +0 -116
  37. data/features/support/test-large.jpg +0 -0
  38. data/features/support/test.empty +0 -0
  39. data/features/support/test.jpg +0 -0
  40. data/features/support/test.png +0 -0
  41. data/features/support/test.txt +0 -1
  42. data/features/support/tiny.png +0 -0
  43. data/features/xid-forwarding.feature +0 -49
  44. data/httpimagestore.gemspec +0 -145
  45. data/load_test/load_test.1k.23a022f6e.m1.small-comp.csv +0 -3
  46. data/load_test/load_test.1k.ec9bde794.m1.small.csv +0 -4
  47. data/load_test/load_test.jmx +0 -317
  48. data/load_test/thumbnail_specs.csv +0 -11
  49. data/load_test/thumbnail_specs_v2.csv +0 -10
  50. data/spec/configuration_file_spec.rb +0 -333
  51. data/spec/configuration_handler_spec.rb +0 -255
  52. data/spec/configuration_identify_spec.rb +0 -67
  53. data/spec/configuration_output_spec.rb +0 -821
  54. data/spec/configuration_path_spec.rb +0 -138
  55. data/spec/configuration_s3_spec.rb +0 -911
  56. data/spec/configuration_source_failover_spec.rb +0 -101
  57. data/spec/configuration_spec.rb +0 -90
  58. data/spec/configuration_thumbnailer_spec.rb +0 -483
  59. data/spec/ruby_string_template_spec.rb +0 -61
  60. data/spec/spec_helper.rb +0 -89
  61. data/spec/support/compute.jpg +0 -0
  62. data/spec/support/cuba_response_env.rb +0 -40
  63. data/spec/support/full.cfg +0 -183
  64. data/spec/support/utf_string.txt +0 -1
@@ -1,101 +0,0 @@
1
- require_relative 'spec_helper'
2
- require 'httpimagestore/configuration'
3
- MemoryLimit.logger = Configuration::Scope.logger = RootLogger.new('/dev/null')
4
-
5
- require 'httpimagestore/configuration/source_failover'
6
- require 'httpimagestore/configuration/file'
7
- require 'httpimagestore/configuration/output'
8
- MemoryLimit.logger = Logger.new('/dev/null')
9
-
10
- describe Configuration do
11
- let :state do
12
- Configuration::RequestState.new('abc')
13
- end
14
-
15
- describe Configuration::FileSource do
16
- subject do
17
- Configuration.read(<<-EOF)
18
- path "in" "test.in"
19
-
20
- get "test" {
21
- source_failover {
22
- source_file "no_fail_1" root="/tmp" path="in"
23
- source_file "no_fail_2" root="/tmp" path="in"
24
- }
25
-
26
- source_failover {
27
- source_file "first_fail_1" root="/tmp/bogous" path="in"
28
- source_file "first_fail_2" root="/tmp" path="in"
29
- }
30
-
31
- source_failover {
32
- source_file "all_fail" root="/tmp/bogous" path="in"
33
- source_file "all_fail" root="/tmp/bogous2" path="in"
34
- }
35
-
36
- source_failover {
37
- source_file "deep_fail_1" root="/tmp/bogous" path="in"
38
- source_file "deep_fail_2" root="/tmp/bogous" path="in"
39
- source_file "deep_fail_3" root="/tmp" path="in"
40
- source_file "deep_fail_4" root="/tmp/bogous" path="in"
41
- }
42
- }
43
- EOF
44
- end
45
-
46
- let :in_file do
47
- Pathname.new("/tmp/test.in")
48
- end
49
-
50
- before :each do
51
- in_file.open('w'){|io| io.write('abc')}
52
- end
53
-
54
- after :each do
55
- in_file.unlink
56
- end
57
-
58
- context 'first source is OK' do
59
- it 'should source first image' do
60
- subject.handlers[0].sources[0].should be_a Configuration::SourceFailover
61
- subject.handlers[0].sources[0].realize(state)
62
-
63
- state.images.keys.should == ['no_fail_1']
64
- state.images['no_fail_1'].should_not be_nil
65
- state.images['no_fail_1'].data.should == 'abc'
66
- end
67
- end
68
-
69
- context 'second source is OK' do
70
- it 'should source second image' do
71
- subject.handlers[0].sources[1].should be_a Configuration::SourceFailover
72
- subject.handlers[0].sources[1].realize(state)
73
-
74
- state.images.keys.should == ['first_fail_2']
75
- state.images['first_fail_2'].should_not be_nil
76
- state.images['first_fail_2'].data.should == 'abc'
77
- end
78
- end
79
-
80
- context 'all sources fail' do
81
- it 'should raise error Configuration::SourceFailoverAllFailedError' do
82
- subject.handlers[0].sources[2].should be_a Configuration::SourceFailover
83
-
84
- expect {
85
- subject.handlers[0].sources[2].realize(state)
86
- }.to raise_error Configuration::SourceFailoverAllFailedError, "all sources failed: FileSource[image_name: 'all_fail' root_dir: '/tmp/bogous' path_spec: 'in'](Configuration::NoSuchFileError: error while processing image 'all_fail': file 'test.in' not found), FileSource[image_name: 'all_fail' root_dir: '/tmp/bogous2' path_spec: 'in'](Configuration::NoSuchFileError: error while processing image 'all_fail': file 'test.in' not found)"
87
- end
88
- end
89
-
90
- context 'tird source is OK' do
91
- it 'should source second image' do
92
- subject.handlers[0].sources[3].should be_a Configuration::SourceFailover
93
- subject.handlers[0].sources[3].realize(state)
94
-
95
- state.images.keys.should == ['deep_fail_3']
96
- state.images['deep_fail_3'].should_not be_nil
97
- state.images['deep_fail_3'].data.should == 'abc'
98
- end
99
- end
100
- end
101
- end
@@ -1,90 +0,0 @@
1
- require_relative 'spec_helper'
2
- require 'httpimagestore/configuration'
3
- MemoryLimit.logger = Configuration::Scope.logger = RootLogger.new('/dev/null')
4
-
5
- require 'pathname'
6
- Pathname.glob('lib/httpimagestore/configuration/*.rb').each do |conf|
7
- require conf.relative_path_from(Pathname.new 'lib').to_s
8
- end
9
-
10
- describe Configuration do
11
- it 'should parse configuration file' do
12
- Configuration.from_file(support_dir + 'full.cfg')
13
- end
14
-
15
- it 'should read configuration from string' do
16
- Configuration.read (support_dir + 'full.cfg').read
17
- end
18
-
19
- describe Configuration::SDL4RTagExtensions do
20
- let :configuration do
21
- SDL4R::read <<-'EOF'
22
- test "hello" "world" abc=123 xyz=321 qwe=true asd="fd"
23
- EOF
24
- end
25
-
26
- subject do
27
- configuration.children.first
28
- end
29
-
30
- describe '#required_attributes' do
31
- it 'should raise NoAttributeError if there is missing required attribute' do
32
- subject.required_attributes('abc', 'xyz')
33
-
34
- expect {
35
- subject.required_attributes('abc', 'xyz', 'blah')
36
- }.to raise_error Configuration::NoAttributeError, %{syntax error while parsing 'test "hello" "world" abc=123 asd="fd" qwe=true xyz=321': expected 'blah' attribute to be set}
37
- end
38
- end
39
-
40
- describe '#grab_attributes' do
41
- it 'should grab list of attributes form node' do
42
- list = subject.grab_attributes('abc', 'xyz', 'qwe', 'opt', 'asd')
43
- list.should == [123, 321, true, nil, 'fd']
44
- end
45
-
46
- it 'should raise UnexpectedAttributesError if unlisted attribut is on closed attribute list' do
47
- expect {
48
- subject.grab_attributes('abc', 'qwe')
49
- }.to raise_error Configuration::UnexpectedAttributesError, %{syntax error while parsing 'test "hello" "world" abc=123 asd="fd" qwe=true xyz=321': unexpected attributes: 'xyz', 'asd'}
50
- end
51
- end
52
-
53
- describe '#grab_attributes_with_remaining' do
54
- it 'should grab list of attributes form node and all other remaining attributes' do
55
- *list, remaining = *subject.grab_attributes_with_remaining('abc', 'xyz')
56
- list.should == [123, 321]
57
- remaining.should == {'qwe' => true, 'asd' => 'fd'}
58
- end
59
- end
60
-
61
- describe '#valid_attribute_values' do
62
- it 'should rise BadAttributeValueError if attribute value is not on defined value list' do
63
- subject.valid_attribute_values('qwe', true, false)
64
-
65
- expect {
66
- subject.valid_attribute_values('qwe', 'hello', 'world')
67
- }.to raise_error Configuration::BadAttributeValueError, %{syntax error while parsing 'test "hello" "world" abc=123 asd="fd" qwe=true xyz=321': expected 'qwe' attribute value to be "hello" or "world"; got: true}
68
- end
69
- end
70
-
71
- describe '#grab_values' do
72
- it 'should grab list of values' do
73
- subject.grab_values('value 1', 'value 2').should == ['hello', 'world']
74
- end
75
-
76
- it 'should raise NoValueError if there is not enought values' do
77
- expect {
78
- subject.grab_values('value 1', 'value 2', 'value 3')
79
- }.to raise_error Configuration::NoValueError, %{syntax error while parsing 'test "hello" "world" abc=123 asd="fd" qwe=true xyz=321': expected value 3}
80
- end
81
-
82
- it 'should raise UnexpectedValueError if there is too many values' do
83
- expect {
84
- subject.grab_values('value 1')
85
- }.to raise_error Configuration::UnexpectedValueError, %{syntax error while parsing 'test "hello" "world" abc=123 asd="fd" qwe=true xyz=321': unexpected values: "world"}
86
- end
87
- end
88
- end
89
- end
90
-
@@ -1,483 +0,0 @@
1
- require_relative 'spec_helper'
2
- require 'httpimagestore/configuration'
3
- MemoryLimit.logger = Configuration::Scope.logger = RootLogger.new('/dev/null')
4
-
5
- require 'httpimagestore/configuration/output'
6
- require 'httpimagestore/configuration/thumbnailer'
7
-
8
- describe Configuration do
9
- describe 'thumbnailer' do
10
- subject do
11
- Configuration.read('')
12
- end
13
-
14
- it 'should provide HTTPThumbnailerClient' do
15
- subject.thumbnailer.should be_a HTTPThumbnailerClient
16
- end
17
-
18
- it 'should use default URL' do
19
- subject.thumbnailer.server_url.should == 'http://localhost:3100'
20
- end
21
-
22
- it 'should allow to override default URL' do
23
- subject = Configuration.read(<<-EOF, thumbnailer_url: 'http://1.1.1.1:8080')
24
- EOF
25
-
26
- subject.thumbnailer.server_url.should == 'http://1.1.1.1:8080'
27
- end
28
-
29
- it 'should get thumbnailer URL from configuration' do
30
- subject = Configuration.read(<<-EOF, thumbnailer_url: 'http://1.1.1.1:8080')
31
- thumbnailer url="http://2.2.2.2:1000"
32
- EOF
33
-
34
- subject.thumbnailer.server_url.should == 'http://2.2.2.2:1000'
35
- end
36
-
37
- describe 'error handling' do
38
- it 'should raise StatementCollisionError on duplicate thumbnailer statement' do
39
- expect {
40
- Configuration.read(<<-EOF)
41
- thumbnailer url="http://2.2.2.2:1000"
42
- thumbnailer url="http://2.2.2.2:1000"
43
- EOF
44
- }.to raise_error Configuration::StatementCollisionError, %{syntax error while parsing 'thumbnailer url="http://2.2.2.2:1000"': only one thumbnailer type statement can be specified within context}
45
- end
46
-
47
- it 'should raise NoAttributeError on missing url attribute' do
48
- expect {
49
- Configuration.read(<<-EOF)
50
- thumbnailer
51
- EOF
52
- }.to raise_error Configuration::NoAttributeError, %{syntax error while parsing 'thumbnailer': expected 'url' attribute to be set}
53
- end
54
- end
55
- end
56
-
57
- describe Configuration::Thumbnail::ThumbnailSpec do
58
- describe 'should provide thumbnail spec array based on given locals' do
59
- it 'where image name is hash key pointing to array where all values are string and options is hash' do
60
- Configuration::Thumbnail::ThumbnailSpec.new('small', 'pad', 100, 100, 'jpeg', 'background-color' => 'red').render.should == {
61
- 'small' =>
62
- ['pad', '100', '100', 'jpeg', {'background-color' => 'red'}]
63
- }
64
- end
65
-
66
- describe 'that are templated' do
67
- it 'with local values for operation, width, height and values of options' do
68
- locals = {
69
- operation: 'fit',
70
- width: 99,
71
- height: 66,
72
- format: 'png',
73
- bg: 'white'
74
- }
75
-
76
- Configuration::Thumbnail::ThumbnailSpec.new('small', '#{operation}', '#{width}', '#{height}', '#{format}', 'background-color' => '#{bg}').render(locals).should == {
77
- 'small' =>
78
- ['fit', '99', '66', 'png', {'background-color' => 'white'}]
79
- }
80
- end
81
-
82
- it 'with nested options provided by options key in <key>:<value>[,<key>:<value>]* format but not overwriting predefined options' do
83
- locals = {
84
- operation: 'fit',
85
- width: 99,
86
- height: 66,
87
- format: 'png',
88
- opts: 'background-color:blue,quality:100'
89
- }
90
-
91
- Configuration::Thumbnail::ThumbnailSpec.new('small', '#{operation}', '#{width}', '#{height}', '#{format}', 'options' => '#{opts}', 'background-color' => 'red').render(locals).should == {
92
- 'small' =>
93
- ['fit', '99', '66', 'png', {'background-color' => 'red', 'quality' => '100'}]
94
- }
95
- end
96
- end
97
-
98
- describe 'error handling' do
99
- it 'should raise NoValueForSpecTemplatePlaceholerError on missing spec template value' do
100
- locals = {
101
- width: 99,
102
- height: 66,
103
- format: 'png'
104
- }
105
-
106
- expect {
107
- Configuration::Thumbnail::ThumbnailSpec.new('small', '#{operation}', '#{width}', '#{height}', '#{format}').render(locals)
108
- }.to raise_error Configuration::NoValueForSpecTemplatePlaceholerError, %q{cannot generate specification for thumbnail 'small': cannot generate value for attribute 'method' from template '#{operation}': no value for #{operation}}
109
- end
110
-
111
- it 'should raise NoValueForSpecTemplatePlaceholerError on missing option template value' do
112
- locals = {
113
- width: 99,
114
- height: 66,
115
- format: 'png',
116
- }
117
-
118
- expect {
119
- Configuration::Thumbnail::ThumbnailSpec.new('small', '#{operation}', '#{width}', '#{height}', '#{format}', 'background-color' => '#{bg}').render(locals)
120
- }.to raise_error Configuration::NoValueForSpecTemplatePlaceholerError, %q{cannot generate specification for thumbnail 'small': cannot generate value for attribute 'background-color' from template '#{bg}': no value for #{bg}}
121
- end
122
- end
123
- end
124
-
125
- describe 'thumbnail source image' do
126
- before :all do
127
- log = support_dir + 'server.log'
128
- start_server(
129
- "httpthumbnailer -f -d -x XID -l #{log}",
130
- '/tmp/httpthumbnailer.pid',
131
- log,
132
- 'http://localhost:3100/'
133
- )
134
- end
135
-
136
- let :state do
137
- Configuration::RequestState.new(
138
- (support_dir + 'compute.jpg').read,
139
- {
140
- operation: 'pad',
141
- width: '10',
142
- height: '10',
143
- options: 'background-color:green'
144
- }
145
- )
146
- end
147
-
148
- before :each do
149
- subject.handlers[0].sources[0].realize(state)
150
- end
151
-
152
- describe 'thumbnailing to single spec' do
153
- subject do
154
- Configuration.read(<<-'EOF')
155
- put ":operation" ":width" ":height" ":options" {
156
- thumbnail "input" "original" operation="#{operation}" width="#{width}" height="#{height}" options="#{options}" quality=84 format="jpeg"
157
- }
158
- EOF
159
- end
160
-
161
- before :each do
162
- state.images['input'].source_path = 'test.in'
163
- state.images['input'].source_url = 'file://test.in'
164
- end
165
-
166
- it 'should provide thumbnail data' do
167
- subject.handlers[0].processors[0].realize(state)
168
- state.images['original'].data.should_not be_nil
169
- end
170
-
171
- it 'should set thumbnail mime type' do
172
- subject.handlers[0].processors[0].realize(state)
173
- state.images['original'].mime_type.should == 'image/jpeg'
174
- end
175
-
176
- it 'should use input image source path and url' do
177
- subject.handlers[0].processors[0].realize(state)
178
- state.images['original'].source_path.should == 'test.in'
179
- state.images['original'].source_url.should == 'file://test.in'
180
- end
181
-
182
- it 'should set input image mime type' do
183
- subject.handlers[0].processors[0].realize(state)
184
- state.images['input'].mime_type.should == 'image/jpeg'
185
- end
186
-
187
- describe 'memory limit' do
188
- let :state do
189
- Configuration::RequestState.new(
190
- (support_dir + 'compute.jpg').read,
191
- {
192
- operation: 'pad',
193
- width: '10',
194
- height: '10',
195
- options: 'background-color:green'
196
- },
197
- '',
198
- {},
199
- MemoryLimit.new(10)
200
- )
201
- end
202
-
203
- it 'should raise MemoryLimit::MemoryLimitedExceededError when limit is exceeded' do
204
- expect {
205
- subject.handlers[0].processors[0].realize(state)
206
- }.to raise_error MemoryLimit::MemoryLimitedExceededError
207
- end
208
- end
209
-
210
- describe 'passing HTTP headers to thumbnailer' do
211
- let :xid do
212
- rand(0..1000)
213
- end
214
-
215
- let :state do
216
- Configuration::RequestState.new(
217
- (support_dir + 'compute.jpg').read,
218
- {
219
- operation: 'pad',
220
- width: '10',
221
- height: '10',
222
- options: 'background-color:green'
223
- },
224
- '', {}, MemoryLimit.new,
225
- {'XID' => xid}
226
- )
227
- end
228
-
229
- it 'should pass headers provided with request state' do
230
- subject.handlers[0].processors[0].realize(state)
231
-
232
- (support_dir + 'server.log').read.should include "xid=\"#{xid}\""
233
- end
234
- end
235
-
236
- describe 'error handling' do
237
- it 'should raise Thumbnail::ThumbnailingError on realization of bad thumbnail sepc' do
238
- state = Configuration::RequestState.new(
239
- (support_dir + 'compute.jpg').read,
240
- {
241
- operation: 'pad',
242
- width: '0',
243
- height: '10',
244
- options: 'background-color:green'
245
- }
246
- )
247
-
248
- expect {
249
- subject.handlers[0].sources[0].realize(state)
250
- subject.handlers[0].processors[0].realize(state)
251
- }.to raise_error Configuration::Thumbnail::ThumbnailingError # WTF?, "thumbnailing of 'input' into 'original' failed: at least one image dimension is zero: 0x10"
252
- end
253
-
254
- it 'should raise NoValueError on missing source image name' do
255
- expect {
256
- Configuration.read(<<-EOF)
257
- put {
258
- thumbnail
259
- }
260
- EOF
261
- }.to raise_error Configuration::NoValueError, %{syntax error while parsing 'thumbnail': expected source image name}
262
- end
263
-
264
- it 'should raise NoValueError on missing source image name' do
265
- expect {
266
- Configuration.read(<<-EOF)
267
- put {
268
- thumbnail "input"
269
- }
270
- EOF
271
- }.to raise_error Configuration::NoValueError, %{syntax error while parsing 'thumbnail "input"': expected thumbnail image name}
272
- end
273
- end
274
- end
275
-
276
- describe 'thumbnailing to multiple specs' do
277
- subject do
278
- Configuration.read(<<-'EOF')
279
- put ":operation" ":width" ":height" ":options" {
280
- thumbnail "input" {
281
- "original" operation="#{operation}" width="#{width}" height="#{height}" options="#{options}" quality=84 format="jpeg"
282
- "small" operation="crop" width=128 height=128 format="jpeg"
283
- "padded" operation="pad" width=128 height=128 format="png" background-color="gray"
284
- }
285
- }
286
- EOF
287
- end
288
-
289
- before :each do
290
- state.images['input'].source_path = 'test.in'
291
- state.images['input'].source_url = 'file://test.in'
292
- end
293
-
294
- it 'should provide thumbnail data' do
295
- subject.handlers[0].processors[0].realize(state)
296
- state.images['original'].data.should_not be_nil
297
- state.images['small'].data.should_not be_nil
298
- state.images['padded'].data.should_not be_nil
299
- end
300
-
301
- it 'should set thumbnail mime type' do
302
- subject.handlers[0].processors[0].realize(state)
303
- state.images['original'].mime_type.should == 'image/jpeg'
304
- state.images['small'].mime_type.should == 'image/jpeg'
305
- state.images['padded'].mime_type.should == 'image/png'
306
- end
307
-
308
- it 'should set input image mime type' do
309
- subject.handlers[0].processors[0].realize(state)
310
- state.images['input'].mime_type.should == 'image/jpeg'
311
- end
312
-
313
- it 'should use input image source path and url' do
314
- subject.handlers[0].processors[0].realize(state)
315
- state.images['original'].source_path.should == 'test.in'
316
- state.images['original'].source_url.should == 'file://test.in'
317
- state.images['small'].source_path.should == 'test.in'
318
- state.images['small'].source_url.should == 'file://test.in'
319
- state.images['padded'].source_path.should == 'test.in'
320
- state.images['padded'].source_url.should == 'file://test.in'
321
- end
322
-
323
- describe 'memory limit' do
324
- let :state do
325
- Configuration::RequestState.new(
326
- (support_dir + 'compute.jpg').read,
327
- {
328
- operation: 'pad',
329
- width: '10',
330
- height: '10',
331
- options: 'background-color:green'
332
- },
333
- '',
334
- {},
335
- MemoryLimit.new(10)
336
- )
337
- end
338
-
339
- it 'should raise MemoryLimit::MemoryLimitedExceededError when limit is exceeded' do
340
- expect {
341
- subject.handlers[0].processors[0].realize(state)
342
- }.to raise_error MemoryLimit::MemoryLimitedExceededError
343
- end
344
- end
345
-
346
- describe 'conditional inclusion support' do
347
- subject do
348
- Configuration.read(<<-'EOF')
349
- put {
350
- thumbnail "input" {
351
- "original" if-image-name-on="#{list}"
352
- "small" if-image-name-on="#{list}"
353
- "padded" if-image-name-on="#{list}"
354
- }
355
- }
356
- EOF
357
- end
358
-
359
- let :state do
360
- Configuration::RequestState.new(
361
- (support_dir + 'compute.jpg').read,
362
- {
363
- operation: 'pad',
364
- width: '10',
365
- height: '10',
366
- options: 'background-color:green',
367
- list: 'small,padded'
368
- }
369
- )
370
- end
371
-
372
- it 'should provide thumbnails that name match if-image-name-on list' do
373
- subject.handlers[0].processors[0].realize(state)
374
- state.images.should_not include 'original'
375
- state.images['small'].data.should_not be_nil
376
- state.images['padded'].data.should_not be_nil
377
- end
378
- end
379
-
380
- describe 'passing HTTP headers to thumbnailer' do
381
- let :xid do
382
- rand(0..1000)
383
- end
384
-
385
- let :state do
386
- Configuration::RequestState.new(
387
- (support_dir + 'compute.jpg').read,
388
- {
389
- operation: 'pad',
390
- width: '10',
391
- height: '10',
392
- options: 'background-color:green'
393
- },
394
- '', {}, MemoryLimit.new,
395
- {'XID' => xid}
396
- )
397
- end
398
-
399
- it 'should pass headers provided with request state' do
400
- subject.handlers[0].processors[0].realize(state)
401
- state.images.keys.should include 'original'
402
- state.images.keys.should include 'small'
403
-
404
- (support_dir + 'server.log').read.should include "xid=\"#{xid}\""
405
- end
406
- end
407
-
408
- describe 'error handling' do
409
- it 'should raise Thumbnail::ThumbnailingError on realization of bad thumbnail sepc' do
410
- state = Configuration::RequestState.new(
411
- (support_dir + 'compute.jpg').read,
412
- {
413
- operation: 'pad',
414
- width: '0',
415
- height: '10',
416
- options: 'background-color:green'
417
- }
418
- )
419
-
420
- subject.handlers[0].sources[0].realize(state)
421
-
422
- expect {
423
- subject.handlers[0].processors[0].realize(state)
424
- }.to raise_error Configuration::Thumbnail::ThumbnailingError, "thumbnailing of 'input' into 'original' failed: at least one image dimension is zero: 0x10"
425
- end
426
-
427
- it 'should raise NoValueError on missing source image name' do
428
- expect {
429
- Configuration.read(<<-EOF)
430
- put {
431
- thumbnail {
432
- }
433
- }
434
- EOF
435
- }.to raise_error Configuration::NoValueError, %{syntax error while parsing 'thumbnail': expected source image name}
436
- end
437
- end
438
- end
439
- end
440
-
441
- describe 'conditional inclusion support' do
442
- let :state do
443
- Configuration::RequestState.new(
444
- (support_dir + 'compute.jpg').read,
445
- {
446
- list: 'thumbnail1,input4,thumbnail5,input6'
447
- }
448
- )
449
- end
450
-
451
- subject do
452
- Configuration.read(<<-'EOF')
453
- put {
454
- thumbnail "input1" "thumbnail1" if-image-name-on="#{list}"
455
- thumbnail "input2" "thumbnail2" if-image-name-on="#{list}"
456
- thumbnail "input3" if-image-name-on="#{list}" {
457
- "thumbnail3"
458
- }
459
- thumbnail "input4" if-image-name-on="#{list}" {
460
- "thumbnail4"
461
- }
462
- thumbnail "input5" if-image-name-on="#{list}" {
463
- "thumbnail5" if-image-name-on="#{list}"
464
- }
465
- thumbnail "input6" if-image-name-on="#{list}" {
466
- "thumbnail6" if-image-name-on="#{list}"
467
- }
468
- }
469
- EOF
470
- end
471
-
472
- it 'should mark source to be included when output image name in oneline and destination image name in multiline statement match if-image-name-on list' do
473
- subject.handlers[0].processors[0].excluded?(state).should be_false
474
- subject.handlers[0].processors[1].excluded?(state).should be_true
475
- subject.handlers[0].processors[2].excluded?(state).should be_true
476
- subject.handlers[0].processors[3].excluded?(state).should be_false
477
- subject.handlers[0].processors[4].excluded?(state).should be_true
478
- subject.handlers[0].processors[5].excluded?(state).should be_false
479
- end
480
- end
481
- end
482
- end
483
-