diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-08-19 09:08:42 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-08-19 09:08:42 +0000 |
commit | b76ae638462ab0f673e5915986070518dd3f9ad3 (patch) | |
tree | bdab0533383b52873be0ec0eb4d3c66598ff8b91 /spec/experiments | |
parent | 434373eabe7b4be9593d18a585fb763f1e5f1a6f (diff) | |
download | gitlab-ce-b76ae638462ab0f673e5915986070518dd3f9ad3.tar.gz |
Add latest changes from gitlab-org/gitlab@14-2-stable-eev14.2.0-rc42
Diffstat (limited to 'spec/experiments')
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 |