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.
- checksums.yaml +15 -0
- data/Gemfile +7 -7
- data/Gemfile.lock +20 -20
- data/README.md +165 -37
- data/Rakefile +7 -2
- data/VERSION +1 -1
- data/bin/httpimagestore +74 -41
- data/lib/httpimagestore/configuration/file.rb +20 -11
- data/lib/httpimagestore/configuration/handler.rb +96 -257
- data/lib/httpimagestore/configuration/handler/source_store_base.rb +37 -0
- data/lib/httpimagestore/configuration/handler/statement.rb +114 -0
- data/lib/httpimagestore/configuration/identify.rb +17 -9
- data/lib/httpimagestore/configuration/output.rb +33 -61
- data/lib/httpimagestore/configuration/path.rb +2 -2
- data/lib/httpimagestore/configuration/request_state.rb +131 -0
- data/lib/httpimagestore/configuration/s3.rb +41 -29
- data/lib/httpimagestore/configuration/thumbnailer.rb +189 -96
- data/lib/httpimagestore/configuration/validate_hmac.rb +170 -0
- data/lib/httpimagestore/error_reporter.rb +6 -1
- data/lib/httpimagestore/ruby_string_template.rb +10 -19
- metadata +40 -102
- data/.rspec +0 -1
- data/features/cache-control.feature +0 -41
- data/features/compatibility.feature +0 -165
- data/features/data-uri.feature +0 -55
- data/features/encoding.feature +0 -103
- data/features/error-reporting.feature +0 -281
- data/features/flexi.feature +0 -259
- data/features/health-check.feature +0 -29
- data/features/request-matching.feature +0 -211
- data/features/rewrite.feature +0 -122
- data/features/s3-store-and-thumbnail.feature +0 -82
- data/features/source-failover.feature +0 -71
- data/features/step_definitions/httpimagestore_steps.rb +0 -203
- data/features/storage.feature +0 -198
- data/features/support/env.rb +0 -116
- data/features/support/test-large.jpg +0 -0
- data/features/support/test.empty +0 -0
- data/features/support/test.jpg +0 -0
- data/features/support/test.png +0 -0
- data/features/support/test.txt +0 -1
- data/features/support/tiny.png +0 -0
- data/features/xid-forwarding.feature +0 -49
- data/httpimagestore.gemspec +0 -145
- data/load_test/load_test.1k.23a022f6e.m1.small-comp.csv +0 -3
- data/load_test/load_test.1k.ec9bde794.m1.small.csv +0 -4
- data/load_test/load_test.jmx +0 -317
- data/load_test/thumbnail_specs.csv +0 -11
- data/load_test/thumbnail_specs_v2.csv +0 -10
- data/spec/configuration_file_spec.rb +0 -333
- data/spec/configuration_handler_spec.rb +0 -255
- data/spec/configuration_identify_spec.rb +0 -67
- data/spec/configuration_output_spec.rb +0 -821
- data/spec/configuration_path_spec.rb +0 -138
- data/spec/configuration_s3_spec.rb +0 -911
- data/spec/configuration_source_failover_spec.rb +0 -101
- data/spec/configuration_spec.rb +0 -90
- data/spec/configuration_thumbnailer_spec.rb +0 -483
- data/spec/ruby_string_template_spec.rb +0 -61
- data/spec/spec_helper.rb +0 -89
- data/spec/support/compute.jpg +0 -0
- data/spec/support/cuba_response_env.rb +0 -40
- data/spec/support/full.cfg +0 -183
- data/spec/support/utf_string.txt +0 -1
|
@@ -1,255 +0,0 @@
|
|
|
1
|
-
require_relative 'spec_helper'
|
|
2
|
-
require_relative 'support/cuba_response_env'
|
|
3
|
-
|
|
4
|
-
require 'httpimagestore/configuration'
|
|
5
|
-
MemoryLimit.logger = Configuration::Scope.logger = RootLogger.new('/dev/null')
|
|
6
|
-
|
|
7
|
-
require 'httpimagestore/configuration/handler'
|
|
8
|
-
require 'httpimagestore/configuration/output'
|
|
9
|
-
|
|
10
|
-
describe Configuration do
|
|
11
|
-
describe Configuration::Handler do
|
|
12
|
-
subject do
|
|
13
|
-
Configuration.read(<<-EOF)
|
|
14
|
-
get "thumbnail" "v1" ":operation" ":width" ":height" ":options" {
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
put "thumbnail" "v1" ":test/.+/" {
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
post {
|
|
21
|
-
}
|
|
22
|
-
EOF
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
describe 'http method and matchers' do
|
|
26
|
-
it 'should provide request http_method and uri_matchers' do
|
|
27
|
-
subject.handlers.length.should == 3
|
|
28
|
-
|
|
29
|
-
subject.handlers[0].http_method.should == 'get'
|
|
30
|
-
subject.handlers[0].uri_matchers.map{|m| m.names}.flatten.should == [:operation, :width, :height, :options]
|
|
31
|
-
|
|
32
|
-
subject.handlers[1].http_method.should == 'put'
|
|
33
|
-
subject.handlers[1].uri_matchers.map{|m| m.names}.flatten.should == [:test]
|
|
34
|
-
|
|
35
|
-
subject.handlers[2].http_method.should == 'post'
|
|
36
|
-
subject.handlers[2].uri_matchers.should be_empty
|
|
37
|
-
end
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
describe Configuration::RequestState do
|
|
41
|
-
subject do
|
|
42
|
-
Configuration::RequestState.new(
|
|
43
|
-
'test',
|
|
44
|
-
{operation: 'pad'},
|
|
45
|
-
'/hello/world.jpg',
|
|
46
|
-
{width: '123', height: '321'}
|
|
47
|
-
)
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
it 'should behave like hash' do
|
|
51
|
-
subject['a'] = 'b'
|
|
52
|
-
subject['a'].should == 'b'
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
it 'should provide body' do
|
|
56
|
-
subject.body.should == 'test'
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
describe 'variables' do
|
|
60
|
-
it 'should provide path' do
|
|
61
|
-
subject[:path].should == '/hello/world.jpg'
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
it 'should provide matches' do
|
|
65
|
-
subject[:operation].should == 'pad'
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
it 'should provide query_string_options' do
|
|
69
|
-
subject[:query_string_options].should == 'height:321,width:123'
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
it 'should provide request body digest' do
|
|
73
|
-
subject[:digest].should == '9f86d081884c7d65' # deprecated
|
|
74
|
-
subject[:input_digest].should == '9f86d081884c7d65'
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
it 'should provide request body full sha256 checsum' do
|
|
78
|
-
subject[:input_sha256].should == '9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08'
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
it 'should provide input image mime extension' do
|
|
82
|
-
subject.images['input'] = Struct.new(:data, :mime_type).new('image body', 'image/jpeg')
|
|
83
|
-
subject.images['input'].extend Configuration::ImageMetaData
|
|
84
|
-
subject[:input_image_mime_extension].should == 'jpg'
|
|
85
|
-
end
|
|
86
|
-
|
|
87
|
-
it 'should provide input image width and height' do
|
|
88
|
-
subject.images['input'] = Struct.new(:data, :width, :height).new('image body', 128, 256)
|
|
89
|
-
subject[:input_image_width].should == 128
|
|
90
|
-
subject[:input_image_height].should == 256
|
|
91
|
-
end
|
|
92
|
-
|
|
93
|
-
it 'should provide image body digest' do
|
|
94
|
-
subject.images['abc'] = Struct.new(:data).new('image body')
|
|
95
|
-
subject.with_locals(image_name: 'abc')[:image_digest].should == 'f5288dd892bb007b'
|
|
96
|
-
end
|
|
97
|
-
|
|
98
|
-
it 'should provide image body full sha256 checsum' do
|
|
99
|
-
subject.images['abc'] = Struct.new(:data).new('image body')
|
|
100
|
-
subject.with_locals(image_name: 'abc')[:image_sha256].should == 'f5288dd892bb007b607304a8fb20c91ea769dcd04d82cc8ddf3239602867eb4d'
|
|
101
|
-
end
|
|
102
|
-
|
|
103
|
-
it 'should provide uuid' do
|
|
104
|
-
subject[:uuid].should_not be_empty
|
|
105
|
-
subject[:uuid].should == subject[:uuid]
|
|
106
|
-
end
|
|
107
|
-
|
|
108
|
-
it 'should provide extension' do
|
|
109
|
-
subject[:extension].should == 'jpg'
|
|
110
|
-
end
|
|
111
|
-
|
|
112
|
-
it 'should provide dirname' do
|
|
113
|
-
subject[:dirname].should == '/hello'
|
|
114
|
-
end
|
|
115
|
-
|
|
116
|
-
it 'should provide basename' do
|
|
117
|
-
subject[:basename].should == 'world'
|
|
118
|
-
end
|
|
119
|
-
|
|
120
|
-
it 'should provide image mime extension' do
|
|
121
|
-
subject.images['abc'] = Struct.new(:data, :mime_type).new('image body', 'image/jpeg')
|
|
122
|
-
subject.images['abc'].extend Configuration::ImageMetaData
|
|
123
|
-
subject.with_locals(image_name: 'abc')[:mimeextension].should == 'jpg' # deprecated
|
|
124
|
-
subject.with_locals(image_name: 'abc')[:image_mime_extension].should == 'jpg'
|
|
125
|
-
end
|
|
126
|
-
|
|
127
|
-
it 'should provide image width and height' do
|
|
128
|
-
subject.images['abc'] = Struct.new(:data, :width, :height).new('image body', 128, 256)
|
|
129
|
-
subject.with_locals(image_name: 'abc')[:image_width].should == 128
|
|
130
|
-
subject.with_locals(image_name: 'abc')[:image_height].should == 256
|
|
131
|
-
end
|
|
132
|
-
|
|
133
|
-
describe "error handling" do
|
|
134
|
-
it 'should raise NoRequestBodyToGenerateMetaVariableError when empty body was provided and body needed for variable calculation' do
|
|
135
|
-
subject = Configuration::RequestState.new(
|
|
136
|
-
'',
|
|
137
|
-
{operation: 'pad'},
|
|
138
|
-
'/hello/world.jpg',
|
|
139
|
-
{width: '123', height: '321'}
|
|
140
|
-
)
|
|
141
|
-
|
|
142
|
-
expect {
|
|
143
|
-
subject[:input_digest]
|
|
144
|
-
}.to raise_error Configuration::NoRequestBodyToGenerateMetaVariableError, %q{need not empty request body to generate value for 'input_digest'}
|
|
145
|
-
end
|
|
146
|
-
|
|
147
|
-
it 'should raise ImageNotLoadedError when asking for image related variable of not loaded image' do
|
|
148
|
-
expect {
|
|
149
|
-
subject.with_locals(image_name: 'abc')[:image_mime_extension]
|
|
150
|
-
}.to raise_error Configuration::ImageNotLoadedError, %q{image 'abc' not loaded}
|
|
151
|
-
end
|
|
152
|
-
|
|
153
|
-
it 'should raise NoVariableToGenerateMetaVariableError when no image_name was defined' do
|
|
154
|
-
expect {
|
|
155
|
-
subject.with_locals({})[:image_mime_extension]
|
|
156
|
-
}.to raise_error Configuration::NoVariableToGenerateMetaVariableError, %q{need 'image_name' variable to generate value for 'image_mime_extension'}
|
|
157
|
-
end
|
|
158
|
-
|
|
159
|
-
it 'should raise NoVariableToGenerateMetaVariableError when no path was defined' do
|
|
160
|
-
expect {
|
|
161
|
-
subject.delete(:path)
|
|
162
|
-
subject[:basename]
|
|
163
|
-
}.to raise_error Configuration::NoVariableToGenerateMetaVariableError, %q{need 'path' variable to generate value for 'basename'}
|
|
164
|
-
end
|
|
165
|
-
|
|
166
|
-
it 'should raise NoImageDataForVariableError when image has no mime type' do
|
|
167
|
-
subject.images['abc'] = Struct.new(:data, :mime_type).new('image body', nil)
|
|
168
|
-
subject.images['abc'].extend Configuration::ImageMetaData
|
|
169
|
-
expect {
|
|
170
|
-
subject.with_locals(image_name: 'abc')[:image_mime_extension]
|
|
171
|
-
}.to raise_error Configuration::NoImageDataForVariableError, %q{image 'abc' does not have data for variable 'image_mime_extension'}
|
|
172
|
-
end
|
|
173
|
-
|
|
174
|
-
it 'should raise NoImageDataForVariableError when image has no known width or height' do
|
|
175
|
-
subject.images['abc'] = Struct.new(:data, :width, :height).new('image body', nil, nil)
|
|
176
|
-
expect {
|
|
177
|
-
subject.with_locals(image_name: 'abc')[:image_width]
|
|
178
|
-
}.to raise_error Configuration::NoImageDataForVariableError, %q{image 'abc' does not have data for variable 'image_width'}
|
|
179
|
-
expect {
|
|
180
|
-
subject.with_locals(image_name: 'abc')[:image_height]
|
|
181
|
-
}.to raise_error Configuration::NoImageDataForVariableError, %q{image 'abc' does not have data for variable 'image_height'}
|
|
182
|
-
end
|
|
183
|
-
end
|
|
184
|
-
end
|
|
185
|
-
|
|
186
|
-
it 'should raise ImageNotLoadedError if image lookup fails' do
|
|
187
|
-
expect {
|
|
188
|
-
Configuration::RequestState.new.images['test']
|
|
189
|
-
}.to raise_error Configuration::ImageNotLoadedError, "image 'test' not loaded"
|
|
190
|
-
end
|
|
191
|
-
|
|
192
|
-
it 'should free memory limit if overwritting image' do
|
|
193
|
-
limit = MemoryLimit.new(2)
|
|
194
|
-
request_state = Configuration::RequestState.new('abc', {}, '', {}, limit)
|
|
195
|
-
|
|
196
|
-
limit.borrow 1
|
|
197
|
-
request_state.images['test'] = Configuration::Image.new('x')
|
|
198
|
-
limit.limit.should == 1
|
|
199
|
-
|
|
200
|
-
limit.borrow 1
|
|
201
|
-
limit.limit.should == 0
|
|
202
|
-
request_state.images['test'] = Configuration::Image.new('x')
|
|
203
|
-
limit.limit.should == 1
|
|
204
|
-
|
|
205
|
-
limit.borrow 1
|
|
206
|
-
limit.limit.should == 0
|
|
207
|
-
request_state.images['test'] = Configuration::Image.new('x')
|
|
208
|
-
limit.limit.should == 1
|
|
209
|
-
|
|
210
|
-
limit.borrow 1
|
|
211
|
-
limit.limit.should == 0
|
|
212
|
-
request_state.images['test2'] = Configuration::Image.new('x')
|
|
213
|
-
limit.limit.should == 0
|
|
214
|
-
end
|
|
215
|
-
end
|
|
216
|
-
|
|
217
|
-
describe 'sources' do
|
|
218
|
-
it 'should have implicit InputSource on non get handlers' do
|
|
219
|
-
subject.handlers[0].sources.first.should_not be_a Configuration::InputSource
|
|
220
|
-
subject.handlers[1].sources.first.should be_a Configuration::InputSource
|
|
221
|
-
subject.handlers[2].sources.first.should be_a Configuration::InputSource
|
|
222
|
-
end
|
|
223
|
-
|
|
224
|
-
describe Configuration::InputSource do
|
|
225
|
-
it 'should copy input data to "input" image when realized' do
|
|
226
|
-
state = Configuration::RequestState.new('abc')
|
|
227
|
-
input_source = subject.handlers[1].sources[0].realize(state)
|
|
228
|
-
state.images['input'].data.should == 'abc'
|
|
229
|
-
end
|
|
230
|
-
|
|
231
|
-
it 'should have nil mime type' do
|
|
232
|
-
state = Configuration::RequestState.new('abc')
|
|
233
|
-
input_source = subject.handlers[1].sources[0].realize(state)
|
|
234
|
-
state.images['input'].mime_type.should be_nil
|
|
235
|
-
end
|
|
236
|
-
|
|
237
|
-
it 'should have nil source path and url' do
|
|
238
|
-
state = Configuration::RequestState.new('abc')
|
|
239
|
-
input_source = subject.handlers[1].sources[0].realize(state)
|
|
240
|
-
state.images['input'].source_path.should be_nil
|
|
241
|
-
state.images['input'].source_url.should be_nil
|
|
242
|
-
end
|
|
243
|
-
end
|
|
244
|
-
end
|
|
245
|
-
|
|
246
|
-
describe 'output' do
|
|
247
|
-
it 'should default to OutputOK' do
|
|
248
|
-
subject.handlers[0].output.should be_a Configuration::OutputOK
|
|
249
|
-
subject.handlers[1].output.should be_a Configuration::OutputOK
|
|
250
|
-
subject.handlers[2].output.should be_a Configuration::OutputOK
|
|
251
|
-
end
|
|
252
|
-
end
|
|
253
|
-
end
|
|
254
|
-
end
|
|
255
|
-
|
|
@@ -1,67 +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
|
-
require 'httpimagestore/configuration/identify'
|
|
8
|
-
|
|
9
|
-
describe Configuration do
|
|
10
|
-
describe 'identify' do
|
|
11
|
-
before :all do
|
|
12
|
-
log = support_dir + 'server.log'
|
|
13
|
-
start_server(
|
|
14
|
-
"httpthumbnailer -f -d -x XID -l #{log}",
|
|
15
|
-
'/tmp/httpthumbnailer.pid',
|
|
16
|
-
log,
|
|
17
|
-
'http://localhost:3100/'
|
|
18
|
-
)
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
let :state do
|
|
22
|
-
Configuration::RequestState.new(
|
|
23
|
-
(support_dir + 'compute.jpg').read
|
|
24
|
-
)
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
subject do
|
|
28
|
-
Configuration.read(<<-'EOF')
|
|
29
|
-
put {
|
|
30
|
-
identify "input"
|
|
31
|
-
}
|
|
32
|
-
EOF
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
it 'should provide input image mime type' do
|
|
36
|
-
subject.handlers[0].sources[0].realize(state)
|
|
37
|
-
state.images['input'].mime_type.should be_nil
|
|
38
|
-
|
|
39
|
-
subject.handlers[0].processors[0].realize(state)
|
|
40
|
-
state.images['input'].mime_type.should == 'image/jpeg'
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
describe 'passing HTTP headers to thumbnailer' do
|
|
44
|
-
let :xid do
|
|
45
|
-
rand(0..1000)
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
let :state do
|
|
49
|
-
Configuration::RequestState.new(
|
|
50
|
-
(support_dir + 'compute.jpg').read,
|
|
51
|
-
{}, '', {}, MemoryLimit.new,
|
|
52
|
-
{'XID' => xid}
|
|
53
|
-
)
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
it 'should pass headers provided with request state' do
|
|
57
|
-
subject.handlers[0].sources[0].realize(state)
|
|
58
|
-
subject.handlers[0].processors[0].realize(state)
|
|
59
|
-
state.images['input'].mime_type.should == 'image/jpeg'
|
|
60
|
-
|
|
61
|
-
(support_dir + 'server.log').read.should include "xid=\"#{xid}\""
|
|
62
|
-
end
|
|
63
|
-
end
|
|
64
|
-
end
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
|
|
@@ -1,821 +0,0 @@
|
|
|
1
|
-
require_relative 'spec_helper'
|
|
2
|
-
require_relative 'support/cuba_response_env'
|
|
3
|
-
|
|
4
|
-
require 'httpimagestore/configuration'
|
|
5
|
-
MemoryLimit.logger = Configuration::Scope.logger = RootLogger.new('/dev/null')
|
|
6
|
-
|
|
7
|
-
require 'httpimagestore/configuration/output'
|
|
8
|
-
require 'httpimagestore/configuration/file'
|
|
9
|
-
|
|
10
|
-
describe Configuration do
|
|
11
|
-
let :state do
|
|
12
|
-
Configuration::RequestState.new('abc')
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
let :env do
|
|
16
|
-
CubaResponseEnv.new
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
describe Configuration::OutputText do
|
|
20
|
-
subject do
|
|
21
|
-
Configuration.read(<<-'EOF')
|
|
22
|
-
get "test" {
|
|
23
|
-
output_text "hello world"
|
|
24
|
-
}
|
|
25
|
-
get "test" {
|
|
26
|
-
output_text "bad stuff" status=500
|
|
27
|
-
}
|
|
28
|
-
get "test" {
|
|
29
|
-
output_text "welcome" cache-control="public"
|
|
30
|
-
}
|
|
31
|
-
get "test" {
|
|
32
|
-
output_text "test1: #{test1} test2: #{test2}"
|
|
33
|
-
}
|
|
34
|
-
EOF
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
it 'should output hello world with default 200 status' do
|
|
38
|
-
subject.handlers[0].output.realize(state)
|
|
39
|
-
env = CubaResponseEnv.new
|
|
40
|
-
env.instance_eval &state.output_callback
|
|
41
|
-
env.res.status.should == 200
|
|
42
|
-
env.res.data.should == "hello world\r\n"
|
|
43
|
-
env.res['Content-Type'].should == 'text/plain'
|
|
44
|
-
env.res['Cache-Control'].should be_nil
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
it 'should output bad stuff with 500 status' do
|
|
48
|
-
subject.handlers[1].output.realize(state)
|
|
49
|
-
env = CubaResponseEnv.new
|
|
50
|
-
env.instance_eval &state.output_callback
|
|
51
|
-
env.res.status.should == 500
|
|
52
|
-
env.res.data.should == "bad stuff\r\n"
|
|
53
|
-
env.res['Content-Type'].should == 'text/plain'
|
|
54
|
-
env.res['Cache-Control'].should be_nil
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
it 'should output welcome with public cache control' do
|
|
58
|
-
subject.handlers[2].output.realize(state)
|
|
59
|
-
env = CubaResponseEnv.new
|
|
60
|
-
env.instance_eval &state.output_callback
|
|
61
|
-
env.res.status.should == 200
|
|
62
|
-
env.res.data.should == "welcome\r\n"
|
|
63
|
-
env.res['Content-Type'].should == 'text/plain'
|
|
64
|
-
env.res['Cache-Control'].should == 'public'
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
it 'should output text interpolated with variable values' do
|
|
68
|
-
state = Configuration::RequestState.new
|
|
69
|
-
state[:test1] = 'abc'
|
|
70
|
-
state[:test2] = 'xyz'
|
|
71
|
-
|
|
72
|
-
subject.handlers[3].output.realize(state)
|
|
73
|
-
env = CubaResponseEnv.new
|
|
74
|
-
env.instance_eval &state.output_callback
|
|
75
|
-
env.res.data.should == "test1: abc test2: xyz\r\n"
|
|
76
|
-
end
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
describe Configuration::OutputOK do
|
|
80
|
-
subject do
|
|
81
|
-
Configuration.read(<<-EOF)
|
|
82
|
-
put "test" {
|
|
83
|
-
output_ok
|
|
84
|
-
}
|
|
85
|
-
EOF
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
before :each do
|
|
89
|
-
subject.handlers[0].sources[0].realize(state)
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
it 'should output 200 with OK text/plain message when realized' do
|
|
93
|
-
state = Configuration::RequestState.new('abc')
|
|
94
|
-
subject.handlers[0].output.realize(state)
|
|
95
|
-
|
|
96
|
-
env = CubaResponseEnv.new
|
|
97
|
-
env.instance_eval &state.output_callback
|
|
98
|
-
env.res.status.should == 200
|
|
99
|
-
env.res.data.should == "OK\r\n"
|
|
100
|
-
env.res['Content-Type'].should == 'text/plain'
|
|
101
|
-
end
|
|
102
|
-
end
|
|
103
|
-
|
|
104
|
-
describe Configuration::OutputImage do
|
|
105
|
-
subject do
|
|
106
|
-
Configuration.read(<<-EOF)
|
|
107
|
-
put "test" {
|
|
108
|
-
output_image "input"
|
|
109
|
-
}
|
|
110
|
-
EOF
|
|
111
|
-
end
|
|
112
|
-
|
|
113
|
-
before :each do
|
|
114
|
-
subject.handlers[0].sources[0].realize(state)
|
|
115
|
-
end
|
|
116
|
-
|
|
117
|
-
it 'should provide given image' do
|
|
118
|
-
subject.handlers[0].output.should be_a Configuration::OutputImage
|
|
119
|
-
subject.handlers[0].output.realize(state)
|
|
120
|
-
|
|
121
|
-
env.instance_eval &state.output_callback
|
|
122
|
-
env.res.status.should == 200
|
|
123
|
-
env.res.data.should == 'abc'
|
|
124
|
-
end
|
|
125
|
-
|
|
126
|
-
it 'should use default content type if not defined on image' do
|
|
127
|
-
subject.handlers[0].output.realize(state)
|
|
128
|
-
|
|
129
|
-
env.instance_eval &state.output_callback
|
|
130
|
-
env.res['Content-Type'].should == 'application/octet-stream'
|
|
131
|
-
end
|
|
132
|
-
|
|
133
|
-
it 'should use image mime type if available' do
|
|
134
|
-
state.images['input'].mime_type = 'image/jpeg'
|
|
135
|
-
|
|
136
|
-
subject.handlers[0].output.realize(state)
|
|
137
|
-
|
|
138
|
-
env.instance_eval &state.output_callback
|
|
139
|
-
env.res['Content-Type'].should == 'image/jpeg'
|
|
140
|
-
end
|
|
141
|
-
|
|
142
|
-
describe 'Cache-Control header support' do
|
|
143
|
-
subject do
|
|
144
|
-
Configuration.read(<<-EOF)
|
|
145
|
-
put "test" {
|
|
146
|
-
output_image "input" cache-control="public, max-age=999, s-maxage=666"
|
|
147
|
-
}
|
|
148
|
-
EOF
|
|
149
|
-
end
|
|
150
|
-
|
|
151
|
-
it 'should allow setting Cache-Control header' do
|
|
152
|
-
subject.handlers[0].output.realize(state)
|
|
153
|
-
|
|
154
|
-
env.instance_eval &state.output_callback
|
|
155
|
-
env.res['Cache-Control'].should == 'public, max-age=999, s-maxage=666'
|
|
156
|
-
end
|
|
157
|
-
end
|
|
158
|
-
end
|
|
159
|
-
|
|
160
|
-
describe 'output store paths and URLs' do
|
|
161
|
-
let :utf_string do
|
|
162
|
-
(support_dir + 'utf_string.txt').read.strip
|
|
163
|
-
end
|
|
164
|
-
|
|
165
|
-
let :in_file do
|
|
166
|
-
Pathname.new("/tmp/test.in")
|
|
167
|
-
end
|
|
168
|
-
|
|
169
|
-
let :out_file do
|
|
170
|
-
Pathname.new("/tmp/test.out")
|
|
171
|
-
end
|
|
172
|
-
|
|
173
|
-
let :out2_file do
|
|
174
|
-
Pathname.new("/tmp/test.out2")
|
|
175
|
-
end
|
|
176
|
-
|
|
177
|
-
let :test_file do
|
|
178
|
-
Pathname.new('/tmp/abc/test.out')
|
|
179
|
-
end
|
|
180
|
-
|
|
181
|
-
let :space_test_file do
|
|
182
|
-
Pathname.new('/tmp/abc/t e s t.out')
|
|
183
|
-
end
|
|
184
|
-
|
|
185
|
-
let :utf_test_file do
|
|
186
|
-
Pathname.new("/tmp/abc/#{utf_string}.out")
|
|
187
|
-
end
|
|
188
|
-
|
|
189
|
-
before :each do
|
|
190
|
-
test_file.dirname.mkdir unless test_file.dirname.directory?
|
|
191
|
-
test_file.open('w'){|io| io.write('abc')}
|
|
192
|
-
space_test_file.open('w'){|io| io.write('abc')}
|
|
193
|
-
in_file.open('w'){|io| io.write('abc')}
|
|
194
|
-
out_file.unlink if out_file.exist?
|
|
195
|
-
out2_file.unlink if out2_file.exist?
|
|
196
|
-
end
|
|
197
|
-
|
|
198
|
-
after :each do
|
|
199
|
-
test_file.exist? and test_file.unlink
|
|
200
|
-
space_test_file.exist? and space_test_file.unlink
|
|
201
|
-
utf_test_file.exist? and utf_test_file.unlink
|
|
202
|
-
test_file.dirname.exist? and test_file.dirname.rmdir
|
|
203
|
-
out_file.unlink if out_file.exist?
|
|
204
|
-
out2_file.unlink if out2_file.exist?
|
|
205
|
-
in_file.unlink
|
|
206
|
-
end
|
|
207
|
-
|
|
208
|
-
describe Configuration::OutputStorePath do
|
|
209
|
-
it 'should provide file store path' do
|
|
210
|
-
subject = Configuration.read(<<-EOF)
|
|
211
|
-
path {
|
|
212
|
-
"out" "test.out"
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
post "single" {
|
|
216
|
-
store_file "input" root="/tmp" path="out"
|
|
217
|
-
|
|
218
|
-
output_store_path "input"
|
|
219
|
-
}
|
|
220
|
-
EOF
|
|
221
|
-
|
|
222
|
-
subject.handlers[0].sources[0].realize(state)
|
|
223
|
-
subject.handlers[0].stores[0].realize(state)
|
|
224
|
-
subject.handlers[0].output.realize(state)
|
|
225
|
-
|
|
226
|
-
env.instance_eval &state.output_callback
|
|
227
|
-
env.res['Content-Type'].should == 'text/plain'
|
|
228
|
-
env.res.data.should == "test.out\r\n"
|
|
229
|
-
end
|
|
230
|
-
|
|
231
|
-
it 'should provide multiple file store paths' do
|
|
232
|
-
subject = Configuration.read(<<-EOF)
|
|
233
|
-
path {
|
|
234
|
-
"in" "test.in"
|
|
235
|
-
"out" "test.out"
|
|
236
|
-
"out2" "test.out2"
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
post "multi" {
|
|
240
|
-
source_file "original" root="/tmp" path="in"
|
|
241
|
-
|
|
242
|
-
store_file "input" root="/tmp" path="out"
|
|
243
|
-
store_file "original" root="/tmp" path="out2"
|
|
244
|
-
|
|
245
|
-
output_store_path {
|
|
246
|
-
"input"
|
|
247
|
-
"original"
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
EOF
|
|
251
|
-
|
|
252
|
-
subject.handlers[0].sources[0].realize(state)
|
|
253
|
-
subject.handlers[0].sources[1].realize(state)
|
|
254
|
-
subject.handlers[0].stores[0].realize(state)
|
|
255
|
-
subject.handlers[0].stores[1].realize(state)
|
|
256
|
-
subject.handlers[0].output.realize(state)
|
|
257
|
-
|
|
258
|
-
env.instance_eval &state.output_callback
|
|
259
|
-
env.res['Content-Type'].should == 'text/plain'
|
|
260
|
-
env.res.data.should == "test.out\r\ntest.out2\r\n"
|
|
261
|
-
end
|
|
262
|
-
|
|
263
|
-
describe 'conditional inclusion support' do
|
|
264
|
-
let :state do
|
|
265
|
-
Configuration::RequestState.new('abc', {list: 'input,image2'})
|
|
266
|
-
end
|
|
267
|
-
|
|
268
|
-
subject do
|
|
269
|
-
Configuration.read(<<-'EOF')
|
|
270
|
-
path {
|
|
271
|
-
"in" "test.in"
|
|
272
|
-
"out1" "test.out1"
|
|
273
|
-
"out2" "test.out2"
|
|
274
|
-
"out3" "test.out3"
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
post "multi" {
|
|
278
|
-
source_file "image1" root="/tmp" path="in"
|
|
279
|
-
source_file "image2" root="/tmp" path="in"
|
|
280
|
-
|
|
281
|
-
store_file "input" root="/tmp" path="out1"
|
|
282
|
-
store_file "image1" root="/tmp" path="out2"
|
|
283
|
-
store_file "image2" root="/tmp" path="out3"
|
|
284
|
-
|
|
285
|
-
output_store_path {
|
|
286
|
-
"input" if-image-name-on="#{list}"
|
|
287
|
-
"image1" if-image-name-on="#{list}"
|
|
288
|
-
"image2" if-image-name-on="#{list}"
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
EOF
|
|
292
|
-
end
|
|
293
|
-
|
|
294
|
-
it 'should output store path only for images that names match if-image-name-on list' do
|
|
295
|
-
subject.handlers[0].sources[0].realize(state)
|
|
296
|
-
subject.handlers[0].sources[1].realize(state)
|
|
297
|
-
subject.handlers[0].sources[2].realize(state)
|
|
298
|
-
subject.handlers[0].stores[0].realize(state)
|
|
299
|
-
subject.handlers[0].stores[1].realize(state)
|
|
300
|
-
subject.handlers[0].stores[2].realize(state)
|
|
301
|
-
subject.handlers[0].output.realize(state)
|
|
302
|
-
|
|
303
|
-
env.instance_eval &state.output_callback
|
|
304
|
-
env.res['Content-Type'].should == 'text/plain'
|
|
305
|
-
env.res.data.should == "test.out1\r\ntest.out3\r\n"
|
|
306
|
-
end
|
|
307
|
-
end
|
|
308
|
-
|
|
309
|
-
describe 'custom formatting' do
|
|
310
|
-
it 'should provide formatted file store path' do
|
|
311
|
-
subject = Configuration.read(<<-'EOF')
|
|
312
|
-
path "out" "abc/test.out"
|
|
313
|
-
path "formatted" "hello/#{dirname}/world/#{basename}-xyz.#{extension}"
|
|
314
|
-
|
|
315
|
-
post "single" {
|
|
316
|
-
store_file "input" root="/tmp" path="out"
|
|
317
|
-
|
|
318
|
-
output_store_path "input" path="formatted"
|
|
319
|
-
}
|
|
320
|
-
EOF
|
|
321
|
-
|
|
322
|
-
subject.handlers[0].sources[0].realize(state)
|
|
323
|
-
subject.handlers[0].stores[0].realize(state)
|
|
324
|
-
subject.handlers[0].output.realize(state)
|
|
325
|
-
|
|
326
|
-
env.instance_eval &state.output_callback
|
|
327
|
-
env.res['Content-Type'].should == 'text/plain'
|
|
328
|
-
env.res.data.should == "hello/abc/world/test-xyz.out\r\n"
|
|
329
|
-
end
|
|
330
|
-
|
|
331
|
-
it 'should provide formatted file store path for each path' do
|
|
332
|
-
subject = Configuration.read(<<-'EOF')
|
|
333
|
-
path "in" "test.in"
|
|
334
|
-
path "out" "abc/test.out"
|
|
335
|
-
path "out2" "test.out2"
|
|
336
|
-
|
|
337
|
-
path "formatted" "hello/#{dirname}/world/#{basename}-xyz.#{extension}"
|
|
338
|
-
path "formatted2" "#{image_digest}.#{extension}"
|
|
339
|
-
|
|
340
|
-
post "single" {
|
|
341
|
-
source_file "original" root="/tmp" path="in"
|
|
342
|
-
|
|
343
|
-
store_file "input" root="/tmp" path="out"
|
|
344
|
-
store_file "original" root="/tmp" path="out2"
|
|
345
|
-
|
|
346
|
-
output_store_path {
|
|
347
|
-
"input" path="formatted"
|
|
348
|
-
"original" path="formatted2"
|
|
349
|
-
}
|
|
350
|
-
}
|
|
351
|
-
EOF
|
|
352
|
-
|
|
353
|
-
subject.handlers[0].sources[0].realize(state)
|
|
354
|
-
subject.handlers[0].sources[1].realize(state)
|
|
355
|
-
subject.handlers[0].stores[0].realize(state)
|
|
356
|
-
subject.handlers[0].stores[1].realize(state)
|
|
357
|
-
subject.handlers[0].output.realize(state)
|
|
358
|
-
|
|
359
|
-
env.instance_eval &state.output_callback
|
|
360
|
-
env.res['Content-Type'].should == 'text/plain'
|
|
361
|
-
env.res.data.should == "hello/abc/world/test-xyz.out\r\nba7816bf8f01cfea.out2\r\n"
|
|
362
|
-
end
|
|
363
|
-
end
|
|
364
|
-
|
|
365
|
-
describe 'error handling' do
|
|
366
|
-
it 'should raise StorePathNotSetForImage for output of not stored image' do
|
|
367
|
-
subject = Configuration.read(<<-EOF)
|
|
368
|
-
post "single" {
|
|
369
|
-
output_store_path "input"
|
|
370
|
-
}
|
|
371
|
-
EOF
|
|
372
|
-
|
|
373
|
-
subject.handlers[0].sources[0].realize(state)
|
|
374
|
-
|
|
375
|
-
expect {
|
|
376
|
-
subject.handlers[0].output.realize(state)
|
|
377
|
-
}.to raise_error Configuration::StorePathNotSetForImage, %{store path not set for image 'input'}
|
|
378
|
-
end
|
|
379
|
-
end
|
|
380
|
-
end
|
|
381
|
-
|
|
382
|
-
describe Configuration::OutputStoreURL do
|
|
383
|
-
it 'should provide file store URL' do
|
|
384
|
-
subject = Configuration.read(<<-EOF)
|
|
385
|
-
path {
|
|
386
|
-
"out" "test.out"
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
post "single" {
|
|
390
|
-
store_file "input" root="/tmp" path="out"
|
|
391
|
-
|
|
392
|
-
output_store_url "input"
|
|
393
|
-
}
|
|
394
|
-
EOF
|
|
395
|
-
|
|
396
|
-
subject.handlers[0].sources[0].realize(state)
|
|
397
|
-
subject.handlers[0].stores[0].realize(state)
|
|
398
|
-
subject.handlers[0].output.realize(state)
|
|
399
|
-
|
|
400
|
-
env.instance_eval &state.output_callback
|
|
401
|
-
env.res['Content-Type'].should == 'text/uri-list'
|
|
402
|
-
env.res.data.should == "file:/test.out\r\n"
|
|
403
|
-
end
|
|
404
|
-
|
|
405
|
-
it 'should provide multiple file store URLs' do
|
|
406
|
-
subject = Configuration.read(<<-EOF)
|
|
407
|
-
path {
|
|
408
|
-
"in" "test.in"
|
|
409
|
-
"out" "test.out"
|
|
410
|
-
"out2" "test.out2"
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
post "multi" {
|
|
414
|
-
source_file "original" root="/tmp" path="in"
|
|
415
|
-
|
|
416
|
-
store_file "input" root="/tmp" path="out"
|
|
417
|
-
store_file "original" root="/tmp" path="out2"
|
|
418
|
-
|
|
419
|
-
output_store_url {
|
|
420
|
-
"input"
|
|
421
|
-
"original"
|
|
422
|
-
}
|
|
423
|
-
}
|
|
424
|
-
EOF
|
|
425
|
-
|
|
426
|
-
subject.handlers[0].sources[0].realize(state)
|
|
427
|
-
subject.handlers[0].sources[1].realize(state)
|
|
428
|
-
subject.handlers[0].stores[0].realize(state)
|
|
429
|
-
subject.handlers[0].stores[1].realize(state)
|
|
430
|
-
subject.handlers[0].output.realize(state)
|
|
431
|
-
|
|
432
|
-
env.instance_eval &state.output_callback
|
|
433
|
-
env.res['Content-Type'].should == 'text/uri-list'
|
|
434
|
-
env.res.data.should == "file:/test.out\r\nfile:/test.out2\r\n"
|
|
435
|
-
end
|
|
436
|
-
|
|
437
|
-
describe 'conditional inclusion support' do
|
|
438
|
-
let :state do
|
|
439
|
-
Configuration::RequestState.new('abc', list: 'input,image2')
|
|
440
|
-
end
|
|
441
|
-
|
|
442
|
-
subject do
|
|
443
|
-
Configuration.read(<<-'EOF')
|
|
444
|
-
path {
|
|
445
|
-
"in" "test.in"
|
|
446
|
-
"out1" "test.out1"
|
|
447
|
-
"out2" "test.out2"
|
|
448
|
-
"out3" "test.out3"
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
post "multi" {
|
|
452
|
-
source_file "image1" root="/tmp" path="in"
|
|
453
|
-
source_file "image2" root="/tmp" path="in"
|
|
454
|
-
|
|
455
|
-
store_file "input" root="/tmp" path="out1"
|
|
456
|
-
store_file "image1" root="/tmp" path="out2"
|
|
457
|
-
store_file "image2" root="/tmp" path="out3"
|
|
458
|
-
|
|
459
|
-
output_store_url {
|
|
460
|
-
"input" if-image-name-on="#{list}"
|
|
461
|
-
"image1" if-image-name-on="#{list}"
|
|
462
|
-
"image2" if-image-name-on="#{list}"
|
|
463
|
-
}
|
|
464
|
-
}
|
|
465
|
-
EOF
|
|
466
|
-
end
|
|
467
|
-
|
|
468
|
-
it 'should output store url only for images that names match if-image-name-on list' do
|
|
469
|
-
subject.handlers[0].sources[0].realize(state)
|
|
470
|
-
subject.handlers[0].sources[1].realize(state)
|
|
471
|
-
subject.handlers[0].sources[2].realize(state)
|
|
472
|
-
subject.handlers[0].stores[0].realize(state)
|
|
473
|
-
subject.handlers[0].stores[1].realize(state)
|
|
474
|
-
subject.handlers[0].stores[2].realize(state)
|
|
475
|
-
subject.handlers[0].output.realize(state)
|
|
476
|
-
|
|
477
|
-
env.instance_eval &state.output_callback
|
|
478
|
-
env.res['Content-Type'].should == 'text/uri-list'
|
|
479
|
-
env.res.data.should == "file:/test.out1\r\nfile:/test.out3\r\n"
|
|
480
|
-
end
|
|
481
|
-
end
|
|
482
|
-
|
|
483
|
-
describe 'URL rewrites' do
|
|
484
|
-
it 'should allow using path spec to rewrite URL path component' do
|
|
485
|
-
subject = Configuration.read(<<-'EOF')
|
|
486
|
-
path "out" "abc/test.out"
|
|
487
|
-
|
|
488
|
-
path "formatted" "hello/#{dirname}/world/#{basename}-xyz.#{extension}"
|
|
489
|
-
|
|
490
|
-
post "single" {
|
|
491
|
-
store_file "input" root="/tmp" path="out"
|
|
492
|
-
|
|
493
|
-
output_store_url "input" path="formatted"
|
|
494
|
-
}
|
|
495
|
-
EOF
|
|
496
|
-
|
|
497
|
-
subject.handlers[0].sources[0].realize(state)
|
|
498
|
-
subject.handlers[0].stores[0].realize(state)
|
|
499
|
-
subject.handlers[0].output.realize(state)
|
|
500
|
-
|
|
501
|
-
env.instance_eval &state.output_callback
|
|
502
|
-
env.res['Content-Type'].should == 'text/uri-list'
|
|
503
|
-
env.res.data.should == "file:/hello/abc/world/test-xyz.out\r\n"
|
|
504
|
-
end
|
|
505
|
-
|
|
506
|
-
it 'should allow rewriting scheme component' do
|
|
507
|
-
subject = Configuration.read(<<-'EOF')
|
|
508
|
-
path "out" "abc/test.out"
|
|
509
|
-
|
|
510
|
-
post "single" {
|
|
511
|
-
store_file "input" root="/tmp" path="out"
|
|
512
|
-
|
|
513
|
-
output_store_url "input" scheme="ftp"
|
|
514
|
-
}
|
|
515
|
-
EOF
|
|
516
|
-
|
|
517
|
-
subject.handlers[0].sources[0].realize(state)
|
|
518
|
-
subject.handlers[0].stores[0].realize(state)
|
|
519
|
-
subject.handlers[0].output.realize(state)
|
|
520
|
-
|
|
521
|
-
env.instance_eval &state.output_callback
|
|
522
|
-
env.res['Content-Type'].should == 'text/uri-list'
|
|
523
|
-
env.res.data.should == "ftp:/abc/test.out\r\n"
|
|
524
|
-
end
|
|
525
|
-
|
|
526
|
-
it 'should allow rewriting host component' do
|
|
527
|
-
subject = Configuration.read(<<-'EOF')
|
|
528
|
-
path "out" "abc/test.out"
|
|
529
|
-
|
|
530
|
-
post "single" {
|
|
531
|
-
store_file "input" root="/tmp" path="out"
|
|
532
|
-
|
|
533
|
-
output_store_url "input" host="localhost"
|
|
534
|
-
}
|
|
535
|
-
EOF
|
|
536
|
-
|
|
537
|
-
subject.handlers[0].sources[0].realize(state)
|
|
538
|
-
subject.handlers[0].stores[0].realize(state)
|
|
539
|
-
subject.handlers[0].output.realize(state)
|
|
540
|
-
|
|
541
|
-
env.instance_eval &state.output_callback
|
|
542
|
-
env.res['Content-Type'].should == 'text/uri-list'
|
|
543
|
-
env.res.data.should == "file://localhost/abc/test.out\r\n"
|
|
544
|
-
end
|
|
545
|
-
|
|
546
|
-
it 'should allow rewriting port component (defaults host to localhost)' do
|
|
547
|
-
subject = Configuration.read(<<-'EOF')
|
|
548
|
-
path "out" "abc/test.out"
|
|
549
|
-
|
|
550
|
-
post "single" {
|
|
551
|
-
store_file "input" root="/tmp" path="out"
|
|
552
|
-
|
|
553
|
-
output_store_url "input" port="21"
|
|
554
|
-
}
|
|
555
|
-
EOF
|
|
556
|
-
|
|
557
|
-
subject.handlers[0].sources[0].realize(state)
|
|
558
|
-
subject.handlers[0].stores[0].realize(state)
|
|
559
|
-
subject.handlers[0].output.realize(state)
|
|
560
|
-
|
|
561
|
-
env.instance_eval &state.output_callback
|
|
562
|
-
env.res['Content-Type'].should == 'text/uri-list'
|
|
563
|
-
env.res.data.should == "file://localhost:21/abc/test.out\r\n"
|
|
564
|
-
end
|
|
565
|
-
|
|
566
|
-
it 'should allow using variables for all supported rewrites' do
|
|
567
|
-
state = Configuration::RequestState.new('abc',
|
|
568
|
-
remote: 'example.com',
|
|
569
|
-
remote_port: 421,
|
|
570
|
-
proto: 'ftp'
|
|
571
|
-
)
|
|
572
|
-
subject = Configuration.read(<<-'EOF')
|
|
573
|
-
path "out" "abc/test.out"
|
|
574
|
-
path "formatted" "hello/#{dirname}/world/#{basename}-xyz.#{extension}"
|
|
575
|
-
|
|
576
|
-
post "single" {
|
|
577
|
-
store_file "input" root="/tmp" path="out"
|
|
578
|
-
|
|
579
|
-
output_store_url "input" scheme="#{proto}" host="#{remote}" port="#{remote_port}" path="formatted"
|
|
580
|
-
}
|
|
581
|
-
EOF
|
|
582
|
-
|
|
583
|
-
subject.handlers[0].sources[0].realize(state)
|
|
584
|
-
subject.handlers[0].stores[0].realize(state)
|
|
585
|
-
subject.handlers[0].output.realize(state)
|
|
586
|
-
|
|
587
|
-
env.instance_eval &state.output_callback
|
|
588
|
-
env.res['Content-Type'].should == 'text/uri-list'
|
|
589
|
-
env.res.data.should == "ftp://example.com:421/hello/abc/world/test-xyz.out\r\n"
|
|
590
|
-
end
|
|
591
|
-
end
|
|
592
|
-
|
|
593
|
-
describe 'URL encoding' do
|
|
594
|
-
it 'should provide properly encoded file store URL' do
|
|
595
|
-
subject = Configuration.read(<<-'EOF')
|
|
596
|
-
path "out" "abc/t e s t.out"
|
|
597
|
-
path "formatted" "hello/#{dirname}/world/#{basename}-xyz.#{extension}"
|
|
598
|
-
|
|
599
|
-
post "single" {
|
|
600
|
-
store_file "input" root="/tmp" path="out"
|
|
601
|
-
|
|
602
|
-
output_store_url {
|
|
603
|
-
"input"
|
|
604
|
-
"input" path="formatted"
|
|
605
|
-
}
|
|
606
|
-
}
|
|
607
|
-
EOF
|
|
608
|
-
|
|
609
|
-
subject.handlers[0].sources[0].realize(state)
|
|
610
|
-
subject.handlers[0].stores[0].realize(state)
|
|
611
|
-
subject.handlers[0].output.realize(state)
|
|
612
|
-
|
|
613
|
-
env.instance_eval &state.output_callback
|
|
614
|
-
env.res['Content-Type'].should == 'text/uri-list'
|
|
615
|
-
env.res.data.should == "file:/abc/t%20e%20s%20t.out\r\nfile:/hello/abc/world/t%20e%20s%20t-xyz.out\r\n"
|
|
616
|
-
end
|
|
617
|
-
end
|
|
618
|
-
|
|
619
|
-
describe 'error handling' do
|
|
620
|
-
it 'should raise StoreURLNotSetForImage for output of not stored image' do
|
|
621
|
-
subject = Configuration.read(<<-EOF)
|
|
622
|
-
post "single" {
|
|
623
|
-
output_store_url "input"
|
|
624
|
-
}
|
|
625
|
-
EOF
|
|
626
|
-
|
|
627
|
-
subject.handlers[0].sources[0].realize(state)
|
|
628
|
-
|
|
629
|
-
expect {
|
|
630
|
-
subject.handlers[0].output.realize(state)
|
|
631
|
-
}.to raise_error Configuration::StoreURLNotSetForImage, %{store URL not set for image 'input'}
|
|
632
|
-
end
|
|
633
|
-
end
|
|
634
|
-
end
|
|
635
|
-
|
|
636
|
-
describe Configuration::OutputStoreURI do
|
|
637
|
-
it 'should provide file store URI' do
|
|
638
|
-
subject = Configuration.read(<<-EOF)
|
|
639
|
-
path {
|
|
640
|
-
"out" "test.out"
|
|
641
|
-
}
|
|
642
|
-
|
|
643
|
-
post "single" {
|
|
644
|
-
store_file "input" root="/tmp" path="out"
|
|
645
|
-
|
|
646
|
-
output_store_uri "input"
|
|
647
|
-
}
|
|
648
|
-
EOF
|
|
649
|
-
|
|
650
|
-
subject.handlers[0].sources[0].realize(state)
|
|
651
|
-
subject.handlers[0].stores[0].realize(state)
|
|
652
|
-
subject.handlers[0].output.realize(state)
|
|
653
|
-
|
|
654
|
-
env.instance_eval &state.output_callback
|
|
655
|
-
env.res['Content-Type'].should == 'text/uri-list'
|
|
656
|
-
env.res.data.should == "/test.out\r\n"
|
|
657
|
-
end
|
|
658
|
-
|
|
659
|
-
it 'should provide multiple file store URIs' do
|
|
660
|
-
subject = Configuration.read(<<-EOF)
|
|
661
|
-
path {
|
|
662
|
-
"in" "test.in"
|
|
663
|
-
"out" "test.out"
|
|
664
|
-
"out2" "test.out2"
|
|
665
|
-
}
|
|
666
|
-
|
|
667
|
-
post "multi" {
|
|
668
|
-
source_file "original" root="/tmp" path="in"
|
|
669
|
-
|
|
670
|
-
store_file "input" root="/tmp" path="out"
|
|
671
|
-
store_file "original" root="/tmp" path="out2"
|
|
672
|
-
|
|
673
|
-
output_store_uri {
|
|
674
|
-
"input"
|
|
675
|
-
"original"
|
|
676
|
-
}
|
|
677
|
-
}
|
|
678
|
-
EOF
|
|
679
|
-
|
|
680
|
-
subject.handlers[0].sources[0].realize(state)
|
|
681
|
-
subject.handlers[0].sources[1].realize(state)
|
|
682
|
-
subject.handlers[0].stores[0].realize(state)
|
|
683
|
-
subject.handlers[0].stores[1].realize(state)
|
|
684
|
-
subject.handlers[0].output.realize(state)
|
|
685
|
-
|
|
686
|
-
env.instance_eval &state.output_callback
|
|
687
|
-
env.res['Content-Type'].should == 'text/uri-list'
|
|
688
|
-
env.res.data.should == "/test.out\r\n/test.out2\r\n"
|
|
689
|
-
end
|
|
690
|
-
|
|
691
|
-
describe 'conditional inclusion support' do
|
|
692
|
-
let :state do
|
|
693
|
-
Configuration::RequestState.new('abc', list: 'input,image2')
|
|
694
|
-
end
|
|
695
|
-
|
|
696
|
-
subject do
|
|
697
|
-
Configuration.read(<<-'EOF')
|
|
698
|
-
path {
|
|
699
|
-
"in" "test.in"
|
|
700
|
-
"out1" "test.out1"
|
|
701
|
-
"out2" "test.out2"
|
|
702
|
-
"out3" "test.out3"
|
|
703
|
-
}
|
|
704
|
-
|
|
705
|
-
post "multi" {
|
|
706
|
-
source_file "image1" root="/tmp" path="in"
|
|
707
|
-
source_file "image2" root="/tmp" path="in"
|
|
708
|
-
|
|
709
|
-
store_file "input" root="/tmp" path="out1"
|
|
710
|
-
store_file "image1" root="/tmp" path="out2"
|
|
711
|
-
store_file "image2" root="/tmp" path="out3"
|
|
712
|
-
|
|
713
|
-
output_store_uri {
|
|
714
|
-
"input" if-image-name-on="#{list}"
|
|
715
|
-
"image1" if-image-name-on="#{list}"
|
|
716
|
-
"image2" if-image-name-on="#{list}"
|
|
717
|
-
}
|
|
718
|
-
}
|
|
719
|
-
EOF
|
|
720
|
-
end
|
|
721
|
-
|
|
722
|
-
it 'should output store url only for images that names match if-image-name-on list' do
|
|
723
|
-
subject.handlers[0].sources[0].realize(state)
|
|
724
|
-
subject.handlers[0].sources[1].realize(state)
|
|
725
|
-
subject.handlers[0].sources[2].realize(state)
|
|
726
|
-
subject.handlers[0].stores[0].realize(state)
|
|
727
|
-
subject.handlers[0].stores[1].realize(state)
|
|
728
|
-
subject.handlers[0].stores[2].realize(state)
|
|
729
|
-
subject.handlers[0].output.realize(state)
|
|
730
|
-
|
|
731
|
-
env.instance_eval &state.output_callback
|
|
732
|
-
env.res['Content-Type'].should == 'text/uri-list'
|
|
733
|
-
env.res.data.should == "/test.out1\r\n/test.out3\r\n"
|
|
734
|
-
end
|
|
735
|
-
end
|
|
736
|
-
|
|
737
|
-
describe 'URI rewrites' do
|
|
738
|
-
it 'should allow using path spec to rewrite URI path' do
|
|
739
|
-
subject = Configuration.read(<<-'EOF')
|
|
740
|
-
path "out" "abc/test.out"
|
|
741
|
-
|
|
742
|
-
path "formatted" "hello/#{dirname}/world/#{basename}-xyz.#{extension}"
|
|
743
|
-
|
|
744
|
-
post "single" {
|
|
745
|
-
store_file "input" root="/tmp" path="out"
|
|
746
|
-
|
|
747
|
-
output_store_uri "input" path="formatted"
|
|
748
|
-
}
|
|
749
|
-
EOF
|
|
750
|
-
|
|
751
|
-
subject.handlers[0].sources[0].realize(state)
|
|
752
|
-
subject.handlers[0].stores[0].realize(state)
|
|
753
|
-
subject.handlers[0].output.realize(state)
|
|
754
|
-
|
|
755
|
-
env.instance_eval &state.output_callback
|
|
756
|
-
env.res['Content-Type'].should == 'text/uri-list'
|
|
757
|
-
env.res.data.should == "/hello/abc/world/test-xyz.out\r\n"
|
|
758
|
-
end
|
|
759
|
-
end
|
|
760
|
-
|
|
761
|
-
describe 'URI encoding' do
|
|
762
|
-
let :subject do
|
|
763
|
-
Configuration.read(<<-'EOF')
|
|
764
|
-
path "out" "abc/#{name}.out"
|
|
765
|
-
path "formatted" "hello/#{dirname}/world/#{basename}-xyz.#{extension}"
|
|
766
|
-
|
|
767
|
-
post "single" {
|
|
768
|
-
store_file "input" root="/tmp" path="out"
|
|
769
|
-
|
|
770
|
-
output_store_uri {
|
|
771
|
-
"input"
|
|
772
|
-
"input" path="formatted"
|
|
773
|
-
}
|
|
774
|
-
}
|
|
775
|
-
EOF
|
|
776
|
-
end
|
|
777
|
-
|
|
778
|
-
it 'should provide properly encoded file store URI' do
|
|
779
|
-
state = Configuration::RequestState.new('abc', name: 't e s t')
|
|
780
|
-
|
|
781
|
-
subject.handlers[0].sources[0].realize(state)
|
|
782
|
-
subject.handlers[0].stores[0].realize(state)
|
|
783
|
-
subject.handlers[0].output.realize(state)
|
|
784
|
-
|
|
785
|
-
env.instance_eval &state.output_callback
|
|
786
|
-
env.res['Content-Type'].should == 'text/uri-list'
|
|
787
|
-
env.res.data.should == "/abc/t%20e%20s%20t.out\r\n/hello/abc/world/t%20e%20s%20t-xyz.out\r\n"
|
|
788
|
-
end
|
|
789
|
-
|
|
790
|
-
it 'should handle UTF-8 characters' do
|
|
791
|
-
state = Configuration::RequestState.new('abc', name: utf_string)
|
|
792
|
-
subject.handlers[0].sources[0].realize(state)
|
|
793
|
-
subject.handlers[0].stores[0].realize(state)
|
|
794
|
-
subject.handlers[0].output.realize(state)
|
|
795
|
-
|
|
796
|
-
env.instance_eval &state.output_callback
|
|
797
|
-
env.res['Content-Type'].should == 'text/uri-list'
|
|
798
|
-
l1, l2 = *env.res.data.split("\r\n")
|
|
799
|
-
URI.utf_decode(l1).should == "/abc/#{utf_string}.out"
|
|
800
|
-
URI.utf_decode(l2).should == "/hello/abc/world/#{utf_string}-xyz.out"
|
|
801
|
-
end
|
|
802
|
-
end
|
|
803
|
-
|
|
804
|
-
describe 'error handling' do
|
|
805
|
-
it 'should raise StoreURLNotSetForImage for output of not stored image' do
|
|
806
|
-
subject = Configuration.read(<<-EOF)
|
|
807
|
-
post "single" {
|
|
808
|
-
output_store_uri "input"
|
|
809
|
-
}
|
|
810
|
-
EOF
|
|
811
|
-
|
|
812
|
-
subject.handlers[0].sources[0].realize(state)
|
|
813
|
-
|
|
814
|
-
expect {
|
|
815
|
-
subject.handlers[0].output.realize(state)
|
|
816
|
-
}.to raise_error Configuration::StoreURLNotSetForImage, %{store URL not set for image 'input'}
|
|
817
|
-
end
|
|
818
|
-
end
|
|
819
|
-
end
|
|
820
|
-
end
|
|
821
|
-
end
|