summaryrefslogtreecommitdiff
path: root/spec/services/snippets
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-07-20 12:26:25 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2020-07-20 12:26:25 +0000
commita09983ae35713f5a2bbb100981116d31ce99826e (patch)
tree2ee2af7bd104d57086db360a7e6d8c9d5d43667a /spec/services/snippets
parent18c5ab32b738c0b6ecb4d0df3994000482f34bd8 (diff)
downloadgitlab-ce-a09983ae35713f5a2bbb100981116d31ce99826e.tar.gz
Add latest changes from gitlab-org/gitlab@13-2-stable-ee
Diffstat (limited to 'spec/services/snippets')
-rw-r--r--spec/services/snippets/bulk_destroy_service_spec.rb2
-rw-r--r--spec/services/snippets/count_service_spec.rb2
-rw-r--r--spec/services/snippets/create_service_spec.rb54
-rw-r--r--spec/services/snippets/destroy_service_spec.rb28
-rw-r--r--spec/services/snippets/repository_validation_service_spec.rb2
-rw-r--r--spec/services/snippets/update_service_spec.rb256
-rw-r--r--spec/services/snippets/update_statistics_service_spec.rb86
7 files changed, 393 insertions, 37 deletions
diff --git a/spec/services/snippets/bulk_destroy_service_spec.rb b/spec/services/snippets/bulk_destroy_service_spec.rb
index 6e5623e575f..8a6250a8b45 100644
--- a/spec/services/snippets/bulk_destroy_service_spec.rb
+++ b/spec/services/snippets/bulk_destroy_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Snippets::BulkDestroyService do
+RSpec.describe Snippets::BulkDestroyService do
let_it_be(:project) { create(:project) }
let(:user) { create(:user) }
let!(:personal_snippet) { create(:personal_snippet, :repository, author: user) }
diff --git a/spec/services/snippets/count_service_spec.rb b/spec/services/snippets/count_service_spec.rb
index 4137e65dcca..5ce637d0bac 100644
--- a/spec/services/snippets/count_service_spec.rb
+++ b/spec/services/snippets/count_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Snippets::CountService do
+RSpec.describe Snippets::CountService do
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project, :public) }
diff --git a/spec/services/snippets/create_service_spec.rb b/spec/services/snippets/create_service_spec.rb
index fa8cbc87563..62eef00b67f 100644
--- a/spec/services/snippets/create_service_spec.rb
+++ b/spec/services/snippets/create_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Snippets::CreateService do
+RSpec.describe Snippets::CreateService do
describe '#execute' do
let_it_be(:user) { create(:user) }
let_it_be(:admin) { create(:user, :admin) }
@@ -177,10 +177,8 @@ describe Snippets::CreateService do
end
it 'returns a generic error' do
- response = subject
-
- expect(response).to be_error
- expect(response.payload[:snippet].errors[:repository]).to eq ['Error creating the snippet']
+ expect(subject).to be_error
+ expect(snippet.errors[:repository]).to eq ['Error creating the snippet']
end
end
@@ -230,15 +228,15 @@ describe Snippets::CreateService do
end
end
- shared_examples 'when snippet_files param is present' do
+ shared_examples 'when snippet_actions param is present' do
let(:file_path) { 'snippet_file_path.rb' }
let(:content) { 'snippet_content' }
- let(:snippet_files) { [{ action: 'create', file_path: file_path, content: content }] }
+ let(:snippet_actions) { [{ action: 'create', file_path: file_path, content: content }] }
let(:base_opts) do
{
title: 'Test snippet',
visibility_level: Gitlab::VisibilityLevel::PRIVATE,
- snippet_files: snippet_files
+ snippet_actions: snippet_actions
}
end
@@ -250,7 +248,7 @@ describe Snippets::CreateService do
end
it 'commit the files to the repository' do
- subject
+ expect(subject).to be_success
blob = snippet.repository.blob_at('master', file_path)
@@ -261,28 +259,42 @@ describe Snippets::CreateService do
let(:extra_opts) { { content: 'foo', file_name: 'path' } }
it 'a validation error is raised' do
- response = subject
- snippet = response.payload[:snippet]
-
- expect(response).to be_error
+ expect(subject).to be_error
expect(snippet.errors.full_messages_for(:content)).to eq ['Content and snippet files cannot be used together']
expect(snippet.errors.full_messages_for(:file_name)).to eq ['File name and snippet files cannot be used together']
expect(snippet.repository.exists?).to be_falsey
end
end
- context 'when snippet_files param is invalid' do
- let(:snippet_files) { [{ action: 'invalid_action', file_path: 'snippet_file_path.rb', content: 'snippet_content' }] }
+ context 'when snippet_actions param is invalid' do
+ let(:snippet_actions) { [{ action: 'invalid_action', file_path: 'snippet_file_path.rb', content: 'snippet_content' }] }
it 'a validation error is raised' do
- response = subject
- snippet = response.payload[:snippet]
+ expect(subject).to be_error
+ expect(snippet.errors.full_messages_for(:snippet_actions)).to eq ['Snippet actions have invalid data']
+ expect(snippet.repository.exists?).to be_falsey
+ end
+ end
- expect(response).to be_error
- expect(snippet.errors.full_messages_for(:snippet_files)).to eq ['Snippet files have invalid data']
+ context 'when snippet_actions contain an action different from "create"' do
+ let(:snippet_actions) { [{ action: 'delete', file_path: 'snippet_file_path.rb' }] }
+
+ it 'a validation error is raised' do
+ expect(subject).to be_error
+ expect(snippet.errors.full_messages_for(:snippet_actions)).to eq ['Snippet actions have invalid data']
expect(snippet.repository.exists?).to be_falsey
end
end
+
+ context 'when "create" operation does not have file_path or is empty' do
+ let(:snippet_actions) { [{ action: 'create', content: content }, { action: 'create', content: content, file_path: '' }] }
+
+ it 'generates the file path for the files' do
+ expect(subject).to be_success
+ expect(snippet.repository.blob_at('master', 'snippetfile1.txt').data).to eq content
+ expect(snippet.repository.blob_at('master', 'snippetfile2.txt').data).to eq content
+ end
+ end
end
context 'when ProjectSnippet' do
@@ -299,7 +311,7 @@ describe Snippets::CreateService do
it_behaves_like 'an error service response when save fails'
it_behaves_like 'creates repository and files'
it_behaves_like 'after_save callback to store_mentions', ProjectSnippet
- it_behaves_like 'when snippet_files param is present'
+ it_behaves_like 'when snippet_actions param is present'
context 'when uploaded files are passed to the service' do
let(:extra_opts) { { files: ['foo'] } }
@@ -326,7 +338,7 @@ describe Snippets::CreateService do
it_behaves_like 'an error service response when save fails'
it_behaves_like 'creates repository and files'
it_behaves_like 'after_save callback to store_mentions', PersonalSnippet
- it_behaves_like 'when snippet_files param is present'
+ it_behaves_like 'when snippet_actions param is present'
context 'when the snippet description contains files' do
include FileMoverHelpers
diff --git a/spec/services/snippets/destroy_service_spec.rb b/spec/services/snippets/destroy_service_spec.rb
index 840dc11a740..e53d00b9ca1 100644
--- a/spec/services/snippets/destroy_service_spec.rb
+++ b/spec/services/snippets/destroy_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Snippets::DestroyService do
+RSpec.describe Snippets::DestroyService do
let_it_be(:project) { create(:project) }
let_it_be(:user) { create(:user) }
let_it_be(:other_user) { create(:user) }
@@ -105,6 +105,26 @@ describe Snippets::DestroyService do
it_behaves_like 'a successful destroy'
it_behaves_like 'deletes the snippet repository'
+
+ context 'project statistics' do
+ before do
+ snippet.statistics.refresh!
+ end
+
+ it 'updates stats after deletion' do
+ expect(project.reload.statistics.snippets_size).not_to be_zero
+
+ subject
+
+ expect(project.reload.statistics.snippets_size).to be_zero
+ end
+
+ it 'schedules a namespace statistics update' do
+ expect(Namespaces::ScheduleAggregationWorker).to receive(:perform_async).with(project.namespace_id).once
+
+ subject
+ end
+ end
end
context 'when user is not able to admin_project_snippet' do
@@ -122,6 +142,12 @@ describe Snippets::DestroyService do
it_behaves_like 'a successful destroy'
it_behaves_like 'deletes the snippet repository'
+
+ it 'schedules a namespace statistics update' do
+ expect(Namespaces::ScheduleAggregationWorker).to receive(:perform_async).with(author.namespace_id)
+
+ subject
+ end
end
context 'when user is not able to admin_personal_snippet' do
diff --git a/spec/services/snippets/repository_validation_service_spec.rb b/spec/services/snippets/repository_validation_service_spec.rb
index 1c139d8c223..e2a0d0faa18 100644
--- a/spec/services/snippets/repository_validation_service_spec.rb
+++ b/spec/services/snippets/repository_validation_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Snippets::RepositoryValidationService do
+RSpec.describe Snippets::RepositoryValidationService do
describe '#execute' do
let_it_be(:user) { create(:user) }
let_it_be(:snippet) { create(:personal_snippet, :empty_repo, author: user) }
diff --git a/spec/services/snippets/update_service_spec.rb b/spec/services/snippets/update_service_spec.rb
index 7e6441ad2f9..66dddcc49de 100644
--- a/spec/services/snippets/update_service_spec.rb
+++ b/spec/services/snippets/update_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Snippets::UpdateService do
+RSpec.describe Snippets::UpdateService do
describe '#execute' do
let_it_be(:user) { create(:user) }
let_it_be(:admin) { create :user, admin: true }
@@ -302,22 +302,22 @@ describe Snippets::UpdateService do
end
end
- shared_examples 'when snippet_files param is present' do
+ shared_examples 'when snippet_actions param is present' do
let(:file_path) { 'CHANGELOG' }
let(:content) { 'snippet_content' }
let(:new_title) { 'New title' }
- let(:snippet_files) { [{ action: 'update', previous_path: file_path, file_path: file_path, content: content }] }
+ let(:snippet_actions) { [{ action: 'update', previous_path: file_path, file_path: file_path, content: content }] }
let(:base_opts) do
{
title: new_title,
- snippet_files: snippet_files
+ snippet_actions: snippet_actions
}
end
it 'updates a snippet with the provided attributes' do
file_path = 'foo'
- snippet_files[0][:action] = 'move'
- snippet_files[0][:file_path] = file_path
+ snippet_actions[0][:action] = 'move'
+ snippet_actions[0][:file_path] = file_path
response = subject
snippet = response.payload[:snippet]
@@ -328,7 +328,7 @@ describe Snippets::UpdateService do
expect(snippet.content).to eq(content)
end
- it 'commit the files to the repository' do
+ it 'commits the files to the repository' do
subject
blob = snippet.repository.blob_at('master', file_path)
@@ -349,15 +349,27 @@ describe Snippets::UpdateService do
end
end
- context 'when snippet_files param is invalid' do
- let(:snippet_files) { [{ action: 'invalid_action' }] }
+ context 'when snippet_file content is not present' do
+ let(:snippet_actions) { [{ action: :move, previous_path: file_path, file_path: 'new_file_path' }] }
+
+ it 'does not update snippet content' do
+ content = snippet.content
+
+ expect(subject).to be_success
+
+ expect(snippet.reload.content).to eq content
+ end
+ end
+
+ context 'when snippet_actions param is invalid' do
+ let(:snippet_actions) { [{ action: 'invalid_action' }] }
it 'raises a validation error' do
response = subject
snippet = response.payload[:snippet]
expect(response).to be_error
- expect(snippet.errors.full_messages_for(:snippet_files)).to eq ['Snippet files have invalid data']
+ expect(snippet.errors.full_messages_for(:snippet_actions)).to eq ['Snippet actions have invalid data']
end
end
@@ -376,6 +388,226 @@ describe Snippets::UpdateService do
expect(snippet.content).to eq(content)
end
end
+
+ context 'commit actions' do
+ let(:new_path) { 'created_new_file' }
+ let(:base_opts) { { snippet_actions: snippet_actions } }
+
+ shared_examples 'returns an error' do |error_msg|
+ specify do
+ response = subject
+
+ expect(response).to be_error
+ expect(response.message).to eq error_msg
+ end
+ end
+
+ context 'update action' do
+ let(:snippet_actions) { [{ action: :update, file_path: file_path, content: content }] }
+
+ it 'updates the file content' do
+ expect(subject).to be_success
+
+ blob = blob(file_path)
+
+ expect(blob.data).to eq content
+ end
+
+ context 'when previous_path is present' do
+ let(:snippet_actions) { [{ action: :update, previous_path: file_path, file_path: file_path, content: content }] }
+
+ it 'updates the file content' do
+ expect(subject).to be_success
+
+ blob = blob(file_path)
+
+ expect(blob.data).to eq content
+ end
+ end
+
+ context 'when content is not present' do
+ let(:snippet_actions) { [{ action: :update, file_path: file_path }] }
+
+ it_behaves_like 'returns an error', 'Snippet actions have invalid data'
+ end
+
+ context 'when file_path does not exist' do
+ let(:snippet_actions) { [{ action: :update, file_path: 'makeup_name', content: content }] }
+
+ it_behaves_like 'returns an error', 'Repository Error updating the snippet'
+ end
+ end
+
+ context 'move action' do
+ context 'when file_path and previous_path are the same' do
+ let(:snippet_actions) { [{ action: :move, previous_path: file_path, file_path: file_path }] }
+
+ it_behaves_like 'returns an error', 'Snippet actions have invalid data'
+ end
+
+ context 'when file_path and previous_path are different' do
+ let(:snippet_actions) { [{ action: :move, previous_path: file_path, file_path: new_path }] }
+
+ it 'renames the file' do
+ old_blob = blob(file_path)
+
+ expect(subject).to be_success
+
+ blob = blob(new_path)
+
+ expect(blob).to be_present
+ expect(blob.data).to eq old_blob.data
+ end
+ end
+
+ context 'when previous_path does not exist' do
+ let(:snippet_actions) { [{ action: :move, previous_path: 'makeup_name', file_path: new_path }] }
+
+ it_behaves_like 'returns an error', 'Repository Error updating the snippet'
+ end
+
+ context 'when user wants to rename the file and update content' do
+ let(:snippet_actions) { [{ action: :move, previous_path: file_path, file_path: new_path, content: content }] }
+
+ it 'performs both operations' do
+ expect(subject).to be_success
+
+ blob = blob(new_path)
+
+ expect(blob).to be_present
+ expect(blob.data).to eq content
+ end
+ end
+ end
+
+ context 'delete action' do
+ let(:snippet_actions) { [{ action: :delete, file_path: file_path }] }
+
+ shared_examples 'deletes the file' do
+ specify do
+ old_blob = blob(file_path)
+ expect(old_blob).to be_present
+
+ expect(subject).to be_success
+ expect(blob(file_path)).to be_nil
+ end
+ end
+
+ it_behaves_like 'deletes the file'
+
+ context 'when previous_path is present and same as file_path' do
+ let(:snippet_actions) { [{ action: :delete, previous_path: file_path, file_path: file_path }] }
+
+ it_behaves_like 'deletes the file'
+ end
+
+ context 'when previous_path is present and is different from file_path' do
+ let(:snippet_actions) { [{ action: :delete, previous_path: 'foo', file_path: file_path }] }
+
+ it_behaves_like 'deletes the file'
+ end
+
+ context 'when content is present' do
+ let(:snippet_actions) { [{ action: :delete, file_path: file_path, content: 'foo' }] }
+
+ it_behaves_like 'deletes the file'
+ end
+
+ context 'when file_path does not exist' do
+ let(:snippet_actions) { [{ action: :delete, file_path: 'makeup_name' }] }
+
+ it_behaves_like 'returns an error', 'Repository Error updating the snippet'
+ end
+ end
+
+ context 'create action' do
+ let(:snippet_actions) { [{ action: :create, file_path: new_path, content: content }] }
+
+ it 'creates the file' do
+ expect(subject).to be_success
+
+ blob = blob(new_path)
+ expect(blob).to be_present
+ expect(blob.data).to eq content
+ end
+
+ context 'when content is not present' do
+ let(:snippet_actions) { [{ action: :create, file_path: new_path }] }
+
+ it_behaves_like 'returns an error', 'Snippet actions have invalid data'
+ end
+
+ context 'when file_path is not present or empty' do
+ let(:snippet_actions) { [{ action: :create, content: content }, { action: :create, file_path: '', content: content }] }
+
+ it 'generates the file path for the files' do
+ expect(blob('snippetfile1.txt')).to be_nil
+ expect(blob('snippetfile2.txt')).to be_nil
+
+ expect(subject).to be_success
+
+ expect(blob('snippetfile1.txt').data).to eq content
+ expect(blob('snippetfile2.txt').data).to eq content
+ end
+ end
+
+ context 'when file_path already exists in the repository' do
+ let(:snippet_actions) { [{ action: :create, file_path: file_path, content: content }] }
+
+ it_behaves_like 'returns an error', 'Repository Error updating the snippet'
+ end
+
+ context 'when previous_path is present' do
+ let(:snippet_actions) { [{ action: :create, previous_path: 'foo', file_path: new_path, content: content }] }
+
+ it 'creates the file' do
+ expect(subject).to be_success
+
+ blob = blob(new_path)
+ expect(blob).to be_present
+ expect(blob.data).to eq content
+ end
+ end
+ end
+
+ context 'combination of actions' do
+ let(:delete_file_path) { 'CHANGELOG' }
+ let(:create_file_path) { 'created_new_file' }
+ let(:update_file_path) { 'LICENSE' }
+ let(:move_previous_path) { 'VERSION' }
+ let(:move_file_path) { 'VERSION_new' }
+
+ let(:snippet_actions) do
+ [
+ { action: :create, file_path: create_file_path, content: content },
+ { action: :update, file_path: update_file_path, content: content },
+ { action: :delete, file_path: delete_file_path },
+ { action: :move, previous_path: move_previous_path, file_path: move_file_path, content: content }
+ ]
+ end
+
+ it 'performs all operations' do
+ expect(subject).to be_success
+
+ expect(blob(delete_file_path)).to be_nil
+
+ created_blob = blob(create_file_path)
+ expect(created_blob.data).to eq content
+
+ updated_blob = blob(update_file_path)
+ expect(updated_blob.data).to eq content
+
+ expect(blob(move_previous_path)).to be_nil
+
+ moved_blob = blob(move_file_path)
+ expect(moved_blob.data).to eq content
+ end
+ end
+
+ def blob(path)
+ snippet.repository.blob_at('master', path)
+ end
+ end
end
shared_examples 'only file_name is present' do
@@ -446,7 +678,7 @@ describe Snippets::UpdateService do
it_behaves_like 'updates repository content'
it_behaves_like 'commit operation fails'
it_behaves_like 'committable attributes'
- it_behaves_like 'when snippet_files param is present'
+ it_behaves_like 'when snippet_actions param is present'
it_behaves_like 'only file_name is present'
it_behaves_like 'only content is present'
it_behaves_like 'snippets spam check is performed' do
@@ -473,7 +705,7 @@ describe Snippets::UpdateService do
it_behaves_like 'updates repository content'
it_behaves_like 'commit operation fails'
it_behaves_like 'committable attributes'
- it_behaves_like 'when snippet_files param is present'
+ it_behaves_like 'when snippet_actions param is present'
it_behaves_like 'only file_name is present'
it_behaves_like 'only content is present'
it_behaves_like 'snippets spam check is performed' do
diff --git a/spec/services/snippets/update_statistics_service_spec.rb b/spec/services/snippets/update_statistics_service_spec.rb
new file mode 100644
index 00000000000..27ae054676a
--- /dev/null
+++ b/spec/services/snippets/update_statistics_service_spec.rb
@@ -0,0 +1,86 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Snippets::UpdateStatisticsService do
+ describe '#execute' do
+ subject { described_class.new(snippet).execute }
+
+ shared_examples 'updates statistics' do
+ it 'returns a successful response' do
+ expect(subject).to be_success
+ end
+
+ it 'expires statistics cache' do
+ expect(snippet.repository).to receive(:expire_statistics_caches)
+
+ subject
+ end
+
+ context 'when snippet statistics does not exist' do
+ it 'creates snippet statistics' do
+ snippet.statistics.delete
+ snippet.reload
+
+ expect do
+ subject
+ end.to change(SnippetStatistics, :count).by(1)
+
+ expect(snippet.statistics.commit_count).not_to be_zero
+ expect(snippet.statistics.file_count).not_to be_zero
+ expect(snippet.statistics.repository_size).not_to be_zero
+ end
+ end
+
+ context 'when snippet statistics exists' do
+ it 'updates snippet statistics' do
+ expect(snippet.statistics.commit_count).to be_zero
+ expect(snippet.statistics.file_count).to be_zero
+ expect(snippet.statistics.repository_size).to be_zero
+
+ subject
+
+ expect(snippet.statistics.commit_count).not_to be_zero
+ expect(snippet.statistics.file_count).not_to be_zero
+ expect(snippet.statistics.repository_size).not_to be_zero
+ end
+ end
+
+ context 'when snippet does not have a repository' do
+ it 'returns an error response' do
+ expect(snippet).to receive(:repository_exists?).and_return(false)
+
+ expect(subject).to be_error
+ end
+ end
+
+ it 'schedules a namespace storage statistics update' do
+ expect(Namespaces::ScheduleAggregationWorker)
+ .to receive(:perform_async).once
+
+ subject
+ end
+ end
+
+ context 'with PersonalSnippet' do
+ let!(:snippet) { create(:personal_snippet, :repository) }
+
+ it_behaves_like 'updates statistics'
+ end
+
+ context 'with ProjectSnippet' do
+ let!(:snippet) { create(:project_snippet, :repository) }
+ let(:project_statistics) { snippet.project.statistics }
+
+ it_behaves_like 'updates statistics'
+
+ it 'updates projects statistics "snippets_size"' do
+ expect(project_statistics.snippets_size).to be_zero
+
+ subject
+
+ expect(snippet.reload.statistics.repository_size).to eq project_statistics.reload.snippets_size
+ end
+ end
+ end
+end