httpthumbnailer 1.0.0 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +1 -1
- data/Gemfile.lock +4 -4
- data/README.md +30 -1
- data/VERSION +1 -1
- data/features/identify.feature +31 -0
- data/features/step_definitions/httpthumbnailer_steps.rb +17 -14
- data/features/support/env.rb +1 -0
- data/features/thumbnail.feature +25 -8
- data/features/thumbnails.feature +38 -22
- data/httpthumbnailer.gemspec +8 -5
- data/lib/httpthumbnailer/error_reporter.rb +1 -14
- data/lib/httpthumbnailer/plugin/thumbnailer.rb +66 -30
- data/lib/httpthumbnailer/thumbnailer.rb +44 -12
- data/load_test/load_test-374846090-1.1.0-rc1-identify-only.csv +3 -0
- data/load_test/load_test-374846090-1.1.0-rc1.csv +11 -0
- data/load_test/soak_test.jmx +60 -3
- metadata +8 -5
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -33,7 +33,7 @@ GEM
|
|
33
33
|
rake
|
34
34
|
rdoc
|
35
35
|
json (1.7.7)
|
36
|
-
kgio (2.8.
|
36
|
+
kgio (2.8.1)
|
37
37
|
mime-types (1.23)
|
38
38
|
multi_json (1.7.3)
|
39
39
|
multipart-parser (0.1.1)
|
@@ -41,7 +41,7 @@ GEM
|
|
41
41
|
rack (1.5.2)
|
42
42
|
rack-test (0.6.2)
|
43
43
|
rack (>= 1.0)
|
44
|
-
raindrops (0.
|
44
|
+
raindrops (0.12.0)
|
45
45
|
rake (10.0.4)
|
46
46
|
rdoc (3.12.2)
|
47
47
|
json (~> 1.4)
|
@@ -65,7 +65,7 @@ GEM
|
|
65
65
|
kgio (~> 2.6)
|
66
66
|
rack
|
67
67
|
raindrops (~> 0.7)
|
68
|
-
unicorn-cuba-base (1.
|
68
|
+
unicorn-cuba-base (1.1.0)
|
69
69
|
cli (~> 1.1.0)
|
70
70
|
cuba (~> 3.0)
|
71
71
|
facter (~> 1.6.11)
|
@@ -90,4 +90,4 @@ DEPENDENCIES
|
|
90
90
|
rmagick (~> 2)
|
91
91
|
rspec (~> 2.13)
|
92
92
|
rspec-mocks (~> 2.13)
|
93
|
-
unicorn-cuba-base (~> 1.
|
93
|
+
unicorn-cuba-base (~> 1.1)
|
data/README.md
CHANGED
@@ -7,6 +7,7 @@ It is using [ImageMagick](http://www.imagemagick.org) or [GraphicsMagick](http:/
|
|
7
7
|
## Features
|
8
8
|
|
9
9
|
* thumbnailing images with different aspect ratio keeping methods
|
10
|
+
* identification of image foramt and size
|
10
11
|
* support of many input and output formats
|
11
12
|
* efficient API for generating multiple thumbnails from single input image with just one request
|
12
13
|
* many image scaling and loading performance optimizations
|
@@ -14,6 +15,16 @@ It is using [ImageMagick](http://www.imagemagick.org) or [GraphicsMagick](http:/
|
|
14
15
|
* memory limits and disk memory offloading support
|
15
16
|
* based on [Unicorn HTTP server](http://unicorn.bogomips.org) with UNIX socket communication support
|
16
17
|
|
18
|
+
## Changelog
|
19
|
+
|
20
|
+
### 1.1.0
|
21
|
+
|
22
|
+
* added identification API for image mime type and size identification
|
23
|
+
* stripping user meta data from input image further reducing output image size
|
24
|
+
* providing image size headers for input image and all generated thumbnails
|
25
|
+
* X-Input-Image-Content-Type header is now deprecated in favour of X-Input-Image-Content-Type
|
26
|
+
* not using [ImageMagick](http://www.imagemagick.org) for input image mime type resolution since it is accessing disk and behaves very inefficiently
|
27
|
+
|
17
28
|
## Installing
|
18
29
|
|
19
30
|
You will need the following system packages installed: `imagemagick`, `pkg-config` and `make`.
|
@@ -140,6 +151,18 @@ HTTP Thumbnailer will generate 3 thumbnails:
|
|
140
151
|
|
141
152
|
For detailed information about the API see [cucumber features](http://github.com/jpastuszek/httpthumbnailer/blob/master/features/thumbnails.feature).
|
142
153
|
|
154
|
+
#### Identification API
|
155
|
+
|
156
|
+
You can identify image mime type, width and height with **PUT** request to URI in format:
|
157
|
+
|
158
|
+
/identify
|
159
|
+
|
160
|
+
Server will respond with **JSON** containing **contentType**, **width** and **height** fields:
|
161
|
+
|
162
|
+
{"mimeType":"image/jpeg","width":1239,"height":1750}
|
163
|
+
|
164
|
+
For detailed information about the API see [cucumber features](http://github.com/jpastuszek/httpthumbnailer/blob/master/features/identify.feature).
|
165
|
+
|
143
166
|
### Ruby API client
|
144
167
|
|
145
168
|
To make it easier to use this server [httpthumbnailer-client](http://github.com/jpastuszek/httpthumbnailer-client) gem provides useful class.
|
@@ -197,7 +220,8 @@ total_errors: 1
|
|
197
220
|
calling: 1
|
198
221
|
writing: 0
|
199
222
|
total_images_loaded: 115
|
200
|
-
|
223
|
+
total_images_reloaded: 30
|
224
|
+
total_images_downscaled: 30
|
201
225
|
total_thumbnails_created: 147
|
202
226
|
images_loaded: 0
|
203
227
|
max_images_loaded: 3
|
@@ -223,6 +247,11 @@ $ curl 127.0.0.1:3100/stats/total_write_multipart
|
|
223
247
|
|
224
248
|
[HTTP Image Store](https://github.com/jpastuszek/httpimagestore) service is configurable image storage and processing HTTP API server that uses this service as thumbnailing backend.
|
225
249
|
|
250
|
+
## Known Issues
|
251
|
+
|
252
|
+
* When 413 error is reported due to memory limit exhaustion the disk offloading won't work any more and only requests that can fit in the memory can be processed without getting 413 - this is due to a bug in ImageMagick v6.8.6-8 (2013-08-06 6.8.6-8) or less
|
253
|
+
* Mime type generated for images may not be the official mime type assigned for given format; please let me know of any inconsistencies or send a patch to get better output in efficient way
|
254
|
+
|
226
255
|
## Contributing to HTTP Thumbnailer
|
227
256
|
|
228
257
|
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.
|
1
|
+
1.1.0
|
@@ -0,0 +1,31 @@
|
|
1
|
+
Feature: Identify API endpoint
|
2
|
+
Identify API allows for image identification.
|
3
|
+
|
4
|
+
Background:
|
5
|
+
Given httpthumbnailer server is running at http://localhost:3100/
|
6
|
+
|
7
|
+
@identify
|
8
|
+
Scenario: Identifying of image mime type
|
9
|
+
Given test.jpg file content as request body
|
10
|
+
When I do PUT request http://localhost:3100/identify
|
11
|
+
Then response status should be 200
|
12
|
+
And response content type should be application/json
|
13
|
+
And response body should be JSON encoded
|
14
|
+
And response JSON should contain key mimeType of value image/jpeg
|
15
|
+
Given test.png file content as request body
|
16
|
+
When I do PUT request http://localhost:3100/identify
|
17
|
+
Then response status should be 200
|
18
|
+
And response content type should be application/json
|
19
|
+
And response body should be JSON encoded
|
20
|
+
And response JSON should contain key mimeType of value image/png
|
21
|
+
|
22
|
+
@identify
|
23
|
+
Scenario: Identifying of image width and height
|
24
|
+
Given test-large.jpg file content as request body
|
25
|
+
When I do PUT request http://localhost:3100/identify
|
26
|
+
Then response status should be 200
|
27
|
+
And response content type should be application/json
|
28
|
+
And response body should be JSON encoded
|
29
|
+
And response JSON should contain key width of integer value 9911
|
30
|
+
And response JSON should contain key height of integer value 14000
|
31
|
+
|
@@ -16,7 +16,7 @@ When /I save response body/ do
|
|
16
16
|
@saved_response_body = @response.body
|
17
17
|
end
|
18
18
|
|
19
|
-
Then
|
19
|
+
Then /^([^ ]+) header should be (.*)/ do |header, value|
|
20
20
|
@response.header[header].should_not be_empty
|
21
21
|
@response.header[header].first.should == value
|
22
22
|
end
|
@@ -69,23 +69,15 @@ Then /response mime type should be (.*)/ do |mime_type|
|
|
69
69
|
step "response content type should be #{mime_type}"
|
70
70
|
end
|
71
71
|
|
72
|
-
Then
|
73
|
-
@response_multipart[part_no(part)].headers[
|
72
|
+
Then /^([^ ]+) part (.*) header should be (.*)/ do |part, header, value|
|
73
|
+
@response_multipart[part_no(part)].headers[header.downcase].should == value
|
74
74
|
end
|
75
75
|
|
76
|
-
Then
|
77
|
-
@response_multipart[part_no(part)].headers['content-type'].should == content_type
|
78
|
-
end
|
79
|
-
|
80
|
-
Then /(.*) part status should be (.*)/ do |part, status|
|
81
|
-
@response_multipart[part_no(part)].headers['status'].should == status
|
82
|
-
end
|
83
|
-
|
84
|
-
Then /(.*) part body should be CRLF endend lines$/ do |part, body|
|
76
|
+
Then /^([^ ]+) part body should be CRLF endend lines$/ do |part, body|
|
85
77
|
@response_multipart[part_no(part)].body.should == body.gsub("\n", "\r\n")
|
86
78
|
end
|
87
79
|
|
88
|
-
Then
|
80
|
+
Then /^([^ ]+) part body should be CRLF endend lines like$/ do |part, body|
|
89
81
|
pbody = @response_multipart[part_no(part)].body
|
90
82
|
pbody.should match(body)
|
91
83
|
end
|
@@ -141,7 +133,6 @@ And /that image should be (.*) bit image/ do |bits|
|
|
141
133
|
@image.depth.should == bits.to_i
|
142
134
|
end
|
143
135
|
|
144
|
-
|
145
136
|
And /there should be no leaked images/ do
|
146
137
|
Integer(http_client.get_content("http://localhost:3100/stats/images_loaded").strip).should == 0
|
147
138
|
end
|
@@ -150,3 +141,15 @@ And /there should be maximum (.*) images loaded during single request/ do |max|
|
|
150
141
|
Integer(http_client.get_content("http://localhost:3100/stats/max_images_loaded").strip).should <= max.to_i
|
151
142
|
end
|
152
143
|
|
144
|
+
And /response body should be JSON encoded/ do
|
145
|
+
@json = JSON.load(@response.body)
|
146
|
+
end
|
147
|
+
|
148
|
+
And /response JSON should contain key (.*) of value (.*)/ do |key, value|
|
149
|
+
@json[key].should == value
|
150
|
+
end
|
151
|
+
|
152
|
+
And /response JSON should contain key (.*) of integer value (.*)/ do |key, value|
|
153
|
+
@json[key].should == value.to_i
|
154
|
+
end
|
155
|
+
|
data/features/support/env.rb
CHANGED
data/features/thumbnail.feature
CHANGED
@@ -9,11 +9,20 @@ Feature: Generating single thumbnail with PUT request
|
|
9
9
|
@test
|
10
10
|
Scenario: Single thumbnail
|
11
11
|
Given test.jpg file content as request body
|
12
|
-
When I do PUT request http://localhost:3100/thumbnail/crop,16,
|
12
|
+
When I do PUT request http://localhost:3100/thumbnail/crop,16,24,png
|
13
13
|
Then response status should be 200
|
14
|
-
Then response should contain PNG image of size
|
14
|
+
Then response should contain PNG image of size 16x24
|
15
15
|
And that image should be 8 bit image
|
16
|
-
And
|
16
|
+
And Content-Type header should be image/png
|
17
|
+
And X-Image-Width header should be 16
|
18
|
+
And X-Image-Height header should be 24
|
19
|
+
When I do PUT request http://localhost:3100/thumbnail/crop,16,24,jpeg
|
20
|
+
Then response status should be 200
|
21
|
+
Then response should contain JPEG image of size 16x24
|
22
|
+
And that image should be 8 bit image
|
23
|
+
And Content-Type header should be image/jpeg
|
24
|
+
And X-Image-Width header should be 16
|
25
|
+
And X-Image-Height header should be 24
|
17
26
|
|
18
27
|
@transparent
|
19
28
|
Scenario: Transparent image to JPEG handling - default background color white
|
@@ -228,14 +237,22 @@ Feature: Generating single thumbnail with PUT request
|
|
228
237
|
Then saved response body will be smaller than response body
|
229
238
|
Then response mime type should be image/png
|
230
239
|
|
231
|
-
@hint
|
240
|
+
@hint @input
|
232
241
|
Scenario: Hint on input image mime type
|
233
242
|
Given test.jpg file content as request body
|
234
|
-
When I do PUT request http://localhost:3100/
|
243
|
+
When I do PUT request http://localhost:3100/thumbnail/crop,16,16,png
|
235
244
|
Then response status should be 200
|
236
|
-
And X-Input-Image-
|
245
|
+
And X-Input-Image-Mime-Type header should be image/jpeg
|
237
246
|
Given test.png file content as request body
|
238
|
-
When I do PUT request http://localhost:3100/
|
247
|
+
When I do PUT request http://localhost:3100/thumbnail/crop,16,16,png
|
248
|
+
Then response status should be 200
|
249
|
+
And X-Input-Image-Mime-Type header should be image/png
|
250
|
+
|
251
|
+
@hint @input
|
252
|
+
Scenario: Hint on input image size
|
253
|
+
Given test-large.jpg file content as request body
|
254
|
+
When I do PUT request http://localhost:3100/thumbnail/crop,16,16,png
|
239
255
|
Then response status should be 200
|
240
|
-
And X-Input-Image-
|
256
|
+
And X-Input-Image-Width header should be 9911
|
257
|
+
And X-Input-Image-Height header should be 14000
|
241
258
|
|
data/features/thumbnails.feature
CHANGED
@@ -9,12 +9,14 @@ Feature: Generating set of thumbnails with single PUT request
|
|
9
9
|
@multipart
|
10
10
|
Scenario: Single thumbnail
|
11
11
|
Given test.jpg file content as request body
|
12
|
-
When I do PUT request http://localhost:3100/thumbnails/crop,16,
|
12
|
+
When I do PUT request http://localhost:3100/thumbnails/crop,16,24,png
|
13
13
|
Then response status should be 200
|
14
14
|
And I should get multipart response
|
15
|
-
Then first part should contain PNG image of size
|
15
|
+
Then first part should contain PNG image of size 16x24
|
16
16
|
And that image should be 8 bit image
|
17
|
-
And first part
|
17
|
+
And first part Content-Type header should be image/png
|
18
|
+
And first part X-Image-Width header should be 16
|
19
|
+
And first part X-Image-Height header should be 24
|
18
20
|
|
19
21
|
@multipart
|
20
22
|
Scenario: Multiple thumbnails
|
@@ -23,11 +25,17 @@ Feature: Generating set of thumbnails with single PUT request
|
|
23
25
|
Then response status should be 200
|
24
26
|
And I should get multipart response
|
25
27
|
Then first part should contain PNG image of size 16x16
|
26
|
-
And first part
|
28
|
+
And first part Content-Type header should be image/png
|
29
|
+
And first part X-Image-Width header should be 16
|
30
|
+
And first part X-Image-Height header should be 16
|
27
31
|
Then second part should contain JPEG image of size 4x8
|
28
|
-
And second part
|
32
|
+
And second part Content-Type header should be image/jpeg
|
33
|
+
And second part X-Image-Width header should be 4
|
34
|
+
And second part X-Image-Height header should be 8
|
29
35
|
Then third part should contain JPEG image of size 16x32
|
30
|
-
And third part
|
36
|
+
And third part Content-Type header should be image/jpeg
|
37
|
+
And third part X-Image-Width header should be 16
|
38
|
+
And third part X-Image-Height header should be 32
|
31
39
|
|
32
40
|
@input_size
|
33
41
|
Scenario: Thumbnails of width or height input should have input image width or height
|
@@ -45,9 +53,9 @@ Feature: Generating set of thumbnails with single PUT request
|
|
45
53
|
When I do PUT request http://localhost:3100/thumbnails/crop,0,0,png/fit,0,0,jpeg/pad,0,0,jpeg
|
46
54
|
Then response status should be 200
|
47
55
|
And I should get multipart response
|
48
|
-
And first part
|
49
|
-
And second part
|
50
|
-
And third part
|
56
|
+
And first part Content-Type header should be text/plain
|
57
|
+
And second part Content-Type header should be text/plain
|
58
|
+
And third part Content-Type header should be text/plain
|
51
59
|
|
52
60
|
@error_handling
|
53
61
|
Scenario: Reporitng of bad thumbanil spec format - bad dimension value
|
@@ -88,12 +96,12 @@ Feature: Generating set of thumbnails with single PUT request
|
|
88
96
|
When I do PUT request http://localhost:3100/thumbnails/crop,4,4,png/blah,128,128,png
|
89
97
|
Then response status should be 200
|
90
98
|
And I should get multipart response
|
91
|
-
And second part
|
99
|
+
And second part Content-Type header should be text/plain
|
92
100
|
And second part body should be CRLF endend lines
|
93
101
|
"""
|
94
102
|
thumbnail method 'blah' is not supported
|
95
103
|
"""
|
96
|
-
And second part
|
104
|
+
And second part Status header should be 400
|
97
105
|
|
98
106
|
@error_handling
|
99
107
|
Scenario: Reporitng of image thumbnailing errors
|
@@ -102,15 +110,15 @@ Feature: Generating set of thumbnails with single PUT request
|
|
102
110
|
Then response status should be 200
|
103
111
|
And I should get multipart response
|
104
112
|
Then first part should contain PNG image of size 16x16
|
105
|
-
And first part
|
106
|
-
And second part
|
113
|
+
And first part Content-Type header should be image/png
|
114
|
+
And second part Content-Type header should be text/plain
|
107
115
|
And second part body should be CRLF endend lines
|
108
116
|
"""
|
109
117
|
at least one image dimension is zero: 0x0
|
110
118
|
"""
|
111
|
-
And second part
|
119
|
+
And second part Status header should be 400
|
112
120
|
Then third part should contain JPEG image of size 16x32
|
113
|
-
And third part
|
121
|
+
And third part Content-Type header should be image/jpeg
|
114
122
|
|
115
123
|
@resources
|
116
124
|
Scenario: Memory limits exhausted while thumbnailing
|
@@ -119,24 +127,32 @@ Feature: Generating set of thumbnails with single PUT request
|
|
119
127
|
Then response status should be 200
|
120
128
|
And I should get multipart response
|
121
129
|
Then first part should contain PNG image of size 16x16
|
122
|
-
And first part
|
123
|
-
And second part
|
130
|
+
And first part Content-Type header should be image/png
|
131
|
+
And second part Content-Type header should be text/plain
|
124
132
|
And second part body should be CRLF endend lines like
|
125
133
|
"""
|
126
134
|
image too large: cache resources exhausted
|
127
135
|
"""
|
128
|
-
And second part
|
136
|
+
And second part Status header should be 413
|
129
137
|
Then third part should contain JPEG image of size 16x32
|
130
|
-
And third part
|
138
|
+
And third part Content-Type header should be image/jpeg
|
131
139
|
|
132
|
-
@hint
|
140
|
+
@hint @input
|
133
141
|
Scenario: Hint on input image mime type
|
134
142
|
Given test.jpg file content as request body
|
135
143
|
When I do PUT request http://localhost:3100/thumbnails/crop,16,16,png
|
136
144
|
Then response status should be 200
|
137
|
-
And X-Input-Image-
|
145
|
+
And X-Input-Image-Mime-Type header should be image/jpeg
|
138
146
|
Given test.png file content as request body
|
139
147
|
When I do PUT request http://localhost:3100/thumbnails/crop,16,16,png
|
140
148
|
Then response status should be 200
|
141
|
-
And X-Input-Image-
|
149
|
+
And X-Input-Image-Mime-Type header should be image/png
|
150
|
+
|
151
|
+
@hint @input
|
152
|
+
Scenario: Hint on input image size
|
153
|
+
Given test-large.jpg file content as request body
|
154
|
+
When I do PUT request http://localhost:3100/thumbnails/crop,16,16,png
|
155
|
+
Then response status should be 200
|
156
|
+
And X-Input-Image-Width header should be 9911
|
157
|
+
And X-Input-Image-Height header should be 14000
|
142
158
|
|
data/httpthumbnailer.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "httpthumbnailer"
|
8
|
-
s.version = "1.
|
8
|
+
s.version = "1.1.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Jakub Pastuszek"]
|
12
|
-
s.date = "2013-
|
12
|
+
s.date = "2013-09-11"
|
13
13
|
s.description = "Provides HTTP API for thumbnailing images"
|
14
14
|
s.email = "jpastuszek@gmail.com"
|
15
15
|
s.executables = ["httpthumbnailer"]
|
@@ -28,6 +28,7 @@ Gem::Specification.new do |s|
|
|
28
28
|
"VERSION",
|
29
29
|
"bin/httpthumbnailer",
|
30
30
|
"features/httpthumbnailer.feature",
|
31
|
+
"features/identify.feature",
|
31
32
|
"features/step_definitions/httpthumbnailer_steps.rb",
|
32
33
|
"features/support/env.rb",
|
33
34
|
"features/support/test-large.jpg",
|
@@ -45,6 +46,8 @@ Gem::Specification.new do |s|
|
|
45
46
|
"load_test/extralarge.jpg",
|
46
47
|
"load_test/large.jpg",
|
47
48
|
"load_test/large.png",
|
49
|
+
"load_test/load_test-374846090-1.1.0-rc1-identify-only.csv",
|
50
|
+
"load_test/load_test-374846090-1.1.0-rc1.csv",
|
48
51
|
"load_test/load_test-cd9679c.csv",
|
49
52
|
"load_test/load_test-v0.3.1.csv",
|
50
53
|
"load_test/load_test.jmx",
|
@@ -73,7 +76,7 @@ Gem::Specification.new do |s|
|
|
73
76
|
s.specification_version = 3
|
74
77
|
|
75
78
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
76
|
-
s.add_runtime_dependency(%q<unicorn-cuba-base>, ["~> 1.
|
79
|
+
s.add_runtime_dependency(%q<unicorn-cuba-base>, ["~> 1.1"])
|
77
80
|
s.add_runtime_dependency(%q<rmagick>, ["~> 2"])
|
78
81
|
s.add_development_dependency(%q<rspec>, ["~> 2.13"])
|
79
82
|
s.add_development_dependency(%q<rspec-mocks>, ["~> 2.13"])
|
@@ -85,7 +88,7 @@ Gem::Specification.new do |s|
|
|
85
88
|
s.add_development_dependency(%q<multipart-parser>, ["~> 0.1.1"])
|
86
89
|
s.add_development_dependency(%q<daemon>, ["~> 1.1"])
|
87
90
|
else
|
88
|
-
s.add_dependency(%q<unicorn-cuba-base>, ["~> 1.
|
91
|
+
s.add_dependency(%q<unicorn-cuba-base>, ["~> 1.1"])
|
89
92
|
s.add_dependency(%q<rmagick>, ["~> 2"])
|
90
93
|
s.add_dependency(%q<rspec>, ["~> 2.13"])
|
91
94
|
s.add_dependency(%q<rspec-mocks>, ["~> 2.13"])
|
@@ -98,7 +101,7 @@ Gem::Specification.new do |s|
|
|
98
101
|
s.add_dependency(%q<daemon>, ["~> 1.1"])
|
99
102
|
end
|
100
103
|
else
|
101
|
-
s.add_dependency(%q<unicorn-cuba-base>, ["~> 1.
|
104
|
+
s.add_dependency(%q<unicorn-cuba-base>, ["~> 1.1"])
|
102
105
|
s.add_dependency(%q<rmagick>, ["~> 2"])
|
103
106
|
s.add_dependency(%q<rspec>, ["~> 2.13"])
|
104
107
|
s.add_dependency(%q<rspec-mocks>, ["~> 2.13"])
|
@@ -1,9 +1,5 @@
|
|
1
1
|
class ErrorReporter < Controler
|
2
2
|
self.define do
|
3
|
-
on error Rack::UnhandledRequest::UnhandledRequestError do |error|
|
4
|
-
write_error 404, error
|
5
|
-
end
|
6
|
-
|
7
3
|
on error Plugin::Thumbnailer::UnsupportedMediaTypeError do |error|
|
8
4
|
write_error 415, error
|
9
5
|
end
|
@@ -23,16 +19,7 @@ class ErrorReporter < Controler
|
|
23
19
|
write_error 400, error
|
24
20
|
end
|
25
21
|
|
26
|
-
|
27
|
-
log.error "unhandled error while processing request: #{env['REQUEST_METHOD']} #{env['SCRIPT_NAME']}[#{env["PATH_INFO"]}]", error
|
28
|
-
log.debug {
|
29
|
-
out = StringIO.new
|
30
|
-
PP::pp(env, out, 200)
|
31
|
-
"Request: \n" + out.string
|
32
|
-
}
|
33
|
-
|
34
|
-
write_error 500, error
|
35
|
-
end
|
22
|
+
run DefaultErrorReporter
|
36
23
|
end
|
37
24
|
end
|
38
25
|
|
@@ -1,6 +1,29 @@
|
|
1
1
|
require 'RMagick'
|
2
2
|
require 'forwardable'
|
3
3
|
|
4
|
+
# ImageMagick Image.mime_type is absolutely bunkers! It goes over file system to look for some strange files WTF?!
|
5
|
+
# Also it cannot be used for thumbnails since they are not yet rendered to desired format
|
6
|
+
# Here is stupid implementaiton
|
7
|
+
module MetaData
|
8
|
+
def width
|
9
|
+
@image.columns
|
10
|
+
end
|
11
|
+
|
12
|
+
def height
|
13
|
+
@image.rows
|
14
|
+
end
|
15
|
+
|
16
|
+
def mime_type
|
17
|
+
#TODO: how do I do it better?
|
18
|
+
format = @format || @image.format
|
19
|
+
mime = case format
|
20
|
+
when 'JPG' then 'jpeg'
|
21
|
+
else format.downcase
|
22
|
+
end
|
23
|
+
"image/#{mime}"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
4
27
|
module Plugin
|
5
28
|
module Thumbnailer
|
6
29
|
class UnsupportedMethodError < ArgumentError
|
@@ -105,7 +128,18 @@ module Plugin
|
|
105
128
|
end
|
106
129
|
end
|
107
130
|
|
108
|
-
def_delegators :@image, :destroy!, :destroyed
|
131
|
+
def_delegators :@image, :destroy!, :destroyed?
|
132
|
+
|
133
|
+
include MetaData
|
134
|
+
|
135
|
+
# We use base values since it might have been loaded with size hint and prescaled
|
136
|
+
def width
|
137
|
+
@image.base_columns
|
138
|
+
end
|
139
|
+
|
140
|
+
def height
|
141
|
+
@image.base_rows
|
142
|
+
end
|
109
143
|
|
110
144
|
# needs to be seen as @image when returned in replace block
|
111
145
|
def equal?(image)
|
@@ -124,24 +158,16 @@ module Plugin
|
|
124
158
|
end
|
125
159
|
|
126
160
|
def data
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
end
|
133
|
-
end
|
134
|
-
|
135
|
-
def mime_type
|
136
|
-
#@image.mime_type cannot be used since it is raw crated image
|
137
|
-
#TODO: how do I do it better?
|
138
|
-
mime = case @format
|
139
|
-
when 'JPG' then 'jpeg'
|
140
|
-
else @format.downcase
|
161
|
+
format = @format
|
162
|
+
quality = @quality
|
163
|
+
@image.to_blob do
|
164
|
+
self.format = format
|
165
|
+
self.quality = quality if quality
|
141
166
|
end
|
142
|
-
"image/#{mime}"
|
143
167
|
end
|
144
168
|
|
169
|
+
include MetaData
|
170
|
+
|
145
171
|
private
|
146
172
|
|
147
173
|
def default_quality(format)
|
@@ -162,7 +188,8 @@ module Plugin
|
|
162
188
|
extend Stats
|
163
189
|
def_stats(
|
164
190
|
:total_images_loaded,
|
165
|
-
:
|
191
|
+
:total_images_reloaded,
|
192
|
+
:total_images_downscaled,
|
166
193
|
:total_thumbnails_created,
|
167
194
|
:images_loaded,
|
168
195
|
:max_images_loaded,
|
@@ -244,8 +271,8 @@ module Plugin
|
|
244
271
|
end
|
245
272
|
|
246
273
|
def load(io, options = {})
|
247
|
-
mw = options[
|
248
|
-
mh = options[
|
274
|
+
mw = options[:max_width]
|
275
|
+
mh = options[:max_height]
|
249
276
|
if mw and mh
|
250
277
|
mw = mw.to_i
|
251
278
|
mh = mh.to_i
|
@@ -258,7 +285,7 @@ module Plugin
|
|
258
285
|
old_memory_limit = nil
|
259
286
|
borrowed_memory_limit = nil
|
260
287
|
if options.member?(:limit_memory)
|
261
|
-
borrowed_memory_limit = options[:limit_memory].borrow(options[:limit_memory].limit)
|
288
|
+
borrowed_memory_limit = options[:limit_memory].borrow(options[:limit_memory].limit, 'image magick')
|
262
289
|
old_memory_limit = set_limit(:memory, borrowed_memory_limit)
|
263
290
|
end
|
264
291
|
|
@@ -270,12 +297,13 @@ module Plugin
|
|
270
297
|
end
|
271
298
|
|
272
299
|
image = images.first
|
273
|
-
if image.columns > image.base_columns or image.rows > image.base_rows
|
300
|
+
if image.columns > image.base_columns or image.rows > image.base_rows and not options[:no_reload]
|
274
301
|
log.warn "input image got upscaled from: #{image.base_columns}x#{image.base_rows} to #{image.columns}x#{image.rows}: reloading without max size hint!"
|
275
302
|
images.each do |other|
|
276
303
|
other.destroy!
|
277
304
|
end
|
278
305
|
images = Magick::Image.from_blob(blob)
|
306
|
+
Service.stats.incr_total_images_reloaded
|
279
307
|
end
|
280
308
|
blob = nil
|
281
309
|
|
@@ -285,14 +313,22 @@ module Plugin
|
|
285
313
|
end
|
286
314
|
log.info "loaded image: #{image.inspect}"
|
287
315
|
Service.stats.incr_total_images_loaded
|
316
|
+
|
317
|
+
# clean up the image
|
288
318
|
image.strip!
|
319
|
+
image.properties do |key, value|
|
320
|
+
log.debug "deleting user propertie '#{key}'"
|
321
|
+
image[key] = nil
|
322
|
+
end
|
323
|
+
|
324
|
+
image
|
289
325
|
end.replace do |image|
|
290
|
-
if mw and mh
|
291
|
-
f = image.
|
326
|
+
if mw and mh and not options[:no_downscale]
|
327
|
+
f = image.find_downscale_factor(mw, mh)
|
292
328
|
if f > 1
|
293
|
-
image = image.
|
294
|
-
log.info "
|
295
|
-
Service.stats.
|
329
|
+
image = image.downscale(f)
|
330
|
+
log.info "downscaled image by factor of #{f}: #{image.inspect}"
|
331
|
+
Service.stats.incr_total_images_downscaled
|
296
332
|
end
|
297
333
|
end
|
298
334
|
InputImage.new(image, @processing_methods)
|
@@ -303,7 +339,7 @@ module Plugin
|
|
303
339
|
ensure
|
304
340
|
if old_memory_limit
|
305
341
|
set_limit(:memory, old_memory_limit)
|
306
|
-
options[:limit_memory].return(borrowed_memory_limit)
|
342
|
+
options[:limit_memory].return(borrowed_memory_limit, 'image magick')
|
307
343
|
end
|
308
344
|
end
|
309
345
|
end
|
@@ -380,14 +416,14 @@ class Magick::Image
|
|
380
416
|
end
|
381
417
|
end
|
382
418
|
|
383
|
-
def
|
419
|
+
def downscale(f)
|
384
420
|
sample(columns / f, rows / f)
|
385
421
|
end
|
386
422
|
|
387
|
-
def
|
423
|
+
def find_downscale_factor(max_width, max_height, factor = 1)
|
388
424
|
new_factor = factor * 2
|
389
425
|
if columns / new_factor > max_width * 2 and rows / new_factor > max_height * 2
|
390
|
-
|
426
|
+
find_downscale_factor(max_width, max_height, factor * 2)
|
391
427
|
else
|
392
428
|
factor
|
393
429
|
end
|
@@ -5,24 +5,29 @@ class Thumbnailer < Controler
|
|
5
5
|
self.plugin Plugin::Thumbnailer
|
6
6
|
|
7
7
|
self.define do
|
8
|
+
opts = {}
|
9
|
+
opts[:limit_memory] = memory_limit
|
10
|
+
|
8
11
|
on put, 'thumbnail', /(.*)/ do |spec|
|
9
12
|
spec = ThumbnailSpec.from_uri(spec)
|
10
13
|
log.info "thumbnailing image to single spec: #{spec}"
|
11
14
|
|
12
|
-
opts = {}
|
13
15
|
if settings[:optimization]
|
14
|
-
opts[
|
15
|
-
opts[
|
16
|
+
opts[:max_width] = spec.width if spec.width.is_a? Integer
|
17
|
+
opts[:max_height] = spec.height if spec.height.is_a? Integer
|
16
18
|
end
|
17
|
-
opts[:limit_memory] = memory_limit
|
18
19
|
|
19
20
|
thumbnailer.load(req.body, opts).use do |input_image|
|
20
21
|
log.info "original image loaded: #{input_image.mime_type}"
|
21
|
-
res["X-Input-Image-Content-Type"] = input_image.mime_type
|
22
22
|
|
23
23
|
log.info "generating thumbnail: #{spec}"
|
24
24
|
input_image.thumbnail(spec) do |image|
|
25
|
-
write 200, image.mime_type, image.data
|
25
|
+
write 200, image.mime_type, image.data,
|
26
|
+
"X-Image-Width" => image.width,
|
27
|
+
"X-Image-Height" => image.height,
|
28
|
+
"X-Input-Image-Mime-Type" => input_image.mime_type,
|
29
|
+
"X-Input-Image-Width" => input_image.width,
|
30
|
+
"X-Input-Image-Height" => input_image.height
|
26
31
|
end
|
27
32
|
end
|
28
33
|
end
|
@@ -31,22 +36,25 @@ class Thumbnailer < Controler
|
|
31
36
|
thumbnail_specs = ThumbnailSpecs.from_uri(specs)
|
32
37
|
log.info "thumbnailing image to multiple specs: #{thumbnail_specs.join(', ')}"
|
33
38
|
|
34
|
-
opts = {}
|
35
39
|
if settings[:optimization]
|
36
|
-
opts[
|
37
|
-
opts[
|
40
|
+
opts[:max_width] = thumbnail_specs.max_width
|
41
|
+
opts[:max_height] = thumbnail_specs.max_height
|
38
42
|
end
|
39
|
-
opts[:limit_memory] = memory_limit
|
40
43
|
|
41
44
|
thumbnailer.load(req.body, opts).use do |input_image|
|
42
45
|
log.info "original image loaded: #{input_image.mime_type}"
|
43
|
-
write_preamble 200,
|
46
|
+
write_preamble 200,
|
47
|
+
"X-Input-Image-Mime-Type" => input_image.mime_type,
|
48
|
+
"X-Input-Image-Width" => input_image.width,
|
49
|
+
"X-Input-Image-Height" => input_image.height
|
44
50
|
|
45
51
|
thumbnail_specs.each do |spec|
|
46
52
|
log.info "generating thumbnail: #{spec}"
|
47
53
|
begin
|
48
54
|
input_image.thumbnail(spec) do |image|
|
49
|
-
write_part image.mime_type, image.data
|
55
|
+
write_part image.mime_type, image.data,
|
56
|
+
"X-Image-Width" => image.width,
|
57
|
+
"X-Image-Height" => image.height
|
50
58
|
end
|
51
59
|
rescue => error
|
52
60
|
case error
|
@@ -65,6 +73,30 @@ class Thumbnailer < Controler
|
|
65
73
|
write_epilogue
|
66
74
|
end
|
67
75
|
end
|
76
|
+
|
77
|
+
on put, 'identify' do
|
78
|
+
log.info "identifying image"
|
79
|
+
# load as little of image as possible
|
80
|
+
if settings[:optimization]
|
81
|
+
opts[:max_width] = 2
|
82
|
+
opts[:max_height] = 2
|
83
|
+
end
|
84
|
+
|
85
|
+
# disable preprocessing since we don't need them here
|
86
|
+
opts[:no_reload] = true
|
87
|
+
opts[:no_downscale] = true
|
88
|
+
|
89
|
+
# RMagick of v2.13.2 does not use ImageMagick's PingBlob so we have to actually load the image
|
90
|
+
thumbnailer.load(req.body, opts).use do |input_image|
|
91
|
+
mime_type = input_image.mime_type
|
92
|
+
log.info "image loaded and identified as: #{mime_type}"
|
93
|
+
write_json 200, {
|
94
|
+
'mimeType' => mime_type,
|
95
|
+
'width' => input_image.width,
|
96
|
+
'height' => input_image.height
|
97
|
+
}
|
98
|
+
end
|
99
|
+
end
|
68
100
|
end
|
69
101
|
end
|
70
102
|
|
@@ -0,0 +1,3 @@
|
|
1
|
+
sampler_label,aggregate_report_count,average,aggregate_report_median,aggregate_report_90%_line,aggregate_report_min,aggregate_report_max,aggregate_report_error%,aggregate_report_rate,aggregate_report_bandwidth
|
2
|
+
identify,9434,98,41,317,2,2041,1.0599957600169599E-4,86.93889211430889,16.460990345050824
|
3
|
+
TOTAL,9434,98,41,317,2,2041,1.0599957600169599E-4,86.93889211430889,16.460990345050824
|
@@ -0,0 +1,11 @@
|
|
1
|
+
sampler_label,aggregate_report_count,average,aggregate_report_median,aggregate_report_90%_line,aggregate_report_min,aggregate_report_max,aggregate_report_error%,aggregate_report_rate,aggregate_report_bandwidth
|
2
|
+
crop 100x100 JPEG,9434,97,67,168,10,6023,1.0599957600169599E-4,2.034068600763908,8.133324288364369
|
3
|
+
crop 800x600 JPEG,9434,437,364,877,11,3589,1.0599957600169599E-4,2.033919060628639,158.9437935773869
|
4
|
+
crop 300x400 PNG,9434,427,388,649,9,1524,1.0599957600169599E-4,2.0337520051341786,231.20404558388668
|
5
|
+
pad 100x100 JPEG,9434,57,43,102,4,940,1.0599957600169599E-4,2.0338642493706423,6.362563138196591
|
6
|
+
fit 100x100 JPEG,9434,55,41,102,3,876,1.0599957600169599E-4,2.033791464586396,6.162153297530174
|
7
|
+
limit 100x100 JPEG,9434,56,43,103,3,572,1.0599957600169599E-4,2.0337879570175277,6.160442445959317
|
8
|
+
limit 500x500 JPEG,9434,335,294,610,3,1638,1.0599957600169599E-4,2.0336318824503,74.19337637719873
|
9
|
+
limit 1500x1500 JPEG,9434,537,158,1366,3,9732,1.0599957600169599E-4,2.033324187613275,330.89337206349103
|
10
|
+
multipart,9434,2402,1201,4951,178,54452,1.0599957600169599E-4,2.0319087644103666,819.6699318973896
|
11
|
+
TOTAL,84906,489,139,992,3,54452,1.0599957600169599E-4,18.28246151103233,1640.6136821422608
|
data/load_test/soak_test.jmx
CHANGED
@@ -30,12 +30,12 @@
|
|
30
30
|
<collectionProp name="Arguments.arguments">
|
31
31
|
<elementProp name="media_dir" elementType="Argument">
|
32
32
|
<stringProp name="Argument.name">media_dir</stringProp>
|
33
|
-
<stringProp name="Argument.value">/home/kazuya/Documents/Test Data
|
33
|
+
<stringProp name="Argument.value">/home/kazuya/Documents/Test Data</stringProp>
|
34
34
|
<stringProp name="Argument.metadata">=</stringProp>
|
35
35
|
</elementProp>
|
36
36
|
<elementProp name="list_file" elementType="Argument">
|
37
37
|
<stringProp name="Argument.name">list_file</stringProp>
|
38
|
-
<stringProp name="Argument.value">/home/kazuya/Documents/Test Data/
|
38
|
+
<stringProp name="Argument.value">/home/kazuya/Documents/Test Data/tatoos.csv</stringProp>
|
39
39
|
<stringProp name="Argument.metadata">=</stringProp>
|
40
40
|
</elementProp>
|
41
41
|
</collectionProp>
|
@@ -75,13 +75,70 @@
|
|
75
75
|
<stringProp name="delimiter">,</stringProp>
|
76
76
|
<stringProp name="fileEncoding"></stringProp>
|
77
77
|
<stringProp name="filename">${list_file}</stringProp>
|
78
|
-
<boolProp name="quotedData">
|
78
|
+
<boolProp name="quotedData">true</boolProp>
|
79
79
|
<boolProp name="recycle">false</boolProp>
|
80
80
|
<stringProp name="shareMode">All threads</stringProp>
|
81
81
|
<boolProp name="stopThread">true</boolProp>
|
82
82
|
<stringProp name="variableNames">file</stringProp>
|
83
83
|
</CSVDataSet>
|
84
84
|
<hashTree/>
|
85
|
+
<HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="identify" enabled="true">
|
86
|
+
<elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
|
87
|
+
<collectionProp name="Arguments.arguments"/>
|
88
|
+
</elementProp>
|
89
|
+
<stringProp name="HTTPSampler.domain"></stringProp>
|
90
|
+
<stringProp name="HTTPSampler.port"></stringProp>
|
91
|
+
<stringProp name="HTTPSampler.connect_timeout"></stringProp>
|
92
|
+
<stringProp name="HTTPSampler.response_timeout"></stringProp>
|
93
|
+
<stringProp name="HTTPSampler.protocol"></stringProp>
|
94
|
+
<stringProp name="HTTPSampler.contentEncoding"></stringProp>
|
95
|
+
<stringProp name="HTTPSampler.path">/identify</stringProp>
|
96
|
+
<stringProp name="HTTPSampler.method">PUT</stringProp>
|
97
|
+
<boolProp name="HTTPSampler.follow_redirects">false</boolProp>
|
98
|
+
<boolProp name="HTTPSampler.auto_redirects">false</boolProp>
|
99
|
+
<boolProp name="HTTPSampler.use_keepalive">true</boolProp>
|
100
|
+
<boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp>
|
101
|
+
<elementProp name="HTTPsampler.Files" elementType="HTTPFileArgs">
|
102
|
+
<collectionProp name="HTTPFileArgs.files">
|
103
|
+
<elementProp name="${media_dir}/${file}" elementType="HTTPFileArg">
|
104
|
+
<stringProp name="File.path">${media_dir}/${file}</stringProp>
|
105
|
+
<stringProp name="File.paramname"></stringProp>
|
106
|
+
<stringProp name="File.mimetype"></stringProp>
|
107
|
+
</elementProp>
|
108
|
+
</collectionProp>
|
109
|
+
</elementProp>
|
110
|
+
<boolProp name="HTTPSampler.monitor">false</boolProp>
|
111
|
+
<stringProp name="HTTPSampler.embedded_url_re"></stringProp>
|
112
|
+
</HTTPSamplerProxy>
|
113
|
+
<hashTree>
|
114
|
+
<ResponseAssertion guiclass="AssertionGui" testclass="ResponseAssertion" testname="200" enabled="true">
|
115
|
+
<collectionProp name="Asserion.test_strings">
|
116
|
+
<stringProp name="49586">200</stringProp>
|
117
|
+
</collectionProp>
|
118
|
+
<stringProp name="Assertion.test_field">Assertion.response_code</stringProp>
|
119
|
+
<boolProp name="Assertion.assume_success">false</boolProp>
|
120
|
+
<intProp name="Assertion.test_type">2</intProp>
|
121
|
+
</ResponseAssertion>
|
122
|
+
<hashTree/>
|
123
|
+
<ResponseAssertion guiclass="AssertionGui" testclass="ResponseAssertion" testname="Content-Type: image/jpeg" enabled="true">
|
124
|
+
<collectionProp name="Asserion.test_strings">
|
125
|
+
<stringProp name="2066544187">Content-Type: application/json</stringProp>
|
126
|
+
</collectionProp>
|
127
|
+
<stringProp name="Assertion.test_field">Assertion.response_headers</stringProp>
|
128
|
+
<boolProp name="Assertion.assume_success">false</boolProp>
|
129
|
+
<intProp name="Assertion.test_type">2</intProp>
|
130
|
+
</ResponseAssertion>
|
131
|
+
<hashTree/>
|
132
|
+
<ResponseAssertion guiclass="AssertionGui" testclass="ResponseAssertion" testname="identify JSON" enabled="true">
|
133
|
+
<collectionProp name="Asserion.test_strings">
|
134
|
+
<stringProp name="-1132805170">"mimeType":"image/</stringProp>
|
135
|
+
</collectionProp>
|
136
|
+
<stringProp name="Assertion.test_field">Assertion.response_data</stringProp>
|
137
|
+
<boolProp name="Assertion.assume_success">false</boolProp>
|
138
|
+
<intProp name="Assertion.test_type">2</intProp>
|
139
|
+
</ResponseAssertion>
|
140
|
+
<hashTree/>
|
141
|
+
</hashTree>
|
85
142
|
<HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="crop 100x100 JPEG" enabled="true">
|
86
143
|
<elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
|
87
144
|
<collectionProp name="Arguments.arguments"/>
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: httpthumbnailer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.1.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-09-11 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: unicorn-cuba-base
|
@@ -18,7 +18,7 @@ dependencies:
|
|
18
18
|
requirements:
|
19
19
|
- - ~>
|
20
20
|
- !ruby/object:Gem::Version
|
21
|
-
version: '1.
|
21
|
+
version: '1.1'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
24
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -26,7 +26,7 @@ dependencies:
|
|
26
26
|
requirements:
|
27
27
|
- - ~>
|
28
28
|
- !ruby/object:Gem::Version
|
29
|
-
version: '1.
|
29
|
+
version: '1.1'
|
30
30
|
- !ruby/object:Gem::Dependency
|
31
31
|
name: rmagick
|
32
32
|
requirement: !ruby/object:Gem::Requirement
|
@@ -206,6 +206,7 @@ files:
|
|
206
206
|
- VERSION
|
207
207
|
- bin/httpthumbnailer
|
208
208
|
- features/httpthumbnailer.feature
|
209
|
+
- features/identify.feature
|
209
210
|
- features/step_definitions/httpthumbnailer_steps.rb
|
210
211
|
- features/support/env.rb
|
211
212
|
- features/support/test-large.jpg
|
@@ -223,6 +224,8 @@ files:
|
|
223
224
|
- load_test/extralarge.jpg
|
224
225
|
- load_test/large.jpg
|
225
226
|
- load_test/large.png
|
227
|
+
- load_test/load_test-374846090-1.1.0-rc1-identify-only.csv
|
228
|
+
- load_test/load_test-374846090-1.1.0-rc1.csv
|
226
229
|
- load_test/load_test-cd9679c.csv
|
227
230
|
- load_test/load_test-v0.3.1.csv
|
228
231
|
- load_test/load_test.jmx
|
@@ -255,7 +258,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
255
258
|
version: '0'
|
256
259
|
segments:
|
257
260
|
- 0
|
258
|
-
hash: -
|
261
|
+
hash: -1021234509576024506
|
259
262
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
260
263
|
none: false
|
261
264
|
requirements:
|