2019-12-21 20:55:43 +05:30
# frozen_string_literal: true
require 'spec_helper'
2021-01-03 14:25:43 +05:30
RSpec . describe Gitlab :: Experimentation , :snowplow do
2019-12-26 22:10:19 +05:30
before do
stub_const ( 'Gitlab::Experimentation::EXPERIMENTS' , {
test_experiment : {
environment : environment ,
tracking_category : 'Team'
}
} )
2019-12-21 20:55:43 +05:30
2020-06-23 00:09:42 +05:30
Feature . enable_percentage_of_time ( :test_experiment_experiment_percentage , enabled_percentage )
2019-12-21 20:55:43 +05:30
end
2019-12-26 22:10:19 +05:30
let ( :environment ) { Rails . env . test? }
2020-05-24 23:13:21 +05:30
let ( :enabled_percentage ) { 10 }
2019-12-26 22:10:19 +05:30
describe Gitlab :: Experimentation :: ControllerConcern , type : :controller do
controller ( ApplicationController ) do
include Gitlab :: Experimentation :: ControllerConcern
def index
head :ok
end
2019-12-21 20:55:43 +05:30
end
2019-12-26 22:10:19 +05:30
describe '#set_experimentation_subject_id_cookie' do
2020-04-08 14:13:33 +05:30
let ( :do_not_track ) { nil }
let ( :cookie ) { cookies . permanent . signed [ :experimentation_subject_id ] }
2019-12-21 20:55:43 +05:30
before do
2020-04-08 14:13:33 +05:30
request . headers [ 'DNT' ] = do_not_track if do_not_track . present?
2019-12-26 22:10:19 +05:30
get :index
2019-12-21 20:55:43 +05:30
end
2019-12-26 22:10:19 +05:30
context 'cookie is present' do
before do
cookies [ :experimentation_subject_id ] = 'test'
end
it 'does not change the cookie' do
expect ( cookies [ :experimentation_subject_id ] ) . to eq 'test'
end
2019-12-21 20:55:43 +05:30
end
2019-12-26 22:10:19 +05:30
context 'cookie is not present' do
it 'sets a permanent signed cookie' do
2020-04-08 14:13:33 +05:30
expect ( cookie ) . to be_present
end
context 'DNT: 0' do
let ( :do_not_Track ) { '0' }
it 'sets a permanent signed cookie' do
expect ( cookie ) . to be_present
end
end
context 'DNT: 1' do
let ( :do_not_track ) { '1' }
it 'does nothing' do
expect ( cookie ) . not_to be_present
end
2019-12-26 22:10:19 +05:30
end
2019-12-21 20:55:43 +05:30
end
end
2021-01-03 14:25:43 +05:30
describe '#push_frontend_experiment' do
it 'pushes an experiment to the frontend' do
gon = instance_double ( 'gon' )
experiments = { experiments : { 'myExperiment' = > true } }
stub_experiment_for_user ( my_experiment : true )
allow ( controller ) . to receive ( :gon ) . and_return ( gon )
expect ( gon ) . to receive ( :push ) . with ( experiments , true )
controller . push_frontend_experiment ( :my_experiment )
end
end
2019-12-26 22:10:19 +05:30
describe '#experiment_enabled?' do
2020-04-08 14:13:33 +05:30
subject { controller . experiment_enabled? ( :test_experiment ) }
2019-12-26 22:10:19 +05:30
context 'cookie is not present' do
2021-01-03 14:25:43 +05:30
it 'calls Gitlab::Experimentation.enabled_for_value? with the name of the experiment and an experimentation_subject_index of nil' do
expect ( Gitlab :: Experimentation ) . to receive ( :enabled_for_value? ) . with ( :test_experiment , nil )
2019-12-26 22:10:19 +05:30
controller . experiment_enabled? ( :test_experiment )
end
end
context 'cookie is present' do
before do
cookies . permanent . signed [ :experimentation_subject_id ] = 'abcd-1234'
get :index
end
2021-01-03 14:25:43 +05:30
it 'calls Gitlab::Experimentation.enabled_for_value? with the name of the experiment and an experimentation_subject_index of the modulo 100 of the hex value of the uuid' do
2019-12-26 22:10:19 +05:30
# 'abcd1234'.hex % 100 = 76
2021-01-03 14:25:43 +05:30
expect ( Gitlab :: Experimentation ) . to receive ( :enabled_for_value? ) . with ( :test_experiment , 76 )
2019-12-26 22:10:19 +05:30
controller . experiment_enabled? ( :test_experiment )
end
end
2020-04-08 14:13:33 +05:30
it 'returns true when DNT: 0 is set in the request' do
2021-01-03 14:25:43 +05:30
allow ( Gitlab :: Experimentation ) . to receive ( :enabled_for_value? ) { true }
2020-04-08 14:13:33 +05:30
controller . request . headers [ 'DNT' ] = '0'
is_expected . to be_truthy
end
it 'returns false when DNT: 1 is set in the request' do
2021-01-03 14:25:43 +05:30
allow ( Gitlab :: Experimentation ) . to receive ( :enabled_for_value? ) { true }
2020-04-08 14:13:33 +05:30
controller . request . headers [ 'DNT' ] = '1'
is_expected . to be_falsy
end
2019-12-26 22:10:19 +05:30
describe 'URL parameter to force enable experiment' do
2020-04-08 14:13:33 +05:30
it 'returns true unconditionally' do
2019-12-26 22:10:19 +05:30
get :index , params : { force_experiment : :test_experiment }
2020-04-08 14:13:33 +05:30
is_expected . to be_truthy
2019-12-26 22:10:19 +05:30
end
2019-12-21 20:55:43 +05:30
end
end
2019-12-26 22:10:19 +05:30
describe '#track_experiment_event' do
context 'when the experiment is enabled' do
before do
stub_experiment ( test_experiment : true )
end
context 'the user is part of the experimental group' do
before do
stub_experiment_for_user ( test_experiment : true )
end
it 'tracks the event with the right parameters' do
2021-01-03 14:25:43 +05:30
controller . track_experiment_event ( :test_experiment , 'start' , 1 )
expect_snowplow_event (
category : 'Team' ,
action : 'start' ,
2020-03-13 15:44:24 +05:30
property : 'experimental_group' ,
2021-01-03 14:25:43 +05:30
value : 1
2019-12-26 22:10:19 +05:30
)
end
end
context 'the user is part of the control group' do
before do
stub_experiment_for_user ( test_experiment : false )
end
it 'tracks the event with the right parameters' do
2021-01-03 14:25:43 +05:30
controller . track_experiment_event ( :test_experiment , 'start' , 1 )
expect_snowplow_event (
category : 'Team' ,
action : 'start' ,
property : 'control_group' ,
value : 1
)
end
end
context 'do not track is disabled' do
before do
request . headers [ 'DNT' ] = '0'
end
it 'does track the event' do
controller . track_experiment_event ( :test_experiment , 'start' , 1 )
expect_snowplow_event (
category : 'Team' ,
action : 'start' ,
2020-03-13 15:44:24 +05:30
property : 'control_group' ,
2021-01-03 14:25:43 +05:30
value : 1
2019-12-26 22:10:19 +05:30
)
2021-01-03 14:25:43 +05:30
end
end
context 'do not track enabled' do
before do
request . headers [ 'DNT' ] = '1'
end
it 'does not track the event' do
controller . track_experiment_event ( :test_experiment , 'start' , 1 )
expect_no_snowplow_event
2019-12-26 22:10:19 +05:30
end
end
2019-12-21 20:55:43 +05:30
end
2019-12-26 22:10:19 +05:30
context 'when the experiment is disabled' do
before do
stub_experiment ( test_experiment : false )
end
it 'does not track the event' do
controller . track_experiment_event ( :test_experiment , 'start' )
2021-01-03 14:25:43 +05:30
expect_no_snowplow_event
2019-12-26 22:10:19 +05:30
end
2019-12-21 20:55:43 +05:30
end
end
2019-12-26 22:10:19 +05:30
describe '#frontend_experimentation_tracking_data' do
context 'when the experiment is enabled' do
before do
stub_experiment ( test_experiment : true )
end
2019-12-21 20:55:43 +05:30
2019-12-26 22:10:19 +05:30
context 'the user is part of the experimental group' do
before do
stub_experiment_for_user ( test_experiment : true )
end
it 'pushes the right parameters to gon' do
2020-03-13 15:44:24 +05:30
controller . frontend_experimentation_tracking_data ( :test_experiment , 'start' , 'team_id' )
2019-12-26 22:10:19 +05:30
expect ( Gon . tracking_data ) . to eq (
{
category : 'Team' ,
action : 'start' ,
2020-03-13 15:44:24 +05:30
property : 'experimental_group' ,
value : 'team_id'
2019-12-26 22:10:19 +05:30
}
)
end
end
2019-12-21 20:55:43 +05:30
2019-12-26 22:10:19 +05:30
context 'the user is part of the control group' do
before do
2020-01-01 13:55:28 +05:30
allow_next_instance_of ( described_class ) do | instance |
allow ( instance ) . to receive ( :experiment_enabled? ) . with ( :test_experiment ) . and_return ( false )
end
2019-12-26 22:10:19 +05:30
end
it 'pushes the right parameters to gon' do
2020-03-13 15:44:24 +05:30
controller . frontend_experimentation_tracking_data ( :test_experiment , 'start' , 'team_id' )
expect ( Gon . tracking_data ) . to eq (
{
category : 'Team' ,
action : 'start' ,
property : 'control_group' ,
value : 'team_id'
}
)
end
it 'does not send nil value to gon' do
2019-12-26 22:10:19 +05:30
controller . frontend_experimentation_tracking_data ( :test_experiment , 'start' )
expect ( Gon . tracking_data ) . to eq (
{
category : 'Team' ,
action : 'start' ,
property : 'control_group'
}
)
end
end
2021-01-03 14:25:43 +05:30
context 'do not track disabled' do
before do
request . headers [ 'DNT' ] = '0'
end
it 'pushes the right parameters to gon' do
controller . frontend_experimentation_tracking_data ( :test_experiment , 'start' )
expect ( Gon . tracking_data ) . to eq (
{
category : 'Team' ,
action : 'start' ,
property : 'control_group'
}
)
end
end
context 'do not track enabled' do
before do
request . headers [ 'DNT' ] = '1'
end
it 'does not push data to gon' do
controller . frontend_experimentation_tracking_data ( :test_experiment , 'start' )
expect ( Gon . method_defined? ( :tracking_data ) ) . to be_falsey
end
end
2019-12-26 22:10:19 +05:30
end
2019-12-21 20:55:43 +05:30
2019-12-26 22:10:19 +05:30
context 'when the experiment is disabled' do
before do
stub_experiment ( test_experiment : false )
end
2019-12-21 20:55:43 +05:30
2019-12-26 22:10:19 +05:30
it 'does not push data to gon' do
expect ( Gon . method_defined? ( :tracking_data ) ) . to be_falsey
controller . track_experiment_event ( :test_experiment , 'start' )
end
end
end
2020-10-24 23:57:45 +05:30
describe '#record_experiment_user' do
let ( :user ) { build ( :user ) }
context 'when the experiment is enabled' do
before do
stub_experiment ( test_experiment : true )
allow ( controller ) . to receive ( :current_user ) . and_return ( user )
end
context 'the user is part of the experimental group' do
before do
stub_experiment_for_user ( test_experiment : true )
end
it 'calls add_user on the Experiment model' do
expect ( :: Experiment ) . to receive ( :add_user ) . with ( :test_experiment , :experimental , user )
controller . record_experiment_user ( :test_experiment )
end
end
context 'the user is part of the control group' do
before do
allow_next_instance_of ( described_class ) do | instance |
allow ( instance ) . to receive ( :experiment_enabled? ) . with ( :test_experiment ) . and_return ( false )
end
end
it 'calls add_user on the Experiment model' do
expect ( :: Experiment ) . to receive ( :add_user ) . with ( :test_experiment , :control , user )
controller . record_experiment_user ( :test_experiment )
end
end
end
context 'when the experiment is disabled' do
before do
stub_experiment ( test_experiment : false )
allow ( controller ) . to receive ( :current_user ) . and_return ( user )
end
it 'does not call add_user on the Experiment model' do
expect ( :: Experiment ) . not_to receive ( :add_user )
controller . record_experiment_user ( :test_experiment )
end
end
context 'when there is no current_user' do
before do
stub_experiment ( test_experiment : true )
end
it 'does not call add_user on the Experiment model' do
expect ( :: Experiment ) . not_to receive ( :add_user )
controller . record_experiment_user ( :test_experiment )
end
end
2021-01-03 14:25:43 +05:30
context 'do not track' do
before do
allow ( controller ) . to receive ( :current_user ) . and_return ( user )
allow_next_instance_of ( described_class ) do | instance |
allow ( instance ) . to receive ( :experiment_enabled? ) . with ( :test_experiment ) . and_return ( false )
end
end
context 'is disabled' do
before do
request . headers [ 'DNT' ] = '0'
end
it 'calls add_user on the Experiment model' do
expect ( :: Experiment ) . to receive ( :add_user ) . with ( :test_experiment , :control , user )
controller . record_experiment_user ( :test_experiment )
end
end
context 'is enabled' do
before do
request . headers [ 'DNT' ] = '1'
end
it 'does not call add_user on the Experiment model' do
expect ( :: Experiment ) . not_to receive ( :add_user )
controller . record_experiment_user ( :test_experiment )
end
end
end
2020-10-24 23:57:45 +05:30
end
2020-11-24 15:15:51 +05:30
describe '#experiment_tracking_category_and_group' do
let_it_be ( :experiment_key ) { :test_something }
subject { controller . experiment_tracking_category_and_group ( experiment_key ) }
it 'returns a string with the experiment tracking category & group joined with a ":"' do
expect ( controller ) . to receive ( :tracking_category ) . with ( experiment_key ) . and_return ( 'Experiment::Category' )
expect ( controller ) . to receive ( :tracking_group ) . with ( experiment_key , '_group' ) . and_return ( 'experimental_group' )
expect ( subject ) . to eq ( 'Experiment::Category:experimental_group' )
end
end
2019-12-26 22:10:19 +05:30
end
describe '.enabled?' do
subject { described_class . enabled? ( :test_experiment ) }
2019-12-21 20:55:43 +05:30
context 'feature toggle is enabled, we are on the right environment and we are selected' do
it { is_expected . to be_truthy }
end
describe 'experiment is not defined' do
it 'returns false' do
2019-12-26 22:10:19 +05:30
expect ( described_class . enabled? ( :missing_experiment ) ) . to be_falsey
2019-12-21 20:55:43 +05:30
end
end
2020-05-24 23:13:21 +05:30
describe 'experiment is disabled' do
let ( :enabled_percentage ) { 0 }
2019-12-21 20:55:43 +05:30
2020-05-24 23:13:21 +05:30
it { is_expected . to be_falsey }
2019-12-21 20:55:43 +05:30
end
2020-05-24 23:13:21 +05:30
describe 'we are on the wrong environment' do
let ( :environment ) { :: Gitlab . com? }
2019-12-21 20:55:43 +05:30
2020-05-24 23:13:21 +05:30
it { is_expected . to be_falsey }
2019-12-21 20:55:43 +05:30
end
2019-12-26 22:10:19 +05:30
end
2019-12-21 20:55:43 +05:30
2021-01-03 14:25:43 +05:30
describe '.enabled_for_value?' do
subject { described_class . enabled_for_value? ( :test_experiment , experimentation_subject_index ) }
2019-12-21 20:55:43 +05:30
2019-12-26 22:10:19 +05:30
let ( :experimentation_subject_index ) { 9 }
context 'experiment is disabled' do
before do
allow ( described_class ) . to receive ( :enabled? ) . and_return ( false )
2019-12-21 20:55:43 +05:30
end
2019-12-26 22:10:19 +05:30
it { is_expected . to be_falsey }
end
2019-12-21 20:55:43 +05:30
2019-12-26 22:10:19 +05:30
context 'experiment is enabled' do
before do
allow ( described_class ) . to receive ( :enabled? ) . and_return ( true )
2019-12-21 20:55:43 +05:30
end
2019-12-26 22:10:19 +05:30
it { is_expected . to be_truthy }
describe 'experimentation_subject_index' do
context 'experimentation_subject_index is not set' do
let ( :experimentation_subject_index ) { nil }
2019-12-21 20:55:43 +05:30
2019-12-26 22:10:19 +05:30
it { is_expected . to be_falsey }
end
context 'experimentation_subject_index is an empty string' do
let ( :experimentation_subject_index ) { '' }
it { is_expected . to be_falsey }
end
context 'experimentation_subject_index outside enabled ratio' do
let ( :experimentation_subject_index ) { 11 }
it { is_expected . to be_falsey }
end
2019-12-21 20:55:43 +05:30
end
end
end
2021-01-03 14:25:43 +05:30
describe '.enabled_for_attribute?' do
subject { described_class . enabled_for_attribute? ( :test_experiment , attribute ) }
let ( :attribute ) { 'abcd' } # Digest::SHA1.hexdigest('abcd').hex % 100 = 7
context 'experiment is disabled' do
before do
allow ( described_class ) . to receive ( :enabled? ) . and_return ( false )
end
it { is_expected . to be false }
end
context 'experiment is enabled' do
before do
allow ( described_class ) . to receive ( :enabled? ) . and_return ( true )
end
it { is_expected . to be true }
context 'outside enabled ratio' do
let ( :attribute ) { 'abc' } # Digest::SHA1.hexdigest('abc').hex % 100 = 17
it { is_expected . to be false }
end
end
end
2019-12-21 20:55:43 +05:30
end