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,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
-