summaryrefslogtreecommitdiff
path: root/spec/graphql/mutations/releases
diff options
context:
space:
mode:
Diffstat (limited to 'spec/graphql/mutations/releases')
-rw-r--r--spec/graphql/mutations/releases/delete_spec.rb92
-rw-r--r--spec/graphql/mutations/releases/update_spec.rb232
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