httpimagestore 0.5.0 → 1.0.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.
- 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
|