diff options
Diffstat (limited to 'spec/graphql/mutations/releases')
-rw-r--r-- | spec/graphql/mutations/releases/delete_spec.rb | 92 | ||||
-rw-r--r-- | spec/graphql/mutations/releases/update_spec.rb | 232 |
2 files changed, 324 insertions, 0 deletions
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 |