spec/outputs/http_spec.rb in logstash-output-http-3.1.1 vs spec/outputs/http_spec.rb in logstash-output-http-4.0.0

- old
+ new

@@ -1,7 +1,8 @@ require "logstash/devutils/rspec/spec_helper" require "logstash/outputs/http" +require "logstash/codecs/plain" require "thread" require "sinatra" PORT = rand(65535-1024) + 1025 @@ -35,123 +36,110 @@ end def self.last_request @last_request end + + def self.retry_fail_count=(count) + @retry_fail_count = count + end + + def self.retry_fail_count() + @retry_fail_count + end multiroute(%w(get post put patch delete), "/good") do self.class.last_request = request [200, "YUP"] end multiroute(%w(get post put patch delete), "/bad") do self.class.last_request = request - [500, "YUP"] + [400, "YUP"] end + + multiroute(%w(get post put patch delete), "/retry") do + self.class.last_request = request + + if self.class.retry_fail_count > 0 + self.class.retry_fail_count -= 1 + [429, "Will succeed in #{self.class.retry_fail_count}"] + else + [200, "Done Retrying"] + end + end end RSpec.configure do |config| #http://stackoverflow.com/questions/6557079/start-and-call-ruby-http-server-in-the-same-script def sinatra_run_wait(app, opts) queue = Queue.new - Thread.new(queue) do |queue| - begin - app.run!(opts) do |server| - queue.push("started") + t = java.lang.Thread.new( + proc do + begin + app.run!(opts) do |server| + queue.push("started") + end + rescue => e + puts "Error in webserver thread #{e}" + # ignore end - rescue - # ignore end - end - + ) + t.daemon = true + t.start queue.pop # blocks until the run! callback runs end config.before(:suite) do sinatra_run_wait(TestApp, :port => PORT, :server => 'webrick') + puts "Test webserver on port #{PORT}" end end describe LogStash::Outputs::Http do # Wait for the async request to finish in this spinlock # Requires pool_max to be 1 - def wait_for_request - loop do - sleep(0.1) - break if subject.request_tokens.size > 0 - end - end - let(:port) { PORT } let(:event) { LogStash::Event.new("message" => "hi") } let(:url) { "http://localhost:#{port}/good" } let(:method) { "post" } - describe "when num requests > token count" do - let(:pool_max) { 10 } - let(:num_reqs) { pool_max / 2 } + shared_examples("verb behavior") do |method| + let(:verb_behavior_config) { {"url" => url, "http_method" => method, "pool_max" => 1} } + subject { LogStash::Outputs::Http.new(verb_behavior_config) } + + let(:expected_method) { method.clone.to_sym } let(:client) { subject.client } let(:client_proxy) { subject.client.background } - subject { - LogStash::Outputs::Http.new("url" => url, - "http_method" => method, - "pool_max" => pool_max) - } - before do allow(client).to receive(:background).and_return(client_proxy) subject.register - end - - after do - subject.close - end - - it "should receive all the requests" do - expect(client_proxy).to receive(:send). - with(method.to_sym, url, anything). - exactly(num_reqs).times. - and_call_original - - num_reqs.times {|t| subject.receive(event)} - end - end - - shared_examples("verb behavior") do |method, async_type| - subject { LogStash::Outputs::Http.new("url" => url, "http_method" => method, "pool_max" => 1) } - - let(:expected_method) { method.clone.to_sym } - let(:client) { subject.client } - let(:client_proxy) { subject.client.send(async_type) } - - before do - allow(client).to receive(async_type).and_return(client_proxy) - subject.register allow(client_proxy).to receive(:send). with(expected_method, url, anything). and_call_original allow(subject).to receive(:log_failure).with(any_args) end context "performing a get" do describe "invoking the request" do before do - subject.receive(event, async_type) + subject.multi_receive([event]) end it "should execute the request" do expect(client_proxy).to have_received(:send). with(expected_method, url, anything) end end context "with passing requests" do before do - subject.receive(event) + subject.multi_receive([event]) end it "should not log a failure" do expect(subject).not_to have_received(:log_failure).with(any_args) end @@ -159,43 +147,64 @@ context "with failing requests" do let(:url) { "http://localhost:#{port}/bad"} before do - subject.receive(event, async_type) - - if async_type == :background - wait_for_request - else - subject.client.execute! - end + subject.multi_receive([event]) end it "should log a failure" do expect(subject).to have_received(:log_failure).with(any_args) end end + + context "with ignorable failing requests" do + let(:url) { "http://localhost:#{port}/bad"} + let(:verb_behavior_config) { super.merge("ignorable_codes" => [400]) } + + before do + subject.multi_receive([event]) + end + + it "should log a failure" do + expect(subject).not_to have_received(:log_failure).with(any_args) + end + end + + context "with retryable failing requests" do + let(:url) { "http://localhost:#{port}/retry"} + + before do + TestApp.retry_fail_count=2 + allow(subject).to receive(:send_event).and_call_original + subject.multi_receive([event]) + end + + it "should log a failure 2 times" do + expect(subject).to have_received(:log_failure).with(any_args).twice + end + + it "should make three total requests" do + expect(subject).to have_received(:send_event).exactly(3).times + end + end + end end LogStash::Outputs::Http::VALID_METHODS.each do |method| - context "when using '#{method}' via :background" do - include_examples("verb behavior", method, :background) + context "when using '#{method}'" do + include_examples("verb behavior", method) end - - context "when using '#{method}' via :parallel" do - include_examples("verb behavior", method, :parallel) - end end shared_examples("a received event") do before do TestApp.last_request = nil end before do - subject.receive(event) - wait_for_request + subject.multi_receive([event]) end let(:last_request) { TestApp.last_request } let(:body) { last_request.body.read } let(:content_type) { last_request.env["CONTENT_TYPE"] }