Skip to content

Commit 4044008

Browse files
committed
Adding tests for HTTP_COMPRESSION => true
We are using a simple rack handling defined in the Sinatra chains that will automatically uncompressed any request with `CONTENT_ENCODING` set to gzip. Fixes logstash-plugins#72
1 parent 2dd58a2 commit 4044008

File tree

2 files changed

+70
-18
lines changed

2 files changed

+70
-18
lines changed

spec/outputs/http_spec.rb

Lines changed: 32 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
require "logstash/codecs/plain"
44
require "thread"
55
require "sinatra"
6+
require_relative "../supports/compressed_requests"
67

78
PORT = rand(65535-1024) + 1025
89

@@ -16,8 +17,10 @@ class LogStash::Outputs::Http
1617
#
1718
# == Sinatra (v1.4.6) has taken the stage on 51572 for development with backup from WEBrick
1819
# == Sinatra has ended his set (crowd applauds)
19-
20+
#
2021
class TestApp < Sinatra::Base
22+
# on the fly uncompress gzip content
23+
use CompressedRequests
2124

2225
# disable WEBrick logging
2326
def self.server_settings
@@ -38,11 +41,11 @@ def self.last_request=(request)
3841
def self.last_request
3942
@last_request
4043
end
41-
44+
4245
def self.retry_fail_count=(count)
4346
@retry_fail_count = count
4447
end
45-
48+
4649
def self.retry_fail_count()
4750
@retry_fail_count
4851
end
@@ -56,10 +59,10 @@ def self.retry_fail_count()
5659
self.class.last_request = request
5760
[400, "YUP"]
5861
end
59-
62+
6063
multiroute(%w(get post put patch delete), "/retry") do
6164
self.class.last_request = request
62-
65+
6366
if self.class.retry_fail_count > 0
6467
self.class.retry_fail_count -= 1
6568
[429, "Will succeed in #{self.class.retry_fail_count}"]
@@ -80,7 +83,7 @@ def sinatra_run_wait(app, opts)
8083
app.run!(opts) do |server|
8184
queue.push("started")
8285
end
83-
rescue => e
86+
rescue => e
8487
puts "Error in webserver thread #{e}"
8588
# ignore
8689
end
@@ -158,7 +161,7 @@ def sinatra_run_wait(app, opts)
158161
expect(subject).to have_received(:log_failure).with(any_args)
159162
end
160163
end
161-
164+
162165
context "with ignorable failing requests" do
163166
let(:url) { "http://localhost:#{port}/bad"}
164167
let(:verb_behavior_config) { super.merge("ignorable_codes" => [400]) }
@@ -171,7 +174,7 @@ def sinatra_run_wait(app, opts)
171174
expect(subject).not_to have_received(:log_failure).with(any_args)
172175
end
173176
end
174-
177+
175178
context "with retryable failing requests" do
176179
let(:url) { "http://localhost:#{port}/retry"}
177180

@@ -184,12 +187,12 @@ def sinatra_run_wait(app, opts)
184187
it "should log a failure 2 times" do
185188
expect(subject).to have_received(:log_failure).with(any_args).twice
186189
end
187-
190+
188191
it "should make three total requests" do
189192
expect(subject).to have_received(:send_event).exactly(3).times
190193
end
191-
end
192-
194+
end
195+
193196
end
194197
end
195198

@@ -225,7 +228,8 @@ def sinatra_run_wait(app, opts)
225228
end
226229
end
227230

228-
describe "integration tests" do
231+
shared_examples "integration tests" do
232+
let(:base_config) { {} }
229233
let(:url) { "http://localhost:#{port}/good" }
230234
let(:event) {
231235
LogStash::Event.new("foo" => "bar", "baz" => "bot", "user" => "McBest")
@@ -239,7 +243,7 @@ def sinatra_run_wait(app, opts)
239243

240244
describe "sending with the default (JSON) config" do
241245
let(:config) {
242-
{"url" => url, "http_method" => "post", "pool_max" => 1}
246+
base_config.merge({"url" => url, "http_method" => "post", "pool_max" => 1})
243247
}
244248
let(:expected_body) { LogStash::Json.dump(event) }
245249
let(:expected_content_type) { "application/json" }
@@ -249,7 +253,7 @@ def sinatra_run_wait(app, opts)
249253

250254
describe "sending the event as a form" do
251255
let(:config) {
252-
{"url" => url, "http_method" => "post", "pool_max" => 1, "format" => "form"}
256+
base_config.merge({"url" => url, "http_method" => "post", "pool_max" => 1, "format" => "form"})
253257
}
254258
let(:expected_body) { subject.send(:encode, event.to_hash) }
255259
let(:expected_content_type) { "application/x-www-form-urlencoded" }
@@ -259,7 +263,7 @@ def sinatra_run_wait(app, opts)
259263

260264
describe "sending the event as a message" do
261265
let(:config) {
262-
{"url" => url, "http_method" => "post", "pool_max" => 1, "format" => "message", "message" => "%{foo} AND %{baz}"}
266+
base_config.merge({"url" => url, "http_method" => "post", "pool_max" => 1, "format" => "message", "message" => "%{foo} AND %{baz}"})
263267
}
264268
let(:expected_body) { "#{event.get("foo")} AND #{event.get("baz")}" }
265269
let(:expected_content_type) { "text/plain" }
@@ -269,7 +273,7 @@ def sinatra_run_wait(app, opts)
269273

270274
describe "sending a mapped event" do
271275
let(:config) {
272-
{"url" => url, "http_method" => "post", "pool_max" => 1, "mapping" => {"blah" => "X %{foo}"} }
276+
base_config.merge({"url" => url, "http_method" => "post", "pool_max" => 1, "mapping" => {"blah" => "X %{foo}"} })
273277
}
274278
let(:expected_body) { LogStash::Json.dump("blah" => "X #{event.get("foo")}") }
275279
let(:expected_content_type) { "application/json" }
@@ -279,7 +283,7 @@ def sinatra_run_wait(app, opts)
279283

280284
describe "sending a mapped, nested event" do
281285
let(:config) {
282-
{
286+
base_config.merge({
283287
"url" => url,
284288
"http_method" => "post",
285289
"pool_max" => 1,
@@ -292,7 +296,7 @@ def sinatra_run_wait(app, opts)
292296
"user" => "Z %{user}"
293297
}]
294298
}
295-
}
299+
})
296300
}
297301
let(:expected_body) {
298302
LogStash::Json.dump({
@@ -310,4 +314,14 @@ def sinatra_run_wait(app, opts)
310314
include_examples("a received event")
311315
end
312316
end
317+
318+
describe "integration test without gzip compression" do
319+
include_examples("integration tests")
320+
end
321+
322+
describe "integration test with gzip compression" do
323+
include_examples("integration tests") do
324+
let(:base_config) { { "http_compression" => true } }
325+
end
326+
end
313327
end
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# encoding: utf-8
2+
#
3+
# based on relistan's rack handler
4+
# out of the box rack only gives use the rack deflater handler to return compressed
5+
# response, this gist offer the inverse and should work on all rack based app like sinatra or rails.
6+
#
7+
# original source: https://gist.github.com/relistan/2109707
8+
require "zlib"
9+
10+
class CompressedRequests
11+
def initialize(app)
12+
@app = app
13+
end
14+
15+
def encoding_handled?(env)
16+
['gzip', 'deflate'].include? env['HTTP_CONTENT_ENCODING']
17+
end
18+
19+
def call(env)
20+
if encoding_handled?(env)
21+
extracted = decode(env['rack.input'], env['HTTP_CONTENT_ENCODING'])
22+
23+
env.delete('HTTP_CONTENT_ENCODING')
24+
env['CONTENT_LENGTH'] = extracted.bytesize
25+
env['rack.input'] = StringIO.new(extracted)
26+
end
27+
28+
status, headers, response = @app.call(env)
29+
return [status, headers, response]
30+
end
31+
32+
def decode(input, content_encoding)
33+
case content_encoding
34+
when 'gzip' then Zlib::GzipReader.new(input).read
35+
when 'deflate' then Zlib::Inflate.inflate(input.read)
36+
end
37+
end
38+
end

0 commit comments

Comments
 (0)