Skip to content

Commit

Permalink
create an option to disable split testing
Browse files Browse the repository at this point in the history
  • Loading branch information
ilyakatz committed Apr 2, 2012
1 parent 92cafb7 commit 6d6c33e
Show file tree
Hide file tree
Showing 6 changed files with 90 additions and 31 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Expand Up @@ -2,4 +2,5 @@
.bundle
Gemfile.lock
pkg/*
*.rbc
*.rbc
.idea
4 changes: 3 additions & 1 deletion lib/split/configuration.rb
Expand Up @@ -5,13 +5,15 @@ class Configuration
attr_accessor :db_failover
attr_accessor :db_failover_on_db_error
attr_accessor :allow_multiple_experiments
attr_accessor :disable_split

def initialize
@robot_regex = /\b(Baidu|Gigabot|Googlebot|libwww-perl|lwp-trivial|msnbot|SiteUptime|Slurp|WordPress|ZIBB|ZyBorg)\b/i
@ignore_ip_addresses = []
@db_failover = false
@db_failover_on_db_error = proc{|error|} # e.g. use Rails logger here
@allow_multiple_experiments = false
@disable_split = false
end
end
end
end
74 changes: 47 additions & 27 deletions lib/split/helper.rb
@@ -1,33 +1,14 @@
module Split
module Helper
def ab_test(experiment_name, control, *alternatives)
puts 'WARNING: You should always pass the control alternative through as the second argument with any other alternatives as the third because the order of the hash is not preserved in ruby 1.8' if RUBY_VERSION.match(/1\.8/) && alternatives.length.zero?
begin
experiment = Split::Experiment.find_or_create(experiment_name, *([control] + alternatives))
if experiment.winner
ret = experiment.winner.name
else
if forced_alternative = override(experiment.name, experiment.alternative_names)
ret = forced_alternative
else
clean_old_versions(experiment)
begin_experiment(experiment) if exclude_visitor? or not_allowed_to_test?(experiment.key)

if ab_user[experiment.key]
ret = ab_user[experiment.key]
puts 'WARNING: You should always pass the control alternative through as the second argument with any other alternatives as the third because the order of the hash is not preserved in ruby 1.8' if RUBY_VERSION.match(/1\.8/) && alternatives.length.zero?
ret = if Split.configuration.disable_split
control_variable(control)
else
alternative = experiment.next_alternative
alternative.increment_participation
begin_experiment(experiment, alternative.name)
ret = alternative.name
experiment_variable(alternatives, control, experiment_name)
end
end
end
rescue Errno::ECONNREFUSED => e
raise unless Split.configuration.db_failover
Split.configuration.db_failover_on_db_error.call(e)
ret = Hash === control ? control.keys.first : control
end

if block_given?
if defined?(capture) # a block in a rails view
block = Proc.new { yield(ret) }
Expand All @@ -42,7 +23,7 @@ def ab_test(experiment_name, control, *alternatives)
end

def finished(experiment_name, options = {:reset => true})
return if exclude_visitor?
return if exclude_visitor? or Split.configuration.disable_split
return unless (experiment = Split::Experiment.find(experiment_name))
if alternative_name = ab_user[experiment.key]
alternative = Split::Alternative.new(alternative_name, experiment_name)
Expand Down Expand Up @@ -76,7 +57,7 @@ def not_allowed_to_test?(experiment_key)
end

def doing_other_tests?(experiment_key)
ab_user.keys.reject{|k| k == experiment_key}.length > 0
ab_user.keys.reject { |k| k == experiment_key }.length > 0
end

def clean_old_versions(experiment)
Expand All @@ -87,7 +68,7 @@ def clean_old_versions(experiment)

def old_versions(experiment)
if experiment.version > 0
ab_user.keys.select{|k| k.match(Regexp.new(experiment.name))}.reject{|k| k == experiment.key}
ab_user.keys.select { |k| k.match(Regexp.new(experiment.name)) }.reject { |k| k == experiment.key }
else
[]
end
Expand All @@ -104,5 +85,44 @@ def is_ignored_ip_address?
false
end
end


protected

def control_variable(control)
Hash === control ? control.keys.first : control
end

def experiment_variable(alternatives, control, experiment_name)
begin
experiment = Split::Experiment.find_or_create(experiment_name, *([control] + alternatives))
if experiment.winner
ret = experiment.winner.name
else
if forced_alternative = override(experiment.name, experiment.alternative_names)
ret = forced_alternative
else
clean_old_versions(experiment)
begin_experiment(experiment) if exclude_visitor? or not_allowed_to_test?(experiment.key)

if ab_user[experiment.key]
ret = ab_user[experiment.key]
else
alternative = experiment.next_alternative
alternative.increment_participation
begin_experiment(experiment, alternative.name)
ret = alternative.name
end
end
end
rescue Errno::ECONNREFUSED => e
raise unless Split.configuration.db_failover
Split.configuration.db_failover_on_db_error.call(e)
ret = control_variable(control)
end
ret
end

end

end
1 change: 1 addition & 0 deletions spec/configuration_spec.rb
Expand Up @@ -9,5 +9,6 @@
config.db_failover.should be_false
config.db_failover_on_db_error.should be_a Proc
config.allow_multiple_experiments.should be_false
config.disable_split.should be_false
end
end
5 changes: 4 additions & 1 deletion spec/experiment_spec.rb
Expand Up @@ -28,7 +28,7 @@

Split::Experiment.find('basket_text').start_time.should == experiment_start_time
end

it "should handle not having a start time" do
experiment_start_time = Time.parse("Sat Mar 03 14:01:03")
Time.stub(:now => experiment_start_time)
Expand Down Expand Up @@ -200,4 +200,7 @@
same_experiment.alternatives.map(&:weight).should == [1, 2]
end
end



end
34 changes: 33 additions & 1 deletion spec/helper_spec.rb
Expand Up @@ -85,7 +85,7 @@
small = Split::Alternative.new('small', 'button_size')
small.participant_count.should eql(0)
end

it "should let a user participate in many experiment with allow_multiple_experiments option" do
Split.configure do |config|
config.allow_multiple_experiments = true
Expand Down Expand Up @@ -346,6 +346,37 @@
end
end

describe "disable split testing" do

before(:each) do
Split.configure do |config|
config.disable_split = true
end
end

after(:each) do
Split.configure do |config|
config.disable_split = false
end
end

it "should not attempt to connect to redis" do

lambda {
ab_test('link_color', 'blue', 'red')
}.should_not raise_error(Errno::ECONNREFUSED)
end

it "should return control variable" do
ab_test('link_color', 'blue', 'red').should eq('blue')
lambda {
finished('link_color')
}.should_not raise_error(Errno::ECONNREFUSED)
end

end


end

context 'and db_failover config option is turned on' do
Expand Down Expand Up @@ -398,6 +429,7 @@
end
end


end

end
Expand Down

0 comments on commit 6d6c33e

Please sign in to comment.