diff options
Diffstat (limited to 'spec/graphql/mutations')
32 files changed, 445 insertions, 197 deletions
diff --git a/spec/graphql/mutations/base_mutation_spec.rb b/spec/graphql/mutations/base_mutation_spec.rb index 7939fadb37b..6b366b0c234 100644 --- a/spec/graphql/mutations/base_mutation_spec.rb +++ b/spec/graphql/mutations/base_mutation_spec.rb @@ -15,6 +15,7 @@ RSpec.describe ::Mutations::BaseMutation do context 'when argument is nullable and required' do let(:mutation_class) do Class.new(described_class) do + graphql_name 'BaseMutation' argument :foo, GraphQL::Types::String, required: :nullable end end @@ -35,6 +36,7 @@ RSpec.describe ::Mutations::BaseMutation do context 'when argument is required and NOT nullable' do let(:mutation_class) do Class.new(described_class) do + graphql_name 'BaseMutation' argument :foo, GraphQL::Types::String, required: true end end diff --git a/spec/graphql/mutations/boards/update_spec.rb b/spec/graphql/mutations/boards/update_spec.rb index da3dfeecd4d..4785bc94624 100644 --- a/spec/graphql/mutations/boards/update_spec.rb +++ b/spec/graphql/mutations/boards/update_spec.rb @@ -29,14 +29,6 @@ RSpec.describe Mutations::Boards::Update do 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) diff --git a/spec/graphql/mutations/ci/runner/delete_spec.rb b/spec/graphql/mutations/ci/runner/delete_spec.rb index ee640b21918..06d360430f8 100644 --- a/spec/graphql/mutations/ci/runner/delete_spec.rb +++ b/spec/graphql/mutations/ci/runner/delete_spec.rb @@ -44,14 +44,6 @@ RSpec.describe Mutations::Ci::Runner::Delete do end end - context 'with invalid params' do - let(:mutation_params) { { id: "invalid-id" } } - - it 'raises an error' do - expect { subject }.to raise_error(::GraphQL::CoercionError) - end - end - context 'when required arguments are missing' do let(:mutation_params) { {} } diff --git a/spec/graphql/mutations/ci/runner/update_spec.rb b/spec/graphql/mutations/ci/runner/update_spec.rb index 0b3489d37dc..75e9b57e60a 100644 --- a/spec/graphql/mutations/ci/runner/update_spec.rb +++ b/spec/graphql/mutations/ci/runner/update_spec.rb @@ -33,14 +33,6 @@ RSpec.describe Mutations::Ci::Runner::Update do end end - context 'with invalid params' do - it 'raises an error' do - mutation_params[:id] = "invalid-id" - - expect { subject }.to raise_error(::GraphQL::CoercionError) - end - end - context 'when required arguments are missing' do let(:mutation_params) { {} } diff --git a/spec/graphql/mutations/clusters/agent_tokens/create_spec.rb b/spec/graphql/mutations/clusters/agent_tokens/create_spec.rb index fc025c8e3d3..45d421509d0 100644 --- a/spec/graphql/mutations/clusters/agent_tokens/create_spec.rb +++ b/spec/graphql/mutations/clusters/agent_tokens/create_spec.rb @@ -48,14 +48,6 @@ RSpec.describe Mutations::Clusters::AgentTokens::Create do expect(token.description).to eq(description) expect(token.name).to eq(name) end - - context 'invalid params' do - subject { mutation.resolve(cluster_agent_id: cluster_agent.id) } - - it 'generates an error message when id invalid', :aggregate_failures do - expect { subject }.to raise_error(::GraphQL::CoercionError) - end - end end end end diff --git a/spec/graphql/mutations/clusters/agent_tokens/delete_spec.rb b/spec/graphql/mutations/clusters/agent_tokens/delete_spec.rb deleted file mode 100644 index 5cdbc0f6d72..00000000000 --- a/spec/graphql/mutations/clusters/agent_tokens/delete_spec.rb +++ /dev/null @@ -1,52 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe Mutations::Clusters::AgentTokens::Delete do - let(:token) { create(:cluster_agent_token) } - let(:user) { create(:user) } - - let(:mutation) do - described_class.new( - object: double, - context: { current_user: user }, - field: double - ) - end - - it { expect(described_class.graphql_name).to eq('ClusterAgentTokenDelete') } - it { expect(described_class).to require_graphql_authorizations(:admin_cluster) } - - describe '#resolve' do - let(:global_id) { token.to_global_id } - - subject { mutation.resolve(id: global_id) } - - context 'without user permissions' do - it 'fails to delete the cluster agent', :aggregate_failures do - expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable) - expect { token.reload }.not_to raise_error - end - end - - context 'with user permissions' do - before do - token.agent.project.add_maintainer(user) - end - - it 'deletes a cluster agent', :aggregate_failures do - expect { subject }.to change { ::Clusters::AgentToken.count }.by(-1) - expect { token.reload }.to raise_error(ActiveRecord::RecordNotFound) - end - end - - context 'with invalid params' do - let(:global_id) { token.id } - - it 'raises an error if the cluster agent id is invalid', :aggregate_failures do - expect { subject }.to raise_error(::GraphQL::CoercionError) - expect { token.reload }.not_to raise_error - end - end - end -end diff --git a/spec/graphql/mutations/clusters/agent_tokens/revoke_spec.rb b/spec/graphql/mutations/clusters/agent_tokens/revoke_spec.rb index f5f4c0cefad..1dd4eece246 100644 --- a/spec/graphql/mutations/clusters/agent_tokens/revoke_spec.rb +++ b/spec/graphql/mutations/clusters/agent_tokens/revoke_spec.rb @@ -40,16 +40,6 @@ RSpec.describe Mutations::Clusters::AgentTokens::Revoke do expect(token.reload).to be_revoked end - - context 'supplied ID is invalid' do - let(:global_id) { token.id } - - it 'raises a coercion error' do - expect { subject }.to raise_error(::GraphQL::CoercionError) - - expect(token.reload).not_to be_revoked - end - end end end end diff --git a/spec/graphql/mutations/clusters/agents/delete_spec.rb b/spec/graphql/mutations/clusters/agents/delete_spec.rb index 0aabf53391a..e0ecff5fe44 100644 --- a/spec/graphql/mutations/clusters/agents/delete_spec.rb +++ b/spec/graphql/mutations/clusters/agents/delete_spec.rb @@ -38,14 +38,5 @@ RSpec.describe Mutations::Clusters::Agents::Delete do expect { cluster_agent.reload }.to raise_error(ActiveRecord::RecordNotFound) end end - - context 'with invalid params' do - subject { mutation.resolve(id: cluster_agent.id) } - - it 'raises an error if the cluster agent id is invalid', :aggregate_failures do - expect { subject }.to raise_error(::GraphQL::CoercionError) - expect { cluster_agent.reload }.not_to raise_error - end - 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 index 37e0fd611e4..451f6d1fe06 100644 --- a/spec/graphql/mutations/concerns/mutations/finds_by_gid_spec.rb +++ b/spec/graphql/mutations/concerns/mutations/finds_by_gid_spec.rb @@ -13,7 +13,7 @@ RSpec.describe Mutations::FindsByGid do end end - let(:query) { double('Query', schema: GitlabSchema) } + let(:query) { query_double(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 } diff --git a/spec/graphql/mutations/container_expiration_policies/update_spec.rb b/spec/graphql/mutations/container_expiration_policies/update_spec.rb index e22fb951172..e070336ef76 100644 --- a/spec/graphql/mutations/container_expiration_policies/update_spec.rb +++ b/spec/graphql/mutations/container_expiration_policies/update_spec.rb @@ -11,7 +11,7 @@ RSpec.describe Mutations::ContainerExpirationPolicies::Update do let(:container_expiration_policy) { project.container_expiration_policy } let(:params) { { project_path: project.full_path, cadence: '3month', keep_n: 100, older_than: '14d' } } - specify { expect(described_class).to require_graphql_authorizations(:destroy_container_image) } + specify { expect(described_class).to require_graphql_authorizations(:admin_container_image) } describe '#resolve' do subject { described_class.new(object: project, context: { current_user: user }, field: nil).resolve(**params) } @@ -76,7 +76,7 @@ RSpec.describe Mutations::ContainerExpirationPolicies::Update do context 'with existing container expiration policy' do where(:user_role, :shared_examples_name) do :maintainer | 'updating the container expiration policy' - :developer | 'updating the container expiration policy' + :developer | 'denying access to container expiration policy' :reporter | 'denying access to container expiration policy' :guest | 'denying access to container expiration policy' :anonymous | 'denying access to container expiration policy' @@ -96,7 +96,7 @@ RSpec.describe Mutations::ContainerExpirationPolicies::Update do where(:user_role, :shared_examples_name) do :maintainer | 'creating the container expiration policy' - :developer | 'creating the container expiration policy' + :developer | 'denying access to container expiration policy' :reporter | 'denying access to container expiration policy' :guest | 'denying access to container expiration policy' :anonymous | 'denying access to container expiration policy' diff --git a/spec/graphql/mutations/container_repositories/destroy_spec.rb b/spec/graphql/mutations/container_repositories/destroy_spec.rb index 3903196a511..97da7846339 100644 --- a/spec/graphql/mutations/container_repositories/destroy_spec.rb +++ b/spec/graphql/mutations/container_repositories/destroy_spec.rb @@ -9,7 +9,7 @@ RSpec.describe Mutations::ContainerRepositories::Destroy do let_it_be(:user) { create(:user) } let(:project) { container_repository.project } - let(:id) { container_repository.to_global_id.to_s } + let(:id) { container_repository.to_global_id } specify { expect(described_class).to require_graphql_authorizations(:destroy_container_image) } @@ -57,11 +57,5 @@ RSpec.describe Mutations::ContainerRepositories::Destroy do 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 end end diff --git a/spec/graphql/mutations/container_repositories/destroy_tags_spec.rb b/spec/graphql/mutations/container_repositories/destroy_tags_spec.rb index f22d9ffe753..3e5f28ee244 100644 --- a/spec/graphql/mutations/container_repositories/destroy_tags_spec.rb +++ b/spec/graphql/mutations/container_repositories/destroy_tags_spec.rb @@ -3,10 +3,12 @@ require 'spec_helper' RSpec.describe Mutations::ContainerRepositories::DestroyTags do + include GraphqlHelpers + include_context 'container repository delete tags service shared context' using RSpec::Parameterized::TableSyntax - let(:id) { repository.to_global_id.to_s } + let(:id) { repository.to_global_id } specify { expect(described_class).to require_graphql_authorizations(:destroy_container_image) } @@ -67,8 +69,8 @@ RSpec.describe Mutations::ContainerRepositories::DestroyTags do end end - context 'with invalid id' do - let(:id) { 'gid://gitlab/ContainerRepository/5555' } + context 'with non-existing id' do + let(:id) { global_id_of(id: non_existing_record_id, model_name: 'ContainerRepository') } it_behaves_like 'denying access to container respository' end diff --git a/spec/graphql/mutations/customer_relations/contacts/create_spec.rb b/spec/graphql/mutations/customer_relations/contacts/create_spec.rb index d17d11305b1..dafc7b4c367 100644 --- a/spec/graphql/mutations/customer_relations/contacts/create_spec.rb +++ b/spec/graphql/mutations/customer_relations/contacts/create_spec.rb @@ -3,6 +3,8 @@ require 'spec_helper' RSpec.describe Mutations::CustomerRelations::Contacts::Create do + include GraphqlHelpers + let_it_be(:user) { create(:user) } let(:group) { create(:group, :crm_enabled) } @@ -78,9 +80,9 @@ RSpec.describe Mutations::CustomerRelations::Contacts::Create do end end - context 'when organization_id is invalid' do + context 'when organization does not exist' do before do - valid_params[:organization_id] = "gid://gitlab/CustomerRelations::Organization/#{non_existing_record_id}" + valid_params[:organization_id] = global_id_of(model_name: 'CustomerRelations::Organization', id: non_existing_record_id) end it 'returns the relevant error' do diff --git a/spec/graphql/mutations/dependency_proxy/group_settings/update_spec.rb b/spec/graphql/mutations/dependency_proxy/group_settings/update_spec.rb index 35d3224d5ba..ae368e4d37e 100644 --- a/spec/graphql/mutations/dependency_proxy/group_settings/update_spec.rb +++ b/spec/graphql/mutations/dependency_proxy/group_settings/update_spec.rb @@ -37,7 +37,7 @@ RSpec.describe Mutations::DependencyProxy::GroupSettings::Update do where(:user_role, :shared_examples_name) do :maintainer | 'updating the dependency proxy group settings' - :developer | 'updating the dependency proxy group settings' + :developer | 'denying access to dependency proxy group settings' :reporter | 'denying access to dependency proxy group settings' :guest | 'denying access to dependency proxy group settings' :anonymous | 'denying access to dependency proxy group settings' diff --git a/spec/graphql/mutations/dependency_proxy/image_ttl_group_policy/update_spec.rb b/spec/graphql/mutations/dependency_proxy/image_ttl_group_policy/update_spec.rb index 792e87f0d25..1e5059d7ef7 100644 --- a/spec/graphql/mutations/dependency_proxy/image_ttl_group_policy/update_spec.rb +++ b/spec/graphql/mutations/dependency_proxy/image_ttl_group_policy/update_spec.rb @@ -72,7 +72,7 @@ RSpec.describe Mutations::DependencyProxy::ImageTtlGroupPolicy::Update do where(:user_role, :shared_examples_name) do :maintainer | 'updating the dependency proxy image ttl policy' - :developer | 'updating the dependency proxy image ttl policy' + :developer | 'denying access to dependency proxy image ttl policy' :reporter | 'denying access to dependency proxy image ttl policy' :guest | 'denying access to dependency proxy image ttl policy' :anonymous | 'denying access to dependency proxy image ttl policy' @@ -92,7 +92,7 @@ RSpec.describe Mutations::DependencyProxy::ImageTtlGroupPolicy::Update do where(:user_role, :shared_examples_name) do :maintainer | 'creating the dependency proxy image ttl policy' - :developer | 'creating the dependency proxy image ttl policy' + :developer | 'denying access to dependency proxy image ttl policy' :reporter | 'denying access to dependency proxy image ttl policy' :guest | 'denying access to dependency proxy image ttl policy' :anonymous | 'denying access to dependency proxy image ttl policy' diff --git a/spec/graphql/mutations/discussions/toggle_resolve_spec.rb b/spec/graphql/mutations/discussions/toggle_resolve_spec.rb index 2041b86d6e7..3f7347798e5 100644 --- a/spec/graphql/mutations/discussions/toggle_resolve_spec.rb +++ b/spec/graphql/mutations/discussions/toggle_resolve_spec.rb @@ -3,6 +3,8 @@ require 'spec_helper' RSpec.describe Mutations::Discussions::ToggleResolve do + include GraphqlHelpers + subject(:mutation) do described_class.new(object: nil, context: { current_user: user }, field: nil) end @@ -15,7 +17,7 @@ RSpec.describe Mutations::Discussions::ToggleResolve do mutation.resolve(id: id_arg, resolve: resolve_arg) end - let(:id_arg) { discussion.to_global_id.to_s } + let(:id_arg) { global_id_of(discussion) } let(:resolve_arg) { true } let(:mutated_discussion) { subject[:discussion] } let(:errors) { subject[:errors] } @@ -36,7 +38,7 @@ RSpec.describe Mutations::Discussions::ToggleResolve do let_it_be(:user) { create(:user, developer_projects: [project]) } context 'when discussion cannot be found' do - let(:id_arg) { "#{discussion.to_global_id}foo" } + let(:id_arg) { global_id_of(id: non_existing_record_id, model_name: discussion.class.name) } it 'raises an error' do expect { subject }.to raise_error( @@ -46,17 +48,6 @@ RSpec.describe Mutations::Discussions::ToggleResolve do end end - context 'when discussion is not a Discussion' do - let(:discussion) { create(:note, noteable: noteable, project: project) } - - it 'raises an error' do - expect { subject }.to raise_error( - GraphQL::CoercionError, - "\"#{discussion.to_global_id}\" does not represent an instance of Discussion" - ) - end - end - shared_examples 'returns a resolved discussion without errors' do it 'returns a resolved discussion' do expect(mutated_discussion).to be_resolved diff --git a/spec/graphql/mutations/environments/canary_ingress/update_spec.rb b/spec/graphql/mutations/environments/canary_ingress/update_spec.rb index fdf9cbaf25b..b93fb36a8ff 100644 --- a/spec/graphql/mutations/environments/canary_ingress/update_spec.rb +++ b/spec/graphql/mutations/environments/canary_ingress/update_spec.rb @@ -20,7 +20,7 @@ RSpec.describe Mutations::Environments::CanaryIngress::Update do describe '#resolve' do subject { mutation.resolve(id: environment_id, weight: weight) } - let(:environment_id) { environment.to_global_id.to_s } + let(:environment_id) { environment.to_global_id } let(:weight) { 50 } let(:update_service) { double('update_service') } @@ -62,14 +62,6 @@ RSpec.describe Mutations::Environments::CanaryIngress::Update do 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 } diff --git a/spec/graphql/mutations/incident_management/timeline_event/create_spec.rb b/spec/graphql/mutations/incident_management/timeline_event/create_spec.rb new file mode 100644 index 00000000000..63faecad5d5 --- /dev/null +++ b/spec/graphql/mutations/incident_management/timeline_event/create_spec.rb @@ -0,0 +1,51 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Mutations::IncidentManagement::TimelineEvent::Create do + let_it_be(:current_user) { create(:user) } + let_it_be(:project) { create(:project) } + let_it_be(:incident) { create(:incident, project: project) } + + let(:args) { { note: 'note', occurred_at: Time.current } } + + specify { expect(described_class).to require_graphql_authorizations(:admin_incident_management_timeline_event) } + + describe '#resolve' do + subject(:resolve) { mutation_for(project, current_user).resolve(incident_id: incident.to_global_id, **args) } + + context 'when a user has permissions to create a timeline event' do + let(:expected_timeline_event) do + instance_double( + 'IncidentManagement::TimelineEvent', + note: args[:note], + occurred_at: args[:occurred_at].to_s, + incident: incident, + author: current_user, + promoted_from_note: nil + ) + end + + before do + project.add_developer(current_user) + end + + it_behaves_like 'creating an incident timeline event' + + context 'when TimelineEvents::CreateService responds with an error' do + let(:args) { {} } + + it_behaves_like 'responding with an incident timeline errors', + errors: ["Occurred at can't be blank, Note can't be blank, and Note html can't be blank"] + end + end + + it_behaves_like 'failing to create an incident timeline event' + end + + private + + def mutation_for(project, user) + described_class.new(object: project, context: { current_user: user }, field: nil) + end +end diff --git a/spec/graphql/mutations/incident_management/timeline_event/destroy_spec.rb b/spec/graphql/mutations/incident_management/timeline_event/destroy_spec.rb new file mode 100644 index 00000000000..4dd7b2ccb14 --- /dev/null +++ b/spec/graphql/mutations/incident_management/timeline_event/destroy_spec.rb @@ -0,0 +1,66 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Mutations::IncidentManagement::TimelineEvent::Destroy do + let_it_be(:current_user) { create(:user) } + let_it_be(:project) { create(:project) } + let_it_be(:incident) { create(:incident, project: project) } + + let(:timeline_event) { create(:incident_management_timeline_event, incident: incident, project: project) } + let(:args) { { id: timeline_event.to_global_id } } + + specify { expect(described_class).to require_graphql_authorizations(:admin_incident_management_timeline_event) } + + describe '#resolve' do + subject(:resolve) { mutation_for(project, current_user).resolve(**args) } + + context 'when a user has permissions to delete timeline event' do + before do + project.add_developer(current_user) + end + + context 'when TimelineEvents::DestroyService responds with success' do + it 'returns the timeline event with no errors' do + expect(resolve).to eq( + timeline_event: timeline_event, + errors: [] + ) + end + end + + context 'when TimelineEvents::DestroyService responds with an error' do + before do + allow_next_instance_of(::IncidentManagement::TimelineEvents::DestroyService) do |service| + allow(service) + .to receive(:execute) + .and_return(ServiceResponse.error(payload: { timeline_event: nil }, message: 'An error has occurred')) + end + end + + it 'returns errors' do + expect(resolve).to eq( + timeline_event: nil, + errors: ['An error has occurred'] + ) + end + end + end + + context 'when a user has no permissions to delete timeline event' do + before do + project.add_guest(current_user) + end + + it 'raises an error' do + expect { resolve }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable) + end + end + end + + private + + def mutation_for(project, user) + described_class.new(object: project, context: { current_user: user }, field: nil) + end +end diff --git a/spec/graphql/mutations/incident_management/timeline_event/promote_from_note_spec.rb b/spec/graphql/mutations/incident_management/timeline_event/promote_from_note_spec.rb new file mode 100644 index 00000000000..598ee496cf1 --- /dev/null +++ b/spec/graphql/mutations/incident_management/timeline_event/promote_from_note_spec.rb @@ -0,0 +1,85 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Mutations::IncidentManagement::TimelineEvent::PromoteFromNote do + let_it_be(:current_user) { create(:user) } + let_it_be(:project) { create(:project) } + let_it_be(:incident) { create(:incident, project: project) } + let_it_be(:comment) { create(:note, project: project, noteable: incident) } + let_it_be(:issue) { create(:issue, project: project) } + let_it_be(:issue_comment) { create(:note, project: project, noteable: issue) } + let_it_be(:alert) { create(:alert_management_alert, project: project) } + let_it_be(:alert_comment) { create(:note, project: project, noteable: alert) } + + let(:args) { { note_id: comment.to_global_id.to_s } } + + specify { expect(described_class).to require_graphql_authorizations(:admin_incident_management_timeline_event) } + + describe '#resolve' do + subject(:resolve) { mutation_for(project, current_user).resolve(**args) } + + context 'when a user has permissions to create timeline event' do + let(:expected_timeline_event) do + instance_double( + 'IncidentManagement::TimelineEvent', + note: comment.note, + occurred_at: comment.created_at.to_s, + incident: incident, + author: current_user, + promoted_from_note: comment + ) + end + + before do + project.add_developer(current_user) + end + + it_behaves_like 'creating an incident timeline event' + + context 'when TimelineEvents::CreateService responds with an error' do + before do + allow_next_instance_of(::IncidentManagement::TimelineEvents::CreateService) do |service| + allow(service).to receive(:execute).and_return( + ServiceResponse.error(payload: { timeline_event: nil }, message: 'Some error') + ) + end + end + + it_behaves_like 'responding with an incident timeline errors', errors: ['Some error'] + end + end + + context 'when note does not exist' do + let(:args) { { note_id: 'gid://gitlab/Note/0' } } + + it 'raises an error' do + expect { resolve }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable) + end + end + + context 'when note does not belong to an incident' do + let(:args) { { note_id: issue_comment.to_global_id.to_s } } + + it 'raises an error' do + expect { resolve }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable) + end + end + + context 'when note belongs to anything else but issuable' do + let(:args) { { note_id: alert_comment.to_global_id.to_s } } + + it 'raises an error' do + expect { resolve }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable) + end + end + + it_behaves_like 'failing to create an incident timeline event' + end + + private + + def mutation_for(project, user) + described_class.new(object: project, context: { current_user: user }, field: nil) + end +end diff --git a/spec/graphql/mutations/incident_management/timeline_event/update_spec.rb b/spec/graphql/mutations/incident_management/timeline_event/update_spec.rb new file mode 100644 index 00000000000..8296e5c6c15 --- /dev/null +++ b/spec/graphql/mutations/incident_management/timeline_event/update_spec.rb @@ -0,0 +1,100 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Mutations::IncidentManagement::TimelineEvent::Update do + let_it_be(:developer) { create(:user) } + let_it_be(:reporter) { create(:user) } + let_it_be(:project) { create(:project) } + let_it_be(:incident) { create(:incident, project: project) } + let_it_be_with_reload(:timeline_event) do + create(:incident_management_timeline_event, project: project, incident: incident) + end + + let(:args) do + { + id: timeline_event_id, + note: note, + occurred_at: occurred_at + } + end + + let(:note) { 'Updated Note' } + let(:timeline_event_id) { GitlabSchema.id_from_object(timeline_event).to_s } + let(:occurred_at) { 1.minute.ago } + + before do + project.add_developer(developer) + project.add_reporter(reporter) + end + + describe '#resolve' do + let(:current_user) { developer } + + subject(:resolve) { mutation_for(current_user).resolve(**args) } + + shared_examples 'failed update with a top-level access error' do |error| + specify do + expect { resolve }.to raise_error( + Gitlab::Graphql::Errors::ResourceNotAvailable, + error || Gitlab::Graphql::Authorize::AuthorizeResource::RESOURCE_ACCESS_ERROR + ) + end + end + + context 'when user has permissions to update the timeline event' do + context 'when timeline event exists' do + it 'updates the timeline event' do + expect { resolve }.to change { timeline_event.reload.note }.to(note) + .and change { timeline_event.reload.occurred_at.to_s }.to(occurred_at.to_s) + end + + it 'returns updated timeline event' do + expect(resolve).to eq( + timeline_event: timeline_event.reload, + errors: [] + ) + end + + context 'when there is a validation error' do + let(:occurred_at) { 'invalid date' } + + it 'does not update the timeline event' do + expect { resolve }.not_to change { timeline_event.reload.updated_at } + end + + it 'responds with error' do + expect(resolve).to eq( + timeline_event: nil, + errors: ["Occurred at can't be blank"] + ) + end + end + end + + context 'when timeline event cannot be found' do + let(:timeline_event_id) do + Gitlab::GlobalId.build( + nil, + model_name: ::IncidentManagement::TimelineEvent.name, + id: non_existing_record_id + ).to_s + end + + it_behaves_like 'failed update with a top-level access error' + end + end + + context 'when user does not have permissions to update the timeline event' do + let(:current_user) { reporter } + + it_behaves_like 'failed update with a top-level access error' + end + end + + private + + def mutation_for(user) + described_class.new(object: nil, context: { current_user: user }, field: nil) + end +end diff --git a/spec/graphql/mutations/issues/set_due_date_spec.rb b/spec/graphql/mutations/issues/set_due_date_spec.rb index 263122e5d5f..83edd670695 100644 --- a/spec/graphql/mutations/issues/set_due_date_spec.rb +++ b/spec/graphql/mutations/issues/set_due_date_spec.rb @@ -26,7 +26,7 @@ RSpec.describe Mutations::Issues::SetDueDate do it 'returns the issue with updated due date', :aggregate_failures do expect(mutated_issue).to eq(issue) - expect(mutated_issue.due_date).to eq(Date.today + 2.days) + expect(mutated_issue.due_date).to eq(due_date.to_date) expect(subject[:errors]).to be_empty end diff --git a/spec/graphql/mutations/merge_requests/accept_spec.rb b/spec/graphql/mutations/merge_requests/accept_spec.rb index c97c78ec206..c99b1d988c5 100644 --- a/spec/graphql/mutations/merge_requests/accept_spec.rb +++ b/spec/graphql/mutations/merge_requests/accept_spec.rb @@ -3,6 +3,7 @@ require 'spec_helper' RSpec.describe Mutations::MergeRequests::Accept do + include GraphqlHelpers include AfterNextHelpers subject(:mutation) { described_class.new(context: context, object: nil, field: nil) } @@ -12,7 +13,7 @@ RSpec.describe Mutations::MergeRequests::Accept do let(:project) { create(:project, :public, :repository) } let(:context) do GraphQL::Query::Context.new( - query: double('query', schema: GitlabSchema), + query: query_double(schema: GitlabSchema), values: { current_user: user }, object: nil ) diff --git a/spec/graphql/mutations/merge_requests/create_spec.rb b/spec/graphql/mutations/merge_requests/create_spec.rb index 83af1e3f1b3..e1edb60e4ff 100644 --- a/spec/graphql/mutations/merge_requests/create_spec.rb +++ b/spec/graphql/mutations/merge_requests/create_spec.rb @@ -3,6 +3,8 @@ require 'spec_helper' RSpec.describe Mutations::MergeRequests::Create do + include GraphqlHelpers + subject(:mutation) { described_class.new(object: nil, context: context, field: nil) } let_it_be(:project) { create(:project, :public, :repository) } @@ -10,7 +12,7 @@ RSpec.describe Mutations::MergeRequests::Create do let(:context) do GraphQL::Query::Context.new( - query: double('query', schema: nil), + query: query_double(schema: nil), values: { current_user: user }, object: nil ) diff --git a/spec/graphql/mutations/namespace/package_settings/update_spec.rb b/spec/graphql/mutations/namespace/package_settings/update_spec.rb index 978c81fadfa..631e02ff3dc 100644 --- a/spec/graphql/mutations/namespace/package_settings/update_spec.rb +++ b/spec/graphql/mutations/namespace/package_settings/update_spec.rb @@ -10,7 +10,7 @@ RSpec.describe Mutations::Namespace::PackageSettings::Update do let(:params) { { namespace_path: namespace.full_path } } - specify { expect(described_class).to require_graphql_authorizations(:create_package_settings) } + specify { expect(described_class).to require_graphql_authorizations(:admin_package) } describe '#resolve' do subject { described_class.new(object: namespace, context: { current_user: user }, field: nil).resolve(**params) } @@ -68,7 +68,7 @@ RSpec.describe Mutations::Namespace::PackageSettings::Update do where(:user_role, :shared_examples_name) do :maintainer | 'updating the namespace package setting' - :developer | 'updating the namespace package setting' + :developer | 'denying access to namespace package setting' :reporter | 'denying access to namespace package setting' :guest | 'denying access to namespace package setting' :anonymous | 'denying access to namespace package setting' @@ -88,7 +88,7 @@ RSpec.describe Mutations::Namespace::PackageSettings::Update do where(:user_role, :shared_examples_name) do :maintainer | 'creating the namespace package setting' - :developer | 'creating the namespace package setting' + :developer | 'denying access to namespace package setting' :reporter | 'denying access to namespace package setting' :guest | 'denying access to namespace package setting' :anonymous | 'denying access to namespace package setting' diff --git a/spec/graphql/mutations/release_asset_links/delete_spec.rb b/spec/graphql/mutations/release_asset_links/delete_spec.rb index cda292f2ffa..cca7bd2ba38 100644 --- a/spec/graphql/mutations/release_asset_links/delete_spec.rb +++ b/spec/graphql/mutations/release_asset_links/delete_spec.rb @@ -52,18 +52,12 @@ RSpec.describe Mutations::ReleaseAssetLinks::Delete do end context "when the link doesn't exist" do - let(:mutation_arguments) { super().merge(id: "gid://gitlab/Releases::Link/#{non_existing_record_id}") } - - it 'raises an error' do - expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable) + let(:mutation_arguments) do + super().merge(id: global_id_of(id: non_existing_record_id, model_name: release_link.class.name)) end - end - - context "when the provided ID is invalid" do - let(:mutation_arguments) { super().merge(id: 'not-a-valid-gid') } it 'raises an error' do - expect { subject }.to raise_error(::GraphQL::CoercionError) + expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable) end end end diff --git a/spec/graphql/mutations/release_asset_links/update_spec.rb b/spec/graphql/mutations/release_asset_links/update_spec.rb index 64648687336..e119cf9cc77 100644 --- a/spec/graphql/mutations/release_asset_links/update_spec.rb +++ b/spec/graphql/mutations/release_asset_links/update_spec.rb @@ -186,18 +186,12 @@ RSpec.describe Mutations::ReleaseAssetLinks::Update do end context "when the link doesn't exist" do - let(:mutation_arguments) { super().merge(id: "gid://gitlab/Releases::Link/#{non_existing_record_id}") } - - it 'raises an error' do - expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable) + let(:mutation_arguments) do + super().merge(id: global_id_of(id: non_existing_record_id, model_name: "Releases::Link")) end - end - - context "when the provided ID is invalid" do - let(:mutation_arguments) { super().merge(id: 'not-a-valid-gid') } it 'raises an error' do - expect { subject }.to raise_error(::GraphQL::CoercionError) + expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable) end end end diff --git a/spec/graphql/mutations/timelogs/delete_spec.rb b/spec/graphql/mutations/timelogs/delete_spec.rb new file mode 100644 index 00000000000..f4a258e0f78 --- /dev/null +++ b/spec/graphql/mutations/timelogs/delete_spec.rb @@ -0,0 +1,93 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Mutations::Timelogs::Delete do + include GraphqlHelpers + + let_it_be(:author) { create(:user) } + let_it_be(:maintainer) { create(:user) } + let_it_be(:administrator) { create(:user, :admin) } + let_it_be(:project) { create(:project, :public) } + let_it_be(:issue) { create(:issue, project: project) } + let_it_be_with_reload(:timelog) { create(:timelog, user: author, issue: issue, time_spent: 1800) } + + let(:mutation) { described_class.new(object: nil, context: { current_user: current_user }, field: nil) } + let(:timelog_id) { global_id_of(timelog) } + let(:mutation_arguments) { { id: timelog_id } } + + describe '#resolve' do + subject(:resolve) do + mutation.resolve(**mutation_arguments) + end + + context 'when the timelog id is not valid' do + let(:current_user) { author } + let(:timelog_id) { global_id_of(model_name: 'Timelog', id: non_existing_record_id) } + + it 'raises Gitlab::Graphql::Errors::ResourceNotAvailable' do + expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable) + end + end + + context 'when the current user is not the timelog\'s author, not a maintainer and not an admin' do + let(:current_user) { create(:user) } + + it 'raises Gitlab::Graphql::Errors::ResourceNotAvailable' do + expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable) + end + end + + context 'when the current user is the timelog\'s author' do + let(:current_user) { author } + + it 'deletes the timelog' do + expect { subject }.to change { Timelog.count }.by(-1) + end + + it 'returns the deleted timelog' do + expect(subject[:timelog]).to eq(timelog) + end + + it 'returns no errors' do + expect(subject[:errors]).to be_empty + end + end + + context 'when the current user is not the timelog\'s author but a maintainer of the project' do + let(:current_user) { maintainer } + + before do + project.add_maintainer(maintainer) + end + + it 'deletes the timelog' do + expect { subject }.to change { Timelog.count }.by(-1) + end + + it 'returns the deleted timelog' do + expect(subject[:timelog]).to eq(timelog) + end + + it 'returns no errors' do + expect(subject[:errors]).to be_empty + end + end + + context 'when the current user is not the timelog\'s author, not a maintainer but an admin', :enable_admin_mode do + let(:current_user) { administrator } + + it 'deletes the timelog' do + expect { subject }.to change { Timelog.count }.by(-1) + end + + it 'returns the deleted timelog' do + expect(subject[:timelog]).to eq(timelog) + end + + it 'returns no errors' do + expect(subject[:errors]).to be_empty + end + end + end +end diff --git a/spec/graphql/mutations/todos/create_spec.rb b/spec/graphql/mutations/todos/create_spec.rb index bbb033e2f33..8c6dca98bad 100644 --- a/spec/graphql/mutations/todos/create_spec.rb +++ b/spec/graphql/mutations/todos/create_spec.rb @@ -10,12 +10,19 @@ RSpec.describe Mutations::Todos::Create do context 'when target does not support todos' do it 'raises error' do current_user = create(:user) - mutation = described_class.new(object: nil, context: { current_user: current_user }, field: nil) - target = create(:milestone) - expect { mutation.resolve(target_id: global_id_of(target)) } - .to raise_error(GraphQL::CoercionError) + ctx = { current_user: current_user } + input = { target_id: global_id_of(target).to_s } + mutation = graphql_mutation(described_class, input) + + response = GitlabSchema.execute(mutation.query, context: ctx, variables: mutation.variables).to_h + + expect(response).to include( + 'errors' => contain_exactly( + include('message' => /invalid value for targetId/) + ) + ) end end diff --git a/spec/graphql/mutations/todos/mark_done_spec.rb b/spec/graphql/mutations/todos/mark_done_spec.rb index 9723ac8af42..51df2032cf1 100644 --- a/spec/graphql/mutations/todos/mark_done_spec.rb +++ b/spec/graphql/mutations/todos/mark_done_spec.rb @@ -56,15 +56,6 @@ RSpec.describe Mutations::Todos::MarkDone do expect(todo2.reload.state).to eq('done') expect(other_user_todo.reload.state).to eq('pending') end - - it 'ignores invalid GIDs' do - expect { mutation.resolve(id: author.to_global_id.to_s) } - .to raise_error(::GraphQL::CoercionError) - - expect(todo1.reload.state).to eq('pending') - expect(todo2.reload.state).to eq('done') - expect(other_user_todo.reload.state).to eq('pending') - end end def mark_done_mutation(todo) diff --git a/spec/graphql/mutations/todos/restore_many_spec.rb b/spec/graphql/mutations/todos/restore_many_spec.rb index dc10355ef22..d43f1c8a2e9 100644 --- a/spec/graphql/mutations/todos/restore_many_spec.rb +++ b/spec/graphql/mutations/todos/restore_many_spec.rb @@ -49,13 +49,6 @@ RSpec.describe Mutations::Todos::RestoreMany do expect_states_were_not_changed end - it 'raises an error with invalid or non-Todo GIDs' do - expect { mutation.resolve(ids: [author.to_global_id.to_s]) } - .to raise_error(GraphQL::CoercionError) - - expect_states_were_not_changed - end - it 'restores multiple todos' do todo4 = create(:todo, user: current_user, author: author, state: :done) diff --git a/spec/graphql/mutations/todos/restore_spec.rb b/spec/graphql/mutations/todos/restore_spec.rb index 954bb3db668..fad9d6c08a6 100644 --- a/spec/graphql/mutations/todos/restore_spec.rb +++ b/spec/graphql/mutations/todos/restore_spec.rb @@ -56,15 +56,6 @@ RSpec.describe Mutations::Todos::Restore do expect(todo2.reload.state).to eq('pending') expect(other_user_todo.reload.state).to eq('done') end - - it 'raises error for invalid GID' do - expect { mutation.resolve(id: author.to_global_id.to_s) } - .to raise_error(::GraphQL::CoercionError) - - expect(todo1.reload.state).to eq('done') - expect(todo2.reload.state).to eq('pending') - expect(other_user_todo.reload.state).to eq('done') - end end def restore_mutation(todo) |