Welcome to mirror list, hosted at ThFree Co, Russian Federation.

experimentation.rb « gitlab « lib - gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 895755376ee40bfb48a20eb1859d0c9ddada8b7d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# frozen_string_literal: true

# == Experimentation
#
# Utility module used for A/B testing experimental features. Define your experiments in the `EXPERIMENTS` constant.
# The feature_toggle and environment keys are optional. If the feature_toggle is not set, a feature with the name of
# the experiment will be checked, with a default value of true. The enabled_ratio is required and should be
# the ratio for the number of users for which this experiment is enabled. For example: a ratio of 0.1 will
# enable the experiment for 10% of the users (determined by the `experimentation_subject_index`).
#
module Gitlab
  module Experimentation
    EXPERIMENTS = {
      signup_flow: {
        feature_toggle: :experimental_separate_sign_up_flow,
        environment: ::Gitlab.dev_env_or_com?,
        enabled_ratio: 0.1
      }
    }.freeze

    # Controller concern that checks if an experimentation_subject_id cookie is present and sets it if absent.
    # Used for A/B testing of experimental features. Exposes the `experiment_enabled?(experiment_name)` method
    # to controllers and views.
    #
    module ControllerConcern
      extend ActiveSupport::Concern

      included do
        before_action :set_experimentation_subject_id_cookie
        helper_method :experiment_enabled?
      end

      def set_experimentation_subject_id_cookie
        return if cookies[:experimentation_subject_id].present?

        cookies.permanent.signed[:experimentation_subject_id] = {
          value: SecureRandom.uuid,
          domain: :all,
          secure: ::Gitlab.config.gitlab.https
        }
      end

      def experiment_enabled?(experiment_key)
        Experimentation.enabled?(experiment_key, experimentation_subject_index)
      end

      private

      def experimentation_subject_index
        experimentation_subject_id = cookies.signed[:experimentation_subject_id]
        return if experimentation_subject_id.blank?

        experimentation_subject_id.delete('-').hex % 100
      end
    end

    class << self
      def experiment(key)
        Experiment.new(EXPERIMENTS[key].merge(key: key))
      end

      def enabled?(experiment_key, experimentation_subject_index)
        return false unless EXPERIMENTS.key?(experiment_key)

        experiment = experiment(experiment_key)

        experiment.feature_toggle_enabled? &&
          experiment.enabled_for_environment? &&
          experiment.enabled_for_experimentation_subject?(experimentation_subject_index)
      end
    end

    Experiment = Struct.new(:key, :feature_toggle, :environment, :enabled_ratio, keyword_init: true) do
      def feature_toggle_enabled?
        return Feature.enabled?(key, default_enabled: true) if feature_toggle.nil?

        Feature.enabled?(feature_toggle)
      end

      def enabled_for_environment?
        return true if environment.nil?

        environment
      end

      def enabled_for_experimentation_subject?(experimentation_subject_index)
        return false if enabled_ratio.nil? || experimentation_subject_index.blank?

        experimentation_subject_index <= enabled_ratio * 100
      end
    end
  end
end