diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-03-12 16:26:10 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-03-12 16:26:10 +0000 |
commit | 6653ccc011dec86e5140a5d09ea3b2357eab6714 (patch) | |
tree | 897193f37bcd98152a0ac214f80a3c4cfe1047c5 /spec/graphql/mutations | |
parent | bff35a05aed6a31380a73c39113808fd262c2c37 (diff) | |
download | gitlab-ce-6653ccc011dec86e5140a5d09ea3b2357eab6714.tar.gz |
Add latest changes from gitlab-org/gitlab@13-10-stable-eev13.10.0-rc41
Diffstat (limited to 'spec/graphql/mutations')
6 files changed, 403 insertions, 1 deletions
diff --git a/spec/graphql/mutations/boards/update_spec.rb b/spec/graphql/mutations/boards/update_spec.rb new file mode 100644 index 00000000000..da3dfeecd4d --- /dev/null +++ b/spec/graphql/mutations/boards/update_spec.rb @@ -0,0 +1,57 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Mutations::Boards::Update do + let_it_be(:project) { create(:project) } + let_it_be(:user) { create(:user) } + let_it_be(:board) { create(:board, project: project) } + + let(:mutation) { described_class.new(object: nil, context: { current_user: user }, field: nil) } + let(:mutated_board) { subject[:board] } + + let(:mutation_params) do + { + id: board.to_global_id, + hide_backlog_list: true, + hide_closed_list: false + } + end + + subject { mutation.resolve(**mutation_params) } + + specify { expect(described_class).to require_graphql_authorizations(:admin_issue_board) } + + describe '#resolve' do + context 'when the user cannot admin the board' do + it 'raises an error' do + expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable) + end + end + + context 'with invalid params' do + it 'raises an error' do + mutation_params[:id] = project.to_global_id + + expect { subject }.to raise_error(::GraphQL::CoercionError) + end + end + + context 'when user can update board' do + before do + board.resource_parent.add_reporter(user) + end + + it 'updates board with correct values' do + expected_attributes = { + hide_backlog_list: true, + hide_closed_list: false + } + + subject + + expect(board.reload).to have_attributes(expected_attributes) + end + end + end +end diff --git a/spec/graphql/mutations/concerns/mutations/can_mutate_spammable_spec.rb b/spec/graphql/mutations/concerns/mutations/can_mutate_spammable_spec.rb index ee8db7a1f31..8d1fce406fa 100644 --- a/spec/graphql/mutations/concerns/mutations/can_mutate_spammable_spec.rb +++ b/spec/graphql/mutations/concerns/mutations/can_mutate_spammable_spec.rb @@ -30,7 +30,7 @@ RSpec.describe Mutations::CanMutateSpammable do end it 'merges in spam action fields from spammable' do - result = subject.send(:with_spam_action_fields, spammable) do + result = subject.send(:with_spam_action_response_fields, spammable) do { other_field: true } end expect(result) diff --git a/spec/graphql/mutations/custom_emoji/create_spec.rb b/spec/graphql/mutations/custom_emoji/create_spec.rb new file mode 100644 index 00000000000..118c5d67188 --- /dev/null +++ b/spec/graphql/mutations/custom_emoji/create_spec.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Mutations::CustomEmoji::Create do + let_it_be(:group) { create(:group) } + let_it_be(:user) { create(:user) } + let(:args) { { group_path: group.full_path, name: 'tanuki', url: 'https://about.gitlab.com/images/press/logo/png/gitlab-icon-rgb.png' } } + + before do + group.add_developer(user) + end + + describe '#resolve' do + subject(:resolve) { described_class.new(object: nil, context: { current_user: user }, field: nil).resolve(**args) } + + it 'creates the custom emoji' do + expect { resolve }.to change(CustomEmoji, :count).by(1) + end + + it 'sets the creator to be the user who added the emoji' do + resolve + + expect(CustomEmoji.last.creator).to eq(user) + end + end +end diff --git a/spec/graphql/mutations/merge_requests/accept_spec.rb b/spec/graphql/mutations/merge_requests/accept_spec.rb new file mode 100644 index 00000000000..db75c64a447 --- /dev/null +++ b/spec/graphql/mutations/merge_requests/accept_spec.rb @@ -0,0 +1,171 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Mutations::MergeRequests::Accept do + include AfterNextHelpers + + let_it_be(:user) { create(:user) } + let(:project) { create(:project, :public, :repository) } + + subject(:mutation) { described_class.new(context: context, object: nil, field: nil) } + + let_it_be(:context) do + GraphQL::Query::Context.new( + query: OpenStruct.new(schema: GitlabSchema), + values: { current_user: user }, + object: nil + ) + end + + before do + project.repository.expire_all_method_caches + end + + describe '#resolve' do + before do + project.add_maintainer(user) + end + + def common_args(merge_request) + { + project_path: project.full_path, + iid: merge_request.iid.to_s, + sha: merge_request.diff_head_sha, + squash: false # default value + } + end + + it 'merges the merge request' do + merge_request = create(:merge_request, source_project: project) + + result = mutation.resolve(**common_args(merge_request)) + + expect(result).to include(errors: be_empty, merge_request: be_merged) + end + + it 'rejects the mutation if the SHA is a mismatch' do + merge_request = create(:merge_request, source_project: project) + args = common_args(merge_request).merge(sha: 'not a good sha') + + result = mutation.resolve(**args) + + expect(result).not_to include(merge_request: be_merged) + expect(result).to include(errors: [described_class::SHA_MISMATCH]) + end + + it 'respects the merge commit message' do + merge_request = create(:merge_request, source_project: project) + args = common_args(merge_request).merge(commit_message: 'my super custom message') + + result = mutation.resolve(**args) + + expect(result).to include(merge_request: be_merged) + expect(project.repository.commit(merge_request.target_branch)).to have_attributes( + message: args[:commit_message] + ) + end + + it 'respects the squash flag' do + merge_request = create(:merge_request, source_project: project) + args = common_args(merge_request).merge(squash: true) + + result = mutation.resolve(**args) + + expect(result).to include(merge_request: be_merged) + expect(result[:merge_request].squash_commit_sha).to be_present + end + + it 'respects the squash_commit_message argument' do + merge_request = create(:merge_request, source_project: project) + args = common_args(merge_request).merge(squash: true, squash_commit_message: 'squish') + + result = mutation.resolve(**args) + sha = result[:merge_request].squash_commit_sha + + expect(result).to include(merge_request: be_merged) + expect(project.repository.commit(sha)).to have_attributes(message: "squish\n") + end + + it 'respects the should_remove_source_branch argument when true' do + b = project.repository.add_branch(user, generate(:branch), 'master') + merge_request = create(:merge_request, source_branch: b.name, source_project: project) + args = common_args(merge_request).merge(should_remove_source_branch: true) + + expect(::MergeRequests::DeleteSourceBranchWorker).to receive(:perform_async) + + result = mutation.resolve(**args) + + expect(result).to include(merge_request: be_merged) + end + + it 'respects the should_remove_source_branch argument when false' do + b = project.repository.add_branch(user, generate(:branch), 'master') + merge_request = create(:merge_request, source_branch: b.name, source_project: project) + args = common_args(merge_request).merge(should_remove_source_branch: false) + + expect(::MergeRequests::DeleteSourceBranchWorker).not_to receive(:perform_async) + + result = mutation.resolve(**args) + + expect(result).to include(merge_request: be_merged) + end + + it 'rejects unmergeable MRs' do + merge_request = create(:merge_request, :closed, source_project: project) + args = common_args(merge_request) + + result = mutation.resolve(**args) + + expect(result).not_to include(merge_request: be_merged) + expect(result).to include(errors: [described_class::NOT_MERGEABLE]) + end + + it 'rejects merges when we cannot validate the hooks' do + merge_request = create(:merge_request, source_project: project) + args = common_args(merge_request) + expect_next(::MergeRequests::MergeService) + .to receive(:hooks_validation_pass?).with(merge_request).and_return(false) + + result = mutation.resolve(**args) + + expect(result).not_to include(merge_request: be_merged) + expect(result).to include(errors: [described_class::HOOKS_VALIDATION_ERROR]) + end + + it 'rejects merges when the merge service returns an error' do + merge_request = create(:merge_request, source_project: project) + args = common_args(merge_request) + expect_next(::MergeRequests::MergeService) + .to receive(:execute).with(merge_request).and_return(:failed) + + result = mutation.resolve(**args) + + expect(result).not_to include(merge_request: be_merged) + expect(result).to include(errors: [described_class::MERGE_FAILED]) + end + + it 'rejects merges when the merge service raises merge error' do + merge_request = create(:merge_request, source_project: project) + args = common_args(merge_request) + expect_next(::MergeRequests::MergeService) + .to receive(:execute).and_raise(::MergeRequests::MergeBaseService::MergeError, 'boom') + + result = mutation.resolve(**args) + + expect(result).not_to include(merge_request: be_merged) + expect(result).to include(errors: ['boom']) + end + + it "can use the MERGE_WHEN_PIPELINE_SUCCEEDS strategy" do + enum = ::Types::MergeStrategyEnum.values['MERGE_WHEN_PIPELINE_SUCCEEDS'] + merge_request = create(:merge_request, :with_head_pipeline, source_project: project) + args = common_args(merge_request).merge(auto_merge_strategy: enum.value) + + result = mutation.resolve(**args) + + expect(result).not_to include(merge_request: be_merged) + expect(result).to include(errors: be_empty, merge_request: be_auto_merge_enabled) + end + end +end diff --git a/spec/graphql/mutations/release_asset_links/create_spec.rb b/spec/graphql/mutations/release_asset_links/create_spec.rb new file mode 100644 index 00000000000..089bc3d3276 --- /dev/null +++ b/spec/graphql/mutations/release_asset_links/create_spec.rb @@ -0,0 +1,105 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Mutations::ReleaseAssetLinks::Create do + include GraphqlHelpers + + let_it_be(:project) { create(:project, :private, :repository) } + let_it_be(:release) { create(:release, project: project, tag: 'v13.10') } + let_it_be(:reporter) { create(:user).tap { |u| project.add_reporter(u) } } + let_it_be(:developer) { create(:user).tap { |u| project.add_developer(u) } } + + let(:current_user) { developer } + let(:context) { { current_user: current_user } } + let(:project_path) { project.full_path } + let(:tag) { release.tag } + let(:name) { 'awesome-app.dmg' } + let(:url) { 'https://example.com/download/awesome-app.dmg' } + let(:filepath) { '/binaries/awesome-app.dmg' } + + let(:args) do + { + project_path: project_path, + tag_name: tag, + name: name, + direct_asset_path: filepath, + url: url + } + end + + let(:last_release_link) { release.links.last } + + describe '#resolve' do + subject do + resolve(described_class, obj: project, args: args, ctx: context) + end + + context 'when the user has access and no validation errors occur' do + it 'creates a new release asset link', :aggregate_failures do + expect(subject).to eq({ + link: release.reload.links.first, + errors: [] + }) + + expect(release.links.length).to be(1) + + expect(last_release_link.name).to eq(name) + expect(last_release_link.url).to eq(url) + expect(last_release_link.filepath).to eq(filepath) + end + end + + context "when the user doesn't have access to the project" do + let(:current_user) { reporter } + + it 'raises an error' do + expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable) + end + end + + context "when the project doesn't exist" do + let(:project_path) { 'project/that/does/not/exist' } + + it 'raises an error' do + expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable) + end + end + + context "when a validation errors occur" do + shared_examples 'returns errors-as-data' do |expected_messages| + it { expect(subject[:errors]).to eq(expected_messages) } + end + + context "when the release doesn't exist" do + let(:tag) { "nonexistent-tag" } + + it_behaves_like 'returns errors-as-data', ['Release with tag "nonexistent-tag" was not found'] + end + + context 'when the URL is badly formatted' do + let(:url) { 'badly-formatted-url' } + + it_behaves_like 'returns errors-as-data', ["Url is blocked: Only allowed schemes are http, https, ftp"] + end + + context 'when the name is not provided' do + let(:name) { '' } + + it_behaves_like 'returns errors-as-data', ["Name can't be blank"] + end + + context 'when the link already exists' do + let!(:existing_release_link) do + create(:release_link, release: release, name: name, url: url, filepath: filepath) + end + + it_behaves_like 'returns errors-as-data', [ + "Url has already been taken", + "Name has already been taken", + "Filepath has already been taken" + ] + end + end + end +end diff --git a/spec/graphql/mutations/user_callouts/create_spec.rb b/spec/graphql/mutations/user_callouts/create_spec.rb new file mode 100644 index 00000000000..93f227d8b82 --- /dev/null +++ b/spec/graphql/mutations/user_callouts/create_spec.rb @@ -0,0 +1,42 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Mutations::UserCallouts::Create do + let(:current_user) { create(:user) } + let(:mutation) { described_class.new(object: nil, context: { current_user: current_user }, field: nil) } + + describe '#resolve' do + subject(:resolve) { mutation.resolve(feature_name: feature_name) } + + context 'when feature name is not supported' do + let(:feature_name) { 'not_supported' } + + it 'does not create a user callout' do + expect { resolve }.not_to change(UserCallout, :count).from(0) + end + + it 'returns error about feature name not being supported' do + expect(resolve[:errors]).to include("Feature name is not included in the list") + end + end + + context 'when feature name is supported' do + let(:feature_name) { UserCallout.feature_names.each_key.first.to_s } + + it 'creates a user callout' do + expect { resolve }.to change(UserCallout, :count).from(0).to(1) + end + + it 'sets dismissed_at for the user callout' do + freeze_time do + expect(resolve[:user_callout].dismissed_at).to eq(Time.current) + end + end + + it 'has no errors' do + expect(resolve[:errors]).to be_empty + end + end + end +end |