Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding environments #10

Merged
merged 5 commits into from
Apr 25, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,38 @@ Because it calls `include?`, this also works for regexes:

### Configuration

#### Environments

The easiest way to coordinate sets of Pester options across an app is via environments--these are basically option hashes configured in Pester by name:

Pester.configure do |c|
c.environments[:aws] = { max_attempts: 3, delay_interval: 5 }
c.environments[:internal] = { max_attempts: 2, delay_interval: 0 }
end

This will create two environments, `aws` and `internal`, which allow you to employ different backoff strategies, depending on the usage context. These are employed simply by calling `Pester.environment_name.retry` (where `retry` can also be another helper method):

def aws_action
Pester.aws.retry do
aws_call
end
end

def action
Pester.internal.retry do
some_other_call
end
end

Environments can also be merged with retry helper methods:

Pester.aws.retry # acts different from
Pester.aws.retry_with_exponential_backoff

where the helper method's `Behavior` will take precedence.

#### Logging

Pester will write retry and exhaustion information into your logs, by default using a ruby `Logger` to standard out. This can be configured either per-call, or one time per application in your initializer via `Pester#configure`. The following will suppress all logs by using a class that simply does nothing with log data, as found in `spec/`:

Pester.configure do |c|
Expand Down
22 changes: 20 additions & 2 deletions lib/pester.rb
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
require 'pester/behaviors'
require 'pester/behaviors/sleep'
require 'pester/environment'
require 'pester/config'
require 'pester/version'

module Pester
def self.configure(&block)
Config.configure(&block)
unless Config.environments.nil?
self.environments = Hash[Config.environments.select { |_, e| e.is_a?(Hash)}.map { |k, e| [k.to_sym, Environment.new(e)] }]
end
end

def self.retry(options = {}, &block)
Expand Down Expand Up @@ -75,11 +79,25 @@ def self.retry_action(opts = {}, &block)
nil
end

def respond_to?(method_sym)
super || Config.environments.has_key?(method_sym)
end

def method_missing(method_sym)
if Config.environments.has_key?(method_sym)
Config.environments[method_sym]
end
end

class << self
attr_accessor :environments
end

private

def self.should_retry?(e, opts = {})
retry_error_classes = opts[:retry_error_classes]
retry_error_messages = opts[:retry_error_messages]
retry_error_classes = opts[:retry_error_classes]
retry_error_messages = opts[:retry_error_messages]
reraise_error_classes = opts[:reraise_error_classes]

if retry_error_classes
Expand Down
5 changes: 5 additions & 0 deletions lib/pester/config.rb
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
module Pester
class Config
class << self
attr_reader :environments
attr_writer :logger

def configure
yield self
end

def environments
@environments ||= {}
end

def logger
require 'logger' unless defined? Logger
@logger ||= Logger.new(STDOUT)
Expand Down
17 changes: 17 additions & 0 deletions lib/pester/environment.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
module Pester
class Environment
attr_accessor :options

def initialize(opts)
@options = opts
end

def method_missing(name, *args, &block)
if name.to_s.start_with?('retry') && args.empty?
Pester.send(name, @options, &block)
else
super
end
end
end
end
45 changes: 45 additions & 0 deletions spec/environment_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
require 'spec_helper'

describe Pester::Environment do
let(:options) { {} }
let!(:environment) { Pester::Environment.new(options) }

describe 'Delegation to Pester' do
context 'for retry-prefixed methods' do
context 'which are supported' do
let(:pester) { class_double("Pester").as_stubbed_const }

context 'without options' do
it 'calls Pester#retry without options' do
expect(pester).to receive(:send).with(:retry, {})
environment.retry { }
end
end
context 'with options' do
let(:options) { { test_opt: 1234 } }

it 'calls Pester#retry with the given options' do
expect(pester).to receive(:send).with(:retry, options)
environment.retry { }
end
end
end

context 'which do not exist' do
let(:options) { { test_opt: 1234 } }

it 'lets Pester raise NoMethodError' do
expect { environment.retry_does_not_exist { } }.to raise_error(NoMethodError)
end
end
end

context 'for non-retry-prefixed methods' do
let(:pester) { class_double("Pester").as_stubbed_const }

it 'raises NoMethodError' do
expect { environment.something_else { } }.to raise_error(NoMethodError)
end
end
end
end
40 changes: 38 additions & 2 deletions spec/pester_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ class UnmatchedError < RuntimeError; end
end
end

describe 'retry_action' do
describe '#retry_action' do
let(:intended_result) { 1000 }
let(:action) { failer.fail(UnmatchedError, 'Dying') }
let(:null_logger) { NullLogger.new }
Expand Down Expand Up @@ -258,7 +258,43 @@ class UnmatchedError < RuntimeError; end
end
end

describe 'logger' do
describe '#environments' do
before { Pester.environments = {} }

context 'when a non-hash environment is configured' do
it 'does not add it to the Pester environment list' do
Pester.configure do |config|
config.environments[:abc] = 1234
end

expect(Pester.environments.count).to eq(0)
end
end

context 'when a non-hash environment is configured' do
let(:environment_name) { :abc }
let(:options) { { option: 1234 } }

it 'adds it to the Pester environment list' do
Pester.configure do |config|
config.environments[environment_name] = options
end

expect(Pester.environments.count).to eq(1)
end

it 'contains an Environment with the appropriate options' do
Pester.configure do |config|
config.environments[environment_name] = options
end

expect(Pester.environments[environment_name].class).to eq(Pester::Environment)
expect(Pester.environments[environment_name].options).to eq(options)
end
end
end

describe '#logger' do
context 'when not otherwise configured' do
it 'defaults to the ruby logger' do
Pester.configure do |config|
Expand Down