httpimagestore 0.5.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +10 -12
- data/Gemfile.lock +57 -55
- data/README.md +829 -0
- data/VERSION +1 -1
- data/bin/httpimagestore +114 -180
- data/features/cache-control.feature +26 -90
- data/features/compatibility.feature +129 -0
- data/features/error-reporting.feature +207 -0
- data/features/health-check.feature +30 -0
- data/features/s3-store-and-thumbnail.feature +65 -0
- data/features/step_definitions/httpimagestore_steps.rb +66 -26
- data/features/support/env.rb +32 -5
- data/features/support/test.empty +0 -0
- data/httpimagestore.gemspec +60 -47
- data/lib/httpimagestore/aws_sdk_regions_hack.rb +23 -0
- data/lib/httpimagestore/configuration/file.rb +120 -0
- data/lib/httpimagestore/configuration/handler.rb +239 -0
- data/lib/httpimagestore/configuration/output.rb +119 -0
- data/lib/httpimagestore/configuration/path.rb +77 -0
- data/lib/httpimagestore/configuration/s3.rb +194 -0
- data/lib/httpimagestore/configuration/thumbnailer.rb +244 -0
- data/lib/httpimagestore/configuration.rb +126 -29
- data/lib/httpimagestore/error_reporter.rb +36 -0
- data/lib/httpimagestore/ruby_string_template.rb +26 -0
- data/load_test/load_test.1k.23a022f6e.m1.small-comp.csv +3 -0
- data/load_test/load_test.1k.ec9bde794.m1.small.csv +4 -0
- data/load_test/load_test.jmx +344 -0
- data/load_test/thumbnail_specs.csv +11 -0
- data/spec/configuration_file_spec.rb +309 -0
- data/spec/configuration_handler_spec.rb +124 -0
- data/spec/configuration_output_spec.rb +338 -0
- data/spec/configuration_path_spec.rb +92 -0
- data/spec/configuration_s3_spec.rb +571 -0
- data/spec/configuration_spec.rb +80 -105
- data/spec/configuration_thumbnailer_spec.rb +417 -0
- data/spec/ruby_string_template_spec.rb +43 -0
- data/spec/spec_helper.rb +61 -0
- data/spec/support/compute.jpg +0 -0
- data/spec/support/cuba_response_env.rb +40 -0
- data/spec/support/full.cfg +49 -0
- metadata +138 -84
- data/README.rdoc +0 -23
- data/features/httpimagestore.feature +0 -167
- data/lib/httpimagestore/image_path.rb +0 -54
- data/lib/httpimagestore/s3_service.rb +0 -37
- data/lib/httpimagestore/thumbnail_class.rb +0 -13
- data/spec/image_path_spec.rb +0 -72
- data/spec/test.cfg +0 -8
@@ -0,0 +1,207 @@
|
|
1
|
+
Feature: Image list based thumbnailing and S3 storage
|
2
|
+
Storage based on URL specified image names to be generated and stored using two different path formats.
|
3
|
+
This configuration should be mostly compatible with pre v1.0 release.
|
4
|
+
|
5
|
+
Background:
|
6
|
+
Given S3 settings in AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY and AWS_S3_TEST_BUCKET environment variables
|
7
|
+
Given httpimagestore server is running at http://localhost:3000/ with the following configuration
|
8
|
+
"""
|
9
|
+
s3 key="@AWS_ACCESS_KEY_ID@" secret="@AWS_SECRET_ACCESS_KEY@" ssl=false
|
10
|
+
|
11
|
+
path "structured-name" "#{dirname}/#{digest}/#{basename}-#{imagename}.#{mimeextension}"
|
12
|
+
path "missing" "blah"
|
13
|
+
path "zero" "zero"
|
14
|
+
|
15
|
+
put "multipart" ":name_list" {
|
16
|
+
thumbnail "input" {
|
17
|
+
"small" operation="crop" width=128 height=128 if-image-name-on="#{name_list}"
|
18
|
+
"bad" operation="crop" width=0 height=0 if-image-name-on="#{name_list}"
|
19
|
+
"bad_dim" operation="crop" width="128x" height=128 if-image-name-on="#{name_list}"
|
20
|
+
"superlarge" operation="crop" width=16000 height=16000 if-image-name-on="#{name_list}"
|
21
|
+
"large_png" operation="crop" width=7000 height=7000 format="png" if-image-name-on="#{name_list}"
|
22
|
+
"bad_opts" operation="crop" width=128 height=128 options="foo=bar" if-image-name-on="#{name_list}"
|
23
|
+
}
|
24
|
+
}
|
25
|
+
|
26
|
+
put "singlepart" ":name_list" {
|
27
|
+
thumbnail "input" "small" operation="crop" width=128 height=128 if-image-name-on="#{name_list}"
|
28
|
+
thumbnail "input" "bad" operation="crop" width=0 height=0 if-image-name-on="#{name_list}"
|
29
|
+
thumbnail "input" "bad_dim" operation="crop" width="128x" height=128 if-image-name-on="#{name_list}"
|
30
|
+
thumbnail "input" "superlarge" operation="crop" width=16000 height=16000 if-image-name-on="#{name_list}"
|
31
|
+
thumbnail "input" "large_png" operation="crop" width=7000 height=7000 format="png" if-image-name-on="#{name_list}"
|
32
|
+
thumbnail "input" "bad_opts" operation="crop" width=128 height=128 options="foo=bar" if-image-name-on="#{name_list}"
|
33
|
+
}
|
34
|
+
|
35
|
+
get "s3" {
|
36
|
+
source_s3 "original" bucket="@AWS_S3_TEST_BUCKET@" path="missing"
|
37
|
+
}
|
38
|
+
|
39
|
+
get "file" {
|
40
|
+
source_file "original" root="/tmp" path="missing"
|
41
|
+
}
|
42
|
+
|
43
|
+
get "zero" {
|
44
|
+
source_file "original" root="/dev" path="zero"
|
45
|
+
}
|
46
|
+
"""
|
47
|
+
Given httpthumbnailer server is running at http://localhost:3100/
|
48
|
+
|
49
|
+
@error-reporting
|
50
|
+
Scenario: Reporting of missing resource
|
51
|
+
When I do GET request http://localhost:3000/blah
|
52
|
+
Then response status will be 404
|
53
|
+
And response content type will be text/plain
|
54
|
+
And response body will be CRLF ended lines
|
55
|
+
"""
|
56
|
+
request for URI '/blah' was not handled by the server
|
57
|
+
"""
|
58
|
+
|
59
|
+
@error-reporting
|
60
|
+
Scenario: Reporting of missing S3 resource
|
61
|
+
When I do GET request http://localhost:3000/s3
|
62
|
+
Then response status will be 404
|
63
|
+
And response content type will be text/plain
|
64
|
+
And response body will be CRLF ended lines
|
65
|
+
"""
|
66
|
+
S3 bucket 'httpimagestoretest' does not contain key 'blah'
|
67
|
+
"""
|
68
|
+
|
69
|
+
@error-reporting
|
70
|
+
Scenario: Reporting of missing file resource
|
71
|
+
When I do GET request http://localhost:3000/file
|
72
|
+
Then response status will be 404
|
73
|
+
And response content type will be text/plain
|
74
|
+
And response body will be CRLF ended lines
|
75
|
+
"""
|
76
|
+
error while processing image 'original': file 'blah' not found
|
77
|
+
"""
|
78
|
+
|
79
|
+
@error-reporting
|
80
|
+
Scenario: Reporting of unsupported media type
|
81
|
+
Given test.txt file content as request body
|
82
|
+
When I do PUT request http://localhost:3000/multipart/small,tiny
|
83
|
+
Then response status will be 415
|
84
|
+
And response content type will be text/plain
|
85
|
+
And response body will be CRLF ended lines like
|
86
|
+
"""
|
87
|
+
thumbnailing of 'input' failed: unsupported media type: no decode delegate for this image format
|
88
|
+
"""
|
89
|
+
When I do PUT request http://localhost:3000/singlepart/small,tiny
|
90
|
+
Then response status will be 415
|
91
|
+
And response content type will be text/plain
|
92
|
+
And response body will be CRLF ended lines like
|
93
|
+
"""
|
94
|
+
thumbnailing of 'input' into 'small' failed: unsupported media type: no decode delegate for this image format
|
95
|
+
"""
|
96
|
+
|
97
|
+
@error-reporting
|
98
|
+
Scenario: Reporting and handling of thumbnailing errors
|
99
|
+
Given test.jpg file content as request body
|
100
|
+
When I do PUT request http://localhost:3000/multipart/small,bad
|
101
|
+
Then response status will be 400
|
102
|
+
And response content type will be text/plain
|
103
|
+
And response body will be CRLF ended lines like
|
104
|
+
"""
|
105
|
+
thumbnailing of 'input' into 'bad' failed: at least one image dimension is zero: 0x0
|
106
|
+
"""
|
107
|
+
When I do PUT request http://localhost:3000/singlepart/small,bad
|
108
|
+
Then response status will be 400
|
109
|
+
And response content type will be text/plain
|
110
|
+
And response body will be CRLF ended lines like
|
111
|
+
"""
|
112
|
+
thumbnailing of 'input' into 'bad' failed: at least one image dimension is zero: 0x0
|
113
|
+
"""
|
114
|
+
|
115
|
+
@error-reporting
|
116
|
+
Scenario: Reporting and handling of thumbnailing errors - bad options format
|
117
|
+
Given test.jpg file content as request body
|
118
|
+
When I do PUT request http://localhost:3000/multipart/small,bad_opts
|
119
|
+
Then response status will be 400
|
120
|
+
And response content type will be text/plain
|
121
|
+
And response body will be CRLF ended lines
|
122
|
+
"""
|
123
|
+
thumbnailing of 'input' into 'bad_opts' failed: missing option value for key 'foo=bar'
|
124
|
+
"""
|
125
|
+
When I do PUT request http://localhost:3000/singlepart/small,bad_opts
|
126
|
+
Then response status will be 400
|
127
|
+
And response content type will be text/plain
|
128
|
+
And response body will be CRLF ended lines
|
129
|
+
"""
|
130
|
+
thumbnailing of 'input' into 'bad_opts' failed: missing option value for key 'foo=bar'
|
131
|
+
"""
|
132
|
+
|
133
|
+
@error-reporting @test
|
134
|
+
Scenario: Bad dimension
|
135
|
+
Given test.jpg file content as request body
|
136
|
+
When I do PUT request http://localhost:3000/multipart/bad_dim
|
137
|
+
Then response status will be 400
|
138
|
+
And response content type will be text/plain
|
139
|
+
And response body will be CRLF ended lines like
|
140
|
+
"""
|
141
|
+
thumbnailing of 'input' into 'bad_dim' failed: bad dimension value: 128x
|
142
|
+
"""
|
143
|
+
When I do PUT request http://localhost:3000/singlepart/bad_dim
|
144
|
+
Then response status will be 400
|
145
|
+
And response content type will be text/plain
|
146
|
+
And response body will be CRLF ended lines like
|
147
|
+
"""
|
148
|
+
thumbnailing of 'input' into 'bad_dim' failed: bad dimension value: 128x
|
149
|
+
"""
|
150
|
+
|
151
|
+
@error-reporting
|
152
|
+
Scenario: Too large image - uploaded image too big to fit in memory limit
|
153
|
+
Given test-large.jpg file content as request body
|
154
|
+
When I do PUT request http://localhost:3000/multipart/large_png
|
155
|
+
Then response status will be 413
|
156
|
+
And response content type will be text/plain
|
157
|
+
And response body will be CRLF ended lines like
|
158
|
+
"""
|
159
|
+
thumbnailing of 'input' failed: image too large: cache resources exhausted
|
160
|
+
"""
|
161
|
+
When I do PUT request http://localhost:3000/singlepart/large_png
|
162
|
+
Then response status will be 413
|
163
|
+
And response content type will be text/plain
|
164
|
+
And response body will be CRLF ended lines like
|
165
|
+
"""
|
166
|
+
thumbnailing of 'input' into 'large_png' failed: image too large: cache resources exhausted
|
167
|
+
"""
|
168
|
+
|
169
|
+
@error-reporting
|
170
|
+
Scenario: Too large image - memory exhausted when thmbnailing
|
171
|
+
Given test.jpg file content as request body
|
172
|
+
When I do PUT request http://localhost:3000/multipart/superlarge
|
173
|
+
Then response status will be 413
|
174
|
+
And response content type will be text/plain
|
175
|
+
And response body will be CRLF ended lines like
|
176
|
+
"""
|
177
|
+
thumbnailing of 'input' into 'superlarge' failed: image too large: cache resources exhausted
|
178
|
+
"""
|
179
|
+
When I do PUT request http://localhost:3000/singlepart/superlarge
|
180
|
+
Then response status will be 413
|
181
|
+
And response content type will be text/plain
|
182
|
+
And response body will be CRLF ended lines like
|
183
|
+
"""
|
184
|
+
thumbnailing of 'input' into 'superlarge' failed: image too large: cache resources exhausted
|
185
|
+
"""
|
186
|
+
|
187
|
+
@error-reporting
|
188
|
+
Scenario: Zero body length
|
189
|
+
Given test.empty file content as request body
|
190
|
+
When I do PUT request http://localhost:3000/multipart/small
|
191
|
+
Then response status will be 400
|
192
|
+
And response content type will be text/plain
|
193
|
+
And response body will be CRLF ended lines like
|
194
|
+
"""
|
195
|
+
empty body - expected image data
|
196
|
+
"""
|
197
|
+
|
198
|
+
@error-reporting
|
199
|
+
Scenario: Memory limit exceeded
|
200
|
+
When I do GET request http://localhost:3000/zero
|
201
|
+
Then response status will be 413
|
202
|
+
And response content type will be text/plain
|
203
|
+
And response body will be CRLF ended lines like
|
204
|
+
"""
|
205
|
+
memory limit exceeded
|
206
|
+
"""
|
207
|
+
|
@@ -0,0 +1,30 @@
|
|
1
|
+
Feature: Health check URL
|
2
|
+
Server can be tested with GET request to '/health_check'.
|
3
|
+
|
4
|
+
Background:
|
5
|
+
Given httpimagestore server is running at http://localhost:3000/ with the following configuration
|
6
|
+
"""
|
7
|
+
"""
|
8
|
+
|
9
|
+
@health-check
|
10
|
+
Scenario: Passing health check when thumbnailer is running
|
11
|
+
Given httpthumbnailer server is running at http://localhost:3100/
|
12
|
+
When I do GET request http://localhost:3000/health_check
|
13
|
+
Then response status will be 200
|
14
|
+
And response content type will be text/plain
|
15
|
+
And response body will be CRLF ended lines
|
16
|
+
"""
|
17
|
+
HTTP Image Store OK
|
18
|
+
"""
|
19
|
+
|
20
|
+
@health-check
|
21
|
+
Scenario: Failing health check when thumbnailer is not running
|
22
|
+
Given httpthumbnailer server is not running
|
23
|
+
When I do GET request http://localhost:3000/health_check
|
24
|
+
Then response status will be 502
|
25
|
+
And response content type will be text/plain
|
26
|
+
And response body will be CRLF ended lines
|
27
|
+
"""
|
28
|
+
Connection refused - connect(2) (http://localhost:3100)
|
29
|
+
"""
|
30
|
+
|
@@ -0,0 +1,65 @@
|
|
1
|
+
Feature: Store limited original image in S3 and thumbnail based on request
|
2
|
+
Posted image will be converted to JPEG and resized if it is bigger that given dimensions.
|
3
|
+
Than it will get stored on S3.
|
4
|
+
Get interface will allow to fetch the image from S3 and thumbnailing to given parameters.
|
5
|
+
|
6
|
+
Background:
|
7
|
+
Given S3 settings in AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY and AWS_S3_TEST_BUCKET environment variables
|
8
|
+
Given httpimagestore server is running at http://localhost:3000/ with the following configuration
|
9
|
+
"""
|
10
|
+
s3 key="@AWS_ACCESS_KEY_ID@" secret="@AWS_SECRET_ACCESS_KEY@" ssl=false
|
11
|
+
|
12
|
+
path "original-hash" "#{digest}.#{mimeextension}"
|
13
|
+
path "path" "#{path}"
|
14
|
+
|
15
|
+
put "original" {
|
16
|
+
thumbnail "input" "original" operation="limit" width=100 height=100 format="jpeg" quality=95
|
17
|
+
|
18
|
+
store_s3 "original" bucket="@AWS_S3_TEST_BUCKET@" path="original-hash"
|
19
|
+
|
20
|
+
output_store_path "original"
|
21
|
+
}
|
22
|
+
|
23
|
+
get "thumbnail" "v1" ":path" ":operation" ":width" ":height" ":options?" {
|
24
|
+
source_s3 "original" bucket="@AWS_S3_TEST_BUCKET@" path="path"
|
25
|
+
|
26
|
+
thumbnail "original" "thumbnail" operation="#{operation}" width="#{width}" height="#{height}" options="#{options}" quality=84 format="png"
|
27
|
+
|
28
|
+
output_image "thumbnail" cache-control="public, max-age=31557600, s-maxage=0"
|
29
|
+
}
|
30
|
+
|
31
|
+
"""
|
32
|
+
Given httpthumbnailer server is running at http://localhost:3100/
|
33
|
+
|
34
|
+
@s3-store-and-thumbnail
|
35
|
+
Scenario: Putting original to S3 bucket
|
36
|
+
Given there is no 4006450256177f4a.jpg file in S3 bucket
|
37
|
+
Given test.jpg file content as request body
|
38
|
+
When I do PUT request http://localhost:3000/original
|
39
|
+
Then response status will be 200
|
40
|
+
And response content type will be text/plain
|
41
|
+
And response body will be CRLF ended lines
|
42
|
+
"""
|
43
|
+
4006450256177f4a.jpg
|
44
|
+
"""
|
45
|
+
Then S3 object 4006450256177f4a.jpg will contain JPEG image of size 71x100
|
46
|
+
When I do GET request http://@AWS_S3_TEST_BUCKET@.s3.amazonaws.com/4006450256177f4a.jpg
|
47
|
+
Then response status will be 403
|
48
|
+
|
49
|
+
@s3-store-and-thumbnail
|
50
|
+
Scenario: Getting thumbnail to spec based on uploaded S3 image
|
51
|
+
Given test.jpg file content is stored in S3 under 4006450256177f4a.jpg
|
52
|
+
When I do GET request http://localhost:3000/thumbnail/v1/4006450256177f4a.jpg/pad/50/50
|
53
|
+
Then response status will be 200
|
54
|
+
And response content type will be image/png
|
55
|
+
Then response body will contain PNG image of size 50x50
|
56
|
+
|
57
|
+
@s3-store-and-thumbnail
|
58
|
+
Scenario: Getting thumbnail to spec based on uploaded S3 image - with options passed
|
59
|
+
Given test.jpg file content is stored in S3 under 4006450256177f4a.jpg
|
60
|
+
When I do GET request http://localhost:3000/thumbnail/v1/4006450256177f4a.jpg/pad/50/50/background-color:green
|
61
|
+
Then response status will be 200
|
62
|
+
And response content type will be image/png
|
63
|
+
Then response body will contain PNG image of size 50x50
|
64
|
+
And that image pixel at 2x2 should be of color green
|
65
|
+
|
@@ -3,15 +3,19 @@ Given /httpimagestore argument (.*)/ do |arg|
|
|
3
3
|
end
|
4
4
|
|
5
5
|
Given /httpimagestore server is running at (.*) with the following configuration/ do |url, config|
|
6
|
-
|
7
|
-
|
8
|
-
cfile.
|
6
|
+
$temp_dir = Pathname.new(Dir.mktmpdir) unless $temp_dir
|
7
|
+
|
8
|
+
cfile = $temp_dir + Digest.hexencode(Digest::MD5.digest(config))
|
9
|
+
cfile.open('w') do |io|
|
10
|
+
io.write(config.replace_s3_variables)
|
11
|
+
end
|
9
12
|
|
10
13
|
begin
|
14
|
+
log = support_dir + 'server.log'
|
11
15
|
start_server(
|
12
|
-
"bundle exec #{script('httpimagestore')} #{(@httpimagestore_args ||= []).join(' ')} #{cfile.
|
16
|
+
"bundle exec #{script('httpimagestore')} -f -d -l #{log} -w 1 #{(@httpimagestore_args ||= []).join(' ')} #{cfile.to_s}",
|
13
17
|
'/tmp/httpimagestore.pid',
|
14
|
-
|
18
|
+
log,
|
15
19
|
url
|
16
20
|
)
|
17
21
|
ensure
|
@@ -20,14 +24,19 @@ Given /httpimagestore server is running at (.*) with the following configuration
|
|
20
24
|
end
|
21
25
|
|
22
26
|
Given /httpthumbnailer server is running at (.*)/ do |url|
|
27
|
+
log = support_dir + 'thumbniler.log'
|
23
28
|
start_server(
|
24
|
-
"httpthumbnailer",
|
29
|
+
"httpthumbnailer -f -d -l #{log} -w 1",
|
25
30
|
'/tmp/httpthumbnailer.pid',
|
26
|
-
|
31
|
+
log,
|
27
32
|
url
|
28
33
|
)
|
29
34
|
end
|
30
35
|
|
36
|
+
Given /httpthumbnailer server is not running/ do
|
37
|
+
stop_server('/tmp/httpthumbnailer.pid')
|
38
|
+
end
|
39
|
+
|
31
40
|
Given /httpimagestore log is empty/ do
|
32
41
|
log = support_dir + 'server.log'
|
33
42
|
log.truncate(0) if log.exist?
|
@@ -38,16 +47,21 @@ Given /httpthumbnailer log is empty/ do
|
|
38
47
|
log.truncate(0) if log.exist?
|
39
48
|
end
|
40
49
|
|
41
|
-
Given
|
50
|
+
Given /^([^ ]*) file content as request body/ do |file|
|
42
51
|
@request_body = File.open(support_dir + file){|f| f.read }
|
43
52
|
end
|
44
53
|
|
45
|
-
Given /
|
46
|
-
|
54
|
+
Given /S3 settings in AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY and AWS_S3_TEST_BUCKET environment variables/ do
|
55
|
+
|
56
|
+
unless ENV['AWS_ACCESS_KEY_ID'] and ENV['AWS_SECRET_ACCESS_KEY'] and ENV['AWS_S3_TEST_BUCKET']
|
57
|
+
fail "AWS_ACCESS_KEY_ID or AWS_SECRET_ACCESS_KEY or AWS_S3_TEST_BUCKET environment variables not set"
|
58
|
+
end
|
59
|
+
|
60
|
+
@bucket = AWS::S3.new(access_key_id: ENV['AWS_ACCESS_KEY_ID'], secret_access_key: ENV['AWS_SECRET_ACCESS_KEY'], use_ssl: false).buckets[ENV['AWS_S3_TEST_BUCKET']]
|
47
61
|
end
|
48
62
|
|
49
63
|
Given /there is no (.*) file in S3 bucket/ do |path|
|
50
|
-
@bucket.objects
|
64
|
+
@bucket.objects[path].delete # rescue S3::Error::NoSuchKey
|
51
65
|
end
|
52
66
|
|
53
67
|
Given /(.*) header set to (.*)/ do |header, value|
|
@@ -55,8 +69,16 @@ Given /(.*) header set to (.*)/ do |header, value|
|
|
55
69
|
@request_headers[header] = value
|
56
70
|
end
|
57
71
|
|
72
|
+
Given /(.*) file content is stored in S3 under (.*)/ do |file, key|
|
73
|
+
@bucket.objects[key].write(File.open(support_dir + file){|f| f.read }, content_type: 'image/jpeg')
|
74
|
+
end
|
75
|
+
|
76
|
+
Then /S3 bucket will not contain (.*)/ do |key|
|
77
|
+
@bucket.objects[key].exists?.should_not be_true
|
78
|
+
end
|
79
|
+
|
58
80
|
When /I do (.*) request (.*)/ do |method, uri|
|
59
|
-
@response = HTTPClient.new.request(method, URI.encode(uri), nil, @request_body, (@request_headers or {}))
|
81
|
+
@response = HTTPClient.new.request(method, URI.encode(uri.replace_s3_variables), nil, @request_body, (@request_headers or {}))
|
60
82
|
end
|
61
83
|
|
62
84
|
Then /response status will be (.*)/ do |status|
|
@@ -68,30 +90,30 @@ Then /response content type will be (.*)/ do |content_type|
|
|
68
90
|
end
|
69
91
|
|
70
92
|
Then /response body will be CRLF ended lines like/ do |body|
|
71
|
-
@response.body.should match(body)
|
93
|
+
@response.body.should match(body.replace_s3_variables)
|
72
94
|
@response.body.each_line do |line|
|
73
95
|
line[-2,2].should == "\r\n"
|
74
96
|
end
|
75
97
|
end
|
76
98
|
|
77
99
|
Then /response body will be CRLF ended lines$/ do |body|
|
78
|
-
@response.body.should == body.gsub("\n", "\r\n") + "\r\n"
|
100
|
+
@response.body.should == body.replace_s3_variables.gsub("\n", "\r\n") + "\r\n"
|
79
101
|
end
|
80
102
|
|
81
103
|
Then /(http.*) content type will be (.*)/ do |url, content_type|
|
82
|
-
get_headers(url)['Content-Type'].should == content_type
|
104
|
+
get_headers(url.replace_s3_variables)['Content-Type'].should == content_type
|
83
105
|
end
|
84
106
|
|
85
107
|
Then /(http.*) ([^ ]+) header will be (.*)/ do |url, header, value|
|
86
|
-
get_headers(url)[header].should == value
|
108
|
+
get_headers(url.replace_s3_variables)[header].should == value
|
87
109
|
end
|
88
110
|
|
89
111
|
Then /(http.*) ([^ ]+) header will not be set/ do |url, header|
|
90
|
-
get_headers(url)[header].should be_nil
|
112
|
+
get_headers(url.replace_s3_variables)[header].should be_nil
|
91
113
|
end
|
92
114
|
|
93
|
-
Then /(.*) will contain (.*) image of size (.*)x(.*)/ do |url, format, width, height|
|
94
|
-
data = get(url)
|
115
|
+
Then /(http.*) will contain (.*) image of size (.*)x(.*)/ do |url, format, width, height|
|
116
|
+
data = get(url.replace_s3_variables)
|
95
117
|
|
96
118
|
@image.destroy! if @image
|
97
119
|
@image = Magick::Image.from_blob(data).first
|
@@ -101,12 +123,30 @@ Then /(.*) will contain (.*) image of size (.*)x(.*)/ do |url, format, width, he
|
|
101
123
|
@image.rows.should == height.to_i
|
102
124
|
end
|
103
125
|
|
104
|
-
Then /S3
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
126
|
+
Then /S3 object (.*) will contain (.*) image of size (.*)x(.*)/ do |key, format, width, height|
|
127
|
+
data = @bucket.objects[key].read
|
128
|
+
|
129
|
+
@image.destroy! if @image
|
130
|
+
@image = Magick::Image.from_blob(data).first
|
131
|
+
|
132
|
+
@image.format.should == format
|
133
|
+
@image.columns.should == width.to_i
|
134
|
+
@image.rows.should == height.to_i
|
135
|
+
end
|
136
|
+
|
137
|
+
Then /response body will contain (.*) image of size (.*)x(.*)/ do |format, width, height|
|
138
|
+
data = @response.body
|
139
|
+
Pathname.new('/tmp/out.jpg').open('w'){|io| io.write data}
|
140
|
+
|
141
|
+
@image.destroy! if @image
|
142
|
+
@image = Magick::Image.from_blob(data).first
|
143
|
+
|
144
|
+
@image.format.should == format
|
145
|
+
@image.columns.should == width.to_i
|
146
|
+
@image.rows.should == height.to_i
|
147
|
+
end
|
148
|
+
|
149
|
+
And /that image pixel at (.*)x(.*) should be of color (.*)/ do |x, y, color|
|
150
|
+
@image.pixel_color(x.to_i, y.to_i).to_color.sub(/^#/, '0x').should == color
|
111
151
|
end
|
112
152
|
|
data/features/support/env.rb
CHANGED
@@ -17,7 +17,19 @@ require "open3"
|
|
17
17
|
require "thread"
|
18
18
|
require 'tempfile'
|
19
19
|
require 'RMagick'
|
20
|
-
require '
|
20
|
+
require 'aws-sdk'
|
21
|
+
require 'httpimagestore/aws_sdk_regions_hack'
|
22
|
+
require 'digest'
|
23
|
+
|
24
|
+
class String
|
25
|
+
def replace_s3_variables
|
26
|
+
string = self.dup
|
27
|
+
string.gsub!(/@AWS_ACCESS_KEY_ID@/, ENV['AWS_ACCESS_KEY_ID'])
|
28
|
+
string.gsub!(/@AWS_SECRET_ACCESS_KEY@/, ENV['AWS_SECRET_ACCESS_KEY'])
|
29
|
+
string.gsub!(/@AWS_S3_TEST_BUCKET@/, ENV['AWS_S3_TEST_BUCKET'])
|
30
|
+
string
|
31
|
+
end
|
32
|
+
end
|
21
33
|
|
22
34
|
def gem_dir
|
23
35
|
Pathname.new(__FILE__).dirname + '..' + '..'
|
@@ -35,22 +47,35 @@ def script(file)
|
|
35
47
|
gem_dir + 'bin' + file
|
36
48
|
end
|
37
49
|
|
50
|
+
def http_client
|
51
|
+
client = HTTPClient.new
|
52
|
+
#client.debug_dev = STDOUT
|
53
|
+
client
|
54
|
+
end
|
55
|
+
|
38
56
|
def get(url)
|
39
|
-
|
57
|
+
http_client.get_content(URI.encode(url))
|
40
58
|
end
|
41
59
|
|
42
60
|
def get_headers(url)
|
43
|
-
|
61
|
+
http_client.get(URI.encode(url)).headers
|
44
62
|
end
|
45
63
|
|
64
|
+
@@running_cmd = {}
|
46
65
|
def start_server(cmd, pid_file, log_file, test_url)
|
47
|
-
|
66
|
+
if @@running_cmd[pid_file]
|
67
|
+
return if @@running_cmd[pid_file] == cmd
|
68
|
+
stop_server(pid_file)
|
69
|
+
end
|
48
70
|
|
49
71
|
fork do
|
50
72
|
Daemon.daemonize(pid_file, log_file)
|
73
|
+
log_file = Pathname.new(log_file)
|
74
|
+
log_file.truncate(0) if log_file.exist?
|
51
75
|
exec(cmd)
|
52
76
|
end
|
53
|
-
|
77
|
+
|
78
|
+
@@running_cmd[pid_file] = cmd
|
54
79
|
|
55
80
|
ppid = Process.pid
|
56
81
|
at_exit do
|
@@ -71,6 +96,7 @@ def stop_server(pid_file)
|
|
71
96
|
pid_file = Pathname.new(pid_file)
|
72
97
|
return unless pid_file.exist?
|
73
98
|
|
99
|
+
STDERR.puts http_client.get_content("http://localhost:3000/stats") if pid_file.to_s.include? 'httpimagestore'
|
74
100
|
pid = pid_file.read.strip.to_i
|
75
101
|
|
76
102
|
Timeout.timeout(20) do
|
@@ -80,6 +106,7 @@ def stop_server(pid_file)
|
|
80
106
|
sleep 0.1
|
81
107
|
end
|
82
108
|
rescue Errno::ESRCH
|
109
|
+
@@running_cmd.delete pid_file.to_s
|
83
110
|
pid_file.unlink
|
84
111
|
end
|
85
112
|
end
|
File without changes
|