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.
Files changed (48) hide show
  1. data/Gemfile +10 -12
  2. data/Gemfile.lock +57 -55
  3. data/README.md +829 -0
  4. data/VERSION +1 -1
  5. data/bin/httpimagestore +114 -180
  6. data/features/cache-control.feature +26 -90
  7. data/features/compatibility.feature +129 -0
  8. data/features/error-reporting.feature +207 -0
  9. data/features/health-check.feature +30 -0
  10. data/features/s3-store-and-thumbnail.feature +65 -0
  11. data/features/step_definitions/httpimagestore_steps.rb +66 -26
  12. data/features/support/env.rb +32 -5
  13. data/features/support/test.empty +0 -0
  14. data/httpimagestore.gemspec +60 -47
  15. data/lib/httpimagestore/aws_sdk_regions_hack.rb +23 -0
  16. data/lib/httpimagestore/configuration/file.rb +120 -0
  17. data/lib/httpimagestore/configuration/handler.rb +239 -0
  18. data/lib/httpimagestore/configuration/output.rb +119 -0
  19. data/lib/httpimagestore/configuration/path.rb +77 -0
  20. data/lib/httpimagestore/configuration/s3.rb +194 -0
  21. data/lib/httpimagestore/configuration/thumbnailer.rb +244 -0
  22. data/lib/httpimagestore/configuration.rb +126 -29
  23. data/lib/httpimagestore/error_reporter.rb +36 -0
  24. data/lib/httpimagestore/ruby_string_template.rb +26 -0
  25. data/load_test/load_test.1k.23a022f6e.m1.small-comp.csv +3 -0
  26. data/load_test/load_test.1k.ec9bde794.m1.small.csv +4 -0
  27. data/load_test/load_test.jmx +344 -0
  28. data/load_test/thumbnail_specs.csv +11 -0
  29. data/spec/configuration_file_spec.rb +309 -0
  30. data/spec/configuration_handler_spec.rb +124 -0
  31. data/spec/configuration_output_spec.rb +338 -0
  32. data/spec/configuration_path_spec.rb +92 -0
  33. data/spec/configuration_s3_spec.rb +571 -0
  34. data/spec/configuration_spec.rb +80 -105
  35. data/spec/configuration_thumbnailer_spec.rb +417 -0
  36. data/spec/ruby_string_template_spec.rb +43 -0
  37. data/spec/spec_helper.rb +61 -0
  38. data/spec/support/compute.jpg +0 -0
  39. data/spec/support/cuba_response_env.rb +40 -0
  40. data/spec/support/full.cfg +49 -0
  41. metadata +138 -84
  42. data/README.rdoc +0 -23
  43. data/features/httpimagestore.feature +0 -167
  44. data/lib/httpimagestore/image_path.rb +0 -54
  45. data/lib/httpimagestore/s3_service.rb +0 -37
  46. data/lib/httpimagestore/thumbnail_class.rb +0 -13
  47. data/spec/image_path_spec.rb +0 -72
  48. 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
- cfile = Tempfile.new('httpimagestore.conf')
7
- cfile.write(config)
8
- cfile.close
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.path}",
16
+ "bundle exec #{script('httpimagestore')} -f -d -l #{log} -w 1 #{(@httpimagestore_args ||= []).join(' ')} #{cfile.to_s}",
13
17
  '/tmp/httpimagestore.pid',
14
- support_dir + 'server.log',
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
- support_dir + 'thumbniler.log',
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 /(.*) file content as request body/ do |file|
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 /(.*) S3 bucket with key (.*) and secret (.*)/ do |bucket, key_id, key_secret|
46
- @bucket = S3::Service.new(:access_key_id => key_id, :secret_access_key => key_secret).buckets.find(bucket)
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.find(path).destroy rescue S3::Error::NoSuchKey
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 bucket will not contain (.*)/ do |path|
105
- begin
106
- @bucket.objects.find(path)
107
- true.should eq(false, "object #{path} found in bucket")
108
- rescue S3::Error::NoSuchKey
109
- true.should == true
110
- end
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
 
@@ -17,7 +17,19 @@ require "open3"
17
17
  require "thread"
18
18
  require 'tempfile'
19
19
  require 'RMagick'
20
- require 's3'
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
- HTTPClient.new.get_content(URI.encode(url))
57
+ http_client.get_content(URI.encode(url))
40
58
  end
41
59
 
42
60
  def get_headers(url)
43
- HTTPClient.new.get(URI.encode(url)).headers
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
- stop_server(pid_file)
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
- Process.wait
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