logstash/spec/util/retryable_spec.rb
2015-11-05 21:05:53 +00:00

139 lines
No EOL
4.1 KiB
Ruby

require "logstash/util/retryable"
describe LogStash::Retryable do
class C
include LogStash::Retryable
end
class E < StandardError; end;
class F < StandardError; end;
subject {C.new}
context "with default fixed 1 second retry sleep" do
it "should execute once" do
expect(subject).to receive(:sleep).never
expect(subject.retryable(:rescue => nil){|i| expect(i).to eq(0); "foo"}).to eq("foo")
end
it "should not retry on non rescued exceptions" do
i = 0
expect(subject).to receive(:sleep).never
expect{subject.retryable(:rescue => E){i += 1; raise F}}.to raise_error(F)
expect(i).to eq(1)
end
it "should execute once and retry once by default" do
i = 0
expect(subject).to receive(:sleep).once.with(1)
expect{subject.retryable{i += 1; raise E}}.to raise_error(E)
expect(i).to eq(2)
end
it "should retry on rescued exceptions" do
i = 0
expect(subject).to receive(:sleep).once.with(1)
expect{subject.retryable(:rescue => E){i += 1; raise E}}.to raise_error(E)
expect(i).to eq(2)
end
it "should retry indefinitely" do
i = 0
expect(subject).to receive(:sleep).exactly(50).times.with(1)
expect{subject.retryable(:tries => 0, :rescue => E){i += 1; raise i <= 50 ? E : F}}.to raise_error(F)
end
it "should execute once and retry once by default and execute on_retry callback" do
i = 0
callback_values = []
callback = lambda do |retry_count, e|
callback_values << [retry_count, e]
end
expect(subject).to receive(:sleep).once.with(1)
expect do
subject.retryable(:on_retry => callback){i += 1; raise E}
end.to raise_error
expect(i).to eq(2)
expect(callback_values.size).to eq(1)
expect(callback_values[0][0]).to eq(1)
expect(callback_values[0][1]).to be_a(E)
end
it "should execute once and retry n times" do
i = 0
n = 3
expect(subject).to receive(:sleep).exactly(n).times.with(1)
expect{subject.retryable(:tries => n){i += 1; raise E}}.to raise_error(E)
expect(i).to eq(n + 1)
end
it "should execute once and retry n times and execute on_retry callback" do
i = 0
n = 3
callback_values = []
callback = lambda do |retry_count, e|
callback_values << [retry_count, e]
end
expect(subject).to receive(:sleep).exactly(n).times.with(1)
expect do
subject.retryable(:tries => n, :on_retry => callback){i += 1; raise E}
end.to raise_error
expect(i).to eq(n + 1)
expect(callback_values.size).to eq(n)
n.times.each do |j|
expect(callback_values[j].first).to eq(j + 1)
expect(callback_values[j].last).to be_a(E)
end
end
end
context "with exponential backoff" do
it "should execute once and retry once with base sleep by default" do
expect(subject).to receive(:sleep).once.with(2)
expect do
subject.retryable(:base_sleep => 2, :max_sleep => 10){raise E}
end.to raise_error(E)
end
it "should execute once and retry n times with exponential backoff sleep" do
n = 3
s = 0.5
n.times.each do |i|
expect(subject).to receive(:sleep).once.with(s * (2 ** i)).ordered
end
expect do
subject.retryable(:tries => n, :base_sleep => s, :max_sleep => 100){raise E}
end.to raise_error(E)
end
it "should execute once and retry n times with exponential backoff sleep capping at max_sleep" do
n = 20
base_sleep = 0.1
max_sleep = 1
expect(subject).to receive(:sleep).once.with(0.1).ordered
expect(subject).to receive(:sleep).once.with(0.2).ordered
expect(subject).to receive(:sleep).once.with(0.4).ordered
expect(subject).to receive(:sleep).once.with(0.8).ordered
(n - 4).times.each do |i|
expect(subject).to receive(:sleep).once.with(1).ordered
end
expect do
subject.retryable(:tries => n, :base_sleep => base_sleep, :max_sleep => max_sleep){raise E}
end.to raise_error(E)
end
end
end