diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-12-17 11:59:07 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-12-17 11:59:07 +0000 |
commit | 8b573c94895dc0ac0e1d9d59cf3e8745e8b539ca (patch) | |
tree | 544930fb309b30317ae9797a9683768705d664c4 /spec/graphql/mutations | |
parent | 4b1de649d0168371549608993deac953eb692019 (diff) | |
download | gitlab-ce-8b573c94895dc0ac0e1d9d59cf3e8745e8b539ca.tar.gz |
Add latest changes from gitlab-org/gitlab@13-7-stable-eev13.7.0-rc42
Diffstat (limited to 'spec/graphql/mutations')
18 files changed, 529 insertions, 33 deletions
diff --git a/spec/graphql/mutations/alert_management/create_alert_issue_spec.rb b/spec/graphql/mutations/alert_management/create_alert_issue_spec.rb index e6a7434d579..47ee338ad34 100644 --- a/spec/graphql/mutations/alert_management/create_alert_issue_spec.rb +++ b/spec/graphql/mutations/alert_management/create_alert_issue_spec.rb @@ -28,6 +28,7 @@ RSpec.describe Mutations::AlertManagement::CreateAlertIssue do end it_behaves_like 'an incident management tracked event', :incident_management_incident_created + it_behaves_like 'an incident management tracked event', :incident_management_alert_create_incident end context 'when CreateAlertIssue responds with an error' do diff --git a/spec/graphql/mutations/alert_management/http_integration/destroy_spec.rb b/spec/graphql/mutations/alert_management/http_integration/destroy_spec.rb index f74f9186743..acd7070d0d3 100644 --- a/spec/graphql/mutations/alert_management/http_integration/destroy_spec.rb +++ b/spec/graphql/mutations/alert_management/http_integration/destroy_spec.rb @@ -11,7 +11,7 @@ RSpec.describe Mutations::AlertManagement::HttpIntegration::Destroy do specify { expect(described_class).to require_graphql_authorizations(:admin_operations) } describe '#resolve' do - subject(:resolve) { mutation_for(project, current_user).resolve(args) } + subject(:resolve) { mutation_for(project, current_user).resolve(**args) } context 'user has access to project' do before do diff --git a/spec/graphql/mutations/alert_management/http_integration/reset_token_spec.rb b/spec/graphql/mutations/alert_management/http_integration/reset_token_spec.rb index d3ffb2abb47..96974c2aa6f 100644 --- a/spec/graphql/mutations/alert_management/http_integration/reset_token_spec.rb +++ b/spec/graphql/mutations/alert_management/http_integration/reset_token_spec.rb @@ -11,7 +11,7 @@ RSpec.describe Mutations::AlertManagement::HttpIntegration::ResetToken do specify { expect(described_class).to require_graphql_authorizations(:admin_operations) } describe '#resolve' do - subject(:resolve) { mutation_for(project, current_user).resolve(args) } + subject(:resolve) { mutation_for(project, current_user).resolve(**args) } context 'user has sufficient access to project' do before do diff --git a/spec/graphql/mutations/alert_management/prometheus_integration/reset_token_spec.rb b/spec/graphql/mutations/alert_management/prometheus_integration/reset_token_spec.rb index 45d92695e06..ddf23909035 100644 --- a/spec/graphql/mutations/alert_management/prometheus_integration/reset_token_spec.rb +++ b/spec/graphql/mutations/alert_management/prometheus_integration/reset_token_spec.rb @@ -11,7 +11,7 @@ RSpec.describe Mutations::AlertManagement::PrometheusIntegration::ResetToken do specify { expect(described_class).to require_graphql_authorizations(:admin_project) } describe '#resolve' do - subject(:resolve) { mutation_for(project, current_user).resolve(args) } + subject(:resolve) { mutation_for(project, current_user).resolve(**args) } context 'user has sufficient access to project' do before do diff --git a/spec/graphql/mutations/alert_management/update_alert_status_spec.rb b/spec/graphql/mutations/alert_management/update_alert_status_spec.rb index 08761ce64c2..8465393f299 100644 --- a/spec/graphql/mutations/alert_management/update_alert_status_spec.rb +++ b/spec/graphql/mutations/alert_management/update_alert_status_spec.rb @@ -12,7 +12,7 @@ RSpec.describe Mutations::AlertManagement::UpdateAlertStatus do specify { expect(described_class).to require_graphql_authorizations(:update_alert_management_alert) } describe '#resolve' do - subject(:resolve) { mutation_for(project, current_user).resolve(args) } + subject(:resolve) { mutation_for(project, current_user).resolve(**args) } context 'user has access to project' do before do diff --git a/spec/graphql/mutations/boards/issues/issue_move_list_spec.rb b/spec/graphql/mutations/boards/issues/issue_move_list_spec.rb index 71c43ed826c..24104a20465 100644 --- a/spec/graphql/mutations/boards/issues/issue_move_list_spec.rb +++ b/spec/graphql/mutations/boards/issues/issue_move_list_spec.rb @@ -34,18 +34,18 @@ RSpec.describe Mutations::Boards::Issues::IssueMoveList do end subject do - mutation.resolve(params.merge(move_params)) + mutation.resolve(**params.merge(move_params)) end describe '#ready?' do it 'raises an error if required arguments are missing' do - expect { mutation.ready?(params) } + expect { mutation.ready?(**params) } .to raise_error(Gitlab::Graphql::Errors::ArgumentError, "At least one of the arguments " \ "fromListId, toListId, afterId or beforeId is required") end it 'raises an error if only one of fromListId and toListId is present' do - expect { mutation.ready?(params.merge(from_list_id: list1.id)) } + expect { mutation.ready?(**params.merge(from_list_id: list1.id)) } .to raise_error(Gitlab::Graphql::Errors::ArgumentError, 'Both fromListId and toListId must be present' ) @@ -73,18 +73,6 @@ RSpec.describe Mutations::Boards::Issues::IssueMoveList do it_behaves_like 'raises a resource not available error' end - - context 'when user cannot access board' do - let(:board) { create(:board, group: create(:group, :private)) } - - it_behaves_like 'raises a resource not available error' - end - - context 'when passing board_id as nil' do - let(:board) { nil } - - it_behaves_like 'raises a resource not available error' - end end end end diff --git a/spec/graphql/mutations/boards/lists/create_spec.rb b/spec/graphql/mutations/boards/lists/create_spec.rb index b1fe9911c7b..894dd1f34b4 100644 --- a/spec/graphql/mutations/boards/lists/create_spec.rb +++ b/spec/graphql/mutations/boards/lists/create_spec.rb @@ -23,12 +23,12 @@ RSpec.describe Mutations::Boards::Lists::Create do describe '#ready?' do it 'raises an error if required arguments are missing' do - expect { mutation.ready?({ board_id: 'some id' }) } + expect { mutation.ready?(board_id: 'some id') } .to raise_error(Gitlab::Graphql::Errors::ArgumentError, /one and only one of/) end it 'raises an error if too many required arguments are specified' do - expect { mutation.ready?({ board_id: 'some id', backlog: true, label_id: 'some label' }) } + expect { mutation.ready?(board_id: 'some id', backlog: true, label_id: 'some label') } .to raise_error(Gitlab::Graphql::Errors::ArgumentError, /one and only one of/) end end @@ -68,9 +68,8 @@ RSpec.describe Mutations::Boards::Lists::Create do context 'when label not found' do let(:list_create_params) { { label_id: "gid://gitlab/Label/#{non_existing_record_id}" } } - it 'raises an error' do - expect { subject } - .to raise_error(Gitlab::Graphql::Errors::ArgumentError, 'Label not found!') + it 'returns an error' do + expect(subject[:errors]).to include 'Label not found' end end end diff --git a/spec/graphql/mutations/concerns/mutations/finds_by_gid_spec.rb b/spec/graphql/mutations/concerns/mutations/finds_by_gid_spec.rb new file mode 100644 index 00000000000..37e0fd611e4 --- /dev/null +++ b/spec/graphql/mutations/concerns/mutations/finds_by_gid_spec.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Mutations::FindsByGid do + include GraphqlHelpers + + let(:mutation_class) do + Class.new(Mutations::BaseMutation) do + authorize :read_user + + include Mutations::FindsByGid + end + end + + let(:query) { double('Query', schema: GitlabSchema) } + let(:context) { GraphQL::Query::Context.new(query: query, object: nil, values: { current_user: user }) } + let(:user) { create(:user) } + let(:gid) { user.to_global_id } + + subject(:mutation) { mutation_class.new(object: nil, context: context, field: nil) } + + it 'calls GitlabSchema.find_by_gid to find objects during authorized_find!' do + expect(mutation.authorized_find!(id: gid)).to eq(user) + end +end diff --git a/spec/graphql/mutations/container_expiration_policies/update_spec.rb b/spec/graphql/mutations/container_expiration_policies/update_spec.rb index 9c6016e0af4..e22fb951172 100644 --- a/spec/graphql/mutations/container_expiration_policies/update_spec.rb +++ b/spec/graphql/mutations/container_expiration_policies/update_spec.rb @@ -14,7 +14,7 @@ RSpec.describe Mutations::ContainerExpirationPolicies::Update do specify { expect(described_class).to require_graphql_authorizations(:destroy_container_image) } describe '#resolve' do - subject { described_class.new(object: project, context: { current_user: user }, field: nil).resolve(params) } + subject { described_class.new(object: project, context: { current_user: user }, field: nil).resolve(**params) } RSpec.shared_examples 'returning a success' do it 'returns the container expiration policy with no errors' do diff --git a/spec/graphql/mutations/container_repositories/destroy_tags_spec.rb b/spec/graphql/mutations/container_repositories/destroy_tags_spec.rb new file mode 100644 index 00000000000..f22d9ffe753 --- /dev/null +++ b/spec/graphql/mutations/container_repositories/destroy_tags_spec.rb @@ -0,0 +1,92 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Mutations::ContainerRepositories::DestroyTags do + include_context 'container repository delete tags service shared context' + using RSpec::Parameterized::TableSyntax + + let(:id) { repository.to_global_id.to_s } + + specify { expect(described_class).to require_graphql_authorizations(:destroy_container_image) } + + describe '#resolve' do + let(:tags) { %w[A C D E] } + + subject do + described_class.new(object: nil, context: { current_user: user }, field: nil) + .resolve(id: id, tag_names: tags) + end + + shared_examples 'destroying container repository tags' do + before do + stub_delete_reference_requests(tags) + expect_delete_tag_by_names(tags) + allow_next_instance_of(ContainerRegistry::Client) do |client| + allow(client).to receive(:supports_tag_delete?).and_return(true) + end + end + + it 'destroys the container repository tags' do + expect(Projects::ContainerRepository::DeleteTagsService) + .to receive(:new).and_call_original + + expect(subject).to eq(errors: [], deleted_tag_names: tags) + end + + it 'creates a package event' do + expect(::Packages::CreateEventService) + .to receive(:new).with(nil, user, event_name: :delete_tag_bulk, scope: :tag).and_call_original + expect { subject }.to change { ::Packages::Event.count }.by(1) + end + end + + shared_examples 'denying access to container respository' do + it 'raises an error' do + expect(::Projects::ContainerRepository::DeleteTagsService).not_to receive(:new) + + expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable) + end + end + + context 'with valid id' do + where(:user_role, :shared_examples_name) do + :maintainer | 'destroying container repository tags' + :developer | 'destroying container repository tags' + :reporter | 'denying access to container respository' + :guest | 'denying access to container respository' + :anonymous | 'denying access to container respository' + end + + with_them do + before do + project.send("add_#{user_role}", user) unless user_role == :anonymous + end + + it_behaves_like params[:shared_examples_name] + end + end + + context 'with invalid id' do + let(:id) { 'gid://gitlab/ContainerRepository/5555' } + + it_behaves_like 'denying access to container respository' + end + + context 'with service error' do + before do + project.add_maintainer(user) + allow_next_instance_of(Projects::ContainerRepository::DeleteTagsService) do |service| + allow(service).to receive(:execute).and_return(message: 'could not delete tags', status: :error) + end + end + + it { is_expected.to eq(errors: ['could not delete tags'], deleted_tag_names: []) } + + it 'does not create a package event' do + expect(::Packages::CreateEventService).not_to receive(:new) + expect { subject }.not_to change { ::Packages::Event.count } + end + end + end +end diff --git a/spec/graphql/mutations/discussions/toggle_resolve_spec.rb b/spec/graphql/mutations/discussions/toggle_resolve_spec.rb index 2e5d41a8f1e..162b1249ab5 100644 --- a/spec/graphql/mutations/discussions/toggle_resolve_spec.rb +++ b/spec/graphql/mutations/discussions/toggle_resolve_spec.rb @@ -11,7 +11,7 @@ RSpec.describe Mutations::Discussions::ToggleResolve do describe '#resolve' do subject do - mutation.resolve({ id: id_arg, resolve: resolve_arg }) + mutation.resolve(id: id_arg, resolve: resolve_arg) end let(:id_arg) { discussion.to_global_id.to_s } diff --git a/spec/graphql/mutations/environments/canary_ingress/update_spec.rb b/spec/graphql/mutations/environments/canary_ingress/update_spec.rb new file mode 100644 index 00000000000..c022828cf09 --- /dev/null +++ b/spec/graphql/mutations/environments/canary_ingress/update_spec.rb @@ -0,0 +1,66 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Mutations::Environments::CanaryIngress::Update do + let_it_be(:project) { create(:project) } + let_it_be(:environment) { create(:environment, project: project) } + let_it_be(:maintainer) { create(:user) } + let_it_be(:reporter) { create(:user) } + let(:user) { maintainer } + + subject(:mutation) { described_class.new(object: nil, context: { current_user: user }, field: nil) } + + before_all do + project.add_maintainer(maintainer) + project.add_reporter(reporter) + end + + describe '#resolve' do + subject { mutation.resolve(id: environment_id, weight: weight) } + + let(:environment_id) { environment.to_global_id.to_s } + let(:weight) { 50 } + let(:update_service) { double('update_service') } + + before do + allow(Environments::CanaryIngress::UpdateService).to receive(:new) { update_service } + end + + context 'when service execution succeeded' do + before do + allow(update_service).to receive(:execute_async) { { status: :success } } + end + + it 'returns no errors' do + expect(subject[:errors]).to be_empty + end + end + + context 'when service encounters a problem' do + before do + allow(update_service).to receive(:execute_async) { { status: :error, message: 'something went wrong' } } + end + + it 'returns an error' do + expect(subject[:errors]).to eq(['something went wrong']) + end + end + + context 'when environment is not found' do + let(:environment_id) { non_existing_record_id.to_s } + + it 'raises an error' do + expect { subject }.to raise_error(GraphQL::CoercionError) + end + end + + context 'when user is reporter who does not have permission to access the environment' do + let(:user) { reporter } + + it 'raises an error' do + expect { subject }.to raise_error("The resource that you are attempting to access does not exist or you don't have permission to perform this action") + end + end + end +end diff --git a/spec/graphql/mutations/issues/create_spec.rb b/spec/graphql/mutations/issues/create_spec.rb index 57658f6b358..422ad40a9cb 100644 --- a/spec/graphql/mutations/issues/create_spec.rb +++ b/spec/graphql/mutations/issues/create_spec.rb @@ -51,7 +51,7 @@ RSpec.describe Mutations::Issues::Create do project.add_guest(assignee2) end - subject { mutation.resolve(mutation_params) } + subject { mutation.resolve(**mutation_params) } context 'when the user does not have permission to create an issue' do it 'raises an error' do @@ -117,7 +117,7 @@ RSpec.describe Mutations::Issues::Create do end it 'raises exception when mutually exclusive params are given' do - expect { mutation.ready?(mutation_params) } + expect { mutation.ready?(**mutation_params) } .to raise_error(Gitlab::Graphql::Errors::ArgumentError, /one and only one of/) end end @@ -128,7 +128,7 @@ RSpec.describe Mutations::Issues::Create do end it 'raises exception when mutually exclusive params are given' do - expect { mutation.ready?(mutation_params) } + expect { mutation.ready?(**mutation_params) } .to raise_error(Gitlab::Graphql::Errors::ArgumentError, /to resolve a discussion please also provide `merge_request_to_resolve_discussions_of` parameter/) end end @@ -139,7 +139,7 @@ RSpec.describe Mutations::Issues::Create do end it 'raises exception when mutually exclusive params are given' do - expect { mutation.ready?(mutation_params) }.not_to raise_error + expect { mutation.ready?(**mutation_params) }.not_to raise_error end end end diff --git a/spec/graphql/mutations/issues/update_spec.rb b/spec/graphql/mutations/issues/update_spec.rb index ce1eb874bcf..f10e257e153 100644 --- a/spec/graphql/mutations/issues/update_spec.rb +++ b/spec/graphql/mutations/issues/update_spec.rb @@ -33,7 +33,7 @@ RSpec.describe Mutations::Issues::Update do }.merge(expected_attributes) end - subject { mutation.resolve(mutation_params) } + subject { mutation.resolve(**mutation_params) } it_behaves_like 'permission level for issue mutation is correctly verified' diff --git a/spec/graphql/mutations/labels/create_spec.rb b/spec/graphql/mutations/labels/create_spec.rb index 8b284816d63..b2dd94f31bb 100644 --- a/spec/graphql/mutations/labels/create_spec.rb +++ b/spec/graphql/mutations/labels/create_spec.rb @@ -58,7 +58,7 @@ RSpec.describe Mutations::Labels::Create do end describe '#ready?' do - subject { mutation.ready?(attributes.merge(extra_params)) } + subject { mutation.ready?(**attributes.merge(extra_params)) } context 'when passing both project_path and group_path' do let(:extra_params) { { project_path: 'foo', group_path: 'bar' } } diff --git a/spec/graphql/mutations/notes/reposition_image_diff_note_spec.rb b/spec/graphql/mutations/notes/reposition_image_diff_note_spec.rb index 8c22e1a1cb6..d88b196cbff 100644 --- a/spec/graphql/mutations/notes/reposition_image_diff_note_spec.rb +++ b/spec/graphql/mutations/notes/reposition_image_diff_note_spec.rb @@ -7,7 +7,7 @@ RSpec.describe Mutations::Notes::RepositionImageDiffNote do describe '#resolve' do subject do - mutation.resolve({ note: note, position: new_position }) + mutation.resolve(note: note, position: new_position) end let_it_be(:noteable) { create(:merge_request) } diff --git a/spec/graphql/mutations/releases/delete_spec.rb b/spec/graphql/mutations/releases/delete_spec.rb new file mode 100644 index 00000000000..bedb72b002c --- /dev/null +++ b/spec/graphql/mutations/releases/delete_spec.rb @@ -0,0 +1,92 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Mutations::Releases::Delete do + let_it_be(:project) { create(:project, :public, :repository) } + let_it_be(:non_project_member) { create(:user) } + let_it_be(:developer) { create(:user) } + let_it_be(:maintainer) { create(:user) } + let_it_be(:tag) { 'v1.1.0'} + let_it_be(:release) { create(:release, project: project, tag: tag) } + + let(:mutation) { described_class.new(object: nil, context: { current_user: current_user }, field: nil) } + + let(:mutation_arguments) do + { + project_path: project.full_path, + tag: tag + } + end + + before do + project.add_developer(developer) + project.add_maintainer(maintainer) + end + + shared_examples 'unauthorized or not found error' do + it 'raises a Gitlab::Graphql::Errors::ResourceNotAvailable error' do + expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable, "The resource that you are attempting to access does not exist or you don't have permission to perform this action") + end + end + + describe '#resolve' do + subject(:resolve) do + mutation.resolve(**mutation_arguments) + end + + context 'when the current user has access to create releases' do + let(:current_user) { maintainer } + + it 'deletes the release' do + expect { subject }.to change { Release.count }.by(-1) + end + + it 'returns the deleted release' do + expect(subject[:release].tag).to eq(tag) + end + + it 'does not remove the Git tag associated with the deleted release' do + expect { subject }.not_to change { Project.find_by_id(project.id).repository.tag_count } + end + + it 'returns no errors' do + expect(subject[:errors]).to eq([]) + end + + context 'validation' do + context 'when the release does not exist' do + let(:mutation_arguments) { super().merge(tag: 'not-a-real-release') } + + it 'returns the release as nil' do + expect(subject[:release]).to be_nil + end + + it 'returns an errors-at-data message' do + expect(subject[:errors]).to eq(['Release does not exist']) + end + end + + context 'when the project does not exist' do + let(:mutation_arguments) { super().merge(project_path: 'not/a/real/path') } + + it_behaves_like 'unauthorized or not found error' + end + end + end + + context "when the current user doesn't have access to update releases" do + context 'when the user is a developer' do + let(:current_user) { developer } + + it_behaves_like 'unauthorized or not found error' + end + + context 'when the user is a non-project member' do + let(:current_user) { non_project_member } + + it_behaves_like 'unauthorized or not found error' + end + end + end +end diff --git a/spec/graphql/mutations/releases/update_spec.rb b/spec/graphql/mutations/releases/update_spec.rb new file mode 100644 index 00000000000..0406e9c96f3 --- /dev/null +++ b/spec/graphql/mutations/releases/update_spec.rb @@ -0,0 +1,232 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Mutations::Releases::Update do + let_it_be(:project) { create(:project, :public, :repository) } + let_it_be(:milestone_12_3) { create(:milestone, project: project, title: '12.3') } + let_it_be(:milestone_12_4) { create(:milestone, project: project, title: '12.4') } + let_it_be(:reporter) { create(:user) } + let_it_be(:developer) { create(:user) } + + let_it_be(:tag) { 'v1.1.0'} + let_it_be(:name) { 'Version 1.0'} + let_it_be(:description) { 'The first release :rocket:' } + let_it_be(:released_at) { Time.parse('2018-12-10').utc } + let_it_be(:created_at) { Time.parse('2018-11-05').utc } + let_it_be(:milestones) { [milestone_12_3.title, milestone_12_4.title] } + + let_it_be(:release) do + create(:release, project: project, tag: tag, name: name, + description: description, released_at: released_at, + created_at: created_at, milestones: [milestone_12_3, milestone_12_4]) + end + + let(:mutation) { described_class.new(object: nil, context: { current_user: current_user }, field: nil) } + + let(:mutation_arguments) do + { + project_path: project.full_path, + tag: tag + } + end + + around do |example| + freeze_time { example.run } + end + + before do + project.add_reporter(reporter) + project.add_developer(developer) + end + + shared_examples 'no changes to the release except for the' do |except_for| + it 'does not change other release properties' do + expect(updated_release.project).to eq(project) + expect(updated_release.tag).to eq(tag) + + expect(updated_release.name).to eq(name) unless except_for == :name + expect(updated_release.description).to eq(description) unless except_for == :description + expect(updated_release.released_at).to eq(released_at) unless except_for == :released_at + + # Right now the milestones are returned in a non-deterministic order. + # Because of this, we need to allow for milestones to be returned in any order. + # Once https://gitlab.com/gitlab-org/gitlab/-/issues/259012 has been + # fixed, this can be updated to expect a specific order. + expect(updated_release.milestones).to match_array([milestone_12_3, milestone_12_4]) unless except_for == :milestones + end + end + + shared_examples 'validation error with message' do |message| + it 'returns the updated release as nil' do + expect(updated_release).to be_nil + end + + it 'returns a validation error' do + expect(subject[:errors]).to eq([message]) + end + end + + describe '#ready?' do + let(:current_user) { developer } + + subject(:ready) do + mutation.ready?(**mutation_arguments) + end + + context 'when released_at is included as an argument but is passed nil' do + let(:mutation_arguments) { super().merge(released_at: nil) } + + it 'raises a validation error' do + expect { subject }.to raise_error(Gitlab::Graphql::Errors::ArgumentError, 'if the releasedAt argument is provided, it cannot be null') + end + end + + context 'when milestones is included as an argument but is passed nil' do + let(:mutation_arguments) { super().merge(milestones: nil) } + + it 'raises a validation error' do + expect { subject }.to raise_error(Gitlab::Graphql::Errors::ArgumentError, 'if the milestones argument is provided, it cannot be null') + end + end + end + + describe '#resolve' do + subject(:resolve) do + mutation.resolve(**mutation_arguments) + end + + let(:updated_release) { subject[:release] } + + context 'when the current user has access to create releases' do + let(:current_user) { developer } + + context 'name' do + let(:mutation_arguments) { super().merge(name: updated_name) } + + context 'when a new name is provided' do + let(:updated_name) { 'Updated name' } + + it 'updates the name' do + expect(updated_release.name).to eq(updated_name) + end + + it_behaves_like 'no changes to the release except for the', :name + end + + context 'when nil is provided' do + let(:updated_name) { nil } + + it 'updates the name to be the tag name' do + expect(updated_release.name).to eq(tag) + end + + it_behaves_like 'no changes to the release except for the', :name + end + end + + context 'description' do + let(:mutation_arguments) { super().merge(description: updated_description) } + + context 'when a new description is provided' do + let(:updated_description) { 'Updated description' } + + it 'updates the description' do + expect(updated_release.description).to eq(updated_description) + end + + it_behaves_like 'no changes to the release except for the', :description + end + + context 'when nil is provided' do + let(:updated_description) { nil } + + it 'updates the description to nil' do + expect(updated_release.description).to eq(nil) + end + + it_behaves_like 'no changes to the release except for the', :description + end + end + + context 'released_at' do + let(:mutation_arguments) { super().merge(released_at: updated_released_at) } + + context 'when a new released_at is provided' do + let(:updated_released_at) { Time.parse('2020-12-10').utc } + + it 'updates the released_at' do + expect(updated_release.released_at).to eq(updated_released_at) + end + + it_behaves_like 'no changes to the release except for the', :released_at + end + end + + context 'milestones' do + let(:mutation_arguments) { super().merge(milestones: updated_milestones) } + + context 'when a new set of milestones is provided provided' do + let(:updated_milestones) { [milestone_12_3.title] } + + it 'updates the milestone associations' do + expect(updated_release.milestones).to eq([milestone_12_3]) + end + + it_behaves_like 'no changes to the release except for the', :milestones + end + + context 'when an empty array is provided' do + let(:updated_milestones) { [] } + + it 'removes all milestone associations' do + expect(updated_release.milestones).to eq([]) + end + + it_behaves_like 'no changes to the release except for the', :milestones + end + + context 'when a non-existent milestone title is provided' do + let(:updated_milestones) { ['not real'] } + + it_behaves_like 'validation error with message', 'Milestone(s) not found: not real' + end + + context 'when a milestone title from a different project is provided' do + let(:milestone_in_different_project) { create(:milestone, title: 'milestone in different project') } + let(:updated_milestones) { [milestone_in_different_project.title] } + + it_behaves_like 'validation error with message', 'Milestone(s) not found: milestone in different project' + end + end + + context 'validation' do + context 'when no updated fields are provided' do + it_behaves_like 'validation error with message', 'params is empty' + end + + context 'when the tag does not exist' do + let(:mutation_arguments) { super().merge(tag: 'not-a-real-tag') } + + it_behaves_like 'validation error with message', 'Tag does not exist' + end + + context 'when the project does not exist' do + let(:mutation_arguments) { super().merge(project_path: 'not/a/real/path') } + + it 'raises an error' do + expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable, "The resource that you are attempting to access does not exist or you don't have permission to perform this action") + end + end + end + end + + context "when the current user doesn't have access to update releases" do + let(:current_user) { reporter } + + it 'raises an error' do + expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable, "The resource that you are attempting to access does not exist or you don't have permission to perform this action") + end + end + end +end |