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,138 +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/handler'
6
- require 'httpimagestore/configuration/path'
7
-
8
- describe Configuration do
9
- describe 'path rendering' do
10
- it 'should load paths form single line and multi line declarations and render spec templates' do
11
- subject = Configuration.read(<<-'EOF')
12
- path "uri" "#{path}"
13
- path "hash" "#{input_digest}.#{extension}"
14
- path {
15
- "hash-name" "#{input_digest}/#{image_name}.#{extension}"
16
- "structured" "#{dirname}/#{input_digest}/#{basename}.#{extension}"
17
- "structured-name" "#{dirname}/#{input_digest}/#{basename}-#{image_name}.#{extension}"
18
- }
19
- EOF
20
-
21
- subject.paths['uri'].render(path: 'test/abc.jpg').should == 'test/abc.jpg'
22
- subject.paths['hash'].render(input_digest: '2cf24dba5fb0a30e', extension: 'jpg').should == '2cf24dba5fb0a30e.jpg'
23
- subject.paths['hash-name'].render(input_digest: '2cf24dba5fb0a30e', image_name: 'xbrna', extension: 'jpg').should == '2cf24dba5fb0a30e/xbrna.jpg'
24
- subject.paths['structured'].render(dirname: 'test', input_digest: '2cf24dba5fb0a30e', basename: 'abc', extension: 'jpg').should == 'test/2cf24dba5fb0a30e/abc.jpg'
25
- subject.paths['structured-name'].render(dirname: 'test', input_digest: '2cf24dba5fb0a30e', basename: 'abc', extension: 'jpg', image_name: 'xbrna').should == 'test/2cf24dba5fb0a30e/abc-xbrna.jpg'
26
- end
27
-
28
- describe 'error handling' do
29
- it 'should raise NoValueError on missing path name' do
30
- expect {
31
- Configuration.read(<<-'EOF')
32
- path
33
- EOF
34
- }.to raise_error Configuration::NoValueError, %{syntax error while parsing 'path': expected path name}
35
- end
36
-
37
- it 'should raise NoValueError on missing path template' do
38
- expect {
39
- Configuration.read(<<-'EOF')
40
- path {
41
- "blah"
42
- }
43
- EOF
44
- }.to raise_error Configuration::NoValueError, %{syntax error while parsing '"blah"': expected path template}
45
- end
46
-
47
- it 'should raise PathNotDefinedError if path lookup fails' do
48
- subject = Configuration.read('')
49
-
50
- expect {
51
- subject.paths['blah']
52
- }.to raise_error Configuration::PathNotDefinedError, "path 'blah' not defined"
53
- end
54
-
55
- it 'should raise NoValueForPathTemplatePlaceholerError if locals value is not found' do
56
- subject = Configuration.read(<<-'EOF')
57
- path {
58
- "test" "#{abc}#{xyz}"
59
- }
60
- EOF
61
-
62
- expect {
63
- subject.paths['test'].render
64
- }.to raise_error Configuration::NoValueForPathTemplatePlaceholerError, %q{cannot generate path 'test' from template '#{abc}#{xyz}': no value for '#{abc}'}
65
- end
66
- end
67
-
68
- describe 'rendering from RequestState' do
69
- let :state do
70
- Configuration::RequestState.new(
71
- 'test',
72
- {operation: 'pad'},
73
- 'test/abc.jpg',
74
- {width: '123', height: '321'}
75
- )
76
- end
77
-
78
- subject do
79
- Configuration.read(<<-'EOF')
80
- path "uri" "#{path}"
81
- path "hash" "#{input_digest}.#{extension}"
82
- path {
83
- "hash-name" "#{input_digest}/#{image_name}.#{extension}"
84
- "structured" "#{dirname}/#{input_digest}/#{basename}.#{extension}"
85
- "structured-name" "#{dirname}/#{input_digest}/#{basename}-#{image_name}.#{extension}"
86
- }
87
- path "name" "#{image_name}"
88
- path "base" "#{basename}"
89
- EOF
90
- end
91
-
92
- it 'should render path using meta variables and locals' do
93
-
94
- subject.paths['uri'].render(state).should == 'test/abc.jpg'
95
- subject.paths['hash'].render(state).should == '9f86d081884c7d65.jpg'
96
- subject.paths['hash-name'].render(state.with_locals(image_name: 'xbrna')).should == '9f86d081884c7d65/xbrna.jpg'
97
- subject.paths['structured'].render(state).should == 'test/9f86d081884c7d65/abc.jpg'
98
- subject.paths['structured-name'].render(state.with_locals(image_name: 'xbrna')).should == 'test/9f86d081884c7d65/abc-xbrna.jpg'
99
- end
100
-
101
- describe 'error handling' do
102
- let :state do
103
- Configuration::RequestState.new(
104
- '',
105
- {operation: 'pad'},
106
- 'test/abc.jpg',
107
- {width: '123', height: '321'}
108
- )
109
- end
110
-
111
- it 'should raise PathRenderingError if body was expected but not provided' do
112
- expect {
113
- subject.paths['hash'].render(state)
114
- }.to raise_error Configuration::PathRenderingError, %q{cannot generate path 'hash' from template '#{input_digest}.#{extension}': need not empty request body to generate value for 'input_digest'}
115
- end
116
-
117
- it 'should raise PathRenderingError if variable not defined' do
118
- expect {
119
- subject.paths['name'].render(state)
120
- }.to raise_error Configuration::PathRenderingError, %q{cannot generate path 'name' from template '#{image_name}': variable 'image_name' not defined}
121
- end
122
-
123
- it 'should raise PathRenderingError if meta variable dependent variable not defined' do
124
- state = Configuration::RequestState.new(
125
- '',
126
- {operation: 'pad'},
127
- nil,
128
- {width: '123', height: '321'}
129
- )
130
- expect {
131
- subject.paths['base'].render(state)
132
- }.to raise_error Configuration::PathRenderingError, %q{cannot generate path 'base' from template '#{basename}': need 'path' variable to generate value for 'basename'}
133
- end
134
- end
135
- end
136
- end
137
- end
138
-
@@ -1,911 +0,0 @@
1
- require_relative 'spec_helper'
2
- require 'aws-sdk'
3
- require 'httpimagestore/configuration'
4
- MemoryLimit.logger = Configuration::Scope.logger = RootLogger.new('/dev/null')
5
-
6
- require 'httpimagestore/configuration/output'
7
- require 'httpimagestore/configuration/s3'
8
-
9
- unless ENV['AWS_ACCESS_KEY_ID'] and ENV['AWS_SECRET_ACCESS_KEY'] and ENV['AWS_S3_TEST_BUCKET']
10
- puts "AWS_ACCESS_KEY_ID or AWS_SECRET_ACCESS_KEY or AWS_S3_TEST_BUCKET environment variables not set - Skipping S3 specs"
11
- else
12
- describe Configuration do
13
- describe Configuration::S3 do
14
- subject do
15
- Configuration.read(<<-EOF)
16
- s3 key="#{ENV['AWS_ACCESS_KEY_ID']}" secret="#{ENV['AWS_SECRET_ACCESS_KEY']}"
17
- EOF
18
- end
19
-
20
- it 'should provide S3 key and secret' do
21
- subject.s3.config.access_key_id.should == ENV['AWS_ACCESS_KEY_ID']
22
- subject.s3.config.secret_access_key.should == ENV['AWS_SECRET_ACCESS_KEY']
23
- end
24
-
25
- it 'should use SSL by default' do
26
- subject.s3.config.use_ssl.should be_true
27
- end
28
-
29
- it 'should allow disabling SSL' do
30
- subject = Configuration.read(<<-EOF)
31
- s3 key="#{ENV['AWS_ACCESS_KEY_ID']}" secret="#{ENV['AWS_SECRET_ACCESS_KEY']}" ssl=false
32
- EOF
33
-
34
- subject.s3.config.use_ssl.should be_false
35
- end
36
-
37
- it 'should provide S3 client' do
38
- subject.s3.should be_a AWS::S3
39
- end
40
-
41
- describe 'error handling' do
42
- it 'should raise StatementCollisionError on duplicate s3 statement' do
43
- expect {
44
- Configuration.read(<<-EOF)
45
- s3 key="#{ENV['AWS_ACCESS_KEY_ID']}" secret="#{ENV['AWS_SECRET_ACCESS_KEY']}"
46
- s3 key="#{ENV['AWS_ACCESS_KEY_ID']}" secret="#{ENV['AWS_SECRET_ACCESS_KEY']}"
47
- EOF
48
- }.to raise_error Configuration::StatementCollisionError, %{syntax error while parsing 's3 key="#{ENV['AWS_ACCESS_KEY_ID']}" secret="#{ENV['AWS_SECRET_ACCESS_KEY']}"': only one s3 type statement can be specified within context}
49
- end
50
-
51
- it 'should raise NoAttributeError on missing key attribute' do
52
- expect {
53
- Configuration.read(<<-EOF)
54
- s3 secret="#{ENV['AWS_SECRET_ACCESS_KEY']}"
55
- EOF
56
- }.to raise_error Configuration::NoAttributeError, %{syntax error while parsing 's3 secret="#{ENV['AWS_SECRET_ACCESS_KEY']}"': expected 'key' attribute to be set}
57
- end
58
-
59
- it 'should raise NoAttributeError on missing secret attribute' do
60
- expect {
61
- Configuration.read(<<-EOF)
62
- s3 key="#{ENV['AWS_ACCESS_KEY_ID']}"
63
- EOF
64
- }.to raise_error Configuration::NoAttributeError, %{syntax error while parsing 's3 key="#{ENV['AWS_ACCESS_KEY_ID']}"': expected 'secret' attribute to be set}
65
- end
66
- end
67
- end
68
-
69
- describe Configuration::S3SourceStoreBase::CacheRoot do
70
- subject do
71
- Configuration::S3SourceStoreBase::CacheRoot.new('/tmp')
72
- end
73
-
74
- before do
75
- @cache_file = Pathname.new('/tmp/0d/bf/50c256d6b6efe55d11d0b6b50600')
76
- @cache_file.dirname.mkpath
77
- @cache_file.open('w') do |io|
78
- io.write 'abc'
79
- end
80
-
81
- test2 = Pathname.new('/tmp/46/b9/7a454d831d7570abbb833330d9fb')
82
- test2.unlink if test2.exist?
83
- end
84
-
85
- it 'should build cache file location for storage location from bucket and key' do
86
- cache_file = subject.cache_file('mybucket', 'hello/world.jpg')
87
- cache_file.should be_a Configuration::S3SourceStoreBase::CacheRoot::CacheFile
88
- cache_file.to_s.should == "/tmp/0d/bf/50c256d6b6efe55d11d0b6b50600"
89
- end
90
- end
91
-
92
- describe Configuration::S3Source do
93
- let :state do
94
- Configuration::RequestState.new('abc', {test_image: 'test.jpg'})
95
- end
96
-
97
- subject do
98
- Configuration.read(<<-EOF)
99
- s3 key="#{ENV['AWS_ACCESS_KEY_ID']}" secret="#{ENV['AWS_SECRET_ACCESS_KEY']}"
100
- path "hash" "\#{test_image}"
101
- get {
102
- source_s3 "original" bucket="#{ENV['AWS_S3_TEST_BUCKET']}" path="hash"
103
- }
104
- EOF
105
- end
106
-
107
- before :all do
108
- @test_data = (support_dir + 'compute.jpg').read.force_encoding('ASCII-8BIT')
109
-
110
- s3_client = AWS::S3.new(use_ssl: false)
111
- s3_test_bucket = s3_client.buckets[ENV['AWS_S3_TEST_BUCKET']]
112
- s3_test_bucket.objects['test.jpg'].write(@test_data, content_type: 'image/jpeg')
113
- s3_test_bucket.objects['test_prefix/test.jpg'].write(@test_data, content_type: 'image/jpeg')
114
- end
115
-
116
- it 'should source image from S3 using path spec' do
117
- subject.handlers[0].sources[0].should be_a Configuration::S3Source
118
- subject.handlers[0].sources[0].realize(state)
119
-
120
- state.images['original'].data.should == @test_data
121
- end
122
-
123
- it 'should use S3 object content type for mime type' do
124
- subject.handlers[0].sources[0].realize(state)
125
-
126
- state.images['original'].mime_type.should == 'image/jpeg'
127
- end
128
-
129
- it 'should provide source path and HTTPS url' do
130
- subject.handlers[0].sources[0].realize(state)
131
-
132
- state.images['original'].source_path.should == "test.jpg"
133
- state.images['original'].source_url.to_s.should start_with "https://"
134
- state.images['original'].source_url.to_s.should include ENV['AWS_S3_TEST_BUCKET']
135
- state.images['original'].source_url.to_s.should include "/test.jpg"
136
- state.images['original'].source_url.to_s.should include ENV['AWS_ACCESS_KEY_ID']
137
- status(state.images['original'].source_url).should == 200
138
- end
139
-
140
- describe 'storage prefix' do
141
- subject do
142
- Configuration.read(<<-EOF)
143
- s3 key="#{ENV['AWS_ACCESS_KEY_ID']}" secret="#{ENV['AWS_SECRET_ACCESS_KEY']}"
144
- path "hash" "\#{test_image}"
145
- get {
146
- source_s3 "original" bucket="#{ENV['AWS_S3_TEST_BUCKET']}" path="hash" prefix="test_prefix/"
147
- }
148
- EOF
149
- end
150
-
151
- it 'should still provide valid HTTPS URL incliding prefix' do
152
- subject.handlers[0].sources[0].realize(state)
153
-
154
- state.images['original'].source_url.to_s.should start_with "https://"
155
- state.images['original'].source_url.to_s.should include ENV['AWS_S3_TEST_BUCKET']
156
- state.images['original'].source_url.to_s.should include "/test_prefix/test.jpg"
157
- state.images['original'].source_url.to_s.should include ENV['AWS_ACCESS_KEY_ID']
158
- status(state.images['original'].source_url).should == 200
159
- end
160
-
161
- it 'should provide source path without prefix' do
162
- subject.handlers[0].sources[0].realize(state)
163
-
164
- state.images['original'].source_path.should == "test.jpg"
165
- end
166
- end
167
-
168
- describe 'object cache' do
169
- let :state do
170
- Configuration::RequestState.new('abc', {test_image: 'test/ghost.jpg'})
171
- end
172
-
173
- subject do
174
- Configuration.read(<<-EOF)
175
- s3 key="#{ENV['AWS_ACCESS_KEY_ID']}" secret="#{ENV['AWS_SECRET_ACCESS_KEY']}"
176
- path "hash" "\#{test_image}"
177
- get {
178
- source_s3 "original" bucket="#{ENV['AWS_S3_TEST_BUCKET']}" path="hash" cache-root="/tmp"
179
- source_s3 "original_cached" bucket="#{ENV['AWS_S3_TEST_BUCKET']}" path="hash" cache-root="/tmp"
180
- source_s3 "original_cached_public" bucket="#{ENV['AWS_S3_TEST_BUCKET']}" path="hash" cache-root="/tmp" public="true"
181
- source_s3 "original_cached_public2" bucket="#{ENV['AWS_S3_TEST_BUCKET']}" path="hash" cache-root="/tmp" public="true"
182
- }
183
-
184
- post {
185
- store_s3 "input" bucket="#{ENV['AWS_S3_TEST_BUCKET']}" path="hash" cache-root="/tmp"
186
- }
187
- EOF
188
- end
189
-
190
- before do
191
- @cache_file = Pathname.new('/tmp/ce/26/b196585e28aa99f55b1260b629e2')
192
- @cache_file.dirname.mkpath
193
- @cache_file.open('wb') do |io|
194
- header = MessagePack.pack(
195
- 'private_url' => 'https://s3-eu-west-1.amazonaws.com/test/ghost.jpg?' + ENV['AWS_ACCESS_KEY_ID'],
196
- 'public_url' => 'https://s3-eu-west-1.amazonaws.com/test/ghost.jpg',
197
- 'content_type' => 'image/jpeg'
198
- )
199
- io.write [header.length].pack('L') # header length
200
- io.write header
201
- io.write 'abc'
202
- end
203
- end
204
-
205
- it 'should use cache when configured and object in cache' do
206
- subject.handlers[0].sources[0].should be_a Configuration::S3Source
207
- subject.handlers[0].sources[0].realize(state)
208
-
209
- state.images['original'].data.should == 'abc'
210
- end
211
-
212
- it 'should keep mime type' do
213
- subject.handlers[0].sources[0].realize(state)
214
-
215
- state.images['original'].mime_type.should == 'image/jpeg'
216
- end
217
-
218
- it 'should keep private source URL' do
219
- subject.handlers[0].sources[0].realize(state)
220
-
221
- state.images['original'].source_url.should be_a Addressable::URI
222
- state.images['original'].source_url.to_s.should == 'https://s3-eu-west-1.amazonaws.com/test/ghost.jpg?' + ENV['AWS_ACCESS_KEY_ID']
223
- end
224
-
225
- it 'should keep public source URL' do
226
- subject = Configuration.read(<<-EOF)
227
- s3 key="#{ENV['AWS_ACCESS_KEY_ID']}" secret="#{ENV['AWS_SECRET_ACCESS_KEY']}"
228
- path "hash" "\#{test_image}"
229
- get {
230
- source_s3 "original" bucket="#{ENV['AWS_S3_TEST_BUCKET']}" path="hash" cache-root="/tmp" public=true
231
- }
232
- EOF
233
- subject.handlers[0].sources[0].realize(state)
234
-
235
- state.images['original'].source_url.should be_a Addressable::URI
236
- state.images['original'].source_url.to_s.should == 'https://s3-eu-west-1.amazonaws.com/test/ghost.jpg'
237
- end
238
-
239
- describe 'read-through' do
240
- it 'shluld use object stored in S3 when not found in the cache' do
241
- cache_file = Pathname.new('/tmp/af/a3/5eaf0a614693e2d1ed455ac1cedb')
242
- cache_file.unlink if cache_file.exist?
243
-
244
- state = Configuration::RequestState.new('abc', {test_image: 'test.jpg'})
245
- subject.handlers[0].sources[0].realize(state)
246
-
247
- cache_file.should exist
248
- end
249
-
250
- it 'should write cache on read and be able to use it on next read' do
251
- cache_file = Pathname.new('/tmp/af/a3/5eaf0a614693e2d1ed455ac1cedb')
252
- cache_file.unlink if cache_file.exist?
253
-
254
- state = Configuration::RequestState.new('abc', {test_image: 'test.jpg'})
255
- subject.handlers[0].sources[0].realize(state)
256
-
257
- cache_file.should exist
258
-
259
- subject.handlers[0].sources[1].realize(state)
260
-
261
- state.images['original'].data.should == @test_data
262
- state.images['original'].mime_type.should == 'image/jpeg'
263
-
264
- state.images['original_cached'].data.should == @test_data
265
- state.images['original_cached'].mime_type.should == 'image/jpeg'
266
- end
267
-
268
- it 'should update cached object with new properties read from S3' do
269
- cache_file = Pathname.new('/tmp/af/a3/5eaf0a614693e2d1ed455ac1cedb')
270
- cache_file.unlink if cache_file.exist?
271
-
272
- state = Configuration::RequestState.new('abc', {test_image: 'test.jpg'})
273
-
274
- ## cache with private URL
275
- subject.handlers[0].sources[0].realize(state)
276
-
277
- cache_file.should exist
278
- sum = Digest::SHA2.new.update(cache_file.read).to_s
279
-
280
- ## read from cache with private URL
281
- subject.handlers[0].sources[1].realize(state)
282
-
283
- # no change
284
- Digest::SHA2.new.update(cache_file.read).to_s.should == sum
285
-
286
- ## read from cache; add public URL
287
- subject.handlers[0].sources[2].realize(state)
288
-
289
- # should get updated
290
- Digest::SHA2.new.update(cache_file.read).to_s.should_not == sum
291
-
292
- sum = Digest::SHA2.new.update(cache_file.read).to_s
293
- ## read from cahce
294
- subject.handlers[0].sources[3].realize(state)
295
-
296
- # no change
297
- Digest::SHA2.new.update(cache_file.read).to_s.should == sum
298
- end
299
-
300
- describe 'error handling' do
301
- let :state do
302
- Configuration::RequestState.new('abc', {test_image: 'test.jpg'})
303
- end
304
-
305
- before :each do
306
- @cache_file = Pathname.new('/tmp/af/a3/5eaf0a614693e2d1ed455ac1cedb')
307
- @cache_file.dirname.mkpath
308
- @cache_file.open('wb') do |io|
309
- header = 'xyz'
310
- io.write [header.length].pack('L') # header length
311
- io.write header
312
- io.write 'abc'
313
- end
314
- end
315
-
316
- it 'should rewrite cached object when corrupted' do
317
- subject.handlers[0].sources[0].realize(state)
318
- state.images['original'].data.should == @test_data
319
-
320
- cache = @cache_file.read.force_encoding('ASCII-8BIT')
321
- cache.should_not include 'xyz'
322
- cache.should include @test_data
323
- end
324
-
325
- it 'should use S3 object when cache file is not accessible' do
326
- @cache_file.chmod(0000)
327
- begin
328
- subject.handlers[0].sources[0].realize(state)
329
- state.images['original'].data.should == @test_data
330
- ensure
331
- @cache_file.chmod(0644)
332
-
333
- cache = @cache_file.read.force_encoding('ASCII-8BIT')
334
- cache.should include 'xyz'
335
- cache.should_not include @test_data
336
- end
337
- end
338
-
339
- it 'should use S3 object when cache direcotry is not accessible' do
340
- @cache_file.dirname.chmod(0000)
341
- begin
342
- subject.handlers[0].sources[0].realize(state)
343
- state.images['original'].data.should == @test_data
344
- ensure
345
- @cache_file.dirname.chmod(0755)
346
-
347
- cache = @cache_file.read.force_encoding('ASCII-8BIT')
348
- cache.should include 'xyz'
349
- cache.should_not include @test_data
350
- end
351
- end
352
-
353
- it 'should not store cache file for S3 objects that does not exist' do
354
- cache_file = Pathname.new('/tmp/a2/fd/4261e9a7586ed772d0c78bb51c9d')
355
- cache_file.unlink if cache_file.exist?
356
-
357
- state = Configuration::RequestState.new('abc', {test_image: 'bogus.jpg'})
358
-
359
- expect {
360
- subject.handlers[0].sources[0].realize(state)
361
- }.to raise_error Configuration::S3NoSuchKeyError
362
-
363
- cache_file.should_not exist
364
- end
365
- end
366
- end
367
-
368
- describe 'write-through' do
369
- let :state do
370
- Configuration::RequestState.new(@test_data, {test_image: 'test_cache.jpg'})
371
- end
372
-
373
- before :each do
374
- end
375
-
376
- it 'should cache S3 object during write' do
377
- cache_file = Pathname.new('/tmp/31/f6/d48147b9981bb880fb1861539e3f')
378
- cache_file.unlink if cache_file.exist?
379
-
380
- subject.handlers[1].sources[0].realize(state)
381
- state.images['input'].mime_type = 'image/jpeg'
382
- subject.handlers[1].stores[0].realize(state)
383
-
384
- # we have cache
385
- cache_file.should exist
386
-
387
- # but delete S3 so it will fail if cache was not used fully
388
- s3_client = AWS::S3.new(use_ssl: false)
389
- s3_test_bucket = s3_client.buckets[ENV['AWS_S3_TEST_BUCKET']]
390
- s3_test_bucket.objects['test_cache.jpg'].delete
391
-
392
- state = Configuration::RequestState.new('', {test_image: 'test_cache.jpg'})
393
- expect {
394
- subject.handlers[0].sources[0].realize(state)
395
- }.not_to raise_error
396
- state.images['original'].data.should == @test_data
397
- end
398
- end
399
- end
400
-
401
- describe 'non encrypted connection mode' do
402
- subject do
403
- Configuration.read(<<-EOF)
404
- s3 key="#{ENV['AWS_ACCESS_KEY_ID']}" secret="#{ENV['AWS_SECRET_ACCESS_KEY']}" ssl=false
405
- path "hash" "\#{test_image}"
406
- get {
407
- source_s3 "original" bucket="#{ENV['AWS_S3_TEST_BUCKET']}" path="hash"
408
- }
409
- EOF
410
- end
411
-
412
- it 'should source image from S3 using path spec' do
413
- subject.handlers[0].sources[0].should be_a Configuration::S3Source
414
- subject.handlers[0].sources[0].realize(state)
415
-
416
- state.images['original'].data.should == @test_data
417
- end
418
-
419
- it 'should provide source HTTP url' do
420
- subject.handlers[0].sources[0].realize(state)
421
- state.images['original'].source_url.to_s.should start_with "http://"
422
- state.images['original'].source_url.to_s.should include ENV['AWS_S3_TEST_BUCKET']
423
- state.images['original'].source_url.to_s.should include "/test.jpg"
424
- state.images['original'].source_url.to_s.should include ENV['AWS_ACCESS_KEY_ID']
425
- status(state.images['original'].source_url).should == 200
426
- end
427
- end
428
-
429
- describe 'context locals' do
430
- before :all do
431
- s3_client = AWS::S3.new(use_ssl: false)
432
- s3_test_bucket = s3_client.buckets[ENV['AWS_S3_TEST_BUCKET']]
433
- s3_test_bucket.objects['test-image-name.jpg'].write('hello world', content_type: 'image/jpeg')
434
- s3_test_bucket.objects["#{ENV['AWS_S3_TEST_BUCKET']}.jpg"].write('hello bucket', content_type: 'image/jpeg')
435
- end
436
-
437
- subject do
438
- Configuration.read(<<-EOF)
439
- s3 key="#{ENV['AWS_ACCESS_KEY_ID']}" secret="#{ENV['AWS_SECRET_ACCESS_KEY']}" ssl=false
440
- path "image_name" "\#{image_name}.jpg"
441
- path "bucket" "\#{bucket}.jpg"
442
- get {
443
- source_s3 "test-image-name" bucket="#{ENV['AWS_S3_TEST_BUCKET']}" path="image_name"
444
- source_s3 "bucket" bucket="#{ENV['AWS_S3_TEST_BUCKET']}" path="bucket"
445
- }
446
- EOF
447
- end
448
-
449
- it 'should provide image name to be used as #{image_name}' do
450
- subject.handlers[0].sources[0].realize(state)
451
- state.images['test-image-name'].source_path.should == 'test-image-name.jpg'
452
- state.images['test-image-name'].data.should == 'hello world'
453
- end
454
-
455
- it 'should provide bucket to be used as #{bucket}' do
456
- subject.handlers[0].sources[1].realize(state)
457
- state.images['bucket'].source_path.should == "#{ENV['AWS_S3_TEST_BUCKET']}.jpg"
458
- state.images['bucket'].data.should == 'hello bucket'
459
- end
460
- end
461
-
462
- describe 'error handling' do
463
- it 'should raise NoValueError on missing image name' do
464
- expect {
465
- Configuration.read(<<-EOF)
466
- get "test" {
467
- source_s3 bucket="#{ENV['AWS_S3_TEST_BUCKET']}" path="hash"
468
- }
469
- EOF
470
- }.to raise_error Configuration::NoValueError, %{syntax error while parsing 'source_s3 bucket="#{ENV['AWS_S3_TEST_BUCKET']}" path="hash"': expected image name}
471
- end
472
-
473
- it 'should raise NoAttributeError on missing bucket name' do
474
- expect {
475
- Configuration.read(<<-EOF)
476
- get "test" {
477
- source_s3 "original" path="hash"
478
- }
479
- EOF
480
- }.to raise_error Configuration::NoAttributeError, %{syntax error while parsing 'source_s3 "original" path="hash"': expected 'bucket' attribute to be set}
481
- end
482
-
483
- it 'should raise NoAttributeError on missing path' do
484
- expect {
485
- Configuration.read(<<-EOF)
486
- get "test" {
487
- source_s3 "original" bucket="#{ENV['AWS_S3_TEST_BUCKET']}"
488
- }
489
- EOF
490
- }.to raise_error Configuration::NoAttributeError, %{syntax error while parsing 'source_s3 "original" bucket="#{ENV['AWS_S3_TEST_BUCKET']}"': expected 'path' attribute to be set}
491
- end
492
-
493
- it 'should raise S3NotConfiguredError if used but no s3 statement was used' do
494
- subject = Configuration.read(<<-'EOF')
495
- path "hash" "#{test_image}"
496
- get "test" {
497
- source_s3 "original" bucket="#{ENV['AWS_S3_TEST_BUCKET']}" path="hash"
498
- }
499
- EOF
500
- expect {
501
- subject.handlers[0].sources[0].realize(state)
502
- }.to raise_error Configuration::S3NotConfiguredError, 'S3 client not configured'
503
- end
504
-
505
- it 'should raise S3NoSuchBucketError if bucket was not found on S3' do
506
- subject = Configuration.read(<<-EOF)
507
- s3 key="#{ENV['AWS_ACCESS_KEY_ID']}" secret="#{ENV['AWS_SECRET_ACCESS_KEY']}" ssl=false
508
- path "hash" "\#{test_image}"
509
- get "test" {
510
- source_s3 "original" bucket="#{ENV['AWS_S3_TEST_BUCKET']}X" path="hash"
511
- }
512
- EOF
513
- expect {
514
- subject.handlers[0].sources[0].realize(state)
515
- }.to raise_error Configuration::S3NoSuchBucketError, %{S3 bucket '#{ENV['AWS_S3_TEST_BUCKET']}X' does not exist}
516
- end
517
-
518
- it 'should raise S3NoSuchKeyError if object was not found on S3' do
519
- subject = Configuration.read(<<-EOF)
520
- s3 key="#{ENV['AWS_ACCESS_KEY_ID']}" secret="#{ENV['AWS_SECRET_ACCESS_KEY']}" ssl=false
521
- path "hash" "blah"
522
- get "test" {
523
- source_s3 "original" bucket="#{ENV['AWS_S3_TEST_BUCKET']}" path="hash"
524
- }
525
- EOF
526
- expect {
527
- subject.handlers[0].sources[0].realize(state)
528
- }.to raise_error Configuration::S3NoSuchKeyError, %{S3 bucket '#{ENV['AWS_S3_TEST_BUCKET']}' does not contain key 'blah'}
529
- end
530
-
531
- it 'should raise S3AccessDenied if bucket was not found on S3' do
532
- subject = Configuration.read(<<-EOF)
533
- s3 key="#{ENV['AWS_ACCESS_KEY_ID']}" secret="#{ENV['AWS_SECRET_ACCESS_KEY']}" ssl=false
534
- path "hash" "\#{test_image}"
535
- get "test" {
536
- source_s3 "original" bucket="blah" path="hash"
537
- }
538
- EOF
539
- expect {
540
- subject.handlers[0].sources[0].realize(state)
541
- }.to raise_error Configuration::S3AccessDenied, %{access to S3 bucket 'blah' or key 'test.jpg' was denied}
542
- end
543
- end
544
-
545
- describe 'memory limit' do
546
- let :state do
547
- Configuration::RequestState.new('abc', {test_image: 'test.jpg'}, '', {}, MemoryLimit.new(10))
548
- end
549
-
550
- it 'should raise MemoryLimit::MemoryLimitedExceededError when sourcing bigger image than limit' do
551
- expect {
552
- subject.handlers[0].sources[0].realize(state)
553
- }.to raise_error MemoryLimit::MemoryLimitedExceededError
554
- end
555
- end
556
-
557
- context 'in failover context' do
558
- subject do
559
- Configuration.read(<<-EOF)
560
- s3 key="#{ENV['AWS_ACCESS_KEY_ID']}" secret="#{ENV['AWS_SECRET_ACCESS_KEY']}"
561
- path "hash" "\#{test_image}"
562
- path "bogus" "bogus"
563
- get {
564
- source_failover {
565
- source_s3 "first_fail_1" bucket="#{ENV['AWS_S3_TEST_BUCKET']}" path="bogus"
566
- source_s3 "first_fail_2" bucket="#{ENV['AWS_S3_TEST_BUCKET']}" path="hash"
567
- }
568
- }
569
- EOF
570
- end
571
-
572
- it 'should source second image' do
573
- subject.handlers[0].sources[0].should be_a Configuration::SourceFailover
574
- subject.handlers[0].sources[0].realize(state)
575
-
576
- state.images.keys.should == ['first_fail_2']
577
- state.images['first_fail_2'].should_not be_nil
578
- state.images['first_fail_2'].data.should == @test_data
579
- end
580
- end
581
- end
582
-
583
- describe Configuration::S3Store do
584
- let :state do
585
- Configuration::RequestState.new(@test_data, {test_image: 'test_out.jpg'})
586
- end
587
-
588
- subject do
589
- Configuration.read(<<-EOF)
590
- s3 key="#{ENV['AWS_ACCESS_KEY_ID']}" secret="#{ENV['AWS_SECRET_ACCESS_KEY']}"
591
- path "hash" "\#{test_image}"
592
- post {
593
- store_s3 "input" bucket="#{ENV['AWS_S3_TEST_BUCKET']}" path="hash"
594
- }
595
- EOF
596
- end
597
-
598
- before :all do
599
- @test_data = (support_dir + 'compute.jpg').read.force_encoding('ASCII-8BIT')
600
-
601
- s3_client = AWS::S3.new(use_ssl: false)
602
- s3_test_bucket = s3_client.buckets[ENV['AWS_S3_TEST_BUCKET']]
603
- @test_object = s3_test_bucket.objects['test_out.jpg']
604
- @test_object.delete
605
- test_object = s3_test_bucket.objects['test_prefix/test_out.jpg']
606
- test_object.delete
607
- end
608
-
609
- before :each do
610
- subject.handlers[0].sources[0].realize(state)
611
- end
612
-
613
- it 'should source image from S3 using path spec' do
614
- subject.handlers[0].stores[0].should be_a Configuration::S3Store
615
- subject.handlers[0].stores[0].realize(state)
616
-
617
- @test_object.read.should == @test_data
618
- end
619
-
620
- it 'should use image mime type as S3 object content type' do
621
- state.images['input'].mime_type = 'image/jpeg'
622
- subject.handlers[0].stores[0].realize(state)
623
-
624
- @test_object.head[:content_type].should == 'image/jpeg'
625
- end
626
-
627
- it 'should provide source path and HTTPS url' do
628
- subject.handlers[0].stores[0].realize(state)
629
-
630
- state.images['input'].store_path.should == "test_out.jpg"
631
- state.images['input'].store_url.to_s.should start_with "https://"
632
- state.images['input'].store_url.to_s.should include ENV['AWS_S3_TEST_BUCKET']
633
- state.images['input'].store_url.to_s.should include "/test_out.jpg"
634
- state.images['input'].store_url.to_s.should include ENV['AWS_ACCESS_KEY_ID']
635
- status(state.images['input'].store_url).should == 200
636
- end
637
-
638
- describe 'storage prefix' do
639
- subject do
640
- Configuration.read(<<-EOF)
641
- s3 key="#{ENV['AWS_ACCESS_KEY_ID']}" secret="#{ENV['AWS_SECRET_ACCESS_KEY']}"
642
- path "hash" "\#{test_image}"
643
- post {
644
- store_s3 "input" bucket="#{ENV['AWS_S3_TEST_BUCKET']}" path="hash" prefix="test_prefix/"
645
- }
646
- EOF
647
- end
648
-
649
- it 'should still provide valid HTTPS URL incliding prefix' do
650
- subject.handlers[0].stores[0].realize(state)
651
-
652
- state.images['input'].store_url.to_s.should start_with "https://"
653
- state.images['input'].store_url.to_s.should include ENV['AWS_S3_TEST_BUCKET']
654
- state.images['input'].store_url.to_s.should include "test_prefix/test_out.jpg"
655
- state.images['input'].store_url.to_s.should include ENV['AWS_ACCESS_KEY_ID']
656
- status(state.images['input'].store_url).should == 200
657
- end
658
-
659
- it 'should provide storage path without prefix' do
660
- subject.handlers[0].stores[0].realize(state)
661
-
662
- state.images['input'].store_path.should == "test_out.jpg"
663
- end
664
- end
665
-
666
- describe 'non encrypted connection mode' do
667
- subject do
668
- Configuration.read(<<-EOF)
669
- s3 key="#{ENV['AWS_ACCESS_KEY_ID']}" secret="#{ENV['AWS_SECRET_ACCESS_KEY']}" ssl=false
670
- path "hash" "\#{test_image}"
671
- post {
672
- store_s3 "input" bucket="#{ENV['AWS_S3_TEST_BUCKET']}" path="hash"
673
- }
674
- EOF
675
- end
676
-
677
- it 'should source image from S3 using path spec' do
678
- subject.handlers[0].stores[0].should be_a Configuration::S3Store
679
- subject.handlers[0].stores[0].realize(state)
680
-
681
- @test_object.read.should == @test_data
682
- end
683
-
684
- it 'should provide source HTTP url' do
685
- subject.handlers[0].stores[0].realize(state)
686
-
687
- state.images['input'].store_url.to_s.should start_with "http://"
688
- state.images['input'].store_url.to_s.should include ENV['AWS_S3_TEST_BUCKET']
689
- state.images['input'].store_url.to_s.should include "/test_out.jpg"
690
- state.images['input'].store_url.to_s.should include ENV['AWS_ACCESS_KEY_ID']
691
- status(state.images['input'].store_url).should == 200
692
- end
693
- end
694
-
695
- describe 'permission control' do
696
- it 'should store images that are not accessible by public by default' do
697
- subject.handlers[0].stores[0].realize(state)
698
- status(state.images['input'].store_url.to_s[/^[^\?]*/]).should == 403
699
- end
700
-
701
- describe 'public' do
702
- subject do
703
- Configuration.read(<<-EOF)
704
- s3 key="#{ENV['AWS_ACCESS_KEY_ID']}" secret="#{ENV['AWS_SECRET_ACCESS_KEY']}"
705
- path "hash" "\#{test_image}"
706
- post {
707
- store_s3 "input" bucket="#{ENV['AWS_S3_TEST_BUCKET']}" path="hash" public=true
708
- }
709
- EOF
710
- end
711
-
712
- it 'should store image accessible for public' do
713
- subject.handlers[0].stores[0].realize(state)
714
-
715
- get(state.images['input'].store_url).should == @test_data
716
- end
717
-
718
- it 'should provide public source HTTPS url' do
719
- subject.handlers[0].stores[0].realize(state)
720
-
721
- state.images['input'].store_url.to_s.should start_with "https://"
722
- state.images['input'].store_url.to_s.should include ENV['AWS_S3_TEST_BUCKET']
723
- state.images['input'].store_url.to_s.should include "/test_out.jpg"
724
- state.images['input'].store_url.to_s.should_not include ENV['AWS_ACCESS_KEY_ID']
725
- status(state.images['input'].store_url).should == 200
726
- end
727
-
728
- describe 'non encrypted connection mode' do
729
- subject do
730
- Configuration.read(<<-EOF)
731
- s3 key="#{ENV['AWS_ACCESS_KEY_ID']}" secret="#{ENV['AWS_SECRET_ACCESS_KEY']}" ssl=false
732
- path "hash" "\#{test_image}"
733
- post {
734
- store_s3 "input" bucket="#{ENV['AWS_S3_TEST_BUCKET']}" path="hash" public=true
735
- }
736
- EOF
737
- end
738
-
739
- it 'should provide public source HTTP url' do
740
- subject.handlers[0].stores[0].realize(state)
741
-
742
- state.images['input'].store_url.to_s.should start_with "http://"
743
- state.images['input'].store_url.to_s.should include ENV['AWS_S3_TEST_BUCKET']
744
- state.images['input'].store_url.to_s.should include "/test_out.jpg"
745
- state.images['input'].store_url.to_s.should_not include ENV['AWS_ACCESS_KEY_ID']
746
- status(state.images['input'].store_url).should == 200
747
- end
748
- end
749
- end
750
- end
751
-
752
- describe 'cache control' do
753
- it 'should have no cache control set by default' do
754
- subject.handlers[0].stores[0].realize(state)
755
- headers(state.images['input'].store_url)["Cache-Control"].should be_nil
756
- end
757
-
758
- describe 'set' do
759
- subject do
760
- Configuration.read(<<-EOF)
761
- s3 key="#{ENV['AWS_ACCESS_KEY_ID']}" secret="#{ENV['AWS_SECRET_ACCESS_KEY']}"
762
- path "hash" "\#{test_image}"
763
- post {
764
- store_s3 "input" bucket="#{ENV['AWS_S3_TEST_BUCKET']}" path="hash" public=true cache-control="public, max-age=3600"
765
- }
766
- EOF
767
- end
768
-
769
- it 'should have given cahce control header set on the object' do
770
- subject.handlers[0].stores[0].realize(state)
771
- headers(state.images['input'].store_url)["Cache-Control"].should == 'public, max-age=3600'
772
- end
773
- end
774
- end
775
-
776
- describe 'conditional inclusion support' do
777
- let :state do
778
- Configuration::RequestState.new(@test_data, {test_image: 'test_out.jpg', list: 'input,input2'})
779
- end
780
-
781
- subject do
782
- Configuration.read(<<-EOF)
783
- post {
784
- store_s3 "input" bucket="#{ENV['AWS_S3_TEST_BUCKET']}" path="hash" if-image-name-on="\#{list}"
785
- store_s3 "input1" bucket="#{ENV['AWS_S3_TEST_BUCKET']}" path="hash" if-image-name-on="\#{list}"
786
- store_s3 "input2" bucket="#{ENV['AWS_S3_TEST_BUCKET']}" path="hash" if-image-name-on="\#{list}"
787
- }
788
- EOF
789
- end
790
-
791
- it 'should mark sores to be included when image name match if-image-name-on list' do
792
- subject.handlers[0].stores[0].excluded?(state).should be_false
793
- subject.handlers[0].stores[1].excluded?(state).should be_true
794
- subject.handlers[0].stores[2].excluded?(state).should be_false
795
- end
796
- end
797
-
798
- describe 'context locals' do
799
- subject do
800
- Configuration.read(<<-EOF)
801
- s3 key="#{ENV['AWS_ACCESS_KEY_ID']}" secret="#{ENV['AWS_SECRET_ACCESS_KEY']}" ssl=false
802
- path "image_name" "\#{image_name}"
803
- path "bucket" "\#{bucket}"
804
- path "image_mime_extension" "\#{image_mime_extension}"
805
- post {
806
- store_s3 "input" bucket="#{ENV['AWS_S3_TEST_BUCKET']}" path="image_name"
807
- store_s3 "input" bucket="#{ENV['AWS_S3_TEST_BUCKET']}" path="bucket"
808
- store_s3 "input" bucket="#{ENV['AWS_S3_TEST_BUCKET']}" path="image_mime_extension"
809
- }
810
- EOF
811
- end
812
-
813
- it 'should provide image name to be used as #{image_name}' do
814
- subject.handlers[0].stores[0].realize(state)
815
-
816
- state.images['input'].store_path.should == 'input'
817
- end
818
-
819
- it 'should provide bucket to be used as #{bucket}' do
820
- subject.handlers[0].stores[1].realize(state)
821
-
822
- state.images['input'].store_path.should == ENV['AWS_S3_TEST_BUCKET']
823
- end
824
-
825
- it 'should provide image mime type based file extension to be used as #{image_mime_extension}' do
826
- state.images['input'].mime_type = 'image/jpeg'
827
- subject.handlers[0].stores[2].realize(state)
828
-
829
- state.images['input'].store_path.should == 'jpg'
830
- end
831
-
832
- it 'should raise PathRenderingError if there is on mime type for image defined and path contains #{image_mime_extension}' do
833
- expect {
834
- subject.handlers[0].stores[2].realize(state)
835
- }.to raise_error Configuration::PathRenderingError, %q{cannot generate path 'image_mime_extension' from template '#{image_mime_extension}': image 'input' does not have data for variable 'image_mime_extension'}
836
- end
837
- end
838
-
839
- describe 'error handling' do
840
- it 'should raise NoValueError on missing image name' do
841
- expect {
842
- Configuration.read(<<-EOF)
843
- post "test" {
844
- store_s3 bucket="#{ENV['AWS_S3_TEST_BUCKET']}" path="hash"
845
- }
846
- EOF
847
- }.to raise_error Configuration::NoValueError, %{syntax error while parsing 'store_s3 bucket="#{ENV['AWS_S3_TEST_BUCKET']}" path="hash"': expected image name}
848
- end
849
-
850
- it 'should raise NoAttributeError on missing bucket name' do
851
- expect {
852
- Configuration.read(<<-EOF)
853
- post "test" {
854
- store_s3 "input" path="hash"
855
- }
856
- EOF
857
- }.to raise_error Configuration::NoAttributeError, %{syntax error while parsing 'store_s3 "input" path="hash"': expected 'bucket' attribute to be set}
858
- end
859
-
860
- it 'should raise NoAttributeError on missing path' do
861
- expect {
862
- Configuration.read(<<-EOF)
863
- post "test" {
864
- store_s3 "input" bucket="#{ENV['AWS_S3_TEST_BUCKET']}"
865
- }
866
- EOF
867
- }.to raise_error Configuration::NoAttributeError, %{syntax error while parsing 'store_s3 "input" bucket="#{ENV['AWS_S3_TEST_BUCKET']}"': expected 'path' attribute to be set}
868
- end
869
-
870
- it 'should raise S3NotConfiguredError if used but no s3 statement was used' do
871
- subject = Configuration.read(<<-EOF)
872
- path "hash" "\#{test_image}"
873
- post "test" {
874
- store_s3 "input" bucket="#{ENV['AWS_S3_TEST_BUCKET']}" path="hash"
875
- }
876
- EOF
877
- expect {
878
- subject.handlers[0].stores[0].realize(state)
879
- }.to raise_error Configuration::S3NotConfiguredError, 'S3 client not configured'
880
- end
881
-
882
- it 'should raise S3NoSuchBucketError if bucket was not found on S3' do
883
- subject = Configuration.read(<<-EOF)
884
- s3 key="#{ENV['AWS_ACCESS_KEY_ID']}" secret="#{ENV['AWS_SECRET_ACCESS_KEY']}" ssl=false
885
- path "hash" "\#{test_image}"
886
- post "test" {
887
- store_s3 "input" bucket="#{ENV['AWS_S3_TEST_BUCKET']}X" path="hash"
888
- }
889
- EOF
890
- expect {
891
- subject.handlers[0].stores[0].realize(state)
892
- }.to raise_error Configuration::S3NoSuchBucketError, %{S3 bucket '#{ENV['AWS_S3_TEST_BUCKET']}X' does not exist}
893
- end
894
-
895
- it 'should raise S3AccessDenied if bucket was not found on S3' do
896
- subject = Configuration.read(<<-EOF)
897
- s3 key="#{ENV['AWS_ACCESS_KEY_ID']}" secret="#{ENV['AWS_SECRET_ACCESS_KEY']}" ssl=false
898
- path "hash" "\#{test_image}"
899
- post "test" {
900
- store_s3 "input" bucket="blah" path="hash"
901
- }
902
- EOF
903
- expect {
904
- subject.handlers[0].stores[0].realize(state)
905
- }.to raise_error Configuration::S3AccessDenied, %{access to S3 bucket 'blah' or key 'test_out.jpg' was denied}
906
- end
907
- end
908
- end
909
- end
910
- end
911
-