# File lib/abingo.rb, line 90
  def test(test_name, alternatives, options = {})

    short_circuit = Abingo.cache.read("Abingo::Experiment::short_circuit(#{test_name})".gsub(" ", "_"))
    unless short_circuit.nil?
      return short_circuit  #Test has been stopped, pick canonical alternative.
    end

    unless Abingo::Experiment.exists?(test_name)
      lock_key = "Abingo::lock_for_creation(#{test_name.gsub(" ", "_")})"
      lock_id  = SecureRandom.hex
      #this prevents (most) repeated creations of experiments in high concurrency environments.
      if Abingo.cache.exist?(lock_key)
        wait_for_lock_release(lock_key)
      else
        Abingo.cache.write(lock_key, lock_id, :expires_in => 5.seconds)
        sleep(0.1)
        if Abingo.cache.read(lock_key) == lock_id
          conversion_name = options[:conversion] || options[:conversion_name]
          Abingo::Experiment.start_experiment!(test_name, Abingo.parse_alternatives(alternatives), conversion_name)
        else
          wait_for_lock_release(lock_key)
        end
      end
      Abingo.cache.delete(lock_key)
    end

    choice = self.find_alternative_for_user(test_name, alternatives)
    participating_tests = Abingo.cache.read("Abingo::participating_tests::#{self.identity}") || []

    #Set this user to participate in this experiment, and increment participants count.
    if options[:multiple_participation] || !(participating_tests.include?(test_name))
      unless participating_tests.include?(test_name)
        participating_tests = participating_tests + [test_name]
        if self.expires_in
          Abingo.cache.write("Abingo::participating_tests::#{self.identity}", participating_tests, {:expires_in => self.expires_in})
        else
          Abingo.cache.write("Abingo::participating_tests::#{self.identity}", participating_tests)
        end
      end
      #If we're only counting known humans, then postpone scoring participation until after we know the user is human.
      if (!@@options[:count_humans_only] || self.is_human?)
        Abingo::Alternative.score_participation(test_name, choice)
      end
    end

    if block_given?
      yield(choice)
    else
      choice
    end
  end