Skip to content

Instantly share code, notes, and snippets.

@floehopper
Created January 12, 2010 13:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save floehopper/275214 to your computer and use it in GitHub Desktop.
Save floehopper/275214 to your computer and use it in GitHub Desktop.
module Yajl
class HttpStream
class HttpError < StandardError; end
def self.get; end
end
end
class Sleeper
def sleep(delay)
sleep(delay)
end
end
class HttpErrorStrategy
def initialize(sleeper = Sleeper.new)
@sleeper = sleeper
@http_error_delay = 10
end
def retry?
if @http_error_delay < 240
@http_error_delay *= 2
@sleeper.sleep(@http_error_delay)
return true
else
return false
end
end
end
require 'test/unit'
require 'mocha'
class HttpErrorStrategyTest < Test::Unit::TestCase
def setup
@sleeper = mock('sleeper')
@strategy = HttpErrorStrategy.new(@sleeper)
end
def test_should_retry_with_exponentially_increasing_delays
exponential = sequence('exponential')
@sleeper.expects(:sleep).with(20).in_sequence(exponential)
@sleeper.expects(:sleep).with(40).in_sequence(exponential)
@sleeper.expects(:sleep).with(80).in_sequence(exponential)
@sleeper.expects(:sleep).with(160).in_sequence(exponential)
@sleeper.expects(:sleep).with(320).in_sequence(exponential)
5.times { assert @strategy.retry? }
end
def test_should_stop_retrying_after_maximum_delay_is_reached
@sleeper.expects(:sleep).times(5)
5.times { @strategy.retry? }
assert !@strategy.retry?
end
end
class IOErrorStrategy
def initialize(sleeper = Sleeper.new)
@sleeper = sleeper
@io_error_delay = 0
end
def retry?
if @io_error_delay < 16
@io_error_delay += 0.25
@sleeper.sleep(@io_error_delay)
return true
else
return false
end
end
end
class IOErrorStrategyTest < Test::Unit::TestCase
def setup
@sleeper = mock('sleeper')
@strategy = IOErrorStrategy.new(@sleeper)
end
def test_should_retry_with_linearly_increasing_delays
linear = sequence('linear')
@sleeper.expects(:sleep).with(0.25).in_sequence(linear)
@sleeper.expects(:sleep).with(0.50).in_sequence(linear)
@sleeper.expects(:sleep).with(0.75).in_sequence(linear)
@sleeper.expects(:sleep).with(1.00).in_sequence(linear)
4.times { assert @strategy.retry? }
end
def test_should_stop_retrying_after_maximum_delay_is_reached
@sleeper.expects(:sleep).times(64)
65.times { @strategy.retry? }
assert !@strategy.retry?
end
end
class Statuses
def initialize(http_error_strategy = HttpErrorStrategy.new, io_error_strategy = IOErrorStrategy.new)
@http_error_strategy = http_error_strategy
@io_error_strategy = io_error_strategy
end
def get
begin
Yajl::HttpStream.get
rescue Yajl::HttpStream::HttpError => e
if @http_error_strategy.retry?
retry
else
raise e
end
rescue IOError => e
if @io_error_strategy.retry?
retry
else
raise e
end
end
end
end
class StatusesTest < Test::Unit::TestCase
def setup
@http_error_strategy = mock('http_error_strategy')
@io_error_strategy = mock('io_error_strategy')
@statuses = Statuses.new(@http_error_strategy, @io_error_strategy)
end
def test_handles_http_error_and_retries
exception = Yajl::HttpStream::HttpError.new
Yajl::HttpStream.stubs(:get).raises(exception).then.returns('json')
@http_error_strategy.stubs(:retry?).returns(true)
assert_equal 'json', @statuses.get
end
def test_handles_http_error_and_raises
exception = Yajl::HttpStream::HttpError.new
Yajl::HttpStream.stubs(:get).raises(exception).then.returns('json')
@http_error_strategy.stubs(:retry?).returns(false)
assert_raises(Yajl::HttpStream::HttpError) { @statuses.get }
end
def test_handles_io_error_and_retries
exception = IOError.new
Yajl::HttpStream.stubs(:get).raises(exception).then.returns('json')
@io_error_strategy.expects(:retry?).returns(true)
assert_equal 'json', @statuses.get
end
def test_handles_io_error_and_raises
exception = IOError.new
Yajl::HttpStream.stubs(:get).raises(exception)
@io_error_strategy.expects(:retry?).returns(false).then.returns('json')
assert_raises(IOError) { @statuses.get }
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment