summaryrefslogtreecommitdiff
path: root/spec/experiments
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2021-08-19 09:08:42 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2021-08-19 09:08:42 +0000
commitb76ae638462ab0f673e5915986070518dd3f9ad3 (patch)
treebdab0533383b52873be0ec0eb4d3c66598ff8b91 /spec/experiments
parent434373eabe7b4be9593d18a585fb763f1e5f1a6f (diff)
downloadgitlab-ce-b76ae638462ab0f673e5915986070518dd3f9ad3.tar.gz
Add latest changes from gitlab-org/gitlab@14-2-stable-eev14.2.0-rc42
Diffstat (limited to 'spec/experiments')
-rw-r--r--spec/experiments/application_experiment_spec.rb114
-rw-r--r--spec/experiments/force_company_trial_experiment_spec.rb24
-rw-r--r--spec/experiments/members/invite_email_experiment_spec.rb117
-rw-r--r--spec/experiments/new_project_readme_content_experiment_spec.rb4
-rw-r--r--spec/experiments/new_project_readme_experiment_spec.rb75
5 files changed, 115 insertions, 219 deletions
diff --git a/spec/experiments/application_experiment_spec.rb b/spec/experiments/application_experiment_spec.rb
index 9c03910cf66..b0788eec808 100644
--- a/spec/experiments/application_experiment_spec.rb
+++ b/spec/experiments/application_experiment_spec.rb
@@ -57,24 +57,23 @@ RSpec.describe ApplicationExperiment, :experiment do
end
describe "#publish" do
- it "doesn't track or publish to the client or database if we can't track", :snowplow do
- allow(subject).to receive(:should_track?).and_return(false)
-
- expect(subject).not_to receive(:publish_to_client)
- expect(subject).not_to receive(:publish_to_database)
-
- subject.publish
+ let(:should_track) { true }
- expect_no_snowplow_event
+ before do
+ allow(subject).to receive(:should_track?).and_return(should_track)
end
- it "tracks the assignment" do
- expect(subject).to receive(:track).with(:assignment)
-
+ it "tracks the assignment", :snowplow do
subject.publish
+
+ expect_snowplow_event(
+ category: 'namespaced/stub',
+ action: 'assignment',
+ context: [{ schema: anything, data: anything }]
+ )
end
- it "publishes the to the client" do
+ it "publishes to the client" do
expect(subject).to receive(:publish_to_client)
subject.publish
@@ -88,6 +87,16 @@ RSpec.describe ApplicationExperiment, :experiment do
subject.publish
end
+ context 'when we should not track' do
+ let(:should_track) { false }
+
+ it 'does not track an event to Snowplow', :snowplow do
+ subject.publish
+
+ expect_no_snowplow_event
+ end
+ end
+
describe "#publish_to_client" do
it "adds the data into Gon" do
signature = { key: '86208ac54ca798e11f127e8b23ec396a', variant: 'control' }
@@ -101,17 +110,34 @@ RSpec.describe ApplicationExperiment, :experiment do
expect { subject.publish_to_client }.not_to raise_error
end
+
+ context 'when we should not track' do
+ let(:should_track) { false }
+
+ it 'returns early' do
+ expect(Gon).not_to receive(:push)
+
+ subject.publish_to_client
+ end
+ end
end
- describe "#publish_to_database" do
+ describe '#publish_to_database' do
using RSpec::Parameterized::TableSyntax
- let(:context) { { context_key => context_value }}
- before do
- subject.record!
+ shared_examples 'does not record to the database' do
+ it 'does not create an experiment record' do
+ expect { subject.publish_to_database }.not_to change(Experiment, :count)
+ end
+
+ it 'does not create an experiment subject record' do
+ expect { subject.publish_to_database }.not_to change(ExperimentSubject, :count)
+ end
end
- context "when there's a usable subject" do
+ context 'when there is a usable subject' do
+ let(:context) { { context_key => context_value } }
+
where(:context_key, :context_value, :object_type) do
:namespace | build(:namespace) | :namespace
:group | build(:namespace) | :namespace
@@ -121,7 +147,7 @@ RSpec.describe ApplicationExperiment, :experiment do
end
with_them do
- it "creates an experiment and experiment subject record" do
+ it 'creates an experiment and experiment subject record' do
expect { subject.publish_to_database }.to change(Experiment, :count).by(1)
expect(Experiment.last.name).to eq('namespaced/stub')
@@ -130,22 +156,24 @@ RSpec.describe ApplicationExperiment, :experiment do
end
end
- context "when there's not a usable subject" do
+ context 'when there is not a usable subject' do
+ let(:context) { { context_key => context_value } }
+
where(:context_key, :context_value) do
:namespace | nil
:foo | :bar
end
with_them do
- it "doesn't create an experiment record" do
- expect { subject.publish_to_database }.not_to change(Experiment, :count)
- end
-
- it "doesn't create an experiment subject record" do
- expect { subject.publish_to_database }.not_to change(ExperimentSubject, :count)
- end
+ include_examples 'does not record to the database'
end
end
+
+ context 'but we should not track' do
+ let(:should_track) { false }
+
+ include_examples 'does not record to the database'
+ end
end
end
@@ -209,6 +237,40 @@ RSpec.describe ApplicationExperiment, :experiment do
end
end
+ describe "#process_redirect_url" do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:url, :processed_url) do
+ 'https://about.gitlab.com/' | 'https://about.gitlab.com/'
+ 'https://gitlab.com/' | 'https://gitlab.com/'
+ 'http://docs.gitlab.com' | 'http://docs.gitlab.com'
+ 'https://docs.gitlab.com/some/path?foo=bar' | 'https://docs.gitlab.com/some/path?foo=bar'
+ 'http://badgitlab.com' | nil
+ 'https://gitlab.com.nefarious.net' | nil
+ 'https://unknown.gitlab.com' | nil
+ "https://badplace.com\nhttps://gitlab.com" | nil
+ 'https://gitlabbcom' | nil
+ 'https://gitlabbcom/' | nil
+ end
+
+ with_them do
+ it "returns the url or nil if invalid" do
+ allow(Gitlab).to receive(:dev_env_or_com?).and_return(true)
+ expect(subject.process_redirect_url(url)).to eq(processed_url)
+ end
+
+ it "considers all urls invalid when not on dev or com" do
+ allow(Gitlab).to receive(:dev_env_or_com?).and_return(false)
+ expect(subject.process_redirect_url(url)).to be_nil
+ end
+ end
+
+ it "generates the correct urls based on where the engine was mounted" do
+ url = Rails.application.routes.url_helpers.experiment_redirect_url(subject, url: 'https://docs.gitlab.com')
+ expect(url).to include("/-/experiment/namespaced%2Fstub:#{subject.context.key}?https://docs.gitlab.com")
+ end
+ end
+
context "when resolving variants" do
it "uses the default value as specified in the yaml" do
expect(Feature).to receive(:enabled?).with('namespaced_stub', subject, type: :experiment, default_enabled: :yaml)
diff --git a/spec/experiments/force_company_trial_experiment_spec.rb b/spec/experiments/force_company_trial_experiment_spec.rb
new file mode 100644
index 00000000000..42a3245771a
--- /dev/null
+++ b/spec/experiments/force_company_trial_experiment_spec.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe ForceCompanyTrialExperiment, :experiment do
+ subject { described_class.new(current_user: user) }
+
+ let(:user) { create(:user, setup_for_company: setup_for_company) }
+ let(:setup_for_company) { true }
+
+ context 'when a user is setup_for_company' do
+ it 'is not excluded' do
+ expect(subject).not_to exclude(user: user)
+ end
+ end
+
+ context 'when a user is not setup_for_company' do
+ let(:setup_for_company) { nil }
+
+ it 'is excluded' do
+ expect(subject).to exclude(user: user)
+ end
+ end
+end
diff --git a/spec/experiments/members/invite_email_experiment_spec.rb b/spec/experiments/members/invite_email_experiment_spec.rb
deleted file mode 100644
index 47ae6e529a1..00000000000
--- a/spec/experiments/members/invite_email_experiment_spec.rb
+++ /dev/null
@@ -1,117 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Members::InviteEmailExperiment, :clean_gitlab_redis_shared_state do
- subject(:invite_email) { experiment('members/invite_email', **context) }
-
- let(:context) { { actor: double('Member', created_by: double('User', avatar_url: '_avatar_url_')) } }
-
- before do
- allow(invite_email).to receive(:enabled?).and_return(true)
- end
-
- describe ".initial_invite_email?" do
- it "is an initial invite email" do
- expect(described_class.initial_invite_email?('initial_email')).to be(true)
- end
-
- it "is not an initial invite email" do
- expect(described_class.initial_invite_email?('_bogus_')).to be(false)
- end
- end
-
- describe "exclusions", :experiment do
- it "excludes when created by is nil" do
- expect(experiment('members/invite_email')).to exclude(actor: double(created_by: nil))
- end
-
- it "excludes when avatar_url is nil" do
- member_without_avatar_url = double('Member', created_by: double('User', avatar_url: nil))
-
- expect(experiment('members/invite_email')).to exclude(actor: member_without_avatar_url)
- end
- end
-
- describe "variant resolution" do
- it "proves out round robin in variant selection", :aggregate_failures do
- instance_1 = described_class.new('members/invite_email', **context)
- allow(instance_1).to receive(:enabled?).and_return(true)
- instance_2 = described_class.new('members/invite_email', **context)
- allow(instance_2).to receive(:enabled?).and_return(true)
-
- instance_1.try { }
-
- expect(instance_1.variant.name).to eq('control')
-
- instance_2.try { }
-
- expect(instance_2.variant.name).to eq('activity')
- end
- end
-
- describe Members::RoundRobin do
- subject(:round_robin) { Members::RoundRobin.new('_key_', %i[variant1 variant2]) }
-
- describe "execute" do
- context "when there are 2 variants" do
- it "proves out round robin in selection", :aggregate_failures do
- expect(round_robin.execute).to eq :variant2
- expect(round_robin.execute).to eq :variant1
- expect(round_robin.execute).to eq :variant2
- end
- end
-
- context "when there are more than 2 variants" do
- subject(:round_robin) { Members::RoundRobin.new('_key_', %i[variant1 variant2 variant3]) }
-
- it "proves out round robin in selection", :aggregate_failures do
- expect(round_robin.execute).to eq :variant2
- expect(round_robin.execute).to eq :variant3
- expect(round_robin.execute).to eq :variant1
-
- expect(round_robin.execute).to eq :variant2
- expect(round_robin.execute).to eq :variant3
- expect(round_robin.execute).to eq :variant1
- end
- end
-
- context "when writing to cache fails" do
- subject(:round_robin) { Members::RoundRobin.new('_key_', []) }
-
- it "raises an error and logs" do
- allow(Gitlab::Redis::SharedState).to receive(:with).and_raise(Members::RoundRobin::CacheError)
- expect(Gitlab::AppLogger).to receive(:warn)
-
- expect { round_robin.execute }.to raise_error(Members::RoundRobin::CacheError)
- end
- end
- end
-
- describe "#counter_expires_in" do
- it 'displays the expiration time in seconds' do
- round_robin.execute
-
- expect(round_robin.counter_expires_in).to be_between(0, described_class::COUNTER_EXPIRE_TIME)
- end
- end
-
- describe '#value' do
- it 'get the count' do
- expect(round_robin.counter_value).to eq(0)
-
- round_robin.execute
-
- expect(round_robin.counter_value).to eq(1)
- end
- end
-
- describe '#reset!' do
- it 'resets the count down to zero' do
- 3.times { round_robin.execute }
-
- expect { round_robin.reset! }.to change { round_robin.counter_value }.from(3).to(0)
- end
- end
- end
-end
diff --git a/spec/experiments/new_project_readme_content_experiment_spec.rb b/spec/experiments/new_project_readme_content_experiment_spec.rb
index 92a883078df..a6a81580a29 100644
--- a/spec/experiments/new_project_readme_content_experiment_spec.rb
+++ b/spec/experiments/new_project_readme_content_experiment_spec.rb
@@ -30,7 +30,9 @@ RSpec.describe NewProjectReadmeContentExperiment, :experiment do
end
it "renders redirect URLs" do
- expect(markdown).to include(Rails.application.routes.url_helpers.experiment_redirect_url(subject, initial_url))
+ url = Rails.application.routes.url_helpers.experiment_redirect_url(subject, url: initial_url)
+ expect(url).to include("/-/experiment/#{subject.to_param}?")
+ expect(markdown).to include(url)
end
end
end
diff --git a/spec/experiments/new_project_readme_experiment_spec.rb b/spec/experiments/new_project_readme_experiment_spec.rb
deleted file mode 100644
index e5ecc4662f6..00000000000
--- a/spec/experiments/new_project_readme_experiment_spec.rb
+++ /dev/null
@@ -1,75 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe NewProjectReadmeExperiment, :experiment do
- subject { described_class.new(actor: actor) }
-
- let(:actor) { User.new(id: 42, created_at: Time.current) }
-
- describe "exclusions" do
- let(:threshold) { described_class::MAX_ACCOUNT_AGE }
-
- it { is_expected.to exclude(actor: User.new(created_at: (threshold + 1.minute).ago)) }
- it { is_expected.not_to exclude(actor: User.new(created_at: (threshold - 1.minute).ago)) }
- end
-
- describe "the control behavior" do
- subject { described_class.new(actor: actor).run(:control) }
-
- it { is_expected.to be false }
- end
-
- describe "the candidate behavior" do
- subject { described_class.new(actor: actor).run(:candidate) }
-
- it { is_expected.to be true }
- end
-
- context "when tracking initial writes" do
- let!(:project) { create(:project, :repository) }
-
- before do
- stub_experiments(new_project_readme: :control)
- end
-
- it "tracks an event for the first commit on a project with a repository" do
- expect(subject).to receive(:commit_count_for).with(project, default_count: described_class::INITIAL_WRITE_LIMIT, max_count: described_class::INITIAL_WRITE_LIMIT, experiment: 'new_project_readme').and_return(1)
- expect(subject).to receive(:track).with(:write, property: project.created_at.to_s, value: 1).and_call_original
-
- subject.track_initial_writes(project)
- end
-
- it "tracks an event for the second commit on a project with a repository" do
- allow(subject).to receive(:commit_count_for).and_return(2)
-
- expect(subject).to receive(:track).with(:write, property: project.created_at.to_s, value: 2).and_call_original
-
- subject.track_initial_writes(project)
- end
-
- it "doesn't track if the repository has more then 2 commits" do
- allow(subject).to receive(:commit_count_for).and_return(3)
-
- expect(subject).not_to receive(:track)
-
- subject.track_initial_writes(project)
- end
-
- it "doesn't track when we generally shouldn't" do
- allow(subject).to receive(:should_track?).and_return(false)
-
- expect(subject).not_to receive(:track)
-
- subject.track_initial_writes(project)
- end
-
- it "doesn't track if the project is older" do
- expect(project).to receive(:created_at).and_return(described_class::EXPERIMENT_START_DATE - 1.minute)
-
- expect(subject).not_to receive(:track)
-
- subject.track_initial_writes(project)
- end
- end
-end