Class: DecisionAgent::ABTesting::ABTest
- Inherits:
-
Object
- Object
- DecisionAgent::ABTesting::ABTest
- Defined in:
- lib/decision_agent/ab_testing/ab_test.rb
Overview
Represents an A/B test configuration for comparing rule versions
Instance Attribute Summary collapse
-
#challenger_version_id ⇒ Object
readonly
Returns the value of attribute challenger_version_id.
-
#champion_version_id ⇒ Object
readonly
Returns the value of attribute champion_version_id.
-
#end_date ⇒ Object
readonly
Returns the value of attribute end_date.
-
#id ⇒ Object
readonly
Returns the value of attribute id.
-
#name ⇒ Object
readonly
Returns the value of attribute name.
-
#start_date ⇒ Object
readonly
Returns the value of attribute start_date.
-
#status ⇒ Object
readonly
Returns the value of attribute status.
-
#traffic_split ⇒ Object
readonly
Returns the value of attribute traffic_split.
Instance Method Summary collapse
-
#assign_variant(user_id: nil) ⇒ Symbol
Assign a variant based on traffic split Uses consistent hashing to ensure same user gets same variant.
-
#cancel! ⇒ Object
Cancel the test.
-
#complete! ⇒ Object
Complete the test.
-
#completed? ⇒ Boolean
Check if test is completed.
-
#initialize(name:, champion_version_id:, challenger_version_id:, **options) ⇒ ABTest
constructor
A new instance of ABTest.
-
#running? ⇒ Boolean
Check if test is currently running.
-
#scheduled? ⇒ Boolean
Check if test is scheduled to start.
-
#start! ⇒ Object
Start the test.
-
#to_h ⇒ Hash
Convert to hash representation.
-
#version_for_variant(variant) ⇒ String, Integer
Get the version ID for the assigned variant.
Constructor Details
#initialize(name:, champion_version_id:, challenger_version_id:, **options) ⇒ ABTest
Returns a new instance of ABTest.
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
# File 'lib/decision_agent/ab_testing/ab_test.rb', line 21 def initialize( name:, champion_version_id:, challenger_version_id:, ** ) @id = [:id] @name = name @champion_version_id = champion_version_id @challenger_version_id = challenger_version_id @traffic_split = normalize_traffic_split([:traffic_split] || { champion: 90, challenger: 10 }) @start_date = [:start_date] || Time.now.utc @end_date = [:end_date] @status = [:status] || "scheduled" validate! end |
Instance Attribute Details
#challenger_version_id ⇒ Object (readonly)
Returns the value of attribute challenger_version_id.
9 10 11 |
# File 'lib/decision_agent/ab_testing/ab_test.rb', line 9 def challenger_version_id @challenger_version_id end |
#champion_version_id ⇒ Object (readonly)
Returns the value of attribute champion_version_id.
9 10 11 |
# File 'lib/decision_agent/ab_testing/ab_test.rb', line 9 def champion_version_id @champion_version_id end |
#end_date ⇒ Object (readonly)
Returns the value of attribute end_date.
9 10 11 |
# File 'lib/decision_agent/ab_testing/ab_test.rb', line 9 def end_date @end_date end |
#id ⇒ Object (readonly)
Returns the value of attribute id.
9 10 11 |
# File 'lib/decision_agent/ab_testing/ab_test.rb', line 9 def id @id end |
#name ⇒ Object (readonly)
Returns the value of attribute name.
9 10 11 |
# File 'lib/decision_agent/ab_testing/ab_test.rb', line 9 def name @name end |
#start_date ⇒ Object (readonly)
Returns the value of attribute start_date.
9 10 11 |
# File 'lib/decision_agent/ab_testing/ab_test.rb', line 9 def start_date @start_date end |
#status ⇒ Object (readonly)
Returns the value of attribute status.
9 10 11 |
# File 'lib/decision_agent/ab_testing/ab_test.rb', line 9 def status @status end |
#traffic_split ⇒ Object (readonly)
Returns the value of attribute traffic_split.
9 10 11 |
# File 'lib/decision_agent/ab_testing/ab_test.rb', line 9 def traffic_split @traffic_split end |
Instance Method Details
#assign_variant(user_id: nil) ⇒ Symbol
Assign a variant based on traffic split Uses consistent hashing to ensure same user gets same variant
43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
# File 'lib/decision_agent/ab_testing/ab_test.rb', line 43 def assign_variant(user_id: nil) raise TestNotRunningError, "Test '#{@name}' is not running (status: #{@status})" unless running? if user_id # Consistent hashing: same user always gets same variant hash_value = OpenSSL::Digest::SHA256.hexdigest("#{@id}:#{user_id}").to_i(16) percentage = hash_value % 100 else # Random assignment percentage = rand(100) end percentage < @traffic_split[:champion] ? :champion : :challenger end |
#cancel! ⇒ Object
Cancel the test
111 112 113 114 115 |
# File 'lib/decision_agent/ab_testing/ab_test.rb', line 111 def cancel! raise InvalidStatusTransitionError, "Cannot cancel test from status: #{@status}" if @status == "completed" @status = "cancelled" end |
#complete! ⇒ Object
Complete the test
103 104 105 106 107 108 |
# File 'lib/decision_agent/ab_testing/ab_test.rb', line 103 def complete! raise InvalidStatusTransitionError, "Cannot complete test from status: #{@status}" unless can_complete? @status = "completed" @end_date = Time.now.utc end |
#completed? ⇒ Boolean
Check if test is completed
90 91 92 |
# File 'lib/decision_agent/ab_testing/ab_test.rb', line 90 def completed? @status == "completed" || (@end_date && Time.now.utc > @end_date) end |
#running? ⇒ Boolean
Check if test is currently running
74 75 76 77 78 79 80 |
# File 'lib/decision_agent/ab_testing/ab_test.rb', line 74 def running? return false unless @status == "running" return false if @start_date && Time.now.utc < @start_date return false if @end_date && Time.now.utc > @end_date true end |
#scheduled? ⇒ Boolean
Check if test is scheduled to start
84 85 86 |
# File 'lib/decision_agent/ab_testing/ab_test.rb', line 84 def scheduled? @status == "scheduled" && @start_date && Time.now.utc < @start_date end |
#start! ⇒ Object
Start the test
95 96 97 98 99 100 |
# File 'lib/decision_agent/ab_testing/ab_test.rb', line 95 def start! raise InvalidStatusTransitionError, "Cannot start test from status: #{@status}" unless can_start? @status = "running" @start_date = Time.now.utc if @start_date.nil? || @start_date > Time.now.utc end |
#to_h ⇒ Hash
Convert to hash representation
119 120 121 122 123 124 125 126 127 128 129 130 |
# File 'lib/decision_agent/ab_testing/ab_test.rb', line 119 def to_h { id: @id, name: @name, champion_version_id: @champion_version_id, challenger_version_id: @challenger_version_id, traffic_split: @traffic_split, start_date: @start_date, end_date: @end_date, status: @status } end |
#version_for_variant(variant) ⇒ String, Integer
Get the version ID for the assigned variant
61 62 63 64 65 66 67 68 69 70 |
# File 'lib/decision_agent/ab_testing/ab_test.rb', line 61 def version_for_variant(variant) case variant when :champion @champion_version_id when :challenger @challenger_version_id else raise ArgumentError, "Invalid variant: #{variant}. Must be :champion or :challenger" end end |