summaryrefslogtreecommitdiff
path: root/spec/graphql/mutations
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2021-03-12 16:26:10 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2021-03-12 16:26:10 +0000
commit6653ccc011dec86e5140a5d09ea3b2357eab6714 (patch)
tree897193f37bcd98152a0ac214f80a3c4cfe1047c5 /spec/graphql/mutations
parentbff35a05aed6a31380a73c39113808fd262c2c37 (diff)
downloadgitlab-ce-6653ccc011dec86e5140a5d09ea3b2357eab6714.tar.gz
Add latest changes from gitlab-org/gitlab@13-10-stable-eev13.10.0-rc41
Diffstat (limited to 'spec/graphql/mutations')
-rw-r--r--spec/graphql/mutations/boards/update_spec.rb57
-rw-r--r--spec/graphql/mutations/concerns/mutations/can_mutate_spammable_spec.rb2
-rw-r--r--spec/graphql/mutations/custom_emoji/create_spec.rb27
-rw-r--r--spec/graphql/mutations/merge_requests/accept_spec.rb171
-rw-r--r--spec/graphql/mutations/release_asset_links/create_spec.rb105
-rw-r--r--spec/graphql/mutations/user_callouts/create_spec.rb42
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