diff --git a/lib/split/experiment.rb b/lib/split/experiment.rb index 4c97bead..07c4565a 100644 --- a/lib/split/experiment.rb +++ b/lib/split/experiment.rb @@ -404,7 +404,7 @@ def load_metadata_from_redis def load_alternatives_from_configuration alts = Split.configuration.experiment_for(@name)[:alternatives] - raise ArgumentError, "Experiment configuration is missing :alternatives array" unless alts + raise(Split::InvalidExperimentsFormatError, "Experiment configuration is missing :alternatives array") unless alts if alts.is_a?(Hash) alts.keys else diff --git a/lib/split/helper.rb b/lib/split/helper.rb index b8ddfc2a..a7e26bbe 100644 --- a/lib/split/helper.rb +++ b/lib/split/helper.rb @@ -5,31 +5,36 @@ module Helper module_function - def ab_test(metric_descriptor, control = nil, *alternatives) - begin - experiment = ExperimentCatalog.find_or_initialize(metric_descriptor, control, *alternatives) - alternative = if Split.configuration.enabled && !exclude_visitor? + def ab_test(metric_descriptor, control = nil, *alternatives, &block) + experiment = ExperimentCatalog.find_or_initialize(metric_descriptor, control, *alternatives) + + if !Split.configuration.enabled || exclude_visitor? || split_generically_disabled? + render_alternative(experiment, &block) + else + begin experiment.save raise(Split::InvalidExperimentsFormatError) unless (Split.configuration.experiments || {}).fetch(experiment.name.to_sym, {})[:combined_experiments].nil? - trial = Trial.new(:user => ab_user, :experiment => experiment, - :override => override_alternative(experiment.name), :exclude => exclude_visitor?, - :disabled => split_generically_disabled?) - alt = trial.choose!(self) - alt ? alt.name : nil - else - control_variable(experiment.control) - end - rescue Errno::ECONNREFUSED, Redis::BaseError, SocketError => e - raise(e) unless Split.configuration.db_failover - Split.configuration.db_failover_on_db_error.call(e) - if Split.configuration.db_failover_allow_parameter_override - alternative = override_alternative(experiment.name) if override_present?(experiment.name) - alternative = control_variable(experiment.control) if split_generically_disabled? + trial = Trial.new(user: ab_user, + experiment: experiment, + override: override_alternative(experiment.name), + exclude: exclude_visitor?, + disabled: split_generically_disabled?) + + alternative = trial.choose!(self) + render_alternative experiment, alternative.name, &block + rescue Errno::ECONNREFUSED, Redis::BaseError, SocketError => e + raise(e) unless Split.configuration.db_failover + Split.configuration.db_failover_on_db_error.call(e) + + alternative = alternative_from_db_error(experiment) + render_alternative(experiment, alternative, &block) end - ensure - alternative ||= control_variable(experiment.control) end + end + + def render_alternative(experiment, alternative = nil) + alternative ||= control_variable(experiment.control) if block_given? metadata = experiment.metadata[alternative] if experiment.metadata @@ -39,6 +44,14 @@ def ab_test(metric_descriptor, control = nil, *alternatives) end end + def alternative_from_db_error(experiment) + if Split.configuration.db_failover_allow_parameter_override + alternative = override_alternative(experiment.name) if override_present?(experiment.name) + alternative = control_variable(experiment.control) if split_generically_disabled? + end + alternative + end + def reset!(experiment) ab_user.delete(experiment.key) end diff --git a/spec/helper_spec.rb b/spec/helper_spec.rb index 95eb32ee..43099363 100755 --- a/spec/helper_spec.rb +++ b/spec/helper_spec.rb @@ -1095,7 +1095,7 @@ def should_finish_experiment(experiment_name, should_finish=true) it "fails gracefully if config is missing alternatives" do Split.configuration.experiments[:my_experiment] = { :foo => "Bar" } - expect(lambda { ab_test :my_experiment }).to raise_error(NoMethodError) + expect(lambda { ab_test :my_experiment }).to raise_error(Split::InvalidExperimentsFormatError) end end