diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-12-22 21:10:06 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-12-22 21:10:06 +0000 |
commit | c66b5f750f309b995529d63708b482bcc4e3d35c (patch) | |
tree | 1baa97efbc3a37828d763cf4ef4ef6668da864b7 /spec | |
parent | 9a14667521070786dbf3e61409a50ef6ef72e7ff (diff) | |
download | gitlab-ce-c66b5f750f309b995529d63708b482bcc4e3d35c.tar.gz |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
13 files changed, 346 insertions, 80 deletions
diff --git a/spec/controllers/projects_controller_spec.rb b/spec/controllers/projects_controller_spec.rb index bd7ef3db8b6..51ac005883e 100644 --- a/spec/controllers/projects_controller_spec.rb +++ b/spec/controllers/projects_controller_spec.rb @@ -232,7 +232,7 @@ RSpec.describe ProjectsController do before do sign_in(user) - allow(controller).to receive(:record_experiment_user).with(:invite_members_empty_project_version_a) + allow(controller).to receive(:record_experiment_user) end User.project_views.keys.each do |project_view| diff --git a/spec/helpers/invite_members_helper_spec.rb b/spec/helpers/invite_members_helper_spec.rb index d75b3c9f2e3..914d0931476 100644 --- a/spec/helpers/invite_members_helper_spec.rb +++ b/spec/helpers/invite_members_helper_spec.rb @@ -114,4 +114,69 @@ RSpec.describe InviteMembersHelper do end end end + + describe '#dropdown_invite_members_link' do + shared_examples_for 'dropdown invite members link' do + let(:link_regex) do + /data-track-event="click_link".*data-track-property="_track_property_".*Invite members/ + end + + before do + allow(helper).to receive(:experiment_tracking_category_and_group) { '_track_property_' } + allow(helper).to receive(:tracking_label).with(owner) + allow(helper).to receive(:current_user) { owner } + end + + it 'records the experiment' do + allow(helper).to receive(:experiment_enabled?) + + helper.dropdown_invite_members_link(form_model) + + expect(helper).to have_received(:experiment_tracking_category_and_group) + .with(:invite_members_new_dropdown, subject: owner) + end + + context 'with experiment enabled' do + before do + allow(helper).to receive(:experiment_enabled?).with(:invite_members_new_dropdown) { true } + end + + it 'returns link' do + link = helper.dropdown_invite_members_link(form_model) + + expect(link).to match(link_regex) + expect(link).to include(link_href) + expect(link).to include('gl-emoji') + end + end + + context 'with no experiment enabled' do + before do + allow(helper).to receive(:experiment_enabled?).with(:invite_members_new_dropdown) { false } + end + + it 'returns link' do + link = helper.dropdown_invite_members_link(form_model) + + expect(link).to match(link_regex) + expect(link).to include(link_href) + expect(link).not_to include('gl-emoji') + end + end + end + + context 'with a project' do + let_it_be(:form_model) { project } + let(:link_href) { "href=\"#{project_project_members_path(form_model)}\"" } + + it_behaves_like 'dropdown invite members link' + end + + context 'with a group' do + let_it_be(:form_model) { create(:group) } + let(:link_href) { "href=\"#{group_group_members_path(form_model)}\"" } + + it_behaves_like 'dropdown invite members link' + end + end end diff --git a/spec/lib/gitlab/usage_data_counters/hll_redis_counter_spec.rb b/spec/lib/gitlab/usage_data_counters/hll_redis_counter_spec.rb index f2ec4526464..b390d7c0c9f 100644 --- a/spec/lib/gitlab/usage_data_counters/hll_redis_counter_spec.rb +++ b/spec/lib/gitlab/usage_data_counters/hll_redis_counter_spec.rb @@ -46,7 +46,8 @@ RSpec.describe Gitlab::UsageDataCounters::HLLRedisCounter, :clean_gitlab_redis_s 'container_packages', 'tag_packages', 'snippets', - 'code_review' + 'code_review', + 'terraform' ) end end diff --git a/spec/lib/gitlab/usage_data_spec.rb b/spec/lib/gitlab/usage_data_spec.rb index 4d12bb6bd8c..6a613cab999 100644 --- a/spec/lib/gitlab/usage_data_spec.rb +++ b/spec/lib/gitlab/usage_data_spec.rb @@ -1260,7 +1260,7 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures do subject { described_class.redis_hll_counters } let(:categories) { ::Gitlab::UsageDataCounters::HLLRedisCounter.categories } - let(:ineligible_total_categories) { %w[source_code testing ci_secrets_management incident_management_alerts snippets] } + let(:ineligible_total_categories) { %w[source_code testing ci_secrets_management incident_management_alerts snippets terraform] } it 'has all known_events' do expect(subject).to have_key(:redis_hll_counters) diff --git a/spec/models/snippet_repository_storage_move_spec.rb b/spec/models/snippet_repository_storage_move_spec.rb index c9feff0c22f..357951f8859 100644 --- a/spec/models/snippet_repository_storage_move_spec.rb +++ b/spec/models/snippet_repository_storage_move_spec.rb @@ -8,6 +8,6 @@ RSpec.describe SnippetRepositoryStorageMove, type: :model do let(:repository_storage_factory_key) { :snippet_repository_storage_move } let(:error_key) { :snippet } - let(:repository_storage_worker) { nil } # TODO set to SnippetUpdateRepositoryStorageWorker after https://gitlab.com/gitlab-org/gitlab/-/issues/218991 is implemented + let(:repository_storage_worker) { SnippetUpdateRepositoryStorageWorker } end end diff --git a/spec/requests/api/terraform/state_spec.rb b/spec/requests/api/terraform/state_spec.rb index 0fa088a641e..bfdb5458fd1 100644 --- a/spec/requests/api/terraform/state_spec.rb +++ b/spec/requests/api/terraform/state_spec.rb @@ -21,9 +21,36 @@ RSpec.describe API::Terraform::State do stub_terraform_state_object_storage end + shared_examples 'endpoint with unique user tracking' do + context 'without authentication' do + let(:auth_header) { basic_auth_header('bad', 'token') } + + before do + stub_feature_flags(usage_data_p_terraform_state_api_unique_users: false) + end + + it 'does not track unique event' do + expect(Gitlab::UsageDataCounters::HLLRedisCounter).not_to receive(:track_event) + + request + end + end + + context 'with maintainer permissions' do + let(:current_user) { maintainer } + + it_behaves_like 'tracking unique hll events', :usage_data_p_terraform_state_api_unique_users do + let(:target_id) { 'p_terraform_state_api_unique_users' } + let(:expected_type) { instance_of(Integer) } + end + end + end + describe 'GET /projects/:id/terraform/state/:name' do subject(:request) { get api(state_path), headers: auth_header } + it_behaves_like 'endpoint with unique user tracking' + context 'without authentication' do let(:auth_header) { basic_auth_header('bad', 'token') } @@ -117,6 +144,8 @@ RSpec.describe API::Terraform::State do subject(:request) { post api(state_path), headers: auth_header, as: :json, params: params } + it_behaves_like 'endpoint with unique user tracking' + context 'when terraform state with a given name is already present' do context 'with maintainer permissions' do let(:current_user) { maintainer } @@ -219,6 +248,8 @@ RSpec.describe API::Terraform::State do describe 'DELETE /projects/:id/terraform/state/:name' do subject(:request) { delete api(state_path), headers: auth_header } + it_behaves_like 'endpoint with unique user tracking' + context 'with maintainer permissions' do let(:current_user) { maintainer } @@ -256,6 +287,8 @@ RSpec.describe API::Terraform::State do subject(:request) { post api("#{state_path}/lock"), headers: auth_header, params: params } + it_behaves_like 'endpoint with unique user tracking' + it 'locks the terraform state' do request @@ -305,6 +338,10 @@ RSpec.describe API::Terraform::State do subject(:request) { delete api("#{state_path}/lock"), headers: auth_header, params: params } + it_behaves_like 'endpoint with unique user tracking' do + let(:lock_id) { 'irrelevant to this test, just needs to be present' } + end + context 'with the correct lock id' do let(:lock_id) { '123-456' } diff --git a/spec/support/matchers/be_sorted.rb b/spec/support/matchers/be_sorted.rb index 1455060fe71..b0ab93efbb2 100644 --- a/spec/support/matchers/be_sorted.rb +++ b/spec/support/matchers/be_sorted.rb @@ -4,18 +4,75 @@ # # By default, this checks that the collection is sorted ascending # but you can check order by specific field and order by passing -# them, eg: +# them, either as arguments, or using the fluent interface, eg: # # ``` +# # Usage examples: +# expect(collection).to be_sorted +# expect(collection).to be_sorted(:field) # expect(collection).to be_sorted(:field, :desc) +# expect(collection).to be_sorted.asc +# expect(collection).to be_sorted.desc.by(&:field) +# expect(collection).to be_sorted.by(&:field).desc +# expect(collection).to be_sorted.by { |x| [x.foo, x.bar] } # ``` -RSpec::Matchers.define :be_sorted do |by, order = :asc| +RSpec::Matchers.define :be_sorted do |on = :itself, order = :asc| + def by(&block) + @comparator = block + self + end + + def asc + @direction = :asc + self + end + + def desc + @direction = :desc + self + end + + def format_with(proc) + @format_with = proc + self + end + + define_method :comparator do + @comparator || on + end + + define_method :descending? do + (@direction || order.to_sym) == :desc + end + + def order(items) + descending? ? items.reverse : items + end + + def sort(items) + items.sort_by(&comparator) + end + match do |actual| - next true unless actual.present? # emtpy collection is sorted + next true unless actual.present? # empty collection is sorted + + actual = actual.to_a if actual.respond_to?(:to_a) && !actual.respond_to?(:sort_by) + + @got = actual + @expected = order(sort(actual)) + + @expected == actual + end + + def failure_message + "Expected #{show(@expected)}, got #{show(@got)}" + end - actual - .then { |collection| by ? collection.sort_by(&by) : collection.sort } - .then { |sorted_collection| order.to_sym == :desc ? sorted_collection.reverse : sorted_collection } - .then { |sorted_collection| sorted_collection == actual } + def show(things) + if @format_with + things.map(&@format_with) + else + things + end end end diff --git a/spec/support/shared_examples/models/concerns/repository_storage_movable_shared_examples.rb b/spec/support/shared_examples/models/concerns/repository_storage_movable_shared_examples.rb index 5a8388d01df..4c617f3ba46 100644 --- a/spec/support/shared_examples/models/concerns/repository_storage_movable_shared_examples.rb +++ b/spec/support/shared_examples/models/concerns/repository_storage_movable_shared_examples.rb @@ -63,7 +63,6 @@ RSpec.shared_examples 'handles repository moves' do context 'and transits to scheduled' do it 'triggers the corresponding repository storage worker' do - skip unless repository_storage_worker # TODO remove after https://gitlab.com/gitlab-org/gitlab/-/issues/218991 is implemented expect(repository_storage_worker).to receive(:perform_async).with(container.id, 'test_second_storage', storage_move.id) storage_move.schedule! @@ -72,8 +71,7 @@ RSpec.shared_examples 'handles repository moves' do end context 'when the transition fails' do - it 'does not trigger ProjectUpdateRepositoryStorageWorker and adds an error' do - skip unless repository_storage_worker # TODO remove after https://gitlab.com/gitlab-org/gitlab/-/issues/218991 is implemented + it 'does not trigger the corresponding repository storage worker and adds an error' do allow(storage_move.container).to receive(:set_repository_read_only!).and_raise(StandardError, 'foobar') expect(repository_storage_worker).not_to receive(:perform_async) diff --git a/spec/support/shared_examples/workers/update_repository_move_shared_examples.rb b/spec/support/shared_examples/workers/update_repository_move_shared_examples.rb new file mode 100644 index 00000000000..babd7cfbbeb --- /dev/null +++ b/spec/support/shared_examples/workers/update_repository_move_shared_examples.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true + +RSpec.shared_examples 'an update storage move worker' do + describe '#perform' do + let(:service) { double(:update_repository_storage_service) } + + before do + allow(Gitlab.config.repositories.storages).to receive(:keys).and_return(%w[default test_second_storage]) + end + + context 'without repository storage move' do + it 'calls the update repository storage service' do + expect(service_klass).to receive(:new).and_return(service) + expect(service).to receive(:execute) + + expect do + subject.perform(container.id, 'test_second_storage') + end.to change(repository_storage_move_klass, :count).by(1) + + storage_move = container.repository_storage_moves.last + expect(storage_move).to have_attributes( + source_storage_name: 'default', + destination_storage_name: 'test_second_storage' + ) + end + end + + context 'with repository storage move' do + it 'calls the update repository storage service' do + expect(service_klass).to receive(:new).and_return(service) + expect(service).to receive(:execute) + + expect do + subject.perform(nil, nil, repository_storage_move.id) + end.not_to change(repository_storage_move_klass, :count) + end + end + end +end diff --git a/spec/support_specs/matchers/be_sorted_spec.rb b/spec/support_specs/matchers/be_sorted_spec.rb new file mode 100644 index 00000000000..e62bc9b36b3 --- /dev/null +++ b/spec/support_specs/matchers/be_sorted_spec.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +require 'fast_spec_helper' + +load File.expand_path('../../../spec/support/matchers/be_sorted.rb', __dir__) + +RSpec.describe 'be_sorted' do + it 'matches empty collections, regardless of arguments' do + expect([]) + .to be_sorted + .and be_sorted.asc + .and be_sorted.desc + .and be_sorted(:foo) + .and be_sorted(:bar) + + expect([].to_set).to be_sorted + expect({}).to be_sorted + end + + it 'matches in both directions' do + expect([1, 2, 3]).to be_sorted.asc + expect([3, 2, 1]).to be_sorted.desc + end + + it 'can match on a projection' do + xs = [['a', 10], ['b', 7], ['c', 4]] + + expect(xs).to be_sorted.asc.by(&:first) + expect(xs).to be_sorted(:first, :asc) + expect(xs).to be_sorted.desc.by(&:second) + expect(xs).to be_sorted(:second, :desc) + end +end diff --git a/spec/views/layouts/header/_new_dropdown.haml_spec.rb b/spec/views/layouts/header/_new_dropdown.haml_spec.rb index cf33ec9884b..01892e72c97 100644 --- a/spec/views/layouts/header/_new_dropdown.haml_spec.rb +++ b/spec/views/layouts/header/_new_dropdown.haml_spec.rb @@ -3,10 +3,42 @@ require 'spec_helper' RSpec.describe 'layouts/header/_new_dropdown' do - let(:user) { create(:user) } + let_it_be(:user) { create(:user) } + + shared_examples_for 'invite member quick link' do + context 'when an experiment is active' do + before do + allow(Gitlab::Experimentation).to receive(:active?).and_return(true) + allow(view).to receive(:experiment_tracking_category_and_group) + allow(view).to receive(:tracking_label).with(user) + end + + context 'with ability to invite members' do + it { is_expected.to have_link('Invite members', href: href) } + + it 'records the experiment' do + subject + + expect(view).to have_received(:experiment_tracking_category_and_group) + .with(:invite_members_new_dropdown, subject: user) + expect(view).to have_received(:tracking_label).with(user) + end + end + + context 'without ability to invite members' do + let(:invite_member) { false } + + it { is_expected.not_to have_link('Invite members') } + end + end + + context 'when experiment is not active' do + it { is_expected.not_to have_link('Invite members') } + end + end context 'group-specific links' do - let(:group) { create(:group) } + let_it_be(:group) { create(:group) } before do stub_current_user(user) @@ -22,25 +54,39 @@ RSpec.describe 'layouts/header/_new_dropdown' do it 'has a "New project" link' do render - expect(rendered).to have_link( - 'New project', - href: new_project_path(namespace_id: group.id) - ) + expect(rendered).to have_link('New project', href: new_project_path(namespace_id: group.id)) end it 'has a "New subgroup" link' do render - expect(rendered).to have_link( - 'New subgroup', - href: new_group_path(parent_id: group.id) - ) + expect(rendered).to have_link('New subgroup', href: new_group_path(parent_id: group.id)) end end + + describe 'invite members quick link' do + let(:href) { group_group_members_path(group) } + let(:invite_member) { true } + + before do + allow(view).to receive(:can?).with(user, :create_projects, group).and_return(true) + allow(view).to receive(:can?).with(user, :admin_group_member, group).and_return(invite_member) + allow(view).to receive(:can_import_members?).and_return(invite_member) + allow(view).to receive(:experiment_enabled?) + end + + subject do + render + + rendered + end + + it_behaves_like 'invite member quick link' + end end context 'project-specific links' do - let(:project) { create(:project, creator: user, namespace: user.namespace) } + let_it_be(:project) { create(:project, creator: user, namespace: user.namespace) } before do assign(:project, project) @@ -54,33 +100,24 @@ RSpec.describe 'layouts/header/_new_dropdown' do it 'has a "New issue" link' do render - expect(rendered).to have_link( - 'New issue', - href: new_project_issue_path(project) - ) + expect(rendered).to have_link('New issue', href: new_project_issue_path(project)) end it 'has a "New merge request" link' do render - expect(rendered).to have_link( - 'New merge request', - href: project_new_merge_request_path(project) - ) + expect(rendered).to have_link('New merge request', href: project_new_merge_request_path(project)) end it 'has a "New snippet" link' do render - expect(rendered).to have_link( - 'New snippet', - href: new_project_snippet_path(project) - ) + expect(rendered).to have_link('New snippet', href: new_project_snippet_path(project)) end end context 'as a Project guest' do - let(:guest) { create(:user) } + let_it_be(:guest) { create(:user) } before do stub_current_user(guest) @@ -96,12 +133,28 @@ RSpec.describe 'layouts/header/_new_dropdown' do it 'has no "New snippet" link' do render - expect(rendered).not_to have_link( - 'New snippet', - href: new_project_snippet_path(project) - ) + expect(rendered).not_to have_link('New snippet', href: new_project_snippet_path(project)) end end + + describe 'invite members quick link' do + let(:invite_member) { true } + let(:href) { project_project_members_path(project) } + + before do + allow(view).to receive(:can_import_members?).and_return(invite_member) + stub_current_user(user) + allow(view).to receive(:experiment_enabled?) + end + + subject do + render + + rendered + end + + it_behaves_like 'invite member quick link' + end end context 'global links' do @@ -128,7 +181,7 @@ RSpec.describe 'layouts/header/_new_dropdown' do end context 'when the user is not allowed to create snippets' do - let(:user) { create(:user, :external)} + let(:user) { create(:user, :external) } it 'has no "New snippet" link' do render diff --git a/spec/workers/project_update_repository_storage_worker_spec.rb b/spec/workers/project_update_repository_storage_worker_spec.rb index f75bb3d1642..490f1f5a2ad 100644 --- a/spec/workers/project_update_repository_storage_worker_spec.rb +++ b/spec/workers/project_update_repository_storage_worker_spec.rb @@ -3,45 +3,13 @@ require 'spec_helper' RSpec.describe ProjectUpdateRepositoryStorageWorker do - let(:project) { create(:project, :repository) } - subject { described_class.new } - describe "#perform" do - let(:service) { double(:update_repository_storage_service) } - - before do - allow(Gitlab.config.repositories.storages).to receive(:keys).and_return(%w[default test_second_storage]) - end - - context 'without repository storage move' do - it "calls the update repository storage service" do - expect(Projects::UpdateRepositoryStorageService).to receive(:new).and_return(service) - expect(service).to receive(:execute) - - expect do - subject.perform(project.id, 'test_second_storage') - end.to change(ProjectRepositoryStorageMove, :count).by(1) - - storage_move = project.repository_storage_moves.last - expect(storage_move).to have_attributes( - source_storage_name: "default", - destination_storage_name: "test_second_storage" - ) - end - end - - context 'with repository storage move' do - let!(:repository_storage_move) { create(:project_repository_storage_move) } - - it "calls the update repository storage service" do - expect(Projects::UpdateRepositoryStorageService).to receive(:new).and_return(service) - expect(service).to receive(:execute) + it_behaves_like 'an update storage move worker' do + let_it_be_with_refind(:container) { create(:project, :repository) } + let_it_be(:repository_storage_move) { create(:project_repository_storage_move) } - expect do - subject.perform(nil, nil, repository_storage_move.id) - end.not_to change(ProjectRepositoryStorageMove, :count) - end - end + let(:service_klass) { Projects::UpdateRepositoryStorageService } + let(:repository_storage_move_klass) { ProjectRepositoryStorageMove } end end diff --git a/spec/workers/snippet_update_repository_storage_worker_spec.rb b/spec/workers/snippet_update_repository_storage_worker_spec.rb new file mode 100644 index 00000000000..a48abe4abf7 --- /dev/null +++ b/spec/workers/snippet_update_repository_storage_worker_spec.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe SnippetUpdateRepositoryStorageWorker do + subject { described_class.new } + + it_behaves_like 'an update storage move worker' do + let_it_be_with_refind(:container) { create(:snippet, :repository) } + let_it_be(:repository_storage_move) { create(:snippet_repository_storage_move) } + + let(:service_klass) { Snippets::UpdateRepositoryStorageService } + let(:repository_storage_move_klass) { SnippetRepositoryStorageMove } + end +end |