httpimagestore 1.8.1 → 1.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
-